From 1d9ba1ceb667b52e26511240f291a1e81bdbdef8 Mon Sep 17 00:00:00 2001
From: Kyle Corbitt <kyle@corbt.com>
Date: Wed, 23 Sep 2015 17:47:31 +0100
Subject: [PATCH 0001/1411] change native-modules link to work on gh-pages

---
 docs/NativeComponentsAndroid.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/NativeComponentsAndroid.md b/docs/NativeComponentsAndroid.md
index b7d41551c6dc..81686e3703f9 100644
--- a/docs/NativeComponentsAndroid.md
+++ b/docs/NativeComponentsAndroid.md
@@ -96,7 +96,7 @@ Setting properties on a view is not handled by automatically calling setter meth
 
 ## 5. Register the `ViewManager`
 
-The final Java step is to register the ViewManager to the application, this happens in a similar way to [Native Modules](NativeModulesAndroid.md), via the applications package member function `createViewManagers.`
+The final Java step is to register the ViewManager to the application, this happens in a similar way to [Native Modules](native-modules-android.html), via the applications package member function `createViewManagers.`
 
 ```java
   @Override

From 1c61a8a510f3ace3b1b1f9c13fd084340ce359c4 Mon Sep 17 00:00:00 2001
From: Nikos <nkatsikanis@gmail.com>
Date: Fri, 9 Oct 2015 22:34:00 +0100
Subject: [PATCH 0002/1411] Create .editorconfig

---
 .editorconfig | 11 +++++++++++
 1 file changed, 11 insertions(+)
 create mode 100644 .editorconfig

diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 000000000000..3b281f2f7d5a
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,11 @@
+# EditorConfig is awesome: http://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+# Unix-style newlines with a newline ending every file
+[*]
+end_of_line = lf
+insert_final_newline = true
+indent_style = space
+indent_size = 2

From 27a0ce3ead8235b53c2081f820063af36401831d Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Mon, 16 Nov 2015 15:01:48 +0800
Subject: [PATCH 0003/1411] update the way of starting packager on windows

update the way of starting packager on windows
---
 docs/LinuxWindowsSupport.md | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/docs/LinuxWindowsSupport.md b/docs/LinuxWindowsSupport.md
index caff0bc027b9..219cd2bf89f7 100644
--- a/docs/LinuxWindowsSupport.md
+++ b/docs/LinuxWindowsSupport.md
@@ -19,5 +19,15 @@ As of **version 0.14** Android development with React native is mostly possible
 
 On Windows the packager won't be started automatically when you run `react-native run-android`. You can start it manually using:
     
+    #For React Native version < 0.14
     cd MyAwesomeApp
     node node_modules/react-native/packager/packager.js
+
+    
+    #For React Native version >= 0.14 （which had removed packager.js)
+    cd MyAwesomeApp
+    react-native start
+
+If you hit a `ERROR  Watcher took too long to load` on Windows, try increasing the [timeout](https://github.com/facebook/react-native/blob/master/packager/react-packager/src/FileWatcher/index.js#L17) in this file (under your node_modules/react-native).
+
+

From 7e22202061a3bd63c6ab40a4b878976e12036dc1 Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Wed, 18 Nov 2015 09:01:17 +0800
Subject: [PATCH 0004/1411] add `ERROR  Watcher took too long to load` hint

add `ERROR  Watcher took too long to load` hint
---
 docs/LinuxWindowsSupport.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/LinuxWindowsSupport.md b/docs/LinuxWindowsSupport.md
index 219cd2bf89f7..2f6d59bcdbce 100644
--- a/docs/LinuxWindowsSupport.md
+++ b/docs/LinuxWindowsSupport.md
@@ -28,6 +28,6 @@ On Windows the packager won't be started automatically when you run `react-nativ
     cd MyAwesomeApp
     react-native start
 
-If you hit a `ERROR  Watcher took too long to load` on Windows, try increasing the [timeout](https://github.com/facebook/react-native/blob/master/packager/react-packager/src/FileWatcher/index.js#L17) in this file (under your node_modules/react-native).
+If you hit a `ERROR  Watcher took too long to load` on Windows, try increasing the timeout in [this file](https://github.com/facebook/react-native/blob/master/packager/react-packager/src/FileWatcher/index.js#L17) (under your node_modules/react-native).
 
 

From 3686facdda377516ad28bc97284ed920556ce42e Mon Sep 17 00:00:00 2001
From: Emilio Rodriguez <emiliorodriguez@gmail.com>
Date: Wed, 18 Nov 2015 12:04:19 +0100
Subject: [PATCH 0005/1411] [Docs] Document Platform in the modules section of
 the docs #3701

---
 docs/PlatformSpecificInformation.md | 67 +++++++++++++++++++++++++++++
 docs/Upgrading.md                   |  2 +-
 2 files changed, 68 insertions(+), 1 deletion(-)
 create mode 100644 docs/PlatformSpecificInformation.md

diff --git a/docs/PlatformSpecificInformation.md b/docs/PlatformSpecificInformation.md
new file mode 100644
index 000000000000..7e2c5d583d13
--- /dev/null
+++ b/docs/PlatformSpecificInformation.md
@@ -0,0 +1,67 @@
+---
+id: platform-specific-code
+title: Platform Specific Code
+layout: docs
+category: Guides
+permalink: docs/platform-specific-code.html
+next: native-modules-ios
+---
+
+When building a cross platform app, the need to write different code for different platforms may arise. This can always be achieved by organizing the various components in different folders: 
+
+```sh
+/common/components/   
+/android/components/   
+/ios/components/
+```
+
+Another option may be naming the components differently depending on the platform they are going to be used in:
+
+```sh
+BigButtonIOS.js
+BigButtonAndroid.js
+```
+
+But React Native provides two alternatives to easily organize your code separating it by platform:
+
+## Platform specific extensions
+React Native will detect when a file has a `.ios.` or `.android.` extension and load the right file for each platform when requiring them from other components. 
+
+For example, you can have these files in your project:
+
+```sh
+BigButton.ios.js
+BigButton.android.js
+```
+
+With this setup, you can just require the files from a different component without paying attention to the platform in which the app will run.
+
+```javascript
+var BigButton = require('./components/BigButton');
+```
+
+React Native will import the correct component for the running platform.
+
+## Platform module
+A module is provided by React Native to detect what is the platform in which the app is running. This piece of functionality can be useful when only small parts of a component are platform specific.
+
+```javascript
+var {Platform} = React;
+
+var styles = StyleSheet.create({
+    height: (Platform.OS === 'ios') ? 200 : 100
+});
+```
+
+`Platform.OS` will be `ios` when running in iOS and `android` when running in an Android device or simulator.
+
+###Detecting android version
+On Android, the Platform module can be also used to detect which is the version of the Android Platform in which the app is running
+
+```javascript
+var {Platform} = React;
+
+if(Platform.Version === '5.0'){
+   console.log('Running on Lollipop!');
+}
+```
\ No newline at end of file
diff --git a/docs/Upgrading.md b/docs/Upgrading.md
index e427796f6bac..aca07b075806 100644
--- a/docs/Upgrading.md
+++ b/docs/Upgrading.md
@@ -4,7 +4,7 @@ title: Upgrading
 layout: docs
 category: Guides
 permalink: docs/upgrading.html
-next: native-modules-ios
+next: platform-specific-code
 ---
 
 Upgrading to new versions of React Native will give you access to more APIs, views, developer tools

From a41afb7a1db325c9455945abffa5927ed10d3e93 Mon Sep 17 00:00:00 2001
From: Marc Riera <mrc2407@gmail.com>
Date: Wed, 18 Nov 2015 16:58:21 +0100
Subject: [PATCH 0006/1411] Add Switch docs

---
 website/server/extractDocs.js | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/website/server/extractDocs.js b/website/server/extractDocs.js
index 1d8abc600257..2875b15c37b2 100644
--- a/website/server/extractDocs.js
+++ b/website/server/extractDocs.js
@@ -192,8 +192,8 @@ var components = [
   '../Libraries/Image/Image.ios.js',
   '../Libraries/CustomComponents/ListView/ListView.js',
   '../Libraries/Components/MapView/MapView.js',
-  '../Libraries/CustomComponents/Navigator/Navigator.js',
   '../Libraries/Modal/Modal.js',
+  '../Libraries/CustomComponents/Navigator/Navigator.js',
   '../Libraries/Components/Navigation/NavigatorIOS.ios.js',
   '../Libraries/Picker/PickerIOS.ios.js',
   '../Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js',
@@ -201,8 +201,7 @@ var components = [
   '../Libraries/Components/ScrollView/ScrollView.js',
   '../Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js',
   '../Libraries/Components/SliderIOS/SliderIOS.ios.js',
-  '../Libraries/Components/SwitchAndroid/SwitchAndroid.android.js',
-  '../Libraries/Components/SwitchIOS/SwitchIOS.ios.js',
+  '../Libraries/Components/Switch/Switch.js',
   '../Libraries/Components/TabBarIOS/TabBarIOS.ios.js',
   '../Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js',
   '../Libraries/Text/Text.js',

From 0e4bd91db7ee95054f6f7c2f4c240ec6ef8e4eee Mon Sep 17 00:00:00 2001
From: Andreas Amsenius <andreas@amsenius.se>
Date: Thu, 19 Nov 2015 01:26:58 -0800
Subject: [PATCH 0007/1411] Add RCTCameraRoll cocoapod subspec

Summary: Struggled for some time to figure out why CameraRoll could not (anymore, upgraded from RN 0.11 iirc) be used in a cocoapods setup. This was the cleanest way to make it work, is it a bad idea for some reason?
Closes https://github.com/facebook/react-native/pull/4230

Reviewed By: svcscm

Differential Revision: D2674063

Pulled By: nicklockwood

fb-gh-sync-id: 3d9e6a8ac1834d05ad807ff1fea1b89a724b9cc8
---
 React.podspec | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/React.podspec b/React.podspec
index d8991c8ed29a..2f52c2ab8f8b 100644
--- a/React.podspec
+++ b/React.podspec
@@ -49,6 +49,12 @@ Pod::Spec.new do |s|
     ss.preserve_paths   = "Libraries/AdSupport/*.js"
   end
 
+  s.subspec 'RCTCameraRoll' do |ss|
+    ss.dependency         'React/Core'
+    ss.source_files     = "Libraries/CameraRoll/*.{h,m}"
+    ss.preserve_paths   = "Libraries/CameraRoll/*.js"
+  end
+
   s.subspec 'RCTGeolocation' do |ss|
     ss.dependency         'React/Core'
     ss.source_files     = "Libraries/Geolocation/*.{h,m}"

From a3d9f5ba8406a837f59652ca2bbc5d6cf31de019 Mon Sep 17 00:00:00 2001
From: gilchenzion <gchenzion@thrillist.com>
Date: Thu, 19 Nov 2015 02:20:23 -0800
Subject: [PATCH 0008/1411] Add showsCompass to MapView props

Summary: Was trying to remove the compass from the map and thought I would contribute to the project for everyone.
Closes https://github.com/facebook/react-native/pull/4225

Reviewed By: svcscm

Differential Revision: D2674060

Pulled By: nicklockwood

fb-gh-sync-id: 66f069dfc53fdeae8aaab76980146296cea1140f
---
 Libraries/Components/MapView/MapView.js | 7 +++++++
 React/Views/RCTMapManager.m             | 1 +
 2 files changed, 8 insertions(+)

diff --git a/Libraries/Components/MapView/MapView.js b/Libraries/Components/MapView/MapView.js
index de8aaa9f729a..58950c490714 100644
--- a/Libraries/Components/MapView/MapView.js
+++ b/Libraries/Components/MapView/MapView.js
@@ -87,6 +87,13 @@ var MapView = React.createClass({
      */
     showsPointsOfInterest: React.PropTypes.bool,
 
+    /**
+     * If `false` compass won't be displayed on the map.
+     * Default value is `true`.
+     * @platform ios
+     */
+    showsCompass: React.PropTypes.bool,
+
     /**
      * If `false` the user won't be able to pinch/zoom the map.
      * Default value is `true`.
diff --git a/React/Views/RCTMapManager.m b/React/Views/RCTMapManager.m
index 44dd0743ec4f..5372793a8166 100644
--- a/React/Views/RCTMapManager.m
+++ b/React/Views/RCTMapManager.m
@@ -38,6 +38,7 @@ - (UIView *)view
 
 RCT_EXPORT_VIEW_PROPERTY(showsUserLocation, BOOL)
 RCT_EXPORT_VIEW_PROPERTY(showsPointsOfInterest, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(showsCompass, BOOL)
 RCT_EXPORT_VIEW_PROPERTY(zoomEnabled, BOOL)
 RCT_EXPORT_VIEW_PROPERTY(rotateEnabled, BOOL)
 RCT_EXPORT_VIEW_PROPERTY(pitchEnabled, BOOL)

From c8fd9f7588ad02d2293cac7224715f4af7b0f352 Mon Sep 17 00:00:00 2001
From: Milen Dzhumerov <mgd@fb.com>
Date: Thu, 19 Nov 2015 03:30:45 -0800
Subject: [PATCH 0009/1411] Split immediate into multiple passes

Reviewed By: tadeuzagallo

Differential Revision: D2663957

fb-gh-sync-id: d7f0041fc98edb46e518f684527effe2f5201240
---
 .../System/JSTimers/JSTimersExecution.js      | 28 +++++++++++++++++--
 1 file changed, 25 insertions(+), 3 deletions(-)

diff --git a/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimersExecution.js b/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimersExecution.js
index 6f56d835796a..bc2b74d220f0 100644
--- a/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimersExecution.js
+++ b/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimersExecution.js
@@ -14,6 +14,7 @@ var invariant = require('invariant');
 var keyMirror = require('keyMirror');
 var performanceNow = require('performanceNow');
 var warning = require('warning');
+var BridgeProfiling = require('BridgeProfiling');
 
 /**
  * JS implementation of timer functions. Must be completely driven by an
@@ -107,15 +108,36 @@ var JSTimersExecution = {
     }
   },
 
+  /**
+   * Performs a single pass over the enqueued immediates. Returns whether
+   * more immediates are queued up (can be used as a condition a while loop).
+   */
+  callImmediatesPass: function() {
+    BridgeProfiling.profile('JSTimersExecution.callImmediatesPass()');
+
+    // The main reason to extract a single pass is so that we can track
+    // in the system trace
+    if (JSTimersExecution.immediates.length > 0) {
+      var passImmediates = JSTimersExecution.immediates.slice();
+      JSTimersExecution.immediates = [];
+
+      passImmediates.forEach((timerID) => {
+        JSTimersExecution.callTimer(timerID);
+      });
+    }
+
+    BridgeProfiling.profileEnd();
+
+    return JSTimersExecution.immediates.length > 0;
+  },
+
   /**
    * This is called after we execute any command we receive from native but
    * before we hand control back to native.
    */
   callImmediates: function() {
     JSTimersExecution.errors = null;
-    while (JSTimersExecution.immediates.length !== 0) {
-      JSTimersExecution.callTimer(JSTimersExecution.immediates.shift());
-    }
+    while (JSTimersExecution.callImmediatesPass()) {}
     if (JSTimersExecution.errors) {
       JSTimersExecution.errors.forEach((error) =>
         require('JSTimers').setTimeout(() => { throw error; }, 0)

From 2a9a5fc9e871c651bafe42f97a0df97124f2e96f Mon Sep 17 00:00:00 2001
From: Mike Armstrong <mikea@fb.com>
Date: Thu, 19 Nov 2015 05:52:58 -0800
Subject: [PATCH 0010/1411] css layout systrace markers

Reviewed By: astreet

Differential Revision: D2668741

fb-gh-sync-id: 043ff740f8cc7c687a79c50c933db99ed67b60e4
---
 .../com/facebook/react/uimanager/UIManagerModule.java  | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
index 81a3bd5f6123..b0d61f61f563 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
@@ -768,7 +768,15 @@ private void dispatchViewUpdates(final int batchId) {
       int tag = mShadowNodeRegistry.getRootTag(i);
       ReactShadowNode cssRoot = mShadowNodeRegistry.getNode(tag);
       notifyOnBeforeLayoutRecursive(cssRoot);
-      cssRoot.calculateLayout(mLayoutContext);
+
+      SystraceMessage.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "cssRoot.calculateLayout")
+          .arg("rootTag", tag)
+          .flush();
+      try {
+        cssRoot.calculateLayout(mLayoutContext);
+      } finally {
+        Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+      }
       applyUpdatesRecursive(cssRoot, 0f, 0f);
     }
 

From 7da42e3950169b12c78a450ac83cbee8c9141dff Mon Sep 17 00:00:00 2001
From: Quentin Valmori <quentin.valmori@gmail.com>
Date: Thu, 19 Nov 2015 07:09:09 -0800
Subject: [PATCH 0011/1411] add allowsInlineMediaPlayback prop to play inline
 html5 video

Summary: Allow an html5 video to be played inline. (see #3112)
Closes https://github.com/facebook/react-native/pull/3137

Reviewed By: svcscm

Differential Revision: D2674318

Pulled By: nicklockwood

fb-gh-sync-id: cf71e4039c7027f1468370ae3ddef6eb3e2d2d4f
---
 Libraries/Components/WebView/WebView.ios.js | 20 +++++++++++++--
 React/Views/RCTWebViewManager.m             | 28 +++++++++++----------
 2 files changed, 33 insertions(+), 15 deletions(-)

diff --git a/Libraries/Components/WebView/WebView.ios.js b/Libraries/Components/WebView/WebView.ios.js
index 5e303ff00b01..0e5452c9dd08 100644
--- a/Libraries/Components/WebView/WebView.ios.js
+++ b/Libraries/Components/WebView/WebView.ios.js
@@ -100,26 +100,41 @@ var WebView = React.createClass({
     onNavigationStateChange: PropTypes.func,
     startInLoadingState: PropTypes.bool, // force WebView to show loadingView on first load
     style: View.propTypes.style,
+
     /**
      * Used for android only, JS is enabled by default for WebView on iOS
+     * @platform android
      */
     javaScriptEnabledAndroid: PropTypes.bool,
+
     /**
      * Sets the JS to be injected when the webpage loads.
      */
     injectedJavaScript: PropTypes.string,
 
     /**
-     * Used for iOS only, sets whether the webpage scales to fit the view and the
-     * user can change the scale
+     * Sets whether the webpage scales to fit the view and the user can change the scale.
+     * @platform ios
      */
     scalesPageToFit: PropTypes.bool,
 
     /**
      * Allows custom handling of any webview requests by a JS handler. Return true
      * or false from this method to continue loading the request.
+     * @platform ios
      */
     onShouldStartLoadWithRequest: PropTypes.func,
+
+    /**
+     * Determines whether HTML5 videos play inline or use the native full-screen
+     * controller.
+     * default value `false`
+     * **NOTE** : "In order for video to play inline, not only does this
+     * property need to be set to true, but the video element in the HTML
+     * document must also include the webkit-playsinline attribute."
+     * @platform ios
+     */
+    allowsInlineMediaPlayback: PropTypes.bool,
   },
 
   getInitialState: function() {
@@ -188,6 +203,7 @@ var WebView = React.createClass({
         onLoadingError={this.onLoadingError}
         onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
         scalesPageToFit={this.props.scalesPageToFit}
+        allowsInlineMediaPlayback={this.props.allowsInlineMediaPlayback}
       />;
 
     return (
diff --git a/React/Views/RCTWebViewManager.m b/React/Views/RCTWebViewManager.m
index 6c765e8d4382..58d663cad6da 100644
--- a/React/Views/RCTWebViewManager.m
+++ b/React/Views/RCTWebViewManager.m
@@ -18,7 +18,8 @@ @interface RCTWebViewManager () <RCTWebViewDelegate>
 
 @end
 
-@implementation RCTWebViewManager {
+@implementation RCTWebViewManager
+{
   NSConditionLock *_shouldStartLoadLock;
   BOOL _shouldStartLoad;
 }
@@ -32,18 +33,19 @@ - (UIView *)view
   return webView;
 }
 
-RCT_REMAP_VIEW_PROPERTY(url, URL, NSURL);
-RCT_REMAP_VIEW_PROPERTY(html, HTML, NSString);
-RCT_REMAP_VIEW_PROPERTY(bounces, _webView.scrollView.bounces, BOOL);
-RCT_REMAP_VIEW_PROPERTY(scrollEnabled, _webView.scrollView.scrollEnabled, BOOL);
-RCT_REMAP_VIEW_PROPERTY(scalesPageToFit, _webView.scalesPageToFit, BOOL);
-RCT_EXPORT_VIEW_PROPERTY(injectedJavaScript, NSString);
-RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets);
-RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets, BOOL);
-RCT_EXPORT_VIEW_PROPERTY(onLoadingStart, RCTDirectEventBlock);
-RCT_EXPORT_VIEW_PROPERTY(onLoadingFinish, RCTDirectEventBlock);
-RCT_EXPORT_VIEW_PROPERTY(onLoadingError, RCTDirectEventBlock);
-RCT_EXPORT_VIEW_PROPERTY(onShouldStartLoadWithRequest, RCTDirectEventBlock);
+RCT_REMAP_VIEW_PROPERTY(url, URL, NSURL)
+RCT_REMAP_VIEW_PROPERTY(html, HTML, NSString)
+RCT_REMAP_VIEW_PROPERTY(bounces, _webView.scrollView.bounces, BOOL)
+RCT_REMAP_VIEW_PROPERTY(scrollEnabled, _webView.scrollView.scrollEnabled, BOOL)
+RCT_REMAP_VIEW_PROPERTY(scalesPageToFit, _webView.scalesPageToFit, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(injectedJavaScript, NSString)
+RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets)
+RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(onLoadingStart, RCTDirectEventBlock)
+RCT_EXPORT_VIEW_PROPERTY(onLoadingFinish, RCTDirectEventBlock)
+RCT_EXPORT_VIEW_PROPERTY(onLoadingError, RCTDirectEventBlock)
+RCT_EXPORT_VIEW_PROPERTY(onShouldStartLoadWithRequest, RCTDirectEventBlock)
+RCT_REMAP_VIEW_PROPERTY(allowsInlineMediaPlayback, _webView.allowsInlineMediaPlayback, BOOL)
 
 - (NSDictionary<NSString *, id> *)constantsToExport
 {

From 3e7db5644514c144f78c5e71d4f8a6d825fd4cd1 Mon Sep 17 00:00:00 2001
From: Mike Armstrong <mikea@fb.com>
Date: Thu, 19 Nov 2015 07:11:39 -0800
Subject: [PATCH 0012/1411] Fix multiple calls to
 createReactContextInBackground

Reviewed By: astreet

Differential Revision: D2674440

fb-gh-sync-id: f842826516d2b03291ad0c4bf5c8dcbf8ec0f3a9
---
 .../java/com/facebook/react/ReactInstanceManager.java     | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
index 4678fd9f4944..b8cf21b23417 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
@@ -438,12 +438,8 @@ public String getSourceUrl() {
 
     // If react context is being created in the background, JS application will be started
     // automatically when creation completes, as root view is part of the attached root view list.
-    if (!mIsContextInitAsyncTaskRunning) {
-      if (mCurrentReactContext == null) {
-        createReactContextInBackground();
-      } else {
-        attachMeasuredRootViewToInstance(rootView, mCurrentReactContext.getCatalystInstance());
-      }
+    if (!mIsContextInitAsyncTaskRunning && mCurrentReactContext != null) {
+      attachMeasuredRootViewToInstance(rootView, mCurrentReactContext.getCatalystInstance());
     }
   }
 

From 0bf7928ebe2c27e6fb22f860a14d5db087391c15 Mon Sep 17 00:00:00 2001
From: dajomu <mundaymeister@gmail.com>
Date: Thu, 19 Nov 2015 08:40:47 -0800
Subject: [PATCH 0013/1411] Added Subject to ActionSheetIOS share options and
 updated example

Summary: I've added a subject property to the ActionSheetIOS.showShareActionSheetWithOptions options object. This will allow users to set a subject for things like emails when they are sharing to them through the ActionSheetIOS.
Options are now as follows:
```
{
   url: 'https://code.facebook.com',
   message: 'message to go with the shared url',
   subject: 'a subject to go in the email heading',
}
```
Closes https://github.com/facebook/react-native/pull/4238

Reviewed By: svcscm

Differential Revision: D2674536

Pulled By: nicklockwood

fb-gh-sync-id: 3dfad39f94f19999233bf777253ef71b6e692a6d
---
 Examples/UIExplorer/ActionSheetIOSExample.js     | 2 ++
 Libraries/ActionSheetIOS/RCTActionSheetManager.m | 6 ++++++
 2 files changed, 8 insertions(+)

diff --git a/Examples/UIExplorer/ActionSheetIOSExample.js b/Examples/UIExplorer/ActionSheetIOSExample.js
index 31aedca627c6..548fe3bd1583 100644
--- a/Examples/UIExplorer/ActionSheetIOSExample.js
+++ b/Examples/UIExplorer/ActionSheetIOSExample.js
@@ -88,6 +88,8 @@ var ShareActionSheetExample = React.createClass({
   showShareActionSheet() {
     ActionSheetIOS.showShareActionSheetWithOptions({
       url: 'https://code.facebook.com',
+      message: 'message to go with the shared url',
+      subject: 'a subject to go in the email heading',
     },
     (error) => {
       console.error(error);
diff --git a/Libraries/ActionSheetIOS/RCTActionSheetManager.m b/Libraries/ActionSheetIOS/RCTActionSheetManager.m
index 626da966ceac..1d4e93ba741b 100644
--- a/Libraries/ActionSheetIOS/RCTActionSheetManager.m
+++ b/Libraries/ActionSheetIOS/RCTActionSheetManager.m
@@ -166,6 +166,12 @@ - (CGRect)sourceRectInView:(UIView *)sourceView
   }
 
   UIActivityViewController *shareController = [[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:nil];
+
+  NSString *subject = [RCTConvert NSString:options[@"subject"]];
+  if (subject) {
+    [shareController setValue:subject forKey:@"subject"];
+  }
+
   UIViewController *controller = RCTKeyWindow().rootViewController;
 
 #if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0

From 5950f8cf1564905daa88d1b5e0aacd8e96fbaf71 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Thu, 19 Nov 2015 18:10:40 +0000
Subject: [PATCH 0014/1411] Update KnownIssues.md

---
 docs/KnownIssues.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/KnownIssues.md b/docs/KnownIssues.md
index 6ce63307e609..9fc543299707 100644
--- a/docs/KnownIssues.md
+++ b/docs/KnownIssues.md
@@ -53,11 +53,11 @@ There are properties that work on one platform only, either because they can inh
 
 There are known cases where the APIs could be made more consistent across iOS and Android:
 
-- `<AndroidViewPager>` (to be open sourced soon) and `<ScrollView pagingEnabled={true}>` on iOS do a similar thing. We might want to unify them to `<ViewPager>`.
+- `<AndroidViewPager>` and `<ScrollView pagingEnabled={true}>` on iOS do a similar thing. We might want to unify them to `<ViewPager>`.
 - `alert()` needs Android support (once the Dialogs module is open sourced)
 - It might be possible to bring `LinkingIOS` and `IntentAndroid` (to be open sourced) closer together.
 - `ActivityIndicator` could render a native spinning indicator on both platforms (currently this is done using `ActivityIndicatorIOS` on iOS and `ProgressBarAndroid` on Android).
-- `ProgressBar` could render a horizontal progress bar on both platforms (currently only supported on iOS via `ProgressViewIOS`).
+- `ProgressBar` could render a horizontal progress bar on both platforms (on iOS this is `ProgressViewIOS`, on Android it's `ProgressBarAndroid`).
 
 ### Publishing modules on Android
 

From 2faf8632d350c1ecb85f20d99eabf8d48202fc82 Mon Sep 17 00:00:00 2001
From: EwanThomas <ewan.thomas@soundcloud.com>
Date: Thu, 19 Nov 2015 11:13:42 -0800
Subject: [PATCH 0015/1411] UIRefreshControl added to scroll view

Summary: **What:**

adds `onRefreshStart` property to `ScrollView.js` for displaying and activating pull to refresh.

**Why:**

Javascript implementations seemed a little flakey and inconsistent.  As you can see in the issues below:

https://github.com/facebook/react-native/issues/2356
https://github.com/facebook/react-native/issues/745

So this is an attempt a completely native implementation.

What do you think?

![Image of dog](http://i.imgur.com/HcTQnzJ.gif)
Closes https://github.com/facebook/react-native/pull/4205

Reviewed By: svcscm

Differential Revision: D2674945

Pulled By: nicklockwood

fb-gh-sync-id: 65113a5db9785df5a95c68323c2cdf19f3b217b1
---
 Libraries/Components/ScrollView/ScrollView.js | 29 ++++++++++++++
 React/Views/RCTScrollView.h                   |  3 ++
 React/Views/RCTScrollView.m                   | 38 +++++++++++++++++++
 React/Views/RCTScrollViewManager.m            | 18 +++++++++
 4 files changed, 88 insertions(+)

diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js
index c373b52c5a3f..7a2dc58e7b86 100644
--- a/Libraries/Components/ScrollView/ScrollView.js
+++ b/Libraries/Components/ScrollView/ScrollView.js
@@ -15,6 +15,7 @@ var EdgeInsetsPropType = require('EdgeInsetsPropType');
 var Platform = require('Platform');
 var PointPropType = require('PointPropType');
 var RCTScrollView = require('NativeModules').UIManager.RCTScrollView;
+var RCTScrollViewManager = require('NativeModules').ScrollViewManager;
 var React = require('React');
 var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
 var RCTUIManager = require('NativeModules').UIManager;
@@ -279,6 +280,21 @@ var ScrollView = React.createClass({
      * @platform ios
      */
     zoomScale: PropTypes.number,
+
+    /**
+     * When defined, displays a UIRefreshControl.
+     * Invoked with a function to stop refreshing when the UIRefreshControl is animating.
+     *
+     * ```
+     * (endRefreshing) => {
+     *      endRefreshing();
+     * }
+     * ```
+     *
+     * @platform ios
+     */
+    onRefreshStart: PropTypes.func,
+
   },
 
   mixins: [ScrollResponder.Mixin],
@@ -291,6 +307,12 @@ var ScrollView = React.createClass({
     this.refs[SCROLLVIEW].setNativeProps(props);
   },
 
+  endRefreshing: function() {
+    RCTScrollViewManager.endRefreshing(
+      React.findNodeHandle(this)
+    );
+  },
+
   /**
    * Returns a reference to the underlying scroll responder, which supports
    * operations like `scrollTo`. All ScrollView-like components should
@@ -396,6 +418,13 @@ var ScrollView = React.createClass({
       onResponderReject: this.scrollResponderHandleResponderReject,
     };
 
+    var onRefreshStart = this.props.onRefreshStart;
+    // this is necessary because if we set it on props, even when empty,
+    // it'll trigger the default pull-to-refresh behaviour on native.
+    props.onRefreshStart = onRefreshStart
+      ? function() { onRefreshStart && onRefreshStart(this.endRefreshing); }.bind(this)
+      : null;
+
     var ScrollViewClass;
     if (Platform.OS === 'ios') {
       ScrollViewClass = RCTScrollView;
diff --git a/React/Views/RCTScrollView.h b/React/Views/RCTScrollView.h
index d44be6fafae1..47fb1753b7ad 100644
--- a/React/Views/RCTScrollView.h
+++ b/React/Views/RCTScrollView.h
@@ -47,6 +47,9 @@
 @property (nonatomic, assign) int snapToInterval;
 @property (nonatomic, copy) NSString *snapToAlignment;
 @property (nonatomic, copy) NSIndexSet *stickyHeaderIndices;
+@property (nonatomic, copy) RCTDirectEventBlock onRefreshStart;
+
+- (void)endRefreshing;
 
 @end
 
diff --git a/React/Views/RCTScrollView.m b/React/Views/RCTScrollView.m
index e125061f4b78..2dc6f3886807 100644
--- a/React/Views/RCTScrollView.m
+++ b/React/Views/RCTScrollView.m
@@ -144,6 +144,7 @@ @interface RCTCustomScrollView : UIScrollView<UIGestureRecognizerDelegate>
 
 @property (nonatomic, copy) NSIndexSet *stickyHeaderIndices;
 @property (nonatomic, assign) BOOL centerContent;
+@property (nonatomic, strong) UIRefreshControl *refreshControl;
 
 @end
 
@@ -352,6 +353,15 @@ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
   return hitView ?: [super hitTest:point withEvent:event];
 }
 
+- (void)setRefreshControl:(UIRefreshControl *)refreshControl
+{
+  if (_refreshControl) {
+    [_refreshControl removeFromSuperview];
+  }
+  _refreshControl = refreshControl;
+  [self addSubview:_refreshControl];
+}
+
 @end
 
 @implementation RCTScrollView
@@ -844,6 +854,34 @@ - (id)valueForUndefinedKey:(NSString *)key
   return [_scrollView valueForKey:key];
 }
 
+- (void)setOnRefreshStart:(RCTDirectEventBlock)onRefreshStart
+{
+  if (!onRefreshStart) {
+    _onRefreshStart = nil;
+    _scrollView.refreshControl = nil;
+    return;
+  }
+  _onRefreshStart = [onRefreshStart copy];
+
+  if (!_scrollView.refreshControl) {
+    UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
+    [refreshControl addTarget:self action:@selector(refreshControlValueChanged) forControlEvents:UIControlEventValueChanged];
+    _scrollView.refreshControl = refreshControl;
+  }
+}
+
+- (void)refreshControlValueChanged
+{
+  if (self.onRefreshStart) {
+    self.onRefreshStart(nil);
+  }
+}
+
+- (void)endRefreshing
+{
+  [_scrollView.refreshControl endRefreshing];
+}
+
 @end
 
 @implementation RCTEventDispatcher (RCTScrollView)
diff --git a/React/Views/RCTScrollViewManager.m b/React/Views/RCTScrollViewManager.m
index e90bda75ecf1..fdefe32cc463 100644
--- a/React/Views/RCTScrollViewManager.m
+++ b/React/Views/RCTScrollViewManager.m
@@ -65,6 +65,7 @@ - (UIView *)view
 RCT_EXPORT_VIEW_PROPERTY(snapToInterval, int)
 RCT_EXPORT_VIEW_PROPERTY(snapToAlignment, NSString)
 RCT_REMAP_VIEW_PROPERTY(contentOffset, scrollView.contentOffset, CGPoint)
+RCT_EXPORT_VIEW_PROPERTY(onRefreshStart, RCTDirectEventBlock)
 
 - (NSDictionary<NSString *, id> *)constantsToExport
 {
@@ -114,6 +115,22 @@ - (UIView *)view
   }];
 }
 
+RCT_EXPORT_METHOD(endRefreshing:(nonnull NSNumber *)reactTag)
+{
+  [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTScrollView *> *viewRegistry) {
+    
+    RCTScrollView *view = viewRegistry[reactTag];
+    if (!view || ![view isKindOfClass:[RCTScrollView class]]) {
+      RCTLogError(@"Cannot find RCTScrollView with tag #%@", reactTag);
+      return;
+    }
+
+    [view endRefreshing];
+    
+  }];
+}
+
+
 - (NSArray<NSString *> *)customDirectEventTypes
 {
   return @[
@@ -127,3 +144,4 @@ - (UIView *)view
 }
 
 @end
+

From 0d17d6a8c0adee8cb3b91d735e0774e3aa381b13 Mon Sep 17 00:00:00 2001
From: Pawel Sienkowski <sienkowski@fb.com>
Date: Thu, 19 Nov 2015 13:32:37 -0800
Subject: [PATCH 0016/1411] RCTRootView integration tests

Reviewed By: javache

Differential Revision: D2631527

fb-gh-sync-id: 377471d9e8546d7c05a045286a6ef7c5277ded16
---
 .../UIExplorer.xcodeproj/project.pbxproj      |   8 +-
 .../RCTRootViewIntegrationTests.m             | 172 ++++++++++++++++++
 IntegrationTests/PropertiesUpdateTest.js      |  32 ++++
 .../RCTRootViewIntegrationTestApp.js          |  94 ++++++++++
 .../ReactContentSizeUpdateTest.js             |  73 ++++++++
 IntegrationTests/SizeFlexibilityUpdateTest.js |  82 +++++++++
 6 files changed, 459 insertions(+), 2 deletions(-)
 create mode 100644 Examples/UIExplorer/UIExplorerIntegrationTests/RCTRootViewIntegrationTests.m
 create mode 100644 IntegrationTests/PropertiesUpdateTest.js
 create mode 100644 IntegrationTests/RCTRootViewIntegrationTestApp.js
 create mode 100644 IntegrationTests/ReactContentSizeUpdateTest.js
 create mode 100644 IntegrationTests/SizeFlexibilityUpdateTest.js

diff --git a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
index 05416d4245ef..49a27dc61e74 100644
--- a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
+++ b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
@@ -50,8 +50,9 @@
 		14D6D7281B2222EF001FB087 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDED91B0651EA00C62182 /* libRCTWebSocket.a */; };
 		14D6D7291B2222EF001FB087 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14AADF041AC3DB95002390C9 /* libReact.a */; };
 		14DC67F41AB71881001358AB /* libRCTPushNotification.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14DC67F11AB71876001358AB /* libRCTPushNotification.a */; };
-		272E6B3F1BEA849E001FCF37 /* UpdatePropertiesExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 272E6B3C1BEA849E001FCF37 /* UpdatePropertiesExampleView.m */; };
-		27F441EC1BEBE5030039B79C /* FlexibleSizeExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 27F441E81BEBE5030039B79C /* FlexibleSizeExampleView.m */; };
+		272E6B3F1BEA849E001FCF37 /* UpdatePropertiesExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 272E6B3C1BEA849E001FCF37 /* UpdatePropertiesExampleView.m */; settings = {ASSET_TAGS = (); }; };
+		27F441EC1BEBE5030039B79C /* FlexibleSizeExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 27F441E81BEBE5030039B79C /* FlexibleSizeExampleView.m */; settings = {ASSET_TAGS = (); }; };
+		27B885561BED29AF00008352 /* RCTRootViewIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 27B885551BED29AF00008352 /* RCTRootViewIntegrationTests.m */; settings = {ASSET_TAGS = (); }; };
 		3578590A1B28D2CF00341EDB /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 357859011B28D2C500341EDB /* libRCTLinking.a */; };
 		3D36915B1BDA8CBB007B22D8 /* uie_thumb_big.png in Resources */ = {isa = PBXBuildFile; fileRef = 3D36915A1BDA8CBB007B22D8 /* uie_thumb_big.png */; };
 		3DB99D0C1BA0340600302749 /* UIExplorerIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DB99D0B1BA0340600302749 /* UIExplorerIntegrationTests.m */; };
@@ -228,6 +229,7 @@
 		272E6B3C1BEA849E001FCF37 /* UpdatePropertiesExampleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = UpdatePropertiesExampleView.m; path = UIExplorer/NativeExampleViews/UpdatePropertiesExampleView.m; sourceTree = "<group>"; };
 		27F441E81BEBE5030039B79C /* FlexibleSizeExampleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FlexibleSizeExampleView.m; path = UIExplorer/NativeExampleViews/FlexibleSizeExampleView.m; sourceTree = "<group>"; };
 		27F441EA1BEBE5030039B79C /* FlexibleSizeExampleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FlexibleSizeExampleView.h; path = UIExplorer/NativeExampleViews/FlexibleSizeExampleView.h; sourceTree = "<group>"; };
+		27B885551BED29AF00008352 /* RCTRootViewIntegrationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRootViewIntegrationTests.m; sourceTree = "<group>"; };
 		357858F81B28D2C400341EDB /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = ../../Libraries/LinkingIOS/RCTLinking.xcodeproj; sourceTree = "<group>"; };
 		3D36915A1BDA8CBB007B22D8 /* uie_thumb_big.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = uie_thumb_big.png; path = UIExplorer/Images.xcassets/uie_thumb_big.imageset/uie_thumb_big.png; sourceTree = SOURCE_ROOT; };
 		3DB99D0B1BA0340600302749 /* UIExplorerIntegrationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIExplorerIntegrationTests.m; sourceTree = "<group>"; };
@@ -434,6 +436,7 @@
 		143BC5961B21E3E100462512 /* UIExplorerIntegrationTests */ = {
 			isa = PBXGroup;
 			children = (
+				27B885551BED29AF00008352 /* RCTRootViewIntegrationTests.m */,
 				3DB99D0B1BA0340600302749 /* UIExplorerIntegrationTests.m */,
 				143BC5A01B21E45C00462512 /* UIExplorerSnapshotTests.m */,
 				83636F8E1B53F22C009F943E /* RCTUIManagerScenarioTests.m */,
@@ -886,6 +889,7 @@
 				3DB99D0C1BA0340600302749 /* UIExplorerIntegrationTests.m in Sources */,
 				83636F8F1B53F22C009F943E /* RCTUIManagerScenarioTests.m in Sources */,
 				143BC5A11B21E45C00462512 /* UIExplorerSnapshotTests.m in Sources */,
+				27B885561BED29AF00008352 /* RCTRootViewIntegrationTests.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/RCTRootViewIntegrationTests.m b/Examples/UIExplorer/UIExplorerIntegrationTests/RCTRootViewIntegrationTests.m
new file mode 100644
index 000000000000..9e665b4e12d3
--- /dev/null
+++ b/Examples/UIExplorer/UIExplorerIntegrationTests/RCTRootViewIntegrationTests.m
@@ -0,0 +1,172 @@
+/**
+ * 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.
+ */
+
+//vs
+
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ */
+
+#import <UIKit/UIKit.h>
+#import <XCTest/XCTest.h>
+
+#import "RCTAssert.h"
+
+#import "RCTEventDispatcher.h"
+#import "RCTRootView.h"
+#import "RCTRootViewDelegate.h"
+
+#import <RCTTest/RCTTestRunner.h>
+
+#define RCT_TEST_DATA_CONFIGURATION_BLOCK(appName, testType, input, block) \
+- (void)test##appName##_##testType##_##input                               \
+{                                                                          \
+  [_runner runTest:_cmd                                                    \
+            module:@#appName                                               \
+      initialProps:@{@#input:@YES}                                         \
+configurationBlock:block];                                                 \
+}
+
+#define RCT_TEST_CONFIGURATION_BLOCK(appName, block)  \
+- (void)test##appName                                 \
+{                                                     \
+  [_runner runTest:_cmd                               \
+            module:@#appName                          \
+      initialProps:nil                                \
+configurationBlock:block];                            \
+}
+
+#define RCTNone   RCTRootViewSizeFlexibilityNone
+#define RCTHeight RCTRootViewSizeFlexibilityHeight
+#define RCTWidth  RCTRootViewSizeFlexibilityWidth
+#define RCTBoth   RCTRootViewSizeFlexibilityWidthAndHeight
+
+typedef void (^ControlBlock)(RCTRootView*);
+
+@interface SizeFlexibilityTestDelegate : NSObject<RCTRootViewDelegate>
+@end
+
+@implementation SizeFlexibilityTestDelegate
+
+- (void)rootViewDidChangeIntrinsicSize:(RCTRootView *)rootView
+{
+  [rootView.bridge.eventDispatcher sendAppEventWithName:@"rootViewDidChangeIntrinsicSize"
+                                                   body:@{@"width": @(rootView.intrinsicSize.width),
+                                                          @"height": @(rootView.intrinsicSize.height)}];
+}
+
+@end
+
+static SizeFlexibilityTestDelegate *sizeFlexibilityDelegate()
+{
+  static SizeFlexibilityTestDelegate *delegate;
+  if (delegate == nil) {
+    delegate = [SizeFlexibilityTestDelegate new];
+  }
+
+  return delegate;
+}
+
+static ControlBlock simpleSizeFlexibilityBlock(RCTRootViewSizeFlexibility sizeFlexibility)
+{
+  return ^(RCTRootView *rootView){
+    rootView.delegate = sizeFlexibilityDelegate();
+    rootView.sizeFlexibility = sizeFlexibility;
+  };
+}
+
+static ControlBlock multipleSizeFlexibilityUpdatesBlock(RCTRootViewSizeFlexibility finalSizeFlexibility)
+{
+  return ^(RCTRootView *rootView){
+
+    NSInteger arr[4] = {RCTNone,
+                        RCTHeight,
+                        RCTWidth,
+                        RCTBoth};
+
+    rootView.delegate = sizeFlexibilityDelegate();
+
+    for (int i = 0; i < 4; ++i) {
+      if (arr[i] != finalSizeFlexibility) {
+        rootView.sizeFlexibility = arr[i];
+      }
+    }
+
+    rootView.sizeFlexibility = finalSizeFlexibility;
+  };
+}
+
+static ControlBlock reactContentSizeUpdateBlock(RCTRootViewSizeFlexibility sizeFlexibility)
+{
+  return ^(RCTRootView *rootView){
+    rootView.delegate = sizeFlexibilityDelegate();
+    rootView.sizeFlexibility = sizeFlexibility;
+  };
+}
+
+static ControlBlock propertiesUpdateBlock()
+{
+  return ^(RCTRootView *rootView){
+    rootView.appProperties = @{@"markTestPassed":@YES};
+  };
+}
+
+@interface RCTRootViewIntegrationTests : XCTestCase
+
+@end
+
+@implementation RCTRootViewIntegrationTests
+{
+  RCTTestRunner *_runner;
+}
+
+- (void)setUp
+{
+#if __LP64__
+  RCTAssert(NO, @"Tests should be run on 32-bit device simulators (e.g. iPhone 5)");
+#endif
+
+  NSOperatingSystemVersion version = [NSProcessInfo processInfo].operatingSystemVersion;
+  RCTAssert((version.majorVersion == 8 && version.minorVersion >= 3) || version.majorVersion >= 9, @"Tests should be run on iOS 8.3+, found %zd.%zd.%zd", version.majorVersion, version.minorVersion, version.patchVersion);
+  _runner = RCTInitRunnerForApp(@"IntegrationTests/RCTRootViewIntegrationTestApp", nil);
+}
+
+#pragma mark Logic Tests
+
+// This list should be kept in sync with RCTRootViewIntegrationTestApp.js
+
+// Simple size flexibility tests - test if the content is measured properly
+RCT_TEST_DATA_CONFIGURATION_BLOCK(SizeFlexibilityUpdateTest, SingleUpdate, none, simpleSizeFlexibilityBlock(RCTNone));
+RCT_TEST_DATA_CONFIGURATION_BLOCK(SizeFlexibilityUpdateTest, SingleUpdate, height, simpleSizeFlexibilityBlock(RCTHeight));
+RCT_TEST_DATA_CONFIGURATION_BLOCK(SizeFlexibilityUpdateTest, SingleUpdate, width, simpleSizeFlexibilityBlock(RCTWidth));
+RCT_TEST_DATA_CONFIGURATION_BLOCK(SizeFlexibilityUpdateTest, SingleUpdate, both, simpleSizeFlexibilityBlock(RCTBoth));
+
+// Consider multiple size flexibility updates in a row. Test if the view's flexibility mode eventually is set to the expected value
+RCT_TEST_DATA_CONFIGURATION_BLOCK(SizeFlexibilityUpdateTest, MultipleUpdates, none, multipleSizeFlexibilityUpdatesBlock(RCTNone));
+RCT_TEST_DATA_CONFIGURATION_BLOCK(SizeFlexibilityUpdateTest, MultipleUpdates, height, multipleSizeFlexibilityUpdatesBlock(RCTHeight));
+RCT_TEST_DATA_CONFIGURATION_BLOCK(SizeFlexibilityUpdateTest, MultipleUpdates, width, multipleSizeFlexibilityUpdatesBlock(RCTWidth));
+RCT_TEST_DATA_CONFIGURATION_BLOCK(SizeFlexibilityUpdateTest, MultipleUpdates, both, multipleSizeFlexibilityUpdatesBlock(RCTBoth));
+
+// Test if the 'rootViewDidChangeIntrinsicSize' delegate method is called after the RN app decides internally to resize
+RCT_TEST_CONFIGURATION_BLOCK(ReactContentSizeUpdateTest, reactContentSizeUpdateBlock(RCTBoth))
+
+// Test if setting 'appProperties' property updates the RN app
+RCT_TEST_CONFIGURATION_BLOCK(PropertiesUpdateTest, propertiesUpdateBlock())
+
+@end
diff --git a/IntegrationTests/PropertiesUpdateTest.js b/IntegrationTests/PropertiesUpdateTest.js
new file mode 100644
index 000000000000..da563ec94a55
--- /dev/null
+++ b/IntegrationTests/PropertiesUpdateTest.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.
+ */
+'use strict';
+
+var React = require('react-native');
+var {
+  View,
+} = React;
+
+var { TestModule } = React.addons;
+
+var PropertiesUpdateTest = React.createClass({
+
+  render() {
+    if (this.props.markTestPassed) {
+      TestModule.markTestPassed(true);
+    }
+    return (
+      <View/>
+    );
+  }
+});
+
+PropertiesUpdateTest.displayName = 'PropertiesUpdateTest';
+
+module.exports = PropertiesUpdateTest;
diff --git a/IntegrationTests/RCTRootViewIntegrationTestApp.js b/IntegrationTests/RCTRootViewIntegrationTestApp.js
new file mode 100644
index 000000000000..5a126a601920
--- /dev/null
+++ b/IntegrationTests/RCTRootViewIntegrationTestApp.js
@@ -0,0 +1,94 @@
+/**
+ * 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 RCTRootViewIntegrationTestsApp
+ */
+'use strict';
+
+require('regenerator/runtime');
+
+var React = require('react-native');
+
+var {
+  AppRegistry,
+  ScrollView,
+  StyleSheet,
+  Text,
+  TouchableOpacity,
+  View,
+} = React;
+
+/* Keep this list in sync with RCTRootViewIntegrationTests.m */
+var TESTS = [
+  require('./PropertiesUpdateTest'),
+  require('./ReactContentSizeUpdateTest'),
+  require('./SizeFlexibilityUpdateTest'),
+];
+
+TESTS.forEach(
+  (test) => AppRegistry.registerComponent(test.displayName, () => test)
+);
+
+var RCTRootViewIntegrationTestsApp = React.createClass({
+  getInitialState: function() {
+    return {
+      test: null,
+    };
+  },
+  render: function() {
+    if (this.state.test) {
+      return (
+        <ScrollView>
+          <this.state.test />
+        </ScrollView>
+      );
+    }
+    return (
+      <View style={styles.container}>
+        <Text style={styles.row}>
+          Click on a test to run it in this shell for easier debugging and
+          development.  Run all tests in the testing environment with cmd+U in
+          Xcode.
+        </Text>
+        <View style={styles.separator} />
+        <ScrollView>
+          {TESTS.map((test) => [
+            <TouchableOpacity
+              onPress={() => this.setState({test})}
+              style={styles.row}>
+              <Text style={styles.testName}>
+                {test.displayName}
+              </Text>
+            </TouchableOpacity>,
+            <View style={styles.separator} />
+          ])}
+        </ScrollView>
+      </View>
+    );
+  }
+});
+
+var styles = StyleSheet.create({
+  container: {
+    backgroundColor: 'white',
+    marginTop: 40,
+    margin: 15,
+  },
+  row: {
+    padding: 10,
+  },
+  testName: {
+    fontWeight: '500',
+  },
+  separator: {
+    height: 1,
+    backgroundColor: '#bbbbbb',
+  },
+});
+
+AppRegistry.registerComponent('RCTRootViewIntegrationTestsApp', () => RCTRootViewIntegrationTestsApp);
diff --git a/IntegrationTests/ReactContentSizeUpdateTest.js b/IntegrationTests/ReactContentSizeUpdateTest.js
new file mode 100644
index 000000000000..73e1c5f5d3d3
--- /dev/null
+++ b/IntegrationTests/ReactContentSizeUpdateTest.js
@@ -0,0 +1,73 @@
+/**
+ * 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.
+ */
+'use strict';
+
+var React = require('react-native');
+var RCTNativeAppEventEmitter = require('RCTNativeAppEventEmitter');
+var Subscribable = require('Subscribable');
+var TimerMixin = require('react-timer-mixin');
+
+var { View } = React;
+
+var { TestModule } = React.addons;
+
+var reactViewWidth = 101;
+var reactViewHeight = 102;
+var newReactViewWidth = 201;
+var newReactViewHeight = 202;
+
+var ReactContentSizeUpdateTest = React.createClass({
+  mixins: [Subscribable.Mixin,
+           TimerMixin],
+
+  componentWillMount: function() {
+    this.addListenerOn(
+      RCTNativeAppEventEmitter,
+      'rootViewDidChangeIntrinsicSize',
+      this.rootViewDidChangeIntrinsicSize
+    );
+  },
+
+  getInitialState: function() {
+    return {
+      height: reactViewHeight,
+      width: reactViewWidth,
+    };
+  },
+
+  updateViewSize: function() {
+    this.setState({
+      height: newReactViewHeight,
+      width: newReactViewWidth,
+    });
+  },
+
+  componentDidMount: function() {
+    this.setTimeout(
+      () => { this.updateViewSize(); },
+      1000
+    );
+  },
+
+  rootViewDidChangeIntrinsicSize: function(intrinsicSize) {
+    if (intrinsicSize.height === newReactViewHeight && intrinsicSize.width === newReactViewWidth) {
+      TestModule.markTestPassed(true);
+    }
+  },
+
+  render() {
+    return (
+      <View style={{'height':this.state.height, 'width':this.state.width}}/>
+    );
+  }
+});
+
+ReactContentSizeUpdateTest.displayName = 'ReactContentSizeUpdateTest';
+
+module.exports = ReactContentSizeUpdateTest;
diff --git a/IntegrationTests/SizeFlexibilityUpdateTest.js b/IntegrationTests/SizeFlexibilityUpdateTest.js
new file mode 100644
index 000000000000..ddc016b70ac6
--- /dev/null
+++ b/IntegrationTests/SizeFlexibilityUpdateTest.js
@@ -0,0 +1,82 @@
+/**
+ * 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.
+ */
+'use strict';
+
+var React = require('react-native');
+var RCTNativeAppEventEmitter = require('RCTNativeAppEventEmitter');
+var Subscribable = require('Subscribable');
+var { View } = React;
+
+var { TestModule } = React.addons;
+
+var reactViewWidth = 111;
+var reactViewHeight = 222;
+
+var finalState = false;
+
+var SizeFlexibilityUpdateTest = React.createClass({
+  mixins: [Subscribable.Mixin],
+
+  componentWillMount: function() {
+    this.addListenerOn(
+      RCTNativeAppEventEmitter,
+      'rootViewDidChangeIntrinsicSize',
+      this.rootViewDidChangeIntrinsicSize
+    );
+  },
+
+  markPassed: function() {
+    TestModule.markTestPassed(true);
+    finalState = true;
+  },
+
+  rootViewDidChangeIntrinsicSize: function(intrinsicSize) {
+
+    if (finalState) {
+      // If a test reaches its final state, it is not expected to do anything more
+      TestModule.markTestPassed(false);
+      return;
+    }
+
+    if (this.props.both) {
+      if (intrinsicSize.width === reactViewWidth && intrinsicSize.height === reactViewHeight) {
+        this.markPassed();
+        return;
+      }
+    }
+    if (this.props.height) {
+      if (intrinsicSize.width !== reactViewWidth && intrinsicSize.height === reactViewHeight) {
+        this.markPassed();
+        return;
+      }
+    }
+    if (this.props.width) {
+      if (intrinsicSize.width === reactViewWidth && intrinsicSize.height !== reactViewHeight) {
+        this.markPassed();
+        return;
+      }
+    }
+    if (this.props.none) {
+      if (intrinsicSize.width !== reactViewWidth && intrinsicSize.height !== reactViewHeight) {
+        this.markPassed();
+        return;
+      }
+    }
+  },
+
+  render() {
+    return (
+      <View style={{'height':reactViewHeight, 'width':reactViewWidth}}/>
+    );
+  }
+});
+
+SizeFlexibilityUpdateTest.displayName = 'SizeFlexibilityUpdateTest';
+
+module.exports = SizeFlexibilityUpdateTest;

From 7cd7591f0466bc8aca617f75f5fd2dee53712846 Mon Sep 17 00:00:00 2001
From: Krzysztof Magiera <krzysztof@fb.com>
Date: Fri, 20 Nov 2015 00:47:24 -0800
Subject: [PATCH 0017/1411] Use requireNativeComponent in View.js.

Summary: public
In a previous diff I've removed a need for using View attributes in requireNativeComponent. Thanks to that we can now use requireNativeComponent in View module. In a follow up diff I'll be getting rid of ReactNativeViewAttributes.

Reviewed By: sahrens

Differential Revision: D2676088

fb-gh-sync-id: d5d6e50f4629bd7982b90f3496e1fd22078e96a8
---
 Libraries/Components/View/View.js                     | 11 ++++++-----
 Libraries/ReactIOS/verifyPropTypes.js                 |  2 --
 .../facebook/react/views/view/ReactViewManager.java   |  6 ++++++
 3 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/Libraries/Components/View/View.js b/Libraries/Components/View/View.js
index 3f62f027c66b..ff2def0afabe 100644
--- a/Libraries/Components/View/View.js
+++ b/Libraries/Components/View/View.js
@@ -20,7 +20,7 @@ var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
 var StyleSheetPropType = require('StyleSheetPropType');
 var ViewStylePropTypes = require('ViewStylePropTypes');
 
-var createReactNativeComponentClass = require('createReactNativeComponentClass');
+var requireNativeComponent = require('requireNativeComponent');
 
 var stylePropType = StyleSheetPropType(ViewStylePropTypes);
 
@@ -316,11 +316,12 @@ var View = React.createClass({
   },
 });
 
-var RCTView = createReactNativeComponentClass({
-  validAttributes: ReactNativeViewAttributes.RCTView,
-  uiViewClassName: 'RCTView',
+var RCTView = requireNativeComponent('RCTView', View, {
+  nativeOnly: {
+    nativeBackgroundAndroid: true,
+  }
 });
-RCTView.propTypes = View.propTypes;
+
 if (__DEV__) {
   var viewConfig = RCTUIManager.viewConfigs && RCTUIManager.viewConfigs.RCTView || {};
   for (var prop in viewConfig.nativeProps) {
diff --git a/Libraries/ReactIOS/verifyPropTypes.js b/Libraries/ReactIOS/verifyPropTypes.js
index 02715c080772..a7ccd210b6b1 100644
--- a/Libraries/ReactIOS/verifyPropTypes.js
+++ b/Libraries/ReactIOS/verifyPropTypes.js
@@ -12,7 +12,6 @@
 'use strict';
 
 var ReactNativeStyleAttributes = require('ReactNativeStyleAttributes');
-var View = require('View');
 
 export type ComponentInterface = ReactClass<any, any, any> | {
   name?: string;
@@ -40,7 +39,6 @@ function verifyPropTypes(
   var nativeProps = viewConfig.NativeProps;
   for (var prop in nativeProps) {
     if (!componentInterface.propTypes[prop] &&
-        !View.propTypes[prop] &&
         !ReactNativeStyleAttributes[prop] &&
         (!nativePropsToIgnore || !nativePropsToIgnore[prop])) {
       throw new Error(
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
index 12c691a616c0..ac0dfee0f0e9 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
@@ -122,6 +122,12 @@ public void setBorderColor(ReactViewGroup view, int index, Integer color) {
         color == null ? CSSConstants.UNDEFINED : (float) color);
   }
 
+  @ReactProp(name = ViewProps.COLLAPSABLE)
+  public void setCollapsable(ReactViewGroup view, boolean collapsable) {
+    // no-op: it's here only so that "collapsable" property is exported to JS. The value is actually
+    // handled in NativeViewHierarchyOptimizer
+  }
+
   @Override
   public String getName() {
     return REACT_CLASS;

From 1a1c3f76a25d8042c606fba3ade80d170df61215 Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Fri, 20 Nov 2015 03:33:07 -0800
Subject: [PATCH 0018/1411] Port CatalystLoggingTestCase to iOS

Reviewed By: nicklockwood

Differential Revision: D2658485

fb-gh-sync-id: e6803aefee69ee058651fc4c8c202619543f0cd2
---
 .../RCTLoggingTests.m                         | 109 ++++++++++++++++++
 IntegrationTests/IntegrationTestsApp.js       |   3 +
 IntegrationTests/LoggingTestModule.js         |  32 +++++
 .../src/Resolver/polyfills/console.js         |  20 ++--
 4 files changed, 157 insertions(+), 7 deletions(-)
 create mode 100644 Examples/UIExplorer/UIExplorerIntegrationTests/RCTLoggingTests.m
 create mode 100644 IntegrationTests/LoggingTestModule.js

diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/RCTLoggingTests.m b/Examples/UIExplorer/UIExplorerIntegrationTests/RCTLoggingTests.m
new file mode 100644
index 000000000000..0011b0524cf4
--- /dev/null
+++ b/Examples/UIExplorer/UIExplorerIntegrationTests/RCTLoggingTests.m
@@ -0,0 +1,109 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ */
+
+#import <XCTest/XCTest.h>
+
+#import "RCTAssert.h"
+#import "RCTLog.h"
+#import "RCTBridge.h"
+
+@interface RCTLoggingTests : XCTestCase
+
+@end
+
+@implementation RCTLoggingTests
+{
+  RCTBridge *_bridge;
+
+  dispatch_semaphore_t _logSem;
+  RCTLogLevel _lastLogLevel;
+  RCTLogSource _lastLogSource;
+  NSString *_lastLogMessage;
+}
+
+- (void)setUp
+{
+#if RUNNING_ON_CI
+  NSURL *scriptURL = [[NSBundle bundleForClass:[RCTBridge class]] URLForResource:@"main" withExtension:@"jsbundle"];
+  RCTAssert(scriptURL != nil, @"Could not locate main.jsBundle");
+#else
+  NSString *app = @"Examples/UIExplorer/UIExplorerIntegrationTests/js/IntegrationTestsApp";
+  NSURL *scriptURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:8081/%@.bundle?platform=ios&dev=true", app]];
+#endif
+
+  _bridge = [[RCTBridge alloc] initWithBundleURL:scriptURL moduleProvider:NULL launchOptions:nil];
+  NSDate *date = [NSDate dateWithTimeIntervalSinceNow:5];
+  while (date.timeIntervalSinceNow > 0 && _bridge.loading) {
+    [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
+  }
+  XCTAssertFalse(_bridge.loading);
+
+  _logSem = dispatch_semaphore_create(0);
+  RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
+    if (source == RCTLogSourceJavaScript) {
+      _lastLogLevel = level;
+      _lastLogSource = source;
+      _lastLogMessage = message;
+      dispatch_semaphore_signal(_logSem);
+    }
+  });
+}
+
+- (void)tearDown
+{
+  [_bridge invalidate];
+  _bridge = nil;
+
+  RCTSetLogFunction(RCTDefaultLogFunction);
+}
+
+- (void)testLogging
+{
+  [_bridge enqueueJSCall:@"LoggingTestModule.logToConsole" args:@[@"Invoking console.log"]];
+  dispatch_semaphore_wait(_logSem, DISPATCH_TIME_FOREVER);
+
+  XCTAssertEqual(_lastLogLevel, RCTLogLevelInfo);
+  XCTAssertEqual(_lastLogSource, RCTLogSourceJavaScript);
+  XCTAssertEqualObjects(_lastLogMessage, @"Invoking console.log");
+
+  [_bridge enqueueJSCall:@"LoggingTestModule.warning" args:@[@"Generating warning"]];
+  dispatch_semaphore_wait(_logSem, DISPATCH_TIME_FOREVER);
+
+  XCTAssertEqual(_lastLogLevel, RCTLogLevelWarning);
+  XCTAssertEqual(_lastLogSource, RCTLogSourceJavaScript);
+  XCTAssertEqualObjects(_lastLogMessage, @"Warning: Generating warning");
+
+  [_bridge enqueueJSCall:@"LoggingTestModule.invariant" args:@[@"Invariant failed"]];
+  dispatch_semaphore_wait(_logSem, DISPATCH_TIME_FOREVER);
+
+  XCTAssertEqual(_lastLogLevel, RCTLogLevelError);
+  XCTAssertEqual(_lastLogSource, RCTLogSourceJavaScript);
+  XCTAssertEqualObjects(_lastLogMessage, @"Invariant Violation: Invariant failed");
+
+  [_bridge enqueueJSCall:@"LoggingTestModule.logErrorToConsole" args:@[@"Invoking console.error"]];
+  dispatch_semaphore_wait(_logSem, DISPATCH_TIME_FOREVER);
+
+  XCTAssertEqual(_lastLogLevel, RCTLogLevelError);
+  XCTAssertEqual(_lastLogSource, RCTLogSourceJavaScript);
+  XCTAssertEqualObjects(_lastLogMessage, @"Invoking console.error");
+
+  [_bridge enqueueJSCall:@"LoggingTestModule.throwError" args:@[@"Throwing an error"]];
+  dispatch_semaphore_wait(_logSem, DISPATCH_TIME_FOREVER);
+
+  XCTAssertEqual(_lastLogLevel, RCTLogLevelError);
+  XCTAssertEqual(_lastLogSource, RCTLogSourceJavaScript);
+  XCTAssertEqualObjects(_lastLogMessage, @"Throwing an error");
+}
+
+@end
diff --git a/IntegrationTests/IntegrationTestsApp.js b/IntegrationTests/IntegrationTestsApp.js
index 95c2697c17ab..ce136f7fd6fa 100644
--- a/IntegrationTests/IntegrationTestsApp.js
+++ b/IntegrationTests/IntegrationTestsApp.js
@@ -36,6 +36,9 @@ TESTS.forEach(
   (test) => AppRegistry.registerComponent(test.displayName, () => test)
 );
 
+// Modules required for integration tests
+require('LoggingTestModule');
+
 var IntegrationTestsApp = React.createClass({
   getInitialState: function() {
     return {
diff --git a/IntegrationTests/LoggingTestModule.js b/IntegrationTests/LoggingTestModule.js
new file mode 100644
index 000000000000..96e59298d8be
--- /dev/null
+++ b/IntegrationTests/LoggingTestModule.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 LoggingTestModule
+ */
+'use strict';
+
+var warning = require('warning');
+var invariant = require('invariant');
+
+module.exports = {
+  logToConsole: function(str) {
+    console.log(str);
+  },
+  warning: function(str) {
+    warning(false, str);
+  },
+  invariant: function(str) {
+    invariant(false, str);
+  },
+  logErrorToConsole: function(str) {
+    console.error(str);
+  },
+  throwError: function(str) {
+    throw new Error(str);
+  }
+};
diff --git a/packager/react-packager/src/Resolver/polyfills/console.js b/packager/react-packager/src/Resolver/polyfills/console.js
index e08e8ef7ce71..5461602b0ed4 100644
--- a/packager/react-packager/src/Resolver/polyfills/console.js
+++ b/packager/react-packager/src/Resolver/polyfills/console.js
@@ -366,7 +366,6 @@
   };
 
   function setupConsole(global) {
-
     var originalConsole = global.console;
 
     if (!global.nativeLoggingHook) {
@@ -375,16 +374,23 @@
 
     function getNativeLogFunction(level) {
       return function() {
-        var str = Array.prototype.map.call(arguments, function(arg) {
-          return inspect(arg, {depth: 10});
-        }).join(', ');
-        if (str.slice(0, 10) === "'Warning: " && level >= LOG_LEVELS.error) {
+        var str;
+        if (arguments.length === 1 && typeof arguments[0] === 'string') {
+          str = arguments[0];
+        } else {
+          str = Array.prototype.map.call(arguments, function(arg) {
+            return inspect(arg, {depth: 10});
+          }).join(', ');
+        }
+
+        var logLevel = level;
+        if (str.slice(0, 9) === 'Warning: ' && logLevel >= LOG_LEVELS.error) {
           // React warnings use console.error so that a stack trace is shown,
           // but we don't (currently) want these to show a redbox
           // (Note: Logic duplicated in ExceptionsManager.js.)
-          level = LOG_LEVELS.warn;
+          logLevel = LOG_LEVELS.warn;
         }
-        global.nativeLoggingHook(str, level);
+        global.nativeLoggingHook(str, logLevel);
       };
     }
 

From 0fe074acbd460fc34aa8f43e51d30ed7e149cebb Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Fri, 20 Nov 2015 05:15:49 -0800
Subject: [PATCH 0019/1411] Removed all calls to [UIImage imageWithData:] on a
 background thread

Summary: public

I had previously assumed (based on past experience and common wisdom) that `[UIImage imageWithData:]` was safe to call concurrently and/or off the main thread, but it seems that may not be the case (see https://github.com/AFNetworking/AFNetworking/pull/2815).

This diff replaces `[UIImage imageWithData:]` with ImageIO-based decoding wherever possible, and ensures that it is called on the main thread wherever that's not possible/convenient.

I've also serialized access to the `NSURLCache` inside `RCTImageLoader`, which was causing a separate-but-similar crash when loading images.

Reviewed By: fkgozali

Differential Revision: D2678369

fb-gh-sync-id: 74d033dafcf6c412556e4c96f5ac5d3432298b18
---
 Libraries/Image/RCTImageLoader.m       | 210 ++++++++++++++-----------
 Libraries/Image/RCTImageStoreManager.m |   3 +-
 Libraries/Image/RCTImageUtils.m        |   3 +-
 React/Base/RCTConvert.m                |  14 +-
 4 files changed, 131 insertions(+), 99 deletions(-)

diff --git a/Libraries/Image/RCTImageLoader.m b/Libraries/Image/RCTImageLoader.m
index b345591a395e..8c77828b058b 100644
--- a/Libraries/Image/RCTImageLoader.m
+++ b/Libraries/Image/RCTImageLoader.m
@@ -37,7 +37,8 @@ @implementation RCTImageLoader
 {
   NSArray<id<RCTImageURLLoader>> *_loaders;
   NSArray<id<RCTImageDataDecoder>> *_decoders;
-  NSURLCache *_cache;
+  dispatch_queue_t _URLCacheQueue;
+  NSURLCache *_URLCache;
 }
 
 @synthesize bridge = _bridge;
@@ -87,9 +88,10 @@ - (void)setBridge:(RCTBridge *)bridge
   _bridge = bridge;
   _loaders = loaders;
   _decoders = decoders;
-  _cache = [[NSURLCache alloc] initWithMemoryCapacity:5 * 1024 * 1024 // 5MB
-                                         diskCapacity:200 * 1024 * 1024 // 200MB
-                                             diskPath:@"React/RCTImageDownloader"];
+  _URLCacheQueue = dispatch_queue_create("com.facebook.react.ImageLoaderURLCacheQueue", DISPATCH_QUEUE_SERIAL);
+  _URLCache = [[NSURLCache alloc] initWithMemoryCapacity:5 * 1024 * 1024 // 5MB
+                                            diskCapacity:200 * 1024 * 1024 // 200MB
+                                                diskPath:@"React/RCTImageDownloader"];
 }
 
 - (id<RCTImageURLLoader>)imageURLLoaderForURL:(NSURL *)URL
@@ -185,12 +187,10 @@ - (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag
                                       progressBlock:(RCTImageLoaderProgressBlock)progressHandler
                                     completionBlock:(RCTImageLoaderCompletionBlock)completionBlock
 {
-  if (imageTag.length == 0) {
-    RCTLogWarn(@"source.uri should not be an empty string <Native>");
-    return ^{};
-  }
-
   __block volatile uint32_t cancelled = 0;
+  __block void(^cancelLoad)(void) = nil;
+  __weak RCTImageLoader *weakSelf = self;
+
   RCTImageLoaderCompletionBlock completionHandler = ^(NSError *error, UIImage *image) {
     if ([NSThread isMainThread]) {
 
@@ -206,111 +206,133 @@ - (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag
     }
   };
 
-  // Find suitable image URL loader
-  NSURLRequest *request = [RCTConvert NSURLRequest:imageTag];
-  id<RCTImageURLLoader> loadHandler = [self imageURLLoaderForURL:request.URL];
-  if (loadHandler) {
-    return [loadHandler loadImageForURL:request.URL
-                                   size:size
-                                  scale:scale
-                             resizeMode:resizeMode
-                        progressHandler:progressHandler
-                      completionHandler:completionHandler] ?: ^{};
-  }
-
-  // Check if networking module is available
-  if (RCT_DEBUG && ![_bridge respondsToSelector:@selector(networking)]) {
-    RCTLogError(@"No suitable image URL loader found for %@. You may need to "
-                " import the RCTNetworking library in order to load images.",
-                imageTag);
+  if (imageTag.length == 0) {
+    completionHandler(RCTErrorWithMessage(@"source.uri should not be an empty string"), nil);
     return ^{};
   }
 
-  // Check if networking module can load image
-  if (RCT_DEBUG && ![_bridge.networking canHandleRequest:request]) {
-    RCTLogError(@"No suitable image URL loader found for %@", imageTag);
-    return ^{};
-  }
+  // All access to URL cache must be serialized
+  dispatch_async(_URLCacheQueue, ^{
+    RCTImageLoader *strongSelf = weakSelf;
+    if (cancelled || !strongSelf) {
+      return;
+    }
 
-  // Use networking module to load image
-  __weak RCTImageLoader *weakSelf = self;
-  __block RCTImageLoaderCancellationBlock decodeCancel = nil;
-  RCTURLRequestCompletionBlock processResponse =
-  ^(NSURLResponse *response, NSData *data, NSError *error) {
+    // Find suitable image URL loader
+    NSURLRequest *request = [RCTConvert NSURLRequest:imageTag];
+    id<RCTImageURLLoader> loadHandler = [strongSelf imageURLLoaderForURL:request.URL];
+    if (loadHandler) {
+      cancelLoad = [loadHandler loadImageForURL:request.URL
+                                           size:size
+                                          scale:scale
+                                     resizeMode:resizeMode
+                                progressHandler:progressHandler
+                              completionHandler:completionHandler] ?: ^{};
+      return;
+    }
 
-    // Check for system errors
-    if (error) {
-      completionHandler(error, nil);
+    // Check if networking module is available
+    if (RCT_DEBUG && ![_bridge respondsToSelector:@selector(networking)]) {
+      RCTLogError(@"No suitable image URL loader found for %@. You may need to "
+                  " import the RCTNetworking library in order to load images.",
+                  imageTag);
       return;
-    } else if (!data) {
-      completionHandler(RCTErrorWithMessage(@"Unknown image download error"), nil);
+    }
+
+    // Check if networking module can load image
+    if (RCT_DEBUG && ![_bridge.networking canHandleRequest:request]) {
+      RCTLogError(@"No suitable image URL loader found for %@", imageTag);
       return;
     }
 
-    // Check for http errors
-    if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
-      NSInteger statusCode = ((NSHTTPURLResponse *)response).statusCode;
-      if (statusCode != 200) {
-        completionHandler([[NSError alloc] initWithDomain:NSURLErrorDomain
-                                                     code:statusCode
-                                                 userInfo:nil], nil);
+    // Use networking module to load image
+    __block RCTImageLoaderCancellationBlock cancelDecode = nil;
+    RCTURLRequestCompletionBlock processResponse =
+    ^(NSURLResponse *response, NSData *data, NSError *error) {
+
+      // Check for system errors
+      if (error) {
+        completionHandler(error, nil);
+        return;
+      } else if (!data) {
+        completionHandler(RCTErrorWithMessage(@"Unknown image download error"), nil);
         return;
       }
-    }
 
-    // Decode image
-    decodeCancel = [weakSelf decodeImageData:data
-                                        size:size
-                                       scale:scale
-                                  resizeMode:resizeMode
-                             completionBlock:completionHandler];
-  };
-
-  // Check for cached response before reloading
-  // TODO: move URL cache out of RCTImageLoader into its own module
-  NSCachedURLResponse *cachedResponse = [_cache cachedResponseForRequest:request];
-  if (cachedResponse) {
-    processResponse(cachedResponse.response, cachedResponse.data, nil);
-    return ^{};
-  }
+      // Check for http errors
+      if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
+        NSInteger statusCode = ((NSHTTPURLResponse *)response).statusCode;
+        if (statusCode != 200) {
+          completionHandler([[NSError alloc] initWithDomain:NSURLErrorDomain
+                                                       code:statusCode
+                                                   userInfo:nil], nil);
+          return;
+        }
+      }
 
-  // Add missing png extension
-  if (request.URL.fileURL && request.URL.pathExtension.length == 0) {
-    NSMutableURLRequest *mutableRequest = [request mutableCopy];
-    mutableRequest.URL = [NSURL fileURLWithPath:[request.URL.path stringByAppendingPathExtension:@"png"]];
-    request = mutableRequest;
-  }
+      // Decode image
+      cancelDecode = [strongSelf decodeImageData:data
+                                            size:size
+                                           scale:scale
+                                      resizeMode:resizeMode
+                                 completionBlock:completionHandler];
+    };
 
-  // Download image
-  RCTNetworkTask *task = [_bridge.networking networkTaskWithRequest:request completionBlock:
-                          ^(NSURLResponse *response, NSData *data, NSError *error) {
-    if (error) {
-      completionHandler(error, nil);
-      return;
+    // Add missing png extension
+    if (request.URL.fileURL && request.URL.pathExtension.length == 0) {
+      NSMutableURLRequest *mutableRequest = [request mutableCopy];
+      mutableRequest.URL = [NSURL fileURLWithPath:[request.URL.path stringByAppendingPathExtension:@"png"]];
+      request = mutableRequest;
     }
 
-    // Cache the response
+    // Check for cached response before reloading
     // TODO: move URL cache out of RCTImageLoader into its own module
-    RCTImageLoader *strongSelf = weakSelf;
-    BOOL isHTTPRequest = [request.URL.scheme hasPrefix:@"http"];
-    [strongSelf->_cache storeCachedResponse:
-     [[NSCachedURLResponse alloc] initWithResponse:response
-                                              data:data
-                                          userInfo:nil
-                                     storagePolicy:isHTTPRequest ? NSURLCacheStorageAllowed: NSURLCacheStorageAllowedInMemoryOnly]
-                                 forRequest:request];
+    NSCachedURLResponse *cachedResponse = [_URLCache cachedResponseForRequest:request];
+    if (cachedResponse) {
+      processResponse(cachedResponse.response, cachedResponse.data, nil);
+    }
 
-    // Process image data
-    processResponse(response, data, nil);
+    // Download image
+    RCTNetworkTask *task = [_bridge.networking networkTaskWithRequest:request completionBlock:
+                            ^(NSURLResponse *response, NSData *data, NSError *error) {
+      if (error) {
+        completionHandler(error, nil);
+        return;
+      }
 
-  }];
-  task.downloadProgressBlock = progressHandler;
-  [task start];
+      dispatch_async(_URLCacheQueue, ^{
+
+        // Cache the response
+        // TODO: move URL cache out of RCTImageLoader into its own module
+        BOOL isHTTPRequest = [request.URL.scheme hasPrefix:@"http"];
+        [strongSelf->_URLCache storeCachedResponse:
+         [[NSCachedURLResponse alloc] initWithResponse:response
+                                                  data:data
+                                              userInfo:nil
+                                         storagePolicy:isHTTPRequest ? NSURLCacheStorageAllowed: NSURLCacheStorageAllowedInMemoryOnly]
+                                        forRequest:request];
+
+        // Process image data
+        processResponse(response, data, nil);
+
+      });
+
+    }];
+    task.downloadProgressBlock = progressHandler;
+    [task start];
+
+    cancelLoad = ^{
+      [task cancel];
+      if (cancelDecode) {
+        cancelDecode();
+      }
+    };
+
+  });
 
   return ^{
-    [task cancel];
-    if (decodeCancel) {
-      decodeCancel();
+    if (cancelLoad) {
+      cancelLoad();
     }
     OSAtomicOr32Barrier(1, &cancelled);
   };
@@ -342,7 +364,7 @@ - (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)data
       if (cancelled) {
         return;
       }
-      UIImage *image = [UIImage imageWithData:data scale:scale];
+      UIImage *image = RCTDecodeImageWithData(data, size, scale, resizeMode);
       if (image) {
         completionHandler(nil, image);
       } else {
diff --git a/Libraries/Image/RCTImageStoreManager.m b/Libraries/Image/RCTImageStoreManager.m
index f34a13e8d653..fe080101e7da 100644
--- a/Libraries/Image/RCTImageStoreManager.m
+++ b/Libraries/Image/RCTImageStoreManager.m
@@ -213,9 +213,8 @@ - (void)getImageForTag:(NSString *)imageTag withBlock:(void (^)(UIImage *image))
   RCTAssertParam(block);
   dispatch_async(_methodQueue, ^{
     NSData *imageData = _store[imageTag];
-    UIImage *image = [UIImage imageWithData:imageData];
     dispatch_async(dispatch_get_main_queue(), ^{
-      block(image);
+      block([UIImage imageWithData:imageData]);
     });
   });
 }
diff --git a/Libraries/Image/RCTImageUtils.m b/Libraries/Image/RCTImageUtils.m
index c05bf526b96c..3146a5b5611d 100644
--- a/Libraries/Image/RCTImageUtils.m
+++ b/Libraries/Image/RCTImageUtils.m
@@ -255,7 +255,8 @@ CGSize RCTSizeInPixels(CGSize pointSize, CGFloat scale)
 
   // adjust scale
   size_t actualWidth = CGImageGetWidth(imageRef);
-  CGFloat scale = actualWidth / targetSize.width;
+  CGFloat scale = actualWidth / targetSize.width * destScale;
+
   // return image
   UIImage *image = [UIImage imageWithCGImage:imageRef
                                        scale:scale
diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m
index 2531b69b9c38..53c6b9cad226 100644
--- a/React/Base/RCTConvert.m
+++ b/React/Base/RCTConvert.m
@@ -429,7 +429,18 @@ + (UIImage *)UIImage:(id)json
     return nil;
   }
 
-  UIImage *image;
+  __block UIImage *image;
+  if (![NSThread isMainThread]) {
+    // It seems that none of the UIImage loading methods can be guaranteed
+    // thread safe, so we'll pick the lesser of two evils here and block rather
+    // than run the risk of crashing
+    RCTLogWarn(@"Calling [RCTConvert UIImage:] on a background thread is not recommended");
+    dispatch_sync(dispatch_get_main_queue(), ^{
+      image = [self UIImage:json];
+    });
+    return image;
+  }
+
   NSString *path;
   CGFloat scale = 0.0;
   BOOL isPackagerAsset = NO;
@@ -452,7 +463,6 @@ + (UIImage *)UIImage:(id)json
     if (RCTIsXCAssetURL(URL)) {
       // Image may reside inside a .car file, in which case we have no choice
       // but to use +[UIImage imageNamed] - but this method isn't thread safe
-      RCTAssertMainThread();
       NSString *assetName = RCTBundlePathForURL(URL);
       image = [UIImage imageNamed:assetName];
     } else {

From 848a151ff815a242ba61e21c9fc384e0a6678934 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Fri, 20 Nov 2015 14:26:54 +0000
Subject: [PATCH 0020/1411] Add a bookmarklet to comment on questions

For higher accuraccy (and less clowniness) it might be better
to have the question bot only label issues that are potentially
questions and then have people quickly go through those issues
and use this bookmarklet to comment on them.
---
 bots/question-bookmarklet.js | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 bots/question-bookmarklet.js

diff --git a/bots/question-bookmarklet.js b/bots/question-bookmarklet.js
new file mode 100644
index 000000000000..f8d0ce52e96d
--- /dev/null
+++ b/bots/question-bookmarklet.js
@@ -0,0 +1 @@
+javascript:(function(){$('#new_comment_field')[0].value='Hey and thanks for reporting this!\n\nThis issue looks like a question - please use [Stack Overflow](http://stackoverflow.com/questions/tagged/react-native) for questions. It\'s the best system for Q&A and the best way to get questions answered.\n\nMany people from the community hang out on Stack Overflow and will be able to see your question and be more likely to answer because of the reputation system. If after reading this you think your question is better suited for Stack Overflow, please consider closing this issue.';$('button.btn-primary:contains("Comment")').click()})()
\ No newline at end of file

From 1195f9c8e8e47c25d90993218f9ea63123d71cc3 Mon Sep 17 00:00:00 2001
From: Krzysztof Magiera <krzysztof@fb.com>
Date: Fri, 20 Nov 2015 07:36:23 -0800
Subject: [PATCH 0021/1411] Further improvements in
 RecyclerViewBackedScrollView.

Summary: public
Changed ListView to use onLayout and onContentSizeChange (new) events instead of measure. Updated ScrollView implementation to support contentSizeChange event with an implementation based on onLayout attached to the content view. For RecyclerViewBackedScrollView we need to generate that event directly as it doesn't have a concept of content view.
This greatly improves performance of ListView that uses RecyclerViewBackedScrollView

Reviewed By: mkonicek

Differential Revision: D2679460

fb-gh-sync-id: ba26462d9d3b071965cbe46314f89f0dcfd9db9f
---
 .../RecyclerViewBackedScrollView.android.js   |  9 +++++
 Libraries/Components/ScrollView/ScrollView.js | 19 +++++++++
 .../CustomComponents/ListView/ListView.js     | 25 ++++++------
 .../recyclerview/ContentSizeChangeEvent.java  | 40 +++++++++++++++++++
 .../RecyclerViewBackedScrollView.java         | 36 ++++++++++++++---
 .../RecyclerViewBackedScrollViewManager.java  | 21 ++++++++++
 6 files changed, 133 insertions(+), 17 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/ContentSizeChangeEvent.java

diff --git a/Libraries/Components/ScrollView/RecyclerViewBackedScrollView.android.js b/Libraries/Components/ScrollView/RecyclerViewBackedScrollView.android.js
index c7b244a6323e..fa019c6be332 100644
--- a/Libraries/Components/ScrollView/RecyclerViewBackedScrollView.android.js
+++ b/Libraries/Components/ScrollView/RecyclerViewBackedScrollView.android.js
@@ -71,6 +71,11 @@ var RecyclerViewBackedScrollView = React.createClass({
     this.refs[INNERVIEW].setNativeProps(props);
   },
 
+  _handleContentSizeChange: function(event) {
+    var {width, height} = event.nativeEvent;
+    this.props.onContentSizeChange(width, height);
+  },
+
   render: function() {
     var props = {
       ...this.props,
@@ -92,6 +97,10 @@ var RecyclerViewBackedScrollView = React.createClass({
       ref: INNERVIEW,
     };
 
+    if (this.props.onContentSizeChange) {
+      props.onContentSizeChange = this._handleContentSizeChange;
+    }
+
     var wrappedChildren = React.Children.map(this.props.children, (child) => {
       if (!child) {
         return null;
diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js
index 7a2dc58e7b86..4d90f19d6c88 100644
--- a/Libraries/Components/ScrollView/ScrollView.js
+++ b/Libraries/Components/ScrollView/ScrollView.js
@@ -193,6 +193,12 @@ var ScrollView = React.createClass({
      * @platform ios
      */
     onScrollAnimationEnd: PropTypes.func,
+    /**
+     * Called when scrollable content view of the ScrollView changes. It's
+     * implemented using onLayout handler attached to the content container
+     * which this ScrollView renders.
+     */
+    onContentSizeChange: PropTypes.func,
     /**
      * When true, the scroll view stops on multiples of the scroll view's size
      * when scrolling. This can be used for horizontal pagination. The default
@@ -360,6 +366,11 @@ var ScrollView = React.createClass({
     this.scrollResponderHandleScroll(e);
   },
 
+  _handleContentOnLayout: function(event) {
+    var {width, height} = event.nativeEvent.layout;
+    this.props.onContentSizeChange && this.props.onContentSizeChange(width, height);
+  },
+
   render: function() {
     var contentContainerStyle = [
       this.props.horizontal && styles.contentContainerHorizontal,
@@ -376,8 +387,16 @@ var ScrollView = React.createClass({
       );
     }
 
+    var contentSizeChangeProps = {};
+    if (this.props.onContentSizeChange) {
+      contentSizeChangeProps = {
+        onLayout: this._handleContentOnLayout,
+      };
+    }
+
     var contentContainer =
       <View
+        {...contentSizeChangeProps}
         ref={INNERVIEW}
         style={contentContainerStyle}
         removeClippedSubviews={this.props.removeClippedSubviews}
diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js
index 6ea615ad530b..fb99f1687595 100644
--- a/Libraries/CustomComponents/ListView/ListView.js
+++ b/Libraries/CustomComponents/ListView/ListView.js
@@ -406,6 +406,8 @@ var ListView = React.createClass({
     // component's original ref instead of clobbering it
     return React.cloneElement(renderScrollComponent(props), {
       ref: SCROLLVIEW_REF,
+      onContentSizeChange: this._onContentSizeChange,
+      onLayout: this._onLayout,
     }, header, bodyComponents, footer);
   },
 
@@ -418,17 +420,6 @@ var ListView = React.createClass({
     if (!scrollComponent || !scrollComponent.getInnerViewNode) {
       return;
     }
-    RCTUIManager.measureLayout(
-      scrollComponent.getInnerViewNode(),
-      React.findNodeHandle(scrollComponent),
-      logError,
-      this._setScrollContentLength
-    );
-    RCTUIManager.measureLayoutRelativeToParent(
-      React.findNodeHandle(scrollComponent),
-      logError,
-      this._setScrollVisibleLength
-    );
 
     // RCTScrollViewManager.calculateChildFrames is not available on
     // every platform
@@ -439,9 +430,19 @@ var ListView = React.createClass({
       );
   },
 
-  _setScrollContentLength: function(left, top, width, height) {
+  _onContentSizeChange: function(width, height) {
     this.scrollProperties.contentLength = !this.props.horizontal ?
       height : width;
+    this._updateVisibleRows();
+    this._renderMoreRowsIfNeeded();
+  },
+
+  _onLayout: function(event) {
+    var {width, height} = event.nativeEvent.layout;
+    this.scrollProperties.visibleLength = !this.props.horizontal ?
+      height : width;
+    this._updateVisibleRows();
+    this._renderMoreRowsIfNeeded();
   },
 
   _setScrollVisibleLength: function(left, top, width, height) {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/ContentSizeChangeEvent.java b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/ContentSizeChangeEvent.java
new file mode 100644
index 000000000000..e7941872c1ba
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/ContentSizeChangeEvent.java
@@ -0,0 +1,40 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.views.recyclerview;
+
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.uimanager.PixelUtil;
+import com.facebook.react.uimanager.events.Event;
+import com.facebook.react.uimanager.events.RCTEventEmitter;
+
+/**
+ * Event dispatched by {@link RecyclerViewBackedScrollView} when total height of it's children
+ * changes
+ */
+public class ContentSizeChangeEvent extends Event<ContentSizeChangeEvent> {
+
+  public static final String EVENT_NAME = "topContentSizeChange";
+
+  private final int mWidth;
+  private final int mHeight;
+
+  public ContentSizeChangeEvent(int viewTag, long timestampMs, int width, int height) {
+    super(viewTag, timestampMs);
+    mWidth = width;
+    mHeight = height;
+  }
+
+  @Override
+  public String getEventName() {
+    return EVENT_NAME;
+  }
+
+  @Override
+  public void dispatch(RCTEventEmitter rctEventEmitter) {
+    WritableMap data = Arguments.createMap();
+    data.putDouble("width", PixelUtil.toDIPFromPixel(mWidth));
+    data.putDouble("height", PixelUtil.toDIPFromPixel(mHeight));
+    rctEventEmitter.receiveEvent(getViewTag(), EVENT_NAME, data);
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollView.java
index a419b58c38e8..054a9522220b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollView.java
@@ -148,6 +148,7 @@ public int getTopOffsetForItem(int index) {
 
     private final List<View> mViews = new ArrayList<>();
     private final ScrollOffsetTracker mScrollOffsetTracker;
+    private final RecyclerViewBackedScrollView mScrollView;
     private int mTotalChildrenHeight = 0;
 
     // The following `OnLayoutChangeListsner` is attached to the views stored in the adapter
@@ -173,7 +174,7 @@ public void onLayoutChange(
         int newHeight = (bottom - top);
 
         if (oldHeight != newHeight) {
-          mTotalChildrenHeight = mTotalChildrenHeight - oldHeight + newHeight;
+          updateTotalChildrenHeight(newHeight - oldHeight);
           mScrollOffsetTracker.onHeightChange(mViews.indexOf(v), oldHeight, newHeight);
 
           // Since "wrapper" view position +dimensions are not managed by NativeViewHierarchyManager
@@ -200,7 +201,8 @@ public void onLayoutChange(
       }
     };
 
-    public ReactListAdapter() {
+    public ReactListAdapter(RecyclerViewBackedScrollView scrollView) {
+      mScrollView = scrollView;
       mScrollOffsetTracker = new ScrollOffsetTracker(this);
       setHasStableIds(true);
     }
@@ -208,7 +210,7 @@ public ReactListAdapter() {
     public void addView(View child, int index) {
       mViews.add(index, child);
 
-      mTotalChildrenHeight += child.getMeasuredHeight();
+      updateTotalChildrenHeight(child.getMeasuredHeight());
       child.addOnLayoutChangeListener(mChildLayoutChangeListener);
 
       notifyItemInserted(index);
@@ -219,12 +221,19 @@ public void removeViewAt(int index) {
       if (child != null) {
         mViews.remove(index);
         child.removeOnLayoutChangeListener(mChildLayoutChangeListener);
-        mTotalChildrenHeight -= child.getMeasuredHeight();
+        updateTotalChildrenHeight(-child.getMeasuredHeight());
 
         notifyItemRemoved(index);
       }
     }
 
+    private void updateTotalChildrenHeight(int delta) {
+      if (delta != 0) {
+        mTotalChildrenHeight += delta;
+        mScrollView.onTotalChildrenHeightChange(mTotalChildrenHeight);
+      }
+    }
+
     @Override
     public ConcreteViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
       return new ConcreteViewHolder(new RecyclableWrapperViewGroup(parent.getContext()));
@@ -268,6 +277,12 @@ public int getTopOffsetForItem(int index) {
     }
   }
 
+  private boolean mSendContentSizeChangeEvents;
+
+  public void setSendContentSizeChangeEvents(boolean sendContentSizeChangeEvents) {
+    mSendContentSizeChangeEvents = sendContentSizeChangeEvents;
+  }
+
   private int calculateAbsoluteOffset() {
     int offsetY = 0;
     if (getChildCount() > 0) {
@@ -304,12 +319,23 @@ protected void onScrollChanged(int l, int t, int oldl, int oldt) {
                 getHeight()));
   }
 
+  private void onTotalChildrenHeightChange(int newTotalChildrenHeight) {
+    if (mSendContentSizeChangeEvents) {
+      ((ReactContext) getContext()).getNativeModule(UIManagerModule.class).getEventDispatcher()
+          .dispatchEvent(new ContentSizeChangeEvent(
+                  getId(),
+                  SystemClock.uptimeMillis(),
+                  getWidth(),
+                  newTotalChildrenHeight));
+    }
+  }
+
   public RecyclerViewBackedScrollView(Context context) {
     super(context);
     setHasFixedSize(true);
     setItemAnimator(new NotAnimatedItemAnimator());
     setLayoutManager(new LinearLayoutManager(context));
-    setAdapter(new ReactListAdapter());
+    setAdapter(new ReactListAdapter(this));
   }
 
   /*package*/ void addViewToAdapter(View child, int index) {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollViewManager.java
index 8c0134dad921..c49c26742ad1 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollViewManager.java
@@ -4,12 +4,17 @@
 
 import javax.annotation.Nullable;
 
+import java.util.Map;
+
 import android.view.View;
 
 import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.common.MapBuilder;
+import com.facebook.react.uimanager.ReactProp;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.ViewGroupManager;
 import com.facebook.react.views.scroll.ReactScrollViewCommandHelper;
+import com.facebook.react.views.scroll.ScrollEvent;
 
 /**
  * View manager for {@link RecyclerViewBackedScrollView}.
@@ -27,6 +32,11 @@ public String getName() {
 
   // TODO(8624925): Implement removeClippedSubviews support for native ListView
 
+  @ReactProp(name = "onContentSizeChange")
+  public void setOnContentSizeChange(RecyclerViewBackedScrollView view, boolean value) {
+    view.setSendContentSizeChangeEvents(value);
+  }
+
   @Override
   protected RecyclerViewBackedScrollView createViewInstance(ThemedReactContext reactContext) {
     return new RecyclerViewBackedScrollView(reactContext);
@@ -76,4 +86,15 @@ public void scrollWithoutAnimationTo(
       ReactScrollViewCommandHelper.ScrollToCommandData data) {
     view.scrollTo(data.mDestX, data.mDestY, false);
   }
+
+  @Override
+  public @Nullable
+  Map getExportedCustomDirectEventTypeConstants() {
+    return MapBuilder.builder()
+        .put(ScrollEvent.EVENT_NAME, MapBuilder.of("registrationName", "onScroll"))
+        .put(
+            ContentSizeChangeEvent.EVENT_NAME,
+            MapBuilder.of("registrationName", "onContentSizeChange"))
+        .build();
+  }
 }

From 06e514076b9f4b54a2211c9e104ec8e2dea71b14 Mon Sep 17 00:00:00 2001
From: Sebastian McKenzie <sebmck@gmail.com>
Date: Fri, 20 Nov 2015 07:52:36 -0800
Subject: [PATCH 0022/1411] Ensure correct Babel plugin locations in packager
 transform

Summary: Manually resolve all default Babel plugins. `babel.transform` will attempt to resolve all base plugins relative to the file it's compiling. This makes sure that we're using the plugins installed in the react-native package.

**NOTE:** Haven't tested this. Please don't merge until Travis has done CI.
Closes https://github.com/facebook/react-native/pull/4248

Reviewed By: svcscm

Differential Revision: D2679651

Pulled By: davidaurelio

fb-gh-sync-id: 0cdef1e738ba28c09c811432a71047f80540ed7b
---
 packager/transformer.js | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/packager/transformer.js b/packager/transformer.js
index ce984be9edb7..4700407c9368 100644
--- a/packager/transformer.js
+++ b/packager/transformer.js
@@ -37,6 +37,21 @@ function transform(src, filename, options) {
   }
   config.plugins = extraPlugins.concat(config.plugins);
 
+  // Manually resolve all default Babel plugins. babel.transform will attempt to resolve
+  // all base plugins relative to the file it's compiling. This makes sure that we're
+  // using the plugins installed in the react-native package.
+  config.plugins = config.plugins.map(function(plugin) {
+    // Normalise plugin to an array.
+    if (!Array.isArray(plugin)) {
+      plugin = [plugin];
+    }
+    // Only resolve the plugin if it's a string reference.
+    if (typeof plugin[0] === 'string') {
+      plugin[0] = require(`babel-plugin-${plugin[0]}`);
+    }
+    return plugin;
+  });
+
   const result = babel.transform(src, Object.assign({}, babelRC, config));
 
   return {

From 0c8850f3a76f2c6d3979fb6aa0403cab3f05a79d Mon Sep 17 00:00:00 2001
From: Krzysztof Magiera <krzysztof@fb.com>
Date: Fri, 20 Nov 2015 07:54:43 -0800
Subject: [PATCH 0023/1411] Only send layout update operation to
 nativehierarchymanager when layout actually changes.

Reviewed By: andreicoman11

Differential Revision: D2679408

fb-gh-sync-id: 7f0a972e9e12f70402e2d285edef458a61ca1c39
---
 .../react/uimanager/ReactShadowNode.java      | 38 +++++++++++++------
 .../react/uimanager/UIManagerModule.java      | 14 +------
 2 files changed, 29 insertions(+), 23 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java
index 73134194fb1b..bbf33b7b2ed2 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java
@@ -18,6 +18,7 @@
 import com.facebook.infer.annotation.Assertions;
 import com.facebook.react.bridge.ReadableMap;
 import com.facebook.react.bridge.ReadableMapKeySetIterator;
+import com.facebook.react.uimanager.events.EventDispatcher;
 
 /**
  * Base node class for representing virtual tree of React nodes. Shadow nodes are used primarily
@@ -202,18 +203,37 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
       float absoluteX,
       float absoluteY,
       UIViewOperationQueue uiViewOperationQueue,
-      NativeViewHierarchyOptimizer nativeViewHierarchyOptimizer) {
+      NativeViewHierarchyOptimizer nativeViewHierarchyOptimizer,
+      EventDispatcher eventDispatcher) {
     if (mNodeUpdated) {
       onCollectExtraUpdates(uiViewOperationQueue);
     }
 
     if (hasNewLayout()) {
-      mAbsoluteLeft = Math.round(absoluteX + getLayoutX());
-      mAbsoluteTop = Math.round(absoluteY + getLayoutY());
-      mAbsoluteRight = Math.round(absoluteX + getLayoutX() + getLayoutWidth());
-      mAbsoluteBottom = Math.round(absoluteY + getLayoutY() + getLayoutHeight());
-
-      nativeViewHierarchyOptimizer.handleUpdateLayout(this);
+      float absoluteLeft = Math.round(absoluteX + getLayoutX());
+      float absoluteTop = Math.round(absoluteY + getLayoutY());
+      float absoluteRight = Math.round(absoluteX + getLayoutX() + getLayoutWidth());
+      float absoluteBottom = Math.round(absoluteY + getLayoutY() + getLayoutHeight());
+      // If the layout didn't change this should calculate exactly same values, it's fine to compare
+      // floats with "==" in this case
+      if (absoluteLeft != mAbsoluteLeft || absoluteTop != mAbsoluteTop ||
+          absoluteRight != mAbsoluteRight || absoluteBottom != mAbsoluteBottom) {
+        mAbsoluteLeft = absoluteLeft;
+        mAbsoluteTop = absoluteTop;
+        mAbsoluteRight = absoluteRight;
+        mAbsoluteBottom = absoluteBottom;
+
+        nativeViewHierarchyOptimizer.handleUpdateLayout(this);
+        if (mShouldNotifyOnLayout) {
+          eventDispatcher.dispatchEvent(
+              OnLayoutEvent.obtain(
+                  getReactTag(),
+                  getScreenX(),
+                  getScreenY(),
+                  getScreenWidth(),
+                  getScreenHeight()));
+        }
+      }
     }
   }
 
@@ -264,10 +284,6 @@ public void setShouldNotifyOnLayout(boolean shouldNotifyOnLayout) {
     mShouldNotifyOnLayout = shouldNotifyOnLayout;
   }
 
-  /* package */ boolean shouldNotifyOnLayout() {
-    return mShouldNotifyOnLayout;
-  }
-
   /**
    * Adds a child that the native view hierarchy will have at this index in the native view
    * corresponding to this node.
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
index b0d61f61f563..a1d498e1c7c6 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
@@ -814,18 +814,8 @@ private void applyUpdatesRecursive(ReactShadowNode cssNode, float absoluteX, flo
           absoluteX,
           absoluteY,
           mOperationsQueue,
-          mNativeViewHierarchyOptimizer);
-
-      // notify JS about layout event if requested
-      if (cssNode.shouldNotifyOnLayout()) {
-        mEventDispatcher.dispatchEvent(
-            OnLayoutEvent.obtain(
-                tag,
-                cssNode.getScreenX(),
-                cssNode.getScreenY(),
-                cssNode.getScreenWidth(),
-                cssNode.getScreenHeight()));
-      }
+          mNativeViewHierarchyOptimizer,
+          mEventDispatcher);
     }
     cssNode.markUpdateSeen();
   }

From 205a35ad37ac99b6a1dbf8c0758ff2d063c54c3e Mon Sep 17 00:00:00 2001
From: Krzysztof Magiera <krzysztof@fb.com>
Date: Fri, 20 Nov 2015 08:02:35 -0800
Subject: [PATCH 0024/1411] View recycling in JS.

Summary: public
Native view recycling implementation based on limited pools of views.

In this diff I introduced new UIManager method: dropViews. Instead of removing views from tag->view maps when they are detached we keep them there until we get a call to dropViews with the appropriate tag. JS may keep a pool of object and selectively decide not to enqueue drop for certain views. Then instead of removing those views it may decide to reuse tag that has been previously allocated for a view that is no longer in use.

Special handling is required for layout-only nodes as they only can transition from layout-only to non-layout-only (reverse transition hasn't been implemented). Because of that we'd loose benefits of view flattening if we decide to recycle existing non-layout-only view as a layout-only one.

This diff provides only a simple and manual method for configuring pools by calling `ReactNativeViewPool.configure` with a dict from native view name to the view count. Note that we may not want recycle all the views (e.g. when we render mapview we don't want to keep it in memory after it's detached)

Reviewed By: davidaurelio

Differential Revision: D2677289

fb-gh-sync-id: 29f44ce5b01db3ec353522af051b6a50924614a2
---
 .../ReactNative/ReactNativeBaseComponent.js   |  21 +-
 Libraries/ReactNative/ReactNativeMount.js     |   2 +
 .../ReactNativeReconcileTransaction.js        |   9 +-
 Libraries/ReactNative/ReactNativeViewPool.js  | 265 ++++++++++++++++++
 .../uimanager/NativeViewHierarchyManager.java |  15 +-
 .../NativeViewHierarchyOptimizer.java         |   4 +
 .../react/uimanager/UIManagerModule.java      |  18 +-
 .../uimanager/UIManagerModuleConstants.java   |   8 +
 .../UIManagerModuleConstantsHelper.java       |   2 +
 .../react/uimanager/UIViewOperationQueue.java |  23 ++
 .../facebook/react/uimanager/ViewProps.java   |   2 +-
 11 files changed, 342 insertions(+), 27 deletions(-)
 create mode 100644 Libraries/ReactNative/ReactNativeViewPool.js

diff --git a/Libraries/ReactNative/ReactNativeBaseComponent.js b/Libraries/ReactNative/ReactNativeBaseComponent.js
index cfd3df3e832d..b187a39f0f97 100644
--- a/Libraries/ReactNative/ReactNativeBaseComponent.js
+++ b/Libraries/ReactNative/ReactNativeBaseComponent.js
@@ -16,6 +16,7 @@ var ReactNativeAttributePayload = require('ReactNativeAttributePayload');
 var ReactNativeEventEmitter = require('ReactNativeEventEmitter');
 var ReactNativeStyleAttributes = require('ReactNativeStyleAttributes');
 var ReactNativeTagHandles = require('ReactNativeTagHandles');
+var ReactNativeViewPool = require('ReactNativeViewPool');
 var ReactMultiChild = require('ReactMultiChild');
 var RCTUIManager = require('NativeModules').UIManager;
 
@@ -88,6 +89,7 @@ ReactNativeBaseComponent.Mixin = {
   unmountComponent: function() {
     deleteAllListeners(this._rootNodeID);
     this.unmountChildren();
+    ReactNativeViewPool.release(this);
     this._rootNodeID = null;
   },
 
@@ -204,24 +206,7 @@ ReactNativeBaseComponent.Mixin = {
   mountComponent: function(rootID, transaction, context) {
     this._rootNodeID = rootID;
 
-    var tag = ReactNativeTagHandles.allocateTag();
-
-    if (__DEV__) {
-      deepFreezeAndThrowOnMutationInDev(this._currentElement.props);
-    }
-
-    var updatePayload = ReactNativeAttributePayload.create(
-      this._currentElement.props,
-      this.viewConfig.validAttributes
-    );
-
-    var nativeTopRootID = ReactNativeTagHandles.getNativeTopRootIDFromNodeID(rootID);
-    RCTUIManager.createView(
-      tag,
-      this.viewConfig.uiViewClassName,
-      nativeTopRootID ? ReactNativeTagHandles.rootNodeIDToTag[nativeTopRootID] : null,
-      updatePayload
-    );
+    var tag = ReactNativeViewPool.acquire(this);
 
     this._registerListenersUponCreation(this._currentElement.props);
     this.initializeChildren(
diff --git a/Libraries/ReactNative/ReactNativeMount.js b/Libraries/ReactNative/ReactNativeMount.js
index 02dbcb40fc7e..aeef4cba77af 100644
--- a/Libraries/ReactNative/ReactNativeMount.js
+++ b/Libraries/ReactNative/ReactNativeMount.js
@@ -15,6 +15,7 @@ var RCTUIManager = require('NativeModules').UIManager;
 
 var ReactElement = require('ReactElement');
 var ReactNativeTagHandles = require('ReactNativeTagHandles');
+var ReactNativeViewPool = require('ReactNativeViewPool');
 var ReactPerf = require('ReactPerf');
 var ReactReconciler = require('ReactReconciler');
 var ReactUpdateQueue = require('ReactUpdateQueue');
@@ -216,6 +217,7 @@ var ReactNativeMount = {
     ReactNativeMount.unmountComponentAtNode(containerTag);
     // call back into native to remove all of the subviews from this container
     RCTUIManager.removeRootView(containerTag);
+    ReactNativeViewPool.clearPoolForRootView(containerTag);
   },
 
   /**
diff --git a/Libraries/ReactNative/ReactNativeReconcileTransaction.js b/Libraries/ReactNative/ReactNativeReconcileTransaction.js
index 309630e3cc36..aff41081d359 100644
--- a/Libraries/ReactNative/ReactNativeReconcileTransaction.js
+++ b/Libraries/ReactNative/ReactNativeReconcileTransaction.js
@@ -14,6 +14,7 @@
 var CallbackQueue = require('CallbackQueue');
 var PooledClass = require('PooledClass');
 var Transaction = require('Transaction');
+var ReactNativeViewPool = require('ReactNativeViewPool');
 
 /**
  * Provides a `CallbackQueue` queue for collecting `onDOMReady` callbacks during
@@ -35,12 +36,18 @@ var ON_DOM_READY_QUEUEING = {
   }
 };
 
+var RN_VIEW_POOL_WRAPPER = {
+  close: function() {
+    ReactNativeViewPool.onReconcileTransactionClose();
+  },
+};
+
 /**
  * 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];
+var TRANSACTION_WRAPPERS = [ON_DOM_READY_QUEUEING, RN_VIEW_POOL_WRAPPER];
 
 /**
  * Currently:
diff --git a/Libraries/ReactNative/ReactNativeViewPool.js b/Libraries/ReactNative/ReactNativeViewPool.js
new file mode 100644
index 000000000000..968449d8ba50
--- /dev/null
+++ b/Libraries/ReactNative/ReactNativeViewPool.js
@@ -0,0 +1,265 @@
+/**
+ * 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 ReactNativeViewPool
+ * @flow
+ */
+'use strict';
+
+var ReactNativeTagHandles = require('ReactNativeTagHandles');
+var ReactNativeAttributePayload = require('ReactNativeAttributePayload');
+var RCTUIManager = require('NativeModules').UIManager;
+var Platform = require('Platform');
+
+var deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
+var emptyFunction = require('emptyFunction');
+var flattenStyle = require('flattenStyle');
+
+var EMPTY_POOL = [[]];
+
+var ENABLED = !!RCTUIManager.dropViews;
+
+/* indicies used for _addToPool arrays */
+var TAGS_IDX = 0;
+var KEYS_IDX = 1;
+var PROPS_IDX = 2;
+
+var _pools = {};
+var _poolSize = {};
+
+var layoutOnlyProps = RCTUIManager.layoutOnlyProps;
+
+function isCollapsableForStyle(style) {
+  var flatStyle = flattenStyle(style);
+  for (var styleKey in flatStyle) {
+    if (layoutOnlyProps[styleKey] !== true) {
+      return false;
+    }
+  }
+  return true;
+}
+
+function isCollapsable(viewRef) {
+  var props = viewRef._currentElement.props;
+  if (props.collapsable !== undefined && !props.collapsable) {
+    return false;
+  }
+  var validAttributes = viewRef.viewConfig.validAttributes;
+  for (var propKey in props) {
+    if (!!validAttributes[propKey] && propKey !== 'style' && propKey !== 'collapsable') {
+      return false;
+    }
+  }
+  return !props.style || isCollapsableForStyle(viewRef._currentElement.props.style);
+}
+
+function enqueueCreate(viewRef, rootTag) {
+  var tag = ReactNativeTagHandles.allocateTag();
+
+  if (__DEV__) {
+    deepFreezeAndThrowOnMutationInDev(viewRef._currentElement.props);
+  }
+
+  var updatePayload = ReactNativeAttributePayload.create(
+    viewRef._currentElement.props,
+    viewRef.viewConfig.validAttributes
+  );
+
+  RCTUIManager.createView(
+    tag,
+    viewRef.viewConfig.uiViewClassName,
+    rootTag,
+    updatePayload
+  );
+
+  return tag;
+}
+
+function getViewTag(viewRef) {
+  return ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(viewRef._rootNodeID);
+}
+
+function getViewProps(viewRef) {
+  return viewRef._currentElement.props;
+}
+
+function getViewValidAttributes(viewRef) {
+  return viewRef.viewConfig.validAttributes;
+}
+
+function getRootViewTag(viewRef) {
+  var nativeTopRootID = ReactNativeTagHandles.getNativeTopRootIDFromNodeID(viewRef._rootNodeID);
+  return ReactNativeTagHandles.rootNodeIDToTag[nativeTopRootID];
+}
+
+function poolKey(viewRef) {
+  var viewClass = viewRef.viewConfig.uiViewClassName;
+  if (Platform.OS === 'android' && viewClass === 'RCTView') {
+    return isCollapsable(viewRef) ? 'CollapsedRCTView' : 'RCTView';
+  }
+  return viewClass;
+}
+
+class ReactNativeViewPool {
+  constructor() {
+    this._pool = {};
+    this._poolQueue = {};
+    this._addToPool = [[],[],[]];
+    this._viewsToDelete = [];
+    if (__DEV__) {
+      this._recycleStats = {};
+      this._deleteStats = {};
+    }
+  }
+
+  onReconcileTransactionClose() {
+    // flush all deletes, move object from pool_queue to the actual pool
+    if (this._viewsToDelete.length > 0) {
+      RCTUIManager.dropViews(this._viewsToDelete);
+    }
+    var addToPoolTags = this._addToPool[TAGS_IDX];
+    var addToPoolKeys = this._addToPool[KEYS_IDX];
+    var addToPoolProps = this._addToPool[PROPS_IDX];
+    for (var i = addToPoolTags.length - 1; i >= 0; i--) {
+      var nativeTag = addToPoolTags[i];
+      var key = addToPoolKeys[i];
+      var props = addToPoolProps[i];
+      var views = this._pool[key] || [[],[]];
+      views[0].push(nativeTag);
+      views[1].push(props);
+      this._pool[key] = views;
+    }
+    this._viewsToDelete = [];
+    this._addToPool = [[],[],[]];
+    this._poolQueue = {};
+  }
+
+  acquire(viewRef, rootTag) {
+    var key = poolKey(viewRef);
+    if ((this._pool[key] || EMPTY_POOL)[0].length) {
+      var views = this._pool[key];
+      var nativeTag = views[0].pop();
+      var oldProps = views[1].pop();
+      var updatePayload = ReactNativeAttributePayload.diff(
+        oldProps,
+        getViewProps(viewRef),
+        getViewValidAttributes(viewRef)
+      );
+      if (__DEV__) {
+        this._recycleStats[key] = (this._recycleStats[key] || 0) + 1;
+      }
+
+      if (updatePayload) {
+        RCTUIManager.updateView(
+          nativeTag,
+          viewRef.viewConfig.uiViewClassName,
+          updatePayload
+        );
+      }
+      return nativeTag;
+    } else {
+      // If there is no view available for the given pool key, we just enqueue call to create one
+      return enqueueCreate(viewRef, rootTag);
+    }
+  }
+
+  release(viewRef) {
+    var key = poolKey(viewRef);
+    var nativeTag = getViewTag(viewRef);
+    var pooledCount = (this._pool[key] || EMPTY_POOL)[0].length + (this._poolQueue[key] || 0);
+    if (pooledCount < (_poolSize[key] || 0)) {
+      // we have room in the pool for this view
+      // we can add it to the queue so that it will be added to the actual pull in
+      // onReconcileTransactionClose
+      this._addToPool[TAGS_IDX].push(nativeTag);
+      this._addToPool[KEYS_IDX].push(key);
+      this._addToPool[PROPS_IDX].push(getViewProps(viewRef));
+      this._poolQueue[key] = (this._poolQueue[key] || 0) + 1;
+    } else {
+      if (__DEV__) {
+        if (_poolSize[key]) {
+          this._deleteStats[key] = (this._deleteStats[key] || 0) + 1;
+        }
+      }
+      this._viewsToDelete.push(nativeTag);
+    }
+  }
+
+  clear() {
+    for (var key in this._pool) {
+      var poolTags = this._pool[key][0];
+      for (var i = poolTags.length - 1; i >= 0; i--) {
+        this._viewsToDelete.push(poolTags[i]);
+      }
+    }
+    var addToPoolTags = this._addToPool[0];
+    for (var i = addToPoolTags.length - 1; i >= 0; i--) {
+      this._viewsToDelete.push(addToPoolTags[i]);
+    }
+    this._addToPool = [[],[],[]];
+    this.onReconcileTransactionClose();
+  }
+
+  printStats() {
+    if (__DEV__) {
+      console.log('Stats', this._recycleStats, this._deleteStats);
+    }
+  }
+}
+
+module.exports = {
+
+  onReconcileTransactionClose: function() {
+    if (ENABLED) {
+      for (var pool in _pools) {
+        _pools[pool].onReconcileTransactionClose();
+      }
+    }
+  },
+
+  acquire: function(viewRef) {
+    var rootTag = getRootViewTag(viewRef);
+    if (ENABLED) {
+      var pool = _pools[rootTag];
+      if (!pool) {
+        pool = _pools[rootTag] = new ReactNativeViewPool();
+      }
+      return pool.acquire(viewRef, rootTag);
+    } else {
+      return enqueueCreate(viewRef, rootTag);
+    }
+  },
+
+  release: ENABLED ? function(viewRef) {
+    var pool = _pools[getRootViewTag(viewRef)];
+    if (pool) {
+      pool.release(viewRef);
+    }
+  } : emptyFunction,
+
+  clearPoolForRootView: ENABLED ? function(rootID) {
+    var pool = _pools[rootID];
+    if (pool) {
+      pool.clear();
+      delete _pools[rootID];
+    }
+  } : emptyFunction,
+
+  configure: function(pool_size) {
+    _poolSize = pool_size;
+  },
+
+  printStats: function() {
+    if (__DEV__) {
+      console.log('Pool size', _poolSize);
+      for (var pool in _pools) {
+        _pools[pool].onReconcileTransactionClose();
+      }
+    }
+  },
+};
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
index 68a1e567f038..0b7b7e1f08ba 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
@@ -349,7 +349,7 @@ public void manageChildren(
                       viewsToAdd,
                       tagsToDelete));
         }
-        dropView(viewToDestroy);
+        detachView(viewToDestroy);
       }
     }
   }
@@ -378,10 +378,15 @@ public void addRootView(
     view.setId(tag);
   }
 
+  public void dropView(int tag) {
+    mTagsToViews.remove(tag);
+    mTagsToViewManagers.remove(tag);
+  }
+
   /**
    * Releases all references to given native View.
    */
-  private void dropView(View view) {
+  private void detachView(View view) {
     UiThreadUtil.assertOnUiThread();
     if (!mRootTags.get(view.getId())) {
       // For non-root views we notify viewmanager with {@link ViewManager#onDropInstance}
@@ -396,13 +401,11 @@ private void dropView(View view) {
       for (int i = viewGroupManager.getChildCount(viewGroup) - 1; i >= 0; i--) {
         View child = viewGroupManager.getChildAt(viewGroup, i);
         if (mTagsToViews.get(child.getId()) != null) {
-          dropView(child);
+          detachView(child);
         }
       }
       viewGroupManager.removeAllViews(viewGroup);
     }
-    mTagsToViews.remove(view.getId());
-    mTagsToViewManagers.remove(view.getId());
   }
 
   public void removeRootView(int rootViewTag) {
@@ -412,7 +415,7 @@ public void removeRootView(int rootViewTag) {
             "View with tag " + rootViewTag + " is not registered as a root view");
     }
     View rootView = mTagsToViews.get(rootViewTag);
-    dropView(rootView);
+    detachView(rootView);
     mRootTags.delete(rootViewTag);
     mRootViewsContext.remove(rootViewTag);
   }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java
index fd3946eeb7c9..e01fab28dcce 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java
@@ -90,6 +90,10 @@ public void handleCreateView(
     }
   }
 
+  public void handleDropViews(int[] viewTagsToDrop, int length) {
+    mUIViewOperationQueue.enqueueDropViews(viewTagsToDrop, length);
+  }
+
   /**
    * Handles native children cleanup when css node is removed from hierarchy
    */
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
index a1d498e1c7c6..6482a209b332 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
@@ -261,6 +261,23 @@ public void createView(int tag, String className, int rootViewTag, ReadableMap p
     }
   }
 
+  @ReactMethod
+  public void dropViews(ReadableArray viewTags) {
+    int size = viewTags.size(), realViewsCount = 0;
+    int realViewTags[] = new int[size];
+    for (int i = 0; i < size; i++) {
+      int tag = viewTags.getInt(i);
+      ReactShadowNode cssNode = mShadowNodeRegistry.getNode(tag);
+      if (!cssNode.isVirtual()) {
+        realViewTags[realViewsCount++] = tag;
+      }
+      mShadowNodeRegistry.removeNode(tag);
+    }
+    if (realViewsCount > 0) {
+      mNativeViewHierarchyOptimizer.handleDropViews(realViewTags, realViewsCount);
+    }
+  }
+
   @ReactMethod
   public void updateView(int tag, String className, ReadableMap props) {
     ViewManager viewManager = mViewManagers.get(className);
@@ -405,7 +422,6 @@ public void manageChildren(
 
   private void removeShadowNode(ReactShadowNode nodeToRemove) {
     mNativeViewHierarchyOptimizer.handleRemoveNode(nodeToRemove);
-    mShadowNodeRegistry.removeNode(nodeToRemove.getReactTag());
     for (int i = nodeToRemove.getChildCount() - 1; i >= 0; i--) {
       removeShadowNode(nodeToRemove.getChildAt(i));
     }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java
index 3287ebf7854c..eab1c3489170 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java
@@ -154,4 +154,12 @@ public static Map<String, Object> getConstants(DisplayMetrics displayMetrics) {
 
     return constants;
   }
+
+  public static Map<String, Object> getLayoutOnlyPropsConstants() {
+    HashMap<String, Object> constants = new HashMap<>();
+    for (String propName : ViewProps.LAYOUT_ONLY_PROPS) {
+      constants.put(propName, Boolean.TRUE);
+    }
+    return constants;
+  }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java
index bce7c37361b2..d5b566529729 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java
@@ -25,6 +25,7 @@
 
   private static final String CUSTOM_BUBBLING_EVENT_TYPES_KEY = "customBubblingEventTypes";
   private static final String CUSTOM_DIRECT_EVENT_TYPES_KEY = "customDirectEventTypes";
+  private static final String LAYOUT_ONLY_PROPS = "layoutOnlyProps";
 
   /**
    * Generates map of constants that is then exposed by {@link UIManagerModule}. The constants map
@@ -75,6 +76,7 @@
 
     constants.put(CUSTOM_BUBBLING_EVENT_TYPES_KEY, bubblingEventTypesConstants);
     constants.put(CUSTOM_DIRECT_EVENT_TYPES_KEY, directEventTypesConstants);
+    constants.put(LAYOUT_ONLY_PROPS, UIManagerModuleConstants.getLayoutOnlyPropsConstants());
 
     return constants;
   }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
index 739558938334..bb9cea705cb3 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
@@ -142,6 +142,25 @@ public void execute() {
     }
   }
 
+  private final class DropViewsOperation extends ViewOperation {
+
+    private final int[] mViewTagsToDrop;
+    private final int mArrayLength;
+
+    public DropViewsOperation(int[] viewTagsToDrop, int length) {
+      super(-1);
+      mViewTagsToDrop = viewTagsToDrop;
+      mArrayLength = length;
+    }
+
+    @Override
+    public void execute() {
+      for (int i = 0; i < mArrayLength; i++) {
+        mNativeViewHierarchyManager.dropView(mViewTagsToDrop[i]);
+      }
+    }
+  }
+
   private final class ManageChildrenOperation extends ViewOperation {
 
     private final @Nullable int[] mIndicesToRemove;
@@ -502,6 +521,10 @@ public void enqueueCreateView(
             initialProps));
   }
 
+  public void enqueueDropViews(int[] viewTagsToDrop, int length) {
+    mOperations.add(new DropViewsOperation(viewTagsToDrop, length));
+  }
+
   public void enqueueUpdateProperties(int reactTag, String className, CatalystStylesDiffMap props) {
     mOperations.add(new UpdatePropertiesOperation(reactTag, props));
   }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java
index 7e87a8419d85..d19ea165e904 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java
@@ -84,7 +84,7 @@ public class ViewProps {
       Spacing.BOTTOM
   };
 
-  private static final HashSet<String> LAYOUT_ONLY_PROPS = new HashSet<>(
+  /*package*/ static final HashSet<String> LAYOUT_ONLY_PROPS = new HashSet<>(
       Arrays.asList(
             ALIGN_SELF,
             ALIGN_ITEMS,

From a7c4ed106b28c609aa10f016e84e4bf22298d65c Mon Sep 17 00:00:00 2001
From: Saurabh Aggarwal <saurabhagg@fb.com>
Date: Fri, 20 Nov 2015 08:56:15 -0800
Subject: [PATCH 0025/1411] Adds stetho interceptor to the OSS react native
 networking module

Reviewed By: mkonicek

Differential Revision: D2669416

fb-gh-sync-id: d061711a412348b16ffb877e0178a05460fd95f2
---
 ReactAndroid/build.gradle                                       | 2 ++
 .../com/facebook/react/modules/network/NetworkingModule.java    | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle
index 13d95719b767..b9dc2f04610e 100644
--- a/ReactAndroid/build.gradle
+++ b/ReactAndroid/build.gradle
@@ -248,6 +248,8 @@ dependencies {
     compile 'com.android.support:recyclerview-v7:23.0.1'
     compile 'com.facebook.fresco:fresco:0.8.1'
     compile 'com.facebook.fresco:imagepipeline-okhttp:0.8.1'
+    compile 'com.facebook.stetho:stetho:1.2.0'
+    compile 'com.facebook.stetho:stetho-okhttp:1.2.0'
     compile 'com.fasterxml.jackson.core:jackson-core:2.2.3'
     compile 'com.google.code.findbugs:jsr305:3.0.0'
     compile 'com.squareup.okhttp:okhttp:2.5.0'
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
index 39d2cb8109ce..4ddbf1f60587 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
@@ -25,6 +25,7 @@
 import com.facebook.react.bridge.WritableArray;
 import com.facebook.react.bridge.WritableMap;
 import com.facebook.react.modules.core.DeviceEventManagerModule;
+import com.facebook.stetho.okhttp.StethoInterceptor;
 
 import com.squareup.okhttp.Callback;
 import com.squareup.okhttp.Headers;
@@ -65,6 +66,7 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
       OkHttpClient client) {
     super(reactContext);
     mClient = client;
+    mClient.networkInterceptors().add(new StethoInterceptor());
     mShuttingDown = false;
     mDefaultUserAgent = defaultUserAgent;
   }

From 155a609781870db8293f37799efeee442f5f3152 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Fri, 20 Nov 2015 09:51:58 -0800
Subject: [PATCH 0026/1411] Unbreak tests

Summary: The recent commits for RecyclerViewBackedScrollView introduced a bunch of Flow errors.

Disable Flow for now in `ReactNativeViewPool` as it looks like that file doesn't use Flow :)

public

Reviewed By: gabelevi

Differential Revision: D2679974

fb-gh-sync-id: 71512f403e3fa271f6c0fa1a64e877ca1750f675
---
 Libraries/Components/ScrollView/ScrollView.js | 6 +++---
 Libraries/ReactNative/ReactNativeViewPool.js  | 1 -
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js
index 4d90f19d6c88..a23ac8c5d505 100644
--- a/Libraries/Components/ScrollView/ScrollView.js
+++ b/Libraries/Components/ScrollView/ScrollView.js
@@ -346,7 +346,7 @@ var ScrollView = React.createClass({
     );
   },
 
-  handleScroll: function(e: Event) {
+  handleScroll: function(e: Object) {
     if (__DEV__) {
       if (this.props.onScroll && !this.props.scrollEventThrottle) {
         console.log(
@@ -366,8 +366,8 @@ var ScrollView = React.createClass({
     this.scrollResponderHandleScroll(e);
   },
 
-  _handleContentOnLayout: function(event) {
-    var {width, height} = event.nativeEvent.layout;
+  _handleContentOnLayout: function(e: Object) {
+    var {width, height} = e.nativeEvent.layout;
     this.props.onContentSizeChange && this.props.onContentSizeChange(width, height);
   },
 
diff --git a/Libraries/ReactNative/ReactNativeViewPool.js b/Libraries/ReactNative/ReactNativeViewPool.js
index 968449d8ba50..dd0a596165a0 100644
--- a/Libraries/ReactNative/ReactNativeViewPool.js
+++ b/Libraries/ReactNative/ReactNativeViewPool.js
@@ -7,7 +7,6 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule ReactNativeViewPool
- * @flow
  */
 'use strict';
 

From 7febd1367656aa1c337f62763624078f9e3062f8 Mon Sep 17 00:00:00 2001
From: Milen Dzhumerov <mgd@fb.com>
Date: Fri, 20 Nov 2015 10:03:21 -0800
Subject: [PATCH 0027/1411] Attach to all RelayProfiler events

Summary: public

Dynamically profile events from RelayProfiler if available. This will expose time spent in Relay in the systraces.

Reviewed By: tadeuzagallo

Differential Revision: D2674215

fb-gh-sync-id: d5f9d529b86d267a80b0cda2223f6a28a08ac385
---
 .../InitializeJavaScriptAppEngine.js           |  4 +++-
 Libraries/Utilities/BridgeProfiling.js         | 18 ++++++++++++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
index 501d4c9cc329..8735e1ab004b 100644
--- a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
+++ b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
@@ -160,7 +160,9 @@ function setUpWebSockets() {
 
 function setUpProfile() {
   if (__DEV__) {
-    require('BridgeProfiling').swizzleReactPerf();
+    var BridgeProfiling = require('BridgeProfiling');
+    BridgeProfiling.swizzleReactPerf();
+    BridgeProfiling.attachToRelayProfiler();
   }
 }
 
diff --git a/Libraries/Utilities/BridgeProfiling.js b/Libraries/Utilities/BridgeProfiling.js
index 16b6a7159339..e62c8b76dcec 100644
--- a/Libraries/Utilities/BridgeProfiling.js
+++ b/Libraries/Utilities/BridgeProfiling.js
@@ -61,6 +61,24 @@ var BridgeProfiling = {
   swizzleReactPerf() {
     ReactPerf().injection.injectMeasure(BridgeProfiling.reactPerfMeasure);
   },
+
+  attachToRelayProfiler() {
+    // We don't want to create a dependency on `RelayProfiler`, so that's why
+    // we require it indirectly (rather than using a literal string). Since
+    // there's no guarantee that the module will be present, we must wrap
+    // everything in a try-catch block as requiring a non-existing module
+    // will just throw.
+    try {
+      var rpName = 'RelayProfiler';
+      var RelayProfiler = require(rpName);
+      RelayProfiler.attachProfileHandler('*', (name) => {
+        BridgeProfiling.profile(name);
+        return () => {
+          BridgeProfiling.profileEnd();
+        };
+      });
+    } catch(err) {}
+  }
 };
 
 BridgeProfiling.setEnabled(global.__RCTProfileIsProfiling || false);

From 67209e6396516358ec47d68eeb14b84f8d0d7991 Mon Sep 17 00:00:00 2001
From: Marc Horowitz <mhorowitz@fb.com>
Date: Fri, 20 Nov 2015 09:09:36 -0800
Subject: [PATCH 0028/1411] If fbsystrace is running when catalyst starts, it
 asserts

Summary: registering with systrace checks if the bridge is
initialized, which it's not yet in the ctor.  Defer registration until
after the bridge is created, and only unregister in that case.
public

Reviewed By: astreet, dreiss

Differential Revision: D2651244

fb-gh-sync-id: 8da1108e9d15fddde48d06f4ed61ee0f787016ad
---
 .../java/com/facebook/react/bridge/CatalystInstance.java     | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
index c96ddb8e469d..f8d7bff457e1 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
@@ -82,7 +82,6 @@ private CatalystInstance(
     mJSBundleLoader = jsBundleLoader;
     mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
     mTraceListener = new JSProfilerTraceListener();
-    Systrace.registerListener(mTraceListener);
 
     final CountDownLatch initLatch = new CountDownLatch(1);
     mCatalystQueueConfiguration.getJSQueueThread().runOnQueue(
@@ -116,6 +115,8 @@ private void initializeBridge(
     mBridge.setGlobalVariable(
         "__fbBatchedBridgeConfig",
         buildModulesConfigJSONProperty(mJavaRegistry, jsModulesConfig));
+
+    Systrace.registerListener(mTraceListener);
   }
 
   public void runJSBundle() {
@@ -239,7 +240,7 @@ public void run() {
       }
     }
 
-    if (mTraceListener != null) {
+    if (mBridge != null) {
       Systrace.unregisterListener(mTraceListener);
     }
 

From 60b67a447dab883bad8065cf719eb4acc6db6e55 Mon Sep 17 00:00:00 2001
From: Mike Fowler <mike@mikefowler.me>
Date: Fri, 20 Nov 2015 11:38:04 -0800
Subject: [PATCH 0029/1411] Update Animations.md

Add a better explanation of the extrapolation options.
---
 docs/Animations.md | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/docs/Animations.md b/docs/Animations.md
index a18f0f78ce69..22a5f1c0f514 100644
--- a/docs/Animations.md
+++ b/docs/Animations.md
@@ -168,9 +168,11 @@ Input | Output
 already implemented in the
 [`Easing`](https://github.com/facebook/react-native/blob/master/Libraries/Animation/Animated/Easing.js)
 class including quadratic, exponential, and bezier curves as well as functions
-like step and bounce.  `interpolation` also has configurable behavior for
-extrapolation, the default being `'extend'`, but `'clamp'` is also very useful
-to prevent the output value from exceeding `outputRange`.
+like step and bounce. `interpolation` also has configurable behavior for
+extrapolating the `outputRange`. You can set the extrapolation by setting the `extrapolate`, 
+`extrapolateLeft` or `extrapolateRight` options. The default value is 
+`extend` but you can use `clamp` to prevent the output value from exceeding 
+`outputRange`.
 
 #### Tracking Dynamic Values
 

From f2a10d1f169f419fbae16c4186f1cc1cbcd0d6ce Mon Sep 17 00:00:00 2001
From: Ricky Reusser <rsreusser@gmail.com>
Date: Fri, 20 Nov 2015 14:59:33 -0500
Subject: [PATCH 0030/1411] Additional note for Android borderRadius clipping
 #3198

---
 docs/KnownIssues.md | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/docs/KnownIssues.md b/docs/KnownIssues.md
index 9fc543299707..27f677da218a 100644
--- a/docs/KnownIssues.md
+++ b/docs/KnownIssues.md
@@ -65,7 +65,9 @@ There is currently no easy way of publishing custom native modules on Android. S
 
 ### The `overflow` style property defaults to `hidden` and cannot be changed on Android
 
-This is a result of how Android rendering works. This feature is not being worked on as it would be a significant undertaking and there are many more important tasks.
+This is a result of how Android rendering works. This feature is not being worked on as it would be a significant undertaking and there are many more important tasks. 
+
+Another issue with `overflow: 'hidden'` on Android: a view is not clipped by the parent's `borderRadius` even if the parent has `overflow: 'hidden'` enabled – the corners of the inner view will be visible outside of the rounded corners. This is only on Android; it works as expected on iOS. See a [demo of the bug](https://rnplay.org/apps/BlGjdQ) and the [corresponding issue](https://github.com/facebook/react-native/issues/3198).
 
 ### No support for shadows on Android
 

From 5b6b5a64d195d03bf407f5e460915d50268370ce Mon Sep 17 00:00:00 2001
From: Marc Horowitz <mhorowitz@fb.com>
Date: Fri, 20 Nov 2015 12:16:19 -0800
Subject: [PATCH 0031/1411] Split JavaSJExecutor and ProxyExecutorException
 into their own file

Summary: This makes the exception a nested class of the interface,
which eliminates the dependency of DevSupportManager on
ProxyJavaScriptExecutor.
public

Reviewed By: astreet

Differential Revision: D2651252

fb-gh-sync-id: 99de1c308b9bce717ab749c4e239d2773a920e1f
---
 .../facebook/react/ReactInstanceManager.java  |  9 ++--
 .../facebook/react/bridge/JavaJSExecutor.java | 54 +++++++++++++++++++
 .../react/bridge/ProxyJavaScriptExecutor.java | 42 ---------------
 .../bridge/WebsocketJavaScriptExecutor.java   | 10 ++--
 .../react/devsupport/DevSupportManager.java   |  2 +-
 .../ReactInstanceDevCommandsHandler.java      |  4 +-
 .../src/main/jni/react/jni/OnLoad.cpp         |  2 +-
 .../src/main/jni/react/jni/ProxyExecutor.cpp  |  2 +-
 8 files changed, 69 insertions(+), 56 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/JavaJSExecutor.java

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
index b8cf21b23417..ba4cd8d12abb 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
@@ -28,6 +28,7 @@
 import com.facebook.react.bridge.CatalystInstance;
 import com.facebook.react.bridge.JSBundleLoader;
 import com.facebook.react.bridge.JSCJavaScriptExecutor;
+import com.facebook.react.bridge.JavaJSExecutor;
 import com.facebook.react.bridge.JavaScriptExecutor;
 import com.facebook.react.bridge.JavaScriptModule;
 import com.facebook.react.bridge.JavaScriptModulesConfig;
@@ -97,8 +98,8 @@ public class ReactInstanceManager {
       new ReactInstanceDevCommandsHandler() {
 
         @Override
-        public void onReloadWithJSDebugger(ProxyJavaScriptExecutor proxyExecutor) {
-          ReactInstanceManager.this.onReloadWithJSDebugger(proxyExecutor);
+        public void onReloadWithJSDebugger(JavaJSExecutor jsExecutor) {
+          ReactInstanceManager.this.onReloadWithJSDebugger(jsExecutor);
         }
 
         @Override
@@ -474,9 +475,9 @@ public String getSourceUrl() {
     return mCurrentReactContext;
   }
 
-  private void onReloadWithJSDebugger(ProxyJavaScriptExecutor proxyExecutor) {
+  private void onReloadWithJSDebugger(JavaJSExecutor jsExecutor) {
     recreateReactContextInBackground(
-        proxyExecutor,
+        new ProxyJavaScriptExecutor(jsExecutor),
         JSBundleLoader.createRemoteDebuggerBundleLoader(
             mDevSupportManager.getJSBundleURLForRemoteDebugging()));
   }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaJSExecutor.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaJSExecutor.java
new file mode 100644
index 000000000000..76b8a1cb5275
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaJSExecutor.java
@@ -0,0 +1,54 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.bridge;
+
+import com.facebook.proguard.annotations.DoNotStrip;
+
+/**
+ * This is class represents java version of native js executor interface. When set through
+ * {@link ProxyJavaScriptExecutor} as a {@link CatalystInstance} executor, native code will
+ * delegate js calls to the given implementation of this interface.
+ */
+@DoNotStrip
+public interface JavaJSExecutor {
+  public static class ProxyExecutorException extends Exception {
+    public ProxyExecutorException(Throwable cause) {
+      super(cause);
+    }
+  }
+
+  /**
+   * Close this executor and cleanup any resources that it was using. No further calls are
+   * expected after this.
+   */
+  void close();
+
+  /**
+   * Load javascript into the js context
+   * @param script script contet to be executed
+   * @param sourceURL url or file location from which script content was loaded
+   */
+  @DoNotStrip
+  void executeApplicationScript(String script, String sourceURL) throws ProxyExecutorException;
+
+  /**
+   * Execute javascript method within js context
+   * @param modulename name of the common-js like module to execute the method from
+   * @param methodName name of the method to be executed
+   * @param jsonArgsArray json encoded array of arguments provided for the method call
+   * @return json encoded value returned from the method call
+   */
+  @DoNotStrip
+  String executeJSCall(String modulename, String methodName, String jsonArgsArray)
+      throws ProxyExecutorException;
+
+  @DoNotStrip
+  void setGlobalVariable(String propertyName, String jsonEncodedValue);
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ProxyJavaScriptExecutor.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ProxyJavaScriptExecutor.java
index 08447802bf0b..f9e58869b3f5 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ProxyJavaScriptExecutor.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ProxyJavaScriptExecutor.java
@@ -29,48 +29,6 @@ public class ProxyJavaScriptExecutor extends JavaScriptExecutor {
     SoLoader.loadLibrary(ReactBridge.REACT_NATIVE_LIB);
   }
 
-  public static class ProxyExecutorException extends Exception {
-    public ProxyExecutorException(Throwable cause) {
-      super(cause);
-    }
-  }
-
-  /**
-   * This is class represents java version of native js executor interface. When set through
-   * {@link ProxyJavaScriptExecutor} as a {@link CatalystInstance} executor, native code will
-   * delegate js calls to the given implementation of this interface.
-   */
-  @DoNotStrip
-  public interface JavaJSExecutor {
-    /**
-     * Close this executor and cleanup any resources that it was using. No further calls are
-     * expected after this.
-     */
-    void close();
-
-    /**
-     * Load javascript into the js context
-     * @param script script contet to be executed
-     * @param sourceURL url or file location from which script content was loaded
-     */
-    @DoNotStrip
-    void executeApplicationScript(String script, String sourceURL) throws ProxyExecutorException;
-
-    /**
-     * Execute javascript method within js context
-     * @param modulename name of the common-js like module to execute the method from
-     * @param methodName name of the method to be executed
-     * @param jsonArgsArray json encoded array of arguments provided for the method call
-     * @return json encoded value returned from the method call
-     */
-    @DoNotStrip
-    String executeJSCall(String modulename, String methodName, String jsonArgsArray)
-        throws ProxyExecutorException;
-
-    @DoNotStrip
-    void setGlobalVariable(String propertyName, String jsonEncodedValue);
-  }
-
   private @Nullable JavaJSExecutor mJavaJSExecutor;
 
   /**
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/WebsocketJavaScriptExecutor.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/WebsocketJavaScriptExecutor.java
index 4557d9fe6747..e044ca8cd65f 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/WebsocketJavaScriptExecutor.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/WebsocketJavaScriptExecutor.java
@@ -23,7 +23,7 @@
 /**
  * Executes JS remotely via the react nodejs server as a proxy to a browser on the host machine.
  */
-public class WebsocketJavaScriptExecutor implements ProxyJavaScriptExecutor.JavaJSExecutor {
+public class WebsocketJavaScriptExecutor implements JavaJSExecutor {
 
   private static final long CONNECT_TIMEOUT_MS = 5000;
   private static final int CONNECT_RETRY_COUNT = 3;
@@ -146,7 +146,7 @@ public void close() {
 
   @Override
   public void executeApplicationScript(String script, String sourceURL)
-      throws ProxyJavaScriptExecutor.ProxyExecutorException {
+      throws ProxyExecutorException {
     JSExecutorCallbackFuture callback = new JSExecutorCallbackFuture();
     Assertions.assertNotNull(mWebSocketClient).executeApplicationScript(
         sourceURL,
@@ -155,13 +155,13 @@ public void executeApplicationScript(String script, String sourceURL)
     try {
       callback.get();
     } catch (Throwable cause) {
-      throw new ProxyJavaScriptExecutor.ProxyExecutorException(cause);
+      throw new ProxyExecutorException(cause);
     }
   }
 
   @Override
   public @Nullable String executeJSCall(String moduleName, String methodName, String jsonArgsArray)
-      throws ProxyJavaScriptExecutor.ProxyExecutorException {
+      throws ProxyExecutorException {
     JSExecutorCallbackFuture callback = new JSExecutorCallbackFuture();
     Assertions.assertNotNull(mWebSocketClient).executeJSCall(
         moduleName,
@@ -171,7 +171,7 @@ public void executeApplicationScript(String script, String sourceURL)
     try {
       return callback.get();
     } catch (Throwable cause) {
-      throw new ProxyJavaScriptExecutor.ProxyExecutorException(cause);
+      throw new ProxyExecutorException(cause);
     }
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
index 69ef7fa96211..bd8add591b80 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
@@ -541,7 +541,7 @@ public void onSuccess() {
                   @Override
                   public void run() {
                     mReactInstanceCommandsHandler.onReloadWithJSDebugger(
-                        new ProxyJavaScriptExecutor(webSocketJSExecutor));
+                        webSocketJSExecutor);
                   }
                 });
           }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/ReactInstanceDevCommandsHandler.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/ReactInstanceDevCommandsHandler.java
index 5489853b085f..e97b16f7d70f 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/ReactInstanceDevCommandsHandler.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/ReactInstanceDevCommandsHandler.java
@@ -9,7 +9,7 @@
 
 package com.facebook.react.devsupport;
 
-import com.facebook.react.bridge.ProxyJavaScriptExecutor;
+import com.facebook.react.bridge.JavaJSExecutor;
 
 /**
  * Interface used by {@link DevSupportManager} for requesting React instance recreation
@@ -20,7 +20,7 @@ public interface ReactInstanceDevCommandsHandler {
   /**
    * Request react instance recreation with JS debugging enabled.
    */
-  void onReloadWithJSDebugger(ProxyJavaScriptExecutor proxyExecutor);
+  void onReloadWithJSDebugger(JavaJSExecutor proxyExecutor);
 
   /**
    * Notify react instance manager about new JS bundle version downloaded from the server.
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index bc35feeb2bd2..6d3a1c2d8bdf 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -808,7 +808,7 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
 
     registerNatives("com/facebook/react/bridge/ProxyJavaScriptExecutor", {
         makeNativeMethod(
-          "initialize", "(Lcom/facebook/react/bridge/ProxyJavaScriptExecutor$JavaJSExecutor;)V",
+          "initialize", "(Lcom/facebook/react/bridge/JavaJSExecutor;)V",
           executors::createProxyExecutor),
     });
 
diff --git a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
index 129d737fc55e..ab86a669854f 100644
--- a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
@@ -10,7 +10,7 @@
 namespace facebook {
 namespace react {
 
-const auto EXECUTOR_BASECLASS = "com/facebook/react/bridge/ProxyJavaScriptExecutor$JavaJSExecutor";
+const auto EXECUTOR_BASECLASS = "com/facebook/react/bridge/JavaJSExecutor";
 
 std::unique_ptr<JSExecutor> ProxyExecutorOneTimeFactory::createJSExecutor(FlushImmediateCallback ignoredCallback) {
   FBASSERTMSGF(

From c8f3b43984d8be9598e0c523472996dcfcefe87a Mon Sep 17 00:00:00 2001
From: Marc Horowitz <mhorowitz@fb.com>
Date: Fri, 20 Nov 2015 12:16:39 -0800
Subject: [PATCH 0032/1411] Don't use the Bridge from CatalystInstance.

Summary: getBridge() is annotated VisibleForTesting, but still used
in DevSupportManager.  Instead, add the necessary methods to the
CatalystInstance interface.
public

Reviewed By: astreet

Differential Revision: D2651265

fb-gh-sync-id: 395893a961c32843871de4451eeccb33135b7ede
---
 .../react/bridge/CatalystInstance.java        | 21 +++++++++++++++++++
 .../react/devsupport/DevSupportManager.java   |  8 +++----
 2 files changed, 24 insertions(+), 5 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
index f8d7bff457e1..ee913802237c 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
@@ -306,6 +306,27 @@ public void removeBridgeIdleDebugListener(NotThreadSafeBridgeIdleDebugListener l
     mBridgeIdleListeners.remove(listener);
   }
 
+  public boolean supportsProfiling() {
+    if (mBridge == null) {
+      return false;
+    }
+    return mBridge.supportsProfiling();
+  }
+
+  public void startProfiler(String title) {
+    if (mBridge == null) {
+      return;
+    }
+    mBridge.startProfiler(title);
+  }
+
+  public void stopProfiler(String title, String filename) {
+    if (mBridge == null) {
+      return;
+    }
+    mBridge.stopProfiler(title, filename);
+  }
+
   private String buildModulesConfigJSONProperty(
       NativeModuleRegistry nativeModuleRegistry,
       JavaScriptModulesConfig jsModulesConfig) {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
index bd8add591b80..0a5d1da14651 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
@@ -285,8 +285,7 @@ public void onOptionSelected() {
     if (mCurrentContext != null &&
         mCurrentContext.getCatalystInstance() != null &&
         !mCurrentContext.getCatalystInstance().isDestroyed() &&
-        mCurrentContext.getCatalystInstance().getBridge() != null &&
-        mCurrentContext.getCatalystInstance().getBridge().supportsProfiling()) {
+        mCurrentContext.getCatalystInstance().supportsProfiling()) {
       options.put(
           mApplicationContext.getString(
               mIsCurrentlyProfiling ? R.string.catalyst_stop_profile :
@@ -302,7 +301,6 @@ public void onOptionSelected() {
                   mProfileIndex++;
                   Debug.stopMethodTracing();
                   mCurrentContext.getCatalystInstance()
-                      .getBridge()
                       .stopProfiler("profile", profileName);
                   Toast.makeText(
                       mCurrentContext,
@@ -310,7 +308,7 @@ public void onOptionSelected() {
                       Toast.LENGTH_LONG).show();
                 } else {
                   mIsCurrentlyProfiling = true;
-                  mCurrentContext.getCatalystInstance().getBridge().startProfiler("profile");
+                  mCurrentContext.getCatalystInstance().startProfiler("profile");
                   Debug.startMethodTracingSampling(
                       profileName,
                       JAVA_SAMPLING_PROFILE_MEMORY_BYTES,
@@ -476,7 +474,7 @@ private void resetCurrentContext(@Nullable ReactContext reactContext) {
           "/profile_" + mProfileIndex + ".json");
       mProfileIndex++;
       Debug.stopMethodTracing();
-      mCurrentContext.getCatalystInstance().getBridge().stopProfiler("profile", profileName);
+      mCurrentContext.getCatalystInstance().stopProfiler("profile", profileName);
     }
 
     mCurrentContext = reactContext;

From facf8a56d2b2c685e63b2f5c7d8f1ada497c9895 Mon Sep 17 00:00:00 2001
From: Marc Horowitz <mhorowitz@fb.com>
Date: Fri, 20 Nov 2015 12:17:00 -0800
Subject: [PATCH 0033/1411] minor build cleanups

Summary: make DevSupportManager PUBLIC visibility, instead of adding
to it more; put private parts of OnLoad into an anonymous namespace,
and move NativeRunnable into it; don't make NativeArray depend on
MethodCall which it does not use.
public

Reviewed By: astreet

Differential Revision: D2651270

fb-gh-sync-id: d5262da79cbd60c4eb490d43d13cc625fa163cdf
---
 ReactAndroid/src/main/jni/react/jni/NativeArray.h |  2 +-
 ReactAndroid/src/main/jni/react/jni/OnLoad.cpp    | 12 ++++++++----
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/jni/NativeArray.h b/ReactAndroid/src/main/jni/react/jni/NativeArray.h
index 452f6b1d054e..f30ef107da2d 100644
--- a/ReactAndroid/src/main/jni/react/jni/NativeArray.h
+++ b/ReactAndroid/src/main/jni/react/jni/NativeArray.h
@@ -3,7 +3,7 @@
 #pragma once
 
 #include <jni/fbjni.h>
-#include <react/MethodCall.h>
+#include <folly/dynamic.h>
 
 namespace facebook {
 namespace react {
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 6d3a1c2d8bdf..e3ceddd5fdb1 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -60,10 +60,6 @@ struct ReadableNativeMapKeySetIterator : public Countable {
     , mapRef(mapRef_) {}
 };
 
-struct NativeRunnable : public Countable {
-  std::function<void()> callable;
-};
-
 static jobject createReadableNativeMapWithContents(JNIEnv* env, folly::dynamic map) {
   if (map.isNull()) {
     return nullptr;
@@ -515,8 +511,14 @@ static jstring getNextKey(JNIEnv* env, jobject obj) {
 } // namespace iterator
 } // namespace map
 
+namespace {
+
 namespace runnable {
 
+struct NativeRunnable : public Countable {
+  std::function<void()> callable;
+};
+
 static jclass gNativeRunnableClass;
 static jmethodID gNativeRunnableCtor;
 
@@ -743,6 +745,8 @@ static void createProxyExecutor(JNIEnv *env, jobject obj, jobject executorInstan
 
 } // namespace executors
 
+}
+
 extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
   return initialize(vm, [] {
     // get the current env

From 9a61628f133a4d3fb67190e38de6c61c017a83e3 Mon Sep 17 00:00:00 2001
From: Marc Horowitz <mhorowitz@fb.com>
Date: Fri, 20 Nov 2015 12:17:23 -0800
Subject: [PATCH 0034/1411] Clean up the interface to the bridge

Summary: Change the following classes into interfaces, with a separate
Impl file:  CatalystInstance, ReactInstanceManager,
CatalystQueueConfiguration, MessageQueueThread.  This is done to help
isolate the interface between React Native and applications which use it.
This will also help some intrusive development work on a branch
such as porting parts of the bridge to common C++ code, without affecting
app reliability while this work is ongoing.
public

Reviewed By: astreet

Differential Revision: D2651277

fb-gh-sync-id: f04dc04a6e68df7acbc2bbf8b2529287d7b5b2ae
---
 .../facebook/react/ReactInstanceManager.java  | 571 +---------------
 .../react/ReactInstanceManagerImpl.java       | 635 ++++++++++++++++++
 .../react/bridge/CatalystInstance.java        | 458 +------------
 .../react/bridge/CatalystInstanceImpl.java    | 510 ++++++++++++++
 .../bridge/JavaScriptModuleRegistry.java      |   6 +-
 .../queue/CatalystQueueConfiguration.java     |  73 +-
 .../queue/CatalystQueueConfigurationImpl.java |  85 +++
 .../bridge/queue/MessageQueueThread.java      | 118 +---
 .../bridge/queue/MessageQueueThreadImpl.java  | 144 ++++
 9 files changed, 1435 insertions(+), 1165 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/queue/CatalystQueueConfigurationImpl.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
index ba4cd8d12abb..609b320fc9e8 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
@@ -16,44 +16,16 @@
 
 import android.app.Activity;
 import android.app.Application;
-import android.content.Context;
 import android.content.Intent;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.view.View;
 
-import com.facebook.common.logging.FLog;
 import com.facebook.infer.annotation.Assertions;
-import com.facebook.react.bridge.Arguments;
-import com.facebook.react.bridge.CatalystInstance;
-import com.facebook.react.bridge.JSBundleLoader;
-import com.facebook.react.bridge.JSCJavaScriptExecutor;
-import com.facebook.react.bridge.JavaJSExecutor;
-import com.facebook.react.bridge.JavaScriptExecutor;
-import com.facebook.react.bridge.JavaScriptModule;
-import com.facebook.react.bridge.JavaScriptModulesConfig;
-import com.facebook.react.bridge.NativeModule;
-import com.facebook.react.bridge.NativeModuleRegistry;
 import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener;
-import com.facebook.react.bridge.ProxyJavaScriptExecutor;
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.ReactContext;
-import com.facebook.react.bridge.UiThreadUtil;
-import com.facebook.react.bridge.WritableMap;
-import com.facebook.react.bridge.WritableNativeMap;
-import com.facebook.react.bridge.queue.CatalystQueueConfigurationSpec;
-import com.facebook.react.common.ReactConstants;
 import com.facebook.react.common.annotations.VisibleForTesting;
-import com.facebook.react.devsupport.DevServerHelper;
 import com.facebook.react.devsupport.DevSupportManager;
-import com.facebook.react.devsupport.ReactInstanceDevCommandsHandler;
 import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
-import com.facebook.react.modules.core.DeviceEventManagerModule;
-import com.facebook.react.uimanager.AppRegistry;
-import com.facebook.react.uimanager.ReactNative;
-import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.ViewManager;
-import com.facebook.soloader.SoLoader;
 
 /**
  * This class is managing instances of {@link CatalystInstance}. It expose a way to configure
@@ -70,169 +42,11 @@
  * owning activity's lifecycle events to the instance manager (see {@link #onPause},
  * {@link #onDestroy} and {@link #onResume}).
  *
- * To instantiate an instance of this class use {@link #builder}.
+ * Ideally, this would be an interface, but because of the API used by earlier versions, it has to
+ * have a static method, and so cannot (in Java < 8), be one.
  */
-public class ReactInstanceManager {
-
-  /* should only be accessed from main thread (UI thread) */
-  private final List<ReactRootView> mAttachedRootViews = new ArrayList<>();
-  private LifecycleState mLifecycleState;
-  private boolean mIsContextInitAsyncTaskRunning;
-  private @Nullable ReactContextInitParams mPendingReactContextInitParams;
-
-  /* accessed from any thread */
-  private @Nullable String mJSBundleFile; /* path to JS bundle on file system */
-  private final @Nullable String mJSMainModuleName; /* path to JS bundle root on packager server */
-  private final List<ReactPackage> mPackages;
-  private final DevSupportManager mDevSupportManager;
-  private final boolean mUseDeveloperSupport;
-  private final @Nullable NotThreadSafeBridgeIdleDebugListener mBridgeIdleDebugListener;
-  private @Nullable volatile ReactContext mCurrentReactContext;
-  private final Context mApplicationContext;
-  private @Nullable DefaultHardwareBackBtnHandler mDefaultBackButtonImpl;
-  private String mSourceUrl;
-  private @Nullable Activity mCurrentActivity;
-  private volatile boolean mHasStartedCreatingInitialContext = false;
-
-  private final ReactInstanceDevCommandsHandler mDevInterface =
-      new ReactInstanceDevCommandsHandler() {
-
-        @Override
-        public void onReloadWithJSDebugger(JavaJSExecutor jsExecutor) {
-          ReactInstanceManager.this.onReloadWithJSDebugger(jsExecutor);
-        }
-
-        @Override
-        public void onJSBundleLoadedFromServer() {
-          ReactInstanceManager.this.onJSBundleLoadedFromServer();
-        }
-
-        @Override
-        public void toggleElementInspector() {
-          ReactInstanceManager.this.toggleElementInspector();
-        }
-      };
-
-  private final DefaultHardwareBackBtnHandler mBackBtnHandler =
-      new DefaultHardwareBackBtnHandler() {
-        @Override
-        public void invokeDefaultOnBackPressed() {
-          ReactInstanceManager.this.invokeDefaultOnBackPressed();
-        }
-      };
-
-  private class ReactContextInitParams {
-    private final JavaScriptExecutor mJsExecutor;
-    private final JSBundleLoader mJsBundleLoader;
-
-    public ReactContextInitParams(
-        JavaScriptExecutor jsExecutor,
-        JSBundleLoader jsBundleLoader) {
-      mJsExecutor = Assertions.assertNotNull(jsExecutor);
-      mJsBundleLoader = Assertions.assertNotNull(jsBundleLoader);
-    }
-
-    public JavaScriptExecutor getJsExecutor() {
-      return mJsExecutor;
-    }
-
-    public JSBundleLoader getJsBundleLoader() {
-      return mJsBundleLoader;
-    }
-  }
-
-  /*
-   * Task class responsible for (re)creating react context in the background. These tasks can only
-   * be executing one at time, see {@link #recreateReactContextInBackground()}.
-   */
-  private final class ReactContextInitAsyncTask extends
-      AsyncTask<ReactContextInitParams, Void, ReactApplicationContext> {
-
-    @Override
-    protected void onPreExecute() {
-      if (mCurrentReactContext != null) {
-        tearDownReactContext(mCurrentReactContext);
-        mCurrentReactContext = null;
-      }
-    }
-
-    @Override
-    protected ReactApplicationContext doInBackground(ReactContextInitParams... params) {
-      Assertions.assertCondition(params != null && params.length > 0 && params[0] != null);
-      return createReactContext(params[0].getJsExecutor(), params[0].getJsBundleLoader());
-    }
-
-    @Override
-    protected void onPostExecute(ReactApplicationContext reactContext) {
-      try {
-        setupReactContext(reactContext);
-      } finally {
-        mIsContextInitAsyncTaskRunning = false;
-      }
-
-      // Handle enqueued request to re-initialize react context.
-      if (mPendingReactContextInitParams != null) {
-        recreateReactContextInBackground(
-            mPendingReactContextInitParams.getJsExecutor(),
-            mPendingReactContextInitParams.getJsBundleLoader());
-        mPendingReactContextInitParams = null;
-      }
-    }
-  }
-
-  private ReactInstanceManager(
-      Context applicationContext,
-      @Nullable String jsBundleFile,
-      @Nullable String jsMainModuleName,
-      List<ReactPackage> packages,
-      boolean useDeveloperSupport,
-      @Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener,
-      LifecycleState initialLifecycleState) {
-    initializeSoLoaderIfNecessary(applicationContext);
-
-    mApplicationContext = applicationContext;
-    mJSBundleFile = jsBundleFile;
-    mJSMainModuleName = jsMainModuleName;
-    mPackages = packages;
-    mUseDeveloperSupport = useDeveloperSupport;
-    // We need to instantiate DevSupportManager regardless to the useDeveloperSupport option,
-    // although will prevent dev support manager from displaying any options or dialogs by
-    // checking useDeveloperSupport option before calling setDevSupportEnabled on this manager
-    // TODO(6803830): Don't instantiate devsupport manager when useDeveloperSupport is false
-    mDevSupportManager = new DevSupportManager(
-        applicationContext,
-        mDevInterface,
-        mJSMainModuleName,
-        useDeveloperSupport);
-    mBridgeIdleDebugListener = bridgeIdleDebugListener;
-    mLifecycleState = initialLifecycleState;
-  }
-
-  public DevSupportManager getDevSupportManager() {
-    return mDevSupportManager;
-  }
-
-  /**
-   * Creates a builder that is capable of creating an instance of {@link ReactInstanceManager}.
-   */
-  public static Builder builder() {
-    return new Builder();
-  }
-
-  private static void initializeSoLoaderIfNecessary(Context applicationContext) {
-    // Call SoLoader.initialize here, this is required for apps that does not use exopackage and
-    // does not use SoLoader for loading other native code except from the one used by React Native
-    // This way we don't need to require others to have additional initialization code and to
-    // subclass android.app.Application.
-
-    // Method SoLoader.init is idempotent, so if you wish to use native exopackage, just call
-    // SoLoader.init with appropriate args before initializing ReactInstanceManager
-    SoLoader.init(applicationContext, /* native exopackage */ false);
-  }
-
-  public void setJSBundleFile(String jsBundleFile) {
-    mJSBundleFile = jsBundleFile;
-  }
+public abstract class ReactInstanceManager {
+  public abstract DevSupportManager getDevSupportManager();
 
   /**
    * Trigger react context initialization asynchronously in a background async task. This enables
@@ -243,129 +57,20 @@ public void setJSBundleFile(String jsBundleFile) {
    *
    * Called from UI thread.
    */
-  public void createReactContextInBackground() {
-    Assertions.assertCondition(
-        !mHasStartedCreatingInitialContext,
-        "createReactContextInBackground should only be called when creating the react " +
-            "application for the first time. When reloading JS, e.g. from a new file, explicitly" +
-            "use recreateReactContextInBackground");
-
-    mHasStartedCreatingInitialContext = true;
-    recreateReactContextInBackgroundInner();
-  }
-
-  /**
-   * Recreate the react application and context. This should be called if configuration has
-   * changed or the developer has requested the app to be reloaded. It should only be called after
-   * an initial call to createReactContextInBackground.
-   *
-   * Called from UI thread.
-   */
-  public void recreateReactContextInBackground() {
-    Assertions.assertCondition(
-        mHasStartedCreatingInitialContext,
-        "recreateReactContextInBackground should only be called after the initial " +
-            "createReactContextInBackground call.");
-    recreateReactContextInBackgroundInner();
-  }
-
-  private void recreateReactContextInBackgroundInner() {
-    UiThreadUtil.assertOnUiThread();
-
-    if (mUseDeveloperSupport && mJSMainModuleName != null) {
-      if (mDevSupportManager.hasUpToDateJSBundleInCache()) {
-        // If there is a up-to-date bundle downloaded from server, always use that
-        onJSBundleLoadedFromServer();
-      } else if (mJSBundleFile == null) {
-        mDevSupportManager.handleReloadJS();
-      } else {
-        mDevSupportManager.isPackagerRunning(
-            new DevServerHelper.PackagerStatusCallback() {
-              @Override
-              public void onPackagerStatusFetched(final boolean packagerIsRunning) {
-                UiThreadUtil.runOnUiThread(
-                    new Runnable() {
-                      @Override
-                      public void run() {
-                        if (packagerIsRunning) {
-                          mDevSupportManager.handleReloadJS();
-                        } else {
-                          recreateReactContextInBackgroundFromBundleFile();
-                        }
-                      }
-                    });
-              }
-            });
-      }
-      return;
-    }
-
-    recreateReactContextInBackgroundFromBundleFile();
-  }
-
-  private void recreateReactContextInBackgroundFromBundleFile() {
-    recreateReactContextInBackground(
-        new JSCJavaScriptExecutor(),
-        JSBundleLoader.createFileLoader(mApplicationContext, mJSBundleFile));
-  }
+  public abstract void createReactContextInBackground();
 
   /**
    * @return whether createReactContextInBackground has been called. Will return false after
    * onDestroy until a new initial context has been created.
    */
-  public boolean hasStartedCreatingInitialContext() {
-    return mHasStartedCreatingInitialContext;
-  }
+  public abstract boolean hasStartedCreatingInitialContext();
 
   /**
    * This method will give JS the opportunity to consume the back button event. If JS does not
    * consume the event, mDefaultBackButtonImpl will be invoked at the end of the round trip to JS.
    */
-  public void onBackPressed() {
-    UiThreadUtil.assertOnUiThread();
-    ReactContext reactContext = mCurrentReactContext;
-    if (mCurrentReactContext == null) {
-      // Invoke without round trip to JS.
-      FLog.w(ReactConstants.TAG, "Instance detached from instance manager");
-      invokeDefaultOnBackPressed();
-    } else {
-      DeviceEventManagerModule deviceEventManagerModule =
-          Assertions.assertNotNull(reactContext).getNativeModule(DeviceEventManagerModule.class);
-      deviceEventManagerModule.emitHardwareBackPressed();
-    }
-  }
-
-  private void invokeDefaultOnBackPressed() {
-    UiThreadUtil.assertOnUiThread();
-    if (mDefaultBackButtonImpl != null) {
-      mDefaultBackButtonImpl.invokeDefaultOnBackPressed();
-    }
-  }
-
-  private void toggleElementInspector() {
-    if (mCurrentReactContext != null) {
-      mCurrentReactContext
-          .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
-          .emit("toggleElementInspector", null);
-    }
-  }
-
-  public void onPause() {
-    UiThreadUtil.assertOnUiThread();
-
-    mLifecycleState = LifecycleState.BEFORE_RESUME;
-
-    mDefaultBackButtonImpl = null;
-    if (mUseDeveloperSupport) {
-      mDevSupportManager.setDevSupportEnabled(false);
-    }
-
-    mCurrentActivity = null;
-    if (mCurrentReactContext != null) {
-      mCurrentReactContext.onPause();
-    }
-  }
-
+  public abstract void onBackPressed();
+  public abstract void onPause();
   /**
    * Use this method when the activity resumes to enable invoking the back button directly from JS.
    *
@@ -377,53 +82,17 @@ public void onPause() {
    * @param defaultBackButtonImpl a {@link DefaultHardwareBackBtnHandler} from an Activity that owns
    * this instance of {@link ReactInstanceManager}.
    */
-  public void onResume(Activity activity, DefaultHardwareBackBtnHandler defaultBackButtonImpl) {
-    UiThreadUtil.assertOnUiThread();
-
-    mLifecycleState = LifecycleState.RESUMED;
-
-    mDefaultBackButtonImpl = defaultBackButtonImpl;
-    if (mUseDeveloperSupport) {
-      mDevSupportManager.setDevSupportEnabled(true);
-    }
-
-    mCurrentActivity = activity;
-    if (mCurrentReactContext != null) {
-      mCurrentReactContext.onResume(activity);
-    }
-  }
-
-  public void onDestroy() {
-    UiThreadUtil.assertOnUiThread();
-
-    if (mUseDeveloperSupport) {
-      mDevSupportManager.setDevSupportEnabled(false);
-    }
-
-    if (mCurrentReactContext != null) {
-      mCurrentReactContext.onDestroy();
-      mCurrentReactContext = null;
-      mHasStartedCreatingInitialContext = false;
-    }
-  }
-
-  public void onActivityResult(int requestCode, int resultCode, Intent data) {
-    if (mCurrentReactContext != null) {
-      mCurrentReactContext.onActivityResult(requestCode, resultCode, data);
-    }
-  }
-
-  public void showDevOptionsDialog() {
-    UiThreadUtil.assertOnUiThread();
-    mDevSupportManager.showDevOptionsDialog();
-  }
+  public abstract void onResume(
+    Activity activity,
+    DefaultHardwareBackBtnHandler defaultBackButtonImpl);
+  public abstract void onDestroy();
+  public abstract void onActivityResult(int requestCode, int resultCode, Intent data);
+  public abstract void showDevOptionsDialog();
 
   /**
    * Get the URL where the last bundle was loaded from.
    */
-  public String getSourceUrl() {
-    return Assertions.assertNotNull(mSourceUrl);
-  }
+  public abstract String getSourceUrl();
 
   /**
    * Attach given {@param rootView} to a catalyst instance manager and start JS application using
@@ -433,218 +102,46 @@ public String getSourceUrl() {
    * This view will then be tracked by this manager and in case of catalyst instance restart it will
    * be re-attached.
    */
-  /* package */ void attachMeasuredRootView(ReactRootView rootView) {
-    UiThreadUtil.assertOnUiThread();
-    mAttachedRootViews.add(rootView);
-
-    // If react context is being created in the background, JS application will be started
-    // automatically when creation completes, as root view is part of the attached root view list.
-    if (!mIsContextInitAsyncTaskRunning && mCurrentReactContext != null) {
-      attachMeasuredRootViewToInstance(rootView, mCurrentReactContext.getCatalystInstance());
-    }
-  }
+  public abstract void attachMeasuredRootView(ReactRootView rootView);
 
   /**
    * Detach given {@param rootView} from current catalyst instance. It's safe to call this method
    * multiple times on the same {@param rootView} - in that case view will be detached with the
    * first call.
    */
-  /* package */ void detachRootView(ReactRootView rootView) {
-    UiThreadUtil.assertOnUiThread();
-    if (mAttachedRootViews.remove(rootView)) {
-      if (mCurrentReactContext != null && mCurrentReactContext.hasActiveCatalystInstance()) {
-        detachViewFromInstance(rootView, mCurrentReactContext.getCatalystInstance());
-      }
-    }
-  }
+  public abstract void detachRootView(ReactRootView rootView);
 
   /**
    * Uses configured {@link ReactPackage} instances to create all view managers
    */
-  /* package */ List<ViewManager> createAllViewManagers(
-      ReactApplicationContext catalystApplicationContext) {
-    List<ViewManager> allViewManagers = new ArrayList<>();
-    for (ReactPackage reactPackage : mPackages) {
-      allViewManagers.addAll(reactPackage.createViewManagers(catalystApplicationContext));
-    }
-    return allViewManagers;
-  }
+  public abstract List<ViewManager> createAllViewManagers(
+    ReactApplicationContext catalystApplicationContext);
 
   @VisibleForTesting
-  public @Nullable ReactContext getCurrentReactContext() {
-    return mCurrentReactContext;
-  }
-
-  private void onReloadWithJSDebugger(JavaJSExecutor jsExecutor) {
-    recreateReactContextInBackground(
-        new ProxyJavaScriptExecutor(jsExecutor),
-        JSBundleLoader.createRemoteDebuggerBundleLoader(
-            mDevSupportManager.getJSBundleURLForRemoteDebugging()));
-  }
-
-  private void onJSBundleLoadedFromServer() {
-    recreateReactContextInBackground(
-        new JSCJavaScriptExecutor(),
-        JSBundleLoader.createCachedBundleFromNetworkLoader(
-            mDevSupportManager.getSourceUrl(),
-            mDevSupportManager.getDownloadedJSBundleFile()));
-  }
-
-  private void recreateReactContextInBackground(
-      JavaScriptExecutor jsExecutor,
-      JSBundleLoader jsBundleLoader) {
-    UiThreadUtil.assertOnUiThread();
-
-    ReactContextInitParams initParams = new ReactContextInitParams(jsExecutor, jsBundleLoader);
-    if (!mIsContextInitAsyncTaskRunning) {
-      // No background task to create react context is currently running, create and execute one.
-      ReactContextInitAsyncTask initTask = new ReactContextInitAsyncTask();
-      initTask.execute(initParams);
-      mIsContextInitAsyncTaskRunning = true;
-    } else {
-      // Background task is currently running, queue up most recent init params to recreate context
-      // once task completes.
-      mPendingReactContextInitParams = initParams;
-    }
-  }
-
-  private void setupReactContext(ReactApplicationContext reactContext) {
-    UiThreadUtil.assertOnUiThread();
-    Assertions.assertCondition(mCurrentReactContext == null);
-    mCurrentReactContext = Assertions.assertNotNull(reactContext);
-    CatalystInstance catalystInstance =
-        Assertions.assertNotNull(reactContext.getCatalystInstance());
-
-    catalystInstance.initialize();
-    mDevSupportManager.onNewReactContextCreated(reactContext);
-    moveReactContextToCurrentLifecycleState(reactContext);
-
-    for (ReactRootView rootView : mAttachedRootViews) {
-      attachMeasuredRootViewToInstance(rootView, catalystInstance);
-    }
-  }
-
-  private void attachMeasuredRootViewToInstance(
-      ReactRootView rootView,
-      CatalystInstance catalystInstance) {
-    UiThreadUtil.assertOnUiThread();
-
-    // Reset view content as it's going to be populated by the application content from JS
-    rootView.removeAllViews();
-    rootView.setId(View.NO_ID);
-
-    UIManagerModule uiManagerModule = catalystInstance.getNativeModule(UIManagerModule.class);
-    int rootTag = uiManagerModule.addMeasuredRootView(rootView);
-    @Nullable Bundle launchOptions = rootView.getLaunchOptions();
-    WritableMap initialProps = launchOptions != null
-        ? Arguments.fromBundle(launchOptions)
-        : Arguments.createMap();
-    String jsAppModuleName = rootView.getJSModuleName();
-
-    WritableNativeMap appParams = new WritableNativeMap();
-    appParams.putDouble("rootTag", rootTag);
-    appParams.putMap("initialProps", initialProps);
-    catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);
-  }
-
-  private void detachViewFromInstance(
-      ReactRootView rootView,
-      CatalystInstance catalystInstance) {
-    UiThreadUtil.assertOnUiThread();
-    catalystInstance.getJSModule(ReactNative.class)
-        .unmountComponentAtNodeAndRemoveContainer(rootView.getId());
-  }
-
-  private void tearDownReactContext(ReactContext reactContext) {
-    UiThreadUtil.assertOnUiThread();
-    if (mLifecycleState == LifecycleState.RESUMED) {
-      reactContext.onPause();
-    }
-    for (ReactRootView rootView : mAttachedRootViews) {
-      detachViewFromInstance(rootView, reactContext.getCatalystInstance());
-    }
-    reactContext.onDestroy();
-    mDevSupportManager.onReactInstanceDestroyed(reactContext);
-  }
+  public abstract @Nullable ReactContext getCurrentReactContext();
 
   /**
-   * @return instance of {@link ReactContext} configured a {@link CatalystInstance} set
+   * Creates a builder that is capable of creating an instance of {@link ReactInstanceManagerImpl}.
    */
-  private ReactApplicationContext createReactContext(
-      JavaScriptExecutor jsExecutor,
-      JSBundleLoader jsBundleLoader) {
-    FLog.i(ReactConstants.TAG, "Creating react context.");
-    mSourceUrl = jsBundleLoader.getSourceUrl();
-    NativeModuleRegistry.Builder nativeRegistryBuilder = new NativeModuleRegistry.Builder();
-    JavaScriptModulesConfig.Builder jsModulesBuilder = new JavaScriptModulesConfig.Builder();
-
-    ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);
-    if (mUseDeveloperSupport) {
-      reactContext.setNativeModuleCallExceptionHandler(mDevSupportManager);
-    }
-
-    CoreModulesPackage coreModulesPackage =
-        new CoreModulesPackage(this, mBackBtnHandler);
-    processPackage(coreModulesPackage, reactContext, nativeRegistryBuilder, jsModulesBuilder);
-
-    // TODO(6818138): Solve use-case of native/js modules overriding
-    for (ReactPackage reactPackage : mPackages) {
-      processPackage(reactPackage, reactContext, nativeRegistryBuilder, jsModulesBuilder);
-    }
-
-    CatalystInstance.Builder catalystInstanceBuilder = new CatalystInstance.Builder()
-        .setCatalystQueueConfigurationSpec(CatalystQueueConfigurationSpec.createDefault())
-        .setJSExecutor(jsExecutor)
-        .setRegistry(nativeRegistryBuilder.build())
-        .setJSModulesConfig(jsModulesBuilder.build())
-        .setJSBundleLoader(jsBundleLoader)
-        .setNativeModuleCallExceptionHandler(mDevSupportManager);
-
-    CatalystInstance catalystInstance = catalystInstanceBuilder.build();
-    if (mBridgeIdleDebugListener != null) {
-      catalystInstance.addBridgeIdleDebugListener(mBridgeIdleDebugListener);
-    }
-
-    reactContext.initializeWithInstance(catalystInstance);
-    catalystInstance.runJSBundle();
-
-    return reactContext;
-  }
-
-  private void processPackage(
-      ReactPackage reactPackage,
-      ReactApplicationContext reactContext,
-      NativeModuleRegistry.Builder nativeRegistryBuilder,
-      JavaScriptModulesConfig.Builder jsModulesBuilder) {
-    for (NativeModule nativeModule : reactPackage.createNativeModules(reactContext)) {
-      nativeRegistryBuilder.add(nativeModule);
-    }
-    for (Class<? extends JavaScriptModule> jsModuleClass : reactPackage.createJSModules()) {
-      jsModulesBuilder.add(jsModuleClass);
-    }
-  }
-
-  private void moveReactContextToCurrentLifecycleState(ReactApplicationContext reactContext) {
-    if (mLifecycleState == LifecycleState.RESUMED) {
-      reactContext.onResume(mCurrentActivity);
-    }
+  public static Builder builder() {
+    return new Builder();
   }
 
   /**
-   * Builder class for {@link ReactInstanceManager}
+   * Builder class for {@link ReactInstanceManagerImpl}
    */
   public static class Builder {
 
-    private final List<ReactPackage> mPackages = new ArrayList<>();
+    protected final List<ReactPackage> mPackages = new ArrayList<>();
 
-    private @Nullable String mJSBundleFile;
-    private @Nullable String mJSMainModuleName;
-    private @Nullable NotThreadSafeBridgeIdleDebugListener mBridgeIdleDebugListener;
-    private @Nullable Application mApplication;
-    private boolean mUseDeveloperSupport;
-    private @Nullable LifecycleState mInitialLifecycleState;
+    protected @Nullable String mJSBundleFile;
+    protected @Nullable String mJSMainModuleName;
+    protected @Nullable NotThreadSafeBridgeIdleDebugListener mBridgeIdleDebugListener;
+    protected @Nullable Application mApplication;
+    protected boolean mUseDeveloperSupport;
+    protected @Nullable LifecycleState mInitialLifecycleState;
 
-    private Builder() {
+    protected Builder() {
     }
 
     /**
@@ -718,7 +215,7 @@ public Builder setInitialLifecycleState(LifecycleState initialLifecycleState) {
     }
 
     /**
-     * Instantiates a new {@link ReactInstanceManager}.
+     * Instantiates a new {@link ReactInstanceManagerImpl}.
      * Before calling {@code build}, the following must be called:
      * <ul>
      * <li> {@link #setApplication}
@@ -734,7 +231,7 @@ public ReactInstanceManager build() {
           mJSMainModuleName != null || mJSBundleFile != null,
           "Either MainModuleName or JS Bundle File needs to be provided");
 
-      return new ReactInstanceManager(
+      return new ReactInstanceManagerImpl(
           Assertions.assertNotNull(
               mApplication,
               "Application property has not been set with this builder"),
diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
new file mode 100644
index 000000000000..f8e0cdc0448a
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -0,0 +1,635 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react;
+
+import javax.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.Activity;
+import android.app.Application;
+import android.content.Context;
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.view.View;
+
+import com.facebook.common.logging.FLog;
+import com.facebook.infer.annotation.Assertions;
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.CatalystInstance;
+import com.facebook.react.bridge.CatalystInstanceImpl;
+import com.facebook.react.bridge.JSBundleLoader;
+import com.facebook.react.bridge.JSCJavaScriptExecutor;
+import com.facebook.react.bridge.JavaJSExecutor;
+import com.facebook.react.bridge.JavaScriptExecutor;
+import com.facebook.react.bridge.JavaScriptModule;
+import com.facebook.react.bridge.JavaScriptModulesConfig;
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.NativeModuleRegistry;
+import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener;
+import com.facebook.react.bridge.ProxyJavaScriptExecutor;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.UiThreadUtil;
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.bridge.WritableNativeMap;
+import com.facebook.react.bridge.queue.CatalystQueueConfigurationSpec;
+import com.facebook.react.common.ReactConstants;
+import com.facebook.react.common.annotations.VisibleForTesting;
+import com.facebook.react.devsupport.DevServerHelper;
+import com.facebook.react.devsupport.DevSupportManager;
+import com.facebook.react.devsupport.ReactInstanceDevCommandsHandler;
+import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
+import com.facebook.react.modules.core.DeviceEventManagerModule;
+import com.facebook.react.uimanager.AppRegistry;
+import com.facebook.react.uimanager.ReactNative;
+import com.facebook.react.uimanager.UIManagerModule;
+import com.facebook.react.uimanager.ViewManager;
+import com.facebook.soloader.SoLoader;
+
+/**
+ * This class is managing instances of {@link CatalystInstance}. It expose a way to configure
+ * catalyst instance using {@link ReactPackage} and keeps track of the lifecycle of that
+ * instance. It also sets up connection between the instance and developers support functionality
+ * of the framework.
+ *
+ * An instance of this manager is required to start JS application in {@link ReactRootView} (see
+ * {@link ReactRootView#startReactApplication} for more info).
+ *
+ * The lifecycle of the instance of {@link ReactInstanceManagerImpl} should be bound to the activity
+ * that owns the {@link ReactRootView} that is used to render react application using this
+ * instance manager (see {@link ReactRootView#startReactApplication}). It's required to pass
+ * owning activity's lifecycle events to the instance manager (see {@link #onPause},
+ * {@link #onDestroy} and {@link #onResume}).
+ *
+ * To instantiate an instance of this class use {@link #builder}.
+ */
+/* package */ class ReactInstanceManagerImpl extends ReactInstanceManager {
+
+  /* should only be accessed from main thread (UI thread) */
+  private final List<ReactRootView> mAttachedRootViews = new ArrayList<>();
+  private LifecycleState mLifecycleState;
+  private boolean mIsContextInitAsyncTaskRunning;
+  private @Nullable ReactContextInitParams mPendingReactContextInitParams;
+
+  /* accessed from any thread */
+  private @Nullable String mJSBundleFile; /* path to JS bundle on file system */
+  private final @Nullable String mJSMainModuleName; /* path to JS bundle root on packager server */
+  private final List<ReactPackage> mPackages;
+  private final DevSupportManager mDevSupportManager;
+  private final boolean mUseDeveloperSupport;
+  private final @Nullable NotThreadSafeBridgeIdleDebugListener mBridgeIdleDebugListener;
+  private @Nullable volatile ReactContext mCurrentReactContext;
+  private final Context mApplicationContext;
+  private @Nullable DefaultHardwareBackBtnHandler mDefaultBackButtonImpl;
+  private String mSourceUrl;
+  private @Nullable Activity mCurrentActivity;
+  private volatile boolean mHasStartedCreatingInitialContext = false;
+
+  private final ReactInstanceDevCommandsHandler mDevInterface =
+      new ReactInstanceDevCommandsHandler() {
+
+        @Override
+        public void onReloadWithJSDebugger(JavaJSExecutor jsExecutor) {
+          ReactInstanceManagerImpl.this.onReloadWithJSDebugger(jsExecutor);
+        }
+
+        @Override
+        public void onJSBundleLoadedFromServer() {
+          ReactInstanceManagerImpl.this.onJSBundleLoadedFromServer();
+        }
+
+        @Override
+        public void toggleElementInspector() {
+          ReactInstanceManagerImpl.this.toggleElementInspector();
+        }
+      };
+
+  private final DefaultHardwareBackBtnHandler mBackBtnHandler =
+      new DefaultHardwareBackBtnHandler() {
+        @Override
+        public void invokeDefaultOnBackPressed() {
+          ReactInstanceManagerImpl.this.invokeDefaultOnBackPressed();
+        }
+      };
+
+  private class ReactContextInitParams {
+    private final JavaScriptExecutor mJsExecutor;
+    private final JSBundleLoader mJsBundleLoader;
+
+    public ReactContextInitParams(
+        JavaScriptExecutor jsExecutor,
+        JSBundleLoader jsBundleLoader) {
+      mJsExecutor = Assertions.assertNotNull(jsExecutor);
+      mJsBundleLoader = Assertions.assertNotNull(jsBundleLoader);
+    }
+
+    public JavaScriptExecutor getJsExecutor() {
+      return mJsExecutor;
+    }
+
+    public JSBundleLoader getJsBundleLoader() {
+      return mJsBundleLoader;
+    }
+  }
+
+  /*
+   * Task class responsible for (re)creating react context in the background. These tasks can only
+   * be executing one at time, see {@link #recreateReactContextInBackground()}.
+   */
+  private final class ReactContextInitAsyncTask extends
+      AsyncTask<ReactContextInitParams, Void, ReactApplicationContext> {
+
+    @Override
+    protected void onPreExecute() {
+      if (mCurrentReactContext != null) {
+        tearDownReactContext(mCurrentReactContext);
+        mCurrentReactContext = null;
+      }
+    }
+
+    @Override
+    protected ReactApplicationContext doInBackground(ReactContextInitParams... params) {
+      Assertions.assertCondition(params != null && params.length > 0 && params[0] != null);
+      return createReactContext(params[0].getJsExecutor(), params[0].getJsBundleLoader());
+    }
+
+    @Override
+    protected void onPostExecute(ReactApplicationContext reactContext) {
+      try {
+        setupReactContext(reactContext);
+      } finally {
+        mIsContextInitAsyncTaskRunning = false;
+      }
+
+      // Handle enqueued request to re-initialize react context.
+      if (mPendingReactContextInitParams != null) {
+        recreateReactContextInBackground(
+            mPendingReactContextInitParams.getJsExecutor(),
+            mPendingReactContextInitParams.getJsBundleLoader());
+        mPendingReactContextInitParams = null;
+      }
+    }
+  }
+
+  /* package */ ReactInstanceManagerImpl(
+      Context applicationContext,
+      @Nullable String jsBundleFile,
+      @Nullable String jsMainModuleName,
+      List<ReactPackage> packages,
+      boolean useDeveloperSupport,
+      @Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener,
+      LifecycleState initialLifecycleState) {
+    initializeSoLoaderIfNecessary(applicationContext);
+
+    mApplicationContext = applicationContext;
+    mJSBundleFile = jsBundleFile;
+    mJSMainModuleName = jsMainModuleName;
+    mPackages = packages;
+    mUseDeveloperSupport = useDeveloperSupport;
+    // We need to instantiate DevSupportManager regardless to the useDeveloperSupport option,
+    // although will prevent dev support manager from displaying any options or dialogs by
+    // checking useDeveloperSupport option before calling setDevSupportEnabled on this manager
+    // TODO(6803830): Don't instantiate devsupport manager when useDeveloperSupport is false
+    mDevSupportManager = new DevSupportManager(
+        applicationContext,
+        mDevInterface,
+        mJSMainModuleName,
+        useDeveloperSupport);
+    mBridgeIdleDebugListener = bridgeIdleDebugListener;
+    mLifecycleState = initialLifecycleState;
+  }
+
+  @Override
+  public DevSupportManager getDevSupportManager() {
+    return mDevSupportManager;
+  }
+
+  private static void initializeSoLoaderIfNecessary(Context applicationContext) {
+    // Call SoLoader.initialize here, this is required for apps that does not use exopackage and
+    // does not use SoLoader for loading other native code except from the one used by React Native
+    // This way we don't need to require others to have additional initialization code and to
+    // subclass android.app.Application.
+
+    // Method SoLoader.init is idempotent, so if you wish to use native exopackage, just call
+    // SoLoader.init with appropriate args before initializing ReactInstanceManagerImpl
+    SoLoader.init(applicationContext, /* native exopackage */ false);
+  }
+
+  /**
+   * Trigger react context initialization asynchronously in a background async task. This enables
+   * applications to pre-load the application JS, and execute global code before
+   * {@link ReactRootView} is available and measured. This should only be called the first time the
+   * application is set up, which is enforced to keep developers from accidentally creating their
+   * application multiple times without realizing it.
+   *
+   * Called from UI thread.
+   */
+  @Override
+  public void createReactContextInBackground() {
+    Assertions.assertCondition(
+        !mHasStartedCreatingInitialContext,
+        "createReactContextInBackground should only be called when creating the react " +
+            "application for the first time. When reloading JS, e.g. from a new file, explicitly" +
+            "use recreateReactContextInBackground");
+
+    mHasStartedCreatingInitialContext = true;
+    recreateReactContextInBackgroundInner();
+  }
+
+  /**
+   * Recreate the react application and context. This should be called if configuration has
+   * changed or the developer has requested the app to be reloaded. It should only be called after
+   * an initial call to createReactContextInBackground.
+   *
+   * Called from UI thread.
+   */
+  public void recreateReactContextInBackground() {
+    Assertions.assertCondition(
+        mHasStartedCreatingInitialContext,
+        "recreateReactContextInBackground should only be called after the initial " +
+            "createReactContextInBackground call.");
+    recreateReactContextInBackgroundInner();
+  }
+
+  private void recreateReactContextInBackgroundInner() {
+    UiThreadUtil.assertOnUiThread();
+
+    if (mUseDeveloperSupport && mJSMainModuleName != null) {
+      if (mDevSupportManager.hasUpToDateJSBundleInCache()) {
+        // If there is a up-to-date bundle downloaded from server, always use that
+        onJSBundleLoadedFromServer();
+      } else if (mJSBundleFile == null) {
+        mDevSupportManager.handleReloadJS();
+      } else {
+        mDevSupportManager.isPackagerRunning(
+            new DevServerHelper.PackagerStatusCallback() {
+              @Override
+              public void onPackagerStatusFetched(final boolean packagerIsRunning) {
+                UiThreadUtil.runOnUiThread(
+                    new Runnable() {
+                      @Override
+                      public void run() {
+                        if (packagerIsRunning) {
+                          mDevSupportManager.handleReloadJS();
+                        } else {
+                          recreateReactContextInBackgroundFromBundleFile();
+                        }
+                      }
+                    });
+              }
+            });
+      }
+      return;
+    }
+
+    recreateReactContextInBackgroundFromBundleFile();
+  }
+
+  private void recreateReactContextInBackgroundFromBundleFile() {
+    recreateReactContextInBackground(
+        new JSCJavaScriptExecutor(),
+        JSBundleLoader.createFileLoader(mApplicationContext, mJSBundleFile));
+  }
+
+  /**
+   * @return whether createReactContextInBackground has been called. Will return false after
+   * onDestroy until a new initial context has been created.
+   */
+  public boolean hasStartedCreatingInitialContext() {
+    return mHasStartedCreatingInitialContext;
+  }
+
+  /**
+   * This method will give JS the opportunity to consume the back button event. If JS does not
+   * consume the event, mDefaultBackButtonImpl will be invoked at the end of the round trip to JS.
+   */
+  @Override
+  public void onBackPressed() {
+    UiThreadUtil.assertOnUiThread();
+    ReactContext reactContext = mCurrentReactContext;
+    if (mCurrentReactContext == null) {
+      // Invoke without round trip to JS.
+      FLog.w(ReactConstants.TAG, "Instance detached from instance manager");
+      invokeDefaultOnBackPressed();
+    } else {
+      DeviceEventManagerModule deviceEventManagerModule =
+          Assertions.assertNotNull(reactContext).getNativeModule(DeviceEventManagerModule.class);
+      deviceEventManagerModule.emitHardwareBackPressed();
+    }
+  }
+
+  private void invokeDefaultOnBackPressed() {
+    UiThreadUtil.assertOnUiThread();
+    if (mDefaultBackButtonImpl != null) {
+      mDefaultBackButtonImpl.invokeDefaultOnBackPressed();
+    }
+  }
+
+  private void toggleElementInspector() {
+    if (mCurrentReactContext != null) {
+      mCurrentReactContext
+          .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
+          .emit("toggleElementInspector", null);
+    }
+  }
+
+  @Override
+  public void onPause() {
+    UiThreadUtil.assertOnUiThread();
+
+    mLifecycleState = LifecycleState.BEFORE_RESUME;
+
+    mDefaultBackButtonImpl = null;
+    if (mUseDeveloperSupport) {
+      mDevSupportManager.setDevSupportEnabled(false);
+    }
+
+    mCurrentActivity = null;
+    if (mCurrentReactContext != null) {
+      mCurrentReactContext.onPause();
+    }
+  }
+
+  /**
+   * Use this method when the activity resumes to enable invoking the back button directly from JS.
+   *
+   * This method retains an instance to provided mDefaultBackButtonImpl. Thus it's
+   * important to pass from the activity instance that owns this particular instance of {@link
+   * ReactInstanceManagerImpl}, so that once this instance receive {@link #onDestroy} event it will
+   * clear the reference to that defaultBackButtonImpl.
+   *
+   * @param defaultBackButtonImpl a {@link DefaultHardwareBackBtnHandler} from an Activity that owns
+   * this instance of {@link ReactInstanceManagerImpl}.
+   */
+  @Override
+  public void onResume(Activity activity, DefaultHardwareBackBtnHandler defaultBackButtonImpl) {
+    UiThreadUtil.assertOnUiThread();
+
+    mLifecycleState = LifecycleState.RESUMED;
+
+    mDefaultBackButtonImpl = defaultBackButtonImpl;
+    if (mUseDeveloperSupport) {
+      mDevSupportManager.setDevSupportEnabled(true);
+    }
+
+    mCurrentActivity = activity;
+    if (mCurrentReactContext != null) {
+      mCurrentReactContext.onResume(activity);
+    }
+  }
+
+  @Override
+  public void onDestroy() {
+    UiThreadUtil.assertOnUiThread();
+
+    if (mUseDeveloperSupport) {
+      mDevSupportManager.setDevSupportEnabled(false);
+    }
+
+    if (mCurrentReactContext != null) {
+      mCurrentReactContext.onDestroy();
+      mCurrentReactContext = null;
+      mHasStartedCreatingInitialContext = false;
+    }
+  }
+
+  @Override
+  public void onActivityResult(int requestCode, int resultCode, Intent data) {
+    if (mCurrentReactContext != null) {
+      mCurrentReactContext.onActivityResult(requestCode, resultCode, data);
+    }
+  }
+
+  @Override
+  public void showDevOptionsDialog() {
+    UiThreadUtil.assertOnUiThread();
+    mDevSupportManager.showDevOptionsDialog();
+  }
+
+  /**
+   * Get the URL where the last bundle was loaded from.
+   */
+  @Override
+  public String getSourceUrl() {
+    return Assertions.assertNotNull(mSourceUrl);
+  }
+
+  /**
+   * Attach given {@param rootView} to a catalyst instance manager and start JS application using
+   * JS module provided by {@link ReactRootView#getJSModuleName}. If the react context is currently
+   * being (re)-created, or if react context has not been created yet, the JS application associated
+   * with the provided root view will be started asynchronously, i.e this method won't block.
+   * This view will then be tracked by this manager and in case of catalyst instance restart it will
+   * be re-attached.
+   */
+  @Override
+  public void attachMeasuredRootView(ReactRootView rootView) {
+    UiThreadUtil.assertOnUiThread();
+    mAttachedRootViews.add(rootView);
+
+    // If react context is being created in the background, JS application will be started
+    // automatically when creation completes, as root view is part of the attached root view list.
+    if (!mIsContextInitAsyncTaskRunning && mCurrentReactContext != null) {
+      attachMeasuredRootViewToInstance(rootView, mCurrentReactContext.getCatalystInstance());
+    }
+  }
+
+  /**
+   * Detach given {@param rootView} from current catalyst instance. It's safe to call this method
+   * multiple times on the same {@param rootView} - in that case view will be detached with the
+   * first call.
+   */
+  @Override
+  public void detachRootView(ReactRootView rootView) {
+    UiThreadUtil.assertOnUiThread();
+    if (mAttachedRootViews.remove(rootView)) {
+      if (mCurrentReactContext != null && mCurrentReactContext.hasActiveCatalystInstance()) {
+        detachViewFromInstance(rootView, mCurrentReactContext.getCatalystInstance());
+      }
+    }
+  }
+
+  /**
+   * Uses configured {@link ReactPackage} instances to create all view managers
+   */
+  @Override
+  public List<ViewManager> createAllViewManagers(
+      ReactApplicationContext catalystApplicationContext) {
+    List<ViewManager> allViewManagers = new ArrayList<>();
+    for (ReactPackage reactPackage : mPackages) {
+      allViewManagers.addAll(reactPackage.createViewManagers(catalystApplicationContext));
+    }
+    return allViewManagers;
+  }
+
+  @VisibleForTesting
+  @Override
+  public @Nullable ReactContext getCurrentReactContext() {
+    return mCurrentReactContext;
+  }
+
+  private void onReloadWithJSDebugger(JavaJSExecutor jsExecutor) {
+    recreateReactContextInBackground(
+        new ProxyJavaScriptExecutor(jsExecutor),
+        JSBundleLoader.createRemoteDebuggerBundleLoader(
+            mDevSupportManager.getJSBundleURLForRemoteDebugging()));
+  }
+
+  private void onJSBundleLoadedFromServer() {
+    recreateReactContextInBackground(
+        new JSCJavaScriptExecutor(),
+        JSBundleLoader.createCachedBundleFromNetworkLoader(
+            mDevSupportManager.getSourceUrl(),
+            mDevSupportManager.getDownloadedJSBundleFile()));
+  }
+
+  private void recreateReactContextInBackground(
+      JavaScriptExecutor jsExecutor,
+      JSBundleLoader jsBundleLoader) {
+    UiThreadUtil.assertOnUiThread();
+
+    ReactContextInitParams initParams = new ReactContextInitParams(jsExecutor, jsBundleLoader);
+    if (!mIsContextInitAsyncTaskRunning) {
+      // No background task to create react context is currently running, create and execute one.
+      ReactContextInitAsyncTask initTask = new ReactContextInitAsyncTask();
+      initTask.execute(initParams);
+      mIsContextInitAsyncTaskRunning = true;
+    } else {
+      // Background task is currently running, queue up most recent init params to recreate context
+      // once task completes.
+      mPendingReactContextInitParams = initParams;
+    }
+  }
+
+  private void setupReactContext(ReactApplicationContext reactContext) {
+    UiThreadUtil.assertOnUiThread();
+    Assertions.assertCondition(mCurrentReactContext == null);
+    mCurrentReactContext = Assertions.assertNotNull(reactContext);
+    CatalystInstance catalystInstance =
+        Assertions.assertNotNull(reactContext.getCatalystInstance());
+
+    catalystInstance.initialize();
+    mDevSupportManager.onNewReactContextCreated(reactContext);
+    moveReactContextToCurrentLifecycleState(reactContext);
+
+    for (ReactRootView rootView : mAttachedRootViews) {
+      attachMeasuredRootViewToInstance(rootView, catalystInstance);
+    }
+  }
+
+  private void attachMeasuredRootViewToInstance(
+      ReactRootView rootView,
+      CatalystInstance catalystInstance) {
+    UiThreadUtil.assertOnUiThread();
+
+    // Reset view content as it's going to be populated by the application content from JS
+    rootView.removeAllViews();
+    rootView.setId(View.NO_ID);
+
+    UIManagerModule uiManagerModule = catalystInstance.getNativeModule(UIManagerModule.class);
+    int rootTag = uiManagerModule.addMeasuredRootView(rootView);
+    @Nullable Bundle launchOptions = rootView.getLaunchOptions();
+    WritableMap initialProps = launchOptions != null
+        ? Arguments.fromBundle(launchOptions)
+        : Arguments.createMap();
+    String jsAppModuleName = rootView.getJSModuleName();
+
+    WritableNativeMap appParams = new WritableNativeMap();
+    appParams.putDouble("rootTag", rootTag);
+    appParams.putMap("initialProps", initialProps);
+    catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);
+  }
+
+  private void detachViewFromInstance(
+      ReactRootView rootView,
+      CatalystInstance catalystInstance) {
+    UiThreadUtil.assertOnUiThread();
+    catalystInstance.getJSModule(ReactNative.class)
+        .unmountComponentAtNodeAndRemoveContainer(rootView.getId());
+  }
+
+  private void tearDownReactContext(ReactContext reactContext) {
+    UiThreadUtil.assertOnUiThread();
+    if (mLifecycleState == LifecycleState.RESUMED) {
+      reactContext.onPause();
+    }
+    for (ReactRootView rootView : mAttachedRootViews) {
+      detachViewFromInstance(rootView, reactContext.getCatalystInstance());
+    }
+    reactContext.onDestroy();
+    mDevSupportManager.onReactInstanceDestroyed(reactContext);
+  }
+
+  /**
+   * @return instance of {@link ReactContext} configured a {@link CatalystInstance} set
+   */
+  private ReactApplicationContext createReactContext(
+      JavaScriptExecutor jsExecutor,
+      JSBundleLoader jsBundleLoader) {
+    FLog.i(ReactConstants.TAG, "Creating react context.");
+    mSourceUrl = jsBundleLoader.getSourceUrl();
+    NativeModuleRegistry.Builder nativeRegistryBuilder = new NativeModuleRegistry.Builder();
+    JavaScriptModulesConfig.Builder jsModulesBuilder = new JavaScriptModulesConfig.Builder();
+
+    ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);
+    if (mUseDeveloperSupport) {
+      reactContext.setNativeModuleCallExceptionHandler(mDevSupportManager);
+    }
+
+    CoreModulesPackage coreModulesPackage =
+        new CoreModulesPackage(this, mBackBtnHandler);
+    processPackage(coreModulesPackage, reactContext, nativeRegistryBuilder, jsModulesBuilder);
+
+    // TODO(6818138): Solve use-case of native/js modules overriding
+    for (ReactPackage reactPackage : mPackages) {
+      processPackage(reactPackage, reactContext, nativeRegistryBuilder, jsModulesBuilder);
+    }
+
+    CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
+        .setCatalystQueueConfigurationSpec(CatalystQueueConfigurationSpec.createDefault())
+        .setJSExecutor(jsExecutor)
+        .setRegistry(nativeRegistryBuilder.build())
+        .setJSModulesConfig(jsModulesBuilder.build())
+        .setJSBundleLoader(jsBundleLoader)
+        .setNativeModuleCallExceptionHandler(mDevSupportManager);
+
+    CatalystInstance catalystInstance = catalystInstanceBuilder.build();
+    if (mBridgeIdleDebugListener != null) {
+      catalystInstance.addBridgeIdleDebugListener(mBridgeIdleDebugListener);
+    }
+
+    reactContext.initializeWithInstance(catalystInstance);
+    catalystInstance.runJSBundle();
+
+    return reactContext;
+  }
+
+  private void processPackage(
+      ReactPackage reactPackage,
+      ReactApplicationContext reactContext,
+      NativeModuleRegistry.Builder nativeRegistryBuilder,
+      JavaScriptModulesConfig.Builder jsModulesBuilder) {
+    for (NativeModule nativeModule : reactPackage.createNativeModules(reactContext)) {
+      nativeRegistryBuilder.add(nativeModule);
+    }
+    for (Class<? extends JavaScriptModule> jsModuleClass : reactPackage.createJSModules()) {
+      jsModulesBuilder.add(jsModuleClass);
+    }
+  }
+
+  private void moveReactContextToCurrentLifecycleState(ReactApplicationContext reactContext) {
+    if (mLifecycleState == LifecycleState.RESUMED) {
+      reactContext.onResume(mCurrentActivity);
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
index ee913802237c..7e5afc3a47ff 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
@@ -11,27 +11,11 @@
 
 import javax.annotation.Nullable;
 
-import java.io.IOException;
-import java.io.StringWriter;
 import java.util.Collection;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
 
-import com.facebook.common.logging.FLog;
 import com.facebook.react.bridge.queue.CatalystQueueConfiguration;
-import com.facebook.react.bridge.queue.CatalystQueueConfigurationSpec;
-import com.facebook.react.bridge.queue.QueueThreadExceptionHandler;
 import com.facebook.proguard.annotations.DoNotStrip;
-import com.facebook.react.common.ReactConstants;
 import com.facebook.react.common.annotations.VisibleForTesting;
-import com.facebook.infer.annotation.Assertions;
-import com.facebook.systrace.Systrace;
-import com.facebook.systrace.TraceListener;
-
-import com.fasterxml.jackson.core.JsonFactory;
-import com.fasterxml.jackson.core.JsonGenerator;
 
 /**
  * A higher level API on top of the asynchronous JSC bridge. This provides an
@@ -39,254 +23,31 @@
  * Java APIs be invokable from JavaScript as well.
  */
 @DoNotStrip
-public class CatalystInstance {
-
-  private static final int BRIDGE_SETUP_TIMEOUT_MS = 30000;
-  private static final int LOAD_JS_BUNDLE_TIMEOUT_MS = 30000;
-
-  private static final AtomicInteger sNextInstanceIdForTrace = new AtomicInteger(1);
-
-  // Access from any thread
-  private final CatalystQueueConfiguration mCatalystQueueConfiguration;
-  private final CopyOnWriteArrayList<NotThreadSafeBridgeIdleDebugListener> mBridgeIdleListeners;
-  private final AtomicInteger mPendingJSCalls = new AtomicInteger(0);
-  private final String mJsPendingCallsTitleForTrace =
-      "pending_js_calls_instance" + sNextInstanceIdForTrace.getAndIncrement();
-  private volatile boolean mDestroyed = false;
-  private final TraceListener mTraceListener;
-  private final JavaScriptModuleRegistry mJSModuleRegistry;
-  private final JSBundleLoader mJSBundleLoader;
-
-  // Access from native modules thread
-  private final NativeModuleRegistry mJavaRegistry;
-  private final NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
-  private boolean mInitialized = false;
-
-  // Access from JS thread
-  private @Nullable ReactBridge mBridge;
-  private boolean mJSBundleHasLoaded;
-
-      private CatalystInstance(
-      final CatalystQueueConfigurationSpec catalystQueueConfigurationSpec,
-      final JavaScriptExecutor jsExecutor,
-      final NativeModuleRegistry registry,
-      final JavaScriptModulesConfig jsModulesConfig,
-      final JSBundleLoader jsBundleLoader,
-      NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
-    mCatalystQueueConfiguration = CatalystQueueConfiguration.create(
-        catalystQueueConfigurationSpec,
-        new NativeExceptionHandler());
-    mBridgeIdleListeners = new CopyOnWriteArrayList<>();
-    mJavaRegistry = registry;
-    mJSModuleRegistry = new JavaScriptModuleRegistry(CatalystInstance.this, jsModulesConfig);
-    mJSBundleLoader = jsBundleLoader;
-    mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
-    mTraceListener = new JSProfilerTraceListener();
-
-    final CountDownLatch initLatch = new CountDownLatch(1);
-    mCatalystQueueConfiguration.getJSQueueThread().runOnQueue(
-        new Runnable() {
-          @Override
-          public void run() {
-            initializeBridge(jsExecutor, jsModulesConfig);
-            initLatch.countDown();
-          }
-        });
-
-    try {
-      Assertions.assertCondition(
-          initLatch.await(BRIDGE_SETUP_TIMEOUT_MS, TimeUnit.MILLISECONDS),
-          "Timed out waiting for bridge to initialize!");
-    } catch (InterruptedException e) {
-      throw new RuntimeException(e);
-    }
-  }
-
-  private void initializeBridge(
-      JavaScriptExecutor jsExecutor,
-      JavaScriptModulesConfig jsModulesConfig) {
-    mCatalystQueueConfiguration.getJSQueueThread().assertIsOnThread();
-    Assertions.assertCondition(mBridge == null, "initializeBridge should be called once");
-
-    mBridge = new ReactBridge(
-        jsExecutor,
-        new NativeModulesReactCallback(),
-        mCatalystQueueConfiguration.getNativeModulesQueueThread());
-    mBridge.setGlobalVariable(
-        "__fbBatchedBridgeConfig",
-        buildModulesConfigJSONProperty(mJavaRegistry, jsModulesConfig));
-
-    Systrace.registerListener(mTraceListener);
-  }
-
-  public void runJSBundle() {
-    Systrace.beginSection(
-        Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
-        "CatalystInstance_runJSBundle");
-
-    try {
-      final CountDownLatch initLatch = new CountDownLatch(1);
-      mCatalystQueueConfiguration.getJSQueueThread().runOnQueue(
-          new Runnable() {
-            @Override
-            public void run() {
-              Assertions.assertCondition(!mJSBundleHasLoaded, "JS bundle was already loaded!");
-              mJSBundleHasLoaded = true;
-
-              incrementPendingJSCalls();
-
-              try {
-                mJSBundleLoader.loadScript(mBridge);
-              } catch (JSExecutionException e) {
-                mNativeModuleCallExceptionHandler.handleException(e);
-              }
-
-              initLatch.countDown();
-            }
-          });
-      Assertions.assertCondition(
-          initLatch.await(LOAD_JS_BUNDLE_TIMEOUT_MS, TimeUnit.MILLISECONDS),
-          "Timed out loading JS!");
-    } catch (InterruptedException e) {
-      throw new RuntimeException(e);
-    } finally {
-      Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
-    }
-  }
-
-  /* package */ void callFunction(
-      final int moduleId,
-      final int methodId,
-      final NativeArray arguments,
-      final String tracingName) {
-    if (mDestroyed) {
-      FLog.w(ReactConstants.TAG, "Calling JS function after bridge has been destroyed.");
-      return;
-    }
-
-    incrementPendingJSCalls();
-
-    mCatalystQueueConfiguration.getJSQueueThread().runOnQueue(
-        new Runnable() {
-          @Override
-          public void run() {
-            mCatalystQueueConfiguration.getJSQueueThread().assertIsOnThread();
-
-            if (mDestroyed) {
-              return;
-            }
-
-            Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, tracingName);
-            try {
-              Assertions.assertNotNull(mBridge).callFunction(moduleId, methodId, arguments);
-            } finally {
-              Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
-            }
-          }
-        });
-  }
-
+public interface CatalystInstance {
+  void runJSBundle();
   // This is called from java code, so it won't be stripped anyway, but proguard will rename it,
   // which this prevents.
   @DoNotStrip
-  /* package */ void invokeCallback(final int callbackID, final NativeArray arguments) {
-    if (mDestroyed) {
-      FLog.w(ReactConstants.TAG, "Invoking JS callback after bridge has been destroyed.");
-      return;
-    }
-
-    incrementPendingJSCalls();
-
-    mCatalystQueueConfiguration.getJSQueueThread().runOnQueue(
-        new Runnable() {
-          @Override
-          public void run() {
-            mCatalystQueueConfiguration.getJSQueueThread().assertIsOnThread();
-
-            if (mDestroyed) {
-              return;
-            }
-
-            Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "<callback>");
-            try {
-              Assertions.assertNotNull(mBridge).invokeCallback(callbackID, arguments);
-            } finally {
-              Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
-            }
-          }
-        });
-  }
-
+  void invokeCallback(final int callbackID, final NativeArray arguments);
   /**
    * Destroys this catalyst instance, waiting for any other threads in CatalystQueueConfiguration
    * (besides the UI thread) to finish running. Must be called from the UI thread so that we can
    * fully shut down other threads.
    */
-  /* package */ void destroy() {
-    UiThreadUtil.assertOnUiThread();
-
-    if (mDestroyed) {
-      return;
-    }
-
-    // TODO: tell all APIs to shut down
-    mDestroyed = true;
-    mJavaRegistry.notifyCatalystInstanceDestroy();
-    mCatalystQueueConfiguration.destroy();
-    boolean wasIdle = (mPendingJSCalls.getAndSet(0) == 0);
-    if (!wasIdle && !mBridgeIdleListeners.isEmpty()) {
-      for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) {
-        listener.onTransitionToBridgeIdle();
-      }
-    }
-
-    if (mBridge != null) {
-      Systrace.unregisterListener(mTraceListener);
-    }
-
-    // We can access the Bridge from any thread now because we know either we are on the JS thread
-    // or the JS thread has finished via CatalystQueueConfiguration#destroy()
-    Assertions.assertNotNull(mBridge).dispose();
-  }
-
-  public boolean isDestroyed() {
-    return mDestroyed;
-  }
+  void destroy();
+  boolean isDestroyed();
 
   /**
    * Initialize all the native modules
    */
   @VisibleForTesting
-  public void initialize() {
-    UiThreadUtil.assertOnUiThread();
-    Assertions.assertCondition(
-        !mInitialized,
-        "This catalyst instance has already been initialized");
-    mInitialized = true;
-    mJavaRegistry.notifyCatalystInstanceInitialized();
-  }
-
-  public CatalystQueueConfiguration getCatalystQueueConfiguration() {
-    return mCatalystQueueConfiguration;
-  }
-
-  @VisibleForTesting
-  public @Nullable
-  ReactBridge getBridge() {
-    return mBridge;
-  }
+  void initialize();
 
-  public <T extends JavaScriptModule> T getJSModule(Class<T> jsInterface) {
-    return Assertions.assertNotNull(mJSModuleRegistry).getJavaScriptModule(jsInterface);
-  }
+  CatalystQueueConfiguration getCatalystQueueConfiguration();
 
-  public <T extends NativeModule> T getNativeModule(Class<T> nativeModuleInterface) {
-    return mJavaRegistry.getModule(nativeModuleInterface);
-  }
-
-  public Collection<NativeModule> getNativeModules() {
-    return mJavaRegistry.getAllModules();
-  }
+  <T extends JavaScriptModule> T getJSModule(Class<T> jsInterface);
+  <T extends NativeModule> T getNativeModule(Class<T> nativeModuleInterface);
+  Collection<NativeModule> getNativeModules();
 
   /**
    * Adds a idle listener for this Catalyst instance. The listener will receive notifications
@@ -294,204 +55,15 @@ public Collection<NativeModule> getNativeModules() {
    * defined as there being some non-zero number of calls to JS that haven't resolved via a
    * onBatchCompleted call. The listener should be purely passive and not affect application logic.
    */
-  public void addBridgeIdleDebugListener(NotThreadSafeBridgeIdleDebugListener listener) {
-    mBridgeIdleListeners.add(listener);
-  }
+  void addBridgeIdleDebugListener(NotThreadSafeBridgeIdleDebugListener listener);
 
   /**
    * Removes a NotThreadSafeBridgeIdleDebugListener previously added with
    * {@link #addBridgeIdleDebugListener}
    */
-  public void removeBridgeIdleDebugListener(NotThreadSafeBridgeIdleDebugListener listener) {
-    mBridgeIdleListeners.remove(listener);
-  }
-
-  public boolean supportsProfiling() {
-    if (mBridge == null) {
-      return false;
-    }
-    return mBridge.supportsProfiling();
-  }
-
-  public void startProfiler(String title) {
-    if (mBridge == null) {
-      return;
-    }
-    mBridge.startProfiler(title);
-  }
-
-  public void stopProfiler(String title, String filename) {
-    if (mBridge == null) {
-      return;
-    }
-    mBridge.stopProfiler(title, filename);
-  }
-
-  private String buildModulesConfigJSONProperty(
-      NativeModuleRegistry nativeModuleRegistry,
-      JavaScriptModulesConfig jsModulesConfig) {
-    // TODO(5300733): Serialize config using single json generator
-    JsonFactory jsonFactory = new JsonFactory();
-    StringWriter writer = new StringWriter();
-    try {
-      JsonGenerator jg = jsonFactory.createGenerator(writer);
-      jg.writeStartObject();
-      jg.writeFieldName("remoteModuleConfig");
-      jg.writeRawValue(nativeModuleRegistry.moduleDescriptions());
-      jg.writeFieldName("localModulesConfig");
-      jg.writeRawValue(jsModulesConfig.moduleDescriptions());
-      jg.writeEndObject();
-      jg.close();
-    } catch (IOException ioe) {
-      throw new RuntimeException("Unable to serialize JavaScript module declaration", ioe);
-    }
-    return writer.getBuffer().toString();
-  }
-
-  private void incrementPendingJSCalls() {
-    int oldPendingCalls = mPendingJSCalls.getAndIncrement();
-    boolean wasIdle = oldPendingCalls == 0;
-    Systrace.traceCounter(
-        Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
-        mJsPendingCallsTitleForTrace,
-        oldPendingCalls + 1);
-    if (wasIdle && !mBridgeIdleListeners.isEmpty()) {
-      for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) {
-        listener.onTransitionToBridgeBusy();
-      }
-    }
-  }
-
-  private void decrementPendingJSCalls() {
-    int newPendingCalls = mPendingJSCalls.decrementAndGet();
-    Assertions.assertCondition(newPendingCalls >= 0);
-    boolean isNowIdle = newPendingCalls == 0;
-    Systrace.traceCounter(
-        Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
-        mJsPendingCallsTitleForTrace,
-        newPendingCalls);
-
-    if (isNowIdle && !mBridgeIdleListeners.isEmpty()) {
-      for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) {
-        listener.onTransitionToBridgeIdle();
-      }
-    }
-  }
-
-  private class NativeModulesReactCallback implements ReactCallback {
-
-    @Override
-    public void call(int moduleId, int methodId, ReadableNativeArray parameters) {
-      mCatalystQueueConfiguration.getNativeModulesQueueThread().assertIsOnThread();
-
-      // Suppress any callbacks if destroyed - will only lead to sadness.
-      if (mDestroyed) {
-        return;
-      }
-
-      mJavaRegistry.call(CatalystInstance.this, moduleId, methodId, parameters);
-    }
-
-    @Override
-    public void onBatchComplete() {
-      mCatalystQueueConfiguration.getNativeModulesQueueThread().assertIsOnThread();
-
-      // The bridge may have been destroyed due to an exception during the batch. In that case
-      // native modules could be in a bad state so we don't want to call anything on them. We
-      // still want to trigger the debug listener since it allows instrumentation tests to end and
-      // check their assertions without waiting for a timeout.
-      if (!mDestroyed) {
-        Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "onBatchComplete");
-        try {
-          mJavaRegistry.onBatchComplete();
-        } finally {
-          Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
-        }
-      }
-
-      decrementPendingJSCalls();
-    }
-  }
-
-  private class NativeExceptionHandler implements QueueThreadExceptionHandler {
-
-    @Override
-    public void handleException(Exception e) {
-      // Any Exception caught here is because of something in JS. Even if it's a bug in the
-      // framework/native code, it was triggered by JS and theoretically since we were able
-      // to set up the bridge, JS could change its logic, reload, and not trigger that crash.
-      mNativeModuleCallExceptionHandler.handleException(e);
-      mCatalystQueueConfiguration.getUIQueueThread().runOnQueue(
-          new Runnable() {
-            @Override
-            public void run() {
-              destroy();
-            }
-          });
-    }
-  }
-
-  private class JSProfilerTraceListener implements TraceListener {
-    @Override
-    public void onTraceStarted() {
-      getJSModule(BridgeProfiling.class).setEnabled(true);
-    }
-
-    @Override
-    public void onTraceStopped() {
-      getJSModule(BridgeProfiling.class).setEnabled(false);
-    }
-  }
-
-  public static class Builder {
-
-    private @Nullable CatalystQueueConfigurationSpec mCatalystQueueConfigurationSpec;
-    private @Nullable JSBundleLoader mJSBundleLoader;
-    private @Nullable NativeModuleRegistry mRegistry;
-    private @Nullable JavaScriptModulesConfig mJSModulesConfig;
-    private @Nullable JavaScriptExecutor mJSExecutor;
-    private @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
-
-    public Builder setCatalystQueueConfigurationSpec(
-        CatalystQueueConfigurationSpec catalystQueueConfigurationSpec) {
-      mCatalystQueueConfigurationSpec = catalystQueueConfigurationSpec;
-      return this;
-    }
-
-    public Builder setRegistry(NativeModuleRegistry registry) {
-      mRegistry = registry;
-      return this;
-    }
-
-    public Builder setJSModulesConfig(JavaScriptModulesConfig jsModulesConfig) {
-      mJSModulesConfig = jsModulesConfig;
-      return this;
-    }
-
-    public Builder setJSBundleLoader(JSBundleLoader jsBundleLoader) {
-      mJSBundleLoader = jsBundleLoader;
-      return this;
-    }
-
-    public Builder setJSExecutor(JavaScriptExecutor jsExecutor) {
-      mJSExecutor = jsExecutor;
-      return this;
-    }
-
-    public Builder setNativeModuleCallExceptionHandler(
-        NativeModuleCallExceptionHandler handler) {
-      mNativeModuleCallExceptionHandler = handler;
-      return this;
-    }
+  void removeBridgeIdleDebugListener(NotThreadSafeBridgeIdleDebugListener listener);
 
-    public CatalystInstance build() {
-      return new CatalystInstance(
-          Assertions.assertNotNull(mCatalystQueueConfigurationSpec),
-          Assertions.assertNotNull(mJSExecutor),
-          Assertions.assertNotNull(mRegistry),
-          Assertions.assertNotNull(mJSModulesConfig),
-          Assertions.assertNotNull(mJSBundleLoader),
-          Assertions.assertNotNull(mNativeModuleCallExceptionHandler));
-    }
-  }
+  boolean supportsProfiling();
+  void startProfiler(String title);
+  void stopProfiler(String title, String filename);
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
new file mode 100644
index 000000000000..4b987e78d256
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
@@ -0,0 +1,510 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.bridge;
+
+import javax.annotation.Nullable;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.Collection;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import com.facebook.common.logging.FLog;
+import com.facebook.react.bridge.queue.CatalystQueueConfiguration;
+import com.facebook.react.bridge.queue.CatalystQueueConfigurationImpl;
+import com.facebook.react.bridge.queue.CatalystQueueConfigurationSpec;
+import com.facebook.react.bridge.queue.QueueThreadExceptionHandler;
+import com.facebook.proguard.annotations.DoNotStrip;
+import com.facebook.react.common.ReactConstants;
+import com.facebook.react.common.annotations.VisibleForTesting;
+import com.facebook.infer.annotation.Assertions;
+import com.facebook.systrace.Systrace;
+import com.facebook.systrace.TraceListener;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+
+/**
+ * This provides an implementation of the public CatalystInstance instance.  It is public because
+ * it is built by ReactInstanceManager which is in a different package.
+ */
+@DoNotStrip
+public class CatalystInstanceImpl implements CatalystInstance {
+
+  private static final int BRIDGE_SETUP_TIMEOUT_MS = 30000;
+  private static final int LOAD_JS_BUNDLE_TIMEOUT_MS = 30000;
+
+  private static final AtomicInteger sNextInstanceIdForTrace = new AtomicInteger(1);
+
+  // Access from any thread
+  private final CatalystQueueConfigurationImpl mCatalystQueueConfiguration;
+  private final CopyOnWriteArrayList<NotThreadSafeBridgeIdleDebugListener> mBridgeIdleListeners;
+  private final AtomicInteger mPendingJSCalls = new AtomicInteger(0);
+  private final String mJsPendingCallsTitleForTrace =
+      "pending_js_calls_instance" + sNextInstanceIdForTrace.getAndIncrement();
+  private volatile boolean mDestroyed = false;
+  private final TraceListener mTraceListener;
+  private final JavaScriptModuleRegistry mJSModuleRegistry;
+  private final JSBundleLoader mJSBundleLoader;
+
+  // Access from native modules thread
+  private final NativeModuleRegistry mJavaRegistry;
+  private final NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
+  private boolean mInitialized = false;
+
+  // Access from JS thread
+  private @Nullable ReactBridge mBridge;
+  private boolean mJSBundleHasLoaded;
+
+  private CatalystInstanceImpl(
+      final CatalystQueueConfigurationSpec catalystQueueConfigurationSpec,
+      final JavaScriptExecutor jsExecutor,
+      final NativeModuleRegistry registry,
+      final JavaScriptModulesConfig jsModulesConfig,
+      final JSBundleLoader jsBundleLoader,
+      NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
+    mCatalystQueueConfiguration = CatalystQueueConfigurationImpl.create(
+        catalystQueueConfigurationSpec,
+        new NativeExceptionHandler());
+    mBridgeIdleListeners = new CopyOnWriteArrayList<>();
+    mJavaRegistry = registry;
+    mJSModuleRegistry = new JavaScriptModuleRegistry(CatalystInstanceImpl.this, jsModulesConfig);
+    mJSBundleLoader = jsBundleLoader;
+    mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
+    mTraceListener = new JSProfilerTraceListener();
+
+    final CountDownLatch initLatch = new CountDownLatch(1);
+    mCatalystQueueConfiguration.getJSQueueThread().runOnQueue(
+        new Runnable() {
+          @Override
+          public void run() {
+            initializeBridge(jsExecutor, jsModulesConfig);
+            initLatch.countDown();
+          }
+        });
+
+    try {
+      Assertions.assertCondition(
+          initLatch.await(BRIDGE_SETUP_TIMEOUT_MS, TimeUnit.MILLISECONDS),
+          "Timed out waiting for bridge to initialize!");
+    } catch (InterruptedException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  private void initializeBridge(
+      JavaScriptExecutor jsExecutor,
+      JavaScriptModulesConfig jsModulesConfig) {
+    mCatalystQueueConfiguration.getJSQueueThread().assertIsOnThread();
+    Assertions.assertCondition(mBridge == null, "initializeBridge should be called once");
+
+    mBridge = new ReactBridge(
+        jsExecutor,
+        new NativeModulesReactCallback(),
+        mCatalystQueueConfiguration.getNativeModulesQueueThread());
+    mBridge.setGlobalVariable(
+        "__fbBatchedBridgeConfig",
+        buildModulesConfigJSONProperty(mJavaRegistry, jsModulesConfig));
+    Systrace.registerListener(mTraceListener);
+  }
+
+  @Override
+  public void runJSBundle() {
+    Systrace.beginSection(
+        Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
+        "CatalystInstance_runJSBundle");
+
+    try {
+      final CountDownLatch initLatch = new CountDownLatch(1);
+      mCatalystQueueConfiguration.getJSQueueThread().runOnQueue(
+          new Runnable() {
+            @Override
+            public void run() {
+              Assertions.assertCondition(!mJSBundleHasLoaded, "JS bundle was already loaded!");
+              mJSBundleHasLoaded = true;
+
+              incrementPendingJSCalls();
+
+              try {
+                mJSBundleLoader.loadScript(mBridge);
+              } catch (JSExecutionException e) {
+                mNativeModuleCallExceptionHandler.handleException(e);
+              }
+
+              initLatch.countDown();
+            }
+          });
+      Assertions.assertCondition(
+          initLatch.await(LOAD_JS_BUNDLE_TIMEOUT_MS, TimeUnit.MILLISECONDS),
+          "Timed out loading JS!");
+    } catch (InterruptedException e) {
+      throw new RuntimeException(e);
+    } finally {
+      Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+    }
+  }
+
+  /* package */ void callFunction(
+      final int moduleId,
+      final int methodId,
+      final NativeArray arguments,
+      final String tracingName) {
+    if (mDestroyed) {
+      FLog.w(ReactConstants.TAG, "Calling JS function after bridge has been destroyed.");
+      return;
+    }
+
+    incrementPendingJSCalls();
+
+    mCatalystQueueConfiguration.getJSQueueThread().runOnQueue(
+        new Runnable() {
+          @Override
+          public void run() {
+            mCatalystQueueConfiguration.getJSQueueThread().assertIsOnThread();
+
+            if (mDestroyed) {
+              return;
+            }
+
+            Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, tracingName);
+            try {
+              Assertions.assertNotNull(mBridge).callFunction(moduleId, methodId, arguments);
+            } finally {
+              Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+            }
+          }
+        });
+  }
+
+  // This is called from java code, so it won't be stripped anyway, but proguard will rename it,
+  // which this prevents.
+  @DoNotStrip
+  @Override
+  public void invokeCallback(final int callbackID, final NativeArray arguments) {
+    if (mDestroyed) {
+      FLog.w(ReactConstants.TAG, "Invoking JS callback after bridge has been destroyed.");
+      return;
+    }
+
+    incrementPendingJSCalls();
+
+    mCatalystQueueConfiguration.getJSQueueThread().runOnQueue(
+        new Runnable() {
+          @Override
+          public void run() {
+            mCatalystQueueConfiguration.getJSQueueThread().assertIsOnThread();
+
+            if (mDestroyed) {
+              return;
+            }
+
+            Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "<callback>");
+            try {
+              Assertions.assertNotNull(mBridge).invokeCallback(callbackID, arguments);
+            } finally {
+              Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+            }
+          }
+        });
+  }
+
+  /**
+   * Destroys this catalyst instance, waiting for any other threads in CatalystQueueConfiguration
+   * (besides the UI thread) to finish running. Must be called from the UI thread so that we can
+   * fully shut down other threads.
+   */
+  @Override
+  public void destroy() {
+    UiThreadUtil.assertOnUiThread();
+
+    if (mDestroyed) {
+      return;
+    }
+
+    // TODO: tell all APIs to shut down
+    mDestroyed = true;
+    mJavaRegistry.notifyCatalystInstanceDestroy();
+    mCatalystQueueConfiguration.destroy();
+    boolean wasIdle = (mPendingJSCalls.getAndSet(0) == 0);
+    if (!wasIdle && !mBridgeIdleListeners.isEmpty()) {
+      for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) {
+        listener.onTransitionToBridgeIdle();
+      }
+    }
+
+    if (mBridge != null) {
+      Systrace.unregisterListener(mTraceListener);
+    }
+
+    // We can access the Bridge from any thread now because we know either we are on the JS thread
+    // or the JS thread has finished via CatalystQueueConfiguration#destroy()
+    Assertions.assertNotNull(mBridge).dispose();
+  }
+
+  @Override
+  public boolean isDestroyed() {
+    return mDestroyed;
+  }
+
+  /**
+   * Initialize all the native modules
+   */
+  @VisibleForTesting
+  @Override
+  public void initialize() {
+    UiThreadUtil.assertOnUiThread();
+    Assertions.assertCondition(
+        !mInitialized,
+        "This catalyst instance has already been initialized");
+    mInitialized = true;
+    mJavaRegistry.notifyCatalystInstanceInitialized();
+  }
+
+  @Override
+  public CatalystQueueConfiguration getCatalystQueueConfiguration() {
+    return mCatalystQueueConfiguration;
+  }
+
+  @VisibleForTesting
+  public @Nullable
+  ReactBridge getBridge() {
+    return mBridge;
+  }
+
+  @Override
+  public <T extends JavaScriptModule> T getJSModule(Class<T> jsInterface) {
+    return Assertions.assertNotNull(mJSModuleRegistry).getJavaScriptModule(jsInterface);
+  }
+
+  @Override
+  public <T extends NativeModule> T getNativeModule(Class<T> nativeModuleInterface) {
+    return mJavaRegistry.getModule(nativeModuleInterface);
+  }
+
+  @Override
+  public Collection<NativeModule> getNativeModules() {
+    return mJavaRegistry.getAllModules();
+  }
+
+  /**
+   * Adds a idle listener for this Catalyst instance. The listener will receive notifications
+   * whenever the bridge transitions from idle to busy and vice-versa, where the busy state is
+   * defined as there being some non-zero number of calls to JS that haven't resolved via a
+   * onBatchCompleted call. The listener should be purely passive and not affect application logic.
+   */
+  @Override
+  public void addBridgeIdleDebugListener(NotThreadSafeBridgeIdleDebugListener listener) {
+    mBridgeIdleListeners.add(listener);
+  }
+
+  /**
+   * Removes a NotThreadSafeBridgeIdleDebugListener previously added with
+   * {@link #addBridgeIdleDebugListener}
+   */
+  @Override
+  public void removeBridgeIdleDebugListener(NotThreadSafeBridgeIdleDebugListener listener) {
+    mBridgeIdleListeners.remove(listener);
+  }
+
+  @Override
+  public boolean supportsProfiling() {
+    if (mBridge == null) {
+      return false;
+    }
+    return mBridge.supportsProfiling();
+  }
+
+  @Override
+  public void startProfiler(String title) {
+    if (mBridge == null) {
+      return;
+    }
+    mBridge.startProfiler(title);
+  }
+
+  @Override
+  public void stopProfiler(String title, String filename) {
+    if (mBridge == null) {
+      return;
+    }
+    mBridge.stopProfiler(title, filename);
+  }
+
+  private String buildModulesConfigJSONProperty(
+      NativeModuleRegistry nativeModuleRegistry,
+      JavaScriptModulesConfig jsModulesConfig) {
+    // TODO(5300733): Serialize config using single json generator
+    JsonFactory jsonFactory = new JsonFactory();
+    StringWriter writer = new StringWriter();
+    try {
+      JsonGenerator jg = jsonFactory.createGenerator(writer);
+      jg.writeStartObject();
+      jg.writeFieldName("remoteModuleConfig");
+      jg.writeRawValue(nativeModuleRegistry.moduleDescriptions());
+      jg.writeFieldName("localModulesConfig");
+      jg.writeRawValue(jsModulesConfig.moduleDescriptions());
+      jg.writeEndObject();
+      jg.close();
+    } catch (IOException ioe) {
+      throw new RuntimeException("Unable to serialize JavaScript module declaration", ioe);
+    }
+    return writer.getBuffer().toString();
+  }
+
+  private void incrementPendingJSCalls() {
+    int oldPendingCalls = mPendingJSCalls.getAndIncrement();
+    boolean wasIdle = oldPendingCalls == 0;
+    Systrace.traceCounter(
+        Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
+        mJsPendingCallsTitleForTrace,
+        oldPendingCalls + 1);
+    if (wasIdle && !mBridgeIdleListeners.isEmpty()) {
+      for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) {
+        listener.onTransitionToBridgeBusy();
+      }
+    }
+  }
+
+  private void decrementPendingJSCalls() {
+    int newPendingCalls = mPendingJSCalls.decrementAndGet();
+    Assertions.assertCondition(newPendingCalls >= 0);
+    boolean isNowIdle = newPendingCalls == 0;
+    Systrace.traceCounter(
+        Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
+        mJsPendingCallsTitleForTrace,
+        newPendingCalls);
+
+    if (isNowIdle && !mBridgeIdleListeners.isEmpty()) {
+      for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) {
+        listener.onTransitionToBridgeIdle();
+      }
+    }
+  }
+
+  private class NativeModulesReactCallback implements ReactCallback {
+
+    @Override
+    public void call(int moduleId, int methodId, ReadableNativeArray parameters) {
+      mCatalystQueueConfiguration.getNativeModulesQueueThread().assertIsOnThread();
+
+      // Suppress any callbacks if destroyed - will only lead to sadness.
+      if (mDestroyed) {
+        return;
+      }
+
+      mJavaRegistry.call(CatalystInstanceImpl.this, moduleId, methodId, parameters);
+    }
+
+    @Override
+    public void onBatchComplete() {
+      mCatalystQueueConfiguration.getNativeModulesQueueThread().assertIsOnThread();
+
+      // The bridge may have been destroyed due to an exception during the batch. In that case
+      // native modules could be in a bad state so we don't want to call anything on them. We
+      // still want to trigger the debug listener since it allows instrumentation tests to end and
+      // check their assertions without waiting for a timeout.
+      if (!mDestroyed) {
+        Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "onBatchComplete");
+        try {
+          mJavaRegistry.onBatchComplete();
+        } finally {
+          Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+        }
+      }
+
+      decrementPendingJSCalls();
+    }
+  }
+
+  private class NativeExceptionHandler implements QueueThreadExceptionHandler {
+
+    @Override
+    public void handleException(Exception e) {
+      // Any Exception caught here is because of something in JS. Even if it's a bug in the
+      // framework/native code, it was triggered by JS and theoretically since we were able
+      // to set up the bridge, JS could change its logic, reload, and not trigger that crash.
+      mNativeModuleCallExceptionHandler.handleException(e);
+      mCatalystQueueConfiguration.getUIQueueThread().runOnQueue(
+          new Runnable() {
+            @Override
+            public void run() {
+              destroy();
+            }
+          });
+    }
+  }
+
+  private class JSProfilerTraceListener implements TraceListener {
+    @Override
+    public void onTraceStarted() {
+      getJSModule(BridgeProfiling.class).setEnabled(true);
+    }
+
+    @Override
+    public void onTraceStopped() {
+      getJSModule(BridgeProfiling.class).setEnabled(false);
+    }
+  }
+
+  public static class Builder {
+
+    private @Nullable CatalystQueueConfigurationSpec mCatalystQueueConfigurationSpec;
+    private @Nullable JSBundleLoader mJSBundleLoader;
+    private @Nullable NativeModuleRegistry mRegistry;
+    private @Nullable JavaScriptModulesConfig mJSModulesConfig;
+    private @Nullable JavaScriptExecutor mJSExecutor;
+    private @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
+
+    public Builder setCatalystQueueConfigurationSpec(
+        CatalystQueueConfigurationSpec catalystQueueConfigurationSpec) {
+      mCatalystQueueConfigurationSpec = catalystQueueConfigurationSpec;
+      return this;
+    }
+
+    public Builder setRegistry(NativeModuleRegistry registry) {
+      mRegistry = registry;
+      return this;
+    }
+
+    public Builder setJSModulesConfig(JavaScriptModulesConfig jsModulesConfig) {
+      mJSModulesConfig = jsModulesConfig;
+      return this;
+    }
+
+    public Builder setJSBundleLoader(JSBundleLoader jsBundleLoader) {
+      mJSBundleLoader = jsBundleLoader;
+      return this;
+    }
+
+    public Builder setJSExecutor(JavaScriptExecutor jsExecutor) {
+      mJSExecutor = jsExecutor;
+      return this;
+    }
+
+    public Builder setNativeModuleCallExceptionHandler(
+        NativeModuleCallExceptionHandler handler) {
+      mNativeModuleCallExceptionHandler = handler;
+      return this;
+    }
+
+    public CatalystInstanceImpl build() {
+      return new CatalystInstanceImpl(
+          Assertions.assertNotNull(mCatalystQueueConfigurationSpec),
+          Assertions.assertNotNull(mJSExecutor),
+          Assertions.assertNotNull(mRegistry),
+          Assertions.assertNotNull(mJSModulesConfig),
+          Assertions.assertNotNull(mJSBundleLoader),
+          Assertions.assertNotNull(mNativeModuleCallExceptionHandler));
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModuleRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModuleRegistry.java
index fab0f231e339..093770fe05fd 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModuleRegistry.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModuleRegistry.java
@@ -30,7 +30,7 @@
   private final HashMap<Class<? extends JavaScriptModule>, JavaScriptModule> mModuleInstances;
 
   public JavaScriptModuleRegistry(
-      CatalystInstance instance,
+      CatalystInstanceImpl instance,
       JavaScriptModulesConfig config) {
     mModuleInstances = new HashMap<>();
     for (JavaScriptModuleRegistration registration : config.getModuleDefinitions()) {
@@ -52,11 +52,11 @@ public <T extends JavaScriptModule> T getJavaScriptModule(Class<T> moduleInterfa
 
   private static class JavaScriptModuleInvocationHandler implements InvocationHandler {
 
-    private final CatalystInstance mCatalystInstance;
+    private final CatalystInstanceImpl mCatalystInstance;
     private final JavaScriptModuleRegistration mModuleRegistration;
 
     public JavaScriptModuleInvocationHandler(
-        CatalystInstance catalystInstance,
+        CatalystInstanceImpl catalystInstance,
         JavaScriptModuleRegistration moduleRegistration) {
       mCatalystInstance = catalystInstance;
       mModuleRegistration = moduleRegistration;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/CatalystQueueConfiguration.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/CatalystQueueConfiguration.java
index 10be2a44df10..99fec74857d3 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/CatalystQueueConfiguration.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/CatalystQueueConfiguration.java
@@ -9,12 +9,6 @@
 
 package com.facebook.react.bridge.queue;
 
-import java.util.Map;
-
-import android.os.Looper;
-
-import com.facebook.react.common.MapBuilder;
-
 /**
  * Specifies which {@link MessageQueueThread}s must be used to run the various contexts of
  * execution within catalyst (Main UI thread, native modules, and JS). Some of these queues *may* be
@@ -24,67 +18,8 @@
  * Native Modules Queue Thread: The thread and Looper that native modules are invoked on.
  * JS Queue Thread: The thread and Looper that JS is executed on.
  */
-public class CatalystQueueConfiguration {
-
-  private final MessageQueueThread mUIQueueThread;
-  private final MessageQueueThread mNativeModulesQueueThread;
-  private final MessageQueueThread mJSQueueThread;
-
-  private CatalystQueueConfiguration(
-      MessageQueueThread uiQueueThread,
-      MessageQueueThread nativeModulesQueueThread,
-      MessageQueueThread jsQueueThread) {
-    mUIQueueThread = uiQueueThread;
-    mNativeModulesQueueThread = nativeModulesQueueThread;
-    mJSQueueThread = jsQueueThread;
-  }
-
-  public MessageQueueThread getUIQueueThread() {
-    return mUIQueueThread;
-  }
-
-  public MessageQueueThread getNativeModulesQueueThread() {
-    return mNativeModulesQueueThread;
-  }
-
-  public MessageQueueThread getJSQueueThread() {
-    return mJSQueueThread;
-  }
-
-  /**
-   * Should be called when the corresponding {@link com.facebook.react.bridge.CatalystInstance}
-   * is destroyed so that we shut down the proper queue threads.
-   */
-  public void destroy() {
-    if (mNativeModulesQueueThread.getLooper() != Looper.getMainLooper()) {
-      mNativeModulesQueueThread.quitSynchronous();
-    }
-    if (mJSQueueThread.getLooper() != Looper.getMainLooper()) {
-      mJSQueueThread.quitSynchronous();
-    }
-  }
-
-  public static CatalystQueueConfiguration create(
-      CatalystQueueConfigurationSpec spec,
-      QueueThreadExceptionHandler exceptionHandler) {
-    Map<MessageQueueThreadSpec, MessageQueueThread> specsToThreads = MapBuilder.newHashMap();
-
-    MessageQueueThreadSpec uiThreadSpec = MessageQueueThreadSpec.mainThreadSpec();
-    MessageQueueThread uiThread = MessageQueueThread.create( uiThreadSpec, exceptionHandler);
-    specsToThreads.put(uiThreadSpec, uiThread);
-
-    MessageQueueThread jsThread = specsToThreads.get(spec.getJSQueueThreadSpec());
-    if (jsThread == null) {
-      jsThread = MessageQueueThread.create(spec.getJSQueueThreadSpec(), exceptionHandler);
-    }
-
-    MessageQueueThread nativeModulesThread =
-        specsToThreads.get(spec.getNativeModulesQueueThreadSpec());
-    if (nativeModulesThread == null) {
-      nativeModulesThread =
-          MessageQueueThread.create(spec.getNativeModulesQueueThreadSpec(), exceptionHandler);
-    }
-
-    return new CatalystQueueConfiguration(uiThread, nativeModulesThread, jsThread);
-  }
+public interface CatalystQueueConfiguration {
+  MessageQueueThread getUIQueueThread();
+  MessageQueueThread getNativeModulesQueueThread();
+  MessageQueueThread getJSQueueThread();
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/CatalystQueueConfigurationImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/CatalystQueueConfigurationImpl.java
new file mode 100644
index 000000000000..c6b8be58b0ea
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/CatalystQueueConfigurationImpl.java
@@ -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.
+ */
+
+package com.facebook.react.bridge.queue;
+
+import java.util.Map;
+
+import android.os.Looper;
+
+import com.facebook.react.common.MapBuilder;
+
+public class CatalystQueueConfigurationImpl implements CatalystQueueConfiguration {
+
+  private final MessageQueueThreadImpl mUIQueueThread;
+  private final MessageQueueThreadImpl mNativeModulesQueueThread;
+  private final MessageQueueThreadImpl mJSQueueThread;
+
+  private CatalystQueueConfigurationImpl(
+      MessageQueueThreadImpl uiQueueThread,
+      MessageQueueThreadImpl nativeModulesQueueThread,
+      MessageQueueThreadImpl jsQueueThread) {
+    mUIQueueThread = uiQueueThread;
+    mNativeModulesQueueThread = nativeModulesQueueThread;
+    mJSQueueThread = jsQueueThread;
+  }
+
+  @Override
+  public MessageQueueThread getUIQueueThread() {
+    return mUIQueueThread;
+  }
+
+  @Override
+  public MessageQueueThread getNativeModulesQueueThread() {
+    return mNativeModulesQueueThread;
+  }
+
+  @Override
+  public MessageQueueThread getJSQueueThread() {
+    return mJSQueueThread;
+  }
+
+  /**
+   * Should be called when the corresponding {@link com.facebook.react.bridge.CatalystInstance}
+   * is destroyed so that we shut down the proper queue threads.
+   */
+  public void destroy() {
+    if (mNativeModulesQueueThread.getLooper() != Looper.getMainLooper()) {
+      mNativeModulesQueueThread.quitSynchronous();
+    }
+    if (mJSQueueThread.getLooper() != Looper.getMainLooper()) {
+      mJSQueueThread.quitSynchronous();
+    }
+  }
+
+  public static CatalystQueueConfigurationImpl create(
+      CatalystQueueConfigurationSpec spec,
+      QueueThreadExceptionHandler exceptionHandler) {
+    Map<MessageQueueThreadSpec, MessageQueueThreadImpl> specsToThreads = MapBuilder.newHashMap();
+
+    MessageQueueThreadSpec uiThreadSpec = MessageQueueThreadSpec.mainThreadSpec();
+    MessageQueueThreadImpl uiThread =
+      MessageQueueThreadImpl.create( uiThreadSpec, exceptionHandler);
+    specsToThreads.put(uiThreadSpec, uiThread);
+
+    MessageQueueThreadImpl jsThread = specsToThreads.get(spec.getJSQueueThreadSpec());
+    if (jsThread == null) {
+      jsThread = MessageQueueThreadImpl.create(spec.getJSQueueThreadSpec(), exceptionHandler);
+    }
+
+    MessageQueueThreadImpl nativeModulesThread =
+        specsToThreads.get(spec.getNativeModulesQueueThreadSpec());
+    if (nativeModulesThread == null) {
+      nativeModulesThread =
+          MessageQueueThreadImpl.create(spec.getNativeModulesQueueThreadSpec(), exceptionHandler);
+    }
+
+    return new CatalystQueueConfigurationImpl(uiThread, nativeModulesThread, jsThread);
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThread.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThread.java
index 0090b82ad0bf..b04285a6f601 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThread.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThread.java
@@ -9,136 +9,28 @@
 
 package com.facebook.react.bridge.queue;
 
-import android.os.Looper;
-
-import com.facebook.common.logging.FLog;
 import com.facebook.proguard.annotations.DoNotStrip;
-import com.facebook.react.bridge.AssertionException;
-import com.facebook.react.bridge.SoftAssertions;
-import com.facebook.react.common.ReactConstants;
-import com.facebook.react.common.futures.SimpleSettableFuture;
 
 /**
- * Encapsulates a Thread that has a {@link Looper} running on it that can accept Runnables.
+ * Encapsulates a Thread that can accept Runnables.
  */
 @DoNotStrip
-public class MessageQueueThread {
-
-  private final String mName;
-  private final Looper mLooper;
-  private final MessageQueueThreadHandler mHandler;
-  private final String mAssertionErrorMessage;
-  private volatile boolean mIsFinished = false;
-
-  private MessageQueueThread(
-      String name,
-      Looper looper,
-      QueueThreadExceptionHandler exceptionHandler) {
-    mName = name;
-    mLooper = looper;
-    mHandler = new MessageQueueThreadHandler(looper, exceptionHandler);
-    mAssertionErrorMessage = "Expected to be called from the '" + getName() + "' thread!";
-  }
-
+public interface MessageQueueThread {
   /**
    * Runs the given Runnable on this Thread. It will be submitted to the end of the event queue even
    * if it is being submitted from the same queue Thread.
    */
   @DoNotStrip
-  public void runOnQueue(Runnable runnable) {
-    if (mIsFinished) {
-      FLog.w(
-          ReactConstants.TAG,
-          "Tried to enqueue runnable on already finished thread: '" + getName() +
-              "... dropping Runnable.");
-    }
-    mHandler.post(runnable);
-  }
+  void runOnQueue(Runnable runnable);
 
   /**
    * @return whether the current Thread is also the Thread associated with this MessageQueueThread.
    */
-  public boolean isOnThread() {
-    return mLooper.getThread() == Thread.currentThread();
-  }
+  boolean isOnThread();
 
   /**
    * Asserts {@link #isOnThread()}, throwing a {@link AssertionException} (NOT an
    * {@link AssertionError}) if the assertion fails.
    */
-  public void assertIsOnThread() {
-    SoftAssertions.assertCondition(isOnThread(), mAssertionErrorMessage);
-  }
-
-  /**
-   * Quits this queue's Looper. If that Looper was running on a different Thread than the current
-   * Thread, also waits for the last message being processed to finish and the Thread to die.
-   */
-  public void quitSynchronous() {
-    mIsFinished = true;
-    mLooper.quit();
-    if (mLooper.getThread() != Thread.currentThread()) {
-      try {
-        mLooper.getThread().join();
-      } catch (InterruptedException e) {
-        throw new RuntimeException("Got interrupted waiting to join thread " + mName);
-      }
-    }
-  }
-
-  public Looper getLooper() {
-    return mLooper;
-  }
-
-  public String getName() {
-    return mName;
-  }
-
-  public static MessageQueueThread create(
-      MessageQueueThreadSpec spec,
-      QueueThreadExceptionHandler exceptionHandler) {
-    switch (spec.getThreadType()) {
-      case MAIN_UI:
-        return createForMainThread(spec.getName(), exceptionHandler);
-      case NEW_BACKGROUND:
-        return startNewBackgroundThread(spec.getName(), exceptionHandler);
-      default:
-        throw new RuntimeException("Unknown thread type: " + spec.getThreadType());
-    }
-  }
-
-  /**
-   * @return a MessageQueueThread corresponding to Android's main UI thread.
-   */
-  private static MessageQueueThread createForMainThread(
-      String name,
-      QueueThreadExceptionHandler exceptionHandler) {
-    Looper mainLooper = Looper.getMainLooper();
-    return new MessageQueueThread(name, mainLooper, exceptionHandler);
-  }
-
-  /**
-   * Creates  and starts a new MessageQueueThread encapsulating a new Thread with a new Looper
-   * running on it. Give it a name for easier debugging. When this method exits, the new
-   * MessageQueueThread is ready to receive events.
-   */
-  private static MessageQueueThread startNewBackgroundThread(
-      String name,
-      QueueThreadExceptionHandler exceptionHandler) {
-    final SimpleSettableFuture<Looper> simpleSettableFuture = new SimpleSettableFuture<>();
-    Thread bgThread = new Thread(
-        new Runnable() {
-          @Override
-          public void run() {
-            Looper.prepare();
-
-            simpleSettableFuture.set(Looper.myLooper());
-
-            Looper.loop();
-          }
-        }, "mqt_" + name);
-    bgThread.start();
-
-    return new MessageQueueThread(name, simpleSettableFuture.get(5000), exceptionHandler);
-  }
+  void assertIsOnThread();
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java
new file mode 100644
index 000000000000..5453e5355638
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java
@@ -0,0 +1,144 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.bridge.queue;
+
+import android.os.Looper;
+
+import com.facebook.common.logging.FLog;
+import com.facebook.proguard.annotations.DoNotStrip;
+import com.facebook.react.bridge.AssertionException;
+import com.facebook.react.bridge.SoftAssertions;
+import com.facebook.react.common.ReactConstants;
+import com.facebook.react.common.futures.SimpleSettableFuture;
+
+/**
+ * Encapsulates a Thread that has a {@link Looper} running on it that can accept Runnables.
+ */
+@DoNotStrip
+/* package */ class MessageQueueThreadImpl implements MessageQueueThread {
+
+  private final String mName;
+  private final Looper mLooper;
+  private final MessageQueueThreadHandler mHandler;
+  private final String mAssertionErrorMessage;
+  private volatile boolean mIsFinished = false;
+
+  private MessageQueueThreadImpl(
+      String name,
+      Looper looper,
+      QueueThreadExceptionHandler exceptionHandler) {
+    mName = name;
+    mLooper = looper;
+    mHandler = new MessageQueueThreadHandler(looper, exceptionHandler);
+    mAssertionErrorMessage = "Expected to be called from the '" + getName() + "' thread!";
+  }
+
+  /**
+   * Runs the given Runnable on this Thread. It will be submitted to the end of the event queue even
+   * if it is being submitted from the same queue Thread.
+   */
+  @DoNotStrip
+  public void runOnQueue(Runnable runnable) {
+    if (mIsFinished) {
+      FLog.w(
+          ReactConstants.TAG,
+          "Tried to enqueue runnable on already finished thread: '" + getName() +
+              "... dropping Runnable.");
+    }
+    mHandler.post(runnable);
+  }
+
+  /**
+   * @return whether the current Thread is also the Thread associated with this MessageQueueThread.
+   */
+  public boolean isOnThread() {
+    return mLooper.getThread() == Thread.currentThread();
+  }
+
+  /**
+   * Asserts {@link #isOnThread()}, throwing a {@link AssertionException} (NOT an
+   * {@link AssertionError}) if the assertion fails.
+   */
+  public void assertIsOnThread() {
+    SoftAssertions.assertCondition(isOnThread(), mAssertionErrorMessage);
+  }
+
+  /**
+   * Quits this queue's Looper. If that Looper was running on a different Thread than the current
+   * Thread, also waits for the last message being processed to finish and the Thread to die.
+   */
+  public void quitSynchronous() {
+    mIsFinished = true;
+    mLooper.quit();
+    if (mLooper.getThread() != Thread.currentThread()) {
+      try {
+        mLooper.getThread().join();
+      } catch (InterruptedException e) {
+        throw new RuntimeException("Got interrupted waiting to join thread " + mName);
+      }
+    }
+  }
+
+  public Looper getLooper() {
+    return mLooper;
+  }
+
+  public String getName() {
+    return mName;
+  }
+
+  public static MessageQueueThreadImpl create(
+      MessageQueueThreadSpec spec,
+      QueueThreadExceptionHandler exceptionHandler) {
+    switch (spec.getThreadType()) {
+      case MAIN_UI:
+        return createForMainThread(spec.getName(), exceptionHandler);
+      case NEW_BACKGROUND:
+        return startNewBackgroundThread(spec.getName(), exceptionHandler);
+      default:
+        throw new RuntimeException("Unknown thread type: " + spec.getThreadType());
+    }
+  }
+
+  /**
+   * @return a MessageQueueThreadImpl corresponding to Android's main UI thread.
+   */
+  private static MessageQueueThreadImpl createForMainThread(
+      String name,
+      QueueThreadExceptionHandler exceptionHandler) {
+    Looper mainLooper = Looper.getMainLooper();
+    return new MessageQueueThreadImpl(name, mainLooper, exceptionHandler);
+  }
+
+  /**
+   * Creates  and starts a new MessageQueueThreadImpl encapsulating a new Thread with a new Looper
+   * running on it. Give it a name for easier debugging. When this method exits, the new
+   * MessageQueueThreadImpl is ready to receive events.
+   */
+  private static MessageQueueThreadImpl startNewBackgroundThread(
+      String name,
+      QueueThreadExceptionHandler exceptionHandler) {
+    final SimpleSettableFuture<Looper> simpleSettableFuture = new SimpleSettableFuture<>();
+    Thread bgThread = new Thread(
+        new Runnable() {
+          @Override
+          public void run() {
+            Looper.prepare();
+
+            simpleSettableFuture.set(Looper.myLooper());
+
+            Looper.loop();
+          }
+        }, "mqt_" + name);
+    bgThread.start();
+
+    return new MessageQueueThreadImpl(name, simpleSettableFuture.get(5000), exceptionHandler);
+  }
+}

From 945a1c72dbc70efc492c68b4b959bdaff8bc1a09 Mon Sep 17 00:00:00 2001
From: Ricky Reusser <rsreusser@gmail.com>
Date: Fri, 20 Nov 2015 15:43:07 -0500
Subject: [PATCH 0035/1411] Note in docs that Android geolocation not yet open
 sourced

---
 Libraries/Geolocation/Geolocation.js | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Libraries/Geolocation/Geolocation.js b/Libraries/Geolocation/Geolocation.js
index b6752e3f08c2..681a5f77b895 100644
--- a/Libraries/Geolocation/Geolocation.js
+++ b/Libraries/Geolocation/Geolocation.js
@@ -42,6 +42,10 @@ type GeoOptions = {
  * app's `AndroidManifest.xml`:
  *
  * `<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />`
+ *
+ * Geolocation support for Android is planned but not yet open sourced. See
+ * [Known Issues](http://facebook.github.io/react-native/docs/known-issues.html#missing-modules-and-native-views).
+ *
  */
 var Geolocation = {
 

From 8ab51828ff077ae0ad10c06f62f9f01d58b9bf85 Mon Sep 17 00:00:00 2001
From: Tim Yung <yungsters@fb.com>
Date: Fri, 20 Nov 2015 13:05:34 -0800
Subject: [PATCH 0036/1411] RN: Revamp YellowBox for Warnings

Reviewed By: vjeux

Differential Revision: D2667624

fb-gh-sync-id: f3c6ed63f3138edd13e7fe283cf877d598018813
---
 Examples/UIExplorer/RCTRootViewIOSExample.js  |  15 +-
 Libraries/ReactIOS/WarningBox.js              | 393 ------------------
 Libraries/ReactIOS/YellowBox.js               | 335 +++++++++++++++
 .../ReactIOS/renderApplication.android.js     |   9 +-
 Libraries/ReactIOS/renderApplication.ios.js   |  13 +-
 5 files changed, 361 insertions(+), 404 deletions(-)
 delete mode 100644 Libraries/ReactIOS/WarningBox.js
 create mode 100644 Libraries/ReactIOS/YellowBox.js

diff --git a/Examples/UIExplorer/RCTRootViewIOSExample.js b/Examples/UIExplorer/RCTRootViewIOSExample.js
index 174dcf2bb947..69ecab0a7655 100644
--- a/Examples/UIExplorer/RCTRootViewIOSExample.js
+++ b/Examples/UIExplorer/RCTRootViewIOSExample.js
@@ -15,19 +15,20 @@
  */
 
 'use strict';
-var React = require('react-native');
-var {
+
+const React = require('react-native');
+const {
   StyleSheet,
   Text,
   View,
 } = React;
 
-var requireNativeComponent = require('requireNativeComponent');
-var UpdatePropertiesExampleView = requireNativeComponent('UpdatePropertiesExampleView');
-var FlexibleSizeExampleView = requireNativeComponent('FlexibleSizeExampleView');
+const requireNativeComponent = require('requireNativeComponent');
 
 class AppPropertiesUpdateExample extends React.Component {
   render() {
+    // Do not require this unless we are actually rendering.
+    const UpdatePropertiesExampleView = requireNativeComponent('UpdatePropertiesExampleView');
     return (
       <View style={styles.container}>
         <Text style={styles.text}>
@@ -45,6 +46,8 @@ class AppPropertiesUpdateExample extends React.Component {
 
 class RootViewSizeFlexibilityExample extends React.Component {
   render() {
+    // Do not require this unless we are actually rendering.
+    const FlexibleSizeExampleView = requireNativeComponent('FlexibleSizeExampleView');
     return (
       <View style={styles.container}>
         <Text style={styles.text}>
@@ -60,7 +63,7 @@ class RootViewSizeFlexibilityExample extends React.Component {
   }
 }
 
-var styles = StyleSheet.create({
+const styles = StyleSheet.create({
   container: {
     flex: 1,
     backgroundColor: '#F5FCFF',
diff --git a/Libraries/ReactIOS/WarningBox.js b/Libraries/ReactIOS/WarningBox.js
deleted file mode 100644
index 09ac954c5502..000000000000
--- a/Libraries/ReactIOS/WarningBox.js
+++ /dev/null
@@ -1,393 +0,0 @@
-/**
- * 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 WarningBox
- */
-'use strict';
-
-var AsyncStorage = require('AsyncStorage');
-var EventEmitter = require('EventEmitter');
-var Map = require('Map');
-var PanResponder = require('PanResponder');
-var React = require('React');
-var StyleSheet = require('StyleSheet');
-var Text = require('Text');
-var TouchableOpacity = require('TouchableOpacity');
-var View = require('View');
-
-var invariant = require('invariant');
-var rebound = require('rebound');
-var stringifySafe = require('stringifySafe');
-
-var SCREEN_WIDTH = require('Dimensions').get('window').width;
-var IGNORED_WARNINGS_KEY = '__DEV_WARNINGS_IGNORED';
-
-var consoleWarn = console.warn.bind(console);
-
-var warningCounts = new Map();
-var ignoredWarnings: Array<string> = [];
-var totalWarningCount = 0;
-var warningCountEvents = new EventEmitter();
-
-/**
- * WarningBox renders warnings on top of the app being developed. Warnings help
- * guard against subtle yet significant issues that can impact the quality of
- * your application, such as accessibility and memory leaks. This "in your
- * face" style of warning allows developers to notice and correct these issues
- * as quickly as possible.
- *
- * The warning box is currently opt-in. Set the following flag to enable it:
- *
- * `console.yellowBoxEnabled = true;`
- *
- * If "ignore" is tapped on a warning, the WarningBox will record that warning
- * and will not display it again. This is useful for hiding errors that already
- * exist or have been introduced elsewhere. To re-enable all of the errors, set
- * the following:
- *
- * `console.yellowBoxResetIgnored = true;`
- *
- * This can also be set permanently, and ignore will only silence the warnings
- * until the next refresh.
- */
-
-if (__DEV__) {
-  console.warn = function() {
-    consoleWarn.apply(null, arguments);
-    if (!console.yellowBoxEnabled) {
-      return;
-    }
-    var warning = Array.prototype.map.call(arguments, stringifySafe).join(' ');
-    if (!console.yellowBoxResetIgnored &&
-        ignoredWarnings.indexOf(warning) !== -1) {
-      return;
-    }
-    var count = warningCounts.has(warning) ? warningCounts.get(warning) + 1 : 1;
-    warningCounts.set(warning, count);
-    totalWarningCount += 1;
-    warningCountEvents.emit('count', totalWarningCount);
-  };
-}
-
-function saveIgnoredWarnings() {
-  AsyncStorage.setItem(
-    IGNORED_WARNINGS_KEY,
-    JSON.stringify(ignoredWarnings),
-    function(err) {
-      if (err) {
-        console.warn('Could not save ignored warnings.', err);
-      }
-    }
-  );
-}
-
-AsyncStorage.getItem(IGNORED_WARNINGS_KEY, function(err, data) {
-  if (!err && data && !console.yellowBoxResetIgnored) {
-    ignoredWarnings = JSON.parse(data);
-  }
-});
-
-var WarningRow = React.createClass({
-  componentWillMount: function() {
-    this.springSystem = new rebound.SpringSystem();
-    this.dismissalSpring = this.springSystem.createSpring();
-    this.dismissalSpring.setRestSpeedThreshold(0.05);
-    this.dismissalSpring.setCurrentValue(0);
-    this.dismissalSpring.addListener({
-      onSpringUpdate: () => {
-        var val = this.dismissalSpring.getCurrentValue();
-        this.text && this.text.setNativeProps({
-          left: SCREEN_WIDTH * val,
-        });
-        this.container && this.container.setNativeProps({
-          opacity: 1 - val,
-        });
-        this.closeButton && this.closeButton.setNativeProps({
-          opacity: 1 - (val * 5),
-        });
-      },
-      onSpringAtRest: () => {
-        if (this.dismissalSpring.getCurrentValue()) {
-          this.collapseSpring.setEndValue(1);
-        }
-      },
-    });
-    this.collapseSpring = this.springSystem.createSpring();
-    this.collapseSpring.setRestSpeedThreshold(0.05);
-    this.collapseSpring.setCurrentValue(0);
-    this.collapseSpring.getSpringConfig().friction = 20;
-    this.collapseSpring.getSpringConfig().tension = 200;
-    this.collapseSpring.addListener({
-      onSpringUpdate: () => {
-        var val = this.collapseSpring.getCurrentValue();
-        this.container && this.container.setNativeProps({
-          height: Math.abs(46 - (val * 46)),
-        });
-      },
-      onSpringAtRest: () => {
-        this.props.onDismissed();
-      },
-    });
-    this.panGesture = PanResponder.create({
-      onStartShouldSetPanResponder: () => {
-        return !!this.dismissalSpring.getCurrentValue();
-      },
-      onMoveShouldSetPanResponder: () => true,
-      onPanResponderGrant: () => {
-        this.isResponderOnlyToBlockTouches =
-          !!this.dismissalSpring.getCurrentValue();
-      },
-      onPanResponderMove: (e, gestureState) => {
-        if (this.isResponderOnlyToBlockTouches) {
-          return;
-        }
-        this.dismissalSpring.setCurrentValue(gestureState.dx / SCREEN_WIDTH);
-      },
-      onPanResponderRelease: (e, gestureState) => {
-        if (this.isResponderOnlyToBlockTouches) {
-          return;
-        }
-        var gestureCompletion = gestureState.dx / SCREEN_WIDTH;
-        var doesGestureRelease = (gestureState.vx + gestureCompletion) > 0.5;
-        this.dismissalSpring.setEndValue(doesGestureRelease ? 1 : 0);
-      }
-    });
-  },
-  render: function() {
-    var countText;
-    if (warningCounts.get(this.props.warning) > 1) {
-      countText = (
-        <Text style={styles.bold}>
-          ({warningCounts.get(this.props.warning)}){" "}
-        </Text>
-      );
-    }
-    return (
-      <View
-        style={styles.warningBox}
-        ref={container => { this.container = container; }}
-        {...this.panGesture.panHandlers}>
-        <TouchableOpacity
-          onPress={this.props.onOpened}>
-          <Text
-            style={styles.warningText}
-            numberOfLines={2}
-            ref={text => { this.text = text; }}>
-            {countText}
-            {this.props.warning}
-          </Text>
-        </TouchableOpacity>
-        <View
-          ref={closeButton => { this.closeButton = closeButton; }}
-          style={styles.closeButton}>
-          <TouchableOpacity
-            onPress={() => {
-              this.dismissalSpring.setEndValue(1);
-            }}>
-            <Text style={styles.closeButtonText}>✕</Text>
-          </TouchableOpacity>
-        </View>
-      </View>
-    );
-  }
-});
-
-var WarningBoxOpened = React.createClass({
-  render: function() {
-    var countText;
-    if (warningCounts.get(this.props.warning) > 1) {
-      countText = (
-        <Text style={styles.bold}>
-          ({warningCounts.get(this.props.warning)}){" "}
-        </Text>
-      );
-    }
-    return (
-      <TouchableOpacity
-        activeOpacity={0.9}
-        onPress={this.props.onClose}
-        style={styles.yellowBox}>
-        <Text style={styles.yellowBoxText}>
-          {countText}
-          {this.props.warning}
-        </Text>
-        <View style={styles.yellowBoxButtons}>
-          <TouchableOpacity
-            onPress={this.props.onDismissed}
-            style={styles.yellowBoxButton}>
-            <Text style={styles.yellowBoxButtonText}>
-              Dismiss
-            </Text>
-          </TouchableOpacity>
-          <TouchableOpacity
-            onPress={this.props.onIgnored}
-            style={styles.yellowBoxButton}>
-            <Text style={styles.yellowBoxButtonText}>
-              Ignore
-            </Text>
-          </TouchableOpacity>
-        </View>
-      </TouchableOpacity>
-    );
-  },
-});
-
-var canMountWarningBox = true;
-
-var WarningBox = React.createClass({
-  getInitialState: function() {
-    return {
-      totalWarningCount,
-      openWarning: null,
-    };
-  },
-  componentWillMount: function() {
-    if (console.yellowBoxResetIgnored) {
-      AsyncStorage.setItem(IGNORED_WARNINGS_KEY, '[]', function(err) {
-        if (err) {
-          console.warn('Could not reset ignored warnings.', err);
-        }
-      });
-      ignoredWarnings = [];
-    }
-  },
-  componentDidMount: function() {
-    invariant(
-      canMountWarningBox,
-      'There can only be one WarningBox'
-    );
-    canMountWarningBox = false;
-    warningCountEvents.addListener(
-      'count',
-      this._onWarningCount
-    );
-  },
-  componentWillUnmount: function() {
-    warningCountEvents.removeAllListeners();
-    canMountWarningBox = true;
-  },
-  _onWarningCount: function(totalWarningCount) {
-    // Must use setImmediate because warnings often happen during render and
-    // state cannot be set while rendering
-    setImmediate(() => {
-      this.setState({ totalWarningCount, });
-    });
-  },
-  _onDismiss: function(warning) {
-    warningCounts.delete(warning);
-    this.setState({
-      openWarning: null,
-    });
-  },
-  render: function() {
-    if (warningCounts.size === 0) {
-      return <View />;
-    }
-    if (this.state.openWarning) {
-      return (
-        <WarningBoxOpened
-          warning={this.state.openWarning}
-          onClose={() => {
-            this.setState({ openWarning: null });
-          }}
-          onDismissed={this._onDismiss.bind(this, this.state.openWarning)}
-          onIgnored={() => {
-            ignoredWarnings.push(this.state.openWarning);
-            saveIgnoredWarnings();
-            this._onDismiss(this.state.openWarning);
-          }}
-        />
-      );
-    }
-    var warningRows = [];
-    warningCounts.forEach((count, warning) => {
-      warningRows.push(
-        <WarningRow
-          key={warning}
-          onOpened={() => {
-            this.setState({ openWarning: warning });
-          }}
-          onDismissed={this._onDismiss.bind(this, warning)}
-          warning={warning}
-        />
-      );
-    });
-    return (
-      <View style={styles.warningContainer}>
-        {warningRows}
-      </View>
-    );
-  },
-});
-
-var styles = StyleSheet.create({
-  bold: {
-    fontWeight: 'bold',
-  },
-  closeButton: {
-    position: 'absolute',
-    right: 0,
-    height: 46,
-    width: 46,
-  },
-  closeButtonText: {
-    color: 'white',
-    fontSize: 32,
-    position: 'relative',
-    left: 8,
-  },
-  warningContainer: {
-    position: 'absolute',
-    left: 0,
-    right: 0,
-    bottom: 0
-  },
-  warningBox: {
-    position: 'relative',
-    backgroundColor: 'rgba(171, 124, 36, 0.9)',
-    flex: 1,
-    height: 46,
-  },
-  warningText: {
-    color: 'white',
-    position: 'absolute',
-    left: 0,
-    marginLeft: 15,
-    marginRight: 46,
-    top: 7,
-  },
-  yellowBox: {
-    backgroundColor: 'rgba(171, 124, 36, 0.9)',
-    position: 'absolute',
-    left: 0,
-    right: 0,
-    top: 0,
-    bottom: 0,
-    padding: 15,
-    paddingTop: 35,
-  },
-  yellowBoxText: {
-    color: 'white',
-    fontSize: 20,
-  },
-  yellowBoxButtons: {
-    flexDirection: 'row',
-    position: 'absolute',
-    bottom: 0,
-  },
-  yellowBoxButton: {
-    flex: 1,
-    padding: 25,
-  },
-  yellowBoxButtonText: {
-    color: 'white',
-    fontSize: 16,
-  }
-});
-
-module.exports = WarningBox;
diff --git a/Libraries/ReactIOS/YellowBox.js b/Libraries/ReactIOS/YellowBox.js
new file mode 100644
index 000000000000..c439b4e20cba
--- /dev/null
+++ b/Libraries/ReactIOS/YellowBox.js
@@ -0,0 +1,335 @@
+/**
+ * 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 YellowBox
+ * @flow
+ */
+
+'use strict';
+
+const EventEmitter = require('EventEmitter');
+import type EmitterSubscription from 'EmitterSubscription';
+const Map = require('Map');
+const Platform = require('Platform');
+const React = require('React');
+const StyleSheet = require('StyleSheet');
+
+const _warningEmitter = new EventEmitter();
+const _warningMap = new Map();
+
+/**
+ * YellowBox renders warnings at the bottom of the app being developed.
+ *
+ * Warnings help guard against subtle yet significant issues that can impact the
+ * quality of the app. This "in your face" style of warning allows developers to
+ * notice and correct these issues as quickly as possible.
+ *
+ * By default, the warning box is enabled in `__DEV__`. Set the following flag
+ * to disable it (and call `console.warn` to update any rendered <YellowBox>):
+ *
+ *   console.disableYellowBox = true;
+ *   console.warn('YellowBox is disabled.');
+ *
+ * Warnings can be ignored programmatically by setting the array:
+ *
+ *   console.ignoredYellowBox = ['Warning: ...'];
+ *
+ * Strings in `console.ignoredYellowBox` can be a prefix of the warning that
+ * should be ignored.
+ */
+
+if (__DEV__) {
+  const {error, warn} = console;
+  console.error = function() {
+    error.apply(console, arguments);
+    // Show yellow box for the `warning` module.
+    if (typeof arguments[0] === 'string' &&
+        arguments[0].startsWith('Warning: ')) {
+      updateWarningMap.apply(null, arguments);
+    }
+  };
+  console.warn = function() {
+    warn.apply(console, arguments);
+    updateWarningMap.apply(null, arguments);
+  };
+}
+
+function updateWarningMap(format, ...args): void {
+  const sprintf = require('sprintf');
+  const stringifySafe = require('stringifySafe');
+
+  format = String(format);
+  const argCount = (format.match(/%s/g) || []).length;
+  const warning = [
+    sprintf(format, ...args.slice(0, argCount)),
+    ...args.slice(argCount).map(stringifySafe),
+  ].join(' ');
+
+  const count = _warningMap.has(warning) ? _warningMap.get(warning) : 0;
+  _warningMap.set(warning, count + 2);
+  _warningEmitter.emit('warning', _warningMap);
+}
+
+function isWarningIgnored(warning: string): boolean {
+  return (
+    Array.isArray(console.ignoredYellowBox) &&
+    console.ignoredYellowBox.some(
+      ignorePrefix => warning.startsWith(ignorePrefix)
+    )
+  );
+}
+
+const WarningRow = ({count, warning, onPress}) => {
+  const Text = require('Text');
+  const TouchableHighlight = require('TouchableHighlight');
+  const View = require('View');
+
+  const countText = count > 1 ?
+    <Text style={styles.listRowCount}>{'(' + count + ') '}</Text> :
+    null;
+
+  return (
+    <View style={styles.listRow}>
+      <TouchableHighlight
+        activeOpacity={0.5}
+        onPress={onPress}
+        style={styles.listRowContent}
+        underlayColor="transparent">
+        <Text style={styles.listRowText} numberOfLines={2}>
+          {countText}
+          {warning}
+        </Text>
+      </TouchableHighlight>
+    </View>
+  );
+};
+
+const WarningInspector = ({count, warning, onClose, onDismiss}) => {
+  const ScrollView = require('ScrollView');
+  const Text = require('Text');
+  const TouchableHighlight = require('TouchableHighlight');
+  const View = require('View');
+
+  const countSentence =
+    'Warning encountered ' + count + ' time' + (count - 1 ? 's' : '') + '.';
+
+  return (
+    <TouchableHighlight
+      activeOpacity={0.95}
+      underlayColor={backgroundColor(0.8)}
+      onPress={onClose}
+      style={styles.inspector}>
+      <View style={styles.inspectorContent}>
+        <View style={styles.inspectorCount}>
+          <Text style={styles.inspectorCountText}>{countSentence}</Text>
+        </View>
+        <ScrollView style={styles.inspectorWarning}>
+          <Text style={styles.inspectorWarningText}>{warning}</Text>
+        </ScrollView>
+        <View style={styles.inspectorButtons}>
+          <TouchableHighlight
+            activeOpacity={0.5}
+            onPress={onDismiss}
+            style={styles.inspectorButton}
+            underlayColor="transparent">
+            <Text style={styles.inspectorButtonText}>
+              Dismiss Warning
+            </Text>
+          </TouchableHighlight>
+        </View>
+      </View>
+    </TouchableHighlight>
+  );
+};
+
+class YellowBox extends React.Component {
+  state: {
+    inspecting: ?string;
+    warningMap: Map;
+  };
+  _listener: ?EmitterSubscription;
+
+  constructor(props: mixed, context: mixed) {
+    super(props, context);
+    this.state = {
+      inspecting: null,
+      warningMap: _warningMap,
+    };
+    this.dismissWarning = warning => {
+      const {inspecting, warningMap} = this.state;
+      warningMap.delete(warning);
+      this.setState({
+        inspecting: inspecting === warning ? null : inspecting,
+        warningMap,
+      });
+    };
+  }
+
+  componentDidMount() {
+    let scheduled = null;
+    this._listener = _warningEmitter.addListener('warning', warningMap => {
+      // Use `setImmediate` because warnings often happen during render, but
+      // state cannot be set while rendering.
+      scheduled = scheduled || setImmediate(() => {
+        scheduled = null;
+        this.setState({
+          warningMap,
+        });
+      });
+    });
+  }
+
+  componentWillUnmount() {
+    if (this._listener) {
+      this._listener.remove();
+    }
+  }
+
+  render() {
+    if (console.disableYellowBox || this.state.warningMap.size === 0) {
+      return null;
+    }
+    const ScrollView = require('ScrollView');
+    const View = require('View');
+
+    const inspecting = this.state.inspecting;
+    const inspector = inspecting !== null ?
+      <WarningInspector
+        count={this.state.warningMap.get(inspecting)}
+        warning={inspecting}
+        onClose={() => this.setState({inspecting: null})}
+        onDismiss={() => this.dismissWarning(inspecting)}
+      /> :
+      null;
+
+    const rows = [];
+    this.state.warningMap.forEach((count, warning) => {
+      if (!isWarningIgnored(warning)) {
+        rows.push(
+          <WarningRow
+            key={warning}
+            count={count}
+            warning={warning}
+            onPress={() => this.setState({inspecting: warning})}
+            onDismiss={() => this.dismissWarning(warning)}
+          />
+        );
+      }
+    });
+
+    const listStyle = [
+      styles.list,
+      // Additional `0.4` so the 5th row can peek into view.
+      {height: Math.min(rows.length, 4.4) * (rowGutter + rowHeight)},
+    ];
+    return (
+      <View style={inspector ? styles.fullScreen : listStyle}>
+        <ScrollView style={listStyle}>
+          {rows}
+        </ScrollView>
+        {inspector}
+      </View>
+    );
+  }
+}
+
+const backgroundColor = opacity => 'rgba(250, 186, 48, ' + opacity + ')';
+const textColor = 'white';
+const rowGutter = 1;
+const rowHeight = 46;
+
+var styles = StyleSheet.create({
+  fullScreen: {
+    backgroundColor: 'transparent',
+    position: 'absolute',
+    left: 0,
+    right: 0,
+    top: 0,
+    bottom: 0,
+  },
+  inspector: {
+    backgroundColor: backgroundColor(0.95),
+    flex: 1,
+  },
+  inspectorContainer: {
+    flex: 1,
+  },
+  inspectorButtons: {
+    flexDirection: 'row',
+    position: 'absolute',
+    left: 0,
+    right: 0,
+    bottom: 0,
+  },
+  inspectorButton: {
+    padding: 22,
+    position: 'absolute',
+    left: 0,
+    right: 0,
+    bottom: 0,
+  },
+  inspectorButtonText: {
+    color: textColor,
+    fontSize: 14,
+    opacity: 0.8,
+    textAlign: 'center',
+  },
+  inspectorContent: {
+    flex: 1,
+    paddingTop: 5,
+  },
+  inspectorCount: {
+    padding: 15,
+    paddingBottom: 0,
+  },
+  inspectorCountText: {
+    color: textColor,
+    fontSize: 14,
+  },
+  inspectorWarning: {
+    padding: 15,
+    position: 'absolute',
+    top: 39,
+    bottom: 60,
+  },
+  inspectorWarningText: {
+    color: textColor,
+    fontSize: 16,
+    fontWeight: '600',
+  },
+  list: {
+    backgroundColor: 'transparent',
+    position: 'absolute',
+    left: 0,
+    right: 0,
+    bottom: 0,
+  },
+  listRow: {
+    position: 'relative',
+    backgroundColor: backgroundColor(0.95),
+    flex: 1,
+    height: rowHeight,
+    marginTop: rowGutter,
+  },
+  listRowContent: {
+    flex: 1,
+  },
+  listRowCount: {
+    color: 'rgba(255, 255, 255, 0.5)',
+  },
+  listRowText: {
+    color: textColor,
+    position: 'absolute',
+    left: 0,
+    top: Platform.OS === 'android' ? 5 : 7,
+    marginLeft: 15,
+    marginRight: 15,
+  },
+});
+
+module.exports = YellowBox;
diff --git a/Libraries/ReactIOS/renderApplication.android.js b/Libraries/ReactIOS/renderApplication.android.js
index d299c2eb3842..05b87178b6f5 100644
--- a/Libraries/ReactIOS/renderApplication.android.js
+++ b/Libraries/ReactIOS/renderApplication.android.js
@@ -8,6 +8,7 @@
  *
  * @providesModule renderApplication
  */
+
 'use strict';
 
 var Inspector = require('Inspector');
@@ -20,6 +21,8 @@ var View = require('View');
 
 var invariant = require('invariant');
 
+var YellowBox = __DEV__ ? require('YellowBox') : null;
+
 // require BackAndroid so it sets the default handler that exits the app if no listeners respond
 require('BackAndroid');
 
@@ -89,10 +92,14 @@ var AppContainer = React.createClass({
         <Portal
           onModalVisibilityChanged={this.setRootAccessibility}/>
       </View>;
-
+    let yellowBox = null;
+    if (__DEV__) {
+      yellowBox = <YellowBox />;
+    }
     return this.state.enabled ?
       <View style={styles.appContainer}>
         {appView}
+        {yellowBox}
         {this.renderInspector()}
       </View> :
       appView;
diff --git a/Libraries/ReactIOS/renderApplication.ios.js b/Libraries/ReactIOS/renderApplication.ios.js
index 01eb1e5d53f9..0b0f306d6be3 100644
--- a/Libraries/ReactIOS/renderApplication.ios.js
+++ b/Libraries/ReactIOS/renderApplication.ios.js
@@ -8,6 +8,7 @@
  *
  * @providesModule renderApplication
  */
+
 'use strict';
 
 var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
@@ -19,7 +20,7 @@ var View = require('View');
 var invariant = require('invariant');
 
 var Inspector = __DEV__ ? require('Inspector') : null;
-var WarningBox = __DEV__ ? require('WarningBox') : null;
+var YellowBox = __DEV__ ? require('YellowBox') : null;
 
 var AppContainer = React.createClass({
   mixins: [Subscribable.Mixin],
@@ -47,14 +48,16 @@ var AppContainer = React.createClass({
   },
 
   render: function() {
-    var shouldRenderWarningBox = __DEV__ && console.yellowBoxEnabled;
-    var warningBox = shouldRenderWarningBox ? <WarningBox /> : null;
+    let yellowBox = null;
+    if (__DEV__) {
+      yellowBox = <YellowBox />;
+    }
     return (
       <View style={styles.appContainer}>
         <View collapsible={false} style={styles.appContainer} ref="main">
           {this.props.children}
         </View>
-        {warningBox}
+        {yellowBox}
         {this.state.inspector}
       </View>
     );
@@ -70,6 +73,7 @@ function renderApplication<D, P, S>(
     rootTag,
     'Expect to have a valid rootTag, instead got ', rootTag
   );
+  /* eslint-disable jsx-no-undef-with-namespace */
   React.render(
     <AppContainer rootTag={rootTag}>
       <RootComponent
@@ -79,6 +83,7 @@ function renderApplication<D, P, S>(
     </AppContainer>,
     rootTag
   );
+  /* eslint-enable jsx-no-undef-with-namespace */
 }
 
 var styles = StyleSheet.create({

From 43f18ffd087280e6df1e4900deb6fe201b87741a Mon Sep 17 00:00:00 2001
From: Sebastian Markbage <sema@fb.com>
Date: Fri, 20 Nov 2015 20:17:17 -0800
Subject: [PATCH 0037/1411] Add infra for Prepack build option

Summary: This adds a build option for using Prepack (an experimental packager) to
build a bundle. It doesn't actually take on the npm package dependency
because it's not published/open source (yet).

This will be used while we experiment and should be maintained as the
build system changes so that we can continue getting fresh builds.

I found that saveBundleAndMap and processBundle were over abstracted and
got in my way so I inlined it and removed the unit tests because the unit
test was testing trivial code that is likely to change interface.

I went with a separate build phase and a separate Bundle class even though
there are a lot of commonalities. I imagine that the requirements for
Prepack will continue to diverge. Especially for source maps but a larger
refactor could try to unify these a bit more. The fact that modules are
wrapped before the write phase seems to be an unfortunate architecture
that makes this difficult.
Closes https://github.com/facebook/react-native/pull/4226

Reviewed By: amasad

Differential Revision: D2673760

Pulled By: sebmarkbage

fb-gh-sync-id: 299ccc42e4be1d9dee19ade443ea3388db2e39a8
---
 .../bundle/__tests__/saveBundleAndMap-test.js |  63 --------
 local-cli/bundle/buildBundle.js               | 108 +++++++++++--
 local-cli/bundle/bundleCommandLineArgs.js     |   8 +
 local-cli/bundle/processBundle.js             |  29 ----
 .../{saveBundleAndMap.js => saveAssets.js}    |  22 +--
 packager/react-packager/index.js              |   9 ++
 .../src/Bundler/PrepackBundle.js              | 149 ++++++++++++++++++
 packager/react-packager/src/Bundler/index.js  | 104 +++++++++---
 packager/react-packager/src/Server/index.js   |  11 ++
 .../src/SocketInterface/SocketClient.js       |   8 +
 .../src/SocketInterface/SocketServer.js       |   8 +
 11 files changed, 372 insertions(+), 147 deletions(-)
 delete mode 100644 local-cli/bundle/__tests__/saveBundleAndMap-test.js
 delete mode 100644 local-cli/bundle/processBundle.js
 rename local-cli/bundle/{saveBundleAndMap.js => saveAssets.js} (80%)
 create mode 100644 packager/react-packager/src/Bundler/PrepackBundle.js

diff --git a/local-cli/bundle/__tests__/saveBundleAndMap-test.js b/local-cli/bundle/__tests__/saveBundleAndMap-test.js
deleted file mode 100644
index 4bd516a05d46..000000000000
--- a/local-cli/bundle/__tests__/saveBundleAndMap-test.js
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-jest.autoMockOff();
-
-jest.mock('fs');
-jest.mock('../sign');
-
-const saveBundleAndMap = require('../saveBundleAndMap');
-const fs = require('fs');
-const temp = require('temp');
-
-const code = 'const foo = "bar";';
-const map = JSON.stringify({
-  version: 3,
-  file: 'foo.js.map',
-  sources: ['foo.js'],
-  sourceRoot: '/',
-  names: ['bar'],
-  mappings: 'AAA0B,kBAAhBA,QAAOC,SACjBD,OAAOC,OAAO'
-});
-
-describe('saveBundleAndMap', () => {
-  beforeEach(() => {
-    fs.writeFileSync = jest.genMockFn();
-  });
-
-  it('should save bundle', () => {
-    const codeWithMap = {code: code};
-    const bundleOutput = temp.path({suffix: '.bundle'});
-
-    saveBundleAndMap(
-      codeWithMap,
-      'ios',
-      bundleOutput,
-      'utf8',
-    );
-
-    expect(fs.writeFileSync.mock.calls[0]).toEqual([bundleOutput, code, 'utf8']);
-  });
-
-  it('should save sourcemaps if required so', () => {
-    const codeWithMap = {code: code, map: map};
-    const bundleOutput = temp.path({suffix: '.bundle'});
-    const sourceMapOutput = temp.path({suffix: '.map'});
-    saveBundleAndMap(
-      codeWithMap,
-      'ios',
-      bundleOutput,
-      'utf8',
-      sourceMapOutput
-    );
-
-    expect(fs.writeFileSync.mock.calls[1]).toEqual([sourceMapOutput, map]);
-  });
-});
diff --git a/local-cli/bundle/buildBundle.js b/local-cli/bundle/buildBundle.js
index f69eea5a8d78..5cb752a43b1c 100644
--- a/local-cli/bundle/buildBundle.js
+++ b/local-cli/bundle/buildBundle.js
@@ -8,11 +8,57 @@
  */
 'use strict';
 
+const fs = require('fs');
 const log = require('../util/log').out('bundle');
-const processBundle = require('./processBundle');
 const Promise = require('promise');
 const ReactPackager = require('../../packager/react-packager');
-const saveBundleAndMap = require('./saveBundleAndMap');
+const saveAssets = require('./saveAssets');
+
+const sign = require('./sign');
+
+function saveBundleAndMap(
+  bundle,
+  bundleOutput,
+  encoding,
+  sourcemapOutput,
+  dev
+) {
+  log('start');
+  let codeWithMap;
+  if (!dev) {
+    codeWithMap = bundle.getMinifiedSourceAndMap(dev);
+  } else {
+    codeWithMap = {
+      code: bundle.getSource({ dev }),
+      map: JSON.stringify(bundle.getSourceMap({ dev })),
+    };
+  }
+  log('finish');
+
+  log('Writing bundle output to:', bundleOutput);
+  fs.writeFileSync(bundleOutput, sign(codeWithMap.code), encoding);
+  log('Done writing bundle output');
+
+  if (sourcemapOutput) {
+    log('Writing sourcemap output to:', sourcemapOutput);
+    fs.writeFileSync(sourcemapOutput, codeWithMap.map);
+    log('Done writing sourcemap output');
+  }
+}
+
+function savePrepackBundleAndMap(
+  bundle,
+  bundleOutput,
+  sourcemapOutput,
+  bridgeConfig
+) {
+  log('Writing prepack bundle output to:', bundleOutput);
+  const result = bundle.build({
+    batchedBridgeConfig: bridgeConfig
+  });
+  fs.writeFileSync(bundleOutput, result, 'ucs-2');
+  log('Done writing prepack bundle output');
+}
 
 function buildBundle(args, config) {
   return new Promise((resolve, reject) => {
@@ -36,24 +82,56 @@ function buildBundle(args, config) {
       platform: args.platform,
     };
 
-    resolve(ReactPackager.createClientFor(options).then(client => {
-      log('Created ReactPackager');
-      return client.buildBundle(requestOpts)
+    const prepack = args.prepack;
+
+    const client = ReactPackager.createClientFor(options);
+
+    client.then(() => log('Created ReactPackager'));
+
+    // Build and save the bundle
+    let bundle;
+    if (prepack) {
+      bundle = client.then(c => c.buildPrepackBundle(requestOpts))
         .then(outputBundle => {
-          log('Closing client');
-          client.close();
+          savePrepackBundleAndMap(
+            outputBundle,
+            args['bundle-output'],
+            args['sourcemap-output'],
+            args['bridge-config']
+          );
           return outputBundle;
-        })
-        .then(outputBundle => processBundle(outputBundle, args.dev))
-        .then(outputBundle => saveBundleAndMap(
-          outputBundle,
+        });
+    } else {
+      bundle = client.then(c => c.buildBundle(requestOpts))
+        .then(outputBundle => {
+          saveBundleAndMap(
+            outputBundle,
+            args['bundle-output'],
+            args['bundle-encoding'],
+            args['sourcemap-output'],
+            args.dev
+          );
+          return outputBundle;
+        });
+    }
+
+    // When we're done bundling, close the client
+    bundle.then(() => client.then(c => {
+      log('Closing client');
+      c.close();
+    }));
+
+    // Save the assets of the bundle
+    const assets = bundle
+        .then(outputBundle => outputBundle.getAssets())
+        .then(outputAssets => saveAssets(
+          outputAssets,
           args.platform,
-          args['bundle-output'],
-          args['bundle-encoding'],
-          args['sourcemap-output'],
           args['assets-dest']
         ));
-    }));
+
+    // When we're done saving the assets, we're done.
+    resolve(assets);
   });
 }
 
diff --git a/local-cli/bundle/bundleCommandLineArgs.js b/local-cli/bundle/bundleCommandLineArgs.js
index 353c7ea5f28e..2597a7f13154 100644
--- a/local-cli/bundle/bundleCommandLineArgs.js
+++ b/local-cli/bundle/bundleCommandLineArgs.js
@@ -27,6 +27,14 @@ module.exports = [
     command: 'dev',
     description: 'If false, warnings are disabled and the bundle is minified',
     default: true,
+  }, {
+    command: 'prepack',
+    description: 'If true, the output bundle will use the Prepack format.',
+    default: false
+  }, {
+    command: 'bridge-config',
+    description: 'File name of a a JSON export of __fbBatchedBridgeConfig. Used by Prepack. Ex. ./bridgeconfig.json',
+    type: 'string'
   }, {
     command: 'bundle-output',
     description: 'File name where to store the resulting bundle, ex. /tmp/groups.bundle',
diff --git a/local-cli/bundle/processBundle.js b/local-cli/bundle/processBundle.js
deleted file mode 100644
index 3a86a61f522e..000000000000
--- a/local-cli/bundle/processBundle.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-const log = require('../util/log').out('bundle');
-
-function processBundle(input, dev) {
-  log('start');
-  let bundle;
-  if (!dev) {
-    bundle = input.getMinifiedSourceAndMap(dev);
-  } else {
-    bundle = {
-      code: input.getSource({ dev }),
-      map: JSON.stringify(input.getSourceMap({ dev })),
-    };
-  }
-  bundle.assets = input.getAssets();
-  log('finish');
-  return bundle;
-}
-
-module.exports = processBundle;
diff --git a/local-cli/bundle/saveBundleAndMap.js b/local-cli/bundle/saveAssets.js
similarity index 80%
rename from local-cli/bundle/saveBundleAndMap.js
rename to local-cli/bundle/saveAssets.js
index bb6bf2291f22..1dd88512b4f2 100644
--- a/local-cli/bundle/saveBundleAndMap.js
+++ b/local-cli/bundle/saveAssets.js
@@ -14,26 +14,12 @@ const getAssetDestPathAndroid = require('./getAssetDestPathAndroid');
 const getAssetDestPathIOS = require('./getAssetDestPathIOS');
 const log = require('../util/log').out('bundle');
 const path = require('path');
-const sign = require('./sign');
 
-function saveBundleAndMap(
-  codeWithMap,
+function saveAssets(
+  assets,
   platform,
-  bundleOutput,
-  encoding,
-  sourcemapOutput,
   assetsDest
 ) {
-  log('Writing bundle output to:', bundleOutput);
-  fs.writeFileSync(bundleOutput, sign(codeWithMap.code), encoding);
-  log('Done writing bundle output');
-
-  if (sourcemapOutput) {
-    log('Writing sourcemap output to:', sourcemapOutput);
-    fs.writeFileSync(sourcemapOutput, codeWithMap.map);
-    log('Done writing sourcemap output');
-  }
-
   if (!assetsDest) {
     console.warn('Assets destination folder is not set, skipping...');
     return Promise.resolve();
@@ -44,7 +30,7 @@ function saveBundleAndMap(
     : getAssetDestPathIOS;
 
   const filesToCopy = Object.create(null); // Map src -> dest
-  codeWithMap.assets
+  assets
     .filter(asset => !asset.deprecated)
     .forEach(asset =>
       asset.scales.forEach((scale, idx) => {
@@ -94,4 +80,4 @@ function copy(src, dest, callback) {
   });
 }
 
-module.exports = saveBundleAndMap;
+module.exports = saveAssets;
diff --git a/packager/react-packager/index.js b/packager/react-packager/index.js
index e0a29684d9bb..e1a294f4097a 100644
--- a/packager/react-packager/index.js
+++ b/packager/react-packager/index.js
@@ -35,6 +35,15 @@ exports.buildBundle = function(options, bundleOptions) {
     });
 };
 
+exports.buildPrepackBundle = function(options, bundleOptions) {
+  var server = createNonPersistentServer(options);
+  return server.buildPrepackBundle(bundleOptions)
+    .then(function(p) {
+      server.end();
+      return p;
+    });
+};
+
 exports.buildPackageFromUrl =
 exports.buildBundleFromUrl = function(options, reqUrl) {
   var server = createNonPersistentServer(options);
diff --git a/packager/react-packager/src/Bundler/PrepackBundle.js b/packager/react-packager/src/Bundler/PrepackBundle.js
new file mode 100644
index 000000000000..123d3297a5c0
--- /dev/null
+++ b/packager/react-packager/src/Bundler/PrepackBundle.js
@@ -0,0 +1,149 @@
+/**
+ * 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.
+ */
+'use strict';
+
+const fs = require('fs');
+
+class PrepackBundle {
+  constructor(sourceMapUrl) {
+    this._finalized = false;
+    this._moduleIds = Object.create(null);
+    this._modules = Object.create(null);
+    this._eagerModules = [];
+    this._mainModule = null;
+    this._assets = [];
+    this._sourceMapUrl = sourceMapUrl;
+  }
+
+  addModule(id, module, deps, isPolyfill) {
+    this._modules[module.sourcePath] = { module, deps };
+    this._moduleIds[id] = module.sourcePath;
+    if (isPolyfill) {
+      this._eagerModules.push(id);
+    }
+  }
+
+  addAsset(asset) {
+    this._assets.push(asset);
+  }
+
+  // Synchronously load a file path.
+  _loadFilename(path) {
+    const module = this._modules[path];
+    if (!module) {
+      throw new Error('Could not find file "' + path + '" in preloaded files.');
+    }
+    return module.module.code;
+  }
+
+  // Synchronously resolve a relative require from a parent module.
+  _resolveFilename(parentPath, relativePath) {
+    if (!parentPath) {
+      const resolvedPath = this._moduleIds[relativePath];
+      if (!resolvedPath) {
+        throw new Error('Could not resolve "' + relativePath + '".');
+      }
+      return resolvedPath;
+    }
+    const deps = this._modules[parentPath].deps;
+    const resolvedPath = deps[relativePath];
+    if (!resolvedPath) {
+      throw new Error(
+        'Could not resolve "' + relativePath + '" from "' + parentPath + '".'
+      );
+    }
+    return resolvedPath;
+  }
+
+  build(options) {
+    var prepack = require('prepack');
+
+    var batchedBridgeConfig = (options && options.batchedBridgeConfig) || null;
+    if (typeof batchedBridgeConfig === 'string') {
+      batchedBridgeConfig = JSON.parse(
+        fs.readFileSync(batchedBridgeConfig, 'utf-8')
+      );
+    }
+
+    var options = {
+      batchedBridgeConfig: batchedBridgeConfig,
+      environment: 'react-native',
+      resolveFilename: this._resolveFilename.bind(this),
+      loadFilename: this._loadFilename.bind(this),
+      eagerModules: this._eagerModules
+    };
+
+    return prepack.compileModule(this._mainModule, options);
+  }
+
+  finalize(options) {
+    options = options || {};
+    if (options.runMainModule) {
+      options.runBeforeMainModule.forEach(this._addRequireCall, this);
+      this._mainModule = options.mainModuleId;
+    }
+
+    Object.freeze(this._moduleIds);
+    Object.freeze(this._modules);
+    Object.freeze(this._assets);
+    Object.freeze(this._eagerModules);
+    this._finalized = true;
+  }
+
+  _addRequireCall(moduleId) {
+    this._eagerModules.push(moduleId);
+  }
+
+  _assertFinalized() {
+    if (!this._finalized) {
+      throw new Error('Bundle needs to be finalized before getting any source');
+    }
+  }
+
+  getAssets() {
+    return this._assets;
+  }
+
+  toJSON() {
+    if (!this._finalized) {
+      throw new Error('Cannot serialize bundle unless finalized');
+    }
+
+    return {
+      modules: this._modules,
+      moduleIds: this._moduleIds,
+      assets: this._assets,
+      sourceMapUrl: this._sourceMapUrl,
+      mainModule: this._mainModule,
+      eagerModules: this._eagerModules,
+    };
+  }
+
+  static fromJSON(json) {
+    const bundle = new PrepackBundle(json.sourceMapUrl);
+    bundle._assets = json.assets;
+    bundle._moduleIds = json.moduleIds;
+    bundle._modules = json.modules;
+    bundle._sourceMapUrl = json.sourceMapUrl;
+
+    bundle._eagerModules = json.eagerModules;
+    bundle._mainModule = json.mainModule;
+
+    Object.freeze(bundle._moduleIds);
+    Object.freeze(bundle._modules);
+    Object.freeze(bundle._assets);
+    Object.freeze(bundle._eagerModules);
+
+    bundle._finalized = true;
+
+    return bundle;
+  }
+}
+
+module.exports = PrepackBundle;
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index 82a0282be22b..5f5d795905e5 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -18,6 +18,7 @@ const Cache = require('../Cache');
 const Transformer = require('../JSTransformer');
 const Resolver = require('../Resolver');
 const Bundle = require('./Bundle');
+const PrepackBundle = require('./PrepackBundle');
 const Activity = require('../Activity');
 const ModuleTransport = require('../lib/ModuleTransport');
 const declareOpts = require('../lib/declareOpts');
@@ -171,7 +172,7 @@ class Bundler {
             if (bar) {
               bar.tick();
             }
-            return transformed;
+            return this._wrapTransformedModule(response, module, transformed);
           })
         )
       );
@@ -187,6 +188,68 @@ class Bundler {
     });
   }
 
+  prepackBundle({
+    entryFile,
+    runModule: runMainModule,
+    runBeforeMainModule,
+    sourceMapUrl,
+    dev: isDev,
+    platform,
+  }) {
+    const bundle = new PrepackBundle(sourceMapUrl);
+    const findEventId = Activity.startEvent('find dependencies');
+    let transformEventId;
+    let mainModuleId;
+
+    return this.getDependencies(entryFile, isDev, platform).then((response) => {
+      Activity.endEvent(findEventId);
+      transformEventId = Activity.startEvent('transform');
+
+      let bar;
+      if (process.stdout.isTTY) {
+        bar = new ProgressBar('transforming [:bar] :percent :current/:total', {
+          complete: '=',
+          incomplete: ' ',
+          width: 40,
+          total: response.dependencies.length,
+        });
+      }
+
+      mainModuleId = response.mainModuleId;
+
+      return Promise.all(
+        response.dependencies.map(
+          module => this._transformModule(
+            bundle,
+            response,
+            module,
+            platform
+          ).then(transformed => {
+            if (bar) {
+              bar.tick();
+            }
+
+            var deps = Object.create(null);
+            var pairs = response.getResolvedDependencyPairs(module);
+            if (pairs) {
+              pairs.forEach(pair => {
+                deps[pair[0]] = pair[1].path;
+              });
+            }
+
+            return module.getName().then(name => {
+              bundle.addModule(name, transformed, deps, module.isPolyfill());
+            });
+          })
+        )
+      );
+    }).then(() => {
+      Activity.endEvent(transformEventId);
+      bundle.finalize({runBeforeMainModule, runMainModule, mainModuleId });
+      return bundle;
+    });
+  }
+
   invalidateFile(filePath) {
     this._transformer.invalidateFile(filePath);
   }
@@ -228,35 +291,32 @@ class Bundler {
   }
 
   _transformModule(bundle, response, module, platform = null) {
-    let transform;
-
     if (module.isAsset_DEPRECATED()) {
-      transform = this.generateAssetModule_DEPRECATED(bundle, module);
+      return this.generateAssetModule_DEPRECATED(bundle, module);
     } else if (module.isAsset()) {
-      transform = this.generateAssetModule(bundle, module, platform);
+      return this.generateAssetModule(bundle, module, platform);
     } else if (module.isJSON()) {
-      transform = generateJSONModule(module);
+      return generateJSONModule(module);
     } else {
-      transform = this._transformer.loadFileAndTransform(
+      return this._transformer.loadFileAndTransform(
         path.resolve(module.path)
       );
     }
+  }
 
-    const resolver = this._resolver;
-    return transform.then(
-      transformed => resolver.wrapModule(
-        response,
-        module,
-        transformed.code
-      ).then(
-        code => new ModuleTransport({
-          code: code,
-          map: transformed.map,
-          sourceCode: transformed.sourceCode,
-          sourcePath: transformed.sourcePath,
-          virtual: transformed.virtual,
-        })
-      )
+  _wrapTransformedModule(response, module, transformed) {
+    return this._resolver.wrapModule(
+      response,
+      module,
+      transformed.code
+    ).then(
+      code => new ModuleTransport({
+        code: code,
+        map: transformed.map,
+        sourceCode: transformed.sourceCode,
+        sourcePath: transformed.sourcePath,
+        virtual: transformed.virtual,
+      })
     );
   }
 
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index 1abb78cf6ece..28c5b4d1bc80 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -190,6 +190,17 @@ class Server {
     });
   }
 
+  buildPrepackBundle(options) {
+    return Promise.resolve().then(() => {
+      if (!options.platform) {
+        options.platform = getPlatformExtension(options.entryFile);
+      }
+
+      const opts = bundleOpts(options);
+      return this._bundler.prepackBundle(opts);
+    });
+  }
+
   buildBundleFromUrl(reqUrl) {
     const options = this._getOptionsFromUrl(reqUrl);
     return this.buildBundle(options);
diff --git a/packager/react-packager/src/SocketInterface/SocketClient.js b/packager/react-packager/src/SocketInterface/SocketClient.js
index 41ce0df14ee2..a344f5d97aee 100644
--- a/packager/react-packager/src/SocketInterface/SocketClient.js
+++ b/packager/react-packager/src/SocketInterface/SocketClient.js
@@ -9,6 +9,7 @@
 'use strict';
 
 const Bundle = require('../Bundler/Bundle');
+const PrepackBundle = require('../Bundler/PrepackBundle');
 const Promise = require('promise');
 const bser = require('bser');
 const debug = require('debug')('ReactNativePackager:SocketClient');
@@ -100,6 +101,13 @@ class SocketClient {
     }).then(json => Bundle.fromJSON(json));
   }
 
+  buildPrepackBundle(options) {
+    return this._send({
+      type: 'buildPrepackBundle',
+      data: options,
+    }).then(json => PrepackBundle.fromJSON(json));
+  }
+
   _send(message) {
     message.id = uid();
     this._sock.write(bser.dumpToBuffer(message));
diff --git a/packager/react-packager/src/SocketInterface/SocketServer.js b/packager/react-packager/src/SocketInterface/SocketServer.js
index 8258873a4bd5..56562e273c99 100644
--- a/packager/react-packager/src/SocketInterface/SocketServer.js
+++ b/packager/react-packager/src/SocketInterface/SocketServer.js
@@ -121,6 +121,14 @@ class SocketServer {
         );
         break;
 
+      case 'buildPrepackBundle':
+        this._jobs++;
+        this._packagerServer.buildPrepackBundle(m.data).then(
+          (result) => this._reply(sock, m.id, 'result', result),
+          handleError,
+        );
+        break;
+
       case 'getOrderedDependencyPaths':
         this._jobs++;
         this._packagerServer.getOrderedDependencyPaths(m.data).then(

From 16dd5d664b4a269aee0989eb257790a38ca83766 Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Sat, 21 Nov 2015 11:08:31 -0800
Subject: [PATCH 0038/1411] Add systrace markers to module require

Summary: public

Show modules' dependencies and time to load.

Reviewed By: davidaurelio

Differential Revision: D2603245

fb-gh-sync-id: a1d5067a8522b908b87fdfdd51ff4c4fdbc2edfc
---
 .../src/Resolver/polyfills/require.js              | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/packager/react-packager/src/Resolver/polyfills/require.js b/packager/react-packager/src/Resolver/polyfills/require.js
index 6ebfee90a1b2..d7550ba1b9bb 100644
--- a/packager/react-packager/src/Resolver/polyfills/require.js
+++ b/packager/react-packager/src/Resolver/polyfills/require.js
@@ -54,9 +54,13 @@
       // require cycles inside the factory from causing an infinite require loop.
       mod.isInitialized = true;
 
+      __DEV__ && BridgeProfiling().profile(id);
+
       // keep args in sync with with defineModuleCode in
       // packager/react-packager/src/Resolver/index.js
       mod.factory.call(global, global, require, mod.module, mod.module.exports);
+
+      __DEV__ && BridgeProfiling().profileEnd();
     } catch (e) {
       mod.hasError = true;
       mod.isInitialized = false;
@@ -66,6 +70,16 @@
     return mod.module.exports;
   }
 
+  const BridgeProfiling = __DEV__ && (() => {
+    var _BridgeProfiling;
+    try {
+      _BridgeProfiling = require('BridgeProfiling');
+    } catch(e) {}
+
+    return _BridgeProfiling && _BridgeProfiling.profile ?
+      _BridgeProfiling : { profile: () => {}, profileEnd: () => {} };
+  });
+
   global.__d = define;
   global.require = require;
 })(this);

From 156b5ad79e16fb93a22a7d5837003c6d08bfe33d Mon Sep 17 00:00:00 2001
From: Rishabh Mehan <darkrishabh@gmail.com>
Date: Sun, 22 Nov 2015 00:14:20 -0800
Subject: [PATCH 0039/1411] Adding DareU to the Showcase

---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 5d485df69d2f..14c181fedf6c 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -43,6 +43,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/company-name-search/id1043824076',
     author: 'The Formations Factory Ltd',
   },
+  {
+    name: 'DareU - dare your friends, dare the world',
+    icon: 'http://a3.mzstatic.com/us/r30/Purple6/v4/10/fb/6a/10fb6a50-57c8-061a-d865-503777bf7f00/icon175x175.png',
+    link: 'https://itunes.apple.com/us/app/dareu-dare-your-friends-dare/id1046434563?mt=8',
+    author: 'Rishabh Mehan',
+  },
   {
     name: 'Discord',
     icon: 'http://a5.mzstatic.com/us/r30/Purple5/v4/c1/2f/4c/c12f4cba-1d9a-f6bf-2240-04085d3470ec/icon175x175.jpeg',

From 54470021ca418a021421dc9fd079726ae71a33e3 Mon Sep 17 00:00:00 2001
From: panjianjun <freedem@163.com>
Date: Mon, 23 Nov 2015 01:18:46 -0800
Subject: [PATCH 0040/1411] remove prepare_command in podspec file

Summary: since 0.13.2 , prepare_command in podspec would download the dependencies of react-native again when you install react-native via cocoapods with local path.
Closes https://github.com/facebook/react-native/pull/4291

Reviewed By: svcscm

Differential Revision: D2685452

Pulled By: nicklockwood

fb-gh-sync-id: b1c1a0f45897d3eb45be99db3633c899c35feb8e
---
 React.podspec | 1 -
 1 file changed, 1 deletion(-)

diff --git a/React.podspec b/React.podspec
index 2f52c2ab8f8b..8083357a2b59 100644
--- a/React.podspec
+++ b/React.podspec
@@ -22,7 +22,6 @@ Pod::Spec.new do |s|
   s.default_subspec     = 'Core'
   s.requires_arc        = true
   s.platform            = :ios, "7.0"
-  s.prepare_command     = 'npm install --production'
   s.preserve_paths      = "cli.js", "Libraries/**/*.js", "lint", "linter.js", "node_modules", "package.json", "packager", "PATENTS", "react-native-cli"
 
   s.subspec 'Core' do |ss|

From f57c2a9140140bc54a83d4a87bde486e2f052ce5 Mon Sep 17 00:00:00 2001
From: Alexander Blom <blom@fb.com>
Date: Mon, 23 Nov 2015 02:16:27 -0800
Subject: [PATCH 0041/1411] Add GuardedResultAsyncTask

Reviewed By: andreicoman11

Differential Revision: D2679459

fb-gh-sync-id: 8a9ec170ce76bbc3340c9e8872e19b78ae5a5c2d
---
 .../react/bridge/GuardedAsyncTask.java        |  5 +--
 .../react/bridge/GuardedResultAsyncTask.java  | 43 +++++++++++++++++++
 2 files changed, 45 insertions(+), 3 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/GuardedResultAsyncTask.java

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/GuardedAsyncTask.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/GuardedAsyncTask.java
index 917c1279c667..83a7fb014e34 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/GuardedAsyncTask.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/GuardedAsyncTask.java
@@ -16,9 +16,8 @@
  * handled by the {@link com.facebook.react.bridge.NativeModuleCallExceptionHandler} registered if
  * the app is in dev mode.
  *
- * This class doesn't allow doInBackground to return a results. This is mostly because when this
- * class was written that functionality wasn't used and it would require some extra code to make
- * work correctly with caught exceptions. Don't let that stop you from adding it if you need it :)
+ * This class doesn't allow doInBackground to return a results. If you need this
+ * use GuardedResultAsyncTask instead.
  */
 public abstract class GuardedAsyncTask<Params, Progress>
     extends AsyncTask<Params, Progress, Void> {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/GuardedResultAsyncTask.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/GuardedResultAsyncTask.java
new file mode 100644
index 000000000000..db13a71464e4
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/GuardedResultAsyncTask.java
@@ -0,0 +1,43 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.bridge;
+
+import android.os.AsyncTask;
+
+/**
+ * Abstract base for a AsyncTask with result support that should have any RuntimeExceptions it
+ * throws handled by the {@link com.facebook.react.bridge.NativeModuleCallExceptionHandler}
+ * registered if the app is in dev mode.
+ */
+public abstract class GuardedResultAsyncTask<Result>
+    extends AsyncTask<Void, Void, Result> {
+
+  private final ReactContext mReactContext;
+
+  protected GuardedResultAsyncTask(ReactContext reactContext) {
+    mReactContext = reactContext;
+  }
+
+  @Override
+  protected final Result doInBackground(Void... params) {
+    try {
+      return doInBackgroundGuarded();
+    } catch (RuntimeException e) {
+      mReactContext.handleException(e);
+      throw e;
+    }
+  }
+
+  @Override
+  protected final void onPostExecute(Result result) {
+    try {
+      onPostExecuteGuarded(result);
+    } catch (RuntimeException e) {
+      mReactContext.handleException(e);
+    }
+  }
+
+  protected abstract Result doInBackgroundGuarded();
+  protected abstract void onPostExecuteGuarded(Result result);
+
+}

From 274c5c78c4933a09335fca0e2fdc266c80fe4017 Mon Sep 17 00:00:00 2001
From: Alexander Blom <blom@fb.com>
Date: Mon, 23 Nov 2015 02:16:51 -0800
Subject: [PATCH 0042/1411] Support cookies on Android

Summary: This adds a persistent cookie store that shares cookies with WebView.

Add a `ForwardingCookieHandler` to OkHttp that uses the underlying Android webkit `CookieManager`.
Use a `LazyCookieHandler` to defer initialization of `CookieManager` as this will in turn trigger initialization of the Chromium stack in KitKat+ which takes some time. This was we will incur this cost on a background network thread instead of during startup.
Also add a `clearCookies()` method to the network module.

Add a cookies example to the XHR example. This example should also work for iOS (except for the clear cookies part). They are for now just scoped to Android.

Closes #2792.

public

Reviewed By: andreicoman11

Differential Revision: D2615550

fb-gh-sync-id: ff726a35f0fc3c7124d2f755448fe24c9d1caf21
---
 Examples/UIExplorer/XHRExample.android.js     |   7 +
 Examples/UIExplorer/XHRExampleCookies.js      | 128 ++++++++++
 Libraries/Network/RCTNetworking.android.js    |   4 +
 .../react/modules/fresco/FrescoModule.java    |   3 +-
 .../network/ForwardingCookieHandler.java      | 230 ++++++++++++++++++
 .../modules/network/NetworkingModule.java     |  26 +-
 .../modules/network/OkHttpClientProvider.java |  36 ++-
 7 files changed, 419 insertions(+), 15 deletions(-)
 create mode 100644 Examples/UIExplorer/XHRExampleCookies.js
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/network/ForwardingCookieHandler.java

diff --git a/Examples/UIExplorer/XHRExample.android.js b/Examples/UIExplorer/XHRExample.android.js
index ab272d133da2..ad4bbf772a90 100644
--- a/Examples/UIExplorer/XHRExample.android.js
+++ b/Examples/UIExplorer/XHRExample.android.js
@@ -27,6 +27,8 @@ var {
 } = React;
 
 var XHRExampleHeaders = require('./XHRExampleHeaders');
+var XHRExampleCookies = require('./XHRExampleCookies');
+
 
 // TODO t7093728 This is a simlified XHRExample.ios.js.
 // Once we have Camera roll, Toast, Intent (for opening URLs)
@@ -284,6 +286,11 @@ exports.examples = [{
   render() {
     return <XHRExampleHeaders/>;
   }
+}, {
+  title: 'Cookies',
+  render() {
+    return <XHRExampleCookies/>;
+  }
 }];
 
 var styles = StyleSheet.create({
diff --git a/Examples/UIExplorer/XHRExampleCookies.js b/Examples/UIExplorer/XHRExampleCookies.js
new file mode 100644
index 000000000000..310accc19b60
--- /dev/null
+++ b/Examples/UIExplorer/XHRExampleCookies.js
@@ -0,0 +1,128 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ *
+ * @flow
+ */
+'use strict';
+
+var React = require('react-native');
+var {
+  StyleSheet,
+  Text,
+  TouchableHighlight,
+  View,
+} = React;
+
+var RCTNetworking = require('RCTNetworking');
+
+class XHRExampleCookies extends React.Component {
+  constructor(props: any) {
+    super(props);
+    this.cancelled = false;
+    this.state = {
+      status: '',
+      a: 1,
+      b: 2,
+    };
+  }
+
+  setCookie(domain: string) {
+    var {a, b} = this.state;
+    var url = `https://${domain}/cookies/set?a=${a}&b=${b}`;
+    fetch(url).then((response) => {
+      this.setStatus(`Cookies a=${a}, b=${b} set`);
+    });
+
+    this.setState({
+      status: 'Setting cookies...',
+      a: a + 1,
+      b: b + 2,
+    });
+  }
+
+  getCookies(domain: string) {
+    fetch(`https://${domain}/cookies`).then((response) => {
+      return response.json();
+    }).then((data) => {
+      this.setStatus(`Got cookies ${JSON.stringify(data.cookies)} from server`);
+    });
+
+    this.setStatus('Getting cookies...');
+  }
+
+  clearCookies() {
+    RCTNetworking.clearCookies((cleared) => {
+      this.setStatus('Cookies cleared, had cookies=' + cleared);
+    });
+  }
+
+  setStatus(status: string) {
+    this.setState({status});
+  }
+
+  render() {
+    return (
+      <View>
+        <TouchableHighlight
+          style={styles.wrapper}
+          onPress={this.setCookie.bind(this, 'httpbin.org')}>
+          <View style={styles.button}>
+            <Text>Set cookie</Text>
+          </View>
+        </TouchableHighlight>
+        <TouchableHighlight
+          style={styles.wrapper}
+          onPress={this.setCookie.bind(this, 'eu.httpbin.org')}>
+          <View style={styles.button}>
+            <Text>Set cookie (EU)</Text>
+          </View>
+        </TouchableHighlight>
+        <TouchableHighlight
+          style={styles.wrapper}
+          onPress={this.getCookies.bind(this, 'httpbin.org')}>
+          <View style={styles.button}>
+            <Text>Get cookies</Text>
+          </View>
+        </TouchableHighlight>
+        <TouchableHighlight
+          style={styles.wrapper}
+          onPress={this.getCookies.bind(this, 'eu.httpbin.org')}>
+          <View style={styles.button}>
+            <Text>Get cookies (EU)</Text>
+          </View>
+        </TouchableHighlight>
+        <TouchableHighlight
+          style={styles.wrapper}
+          onPress={this.clearCookies.bind(this)}>
+          <View style={styles.button}>
+            <Text>Clear cookies</Text>
+          </View>
+        </TouchableHighlight>
+        <Text>{this.state.status}</Text>
+      </View>
+    );
+  }
+}
+
+var styles = StyleSheet.create({
+  wrapper: {
+    borderRadius: 5,
+    marginBottom: 5,
+  },
+  button: {
+    backgroundColor: '#eeeeee',
+    padding: 8,
+  },
+});
+
+module.exports = XHRExampleCookies;
diff --git a/Libraries/Network/RCTNetworking.android.js b/Libraries/Network/RCTNetworking.android.js
index e8c4be0bd109..351524eb991a 100644
--- a/Libraries/Network/RCTNetworking.android.js
+++ b/Libraries/Network/RCTNetworking.android.js
@@ -40,6 +40,10 @@ class RCTNetworking {
   static abortRequest(requestId) {
     RCTNetworkingNative.abortRequest(requestId);
   }
+
+  static clearCookies(callback) {
+    RCTNetworkingNative.clearCookies(callback);
+  }
 }
 
 module.exports = RCTNetworking;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java
index 14b95c0aebdc..8a980cb46e18 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java
@@ -80,7 +80,8 @@ public void loadLibrary(String libraryName) {
     }
 
     Context context = this.getReactApplicationContext().getApplicationContext();
-    OkHttpClient okHttpClient = OkHttpClientProvider.getOkHttpClient();
+    OkHttpClient okHttpClient =
+        OkHttpClientProvider.getCookieAwareOkHttpClient(getReactApplicationContext());
     ImagePipelineConfig.Builder builder =
         OkHttpImagePipelineConfigFactory.newBuilder(context, okHttpClient);
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/ForwardingCookieHandler.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/ForwardingCookieHandler.java
new file mode 100644
index 000000000000..d24540ceaa4d
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/ForwardingCookieHandler.java
@@ -0,0 +1,230 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.modules.network;
+
+import javax.annotation.Nullable;
+
+import java.io.IOException;
+import java.net.CookieHandler;
+import java.net.URI;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.text.TextUtils;
+import android.webkit.CookieManager;
+import android.webkit.CookieSyncManager;
+import android.webkit.ValueCallback;
+
+import com.facebook.react.bridge.Callback;
+import com.facebook.react.bridge.GuardedAsyncTask;
+import com.facebook.react.bridge.GuardedResultAsyncTask;
+import com.facebook.react.bridge.ReactContext;
+
+/**
+ * Cookie handler that forwards all cookies to the WebView CookieManager.
+ *
+ * This class relies on CookieManager to persist cookies to disk so cookies may be lost if the
+ * application is terminated before it syncs.
+ */
+public class ForwardingCookieHandler extends CookieHandler {
+  private static final String VERSION_ZERO_HEADER = "Set-cookie";
+  private static final String VERSION_ONE_HEADER = "Set-cookie2";
+  private static final String COOKIE_HEADER = "Cookie";
+
+  // As CookieManager was synchronous before API 21 this class emulates the async behavior on <21.
+  private static final boolean USES_LEGACY_STORE = Build.VERSION.SDK_INT < 21;
+
+  private final CookieSaver mCookieSaver;
+  private final ReactContext mContext;
+  private @Nullable CookieManager mCookieManager;
+
+  public ForwardingCookieHandler(ReactContext context) {
+    mContext = context;
+    mCookieSaver = new CookieSaver();
+  }
+
+  @Override
+  public Map<String, List<String>> get(URI uri, Map<String, List<String>> headers)
+      throws IOException {
+    String cookies = getCookieManager().getCookie(uri.toString());
+    if (TextUtils.isEmpty(cookies)) {
+      return Collections.emptyMap();
+    }
+
+    return Collections.singletonMap(COOKIE_HEADER, Collections.singletonList(cookies));
+  }
+
+  @Override
+  public void put(URI uri, Map<String, List<String>> headers) throws IOException {
+    String url = uri.toString();
+    for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
+      String key = entry.getKey();
+      if (key != null && isCookieHeader(key)) {
+        addCookies(url, entry.getValue());
+      }
+    }
+  }
+
+  public void clearCookies(final Callback callback) {
+    if (USES_LEGACY_STORE) {
+      new GuardedResultAsyncTask<Boolean>(mContext) {
+        @Override
+        protected Boolean doInBackgroundGuarded() {
+          getCookieManager().removeAllCookie();
+          mCookieSaver.onCookiesModified();
+          return true;
+        }
+
+        @Override
+        protected void onPostExecuteGuarded(Boolean result) {
+          callback.invoke(result);
+        }
+      }.execute();
+    } else {
+      clearCookiesAsync(callback);
+    }
+  }
+
+  private void clearCookiesAsync(final Callback callback) {
+    getCookieManager().removeAllCookies(
+        new ValueCallback<Boolean>() {
+          @Override
+          public void onReceiveValue(Boolean value) {
+            mCookieSaver.onCookiesModified();
+            callback.invoke(value);
+          }
+        });
+  }
+
+  public void destroy() {
+    if (USES_LEGACY_STORE) {
+      getCookieManager().removeExpiredCookie();
+      mCookieSaver.persistCookies();
+    }
+  }
+
+  private void addCookies(final String url, final List<String> cookies) {
+    if (USES_LEGACY_STORE) {
+      runInBackground(
+          new Runnable() {
+            @Override
+            public void run() {
+              for (String cookie : cookies) {
+                getCookieManager().setCookie(url, cookie);
+              }
+              mCookieSaver.onCookiesModified();
+            }
+          });
+    } else {
+      for (String cookie : cookies) {
+        addCookieAsync(url, cookie);
+      }
+      mCookieSaver.onCookiesModified();
+    }
+  }
+
+  @TargetApi(21)
+  private void addCookieAsync(String url, String cookie) {
+    getCookieManager().setCookie(url, cookie, null);
+  }
+
+  private static boolean isCookieHeader(String name) {
+    return name.equalsIgnoreCase(VERSION_ZERO_HEADER) || name.equalsIgnoreCase(VERSION_ONE_HEADER);
+  }
+
+  private void runInBackground(final Runnable runnable) {
+    new GuardedAsyncTask<Void, Void>(mContext) {
+      @Override
+      protected void doInBackgroundGuarded(Void... params) {
+        runnable.run();
+      }
+    }.execute();
+  }
+
+  /**
+   * Instantiating CookieManager in KitKat+ will load the Chromium task taking a 100ish ms so we
+   * do it lazily to make sure it's done on a background thread as needed.
+   */
+  private CookieManager getCookieManager() {
+    if (mCookieManager == null) {
+      possiblyWorkaroundSyncManager(mContext);
+      mCookieManager = CookieManager.getInstance();
+
+      if (USES_LEGACY_STORE) {
+        mCookieManager.removeExpiredCookie();
+      }
+    }
+
+    return mCookieManager;
+  }
+
+  private static void possiblyWorkaroundSyncManager(Context context) {
+    if (USES_LEGACY_STORE) {
+      // This is to work around a bug where CookieManager may fail to instantiate if
+      // CookieSyncManager has never been created. Note that the sync() may not be required but is
+      // here of legacy reasons.
+      CookieSyncManager syncManager = CookieSyncManager.createInstance(context);
+      syncManager.sync();
+    }
+  }
+
+  /**
+   * Responsible for flushing cookies to disk. Flushes to disk with a maximum delay of 30 seconds.
+   * This class is only active if we are on API < 21.
+   */
+  private class CookieSaver {
+    private static final int MSG_PERSIST_COOKIES = 1;
+
+    private static final int TIMEOUT = 30 * 1000; // 30 seconds
+
+    private final Handler mHandler;
+
+    public CookieSaver() {
+      mHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
+        @Override
+        public boolean handleMessage(Message msg) {
+          if (msg.what == MSG_PERSIST_COOKIES) {
+            persistCookies();
+            return true;
+          } else {
+            return false;
+          }
+        }
+      });
+    }
+
+    public void onCookiesModified() {
+      if (USES_LEGACY_STORE) {
+        mHandler.sendEmptyMessageDelayed(MSG_PERSIST_COOKIES, TIMEOUT);
+      }
+    }
+
+    public void persistCookies() {
+      mHandler.removeMessages(MSG_PERSIST_COOKIES);
+      runInBackground(
+          new Runnable() {
+            @Override
+            public void run() {
+              if (USES_LEGACY_STORE) {
+                CookieSyncManager syncManager = CookieSyncManager.getInstance();
+                syncManager.sync();
+              } else {
+                flush();
+              }
+            }
+          });
+    }
+
+    @TargetApi(21)
+    private void flush() {
+      getCookieManager().flush();
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
index 4ddbf1f60587..db316e3710e3 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
@@ -14,6 +14,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Reader;
+import java.net.CookieHandler;
 
 import com.facebook.react.bridge.Arguments;
 import com.facebook.react.bridge.GuardedAsyncTask;
@@ -72,19 +73,19 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
   }
 
   /**
-   * @param reactContext the ReactContext of the application
+   * @param context the ReactContext of the application
    */
-  public NetworkingModule(ReactApplicationContext reactContext) {
-    this(reactContext, null, OkHttpClientProvider.getOkHttpClient());
+  public NetworkingModule(final ReactApplicationContext context) {
+    this(context, null, OkHttpClientProvider.getCookieAwareOkHttpClient(context));
   }
 
   /**
-   * @param reactContext the ReactContext of the application
+   * @param context the ReactContext of the application
    * @param defaultUserAgent the User-Agent header that will be set for all requests where the
    * caller does not provide one explicitly
    */
-  public NetworkingModule(ReactApplicationContext reactContext, String defaultUserAgent) {
-    this(reactContext, defaultUserAgent, OkHttpClientProvider.getOkHttpClient());
+  public NetworkingModule(ReactApplicationContext context, String defaultUserAgent) {
+    this(context, defaultUserAgent, OkHttpClientProvider.getCookieAwareOkHttpClient(context));
   }
 
   public NetworkingModule(ReactApplicationContext reactContext, OkHttpClient client) {
@@ -100,6 +101,11 @@ public String getName() {
   public void onCatalystInstanceDestroy() {
     mShuttingDown = true;
     mClient.cancel(null);
+
+    CookieHandler cookieHandler = mClient.getCookieHandler();
+    if (cookieHandler instanceof ForwardingCookieHandler) {
+      ((ForwardingCookieHandler) cookieHandler).destroy();
+    }
   }
 
   @ReactMethod
@@ -311,6 +317,14 @@ protected void doInBackgroundGuarded(Void... params) {
     }.execute();
   }
 
+  @ReactMethod
+  public void clearCookies(com.facebook.react.bridge.Callback callback) {
+    CookieHandler cookieHandler = mClient.getCookieHandler();
+    if (cookieHandler instanceof ForwardingCookieHandler) {
+      ((ForwardingCookieHandler) cookieHandler).clearCookies(callback);
+    }
+  }
+
   private @Nullable MultipartBuilder constructMultipartBody(
       ReadableArray body,
       String contentType,
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/OkHttpClientProvider.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/OkHttpClientProvider.java
index fb700201302c..699ffa5255c4 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/OkHttpClientProvider.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/OkHttpClientProvider.java
@@ -9,7 +9,12 @@
 
 package com.facebook.react.modules.network;
 
+import javax.annotation.Nullable;
+
 import java.util.concurrent.TimeUnit;
+
+import com.facebook.react.bridge.ReactContext;
+
 import com.squareup.okhttp.OkHttpClient;
 
 /**
@@ -19,18 +24,33 @@
 public class OkHttpClientProvider {
 
   // Centralized OkHttpClient for all networking requests.
-  private static OkHttpClient sClient;
+  private static @Nullable OkHttpClient sClient;
+  private static ForwardingCookieHandler sCookieHandler;
 
   public static OkHttpClient getOkHttpClient() {
     if (sClient == null) {
-      // TODO: #7108751 plug in stetho
-      sClient = new OkHttpClient();
-
-      // No timeouts by default
-      sClient.setConnectTimeout(0, TimeUnit.MILLISECONDS);
-      sClient.setReadTimeout(0, TimeUnit.MILLISECONDS);
-      sClient.setWriteTimeout(0, TimeUnit.MILLISECONDS);
+      sClient = createClient();
     }
     return sClient;
   }
+
+  public static OkHttpClient getCookieAwareOkHttpClient(ReactContext context) {
+    if (sCookieHandler == null) {
+      sCookieHandler = new ForwardingCookieHandler(context);
+      getOkHttpClient().setCookieHandler(sCookieHandler);
+    }
+    return getOkHttpClient();
+  }
+
+  private static OkHttpClient createClient() {
+    // TODO: #7108751 plug in stetho
+    OkHttpClient client = new OkHttpClient();
+
+    // No timeouts by default
+    client.setConnectTimeout(0, TimeUnit.MILLISECONDS);
+    client.setReadTimeout(0, TimeUnit.MILLISECONDS);
+    client.setWriteTimeout(0, TimeUnit.MILLISECONDS);
+
+    return client;
+  }
 }

From f827a513a1a312a9d7b2f056cd025f9621426fff Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Mon, 23 Nov 2015 04:18:20 -0800
Subject: [PATCH 0043/1411] Fixed double-callback for cached images

Summary: public

A missing return statement in RCTImageLoader meant that cached images would be loaded twice - once from cache and again from the source.

This was mostly innocuous, causing only a slight perf regression due to the image cache being effectively disabled, however in some cases (such as RCTImageEditingManager.cropImage) it caused the success callback to fire twice, resulting in a crash.

Reviewed By: fkgozali

Differential Revision: D2684956

fb-gh-sync-id: 7580a6fbfe00a30807951803e04bfcdbee3bb80a
---
 Libraries/Image/RCTImageLoader.m | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Libraries/Image/RCTImageLoader.m b/Libraries/Image/RCTImageLoader.m
index 8c77828b058b..7f67b53b7fda 100644
--- a/Libraries/Image/RCTImageLoader.m
+++ b/Libraries/Image/RCTImageLoader.m
@@ -290,6 +290,7 @@ - (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag
     NSCachedURLResponse *cachedResponse = [_URLCache cachedResponseForRequest:request];
     if (cachedResponse) {
       processResponse(cachedResponse.response, cachedResponse.data, nil);
+      return;
     }
 
     // Download image

From d92b3b3e9b453231853f0440c37514d02252d70f Mon Sep 17 00:00:00 2001
From: Andrew Sardone <andrew@andrewsardone.com>
Date: Mon, 23 Nov 2015 08:20:20 -0500
Subject: [PATCH 0044/1411] Clarify --dev flag for react-native-bundle
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Given some [confusion around `react-native bundle`'s `--dev` flag][1],
this hopes to clear somet things up int he docs by…

- Removing mentions of the `__DEV__` environment variable
    - I think it confuses the user on how to work with the command-line
      flag, and frankly it seems like an internal implementation detail
      from the perspective of react-native-cli. We should focus on what
      the `--dev` flag does (e.g., toggles dev warnings, performance
      optimizations).
- Adding a minimal note about native-land's build configurations and how
  that should be checked for production builds

[1]: https://github.com/facebook/react-native/issues/4181
---
 docs/RunningOnDeviceIOS.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/RunningOnDeviceIOS.md b/docs/RunningOnDeviceIOS.md
index f4bc780235ae..5dae7ccc4a05 100644
--- a/docs/RunningOnDeviceIOS.md
+++ b/docs/RunningOnDeviceIOS.md
@@ -32,7 +32,7 @@ You can also pack all the JavaScript code within the app itself. This way you ca
 
 The bundle script supports a couple of flags:
 
-* `--dev` - sets the value of `__DEV__` variable to true. When `true` it turns on a bunch of useful development warnings. For production it is recommended to set `__DEV__=false`.
+* `--dev` - a boolean with a default value of `true`. With the `--dev true` flag, the bundled JavaScript code turns on useful development warnings and limits performance optimizations. For production it is recommended to pass `--dev false`. Also for production, be sure to have your native build configuration set to `Release` (e.g., Xcode's Release configuration for iOS and gradle's `assembleRelease` task for Android) in order to disable things like the shake-to-show developer menu.
 * `--minify` - pipe the JS code through UglifyJS.
 
 Note that on 0.14 we'll change the API of `react-native bundle`. The major changes are: 

From 6b3a6e59580e71256a3a6b885b0fb8f88bd1cb6e Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Mon, 23 Nov 2015 06:35:18 -0800
Subject: [PATCH 0045/1411] Unbreak open source release due to import of
 internal module

Reviewed By: majak

Differential Revision: D2685592

fb-gh-sync-id: eb5e9baf15d08ff1ec2c29e0ca1fe94df079d79e
---
 Libraries/ReactIOS/YellowBox.js | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/Libraries/ReactIOS/YellowBox.js b/Libraries/ReactIOS/YellowBox.js
index c439b4e20cba..5c1e0e37284d 100644
--- a/Libraries/ReactIOS/YellowBox.js
+++ b/Libraries/ReactIOS/YellowBox.js
@@ -59,8 +59,21 @@ if (__DEV__) {
   };
 }
 
+/**
+ * Simple function for formatting strings.
+ *
+ * Replaces placeholders with values passed as extra arguments
+ *
+ * @param {string} format the base string
+ * @param ...args the values to insert
+ * @return {string} the replaced string
+ */
+function sprintf(format, ...args) {
+  var index = 0;
+  return format.replace(/%s/g, match => args[index++]);
+}
+
 function updateWarningMap(format, ...args): void {
-  const sprintf = require('sprintf');
   const stringifySafe = require('stringifySafe');
 
   format = String(format);

From 02b67d9d403e4c7fb02bbfc2b21b74b8db1d1352 Mon Sep 17 00:00:00 2001
From: Milen Dzhumerov <mgd@fb.com>
Date: Mon, 23 Nov 2015 07:01:06 -0800
Subject: [PATCH 0046/1411] BridgeProfiling measure methods

Summary: public Add measure() family of methods which allow to easily swizzle methods for profiling

Reviewed By: tadeuzagallo

Differential Revision: D2679904

fb-gh-sync-id: 3724440e1bdaca9e854f4d4124a897a204966dc7
---
 Libraries/Utilities/BridgeProfiling.js | 51 +++++++++++++++++++++++++-
 1 file changed, 50 insertions(+), 1 deletion(-)

diff --git a/Libraries/Utilities/BridgeProfiling.js b/Libraries/Utilities/BridgeProfiling.js
index e62c8b76dcec..e707b357d3d1 100644
--- a/Libraries/Utilities/BridgeProfiling.js
+++ b/Libraries/Utilities/BridgeProfiling.js
@@ -78,7 +78,56 @@ var BridgeProfiling = {
         };
       });
     } catch(err) {}
-  }
+  },
+
+ /**
+  * Measures multiple methods of a class. For example, you can do:
+  * BridgeProfiling.measureMethods(JSON, 'JSON', ['parse', 'stringify']);
+  *
+  * @param object
+  * @param objectName
+  * @param methodNames Map from method names to method display names.
+  */
+ measureMethods(object: any, objectName: string, methodNames: Array<string>): void {
+   if (!__DEV__) {
+     return;
+   }
+
+   methodNames.forEach(methodName => {
+     object[methodName] = BridgeProfiling.measure(
+       objectName,
+       methodName,
+       object[methodName]
+     );
+   });
+ },
+
+ /**
+  * Returns an profiled version of the input function. For example, you can:
+  * JSON.parse = BridgeProfiling.measure('JSON', 'parse', JSON.parse);
+  *
+  * @param objName
+  * @param fnName
+  * @param {function} func
+  * @return {function} replacement function
+  */
+ measure(objName: string, fnName: string, func: any): any {
+   if (!__DEV__) {
+     return func;
+   }
+
+   var profileName = `${objName}.${fnName}`;
+   return function() {
+     if (!_enabled) {
+       return func.apply(this, arguments);
+     }
+
+     BridgeProfiling.profile(profileName);
+     var ret = func.apply(this, arguments);
+     BridgeProfiling.profileEnd();
+     return ret;
+   };
+ },
 };
 
 BridgeProfiling.setEnabled(global.__RCTProfileIsProfiling || false);

From e4dca7a1fa29bf500849a0fea4f0f6ecc3581293 Mon Sep 17 00:00:00 2001
From: Milen Dzhumerov <mgd@fb.com>
Date: Mon, 23 Nov 2015 07:01:11 -0800
Subject: [PATCH 0047/1411] Add JSON methods to systrace

Summary: public Add JSON methods to systraces

Reviewed By: jspahrsummers

Differential Revision: D2679719

fb-gh-sync-id: d8bbdc9577264b1de01d7bb52656f4f1a86a5982
---
 Libraries/Utilities/BridgeProfiling.js | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/Libraries/Utilities/BridgeProfiling.js b/Libraries/Utilities/BridgeProfiling.js
index e707b357d3d1..f71b6511c7ed 100644
--- a/Libraries/Utilities/BridgeProfiling.js
+++ b/Libraries/Utilities/BridgeProfiling.js
@@ -80,6 +80,15 @@ var BridgeProfiling = {
     } catch(err) {}
   },
 
+  /* This is not called by default due to perf overhead but it's useful
+     if you want to find traces which spend too much time in JSON. */
+  swizzleJSON() {
+    BridgeProfiling.measureMethods(JSON, 'JSON', [
+      'parse',
+      'stringify'
+    ]);
+  },
+
  /**
   * Measures multiple methods of a class. For example, you can do:
   * BridgeProfiling.measureMethods(JSON, 'JSON', ['parse', 'stringify']);

From e0d53e1c48d34419ea9a0622bd9b360c51ec3b78 Mon Sep 17 00:00:00 2001
From: Hedger Wang <hedger@fb.com>
Date: Mon, 23 Nov 2015 09:17:32 -0800
Subject: [PATCH 0048/1411] Fix move gesture handling.

Summary: public

The gesture that moves scene around should only be attached when the
move starts at the moment that the first move is granted.

No move would ever be granted if the move event is prevented by the
decendent children (e.g. a slider component).

For now, the move gesture is attached at `onPanResponderGrant`
instead of `onPanResponderMove` thus we'd create "ghost-move-gesture"
when no actual moves is received my the navigator.

Reviewed By: fkgozali

Differential Revision: D2683802

fb-gh-sync-id: 50ae877787167511df48378304bd2ad665c73300
---
 .../CustomComponents/Navigator/Navigator.js   | 26 +++++++++----------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/Libraries/CustomComponents/Navigator/Navigator.js b/Libraries/CustomComponents/Navigator/Navigator.js
index 8bfd55457a3d..ff7ff2c632f7 100644
--- a/Libraries/CustomComponents/Navigator/Navigator.js
+++ b/Libraries/CustomComponents/Navigator/Navigator.js
@@ -329,7 +329,6 @@ var Navigator = React.createClass({
     });
     this.panGesture = PanResponder.create({
       onMoveShouldSetPanResponder: this._handleMoveShouldSetPanResponder,
-      onPanResponderGrant: this._handlePanResponderGrant,
       onPanResponderRelease: this._handlePanResponderRelease,
       onPanResponderMove: this._handlePanResponderMove,
       onPanResponderTerminate: this._handlePanResponderTerminate,
@@ -609,7 +608,8 @@ var Navigator = React.createClass({
     if (!sceneConfig) {
       return false;
     }
-    this._expectingGestureGrant = this._matchGestureAction(this._eligibleGestures, sceneConfig.gestures, gestureState);
+    this._expectingGestureGrant =
+      this._matchGestureAction(this._eligibleGestures, sceneConfig.gestures, gestureState);
     return !!this._expectingGestureGrant;
   },
 
@@ -621,16 +621,6 @@ var Navigator = React.createClass({
     return wouldOverswipeForward || wouldOverswipeBack;
   },
 
-  _handlePanResponderGrant: function(e, gestureState) {
-    invariant(
-      this._expectingGestureGrant,
-      'Responder granted unexpectedly.'
-    );
-    this._attachGesture(this._expectingGestureGrant);
-    this._onAnimationStart();
-    this._expectingGestureGrant = null;
-  },
-
   _deltaForGestureAction: function(gestureAction) {
     switch (gestureAction) {
       case 'pop':
@@ -735,6 +725,16 @@ var Navigator = React.createClass({
   },
 
   _handlePanResponderMove: function(e, gestureState) {
+    if (this._isMoveGestureAttached !== undefined) {
+      invariant(
+        this._expectingGestureGrant,
+        'Responder granted unexpectedly.'
+      );
+      this._attachGesture(this._expectingGestureGrant);
+      this._onAnimationStart();
+      this._expectingGestureGrant = undefined;
+    }
+
     var sceneConfig = this.state.sceneConfigStack[this.state.presentedIndex];
     if (this.state.activeGesture) {
       var gesture = sceneConfig.gestures[this.state.activeGesture];
@@ -825,7 +825,7 @@ var Navigator = React.createClass({
         this._eligibleGestures = this._eligibleGestures.slice().splice(gestureIndex, 1);
       }
     });
-    return matchedGesture;
+    return matchedGesture || null;
   },
 
   _transitionSceneStyle: function(fromIndex, toIndex, progress, index) {

From 0c2ee5d480e696f8621252c936a8773e8de9f8b6 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Mon, 23 Nov 2015 08:00:46 -0800
Subject: [PATCH 0049/1411] Update Android Touch events

Summary: public

This moves Android touch events to parity with iOS.  The locationX,Y value passed to js now is view relative to the view that is handling the touch.
The pageX,Y is now relative to the root view.

Reviewed By: andreicoman11

Differential Revision: D2670028

fb-gh-sync-id: 5438640d6c78633629b9a308a59cc306bb07815e
---
 .../com/facebook/react/ReactRootView.java     | 53 ++++++++++++++++---
 .../react/uimanager/TouchTargetHelper.java    | 27 ++++++++--
 .../react/uimanager/events/TouchEvent.java    | 31 +++++++++--
 .../react/uimanager/events/TouchesHelper.java | 49 ++++++++++-------
 4 files changed, 125 insertions(+), 35 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
index 0a4eadc00862..0f51cd86d4bb 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
@@ -61,6 +61,9 @@ public class ReactRootView extends SizeMonitoringFrameLayout implements RootView
   private @Nullable String mJSModuleName;
   private @Nullable Bundle mLaunchOptions;
   private int mTargetTag = -1;
+  // Note mTargetCoordinates are Y,X
+  // TODO: t9136625 tracks moving to X,Y
+  private final float[] mTargetCoordinates = new float[2];
   private boolean mChildIsHandlingNativeGesture = false;
   private boolean mWasMeasured = false;
   private boolean mAttachScheduled = false;
@@ -143,9 +146,19 @@ private void handleTouchEvent(MotionEvent ev) {
       // {@link #findTargetTagForTouch} to find react view ID that will be responsible for handling
       // this gesture
       mChildIsHandlingNativeGesture = false;
-      mTargetTag = TouchTargetHelper.findTargetTagForTouch(ev.getY(), ev.getX(), this);
+      mTargetTag = TouchTargetHelper.findTargetTagAndCoordinatesForTouch(
+          ev.getY(),
+          ev.getX(),
+          this,
+          mTargetCoordinates);
       eventDispatcher.dispatchEvent(
-          TouchEvent.obtain(mTargetTag, SystemClock.uptimeMillis(), TouchEventType.START, ev));
+          TouchEvent.obtain(
+              mTargetTag,
+              SystemClock.uptimeMillis(),
+              TouchEventType.START,
+              ev,
+              mTargetCoordinates[1],
+              mTargetCoordinates[0]));
     } else if (mChildIsHandlingNativeGesture) {
       // If the touch was intercepted by a child, we've already sent a cancel event to JS for this
       // gesture, so we shouldn't send any more touches related to it.
@@ -161,20 +174,44 @@ private void handleTouchEvent(MotionEvent ev) {
       // End of the gesture. We reset target tag to -1 and expect no further event associated with
       // this gesture.
       eventDispatcher.dispatchEvent(
-          TouchEvent.obtain(mTargetTag, SystemClock.uptimeMillis(), TouchEventType.END, ev));
+          TouchEvent.obtain(
+              mTargetTag,
+              SystemClock.uptimeMillis(),
+              TouchEventType.END,
+              ev,
+              mTargetCoordinates[1],
+              mTargetCoordinates[0]));
       mTargetTag = -1;
     } else if (action == MotionEvent.ACTION_MOVE) {
       // Update pointer position for current gesture
       eventDispatcher.dispatchEvent(
-          TouchEvent.obtain(mTargetTag, SystemClock.uptimeMillis(), TouchEventType.MOVE, ev));
+          TouchEvent.obtain(
+              mTargetTag,
+              SystemClock.uptimeMillis(),
+              TouchEventType.MOVE,
+              ev,
+              mTargetCoordinates[1],
+              mTargetCoordinates[0]));
     } else if (action == MotionEvent.ACTION_POINTER_DOWN) {
       // New pointer goes down, this can only happen after ACTION_DOWN is sent for the first pointer
       eventDispatcher.dispatchEvent(
-          TouchEvent.obtain(mTargetTag, SystemClock.uptimeMillis(), TouchEventType.START, ev));
+          TouchEvent.obtain(
+              mTargetTag,
+              SystemClock.uptimeMillis(),
+              TouchEventType.START,
+              ev,
+              mTargetCoordinates[1],
+              mTargetCoordinates[0]));
     } else if (action == MotionEvent.ACTION_POINTER_UP) {
       // Exactly onw of the pointers goes up
       eventDispatcher.dispatchEvent(
-          TouchEvent.obtain(mTargetTag, SystemClock.uptimeMillis(), TouchEventType.END, ev));
+          TouchEvent.obtain(
+              mTargetTag,
+              SystemClock.uptimeMillis(),
+              TouchEventType.END,
+              ev,
+              mTargetCoordinates[1],
+              mTargetCoordinates[0]));
     } else if (action == MotionEvent.ACTION_CANCEL) {
       dispatchCancelEvent(ev);
       mTargetTag = -1;
@@ -223,7 +260,9 @@ private void dispatchCancelEvent(MotionEvent androidEvent) {
             mTargetTag,
             SystemClock.uptimeMillis(),
             TouchEventType.CANCEL,
-            androidEvent));
+            androidEvent,
+            mTargetCoordinates[1],
+            mTargetCoordinates[0]));
   }
 
   @Override
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java
index 0658f7005ccd..409a9f91f402 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java
@@ -39,17 +39,34 @@ public static int findTargetTagForTouch(
       float eventY,
       float eventX,
       ViewGroup viewGroup) {
+    return findTargetTagAndCoordinatesForTouch(eventY, eventX, viewGroup, mEventCoords);
+  }
+
+  /**
+   * Find touch event target view within the provided container given the coordinates provided
+   * via {@link MotionEvent}.
+   *
+   * @param eventY the Y screen coordinate of the touch location
+   * @param eventX the X screen coordinate of the touch location
+   * @param viewGroup the container view to traverse
+   * @param viewCoords an out parameter that will return the Y,X value in the target view
+   * @return the react tag ID of the child view that should handle the event
+   */
+  public static int findTargetTagAndCoordinatesForTouch(
+      float eventY,
+      float eventX,
+      ViewGroup viewGroup,
+      float[] viewCoords) {
     UiThreadUtil.assertOnUiThread();
     int targetTag = viewGroup.getId();
     // Store eventCoords in array so that they are modified to be relative to the targetView found.
-    float[] eventCoords = mEventCoords;
-    eventCoords[0] = eventY;
-    eventCoords[1] = eventX;
-    View nativeTargetView = findTouchTargetView(eventCoords, viewGroup);
+    viewCoords[0] = eventY;
+    viewCoords[1] = eventX;
+    View nativeTargetView = findTouchTargetView(viewCoords, viewGroup);
     if (nativeTargetView != null) {
       View reactTargetView = findClosestReactAncestor(nativeTargetView);
       if (reactTargetView != null) {
-        targetTag = getTouchTargetForView(reactTargetView, eventCoords[0], eventCoords[1]);
+        targetTag = getTouchTargetForView(reactTargetView, viewCoords[0], viewCoords[1]);
       }
     }
     return targetTag;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchEvent.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchEvent.java
index 407b8c69108e..1600b74783d0 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchEvent.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchEvent.java
@@ -35,12 +35,14 @@ public static TouchEvent obtain(
       int viewTag,
       long timestampMs,
       TouchEventType touchEventType,
-      MotionEvent motionEventToCopy) {
+      MotionEvent motionEventToCopy,
+      float viewX,
+      float viewY) {
     TouchEvent event = EVENTS_POOL.acquire();
     if (event == null) {
       event = new TouchEvent();
     }
-    event.init(viewTag, timestampMs, touchEventType, motionEventToCopy);
+    event.init(viewTag, timestampMs, touchEventType, motionEventToCopy, viewX, viewY);
     return event;
   }
 
@@ -48,6 +50,10 @@ public static TouchEvent obtain(
   private @Nullable TouchEventType mTouchEventType;
   private short mCoalescingKey;
 
+  // Coordinates in the ViewTag coordinate space
+  private float mViewX;
+  private float mViewY;
+
   private TouchEvent() {
   }
 
@@ -55,7 +61,9 @@ private void init(
       int viewTag,
       long timestampMs,
       TouchEventType touchEventType,
-      MotionEvent motionEventToCopy) {
+      MotionEvent motionEventToCopy,
+      float viewX,
+      float viewY) {
     super.init(viewTag, timestampMs);
 
     short coalescingKey = 0;
@@ -84,6 +92,8 @@ private void init(
     mTouchEventType = touchEventType;
     mMotionEvent = MotionEvent.obtain(motionEventToCopy);
     mCoalescingKey = coalescingKey;
+    mViewX = viewX;
+    mViewY = viewY;
   }
 
   @Override
@@ -126,6 +136,19 @@ public void dispatch(RCTEventEmitter rctEventEmitter) {
         rctEventEmitter,
         Assertions.assertNotNull(mTouchEventType),
         getViewTag(),
-        Assertions.assertNotNull(mMotionEvent));
+        this);
+  }
+
+  public MotionEvent getMotionEvent() {
+    Assertions.assertNotNull(mMotionEvent);
+    return mMotionEvent;
+  }
+
+  public float getViewX() {
+    return mViewX;
+  }
+
+  public float getViewY() {
+    return mViewY;
   }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchesHelper.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchesHelper.java
index 56c6ff0ada2f..d312a402026b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchesHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchesHelper.java
@@ -27,8 +27,6 @@
   private static final String TIMESTAMP_KEY = "timeStamp";
   private static final String POINTER_IDENTIFIER_KEY = "identifier";
 
-  // TODO(7351435): remove when we standardize touchEvent payload, since iOS uses locationXYZ but
-  // Android uses pageXYZ. As a temporary solution, Android currently sends both.
   private static final String LOCATION_X_KEY = "locationX";
   private static final String LOCATION_Y_KEY = "locationY";
 
@@ -37,23 +35,35 @@
    * given {@param event} instance. This method use {@param reactTarget} parameter to set as a
    * target view id associated with current gesture.
    */
-  private static WritableArray createsPointersArray(int reactTarget, MotionEvent event) {
+  private static WritableArray createsPointersArray(int reactTarget, TouchEvent event) {
     WritableArray touches = Arguments.createArray();
+    MotionEvent motionEvent = event.getMotionEvent();
 
-    // Calculate raw-to-relative offset as getRawX() and getRawY() can only return values for the
-    // pointer at index 0. We use those value to calculate "raw" coordinates for other pointers
-    float offsetX = event.getRawX() - event.getX();
-    float offsetY = event.getRawY() - event.getY();
+    // Calculate the coordinates for the target view.
+    // The MotionEvent contains the X,Y of the touch in the coordinate space of the root view
+    // The TouchEvent contains the X,Y of the touch in the coordinate space of the target view
+    // Subtracting them allows us to get the coordinates of the target view's top left corner
+    // We then use this when computing the view specific touches below
+    // Since only one view is actually handling even multiple touches, the values are all relative
+    // to this one target view.
+    float targetViewCoordinateX = motionEvent.getX() - event.getViewX();
+    float targetViewCoordinateY = motionEvent.getY() - event.getViewY();
 
-    for (int index = 0; index < event.getPointerCount(); index++) {
+    for (int index = 0; index < motionEvent.getPointerCount(); index++) {
       WritableMap touch = Arguments.createMap();
-      touch.putDouble(PAGE_X_KEY, PixelUtil.toDIPFromPixel(event.getX(index) + offsetX));
-      touch.putDouble(PAGE_Y_KEY, PixelUtil.toDIPFromPixel(event.getY(index) + offsetY));
-      touch.putDouble(LOCATION_X_KEY, PixelUtil.toDIPFromPixel(event.getX(index)));
-      touch.putDouble(LOCATION_Y_KEY, PixelUtil.toDIPFromPixel(event.getY(index)));
+      // pageX,Y values are relative to the RootReactView
+      // the motionEvent already contains coordinates in that view
+      touch.putDouble(PAGE_X_KEY, PixelUtil.toDIPFromPixel(motionEvent.getX(index)));
+      touch.putDouble(PAGE_Y_KEY, PixelUtil.toDIPFromPixel(motionEvent.getY(index)));
+      // locationX,Y values are relative to the target view
+      // To compute the values for the view, we subtract that views location from the event X,Y
+      float locationX = motionEvent.getX(index) - targetViewCoordinateX;
+      float locationY = motionEvent.getY(index) - targetViewCoordinateY;
+      touch.putDouble(LOCATION_X_KEY, PixelUtil.toDIPFromPixel(locationX));
+      touch.putDouble(LOCATION_Y_KEY, PixelUtil.toDIPFromPixel(locationY));
       touch.putInt(TARGET_KEY, reactTarget);
-      touch.putDouble(TIMESTAMP_KEY, event.getEventTime());
-      touch.putDouble(POINTER_IDENTIFIER_KEY, event.getPointerId(index));
+      touch.putDouble(TIMESTAMP_KEY, motionEvent.getEventTime());
+      touch.putDouble(POINTER_IDENTIFIER_KEY, motionEvent.getPointerId(index));
       touches.pushMap(touch);
     }
 
@@ -67,25 +77,26 @@ private static WritableArray createsPointersArray(int reactTarget, MotionEvent e
    * @param rctEventEmitter Event emitter used to execute JS module call
    * @param type type of the touch event (see {@link TouchEventType})
    * @param reactTarget target view react id associated with this gesture
-   * @param androidMotionEvent native touch event to read pointers count and coordinates from
+   * @param touchEvent native touch event to read pointers count and coordinates from
    */
   public static void sendTouchEvent(
       RCTEventEmitter rctEventEmitter,
       TouchEventType type,
       int reactTarget,
-      MotionEvent androidMotionEvent) {
+      TouchEvent touchEvent) {
 
-    WritableArray pointers = createsPointersArray(reactTarget, androidMotionEvent);
+    WritableArray pointers = createsPointersArray(reactTarget, touchEvent);
+    MotionEvent motionEvent = touchEvent.getMotionEvent();
 
     // For START and END events send only index of the pointer that is associated with that event
     // For MOVE and CANCEL events 'changedIndices' array should contain all the pointers indices
     WritableArray changedIndices = Arguments.createArray();
     if (type == TouchEventType.MOVE || type == TouchEventType.CANCEL) {
-      for (int i = 0; i < androidMotionEvent.getPointerCount(); i++) {
+      for (int i = 0; i < motionEvent.getPointerCount(); i++) {
         changedIndices.pushInt(i);
       }
     } else if (type == TouchEventType.START || type == TouchEventType.END) {
-      changedIndices.pushInt(androidMotionEvent.getActionIndex());
+      changedIndices.pushInt(motionEvent.getActionIndex());
     } else {
       throw new RuntimeException("Unknown touch type: " + type);
     }

From 3afa8b6c5f7df50a2f4ce000e042ae7b2633c10b Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Mon, 23 Nov 2015 17:32:59 +0000
Subject: [PATCH 0050/1411] Update breaking-changes.md

---
 breaking-changes.md | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/breaking-changes.md b/breaking-changes.md
index 5cb09da7966b..96f4b7e49e24 100644
--- a/breaking-changes.md
+++ b/breaking-changes.md
@@ -1,5 +1,9 @@
 # Breaking Changes
 
+## 0.16
+
+- Touch events on Android now have coordinates consistent with iOS: https://github.com/facebook/react-native/commit/0c2ee5d480e696f8621252c936a8773e8de9f8b6
+
 ## 0.15
 
 - React Native now uses [React 0.14](http://facebook.github.io/react/blog/2015/10/07/react-v0.14.html); see the linked blog post for a changelog (at this time, the package split has not been made in RN (i.e., please continue to use `require('react-native')`) and refs to native components have not changed)

From 659cc005ad74f760ceee1c529363bea94bca98a4 Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Mon, 23 Nov 2015 09:48:43 -0800
Subject: [PATCH 0051/1411] Restore VSYNC markers on RCTProfile

Summary: public

The VSYNC markers got lost at some point when refactoring RCTBatchedBridge, restore it, but keep it in RCTProfile.

Reviewed By: jspahrsummers

Differential Revision: D2685805

fb-gh-sync-id: 1acad330de7baf004a83b41f90ba4b6532605de6
---
 React/Profiler/RCTProfile.m | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/React/Profiler/RCTProfile.m b/React/Profiler/RCTProfile.m
index db23fb8c200e..681a464b7a77 100644
--- a/React/Profiler/RCTProfile.m
+++ b/React/Profiler/RCTProfile.m
@@ -46,6 +46,7 @@
 static NSMutableDictionary *RCTProfileOngoingEvents;
 static NSTimeInterval RCTProfileStartTime;
 static NSUInteger RCTProfileEventID = 0;
+static CADisplayLink *RCTProfileDisplayLink;
 
 #pragma mark - Macros
 
@@ -266,6 +267,19 @@ void RCTProfileUnhookModules(RCTBridge *bridge)
   dispatch_group_leave(RCTProfileGetUnhookGroup());
 }
 
+#pragma mark - Private ObjC class only used for the vSYNC CADisplayLink target
+
+@interface RCTProfile : NSObject
+@end
+
+@implementation RCTProfile
+
++ (void)vsync:(__unused CADisplayLink *)displayLink
+{
+  RCTProfileImmediateEvent(0, @"VSYNC", 'g');
+}
+
+@end
 
 #pragma mark - Public Functions
 
@@ -312,6 +326,11 @@ void RCTProfileInit(RCTBridge *bridge)
 
   RCTProfileHookModules(bridge);
 
+  RCTProfileDisplayLink = [CADisplayLink displayLinkWithTarget:[RCTProfile class]
+                                                      selector:@selector(vsync:)];
+  [RCTProfileDisplayLink addToRunLoop:[NSRunLoop mainRunLoop]
+                              forMode:NSRunLoopCommonModes];
+
   [[NSNotificationCenter defaultCenter] postNotificationName:RCTProfileDidStartProfiling
                                                       object:nil];
 }
@@ -329,6 +348,9 @@ void RCTProfileEnd(RCTBridge *bridge, void (^callback)(NSString *))
   [[NSNotificationCenter defaultCenter] postNotificationName:RCTProfileDidEndProfiling
                                                       object:nil];
 
+  [RCTProfileDisplayLink invalidate];
+  RCTProfileDisplayLink = nil;
+
   RCTProfileUnhookModules(bridge);
 
   if (callbacks != NULL) {

From 90de853cc1d06ec22b2a291ab76131a178aa17b5 Mon Sep 17 00:00:00 2001
From: dmmiller <dmmiller@fb.com>
Date: Mon, 23 Nov 2015 18:19:58 +0000
Subject: [PATCH 0052/1411] Update GestureResponderSystem.md

Update to reflect the reality of what pageX and pageY are on both platforms.
---
 docs/GestureResponderSystem.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/GestureResponderSystem.md b/docs/GestureResponderSystem.md
index fac70d0d28c4..2c83274350c7 100644
--- a/docs/GestureResponderSystem.md
+++ b/docs/GestureResponderSystem.md
@@ -51,8 +51,8 @@ If the view is responding, the following handlers can be called:
      + `identifier` - The ID of the touch
      + `locationX` - The X position of the touch, relative to the element
      + `locationY` - The Y position of the touch, relative to the element
-     + `pageX` - The X position of the touch, relative to the screen
-     + `pageY` - The Y position of the touch, relative to the screen
+     + `pageX` - The X position of the touch, relative to the root element
+     + `pageY` - The Y position of the touch, relative to the root element
      + `target` - The node id of the element receiving the touch event
      + `timestamp` - A time identifier for the touch, useful for velocity calculation
      + `touches` - Array of all current touches on the screen

From 56a56f33d144c96d330bd19eae7a84137f924efc Mon Sep 17 00:00:00 2001
From: Peter Lai <peetah@fb.com>
Date: Mon, 23 Nov 2015 10:47:06 -0800
Subject: [PATCH 0053/1411] add method to determine if current activity is null

Reviewed By: andreicoman11

Differential Revision: D2680281

fb-gh-sync-id: ac158fb55dd60d05b7e3444d68e06a010e04eef4
---
 .../main/java/com/facebook/react/bridge/ReactContext.java | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java
index ee669462ad35..ca2d40c73434 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java
@@ -225,15 +225,17 @@ public void handleException(RuntimeException e) {
     }
   }
 
+  public boolean hasCurrentActivity() {
+    return mCurrentActivity != null;
+  }
+
   /**
    * Same as {@link Activity#startActivityForResult(Intent, int)}, this just redirects the call to
    * the current activity. Returns whether the activity was started, as this might fail if this
    * was called before the context is in the right state.
    */
   public boolean startActivityForResult(Intent intent, int code, Bundle bundle) {
-    if (mCurrentActivity == null) {
-      return false;
-    }
+    Assertions.assertNotNull(mCurrentActivity);
     mCurrentActivity.startActivityForResult(intent, code, bundle);
     return true;
   }

From b9580511a6e3d3096705b87c38bf7a76ddbdd7ff Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Mon, 23 Nov 2015 09:49:20 -0800
Subject: [PATCH 0054/1411] Codemod IntentAndroid.{openURI -> openURL}

Reviewed By: olegbl

Differential Revision: D2680128

fb-gh-sync-id: d9786b6c20d4d6f62cc79fb21ab6861afe30bb54
---
 Libraries/Components/Intent/IntentAndroid.ios.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/Components/Intent/IntentAndroid.ios.js b/Libraries/Components/Intent/IntentAndroid.ios.js
index 7ae19934d682..8b4af29ae6e3 100644
--- a/Libraries/Components/Intent/IntentAndroid.ios.js
+++ b/Libraries/Components/Intent/IntentAndroid.ios.js
@@ -11,7 +11,7 @@
 'use strict';
 
 module.exports = {
-  openURI: function(url) {
+  openURL: function(url) {
     console.error('IntentAndroid is not supported on iOS');
   },
 };

From 5f226cf4c5176141ad9d67741acf1365d525b31e Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeuxx@gmail.com>
Date: Mon, 23 Nov 2015 11:10:36 -0800
Subject: [PATCH 0055/1411] Update breaking-changes.md

---
 breaking-changes.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/breaking-changes.md b/breaking-changes.md
index 96f4b7e49e24..77a6268fcb2b 100644
--- a/breaking-changes.md
+++ b/breaking-changes.md
@@ -3,6 +3,7 @@
 ## 0.16
 
 - Touch events on Android now have coordinates consistent with iOS: https://github.com/facebook/react-native/commit/0c2ee5d480e696f8621252c936a8773e8de9f8b6
+- YellowBox enabled by default: https://github.com/facebook/react-native/commit/8ab51828ff077ae0ad10c06f62f9f01d58b9bf85
 
 ## 0.15
 

From cfd9f65cfef525ab17ae2181f6e64c3534b92cac Mon Sep 17 00:00:00 2001
From: Christopher Dro <hello@blick-labs.com>
Date: Mon, 23 Nov 2015 12:29:57 -0800
Subject: [PATCH 0056/1411] Add space after url. Fixes #4292

Summary: Closes https://github.com/facebook/react-native/pull/4297

Reviewed By: svcscm

Differential Revision: D2686725

Pulled By: foghina

fb-gh-sync-id: 3679c7e8d9b3e4c12ef42628e348c6a6d5cc32d7
---
 local-cli/generator-ios/templates/app/Info.plist | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/local-cli/generator-ios/templates/app/Info.plist b/local-cli/generator-ios/templates/app/Info.plist
index cddf0766c980..91963b267072 100644
--- a/local-cli/generator-ios/templates/app/Info.plist
+++ b/local-cli/generator-ios/templates/app/Info.plist
@@ -40,7 +40,7 @@
 	<string></string>
   <key>NSAppTransportSecurity</key>
   <dict>
-    <!--See http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/-->
+    <!--See http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/ -->
     <key>NSAllowsArbitraryLoads</key>
     <true/>
   </dict>

From fdca4224bc7e42a6169debe998613583f1c28afa Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Tue, 24 Nov 2015 02:51:51 +0530
Subject: [PATCH 0057/1411] Added docs on using Promisesin Native Modules

---
 docs/NativeModulesAndroid.md | 60 ++++++++++++++++++++++++++++++++++--
 docs/NativeModulesIOS.md     | 36 ++++++++++++++++++++++
 2 files changed, 94 insertions(+), 2 deletions(-)

diff --git a/docs/NativeModulesAndroid.md b/docs/NativeModulesAndroid.md
index c7dcf2eb9750..dbbcd0cd3072 100644
--- a/docs/NativeModulesAndroid.md
+++ b/docs/NativeModulesAndroid.md
@@ -124,7 +124,7 @@ mReactInstanceManager = ReactInstanceManager.builder()
 
 To make it simpler to access your new functionality from JavaScript, it is common to wrap the native module in a JavaScript module. This is not necessary but saves the consumers of your library the need to pull it off of `NativeModules` each time. This JavaScript file also becomes a good location for you to add any JavaScript side functionality.
 
-```java
+```js
 /**
  * @providesModule ToastAndroid
  */
@@ -203,6 +203,62 @@ A native module is supposed to invoke its callback only once. It can, however, s
 
 It is very important to highlight that the callback is not invoked immediately after the native function completes - remember that bridge communication is asynchronous, and this too is tied to the run loop.
 
+### Promises
+
+Native modules can also fulfill a promise, which can simplify your code, especially when using ES2016's `async/await` syntax. When the last parameter of a bridged native method is a `Promise`, its corresponding JS method will return a JS Promise object.
+
+Refactoring the above code to use a promise instead of callbacks looks like this:
+
+```java
+public class UIManagerModule extends ReactContextBaseJavaModule {
+
+...
+
+  @ReactMethod
+  public void measureLayout(
+      int tag,
+      int ancestorTag,
+      Promise promise) {
+    try {
+      measureLayout(tag, ancestorTag, mMeasureBuffer);
+
+      WritableMap map = Arguments.createMap();
+
+      map.putDouble("relativeX", PixelUtil.toDIPFromPixel(mMeasureBuffer[0]));
+      map.putDouble("relativeY", PixelUtil.toDIPFromPixel(mMeasureBuffer[1]));
+      map.putDouble("width", PixelUtil.toDIPFromPixel(mMeasureBuffer[2]));
+      map.putDouble("height", PixelUtil.toDIPFromPixel(mMeasureBuffer[3]));
+
+      promise.resolve(map);
+    } catch (IllegalViewOperationException e) {
+      promise.reject(e.getMessage());
+    }
+  }
+
+...
+```
+
+The JavaScript counterpart of this method returns a Promise. This means you can use the `await` keyword within an async function to call it and wait for its result:
+
+```js
+async function measureLayout() {
+  try {
+    var {
+      relativeX,
+      relativeY,
+      width,
+      height,
+    } = await UIManager.measureLayout(100, 100);
+
+    console.log(relativeX + ':' + relativeY + ':' + width + ':' + height);
+  } catch (e) {
+    console.error(e);
+  }
+}
+
+measureLayout();
+```
+
 ### Threading
 
 Native modules should not have any assumptions about what thread they are being called on, as the current assignment is subject to change in the future. If a blocking call is required, the heavy work should be dispatched to an internally managed worker thread, and any callbacks distributed from there.
@@ -259,4 +315,4 @@ componentWillMount: function() {
   });
 }
 ...
-```
\ No newline at end of file
+```
diff --git a/docs/NativeModulesIOS.md b/docs/NativeModulesIOS.md
index f3b8510c4337..b50b82a27ae1 100644
--- a/docs/NativeModulesIOS.md
+++ b/docs/NativeModulesIOS.md
@@ -173,6 +173,42 @@ A native module is supposed to invoke its callback only once. It can, however, s
 
 If you want to pass error-like objects to JavaScript, use `RCTMakeError` from [`RCTUtils.h`](https://github.com/facebook/react-native/blob/master/React/Base/RCTUtils.h).  Right now this just passes an Error-shaped dictionary to JavaScript, but we would like to automatically generate real JavaScript `Error` objects in the future.
 
+## Promises
+
+Native modules can also fulfill a promise, which can simplify your code, especially when using ES2016's `async/await` syntax. When the last parameters of a bridged native method are an `RCTPromiseResolveBlock` and `RCTPromiseRejectBlock`, its corresponding JS method will return a JS Promise object.
+
+Refactoring the above code to use a promise instead of callbacks looks like this:
+
+```objective-c
+RCT_REMAP_METHOD(findEvents,
+                 resolver:(RCTPromiseResolveBlock)resolve,
+                 rejecter:(RCTPromiseRejectBlock)reject))
+{
+  NSArray *events = ...
+  if (events) {
+    resolve(events);
+  } else {
+    reject(error);
+  }
+}
+```
+
+The JavaScript counterpart of this method returns a Promise. This means you can use the `await` keyword within an async function to call it and wait for its result:
+
+```js
+async function updateEvents() {
+  try {
+    var events = await CalendarManager.findEvents();
+
+    this.setState({ events });
+  } catch (e) {
+    console.error(e);
+  }
+}
+
+updateEvents();
+```
+
 ## Threading
 
 The native module should not have any assumptions about what thread it is being called on. React Native invokes native modules methods on a separate serial GCD queue, but this is an implementation detail and might change.  The `- (dispatch_queue_t)methodQueue` method allows the native module to specify which queue its methods should be run on.  For example, if it needs to use a main-thread-only iOS API, it should specify this via:

From db617e56a308de0db09c93e73a05d7627653ff11 Mon Sep 17 00:00:00 2001
From: Kevin Gozali <fkg@fb.com>
Date: Mon, 23 Nov 2015 13:41:34 -0800
Subject: [PATCH 0058/1411] send fatal error for js exception in eventEmitter

Summary: public

Any uncaught exception inside an event emitter handler was reported as softError, which didn't crash the app, but left the app running in an unknown state. Since there's no way for the app to catch these softerror (to provide a fallback error view, etc), let's change it to report fatal error for uncaught exception for the time being.

Reviewed By: javache

Differential Revision: D2685322

fb-gh-sync-id: 52956d3db20809cc90448bd080795754b899435e
---
 Libraries/vendor/emitter/EventEmitter.js | 24 +++++++-----------------
 1 file changed, 7 insertions(+), 17 deletions(-)

diff --git a/Libraries/vendor/emitter/EventEmitter.js b/Libraries/vendor/emitter/EventEmitter.js
index d8b679214e2a..cb3725ebb989 100644
--- a/Libraries/vendor/emitter/EventEmitter.js
+++ b/Libraries/vendor/emitter/EventEmitter.js
@@ -1,16 +1,10 @@
 /**
- * @generated SignedSource<<494e66dea72a3e90b763a5ec50b1e0ca>>
+ * Copyright (c) 2015-present, Facebook, Inc.
+ * All rights reserved.
  *
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !! This file is a check-in of a static_upstream project!      !!
- * !!                                                            !!
- * !! You should not modify this file directly. Instead:         !!
- * !! 1) Use `fjs use-upstream` to temporarily replace this with !!
- * !!    the latest version from upstream.                       !!
- * !! 2) Make your changes, test them, etc.                      !!
- * !! 3) Use `fjs push-upstream` to copy your changes back to    !!
- * !!    static_upstream.                                        !!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule EventEmitter
  * @typechecks
@@ -164,13 +158,9 @@ class EventEmitter {
         // The subscription may have been removed during this event loop.
         if (subscription) {
           this._currentSubscription = subscription;
-
-          ErrorUtils.applyWithGuard(
-            subscription.listener,
+          subscription.listener.apply(
             subscription.context,
-            Array.prototype.slice.call(arguments, 1),
-            null,
-            'EventEmitter:' + eventType
+            Array.prototype.slice.call(arguments, 1)
           );
         }
       }

From 598d37f6d5eb7bc4faf2ff7e00a2f04b6c858e56 Mon Sep 17 00:00:00 2001
From: Spencer Ahrens <sahrens@fb.com>
Date: Mon, 23 Nov 2015 13:02:05 -0800
Subject: [PATCH 0059/1411] Quick fix to require cycle in UnimplementedView

Reviewed By: vjeux

Differential Revision: D2686884

fb-gh-sync-id: 99afd8b389d5849d708654a4967dbd403ac24a9b
---
 Libraries/Components/UnimplementedViews/UnimplementedView.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/Libraries/Components/UnimplementedViews/UnimplementedView.js b/Libraries/Components/UnimplementedViews/UnimplementedView.js
index 6aebef38b16b..1870f495bcc7 100644
--- a/Libraries/Components/UnimplementedViews/UnimplementedView.js
+++ b/Libraries/Components/UnimplementedViews/UnimplementedView.js
@@ -9,7 +9,6 @@
 
 var React = require('React');
 var StyleSheet = require('StyleSheet');
-var View = require('View');
 
 var UnimplementedView = React.createClass({
   setNativeProps: function() {
@@ -18,6 +17,8 @@ var UnimplementedView = React.createClass({
     // See ensureComponentIsNative.js for more info
   },
   render: function() {
+    // Workaround require cycle from requireNativeComponent
+    var View = require('View');
     return (
       <View style={[styles.unimplementedView, this.props.style]}>
         {this.props.children}

From f624d01cacf64ae8adc76231e2c8efa30fb71f33 Mon Sep 17 00:00:00 2001
From: Sebastian Markbage <sema@fb.com>
Date: Mon, 23 Nov 2015 14:17:54 -0800
Subject: [PATCH 0060/1411] Make Style Interpolator Function Generation Lazy

Summary: This code generation executes eagerly and these functions are fairly large and takes time to compile.

However, I'm mostly doing this change because it significantly increases the Prepack binary file size.

In theory, there might be a slight impact on the first use of these interpolators but I couldn't really tell.

An alternative would be to create a factory that is called by the components at an appropriate time, or to just refactor the whole thing to use Animated.

I didn't want to dig too deeply for a single component though.

public

Reviewed By: vjeux

Differential Revision: D2687296

fb-gh-sync-id: 6fc8cdf54dfb6f0b50c11db973d67d114bbc7400
---
 Libraries/Utilities/buildStyleInterpolator.js | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/Libraries/Utilities/buildStyleInterpolator.js b/Libraries/Utilities/buildStyleInterpolator.js
index fdb9653e8f01..1ff93d106400 100644
--- a/Libraries/Utilities/buildStyleInterpolator.js
+++ b/Libraries/Utilities/buildStyleInterpolator.js
@@ -553,8 +553,15 @@ var createFunctionString = function(anims) {
  * object and returns a boolean describing if any update was actually applied.
  */
 var buildStyleInterpolator = function(anims) {
-  return Function(createFunctionString(anims))();
+  // Defer compiling this method until we really need it.
+  var interpolator = null;
+  function lazyStyleInterpolator(result, value) {
+    if (interpolator === null) {
+      interpolator = Function(createFunctionString(anims))();
+    }
+    return interpolator(result, value);
+  }
+  return lazyStyleInterpolator;
 };
 
-
 module.exports = buildStyleInterpolator;

From ac0134322ff25b0c527f75fd3da1b743caaaf148 Mon Sep 17 00:00:00 2001
From: Denis Koroskin <dkoroskin@fb.com>
Date: Mon, 23 Nov 2015 13:21:29 -0800
Subject: [PATCH 0061/1411] Remove UIManagerModule dependency in
 UIViewOperationQueue

Reviewed By: astreet

Differential Revision: D2463226

fb-gh-sync-id: eafc876ca750a08406917d8bbbfe87c27a4649fd
---
 .../DidJSUpdateUiDuringFrameDetector.java     |  4 +--
 .../modules/debug/FpsDebugFrameCallback.java  |  4 +--
 .../react/uimanager/UIManagerModule.java      | 34 +++----------------
 .../react/uimanager/UIViewOperationQueue.java | 28 +++++++++------
 ...SafeViewHierarchyUpdateDebugListener.java} |  4 +--
 5 files changed, 28 insertions(+), 46 deletions(-)
 rename ReactAndroid/src/main/java/com/facebook/react/uimanager/debug/{NotThreadSafeUiManagerDebugListener.java => NotThreadSafeViewHierarchyUpdateDebugListener.java} (85%)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/debug/DidJSUpdateUiDuringFrameDetector.java b/ReactAndroid/src/main/java/com/facebook/react/modules/debug/DidJSUpdateUiDuringFrameDetector.java
index 28144b9afaf2..f15a143df7c6 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/debug/DidJSUpdateUiDuringFrameDetector.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/debug/DidJSUpdateUiDuringFrameDetector.java
@@ -15,7 +15,7 @@
 import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener;
 import com.facebook.react.common.LongArray;
 import com.facebook.react.uimanager.UIManagerModule;
-import com.facebook.react.uimanager.debug.NotThreadSafeUiManagerDebugListener;
+import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
 
 /**
  * Debug object that listens to bridge busy/idle events and UiManagerModule dispatches and uses it
@@ -25,7 +25,7 @@
  * {@link Choreographer.FrameCallback}.
  */
 public class DidJSUpdateUiDuringFrameDetector implements NotThreadSafeBridgeIdleDebugListener,
-    NotThreadSafeUiManagerDebugListener {
+    NotThreadSafeViewHierarchyUpdateDebugListener {
 
   private final LongArray mTransitionToIdleEvents = LongArray.createWithInitialCapacity(20);
   private final LongArray mTransitionToBusyEvents = LongArray.createWithInitialCapacity(20);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/debug/FpsDebugFrameCallback.java b/ReactAndroid/src/main/java/com/facebook/react/modules/debug/FpsDebugFrameCallback.java
index 71400867e640..1eac40fae1a4 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/debug/FpsDebugFrameCallback.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/debug/FpsDebugFrameCallback.java
@@ -135,7 +135,7 @@ public void start() {
     mShouldStop = false;
     mReactContext.getCatalystInstance().addBridgeIdleDebugListener(
         mDidJSUpdateUiDuringFrameDetector);
-    mUIManagerModule.setUiManagerDebugListener(mDidJSUpdateUiDuringFrameDetector);
+    mUIManagerModule.setViewHierarchyUpdateDebugListener(mDidJSUpdateUiDuringFrameDetector);
     mChoreographer.postFrameCallback(this);
   }
 
@@ -149,7 +149,7 @@ public void stop() {
     mShouldStop = true;
     mReactContext.getCatalystInstance().removeBridgeIdleDebugListener(
         mDidJSUpdateUiDuringFrameDetector);
-    mUIManagerModule.setUiManagerDebugListener(null);
+    mUIManagerModule.setViewHierarchyUpdateDebugListener(null);
   }
 
   public double getFPS() {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
index 6482a209b332..67b171ee9a34 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
@@ -35,7 +35,7 @@
 import com.facebook.react.bridge.SoftAssertions;
 import com.facebook.react.bridge.UiThreadUtil;
 import com.facebook.react.bridge.WritableArray;
-import com.facebook.react.uimanager.debug.NotThreadSafeUiManagerDebugListener;
+import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
 import com.facebook.react.uimanager.events.EventDispatcher;
 import com.facebook.systrace.Systrace;
 import com.facebook.systrace.SystraceMessage;
@@ -87,7 +87,6 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements
   private final NativeViewHierarchyOptimizer mNativeViewHierarchyOptimizer;
   private final int[] mMeasureBuffer = new int[4];
 
-  private @Nullable NotThreadSafeUiManagerDebugListener mUiManagerDebugListener;
   private int mNextRootViewTag = 1;
   private int mBatchId = 0;
 
@@ -100,7 +99,6 @@ public UIManagerModule(ReactApplicationContext reactContext, List<ViewManager> v
         mViewManagers);
     mOperationsQueue = new UIViewOperationQueue(
         reactContext,
-        this,
         mNativeViewHierarchyManager,
         mAnimationRegistry);
     mNativeViewHierarchyOptimizer = new NativeViewHierarchyOptimizer(
@@ -771,8 +769,9 @@ public void onBatchComplete() {
     }
   }
 
-  public void setUiManagerDebugListener(@Nullable NotThreadSafeUiManagerDebugListener listener) {
-    mUiManagerDebugListener = listener;
+  public void setViewHierarchyUpdateDebugListener(
+      @Nullable NotThreadSafeViewHierarchyUpdateDebugListener listener) {
+    mOperationsQueue.setViewHierarchyUpdateDebugListener(listener);
   }
 
   public EventDispatcher getEventDispatcher() {
@@ -836,34 +835,9 @@ private void applyUpdatesRecursive(ReactShadowNode cssNode, float absoluteX, flo
     cssNode.markUpdateSeen();
   }
 
-  /* package */ void notifyOnViewHierarchyUpdateEnqueued() {
-    if (mUiManagerDebugListener != null) {
-      mUiManagerDebugListener.onViewHierarchyUpdateEnqueued();
-    }
-  }
-
-  /* package */ void notifyOnViewHierarchyUpdateFinished() {
-    if (mUiManagerDebugListener != null) {
-      mUiManagerDebugListener.onViewHierarchyUpdateFinished();
-    }
-  }
-
   @ReactMethod
   public void sendAccessibilityEvent(int tag, int eventType) {
     mOperationsQueue.enqueueSendAccessibilityEvent(tag, eventType);
   }
 
-  /**
-   * Get the first non-virtual (i.e. native) parent view tag of the react view with the passed tag.
-   * If the passed tag represents a non-virtual view, the same tag is returned. If the passed tag
-   * doesn't map to a react view, or a non-virtual parent cannot be found, -1 is returned.
-   */
-  /* package */ int getNonVirtualParent(int reactTag) {
-    ReactShadowNode node = mShadowNodeRegistry.getNode(reactTag);
-    while (node != null && node.isVirtual()) {
-      node = node.getParent();
-    }
-    return node == null ? -1 : node.getReactTag();
-  }
-
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
index bb9cea705cb3..a931b5e0f976 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
@@ -20,6 +20,7 @@
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
 import com.facebook.systrace.Systrace;
 import com.facebook.systrace.SystraceMessage;
 
@@ -405,11 +406,10 @@ public void execute() {
       final float containerX = (float) mMeasureBuffer[0];
       final float containerY = (float) mMeasureBuffer[1];
 
-      final int touchTargetReactTag = mUIManagerModule.getNonVirtualParent(
-          mNativeViewHierarchyManager.findTargetTagForTouch(
-            mReactTag,
-            mTargetX,
-            mTargetY));
+      final int touchTargetReactTag = mNativeViewHierarchyManager.findTargetTagForTouch(
+          mReactTag,
+          mTargetX,
+          mTargetY);
 
       try {
         mNativeViewHierarchyManager.measure(
@@ -443,7 +443,6 @@ public void execute() {
     }
   }
 
-  private final UIManagerModule mUIManagerModule;
   private final NativeViewHierarchyManager mNativeViewHierarchyManager;
   private final AnimationRegistry mAnimationRegistry;
 
@@ -453,17 +452,22 @@ public void execute() {
   @GuardedBy("mDispatchRunnablesLock")
   private final ArrayList<Runnable> mDispatchUIRunnables = new ArrayList<>();
 
+  private @Nullable NotThreadSafeViewHierarchyUpdateDebugListener mViewHierarchyUpdateDebugListener;
+
   /* package */ UIViewOperationQueue(
       ReactApplicationContext reactContext,
-      UIManagerModule uiManagerModule,
       NativeViewHierarchyManager nativeViewHierarchyManager,
       AnimationRegistry animationRegistry) {
-    mUIManagerModule = uiManagerModule;
     mNativeViewHierarchyManager = nativeViewHierarchyManager;
     mAnimationRegistry = animationRegistry;
     mDispatchUIFrameCallback = new DispatchUIFrameCallback(reactContext);
   }
 
+  public void setViewHierarchyUpdateDebugListener(
+      @Nullable NotThreadSafeViewHierarchyUpdateDebugListener listener) {
+    mViewHierarchyUpdateDebugListener = listener;
+  }
+
   public boolean isEmpty() {
     return mOperations.isEmpty();
   }
@@ -592,7 +596,9 @@ public void enqueueSendAccessibilityEvent(int tag, int eventType) {
       mOperations = new ArrayList<>();
     }
 
-    mUIManagerModule.notifyOnViewHierarchyUpdateEnqueued();
+    if (mViewHierarchyUpdateDebugListener != null) {
+      mViewHierarchyUpdateDebugListener.onViewHierarchyUpdateEnqueued();
+    }
 
     synchronized (mDispatchRunnablesLock) {
       mDispatchUIRunnables.add(
@@ -608,7 +614,9 @@ public void run() {
                      operations.get(i).execute();
                    }
                  }
-                 mUIManagerModule.notifyOnViewHierarchyUpdateFinished();
+                 if (mViewHierarchyUpdateDebugListener != null) {
+                   mViewHierarchyUpdateDebugListener.onViewHierarchyUpdateFinished();
+                 }
                } finally {
                  Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
                }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/debug/NotThreadSafeUiManagerDebugListener.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/debug/NotThreadSafeViewHierarchyUpdateDebugListener.java
similarity index 85%
rename from ReactAndroid/src/main/java/com/facebook/react/uimanager/debug/NotThreadSafeUiManagerDebugListener.java
rename to ReactAndroid/src/main/java/com/facebook/react/uimanager/debug/NotThreadSafeViewHierarchyUpdateDebugListener.java
index 1f4a5690b558..6f35ca06588e 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/debug/NotThreadSafeUiManagerDebugListener.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/debug/NotThreadSafeViewHierarchyUpdateDebugListener.java
@@ -12,13 +12,13 @@
 import com.facebook.react.uimanager.UIManagerModule;
 
 /**
- * A listener that is notified about {@link UIManagerModule} events. This listener should only be
+ * A listener that is notified about view hierarchy update events. This listener should only be
  * used for debug purposes and should not affect application state.
  *
  * NB: while onViewHierarchyUpdateFinished will always be called from the UI thread, there are no
  * guarantees what thread onViewHierarchyUpdateEnqueued is called on.
  */
-public interface NotThreadSafeUiManagerDebugListener {
+public interface NotThreadSafeViewHierarchyUpdateDebugListener {
 
   /**
    * Called when {@link UIManagerModule} enqueues a UI batch to be dispatched to the main thread.

From 6b8f3da955249f7cc5208bcf87e0d3d04f26a37b Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Mon, 23 Nov 2015 23:57:54 +0000
Subject: [PATCH 0062/1411] Update NewIssueGreeting.md

---
 bots/NewIssueGreeting.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bots/NewIssueGreeting.md b/bots/NewIssueGreeting.md
index 71f3cad64664..76ac0bd42b39 100644
--- a/bots/NewIssueGreeting.md
+++ b/bots/NewIssueGreeting.md
@@ -1,4 +1,4 @@
-Hey {author}, thanks for reporting this issue!
+Hey @{author}, thanks for reporting this issue!
 
 We've started using a new website called **[Product Pains](https://productpains.com/product/react-native/?tab=top)** to help the community **prioritize issues**.
 

From 8ccd13b9b63fac6d1365017b4d4da43e7813ed19 Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeuxx@gmail.com>
Date: Mon, 23 Nov 2015 16:05:51 -0800
Subject: [PATCH 0063/1411] Update NewIssueGreeting.md

---
 bots/NewIssueGreeting.md | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/bots/NewIssueGreeting.md b/bots/NewIssueGreeting.md
index 76ac0bd42b39..f170c5b2f5fd 100644
--- a/bots/NewIssueGreeting.md
+++ b/bots/NewIssueGreeting.md
@@ -1,7 +1,8 @@
-Hey @{author}, thanks for reporting this issue!
+Hey {author}, thanks for reporting this issue!
 
-We've started using a new website called **[Product Pains](https://productpains.com/product/react-native/?tab=top)** to help the community **prioritize issues**.
+React Native, as you've probably heard, is getting really popular and truth is we're getting a bit overwhelmed by the activity surrounding it. There are just too many issues for us to manage properly.
 
-We have a limited number of people working on React Native; it's therefore important to know which issues should be fixed first. The reason Product Pains works better than GitHub is that people can **vote on issues**. If you want to help the community prioritize, go ahead and give [Product Pains](https://productpains.com/product/react-native/?tab=top) a try. You can link to this issue from Product Pains.
+- If this is a feature request or a bug that you would like to be fixed by the team, please report it on [Product Pains](https://productpains.com/product/react-native/). It has a ranking feature that lets us focus on the most important issues the community is experiencing.
+
+- If you don't know how to do something, asking on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native) with the tag `react-native` or for more real time interactions, ask on [Discord](https://discord.gg/0ZcbPKXt5bZjGY5n) in the #react-native channel.
 
-There are also other ways to get help. Chat with us on [Reactiflux](https://discord.gg/0ZcbPKXt5bWJVmUY) in #react-native or check out the [README](https://github.com/facebook/react-native#getting-help).

From 5d9b8d9c15c681b5126ef504c056b730d2e207b8 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Tue, 24 Nov 2015 00:07:40 +0000
Subject: [PATCH 0064/1411] Update NewIssueGreeting.md

---
 bots/NewIssueGreeting.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bots/NewIssueGreeting.md b/bots/NewIssueGreeting.md
index f170c5b2f5fd..ea708fafdb18 100644
--- a/bots/NewIssueGreeting.md
+++ b/bots/NewIssueGreeting.md
@@ -4,5 +4,5 @@ React Native, as you've probably heard, is getting really popular and truth is w
 
 - If this is a feature request or a bug that you would like to be fixed by the team, please report it on [Product Pains](https://productpains.com/product/react-native/). It has a ranking feature that lets us focus on the most important issues the community is experiencing.
 
-- If you don't know how to do something, asking on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native) with the tag `react-native` or for more real time interactions, ask on [Discord](https://discord.gg/0ZcbPKXt5bZjGY5n) in the #react-native channel.
+- If you don't know how to do something, please ask on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native) with the tag `react-native` or for more real time interactions, ask on [Discord](https://discord.gg/0ZcbPKXt5bZjGY5n) in the #react-native channel.
 

From e49c70026a93a0f006b7c637b97b3a09610d1768 Mon Sep 17 00:00:00 2001
From: James Ide <ide+github@jameside.com>
Date: Mon, 23 Nov 2015 16:18:16 -0800
Subject: [PATCH 0065/1411] [Issues] Solicit high quality issues and PRs

---
 bots/NewIssueGreeting.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/bots/NewIssueGreeting.md b/bots/NewIssueGreeting.md
index ea708fafdb18..dc5d6629090c 100644
--- a/bots/NewIssueGreeting.md
+++ b/bots/NewIssueGreeting.md
@@ -6,3 +6,4 @@ React Native, as you've probably heard, is getting really popular and truth is w
 
 - If you don't know how to do something, please ask on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native) with the tag `react-native` or for more real time interactions, ask on [Discord](https://discord.gg/0ZcbPKXt5bZjGY5n) in the #react-native channel.
 
+- We welcome well-written issues and PRs that are ready for in-depth discussion; thank you for your contributions!

From b40631d0db88adfebcf0967014f682c1ac09dc9c Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Mon, 23 Nov 2015 14:47:36 -0800
Subject: [PATCH 0066/1411] Add exception description to exception name

Reviewed By: fkgozali

Differential Revision: D2687906

fb-gh-sync-id: f1bbc7c3deb9068877add37619faee730cdec743
---
 React/Base/RCTAssert.m        | 5 +++--
 React/Base/RCTBatchedBridge.m | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/React/Base/RCTAssert.m b/React/Base/RCTAssert.m
index 03e40c9308fb..4742cb381d91 100644
--- a/React/Base/RCTAssert.m
+++ b/React/Base/RCTAssert.m
@@ -128,8 +128,9 @@ void RCTFatal(NSError *error)
 #if DEBUG
     @try {
 #endif
+      NSString *name = [NSString stringWithFormat:@"%@: %@", RCTFatalExceptionName, [error localizedDescription]];
       NSString *message = RCTFormatError([error localizedDescription], error.userInfo[RCTJSStackTraceKey], 75);
-      [NSException raise:RCTFatalExceptionName format:@"%@", message];
+      [NSException raise:name format:@"%@", message];
 #if DEBUG
     } @catch (NSException *e) {}
 #endif
@@ -160,5 +161,5 @@ RCTFatalHandler RCTGetFatalHandler(void)
     }
   }
 
-  return [NSString stringWithFormat:@"Message: %@%@", message, prettyStack];
+  return [NSString stringWithFormat:@"%@%@", message, prettyStack];
 }
diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index 66f1f737d6a4..26dcb57721ac 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -780,7 +780,7 @@ - (BOOL)_handleRequestNumber:(NSUInteger)i
   }
   @catch (NSException *exception) {
     // Pass on JS exceptions
-    if ([exception.name isEqualToString:RCTFatalExceptionName]) {
+    if ([exception.name hasPrefix:RCTFatalExceptionName]) {
       @throw exception;
     }
 

From 26946e07f17702c42cbe3d123f3656ba3affb328 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Tue, 24 Nov 2015 01:20:33 +0000
Subject: [PATCH 0067/1411] Update KnownIssues.md

---
 docs/KnownIssues.md | 2 --
 1 file changed, 2 deletions(-)

diff --git a/docs/KnownIssues.md b/docs/KnownIssues.md
index 9fc543299707..5cfefec8bab4 100644
--- a/docs/KnownIssues.md
+++ b/docs/KnownIssues.md
@@ -33,12 +33,10 @@ Webview
 #### Modules
 
 ```
-Geo Location
 Net Info
 Camera Roll
 App State
 Dialog
-Intent
 Media
 Pasteboard
 PushNotificationIOS

From d5678e95e1d12704ee8c2101d722b84f8ce5732e Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Tue, 24 Nov 2015 10:29:38 +0800
Subject: [PATCH 0068/1411] Update removeClippedSubviews default value

Update removeClippedSubviews default value
---
 docs/Performance.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/Performance.md b/docs/Performance.md
index a69f6d17e80a..39a4ae254c56 100644
--- a/docs/Performance.md
+++ b/docs/Performance.md
@@ -205,7 +205,7 @@ should continue to render rows.
 "When true, offscreen child views (whose `overflow` value is `hidden`)
 are removed from their native backing superview when offscreen.  This
 can improve scrolling performance on long lists. The default value is
-false."
+`true`."(note:before version 0.14-rc, the default value is `false`).
 
 This is an extremely important optimization to apply on large ListViews.
 On Android the `overflow` value is always `hidden` so you don't need to

From bb3123353f642abf37671b4637e8687dd2b938ba Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Tue, 24 Nov 2015 10:31:35 +0800
Subject: [PATCH 0069/1411] Update Performance.md

---
 docs/Performance.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/Performance.md b/docs/Performance.md
index 39a4ae254c56..1dfbb544445c 100644
--- a/docs/Performance.md
+++ b/docs/Performance.md
@@ -205,7 +205,7 @@ should continue to render rows.
 "When true, offscreen child views (whose `overflow` value is `hidden`)
 are removed from their native backing superview when offscreen.  This
 can improve scrolling performance on long lists. The default value is
-`true`."(note:before version 0.14-rc, the default value is `false`).
+`true`."(The default value is `false` before version 0.14-rc).
 
 This is an extremely important optimization to apply on large ListViews.
 On Android the `overflow` value is always `hidden` so you don't need to

From 64675dc078a7447fc7c92c441f0c04219b4db2d3 Mon Sep 17 00:00:00 2001
From: Sebastian Markbage <sema@fb.com>
Date: Mon, 23 Nov 2015 19:22:34 -0800
Subject: [PATCH 0070/1411] Move RelayProfiler Decoupled Initialization to use
 Double Dispatch

Reviewed By: josephsavona

Differential Revision: D2689433

fb-gh-sync-id: 966b3d855a5a0a755fd55fb583e31ba648de2a7a
---
 .../InitializeJavaScriptAppEngine.js          |  1 -
 Libraries/Utilities/BridgeProfiling.js        | 32 +++++++++----------
 2 files changed, 15 insertions(+), 18 deletions(-)

diff --git a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
index 8735e1ab004b..ec13c1615032 100644
--- a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
+++ b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
@@ -162,7 +162,6 @@ function setUpProfile() {
   if (__DEV__) {
     var BridgeProfiling = require('BridgeProfiling');
     BridgeProfiling.swizzleReactPerf();
-    BridgeProfiling.attachToRelayProfiler();
   }
 }
 
diff --git a/Libraries/Utilities/BridgeProfiling.js b/Libraries/Utilities/BridgeProfiling.js
index f71b6511c7ed..526775b20793 100644
--- a/Libraries/Utilities/BridgeProfiling.js
+++ b/Libraries/Utilities/BridgeProfiling.js
@@ -11,6 +11,13 @@
  */
 'use strict';
 
+type RelayProfiler = {
+  attachProfileHandler(
+    name: string,
+    handler: (name: string, state?: any) => () => void
+  ): void
+};
+
 var GLOBAL = GLOBAL || this;
 var TRACE_TAG_REACT_APPS = 1 << 17;
 
@@ -52,7 +59,7 @@ var BridgeProfiling = {
 
       var name = objName === 'ReactCompositeComponent' && this.getName() || '';
       BridgeProfiling.profile(`${objName}.${fnName}(${name})`);
-      var ret = func.apply(this, arguments);
+    var ret = func.apply(this, arguments);
       BridgeProfiling.profileEnd();
       return ret;
     };
@@ -62,22 +69,13 @@ var BridgeProfiling = {
     ReactPerf().injection.injectMeasure(BridgeProfiling.reactPerfMeasure);
   },
 
-  attachToRelayProfiler() {
-    // We don't want to create a dependency on `RelayProfiler`, so that's why
-    // we require it indirectly (rather than using a literal string). Since
-    // there's no guarantee that the module will be present, we must wrap
-    // everything in a try-catch block as requiring a non-existing module
-    // will just throw.
-    try {
-      var rpName = 'RelayProfiler';
-      var RelayProfiler = require(rpName);
-      RelayProfiler.attachProfileHandler('*', (name) => {
-        BridgeProfiling.profile(name);
-        return () => {
-          BridgeProfiling.profileEnd();
-        };
-      });
-    } catch(err) {}
+  attachToRelayProfiler(relayProfiler: RelayProfiler) {
+    relayProfiler.attachProfileHandler('*', (name) => {
+      BridgeProfiling.profile(name);
+      return () => {
+        BridgeProfiling.profileEnd();
+      };
+    });
   },
 
   /* This is not called by default due to perf overhead but it's useful

From 87302ac74b710fb39de216f6769b4c2adb8541e9 Mon Sep 17 00:00:00 2001
From: Emilio Rodriguez <emiliorodriguez@gmail.com>
Date: Tue, 24 Nov 2015 08:44:34 +0100
Subject: [PATCH 0071/1411] style and typos

---
 docs/PlatformSpecificInformation.md | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/docs/PlatformSpecificInformation.md b/docs/PlatformSpecificInformation.md
index 7e2c5d583d13..38345e541ca8 100644
--- a/docs/PlatformSpecificInformation.md
+++ b/docs/PlatformSpecificInformation.md
@@ -7,7 +7,7 @@ permalink: docs/platform-specific-code.html
 next: native-modules-ios
 ---
 
-When building a cross platform app, the need to write different code for different platforms may arise. This can always be achieved by organizing the various components in different folders: 
+When building a cross-platform app, the need to write different code for different platforms may arise. This can always be achieved by organizing the various components in different folders: 
 
 ```sh
 /common/components/   
@@ -49,19 +49,19 @@ A module is provided by React Native to detect what is the platform in which the
 var {Platform} = React;
 
 var styles = StyleSheet.create({
-    height: (Platform.OS === 'ios') ? 200 : 100
+  height: (Platform.OS === 'ios') ? 200 : 100,
 });
 ```
 
 `Platform.OS` will be `ios` when running in iOS and `android` when running in an Android device or simulator.
 
-###Detecting android version
+###Detecting Android version
 On Android, the Platform module can be also used to detect which is the version of the Android Platform in which the app is running
 
 ```javascript
 var {Platform} = React;
 
 if(Platform.Version === '5.0'){
-   console.log('Running on Lollipop!');
+  console.log('Running on Lollipop!');
 }
 ```
\ No newline at end of file

From e919567323ce9e66ac625b9de786958911f41dab Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Tue, 24 Nov 2015 17:30:36 +0800
Subject: [PATCH 0072/1411] Give more details about js require.

Native developers may get confused by require statement.
---
 docs/NativeModulesAndroid.md | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/docs/NativeModulesAndroid.md b/docs/NativeModulesAndroid.md
index dbbcd0cd3072..8ce2ef3d2986 100644
--- a/docs/NativeModulesAndroid.md
+++ b/docs/NativeModulesAndroid.md
@@ -142,10 +142,12 @@ var { NativeModules } = require('react-native');
 module.exports = NativeModules.ToastAndroid;
 ```
 
-Now, from your JavaScript file you can call the method like this:
+Save the above code into a file named "ToastAndroid.js". Now, from your other JavaScript file you can call the method like this:
 
 ```js
-var ToastAndroid = require('ToastAndroid')
+// Suppose this js file is under the same directory as ToastAndroid.js. 
+// Otherwise change the require path.
+var ToastAndroid = require('./ToastAndroid'); 
 ToastAndroid.show('Awesome', ToastAndroid.SHORT);
 
 // Note: We require ToastAndroid without any relative filepath because

From 05c79059aefdd60e813223319abd9da564137253 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Tue, 24 Nov 2015 03:34:41 -0800
Subject: [PATCH 0073/1411] Reduce logcat spew when checking packager status

Summary: public

The common case is to hit an error when the server isn't running. We shouldn't spew a stack trace for it.

Reviewed By: foghina

Differential Revision: D2685706

fb-gh-sync-id: d230af170b92a05452f04a90f23172f15e62dce6
---
 .../java/com/facebook/react/devsupport/DevServerHelper.java  | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java
index 2db8f0b019db..1ba9b96e3727 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java
@@ -217,7 +217,10 @@ public void isPackagerRunning(final PackagerStatusCallback callback) {
         new Callback() {
           @Override
           public void onFailure(Request request, IOException e) {
-            FLog.e(ReactConstants.TAG, "IOException requesting status from packager", e);
+            FLog.w(
+                ReactConstants.TAG,
+                "The packager does not seem to be running as we got an IOException requesting " +
+                    "its status: " + e.getMessage());
             callback.onPackagerStatusFetched(false);
           }
 

From c324286fb78834d38b50b9caa2bfa0b1fa05bf3e Mon Sep 17 00:00:00 2001
From: Martin Kralik <kralik@fb.com>
Date: Tue, 24 Nov 2015 06:28:08 -0800
Subject: [PATCH 0074/1411] truncate redbox error

Summary: If a redbox error is too long it's not shown at all:
{F24443416}
This diff truncates it to its first 10000 chars, which should be good enough:
{F24443417}

The reason is a limitation of UILabel which backs text property on the used UITableViewCell.
Ideally we would use a custom cell with UITextView, but I don't feel there is any value in displaying super long error messages in a redbox.

public

Reviewed By: jspahrsummers, nicklockwood

Differential Revision: D2690638

fb-gh-sync-id: d9b3fcecd2602e8c2618afe1bb97221c2e506605
---
 React/Modules/RCTRedBox.m | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/React/Modules/RCTRedBox.m b/React/Modules/RCTRedBox.m
index a334c753368b..9f603afd0c86 100644
--- a/React/Modules/RCTRedBox.m
+++ b/React/Modules/RCTRedBox.m
@@ -107,7 +107,8 @@ - (void)showErrorMessage:(NSString *)message withStack:(NSArray<NSDictionary *>
 {
   if ((self.hidden && shouldShow) || (!self.hidden && [_lastErrorMessage isEqualToString:message])) {
     _lastStackTrace = stack;
-    _lastErrorMessage = message;
+    // message is displayed using UILabel, which is unable to render text of unlimited length, so we truncate it
+    _lastErrorMessage = [message substringToIndex:MIN(10000, message.length)];
 
     [_stackTraceTableView reloadData];
 

From 789b5708ec8afa79b3fdc2eb50772908f23cd91c Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Tue, 24 Nov 2015 06:48:04 -0800
Subject: [PATCH 0075/1411] Fix arch macro on profiler

Summary: public

Bad typo in `RCTProfile.m`, was using `__x86__` instead of the right one `__i386__`.

Reviewed By: jspahrsummers

Differential Revision: D2690557

fb-gh-sync-id: 537eb0502f5df22cd93665cabfddeead12cad9db
---
 React/Profiler/RCTProfile.m                            |  4 ++--
 ...ileTrampoline-x86.S => RCTProfileTrampoline-i386.S} |  0
 React/Profiler/RCTProfileTrampoline-x86_64.S           |  3 ---
 React/React.xcodeproj/project.pbxproj                  | 10 ++++++----
 4 files changed, 8 insertions(+), 9 deletions(-)
 rename React/Profiler/{RCTProfileTrampoline-x86.S => RCTProfileTrampoline-i386.S} (100%)

diff --git a/React/Profiler/RCTProfile.m b/React/Profiler/RCTProfile.m
index 681a464b7a77..276ae2d4f17b 100644
--- a/React/Profiler/RCTProfile.m
+++ b/React/Profiler/RCTProfile.m
@@ -175,9 +175,9 @@ IMP RCTProfileGetImplementation(id obj, SEL cmd)
  * state, call the actual function we want to profile and stop the profiler.
  *
  * The implementation can be found in RCTProfileTrampoline-<arch>.s where arch
- * is one of: x86, x86_64, arm, arm64.
+ * is one of: i386, x86_64, arm, arm64.
  */
-#if defined(__x86__) || \
+#if defined(__i386__) || \
     defined(__x86_64__) || \
     defined(__arm__) || \
     defined(__arm64__)
diff --git a/React/Profiler/RCTProfileTrampoline-x86.S b/React/Profiler/RCTProfileTrampoline-i386.S
similarity index 100%
rename from React/Profiler/RCTProfileTrampoline-x86.S
rename to React/Profiler/RCTProfileTrampoline-i386.S
diff --git a/React/Profiler/RCTProfileTrampoline-x86_64.S b/React/Profiler/RCTProfileTrampoline-x86_64.S
index 2f9d17786290..9a7a81c8594a 100644
--- a/React/Profiler/RCTProfileTrampoline-x86_64.S
+++ b/React/Profiler/RCTProfileTrampoline-x86_64.S
@@ -3,9 +3,6 @@
 
 #if RCT_DEV && defined(__x86_64__)
 
-/**
- * Define both symbols for compatibility with other assemblers
- */
   .globl SYMBOL_NAME(RCTProfileTrampoline)
 SYMBOL_NAME(RCTProfileTrampoline):
 
diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj
index 973e917618c7..b04420043bcd 100644
--- a/React/React.xcodeproj/project.pbxproj
+++ b/React/React.xcodeproj/project.pbxproj
@@ -56,8 +56,8 @@
 		1450FF861BCFF28A00208362 /* RCTProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF811BCFF28A00208362 /* RCTProfile.m */; };
 		1450FF871BCFF28A00208362 /* RCTProfileTrampoline-arm.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF821BCFF28A00208362 /* RCTProfileTrampoline-arm.S */; };
 		1450FF881BCFF28A00208362 /* RCTProfileTrampoline-arm64.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF831BCFF28A00208362 /* RCTProfileTrampoline-arm64.S */; };
-		1450FF891BCFF28A00208362 /* RCTProfileTrampoline-x86.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF841BCFF28A00208362 /* RCTProfileTrampoline-x86.S */; };
 		1450FF8A1BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF851BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S */; };
+		14BF71801C04793D00C97D0C /* RCTProfileTrampoline-i386.S in Sources */ = {isa = PBXBuildFile; fileRef = 14BF717F1C04793D00C97D0C /* RCTProfileTrampoline-i386.S */; };
 		14C2CA711B3AC63800E6CBB2 /* RCTModuleMethod.m in Sources */ = {isa = PBXBuildFile; fileRef = 14C2CA701B3AC63800E6CBB2 /* RCTModuleMethod.m */; };
 		14C2CA741B3AC64300E6CBB2 /* RCTModuleData.m in Sources */ = {isa = PBXBuildFile; fileRef = 14C2CA731B3AC64300E6CBB2 /* RCTModuleData.m */; };
 		14C2CA761B3AC64F00E6CBB2 /* RCTFrameUpdate.m in Sources */ = {isa = PBXBuildFile; fileRef = 14C2CA751B3AC64F00E6CBB2 /* RCTFrameUpdate.m */; };
@@ -210,9 +210,10 @@
 		1450FF811BCFF28A00208362 /* RCTProfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTProfile.m; sourceTree = "<group>"; };
 		1450FF821BCFF28A00208362 /* RCTProfileTrampoline-arm.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = "RCTProfileTrampoline-arm.S"; sourceTree = "<group>"; };
 		1450FF831BCFF28A00208362 /* RCTProfileTrampoline-arm64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = "RCTProfileTrampoline-arm64.S"; sourceTree = "<group>"; };
-		1450FF841BCFF28A00208362 /* RCTProfileTrampoline-x86.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = "RCTProfileTrampoline-x86.S"; sourceTree = "<group>"; };
 		1450FF851BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = "RCTProfileTrampoline-x86_64.S"; sourceTree = "<group>"; };
 		1482F9E61B55B927000ADFF3 /* RCTBridgeDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTBridgeDelegate.h; sourceTree = "<group>"; };
+		14BF717F1C04793D00C97D0C /* RCTProfileTrampoline-i386.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = "RCTProfileTrampoline-i386.S"; sourceTree = "<group>"; };
+		14BF71811C04795500C97D0C /* RCTMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTMacros.h; sourceTree = "<group>"; };
 		14C2CA6F1B3AC63800E6CBB2 /* RCTModuleMethod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTModuleMethod.h; sourceTree = "<group>"; };
 		14C2CA701B3AC63800E6CBB2 /* RCTModuleMethod.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTModuleMethod.m; sourceTree = "<group>"; };
 		14C2CA721B3AC64300E6CBB2 /* RCTModuleData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTModuleData.h; sourceTree = "<group>"; };
@@ -430,6 +431,8 @@
 		1450FF7F1BCFF28A00208362 /* Profiler */ = {
 			isa = PBXGroup;
 			children = (
+				14BF71811C04795500C97D0C /* RCTMacros.h */,
+				14BF717F1C04793D00C97D0C /* RCTProfileTrampoline-i386.S */,
 				14F7A0EB1BDA3B3C003C6C10 /* RCTPerfMonitor.m */,
 				14F7A0EE1BDA714B003C6C10 /* RCTFPSGraph.h */,
 				14F7A0EF1BDA714B003C6C10 /* RCTFPSGraph.m */,
@@ -437,7 +440,6 @@
 				1450FF811BCFF28A00208362 /* RCTProfile.m */,
 				1450FF821BCFF28A00208362 /* RCTProfileTrampoline-arm.S */,
 				1450FF831BCFF28A00208362 /* RCTProfileTrampoline-arm64.S */,
-				1450FF841BCFF28A00208362 /* RCTProfileTrampoline-x86.S */,
 				1450FF851BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S */,
 			);
 			path = Profiler;
@@ -680,8 +682,8 @@
 				13F17A851B8493E5007D4C75 /* RCTRedBox.m in Sources */,
 				83392EB31B6634E10013B15F /* RCTModalHostViewController.m in Sources */,
 				14435CE51AAC4AE100FC20F4 /* RCTMap.m in Sources */,
-				1450FF891BCFF28A00208362 /* RCTProfileTrampoline-x86.S in Sources */,
 				13B0801C1A69489C00A75B9A /* RCTNavItem.m in Sources */,
+				14BF71801C04793D00C97D0C /* RCTProfileTrampoline-i386.S in Sources */,
 				1385D0341B665AAE000A309B /* RCTModuleMap.m in Sources */,
 				83CBBA691A601EF300E9B192 /* RCTEventDispatcher.m in Sources */,
 				83A1FE8F1B62643A00BE0E65 /* RCTModalHostViewManager.m in Sources */,

From 3622e44426431988cd03ffeb6d1e4671207c9a2a Mon Sep 17 00:00:00 2001
From: Roman Telicak <roman.telicak@gmail.com>
Date: Tue, 24 Nov 2015 16:04:35 +0100
Subject: [PATCH 0076/1411] Update removeClippedSubviews prop default value

---
 Libraries/Components/ScrollView/ScrollView.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js
index a23ac8c5d505..62b619ca381a 100644
--- a/Libraries/Components/ScrollView/ScrollView.js
+++ b/Libraries/Components/ScrollView/ScrollView.js
@@ -278,7 +278,7 @@ var ScrollView = React.createClass({
      * Experimental: When true, offscreen child views (whose `overflow` value is
      * `hidden`) are removed from their native backing superview when offscreen.
      * This can improve scrolling performance on long lists. The default value is
-     * false.
+     * true.
      */
     removeClippedSubviews: PropTypes.bool,
     /**

From 40e15e15bcd9516b8d3813273edab6799a805eff Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Tue, 24 Nov 2015 15:19:25 +0000
Subject: [PATCH 0077/1411] Update KnownIssues.md

---
 docs/KnownIssues.md | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/docs/KnownIssues.md b/docs/KnownIssues.md
index 5cfefec8bab4..b350cae6a62e 100644
--- a/docs/KnownIssues.md
+++ b/docs/KnownIssues.md
@@ -57,9 +57,11 @@ There are known cases where the APIs could be made more consistent across iOS an
 - `ActivityIndicator` could render a native spinning indicator on both platforms (currently this is done using `ActivityIndicatorIOS` on iOS and `ProgressBarAndroid` on Android).
 - `ProgressBar` could render a horizontal progress bar on both platforms (on iOS this is `ProgressViewIOS`, on Android it's `ProgressBarAndroid`).
 
-### Publishing modules on Android
+### Using 3rd-party native modules
 
-There is currently no easy way of publishing custom native modules on Android. Smooth work flow for contributors is important and this will be looked at very closely after the initial Open Source release. Of course the aim will be to streamline and optimize the process between iOS and Android as much as possible.
+There are many awesome 3rd party modules: https://react.parts/native
+
+Adding these to your apps should be made simpler. Here's [an example](https://github.com/apptailor/react-native-google-signin) how this is done currently.
 
 ### The `overflow` style property defaults to `hidden` and cannot be changed on Android
 
@@ -69,6 +71,10 @@ This is a result of how Android rendering works. This feature is not being worke
 
 We don't support shadows on Android currently. These are notoriously hard to implement as they require drawing outside of a view's bounds and Android's invalidation logic has a hard time with that. A possible solution is to use [elevation](https://developer.android.com/training/material/shadows-clipping.html), but more experimentation will be required.
 
+### Android M permissions
+
+The open source version of React Native doesn't yet support the [Android M permission model](http://developer.android.com/training/permissions/requesting.html).
+
 ### Layout-only nodes on Android
 
 An optimization feature of the Android version of React Native is for views which only contribute to the layout to not have a native view, only their layout properties are propagated to their children views. This optimization is to provide stability in deep view hierarchies for React Native and is therefore enabled by default. Should you depend on a view being present or internal tests incorrectly detect a view is layout only it will be necessary to turn off this behavior. To do this, set `collapsable` to false as in this example:

From 9a484757dd4a80a5d5481740a47bd8dd6da48efc Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Tue, 24 Nov 2015 15:29:14 +0000
Subject: [PATCH 0078/1411] Update breaking-changes.md

---
 breaking-changes.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/breaking-changes.md b/breaking-changes.md
index 77a6268fcb2b..21cfe4b174aa 100644
--- a/breaking-changes.md
+++ b/breaking-changes.md
@@ -4,6 +4,7 @@
 
 - Touch events on Android now have coordinates consistent with iOS: https://github.com/facebook/react-native/commit/0c2ee5d480e696f8621252c936a8773e8de9f8b6
 - YellowBox enabled by default: https://github.com/facebook/react-native/commit/8ab51828ff077ae0ad10c06f62f9f01d58b9bf85
+- React Native now uses Babel 6 (props to tadeuzagallo for upgrading!). We've been using React Native with Babel 6 at Facebook for quite a while now. Nevertheless, please report any errors related to Babel, such as transforms for some JS features not working as expected and we'll fix them.
 
 ## 0.15
 

From bf269659686e862bf7b43b80bd18c6f721930e38 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Tue, 24 Nov 2015 15:30:29 +0000
Subject: [PATCH 0079/1411] Update breaking-changes.md

---
 breaking-changes.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/breaking-changes.md b/breaking-changes.md
index 21cfe4b174aa..3501907b85d8 100644
--- a/breaking-changes.md
+++ b/breaking-changes.md
@@ -2,8 +2,8 @@
 
 ## 0.16
 
-- Touch events on Android now have coordinates consistent with iOS: https://github.com/facebook/react-native/commit/0c2ee5d480e696f8621252c936a8773e8de9f8b6
-- YellowBox enabled by default: https://github.com/facebook/react-native/commit/8ab51828ff077ae0ad10c06f62f9f01d58b9bf85
+- Touch events on Android now have coordinates consistent with iOS: [0c2ee5](https://github.com/facebook/react-native/commit/0c2ee5d480e696f8621252c936a8773e8de9f8b6)
+- YellowBox enabled by default: [8ab518](https://github.com/facebook/react-native/commit/8ab51828ff077ae0ad10c06f62f9f01d58b9bf85)
 - React Native now uses Babel 6 (props to tadeuzagallo for upgrading!). We've been using React Native with Babel 6 at Facebook for quite a while now. Nevertheless, please report any errors related to Babel, such as transforms for some JS features not working as expected and we'll fix them.
 
 ## 0.15

From 918ef31e105590dfc6b3ffcc2f55c38dc79decfc Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Tue, 24 Nov 2015 15:47:29 +0000
Subject: [PATCH 0080/1411] Update NewIssueGreeting.md

---
 bots/NewIssueGreeting.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bots/NewIssueGreeting.md b/bots/NewIssueGreeting.md
index dc5d6629090c..6e3fe153cf26 100644
--- a/bots/NewIssueGreeting.md
+++ b/bots/NewIssueGreeting.md
@@ -4,6 +4,6 @@ React Native, as you've probably heard, is getting really popular and truth is w
 
 - If this is a feature request or a bug that you would like to be fixed by the team, please report it on [Product Pains](https://productpains.com/product/react-native/). It has a ranking feature that lets us focus on the most important issues the community is experiencing.
 
-- If you don't know how to do something, please ask on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native) with the tag `react-native` or for more real time interactions, ask on [Discord](https://discord.gg/0ZcbPKXt5bZjGY5n) in the #react-native channel.
+- If you don't know how to do something or not sure whether some behavior is expected or a bug, please ask on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native) with the tag `react-native` or for more real time interactions, ask on [Discord](https://discord.gg/0ZcbPKXt5bZjGY5n) in the #react-native channel.
 
 - We welcome well-written issues and PRs that are ready for in-depth discussion; thank you for your contributions!

From 7bfbc5dd00ce297d359677fa4556f9f5587504cf Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Tue, 24 Nov 2015 07:17:14 -0800
Subject: [PATCH 0081/1411] Add support for providing
 AbstractDraweeControllerBuilder to TextInlineImageSpan similar to ImageView

Reviewed By: andreicoman11

Differential Revision: D2690762

fb-gh-sync-id: 80596575d3fa577f8eb05d9f44f72337a640a3db
---
 .../text/ReactTextInlineImageShadowNode.java  | 18 +++++++++++++
 .../text/ReactTextInlineImageViewManager.java | 25 ++++++++++++++++++-
 .../react/views/text/ReactTextShadowNode.java |  9 +++++--
 .../react/views/text/TextInlineImageSpan.java | 19 +++++++++++---
 4 files changed, 65 insertions(+), 6 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextInlineImageShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextInlineImageShadowNode.java
index 9dc4132abc2d..dbe716020fd2 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextInlineImageShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextInlineImageShadowNode.java
@@ -17,6 +17,7 @@
 import android.net.Uri;
 
 import com.facebook.common.util.UriUtil;
+import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
 import com.facebook.react.uimanager.LayoutShadowNode;
 import com.facebook.react.uimanager.ReactProp;
 import com.facebook.react.uimanager.ReactShadowNode;
@@ -28,6 +29,15 @@
 public class ReactTextInlineImageShadowNode extends LayoutShadowNode {
 
   private @Nullable Uri mUri;
+  private final AbstractDraweeControllerBuilder mDraweeControllerBuilder;
+  private final @Nullable Object mCallerContext;
+
+  public ReactTextInlineImageShadowNode(
+      AbstractDraweeControllerBuilder draweeControllerBuilder,
+      @Nullable Object callerContext) {
+    mDraweeControllerBuilder = draweeControllerBuilder;
+    mCallerContext = callerContext;
+  }
 
   @ReactProp(name = "src")
   public void setSource(@Nullable String source) {
@@ -77,4 +87,12 @@ public boolean isVirtual() {
     return true;
   }
 
+  public AbstractDraweeControllerBuilder getDraweeControllerBuilder() {
+    return mDraweeControllerBuilder;
+  }
+
+  public @Nullable Object getCallerContext() {
+    return mCallerContext;
+  }
+
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextInlineImageViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextInlineImageViewManager.java
index 8df8645da987..b16b42deaf94 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextInlineImageViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextInlineImageViewManager.java
@@ -9,8 +9,12 @@
 
 package com.facebook.react.views.text;
 
+import javax.annotation.Nullable;
+
 import android.view.View;
 
+import com.facebook.drawee.backends.pipeline.Fresco;
+import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.ViewManager;
 
@@ -23,6 +27,20 @@ public class ReactTextInlineImageViewManager
 
   static final String REACT_CLASS = "RCTTextInlineImage";
 
+  private final @Nullable AbstractDraweeControllerBuilder mDraweeControllerBuilder;
+  private final @Nullable Object mCallerContext;
+
+  public ReactTextInlineImageViewManager() {
+    this(null, null);
+  }
+
+  public ReactTextInlineImageViewManager(
+      @Nullable AbstractDraweeControllerBuilder draweeControllerBuilder,
+      @Nullable Object callerContext) {
+    mDraweeControllerBuilder = draweeControllerBuilder;
+    mCallerContext = callerContext;
+  }
+
   @Override
   public String getName() {
     return REACT_CLASS;
@@ -35,7 +53,12 @@ public View createViewInstance(ThemedReactContext context) {
 
   @Override
   public ReactTextInlineImageShadowNode createShadowNodeInstance() {
-    return new ReactTextInlineImageShadowNode();
+    return new ReactTextInlineImageShadowNode(
+        (mDraweeControllerBuilder != null) ?
+            mDraweeControllerBuilder :
+            Fresco.newDraweeControllerBuilder(),
+        mCallerContext
+    );
   }
 
   @Override
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java
index 11c09a24a514..1e4286f78751 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java
@@ -148,8 +148,13 @@ private static final void buildSpannedFromImageNode(
     Resources resources = node.getThemedContext().getResources();
     int height = (int) PixelUtil.toDIPFromPixel(node.getStyleHeight());
     int width = (int) PixelUtil.toDIPFromPixel(node.getStyleWidth());
-    TextInlineImageSpan imageSpan =
-        new TextInlineImageSpan(resources, height, width, node.getUri());
+    TextInlineImageSpan imageSpan = new TextInlineImageSpan(
+        resources,
+        height,
+        width,
+        node.getUri(),
+        node.getDraweeControllerBuilder(),
+        node.getCallerContext());
     // We make the image take up 1 character in the span and put a corresponding character into the
     // text so that the image doesn't run over any following text.
     sb.append(INLINE_IMAGE_PLACEHOLDER);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextInlineImageSpan.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextInlineImageSpan.java
index e0a124109109..6079ce00b552 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextInlineImageSpan.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextInlineImageSpan.java
@@ -21,6 +21,7 @@
 import android.widget.TextView;
 
 import com.facebook.drawee.backends.pipeline.Fresco;
+import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
 import com.facebook.drawee.generic.GenericDraweeHierarchy;
 import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
 import com.facebook.drawee.interfaces.DraweeController;
@@ -42,7 +43,9 @@
 public class TextInlineImageSpan extends ReplacementSpan {
 
   private @Nullable Drawable mDrawable;
-  private DraweeHolder<GenericDraweeHierarchy> mDraweeHolder;
+  private final AbstractDraweeControllerBuilder mDraweeControllerBuilder;
+  private final DraweeHolder<GenericDraweeHierarchy> mDraweeHolder;
+  private final @Nullable Object mCallerContext;
 
   private int mHeight;
   private Uri mUri;
@@ -50,11 +53,19 @@ public class TextInlineImageSpan extends ReplacementSpan {
 
   private @Nullable TextView mTextView;
 
-  public TextInlineImageSpan(Resources resources, int height, int width, @Nullable Uri uri) {
+  public TextInlineImageSpan(
+      Resources resources,
+      int height,
+      int width,
+      @Nullable Uri uri,
+      AbstractDraweeControllerBuilder draweeControllerBuilder,
+      @Nullable Object callerContext) {
     mDraweeHolder = new DraweeHolder(
         GenericDraweeHierarchyBuilder.newInstance(resources)
             .build()
     );
+    mDraweeControllerBuilder = draweeControllerBuilder;
+    mCallerContext = callerContext;
 
     mHeight = height;
     mWidth = width;
@@ -116,8 +127,10 @@ public void draw(
       ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(mUri)
           .build();
 
-      DraweeController draweeController = Fresco.newDraweeControllerBuilder()
+      DraweeController draweeController = mDraweeControllerBuilder
+          .reset()
           .setOldController(mDraweeHolder.getController())
+          .setCallerContext(mCallerContext)
           .setImageRequest(imageRequest)
           .build();
       mDraweeHolder.setController(draweeController);

From 55f72c4c8f343f587a4ab522707e8805fdbe52ca Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Tue, 24 Nov 2015 16:55:29 +0000
Subject: [PATCH 0082/1411] Update question-bookmarklet.js

---
 bots/question-bookmarklet.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bots/question-bookmarklet.js b/bots/question-bookmarklet.js
index f8d0ce52e96d..9fa4885de85c 100644
--- a/bots/question-bookmarklet.js
+++ b/bots/question-bookmarklet.js
@@ -1 +1 @@
-javascript:(function(){$('#new_comment_field')[0].value='Hey and thanks for reporting this!\n\nThis issue looks like a question - please use [Stack Overflow](http://stackoverflow.com/questions/tagged/react-native) for questions. It\'s the best system for Q&A and the best way to get questions answered.\n\nMany people from the community hang out on Stack Overflow and will be able to see your question and be more likely to answer because of the reputation system. If after reading this you think your question is better suited for Stack Overflow, please consider closing this issue.';$('button.btn-primary:contains("Comment")').click()})()
\ No newline at end of file
+javascript:(function(){$('#new_comment_field')[0].value='Hey and thanks for reporting this!\n\nThere\'s an awesome place to ask question like this one: [StackOverflow](http://stackoverflow.com/questions/tagged/react-native). It\'s the best system for Q&A. Many people from the community hang out there and will be able to see your question, you can vote on answers and mark question as answered etc. This lets us keep a list of bug reports and feature requests on github and especially [Product Pains](https://productpains.com/product/react-native/?tab=top) (again, with voting which is really nice).\n\nIf you think StackOverflow works for you please consider posting there instead and closing this issue.\n\nI\'m posting this here because github issues haven\'t been working very well for us and because StackOverflow is so much better. Thanks for reading! :)';$('button.btn-primary:contains("Comment")').click()})()

From ffea7793aff0961ebc22007d650ce36f7c2e61cb Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Tue, 24 Nov 2015 09:14:44 -0800
Subject: [PATCH 0083/1411] Add babel helpers necessary for es2015 imports

Summary: public

Adding the babel helpers that are necessary to support ES2015 imports.

Fixes: https://gist.github.com/ehd/49cb2465df9da6b39710

Reviewed By: mkonicek

Differential Revision: D2690772

fb-gh-sync-id: b1b6c0c048bad809a5c58cdd0a2cbeaa11c72ea7
---
 .../src/Resolver/polyfills/babelHelpers.js    | 27 ++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/packager/react-packager/src/Resolver/polyfills/babelHelpers.js b/packager/react-packager/src/Resolver/polyfills/babelHelpers.js
index b1254a688e6a..a7fac6bcd6ab 100644
--- a/packager/react-packager/src/Resolver/polyfills/babelHelpers.js
+++ b/packager/react-packager/src/Resolver/polyfills/babelHelpers.js
@@ -11,8 +11,10 @@
 /* eslint-disable strict */
 
 // Created by running:
-// require('babel-core').buildExternalHelpers('_extends classCallCheck createClass createRawReactElement defineProperty get inherits objectWithoutProperties possibleConstructorReturn slicedToArray toConsumableArray'.split(' '))
+// require('babel-core').buildExternalHelpers('_extends classCallCheck createClass createRawReactElement defineProperty get inherits  interopRequireDefault interopRequireWildcard objectWithoutProperties possibleConstructorReturn slicedToArray toConsumableArray'.split(' '))
 // then replacing the `global` reference in the last line to also use `this`.
+//
+// actually, that's a lie, because babel6 omits _extends and createRawReactElement
 
 (function (global) {
   var babelHelpers = global.babelHelpers = {};
@@ -125,6 +127,29 @@
     if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
   };
 
+  babelHelpers.interopRequireDefault = function (obj) {
+    return obj && obj.__esModule ? obj : {
+      default: obj
+    };
+  };
+
+  babelHelpers.interopRequireWildcard = function (obj) {
+    if (obj && obj.__esModule) {
+      return obj;
+    } else {
+      var newObj = {};
+
+      if (obj != null) {
+        for (var key in obj) {
+          if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key];
+        }
+      }
+
+      newObj.default = obj;
+      return newObj;
+    }
+  };
+
   babelHelpers.objectWithoutProperties = function (obj, keys) {
     var target = {};
 

From e55d70789c457be9cf42043f312a9918380fa3b4 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Tue, 24 Nov 2015 17:19:46 +0000
Subject: [PATCH 0084/1411] Update breaking-changes.md

---
 breaking-changes.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/breaking-changes.md b/breaking-changes.md
index 3501907b85d8..b4448fb2aca8 100644
--- a/breaking-changes.md
+++ b/breaking-changes.md
@@ -5,6 +5,7 @@
 - Touch events on Android now have coordinates consistent with iOS: [0c2ee5](https://github.com/facebook/react-native/commit/0c2ee5d480e696f8621252c936a8773e8de9f8b6)
 - YellowBox enabled by default: [8ab518](https://github.com/facebook/react-native/commit/8ab51828ff077ae0ad10c06f62f9f01d58b9bf85)
 - React Native now uses Babel 6 (props to tadeuzagallo for upgrading!). We've been using React Native with Babel 6 at Facebook for quite a while now. Nevertheless, please report any errors related to Babel, such as transforms for some JS features not working as expected and we'll fix them.
+- Decorators won't work until [T2645](https://phabricator.babeljs.io/T2645) lands in Babel.
 
 ## 0.15
 

From 37f81341a006458d84d934882485c2a0a8838497 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Tue, 24 Nov 2015 08:50:39 -0800
Subject: [PATCH 0085/1411] Open source SwipeRefreshLayoutAndroid

Reviewed By: mkonicek

Differential Revision: D2679605

fb-gh-sync-id: 7f3e7384b37f29002ddd8cb7a4567fa96c76f047
---
 ...llToRefreshLayoutAndroidExample.android.js | 127 ++++++++++++++++++
 Examples/UIExplorer/UIExplorerList.android.js |   1 +
 .../PullToRefreshLayoutAndroid.android.js     |  87 ++++++++++++
 .../PullToRefreshLayoutAndroid.ios.js         |  13 ++
 Libraries/react-native/react-native.js        |   1 +
 .../react/shell/MainReactPackage.java         |   4 +-
 .../swiperefresh/ReactSwipeRefreshLayout.java |  35 +++++
 .../views/swiperefresh/RefreshEvent.java      |  30 +++++
 .../SwipeRefreshLayoutManager.java            | 106 +++++++++++++++
 9 files changed, 403 insertions(+), 1 deletion(-)
 create mode 100644 Examples/UIExplorer/PullToRefreshLayoutAndroidExample.android.js
 create mode 100644 Libraries/PullToRefresh/PullToRefreshLayoutAndroid.android.js
 create mode 100644 Libraries/PullToRefresh/PullToRefreshLayoutAndroid.ios.js
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/ReactSwipeRefreshLayout.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/RefreshEvent.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/SwipeRefreshLayoutManager.java

diff --git a/Examples/UIExplorer/PullToRefreshLayoutAndroidExample.android.js b/Examples/UIExplorer/PullToRefreshLayoutAndroidExample.android.js
new file mode 100644
index 000000000000..06a39c7ccd86
--- /dev/null
+++ b/Examples/UIExplorer/PullToRefreshLayoutAndroidExample.android.js
@@ -0,0 +1,127 @@
+/**
+* The examples provided by Facebook are for non-commercial testing and
+* evaluation purposes only.
+*
+* Facebook reserves all rights not expressly granted.
+*
+* 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 NON INFRINGEMENT. IN NO EVENT SHALL
+* FACEBOOK 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.
+*
+*/
+'use strict';
+
+const React = require('react-native');
+const {
+  ScrollView,
+  StyleSheet,
+  PullToRefreshLayoutAndroid,
+  Text,
+  TouchableWithoutFeedback,
+  View,
+} = React;
+
+const styles = StyleSheet.create({
+  row: {
+    borderColor: 'grey',
+    borderWidth: 1,
+    padding: 20,
+    backgroundColor: '#3a5795',
+    margin: 5,
+  },
+  text: {
+    alignSelf: 'center',
+    color: '#fff',
+
+  },
+  layout: {
+    flex: 1,
+  },
+  scrollview: {
+    flex: 1,
+  },
+});
+
+const Row = React.createClass({
+  _onClick: function() {
+    this.props.onClick(this.props.data);
+  },
+  render: function() {
+    return (
+     <TouchableWithoutFeedback onPress={this._onClick} >
+        <View style={styles.row}>
+          <Text style={styles.text}>
+            {this.props.data.text + ' (' + this.props.data.clicks + ' clicks)'}
+          </Text>
+        </View>
+    </TouchableWithoutFeedback>
+    );
+  },
+});
+const PullToRefreshLayoutAndroidExample = React.createClass({
+  statics: {
+    title: '<PullToRefreshLayoutAndroid>',
+    description: 'Container that adds pull-to-refresh support to its child view.'
+  },
+
+  getInitialState() {
+    return {
+      isRefreshing: false,
+      loaded: 0,
+      rowData: Array.from(new Array(20)).map(
+        (val, i) => {return {text: 'Initial row' + i, clicks: 0}}),
+    };
+  },
+
+  _onClick(row) {
+    row.clicks++;
+    this.setState({
+      rowData: this.state.rowData,
+    });
+  },
+
+  render() {
+    const rows = this.state.rowData.map((row) => {
+      return <Row data={row} onClick={this._onClick}/>;
+    });
+    return (
+      <PullToRefreshLayoutAndroid
+        style={styles.layout}
+        refreshing={this.state.isRefreshing}
+        onRefresh={this._onRefresh}
+        colors={['#ff0000', '#00ff00', '#0000ff']}
+        progressBackgroundColor={'#ffff00'}
+        >
+        <ScrollView style={styles.scrollview}>
+          {rows}
+        </ScrollView>
+      </PullToRefreshLayoutAndroid>
+    );
+  },
+
+  _onRefresh() {
+    this.setState({isRefreshing: true});
+    setTimeout(() => {
+      // prepend 10 items
+      const rowData = Array.from(new Array(10))
+      .map((val, i) => {return {
+        text: 'Loaded row' + (+this.state.loaded + i),
+        clicks: 0,
+      }})
+      .concat(this.state.rowData);
+
+      this.setState({
+        loaded: this.state.loaded + 10,
+        isRefreshing: false,
+        rowData: rowData,
+      });
+    }, 5000);
+  },
+
+});
+
+
+module.exports = PullToRefreshLayoutAndroidExample;
diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index 5a370a01ce06..7d57332c2318 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -27,6 +27,7 @@ var COMPONENTS = [
   require('./ProgressBarAndroidExample'),
   require('./ScrollViewSimpleExample'),
   require('./SwitchAndroidExample'),
+  require('./PullToRefreshLayoutAndroidExample.android'),
   require('./TextExample.android'),
   require('./TextInputExample.android'),
   require('./ToolbarAndroidExample'),
diff --git a/Libraries/PullToRefresh/PullToRefreshLayoutAndroid.android.js b/Libraries/PullToRefresh/PullToRefreshLayoutAndroid.android.js
new file mode 100644
index 000000000000..a1d69c353e8d
--- /dev/null
+++ b/Libraries/PullToRefresh/PullToRefreshLayoutAndroid.android.js
@@ -0,0 +1,87 @@
+/**
+ * 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 PullToRefreshLayoutAndroid
+ */
+'use strict';
+
+var React = require('React');
+var RefreshLayoutConsts = require('NativeModules').UIManager.AndroidSwipeRefreshLayout.Constants;
+var View = require('View');
+
+var onlyChild = require('onlyChild');
+var processColor = require('processColor');
+var requireNativeComponent = require('requireNativeComponent');
+
+var NATIVE_REF = 'native_swiperefreshlayout';
+
+/**
+ * React view that supports a single scrollable child view (e.g. `ScrollView`). When this child
+ * view is at `scrollY: 0`, swiping down triggers an `onRefresh` event.
+ */
+var PullToRefreshLayoutAndroid = React.createClass({
+  statics: {
+    SIZE: RefreshLayoutConsts.SIZE,
+  },
+
+  propTypes: {
+    ...View.propTypes,
+    /**
+     * Whether the pull to refresh functionality is enabled
+     */
+    enabled: React.PropTypes.bool,
+    /**
+     * The colors (at least one) that will be used to draw the refresh indicator
+     */
+    colors: React.PropTypes.arrayOf(React.PropTypes.string),
+    /**
+     * The background color of the refresh indicator
+     */
+    progressBackgroundColor: React.PropTypes.string,
+    /**
+     * Whether the view should be indicating an active refresh
+     */
+    refreshing: React.PropTypes.bool,
+    /**
+     * Size of the refresh indicator, see PullToRefreshLayoutAndroid.SIZE
+     */
+    size: React.PropTypes.oneOf(RefreshLayoutConsts.SIZE.DEFAULT, RefreshLayoutConsts.SIZE.LARGE),
+  },
+
+  getInnerViewNode: function() {
+    return this.refs[NATIVE_REF];
+  },
+
+  render: function() {
+    return (
+      <NativePullToRefresh
+        colors={this.props.colors && this.props.colors.map(processColor)}
+        enabled={this.props.enabled}
+        onRefresh={this._onRefresh}
+        progressBackgroundColor={this.props.progressBackgroundColor}
+        ref={NATIVE_REF}
+        refreshing={this.props.refreshing}
+        size={this.props.size}
+        style={this.props.style}>
+        {onlyChild(this.props.children)}
+      </NativePullToRefresh>
+    );
+  },
+
+  _onRefresh: function() {
+    this.props.onRefresh && this.props.onRefresh();
+    this.refs[NATIVE_REF].setNativeProps({refreshing: !!this.props.refreshing});
+  }
+});
+
+var NativePullToRefresh = requireNativeComponent(
+  'AndroidSwipeRefreshLayout',
+  PullToRefreshLayoutAndroid
+);
+
+module.exports = PullToRefreshLayoutAndroid;
diff --git a/Libraries/PullToRefresh/PullToRefreshLayoutAndroid.ios.js b/Libraries/PullToRefresh/PullToRefreshLayoutAndroid.ios.js
new file mode 100644
index 000000000000..eea4dbae7695
--- /dev/null
+++ b/Libraries/PullToRefresh/PullToRefreshLayoutAndroid.ios.js
@@ -0,0 +1,13 @@
+/**
+ * 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 PullToRefreshLayoutAndroid
+ */
+ 'use strict';
+
+ module.exports = require('UnimplementedView');
diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js
index 206b5f785f9f..29ff95205868 100644
--- a/Libraries/react-native/react-native.js
+++ b/Libraries/react-native/react-native.js
@@ -37,6 +37,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
   SliderIOS: require('SliderIOS'),
   SnapshotViewIOS: require('SnapshotViewIOS'),
   Switch: require('Switch'),
+  PullToRefreshLayoutAndroid: require('PullToRefreshLayoutAndroid'),
   SwitchAndroid: require('SwitchAndroid'),
   SwitchIOS: require('SwitchIOS'),
   TabBarIOS: require('TabBarIOS'),
diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
index 115c33ea63f6..a0e90db20613 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
@@ -39,6 +39,7 @@
 import com.facebook.react.views.toolbar.ReactToolbarManager;
 import com.facebook.react.views.view.ReactViewManager;
 import com.facebook.react.views.viewpager.ReactViewPagerManager;
+import com.facebook.react.views.swiperefresh.SwipeRefreshLayoutManager;
 
 /**
  * Package defining basic modules and view managers.
@@ -78,6 +79,7 @@ public List<ViewManager> createViewManagers(ReactApplicationContext reactContext
       new ReactViewManager(),
       new ReactViewPagerManager(),
       new ReactTextInlineImageViewManager(),
-      new ReactVirtualTextViewManager());
+      new ReactVirtualTextViewManager(),
+      new SwipeRefreshLayoutManager());
   }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/ReactSwipeRefreshLayout.java b/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/ReactSwipeRefreshLayout.java
new file mode 100644
index 000000000000..f458c0ab06b9
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/ReactSwipeRefreshLayout.java
@@ -0,0 +1,35 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.swiperefresh;
+
+import android.support.v4.widget.SwipeRefreshLayout;
+import android.view.MotionEvent;
+
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.uimanager.events.NativeGestureUtil;
+
+/**
+ * Basic extension of {@link SwipeRefreshLayout} with ReactNative-specific functionality.
+ */
+public class ReactSwipeRefreshLayout extends SwipeRefreshLayout {
+
+  public ReactSwipeRefreshLayout(ReactContext reactContext) {
+    super(reactContext);
+  }
+
+  @Override
+  public boolean onInterceptTouchEvent(MotionEvent ev) {
+    if (super.onInterceptTouchEvent(ev)) {
+      NativeGestureUtil.notifyNativeGestureStarted(this, ev);
+      return true;
+    }
+    return false;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/RefreshEvent.java b/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/RefreshEvent.java
new file mode 100644
index 000000000000..d8325d2bce49
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/RefreshEvent.java
@@ -0,0 +1,30 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.swiperefresh;
+
+import com.facebook.react.uimanager.events.Event;
+import com.facebook.react.uimanager.events.RCTEventEmitter;
+
+public class RefreshEvent extends Event<RefreshEvent> {
+
+    protected RefreshEvent(int viewTag, long timestampMs) {
+        super(viewTag, timestampMs);
+    }
+
+    @Override
+    public String getEventName() {
+        return "topRefresh";
+    }
+
+    @Override
+    public void dispatch(RCTEventEmitter rctEventEmitter) {
+        rctEventEmitter.receiveEvent(getViewTag(), getEventName(), null);
+    }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/SwipeRefreshLayoutManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/SwipeRefreshLayoutManager.java
new file mode 100644
index 000000000000..1520dc1f987c
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/SwipeRefreshLayoutManager.java
@@ -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.
+ */
+
+package com.facebook.react.views.swiperefresh;
+
+import javax.annotation.Nullable;
+
+import java.util.Map;
+
+import android.graphics.Color;
+import android.os.SystemClock;
+import android.support.v4.widget.SwipeRefreshLayout;
+import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener;
+
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.common.MapBuilder;
+import com.facebook.react.uimanager.ReactProp;
+import com.facebook.react.uimanager.ThemedReactContext;
+import com.facebook.react.uimanager.UIManagerModule;
+import com.facebook.react.uimanager.ViewGroupManager;
+import com.facebook.react.uimanager.ViewProps;
+
+/**
+ * ViewManager for {@link ReactSwipeRefreshLayout} which allows the user to "pull to refresh" a
+ * child view. Emits an {@code onRefresh} event when this happens.
+ */
+public class SwipeRefreshLayoutManager extends ViewGroupManager<ReactSwipeRefreshLayout> {
+
+  @Override
+  protected ReactSwipeRefreshLayout createViewInstance(ThemedReactContext reactContext) {
+    return new ReactSwipeRefreshLayout(reactContext);
+  }
+
+  @Override
+  public String getName() {
+    return "AndroidSwipeRefreshLayout";
+  }
+
+  @ReactProp(name = ViewProps.ENABLED, defaultBoolean = true)
+  public void setEnabled(ReactSwipeRefreshLayout view, boolean enabled) {
+    view.setEnabled(enabled);
+  }
+
+  @ReactProp(name = "colors")
+  public void setColors(ReactSwipeRefreshLayout view, @Nullable ReadableArray colors) {
+    if (colors != null) {
+      int[] colorValues = new int[colors.size()];
+      for (int i = 0; i < colors.size(); i++) {
+        colorValues[i] = colors.getInt(i);
+      }
+      view.setColorSchemeColors(colorValues);
+    } else {
+      view.setColorSchemeColors();
+    }
+  }
+
+  @ReactProp(name = "progressBackgroundColor", defaultInt = Color.TRANSPARENT, customType = "Color")
+  public void setProgressBackgroundColor(ReactSwipeRefreshLayout view, int color) {
+    view.setProgressBackgroundColorSchemeColor(color);
+  }
+
+  @ReactProp(name = "size", defaultInt = SwipeRefreshLayout.DEFAULT)
+  public void setSize(ReactSwipeRefreshLayout view, int size) {
+    view.setSize(size);
+  }
+
+  @ReactProp(name = "refreshing")
+  public void setRefreshing(ReactSwipeRefreshLayout view, boolean refreshing) {
+    view.setRefreshing(refreshing);
+  }
+
+  @Override
+  protected void addEventEmitters(
+      final ThemedReactContext reactContext,
+      final ReactSwipeRefreshLayout view) {
+    view.setOnRefreshListener(
+        new OnRefreshListener() {
+          @Override
+          public void onRefresh() {
+            reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher()
+                .dispatchEvent(new RefreshEvent(view.getId(), SystemClock.uptimeMillis()));
+          }
+        });
+  }
+
+  @Nullable
+  @Override
+  public Map<String, Object> getExportedViewConstants() {
+    return MapBuilder.<String, Object>of(
+        "SIZE",
+        MapBuilder.of("DEFAULT", SwipeRefreshLayout.DEFAULT, "LARGE", SwipeRefreshLayout.LARGE));
+  }
+
+  @Override
+  public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
+    return MapBuilder.<String, Object>builder()
+        .put("topRefresh", MapBuilder.of("registrationName", "onRefresh"))
+        .build();
+  }
+}

From b4beba521779ef5bb4a9ef26987db7c3f34587b7 Mon Sep 17 00:00:00 2001
From: Alexey Lang <alexeylang@fb.com>
Date: Tue, 24 Nov 2015 10:18:07 -0800
Subject: [PATCH 0086/1411] Fix logging JSAppRequireTime

Reviewed By: andreicoman11

Differential Revision: D2690760

fb-gh-sync-id: 41e88c48deec05539e7681862d794ed650b81bfa
---
 Libraries/Utilities/PerformanceLogger.js | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/Libraries/Utilities/PerformanceLogger.js b/Libraries/Utilities/PerformanceLogger.js
index 75d8478bc350..daafe46a5663 100644
--- a/Libraries/Utilities/PerformanceLogger.js
+++ b/Libraries/Utilities/PerformanceLogger.js
@@ -65,6 +65,15 @@ var PerformanceLogger = {
       }
       return;
     }
+    if (timespans[key].endTime) {
+      if (__DEV__) {
+        console.log(
+          'PerformanceLogger: Attempting to end a timespan that has already ended ',
+          key
+        );
+      }
+      return;
+    }
 
     timespans[key].endTime = performanceNow();
     timespans[key].totalTime =

From 9d333e6411e63afaa6c5129dece62b458268c492 Mon Sep 17 00:00:00 2001
From: James Ide <ide+github@jameside.com>
Date: Tue, 24 Nov 2015 10:29:40 -0800
Subject: [PATCH 0087/1411] Update NewIssueGreeting.md

---
 bots/NewIssueGreeting.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bots/NewIssueGreeting.md b/bots/NewIssueGreeting.md
index 6e3fe153cf26..87e421b499eb 100644
--- a/bots/NewIssueGreeting.md
+++ b/bots/NewIssueGreeting.md
@@ -6,4 +6,4 @@ React Native, as you've probably heard, is getting really popular and truth is w
 
 - If you don't know how to do something or not sure whether some behavior is expected or a bug, please ask on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native) with the tag `react-native` or for more real time interactions, ask on [Discord](https://discord.gg/0ZcbPKXt5bZjGY5n) in the #react-native channel.
 
-- We welcome well-written issues and PRs that are ready for in-depth discussion; thank you for your contributions!
+- We welcome clear issues and PRs that are ready for in-depth discussion; thank you for your contributions!

From 3a00545bc77c74d4fd49584e262326d3dffabb2f Mon Sep 17 00:00:00 2001
From: Alexander Blom <blom@fb.com>
Date: Tue, 24 Nov 2015 09:46:45 -0800
Subject: [PATCH 0088/1411] Remove cookie handler on destroy

Reviewed By: andreicoman11, astreet

Differential Revision: D2690634

fb-gh-sync-id: a2ab8ce52dd501eed88f166b4c218886ea229744
---
 .../react/modules/fresco/FrescoModule.java    |  3 +--
 .../modules/network/NetworkingModule.java     | 23 ++++++++++---------
 .../modules/network/OkHttpClientProvider.java | 11 ---------
 3 files changed, 13 insertions(+), 24 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java
index 8a980cb46e18..14b95c0aebdc 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java
@@ -80,8 +80,7 @@ public void loadLibrary(String libraryName) {
     }
 
     Context context = this.getReactApplicationContext().getApplicationContext();
-    OkHttpClient okHttpClient =
-        OkHttpClientProvider.getCookieAwareOkHttpClient(getReactApplicationContext());
+    OkHttpClient okHttpClient = OkHttpClientProvider.getOkHttpClient();
     ImagePipelineConfig.Builder builder =
         OkHttpImagePipelineConfigFactory.newBuilder(context, okHttpClient);
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
index db316e3710e3..1156aa2fd195 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
@@ -14,7 +14,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Reader;
-import java.net.CookieHandler;
 
 import com.facebook.react.bridge.Arguments;
 import com.facebook.react.bridge.GuardedAsyncTask;
@@ -58,6 +57,7 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
   private static final int CHUNK_TIMEOUT_NS = 100 * 1000000; // 100ms
 
   private final OkHttpClient mClient;
+  private final ForwardingCookieHandler mCookieHandler;
   private final @Nullable String mDefaultUserAgent;
   private boolean mShuttingDown;
 
@@ -68,6 +68,7 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
     super(reactContext);
     mClient = client;
     mClient.networkInterceptors().add(new StethoInterceptor());
+    mCookieHandler = new ForwardingCookieHandler(reactContext);
     mShuttingDown = false;
     mDefaultUserAgent = defaultUserAgent;
   }
@@ -76,7 +77,7 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
    * @param context the ReactContext of the application
    */
   public NetworkingModule(final ReactApplicationContext context) {
-    this(context, null, OkHttpClientProvider.getCookieAwareOkHttpClient(context));
+    this(context, null, OkHttpClientProvider.getOkHttpClient());
   }
 
   /**
@@ -85,13 +86,18 @@ public NetworkingModule(final ReactApplicationContext context) {
    * caller does not provide one explicitly
    */
   public NetworkingModule(ReactApplicationContext context, String defaultUserAgent) {
-    this(context, defaultUserAgent, OkHttpClientProvider.getCookieAwareOkHttpClient(context));
+    this(context, defaultUserAgent, OkHttpClientProvider.getOkHttpClient());
   }
 
   public NetworkingModule(ReactApplicationContext reactContext, OkHttpClient client) {
     this(reactContext, null, client);
   }
 
+  @Override
+  public void initialize() {
+    mClient.setCookieHandler(mCookieHandler);
+  }
+
   @Override
   public String getName() {
     return "RCTNetworking";
@@ -102,10 +108,8 @@ public void onCatalystInstanceDestroy() {
     mShuttingDown = true;
     mClient.cancel(null);
 
-    CookieHandler cookieHandler = mClient.getCookieHandler();
-    if (cookieHandler instanceof ForwardingCookieHandler) {
-      ((ForwardingCookieHandler) cookieHandler).destroy();
-    }
+    mCookieHandler.destroy();
+    mClient.setCookieHandler(null);
   }
 
   @ReactMethod
@@ -319,10 +323,7 @@ protected void doInBackgroundGuarded(Void... params) {
 
   @ReactMethod
   public void clearCookies(com.facebook.react.bridge.Callback callback) {
-    CookieHandler cookieHandler = mClient.getCookieHandler();
-    if (cookieHandler instanceof ForwardingCookieHandler) {
-      ((ForwardingCookieHandler) cookieHandler).clearCookies(callback);
-    }
+    mCookieHandler.clearCookies(callback);
   }
 
   private @Nullable MultipartBuilder constructMultipartBody(
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/OkHttpClientProvider.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/OkHttpClientProvider.java
index 699ffa5255c4..c9c1b733a6d9 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/OkHttpClientProvider.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/OkHttpClientProvider.java
@@ -13,8 +13,6 @@
 
 import java.util.concurrent.TimeUnit;
 
-import com.facebook.react.bridge.ReactContext;
-
 import com.squareup.okhttp.OkHttpClient;
 
 /**
@@ -25,7 +23,6 @@ public class OkHttpClientProvider {
 
   // Centralized OkHttpClient for all networking requests.
   private static @Nullable OkHttpClient sClient;
-  private static ForwardingCookieHandler sCookieHandler;
 
   public static OkHttpClient getOkHttpClient() {
     if (sClient == null) {
@@ -34,14 +31,6 @@ public static OkHttpClient getOkHttpClient() {
     return sClient;
   }
 
-  public static OkHttpClient getCookieAwareOkHttpClient(ReactContext context) {
-    if (sCookieHandler == null) {
-      sCookieHandler = new ForwardingCookieHandler(context);
-      getOkHttpClient().setCookieHandler(sCookieHandler);
-    }
-    return getOkHttpClient();
-  }
-
   private static OkHttpClient createClient() {
     // TODO: #7108751 plug in stetho
     OkHttpClient client = new OkHttpClient();

From 5387df8dc569c3dfbb5ba4d66b88f70c5ec22d50 Mon Sep 17 00:00:00 2001
From: Alexander Blom <blom@fb.com>
Date: Tue, 24 Nov 2015 09:46:58 -0800
Subject: [PATCH 0089/1411] Make ReactDatabaseSupplier use application context

Summary: public
We pass in a `ReactContext` but we really only need a context. Make sure we're using the application one.

Reviewed By: astreet

Differential Revision: D2690692

fb-gh-sync-id: 857d6571c9c01d35e12f09be4c8733cca007306f
---
 .../react/modules/storage/ReactDatabaseSupplier.java  | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/storage/ReactDatabaseSupplier.java b/ReactAndroid/src/main/java/com/facebook/react/modules/storage/ReactDatabaseSupplier.java
index ef27b332ff3e..620d231461d9 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/storage/ReactDatabaseSupplier.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/storage/ReactDatabaseSupplier.java
@@ -42,9 +42,10 @@ public class ReactDatabaseSupplier extends SQLiteOpenHelper {
           VALUE_COLUMN + " TEXT NOT NULL" +
           ")";
 
+  private static @Nullable ReactDatabaseSupplier sReactDatabaseSupplierInstance;
+
   private Context mContext;
   private @Nullable SQLiteDatabase mDb;
-  private static @Nullable ReactDatabaseSupplier mReactDatabaseSupplierInstance;
 
   private ReactDatabaseSupplier(Context context) {
     super(context, DATABASE_NAME, null, DATABASE_VERSION);
@@ -52,10 +53,10 @@ private ReactDatabaseSupplier(Context context) {
   }
 
   public static ReactDatabaseSupplier getInstance(Context context) {
-    if (mReactDatabaseSupplierInstance == null) {
-      mReactDatabaseSupplierInstance = new ReactDatabaseSupplier(context);
+    if (sReactDatabaseSupplierInstance == null) {
+      sReactDatabaseSupplierInstance = new ReactDatabaseSupplier(context.getApplicationContext());
     }
-    return mReactDatabaseSupplierInstance;
+    return sReactDatabaseSupplierInstance;
   }
 
   @Override
@@ -150,6 +151,6 @@ private synchronized void closeDatabase() {
 
   // For testing purposes only!
   public static void deleteInstance() {
-    mReactDatabaseSupplierInstance = null;
+    sReactDatabaseSupplierInstance = null;
   }
 }

From 69c8dd50fe37b78207b49356d936a547b07685ce Mon Sep 17 00:00:00 2001
From: Alexander Blom <blom@fb.com>
Date: Tue, 24 Nov 2015 09:47:26 -0800
Subject: [PATCH 0090/1411] Avoid leaking FrescoModule when setting
 SoLoaderShim handler

Summary: The anonymous class had an implicit reference back to FrescoModule that would in turn retain the context.

public

Reviewed By: astreet

Differential Revision: D2690747

fb-gh-sync-id: 8a97c102e461b903c6adf7c65956baf364fa5faf
---
 .../react/modules/fresco/FrescoModule.java        | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java
index 14b95c0aebdc..666acc2fe159 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java
@@ -65,13 +65,7 @@ public void initialize() {
     super.initialize();
     // Make sure the SoLoaderShim is configured to use our loader for native libraries.
     // This code can be removed if using Fresco from Maven rather than from source
-    SoLoaderShim.setHandler(
-        new SoLoaderShim.Handler() {
-          @Override
-          public void loadLibrary(String libraryName) {
-            SoLoader.loadLibrary(libraryName);
-          }
-        });
+    SoLoaderShim.setHandler(new FrescoHandler());
 
     HashSet<RequestListener> requestListeners = new HashSet<>();
     requestListeners.add(new SystraceRequestListener());
@@ -110,4 +104,11 @@ public void clearSensitiveData() {
     imagePipelineFactory.getMainDiskStorageCache().clearAll();
     imagePipelineFactory.getSmallImageDiskStorageCache().clearAll();
   }
+
+  private static class FrescoHandler implements SoLoaderShim.Handler {
+    @Override
+    public void loadLibrary(String libraryName) {
+      SoLoader.loadLibrary(libraryName);
+    }
+  }
 }

From 2b22d22a8384a800043bc0141b3a36eaa59c0716 Mon Sep 17 00:00:00 2001
From: Alexander Blom <blom@fb.com>
Date: Tue, 24 Nov 2015 09:47:39 -0800
Subject: [PATCH 0091/1411] Clear static arg arrays after use

Reviewed By: astreet

Differential Revision: D2690812

fb-gh-sync-id: b00291c57e294eece5772531e9f16e0c60b8b8f4
---
 .../facebook/react/uimanager/ViewManagersPropertyCache.java  | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagersPropertyCache.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagersPropertyCache.java
index c34430cc6480..fd0ce6c41e49 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagersPropertyCache.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagersPropertyCache.java
@@ -5,6 +5,7 @@
 import javax.annotation.Nullable;
 
 import java.lang.reflect.Method;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -72,11 +73,13 @@ public void updateViewProp(
           VIEW_MGR_ARGS[0] = viewToUpdate;
           VIEW_MGR_ARGS[1] = extractProperty(props);
           mSetter.invoke(viewManager, VIEW_MGR_ARGS);
+          Arrays.fill(VIEW_MGR_ARGS, null);
         } else {
           VIEW_MGR_GROUP_ARGS[0] = viewToUpdate;
           VIEW_MGR_GROUP_ARGS[1] = mIndex;
           VIEW_MGR_GROUP_ARGS[2] = extractProperty(props);
           mSetter.invoke(viewManager, VIEW_MGR_GROUP_ARGS);
+          Arrays.fill(VIEW_MGR_GROUP_ARGS, null);
         }
       } catch (Throwable t) {
         FLog.e(ViewManager.class, "Error while updating prop " + mPropName, t);
@@ -92,10 +95,12 @@ public void updateShadowNodeProp(
         if (mIndex == null) {
           SHADOW_ARGS[0] = extractProperty(props);
           mSetter.invoke(nodeToUpdate, SHADOW_ARGS);
+          Arrays.fill(SHADOW_ARGS, null);
         } else {
           SHADOW_GROUP_ARGS[0] = mIndex;
           SHADOW_GROUP_ARGS[1] = extractProperty(props);
           mSetter.invoke(nodeToUpdate, SHADOW_GROUP_ARGS);
+          Arrays.fill(SHADOW_GROUP_ARGS, null);
         }
       } catch (Throwable t) {
         FLog.e(ViewManager.class, "Error while updating prop " + mPropName, t);

From b86f14738ee8bcb925ad447e0daf58d7ee95f5bb Mon Sep 17 00:00:00 2001
From: Mark Vayngrib <mark.vayngrib@lablz.com>
Date: Tue, 24 Nov 2015 11:03:57 -0800
Subject: [PATCH 0092/1411] support react-native field with fallback to browser
 field

Summary: React Native is a lot more powerful an environment than the browser, so we need an alternate mapping, as specified [here](https://github.com/defunctzombie/node-browser-resolve#browser-field)

An example:
```js
{
  "browser": {
     "./lib/server": false
   },
   "react-native": {
     "dgram": "react-native-udp",
     "fs": "react-native-level-fs"
   },
   "chromeapp": {
     "dgram": "chrome-dgram",
     "fs": "level-filesystem"
   }
}
```

on the other hand, if "react-native" is not present in package.json, you should fall back to "browser"

other than the one (nesting) test added, the tests are unchanged, just done for both "react-native" and "browser"

(I've implemented [react-native-udp](https://npmjs.org/package/react-native-udp) and [react-native-level-fs](https://npmjs.org/package/react-native-level-fs), but they obviously don't belong in the traditional "browser" field as they won't run anywhere except in React Native.)
Closes https://github.com/facebook/react-native/pull/2208

Reviewed By: svcscm

Differential Revision: D2691236

Pulled By: vjeux

fb-gh-sync-id: 34041ed50bda4ec07f31d1dc50dcdfa428af2512
---
 .../__tests__/DependencyGraph-test.js         | 818 +++++++++++-------
 .../src/DependencyResolver/Package.js         |  33 +-
 2 files changed, 519 insertions(+), 332 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
index b8caec76a19b..a89ce97aa064 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
@@ -1362,331 +1362,491 @@ describe('DependencyGraph', function() {
       });
     });
 
-    pit('should support simple browser field in packages', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("aPackage")',
-          ].join('\n'),
-          'aPackage': {
-            'package.json': JSON.stringify({
-              name: 'aPackage',
-              main: 'main.js',
-              browser: 'client.js',
-            }),
-            'main.js': 'some other code',
-            'client.js': 'some code',
-          },
-        },
-      });
+    testBrowserField('browser')
+    testBrowserField('react-native')
+
+    function replaceBrowserField (json, fieldName) {
+      if (fieldName !== 'browser') {
+        json[fieldName] = json.browser
+        delete json.browser
+      }
+
+      return json
+    }
+
+    function testBrowserField (fieldName) {
+      pit('should support simple browser field in packages ("' + fieldName + '")', function() {
+        var root = '/root';
+        fs.__setMockFilesystem({
+          'root': {
+            'index.js': [
+              '/**',
+              ' * @providesModule index',
+              ' */',
+              'require("aPackage")',
+            ].join('\n'),
+            'aPackage': {
+              'package.json': JSON.stringify(replaceBrowserField({
+                name: 'aPackage',
+                main: 'main.js',
+                browser: 'client.js',
+              }, fieldName)),
+              'main.js': 'some other code',
+              'client.js': 'some code',
+            }
+          }
+        });
 
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['aPackage'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-              resolveDependency: undefined,
-            },
-            {
-              id: 'aPackage/client.js',
-              path: '/root/aPackage/client.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-              resolveDependency: undefined,
-            },
-          ]);
+        var dgraph = new DependencyGraph({
+          ...defaults,
+          roots: [root],
+        });
+        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
+          expect(deps)
+            .toEqual([
+              {
+                id: 'index',
+                path: '/root/index.js',
+                dependencies: ['aPackage'],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
+                resolveDependency: undefined,
+              },
+              {
+                id: 'aPackage/client.js',
+                path: '/root/aPackage/client.js',
+                dependencies: [],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
+                resolveDependency: undefined,
+              },
+            ]);
+        });
       });
-    });
 
-    pit('should support browser field in packages w/o .js ext', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("aPackage")',
-          ].join('\n'),
-          'aPackage': {
-            'package.json': JSON.stringify({
-              name: 'aPackage',
-              main: 'main.js',
-              browser: 'client',
-            }),
-            'main.js': 'some other code',
-            'client.js': 'some code',
-          },
-        },
-      });
+      pit('should support browser field in packages w/o .js ext ("' + fieldName + '")', function() {
+        var root = '/root';
+        fs.__setMockFilesystem({
+          'root': {
+            'index.js': [
+              '/**',
+              ' * @providesModule index',
+              ' */',
+              'require("aPackage")',
+            ].join('\n'),
+            'aPackage': {
+              'package.json': JSON.stringify(replaceBrowserField({
+                name: 'aPackage',
+                main: 'main.js',
+                browser: 'client',
+              }, fieldName)),
+              'main.js': 'some other code',
+              'client.js': 'some code',
+            }
+          }
+        });
 
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['aPackage'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'aPackage/client.js',
-              path: '/root/aPackage/client.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
+        var dgraph = new DependencyGraph({
+          ...defaults,
+          roots: [root],
+        });
+        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
+          expect(deps)
+            .toEqual([
+              {
+                id: 'index',
+                path: '/root/index.js',
+                dependencies: ['aPackage'],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
+              },
+              {
+                id: 'aPackage/client.js',
+                path: '/root/aPackage/client.js',
+                dependencies: [],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
+              },
+            ]);
+        });
       });
-    });
 
-    pit('should support mapping main in browser field json', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("aPackage")',
-          ].join('\n'),
-          'aPackage': {
-            'package.json': JSON.stringify({
-              name: 'aPackage',
-              main: './main.js',
-              browser: {
-                './main.js': './client.js',
+      pit('should support mapping main in browser field json ("' + fieldName + '")', function() {
+        var root = '/root';
+        fs.__setMockFilesystem({
+          'root': {
+            'index.js': [
+              '/**',
+              ' * @providesModule index',
+              ' */',
+              'require("aPackage")',
+            ].join('\n'),
+            'aPackage': {
+              'package.json': JSON.stringify(replaceBrowserField({
+                name: 'aPackage',
+                main: './main.js',
+                browser: {
+                  './main.js': './client.js',
+                },
+              }, fieldName)),
+              'main.js': 'some other code',
+              'client.js': 'some code',
+            }
+          }
+        });
+
+        var dgraph = new DependencyGraph({
+          ...defaults,
+          roots: [root],
+          assetExts: ['png', 'jpg'],
+        });
+        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
+          expect(deps)
+            .toEqual([
+              {
+                id: 'index',
+                path: '/root/index.js',
+                dependencies: ['aPackage'],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
               },
-            }),
-            'main.js': 'some other code',
-            'client.js': 'some code',
-          },
-        },
+              { id: 'aPackage/client.js',
+                path: '/root/aPackage/client.js',
+                dependencies: [],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
+                resolveDependency: undefined,
+              },
+            ]);
+        });
       });
 
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['aPackage'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            { id: 'aPackage/client.js',
-              path: '/root/aPackage/client.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-              resolveDependency: undefined,
-            },
-          ]);
-      });
-    });
+      pit('should work do correct browser mapping w/o js ext ("' + fieldName + '")', function() {
+        var root = '/root';
+        fs.__setMockFilesystem({
+          'root': {
+            'index.js': [
+              '/**',
+              ' * @providesModule index',
+              ' */',
+              'require("aPackage")',
+            ].join('\n'),
+            'aPackage': {
+              'package.json': JSON.stringify(replaceBrowserField({
+                name: 'aPackage',
+                main: './main.js',
+                browser: {
+                  './main': './client.js',
+                },
+              }, fieldName)),
+              'main.js': 'some other code',
+              'client.js': 'some code',
+            }
+          }
+        });
 
-    pit('should work do correct browser mapping w/o js ext', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("aPackage")',
-          ].join('\n'),
-          'aPackage': {
-            'package.json': JSON.stringify({
-              name: 'aPackage',
-              main: './main.js',
-              browser: {
-                './main': './client.js',
+        var dgraph = new DependencyGraph({
+          ...defaults,
+          roots: [root],
+          assetExts: ['png', 'jpg'],
+        });
+        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
+          expect(deps)
+            .toEqual([
+              {
+                id: 'index',
+                path: '/root/index.js',
+                dependencies: ['aPackage'],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
+                resolveDependency: undefined,
               },
-            }),
-            'main.js': 'some other code',
-            'client.js': 'some code',
-          },
-        },
+              {
+                id: 'aPackage/client.js',
+                path: '/root/aPackage/client.js',
+                dependencies: [],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
+                resolveDependency: undefined,
+              },
+            ]);
+        });
       });
 
+      pit('should support browser mapping of files ("' + fieldName + '")', function() {
+        var root = '/root';
+        fs.__setMockFilesystem({
+          'root': {
+            'index.js': [
+              '/**',
+              ' * @providesModule index',
+              ' */',
+              'require("aPackage")',
+            ].join('\n'),
+            'aPackage': {
+              'package.json': JSON.stringify(replaceBrowserField({
+                name: 'aPackage',
+                main: './main.js',
+                browser: {
+                  './main': './client.js',
+                  './node.js': './not-node.js',
+                  './not-browser': './browser.js',
+                  './dir/server.js': './dir/client',
+                  './hello.js': './bye.js',
+                },
+              }, fieldName)),
+              'main.js': 'some other code',
+              'client.js': 'require("./node")\nrequire("./dir/server.js")',
+              'not-node.js': 'require("./not-browser")',
+              'not-browser.js': 'require("./dir/server")',
+              'browser.js': 'some browser code',
+              'dir': {
+                'server.js': 'some node code',
+                'client.js': 'require("../hello")',
+              },
+              'hello.js': 'hello',
+              'bye.js': 'bye',
+            }
+          }
+        });
+
       var dgraph = new DependencyGraph({
         ...defaults,
         roots: [root],
       });
       return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['aPackage'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-              resolveDependency: undefined,
-            },
-            {
-              id: 'aPackage/client.js',
-              path: '/root/aPackage/client.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-              resolveDependency: undefined,
-            },
-          ]);
+          expect(deps)
+            .toEqual([
+              { id: 'index',
+                path: '/root/index.js',
+                dependencies: ['aPackage'],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
+              },
+              { id: 'aPackage/client.js',
+                path: '/root/aPackage/client.js',
+                dependencies: ['./node', './dir/server.js'],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
+              },
+              { id: 'aPackage/not-node.js',
+                path: '/root/aPackage/not-node.js',
+                dependencies: ['./not-browser'],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
+              },
+              { id: 'aPackage/browser.js',
+                path: '/root/aPackage/browser.js',
+                dependencies: [],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
+              },
+              {
+                id: 'aPackage/dir/client.js',
+                path: '/root/aPackage/dir/client.js',
+                dependencies: ['../hello'],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
+              },
+              {
+                id: 'aPackage/bye.js',
+                path: '/root/aPackage/bye.js',
+                dependencies: [],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
+              },
+            ]);
+        });
       });
-    });
 
-    pit('should support browser mapping of files', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("aPackage")',
-          ].join('\n'),
-          'aPackage': {
-            'package.json': JSON.stringify({
-              name: 'aPackage',
-              main: './main.js',
-              browser: {
-                './main': './client.js',
-                './node.js': './not-node.js',
-                './not-browser': './browser.js',
-                './dir/server.js': './dir/client',
-                './hello.js': './bye.js',
+      pit('should support browser mapping for packages ("' + fieldName + '")', function() {
+        var root = '/root';
+        fs.__setMockFilesystem({
+          'root': {
+            'index.js': [
+              '/**',
+              ' * @providesModule index',
+              ' */',
+              'require("aPackage")',
+            ].join('\n'),
+            'aPackage': {
+              'package.json': JSON.stringify(replaceBrowserField({
+                name: 'aPackage',
+                browser: {
+                  'node-package': 'browser-package',
+                }
+              }, fieldName)),
+              'index.js': 'require("node-package")',
+              'node-package': {
+                'package.json': JSON.stringify({
+                  'name': 'node-package',
+                }),
+                'index.js': 'some node code',
               },
-            }),
-            'main.js': 'some other code',
-            'client.js': 'require("./node")\nrequire("./dir/server.js")',
-            'not-node.js': 'require("./not-browser")',
-            'not-browser.js': 'require("./dir/server")',
-            'browser.js': 'some browser code',
-            'dir': {
-              'server.js': 'some node code',
-              'client.js': 'require("../hello")',
-            },
-            'hello.js': 'hello',
-            'bye.js': 'bye',
-          },
-        },
-      });
+              'browser-package': {
+                'package.json': JSON.stringify({
+                  'name': 'browser-package',
+                }),
+                'index.js': 'some browser code',
+              },
+            }
+          }
+        });
 
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
+        var dgraph = new DependencyGraph({
+          ...defaults,
+          roots: [root],
+        });
+        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
+          expect(deps)
+            .toEqual([
+              { id: 'index',
+                path: '/root/index.js',
+                dependencies: ['aPackage'],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
+              },
+              { id: 'aPackage/index.js',
+                path: '/root/aPackage/index.js',
+                dependencies: ['node-package'],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
+              },
+              { id: 'browser-package/index.js',
+                path: '/root/aPackage/browser-package/index.js',
+                dependencies: [],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
+              },
+            ]);
+        });
       });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            { id: 'index',
-              path: '/root/index.js',
-              dependencies: ['aPackage'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            { id: 'aPackage/client.js',
-              path: '/root/aPackage/client.js',
-              dependencies: ['./node', './dir/server.js'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            { id: 'aPackage/not-node.js',
-              path: '/root/aPackage/not-node.js',
-              dependencies: ['./not-browser'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            { id: 'aPackage/browser.js',
-              path: '/root/aPackage/browser.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'aPackage/dir/client.js',
-              path: '/root/aPackage/dir/client.js',
-              dependencies: ['../hello'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'aPackage/bye.js',
-              path: '/root/aPackage/bye.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
+
+      pit('should support browser mapping for packages ("' + fieldName + '")', function() {
+        var root = '/root';
+        fs.__setMockFilesystem({
+          'root': {
+            'index.js': [
+              '/**',
+              ' * @providesModule index',
+              ' */',
+              'require("aPackage")',
+            ].join('\n'),
+            'aPackage': {
+              'package.json': JSON.stringify(replaceBrowserField({
+                name: 'aPackage',
+                browser: {
+                  'node-package': 'browser-package',
+                }
+              }, fieldName)),
+              'index.js': 'require("node-package")',
+              'node-package': {
+                'package.json': JSON.stringify({
+                  'name': 'node-package',
+                }),
+                'index.js': 'some node code',
+              },
+              'browser-package': {
+                'package.json': JSON.stringify({
+                  'name': 'browser-package',
+                }),
+                'index.js': 'some browser code',
+              },
+            }
+          }
+        });
+
+        var dgraph = new DependencyGraph({
+          ...defaults,
+          roots: [root],
+        });
+        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
+          expect(deps)
+            .toEqual([
+              { id: 'index',
+                path: '/root/index.js',
+                dependencies: ['aPackage'],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
+              },
+              { id: 'aPackage/index.js',
+                path: '/root/aPackage/index.js',
+                dependencies: ['node-package'],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
+              },
+              { id: 'browser-package/index.js',
+                path: '/root/aPackage/browser-package/index.js',
+                dependencies: [],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
+              },
+            ]);
+        });
       });
-    });
+    }
 
-    pit('should support browser mapping for packages', function() {
+    pit('should fall back to browser mapping from react-native mapping', function() {
       var root = '/root';
       fs.__setMockFilesystem({
         'root': {
@@ -1699,25 +1859,36 @@ describe('DependencyGraph', function() {
           'aPackage': {
             'package.json': JSON.stringify({
               name: 'aPackage',
-              browser: {
-                'node-package': 'browser-package',
-              },
+              'react-native': {
+                'node-package': 'rn-package',
+              }
             }),
             'index.js': 'require("node-package")',
-            'node-package': {
-              'package.json': JSON.stringify({
-                'name': 'node-package',
-              }),
-              'index.js': 'some node code',
-            },
-            'browser-package': {
-              'package.json': JSON.stringify({
-                'name': 'browser-package',
-              }),
-              'index.js': 'some browser code',
-            },
-          },
-        },
+            'node_modules': {
+              'node-package': {
+                'package.json': JSON.stringify({
+                  'name': 'node-package'
+                }),
+                'index.js': 'some node code',
+              },
+              'rn-package': {
+                'package.json': JSON.stringify({
+                  'name': 'rn-package',
+                  browser: {
+                    'nested-package': 'nested-browser-package'
+                  }
+                }),
+                'index.js': 'require("nested-package")',
+              },
+              'nested-browser-package': {
+                'package.json': JSON.stringify({
+                  'name': 'nested-browser-package',
+                }),
+                'index.js': 'some code'
+              }
+            }
+          }
+        }
       });
 
       var dgraph = new DependencyGraph({
@@ -1745,8 +1916,17 @@ describe('DependencyGraph', function() {
               isPolyfill: false,
               resolution: undefined,
             },
-            { id: 'browser-package/index.js',
-              path: '/root/aPackage/browser-package/index.js',
+            { id: 'rn-package/index.js',
+              path: '/root/aPackage/node_modules/rn-package/index.js',
+              dependencies: ['nested-package'],
+              isAsset: false,
+              isAsset_DEPRECATED: false,
+              isJSON: false,
+              isPolyfill: false,
+              resolution: undefined,
+            },
+            { id: 'nested-browser-package/index.js',
+              path: '/root/aPackage/node_modules/nested-browser-package/index.js',
               dependencies: [],
               isAsset: false,
               isAsset_DEPRECATED: false,
diff --git a/packager/react-packager/src/DependencyResolver/Package.js b/packager/react-packager/src/DependencyResolver/Package.js
index d45a8923e35e..2117e3f1976a 100644
--- a/packager/react-packager/src/DependencyResolver/Package.js
+++ b/packager/react-packager/src/DependencyResolver/Package.js
@@ -15,17 +15,18 @@ class Package {
 
   getMain() {
     return this._read().then(json => {
-      if (typeof json.browser === 'string') {
-        return path.join(this.root, json.browser);
+      var replacements = getReplacements(json)
+      if (typeof replacements === 'string') {
+        return path.join(this.root, replacements);
       }
 
       let main = json.main || 'index';
 
-      if (json.browser && typeof json.browser === 'object') {
-        main = json.browser[main] ||
-          json.browser[main + '.js'] ||
-          json.browser[main + '.json'] ||
-          json.browser[main.replace(/(\.js|\.json)$/, '')] ||
+      if (replacements && typeof replacements === 'object') {
+        main = replacements[main] ||
+          replacements[main + '.js'] ||
+          replacements[main + '.json'] ||
+          replacements[main.replace(/(\.js|\.json)$/, '')] ||
           main;
       }
 
@@ -51,14 +52,14 @@ class Package {
 
   redirectRequire(name) {
     return this._read().then(json => {
-      const {browser} = json;
+      var replacements = getReplacements(json);
 
-      if (!browser || typeof browser !== 'object') {
+      if (!replacements || typeof replacements !== 'object') {
         return name;
       }
 
       if (name[0] !== '/') {
-        return browser[name] || name;
+        return replacements[name] || name;
       }
 
       if (!isAbsolutePath(name)) {
@@ -66,9 +67,9 @@ class Package {
       }
 
       const relPath = './' + path.relative(this.root, name);
-      const redirect = browser[relPath] ||
-              browser[relPath + '.js'] ||
-              browser[relPath + '.json'];
+      const redirect = replacements[relPath] ||
+              replacements[relPath + '.js'] ||
+              replacements[relPath + '.json'];
       if (redirect) {
         return path.join(
           this.root,
@@ -90,4 +91,10 @@ class Package {
   }
 }
 
+function getReplacements(pkg) {
+  return pkg['react-native'] == null
+    ? pkg.browser
+    : pkg['react-native'];
+}
+
 module.exports = Package;

From 2c14ab582a629e73619999a0d4b4577a852d0e40 Mon Sep 17 00:00:00 2001
From: Tim Yung <yungsters@fb.com>
Date: Tue, 24 Nov 2015 11:29:44 -0800
Subject: [PATCH 0093/1411] RN: Add "Dismiss All" to YellowBox

Summary: Adds a "Dismiss All" button to YellowBox for people who see litter on the ground and continue walking. (Just kidding).

public

Reviewed By: vjeux

Differential Revision: D2691764

fb-gh-sync-id: 9746b42bc1e5dc51f2320880f47f8cb17b952570
---
 Libraries/ReactIOS/YellowBox.js | 33 +++++++++++++++++++++++++--------
 1 file changed, 25 insertions(+), 8 deletions(-)

diff --git a/Libraries/ReactIOS/YellowBox.js b/Libraries/ReactIOS/YellowBox.js
index 5c1e0e37284d..012515cc48c1 100644
--- a/Libraries/ReactIOS/YellowBox.js
+++ b/Libraries/ReactIOS/YellowBox.js
@@ -122,7 +122,13 @@ const WarningRow = ({count, warning, onPress}) => {
   );
 };
 
-const WarningInspector = ({count, warning, onClose, onDismiss}) => {
+const WarningInspector = ({
+  count,
+  warning,
+  onClose,
+  onDismiss,
+  onDismissAll,
+}) => {
   const ScrollView = require('ScrollView');
   const Text = require('Text');
   const TouchableHighlight = require('TouchableHighlight');
@@ -151,7 +157,16 @@ const WarningInspector = ({count, warning, onClose, onDismiss}) => {
             style={styles.inspectorButton}
             underlayColor="transparent">
             <Text style={styles.inspectorButtonText}>
-              Dismiss Warning
+              Dismiss
+            </Text>
+          </TouchableHighlight>
+          <TouchableHighlight
+            activeOpacity={0.5}
+            onPress={onDismissAll}
+            style={styles.inspectorButton}
+            underlayColor="transparent">
+            <Text style={styles.inspectorButtonText}>
+              Dismiss All
             </Text>
           </TouchableHighlight>
         </View>
@@ -175,9 +190,13 @@ class YellowBox extends React.Component {
     };
     this.dismissWarning = warning => {
       const {inspecting, warningMap} = this.state;
-      warningMap.delete(warning);
+      if (warning) {
+        warningMap.delete(warning);
+      } else {
+        warningMap.clear();
+      }
       this.setState({
-        inspecting: inspecting === warning ? null : inspecting,
+        inspecting: (warning && inspecting !== warning) ? inspecting : null,
         warningMap,
       });
     };
@@ -217,6 +236,7 @@ class YellowBox extends React.Component {
         warning={inspecting}
         onClose={() => this.setState({inspecting: null})}
         onDismiss={() => this.dismissWarning(inspecting)}
+        onDismissAll={() => this.dismissWarning(null)}
       /> :
       null;
 
@@ -280,11 +300,8 @@ var styles = StyleSheet.create({
     bottom: 0,
   },
   inspectorButton: {
+    flex: 1,
     padding: 22,
-    position: 'absolute',
-    left: 0,
-    right: 0,
-    bottom: 0,
   },
   inspectorButtonText: {
     color: textColor,

From 510f001390519137a951903d7143f10cd03fc03a Mon Sep 17 00:00:00 2001
From: Martin Kralik <kralik@fb.com>
Date: Tue, 24 Nov 2015 12:10:48 -0800
Subject: [PATCH 0094/1411] put exception message in front of error log

Summary: Exception message was the last part of the whole shown error. This is not optimal in case where there are deeply nested objects as parameters, which used to be displayed before the message.
This diff moves the exception message to the front.

public

Reviewed By: javache

Differential Revision: D2691426

fb-gh-sync-id: c6c9ad3ac4681a8102ea2c580f24382640b7246c
---
 React/Base/RCTBatchedBridge.m | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index 26dcb57721ac..98998dd3c36d 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -785,8 +785,8 @@ - (BOOL)_handleRequestNumber:(NSUInteger)i
     }
 
     NSString *message = [NSString stringWithFormat:
-                         @"Exception thrown while invoking %@ on target %@ with params %@: %@",
-                         method.JSMethodName, moduleData.name, params, exception];
+                         @"Exception '%@' was thrown while invoking %@ on target %@ with params %@",
+                         exception, method.JSMethodName, moduleData.name, params];
     RCTFatal(RCTErrorWithMessage(message));
   }
 

From 469a65217c4f0a3e46e69037d86a91b0a60d7bc3 Mon Sep 17 00:00:00 2001
From: Krzysztof Magiera <krzys.magiera@gmail.com>
Date: Tue, 24 Nov 2015 13:05:34 -0800
Subject: [PATCH 0095/1411] Add note in View.js render method that wrapper
 component is not used.

Summary: Got bitten lately by View.js returning different component based on `__DEV__`

Adding a warning in the render method that should make it cleaner in the future that this method is not actually being used in prod mode.
Closes https://github.com/facebook/react-native/pull/4322

Reviewed By: svcscm

Differential Revision: D2691880

Pulled By: vjeux

fb-gh-sync-id: 119672740969a857ab6288b7914d52e8d40a1d95
---
 Libraries/Components/View/View.js | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Libraries/Components/View/View.js b/Libraries/Components/View/View.js
index ff2def0afabe..84ab491875d9 100644
--- a/Libraries/Components/View/View.js
+++ b/Libraries/Components/View/View.js
@@ -312,6 +312,10 @@ var View = React.createClass({
   },
 
   render: function() {
+    // WARNING: This method will not be used in production mode as in that mode we
+    // replace wrapper component View with generated native wrapper RCTView. Avoid
+    // adding functionality this component that you'd want to be available in both
+    // dev and prod modes.
     return <RCTView {...this.props} />;
   },
 });

From b5be05d82bfddb0c29317af14dc07652beb3cacc Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Tue, 24 Nov 2015 14:26:14 -0800
Subject: [PATCH 0096/1411] Fix flaky scrolling for TextInput when using rich
 text

Summary: public

This diff fixes the jumpy scrolling for multiline `<TextInput>` when using nested `<Text>` components to implement rich text highlighting.

The fix is to disable scrolling on the underlying UITextView, and nest it inside another UIScrollView that we control.

Reviewed By: ericvicenti, tadeuzagallo

Differential Revision: D2674670

fb-gh-sync-id: bacee3ae485523cc26ca8102b714e081df230629
---
 Examples/UIExplorer/TextInputExample.ios.js | 88 ++++++++++-----------
 Libraries/Text/RCTTextView.h                |  1 -
 Libraries/Text/RCTTextView.m                | 41 +++++-----
 Libraries/Text/RCTTextViewManager.m         | 19 ++---
 4 files changed, 74 insertions(+), 75 deletions(-)

diff --git a/Examples/UIExplorer/TextInputExample.ios.js b/Examples/UIExplorer/TextInputExample.ios.js
index 5f13d822fd54..471920a0b4d0 100644
--- a/Examples/UIExplorer/TextInputExample.ios.js
+++ b/Examples/UIExplorer/TextInputExample.ios.js
@@ -301,6 +301,50 @@ exports.displayName = (undefined: ?string);
 exports.title = '<TextInput>';
 exports.description = 'Single and multi-line text inputs.';
 exports.examples = [
+  {
+    title: 'Multiline',
+    render: function() {
+      return (
+        <View>
+          <TextInput
+            placeholder="multiline text input"
+            multiline={true}
+            style={styles.multiline}
+          />
+          <TextInput
+            placeholder="multiline text input with font styles and placeholder"
+            multiline={true}
+            clearTextOnFocus={true}
+            autoCorrect={true}
+            autoCapitalize="words"
+            placeholderTextColor="red"
+            keyboardType="url"
+            style={[styles.multiline, styles.multilineWithFontStyles]}
+          />
+          <TextInput
+            placeholder="uneditable multiline text input"
+            editable={false}
+            multiline={true}
+            style={styles.multiline}
+          />
+          <TextInput
+            placeholder="multiline with children"
+            multiline={true}
+            enablesReturnKeyAutomatically={true}
+            returnKeyType="go"
+            style={styles.multiline}>
+            <View style={styles.multilineChild}/>
+          </TextInput>
+        </View>
+      );
+    }
+  },
+  {
+    title: 'Attributed text',
+    render: function() {
+      return <TokenizedTextExample />;
+    }
+  },
   {
     title: 'Auto-focus',
     render: function() {
@@ -544,50 +588,6 @@ exports.examples = [
       );
     }
   },
-  {
-    title: 'Multiline',
-    render: function() {
-      return (
-        <View>
-          <TextInput
-            placeholder="multiline text input"
-            multiline={true}
-            style={styles.multiline}
-          />
-          <TextInput
-            placeholder="multiline text input with font styles and placeholder"
-            multiline={true}
-            clearTextOnFocus={true}
-            autoCorrect={true}
-            autoCapitalize="words"
-            placeholderTextColor="red"
-            keyboardType="url"
-            style={[styles.multiline, styles.multilineWithFontStyles]}
-          />
-          <TextInput
-            placeholder="uneditable multiline text input"
-            editable={false}
-            multiline={true}
-            style={styles.multiline}
-          />
-          <TextInput
-            placeholder="multiline with children"
-            multiline={true}
-            enablesReturnKeyAutomatically={true}
-            returnKeyType="go"
-            style={styles.multiline}>
-            <View style={styles.multilineChild}/>
-          </TextInput>
-        </View>
-      );
-    }
-  },
-  {
-    title: 'Attributed text',
-    render: function() {
-      return <TokenizedTextExample />;
-    }
-  },
   {
     title: 'Blur on submit',
     render: function(): ReactElement { return <BlurOnSubmitExample />; },
diff --git a/Libraries/Text/RCTTextView.h b/Libraries/Text/RCTTextView.h
index a6d8bca08917..9305442abe91 100644
--- a/Libraries/Text/RCTTextView.h
+++ b/Libraries/Text/RCTTextView.h
@@ -22,7 +22,6 @@
 @property (nonatomic, assign) UIEdgeInsets contentInset;
 @property (nonatomic, assign) BOOL automaticallyAdjustContentInsets;
 @property (nonatomic, copy) NSString *text;
-@property (nonatomic, strong) UIColor *textColor;
 @property (nonatomic, strong) UIColor *placeholderTextColor;
 @property (nonatomic, strong) UIFont *font;
 @property (nonatomic, assign) NSInteger mostRecentEventCount;
diff --git a/Libraries/Text/RCTTextView.m b/Libraries/Text/RCTTextView.m
index 2af31f39aa65..f75a4c013ef1 100644
--- a/Libraries/Text/RCTTextView.m
+++ b/Libraries/Text/RCTTextView.m
@@ -44,6 +44,7 @@ @implementation RCTTextView
   NSMutableArray<UIView *> *_subviews;
   BOOL _blockTextShouldChange;
   UITextRange *_previousSelectionRange;
+  UIScrollView *_scrollView;
 }
 
 - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
@@ -55,15 +56,19 @@ - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
     _eventDispatcher = eventDispatcher;
     _placeholderTextColor = [self defaultPlaceholderTextColor];
 
-    _textView = [[RCTUITextView alloc] initWithFrame:self.bounds];
+    _textView = [[RCTUITextView alloc] initWithFrame:CGRectZero];
     _textView.backgroundColor = [UIColor clearColor];
     _textView.scrollsToTop = NO;
+    _textView.scrollEnabled = NO;
     _textView.delegate = self;
 
+    _scrollView = [[UIScrollView alloc] initWithFrame:CGRectZero];
+    [_scrollView addSubview:_textView];
+
     _previousSelectionRange = _textView.selectedTextRange;
 
     _subviews = [NSMutableArray new];
-    [self addSubview:_textView];
+    [self addSubview:_scrollView];
   }
   return self;
 }
@@ -139,16 +144,11 @@ - (void)performPendingTextUpdate
   // we temporarily block all textShouldChange events so they are not applied.
   _blockTextShouldChange = YES;
 
-  // We compute the new selectedRange manually to make sure the cursor is at the
-  // end of the newly inserted/deleted text after update.
   NSRange range = _textView.selectedRange;
-  CGPoint contentOffset = _textView.contentOffset;
-
   _textView.attributedText = _pendingAttributedText;
   _pendingAttributedText = nil;
   _textView.selectedRange = range;
   [_textView layoutIfNeeded];
-  _textView.contentOffset = contentOffset;
 
   [self _setPlaceholderVisibility];
 
@@ -174,11 +174,21 @@ - (void)updateFrames
   CGRect frame = UIEdgeInsetsInsetRect(self.bounds, adjustedFrameInset);
   _textView.frame = frame;
   _placeholderView.frame = frame;
+  _scrollView.frame = frame;
+  [self updateContentSize];
 
   _textView.textContainerInset = adjustedTextContainerInset;
   _placeholderView.textContainerInset = adjustedTextContainerInset;
 }
 
+- (void)updateContentSize
+{
+  _textView.scrollEnabled = YES;
+  _scrollView.contentSize = _textView.contentSize;
+  _textView.frame = (CGRect){CGPointZero, _scrollView.contentSize};
+  _textView.scrollEnabled = NO;
+}
+
 - (void)updatePlaceholder
 {
   [_placeholderView removeFromSuperview];
@@ -186,6 +196,8 @@ - (void)updatePlaceholder
 
   if (_placeholder) {
     _placeholderView = [[UITextView alloc] initWithFrame:self.bounds];
+    _placeholderView.editable = NO;
+    _placeholderView.userInteractionEnabled = NO;
     _placeholderView.backgroundColor = [UIColor clearColor];
     _placeholderView.scrollEnabled = false;
     _placeholderView.scrollsToTop = NO;
@@ -211,16 +223,6 @@ - (void)setFont:(UIFont *)font
   [self updatePlaceholder];
 }
 
-- (UIColor *)textColor
-{
-  return _textView.textColor;
-}
-
-- (void)setTextColor:(UIColor *)textColor
-{
-  _textView.textColor = textColor;
-}
-
 - (void)setPlaceholder:(NSString *)placeholder
 {
   _placeholder = placeholder;
@@ -305,10 +307,6 @@ - (void)textViewDidChangeSelection:(RCTUITextView *)textView
       },
     });
   }
-
-  if (textView.editable && [textView isFirstResponder]) {
-    [textView scrollRangeToVisible:textView.selectedRange];
-  }
 }
 
 - (void)setText:(NSString *)text
@@ -369,6 +367,7 @@ - (void)textViewDidBeginEditing:(UITextView *)textView
 
 - (void)textViewDidChange:(UITextView *)textView
 {
+  [self updateContentSize];
   [self _setPlaceholderVisibility];
   _nativeEventCount++;
   [_eventDispatcher sendTextEventWithType:RCTTextEventTypeChange
diff --git a/Libraries/Text/RCTTextViewManager.m b/Libraries/Text/RCTTextViewManager.m
index c5c04ee7fb32..94ba4609c94a 100644
--- a/Libraries/Text/RCTTextViewManager.m
+++ b/Libraries/Text/RCTTextViewManager.m
@@ -23,21 +23,22 @@ - (UIView *)view
   return [[RCTTextView alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
 }
 
+RCT_REMAP_VIEW_PROPERTY(autoCapitalize, textView.autocapitalizationType, UITextAutocapitalizationType)
 RCT_EXPORT_VIEW_PROPERTY(autoCorrect, BOOL)
-RCT_REMAP_VIEW_PROPERTY(editable, textView.editable, BOOL)
-RCT_EXPORT_VIEW_PROPERTY(placeholder, NSString)
-RCT_EXPORT_VIEW_PROPERTY(placeholderTextColor, UIColor)
-RCT_EXPORT_VIEW_PROPERTY(text, NSString)
-RCT_EXPORT_VIEW_PROPERTY(maxLength, NSNumber)
 RCT_EXPORT_VIEW_PROPERTY(clearTextOnFocus, BOOL)
-RCT_EXPORT_VIEW_PROPERTY(selectTextOnFocus, BOOL)
+RCT_REMAP_VIEW_PROPERTY(color, textView.textColor, UIColor)
+RCT_REMAP_VIEW_PROPERTY(editable, textView.editable, BOOL)
+RCT_REMAP_VIEW_PROPERTY(enablesReturnKeyAutomatically, textView.enablesReturnKeyAutomatically, BOOL)
 RCT_REMAP_VIEW_PROPERTY(keyboardType, textView.keyboardType, UIKeyboardType)
 RCT_REMAP_VIEW_PROPERTY(keyboardAppearance, textView.keyboardAppearance, UIKeyboardAppearance)
+RCT_EXPORT_VIEW_PROPERTY(maxLength, NSNumber)
 RCT_EXPORT_VIEW_PROPERTY(onSelectionChange, RCTDirectEventBlock)
+RCT_EXPORT_VIEW_PROPERTY(placeholder, NSString)
+RCT_EXPORT_VIEW_PROPERTY(placeholderTextColor, UIColor)
 RCT_REMAP_VIEW_PROPERTY(returnKeyType, textView.returnKeyType, UIReturnKeyType)
-RCT_REMAP_VIEW_PROPERTY(enablesReturnKeyAutomatically, textView.enablesReturnKeyAutomatically, BOOL)
-RCT_REMAP_VIEW_PROPERTY(color, textColor, UIColor)
-RCT_REMAP_VIEW_PROPERTY(autoCapitalize, textView.autocapitalizationType, UITextAutocapitalizationType)
+RCT_REMAP_VIEW_PROPERTY(secureTextEntry, textView.secureTextEntry, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(selectTextOnFocus, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(text, NSString)
 RCT_CUSTOM_VIEW_PROPERTY(fontSize, CGFloat, RCTTextView)
 {
   view.font = [RCTConvert UIFont:view.font withSize:json ?: @(defaultView.font.pointSize)];

From 9fc3991615b5dd6815713697945dd5d9bc300a66 Mon Sep 17 00:00:00 2001
From: Manuel Nakamurakare <manask88@gmail.com>
Date: Tue, 24 Nov 2015 14:52:09 -0800
Subject: [PATCH 0097/1411] added method to set thumb image

Summary: this change will allow the slider to have different thumb images .

Sets an image for the thumb. It only supports static images
Closes https://github.com/facebook/react-native/pull/3849

Reviewed By: svcscm

Differential Revision: D2665699

Pulled By: nicklockwood

fb-gh-sync-id: 3a767e43170074e2419067d5c8eae61668ebb5e9
---
 Examples/UIExplorer/SliderIOSExample.js       |   6 +++
 .../UIExplorer.xcodeproj/project.pbxproj      |  40 ++++++++++++++----
 .../UIExplorer/Base.lproj/LaunchScreen.xib    |   8 +++-
 .../uie_thumb_big.imageset/Contents.json      |  21 ---------
 .../testSliderExample_1@2x.png                | Bin 40184 -> 69018 bytes
 .../UIExplorerSnapshotTests.m                 |   2 +-
 .../uie_thumb_big.png                         | Bin
 .../Components/SliderIOS/SliderIOS.ios.js     |   7 ++-
 React/Views/RCTSlider.h                       |   2 +
 React/Views/RCTSlider.m                       |  10 +++++
 React/Views/RCTSliderManager.m                |   1 +
 11 files changed, 63 insertions(+), 34 deletions(-)
 delete mode 100644 Examples/UIExplorer/UIExplorer/Images.xcassets/uie_thumb_big.imageset/Contents.json
 rename Examples/UIExplorer/{UIExplorer/Images.xcassets/uie_thumb_big.imageset => }/uie_thumb_big.png (100%)

diff --git a/Examples/UIExplorer/SliderIOSExample.js b/Examples/UIExplorer/SliderIOSExample.js
index 245fe10ad57e..9b3c584db151 100644
--- a/Examples/UIExplorer/SliderIOSExample.js
+++ b/Examples/UIExplorer/SliderIOSExample.js
@@ -83,5 +83,11 @@ exports.examples = [
     render(): ReactElement {
       return <SliderExample step={0.25} />;
     }
+  },
+  {
+    title: 'Custom thumb image',
+    render(): ReactElement {
+      return <SliderExample thumbImage={require('image!uie_thumb_big')} />;
+    }
   }
 ];
diff --git a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
index 49a27dc61e74..2f10b53ae305 100644
--- a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
+++ b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
@@ -8,6 +8,11 @@
 
 /* Begin PBXBuildFile section */
 		1300627F1B59179B0043FE5A /* RCTGzipTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1300627E1B59179B0043FE5A /* RCTGzipTests.m */; };
+		1323F1891C04AB9F0091BED0 /* bunny.png in Resources */ = {isa = PBXBuildFile; fileRef = 1323F1851C04AB9F0091BED0 /* bunny.png */; };
+		1323F18A1C04AB9F0091BED0 /* flux@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1323F1861C04AB9F0091BED0 /* flux@3x.png */; };
+		1323F18B1C04AB9F0091BED0 /* hawk.png in Resources */ = {isa = PBXBuildFile; fileRef = 1323F1871C04AB9F0091BED0 /* hawk.png */; };
+		1323F18C1C04AB9F0091BED0 /* uie_thumb_big.png in Resources */ = {isa = PBXBuildFile; fileRef = 1323F1881C04AB9F0091BED0 /* uie_thumb_big.png */; };
+		1323F18F1C04ABEB0091BED0 /* Thumbnails in Resources */ = {isa = PBXBuildFile; fileRef = 1323F18E1C04ABEB0091BED0 /* Thumbnails */; };
 		13417FE91AA91432003F314A /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 13417FE81AA91428003F314A /* libRCTImage.a */; };
 		134180011AA9153C003F314A /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 13417FEF1AA914B8003F314A /* libRCTText.a */; };
 		1341802C1AA9178B003F314A /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1341802B1AA91779003F314A /* libRCTNetwork.a */; };
@@ -50,11 +55,10 @@
 		14D6D7281B2222EF001FB087 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDED91B0651EA00C62182 /* libRCTWebSocket.a */; };
 		14D6D7291B2222EF001FB087 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14AADF041AC3DB95002390C9 /* libReact.a */; };
 		14DC67F41AB71881001358AB /* libRCTPushNotification.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14DC67F11AB71876001358AB /* libRCTPushNotification.a */; };
-		272E6B3F1BEA849E001FCF37 /* UpdatePropertiesExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 272E6B3C1BEA849E001FCF37 /* UpdatePropertiesExampleView.m */; settings = {ASSET_TAGS = (); }; };
-		27F441EC1BEBE5030039B79C /* FlexibleSizeExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 27F441E81BEBE5030039B79C /* FlexibleSizeExampleView.m */; settings = {ASSET_TAGS = (); }; };
+		272E6B3F1BEA849E001FCF37 /* UpdatePropertiesExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 272E6B3C1BEA849E001FCF37 /* UpdatePropertiesExampleView.m */; };
+		27F441EC1BEBE5030039B79C /* FlexibleSizeExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 27F441E81BEBE5030039B79C /* FlexibleSizeExampleView.m */; };
 		27B885561BED29AF00008352 /* RCTRootViewIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 27B885551BED29AF00008352 /* RCTRootViewIntegrationTests.m */; settings = {ASSET_TAGS = (); }; };
 		3578590A1B28D2CF00341EDB /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 357859011B28D2C500341EDB /* libRCTLinking.a */; };
-		3D36915B1BDA8CBB007B22D8 /* uie_thumb_big.png in Resources */ = {isa = PBXBuildFile; fileRef = 3D36915A1BDA8CBB007B22D8 /* uie_thumb_big.png */; };
 		3DB99D0C1BA0340600302749 /* UIExplorerIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DB99D0B1BA0340600302749 /* UIExplorerIntegrationTests.m */; };
 		834C36EC1AF8DED70019C93C /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 834C36D21AF8DA610019C93C /* libRCTSettings.a */; };
 		83636F8F1B53F22C009F943E /* RCTUIManagerScenarioTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 83636F8E1B53F22C009F943E /* RCTUIManagerScenarioTests.m */; };
@@ -174,6 +178,11 @@
 /* Begin PBXFileReference section */
 		004D289E1AAF61C70097A701 /* UIExplorerUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UIExplorerUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 		1300627E1B59179B0043FE5A /* RCTGzipTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTGzipTests.m; sourceTree = "<group>"; };
+		1323F1851C04AB9F0091BED0 /* bunny.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = bunny.png; sourceTree = "<group>"; };
+		1323F1861C04AB9F0091BED0 /* flux@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "flux@3x.png"; sourceTree = "<group>"; };
+		1323F1871C04AB9F0091BED0 /* hawk.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = hawk.png; sourceTree = "<group>"; };
+		1323F1881C04AB9F0091BED0 /* uie_thumb_big.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = uie_thumb_big.png; sourceTree = "<group>"; };
+		1323F18E1C04ABEB0091BED0 /* Thumbnails */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Thumbnails; sourceTree = "<group>"; };
 		13417FE31AA91428003F314A /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = ../../Libraries/Image/RCTImage.xcodeproj; sourceTree = "<group>"; };
 		13417FEA1AA914B8003F314A /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = ../../Libraries/Text/RCTText.xcodeproj; sourceTree = "<group>"; };
 		134180261AA91779003F314A /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../../Libraries/Network/RCTNetwork.xcodeproj; sourceTree = "<group>"; };
@@ -231,7 +240,6 @@
 		27F441EA1BEBE5030039B79C /* FlexibleSizeExampleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FlexibleSizeExampleView.h; path = UIExplorer/NativeExampleViews/FlexibleSizeExampleView.h; sourceTree = "<group>"; };
 		27B885551BED29AF00008352 /* RCTRootViewIntegrationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRootViewIntegrationTests.m; sourceTree = "<group>"; };
 		357858F81B28D2C400341EDB /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = ../../Libraries/LinkingIOS/RCTLinking.xcodeproj; sourceTree = "<group>"; };
-		3D36915A1BDA8CBB007B22D8 /* uie_thumb_big.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = uie_thumb_big.png; path = UIExplorer/Images.xcassets/uie_thumb_big.imageset/uie_thumb_big.png; sourceTree = SOURCE_ROOT; };
 		3DB99D0B1BA0340600302749 /* UIExplorerIntegrationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIExplorerIntegrationTests.m; sourceTree = "<group>"; };
 		58005BE41ABA80530062E044 /* RCTTest.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTTest.xcodeproj; path = ../../Libraries/RCTTest/RCTTest.xcodeproj; sourceTree = "<group>"; };
 		83636F8E1B53F22C009F943E /* RCTUIManagerScenarioTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTUIManagerScenarioTests.m; sourceTree = "<group>"; };
@@ -314,6 +322,18 @@
 			name = Libraries;
 			sourceTree = "<group>";
 		};
+		1323F18D1C04ABAC0091BED0 /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				13B07FB61A68108700A75B9A /* Info.plist */,
+				1323F1851C04AB9F0091BED0 /* bunny.png */,
+				1323F1861C04AB9F0091BED0 /* flux@3x.png */,
+				1323F1871C04AB9F0091BED0 /* hawk.png */,
+				1323F1881C04AB9F0091BED0 /* uie_thumb_big.png */,
+			);
+			name = "Supporting Files";
+			sourceTree = "<group>";
+		};
 		13417FE41AA91428003F314A /* Products */ = {
 			isa = PBXGroup;
 			children = (
@@ -377,10 +397,10 @@
 				13B07FAF1A68108700A75B9A /* AppDelegate.h */,
 				13B07FB01A68108700A75B9A /* AppDelegate.m */,
 				13B07FB51A68108700A75B9A /* Images.xcassets */,
-				134366AE1BFD2C76000A2DE1 /* Thumbnails */,
-				13B07FB61A68108700A75B9A /* Info.plist */,
 				13B07FB11A68108700A75B9A /* LaunchScreen.xib */,
 				13B07FB71A68108700A75B9A /* main.m */,
+				1323F18E1C04ABEB0091BED0 /* Thumbnails */,
+				1323F18D1C04ABAC0091BED0 /* Supporting Files */,
 			);
 			name = UIExplorer;
 			sourceTree = "<group>";
@@ -448,7 +468,6 @@
 		143BC5971B21E3E100462512 /* Supporting Files */ = {
 			isa = PBXGroup;
 			children = (
-				3D36915A1BDA8CBB007B22D8 /* uie_thumb_big.png */,
 				143BC5981B21E3E100462512 /* Info.plist */,
 			);
 			name = "Supporting Files";
@@ -832,9 +851,13 @@
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				134366AF1BFD2C76000A2DE1 /* Thumbnails in Resources */,
+				1323F18A1C04AB9F0091BED0 /* flux@3x.png in Resources */,
+				1323F18F1C04ABEB0091BED0 /* Thumbnails in Resources */,
+				1323F18B1C04AB9F0091BED0 /* hawk.png in Resources */,
 				13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
 				13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */,
+				1323F1891C04AB9F0091BED0 /* bunny.png in Resources */,
+				1323F18C1C04AB9F0091BED0 /* uie_thumb_big.png in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -842,7 +865,6 @@
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				3D36915B1BDA8CBB007B22D8 /* uie_thumb_big.png in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
diff --git a/Examples/UIExplorer/UIExplorer/Base.lproj/LaunchScreen.xib b/Examples/UIExplorer/UIExplorer/Base.lproj/LaunchScreen.xib
index 3b7dcb4a082b..0556e6641fb0 100644
--- a/Examples/UIExplorer/UIExplorer/Base.lproj/LaunchScreen.xib
+++ b/Examples/UIExplorer/UIExplorer/Base.lproj/LaunchScreen.xib
@@ -1,7 +1,8 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6254" systemVersion="13F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9059" systemVersion="15A284" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
     <dependencies>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6247"/>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9049"/>
         <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
     </dependencies>
     <objects>
@@ -13,17 +14,20 @@
             <subviews>
                 <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="  Copyright (c) 2015 Facebook. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
                     <rect key="frame" x="20" y="439" width="441" height="21"/>
+                    <animations/>
                     <fontDescription key="fontDescription" type="system" pointSize="17"/>
                     <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
                     <nil key="highlightedColor"/>
                 </label>
                 <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="UIExplorer" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
                     <rect key="frame" x="20" y="140" width="441" height="43"/>
+                    <animations/>
                     <fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
                     <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
                     <nil key="highlightedColor"/>
                 </label>
             </subviews>
+            <animations/>
             <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
             <constraints>
                 <constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
diff --git a/Examples/UIExplorer/UIExplorer/Images.xcassets/uie_thumb_big.imageset/Contents.json b/Examples/UIExplorer/UIExplorer/Images.xcassets/uie_thumb_big.imageset/Contents.json
deleted file mode 100644
index cdd15d023904..000000000000
--- a/Examples/UIExplorer/UIExplorer/Images.xcassets/uie_thumb_big.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "filename" : "uie_thumb_big.png",
-      "scale" : "1x"
-    },
-    {
-      "idiom" : "universal",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "universal",
-      "scale" : "3x"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  }
-}
\ No newline at end of file
diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testSliderExample_1@2x.png b/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testSliderExample_1@2x.png
index c38d68b526b0336c3b21be2cf6f5176f68efd2f2..45b9547a82be78b30072e4ce1218b8d0033f141b 100644
GIT binary patch
diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerSnapshotTests.m b/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerSnapshotTests.m
index 2f3639cdc08d..81c11503ca2a 100644
--- a/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerSnapshotTests.m
+++ b/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerSnapshotTests.m
@@ -52,7 +52,7 @@ - (void)test##name                      \
 RCT_TEST(LayoutExample)
 RCT_TEST(TextExample)
 RCT_TEST(SwitchExample)
-RCT_TEST(SliderExample)
+//RCT_TEST(SliderExample) // Disabled: #8985988
 //RCT_TEST(TabBarExample) // Disabled: #8985988
 
 - (void)testZZZNotInRecordMode
diff --git a/Examples/UIExplorer/UIExplorer/Images.xcassets/uie_thumb_big.imageset/uie_thumb_big.png b/Examples/UIExplorer/uie_thumb_big.png
similarity index 100%
rename from Examples/UIExplorer/UIExplorer/Images.xcassets/uie_thumb_big.imageset/uie_thumb_big.png
rename to Examples/UIExplorer/uie_thumb_big.png
diff --git a/Libraries/Components/SliderIOS/SliderIOS.ios.js b/Libraries/Components/SliderIOS/SliderIOS.ios.js
index f151a29b7c67..925f9ad60d34 100644
--- a/Libraries/Components/SliderIOS/SliderIOS.ios.js
+++ b/Libraries/Components/SliderIOS/SliderIOS.ios.js
@@ -83,6 +83,11 @@ var SliderIOS = React.createClass({
      */
     trackImage: Image.propTypes.source,
 
+    /**
+     * Sets an image for the thumb. It only supports static images.
+     */
+    thumbImage: Image.propTypes.source,
+
     /**
      * Callback continuously called while the user is dragging the slider.
      */
@@ -114,7 +119,7 @@ var SliderIOS = React.createClass({
     });
 
     let {style, ...props} = this.props;
-    style = [styles.slider, this.props.style];
+    style = [styles.slider, style];
 
     return (
       <RCTSlider
diff --git a/React/Views/RCTSlider.h b/React/Views/RCTSlider.h
index 0c2269ce8436..83e3d7eadfb1 100644
--- a/React/Views/RCTSlider.h
+++ b/React/Views/RCTSlider.h
@@ -20,5 +20,7 @@
 @property (nonatomic, assign) float lastValue;
 
 @property (nonatomic, strong) UIImage *trackImage;
+@property (nonatomic, strong) UIImage *thumbImage;
+
 
 @end
diff --git a/React/Views/RCTSlider.m b/React/Views/RCTSlider.m
index 0886c8e20ef3..d95f4d6879a4 100644
--- a/React/Views/RCTSlider.m
+++ b/React/Views/RCTSlider.m
@@ -47,4 +47,14 @@ - (void)setTrackImage:(UIImage *)trackImage
   }
 }
 
+- (void)setThumbImage:(UIImage *)thumbImage
+{
+  [self setThumbImage:thumbImage forState:UIControlStateNormal];
+}
+
+- (UIImage *)thumbImage
+{
+  return [self thumbImageForState:UIControlStateNormal];
+}
+
 @end
diff --git a/React/Views/RCTSliderManager.m b/React/Views/RCTSliderManager.m
index 92eb4b7c4709..bdb89ab06f51 100644
--- a/React/Views/RCTSliderManager.m
+++ b/React/Views/RCTSliderManager.m
@@ -83,6 +83,7 @@ - (void)sliderTouchEnd:(RCTSlider *)sender
 RCT_EXPORT_VIEW_PROPERTY(maximumTrackTintColor, UIColor);
 RCT_EXPORT_VIEW_PROPERTY(onValueChange, RCTBubblingEventBlock);
 RCT_EXPORT_VIEW_PROPERTY(onSlidingComplete, RCTBubblingEventBlock);
+RCT_EXPORT_VIEW_PROPERTY(thumbImage, UIImage);
 RCT_CUSTOM_VIEW_PROPERTY(disabled, BOOL, RCTSlider)
 {
   if (json) {

From bd99f31358200252e662dbdf6fae26ead8670101 Mon Sep 17 00:00:00 2001
From: Rajeesh C V <cvrajeesh@gmail.com>
Date: Wed, 25 Nov 2015 12:36:36 +0530
Subject: [PATCH 0098/1411] Add Nalathe Kerala to showcase

---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 5d485df69d2f..52c4c92ee183 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -201,6 +201,12 @@ var apps = [
     link: 'https://itunes.apple.com/in/app/myntra-fashion-shopping-app/id907394059',
     author: 'Myntra Designs',
   },
+  {
+    name: 'Nalathe Kerala',
+    icon: 'https://lh3.googleusercontent.com/5N0WYat5WuFbhi5yR2ccdbqmiZ0wbTtKRG9GhT3YK7Z-qRvmykZyAgk0HNElOxD2JOPr=w300-rw',
+    link: 'https://play.google.com/store/apps/details?id=com.rhyble.nalathekerala',
+    author: 'Rhyble',
+  },
   {
     name: 'Ncredible',
     icon: 'http://a3.mzstatic.com/us/r30/Purple2/v4/a9/00/74/a9007400-7ccf-df10-553b-3b6cb67f3f5f/icon350x350.png',

From aaffb239cab5e730bbe83041fc9404946f2215e3 Mon Sep 17 00:00:00 2001
From: Mike Armstrong <mikea@fb.com>
Date: Wed, 25 Nov 2015 00:49:17 -0800
Subject: [PATCH 0099/1411] Allow the output of the JSC profile to be specified
 in JS

Reviewed By: astreet

Differential Revision: D2674869

fb-gh-sync-id: 15e192015ecc9291359d6c988e793849eac97513
---
 .../src/main/jni/react/JSCLegacyProfiler.cpp      | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/JSCLegacyProfiler.cpp b/ReactAndroid/src/main/jni/react/JSCLegacyProfiler.cpp
index 64f47b00bc3d..5d2a7e499e18 100644
--- a/ReactAndroid/src/main/jni/react/JSCLegacyProfiler.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCLegacyProfiler.cpp
@@ -7,6 +7,7 @@
 #include <jsc_legacy_profiler.h>
 #include "JSCHelpers.h"
 #include "JSCLegacyProfiler.h"
+#include "Value.h"
 
 static JSValueRef nativeProfilerStart(
     JSContextRef ctx,
@@ -20,7 +21,7 @@ static JSValueRef nativeProfilerStart(
     return JSValueMakeUndefined(ctx);
   }
 
-  JSStringRef title = JSValueToStringCopy(ctx, arguments[0], NULL);
+  JSStringRef title = JSValueToStringCopy(ctx, arguments[0], exception);
   JSStartProfiling(ctx, title);
   JSStringRelease(title);
   return JSValueMakeUndefined(ctx);
@@ -38,8 +39,16 @@ static JSValueRef nativeProfilerEnd(
     return JSValueMakeUndefined(ctx);
   }
 
-  JSStringRef title = JSValueToStringCopy(ctx, arguments[0], NULL);
-  JSEndProfilingAndRender(ctx, title, "/sdcard/profile.json");
+  std::string writeLocation("/sdcard/");
+  if (argumentCount > 1) {
+    JSStringRef fileName = JSValueToStringCopy(ctx, arguments[1], exception);
+    writeLocation += facebook::react::String::ref(fileName).str();
+    JSStringRelease(fileName);
+  } else {
+    writeLocation += "profile.json";
+  }
+  JSStringRef title = JSValueToStringCopy(ctx, arguments[0], exception);
+  JSEndProfilingAndRender(ctx, title, writeLocation.c_str());
   JSStringRelease(title);
   return JSValueMakeUndefined(ctx);
 }

From fc5a8678d37685170b5e5e0f4086efdfa2756bab Mon Sep 17 00:00:00 2001
From: Milen Dzhumerov <mgd@fb.com>
Date: Wed, 25 Nov 2015 03:17:50 -0800
Subject: [PATCH 0100/1411] Implement efficient DiskCache.clear()

Summary: public

Ability to efficiently remove all keys with a particular prefix

Reviewed By: tadeuzagallo

Differential Revision: D2658741

fb-gh-sync-id: 3770f061c83288efe645162ae84a9fd9194d2fd6
---
 Libraries/Storage/AsyncStorage.js    | 25 +++++++++++++++++++++++++
 React/Modules/RCTAsyncLocalStorage.m | 18 ++++++++++++++++++
 2 files changed, 43 insertions(+)

diff --git a/Libraries/Storage/AsyncStorage.js b/Libraries/Storage/AsyncStorage.js
index c5be992e2aba..4b3a8e0008bb 100644
--- a/Libraries/Storage/AsyncStorage.js
+++ b/Libraries/Storage/AsyncStorage.js
@@ -137,6 +137,26 @@ var AsyncStorage = {
     });
   },
 
+  /**
+   * Erases all keys with a particular prefix. Useful if all your keys have a
+   * specific prefix.
+   */
+  clearPrefix: function(
+    prefix: string,
+    callback?: ?(error: ?Error) => void
+  ): Promise {
+    return new Promise((resolve, reject) => {
+      RCTAsyncStorage.clearPrefix(prefix, function(error) {
+        callback && callback(convertError(error));
+        if (error && convertError(error)){
+          reject(convertError(error));
+        } else {
+          resolve(null);
+        }
+      });
+    });
+  },
+
   /**
    * Gets *all* keys known to the app, for all callers, libraries, etc. Returns a `Promise` object.
    */
@@ -259,6 +279,11 @@ if (!RCTAsyncStorage.multiMerge) {
   delete AsyncStorage.multiMerge;
 }
 
+// clearPrefix() only supported by certain backends
+if (!RCTAsyncStorage.clearPrefix) {
+  delete AsyncStorage.clearPrefix;
+}
+
 function convertErrors(errs) {
   if (!errs) {
     return null;
diff --git a/React/Modules/RCTAsyncLocalStorage.m b/React/Modules/RCTAsyncLocalStorage.m
index 273ef40c6bf8..eceb15847c2a 100644
--- a/React/Modules/RCTAsyncLocalStorage.m
+++ b/React/Modules/RCTAsyncLocalStorage.m
@@ -435,6 +435,24 @@ - (NSDictionary *)_writeEntry:(NSArray<NSString *> *)entry changedManifest:(BOOL
   callback(@[RCTNullIfNil(error)]);
 }
 
+RCT_EXPORT_METHOD(clearPrefix:(NSString *)prefix callack:(RCTResponseSenderBlock)callback)
+{
+  NSDictionary *errorOut = [self _ensureSetup];
+  if (errorOut) {
+    callback(@[errorOut]);
+    return;
+  }
+
+  NSMutableArray<NSString *> *keys = [NSMutableArray array];
+  for (NSString *key in _manifest.allKeys) {
+    if ([key hasPrefix:prefix]) {
+      [keys addObject:key];
+    }
+  }
+
+  [self multiRemove:keys callback:callback];
+}
+
 RCT_EXPORT_METHOD(getAllKeys:(RCTResponseSenderBlock)callback)
 {
   NSDictionary *errorOut = [self _ensureSetup];

From 38db6fa4658e8074a91f2c541bee3d00fe3ea50a Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Wed, 25 Nov 2015 03:07:06 -0800
Subject: [PATCH 0101/1411] Remove scrollview support from UIManager, remove
 mainScrollView(delegate)

Reviewed By: nicklockwood

Differential Revision: D2692749

fb-gh-sync-id: 48975d2f09f3b2902dfa2e56ff9d34257b2395bc
---
 Libraries/Components/ScrollResponder.js       | 34 +++++-----
 Libraries/Components/ScrollView/ScrollView.js |  1 -
 React/Modules/RCTUIManager.h                  | 13 ----
 React/Modules/RCTUIManager.m                  | 67 -------------------
 React/Views/RCTScrollView.m                   | 14 ++--
 React/Views/RCTScrollViewManager.h            |  1 -
 React/Views/RCTScrollViewManager.m            | 40 +++++++++--
 React/Views/RCTScrollableProtocol.h           |  2 +-
 .../react/uimanager/UIManagerModule.java      |  5 --
 9 files changed, 62 insertions(+), 115 deletions(-)

diff --git a/Libraries/Components/ScrollResponder.js b/Libraries/Components/ScrollResponder.js
index 75ceb561d522..3374cf22d53e 100644
--- a/Libraries/Components/ScrollResponder.js
+++ b/Libraries/Components/ScrollResponder.js
@@ -12,18 +12,19 @@
 'use strict';
 
 var Dimensions = require('Dimensions');
-var NativeModules = require('NativeModules');
 var Platform = require('Platform');
 var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
 var React = require('React');
 var Subscribable = require('Subscribable');
 var TextInputState = require('TextInputState');
 
-var RCTUIManager = NativeModules.UIManager;
-var RCTScrollViewConsts = RCTUIManager.RCTScrollView.Constants;
+var { UIManager, ScrollViewManager } = require('NativeModules');
 
+var invariant = require('invariant');
 var warning = require('warning');
 
+import type ReactComponent from 'ReactComponent';
+
 /**
  * Mixin that can be integrated in order to handle scrolling that plays well
  * with `ResponderEventPlugin`. Integrate with your platform specific scroll
@@ -115,7 +116,6 @@ type Event = Object;
 
 var ScrollResponderMixin = {
   mixins: [Subscribable.Mixin],
-  statics: RCTScrollViewConsts,
   scrollResponderMixinGetInitialState: function(): State {
     return {
       isTouching: false,
@@ -353,16 +353,15 @@ var ScrollResponderMixin = {
    */
   scrollResponderScrollTo: function(offsetX: number, offsetY: number) {
     if (Platform.OS === 'android') {
-      RCTUIManager.dispatchViewManagerCommand(
+      UIManager.dispatchViewManagerCommand(
         React.findNodeHandle(this),
-        RCTUIManager.RCTScrollView.Commands.scrollTo,
+        UIManager.RCTScrollView.Commands.scrollTo,
         [Math.round(offsetX), Math.round(offsetY)],
       );
     } else {
-      RCTUIManager.scrollTo(
+      ScrollViewManager.scrollTo(
         React.findNodeHandle(this),
-        offsetX,
-        offsetY,
+        { x: offsetX, y: offsetY }
       );
     }
   },
@@ -373,16 +372,15 @@ var ScrollResponderMixin = {
    */
   scrollResponderScrollWithouthAnimationTo: function(offsetX: number, offsetY: number) {
     if (Platform.OS === 'android') {
-      RCTUIManager.dispatchViewManagerCommand(
+      UIManager.dispatchViewManagerCommand(
         React.findNodeHandle(this),
-        RCTUIManager.RCTScrollView.Commands.scrollWithoutAnimationTo,
+        UIManager.RCTScrollView.Commands.scrollWithoutAnimationTo,
         [offsetX, offsetY],
       );
     } else {
-      RCTUIManager.scrollWithoutAnimationTo(
+      ScrollViewManager.scrollWithoutAnimationTo(
         React.findNodeHandle(this),
-        offsetX,
-        offsetY
+        { x: offsetX, y: offsetY }
       );
     }
   },
@@ -392,7 +390,11 @@ var ScrollResponderMixin = {
    * @param {object} rect Should have shape {x, y, width, height}
    */
   scrollResponderZoomTo: function(rect: { x: number; y: number; width: number; height: number; }) {
-    RCTUIManager.zoomToRect(React.findNodeHandle(this), rect);
+    if (Platform.OS === 'android') {
+      invariant('zoomToRect is not implemented');
+    } else {
+      ScrollViewManager.zoomToRect(React.findNodeHandle(this), rect);
+    }
   },
 
   /**
@@ -408,7 +410,7 @@ var ScrollResponderMixin = {
   scrollResponderScrollNativeHandleToKeyboard: function(nodeHandle: any, additionalOffset?: number, preventNegativeScrollOffset?: bool) {
     this.additionalScrollOffset = additionalOffset || 0;
     this.preventNegativeScrollOffset = !!preventNegativeScrollOffset;
-    RCTUIManager.measureLayout(
+    UIManager.measureLayout(
       nodeHandle,
       React.findNodeHandle(this.getInnerViewNode()),
       this.scrollResponderTextInputFocusError,
diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js
index 62b619ca381a..8069b9647be5 100644
--- a/Libraries/Components/ScrollView/ScrollView.js
+++ b/Libraries/Components/ScrollView/ScrollView.js
@@ -18,7 +18,6 @@ var RCTScrollView = require('NativeModules').UIManager.RCTScrollView;
 var RCTScrollViewManager = require('NativeModules').ScrollViewManager;
 var React = require('React');
 var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
-var RCTUIManager = require('NativeModules').UIManager;
 var ScrollResponder = require('ScrollResponder');
 var StyleSheet = require('StyleSheet');
 var StyleSheetPropType = require('StyleSheetPropType');
diff --git a/React/Modules/RCTUIManager.h b/React/Modules/RCTUIManager.h
index 9fd8cb7e8f3d..daaf40ac2e91 100644
--- a/React/Modules/RCTUIManager.h
+++ b/React/Modules/RCTUIManager.h
@@ -44,19 +44,6 @@ RCT_EXTERN NSString *const RCTUIManagerRootViewKey;
  */
 @interface RCTUIManager : NSObject <RCTBridgeModule, RCTInvalidating>
 
-/**
- * The UIIManager has the concept of a designated "main scroll view", which is
- * useful for apps built around a central scrolling content area (e.g. a
- * timeline).
- */
-@property (nonatomic, weak) id<RCTScrollableProtocol> mainScrollView;
-
-/**
- * Allows native environment code to respond to "the main scroll view" events.
- * see `RCTUIManager`'s `setMainScrollViewTag`.
- */
-@property (nonatomic, readwrite, weak) id<UIScrollViewDelegate> nativeMainScrollDelegate;
-
 /**
  * Register a root view with the RCTUIManager.
  */
diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m
index 679e84767553..a15d2516421b 100644
--- a/React/Modules/RCTUIManager.m
+++ b/React/Modules/RCTUIManager.m
@@ -1095,73 +1095,6 @@ static void RCTMeasureLayout(RCTShadowView *view,
   callback(@[results]);
 }
 
-RCT_EXPORT_METHOD(setMainScrollViewTag:(nonnull NSNumber *)reactTag)
-{
-  [self addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
-    // - There should be at most one designated "main scroll view"
-    // - There should be at most one designated "`nativeMainScrollDelegate`"
-    // - The one designated main scroll view should have the one designated
-    // `nativeMainScrollDelegate` set as its `nativeMainScrollDelegate`.
-    if (uiManager.mainScrollView) {
-      uiManager.mainScrollView.nativeMainScrollDelegate = nil;
-    }
-    id view = viewRegistry[reactTag];
-    if (view) {
-      if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
-        uiManager.mainScrollView = (id<RCTScrollableProtocol>)view;
-        uiManager.mainScrollView.nativeMainScrollDelegate = uiManager.nativeMainScrollDelegate;
-      } else {
-        RCTLogError(@"Tag #%@ does not conform to RCTScrollableProtocol", reactTag);
-      }
-    } else {
-      uiManager.mainScrollView = nil;
-    }
-  }];
-}
-
-// TODO: we could just pass point property
-RCT_EXPORT_METHOD(scrollTo:(nonnull NSNumber *)reactTag
-                  withOffsetX:(CGFloat)offsetX
-                  offsetY:(CGFloat)offsetY)
-{
-  [self addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry){
-    UIView *view = viewRegistry[reactTag];
-    if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
-      [(id<RCTScrollableProtocol>)view scrollToOffset:(CGPoint){offsetX, offsetY} animated:YES];
-    } else {
-      RCTLogError(@"tried to scrollToOffset: on non-RCTScrollableProtocol view %@ with tag #%@", view, reactTag);
-    }
-  }];
-}
-
-// TODO: we could just pass point property
-RCT_EXPORT_METHOD(scrollWithoutAnimationTo:(nonnull NSNumber *)reactTag
-                  offsetX:(CGFloat)offsetX
-                  offsetY:(CGFloat)offsetY)
-{
-    [self addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry){
-        UIView *view = viewRegistry[reactTag];
-        if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
-            [(id<RCTScrollableProtocol>)view scrollToOffset:(CGPoint){offsetX, offsetY} animated:NO];
-        } else {
-            RCTLogError(@"tried to scrollToOffset: on non-RCTScrollableProtocol view %@ with tag #%@", view, reactTag);
-        }
-    }];
-}
-
-RCT_EXPORT_METHOD(zoomToRect:(nonnull NSNumber *)reactTag
-                  withRect:(CGRect)rect)
-{
-  [self addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry){
-    UIView *view = viewRegistry[reactTag];
-    if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
-      [(id<RCTScrollableProtocol>)view zoomToRect:rect animated:YES];
-    } else {
-      RCTLogError(@"tried to zoomToRect: on non-RCTScrollableProtocol view %@ with tag #%@", view, reactTag);
-    }
-  }];
-}
-
 /**
  * JS sets what *it* considers to be the responder. Later, scroll views can use
  * this in order to determine if scrolling is appropriate.
diff --git a/React/Views/RCTScrollView.m b/React/Views/RCTScrollView.m
index 2dc6f3886807..f1ef89572119 100644
--- a/React/Views/RCTScrollView.m
+++ b/React/Views/RCTScrollView.m
@@ -375,7 +375,7 @@ @implementation RCTScrollView
   CGRect _lastClippedToRect;
 }
 
-@synthesize nativeMainScrollDelegate = _nativeMainScrollDelegate;
+@synthesize nativeScrollDelegate = _nativeScrollDelegate;
 
 - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
 {
@@ -542,14 +542,14 @@ - (void)refreshContentInset
 - (void)delegateMethod:(UIScrollView *)scrollView           \
 {                                                           \
   [_eventDispatcher sendScrollEventWithType:eventName reactTag:self.reactTag scrollView:scrollView userData:nil]; \
-  if ([_nativeMainScrollDelegate respondsToSelector:_cmd]) { \
-    [_nativeMainScrollDelegate delegateMethod:scrollView]; \
+  if ([_nativeScrollDelegate respondsToSelector:_cmd]) { \
+    [_nativeScrollDelegate delegateMethod:scrollView]; \
   } \
 }
 
 #define RCT_FORWARD_SCROLL_EVENT(call) \
-if ([_nativeMainScrollDelegate respondsToSelector:_cmd]) { \
-  [_nativeMainScrollDelegate call]; \
+if ([_nativeScrollDelegate respondsToSelector:_cmd]) { \
+  [_nativeScrollDelegate call]; \
 }
 
 RCT_SCROLL_EVENT_HANDLER(scrollViewDidEndScrollingAnimation, RCTScrollEventTypeEndDeceleration)
@@ -706,8 +706,8 @@ - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)vi
 
 - (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView
 {
-  if ([_nativeMainScrollDelegate respondsToSelector:_cmd]) {
-    return [_nativeMainScrollDelegate scrollViewShouldScrollToTop:scrollView];
+  if ([_nativeScrollDelegate respondsToSelector:_cmd]) {
+    return [_nativeScrollDelegate scrollViewShouldScrollToTop:scrollView];
   }
   return YES;
 }
diff --git a/React/Views/RCTScrollViewManager.h b/React/Views/RCTScrollViewManager.h
index 83b3126e8f1c..a53bf4c80796 100644
--- a/React/Views/RCTScrollViewManager.h
+++ b/React/Views/RCTScrollViewManager.h
@@ -19,4 +19,3 @@
 @interface RCTScrollViewManager : RCTViewManager
 
 @end
-
diff --git a/React/Views/RCTScrollViewManager.m b/React/Views/RCTScrollViewManager.m
index fdefe32cc463..702b75043944 100644
--- a/React/Views/RCTScrollViewManager.m
+++ b/React/Views/RCTScrollViewManager.m
@@ -70,7 +70,6 @@ - (UIView *)view
 - (NSDictionary<NSString *, id> *)constantsToExport
 {
   return @{
-    // TODO: unused - remove these?
     @"DecelerationRate": @{
       @"normal": @(UIScrollViewDecelerationRateNormal),
       @"fast": @(UIScrollViewDecelerationRateFast),
@@ -118,7 +117,7 @@ - (UIView *)view
 RCT_EXPORT_METHOD(endRefreshing:(nonnull NSNumber *)reactTag)
 {
   [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTScrollView *> *viewRegistry) {
-    
+
     RCTScrollView *view = viewRegistry[reactTag];
     if (!view || ![view isKindOfClass:[RCTScrollView class]]) {
       RCTLogError(@"Cannot find RCTScrollView with tag #%@", reactTag);
@@ -126,10 +125,44 @@ - (UIView *)view
     }
 
     [view endRefreshing];
-    
   }];
 }
 
+RCT_EXPORT_METHOD(scrollTo:(nonnull NSNumber *)reactTag withOffset:(CGPoint)offset)
+{
+  [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry){
+    UIView *view = viewRegistry[reactTag];
+    if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
+      [(id<RCTScrollableProtocol>)view scrollToOffset:offset animated:YES];
+    } else {
+      RCTLogError(@"tried to scrollToOffset: on non-RCTScrollableProtocol view %@ with tag #%@", view, reactTag);
+    }
+  }];
+}
+
+RCT_EXPORT_METHOD(scrollWithoutAnimationTo:(nonnull NSNumber *)reactTag withOffset:(CGPoint)offset)
+{
+    [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry){
+        UIView *view = viewRegistry[reactTag];
+        if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
+          [(id<RCTScrollableProtocol>)view scrollToOffset:offset animated:NO];
+        } else {
+          RCTLogError(@"tried to scrollToOffset: on non-RCTScrollableProtocol view %@ with tag #%@", view, reactTag);
+        }
+    }];
+}
+
+RCT_EXPORT_METHOD(zoomToRect:(nonnull NSNumber *)reactTag withRect:(CGRect)rect)
+{
+  [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry){
+    UIView *view = viewRegistry[reactTag];
+    if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
+      [(id<RCTScrollableProtocol>)view zoomToRect:rect animated:YES];
+    } else {
+      RCTLogError(@"tried to zoomToRect: on non-RCTScrollableProtocol view %@ with tag #%@", view, reactTag);
+    }
+  }];
+}
 
 - (NSArray<NSString *> *)customDirectEventTypes
 {
@@ -144,4 +177,3 @@ - (UIView *)view
 }
 
 @end
-
diff --git a/React/Views/RCTScrollableProtocol.h b/React/Views/RCTScrollableProtocol.h
index f612a7afa2cc..f871d51925d4 100644
--- a/React/Views/RCTScrollableProtocol.h
+++ b/React/Views/RCTScrollableProtocol.h
@@ -15,7 +15,7 @@
  */
 @protocol RCTScrollableProtocol
 
-@property (nonatomic, weak) NSObject<UIScrollViewDelegate> *nativeMainScrollDelegate;
+@property (nonatomic, weak) NSObject<UIScrollViewDelegate> *nativeScrollDelegate;
 @property (nonatomic, readonly) CGSize contentSize;
 
 - (void)scrollToOffset:(CGPoint)offset;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
index 67b171ee9a34..38e78cc65b66 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
@@ -719,11 +719,6 @@ public void showPopupMenu(
     mOperationsQueue.enqueueShowPopupMenu(reactTag, items, error, success);
   }
 
-  @ReactMethod
-  public void setMainScrollViewTag(int reactTag) {
-    // TODO(6588266): Implement if required
-  }
-
   @ReactMethod
   public void configureNextLayoutAnimation(
       ReadableMap config,

From bba71f146d011ea9674275b00ddf4861880436a7 Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Wed, 25 Nov 2015 03:00:23 -0800
Subject: [PATCH 0102/1411] Defer rendering events popover until required

Reviewed By: davidaurelio

Differential Revision: D2690835

fb-gh-sync-id: 1d17c20b308e364c49f868d8861c6ad93957bffe
---
 Libraries/ReactNative/ReactNativeDefaultInjection.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Libraries/ReactNative/ReactNativeDefaultInjection.js b/Libraries/ReactNative/ReactNativeDefaultInjection.js
index 5185af953d31..3ee1675c31dd 100644
--- a/Libraries/ReactNative/ReactNativeDefaultInjection.js
+++ b/Libraries/ReactNative/ReactNativeDefaultInjection.js
@@ -86,6 +86,7 @@ function inject() {
     validAttributes: {},
     uiViewClassName: 'RCTView',
   });
+  // TODO #9121531: make this position: absolute; by default, to avoid interfering with flexbox
   ReactEmptyComponent.injection.injectEmptyComponent(RCTView);
 
   EventPluginUtils.injection.injectMount(ReactNativeMount);

From 060664fd3d9331f062696e68179bac9cd4544a06 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Wed, 25 Nov 2015 03:09:00 -0800
Subject: [PATCH 0103/1411] Refactored module access to allow for lazy loading

Summary: public

The `bridge.modules` dictionary provides access to all native modules, but this API requires that every module is initialized in advance so that any module can be accessed.

This diff introduces a better API that will allow modules to be initialized lazily as they are needed, and deprecates `bridge.modules` (modules that use it will still work, but should be rewritten to use `bridge.moduleClasses` or `-[bridge moduleForName/Class:` instead.

The rules are now as follows:

* Any module that overrides `init` or `setBridge:` will be initialized on the main thread when the bridge is created
* Any module that implements `constantsToExport:` will be initialized later when the config is exported (the module itself will be initialized on a background queue, but  `constantsToExport:` will still be called on the main thread.
* All other modules will be initialized lazily when a method is first called on them.

These rules may seem slightly arcane, but they have the advantage of not violating any assumptions that may have been made by existing code - any module written under the original assumption that it would be initialized synchronously on the main thread when the bridge is created should still function exactly the same, but modules that avoid overriding `init` or `setBridge:` will now be loaded lazily.

I've rewritten most of the standard modules to take advantage of this new lazy loading, with the following results:

Out of the 65 modules included in UIExplorer:

* 16 are initialized on the main thread when the bridge is created
* A further 8 are initialized when the config is exported to JS
* The remaining 41 will be initialized lazily on-demand

Reviewed By: jspahrsummers

Differential Revision: D2677695

fb-gh-sync-id: 507ae7e9fd6b563e89292c7371767c978e928f33
---
 .../FlexibleSizeExampleView.m                 |   3 +-
 .../RCTEventDispatcherTests.m                 |   2 +-
 .../UIExplorerUnitTests/RCTGzipTests.m        |  22 +-
 .../CameraRoll/RCTAssetsLibraryImageLoader.m  |   2 +-
 Libraries/CameraRoll/RCTImagePickerManager.m  |  65 +++--
 Libraries/Geolocation/RCTLocationObserver.m   |  20 +-
 Libraries/Image/RCTImageLoader.m              |  46 ++--
 Libraries/Image/RCTImageStoreManager.m        |  17 +-
 Libraries/LinkingIOS/RCTLinkingManager.m      |  27 +--
 Libraries/Network/RCTHTTPRequestHandler.m     |  19 +-
 Libraries/Network/RCTNetworking.m             |  66 +++---
 .../RCTPushNotificationManager.m              |  41 ++--
 Libraries/RCTTest/RCTTestModule.m             |  11 +-
 Libraries/RCTTest/RCTTestRunner.m             |   3 +-
 Libraries/Settings/RCTSettingsManager.h       |   2 +-
 Libraries/Settings/RCTSettingsManager.m       |  35 +--
 Libraries/WebSocket/RCTWebSocketExecutor.h    |   2 +-
 Libraries/WebSocket/RCTWebSocketExecutor.m    |  23 +-
 Libraries/WebSocket/RCTWebSocketModule.m      |  11 +-
 React/Base/RCTBatchedBridge.m                 | 223 ++++++++++++------
 React/Base/RCTBridge.h                        |  37 ++-
 React/Base/RCTBridge.m                        |  34 ++-
 React/Base/RCTBridgeModule.h                  |   2 +-
 React/Base/RCTEventDispatcher.m               |  12 +-
 React/Base/RCTKeyboardObserver.m              |  23 +-
 React/Base/RCTModuleData.h                    |  54 ++++-
 React/Base/RCTModuleData.m                    | 124 ++++++----
 React/Base/RCTModuleMap.h                     |  16 --
 React/Base/RCTModuleMap.m                     |  79 -------
 React/Base/RCTPerformanceLogger.m             |  15 +-
 React/Base/RCTUtils.h                         |   4 +
 React/Base/RCTUtils.m                         |  31 ++-
 React/Modules/RCTAccessibilityManager.m       |   4 +-
 React/Modules/RCTAlertManager.m               |  21 +-
 React/Modules/RCTAppState.m                   |  29 ++-
 React/Modules/RCTDevLoadingView.m             |  27 +--
 React/Modules/RCTDevMenu.m                    |   4 +-
 React/Modules/RCTExceptionsManager.h          |   2 +-
 React/Modules/RCTExceptionsManager.m          |   8 +-
 React/Modules/RCTRedBox.m                     |   7 +-
 React/Modules/RCTStatusBarManager.m           |  13 +-
 React/Modules/RCTUIManager.m                  |  85 ++++---
 React/Profiler/RCTProfile.m                   |  11 +-
 React/Profiler/RCTProfileTrampoline-arm.S     |   9 +
 React/Profiler/RCTProfileTrampoline-arm64.S   |   9 +
 React/Profiler/RCTProfileTrampoline-i386.S    |   9 +
 React/Profiler/RCTProfileTrampoline-x86_64.S  |   9 +
 React/React.xcodeproj/project.pbxproj         |  12 +-
 React/Views/RCTComponentData.h                |   5 +-
 React/Views/RCTComponentData.m                |  41 ++--
 React/Views/RCTModalHostViewController.m      |   3 +-
 React/Views/RCTModalHostViewManager.m         |  12 +-
 React/Views/RCTViewManager.h                  |   2 +-
 React/Views/RCTViewManager.m                  |   5 -
 54 files changed, 754 insertions(+), 644 deletions(-)
 delete mode 100644 React/Base/RCTModuleMap.h
 delete mode 100644 React/Base/RCTModuleMap.m

diff --git a/Examples/UIExplorer/UIExplorer/NativeExampleViews/FlexibleSizeExampleView.m b/Examples/UIExplorer/UIExplorer/NativeExampleViews/FlexibleSizeExampleView.m
index 134d128cf835..ce899207027a 100644
--- a/Examples/UIExplorer/UIExplorer/NativeExampleViews/FlexibleSizeExampleView.m
+++ b/Examples/UIExplorer/UIExplorer/NativeExampleViews/FlexibleSizeExampleView.m
@@ -52,8 +52,7 @@ @implementation FlexibleSizeExampleView
 
 - (instancetype)initWithFrame:(CGRect)frame
 {
-  self = [super initWithFrame:frame];
-  if (self) {
+  if ((self = [super initWithFrame:frame])) {
     _sizeUpdated = NO;
 
     AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m
index 5761849d69d4..e0406d49727f 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m
@@ -62,7 +62,7 @@ - (void)setUp
 
   _bridge = [OCMockObject mockForClass:[RCTBridge class]];
   _eventDispatcher = [RCTEventDispatcher new];
-  ((id<RCTBridgeModule>)_eventDispatcher).bridge = _bridge;
+  [_eventDispatcher setValue:_bridge forKey:@"bridge"];
 
   _eventName = RCTNormalizeInputEventName(@"sampleEvent");
   _body = @{ @"foo": @"bar" };
diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTGzipTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTGzipTests.m
index 69162a764e07..55b53e48dbd1 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTGzipTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTGzipTests.m
@@ -16,6 +16,15 @@
 #import "RCTUtils.h"
 #import "RCTNetworking.h"
 
+#define RUN_RUNLOOP_WHILE(CONDITION) \
+_Pragma("clang diagnostic push") \
+_Pragma("clang diagnostic ignored \"-Wshadow\"") \
+NSDate *timeout = [[NSDate date] dateByAddingTimeInterval:5]; \
+while ((CONDITION) && [timeout timeIntervalSinceNow] > 0) { \
+  [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:timeout]; \
+} \
+_Pragma("clang diagnostic pop")
+
 extern BOOL RCTIsGzippedData(NSData *data);
 
 @interface RCTNetworking (Private)
@@ -61,18 +70,21 @@ - (void)testDontRezipZippedData
 - (void)testRequestBodyEncoding
 {
   NSDictionary *query = @{
-                          @"url": @"http://example.com",
-                          @"method": @"POST",
-                          @"data": @{@"string": @"Hello World"},
-                          @"headers": @{@"Content-Encoding": @"gzip"},
-                          };
+    @"url": @"http://example.com",
+    @"method": @"POST",
+    @"data": @{@"string": @"Hello World"},
+    @"headers": @{@"Content-Encoding": @"gzip"},
+  };
 
   RCTNetworking *networker = [RCTNetworking new];
+  [networker setValue:dispatch_get_main_queue() forKey:@"methodQueue"];
   __block NSURLRequest *request = nil;
   [networker buildRequest:query completionBlock:^(NSURLRequest *_request) {
     request = _request;
   }];
 
+  RUN_RUNLOOP_WHILE(request == nil);
+
   XCTAssertNotNil(request);
   XCTAssertNotNil(request.HTTPBody);
   XCTAssertTrue(RCTIsGzippedData(request.HTTPBody));
diff --git a/Libraries/CameraRoll/RCTAssetsLibraryImageLoader.m b/Libraries/CameraRoll/RCTAssetsLibraryImageLoader.m
index 9b49742ace43..f5cd3cb25cec 100644
--- a/Libraries/CameraRoll/RCTAssetsLibraryImageLoader.m
+++ b/Libraries/CameraRoll/RCTAssetsLibraryImageLoader.m
@@ -151,7 +151,7 @@ @implementation RCTBridge (RCTAssetsLibraryImageLoader)
 
 - (ALAssetsLibrary *)assetsLibrary
 {
-  return [self.modules[RCTBridgeModuleNameForClass([RCTAssetsLibraryImageLoader class])] assetsLibrary];
+  return [[self moduleForClass:[RCTAssetsLibraryImageLoader class]] assetsLibrary];
 }
 
 @end
diff --git a/Libraries/CameraRoll/RCTImagePickerManager.m b/Libraries/CameraRoll/RCTImagePickerManager.m
index 87071863b8b5..0ad9e8e71ec4 100644
--- a/Libraries/CameraRoll/RCTImagePickerManager.m
+++ b/Libraries/CameraRoll/RCTImagePickerManager.m
@@ -32,16 +32,6 @@ @implementation RCTImagePickerManager
 
 RCT_EXPORT_MODULE(ImagePickerIOS);
 
-- (instancetype)init
-{
-  if ((self = [super init])) {
-    _pickers = [NSMutableArray new];
-    _pickerCallbacks = [NSMutableArray new];
-    _pickerCancelCallbacks = [NSMutableArray new];
-  }
-  return self;
-}
-
 - (dispatch_queue_t)methodQueue
 {
   return dispatch_get_main_queue();
@@ -67,8 +57,6 @@ - (dispatch_queue_t)methodQueue
     return;
   }
 
-  UIViewController *rootViewController = RCTKeyWindow().rootViewController;
-
   UIImagePickerController *imagePicker = [UIImagePickerController new];
   imagePicker.delegate = self;
   imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
@@ -77,11 +65,9 @@ - (dispatch_queue_t)methodQueue
     imagePicker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModeVideo;
   }
 
-  [_pickers addObject:imagePicker];
-  [_pickerCallbacks addObject:callback];
-  [_pickerCancelCallbacks addObject:cancelCallback];
-
-  [rootViewController presentViewController:imagePicker animated:YES completion:nil];
+  [self _presentPicker:imagePicker
+       successCallback:callback
+        cancelCallback:cancelCallback];
 }
 
 RCT_EXPORT_METHOD(openSelectDialog:(NSDictionary *)config
@@ -93,8 +79,6 @@ - (dispatch_queue_t)methodQueue
     return;
   }
 
-  UIViewController *rootViewController = RCTKeyWindow().rootViewController;
-
   UIImagePickerController *imagePicker = [UIImagePickerController new];
   imagePicker.delegate = self;
   imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
@@ -109,30 +93,43 @@ - (dispatch_queue_t)methodQueue
 
   imagePicker.mediaTypes = allowedTypes;
 
-  [_pickers addObject:imagePicker];
-  [_pickerCallbacks addObject:callback];
-  [_pickerCancelCallbacks addObject:cancelCallback];
-
-  [rootViewController presentViewController:imagePicker animated:YES completion:nil];
+  [self _presentPicker:imagePicker
+       successCallback:callback
+        cancelCallback:cancelCallback];
 }
 
 - (void)imagePickerController:(UIImagePickerController *)picker
 didFinishPickingMediaWithInfo:(NSDictionary<NSString *, id> *)info
 {
-  NSUInteger index = [_pickers indexOfObject:picker];
-  RCTResponseSenderBlock callback = _pickerCallbacks[index];
+  [self _dismissPicker:picker args:@[
+    [info[UIImagePickerControllerReferenceURL] absoluteString]
+  ]];
+}
 
-  [_pickers removeObjectAtIndex:index];
-  [_pickerCallbacks removeObjectAtIndex:index];
-  [_pickerCancelCallbacks removeObjectAtIndex:index];
+- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
+{
+  [self _dismissPicker:picker args:nil];
+}
 
-  UIViewController *rootViewController = RCTKeyWindow().rootViewController;
-  [rootViewController dismissViewControllerAnimated:YES completion:nil];
+- (void)_presentPicker:(UIImagePickerController *)imagePicker
+       successCallback:(RCTResponseSenderBlock)callback
+        cancelCallback:(RCTResponseSenderBlock)cancelCallback
+{
+  if (!_pickers) {
+    _pickers = [NSMutableArray new];
+    _pickerCallbacks = [NSMutableArray new];
+    _pickerCancelCallbacks = [NSMutableArray new];
+  }
+
+  [_pickers addObject:imagePicker];
+  [_pickerCallbacks addObject:callback];
+  [_pickerCancelCallbacks addObject:cancelCallback];
 
-  callback(@[[info[UIImagePickerControllerReferenceURL] absoluteString]]);
+  UIViewController *rootViewController = RCTKeyWindow().rootViewController;
+  [rootViewController presentViewController:imagePicker animated:YES completion:nil];
 }
 
-- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
+- (void)_dismissPicker:(UIImagePickerController *)picker args:(NSArray *)args
 {
   NSUInteger index = [_pickers indexOfObject:picker];
   RCTResponseSenderBlock callback = _pickerCancelCallbacks[index];
@@ -144,7 +141,7 @@ - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
   UIViewController *rootViewController = RCTKeyWindow().rootViewController;
   [rootViewController dismissViewControllerAnimated:YES completion:nil];
 
-  callback(@[]);
+  callback(args ?: @[]);
 }
 
 @end
diff --git a/Libraries/Geolocation/RCTLocationObserver.m b/Libraries/Geolocation/RCTLocationObserver.m
index ab02bd5824fd..9f9d57aa247f 100644
--- a/Libraries/Geolocation/RCTLocationObserver.m
+++ b/Libraries/Geolocation/RCTLocationObserver.m
@@ -111,19 +111,6 @@ @implementation RCTLocationObserver
 
 #pragma mark - Lifecycle
 
-- (instancetype)init
-{
-  if ((self = [super init])) {
-
-    _locationManager = [CLLocationManager new];
-    _locationManager.distanceFilter = RCT_DEFAULT_LOCATION_ACCURACY;
-    _locationManager.delegate = self;
-
-    _pendingRequests = [NSMutableArray new];
-  }
-  return self;
-}
-
 - (void)dealloc
 {
   [_locationManager stopUpdatingLocation];
@@ -139,6 +126,13 @@ - (dispatch_queue_t)methodQueue
 
 - (void)beginLocationUpdates
 {
+  if (!_locationManager) {
+    _locationManager = [CLLocationManager new];
+    _locationManager.distanceFilter = RCT_DEFAULT_LOCATION_ACCURACY;
+    _locationManager.delegate = self;
+    _pendingRequests = [NSMutableArray new];
+  }
+
   // Request location access permission
   if ([_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
     [_locationManager requestWhenInUseAuthorization];
diff --git a/Libraries/Image/RCTImageLoader.m b/Libraries/Image/RCTImageLoader.m
index 7f67b53b7fda..acee9dbecea4 100644
--- a/Libraries/Image/RCTImageLoader.m
+++ b/Libraries/Image/RCTImageLoader.m
@@ -45,17 +45,17 @@ @implementation RCTImageLoader
 
 RCT_EXPORT_MODULE()
 
-- (void)setBridge:(RCTBridge *)bridge
+- (void)setUp
 {
   // Get image loaders and decoders
   NSMutableArray<id<RCTImageURLLoader>> *loaders = [NSMutableArray array];
   NSMutableArray<id<RCTImageDataDecoder>> *decoders = [NSMutableArray array];
-  for (id<RCTBridgeModule> module in bridge.modules.allValues) {
-    if ([module conformsToProtocol:@protocol(RCTImageURLLoader)]) {
-      [loaders addObject:(id<RCTImageURLLoader>)module];
+  for (Class moduleClass in _bridge.moduleClasses) {
+    if ([moduleClass conformsToProtocol:@protocol(RCTImageURLLoader)]) {
+      [loaders addObject:[_bridge moduleForClass:moduleClass]];
     }
-    if ([module conformsToProtocol:@protocol(RCTImageDataDecoder)]) {
-      [decoders addObject:(id<RCTImageDataDecoder>)module];
+    if ([moduleClass conformsToProtocol:@protocol(RCTImageDataDecoder)]) {
+      [decoders addObject:[_bridge moduleForClass:moduleClass]];
     }
   }
 
@@ -85,17 +85,16 @@ - (void)setBridge:(RCTBridge *)bridge
     }
   }];
 
-  _bridge = bridge;
   _loaders = loaders;
   _decoders = decoders;
-  _URLCacheQueue = dispatch_queue_create("com.facebook.react.ImageLoaderURLCacheQueue", DISPATCH_QUEUE_SERIAL);
-  _URLCache = [[NSURLCache alloc] initWithMemoryCapacity:5 * 1024 * 1024 // 5MB
-                                            diskCapacity:200 * 1024 * 1024 // 200MB
-                                                diskPath:@"React/RCTImageDownloader"];
 }
 
 - (id<RCTImageURLLoader>)imageURLLoaderForURL:(NSURL *)URL
 {
+  if (!_loaders) {
+    [self setUp];
+  }
+
   if (RCT_DEBUG) {
     // Check for handler conflicts
     float previousPriority = 0;
@@ -133,6 +132,10 @@ - (void)setBridge:(RCTBridge *)bridge
 
 - (id<RCTImageDataDecoder>)imageDataDecoderForData:(NSData *)data
 {
+  if (!_decoders) {
+    [self setUp];
+  }
+
   if (RCT_DEBUG) {
     // Check for handler conflicts
     float previousPriority = 0;
@@ -212,7 +215,17 @@ - (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag
   }
 
   // All access to URL cache must be serialized
+  if (!_URLCacheQueue) {
+    _URLCacheQueue = dispatch_queue_create("com.facebook.react.ImageLoaderURLCacheQueue", DISPATCH_QUEUE_SERIAL);
+  }
   dispatch_async(_URLCacheQueue, ^{
+
+    if (!_URLCache) {
+      _URLCache = [[NSURLCache alloc] initWithMemoryCapacity:5 * 1024 * 1024 // 5MB
+                                                diskCapacity:200 * 1024 * 1024 // 200MB
+                                                    diskPath:@"React/RCTImageDownloader"];
+    }
+
     RCTImageLoader *strongSelf = weakSelf;
     if (cancelled || !strongSelf) {
       return;
@@ -385,14 +398,7 @@ - (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)data
 
 - (BOOL)canHandleRequest:(NSURLRequest *)request
 {
-  NSURL *requestURL = request.URL;
-  for (id<RCTBridgeModule> module in _bridge.modules.allValues) {
-    if ([module conformsToProtocol:@protocol(RCTImageURLLoader)] &&
-        [(id<RCTImageURLLoader>)module canLoadImageURL:requestURL]) {
-      return YES;
-    }
-  }
-  return NO;
+  return [self imageURLLoaderForURL:request.URL] != nil;
 }
 
 - (id)sendRequest:(NSURLRequest *)request withDelegate:(id<RCTURLRequestDelegate>)delegate
@@ -440,7 +446,7 @@ @implementation RCTBridge (RCTImageLoader)
 
 - (RCTImageLoader *)imageLoader
 {
-  return self.modules[RCTBridgeModuleNameForClass([RCTImageLoader class])];
+  return [self moduleForClass:[RCTImageLoader class]];
 }
 
 @end
diff --git a/Libraries/Image/RCTImageStoreManager.m b/Libraries/Image/RCTImageStoreManager.m
index fe080101e7da..3bda2df35abe 100644
--- a/Libraries/Image/RCTImageStoreManager.m
+++ b/Libraries/Image/RCTImageStoreManager.m
@@ -30,15 +30,6 @@ @implementation RCTImageStoreManager
 
 RCT_EXPORT_MODULE()
 
-- (instancetype)init
-{
-  if ((self = [super init])) {
-    _store = [NSMutableDictionary new];
-    _id = 0;
-  }
-  return self;
-}
-
 - (void)removeImageForTag:(NSString *)imageTag withBlock:(void (^)())block
 {
   dispatch_async(_methodQueue, ^{
@@ -52,6 +43,12 @@ - (void)removeImageForTag:(NSString *)imageTag withBlock:(void (^)())block
 - (NSString *)_storeImageData:(NSData *)imageData
 {
   RCTAssertThread(_methodQueue, @"Must be called on RCTImageStoreManager thread");
+
+  if (!_store) {
+    _store = [NSMutableDictionary new];
+    _id = 0;
+  }
+
   NSString *imageTag = [NSString stringWithFormat:@"%@://%tu", RCTImageStoreURLScheme, _id++];
   _store[imageTag] = imageData;
   return imageTag;
@@ -225,7 +222,7 @@ @implementation RCTBridge (RCTImageStoreManager)
 
 - (RCTImageStoreManager *)imageStoreManager
 {
-  return self.modules[RCTBridgeModuleNameForClass([RCTImageStoreManager class])];
+  return [self moduleForClass:[RCTImageStoreManager class]];
 }
 
 @end
diff --git a/Libraries/LinkingIOS/RCTLinkingManager.m b/Libraries/LinkingIOS/RCTLinkingManager.m
index 39fff4eb9658..96c01ca2c47c 100644
--- a/Libraries/LinkingIOS/RCTLinkingManager.m
+++ b/Libraries/LinkingIOS/RCTLinkingManager.m
@@ -21,15 +21,20 @@ @implementation RCTLinkingManager
 
 RCT_EXPORT_MODULE()
 
-- (instancetype)init
+- (void)setBridge:(RCTBridge *)bridge
 {
-  if ((self = [super init])) {
-    [[NSNotificationCenter defaultCenter] addObserver:self
-                                             selector:@selector(handleOpenURLNotification:)
-                                                 name:RCTOpenURLNotification
-                                               object:nil];
-  }
-  return self;
+  _bridge = bridge;
+
+  [[NSNotificationCenter defaultCenter] addObserver:self
+                                           selector:@selector(handleOpenURLNotification:)
+                                               name:RCTOpenURLNotification
+                                             object:nil];
+}
+
+- (NSDictionary<NSString *, id> *)constantsToExport
+{
+  NSURL *initialURL = _bridge.launchOptions[UIApplicationLaunchOptionsURLKey];
+  return @{@"initialURL": RCTNullIfNil(initialURL.absoluteString)};
 }
 
 - (void)dealloc
@@ -75,10 +80,4 @@ - (void)handleOpenURLNotification:(NSNotification *)notification
   callback(@[@(canOpen)]);
 }
 
-- (NSDictionary<NSString *, id> *)constantsToExport
-{
-  NSURL *initialURL = _bridge.launchOptions[UIApplicationLaunchOptionsURLKey];
-  return @{@"initialURL": RCTNullIfNil(initialURL.absoluteString)};
-}
-
 @end
diff --git a/Libraries/Network/RCTHTTPRequestHandler.m b/Libraries/Network/RCTHTTPRequestHandler.m
index f52a20426ceb..1def6d4c7801 100644
--- a/Libraries/Network/RCTHTTPRequestHandler.m
+++ b/Libraries/Network/RCTHTTPRequestHandler.m
@@ -21,26 +21,16 @@ @implementation RCTHTTPRequestHandler
 
 RCT_EXPORT_MODULE()
 
-- (instancetype)init
-{
-  if ((self = [super init])) {
-    _delegates = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory
-                                           valueOptions:NSPointerFunctionsStrongMemory
-                                               capacity:0];
-  }
-  return self;
-}
-
 - (void)invalidate
 {
   [_session invalidateAndCancel];
   _session = nil;
-  _delegates = nil;
 }
 
 - (BOOL)isValid
 {
-  return _delegates != nil;
+  // if session == nil and delegates != nil, we've been invalidated
+  return _session || !_delegates;
 }
 
 #pragma mark - NSURLRequestHandler
@@ -62,12 +52,17 @@ - (NSURLSessionDataTask *)sendRequest:(NSURLRequest *)request
 {
   // Lazy setup
   if (!_session && [self isValid]) {
+
     NSOperationQueue *callbackQueue = [NSOperationQueue new];
     callbackQueue.maxConcurrentOperationCount = 1;
     NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
     _session = [NSURLSession sessionWithConfiguration:configuration
                                              delegate:self
                                         delegateQueue:callbackQueue];
+
+    _delegates = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory
+                                           valueOptions:NSPointerFunctionsStrongMemory
+                                               capacity:0];
   }
 
   NSURLSessionDataTask *task = [_session dataTaskWithRequest:request];
diff --git a/Libraries/Network/RCTNetworking.m b/Libraries/Network/RCTNetworking.m
index 749c9e0b6020..74b58972ccac 100644
--- a/Libraries/Network/RCTNetworking.m
+++ b/Libraries/Network/RCTNetworking.m
@@ -130,36 +130,34 @@ @implementation RCTNetworking
 
 RCT_EXPORT_MODULE()
 
-- (void)setBridge:(RCTBridge *)bridge
+- (id<RCTURLRequestHandler>)handlerForRequest:(NSURLRequest *)request
 {
-  // get handlers
-  NSMutableArray<id<RCTURLRequestHandler>> *handlers = [NSMutableArray array];
-  for (id<RCTBridgeModule> module in bridge.modules.allValues) {
-    if ([module conformsToProtocol:@protocol(RCTURLRequestHandler)]) {
-      [handlers addObject:(id<RCTURLRequestHandler>)module];
-    }
-  }
+  if (!_handlers) {
 
-  // Sort handlers in reverse priority order (highest priority first)
-  [handlers sortUsingComparator:^NSComparisonResult(id<RCTURLRequestHandler> a, id<RCTURLRequestHandler> b) {
-    float priorityA = [a respondsToSelector:@selector(handlerPriority)] ? [a handlerPriority] : 0;
-    float priorityB = [b respondsToSelector:@selector(handlerPriority)] ? [b handlerPriority] : 0;
-    if (priorityA > priorityB) {
-      return NSOrderedAscending;
-    } else if (priorityA < priorityB) {
-      return NSOrderedDescending;
-    } else {
-      return NSOrderedSame;
+    // get handlers
+    NSMutableArray<id<RCTURLRequestHandler>> *handlers = [NSMutableArray array];
+    for (Class moduleClass in _bridge.moduleClasses) {
+      if ([moduleClass conformsToProtocol:@protocol(RCTURLRequestHandler)]) {
+        [handlers addObject:[_bridge moduleForClass:moduleClass]];
+      }
     }
-  }];
 
-  _bridge = bridge;
-  _handlers = handlers;
-  _tasksByRequestID = [NSMutableDictionary new];
-}
+    // Sort handlers in reverse priority order (highest priority first)
+    [handlers sortUsingComparator:^NSComparisonResult(id<RCTURLRequestHandler> a, id<RCTURLRequestHandler> b) {
+      float priorityA = [a respondsToSelector:@selector(handlerPriority)] ? [a handlerPriority] : 0;
+      float priorityB = [b respondsToSelector:@selector(handlerPriority)] ? [b handlerPriority] : 0;
+      if (priorityA > priorityB) {
+        return NSOrderedAscending;
+      } else if (priorityA < priorityB) {
+        return NSOrderedDescending;
+      } else {
+        return NSOrderedSame;
+      }
+    }];
+
+    _handlers = handlers;
+  }
 
-- (id<RCTURLRequestHandler>)handlerForRequest:(NSURLRequest *)request
-{
   if (RCT_DEBUG) {
     // Check for handler conflicts
     float previousPriority = 0;
@@ -198,6 +196,8 @@ - (void)setBridge:(RCTBridge *)bridge
 - (RCTURLRequestCancellationBlock)buildRequest:(NSDictionary<NSString *, id> *)query
                                  completionBlock:(void (^)(NSURLRequest *request))block
 {
+  RCTAssertThread(_methodQueue, @"buildRequest: must be called on method queue");
+
   NSURL *URL = [RCTConvert NSURL:query[@"url"]]; // this is marked as nullable in JS, but should not be null
   NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
   request.HTTPMethod = [RCTConvert NSString:RCTNilIfNull(query[@"method"])].uppercaseString ?: @"GET";
@@ -222,7 +222,10 @@ - (RCTURLRequestCancellationBlock)buildRequest:(NSDictionary<NSString *, id> *)q
       [request setValue:(@(request.HTTPBody.length)).description forHTTPHeaderField:@"Content-Length"];
     }
 
-    block(request);
+    dispatch_async(_methodQueue, ^{
+      block(request);
+    });
+
     return (RCTURLRequestCancellationBlock)nil;
   }];
 }
@@ -253,6 +256,8 @@ - (BOOL)canHandleRequest:(NSURLRequest *)request
 - (RCTURLRequestCancellationBlock)processDataForHTTPQuery:(nullable NSDictionary<NSString *, id> *)query callback:
 (RCTURLRequestCancellationBlock (^)(NSError *error, NSDictionary<NSString *, id> *result))callback
 {
+  RCTAssertThread(_methodQueue, @"processData: must be called on method queue");
+
   if (!query) {
     return callback(nil, nil);
   }
@@ -291,6 +296,8 @@ - (RCTURLRequestCancellationBlock)processDataForHTTPQuery:(nullable NSDictionary
 
 - (void)sendData:(NSData *)data forTask:(RCTNetworkTask *)task
 {
+  RCTAssertThread(_methodQueue, @"sendData: must be called on method queue");
+
   if (data.length == 0) {
     return;
   }
@@ -335,6 +342,8 @@ - (void)sendRequest:(NSURLRequest *)request
  incrementalUpdates:(BOOL)incrementalUpdates
      responseSender:(RCTResponseSenderBlock)responseSender
 {
+  RCTAssertThread(_methodQueue, @"sendRequest: must be called on method queue");
+
   __block RCTNetworkTask *task;
 
   RCTURLRequestProgressBlock uploadProgressBlock = ^(int64_t progress, int64_t total) {
@@ -391,6 +400,9 @@ - (void)sendRequest:(NSURLRequest *)request
   task.uploadProgressBlock = uploadProgressBlock;
 
   if (task.requestID) {
+    if (_tasksByRequestID) {
+      _tasksByRequestID = [NSMutableDictionary new];
+    }
     _tasksByRequestID[task.requestID] = task;
     responseSender(@[task.requestID]);
   }
@@ -443,7 +455,7 @@ @implementation RCTBridge (RCTNetworking)
 
 - (RCTNetworking *)networking
 {
-  return self.modules[RCTBridgeModuleNameForClass([RCTNetworking class])];
+  return [self moduleForClass:[RCTNetworking class]];
 }
 
 @end
diff --git a/Libraries/PushNotificationIOS/RCTPushNotificationManager.m b/Libraries/PushNotificationIOS/RCTPushNotificationManager.m
index 751e8ec349ea..0fda6ee10f0a 100644
--- a/Libraries/PushNotificationIOS/RCTPushNotificationManager.m
+++ b/Libraries/PushNotificationIOS/RCTPushNotificationManager.m
@@ -41,29 +41,11 @@ + (UILocalNotification *)UILocalNotification:(id)json
 @end
 
 @implementation RCTPushNotificationManager
-{
-  NSDictionary<NSString *, id> *_initialNotification;
-}
 
 RCT_EXPORT_MODULE()
 
 @synthesize bridge = _bridge;
 
-- (instancetype)init
-{
-  if ((self = [super init])) {
-    [[NSNotificationCenter defaultCenter] addObserver:self
-                                             selector:@selector(handleRemoteNotificationReceived:)
-                                                 name:RCTRemoteNotificationReceived
-                                               object:nil];
-    [[NSNotificationCenter defaultCenter] addObserver:self
-                                             selector:@selector(handleRemoteNotificationsRegistered:)
-                                                 name:RCTRemoteNotificationsRegistered
-                                               object:nil];
-  }
-  return self;
-}
-
 - (void)dealloc
 {
   [[NSNotificationCenter defaultCenter] removeObserver:self];
@@ -72,7 +54,21 @@ - (void)dealloc
 - (void)setBridge:(RCTBridge *)bridge
 {
   _bridge = bridge;
-  _initialNotification = [bridge.launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey] copy];
+
+  [[NSNotificationCenter defaultCenter] addObserver:self
+                                           selector:@selector(handleRemoteNotificationReceived:)
+                                               name:RCTRemoteNotificationReceived
+                                             object:nil];
+  [[NSNotificationCenter defaultCenter] addObserver:self
+                                           selector:@selector(handleRemoteNotificationsRegistered:)
+                                               name:RCTRemoteNotificationsRegistered
+                                             object:nil];
+}
+
+- (NSDictionary<NSString *, id> *)constantsToExport
+{
+  NSDictionary<NSString *, id> *initialNotification = [_bridge.launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey] copy];
+  return @{@"initialNotification": RCTNullIfNil(initialNotification)};
 }
 
 + (void)application:(__unused UIApplication *)application didRegisterUserNotificationSettings:(__unused UIUserNotificationSettings *)notificationSettings
@@ -200,13 +196,6 @@ - (void)handleRemoteNotificationsRegistered:(NSNotification *)notification
   callback(@[permissions]);
 }
 
-- (NSDictionary<NSString *, id> *)constantsToExport
-{
-  return @{
-    @"initialNotification": RCTNullIfNil(_initialNotification),
-  };
-}
-
 RCT_EXPORT_METHOD(presentLocalNotification:(UILocalNotification *)notification)
 {
   [RCTSharedApplication() presentLocalNotificationNow:notification];
diff --git a/Libraries/RCTTest/RCTTestModule.m b/Libraries/RCTTest/RCTTestModule.m
index 3976f146ecf5..0692543e755a 100644
--- a/Libraries/RCTTest/RCTTestModule.m
+++ b/Libraries/RCTTest/RCTTestModule.m
@@ -29,14 +29,6 @@ - (dispatch_queue_t)methodQueue
   return _bridge.uiManager.methodQueue;
 }
 
-- (instancetype)init
-{
-  if ((self = [super init])) {
-    _snapshotCounter = [NSMutableDictionary new];
-  }
-  return self;
-}
-
 RCT_EXPORT_METHOD(verifySnapshot:(RCTResponseSenderBlock)callback)
 {
   RCTAssert(_controller != nil, @"No snapshot controller configured.");
@@ -44,6 +36,9 @@ - (instancetype)init
   [_bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
 
     NSString *testName = NSStringFromSelector(_testSelector);
+    if (!_snapshotCounter) {
+      _snapshotCounter = [NSMutableDictionary new];
+    }
     _snapshotCounter[testName] = (@([_snapshotCounter[testName] integerValue] + 1)).stringValue;
 
     NSError *error = nil;
diff --git a/Libraries/RCTTest/RCTTestRunner.m b/Libraries/RCTTest/RCTTestRunner.m
index 573c7e0a24a8..6c2e9b5d1675 100644
--- a/Libraries/RCTTest/RCTTestRunner.m
+++ b/Libraries/RCTTest/RCTTestRunner.m
@@ -112,8 +112,7 @@ - (void)runTest:(SEL)test module:(NSString *)moduleName
     RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:moduleName initialProperties:initialProps];
     rootView.frame = CGRectMake(0, 0, 320, 2000); // Constant size for testing on multiple devices
 
-    NSString *testModuleName = RCTBridgeModuleNameForClass([RCTTestModule class]);
-    RCTTestModule *testModule = rootView.bridge.modules[testModuleName];
+    RCTTestModule *testModule = [rootView.bridge moduleForClass:[RCTTestModule class]];
     RCTAssert(_testController != nil, @"_testController should not be nil");
     testModule.controller = _testController;
     testModule.testSelector = test;
diff --git a/Libraries/Settings/RCTSettingsManager.h b/Libraries/Settings/RCTSettingsManager.h
index 274cc69aed43..e0c2908806a6 100644
--- a/Libraries/Settings/RCTSettingsManager.h
+++ b/Libraries/Settings/RCTSettingsManager.h
@@ -13,6 +13,6 @@
 
 @interface RCTSettingsManager : NSObject <RCTBridgeModule>
 
-- (instancetype)initWithUserDefaults:(NSUserDefaults *)defaults NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithUserDefaults:(NSUserDefaults *)defaults;
 
 @end
diff --git a/Libraries/Settings/RCTSettingsManager.m b/Libraries/Settings/RCTSettingsManager.m
index 3e812e2462d7..2ff4f3b4d770 100644
--- a/Libraries/Settings/RCTSettingsManager.m
+++ b/Libraries/Settings/RCTSettingsManager.m
@@ -24,23 +24,31 @@ @implementation RCTSettingsManager
 
 RCT_EXPORT_MODULE()
 
-- (instancetype)init
+- (instancetype)initWithUserDefaults:(NSUserDefaults *)defaults
 {
-  return [self initWithUserDefaults:[NSUserDefaults standardUserDefaults]];
+  if ((self = [self init])) {
+    _defaults = defaults;
+  }
+  return self;
 }
 
-- (instancetype)initWithUserDefaults:(NSUserDefaults *)defaults
+- (void)setBridge:(RCTBridge *)bridge
 {
-  if ((self = [super init])) {
-    _defaults = defaults;
+  _bridge = bridge;
 
-    [[NSNotificationCenter defaultCenter] addObserver:self
-                                             selector:@selector(userDefaultsDidChange:)
-                                                 name:NSUserDefaultsDidChangeNotification
-                                               object:_defaults];
+  if (!_defaults) {
+    _defaults = [NSUserDefaults standardUserDefaults];
   }
 
-  return self;
+  [[NSNotificationCenter defaultCenter] addObserver:self
+                                           selector:@selector(userDefaultsDidChange:)
+                                               name:NSUserDefaultsDidChangeNotification
+                                             object:_defaults];
+}
+
+- (NSDictionary<NSString *, id> *)constantsToExport
+{
+  return @{@"settings": RCTJSONClean([_defaults dictionaryRepresentation])};
 }
 
 - (void)dealloc
@@ -59,13 +67,6 @@ - (void)userDefaultsDidChange:(NSNotification *)note
    body:RCTJSONClean([_defaults dictionaryRepresentation])];
 }
 
-- (NSDictionary<NSString *, id> *)constantsToExport
-{
-  return @{
-    @"settings": RCTJSONClean([_defaults dictionaryRepresentation])
-  };
-}
-
 /**
  * Set one or more values in the settings.
  * TODO: would it be useful to have a callback for when this has completed?
diff --git a/Libraries/WebSocket/RCTWebSocketExecutor.h b/Libraries/WebSocket/RCTWebSocketExecutor.h
index 2c17541f1e8c..9993cbc5a306 100644
--- a/Libraries/WebSocket/RCTWebSocketExecutor.h
+++ b/Libraries/WebSocket/RCTWebSocketExecutor.h
@@ -15,7 +15,7 @@
 
 @interface RCTWebSocketExecutor : NSObject <RCTJavaScriptExecutor>
 
-- (instancetype)initWithURL:(NSURL *)URL NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithURL:(NSURL *)URL;
 
 @end
 
diff --git a/Libraries/WebSocket/RCTWebSocketExecutor.m b/Libraries/WebSocket/RCTWebSocketExecutor.m
index 41ac0baf29f0..6ef4b4999fcd 100644
--- a/Libraries/WebSocket/RCTWebSocketExecutor.m
+++ b/Libraries/WebSocket/RCTWebSocketExecutor.m
@@ -36,19 +36,11 @@ @implementation RCTWebSocketExecutor
 
 RCT_EXPORT_MODULE()
 
-- (instancetype)init
-{
-  NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
-  NSInteger port = [standardDefaults integerForKey:@"websocket-executor-port"] ?: 8081;
-  NSString *URLString = [NSString stringWithFormat:@"http://localhost:%zd/debugger-proxy", port];
-  return [self initWithURL:[RCTConvert NSURL:URLString]];
-}
-
 - (instancetype)initWithURL:(NSURL *)URL
 {
   RCTAssertParam(URL);
 
-  if ((self = [super init])) {
+  if ((self = [self init])) {
     _url = URL;
   }
   return self;
@@ -56,6 +48,13 @@ - (instancetype)initWithURL:(NSURL *)URL
 
 - (void)setUp
 {
+  if (!_url) {
+    NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
+    NSInteger port = [standardDefaults integerForKey:@"websocket-executor-port"] ?: 8081;
+    NSString *URLString = [NSString stringWithFormat:@"http://localhost:%zd/debugger-proxy", port];
+    _url = [RCTConvert NSURL:URLString];
+  }
+
   _jsQueue = dispatch_queue_create("com.facebook.React.WebSocketExecutor", DISPATCH_QUEUE_SERIAL);
   _socket = [[RCTSRWebSocket alloc] initWithURL:_url];
   _socket.delegate = self;
@@ -193,11 +192,7 @@ - (void)injectJSONText:(NSString *)script asGlobalObjectNamed:(NSString *)object
 
 - (void)executeBlockOnJavaScriptQueue:(dispatch_block_t)block
 {
-  if ([NSThread isMainThread]) {
-    block();
-  } else {
-    dispatch_async(dispatch_get_main_queue(), block);
-  }
+  RCTExecuteOnMainThread(block, NO);
 }
 
 - (void)executeAsyncBlockOnJavaScriptQueue:(dispatch_block_t)block
diff --git a/Libraries/WebSocket/RCTWebSocketModule.m b/Libraries/WebSocket/RCTWebSocketModule.m
index df706f0d6f1e..a19335331941 100644
--- a/Libraries/WebSocket/RCTWebSocketModule.m
+++ b/Libraries/WebSocket/RCTWebSocketModule.m
@@ -41,14 +41,6 @@ @implementation RCTWebSocketModule
 
 @synthesize bridge = _bridge;
 
-- (instancetype)init
-{
-  if ((self = [super init])) {
-    _sockets = [NSMutableDictionary new];
-  }
-  return self;
-}
-
 - (void)dealloc
 {
   for (RCTSRWebSocket *socket in _sockets.allValues) {
@@ -62,6 +54,9 @@ - (void)dealloc
   RCTSRWebSocket *webSocket = [[RCTSRWebSocket alloc] initWithURL:URL];
   webSocket.delegate = self;
   webSocket.reactTag = socketID;
+  if (!_sockets) {
+    _sockets = [NSMutableDictionary new];
+  }
   _sockets[socketID] = webSocket;
   [webSocket open];
 }
diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index 98998dd3c36d..0430f2b0af1f 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -18,7 +18,6 @@
 #import "RCTJavaScriptLoader.h"
 #import "RCTLog.h"
 #import "RCTModuleData.h"
-#import "RCTModuleMap.h"
 #import "RCTPerformanceLogger.h"
 #import "RCTProfile.h"
 #import "RCTSourceCode.h"
@@ -48,6 +47,8 @@ @interface RCTBridge ()
 + (instancetype)currentBridge;
 + (void)setCurrentBridge:(RCTBridge *)bridge;
 
+@property (nonatomic, copy, readonly) RCTBridgeModuleProviderBlock moduleProvider;
+
 @end
 
 @interface RCTBatchedBridge : RCTBridge
@@ -63,10 +64,16 @@ @implementation RCTBatchedBridge
   BOOL _wasBatchActive;
   __weak id<RCTJavaScriptExecutor> _javaScriptExecutor;
   NSMutableArray<NSArray *> *_pendingCalls;
-  NSMutableArray<RCTModuleData *> *_moduleDataByID;
-  RCTModuleMap *_modulesByName;
+  NSMutableDictionary<NSString *, RCTModuleData *> *_moduleDataByName;
+  NSArray<RCTModuleData *> *_moduleDataByID;
+  NSDictionary<NSString *, id<RCTBridgeModule>> *_modulesByName_DEPRECATED;
+  NSArray<Class> *_moduleClassesByID;
   CADisplayLink *_jsDisplayLink;
   NSMutableSet<RCTModuleData *> *_frameUpdateObservers;
+
+  // Bridge startup stats (TODO: capture in perf logger)
+  NSUInteger _syncInitializedModules;
+  NSUInteger _asyncInitializedModules;
 }
 
 - (instancetype)initWithParentBridge:(RCTBridge *)bridge
@@ -86,7 +93,6 @@ - (instancetype)initWithParentBridge:(RCTBridge *)bridge
     _valid = YES;
     _loading = YES;
     _pendingCalls = [NSMutableArray new];
-    _moduleDataByID = [NSMutableArray new];
     _frameUpdateObservers = [NSMutableSet new];
     _jsDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_jsThreadUpdate:)];
 
@@ -106,6 +112,8 @@ - (void)start
   dispatch_queue_t bridgeQueue = dispatch_queue_create("com.facebook.react.RCTBridgeQueue", DISPATCH_QUEUE_CONCURRENT);
 
   dispatch_group_t initModulesAndLoadSource = dispatch_group_create();
+
+  // Asynchronously load source code
   dispatch_group_enter(initModulesAndLoadSource);
   __weak RCTBatchedBridge *weakSelf = self;
   __block NSData *sourceCode;
@@ -120,9 +128,13 @@ - (void)start
     dispatch_group_leave(initModulesAndLoadSource);
   }];
 
-  // Synchronously initialize all native modules
+  // Synchronously initialize all native modules that cannot be deferred
   [self initModules];
 
+#if RCT_DEBUG
+  _syncInitializedModules = [[_moduleDataByID valueForKeyPath:@"@sum.hasInstance"] integerValue];
+#endif
+
   if (RCTProfileIsProfiling()) {
     // Depends on moduleDataByID being loaded
     RCTProfileHookModules(self);
@@ -132,22 +144,32 @@ - (void)start
   dispatch_group_enter(initModulesAndLoadSource);
   dispatch_async(bridgeQueue, ^{
     dispatch_group_t setupJSExecutorAndModuleConfig = dispatch_group_create();
+
+    // Asynchronously initialize the JS executor
     dispatch_group_async(setupJSExecutorAndModuleConfig, bridgeQueue, ^{
-      [weakSelf setupExecutor];
+      [weakSelf setUpExecutor];
     });
 
+    // Asynchronously gather the module config
     dispatch_group_async(setupJSExecutorAndModuleConfig, bridgeQueue, ^{
       if (weakSelf.isValid) {
+
         RCTPerformanceLoggerStart(RCTPLNativeModulePrepareConfig);
         config = [weakSelf moduleConfig];
         RCTPerformanceLoggerEnd(RCTPLNativeModulePrepareConfig);
+
+#if RCT_DEBUG
+        NSInteger total = [[_moduleDataByID valueForKeyPath:@"@sum.hasInstance"] integerValue];
+        _asyncInitializedModules = total - _syncInitializedModules;
+#endif
+
       }
     });
 
     dispatch_group_notify(setupJSExecutorAndModuleConfig, bridgeQueue, ^{
-      // We're not waiting for this complete to leave the dispatch group, since
-      // injectJSONConfiguration and executeSourceCode will schedule operations on the
-      // same queue anyway.
+      // We're not waiting for this to complete to leave dispatch group, since
+      // injectJSONConfiguration and executeSourceCode will schedule operations
+      // on the same queue anyway.
       RCTPerformanceLoggerStart(RCTPLNativeModuleInjectConfig);
       [weakSelf injectJSONConfiguration:config onComplete:^(NSError *error) {
         RCTPerformanceLoggerEnd(RCTPLNativeModuleInjectConfig);
@@ -199,6 +221,28 @@ - (void)loadSource:(RCTSourceLoadBlock)_onSourceLoad
   }
 }
 
+- (NSArray<Class> *)moduleClasses
+{
+  if (RCT_DEBUG && self.isValid && _moduleClassesByID == nil) {
+    RCTLogError(@"Bridge modules have not yet been initialized. You may be "
+                "trying to access a module too early in the startup procedure.");
+  }
+  return _moduleClassesByID;
+}
+
+- (id)moduleForName:(NSString *)moduleName
+{
+  RCTModuleData *moduleData = _moduleDataByName[moduleName];
+  if (RCT_DEBUG) {
+    Class moduleClass = moduleData.moduleClass;
+    if (!RCTBridgeModuleClassIsRegistered(moduleClass)) {
+      RCTLogError(@"Class %@ was not exported. Did you forget to use "
+                  "RCT_EXPORT_MODULE()?", moduleClass);
+    }
+  }
+  return moduleData.instance;
+}
+
 - (void)initModules
 {
   RCTAssertMainThread();
@@ -220,54 +264,71 @@ - (void)initModules
     preregisteredModules[RCTBridgeModuleNameForClass([module class])] = module;
   }
 
-  // Instantiate modules
-  _moduleDataByID = [NSMutableArray new];
-  NSMutableDictionary *modulesByName = [preregisteredModules mutableCopy];
+  SEL setBridgeSelector = NSSelectorFromString(@"setBridge:");
+  IMP objectInitMethod = [NSObject instanceMethodForSelector:@selector(init)];
+
+  // Set up moduleData and pre-initialize module instances
+  NSMutableArray<RCTModuleData *> *moduleDataByID = [NSMutableArray new];
+  NSMutableDictionary<NSString *, RCTModuleData *> *moduleDataByName = [NSMutableDictionary new];
   for (Class moduleClass in RCTGetModuleClasses()) {
     NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass);
+    id module = preregisteredModules[moduleName];
+    if (!module) {
+      // Check if the module class, or any of its superclasses override init
+      // or setBridge:. If they do, we assume that they are expecting to be
+      // initialized when the bridge first loads.
+      if ([moduleClass instanceMethodForSelector:@selector(init)] != objectInitMethod ||
+          [moduleClass instancesRespondToSelector:setBridgeSelector]) {
+        module = [moduleClass new];
+        if (!module) {
+          module = [NSNull null];
+        }
+      }
+    }
+
+    // Check for module name collisions.
+    // It's OK to have a name collision as long as the second instance is null.
+    if (module != [NSNull class] && _moduleDataByName[moduleName]) {
+      RCTLogError(@"Attempted to register RCTBridgeModule class %@ for the name "
+                  "'%@', but name was already registered by class %@", moduleClass,
+                  moduleName, _moduleDataByName[moduleName]);
+    }
 
-     // Check if module instance has already been registered for this name
-     id<RCTBridgeModule> module = modulesByName[moduleName];
-
-     if (module) {
-       // Preregistered instances takes precedence, no questions asked
-       if (!preregisteredModules[moduleName]) {
-         // It's OK to have a name collision as long as the second instance is nil
-         RCTAssert([moduleClass new] == nil,
-                   @"Attempted to register RCTBridgeModule class %@ for the name "
-                   "'%@', but name was already registered by class %@", moduleClass,
-                   moduleName, [modulesByName[moduleName] class]);
-       }
-     } else {
-       // Module name hasn't been used before, so go ahead and instantiate
-       module = [moduleClass new];
-     }
-     if (module) {
-       modulesByName[moduleName] = module;
-     }
+    // Instantiate moduleData (TODO: defer this until config generation)
+    RCTModuleData *moduleData;
+    if (module) {
+      if (module != [NSNull null]) {
+        moduleData = [[RCTModuleData alloc] initWithModuleInstance:module];
+      }
+    } else {
+       moduleData = [[RCTModuleData alloc] initWithModuleClass:moduleClass
+                                                        bridge:self];
+    }
+    if (moduleData) {
+      moduleDataByName[moduleName] = moduleData;
+      [moduleDataByID addObject:moduleData];
+    }
   }
 
   // Store modules
-  _modulesByName = [[RCTModuleMap alloc] initWithDictionary:modulesByName];
+  _moduleDataByID = [moduleDataByID copy];
+  _moduleDataByName = [moduleDataByName copy];
+  _moduleClassesByID = [moduleDataByID valueForKey:@"moduleClass"];
 
   /**
    * The executor is a bridge module, wait for it to be created and set it before
    * any other module has access to the bridge
    */
-  _javaScriptExecutor = _modulesByName[RCTBridgeModuleNameForClass(self.executorClass)];
-
-  for (id<RCTBridgeModule> module in _modulesByName.allValues) {
-    // Bridge must be set before moduleData is set up, as methodQueue
-    // initialization requires it (View Managers get their queue by calling
-    // self.bridge.uiManager.methodQueue)
-    if ([module respondsToSelector:@selector(setBridge:)]) {
-      module.bridge = self;
-    }
+  _javaScriptExecutor = [self moduleForClass:self.executorClass];
+
+  for (RCTModuleData *moduleData in _moduleDataByID) {
+    [moduleData setBridgeForInstance:self];
+  }
 
-    RCTModuleData *moduleData = [[RCTModuleData alloc] initWithExecutor:_javaScriptExecutor
-                                                               moduleID:@(_moduleDataByID.count)
-                                                               instance:module];
-    [_moduleDataByID addObject:moduleData];
+  for (RCTModuleData *moduleData in _moduleDataByID) {
+    if (moduleData.hasInstance) {
+      [moduleData methodQueue]; // initialize the queue
+    }
   }
 
   [[NSNotificationCenter defaultCenter] postNotificationName:RCTDidCreateNativeModules
@@ -275,7 +336,7 @@ - (void)initModules
   RCTPerformanceLoggerEnd(RCTPLNativeModuleInit);
 }
 
-- (void)setupExecutor
+- (void)setUpExecutor
 {
   [_javaScriptExecutor setUp];
 }
@@ -284,8 +345,8 @@ - (NSString *)moduleConfig
 {
   NSMutableArray<NSArray *> *config = [NSMutableArray new];
   for (RCTModuleData *moduleData in _moduleDataByID) {
-    [config addObject:moduleData.config];
-    if ([moduleData.instance conformsToProtocol:@protocol(RCTFrameUpdateObserver)]) {
+    [config addObject:RCTNullIfNil(moduleData.config)];
+    if ([moduleData.moduleClass conformsToProtocol:@protocol(RCTFrameUpdateObserver)]) {
       [_frameUpdateObservers addObject:moduleData];
       id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)moduleData.instance;
       __weak typeof(self) weakSelf = self;
@@ -336,7 +397,7 @@ - (void)executeSourceCode:(NSData *)sourceCode
     return;
   }
 
-  RCTSourceCode *sourceCodeModule = self.modules[RCTBridgeModuleNameForClass([RCTSourceCode class])];
+  RCTSourceCode *sourceCodeModule = [self moduleForClass:[RCTSourceCode class]];
   sourceCodeModule.scriptURL = self.bundleURL;
   sourceCodeModule.scriptData = sourceCode;
 
@@ -448,13 +509,14 @@ - (BOOL)isValid
   return _valid;
 }
 
-- (NSDictionary *)modules
+- (void)dispatchBlock:(dispatch_block_t)block
+                queue:(dispatch_queue_t)queue
 {
-  if (RCT_DEBUG && self.isValid && _modulesByName == nil) {
-    RCTLogError(@"Bridge modules have not yet been initialized. You may be "
-                "trying to access a module too early in the startup procedure.");
+  if (queue == RCTJSThread) {
+    [_javaScriptExecutor executeBlockOnJavaScriptQueue:block];
+  } else if (queue) {
+    dispatch_async(queue, block);
   }
-  return _modulesByName;
 }
 
 #pragma mark - RCTInvalidating
@@ -475,17 +537,19 @@ - (void)invalidate
 
   // Invalidate modules
   dispatch_group_t group = dispatch_group_create();
-  for (RCTModuleData *moduleData in _moduleDataByID) {
+  for (RCTModuleData *moduleData in _moduleDataByName.allValues) {
     if (moduleData.instance == _javaScriptExecutor) {
       continue;
     }
 
     if ([moduleData.instance respondsToSelector:@selector(invalidate)]) {
-      [moduleData dispatchBlock:^{
+      dispatch_group_enter(group);
+      [self dispatchBlock:^{
         [(id<RCTInvalidating>)moduleData.instance invalidate];
-      } dispatchGroup:group];
+        dispatch_group_leave(group);
+      } queue:moduleData.methodQueue];
     }
-    moduleData.queue = nil;
+    [moduleData invalidate];
   }
 
   dispatch_group_notify(group, dispatch_get_main_queue(), ^{
@@ -499,8 +563,10 @@ - (void)invalidate
       if (RCTProfileIsProfiling()) {
         RCTProfileUnhookModules(self);
       }
+      _moduleDataByName = nil;
       _moduleDataByID = nil;
-      _modulesByName = nil;
+      _moduleClassesByID = nil;
+      _modulesByName_DEPRECATED = nil;
       _frameUpdateObservers = nil;
 
     }];
@@ -683,15 +749,11 @@ - (void)handleBuffer:(NSArray<NSArray *> *)buffer
 
   NSMapTable *buckets = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory
                                                   valueOptions:NSPointerFunctionsStrongMemory
-                                                      capacity:_moduleDataByID.count];
+                                                      capacity:_moduleDataByName.count];
 
   [moduleIDs enumerateObjectsUsingBlock:^(NSNumber *moduleID, NSUInteger i, __unused BOOL *stop) {
     RCTModuleData *moduleData = _moduleDataByID[moduleID.integerValue];
-    if (RCT_DEBUG) {
-      // verify that class has been registered
-      (void)_modulesByName[moduleData.name];
-    }
-    dispatch_queue_t queue = moduleData.queue;
+    dispatch_queue_t queue = moduleData.methodQueue;
     NSMutableOrderedSet<NSNumber *> *set = [buckets objectForKey:queue];
     if (!set) {
       set = [NSMutableOrderedSet new];
@@ -739,10 +801,10 @@ - (void)batchDidComplete
 {
   // TODO: batchDidComplete is only used by RCTUIManager - can we eliminate this special case?
   for (RCTModuleData *moduleData in _moduleDataByID) {
-    if ([moduleData.instance respondsToSelector:@selector(batchDidComplete)]) {
-      [moduleData dispatchBlock:^{
+    if (moduleData.hasInstance && [moduleData.instance respondsToSelector:@selector(batchDidComplete)]) {
+      [self dispatchBlock:^{
         [moduleData.instance batchDidComplete];
-      }];
+      } queue:moduleData.methodQueue];
     }
   }
 }
@@ -812,12 +874,12 @@ - (void)_jsThreadUpdate:(CADisplayLink *)displayLink
       RCT_IF_DEV(NSString *name = [NSString stringWithFormat:@"[%@ didUpdateFrame:%f]", observer, displayLink.timestamp];)
       RCTProfileBeginFlowEvent();
 
-      [moduleData dispatchBlock:^{
+      [self dispatchBlock:^{
         RCTProfileEndFlowEvent();
         RCT_PROFILE_BEGIN_EVENT(0, name, nil);
         [observer didUpdateFrame:frameUpdate];
         RCT_PROFILE_END_EVENT(0, @"objc_call,fps", nil);
-      }];
+      } queue:moduleData.methodQueue];
     }
   }
 
@@ -851,3 +913,24 @@ - (void)stopProfiling:(void (^)(NSData *))callback
 }
 
 @end
+
+@implementation RCTBatchedBridge(Deprecated)
+
+- (NSDictionary *)modules
+{
+  if (!_modulesByName_DEPRECATED) {
+    // Check classes are set up
+    [self moduleClasses];
+    NSMutableDictionary *modulesByName = [NSMutableDictionary new];
+    for (NSString *moduleName in _moduleDataByName) {
+      id module = [self moduleForName:moduleName];
+      if (module) {
+         modulesByName[moduleName] = module;
+      }
+    };
+    _modulesByName_DEPRECATED = [modulesByName copy];
+  }
+  return _modulesByName_DEPRECATED;
+}
+
+@end
diff --git a/React/Base/RCTBridge.h b/React/Base/RCTBridge.h
index c16786b454e1..487773f5217a 100644
--- a/React/Base/RCTBridge.h
+++ b/React/Base/RCTBridge.h
@@ -59,6 +59,11 @@ typedef NSArray<id<RCTBridgeModule>> *(^RCTBridgeModuleProviderBlock)(void);
  */
 RCT_EXTERN NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass);
 
+/**
+ * This function checks if a class has been registered
+ */
+RCT_EXTERN BOOL RCTBridgeModuleClassIsRegistered(Class);
+
 /**
  * Async batched bridge used to communicate with the JavaScript application.
  */
@@ -98,10 +103,18 @@ RCT_EXTERN NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass);
 - (void)enqueueJSCall:(NSString *)moduleDotMethod args:(NSArray *)args;
 
 /**
- * DEPRECATED: Do not use.
+ * Retrieve a bridge module instance by name or class. Note that modules are
+ * lazily instantiated, so calling these methods for the first time with a given
+ * module name/class may cause the class to be sychronously instantiated,
+ * blocking both the calling thread and main thread for a short time.
+ */
+- (id)moduleForName:(NSString *)moduleName;
+- (id)moduleForClass:(Class)moduleClass;
+
+/**
+ * All registered bridge module classes.
  */
-#define RCT_IMPORT_METHOD(module, method) \
-  _Pragma("message(\"This macro is no longer required\")")
+@property (nonatomic, copy, readonly) NSArray<Class> *moduleClasses;
 
 /**
  * URL of the script that was loaded into the bridge.
@@ -130,11 +143,6 @@ RCT_EXTERN NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass);
  */
 @property (nonatomic, readonly) RCTEventDispatcher *eventDispatcher;
 
-/**
- * A dictionary of all registered RCTBridgeModule instances, keyed by moduleName.
- */
-@property (nonatomic, copy, readonly) NSDictionary *modules;
-
 /**
  * The launch options that were used to initialize the bridge.
  */
@@ -151,13 +159,18 @@ RCT_EXTERN NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass);
 @property (nonatomic, readonly, getter=isValid) BOOL valid;
 
 /**
- * The block passed in the constructor with pre-initialized modules
+ * Reload the bundle and reset executor & modules. Safe to call from any thread.
  */
-@property (nonatomic, copy, readonly) RCTBridgeModuleProviderBlock moduleProvider;
+- (void)reload;
+
+@end
 
 /**
- * Reload the bundle and reset executor & modules. Safe to call from any thread.
+ * These properties and methods are deprecated and should not be used
  */
-- (void)reload;
+@interface RCTBridge (Deprecated)
+
+@property (nonatomic, copy, readonly) NSDictionary *modules
+__deprecated_msg("Use moduleClasses and/or moduleForName: instead");
 
 @end
diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m
index 15f85c8da4a2..013a541368c5 100644
--- a/React/Base/RCTBridge.m
+++ b/React/Base/RCTBridge.m
@@ -37,6 +37,7 @@ - (instancetype)initWithParentBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZ
 @interface RCTBridge ()
 
 @property (nonatomic, strong) RCTBatchedBridge *batchedBridge;
+@property (nonatomic, copy, readonly) RCTBridgeModuleProviderBlock moduleProvider;
 
 @end
 
@@ -87,9 +88,8 @@ void RCTRegisterModule(Class moduleClass)
 }
 
 /**
- * Check if class has been registered
+ * This function checks if a class has been registered
  */
-BOOL RCTBridgeModuleClassIsRegistered(Class);
 BOOL RCTBridgeModuleClassIsRegistered(Class cls)
 {
   return [objc_getAssociatedObject(cls, &RCTBridgeModuleClassIsRegistered) ?: @YES boolValue];
@@ -230,9 +230,24 @@ - (void)bindKeys
 #endif
 }
 
+- (NSArray<Class> *)moduleClasses
+{
+  return _batchedBridge.moduleClasses;
+}
+
+- (id)moduleForName:(NSString *)moduleName
+{
+  return [_batchedBridge moduleForName:moduleName];
+}
+
+- (id)moduleForClass:(Class)moduleClass
+{
+  return [self moduleForName:RCTBridgeModuleNameForClass(moduleClass)];
+}
+
 - (RCTEventDispatcher *)eventDispatcher
 {
-  return self.modules[RCTBridgeModuleNameForClass([RCTEventDispatcher class])];
+  return [self moduleForClass:[RCTEventDispatcher class]];
 }
 
 - (void)reload
@@ -281,10 +296,6 @@ - (void)logMessage:(NSString *)message level:(NSString *)level
   [_batchedBridge logMessage:message level:level];
 }
 
-- (NSDictionary *)modules
-{
-  return _batchedBridge.modules;
-}
 
 #define RCT_INNER_BRIDGE_ONLY(...) \
 - (void)__VA_ARGS__ \
@@ -303,3 +314,12 @@ - (void)enqueueJSCall:(NSString *)moduleDotMethod args:(NSArray *)args
                       method:(__unused NSString *)method
                       arguments:(__unused NSArray *)args);
 @end
+
+@implementation RCTBridge(Deprecated)
+
+- (NSDictionary *)modules
+{
+  return _batchedBridge.modules;
+}
+
+@end
diff --git a/React/Base/RCTBridgeModule.h b/React/Base/RCTBridgeModule.h
index ee51f5d5b412..436b26c80bd0 100644
--- a/React/Base/RCTBridgeModule.h
+++ b/React/Base/RCTBridgeModule.h
@@ -76,7 +76,7 @@ RCT_EXTERN void RCTRegisterModule(Class); \
  * will be set automatically by the bridge when it initializes the module.
  * To implement this in your module, just add `@synthesize bridge = _bridge;`
  */
-@property (nonatomic, weak) RCTBridge *bridge;
+@property (nonatomic, weak, readonly) RCTBridge *bridge;
 
 /**
  * The queue that will be used to call all exported methods. If omitted, this
diff --git a/React/Base/RCTEventDispatcher.m b/React/Base/RCTEventDispatcher.m
index d8d6f3268daa..b0d2be661d2a 100644
--- a/React/Base/RCTEventDispatcher.m
+++ b/React/Base/RCTEventDispatcher.m
@@ -97,14 +97,12 @@ @implementation RCTEventDispatcher
 
 RCT_EXPORT_MODULE()
 
-- (instancetype)init
+- (void)setBridge:(RCTBridge *)bridge
 {
-  if ((self = [super init])) {
-    _paused = YES;
-    _eventQueue = [NSMutableDictionary new];
-    _eventQueueLock = [NSLock new];
-  }
-  return self;
+  _bridge = bridge;
+  _paused = YES;
+  _eventQueue = [NSMutableDictionary new];
+  _eventQueueLock = [NSLock new];
 }
 
 - (void)setPaused:(BOOL)paused
diff --git a/React/Base/RCTKeyboardObserver.m b/React/Base/RCTKeyboardObserver.m
index fbe4e4f7647b..88523a549f4f 100644
--- a/React/Base/RCTKeyboardObserver.m
+++ b/React/Base/RCTKeyboardObserver.m
@@ -19,25 +19,24 @@ @implementation RCTKeyboardObserver
 
 RCT_EXPORT_MODULE()
 
-- (instancetype)init
+- (void)setBridge:(RCTBridge *)bridge
 {
-  if ((self = [super init])) {
-    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+  _bridge = bridge;
+
+  NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
 
 #define ADD_KEYBOARD_HANDLER(NAME, SELECTOR) \
-    [nc addObserver:self selector:@selector(SELECTOR:) name:NAME object:nil]
+  [nc addObserver:self selector:@selector(SELECTOR:) name:NAME object:nil]
 
-    ADD_KEYBOARD_HANDLER(UIKeyboardWillShowNotification, keyboardWillShow);
-    ADD_KEYBOARD_HANDLER(UIKeyboardDidShowNotification, keyboardDidShow);
-    ADD_KEYBOARD_HANDLER(UIKeyboardWillHideNotification, keyboardWillHide);
-    ADD_KEYBOARD_HANDLER(UIKeyboardDidHideNotification, keyboardDidHide);
-    ADD_KEYBOARD_HANDLER(UIKeyboardWillChangeFrameNotification, keyboardWillChangeFrame);
-    ADD_KEYBOARD_HANDLER(UIKeyboardDidChangeFrameNotification, keyboardDidChangeFrame);
+  ADD_KEYBOARD_HANDLER(UIKeyboardWillShowNotification, keyboardWillShow);
+  ADD_KEYBOARD_HANDLER(UIKeyboardDidShowNotification, keyboardDidShow);
+  ADD_KEYBOARD_HANDLER(UIKeyboardWillHideNotification, keyboardWillHide);
+  ADD_KEYBOARD_HANDLER(UIKeyboardDidHideNotification, keyboardDidHide);
+  ADD_KEYBOARD_HANDLER(UIKeyboardWillChangeFrameNotification, keyboardWillChangeFrame);
+  ADD_KEYBOARD_HANDLER(UIKeyboardDidChangeFrameNotification, keyboardDidChangeFrame);
 
 #undef ADD_KEYBOARD_HANDLER
-  }
 
-  return self;
 }
 
 - (void)dealloc
diff --git a/React/Base/RCTModuleData.h b/React/Base/RCTModuleData.h
index cc3747eae8be..540059842035 100644
--- a/React/Base/RCTModuleData.h
+++ b/React/Base/RCTModuleData.h
@@ -9,28 +9,58 @@
 
 #import <Foundation/Foundation.h>
 
-#import "RCTJavaScriptExecutor.h"
+#import "RCTInvalidating.h"
 
 @protocol RCTBridgeMethod;
+@protocol RCTBridgeModule;
+@class RCTBridge;
 
-@interface RCTModuleData : NSObject
+@interface RCTModuleData : NSObject <RCTInvalidating>
 
-@property (nonatomic, weak, readonly) id<RCTJavaScriptExecutor> javaScriptExecutor;
-@property (nonatomic, strong, readonly) NSNumber *moduleID;
-@property (nonatomic, strong, readonly) id<RCTBridgeModule> instance;
+- (instancetype)initWithModuleClass:(Class)moduleClass
+                             bridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)initWithModuleInstance:(id<RCTBridgeModule>)instance NS_DESIGNATED_INITIALIZER;
+
+/**
+ * Sets the bridge for the module instance. This is only needed when using the
+ * `initWithModuleID:instance:` constructor. Otherwise, the bridge will be set
+ * automatically when the module is first accessed.
+ */
+- (void)setBridgeForInstance:(RCTBridge *)bridge;
 
 @property (nonatomic, strong, readonly) Class moduleClass;
 @property (nonatomic, copy, readonly) NSString *name;
+
+/**
+ * Returns the module methods. Note that this will gather the methods the first
+ * time it is called and then memoize the results.
+ */
 @property (nonatomic, copy, readonly) NSArray<id<RCTBridgeMethod>> *methods;
-@property (nonatomic, copy, readonly) NSArray *config;
 
-@property (nonatomic, strong) dispatch_queue_t queue;
+/**
+ * Returns YES if module instance has already been initialized; NO otherwise.
+ */
+@property (nonatomic, assign, readonly) BOOL hasInstance;
+
+/**
+ * Returns the current module instance. Note that this will init the instance
+ * if it has not already been created. To check if the module instance exists
+ * without causing it to be created, use `hasInstance` instead.
+ */
+@property (nonatomic, strong, readonly) id<RCTBridgeModule> instance;
 
-- (instancetype)initWithExecutor:(id<RCTJavaScriptExecutor>)javaScriptExecutor
-                        moduleID:(NSNumber *)moduleID
-                        instance:(id<RCTBridgeModule>)instance NS_DESIGNATED_INITIALIZER;
+/**
+ * Returns the module method dispatch queue. Note that this will init both the
+ * queue and the module itself if they have not already been created.
+ */
+@property (nonatomic, strong, readonly) dispatch_queue_t methodQueue;
 
-- (void)dispatchBlock:(dispatch_block_t)block;
-- (void)dispatchBlock:(dispatch_block_t)block dispatchGroup:(dispatch_group_t)group;
+/**
+ * Returns the module config. Note that this will init the module if it has
+ * not already been created. This method can be called on any thread, but will
+ * block the main thread briefly if the module implements `constantsToExport`.
+ */
+@property (nonatomic, copy, readonly) NSArray *config;
 
 @end
diff --git a/React/Base/RCTModuleData.m b/React/Base/RCTModuleData.m
index ddd0384d49d6..11603850f73b 100644
--- a/React/Base/RCTModuleData.m
+++ b/React/Base/RCTModuleData.m
@@ -16,37 +16,75 @@
 
 @implementation RCTModuleData
 {
-  NSDictionary *_constants;
   NSString *_queueName;
+  __weak RCTBridge *_bridge;
 }
 
 @synthesize methods = _methods;
+@synthesize instance = _instance;
+@synthesize methodQueue = _methodQueue;
 
-- (instancetype)initWithExecutor:(id<RCTJavaScriptExecutor>)javaScriptExecutor
-                        moduleID:(NSNumber *)moduleID
-                        instance:(id<RCTBridgeModule>)instance
+- (instancetype)initWithModuleClass:(Class)moduleClass
+                             bridge:(RCTBridge *)bridge
+{
+  if ((self = [super init])) {
+    _moduleClass = moduleClass;
+    _bridge = bridge;
+  }
+  return self;
+}
+
+- (instancetype)initWithModuleInstance:(id<RCTBridgeModule>)instance
 {
   if ((self = [super init])) {
-    _javaScriptExecutor = javaScriptExecutor;
-    _moduleID = moduleID;
     _instance = instance;
     _moduleClass = [instance class];
-    _name = RCTBridgeModuleNameForClass(_moduleClass);
-
-    // Must be done at init time to ensure it's called on main thread
-    RCTAssertMainThread();
-    if ([_instance respondsToSelector:@selector(constantsToExport)]) {
-      _constants = [_instance constantsToExport];
-    }
-
-    // Must be done at init time due to race conditions
-    (void)self.queue;
   }
   return self;
 }
 
 RCT_NOT_IMPLEMENTED(- (instancetype)init);
 
+- (BOOL)hasInstance
+{
+  return _instance != nil;
+}
+
+- (id<RCTBridgeModule>)instance
+{
+  if (!_instance) {
+    _instance = [_moduleClass new];
+
+    // Bridge must be set before methodQueue is set up, as methodQueue
+    // initialization requires it (View Managers get their queue by calling
+    // self.bridge.uiManager.methodQueue)
+    [self setBridgeForInstance:_bridge];
+
+    // Initialize queue
+    [self methodQueue];
+  }
+  return _instance;
+}
+
+- (void)setBridgeForInstance:(RCTBridge *)bridge
+{
+  if ([_instance respondsToSelector:@selector(bridge)]) {
+    @try {
+      [(id)_instance setValue:bridge forKey:@"bridge"];
+    }
+    @catch (NSException *exception) {
+      RCTLogError(@"%@ has no setter or ivar for its bridge, which is not "
+                  "permitted. You must either @synthesize the bridge property, "
+                  "or provide your own setter method.", self.name);
+    }
+  }
+}
+
+- (NSString *)name
+{
+  return RCTBridgeModuleNameForClass(_moduleClass);
+}
+
 - (NSArray<id<RCTBridgeMethod>> *)methods
 {
   if (!_methods) {
@@ -84,7 +122,15 @@ - (instancetype)initWithExecutor:(id<RCTJavaScriptExecutor>)javaScriptExecutor
 
 - (NSArray *)config
 {
-  if (_constants.count == 0 && self.methods.count == 0) {
+  __block NSDictionary<NSString *, id> *constants;
+  if (RCTClassOverridesInstanceMethod(_moduleClass, @selector(constantsToExport))) {
+    [self instance]; // Initialize instance
+    RCTExecuteOnMainThread(^{
+      constants = [_instance constantsToExport];
+    }, YES);
+  }
+
+  if (constants.count == 0 && self.methods.count == 0) {
     return (id)kCFNull; // Nothing to export
   }
 
@@ -101,9 +147,9 @@ - (NSArray *)config
   }
 
   NSMutableArray *config = [NSMutableArray new];
-  [config addObject:_name];
-  if (_constants.count) {
-    [config addObject:_constants];
+  [config addObject:self.name];
+  if (constants.count) {
+    [config addObject:constants];
   }
   if (methods) {
     [config addObject:methods];
@@ -114,53 +160,39 @@ - (NSArray *)config
   return config;
 }
 
-- (dispatch_queue_t)queue
+- (dispatch_queue_t)methodQueue
 {
-  if (!_queue) {
-    BOOL implementsMethodQueue = [_instance respondsToSelector:@selector(methodQueue)];
+  if (!_methodQueue) {
+    BOOL implementsMethodQueue = [self.instance respondsToSelector:@selector(methodQueue)];
     if (implementsMethodQueue) {
-      _queue = _instance.methodQueue;
+      _methodQueue = _instance.methodQueue;
     }
-    if (!_queue) {
+    if (!_methodQueue) {
 
       // Create new queue (store queueName, as it isn't retained by dispatch_queue)
-      _queueName = [NSString stringWithFormat:@"com.facebook.React.%@Queue", _name];
-      _queue = dispatch_queue_create(_queueName.UTF8String, DISPATCH_QUEUE_SERIAL);
+      _queueName = [NSString stringWithFormat:@"com.facebook.React.%@Queue", self.name];
+      _methodQueue = dispatch_queue_create(_queueName.UTF8String, DISPATCH_QUEUE_SERIAL);
 
       // assign it to the module
       if (implementsMethodQueue) {
         @try {
-          [(id)_instance setValue:_queue forKey:@"methodQueue"];
+          [(id)_instance setValue:_methodQueue forKey:@"methodQueue"];
         }
         @catch (NSException *exception) {
           RCTLogError(@"%@ is returning nil for it's methodQueue, which is not "
                       "permitted. You must either return a pre-initialized "
                       "queue, or @synthesize the methodQueue to let the bridge "
-                      "create a queue for you.", _name);
+                      "create a queue for you.", self.name);
         }
       }
     }
   }
-  return _queue;
-}
-
-- (void)dispatchBlock:(dispatch_block_t)block
-{
-  [self dispatchBlock:block dispatchGroup:NULL];
+  return _methodQueue;
 }
 
-- (void)dispatchBlock:(dispatch_block_t)block
-        dispatchGroup:(dispatch_group_t)group
+- (void)invalidate
 {
-  if (self.queue == RCTJSThread) {
-    [_javaScriptExecutor executeBlockOnJavaScriptQueue:block];
-  } else if (self.queue) {
-    if (group != NULL) {
-      dispatch_group_async(group, self.queue, block);
-    } else {
-      dispatch_async(self.queue, block);
-    }
-  }
+  _methodQueue = nil;
 }
 
 @end
diff --git a/React/Base/RCTModuleMap.h b/React/Base/RCTModuleMap.h
deleted file mode 100644
index 48e7c73e66a7..000000000000
--- a/React/Base/RCTModuleMap.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/**
- * 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.
- */
-
-#import <Foundation/Foundation.h>
-
-@interface RCTModuleMap : NSDictionary
-
-- (instancetype)initWithDictionary:(NSDictionary *)modulesByName NS_DESIGNATED_INITIALIZER;
-
-@end
diff --git a/React/Base/RCTModuleMap.m b/React/Base/RCTModuleMap.m
deleted file mode 100644
index fef338763193..000000000000
--- a/React/Base/RCTModuleMap.m
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * 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.
- */
-
-#import "RCTModuleMap.h"
-
-#import "RCTBridge.h"
-#import "RCTBridgeModule.h"
-#import "RCTDefines.h"
-#import "RCTLog.h"
-
-@implementation RCTModuleMap
-{
-  NSDictionary *_modulesByName;
-}
-
-RCT_NOT_IMPLEMENTED(- (instancetype)init)
-RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:aDecoder)
-RCT_NOT_IMPLEMENTED(- (instancetype)initWithObjects:(const id [])objects
-                                            forKeys:(const id<NSCopying> [])keys
-                                              count:(NSUInteger)cnt)
-
-- (instancetype)initWithDictionary:(NSDictionary *)modulesByName
-{
-  if ((self = [super init])) {
-    _modulesByName = [modulesByName copy];
-  }
-  return self;
-}
-
-- (NSUInteger)count
-{
-  return _modulesByName.count;
-}
-
-//declared in RCTBridge.m
-extern BOOL RCTBridgeModuleClassIsRegistered(Class cls);
-
-- (id)objectForKey:(NSString *)moduleName
-{
-  id<RCTBridgeModule> module = _modulesByName[moduleName];
-  if (RCT_DEBUG) {
-    if (module) {
-      Class moduleClass = [module class];
-      if (!RCTBridgeModuleClassIsRegistered(moduleClass)) {
-        RCTLogError(@"Class %@ was not exported. Did you forget to use "
-                    "RCT_EXPORT_MODULE()?", moduleClass);
-      }
-    } else {
-      Class moduleClass = NSClassFromString(moduleName);
-      module = _modulesByName[moduleName];
-      if (module) {
-        RCTLogError(@"bridge.modules[name] expects a module name, not a class "
-                    "name. Did you mean to pass '%@' instead?",
-                    RCTBridgeModuleNameForClass(moduleClass));
-      }
-    }
-  }
-  return module;
-}
-
-- (NSEnumerator *)keyEnumerator
-{
-  return [_modulesByName keyEnumerator];
-}
-
-- (NSArray<id<RCTBridgeModule>> *)allValues
-{
-  // don't perform validation in this case because we only want to error when
-  // an invalid module is specifically requested
-  return _modulesByName.allValues;
-}
-
-@end
diff --git a/React/Base/RCTPerformanceLogger.m b/React/Base/RCTPerformanceLogger.m
index f099db677122..d7f45d6930c4 100644
--- a/React/Base/RCTPerformanceLogger.m
+++ b/React/Base/RCTPerformanceLogger.m
@@ -79,15 +79,14 @@ @implementation RCTPerformanceLogger
 
 @synthesize bridge = _bridge;
 
-- (instancetype)init
+- (void)setBridge:(RCTBridge *)bridge
 {
-  if ((self = [super init])) {
-    [[NSNotificationCenter defaultCenter] addObserver:self
-                                             selector:@selector(sendTimespans)
-                                                 name:RCTContentDidAppearNotification
-                                               object:nil];
-  }
-  return self;
+  _bridge = bridge;
+
+  [[NSNotificationCenter defaultCenter] addObserver:self
+                                           selector:@selector(sendTimespans)
+                                               name:RCTContentDidAppearNotification
+                                             object:nil];
 }
 
 - (void)dealloc
diff --git a/React/Base/RCTUtils.h b/React/Base/RCTUtils.h
index 6d399594e954..e138da40531b 100644
--- a/React/Base/RCTUtils.h
+++ b/React/Base/RCTUtils.h
@@ -27,6 +27,10 @@ RCT_EXTERN id RCTJSONClean(id object);
 // Get MD5 hash of a string
 RCT_EXTERN NSString *RCTMD5Hash(NSString *string);
 
+// Execute the specified block on the main thread. Unlike dispatch_sync/async
+// this will not context-switch if we're already running on the main thread.
+RCT_EXTERN void RCTExecuteOnMainThread(dispatch_block_t block, BOOL sync);
+
 // Get screen metrics in a thread-safe way
 RCT_EXTERN CGFloat RCTScreenScale(void);
 RCT_EXTERN CGSize RCTScreenSize(void);
diff --git a/React/Base/RCTUtils.m b/React/Base/RCTUtils.m
index 036ecc2bd38a..8d6f3238d0c9 100644
--- a/React/Base/RCTUtils.m
+++ b/React/Base/RCTUtils.m
@@ -183,18 +183,29 @@ id RCTJSONClean(id object)
   ];
 }
 
+void RCTExecuteOnMainThread(dispatch_block_t block, BOOL sync)
+{
+  if ([NSThread isMainThread]) {
+    block();
+  } else if (sync) {
+    dispatch_sync(dispatch_get_main_queue(), ^{
+      block();
+    });
+  } else {
+    dispatch_async(dispatch_get_main_queue(), ^{
+      block();
+    });
+  }
+}
+
 CGFloat RCTScreenScale()
 {
   static CGFloat scale;
   static dispatch_once_t onceToken;
   dispatch_once(&onceToken, ^{
-    if (![NSThread isMainThread]) {
-      dispatch_sync(dispatch_get_main_queue(), ^{
-        scale = [UIScreen mainScreen].scale;
-      });
-    } else {
+    RCTExecuteOnMainThread(^{
       scale = [UIScreen mainScreen].scale;
-    }
+    }, YES);
   });
 
   return scale;
@@ -205,13 +216,9 @@ CGSize RCTScreenSize()
   static CGSize size;
   static dispatch_once_t onceToken;
   dispatch_once(&onceToken, ^{
-    if (![NSThread isMainThread]) {
-      dispatch_sync(dispatch_get_main_queue(), ^{
-        size = [UIScreen mainScreen].bounds.size;
-      });
-    } else {
+    RCTExecuteOnMainThread(^{
       size = [UIScreen mainScreen].bounds.size;
-    }
+    }, YES);
   });
 
   return size;
diff --git a/React/Modules/RCTAccessibilityManager.m b/React/Modules/RCTAccessibilityManager.m
index eb4d319547b5..fd629cae33c0 100644
--- a/React/Modules/RCTAccessibilityManager.m
+++ b/React/Modules/RCTAccessibilityManager.m
@@ -59,6 +59,8 @@ + (NSString *)UIKitCategoryFromJSCategory:(NSString *)JSCategory
 - (instancetype)init
 {
   if ((self = [super init])) {
+
+    // TODO: can this be moved out of the startup path?
     [[NSNotificationCenter defaultCenter] addObserver:self
                                              selector:@selector(didReceiveNewContentSizeCategory:)
                                                  name:UIContentSizeCategoryDidChangeNotification
@@ -176,7 +178,7 @@ @implementation RCTBridge (RCTAccessibilityManager)
 
 - (RCTAccessibilityManager *)accessibilityManager
 {
-  return self.modules[RCTBridgeModuleNameForClass([RCTAccessibilityManager class])];
+  return [self moduleForClass:[RCTAccessibilityManager class]];
 }
 
 @end
diff --git a/React/Modules/RCTAlertManager.m b/React/Modules/RCTAlertManager.m
index 3bdb59b40472..74168866af06 100644
--- a/React/Modules/RCTAlertManager.m
+++ b/React/Modules/RCTAlertManager.m
@@ -28,17 +28,6 @@ @implementation RCTAlertManager
 
 RCT_EXPORT_MODULE()
 
-- (instancetype)init
-{
-  if ((self = [super init])) {
-    _alerts = [NSMutableArray new];
-    _alertControllers = [NSMutableArray new];
-    _alertCallbacks = [NSMutableArray new];
-    _alertButtonKeys = [NSMutableArray new];
-  }
-  return self;
-}
-
 - (dispatch_queue_t)methodQueue
 {
   return dispatch_get_main_queue();
@@ -118,6 +107,11 @@ - (void)invalidate
       index ++;
     }
 
+    if (!_alerts) {
+      _alerts = [NSMutableArray new];
+      _alertCallbacks = [NSMutableArray new];
+      _alertButtonKeys = [NSMutableArray new];
+    }
     [_alerts addObject:alertView];
     [_alertCallbacks addObject:callback ?: ^(__unused id unused) {}];
     [_alertButtonKeys addObject:buttonKeys];
@@ -175,6 +169,11 @@ - (void)invalidate
       }]];
     }
 
+    if (!_alertControllers) {
+      _alertControllers = [NSMutableArray new];
+    }
+    [_alertControllers addObject:alertController];
+
     [presentingController presentViewController:alertController animated:YES completion:nil];
   }
 }
diff --git a/React/Modules/RCTAppState.m b/React/Modules/RCTAppState.m
index f9ee2cb33093..6a22ae626f0e 100644
--- a/React/Modules/RCTAppState.m
+++ b/React/Modules/RCTAppState.m
@@ -44,27 +44,26 @@ @implementation RCTAppState
 
 #pragma mark - Lifecycle
 
-- (instancetype)init
+- (void)setBridge:(RCTBridge *)bridge
 {
-  if ((self = [super init])) {
+  _bridge = bridge;
 
-    _lastKnownState = RCTCurrentAppBackgroundState();
-
-    for (NSString *name in @[UIApplicationDidBecomeActiveNotification,
-                             UIApplicationDidEnterBackgroundNotification,
-                             UIApplicationDidFinishLaunchingNotification]) {
-      [[NSNotificationCenter defaultCenter] addObserver:self
-                                               selector:@selector(handleAppStateDidChange)
-                                                   name:name
-                                                 object:nil];
-    }
+  // Is this thread-safe?
+  _lastKnownState = RCTCurrentAppBackgroundState();
 
+  for (NSString *name in @[UIApplicationDidBecomeActiveNotification,
+                           UIApplicationDidEnterBackgroundNotification,
+                           UIApplicationDidFinishLaunchingNotification]) {
     [[NSNotificationCenter defaultCenter] addObserver:self
-                                             selector:@selector(handleMemoryWarning)
-                                                 name:UIApplicationDidReceiveMemoryWarningNotification
+                                             selector:@selector(handleAppStateDidChange)
+                                                 name:name
                                                object:nil];
   }
-  return self;
+
+  [[NSNotificationCenter defaultCenter] addObserver:self
+                                           selector:@selector(handleMemoryWarning)
+                                               name:UIApplicationDidReceiveMemoryWarningNotification
+                                             object:nil];
 }
 
 - (void)handleMemoryWarning
diff --git a/React/Modules/RCTDevLoadingView.m b/React/Modules/RCTDevLoadingView.m
index a0266b7ce60d..f522794ab316 100644
--- a/React/Modules/RCTDevLoadingView.m
+++ b/React/Modules/RCTDevLoadingView.m
@@ -34,23 +34,6 @@ + (void)setEnabled:(BOOL)enabled
   isEnabled = enabled;
 }
 
-- (instancetype)init
-{
-  if ((self = [super init])) {
-
-    [[NSNotificationCenter defaultCenter] addObserver:self
-                                             selector:@selector(hide)
-                                                 name:RCTJavaScriptDidLoadNotification
-                                               object:nil];
-
-    [[NSNotificationCenter defaultCenter] addObserver:self
-                                             selector:@selector(hide)
-                                                 name:RCTJavaScriptDidFailToLoadNotification
-                                               object:nil];
-  }
-  return self;
-}
-
 - (void)dealloc
 {
   [[NSNotificationCenter defaultCenter] removeObserver:self];
@@ -59,6 +42,16 @@ - (void)dealloc
 - (void)setBridge:(RCTBridge *)bridge
 {
   _bridge = bridge;
+
+  [[NSNotificationCenter defaultCenter] addObserver:self
+                                           selector:@selector(hide)
+                                               name:RCTJavaScriptDidLoadNotification
+                                             object:nil];
+
+  [[NSNotificationCenter defaultCenter] addObserver:self
+                                           selector:@selector(hide)
+                                               name:RCTJavaScriptDidFailToLoadNotification
+                                             object:nil];
   [self showWithURL:bridge.bundleURL];
 }
 
diff --git a/React/Modules/RCTDevMenu.m b/React/Modules/RCTDevMenu.m
index a57c4b6432f4..dd66c900b2cd 100644
--- a/React/Modules/RCTDevMenu.m
+++ b/React/Modules/RCTDevMenu.m
@@ -321,7 +321,7 @@ - (void)jsLoaded:(NSNotification *)notification
 
   // Check if live reloading is available
   _liveReloadURL = nil;
-  RCTSourceCode *sourceCodeModule = _bridge.modules[RCTBridgeModuleNameForClass([RCTSourceCode class])];
+  RCTSourceCode *sourceCodeModule = [_bridge moduleForClass:[RCTSourceCode class]];
   if (!sourceCodeModule.scriptURL) {
     if (!sourceCodeModule) {
       RCTLogWarn(@"RCTSourceCode module not found");
@@ -614,7 +614,7 @@ @implementation  RCTBridge (RCTDevMenu)
 - (RCTDevMenu *)devMenu
 {
 #if RCT_DEV
-  return self.modules[RCTBridgeModuleNameForClass([RCTDevMenu class])];
+  return [self moduleForClass:[RCTDevMenu class]];
 #else
   return nil;
 #endif
diff --git a/React/Modules/RCTExceptionsManager.h b/React/Modules/RCTExceptionsManager.h
index 20ca8d26e219..ad5625287eb7 100644
--- a/React/Modules/RCTExceptionsManager.h
+++ b/React/Modules/RCTExceptionsManager.h
@@ -23,7 +23,7 @@
 
 @interface RCTExceptionsManager : NSObject <RCTBridgeModule>
 
-- (instancetype)initWithDelegate:(id<RCTExceptionsManagerDelegate>)delegate NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithDelegate:(id<RCTExceptionsManagerDelegate>)delegate;
 
 @property (nonatomic, assign) NSUInteger maxReloadAttempts;
 
diff --git a/React/Modules/RCTExceptionsManager.m b/React/Modules/RCTExceptionsManager.m
index 9cc5d572212c..c536e20a10da 100644
--- a/React/Modules/RCTExceptionsManager.m
+++ b/React/Modules/RCTExceptionsManager.m
@@ -27,18 +27,12 @@ @implementation RCTExceptionsManager
 
 - (instancetype)initWithDelegate:(id<RCTExceptionsManagerDelegate>)delegate
 {
-  if ((self = [super init])) {
+  if ((self = [self init])) {
     _delegate = delegate;
-    _maxReloadAttempts = 0;
   }
   return self;
 }
 
-- (instancetype)init
-{
-  return [self initWithDelegate:nil];
-}
-
 RCT_EXPORT_METHOD(reportSoftException:(NSString *)message
                   stack:(NSDictionaryArray *)stack
                   exceptionId:(nonnull NSNumber *)exceptionId)
diff --git a/React/Modules/RCTRedBox.m b/React/Modules/RCTRedBox.m
index 9f603afd0c86..6379c1164dbb 100644
--- a/React/Modules/RCTRedBox.m
+++ b/React/Modules/RCTRedBox.m
@@ -107,8 +107,9 @@ - (void)showErrorMessage:(NSString *)message withStack:(NSArray<NSDictionary *>
 {
   if ((self.hidden && shouldShow) || (!self.hidden && [_lastErrorMessage isEqualToString:message])) {
     _lastStackTrace = stack;
-    // message is displayed using UILabel, which is unable to render text of unlimited length, so we truncate it
-    _lastErrorMessage = [message substringToIndex:MIN(10000, message.length)];
+    // message is displayed using UILabel, which is unable to render text of
+    // unlimited length, so we truncate it
+    _lastErrorMessage = [message substringToIndex:MIN((NSUInteger)10000, message.length)];
 
     [_stackTraceTableView reloadData];
 
@@ -326,7 +327,7 @@ @implementation RCTBridge (RCTRedBox)
 
 - (RCTRedBox *)redBox
 {
-  return self.modules[RCTBridgeModuleNameForClass([RCTRedBox class])];
+  return [self moduleForClass:[RCTRedBox class]];
 }
 
 @end
diff --git a/React/Modules/RCTStatusBarManager.m b/React/Modules/RCTStatusBarManager.m
index 80e40c9aae14..dd29a078992d 100644
--- a/React/Modules/RCTStatusBarManager.m
+++ b/React/Modules/RCTStatusBarManager.m
@@ -46,14 +46,13 @@ static BOOL RCTViewControllerBasedStatusBarAppearance()
 
 @synthesize bridge = _bridge;
 
-- (instancetype)init
+- (void)setBridge:(RCTBridge *)bridge
 {
-  if ((self = [super init])) {
-    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
-    [nc addObserver:self selector:@selector(applicationDidChangeStatusBarFrame:) name:UIApplicationDidChangeStatusBarFrameNotification object:nil];
-    [nc addObserver:self selector:@selector(applicationWillChangeStatusBarFrame:) name:UIApplicationWillChangeStatusBarFrameNotification object:nil];
-  }
-  return self;
+  _bridge = bridge;
+
+  NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+  [nc addObserver:self selector:@selector(applicationDidChangeStatusBarFrame:) name:UIApplicationDidChangeStatusBarFrameNotification object:nil];
+  [nc addObserver:self selector:@selector(applicationWillChangeStatusBarFrame:) name:UIApplicationWillChangeStatusBarFrameNotification object:nil];
 }
 
 - (void)dealloc
diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m
index a15d2516421b..51911fdb055c 100644
--- a/React/Modules/RCTUIManager.m
+++ b/React/Modules/RCTUIManager.m
@@ -179,14 +179,6 @@ - (instancetype)initWithDictionary:(NSDictionary *)config callback:(RCTResponseS
 
 @end
 
-@interface RCTUIManager ()
-
-// NOTE: these are properties so that they can be accessed by unit tests
-@property (nonatomic, strong) NSMutableDictionary<NSNumber *, RCTShadowView *> *shadowViewRegistry; // RCT thread only
-@property (nonatomic, strong) NSMutableDictionary<NSNumber *, UIView *> *viewRegistry; // Main thread only
-
-@end
-
 @implementation RCTUIManager
 {
   dispatch_queue_t _shadowQueue;
@@ -199,6 +191,9 @@ @implementation RCTUIManager
   RCTLayoutAnimation *_nextLayoutAnimation; // RCT thread only
   RCTLayoutAnimation *_layoutAnimation; // Main thread only
 
+  NSMutableDictionary<NSNumber *, RCTShadowView *> *_shadowViewRegistry; // RCT thread only
+  NSMutableDictionary<NSNumber *, UIView *> *_viewRegistry; // Main thread only
+
   // Keyed by viewName
   NSDictionary *_componentDataByName;
 
@@ -214,31 +209,6 @@ @implementation RCTUIManager
  */
 extern NSString *RCTBridgeModuleNameForClass(Class cls);
 
-- (instancetype)init
-{
-  if ((self = [super init])) {
-    const char *queueName = "com.facebook.React.ShadowQueue";
-
-    if ([NSOperation instancesRespondToSelector:@selector(qualityOfService)]) {
-      dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INTERACTIVE, 0);
-      _shadowQueue = dispatch_queue_create(queueName, attr);
-    } else {
-      _shadowQueue = dispatch_queue_create(queueName, DISPATCH_QUEUE_SERIAL);
-      dispatch_set_target_queue(_shadowQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
-    }
-
-    _shadowViewRegistry = [NSMutableDictionary new];
-    _viewRegistry = [NSMutableDictionary new];
-
-    // Internal resources
-    _pendingUIBlocks = [NSMutableArray new];
-    _rootViewTags = [NSMutableSet new];
-
-    _bridgeTransactionListeners = [NSMutableSet new];
-  }
-  return self;
-}
-
 - (void)didReceiveNewContentSizeMultiplier
 {
   __weak RCTUIManager *weakSelf = self;
@@ -276,18 +246,45 @@ - (void)invalidate
   });
 }
 
+- (NSMutableDictionary<NSNumber *, RCTShadowView *> *)shadowViewRegistry
+{
+  // NOTE: this method only exists so that it can be accessed by unit tests
+  if (!_shadowViewRegistry) {
+    _shadowViewRegistry = [NSMutableDictionary new];
+  }
+  return _shadowViewRegistry;
+}
+
+- (NSMutableDictionary<NSNumber *, UIView *> *)viewRegistry
+{
+  // NOTE: this method only exists so that it can be accessed by unit tests
+  if (!_viewRegistry) {
+    _viewRegistry = [NSMutableDictionary new];
+  }
+  return _viewRegistry;
+}
+
 - (void)setBridge:(RCTBridge *)bridge
 {
   RCTAssert(_bridge == nil, @"Should not re-use same UIIManager instance");
 
   _bridge = bridge;
+
   _shadowViewRegistry = [NSMutableDictionary new];
+  _viewRegistry = [NSMutableDictionary new];
+
+  // Internal resources
+  _pendingUIBlocks = [NSMutableArray new];
+  _rootViewTags = [NSMutableSet new];
+
+  _bridgeTransactionListeners = [NSMutableSet new];
 
   // Get view managers from bridge
   NSMutableDictionary *componentDataByName = [NSMutableDictionary new];
-  for (RCTViewManager *manager in _bridge.modules.allValues) {
-    if ([manager isKindOfClass:[RCTViewManager class]]) {
-      RCTComponentData *componentData = [[RCTComponentData alloc] initWithManager:manager];
+  for (Class moduleClass in _bridge.moduleClasses) {
+    if ([moduleClass isSubclassOfClass:[RCTViewManager class]]) {
+      RCTComponentData *componentData = [[RCTComponentData alloc] initWithManagerClass:moduleClass
+                                                                                bridge:_bridge];
       componentDataByName[componentData.name] = componentData;
     }
   }
@@ -302,6 +299,17 @@ - (void)setBridge:(RCTBridge *)bridge
 
 - (dispatch_queue_t)methodQueue
 {
+  if (!_shadowQueue) {
+    const char *queueName = "com.facebook.React.ShadowQueue";
+
+    if ([NSOperation instancesRespondToSelector:@selector(qualityOfService)]) {
+      dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INTERACTIVE, 0);
+      _shadowQueue = dispatch_queue_create(queueName, attr);
+    } else {
+      _shadowQueue = dispatch_queue_create(queueName, DISPATCH_QUEUE_SERIAL);
+      dispatch_set_target_queue(_shadowQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
+    }
+  }
   return _shadowQueue;
 }
 
@@ -1126,12 +1134,11 @@ static void RCTMeasureLayout(RCTShadowView *view,
   [_componentDataByName enumerateKeysAndObjectsUsingBlock:
    ^(NSString *name, RCTComponentData *componentData, __unused BOOL *stop) {
 
-     RCTViewManager *manager = componentData.manager;
      NSMutableDictionary<NSString *, id> *constantsNamespace =
        [NSMutableDictionary dictionaryWithDictionary:allJSConstants[name]];
 
      // Add manager class
-     constantsNamespace[@"Manager"] = RCTBridgeModuleNameForClass([manager class]);
+     constantsNamespace[@"Manager"] = RCTBridgeModuleNameForClass(componentData.managerClass);
 
      // Add native props
      NSDictionary<NSString *, id> *viewConfig = [componentData viewConfig];
@@ -1216,7 +1223,7 @@ @implementation RCTBridge (RCTUIManager)
 
 - (RCTUIManager *)uiManager
 {
-  return self.modules[RCTBridgeModuleNameForClass([RCTUIManager class])];
+  return [self moduleForClass:[RCTUIManager class]];
 }
 
 @end
diff --git a/React/Profiler/RCTProfile.m b/React/Profiler/RCTProfile.m
index 276ae2d4f17b..fe93b658050e 100644
--- a/React/Profiler/RCTProfile.m
+++ b/React/Profiler/RCTProfile.m
@@ -30,6 +30,13 @@
 
 #if RCT_DEV
 
+@interface RCTBridge ()
+
+- (void)dispatchBlock:(dispatch_block_t)block
+                queue:(dispatch_queue_t)queue;
+
+@end
+
 #pragma mark - Constants
 
 NSString const *RCTProfileTraceEvents = @"traceEvents";
@@ -211,7 +218,7 @@ void RCTProfileHookModules(RCTBridge *bridge)
   RCTProfileHookedModules = YES;
 
   for (RCTModuleData *moduleData in [bridge valueForKey:@"moduleDataByID"]) {
-    [moduleData dispatchBlock:^{
+    [bridge dispatchBlock:^{
       Class moduleClass = moduleData.moduleClass;
       Class proxyClass = objc_allocateClassPair(moduleClass, RCTProfileProxyClassName(moduleClass), 0);
 
@@ -242,7 +249,7 @@ void RCTProfileHookModules(RCTBridge *bridge)
 
       objc_registerClassPair(proxyClass);
       object_setClass(moduleData.instance, proxyClass);
-    }];
+    } queue:moduleData.methodQueue];
   }
 }
 
diff --git a/React/Profiler/RCTProfileTrampoline-arm.S b/React/Profiler/RCTProfileTrampoline-arm.S
index 4835d261adcb..61c32df92855 100644
--- a/React/Profiler/RCTProfileTrampoline-arm.S
+++ b/React/Profiler/RCTProfileTrampoline-arm.S
@@ -1,3 +1,12 @@
+/**
+ * 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.
+ */
+
 #include "RCTDefines.h"
 #include "RCTMacros.h"
 
diff --git a/React/Profiler/RCTProfileTrampoline-arm64.S b/React/Profiler/RCTProfileTrampoline-arm64.S
index 92ea42a833f0..435d86a4d517 100644
--- a/React/Profiler/RCTProfileTrampoline-arm64.S
+++ b/React/Profiler/RCTProfileTrampoline-arm64.S
@@ -1,3 +1,12 @@
+/**
+ * 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.
+ */
+
 #include "RCTDefines.h"
 #include "RCTMacros.h"
 
diff --git a/React/Profiler/RCTProfileTrampoline-i386.S b/React/Profiler/RCTProfileTrampoline-i386.S
index 0ccd37b4fe09..7aed481325a2 100644
--- a/React/Profiler/RCTProfileTrampoline-i386.S
+++ b/React/Profiler/RCTProfileTrampoline-i386.S
@@ -1,3 +1,12 @@
+/**
+ * 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.
+ */
+
 #include "RCTDefines.h"
 #include "RCTMacros.h"
 
diff --git a/React/Profiler/RCTProfileTrampoline-x86_64.S b/React/Profiler/RCTProfileTrampoline-x86_64.S
index 9a7a81c8594a..02fa010a4814 100644
--- a/React/Profiler/RCTProfileTrampoline-x86_64.S
+++ b/React/Profiler/RCTProfileTrampoline-x86_64.S
@@ -1,3 +1,12 @@
+/**
+ * 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.
+ */
+
 #include "RCTDefines.h"
 #include "RCTMacros.h"
 
diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj
index b04420043bcd..4250901f6893 100644
--- a/React/React.xcodeproj/project.pbxproj
+++ b/React/React.xcodeproj/project.pbxproj
@@ -21,7 +21,6 @@
 		137327E81AA5CF210034F82E /* RCTTabBarItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E21AA5CF210034F82E /* RCTTabBarItem.m */; };
 		137327E91AA5CF210034F82E /* RCTTabBarItemManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E41AA5CF210034F82E /* RCTTabBarItemManager.m */; };
 		137327EA1AA5CF210034F82E /* RCTTabBarManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E61AA5CF210034F82E /* RCTTabBarManager.m */; };
-		1385D0341B665AAE000A309B /* RCTModuleMap.m in Sources */ = {isa = PBXBuildFile; fileRef = 1385D0331B665AAE000A309B /* RCTModuleMap.m */; };
 		13A0C2891B74F71200B29F6F /* RCTDevLoadingView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A0C2861B74F71200B29F6F /* RCTDevLoadingView.m */; };
 		13A0C28A1B74F71200B29F6F /* RCTDevMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A0C2881B74F71200B29F6F /* RCTDevMenu.m */; };
 		13A1F71E1A75392D00D3D453 /* RCTKeyCommands.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A1F71D1A75392D00D3D453 /* RCTKeyCommands.m */; };
@@ -48,6 +47,7 @@
 		13E067561A70F44B002CDEE1 /* RCTViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E0674E1A70F44B002CDEE1 /* RCTViewManager.m */; };
 		13E067571A70F44B002CDEE1 /* RCTView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E067501A70F44B002CDEE1 /* RCTView.m */; };
 		13E067591A70F44B002CDEE1 /* UIView+React.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E067541A70F44B002CDEE1 /* UIView+React.m */; };
+		13E41EEB1C05CA0B00CD8DAC /* RCTProfileTrampoline-i386.S in Sources */ = {isa = PBXBuildFile; fileRef = 14BF717F1C04793D00C97D0C /* RCTProfileTrampoline-i386.S */; };
 		13F17A851B8493E5007D4C75 /* RCTRedBox.m in Sources */ = {isa = PBXBuildFile; fileRef = 13F17A841B8493E5007D4C75 /* RCTRedBox.m */; };
 		14200DAA1AC179B3008EE6BA /* RCTJavaScriptLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 14200DA91AC179B3008EE6BA /* RCTJavaScriptLoader.m */; };
 		142014191B32094000CC17BA /* RCTPerformanceLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 142014171B32094000CC17BA /* RCTPerformanceLogger.m */; };
@@ -57,7 +57,6 @@
 		1450FF871BCFF28A00208362 /* RCTProfileTrampoline-arm.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF821BCFF28A00208362 /* RCTProfileTrampoline-arm.S */; };
 		1450FF881BCFF28A00208362 /* RCTProfileTrampoline-arm64.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF831BCFF28A00208362 /* RCTProfileTrampoline-arm64.S */; };
 		1450FF8A1BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF851BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S */; };
-		14BF71801C04793D00C97D0C /* RCTProfileTrampoline-i386.S in Sources */ = {isa = PBXBuildFile; fileRef = 14BF717F1C04793D00C97D0C /* RCTProfileTrampoline-i386.S */; };
 		14C2CA711B3AC63800E6CBB2 /* RCTModuleMethod.m in Sources */ = {isa = PBXBuildFile; fileRef = 14C2CA701B3AC63800E6CBB2 /* RCTModuleMethod.m */; };
 		14C2CA741B3AC64300E6CBB2 /* RCTModuleData.m in Sources */ = {isa = PBXBuildFile; fileRef = 14C2CA731B3AC64300E6CBB2 /* RCTModuleData.m */; };
 		14C2CA761B3AC64F00E6CBB2 /* RCTFrameUpdate.m in Sources */ = {isa = PBXBuildFile; fileRef = 14C2CA751B3AC64F00E6CBB2 /* RCTFrameUpdate.m */; };
@@ -134,8 +133,6 @@
 		137327E41AA5CF210034F82E /* RCTTabBarItemManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTabBarItemManager.m; sourceTree = "<group>"; };
 		137327E51AA5CF210034F82E /* RCTTabBarManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTabBarManager.h; sourceTree = "<group>"; };
 		137327E61AA5CF210034F82E /* RCTTabBarManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTabBarManager.m; sourceTree = "<group>"; };
-		1385D0331B665AAE000A309B /* RCTModuleMap.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTModuleMap.m; sourceTree = "<group>"; };
-		1385D0351B6661DB000A309B /* RCTModuleMap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTModuleMap.h; sourceTree = "<group>"; };
 		13A0C2851B74F71200B29F6F /* RCTDevLoadingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDevLoadingView.h; sourceTree = "<group>"; };
 		13A0C2861B74F71200B29F6F /* RCTDevLoadingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDevLoadingView.m; sourceTree = "<group>"; };
 		13A0C2871B74F71200B29F6F /* RCTDevMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDevMenu.h; sourceTree = "<group>"; };
@@ -432,7 +429,6 @@
 			isa = PBXGroup;
 			children = (
 				14BF71811C04795500C97D0C /* RCTMacros.h */,
-				14BF717F1C04793D00C97D0C /* RCTProfileTrampoline-i386.S */,
 				14F7A0EB1BDA3B3C003C6C10 /* RCTPerfMonitor.m */,
 				14F7A0EE1BDA714B003C6C10 /* RCTFPSGraph.h */,
 				14F7A0EF1BDA714B003C6C10 /* RCTFPSGraph.m */,
@@ -440,6 +436,7 @@
 				1450FF811BCFF28A00208362 /* RCTProfile.m */,
 				1450FF821BCFF28A00208362 /* RCTProfileTrampoline-arm.S */,
 				1450FF831BCFF28A00208362 /* RCTProfileTrampoline-arm64.S */,
+				14BF717F1C04793D00C97D0C /* RCTProfileTrampoline-i386.S */,
 				1450FF851BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S */,
 			);
 			path = Profiler;
@@ -506,8 +503,6 @@
 				83CBBA4E1A601E3B00E9B192 /* RCTLog.m */,
 				14C2CA721B3AC64300E6CBB2 /* RCTModuleData.h */,
 				14C2CA731B3AC64300E6CBB2 /* RCTModuleData.m */,
-				1385D0351B6661DB000A309B /* RCTModuleMap.h */,
-				1385D0331B665AAE000A309B /* RCTModuleMap.m */,
 				14C2CA6F1B3AC63800E6CBB2 /* RCTModuleMethod.h */,
 				14C2CA701B3AC63800E6CBB2 /* RCTModuleMethod.m */,
 				142014181B32094000CC17BA /* RCTPerformanceLogger.h */,
@@ -643,6 +638,7 @@
 				1450FF8A1BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S in Sources */,
 				14F7A0EC1BDA3B3C003C6C10 /* RCTPerfMonitor.m in Sources */,
 				1450FF881BCFF28A00208362 /* RCTProfileTrampoline-arm64.S in Sources */,
+				13E41EEB1C05CA0B00CD8DAC /* RCTProfileTrampoline-i386.S in Sources */,
 				13B080061A6947C200A75B9A /* RCTScrollViewManager.m in Sources */,
 				14200DAA1AC179B3008EE6BA /* RCTJavaScriptLoader.m in Sources */,
 				137327EA1AA5CF210034F82E /* RCTTabBarManager.m in Sources */,
@@ -683,8 +679,6 @@
 				83392EB31B6634E10013B15F /* RCTModalHostViewController.m in Sources */,
 				14435CE51AAC4AE100FC20F4 /* RCTMap.m in Sources */,
 				13B0801C1A69489C00A75B9A /* RCTNavItem.m in Sources */,
-				14BF71801C04793D00C97D0C /* RCTProfileTrampoline-i386.S in Sources */,
-				1385D0341B665AAE000A309B /* RCTModuleMap.m in Sources */,
 				83CBBA691A601EF300E9B192 /* RCTEventDispatcher.m in Sources */,
 				83A1FE8F1B62643A00BE0E65 /* RCTModalHostViewManager.m in Sources */,
 				13E0674A1A70F434002CDEE1 /* RCTUIManager.m in Sources */,
diff --git a/React/Views/RCTComponentData.h b/React/Views/RCTComponentData.h
index 9a43e9865a39..f7151c22b543 100644
--- a/React/Views/RCTComponentData.h
+++ b/React/Views/RCTComponentData.h
@@ -12,16 +12,19 @@
 #import "RCTComponent.h"
 #import "RCTDefines.h"
 
+@class RCTBridge;
 @class RCTShadowView;
 @class RCTViewManager;
 @class UIView;
 
 @interface RCTComponentData : NSObject
 
+@property (nonatomic, readonly) Class managerClass;
 @property (nonatomic, copy, readonly) NSString *name;
 @property (nonatomic, strong, readonly) RCTViewManager *manager;
 
-- (instancetype)initWithManager:(RCTViewManager *)manager NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithManagerClass:(Class)managerClass
+                              bridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
 
 - (UIView *)createViewWithTag:(NSNumber *)tag props:(NSDictionary<NSString *, id> *)props;
 - (RCTShadowView *)createShadowViewWithTag:(NSNumber *)tag;
diff --git a/React/Views/RCTComponentData.m b/React/Views/RCTComponentData.m
index 20c64c3e1582..dbcbc10c9f2c 100644
--- a/React/Views/RCTComponentData.m
+++ b/React/Views/RCTComponentData.m
@@ -44,16 +44,21 @@ @implementation RCTComponentData
   RCTShadowView *_defaultShadowView;
   NSMutableDictionary<NSString *, RCTPropBlock> *_viewPropBlocks;
   NSMutableDictionary<NSString *, RCTPropBlock> *_shadowPropBlocks;
+  RCTBridge *_bridge;
 }
 
-- (instancetype)initWithManager:(RCTViewManager *)manager
+@synthesize manager = _manager;
+
+- (instancetype)initWithManagerClass:(Class)managerClass
+                              bridge:(RCTBridge *)bridge
 {
   if ((self = [super init])) {
-    _manager = manager;
+    _bridge = bridge;
+    _managerClass = managerClass;
     _viewPropBlocks = [NSMutableDictionary new];
     _shadowPropBlocks = [NSMutableDictionary new];
 
-    _name = RCTBridgeModuleNameForClass([manager class]);
+    _name = RCTBridgeModuleNameForClass(_managerClass);
     RCTAssert(_name.length, @"Invalid moduleName '%@'", _name);
     if ([_name hasSuffix:@"Manager"]) {
       _name = [_name substringToIndex:_name.length - @"Manager".length];
@@ -62,13 +67,21 @@ - (instancetype)initWithManager:(RCTViewManager *)manager
   return self;
 }
 
+- (RCTViewManager *)manager
+{
+  if (!_manager) {
+    _manager = [_bridge moduleForClass:_managerClass];
+  }
+  return _manager;
+}
+
 RCT_NOT_IMPLEMENTED(- (instancetype)init)
 
 - (UIView *)createViewWithTag:(NSNumber *)tag props:(NSDictionary<NSString *, id> *)props
 {
   RCTAssertMainThread();
 
-  UIView *view = (UIView *)(props ? [_manager viewWithProps:props] : [_manager view]);
+  UIView *view = (UIView *)(props ? [self.manager viewWithProps:props] : [_manager view]);
   view.reactTag = tag;
   view.multipleTouchEnabled = YES;
   view.userInteractionEnabled = YES; // required for touch handling
@@ -78,7 +91,7 @@ - (UIView *)createViewWithTag:(NSNumber *)tag props:(NSDictionary<NSString *, id
 
 - (RCTShadowView *)createShadowViewWithTag:(NSNumber *)tag
 {
-  RCTShadowView *shadowView = [_manager shadowView];
+  RCTShadowView *shadowView = [self.manager shadowView];
   shadowView.reactTag = tag;
   shadowView.viewName = _name;
   return shadowView;
@@ -310,15 +323,13 @@ - (void)setProps:(NSDictionary<NSString *, id> *)props forShadowView:(RCTShadowV
 
 - (NSDictionary<NSString *, id> *)viewConfig
 {
-  Class managerClass = [_manager class];
-
   NSMutableArray<NSString *> *directEvents = [NSMutableArray new];
-  if (RCTClassOverridesInstanceMethod(managerClass, @selector(customDirectEventTypes))) {
-    NSArray<NSString *> *events = [_manager customDirectEventTypes];
+  if (RCTClassOverridesInstanceMethod(_managerClass, @selector(customDirectEventTypes))) {
+    NSArray<NSString *> *events = [self.manager customDirectEventTypes];
     if (RCT_DEBUG) {
       RCTAssert(!events || [events isKindOfClass:[NSArray class]],
         @"customDirectEventTypes must return an array, but %@ returned %@",
-        managerClass, [events class]);
+        _managerClass, [events class]);
     }
     for (NSString *event in events) {
       [directEvents addObject:RCTNormalizeInputEventName(event)];
@@ -326,12 +337,12 @@ - (void)setProps:(NSDictionary<NSString *, id> *)props forShadowView:(RCTShadowV
   }
 
   NSMutableArray<NSString *> *bubblingEvents = [NSMutableArray new];
-  if (RCTClassOverridesInstanceMethod(managerClass, @selector(customBubblingEventTypes))) {
-    NSArray<NSString *> *events = [_manager customBubblingEventTypes];
+  if (RCTClassOverridesInstanceMethod(_managerClass, @selector(customBubblingEventTypes))) {
+    NSArray<NSString *> *events = [self.manager customBubblingEventTypes];
     if (RCT_DEBUG) {
       RCTAssert(!events || [events isKindOfClass:[NSArray class]],
         @"customBubblingEventTypes must return an array, but %@ returned %@",
-        managerClass, [events class]);
+        _managerClass, [events class]);
     }
     for (NSString *event in events) {
       [bubblingEvents addObject:RCTNormalizeInputEventName(event)];
@@ -340,7 +351,7 @@ - (void)setProps:(NSDictionary<NSString *, id> *)props forShadowView:(RCTShadowV
 
   unsigned int count = 0;
   NSMutableDictionary *propTypes = [NSMutableDictionary new];
-  Method *methods = class_copyMethodList(object_getClass(managerClass), &count);
+  Method *methods = class_copyMethodList(object_getClass(_managerClass), &count);
   for (unsigned int i = 0; i < count; i++) {
     Method method = methods[i];
     SEL selector = method_getName(method);
@@ -349,7 +360,7 @@ - (void)setProps:(NSDictionary<NSString *, id> *)props forShadowView:(RCTShadowV
       NSRange nameRange = [methodName rangeOfString:@"_"];
       if (nameRange.length) {
         NSString *name = [methodName substringFromIndex:nameRange.location + 1];
-        NSString *type = ((NSArray<NSString *> *(*)(id, SEL))objc_msgSend)(managerClass, selector)[0];
+        NSString *type = ((NSArray<NSString *> *(*)(id, SEL))objc_msgSend)(_managerClass, selector)[0];
         if (RCT_DEBUG && propTypes[name] && ![propTypes[name] isEqualToString:type]) {
           RCTLogError(@"Property '%@' of component '%@' redefined from '%@' "
                       "to '%@'", name, _name, propTypes[name], type);
diff --git a/React/Views/RCTModalHostViewController.m b/React/Views/RCTModalHostViewController.m
index 055036726bcd..ce40551bddc0 100644
--- a/React/Views/RCTModalHostViewController.m
+++ b/React/Views/RCTModalHostViewController.m
@@ -9,7 +9,8 @@
 
 #import "RCTModalHostViewController.h"
 
-@implementation RCTModalHostViewController {
+@implementation RCTModalHostViewController
+{
   CGRect _lastViewFrame;
 }
 
diff --git a/React/Views/RCTModalHostViewManager.m b/React/Views/RCTModalHostViewManager.m
index 3ad022b213fb..ae3b21f2c063 100644
--- a/React/Views/RCTModalHostViewManager.m
+++ b/React/Views/RCTModalHostViewManager.m
@@ -20,18 +20,12 @@ @implementation RCTModalHostViewManager
 
 RCT_EXPORT_MODULE()
 
-- (instancetype)init
-{
-  if ((self = [super init])) {
-    _hostViews = [NSHashTable weakObjectsHashTable];
-  }
-
-  return self;
-}
-
 - (UIView *)view
 {
   UIView *view = [[RCTModalHostView alloc] initWithBridge:self.bridge];
+  if (_hostViews) {
+    _hostViews = [NSHashTable weakObjectsHashTable];
+  }
   [_hostViews addObject:view];
   return view;
 }
diff --git a/React/Views/RCTViewManager.h b/React/Views/RCTViewManager.h
index def09910d286..235f52a7b2ee 100644
--- a/React/Views/RCTViewManager.h
+++ b/React/Views/RCTViewManager.h
@@ -30,7 +30,7 @@ typedef void (^RCTViewManagerUIBlock)(RCTUIManager *uiManager, NSDictionary<NSNu
  * allowing the manager (or the views that it manages) to manipulate the view
  * hierarchy and send events back to the JS context.
  */
-@property (nonatomic, weak) RCTBridge *bridge;
+@property (nonatomic, weak, readonly) RCTBridge *bridge;
 
 /**
  * This method instantiates a native view to be managed by the module. Override
diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m
index ef70a4cdd440..aaac6d27987d 100644
--- a/React/Views/RCTViewManager.m
+++ b/React/Views/RCTViewManager.m
@@ -95,11 +95,6 @@ - (RCTShadowView *)shadowView
   return @[];
 }
 
-- (NSDictionary<NSString *, id> *)constantsToExport
-{
-  return nil;
-}
-
 - (RCTViewManagerUIBlock)uiBlockToAmendWithShadowView:(__unused RCTShadowView *)shadowView
 {
   return nil;

From 638fd11c5c7b1bd10069205f2063aac0e887b414 Mon Sep 17 00:00:00 2001
From: Milen Dzhumerov <mgd@fb.com>
Date: Wed, 25 Nov 2015 05:20:34 -0800
Subject: [PATCH 0104/1411] Revert 3770f061c832 for further investigation

Reviewed By: idevelop

Differential Revision: D2695659

fb-gh-sync-id: b1ba529c648681faef5d4f07273722764722fbe1
---
 Libraries/Storage/AsyncStorage.js    | 25 -------------------------
 React/Modules/RCTAsyncLocalStorage.m | 18 ------------------
 2 files changed, 43 deletions(-)

diff --git a/Libraries/Storage/AsyncStorage.js b/Libraries/Storage/AsyncStorage.js
index 4b3a8e0008bb..c5be992e2aba 100644
--- a/Libraries/Storage/AsyncStorage.js
+++ b/Libraries/Storage/AsyncStorage.js
@@ -137,26 +137,6 @@ var AsyncStorage = {
     });
   },
 
-  /**
-   * Erases all keys with a particular prefix. Useful if all your keys have a
-   * specific prefix.
-   */
-  clearPrefix: function(
-    prefix: string,
-    callback?: ?(error: ?Error) => void
-  ): Promise {
-    return new Promise((resolve, reject) => {
-      RCTAsyncStorage.clearPrefix(prefix, function(error) {
-        callback && callback(convertError(error));
-        if (error && convertError(error)){
-          reject(convertError(error));
-        } else {
-          resolve(null);
-        }
-      });
-    });
-  },
-
   /**
    * Gets *all* keys known to the app, for all callers, libraries, etc. Returns a `Promise` object.
    */
@@ -279,11 +259,6 @@ if (!RCTAsyncStorage.multiMerge) {
   delete AsyncStorage.multiMerge;
 }
 
-// clearPrefix() only supported by certain backends
-if (!RCTAsyncStorage.clearPrefix) {
-  delete AsyncStorage.clearPrefix;
-}
-
 function convertErrors(errs) {
   if (!errs) {
     return null;
diff --git a/React/Modules/RCTAsyncLocalStorage.m b/React/Modules/RCTAsyncLocalStorage.m
index eceb15847c2a..273ef40c6bf8 100644
--- a/React/Modules/RCTAsyncLocalStorage.m
+++ b/React/Modules/RCTAsyncLocalStorage.m
@@ -435,24 +435,6 @@ - (NSDictionary *)_writeEntry:(NSArray<NSString *> *)entry changedManifest:(BOOL
   callback(@[RCTNullIfNil(error)]);
 }
 
-RCT_EXPORT_METHOD(clearPrefix:(NSString *)prefix callack:(RCTResponseSenderBlock)callback)
-{
-  NSDictionary *errorOut = [self _ensureSetup];
-  if (errorOut) {
-    callback(@[errorOut]);
-    return;
-  }
-
-  NSMutableArray<NSString *> *keys = [NSMutableArray array];
-  for (NSString *key in _manifest.allKeys) {
-    if ([key hasPrefix:prefix]) {
-      [keys addObject:key];
-    }
-  }
-
-  [self multiRemove:keys callback:callback];
-}
-
 RCT_EXPORT_METHOD(getAllKeys:(RCTResponseSenderBlock)callback)
 {
   NSDictionary *errorOut = [self _ensureSetup];

From 388d8c8f9bd2d27194779e682747359a00cb4b86 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Wed, 25 Nov 2015 13:41:40 +0000
Subject: [PATCH 0105/1411] Update breaking-changes.md

---
 breaking-changes.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/breaking-changes.md b/breaking-changes.md
index b4448fb2aca8..77f27ca393ea 100644
--- a/breaking-changes.md
+++ b/breaking-changes.md
@@ -6,6 +6,7 @@
 - YellowBox enabled by default: [8ab518](https://github.com/facebook/react-native/commit/8ab51828ff077ae0ad10c06f62f9f01d58b9bf85)
 - React Native now uses Babel 6 (props to tadeuzagallo for upgrading!). We've been using React Native with Babel 6 at Facebook for quite a while now. Nevertheless, please report any errors related to Babel, such as transforms for some JS features not working as expected and we'll fix them.
 - Decorators won't work until [T2645](https://phabricator.babeljs.io/T2645) lands in Babel.
+- Exporting default class that extends a base class won't work due to Babel's [T2694](https://phabricator.babeljs.io/T2694).
 
 ## 0.15
 

From ca016e4eb30e4535c42e8e108ea6ff06e2b44b44 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Wed, 25 Nov 2015 04:56:15 -0800
Subject: [PATCH 0106/1411] Add perf markers for cold start

Summary: public

Adds useful systrace perf markers for cold start analysis

Reviewed By: mikearmstrong001

Differential Revision: D2695629

fb-gh-sync-id: d964f28a1f3e10a13c441a17b0300c980d4914e8
---
 .../facebook/react/CoreModulesPackage.java    | 15 +++-
 .../react/ReactInstanceManagerImpl.java       | 73 ++++++++++++++++---
 .../react/bridge/CatalystInstanceImpl.java    | 50 +++++++++----
 .../react/bridge/NativeModuleRegistry.java    | 47 ++++++------
 .../react/uimanager/UIManagerModule.java      | 18 ++++-
 5 files changed, 147 insertions(+), 56 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java b/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java
index a7bc29aa63a1..02bd96d0dc0f 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java
@@ -32,6 +32,7 @@
 import com.facebook.react.uimanager.ViewManager;
 import com.facebook.react.uimanager.debug.DebugComponentOwnershipModule;
 import com.facebook.react.uimanager.events.RCTEventEmitter;
+import com.facebook.systrace.Systrace;
 
 /**
  * Package defining core framework modules (e.g. UIManager). It should be used for modules that
@@ -53,6 +54,16 @@
   @Override
   public List<NativeModule> createNativeModules(
       ReactApplicationContext catalystApplicationContext) {
+    Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "createUIManagerModule");
+    UIManagerModule uiManagerModule;
+    try {
+      uiManagerModule = new UIManagerModule(
+          catalystApplicationContext,
+          mReactInstanceManager.createAllViewManagers(catalystApplicationContext));
+    } finally {
+      Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+    }
+
     return Arrays.<NativeModule>asList(
         new AnimationsDebugModule(
             catalystApplicationContext,
@@ -64,9 +75,7 @@ public List<NativeModule> createNativeModules(
         new SourceCodeModule(
             mReactInstanceManager.getSourceUrl(),
             mReactInstanceManager.getDevSupportManager().getSourceMapUrl()),
-        new UIManagerModule(
-            catalystApplicationContext,
-            mReactInstanceManager.createAllViewManagers(catalystApplicationContext)),
+        uiManagerModule,
         new DebugComponentOwnershipModule(catalystApplicationContext));
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index f8e0cdc0448a..deb6bf21c29b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -55,6 +55,7 @@
 import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.ViewManager;
 import com.facebook.soloader.SoLoader;
+import com.facebook.systrace.Systrace;
 
 /**
  * This class is managing instances of {@link CatalystInstance}. It expose a way to configure
@@ -465,11 +466,16 @@ public void detachRootView(ReactRootView rootView) {
   @Override
   public List<ViewManager> createAllViewManagers(
       ReactApplicationContext catalystApplicationContext) {
-    List<ViewManager> allViewManagers = new ArrayList<>();
-    for (ReactPackage reactPackage : mPackages) {
-      allViewManagers.addAll(reactPackage.createViewManagers(catalystApplicationContext));
+    Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "createAllViewManagers");
+    try {
+      List<ViewManager> allViewManagers = new ArrayList<>();
+      for (ReactPackage reactPackage : mPackages) {
+        allViewManagers.addAll(reactPackage.createViewManagers(catalystApplicationContext));
+      }
+      return allViewManagers;
+    } finally {
+      Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
     }
-    return allViewManagers;
   }
 
   @VisibleForTesting
@@ -586,30 +592,73 @@ private ReactApplicationContext createReactContext(
       reactContext.setNativeModuleCallExceptionHandler(mDevSupportManager);
     }
 
-    CoreModulesPackage coreModulesPackage =
-        new CoreModulesPackage(this, mBackBtnHandler);
-    processPackage(coreModulesPackage, reactContext, nativeRegistryBuilder, jsModulesBuilder);
+    Systrace.beginSection(
+        Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
+        "createAndProcessCoreModulesPackage");
+    try {
+      CoreModulesPackage coreModulesPackage =
+          new CoreModulesPackage(this, mBackBtnHandler);
+      processPackage(coreModulesPackage, reactContext, nativeRegistryBuilder, jsModulesBuilder);
+    } finally {
+      Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+    }
 
     // TODO(6818138): Solve use-case of native/js modules overriding
     for (ReactPackage reactPackage : mPackages) {
-      processPackage(reactPackage, reactContext, nativeRegistryBuilder, jsModulesBuilder);
+      Systrace.beginSection(
+          Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
+          "createAndProcessCustomReactPackage");
+      try {
+        processPackage(reactPackage, reactContext, nativeRegistryBuilder, jsModulesBuilder);
+      } finally {
+        Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+      }
+    }
+
+    Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "buildNativeModuleRegistry");
+    NativeModuleRegistry nativeModuleRegistry;
+    try {
+       nativeModuleRegistry = nativeRegistryBuilder.build();
+    } finally {
+      Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+    }
+
+    Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "buildJSModuleConfig");
+    JavaScriptModulesConfig javaScriptModulesConfig;
+    try {
+      javaScriptModulesConfig = jsModulesBuilder.build();
+    } finally {
+      Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
     }
 
     CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
         .setCatalystQueueConfigurationSpec(CatalystQueueConfigurationSpec.createDefault())
         .setJSExecutor(jsExecutor)
-        .setRegistry(nativeRegistryBuilder.build())
-        .setJSModulesConfig(jsModulesBuilder.build())
+        .setRegistry(nativeModuleRegistry)
+        .setJSModulesConfig(javaScriptModulesConfig)
         .setJSBundleLoader(jsBundleLoader)
         .setNativeModuleCallExceptionHandler(mDevSupportManager);
 
-    CatalystInstance catalystInstance = catalystInstanceBuilder.build();
+    Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstance");
+    CatalystInstance catalystInstance;
+    try {
+      catalystInstance = catalystInstanceBuilder.build();
+    } finally {
+      Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+    }
+
     if (mBridgeIdleDebugListener != null) {
       catalystInstance.addBridgeIdleDebugListener(mBridgeIdleDebugListener);
     }
 
     reactContext.initializeWithInstance(catalystInstance);
-    catalystInstance.runJSBundle();
+
+    Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "runJSBundle");
+    try {
+      catalystInstance.runJSBundle();
+    } finally {
+      Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+    }
 
     return reactContext;
   }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
index 4b987e78d256..08f5a702100b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
@@ -88,8 +88,13 @@ private CatalystInstanceImpl(
         new Runnable() {
           @Override
           public void run() {
-            initializeBridge(jsExecutor, jsModulesConfig);
-            initLatch.countDown();
+            Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "initializeBridge");
+            try {
+              initializeBridge(jsExecutor, jsModulesConfig);
+              initLatch.countDown();
+            } finally {
+              Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+            }
           }
         });
 
@@ -108,22 +113,31 @@ private void initializeBridge(
     mCatalystQueueConfiguration.getJSQueueThread().assertIsOnThread();
     Assertions.assertCondition(mBridge == null, "initializeBridge should be called once");
 
-    mBridge = new ReactBridge(
-        jsExecutor,
-        new NativeModulesReactCallback(),
-        mCatalystQueueConfiguration.getNativeModulesQueueThread());
-    mBridge.setGlobalVariable(
-        "__fbBatchedBridgeConfig",
-        buildModulesConfigJSONProperty(mJavaRegistry, jsModulesConfig));
-    Systrace.registerListener(mTraceListener);
+    Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ReactBridgeCtor");
+    try {
+      mBridge = new ReactBridge(
+          jsExecutor,
+          new NativeModulesReactCallback(),
+          mCatalystQueueConfiguration.getNativeModulesQueueThread());
+    } finally {
+      Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+    }
+
+    Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "setBatchedBridgeConfig");
+    try {
+      mBridge.setGlobalVariable(
+          "__fbBatchedBridgeConfig",
+          buildModulesConfigJSONProperty(mJavaRegistry, jsModulesConfig));
+      mBridge.setGlobalVariable(
+          "__RCTProfileIsProfiling",
+          Systrace.isTracing(Systrace.TRACE_TAG_REACT_APPS) ? "true" : "false");
+    } finally {
+      Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+    }
   }
 
   @Override
   public void runJSBundle() {
-    Systrace.beginSection(
-        Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
-        "CatalystInstance_runJSBundle");
-
     try {
       final CountDownLatch initLatch = new CountDownLatch(1);
       mCatalystQueueConfiguration.getJSQueueThread().runOnQueue(
@@ -135,10 +149,16 @@ public void run() {
 
               incrementPendingJSCalls();
 
+              Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "loadJSScript");
               try {
                 mJSBundleLoader.loadScript(mBridge);
+
+                // This is registered after JS starts since it makes a JS call
+                Systrace.registerListener(mTraceListener);
               } catch (JSExecutionException e) {
                 mNativeModuleCallExceptionHandler.handleException(e);
+              } finally {
+                Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
               }
 
               initLatch.countDown();
@@ -149,8 +169,6 @@ public void run() {
           "Timed out loading JS!");
     } catch (InterruptedException e) {
       throw new RuntimeException(e);
-    } finally {
-      Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
     }
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java
index 72b3ad666953..80b1b4616119 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java
@@ -13,7 +13,6 @@
 import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
@@ -186,32 +185,38 @@ public Builder add(NativeModule module) {
     }
 
     public NativeModuleRegistry build() {
-      JsonFactory jsonFactory = new JsonFactory();
-      StringWriter writer = new StringWriter();
+      Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "CreateJSON");
+      String moduleDefinitionJson;
       try {
-        JsonGenerator jg = jsonFactory.createGenerator(writer);
-        jg.writeStartObject();
-        for (ModuleDefinition module : mModuleDefinitions) {
-          jg.writeObjectFieldStart(module.name);
-          jg.writeNumberField("moduleID", module.id);
-          jg.writeObjectFieldStart("methods");
-          for (int i = 0; i < module.methods.size(); i++) {
-            MethodRegistration method = module.methods.get(i);
-            jg.writeObjectFieldStart(method.name);
-            jg.writeNumberField("methodID", i);
-            jg.writeStringField("type", method.method.getType());
+        JsonFactory jsonFactory = new JsonFactory();
+        StringWriter writer = new StringWriter();
+        try {
+          JsonGenerator jg = jsonFactory.createGenerator(writer);
+          jg.writeStartObject();
+          for (ModuleDefinition module : mModuleDefinitions) {
+            jg.writeObjectFieldStart(module.name);
+            jg.writeNumberField("moduleID", module.id);
+            jg.writeObjectFieldStart("methods");
+            for (int i = 0; i < module.methods.size(); i++) {
+              MethodRegistration method = module.methods.get(i);
+              jg.writeObjectFieldStart(method.name);
+              jg.writeNumberField("methodID", i);
+              jg.writeStringField("type", method.method.getType());
+              jg.writeEndObject();
+            }
+            jg.writeEndObject();
+            module.target.writeConstantsField(jg, "constants");
             jg.writeEndObject();
           }
           jg.writeEndObject();
-          module.target.writeConstantsField(jg, "constants");
-          jg.writeEndObject();
+          jg.close();
+        } catch (IOException ioe) {
+          throw new RuntimeException("Unable to serialize Java module configuration", ioe);
         }
-        jg.writeEndObject();
-        jg.close();
-      } catch (IOException ioe) {
-        throw new RuntimeException("Unable to serialize Java module configuration", ioe);
+        moduleDefinitionJson = writer.getBuffer().toString();
+      } finally {
+        Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
       }
-      String moduleDefinitionJson = writer.getBuffer().toString();
       return new NativeModuleRegistry(mModuleDefinitions, mModuleInstances, moduleDefinitionJson);
     }
   }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
index 38e78cc65b66..1512f305f7e7 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
@@ -106,10 +106,7 @@ public UIManagerModule(ReactApplicationContext reactContext, List<ViewManager> v
         mShadowNodeRegistry);
     DisplayMetrics displayMetrics = reactContext.getResources().getDisplayMetrics();
     DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
-
-    mModuleConstants = UIManagerModuleConstantsHelper.createConstants(
-        displayMetrics,
-        viewManagerList);
+    mModuleConstants = createConstants(displayMetrics, viewManagerList);
     reactContext.addLifecycleEventListener(this);
   }
 
@@ -143,6 +140,19 @@ public void onCatalystInstanceDestroy() {
     mEventDispatcher.onCatalystInstanceDestroyed();
   }
 
+  private static Map<String, Object> createConstants(
+      DisplayMetrics displayMetrics,
+      List<ViewManager> viewManagerList) {
+    Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "CreateUIManagerConstants");
+    try {
+      return UIManagerModuleConstantsHelper.createConstants(
+          displayMetrics,
+          viewManagerList);
+    } finally {
+      Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+    }
+  }
+
   /**
    * Registers a new root view. JS can use the returned tag with manageChildren to add/remove
    * children to this view.

From a663d4d8d5daa601c43d85871fe8b335eb848dd2 Mon Sep 17 00:00:00 2001
From: Milen Dzhumerov <mgd@fb.com>
Date: Wed, 25 Nov 2015 07:22:28 -0800
Subject: [PATCH 0107/1411] Use for-loop instead of forEach() in a hot path

Summary: public

Replaces the usage of forEach() with a for loop on a hot code path

Reviewed By: tadeuzagallo

Differential Revision: D2690727

fb-gh-sync-id: b7cbcda5cf80a0e31753f49c01e145abb789f3e5
---
 .../System/JSTimers/JSTimersExecution.js                  | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimersExecution.js b/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimersExecution.js
index bc2b74d220f0..07a324d41f4c 100644
--- a/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimersExecution.js
+++ b/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimersExecution.js
@@ -121,9 +121,11 @@ var JSTimersExecution = {
       var passImmediates = JSTimersExecution.immediates.slice();
       JSTimersExecution.immediates = [];
 
-      passImmediates.forEach((timerID) => {
-        JSTimersExecution.callTimer(timerID);
-      });
+      // Use for loop rather than forEach as per @vjeux's advice
+      // https://github.com/facebook/react-native/commit/c8fd9f7588ad02d2293cac7224715f4af7b0f352#commitcomment-14570051
+      for (var i = 0; i < passImmediates.length; ++i) {
+        JSTimersExecution.callTimer(passImmediates[i]);
+      }
     }
 
     BridgeProfiling.profileEnd();

From e966cd104110a980f343b794d85ac1b3afb2449e Mon Sep 17 00:00:00 2001
From: Chester Wood <chet@dewachen.org>
Date: Wed, 25 Nov 2015 12:43:39 -0800
Subject: [PATCH 0108/1411] Set navigator.product to ReactNative

Summary: Fix for [Issue 1331](https://github.com/facebook/react-native/issues/1331). Sets navigator.product to ReactNative and navigator.productSub to the version string in package.json.

Note that the code requires package.json, which works fine in the RN packager, but webpack users will probably a need to configure a json loader in their config file.

Tested using UIExplorer and console.log printout of the product variables in xcode and Chrome debugger.
Closes https://github.com/facebook/react-native/pull/4083

Reviewed By: svcscm

Differential Revision: D2696881

Pulled By: vjeux

fb-gh-sync-id: 511446432dcd0ec658100715129c77153e743423
---
 .../Initialization/InitializeJavaScriptAppEngine.js         | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
index ec13c1615032..9c2b7f58438b 100644
--- a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
+++ b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
@@ -154,6 +154,11 @@ function setUpGeolocation() {
   polyfillGlobal('geolocation', require('Geolocation'), GLOBAL.navigator);
 }
 
+function setUpProduct() {
+  Object.defineProperty(GLOBAL.navigator, 'product', {value: 'ReactNative'});
+}
+
+
 function setUpWebSockets() {
   polyfillGlobal('WebSocket', require('WebSocket'));
 }
@@ -197,6 +202,7 @@ setUpPromise();
 setUpErrorHandler();
 setUpXHR();
 setUpGeolocation();
+setUpProduct();
 setUpWebSockets();
 setUpProfile();
 setUpFlowChecker();

From 0d2eb748f744c54b24ea2363cce76dd9747433d5 Mon Sep 17 00:00:00 2001
From: Brent Vatne <brentvatne@gmail.com>
Date: Wed, 25 Nov 2015 14:10:03 -0800
Subject: [PATCH 0109/1411] =?UTF-8?q?[Docs]=20Re-imagining=20the=20showcas?=
 =?UTF-8?q?e=20=F0=9F=98=87?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 website/src/react-native/css/react-native.css |  11 +-
 website/src/react-native/showcase.js          | 298 +++++++++++-------
 2 files changed, 197 insertions(+), 112 deletions(-)

diff --git a/website/src/react-native/css/react-native.css b/website/src/react-native/css/react-native.css
index 54e3930f94b7..034d52e26e2e 100644
--- a/website/src/react-native/css/react-native.css
+++ b/website/src/react-native/css/react-native.css
@@ -701,6 +701,10 @@ figure {
   width: 650px;
 }
 
+.showcaseSection .inner-content {
+  width: 800px;
+}
+
 .nosidebar .inner-content {
   float: none;
   margin: 0 auto;
@@ -1084,18 +1088,17 @@ div[data-twttr-id] iframe {
 }
 
 .showcaseHeader {
-  text-align: center;
   padding-bottom: 15px;
   padding-top: 15px;
+  text-align: center;
 }
 
 .showcase {
-  margin: 30px auto;
+  margin: 30px auto 10px auto;
   width: 100%;
   display: inline-block;
   text-align: center;
   vertical-align: top;
-  transition: 0.2s opacity ease-in;
 }
 
 @media only screen
@@ -1109,7 +1112,7 @@ div[data-twttr-id] iframe {
 @media only screen
   and (min-device-width: 1024px) {
   .showcase {
-    width: 25%;
+    width: 20%;
   }
 }
 
diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 706615c45b79..987580237dd9 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -11,13 +11,111 @@ var React = require('React');
 var Site = require('Site');
 var center = require('center');
 
-var apps = [
+var featured = [
+  {
+    name: 'Facebook Groups',
+    icon: 'http://is4.mzstatic.com/image/pf/us/r30/Purple69/v4/57/f8/4c/57f84c0c-793d-5f9a-95ee-c212d0369e37/mzl.ugjwfhzx.png',
+    link: 'https://itunes.apple.com/us/app/facebook-groups/id931735837?mt=8',
+    author: 'Facebook',
+  },
   {
-    name: 'AIGA Design Conference 2015: New Orleans',
+    name: 'Facebook Ads Manager',
+    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple5/v4/9e/16/86/9e1686ef-cc55-805a-c977-538ddb5e6832/mzl.gqbhwitj.png',
+    linkAppStore: 'https://itunes.apple.com/us/app/facebook-ads-manager/id964397083?mt=8',
+    linkPlayStore: 'https://play.google.com/store/apps/details?id=com.facebook.adsmanager',
+    author: 'Facebook',
+    blogs: [
+      "https://code.facebook.com/posts/1014532261909640/react-native-bringing-modern-web-techniques-to-mobile/",
+      "https://code.facebook.com/posts/1189117404435352/react-native-for-android-how-we-built-the-first-cross-platform-react-native-app/",
+      "https://code.facebook.com/posts/435862739941212/making-react-native-apps-accessible/",
+    ],
+  },
+  {
+    name: 'AIGA Design Conference 2015',
     icon: 'http://a5.mzstatic.com/us/r30/Purple69/v4/b0/4b/29/b04b2939-88d2-f61f-dec9-24fae083d8b3/icon175x175.png',
     link: 'https://itunes.apple.com/us/app/aiga-design-conference-2015/id1038145272?ls=1&mt=8',
     author: 'W&Co',
   },
+  {
+    name: 'Discord',
+    icon: 'http://a5.mzstatic.com/us/r30/Purple5/v4/c1/2f/4c/c12f4cba-1d9a-f6bf-2240-04085d3470ec/icon175x175.jpeg',
+    link:  'https://itunes.apple.com/us/app/discord-chat-for-gamers/id985746746?mt=8',
+    author: 'Hammer & Chisel',
+  },
+  {
+    name: 'Discovery VR',
+    icon: 'http://a2.mzstatic.com/us/r30/Purple6/v4/d1/d5/f4/d1d5f437-9f6b-b5aa-5fe7-47bd19f934bf/icon175x175.png',
+    link:  'https://itunes.apple.com/us/app/discovery-vr/id1030815031?mt=8',
+    author: 'Discovery Communications',
+    blog: [
+      "https://medium.com/ios-os-x-development/an-ios-developer-on-react-native-1f24786c29f0",
+    ],
+  },
+  {
+    name: 'Exponent',
+    icon: 'http://a4.mzstatic.com/us/r30/Purple2/v4/3a/d3/c9/3ad3c96c-5e14-f988-4bdd-0fdc95efd140/icon175x175.png',
+    link:  'http://exponentjs.com/',
+    author: 'Exponent',
+  },
+  {
+    name: 'Lrn',
+    icon: 'http://is4.mzstatic.com/image/pf/us/r30/Purple1/v4/41/a9/e9/41a9e9b6-7801-aef7-2400-2eca14923321/mzl.adyswxad.png',
+    link: 'https://itunes.apple.com/us/app/lrn-learn-to-code-at-your/id1019622677',
+    author: 'Lrn Labs, Inc',
+  },
+  {
+    name: 'Myntra',
+    icon: 'http://a5.mzstatic.com/us/r30/Purple6/v4/9c/78/df/9c78dfa6-0061-1af2-5026-3e1d5a073c94/icon350x350.png',
+    link: 'https://itunes.apple.com/in/app/myntra-fashion-shopping-app/id907394059',
+    author: 'Myntra Designs',
+  },
+  {
+    name: 'React Native Playground',
+    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple1/v4/20/ec/8e/20ec8eb8-9e12-6686-cd16-7ac9e3ef1d52/mzl.ngvuoybx.png',
+    linkAppStore: 'https://itunes.apple.com/us/app/react-native-playground/id1002032944?mt=8',
+    linkPlayStore: 'https://play.google.com/store/apps/details?id=org.rnplay.playground',
+    author: 'Joshua Sierles',
+  },
+  {
+    name: 'Running',
+    icon: 'http://a1.mzstatic.com/us/r30/Purple3/v4/33/eb/4f/33eb4f73-c7e3-8659-9285-f758e403485b/icon175x175.jpeg',
+    link: 'https://gyrosco.pe/running/',
+    author: 'Gyroscope Innovations',
+    blogs: [
+      'https://blog.gyrosco.pe/the-making-of-gyroscope-running-a4ad10acc0d0',
+    ],
+  },
+  {
+    name: 'Squad',
+    icon: 'http://a4.mzstatic.com/us/r30/Purple69/v4/e8/5b/3f/e85b3f52-72f3-f427-a32e-a73efe2e9682/icon175x175.jpeg',
+    link: 'https://itunes.apple.com/us/app/squad-snaps-for-groups-friends/id1043626975?mt=8',
+    author: 'Tackk Inc.',
+  },
+  {
+    name: 'Start - medication manager for depression',
+    icon: 'http://a1.mzstatic.com/us/r30/Purple49/v4/de/9b/6f/de9b6fe8-84ea-7a12-ba2c-0a6d6c7b10b0/icon175x175.png',
+    link: 'https://itunes.apple.com/us/app/start-medication-manager-for/id1012099928?mt=8',
+    author: 'Iodine Inc.',
+  },
+  {
+    name: 'Townske',
+    icon: 'http://a3.mzstatic.com/us/r30/Purple69/v4/8b/42/20/8b4220af-5165-91fd-0f05-014332df73ef/icon175x175.png',
+    link: 'https://itunes.apple.com/us/app/townske-stunning-city-guides/id1018136179?ls=1&mt=8',
+    author: 'Townske PTY LTD',
+  },
+  {
+    name: 'Tucci',
+    icon: 'http://a3.mzstatic.com/us/r30/Purple3/v4/c0/0c/95/c00c95ce-4cc5-e516-db77-5c5164b89189/icon175x175.jpeg',
+    link: 'https://itunes.apple.com/app/apple-store/id1039661754?mt=8',
+    author: 'Clay Allsopp & Tiffany Young',
+    blogs: [
+      'https://medium.com/@clayallsopp/making-tucci-what-is-it-and-why-eaa2bf94c1df#.lmm3dmkaf',
+      'https://medium.com/@clayallsopp/making-tucci-the-technical-details-cc7aded6c75f#.wf72nq372',
+    ],
+  },
+];
+
+var apps = [
   {
     name: 'Beetroot',
     icon: 'http://is1.mzstatic.com/image/pf/us/r30/Purple5/v4/66/fd/dd/66fddd70-f848-4fc5-43ee-4d52197ccab8/pr_source.png',
@@ -44,54 +142,17 @@ var apps = [
     author: 'The Formations Factory Ltd',
   },
   {
-    name: 'DareU - dare your friends, dare the world',
+    name: 'DareU',
     icon: 'http://a3.mzstatic.com/us/r30/Purple6/v4/10/fb/6a/10fb6a50-57c8-061a-d865-503777bf7f00/icon175x175.png',
     link: 'https://itunes.apple.com/us/app/dareu-dare-your-friends-dare/id1046434563?mt=8',
     author: 'Rishabh Mehan',
   },
-  {
-    name: 'Discord',
-    icon: 'http://a5.mzstatic.com/us/r30/Purple5/v4/c1/2f/4c/c12f4cba-1d9a-f6bf-2240-04085d3470ec/icon175x175.jpeg',
-    link:  'https://itunes.apple.com/us/app/discord-chat-for-gamers/id985746746?mt=8',
-    author: 'Hammer & Chisel',
-  },
-  {
-    name: 'Discovery VR',
-    icon: 'http://a2.mzstatic.com/us/r30/Purple6/v4/d1/d5/f4/d1d5f437-9f6b-b5aa-5fe7-47bd19f934bf/icon175x175.png',
-    link:  'https://itunes.apple.com/us/app/discovery-vr/id1030815031?mt=8',
-    author: 'Discovery Communications',
-  },
   {
     name: 'DropBot',
     icon: 'http://a2.mzstatic.com/us/r30/Purple69/v4/fb/df/73/fbdf73e0-22d2-c936-3115-1defa195acba/icon175x175.png',
     link:  'https://itunes.apple.com/us/app/dropbot-phone-replacement/id1000855694?mt=8',
     author: 'Peach Labs',
   },
-  {
-    name: 'Exponent',
-    icon: 'http://a4.mzstatic.com/us/r30/Purple2/v4/3a/d3/c9/3ad3c96c-5e14-f988-4bdd-0fdc95efd140/icon175x175.png',
-    link:  'https://itunes.apple.com/ca/app/exponent/id982107779?mt=8',
-    author: 'Exponent',
-  },
-  {
-    name: 'F8',
-    icon: 'http://is4.mzstatic.com/image/pf/us/r30/Purple5/v4/bf/d9/50/bfd9504e-a1bd-67c5-b50b-24e97016dae9/pr_source.jpg',
-    link: 'https://itunes.apple.com/us/app/f8/id853467066?mt=8',
-    author: 'Facebook',
-  },
-  {
-    name: 'Facebook Groups',
-    icon: 'http://is4.mzstatic.com/image/pf/us/r30/Purple69/v4/57/f8/4c/57f84c0c-793d-5f9a-95ee-c212d0369e37/mzl.ugjwfhzx.png',
-    link: 'https://itunes.apple.com/us/app/facebook-groups/id931735837?mt=8',
-    author: 'Facebook',
-  },
-  {
-    name: 'Facebook Ads Manager',
-    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple5/v4/9e/16/86/9e1686ef-cc55-805a-c977-538ddb5e6832/mzl.gqbhwitj.png',
-    linkAppStore: 'https://itunes.apple.com/us/app/facebook-ads-manager/id964397083?mt=8',
-    linkPlayStore: 'https://play.google.com/store/apps/details?id=com.facebook.adsmanager',
-    author: 'Facebook',
-  },
   {
     name: 'Fan of it',
     icon: 'http://a4.mzstatic.com/us/r30/Purple3/v4/c9/3f/e8/c93fe8fb-9332-e744-f04a-0f4f78e42aa8/icon350x350.png',
@@ -159,12 +220,6 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/loaddocs/id1041596066',
     author: 'LoadDocs',
   },
-  {
-    name: 'Lrn',
-    icon: 'http://is4.mzstatic.com/image/pf/us/r30/Purple1/v4/41/a9/e9/41a9e9b6-7801-aef7-2400-2eca14923321/mzl.adyswxad.png',
-    link: 'https://itunes.apple.com/us/app/lrn-learn-to-code-at-your/id1019622677',
-    author: 'Lrn Labs, Inc',
-  },
   {
     name: 'Lumpen Radio',
     icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple1/v4/46/43/00/464300b1-fae3-9640-d4a2-0eb050ea3ff2/mzl.xjjawige.png',
@@ -180,13 +235,8 @@ var apps = [
   {
     name: 'MaxReward - Android',
     icon: 'https://lh3.googleusercontent.com/yynCUCdEnyW6T96xCto8KzWQr4Yeiy0M6c2p8auYMIyFgAZVBsjf4JCEX7QkPijhBg=w175-rw',
-    link: 'https://play.google.com/store/apps/details?id=com.bitstrek.maxreward&hl=en',
-    author: 'Neil Ma',
-  },
-  {
-    name: 'MaxReward - iOS',
-    icon: 'https://lh3.googleusercontent.com/yynCUCdEnyW6T96xCto8KzWQr4Yeiy0M6c2p8auYMIyFgAZVBsjf4JCEX7QkPijhBg=w175-rw',
-    link: 'https://itunes.apple.com/us/app/maxreward/id1050479192?ls=1&mt=8',
+    linkAppStore: 'https://itunes.apple.com/us/app/maxreward/id1050479192?ls=1&mt=8',
+    linkPlayStore: 'https://play.google.com/store/apps/details?id=com.bitstrek.maxreward&hl=en',
     author: 'Neil Ma',
   },
   {
@@ -201,12 +251,6 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/mr.-dapper-men-fashion-app/id989735184?ls=1&mt=8',
     author: 'wei ping woon',
   },
-  {
-    name: 'Myntra',
-    icon: 'http://a5.mzstatic.com/us/r30/Purple6/v4/9c/78/df/9c78dfa6-0061-1af2-5026-3e1d5a073c94/icon350x350.png',
-    link: 'https://itunes.apple.com/in/app/myntra-fashion-shopping-app/id907394059',
-    author: 'Myntra Designs',
-  },
   {
     name: 'Nalathe Kerala',
     icon: 'https://lh3.googleusercontent.com/5N0WYat5WuFbhi5yR2ccdbqmiZ0wbTtKRG9GhT3YK7Z-qRvmykZyAgk0HNElOxD2JOPr=w300-rw',
@@ -267,13 +311,6 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/repairshopr-payments-lite/id1023262888?mt=8',
     author: 'Jed Tiotuico',
   },
-  {
-    name: 'RN Playground',
-    icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple1/v4/20/ec/8e/20ec8eb8-9e12-6686-cd16-7ac9e3ef1d52/mzl.ngvuoybx.png',
-    linkAppStore: 'https://itunes.apple.com/us/app/react-native-playground/id1002032944?mt=8',
-    linkPlayStore: 'https://play.google.com/store/apps/details?id=org.rnplay.playground',
-    author: 'Joshua Sierles',
-  },
   {
     name: 'Rota Employer - Hire On Demand',
     link: 'https://itunes.apple.com/us/app/rota-employer-hire-on-demand/id1042270305?mt=8',
@@ -298,18 +335,6 @@ var apps = [
     link: 'https://geo.itunes.apple.com/us/app/spero-for-cancer/id1033923573?mt=8',
     author: 'Spero.io',
   },
-  {
-    name: 'Squad',
-    icon: 'http://a4.mzstatic.com/us/r30/Purple69/v4/e8/5b/3f/e85b3f52-72f3-f427-a32e-a73efe2e9682/icon175x175.jpeg',
-    link: 'https://itunes.apple.com/us/app/squad-snaps-for-groups-friends/id1043626975?mt=8',
-    author: 'Tackk Inc.',
-  },
-  {
-    name: 'Start - medication manager for depression',
-    icon: 'http://a1.mzstatic.com/us/r30/Purple49/v4/de/9b/6f/de9b6fe8-84ea-7a12-ba2c-0a6d6c7b10b0/icon175x175.png',
-    link: 'https://itunes.apple.com/us/app/start-medication-manager-for/id1012099928?mt=8',
-    author: 'Iodine Inc.',
-  },
   {
     name: 'Tabtor Parent',
     icon: 'http://a1.mzstatic.com/us/r30/Purple4/v4/80/50/9d/80509d05-18f4-a0b8-0cbb-9ba927d04477/icon175x175.jpeg',
@@ -322,12 +347,6 @@ var apps = [
     link: 'https://itunes.apple.com/cn/app/tong-xing-wang/id914254459?mt=8',
     author: 'Ho Yin Tsun Eugene',
   },
-  {
-    name: 'Townske - Stunning City Guides Made By Locals & Traveller',
-    icon: 'http://a3.mzstatic.com/us/r30/Purple69/v4/8b/42/20/8b4220af-5165-91fd-0f05-014332df73ef/icon175x175.png',
-    link: 'https://itunes.apple.com/us/app/townske-stunning-city-guides/id1018136179?ls=1&mt=8',
-    author: 'Townske PTY LTD',
-  },
   {
     name: 'WOOP',
     icon: 'http://a4.mzstatic.com/us/r30/Purple6/v4/b0/44/f9/b044f93b-dbf3-9ae5-0f36-9b4956628cab/icon350x350.jpeg',
@@ -366,39 +385,102 @@ var apps = [
   },
 ];
 
-var showcase = React.createClass({
-  renderLinks: function(app) {
+var AppList = React.createClass({
+
+  render: function() {
+    return (
+      <div>
+        {this.props.apps.map(this._renderApp)}
+      </div>
+    )
+  },
+
+  _renderApp: function(app, i) {
+    var inner = (
+      <div>
+        <img src={app.icon} alt={app.name} />
+        <h3>{app.name}</h3>
+        {app.linkAppStore && app.linkPlayStore ? this._renderLinks(app) : null}
+        <p>By {app.author}</p>
+        {this._renderBlogPosts(app)}
+      </div>
+    );
+
+    if (app.linkAppStore && app.linkPlayStore) {
+      return (<div className="showcase" key={i}>{inner}</div>);
+    }
+
+    return (
+      <div className="showcase" key={i}>
+        <a href={app.link} target="blank">
+          {inner}
+        </a>
+      </div>
+    );
+  },
+
+  _renderBlogPosts: function(app) {
+    if (!app.blogs) {
+      return;
+    }
+
+    if (app.blogs.length === 1) {
+      return (
+        <p><a href={app.blogs[0]} target="blank">Blog post</a></p>
+      );
+    } else if (app.blogs.length > 1) {
+      return (
+        <p>Blog posts: {app.blogs.map(this._renderBlogPost)}</p>
+      );
+    }
+  },
+
+  _renderBlogPost: function(url, i) {
     return (
-      <p><a href={app.linkAppStore} target="blank">iOS</a> - <a href={app.linkPlayStore} target="blank">Android</a></p>
+      <a href={url} target="blank">
+        {i + 1}&nbsp;
+      </a>
     );
   },
+
+  _renderLinks: function(app) {
+    return (
+      <p>
+        <a href={app.linkAppStore} target="blank">iOS</a> -
+        <a href={app.linkPlayStore} target="blank">Android</a>
+      </p>
+    );
+  },
+});
+
+var showcase = React.createClass({
   render: function() {
     return (
       <Site section="showcase" title="Showcase">
-        <section className="content wrap documentationContent nosidebar">
+        <section className="content wrap documentationContent nosidebar showcaseSection">
+          <div className="inner-content showcaseHeader">
+            <h1 style={{textAlign: 'center'}}>Apps using React Native</h1>
+            <div className="subHeader"></div>
+            <p>The following is a list of some of the public apps using <strong>React Native</strong> and are published on the Apple App Store or the Google Play Store. Not all are implemented 100% in React Native -- many are hybrid native/React Native. Can you tell which parts are which? :)</p>
+            <p>Want to add your app? Found an app that no longer works or no longer uses React Native? Please submit a pull request on <a href="https://github.com/facebook/react-native">GitHub</a> to update this page!</p>
+          </div>
+
           <div className="inner-content showcaseHeader">
-            <h1>Apps using React Native</h1>
+            <h1 style={{textAlign: 'center'}}>Featured Apps</h1>
             <div className="subHeader"></div>
-            <p>
-              Here is a list of apps using <strong>React Native</strong>. Submit a pull request on <a href="https://github.com/facebook/react-native">GitHub</a> to list your app.
-            </p>
+            <p>These are some of the most well-crafted React Native apps that we have come across.<br/>Be sure to check them out to get a feel for what React Native is capable of!</p>
+          </div>
+          <div className="inner-content">
+            <AppList apps={featured} />
+          </div>
+
+          <div className="inner-content showcaseHeader">
+            <h1 style={{textAlign: 'center'}}>All Apps</h1>
+            <p>Not all apps can be featured, otherwise we would have to create some other category like &quot;super featured&quot; and that's just silly. But that doesn't mean you shouldn't check these apps out!</p>
+          </div>
+          <div className="inner-content">
+            <AppList apps={apps} />
           </div>
-          {
-            apps.map((app, i) => {
-              var inner = (
-                <div>
-                  <img src={app.icon} alt={app.name} />
-                  <h3>{app.name}</h3>
-                  {app.linkAppStore && app.linkPlayStore ? this.renderLinks(app) : null}
-                  <p>By {app.author}</p>
-                </div>
-              );
-              if (app.linkAppStore && app.linkPlayStore) {
-                return (<div className="showcase" key={i}>{inner}</div>);
-              }
-              return (<a href={app.link} className="showcase" key={i} target="blank">{inner}</a>);
-            })
-          }
         </section>
       </Site>
     );

From c11d861807def358928babcde74a3ec57a73f52b Mon Sep 17 00:00:00 2001
From: Brent Vatne <brentvatne@gmail.com>
Date: Wed, 25 Nov 2015 14:15:47 -0800
Subject: [PATCH 0110/1411] [Docs] Update style of paragraphs within showcase

---
 website/src/react-native/css/react-native.css | 1 +
 1 file changed, 1 insertion(+)

diff --git a/website/src/react-native/css/react-native.css b/website/src/react-native/css/react-native.css
index 034d52e26e2e..8547254340e6 100644
--- a/website/src/react-native/css/react-native.css
+++ b/website/src/react-native/css/react-native.css
@@ -1131,6 +1131,7 @@ div[data-twttr-id] iframe {
 
 .showcase p {
   margin-top: 5px;
+  font-weight: normal;
 }
 
 .showcase a {

From b65f1f223488b52963f80a67bb41956103263d27 Mon Sep 17 00:00:00 2001
From: Kyle Corbitt <kyle@corbt.com>
Date: Wed, 25 Nov 2015 17:03:51 -0800
Subject: [PATCH 0111/1411] Use elevation to implement shadows on Android

Summary: This PR includes a working interface to Android's `elevation` property implemented as an RN style. Elevation is the only (easy) [platform-supported way to create shadows](http://developer.android.com/training/material/shadows-clipping.html). For it to work note that you must be running on Android 5.0+, and add `elevation` to a view with a `backgroundColor` set. These are platform limitations.

This PR is not intended to be merged in its current state, but rather to inform the discussion from #2768. At a minimum, before merging we would need to add the elevation style to the docs and rebase this to master (**EDIT** I have now rebased on master because from v0.14.2 too many commits were being pulled in -- haven't tested it since the rebase though). Additionally, it might be good to add tests, although I couldn't find any for the Android code. I'm happy to get that done if this feature gets signed off by the React Native team.

Finally, as I argued in #2768 I think that `elevation` is a useful abstraction ov
Closes https://github.com/facebook/react-native/pull/4180

Reviewed By: svcscm

Differential Revision: D2684746

Pulled By: mkonicek

fb-gh-sync-id: 825f3ccd20c4b0eea9d11b5f0e3a6b018b7e4378
---
 .../Components/View/ViewStylePropTypes.js     |  8 ++++++++
 .../view/ReactViewBackgroundDrawable.java     | 19 +++++++++++++++++++
 .../react/views/view/ReactViewManager.java    |  8 ++++++++
 3 files changed, 35 insertions(+)

diff --git a/Libraries/Components/View/ViewStylePropTypes.js b/Libraries/Components/View/ViewStylePropTypes.js
index e36b143a1e4b..9f7ba776aab7 100644
--- a/Libraries/Components/View/ViewStylePropTypes.js
+++ b/Libraries/Components/View/ViewStylePropTypes.js
@@ -47,6 +47,14 @@ var ViewStylePropTypes = {
   ),
   shadowOpacity: ReactPropTypes.number,
   shadowRadius: ReactPropTypes.number,
+  /**
+   * (Android-only) Sets the elevation of a view, using Android's underlying 
+   * [elevation API](https://developer.android.com/training/material/shadows-clipping.html#Elevation).
+   * This adds a drop shadow to the item and affects z-order for overlapping views.
+   * Only supported on Android 5.0+, has no effect on earlier versions.
+   * @platform android
+   */
+  elevation: ReactPropTypes.number,
 };
 
 module.exports = ViewStylePropTypes;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java
index 84289b62d605..4a8805614e5c 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java
@@ -17,12 +17,14 @@
 import android.graphics.Color;
 import android.graphics.ColorFilter;
 import android.graphics.DashPathEffect;
+import android.graphics.Outline;
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.PathEffect;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 
 import com.facebook.react.common.annotations.VisibleForTesting;
 import com.facebook.csslayout.CSSConstants;
@@ -123,6 +125,23 @@ public int getOpacity() {
     return ColorUtil.getOpacityFromColor(ColorUtil.multiplyColorAlpha(mColor, mAlpha));
   }
 
+  /* Android's elevation implementation requires this to be implemented to know where to draw the shadow. */
+  @Override
+  public void getOutline(Outline outline) {
+    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+      super.getOutline(outline);
+      return;
+    }
+    if(!CSSConstants.isUndefined(mBorderRadius) && mBorderRadius > 0) {
+      float extraRadiusFromBorderWidth = (mBorderWidth != null)
+              ? mBorderWidth.get(Spacing.ALL) / 2f
+              : 0;
+      outline.setRoundRect(getBounds(), mBorderRadius + extraRadiusFromBorderWidth);
+    } else {
+      super.getOutline(outline);
+    }
+  }
+
   public void setBorderWidth(int position, float width) {
     if (mBorderWidth == null) {
       mBorderWidth = new Spacing();
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
index ac0dfee0f0e9..6e002fb9f978 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
@@ -64,6 +64,14 @@ public void setBorderStyle(ReactViewGroup view, @Nullable String borderStyle) {
     view.setBorderStyle(borderStyle);
   }
 
+  @ReactProp(name = "elevation")
+  public void setElevation(ReactViewGroup view, float elevation) {
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+      view.setElevation(PixelUtil.toPixelFromDIP(elevation));
+    }
+    // Do nothing on API < 21
+  }
+
   @ReactProp(name = "pointerEvents")
   public void setPointerEvents(ReactViewGroup view, @Nullable String pointerEventsStr) {
     if (pointerEventsStr != null) {

From ae09a10c9553016cce9a3131ff442fea8fa1e180 Mon Sep 17 00:00:00 2001
From: Brent Vatne <brentvatne@gmail.com>
Date: Wed, 25 Nov 2015 17:06:59 -0800
Subject: [PATCH 0112/1411] Add onLoadX support on Android

Summary: ~~This is a WIP, just finished the first bit and wanted to get some feedback to see if this approach seems appropriate, as I haven't done a lot of Android development.~~

Looks ready for review now.
Closes https://github.com/facebook/react-native/pull/3791

Reviewed By: svcscm

Differential Revision: D2672262

Pulled By: mkonicek

fb-gh-sync-id: 1e8f1cc6658fb719a68f7da455f30a7c9b1db730
---
 Examples/UIExplorer/ImageExample.js           | 46 +++++++++++
 Libraries/Image/Image.android.js              | 17 +++-
 Libraries/Image/Image.ios.js                  |  3 -
 .../react/views/image/ImageLoadEvent.java     | 73 +++++++++++++++++
 .../react/views/image/ReactImageManager.java  | 20 +++++
 .../react/views/image/ReactImageView.java     | 79 +++++++++++++++++--
 6 files changed, 226 insertions(+), 12 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/image/ImageLoadEvent.java

diff --git a/Examples/UIExplorer/ImageExample.js b/Examples/UIExplorer/ImageExample.js
index 4cab0c1a1cda..68b16b2d103e 100644
--- a/Examples/UIExplorer/ImageExample.js
+++ b/Examples/UIExplorer/ImageExample.js
@@ -28,6 +28,44 @@ var base64Icon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEsAAABLCAQAAACS
 
 var ImageCapInsetsExample = require('./ImageCapInsetsExample');
 
+var NetworkImageCallbackExample = React.createClass({
+  getInitialState: function() {
+    return {
+      events: [],
+    };
+  },
+
+  componentWillMount() {
+    this.setState({mountTime: new Date()});
+  },
+
+  render: function() {
+    var { mountTime } = this.state;
+
+    return (
+      <View>
+        <Image
+          source={this.props.source}
+          style={[styles.base, {overflow: 'visible'}]}
+          onLoadStart={() => this._loadEventFired(`✔ onLoadStart (+${new Date() - mountTime}ms)`)}
+          onLoad={() => this._loadEventFired(`✔ onLoad (+${new Date() - mountTime}ms)`)}
+          onLoadEnd={() => this._loadEventFired(`✔ onLoadEnd (+${new Date() - mountTime}ms)`)}
+        />
+
+        <Text style={{marginTop: 20}}>
+          {this.state.events.join('\n')}
+        </Text>
+      </View>
+    );
+  },
+
+  _loadEventFired(event) {
+    this.setState((state) => {
+      return state.events = [...state.events, event];
+    });
+  }
+});
+
 var NetworkImageExample = React.createClass({
   watchID: (null: ?number),
 
@@ -92,6 +130,14 @@ exports.examples = [
       );
     },
   },
+  {
+    title: 'Image Loading Events',
+    render: function() {
+      return (
+        <NetworkImageCallbackExample source={{uri: 'http://facebook.github.io/origami/public/images/blog-hero.jpg?r=1'}}/>
+      );
+    },
+  },
   {
     title: 'Error Handler',
     render: function() {
diff --git a/Libraries/Image/Image.android.js b/Libraries/Image/Image.android.js
index 66308f682c0b..9d9558c9687f 100644
--- a/Libraries/Image/Image.android.js
+++ b/Libraries/Image/Image.android.js
@@ -56,6 +56,7 @@ var ImageViewAttributes = merge(ReactNativeViewAttributes.UIView, {
   resizeMode: true,
   progressiveRenderingEnabled: true,
   fadeDuration: true,
+  shouldNotifyLoadEvents: true,
 });
 
 var Image = React.createClass({
@@ -75,7 +76,18 @@ var Image = React.createClass({
     ]).isRequired,
     progressiveRenderingEnabled: PropTypes.bool,
     fadeDuration: PropTypes.number,
-    style: StyleSheetPropType(ImageStylePropTypes),
+    /**
+     * Invoked on load start
+     */
+    onLoadStart: PropTypes.func,
+    /**
+     * Invoked when load completes successfully
+     */
+    onLoad: PropTypes.func,
+    /**
+     * Invoked when load either succeeds or fails
+     */
+    onLoadEnd: PropTypes.func,
     /**
      * Used to locate this view in end-to-end tests.
      */
@@ -137,9 +149,11 @@ var Image = React.createClass({
     if (source && source.uri) {
       var {width, height} = source;
       var style = flattenStyle([{width, height}, styles.base, this.props.style]);
+      var {onLoadStart, onLoad, onLoadEnd} = this.props;
 
       var nativeProps = merge(this.props, {
         style,
+        shouldNotifyLoadEvents: !!(onLoadStart || onLoad || onLoadEnd),
         src: source.uri,
       });
 
@@ -186,6 +200,7 @@ var cfg = {
     defaultImageSrc: true,
     imageTag: true,
     progressHandlerRegistered: true,
+    shouldNotifyLoadEvents: true,
   },
 };
 var RKImage = requireNativeComponent('RCTImageView', Image, cfg);
diff --git a/Libraries/Image/Image.ios.js b/Libraries/Image/Image.ios.js
index 4da2d53e5096..6943bf909e33 100644
--- a/Libraries/Image/Image.ios.js
+++ b/Libraries/Image/Image.ios.js
@@ -113,7 +113,6 @@ var Image = React.createClass({
     onLayout: PropTypes.func,
     /**
      * Invoked on load start
-     * @platform ios
      */
     onLoadStart: PropTypes.func,
     /**
@@ -128,12 +127,10 @@ var Image = React.createClass({
     onError: PropTypes.func,
     /**
      * Invoked when load completes successfully
-     * @platform ios
      */
     onLoad: PropTypes.func,
     /**
      * Invoked when load either succeeds or fails
-     * @platform ios
      */
     onLoadEnd: PropTypes.func,
   },
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ImageLoadEvent.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ImageLoadEvent.java
new file mode 100644
index 000000000000..fc183507a63c
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ImageLoadEvent.java
@@ -0,0 +1,73 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.image;
+
+import android.support.annotation.IntDef;
+
+import com.facebook.react.uimanager.events.Event;
+import com.facebook.react.uimanager.events.RCTEventEmitter;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+public class ImageLoadEvent extends Event<ImageLoadEvent> {
+  @IntDef({ON_ERROR, ON_LOAD, ON_LOAD_END, ON_LOAD_START, ON_PROGRESS})
+  @Retention(RetentionPolicy.SOURCE)
+  @interface ImageEventType {}
+
+  // Currently ON_ERROR and ON_PROGRESS are not implemented, these can be added
+  // easily once support exists in fresco.
+  public static final int ON_ERROR = 1;
+  public static final int ON_LOAD = 2;
+  public static final int ON_LOAD_END = 3;
+  public static final int ON_LOAD_START = 4;
+  public static final int ON_PROGRESS = 5;
+
+  private final int mEventType;
+
+  public ImageLoadEvent(int viewId, long timestampMs, @ImageEventType int eventType) {
+    super(viewId, timestampMs);
+    mEventType = eventType;
+  }
+
+  public static String eventNameForType(@ImageEventType int eventType) {
+    switch(eventType) {
+      case ON_ERROR:
+        return "topError";
+      case ON_LOAD:
+        return "topLoad";
+      case ON_LOAD_END:
+        return "topLoadEnd";
+      case ON_LOAD_START:
+        return "topLoadStart";
+      case ON_PROGRESS:
+        return "topProgress";
+      default:
+        throw new IllegalStateException("Invalid image event: " + Integer.toString(eventType));
+    }
+  }
+
+  @Override
+  public String getEventName() {
+    return ImageLoadEvent.eventNameForType(mEventType);
+  }
+
+  @Override
+  public short getCoalescingKey() {
+    // Intentionally casting mEventType because it is guaranteed to be small
+    // enough to fit into short.
+    return (short) mEventType;
+  }
+
+  @Override
+  public void dispatch(RCTEventEmitter rctEventEmitter) {
+    rctEventEmitter.receiveEvent(getViewTag(), getEventName(), null);
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
index 0158ff072c40..19ff94205332 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
@@ -11,10 +11,13 @@
 
 import javax.annotation.Nullable;
 
+import java.util.Map;
+
 import android.graphics.Color;
 
 import com.facebook.drawee.backends.pipeline.Fresco;
 import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
+import com.facebook.react.common.MapBuilder;
 import com.facebook.react.uimanager.ReactProp;
 import com.facebook.react.uimanager.SimpleViewManager;
 import com.facebook.react.uimanager.ThemedReactContext;
@@ -102,6 +105,23 @@ public void setFadeDuration(ReactImageView view, int durationMs) {
     view.setFadeDuration(durationMs);
   }
 
+  @ReactProp(name = "shouldNotifyLoadEvents")
+  public void setLoadHandlersRegistered(ReactImageView view, boolean shouldNotifyLoadEvents) {
+    view.setShouldNotifyLoadEvents(shouldNotifyLoadEvents);
+  }
+
+  @Override
+  public @Nullable Map getExportedCustomDirectEventTypeConstants() {
+    return MapBuilder.of(
+      ImageLoadEvent.eventNameForType(ImageLoadEvent.ON_LOAD_START),
+        MapBuilder.of("registrationName", "onLoadStart"),
+      ImageLoadEvent.eventNameForType(ImageLoadEvent.ON_LOAD),
+        MapBuilder.of("registrationName", "onLoad"),
+      ImageLoadEvent.eventNameForType(ImageLoadEvent.ON_LOAD_END),
+        MapBuilder.of("registrationName", "onLoadEnd")
+    );
+  }
+
   @Override
   protected void onAfterUpdateTransaction(ReactImageView view) {
     super.onAfterUpdateTransaction(view);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
index d741356fe7f1..c889c81837da 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
@@ -20,11 +20,15 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Shader;
+import android.graphics.drawable.Animatable;
 import android.net.Uri;
+import android.os.SystemClock;
 
 import com.facebook.common.util.UriUtil;
 import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
+import com.facebook.drawee.controller.BaseControllerListener;
 import com.facebook.drawee.controller.ControllerListener;
+import com.facebook.drawee.controller.ForwardingControllerListener;
 import com.facebook.drawee.drawable.ScalingUtils;
 import com.facebook.drawee.generic.GenericDraweeHierarchy;
 import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
@@ -32,11 +36,15 @@
 import com.facebook.drawee.interfaces.DraweeController;
 import com.facebook.drawee.view.GenericDraweeView;
 import com.facebook.imagepipeline.common.ResizeOptions;
+import com.facebook.imagepipeline.image.ImageInfo;
 import com.facebook.imagepipeline.request.BasePostprocessor;
 import com.facebook.imagepipeline.request.ImageRequest;
 import com.facebook.imagepipeline.request.ImageRequestBuilder;
 import com.facebook.imagepipeline.request.Postprocessor;
+import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.uimanager.PixelUtil;
+import com.facebook.react.uimanager.UIManagerModule;
+import com.facebook.react.uimanager.events.EventDispatcher;
 
 /**
  * Wrapper class around Fresco's GenericDraweeView, enabling persisting props across multiple view
@@ -104,8 +112,9 @@ public void process(Bitmap output, Bitmap source) {
   private boolean mIsLocalImage;
   private final AbstractDraweeControllerBuilder mDraweeControllerBuilder;
   private final RoundedCornerPostprocessor mRoundedCornerPostprocessor;
-  private final @Nullable Object mCallerContext;
   private @Nullable ControllerListener mControllerListener;
+  private @Nullable ControllerListener mControllerForTesting;
+  private final @Nullable Object mCallerContext;
   private int mFadeDurationMs = -1;
   private boolean mProgressiveRenderingEnabled;
 
@@ -127,6 +136,48 @@ public ReactImageView(
     mCallerContext = callerContext;
   }
 
+  public void setShouldNotifyLoadEvents(boolean shouldNotify) {
+    if (!shouldNotify) {
+      mControllerListener = null;
+    } else {
+      final EventDispatcher mEventDispatcher = ((ReactContext) getContext()).
+          getNativeModule(UIManagerModule.class).getEventDispatcher();
+
+      mControllerListener = new BaseControllerListener<ImageInfo>() {
+        @Override
+        public void onSubmit(String id, Object callerContext) {
+          mEventDispatcher.dispatchEvent(
+              new ImageLoadEvent(getId(), SystemClock.uptimeMillis(), ImageLoadEvent.ON_LOAD_START)
+          );
+        }
+
+        @Override
+        public void onFinalImageSet(
+            String id,
+            @Nullable final ImageInfo imageInfo,
+            @Nullable Animatable animatable) {
+          if (imageInfo != null) {
+            mEventDispatcher.dispatchEvent(
+                new ImageLoadEvent(getId(), SystemClock.uptimeMillis(), ImageLoadEvent.ON_LOAD_END)
+            );
+            mEventDispatcher.dispatchEvent(
+                new ImageLoadEvent(getId(), SystemClock.uptimeMillis(), ImageLoadEvent.ON_LOAD)
+            );
+          }
+        }
+
+        @Override
+        public void onFailure(String id, Throwable throwable) {
+          mEventDispatcher.dispatchEvent(
+              new ImageLoadEvent(getId(), SystemClock.uptimeMillis(), ImageLoadEvent.ON_LOAD_END)
+          );
+        }
+      };
+    }
+
+    mIsDirty = true;
+  }
+
   public void setBorderColor(int borderColor) {
     mBorderColor = borderColor;
     mIsDirty = true;
@@ -217,21 +268,33 @@ public void maybeUpdateView() {
         .setProgressiveRenderingEnabled(mProgressiveRenderingEnabled)
         .build();
 
-    DraweeController draweeController = mDraweeControllerBuilder
-        .reset()
+    // This builder is reused
+    mDraweeControllerBuilder.reset();
+
+    mDraweeControllerBuilder
         .setAutoPlayAnimations(true)
         .setCallerContext(mCallerContext)
         .setOldController(getController())
-        .setImageRequest(imageRequest)
-        .setControllerListener(mControllerListener)
-        .build();
-    setController(draweeController);
+        .setImageRequest(imageRequest);
+
+    if (mControllerListener != null && mControllerForTesting != null) {
+      ForwardingControllerListener combinedListener = new ForwardingControllerListener();
+      combinedListener.addListener(mControllerListener);
+      combinedListener.addListener(mControllerForTesting);
+      mDraweeControllerBuilder.setControllerListener(combinedListener);
+    } else if (mControllerForTesting != null) {
+      mDraweeControllerBuilder.setControllerListener(mControllerForTesting);
+    } else if (mControllerListener != null) {
+      mDraweeControllerBuilder.setControllerListener(mControllerListener);
+    }
+
+    setController(mDraweeControllerBuilder.build());
     mIsDirty = false;
   }
 
   // VisibleForTesting
   public void setControllerListener(ControllerListener controllerListener) {
-    mControllerListener = controllerListener;
+    mControllerForTesting = controllerListener;
     mIsDirty = true;
     maybeUpdateView();
   }

From 0e11379dbb2ffef1ac3dcc2a70d0014c162ba286 Mon Sep 17 00:00:00 2001
From: Sebastian Markbage <sema@fb.com>
Date: Wed, 25 Nov 2015 17:34:55 -0800
Subject: [PATCH 0113/1411] Extract the Require polyfill from the default list
 of polyfills

Summary: Extracts the module system from the list of dependencies and adds it back to the bundling process.

Unbundling and Prepack has their own module systems. jest does as well. This is not normally part of the resolver, nor polyfills.

In fact, I think we'll eventually start treating polyfills as normal modules just like core-js.

The prelude is the weird part right now but I think that we'll eventually move the DEV flag to be module level instead of global and we can just get rid of this prelude.

public

Reviewed By: davidaurelio

Differential Revision: D2693701

fb-gh-sync-id: a59ccda0fa15fcfcda52897e8290805eed1b92b3
---
 .../src/Bundler/__tests__/Bundler-test.js     |  7 +++++
 packager/react-packager/src/Bundler/index.js  | 11 ++++++--
 .../src/Resolver/__tests__/Resolver-test.js   | 26 +----------------
 packager/react-packager/src/Resolver/index.js | 28 +++++++++++++++----
 4 files changed, 39 insertions(+), 33 deletions(-)

diff --git a/packager/react-packager/src/Bundler/__tests__/Bundler-test.js b/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
index ac8494bec9c3..9ce3f7c46da4 100644
--- a/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
+++ b/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
@@ -46,6 +46,7 @@ describe('Bundler', function() {
   }
 
   var getDependencies;
+  var getModuleSystemDependencies;
   var wrapModule;
   var bundler;
   var assetServer;
@@ -53,10 +54,12 @@ describe('Bundler', function() {
 
   beforeEach(function() {
     getDependencies = jest.genMockFn();
+    getModuleSystemDependencies = jest.genMockFn();
     wrapModule = jest.genMockFn();
     Resolver.mockImpl(function() {
       return {
         getDependencies: getDependencies,
+        getModuleSystemDependencies: getModuleSystemDependencies,
         wrapModule: wrapModule,
       };
     });
@@ -112,6 +115,10 @@ describe('Bundler', function() {
       });
     });
 
+    getModuleSystemDependencies.mockImpl(function() {
+      return [];
+    });
+
     JSTransformer.prototype.loadFileAndTransform
       .mockImpl(function(path) {
         return Promise.resolve({
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index 5f5d795905e5..e097667ff58c 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -146,23 +146,30 @@ class Bundler {
     const findEventId = Activity.startEvent('find dependencies');
     let transformEventId;
 
+    const moduleSystem = this._resolver.getModuleSystemDependencies(
+      { dev: isDev, platform }
+    );
+
     return this.getDependencies(entryFile, isDev, platform).then((response) => {
       Activity.endEvent(findEventId);
       transformEventId = Activity.startEvent('transform');
 
+      // Prepend the module system polyfill to the top of dependencies
+      var dependencies = moduleSystem.concat(response.dependencies);
+
       let bar;
       if (process.stdout.isTTY) {
         bar = new ProgressBar('transforming [:bar] :percent :current/:total', {
           complete: '=',
           incomplete: ' ',
           width: 40,
-          total: response.dependencies.length,
+          total: dependencies.length,
         });
       }
 
       bbundle.setMainModuleId(response.mainModuleId);
       return Promise.all(
-        response.dependencies.map(
+        dependencies.map(
           module => this._transformModule(
             bbundle,
             response,
diff --git a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
index f58589215d5b..bf6363c520da 100644
--- a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
+++ b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
@@ -79,27 +79,15 @@ describe('Resolver', function() {
           expect(result.mainModuleId).toEqual('index');
           expect(result.dependencies[result.dependencies.length - 1]).toBe(module);
           expect(_.pluck(Polyfill.mock.calls, 0)).toEqual([
-            { path: 'polyfills/prelude.js',
-              id: 'polyfills/prelude.js',
-              isPolyfill: true,
-              dependencies: []
-            },
-            { path: 'polyfills/require.js',
-              id: 'polyfills/require.js',
-              isPolyfill: true,
-              dependencies: ['polyfills/prelude.js']
-            },
             { path: 'polyfills/polyfills.js',
               id: 'polyfills/polyfills.js',
               isPolyfill: true,
-              dependencies: ['polyfills/prelude.js', 'polyfills/require.js']
+              dependencies: []
             },
             { id: 'polyfills/console.js',
               isPolyfill: true,
               path: 'polyfills/console.js',
               dependencies: [
-                'polyfills/prelude.js',
-                'polyfills/require.js',
                 'polyfills/polyfills.js'
               ],
             },
@@ -107,8 +95,6 @@ describe('Resolver', function() {
               isPolyfill: true,
               path: 'polyfills/error-guard.js',
               dependencies: [
-                'polyfills/prelude.js',
-                'polyfills/require.js',
                 'polyfills/polyfills.js',
                 'polyfills/console.js'
               ],
@@ -117,8 +103,6 @@ describe('Resolver', function() {
               isPolyfill: true,
               path: 'polyfills/String.prototype.es6.js',
               dependencies: [
-                'polyfills/prelude.js',
-                'polyfills/require.js',
                 'polyfills/polyfills.js',
                 'polyfills/console.js',
                 'polyfills/error-guard.js'
@@ -128,8 +112,6 @@ describe('Resolver', function() {
               isPolyfill: true,
               path: 'polyfills/Array.prototype.es6.js',
               dependencies: [
-                'polyfills/prelude.js',
-                'polyfills/require.js',
                 'polyfills/polyfills.js',
                 'polyfills/console.js',
                 'polyfills/error-guard.js',
@@ -140,8 +122,6 @@ describe('Resolver', function() {
               isPolyfill: true,
               path: 'polyfills/Array.es6.js',
               dependencies: [
-                'polyfills/prelude.js',
-                'polyfills/require.js',
                 'polyfills/polyfills.js',
                 'polyfills/console.js',
                 'polyfills/error-guard.js',
@@ -153,8 +133,6 @@ describe('Resolver', function() {
               isPolyfill: true,
               path: 'polyfills/babelHelpers.js',
               dependencies: [
-                'polyfills/prelude.js',
-                'polyfills/require.js',
                 'polyfills/polyfills.js',
                 'polyfills/console.js',
                 'polyfills/error-guard.js',
@@ -218,8 +196,6 @@ describe('Resolver', function() {
               id: 'some module',
               isPolyfill: true,
               dependencies: [
-                'polyfills/prelude.js',
-                'polyfills/require.js',
                 'polyfills/polyfills.js',
                 'polyfills/console.js',
                 'polyfills/error-guard.js',
diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index 60820faa16a3..a4e546e07bbe 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -99,7 +99,7 @@ class Resolver {
 
     return this._depGraph.getDependencies(main, opts.platform).then(
       resolutionResponse => {
-        this._getPolyfillDependencies(opts.dev).reverse().forEach(
+        this._getPolyfillDependencies().reverse().forEach(
           polyfill => resolutionResponse.prependDependency(polyfill)
         );
 
@@ -108,12 +108,28 @@ class Resolver {
     );
   }
 
-  _getPolyfillDependencies(isDev) {
-    const polyfillModuleNames = [
-     isDev
+  getModuleSystemDependencies(options) {
+    const opts = getDependenciesValidateOpts(options);
+
+    const prelude = opts.dev
         ? path.join(__dirname, 'polyfills/prelude_dev.js')
-        : path.join(__dirname, 'polyfills/prelude.js'),
-      path.join(__dirname, 'polyfills/require.js'),
+        : path.join(__dirname, 'polyfills/prelude.js');
+
+    const moduleSystem = path.join(__dirname, 'polyfills/require.js');
+
+    return [
+      prelude,
+      moduleSystem
+    ].map(moduleName => new Polyfill({
+      path: moduleName,
+      id: moduleName,
+      dependencies: [],
+      isPolyfill: true,
+    }));
+  }
+
+  _getPolyfillDependencies() {
+    const polyfillModuleNames = [
       path.join(__dirname, 'polyfills/polyfills.js'),
       path.join(__dirname, 'polyfills/console.js'),
       path.join(__dirname, 'polyfills/error-guard.js'),

From fab8e38759f620f242557e1219c2e6c8c5766f1f Mon Sep 17 00:00:00 2001
From: Ben Alpert <balpert@fb.com>
Date: Wed, 25 Nov 2015 21:26:32 -0800
Subject: [PATCH 0114/1411] Fix ABC order of docs nav

---
 website/server/extractDocs.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/website/server/extractDocs.js b/website/server/extractDocs.js
index 1d8abc600257..8279a6f8d0e7 100644
--- a/website/server/extractDocs.js
+++ b/website/server/extractDocs.js
@@ -192,8 +192,8 @@ var components = [
   '../Libraries/Image/Image.ios.js',
   '../Libraries/CustomComponents/ListView/ListView.js',
   '../Libraries/Components/MapView/MapView.js',
-  '../Libraries/CustomComponents/Navigator/Navigator.js',
   '../Libraries/Modal/Modal.js',
+  '../Libraries/CustomComponents/Navigator/Navigator.js',
   '../Libraries/Components/Navigation/NavigatorIOS.ios.js',
   '../Libraries/Picker/PickerIOS.ios.js',
   '../Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js',

From 16350ae09b4fb5bbeb3edc8cc9df623e4048c6b1 Mon Sep 17 00:00:00 2001
From: Denis Koroskin <dkoroskin@fb.com>
Date: Wed, 25 Nov 2015 21:16:58 -0800
Subject: [PATCH 0115/1411] Remove AnimationRegistry from UIManageModule

Summary: public UIManageModule creates AnimationRegistry but never uses it, this diff moves it to NativeViewHierarchyManager who owns it. UIViewOperationQueue depends on AnimationRegistry to perform some of the enqueued operations, so it accessed it through a getting in NativeViewHierarchyManager. This will also make sure NativeViewHierarchyManager. and UIViewOperationQueue operate on the same AnimationManager (previously, that wasn't really enforced). This is needed so I can move away UIViewOperationQueue creation off the UIManagerModule. This diff should have no functional changes whatsoever.

Reviewed By: astreet

Differential Revision: D2462605

fb-gh-sync-id: 1e3cd64908f51126362f2b5fb39b1efa6521854e
---
 .../react/uimanager/NativeViewHierarchyManager.java    | 10 ++++++----
 .../com/facebook/react/uimanager/UIManagerModule.java  |  9 ++-------
 .../facebook/react/uimanager/UIViewOperationQueue.java |  5 ++---
 3 files changed, 10 insertions(+), 14 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
index 0b7b7e1f08ba..cf3c5645587e 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
@@ -67,10 +67,8 @@
   private final JSResponderHandler mJSResponderHandler = new JSResponderHandler();
   private final RootViewManager mRootViewManager = new RootViewManager();
 
-  public NativeViewHierarchyManager(
-      AnimationRegistry animationRegistry,
-      ViewManagerRegistry viewManagers) {
-    mAnimationRegistry = animationRegistry;
+  public NativeViewHierarchyManager(ViewManagerRegistry viewManagers) {
+    mAnimationRegistry = new AnimationRegistry();
     mViewManagers = viewManagers;
     mTagsToViews = new SparseArray<>();
     mTagsToViewManagers = new SparseArray<>();
@@ -78,6 +76,10 @@ public NativeViewHierarchyManager(
     mRootViewsContext = new SparseArray<>();
   }
 
+  public AnimationRegistry getAnimationRegistry() {
+    return mAnimationRegistry;
+  }
+
   public void updateProperties(int tag, CatalystStylesDiffMap props) {
     UiThreadUtil.assertOnUiThread();
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
index 1512f305f7e7..f8609dc611e5 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
@@ -22,7 +22,6 @@
 import com.facebook.csslayout.CSSLayoutContext;
 import com.facebook.infer.annotation.Assertions;
 import com.facebook.react.animation.Animation;
-import com.facebook.react.animation.AnimationRegistry;
 import com.facebook.react.bridge.Arguments;
 import com.facebook.react.bridge.Callback;
 import com.facebook.react.bridge.LifecycleEventListener;
@@ -78,7 +77,6 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements
 
   private final NativeViewHierarchyManager mNativeViewHierarchyManager;
   private final EventDispatcher mEventDispatcher;
-  private final AnimationRegistry mAnimationRegistry = new AnimationRegistry();
   private final ShadowNodeRegistry mShadowNodeRegistry = new ShadowNodeRegistry();
   private final ViewManagerRegistry mViewManagers;
   private final CSSLayoutContext mLayoutContext = new CSSLayoutContext();
@@ -94,13 +92,10 @@ public UIManagerModule(ReactApplicationContext reactContext, List<ViewManager> v
     super(reactContext);
     mViewManagers = new ViewManagerRegistry(viewManagerList);
     mEventDispatcher = new EventDispatcher(reactContext);
-    mNativeViewHierarchyManager = new NativeViewHierarchyManager(
-        mAnimationRegistry,
-        mViewManagers);
+    mNativeViewHierarchyManager = new NativeViewHierarchyManager(mViewManagers);
     mOperationsQueue = new UIViewOperationQueue(
         reactContext,
-        mNativeViewHierarchyManager,
-        mAnimationRegistry);
+        mNativeViewHierarchyManager);
     mNativeViewHierarchyOptimizer = new NativeViewHierarchyOptimizer(
         mOperationsQueue,
         mShadowNodeRegistry);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
index a931b5e0f976..d118561be2df 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
@@ -456,10 +456,9 @@ public void execute() {
 
   /* package */ UIViewOperationQueue(
       ReactApplicationContext reactContext,
-      NativeViewHierarchyManager nativeViewHierarchyManager,
-      AnimationRegistry animationRegistry) {
+      NativeViewHierarchyManager nativeViewHierarchyManager) {
     mNativeViewHierarchyManager = nativeViewHierarchyManager;
-    mAnimationRegistry = animationRegistry;
+    mAnimationRegistry = nativeViewHierarchyManager.getAnimationRegistry();
     mDispatchUIFrameCallback = new DispatchUIFrameCallback(reactContext);
   }
 

From aeda31428df7b88c684f15edd9687ed6ed8cfc21 Mon Sep 17 00:00:00 2001
From: Denis Koroskin <dkoroskin@fb.com>
Date: Wed, 25 Nov 2015 21:17:13 -0800
Subject: [PATCH 0116/1411] When addRootView() is called in a background
 thread, execute it as a generic UIOperation command in UIViewOperationQueue

Summary: public There is really no reason NativeViewHierarchyManager.addRootView() should be performed synchroniously when called from background thread, as long as it is executed before every other command in UIViewOperationQueue, and we can ensure that by putting add view command at the front of the queue. When that happpens, the queue should always be empty anyway, but it's best to be safe.

This eliminates an unnecessary blocking call and should overall make the code simpler and safer (Semaphores can timeout).

Reviewed By: astreet

Differential Revision: D2462680

fb-gh-sync-id: 784ac6573a455019b93628c70992f3830b9d6f1f
---
 .../react/uimanager/UIManagerModule.java      | 30 ++---------------
 .../react/uimanager/UIViewOperationQueue.java | 32 +++++++++++++++++++
 2 files changed, 35 insertions(+), 27 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
index f8609dc611e5..5633c32b98dc 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
@@ -14,8 +14,6 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
 
 import android.util.DisplayMetrics;
 
@@ -31,8 +29,6 @@
 import com.facebook.react.bridge.ReactMethod;
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.bridge.ReadableMap;
-import com.facebook.react.bridge.SoftAssertions;
-import com.facebook.react.bridge.UiThreadUtil;
 import com.facebook.react.bridge.WritableArray;
 import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
 import com.facebook.react.uimanager.events.EventDispatcher;
@@ -75,7 +71,6 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements
   // increment here is 10
   private static final int ROOT_VIEW_TAG_INCREMENT = 10;
 
-  private final NativeViewHierarchyManager mNativeViewHierarchyManager;
   private final EventDispatcher mEventDispatcher;
   private final ShadowNodeRegistry mShadowNodeRegistry = new ShadowNodeRegistry();
   private final ViewManagerRegistry mViewManagers;
@@ -92,10 +87,9 @@ public UIManagerModule(ReactApplicationContext reactContext, List<ViewManager> v
     super(reactContext);
     mViewManagers = new ViewManagerRegistry(viewManagerList);
     mEventDispatcher = new EventDispatcher(reactContext);
-    mNativeViewHierarchyManager = new NativeViewHierarchyManager(mViewManagers);
     mOperationsQueue = new UIViewOperationQueue(
         reactContext,
-        mNativeViewHierarchyManager);
+        new NativeViewHierarchyManager(mViewManagers));
     mNativeViewHierarchyOptimizer = new NativeViewHierarchyOptimizer(
         mOperationsQueue,
         mShadowNodeRegistry);
@@ -197,26 +191,8 @@ public void run() {
 
     mShadowNodeRegistry.addRootNode(rootCSSNode);
 
-    if (UiThreadUtil.isOnUiThread()) {
-      mNativeViewHierarchyManager.addRootView(tag, rootView, themedRootContext);
-    } else {
-      final Semaphore semaphore = new Semaphore(0);
-      getReactApplicationContext().runOnUiQueueThread(
-          new Runnable() {
-            @Override
-            public void run() {
-              mNativeViewHierarchyManager.addRootView(tag, rootView, themedRootContext);
-              semaphore.release();
-            }
-          });
-      try {
-        SoftAssertions.assertCondition(
-            semaphore.tryAcquire(5000, TimeUnit.MILLISECONDS),
-            "Timed out adding root view");
-      } catch (InterruptedException e) {
-        throw new RuntimeException(e);
-      }
-    }
+    // register it within NativeViewHierarchyManager
+    mOperationsQueue.addRootView(tag, rootView, themedRootContext);
 
     return tag;
   }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
index d118561be2df..21f1128d8ebe 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
@@ -13,13 +13,17 @@
 import javax.annotation.concurrent.GuardedBy;
 
 import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
 
 import com.facebook.react.animation.Animation;
 import com.facebook.react.animation.AnimationRegistry;
 import com.facebook.react.bridge.Callback;
 import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.SoftAssertions;
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.UiThreadUtil;
 import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
 import com.facebook.systrace.Systrace;
 import com.facebook.systrace.SystraceMessage;
@@ -448,6 +452,7 @@ public void execute() {
 
   private final Object mDispatchRunnablesLock = new Object();
   private final DispatchUIFrameCallback mDispatchUIFrameCallback;
+  private final ReactApplicationContext mReactApplicationContext;
 
   @GuardedBy("mDispatchRunnablesLock")
   private final ArrayList<Runnable> mDispatchUIRunnables = new ArrayList<>();
@@ -460,6 +465,7 @@ public void execute() {
     mNativeViewHierarchyManager = nativeViewHierarchyManager;
     mAnimationRegistry = nativeViewHierarchyManager.getAnimationRegistry();
     mDispatchUIFrameCallback = new DispatchUIFrameCallback(reactContext);
+    mReactApplicationContext = reactContext;
   }
 
   public void setViewHierarchyUpdateDebugListener(
@@ -471,6 +477,32 @@ public boolean isEmpty() {
     return mOperations.isEmpty();
   }
 
+  public void addRootView(
+      final int tag,
+      final SizeMonitoringFrameLayout rootView,
+      final ThemedReactContext themedRootContext) {
+    if (UiThreadUtil.isOnUiThread()) {
+      mNativeViewHierarchyManager.addRootView(tag, rootView, themedRootContext);
+    } else {
+      final Semaphore semaphore = new Semaphore(0);
+      mReactApplicationContext.runOnUiQueueThread(
+          new Runnable() {
+            @Override
+            public void run() {
+              mNativeViewHierarchyManager.addRootView(tag, rootView, themedRootContext);
+              semaphore.release();
+            }
+          });
+      try {
+        SoftAssertions.assertCondition(
+            semaphore.tryAcquire(5000, TimeUnit.MILLISECONDS),
+            "Timed out adding root view");
+      } catch (InterruptedException e) {
+        throw new RuntimeException(e);
+      }
+    }
+  }
+
   public void enqueueRemoveRootView(int rootViewTag) {
     mOperations.add(new RemoveRootViewOperation(rootViewTag));
   }

From 76e033ead9d5d1b3c867abf419c0d9cca0bcdaa1 Mon Sep 17 00:00:00 2001
From: Denis Koroskin <dkoroskin@fb.com>
Date: Wed, 25 Nov 2015 21:17:26 -0800
Subject: [PATCH 0117/1411] Extract shadow hierarchy logic from UIManagerModule
 into UIImplementation

Summary: public This diff extracts all shadow hierarchy-specific logic from UIManagerModule into a UIImplementation class. This will later allow using in alternative UIImplementations in future.

Reviewed By: astreet

Differential Revision: D2457849

fb-gh-sync-id: 532128ce1d67b525cdf03794a5a29d7e9ed0ab90
---
 .../react/uimanager/UIImplementation.java     | 644 ++++++++++++++++++
 .../react/uimanager/UIManagerModule.java      | 494 ++------------
 2 files changed, 697 insertions(+), 441 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
new file mode 100644
index 000000000000..b9eb9a64ffe6
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
@@ -0,0 +1,644 @@
+/**
+ * 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.
+ */
+package com.facebook.react.uimanager;
+
+import javax.annotation.Nullable;
+
+import java.util.Arrays;
+
+import com.facebook.csslayout.CSSLayoutContext;
+import com.facebook.infer.annotation.Assertions;
+import com.facebook.react.animation.Animation;
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.Callback;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.WritableArray;
+import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
+import com.facebook.react.uimanager.events.EventDispatcher;
+import com.facebook.systrace.Systrace;
+import com.facebook.systrace.SystraceMessage;
+
+/**
+ * An class that is used to receive React commands from JS and translate them into a
+ * shadow node hierarchy that is then mapped to a native view hierarchy.
+ */
+public class UIImplementation {
+
+  private final ShadowNodeRegistry mShadowNodeRegistry = new ShadowNodeRegistry();
+  private final ViewManagerRegistry mViewManagers;
+  private final CSSLayoutContext mLayoutContext = new CSSLayoutContext();
+  private final UIViewOperationQueue mOperationsQueue;
+  private final NativeViewHierarchyOptimizer mNativeViewHierarchyOptimizer;
+  private final int[] mMeasureBuffer = new int[4];
+
+  public UIImplementation(ReactApplicationContext reactContext, ViewManagerRegistry viewManagers) {
+    mOperationsQueue = new UIViewOperationQueue(
+        reactContext,
+        new NativeViewHierarchyManager(viewManagers));
+    mViewManagers = viewManagers;
+    mNativeViewHierarchyOptimizer = new NativeViewHierarchyOptimizer(
+        mOperationsQueue,
+        mShadowNodeRegistry);
+  }
+
+  /**
+   * Registers a root node with a given tag, size and ThemedReactContext
+   * and adds it to a node registry.
+   */
+  public void registerRootView(
+      SizeMonitoringFrameLayout rootView,
+      int tag,
+      int width,
+      int height,
+      ThemedReactContext context) {
+    final ReactShadowNode rootCSSNode = new ReactShadowNode();
+    rootCSSNode.setReactTag(tag);
+    rootCSSNode.setThemedContext(context);
+    rootCSSNode.setStyleWidth(width);
+    rootCSSNode.setStyleHeight(height);
+    rootCSSNode.setViewClassName("Root");
+    mShadowNodeRegistry.addRootNode(rootCSSNode);
+
+    // register it within NativeViewHierarchyManager
+    mOperationsQueue.addRootView(tag, rootView, context);
+  }
+
+  /**
+   * Unregisters a root node with a given tag.
+   */
+  public void removeRootView(int rootViewTag) {
+    mShadowNodeRegistry.removeRootNode(rootViewTag);
+    mOperationsQueue.enqueueRemoveRootView(rootViewTag);
+  }
+
+  /**
+   * Invoked when native view that corresponds to a root node has its size changed.
+   */
+  public void updateRootNodeSize(
+      int rootViewTag,
+      int newWidth,
+      int newHeight,
+      EventDispatcher eventDispatcher) {
+    ReactShadowNode rootCSSNode = mShadowNodeRegistry.getNode(rootViewTag);
+    rootCSSNode.setStyleWidth(newWidth);
+    rootCSSNode.setStyleHeight(newHeight);
+
+    // If we're in the middle of a batch, the change will automatically be dispatched at the end of
+    // the batch. As all batches are executed as a single runnable on the event queue this should
+    // always be empty, but that calling architecture is an implementation detail.
+    if (mOperationsQueue.isEmpty()) {
+      dispatchViewUpdates(eventDispatcher, -1); // -1 = no associated batch id
+    }
+  }
+
+  /**
+   * Invoked by React to create a new node with a given tag, class name and properties.
+   */
+  public void createView(int tag, String className, int rootViewTag, ReadableMap props) {
+    ViewManager viewManager = mViewManagers.get(className);
+    ReactShadowNode cssNode = viewManager.createShadowNodeInstance();
+    ReactShadowNode rootNode = mShadowNodeRegistry.getNode(rootViewTag);
+    cssNode.setReactTag(tag);
+    cssNode.setViewClassName(className);
+    cssNode.setRootNode(rootNode);
+    cssNode.setThemedContext(rootNode.getThemedContext());
+
+    mShadowNodeRegistry.addNode(cssNode);
+
+    CatalystStylesDiffMap styles = null;
+    if (props != null) {
+      styles = new CatalystStylesDiffMap(props);
+      cssNode.updateProperties(styles);
+    }
+
+    if (!cssNode.isVirtual()) {
+      mNativeViewHierarchyOptimizer.handleCreateView(cssNode, rootViewTag, styles);
+    }
+  }
+
+  public void dropViews(ReadableArray viewTags) {
+    int size = viewTags.size(), realViewsCount = 0;
+    int realViewTags[] = new int[size];
+    for (int i = 0; i < size; i++) {
+      int tag = viewTags.getInt(i);
+      ReactShadowNode cssNode = mShadowNodeRegistry.getNode(tag);
+      if (!cssNode.isVirtual()) {
+        realViewTags[realViewsCount++] = tag;
+      }
+      mShadowNodeRegistry.removeNode(tag);
+    }
+    if (realViewsCount > 0) {
+      mNativeViewHierarchyOptimizer.handleDropViews(realViewTags, realViewsCount);
+    }
+  }
+
+  /**
+   * Invoked by React to create a new node with a given tag has its properties changed.
+   */
+  public void updateView(int tag, String className, ReadableMap props) {
+    ViewManager viewManager = mViewManagers.get(className);
+    if (viewManager == null) {
+      throw new IllegalViewOperationException("Got unknown view type: " + className);
+    }
+    ReactShadowNode cssNode = mShadowNodeRegistry.getNode(tag);
+    if (cssNode == null) {
+      throw new IllegalViewOperationException("Trying to update non-existent view with tag " + tag);
+    }
+
+    if (props != null) {
+      CatalystStylesDiffMap styles = new CatalystStylesDiffMap(props);
+      cssNode.updateProperties(styles);
+      if (!cssNode.isVirtual()) {
+        mNativeViewHierarchyOptimizer.handleUpdateView(cssNode, className, styles);
+      }
+    }
+  }
+
+  /**
+   * Invoked when there is a mutation in a node tree.
+   *
+   * @param tag react tag of the node we want to manage
+   * @param indicesToRemove ordered (asc) list of indicies at which view should be removed
+   * @param viewsToAdd ordered (asc based on mIndex property) list of tag-index pairs that represent
+   * a view which should be added at the specified index
+   * @param tagsToDelete list of tags corresponding to views that should be removed
+   */
+  public void manageChildren(
+      int viewTag,
+      @Nullable ReadableArray moveFrom,
+      @Nullable ReadableArray moveTo,
+      @Nullable ReadableArray addChildTags,
+      @Nullable ReadableArray addAtIndices,
+      @Nullable ReadableArray removeFrom) {
+    ReactShadowNode cssNodeToManage = mShadowNodeRegistry.getNode(viewTag);
+
+    int numToMove = moveFrom == null ? 0 : moveFrom.size();
+    int numToAdd = addChildTags == null ? 0 : addChildTags.size();
+    int numToRemove = removeFrom == null ? 0 : removeFrom.size();
+
+    if (numToMove != 0 && (moveTo == null || numToMove != moveTo.size())) {
+      throw new IllegalViewOperationException("Size of moveFrom != size of moveTo!");
+    }
+
+    if (numToAdd != 0 && (addAtIndices == null || numToAdd != addAtIndices.size())) {
+      throw new IllegalViewOperationException("Size of addChildTags != size of addAtIndices!");
+    }
+
+    // We treat moves as an add and a delete
+    ViewAtIndex[] viewsToAdd = new ViewAtIndex[numToMove + numToAdd];
+    int[] indicesToRemove = new int[numToMove + numToRemove];
+    int[] tagsToRemove = new int[indicesToRemove.length];
+    int[] tagsToDelete = new int[numToRemove];
+
+    if (numToMove > 0) {
+      Assertions.assertNotNull(moveFrom);
+      Assertions.assertNotNull(moveTo);
+      for (int i = 0; i < numToMove; i++) {
+        int moveFromIndex = moveFrom.getInt(i);
+        int tagToMove = cssNodeToManage.getChildAt(moveFromIndex).getReactTag();
+        viewsToAdd[i] = new ViewAtIndex(
+            tagToMove,
+            moveTo.getInt(i));
+        indicesToRemove[i] = moveFromIndex;
+        tagsToRemove[i] = tagToMove;
+      }
+    }
+
+    if (numToAdd > 0) {
+      Assertions.assertNotNull(addChildTags);
+      Assertions.assertNotNull(addAtIndices);
+      for (int i = 0; i < numToAdd; i++) {
+        int viewTagToAdd = addChildTags.getInt(i);
+        int indexToAddAt = addAtIndices.getInt(i);
+        viewsToAdd[numToMove + i] = new ViewAtIndex(viewTagToAdd, indexToAddAt);
+      }
+    }
+
+    if (numToRemove > 0) {
+      Assertions.assertNotNull(removeFrom);
+      for (int i = 0; i < numToRemove; i++) {
+        int indexToRemove = removeFrom.getInt(i);
+        int tagToRemove = cssNodeToManage.getChildAt(indexToRemove).getReactTag();
+        indicesToRemove[numToMove + i] = indexToRemove;
+        tagsToRemove[numToMove + i] = tagToRemove;
+        tagsToDelete[i] = tagToRemove;
+      }
+    }
+
+    // NB: moveFrom and removeFrom are both relative to the starting state of the View's children.
+    // moveTo and addAt are both relative to the final state of the View's children.
+    //
+    // 1) Sort the views to add and indices to remove by index
+    // 2) Iterate the indices being removed from high to low and remove them. Going high to low
+    //    makes sure we remove the correct index when there are multiple to remove.
+    // 3) Iterate the views being added by index low to high and add them. Like the view removal,
+    //    iteration direction is important to preserve the correct index.
+
+    Arrays.sort(viewsToAdd, ViewAtIndex.COMPARATOR);
+    Arrays.sort(indicesToRemove);
+
+    // Apply changes to CSSNode hierarchy
+    int lastIndexRemoved = -1;
+    for (int i = indicesToRemove.length - 1; i >= 0; i--) {
+      int indexToRemove = indicesToRemove[i];
+      if (indexToRemove == lastIndexRemoved) {
+        throw new IllegalViewOperationException("Repeated indices in Removal list for view tag: "
+            + viewTag);
+      }
+      cssNodeToManage.removeChildAt(indicesToRemove[i]);
+      lastIndexRemoved = indicesToRemove[i];
+    }
+
+    for (int i = 0; i < viewsToAdd.length; i++) {
+      ViewAtIndex viewAtIndex = viewsToAdd[i];
+      ReactShadowNode cssNodeToAdd = mShadowNodeRegistry.getNode(viewAtIndex.mTag);
+      if (cssNodeToAdd == null) {
+        throw new IllegalViewOperationException("Trying to add unknown view tag: "
+            + viewAtIndex.mTag);
+      }
+      cssNodeToManage.addChildAt(cssNodeToAdd, viewAtIndex.mIndex);
+    }
+
+    if (!cssNodeToManage.isVirtual() && !cssNodeToManage.isVirtualAnchor()) {
+      mNativeViewHierarchyOptimizer.handleManageChildren(
+          cssNodeToManage,
+          indicesToRemove,
+          tagsToRemove,
+          viewsToAdd,
+          tagsToDelete);
+    }
+
+    for (int i = 0; i < tagsToDelete.length; i++) {
+      removeShadowNode(mShadowNodeRegistry.getNode(tagsToDelete[i]));
+    }
+  }
+
+  /**
+   * Replaces the View specified by oldTag with the View specified by newTag within oldTag's parent.
+   */
+  public void replaceExistingNonRootView(int oldTag, int newTag) {
+    if (mShadowNodeRegistry.isRootNode(oldTag) || mShadowNodeRegistry.isRootNode(newTag)) {
+      throw new IllegalViewOperationException("Trying to add or replace a root tag!");
+    }
+
+    ReactShadowNode oldNode = mShadowNodeRegistry.getNode(oldTag);
+    if (oldNode == null) {
+      throw new IllegalViewOperationException("Trying to replace unknown view tag: " + oldTag);
+    }
+
+    ReactShadowNode parent = oldNode.getParent();
+    if (parent == null) {
+      throw new IllegalViewOperationException("Node is not attached to a parent: " + oldTag);
+    }
+
+    int oldIndex = parent.indexOf(oldNode);
+    if (oldIndex < 0) {
+      throw new IllegalStateException("Didn't find child tag in parent");
+    }
+
+    WritableArray tagsToAdd = Arguments.createArray();
+    tagsToAdd.pushInt(newTag);
+
+    WritableArray addAtIndices = Arguments.createArray();
+    addAtIndices.pushInt(oldIndex);
+
+    WritableArray indicesToRemove = Arguments.createArray();
+    indicesToRemove.pushInt(oldIndex);
+
+    manageChildren(parent.getReactTag(), null, null, tagsToAdd, addAtIndices, indicesToRemove);
+  }
+
+  /**
+   * Method which takes a container tag and then releases all subviews for that container upon
+   * receipt.
+   * TODO: The method name is incorrect and will be renamed, #6033872
+   * @param containerTag the tag of the container for which the subviews must be removed
+   */
+  public void removeSubviewsFromContainerWithID(int containerTag) {
+    ReactShadowNode containerNode = mShadowNodeRegistry.getNode(containerTag);
+    if (containerNode == null) {
+      throw new IllegalViewOperationException(
+          "Trying to remove subviews of an unknown view tag: " + containerTag);
+    }
+
+    WritableArray indicesToRemove = Arguments.createArray();
+    for (int childIndex = 0; childIndex < containerNode.getChildCount(); childIndex++) {
+      indicesToRemove.pushInt(childIndex);
+    }
+
+    manageChildren(containerTag, null, null, null, null, indicesToRemove);
+  }
+
+  /**
+   * Find the touch target child native view in  the supplied root view hierarchy, given a react
+   * target location.
+   *
+   * This method is currently used only by Element Inspector DevTool.
+   *
+   * @param reactTag the tag of the root view to traverse
+   * @param targetX target X location
+   * @param targetY target Y location
+   * @param callback will be called if with the identified child view react ID, and measurement
+   *        info. If no view was found, callback will be invoked with no data.
+   */
+  public void findSubviewIn(int reactTag, float targetX, float targetY, Callback callback) {
+    mOperationsQueue.enqueueFindTargetForTouch(reactTag, targetX, targetY, callback);
+  }
+
+  /**
+   * Determines the location on screen, width, and height of the given view and returns the values
+   * via an async callback.
+   */
+  public void measure(int reactTag, Callback callback) {
+    // This method is called by the implementation of JS touchable interface (see Touchable.js for
+    // more details) at the moment of touch activation. That is after user starts the gesture from
+    // a touchable view with a given reactTag, or when user drag finger back into the press
+    // activation area of a touchable view that have been activated before.
+    mOperationsQueue.enqueueMeasure(reactTag, callback);
+  }
+
+  /**
+   * Measures the view specified by tag relative to the given ancestorTag. This means that the
+   * returned x, y are relative to the origin x, y of the ancestor view. Results are stored in the
+   * given outputBuffer. We allow ancestor view and measured view to be the same, in which case
+   * the position always will be (0, 0) and method will only measure the view dimensions.
+   */
+  public void measureLayout(
+      int tag,
+      int ancestorTag,
+      Callback errorCallback,
+      Callback successCallback) {
+    try {
+      measureLayout(tag, ancestorTag, mMeasureBuffer);
+      float relativeX = PixelUtil.toDIPFromPixel(mMeasureBuffer[0]);
+      float relativeY = PixelUtil.toDIPFromPixel(mMeasureBuffer[1]);
+      float width = PixelUtil.toDIPFromPixel(mMeasureBuffer[2]);
+      float height = PixelUtil.toDIPFromPixel(mMeasureBuffer[3]);
+      successCallback.invoke(relativeX, relativeY, width, height);
+    } catch (IllegalViewOperationException e) {
+      errorCallback.invoke(e.getMessage());
+    }
+  }
+
+  /**
+   * Like {@link #measure} and {@link #measureLayout} but measures relative to the immediate parent.
+   */
+  public void measureLayoutRelativeToParent(
+      int tag,
+      Callback errorCallback,
+      Callback successCallback) {
+    try {
+      measureLayoutRelativeToParent(tag, mMeasureBuffer);
+      float relativeX = PixelUtil.toDIPFromPixel(mMeasureBuffer[0]);
+      float relativeY = PixelUtil.toDIPFromPixel(mMeasureBuffer[1]);
+      float width = PixelUtil.toDIPFromPixel(mMeasureBuffer[2]);
+      float height = PixelUtil.toDIPFromPixel(mMeasureBuffer[3]);
+      successCallback.invoke(relativeX, relativeY, width, height);
+    } catch (IllegalViewOperationException e) {
+      errorCallback.invoke(e.getMessage());
+    }
+  }
+
+  /**
+   * Invoked at the end of the transaction to commit any updates to the node hierarchy.
+   */
+  public void dispatchViewUpdates(EventDispatcher eventDispatcher, int batchId) {
+    for (int i = 0; i < mShadowNodeRegistry.getRootNodeCount(); i++) {
+      int tag = mShadowNodeRegistry.getRootTag(i);
+      ReactShadowNode cssRoot = mShadowNodeRegistry.getNode(tag);
+      notifyOnBeforeLayoutRecursive(cssRoot);
+
+      SystraceMessage.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "cssRoot.calculateLayout")
+          .arg("rootTag", tag)
+          .flush();
+      try {
+        cssRoot.calculateLayout(mLayoutContext);
+      } finally {
+        Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+      }
+      applyUpdatesRecursive(cssRoot, 0f, 0f, eventDispatcher);
+    }
+
+    mNativeViewHierarchyOptimizer.onBatchComplete();
+    mOperationsQueue.dispatchViewUpdates(batchId);
+  }
+
+  /**
+   * Registers a new Animation that can then be added to a View using {@link #addAnimation}.
+   */
+  public void registerAnimation(Animation animation) {
+    mOperationsQueue.enqueueRegisterAnimation(animation);
+  }
+
+  /**
+   * Adds an Animation previously registered with {@link #registerAnimation} to a View and starts it
+   */
+  public void addAnimation(int reactTag, int animationID, Callback onSuccess) {
+    assertViewExists(reactTag, "addAnimation");
+    mOperationsQueue.enqueueAddAnimation(reactTag, animationID, onSuccess);
+  }
+
+  /**
+   * Removes an existing Animation, canceling it if it was in progress.
+   */
+  public void removeAnimation(int reactTag, int animationID) {
+    assertViewExists(reactTag, "removeAnimation");
+    mOperationsQueue.enqueueRemoveAnimation(animationID);
+  }
+
+  public void setJSResponder(int reactTag, boolean blockNativeResponder) {
+    assertViewExists(reactTag, "setJSResponder");
+    ReactShadowNode node = mShadowNodeRegistry.getNode(reactTag);
+    while (node.isVirtual() || node.isLayoutOnly()) {
+      node = node.getParent();
+    }
+    mOperationsQueue.enqueueSetJSResponder(node.getReactTag(), reactTag, blockNativeResponder);
+  }
+
+  public void clearJSResponder() {
+    mOperationsQueue.enqueueClearJSResponder();
+  }
+
+  public void dispatchViewManagerCommand(int reactTag, int commandId, ReadableArray commandArgs) {
+    assertViewExists(reactTag, "dispatchViewManagerCommand");
+    mOperationsQueue.enqueueDispatchCommand(reactTag, commandId, commandArgs);
+  }
+
+  /**
+   * Show a PopupMenu.
+   *
+   * @param reactTag the tag of the anchor view (the PopupMenu is displayed next to this view); this
+   *        needs to be the tag of a native view (shadow views can not be anchors)
+   * @param items the menu items as an array of strings
+   * @param error will be called if there is an error displaying the menu
+   * @param success will be called with the position of the selected item as the first argument, or
+   *        no arguments if the menu is dismissed
+   */
+  public void showPopupMenu(int reactTag, ReadableArray items, Callback error, Callback success) {
+    assertViewExists(reactTag, "showPopupMenu");
+    mOperationsQueue.enqueueShowPopupMenu(reactTag, items, error, success);
+  }
+
+  public void sendAccessibilityEvent(int tag, int eventType) {
+    mOperationsQueue.enqueueSendAccessibilityEvent(tag, eventType);
+  }
+
+  public void onHostResume() {
+    mOperationsQueue.resumeFrameCallback();
+  }
+
+  public void onHostPause() {
+    mOperationsQueue.pauseFrameCallback();
+  }
+
+  public void onHostDestroy() {
+  }
+
+  public void setViewHierarchyUpdateDebugListener(
+      @Nullable NotThreadSafeViewHierarchyUpdateDebugListener listener) {
+    mOperationsQueue.setViewHierarchyUpdateDebugListener(listener);
+  }
+
+  private void removeShadowNode(ReactShadowNode nodeToRemove) {
+    mNativeViewHierarchyOptimizer.handleRemoveNode(nodeToRemove);
+    for (int i = nodeToRemove.getChildCount() - 1; i >= 0; i--) {
+      removeShadowNode(nodeToRemove.getChildAt(i));
+    }
+    nodeToRemove.removeAllChildren();
+  }
+
+  private void measureLayout(int tag, int ancestorTag, int[] outputBuffer) {
+    ReactShadowNode node = mShadowNodeRegistry.getNode(tag);
+    ReactShadowNode ancestor = mShadowNodeRegistry.getNode(ancestorTag);
+    if (node == null || ancestor == null) {
+      throw new IllegalViewOperationException(
+          "Tag " + (node == null ? tag : ancestorTag) + " does not exist");
+    }
+
+    if (node != ancestor) {
+      ReactShadowNode currentParent = node.getParent();
+      while (currentParent != ancestor) {
+        if (currentParent == null) {
+          throw new IllegalViewOperationException(
+              "Tag " + ancestorTag + " is not an ancestor of tag " + tag);
+        }
+        currentParent = currentParent.getParent();
+      }
+    }
+
+    measureLayoutRelativeToVerifiedAncestor(node, ancestor, outputBuffer);
+  }
+
+  private void measureLayoutRelativeToParent(int tag, int[] outputBuffer) {
+    ReactShadowNode node = mShadowNodeRegistry.getNode(tag);
+    if (node == null) {
+      throw new IllegalViewOperationException("No native view for tag " + tag + " exists!");
+    }
+    ReactShadowNode parent = node.getParent();
+    if (parent == null) {
+      throw new IllegalViewOperationException("View with tag " + tag + " doesn't have a parent!");
+    }
+
+    measureLayoutRelativeToVerifiedAncestor(node, parent, outputBuffer);
+  }
+
+  private void measureLayoutRelativeToVerifiedAncestor(
+      ReactShadowNode node,
+      ReactShadowNode ancestor,
+      int[] outputBuffer) {
+    int offsetX = 0;
+    int offsetY = 0;
+    if (node != ancestor) {
+      offsetX = Math.round(node.getLayoutX());
+      offsetY = Math.round(node.getLayoutY());
+      ReactShadowNode current = node.getParent();
+      while (current != ancestor) {
+        Assertions.assertNotNull(current);
+        assertNodeDoesNotNeedCustomLayoutForChildren(current);
+        offsetX += Math.round(current.getLayoutX());
+        offsetY += Math.round(current.getLayoutY());
+        current = current.getParent();
+      }
+      assertNodeDoesNotNeedCustomLayoutForChildren(ancestor);
+    }
+
+    outputBuffer[0] = offsetX;
+    outputBuffer[1] = offsetY;
+    outputBuffer[2] = node.getScreenWidth();
+    outputBuffer[3] = node.getScreenHeight();
+  }
+
+  private void assertViewExists(int reactTag, String operationNameForExceptionMessage) {
+    if (mShadowNodeRegistry.getNode(reactTag) == null) {
+      throw new IllegalViewOperationException(
+          "Unable to execute operation " + operationNameForExceptionMessage + " on view with " +
+              "tag: " + reactTag + ", since the view does not exists");
+    }
+  }
+
+  private void assertNodeDoesNotNeedCustomLayoutForChildren(ReactShadowNode node) {
+    ViewManager viewManager = Assertions.assertNotNull(mViewManagers.get(node.getViewClass()));
+    ViewGroupManager viewGroupManager;
+    if (viewManager instanceof ViewGroupManager) {
+      viewGroupManager = (ViewGroupManager) viewManager;
+    } else {
+      throw new IllegalViewOperationException("Trying to use view " + node.getViewClass() +
+          " as a parent, but its Manager doesn't extends ViewGroupManager");
+    }
+    if (viewGroupManager != null && viewGroupManager.needsCustomLayoutForChildren()) {
+      throw new IllegalViewOperationException(
+          "Trying to measure a view using measureLayout/measureLayoutRelativeToParent relative to" +
+              " an ancestor that requires custom layout for it's children (" + node.getViewClass() +
+              "). Use measure instead.");
+    }
+  }
+
+  private void notifyOnBeforeLayoutRecursive(ReactShadowNode cssNode) {
+    if (!cssNode.hasUpdates()) {
+      return;
+    }
+    for (int i = 0; i < cssNode.getChildCount(); i++) {
+      notifyOnBeforeLayoutRecursive(cssNode.getChildAt(i));
+    }
+    cssNode.onBeforeLayout();
+  }
+
+  private void applyUpdatesRecursive(
+      ReactShadowNode cssNode,
+      float absoluteX,
+      float absoluteY,
+      EventDispatcher eventDispatcher) {
+    if (!cssNode.hasUpdates()) {
+      return;
+    }
+
+    if (!cssNode.isVirtualAnchor()) {
+      for (int i = 0; i < cssNode.getChildCount(); i++) {
+        applyUpdatesRecursive(
+            cssNode.getChildAt(i),
+            absoluteX + cssNode.getLayoutX(),
+            absoluteY + cssNode.getLayoutY(),
+            eventDispatcher);
+      }
+    }
+
+    int tag = cssNode.getReactTag();
+    if (!mShadowNodeRegistry.isRootNode(tag)) {
+      cssNode.dispatchUpdates(
+          absoluteX,
+          absoluteY,
+          mOperationsQueue,
+          mNativeViewHierarchyOptimizer,
+          eventDispatcher);
+    }
+    cssNode.markUpdateSeen();
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
index 5633c32b98dc..ff473aaf683f 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
@@ -72,31 +72,23 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements
   private static final int ROOT_VIEW_TAG_INCREMENT = 10;
 
   private final EventDispatcher mEventDispatcher;
-  private final ShadowNodeRegistry mShadowNodeRegistry = new ShadowNodeRegistry();
-  private final ViewManagerRegistry mViewManagers;
-  private final CSSLayoutContext mLayoutContext = new CSSLayoutContext();
   private final Map<String, Object> mModuleConstants;
-  private final UIViewOperationQueue mOperationsQueue;
-  private final NativeViewHierarchyOptimizer mNativeViewHierarchyOptimizer;
-  private final int[] mMeasureBuffer = new int[4];
+  private final UIImplementation mUIImplementation;
 
   private int mNextRootViewTag = 1;
   private int mBatchId = 0;
 
   public UIManagerModule(ReactApplicationContext reactContext, List<ViewManager> viewManagerList) {
     super(reactContext);
-    mViewManagers = new ViewManagerRegistry(viewManagerList);
     mEventDispatcher = new EventDispatcher(reactContext);
-    mOperationsQueue = new UIViewOperationQueue(
-        reactContext,
-        new NativeViewHierarchyManager(mViewManagers));
-    mNativeViewHierarchyOptimizer = new NativeViewHierarchyOptimizer(
-        mOperationsQueue,
-        mShadowNodeRegistry);
     DisplayMetrics displayMetrics = reactContext.getResources().getDisplayMetrics();
     DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
     mModuleConstants = createConstants(displayMetrics, viewManagerList);
     reactContext.addLifecycleEventListener(this);
+
+    mUIImplementation = new UIImplementation(
+        reactContext,
+        new ViewManagerRegistry(viewManagerList));
   }
 
   @Override
@@ -111,16 +103,17 @@ public Map<String, Object> getConstants() {
 
   @Override
   public void onHostResume() {
-    mOperationsQueue.resumeFrameCallback();
+    mUIImplementation.onHostResume();
   }
 
   @Override
   public void onHostPause() {
-    mOperationsQueue.pauseFrameCallback();
+    mUIImplementation.onHostPause();
   }
 
   @Override
   public void onHostDestroy() {
+    mUIImplementation.onHostDestroy();
   }
 
   @Override
@@ -158,22 +151,23 @@ public int addMeasuredRootView(final SizeMonitoringFrameLayout rootView) {
     final int tag = mNextRootViewTag;
     mNextRootViewTag += ROOT_VIEW_TAG_INCREMENT;
 
-    final ReactShadowNode rootCSSNode = new ReactShadowNode();
-    rootCSSNode.setReactTag(tag);
-    final ThemedReactContext themedRootContext =
-        new ThemedReactContext(getReactApplicationContext(), rootView.getContext());
-    rootCSSNode.setThemedContext(themedRootContext);
+    final int width;
+    final int height;
     // If LayoutParams sets size explicitly, we can use that. Otherwise get the size from the view.
     if (rootView.getLayoutParams() != null &&
         rootView.getLayoutParams().width > 0 &&
         rootView.getLayoutParams().height > 0) {
-      rootCSSNode.setStyleWidth(rootView.getLayoutParams().width);
-      rootCSSNode.setStyleHeight(rootView.getLayoutParams().height);
+      width = rootView.getLayoutParams().width;
+      height = rootView.getLayoutParams().height;
     } else {
-      rootCSSNode.setStyleWidth(rootView.getWidth());
-      rootCSSNode.setStyleHeight(rootView.getHeight());
+      width = rootView.getWidth();
+      height = rootView.getHeight();
     }
-    rootCSSNode.setViewClassName("Root");
+
+    final ThemedReactContext themedRootContext =
+        new ThemedReactContext(getReactApplicationContext(), rootView.getContext());
+
+    mUIImplementation.registerRootView(rootView, tag, width, height, themedRootContext);
 
     rootView.setOnSizeChangedListener(
         new SizeMonitoringFrameLayout.OnSizeChangedListener() {
@@ -183,98 +177,39 @@ public void onSizeChanged(final int width, final int height, int oldW, int oldH)
                 new Runnable() {
                   @Override
                   public void run() {
-                    updateRootNodeSize(rootCSSNode, width, height);
+                    updateRootNodeSize(tag, width, height);
                   }
                 });
           }
         });
 
-    mShadowNodeRegistry.addRootNode(rootCSSNode);
-
-    // register it within NativeViewHierarchyManager
-    mOperationsQueue.addRootView(tag, rootView, themedRootContext);
-
     return tag;
   }
 
   @ReactMethod
   public void removeRootView(int rootViewTag) {
-    mShadowNodeRegistry.removeRootNode(rootViewTag);
-    mOperationsQueue.enqueueRemoveRootView(rootViewTag);
+    mUIImplementation.removeRootView(rootViewTag);
   }
 
-  private void updateRootNodeSize(ReactShadowNode rootCSSNode, int newWidth, int newHeight) {
+  private void updateRootNodeSize(int rootViewTag, int newWidth, int newHeight) {
     getReactApplicationContext().assertOnNativeModulesQueueThread();
 
-    rootCSSNode.setStyleWidth(newWidth);
-    rootCSSNode.setStyleHeight(newHeight);
-
-    // If we're in the middle of a batch, the change will automatically be dispatched at the end of
-    // the batch. As all batches are executed as a single runnable on the event queue this should
-    // always be empty, but that calling architecture is an implementation detail.
-    if (mOperationsQueue.isEmpty()) {
-      dispatchViewUpdates(-1); // -1 = no associated batch id
-    }
+    mUIImplementation.updateRootNodeSize(rootViewTag, newWidth, newHeight, mEventDispatcher);
   }
 
   @ReactMethod
   public void createView(int tag, String className, int rootViewTag, ReadableMap props) {
-    ViewManager viewManager = mViewManagers.get(className);
-    ReactShadowNode cssNode = viewManager.createShadowNodeInstance();
-    ReactShadowNode rootNode = mShadowNodeRegistry.getNode(rootViewTag);
-    cssNode.setReactTag(tag);
-    cssNode.setViewClassName(className);
-    cssNode.setRootNode(rootNode);
-    cssNode.setThemedContext(rootNode.getThemedContext());
-
-    mShadowNodeRegistry.addNode(cssNode);
-
-    CatalystStylesDiffMap styles = null;
-    if (props != null) {
-      styles = new CatalystStylesDiffMap(props);
-      cssNode.updateProperties(styles);
-    }
-
-    if (!cssNode.isVirtual()) {
-      mNativeViewHierarchyOptimizer.handleCreateView(cssNode, rootViewTag, styles);
-    }
+    mUIImplementation.createView(tag, className, rootViewTag, props);
   }
 
   @ReactMethod
   public void dropViews(ReadableArray viewTags) {
-    int size = viewTags.size(), realViewsCount = 0;
-    int realViewTags[] = new int[size];
-    for (int i = 0; i < size; i++) {
-      int tag = viewTags.getInt(i);
-      ReactShadowNode cssNode = mShadowNodeRegistry.getNode(tag);
-      if (!cssNode.isVirtual()) {
-        realViewTags[realViewsCount++] = tag;
-      }
-      mShadowNodeRegistry.removeNode(tag);
-    }
-    if (realViewsCount > 0) {
-      mNativeViewHierarchyOptimizer.handleDropViews(realViewTags, realViewsCount);
-    }
+    mUIImplementation.dropViews(viewTags);
   }
 
   @ReactMethod
   public void updateView(int tag, String className, ReadableMap props) {
-    ViewManager viewManager = mViewManagers.get(className);
-    if (viewManager == null) {
-      throw new IllegalViewOperationException("Got unknown view type: " + className);
-    }
-    ReactShadowNode cssNode = mShadowNodeRegistry.getNode(tag);
-    if (cssNode == null) {
-      throw new IllegalViewOperationException("Trying to update non-existent view with tag " + tag);
-    }
-
-    if (props != null) {
-      CatalystStylesDiffMap styles = new CatalystStylesDiffMap(props);
-      cssNode.updateProperties(styles);
-      if (!cssNode.isVirtual()) {
-        mNativeViewHierarchyOptimizer.handleUpdateView(cssNode, className, styles);
-      }
-    }
+    mUIImplementation.updateView(tag, className, props);
   }
 
   /**
@@ -296,115 +231,13 @@ public void manageChildren(
       @Nullable ReadableArray addChildTags,
       @Nullable ReadableArray addAtIndices,
       @Nullable ReadableArray removeFrom) {
-    ReactShadowNode cssNodeToManage = mShadowNodeRegistry.getNode(viewTag);
-
-    int numToMove = moveFrom == null ? 0 : moveFrom.size();
-    int numToAdd = addChildTags == null ? 0 : addChildTags.size();
-    int numToRemove = removeFrom == null ? 0 : removeFrom.size();
-
-    if (numToMove != 0 && (moveTo == null || numToMove != moveTo.size())) {
-      throw new IllegalViewOperationException("Size of moveFrom != size of moveTo!");
-    }
-
-    if (numToAdd != 0 && (addAtIndices == null || numToAdd != addAtIndices.size())) {
-      throw new IllegalViewOperationException("Size of addChildTags != size of addAtIndices!");
-    }
-
-    // We treat moves as an add and a delete
-    ViewAtIndex[] viewsToAdd = new ViewAtIndex[numToMove + numToAdd];
-    int[] indicesToRemove = new int[numToMove + numToRemove];
-    int[] tagsToRemove = new int[indicesToRemove.length];
-    int[] tagsToDelete = new int[numToRemove];
-
-    if (numToMove > 0) {
-      Assertions.assertNotNull(moveFrom);
-      Assertions.assertNotNull(moveTo);
-      for (int i = 0; i < numToMove; i++) {
-        int moveFromIndex = moveFrom.getInt(i);
-        int tagToMove = cssNodeToManage.getChildAt(moveFromIndex).getReactTag();
-        viewsToAdd[i] = new ViewAtIndex(
-            tagToMove,
-            moveTo.getInt(i));
-        indicesToRemove[i] = moveFromIndex;
-        tagsToRemove[i] = tagToMove;
-      }
-    }
-
-    if (numToAdd > 0) {
-      Assertions.assertNotNull(addChildTags);
-      Assertions.assertNotNull(addAtIndices);
-      for (int i = 0; i < numToAdd; i++) {
-        int viewTagToAdd = addChildTags.getInt(i);
-        int indexToAddAt = addAtIndices.getInt(i);
-        viewsToAdd[numToMove + i] = new ViewAtIndex(viewTagToAdd, indexToAddAt);
-      }
-    }
-
-    if (numToRemove > 0) {
-      Assertions.assertNotNull(removeFrom);
-      for (int i = 0; i < numToRemove; i++) {
-        int indexToRemove = removeFrom.getInt(i);
-        int tagToRemove = cssNodeToManage.getChildAt(indexToRemove).getReactTag();
-        indicesToRemove[numToMove + i] = indexToRemove;
-        tagsToRemove[numToMove + i] = tagToRemove;
-        tagsToDelete[i] = tagToRemove;
-      }
-    }
-
-    // NB: moveFrom and removeFrom are both relative to the starting state of the View's children.
-    // moveTo and addAt are both relative to the final state of the View's children.
-    //
-    // 1) Sort the views to add and indices to remove by index
-    // 2) Iterate the indices being removed from high to low and remove them. Going high to low
-    //    makes sure we remove the correct index when there are multiple to remove.
-    // 3) Iterate the views being added by index low to high and add them. Like the view removal,
-    //    iteration direction is important to preserve the correct index.
-
-    Arrays.sort(viewsToAdd, ViewAtIndex.COMPARATOR);
-    Arrays.sort(indicesToRemove);
-
-    // Apply changes to CSSNode hierarchy
-    int lastIndexRemoved = -1;
-    for (int i = indicesToRemove.length - 1; i >= 0; i--) {
-      int indexToRemove = indicesToRemove[i];
-      if (indexToRemove == lastIndexRemoved) {
-        throw new IllegalViewOperationException("Repeated indices in Removal list for view tag: "
-            + viewTag);
-      }
-      cssNodeToManage.removeChildAt(indicesToRemove[i]);
-      lastIndexRemoved = indicesToRemove[i];
-    }
-
-    for (int i = 0; i < viewsToAdd.length; i++) {
-      ViewAtIndex viewAtIndex = viewsToAdd[i];
-      ReactShadowNode cssNodeToAdd = mShadowNodeRegistry.getNode(viewAtIndex.mTag);
-      if (cssNodeToAdd == null) {
-        throw new IllegalViewOperationException("Trying to add unknown view tag: "
-            + viewAtIndex.mTag);
-      }
-      cssNodeToManage.addChildAt(cssNodeToAdd, viewAtIndex.mIndex);
-    }
-
-    if (!cssNodeToManage.isVirtual() && !cssNodeToManage.isVirtualAnchor()) {
-      mNativeViewHierarchyOptimizer.handleManageChildren(
-          cssNodeToManage,
-          indicesToRemove,
-          tagsToRemove,
-          viewsToAdd,
-          tagsToDelete);
-    }
-
-    for (int i = 0; i < tagsToDelete.length; i++) {
-      removeShadowNode(mShadowNodeRegistry.getNode(tagsToDelete[i]));
-    }
-  }
-
-  private void removeShadowNode(ReactShadowNode nodeToRemove) {
-    mNativeViewHierarchyOptimizer.handleRemoveNode(nodeToRemove);
-    for (int i = nodeToRemove.getChildCount() - 1; i >= 0; i--) {
-      removeShadowNode(nodeToRemove.getChildAt(i));
-    }
-    nodeToRemove.removeAllChildren();
+    mUIImplementation.manageChildren(
+        viewTag,
+        moveFrom,
+        moveTo,
+        addChildTags,
+        addAtIndices,
+        removeFrom);
   }
 
   /**
@@ -414,35 +247,7 @@ private void removeShadowNode(ReactShadowNode nodeToRemove) {
    */
   @ReactMethod
   public void replaceExistingNonRootView(int oldTag, int newTag) {
-    if (mShadowNodeRegistry.isRootNode(oldTag) || mShadowNodeRegistry.isRootNode(newTag)) {
-      throw new IllegalViewOperationException("Trying to add or replace a root tag!");
-    }
-
-    ReactShadowNode oldNode = mShadowNodeRegistry.getNode(oldTag);
-    if (oldNode == null) {
-      throw new IllegalViewOperationException("Trying to replace unknown view tag: " + oldTag);
-    }
-
-    ReactShadowNode parent = oldNode.getParent();
-    if (parent == null) {
-      throw new IllegalViewOperationException("Node is not attached to a parent: " + oldTag);
-    }
-
-    int oldIndex = parent.indexOf(oldNode);
-    if (oldIndex < 0) {
-      throw new IllegalStateException("Didn't find child tag in parent");
-    }
-
-    WritableArray tagsToAdd = Arguments.createArray();
-    tagsToAdd.pushInt(newTag);
-
-    WritableArray addAtIndices = Arguments.createArray();
-    addAtIndices.pushInt(oldIndex);
-
-    WritableArray indicesToRemove = Arguments.createArray();
-    indicesToRemove.pushInt(oldIndex);
-
-    manageChildren(parent.getReactTag(), null, null, tagsToAdd, addAtIndices, indicesToRemove);
+    mUIImplementation.replaceExistingNonRootView(oldTag, newTag);
   }
 
   /**
@@ -453,18 +258,7 @@ public void replaceExistingNonRootView(int oldTag, int newTag) {
    */
   @ReactMethod
   public void removeSubviewsFromContainerWithID(int containerTag) {
-    ReactShadowNode containerNode = mShadowNodeRegistry.getNode(containerTag);
-    if (containerNode == null) {
-      throw new IllegalViewOperationException(
-          "Trying to remove subviews of an unknown view tag: " + containerTag);
-    }
-
-    WritableArray indicesToRemove = Arguments.createArray();
-    for (int childIndex = 0; childIndex < containerNode.getChildCount(); childIndex++) {
-      indicesToRemove.pushInt(childIndex);
-    }
-
-    manageChildren(containerTag, null, null, null, null, indicesToRemove);
+    mUIImplementation.removeSubviewsFromContainerWithID(containerTag);
   }
 
   /**
@@ -472,12 +266,8 @@ public void removeSubviewsFromContainerWithID(int containerTag) {
    * via an async callback.
    */
   @ReactMethod
-  public void measure(final int reactTag, final Callback callback) {
-    // This method is called by the implementation of JS touchable interface (see Touchable.js for
-    // more details) at the moment of touch activation. That is after user starts the gesture from
-    // a touchable view with a given reactTag, or when user drag finger back into the press
-    // activation area of a touchable view that have been activated before.
-    mOperationsQueue.enqueueMeasure(reactTag, callback);
+  public void measure(int reactTag, Callback callback) {
+    mUIImplementation.measure(reactTag, callback);
   }
 
   /**
@@ -496,16 +286,7 @@ public void measureLayout(
       int ancestorTag,
       Callback errorCallback,
       Callback successCallback) {
-    try {
-      measureLayout(tag, ancestorTag, mMeasureBuffer);
-      float relativeX = PixelUtil.toDIPFromPixel(mMeasureBuffer[0]);
-      float relativeY = PixelUtil.toDIPFromPixel(mMeasureBuffer[1]);
-      float width = PixelUtil.toDIPFromPixel(mMeasureBuffer[2]);
-      float height = PixelUtil.toDIPFromPixel(mMeasureBuffer[3]);
-      successCallback.invoke(relativeX, relativeY, width, height);
-    } catch (IllegalViewOperationException e) {
-      errorCallback.invoke(e.getMessage());
-    }
+    mUIImplementation.measureLayout(tag, ancestorTag, errorCallback, successCallback);
   }
 
   /**
@@ -520,94 +301,7 @@ public void measureLayoutRelativeToParent(
       int tag,
       Callback errorCallback,
       Callback successCallback) {
-    try {
-      measureLayoutRelativeToParent(tag, mMeasureBuffer);
-      float relativeX = PixelUtil.toDIPFromPixel(mMeasureBuffer[0]);
-      float relativeY = PixelUtil.toDIPFromPixel(mMeasureBuffer[1]);
-      float width = PixelUtil.toDIPFromPixel(mMeasureBuffer[2]);
-      float height = PixelUtil.toDIPFromPixel(mMeasureBuffer[3]);
-      successCallback.invoke(relativeX, relativeY, width, height);
-    } catch (IllegalViewOperationException e) {
-      errorCallback.invoke(e.getMessage());
-    }
-  }
-
-  private void measureLayout(int tag, int ancestorTag, int[] outputBuffer) {
-    ReactShadowNode node = mShadowNodeRegistry.getNode(tag);
-    ReactShadowNode ancestor = mShadowNodeRegistry.getNode(ancestorTag);
-    if (node == null || ancestor == null) {
-      throw new IllegalViewOperationException(
-          "Tag " + (node == null ? tag : ancestorTag) + " does not exist");
-    }
-
-    if (node != ancestor) {
-      ReactShadowNode currentParent = node.getParent();
-      while (currentParent != ancestor) {
-        if (currentParent == null) {
-          throw new IllegalViewOperationException(
-              "Tag " + ancestorTag + " is not an ancestor of tag " + tag);
-        }
-        currentParent = currentParent.getParent();
-      }
-    }
-
-    measureLayoutRelativeToVerifiedAncestor(node, ancestor, outputBuffer);
-  }
-
-  private void measureLayoutRelativeToParent(int tag, int[] outputBuffer) {
-    ReactShadowNode node = mShadowNodeRegistry.getNode(tag);
-    if (node == null) {
-      throw new IllegalViewOperationException("No native view for tag " + tag + " exists!");
-    }
-    ReactShadowNode parent = node.getParent();
-    if (parent == null) {
-      throw new IllegalViewOperationException("View with tag " + tag + " doesn't have a parent!");
-    }
-
-    measureLayoutRelativeToVerifiedAncestor(node, parent, outputBuffer);
-  }
-
-  private void measureLayoutRelativeToVerifiedAncestor(
-      ReactShadowNode node,
-      ReactShadowNode ancestor,
-      int[] outputBuffer) {
-    int offsetX = 0;
-    int offsetY = 0;
-    if (node != ancestor) {
-      offsetX = Math.round(node.getLayoutX());
-      offsetY = Math.round(node.getLayoutY());
-      ReactShadowNode current = node.getParent();
-      while (current != ancestor) {
-        Assertions.assertNotNull(current);
-        assertNodeDoesNotNeedCustomLayoutForChildren(current);
-        offsetX += Math.round(current.getLayoutX());
-        offsetY += Math.round(current.getLayoutY());
-        current = current.getParent();
-      }
-      assertNodeDoesNotNeedCustomLayoutForChildren(ancestor);
-    }
-
-    outputBuffer[0] = offsetX;
-    outputBuffer[1] = offsetY;
-    outputBuffer[2] = node.getScreenWidth();
-    outputBuffer[3] = node.getScreenHeight();
-  }
-
-  private void assertNodeDoesNotNeedCustomLayoutForChildren(ReactShadowNode node) {
-    ViewManager viewManager = Assertions.assertNotNull(mViewManagers.get(node.getViewClass()));
-    ViewGroupManager viewGroupManager;
-    if (viewManager instanceof ViewGroupManager) {
-      viewGroupManager = (ViewGroupManager) viewManager;
-    } else {
-      throw new IllegalViewOperationException("Trying to use view " + node.getViewClass() +
-          " as a parent, but its Manager doesn't extends ViewGroupManager");
-    }
-    if (viewGroupManager != null && viewGroupManager.needsCustomLayoutForChildren()) {
-      throw new IllegalViewOperationException(
-          "Trying to measure a view using measureLayout/measureLayoutRelativeToParent relative to" +
-              " an ancestor that requires custom layout for it's children (" + node.getViewClass() +
-              "). Use measure instead.");
-    }
+    mUIImplementation.measureLayoutRelativeToParent(tag, errorCallback, successCallback);
   }
 
   /**
@@ -626,7 +320,7 @@ public void findSubviewIn(
       final int reactTag,
       final ReadableArray point,
       final Callback callback) {
-    mOperationsQueue.enqueueFindTargetForTouch(
+    mUIImplementation.findSubviewIn(
         reactTag,
         Math.round(PixelUtil.toPixelFromDIP(point.getDouble(0))),
         Math.round(PixelUtil.toPixelFromDIP(point.getDouble(1))),
@@ -637,47 +331,36 @@ public void findSubviewIn(
    * Registers a new Animation that can then be added to a View using {@link #addAnimation}.
    */
   public void registerAnimation(Animation animation) {
-    mOperationsQueue.enqueueRegisterAnimation(animation);
+    mUIImplementation.registerAnimation(animation);
   }
 
   /**
    * Adds an Animation previously registered with {@link #registerAnimation} to a View and starts it
    */
-  public void addAnimation(final int reactTag, final int animationID, final Callback onSuccess) {
-    assertViewExists(reactTag, "addAnimation");
-    mOperationsQueue.enqueueAddAnimation(reactTag, animationID, onSuccess);
+  public void addAnimation(int reactTag, int animationID, Callback onSuccess) {
+    mUIImplementation.addAnimation(reactTag, animationID, onSuccess);
   }
 
   /**
    * Removes an existing Animation, canceling it if it was in progress.
    */
   public void removeAnimation(int reactTag, int animationID) {
-    assertViewExists(reactTag, "removeAnimation");
-    mOperationsQueue.enqueueRemoveAnimation(animationID);
+    mUIImplementation.removeAnimation(reactTag, animationID);
   }
 
   @ReactMethod
   public void setJSResponder(int reactTag, boolean blockNativeResponder) {
-    assertViewExists(reactTag, "setJSResponder");
-    ReactShadowNode node = mShadowNodeRegistry.getNode(reactTag);
-    while (node.isVirtual() || node.isLayoutOnly()) {
-      node = node.getParent();
-    }
-    mOperationsQueue.enqueueSetJSResponder(node.getReactTag(), reactTag, blockNativeResponder);
+    mUIImplementation.setJSResponder(reactTag, blockNativeResponder);
   }
 
   @ReactMethod
   public void clearJSResponder() {
-    mOperationsQueue.enqueueClearJSResponder();
+    mUIImplementation.clearJSResponder();
   }
 
   @ReactMethod
-  public void dispatchViewManagerCommand(
-      int reactTag,
-      int commandId,
-      ReadableArray commandArgs) {
-    assertViewExists(reactTag, "dispatchViewManagerCommand");
-    mOperationsQueue.enqueueDispatchCommand(reactTag, commandId, commandArgs);
+  public void dispatchViewManagerCommand(int reactTag, int commandId, ReadableArray commandArgs) {
+    mUIImplementation.dispatchViewManagerCommand(reactTag, commandId, commandArgs);
   }
 
   /**
@@ -691,13 +374,8 @@ public void dispatchViewManagerCommand(
    *        no arguments if the menu is dismissed
    */
   @ReactMethod
-  public void showPopupMenu(
-      int reactTag,
-      ReadableArray items,
-      Callback error,
-      Callback success) {
-    assertViewExists(reactTag, "showPopupMenu");
-    mOperationsQueue.enqueueShowPopupMenu(reactTag, items, error, success);
+  public void showPopupMenu(int reactTag, ReadableArray items, Callback error, Callback success) {
+    mUIImplementation.showPopupMenu(reactTag, items, error, success);
   }
 
   @ReactMethod
@@ -708,14 +386,6 @@ public void configureNextLayoutAnimation(
     // TODO(6588266): Implement if required
   }
 
-  private void assertViewExists(int reactTag, String operationNameForExceptionMessage) {
-    if (mShadowNodeRegistry.getNode(reactTag) == null) {
-      throw new IllegalViewOperationException(
-          "Unable to execute operation " + operationNameForExceptionMessage + " on view with " +
-              "tag: " + reactTag + ", since the view does not exists");
-    }
-  }
-
   /**
    * To implement the transactional requirement mentioned in the class javadoc, we only commit
    * UI changes to the actual view hierarchy once a batch of JS->Java calls have been completed.
@@ -739,7 +409,7 @@ public void onBatchComplete() {
           .arg("BatchId", batchId)
           .flush();
     try {
-      dispatchViewUpdates(batchId);
+      mUIImplementation.dispatchViewUpdates(mEventDispatcher, batchId);
     } finally {
       Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
     }
@@ -747,73 +417,15 @@ public void onBatchComplete() {
 
   public void setViewHierarchyUpdateDebugListener(
       @Nullable NotThreadSafeViewHierarchyUpdateDebugListener listener) {
-    mOperationsQueue.setViewHierarchyUpdateDebugListener(listener);
+    mUIImplementation.setViewHierarchyUpdateDebugListener(listener);
   }
 
   public EventDispatcher getEventDispatcher() {
     return mEventDispatcher;
   }
 
-  private void dispatchViewUpdates(final int batchId) {
-    for (int i = 0; i < mShadowNodeRegistry.getRootNodeCount(); i++) {
-      int tag = mShadowNodeRegistry.getRootTag(i);
-      ReactShadowNode cssRoot = mShadowNodeRegistry.getNode(tag);
-      notifyOnBeforeLayoutRecursive(cssRoot);
-
-      SystraceMessage.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "cssRoot.calculateLayout")
-          .arg("rootTag", tag)
-          .flush();
-      try {
-        cssRoot.calculateLayout(mLayoutContext);
-      } finally {
-        Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
-      }
-      applyUpdatesRecursive(cssRoot, 0f, 0f);
-    }
-
-    mNativeViewHierarchyOptimizer.onBatchComplete();
-    mOperationsQueue.dispatchViewUpdates(batchId);
-  }
-
-  private void notifyOnBeforeLayoutRecursive(ReactShadowNode cssNode) {
-    if (!cssNode.hasUpdates()) {
-      return;
-    }
-    for (int i = 0; i < cssNode.getChildCount(); i++) {
-      notifyOnBeforeLayoutRecursive(cssNode.getChildAt(i));
-    }
-    cssNode.onBeforeLayout();
-  }
-
-  private void applyUpdatesRecursive(ReactShadowNode cssNode, float absoluteX, float absoluteY) {
-    if (!cssNode.hasUpdates()) {
-      return;
-    }
-
-    if (!cssNode.isVirtualAnchor()) {
-      for (int i = 0; i < cssNode.getChildCount(); i++) {
-        applyUpdatesRecursive(
-            cssNode.getChildAt(i),
-            absoluteX + cssNode.getLayoutX(),
-            absoluteY + cssNode.getLayoutY());
-      }
-    }
-
-    int tag = cssNode.getReactTag();
-    if (!mShadowNodeRegistry.isRootNode(tag)) {
-      cssNode.dispatchUpdates(
-          absoluteX,
-          absoluteY,
-          mOperationsQueue,
-          mNativeViewHierarchyOptimizer,
-          mEventDispatcher);
-    }
-    cssNode.markUpdateSeen();
-  }
-
   @ReactMethod
   public void sendAccessibilityEvent(int tag, int eventType) {
-    mOperationsQueue.enqueueSendAccessibilityEvent(tag, eventType);
+    mUIImplementation.sendAccessibilityEvent(tag, eventType);
   }
-
 }

From e379536c113c7adde291854f1cd1808e6df64574 Mon Sep 17 00:00:00 2001
From: Julius Jurgelenas <julius@jurgelenas.lt>
Date: Thu, 26 Nov 2015 12:43:39 +0200
Subject: [PATCH 0118/1411] Showcase: add blog post link to Formations Factory
 Company name search app

---
 website/src/react-native/showcase.js | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 987580237dd9..7d9bbfd816a9 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -140,6 +140,9 @@ var apps = [
     icon: 'http://a4.mzstatic.com/us/r30/Purple69/v4/fd/47/53/fd47537c-5861-e208-d1d1-1e26b5e45a36/icon350x350.jpeg',
     link: 'https://itunes.apple.com/us/app/company-name-search/id1043824076',
     author: 'The Formations Factory Ltd',
+    blogs: [
+      'https://medium.com/formations-factory/creating-company-name-search-app-with-react-native-36a049b0848d',
+    ],
   },
   {
     name: 'DareU',

From 5b5b55027b1c63f4b1979a5af789f350898bdce5 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 26 Nov 2015 03:04:33 -0800
Subject: [PATCH 0119/1411] Added support for custom color and image for map
 annotations

Summary: public

This diff extends RCTMap annotations with an `image` and `tintColor` property, which can be used to render completely custom pin graphics.

The tintColor applies to both regular pins and custom pin images, allowing you to provide varied pin colors without needing multiple graphic assets.

Reviewed By: fredliu

Differential Revision: D2685581

fb-gh-sync-id: c7cf0af5c90fd8d1e9b3fec4b89206440b47ba8f
---
 Examples/UIExplorer/MapViewExample.js   | 137 ++++++++++++++++++++++--
 Libraries/Components/MapView/MapView.js | 114 ++++++++++++++------
 React/Base/RCTConvert.m                 |  17 +--
 React/Base/RCTUtils.h                   |   6 ++
 React/Base/RCTUtils.m                   |  64 +++++++++++
 React/Views/RCTConvert+MapKit.m         |   5 +
 React/Views/RCTMapManager.m             |  69 +++++++++---
 React/Views/RCTPointAnnotation.h        |   2 +
 8 files changed, 356 insertions(+), 58 deletions(-)

diff --git a/Examples/UIExplorer/MapViewExample.js b/Examples/UIExplorer/MapViewExample.js
index 572017574759..9a7e2e1aab23 100644
--- a/Examples/UIExplorer/MapViewExample.js
+++ b/Examples/UIExplorer/MapViewExample.js
@@ -149,9 +149,6 @@ var MapViewExample = React.createClass({
 
   getInitialState() {
     return {
-      mapRegion: null,
-      mapRegionInput: null,
-      annotations: null,
       isFirstLoad: true,
     };
   },
@@ -163,12 +160,12 @@ var MapViewExample = React.createClass({
           style={styles.map}
           onRegionChange={this._onRegionChange}
           onRegionChangeComplete={this._onRegionChangeComplete}
-          region={this.state.mapRegion || undefined}
-          annotations={this.state.annotations || undefined}
+          region={this.state.mapRegion}
+          annotations={this.state.annotations}
         />
         <MapRegionInput
           onChange={this._onRegionInputChanged}
-          region={this.state.mapRegionInput || undefined}
+          region={this.state.mapRegionInput}
         />
       </View>
     );
@@ -208,6 +205,114 @@ var MapViewExample = React.createClass({
 
 });
 
+var CalloutMapViewExample = React.createClass({
+
+  getInitialState() {
+    return {
+      isFirstLoad: true,
+    };
+  },
+
+  render() {
+    if (this.state.isFirstLoad) {
+      var onRegionChangeComplete = (region) => {
+        this.setState({
+          isFirstLoad: false,
+          annotations: [{
+            longitude: region.longitude,
+            latitude: region.latitude,
+            title: 'More Info...',
+            hasRightCallout: true,
+            onRightCalloutPress: () => {
+              alert('You Are Here');
+            },
+          }],
+        });
+      };
+    }
+
+    return (
+      <MapView
+        style={styles.map}
+        onRegionChangeComplete={onRegionChangeComplete}
+        region={this.state.mapRegion}
+        annotations={this.state.annotations}
+      />
+    );
+  },
+
+});
+
+var CustomPinColorMapViewExample = React.createClass({
+
+  getInitialState() {
+    return {
+      isFirstLoad: true,
+    };
+  },
+
+  render() {
+    if (this.state.isFirstLoad) {
+      var onRegionChangeComplete = (region) => {
+        this.setState({
+          isFirstLoad: false,
+          annotations: [{
+            longitude: region.longitude,
+            latitude: region.latitude,
+            title: 'You Are Purple',
+            tintColor: MapView.PinColors.PURPLE,
+          }],
+        });
+      };
+    }
+
+    return (
+      <MapView
+        style={styles.map}
+        onRegionChangeComplete={onRegionChangeComplete}
+        region={this.state.mapRegion}
+        annotations={this.state.annotations}
+      />
+    );
+  },
+
+});
+
+var CustomPinImageMapViewExample = React.createClass({
+
+  getInitialState() {
+    return {
+      isFirstLoad: true,
+    };
+  },
+
+  render() {
+    if (this.state.isFirstLoad) {
+      var onRegionChangeComplete = (region) => {
+        this.setState({
+          isFirstLoad: false,
+          annotations: [{
+            longitude: region.longitude,
+            latitude: region.latitude,
+            title: 'Thumbs Up!',
+            image: require('image!uie_thumb_big'),
+          }],
+        });
+      };
+    }
+
+    return (
+      <MapView
+        style={styles.map}
+        onRegionChangeComplete={onRegionChangeComplete}
+        region={this.state.mapRegion}
+        annotations={this.state.annotations}
+      />
+    );
+  },
+
+});
+
 var styles = StyleSheet.create({
   map: {
     height: 150,
@@ -249,5 +354,23 @@ exports.examples = [
     render() {
       return  <MapView style={styles.map} showsUserLocation={true} />;
     }
-  }
+  },
+  {
+    title: 'Callout example',
+    render() {
+      return  <CalloutMapViewExample style={styles.map} />;
+    }
+  },
+  {
+    title: 'Custom pin color',
+    render() {
+      return  <CustomPinColorMapViewExample style={styles.map} />;
+    }
+  },
+  {
+    title: 'Custom pin image',
+    render() {
+      return  <CustomPinImageMapViewExample style={styles.map} />;
+    }
+  },
 ];
diff --git a/Libraries/Components/MapView/MapView.js b/Libraries/Components/MapView/MapView.js
index 58950c490714..26cd3f61ee62 100644
--- a/Libraries/Components/MapView/MapView.js
+++ b/Libraries/Components/MapView/MapView.js
@@ -12,7 +12,9 @@
 'use strict';
 
 var EdgeInsetsPropType = require('EdgeInsetsPropType');
+var Image = require('Image');
 var NativeMethodsMixin = require('NativeMethodsMixin');
+var PinColors = require('NativeModules').UIManager.RCTMap.Constants.PinColors;
 var Platform = require('Platform');
 var React = require('React');
 var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
@@ -21,6 +23,8 @@ var View = require('View');
 var deepDiffer = require('deepDiffer');
 var insetsDiffer = require('insetsDiffer');
 var merge = require('merge');
+var processColor = require('processColor');
+var resolveAssetSource = require('resolveAssetSource');
 var requireNativeComponent = require('requireNativeComponent');
 
 type Event = Object;
@@ -194,7 +198,21 @@ var MapView = React.createClass({
       /**
        * annotation id
        */
-      id: React.PropTypes.string
+      id: React.PropTypes.string,
+
+      /**
+       * The pin color. This can be any valid color string, or you can use one
+       * of the predefined PinColors constants. Applies to both standard pins
+       * and custom pin images.
+       * @platform ios
+       */
+      tintColor: React.PropTypes.string,
+
+      /**
+       * Custom pin image. This must be a static image resource inside the app.
+       * @platform ios
+       */
+      image: Image.propTypes.source,
 
     })),
 
@@ -235,47 +253,79 @@ var MapView = React.createClass({
     active: React.PropTypes.bool,
   },
 
-  _onChange: function(event: Event) {
-    if (event.nativeEvent.continuous) {
-      this.props.onRegionChange &&
-        this.props.onRegionChange(event.nativeEvent.region);
-    } else {
-      this.props.onRegionChangeComplete &&
-        this.props.onRegionChangeComplete(event.nativeEvent.region);
-    }
-  },
-
-  _onPress: function(event: Event) {
-    if (event.nativeEvent.action === 'annotation-click') {
-      this.props.onAnnotationPress && this.props.onAnnotationPress(event.nativeEvent.annotation);
-    }
+  render: function() {
 
-    if (event.nativeEvent.action === 'callout-click') {
-      if (!this.props.annotations) {
-        return;
-      }
+    let {annotations} = this.props;
+    annotations = annotations && annotations.map((annotation: Object) => {
+      let {tintColor, image} = annotation;
+      return {
+        ...annotation,
+        tintColor: tintColor && processColor(tintColor),
+        image: image && resolveAssetSource(image),
+      };
+    });
 
-      // Find the annotation with the id of what has been pressed
-      for (var i = 0; i < this.props.annotations.length; i++) {
-        var annotation = this.props.annotations[i];
-        if (annotation.id === event.nativeEvent.annotationId) {
-          // Pass the right function
-          if (event.nativeEvent.side === 'left') {
-            annotation.onLeftCalloutPress && annotation.onLeftCalloutPress(event.nativeEvent);
-          } else if (event.nativeEvent.side === 'right') {
-            annotation.onRightCalloutPress && annotation.onRightCalloutPress(event.nativeEvent);
+    // TODO: these should be separate events, to reduce bridge traffic
+    if (annotations || this.props.onAnnotationPress) {
+      var onPress = (event: Event) => {
+        if (event.nativeEvent.action === 'annotation-click') {
+          this.props.onAnnotationPress &&
+            this.props.onAnnotationPress(event.nativeEvent.annotation);
+        } else if (event.nativeEvent.action === 'callout-click') {
+          // Find the annotation with the id that was pressed
+          for (let i = 0, l = annotations.length; i < l; i++) {
+            let annotation = annotations[i];
+            if (annotation.id === event.nativeEvent.annotationId) {
+              // Pass the right function
+              if (event.nativeEvent.side === 'left') {
+                annotation.onLeftCalloutPress &&
+                  annotation.onLeftCalloutPress(event.nativeEvent);
+              } else if (event.nativeEvent.side === 'right') {
+                annotation.onRightCalloutPress &&
+                  annotation.onRightCalloutPress(event.nativeEvent);
+              }
+              break;
+            }
           }
         }
-      }
+      };
+    }
 
+    // TODO: these should be separate events, to reduce bridge traffic
+    if (this.props.onRegionChange || this.props.onRegionChangeComplete) {
+      var onChange = (event: Event) => {
+        if (event.nativeEvent.continuous) {
+          this.props.onRegionChange &&
+            this.props.onRegionChange(event.nativeEvent.region);
+        } else {
+          this.props.onRegionChangeComplete &&
+            this.props.onRegionChangeComplete(event.nativeEvent.region);
+        }
+      };
     }
-  },
 
-  render: function() {
-    return <RCTMap {...this.props} onPress={this._onPress} onChange={this._onChange} />;
+    return (
+      <RCTMap
+        {...this.props}
+        annotations={annotations}
+        onPress={onPress}
+        onChange={onChange}
+      />
+    );
   },
 });
 
+/**
+ * Standard iOS MapView pin color constants, to be used with the
+ * `annotation.tintColor` property. You are not obliged to use these,
+ * but they are useful for matching the standard iOS look and feel.
+ */
+MapView.PinColors = PinColors && {
+  RED: PinColors.RED,
+  GREEN: PinColors.GREEN,
+  PURPLE: PinColors.PURPLE,
+};
+
 var RCTMap = requireNativeComponent('RCTMap', MapView, {
   nativeOnly: {onChange: true, onPress: true}
 });
diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m
index 53c6b9cad226..8fc14e102fb0 100644
--- a/React/Base/RCTConvert.m
+++ b/React/Base/RCTConvert.m
@@ -397,6 +397,9 @@ + (type)type:(id)json                                 \
 
 + (UIColor *)UIColor:(id)json
 {
+  if (!json) {
+    return nil;
+  }
   if ([json isKindOfClass:[NSArray class]]) {
     NSArray *components = [self NSNumberArray:json];
     CGFloat alpha = components.count > 3 ? [self CGFloat:components[3]] : 1.0;
@@ -404,13 +407,16 @@ + (UIColor *)UIColor:(id)json
                            green:[self CGFloat:components[1]]
                             blue:[self CGFloat:components[2]]
                            alpha:alpha];
-  } else {
+  } else if ([json isKindOfClass:[NSNumber class]]) {
     NSUInteger argb = [self NSUInteger:json];
     CGFloat a = ((argb >> 24) & 0xFF) / 255.0;
     CGFloat r = ((argb >> 16) & 0xFF) / 255.0;
     CGFloat g = ((argb >> 8) & 0xFF) / 255.0;
     CGFloat b = (argb & 0xFF) / 255.0;
     return [UIColor colorWithRed:r green:g blue:b alpha:a];
+  } else {
+    RCTLogConvertError(json, @"a color");
+    return nil;
   }
 }
 
@@ -460,12 +466,9 @@ + (UIImage *)UIImage:(id)json
   NSURL *URL = [self NSURL:path];
   NSString *scheme = URL.scheme.lowercaseString;
   if ([scheme isEqualToString:@"file"]) {
-    if (RCTIsXCAssetURL(URL)) {
-      // Image may reside inside a .car file, in which case we have no choice
-      // but to use +[UIImage imageNamed] - but this method isn't thread safe
-      NSString *assetName = RCTBundlePathForURL(URL);
-      image = [UIImage imageNamed:assetName];
-    } else {
+    NSString *assetName = RCTBundlePathForURL(URL);
+    image = [UIImage imageNamed:assetName];
+    if (!image) {
       // Attempt to load from the file system
       NSString *filePath = URL.path;
       if (filePath.pathExtension.length == 0) {
diff --git a/React/Base/RCTUtils.h b/React/Base/RCTUtils.h
index e138da40531b..e8f3781a6c61 100644
--- a/React/Base/RCTUtils.h
+++ b/React/Base/RCTUtils.h
@@ -84,6 +84,9 @@ RCT_EXTERN NSError *RCTErrorWithMessage(NSString *message);
 RCT_EXTERN id RCTNilIfNull(id value);
 RCT_EXTERN id RCTNullIfNil(id value);
 
+// Convert NaN or infinite values to zero, as these aren't JSON-safe
+RCT_EXTERN double RCTZeroIfNaN(double value);
+
 // Convert data to a Base64-encoded data URL
 RCT_EXTERN NSURL *RCTDataURL(NSString *mimeType, NSData *data);
 
@@ -96,3 +99,6 @@ RCT_EXTERN NSString *RCTBundlePathForURL(NSURL *URL);
 
 // Determines if a given image URL actually refers to an XCAsset
 RCT_EXTERN BOOL RCTIsXCAssetURL(NSURL *imageURL);
+
+// Converts a CGColor to a hex string
+RCT_EXTERN NSString *RCTColorToHexString(CGColorRef color);
diff --git a/React/Base/RCTUtils.m b/React/Base/RCTUtils.m
index 8d6f3238d0c9..b7a751488378 100644
--- a/React/Base/RCTUtils.m
+++ b/React/Base/RCTUtils.m
@@ -420,6 +420,11 @@ id RCTNilIfNull(id value)
   return value == (id)kCFNull ? nil : value;
 }
 
+RCT_EXTERN double RCTZeroIfNaN(double value)
+{
+  return isnan(value) || isinf(value) ? 0 : value;
+}
+
 NSURL *RCTDataURL(NSString *mimeType, NSData *data)
 {
   return [NSURL URLWithString:
@@ -511,3 +516,62 @@ BOOL RCTIsXCAssetURL(NSURL *imageURL)
   }
   return YES;
 }
+
+static void RCTGetRGBAColorComponents(CGColorRef color, CGFloat rgba[4])
+{
+  CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(color));
+  const CGFloat *components = CGColorGetComponents(color);
+  switch (model)
+  {
+    case kCGColorSpaceModelMonochrome:
+    {
+      rgba[0] = components[0];
+      rgba[1] = components[0];
+      rgba[2] = components[0];
+      rgba[3] = components[1];
+      break;
+    }
+    case kCGColorSpaceModelRGB:
+    {
+      rgba[0] = components[0];
+      rgba[1] = components[1];
+      rgba[2] = components[2];
+      rgba[3] = components[3];
+      break;
+    }
+    case kCGColorSpaceModelCMYK:
+    case kCGColorSpaceModelDeviceN:
+    case kCGColorSpaceModelIndexed:
+    case kCGColorSpaceModelLab:
+    case kCGColorSpaceModelPattern:
+    case kCGColorSpaceModelUnknown:
+    {
+
+#ifdef RCT_DEBUG
+      //unsupported format
+      RCTLogError(@"Unsupported color model: %i", model);
+#endif
+
+      rgba[0] = 0.0;
+      rgba[1] = 0.0;
+      rgba[2] = 0.0;
+      rgba[3] = 1.0;
+      break;
+    }
+  }
+}
+
+NSString *RCTColorToHexString(CGColorRef color)
+{
+  CGFloat rgba[4];
+  RCTGetRGBAColorComponents(color, rgba);
+  uint8_t r = rgba[0]*255;
+  uint8_t g = rgba[1]*255;
+  uint8_t b = rgba[2]*255;
+  uint8_t a = rgba[3]*255;
+  if (a < 255) {
+    return [NSString stringWithFormat:@"#%02x%02x%02x%02x", r, g, b, a];
+  } else {
+    return [NSString stringWithFormat:@"#%02x%02x%02x", r, g, b];
+  }
+}
diff --git a/React/Views/RCTConvert+MapKit.m b/React/Views/RCTConvert+MapKit.m
index 9206c3a4050e..dab5b7661719 100644
--- a/React/Views/RCTConvert+MapKit.m
+++ b/React/Views/RCTConvert+MapKit.m
@@ -61,6 +61,11 @@ + (RCTPointAnnotation *)RCTPointAnnotation:(id)json
   shape.hasLeftCallout = [RCTConvert BOOL:json[@"hasLeftCallout"]];
   shape.hasRightCallout = [RCTConvert BOOL:json[@"hasRightCallout"]];
   shape.animateDrop = [RCTConvert BOOL:json[@"animateDrop"]];
+  shape.tintColor = [RCTConvert UIColor:json[@"tintColor"]];
+  shape.image = [RCTConvert UIImage:json[@"image"]];
+  if (shape.tintColor && shape.image) {
+    shape.image = [shape.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+  }
   return shape;
 }
 
diff --git a/React/Views/RCTMapManager.m b/React/Views/RCTMapManager.m
index 5372793a8166..75602578d334 100644
--- a/React/Views/RCTMapManager.m
+++ b/React/Views/RCTMapManager.m
@@ -14,6 +14,7 @@
 #import "RCTConvert+MapKit.h"
 #import "RCTEventDispatcher.h"
 #import "RCTMap.h"
+#import "RCTUtils.h"
 #import "UIView+React.h"
 #import "RCTPointAnnotation.h"
 
@@ -55,6 +56,17 @@ - (UIView *)view
   [view setRegion:json ? [RCTConvert MKCoordinateRegion:json] : defaultView.region animated:YES];
 }
 
+- (NSDictionary<NSString *, id> *)constantsToExport
+{
+  return @{
+    @"PinColors": @{
+      @"RED": RCTColorToHexString([MKPinAnnotationView redPinColor].CGColor),
+      @"GREEN": RCTColorToHexString([MKPinAnnotationView greenPinColor].CGColor),
+      @"PURPLE": RCTColorToHexString([MKPinAnnotationView purplePinColor].CGColor),
+    }
+  };
+}
+
 #pragma mark MKMapViewDelegate
 
 - (void)mapView:(RCTMap *)mapView didSelectAnnotationView:(MKAnnotationView *)view
@@ -81,10 +93,41 @@ - (MKAnnotationView *)mapView:(__unused MKMapView *)mapView viewForAnnotation:(R
     return nil;
   }
 
-  MKPinAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"RCTAnnotation"];
+  MKAnnotationView *annotationView;
+  if (annotation.image) {
+    if (annotation.tintColor) {
+
+      NSString *const reuseIdentifier = @"RCTImageViewAnnotation";
+      NSInteger imageViewTag = 99;
+      annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseIdentifier];
+      if (!annotationView) {
+        annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
+        UIImageView *imageView = [UIImageView new];
+        imageView.tag = imageViewTag;
+        [annotationView addSubview:imageView];
+      }
+
+      UIImageView *imageView = (UIImageView *)[annotationView viewWithTag:imageViewTag];
+      imageView.image = annotation.image;
+      imageView.tintColor = annotation.tintColor;
+      [imageView sizeToFit];
+      imageView.center = CGPointZero;
+
+    } else {
 
+      NSString *reuseIdentifier = NSStringFromClass([MKAnnotationView class]);
+      annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseIdentifier] ?: [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
+      annotationView.image = annotation.image;
+    }
+
+  } else {
+
+    NSString *reuseIdentifier = NSStringFromClass([MKPinAnnotationView class]);
+    annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseIdentifier] ?: [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
+    ((MKPinAnnotationView *)annotationView).animatesDrop = annotation.animateDrop;
+    ((MKPinAnnotationView *)annotationView).pinTintColor = annotation.tintColor ?: [MKPinAnnotationView redPinColor];
+  }
   annotationView.canShowCallout = true;
-  annotationView.animatesDrop = annotation.animateDrop;
 
   annotationView.leftCalloutAccessoryView = nil;
   if (annotation.hasLeftCallout) {
@@ -172,13 +215,17 @@ - (void)_regionChanged:(RCTMap *)mapView
   BOOL needZoom = NO;
   CGFloat newLongitudeDelta = 0.0f;
   MKCoordinateRegion region = mapView.region;
-  // On iOS 7, it's possible that we observe invalid locations during initialization of the map.
-  // Filter those out.
+
+  // On iOS 7, it's possible that we observe invalid locations during
+  // initialization of the map. Filter those out.
   if (!CLLocationCoordinate2DIsValid(region.center)) {
     return;
   }
-  // Calculation on float is not 100% accurate. If user zoom to max/min and then move, it's likely the map will auto zoom to max/min from time to time.
-  // So let's try to make map zoom back to 99% max or 101% min so that there are some buffer that moving the map won't constantly hitting the max/min bound.
+
+  // Calculation on float is not 100% accurate. If user zoom to max/min and then
+  // move, it's likely the map will auto zoom to max/min from time to time.
+  // So let's try to make map zoom back to 99% max or 101% min so that there is
+  // some buffer, and moving the map won't constantly hit the max/min bound.
   if (mapView.maxDelta > FLT_EPSILON && region.span.longitudeDelta > mapView.maxDelta) {
     needZoom = YES;
     newLongitudeDelta = mapView.maxDelta * (1 - RCTMapZoomBoundBuffer);
@@ -204,15 +251,13 @@ - (void)_emitRegionChangeEvent:(RCTMap *)mapView continuous:(BOOL)continuous
       return;
     }
 
-  #define FLUSH_NAN(value) (isnan(value) ? 0 : value)
-
     mapView.onChange(@{
       @"continuous": @(continuous),
       @"region": @{
-        @"latitude": @(FLUSH_NAN(region.center.latitude)),
-        @"longitude": @(FLUSH_NAN(region.center.longitude)),
-        @"latitudeDelta": @(FLUSH_NAN(region.span.latitudeDelta)),
-        @"longitudeDelta": @(FLUSH_NAN(region.span.longitudeDelta)),
+        @"latitude": @(RCTZeroIfNaN(region.center.latitude)),
+        @"longitude": @(RCTZeroIfNaN(region.center.longitude)),
+        @"latitudeDelta": @(RCTZeroIfNaN(region.span.latitudeDelta)),
+        @"longitudeDelta": @(RCTZeroIfNaN(region.span.longitudeDelta)),
       }
     });
   }
diff --git a/React/Views/RCTPointAnnotation.h b/React/Views/RCTPointAnnotation.h
index 0646608d4805..1ee8fb05508a 100644
--- a/React/Views/RCTPointAnnotation.h
+++ b/React/Views/RCTPointAnnotation.h
@@ -15,5 +15,7 @@
 @property (nonatomic, assign) BOOL hasLeftCallout;
 @property (nonatomic, assign) BOOL hasRightCallout;
 @property (nonatomic, assign) BOOL animateDrop;
+@property (nonatomic, strong) UIColor *tintColor;
+@property (nonatomic, strong) UIImage *image;
 
 @end

From 9365414559a8ae629496f78d78ba043afdee29ee Mon Sep 17 00:00:00 2001
From: SungHyun Park <puresprout@gmail.com>
Date: Thu, 26 Nov 2015 03:32:57 -0800
Subject: [PATCH 0120/1411] added TRACE_TAG_REACT_APPS constants

Summary: added required constants
Closes https://github.com/facebook/react-native/pull/4366

Reviewed By: svcscm

Differential Revision: D2699433

Pulled By: astreet

fb-gh-sync-id: 33c69b248f682e1b31bb2ef79cb0253ddd8d8817
---
 ReactAndroid/src/main/java/com/facebook/systrace/Systrace.java | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ReactAndroid/src/main/java/com/facebook/systrace/Systrace.java b/ReactAndroid/src/main/java/com/facebook/systrace/Systrace.java
index 20867d7e248d..4ffaa3eb4a26 100644
--- a/ReactAndroid/src/main/java/com/facebook/systrace/Systrace.java
+++ b/ReactAndroid/src/main/java/com/facebook/systrace/Systrace.java
@@ -20,6 +20,7 @@ public class Systrace {
 
   public static final long TRACE_TAG_REACT_JAVA_BRIDGE = 0L;
   public static final long TRACE_TAG_REACT_FRESCO = 0L;
+  public static final long TRACE_TAG_REACT_APPS = 0L;
 
   public enum EventScope {
     THREAD('t'),

From ea96a7edb8a17fbcc57db99217783302bb790056 Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Thu, 26 Nov 2015 03:15:04 -0800
Subject: [PATCH 0121/1411] Avoid dispatch_async on RCTProfile when not
 profiling

Summary: public

Fixes #3953

Bail out soon when the profiler is not running + move string formating into the macro so that it happens in a background queue.

Reviewed By: jspahrsummers

Differential Revision: D2696167

fb-gh-sync-id: a1b91ee4459078ab9a4c0be62bd23362ec05e208
---
 React/Base/RCTBatchedBridge.m |  3 +--
 React/Profiler/RCTProfile.h   | 36 ++++++++++++++++++++---------------
 2 files changed, 22 insertions(+), 17 deletions(-)

diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index 0430f2b0af1f..89861dedaf53 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -871,12 +871,11 @@ - (void)_jsThreadUpdate:(CADisplayLink *)displayLink
   for (RCTModuleData *moduleData in _frameUpdateObservers) {
     id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)moduleData.instance;
     if (!observer.paused) {
-      RCT_IF_DEV(NSString *name = [NSString stringWithFormat:@"[%@ didUpdateFrame:%f]", observer, displayLink.timestamp];)
       RCTProfileBeginFlowEvent();
 
       [self dispatchBlock:^{
         RCTProfileEndFlowEvent();
-        RCT_PROFILE_BEGIN_EVENT(0, name, nil);
+        RCT_PROFILE_BEGIN_EVENT(0, [NSString stringWithFormat:@"[%@ didUpdateFrame:%f]", observer, displayLink.timestamp], nil);
         [observer didUpdateFrame:frameUpdate];
         RCT_PROFILE_END_EVENT(0, @"objc_call,fps", nil);
       } queue:moduleData.methodQueue];
diff --git a/React/Profiler/RCTProfile.h b/React/Profiler/RCTProfile.h
index 5829a8eb4b93..2e6e921d3d26 100644
--- a/React/Profiler/RCTProfile.h
+++ b/React/Profiler/RCTProfile.h
@@ -66,13 +66,16 @@ RCT_EXTERN void _RCTProfileBeginEvent(NSThread *calleeThread,
                                       uint64_t tag,
                                       NSString *name,
                                       NSDictionary *args);
-#define RCT_PROFILE_BEGIN_EVENT(...) { \
-  NSThread *calleeThread = [NSThread currentThread]; \
-  NSTimeInterval time = CACurrentMediaTime(); \
-  dispatch_async(RCTProfileGetQueue(), ^{ \
-    _RCTProfileBeginEvent(calleeThread, time, __VA_ARGS__); \
-  }); \
-}
+#define RCT_PROFILE_BEGIN_EVENT(...) \
+  do { \
+    if (RCTProfileIsProfiling()) { \
+      NSThread *calleeThread = [NSThread currentThread]; \
+      NSTimeInterval time = CACurrentMediaTime(); \
+      dispatch_async(RCTProfileGetQueue(), ^{ \
+        _RCTProfileBeginEvent(calleeThread, time, __VA_ARGS__); \
+      }); \
+    } \
+  } while(0)
 
 /**
  * The ID returned by BeginEvent should then be passed into EndEvent, with the
@@ -86,14 +89,17 @@ RCT_EXTERN void _RCTProfileEndEvent(NSThread *calleeThread,
                                     NSString *category,
                                     NSDictionary *args);
 
-#define RCT_PROFILE_END_EVENT(...) { \
-  NSThread *calleeThread = [NSThread currentThread]; \
-  NSString *threadName = RCTCurrentThreadName(); \
-  NSTimeInterval time = CACurrentMediaTime(); \
-  dispatch_async(RCTProfileGetQueue(), ^{ \
-    _RCTProfileEndEvent(calleeThread, threadName, time, __VA_ARGS__); \
-  }); \
-}
+#define RCT_PROFILE_END_EVENT(...) \
+  do { \
+    if (RCTProfileIsProfiling()) { \
+      NSThread *calleeThread = [NSThread currentThread]; \
+      NSString *threadName = RCTCurrentThreadName(); \
+      NSTimeInterval time = CACurrentMediaTime(); \
+      dispatch_async(RCTProfileGetQueue(), ^{ \
+        _RCTProfileEndEvent(calleeThread, threadName, time, __VA_ARGS__); \
+      }); \
+    } \
+  } while(0)
 
 /**
  * Collects the initial event information for the event and returns a reference ID

From bf0934a5318bb506c1d6c05730cbe6093725c24a Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Thu, 26 Nov 2015 04:07:56 -0800
Subject: [PATCH 0122/1411] Delete RCTRootView's deprecated 'initialProperties'
 property

Reviewed By: majak

Differential Revision: D2597411

fb-gh-sync-id: 547837cac8e22e7fe78db6213741634b87bcf571
---
 React/Base/RCTRootView.h | 8 --------
 React/Base/RCTRootView.m | 8 --------
 2 files changed, 16 deletions(-)

diff --git a/React/Base/RCTRootView.h b/React/Base/RCTRootView.h
index fdb7d6b9b22e..710711704000 100644
--- a/React/Base/RCTRootView.h
+++ b/React/Base/RCTRootView.h
@@ -74,14 +74,6 @@ extern NSString *const RCTContentDidAppearNotification;
  */
 @property (nonatomic, strong, readonly) RCTBridge *bridge;
 
-/**
- * DEPRECATED: access app properties via appProperties property instead
- *
- * The default properties to apply to the view when the script bundle
- * is first loaded. Defaults to nil/empty.
- */
-@property (nonatomic, copy, readonly) NSDictionary *initialProperties DEPRECATED_MSG_ATTRIBUTE ("use appProperties instead");
-
 /**
  * The properties to apply to the view. Use this property to update
  * application properties and rerender the view. Initialized with
diff --git a/React/Base/RCTRootView.m b/React/Base/RCTRootView.m
index fb9116d620ab..6be45621c43e 100644
--- a/React/Base/RCTRootView.m
+++ b/React/Base/RCTRootView.m
@@ -53,7 +53,6 @@ @implementation RCTRootView
   RCTBridge *_bridge;
   NSString *_moduleName;
   NSDictionary *_launchOptions;
-  NSDictionary *_initialProperties;
   RCTRootContentView *_contentView;
 }
 
@@ -71,7 +70,6 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
 
     _bridge = bridge;
     _moduleName = moduleName;
-    _initialProperties = [initialProperties copy];
     _appProperties = [initialProperties copy];
     _loadingViewFadeDelay = 0.25;
     _loadingViewFadeDuration = 0.25;
@@ -214,12 +212,6 @@ - (void)layoutSubviews
   };
 }
 
-- (NSDictionary *)initialProperties
-{
-  RCTLogWarn(@"Using deprecated 'initialProperties' property. Use 'appProperties' instead.");
-  return _initialProperties;
-}
-
 - (void)setAppProperties:(NSDictionary *)appProperties
 {
   RCTAssertMainThread();

From 4b6b71664ecdb9a7888bf45f46f673bcce613579 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 26 Nov 2015 05:39:28 -0800
Subject: [PATCH 0123/1411] Fix buck error

Reviewed By: idevelop

Differential Revision: D2699529

fb-gh-sync-id: d71a5abf04b767a58dd6f054a88a8bf0c561aa8d
---
 Libraries/Components/MapView/MapView.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/Libraries/Components/MapView/MapView.js b/Libraries/Components/MapView/MapView.js
index 26cd3f61ee62..b0468e1877c3 100644
--- a/Libraries/Components/MapView/MapView.js
+++ b/Libraries/Components/MapView/MapView.js
@@ -14,8 +14,8 @@
 var EdgeInsetsPropType = require('EdgeInsetsPropType');
 var Image = require('Image');
 var NativeMethodsMixin = require('NativeMethodsMixin');
-var PinColors = require('NativeModules').UIManager.RCTMap.Constants.PinColors;
 var Platform = require('Platform');
+var RCTMapConstants = require('NativeModules').UIManager.RCTMap.Constants;
 var React = require('React');
 var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
 var View = require('View');
@@ -320,6 +320,7 @@ var MapView = React.createClass({
  * `annotation.tintColor` property. You are not obliged to use these,
  * but they are useful for matching the standard iOS look and feel.
  */
+let PinColors = RCTMapConstants && RCTMapConstants.PinColors;
 MapView.PinColors = PinColors && {
   RED: PinColors.RED,
   GREEN: PinColors.GREEN,

From 977a40ed04209fc7f792de9bb989df353873cfe8 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Thu, 26 Nov 2015 05:33:38 -0800
Subject: [PATCH 0124/1411] =?UTF-8?q?Don=E2=80=99t=20error=20for=20known?=
 =?UTF-8?q?=20files=20that=20are=20reported=20as=20=E2=80=9Cadded=E2=80=9D?=
 =?UTF-8?q?=20by=20watchman?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Reviewed By: tadeuzagallo

Differential Revision: D2696636

fb-gh-sync-id: 89f90aba2a22d9c3e93632df4c4bc01791525833
---
 .../DependencyGraph/HasteMap.js               |  6 ++--
 .../__tests__/DependencyGraph-test.js         | 30 +++++++++++++++++++
 2 files changed, 33 insertions(+), 3 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/HasteMap.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/HasteMap.js
index e1626fef8067..38d27e3e3b66 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/HasteMap.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/HasteMap.js
@@ -7,7 +7,6 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  */
 'use strict';
-
 const path = require('path');
 const getPlatformExtension = require('../lib/getPlatformExtension');
 const Promise = require('promise');
@@ -118,11 +117,12 @@ class HasteMap {
 
     const moduleMap = this._map[name];
     const modulePlatform = getPlatformExtension(mod.path) || GENERIC_PLATFORM;
+    const existingModule = moduleMap[modulePlatform];
 
-    if (moduleMap[modulePlatform]) {
+    if (existingModule && existingModule.path !== mod.path) {
       throw new Error(
         `Naming collision detected: ${mod.path} ` +
-        `collides with ${moduleMap[modulePlatform].path}`
+        `collides with ${existingModule.path}`
       );
     }
 
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
index a89ce97aa064..d830cc825dda 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
@@ -3821,6 +3821,36 @@ describe('DependencyGraph', function() {
         });
       });
     });
+
+    pit('should not error when the watcher reports a known file as added', function() {
+      var root = '/root';
+      fs.__setMockFilesystem({
+        'root': {
+          'index.js': [
+            '/**',
+            ' * @providesModule index',
+            ' */',
+            'var b = require("b");',
+          ].join('\n'),
+          'b.js': [
+            '/**',
+            ' * @providesModule b',
+            ' */',
+            'module.exports = function() {};',
+          ].join('\n'),
+        },
+      });
+
+      var dgraph = new DependencyGraph({
+        ...defaults,
+        roots: [root],
+      });
+
+      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function() {
+        triggerFileChange('add', 'index.js', root, mockStat);
+        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js');
+      });
+    });
   });
 
   describe('getAsyncDependencies', () => {

From a7e2059c152a2aef52b3071256e1376f28f205dd Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Thu, 26 Nov 2015 06:38:11 -0800
Subject: [PATCH 0125/1411] Fix class pair register on reload

Summary: public

It was possible after reload to detach from the new instance, removing the markers.

Reviewed By: jspahrsummers

Differential Revision: D2696208

fb-gh-sync-id: ad8f5d449f51c7c74a20ae7c0cafc4fc786ea390
---
 React/Profiler/RCTProfile.m | 16 +++++-----------
 1 file changed, 5 insertions(+), 11 deletions(-)

diff --git a/React/Profiler/RCTProfile.m b/React/Profiler/RCTProfile.m
index fe93b658050e..f311a35045d6 100644
--- a/React/Profiler/RCTProfile.m
+++ b/React/Profiler/RCTProfile.m
@@ -48,7 +48,6 @@ - (void)dispatchBlock:(dispatch_block_t)block
 // This is actually a BOOL - but has to be compatible with OSAtomic
 static volatile uint32_t RCTProfileProfiling;
 
-static BOOL RCTProfileHookedModules;
 static NSDictionary *RCTProfileInfo;
 static NSMutableDictionary *RCTProfileOngoingEvents;
 static NSTimeInterval RCTProfileStartTime;
@@ -210,19 +209,21 @@ void RCTProfileHookModules(RCTBridge *bridge)
 {
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wtautological-pointer-compare"
-  if (RCTProfileTrampoline == NULL || RCTProfileHookedModules) {
+  if (RCTProfileTrampoline == NULL) {
     return;
   }
 #pragma clang diagnostic pop
 
-  RCTProfileHookedModules = YES;
-
   for (RCTModuleData *moduleData in [bridge valueForKey:@"moduleDataByID"]) {
     [bridge dispatchBlock:^{
       Class moduleClass = moduleData.moduleClass;
       Class proxyClass = objc_allocateClassPair(moduleClass, RCTProfileProxyClassName(moduleClass), 0);
 
       if (!proxyClass) {
+        proxyClass = objc_getClass(RCTProfileProxyClassName(moduleClass));
+        if (proxyClass) {
+          object_setClass(moduleData.instance, proxyClass);
+        }
         return;
       }
 
@@ -255,19 +256,12 @@ void RCTProfileHookModules(RCTBridge *bridge)
 
 void RCTProfileUnhookModules(RCTBridge *bridge)
 {
-  if (!RCTProfileHookedModules) {
-    return;
-  }
-
-  RCTProfileHookedModules = NO;
-
   dispatch_group_enter(RCTProfileGetUnhookGroup());
 
   for (RCTModuleData *moduleData in [bridge valueForKey:@"moduleDataByID"]) {
     Class proxyClass = object_getClass(moduleData.instance);
     if (moduleData.moduleClass != proxyClass) {
       object_setClass(moduleData.instance, moduleData.moduleClass);
-      objc_disposeClassPair(proxyClass);
     }
   }
 

From c0f60d201839ce8ec572afb4da164c4773fd94e1 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Thu, 26 Nov 2015 07:25:54 -0800
Subject: [PATCH 0126/1411] Moved React Native Android unit tests to open
 source

Reviewed By: mkonicek

Differential Revision: D2685799

fb-gh-sync-id: 56f061df58641c8cb13fc16bad5f87039f0c49fb
---
 .../react/bridge/CatalystTestHelper.java      |  64 +++
 .../facebook/react/bridge/SimpleArray.java    | 145 ++++++
 .../com/facebook/react/bridge/SimpleMap.java  | 168 +++++++
 .../modules/network/NetworkingModuleTest.java | 466 ++++++++++++++++++
 .../storage/AsyncStorageModuleTest.java       | 352 +++++++++++++
 .../modules/timing/TimingModuleTest.java      | 180 +++++++
 6 files changed, 1375 insertions(+)
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/bridge/CatalystTestHelper.java
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/bridge/SimpleArray.java
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/bridge/SimpleMap.java
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkingModuleTest.java
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/modules/storage/AsyncStorageModuleTest.java
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java

diff --git a/ReactAndroid/src/test/java/com/facebook/react/bridge/CatalystTestHelper.java b/ReactAndroid/src/test/java/com/facebook/react/bridge/CatalystTestHelper.java
new file mode 100644
index 000000000000..27a1b7a9fee7
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/bridge/CatalystTestHelper.java
@@ -0,0 +1,64 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.bridge;
+
+import com.facebook.react.bridge.queue.CatalystQueueConfiguration;
+import com.facebook.react.bridge.queue.CatalystQueueConfigurationImpl;
+import com.facebook.react.bridge.queue.CatalystQueueConfigurationSpec;
+import com.facebook.react.bridge.queue.MessageQueueThreadSpec;
+import com.facebook.react.bridge.queue.QueueThreadExceptionHandler;
+import com.facebook.react.uimanager.UIManagerModule;
+
+import org.robolectric.RuntimeEnvironment;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Utility for creating pre-configured instances of core react components for tests.
+ */
+public class CatalystTestHelper {
+
+  /**
+   * @return a ReactApplicationContext that has a CatalystInstance mock returned by
+   * {@link #createMockCatalystInstance}
+   */
+  public static ReactApplicationContext createCatalystContextForTest() {
+    ReactApplicationContext context =
+        new ReactApplicationContext(RuntimeEnvironment.application);
+    context.initializeWithInstance(createMockCatalystInstance());
+    return context;
+  }
+
+  /**
+   * @return a CatalystInstance mock that has a default working CatalystQueueConfiguration.
+   */
+  public static CatalystInstance createMockCatalystInstance() {
+    CatalystQueueConfigurationSpec spec = CatalystQueueConfigurationSpec.builder()
+        .setJSQueueThreadSpec(MessageQueueThreadSpec.mainThreadSpec())
+        .setNativeModulesQueueThreadSpec(MessageQueueThreadSpec.mainThreadSpec())
+        .build();
+    CatalystQueueConfiguration catalystQueueConfiguration = CatalystQueueConfigurationImpl.create(
+        spec,
+        new QueueThreadExceptionHandler() {
+          @Override
+          public void handleException(Exception e) {
+            throw new RuntimeException(e);
+          }
+        });
+
+    CatalystInstance reactInstance = mock(CatalystInstance.class);
+    when(reactInstance.getCatalystQueueConfiguration()).thenReturn(catalystQueueConfiguration);
+    when(reactInstance.getNativeModule(UIManagerModule.class))
+        .thenReturn(mock(UIManagerModule.class));
+
+    return reactInstance;
+  }
+}
diff --git a/ReactAndroid/src/test/java/com/facebook/react/bridge/SimpleArray.java b/ReactAndroid/src/test/java/com/facebook/react/bridge/SimpleArray.java
new file mode 100644
index 000000000000..15656bde422e
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/bridge/SimpleArray.java
@@ -0,0 +1,145 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.bridge;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A simple read/write array that can be used in tests in place of {@link WritableNativeArray}.
+ */
+public class SimpleArray implements ReadableArray, WritableArray {
+
+  private final List mBackingList;
+
+  public static SimpleArray from(List list) {
+    return new SimpleArray(list);
+  }
+
+  public static SimpleArray of(Object... values) {
+    return new SimpleArray(values);
+  }
+
+  private SimpleArray(Object... values) {
+    mBackingList = Arrays.asList(values);
+  }
+
+  private SimpleArray(List list) {
+    mBackingList = new ArrayList(list);
+  }
+
+  public SimpleArray() {
+    mBackingList = new ArrayList();
+  }
+
+  @Override
+  public int size() {
+    return mBackingList.size();
+  }
+
+  @Override
+  public boolean isNull(int index) {
+    return mBackingList.get(index) == null;
+  }
+
+  @Override
+  public double getDouble(int index) {
+    return (Double) mBackingList.get(index);
+  }
+
+  @Override
+  public int getInt(int index) {
+    return (Integer) mBackingList.get(index);
+  }
+
+  @Override
+  public String getString(int index) {
+    return (String) mBackingList.get(index);
+  }
+
+  @Override
+  public SimpleArray getArray(int index) {
+    return (SimpleArray) mBackingList.get(index);
+  }
+
+  @Override
+  public boolean getBoolean(int index) {
+    return (Boolean) mBackingList.get(index);
+  }
+
+  @Override
+  public SimpleMap getMap(int index) {
+    return (SimpleMap) mBackingList.get(index);
+  }
+
+  @Override
+  public ReadableType getType(int index) {
+    return null;
+  }
+
+  @Override
+  public void pushBoolean(boolean value) {
+    mBackingList.add(value);
+  }
+
+  @Override
+  public void pushDouble(double value) {
+    mBackingList.add(value);
+  }
+
+  @Override
+  public void pushInt(int value) {
+    mBackingList.add(value);
+  }
+
+  @Override
+  public void pushString(String value) {
+    mBackingList.add(value);
+  }
+
+  @Override
+  public void pushArray(WritableArray array) {
+    mBackingList.add(array);
+  }
+
+  @Override
+  public void pushMap(WritableMap map) {
+    mBackingList.add(map);
+  }
+
+  @Override
+  public void pushNull() {
+    mBackingList.add(null);
+  }
+
+  @Override
+  public String toString() {
+    return mBackingList.toString();
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    SimpleArray that = (SimpleArray) o;
+
+    if (mBackingList != null ? !mBackingList.equals(that.mBackingList) : that.mBackingList != null)
+      return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    return mBackingList != null ? mBackingList.hashCode() : 0;
+  }
+}
diff --git a/ReactAndroid/src/test/java/com/facebook/react/bridge/SimpleMap.java b/ReactAndroid/src/test/java/com/facebook/react/bridge/SimpleMap.java
new file mode 100644
index 000000000000..f86f04e8cc62
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/bridge/SimpleMap.java
@@ -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.
+ */
+
+package com.facebook.react.bridge;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * A simple read/write map that can be used in tests in place of {@link WritableNativeMap}.
+ */
+public class SimpleMap implements ReadableMap, WritableMap {
+
+  private final Map mBackingMap;
+
+  public static SimpleMap of(Object... keysAndValues) {
+    return new SimpleMap(keysAndValues);
+  }
+
+  /**
+   * @param keysAndValues keys and values, interleaved
+   */
+  private SimpleMap(Object... keysAndValues) {
+    if (keysAndValues.length % 2 != 0) {
+      throw new IllegalArgumentException("You must provide the same number of keys and values");
+    }
+    mBackingMap = new HashMap();
+    for (int i = 0; i < keysAndValues.length; i += 2) {
+      mBackingMap.put(keysAndValues[i], keysAndValues[i + 1]);
+    }
+  }
+
+  public SimpleMap() {
+    mBackingMap = new HashMap();
+  }
+
+  @Override
+  public boolean hasKey(String name) {
+    return mBackingMap.containsKey(name);
+  }
+
+  @Override
+  public boolean isNull(String name) {
+    return mBackingMap.get(name) == null;
+  }
+
+  @Override
+  public boolean getBoolean(String name) {
+    return (Boolean) mBackingMap.get(name);
+  }
+
+  @Override
+  public double getDouble(String name) {
+    return (Double) mBackingMap.get(name);
+  }
+
+  @Override
+  public int getInt(String name) {
+    return (Integer) mBackingMap.get(name);
+  }
+
+  @Override
+  public String getString(String name) {
+    return (String) mBackingMap.get(name);
+  }
+
+  @Override
+  public SimpleMap getMap(String name) {
+    return (SimpleMap) mBackingMap.get(name);
+  }
+
+  @Override
+  public SimpleArray getArray(String name) {
+    return (SimpleArray) mBackingMap.get(name);
+  }
+
+  @Override
+  public ReadableType getType(String name) {
+    throw new UnsupportedOperationException("Method not implemented");
+  }
+
+  @Override
+  public ReadableMapKeySetIterator keySetIterator() {
+    return new ReadableMapKeySetIterator() {
+      Iterator<String> mIterator = mBackingMap.keySet().iterator();
+
+      @Override
+      public boolean hasNextKey() {
+        return mIterator.hasNext();
+      }
+
+      @Override
+      public String nextKey() {
+        return mIterator.next();
+      }
+    };
+  }
+
+  @Override
+  public void putBoolean(String key, boolean value) {
+    mBackingMap.put(key, value);
+  }
+
+  @Override
+  public void putDouble(String key, double value) {
+    mBackingMap.put(key, value);
+  }
+
+  @Override
+  public void putInt(String key, int value) {
+    mBackingMap.put(key, value);
+  }
+
+  @Override
+  public void putString(String key, String value) {
+    mBackingMap.put(key, value);
+  }
+
+  @Override
+  public void putNull(String key) {
+    mBackingMap.put(key, null);
+  }
+
+  @Override
+  public void putMap(String key, WritableMap value) {
+    mBackingMap.put(key, value);
+  }
+
+  @Override
+  public void merge(ReadableMap source) {
+    mBackingMap.putAll(((SimpleMap) source).mBackingMap);
+  }
+
+  @Override
+  public void putArray(String key, WritableArray value) {
+    mBackingMap.put(key, value);
+  }
+
+  @Override
+  public String toString() {
+    return mBackingMap.toString();
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    SimpleMap that = (SimpleMap) o;
+
+    if (mBackingMap != null ? !mBackingMap.equals(that.mBackingMap) : that.mBackingMap != null)
+      return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    return mBackingMap != null ? mBackingMap.hashCode() : 0;
+  }
+}
diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkingModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkingModuleTest.java
new file mode 100644
index 000000000000..454a3cb986af
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkingModuleTest.java
@@ -0,0 +1,466 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.modules.network;
+
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.List;
+
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.SimpleArray;
+import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.bridge.WritableArray;
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter;
+
+import com.squareup.okhttp.Call;
+import com.squareup.okhttp.Headers;
+import com.squareup.okhttp.MediaType;
+import com.squareup.okhttp.MultipartBuilder;
+import com.squareup.okhttp.OkHttpClient;
+import com.squareup.okhttp.Request;
+import com.squareup.okhttp.RequestBody;
+import okio.Buffer;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.modules.junit4.rule.PowerMockRule;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for {@link NetworkingModule}.
+ */
+@PrepareForTest({
+    Arguments.class,
+    Call.class,
+    RequestBodyUtil.class,
+    MultipartBuilder.class,
+    NetworkingModule.class,
+    OkHttpClient.class})
+@RunWith(RobolectricTestRunner.class)
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+public class NetworkingModuleTest {
+
+  @Rule
+  public PowerMockRule rule = new PowerMockRule();
+
+  @Test
+  public void testGetWithoutHeaders() throws Exception {
+    OkHttpClient httpClient = mock(OkHttpClient.class);
+    when(httpClient.newCall(any(Request.class))).thenAnswer(new Answer<Object>() {
+      @Override
+      public Object answer(InvocationOnMock invocation) throws Throwable {
+        Call callMock = mock(Call.class);
+        return callMock;
+      }
+    });
+
+    NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient);
+
+    networkingModule.sendRequest(
+        "GET",
+        "http://somedomain/foo",
+        0,
+        SimpleArray.of(),
+        null,
+        true);
+
+    ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
+    verify(httpClient).newCall(argumentCaptor.capture());
+    assertThat(argumentCaptor.getValue().urlString()).isEqualTo("http://somedomain/foo");
+    // We set the User-Agent header by default
+    assertThat(argumentCaptor.getValue().headers().size()).isEqualTo(1);
+    assertThat(argumentCaptor.getValue().method()).isEqualTo("GET");
+  }
+
+  @Test
+  public void testFailGetWithInvalidHeadersStruct() throws Exception {
+    RCTDeviceEventEmitter emitter = mock(RCTDeviceEventEmitter.class);
+    ReactApplicationContext context = mock(ReactApplicationContext.class);
+    when(context.getJSModule(any(Class.class))).thenReturn(emitter);
+
+    OkHttpClient httpClient = mock(OkHttpClient.class);
+    NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient);
+
+    List<SimpleArray> invalidHeaders = Arrays.asList(SimpleArray.of("foo"));
+
+    mockEvents();
+
+    networkingModule.sendRequest(
+        "GET",
+        "http://somedoman/foo",
+        0,
+        SimpleArray.from(invalidHeaders),
+        null,
+        true);
+
+    verifyErrorEmit(emitter, 0);
+  }
+
+  @Test
+  public void testFailPostWithoutContentType() throws Exception {
+    RCTDeviceEventEmitter emitter = mock(RCTDeviceEventEmitter.class);
+    ReactApplicationContext context = mock(ReactApplicationContext.class);
+    when(context.getJSModule(any(Class.class))).thenReturn(emitter);
+
+    OkHttpClient httpClient = mock(OkHttpClient.class);
+    NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient);
+
+    SimpleMap body = new SimpleMap();
+    body.putString("string", "This is request body");
+
+    mockEvents();
+
+    networkingModule.sendRequest(
+        "POST",
+        "http://somedomain/bar",
+        0,
+        SimpleArray.of(),
+        body,
+        true);
+
+    verifyErrorEmit(emitter, 0);
+  }
+
+  private static void verifyErrorEmit(RCTDeviceEventEmitter emitter, int requestId) {
+    ArgumentCaptor<WritableArray> captor = ArgumentCaptor.forClass(WritableArray.class);
+    verify(emitter).emit(eq("didCompleteNetworkResponse"), captor.capture());
+
+    WritableArray array = captor.getValue();
+    assertThat(array.getInt(0)).isEqualTo(requestId);
+    assertThat(array.getString(1)).isNotNull();
+  }
+
+  private static void mockEvents() {
+    PowerMockito.mockStatic(Arguments.class);
+    Mockito.when(Arguments.createArray()).thenAnswer(
+        new Answer<WritableArray>() {
+          @Override
+          public WritableArray answer(InvocationOnMock invocation) throws Throwable {
+            return new SimpleArray();
+          }
+        });
+
+    Mockito.when(Arguments.createMap()).thenAnswer(
+        new Answer<WritableMap>() {
+          @Override
+          public WritableMap answer(InvocationOnMock invocation) throws Throwable {
+            return new SimpleMap();
+          }
+        });
+  }
+
+  @Test
+  public void testSuccessfullPostRequest() throws Exception {
+    OkHttpClient httpClient = mock(OkHttpClient.class);
+    when(httpClient.newCall(any(Request.class))).thenAnswer(new Answer<Object>() {
+          @Override
+          public Object answer(InvocationOnMock invocation) throws Throwable {
+            Call callMock = mock(Call.class);
+            return callMock;
+          }
+        });
+
+    NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient);
+
+    SimpleMap body = new SimpleMap();
+    body.putString("string", "This is request body");
+
+    networkingModule.sendRequest(
+        "POST",
+        "http://somedomain/bar",
+        0,
+        SimpleArray.of(SimpleArray.of("Content-Type", "text/plain")),
+        body,
+        true);
+
+    ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
+    verify(httpClient).newCall(argumentCaptor.capture());
+    assertThat(argumentCaptor.getValue().urlString()).isEqualTo("http://somedomain/bar");
+    assertThat(argumentCaptor.getValue().headers().size()).isEqualTo(2);
+    assertThat(argumentCaptor.getValue().method()).isEqualTo("POST");
+    assertThat(argumentCaptor.getValue().body().contentType().type()).isEqualTo("text");
+    assertThat(argumentCaptor.getValue().body().contentType().subtype()).isEqualTo("plain");
+    Buffer contentBuffer = new Buffer();
+    argumentCaptor.getValue().body().writeTo(contentBuffer);
+    assertThat(contentBuffer.readUtf8()).isEqualTo("This is request body");
+  }
+
+  @Test
+  public void testHeaders() throws Exception {
+    OkHttpClient httpClient = mock(OkHttpClient.class);
+    when(httpClient.newCall(any(Request.class))).thenAnswer(new Answer<Object>() {
+      @Override
+      public Object answer(InvocationOnMock invocation) throws Throwable {
+        Call callMock = mock(Call.class);
+        return callMock;
+      }
+    });
+    NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient);
+
+    List<SimpleArray> headers = Arrays.asList(
+        SimpleArray.of("Accept", "text/plain"),
+        SimpleArray.of("User-Agent", "React test agent/1.0"));
+
+    networkingModule.sendRequest(
+        "GET",
+        "http://someurl/baz",
+        0,
+        SimpleArray.from(headers),
+        null,
+        true);
+    ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
+    verify(httpClient).newCall(argumentCaptor.capture());
+    Headers requestHeaders = argumentCaptor.getValue().headers();
+    assertThat(requestHeaders.size()).isEqualTo(2);
+    assertThat(requestHeaders.get("Accept")).isEqualTo("text/plain");
+    assertThat(requestHeaders.get("User-Agent")).isEqualTo("React test agent/1.0");
+  }
+
+  @Test
+  public void testMultipartPostRequestSimple() throws Exception {
+    PowerMockito.mockStatic(RequestBodyUtil.class);
+    when(RequestBodyUtil.getFileInputStream(any(ReactContext.class), any(String.class)))
+        .thenReturn(mock(InputStream.class));
+    when(RequestBodyUtil.create(any(MediaType.class), any(InputStream.class)))
+        .thenReturn(mock(RequestBody.class));
+
+    SimpleMap body = new SimpleMap();
+    SimpleArray formData = new SimpleArray();
+    SimpleMap bodyPart = new SimpleMap();
+    bodyPart.putString("string", "value");
+    bodyPart.putArray(
+        "headers",
+        SimpleArray.from(
+            Arrays.asList(
+                SimpleArray.of("content-disposition", "name"))));
+    formData.pushMap(bodyPart);
+    body.putArray("formData", formData);
+
+    OkHttpClient httpClient = mock(OkHttpClient.class);
+    when(httpClient.newCall(any(Request.class))).thenAnswer(
+        new Answer<Object>() {
+          @Override
+          public Object answer(InvocationOnMock invocation) throws Throwable {
+            Call callMock = mock(Call.class);
+            return callMock;
+          }
+        });
+
+    NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient);
+    networkingModule.sendRequest(
+        "POST",
+        "http://someurl/uploadFoo",
+        0,
+        new SimpleArray(),
+        body,
+        true);
+
+    // verify url, method, headers
+    ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
+    verify(httpClient).newCall(argumentCaptor.capture());
+    assertThat(argumentCaptor.getValue().urlString()).isEqualTo("http://someurl/uploadFoo");
+    assertThat(argumentCaptor.getValue().method()).isEqualTo("POST");
+    assertThat(argumentCaptor.getValue().body().contentType().type()).
+        isEqualTo(MultipartBuilder.FORM.type());
+    assertThat(argumentCaptor.getValue().body().contentType().subtype()).
+        isEqualTo(MultipartBuilder.FORM.subtype());
+    Headers requestHeaders = argumentCaptor.getValue().headers();
+    assertThat(requestHeaders.size()).isEqualTo(1);
+  }
+
+  @Test
+  public void testMultipartPostRequestHeaders() throws Exception {
+    PowerMockito.mockStatic(RequestBodyUtil.class);
+    when(RequestBodyUtil.getFileInputStream(any(ReactContext.class), any(String.class)))
+        .thenReturn(mock(InputStream.class));
+    when(RequestBodyUtil.create(any(MediaType.class), any(InputStream.class)))
+        .thenReturn(mock(RequestBody.class));
+
+    List<SimpleArray> headers = Arrays.asList(
+            SimpleArray.of("Accept", "text/plain"),
+            SimpleArray.of("User-Agent", "React test agent/1.0"),
+            SimpleArray.of("content-type", "multipart/form-data"));
+
+    SimpleMap body = new SimpleMap();
+    SimpleArray formData = new SimpleArray();
+    SimpleMap bodyPart = new SimpleMap();
+    bodyPart.putString("string", "value");
+    bodyPart.putArray(
+        "headers",
+        SimpleArray.from(
+            Arrays.asList(
+                SimpleArray.of("content-disposition", "name"))));
+    formData.pushMap(bodyPart);
+    body.putArray("formData", formData);
+
+    OkHttpClient httpClient = mock(OkHttpClient.class);
+    when(httpClient.newCall(any(Request.class))).thenAnswer(
+        new Answer<Object>() {
+          @Override
+          public Object answer(InvocationOnMock invocation) throws Throwable {
+            Call callMock = mock(Call.class);
+            return callMock;
+          }
+        });
+
+    NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient);
+    networkingModule.sendRequest(
+        "POST",
+        "http://someurl/uploadFoo",
+        0,
+        SimpleArray.from(headers),
+        body,
+        true);
+
+    // verify url, method, headers
+    ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
+    verify(httpClient).newCall(argumentCaptor.capture());
+    assertThat(argumentCaptor.getValue().urlString()).isEqualTo("http://someurl/uploadFoo");
+    assertThat(argumentCaptor.getValue().method()).isEqualTo("POST");
+    assertThat(argumentCaptor.getValue().body().contentType().type()).
+        isEqualTo(MultipartBuilder.FORM.type());
+    assertThat(argumentCaptor.getValue().body().contentType().subtype()).
+        isEqualTo(MultipartBuilder.FORM.subtype());
+    Headers requestHeaders = argumentCaptor.getValue().headers();
+    assertThat(requestHeaders.size()).isEqualTo(3);
+    assertThat(requestHeaders.get("Accept")).isEqualTo("text/plain");
+    assertThat(requestHeaders.get("User-Agent")).isEqualTo("React test agent/1.0");
+    assertThat(requestHeaders.get("content-type")).isEqualTo("multipart/form-data");
+  }
+
+  @Test
+  public void testMultipartPostRequestBody() throws Exception {
+    InputStream inputStream = mock(InputStream.class);
+    PowerMockito.mockStatic(RequestBodyUtil.class);
+    when(RequestBodyUtil.getFileInputStream(any(ReactContext.class), any(String.class)))
+        .thenReturn(inputStream);
+    when(RequestBodyUtil.create(any(MediaType.class), any(InputStream.class))).thenCallRealMethod();
+    when(inputStream.available()).thenReturn("imageUri".length());
+
+    final MultipartBuilder multipartBuilder = mock(MultipartBuilder.class);
+    PowerMockito.whenNew(MultipartBuilder.class).withNoArguments().thenReturn(multipartBuilder);
+    when(multipartBuilder.type(any(MediaType.class))).thenAnswer(
+        new Answer<Object>() {
+          @Override
+          public Object answer(InvocationOnMock invocation) throws Throwable {
+            return multipartBuilder;
+          }
+        });
+    when(multipartBuilder.addPart(any(Headers.class), any(RequestBody.class))).thenAnswer(
+        new Answer<Object>() {
+          @Override
+          public Object answer(InvocationOnMock invocation) throws Throwable {
+            return multipartBuilder;
+          }
+        });
+    when(multipartBuilder.build()).thenAnswer(
+        new Answer<Object>() {
+          @Override
+          public Object answer(InvocationOnMock invocation) throws Throwable {
+            return mock(RequestBody.class);
+          }
+        });
+
+    List<SimpleArray> headers = Arrays.asList(
+            SimpleArray.of("content-type", "multipart/form-data"));
+
+    SimpleMap body = new SimpleMap();
+    SimpleArray formData = new SimpleArray();
+    body.putArray("formData", formData);
+
+    SimpleMap bodyPart = new SimpleMap();
+    bodyPart.putString("string", "locale");
+    bodyPart.putArray(
+        "headers",
+        SimpleArray.from(
+            Arrays.asList(
+                          SimpleArray.of("content-disposition", "user"))));
+    formData.pushMap(bodyPart);
+
+    SimpleMap imageBodyPart = new SimpleMap();
+    imageBodyPart.putString("uri", "imageUri");
+    imageBodyPart.putArray(
+        "headers",
+        SimpleArray.from(
+            Arrays.asList(
+                SimpleArray.of("content-type", "image/jpg"),
+                SimpleArray.of("content-disposition", "filename=photo.jpg"))));
+    formData.pushMap(imageBodyPart);
+
+    OkHttpClient httpClient = mock(OkHttpClient.class);
+    when(httpClient.newCall(any(Request.class))).thenAnswer(
+        new Answer<Object>() {
+          @Override
+          public Object answer(InvocationOnMock invocation) throws Throwable {
+            Call callMock = mock(Call.class);
+            return callMock;
+          }
+        });
+
+    NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient);
+    networkingModule.sendRequest(
+        "POST",
+        "http://someurl/uploadFoo",
+        0,
+        SimpleArray.from(headers),
+        body,
+        true);
+
+    // verify RequestBodyPart for image
+    PowerMockito.verifyStatic(times(1));
+    RequestBodyUtil.getFileInputStream(any(ReactContext.class), eq("imageUri"));
+    PowerMockito.verifyStatic(times(1));
+    RequestBodyUtil.create(MediaType.parse("image/jpg"), inputStream);
+
+    // verify body
+    verify(multipartBuilder).build();
+    verify(multipartBuilder).type(MultipartBuilder.FORM);
+    ArgumentCaptor<Headers> headersArgumentCaptor = ArgumentCaptor.forClass(Headers.class);
+    ArgumentCaptor<RequestBody> bodyArgumentCaptor = ArgumentCaptor.forClass(RequestBody.class);
+    verify(multipartBuilder, times(2)).
+        addPart(headersArgumentCaptor.capture(), bodyArgumentCaptor.capture());
+
+    List<Headers> bodyHeaders = headersArgumentCaptor.getAllValues();
+    assertThat(bodyHeaders.size()).isEqualTo(2);
+    List<RequestBody> bodyRequestBody = bodyArgumentCaptor.getAllValues();
+    assertThat(bodyRequestBody.size()).isEqualTo(2);
+
+    assertThat(bodyHeaders.get(0).get("content-disposition")).isEqualTo("user");
+    assertThat(bodyRequestBody.get(0).contentType()).isNull();
+    assertThat(bodyRequestBody.get(0).contentLength()).isEqualTo("locale".getBytes().length);
+    assertThat(bodyHeaders.get(1).get("content-disposition")).isEqualTo("filename=photo.jpg");
+    assertThat(bodyRequestBody.get(1).contentType()).isEqualTo(MediaType.parse("image/jpg"));
+    assertThat(bodyRequestBody.get(1).contentLength()).isEqualTo("imageUri".getBytes().length);
+  }
+}
diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/storage/AsyncStorageModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/storage/AsyncStorageModuleTest.java
new file mode 100644
index 000000000000..bd7076fc9258
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/modules/storage/AsyncStorageModuleTest.java
@@ -0,0 +1,352 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.modules.storage;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.ContextWrapper;
+
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.Callback;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.SimpleArray;
+import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.modules.storage.AsyncStorageModule;
+import com.facebook.react.modules.storage.ReactDatabaseSupplier;
+
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.modules.junit4.rule.PowerMockRule;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import static org.mockito.Mockito.mock;
+import static org.fest.assertions.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link AsyncStorageModule}.
+ */
+@PrepareForTest({Arguments.class})
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+@RunWith(RobolectricTestRunner.class)
+public class AsyncStorageModuleTest {
+
+  private AsyncStorageModule mStorage;
+  private SimpleArray mEmptyArray;
+
+  private static class FakeFragmentContext extends ContextWrapper {
+
+    public FakeFragmentContext(Context base) {
+      super(base);
+    }
+  }
+
+  @Rule
+  public PowerMockRule rule = new PowerMockRule();
+
+  @Before
+  public void prepareModules() {
+    PowerMockito.mockStatic(Arguments.class);
+    Mockito.when(Arguments.createArray()).thenAnswer(
+        new Answer<Object>() {
+     @Override
+     public Object answer(InvocationOnMock invocation) throws Throwable {
+       return new SimpleArray();
+     }
+   });
+
+    Mockito.when(Arguments.createMap()).thenAnswer(
+        new Answer<Object>() {
+       @Override
+       public Object answer(InvocationOnMock invocation) throws Throwable {
+         return new SimpleMap();
+       }
+     });
+
+    // don't use Robolectric before initializing mocks
+    mStorage = new AsyncStorageModule(new ReactApplicationContext(
+      new FakeFragmentContext(RuntimeEnvironment.application)));
+    mEmptyArray = new SimpleArray();
+  }
+
+  @After
+  public void cleanUp() {
+    RuntimeEnvironment.application.deleteDatabase(ReactDatabaseSupplier.DATABASE_NAME);
+    ReactDatabaseSupplier.deleteInstance();
+  }
+
+  @Test
+  public void testMultiSetMultiGet() {
+    final String key1 = "foo1";
+    final String key2 = "foo2";
+    final String fakeKey = "fakeKey";
+    final String value1 = "bar1";
+    final String value2 = "bar2";
+    SimpleArray keyValues = new SimpleArray();
+    keyValues.pushArray(getArray(key1, value1));
+    keyValues.pushArray(getArray(key2, value2));
+
+    Callback setCallback = mock(Callback.class);
+    mStorage.multiSet(keyValues, setCallback);
+    Mockito.verify(setCallback, Mockito.times(1)).invoke();
+
+    SimpleArray keys = new SimpleArray();
+    keys.pushString(key1);
+    keys.pushString(key2);
+
+    Callback getCallback = mock(Callback.class);
+    mStorage.multiGet(keys, getCallback);
+    Mockito.verify(getCallback, Mockito.times(1)).invoke(null, keyValues);
+
+    keys.pushString(fakeKey);
+    SimpleArray row3 = new SimpleArray();
+    row3.pushString(fakeKey);
+    row3.pushString(null);
+    keyValues.pushArray(row3);
+
+    Callback getCallback2 = mock(Callback.class);
+    mStorage.multiGet(keys, getCallback2);
+    Mockito.verify(getCallback2, Mockito.times(1)).invoke(null, keyValues);
+  }
+
+  @Test
+  public void testMultiRemove() {
+    final String key1 = "foo1";
+    final String key2 = "foo2";
+    final String value1 = "bar1";
+    final String value2 = "bar2";
+
+    SimpleArray keyValues = new SimpleArray();
+    keyValues.pushArray(getArray(key1, value1));
+    keyValues.pushArray(getArray(key2, value2));
+    mStorage.multiSet(keyValues, mock(Callback.class));
+
+    SimpleArray keys = new SimpleArray();
+    keys.pushString(key1);
+    keys.pushString(key2);
+
+    Callback getCallback = mock(Callback.class);
+    mStorage.multiRemove(keys, getCallback);
+    Mockito.verify(getCallback, Mockito.times(1)).invoke();
+
+    Callback getAllCallback = mock(Callback.class);
+    mStorage.getAllKeys(getAllCallback);
+    Mockito.verify(getAllCallback, Mockito.times(1)).invoke(null, mEmptyArray);
+
+    mStorage.multiSet(keyValues, mock(Callback.class));
+
+    keys.pushString("fakeKey");
+    Callback getCallback2 = mock(Callback.class);
+    mStorage.multiRemove(keys, getCallback2);
+    Mockito.verify(getCallback2, Mockito.times(1)).invoke();
+
+    Callback getAllCallback2 = mock(Callback.class);
+    mStorage.getAllKeys(getAllCallback2);
+    Mockito.verify(getAllCallback2, Mockito.times(1)).invoke(null, mEmptyArray);
+  }
+
+  @Test
+  public void testMultiMerge() throws Exception {
+    final String mergeKey = "mergeTest";
+
+    JSONObject value = new JSONObject();
+    value.put("foo1", "bar1");
+    value.put("foo2", createJSONArray("val1", "val2", 3));
+    value.put("foo3", 1001);
+    value.put("foo4", createJSONObject("key1", "randomValueThatWillNeverBeUsed"));
+
+    mStorage.multiSet(SimpleArray.of(getArray(mergeKey, value.toString())), mock(Callback.class));
+    {
+      Callback callback = mock(Callback.class);
+      mStorage.multiGet(getArray(mergeKey), callback);
+      Mockito.verify(callback, Mockito.times(1))
+          .invoke(null, SimpleArray.of(getArray(mergeKey, value.toString())));
+    }
+
+    value.put("foo1", 1001);
+    value.put("foo2", createJSONObject("key1", "val1"));
+    value.put("foo3", "bar1");
+    value.put("foo4", createJSONArray("val1", "val2", 3));
+
+    JSONObject newValue = new JSONObject();
+    newValue.put("foo2", createJSONObject("key2", "val2"));
+
+    JSONObject newValue2 = new JSONObject();
+    newValue2.put("foo2", createJSONObject("key1", "val3"));
+
+    mStorage.multiMerge(
+        SimpleArray.of(
+            SimpleArray.of(mergeKey, value.toString()),
+            SimpleArray.of(mergeKey, newValue.toString()),
+            SimpleArray.of(mergeKey, newValue2.toString())),
+        mock(Callback.class));
+
+    value.put("foo2", createJSONObject("key1", "val3", "key2", "val2"));
+    Callback callback = mock(Callback.class);
+    mStorage.multiGet(getArray(mergeKey), callback);
+    Mockito.verify(callback, Mockito.times(1))
+        .invoke(null, SimpleArray.of(getArray(mergeKey, value.toString())));
+  }
+
+  @Test
+  public void testGetAllKeys() {
+    final String[] keys = {"foo", "foo2"};
+    final String[] values = {"bar", "bar2"};
+    SimpleArray keyValues = new SimpleArray();
+    keyValues.pushArray(getArray(keys[0], values[0]));
+    keyValues.pushArray(getArray(keys[1], values[1]));
+    mStorage.multiSet(keyValues, mock(Callback.class));
+
+    SimpleArray storedKeys = new SimpleArray();
+    storedKeys.pushString(keys[0]);
+    storedKeys.pushString(keys[1]);
+
+    Callback getAllCallback = mock(Callback.class);
+    mStorage.getAllKeys(getAllCallback);
+    Mockito.verify(getAllCallback, Mockito.times(1)).invoke(null, storedKeys);
+
+    Callback getAllCallback2 = mock(Callback.class);
+    mStorage.multiRemove(getArray(keys[0]), mock(Callback.class));
+
+    mStorage.getAllKeys(getAllCallback2);
+    Mockito.verify(getAllCallback2, Mockito.times(1)).invoke(null, getArray(keys[1]));
+
+    mStorage.multiRemove(getArray(keys[1]), mock(Callback.class));
+    Callback getAllCallback3 = mock(Callback.class);
+    mStorage.getAllKeys(getAllCallback3);
+    Mockito.verify(getAllCallback3, Mockito.times(1)).invoke(null, mEmptyArray);
+  }
+
+  @Test
+  public void testClear() {
+    SimpleArray keyValues = new SimpleArray();
+    keyValues.pushArray(getArray("foo", "foo2"));
+    keyValues.pushArray(getArray("bar", "bar2"));
+    mStorage.multiSet(keyValues, mock(Callback.class));
+
+    Callback clearCallback2 = mock(Callback.class);
+    mStorage.clear(clearCallback2);
+    Mockito.verify(clearCallback2, Mockito.times(1)).invoke();
+
+    Callback getAllCallback2 = mock(Callback.class);
+    mStorage.getAllKeys(getAllCallback2);
+    Mockito.verify(getAllCallback2, Mockito.times(1)).invoke(null, mEmptyArray);
+  }
+
+  @Test
+  public void testHugeMultiGetMultiGet() {
+    // Test with many keys, so that it's above the 999 limit per batch imposed by SQLite.
+    final int keyCount = 1001;
+    // don't set keys that divide by this magical number, so that we can check that multiGet works,
+    // and returns null for missing keys
+    final int magicalNumber = 343;
+
+    SimpleArray keyValues = new SimpleArray();
+    for (int i = 0; i < keyCount; i++) {
+      if (i % magicalNumber > 0) {
+        keyValues.pushArray(getArray("key" + i, "value" + i));
+      }
+    }
+    mStorage.multiSet(keyValues, mock(Callback.class));
+    SimpleArray keys = new SimpleArray();
+    for (int i = 0; i < keyCount; i++) {
+      keys.pushString("key" + i);
+    }
+    mStorage.multiGet(
+        keys, new Callback() {
+          @Override
+          public void invoke(Object... args) {
+            assertThat(args.length).isEqualTo(2);
+            SimpleArray resultArray = (SimpleArray) args[1];
+
+            assertThat(resultArray.size()).isEqualTo(keyCount);
+            boolean keyReceived[] = new boolean[keyCount];
+            for (int i = 0; i < keyCount; i++) {
+              String key = resultArray.getArray(i).getString(0).substring(3);
+              int idx = Integer.parseInt(key);
+              assertThat(keyReceived[idx]).isFalse();
+              keyReceived[idx] = true;
+
+              if (idx % magicalNumber > 0) {
+                String value = resultArray.getArray(i).getString(1).substring(5);
+                assertThat(key).isEqualTo(value);
+              } else {
+                assertThat(resultArray.getArray(i).isNull(1));
+              }
+            }
+          }
+        });
+
+    // Test removal in same test, since it's costly to set up the test again.
+    // Remove only odd keys
+    SimpleArray keyRemoves = new SimpleArray();
+    for (int i = 0; i < keyCount; i++) {
+      if (i % 2 > 0) {
+        keyRemoves.pushString("key" + i);
+      }
+    }
+    mStorage.multiRemove(keyRemoves, mock(Callback.class));
+    mStorage.getAllKeys(
+        new Callback() {
+          @Override
+          public void invoke(Object... args) {
+            SimpleArray resultArray = (SimpleArray) args[1];
+            assertThat(resultArray.size()).isEqualTo(499);
+            for (int i = 0; i < resultArray.size(); i++) {
+              String key = resultArray.getString(i).substring(3);
+              int idx = Integer.parseInt(key);
+              assertThat(idx % 2).isEqualTo(0);
+            }
+          }
+        });
+  }
+
+  private static JSONArray createJSONArray(Object... objects) {
+    return new JSONArray(Arrays.asList(objects));
+  }
+
+  private static JSONObject createJSONObject(Object... keysAndValues) {
+    if (keysAndValues.length % 2 != 0) {
+      throw new IllegalArgumentException("You must provide the same number of keys and values");
+    }
+    Map map = new HashMap();
+    for (int i = 0; i < keysAndValues.length; i += 2) {
+      map.put(keysAndValues[i], keysAndValues[i + 1]);
+    }
+    return new JSONObject(map);
+  }
+
+  private SimpleArray getArray(String... values) {
+    SimpleArray array = new SimpleArray();
+    for (String value : values) {
+      array.pushString(value);
+    }
+    return array;
+  }
+}
diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java
new file mode 100644
index 000000000000..0d14cdc43b89
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java
@@ -0,0 +1,180 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.modules.timing;
+
+import android.view.Choreographer;
+
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.CatalystInstance;
+import com.facebook.react.bridge.SimpleArray;
+import com.facebook.react.uimanager.ReactChoreographer;
+import com.facebook.react.common.SystemClock;
+import com.facebook.react.modules.core.JSTimersExecution;
+import com.facebook.react.modules.core.Timing;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.modules.junit4.rule.PowerMockRule;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import static org.mockito.Mockito.*;
+
+/**
+ * Tests for {@link Timing}.
+ */
+@PrepareForTest({Arguments.class, SystemClock.class, ReactChoreographer.class})
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+@RunWith(RobolectricTestRunner.class)
+public class TimingModuleTest {
+
+  private static final long FRAME_TIME_NS = 17 * 1000 * 1000; // 17 ms
+
+  private Timing mTiming;
+  private ReactChoreographer mChoreographerMock;
+  private PostFrameCallbackHandler mPostFrameCallbackHandler;
+  private long mCurrentTimeNs;
+  private JSTimersExecution mJSTimersMock;
+
+  @Rule
+  public PowerMockRule rule = new PowerMockRule();
+
+  @Before
+  public void prepareModules() {
+    PowerMockito.mockStatic(Arguments.class);
+    when(Arguments.createArray()).thenAnswer(
+        new Answer<Object>() {
+          @Override
+          public Object answer(InvocationOnMock invocation) throws Throwable {
+            return new SimpleArray();
+          }
+        });
+
+    PowerMockito.mockStatic(SystemClock.class);
+    when(SystemClock.currentTimeMillis()).thenReturn(mCurrentTimeNs / 1000000);
+    when(SystemClock.nanoTime()).thenReturn(mCurrentTimeNs);
+
+    mChoreographerMock = mock(ReactChoreographer.class);
+    PowerMockito.mockStatic(ReactChoreographer.class);
+    when(ReactChoreographer.getInstance()).thenReturn(mChoreographerMock);
+
+    CatalystInstance catalystInstance = mock(CatalystInstance.class);
+    ReactApplicationContext reactContext = mock(ReactApplicationContext.class);
+    when(reactContext.getCatalystInstance()).thenReturn(catalystInstance);
+
+    mCurrentTimeNs = 0;
+    mPostFrameCallbackHandler = new PostFrameCallbackHandler();
+
+    doAnswer(mPostFrameCallbackHandler)
+        .when(mChoreographerMock)
+        .postFrameCallback(
+            eq(ReactChoreographer.CallbackType.TIMERS_EVENTS),
+            any(Choreographer.FrameCallback.class));
+
+    mTiming = new Timing(reactContext);
+    mJSTimersMock = mock(JSTimersExecution.class);
+    when(catalystInstance.getJSModule(JSTimersExecution.class)).thenReturn(mJSTimersMock);
+    mTiming.initialize();
+  }
+
+  private void stepChoreographerFrame() {
+    Choreographer.FrameCallback callback = mPostFrameCallbackHandler.getAndResetFrameCallback();
+    mCurrentTimeNs += FRAME_TIME_NS;
+    if (callback != null) {
+      callback.doFrame(mCurrentTimeNs);
+    }
+  }
+
+  @Test
+  public void testSimpleTimer() {
+    mTiming.onHostResume();
+    mTiming.createTimer(1, 0, 0, false);
+    stepChoreographerFrame();
+    verify(mJSTimersMock).callTimers(SimpleArray.of(1));
+    reset(mJSTimersMock);
+    stepChoreographerFrame();
+    verifyNoMoreInteractions(mJSTimersMock);
+  }
+
+  @Test
+  public void testSimpleRecurringTimer() {
+    mTiming.createTimer(100, 0, 0, true);
+    mTiming.onHostResume();
+    stepChoreographerFrame();
+    verify(mJSTimersMock).callTimers(SimpleArray.of(100));
+
+    reset(mJSTimersMock);
+    stepChoreographerFrame();
+    verify(mJSTimersMock).callTimers(SimpleArray.of(100));
+  }
+
+  @Test
+  public void testCancelRecurringTimer() {
+    mTiming.onHostResume();
+    mTiming.createTimer(105, 0, 0, true);
+
+    stepChoreographerFrame();
+    verify(mJSTimersMock).callTimers(SimpleArray.of(105));
+
+    reset(mJSTimersMock);
+    mTiming.deleteTimer(105);
+    stepChoreographerFrame();
+    verifyNoMoreInteractions(mJSTimersMock);
+  }
+
+  @Test
+  public void testPausingAndResuming() {
+    mTiming.onHostResume();
+    mTiming.createTimer(41, 0, 0, true);
+
+    stepChoreographerFrame();
+    verify(mJSTimersMock).callTimers(SimpleArray.of(41));
+
+    reset(mJSTimersMock);
+    mTiming.onHostPause();
+    stepChoreographerFrame();
+    verifyNoMoreInteractions(mJSTimersMock);
+
+    reset(mJSTimersMock);
+    mTiming.onHostResume();
+    stepChoreographerFrame();
+    verify(mJSTimersMock).callTimers(SimpleArray.of(41));
+  }
+
+  private static class PostFrameCallbackHandler implements Answer<Void> {
+
+    private Choreographer.FrameCallback mFrameCallback;
+
+    @Override
+    public Void answer(InvocationOnMock invocation) throws Throwable {
+      Object[] args = invocation.getArguments();
+      mFrameCallback = (Choreographer.FrameCallback) args[1];
+      return null;
+    }
+
+    public Choreographer.FrameCallback getAndResetFrameCallback() {
+      Choreographer.FrameCallback callback = mFrameCallback;
+      mFrameCallback = null;
+      return callback;
+    }
+  }
+}

From bb11e05c33ce1910d776eb8dd16f65eb4ad2776e Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Thu, 26 Nov 2015 07:13:16 -0800
Subject: [PATCH 0127/1411] Default empty view to RCTView with position:
 absolute

Reviewed By: spicyj, davidaurelio

Differential Revision: D2693494

fb-gh-sync-id: fc00b995d7d4fdaaedf4c3e5382354f0a1f4ac23
---
 .../ReactNative/ReactNativeDefaultInjection.js | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/Libraries/ReactNative/ReactNativeDefaultInjection.js b/Libraries/ReactNative/ReactNativeDefaultInjection.js
index 3ee1675c31dd..0d55d670c40e 100644
--- a/Libraries/ReactNative/ReactNativeDefaultInjection.js
+++ b/Libraries/ReactNative/ReactNativeDefaultInjection.js
@@ -23,6 +23,7 @@ var EventPluginUtils = require('EventPluginUtils');
 var IOSDefaultEventPluginOrder = require('IOSDefaultEventPluginOrder');
 var IOSNativeBridgeEventPlugin = require('IOSNativeBridgeEventPlugin');
 var NodeHandle = require('NodeHandle');
+var ReactElement = require('ReactElement');
 var ReactComponentEnvironment = require('ReactComponentEnvironment');
 var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy');
 var ReactEmptyComponent = require('ReactEmptyComponent');
@@ -37,7 +38,6 @@ var ReactUpdates = require('ReactUpdates');
 var ResponderEventPlugin = require('ResponderEventPlugin');
 var UniversalWorkerNodeHandle = require('UniversalWorkerNodeHandle');
 
-var createReactNativeComponentClass = require('createReactNativeComponentClass');
 var invariant = require('invariant');
 
 // Just to ensure this gets packaged, since its only caller is from Native.
@@ -81,13 +81,15 @@ function inject() {
     ReactNativeComponentEnvironment
   );
 
-  // Can't import View here because it depends on React to make its composite
-  var RCTView = createReactNativeComponentClass({
-    validAttributes: {},
-    uiViewClassName: 'RCTView',
-  });
-  // TODO #9121531: make this position: absolute; by default, to avoid interfering with flexbox
-  ReactEmptyComponent.injection.injectEmptyComponent(RCTView);
+  var EmptyComponent = () => {
+    // Can't import View at the top because it depends on React to make its composite
+    var View = require('View');
+    return ReactElement.createElement(View, {
+      collapsable: true,
+      style: { position: 'absolute' }
+    });
+  };
+  ReactEmptyComponent.injection.injectEmptyComponent(EmptyComponent);
 
   EventPluginUtils.injection.injectMount(ReactNativeMount);
 

From a636ddd9f07d8d3e6febb2118a7c7a4d225ad129 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Thu, 26 Nov 2015 08:36:02 -0800
Subject: [PATCH 0128/1411] Backout D2677289 [react_native] View recycling in
 JS

Summary: public

We're seeing related crashes. The diff has no tests, the perf tests weren't conclusive, and the person who'd be supporting it no longer is available to work on it. We can try this again later in a less rushed manner with proper perf testing.

Reviewed By: davidaurelio

Differential Revision: D2696615

fb-gh-sync-id: 3b6814ac12af19516146d5c42d2add8321b10db5
---
 .../ReactNative/ReactNativeBaseComponent.js   |  21 +-
 Libraries/ReactNative/ReactNativeMount.js     |   2 -
 .../ReactNativeReconcileTransaction.js        |   9 +-
 Libraries/ReactNative/ReactNativeViewPool.js  | 264 ------------------
 .../uimanager/NativeViewHierarchyManager.java |  15 +-
 .../NativeViewHierarchyOptimizer.java         |   4 -
 .../react/uimanager/UIImplementation.java     |  17 +-
 .../react/uimanager/UIManagerModule.java      |   5 -
 .../uimanager/UIManagerModuleConstants.java   |   8 -
 .../UIManagerModuleConstantsHelper.java       |   2 -
 .../react/uimanager/UIViewOperationQueue.java |  23 --
 .../facebook/react/uimanager/ViewProps.java   |   2 +-
 12 files changed, 27 insertions(+), 345 deletions(-)
 delete mode 100644 Libraries/ReactNative/ReactNativeViewPool.js

diff --git a/Libraries/ReactNative/ReactNativeBaseComponent.js b/Libraries/ReactNative/ReactNativeBaseComponent.js
index b187a39f0f97..cfd3df3e832d 100644
--- a/Libraries/ReactNative/ReactNativeBaseComponent.js
+++ b/Libraries/ReactNative/ReactNativeBaseComponent.js
@@ -16,7 +16,6 @@ var ReactNativeAttributePayload = require('ReactNativeAttributePayload');
 var ReactNativeEventEmitter = require('ReactNativeEventEmitter');
 var ReactNativeStyleAttributes = require('ReactNativeStyleAttributes');
 var ReactNativeTagHandles = require('ReactNativeTagHandles');
-var ReactNativeViewPool = require('ReactNativeViewPool');
 var ReactMultiChild = require('ReactMultiChild');
 var RCTUIManager = require('NativeModules').UIManager;
 
@@ -89,7 +88,6 @@ ReactNativeBaseComponent.Mixin = {
   unmountComponent: function() {
     deleteAllListeners(this._rootNodeID);
     this.unmountChildren();
-    ReactNativeViewPool.release(this);
     this._rootNodeID = null;
   },
 
@@ -206,7 +204,24 @@ ReactNativeBaseComponent.Mixin = {
   mountComponent: function(rootID, transaction, context) {
     this._rootNodeID = rootID;
 
-    var tag = ReactNativeViewPool.acquire(this);
+    var tag = ReactNativeTagHandles.allocateTag();
+
+    if (__DEV__) {
+      deepFreezeAndThrowOnMutationInDev(this._currentElement.props);
+    }
+
+    var updatePayload = ReactNativeAttributePayload.create(
+      this._currentElement.props,
+      this.viewConfig.validAttributes
+    );
+
+    var nativeTopRootID = ReactNativeTagHandles.getNativeTopRootIDFromNodeID(rootID);
+    RCTUIManager.createView(
+      tag,
+      this.viewConfig.uiViewClassName,
+      nativeTopRootID ? ReactNativeTagHandles.rootNodeIDToTag[nativeTopRootID] : null,
+      updatePayload
+    );
 
     this._registerListenersUponCreation(this._currentElement.props);
     this.initializeChildren(
diff --git a/Libraries/ReactNative/ReactNativeMount.js b/Libraries/ReactNative/ReactNativeMount.js
index aeef4cba77af..02dbcb40fc7e 100644
--- a/Libraries/ReactNative/ReactNativeMount.js
+++ b/Libraries/ReactNative/ReactNativeMount.js
@@ -15,7 +15,6 @@ var RCTUIManager = require('NativeModules').UIManager;
 
 var ReactElement = require('ReactElement');
 var ReactNativeTagHandles = require('ReactNativeTagHandles');
-var ReactNativeViewPool = require('ReactNativeViewPool');
 var ReactPerf = require('ReactPerf');
 var ReactReconciler = require('ReactReconciler');
 var ReactUpdateQueue = require('ReactUpdateQueue');
@@ -217,7 +216,6 @@ var ReactNativeMount = {
     ReactNativeMount.unmountComponentAtNode(containerTag);
     // call back into native to remove all of the subviews from this container
     RCTUIManager.removeRootView(containerTag);
-    ReactNativeViewPool.clearPoolForRootView(containerTag);
   },
 
   /**
diff --git a/Libraries/ReactNative/ReactNativeReconcileTransaction.js b/Libraries/ReactNative/ReactNativeReconcileTransaction.js
index aff41081d359..309630e3cc36 100644
--- a/Libraries/ReactNative/ReactNativeReconcileTransaction.js
+++ b/Libraries/ReactNative/ReactNativeReconcileTransaction.js
@@ -14,7 +14,6 @@
 var CallbackQueue = require('CallbackQueue');
 var PooledClass = require('PooledClass');
 var Transaction = require('Transaction');
-var ReactNativeViewPool = require('ReactNativeViewPool');
 
 /**
  * Provides a `CallbackQueue` queue for collecting `onDOMReady` callbacks during
@@ -36,18 +35,12 @@ var ON_DOM_READY_QUEUEING = {
   }
 };
 
-var RN_VIEW_POOL_WRAPPER = {
-  close: function() {
-    ReactNativeViewPool.onReconcileTransactionClose();
-  },
-};
-
 /**
  * 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, RN_VIEW_POOL_WRAPPER];
+var TRANSACTION_WRAPPERS = [ON_DOM_READY_QUEUEING];
 
 /**
  * Currently:
diff --git a/Libraries/ReactNative/ReactNativeViewPool.js b/Libraries/ReactNative/ReactNativeViewPool.js
deleted file mode 100644
index dd0a596165a0..000000000000
--- a/Libraries/ReactNative/ReactNativeViewPool.js
+++ /dev/null
@@ -1,264 +0,0 @@
-/**
- * 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 ReactNativeViewPool
- */
-'use strict';
-
-var ReactNativeTagHandles = require('ReactNativeTagHandles');
-var ReactNativeAttributePayload = require('ReactNativeAttributePayload');
-var RCTUIManager = require('NativeModules').UIManager;
-var Platform = require('Platform');
-
-var deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
-var emptyFunction = require('emptyFunction');
-var flattenStyle = require('flattenStyle');
-
-var EMPTY_POOL = [[]];
-
-var ENABLED = !!RCTUIManager.dropViews;
-
-/* indicies used for _addToPool arrays */
-var TAGS_IDX = 0;
-var KEYS_IDX = 1;
-var PROPS_IDX = 2;
-
-var _pools = {};
-var _poolSize = {};
-
-var layoutOnlyProps = RCTUIManager.layoutOnlyProps;
-
-function isCollapsableForStyle(style) {
-  var flatStyle = flattenStyle(style);
-  for (var styleKey in flatStyle) {
-    if (layoutOnlyProps[styleKey] !== true) {
-      return false;
-    }
-  }
-  return true;
-}
-
-function isCollapsable(viewRef) {
-  var props = viewRef._currentElement.props;
-  if (props.collapsable !== undefined && !props.collapsable) {
-    return false;
-  }
-  var validAttributes = viewRef.viewConfig.validAttributes;
-  for (var propKey in props) {
-    if (!!validAttributes[propKey] && propKey !== 'style' && propKey !== 'collapsable') {
-      return false;
-    }
-  }
-  return !props.style || isCollapsableForStyle(viewRef._currentElement.props.style);
-}
-
-function enqueueCreate(viewRef, rootTag) {
-  var tag = ReactNativeTagHandles.allocateTag();
-
-  if (__DEV__) {
-    deepFreezeAndThrowOnMutationInDev(viewRef._currentElement.props);
-  }
-
-  var updatePayload = ReactNativeAttributePayload.create(
-    viewRef._currentElement.props,
-    viewRef.viewConfig.validAttributes
-  );
-
-  RCTUIManager.createView(
-    tag,
-    viewRef.viewConfig.uiViewClassName,
-    rootTag,
-    updatePayload
-  );
-
-  return tag;
-}
-
-function getViewTag(viewRef) {
-  return ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(viewRef._rootNodeID);
-}
-
-function getViewProps(viewRef) {
-  return viewRef._currentElement.props;
-}
-
-function getViewValidAttributes(viewRef) {
-  return viewRef.viewConfig.validAttributes;
-}
-
-function getRootViewTag(viewRef) {
-  var nativeTopRootID = ReactNativeTagHandles.getNativeTopRootIDFromNodeID(viewRef._rootNodeID);
-  return ReactNativeTagHandles.rootNodeIDToTag[nativeTopRootID];
-}
-
-function poolKey(viewRef) {
-  var viewClass = viewRef.viewConfig.uiViewClassName;
-  if (Platform.OS === 'android' && viewClass === 'RCTView') {
-    return isCollapsable(viewRef) ? 'CollapsedRCTView' : 'RCTView';
-  }
-  return viewClass;
-}
-
-class ReactNativeViewPool {
-  constructor() {
-    this._pool = {};
-    this._poolQueue = {};
-    this._addToPool = [[],[],[]];
-    this._viewsToDelete = [];
-    if (__DEV__) {
-      this._recycleStats = {};
-      this._deleteStats = {};
-    }
-  }
-
-  onReconcileTransactionClose() {
-    // flush all deletes, move object from pool_queue to the actual pool
-    if (this._viewsToDelete.length > 0) {
-      RCTUIManager.dropViews(this._viewsToDelete);
-    }
-    var addToPoolTags = this._addToPool[TAGS_IDX];
-    var addToPoolKeys = this._addToPool[KEYS_IDX];
-    var addToPoolProps = this._addToPool[PROPS_IDX];
-    for (var i = addToPoolTags.length - 1; i >= 0; i--) {
-      var nativeTag = addToPoolTags[i];
-      var key = addToPoolKeys[i];
-      var props = addToPoolProps[i];
-      var views = this._pool[key] || [[],[]];
-      views[0].push(nativeTag);
-      views[1].push(props);
-      this._pool[key] = views;
-    }
-    this._viewsToDelete = [];
-    this._addToPool = [[],[],[]];
-    this._poolQueue = {};
-  }
-
-  acquire(viewRef, rootTag) {
-    var key = poolKey(viewRef);
-    if ((this._pool[key] || EMPTY_POOL)[0].length) {
-      var views = this._pool[key];
-      var nativeTag = views[0].pop();
-      var oldProps = views[1].pop();
-      var updatePayload = ReactNativeAttributePayload.diff(
-        oldProps,
-        getViewProps(viewRef),
-        getViewValidAttributes(viewRef)
-      );
-      if (__DEV__) {
-        this._recycleStats[key] = (this._recycleStats[key] || 0) + 1;
-      }
-
-      if (updatePayload) {
-        RCTUIManager.updateView(
-          nativeTag,
-          viewRef.viewConfig.uiViewClassName,
-          updatePayload
-        );
-      }
-      return nativeTag;
-    } else {
-      // If there is no view available for the given pool key, we just enqueue call to create one
-      return enqueueCreate(viewRef, rootTag);
-    }
-  }
-
-  release(viewRef) {
-    var key = poolKey(viewRef);
-    var nativeTag = getViewTag(viewRef);
-    var pooledCount = (this._pool[key] || EMPTY_POOL)[0].length + (this._poolQueue[key] || 0);
-    if (pooledCount < (_poolSize[key] || 0)) {
-      // we have room in the pool for this view
-      // we can add it to the queue so that it will be added to the actual pull in
-      // onReconcileTransactionClose
-      this._addToPool[TAGS_IDX].push(nativeTag);
-      this._addToPool[KEYS_IDX].push(key);
-      this._addToPool[PROPS_IDX].push(getViewProps(viewRef));
-      this._poolQueue[key] = (this._poolQueue[key] || 0) + 1;
-    } else {
-      if (__DEV__) {
-        if (_poolSize[key]) {
-          this._deleteStats[key] = (this._deleteStats[key] || 0) + 1;
-        }
-      }
-      this._viewsToDelete.push(nativeTag);
-    }
-  }
-
-  clear() {
-    for (var key in this._pool) {
-      var poolTags = this._pool[key][0];
-      for (var i = poolTags.length - 1; i >= 0; i--) {
-        this._viewsToDelete.push(poolTags[i]);
-      }
-    }
-    var addToPoolTags = this._addToPool[0];
-    for (var i = addToPoolTags.length - 1; i >= 0; i--) {
-      this._viewsToDelete.push(addToPoolTags[i]);
-    }
-    this._addToPool = [[],[],[]];
-    this.onReconcileTransactionClose();
-  }
-
-  printStats() {
-    if (__DEV__) {
-      console.log('Stats', this._recycleStats, this._deleteStats);
-    }
-  }
-}
-
-module.exports = {
-
-  onReconcileTransactionClose: function() {
-    if (ENABLED) {
-      for (var pool in _pools) {
-        _pools[pool].onReconcileTransactionClose();
-      }
-    }
-  },
-
-  acquire: function(viewRef) {
-    var rootTag = getRootViewTag(viewRef);
-    if (ENABLED) {
-      var pool = _pools[rootTag];
-      if (!pool) {
-        pool = _pools[rootTag] = new ReactNativeViewPool();
-      }
-      return pool.acquire(viewRef, rootTag);
-    } else {
-      return enqueueCreate(viewRef, rootTag);
-    }
-  },
-
-  release: ENABLED ? function(viewRef) {
-    var pool = _pools[getRootViewTag(viewRef)];
-    if (pool) {
-      pool.release(viewRef);
-    }
-  } : emptyFunction,
-
-  clearPoolForRootView: ENABLED ? function(rootID) {
-    var pool = _pools[rootID];
-    if (pool) {
-      pool.clear();
-      delete _pools[rootID];
-    }
-  } : emptyFunction,
-
-  configure: function(pool_size) {
-    _poolSize = pool_size;
-  },
-
-  printStats: function() {
-    if (__DEV__) {
-      console.log('Pool size', _poolSize);
-      for (var pool in _pools) {
-        _pools[pool].onReconcileTransactionClose();
-      }
-    }
-  },
-};
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
index cf3c5645587e..fddd7047820f 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
@@ -351,7 +351,7 @@ public void manageChildren(
                       viewsToAdd,
                       tagsToDelete));
         }
-        detachView(viewToDestroy);
+        dropView(viewToDestroy);
       }
     }
   }
@@ -380,15 +380,10 @@ public void addRootView(
     view.setId(tag);
   }
 
-  public void dropView(int tag) {
-    mTagsToViews.remove(tag);
-    mTagsToViewManagers.remove(tag);
-  }
-
   /**
    * Releases all references to given native View.
    */
-  private void detachView(View view) {
+  private void dropView(View view) {
     UiThreadUtil.assertOnUiThread();
     if (!mRootTags.get(view.getId())) {
       // For non-root views we notify viewmanager with {@link ViewManager#onDropInstance}
@@ -403,11 +398,13 @@ private void detachView(View view) {
       for (int i = viewGroupManager.getChildCount(viewGroup) - 1; i >= 0; i--) {
         View child = viewGroupManager.getChildAt(viewGroup, i);
         if (mTagsToViews.get(child.getId()) != null) {
-          detachView(child);
+          dropView(child);
         }
       }
       viewGroupManager.removeAllViews(viewGroup);
     }
+    mTagsToViews.remove(view.getId());
+    mTagsToViewManagers.remove(view.getId());
   }
 
   public void removeRootView(int rootViewTag) {
@@ -417,7 +414,7 @@ public void removeRootView(int rootViewTag) {
             "View with tag " + rootViewTag + " is not registered as a root view");
     }
     View rootView = mTagsToViews.get(rootViewTag);
-    detachView(rootView);
+    dropView(rootView);
     mRootTags.delete(rootViewTag);
     mRootViewsContext.remove(rootViewTag);
   }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java
index e01fab28dcce..fd3946eeb7c9 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java
@@ -90,10 +90,6 @@ public void handleCreateView(
     }
   }
 
-  public void handleDropViews(int[] viewTagsToDrop, int length) {
-    mUIViewOperationQueue.enqueueDropViews(viewTagsToDrop, length);
-  }
-
   /**
    * Handles native children cleanup when css node is removed from hierarchy
    */
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
index b9eb9a64ffe6..1718fe2bbab1 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
@@ -124,22 +124,6 @@ public void createView(int tag, String className, int rootViewTag, ReadableMap p
     }
   }
 
-  public void dropViews(ReadableArray viewTags) {
-    int size = viewTags.size(), realViewsCount = 0;
-    int realViewTags[] = new int[size];
-    for (int i = 0; i < size; i++) {
-      int tag = viewTags.getInt(i);
-      ReactShadowNode cssNode = mShadowNodeRegistry.getNode(tag);
-      if (!cssNode.isVirtual()) {
-        realViewTags[realViewsCount++] = tag;
-      }
-      mShadowNodeRegistry.removeNode(tag);
-    }
-    if (realViewsCount > 0) {
-      mNativeViewHierarchyOptimizer.handleDropViews(realViewTags, realViewsCount);
-    }
-  }
-
   /**
    * Invoked by React to create a new node with a given tag has its properties changed.
    */
@@ -509,6 +493,7 @@ public void setViewHierarchyUpdateDebugListener(
 
   private void removeShadowNode(ReactShadowNode nodeToRemove) {
     mNativeViewHierarchyOptimizer.handleRemoveNode(nodeToRemove);
+    mShadowNodeRegistry.removeNode(nodeToRemove.getReactTag());
     for (int i = nodeToRemove.getChildCount() - 1; i >= 0; i--) {
       removeShadowNode(nodeToRemove.getChildAt(i));
     }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
index ff473aaf683f..04724229bed3 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
@@ -202,11 +202,6 @@ public void createView(int tag, String className, int rootViewTag, ReadableMap p
     mUIImplementation.createView(tag, className, rootViewTag, props);
   }
 
-  @ReactMethod
-  public void dropViews(ReadableArray viewTags) {
-    mUIImplementation.dropViews(viewTags);
-  }
-
   @ReactMethod
   public void updateView(int tag, String className, ReadableMap props) {
     mUIImplementation.updateView(tag, className, props);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java
index eab1c3489170..3287ebf7854c 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java
@@ -154,12 +154,4 @@ public static Map<String, Object> getConstants(DisplayMetrics displayMetrics) {
 
     return constants;
   }
-
-  public static Map<String, Object> getLayoutOnlyPropsConstants() {
-    HashMap<String, Object> constants = new HashMap<>();
-    for (String propName : ViewProps.LAYOUT_ONLY_PROPS) {
-      constants.put(propName, Boolean.TRUE);
-    }
-    return constants;
-  }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java
index d5b566529729..bce7c37361b2 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java
@@ -25,7 +25,6 @@
 
   private static final String CUSTOM_BUBBLING_EVENT_TYPES_KEY = "customBubblingEventTypes";
   private static final String CUSTOM_DIRECT_EVENT_TYPES_KEY = "customDirectEventTypes";
-  private static final String LAYOUT_ONLY_PROPS = "layoutOnlyProps";
 
   /**
    * Generates map of constants that is then exposed by {@link UIManagerModule}. The constants map
@@ -76,7 +75,6 @@
 
     constants.put(CUSTOM_BUBBLING_EVENT_TYPES_KEY, bubblingEventTypesConstants);
     constants.put(CUSTOM_DIRECT_EVENT_TYPES_KEY, directEventTypesConstants);
-    constants.put(LAYOUT_ONLY_PROPS, UIManagerModuleConstants.getLayoutOnlyPropsConstants());
 
     return constants;
   }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
index 21f1128d8ebe..ed507fd3ec63 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
@@ -147,25 +147,6 @@ public void execute() {
     }
   }
 
-  private final class DropViewsOperation extends ViewOperation {
-
-    private final int[] mViewTagsToDrop;
-    private final int mArrayLength;
-
-    public DropViewsOperation(int[] viewTagsToDrop, int length) {
-      super(-1);
-      mViewTagsToDrop = viewTagsToDrop;
-      mArrayLength = length;
-    }
-
-    @Override
-    public void execute() {
-      for (int i = 0; i < mArrayLength; i++) {
-        mNativeViewHierarchyManager.dropView(mViewTagsToDrop[i]);
-      }
-    }
-  }
-
   private final class ManageChildrenOperation extends ViewOperation {
 
     private final @Nullable int[] mIndicesToRemove;
@@ -556,10 +537,6 @@ public void enqueueCreateView(
             initialProps));
   }
 
-  public void enqueueDropViews(int[] viewTagsToDrop, int length) {
-    mOperations.add(new DropViewsOperation(viewTagsToDrop, length));
-  }
-
   public void enqueueUpdateProperties(int reactTag, String className, CatalystStylesDiffMap props) {
     mOperations.add(new UpdatePropertiesOperation(reactTag, props));
   }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java
index d19ea165e904..7e87a8419d85 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java
@@ -84,7 +84,7 @@ public class ViewProps {
       Spacing.BOTTOM
   };
 
-  /*package*/ static final HashSet<String> LAYOUT_ONLY_PROPS = new HashSet<>(
+  private static final HashSet<String> LAYOUT_ONLY_PROPS = new HashSet<>(
       Arrays.asList(
             ALIGN_SELF,
             ALIGN_ITEMS,

From 8911b72d9e78d78b6f8eb99efe21b1205047fd16 Mon Sep 17 00:00:00 2001
From: Tim Park <timfpark@gmail.com>
Date: Thu, 26 Nov 2015 07:09:59 -0800
Subject: [PATCH 0129/1411] Add Polyline support to MapView

Summary: Per issue #1925, add support for Polyline to MapView.

Briefly, if you have a MapView declared as:

    <MapView
      annotations={this.state.annotations}
      overlays={this.state.overlays}
      style={styles.map}
      region={this.state.region}
      ref="mapView"
    />

then setting

    this.state.overlays = [{
      coordinates: [
        { latitude: 35.5, longitude: -5.5 },
        { latitude: 35.6, longitude: -5.6 },
        ...
      ],
      strokeColor: 'rgba(255, 0, 0, 0.5)',
      lineWidth: 3,
    }];

will draw a red line between the points in locations with a width of 3 and equally blended with the background.
Closes https://github.com/facebook/react-native/pull/4153

Reviewed By: svcscm

Differential Revision: D2697347

Pulled By: nicklockwood

fb-gh-sync-id: a436e4ed8d4e43f2872b39b4694fad7c02de8fe5
---
 Examples/UIExplorer/MapViewExample.js         | 45 +++++++++++
 Libraries/Components/MapView/MapView.js       | 72 +++++++++++++++--
 React/React.xcodeproj/project.pbxproj         | 24 ++++--
 React/Views/RCTConvert+MapKit.h               | 17 ++--
 React/Views/RCTConvert+MapKit.m               | 68 ++++++++--------
 React/Views/RCTMap.h                          | 12 +--
 React/Views/RCTMap.m                          | 77 ++++++++++++++-----
 ...CTPointAnnotation.h => RCTMapAnnotation.h} |  2 +-
 ...CTPointAnnotation.m => RCTMapAnnotation.m} |  4 +-
 React/Views/RCTMapManager.m                   | 28 +++++--
 React/Views/RCTMapOverlay.h                   | 18 +++++
 React/Views/RCTMapOverlay.m                   | 14 ++++
 12 files changed, 296 insertions(+), 85 deletions(-)
 rename React/Views/{RCTPointAnnotation.h => RCTMapAnnotation.h} (90%)
 rename React/Views/{RCTPointAnnotation.m => RCTMapAnnotation.m} (82%)
 create mode 100644 React/Views/RCTMapOverlay.h
 create mode 100644 React/Views/RCTMapOverlay.m

diff --git a/Examples/UIExplorer/MapViewExample.js b/Examples/UIExplorer/MapViewExample.js
index 9a7e2e1aab23..863187edab61 100644
--- a/Examples/UIExplorer/MapViewExample.js
+++ b/Examples/UIExplorer/MapViewExample.js
@@ -313,6 +313,45 @@ var CustomPinImageMapViewExample = React.createClass({
 
 });
 
+var CustomOverlayMapViewExample = React.createClass({
+
+  getInitialState() {
+    return {
+      isFirstLoad: true,
+    };
+  },
+
+  render() {
+    if (this.state.isFirstLoad) {
+      var onRegionChangeComplete = (region) => {
+        this.setState({
+          isFirstLoad: false,
+          overlays: [{
+            coordinates:[
+              {latitude: 32.47, longitude: -107.85},
+              {latitude: 45.13, longitude: -94.48},
+              {latitude: 39.27, longitude: -83.25},
+              {latitude: 32.47, longitude: -107.85},
+            ],
+            strokeColor: '#f007',
+            lineWidth: 3,
+          }],
+        });
+      };
+    }
+
+    return (
+      <MapView
+        style={styles.map}
+        onRegionChangeComplete={onRegionChangeComplete}
+        region={this.state.mapRegion}
+        overlays={this.state.overlays}
+      />
+    );
+  },
+
+});
+
 var styles = StyleSheet.create({
   map: {
     height: 150,
@@ -373,4 +412,10 @@ exports.examples = [
       return  <CustomPinImageMapViewExample style={styles.map} />;
     }
   },
+  {
+    title: 'Custom overlay',
+    render() {
+      return  <CustomOverlayMapViewExample style={styles.map} />;
+    }
+  },
 ];
diff --git a/Libraries/Components/MapView/MapView.js b/Libraries/Components/MapView/MapView.js
index b0468e1877c3..9324a2aeca43 100644
--- a/Libraries/Components/MapView/MapView.js
+++ b/Libraries/Components/MapView/MapView.js
@@ -45,7 +45,6 @@ var MapView = React.createClass({
         // TODO: add a base64 (or similar) encoder here
         annotation.id = encodeURIComponent(JSON.stringify(annotation));
       }
-
       return annotation;
     });
 
@@ -54,16 +53,37 @@ var MapView = React.createClass({
     });
   },
 
+  checkOverlayIds: function (overlays: Array<Object>) {
+
+    var newOverlays = overlays.map(function (overlay) {
+      if (!overlay.id) {
+        // TODO: add a base64 (or similar) encoder here
+        overlay.id = encodeURIComponent(JSON.stringify(overlay));
+      }
+      return overlay;
+    });
+
+    this.setState({
+      overlays: newOverlays
+    });
+  },
+
   componentWillMount: function() {
     if (this.props.annotations) {
       this.checkAnnotationIds(this.props.annotations);
     }
+    if (this.props.overlays) {
+      this.checkOverlayIds(this.props.overlays);
+    }
   },
 
   componentWillReceiveProps: function(nextProps: Object) {
     if (nextProps.annotations) {
       this.checkAnnotationIds(nextProps.annotations);
     }
+    if (nextProps.overlays) {
+      this.checkOverlayIds(nextProps.overlays);
+    }
   },
 
   propTypes: {
@@ -195,11 +215,6 @@ var MapView = React.createClass({
       onLeftCalloutPress: React.PropTypes.func,
       onRightCalloutPress: React.PropTypes.func,
 
-      /**
-       * annotation id
-       */
-      id: React.PropTypes.string,
-
       /**
        * The pin color. This can be any valid color string, or you can use one
        * of the predefined PinColors constants. Applies to both standard pins
@@ -213,7 +228,36 @@ var MapView = React.createClass({
        * @platform ios
        */
       image: Image.propTypes.source,
+      
+      /**
+       * annotation id
+       */
+      id: React.PropTypes.string,
+    })),
+
+    /**
+     * Map overlays
+     */
+    overlays: React.PropTypes.arrayOf(React.PropTypes.shape({
+      /**
+       * Polyline coordinates
+       */
+      coordinates: React.PropTypes.arrayOf(React.PropTypes.shape({
+        latitude: React.PropTypes.number.isRequired,
+        longitude: React.PropTypes.number.isRequired
+      })),
 
+      /**
+       * Line attributes
+       */
+      lineWidth: React.PropTypes.number,
+      strokeColor: React.PropTypes.string,
+      fillColor: React.PropTypes.string,
+
+      /**
+       * Overlay id
+       */
+      id: React.PropTypes.string
     })),
 
     /**
@@ -255,7 +299,7 @@ var MapView = React.createClass({
 
   render: function() {
 
-    let {annotations} = this.props;
+    let {annotations, overlays} = this.props;
     annotations = annotations && annotations.map((annotation: Object) => {
       let {tintColor, image} = annotation;
       return {
@@ -264,10 +308,21 @@ var MapView = React.createClass({
         image: image && resolveAssetSource(image),
       };
     });
+    overlays = overlays && overlays.map((overlay: Object) => {
+      let {strokeColor, fillColor} = overlay;
+      return {
+        ...overlay,
+        strokeColor: strokeColor && processColor(strokeColor),
+        fillColor: fillColor && processColor(fillColor),
+      };
+    });
 
     // TODO: these should be separate events, to reduce bridge traffic
-    if (annotations || this.props.onAnnotationPress) {
+    if (annotations) {
       var onPress = (event: Event) => {
+        if (!annotations) {
+          return;
+        }
         if (event.nativeEvent.action === 'annotation-click') {
           this.props.onAnnotationPress &&
             this.props.onAnnotationPress(event.nativeEvent.annotation);
@@ -308,6 +363,7 @@ var MapView = React.createClass({
       <RCTMap
         {...this.props}
         annotations={annotations}
+        overlays={overlays}
         onPress={onPress}
         onChange={onChange}
       />
diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj
index 4250901f6893..92b4cf7f6a8d 100644
--- a/React/React.xcodeproj/project.pbxproj
+++ b/React/React.xcodeproj/project.pbxproj
@@ -26,6 +26,7 @@
 		13A1F71E1A75392D00D3D453 /* RCTKeyCommands.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A1F71D1A75392D00D3D453 /* RCTKeyCommands.m */; };
 		13AB90C11B6FA36700713B4F /* RCTComponentData.m in Sources */ = {isa = PBXBuildFile; fileRef = 13AB90C01B6FA36700713B4F /* RCTComponentData.m */; };
 		13AF20451AE707F9005F5298 /* RCTSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = 13AF20441AE707F9005F5298 /* RCTSlider.m */; };
+		13AFBCA01C07247D00BBAEAA /* RCTMapOverlay.m in Sources */ = {isa = PBXBuildFile; fileRef = 13AFBC9F1C07247D00BBAEAA /* RCTMapOverlay.m */; };
 		13B07FEF1A69327A00A75B9A /* RCTAlertManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FE81A69327A00A75B9A /* RCTAlertManager.m */; };
 		13B07FF01A69327A00A75B9A /* RCTExceptionsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FEA1A69327A00A75B9A /* RCTExceptionsManager.m */; };
 		13B07FF21A69327A00A75B9A /* RCTTiming.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FEE1A69327A00A75B9A /* RCTTiming.m */; };
@@ -38,7 +39,7 @@
 		13B080201A69489C00A75B9A /* RCTActivityIndicatorViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B080191A69489C00A75B9A /* RCTActivityIndicatorViewManager.m */; };
 		13B080261A694A8400A75B9A /* RCTWrapperViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B080241A694A8400A75B9A /* RCTWrapperViewController.m */; };
 		13B202011BFB945300C07393 /* RCTPasteboard.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B202001BFB945300C07393 /* RCTPasteboard.m */; };
-		13B202041BFB948C00C07393 /* RCTPointAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B202031BFB948C00C07393 /* RCTPointAnnotation.m */; };
+		13B202041BFB948C00C07393 /* RCTMapAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B202031BFB948C00C07393 /* RCTMapAnnotation.m */; };
 		13C156051AB1A2840079392D /* RCTWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13C156021AB1A2840079392D /* RCTWebView.m */; };
 		13C156061AB1A2840079392D /* RCTWebViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13C156041AB1A2840079392D /* RCTWebViewManager.m */; };
 		13CC8A821B17642100940AE7 /* RCTBorderDrawing.m in Sources */ = {isa = PBXBuildFile; fileRef = 13CC8A811B17642100940AE7 /* RCTBorderDrawing.m */; };
@@ -144,6 +145,10 @@
 		13AF1F851AE6E777005F5298 /* RCTDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDefines.h; sourceTree = "<group>"; };
 		13AF20431AE707F8005F5298 /* RCTSlider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSlider.h; sourceTree = "<group>"; };
 		13AF20441AE707F9005F5298 /* RCTSlider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSlider.m; sourceTree = "<group>"; };
+		13AFBC9E1C07247D00BBAEAA /* RCTMapOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTMapOverlay.h; sourceTree = "<group>"; };
+		13AFBC9F1C07247D00BBAEAA /* RCTMapOverlay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTMapOverlay.m; sourceTree = "<group>"; };
+		13AFBCA11C07287B00BBAEAA /* RCTBridgeMethod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBridgeMethod.h; sourceTree = "<group>"; };
+		13AFBCA21C07287B00BBAEAA /* RCTRootViewDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRootViewDelegate.h; sourceTree = "<group>"; };
 		13B07FC71A68125100A75B9A /* Layout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Layout.c; sourceTree = "<group>"; };
 		13B07FC81A68125100A75B9A /* Layout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Layout.h; sourceTree = "<group>"; };
 		13B07FE71A69327A00A75B9A /* RCTAlertManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAlertManager.h; sourceTree = "<group>"; };
@@ -170,8 +175,8 @@
 		13B080241A694A8400A75B9A /* RCTWrapperViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWrapperViewController.m; sourceTree = "<group>"; };
 		13B201FF1BFB945300C07393 /* RCTPasteboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPasteboard.h; sourceTree = "<group>"; };
 		13B202001BFB945300C07393 /* RCTPasteboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPasteboard.m; sourceTree = "<group>"; };
-		13B202021BFB948C00C07393 /* RCTPointAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPointAnnotation.h; sourceTree = "<group>"; };
-		13B202031BFB948C00C07393 /* RCTPointAnnotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPointAnnotation.m; sourceTree = "<group>"; };
+		13B202021BFB948C00C07393 /* RCTMapAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTMapAnnotation.h; sourceTree = "<group>"; };
+		13B202031BFB948C00C07393 /* RCTMapAnnotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTMapAnnotation.m; sourceTree = "<group>"; };
 		13C156011AB1A2840079392D /* RCTWebView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebView.h; sourceTree = "<group>"; };
 		13C156021AB1A2840079392D /* RCTWebView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWebView.m; sourceTree = "<group>"; };
 		13C156031AB1A2840079392D /* RCTWebViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebViewManager.h; sourceTree = "<group>"; };
@@ -342,11 +347,11 @@
 				13CC8A811B17642100940AE7 /* RCTBorderDrawing.m */,
 				13C325281AA63B6A0048765F /* RCTComponent.h */,
 				13AB90BF1B6FA36700713B4F /* RCTComponentData.h */,
+				13456E941ADAD482009F94A7 /* RCTConvert+MapKit.h */,
 				13AB90C01B6FA36700713B4F /* RCTComponentData.m */,
 				13EF7F441BC69646003F47DD /* RCTImageComponent.h */,
 				13456E911ADAD2DE009F94A7 /* RCTConvert+CoreLocation.h */,
 				13456E921ADAD2DE009F94A7 /* RCTConvert+CoreLocation.m */,
-				13456E941ADAD482009F94A7 /* RCTConvert+MapKit.h */,
 				13456E951ADAD482009F94A7 /* RCTConvert+MapKit.m */,
 				133CAE8C1B8E5CFD00F6AD92 /* RCTDatePicker.h */,
 				133CAE8D1B8E5CFD00F6AD92 /* RCTDatePicker.m */,
@@ -354,6 +359,10 @@
 				58C571BF1AA56C1900CDF9C8 /* RCTDatePickerManager.m */,
 				14435CE11AAC4AE100FC20F4 /* RCTMap.h */,
 				14435CE21AAC4AE100FC20F4 /* RCTMap.m */,
+				13B202021BFB948C00C07393 /* RCTMapAnnotation.h */,
+				13B202031BFB948C00C07393 /* RCTMapAnnotation.m */,
+				13AFBC9E1C07247D00BBAEAA /* RCTMapOverlay.h */,
+				13AFBC9F1C07247D00BBAEAA /* RCTMapOverlay.m */,
 				14435CE31AAC4AE100FC20F4 /* RCTMapManager.h */,
 				14435CE41AAC4AE100FC20F4 /* RCTMapManager.m */,
 				83A1FE8A1B62640A00BE0E65 /* RCTModalHostView.h */,
@@ -362,8 +371,6 @@
 				83392EB21B6634E10013B15F /* RCTModalHostViewController.m */,
 				83A1FE8D1B62643A00BE0E65 /* RCTModalHostViewManager.h */,
 				83A1FE8E1B62643A00BE0E65 /* RCTModalHostViewManager.m */,
-				13B202021BFB948C00C07393 /* RCTPointAnnotation.h */,
-				13B202031BFB948C00C07393 /* RCTPointAnnotation.m */,
 				13B0800C1A69489C00A75B9A /* RCTNavigator.h */,
 				13B0800D1A69489C00A75B9A /* RCTNavigator.m */,
 				13B0800E1A69489C00A75B9A /* RCTNavigatorManager.h */,
@@ -484,6 +491,7 @@
 				83CBBA5F1A601EAA00E9B192 /* RCTBridge.m */,
 				1482F9E61B55B927000ADFF3 /* RCTBridgeDelegate.h */,
 				830213F31A654E0800B993E6 /* RCTBridgeModule.h */,
+				13AFBCA11C07287B00BBAEAA /* RCTBridgeMethod.h */,
 				83CBBACA1A6023D300E9B192 /* RCTConvert.h */,
 				83CBBACB1A6023D300E9B192 /* RCTConvert.m */,
 				13AF1F851AE6E777005F5298 /* RCTDefines.h */,
@@ -509,6 +517,7 @@
 				142014171B32094000CC17BA /* RCTPerformanceLogger.m */,
 				830A229C1A66C68A008503DA /* RCTRootView.h */,
 				830A229D1A66C68A008503DA /* RCTRootView.m */,
+				13AFBCA21C07287B00BBAEAA /* RCTRootViewDelegate.h */,
 				83CBBA961A6020BB00E9B192 /* RCTTouchHandler.h */,
 				83CBBA971A6020BB00E9B192 /* RCTTouchHandler.m */,
 				1345A83A1B265A0E00583190 /* RCTURLRequestDelegate.h */,
@@ -619,7 +628,7 @@
 				131B6AF41AF1093D00FFC3E0 /* RCTSegmentedControl.m in Sources */,
 				830A229E1A66C68A008503DA /* RCTRootView.m in Sources */,
 				13B07FF01A69327A00A75B9A /* RCTExceptionsManager.m in Sources */,
-				13B202041BFB948C00C07393 /* RCTPointAnnotation.m in Sources */,
+				13B202041BFB948C00C07393 /* RCTMapAnnotation.m in Sources */,
 				13A0C28A1B74F71200B29F6F /* RCTDevMenu.m in Sources */,
 				14C2CA711B3AC63800E6CBB2 /* RCTModuleMethod.m in Sources */,
 				13CC8A821B17642100940AE7 /* RCTBorderDrawing.m in Sources */,
@@ -658,6 +667,7 @@
 				83CBBA521A601E3B00E9B192 /* RCTLog.m in Sources */,
 				13B0801D1A69489C00A75B9A /* RCTNavItemManager.m in Sources */,
 				13E067571A70F44B002CDEE1 /* RCTView.m in Sources */,
+				13AFBCA01C07247D00BBAEAA /* RCTMapOverlay.m in Sources */,
 				13456E931ADAD2DE009F94A7 /* RCTConvert+CoreLocation.m in Sources */,
 				137327E91AA5CF210034F82E /* RCTTabBarItemManager.m in Sources */,
 				13A1F71E1A75392D00D3D453 /* RCTKeyCommands.m in Sources */,
diff --git a/React/Views/RCTConvert+MapKit.h b/React/Views/RCTConvert+MapKit.h
index d3e7fbc153f3..42add42d9ede 100644
--- a/React/Views/RCTConvert+MapKit.h
+++ b/React/Views/RCTConvert+MapKit.h
@@ -9,21 +9,24 @@
 
 #import <MapKit/MapKit.h>
 
-#import "RCTPointAnnotation.h"
 #import "RCTConvert.h"
 
+@class RCTMapAnnotation;
+@class RCTMapOverlay;
+
 @interface RCTConvert (MapKit)
 
 + (MKCoordinateSpan)MKCoordinateSpan:(id)json;
 + (MKCoordinateRegion)MKCoordinateRegion:(id)json;
-+ (MKShape *)MKShape:(id)json;
 + (MKMapType)MKMapType:(id)json;
-+ (RCTPointAnnotation *)RCTPointAnnotation:(id)json;
 
-typedef NSArray MKShapeArray;
-+ (MKShapeArray *)MKShapeArray:(id)json;
++ (RCTMapAnnotation *)RCTMapAnnotation:(id)json;
++ (RCTMapOverlay *)RCTMapOverlay:(id)json;
+
+typedef NSArray RCTMapAnnotationArray;
++ (NSArray<RCTMapAnnotation *> *)RCTMapAnnotationArray:(id)json;
 
-typedef NSArray RCTPointAnnotationArray;
-+ (RCTPointAnnotationArray *)RCTPointAnnotationArray:(id)json;
+typedef NSArray RCTMapOverlayArray;
++ (NSArray<RCTMapOverlay *> *)RCTMapOverlayArray:(id)json;
 
 @end
diff --git a/React/Views/RCTConvert+MapKit.m b/React/Views/RCTConvert+MapKit.m
index dab5b7661719..78729fe04568 100644
--- a/React/Views/RCTConvert+MapKit.m
+++ b/React/Views/RCTConvert+MapKit.m
@@ -9,7 +9,8 @@
 
 #import "RCTConvert+MapKit.h"
 #import "RCTConvert+CoreLocation.h"
-#import "RCTPointAnnotation.h"
+#import "RCTMapAnnotation.h"
+#import "RCTMapOverlay.h"
 
 @implementation RCTConvert(MapKit)
 
@@ -30,45 +31,52 @@ + (MKCoordinateRegion)MKCoordinateRegion:(id)json
   };
 }
 
-+ (MKShape *)MKShape:(id)json
-{
-  json = [self NSDictionary:json];
-
-  // TODO: more shape types
-  MKShape *shape = [MKPointAnnotation new];
-  shape.coordinate = [self CLLocationCoordinate2D:json];
-  shape.title = [RCTConvert NSString:json[@"title"]];
-  shape.subtitle = [RCTConvert NSString:json[@"subtitle"]];
-  return shape;
-}
-
-RCT_ARRAY_CONVERTER(MKShape)
-
 RCT_ENUM_CONVERTER(MKMapType, (@{
   @"standard": @(MKMapTypeStandard),
   @"satellite": @(MKMapTypeSatellite),
   @"hybrid": @(MKMapTypeHybrid),
 }), MKMapTypeStandard, integerValue)
 
-+ (RCTPointAnnotation *)RCTPointAnnotation:(id)json
++ (RCTMapAnnotation *)RCTMapAnnotation:(id)json
+{
+  json = [self NSDictionary:json];
+  RCTMapAnnotation *annotation = [RCTMapAnnotation new];
+  annotation.coordinate = [self CLLocationCoordinate2D:json];
+  annotation.title = [RCTConvert NSString:json[@"title"]];
+  annotation.subtitle = [RCTConvert NSString:json[@"subtitle"]];
+  annotation.identifier = [RCTConvert NSString:json[@"id"]];
+  annotation.hasLeftCallout = [RCTConvert BOOL:json[@"hasLeftCallout"]];
+  annotation.hasRightCallout = [RCTConvert BOOL:json[@"hasRightCallout"]];
+  annotation.animateDrop = [RCTConvert BOOL:json[@"animateDrop"]];
+  annotation.tintColor = [RCTConvert UIColor:json[@"tintColor"]];
+  annotation.image = [RCTConvert UIImage:json[@"image"]];
+  if (annotation.tintColor && annotation.image) {
+    annotation.image = [annotation.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+  }
+  return annotation;
+}
+
+RCT_ARRAY_CONVERTER(RCTMapAnnotation)
+
++ (RCTMapOverlay *)RCTMapOverlay:(id)json
 {
   json = [self NSDictionary:json];
-  RCTPointAnnotation *shape = [RCTPointAnnotation new];
-  shape.coordinate = [self CLLocationCoordinate2D:json];
-  shape.title = [RCTConvert NSString:json[@"title"]];
-  shape.subtitle = [RCTConvert NSString:json[@"subtitle"]];
-  shape.identifier = [RCTConvert NSString:json[@"id"]];
-  shape.hasLeftCallout = [RCTConvert BOOL:json[@"hasLeftCallout"]];
-  shape.hasRightCallout = [RCTConvert BOOL:json[@"hasRightCallout"]];
-  shape.animateDrop = [RCTConvert BOOL:json[@"animateDrop"]];
-  shape.tintColor = [RCTConvert UIColor:json[@"tintColor"]];
-  shape.image = [RCTConvert UIImage:json[@"image"]];
-  if (shape.tintColor && shape.image) {
-    shape.image = [shape.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+  NSArray<NSDictionary *> *locations = [RCTConvert NSDictionaryArray:json[@"coordinates"]];
+  CLLocationCoordinate2D coordinates[locations.count];
+  NSUInteger index = 0;
+  for (NSDictionary *location in locations) {
+    coordinates[index++] = [RCTConvert CLLocationCoordinate2D:location];
   }
-  return shape;
+
+  RCTMapOverlay *overlay = [RCTMapOverlay polylineWithCoordinates:coordinates
+                                                            count:locations.count];
+
+  overlay.strokeColor = [RCTConvert UIColor:json[@"strokeColor"]];
+  overlay.identifier = [RCTConvert NSString:json[@"id"]];
+  overlay.lineWidth = [RCTConvert CGFloat:json[@"lineWidth"] ?: @1];
+  return overlay;
 }
 
-RCT_ARRAY_CONVERTER(RCTPointAnnotation)
+RCT_ARRAY_CONVERTER(RCTMapOverlay)
 
 @end
diff --git a/React/Views/RCTMap.h b/React/Views/RCTMap.h
index c9025d6d346a..a83bb93dad91 100644
--- a/React/Views/RCTMap.h
+++ b/React/Views/RCTMap.h
@@ -13,9 +13,9 @@
 #import "RCTConvert+MapKit.h"
 #import "RCTComponent.h"
 
-extern const CLLocationDegrees RCTMapDefaultSpan;
-extern const NSTimeInterval RCTMapRegionChangeObserveInterval;
-extern const CGFloat RCTMapZoomBoundBuffer;
+RCT_EXTERN const CLLocationDegrees RCTMapDefaultSpan;
+RCT_EXTERN const NSTimeInterval RCTMapRegionChangeObserveInterval;
+RCT_EXTERN const CGFloat RCTMapZoomBoundBuffer;
 
 @interface RCTMap: MKMapView
 
@@ -25,11 +25,13 @@ extern const CGFloat RCTMapZoomBoundBuffer;
 @property (nonatomic, assign) CGFloat maxDelta;
 @property (nonatomic, assign) UIEdgeInsets legalLabelInsets;
 @property (nonatomic, strong) NSTimer *regionChangeObserveTimer;
-@property (nonatomic, copy) NSArray<NSString *> *annotationIds;
+@property (nonatomic, copy) NSArray<NSString *> *annotationIDs;
+@property (nonatomic, copy) NSArray<NSString *> *overlayIDs;
 
 @property (nonatomic, copy) RCTBubblingEventBlock onChange;
 @property (nonatomic, copy) RCTBubblingEventBlock onPress;
 
-- (void)setAnnotations:(RCTPointAnnotationArray *)annotations;
+- (void)setAnnotations:(RCTMapAnnotationArray *)annotations;
+- (void)setOverlays:(RCTMapOverlayArray *)overlays;
 
 @end
diff --git a/React/Views/RCTMap.m b/React/Views/RCTMap.m
index 238c7a4d3270..4f542c4c4a30 100644
--- a/React/Views/RCTMap.m
+++ b/React/Views/RCTMap.m
@@ -11,6 +11,8 @@
 
 #import "RCTEventDispatcher.h"
 #import "RCTLog.h"
+#import "RCTMapAnnotation.h"
+#import "RCTMapOverlay.h"
 #import "RCTUtils.h"
 
 const CLLocationDegrees RCTMapDefaultSpan = 0.005;
@@ -107,32 +109,34 @@ - (void)setRegion:(MKCoordinateRegion)region animated:(BOOL)animated
   [super setRegion:region animated:animated];
 }
 
-- (void)setAnnotations:(RCTPointAnnotationArray *)annotations
+// TODO: this doesn't preserve order. Should it? If so we should change the
+// algorithm. If not, it would be more efficient to use an NSSet
+- (void)setAnnotations:(RCTMapAnnotationArray *)annotations
 {
-  NSMutableArray<NSString *> *newAnnotationIds = [NSMutableArray new];
-  NSMutableArray<RCTPointAnnotation *> *annotationsToDelete = [NSMutableArray new];
-  NSMutableArray<RCTPointAnnotation *> *annotationsToAdd = [NSMutableArray new];
+  NSMutableArray<NSString *> *newAnnotationIDs = [NSMutableArray new];
+  NSMutableArray<RCTMapAnnotation *> *annotationsToDelete = [NSMutableArray new];
+  NSMutableArray<RCTMapAnnotation *> *annotationsToAdd = [NSMutableArray new];
 
-  for (RCTPointAnnotation *annotation in annotations) {
-    if (![annotation isKindOfClass:[RCTPointAnnotation class]]) {
+  for (RCTMapAnnotation *annotation in annotations) {
+    if (![annotation isKindOfClass:[RCTMapAnnotation class]]) {
       continue;
     }
 
-    [newAnnotationIds addObject:annotation.identifier];
+    [newAnnotationIDs addObject:annotation.identifier];
 
-    // If the current set does not contain the new annotation, mark it as add
-    if (![self.annotationIds containsObject:annotation.identifier]) {
+    // If the current set does not contain the new annotation, mark it to add
+    if (![_annotationIDs containsObject:annotation.identifier]) {
       [annotationsToAdd addObject:annotation];
     }
   }
 
-  for (RCTPointAnnotation *annotation in self.annotations) {
-    if (![annotation isKindOfClass:[RCTPointAnnotation class]]) {
+  for (RCTMapAnnotation *annotation in self.annotations) {
+    if (![annotation isKindOfClass:[RCTMapAnnotation class]]) {
       continue;
     }
 
-    // If the new set does not contain an existing annotation, mark it as delete
-    if (![newAnnotationIds containsObject:annotation.identifier]) {
+    // If the new set does not contain an existing annotation, mark it to delete
+    if (![newAnnotationIDs containsObject:annotation.identifier]) {
       [annotationsToDelete addObject:annotation];
     }
   }
@@ -145,14 +149,51 @@ - (void)setAnnotations:(RCTPointAnnotationArray *)annotations
     [self addAnnotations:(NSArray<id<MKAnnotation>> *)annotationsToAdd];
   }
 
-  NSMutableArray<NSString *> *newIds = [NSMutableArray new];
-  for (RCTPointAnnotation *annotation in self.annotations) {
-    if ([annotation isKindOfClass:[MKUserLocation class]]) {
+  self.annotationIDs = newAnnotationIDs;
+}
+
+// TODO: this doesn't preserve order. Should it? If so we should change the
+// algorithm. If not, it would be more efficient to use an NSSet
+- (void)setOverlays:(RCTMapOverlayArray *)overlays
+{
+  NSMutableArray *newOverlayIDs = [NSMutableArray new];
+  NSMutableArray *overlaysToDelete = [NSMutableArray new];
+  NSMutableArray *overlaysToAdd = [NSMutableArray new];
+
+  for (RCTMapOverlay *overlay in overlays) {
+    if (![overlay isKindOfClass:[RCTMapOverlay class]]) {
+      continue;
+    }
+
+    [newOverlayIDs addObject:overlay.identifier];
+
+    // If the current set does not contain the new annotation, mark it to add
+    if (![_annotationIDs containsObject:overlay.identifier]) {
+      [overlaysToAdd addObject:overlay];
+    }
+  }
+
+  for (RCTMapOverlay *overlay in self.overlays) {
+    if (![overlay isKindOfClass:[RCTMapOverlay class]]) {
       continue;
     }
-    [newIds addObject:annotation.identifier];
+
+    // If the new set does not contain an existing annotation, mark it to delete
+    if (![newOverlayIDs containsObject:overlay.identifier]) {
+      [overlaysToDelete addObject:overlay];
+    }
   }
-  self.annotationIds = newIds;
+
+  if (overlaysToDelete.count) {
+    [self removeOverlays:(NSArray<id<MKOverlay>> *)overlaysToDelete];
+  }
+
+  if (overlaysToAdd.count) {
+    [self addOverlays:(NSArray<id<MKOverlay>> *)overlaysToAdd
+                level:MKOverlayLevelAboveRoads];
+  }
+
+  self.overlayIDs = newOverlayIDs;
 }
 
 @end
diff --git a/React/Views/RCTPointAnnotation.h b/React/Views/RCTMapAnnotation.h
similarity index 90%
rename from React/Views/RCTPointAnnotation.h
rename to React/Views/RCTMapAnnotation.h
index 1ee8fb05508a..0f4479c484bd 100644
--- a/React/Views/RCTPointAnnotation.h
+++ b/React/Views/RCTMapAnnotation.h
@@ -9,7 +9,7 @@
 
 #import <MapKit/MapKit.h>
 
-@interface RCTPointAnnotation : MKPointAnnotation <MKAnnotation>
+@interface RCTMapAnnotation : MKPointAnnotation <MKAnnotation>
 
 @property (nonatomic, copy) NSString *identifier;
 @property (nonatomic, assign) BOOL hasLeftCallout;
diff --git a/React/Views/RCTPointAnnotation.m b/React/Views/RCTMapAnnotation.m
similarity index 82%
rename from React/Views/RCTPointAnnotation.m
rename to React/Views/RCTMapAnnotation.m
index aaaf2d7e20a2..0b90fe8ab1e8 100644
--- a/React/Views/RCTPointAnnotation.m
+++ b/React/Views/RCTMapAnnotation.m
@@ -7,8 +7,8 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  */
 
-#import "RCTPointAnnotation.h"
+#import "RCTMapAnnotation.h"
 
-@implementation RCTPointAnnotation
+@implementation RCTMapAnnotation
 
 @end
diff --git a/React/Views/RCTMapManager.m b/React/Views/RCTMapManager.m
index 75602578d334..6c22c6b16c4a 100644
--- a/React/Views/RCTMapManager.m
+++ b/React/Views/RCTMapManager.m
@@ -16,7 +16,8 @@
 #import "RCTMap.h"
 #import "RCTUtils.h"
 #import "UIView+React.h"
-#import "RCTPointAnnotation.h"
+#import "RCTMapAnnotation.h"
+#import "RCTMapOverlay.h"
 
 #import <MapKit/MapKit.h>
 
@@ -48,7 +49,8 @@ - (UIView *)view
 RCT_EXPORT_VIEW_PROPERTY(minDelta, CGFloat)
 RCT_EXPORT_VIEW_PROPERTY(legalLabelInsets, UIEdgeInsets)
 RCT_EXPORT_VIEW_PROPERTY(mapType, MKMapType)
-RCT_EXPORT_VIEW_PROPERTY(annotations, RCTPointAnnotationArray)
+RCT_EXPORT_VIEW_PROPERTY(annotations, RCTMapAnnotationArray)
+RCT_EXPORT_VIEW_PROPERTY(overlays, RCTMapOverlayArray)
 RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock)
 RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
 RCT_CUSTOM_VIEW_PROPERTY(region, MKCoordinateRegion, RCTMap)
@@ -71,9 +73,9 @@ - (UIView *)view
 
 - (void)mapView:(RCTMap *)mapView didSelectAnnotationView:(MKAnnotationView *)view
 {
-  if (mapView.onPress && [view.annotation isKindOfClass:[RCTPointAnnotation class]]) {
+  if (mapView.onPress && [view.annotation isKindOfClass:[RCTMapAnnotation class]]) {
 
-    RCTPointAnnotation *annotation = (RCTPointAnnotation *)view.annotation;
+    RCTMapAnnotation *annotation = (RCTMapAnnotation *)view.annotation;
     mapView.onPress(@{
       @"action": @"annotation-click",
       @"annotation": @{
@@ -87,9 +89,9 @@ - (void)mapView:(RCTMap *)mapView didSelectAnnotationView:(MKAnnotationView *)vi
   }
 }
 
-- (MKAnnotationView *)mapView:(__unused MKMapView *)mapView viewForAnnotation:(RCTPointAnnotation *)annotation
+- (MKAnnotationView *)mapView:(__unused MKMapView *)mapView viewForAnnotation:(RCTMapAnnotation *)annotation
 {
-  if (![annotation isKindOfClass:[RCTPointAnnotation class]]) {
+  if (![annotation isKindOfClass:[RCTMapAnnotation class]]) {
     return nil;
   }
 
@@ -142,12 +144,24 @@ - (MKAnnotationView *)mapView:(__unused MKMapView *)mapView viewForAnnotation:(R
   return annotationView;
 }
 
+- (MKOverlayRenderer *)mapView:(__unused MKMapView *)mapView rendererForOverlay:(RCTMapOverlay *)overlay
+{
+  if ([overlay isKindOfClass:[RCTMapOverlay class]]) {
+    MKPolylineRenderer *polylineRenderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay];
+    polylineRenderer.strokeColor = overlay.strokeColor;
+    polylineRenderer.lineWidth = overlay.lineWidth;
+    return polylineRenderer;
+  } else {
+    return nil;
+  }
+}
+
 - (void)mapView:(RCTMap *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
 {
   if (mapView.onPress) {
 
     // Pass to js
-    RCTPointAnnotation *annotation = (RCTPointAnnotation *)view.annotation;
+    RCTMapAnnotation *annotation = (RCTMapAnnotation *)view.annotation;
     mapView.onPress(@{
       @"side": (control == view.leftCalloutAccessoryView) ? @"left" : @"right",
       @"action": @"callout-click",
diff --git a/React/Views/RCTMapOverlay.h b/React/Views/RCTMapOverlay.h
new file mode 100644
index 000000000000..a6fcdad5e452
--- /dev/null
+++ b/React/Views/RCTMapOverlay.h
@@ -0,0 +1,18 @@
+/**
+ * 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.
+ */
+
+#import <MapKit/MapKit.h>
+
+@interface RCTMapOverlay : MKPolyline <MKAnnotation>
+
+@property (nonatomic, copy) NSString *identifier;
+@property (nonatomic, strong) UIColor *strokeColor;
+@property (nonatomic, assign) CGFloat lineWidth;
+
+@end
diff --git a/React/Views/RCTMapOverlay.m b/React/Views/RCTMapOverlay.m
new file mode 100644
index 000000000000..2a52dd5b28fb
--- /dev/null
+++ b/React/Views/RCTMapOverlay.m
@@ -0,0 +1,14 @@
+/**
+ * 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.
+ */
+
+#import "RCTMapOverlay.h"
+
+@implementation RCTMapOverlay
+
+@end

From 0f89696f76845925de425bbd6dd29cae8e5f0b43 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Thu, 26 Nov 2015 17:39:15 +0000
Subject: [PATCH 0130/1411] Update KnownIssues.md

---
 docs/KnownIssues.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/KnownIssues.md b/docs/KnownIssues.md
index 0af7876044a7..b7a219d59f27 100644
--- a/docs/KnownIssues.md
+++ b/docs/KnownIssues.md
@@ -69,9 +69,9 @@ This is a result of how Android rendering works. This feature is not being worke
 
 Another issue with `overflow: 'hidden'` on Android: a view is not clipped by the parent's `borderRadius` even if the parent has `overflow: 'hidden'` enabled – the corners of the inner view will be visible outside of the rounded corners. This is only on Android; it works as expected on iOS. See a [demo of the bug](https://rnplay.org/apps/BlGjdQ) and the [corresponding issue](https://github.com/facebook/react-native/issues/3198).
 
-### No support for shadows on Android
+### View shadows
 
-We don't support shadows on Android currently. These are notoriously hard to implement as they require drawing outside of a view's bounds and Android's invalidation logic has a hard time with that. A possible solution is to use [elevation](https://developer.android.com/training/material/shadows-clipping.html), but more experimentation will be required.
+The `shadow*` [view styles](/react-native/docs/view.html#style) apply on iOS, and the `elevation` view prop is available on Android. Setting `elevation` on Android is equivalent to using the [native elevation API](https://developer.android.com/training/material/shadows-clipping.html#Elevation), and has the same limitations (most significantly, it only works on Android 5.0+). Setting `elevation` on Android also affects the z-order for overlapping views.
 
 ### Android M permissions
 

From fd6ec34cdcfb82febcfaea39c0f5cf3e19c12ff6 Mon Sep 17 00:00:00 2001
From: mkonicek-tester <martinkonicek@seznam.cz>
Date: Thu, 26 Nov 2015 18:01:53 +0000
Subject: [PATCH 0131/1411] Update KnownIssues.md

---
 docs/KnownIssues.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/KnownIssues.md b/docs/KnownIssues.md
index b350cae6a62e..f133bb952f1d 100644
--- a/docs/KnownIssues.md
+++ b/docs/KnownIssues.md
@@ -59,7 +59,7 @@ There are known cases where the APIs could be made more consistent across iOS an
 
 ### Using 3rd-party native modules
 
-There are many awesome 3rd party modules: https://react.parts/native
+There are many awesome 3rd-party modules: https://react.parts/native
 
 Adding these to your apps should be made simpler. Here's [an example](https://github.com/apptailor/react-native-google-signin) how this is done currently.
 

From ab68d8e8d1a1856d0f374c137ea2669e13799808 Mon Sep 17 00:00:00 2001
From: mkonicek-tester <martinkonicek@seznam.cz>
Date: Thu, 26 Nov 2015 18:07:17 +0000
Subject: [PATCH 0132/1411] Alpha-sort modules in Known Issues

---
 docs/KnownIssues.md | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/docs/KnownIssues.md b/docs/KnownIssues.md
index f133bb952f1d..4db8dfa4bcea 100644
--- a/docs/KnownIssues.md
+++ b/docs/KnownIssues.md
@@ -22,25 +22,25 @@ Our provisional plan for common views and modules includes:
 #### Views
 
 ```
-Swipe Refresh
-Spinner
 ART
 Maps
 Modal
+Spinner
+Swipe Refresh
 Webview
 ```
 
 #### Modules
 
 ```
-Net Info
-Camera Roll
 App State
+Alert
+Camera Roll
 Dialog
 Media
+Net Info
 Pasteboard
 PushNotificationIOS
-Alert
 ```
 
 ### Some props are only supported on one platform

From 8ebe136f61bcb648581df11e0818d762540ab630 Mon Sep 17 00:00:00 2001
From: mkonicek-tester <martinkonicek@seznam.cz>
Date: Thu, 26 Nov 2015 18:07:58 +0000
Subject: [PATCH 0133/1411] Alpha-sort modules

---
 docs/KnownIssues.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/KnownIssues.md b/docs/KnownIssues.md
index 4db8dfa4bcea..6e2955b1b6b2 100644
--- a/docs/KnownIssues.md
+++ b/docs/KnownIssues.md
@@ -33,8 +33,8 @@ Webview
 #### Modules
 
 ```
-App State
 Alert
+App State
 Camera Roll
 Dialog
 Media

From 9c322df7b8ffa7c1467ebafe9b278eaa78bd1b29 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Thu, 26 Nov 2015 10:07:12 -0800
Subject: [PATCH 0134/1411] =?UTF-8?q?Don=E2=80=99t=20do=20manual=20connect?=
 =?UTF-8?q?ion=20counting?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Reviewed By: tadeuzagallo

Differential Revision: D2696017

fb-gh-sync-id: 039abf9b7ed1570590e96e7077bb48a5493e8471
---
 .../src/SocketInterface/SocketServer.js       | 23 +++++++------------
 1 file changed, 8 insertions(+), 15 deletions(-)

diff --git a/packager/react-packager/src/SocketInterface/SocketServer.js b/packager/react-packager/src/SocketInterface/SocketServer.js
index 56562e273c99..2e5335270d57 100644
--- a/packager/react-packager/src/SocketInterface/SocketServer.js
+++ b/packager/react-packager/src/SocketInterface/SocketServer.js
@@ -52,13 +52,11 @@ class SocketServer {
       setImmediate(() => process.exit(1));
     });
 
-    this._numConnections = 0;
     this._server.on('connection', (sock) => this._handleConnection(sock));
 
     // Disable the file watcher.
     options.nonPersistent = true;
     this._packagerServer = new Server(options);
-    this._jobs = 0;
     this._dieEventually(MAX_STARTUP_TIME);
   }
 
@@ -68,8 +66,6 @@ class SocketServer {
 
   _handleConnection(sock) {
     debug('connection to server', process.pid);
-    this._numConnections++;
-    sock.on('close', () => this._numConnections--);
 
     const bunser = new bser.BunserBuf();
     sock.on('data', (buf) => bunser.append(buf));
@@ -95,7 +91,6 @@ class SocketServer {
 
     const handleError = (error) => {
       debug('request error', error);
-      this._jobs--;
       this._reply(sock, m.id, 'error', error.stack);
 
       // Fatal error from JSTransformer transform workers.
@@ -106,7 +101,6 @@ class SocketServer {
 
     switch (m.type) {
       case 'getDependencies':
-        this._jobs++;
         this._packagerServer.getDependencies(m.data).then(
           ({ dependencies }) => this._reply(sock, m.id, 'result', dependencies),
           handleError,
@@ -114,7 +108,6 @@ class SocketServer {
         break;
 
       case 'buildBundle':
-        this._jobs++;
         this._packagerServer.buildBundle(m.data).then(
           (result) => this._reply(sock, m.id, 'result', result),
           handleError,
@@ -122,7 +115,6 @@ class SocketServer {
         break;
 
       case 'buildPrepackBundle':
-        this._jobs++;
         this._packagerServer.buildPrepackBundle(m.data).then(
           (result) => this._reply(sock, m.id, 'result', result),
           handleError,
@@ -130,7 +122,6 @@ class SocketServer {
         break;
 
       case 'getOrderedDependencyPaths':
-        this._jobs++;
         this._packagerServer.getOrderedDependencyPaths(m.data).then(
           (dependencies) => this._reply(sock, m.id, 'result', dependencies),
           handleError,
@@ -156,17 +147,19 @@ class SocketServer {
     // Debounce the kill timer to make sure all the bytes are sent through
     // the socket and the client has time to fully finish and disconnect.
     this._dieEventually();
-    this._jobs--;
   }
 
   _dieEventually(delay = MAX_IDLE_TIME) {
     clearTimeout(this._deathTimer);
     this._deathTimer = setTimeout(() => {
-      if (this._jobs <= 0 && this._numConnections <= 0) {
-        debug('server dying', process.pid);
-        process.exit();
-      }
-      this._dieEventually();
+      this._server.getConnections((error, numConnections) => {
+        // error is passed when connection count is below 0
+        if (error || numConnections <= 0) {
+          debug('server dying', process.pid);
+          process.exit();
+        }
+        this._dieEventually();
+      });
     }, delay);
   }
 

From e1533fdff6892aac734efda9ea488dd87c7ae938 Mon Sep 17 00:00:00 2001
From: Mike Armstrong <mikea@fb.com>
Date: Fri, 27 Nov 2015 00:12:36 -0800
Subject: [PATCH 0135/1411] Move BridgeProfile call to give better systrace
 info

Reviewed By: tadeuzagallo, sahrens

Differential Revision: D2697510

fb-gh-sync-id: 00ec4d5835331b78c554c904dd29661dad9f6f97
---
 Libraries/Utilities/MessageQueue.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/Utilities/MessageQueue.js b/Libraries/Utilities/MessageQueue.js
index 8b336bd7e461..faefc7827048 100644
--- a/Libraries/Utilities/MessageQueue.js
+++ b/Libraries/Utilities/MessageQueue.js
@@ -146,12 +146,12 @@ class MessageQueue {
   }
 
   __callFunction(module, method, args) {
-    BridgeProfiling.profile(() => `${module}.${method}(${stringifySafe(args)})`);
     this._lastFlush = new Date().getTime();
     if (isFinite(module)) {
       method = this._methodTable[module][method];
       module = this._moduleTable[module];
     }
+    BridgeProfiling.profile(() => `${module}.${method}(${stringifySafe(args)})`);
     if (__DEV__ && SPY_MODE) {
       console.log('N->JS : ' + module + '.' + method + '(' + JSON.stringify(args) + ')');
     }

From e1adea86c601fca146a58f9eae69d24662c45900 Mon Sep 17 00:00:00 2001
From: Mike Armstrong <mikea@fb.com>
Date: Fri, 27 Nov 2015 02:04:32 -0800
Subject: [PATCH 0136/1411] add timestamps to determine string convert time

Reviewed By: astreet

Differential Revision: D2684174

fb-gh-sync-id: feed759025e131fd913c6188f783d6920ad1839c
---
 ReactAndroid/src/main/jni/react/JSCExecutor.cpp | 13 +++++++++++++
 ReactAndroid/src/main/jni/react/jni/OnLoad.cpp  |  5 +++++
 ReactAndroid/src/main/jni/react/jni/OnLoad.h    | 13 +++++++++++++
 3 files changed, 31 insertions(+)
 create mode 100644 ReactAndroid/src/main/jni/react/jni/OnLoad.h

diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index ca7afa29a30b..52eb369e77b9 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -10,6 +10,7 @@
 #include <folly/String.h>
 #include <jni/fbjni/Exceptions.h>
 #include "Value.h"
+#include "jni/OnLoad.h"
 
 #ifdef WITH_JSC_EXTRA_TRACING
 #include <react/JSCTracing.h>
@@ -96,7 +97,19 @@ JSCExecutor::~JSCExecutor() {
 void JSCExecutor::executeApplicationScript(
     const std::string& script,
     const std::string& sourceURL) {
+  JNIEnv* env = Environment::current();
+  jclass markerClass = env->FindClass("com/facebook/react/bridge/ReactMarker");
+  jmethodID logMarkerMethod = facebook::react::getLogMarkerMethod();
+  jstring startStringMarker = env->NewStringUTF("executeApplicationScript_startStringConvert");
+  jstring endStringMarker = env->NewStringUTF("executeApplicationScript_endStringConvert");
+
+  env->CallStaticVoidMethod(markerClass, logMarkerMethod, startStringMarker);
   String jsScript(script.c_str());
+  env->CallStaticVoidMethod(markerClass, logMarkerMethod, endStringMarker);
+
+  env->DeleteLocalRef(startStringMarker);
+  env->DeleteLocalRef(endStringMarker);
+
   String jsSourceURL(sourceURL.c_str());
   #ifdef WITH_FBSYSTRACE
   FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor::executeApplicationScript",
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index e3ceddd5fdb1..6afa306da05e 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -16,6 +16,7 @@
 #include "JSLoader.h"
 #include "ReadableNativeArray.h"
 #include "ProxyExecutor.h"
+#include "OnLoad.h"
 
 #ifdef WITH_FBSYSTRACE
 #include <fbsystrace.h>
@@ -747,6 +748,10 @@ static void createProxyExecutor(JNIEnv *env, jobject obj, jobject executorInstan
 
 }
 
+jmethodID getLogMarkerMethod() {
+  return bridge::gLogMarkerMethod;
+}
+
 extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
   return initialize(vm, [] {
     // get the current env
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.h b/ReactAndroid/src/main/jni/react/jni/OnLoad.h
new file mode 100644
index 000000000000..9da83c447b96
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.h
@@ -0,0 +1,13 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+#include <jni.h>
+
+namespace facebook {
+namespace react {
+
+jmethodID getLogMarkerMethod();
+
+} // namespace react
+} // namespace facebook

From 699a75b01f2147919ff2f700234d6a7d9a18e261 Mon Sep 17 00:00:00 2001
From: Alexander Blom <blom@fb.com>
Date: Fri, 27 Nov 2015 02:05:14 -0800
Subject: [PATCH 0137/1411] Clear Fresco caches when going low on memory

Reviewed By: astreet

Differential Revision: D2699721

fb-gh-sync-id: 2d4685885ee254546496b0517633e5fe2de840d6
---
 .../react/modules/fresco/FrescoModule.java    | 32 ++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java
index 666acc2fe159..a9a16ecae3d5 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java
@@ -11,7 +11,9 @@
 
 import java.util.HashSet;
 
+import android.content.ComponentCallbacks2;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.support.annotation.Nullable;
 
 import com.facebook.cache.common.CacheKey;
@@ -37,7 +39,7 @@
  * <p>Does not expose any methods to JavaScript code. For initialization and cleanup only.
  */
 public class FrescoModule extends ReactContextBaseJavaModule implements
-    ModuleDataCleaner.Cleanable {
+    ModuleDataCleaner.Cleanable, ComponentCallbacks2 {
 
   @Nullable private RequestListener mRequestListener;
   @Nullable private DiskCacheConfig mDiskCacheConfig;
@@ -88,6 +90,14 @@ public void initialize() {
 
     ImagePipelineConfig config = builder.build();
     Fresco.initialize(context, config);
+
+    getReactApplicationContext().getApplicationContext().registerComponentCallbacks(this);
+  }
+
+  @Override
+  public void onCatalystInstanceDestroy() {
+    getReactApplicationContext().getApplicationContext().unregisterComponentCallbacks(this);
+    clearMemoryCaches();
   }
 
   @Override
@@ -105,6 +115,26 @@ public void clearSensitiveData() {
     imagePipelineFactory.getSmallImageDiskStorageCache().clearAll();
   }
 
+  @Override
+  public void onTrimMemory(int level) {
+    if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE ||
+        level == ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL) {
+      clearMemoryCaches();
+    }
+  }
+
+  @Override
+  public void onConfigurationChanged(Configuration newConfig) {
+  }
+
+  @Override
+  public void onLowMemory() {
+  }
+
+  private void clearMemoryCaches() {
+    Fresco.getImagePipeline().clearMemoryCaches();
+  }
+
   private static class FrescoHandler implements SoLoaderShim.Handler {
     @Override
     public void loadLibrary(String libraryName) {

From 2c0679bed12bfdd4f6359282eb2feb3018ce636c Mon Sep 17 00:00:00 2001
From: Alexander Blom <blom@fb.com>
Date: Fri, 27 Nov 2015 02:05:56 -0800
Subject: [PATCH 0138/1411] Reuse DraweeControllerBuilder instead of allocating
 one for every image

Reviewed By: astreet

Differential Revision: D2699801

fb-gh-sync-id: 883e788f0a5c7231bf26f1ba4149115a15487366
---
 .../facebook/react/views/image/ReactImageManager.java  | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
index 19ff94205332..8803652d1153 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
@@ -32,7 +32,7 @@ public String getName() {
     return REACT_CLASS;
   }
 
-  private final @Nullable AbstractDraweeControllerBuilder mDraweeControllerBuilder;
+  private @Nullable AbstractDraweeControllerBuilder mDraweeControllerBuilder;
   private final @Nullable Object mCallerContext;
 
   public ReactImageManager(
@@ -43,16 +43,20 @@ public ReactImageManager(
   }
 
   public ReactImageManager() {
+    // Lazily initialize as FrescoModule have not been initialized yet
     mDraweeControllerBuilder = null;
     mCallerContext = null;
   }
 
   @Override
   public ReactImageView createViewInstance(ThemedReactContext context) {
+    if (mDraweeControllerBuilder == null) {
+      mDraweeControllerBuilder = Fresco.newDraweeControllerBuilder();
+    }
+
     return new ReactImageView(
         context,
-        mDraweeControllerBuilder == null ?
-            Fresco.newDraweeControllerBuilder() : mDraweeControllerBuilder,
+        mDraweeControllerBuilder,
         mCallerContext);
   }
 

From f86691a44914ce35fd328e278a960ce284a80da1 Mon Sep 17 00:00:00 2001
From: Martin Kralik <kralik@fb.com>
Date: Fri, 27 Nov 2015 02:51:58 -0800
Subject: [PATCH 0139/1411] added `didSetProps` for views and shadow views

Summary: Views and shadow views might want to configure themself once all of their props were set.
So far there was no way to do it without writing some synchronization code.

This diff adds a `didSetProps` call on both uiviews and shadow views, passing names of all props that were set for convenience.

public

Reviewed By: nicklockwood

Differential Revision: D2699512

fb-gh-sync-id: 65f76e7bcbf5751d5b550261a953c463ed2f4e8a
---
 React/Views/RCTComponent.h     | 7 +++++++
 React/Views/RCTComponentData.m | 7 +++++++
 2 files changed, 14 insertions(+)

diff --git a/React/Views/RCTComponent.h b/React/Views/RCTComponent.h
index 2940b431145e..5236f850b799 100644
--- a/React/Views/RCTComponent.h
+++ b/React/Views/RCTComponent.h
@@ -36,6 +36,13 @@ typedef void (^RCTBubblingEventBlock)(NSDictionary *body);
 
 @optional
 
+/**
+ * Called each time props have been set.
+ * Not all props have to be set - React can set only changed ones.
+ * @param changedProps String names of all set props.
+ */
+- (void)didSetProps:(NSArray<NSString *> *)changedProps;
+
 // TODO: Deprecate this
 // This method is called after layout has been performed for all views known
 // to the RCTViewManager. It is only called on UIViews, not shadow views.
diff --git a/React/Views/RCTComponentData.m b/React/Views/RCTComponentData.m
index dbcbc10c9f2c..8aa82bf28b5f 100644
--- a/React/Views/RCTComponentData.m
+++ b/React/Views/RCTComponentData.m
@@ -302,6 +302,10 @@ - (void)setProps:(NSDictionary<NSString *, id> *)props forView:(id<RCTComponent>
   [props enumerateKeysAndObjectsUsingBlock:^(NSString *key, id json, __unused BOOL *stop) {
     [self propBlockForKey:key defaultView:_defaultView](view, json);
   }];
+
+  if ([view respondsToSelector:@selector(didSetProps:)]) {
+    [view didSetProps:[props allKeys]];
+  }
 }
 
 - (void)setProps:(NSDictionary<NSString *, id> *)props forShadowView:(RCTShadowView *)shadowView
@@ -318,6 +322,9 @@ - (void)setProps:(NSDictionary<NSString *, id> *)props forShadowView:(RCTShadowV
     [self propBlockForKey:key defaultView:_defaultShadowView](shadowView, json);
   }];
 
+  if ([shadowView respondsToSelector:@selector(didSetProps:)]) {
+    [shadowView didSetProps:[props allKeys]];
+  }
   [shadowView updateLayout];
 }
 

From be285c43d1f86419c3bc537bff3889feae6ba85b Mon Sep 17 00:00:00 2001
From: Martin Kralik <kralik@fb.com>
Date: Fri, 27 Nov 2015 02:52:14 -0800
Subject: [PATCH 0140/1411] use didSetProps instead of updateLayout

Summary: There is no point in using `updateLayout` when we have `didSetProps`.
The only a bit risky part is calling `dirtyLayout` in `setFrame:forView:` instead of `updateLayout`,
but since setting frame shouldn't really change border/margin/padding it should be ok.

Depends on D2699512.

public

Reviewed By: nicklockwood

Differential Revision: D2700012

fb-gh-sync-id: a7c33b3b4e3ddc195bebebb8b03934131af016fb
---
 React/Modules/RCTUIManager.m   | 2 +-
 React/Views/RCTComponentData.m | 1 -
 React/Views/RCTShadowView.h    | 5 +----
 React/Views/RCTShadowView.m    | 2 +-
 4 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m
index 51911fdb055c..e4f569e5e1bf 100644
--- a/React/Modules/RCTUIManager.m
+++ b/React/Modules/RCTUIManager.m
@@ -382,7 +382,7 @@ - (void)setFrame:(CGRect)frame forView:(UIView *)view
       rootShadowView.frame = frame;
     }
 
-    [rootShadowView updateLayout];
+    [rootShadowView dirtyLayout];
 
     [self batchDidComplete];
   });
diff --git a/React/Views/RCTComponentData.m b/React/Views/RCTComponentData.m
index 8aa82bf28b5f..4a0b45ad1e1b 100644
--- a/React/Views/RCTComponentData.m
+++ b/React/Views/RCTComponentData.m
@@ -325,7 +325,6 @@ - (void)setProps:(NSDictionary<NSString *, id> *)props forShadowView:(RCTShadowV
   if ([shadowView respondsToSelector:@selector(didSetProps:)]) {
     [shadowView didSetProps:[props allKeys]];
   }
-  [shadowView updateLayout];
 }
 
 - (NSDictionary<NSString *, id> *)viewConfig
diff --git a/React/Views/RCTShadowView.h b/React/Views/RCTShadowView.h
index e565e73d14ed..d77bb3aea04e 100644
--- a/React/Views/RCTShadowView.h
+++ b/React/Views/RCTShadowView.h
@@ -164,10 +164,7 @@ typedef void (^RCTApplierBlock)(NSDictionary<NSNumber *, UIView *> *viewRegistry
 - (void)setTextComputed NS_REQUIRES_SUPER;
 - (BOOL)isTextDirty;
 
-/**
- * Triggers a recalculation of the shadow view's layout.
- */
-- (void)updateLayout NS_REQUIRES_SUPER;
+- (void)didSetProps:(NSArray<NSString *> *)changedProps NS_REQUIRES_SUPER;
 
 /**
  * Computes the recursive offset, meaning the sum of all descendant offsets -
diff --git a/React/Views/RCTShadowView.m b/React/Views/RCTShadowView.m
index e47bec2443e0..75625fd7d3e0 100644
--- a/React/Views/RCTShadowView.m
+++ b/React/Views/RCTShadowView.m
@@ -580,7 +580,7 @@ - (void)setBackgroundColor:(UIColor *)color
   [self dirtyPropagation];
 }
 
-- (void)updateLayout
+- (void)didSetProps:(NSArray<NSString *> *)changedProps
 {
   if (_recomputePadding) {
     RCTProcessMetaProps(_paddingMetaProps, _cssNode->style.padding);

From 01983c2f0ab4e85c1f7db7f0073942cd7fee3836 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Fri, 27 Nov 2015 03:57:38 -0800
Subject: [PATCH 0141/1411] Ability to run unit tests in react-android-github
 via gradle

Reviewed By: mkonicek

Differential Revision: D2699804

fb-gh-sync-id: 7b31287407bacf2e8e3de6ee1c723a11bb2a0f27
---
 ReactAndroid/build.gradle                     |  8 ++++++
 ReactAndroid/gradle.properties                |  6 +++++
 .../storage/AsyncStorageModuleTest.java       |  2 +-
 .../modules/timing/TimingModuleTest.java      |  6 ++---
 .../configuration/MockitoConfiguration.java   | 26 +++++++++++++++++++
 5 files changed, 44 insertions(+), 4 deletions(-)
 create mode 100644 ReactAndroid/src/test/java/org/mockito/configuration/MockitoConfiguration.java

diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle
index b9dc2f04610e..ef343d4a7fdf 100644
--- a/ReactAndroid/build.gradle
+++ b/ReactAndroid/build.gradle
@@ -256,6 +256,14 @@ dependencies {
     compile 'com.squareup.okhttp:okhttp-ws:2.5.0'
     compile 'com.squareup.okio:okio:1.6.0'
     compile 'org.webkit:android-jsc:r174650'
+
+    testCompile "junit:junit:${JUNIT_VERSION}"
+    testCompile "org.powermock:powermock-api-mockito:${POWERMOCK_VERSION}"
+    testCompile "org.powermock:powermock-module-junit4-rule:${POWERMOCK_VERSION}"
+    testCompile "org.powermock:powermock-classloading-xstream:${POWERMOCK_VERSION}"
+    testCompile "org.mockito:mockito-core:${MOCKITO_CORE_VERSION}"
+    testCompile "org.easytesting:fest-assert-core:${FEST_ASSERT_CORE_VERSION}"
+    testCompile("org.robolectric:robolectric:${ROBOLECTRIC_VERSION}")
 }
 
 apply from: 'release.gradle'
diff --git a/ReactAndroid/gradle.properties b/ReactAndroid/gradle.properties
index 96433c14b48e..e038115dd4ea 100644
--- a/ReactAndroid/gradle.properties
+++ b/ReactAndroid/gradle.properties
@@ -6,3 +6,9 @@ POM_ARTIFACT_ID=react-native
 POM_PACKAGING=aar
 
 android.useDeprecatedNdk=true
+
+MOCKITO_CORE_VERSION=1.+
+POWERMOCK_VERSION=1.6.2
+ROBOLECTRIC_VERSION=3.0
+JUNIT_VERSION=4.12
+FEST_ASSERT_CORE_VERSION=2.0M10
diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/storage/AsyncStorageModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/storage/AsyncStorageModuleTest.java
index bd7076fc9258..c11e9ba932a4 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/modules/storage/AsyncStorageModuleTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/modules/storage/AsyncStorageModuleTest.java
@@ -53,7 +53,7 @@
  * Tests for {@link AsyncStorageModule}.
  */
 @PrepareForTest({Arguments.class})
-@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*", "org.json.*"})
 @RunWith(RobolectricTestRunner.class)
 public class AsyncStorageModuleTest {
 
diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java
index 0d14cdc43b89..219bccf13b35 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java
@@ -77,9 +77,9 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
     PowerMockito.mockStatic(ReactChoreographer.class);
     when(ReactChoreographer.getInstance()).thenReturn(mChoreographerMock);
 
-    CatalystInstance catalystInstance = mock(CatalystInstance.class);
+    CatalystInstance reactInstance = mock(CatalystInstance.class);
     ReactApplicationContext reactContext = mock(ReactApplicationContext.class);
-    when(reactContext.getCatalystInstance()).thenReturn(catalystInstance);
+    when(reactContext.getCatalystInstance()).thenReturn(reactInstance);
 
     mCurrentTimeNs = 0;
     mPostFrameCallbackHandler = new PostFrameCallbackHandler();
@@ -92,7 +92,7 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
 
     mTiming = new Timing(reactContext);
     mJSTimersMock = mock(JSTimersExecution.class);
-    when(catalystInstance.getJSModule(JSTimersExecution.class)).thenReturn(mJSTimersMock);
+    when(reactInstance.getJSModule(JSTimersExecution.class)).thenReturn(mJSTimersMock);
     mTiming.initialize();
   }
 
diff --git a/ReactAndroid/src/test/java/org/mockito/configuration/MockitoConfiguration.java b/ReactAndroid/src/test/java/org/mockito/configuration/MockitoConfiguration.java
new file mode 100644
index 000000000000..20f4aa035f43
--- /dev/null
+++ b/ReactAndroid/src/test/java/org/mockito/configuration/MockitoConfiguration.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+package org.mockito.configuration;
+
+/**
+ * Disables the Mockito cache to prevent Mockito & Robolectric bugs.
+ *
+ * Mockito loads this with reflection, so this class might appear unused.
+ */
+@SuppressWarnings("unused")
+public class MockitoConfiguration extends DefaultMockitoConfiguration {
+
+  /* (non-Javadoc)
+   * @see org.mockito.configuration.IMockitoConfiguration#enableClassCache()
+   */
+  public boolean enableClassCache() {
+    return false;
+  }
+}

From af1475fc4ce95c1c38404a71e932fd179724188f Mon Sep 17 00:00:00 2001
From: Oleksandr Stashuk <sashko@fb.com>
Date: Fri, 27 Nov 2015 04:24:33 -0800
Subject: [PATCH 0142/1411] revert of D2699721

Reviewed By: lexs

Differential Revision: D2700660

fb-gh-sync-id: c59fc46e03146af9a1a6ce836070924d6bcfaba6
---
 .../react/modules/fresco/FrescoModule.java    | 32 +------------------
 1 file changed, 1 insertion(+), 31 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java
index a9a16ecae3d5..666acc2fe159 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java
@@ -11,9 +11,7 @@
 
 import java.util.HashSet;
 
-import android.content.ComponentCallbacks2;
 import android.content.Context;
-import android.content.res.Configuration;
 import android.support.annotation.Nullable;
 
 import com.facebook.cache.common.CacheKey;
@@ -39,7 +37,7 @@
  * <p>Does not expose any methods to JavaScript code. For initialization and cleanup only.
  */
 public class FrescoModule extends ReactContextBaseJavaModule implements
-    ModuleDataCleaner.Cleanable, ComponentCallbacks2 {
+    ModuleDataCleaner.Cleanable {
 
   @Nullable private RequestListener mRequestListener;
   @Nullable private DiskCacheConfig mDiskCacheConfig;
@@ -90,14 +88,6 @@ public void initialize() {
 
     ImagePipelineConfig config = builder.build();
     Fresco.initialize(context, config);
-
-    getReactApplicationContext().getApplicationContext().registerComponentCallbacks(this);
-  }
-
-  @Override
-  public void onCatalystInstanceDestroy() {
-    getReactApplicationContext().getApplicationContext().unregisterComponentCallbacks(this);
-    clearMemoryCaches();
   }
 
   @Override
@@ -115,26 +105,6 @@ public void clearSensitiveData() {
     imagePipelineFactory.getSmallImageDiskStorageCache().clearAll();
   }
 
-  @Override
-  public void onTrimMemory(int level) {
-    if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE ||
-        level == ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL) {
-      clearMemoryCaches();
-    }
-  }
-
-  @Override
-  public void onConfigurationChanged(Configuration newConfig) {
-  }
-
-  @Override
-  public void onLowMemory() {
-  }
-
-  private void clearMemoryCaches() {
-    Fresco.getImagePipeline().clearMemoryCaches();
-  }
-
   private static class FrescoHandler implements SoLoaderShim.Handler {
     @Override
     public void loadLibrary(String libraryName) {

From af753a8a4d0842531bc7549fa78b2a4bfbf5dbdd Mon Sep 17 00:00:00 2001
From: Mike Armstrong <mikea@fb.com>
Date: Fri, 27 Nov 2015 03:48:57 -0800
Subject: [PATCH 0143/1411] Add NativeProfiling module that uses RN
 nativeProfiler or console.profile

Reviewed By: jspahrsummers

Differential Revision: D2696072

fb-gh-sync-id: 6a2b9793424cf9a82b9472e6d468cbd81dd6780a
---
 Libraries/Utilities/CPUProfiler.js | 43 ++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)
 create mode 100644 Libraries/Utilities/CPUProfiler.js

diff --git a/Libraries/Utilities/CPUProfiler.js b/Libraries/Utilities/CPUProfiler.js
new file mode 100644
index 000000000000..445706c7b088
--- /dev/null
+++ b/Libraries/Utilities/CPUProfiler.js
@@ -0,0 +1,43 @@
+/**
+ * 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 CPUProfiler
+ * @flow
+ */
+'use strict';
+
+var _label;
+var _nestingLevel = 0;
+
+var CPUProfiler = {
+
+  start(profileName: string) {
+    if (_nestingLevel === 0) {
+      if (global.nativeProfilerStart) {
+        _label = profileName;
+        global.nativeProfilerStart(profileName);
+      } else if (console.profile) {
+        console.profile(profileName);
+      }
+    }
+    _nestingLevel++;
+  },
+  end() {
+    _nestingLevel--;
+    if (_nestingLevel === 0) {
+      if (global.nativeProfilerEnd) {
+        global.nativeProfilerEnd(_label);
+      } else if (console.profileEnd) {
+        console.profileEnd();
+      }
+      _label = undefined;
+    }
+  }
+};
+
+module.exports = CPUProfiler;

From 9e30c3b218c08afb51ae0e274f15422b9bcca480 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Felix=20Oghin=C4=83?= <foghina@fb.com>
Date: Fri, 27 Nov 2015 06:25:35 -0800
Subject: [PATCH 0144/1411] add native module overriding

Differential Revision: D2700638

fb-gh-sync-id: a88ffaf864be848e1bba22e443d301e4623f04ec
---
 .../facebook/react/bridge/BaseJavaModule.java |  5 ++
 .../facebook/react/bridge/NativeModule.java   | 20 +++++--
 .../react/bridge/NativeModuleRegistry.java    | 55 +++++++++----------
 3 files changed, 44 insertions(+), 36 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java
index 061611e7408d..1a84c05fa410 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java
@@ -327,6 +327,11 @@ public void initialize() {
     // do nothing
   }
 
+  @Override
+  public boolean canOverrideExistingModule() {
+    return false;
+  }
+
   @Override
   public void onCatalystInstanceDestroy() {
     // do nothing
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java
index 480e42182079..905b5be93521 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java
@@ -22,7 +22,7 @@
  * register themselves using {@link CxxModuleWrapper}.
  */
 public interface NativeModule {
-  public static interface NativeMethod {
+  interface NativeMethod {
     void invoke(CatalystInstance catalystInstance, ReadableNativeArray parameters);
     String getType();
   }
@@ -31,28 +31,36 @@ public static interface NativeMethod {
    * @return the name of this module. This will be the name used to {@code require()} this module
    * from javascript.
    */
-  public String getName();
+  String getName();
 
   /**
    * @return methods callable from JS on this module
    */
-  public Map<String, NativeMethod> getMethods();
+  Map<String, NativeMethod> getMethods();
 
   /**
    * Append a field which represents the constants this module exports
    * to JS.  If no constants are exported this should do nothing.
    */
-  public void writeConstantsField(JsonGenerator jg, String fieldName) throws IOException;
+  void writeConstantsField(JsonGenerator jg, String fieldName) throws IOException;
 
   /**
    * This is called at the end of {@link CatalystApplicationFragment#createCatalystInstance()}
    * after the CatalystInstance has been created, in order to initialize NativeModules that require
    * the CatalystInstance or JS modules.
    */
-  public void initialize();
+  void initialize();
+
+  /**
+   * Return true if you intend to override some other native module that was registered e.g. as part
+   * of a different package (such as the core one). Trying to override without returning true from
+   * this method is considered an error and will throw an exception during initialization. By
+   * default all modules return false.
+   */
+  boolean canOverrideExistingModule();
 
   /**
    * Called before {CatalystInstance#onHostDestroy}
    */
-  public void onCatalystInstanceDestroy();
+  void onCatalystInstanceDestroy();
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java
index 80b1b4616119..50bdd69bbe2d 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java
@@ -13,11 +13,10 @@
 import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.Map;
-import java.util.Set;
 
 import com.facebook.react.common.MapBuilder;
-import com.facebook.react.common.SetBuilder;
 import com.facebook.infer.annotation.Assertions;
 import com.facebook.systrace.Systrace;
 
@@ -30,13 +29,13 @@
 public class NativeModuleRegistry {
 
   private final ArrayList<ModuleDefinition> mModuleTable;
-  private final Map<Class<NativeModule>, NativeModule> mModuleInstances;
+  private final Map<Class<? extends NativeModule>, NativeModule> mModuleInstances;
   private final String mModuleDescriptions;
   private final ArrayList<OnBatchCompleteListener> mBatchCompleteListenerModules;
 
   private NativeModuleRegistry(
       ArrayList<ModuleDefinition> moduleTable,
-      Map<Class<NativeModule>, NativeModule> moduleInstances,
+      Map<Class<? extends NativeModule>, NativeModule> moduleInstances,
       String moduleDescriptions) {
     mModuleTable = moduleTable;
     mModuleInstances = moduleInstances;
@@ -160,32 +159,24 @@ public MethodRegistration(String name, String tracingName, NativeModule.NativeMe
 
   public static class Builder {
 
-    private ArrayList<ModuleDefinition> mModuleDefinitions;
-    private Map<Class<NativeModule>, NativeModule> mModuleInstances;
-    private Set<String> mSeenModuleNames;
-
-    public Builder() {
-      mModuleDefinitions = new ArrayList<ModuleDefinition>();
-      mModuleInstances = MapBuilder.newHashMap();
-      mSeenModuleNames = SetBuilder.newHashSet();
-    }
+    private final HashMap<String, NativeModule> mModules = MapBuilder.newHashMap();
 
     public Builder add(NativeModule module) {
-      ModuleDefinition registration = new ModuleDefinition(
-          mModuleDefinitions.size(),
-          module.getName(),
-          module);
-      Assertions.assertCondition(
-          !mSeenModuleNames.contains(module.getName()),
-          "Module " + module.getName() + " was already registered!");
-      mSeenModuleNames.add(module.getName());
-      mModuleDefinitions.add(registration);
-      mModuleInstances.put((Class<NativeModule>) module.getClass(), module);
+      NativeModule existing = mModules.get(module.getName());
+      if (existing != null && !module.canOverrideExistingModule()) {
+        throw new IllegalStateException("Native module " + module.getClass().getSimpleName() +
+            " tried to override " + existing.getClass().getSimpleName() + " for module name " +
+            module.getName() + ". If this was your intention, return true from " +
+            module.getClass().getSimpleName() + "#canOverrideExistingModule()");
+      }
+      mModules.put(module.getName(), module);
       return this;
     }
 
     public NativeModuleRegistry build() {
       Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "CreateJSON");
+      ArrayList<ModuleDefinition> moduleTable = new ArrayList<>();
+      Map<Class<? extends NativeModule>, NativeModule> moduleInstances = MapBuilder.newHashMap();
       String moduleDefinitionJson;
       try {
         JsonFactory jsonFactory = new JsonFactory();
@@ -193,19 +184,23 @@ public NativeModuleRegistry build() {
         try {
           JsonGenerator jg = jsonFactory.createGenerator(writer);
           jg.writeStartObject();
-          for (ModuleDefinition module : mModuleDefinitions) {
-            jg.writeObjectFieldStart(module.name);
-            jg.writeNumberField("moduleID", module.id);
+          int idx = 0;
+          for (NativeModule module : mModules.values()) {
+            ModuleDefinition moduleDef = new ModuleDefinition(idx++, module.getName(), module);
+            moduleTable.add(moduleDef);
+            moduleInstances.put(module.getClass(), module);
+            jg.writeObjectFieldStart(moduleDef.name);
+            jg.writeNumberField("moduleID", moduleDef.id);
             jg.writeObjectFieldStart("methods");
-            for (int i = 0; i < module.methods.size(); i++) {
-              MethodRegistration method = module.methods.get(i);
+            for (int i = 0; i < moduleDef.methods.size(); i++) {
+              MethodRegistration method = moduleDef.methods.get(i);
               jg.writeObjectFieldStart(method.name);
               jg.writeNumberField("methodID", i);
               jg.writeStringField("type", method.method.getType());
               jg.writeEndObject();
             }
             jg.writeEndObject();
-            module.target.writeConstantsField(jg, "constants");
+            moduleDef.target.writeConstantsField(jg, "constants");
             jg.writeEndObject();
           }
           jg.writeEndObject();
@@ -217,7 +212,7 @@ public NativeModuleRegistry build() {
       } finally {
         Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
       }
-      return new NativeModuleRegistry(mModuleDefinitions, mModuleInstances, moduleDefinitionJson);
+      return new NativeModuleRegistry(moduleTable, moduleInstances, moduleDefinitionJson);
     }
   }
 }

From 60db876f666e256eba8527251ce7035cfbca6014 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Fri, 27 Nov 2015 05:39:00 -0800
Subject: [PATCH 0145/1411] Wrapped UIManager native module for better
 abstraction

Summary: public

RCTUIManager is a public module with several useful methods, however, unlike most such modules, it does not have a JS wrapper that would allow it to be required directly.

Besides making it more cumbersome to use, this also makes it impossible to modify the UIManager API, or smooth over differences between platforms in the JS layer without breaking all of the call sites.

This diff adds a simple JS wrapper file for the UIManager module to make it easier to work with.

Reviewed By: tadeuzagallo

Differential Revision: D2700348

fb-gh-sync-id: dd9030eface100b1baf756da11bae355dc0f266f
---
 Examples/UIExplorer/ImageEditingExample.js       |  3 ++-
 .../DrawerAndroid/DrawerLayoutAndroid.android.js | 13 +++++++------
 Libraries/Components/TextInput/TextInput.js      |  8 ++++----
 Libraries/Components/TextInput/TextInputState.js | 14 +++++++-------
 .../ToolbarAndroid/ToolbarAndroid.android.js     |  4 ++--
 .../Touchable/TouchableNativeFeedback.android.js | 10 +++++-----
 Libraries/Components/View/View.js                |  4 ++--
 .../ViewPager/ViewPagerAndroid.android.js        | 12 +++++-------
 Libraries/Components/WebView/WebView.android.js  | 14 +++++++-------
 Libraries/CustomComponents/ListView/ListView.js  |  1 -
 Libraries/LayoutAnimation/LayoutAnimation.js     |  4 ++--
 Libraries/Portal/Portal.js                       |  6 +++---
 Libraries/RKBackendNode/queryLayoutByID.js       |  4 ++--
 Libraries/ReactIOS/IOSNativeBridgeEventPlugin.js |  8 +++-----
 Libraries/ReactIOS/NativeMethodsMixin.js         |  9 ++++-----
 Libraries/ReactIOS/requireNativeComponent.js     |  8 ++++----
 .../ReactNative/ReactNativeBaseComponent.js      |  8 ++++----
 .../ReactNative/ReactNativeDOMIDOperations.js    |  6 +++---
 .../ReactNativeGlobalResponderHandler.js         |  6 +++---
 Libraries/ReactNative/ReactNativeMount.js        |  9 ++++-----
 .../ReactNative/ReactNativeTextComponent.js      |  6 +++---
 Libraries/ReactNative/UIManagerStatTracker.js    | 14 +++++++-------
 Libraries/Utilities/Dimensions.js                |  4 ++--
 Libraries/Utilities/UIManager.js                 | 16 ++++++++++++++++
 Libraries/react-native/react-native.js           |  1 +
 25 files changed, 102 insertions(+), 90 deletions(-)
 create mode 100644 Libraries/Utilities/UIManager.js

diff --git a/Examples/UIExplorer/ImageEditingExample.js b/Examples/UIExplorer/ImageEditingExample.js
index affd36796772..56ab1c4ba342 100644
--- a/Examples/UIExplorer/ImageEditingExample.js
+++ b/Examples/UIExplorer/ImageEditingExample.js
@@ -25,10 +25,11 @@ var {
   StyleSheet,
   Text,
   TouchableHighlight,
+  UIManager,
   View,
 } = React;
 var ImageEditingManager = NativeModules.ImageEditingManager;
-var RCTScrollViewConsts = NativeModules.UIManager.RCTScrollView.Constants;
+var RCTScrollViewConsts = UIManager.RCTScrollView.Constants;
 
 var PAGE_SIZE = 20;
 
diff --git a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js
index 407f237e5052..4b209bd41792 100644
--- a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js
+++ b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js
@@ -10,15 +10,16 @@
  */
 'use strict';
 
-var DrawerConsts = require('NativeModules').UIManager.AndroidDrawerLayout.Constants;
 var NativeMethodsMixin = require('NativeMethodsMixin');
 var React = require('React');
 var ReactPropTypes = require('ReactPropTypes');
 var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
-var RCTUIManager = require('NativeModules').UIManager;
 var StyleSheet = require('StyleSheet');
+var UIManager = require('UIManager');
 var View = require('View');
 
+var DrawerConsts = UIManager.AndroidDrawerLayout.Constants;
+
 var dismissKeyboard = require('dismissKeyboard');
 var merge = require('merge');
 var requireNativeComponent = require('requireNativeComponent');
@@ -182,17 +183,17 @@ var DrawerLayoutAndroid = React.createClass({
   },
 
   openDrawer: function() {
-    RCTUIManager.dispatchViewManagerCommand(
+    UIManager.dispatchViewManagerCommand(
       this._getDrawerLayoutHandle(),
-      RCTUIManager.AndroidDrawerLayout.Commands.openDrawer,
+      UIManager.AndroidDrawerLayout.Commands.openDrawer,
       null
     );
   },
 
   closeDrawer: function() {
-    RCTUIManager.dispatchViewManagerCommand(
+    UIManager.dispatchViewManagerCommand(
       this._getDrawerLayoutHandle(),
-      RCTUIManager.AndroidDrawerLayout.Commands.closeDrawer,
+      UIManager.AndroidDrawerLayout.Commands.closeDrawer,
       null
     );
   },
diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js
index c9728d96ab9d..e7416e833bf0 100644
--- a/Libraries/Components/TextInput/TextInput.js
+++ b/Libraries/Components/TextInput/TextInput.js
@@ -16,7 +16,6 @@ var EventEmitter = require('EventEmitter');
 var NativeMethodsMixin = require('NativeMethodsMixin');
 var Platform = require('Platform');
 var PropTypes = require('ReactPropTypes');
-var RCTUIManager = require('NativeModules').UIManager;
 var React = require('React');
 var ReactChildren = require('ReactChildren');
 var StyleSheet = require('StyleSheet');
@@ -24,6 +23,7 @@ var Text = require('Text');
 var TextInputState = require('TextInputState');
 var TimerMixin = require('react-timer-mixin');
 var TouchableWithoutFeedback = require('TouchableWithoutFeedback');
+var UIManager = require('UIManager');
 var View = require('View');
 
 var createReactNativeComponentClass = require('createReactNativeComponentClass');
@@ -496,11 +496,11 @@ var TextInput = React.createClass({
   },
 
   _renderAndroid: function() {
-    var autoCapitalize = RCTUIManager.UIText.AutocapitalizationType[this.props.autoCapitalize];
+    var autoCapitalize = UIManager.UIText.AutocapitalizationType[this.props.autoCapitalize];
     var textAlign =
-      RCTUIManager.AndroidTextInput.Constants.TextAlign[this.props.textAlign];
+      UIManager.AndroidTextInput.Constants.TextAlign[this.props.textAlign];
     var textAlignVertical =
-      RCTUIManager.AndroidTextInput.Constants.TextAlignVertical[this.props.textAlignVertical];
+      UIManager.AndroidTextInput.Constants.TextAlignVertical[this.props.textAlignVertical];
     var children = this.props.children;
     var childCount = 0;
     ReactChildren.forEach(children, () => ++childCount);
diff --git a/Libraries/Components/TextInput/TextInputState.js b/Libraries/Components/TextInput/TextInputState.js
index f3e35b78c2f0..276bba0d781b 100644
--- a/Libraries/Components/TextInput/TextInputState.js
+++ b/Libraries/Components/TextInput/TextInputState.js
@@ -16,7 +16,7 @@
 'use strict';
 
 var Platform = require('Platform');
-var RCTUIManager = require('NativeModules').UIManager;
+var UIManager = require('UIManager');
 
 var TextInputState = {
    /**
@@ -41,11 +41,11 @@ var TextInputState = {
     if (this._currentlyFocusedID !== textFieldID && textFieldID !== null) {
       this._currentlyFocusedID = textFieldID;
       if (Platform.OS === 'ios') {
-        RCTUIManager.focus(textFieldID);
+        UIManager.focus(textFieldID);
       } else if (Platform.OS === 'android') {
-        RCTUIManager.dispatchViewManagerCommand(
+        UIManager.dispatchViewManagerCommand(
           textFieldID,
-          RCTUIManager.AndroidTextInput.Commands.focusTextInput,
+          UIManager.AndroidTextInput.Commands.focusTextInput,
           null
         );
       }
@@ -61,11 +61,11 @@ var TextInputState = {
     if (this._currentlyFocusedID === textFieldID && textFieldID !== null) {
       this._currentlyFocusedID = null;
       if (Platform.OS === 'ios') {
-        RCTUIManager.blur(textFieldID);
+        UIManager.blur(textFieldID);
       } else if (Platform.OS === 'android') {
-        RCTUIManager.dispatchViewManagerCommand(
+        UIManager.dispatchViewManagerCommand(
           textFieldID,
-          RCTUIManager.AndroidTextInput.Commands.blurTextInput,
+          UIManager.AndroidTextInput.Commands.blurTextInput,
           null
         );
       }
diff --git a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js
index 774e602bee68..eb904d867af9 100644
--- a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js
+++ b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js
@@ -13,10 +13,10 @@
 
 var Image = require('Image');
 var NativeMethodsMixin = require('NativeMethodsMixin');
-var RCTUIManager = require('NativeModules').UIManager;
 var React = require('React');
 var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
 var ReactPropTypes = require('ReactPropTypes');
+var UIManager = require('UIManager');
 var View = require('View');
 
 var requireNativeComponent = require('requireNativeComponent');
@@ -154,7 +154,7 @@ var ToolbarAndroid = React.createClass({
           action.icon = resolveAssetSource(action.icon);
         }
         if (action.show) {
-          action.show = RCTUIManager.ToolbarAndroid.Constants.ShowAsAction[action.show];
+          action.show = UIManager.ToolbarAndroid.Constants.ShowAsAction[action.show];
         }
         nativeActions.push(action);
       }
diff --git a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js
index dd479bdfefbb..bc875eda531c 100644
--- a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js
+++ b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js
@@ -11,11 +11,11 @@
 'use strict';
 
 var PropTypes = require('ReactPropTypes');
-var RCTUIManager = require('NativeModules').UIManager;
 var React = require('React');
 var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
 var Touchable = require('Touchable');
 var TouchableWithoutFeedback = require('TouchableWithoutFeedback');
+var UIManager = require('UIManager');
 
 var createStrictShapeTypeChecker = require('createStrictShapeTypeChecker');
 var ensurePositiveDelayProps = require('ensurePositiveDelayProps');
@@ -181,17 +181,17 @@ var TouchableNativeFeedback = React.createClass({
   },
 
   _dispatchHotspotUpdate: function(destX, destY) {
-    RCTUIManager.dispatchViewManagerCommand(
+    UIManager.dispatchViewManagerCommand(
       React.findNodeHandle(this),
-      RCTUIManager.RCTView.Commands.hotspotUpdate,
+      UIManager.RCTView.Commands.hotspotUpdate,
       [destX || 0, destY || 0]
     );
   },
 
   _dispatchPressedStateChange: function(pressed) {
-    RCTUIManager.dispatchViewManagerCommand(
+    UIManager.dispatchViewManagerCommand(
       React.findNodeHandle(this),
-      RCTUIManager.RCTView.Commands.setPressed,
+      UIManager.RCTView.Commands.setPressed,
       [pressed]
     );
   },
diff --git a/Libraries/Components/View/View.js b/Libraries/Components/View/View.js
index 84ab491875d9..beaffb75c09a 100644
--- a/Libraries/Components/View/View.js
+++ b/Libraries/Components/View/View.js
@@ -13,11 +13,11 @@
 
 var NativeMethodsMixin = require('NativeMethodsMixin');
 var PropTypes = require('ReactPropTypes');
-var RCTUIManager = require('NativeModules').UIManager;
 var React = require('React');
 var ReactNativeStyleAttributes = require('ReactNativeStyleAttributes');
 var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
 var StyleSheetPropType = require('StyleSheetPropType');
+var UIManager = require('UIManager');
 var ViewStylePropTypes = require('ViewStylePropTypes');
 
 var requireNativeComponent = require('requireNativeComponent');
@@ -327,7 +327,7 @@ var RCTView = requireNativeComponent('RCTView', View, {
 });
 
 if (__DEV__) {
-  var viewConfig = RCTUIManager.viewConfigs && RCTUIManager.viewConfigs.RCTView || {};
+  var viewConfig = UIManager.viewConfigs && UIManager.viewConfigs.RCTView || {};
   for (var prop in viewConfig.nativeProps) {
     var viewAny: any = View; // Appease flow
     if (!viewAny.propTypes[prop] && !ReactNativeStyleAttributes[prop]) {
diff --git a/Libraries/Components/ViewPager/ViewPagerAndroid.android.js b/Libraries/Components/ViewPager/ViewPagerAndroid.android.js
index 7151917ff637..ec08841ec763 100644
--- a/Libraries/Components/ViewPager/ViewPagerAndroid.android.js
+++ b/Libraries/Components/ViewPager/ViewPagerAndroid.android.js
@@ -7,15 +7,13 @@
 'use strict';
 
 var NativeMethodsMixin = require('NativeMethodsMixin');
-var NativeModules = require('NativeModules');
 var React = require('React');
 var ReactElement = require('ReactElement');
 var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
 var ReactPropTypes = require('ReactPropTypes');
+var UIManager = require('UIManager');
 var View = require('View');
 
-var RCTUIManager = NativeModules.UIManager;
-
 var dismissKeyboard = require('dismissKeyboard');
 var requireNativeComponent = require('requireNativeComponent');
 
@@ -157,9 +155,9 @@ var ViewPagerAndroid = React.createClass({
    * The transition between pages will be animated.
    */
   setPage: function(selectedPage: number) {
-    RCTUIManager.dispatchViewManagerCommand(
+    UIManager.dispatchViewManagerCommand(
       React.findNodeHandle(this),
-      RCTUIManager.AndroidViewPager.Commands.setPage,
+      UIManager.AndroidViewPager.Commands.setPage,
       [selectedPage],
     );
   },
@@ -169,9 +167,9 @@ var ViewPagerAndroid = React.createClass({
    * The transition between pages will be *not* be animated.
    */
   setPageWithoutAnimation: function(selectedPage: number) {
-    RCTUIManager.dispatchViewManagerCommand(
+    UIManager.dispatchViewManagerCommand(
       React.findNodeHandle(this),
-      RCTUIManager.AndroidViewPager.Commands.setPageWithoutAnimation,
+      UIManager.AndroidViewPager.Commands.setPageWithoutAnimation,
       [selectedPage],
     );
   },
diff --git a/Libraries/Components/WebView/WebView.android.js b/Libraries/Components/WebView/WebView.android.js
index f3ce5956d80e..d5569dcad39d 100644
--- a/Libraries/Components/WebView/WebView.android.js
+++ b/Libraries/Components/WebView/WebView.android.js
@@ -14,6 +14,7 @@ var EdgeInsetsPropType = require('EdgeInsetsPropType');
 var React = require('React');
 var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
 var StyleSheet = require('StyleSheet');
+var UIManager = require('UIManager');
 var View = require('View');
 
 var keyMirror = require('keyMirror');
@@ -21,7 +22,6 @@ var merge = require('merge');
 var requireNativeComponent = require('requireNativeComponent');
 
 var PropTypes = React.PropTypes;
-var RCTUIManager = require('NativeModules').UIManager;
 
 var RCT_WEBVIEW_REF = 'webview';
 
@@ -129,25 +129,25 @@ var WebView = React.createClass({
   },
 
   goForward: function() {
-    RCTUIManager.dispatchViewManagerCommand(
+    UIManager.dispatchViewManagerCommand(
       this.getWebWiewHandle(),
-      RCTUIManager.RCTWebView.Commands.goForward,
+      UIManager.RCTWebView.Commands.goForward,
       null
     );
   },
 
   goBack: function() {
-    RCTUIManager.dispatchViewManagerCommand(
+    UIManager.dispatchViewManagerCommand(
       this.getWebWiewHandle(),
-      RCTUIManager.RCTWebView.Commands.goBack,
+      UIManager.RCTWebView.Commands.goBack,
       null
     );
   },
 
   reload: function() {
-    RCTUIManager.dispatchViewManagerCommand(
+    UIManager.dispatchViewManagerCommand(
       this.getWebWiewHandle(),
-      RCTUIManager.RCTWebView.Commands.reload,
+      UIManager.RCTWebView.Commands.reload,
       null
     );
   },
diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js
index fb99f1687595..5706ff0f91b2 100644
--- a/Libraries/CustomComponents/ListView/ListView.js
+++ b/Libraries/CustomComponents/ListView/ListView.js
@@ -28,7 +28,6 @@
 
 var ListViewDataSource = require('ListViewDataSource');
 var React = require('React');
-var RCTUIManager = require('NativeModules').UIManager;
 var RCTScrollViewManager = require('NativeModules').ScrollViewManager;
 var ScrollView = require('ScrollView');
 var ScrollResponder = require('ScrollResponder');
diff --git a/Libraries/LayoutAnimation/LayoutAnimation.js b/Libraries/LayoutAnimation/LayoutAnimation.js
index 881b499f2ba3..140c35ff8785 100644
--- a/Libraries/LayoutAnimation/LayoutAnimation.js
+++ b/Libraries/LayoutAnimation/LayoutAnimation.js
@@ -12,7 +12,7 @@
 'use strict';
 
 var PropTypes = require('ReactPropTypes');
-var RCTUIManager = require('NativeModules').UIManager;
+var UIManager = require('UIManager');
 
 var createStrictShapeTypeChecker = require('createStrictShapeTypeChecker');
 var keyMirror = require('keyMirror');
@@ -71,7 +71,7 @@ type Config = {
 
 function configureNext(config: Config, onAnimationDidEnd?: Function) {
   configChecker({config}, 'config', 'LayoutAnimation.configureNext');
-  RCTUIManager.configureNextLayoutAnimation(
+  UIManager.configureNextLayoutAnimation(
     config, onAnimationDidEnd || function() {}, function() { /* unused */ }
   );
 }
diff --git a/Libraries/Portal/Portal.js b/Libraries/Portal/Portal.js
index ac80e04109fe..f6ed4c8f7860 100644
--- a/Libraries/Portal/Portal.js
+++ b/Libraries/Portal/Portal.js
@@ -8,8 +8,8 @@
 
 var Platform = require('Platform');
 var React = require('React');
-var RCTUIManager = require('NativeModules').UIManager;
 var StyleSheet = require('StyleSheet');
+var UIManager = require('UIManager');
 var View = require('View');
 
 var _portalRef: any;
@@ -135,9 +135,9 @@ var Portal = React.createClass({
       // TextViews have no text set at the moment of populating event.
       setTimeout(() => {
         if (this._getOpenModals().length > 0) {
-          RCTUIManager.sendAccessibilityEvent(
+          UIManager.sendAccessibilityEvent(
             React.findNodeHandle(this),
-            RCTUIManager.AccessibilityEventTypes.typeWindowStateChanged);
+            UIManager.AccessibilityEventTypes.typeWindowStateChanged);
         }
       }, 0);
     }
diff --git a/Libraries/RKBackendNode/queryLayoutByID.js b/Libraries/RKBackendNode/queryLayoutByID.js
index d6492e6da487..5d038c232bb1 100644
--- a/Libraries/RKBackendNode/queryLayoutByID.js
+++ b/Libraries/RKBackendNode/queryLayoutByID.js
@@ -12,7 +12,7 @@
 'use strict';
 
 var ReactNativeTagHandles = require('ReactNativeTagHandles');
-var RCTUIManager = require('NativeModules').UIManager;
+var UIManager = require('UIManager');
 
 type OnSuccessCallback = (
   left: number,
@@ -51,7 +51,7 @@ var queryLayoutByID = function(
   onSuccess: OnSuccessCallback
 ): void {
   // Native bridge doesn't *yet* surface errors.
-  RCTUIManager.measure(
+  UIManager.measure(
     ReactNativeTagHandles.rootNodeIDToTag[rootNodeID],
     onSuccess
   );
diff --git a/Libraries/ReactIOS/IOSNativeBridgeEventPlugin.js b/Libraries/ReactIOS/IOSNativeBridgeEventPlugin.js
index 55b22a959934..6c1d887e555d 100644
--- a/Libraries/ReactIOS/IOSNativeBridgeEventPlugin.js
+++ b/Libraries/ReactIOS/IOSNativeBridgeEventPlugin.js
@@ -12,16 +12,14 @@
 'use strict';
 
 var EventPropagators = require('EventPropagators');
-var NativeModules = require('NativeModules');
 var SyntheticEvent = require('SyntheticEvent');
+var UIManager = require('UIManager');
 
 var merge = require('merge');
 var warning = require('warning');
 
-var RCTUIManager = NativeModules.UIManager;
-
-var customBubblingEventTypes = RCTUIManager.customBubblingEventTypes;
-var customDirectEventTypes = RCTUIManager.customDirectEventTypes;
+var customBubblingEventTypes = UIManager.customBubblingEventTypes;
+var customDirectEventTypes = UIManager.customDirectEventTypes;
 
 var allTypesByEventName = {};
 
diff --git a/Libraries/ReactIOS/NativeMethodsMixin.js b/Libraries/ReactIOS/NativeMethodsMixin.js
index b2b5ba41928d..33b99994a72d 100644
--- a/Libraries/ReactIOS/NativeMethodsMixin.js
+++ b/Libraries/ReactIOS/NativeMethodsMixin.js
@@ -11,10 +11,9 @@
  */
 'use strict';
 
-var NativeModules = require('NativeModules');
-var RCTUIManager = NativeModules.UIManager;
 var ReactNativeAttributePayload = require('ReactNativeAttributePayload');
 var TextInputState = require('TextInputState');
+var UIManager = require('UIManager');
 
 var findNodeHandle = require('findNodeHandle');
 var invariant = require('invariant');
@@ -78,7 +77,7 @@ var NativeMethodsMixin = {
    * prop](/react-native/docs/view.html#onlayout) instead.
    */
   measure: function(callback: MeasureOnSuccessCallback) {
-    RCTUIManager.measure(
+    UIManager.measure(
       findNodeHandle(this),
       mountSafeCallback(this, callback)
     );
@@ -97,7 +96,7 @@ var NativeMethodsMixin = {
     onSuccess: MeasureLayoutOnSuccessCallback,
     onFail: () => void /* currently unused */
   ) {
-    RCTUIManager.measureLayout(
+    UIManager.measureLayout(
       findNodeHandle(this),
       relativeToNativeNode,
       mountSafeCallback(this, onFail),
@@ -121,7 +120,7 @@ var NativeMethodsMixin = {
       this.viewConfig.validAttributes
     );
 
-    RCTUIManager.updateView(
+    UIManager.updateView(
       findNodeHandle(this),
       this.viewConfig.uiViewClassName,
       updatePayload
diff --git a/Libraries/ReactIOS/requireNativeComponent.js b/Libraries/ReactIOS/requireNativeComponent.js
index 11defc0ada13..a046fcbd1498 100644
--- a/Libraries/ReactIOS/requireNativeComponent.js
+++ b/Libraries/ReactIOS/requireNativeComponent.js
@@ -11,8 +11,8 @@
  */
 'use strict';
 
-var RCTUIManager = require('NativeModules').UIManager;
 var ReactNativeStyleAttributes = require('ReactNativeStyleAttributes');
+var UIManager = require('UIManager');
 var UnimplementedView = require('UnimplementedView');
 
 var createReactNativeComponentClass = require('createReactNativeComponentClass');
@@ -27,7 +27,7 @@ var warning = require('warning');
 /**
  * Used to create React components that directly wrap native component
  * implementations.  Config information is extracted from data exported from the
- * RCTUIManager module.  You should also wrap the native component in a
+ * UIManager module.  You should also wrap the native component in a
  * hand-written component with full propTypes definitions and other
  * documentation - pass the hand-written component in as `componentInterface` to
  * verify all the native props are documented via `propTypes`.
@@ -46,13 +46,13 @@ function requireNativeComponent(
   componentInterface?: ?ComponentInterface,
   extraConfig?: ?{nativeOnly?: Object},
 ): Function {
-  var viewConfig = RCTUIManager[viewName];
+  var viewConfig = UIManager[viewName];
   if (!viewConfig || !viewConfig.NativeProps) {
     warning(false, 'Native component for "%s" does not exist', viewName);
     return UnimplementedView;
   }
   var nativeProps = {
-    ...RCTUIManager.RCTView.NativeProps,
+    ...UIManager.RCTView.NativeProps,
     ...viewConfig.NativeProps,
   };
   viewConfig.uiViewClassName = viewName;
diff --git a/Libraries/ReactNative/ReactNativeBaseComponent.js b/Libraries/ReactNative/ReactNativeBaseComponent.js
index cfd3df3e832d..765c0429063b 100644
--- a/Libraries/ReactNative/ReactNativeBaseComponent.js
+++ b/Libraries/ReactNative/ReactNativeBaseComponent.js
@@ -17,7 +17,7 @@ var ReactNativeEventEmitter = require('ReactNativeEventEmitter');
 var ReactNativeStyleAttributes = require('ReactNativeStyleAttributes');
 var ReactNativeTagHandles = require('ReactNativeTagHandles');
 var ReactMultiChild = require('ReactMultiChild');
-var RCTUIManager = require('NativeModules').UIManager;
+var UIManager = require('UIManager');
 
 var deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
 var warning = require('warning');
@@ -123,7 +123,7 @@ ReactNativeBaseComponent.Mixin = {
         );
         createdTags[i] = mountImage.tag;
       }
-      RCTUIManager
+      UIManager
         .manageChildren(containerTag, null, null, createdTags, indexes, null);
     }
   },
@@ -151,7 +151,7 @@ ReactNativeBaseComponent.Mixin = {
     );
 
     if (updatePayload) {
-      RCTUIManager.updateView(
+      UIManager.updateView(
         ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(this._rootNodeID),
         this.viewConfig.uiViewClassName,
         updatePayload
@@ -216,7 +216,7 @@ ReactNativeBaseComponent.Mixin = {
     );
 
     var nativeTopRootID = ReactNativeTagHandles.getNativeTopRootIDFromNodeID(rootID);
-    RCTUIManager.createView(
+    UIManager.createView(
       tag,
       this.viewConfig.uiViewClassName,
       nativeTopRootID ? ReactNativeTagHandles.rootNodeIDToTag[nativeTopRootID] : null,
diff --git a/Libraries/ReactNative/ReactNativeDOMIDOperations.js b/Libraries/ReactNative/ReactNativeDOMIDOperations.js
index af17f9e0742e..fbf90db50337 100644
--- a/Libraries/ReactNative/ReactNativeDOMIDOperations.js
+++ b/Libraries/ReactNative/ReactNativeDOMIDOperations.js
@@ -13,8 +13,8 @@
 
 var ReactNativeTagHandles = require('ReactNativeTagHandles');
 var ReactMultiChildUpdateTypes = require('ReactMultiChildUpdateTypes');
-var RCTUIManager = require('NativeModules').UIManager;
 var ReactPerf = require('ReactPerf');
+var UIManager = require('UIManager');
 
 /**
  * Updates a component's children by processing a series of updates.
@@ -59,7 +59,7 @@ var dangerouslyProcessChildrenUpdates = function(childrenUpdates, markupList) {
   for (var updateParentTagString in byContainerTag) {
     var updateParentTagNumber = +updateParentTagString;
     var childUpdatesToSend = byContainerTag[updateParentTagNumber];
-    RCTUIManager.manageChildren(
+    UIManager.manageChildren(
       updateParentTagNumber,
       childUpdatesToSend.moveFromIndices,
       childUpdatesToSend.moveToIndices,
@@ -93,7 +93,7 @@ var ReactNativeDOMIDOperations = {
     'dangerouslyReplaceNodeWithMarkupByID',
     function(id, mountImage) {
       var oldTag = ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(id);
-      RCTUIManager.replaceExistingNonRootView(oldTag, mountImage.tag);
+      UIManager.replaceExistingNonRootView(oldTag, mountImage.tag);
       ReactNativeTagHandles.associateRootNodeIDWithMountedNodeHandle(id, mountImage.tag);
     }
   ),
diff --git a/Libraries/ReactNative/ReactNativeGlobalResponderHandler.js b/Libraries/ReactNative/ReactNativeGlobalResponderHandler.js
index 1f548c3ebcc2..1094e60451b8 100644
--- a/Libraries/ReactNative/ReactNativeGlobalResponderHandler.js
+++ b/Libraries/ReactNative/ReactNativeGlobalResponderHandler.js
@@ -11,18 +11,18 @@
  */
 'use strict';
 
-var RCTUIManager = require('NativeModules').UIManager;
 var ReactNativeTagHandles = require('ReactNativeTagHandles');
+var UIManager = require('UIManager');
 
 var ReactNativeGlobalResponderHandler = {
   onChange: function(from: string, to: string, blockNativeResponder: boolean) {
     if (to !== null) {
-      RCTUIManager.setJSResponder(
+      UIManager.setJSResponder(
         ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(to),
         blockNativeResponder
       );
     } else {
-      RCTUIManager.clearJSResponder();
+      UIManager.clearJSResponder();
     }
   }
 };
diff --git a/Libraries/ReactNative/ReactNativeMount.js b/Libraries/ReactNative/ReactNativeMount.js
index 02dbcb40fc7e..1f6dab51b8a4 100644
--- a/Libraries/ReactNative/ReactNativeMount.js
+++ b/Libraries/ReactNative/ReactNativeMount.js
@@ -11,14 +11,13 @@
  */
 'use strict';
 
-var RCTUIManager = require('NativeModules').UIManager;
-
 var ReactElement = require('ReactElement');
 var ReactNativeTagHandles = require('ReactNativeTagHandles');
 var ReactPerf = require('ReactPerf');
 var ReactReconciler = require('ReactReconciler');
 var ReactUpdateQueue = require('ReactUpdateQueue');
 var ReactUpdates = require('ReactUpdates');
+var UIManager = require('UIManager');
 
 var emptyObject = require('emptyObject');
 var instantiateReactComponent = require('instantiateReactComponent');
@@ -191,7 +190,7 @@ var ReactNativeMount = {
       );
       var addChildTags = [mountImage.tag];
       var addAtIndices = [0];
-      RCTUIManager.manageChildren(
+      UIManager.manageChildren(
         ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(containerID),
         null,         // moveFromIndices
         null,         // moveToIndices
@@ -215,7 +214,7 @@ var ReactNativeMount = {
   ) {
     ReactNativeMount.unmountComponentAtNode(containerTag);
     // call back into native to remove all of the subviews from this container
-    RCTUIManager.removeRootView(containerTag);
+    UIManager.removeRootView(containerTag);
   },
 
   /**
@@ -256,7 +255,7 @@ var ReactNativeMount = {
     ReactReconciler.unmountComponent(instance);
     var containerTag =
       ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(containerID);
-    RCTUIManager.removeSubviewsFromContainerWithID(containerTag);
+    UIManager.removeSubviewsFromContainerWithID(containerTag);
   },
 
   getNode: function(rootNodeID: string): number {
diff --git a/Libraries/ReactNative/ReactNativeTextComponent.js b/Libraries/ReactNative/ReactNativeTextComponent.js
index a7694c1394c9..e9f67ce59fdb 100644
--- a/Libraries/ReactNative/ReactNativeTextComponent.js
+++ b/Libraries/ReactNative/ReactNativeTextComponent.js
@@ -12,7 +12,7 @@
 'use strict';
 
 var ReactNativeTagHandles = require('ReactNativeTagHandles');
-var RCTUIManager = require('NativeModules').UIManager;
+var UIManager = require('UIManager');
 
 var assign = require('Object.assign');
 var invariant = require('invariant');
@@ -39,7 +39,7 @@ assign(ReactNativeTextComponent.prototype, {
     this._rootNodeID = rootID;
     var tag = ReactNativeTagHandles.allocateTag();
     var nativeTopRootID = ReactNativeTagHandles.getNativeTopRootIDFromNodeID(rootID);
-    RCTUIManager.createView(
+    UIManager.createView(
       tag,
       'RCTRawText',
       nativeTopRootID ? ReactNativeTagHandles.rootNodeIDToTag[nativeTopRootID] : null,
@@ -57,7 +57,7 @@ assign(ReactNativeTextComponent.prototype, {
       var nextStringText = '' + nextText;
       if (nextStringText !== this._stringText) {
         this._stringText = nextStringText;
-        RCTUIManager.updateView(
+        UIManager.updateView(
           ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(
             this._rootNodeID
           ),
diff --git a/Libraries/ReactNative/UIManagerStatTracker.js b/Libraries/ReactNative/UIManagerStatTracker.js
index ef9c64b2bbb5..a3b8779234f5 100644
--- a/Libraries/ReactNative/UIManagerStatTracker.js
+++ b/Libraries/ReactNative/UIManagerStatTracker.js
@@ -11,7 +11,7 @@
  */
 'use strict';
 
-var RCTUIManager = require('NativeModules').UIManager;
+var UIManager = require('UIManager');
 
 var installed = false;
 var UIManagerStatTracker = {
@@ -32,20 +32,20 @@ var UIManagerStatTracker = {
         statLogHandle = setImmediate(printStats);
       }
     }
-    var createViewOrig = RCTUIManager.createView;
-    RCTUIManager.createView = function(tag, className, rootTag, props) {
+    var createViewOrig = UIManager.createView;
+    UIManager.createView = function(tag, className, rootTag, props) {
       incStat('createView', 1);
       incStat('setProp', Object.keys(props || []).length);
       createViewOrig(tag, className, rootTag, props);
     };
-    var updateViewOrig = RCTUIManager.updateView;
-    RCTUIManager.updateView = function(tag, className, props) {
+    var updateViewOrig = UIManager.updateView;
+    UIManager.updateView = function(tag, className, props) {
       incStat('updateView', 1);
       incStat('setProp', Object.keys(props || []).length);
       updateViewOrig(tag, className, props);
     };
-    var manageChildrenOrig = RCTUIManager.manageChildren;
-    RCTUIManager.manageChildren = function(tag, moveFrom, moveTo, addTags, addIndices, remove) {
+    var manageChildrenOrig = UIManager.manageChildren;
+    UIManager.manageChildren = function(tag, moveFrom, moveTo, addTags, addIndices, remove) {
       incStat('manageChildren', 1);
       incStat('move', Object.keys(moveFrom || []).length);
       incStat('remove', Object.keys(remove || []).length);
diff --git a/Libraries/Utilities/Dimensions.js b/Libraries/Utilities/Dimensions.js
index 31fa0d4dc4f3..319aa84622e3 100644
--- a/Libraries/Utilities/Dimensions.js
+++ b/Libraries/Utilities/Dimensions.js
@@ -11,11 +11,11 @@
  */
 'use strict';
 
-var NativeModules = require('NativeModules');
+var UIManager = require('UIManager');
 
 var invariant = require('invariant');
 
-var dimensions = NativeModules.UIManager.Dimensions;
+var dimensions = UIManager.Dimensions;
 
 // We calculate the window dimensions in JS so that we don't encounter loss of
 // precision in transferring the dimensions (which could be non-integers) over
diff --git a/Libraries/Utilities/UIManager.js b/Libraries/Utilities/UIManager.js
new file mode 100644
index 000000000000..3cdfb2e91db1
--- /dev/null
+++ b/Libraries/Utilities/UIManager.js
@@ -0,0 +1,16 @@
+/**
+ * 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 UIManager
+ * @flow
+ */
+'use strict';
+
+var UIManager = require('NativeModules').UIManager;
+
+module.exports = UIManager;
diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js
index 29ff95205868..2264fa5c6657 100644
--- a/Libraries/react-native/react-native.js
+++ b/Libraries/react-native/react-native.js
@@ -78,6 +78,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
   Settings: require('Settings'),
   StatusBarIOS: require('StatusBarIOS'),
   StyleSheet: require('StyleSheet'),
+  UIManager: require('UIManager'),
   VibrationIOS: require('VibrationIOS'),
 
   // Plugins

From 01a0facf33fac82fd37be92fa515e8559c4a7636 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Fri, 27 Nov 2015 06:52:29 -0800
Subject: [PATCH 0146/1411] Fixed onFocus/onBlur events for multiline TextInput

Summary: public

onFocus and onBlur were not firing for multiline TextInputs.

Reviewed By: tadeuzagallo

Differential Revision: D2699846

fb-gh-sync-id: 7e64309bc631a42a99f989f615fef927dc50217c
---
 Examples/UIExplorer/TextInputExample.ios.js | 88 ++++++++++-----------
 Libraries/Text/RCTTextField.m               | 18 +++--
 Libraries/Text/RCTTextView.m                | 55 +++++++------
 3 files changed, 87 insertions(+), 74 deletions(-)

diff --git a/Examples/UIExplorer/TextInputExample.ios.js b/Examples/UIExplorer/TextInputExample.ios.js
index 471920a0b4d0..826139048cb5 100644
--- a/Examples/UIExplorer/TextInputExample.ios.js
+++ b/Examples/UIExplorer/TextInputExample.ios.js
@@ -301,50 +301,6 @@ exports.displayName = (undefined: ?string);
 exports.title = '<TextInput>';
 exports.description = 'Single and multi-line text inputs.';
 exports.examples = [
-  {
-    title: 'Multiline',
-    render: function() {
-      return (
-        <View>
-          <TextInput
-            placeholder="multiline text input"
-            multiline={true}
-            style={styles.multiline}
-          />
-          <TextInput
-            placeholder="multiline text input with font styles and placeholder"
-            multiline={true}
-            clearTextOnFocus={true}
-            autoCorrect={true}
-            autoCapitalize="words"
-            placeholderTextColor="red"
-            keyboardType="url"
-            style={[styles.multiline, styles.multilineWithFontStyles]}
-          />
-          <TextInput
-            placeholder="uneditable multiline text input"
-            editable={false}
-            multiline={true}
-            style={styles.multiline}
-          />
-          <TextInput
-            placeholder="multiline with children"
-            multiline={true}
-            enablesReturnKeyAutomatically={true}
-            returnKeyType="go"
-            style={styles.multiline}>
-            <View style={styles.multilineChild}/>
-          </TextInput>
-        </View>
-      );
-    }
-  },
-  {
-    title: 'Attributed text',
-    render: function() {
-      return <TokenizedTextExample />;
-    }
-  },
   {
     title: 'Auto-focus',
     render: function() {
@@ -592,4 +548,48 @@ exports.examples = [
     title: 'Blur on submit',
     render: function(): ReactElement { return <BlurOnSubmitExample />; },
   },
+  {
+    title: 'Multiline',
+    render: function() {
+      return (
+        <View>
+          <TextInput
+            placeholder="multiline text input"
+            multiline={true}
+            style={styles.multiline}
+          />
+          <TextInput
+            placeholder="multiline text input with font styles and placeholder"
+            multiline={true}
+            clearTextOnFocus={true}
+            autoCorrect={true}
+            autoCapitalize="words"
+            placeholderTextColor="red"
+            keyboardType="url"
+            style={[styles.multiline, styles.multilineWithFontStyles]}
+          />
+          <TextInput
+            placeholder="uneditable multiline text input"
+            editable={false}
+            multiline={true}
+            style={styles.multiline}
+          />
+          <TextInput
+            placeholder="multiline with children"
+            multiline={true}
+            enablesReturnKeyAutomatically={true}
+            returnKeyType="go"
+            style={styles.multiline}>
+            <View style={styles.multilineChild}/>
+          </TextInput>
+        </View>
+      );
+    }
+  },
+  {
+    title: 'Attributed text',
+    render: function() {
+      return <TokenizedTextExample />;
+    }
+  },
 ];
diff --git a/Libraries/Text/RCTTextField.m b/Libraries/Text/RCTTextField.m
index 222d280e1576..de4fd867bd35 100644
--- a/Libraries/Text/RCTTextField.m
+++ b/Libraries/Text/RCTTextField.m
@@ -239,12 +239,19 @@ - (void)sendSelectionEvent
   }
 }
 
-- (BOOL)becomeFirstResponder
+- (void)reactWillMakeFirstResponder
 {
   _jsRequestingFirstResponder = YES;
-  BOOL result = [super becomeFirstResponder];
+}
+
+- (void)reactDidMakeFirstResponder
+{
   _jsRequestingFirstResponder = NO;
-  return result;
+}
+
+- (BOOL)canBecomeFirstResponder
+{
+  return _jsRequestingFirstResponder;
 }
 
 - (BOOL)resignFirstResponder
@@ -261,9 +268,4 @@ - (BOOL)resignFirstResponder
   return result;
 }
 
-- (BOOL)canBecomeFirstResponder
-{
-  return _jsRequestingFirstResponder;
-}
-
 @end
diff --git a/Libraries/Text/RCTTextView.m b/Libraries/Text/RCTTextView.m
index f75a4c013ef1..412dd47acc06 100644
--- a/Libraries/Text/RCTTextView.m
+++ b/Libraries/Text/RCTTextView.m
@@ -22,6 +22,9 @@ @interface RCTUITextView : UITextView
 @end
 
 @implementation RCTUITextView
+{
+  BOOL _jsRequestingFirstResponder;
+}
 
 - (void)paste:(id)sender
 {
@@ -29,12 +32,26 @@ - (void)paste:(id)sender
   [super paste:sender];
 }
 
+- (void)reactWillMakeFirstResponder
+{
+  _jsRequestingFirstResponder = YES;
+}
+
+- (BOOL)canBecomeFirstResponder
+{
+  return _jsRequestingFirstResponder;
+}
+
+- (void)reactDidMakeFirstResponder
+{
+  _jsRequestingFirstResponder = NO;
+}
+
 @end
 
 @implementation RCTTextView
 {
   RCTEventDispatcher *_eventDispatcher;
-  BOOL _jsRequestingFirstResponder;
   NSString *_placeholder;
   UITextView *_placeholderView;
   UITextView *_textView;
@@ -360,7 +377,7 @@ - (void)textViewDidBeginEditing:(UITextView *)textView
 
   [_eventDispatcher sendTextEventWithType:RCTTextEventTypeFocus
                                  reactTag:self.reactTag
-                                     text:textView.text
+                                     text:nil
                                       key:nil
                                eventCount:_nativeEventCount];
 }
@@ -385,28 +402,27 @@ - (void)textViewDidEndEditing:(UITextView *)textView
                                      text:textView.text
                                       key:nil
                                eventCount:_nativeEventCount];
+
+  [_eventDispatcher sendTextEventWithType:RCTTextEventTypeBlur
+                                 reactTag:self.reactTag
+                                     text:nil
+                                      key:nil
+                               eventCount:_nativeEventCount];
+}
+
+- (void)reactWillMakeFirstResponder
+{
+  [_textView reactWillMakeFirstResponder];
 }
 
 - (BOOL)becomeFirstResponder
 {
-  _jsRequestingFirstResponder = YES;
-  BOOL result = [_textView becomeFirstResponder];
-  _jsRequestingFirstResponder = NO;
-  return result;
+  return [_textView becomeFirstResponder];
 }
 
-- (BOOL)resignFirstResponder
+- (void)reactDidMakeFirstResponder
 {
-  [super resignFirstResponder];
-  BOOL result = [_textView resignFirstResponder];
-  if (result) {
-    [_eventDispatcher sendTextEventWithType:RCTTextEventTypeBlur
-                                   reactTag:self.reactTag
-                                       text:_textView.text
-                                        key:nil
-                                 eventCount:_nativeEventCount];
-  }
-  return result;
+  [_textView reactDidMakeFirstResponder];
 }
 
 - (void)layoutSubviews
@@ -415,11 +431,6 @@ - (void)layoutSubviews
   [self updateFrames];
 }
 
-- (BOOL)canBecomeFirstResponder
-{
-  return _jsRequestingFirstResponder;
-}
-
 - (UIFont *)defaultPlaceholderFont
 {
   return [UIFont systemFontOfSize:17];

From 710b443af1173b927d16efa9aa3f82020d4dfb8f Mon Sep 17 00:00:00 2001
From: Bram <bram@b2it.be>
Date: Fri, 27 Nov 2015 07:15:28 -0800
Subject: [PATCH 0147/1411] bugfix #3997: react-native bundle not working on
 windows 10

Summary: fixes https://github.com/facebook/react-native/issues/3997

the root cause is in

Mon, 09 Nov 2015 13:22:47 GMT ReactNativePackager:SocketServer uncaught error Error: listen EACCES C:\Users\donald\AppData\Local\Temp\react-packager-9248a9803ac72b509b389b456696850d

This means that the socket server cannot create the socket.

cfr https://gist.github.com/domenic/2790533 the socket name is not a valid windows socket name.
Closes https://github.com/facebook/react-native/pull/4071

Reviewed By: mkonicek

Differential Revision: D2699546

Pulled By: davidaurelio

fb-gh-sync-id: 6c6494c14c42bb17506b8559001419c9f85e91e3
---
 local-cli/bundle/saveAssets.js                       | 4 ++--
 package.json                                         | 1 +
 packager/react-packager/src/SocketInterface/index.js | 9 ++++++++-
 3 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/local-cli/bundle/saveAssets.js b/local-cli/bundle/saveAssets.js
index 1dd88512b4f2..f95cd4c166ae 100644
--- a/local-cli/bundle/saveAssets.js
+++ b/local-cli/bundle/saveAssets.js
@@ -8,11 +8,11 @@
  */
 'use strict';
 
-const execFile = require('child_process').execFile;
 const fs = require('fs');
 const getAssetDestPathAndroid = require('./getAssetDestPathAndroid');
 const getAssetDestPathIOS = require('./getAssetDestPathIOS');
 const log = require('../util/log').out('bundle');
+const mkdirp = require('mkdirp');
 const path = require('path');
 
 function saveAssets(
@@ -70,7 +70,7 @@ function copyAll(filesToCopy) {
 
 function copy(src, dest, callback) {
   const destDir = path.dirname(dest);
-  execFile('mkdir', ['-p', destDir], err => {
+  mkdirp(destDir, err => {
     if (err) {
       return callback(err);
     }
diff --git a/package.json b/package.json
index b3f5727f70c1..5be50c910962 100644
--- a/package.json
+++ b/package.json
@@ -96,6 +96,7 @@
     "joi": "^6.6.1",
     "json5": "^0.4.0",
     "jstransform": "^11.0.3",
+    "mkdirp": "^0.5.0",
     "module-deps": "^3.9.1",
     "node-fetch": "^1.3.3",
     "opn": "^3.0.2",
diff --git a/packager/react-packager/src/SocketInterface/index.js b/packager/react-packager/src/SocketInterface/index.js
index c56026ead4c3..32e3688c333f 100644
--- a/packager/react-packager/src/SocketInterface/index.js
+++ b/packager/react-packager/src/SocketInterface/index.js
@@ -35,10 +35,17 @@ const SocketInterface = {
         }
       });
 
-      const sockPath = path.join(
+      let sockPath = path.join(
         tmpdir,
         'react-packager-' + hash.digest('hex')
       );
+      if (process.platform === 'win32'){
+        // on Windows, use a named pipe, convert sockPath into a valid pipe name
+        // based on https://gist.github.com/domenic/2790533
+        sockPath = sockPath.replace(/^\//, '')
+        sockPath = sockPath.replace(/\//g, '-')
+        sockPath = '\\\\.\\pipe\\' + sockPath
+      }
 
       if (fs.existsSync(sockPath)) {
         var sock = net.connect(sockPath);

From 599a130c9ac341796f14e4622cd610c4d5f6620e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Sagnes?= <frd@fb.com>
Date: Fri, 27 Nov 2015 08:36:00 -0800
Subject: [PATCH 0148/1411] Add perf tests to avoid decoding the bundle
 completely

Reviewed By: jspahrsummers

Differential Revision: D2574965

fb-gh-sync-id: 7bea6b3af04ba7e15471cc94a324a6c4a1d3614d
---
 React/Base/RCTBatchedBridge.m | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index 89861dedaf53..8923d85ef6a7 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -198,6 +198,9 @@ - (void)loadSource:(RCTSourceLoadBlock)_onSourceLoad
   RCTPerformanceLoggerStart(RCTPLScriptDownload);
   NSUInteger cookie = RCTProfileBeginAsyncEvent(0, @"JavaScript download", nil);
 
+  // Suppress a warning if RCTProfileBeginAsyncEvent gets compiled out
+  (void)cookie;
+
   RCTSourceLoadBlock onSourceLoad = ^(NSError *error, NSData *source) {
     RCTProfileEndAsyncEvent(0, @"init,download", cookie, @"JavaScript download", nil);
     RCTPerformanceLoggerEnd(RCTPLScriptDownload);

From fd0d9877685b5135c73fe5f6ba8fbed0722a81ab Mon Sep 17 00:00:00 2001
From: Denis Koroskin <dkoroskin@fb.com>
Date: Sat, 28 Nov 2015 11:00:43 -0800
Subject: [PATCH 0149/1411] ShadowNodeHierarchyManager should be supplied
 externally to UIManagerModule

Summary: public UIManagerModule should not be creating UIImplementation. Instead, UIImplementation instance should be supplied to it to allow plugging in different implementations. No functional changes.

Reviewed By: astreet

Differential Revision: D2464632

fb-gh-sync-id: e7372977c93ceb7ef5e8658e5ee7e8e87f52d851
---
 .../facebook/react/CoreModulesPackage.java    |  6 ++++-
 .../react/uimanager/UIImplementation.java     |  7 +++---
 .../react/uimanager/UIManagerModule.java      | 22 ++++++++++++++-----
 3 files changed, 25 insertions(+), 10 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java b/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java
index 02bd96d0dc0f..5dd7b1959e88 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java
@@ -28,6 +28,7 @@
 import com.facebook.react.modules.systeminfo.AndroidInfoModule;
 import com.facebook.react.uimanager.AppRegistry;
 import com.facebook.react.uimanager.ReactNative;
+import com.facebook.react.uimanager.UIImplementation;
 import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.ViewManager;
 import com.facebook.react.uimanager.debug.DebugComponentOwnershipModule;
@@ -57,9 +58,12 @@ public List<NativeModule> createNativeModules(
     Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "createUIManagerModule");
     UIManagerModule uiManagerModule;
     try {
+      List<ViewManager> viewManagersList = mReactInstanceManager.createAllViewManagers(
+          catalystApplicationContext);
       uiManagerModule = new UIManagerModule(
           catalystApplicationContext,
-          mReactInstanceManager.createAllViewManagers(catalystApplicationContext));
+          viewManagersList,
+          new UIImplementation(catalystApplicationContext, viewManagersList));
     } finally {
       Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
     }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
index 1718fe2bbab1..94b2307b1702 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
@@ -11,6 +11,7 @@
 import javax.annotation.Nullable;
 
 import java.util.Arrays;
+import java.util.List;
 
 import com.facebook.csslayout.CSSLayoutContext;
 import com.facebook.infer.annotation.Assertions;
@@ -39,11 +40,11 @@ public class UIImplementation {
   private final NativeViewHierarchyOptimizer mNativeViewHierarchyOptimizer;
   private final int[] mMeasureBuffer = new int[4];
 
-  public UIImplementation(ReactApplicationContext reactContext, ViewManagerRegistry viewManagers) {
+  public UIImplementation(ReactApplicationContext reactContext, List<ViewManager> viewManagers) {
+    mViewManagers = new ViewManagerRegistry(viewManagers);
     mOperationsQueue = new UIViewOperationQueue(
         reactContext,
-        new NativeViewHierarchyManager(viewManagers));
-    mViewManagers = viewManagers;
+        new NativeViewHierarchyManager(mViewManagers));
     mNativeViewHierarchyOptimizer = new NativeViewHierarchyOptimizer(
         mOperationsQueue,
         mShadowNodeRegistry);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
index 04724229bed3..59fd688e348b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
@@ -1,4 +1,4 @@
-/**
+  /**
  * Copyright (c) 2015-present, Facebook, Inc.
  * All rights reserved.
  *
@@ -78,17 +78,27 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements
   private int mNextRootViewTag = 1;
   private int mBatchId = 0;
 
-  public UIManagerModule(ReactApplicationContext reactContext, List<ViewManager> viewManagerList) {
+  /**
+   * This contructor is temporarily here to workaround Sandcastle error.
+   */
+  public UIManagerModule(
+      ReactApplicationContext reactContext,
+      List<ViewManager> viewManagerList) {
+    this(reactContext, viewManagerList, new UIImplementation(reactContext, viewManagerList));
+  }
+
+  public UIManagerModule(
+      ReactApplicationContext reactContext,
+      List<ViewManager> viewManagerList,
+      UIImplementation uiImplementation) {
     super(reactContext);
     mEventDispatcher = new EventDispatcher(reactContext);
     DisplayMetrics displayMetrics = reactContext.getResources().getDisplayMetrics();
     DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
     mModuleConstants = createConstants(displayMetrics, viewManagerList);
-    reactContext.addLifecycleEventListener(this);
+    mUIImplementation = uiImplementation;
 
-    mUIImplementation = new UIImplementation(
-        reactContext,
-        new ViewManagerRegistry(viewManagerList));
+    reactContext.addLifecycleEventListener(this);
   }
 
   @Override

From 3c3495739d72e93b5ef22635cc2b8dccd2d545f1 Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Sun, 29 Nov 2015 10:04:07 +0530
Subject: [PATCH 0150/1411] Add docs on building from source

---
 docs/AndroidBuildingFromSource.md | 106 ++++++++++++++++++++++++++++++
 docs/AndroidUIPerformance.md      |   4 +-
 2 files changed, 108 insertions(+), 2 deletions(-)
 create mode 100644 docs/AndroidBuildingFromSource.md

diff --git a/docs/AndroidBuildingFromSource.md b/docs/AndroidBuildingFromSource.md
new file mode 100644
index 000000000000..303c43dd26bc
--- /dev/null
+++ b/docs/AndroidBuildingFromSource.md
@@ -0,0 +1,106 @@
+---
+id: android-building-from-source
+title: Building React Native from source
+layout: docs
+category: Guides (Android)
+permalink: docs/android-building-from-source
+next: activityindicatorios
+---
+
+You will need to build React Native from source if you want to work on a new feature/bug fix, try out the latest features which are not released yet, or maintain your own fork with patches that cannot be merged to the core.
+
+## Prerequisites
+
+Assuming you have the Android SDK installed, run `android` to open the Android SDK Manager.
+
+Make sure you have the following installed:
+
+1. Android SDK version 23 (compileSdkVersion in [`build.gradle`](https://github.com/facebook/react-native/blob/master/ReactAndroid/build.gradle))
+2. SDK build tools version 23.0.1 (buildToolsVersion in [`build.gradle`](https://github.com/facebook/react-native/blob/master/ReactAndroid/build.gradle)])
+3. Android Support Repository >= 17 (for Android Support Library)
+4. Android NDK (download & extraction instructions [here](http://developer.android.com/ndk/downloads/index.html))
+
+Point Gradle to your Android SDK: either have `$ANDROID_SDK` and `$ANDROID_NDK ` defined, or create a local.properties file in the root of your react-native checkout with the following contents:
+
+```
+sdk.dir=absolute_path_to_android_sdk
+ndk.dir=absolute_path_to_android_ndk
+```
+
+Example:
+
+```
+sdk.dir=/Users/your_unix_name/android-sdk-macosx
+ndk.dir=/Users/your_unix_name/android-ndk/android-ndk-r10e
+```
+
+
+## Building the source
+
+1. Install `react-native` from your fork. For example, to install the master branch from the offcial repo, run the following:
+
+```sh
+npm install --save github:facebook/react-native#master
+```
+
+Alternatively, you can clone the repo to your `node_modules` directory and run `npm install` inside the cloned repo.
+
+2. Add `gradle-download-task` as dependency in `andoid/build.gradle`:
+
+```gradle
+...
+    dependencies {
+        classpath 'com.android.tools.build:gradle:1.3.1'
+        classpath 'de.undercouch:gradle-download-task:2.0.0'
+
+        // NOTE: Do not place your application dependencies here; they belong
+        // in the individual module build.gradle files
+    }
+...
+```
+
+3. Add the `:ReactAndroid` project in `andoid/settings.gradle`:
+
+```gradle
+...
+include ':ReactAndroid'
+
+project(':ReactAndroid').projectDir = new File(rootProject.projectDir, '../node_modules/react-native/ReactAndroid')
+...
+```
+
+4. Modify your `android/app/build.gradle` to use the `:ReactAndroid` project instead of the pre-compiled library, e.g. - replace `compile 'com.facebook.react:react-native:0.16.+'` with `compile project(':ReactAndroid')`:
+
+```gradle
+...
+dependencies {
+    compile fileTree(dir: 'libs', include: ['*.jar'])
+    compile 'com.android.support:appcompat-v7:23.0.1'
+
+    compile project(':ReactAndroid')
+
+    ...
+}
+...
+```
+
+5. If you use 3rd-party React Native modules, modify your `android/app/build.gradle` to override their dependencies so that they don't bundle the pre-compiled library, e.g. - replace `compile project(':react-native-custom-module')` with:
+
+```gradle
+compile(project(':react-native-custom-module')) {
+    exclude group: 'com.facebook.react', module: 'react-native'
+}
+```
+
+
+## Additional notes
+
+Building from source can take a long time, especially for the first build, as it needs to download ~200 MB of files and compile JSC etc. Every time you update the `react-native` version from your repo, the build directory may get deleted, and all the files are re-downloaded. To avoid this, you might want to change your build directory path by editing the `~/.gradle/init.gradle ` file:
+
+```gradle
+gradle.projectsLoaded {
+    rootProject.allprojects {
+        buildDir = "/path/to/build/directory/${rootProject.name}/${project.name}"
+    }
+}
+```
diff --git a/docs/AndroidUIPerformance.md b/docs/AndroidUIPerformance.md
index 927ba2131b68..399bd09eefe0 100644
--- a/docs/AndroidUIPerformance.md
+++ b/docs/AndroidUIPerformance.md
@@ -4,7 +4,7 @@ title: Profiling Android UI Performance
 layout: docs
 category: Guides (Android)
 permalink: docs/android-ui-performance.html
-next: activityindicatorios
+next: android-building-from-source
 ---
 
 We try our best to deliver buttery-smooth UI performance by default, but sometimes that just isn't possible. Remember, Android supports 10k+ different phones and is generalized to support software rendering: the framework architecture and need to generalize across many hardware targets unfortunately means you get less for free relative to iOS. But sometimes, there are things you can improve (and many times it's not native code's fault at all!).
@@ -12,7 +12,7 @@ We try our best to deliver buttery-smooth UI performance by default, but sometim
 The first step for debugging this jank is to answer the fundamental question of where your time is being spent during each 16ms frame. For that, we'll be using a standard Android profiling tool called systrace. But first...
 
 > Make sure that JS dev mode is OFF!
-> 
+>
 > You should see `__DEV__ === false, development-level warning are OFF, performance optimizations are ON` in your application logs (which you can view using `adb logcat`)
 
 ## Profiling with Systrace

From c4f882a59fc0c2ef9a15e5d955f74899fef89e87 Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Sun, 29 Nov 2015 10:13:06 +0530
Subject: [PATCH 0151/1411] [Docs] Syntax highlight gradle code

---
 docs/SignedAPKAndroid.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/SignedAPKAndroid.md b/docs/SignedAPKAndroid.md
index 231c82ac89d0..d35e95d82d9d 100644
--- a/docs/SignedAPKAndroid.md
+++ b/docs/SignedAPKAndroid.md
@@ -41,7 +41,7 @@ _Note: Once you publish the app on the Play Store, you will need to republish yo
 
 Edit the file `android/app/build.gradle` in your project folder and add the signing config,
 
-```
+```gradle
 ...
 android {
     ...
@@ -110,7 +110,7 @@ _**IMPORTANT**: Make sure to thoroughly test your app if you've enabled Proguard
 
 To enable Proguard, set `minifyEnabled` to `true`:
 
-```
+```gradle
 ...
 android {
     ...

From 489042456225e1a24a0555ca44fc651574c24941 Mon Sep 17 00:00:00 2001
From: Alexander Blom <blom@fb.com>
Date: Sun, 29 Nov 2015 03:53:49 -0800
Subject: [PATCH 0152/1411] Allow to pass in `ImagePipelineConfig` to
 `FrescoModule`

Summary: This allows an app to configure much more options in Fresco. public

Reviewed By: astreet

Differential Revision: D2700598

fb-gh-sync-id: e1ffff18bff270e14ef82c14f7bfeef984605738
---
 .../react/modules/fresco/FrescoModule.java    | 64 +++++++++++--------
 1 file changed, 36 insertions(+), 28 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java
index 666acc2fe159..3f2302ab9ab4 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/FrescoModule.java
@@ -39,25 +39,26 @@
 public class FrescoModule extends ReactContextBaseJavaModule implements
     ModuleDataCleaner.Cleanable {
 
-  @Nullable private RequestListener mRequestListener;
-  @Nullable private DiskCacheConfig mDiskCacheConfig;
+  private @Nullable ImagePipelineConfig mConfig;
 
   public FrescoModule(ReactApplicationContext reactContext) {
-    super(reactContext);
+    this(reactContext, getDefaultConfig(reactContext, null, null));
   }
 
   public FrescoModule(ReactApplicationContext reactContext, RequestListener listener) {
-    super(reactContext);
-    mRequestListener = listener;
+    this(reactContext, getDefaultConfig(reactContext, listener, null));
   }
 
   public FrescoModule(
       ReactApplicationContext reactContext,
       RequestListener listener,
       DiskCacheConfig diskCacheConfig) {
+    this(reactContext, getDefaultConfig(reactContext, listener, diskCacheConfig));
+  }
+
+  public FrescoModule(ReactApplicationContext reactContext, ImagePipelineConfig config) {
     super(reactContext);
-    mRequestListener = listener;
-    mDiskCacheConfig = diskCacheConfig;
+    mConfig = config;
   }
 
   @Override
@@ -67,27 +68,9 @@ public void initialize() {
     // This code can be removed if using Fresco from Maven rather than from source
     SoLoaderShim.setHandler(new FrescoHandler());
 
-    HashSet<RequestListener> requestListeners = new HashSet<>();
-    requestListeners.add(new SystraceRequestListener());
-    if (mRequestListener != null) {
-      requestListeners.add(mRequestListener);
-    }
-
-    Context context = this.getReactApplicationContext().getApplicationContext();
-    OkHttpClient okHttpClient = OkHttpClientProvider.getOkHttpClient();
-    ImagePipelineConfig.Builder builder =
-        OkHttpImagePipelineConfigFactory.newBuilder(context, okHttpClient);
-
-    builder
-        .setDownsampleEnabled(false)
-        .setRequestListeners(requestListeners);
-
-    if (mDiskCacheConfig != null) {
-      builder.setMainDiskCacheConfig(mDiskCacheConfig);
-    }
-
-    ImagePipelineConfig config = builder.build();
-    Fresco.initialize(context, config);
+    Context context = getReactApplicationContext().getApplicationContext();
+    Fresco.initialize(context, mConfig);
+    mConfig = null;
   }
 
   @Override
@@ -105,6 +88,31 @@ public void clearSensitiveData() {
     imagePipelineFactory.getSmallImageDiskStorageCache().clearAll();
   }
 
+  private static ImagePipelineConfig getDefaultConfig(
+      Context context,
+      @Nullable RequestListener listener,
+      @Nullable DiskCacheConfig diskCacheConfig) {
+    HashSet<RequestListener> requestListeners = new HashSet<>();
+    requestListeners.add(new SystraceRequestListener());
+    if (listener != null) {
+      requestListeners.add(listener);
+    }
+
+    OkHttpClient okHttpClient = OkHttpClientProvider.getOkHttpClient();
+    ImagePipelineConfig.Builder builder =
+        OkHttpImagePipelineConfigFactory.newBuilder(context.getApplicationContext(), okHttpClient);
+
+    builder
+        .setDownsampleEnabled(false)
+        .setRequestListeners(requestListeners);
+
+    if (diskCacheConfig != null) {
+      builder.setMainDiskCacheConfig(diskCacheConfig);
+    }
+
+    return builder.build();
+  }
+
   private static class FrescoHandler implements SoLoaderShim.Handler {
     @Override
     public void loadLibrary(String libraryName) {

From 593a45e31966120318102024615549b337066b13 Mon Sep 17 00:00:00 2001
From: olivier notteghem <oli@fb.com>
Date: Sun, 29 Nov 2015 16:26:13 -0800
Subject: [PATCH 0153/1411] LayoutAnimation support for Android RN

Reviewed By: astreet

Differential Revision: D2217731

fb-gh-sync-id: d990af4b630995f95433690d5dcf510382dc34d2
---
 Examples/UIExplorer/ListViewPagingExample.js  |  10 ++
 .../uimanager/NativeViewHierarchyManager.java |  28 ++++-
 .../react/uimanager/UIManagerModule.java      |  39 ++++++-
 .../react/uimanager/UIViewOperationQueue.java |  42 +++++++
 .../AbstractLayoutAnimation.java              | 108 ++++++++++++++++++
 .../layoutanimation/AnimatedPropertyType.java |  32 ++++++
 .../layoutanimation/BaseLayoutAnimation.java  |  48 ++++++++
 .../layoutanimation/HandlesLayout.java        |  10 ++
 .../layoutanimation/InterpolatorType.java     |  34 ++++++
 .../LayoutAnimationController.java            |  94 +++++++++++++++
 .../layoutanimation/LayoutAnimationType.java  |  22 ++++
 .../LayoutCreateAnimation.java                |  15 +++
 .../LayoutUpdateAnimation.java                |  42 +++++++
 .../layoutanimation/OpacityAnimation.java     |  66 +++++++++++
 .../PositionAndSizeAnimation.java             |  52 +++++++++
 .../SimpleSpringInterpolator.java             |  20 ++++
 .../react/views/view/ReactViewGroup.java      |  11 +-
 17 files changed, 668 insertions(+), 5 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AbstractLayoutAnimation.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AnimatedPropertyType.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/BaseLayoutAnimation.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/HandlesLayout.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/InterpolatorType.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationType.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutCreateAnimation.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutUpdateAnimation.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/OpacityAnimation.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/PositionAndSizeAnimation.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/SimpleSpringInterpolator.java

diff --git a/Examples/UIExplorer/ListViewPagingExample.js b/Examples/UIExplorer/ListViewPagingExample.js
index b82f272c9dbb..7d0ac98f2bfd 100644
--- a/Examples/UIExplorer/ListViewPagingExample.js
+++ b/Examples/UIExplorer/ListViewPagingExample.js
@@ -11,6 +11,7 @@
  * 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.
  *
+ * @provides ListViewPagingExample
  * @flow
  */
 'use strict';
@@ -26,6 +27,11 @@ var {
   View,
 } = React;
 
+var NativeModules = require('NativeModules');
+var {
+  UIManager,
+} = NativeModules;
+
 var PAGE_SIZE = 4;
 var THUMB_URLS = [
   'Thumbnails/like.png',
@@ -48,6 +54,10 @@ var Thumb = React.createClass({
   getInitialState: function() {
     return {thumbIndex: this._getThumbIdx(), dir: 'row'};
   },
+  componentWillMount: function() {
+    UIManager.setLayoutAnimationEnabledExperimental &&
+      UIManager.setLayoutAnimationEnabledExperimental(true);
+  },
   _getThumbIdx: function() {
     return Math.floor(Math.random() * THUMB_URLS.length);
   },
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
index fddd7047820f..744279880b53 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
@@ -29,9 +29,11 @@
 import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
 import com.facebook.react.bridge.SoftAssertions;
 import com.facebook.react.bridge.UiThreadUtil;
 import com.facebook.react.touch.JSResponderHandler;
+import com.facebook.react.uimanager.layoutanimation.LayoutAnimationController;
 
 /**
  * Delegate of {@link UIManagerModule} that owns the native view hierarchy and mapping between
@@ -66,6 +68,9 @@
   private final ViewManagerRegistry mViewManagers;
   private final JSResponderHandler mJSResponderHandler = new JSResponderHandler();
   private final RootViewManager mRootViewManager = new RootViewManager();
+  private final LayoutAnimationController mLayoutAnimator = new LayoutAnimationController();
+
+  private boolean mLayoutAnimationEnabled;
 
   public NativeViewHierarchyManager(ViewManagerRegistry viewManagers) {
     mAnimationRegistry = new AnimationRegistry();
@@ -80,6 +85,10 @@ public AnimationRegistry getAnimationRegistry() {
     return mAnimationRegistry;
   }
 
+  public void setLayoutAnimationEnabled(boolean enabled) {
+    mLayoutAnimationEnabled = enabled;
+  }
+
   public void updateProperties(int tag, CatalystStylesDiffMap props) {
     UiThreadUtil.assertOnUiThread();
 
@@ -154,8 +163,17 @@ public void updateLayout(
       }
       if (parentViewGroupManager != null
           && !parentViewGroupManager.needsCustomLayoutForChildren()) {
-        viewToUpdate.layout(x, y, x + width, y + height);
+        updateLayout(viewToUpdate, x, y, width, height);
       }
+    } else {
+      updateLayout(viewToUpdate, x, y, width, height);
+    }
+  }
+
+  private void updateLayout(View viewToUpdate, int x, int y, int width, int height) {
+    if (mLayoutAnimationEnabled &&
+        mLayoutAnimator.shouldAnimateLayout(viewToUpdate)) {
+      mLayoutAnimator.applyLayoutUpdate(viewToUpdate, x, y, width, height);
     } else {
       viewToUpdate.layout(x, y, x + width, y + height);
     }
@@ -470,6 +488,14 @@ public void clearJSResponder() {
     mJSResponderHandler.clearJSResponder();
   }
 
+  void configureLayoutAnimation(final ReadableMap config) {
+    mLayoutAnimator.initializeFromConfig(config);
+  }
+
+  void clearLayoutAnimation() {
+    mLayoutAnimator.reset();
+  }
+
   /* package */ void startAnimationForNativeView(
       int reactTag,
       Animation animation,
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
index 59fd688e348b..adfd7f3ff906 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
@@ -383,12 +383,45 @@ public void showPopupMenu(int reactTag, ReadableArray items, Callback error, Cal
     mUIImplementation.showPopupMenu(reactTag, items, error, success);
   }
 
+  @ReactMethod
+  public void setMainScrollViewTag(int reactTag) {
+    // TODO(6588266): Implement if required
+  }
+
+  /**
+   * LayoutAnimation API on Android is currently experimental. Therefore, it needs to be enabled
+   * explicitly in order to avoid regression in existing application written for iOS using this API.
+   *
+   * Warning : This method will be removed in future version of React Native, and layout animation
+   * will be enabled by default, so always check for its existence before invoking it.
+   *
+   * TODO(9139831) : remove this method once layout animation is fully stable.
+   *
+   * @param enabled whether layout animation is enabled or not
+   */
+  @ReactMethod
+  public void setLayoutAnimationEnabledExperimental(boolean enabled) {
+    mOperationsQueue.enqueueSetLayoutAnimationEnabled(enabled);
+  }
+
+  /**
+   * Configure an animation to be used for the native layout changes, and native views
+   * creation. The animation will only apply during the current batch operations.
+   *
+   * TODO(7728153) : animating view deletion is currently not supported.
+   * TODO(7613721) : callbacks are not supported, this feature will likely be killed.
+   *
+   * @param config the configuration of the animation for view addition/removal/update.
+   * @param success will be called when the animation completes, or when the animation get
+   *        interrupted. In this case, callback parameter will be false.
+   * @param error will be called if there was an error processing the animation
+   */
   @ReactMethod
   public void configureNextLayoutAnimation(
       ReadableMap config,
-      Callback successCallback,
-      Callback errorCallback) {
-    // TODO(6588266): Implement if required
+      Callback success,
+      Callback error) {
+    mOperationsQueue.enqueueConfigureLayoutAnimation(config, success, error);
   }
 
   /**
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
index ed507fd3ec63..a8dc4aefdeeb 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
@@ -23,6 +23,7 @@
 import com.facebook.react.bridge.SoftAssertions;
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
 import com.facebook.react.bridge.UiThreadUtil;
 import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
 import com.facebook.systrace.Systrace;
@@ -322,6 +323,32 @@ public void execute() {
     }
   }
 
+  private class SetLayoutAnimationEnabledOperation implements UIOperation {
+    private final boolean mEnabled;
+
+    private SetLayoutAnimationEnabledOperation(final boolean enabled) {
+      mEnabled = enabled;
+    }
+
+    @Override
+    public void execute() {
+      mNativeViewHierarchyManager.setLayoutAnimationEnabled(mEnabled);
+    }
+  }
+
+  private class ConfigureLayoutAnimationOperation implements UIOperation {
+    private final ReadableMap mConfig;
+
+    private ConfigureLayoutAnimationOperation(final ReadableMap config) {
+      mConfig = config;
+    }
+
+    @Override
+    public void execute() {
+      mNativeViewHierarchyManager.configureLayoutAnimation(mConfig);
+    }
+  }
+
   private final class MeasureOperation implements UIOperation {
 
     private final int mReactTag;
@@ -576,6 +603,18 @@ public void enqueueRemoveAnimation(int animationID) {
     mOperations.add(new RemoveAnimationOperation(animationID));
   }
 
+  public void enqueueSetLayoutAnimationEnabled(
+      final boolean enabled) {
+    mOperations.add(new SetLayoutAnimationEnabledOperation(enabled));
+  }
+
+  public void enqueueConfigureLayoutAnimation(
+      final ReadableMap config,
+      final Callback onSuccess,
+      final Callback onError) {
+    mOperations.add(new ConfigureLayoutAnimationOperation(config));
+  }
+
   public void enqueueMeasure(
       final int reactTag,
       final Callback callback) {
@@ -672,6 +711,9 @@ public void doFrameGuarded(long frameTimeNanos) {
           mDispatchUIRunnables.get(i).run();
         }
         mDispatchUIRunnables.clear();
+
+        // Clear layout animation, as animation only apply to current UI operations batch.
+        mNativeViewHierarchyManager.clearLayoutAnimation();
       }
 
       ReactChoreographer.getInstance().postFrameCallback(
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AbstractLayoutAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AbstractLayoutAnimation.java
new file mode 100644
index 000000000000..c29d7ae0bef9
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AbstractLayoutAnimation.java
@@ -0,0 +1,108 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+import javax.annotation.Nullable;
+
+import java.util.Map;
+
+import android.view.View;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.Animation;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
+
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.common.MapBuilder;
+import com.facebook.react.uimanager.IllegalViewOperationException;
+
+/**
+ * Class responsible for parsing and converting layout animation data into native {@link Animation}
+ * in order to animate layout when a valid configuration has been supplied by the application.
+ */
+/* package */ abstract class AbstractLayoutAnimation {
+
+  // Forces animation to be playing 10x slower, used for debug purposes.
+  private static final boolean SLOWDOWN_ANIMATION_MODE = false;
+
+  abstract boolean isValid();
+
+  /**
+   * Create an animation object for the current animation type, based on the view and final screen
+   * coordinates. If the application-supplied configuraiton does not specify an animation definition
+   * for this types, or if the animation definition is invalid, returns null.
+   */
+  abstract @Nullable Animation createAnimationImpl(View view, int x, int y, int width, int height);
+
+  private static final Map<InterpolatorType, Interpolator> INTERPOLATOR = MapBuilder.of(
+      InterpolatorType.LINEAR, new LinearInterpolator(),
+      InterpolatorType.EASE_IN, new AccelerateInterpolator(),
+      InterpolatorType.EASE_OUT, new DecelerateInterpolator(),
+      InterpolatorType.EASE_IN_EASE_OUT, new AccelerateDecelerateInterpolator(),
+      InterpolatorType.SPRING, new SimpleSpringInterpolator());
+
+  private @Nullable Interpolator mInterpolator;
+  private int mDelayMs;
+
+  protected @Nullable AnimatedPropertyType mAnimatedProperty;
+  protected int mDurationMs;
+
+  public void reset() {
+    mAnimatedProperty = null;
+    mDurationMs = 0;
+    mDelayMs = 0;
+    mInterpolator = null;
+  }
+
+  public void initializeFromConfig(ReadableMap data, int globalDuration) {
+    mAnimatedProperty = data.hasKey("property") ?
+        AnimatedPropertyType.fromString(data.getString("property")) : null;
+    mDurationMs = data.hasKey("duration") ? data.getInt("duration") : globalDuration;
+    mDelayMs = data.hasKey("delay") ? data.getInt("delay") : 0;
+    mInterpolator = data.hasKey("type") ?
+        getInterpolator(InterpolatorType.fromString(data.getString("type"))) : null;
+
+    if (!isValid()) {
+      throw new IllegalViewOperationException("Invalid layout animation : " + data);
+    }
+  }
+
+  /**
+   * Create an animation object to be used to animate the view, based on the animation config
+   * supplied at initialization time and the new view position and size.
+   *
+   * @param view the view to create the animation for
+   * @param x the new X position for the view
+   * @param y the new Y position for the view
+   * @param width the new width value for the view
+   * @param height the new height value for the view
+   */
+   public final @Nullable Animation createAnimation(
+       View view,
+       int x,
+       int y,
+       int width,
+       int height) {
+    if (!isValid()) {
+      return null;
+    }
+    Animation animation = createAnimationImpl(view, x, y, width, height);
+    if (animation != null) {
+      int slowdownFactor = SLOWDOWN_ANIMATION_MODE ? 10 : 1;
+      animation.setDuration(mDurationMs * slowdownFactor);
+      animation.setStartOffset(mDelayMs * slowdownFactor);
+      animation.setInterpolator(mInterpolator);
+    }
+    return animation;
+  }
+
+  private static Interpolator getInterpolator(InterpolatorType type) {
+    Interpolator interpolator = INTERPOLATOR.get(type);
+    if (interpolator == null) {
+      throw new IllegalArgumentException("Missing interpolator for type : " + type);
+    }
+    return interpolator;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AnimatedPropertyType.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AnimatedPropertyType.java
new file mode 100644
index 000000000000..51a9d246c061
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AnimatedPropertyType.java
@@ -0,0 +1,32 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+/**
+ * Enum representing the different view properties that can be used when animating layout for
+ * view creation.
+ */
+/* package */ enum AnimatedPropertyType {
+  OPACITY("opacity"),
+  SCALE_XY("scaleXY");
+
+  private final String mName;
+
+  private AnimatedPropertyType(String name) {
+    mName = name;
+  }
+
+  public static AnimatedPropertyType fromString(String name) {
+    for (AnimatedPropertyType property : AnimatedPropertyType.values()) {
+      if (property.toString().equalsIgnoreCase(name)) {
+        return property;
+      }
+    }
+    throw new IllegalArgumentException("Unsupported animated property : " + name);
+  }
+
+  @Override
+  public String toString() {
+    return mName;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/BaseLayoutAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/BaseLayoutAnimation.java
new file mode 100644
index 000000000000..9d3d0f45aa79
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/BaseLayoutAnimation.java
@@ -0,0 +1,48 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.ScaleAnimation;
+
+import com.facebook.react.uimanager.IllegalViewOperationException;
+
+/**
+ * Class responsible for default layout animation, i.e animation of view creation and deletion.
+ */
+/* package */ abstract class BaseLayoutAnimation extends AbstractLayoutAnimation {
+
+  abstract boolean isReverse();
+
+  @Override
+  boolean isValid() {
+    return mDurationMs > 0 && mAnimatedProperty != null;
+  }
+
+  @Override
+  Animation createAnimationImpl(View view, int x, int y, int width, int height) {
+    float fromValue = isReverse() ? 1.0f : 0.0f;
+    float toValue = isReverse() ? 0.0f : 1.0f;
+    if (mAnimatedProperty != null) {
+      switch (mAnimatedProperty) {
+        case OPACITY:
+          return new OpacityAnimation(view, fromValue, toValue);
+        case SCALE_XY:
+          return new ScaleAnimation(
+              fromValue,
+              toValue,
+              fromValue,
+              toValue,
+              Animation.RELATIVE_TO_PARENT,
+              .5f,
+              Animation.RELATIVE_TO_PARENT,
+              .5f);
+        default:
+          throw new IllegalViewOperationException(
+              "Missing animation for property : " + mAnimatedProperty);
+      }
+    }
+    throw new IllegalViewOperationException("Missing animated property from animation config");
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/HandlesLayout.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/HandlesLayout.java
new file mode 100644
index 000000000000..9f3c907e97d0
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/HandlesLayout.java
@@ -0,0 +1,10 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+/**
+ * Marker interface to indicate a given animation type takes care of updating the view layout.
+ */
+/* package */ interface HandleLayout {
+
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/InterpolatorType.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/InterpolatorType.java
new file mode 100644
index 000000000000..f59675a8fbe1
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/InterpolatorType.java
@@ -0,0 +1,34 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+/**
+ * Enum representing the different interpolators that can be used in layout animation configuration.
+ */
+/* package */ enum InterpolatorType {
+  LINEAR("linear"),
+  EASE_IN("easeIn"),
+  EASE_OUT("easeOut"),
+  EASE_IN_EASE_OUT("easeInEaseOut"),
+  SPRING("spring");
+
+  private final String mName;
+
+  private InterpolatorType(String name) {
+    mName = name;
+  }
+
+  public static InterpolatorType fromString(String name) {
+    for (InterpolatorType type : InterpolatorType.values()) {
+      if (type.toString().equalsIgnoreCase(name)) {
+        return type;
+      }
+    }
+    throw new IllegalArgumentException("Unsupported interpolation type : " + name);
+  }
+
+  @Override
+  public String toString() {
+    return mName;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java
new file mode 100644
index 000000000000..d3522947fd36
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java
@@ -0,0 +1,94 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.NotThreadSafe;
+
+import android.view.View;
+import android.view.animation.Animation;
+
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.UiThreadUtil;
+
+/**
+ * Class responsible for animation layout changes, if a valid layout animation config has been
+ * supplied. If not animation is available, layout change is applied immediately instead of
+ * performing an animation.
+ *
+ * TODO(7613721): Invoke success callback at the end of animation and when animation gets cancelled.
+ */
+@NotThreadSafe
+public class LayoutAnimationController {
+
+  private static final boolean ENABLED = true;
+
+  private final AbstractLayoutAnimation mLayoutCreateAnimation = new LayoutCreateAnimation();
+  private final AbstractLayoutAnimation mLayoutUpdateAnimation = new LayoutUpdateAnimation();
+  private boolean mShouldAnimateLayout;
+
+  public void initializeFromConfig(final @Nullable ReadableMap config) {
+    if (!ENABLED) {
+      return;
+    }
+
+    if (config == null) {
+      reset();
+      return;
+    }
+
+    mShouldAnimateLayout = false;
+    int globalDuration = config.hasKey("duration") ? config.getInt("duration") : 0;
+    if (config.hasKey(LayoutAnimationType.CREATE.toString())) {
+      mLayoutCreateAnimation.initializeFromConfig(
+          config.getMap(LayoutAnimationType.CREATE.toString()), globalDuration);
+      mShouldAnimateLayout = true;
+    }
+    if (config.hasKey(LayoutAnimationType.UPDATE.toString())) {
+      mLayoutUpdateAnimation.initializeFromConfig(
+          config.getMap(LayoutAnimationType.UPDATE.toString()), globalDuration);
+      mShouldAnimateLayout = true;
+    }
+  }
+
+  public void reset() {
+    mLayoutCreateAnimation.reset();
+    mLayoutUpdateAnimation.reset();
+    mShouldAnimateLayout = false;
+  }
+
+  public boolean shouldAnimateLayout(View viewToAnimate) {
+    // if view parent is null, skip animation: view have been clipped, we don't want animation to
+    // resume when view is re-attached to parent, which is the standard android animation behavior.
+    return mShouldAnimateLayout && viewToAnimate.getParent() != null;
+  }
+
+  /**
+   * Update layout of given view, via immediate update or animation depending on the current batch
+   * layout animation configuration supplied during initialization.
+   *
+   * @param view the view to update layout of
+   * @param x the new X position for the view
+   * @param y the new Y position for the view
+   * @param width the new width value for the view
+   * @param height the new height value for the view
+   */
+  public void applyLayoutUpdate(View view, int x, int y, int width, int height) {
+    UiThreadUtil.assertOnUiThread();
+
+    // Determine which animation to use : if view is initially invisible, use create animation.
+    // If view is becoming invisible, use delete animation. Otherwise, use update animation.
+    // This approach is easier than maintaining a list of tags for recently created/deleted views.
+    AbstractLayoutAnimation layoutAnimation = (view.getWidth() == 0 || view.getHeight() == 0) ?
+        mLayoutCreateAnimation :
+        mLayoutUpdateAnimation;
+
+    Animation animation = layoutAnimation.createAnimation(view, x, y, width, height);
+    if (animation == null || !(animation instanceof HandleLayout)) {
+      view.layout(x, y, x + width, y + height);
+    }
+    if (animation != null) {
+      view.startAnimation(animation);
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationType.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationType.java
new file mode 100644
index 000000000000..0f3d9d7fdb2b
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationType.java
@@ -0,0 +1,22 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+/**
+ * Enum representing the different animation type that can be specified in layout animation config.
+ */
+/* package */ enum LayoutAnimationType {
+  CREATE("create"),
+  UPDATE("update");
+
+  private final String mName;
+
+  private LayoutAnimationType(String name) {
+    mName = name;
+  }
+
+  @Override
+  public String toString() {
+    return mName;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutCreateAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutCreateAnimation.java
new file mode 100644
index 000000000000..a989e625c675
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutCreateAnimation.java
@@ -0,0 +1,15 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+/**
+ * Class responsible for handling layout view creation animation, applied to view whenever a
+ * valid config was supplied for the layout animation of CREATE type.
+ */
+/* package */ class LayoutCreateAnimation extends BaseLayoutAnimation {
+
+  @Override
+  boolean isReverse() {
+    return false;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutUpdateAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutUpdateAnimation.java
new file mode 100644
index 000000000000..8189716f729d
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutUpdateAnimation.java
@@ -0,0 +1,42 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+import javax.annotation.Nullable;
+
+import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.TranslateAnimation;
+
+/**
+ * Class responsible for handling layout update animation, applied to view whenever a valid config
+ * was supplied for the layout animation of UPDATE type.
+ */
+/* package */ class LayoutUpdateAnimation extends AbstractLayoutAnimation {
+
+  // We are currently not enabling translation GPU-accelerated animated, as it creates odd
+  // artifacts with native react scrollview. This needs to be investigated.
+  private static final boolean USE_TRANSLATE_ANIMATION = false;
+
+  @Override
+  boolean isValid() {
+    return mDurationMs > 0;
+  }
+
+  @Override
+  @Nullable Animation createAnimationImpl(View view, int x, int y, int width, int height) {
+    boolean animateLocation = view.getX() != x || view.getY() != y;
+    boolean animateSize = view.getWidth() != width || view.getHeight() != height;
+    if (!animateLocation && !animateSize) {
+      return null;
+    } else if (animateLocation && !animateSize && USE_TRANSLATE_ANIMATION) {
+      // Use GPU-accelerated animation, however we loose the ability to resume interrupted
+      // animation where it was left off. We may be able to listen to animation interruption
+      // and set the layout manually in this case, so that next animation kicks off smoothly.
+      return new TranslateAnimation(view.getX() - x, 0, view.getY() - y, 0);
+    } else {
+      // Animation is sub-optimal for perf, but scale transformation can't be use in this case.
+      return new PositionAndSizeAnimation(view, x, y, width, height);
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/OpacityAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/OpacityAnimation.java
new file mode 100644
index 000000000000..a7ad690023c5
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/OpacityAnimation.java
@@ -0,0 +1,66 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.Transformation;
+
+/**
+ * Animation responsible for updating opacity of a view. It should ideally use hardware texture
+ * to optimize rendering performances.
+ */
+/* package */ class OpacityAnimation extends Animation {
+
+  static class OpacityAnimationListener implements AnimationListener {
+
+    private final View mView;
+    private boolean mLayerTypeChanged = false;
+
+    public OpacityAnimationListener(View view) {
+      mView = view;
+    }
+
+    @Override
+    public void onAnimationStart(Animation animation) {
+      if (mView.hasOverlappingRendering() &&
+          mView.getLayerType() == View.LAYER_TYPE_NONE) {
+        mLayerTypeChanged = true;
+        mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+      }
+    }
+
+    @Override
+    public void onAnimationEnd(Animation animation) {
+      if (mLayerTypeChanged) {
+        mView.setLayerType(View.LAYER_TYPE_NONE, null);
+      }
+    }
+
+    @Override
+    public void onAnimationRepeat(Animation animation) {
+      // do nothing
+    }
+  }
+
+  private final View mView;
+  private final float mStartOpacity, mDeltaOpacity;
+
+  public OpacityAnimation(View view, float startOpacity, float endOpacity) {
+    mView = view;
+    mStartOpacity = startOpacity;
+    mDeltaOpacity = endOpacity - startOpacity;
+
+    setAnimationListener(new OpacityAnimationListener(view));
+  }
+
+  @Override
+  protected void applyTransformation(float interpolatedTime, Transformation t) {
+    mView.setAlpha(mStartOpacity + mDeltaOpacity * interpolatedTime);
+  }
+
+  @Override
+  public boolean willChangeBounds() {
+    return false;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/PositionAndSizeAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/PositionAndSizeAnimation.java
new file mode 100644
index 000000000000..2adf81a6bb6c
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/PositionAndSizeAnimation.java
@@ -0,0 +1,52 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.Transformation;
+
+/**
+ * Animation responsible for updating size and position of a view. We can't use scaling as view
+ * content may not necessarily stretch. As a result, this approach is inefficient because of
+ * layout passes occurring on every frame.
+ * What we might want to try to do instead is use a combined ScaleAnimation and TranslateAnimation.
+ */
+/* package */ class PositionAndSizeAnimation extends Animation implements HandleLayout {
+
+  private final View mView;
+  private final float mStartX, mStartY, mDeltaX, mDeltaY;
+  private final int mStartWidth, mStartHeight, mDeltaWidth, mDeltaHeight;
+
+  public PositionAndSizeAnimation(View view, int x, int y, int width, int height) {
+    mView = view;
+
+    mStartX = view.getX();
+    mStartY = view.getY();
+    mStartWidth = view.getWidth();
+    mStartHeight = view.getHeight();
+
+    mDeltaX = x - mStartX;
+    mDeltaY = y - mStartY;
+    mDeltaWidth = width - mStartWidth;
+    mDeltaHeight = height - mStartHeight;
+  }
+
+  @Override
+  protected void applyTransformation(float interpolatedTime, Transformation t) {
+    float newX = mStartX + mDeltaX * interpolatedTime;
+    float newY = mStartY + mDeltaY * interpolatedTime;
+    float newWidth = mStartWidth + mDeltaWidth * interpolatedTime;
+    float newHeight = mStartHeight + mDeltaHeight * interpolatedTime;
+    mView.layout(
+        Math.round(newX),
+        Math.round(newY),
+        Math.round(newX + newWidth),
+        Math.round(newY + newHeight));
+  }
+
+  @Override
+  public boolean willChangeBounds() {
+    return true;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/SimpleSpringInterpolator.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/SimpleSpringInterpolator.java
new file mode 100644
index 000000000000..9696fe90a1a3
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/SimpleSpringInterpolator.java
@@ -0,0 +1,20 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+import android.view.animation.Interpolator;
+
+/**
+ * Simple spring interpolator
+ */
+//TODO(7613736): Improve spring interpolator with friction and damping variable support
+/* package */  class SimpleSpringInterpolator implements Interpolator {
+
+  private static final float FACTOR = 0.5f;
+
+  @Override
+  public float getInterpolation(float input) {
+    return (float)
+        (1 + Math.pow(2, -10 * input) * Math.sin((input - FACTOR / 4) * Math.PI * 2 / FACTOR));
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
index 134b6492b9bf..9e2728db4e1e 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
@@ -16,6 +16,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
+import android.view.animation.Animation;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
@@ -286,7 +287,15 @@ private void updateSubviewClipStatus(Rect clippingRect, int idx, int clippedSoFa
     boolean intersects = clippingRect
         .intersects(sHelperRect.left, sHelperRect.top, sHelperRect.right, sHelperRect.bottom);
     boolean needUpdateClippingRecursive = false;
-    if (!intersects && child.getParent() != null) {
+    // We never want to clip children that are being animated, as this can easily break layout :
+    // when layout animation changes size and/or position of views contained inside a listview that
+    // clips offscreen children, we need to ensure that, when view exits the viewport, final size
+    // and position is set prior to removing the view from its listview parent.
+    // Otherwise, when view gets re-attached again, i.e when it re-enters the viewport after scroll,
+    // it won't be size and located properly.
+    Animation animation = child.getAnimation();
+    boolean isAnimating = animation != null && !animation.hasEnded();
+    if (!intersects && child.getParent() != null && !isAnimating) {
       // We can try saving on invalidate call here as the view that we remove is out of visible area
       // therefore invalidation is not necessary.
       super.removeViewsInLayout(idx - clippedSoFar, 1);

From e8e7a2db57c26923522390deb9200fbb678b4cce Mon Sep 17 00:00:00 2001
From: Der-Nien Lee <dernienl@fb.com>
Date: Sun, 29 Nov 2015 17:22:04 -0800
Subject: [PATCH 0154/1411] @build-break revert of D2217731

Differential Revision: D2702368

fb-gh-sync-id: 64f53168610c5bf5f3dc22cd7e4dd6b4bb620b4c
---
 Examples/UIExplorer/ListViewPagingExample.js  |  10 --
 .../uimanager/NativeViewHierarchyManager.java |  28 +----
 .../react/uimanager/UIManagerModule.java      |  39 +------
 .../react/uimanager/UIViewOperationQueue.java |  42 -------
 .../AbstractLayoutAnimation.java              | 108 ------------------
 .../layoutanimation/AnimatedPropertyType.java |  32 ------
 .../layoutanimation/BaseLayoutAnimation.java  |  48 --------
 .../layoutanimation/HandlesLayout.java        |  10 --
 .../layoutanimation/InterpolatorType.java     |  34 ------
 .../LayoutAnimationController.java            |  94 ---------------
 .../layoutanimation/LayoutAnimationType.java  |  22 ----
 .../LayoutCreateAnimation.java                |  15 ---
 .../LayoutUpdateAnimation.java                |  42 -------
 .../layoutanimation/OpacityAnimation.java     |  66 -----------
 .../PositionAndSizeAnimation.java             |  52 ---------
 .../SimpleSpringInterpolator.java             |  20 ----
 .../react/views/view/ReactViewGroup.java      |  11 +-
 17 files changed, 5 insertions(+), 668 deletions(-)
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AbstractLayoutAnimation.java
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AnimatedPropertyType.java
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/BaseLayoutAnimation.java
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/HandlesLayout.java
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/InterpolatorType.java
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationType.java
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutCreateAnimation.java
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutUpdateAnimation.java
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/OpacityAnimation.java
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/PositionAndSizeAnimation.java
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/SimpleSpringInterpolator.java

diff --git a/Examples/UIExplorer/ListViewPagingExample.js b/Examples/UIExplorer/ListViewPagingExample.js
index 7d0ac98f2bfd..b82f272c9dbb 100644
--- a/Examples/UIExplorer/ListViewPagingExample.js
+++ b/Examples/UIExplorer/ListViewPagingExample.js
@@ -11,7 +11,6 @@
  * 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.
  *
- * @provides ListViewPagingExample
  * @flow
  */
 'use strict';
@@ -27,11 +26,6 @@ var {
   View,
 } = React;
 
-var NativeModules = require('NativeModules');
-var {
-  UIManager,
-} = NativeModules;
-
 var PAGE_SIZE = 4;
 var THUMB_URLS = [
   'Thumbnails/like.png',
@@ -54,10 +48,6 @@ var Thumb = React.createClass({
   getInitialState: function() {
     return {thumbIndex: this._getThumbIdx(), dir: 'row'};
   },
-  componentWillMount: function() {
-    UIManager.setLayoutAnimationEnabledExperimental &&
-      UIManager.setLayoutAnimationEnabledExperimental(true);
-  },
   _getThumbIdx: function() {
     return Math.floor(Math.random() * THUMB_URLS.length);
   },
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
index 744279880b53..fddd7047820f 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
@@ -29,11 +29,9 @@
 import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReadableArray;
-import com.facebook.react.bridge.ReadableMap;
 import com.facebook.react.bridge.SoftAssertions;
 import com.facebook.react.bridge.UiThreadUtil;
 import com.facebook.react.touch.JSResponderHandler;
-import com.facebook.react.uimanager.layoutanimation.LayoutAnimationController;
 
 /**
  * Delegate of {@link UIManagerModule} that owns the native view hierarchy and mapping between
@@ -68,9 +66,6 @@
   private final ViewManagerRegistry mViewManagers;
   private final JSResponderHandler mJSResponderHandler = new JSResponderHandler();
   private final RootViewManager mRootViewManager = new RootViewManager();
-  private final LayoutAnimationController mLayoutAnimator = new LayoutAnimationController();
-
-  private boolean mLayoutAnimationEnabled;
 
   public NativeViewHierarchyManager(ViewManagerRegistry viewManagers) {
     mAnimationRegistry = new AnimationRegistry();
@@ -85,10 +80,6 @@ public AnimationRegistry getAnimationRegistry() {
     return mAnimationRegistry;
   }
 
-  public void setLayoutAnimationEnabled(boolean enabled) {
-    mLayoutAnimationEnabled = enabled;
-  }
-
   public void updateProperties(int tag, CatalystStylesDiffMap props) {
     UiThreadUtil.assertOnUiThread();
 
@@ -163,17 +154,8 @@ public void updateLayout(
       }
       if (parentViewGroupManager != null
           && !parentViewGroupManager.needsCustomLayoutForChildren()) {
-        updateLayout(viewToUpdate, x, y, width, height);
+        viewToUpdate.layout(x, y, x + width, y + height);
       }
-    } else {
-      updateLayout(viewToUpdate, x, y, width, height);
-    }
-  }
-
-  private void updateLayout(View viewToUpdate, int x, int y, int width, int height) {
-    if (mLayoutAnimationEnabled &&
-        mLayoutAnimator.shouldAnimateLayout(viewToUpdate)) {
-      mLayoutAnimator.applyLayoutUpdate(viewToUpdate, x, y, width, height);
     } else {
       viewToUpdate.layout(x, y, x + width, y + height);
     }
@@ -488,14 +470,6 @@ public void clearJSResponder() {
     mJSResponderHandler.clearJSResponder();
   }
 
-  void configureLayoutAnimation(final ReadableMap config) {
-    mLayoutAnimator.initializeFromConfig(config);
-  }
-
-  void clearLayoutAnimation() {
-    mLayoutAnimator.reset();
-  }
-
   /* package */ void startAnimationForNativeView(
       int reactTag,
       Animation animation,
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
index adfd7f3ff906..59fd688e348b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
@@ -383,45 +383,12 @@ public void showPopupMenu(int reactTag, ReadableArray items, Callback error, Cal
     mUIImplementation.showPopupMenu(reactTag, items, error, success);
   }
 
-  @ReactMethod
-  public void setMainScrollViewTag(int reactTag) {
-    // TODO(6588266): Implement if required
-  }
-
-  /**
-   * LayoutAnimation API on Android is currently experimental. Therefore, it needs to be enabled
-   * explicitly in order to avoid regression in existing application written for iOS using this API.
-   *
-   * Warning : This method will be removed in future version of React Native, and layout animation
-   * will be enabled by default, so always check for its existence before invoking it.
-   *
-   * TODO(9139831) : remove this method once layout animation is fully stable.
-   *
-   * @param enabled whether layout animation is enabled or not
-   */
-  @ReactMethod
-  public void setLayoutAnimationEnabledExperimental(boolean enabled) {
-    mOperationsQueue.enqueueSetLayoutAnimationEnabled(enabled);
-  }
-
-  /**
-   * Configure an animation to be used for the native layout changes, and native views
-   * creation. The animation will only apply during the current batch operations.
-   *
-   * TODO(7728153) : animating view deletion is currently not supported.
-   * TODO(7613721) : callbacks are not supported, this feature will likely be killed.
-   *
-   * @param config the configuration of the animation for view addition/removal/update.
-   * @param success will be called when the animation completes, or when the animation get
-   *        interrupted. In this case, callback parameter will be false.
-   * @param error will be called if there was an error processing the animation
-   */
   @ReactMethod
   public void configureNextLayoutAnimation(
       ReadableMap config,
-      Callback success,
-      Callback error) {
-    mOperationsQueue.enqueueConfigureLayoutAnimation(config, success, error);
+      Callback successCallback,
+      Callback errorCallback) {
+    // TODO(6588266): Implement if required
   }
 
   /**
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
index a8dc4aefdeeb..ed507fd3ec63 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
@@ -23,7 +23,6 @@
 import com.facebook.react.bridge.SoftAssertions;
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReadableArray;
-import com.facebook.react.bridge.ReadableMap;
 import com.facebook.react.bridge.UiThreadUtil;
 import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
 import com.facebook.systrace.Systrace;
@@ -323,32 +322,6 @@ public void execute() {
     }
   }
 
-  private class SetLayoutAnimationEnabledOperation implements UIOperation {
-    private final boolean mEnabled;
-
-    private SetLayoutAnimationEnabledOperation(final boolean enabled) {
-      mEnabled = enabled;
-    }
-
-    @Override
-    public void execute() {
-      mNativeViewHierarchyManager.setLayoutAnimationEnabled(mEnabled);
-    }
-  }
-
-  private class ConfigureLayoutAnimationOperation implements UIOperation {
-    private final ReadableMap mConfig;
-
-    private ConfigureLayoutAnimationOperation(final ReadableMap config) {
-      mConfig = config;
-    }
-
-    @Override
-    public void execute() {
-      mNativeViewHierarchyManager.configureLayoutAnimation(mConfig);
-    }
-  }
-
   private final class MeasureOperation implements UIOperation {
 
     private final int mReactTag;
@@ -603,18 +576,6 @@ public void enqueueRemoveAnimation(int animationID) {
     mOperations.add(new RemoveAnimationOperation(animationID));
   }
 
-  public void enqueueSetLayoutAnimationEnabled(
-      final boolean enabled) {
-    mOperations.add(new SetLayoutAnimationEnabledOperation(enabled));
-  }
-
-  public void enqueueConfigureLayoutAnimation(
-      final ReadableMap config,
-      final Callback onSuccess,
-      final Callback onError) {
-    mOperations.add(new ConfigureLayoutAnimationOperation(config));
-  }
-
   public void enqueueMeasure(
       final int reactTag,
       final Callback callback) {
@@ -711,9 +672,6 @@ public void doFrameGuarded(long frameTimeNanos) {
           mDispatchUIRunnables.get(i).run();
         }
         mDispatchUIRunnables.clear();
-
-        // Clear layout animation, as animation only apply to current UI operations batch.
-        mNativeViewHierarchyManager.clearLayoutAnimation();
       }
 
       ReactChoreographer.getInstance().postFrameCallback(
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AbstractLayoutAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AbstractLayoutAnimation.java
deleted file mode 100644
index c29d7ae0bef9..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AbstractLayoutAnimation.java
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-package com.facebook.react.uimanager.layoutanimation;
-
-import javax.annotation.Nullable;
-
-import java.util.Map;
-
-import android.view.View;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.Animation;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
-
-import com.facebook.react.bridge.ReadableMap;
-import com.facebook.react.common.MapBuilder;
-import com.facebook.react.uimanager.IllegalViewOperationException;
-
-/**
- * Class responsible for parsing and converting layout animation data into native {@link Animation}
- * in order to animate layout when a valid configuration has been supplied by the application.
- */
-/* package */ abstract class AbstractLayoutAnimation {
-
-  // Forces animation to be playing 10x slower, used for debug purposes.
-  private static final boolean SLOWDOWN_ANIMATION_MODE = false;
-
-  abstract boolean isValid();
-
-  /**
-   * Create an animation object for the current animation type, based on the view and final screen
-   * coordinates. If the application-supplied configuraiton does not specify an animation definition
-   * for this types, or if the animation definition is invalid, returns null.
-   */
-  abstract @Nullable Animation createAnimationImpl(View view, int x, int y, int width, int height);
-
-  private static final Map<InterpolatorType, Interpolator> INTERPOLATOR = MapBuilder.of(
-      InterpolatorType.LINEAR, new LinearInterpolator(),
-      InterpolatorType.EASE_IN, new AccelerateInterpolator(),
-      InterpolatorType.EASE_OUT, new DecelerateInterpolator(),
-      InterpolatorType.EASE_IN_EASE_OUT, new AccelerateDecelerateInterpolator(),
-      InterpolatorType.SPRING, new SimpleSpringInterpolator());
-
-  private @Nullable Interpolator mInterpolator;
-  private int mDelayMs;
-
-  protected @Nullable AnimatedPropertyType mAnimatedProperty;
-  protected int mDurationMs;
-
-  public void reset() {
-    mAnimatedProperty = null;
-    mDurationMs = 0;
-    mDelayMs = 0;
-    mInterpolator = null;
-  }
-
-  public void initializeFromConfig(ReadableMap data, int globalDuration) {
-    mAnimatedProperty = data.hasKey("property") ?
-        AnimatedPropertyType.fromString(data.getString("property")) : null;
-    mDurationMs = data.hasKey("duration") ? data.getInt("duration") : globalDuration;
-    mDelayMs = data.hasKey("delay") ? data.getInt("delay") : 0;
-    mInterpolator = data.hasKey("type") ?
-        getInterpolator(InterpolatorType.fromString(data.getString("type"))) : null;
-
-    if (!isValid()) {
-      throw new IllegalViewOperationException("Invalid layout animation : " + data);
-    }
-  }
-
-  /**
-   * Create an animation object to be used to animate the view, based on the animation config
-   * supplied at initialization time and the new view position and size.
-   *
-   * @param view the view to create the animation for
-   * @param x the new X position for the view
-   * @param y the new Y position for the view
-   * @param width the new width value for the view
-   * @param height the new height value for the view
-   */
-   public final @Nullable Animation createAnimation(
-       View view,
-       int x,
-       int y,
-       int width,
-       int height) {
-    if (!isValid()) {
-      return null;
-    }
-    Animation animation = createAnimationImpl(view, x, y, width, height);
-    if (animation != null) {
-      int slowdownFactor = SLOWDOWN_ANIMATION_MODE ? 10 : 1;
-      animation.setDuration(mDurationMs * slowdownFactor);
-      animation.setStartOffset(mDelayMs * slowdownFactor);
-      animation.setInterpolator(mInterpolator);
-    }
-    return animation;
-  }
-
-  private static Interpolator getInterpolator(InterpolatorType type) {
-    Interpolator interpolator = INTERPOLATOR.get(type);
-    if (interpolator == null) {
-      throw new IllegalArgumentException("Missing interpolator for type : " + type);
-    }
-    return interpolator;
-  }
-}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AnimatedPropertyType.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AnimatedPropertyType.java
deleted file mode 100644
index 51a9d246c061..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AnimatedPropertyType.java
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-package com.facebook.react.uimanager.layoutanimation;
-
-/**
- * Enum representing the different view properties that can be used when animating layout for
- * view creation.
- */
-/* package */ enum AnimatedPropertyType {
-  OPACITY("opacity"),
-  SCALE_XY("scaleXY");
-
-  private final String mName;
-
-  private AnimatedPropertyType(String name) {
-    mName = name;
-  }
-
-  public static AnimatedPropertyType fromString(String name) {
-    for (AnimatedPropertyType property : AnimatedPropertyType.values()) {
-      if (property.toString().equalsIgnoreCase(name)) {
-        return property;
-      }
-    }
-    throw new IllegalArgumentException("Unsupported animated property : " + name);
-  }
-
-  @Override
-  public String toString() {
-    return mName;
-  }
-}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/BaseLayoutAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/BaseLayoutAnimation.java
deleted file mode 100644
index 9d3d0f45aa79..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/BaseLayoutAnimation.java
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-package com.facebook.react.uimanager.layoutanimation;
-
-import android.view.View;
-import android.view.animation.Animation;
-import android.view.animation.ScaleAnimation;
-
-import com.facebook.react.uimanager.IllegalViewOperationException;
-
-/**
- * Class responsible for default layout animation, i.e animation of view creation and deletion.
- */
-/* package */ abstract class BaseLayoutAnimation extends AbstractLayoutAnimation {
-
-  abstract boolean isReverse();
-
-  @Override
-  boolean isValid() {
-    return mDurationMs > 0 && mAnimatedProperty != null;
-  }
-
-  @Override
-  Animation createAnimationImpl(View view, int x, int y, int width, int height) {
-    float fromValue = isReverse() ? 1.0f : 0.0f;
-    float toValue = isReverse() ? 0.0f : 1.0f;
-    if (mAnimatedProperty != null) {
-      switch (mAnimatedProperty) {
-        case OPACITY:
-          return new OpacityAnimation(view, fromValue, toValue);
-        case SCALE_XY:
-          return new ScaleAnimation(
-              fromValue,
-              toValue,
-              fromValue,
-              toValue,
-              Animation.RELATIVE_TO_PARENT,
-              .5f,
-              Animation.RELATIVE_TO_PARENT,
-              .5f);
-        default:
-          throw new IllegalViewOperationException(
-              "Missing animation for property : " + mAnimatedProperty);
-      }
-    }
-    throw new IllegalViewOperationException("Missing animated property from animation config");
-  }
-}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/HandlesLayout.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/HandlesLayout.java
deleted file mode 100644
index 9f3c907e97d0..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/HandlesLayout.java
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-package com.facebook.react.uimanager.layoutanimation;
-
-/**
- * Marker interface to indicate a given animation type takes care of updating the view layout.
- */
-/* package */ interface HandleLayout {
-
-}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/InterpolatorType.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/InterpolatorType.java
deleted file mode 100644
index f59675a8fbe1..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/InterpolatorType.java
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-package com.facebook.react.uimanager.layoutanimation;
-
-/**
- * Enum representing the different interpolators that can be used in layout animation configuration.
- */
-/* package */ enum InterpolatorType {
-  LINEAR("linear"),
-  EASE_IN("easeIn"),
-  EASE_OUT("easeOut"),
-  EASE_IN_EASE_OUT("easeInEaseOut"),
-  SPRING("spring");
-
-  private final String mName;
-
-  private InterpolatorType(String name) {
-    mName = name;
-  }
-
-  public static InterpolatorType fromString(String name) {
-    for (InterpolatorType type : InterpolatorType.values()) {
-      if (type.toString().equalsIgnoreCase(name)) {
-        return type;
-      }
-    }
-    throw new IllegalArgumentException("Unsupported interpolation type : " + name);
-  }
-
-  @Override
-  public String toString() {
-    return mName;
-  }
-}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java
deleted file mode 100644
index d3522947fd36..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-package com.facebook.react.uimanager.layoutanimation;
-
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.NotThreadSafe;
-
-import android.view.View;
-import android.view.animation.Animation;
-
-import com.facebook.react.bridge.ReadableMap;
-import com.facebook.react.bridge.UiThreadUtil;
-
-/**
- * Class responsible for animation layout changes, if a valid layout animation config has been
- * supplied. If not animation is available, layout change is applied immediately instead of
- * performing an animation.
- *
- * TODO(7613721): Invoke success callback at the end of animation and when animation gets cancelled.
- */
-@NotThreadSafe
-public class LayoutAnimationController {
-
-  private static final boolean ENABLED = true;
-
-  private final AbstractLayoutAnimation mLayoutCreateAnimation = new LayoutCreateAnimation();
-  private final AbstractLayoutAnimation mLayoutUpdateAnimation = new LayoutUpdateAnimation();
-  private boolean mShouldAnimateLayout;
-
-  public void initializeFromConfig(final @Nullable ReadableMap config) {
-    if (!ENABLED) {
-      return;
-    }
-
-    if (config == null) {
-      reset();
-      return;
-    }
-
-    mShouldAnimateLayout = false;
-    int globalDuration = config.hasKey("duration") ? config.getInt("duration") : 0;
-    if (config.hasKey(LayoutAnimationType.CREATE.toString())) {
-      mLayoutCreateAnimation.initializeFromConfig(
-          config.getMap(LayoutAnimationType.CREATE.toString()), globalDuration);
-      mShouldAnimateLayout = true;
-    }
-    if (config.hasKey(LayoutAnimationType.UPDATE.toString())) {
-      mLayoutUpdateAnimation.initializeFromConfig(
-          config.getMap(LayoutAnimationType.UPDATE.toString()), globalDuration);
-      mShouldAnimateLayout = true;
-    }
-  }
-
-  public void reset() {
-    mLayoutCreateAnimation.reset();
-    mLayoutUpdateAnimation.reset();
-    mShouldAnimateLayout = false;
-  }
-
-  public boolean shouldAnimateLayout(View viewToAnimate) {
-    // if view parent is null, skip animation: view have been clipped, we don't want animation to
-    // resume when view is re-attached to parent, which is the standard android animation behavior.
-    return mShouldAnimateLayout && viewToAnimate.getParent() != null;
-  }
-
-  /**
-   * Update layout of given view, via immediate update or animation depending on the current batch
-   * layout animation configuration supplied during initialization.
-   *
-   * @param view the view to update layout of
-   * @param x the new X position for the view
-   * @param y the new Y position for the view
-   * @param width the new width value for the view
-   * @param height the new height value for the view
-   */
-  public void applyLayoutUpdate(View view, int x, int y, int width, int height) {
-    UiThreadUtil.assertOnUiThread();
-
-    // Determine which animation to use : if view is initially invisible, use create animation.
-    // If view is becoming invisible, use delete animation. Otherwise, use update animation.
-    // This approach is easier than maintaining a list of tags for recently created/deleted views.
-    AbstractLayoutAnimation layoutAnimation = (view.getWidth() == 0 || view.getHeight() == 0) ?
-        mLayoutCreateAnimation :
-        mLayoutUpdateAnimation;
-
-    Animation animation = layoutAnimation.createAnimation(view, x, y, width, height);
-    if (animation == null || !(animation instanceof HandleLayout)) {
-      view.layout(x, y, x + width, y + height);
-    }
-    if (animation != null) {
-      view.startAnimation(animation);
-    }
-  }
-}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationType.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationType.java
deleted file mode 100644
index 0f3d9d7fdb2b..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationType.java
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-package com.facebook.react.uimanager.layoutanimation;
-
-/**
- * Enum representing the different animation type that can be specified in layout animation config.
- */
-/* package */ enum LayoutAnimationType {
-  CREATE("create"),
-  UPDATE("update");
-
-  private final String mName;
-
-  private LayoutAnimationType(String name) {
-    mName = name;
-  }
-
-  @Override
-  public String toString() {
-    return mName;
-  }
-}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutCreateAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutCreateAnimation.java
deleted file mode 100644
index a989e625c675..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutCreateAnimation.java
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-package com.facebook.react.uimanager.layoutanimation;
-
-/**
- * Class responsible for handling layout view creation animation, applied to view whenever a
- * valid config was supplied for the layout animation of CREATE type.
- */
-/* package */ class LayoutCreateAnimation extends BaseLayoutAnimation {
-
-  @Override
-  boolean isReverse() {
-    return false;
-  }
-}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutUpdateAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutUpdateAnimation.java
deleted file mode 100644
index 8189716f729d..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutUpdateAnimation.java
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-package com.facebook.react.uimanager.layoutanimation;
-
-import javax.annotation.Nullable;
-
-import android.view.View;
-import android.view.animation.Animation;
-import android.view.animation.TranslateAnimation;
-
-/**
- * Class responsible for handling layout update animation, applied to view whenever a valid config
- * was supplied for the layout animation of UPDATE type.
- */
-/* package */ class LayoutUpdateAnimation extends AbstractLayoutAnimation {
-
-  // We are currently not enabling translation GPU-accelerated animated, as it creates odd
-  // artifacts with native react scrollview. This needs to be investigated.
-  private static final boolean USE_TRANSLATE_ANIMATION = false;
-
-  @Override
-  boolean isValid() {
-    return mDurationMs > 0;
-  }
-
-  @Override
-  @Nullable Animation createAnimationImpl(View view, int x, int y, int width, int height) {
-    boolean animateLocation = view.getX() != x || view.getY() != y;
-    boolean animateSize = view.getWidth() != width || view.getHeight() != height;
-    if (!animateLocation && !animateSize) {
-      return null;
-    } else if (animateLocation && !animateSize && USE_TRANSLATE_ANIMATION) {
-      // Use GPU-accelerated animation, however we loose the ability to resume interrupted
-      // animation where it was left off. We may be able to listen to animation interruption
-      // and set the layout manually in this case, so that next animation kicks off smoothly.
-      return new TranslateAnimation(view.getX() - x, 0, view.getY() - y, 0);
-    } else {
-      // Animation is sub-optimal for perf, but scale transformation can't be use in this case.
-      return new PositionAndSizeAnimation(view, x, y, width, height);
-    }
-  }
-}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/OpacityAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/OpacityAnimation.java
deleted file mode 100644
index a7ad690023c5..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/OpacityAnimation.java
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-package com.facebook.react.uimanager.layoutanimation;
-
-import android.view.View;
-import android.view.animation.Animation;
-import android.view.animation.Transformation;
-
-/**
- * Animation responsible for updating opacity of a view. It should ideally use hardware texture
- * to optimize rendering performances.
- */
-/* package */ class OpacityAnimation extends Animation {
-
-  static class OpacityAnimationListener implements AnimationListener {
-
-    private final View mView;
-    private boolean mLayerTypeChanged = false;
-
-    public OpacityAnimationListener(View view) {
-      mView = view;
-    }
-
-    @Override
-    public void onAnimationStart(Animation animation) {
-      if (mView.hasOverlappingRendering() &&
-          mView.getLayerType() == View.LAYER_TYPE_NONE) {
-        mLayerTypeChanged = true;
-        mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-      }
-    }
-
-    @Override
-    public void onAnimationEnd(Animation animation) {
-      if (mLayerTypeChanged) {
-        mView.setLayerType(View.LAYER_TYPE_NONE, null);
-      }
-    }
-
-    @Override
-    public void onAnimationRepeat(Animation animation) {
-      // do nothing
-    }
-  }
-
-  private final View mView;
-  private final float mStartOpacity, mDeltaOpacity;
-
-  public OpacityAnimation(View view, float startOpacity, float endOpacity) {
-    mView = view;
-    mStartOpacity = startOpacity;
-    mDeltaOpacity = endOpacity - startOpacity;
-
-    setAnimationListener(new OpacityAnimationListener(view));
-  }
-
-  @Override
-  protected void applyTransformation(float interpolatedTime, Transformation t) {
-    mView.setAlpha(mStartOpacity + mDeltaOpacity * interpolatedTime);
-  }
-
-  @Override
-  public boolean willChangeBounds() {
-    return false;
-  }
-}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/PositionAndSizeAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/PositionAndSizeAnimation.java
deleted file mode 100644
index 2adf81a6bb6c..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/PositionAndSizeAnimation.java
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-package com.facebook.react.uimanager.layoutanimation;
-
-import android.view.View;
-import android.view.animation.Animation;
-import android.view.animation.Transformation;
-
-/**
- * Animation responsible for updating size and position of a view. We can't use scaling as view
- * content may not necessarily stretch. As a result, this approach is inefficient because of
- * layout passes occurring on every frame.
- * What we might want to try to do instead is use a combined ScaleAnimation and TranslateAnimation.
- */
-/* package */ class PositionAndSizeAnimation extends Animation implements HandleLayout {
-
-  private final View mView;
-  private final float mStartX, mStartY, mDeltaX, mDeltaY;
-  private final int mStartWidth, mStartHeight, mDeltaWidth, mDeltaHeight;
-
-  public PositionAndSizeAnimation(View view, int x, int y, int width, int height) {
-    mView = view;
-
-    mStartX = view.getX();
-    mStartY = view.getY();
-    mStartWidth = view.getWidth();
-    mStartHeight = view.getHeight();
-
-    mDeltaX = x - mStartX;
-    mDeltaY = y - mStartY;
-    mDeltaWidth = width - mStartWidth;
-    mDeltaHeight = height - mStartHeight;
-  }
-
-  @Override
-  protected void applyTransformation(float interpolatedTime, Transformation t) {
-    float newX = mStartX + mDeltaX * interpolatedTime;
-    float newY = mStartY + mDeltaY * interpolatedTime;
-    float newWidth = mStartWidth + mDeltaWidth * interpolatedTime;
-    float newHeight = mStartHeight + mDeltaHeight * interpolatedTime;
-    mView.layout(
-        Math.round(newX),
-        Math.round(newY),
-        Math.round(newX + newWidth),
-        Math.round(newY + newHeight));
-  }
-
-  @Override
-  public boolean willChangeBounds() {
-    return true;
-  }
-}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/SimpleSpringInterpolator.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/SimpleSpringInterpolator.java
deleted file mode 100644
index 9696fe90a1a3..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/SimpleSpringInterpolator.java
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-package com.facebook.react.uimanager.layoutanimation;
-
-import android.view.animation.Interpolator;
-
-/**
- * Simple spring interpolator
- */
-//TODO(7613736): Improve spring interpolator with friction and damping variable support
-/* package */  class SimpleSpringInterpolator implements Interpolator {
-
-  private static final float FACTOR = 0.5f;
-
-  @Override
-  public float getInterpolation(float input) {
-    return (float)
-        (1 + Math.pow(2, -10 * input) * Math.sin((input - FACTOR / 4) * Math.PI * 2 / FACTOR));
-  }
-}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
index 9e2728db4e1e..134b6492b9bf 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
@@ -16,7 +16,6 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
-import android.view.animation.Animation;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
@@ -287,15 +286,7 @@ private void updateSubviewClipStatus(Rect clippingRect, int idx, int clippedSoFa
     boolean intersects = clippingRect
         .intersects(sHelperRect.left, sHelperRect.top, sHelperRect.right, sHelperRect.bottom);
     boolean needUpdateClippingRecursive = false;
-    // We never want to clip children that are being animated, as this can easily break layout :
-    // when layout animation changes size and/or position of views contained inside a listview that
-    // clips offscreen children, we need to ensure that, when view exits the viewport, final size
-    // and position is set prior to removing the view from its listview parent.
-    // Otherwise, when view gets re-attached again, i.e when it re-enters the viewport after scroll,
-    // it won't be size and located properly.
-    Animation animation = child.getAnimation();
-    boolean isAnimating = animation != null && !animation.hasEnded();
-    if (!intersects && child.getParent() != null && !isAnimating) {
+    if (!intersects && child.getParent() != null) {
       // We can try saving on invalidate call here as the view that we remove is out of visible area
       // therefore invalidation is not necessary.
       super.removeViewsInLayout(idx - clippedSoFar, 1);

From 3dca8cf9fdd864b1359fc7276bf98cb154c3e360 Mon Sep 17 00:00:00 2001
From: Denis Koroskin <dkoroskin@fb.com>
Date: Sun, 29 Nov 2015 22:24:36 -0800
Subject: [PATCH 0155/1411] Add UIImplementationProvider and allow overriding
 it in AbstractReactActivity

Summary: public UIImplementationProvider allows plugging in an alternative UIImplementation. A follow up diff adds a toggle under FB Dev Settings and uses this class to control an implementation. This allows us experimenting with other ways of generating UI hierarchy from JavaScript components.

Reviewed By: astreet

Differential Revision: D2554774

fb-gh-sync-id: 6574a893020e3519bd2ab00b9620a6dbdfaed595
---
 .../facebook/react/CoreModulesPackage.java    | 11 ++++++---
 .../facebook/react/ReactInstanceManager.java  | 21 ++++++++++++++--
 .../react/ReactInstanceManagerImpl.java       |  8 +++++--
 .../uimanager/UIImplementationProvider.java   | 24 +++++++++++++++++++
 .../react/uimanager/UIManagerModule.java      |  9 -------
 5 files changed, 57 insertions(+), 16 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementationProvider.java

diff --git a/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java b/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java
index 5dd7b1959e88..b770b3b756d9 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java
@@ -28,7 +28,7 @@
 import com.facebook.react.modules.systeminfo.AndroidInfoModule;
 import com.facebook.react.uimanager.AppRegistry;
 import com.facebook.react.uimanager.ReactNative;
-import com.facebook.react.uimanager.UIImplementation;
+import com.facebook.react.uimanager.UIImplementationProvider;
 import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.ViewManager;
 import com.facebook.react.uimanager.debug.DebugComponentOwnershipModule;
@@ -44,12 +44,15 @@
 
   private final ReactInstanceManager mReactInstanceManager;
   private final DefaultHardwareBackBtnHandler mHardwareBackBtnHandler;
+  private final UIImplementationProvider mUIImplementationProvider;
 
   CoreModulesPackage(
       ReactInstanceManager reactInstanceManager,
-      DefaultHardwareBackBtnHandler hardwareBackBtnHandler) {
+      DefaultHardwareBackBtnHandler hardwareBackBtnHandler,
+      UIImplementationProvider uiImplementationProvider) {
     mReactInstanceManager = reactInstanceManager;
     mHardwareBackBtnHandler = hardwareBackBtnHandler;
+    mUIImplementationProvider = uiImplementationProvider;
   }
 
   @Override
@@ -63,7 +66,9 @@ public List<NativeModule> createNativeModules(
       uiManagerModule = new UIManagerModule(
           catalystApplicationContext,
           viewManagersList,
-          new UIImplementation(catalystApplicationContext, viewManagersList));
+          mUIImplementationProvider.createUIImplementation(
+              catalystApplicationContext,
+              viewManagersList));
     } finally {
       Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
     }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
index 609b320fc9e8..2449c28ea491 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
@@ -25,6 +25,7 @@
 import com.facebook.react.common.annotations.VisibleForTesting;
 import com.facebook.react.devsupport.DevSupportManager;
 import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
+import com.facebook.react.uimanager.UIImplementationProvider;
 import com.facebook.react.uimanager.ViewManager;
 
 /**
@@ -140,13 +141,23 @@ public static class Builder {
     protected @Nullable Application mApplication;
     protected boolean mUseDeveloperSupport;
     protected @Nullable LifecycleState mInitialLifecycleState;
+    protected @Nullable UIImplementationProvider mUIImplementationProvider;
 
     protected Builder() {
     }
 
+    /**
+     * Sets a provider of {@link UIImplementation}.
+     * Uses default provider if null is passed.
+     */
+    public Builder setUIImplementationProvider(
+        @Nullable UIImplementationProvider uiImplementationProvider) {
+      mUIImplementationProvider = uiImplementationProvider;
+      return this;
+    }
+
     /**
      * Name of the JS bundle file to be loaded from application's raw assets.
-     *
      * Example: {@code "index.android.js"}
      */
     public Builder setBundleAssetName(String bundleAssetName) {
@@ -231,6 +242,11 @@ public ReactInstanceManager build() {
           mJSMainModuleName != null || mJSBundleFile != null,
           "Either MainModuleName or JS Bundle File needs to be provided");
 
+      if (mUIImplementationProvider == null) {
+        // create default UIImplementationProvider if the provided one is null.
+        mUIImplementationProvider = new UIImplementationProvider();
+      }
+
       return new ReactInstanceManagerImpl(
           Assertions.assertNotNull(
               mApplication,
@@ -240,7 +256,8 @@ public ReactInstanceManager build() {
           mPackages,
           mUseDeveloperSupport,
           mBridgeIdleDebugListener,
-          Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"));
+          Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"),
+          mUIImplementationProvider);
     }
   }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index deb6bf21c29b..c97a55b067fe 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -52,6 +52,7 @@
 import com.facebook.react.modules.core.DeviceEventManagerModule;
 import com.facebook.react.uimanager.AppRegistry;
 import com.facebook.react.uimanager.ReactNative;
+import com.facebook.react.uimanager.UIImplementationProvider;
 import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.ViewManager;
 import com.facebook.soloader.SoLoader;
@@ -95,6 +96,7 @@
   private String mSourceUrl;
   private @Nullable Activity mCurrentActivity;
   private volatile boolean mHasStartedCreatingInitialContext = false;
+  private final UIImplementationProvider mUIImplementationProvider;
 
   private final ReactInstanceDevCommandsHandler mDevInterface =
       new ReactInstanceDevCommandsHandler() {
@@ -189,7 +191,8 @@ protected void onPostExecute(ReactApplicationContext reactContext) {
       List<ReactPackage> packages,
       boolean useDeveloperSupport,
       @Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener,
-      LifecycleState initialLifecycleState) {
+      LifecycleState initialLifecycleState,
+      UIImplementationProvider uiImplementationProvider) {
     initializeSoLoaderIfNecessary(applicationContext);
 
     mApplicationContext = applicationContext;
@@ -208,6 +211,7 @@ protected void onPostExecute(ReactApplicationContext reactContext) {
         useDeveloperSupport);
     mBridgeIdleDebugListener = bridgeIdleDebugListener;
     mLifecycleState = initialLifecycleState;
+    mUIImplementationProvider = uiImplementationProvider;
   }
 
   @Override
@@ -597,7 +601,7 @@ private ReactApplicationContext createReactContext(
         "createAndProcessCoreModulesPackage");
     try {
       CoreModulesPackage coreModulesPackage =
-          new CoreModulesPackage(this, mBackBtnHandler);
+          new CoreModulesPackage(this, mBackBtnHandler, mUIImplementationProvider);
       processPackage(coreModulesPackage, reactContext, nativeRegistryBuilder, jsModulesBuilder);
     } finally {
       Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementationProvider.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementationProvider.java
new file mode 100644
index 000000000000..3d1a4a2f39cd
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementationProvider.java
@@ -0,0 +1,24 @@
+/**
+ * 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.
+ */
+package com.facebook.react.uimanager;
+
+import java.util.List;
+
+import com.facebook.react.bridge.ReactApplicationContext;
+
+/**
+ * Provides UIImplementation to use in {@link UIManagerModule}.
+ */
+public class UIImplementationProvider {
+  public UIImplementation createUIImplementation(
+      ReactApplicationContext reactContext,
+      List<ViewManager> viewManagers) {
+    return new UIImplementation(reactContext, viewManagers);
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
index 59fd688e348b..b60598569bf0 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
@@ -78,15 +78,6 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements
   private int mNextRootViewTag = 1;
   private int mBatchId = 0;
 
-  /**
-   * This contructor is temporarily here to workaround Sandcastle error.
-   */
-  public UIManagerModule(
-      ReactApplicationContext reactContext,
-      List<ViewManager> viewManagerList) {
-    this(reactContext, viewManagerList, new UIImplementation(reactContext, viewManagerList));
-  }
-
   public UIManagerModule(
       ReactApplicationContext reactContext,
       List<ViewManager> viewManagerList,

From c9dd4015f1ff50ce433b036be8459ab1366eb07b Mon Sep 17 00:00:00 2001
From: mkonicek pr tester <martinkonicek@centrum.cz>
Date: Mon, 30 Nov 2015 04:25:55 -0800
Subject: [PATCH 0156/1411] Better error handling in Android Geolocation module
 (PR 2)

Summary: Just a testing PR for the shipit bot (please don't close :))
Closes https://github.com/facebook/react-native/pull/4355

Reviewed By: svcscm

Differential Revision: D2702784

Pulled By: mkonicek

fb-gh-sync-id: 867c65dcea486750ca65a8437b37a0f658538111
---
 .../modules/location/LocationModule.java      | 50 +++++++++----------
 1 file changed, 23 insertions(+), 27 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/location/LocationModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/location/LocationModule.java
index 188a45905642..9973563fc120 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/location/LocationModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/location/LocationModule.java
@@ -107,28 +107,25 @@ public void getCurrentPosition(
       Callback error) {
     LocationOptions locationOptions = LocationOptions.fromReactMap(options);
 
-    LocationManager locationManager =
-        (LocationManager) getReactApplicationContext().getSystemService(Context.LOCATION_SERVICE);
-    String provider = getValidProvider(locationManager, locationOptions.highAccuracy);
-    if (provider == null) {
-      error.invoke("No available location provider.");
-      return;
-    }
-
-    Location location = null;
     try {
-      location = locationManager.getLastKnownLocation(provider);
+      LocationManager locationManager =
+          (LocationManager) getReactApplicationContext().getSystemService(Context.LOCATION_SERVICE);
+      String provider = getValidProvider(locationManager, locationOptions.highAccuracy);
+      if (provider == null) {
+        error.invoke("No available location provider.");
+        return;
+      }
+      Location location = locationManager.getLastKnownLocation(provider);
+      if (location != null &&
+          SystemClock.currentTimeMillis() - location.getTime() < locationOptions.maximumAge) {
+        success.invoke(locationToMap(location));
+        return;
+      }
+      new SingleUpdateRequest(locationManager, provider, locationOptions.timeout, success, error)
+          .invoke();
     } catch (SecurityException e) {
       throwLocationPermissionMissing(e);
     }
-    if (location != null &&
-        SystemClock.currentTimeMillis() - location.getTime() < locationOptions.maximumAge) {
-      success.invoke(locationToMap(location));
-      return;
-    }
-
-    new SingleUpdateRequest(locationManager, provider, locationOptions.timeout, success, error)
-        .invoke();
   }
 
   /**
@@ -143,24 +140,23 @@ public void startObserving(ReadableMap options) {
       return;
     }
     LocationOptions locationOptions = LocationOptions.fromReactMap(options);
-    LocationManager locationManager =
-        (LocationManager) getReactApplicationContext().getSystemService(Context.LOCATION_SERVICE);
-    String provider = getValidProvider(locationManager, locationOptions.highAccuracy);
-    if (provider == null) {
-      emitError("No location provider available.");
-      return;
-    }
 
     try {
+      LocationManager locationManager =
+          (LocationManager) getReactApplicationContext().getSystemService(Context.LOCATION_SERVICE);
+      String provider = getValidProvider(locationManager, locationOptions.highAccuracy);
+      if (provider == null) {
+        emitError("No location provider available.");
+        return;
+      }
       if (!provider.equals(mWatchedProvider)) {
         locationManager.removeUpdates(mLocationListener);
         locationManager.requestLocationUpdates(provider, 1000, 0, mLocationListener);
       }
+      mWatchedProvider = provider;
     } catch (SecurityException e) {
       throwLocationPermissionMissing(e);
     }
-
-    mWatchedProvider = provider;
   }
 
   /**

From c63de5e2a58df1ecf16b4be62a9c314b2770b627 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Mon, 30 Nov 2015 05:07:43 -0800
Subject: [PATCH 0157/1411] Fixed MapView crash on iOS 8 and earlier

Summary: public

[MKPinAnnotationView redPinColor] is only supported on iOS 9 and later. This caused React Native to crash on iOS 8 and earlier.

This fixes the crash by providing a forked implementation for different OS versions.

Reviewed By: tadeuzagallo, javache

Differential Revision: D2702737

fb-gh-sync-id: cd8984f1f3d42989001f3c571e325f1b4ba09ac8
---
 Libraries/Components/MapView/MapView.js | 10 ++++-
 React/Views/RCTMapManager.m             | 56 +++++++++++++++++++++++--
 2 files changed, 60 insertions(+), 6 deletions(-)

diff --git a/Libraries/Components/MapView/MapView.js b/Libraries/Components/MapView/MapView.js
index 9324a2aeca43..2dc4fdf30895 100644
--- a/Libraries/Components/MapView/MapView.js
+++ b/Libraries/Components/MapView/MapView.js
@@ -219,6 +219,10 @@ var MapView = React.createClass({
        * The pin color. This can be any valid color string, or you can use one
        * of the predefined PinColors constants. Applies to both standard pins
        * and custom pin images.
+       *
+       * Note that on iOS 8 and earlier, only the standard PinColor constants
+       * are supported for regualr pins. For custom pin images, any tintColor
+       * value is supported on all iOS versions.
        * @platform ios
        */
       tintColor: React.PropTypes.string,
@@ -373,8 +377,10 @@ var MapView = React.createClass({
 
 /**
  * Standard iOS MapView pin color constants, to be used with the
- * `annotation.tintColor` property. You are not obliged to use these,
- * but they are useful for matching the standard iOS look and feel.
+ * `annotation.tintColor` property. On iOS 8 and earlier these are the
+ * only supported values when using regular pins. On iOS 9 and later
+ * you are not obliged to use these, but they are useful for matching
+ * the standard iOS look and feel.
  */
 let PinColors = RCTMapConstants && RCTMapConstants.PinColors;
 MapView.PinColors = PinColors && {
diff --git a/React/Views/RCTMapManager.m b/React/Views/RCTMapManager.m
index 6c22c6b16c4a..e662d486829f 100644
--- a/React/Views/RCTMapManager.m
+++ b/React/Views/RCTMapManager.m
@@ -23,6 +23,24 @@
 
 static NSString *const RCTMapViewKey = @"MapView";
 
+#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0
+
+static NSString *const RCTMapPinRed = @"#ff3b30";
+static NSString *const RCTMapPinGreen = @"#4cd964";
+static NSString *const RCTMapPinPurple = @"#c969e0";
+
+@implementation RCTConvert (MKPinAnnotationColor)
+
+RCT_ENUM_CONVERTER(MKPinAnnotationColor, (@{
+  RCTMapPinRed: @(MKPinAnnotationColorRed),
+  RCTMapPinGreen: @(MKPinAnnotationColorGreen),
+  RCTMapPinPurple: @(MKPinAnnotationColorPurple)
+}), MKPinAnnotationColorRed, unsignedIntegerValue)
+
+@end
+
+#endif
+
 @interface RCTMapManager() <MKMapViewDelegate>
 
 @end
@@ -60,11 +78,29 @@ - (UIView *)view
 
 - (NSDictionary<NSString *, id> *)constantsToExport
 {
+  NSString *red, *green, *purple;
+
+#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0
+
+  if (![MKPinAnnotationView respondsToSelector:@selector(redPinColor)]) {
+    red = RCTMapPinRed;
+    green = RCTMapPinGreen;
+    purple = RCTMapPinPurple;
+  } else
+
+#endif
+
+  {
+    red = RCTColorToHexString([MKPinAnnotationView redPinColor].CGColor);
+    green = RCTColorToHexString([MKPinAnnotationView greenPinColor].CGColor);
+    purple = RCTColorToHexString([MKPinAnnotationView purplePinColor].CGColor);
+  }
+
   return @{
     @"PinColors": @{
-      @"RED": RCTColorToHexString([MKPinAnnotationView redPinColor].CGColor),
-      @"GREEN": RCTColorToHexString([MKPinAnnotationView greenPinColor].CGColor),
-      @"PURPLE": RCTColorToHexString([MKPinAnnotationView purplePinColor].CGColor),
+      @"RED": red,
+      @"GREEN": green,
+      @"PURPLE": purple,
     }
   };
 }
@@ -127,7 +163,19 @@ - (MKAnnotationView *)mapView:(__unused MKMapView *)mapView viewForAnnotation:(R
     NSString *reuseIdentifier = NSStringFromClass([MKPinAnnotationView class]);
     annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseIdentifier] ?: [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
     ((MKPinAnnotationView *)annotationView).animatesDrop = annotation.animateDrop;
-    ((MKPinAnnotationView *)annotationView).pinTintColor = annotation.tintColor ?: [MKPinAnnotationView redPinColor];
+
+#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0
+
+    if (![annotationView respondsToSelector:@selector(pinTintColor)]) {
+      NSString *hexColor = annotation.tintColor ? RCTColorToHexString(annotation.tintColor.CGColor) : RCTMapPinRed;
+      ((MKPinAnnotationView *)annotationView).pinColor = [RCTConvert MKPinAnnotationColor:hexColor];
+    } else
+
+#endif
+
+    {
+      ((MKPinAnnotationView *)annotationView).pinTintColor = annotation.tintColor ?: [MKPinAnnotationView redPinColor];
+    }
   }
   annotationView.canShowCallout = true;
 

From c852e73f5a488a4c560df47a69f198730f1834c8 Mon Sep 17 00:00:00 2001
From: Pawel Sienkowski <sienkowski@fb.com>
Date: Fri, 20 Nov 2015 15:18:43 -0500
Subject: [PATCH 0158/1411] [docs] A guide coverin communication between native
 and RN on IOS. WARNING: I was not able to run the website locally because of
 a bug, so please test it before merging

---
 docs/CommunicationIOS.md | 218 +++++++++++++++++++++++++++++++++++++++
 docs/EmbeddedAppIOS.md   |   2 +-
 2 files changed, 219 insertions(+), 1 deletion(-)
 create mode 100644 docs/CommunicationIOS.md

diff --git a/docs/CommunicationIOS.md b/docs/CommunicationIOS.md
new file mode 100644
index 000000000000..686cf0059055
--- /dev/null
+++ b/docs/CommunicationIOS.md
@@ -0,0 +1,218 @@
+---
+id: communication-ios
+title: Communication between native and React Native
+layout: docs
+category: Guides (iOS)
+permalink: docs/communication-ios.html
+next: native-modules-android
+---
+
+In [Integrating with Existing Apps guide](http://facebook.github.io/react-native/docs/embedded-app-ios.html) and [Native UI Components guide](https://facebook.github.io/react-native/docs/native-components-ios.html) we learn how to embed React Native in a native component and vice versa. When we mix native and React Native components, we'll eventually find a need to communicate between these two worlds. Some ways to achieve that have been already mentioned in other guides. This article summarizes available techniques.
+
+## Introduction
+
+React Native is inspired by React, so the basic idea of the information flow is similar. The flow in React is one-directional. We maintain a hierarchy of components, in which each component depends only on its parent and own internal state. We do this with properties: data is passed from a parent to its children in a top-down manner.If we have an ancestor component that rely on the state of its descendant, the recommended solution would be to pass down a callback that would be used by the descendant to update the ancestor.
+
+The same concept applies to React Native. As long as we are building our application purely within the framework, we can drive our app with properties and callbacks. But, when we mix React Native and native components, we need some special, cross-language mechanisms that would allow us to pass information between them.
+
+## Properties
+
+Properties are the simplest way of cross-component communication. So we need a way to pass properties both from native to React Native, and from React Native to native.
+
+### Passing properties from native to React Native
+
+In order to embed a React Native view in a native component, we use `RCTRootView`. `RCTRootView` is a `UIView` that holds a React Native app. It also provides an interface between native side and the hosted app.
+
+`RCTRootView` has an initializer that allows you to pass arbitrary properties down to the React Native app. The `initialProperties` parameter has to be an instance of `NSDictionary`. The dictionary is internally converted into a JSON object that the top-level JS component can reference.
+
+```
+NSArray *imageList = @[@"http://foo.com/bar1.png",
+                       @"http://foo.com/bar2.png"];
+
+NSDictionary *props = @{@"images" : imageList};
+
+RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
+                                                 moduleName:@"ImageBrowserApp"
+                                          initialProperties:props];
+```
+
+```
+'use strict';
+
+var React = require('react-native');
+  var {
+  View,
+  Image
+} = React;
+
+class ImageBrowserApp extends React.Component {
+  renderImage: function(imgURI) {
+    return (
+      <Image source={{uri: imgURI}} />
+    );
+  },
+  render() {
+    return (
+      <View>
+        {this.props.imageList.map(this.renderImage)}
+      </View>
+    );
+  }
+}
+
+React.AppRegistry.registerComponent('ImageBrowserApp', () => ImageBrowserApp);
+```
+
+`RCTRootView` also provides a read-write property `appProperties`. After `appProperties` is set, the React Native app is re-rendered with new properties. The update is only performed when the new updated properties differ from the previous ones.
+
+```
+NSArray *imageList = @[@"http://foo.com/bar3.png",
+                       @"http://foo.com/bar4.png"];
+
+rootView.appProperties = @{@"images" : imageList};
+```
+
+It is fine to update properties anytime. However, updates have to be performed on the main thread. You use the getter on any thread.
+
+There is no way to update only a few properties at a time. We suggest that you build it into your own wrapper instead.
+
+> ***Note:***
+> Currently, JS functions `componentWillReceiveProps` and `componentWillUpdateProps` of the top level RN component will not be called after a prop update. However, you can access the new props in `componentWillMount` function.
+
+### Passing properties from React Native to native
+The problem exposing properties of native components is covered in detail in [this article](https://facebook.github.io/react-native/docs/native-components-ios.html#properties). In short, export properties with `RCT_CUSTOM_VIEW_PROPERTY` macro in your custom native component, then just use them in React Native as if the component was an ordinary React Native component.
+
+### Limits of properties
+
+The main drawback of cross-language properties is that they do not support callbacks, which would allow us to handle bottom-up data bindings. Imagine you have a small RN view that you want to be removed from the native parent view as a result of a JS action. There is no way to do that with props, as the information would need to go bottom-up.
+
+Although we have a flavor of cross-language callbacks ([described here](https://facebook.github.io/react-native/docs/native-modules-ios.html#callbacks)), these callbacks are not always the thing we need. The main problem is that they are not intended to be passed as properties. Rather, this mechanism allows us to trigger a native action from JS, and handle the result of that action in JS.
+
+## Other ways of cross-language interaction (events and native modules)
+
+As stated in the previous chapter, using properties comes with some limitations. Sometimes properties are not enough to drive the logic of our app and we need a solution that gives more flexibility. This chapter covers other communication techniques available in React Native. They can be used for internal communication (between JS and native layers in RN) as well as for external communication (between RN and the 'pure native' part of your app).
+
+React Native enables you to perform cross-language function calls. You can execute custom native code from JS and vice versa. Unfortunately, depending on the side we are working on, we achieve the same goal in different ways. For native - we use events mechanism to schedule an execution of a handler function in JS, while for React Native we directly call methods exported by native modules.
+
+### Calling React Native functions from native (events)
+
+Events are described in detail in [this article](http://facebook.github.io/react-native/docs/native-components-ios.html#events). Note that using events gives us no guarantees about execution time, as the event is handled on a separate thread.
+
+Events are powerful, because they allow us to change React Native components without needing a reference to them. However, there are some pitfalls that you can fall into while using them:
+
+* As events can be sent from anywhere, they can introduce spaghetti-style dependencies into your project. 
+* Events share namespace, which means that you may encounter some name collisions. Collisions will not be detected statically, what makes them hard to debug. 
+* If you use several instances of the same React Native component and you want to distinguish them from the perspective of your event, you'll likely need to introduce some kind of identifiers and pass them along with events (you can use the native view's `reactTag` as an identifier).
+
+The common pattern we use when embedding native in React Native is to make the native component's RCTViewManager a delegate for the views, sending events back to JavaScript via the bridge. This keeps related event calls in one place.
+
+### Calling native functions from React Native (native modules)
+
+Native modules are Objective-C classes that are available in JS. Typically one instance of each module is created per JS bridge. They can export arbitrary functions and constants to React Native. They have been covered in detail in [this article](https://facebook.github.io/react-native/docs/native-modules-ios.html#content).
+
+The fact that native modules are singletons limits the mechanism in context of embedding. Let's say we have a React Native component embedded in a native view and we want to update the native, parent view. Using the native module mechanism, we would export a function that not only takes expected arguments, but also an identifier of the parent native view. The identifier would be used to retrieve a reference to the parent view to update. That said, we would need to keep a mapping from identifiers to native views in the module.
+
+Although this solution is complex, it is used in `RCTUIManager`, which is an internal React Native class that manages all React Native views.
+
+Native modules can also be used to expose existing native libraries to JS. [Geolocation library](https://github.com/facebook/react-native/tree/master/Libraries/Geolocation) is a living example of the idea.
+
+> ***Warning***:
+> All native modules share the same namespace. Watch out for name collisions when creating new ones.
+
+## Layout computation flow
+
+When integrating native and React Native, we also need a way to consolidate two different layout systems. This section covers common layouting problems and provides a brief description of mechanisms that are intended to address them.
+
+### Layout of a native component embedded in React Native
+
+This case is covered in [this article](https://facebook.github.io/react-native/docs/native-components-ios.html#styles). Basically, as all our native react views are subclasses of `UIView`, most style and size attributes will work like you would expect out of the box.
+
+### Layout of a React Native component embedded in native
+
+#### React Native content with fixed size
+The simplest scenario is when we have a React Native app with a fixed size, which is known to the native side. In particular, a full-screen React Native view falls into this case. If we want a smaller root view, we can explicitly set RCTRootView's frame.
+
+For instance, to make an RN app 200 (logical) pixels high, and the hosting view's width wide, we could do:
+
+```
+// SomeViewController.m
+
+- (void)viewDidLoad
+{
+  [...]
+  RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
+                                                   moduleName:appName
+                                            initialProperties:props];
+  rootView.frame = CGMakeRect(0, 0, self.view.width, 200);
+  [self.view addSubview:rootView];
+}
+```
+
+When we have a fixed size root view, we need to respect its bounds on the JS side. In other words, we need to ensure that the React Native content can be contained within the fixed-size root view. The easiest way to ensure this is to use flexbox layout. If you use absolute positioning, and React components are visible outside the root view's bounds, you'll get overlap with native views, causing some features to behave unexpectedly. For instance, 'TouchableHighlight' will not highlight your touches outside the root view's bounds.
+
+It's totally fine to update root view's size dynamically by re-setting its frame property. React Native will take care of the content's layout.
+
+#### React Native content with flexible size
+
+In some cases we'd like to render content of initially unknown size. Let's say the size will be defined dynamically in JS. We have two solutions to this problem.
+
+
+1. You can wrap your React Native view in `ScrollView` component. This guarantees that your content will always be available and it won't overlap with native views.
+2. React Native allows you to determine, in JS, the size of the RN app and provide it to the owner of the hosting `RCTRootView`. The owner is then responsible for re-laying out the subviews and keeping the UI consistent. We achieve this with `RCTRootView`'s flexibility modes.
+
+
+`RCTRootView` supports 4 different size flexibility modes:
+
+```
+// RCTRootView.h
+
+typedef NS_ENUM(NSInteger, RCTRootViewSizeFlexibility) {
+  RCTRootViewSizeFlexibilityNone = 0,
+  RCTRootViewSizeFlexibilityWidth,
+  RCTRootViewSizeFlexibilityHeight,
+  RCTRootViewSizeFlexibilityWidthAndHeight,
+};
+```
+
+`RCTRootViewSizeFlexibilityNone` is the default value, which makes a root view's size fixed (but it still can be updated with `setFrame:`). The other three modes allow us to track React Native content's size updates. For instance, setting mode to `RCTRootViewSizeFlexibilityHeight` will cause React Native to measure the content's height and pass that information back to `RCTRootView`'s delegate. An arbitrary action can be performed within the delegate, including setting the root view's frame, so the content fits. The delegate is called only when the size of the content has changed.
+
+> ***Warning:***
+> Making a dimension flexible in both JS and native leads to undefined behavior. For example - don't make a top-level React component's width flexible (with `flexbox`) while you're using `RCTRootViewSizeFlexibilityWidth` on the hosting `RCTRootView`.
+
+Let's look at an example.
+
+```
+// FlexibleSizeExampleView.m
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+  [...]
+
+  _rootView = [[RCTRootView alloc] initWithBridge:bridge
+  moduleName:@"FlexibilityExampleApp"
+  initialProperties:@{}];
+
+  _rootView.delegate = self;
+  _rootView.sizeFlexibility = RCTRootViewSizeFlexibilityHeight;
+  _rootView.frame = CGRectMake(0, 0, self.frame.size.width, 0);
+}
+
+#pragma mark - RCTRootViewDelegate
+- (void)rootViewDidChangeIntrinsicSize:(RCTRootView *)rootView
+{
+  CGRect newFrame = rootView.frame;
+  newFrame.size = rootView.intrinsicSize;
+
+  rootView.frame = newFrame;
+}
+```
+
+In the example we have a `FlexibleSizeExampleView` view that holds a root view. We create the root view, initialize it and set the delegate. The delegate will handle size updates. Then, we set the root view's size flexibility to `RCTRootViewSizeFlexibilityHeight`, which means that `rootViewDidChangeIntrinsicSize:` method will be called every time the React Native content changes its height. Finally, we set the root view's width and position. Note that we set there height as well, but it has no effect as we made the height RN-dependent.
+
+You can checkout full source code of the example [here](https://phabricator.fb.com/diffusion/FBOBJC/browse/master/Libraries/FBReactKit/js/react-native-github/Examples/UIExplorer/UIExplorer/NativeExampleViews/FlexibleSizeExampleView.m).
+
+It's fine to change root view's size flexibility mode dynamically. Changing flexibility mode of a root view will schedule a layout recalculation and the delegate `rootViewDidChangeIntrinsicSize:` method will be called once the content size is known.
+
+> ***Note:*** React Native layout calculation is performed on a special thread, while native UI view updates are done on the main thread. This may cause temporary UI inconsistencies between native and React Native. This is a known problem and our team is working on synchronizing UI updates coming from different sources.
+
+> ***Note:*** React Native does not perform any layout calculations until the root view becomes a subview of some other views. If you want to hide React Native view until its dimensions are known, add the root view as a subview and make it initially hidden (use `UIView`'s `hidden` property). Then change its visibility in the delegate method.
diff --git a/docs/EmbeddedAppIOS.md b/docs/EmbeddedAppIOS.md
index d913d0beb0d4..655809fa044a 100644
--- a/docs/EmbeddedAppIOS.md
+++ b/docs/EmbeddedAppIOS.md
@@ -4,7 +4,7 @@ title: Integrating with Existing Apps
 layout: docs
 category: Guides (iOS)
 permalink: docs/embedded-app-ios.html
-next: native-modules-android
+next: communication-ios
 ---
 
 Since React makes no assumptions about the rest of your technology stack – it’s commonly noted as simply the `V` in `MVC` – it’s easily embeddable within an existing non-React Native app. In fact, it integrates with other best practice community tools like [CocoaPods](http://cocoapods.org/).

From c929e15523c2c33297b1e9895e9bea49442e4f73 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Mon, 30 Nov 2015 05:24:13 -0800
Subject: [PATCH 0159/1411] Update touch handling to properly handle
 transformed Views

Summary: public

Our view handling for determining if a touch was in a view was not transform aware.  This updates it to be
transform aware (by borrowing the code from ViewGroup).

Now, touches will be correctly translated to the view if the view is transformed.  They will also have the correct
local touch point.

This fixes https://github.com/facebook/react-native/issues/3557

Reviewed By: andreicoman11

Differential Revision: D2696063

fb-gh-sync-id: 291f6b9884c610c29f8f8b9992c98d59863ab481
---
 .../react/uimanager/TouchTargetHelper.java    | 60 +++++++++++++++----
 1 file changed, 47 insertions(+), 13 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java
index 409a9f91f402..24a4d286946f 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java
@@ -11,6 +11,8 @@
 
 import javax.annotation.Nullable;
 
+import android.graphics.Matrix;
+import android.graphics.PointF;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
@@ -25,6 +27,9 @@
 public class TouchTargetHelper {
 
   private static final float[] mEventCoords = new float[2];
+  private static final PointF mTempPoint = new PointF();
+  private static final float[] mMatrixTransformCoords = new float[2];
+  private static final Matrix mInverseMatrix = new Matrix();
 
   /**
    * Find touch event target view within the provided container given the coordinates provided
@@ -94,31 +99,60 @@ private static View findTouchTargetView(float[] eventCoords, ViewGroup viewGroup
     int childrenCount = viewGroup.getChildCount();
     for (int i = childrenCount - 1; i >= 0; i--) {
       View child = viewGroup.getChildAt(i);
-      if (isTouchPointInView(eventCoords[0], eventCoords[1], viewGroup, child)) {
-        // Apply offset to event coordinates to transform them into the coordinate space of the
-        // child view, taken from {@link ViewGroup#dispatchTransformedTouchEvent()}.
-        eventCoords[0] += viewGroup.getScrollY() - child.getTop();
-        eventCoords[1] += viewGroup.getScrollX() - child.getLeft();
+      PointF childPoint = mTempPoint;
+      if (isTransformedTouchPointInView(eventCoords[0], eventCoords[1], viewGroup, child, childPoint)) {
+        // If it is contained within the child View, the childPoint value will contain the view
+        // coordinates relative to the child
+        // We need to store the existing X,Y for the viewGroup away as it is possible this child
+        // will not actually be the target and so we restore them if not
+        float restoreY = eventCoords[0];
+        float restoreX = eventCoords[1];
+        eventCoords[0] = childPoint.y;
+        eventCoords[1] = childPoint.x;
         View targetView = findTouchTargetViewWithPointerEvents(eventCoords, child);
         if (targetView != null) {
           return targetView;
         }
-        eventCoords[0] -= viewGroup.getScrollY() - child.getTop();
-        eventCoords[1] -= viewGroup.getScrollX() - child.getLeft();
+        eventCoords[0] = restoreY;
+        eventCoords[1] = restoreX;
       }
     }
     return viewGroup;
 }
 
-  // Taken from {@link ViewGroup#isTransformedTouchPointInView()}
-  private static boolean isTouchPointInView(float y, float x, ViewGroup parent, View child) {
-    float localY = y + parent.getScrollY() - child.getTop();
+  /**
+   * Returns whether the touch point is within the child View
+   * It is transform aware and will invert the transform Matrix to find the true local points
+   * This code is taken from {@link ViewGroup#isTransformedTouchPointInView()}
+   */
+  private static boolean isTransformedTouchPointInView(
+      float y,
+      float x,
+      ViewGroup parent,
+      View child,
+      PointF outLocalPoint) {
     float localX = x + parent.getScrollX() - child.getLeft();
-    // Taken from {@link View#pointInView()}.
-    return localY >= 0 && localY < (child.getBottom() - child.getTop())
-        && localX >= 0 && localX < (child.getRight() - child.getLeft());
+    float localY = y + parent.getScrollY() - child.getTop();
+    Matrix matrix = child.getMatrix();
+    if (!matrix.isIdentity()) {
+      float[] localXY = mMatrixTransformCoords;
+      localXY[0] = localX;
+      localXY[1] = localY;
+      Matrix inverseMatrix = mInverseMatrix;
+      matrix.invert(inverseMatrix);
+      inverseMatrix.mapPoints(localXY);
+      localX = localXY[0];
+      localY = localXY[1];
+    }
+    if ((localX >= 0 && localX < (child.getRight() - child.getLeft()))
+        && (localY >= 0 && localY < (child.getBottom() - child.getTop()))) {
+      outLocalPoint.set(localX, localY);
+      return true;
+    }
+    return false;
   }
 
+
   /**
    * Returns the touch target View of the event given, or null if neither the given View nor any of
    * its descendants are the touch target.

From 0f0b57880fe5b2565cc247a2e0c0b7611330b5d1 Mon Sep 17 00:00:00 2001
From: Andreas Amsenius <andreas@amsenius.se>
Date: Mon, 30 Nov 2015 06:18:55 -0800
Subject: [PATCH 0160/1411] ActionSheetIOS sharing exclude activity types

Summary: Closes https://github.com/facebook/react-native/pull/4427

Reviewed By: svcscm

Differential Revision: D2702825

Pulled By: nicklockwood

fb-gh-sync-id: f12e83332f2083cee2c04625b5113774c8a907e0
---
 Examples/UIExplorer/ActionSheetIOSExample.js     | 3 +++
 Libraries/ActionSheetIOS/RCTActionSheetManager.m | 5 +++++
 2 files changed, 8 insertions(+)

diff --git a/Examples/UIExplorer/ActionSheetIOSExample.js b/Examples/UIExplorer/ActionSheetIOSExample.js
index 548fe3bd1583..1ef41c1edef7 100644
--- a/Examples/UIExplorer/ActionSheetIOSExample.js
+++ b/Examples/UIExplorer/ActionSheetIOSExample.js
@@ -90,6 +90,9 @@ var ShareActionSheetExample = React.createClass({
       url: 'https://code.facebook.com',
       message: 'message to go with the shared url',
       subject: 'a subject to go in the email heading',
+      excludedActivityTypes: [
+        'com.apple.UIKit.activity.PostToTwitter'
+      ]
     },
     (error) => {
       console.error(error);
diff --git a/Libraries/ActionSheetIOS/RCTActionSheetManager.m b/Libraries/ActionSheetIOS/RCTActionSheetManager.m
index 1d4e93ba741b..245493b0ceef 100644
--- a/Libraries/ActionSheetIOS/RCTActionSheetManager.m
+++ b/Libraries/ActionSheetIOS/RCTActionSheetManager.m
@@ -172,6 +172,11 @@ - (CGRect)sourceRectInView:(UIView *)sourceView
     [shareController setValue:subject forKey:@"subject"];
   }
 
+  NSArray *excludedActivityTypes = [RCTConvert NSStringArray:options[@"excludedActivityTypes"]];
+  if (excludedActivityTypes) {
+    shareController.excludedActivityTypes = excludedActivityTypes;
+  }
+
   UIViewController *controller = RCTKeyWindow().rootViewController;
 
 #if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0

From df70005c12e3be14bfbdf0b32f9ea0a5c052deba Mon Sep 17 00:00:00 2001
From: Danny Arnold <despair.blue@gmail.com>
Date: Mon, 30 Nov 2015 07:32:24 -0800
Subject: [PATCH 0161/1411] calling navigationBar's overridden ref function

Summary: Before that it was not possible to get a ref to a navigation bar (unless using Navigator's internal `_navBar` prop)
Closes https://github.com/facebook/react-native/pull/3755

Reviewed By: svcscm

Differential Revision: D2674315

Pulled By: nicklockwood

fb-gh-sync-id: 26120f7bcbb675e8217b8bd963dcc6ed314d4ba3
---
 Libraries/CustomComponents/Navigator/Navigator.js | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Libraries/CustomComponents/Navigator/Navigator.js b/Libraries/CustomComponents/Navigator/Navigator.js
index ff7ff2c632f7..e11ee25055ed 100644
--- a/Libraries/CustomComponents/Navigator/Navigator.js
+++ b/Libraries/CustomComponents/Navigator/Navigator.js
@@ -1087,7 +1087,10 @@ var Navigator = React.createClass({
       return null;
     }
     return React.cloneElement(this.props.navigationBar, {
-      ref: (navBar) => { this._navBar = navBar; },
+      ref: (navBar) => {
+        this.props.navigationBar.ref instanceof Function && this.props.navigationBar.ref(navBar);
+        this._navBar = navBar;
+      },
       navigator: this._navigationBarNavigator,
       navState: this.state,
     });

From 32fa0b7fa196ae83e7f65bf1836d672b58f2213c Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Mon, 30 Nov 2015 08:31:35 -0800
Subject: [PATCH 0162/1411] Move bundle output formats to their own files

Reviewed By: tadeuzagallo

Differential Revision: D2702834

fb-gh-sync-id: fca308c5078a11924e071077822fb77d762bd564
---
 local-cli/bundle/buildBundle.js      | 117 ++++++---------------------
 local-cli/bundle/bundle.js           |   6 +-
 local-cli/bundle/output/bundle.js    |  59 ++++++++++++++
 local-cli/bundle/output/prepack.js   |  34 ++++++++
 local-cli/bundle/output/writeFile.js |  25 ++++++
 5 files changed, 149 insertions(+), 92 deletions(-)
 create mode 100644 local-cli/bundle/output/bundle.js
 create mode 100644 local-cli/bundle/output/prepack.js
 create mode 100644 local-cli/bundle/output/writeFile.js

diff --git a/local-cli/bundle/buildBundle.js b/local-cli/bundle/buildBundle.js
index 5cb752a43b1c..f2f1e3291ec1 100644
--- a/local-cli/bundle/buildBundle.js
+++ b/local-cli/bundle/buildBundle.js
@@ -8,59 +8,13 @@
  */
 'use strict';
 
-const fs = require('fs');
 const log = require('../util/log').out('bundle');
+const outputBundle = require('./output/bundle');
 const Promise = require('promise');
 const ReactPackager = require('../../packager/react-packager');
 const saveAssets = require('./saveAssets');
 
-const sign = require('./sign');
-
-function saveBundleAndMap(
-  bundle,
-  bundleOutput,
-  encoding,
-  sourcemapOutput,
-  dev
-) {
-  log('start');
-  let codeWithMap;
-  if (!dev) {
-    codeWithMap = bundle.getMinifiedSourceAndMap(dev);
-  } else {
-    codeWithMap = {
-      code: bundle.getSource({ dev }),
-      map: JSON.stringify(bundle.getSourceMap({ dev })),
-    };
-  }
-  log('finish');
-
-  log('Writing bundle output to:', bundleOutput);
-  fs.writeFileSync(bundleOutput, sign(codeWithMap.code), encoding);
-  log('Done writing bundle output');
-
-  if (sourcemapOutput) {
-    log('Writing sourcemap output to:', sourcemapOutput);
-    fs.writeFileSync(sourcemapOutput, codeWithMap.map);
-    log('Done writing sourcemap output');
-  }
-}
-
-function savePrepackBundleAndMap(
-  bundle,
-  bundleOutput,
-  sourcemapOutput,
-  bridgeConfig
-) {
-  log('Writing prepack bundle output to:', bundleOutput);
-  const result = bundle.build({
-    batchedBridgeConfig: bridgeConfig
-  });
-  fs.writeFileSync(bundleOutput, result, 'ucs-2');
-  log('Done writing prepack bundle output');
-}
-
-function buildBundle(args, config) {
+function buildBundle(args, config, output = outputBundle) {
   return new Promise((resolve, reject) => {
 
     // This is used by a bazillion of npm modules we don't control so we don't
@@ -82,55 +36,36 @@ function buildBundle(args, config) {
       platform: args.platform,
     };
 
-    const prepack = args.prepack;
-
-    const client = ReactPackager.createClientFor(options);
-
-    client.then(() => log('Created ReactPackager'));
+    const clientPromise = ReactPackager.createClientFor(options);
 
     // Build and save the bundle
-    let bundle;
-    if (prepack) {
-      bundle = client.then(c => c.buildPrepackBundle(requestOpts))
-        .then(outputBundle => {
-          savePrepackBundleAndMap(
-            outputBundle,
-            args['bundle-output'],
-            args['sourcemap-output'],
-            args['bridge-config']
-          );
-          return outputBundle;
-        });
-    } else {
-      bundle = client.then(c => c.buildBundle(requestOpts))
-        .then(outputBundle => {
-          saveBundleAndMap(
-            outputBundle,
-            args['bundle-output'],
-            args['bundle-encoding'],
-            args['sourcemap-output'],
-            args.dev
-          );
-          return outputBundle;
-        });
-    }
+    const bundlePromise = clientPromise
+      .then(client => {
+        log('Created ReactPackager');
+        return output.build(client, requestOpts);
+      })
+      .then(bundle => {
+        output.save(bundle, args, log);
+        return bundle;
+      });
 
     // When we're done bundling, close the client
-    bundle.then(() => client.then(c => {
-      log('Closing client');
-      c.close();
-    }));
+    Promise.all([clientPromise, bundlePromise])
+      .then(([client]) => {
+        log('Closing client');
+        client.close();
+      });
 
     // Save the assets of the bundle
-    const assets = bundle
-        .then(outputBundle => outputBundle.getAssets())
-        .then(outputAssets => saveAssets(
-          outputAssets,
-          args.platform,
-          args['assets-dest']
-        ));
-
-    // When we're done saving the assets, we're done.
+    const assets = bundlePromise
+      .then(bundle => bundle.getAssets())
+      .then(outputAssets => saveAssets(
+        outputAssets,
+        args.platform,
+        args['assets-dest']
+      ));
+
+    // When we're done saving bundle output and the assets, we're done.
     resolve(assets);
   });
 }
diff --git a/local-cli/bundle/bundle.js b/local-cli/bundle/bundle.js
index 6826de71faa4..e242049f0156 100644
--- a/local-cli/bundle/bundle.js
+++ b/local-cli/bundle/bundle.js
@@ -11,12 +11,16 @@
 const buildBundle = require('./buildBundle');
 const bundleCommandLineArgs = require('./bundleCommandLineArgs');
 const parseCommandLine = require('../util/parseCommandLine');
+const outputBundle = require('./output/bundle');
+const outputPrepack = require('./output/prepack');
 
 /**
  * Builds the bundle starting to look for dependencies at the given entry path.
  */
 function bundle(argv, config) {
-  return buildBundle(parseCommandLine(bundleCommandLineArgs, argv), config);
+  const args = parseCommandLine(bundleCommandLineArgs, argv);
+  const output = args.prepack ? outputPrepack : outputBundle;
+  return buildBundle(args, config, output);
 }
 
 module.exports = bundle;
diff --git a/local-cli/bundle/output/bundle.js b/local-cli/bundle/output/bundle.js
new file mode 100644
index 000000000000..4ffd8a649bc4
--- /dev/null
+++ b/local-cli/bundle/output/bundle.js
@@ -0,0 +1,59 @@
+/**
+ * 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.
+ */
+'use strict';
+
+const Promise = require('promise');
+const sign = require('../sign');
+const writeFile = require('./writeFile');
+
+function buildBundle(packagerClient, requestOptions) {
+  return packagerClient.buildBundle(requestOptions);
+}
+
+function createCodeWithMap(bundle, dev) {
+  if (!dev) {
+    return bundle.getMinifiedSourceAndMap(dev);
+  } else {
+    return {
+      code: bundle.getSource({dev}),
+      map: JSON.stringify(bundle.getSourceMap({dev})),
+    };
+  }
+}
+
+function saveBundleAndMap(bundle, options, log) {
+  const {
+    'bundle-output': bundleOutput,
+    'bundle-encoding': encoding,
+    dev,
+    'sourcemap-output': sourcemapOutput,
+} = options;
+
+  log('start');
+  const codeWithMap = createCodeWithMap(bundle, dev);
+  log('finish');
+
+  log('Writing bundle output to:', bundleOutput);
+  const writeBundle = writeFile(bundleOutput, sign(codeWithMap.code), encoding);
+  writeBundle.then(() => log('Done writing bundle output'));
+
+  if (sourcemapOutput) {
+    log('Writing sourcemap output to:', sourcemapOutput);
+    const writeMap = writeFile(sourcemapOutput, codeWithMap.map, null);
+    writeMap.then(() => log('Done writing sourcemap output'));
+    return Promise.all([writeBundle, writeMap]);
+  } else {
+    return writeBundle;
+  }
+}
+
+
+exports.build = buildBundle;
+exports.save = saveBundleAndMap;
+exports.formatName = 'bundle';
diff --git a/local-cli/bundle/output/prepack.js b/local-cli/bundle/output/prepack.js
new file mode 100644
index 000000000000..9165b8763571
--- /dev/null
+++ b/local-cli/bundle/output/prepack.js
@@ -0,0 +1,34 @@
+/**
+ * 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.
+ */
+'use strict';
+
+const writeFile = require('./writeFile');
+
+function buildPrepackBundle(packagerClient, requestOptions) {
+  return packagerClient.buildPrepackBundle(requestOptions);
+}
+
+function savePrepackBundle(bundle, options, log) {
+  const {
+    'bundle-output': bundleOutput,
+    'bridge-config': bridgeConfig,
+  } = options;
+
+  const result = bundle.build({
+    batchedBridgeConfig: bridgeConfig
+  });
+
+  log('Writing prepack bundle output to:', bundleOutput);
+  const writePrepackBundle = writeFile(bundleOutput, result, 'ucs-2');
+  writePrepackBundle.then(() => log('Done writing prepack bundle output'));
+  return writePrepackBundle;
+}
+
+exports.build = buildPrepackBundle;
+exports.save = savePrepackBundle;
diff --git a/local-cli/bundle/output/writeFile.js b/local-cli/bundle/output/writeFile.js
new file mode 100644
index 000000000000..bb30d941fae5
--- /dev/null
+++ b/local-cli/bundle/output/writeFile.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.
+ */
+'use strict';
+
+const fs = require('fs');
+const Promise = require('promise');
+
+function writeFile(file, data, encoding) {
+  return new Promise((resolve, reject) => {
+    fs.writeFile(
+      file,
+      data,
+      encoding,
+      error => error ? reject(error) : resolve()
+    );
+  });
+}
+
+module.exports = writeFile;

From 015c6b3be273a40b530b9b79bb1f9da3d0ba1cdf Mon Sep 17 00:00:00 2001
From: Aleksei Androsov <doochik@ya.ru>
Date: Mon, 30 Nov 2015 10:28:49 -0800
Subject: [PATCH 0163/1411] ImagePicker always called with cancelCallback

Summary: We should pick 2 callbacks from pickerCallbacks and pickerCancelCallbacks arrays and call them depens on args.
Closes https://github.com/facebook/react-native/pull/4411

Reviewed By: svcscm

Differential Revision: D2703209

Pulled By: javache

fb-gh-sync-id: 7d2d7c63b933a66a1ff600663c3a7fcc821c750b
---
 Libraries/CameraRoll/RCTImagePickerManager.m | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/Libraries/CameraRoll/RCTImagePickerManager.m b/Libraries/CameraRoll/RCTImagePickerManager.m
index 0ad9e8e71ec4..d82d0e9bf554 100644
--- a/Libraries/CameraRoll/RCTImagePickerManager.m
+++ b/Libraries/CameraRoll/RCTImagePickerManager.m
@@ -132,7 +132,8 @@ - (void)_presentPicker:(UIImagePickerController *)imagePicker
 - (void)_dismissPicker:(UIImagePickerController *)picker args:(NSArray *)args
 {
   NSUInteger index = [_pickers indexOfObject:picker];
-  RCTResponseSenderBlock callback = _pickerCancelCallbacks[index];
+  RCTResponseSenderBlock successCallback = _pickerCallbacks[index];
+  RCTResponseSenderBlock cancelCallback = _pickerCancelCallbacks[index];
 
   [_pickers removeObjectAtIndex:index];
   [_pickerCallbacks removeObjectAtIndex:index];
@@ -141,7 +142,11 @@ - (void)_dismissPicker:(UIImagePickerController *)picker args:(NSArray *)args
   UIViewController *rootViewController = RCTKeyWindow().rootViewController;
   [rootViewController dismissViewControllerAnimated:YES completion:nil];
 
-  callback(args ?: @[]);
+  if (args) {
+    successCallback(args);
+  } else {
+    cancelCallback(@[]);
+  }
 }
 
 @end

From 8f50ace8b3a6439fec63ea5ed8642d290c843cfd Mon Sep 17 00:00:00 2001
From: mkonicek-pr-test <martinkonicek@centrum.cz>
Date: Mon, 30 Nov 2015 11:08:58 -0800
Subject: [PATCH 0164/1411] Remove newline in TicTacToe example

Summary: Really just for testing the shipit bot :)
Closes https://github.com/facebook/react-native/pull/4434

Reviewed By: svcscm

Differential Revision: D2703503

Pulled By: mkonicek

fb-gh-sync-id: 4b93638e01eaf86d63c429e6797d08095c4824ee
---
 Examples/TicTacToe/TicTacToeApp.js | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Examples/TicTacToe/TicTacToeApp.js b/Examples/TicTacToe/TicTacToeApp.js
index 15652ee4de64..6d5c460cbea3 100755
--- a/Examples/TicTacToe/TicTacToeApp.js
+++ b/Examples/TicTacToe/TicTacToeApp.js
@@ -89,7 +89,6 @@ class Board {
         }
       }
     }
-
     return this.winner() === null;
   }
 }

From b86b5af1e864b77da48c5c4f43f7c2c53be9999e Mon Sep 17 00:00:00 2001
From: Jake Yang <tsunghan614@gmail.com>
Date: Mon, 30 Nov 2015 11:30:02 -0800
Subject: [PATCH 0165/1411] Add TYDY to the Showcase

---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 7d9bbfd816a9..889fd69bd6ee 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -350,6 +350,12 @@ var apps = [
     link: 'https://itunes.apple.com/cn/app/tong-xing-wang/id914254459?mt=8',
     author: 'Ho Yin Tsun Eugene',
   },
+  {
+    name: 'TYDY',
+    icon: 'http://d2j2p20zkb3bwp.cloudfront.net/images/appicon76x76_2x.png',
+    link: 'https://itunes.apple.com/us/app/tydy-buy-sell-free-your-local/id1039965583?mt=8',
+    author: '99gamers',
+  },
   {
     name: 'WOOP',
     icon: 'http://a4.mzstatic.com/us/r30/Purple6/v4/b0/44/f9/b044f93b-dbf3-9ae5-0f36-9b4956628cab/icon350x350.jpeg',

From 4e04e3bc28141243ba901789e86cdc8d996f001f Mon Sep 17 00:00:00 2001
From: "Tsung Han (Jake) Yang" <tsunghan614@gmail.com>
Date: Mon, 30 Nov 2015 11:50:56 -0800
Subject: [PATCH 0166/1411] Revert "Add TYDY to the Showcase"

---
 website/src/react-native/showcase.js | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 889fd69bd6ee..7d9bbfd816a9 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -350,12 +350,6 @@ var apps = [
     link: 'https://itunes.apple.com/cn/app/tong-xing-wang/id914254459?mt=8',
     author: 'Ho Yin Tsun Eugene',
   },
-  {
-    name: 'TYDY',
-    icon: 'http://d2j2p20zkb3bwp.cloudfront.net/images/appicon76x76_2x.png',
-    link: 'https://itunes.apple.com/us/app/tydy-buy-sell-free-your-local/id1039965583?mt=8',
-    author: '99gamers',
-  },
   {
     name: 'WOOP',
     icon: 'http://a4.mzstatic.com/us/r30/Purple6/v4/b0/44/f9/b044f93b-dbf3-9ae5-0f36-9b4956628cab/icon350x350.jpeg',

From dd5bb96e44c8c1a9b5d6783053c053de92455f59 Mon Sep 17 00:00:00 2001
From: Denis Koroskin <dkoroskin@fb.com>
Date: Mon, 30 Nov 2015 12:31:43 -0800
Subject: [PATCH 0167/1411] Provide getters for CallerContext and
 DraweeControllerBuilder in ReactViewManager

Summary: public Right now there is no centralized place to initialize CallerContext for Fresco. It should probably go through FrescoModule, but currently it's going through ReactImageManager, and thus unavailable to FlatUIImplementation, that doesn't use ReactImageManager. So this diff provides public getters for CallerContext (and DraweeControllerBuilder) in ReactViewManager. This is hacky and generally should not be needed, but without it groups don't have correct CallerContext set.

Reviewed By: kmagiera, astreet

Differential Revision: D2569372

fb-gh-sync-id: 2622e69c64bfebfc575deb330ee77e0139efb7ec
---
 .../react/views/image/ReactImageManager.java      | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
index 8803652d1153..b0df41db0b3c 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
@@ -48,16 +48,23 @@ public ReactImageManager() {
     mCallerContext = null;
   }
 
-  @Override
-  public ReactImageView createViewInstance(ThemedReactContext context) {
+  public AbstractDraweeControllerBuilder getDraweeControllerBuilder() {
     if (mDraweeControllerBuilder == null) {
       mDraweeControllerBuilder = Fresco.newDraweeControllerBuilder();
     }
+    return mDraweeControllerBuilder;
+  }
 
+  public Object getCallerContext() {
+    return mCallerContext;
+  }
+
+  @Override
+  public ReactImageView createViewInstance(ThemedReactContext context) {
     return new ReactImageView(
         context,
-        mDraweeControllerBuilder,
-        mCallerContext);
+        getDraweeControllerBuilder(),
+        getCallerContext());
   }
 
   // In JS this is Image.props.source.uri

From 94f126ddbf1e3600ed7d34b8aba444a5df587c58 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Mon, 30 Nov 2015 13:37:37 -0800
Subject: [PATCH 0168/1411] Fixed TextInput.blur()

Reviewed By: helouree

Differential Revision: D2704065

fb-gh-sync-id: a4f5aa9c9b4fcb7980eb85289d16982840a980bd
---
 Libraries/Text/RCTTextView.m | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Libraries/Text/RCTTextView.m b/Libraries/Text/RCTTextView.m
index 412dd47acc06..34f3b74970f0 100644
--- a/Libraries/Text/RCTTextView.m
+++ b/Libraries/Text/RCTTextView.m
@@ -425,6 +425,11 @@ - (void)reactDidMakeFirstResponder
   [_textView reactDidMakeFirstResponder];
 }
 
+- (BOOL)resignFirstResponder
+{
+  return [_textView resignFirstResponder];
+}
+
 - (void)layoutSubviews
 {
   [super layoutSubviews];

From 0c8bafe84a07aa9038e438d07fc4d54a69a6f8d1 Mon Sep 17 00:00:00 2001
From: Huang Yu <huang@bitgo.com>
Date: Mon, 30 Nov 2015 16:12:44 -0800
Subject: [PATCH 0169/1411] fix library/utility lint warnings

Summary: I have disected lint warnings fixes to several PRs. This one fixes lint warnings under Libraries/Utility path.
Closes https://github.com/facebook/react-native/pull/4444

Reviewed By: svcscm

Differential Revision: D2705303

Pulled By: spicyj

fb-gh-sync-id: c745ac62cbff30d6bb9478a1d2465fe56b305f0c
---
 Libraries/Utilities/MessageQueue.js                 | 1 -
 Libraries/Utilities/createStrictShapeTypeChecker.js | 2 +-
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/Libraries/Utilities/MessageQueue.js b/Libraries/Utilities/MessageQueue.js
index faefc7827048..940b3b459997 100644
--- a/Libraries/Utilities/MessageQueue.js
+++ b/Libraries/Utilities/MessageQueue.js
@@ -16,7 +16,6 @@
 let BridgeProfiling = require('BridgeProfiling');
 let ErrorUtils = require('ErrorUtils');
 let JSTimersExecution = require('JSTimersExecution');
-let ReactUpdates = require('ReactUpdates');
 
 let invariant = require('invariant');
 let keyMirror = require('keyMirror');
diff --git a/Libraries/Utilities/createStrictShapeTypeChecker.js b/Libraries/Utilities/createStrictShapeTypeChecker.js
index cd0d5757a96d..883da2459f7c 100644
--- a/Libraries/Utilities/createStrictShapeTypeChecker.js
+++ b/Libraries/Utilities/createStrictShapeTypeChecker.js
@@ -24,7 +24,7 @@ function createStrictShapeTypeChecker(
       if (isRequired) {
         invariant(
           false,
-          `Required object \`${propName}\` was not specified in `+
+          `Required object \`${propName}\` was not specified in ` +
           `\`${componentName}\`.`
         );
       }

From 9f92e916086d91821098abed88da25f67dec82a1 Mon Sep 17 00:00:00 2001
From: Huang Yu <huang@bitgo.com>
Date: Mon, 30 Nov 2015 16:20:41 -0800
Subject: [PATCH 0170/1411] fix camera roll lint warnings

Summary: fix lint warnings under `Libraries/CameraRoll` directory
Closes https://github.com/facebook/react-native/pull/4445

Reviewed By: svcscm

Differential Revision: D2705430

Pulled By: nicklockwood

fb-gh-sync-id: b5a179750a6696836cf458bc8e646e6b8a23fd98
---
 Libraries/CameraRoll/CameraRoll.js     | 2 +-
 Libraries/CameraRoll/ImagePickerIOS.js | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Libraries/CameraRoll/CameraRoll.js b/Libraries/CameraRoll/CameraRoll.js
index 1eee46a3edbf..c7e28d9510b3 100644
--- a/Libraries/CameraRoll/CameraRoll.js
+++ b/Libraries/CameraRoll/CameraRoll.js
@@ -120,7 +120,7 @@ class CameraRoll {
    * Saves the image to the camera roll / gallery.
    *
    * The CameraRoll API is not yet implemented for Android.
-   * 
+   *
    * @param {string} tag On Android, this is a local URI, such
    * as `"file:///sdcard/img.png"`.
    *
diff --git a/Libraries/CameraRoll/ImagePickerIOS.js b/Libraries/CameraRoll/ImagePickerIOS.js
index 9b2f75e5b92d..a67884dc8435 100644
--- a/Libraries/CameraRoll/ImagePickerIOS.js
+++ b/Libraries/CameraRoll/ImagePickerIOS.js
@@ -24,7 +24,7 @@ var ImagePickerIOS = {
     config = {
       videoMode: false,
       ...config,
-    }
+    };
     return RCTImagePicker.openCameraDialog(config, successCallback, cancelCallback);
   },
   openSelectDialog: function(config: Object, successCallback: Function, cancelCallback: Function) {
@@ -32,7 +32,7 @@ var ImagePickerIOS = {
       showImages: true,
       showVideos: false,
       ...config,
-    }
+    };
     return RCTImagePicker.openSelectDialog(config, successCallback, cancelCallback);
   },
 };

From da0744892c64f9bff128338e863fa45b3fc71986 Mon Sep 17 00:00:00 2001
From: Huang Yu <huang@bitgo.com>
Date: Mon, 30 Nov 2015 16:21:44 -0800
Subject: [PATCH 0171/1411] fix Library/ReactNative lint warnings

Summary: fix 2 lint warnings under `Libraries/ReactNative` directory
Closes https://github.com/facebook/react-native/pull/4446

Reviewed By: svcscm

Differential Revision: D2705429

Pulled By: nicklockwood

fb-gh-sync-id: a7318ef9d1d194f077b0879fd041c42da5b2dec3
---
 Libraries/ReactNative/ReactNative.js              | 1 -
 Libraries/ReactNative/ReactNativeBaseComponent.js | 1 -
 2 files changed, 2 deletions(-)

diff --git a/Libraries/ReactNative/ReactNative.js b/Libraries/ReactNative/ReactNative.js
index a5554c0f4b51..1b02747532af 100644
--- a/Libraries/ReactNative/ReactNative.js
+++ b/Libraries/ReactNative/ReactNative.js
@@ -26,7 +26,6 @@ var ReactNativeMount = require('ReactNativeMount');
 var ReactPropTypes = require('ReactPropTypes');
 var ReactUpdates = require('ReactUpdates');
 
-var deprecated = require('deprecated');
 var findNodeHandle = require('findNodeHandle');
 var invariant = require('invariant');
 var onlyChild = require('onlyChild');
diff --git a/Libraries/ReactNative/ReactNativeBaseComponent.js b/Libraries/ReactNative/ReactNativeBaseComponent.js
index 765c0429063b..266c7b30fbf6 100644
--- a/Libraries/ReactNative/ReactNativeBaseComponent.js
+++ b/Libraries/ReactNative/ReactNativeBaseComponent.js
@@ -14,7 +14,6 @@
 var NativeMethodsMixin = require('NativeMethodsMixin');
 var ReactNativeAttributePayload = require('ReactNativeAttributePayload');
 var ReactNativeEventEmitter = require('ReactNativeEventEmitter');
-var ReactNativeStyleAttributes = require('ReactNativeStyleAttributes');
 var ReactNativeTagHandles = require('ReactNativeTagHandles');
 var ReactMultiChild = require('ReactMultiChild');
 var UIManager = require('UIManager');

From 8f2023d9617804201293b6226d0e4a58c343f97a Mon Sep 17 00:00:00 2001
From: Huang Yu <huang@bitgo.com>
Date: Mon, 30 Nov 2015 17:14:10 -0800
Subject: [PATCH 0172/1411] fix Libraries/Components/Touchable lint warnings

Summary: fix 4 lint warnings under Libraries/Components/Touchable directory
Closes https://github.com/facebook/react-native/pull/4449

Reviewed By: svcscm

Differential Revision: D2705537

Pulled By: spicyj

fb-gh-sync-id: 0c573d846a2263819c2a0bffe0a178eee1fe3fca
---
 Libraries/Components/Touchable/BoundingDimensions.js | 2 +-
 Libraries/Components/Touchable/Position.js           | 2 +-
 Libraries/Components/Touchable/Touchable.js          | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Libraries/Components/Touchable/BoundingDimensions.js b/Libraries/Components/Touchable/BoundingDimensions.js
index f4acffc0237e..ca63fd14b08e 100644
--- a/Libraries/Components/Touchable/BoundingDimensions.js
+++ b/Libraries/Components/Touchable/BoundingDimensions.js
@@ -2,7 +2,7 @@
  * @providesModule BoundingDimensions
  */
 
-"use strict";
+'use strict';
 
 var PooledClass = require('PooledClass');
 
diff --git a/Libraries/Components/Touchable/Position.js b/Libraries/Components/Touchable/Position.js
index 6175b6b9ea8c..0de7372e9811 100644
--- a/Libraries/Components/Touchable/Position.js
+++ b/Libraries/Components/Touchable/Position.js
@@ -2,7 +2,7 @@
  * @providesModule Position
  */
 
-"use strict";
+'use strict';
 
 var PooledClass = require('PooledClass');
 
diff --git a/Libraries/Components/Touchable/Touchable.js b/Libraries/Components/Touchable/Touchable.js
index 7b1f56a551e5..0a2f554c43b0 100644
--- a/Libraries/Components/Touchable/Touchable.js
+++ b/Libraries/Components/Touchable/Touchable.js
@@ -426,12 +426,12 @@ var TouchableMixin = {
         top: PRESS_EXPAND_PX,
         bottom: PRESS_EXPAND_PX
       };
-      
+
     var pressExpandLeft = pressRectOffset.left;
     var pressExpandTop = pressRectOffset.top;
     var pressExpandRight = pressRectOffset.right;
     var pressExpandBottom = pressRectOffset.bottom;
-    
+
     var touch = TouchEventUtils.extractSingleTouch(e.nativeEvent);
     var pageX = touch && touch.pageX;
     var pageY = touch && touch.pageY;

From c4c74215fad0c7169c3001ec7ee76daa4e90daea Mon Sep 17 00:00:00 2001
From: Denis Koroskin <dkoroskin@fb.com>
Date: Mon, 30 Nov 2015 16:36:54 -0800
Subject: [PATCH 0173/1411] Allow extending UIViewOperationQueue

Summary: public I need to extend NativeViewHierarchyManager to support a richer set of operations on Views, and those operations needs to be ran in UI thread.
Existing UIViewOperationQueue doesn't know about those operations, so I need to extend it too to allow them. This patch is making the class constructor protected to allow subclassing it from another package. Should not have any functional changes.

Reviewed By: astreet

Differential Revision: D2554826

fb-gh-sync-id: ad2d44a61beb216d940e20cd1489d3b5da1b398b
---
 .../react/uimanager/UIViewOperationQueue.java        | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
index ed507fd3ec63..f26a295eef4b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
@@ -46,7 +46,7 @@ public class UIViewOperationQueue {
   /**
    * A mutation or animation operation on the view hierarchy.
    */
-  private interface UIOperation {
+  protected interface UIOperation {
 
     void execute();
   }
@@ -440,7 +440,7 @@ public void execute() {
 
   private @Nullable NotThreadSafeViewHierarchyUpdateDebugListener mViewHierarchyUpdateDebugListener;
 
-  /* package */ UIViewOperationQueue(
+  protected UIViewOperationQueue(
       ReactApplicationContext reactContext,
       NativeViewHierarchyManager nativeViewHierarchyManager) {
     mNativeViewHierarchyManager = nativeViewHierarchyManager;
@@ -484,6 +484,14 @@ public void run() {
     }
   }
 
+  /**
+   * Enqueues a UIOperation to be executed in UI thread. This method should only be used by a
+   * subclass to support UIOperations not provided by UIViewOperationQueue.
+   */
+  protected void enqueueUIOperation(UIOperation operation) {
+    mOperations.add(operation);
+  }
+
   public void enqueueRemoveRootView(int rootViewTag) {
     mOperations.add(new RemoveRootViewOperation(rootViewTag));
   }

From fe28118a48f2677395fb209feaa21626143c3164 Mon Sep 17 00:00:00 2001
From: Denis Koroskin <dkoroskin@fb.com>
Date: Mon, 30 Nov 2015 16:47:12 -0800
Subject: [PATCH 0174/1411] When creating a View using
 NativeViewHierarchyManager, pass ThemedReactContext instead of root view tag

Summary: public NativeViewHierarchyManager.createView() takes int rootViewTag which is only used to resolve ThemedReactContext, but we already have it resolved before we enqueueCreateView, so we can just pass it directly. This makes mRootViewsContext tag -> to ThemedReactContext mapping unnecessary in NativeViewHierarchyManager. Makes the class simpler.

Reviewed By: kmagiera, astreet

Differential Revision: D2460280

fb-gh-sync-id: 68c503f4fb37ca0b1dcb2abc9e0c33a5225d1f6a
---
 .../uimanager/NativeViewHierarchyManager.java     | 15 +++------------
 .../uimanager/NativeViewHierarchyOptimizer.java   | 12 ++++++++----
 .../react/uimanager/UIImplementation.java         |  2 +-
 .../react/uimanager/UIViewOperationQueue.java     | 12 ++++++------
 4 files changed, 18 insertions(+), 23 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
index fddd7047820f..3be9a92e1db1 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
@@ -62,7 +62,6 @@
   private final SparseArray<View> mTagsToViews;
   private final SparseArray<ViewManager> mTagsToViewManagers;
   private final SparseBooleanArray mRootTags;
-  private final SparseArray<ThemedReactContext> mRootViewsContext;
   private final ViewManagerRegistry mViewManagers;
   private final JSResponderHandler mJSResponderHandler = new JSResponderHandler();
   private final RootViewManager mRootViewManager = new RootViewManager();
@@ -73,7 +72,6 @@ public NativeViewHierarchyManager(ViewManagerRegistry viewManagers) {
     mTagsToViews = new SparseArray<>();
     mTagsToViewManagers = new SparseArray<>();
     mRootTags = new SparseBooleanArray();
-    mRootViewsContext = new SparseArray<>();
   }
 
   public AnimationRegistry getAnimationRegistry() {
@@ -162,15 +160,14 @@ public void updateLayout(
   }
 
   public void createView(
-      int rootViewTagForContext,
+      ThemedReactContext themedContext,
       int tag,
       String className,
       @Nullable CatalystStylesDiffMap initialProps) {
     UiThreadUtil.assertOnUiThread();
     ViewManager viewManager = mViewManagers.get(className);
 
-    View view =
-        viewManager.createView(mRootViewsContext.get(rootViewTagForContext), mJSResponderHandler);
+    View view = viewManager.createView(themedContext, mJSResponderHandler);
     mTagsToViews.put(tag, view);
     mTagsToViewManagers.put(tag, viewManager);
 
@@ -376,7 +373,6 @@ public void addRootView(
     mTagsToViews.put(tag, view);
     mTagsToViewManagers.put(tag, mRootViewManager);
     mRootTags.put(tag, true);
-    mRootViewsContext.put(tag, themedContext);
     view.setId(tag);
   }
 
@@ -416,7 +412,6 @@ public void removeRootView(int rootViewTag) {
     View rootView = mTagsToViews.get(rootViewTag);
     dropView(rootView);
     mRootTags.delete(rootViewTag);
-    mRootViewsContext.remove(rootViewTag);
   }
 
   /**
@@ -585,14 +580,10 @@ public boolean onMenuItemClick(MenuItem item) {
   }
 
   /**
-   * @return Themed React context for view with a given {@param reactTag} - in the case of root
-   * view it returns the context from {@link #mRootViewsContext} and all the other cases it gets the
+   * @return Themed React context for view with a given {@param reactTag} -  it gets the
    * context directly from the view using {@link View#getContext}.
    */
   private ThemedReactContext getReactContextForView(int reactTag) {
-    if (mRootTags.get(reactTag)) {
-      return Assertions.assertNotNull(mRootViewsContext.get(reactTag));
-    }
     View view = mTagsToViews.get(reactTag);
     if (view == null) {
       throw new JSApplicationIllegalArgumentException("Could not find view with tag " + reactTag);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java
index fd3946eeb7c9..ef3c2c8484bb 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java
@@ -69,11 +69,15 @@ public NativeViewHierarchyOptimizer(
    */
   public void handleCreateView(
       ReactShadowNode node,
-      int rootViewTag,
+      ThemedReactContext themedContext,
       @Nullable CatalystStylesDiffMap initialProps) {
     if (!ENABLED) {
       int tag = node.getReactTag();
-      mUIViewOperationQueue.enqueueCreateView(rootViewTag, tag, node.getViewClass(), initialProps);
+      mUIViewOperationQueue.enqueueCreateView(
+          themedContext,
+          tag,
+          node.getViewClass(),
+          initialProps);
       return;
     }
 
@@ -83,7 +87,7 @@ public void handleCreateView(
 
     if (!isLayoutOnly) {
       mUIViewOperationQueue.enqueueCreateView(
-          rootViewTag,
+          themedContext,
           node.getReactTag(),
           node.getViewClass(),
           initialProps);
@@ -391,7 +395,7 @@ private void transitionLayoutOnlyViewToNativeView(
 
     // Create the view since it doesn't exist in the native hierarchy yet
     mUIViewOperationQueue.enqueueCreateView(
-        node.getRootNode().getReactTag(),
+        node.getRootNode().getThemedContext(),
         node.getReactTag(),
         node.getViewClass(),
         props);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
index 94b2307b1702..369ffda90f6c 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
@@ -121,7 +121,7 @@ public void createView(int tag, String className, int rootViewTag, ReadableMap p
     }
 
     if (!cssNode.isVirtual()) {
-      mNativeViewHierarchyOptimizer.handleCreateView(cssNode, rootViewTag, styles);
+      mNativeViewHierarchyOptimizer.handleCreateView(cssNode, rootNode.getThemedContext(), styles);
     }
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
index f26a295eef4b..6f0ebdcc9258 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
@@ -122,17 +122,17 @@ public void execute() {
 
   private final class CreateViewOperation extends ViewOperation {
 
-    private final int mRootViewTagForContext;
+    private final ThemedReactContext mThemedContext;
     private final String mClassName;
     private final @Nullable CatalystStylesDiffMap mInitialProps;
 
     public CreateViewOperation(
-        int rootViewTagForContext,
+        ThemedReactContext themedContext,
         int tag,
         String className,
         @Nullable CatalystStylesDiffMap initialProps) {
       super(tag);
-      mRootViewTagForContext = rootViewTagForContext;
+      mThemedContext = themedContext;
       mClassName = className;
       mInitialProps = initialProps;
     }
@@ -140,7 +140,7 @@ public CreateViewOperation(
     @Override
     public void execute() {
       mNativeViewHierarchyManager.createView(
-          mRootViewTagForContext,
+          mThemedContext,
           mTag,
           mClassName,
           mInitialProps);
@@ -533,13 +533,13 @@ public void enqueueShowPopupMenu(
   }
 
   public void enqueueCreateView(
-      int rootViewTagForContext,
+      ThemedReactContext themedContext,
       int viewReactTag,
       String viewClassName,
       @Nullable CatalystStylesDiffMap initialProps) {
     mOperations.add(
         new CreateViewOperation(
-            rootViewTagForContext,
+            themedContext,
             viewReactTag,
             viewClassName,
             initialProps));

From da9e9e709b42a8875d38977c4ae37c88de92b084 Mon Sep 17 00:00:00 2001
From: Perry Poon <plrthink@gmail.com>
Date: Tue, 1 Dec 2015 10:50:35 +0800
Subject: [PATCH 0175/1411] add mockingbot to showcase

---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 7d9bbfd816a9..ab74ad8aad96 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -386,6 +386,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/yazboz-batak-esli-batak-okey/id1048620855?ls=1&mt=8',
     author: 'Melih Mucuk',
   },
+  {
+    name: 'MockingBot',
+    icon: 'https://s3.cn-north-1.amazonaws.com.cn/modao/downloads/images/MockingBot175.png',
+    link: 'https://itunes.apple.com/cn/app/mockingbot/id1050565468?l=en&mt=8',
+    author: 'YuanYi Zhang (@mockingbot)',
+  },
 ];
 
 var AppList = React.createClass({

From 00046bc832d5b0f87a56d3016d6fe4ab1d6898aa Mon Sep 17 00:00:00 2001
From: Denis Koroskin <dkoroskin@fb.com>
Date: Mon, 30 Nov 2015 18:03:09 -0800
Subject: [PATCH 0176/1411] Allow extending NativeViewHierarchyManager

Summary: public This diff makes a few small changes to NativeViewHierarchyManager to allow extending it:
a) makes the class public so it can be constructed from outside of the package
b) adds resolveView and resolveViewManager to access mTagsToViews and mTagsToViewManagers
c) changes addRootView signature to make root view a ViewGroup instead of SizeMonitoringFrameLayout

The reason behind change c) is that in FlatUIImplementation I want to use a root view that does not extend SizeMonitoringFrameLayout. NativeViewHierarchyManager doesn't really use any of the root view properties, so it could be even a View, but ViewGroup seems more fitting.

This diff should contain no functional changes or other side-effects.

Reviewed By: astreet

Differential Revision: D2554841

fb-gh-sync-id: cce748707cf7485d456e4a057dae1db87aa17160
---
 .../uimanager/NativeViewHierarchyManager.java | 70 +++++++++----------
 1 file changed, 33 insertions(+), 37 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
index 3be9a92e1db1..28b95139ca9a 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
@@ -56,7 +56,7 @@
  * TODO(5483031): Only dispatch updates when shadow views have changed
  */
 @NotThreadSafe
-/* package */ final class NativeViewHierarchyManager {
+public class NativeViewHierarchyManager {
 
   private final AnimationRegistry mAnimationRegistry;
   private final SparseArray<View> mTagsToViews;
@@ -74,39 +74,40 @@ public NativeViewHierarchyManager(ViewManagerRegistry viewManagers) {
     mRootTags = new SparseBooleanArray();
   }
 
-  public AnimationRegistry getAnimationRegistry() {
-    return mAnimationRegistry;
+  protected final View resolveView(int tag) {
+    View view = mTagsToViews.get(tag);
+    if (view == null) {
+      throw new IllegalViewOperationException("Trying to resolve view with tag " + tag
+          + " which doesn't exist");
+    }
+    return view;
   }
 
-  public void updateProperties(int tag, CatalystStylesDiffMap props) {
-    UiThreadUtil.assertOnUiThread();
-
+  protected final ViewManager resolveViewManager(int tag) {
     ViewManager viewManager = mTagsToViewManagers.get(tag);
     if (viewManager == null) {
       throw new IllegalViewOperationException("ViewManager for tag " + tag + " could not be found");
     }
+    return viewManager;
+  }
 
-    View viewToUpdate = mTagsToViews.get(tag);
-    if (viewToUpdate == null) {
-      throw new IllegalViewOperationException("Trying to update view with tag " + tag
-          + " which doesn't exist");
-    }
+  public AnimationRegistry getAnimationRegistry() {
+    return mAnimationRegistry;
+  }
+
+  public void updateProperties(int tag, CatalystStylesDiffMap props) {
+    UiThreadUtil.assertOnUiThread();
+
+    ViewManager viewManager = resolveViewManager(tag);
+    View viewToUpdate = resolveView(tag);
     viewManager.updateProperties(viewToUpdate, props);
   }
 
   public void updateViewExtraData(int tag, Object extraData) {
     UiThreadUtil.assertOnUiThread();
 
-    ViewManager viewManager = mTagsToViewManagers.get(tag);
-    if (viewManager == null) {
-      throw new IllegalViewOperationException("ViewManager for tag " + tag + " could not be found");
-    }
-
-    View viewToUpdate = mTagsToViews.get(tag);
-    if (viewToUpdate == null) {
-      throw new IllegalViewOperationException("Trying to update view with tag " + tag + " which " +
-          "doesn't exist");
-    }
+    ViewManager viewManager = resolveViewManager(tag);
+    View viewToUpdate = resolveView(tag);
     viewManager.updateExtraData(viewToUpdate, extraData);
   }
 
@@ -119,11 +120,7 @@ public void updateLayout(
       int height) {
     UiThreadUtil.assertOnUiThread();
 
-    View viewToUpdate = mTagsToViews.get(tag);
-    if (viewToUpdate == null) {
-      throw new IllegalViewOperationException("Trying to update view with tag " + tag + " which " +
-          "doesn't exist");
-    }
+    View viewToUpdate = resolveView(tag);
 
     // Even though we have exact dimensions, we still call measure because some platform views (e.g.
     // Switch) assume that method will always be called before onLayout and onDraw. They use it to
@@ -257,10 +254,7 @@ public void manageChildren(
       @Nullable ViewAtIndex[] viewsToAdd,
       @Nullable int[] tagsToDelete) {
     ViewGroup viewToManage = (ViewGroup) mTagsToViews.get(tag);
-    ViewGroupManager viewManager = (ViewGroupManager) mTagsToViewManagers.get(tag);
-    if (viewManager == null) {
-      throw new IllegalViewOperationException("ViewManager for tag " + tag + " could not be found");
-    }
+    ViewGroupManager viewManager = (ViewGroupManager) resolveViewManager(tag);
     if (viewToManage == null) {
       throw new IllegalViewOperationException("Trying to manageChildren view with tag " + tag +
         " which doesn't exist\n detail: " +
@@ -362,6 +356,13 @@ public void addRootView(
       int tag,
       SizeMonitoringFrameLayout view,
       ThemedReactContext themedContext) {
+    addRootViewGroup(tag, view, themedContext);
+  }
+
+  protected final void addRootViewGroup(
+      int tag,
+      ViewGroup view,
+      ThemedReactContext themedContext) {
     UiThreadUtil.assertOnUiThread();
     if (view.getId() != View.NO_ID) {
       throw new IllegalViewOperationException(
@@ -383,7 +384,7 @@ private void dropView(View view) {
     UiThreadUtil.assertOnUiThread();
     if (!mRootTags.get(view.getId())) {
       // For non-root views we notify viewmanager with {@link ViewManager#onDropInstance}
-      Assertions.assertNotNull(mTagsToViewManagers.get(view.getId())).onDropViewInstance(
+      resolveViewManager(view.getId()).onDropViewInstance(
           (ThemedReactContext) view.getContext(),
           view);
     }
@@ -512,12 +513,7 @@ public void dispatchCommand(int reactTag, int commandId, @Nullable ReadableArray
           "with tag " + reactTag);
     }
 
-    ViewManager viewManager = mTagsToViewManagers.get(reactTag);
-    if (viewManager == null) {
-      throw new IllegalViewOperationException(
-          "ViewManager for view tag " + reactTag + " could not be found");
-    }
-
+    ViewManager viewManager = resolveViewManager(reactTag);
     viewManager.receiveCommand(view, commandId, args);
   }
 

From baa97b2e9fd4125df6112573cb793688ed6f63c6 Mon Sep 17 00:00:00 2001
From: Denis Koroskin <dkoroskin@fb.com>
Date: Mon, 30 Nov 2015 18:18:52 -0800
Subject: [PATCH 0177/1411] Make ViewManagerRegistry class public

Summary: public I need to construct this class outside of the uimanager package, and this requires the class (and its constructor) to be public.

Reviewed By: astreet

Differential Revision: D2554847

fb-gh-sync-id: a73c3236b91a1ed7074521e19b72e1994804cced
---
 .../com/facebook/react/uimanager/ViewManagerRegistry.java     | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerRegistry.java
index 2dffc8c26ca7..3dfacf1b387e 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerRegistry.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerRegistry.java
@@ -17,7 +17,7 @@
  * Class that stores the mapping between native view name used in JS and the corresponding instance
  * of {@link ViewManager}.
  */
-/* package */ class ViewManagerRegistry {
+public class ViewManagerRegistry {
 
   private final Map<String, ViewManager> mViewManagers = new HashMap<>();
 
@@ -27,7 +27,7 @@ public ViewManagerRegistry(List<ViewManager> viewManagerList) {
     }
   }
 
-  /* package */ ViewManager get(String className) {
+  public ViewManager get(String className) {
     ViewManager viewManager = mViewManagers.get(className);
     if (viewManager != null) {
       return viewManager;

From 7242efde0ae56545fedc29630fa70158128dca7d Mon Sep 17 00:00:00 2001
From: Huang Yu <huang@bitgo.com>
Date: Mon, 30 Nov 2015 19:30:17 -0800
Subject: [PATCH 0178/1411] fix navigator lint warnings

Summary: fix some lint warnings under `Libraries/CustomComponents/Navigator/` directory
Closes https://github.com/facebook/react-native/pull/4447

Reviewed By: svcscm

Differential Revision: D2706390

Pulled By: ericvicenti

fb-gh-sync-id: 5bfed687265e07a162ffc528a41fa5b0d384f635
---
 Libraries/CustomComponents/Navigator/Navigator.js      |  4 ++--
 .../Navigator/NavigatorBreadcrumbNavigationBar.js      | 10 +++++-----
 .../NavigatorBreadcrumbNavigationBarStyles.ios.js      |  2 +-
 .../Navigator/NavigatorNavigationBar.js                |  1 -
 .../Navigator/NavigatorNavigationBarStylesIOS.js       |  4 ++--
 5 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/Libraries/CustomComponents/Navigator/Navigator.js b/Libraries/CustomComponents/Navigator/Navigator.js
index e11ee25055ed..22bb84365235 100644
--- a/Libraries/CustomComponents/Navigator/Navigator.js
+++ b/Libraries/CustomComponents/Navigator/Navigator.js
@@ -675,7 +675,7 @@ var Navigator = React.createClass({
         this.state.presentedIndex = destIndex;
         this._transitionTo(
           transitionBackToPresentedIndex,
-          - transitionVelocity,
+          -transitionVelocity,
           1 - this.spring.getCurrentValue()
         );
       }
@@ -750,7 +750,7 @@ var Navigator = React.createClass({
     var isTravelVertical = gesture.direction === 'top-to-bottom' || gesture.direction === 'bottom-to-top';
     var isTravelInverted = gesture.direction === 'right-to-left' || gesture.direction === 'bottom-to-top';
     var distance = isTravelVertical ? gestureState.dy : gestureState.dx;
-    distance = isTravelInverted ? - distance : distance;
+    distance = isTravelInverted ? -distance : distance;
     var gestureDetectMovement = gesture.gestureDetectMovement;
     var nextProgress = (distance - gestureDetectMovement) /
       (gesture.fullDistance - gestureDetectMovement);
diff --git a/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js b/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js
index b205327afa18..ccf28f1f9d1e 100644
--- a/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js
+++ b/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js
@@ -46,11 +46,11 @@ var PropTypes = React.PropTypes;
 /**
  * Reusable props objects.
  */
-var CRUMB_PROPS = Interpolators.map(() => {return {style: {}};});
-var ICON_PROPS = Interpolators.map(() => {return {style: {}};});
-var SEPARATOR_PROPS = Interpolators.map(() => {return {style: {}};});
-var TITLE_PROPS = Interpolators.map(() => {return {style: {}};});
-var RIGHT_BUTTON_PROPS = Interpolators.map(() => {return {style: {}};});
+var CRUMB_PROPS = Interpolators.map(() => ({style: {}}));
+var ICON_PROPS = Interpolators.map(() => ({style: {}}));
+var SEPARATOR_PROPS = Interpolators.map(() => ({style: {}}));
+var TITLE_PROPS = Interpolators.map(() => ({style: {}}));
+var RIGHT_BUTTON_PROPS = Interpolators.map(() => ({style: {}}));
 
 
 var navStatePresentedIndex = function(navState) {
diff --git a/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBarStyles.ios.js b/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBarStyles.ios.js
index d73cb5661661..eea15eee9bec 100644
--- a/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBarStyles.ios.js
+++ b/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBarStyles.ios.js
@@ -136,7 +136,7 @@ CENTER[0] = {
   Title: merge(FIRST_TITLE_BASE, {opacity: 1}),
   RightItem: CENTER[0].RightItem,
 };
-LEFT[0].Title = merge(FIRST_TITLE_BASE, {left: - SCREEN_WIDTH / 4, opacity: 0});
+LEFT[0].Title = merge(FIRST_TITLE_BASE, {left: -SCREEN_WIDTH / 4, opacity: 0});
 RIGHT[0].Title = merge(FIRST_TITLE_BASE, {opacity: 0});
 
 
diff --git a/Libraries/CustomComponents/Navigator/NavigatorNavigationBar.js b/Libraries/CustomComponents/Navigator/NavigatorNavigationBar.js
index 2b6c79def612..b6fbcdc378e5 100644
--- a/Libraries/CustomComponents/Navigator/NavigatorNavigationBar.js
+++ b/Libraries/CustomComponents/Navigator/NavigatorNavigationBar.js
@@ -30,7 +30,6 @@ var React = require('React');
 var NavigatorNavigationBarStylesAndroid = require('NavigatorNavigationBarStylesAndroid');
 var NavigatorNavigationBarStylesIOS = require('NavigatorNavigationBarStylesIOS');
 var Platform = require('Platform');
-var StaticContainer = require('StaticContainer.react');
 var StyleSheet = require('StyleSheet');
 var View = require('View');
 
diff --git a/Libraries/CustomComponents/Navigator/NavigatorNavigationBarStylesIOS.js b/Libraries/CustomComponents/Navigator/NavigatorNavigationBarStylesIOS.js
index fdad315adc81..9e14677519a4 100644
--- a/Libraries/CustomComponents/Navigator/NavigatorNavigationBarStylesIOS.js
+++ b/Libraries/CustomComponents/Navigator/NavigatorNavigationBarStylesIOS.js
@@ -76,8 +76,8 @@ var BASE_STYLES = {
 // center-to-left transition on the current navigation item.
 var Stages = {
   Left: {
-    Title: merge(BASE_STYLES.Title, { left: - SCREEN_WIDTH / 2, opacity: 0 }),
-    LeftButton: merge(BASE_STYLES.LeftButton, { left: - SCREEN_WIDTH / 3, opacity: 0 }),
+    Title: merge(BASE_STYLES.Title, { left: -SCREEN_WIDTH / 2, opacity: 0 }),
+    LeftButton: merge(BASE_STYLES.LeftButton, { left: -SCREEN_WIDTH / 3, opacity: 0 }),
     RightButton: merge(BASE_STYLES.RightButton, { left: SCREEN_WIDTH / 3, opacity: 0 }),
   },
   Center: {

From f025049b6cc10fc1c91556a8dd250d94329bf363 Mon Sep 17 00:00:00 2001
From: Christopher Dro <hello@blick-labs.com>
Date: Mon, 30 Nov 2015 18:44:06 -0800
Subject: [PATCH 0179/1411] Add secure and login-password types to AlertIOS.

Summary: Request from issue #3893

* Added support for `secure-text` and `login-password` types to AlertIOS.
* Fixed and extended the cancel button highlighting functionality, which was broken at some point
* Added localization for default `OK` and `Cancel` labels when using UIAlertController

Closes https://github.com/facebook/react-native/pull/4401

Reviewed By: javache

Differential Revision: D2702052

Pulled By: nicklockwood

fb-gh-sync-id: cce312d7fec949f5fd2a7c656e65c657c4832c8f
---
 Examples/UIExplorer/AlertIOSExample.js |  88 ++++++++++++-
 Libraries/Utilities/AlertIOS.js        |  69 ++++++-----
 React/Base/RCTUtils.h                  |   3 +
 React/Base/RCTUtils.m                  |   8 ++
 React/Modules/RCTAlertManager.m        | 164 +++++++++++++++++--------
 5 files changed, 249 insertions(+), 83 deletions(-)

diff --git a/Examples/UIExplorer/AlertIOSExample.js b/Examples/UIExplorer/AlertIOSExample.js
index e09c883c137e..8666d5ba9bcc 100644
--- a/Examples/UIExplorer/AlertIOSExample.js
+++ b/Examples/UIExplorer/AlertIOSExample.js
@@ -43,7 +43,7 @@ exports.examples = [{
         </TouchableHighlight>
         <TouchableHighlight style={styles.wrapper}
           onPress={() => AlertIOS.alert(
-            null,
+            'Foo Title',
             null,
             [
               {text: 'Button', onPress: () => console.log('Button Pressed!')},
@@ -97,6 +97,87 @@ exports.examples = [{
     );
   }
 },
+{
+  title: 'Alert Types',
+  render() {
+    return (
+      <View>
+        <TouchableHighlight
+          style={styles.wrapper}
+          onPress={() => AlertIOS.alert(
+            'Hello World',
+            null,
+            [
+              {text: 'OK', onPress: (text) => console.log('OK pressed')},
+            ],
+            'default'
+          )}>
+
+          <View style={styles.button}>
+            <Text>
+              {'default'}
+            </Text>
+          </View>
+          
+        </TouchableHighlight>
+        <TouchableHighlight
+          style={styles.wrapper}
+          onPress={() => AlertIOS.alert(
+            'Plain Text Entry',
+            null,
+            [
+              {text: 'Submit', onPress: (text) => console.log('Text: ' + text)},
+            ],
+            'plain-text'
+          )}>
+
+          <View style={styles.button}>
+            <Text>
+              plain-text
+            </Text>
+          </View>
+          
+        </TouchableHighlight>
+        <TouchableHighlight
+          style={styles.wrapper}
+          onPress={() => AlertIOS.alert(
+            'Secure Text Entry',
+            null,
+            [
+              {text: 'Submit', onPress: (text) => console.log('Password: ' + text)},
+            ],
+            'secure-text'
+          )}>
+
+          <View style={styles.button}>
+            <Text>
+              secure-text
+            </Text>
+          </View>
+          
+        </TouchableHighlight>
+        <TouchableHighlight
+          style={styles.wrapper}
+          onPress={() => AlertIOS.alert(
+            'Login & Password',
+            null,
+            [
+              {text: 'Submit', onPress: (details) => console.log('Login: ' + details.login + '; Password: ' + details.password)},
+            ],
+            'login-password'
+          )}>
+
+          <View style={styles.button}>
+            <Text>
+              login-password
+            </Text>
+          </View>
+          
+        </TouchableHighlight>
+      </View>
+    );
+  }
+},
 {
   title: 'Prompt',
   render(): React.Component {
@@ -116,10 +197,11 @@ class PromptExample extends React.Component {
     this.title = 'Type a value';
     this.defaultValue = 'Default value';
     this.buttons = [{
-      text: 'Custom cancel',
-    }, {
       text: 'Custom OK',
       onPress: this.promptResponse
+    }, {
+      text: 'Custom Cancel',
+      style: 'cancel',
     }];
   }
 
diff --git a/Libraries/Utilities/AlertIOS.js b/Libraries/Utilities/AlertIOS.js
index 7fd15d254ae6..2bd1a3223680 100644
--- a/Libraries/Utilities/AlertIOS.js
+++ b/Libraries/Utilities/AlertIOS.js
@@ -14,11 +14,18 @@
 var RCTAlertManager = require('NativeModules').AlertManager;
 var invariant = require('invariant');
 
-var DEFAULT_BUTTON_TEXT = 'OK';
-var DEFAULT_BUTTON = {
-  text: DEFAULT_BUTTON_TEXT,
-  onPress: null,
-};
+type AlertType = $Enum<{
+  'default': string;
+  'plain-text': string;
+  'secure-text': string;
+  'login-password': string;
+}>;
+
+type AlertButtonStyle = $Enum<{
+  'default': string;
+  'cancel': string;
+  'destructive': string;
+}>;
 
 /**
  * Launches an alert dialog with the specified title and message.
@@ -27,16 +34,13 @@ var DEFAULT_BUTTON = {
  * respective onPress callback and dismiss the alert. By default, the only
  * button will be an 'OK' button
  *
- * The last button in the list will be considered the 'Primary' button and
- * it will appear bold.
- *
  * ```
  * AlertIOS.alert(
  *   'Foo Title',
  *   'My Alert Msg',
  *   [
- *     {text: 'Foo', onPress: () => console.log('Foo Pressed!')},
- *     {text: 'Bar', onPress: () => console.log('Bar Pressed!')},
+ *     {text: 'OK', onPress: () => console.log('OK Pressed!')},
+ *     {text: 'Cancel', onPress: () => console.log('Cancel Pressed!'), style: 'cancel'},
  *   ]
  * )
  * ```
@@ -47,29 +51,36 @@ class AlertIOS {
     title: ?string,
     message?: ?string,
     buttons?: Array<{
-      text: ?string;
+      text?: string;
       onPress?: ?Function;
+      style?: AlertButtonStyle;
     }>,
-    type?: ?string
+    type?: ?AlertType
   ): void {
     var callbacks = [];
     var buttonsSpec = [];
-    title = title || '';
-    message = message || '';
-    buttons = buttons || [DEFAULT_BUTTON];
-    type = type || '';
-
-    buttons.forEach((btn, index) => {
+    var cancelButtonKey;
+    var destructiveButtonKey;
+    buttons && buttons.forEach((btn, index) => {
       callbacks[index] = btn.onPress;
-      var btnDef = {};
-      btnDef[index] = btn.text || DEFAULT_BUTTON_TEXT;
-      buttonsSpec.push(btnDef);
+      if (btn.style == 'cancel') {
+        cancelButtonKey = String(index);
+      } else if (btn.style == 'destructive') {
+        destructiveButtonKey = String(index);
+      }
+      if (btn.text || index < (buttons || []).length - 1) {
+        var btnDef = {};
+        btnDef[index] = btn.text || '';
+        buttonsSpec.push(btnDef);
+      }
     });
     RCTAlertManager.alertWithArgs({
-      title,
-      message,
+      title: title || undefined,
+      message: message || undefined,
       buttons: buttonsSpec,
-      type,
+      type: type || undefined,
+      cancelButtonKey,
+      destructiveButtonKey,
     }, (id, value) => {
       var cb = callbacks[id];
       cb && cb(value);
@@ -80,8 +91,9 @@ class AlertIOS {
     title: string,
     value?: string,
     buttons?: Array<{
-      text: ?string;
+      text?: string;
       onPress?: ?Function;
+      style?: AlertButtonStyle;
     }>,
     callback?: ?Function
   ): void {
@@ -104,12 +116,7 @@ class AlertIOS {
     );
 
     if (!buttons) {
-      buttons = [{
-        text: 'Cancel',
-      }, {
-        text: 'OK',
-        onPress: callback
-      }];
+      buttons = [{ onPress: callback }];
     }
     this.alert(title, value, buttons, 'plain-text');
   }
diff --git a/React/Base/RCTUtils.h b/React/Base/RCTUtils.h
index e8f3781a6c61..251167e0ba34 100644
--- a/React/Base/RCTUtils.h
+++ b/React/Base/RCTUtils.h
@@ -102,3 +102,6 @@ RCT_EXTERN BOOL RCTIsXCAssetURL(NSURL *imageURL);
 
 // Converts a CGColor to a hex string
 RCT_EXTERN NSString *RCTColorToHexString(CGColorRef color);
+
+// Get standard localized string (if it exists)
+RCT_EXTERN NSString *RCTUIKitLocalizedString(NSString *string);
diff --git a/React/Base/RCTUtils.m b/React/Base/RCTUtils.m
index b7a751488378..d1254a98abbd 100644
--- a/React/Base/RCTUtils.m
+++ b/React/Base/RCTUtils.m
@@ -575,3 +575,11 @@ static void RCTGetRGBAColorComponents(CGColorRef color, CGFloat rgba[4])
     return [NSString stringWithFormat:@"#%02x%02x%02x", r, g, b];
   }
 }
+
+
+// (https://github.com/0xced/XCDFormInputAccessoryView/blob/master/XCDFormInputAccessoryView/XCDFormInputAccessoryView.m#L10-L14)
+RCT_EXTERN NSString *RCTUIKitLocalizedString(NSString *string)
+{
+  NSBundle *UIKitBundle = [NSBundle bundleForClass:[UIApplication class]];
+  return UIKitBundle ? [UIKitBundle localizedStringForKey:string value:string table:nil] : string;
+}
diff --git a/React/Modules/RCTAlertManager.m b/React/Modules/RCTAlertManager.m
index 74168866af06..d735d54423a2 100644
--- a/React/Modules/RCTAlertManager.m
+++ b/React/Modules/RCTAlertManager.m
@@ -14,6 +14,17 @@
 #import "RCTLog.h"
 #import "RCTUtils.h"
 
+@implementation RCTConvert (UIAlertViewStyle)
+
+RCT_ENUM_CONVERTER(UIAlertViewStyle, (@{
+  @"default": @(UIAlertViewStyleDefault),
+  @"secure-text": @(UIAlertViewStyleSecureTextInput),
+  @"plain-text": @(UIAlertViewStylePlainTextInput),
+  @"login-password": @(UIAlertViewStyleLoginAndPasswordInput),
+}), UIAlertViewStyleDefault, integerValue)
+
+@end
+
 @interface RCTAlertManager() <UIAlertViewDelegate>
 
 @end
@@ -50,58 +61,69 @@ - (void)invalidate
  *     @"message": @"<Alert message>",
  *     @"buttons": @[
  *       @{@"<key1>": @"<title1>"},
- *       @{@"<key2>": @"<cancelButtonTitle>"},
- *     ]
+ *       @{@"<key2>": @"<title2>"},
+ *     ],
+ *     @"cancelButtonKey": @"<key2>",
  *   }
  * The key from the `buttons` dictionary is passed back in the callback on click.
- * Buttons are displayed in the order they are specified. If "cancel" is used as
- * the button key, it will be differently highlighted, according to iOS UI conventions.
+ * Buttons are displayed in the order they are specified.
  */
 RCT_EXPORT_METHOD(alertWithArgs:(NSDictionary *)args
                   callback:(RCTResponseSenderBlock)callback)
 {
   NSString *title = [RCTConvert NSString:args[@"title"]];
   NSString *message = [RCTConvert NSString:args[@"message"]];
-  NSString *type = [RCTConvert NSString:args[@"type"]];
-  NSDictionaryArray *buttons = [RCTConvert NSDictionaryArray:args[@"buttons"]];
-  BOOL allowsTextInput = [type isEqual:@"plain-text"];
+  UIAlertViewStyle type = [RCTConvert UIAlertViewStyle:args[@"type"]];
+  NSArray<NSDictionary *> *buttons = [RCTConvert NSDictionaryArray:args[@"buttons"]];
+  NSString *cancelButtonKey = [RCTConvert NSString:args[@"cancelButtonKey"]];
+  NSString *destructiveButtonKey = [RCTConvert NSString:args[@"destructiveButtonKey"]];
 
   if (!title && !message) {
     RCTLogError(@"Must specify either an alert title, or message, or both");
     return;
-  } else if (buttons.count == 0) {
-    RCTLogError(@"Must have at least one button.");
-    return;
+  }
+
+  if (buttons.count == 0) {
+    if (type == UIAlertViewStyleDefault) {
+      buttons = @[@{@"0": RCTUIKitLocalizedString(@"OK")}];
+      cancelButtonKey = @"0";
+    } else {
+      buttons = @[
+        @{@"0": RCTUIKitLocalizedString(@"OK")},
+        @{@"1": RCTUIKitLocalizedString(@"Cancel")},
+      ];
+      cancelButtonKey = @"1";
+    }
   }
 
 #if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0
 
-  // TODO: we've encountered some bug when presenting alerts on top of a window that is subsequently
-  // dismissed. As a temporary solution to this, we'll use UIAlertView preferentially if it's available.
-  BOOL preferAlertView = (!RCTRunningInAppExtension() && UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone);
+  // TODO: we've encountered some bug when presenting alerts on top of a window
+  // that is subsequently dismissed. As a temporary solution to this, we'll use
+  // UIAlertView preferentially if it's available and supports our use case.
+  BOOL preferAlertView = (!RCTRunningInAppExtension() &&
+                          !destructiveButtonKey &&
+                          UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone);
 
   if (preferAlertView || [UIAlertController class] == nil) {
 
     UIAlertView *alertView = RCTAlertView(title, nil, self, nil, nil);
-    NSMutableArray<NSString *> *buttonKeys = [[NSMutableArray alloc] initWithCapacity:buttons.count];
+    alertView.alertViewStyle = type;
+    alertView.message = message;
 
-    if (allowsTextInput) {
-      alertView.alertViewStyle = UIAlertViewStylePlainTextInput;
-      [alertView textFieldAtIndex:0].text = message;
-    } else {
-      alertView.message = message;
-    }
+    NSMutableArray<NSString *> *buttonKeys =
+      [[NSMutableArray alloc] initWithCapacity:buttons.count];
 
     NSInteger index = 0;
-    for (NSDictionary *button in buttons) {
+    for (NSDictionary<NSString *, id> *button in buttons) {
       if (button.count != 1) {
         RCTLogError(@"Button definitions should have exactly one key.");
       }
       NSString *buttonKey = button.allKeys.firstObject;
-      NSString *buttonTitle = [button[buttonKey] description];
+      NSString *buttonTitle = [RCTConvert NSString:button[buttonKey]];
       [alertView addButtonWithTitle:buttonTitle];
-      if ([buttonKey isEqualToString:@"cancel"]) {
-        alertView.cancelButtonIndex = index;
+      if ([buttonKey isEqualToString:cancelButtonKey]) {
+        alertView.cancelButtonIndex = buttonKeys.count;
       }
       [buttonKeys addObject:buttonKey];
       index ++;
@@ -129,42 +151,74 @@ - (void)invalidate
       return;
     }
 
-    // Walk the chain up to get the topmost modal view controller. If modals are presented,
-    // the root view controller's view might not be in the window hierarchy, and presenting from it will fail.
+    // Walk the chain up to get the topmost modal view controller. If modals are
+    // presented the root view controller's view might not be in the window
+    // hierarchy, and presenting from it will fail.
     while (presentingController.presentedViewController) {
       presentingController = presentingController.presentedViewController;
     }
 
     UIAlertController *alertController =
-    [UIAlertController alertControllerWithTitle:title
-                                        message:nil
-                                 preferredStyle:UIAlertControllerStyleAlert];
-
-    if (allowsTextInput) {
-      [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
-        textField.text = message;
-      }];
-    } else {
-      alertController.message = message;
+      [UIAlertController alertControllerWithTitle:title
+                                          message:nil
+                                   preferredStyle:UIAlertControllerStyleAlert];
+    switch (type) {
+      case UIAlertViewStylePlainTextInput:
+        [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
+          textField.secureTextEntry = NO;
+        }];
+        break;
+      case UIAlertViewStyleSecureTextInput:
+        [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
+          textField.placeholder = RCTUIKitLocalizedString(@"Password");
+          textField.secureTextEntry = YES;
+        }];
+        break;
+      case UIAlertViewStyleLoginAndPasswordInput:
+        [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
+          textField.placeholder = RCTUIKitLocalizedString(@"Login");
+        }];
+        [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
+          textField.placeholder = RCTUIKitLocalizedString(@"Password");
+          textField.secureTextEntry = YES;
+        }];
+      case UIAlertViewStyleDefault:
+        break;
     }
 
-    for (NSDictionary *button in buttons) {
+    alertController.message = message;
+
+    for (NSDictionary<NSString *, id> *button in buttons) {
       if (button.count != 1) {
         RCTLogError(@"Button definitions should have exactly one key.");
       }
       NSString *buttonKey = button.allKeys.firstObject;
-      NSString *buttonTitle = [button[buttonKey] description];
-      UIAlertActionStyle buttonStyle = [buttonKey isEqualToString:@"cancel"] ? UIAlertActionStyleCancel : UIAlertActionStyleDefault;
-      UITextField *textField = allowsTextInput ? alertController.textFields.firstObject : nil;
+      NSString *buttonTitle = [RCTConvert NSString:button[buttonKey]];
+      UIAlertActionStyle buttonStyle = UIAlertActionStyleDefault;
+      if ([buttonKey isEqualToString:cancelButtonKey]) {
+        buttonStyle = UIAlertActionStyleCancel;
+      } else if ([buttonKey isEqualToString:destructiveButtonKey]) {
+        buttonStyle = UIAlertActionStyleDestructive;
+      }
       [alertController addAction:[UIAlertAction actionWithTitle:buttonTitle
                                                           style:buttonStyle
                                                         handler:^(__unused UIAlertAction *action) {
-        if (callback) {
-          if (allowsTextInput) {
-            callback(@[buttonKey, textField.text]);
-          } else {
-            callback(@[buttonKey]);
+        switch (type) {
+          case UIAlertViewStylePlainTextInput:
+          case UIAlertViewStyleSecureTextInput:
+            callback(@[buttonKey, [alertController.textFields.firstObject text]]);
+            break;
+          case UIAlertViewStyleLoginAndPasswordInput: {
+            NSDictionary<NSString *, NSString *> *loginCredentials = @{
+              @"login": [alertController.textFields.firstObject text],
+              @"password": [alertController.textFields.lastObject text]
+            };
+            callback(@[buttonKey, loginCredentials]);
+            break;
           }
+          case UIAlertViewStyleDefault:
+            callback(@[buttonKey]);
+            break;
         }
       }]];
     }
@@ -188,10 +242,22 @@ - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)butto
   RCTResponseSenderBlock callback = _alertCallbacks[index];
   NSArray<NSString *> *buttonKeys = _alertButtonKeys[index];
 
-  if (alertView.alertViewStyle == UIAlertViewStylePlainTextInput) {
-    callback(@[buttonKeys[buttonIndex], [alertView textFieldAtIndex:0].text]);
-  } else {
-    callback(@[buttonKeys[buttonIndex]]);
+  switch (alertView.alertViewStyle) {
+    case UIAlertViewStylePlainTextInput:
+    case UIAlertViewStyleSecureTextInput:
+      callback(@[buttonKeys[buttonIndex], [alertView textFieldAtIndex:0].text]);
+      break;
+    case UIAlertViewStyleLoginAndPasswordInput: {
+      NSDictionary<NSString *, NSString *> *loginCredentials = @{
+        @"login": [alertView textFieldAtIndex:0].text,
+        @"password": [alertView textFieldAtIndex:1].text,
+      };
+      callback(@[buttonKeys[buttonIndex], loginCredentials]);
+      break;
+    }
+    case UIAlertViewStyleDefault:
+      callback(@[buttonKeys[buttonIndex]]);
+      break;
   }
 
   [_alerts removeObjectAtIndex:index];

From aad40b8b1d3c53145272fd958a0e9f1cdc4531a0 Mon Sep 17 00:00:00 2001
From: Krzysztof Magiera <krzys.magiera@gmail.com>
Date: Tue, 1 Dec 2015 09:55:57 +0100
Subject: [PATCH 0180/1411] Update Android Setup with recommendation to use
 gradle daemon

---
 docs/DevelopmentSetupAndroid.md | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/docs/DevelopmentSetupAndroid.md b/docs/DevelopmentSetupAndroid.md
index 2cc0a9159373..6a7b7d87f3c6 100644
--- a/docs/DevelopmentSetupAndroid.md
+++ b/docs/DevelopmentSetupAndroid.md
@@ -30,6 +30,10 @@ __IMPORTANT__: Make sure the `ANDROID_HOME` environment variable points to your
 
   - **On Windows**, go to `Control Panel` -> `System and Security` -> `System` -> `Change settings` -> `Advanced` -> `Environment variables` -> `New`
 
+### Use gradle daemon
+
+React Native Android use [gradle](https://docs.gradle.org) as a build system. We recommend to enable gradle daemon functionailty which may result in up to 50% improvement in incremental build times for changes in java code. Learn [here](https://docs.gradle.org/2.9/userguide/gradle_daemon.html) how to enable it for your platform.
+
 ### Configure your SDK
 
 1. Open the Android SDK Manager (**on Mac** start a new shell and run `android`); in the window that appears make sure you check:

From d08727d99fa07caabcb1fb37cf91de9a47e13b82 Mon Sep 17 00:00:00 2001
From: Aleksei Androsov <aandrosov@yandex-team.ru>
Date: Tue, 1 Dec 2015 02:10:20 -0800
Subject: [PATCH 0181/1411] RCTImagePickerManager crash on image from
 CameraRoll

Summary: Image from CameraRoll haven't UIImagePickerControllerReferenceURL. So we need to save it to PhotoAlbums first.

To save image I've used the same method from RCTCameraRollManager.
Closes https://github.com/facebook/react-native/pull/4412

Reviewed By: svcscm

Differential Revision: D2707249

Pulled By: nicklockwood

fb-gh-sync-id: eee683bd4179700bed46ebf45e569197f3ad2077
---
 Libraries/CameraRoll/RCTImagePickerManager.m | 26 +++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/Libraries/CameraRoll/RCTImagePickerManager.m b/Libraries/CameraRoll/RCTImagePickerManager.m
index d82d0e9bf554..0f97099ad851 100644
--- a/Libraries/CameraRoll/RCTImagePickerManager.m
+++ b/Libraries/CameraRoll/RCTImagePickerManager.m
@@ -9,6 +9,7 @@
  */
 
 #import "RCTImagePickerManager.h"
+#import "RCTImageStoreManager.h"
 
 #import "RCTConvert.h"
 #import "RCTRootView.h"
@@ -32,6 +33,8 @@ @implementation RCTImagePickerManager
 
 RCT_EXPORT_MODULE(ImagePickerIOS);
 
+@synthesize bridge = _bridge;
+
 - (dispatch_queue_t)methodQueue
 {
   return dispatch_get_main_queue();
@@ -101,9 +104,26 @@ - (dispatch_queue_t)methodQueue
 - (void)imagePickerController:(UIImagePickerController *)picker
 didFinishPickingMediaWithInfo:(NSDictionary<NSString *, id> *)info
 {
-  [self _dismissPicker:picker args:@[
-    [info[UIImagePickerControllerReferenceURL] absoluteString]
-  ]];
+  // Image from PhotoLibrary
+  NSString *imageUri = [info[UIImagePickerControllerReferenceURL] absoluteString];
+  if (imageUri) {
+    [self _dismissPicker:picker args:@[imageUri]];
+
+  } else {
+    // Image from CameraRoll hasn't uri.
+    // We need to save it to the store first.
+    UIImage *originalImage = info[UIImagePickerControllerOriginalImage];
+
+    // WARNING: Using imageStoreManager causes memory leak
+    // because image isn't removed from store once we're done using it
+    [_bridge.imageStoreManager storeImage:originalImage withBlock:^(NSString *tempImageTag) {
+      if (!tempImageTag) {
+        [self _dismissPicker:picker args:nil];
+        return;
+      }
+      [self _dismissPicker:picker args:@[tempImageTag]];
+    }];
+  }
 }
 
 - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker

From 7377fdcc70b25eb023e7c6d1b37eeae2a700cb88 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Tue, 1 Dec 2015 04:41:04 -0800
Subject: [PATCH 0182/1411] Fix XY coords to be XY instead of YX

Summary: public

This fixes the ordering of methods in touch handling to take their arguments as X,Y instead of Y,X.

This is really just internal cleanup of native touch handling.

Reviewed By: andreicoman11

Differential Revision: D2703003

fb-gh-sync-id: d169436d21fd11c1a9cb251e7e0b57b2094699e4
---
 .../com/facebook/react/ReactRootView.java     | 28 ++++++++--------
 .../uimanager/NativeViewHierarchyManager.java |  2 +-
 .../react/uimanager/TouchTargetHelper.java    | 32 +++++++++----------
 3 files changed, 30 insertions(+), 32 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
index 0f51cd86d4bb..3450f883aa55 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
@@ -61,8 +61,6 @@ public class ReactRootView extends SizeMonitoringFrameLayout implements RootView
   private @Nullable String mJSModuleName;
   private @Nullable Bundle mLaunchOptions;
   private int mTargetTag = -1;
-  // Note mTargetCoordinates are Y,X
-  // TODO: t9136625 tracks moving to X,Y
   private final float[] mTargetCoordinates = new float[2];
   private boolean mChildIsHandlingNativeGesture = false;
   private boolean mWasMeasured = false;
@@ -147,8 +145,8 @@ private void handleTouchEvent(MotionEvent ev) {
       // this gesture
       mChildIsHandlingNativeGesture = false;
       mTargetTag = TouchTargetHelper.findTargetTagAndCoordinatesForTouch(
-          ev.getY(),
           ev.getX(),
+          ev.getY(),
           this,
           mTargetCoordinates);
       eventDispatcher.dispatchEvent(
@@ -157,8 +155,8 @@ private void handleTouchEvent(MotionEvent ev) {
               SystemClock.uptimeMillis(),
               TouchEventType.START,
               ev,
-              mTargetCoordinates[1],
-              mTargetCoordinates[0]));
+              mTargetCoordinates[0],
+              mTargetCoordinates[1]));
     } else if (mChildIsHandlingNativeGesture) {
       // If the touch was intercepted by a child, we've already sent a cancel event to JS for this
       // gesture, so we shouldn't send any more touches related to it.
@@ -179,8 +177,8 @@ private void handleTouchEvent(MotionEvent ev) {
               SystemClock.uptimeMillis(),
               TouchEventType.END,
               ev,
-              mTargetCoordinates[1],
-              mTargetCoordinates[0]));
+              mTargetCoordinates[0],
+              mTargetCoordinates[1]));
       mTargetTag = -1;
     } else if (action == MotionEvent.ACTION_MOVE) {
       // Update pointer position for current gesture
@@ -190,8 +188,8 @@ private void handleTouchEvent(MotionEvent ev) {
               SystemClock.uptimeMillis(),
               TouchEventType.MOVE,
               ev,
-              mTargetCoordinates[1],
-              mTargetCoordinates[0]));
+              mTargetCoordinates[0],
+              mTargetCoordinates[1]));
     } else if (action == MotionEvent.ACTION_POINTER_DOWN) {
       // New pointer goes down, this can only happen after ACTION_DOWN is sent for the first pointer
       eventDispatcher.dispatchEvent(
@@ -200,8 +198,8 @@ private void handleTouchEvent(MotionEvent ev) {
               SystemClock.uptimeMillis(),
               TouchEventType.START,
               ev,
-              mTargetCoordinates[1],
-              mTargetCoordinates[0]));
+              mTargetCoordinates[0],
+              mTargetCoordinates[1]));
     } else if (action == MotionEvent.ACTION_POINTER_UP) {
       // Exactly onw of the pointers goes up
       eventDispatcher.dispatchEvent(
@@ -210,8 +208,8 @@ private void handleTouchEvent(MotionEvent ev) {
               SystemClock.uptimeMillis(),
               TouchEventType.END,
               ev,
-              mTargetCoordinates[1],
-              mTargetCoordinates[0]));
+              mTargetCoordinates[0],
+              mTargetCoordinates[1]));
     } else if (action == MotionEvent.ACTION_CANCEL) {
       dispatchCancelEvent(ev);
       mTargetTag = -1;
@@ -261,8 +259,8 @@ private void dispatchCancelEvent(MotionEvent androidEvent) {
             SystemClock.uptimeMillis(),
             TouchEventType.CANCEL,
             androidEvent,
-            mTargetCoordinates[1],
-            mTargetCoordinates[0]));
+            mTargetCoordinates[0],
+            mTargetCoordinates[1]));
   }
 
   @Override
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
index 28b95139ca9a..ac6ae4e46d8c 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
@@ -437,7 +437,7 @@ public int findTargetTagForTouch(int reactTag, float touchX, float touchY) {
     if (view == null) {
       throw new JSApplicationIllegalArgumentException("Could not find view with tag " + reactTag);
     }
-    return TouchTargetHelper.findTargetTagForTouch(touchY, touchX, (ViewGroup) view);
+    return TouchTargetHelper.findTargetTagForTouch(touchX, touchY, (ViewGroup) view);
   }
 
   public void setJSResponder(int reactTag, int initialReactTag, boolean blockNativeResponder) {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java
index 24a4d286946f..8564258babe7 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java
@@ -35,38 +35,38 @@ public class TouchTargetHelper {
    * Find touch event target view within the provided container given the coordinates provided
    * via {@link MotionEvent}.
    *
-   * @param eventY the Y screen coordinate of the touch location
    * @param eventX the X screen coordinate of the touch location
+   * @param eventY the Y screen coordinate of the touch location
    * @param viewGroup the container view to traverse
    * @return the react tag ID of the child view that should handle the event
    */
   public static int findTargetTagForTouch(
-      float eventY,
       float eventX,
+      float eventY,
       ViewGroup viewGroup) {
-    return findTargetTagAndCoordinatesForTouch(eventY, eventX, viewGroup, mEventCoords);
+    return findTargetTagAndCoordinatesForTouch(eventX, eventY, viewGroup, mEventCoords);
   }
 
   /**
    * Find touch event target view within the provided container given the coordinates provided
    * via {@link MotionEvent}.
    *
-   * @param eventY the Y screen coordinate of the touch location
    * @param eventX the X screen coordinate of the touch location
+   * @param eventY the Y screen coordinate of the touch location
    * @param viewGroup the container view to traverse
-   * @param viewCoords an out parameter that will return the Y,X value in the target view
+   * @param viewCoords an out parameter that will return the X,Y value in the target view
    * @return the react tag ID of the child view that should handle the event
    */
   public static int findTargetTagAndCoordinatesForTouch(
-      float eventY,
       float eventX,
+      float eventY,
       ViewGroup viewGroup,
       float[] viewCoords) {
     UiThreadUtil.assertOnUiThread();
     int targetTag = viewGroup.getId();
     // Store eventCoords in array so that they are modified to be relative to the targetView found.
-    viewCoords[0] = eventY;
-    viewCoords[1] = eventX;
+    viewCoords[0] = eventX;
+    viewCoords[1] = eventY;
     View nativeTargetView = findTouchTargetView(viewCoords, viewGroup);
     if (nativeTargetView != null) {
       View reactTargetView = findClosestReactAncestor(nativeTargetView);
@@ -105,16 +105,16 @@ private static View findTouchTargetView(float[] eventCoords, ViewGroup viewGroup
         // coordinates relative to the child
         // We need to store the existing X,Y for the viewGroup away as it is possible this child
         // will not actually be the target and so we restore them if not
-        float restoreY = eventCoords[0];
-        float restoreX = eventCoords[1];
-        eventCoords[0] = childPoint.y;
-        eventCoords[1] = childPoint.x;
+        float restoreX = eventCoords[0];
+        float restoreY = eventCoords[1];
+        eventCoords[0] = childPoint.x;
+        eventCoords[1] = childPoint.y;
         View targetView = findTouchTargetViewWithPointerEvents(eventCoords, child);
         if (targetView != null) {
           return targetView;
         }
-        eventCoords[0] = restoreY;
-        eventCoords[1] = restoreX;
+        eventCoords[0] = restoreX;
+        eventCoords[1] = restoreY;
       }
     }
     return viewGroup;
@@ -126,8 +126,8 @@ private static View findTouchTargetView(float[] eventCoords, ViewGroup viewGroup
    * This code is taken from {@link ViewGroup#isTransformedTouchPointInView()}
    */
   private static boolean isTransformedTouchPointInView(
-      float y,
       float x,
+      float y,
       ViewGroup parent,
       View child,
       PointF outLocalPoint) {
@@ -190,7 +190,7 @@ private static boolean isTransformedTouchPointInView(
     }
   }
 
-  private static int getTouchTargetForView(View targetView, float eventY, float eventX) {
+  private static int getTouchTargetForView(View targetView, float eventX, float eventY) {
     if (targetView instanceof ReactCompoundView) {
       // Use coordinates relative to the view, which have been already computed by
       // {@link #findTouchTargetView()}.

From 8ec052a727c45e98e23fac581cf0bc31c2271c9b Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Tue, 1 Dec 2015 05:06:45 -0800
Subject: [PATCH 0183/1411] Expose JS hooks to profile async events

Summary: public

Expose JS hooks to add async events to Systrace from JS.

Reviewed By: mikearmstrong001

Differential Revision: D2702739

fb-gh-sync-id: 906849d3819a914c521b9315e396c75946c9211d
---
 React/Executors/RCTContextExecutor.m | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/React/Executors/RCTContextExecutor.m b/React/Executors/RCTContextExecutor.m
index 163718799f87..b666690f165d 100644
--- a/React/Executors/RCTContextExecutor.m
+++ b/React/Executors/RCTContextExecutor.m
@@ -352,7 +352,7 @@ - (void)setUp
       [bridge handleBuffer:calls batchEnded:NO];
     };
 
-    strongSelf->_context.context[@"RCTPerformanceNow"] = ^(){
+    strongSelf->_context.context[@"RCTPerformanceNow"] = ^{
       return CACurrentMediaTime() * 1000 * 1000;
     };
 
@@ -361,6 +361,20 @@ - (void)setUp
       strongSelf->_context.context[@"__RCTProfileIsProfiling"] = @YES;
     }
 
+    CFMutableDictionaryRef cookieMap = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
+    strongSelf->_context.context[@"nativeTraceBeginAsyncSection"] = ^(uint64_t tag, NSString *name, NSUInteger cookie) {
+      NSUInteger newCookie = RCTProfileBeginAsyncEvent(tag, name, nil);
+      CFDictionarySetValue(cookieMap, (const void *)cookie, (const void *)newCookie);
+      return;
+    };
+
+    strongSelf->_context.context[@"nativeTraceEndAsyncSection"] = ^(uint64_t tag, NSString *name, NSUInteger cookie) {
+      NSUInteger newCookie = (NSUInteger)CFDictionaryGetValue(cookieMap, (const void *)cookie);
+      RCTProfileEndAsyncEvent(tag, @"js,async", newCookie, name, nil);
+      CFDictionaryRemoveValue(cookieMap, (const void *)cookie);
+      return;
+    };
+
     [strongSelf _addNativeHook:RCTNativeTraceBeginSection withName:"nativeTraceBeginSection"];
     [strongSelf _addNativeHook:RCTNativeTraceEndSection withName:"nativeTraceEndSection"];
 

From 16b9c7d6f61b49917ccdb30335d1190e3fdb8247 Mon Sep 17 00:00:00 2001
From: Perry Poon <plrthink@gmail.com>
Date: Tue, 1 Dec 2015 23:01:48 +0800
Subject: [PATCH 0184/1411] change order in showcase

---
 website/src/react-native/showcase.js | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index ab74ad8aad96..439ec56c9d7e 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -248,6 +248,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/mintrain/id1015739031?mt=8',
     author: 'Peter Cottle',
   },
+  {
+    name: 'MockingBot',
+    icon: 'https://s3.cn-north-1.amazonaws.com.cn/modao/downloads/images/MockingBot175.png',
+    link: 'https://itunes.apple.com/cn/app/mockingbot/id1050565468?l=en&mt=8',
+    author: 'YuanYi Zhang (@mockingbot)',
+  },
   {
     name: 'Mr. Dapper',
     icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple4/v4/e8/3f/7c/e83f7cb3-2602-f8e8-de9a-ce0a775a4a14/mzl.hmdjhfai.png',
@@ -386,12 +392,6 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/yazboz-batak-esli-batak-okey/id1048620855?ls=1&mt=8',
     author: 'Melih Mucuk',
   },
-  {
-    name: 'MockingBot',
-    icon: 'https://s3.cn-north-1.amazonaws.com.cn/modao/downloads/images/MockingBot175.png',
-    link: 'https://itunes.apple.com/cn/app/mockingbot/id1050565468?l=en&mt=8',
-    author: 'YuanYi Zhang (@mockingbot)',
-  },
 ];
 
 var AppList = React.createClass({

From 0a3694ce48be8991839c42aab2586202a12d43aa Mon Sep 17 00:00:00 2001
From: Huang Yu <huang@bitgo.com>
Date: Tue, 1 Dec 2015 07:24:14 -0800
Subject: [PATCH 0185/1411] fix several lint warnings

Summary: fix some ling warnings from several files
Closes https://github.com/facebook/react-native/pull/4450

Reviewed By: svcscm

Differential Revision: D2707606

Pulled By: mkonicek

fb-gh-sync-id: 410ccacf061ac7b0f6e44d1a5e4621a9d1d606fc
---
 Libraries/Components/MapView/MapView.js                         | 2 +-
 Libraries/Components/View/ViewStylePropTypes.js                 | 2 +-
 .../Initialization/InitializeJavaScriptAppEngine.js             | 2 +-
 Libraries/LinkingIOS/LinkingIOS.js                              | 2 +-
 Libraries/Network/XMLHttpRequest.ios.js                         | 1 -
 Libraries/Picker/PickerIOS.ios.js                               | 2 --
 Libraries/RCTTest/SnapshotViewIOS.ios.js                        | 1 -
 7 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/Libraries/Components/MapView/MapView.js b/Libraries/Components/MapView/MapView.js
index 2dc4fdf30895..74f2774d68fc 100644
--- a/Libraries/Components/MapView/MapView.js
+++ b/Libraries/Components/MapView/MapView.js
@@ -232,7 +232,7 @@ var MapView = React.createClass({
        * @platform ios
        */
       image: Image.propTypes.source,
-      
+
       /**
        * annotation id
        */
diff --git a/Libraries/Components/View/ViewStylePropTypes.js b/Libraries/Components/View/ViewStylePropTypes.js
index 9f7ba776aab7..95767970510d 100644
--- a/Libraries/Components/View/ViewStylePropTypes.js
+++ b/Libraries/Components/View/ViewStylePropTypes.js
@@ -48,7 +48,7 @@ var ViewStylePropTypes = {
   shadowOpacity: ReactPropTypes.number,
   shadowRadius: ReactPropTypes.number,
   /**
-   * (Android-only) Sets the elevation of a view, using Android's underlying 
+   * (Android-only) Sets the elevation of a view, using Android's underlying
    * [elevation API](https://developer.android.com/training/material/shadows-clipping.html#Elevation).
    * This adds a drop shadow to the item and affects z-order for overlapping views.
    * Only supported on Android 5.0+, has no effect on earlier versions.
diff --git a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
index 9c2b7f58438b..141ea7045cd7 100644
--- a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
+++ b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
@@ -53,7 +53,7 @@ function setUpConsole() {
  * For more info on that particular case, see:
  * https://github.com/facebook/react-native/issues/934
  */
-function polyfillGlobal(name, newValue, scope=GLOBAL) {
+function polyfillGlobal(name, newValue, scope = GLOBAL) {
   var descriptor = Object.getOwnPropertyDescriptor(scope, name) || {
     // jest for some bad reasons runs the polyfill code multiple times. In jest
     // environment, XmlHttpRequest doesn't exist so getOwnPropertyDescriptor
diff --git a/Libraries/LinkingIOS/LinkingIOS.js b/Libraries/LinkingIOS/LinkingIOS.js
index 0ee8367df073..7ee6ace38ce0 100644
--- a/Libraries/LinkingIOS/LinkingIOS.js
+++ b/Libraries/LinkingIOS/LinkingIOS.js
@@ -130,7 +130,7 @@ class LinkingIOS {
    * Determine whether or not an installed app can handle a given URL.
    * The callback function will be called with `bool supported` as the only argument
    *
-   * NOTE: As of iOS 9, your app needs to provide a `LSApplicationQueriesSchemes` key 
+   * NOTE: As of iOS 9, your app needs to provide a `LSApplicationQueriesSchemes` key
    * inside `Info.plist`.
    */
   static canOpenURL(url: string, callback: Function) {
diff --git a/Libraries/Network/XMLHttpRequest.ios.js b/Libraries/Network/XMLHttpRequest.ios.js
index 56b319a254d8..21614ff36163 100644
--- a/Libraries/Network/XMLHttpRequest.ios.js
+++ b/Libraries/Network/XMLHttpRequest.ios.js
@@ -13,7 +13,6 @@
 
 var FormData = require('FormData');
 var RCTNetworking = require('RCTNetworking');
-var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
 
 var XMLHttpRequestBase = require('XMLHttpRequestBase');
 
diff --git a/Libraries/Picker/PickerIOS.ios.js b/Libraries/Picker/PickerIOS.ios.js
index 924f13573907..5c245397d0b0 100644
--- a/Libraries/Picker/PickerIOS.ios.js
+++ b/Libraries/Picker/PickerIOS.ios.js
@@ -15,13 +15,11 @@
 var NativeMethodsMixin = require('NativeMethodsMixin');
 var React = require('React');
 var ReactChildren = require('ReactChildren');
-var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
 var RCTPickerIOSConsts = require('NativeModules').UIManager.RCTPicker.Constants;
 var StyleSheet = require('StyleSheet');
 var View = require('View');
 
 var requireNativeComponent = require('requireNativeComponent');
-var merge = require('merge');
 
 var PICKER = 'picker';
 
diff --git a/Libraries/RCTTest/SnapshotViewIOS.ios.js b/Libraries/RCTTest/SnapshotViewIOS.ios.js
index 7b6294be1ce7..3ecefdc3dea1 100644
--- a/Libraries/RCTTest/SnapshotViewIOS.ios.js
+++ b/Libraries/RCTTest/SnapshotViewIOS.ios.js
@@ -11,7 +11,6 @@
  */
 'use strict';
 
-var Platform = require('Platform');
 var React = require('React');
 var StyleSheet = require('StyleSheet');
 var { TestModule, UIManager } = require('NativeModules');

From b6f5c7fa041fb5e13b07876beed117d8a4de0d17 Mon Sep 17 00:00:00 2001
From: Mike Armstrong <mikea@fb.com>
Date: Tue, 1 Dec 2015 07:37:52 -0800
Subject: [PATCH 0186/1411] Fix systrace profile handling for relay async calls

Reviewed By: astreet

Differential Revision: D2700239

fb-gh-sync-id: eaa29d63ee4f7688dd70b0cdc12564a9d479f9ef
---
 Libraries/Utilities/BridgeProfiling.js | 36 ++++++++++++++++++++++++--
 1 file changed, 34 insertions(+), 2 deletions(-)

diff --git a/Libraries/Utilities/BridgeProfiling.js b/Libraries/Utilities/BridgeProfiling.js
index 526775b20793..8e60354f2a50 100644
--- a/Libraries/Utilities/BridgeProfiling.js
+++ b/Libraries/Utilities/BridgeProfiling.js
@@ -22,6 +22,7 @@ var GLOBAL = GLOBAL || this;
 var TRACE_TAG_REACT_APPS = 1 << 17;
 
 var _enabled;
+var _asyncCookie = 0;
 var _ReactPerf = null;
 function ReactPerf() {
   if (!_ReactPerf) {
@@ -37,6 +38,9 @@ var BridgeProfiling = {
     ReactPerf().enableMeasure = enabled;
   },
 
+  /**
+   * profile/profileEnd for starting and then ending a profile within the same call stack frame
+  **/
   profile(profileName?: any) {
     if (_enabled) {
       profileName = typeof profileName === 'function' ?
@@ -51,6 +55,30 @@ var BridgeProfiling = {
     }
   },
 
+  /**
+   * profileAsync/profileAsyncEnd for starting and then ending a profile where the end can either
+   * occur on another thread or out of the current stack frame, eg await
+   * the returned cookie variable should be used as input into the asyncEnd call to end the profile
+  **/
+  profileAsync(profileName?: any): any {
+    var cookie = _asyncCookie;
+    if (_enabled) {
+      _asyncCookie++;
+      profileName = typeof profileName === 'function' ?
+        profileName() : profileName;
+      global.nativeTraceBeginAsyncSection(TRACE_TAG_REACT_APPS, profileName, cookie, 0);
+    }
+    return cookie;
+  },
+
+  profileAsyncEnd(profileName?: any, cookie?: any) {
+    if (_enabled) {
+      profileName = typeof profileName === 'function' ?
+        profileName() : profileName;
+      global.nativeTraceEndAsyncSection(TRACE_TAG_REACT_APPS, profileName, cookie, 0);
+    }
+  },
+
   reactPerfMeasure(objName: string, fnName: string, func: any): any {
     return function (component) {
       if (!_enabled) {
@@ -69,11 +97,15 @@ var BridgeProfiling = {
     ReactPerf().injection.injectMeasure(BridgeProfiling.reactPerfMeasure);
   },
 
+  /**
+   * Relay profiles use await calls, so likely occur out of current stack frame
+   * therefore async variant of profiling is used
+  **/
   attachToRelayProfiler(relayProfiler: RelayProfiler) {
     relayProfiler.attachProfileHandler('*', (name) => {
-      BridgeProfiling.profile(name);
+      var cookie = BridgeProfiling.profileAsync(name);
       return () => {
-        BridgeProfiling.profileEnd();
+        BridgeProfiling.profileAsyncEnd(name, cookie);
       };
     });
   },

From cc4a5d39db23c5c18b562cb0273d5edae65a287b Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Tue, 1 Dec 2015 07:42:44 -0800
Subject: [PATCH 0187/1411] Add unbundling to packager

Reviewed By: tadeuzagallo

Differential Revision: D2707409

fb-gh-sync-id: 30216c36066dae68d83622dba2d598e9dc0a29db
---
 local-cli/bundle/bundle.js                    |  12 +-
 local-cli/bundle/output/bundle.js             |   2 +-
 local-cli/bundle/output/unbundle.js           | 126 ++++++++++++++++++
 local-cli/bundle/unbundle.js                  |  21 +++
 local-cli/cli.js                              |   2 +
 packager/react-packager/src/Bundler/Bundle.js |  39 ++++++
 .../src/Bundler/__tests__/Bundler-test.js     |  10 +-
 packager/react-packager/src/Bundler/index.js  |  10 +-
 .../DependencyGraph/ResolutionResponse.js     |   2 +
 .../src/Resolver/__tests__/Resolver-test.js   |   3 +-
 packager/react-packager/src/Resolver/index.js |  27 ++--
 .../Resolver/polyfills/require-unbundle.js    |  73 ++++++++++
 .../src/Server/__tests__/Server-test.js       |   4 +
 packager/react-packager/src/Server/index.js   |   4 +
 .../react-packager/src/lib/ModuleTransport.js |   2 +
 15 files changed, 318 insertions(+), 19 deletions(-)
 create mode 100644 local-cli/bundle/output/unbundle.js
 create mode 100644 local-cli/bundle/unbundle.js
 create mode 100644 packager/react-packager/src/Resolver/polyfills/require-unbundle.js

diff --git a/local-cli/bundle/bundle.js b/local-cli/bundle/bundle.js
index e242049f0156..debbb62ecfc1 100644
--- a/local-cli/bundle/bundle.js
+++ b/local-cli/bundle/bundle.js
@@ -17,10 +17,18 @@ const outputPrepack = require('./output/prepack');
 /**
  * Builds the bundle starting to look for dependencies at the given entry path.
  */
-function bundle(argv, config) {
+function bundleWithOutput(argv, config, output) {
   const args = parseCommandLine(bundleCommandLineArgs, argv);
-  const output = args.prepack ? outputPrepack : outputBundle;
+  if (!output) {
+    output = args.prepack ? outputPrepack : outputBundle;
+  }
   return buildBundle(args, config, output);
+
+}
+
+function bundle(argv, config) {
+  return bundleWithOutput(argv, config);
 }
 
 module.exports = bundle;
+module.exports.withOutput = bundleWithOutput;
diff --git a/local-cli/bundle/output/bundle.js b/local-cli/bundle/output/bundle.js
index 4ffd8a649bc4..6f40e5baccde 100644
--- a/local-cli/bundle/output/bundle.js
+++ b/local-cli/bundle/output/bundle.js
@@ -33,7 +33,7 @@ function saveBundleAndMap(bundle, options, log) {
     'bundle-encoding': encoding,
     dev,
     'sourcemap-output': sourcemapOutput,
-} = options;
+  } = options;
 
   log('start');
   const codeWithMap = createCodeWithMap(bundle, dev);
diff --git a/local-cli/bundle/output/unbundle.js b/local-cli/bundle/output/unbundle.js
new file mode 100644
index 000000000000..65156dcca031
--- /dev/null
+++ b/local-cli/bundle/output/unbundle.js
@@ -0,0 +1,126 @@
+/**
+ * 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.
+ */
+'use strict';
+
+const fs = require('fs');
+const Promise = require('promise');
+const writeFile = require('./writeFile');
+
+const MAGIC_STARTUP_MODULE_ID = '';
+
+function buildBundle(packagerClient, requestOptions) {
+  return packagerClient.buildBundle({...requestOptions, unbundle: true});
+}
+
+function saveUnbundle(bundle, options, log) {
+  const {
+    'bundle-output': bundleOutput,
+    'bundle-encoding': encoding,
+    dev,
+    'sourcemap-output': sourcemapOutput,
+  } = options;
+
+  log('start');
+  const {startupCode, modules} = bundle.getUnbundle({minify: !dev});
+  log('finish');
+
+  log('Writing unbundle output to:', bundleOutput);
+  const writeUnbundle = writeBuffers(
+    fs.createWriteStream(bundleOutput),
+    buildTableAndContents(startupCode, modules, encoding)
+  );
+
+  writeUnbundle.then(() => log('Done writing unbundle output'));
+
+  if (sourcemapOutput) {
+    log('Writing sourcemap output to:', sourcemapOutput);
+    const writeMap = writeFile(sourcemapOutput, '', null);
+    writeMap.then(() => log('Done writing sourcemap output'));
+    return Promise.all([writeUnbundle, writeMap]);
+  } else {
+    return writeUnbundle;
+  }
+}
+
+/* global Buffer: true */
+const nullByteBuffer = Buffer(1).fill(0);
+
+const moduleToBuffer = ({name, code}, encoding) => ({
+  name,
+  buffer: Buffer.concat([
+    Buffer(code, encoding),
+    nullByteBuffer // create \0-terminated strings
+  ])
+});
+
+function buildModuleBuffers(startupCode, modules, encoding) {
+  return (
+    [moduleToBuffer({name: '', code: startupCode}, encoding)]
+      .concat(modules.map(module => moduleToBuffer(module, encoding)))
+  );
+}
+
+function uInt32Buffer(n) {
+  const buffer = Buffer(4);
+  buffer.writeUInt32LE(n, 0); // let's assume LE for now :)
+  return buffer;
+}
+
+function buildModuleTable(buffers) {
+  // table format:
+  //  - table_length: uint_32 length of all table entries in bytes
+  //  - entries: entry...
+  //
+  // entry:
+  //  - module_id: NUL terminated utf8 string
+  //  - module_offset: uint_32 offset into the module string
+  //  - module_length: uint_32 length of the module string, including terminating NUL byte
+
+  const numBuffers = buffers.length;
+
+  const tableLengthBuffer = uInt32Buffer(0);
+  let tableLength = 4; // the table length itself, 4 == tableLengthBuffer.length
+  let currentOffset = 0;
+
+  const offsetTable = [tableLengthBuffer];
+  for (let i = 0; i < numBuffers; i++) {
+    const {name, buffer: {length}} = buffers[i];
+    const entry = Buffer.concat([
+      Buffer(i === 0 ? MAGIC_STARTUP_MODULE_ID : name, 'utf8'),
+      nullByteBuffer,
+      uInt32Buffer(currentOffset),
+      uInt32Buffer(length)
+    ]);
+    currentOffset += length;
+    tableLength += entry.length;
+    offsetTable.push(entry);
+  }
+
+  tableLengthBuffer.writeUInt32LE(tableLength, 0);
+  return Buffer.concat(offsetTable);
+}
+
+function buildTableAndContents(startupCode, modules, encoding) {
+  const buffers = buildModuleBuffers(startupCode, modules, encoding);
+  const table = buildModuleTable(buffers, encoding);
+  return [table].concat(buffers.map(({buffer}) => buffer));
+}
+
+function writeBuffers(stream, buffers) {
+  buffers.forEach(buffer => stream.write(buffer));
+  return new Promise((resolve, reject) => {
+    stream.on('error', reject);
+    stream.on('finish', () => resolve());
+    stream.end();
+  });
+}
+
+exports.build = buildBundle;
+exports.save = saveUnbundle;
+exports.formatName = 'bundle';
diff --git a/local-cli/bundle/unbundle.js b/local-cli/bundle/unbundle.js
new file mode 100644
index 000000000000..042093ced897
--- /dev/null
+++ b/local-cli/bundle/unbundle.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.
+ */
+'use strict';
+
+const bundleWithOutput = require('./bundle').withOutput;
+const outputUnbundle = require('./output/unbundle');
+
+/**
+ * Builds the bundle starting to look for dependencies at the given entry path.
+ */
+function unbundle(argv, config) {
+  return bundleWithOutput(argv, config, outputUnbundle);
+}
+
+module.exports = unbundle;
diff --git a/local-cli/cli.js b/local-cli/cli.js
index a7b6a2cf5ef6..9fd1fda7f1a5 100644
--- a/local-cli/cli.js
+++ b/local-cli/cli.js
@@ -28,6 +28,7 @@ var runAndroid = require('./runAndroid/runAndroid');
 var server = require('./server/server');
 var TerminalAdapter = require('yeoman-environment/lib/adapter.js');
 var yeoman = require('yeoman-environment');
+var unbundle = require('./bundle/unbundle');
 var upgrade = require('./upgrade/upgrade');
 
 var fs = require('fs');
@@ -40,6 +41,7 @@ gracefulFs.gracefulify(fs);
 var documentedCommands = {
   'start': [server, 'starts the webserver'],
   'bundle': [bundle, 'builds the javascript bundle for offline use'],
+  'unbundle': [unbundle, 'builds javascript as "unbundle" for offline use'],
   'new-library': [library, 'generates a native library bridge'],
   'link': [link, 'Adds a third-party library to your project. Example: react-native link awesome-camera'],
   'android': [generateWrapper, 'generates an Android project for your app'],
diff --git a/packager/react-packager/src/Bundler/Bundle.js b/packager/react-packager/src/Bundler/Bundle.js
index b6635be9eacf..f94c8ff581f5 100644
--- a/packager/react-packager/src/Bundler/Bundle.js
+++ b/packager/react-packager/src/Bundler/Bundle.js
@@ -16,6 +16,14 @@ const Activity = require('../Activity');
 
 const SOURCEMAPPING_URL = '\n\/\/@ sourceMappingURL=';
 
+const minifyCode = code =>
+  UglifyJS.minify(code, {fromString: true, ascii_only: true}).code;
+const getCode = x => x.code;
+const getMinifiedCode = x => minifyCode(x.code);
+const getNameAndCode = ({name, code}) => ({name, code});
+const getNameAndMinifiedCode =
+  ({name, code}) => ({name, code: minifyCode(code)});
+
 class Bundle {
   constructor(sourceMapUrl) {
     this._finalized = false;
@@ -24,6 +32,8 @@ class Bundle {
     this._sourceMap = false;
     this._sourceMapUrl = sourceMapUrl;
     this._shouldCombineSourceMaps = false;
+    this._numPrependedModules = 0;
+    this._numRequireCalls = 0;
   }
 
   setMainModuleId(moduleId) {
@@ -48,6 +58,10 @@ class Bundle {
     return this._modules;
   }
 
+  setNumPrependedModules(n) {
+    this._numPrependedModules = n;
+  }
+
   addAsset(asset) {
     this._assets.push(asset);
   }
@@ -76,6 +90,7 @@ class Bundle {
       sourceCode: code,
       sourcePath: name + '.js',
     }));
+    this._numRequireCalls += 1;
   }
 
   _assertFinalized() {
@@ -141,6 +156,26 @@ class Bundle {
     return source;
   }
 
+  getUnbundle({minify}) {
+    const allModules = this._modules.slice();
+    const prependedModules = this._numPrependedModules;
+    const requireCalls = this._numRequireCalls;
+
+    const modules =
+      allModules
+        .splice(prependedModules, allModules.length - requireCalls - prependedModules);
+    const startupCode =
+      allModules
+        .map(minify ? getMinifiedCode : getCode)
+        .join('\n');
+
+    return {
+      startupCode,
+      modules:
+        modules.map(minify ? getNameAndMinifiedCode : getNameAndCode)
+    };
+  }
+
   getMinifiedSourceAndMap(dev) {
     this._assertFinalized();
 
@@ -336,6 +371,8 @@ class Bundle {
       assets: this._assets,
       sourceMapUrl: this._sourceMapUrl,
       mainModuleId: this._mainModuleId,
+      numPrependedModules: this._numPrependedModules,
+      numRequireCalls: this._numRequireCalls,
     };
   }
 
@@ -345,6 +382,8 @@ class Bundle {
     bundle._assets = json.assets;
     bundle._modules = json.modules;
     bundle._sourceMapUrl = json.sourceMapUrl;
+    bundle._numPrependedModules = json.numPrependedModules;
+    bundle._numRequireCalls = json.numRequireCalls;
 
     Object.freeze(bundle._modules);
     Object.seal(bundle._modules);
diff --git a/packager/react-packager/src/Bundler/__tests__/Bundler-test.js b/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
index 9ce3f7c46da4..ccdc84961d4c 100644
--- a/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
+++ b/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
@@ -130,7 +130,10 @@ describe('Bundler', function() {
       });
 
     wrapModule.mockImpl(function(response, module, code) {
-      return Promise.resolve('lol ' + code + ' lol');
+      return module.getName().then(name => ({
+        name,
+        code: 'lol ' + code + ' lol'
+      }));
     });
 
     sizeOf.mockImpl(function(path, cb) {
@@ -160,6 +163,7 @@ describe('Bundler', function() {
       sourceMapUrl: 'source_map_url',
     }).then(function(p) {
         expect(p.addModule.mock.calls[0][0]).toEqual({
+          name: 'foo',
           code: 'lol transformed /root/foo.js lol',
           map: 'sourcemap /root/foo.js',
           sourceCode: 'source /root/foo.js',
@@ -167,6 +171,7 @@ describe('Bundler', function() {
         });
 
         expect(p.addModule.mock.calls[1][0]).toEqual({
+          name: 'bar',
           code: 'lol transformed /root/bar.js lol',
           map: 'sourcemap /root/bar.js',
           sourceCode: 'source /root/bar.js',
@@ -183,6 +188,7 @@ describe('Bundler', function() {
         };
 
         expect(p.addModule.mock.calls[2][0]).toEqual({
+          name: 'image!img',
           code: 'lol module.exports = ' +
             JSON.stringify(imgModule_DEPRECATED) +
             '; lol',
@@ -212,6 +218,7 @@ describe('Bundler', function() {
         };
 
         expect(p.addModule.mock.calls[3][0]).toEqual({
+          name: 'new_image.png',
           code: 'lol module.exports = require("AssetRegistry").registerAsset(' +
             JSON.stringify(imgModule) +
             '); lol',
@@ -224,6 +231,7 @@ describe('Bundler', function() {
         });
 
         expect(p.addModule.mock.calls[4][0]).toEqual({
+          name: 'package/file.json',
           code: 'lol module.exports = {"json":true}; lol',
           sourceCode: 'module.exports = {"json":true};',
           sourcePath: '/root/file.json',
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index e097667ff58c..ffe17735626d 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -140,6 +140,7 @@ class Bundler {
     sourceMapUrl,
     dev: isDev,
     platform,
+    unbundle: isUnbundle,
   }) {
     // Const cannot have the same name as the method (babel/babel#2834)
     const bbundle = new Bundle(sourceMapUrl);
@@ -147,7 +148,7 @@ class Bundler {
     let transformEventId;
 
     const moduleSystem = this._resolver.getModuleSystemDependencies(
-      { dev: isDev, platform }
+      { dev: isDev, platform, isUnbundle }
     );
 
     return this.getDependencies(entryFile, isDev, platform).then((response) => {
@@ -168,6 +169,8 @@ class Bundler {
       }
 
       bbundle.setMainModuleId(response.mainModuleId);
+      bbundle.setNumPrependedModules(
+        response.numPrependedDependencies + moduleSystem.length);
       return Promise.all(
         dependencies.map(
           module => this._transformModule(
@@ -317,8 +320,9 @@ class Bundler {
       module,
       transformed.code
     ).then(
-      code => new ModuleTransport({
-        code: code,
+      ({code, name}) => new ModuleTransport({
+        code,
+        name,
         map: transformed.map,
         sourceCode: transformed.sourceCode,
         sourcePath: transformed.sourcePath,
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js
index aa454a9f5fdd..7fbafde84982 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js
@@ -14,6 +14,7 @@ class ResolutionResponse {
     this.asyncDependencies = [];
     this.mainModuleId = null;
     this.mocks = null;
+    this.numPrependedDependencies = 0;
     this._mappings = Object.create(null);
     this._finalized = false;
   }
@@ -50,6 +51,7 @@ class ResolutionResponse {
   prependDependency(module) {
     this._assertNotFinalized();
     this.dependencies.unshift(module);
+    this.numPrependedDependencies += 1;
   }
 
   pushAsyncDependency(dependency) {
diff --git a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
index bf6363c520da..1de9905b9a40 100644
--- a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
+++ b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
@@ -627,7 +627,8 @@ describe('Resolver', function() {
         createModule('test module', ['x', 'y']),
         code
       ).then(processedCode => {
-        expect(processedCode).toEqual([
+        expect(processedCode.name).toEqual('test module');
+        expect(processedCode.code).toEqual([
           '__d(\'test module\',function(global, require,' +
             ' module, exports) {  ' +
             // single line import
diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index a4e546e07bbe..8e8dd315c529 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -60,6 +60,10 @@ const getDependenciesValidateOpts = declareOpts({
     type: 'string',
     required: false,
   },
+  isUnbundle: {
+    type: 'boolean',
+    default: false
+  },
 });
 
 class Resolver {
@@ -115,7 +119,9 @@ class Resolver {
         ? path.join(__dirname, 'polyfills/prelude_dev.js')
         : path.join(__dirname, 'polyfills/prelude.js');
 
-    const moduleSystem = path.join(__dirname, 'polyfills/require.js');
+    const moduleSystem = opts.isUnbundle
+        ? path.join(__dirname, 'polyfills/require-unbundle.js')
+        : path.join(__dirname, 'polyfills/require.js');
 
     return [
       prelude,
@@ -152,7 +158,7 @@ class Resolver {
   wrapModule(resolutionResponse, module, code) {
     return Promise.resolve().then(() => {
       if (module.isPolyfill()) {
-        return Promise.resolve(code);
+        return Promise.resolve({code});
       }
 
       const resolvedDeps = Object.create(null);
@@ -179,14 +185,13 @@ class Resolver {
           }
         };
 
-        return module.getName().then(
-          name => defineModuleCode({
-            code: code.replace(replacePatterns.IMPORT_RE, relativizeCode)
-                      .replace(replacePatterns.EXPORT_RE, relativizeCode)
-                      .replace(replacePatterns.REQUIRE_RE, relativizeCode),
-            moduleName: name,
-          })
-        );
+        code = code
+          .replace(replacePatterns.IMPORT_RE, relativizeCode)
+          .replace(replacePatterns.EXPORT_RE, relativizeCode)
+          .replace(replacePatterns.REQUIRE_RE, relativizeCode);
+
+        return module.getName().then(name =>
+          ({name, code: defineModuleCode(name, code)}));
       });
     });
   }
@@ -197,7 +202,7 @@ class Resolver {
 
 }
 
-function defineModuleCode({moduleName, code}) {
+function defineModuleCode(moduleName, code) {
   return [
     `__d(`,
     `'${moduleName}',`,
diff --git a/packager/react-packager/src/Resolver/polyfills/require-unbundle.js b/packager/react-packager/src/Resolver/polyfills/require-unbundle.js
new file mode 100644
index 000000000000..1ea71705d401
--- /dev/null
+++ b/packager/react-packager/src/Resolver/polyfills/require-unbundle.js
@@ -0,0 +1,73 @@
+'use strict';
+
+((global) => {
+  const {ErrorUtils, __nativeRequire} = global;
+  global.require = require;
+  global.__d = define;
+
+  const modules = Object.create(null);
+
+  const loadModule = ErrorUtils ?
+    guardedLoadModule : loadModuleImplementation;
+
+  function define(moduleId, factory) {
+    modules[moduleId] = {
+      factory,
+      hasError: false,
+      exports: undefined,
+    };
+  }
+
+  function require(moduleId) {
+    const module = modules[moduleId];
+    return module && module.exports || loadModule(moduleId, module);
+  }
+
+  function guardedLoadModule(moduleId, module) {
+    try {
+      return loadModuleImplementation(moduleId, module);
+    } catch (e) {
+      ErrorUtils.reportFatalError(e);
+    }
+  }
+
+  function loadModuleImplementation(moduleId, module) {
+    if (!module) {
+      __nativeRequire(moduleId);
+      module = modules[moduleId];
+    }
+
+    if (!module) {
+      throw unknownModuleError(moduleId);
+    }
+
+    if (module.hasError) {
+      throw moduleThrewError(moduleId);
+    }
+
+    const exports = module.exports = {};
+    const {factory} = module;
+    try {
+      const moduleObject = {exports};
+      factory(global, require, moduleObject, exports);
+      return (module.exports = moduleObject.exports);
+    } catch(e) {
+      module.hasError = true;
+      module.exports = undefined;
+    }
+  }
+
+  function unknownModuleError(id) {
+    let message = 'Requiring unknown module "' + id + '".';
+    if (__DEV__) {
+      message +=
+        'If you are sure the module is there, try restarting the packager.';
+    }
+    return Error(message);
+  }
+
+  function moduleThrewError(id) {
+    return Error('Requiring module "' + id + '", which threw an exception.');
+  }
+
+})(this);
diff --git a/packager/react-packager/src/Server/__tests__/Server-test.js b/packager/react-packager/src/Server/__tests__/Server-test.js
index d68e04105613..b8fee5fad049 100644
--- a/packager/react-packager/src/Server/__tests__/Server-test.js
+++ b/packager/react-packager/src/Server/__tests__/Server-test.js
@@ -115,6 +115,7 @@ describe('processRequest', () => {
         dev: true,
         platform: undefined,
         runBeforeMainModule: ['InitializeJavaScriptAppEngine'],
+        unbundle: false,
       });
     });
   });
@@ -134,6 +135,7 @@ describe('processRequest', () => {
         dev: true,
         platform: 'ios',
         runBeforeMainModule: ['InitializeJavaScriptAppEngine'],
+        unbundle: false,
       });
     });
   });
@@ -274,6 +276,7 @@ describe('processRequest', () => {
           dev: true,
           platform: undefined,
           runBeforeMainModule: ['InitializeJavaScriptAppEngine'],
+          unbundle: false,
         })
       );
     });
@@ -292,6 +295,7 @@ describe('processRequest', () => {
             dev: false,
             platform: undefined,
             runBeforeMainModule: ['InitializeJavaScriptAppEngine'],
+            unbundle: false,
           })
         );
     });
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index 28c5b4d1bc80..b2ca6d73b66d 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -102,6 +102,10 @@ const bundleOpts = declareOpts({
       'InitializeJavaScriptAppEngine'
     ],
   },
+  unbundle: {
+    type: 'boolean',
+    default: false,
+  }
 });
 
 const dependencyOpts = declareOpts({
diff --git a/packager/react-packager/src/lib/ModuleTransport.js b/packager/react-packager/src/lib/ModuleTransport.js
index a5f1d5689106..afb660d386dd 100644
--- a/packager/react-packager/src/lib/ModuleTransport.js
+++ b/packager/react-packager/src/lib/ModuleTransport.js
@@ -9,6 +9,8 @@
 'use strict';
 
 function ModuleTransport(data) {
+  this.name = data.name;
+
   assertExists(data, 'code');
   this.code = data.code;
 

From 765801dfc283b90c7054a64d182b359e859dbb50 Mon Sep 17 00:00:00 2001
From: Satish Sampath <ssm@fb.com>
Date: Tue, 1 Dec 2015 08:04:19 -0800
Subject: [PATCH 0188/1411] Improve JSC GC implementation on android

Reviewed By: astreet

Differential Revision: D2657643

fb-gh-sync-id: a049ee745de9a066a4a2da2762ec6a2f1517c78b
---
 ReactAndroid/src/main/jni/react/JSCExecutor.cpp | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index 52eb369e77b9..5e6caae2630e 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -26,6 +26,10 @@ using fbsystrace::FbSystraceSection;
 // Add native performance markers support
 #include <react/JSCPerfLogging.h>
 
+#ifdef WITH_FB_JSC_TUNING
+#include <jsc_config_android.h>
+#endif
+
 using namespace facebook::jni;
 
 namespace facebook {
@@ -82,6 +86,11 @@ JSCExecutor::JSCExecutor(FlushImmediateCallback cb) :
   s_globalContextRefToJSCExecutor[m_context] = this;
   installGlobalFunction(m_context, "nativeFlushQueueImmediate", nativeFlushQueueImmediate);
   installGlobalFunction(m_context, "nativeLoggingHook", nativeLoggingHook);
+
+  #ifdef WITH_FB_JSC_TUNING
+  configureJSCForAndroid();
+  #endif
+
   #ifdef WITH_JSC_EXTRA_TRACING
   addNativeTracingHooks(m_context);
   addNativeProfilingHooks(m_context);

From a26b89f8bd7d6db66614095afeaf0ce6a1982378 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Tue, 1 Dec 2015 07:41:20 -0800
Subject: [PATCH 0189/1411] Add property mapping for `borderStyle` from JS to
 `RCTView` (iOS)

Reviewed By: nicklockwood

Differential Revision: D2540321

fb-gh-sync-id: 57316f7b8dc734ee784179dbfde83e6034827819
---
 React/Base/RCTConvert.h               |  2 ++
 React/Base/RCTConvert.m               |  6 ++++++
 React/React.xcodeproj/project.pbxproj |  2 ++
 React/Views/RCTBorderStyle.h          | 17 +++++++++++++++++
 React/Views/RCTView.h                 |  6 ++++++
 React/Views/RCTView.m                 | 24 +++++++++++++++++++++---
 React/Views/RCTViewManager.m          |  7 +++++++
 7 files changed, 61 insertions(+), 3 deletions(-)
 create mode 100644 React/Views/RCTBorderStyle.h

diff --git a/React/Base/RCTConvert.h b/React/Base/RCTConvert.h
index 35106a6940bc..3d1c4291d11a 100644
--- a/React/Base/RCTConvert.h
+++ b/React/Base/RCTConvert.h
@@ -12,6 +12,7 @@
 
 #import "Layout.h"
 #import "RCTAnimationType.h"
+#import "RCTBorderStyle.h"
 #import "RCTTextDecorationLineType.h"
 #import "RCTDefines.h"
 #import "RCTLog.h"
@@ -140,6 +141,7 @@ typedef BOOL css_clip_t, css_backface_visibility_t;
 
 + (RCTPointerEvents)RCTPointerEvents:(id)json;
 + (RCTAnimationType)RCTAnimationType:(id)json;
++ (RCTBorderStyle)RCTBorderStyle:(id)json;
 + (RCTTextDecorationLineType)RCTTextDecorationLineType:(id)json;
 
 @end
diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m
index 8fc14e102fb0..f5f6033432ce 100644
--- a/React/Base/RCTConvert.m
+++ b/React/Base/RCTConvert.m
@@ -229,6 +229,12 @@ + (NSDate *)NSDate:(id)json
   @"dashed": @(NSUnderlinePatternDash | NSUnderlineStyleSingle),
 }), NSUnderlineStyleSingle, integerValue)
 
+RCT_ENUM_CONVERTER(RCTBorderStyle, (@{
+  @"solid": @(RCTBorderStyleSolid),
+  @"dotted": @(RCTBorderStyleDotted),
+  @"dashed": @(RCTBorderStyleDashed),
+}), RCTBorderStyleSolid, integerValue)
+
 RCT_ENUM_CONVERTER(RCTTextDecorationLineType, (@{
   @"none": @(RCTTextDecorationLineTypeNone),
   @"underline": @(RCTTextDecorationLineTypeUnderline),
diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj
index 92b4cf7f6a8d..6d671d58b4b4 100644
--- a/React/React.xcodeproj/project.pbxproj
+++ b/React/React.xcodeproj/project.pbxproj
@@ -269,6 +269,7 @@
 		83CBBACA1A6023D300E9B192 /* RCTConvert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTConvert.h; sourceTree = "<group>"; };
 		83CBBACB1A6023D300E9B192 /* RCTConvert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTConvert.m; sourceTree = "<group>"; };
 		83F15A171B7CC46900F10295 /* UIView+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIView+Private.h"; sourceTree = "<group>"; };
+		ACDD3FDA1BC7430D00E7DE33 /* RCTBorderStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBorderStyle.h; sourceTree = "<group>"; };
 		E3BBC8EB1ADE6F47001BBD81 /* RCTTextDecorationLineType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTTextDecorationLineType.h; sourceTree = "<group>"; };
 		E9B20B791B500126007A2DA7 /* RCTAccessibilityManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAccessibilityManager.h; sourceTree = "<group>"; };
 		E9B20B7A1B500126007A2DA7 /* RCTAccessibilityManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAccessibilityManager.m; sourceTree = "<group>"; };
@@ -414,6 +415,7 @@
 				137327E51AA5CF210034F82E /* RCTTabBarManager.h */,
 				137327E61AA5CF210034F82E /* RCTTabBarManager.m */,
 				E3BBC8EB1ADE6F47001BBD81 /* RCTTextDecorationLineType.h */,
+				ACDD3FDA1BC7430D00E7DE33 /* RCTBorderStyle.h */,
 				13E0674F1A70F44B002CDEE1 /* RCTView.h */,
 				13E067501A70F44B002CDEE1 /* RCTView.m */,
 				13442BF41AA90E0B0037E5B0 /* RCTViewControllerProtocol.h */,
diff --git a/React/Views/RCTBorderStyle.h b/React/Views/RCTBorderStyle.h
new file mode 100644
index 000000000000..470d832314b7
--- /dev/null
+++ b/React/Views/RCTBorderStyle.h
@@ -0,0 +1,17 @@
+/**
+ * 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+typedef NS_ENUM(NSInteger, RCTBorderStyle) {
+  RCTBorderStyleUnset = 0,
+  RCTBorderStyleSolid,
+  RCTBorderStyleDotted,
+  RCTBorderStyleDashed,
+};
diff --git a/React/Views/RCTView.h b/React/Views/RCTView.h
index 1222dc9cf7d0..3f312abd1d87 100644
--- a/React/Views/RCTView.h
+++ b/React/Views/RCTView.h
@@ -11,6 +11,7 @@
 
 #import <UIKit/UIKit.h>
 
+#import "RCTBorderStyle.h"
 #import "RCTComponent.h"
 #import "RCTPointerEvents.h"
 
@@ -84,4 +85,9 @@
 @property (nonatomic, assign) CGFloat borderLeftWidth;
 @property (nonatomic, assign) CGFloat borderWidth;
 
+/**
+ * Border styles.
+ */
+@property (nonatomic, assign) RCTBorderStyle borderStyle;
+
 @end
diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m
index 8f143d8a9ff8..3a3ea732548a 100644
--- a/React/Views/RCTView.m
+++ b/React/Views/RCTView.m
@@ -108,6 +108,7 @@ - (instancetype)initWithFrame:(CGRect)frame
     _borderTopRightRadius = -1;
     _borderBottomLeftRadius = -1;
     _borderBottomRightRadius = -1;
+    _borderStyle = RCTBorderStyleSolid;
 
     _backgroundColor = super.backgroundColor;
   }
@@ -509,6 +510,7 @@ - (void)displayLayer:(CALayer *)layer
   RCTCornerRadiiAreEqual(cornerRadii) &&
   RCTBorderInsetsAreEqual(borderInsets) &&
   RCTBorderColorsAreEqual(borderColors) &&
+  _borderStyle == RCTBorderStyleSolid &&
 
   // iOS draws borders in front of the content whereas CSS draws them behind
   // the content. For this reason, only use iOS border drawing when clipping
@@ -531,9 +533,9 @@ - (void)displayLayer:(CALayer *)layer
     return;
   }
 
-  UIImage *image = RCTGetBorderImage([self cornerRadii],
-                                     [self bordersAsInsets],
-                                     [self borderColors],
+  UIImage *image = RCTGetBorderImage(cornerRadii,
+                                     borderInsets,
+                                     borderColors,
                                      _backgroundColor.CGColor,
                                      self.clipsToBounds);
 
@@ -630,6 +632,8 @@ - (void)setBorder##side##Width:(CGFloat)width \
 setBorderWidth(Bottom)
 setBorderWidth(Left)
 
+#pragma mark - Border Radius
+
 #define setBorderRadius(side)                     \
   - (void)setBorder##side##Radius:(CGFloat)radius \
   {                                               \
@@ -646,6 +650,20 @@ - (void)setBorder##side##Radius:(CGFloat)radius \
 setBorderRadius(BottomLeft)
 setBorderRadius(BottomRight)
 
+#pragma mark - Border Style
+
+#define setBorderStyle(side)                                   \
+  - (void)setBorder##side##Style:(RCTBorderStyle)style \
+  {                                                            \
+    if (_border##side##Style == style) {                       \
+      return;                                                  \
+    }                                                          \
+    _border##side##Style = style;                              \
+    [self.layer setNeedsDisplay];                              \
+  }
+
+setBorderStyle()
+
 - (void)dealloc
 {
   CGColorRelease(_borderColor);
diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m
index aaac6d27987d..379adecdc02f 100644
--- a/React/Views/RCTViewManager.m
+++ b/React/Views/RCTViewManager.m
@@ -10,6 +10,7 @@
 #import "RCTViewManager.h"
 
 #import "RCTBridge.h"
+#import "RCTBorderStyle.h"
 #import "RCTConvert.h"
 #import "RCTEventDispatcher.h"
 #import "RCTLog.h"
@@ -186,6 +187,12 @@ - (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(__unused NSDictio
     view.layer.borderWidth = json ? [RCTConvert CGFloat:json] : defaultView.layer.borderWidth;
   }
 }
+RCT_CUSTOM_VIEW_PROPERTY(borderStyle, RCTBorderStyle, RCTView)
+{
+  if ([view respondsToSelector:@selector(setBorderStyle:)]) {
+    view.borderStyle = json ? [RCTConvert RCTBorderStyle:json] : defaultView.borderStyle;
+  }
+}
 RCT_EXPORT_VIEW_PROPERTY(onAccessibilityTap, RCTDirectEventBlock)
 RCT_EXPORT_VIEW_PROPERTY(onMagicTap, RCTDirectEventBlock)
 

From b6f662d6b602f45f70a1c3f7f3809e271d340a0d Mon Sep 17 00:00:00 2001
From: Aaron Chiu <aaronechiu@fb.com>
Date: Tue, 1 Dec 2015 08:54:34 -0800
Subject: [PATCH 0190/1411] init Timing.java in a paused state

Summary: It hasn't been resumed yet when first constructed.

public

Reviewed By: astreet

Differential Revision: D2705635

fb-gh-sync-id: fa90a89524d56fd5e349ebad2820b42deba7f26f
---
 .../src/main/java/com/facebook/react/modules/core/Timing.java   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java b/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java
index 8b0888e0882d..a29b2632b479 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java
@@ -90,7 +90,7 @@ public void doFrame(long frameTimeNanos) {
   private final Object mTimerGuard = new Object();
   private final PriorityQueue<Timer> mTimers;
   private final SparseArray<Timer> mTimerIdsToTimers;
-  private final AtomicBoolean isPaused = new AtomicBoolean(false);
+  private final AtomicBoolean isPaused = new AtomicBoolean(true);
   private final FrameCallback mFrameCallback = new FrameCallback();
   private @Nullable ReactChoreographer mReactChoreographer;
   private @Nullable JSTimersExecution mJSTimersModule;

From b0e39d26aecce2b5aa33888ca3172205a879ed98 Mon Sep 17 00:00:00 2001
From: Daniel Hugenroth <hugenroth@fb.com>
Date: Tue, 1 Dec 2015 09:10:46 -0800
Subject: [PATCH 0191/1411] implemented tracing async flow events (s, t and f)

Reviewed By: jkeljo

Differential Revision: D2699625

fb-gh-sync-id: 1d1b41fac157650e98a49307b701b6da63589c4b
---
 .../java/com/facebook/systrace/Systrace.java   | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/ReactAndroid/src/main/java/com/facebook/systrace/Systrace.java b/ReactAndroid/src/main/java/com/facebook/systrace/Systrace.java
index 4ffaa3eb4a26..042a1668ee0d 100644
--- a/ReactAndroid/src/main/java/com/facebook/systrace/Systrace.java
+++ b/ReactAndroid/src/main/java/com/facebook/systrace/Systrace.java
@@ -83,4 +83,22 @@ public static void traceCounter(
       final String counterName,
       final int counterValue) {
   }
+
+  public static void startAsyncFlow(
+      long tag,
+      final String sectionName,
+      final int cookie){
+  }
+
+  public static void stepAsyncFlow(
+      long tag,
+      final String sectionName,
+      final int cookie){
+  }
+
+  public static void endAsyncFlow(
+      long tag,
+      final String sectionName,
+      final int cookie){
+  }
 }

From b828ae4200c6e2650d1ae608982e945cfb1470ec Mon Sep 17 00:00:00 2001
From: Denis Koroskin <dkoroskin@fb.com>
Date: Tue, 1 Dec 2015 12:07:36 -0800
Subject: [PATCH 0192/1411] Initial FlatUIImplemenatation

Summary: public This patch adds an alternative UIImplementation based on an idea of creating UI hierarchy off-the-main-thread (everything but Views), flattening ReactShadowNode hierarchy and displaying it within a single View when possible. While NativeViewHierarchyOptimizer allows removing layout-only RCTViews, this allows removing RCTView, RCTText and RCTImage.

This is an initial bare-bones implementation that doesn't really draw anything, only lays out the shadow nodes. Followup diffs will add missing features.

Reviewed By: astreet

Differential Revision: D2564309

fb-gh-sync-id: 2dda4c8cfc2bac3eb39c5c15e97bd23a57550a1d
---
 .../react/uimanager/UIImplementation.java     | 85 ++++++++++++++-----
 .../react/uimanager/UIViewOperationQueue.java |  2 +-
 2 files changed, 64 insertions(+), 23 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
index 369ffda90f6c..608e33792198 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
@@ -41,15 +41,40 @@ public class UIImplementation {
   private final int[] mMeasureBuffer = new int[4];
 
   public UIImplementation(ReactApplicationContext reactContext, List<ViewManager> viewManagers) {
-    mViewManagers = new ViewManagerRegistry(viewManagers);
-    mOperationsQueue = new UIViewOperationQueue(
-        reactContext,
-        new NativeViewHierarchyManager(mViewManagers));
+    this(reactContext, new ViewManagerRegistry(viewManagers));
+  }
+
+  private UIImplementation(ReactApplicationContext reactContext, ViewManagerRegistry viewManagers) {
+    this(
+        viewManagers,
+        new UIViewOperationQueue(reactContext, new NativeViewHierarchyManager(viewManagers)));
+  }
+
+  protected UIImplementation(
+      ViewManagerRegistry viewManagers,
+      UIViewOperationQueue operationsQueue) {
+    mViewManagers = viewManagers;
+    mOperationsQueue = operationsQueue;
     mNativeViewHierarchyOptimizer = new NativeViewHierarchyOptimizer(
         mOperationsQueue,
         mShadowNodeRegistry);
   }
 
+  protected ReactShadowNode createRootShadowNode() {
+    ReactShadowNode rootCSSNode = new ReactShadowNode();
+    rootCSSNode.setViewClassName("Root");
+    return rootCSSNode;
+  }
+
+  protected ReactShadowNode createShadowNode(String className) {
+    ViewManager viewManager = mViewManagers.get(className);
+    return viewManager.createShadowNodeInstance();
+  }
+
+  protected final ReactShadowNode resolveShadowNode(int reactTag) {
+    return mShadowNodeRegistry.getNode(reactTag);
+  }
+
   /**
    * Registers a root node with a given tag, size and ThemedReactContext
    * and adds it to a node registry.
@@ -60,12 +85,11 @@ public void registerRootView(
       int width,
       int height,
       ThemedReactContext context) {
-    final ReactShadowNode rootCSSNode = new ReactShadowNode();
+    final ReactShadowNode rootCSSNode = createRootShadowNode();
     rootCSSNode.setReactTag(tag);
     rootCSSNode.setThemedContext(context);
     rootCSSNode.setStyleWidth(width);
     rootCSSNode.setStyleHeight(height);
-    rootCSSNode.setViewClassName("Root");
     mShadowNodeRegistry.addRootNode(rootCSSNode);
 
     // register it within NativeViewHierarchyManager
@@ -104,8 +128,7 @@ public void updateRootNodeSize(
    * Invoked by React to create a new node with a given tag, class name and properties.
    */
   public void createView(int tag, String className, int rootViewTag, ReadableMap props) {
-    ViewManager viewManager = mViewManagers.get(className);
-    ReactShadowNode cssNode = viewManager.createShadowNodeInstance();
+    ReactShadowNode cssNode = createShadowNode(className);
     ReactShadowNode rootNode = mShadowNodeRegistry.getNode(rootViewTag);
     cssNode.setReactTag(tag);
     cssNode.setViewClassName(className);
@@ -120,8 +143,15 @@ public void createView(int tag, String className, int rootViewTag, ReadableMap p
       cssNode.updateProperties(styles);
     }
 
+    handleCreateView(cssNode, rootViewTag, styles);
+  }
+
+  protected void handleCreateView(
+      ReactShadowNode cssNode,
+      int rootViewTag,
+      @Nullable CatalystStylesDiffMap styles) {
     if (!cssNode.isVirtual()) {
-      mNativeViewHierarchyOptimizer.handleCreateView(cssNode, rootNode.getThemedContext(), styles);
+      mNativeViewHierarchyOptimizer.handleCreateView(cssNode, cssNode.getThemedContext(), styles);
     }
   }
 
@@ -141,9 +171,16 @@ public void updateView(int tag, String className, ReadableMap props) {
     if (props != null) {
       CatalystStylesDiffMap styles = new CatalystStylesDiffMap(props);
       cssNode.updateProperties(styles);
-      if (!cssNode.isVirtual()) {
-        mNativeViewHierarchyOptimizer.handleUpdateView(cssNode, className, styles);
-      }
+      handleUpdateView(cssNode, className, styles);
+    }
+  }
+
+  protected void handleUpdateView(
+      ReactShadowNode cssNode,
+      String className,
+      CatalystStylesDiffMap styles) {
+    if (!cssNode.isVirtual()) {
+      mNativeViewHierarchyOptimizer.handleUpdateView(cssNode, className, styles);
     }
   }
 
@@ -401,14 +438,7 @@ public void dispatchViewUpdates(EventDispatcher eventDispatcher, int batchId) {
       ReactShadowNode cssRoot = mShadowNodeRegistry.getNode(tag);
       notifyOnBeforeLayoutRecursive(cssRoot);
 
-      SystraceMessage.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "cssRoot.calculateLayout")
-          .arg("rootTag", tag)
-          .flush();
-      try {
-        cssRoot.calculateLayout(mLayoutContext);
-      } finally {
-        Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
-      }
+      calculateRootLayout(cssRoot);
       applyUpdatesRecursive(cssRoot, 0f, 0f, eventDispatcher);
     }
 
@@ -492,7 +522,7 @@ public void setViewHierarchyUpdateDebugListener(
     mOperationsQueue.setViewHierarchyUpdateDebugListener(listener);
   }
 
-  private void removeShadowNode(ReactShadowNode nodeToRemove) {
+  protected final void removeShadowNode(ReactShadowNode nodeToRemove) {
     mNativeViewHierarchyOptimizer.handleRemoveNode(nodeToRemove);
     mShadowNodeRegistry.removeNode(nodeToRemove.getReactTag());
     for (int i = nodeToRemove.getChildCount() - 1; i >= 0; i--) {
@@ -597,7 +627,18 @@ private void notifyOnBeforeLayoutRecursive(ReactShadowNode cssNode) {
     cssNode.onBeforeLayout();
   }
 
-  private void applyUpdatesRecursive(
+  protected void calculateRootLayout(ReactShadowNode cssRoot) {
+    SystraceMessage.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "cssRoot.calculateLayout")
+        .arg("rootTag", cssRoot.getReactTag())
+        .flush();
+    try {
+      cssRoot.calculateLayout(mLayoutContext);
+    } finally {
+      Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+    }
+  }
+
+  protected void applyUpdatesRecursive(
       ReactShadowNode cssNode,
       float absoluteX,
       float absoluteY,
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
index 6f0ebdcc9258..8f79a72081f3 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
@@ -440,7 +440,7 @@ public void execute() {
 
   private @Nullable NotThreadSafeViewHierarchyUpdateDebugListener mViewHierarchyUpdateDebugListener;
 
-  protected UIViewOperationQueue(
+  public UIViewOperationQueue(
       ReactApplicationContext reactContext,
       NativeViewHierarchyManager nativeViewHierarchyManager) {
     mNativeViewHierarchyManager = nativeViewHierarchyManager;

From cf892a96d693af778679278549fc8fa354326f43 Mon Sep 17 00:00:00 2001
From: Nathan Spaun <nspaun@fb.com>
Date: Tue, 1 Dec 2015 14:17:59 -0800
Subject: [PATCH 0193/1411] Fix NetInfo for Android

Reviewed By: oli

Differential Revision: D2708102

fb-gh-sync-id: f6a12c49c89c46d31114fefaf3e2b1ba72dabdee
---
 Libraries/Network/NetInfo.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Libraries/Network/NetInfo.js b/Libraries/Network/NetInfo.js
index 6c811f9256c4..41eb9390d708 100644
--- a/Libraries/Network/NetInfo.js
+++ b/Libraries/Network/NetInfo.js
@@ -17,7 +17,7 @@ var Platform = require('Platform');
 var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
 var RCTNetInfo = NativeModules.NetInfo;
 
-var DEVICE_REACHABILITY_EVENT = 'networkDidChange';
+var DEVICE_REACHABILITY_EVENT = 'reachabilityDidChange';
 
 type ChangeEventName = $Enum<{
   change: string;
@@ -163,7 +163,7 @@ var NetInfo = {
     var listener = RCTDeviceEventEmitter.addListener(
       DEVICE_REACHABILITY_EVENT,
       (appStateData) => {
-        handler(appStateData.network_info);
+        handler(appStateData.network_reachability);
       }
     );
     _subscriptions.set(handler, listener);

From 098fcb3a277f0c363e00aeeb49880db52ab03424 Mon Sep 17 00:00:00 2001
From: Olivier Notteghem <oli@fb.com>
Date: Tue, 1 Dec 2015 18:03:58 -0800
Subject: [PATCH 0194/1411] LayoutAnimation support for Android RN

Reviewed By: dernienl

Differential Revision: D2710141

fb-gh-sync-id: 28d6af84441b7c2dbc423b73eb05e71f62f7cdea
---
 Examples/UIExplorer/ListViewPagingExample.js  |  10 ++
 .../uimanager/NativeViewHierarchyManager.java |  28 ++++-
 .../react/uimanager/UIImplementation.java     |  35 ++++++
 .../react/uimanager/UIManagerModule.java      |  34 +++++-
 .../react/uimanager/UIViewOperationQueue.java |  42 +++++++
 .../AbstractLayoutAnimation.java              | 108 ++++++++++++++++++
 .../layoutanimation/AnimatedPropertyType.java |  32 ++++++
 .../layoutanimation/BaseLayoutAnimation.java  |  48 ++++++++
 .../layoutanimation/HandlesLayout.java        |  10 ++
 .../layoutanimation/InterpolatorType.java     |  34 ++++++
 .../LayoutAnimationController.java            |  94 +++++++++++++++
 .../layoutanimation/LayoutAnimationType.java  |  22 ++++
 .../LayoutCreateAnimation.java                |  15 +++
 .../LayoutUpdateAnimation.java                |  42 +++++++
 .../layoutanimation/OpacityAnimation.java     |  66 +++++++++++
 .../PositionAndSizeAnimation.java             |  52 +++++++++
 .../SimpleSpringInterpolator.java             |  20 ++++
 .../react/views/view/ReactViewGroup.java      |  11 +-
 18 files changed, 698 insertions(+), 5 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AbstractLayoutAnimation.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AnimatedPropertyType.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/BaseLayoutAnimation.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/HandlesLayout.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/InterpolatorType.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationType.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutCreateAnimation.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutUpdateAnimation.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/OpacityAnimation.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/PositionAndSizeAnimation.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/SimpleSpringInterpolator.java

diff --git a/Examples/UIExplorer/ListViewPagingExample.js b/Examples/UIExplorer/ListViewPagingExample.js
index b82f272c9dbb..7d0ac98f2bfd 100644
--- a/Examples/UIExplorer/ListViewPagingExample.js
+++ b/Examples/UIExplorer/ListViewPagingExample.js
@@ -11,6 +11,7 @@
  * 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.
  *
+ * @provides ListViewPagingExample
  * @flow
  */
 'use strict';
@@ -26,6 +27,11 @@ var {
   View,
 } = React;
 
+var NativeModules = require('NativeModules');
+var {
+  UIManager,
+} = NativeModules;
+
 var PAGE_SIZE = 4;
 var THUMB_URLS = [
   'Thumbnails/like.png',
@@ -48,6 +54,10 @@ var Thumb = React.createClass({
   getInitialState: function() {
     return {thumbIndex: this._getThumbIdx(), dir: 'row'};
   },
+  componentWillMount: function() {
+    UIManager.setLayoutAnimationEnabledExperimental &&
+      UIManager.setLayoutAnimationEnabledExperimental(true);
+  },
   _getThumbIdx: function() {
     return Math.floor(Math.random() * THUMB_URLS.length);
   },
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
index ac6ae4e46d8c..752ffaf291bc 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
@@ -29,9 +29,11 @@
 import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
 import com.facebook.react.bridge.SoftAssertions;
 import com.facebook.react.bridge.UiThreadUtil;
 import com.facebook.react.touch.JSResponderHandler;
+import com.facebook.react.uimanager.layoutanimation.LayoutAnimationController;
 
 /**
  * Delegate of {@link UIManagerModule} that owns the native view hierarchy and mapping between
@@ -65,6 +67,9 @@ public class NativeViewHierarchyManager {
   private final ViewManagerRegistry mViewManagers;
   private final JSResponderHandler mJSResponderHandler = new JSResponderHandler();
   private final RootViewManager mRootViewManager = new RootViewManager();
+  private final LayoutAnimationController mLayoutAnimator = new LayoutAnimationController();
+
+  private boolean mLayoutAnimationEnabled;
 
   public NativeViewHierarchyManager(ViewManagerRegistry viewManagers) {
     mAnimationRegistry = new AnimationRegistry();
@@ -95,6 +100,10 @@ public AnimationRegistry getAnimationRegistry() {
     return mAnimationRegistry;
   }
 
+  public void setLayoutAnimationEnabled(boolean enabled) {
+    mLayoutAnimationEnabled = enabled;
+  }
+
   public void updateProperties(int tag, CatalystStylesDiffMap props) {
     UiThreadUtil.assertOnUiThread();
 
@@ -149,8 +158,17 @@ public void updateLayout(
       }
       if (parentViewGroupManager != null
           && !parentViewGroupManager.needsCustomLayoutForChildren()) {
-        viewToUpdate.layout(x, y, x + width, y + height);
+        updateLayout(viewToUpdate, x, y, width, height);
       }
+    } else {
+      updateLayout(viewToUpdate, x, y, width, height);
+    }
+  }
+
+  private void updateLayout(View viewToUpdate, int x, int y, int width, int height) {
+    if (mLayoutAnimationEnabled &&
+        mLayoutAnimator.shouldAnimateLayout(viewToUpdate)) {
+      mLayoutAnimator.applyLayoutUpdate(viewToUpdate, x, y, width, height);
     } else {
       viewToUpdate.layout(x, y, x + width, y + height);
     }
@@ -466,6 +484,14 @@ public void clearJSResponder() {
     mJSResponderHandler.clearJSResponder();
   }
 
+  void configureLayoutAnimation(final ReadableMap config) {
+    mLayoutAnimator.initializeFromConfig(config);
+  }
+
+  void clearLayoutAnimation() {
+    mLayoutAnimator.reset();
+  }
+
   /* package */ void startAnimationForNativeView(
       int reactTag,
       Animation animation,
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
index 608e33792198..aef2ebc29317 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
@@ -469,6 +469,41 @@ public void removeAnimation(int reactTag, int animationID) {
     mOperationsQueue.enqueueRemoveAnimation(animationID);
   }
 
+  /**
+   * LayoutAnimation API on Android is currently experimental. Therefore, it needs to be enabled
+   * explicitly in order to avoid regression in existing application written for iOS using this API.
+   *
+   * Warning : This method will be removed in future version of React Native, and layout animation
+   * will be enabled by default, so always check for its existence before invoking it.
+   *
+   * TODO(9139831) : remove this method once layout animation is fully stable.
+   *
+   * @param enabled whether layout animation is enabled or not
+   */
+  public void setLayoutAnimationEnabledExperimental(boolean enabled) {
+    mOperationsQueue.enqueueSetLayoutAnimationEnabled(enabled);
+  }
+
+  /**
+   * Configure an animation to be used for the native layout changes, and native views
+   * creation. The animation will only apply during the current batch operations.
+   *
+   * TODO(7728153) : animating view deletion is currently not supported.
+   * TODO(7613721) : callbacks are not supported, this feature will likely be killed.
+   *
+   * @param config the configuration of the animation for view addition/removal/update.
+   * @param success will be called when the animation completes, or when the animation get
+   *        interrupted. In this case, callback parameter will be false.
+   * @param error will be called if there was an error processing the animation
+   */
+  public void configureNextLayoutAnimation(
+      ReadableMap config,
+      Callback success,
+      Callback error) {
+    mOperationsQueue.enqueueConfigureLayoutAnimation(config, success, error);
+  }
+
+
   public void setJSResponder(int reactTag, boolean blockNativeResponder) {
     assertViewExists(reactTag, "setJSResponder");
     ReactShadowNode node = mShadowNodeRegistry.getNode(reactTag);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
index b60598569bf0..b352f4d53e61 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
@@ -374,12 +374,40 @@ public void showPopupMenu(int reactTag, ReadableArray items, Callback error, Cal
     mUIImplementation.showPopupMenu(reactTag, items, error, success);
   }
 
+  /**
+   * LayoutAnimation API on Android is currently experimental. Therefore, it needs to be enabled
+   * explicitly in order to avoid regression in existing application written for iOS using this API.
+   *
+   * Warning : This method will be removed in future version of React Native, and layout animation
+   * will be enabled by default, so always check for its existence before invoking it.
+   *
+   * TODO(9139831) : remove this method once layout animation is fully stable.
+   *
+   * @param enabled whether layout animation is enabled or not
+   */
+  @ReactMethod
+  public void setLayoutAnimationEnabledExperimental(boolean enabled) {
+    mUIImplementation.setLayoutAnimationEnabledExperimental(enabled);
+  }
+
+  /**
+   * Configure an animation to be used for the native layout changes, and native views
+   * creation. The animation will only apply during the current batch operations.
+   *
+   * TODO(7728153) : animating view deletion is currently not supported.
+   * TODO(7613721) : callbacks are not supported, this feature will likely be killed.
+   *
+   * @param config the configuration of the animation for view addition/removal/update.
+   * @param success will be called when the animation completes, or when the animation get
+   *        interrupted. In this case, callback parameter will be false.
+   * @param error will be called if there was an error processing the animation
+   */
   @ReactMethod
   public void configureNextLayoutAnimation(
       ReadableMap config,
-      Callback successCallback,
-      Callback errorCallback) {
-    // TODO(6588266): Implement if required
+      Callback success,
+      Callback error) {
+    mUIImplementation.configureNextLayoutAnimation(config, success, error);
   }
 
   /**
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
index 8f79a72081f3..5fc65cd64a23 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
@@ -23,6 +23,7 @@
 import com.facebook.react.bridge.SoftAssertions;
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
 import com.facebook.react.bridge.UiThreadUtil;
 import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
 import com.facebook.systrace.Systrace;
@@ -322,6 +323,32 @@ public void execute() {
     }
   }
 
+  private class SetLayoutAnimationEnabledOperation implements UIOperation {
+    private final boolean mEnabled;
+
+    private SetLayoutAnimationEnabledOperation(final boolean enabled) {
+      mEnabled = enabled;
+    }
+
+    @Override
+    public void execute() {
+      mNativeViewHierarchyManager.setLayoutAnimationEnabled(mEnabled);
+    }
+  }
+
+  private class ConfigureLayoutAnimationOperation implements UIOperation {
+    private final ReadableMap mConfig;
+
+    private ConfigureLayoutAnimationOperation(final ReadableMap config) {
+      mConfig = config;
+    }
+
+    @Override
+    public void execute() {
+      mNativeViewHierarchyManager.configureLayoutAnimation(mConfig);
+    }
+  }
+
   private final class MeasureOperation implements UIOperation {
 
     private final int mReactTag;
@@ -584,6 +611,18 @@ public void enqueueRemoveAnimation(int animationID) {
     mOperations.add(new RemoveAnimationOperation(animationID));
   }
 
+  public void enqueueSetLayoutAnimationEnabled(
+      final boolean enabled) {
+    mOperations.add(new SetLayoutAnimationEnabledOperation(enabled));
+  }
+
+  public void enqueueConfigureLayoutAnimation(
+      final ReadableMap config,
+      final Callback onSuccess,
+      final Callback onError) {
+    mOperations.add(new ConfigureLayoutAnimationOperation(config));
+  }
+
   public void enqueueMeasure(
       final int reactTag,
       final Callback callback) {
@@ -680,6 +719,9 @@ public void doFrameGuarded(long frameTimeNanos) {
           mDispatchUIRunnables.get(i).run();
         }
         mDispatchUIRunnables.clear();
+
+        // Clear layout animation, as animation only apply to current UI operations batch.
+        mNativeViewHierarchyManager.clearLayoutAnimation();
       }
 
       ReactChoreographer.getInstance().postFrameCallback(
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AbstractLayoutAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AbstractLayoutAnimation.java
new file mode 100644
index 000000000000..c29d7ae0bef9
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AbstractLayoutAnimation.java
@@ -0,0 +1,108 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+import javax.annotation.Nullable;
+
+import java.util.Map;
+
+import android.view.View;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.Animation;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
+
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.common.MapBuilder;
+import com.facebook.react.uimanager.IllegalViewOperationException;
+
+/**
+ * Class responsible for parsing and converting layout animation data into native {@link Animation}
+ * in order to animate layout when a valid configuration has been supplied by the application.
+ */
+/* package */ abstract class AbstractLayoutAnimation {
+
+  // Forces animation to be playing 10x slower, used for debug purposes.
+  private static final boolean SLOWDOWN_ANIMATION_MODE = false;
+
+  abstract boolean isValid();
+
+  /**
+   * Create an animation object for the current animation type, based on the view and final screen
+   * coordinates. If the application-supplied configuraiton does not specify an animation definition
+   * for this types, or if the animation definition is invalid, returns null.
+   */
+  abstract @Nullable Animation createAnimationImpl(View view, int x, int y, int width, int height);
+
+  private static final Map<InterpolatorType, Interpolator> INTERPOLATOR = MapBuilder.of(
+      InterpolatorType.LINEAR, new LinearInterpolator(),
+      InterpolatorType.EASE_IN, new AccelerateInterpolator(),
+      InterpolatorType.EASE_OUT, new DecelerateInterpolator(),
+      InterpolatorType.EASE_IN_EASE_OUT, new AccelerateDecelerateInterpolator(),
+      InterpolatorType.SPRING, new SimpleSpringInterpolator());
+
+  private @Nullable Interpolator mInterpolator;
+  private int mDelayMs;
+
+  protected @Nullable AnimatedPropertyType mAnimatedProperty;
+  protected int mDurationMs;
+
+  public void reset() {
+    mAnimatedProperty = null;
+    mDurationMs = 0;
+    mDelayMs = 0;
+    mInterpolator = null;
+  }
+
+  public void initializeFromConfig(ReadableMap data, int globalDuration) {
+    mAnimatedProperty = data.hasKey("property") ?
+        AnimatedPropertyType.fromString(data.getString("property")) : null;
+    mDurationMs = data.hasKey("duration") ? data.getInt("duration") : globalDuration;
+    mDelayMs = data.hasKey("delay") ? data.getInt("delay") : 0;
+    mInterpolator = data.hasKey("type") ?
+        getInterpolator(InterpolatorType.fromString(data.getString("type"))) : null;
+
+    if (!isValid()) {
+      throw new IllegalViewOperationException("Invalid layout animation : " + data);
+    }
+  }
+
+  /**
+   * Create an animation object to be used to animate the view, based on the animation config
+   * supplied at initialization time and the new view position and size.
+   *
+   * @param view the view to create the animation for
+   * @param x the new X position for the view
+   * @param y the new Y position for the view
+   * @param width the new width value for the view
+   * @param height the new height value for the view
+   */
+   public final @Nullable Animation createAnimation(
+       View view,
+       int x,
+       int y,
+       int width,
+       int height) {
+    if (!isValid()) {
+      return null;
+    }
+    Animation animation = createAnimationImpl(view, x, y, width, height);
+    if (animation != null) {
+      int slowdownFactor = SLOWDOWN_ANIMATION_MODE ? 10 : 1;
+      animation.setDuration(mDurationMs * slowdownFactor);
+      animation.setStartOffset(mDelayMs * slowdownFactor);
+      animation.setInterpolator(mInterpolator);
+    }
+    return animation;
+  }
+
+  private static Interpolator getInterpolator(InterpolatorType type) {
+    Interpolator interpolator = INTERPOLATOR.get(type);
+    if (interpolator == null) {
+      throw new IllegalArgumentException("Missing interpolator for type : " + type);
+    }
+    return interpolator;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AnimatedPropertyType.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AnimatedPropertyType.java
new file mode 100644
index 000000000000..51a9d246c061
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/AnimatedPropertyType.java
@@ -0,0 +1,32 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+/**
+ * Enum representing the different view properties that can be used when animating layout for
+ * view creation.
+ */
+/* package */ enum AnimatedPropertyType {
+  OPACITY("opacity"),
+  SCALE_XY("scaleXY");
+
+  private final String mName;
+
+  private AnimatedPropertyType(String name) {
+    mName = name;
+  }
+
+  public static AnimatedPropertyType fromString(String name) {
+    for (AnimatedPropertyType property : AnimatedPropertyType.values()) {
+      if (property.toString().equalsIgnoreCase(name)) {
+        return property;
+      }
+    }
+    throw new IllegalArgumentException("Unsupported animated property : " + name);
+  }
+
+  @Override
+  public String toString() {
+    return mName;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/BaseLayoutAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/BaseLayoutAnimation.java
new file mode 100644
index 000000000000..9d3d0f45aa79
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/BaseLayoutAnimation.java
@@ -0,0 +1,48 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.ScaleAnimation;
+
+import com.facebook.react.uimanager.IllegalViewOperationException;
+
+/**
+ * Class responsible for default layout animation, i.e animation of view creation and deletion.
+ */
+/* package */ abstract class BaseLayoutAnimation extends AbstractLayoutAnimation {
+
+  abstract boolean isReverse();
+
+  @Override
+  boolean isValid() {
+    return mDurationMs > 0 && mAnimatedProperty != null;
+  }
+
+  @Override
+  Animation createAnimationImpl(View view, int x, int y, int width, int height) {
+    float fromValue = isReverse() ? 1.0f : 0.0f;
+    float toValue = isReverse() ? 0.0f : 1.0f;
+    if (mAnimatedProperty != null) {
+      switch (mAnimatedProperty) {
+        case OPACITY:
+          return new OpacityAnimation(view, fromValue, toValue);
+        case SCALE_XY:
+          return new ScaleAnimation(
+              fromValue,
+              toValue,
+              fromValue,
+              toValue,
+              Animation.RELATIVE_TO_PARENT,
+              .5f,
+              Animation.RELATIVE_TO_PARENT,
+              .5f);
+        default:
+          throw new IllegalViewOperationException(
+              "Missing animation for property : " + mAnimatedProperty);
+      }
+    }
+    throw new IllegalViewOperationException("Missing animated property from animation config");
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/HandlesLayout.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/HandlesLayout.java
new file mode 100644
index 000000000000..9f3c907e97d0
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/HandlesLayout.java
@@ -0,0 +1,10 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+/**
+ * Marker interface to indicate a given animation type takes care of updating the view layout.
+ */
+/* package */ interface HandleLayout {
+
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/InterpolatorType.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/InterpolatorType.java
new file mode 100644
index 000000000000..f59675a8fbe1
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/InterpolatorType.java
@@ -0,0 +1,34 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+/**
+ * Enum representing the different interpolators that can be used in layout animation configuration.
+ */
+/* package */ enum InterpolatorType {
+  LINEAR("linear"),
+  EASE_IN("easeIn"),
+  EASE_OUT("easeOut"),
+  EASE_IN_EASE_OUT("easeInEaseOut"),
+  SPRING("spring");
+
+  private final String mName;
+
+  private InterpolatorType(String name) {
+    mName = name;
+  }
+
+  public static InterpolatorType fromString(String name) {
+    for (InterpolatorType type : InterpolatorType.values()) {
+      if (type.toString().equalsIgnoreCase(name)) {
+        return type;
+      }
+    }
+    throw new IllegalArgumentException("Unsupported interpolation type : " + name);
+  }
+
+  @Override
+  public String toString() {
+    return mName;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java
new file mode 100644
index 000000000000..d3522947fd36
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java
@@ -0,0 +1,94 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.NotThreadSafe;
+
+import android.view.View;
+import android.view.animation.Animation;
+
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.UiThreadUtil;
+
+/**
+ * Class responsible for animation layout changes, if a valid layout animation config has been
+ * supplied. If not animation is available, layout change is applied immediately instead of
+ * performing an animation.
+ *
+ * TODO(7613721): Invoke success callback at the end of animation and when animation gets cancelled.
+ */
+@NotThreadSafe
+public class LayoutAnimationController {
+
+  private static final boolean ENABLED = true;
+
+  private final AbstractLayoutAnimation mLayoutCreateAnimation = new LayoutCreateAnimation();
+  private final AbstractLayoutAnimation mLayoutUpdateAnimation = new LayoutUpdateAnimation();
+  private boolean mShouldAnimateLayout;
+
+  public void initializeFromConfig(final @Nullable ReadableMap config) {
+    if (!ENABLED) {
+      return;
+    }
+
+    if (config == null) {
+      reset();
+      return;
+    }
+
+    mShouldAnimateLayout = false;
+    int globalDuration = config.hasKey("duration") ? config.getInt("duration") : 0;
+    if (config.hasKey(LayoutAnimationType.CREATE.toString())) {
+      mLayoutCreateAnimation.initializeFromConfig(
+          config.getMap(LayoutAnimationType.CREATE.toString()), globalDuration);
+      mShouldAnimateLayout = true;
+    }
+    if (config.hasKey(LayoutAnimationType.UPDATE.toString())) {
+      mLayoutUpdateAnimation.initializeFromConfig(
+          config.getMap(LayoutAnimationType.UPDATE.toString()), globalDuration);
+      mShouldAnimateLayout = true;
+    }
+  }
+
+  public void reset() {
+    mLayoutCreateAnimation.reset();
+    mLayoutUpdateAnimation.reset();
+    mShouldAnimateLayout = false;
+  }
+
+  public boolean shouldAnimateLayout(View viewToAnimate) {
+    // if view parent is null, skip animation: view have been clipped, we don't want animation to
+    // resume when view is re-attached to parent, which is the standard android animation behavior.
+    return mShouldAnimateLayout && viewToAnimate.getParent() != null;
+  }
+
+  /**
+   * Update layout of given view, via immediate update or animation depending on the current batch
+   * layout animation configuration supplied during initialization.
+   *
+   * @param view the view to update layout of
+   * @param x the new X position for the view
+   * @param y the new Y position for the view
+   * @param width the new width value for the view
+   * @param height the new height value for the view
+   */
+  public void applyLayoutUpdate(View view, int x, int y, int width, int height) {
+    UiThreadUtil.assertOnUiThread();
+
+    // Determine which animation to use : if view is initially invisible, use create animation.
+    // If view is becoming invisible, use delete animation. Otherwise, use update animation.
+    // This approach is easier than maintaining a list of tags for recently created/deleted views.
+    AbstractLayoutAnimation layoutAnimation = (view.getWidth() == 0 || view.getHeight() == 0) ?
+        mLayoutCreateAnimation :
+        mLayoutUpdateAnimation;
+
+    Animation animation = layoutAnimation.createAnimation(view, x, y, width, height);
+    if (animation == null || !(animation instanceof HandleLayout)) {
+      view.layout(x, y, x + width, y + height);
+    }
+    if (animation != null) {
+      view.startAnimation(animation);
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationType.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationType.java
new file mode 100644
index 000000000000..0f3d9d7fdb2b
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationType.java
@@ -0,0 +1,22 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+/**
+ * Enum representing the different animation type that can be specified in layout animation config.
+ */
+/* package */ enum LayoutAnimationType {
+  CREATE("create"),
+  UPDATE("update");
+
+  private final String mName;
+
+  private LayoutAnimationType(String name) {
+    mName = name;
+  }
+
+  @Override
+  public String toString() {
+    return mName;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutCreateAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutCreateAnimation.java
new file mode 100644
index 000000000000..a989e625c675
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutCreateAnimation.java
@@ -0,0 +1,15 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+/**
+ * Class responsible for handling layout view creation animation, applied to view whenever a
+ * valid config was supplied for the layout animation of CREATE type.
+ */
+/* package */ class LayoutCreateAnimation extends BaseLayoutAnimation {
+
+  @Override
+  boolean isReverse() {
+    return false;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutUpdateAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutUpdateAnimation.java
new file mode 100644
index 000000000000..8189716f729d
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutUpdateAnimation.java
@@ -0,0 +1,42 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+import javax.annotation.Nullable;
+
+import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.TranslateAnimation;
+
+/**
+ * Class responsible for handling layout update animation, applied to view whenever a valid config
+ * was supplied for the layout animation of UPDATE type.
+ */
+/* package */ class LayoutUpdateAnimation extends AbstractLayoutAnimation {
+
+  // We are currently not enabling translation GPU-accelerated animated, as it creates odd
+  // artifacts with native react scrollview. This needs to be investigated.
+  private static final boolean USE_TRANSLATE_ANIMATION = false;
+
+  @Override
+  boolean isValid() {
+    return mDurationMs > 0;
+  }
+
+  @Override
+  @Nullable Animation createAnimationImpl(View view, int x, int y, int width, int height) {
+    boolean animateLocation = view.getX() != x || view.getY() != y;
+    boolean animateSize = view.getWidth() != width || view.getHeight() != height;
+    if (!animateLocation && !animateSize) {
+      return null;
+    } else if (animateLocation && !animateSize && USE_TRANSLATE_ANIMATION) {
+      // Use GPU-accelerated animation, however we loose the ability to resume interrupted
+      // animation where it was left off. We may be able to listen to animation interruption
+      // and set the layout manually in this case, so that next animation kicks off smoothly.
+      return new TranslateAnimation(view.getX() - x, 0, view.getY() - y, 0);
+    } else {
+      // Animation is sub-optimal for perf, but scale transformation can't be use in this case.
+      return new PositionAndSizeAnimation(view, x, y, width, height);
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/OpacityAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/OpacityAnimation.java
new file mode 100644
index 000000000000..a7ad690023c5
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/OpacityAnimation.java
@@ -0,0 +1,66 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.Transformation;
+
+/**
+ * Animation responsible for updating opacity of a view. It should ideally use hardware texture
+ * to optimize rendering performances.
+ */
+/* package */ class OpacityAnimation extends Animation {
+
+  static class OpacityAnimationListener implements AnimationListener {
+
+    private final View mView;
+    private boolean mLayerTypeChanged = false;
+
+    public OpacityAnimationListener(View view) {
+      mView = view;
+    }
+
+    @Override
+    public void onAnimationStart(Animation animation) {
+      if (mView.hasOverlappingRendering() &&
+          mView.getLayerType() == View.LAYER_TYPE_NONE) {
+        mLayerTypeChanged = true;
+        mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+      }
+    }
+
+    @Override
+    public void onAnimationEnd(Animation animation) {
+      if (mLayerTypeChanged) {
+        mView.setLayerType(View.LAYER_TYPE_NONE, null);
+      }
+    }
+
+    @Override
+    public void onAnimationRepeat(Animation animation) {
+      // do nothing
+    }
+  }
+
+  private final View mView;
+  private final float mStartOpacity, mDeltaOpacity;
+
+  public OpacityAnimation(View view, float startOpacity, float endOpacity) {
+    mView = view;
+    mStartOpacity = startOpacity;
+    mDeltaOpacity = endOpacity - startOpacity;
+
+    setAnimationListener(new OpacityAnimationListener(view));
+  }
+
+  @Override
+  protected void applyTransformation(float interpolatedTime, Transformation t) {
+    mView.setAlpha(mStartOpacity + mDeltaOpacity * interpolatedTime);
+  }
+
+  @Override
+  public boolean willChangeBounds() {
+    return false;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/PositionAndSizeAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/PositionAndSizeAnimation.java
new file mode 100644
index 000000000000..2adf81a6bb6c
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/PositionAndSizeAnimation.java
@@ -0,0 +1,52 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.Transformation;
+
+/**
+ * Animation responsible for updating size and position of a view. We can't use scaling as view
+ * content may not necessarily stretch. As a result, this approach is inefficient because of
+ * layout passes occurring on every frame.
+ * What we might want to try to do instead is use a combined ScaleAnimation and TranslateAnimation.
+ */
+/* package */ class PositionAndSizeAnimation extends Animation implements HandleLayout {
+
+  private final View mView;
+  private final float mStartX, mStartY, mDeltaX, mDeltaY;
+  private final int mStartWidth, mStartHeight, mDeltaWidth, mDeltaHeight;
+
+  public PositionAndSizeAnimation(View view, int x, int y, int width, int height) {
+    mView = view;
+
+    mStartX = view.getX();
+    mStartY = view.getY();
+    mStartWidth = view.getWidth();
+    mStartHeight = view.getHeight();
+
+    mDeltaX = x - mStartX;
+    mDeltaY = y - mStartY;
+    mDeltaWidth = width - mStartWidth;
+    mDeltaHeight = height - mStartHeight;
+  }
+
+  @Override
+  protected void applyTransformation(float interpolatedTime, Transformation t) {
+    float newX = mStartX + mDeltaX * interpolatedTime;
+    float newY = mStartY + mDeltaY * interpolatedTime;
+    float newWidth = mStartWidth + mDeltaWidth * interpolatedTime;
+    float newHeight = mStartHeight + mDeltaHeight * interpolatedTime;
+    mView.layout(
+        Math.round(newX),
+        Math.round(newY),
+        Math.round(newX + newWidth),
+        Math.round(newY + newHeight));
+  }
+
+  @Override
+  public boolean willChangeBounds() {
+    return true;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/SimpleSpringInterpolator.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/SimpleSpringInterpolator.java
new file mode 100644
index 000000000000..9696fe90a1a3
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/SimpleSpringInterpolator.java
@@ -0,0 +1,20 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.layoutanimation;
+
+import android.view.animation.Interpolator;
+
+/**
+ * Simple spring interpolator
+ */
+//TODO(7613736): Improve spring interpolator with friction and damping variable support
+/* package */  class SimpleSpringInterpolator implements Interpolator {
+
+  private static final float FACTOR = 0.5f;
+
+  @Override
+  public float getInterpolation(float input) {
+    return (float)
+        (1 + Math.pow(2, -10 * input) * Math.sin((input - FACTOR / 4) * Math.PI * 2 / FACTOR));
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
index 134b6492b9bf..9e2728db4e1e 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
@@ -16,6 +16,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
+import android.view.animation.Animation;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
@@ -286,7 +287,15 @@ private void updateSubviewClipStatus(Rect clippingRect, int idx, int clippedSoFa
     boolean intersects = clippingRect
         .intersects(sHelperRect.left, sHelperRect.top, sHelperRect.right, sHelperRect.bottom);
     boolean needUpdateClippingRecursive = false;
-    if (!intersects && child.getParent() != null) {
+    // We never want to clip children that are being animated, as this can easily break layout :
+    // when layout animation changes size and/or position of views contained inside a listview that
+    // clips offscreen children, we need to ensure that, when view exits the viewport, final size
+    // and position is set prior to removing the view from its listview parent.
+    // Otherwise, when view gets re-attached again, i.e when it re-enters the viewport after scroll,
+    // it won't be size and located properly.
+    Animation animation = child.getAnimation();
+    boolean isAnimating = animation != null && !animation.hasEnded();
+    if (!intersects && child.getParent() != null && !isAnimating) {
       // We can try saving on invalidate call here as the view that we remove is out of visible area
       // therefore invalidation is not necessary.
       super.removeViewsInLayout(idx - clippedSoFar, 1);

From 892dd5b86ab6e90337ccfb3f78e5ac5a4ef17839 Mon Sep 17 00:00:00 2001
From: Gabe Levi <glevi@fb.com>
Date: Tue, 1 Dec 2015 19:09:01 -0800
Subject: [PATCH 0195/1411] Fix errors uncovered by v0.19.0

Reviewed By: mroch

Differential Revision: D2706663

fb-gh-sync-id: 017c91bab849bf18767cacd2ebe32d1a1b10c715
---
 Examples/UIExplorer/GeolocationExample.js     | 12 ++-
 Examples/UIExplorer/ImageExample.js           |  1 +
 Examples/UIExplorer/LayoutEventsExample.js    | 25 ++++--
 Examples/UIExplorer/MapViewExample.js         | 87 ++++++++++++++++---
 Examples/UIExplorer/PanResponderExample.js    |  8 +-
 Examples/UIExplorer/PickerIOSExample.js       |  2 +-
 Examples/UIExplorer/UIExplorerListBase.js     |  2 +-
 Examples/UIExplorer/XHRExampleHeaders.js      |  3 +-
 IntegrationTests/AppEventsTest.js             |  9 +-
 IntegrationTests/IntegrationTestsApp.js       |  4 +-
 IntegrationTests/LayoutEventsTest.js          | 33 +++++--
 .../Components/Navigation/NavigatorIOS.ios.js |  4 +-
 .../Components/TabBarIOS/TabBarItemIOS.ios.js |  1 +
 Libraries/Components/TextInput/TextInput.js   |  8 +-
 .../ToastAndroid/ToastAndroid.ios.js          |  1 +
 .../Components/Touchable/TouchableBounce.js   |  1 +
 .../Touchable/TouchableHighlight.js           |  1 +
 .../Components/Touchable/TouchableOpacity.js  |  1 +
 .../Navigator/Navigation/NavigationContext.js |  1 +
 Libraries/ReactIOS/renderApplication.ios.js   |  1 +
 Libraries/Storage/AsyncStorage.js             |  1 +
 Libraries/Utilities/MatrixMath.js             |  1 +
 .../vendor/emitter/EmitterSubscription.js     |  1 +
 Libraries/vendor/emitter/EventEmitter.js      |  1 +
 24 files changed, 168 insertions(+), 41 deletions(-)

diff --git a/Examples/UIExplorer/GeolocationExample.js b/Examples/UIExplorer/GeolocationExample.js
index d9dd4e842b74..61d7d3778bda 100644
--- a/Examples/UIExplorer/GeolocationExample.js
+++ b/Examples/UIExplorer/GeolocationExample.js
@@ -49,11 +49,15 @@ var GeolocationExample = React.createClass({
 
   componentDidMount: function() {
     navigator.geolocation.getCurrentPosition(
-      (initialPosition) => this.setState({initialPosition}),
+      (position) => {
+        var initialPosition = JSON.stringify(position);
+        this.setState({initialPosition});
+      },
       (error) => alert(error.message),
       {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
     );
-    this.watchID = navigator.geolocation.watchPosition((lastPosition) => {
+    this.watchID = navigator.geolocation.watchPosition((position) => {
+      var lastPosition = JSON.stringify(position);
       this.setState({lastPosition});
     });
   },
@@ -67,11 +71,11 @@ var GeolocationExample = React.createClass({
       <View>
         <Text>
           <Text style={styles.title}>Initial position: </Text>
-          {JSON.stringify(this.state.initialPosition)}
+          {this.state.initialPosition}
         </Text>
         <Text>
           <Text style={styles.title}>Current position: </Text>
-          {JSON.stringify(this.state.lastPosition)}
+          {this.state.lastPosition}
         </Text>
       </View>
     );
diff --git a/Examples/UIExplorer/ImageExample.js b/Examples/UIExplorer/ImageExample.js
index 68b16b2d103e..50c96ffd285e 100644
--- a/Examples/UIExplorer/ImageExample.js
+++ b/Examples/UIExplorer/ImageExample.js
@@ -32,6 +32,7 @@ var NetworkImageCallbackExample = React.createClass({
   getInitialState: function() {
     return {
       events: [],
+      mountTime: new Date(),
     };
   },
 
diff --git a/Examples/UIExplorer/LayoutEventsExample.js b/Examples/UIExplorer/LayoutEventsExample.js
index bcbb5cbb7f93..a6b0cea89c0f 100644
--- a/Examples/UIExplorer/LayoutEventsExample.js
+++ b/Examples/UIExplorer/LayoutEventsExample.js
@@ -24,19 +24,30 @@ var {
   View,
 } = React;
 
+type Layout = {
+  x: number;
+  y: number;
+  width: number;
+  height: number;
+};
+
 type LayoutEvent = {
   nativeEvent: {
-    layout: {
-      x: number;
-      y: number;
-      width: number;
-      height: number;
-    };
+    layout: Layout,
   };
 };
 
+type State = {
+  containerStyle?: { width: number },
+  extraText?: string,
+  imageLayout?: Layout,
+  textLayout?: Layout,
+  viewLayout?: Layout,
+  viewStyle: { margin: number },
+};
+
 var LayoutEventExample = React.createClass({
-  getInitialState: function() {
+  getInitialState(): State {
     return {
       viewStyle: {
         margin: 20,
diff --git a/Examples/UIExplorer/MapViewExample.js b/Examples/UIExplorer/MapViewExample.js
index 863187edab61..44142a4af160 100644
--- a/Examples/UIExplorer/MapViewExample.js
+++ b/Examples/UIExplorer/MapViewExample.js
@@ -31,6 +31,17 @@ var regionText = {
   longitudeDelta: '0',
 };
 
+type MapRegion = {
+  latitude: number,
+  longitude: number,
+  latitudeDelta: number,
+  longitudeDelta: number,
+};
+
+type MapRegionInputState = {
+  region: MapRegion,
+};
+
 var MapRegionInput = React.createClass({
 
   propTypes: {
@@ -43,7 +54,7 @@ var MapRegionInput = React.createClass({
     onChange: React.PropTypes.func.isRequired,
   },
 
-  getInitialState: function() {
+  getInitialState(): MapRegionInputState {
     return {
       region: {
         latitude: 0,
@@ -135,19 +146,42 @@ var MapRegionInput = React.createClass({
 
   _change: function() {
     this.setState({
-      latitude: parseFloat(regionText.latitude),
-      longitude: parseFloat(regionText.longitude),
-      latitudeDelta: parseFloat(regionText.latitudeDelta),
-      longitudeDelta: parseFloat(regionText.longitudeDelta),
+      region: {
+        latitude: parseFloat(regionText.latitude),
+        longitude: parseFloat(regionText.longitude),
+        latitudeDelta: parseFloat(regionText.latitudeDelta),
+        longitudeDelta: parseFloat(regionText.longitudeDelta),
+      },
     });
     this.props.onChange(this.state.region);
   },
 
 });
 
+type Annotations = Array<{
+  animateDrop?: boolean,
+  latitude: number,
+  longitude: number,
+  title?: string,
+  subtitle?: string,
+  hasLeftCallout?: boolean,
+  hasRightCallout?: boolean,
+  onLeftCalloutPress?: Function,
+  onRightCalloutPress?: Function,
+  tintColor?: string,
+  image?: any,
+  id?: string,
+}>;
+type MapViewExampleState = {
+  isFirstLoad: boolean,
+  mapRegion?: MapRegion,
+  mapRegionInput?: MapRegion,
+  annotations?: Annotations,
+};
+
 var MapViewExample = React.createClass({
 
-  getInitialState() {
+  getInitialState(): MapViewExampleState {
     return {
       isFirstLoad: true,
     };
@@ -171,7 +205,7 @@ var MapViewExample = React.createClass({
     );
   },
 
-  _getAnnotations(region) {
+  _getAnnotations(region): Annotations {
     return [{
       longitude: region.longitude,
       latitude: region.latitude,
@@ -205,9 +239,14 @@ var MapViewExample = React.createClass({
 
 });
 
+type CalloutMapViewExampleState = {
+  isFirstLoad: boolean,
+  annotations?: Annotations,
+  mapRegion?: MapRegion,
+};
 var CalloutMapViewExample = React.createClass({
 
-  getInitialState() {
+  getInitialState(): CalloutMapViewExampleState {
     return {
       isFirstLoad: true,
     };
@@ -243,9 +282,14 @@ var CalloutMapViewExample = React.createClass({
 
 });
 
+type CustomPinColorMapViewExampleState = {
+  isFirstLoad: boolean,
+  annotations?: Annotations,
+  mapRegion?: MapRegion,
+};
 var CustomPinColorMapViewExample = React.createClass({
 
-  getInitialState() {
+  getInitialState(): CustomPinColorMapViewExampleState {
     return {
       isFirstLoad: true,
     };
@@ -278,9 +322,14 @@ var CustomPinColorMapViewExample = React.createClass({
 
 });
 
+type CustomPinImageMapViewExampleState = {
+  isFirstLoad: boolean,
+  annotations?: Annotations,
+  mapRegion?: MapRegion,
+};
 var CustomPinImageMapViewExample = React.createClass({
 
-  getInitialState() {
+  getInitialState(): CustomPinImageMapViewExampleState {
     return {
       isFirstLoad: true,
     };
@@ -313,9 +362,25 @@ var CustomPinImageMapViewExample = React.createClass({
 
 });
 
+type Overlays = Array<{
+  coordinates?: Array<{
+    latitude: number,
+    longitude: number,
+  }>,
+  lineWidth?: number,
+  strokeColor?: string,
+  fillColor?: string,
+  id?: string,
+}>;
+type CustomOverlayMapViewExampleState = {
+  isFirstLoad: boolean,
+  overlays?: Overlays,
+  annotations?: Annotations,
+  mapRegion?: MapRegion,
+};
 var CustomOverlayMapViewExample = React.createClass({
 
-  getInitialState() {
+  getInitialState(): CustomOverlayMapViewExampleState {
     return {
       isFirstLoad: true,
     };
diff --git a/Examples/UIExplorer/PanResponderExample.js b/Examples/UIExplorer/PanResponderExample.js
index c2e6a667ce0d..47833af3f5a8 100644
--- a/Examples/UIExplorer/PanResponderExample.js
+++ b/Examples/UIExplorer/PanResponderExample.js
@@ -11,7 +11,7 @@
  * 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.
  *
- * @flow-weak
+ * @flow weak
  */
 'use strict';
 
@@ -79,7 +79,8 @@ var PanResponderExample = React.createClass({
   },
 
   _highlight: function() {
-    this.circle && this.circle.setNativeProps({
+    const circle = this.circle;
+    circle && circle.setNativeProps({
       style: {
         backgroundColor: processColor(CIRCLE_HIGHLIGHT_COLOR)
       }
@@ -87,7 +88,8 @@ var PanResponderExample = React.createClass({
   },
 
   _unHighlight: function() {
-    this.circle && this.circle.setNativeProps({
+    const circle = this.circle;
+    circle && circle.setNativeProps({
       style: {
         backgroundColor: processColor(CIRCLE_COLOR)
       }
diff --git a/Examples/UIExplorer/PickerIOSExample.js b/Examples/UIExplorer/PickerIOSExample.js
index 31c81ccccdad..b0cc5cb9729d 100644
--- a/Examples/UIExplorer/PickerIOSExample.js
+++ b/Examples/UIExplorer/PickerIOSExample.js
@@ -99,7 +99,7 @@ var PickerExample = React.createClass({
           {CAR_MAKES_AND_MODELS[this.state.carMake].models.map(
             (modelName, modelIndex) => (
               <PickerItemIOS
-                key={this.state.carmake + '_' + modelIndex}
+                key={this.state.carMake + '_' + modelIndex}
                 value={modelIndex}
                 label={modelName}
               />
diff --git a/Examples/UIExplorer/UIExplorerListBase.js b/Examples/UIExplorer/UIExplorerListBase.js
index 4b26a6976dc6..c4b55f6d0ab3 100644
--- a/Examples/UIExplorer/UIExplorerListBase.js
+++ b/Examples/UIExplorer/UIExplorerListBase.js
@@ -116,7 +116,7 @@ class UIExplorerListBase extends React.Component {
   search(text: mixed): void {
     this.props.search && this.props.search(text);
 
-    var regex = new RegExp(text, 'i');
+    var regex = new RegExp(String(text), 'i');
     var filter = (component) => regex.test(component.title);
 
     this.setState({
diff --git a/Examples/UIExplorer/XHRExampleHeaders.js b/Examples/UIExplorer/XHRExampleHeaders.js
index e9f5e2c4c974..e83c1b071d95 100644
--- a/Examples/UIExplorer/XHRExampleHeaders.js
+++ b/Examples/UIExplorer/XHRExampleHeaders.js
@@ -11,6 +11,7 @@
  * 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.
  *
+ * @noflow
  */
 'use strict';
 
@@ -113,4 +114,4 @@ var styles = StyleSheet.create({
   },
 });
 
-module.exports = XHRExampleHeaders;
\ No newline at end of file
+module.exports = XHRExampleHeaders;
diff --git a/IntegrationTests/AppEventsTest.js b/IntegrationTests/AppEventsTest.js
index 7362072ffd48..c003b014d1ea 100644
--- a/IntegrationTests/AppEventsTest.js
+++ b/IntegrationTests/AppEventsTest.js
@@ -24,8 +24,15 @@ var deepDiffer = require('deepDiffer');
 
 var TEST_PAYLOAD = {foo: 'bar'};
 
+type AppEvent = { data: Object, ts: number, };
+type State = {
+  sent: 'none' | AppEvent,
+  received: 'none' | AppEvent,
+  elapsed?: string,
+};
+
 var AppEventsTest = React.createClass({
-  getInitialState: function() {
+  getInitialState(): State {
     return {sent: 'none', received: 'none'};
   },
   componentDidMount: function() {
diff --git a/IntegrationTests/IntegrationTestsApp.js b/IntegrationTests/IntegrationTestsApp.js
index ce136f7fd6fa..54fca9a4bd49 100644
--- a/IntegrationTests/IntegrationTestsApp.js
+++ b/IntegrationTests/IntegrationTestsApp.js
@@ -39,10 +39,12 @@ TESTS.forEach(
 // Modules required for integration tests
 require('LoggingTestModule');
 
+type Test = any;
+
 var IntegrationTestsApp = React.createClass({
   getInitialState: function() {
     return {
-      test: null,
+      test: (null: ?Test),
     };
   },
   render: function() {
diff --git a/IntegrationTests/LayoutEventsTest.js b/IntegrationTests/LayoutEventsTest.js
index 9f7eb7d54b35..2cfe13f9b9dd 100644
--- a/IntegrationTests/LayoutEventsTest.js
+++ b/IntegrationTests/LayoutEventsTest.js
@@ -27,19 +27,38 @@ function debug() {
   // console.log.apply(null, arguments);
 }
 
+type Layout = {
+  x: number;
+  y: number;
+  width: number;
+  height: number;
+};
 type LayoutEvent = {
   nativeEvent: {
-    layout: {
-      x: number;
-      y: number;
-      width: number;
-      height: number;
-    };
+    layout: Layout;
   };
 };
+type Style = {
+  margin?: number,
+  padding?: number,
+  borderColor?: string,
+  borderWidth?: number,
+  backgroundColor?: string,
+  width?: number,
+};
+
+type State = {
+  didAnimation: boolean,
+  extraText?: string,
+  imageLayout?: Layout,
+  textLayout?: Layout,
+  viewLayout?: Layout,
+  viewStyle?: Style,
+  containerStyle?: Style,
+};
 
 var LayoutEventsTest = React.createClass({
-  getInitialState: function() {
+  getInitialState(): State {
     return {
       didAnimation: false,
     };
diff --git a/Libraries/Components/Navigation/NavigatorIOS.ios.js b/Libraries/Components/Navigation/NavigatorIOS.ios.js
index a0f2199b295d..6d86930b7a6f 100644
--- a/Libraries/Components/Navigation/NavigatorIOS.ios.js
+++ b/Libraries/Components/Navigation/NavigatorIOS.ios.js
@@ -74,7 +74,7 @@ type State = {
   fromIndex: number;
   toIndex: number;
   makingNavigatorRequest: boolean;
-  updatingAllIndicesAtOrBeyond: number;
+  updatingAllIndicesAtOrBeyond: ?number;
 }
 
 type Event = Object;
@@ -592,7 +592,7 @@ var NavigatorIOS = React.createClass({
 
   _routeToStackItem: function(route: Route, i: number) {
     var Component = route.component;
-    var shouldUpdateChild = this.state.updatingAllIndicesAtOrBeyond !== null &&
+    var shouldUpdateChild = this.state.updatingAllIndicesAtOrBeyond != null &&
       this.state.updatingAllIndicesAtOrBeyond >= i;
 
     return (
diff --git a/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js b/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js
index a4c883bc900e..f220249c76c7 100644
--- a/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js
+++ b/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js
@@ -7,6 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule TabBarItemIOS
+ * @noflow
  */
 'use strict';
 
diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js
index e7416e833bf0..e7049d2e07d9 100644
--- a/Libraries/Components/TextInput/TextInput.js
+++ b/Libraries/Components/TextInput/TextInput.js
@@ -335,8 +335,12 @@ var TextInput = React.createClass({
    */
   mixins: [NativeMethodsMixin, TimerMixin],
 
-  viewConfig: ((Platform.OS === 'ios' ? RCTTextField.viewConfig :
-    (Platform.OS === 'android' ? AndroidTextInput.viewConfig : {})) : Object),
+  viewConfig:
+    ((Platform.OS === 'ios' && RCTTextField ?
+      RCTTextField.viewConfig :
+      (Platform.OS === 'android' && AndroidTextInput ?
+        AndroidTextInput.viewConfig :
+        {})) : Object),
 
   isFocused: function(): boolean {
     return TextInputState.currentlyFocusedField() ===
diff --git a/Libraries/Components/ToastAndroid/ToastAndroid.ios.js b/Libraries/Components/ToastAndroid/ToastAndroid.ios.js
index bf42aae640e8..087786e08937 100644
--- a/Libraries/Components/ToastAndroid/ToastAndroid.ios.js
+++ b/Libraries/Components/ToastAndroid/ToastAndroid.ios.js
@@ -7,6 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule ToastAndroid
+ * @noflow
  */
 'use strict';
 
diff --git a/Libraries/Components/Touchable/TouchableBounce.js b/Libraries/Components/Touchable/TouchableBounce.js
index 0b7d91152c76..d3c1696769e8 100644
--- a/Libraries/Components/Touchable/TouchableBounce.js
+++ b/Libraries/Components/Touchable/TouchableBounce.js
@@ -21,6 +21,7 @@ type Event = Object;
 
 type State = {
   animationID: ?number;
+  scale: Animated.Value;
 };
 
 var PRESS_RETENTION_OFFSET = {top: 20, left: 20, right: 20, bottom: 30};
diff --git a/Libraries/Components/Touchable/TouchableHighlight.js b/Libraries/Components/Touchable/TouchableHighlight.js
index b7dc706eb6a0..67c1e55a0b85 100644
--- a/Libraries/Components/Touchable/TouchableHighlight.js
+++ b/Libraries/Components/Touchable/TouchableHighlight.js
@@ -7,6 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule TouchableHighlight
+ * @noflow
  */
 'use strict';
 
diff --git a/Libraries/Components/Touchable/TouchableOpacity.js b/Libraries/Components/Touchable/TouchableOpacity.js
index 5d7d8f3fbb28..627dd1205bd6 100644
--- a/Libraries/Components/Touchable/TouchableOpacity.js
+++ b/Libraries/Components/Touchable/TouchableOpacity.js
@@ -7,6 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule TouchableOpacity
+ * @noflow
  */
 'use strict';
 
diff --git a/Libraries/CustomComponents/Navigator/Navigation/NavigationContext.js b/Libraries/CustomComponents/Navigator/Navigation/NavigationContext.js
index 5a0c35f37e07..6d17fe1256df 100644
--- a/Libraries/CustomComponents/Navigator/Navigation/NavigationContext.js
+++ b/Libraries/CustomComponents/Navigator/Navigation/NavigationContext.js
@@ -23,6 +23,7 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * @providesModule NavigationContext
+ * @noflow
  */
 'use strict';
 
diff --git a/Libraries/ReactIOS/renderApplication.ios.js b/Libraries/ReactIOS/renderApplication.ios.js
index 0b0f306d6be3..ad000f643051 100644
--- a/Libraries/ReactIOS/renderApplication.ios.js
+++ b/Libraries/ReactIOS/renderApplication.ios.js
@@ -7,6 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule renderApplication
+ * @noflow
  */
 
 'use strict';
diff --git a/Libraries/Storage/AsyncStorage.js b/Libraries/Storage/AsyncStorage.js
index c5be992e2aba..9135088f6163 100644
--- a/Libraries/Storage/AsyncStorage.js
+++ b/Libraries/Storage/AsyncStorage.js
@@ -7,6 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule AsyncStorage
+ * @noflow
  * @flow-weak
  */
 'use strict';
diff --git a/Libraries/Utilities/MatrixMath.js b/Libraries/Utilities/MatrixMath.js
index 23db73811f18..e248ba75dc87 100755
--- a/Libraries/Utilities/MatrixMath.js
+++ b/Libraries/Utilities/MatrixMath.js
@@ -2,6 +2,7 @@
  * Copyright 2004-present Facebook. All Rights Reserved.
  *
  * @providesModule MatrixMath
+ * @noflow
  */
 /* eslint-disable space-infix-ops */
 'use strict';
diff --git a/Libraries/vendor/emitter/EmitterSubscription.js b/Libraries/vendor/emitter/EmitterSubscription.js
index a4d52a802ee5..bbd1d414c431 100644
--- a/Libraries/vendor/emitter/EmitterSubscription.js
+++ b/Libraries/vendor/emitter/EmitterSubscription.js
@@ -13,6 +13,7 @@
  * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  *
  * @providesModule EmitterSubscription
+ * @noflow
  * @typechecks
  */
 'use strict';
diff --git a/Libraries/vendor/emitter/EventEmitter.js b/Libraries/vendor/emitter/EventEmitter.js
index cb3725ebb989..b5c14a66a7c7 100644
--- a/Libraries/vendor/emitter/EventEmitter.js
+++ b/Libraries/vendor/emitter/EventEmitter.js
@@ -7,6 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule EventEmitter
+ * @noflow
  * @typechecks
  */
 

From c11dce36e6488c77eb16c121ea7cfe497c26ff4a Mon Sep 17 00:00:00 2001
From: Gabe Levi <glevi@fb.com>
Date: Tue, 1 Dec 2015 19:10:06 -0800
Subject: [PATCH 0196/1411] Deploy 0.19.0

Reviewed By: mroch

Differential Revision: D2711202

fb-gh-sync-id: b889cc9fe13f676aa4e7a5672556174792ece365
---
 .flowconfig | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/.flowconfig b/.flowconfig
index 7f4891b33340..08acf4e61aeb 100644
--- a/.flowconfig
+++ b/.flowconfig
@@ -55,9 +55,9 @@ suppress_type=$FlowIssue
 suppress_type=$FlowFixMe
 suppress_type=$FixMe
 
-suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(1[0-8]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
-suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(1[0-8]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)? #[0-9]+
+suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
+suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)? #[0-9]+
 suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
 
 [version]
-0.18.1
+0.19.0

From 0571250521c6fc21c3112481f335daa7dea1b18b Mon Sep 17 00:00:00 2001
From: Wenjing Wang <wenjingw@fb.com>
Date: Tue, 1 Dec 2015 22:04:55 -0800
Subject: [PATCH 0197/1411] 8/n Fix warnings at startup

Summary:
public
- Add missing required `key` prop for array of child components

Reviewed By: zjj010104

Differential Revision: D2711271

fb-gh-sync-id: b9848abffd3c458cf45b1231be5eff0a5de805f1
---
 .../Navigator/NavigatorBreadcrumbNavigationBar.js | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js b/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js
index ccf28f1f9d1e..b142b18fbbae 100644
--- a/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js
+++ b/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js
@@ -205,7 +205,10 @@ var NavigatorBreadcrumbNavigationBar = React.createClass({
     var firstStyles = initStyle(index, navStatePresentedIndex(this.props.navState));
 
     var breadcrumbDescriptor = (
-      <View ref={'crumb_' + index} style={firstStyles.Crumb}>
+      <View
+        key={'crumb_' + index}
+        ref={'crumb_' + index}
+        style={firstStyles.Crumb}>
         <View ref={'icon_' + index} style={firstStyles.Icon}>
           {navBarRouteMapper.iconForRoute(route, this.props.navigator)}
         </View>
@@ -231,7 +234,10 @@ var NavigatorBreadcrumbNavigationBar = React.createClass({
     var firstStyles = initStyle(index, navStatePresentedIndex(this.props.navState));
 
     var titleDescriptor = (
-      <View ref={'title_' + index} style={firstStyles.Title}>
+      <View
+        key={'title_' + index}
+        ref={'title_' + index}
+        style={firstStyles.Title}>
         {titleContent}
       </View>
     );
@@ -253,7 +259,10 @@ var NavigatorBreadcrumbNavigationBar = React.createClass({
     }
     var firstStyles = initStyle(index, navStatePresentedIndex(this.props.navState));
     var rightButtonDescriptor = (
-      <View ref={'right_' + index} style={firstStyles.RightItem}>
+      <View
+        key={'right_' + index}
+        ref={'right_' + index}
+        style={firstStyles.RightItem}>
         {rightContent}
       </View>
     );

From 04187536d15d8946084aa24cda41dd5705028104 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Wed, 2 Dec 2015 01:27:56 -0800
Subject: [PATCH 0198/1411] Fixed threading bug in RCTNetworking

Summary:
public

When uploading images, RCTHTTPFormDataHelper was sometimes accessed on the wrong thread.

Reviewed By: helouree

Differential Revision: D2709186

fb-gh-sync-id: d0a14926927d1d41f602f78a9f6892dfbdfc6ff9
---
 Libraries/Network/RCTNetworking.m | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/Libraries/Network/RCTNetworking.m b/Libraries/Network/RCTNetworking.m
index 74b58972ccac..9afb0914ee80 100644
--- a/Libraries/Network/RCTNetworking.m
+++ b/Libraries/Network/RCTNetworking.m
@@ -59,6 +59,8 @@ @implementation RCTHTTPFormDataHelper
 - (RCTURLRequestCancellationBlock)process:(NSDictionaryArray *)formData
                                  callback:(RCTHTTPQueryResult)callback
 {
+  RCTAssertThread(_networker.methodQueue, @"process: must be called on method queue");
+
   if (formData.count == 0) {
     return callback(nil, nil);
   }
@@ -76,6 +78,8 @@ - (RCTURLRequestCancellationBlock)process:(NSDictionaryArray *)formData
 - (RCTURLRequestCancellationBlock)handleResult:(NSDictionary<NSString *, id> *)result
                                          error:(NSError *)error
 {
+  RCTAssertThread(_networker.methodQueue, @"handleResult: must be called on method queue");
+
   if (error) {
     return _callback(error, nil);
   }
@@ -256,7 +260,7 @@ - (BOOL)canHandleRequest:(NSURLRequest *)request
 - (RCTURLRequestCancellationBlock)processDataForHTTPQuery:(nullable NSDictionary<NSString *, id> *)query callback:
 (RCTURLRequestCancellationBlock (^)(NSError *error, NSDictionary<NSString *, id> *result))callback
 {
-  RCTAssertThread(_methodQueue, @"processData: must be called on method queue");
+  RCTAssertThread(_methodQueue, @"processDataForHTTPQuery: must be called on method queue");
 
   if (!query) {
     return callback(nil, nil);
@@ -270,7 +274,9 @@ - (RCTURLRequestCancellationBlock)processDataForHTTPQuery:(nullable NSDictionary
 
     __block RCTURLRequestCancellationBlock cancellationBlock = nil;
     RCTNetworkTask *task = [self networkTaskWithRequest:request completionBlock:^(NSURLResponse *response, NSData *data, NSError *error) {
-      cancellationBlock = callback(error, data ? @{@"body": data, @"contentType": RCTNullIfNil(response.MIMEType)} : nil);
+      dispatch_async(_methodQueue, ^{
+        cancellationBlock = callback(error, data ? @{@"body": data, @"contentType": RCTNullIfNil(response.MIMEType)} : nil);
+      });
     }];
 
     [task start];

From 5dc40afbf681839947cbab691a9f4d2d1ccb7bc0 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Wed, 2 Dec 2015 03:10:42 -0800
Subject: [PATCH 0199/1411] Add for-of transform to babel configurations

Summary:
Adds babel-plugin-transform-es2015-for-of to babel configuration.

public

Reviewed By: tadeuzagallo

Differential Revision: D2712220

fb-gh-sync-id: cc6dd9e6e70946607ef9bb9f659eb628cf2eb555
---
 package.json                     | 1 +
 packager/react-packager/.babelrc | 3 ++-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 5be50c910962..d2249d02e799 100644
--- a/package.json
+++ b/package.json
@@ -69,6 +69,7 @@
     "babel-plugin-transform-es2015-computed-properties": "^6.0.14",
     "babel-plugin-transform-es2015-constants": "^6.0.15",
     "babel-plugin-transform-es2015-destructuring": "^6.0.18",
+    "babel-plugin-transform-es2015-for-of": "^6.0.14",
     "babel-plugin-transform-es2015-modules-commonjs": "^6.1.3",
     "babel-plugin-transform-es2015-parameters": "^6.0.18",
     "babel-plugin-transform-es2015-shorthand-properties": "^6.0.14",
diff --git a/packager/react-packager/.babelrc b/packager/react-packager/.babelrc
index c72259dac08c..e1c61b11f7df 100644
--- a/packager/react-packager/.babelrc
+++ b/packager/react-packager/.babelrc
@@ -23,7 +23,8 @@
     "transform-object-rest-spread",
     "transform-react-display-name",
     "transform-react-jsx",
-    "transform-regenerator"
+    "transform-regenerator",
+    "transform-es2015-for-of"
   ],
   "sourceMaps": false
 }

From 873efa2e972169c6b787158d31b63617888f2a75 Mon Sep 17 00:00:00 2001
From: sercanov <srcn.dmrcn@gmail.com>
Date: Wed, 2 Dec 2015 14:27:18 +0200
Subject: [PATCH 0200/1411] added Mobabuild app

---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 439ec56c9d7e..fe6e00741c31 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -392,6 +392,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/yazboz-batak-esli-batak-okey/id1048620855?ls=1&mt=8',
     author: 'Melih Mucuk',
   },
+  {
+    name: 'Mobabuild',
+    icon: 'http://mobabuild.co/images/applogo.png',
+    link: 'http://mobabuild.co',
+    author: 'Sercan Demircan ( @sercanov )',
+  },
 ];
 
 var AppList = React.createClass({

From edb26072c397180840de54738235f064402ad75c Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Wed, 2 Dec 2015 20:31:05 +0800
Subject: [PATCH 0201/1411] add git requirement and note for environment
 variables

---
 docs/DevelopmentSetupAndroid.md | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/docs/DevelopmentSetupAndroid.md b/docs/DevelopmentSetupAndroid.md
index 6a7b7d87f3c6..e7d1f8b36ac2 100644
--- a/docs/DevelopmentSetupAndroid.md
+++ b/docs/DevelopmentSetupAndroid.md
@@ -7,8 +7,18 @@ permalink: docs/android-setup.html
 next: linux-windows-support
 ---
 
-This guide describes basic steps of the Android development environment setup that are required to run React Native android apps on an android emulator. We don't discuss developer tool configuration such as IDEs here.
+This guide describes basic steps of the Android development environment setup that are required to run React Native android apps on an android emulator. We don't discuss developer tool configuration such as IDEs here.  
 
+### Install Git
+
+  - **On Mac**, if you have installed [XCode](https://developer.apple.com/xcode/), Git is already installed, otherwise run the following:
+
+         brew install git
+
+  - **On Linux**, install Git [via your package manager](https://git-scm.com/download/linux).
+
+  - **On Windows**, download and install [Git for Windows](https://git-for-windows.github.io/). During the setup process, choose "Run Git from Windows Command Prompt", which will add Git to your `PATH` environment variable.  
+  
 ### Install the Android SDK (unless you have it)
 
 1. [Install the latest JDK](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
@@ -28,7 +38,10 @@ __IMPORTANT__: Make sure the `ANDROID_HOME` environment variable points to your
         
         export ANDROID_HOME=<path_where_you_unpacked_android_sdk>
 
-  - **On Windows**, go to `Control Panel` -> `System and Security` -> `System` -> `Change settings` -> `Advanced` -> `Environment variables` -> `New`
+  - **On Windows**, go to `Control Panel` -> `System and Security` -> `System` -> `Change settings` -> `Advanced` -> `Environment variables` -> `New`   
+   
+__NOTE__: You need to restart the Command Prompt (Windows) / Terminal Emulator (Mac OS X, Linux) to apply the new Environment variables.
+
 
 ### Use gradle daemon
 

From 7e4c8b2d2d2b27ecfc96a5594ae162f939a4f4f1 Mon Sep 17 00:00:00 2001
From: sercanov <srcn.dmrcn@gmail.com>
Date: Wed, 2 Dec 2015 14:43:01 +0200
Subject: [PATCH 0202/1411] sorted alphabetically

---
 website/src/react-native/showcase.js | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index fe6e00741c31..89b74d7033f2 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -248,6 +248,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/mintrain/id1015739031?mt=8',
     author: 'Peter Cottle',
   },
+  {
+    name: 'Mobabuild',
+    icon: 'http://mobabuild.co/images/applogo.png',
+    link: 'http://mobabuild.co',
+    author: 'Sercan Demircan ( @sercanov )',
+  },
   {
     name: 'MockingBot',
     icon: 'https://s3.cn-north-1.amazonaws.com.cn/modao/downloads/images/MockingBot175.png',
@@ -392,12 +398,6 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/yazboz-batak-esli-batak-okey/id1048620855?ls=1&mt=8',
     author: 'Melih Mucuk',
   },
-  {
-    name: 'Mobabuild',
-    icon: 'http://mobabuild.co/images/applogo.png',
-    link: 'http://mobabuild.co',
-    author: 'Sercan Demircan ( @sercanov )',
-  },
 ];
 
 var AppList = React.createClass({

From 802aef95097ce76a452fb70086a38075ca37c9ae Mon Sep 17 00:00:00 2001
From: Christopher Dro <hello@blick-labs.com>
Date: Wed, 2 Dec 2015 05:53:38 -0800
Subject: [PATCH 0203/1411] Update argument passed for assetRoots.

Summary:
Fixes #4388
Closes https://github.com/facebook/react-native/pull/4431

Reviewed By: svcscm

Differential Revision: D2704076

Pulled By: mkonicek

fb-gh-sync-id: 2b788eb15787334bf7309fde730566092ff63832
---
 local-cli/server/server.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/local-cli/server/server.js b/local-cli/server/server.js
index 0648d937c2de..3abffb5beef4 100644
--- a/local-cli/server/server.js
+++ b/local-cli/server/server.js
@@ -79,7 +79,7 @@ function _server(argv, config, resolve, reject) {
   }
 
   args.assetRoots = args.assetRoots
-    ? argToArray(args.projectRoots).map(dir =>
+    ? argToArray(args.assetRoots).map(dir =>
       path.resolve(process.cwd(), dir)
     )
     : config.getAssetRoots();

From c25c98c00c8c195f85c9fb17eae3cb0c36b465f5 Mon Sep 17 00:00:00 2001
From: Justin Spahr-Summers <jspahrsummers@fb.com>
Date: Wed, 2 Dec 2015 05:12:17 -0800
Subject: [PATCH 0204/1411] Flush UI blocks as soon as they're accumulated

Summary:
public

Currently, we wait to invoke `-flushUIBlocks` until the JavaScript batch to native has completed. This means we may be waiting an unnecessarily long time to perform view hierarchy changes and prop changes.

By instead invoking this after each chunk of enqueued UI blocks, we can perform some updates more eagerly, increasing our utilization of the main thread while splitting up the amount of time we spend running upon it.

This shouldn't affect layout, which is still tied to `-batchDidComplete`, so any visual inconsistencies should be limited to prop changes, which seems acceptable for the dramatic improvement in performance.

Reviewed By: javache

Differential Revision: D2658552

fb-gh-sync-id: 6d4560e21d7da1b02d2f30d1860d60735f11c4b5
---
 React/Base/RCTBatchedBridge.m | 12 ++++++++++++
 React/Base/RCTBridgeModule.h  |  8 ++++++++
 React/Modules/RCTUIManager.h  | 11 +++++++++++
 React/Modules/RCTUIManager.m  |  7 +++++++
 4 files changed, 38 insertions(+)

diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index 8923d85ef6a7..bbb8fe24a465 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -720,6 +720,7 @@ - (void)handleBuffer:(id)buffer batchEnded:(BOOL)batchEnded
   if (buffer != nil && buffer != (id)kCFNull) {
     _wasBatchActive = YES;
     [self handleBuffer:buffer];
+    [self partialBatchDidFlush];
   }
 
   if (batchEnded) {
@@ -800,6 +801,17 @@ - (void)handleBuffer:(NSArray<NSArray *> *)buffer
   }
 }
 
+- (void)partialBatchDidFlush
+{
+  for (RCTModuleData *moduleData in _moduleDataByID) {
+    if (moduleData.hasInstance && [moduleData.instance respondsToSelector:@selector(partialBatchDidFlush)]) {
+      [self dispatchBlock:^{
+        [moduleData.instance partialBatchDidFlush];
+      } queue:moduleData.methodQueue];
+    }
+  }
+}
+
 - (void)batchDidComplete
 {
   // TODO: batchDidComplete is only used by RCTUIManager - can we eliminate this special case?
diff --git a/React/Base/RCTBridgeModule.h b/React/Base/RCTBridgeModule.h
index 436b26c80bd0..dd6dda34cf18 100644
--- a/React/Base/RCTBridgeModule.h
+++ b/React/Base/RCTBridgeModule.h
@@ -235,4 +235,12 @@ RCT_EXTERN void RCTRegisterModule(Class); \
  */
 - (void)batchDidComplete;
 
+/**
+ * Notifies the module that the active batch of JS method invocations has been
+ * partially flushed.
+ *
+ * This occurs before -batchDidComplete, and more frequently.
+ */
+- (void)partialBatchDidFlush;
+
 @end
diff --git a/React/Modules/RCTUIManager.h b/React/Modules/RCTUIManager.h
index daaf40ac2e91..dc0bcd9d985b 100644
--- a/React/Modules/RCTUIManager.h
+++ b/React/Modules/RCTUIManager.h
@@ -77,6 +77,17 @@ RCT_EXTERN NSString *const RCTUIManagerRootViewKey;
  */
 + (UIView *)JSResponder;
 
+/**
+ * Normally, UI changes are not applied until the complete batch of method
+ * invocations from JavaScript to native has completed.
+ *
+ * Setting this to YES will flush UI changes sooner, which could potentially
+ * result in inconsistent UI updates.
+ *
+ * The default is NO (recommended).
+ */
+@property (atomic, assign) BOOL unsafeFlushUIChangesBeforeBatchEnds;
+
 @end
 
 /**
diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m
index e4f569e5e1bf..c3c1ea58917b 100644
--- a/React/Modules/RCTUIManager.m
+++ b/React/Modules/RCTUIManager.m
@@ -880,6 +880,13 @@ - (void)_manageChildren:(NSNumber *)containerReactTag
   }];
 }
 
+- (void)partialBatchDidFlush
+{
+  if (self.unsafeFlushUIChangesBeforeBatchEnds) {
+    [self flushUIBlocks];
+  }
+}
+
 - (void)batchDidComplete
 {
   // Gather blocks to be executed now that all view hierarchy manipulations have

From 30a5eb51f8efea5cb5ccc75edbefc9575eadba3b Mon Sep 17 00:00:00 2001
From: Alexander Blom <blom@fb.com>
Date: Wed, 2 Dec 2015 05:30:33 -0800
Subject: [PATCH 0205/1411] Generate module definition on demand

Reviewed By: astreet

Differential Revision: D2707977

fb-gh-sync-id: fb2baa464a23df82e8b48a91a84c98370517d311
---
 .../react/bridge/CatalystInstanceImpl.java    |  5 +-
 .../react/bridge/JavaScriptModulesConfig.java | 23 ++---
 .../react/bridge/NativeModuleRegistry.java    | 84 ++++++++-----------
 3 files changed, 44 insertions(+), 68 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
index 08f5a702100b..6929ea3d7e75 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
@@ -361,16 +361,15 @@ public void stopProfiler(String title, String filename) {
   private String buildModulesConfigJSONProperty(
       NativeModuleRegistry nativeModuleRegistry,
       JavaScriptModulesConfig jsModulesConfig) {
-    // TODO(5300733): Serialize config using single json generator
     JsonFactory jsonFactory = new JsonFactory();
     StringWriter writer = new StringWriter();
     try {
       JsonGenerator jg = jsonFactory.createGenerator(writer);
       jg.writeStartObject();
       jg.writeFieldName("remoteModuleConfig");
-      jg.writeRawValue(nativeModuleRegistry.moduleDescriptions());
+      nativeModuleRegistry.writeModuleDescriptions(jg);
       jg.writeFieldName("localModulesConfig");
-      jg.writeRawValue(jsModulesConfig.moduleDescriptions());
+      jsModulesConfig.writeModuleDescriptions(jg);
       jg.writeEndObject();
       jg.close();
     } catch (IOException ioe) {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModulesConfig.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModulesConfig.java
index bc75da277911..abeba7230c2f 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModulesConfig.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModulesConfig.java
@@ -10,12 +10,10 @@
 package com.facebook.react.bridge;
 
 import java.io.IOException;
-import java.io.StringWriter;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
 
-import com.fasterxml.jackson.core.JsonFactory;
 import com.fasterxml.jackson.core.JsonGenerator;
 
 /**
@@ -33,23 +31,14 @@ private JavaScriptModulesConfig(List<JavaScriptModuleRegistration> modules) {
     return mModules;
   }
 
-  /*package*/ String moduleDescriptions() {
-    JsonFactory jsonFactory = new JsonFactory();
-    StringWriter writer = new StringWriter();
-    try {
-      JsonGenerator jg = jsonFactory.createGenerator(writer);
-      jg.writeStartObject();
-      for (JavaScriptModuleRegistration registration : mModules) {
-        jg.writeObjectFieldStart(registration.getName());
-        appendJSModuleToJSONObject(jg, registration);
-        jg.writeEndObject();
-      }
+  /*package*/ void writeModuleDescriptions(JsonGenerator jg) throws IOException {
+    jg.writeStartObject();
+    for (JavaScriptModuleRegistration registration : mModules) {
+      jg.writeObjectFieldStart(registration.getName());
+      appendJSModuleToJSONObject(jg, registration);
       jg.writeEndObject();
-      jg.close();
-    } catch (IOException ioe) {
-      throw new RuntimeException("Unable to serialize JavaScript module declaration", ioe);
     }
-    return writer.getBuffer().toString();
+    jg.writeEndObject();
   }
 
   private void appendJSModuleToJSONObject(
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java
index 50bdd69bbe2d..389fd66b4616 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java
@@ -10,17 +10,16 @@
 package com.facebook.react.bridge;
 
 import java.io.IOException;
-import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import com.facebook.react.common.MapBuilder;
 import com.facebook.infer.annotation.Assertions;
 import com.facebook.systrace.Systrace;
 
-import com.fasterxml.jackson.core.JsonFactory;
 import com.fasterxml.jackson.core.JsonGenerator;
 
 /**
@@ -28,18 +27,15 @@
   */
 public class NativeModuleRegistry {
 
-  private final ArrayList<ModuleDefinition> mModuleTable;
+  private final List<ModuleDefinition> mModuleTable;
   private final Map<Class<? extends NativeModule>, NativeModule> mModuleInstances;
-  private final String mModuleDescriptions;
   private final ArrayList<OnBatchCompleteListener> mBatchCompleteListenerModules;
 
   private NativeModuleRegistry(
-      ArrayList<ModuleDefinition> moduleTable,
-      Map<Class<? extends NativeModule>, NativeModule> moduleInstances,
-      String moduleDescriptions) {
+      List<ModuleDefinition> moduleTable,
+      Map<Class<? extends NativeModule>, NativeModule> moduleInstances) {
     mModuleTable = moduleTable;
     mModuleInstances = moduleInstances;
-    mModuleDescriptions = moduleDescriptions;
 
     mBatchCompleteListenerModules = new ArrayList<OnBatchCompleteListener>(mModuleTable.size());
     for (int i = 0; i < mModuleTable.size(); i++) {
@@ -62,8 +58,29 @@ private NativeModuleRegistry(
     definition.call(catalystInstance, methodId, parameters);
   }
 
-  /* package */ String moduleDescriptions() {
-    return mModuleDescriptions;
+  /* package */ void writeModuleDescriptions(JsonGenerator jg) throws IOException {
+    Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "CreateJSON");
+    try {
+      jg.writeStartObject();
+      for (ModuleDefinition moduleDef : mModuleTable) {
+        jg.writeObjectFieldStart(moduleDef.name);
+        jg.writeNumberField("moduleID", moduleDef.id);
+        jg.writeObjectFieldStart("methods");
+        for (int i = 0; i < moduleDef.methods.size(); i++) {
+          MethodRegistration method = moduleDef.methods.get(i);
+          jg.writeObjectFieldStart(method.name);
+          jg.writeNumberField("methodID", i);
+          jg.writeStringField("type", method.method.getType());
+          jg.writeEndObject();
+        }
+        jg.writeEndObject();
+        moduleDef.target.writeConstantsField(jg, "constants");
+        jg.writeEndObject();
+      }
+      jg.writeEndObject();
+    } finally {
+      Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+    }
   }
 
   /* package */ void notifyCatalystInstanceDestroy() {
@@ -174,45 +191,16 @@ public Builder add(NativeModule module) {
     }
 
     public NativeModuleRegistry build() {
-      Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "CreateJSON");
-      ArrayList<ModuleDefinition> moduleTable = new ArrayList<>();
-      Map<Class<? extends NativeModule>, NativeModule> moduleInstances = MapBuilder.newHashMap();
-      String moduleDefinitionJson;
-      try {
-        JsonFactory jsonFactory = new JsonFactory();
-        StringWriter writer = new StringWriter();
-        try {
-          JsonGenerator jg = jsonFactory.createGenerator(writer);
-          jg.writeStartObject();
-          int idx = 0;
-          for (NativeModule module : mModules.values()) {
-            ModuleDefinition moduleDef = new ModuleDefinition(idx++, module.getName(), module);
-            moduleTable.add(moduleDef);
-            moduleInstances.put(module.getClass(), module);
-            jg.writeObjectFieldStart(moduleDef.name);
-            jg.writeNumberField("moduleID", moduleDef.id);
-            jg.writeObjectFieldStart("methods");
-            for (int i = 0; i < moduleDef.methods.size(); i++) {
-              MethodRegistration method = moduleDef.methods.get(i);
-              jg.writeObjectFieldStart(method.name);
-              jg.writeNumberField("methodID", i);
-              jg.writeStringField("type", method.method.getType());
-              jg.writeEndObject();
-            }
-            jg.writeEndObject();
-            moduleDef.target.writeConstantsField(jg, "constants");
-            jg.writeEndObject();
-          }
-          jg.writeEndObject();
-          jg.close();
-        } catch (IOException ioe) {
-          throw new RuntimeException("Unable to serialize Java module configuration", ioe);
-        }
-        moduleDefinitionJson = writer.getBuffer().toString();
-      } finally {
-        Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+      List<ModuleDefinition> moduleTable = new ArrayList<>();
+      Map<Class<? extends NativeModule>, NativeModule> moduleInstances = new HashMap<>();
+
+      int idx = 0;
+      for (NativeModule module : mModules.values()) {
+        ModuleDefinition moduleDef = new ModuleDefinition(idx++, module.getName(), module);
+        moduleTable.add(moduleDef);
+        moduleInstances.put(module.getClass(), module);
       }
-      return new NativeModuleRegistry(moduleTable, moduleInstances, moduleDefinitionJson);
+      return new NativeModuleRegistry(moduleTable, moduleInstances);
     }
   }
 }

From f69ac1eaefd35821623f68622fa2f1e10921f725 Mon Sep 17 00:00:00 2001
From: Alon Schwarz <alonsch@fb.com>
Date: Wed, 2 Dec 2015 05:50:34 -0800
Subject: [PATCH 0206/1411] Revert D2679408 (Only send layout update operation
 to nativehierarchymanager when layout actually changes)

Reviewed By: andreicoman11

Differential Revision: D2712224

fb-gh-sync-id: e6aebe6fcf54e9f36cac092cab801bb97a65dbfd
---
 .../react/uimanager/ReactShadowNode.java      | 38 ++++++-------------
 .../react/uimanager/UIImplementation.java     | 14 ++++++-
 2 files changed, 23 insertions(+), 29 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java
index bbf33b7b2ed2..73134194fb1b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java
@@ -18,7 +18,6 @@
 import com.facebook.infer.annotation.Assertions;
 import com.facebook.react.bridge.ReadableMap;
 import com.facebook.react.bridge.ReadableMapKeySetIterator;
-import com.facebook.react.uimanager.events.EventDispatcher;
 
 /**
  * Base node class for representing virtual tree of React nodes. Shadow nodes are used primarily
@@ -203,37 +202,18 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
       float absoluteX,
       float absoluteY,
       UIViewOperationQueue uiViewOperationQueue,
-      NativeViewHierarchyOptimizer nativeViewHierarchyOptimizer,
-      EventDispatcher eventDispatcher) {
+      NativeViewHierarchyOptimizer nativeViewHierarchyOptimizer) {
     if (mNodeUpdated) {
       onCollectExtraUpdates(uiViewOperationQueue);
     }
 
     if (hasNewLayout()) {
-      float absoluteLeft = Math.round(absoluteX + getLayoutX());
-      float absoluteTop = Math.round(absoluteY + getLayoutY());
-      float absoluteRight = Math.round(absoluteX + getLayoutX() + getLayoutWidth());
-      float absoluteBottom = Math.round(absoluteY + getLayoutY() + getLayoutHeight());
-      // If the layout didn't change this should calculate exactly same values, it's fine to compare
-      // floats with "==" in this case
-      if (absoluteLeft != mAbsoluteLeft || absoluteTop != mAbsoluteTop ||
-          absoluteRight != mAbsoluteRight || absoluteBottom != mAbsoluteBottom) {
-        mAbsoluteLeft = absoluteLeft;
-        mAbsoluteTop = absoluteTop;
-        mAbsoluteRight = absoluteRight;
-        mAbsoluteBottom = absoluteBottom;
-
-        nativeViewHierarchyOptimizer.handleUpdateLayout(this);
-        if (mShouldNotifyOnLayout) {
-          eventDispatcher.dispatchEvent(
-              OnLayoutEvent.obtain(
-                  getReactTag(),
-                  getScreenX(),
-                  getScreenY(),
-                  getScreenWidth(),
-                  getScreenHeight()));
-        }
-      }
+      mAbsoluteLeft = Math.round(absoluteX + getLayoutX());
+      mAbsoluteTop = Math.round(absoluteY + getLayoutY());
+      mAbsoluteRight = Math.round(absoluteX + getLayoutX() + getLayoutWidth());
+      mAbsoluteBottom = Math.round(absoluteY + getLayoutY() + getLayoutHeight());
+
+      nativeViewHierarchyOptimizer.handleUpdateLayout(this);
     }
   }
 
@@ -284,6 +264,10 @@ public void setShouldNotifyOnLayout(boolean shouldNotifyOnLayout) {
     mShouldNotifyOnLayout = shouldNotifyOnLayout;
   }
 
+  /* package */ boolean shouldNotifyOnLayout() {
+    return mShouldNotifyOnLayout;
+  }
+
   /**
    * Adds a child that the native view hierarchy will have at this index in the native view
    * corresponding to this node.
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
index aef2ebc29317..633c8dd43c9d 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
@@ -698,8 +698,18 @@ protected void applyUpdatesRecursive(
           absoluteX,
           absoluteY,
           mOperationsQueue,
-          mNativeViewHierarchyOptimizer,
-          eventDispatcher);
+          mNativeViewHierarchyOptimizer);
+      
+      // notify JS about layout event if requested
+      if (cssNode.shouldNotifyOnLayout()) {
+        eventDispatcher.dispatchEvent(
+            OnLayoutEvent.obtain(
+                tag,
+                cssNode.getScreenX(),
+                cssNode.getScreenY(),
+                cssNode.getScreenWidth(),
+                cssNode.getScreenHeight()));
+      }
     }
     cssNode.markUpdateSeen();
   }

From 807e0d931097042c581d11b64d047e0dd338f9e2 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Wed, 2 Dec 2015 07:08:29 -0800
Subject: [PATCH 0207/1411] Fixed Xcode warnings

Summary:
public

Fixed some Xcode warnings, and added some missing UIResponder methods to make the behavior of RCTTextView more self-consistent.

Reviewed By: javache

Differential Revision: D2712250

fb-gh-sync-id: d30038500194d7a5262d9e77d516c65d836a4420
---
 Libraries/Text/RCTTextField.m | 10 +++++-----
 Libraries/Text/RCTTextView.m  | 12 +++++++++++-
 React/Views/RCTShadowView.m   |  2 +-
 3 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/Libraries/Text/RCTTextField.m b/Libraries/Text/RCTTextField.m
index de4fd867bd35..8a2bbb5a67c4 100644
--- a/Libraries/Text/RCTTextField.m
+++ b/Libraries/Text/RCTTextField.m
@@ -239,6 +239,11 @@ - (void)sendSelectionEvent
   }
 }
 
+- (BOOL)canBecomeFirstResponder
+{
+  return _jsRequestingFirstResponder;
+}
+
 - (void)reactWillMakeFirstResponder
 {
   _jsRequestingFirstResponder = YES;
@@ -249,11 +254,6 @@ - (void)reactDidMakeFirstResponder
   _jsRequestingFirstResponder = NO;
 }
 
-- (BOOL)canBecomeFirstResponder
-{
-  return _jsRequestingFirstResponder;
-}
-
 - (BOOL)resignFirstResponder
 {
   BOOL result = [super resignFirstResponder];
diff --git a/Libraries/Text/RCTTextView.m b/Libraries/Text/RCTTextView.m
index 34f3b74970f0..e7cf180d4976 100644
--- a/Libraries/Text/RCTTextView.m
+++ b/Libraries/Text/RCTTextView.m
@@ -410,6 +410,16 @@ - (void)textViewDidEndEditing:(UITextView *)textView
                                eventCount:_nativeEventCount];
 }
 
+- (BOOL)isFirstResponder
+{
+  return [_textView isFirstResponder];
+}
+
+- (BOOL)canBecomeFirstResponder
+{
+  return [_textView canBecomeFirstResponder];
+}
+
 - (void)reactWillMakeFirstResponder
 {
   [_textView reactWillMakeFirstResponder];
@@ -427,7 +437,7 @@ - (void)reactDidMakeFirstResponder
 
 - (BOOL)resignFirstResponder
 {
-  return [_textView resignFirstResponder];
+  return [super resignFirstResponder] && [_textView resignFirstResponder];
 }
 
 - (void)layoutSubviews
diff --git a/React/Views/RCTShadowView.m b/React/Views/RCTShadowView.m
index 75625fd7d3e0..f6c775f2ad75 100644
--- a/React/Views/RCTShadowView.m
+++ b/React/Views/RCTShadowView.m
@@ -580,7 +580,7 @@ - (void)setBackgroundColor:(UIColor *)color
   [self dirtyPropagation];
 }
 
-- (void)didSetProps:(NSArray<NSString *> *)changedProps
+- (void)didSetProps:(__unused NSArray<NSString *> *)changedProps
 {
   if (_recomputePadding) {
     RCTProcessMetaProps(_paddingMetaProps, _cssNode->style.padding);

From 37042573b82e1c56ffabf80a505de80dee12c553 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Wed, 2 Dec 2015 07:11:20 -0800
Subject: [PATCH 0208/1411] Added blurOnSubmit support to multine TextInput
 (aka RCTTextView)

Summary:
public

Setting `blurOnSubmit=true` on a multiline `<TextInput>` now causes it to behave like a single-line input with respect to the return key:

With the default value of `false`, pressing return will enter a newline character into the field. If you set the value to `true`, pressing return will now blur the field and trigger the onSubmitEditing event. The newline character will *not* be added to the text.

(See associated github task for dicussion: https://github.com/facebook/react-native/pull/2149)

Reviewed By: javache

Differential Revision: D2710448

fb-gh-sync-id: c9706ae11f8b399932d3400ceb4c7558e455570d
---
 Examples/UIExplorer/TextInputExample.ios.js | 17 +++++++++++++
 Libraries/Components/TextInput/TextInput.js | 28 ++++-----------------
 Libraries/Text/RCTTextField.m               |  1 +
 Libraries/Text/RCTTextView.h                |  1 +
 Libraries/Text/RCTTextView.m                | 25 ++++++++++++++++++
 Libraries/Text/RCTTextViewManager.m         |  1 +
 6 files changed, 50 insertions(+), 23 deletions(-)

diff --git a/Examples/UIExplorer/TextInputExample.ios.js b/Examples/UIExplorer/TextInputExample.ios.js
index 826139048cb5..9efde2ea0aeb 100644
--- a/Examples/UIExplorer/TextInputExample.ios.js
+++ b/Examples/UIExplorer/TextInputExample.ios.js
@@ -548,6 +548,23 @@ exports.examples = [
     title: 'Blur on submit',
     render: function(): ReactElement { return <BlurOnSubmitExample />; },
   },
+  {
+    title: 'Multiline blur on submit',
+    render: function() {
+      return (
+        <View>
+          <TextInput
+            style={styles.multiline}
+            placeholder='blurOnSubmit = true'
+            returnKeyType='next'
+            blurOnSubmit={true}
+            multiline={true}
+            onSubmitEditing={event => alert(event.nativeEvent.text)}
+          />
+        </View>
+      );
+    }
+  },
   {
     title: 'Multiline',
     render: function() {
diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js
index e7049d2e07d9..9f8f44ed75e9 100644
--- a/Libraries/Components/TextInput/TextInput.js
+++ b/Libraries/Components/TextInput/TextInput.js
@@ -37,7 +37,7 @@ var onlyMultiline = {
 };
 
 var notMultiline = {
-  onSubmitEditing: true,
+  // nothing yet
 };
 
 if (Platform.OS === 'android') {
@@ -47,10 +47,6 @@ if (Platform.OS === 'android') {
   var RCTTextField = requireNativeComponent('RCTTextField', null);
 }
 
-type DefaultProps = {
-  blurOnSubmit: boolean;
-};
-
 type Event = Object;
 
 /**
@@ -73,17 +69,6 @@ type Event = Object;
  * ```
  *
  * Note that some props are only available with `multiline={true/false}`:
- * ```
- *   var onlyMultiline = {
- *     onSelectionChange: true, // not supported in Open Source yet
- *     onTextInput: true, // not supported in Open Source yet
- *     children: true,
- *   };
- *
- *   var notMultiline = {
- *     onSubmitEditing: true,
- *   };
- * ```
  */
 var TextInput = React.createClass({
   statics: {
@@ -304,7 +289,10 @@ var TextInput = React.createClass({
     selectTextOnFocus: PropTypes.bool,
     /**
      * If true, the text field will blur when submitted.
-     * The default value is true.
+     * The default value is true for single-line fields and false for
+     * multiline fields. Note that for multiline fields, setting blurOnSubmit
+     * to true means that pressing return will blur the field and trigger the
+     * onSubmitEditing event instead of inserting a newline into the field.
      * @platform ios
      */
     blurOnSubmit: PropTypes.bool,
@@ -323,12 +311,6 @@ var TextInput = React.createClass({
     underlineColorAndroid: PropTypes.string,
   },
 
-  getDefaultProps: function(): DefaultProps {
-    return {
-      blurOnSubmit: true,
-    };
-  },
-
   /**
    * `NativeMethodsMixin` will look for this when invoking `setNativeProps`. We
    * make `this` look like an actual native component class.
diff --git a/Libraries/Text/RCTTextField.m b/Libraries/Text/RCTTextField.m
index 8a2bbb5a67c4..b8d172cc2894 100644
--- a/Libraries/Text/RCTTextField.m
+++ b/Libraries/Text/RCTTextField.m
@@ -36,6 +36,7 @@ - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
     [self addTarget:self action:@selector(textFieldSubmitEditing) forControlEvents:UIControlEventEditingDidEndOnExit];
     [self addObserver:self forKeyPath:@"selectedTextRange" options:0 context:nil];
     _reactSubviews = [NSMutableArray new];
+    _blurOnSubmit = YES;
   }
   return self;
 }
diff --git a/Libraries/Text/RCTTextView.h b/Libraries/Text/RCTTextView.h
index 9305442abe91..5279eafb6731 100644
--- a/Libraries/Text/RCTTextView.h
+++ b/Libraries/Text/RCTTextView.h
@@ -17,6 +17,7 @@
 @interface RCTTextView : RCTView <UITextViewDelegate>
 
 @property (nonatomic, assign) BOOL autoCorrect;
+@property (nonatomic, assign) BOOL blurOnSubmit;
 @property (nonatomic, assign) BOOL clearTextOnFocus;
 @property (nonatomic, assign) BOOL selectTextOnFocus;
 @property (nonatomic, assign) UIEdgeInsets contentInset;
diff --git a/Libraries/Text/RCTTextView.m b/Libraries/Text/RCTTextView.m
index e7cf180d4976..9a33f7e4696f 100644
--- a/Libraries/Text/RCTTextView.m
+++ b/Libraries/Text/RCTTextView.m
@@ -72,6 +72,7 @@ - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
     _contentInset = UIEdgeInsetsZero;
     _eventDispatcher = eventDispatcher;
     _placeholderTextColor = [self defaultPlaceholderTextColor];
+    _blurOnSubmit = NO;
 
     _textView = [[RCTUITextView alloc] initWithFrame:CGRectZero];
     _textView.backgroundColor = [UIColor clearColor];
@@ -276,11 +277,35 @@ - (BOOL)textView:(RCTUITextView *)textView shouldChangeTextInRange:(NSRange)rang
   if (textView.textWasPasted) {
     textView.textWasPasted = NO;
   } else {
+    
     [_eventDispatcher sendTextEventWithType:RCTTextEventTypeKeyPress
                                    reactTag:self.reactTag
                                        text:nil
                                         key:text
                                  eventCount:_nativeEventCount];
+
+    if (_blurOnSubmit && [text isEqualToString:@"\n"]) {
+
+      // TODO: the purpose of blurOnSubmit on RCTextField is to decide if the
+      // field should lose focus when return is pressed or not. We're cheating a
+      // bit here by using it on RCTextView to decide if return character should
+      // submit the form, or be entered into the field.
+      //
+      // The reason this is cheating is because there's no way to specify that
+      // you want the return key to be swallowed *and* have the field retain
+      // focus (which was what blurOnSubmit was originally for). For the case
+      // where _blurOnSubmit = YES, this is still the correct and expected
+      // behavior though, so we'll leave the don't-blur-or-add-newline problem
+      // to be solved another day.
+
+      [_eventDispatcher sendTextEventWithType:RCTTextEventTypeSubmit
+                                     reactTag:self.reactTag
+                                         text:self.text
+                                          key:nil
+                                   eventCount:_nativeEventCount];
+      [self resignFirstResponder];
+      return NO;
+    }
   }
 
   if (_maxLength == nil) {
diff --git a/Libraries/Text/RCTTextViewManager.m b/Libraries/Text/RCTTextViewManager.m
index 94ba4609c94a..f32369c4a3ce 100644
--- a/Libraries/Text/RCTTextViewManager.m
+++ b/Libraries/Text/RCTTextViewManager.m
@@ -25,6 +25,7 @@ - (UIView *)view
 
 RCT_REMAP_VIEW_PROPERTY(autoCapitalize, textView.autocapitalizationType, UITextAutocapitalizationType)
 RCT_EXPORT_VIEW_PROPERTY(autoCorrect, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(blurOnSubmit, BOOL)
 RCT_EXPORT_VIEW_PROPERTY(clearTextOnFocus, BOOL)
 RCT_REMAP_VIEW_PROPERTY(color, textView.textColor, UIColor)
 RCT_REMAP_VIEW_PROPERTY(editable, textView.editable, BOOL)

From 7424af6078159e83a83c61b64f7bc1cb2eb05259 Mon Sep 17 00:00:00 2001
From: mkonicek-pr-test <martinkonicek@centrum.cz>
Date: Wed, 2 Dec 2015 09:02:39 -0800
Subject: [PATCH 0209/1411] Test PR 6: Tweak colors in 2048 example

Summary:
Just testing the shipit bot
Closes https://github.com/facebook/react-native/pull/4503

Reviewed By: svcscm

Differential Revision: D2712738

Pulled By: androidtrunkagent

fb-gh-sync-id: 267f55991ca8267cb651734093bc62fb9c77a056
---
 Examples/2048/Game2048.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Examples/2048/Game2048.js b/Examples/2048/Game2048.js
index 90111d38b871..3bc49217b7a2 100644
--- a/Examples/2048/Game2048.js
+++ b/Examples/2048/Game2048.js
@@ -237,7 +237,7 @@ var styles = StyleSheet.create({
     marginBottom: 20,
   },
   tryAgain: {
-    backgroundColor: '#887766',
+    backgroundColor: '#887761',
     padding: 20,
     borderRadius: 5,
   },

From 7ab17e5ef30d9b2fc4d639972855bb8f2074ef7a Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Wed, 2 Dec 2015 09:05:39 -0800
Subject: [PATCH 0210/1411] Fix for long press state transition error in
 Touchable.js

Summary:
public

This diff fixes an occasional JS exception thrown by Touchable.js when it attempts to transitions to the RESPONDER_ACTIVE_LONG_PRESS_IN state from the RESPONDER_INACTIVE_PRESS_IN state.

Although I wasn't able to reproduce the error while testing, I was able to identify the likely cause: the LONG_PRESS_DETECTED state transition is triggered by a timer that is started on touch-down. This timer should be cancelled if the gesture is interrupted, however I identified a code path where the state can be changed to RESPONDER_INACTIVE_PRESS_IN without the longPressDelayTimeout being cancelled.

To fix this, I've added some logic to cancel the timer in that case. I've also added a test for the error scenario that will display a redbox in __DEV__ mode, but will fail gracefully in production mode.

Reviewed By: jingc

Differential Revision: D2709750

fb-gh-sync-id: aeea1a31de5e92eb394c2ea177f556b131d50790
---
 Libraries/Components/Touchable/Touchable.js | 24 ++++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/Libraries/Components/Touchable/Touchable.js b/Libraries/Components/Touchable/Touchable.js
index 0a2f554c43b0..0493311c5c2d 100644
--- a/Libraries/Components/Touchable/Touchable.js
+++ b/Libraries/Components/Touchable/Touchable.js
@@ -456,6 +456,11 @@ var TouchableMixin = {
           pressExpandBottom;
     if (isTouchWithinActive) {
       this._receiveSignal(Signals.ENTER_PRESS_RECT, e);
+      var curState = this.state.touchable.touchState;
+      if (curState === States.RESPONDER_INACTIVE_PRESS_IN) {
+        // fix for t7967420
+        this._cancelLongPressDelayTimeout();
+      }
     } else {
       this._cancelLongPressDelayTimeout();
       this._receiveSignal(Signals.LEAVE_PRESS_RECT, e);
@@ -564,7 +569,20 @@ var TouchableMixin = {
 
   _handleLongDelay: function(e) {
     this.longPressDelayTimeout = null;
-    this._receiveSignal(Signals.LONG_PRESS_DETECTED, e);
+    var curState = this.state.touchable.touchState;
+    if (curState !== States.RESPONDER_ACTIVE_PRESS_IN &&
+        curState !== States.RESPONDER_ACTIVE_LONG_PRESS_IN) {
+      if (__DEV__) {
+        throw new Error(
+          'Attempted to transition from state `' + curState + '` to `' +
+          States.RESPONDER_ACTIVE_LONG_PRESS_IN + '`, which is not supported. ' +
+          'This is most likely due to `Touchable.longPressDelayTimeout` not ' +
+          'being cancelled.'
+        );  
+      } 
+    } else {
+      this._receiveSignal(Signals.LONG_PRESS_DETECTED, e);
+    }
   },
 
   /**
@@ -577,13 +595,13 @@ var TouchableMixin = {
    */
   _receiveSignal: function(signal, e) {
     var curState = this.state.touchable.touchState;
-    if (!(Transitions[curState] && Transitions[curState][signal])) {
+    var nextState = Transitions[curState] && Transitions[curState][signal];
+    if (!nextState) {
       throw new Error(
         'Unrecognized signal `' + signal + '` or state `' + curState +
         '` for Touchable responder `' + this.state.touchable.responderID + '`'
       );
     }
-    var nextState = Transitions[curState][signal];
     if (nextState === States.ERROR) {
       throw new Error(
         'Touchable cannot transition from `' + curState + '` to `' + signal +

From c06efc0831b9156ee6261d7ddd2086ed87cbc0aa Mon Sep 17 00:00:00 2001
From: Felix Oghina <foghina@fb.com>
Date: Wed, 2 Dec 2015 09:10:28 -0800
Subject: [PATCH 0211/1411] remove activities from module constructors

Summary:
Refactor modules that take activities (or activities that implement some interface) as constructor args to not do that. Expose `getCurrentActivity()` in `ReactContext` and use that wherever the activity is needed.

public

Reviewed By: astreet

Differential Revision: D2680462

fb-gh-sync-id: f263b3fe5b422b7aab9fdadd051cef4e82797b0a
---
 .../facebook/react/ReactInstanceManager.java    | 17 +++++++++++++++++
 .../react/ReactInstanceManagerImpl.java         | 15 ++++++++++++++-
 .../com/facebook/react/bridge/ReactContext.java | 11 ++++++++++-
 .../bridge/ReactContextBaseJavaModule.java      | 17 +++++++++++++++++
 4 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
index 2449c28ea491..bdffdf261a53 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
@@ -47,6 +47,18 @@
  * have a static method, and so cannot (in Java < 8), be one.
  */
 public abstract class ReactInstanceManager {
+
+  /**
+   * Listener interface for react instance events.
+   */
+  public interface ReactInstanceEventListener {
+    /**
+     * Called when the react context is initialized (all modules registered). Always called on the
+     * UI thread.
+     */
+    void onReactContextInitialized(ReactContext context);
+  }
+
   public abstract DevSupportManager getDevSupportManager();
 
   /**
@@ -118,6 +130,11 @@ public abstract void onResume(
   public abstract List<ViewManager> createAllViewManagers(
     ReactApplicationContext catalystApplicationContext);
 
+  /**
+   * Add a listener to be notified of react instance events.
+   */
+  public abstract void addReactInstanceEventListener(ReactInstanceEventListener listener);
+
   @VisibleForTesting
   public abstract @Nullable ReactContext getCurrentReactContext();
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index c97a55b067fe..1eecb403269b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -12,10 +12,11 @@
 import javax.annotation.Nullable;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
+import java.util.concurrent.ConcurrentLinkedQueue;
 
 import android.app.Activity;
-import android.app.Application;
 import android.content.Context;
 import android.content.Intent;
 import android.os.AsyncTask;
@@ -95,6 +96,8 @@
   private @Nullable DefaultHardwareBackBtnHandler mDefaultBackButtonImpl;
   private String mSourceUrl;
   private @Nullable Activity mCurrentActivity;
+  private final Collection<ReactInstanceEventListener> mReactInstanceEventListeners =
+      new ConcurrentLinkedQueue<>();
   private volatile boolean mHasStartedCreatingInitialContext = false;
   private final UIImplementationProvider mUIImplementationProvider;
 
@@ -406,6 +409,7 @@ public void onDestroy() {
       mCurrentReactContext = null;
       mHasStartedCreatingInitialContext = false;
     }
+    mCurrentActivity = null;
   }
 
   @Override
@@ -482,6 +486,11 @@ public List<ViewManager> createAllViewManagers(
     }
   }
 
+  @Override
+  public void addReactInstanceEventListener(ReactInstanceEventListener listener) {
+    mReactInstanceEventListeners.add(listener);
+  }
+
   @VisibleForTesting
   @Override
   public @Nullable ReactContext getCurrentReactContext() {
@@ -535,6 +544,10 @@ private void setupReactContext(ReactApplicationContext reactContext) {
     for (ReactRootView rootView : mAttachedRootViews) {
       attachMeasuredRootViewToInstance(rootView, catalystInstance);
     }
+
+    for (ReactInstanceEventListener listener : mReactInstanceEventListeners) {
+      listener.onReactContextInitialized(reactContext);
+    }
   }
 
   private void attachMeasuredRootViewToInstance(
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java
index ca2d40c73434..e1632401f460 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java
@@ -146,7 +146,6 @@ public void onResume(@Nullable Activity activity) {
    */
   public void onPause() {
     UiThreadUtil.assertOnUiThread();
-    mCurrentActivity = null;
     for (LifecycleEventListener listener : mLifecycleEventListeners) {
       listener.onHostPause();
     }
@@ -163,6 +162,7 @@ public void onDestroy() {
     if (mCatalystInstance != null) {
       mCatalystInstance.destroy();
     }
+    mCurrentActivity = null;
   }
 
   /**
@@ -239,4 +239,13 @@ public boolean startActivityForResult(Intent intent, int code, Bundle bundle) {
     mCurrentActivity.startActivityForResult(intent, code, bundle);
     return true;
   }
+
+  /**
+   * Get the activity to which this context is currently attached, or {@code null} if not attached.
+   * DO NOT HOLD LONG-LIVED REFERENCES TO THE OBJECT RETURNED BY THIS METHOD, AS THIS WILL CAUSE
+   * MEMORY LEAKS.
+   */
+  /* package */ @Nullable Activity getCurrentActivity() {
+    return mCurrentActivity;
+  }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContextBaseJavaModule.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContextBaseJavaModule.java
index 4d0470f46b86..6a73f73ccb25 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContextBaseJavaModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContextBaseJavaModule.java
@@ -9,6 +9,10 @@
 
 package com.facebook.react.bridge;
 
+import javax.annotation.Nullable;
+
+import android.app.Activity;
+
 /**
  * Base class for Catalyst native modules that require access to the {@link ReactContext}
  * instance.
@@ -27,4 +31,17 @@ public ReactContextBaseJavaModule(ReactApplicationContext reactContext) {
   protected final ReactApplicationContext getReactApplicationContext() {
     return mReactApplicationContext;
   }
+
+  /**
+   * Get the activity to which this context is currently attached, or {@code null} if not attached.
+   *
+   * DO NOT HOLD LONG-LIVED REFERENCES TO THE OBJECT RETURNED BY THIS METHOD, AS THIS WILL CAUSE
+   * MEMORY LEAKS.
+   *
+   * For example, never store the value returned by this method in a member variable. Instead, call
+   * this method whenever you actually need the Activity and make sure to check for {@code null}.
+   */
+  protected @Nullable final Activity getCurrentActivity() {
+    return mReactApplicationContext.getCurrentActivity();
+  }
 }

From 6d29f710e1e22e9a6a605b0b64713d85313f074a Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Wed, 2 Dec 2015 09:33:50 -0800
Subject: [PATCH 0212/1411] Fixed TextInput on iOS 8 and earlier

Summary:
public

The scrolling fix I added to RCTTextView doesn't work on iOS 8 because the underlying UITextField doesn't resize correctly, which breaks text input functionality. This diff fixes it.

Reviewed By: tadeuzagallo

Differential Revision: D2712618

fb-gh-sync-id: 1d0282df3a16f1cb6ddf9d005d640738bb1b5659
---
 Libraries/Text/RCTTextView.m | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/Libraries/Text/RCTTextView.m b/Libraries/Text/RCTTextView.m
index 9a33f7e4696f..eda22a421e0c 100644
--- a/Libraries/Text/RCTTextView.m
+++ b/Libraries/Text/RCTTextView.m
@@ -201,10 +201,10 @@ - (void)updateFrames
 
 - (void)updateContentSize
 {
-  _textView.scrollEnabled = YES;
-  _scrollView.contentSize = _textView.contentSize;
-  _textView.frame = (CGRect){CGPointZero, _scrollView.contentSize};
-  _textView.scrollEnabled = NO;
+  CGSize size = (CGSize){_scrollView.frame.size.width, INFINITY};
+  size.height = [_textView sizeThatFits:size].height;
+  _scrollView.contentSize = size;
+  _textView.frame = (CGRect){CGPointZero, size};
 }
 
 - (void)updatePlaceholder
@@ -462,7 +462,8 @@ - (void)reactDidMakeFirstResponder
 
 - (BOOL)resignFirstResponder
 {
-  return [super resignFirstResponder] && [_textView resignFirstResponder];
+  [super resignFirstResponder];
+  return [_textView resignFirstResponder];
 }
 
 - (void)layoutSubviews

From 0779dd1e87f6c0c9481f4063e72aafe7805383c6 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Wed, 2 Dec 2015 10:50:09 -0800
Subject: [PATCH 0213/1411] Open source the Android NetInfo module

Reviewed By: mkonicek

Differential Revision: D2703432

fb-gh-sync-id: 4a85844f1734ec433df543c89f0fdd56fe5db13c
---
 Examples/UIExplorer/NetInfoExample.android.js | 158 ++++++++++++++++++
 ...etInfoExample.js => NetInfoExample.ios.js} |   0
 Examples/UIExplorer/UIExplorerList.android.js |   1 +
 Examples/UIExplorer/UIExplorerList.ios.js     |   2 +-
 .../android/app/src/main/AndroidManifest.xml  |   1 +
 Libraries/Network/NetInfo.js                  |  52 +++---
 Libraries/Network/RCTNetInfo.m                |   4 +-
 .../modules/netinfo/ConnectivityModule.java   | 154 +++++++++++++++++
 .../react/shell/MainReactPackage.java         |   2 +
 9 files changed, 347 insertions(+), 27 deletions(-)
 create mode 100644 Examples/UIExplorer/NetInfoExample.android.js
 rename Examples/UIExplorer/{NetInfoExample.js => NetInfoExample.ios.js} (100%)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/ConnectivityModule.java

diff --git a/Examples/UIExplorer/NetInfoExample.android.js b/Examples/UIExplorer/NetInfoExample.android.js
new file mode 100644
index 000000000000..41d77232195f
--- /dev/null
+++ b/Examples/UIExplorer/NetInfoExample.android.js
@@ -0,0 +1,158 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ *
+ * @flow
+ */
+'use strict';
+
+const React = require('react-native');
+const {
+  NetInfo, // requires android.permission.ACCESS_NETWORK_STATE
+  Text,
+  View
+} = React;
+const TouchableWithoutFeedback = require('TouchableWithoutFeedback');
+
+const ConnectionSubscription = React.createClass({
+  getInitialState() {
+    return {
+      connectionHistory: [],
+    };
+  },
+  componentDidMount: function() {
+    NetInfo.addEventListener(
+      'change',
+      this._handleConnectionChange
+    );
+  },
+  componentWillUnmount: function() {
+    NetInfo.removeEventListener(
+      'change',
+      this._handleConnectionChange
+    );
+  },
+  _handleConnectionChange: function(netInfo) {
+    var connectionHistory = this.state.connectionHistory.slice();
+    connectionHistory.push(netInfo);
+    this.setState({
+      connectionHistory,
+    });
+  },
+  render() {
+    return (
+      <Text>{JSON.stringify(this.state.connectionHistory)}</Text>
+    );
+  }
+});
+
+const ConnectionCurrent = React.createClass({
+  getInitialState() {
+    return {
+      netInfo: null,
+    };
+  },
+  componentDidMount: function() {
+    NetInfo.addEventListener(
+      'change',
+      this._handleConnectionChange
+    );
+    NetInfo.fetch().done(
+      (netInfo) => { this.setState({netInfo}); }
+    );
+  },
+  componentWillUnmount: function() {
+    NetInfo.removeEventListener(
+      'change',
+      this._handleConnectionChange
+    );
+  },
+  _handleConnectionChange: function(netInfo) {
+    this.setState({
+      netInfo,
+    });
+  },
+  render() {
+    return (
+      <Text>{JSON.stringify(this.state.netInfo)}</Text>
+    );
+  }
+});
+
+const IsConnected = React.createClass({
+  getInitialState() {
+    return {
+      isConnected: null,
+    };
+  },
+  componentDidMount: function() {
+    NetInfo.isConnected.addEventListener(
+      'change',
+      this._handleConnectivityChange
+    );
+    NetInfo.isConnected.fetch().done(
+      (isConnected) => { this.setState({isConnected}); }
+    );
+  },
+  componentWillUnmount: function() {
+    NetInfo.isConnected.removeEventListener(
+      'change',
+      this._handleConnectivityChange
+    );
+  },
+  _handleConnectivityChange: function(isConnected) {
+    this.setState({
+      isConnected,
+    });
+  },
+  render() {
+    return (
+      <Text>{this.state.isConnected ? 'Online' : 'Offline'}</Text>
+    );
+  }
+});
+
+const NetInfoExample = React.createClass({
+  statics: {
+    title: '<NetInfo>',
+    description: 'Monitor network status.'
+  },
+
+  getInitialState() {
+    return {
+      isMetered: null,
+    };
+  },
+  render() {
+    return (
+      <View >
+        <Text> Is Connected: <IsConnected /> </Text>
+        <Text> Current Connection Type: <ConnectionCurrent /> </Text>
+        <Text> Connection History: <ConnectionSubscription /> </Text>
+        <TouchableWithoutFeedback onPress={this.isConnectionMetered}>
+          <View>
+            <Text>Click to see if connection is metered: {this.state.isMetered}</Text>
+          </View>
+        </TouchableWithoutFeedback>
+      </View>
+    );
+  },
+  isConnectionMetered: function() {
+    NetInfo.isConnectionMetered((isConnectionMetered) => {
+      this.setState({
+        isMetered: isConnectionMetered ? 'Is Metered' : 'Is Not Metered',
+      });
+    });
+  }
+});
+
+module.exports = NetInfoExample;
diff --git a/Examples/UIExplorer/NetInfoExample.js b/Examples/UIExplorer/NetInfoExample.ios.js
similarity index 100%
rename from Examples/UIExplorer/NetInfoExample.js
rename to Examples/UIExplorer/NetInfoExample.ios.js
diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index 7d57332c2318..b3b0fc4d50ff 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -43,6 +43,7 @@ var APIS = [
   require('./IntentAndroidExample.android'),
   require('./LayoutEventsExample'),
   require('./LayoutExample'),
+  require('./NetInfoExample.android'),
   require('./PanResponderExample'),
   require('./PointerEventsExample'),
   require('./TimerExample'),
diff --git a/Examples/UIExplorer/UIExplorerList.ios.js b/Examples/UIExplorer/UIExplorerList.ios.js
index 940bd79ba42e..2f937cbeb6be 100644
--- a/Examples/UIExplorer/UIExplorerList.ios.js
+++ b/Examples/UIExplorer/UIExplorerList.ios.js
@@ -68,7 +68,7 @@ var APIS = [
   require('./CameraRollExample.ios'),
   require('./GeolocationExample'),
   require('./LayoutExample'),
-  require('./NetInfoExample'),
+  require('./NetInfoExample.ios'),
   require('./PanResponderExample'),
   require('./PointerEventsExample'),
   require('./PushNotificationIOSExample'),
diff --git a/Examples/UIExplorer/android/app/src/main/AndroidManifest.xml b/Examples/UIExplorer/android/app/src/main/AndroidManifest.xml
index b69776f9a5d4..40bbd20f538f 100644
--- a/Examples/UIExplorer/android/app/src/main/AndroidManifest.xml
+++ b/Examples/UIExplorer/android/app/src/main/AndroidManifest.xml
@@ -3,6 +3,7 @@
           package="com.facebook.react.uiapp" >
 
   <uses-permission android:name="android.permission.INTERNET" />
+  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
 
   <application
       android:allowBackup="true"
diff --git a/Libraries/Network/NetInfo.js b/Libraries/Network/NetInfo.js
index 41eb9390d708..1414b363d01e 100644
--- a/Libraries/Network/NetInfo.js
+++ b/Libraries/Network/NetInfo.js
@@ -17,7 +17,7 @@ var Platform = require('Platform');
 var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
 var RCTNetInfo = NativeModules.NetInfo;
 
-var DEVICE_REACHABILITY_EVENT = 'reachabilityDidChange';
+var DEVICE_CONNECTIVITY_EVENT = 'networkStatusDidChange';
 
 type ChangeEventName = $Enum<{
   change: string;
@@ -53,6 +53,26 @@ type ConnectivityStateAndroid = $Enum<{
   UNKNOWN: string;
 }>;
 
+
+var _subscriptions = new Map();
+
+if (Platform.OS === 'ios') {
+  var _isConnected = function(
+    reachability: ReachabilityStateIOS
+  ): bool {
+    return reachability !== 'none' &&
+      reachability !== 'unknown';
+  };
+} else if (Platform.OS === 'android') {
+  var _isConnected = function(
+      connectionType: ConnectivityStateAndroid
+    ): bool {
+    return connectionType !== 'NONE' && connectionType !== 'UNKNOWN';
+  };
+}
+
+var _isConnectedSubscriptions = new Map();
+
 /**
  * NetInfo exposes info about online/offline status
  *
@@ -84,6 +104,10 @@ type ConnectivityStateAndroid = $Enum<{
  *
  * ### Android
  *
+ * To request network info, you need to add the following line to your
+ * app's `AndroidManifest.xml`:
+ *
+ * `<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />`
  * Asynchronously determine if the device is connected and details about that connection.
  *
  * Android Connectivity Types
@@ -135,35 +159,15 @@ type ConnectivityStateAndroid = $Enum<{
  * );
  * ```
  */
-
-var _subscriptions = new Map();
-
-if (Platform.OS === 'ios') {
-  var _isConnected = function(
-    reachability: ReachabilityStateIOS
-  ): bool {
-    return reachability !== 'none' &&
-      reachability !== 'unknown';
-  };
-} else if (Platform.OS === 'android') {
-  var _isConnected = function(
-      connectionType: ConnectivityStateAndroid
-    ): bool {
-    return connectionType !== 'NONE' && connectionType !== 'UNKNOWN';
-  };
-}
-
-var _isConnectedSubscriptions = new Map();
-
 var NetInfo = {
   addEventListener: function (
     eventName: ChangeEventName,
     handler: Function
   ): void {
     var listener = RCTDeviceEventEmitter.addListener(
-      DEVICE_REACHABILITY_EVENT,
+      DEVICE_CONNECTIVITY_EVENT,
       (appStateData) => {
-        handler(appStateData.network_reachability);
+        handler(appStateData.network_info);
       }
     );
     _subscriptions.set(handler, listener);
@@ -183,7 +187,7 @@ var NetInfo = {
 
   fetch: function(): Promise {
     return new Promise((resolve, reject) => {
-      RCTNetInfo.getCurrentReachability(
+      RCTNetInfo.getCurrentConnectivity(
         function(resp) {
           resolve(resp.network_info);
         },
diff --git a/Libraries/Network/RCTNetInfo.m b/Libraries/Network/RCTNetInfo.m
index 5aab64432488..78e1c3ab732d 100644
--- a/Libraries/Network/RCTNetInfo.m
+++ b/Libraries/Network/RCTNetInfo.m
@@ -51,7 +51,7 @@ static void RCTReachabilityCallback(__unused SCNetworkReachabilityRef target, SC
 
   if (![status isEqualToString:self->_status]) {
     self->_status = status;
-    [self->_bridge.eventDispatcher sendDeviceEventWithName:@"networkDidChange"
+    [self->_bridge.eventDispatcher sendDeviceEventWithName:@"networkStatusDidChange"
                                                       body:@{@"network_info": status}];
   }
 }
@@ -87,7 +87,7 @@ - (void)dealloc
 #pragma mark - Public API
 
 // TODO: remove error callback - not needed except by Subscribable interface
-RCT_EXPORT_METHOD(getCurrentReachability:(RCTResponseSenderBlock)getSuccess
+RCT_EXPORT_METHOD(getCurrentConnectivity:(RCTResponseSenderBlock)getSuccess
                   withErrorCallback:(__unused RCTResponseSenderBlock)getError)
 {
   getSuccess(@[@{@"network_info": _status}]);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/ConnectivityModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/ConnectivityModule.java
new file mode 100644
index 000000000000..00414d86a688
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/ConnectivityModule.java
@@ -0,0 +1,154 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.modules.netinfo;
+
+import javax.annotation.Nullable;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.support.v4.net.ConnectivityManagerCompat;
+
+import com.facebook.react.bridge.Callback;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.bridge.LifecycleEventListener;
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.bridge.WritableNativeMap;
+
+import static com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter;
+
+/**
+ * Module that monitors and provides information about the connectivity state of the device.
+ */
+public class ConnectivityModule extends ReactContextBaseJavaModule
+    implements LifecycleEventListener {
+
+  private static final String CONNECTION_TYPE_NONE = "NONE";
+  private static final String CONNECTION_TYPE_UNKNOWN = "UNKNOWN";
+
+  private final ConnectivityManager mConnectivityManager;
+  private final ConnectivityManagerCompat mConnectivityManagerCompat;
+
+  private String mConnectivity;
+  private @Nullable ConnectivityBroadcastReceiver mConnectivityBroadcastReceiver;
+
+  public ConnectivityModule(ReactApplicationContext reactContext) {
+    super(reactContext);
+    mConnectivityManager =
+        (ConnectivityManager) reactContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+    mConnectivityManagerCompat = new ConnectivityManagerCompat();
+    mConnectivity = "";
+  }
+
+  @Override
+  public void onHostResume() {
+    maybeRegisterReceiver();
+    updateAndSendConnectionType();
+  }
+
+  @Override
+  public void onHostPause() {
+    maybeUnregisterReceiver();
+  }
+
+  @Override
+  public void onHostDestroy() {
+  }
+
+  @Override
+  public void initialize() {
+    getReactApplicationContext().addLifecycleEventListener(this);
+    maybeRegisterReceiver();
+    updateAndSendConnectionType();
+  }
+
+  @Override
+  public void onCatalystInstanceDestroy() {
+    maybeUnregisterReceiver();
+  }
+
+  @Override
+  public String getName() {
+    return "NetInfo";
+  }
+
+  @ReactMethod
+  public void getCurrentConnectivity(Callback successCallback, Callback errorCallback) {
+    successCallback.invoke(createConnectivityEventMap());
+  }
+
+  @ReactMethod
+  public void isConnectionMetered(Callback successCallback) {
+    successCallback.invoke(mConnectivityManagerCompat.isActiveNetworkMetered(mConnectivityManager));
+  }
+
+  private void maybeRegisterReceiver() {
+    if (mConnectivityBroadcastReceiver != null) {
+      return;
+    }
+    mConnectivityBroadcastReceiver = new ConnectivityBroadcastReceiver();
+    IntentFilter filter = new IntentFilter();
+    filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+    getReactApplicationContext().registerReceiver(mConnectivityBroadcastReceiver, filter);
+  }
+
+  private void maybeUnregisterReceiver() {
+    if (mConnectivityBroadcastReceiver == null) {
+      return;
+    }
+    getReactApplicationContext().unregisterReceiver(mConnectivityBroadcastReceiver);
+    mConnectivityBroadcastReceiver = null;
+    mConnectivity = "";
+  }
+
+  private void updateAndSendConnectionType() {
+    String currentConnectivity = getCurrentConnectionType();
+    // It is possible to get multiple broadcasts for the same connectivity change, so we only
+    // update and send an event when the connectivity has indeed changed.
+    if (!currentConnectivity.equalsIgnoreCase(mConnectivity)) {
+      mConnectivity = currentConnectivity;
+      sendConnectivityChangedEvent();
+    }
+  }
+
+  private String getCurrentConnectionType() {
+    NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo();
+    if (networkInfo == null || !networkInfo.isConnected()) {
+      return CONNECTION_TYPE_NONE;
+    } else if (ConnectivityManager.isNetworkTypeValid(networkInfo.getType())) {
+      return networkInfo.getTypeName().toUpperCase();
+    } else {
+      return CONNECTION_TYPE_UNKNOWN;
+    }
+  }
+  private void sendConnectivityChangedEvent() {
+    getReactApplicationContext().getJSModule(RCTDeviceEventEmitter.class)
+        .emit("networkStatusDidChange", createConnectivityEventMap());
+  }
+
+  private WritableMap createConnectivityEventMap() {
+    WritableMap event = new WritableNativeMap();
+    event.putString("network_info", mConnectivity);
+    return event;
+  }
+
+  /**
+   * Class that receives intents whenever the connection type changes.
+   * NB: It is possible on some devices to receive certain connection type changes multiple times.
+   */
+  private class ConnectivityBroadcastReceiver extends BroadcastReceiver {
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+      if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+        updateAndSendConnectionType();
+      }
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
index a0e90db20613..bf91bade6ccd 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
@@ -20,6 +20,7 @@
 import com.facebook.react.modules.fresco.FrescoModule;
 import com.facebook.react.modules.intent.IntentModule;
 import com.facebook.react.modules.location.LocationModule;
+import com.facebook.react.modules.netinfo.ConnectivityModule;
 import com.facebook.react.modules.network.NetworkingModule;
 import com.facebook.react.modules.storage.AsyncStorageModule;
 import com.facebook.react.modules.toast.ToastModule;
@@ -54,6 +55,7 @@ public List<NativeModule> createNativeModules(ReactApplicationContext reactConte
       new IntentModule(reactContext),
       new LocationModule(reactContext),
       new NetworkingModule(reactContext),
+      new ConnectivityModule(reactContext),
       new WebSocketModule(reactContext),
       new ToastModule(reactContext));
   }

From 0058b0806bf64f4f1c1277bca46198399b67c8ba Mon Sep 17 00:00:00 2001
From: Wenjing Wang <wenjingw@fb.com>
Date: Wed, 2 Dec 2015 11:23:22 -0800
Subject: [PATCH 0214/1411] propTypes could be undefined

Summary:
public
This causes a warning since propType not exist

Reviewed By: vjeux

Differential Revision: D2713358

fb-gh-sync-id: 58406d1dc969e6f1d40bee958c28cc87036b30c2
---
 Libraries/Animated/src/AnimatedImplementation.js | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Libraries/Animated/src/AnimatedImplementation.js b/Libraries/Animated/src/AnimatedImplementation.js
index b8b3aee77b96..3039f887b47c 100644
--- a/Libraries/Animated/src/AnimatedImplementation.js
+++ b/Libraries/Animated/src/AnimatedImplementation.js
@@ -1094,6 +1094,10 @@ function createAnimatedComponent(Component: any): any {
   }
   AnimatedComponent.propTypes = {
     style: function(props, propName, componentName) {
+      if (!Component.propTypes) {
+        return;
+      }
+
       for (var key in ViewStylePropTypes) {
         if (!Component.propTypes[key] && props[key] !== undefined) {
           console.error(

From 2b7d65fdc9cb4ebe41df2ff184a771a7a031409d Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Thu, 3 Dec 2015 08:27:19 +0800
Subject: [PATCH 0215/1411] remove packager.js way

---
 docs/LinuxWindowsSupport.md | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/docs/LinuxWindowsSupport.md b/docs/LinuxWindowsSupport.md
index 2f6d59bcdbce..18c4ea9db68c 100644
--- a/docs/LinuxWindowsSupport.md
+++ b/docs/LinuxWindowsSupport.md
@@ -19,12 +19,6 @@ As of **version 0.14** Android development with React native is mostly possible
 
 On Windows the packager won't be started automatically when you run `react-native run-android`. You can start it manually using:
     
-    #For React Native version < 0.14
-    cd MyAwesomeApp
-    node node_modules/react-native/packager/packager.js
-
-    
-    #For React Native version >= 0.14 （which had removed packager.js)
     cd MyAwesomeApp
     react-native start
 

From d691091530c925cbfe528825b391ec44a4bbd112 Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Thu, 3 Dec 2015 07:47:11 +0530
Subject: [PATCH 0216/1411] Fix typo in permalink

---
 docs/AndroidBuildingFromSource.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/AndroidBuildingFromSource.md b/docs/AndroidBuildingFromSource.md
index 303c43dd26bc..bf3d8289b930 100644
--- a/docs/AndroidBuildingFromSource.md
+++ b/docs/AndroidBuildingFromSource.md
@@ -3,7 +3,7 @@ id: android-building-from-source
 title: Building React Native from source
 layout: docs
 category: Guides (Android)
-permalink: docs/android-building-from-source
+permalink: docs/android-building-from-source.html
 next: activityindicatorios
 ---
 

From 1c57291faae4cd13a4686dd18cb59c4fb4d40560 Mon Sep 17 00:00:00 2001
From: Tim Yung <yungsters@fb.com>
Date: Wed, 2 Dec 2015 18:57:20 -0800
Subject: [PATCH 0217/1411] RN: Support Multiple Packager Servers

Summary:
Adds support for multiple packager servers, which could be used to hot-reload dependencies in response to a change in the `cacheVersion`.

Currently, there is no way to:

- Create multiple `ReactPackager` servers.
- Instantiate more than one `FileWatcher` constructor (due to the "single instance" invariant).

public

Reviewed By: martinbigio

Differential Revision: D2713455

fb-gh-sync-id: 9be0f0cb2b846baf088d0cf14650cc8b9e950815
---
 packager/react-packager/index.js                 | 1 +
 packager/react-packager/src/FileWatcher/index.js | 1 +
 2 files changed, 2 insertions(+)

diff --git a/packager/react-packager/index.js b/packager/react-packager/index.js
index e1a294f4097a..5b28e7741a2b 100644
--- a/packager/react-packager/index.js
+++ b/packager/react-packager/index.js
@@ -16,6 +16,7 @@ var debug = require('debug');
 var omit = require('underscore').omit;
 var Activity = require('./src/Activity');
 
+exports.createServer = createServer;
 exports.middleware = function(options) {
   var server = createServer(options);
   return server.processRequest.bind(server);
diff --git a/packager/react-packager/src/FileWatcher/index.js b/packager/react-packager/src/FileWatcher/index.js
index d9ed7f32fd25..e32c36963ae5 100644
--- a/packager/react-packager/src/FileWatcher/index.js
+++ b/packager/react-packager/src/FileWatcher/index.js
@@ -72,6 +72,7 @@ class FileWatcher extends EventEmitter {
   }
 
   end() {
+    inited = false;
     return this._loading.then(
       (watchers) => watchers.map(
         watcher => Promise.denodeify(watcher.close).call(watcher)

From 8e5585839728320e8ec259b0d03e0c329247cd17 Mon Sep 17 00:00:00 2001
From: Justin Spahr-Summers <jspahrsummers@fb.com>
Date: Thu, 3 Dec 2015 03:19:45 -0800
Subject: [PATCH 0218/1411] Precompute whether modules respond to batch
 notification methods

Summary:
public

Looping through every `RCTModuleData` to check whether the module responds to `-batchDidComplete` or `-partialBatchDidFlush` is unnecessarily expensive. We can cache the answer at the time that the module instance is actually initialized.

Reviewed By: tadeuzagallo

Differential Revision: D2717594

fb-gh-sync-id: 274a59ec2d6014ce18c93404ce6b9940c1dc9c32
---
 React/Base/RCTBatchedBridge.m |  4 ++--
 React/Base/RCTModuleData.h    | 11 +++++++++++
 React/Base/RCTModuleData.m    | 10 ++++++++++
 3 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index bbb8fe24a465..bb6aff8e4fee 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -804,7 +804,7 @@ - (void)handleBuffer:(NSArray<NSArray *> *)buffer
 - (void)partialBatchDidFlush
 {
   for (RCTModuleData *moduleData in _moduleDataByID) {
-    if (moduleData.hasInstance && [moduleData.instance respondsToSelector:@selector(partialBatchDidFlush)]) {
+    if (moduleData.implementsPartialBatchDidFlush) {
       [self dispatchBlock:^{
         [moduleData.instance partialBatchDidFlush];
       } queue:moduleData.methodQueue];
@@ -816,7 +816,7 @@ - (void)batchDidComplete
 {
   // TODO: batchDidComplete is only used by RCTUIManager - can we eliminate this special case?
   for (RCTModuleData *moduleData in _moduleDataByID) {
-    if (moduleData.hasInstance && [moduleData.instance respondsToSelector:@selector(batchDidComplete)]) {
+    if (moduleData.implementsBatchDidComplete) {
       [self dispatchBlock:^{
         [moduleData.instance batchDidComplete];
       } queue:moduleData.methodQueue];
diff --git a/React/Base/RCTModuleData.h b/React/Base/RCTModuleData.h
index 540059842035..79752ba292ab 100644
--- a/React/Base/RCTModuleData.h
+++ b/React/Base/RCTModuleData.h
@@ -63,4 +63,15 @@
  */
 @property (nonatomic, copy, readonly) NSArray *config;
 
+/**
+ * Whether the receiver has a valid `instance` which implements -batchDidComplete.
+ */
+@property (nonatomic, assign, readonly) BOOL implementsBatchDidComplete;
+
+/**
+ * Whether the receiver has a valid `instance` which implements
+ * -partialBatchDidFlush.
+ */
+@property (nonatomic, assign, readonly) BOOL implementsPartialBatchDidFlush;
+
 @end
diff --git a/React/Base/RCTModuleData.m b/React/Base/RCTModuleData.m
index 11603850f73b..011159db829e 100644
--- a/React/Base/RCTModuleData.m
+++ b/React/Base/RCTModuleData.m
@@ -39,6 +39,8 @@ - (instancetype)initWithModuleInstance:(id<RCTBridgeModule>)instance
   if ((self = [super init])) {
     _instance = instance;
     _moduleClass = [instance class];
+
+    [self cacheImplementedSelectors];
   }
   return self;
 }
@@ -62,10 +64,18 @@ - (BOOL)hasInstance
 
     // Initialize queue
     [self methodQueue];
+
+    [self cacheImplementedSelectors];
   }
   return _instance;
 }
 
+- (void)cacheImplementedSelectors
+{
+  _implementsBatchDidComplete = [_instance respondsToSelector:@selector(batchDidComplete)];
+  _implementsPartialBatchDidFlush = [_instance respondsToSelector:@selector(partialBatchDidFlush)];
+}
+
 - (void)setBridgeForInstance:(RCTBridge *)bridge
 {
   if ([_instance respondsToSelector:@selector(bridge)]) {

From 1a748f5ed6c291888494addefa64adac38df2901 Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Thu, 3 Dec 2015 03:26:08 -0800
Subject: [PATCH 0219/1411] Fix profile build

Reviewed By: jspahrsummers

Differential Revision: D2717604

fb-gh-sync-id: 9817bf743de0d6b5bd22f12ae50a8e1f99c1c0c3
---
 React/Base/RCTConvert.m | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m
index f5f6033432ce..b2c033b38dbc 100644
--- a/React/Base/RCTConvert.m
+++ b/React/Base/RCTConvert.m
@@ -172,7 +172,7 @@ + (NSDate *)NSDate:(id)json
   }
   if ([json isKindOfClass:[NSNumber class]]) {
     NSArray *allValues = mapping.allValues;
-    if ([mapping.allValues containsObject:json] || [json isEqual:defaultValue]) {
+    if ([allValues containsObject:json] || [json isEqual:defaultValue]) {
       return json;
     }
     RCTLogError(@"Invalid %s '%@'. should be one of: %@", typeName, json, allValues);

From a68c731aca86a9dfdfda678776ce4f23e463fcf5 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Thu, 3 Dec 2015 03:55:14 -0800
Subject: [PATCH 0220/1411] Android: Accept Throwables in Promise.reject()

Summary:
public

Fixes #4309

This adds the possibility to reject `Promise` instances with `Throwable`s in java, instead of strings.
For now, it only reads the message, but we can add more features on top of this, e.g. forwarding the error stack.

Reviewed By: andreicoman11

Differential Revision: D2708192

fb-gh-sync-id: ca5ff584eca29370a9f9b780fa9825b17863a7e9
---
 .../src/main/java/com/facebook/react/bridge/Promise.java     | 1 +
 .../src/main/java/com/facebook/react/bridge/PromiseImpl.java | 5 +++++
 2 files changed, 6 insertions(+)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/Promise.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/Promise.java
index c19907af83cd..92ce60699ce8 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/Promise.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/Promise.java
@@ -18,5 +18,6 @@
  */
 public interface Promise {
   void resolve(Object value);
+  void reject(Throwable reason);
   void reject(String reason);
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/PromiseImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/PromiseImpl.java
index 688b081028e8..d6e25b694fb9 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/PromiseImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/PromiseImpl.java
@@ -30,6 +30,11 @@ public void resolve(Object value) {
     }
   }
 
+  @Override
+  public void reject(Throwable reason) {
+    reject(reason.getMessage());
+  }
+
   @Override
   public void reject(String reason) {
     if (mReject != null) {

From c8eed6a3619ac45f129da426b4cc2d01a877d923 Mon Sep 17 00:00:00 2001
From: Sameer Rahmani <lxsameer@gnu.org>
Date: Thu, 3 Dec 2015 04:38:07 -0800
Subject: [PATCH 0221/1411] RTL support added for ToolbarAndroid via "rtl"
 property

Summary: Closes https://github.com/facebook/react-native/pull/4378

Reviewed By: svcscm

Differential Revision: D2715052

Pulled By: mkonicek

fb-gh-sync-id: e24f5db230cd7329911797794e5ef150f6195c4a
---
 .../ToolbarAndroid/ToolbarAndroid.android.js         | 12 ++++++++++++
 .../react/views/toolbar/ReactToolbarManager.java     |  6 ++++++
 2 files changed, 18 insertions(+)

diff --git a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js
index eb904d867af9..2658361a9403 100644
--- a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js
+++ b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js
@@ -125,6 +125,17 @@ var ToolbarAndroid = React.createClass({
      * Sets the toolbar title color.
      */
     titleColor: ReactPropTypes.string,
+    /**
+     * Used to set the toolbar direction to RTL.
+     * In addition to this property you need to add
+     *
+     *   android:supportsRtl="true"
+     *
+     * to your application AndroidManifest.xml and then call
+     * `setLayoutDirection(LayoutDirection.RTL)` in your MainActivity
+     * `onCreate` method.
+     */
+    rtl: ReactPropTypes.bool,
     /**
      * Used to locate this view in end-to-end tests.
      */
@@ -180,6 +191,7 @@ var toolbarAttributes = {
   logo: true,
   navIcon: true,
   overflowIcon: true,
+  rtl: true,
   subtitle: true,
   subtitleColor: true,
   title: true,
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java
index f55d6d8694c9..36aac87e73ef 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java
@@ -18,6 +18,7 @@
 import android.content.res.TypedArray;
 import android.graphics.Color;
 import android.os.SystemClock;
+import android.util.LayoutDirection;
 import android.view.MenuItem;
 import android.view.View;
 
@@ -64,6 +65,11 @@ public void setOverflowIcon(ReactToolbar view, @Nullable ReadableMap overflowIco
     view.setOverflowIconSource(overflowIcon);
   }
 
+  @ReactProp(name = "rtl")
+  public void setRtl(ReactToolbar view, boolean rtl) {
+    view.setLayoutDirection(rtl ? LayoutDirection.LTR : LayoutDirection.RTL);
+  }
+
   @ReactProp(name = "subtitle")
   public void setSubtitle(ReactToolbar view, @Nullable String subtitle) {
     view.setSubtitle(subtitle);

From 5ad7dd3cac1a827beec81991088834b31279e996 Mon Sep 17 00:00:00 2001
From: Mike Armstrong <mikea@fb.com>
Date: Thu, 3 Dec 2015 05:49:00 -0800
Subject: [PATCH 0222/1411] pre add new systrace TRACE_TAG_REACT_VIEW

Reviewed By: foghina

Differential Revision: D2717692

fb-gh-sync-id: 572b9286bd5be9f15ba3295e29770c4d33ee7590
---
 ReactAndroid/src/main/java/com/facebook/systrace/Systrace.java | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ReactAndroid/src/main/java/com/facebook/systrace/Systrace.java b/ReactAndroid/src/main/java/com/facebook/systrace/Systrace.java
index 042a1668ee0d..a3d7699ce7d4 100644
--- a/ReactAndroid/src/main/java/com/facebook/systrace/Systrace.java
+++ b/ReactAndroid/src/main/java/com/facebook/systrace/Systrace.java
@@ -21,6 +21,7 @@ public class Systrace {
   public static final long TRACE_TAG_REACT_JAVA_BRIDGE = 0L;
   public static final long TRACE_TAG_REACT_FRESCO = 0L;
   public static final long TRACE_TAG_REACT_APPS = 0L;
+  public static final long TRACE_TAG_REACT_VIEW = 0L;
 
   public enum EventScope {
     THREAD('t'),

From 67bf0f1a70aa6efc667a6fe4499ae7c2212332ff Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Thu, 3 Dec 2015 06:07:23 -0800
Subject: [PATCH 0223/1411] Avoid interrupting scrolling in nested scrollviews

Summary:
When we nest scrollviews, the hack in handleCustomPan: will cause the scroll to stall and break.

There's still some weird behaviour inside ScrollResponder.js but this does not seem the affect the scrollview's scrolling.

public

Reviewed By: fionaf, jingc, majak

Differential Revision: D2713639

fb-gh-sync-id: ad898ead62415bc14c91bc84fdfdb8c0fbb32b06
---
 React/Views/RCTScrollView.m | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/React/Views/RCTScrollView.m b/React/Views/RCTScrollView.m
index f1ef89572119..5ae7fb05a6b5 100644
--- a/React/Views/RCTScrollView.m
+++ b/React/Views/RCTScrollView.m
@@ -182,7 +182,7 @@ - (BOOL)_shouldDisableScrollInteraction
 
 - (void)handleCustomPan:(__unused UIPanGestureRecognizer *)sender
 {
-  if ([self _shouldDisableScrollInteraction]) {
+  if ([self _shouldDisableScrollInteraction] && ![[RCTUIManager JSResponder] isKindOfClass:[RCTScrollView class]]) {
     self.panGestureRecognizer.enabled = NO;
     self.panGestureRecognizer.enabled = YES;
     // TODO: If mid bounce, animate the scroll view to a non-bounced position

From ff808fa4e0169f7a7aa9d51066b63fbc4d538249 Mon Sep 17 00:00:00 2001
From: sathis <sathis@genwi.com>
Date: Thu, 3 Dec 2015 19:52:02 +0530
Subject: [PATCH 0224/1411] Fix typos

---
 docs/AndroidBuildingFromSource.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/AndroidBuildingFromSource.md b/docs/AndroidBuildingFromSource.md
index bf3d8289b930..b0fd0896a590 100644
--- a/docs/AndroidBuildingFromSource.md
+++ b/docs/AndroidBuildingFromSource.md
@@ -45,7 +45,7 @@ npm install --save github:facebook/react-native#master
 
 Alternatively, you can clone the repo to your `node_modules` directory and run `npm install` inside the cloned repo.
 
-2. Add `gradle-download-task` as dependency in `andoid/build.gradle`:
+2. Add `gradle-download-task` as dependency in `android/build.gradle`:
 
 ```gradle
 ...
@@ -59,7 +59,7 @@ Alternatively, you can clone the repo to your `node_modules` directory and run `
 ...
 ```
 
-3. Add the `:ReactAndroid` project in `andoid/settings.gradle`:
+3. Add the `:ReactAndroid` project in `android/settings.gradle`:
 
 ```gradle
 ...

From 5030cae757a520886c6378be0d5a46216e9bc4b7 Mon Sep 17 00:00:00 2001
From: Qiao Liang <qiaoliang89@gmail.com>
Date: Thu, 3 Dec 2015 05:59:57 -0800
Subject: [PATCH 0225/1411] add permission for android geolocation example

Summary:
<img width="860" alt="screen shot 2015-12-03 at 3 38 02 pm" src="https://cloud.githubusercontent.com/assets/5563225/11554542/e7a33554-99d3-11e5-8d3a-e9ea47952a28.png">
Closes https://github.com/facebook/react-native/pull/4524

Reviewed By: svcscm

Differential Revision: D2717843

Pulled By: mkonicek

fb-gh-sync-id: 7828a7f28bb95be3d292d0ae3351c9d9678bb964
---
 Examples/UIExplorer/android/app/src/main/AndroidManifest.xml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Examples/UIExplorer/android/app/src/main/AndroidManifest.xml b/Examples/UIExplorer/android/app/src/main/AndroidManifest.xml
index 40bbd20f538f..abb275d7055d 100644
--- a/Examples/UIExplorer/android/app/src/main/AndroidManifest.xml
+++ b/Examples/UIExplorer/android/app/src/main/AndroidManifest.xml
@@ -4,6 +4,7 @@
 
   <uses-permission android:name="android.permission.INTERNET" />
   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
 
   <application
       android:allowBackup="true"

From 752a86786f46388ef5c6141feca62a9bae7f05b4 Mon Sep 17 00:00:00 2001
From: mkonicek-pr-test <martinkonicek@centrum.cz>
Date: Thu, 3 Dec 2015 07:09:09 -0800
Subject: [PATCH 0226/1411] Test PR 12

Summary:
Testing the shipit bot
Closes https://github.com/facebook/react-native/pull/4536

Reviewed By: svcscm

Differential Revision: D2717972

Pulled By: mkonicek

fb-gh-sync-id: 6cb1fe6a054d050d4bc9d693adda44381d6ad6e2
---
 Examples/2048/Game2048.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Examples/2048/Game2048.js b/Examples/2048/Game2048.js
index 3bc49217b7a2..239d1dadeca4 100644
--- a/Examples/2048/Game2048.js
+++ b/Examples/2048/Game2048.js
@@ -279,7 +279,7 @@ var styles = StyleSheet.create({
     backgroundColor: '#eeeecc',
   },
   tile8: {
-    backgroundColor: '#ffbb88',
+    backgroundColor: '#ffbb87',
   },
   tile16: {
     backgroundColor: '#ff9966',

From 10c8a1c417ce1d91e19312fb75af404c52ad5a55 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Thu, 3 Dec 2015 07:02:33 -0800
Subject: [PATCH 0227/1411] fixed mardown formatting in NetInfo code to allow
 proper JS Docs

Summary:
Current docs look bad https://facebook.github.io/react-native/docs/netinfo.html#content
Closes https://github.com/facebook/react-native/pull/4531

Reviewed By: svcscm

Differential Revision: D2717974

Pulled By: androidtrunkagent

fb-gh-sync-id: cd2cadfb782f8ce6a418ca7af5fcefb54504059b
---
 Libraries/Network/NetInfo.js | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Libraries/Network/NetInfo.js b/Libraries/Network/NetInfo.js
index 1414b363d01e..c2099c9e3eac 100644
--- a/Libraries/Network/NetInfo.js
+++ b/Libraries/Network/NetInfo.js
@@ -110,7 +110,8 @@ var _isConnectedSubscriptions = new Map();
  * `<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />`
  * Asynchronously determine if the device is connected and details about that connection.
  *
- * Android Connectivity Types
+ * Android Connectivity Types.
+ *
  * - `NONE` - device is offline
  * - `BLUETOOTH` - The Bluetooth data connection.
  * - `DUMMY` -  Dummy data connection.
@@ -124,6 +125,7 @@ var _isConnectedSubscriptions = new Map();
  * - `WIFI` - The WIFI data connection.
  * - `WIMAX` -  The WiMAX data connection.
  * - `UNKNOWN` - Unknown data connection.
+ *
  * The rest ConnectivityStates are hidden by the Android API, but can be used if necessary.
  *
  * ### isConnectionMetered
@@ -132,6 +134,7 @@ var _isConnectedSubscriptions = new Map();
  * classified as metered when the user is sensitive to heavy data usage on that connection due to
  * monetary costs, data limitations or battery/performance issues.
  *
+ * ```
  * NetInfo.isConnectionMetered((isConnectionMetered) => {
  *   console.log('Connection is ' + (isConnectionMetered ? 'Metered' : 'Not Metered'));
  * });

From 87253ca722a47534b8fd33d38ae1dbe96e2c5dbe Mon Sep 17 00:00:00 2001
From: Mike Armstrong <mikea@fb.com>
Date: Thu, 3 Dec 2015 07:23:58 -0800
Subject: [PATCH 0228/1411] Append JS_require_ to require profile names

Reviewed By: tadeuzagallo

Differential Revision: D2717939

fb-gh-sync-id: 4648e240eebfb3a7bc1c5041d4f1fba8761264a9
---
 packager/react-packager/src/Resolver/polyfills/require.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packager/react-packager/src/Resolver/polyfills/require.js b/packager/react-packager/src/Resolver/polyfills/require.js
index d7550ba1b9bb..ebaa8c406d75 100644
--- a/packager/react-packager/src/Resolver/polyfills/require.js
+++ b/packager/react-packager/src/Resolver/polyfills/require.js
@@ -54,7 +54,7 @@
       // require cycles inside the factory from causing an infinite require loop.
       mod.isInitialized = true;
 
-      __DEV__ && BridgeProfiling().profile(id);
+      __DEV__ && BridgeProfiling().profile('JS_require_' + id);
 
       // keep args in sync with with defineModuleCode in
       // packager/react-packager/src/Resolver/index.js

From 3313f769f5660857487bc9fc012bd51c80056bd3 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 3 Dec 2015 07:43:34 -0800
Subject: [PATCH 0229/1411] Use console.error() for the Touchable.js bug so we
 can capture it in production logs

Reviewed By: javache

Differential Revision: D2717874

fb-gh-sync-id: 7c2cac61fe4fbd2c6de6cf1d9059df9ac119f543
---
 Libraries/Components/Touchable/Touchable.js | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/Libraries/Components/Touchable/Touchable.js b/Libraries/Components/Touchable/Touchable.js
index 0493311c5c2d..9172739ebc47 100644
--- a/Libraries/Components/Touchable/Touchable.js
+++ b/Libraries/Components/Touchable/Touchable.js
@@ -572,14 +572,9 @@ var TouchableMixin = {
     var curState = this.state.touchable.touchState;
     if (curState !== States.RESPONDER_ACTIVE_PRESS_IN &&
         curState !== States.RESPONDER_ACTIVE_LONG_PRESS_IN) {
-      if (__DEV__) {
-        throw new Error(
-          'Attempted to transition from state `' + curState + '` to `' +
-          States.RESPONDER_ACTIVE_LONG_PRESS_IN + '`, which is not supported. ' +
-          'This is most likely due to `Touchable.longPressDelayTimeout` not ' +
-          'being cancelled.'
-        );  
-      } 
+      console.error('Attempted to transition from state `' + curState + '` to `' +
+        States.RESPONDER_ACTIVE_LONG_PRESS_IN + '`, which is not supported. This is ' +
+        'most likely due to `Touchable.longPressDelayTimeout` not being cancelled.');   
     } else {
       this._receiveSignal(Signals.LONG_PRESS_DETECTED, e);
     }

From a64ee7d8c5b717051f0659bf25ec38a8bd583d54 Mon Sep 17 00:00:00 2001
From: Milen Dzhumerov <mgd@fb.com>
Date: Thu, 3 Dec 2015 08:08:37 -0800
Subject: [PATCH 0230/1411] Batch AsyncStorage.multiGet calls

Reviewed By: javache

Differential Revision: D2636553

fb-gh-sync-id: d6351b67c615d8c01c11c10e32321a9764c54c67
---
 Libraries/Storage/AsyncStorage.js | 61 ++++++++++++++++++++++++++-----
 1 file changed, 52 insertions(+), 9 deletions(-)

diff --git a/Libraries/Storage/AsyncStorage.js b/Libraries/Storage/AsyncStorage.js
index 9135088f6163..eb41c8a736f5 100644
--- a/Libraries/Storage/AsyncStorage.js
+++ b/Libraries/Storage/AsyncStorage.js
@@ -33,6 +33,10 @@ var RCTAsyncStorage = RCTAsyncRocksDBStorage || RCTAsyncSQLiteStorage || RCTAsyn
  * method returns a `Promise` object.
  */
 var AsyncStorage = {
+  _getRequests: ([]: Array<any>),
+  _getKeys: ([]: Array<string>),
+  _immediate: (null: ?number),
+
   /**
    * Fetches `key` and passes the result to `callback`, along with an `Error` if
    * there is any. Returns a `Promise` object.
@@ -164,6 +168,32 @@ var AsyncStorage = {
    * indicate which key caused the error.
    */
 
+  /** Flushes any pending requests using a single multiget */
+  flushGetRequests: function(): void {
+    const getRequests = this._getRequests;
+    const getKeys = this._getKeys;
+
+    this._getRequests = [];
+    this._getKeys = [];
+
+    RCTAsyncStorage.multiGet(getKeys, function(errors, result) {
+      // Even though the runtime complexity of this is theoretically worse vs if we used a map,
+      // it's much, much faster in practice for the data sets we deal with (we avoid
+      // allocating result pair arrays). This was heavily benchmarked.
+      const reqLength = getRequests.length;
+      for (let i = 0; i < reqLength; i++) {
+        const request = getRequests[i];
+        const requestKeys = request.keys;
+        var requestResult = result.filter(function(resultPair) {
+          return requestKeys.indexOf(resultPair[0]) !== -1;
+        });
+
+        request.callback && request.callback(null, requestResult);
+        request.resolve && request.resolve(requestResult);
+      }
+    });
+  },
+
   /**
    * multiGet invokes callback with an array of key-value pair arrays that
    * matches the input format of multiSet. Returns a `Promise` object.
@@ -174,17 +204,30 @@ var AsyncStorage = {
     keys: Array<string>,
     callback?: ?(errors: ?Array<Error>, result: ?Array<Array<string>>) => void
   ): Promise {
-    return new Promise((resolve, reject) => {
-      RCTAsyncStorage.multiGet(keys, function(errors, result) {
-        var error = convertErrors(errors);
-        callback && callback(error, result);
-        if (error) {
-          reject(error);
-        } else {
-          resolve(result);
-        }
+    if (!this._immediate) {
+      this._immediate = setImmediate(() => {
+        this._immediate = null;
+        this.flushGetRequests();
       });
+    }
+
+    var getRequest = {
+      keys: keys,
+      callback: callback,
+      keyIndex: this._getKeys.length,
+      resolve: null,
+      reject: null,
+    };
+
+    var promiseResult = new Promise((resolve, reject) => {
+      getRequest.resolve = resolve;
+      getRequest.reject = reject;
     });
+
+    this._getRequests.push(getRequest);
+    this._getKeys.push.apply(this._getKeys, keys);
+
+    return promiseResult;
   },
 
   /**

From 200e69e39f5509a6cd023867104e1db1f3d6295c Mon Sep 17 00:00:00 2001
From: Christopher Dro <hello@blick-labs.com>
Date: Thu, 3 Dec 2015 10:48:03 -0800
Subject: [PATCH 0231/1411] [Docs] Website - Change port from 8080 to 8079

---
 website/README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/website/README.md b/website/README.md
index 43d3debf7803..37afeadb9832 100644
--- a/website/README.md
+++ b/website/README.md
@@ -10,7 +10,7 @@ Then, run the server via
 
 ```
 npm start
-open http://localhost:8080/react-native/index.html
+open http://localhost:8079/react-native/index.html
 ```
 
 Anytime you change the contents, just refresh the page and it's going to be updated.

From dd9c1e16ee372f419e9c4e5757dc25cb3e2dcd66 Mon Sep 17 00:00:00 2001
From: Christopher Dro <hello@blick-labs.com>
Date: Thu, 3 Dec 2015 10:16:03 -0800
Subject: [PATCH 0232/1411] Add string as possible propType for 'systemIcon'

Summary:
Fixes #2361
Closes https://github.com/facebook/react-native/pull/4523

Reviewed By: svcscm

Differential Revision: D2718568

Pulled By: androidtrunkagent

fb-gh-sync-id: a15c94acaac899dfdaeb397c8c764053d1430854
---
 Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js b/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js
index f220249c76c7..20e0cf624066 100644
--- a/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js
+++ b/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js
@@ -52,7 +52,10 @@ var TabBarItemIOS = React.createClass({
     /**
      * A custom icon for the tab. It is ignored when a system icon is defined.
      */
-    icon: Image.propTypes.source,
+    icon: React.PropTypes.oneOfType([
+      React.PropTypes.string,
+      Image.propTypes.source,
+    ]),
     /**
      * A custom icon when the tab is selected. It is ignored when a system
      * icon is defined. If left empty, the icon will be tinted in blue.

From ecdc3429cd25c0d305627897a076910f33368bb8 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Thu, 3 Dec 2015 09:24:01 -0800
Subject: [PATCH 0233/1411] Fork v4 support library NestedScrollView to fix
 fling bug

Reviewed By: oli, lexs

Differential Revision: D2707733

fb-gh-sync-id: c9b375a6aa1010d60d21ca7500e862a6ff91a49b
---
 .../facebook/react/views/scroll/ReactScrollViewHelper.java    | 2 +-
 .../facebook/react/views/scroll/ReactScrollViewManager.java   | 4 ++++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java
index 12f5606fc8a6..c8e7fa22e5cb 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java
@@ -24,7 +24,7 @@ public class ReactScrollViewHelper {
   /**
    * Shared by {@link ReactScrollView} and {@link ReactHorizontalScrollView}.
    */
-  /* package */ static void emitScrollEvent(ViewGroup scrollView, int scrollX, int scrollY) {
+  public static void emitScrollEvent(ViewGroup scrollView, int scrollX, int scrollY) {
     View contentView = scrollView.getChildAt(0);
     ReactContext reactContext = (ReactContext) scrollView.getContext();
     reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java
index 2c3363f8ec66..6de7da6bcf3d 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java
@@ -81,6 +81,10 @@ public void scrollWithoutAnimationTo(
 
   @Override
   public @Nullable Map getExportedCustomDirectEventTypeConstants() {
+    return createExportedCustomDirectEventTypeConstants();
+  }
+
+  public static Map createExportedCustomDirectEventTypeConstants() {
     return MapBuilder.builder()
         .put(ScrollEvent.EVENT_NAME, MapBuilder.of("registrationName", "onScroll"))
         .put("topScrollBeginDrag", MapBuilder.of("registrationName", "onScrollBeginDrag"))

From 9a47ca1cc927d72b5db3795536e4c846c5997706 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 3 Dec 2015 10:33:03 -0800
Subject: [PATCH 0234/1411] Added addChildren() function as a more-optimal
 replacement for manageChildren for common use cases.

Reviewed By: jspahrsummers

Differential Revision: D2707930

fb-gh-sync-id: c44219bf9af943cad5b57f370656c1bcac732cd9
---
 .../ReactNative/ReactNativeBaseComponent.js   |  15 ++-
 .../ReactNative/ReactNativeDOMIDOperations.js |   1 +
 Libraries/ReactNative/ReactNativeMount.js     |  10 ++
 React/Modules/RCTUIManager.m                  | 101 +++++++++++++-----
 4 files changed, 95 insertions(+), 32 deletions(-)

diff --git a/Libraries/ReactNative/ReactNativeBaseComponent.js b/Libraries/ReactNative/ReactNativeBaseComponent.js
index 266c7b30fbf6..c7b4b42a8e1c 100644
--- a/Libraries/ReactNative/ReactNativeBaseComponent.js
+++ b/Libraries/ReactNative/ReactNativeBaseComponent.js
@@ -104,11 +104,11 @@ ReactNativeBaseComponent.Mixin = {
     // no children - let's avoid calling out to the native bridge for a large
     // portion of the children.
     if (mountImages.length) {
-      var indexes = cachedIndexArray(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; i < mountImages.length; i++) {
+      for (var i = 0, l = mountImages.length; i < l; i++) {
         var mountImage = mountImages[i];
         var childTag = mountImage.tag;
         var childID = mountImage.rootNodeID;
@@ -122,8 +122,15 @@ ReactNativeBaseComponent.Mixin = {
         );
         createdTags[i] = mountImage.tag;
       }
-      UIManager
-        .manageChildren(containerTag, null, null, createdTags, indexes, null);
+      
+      // Fast path for iOS
+      if (UIManager.addChildren) {
+        UIManager.addChildren(containerTag, createdTags);
+        return; 
+      }
+      
+      var indexes = cachedIndexArray(mountImages.length);
+      UIManager.manageChildren(containerTag, null, null, createdTags, indexes, null);
     }
   },
 
diff --git a/Libraries/ReactNative/ReactNativeDOMIDOperations.js b/Libraries/ReactNative/ReactNativeDOMIDOperations.js
index fbf90db50337..a3ef1cc36f2c 100644
--- a/Libraries/ReactNative/ReactNativeDOMIDOperations.js
+++ b/Libraries/ReactNative/ReactNativeDOMIDOperations.js
@@ -53,6 +53,7 @@ var dangerouslyProcessChildrenUpdates = function(childrenUpdates, markupList) {
       (updates.addChildTags || (updates.addChildTags = [])).push(tag);
     }
   }
+  
   // Note this enumeration order will be different on V8!  Move `byContainerTag`
   // to a sparse array as soon as we confirm there are not horrible perf
   // penalties.
diff --git a/Libraries/ReactNative/ReactNativeMount.js b/Libraries/ReactNative/ReactNativeMount.js
index 1f6dab51b8a4..758fe1e5c174 100644
--- a/Libraries/ReactNative/ReactNativeMount.js
+++ b/Libraries/ReactNative/ReactNativeMount.js
@@ -188,6 +188,16 @@ var ReactNativeMount = {
         mountImage.rootNodeID,
         mountImage.tag
       );
+      
+      // Fast path for iOS
+      if (UIManager.addChildren) {
+        UIManager.addChildren(
+          ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(containerID),
+          [mountImage.tag]
+        );
+        return;
+      }
+      
       var addChildTags = [mountImage.tag];
       var addAtIndices = [0];
       UIManager.manageChildren(
diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m
index c3c1ea58917b..96ed3aa4e9cb 100644
--- a/React/Modules/RCTUIManager.m
+++ b/React/Modules/RCTUIManager.m
@@ -720,6 +720,33 @@ - (void)_removeChildren:(NSArray<id<RCTComponent>> *)children
         removeAtIndices:removeAtIndices];
 }
 
+RCT_EXPORT_METHOD(addChildren:(nonnull NSNumber *)containerTag
+                  reactTags:(NSNumberArray *)reactTags)
+{
+  RCTAddChildren(containerTag, reactTags,
+                 (NSDictionary<NSNumber *, id<RCTComponent>> *)_shadowViewRegistry);
+
+  [self addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry){
+
+    RCTAddChildren(containerTag, reactTags,
+                   (NSDictionary<NSNumber *, id<RCTComponent>> *)viewRegistry);
+  }];
+}
+
+static void RCTAddChildren(NSNumber *containerTag,
+                           NSArray<NSNumber *> *reactTags,
+                           NSDictionary<NSNumber *, id<RCTComponent>> *registry)
+{
+  id<RCTComponent> container = registry[containerTag];
+  NSInteger index = [container reactSubviews].count;
+  for (NSNumber *reactTag in reactTags) {
+    id<RCTComponent> view = registry[reactTag];
+    if (view) {
+      [container insertReactSubview:view atIndex:index++];
+    }
+  }
+}
+
 RCT_EXPORT_METHOD(manageChildren:(nonnull NSNumber *)containerReactTag
                   moveFromIndices:(NSNumberArray *)moveFromIndices
                   moveToIndices:(NSNumberArray *)moveToIndices
@@ -754,39 +781,57 @@ - (void)_manageChildren:(NSNumber *)containerReactTag
         removeAtIndices:(NSArray<NSNumber *> *)removeAtIndices
                registry:(NSMutableDictionary<NSNumber *, id<RCTComponent>> *)registry
 {
-  id<RCTComponent> container = registry[containerReactTag];
-  RCTAssert(moveFromIndices.count == moveToIndices.count, @"moveFromIndices had size %tu, moveToIndices had size %tu", moveFromIndices.count, moveToIndices.count);
-  RCTAssert(addChildReactTags.count == addAtIndices.count, @"there should be at least one React child to add");
+  RCTAssert(moveFromIndices.count == moveToIndices.count,
+            @"moveFromIndices had size %tu, moveToIndices had size %tu",
+            moveFromIndices.count, moveToIndices.count);
 
-  // Removes (both permanent and temporary moves) are using "before" indices
-  NSArray<id<RCTComponent>> *permanentlyRemovedChildren =
-    [self _childrenToRemoveFromContainer:container atIndices:removeAtIndices];
-  NSArray<id<RCTComponent>> *temporarilyRemovedChildren =
-    [self _childrenToRemoveFromContainer:container atIndices:moveFromIndices];
-  [self _removeChildren:permanentlyRemovedChildren fromContainer:container];
-  [self _removeChildren:temporarilyRemovedChildren fromContainer:container];
+  RCTAssert(addChildReactTags.count == addAtIndices.count,
+            @"addChildReactTags had size %tu, addAtIndices had size %tu",
+            addChildReactTags.count, addAtIndices.count);
 
-  [self _purgeChildren:permanentlyRemovedChildren fromRegistry:registry];
-
-  // TODO (#5906496): optimize all these loops - constantly calling array.count is not efficient
-
-  // Figure out what to insert - merge temporary inserts and adds
-  NSMutableDictionary *destinationsToChildrenToAdd = [NSMutableDictionary dictionary];
-  for (NSInteger index = 0, length = temporarilyRemovedChildren.count; index < length; index++) {
-    destinationsToChildrenToAdd[moveToIndices[index]] = temporarilyRemovedChildren[index];
+  id<RCTComponent> container = registry[containerReactTag];
+  NSArray<id<RCTComponent>> *views = [container reactSubviews];
+
+  // Get indices to insert/remove
+  NSUInteger purgeCount = removeAtIndices.count;
+  NSUInteger moveCount = moveFromIndices.count;
+  NSUInteger insertCount = addAtIndices.count;
+  NSUInteger removeCount = purgeCount + moveCount;
+  NSMutableArray<id<RCTComponent>> *toRemove = removeCount ? [NSMutableArray new] : nil;
+  NSMutableDictionary *toInsert = insertCount ? [NSMutableDictionary new] : nil;
+  for (NSNumber *index in removeAtIndices) {
+    id<RCTComponent> view = views[index.integerValue];
+    [toRemove addObject:view];
+    RCTTraverseViewNodes(registry[view.reactTag], ^(id<RCTComponent> subview) {
+      RCTAssert(![subview isReactRootView], @"Root views should not be unregistered");
+      if ([subview conformsToProtocol:@protocol(RCTInvalidating)]) {
+        [(id<RCTInvalidating>)subview invalidate];
+      }
+      [registry removeObjectForKey:subview.reactTag];
+      [_bridgeTransactionListeners removeObject:subview];
+    });
   }
-  for (NSInteger index = 0, length = addAtIndices.count; index < length; index++) {
-    id<RCTComponent> view = registry[addChildReactTags[index]];
-    if (view) {
-      destinationsToChildrenToAdd[addAtIndices[index]] = view;
-    }
+  NSInteger i = 0;
+  for (NSNumber *index in moveFromIndices) {
+    id<RCTComponent> view = views[index.integerValue];
+    [toRemove addObject:view];
+    toInsert[moveToIndices[i]] = view;
+    i++;
+  }
+  i = 0;
+  for (NSNumber *reactTag in addChildReactTags) {
+    toInsert[addAtIndices[i]] = registry[reactTag];
+    i++;
+  }
+
+  // Remove old views
+  for (id<RCTComponent> view in toRemove) {
+    [container removeReactSubview:view];
   }
 
-  NSArray<NSNumber *> *sortedIndices =
-    [destinationsToChildrenToAdd.allKeys sortedArrayUsingSelector:@selector(compare:)];
-  for (NSNumber *reactIndex in sortedIndices) {
-    [container insertReactSubview:destinationsToChildrenToAdd[reactIndex]
-                          atIndex:reactIndex.integerValue];
+  // Insert new views in ascending order
+  for (NSNumber *index in [toInsert.allKeys sortedArrayUsingSelector:@selector(compare:)]) {
+    [container insertReactSubview:toInsert[index] atIndex:index.integerValue];
   }
 }
 

From d1029d1b9d7c432f7cdf2565d5f93529bdd818db Mon Sep 17 00:00:00 2001
From: moschan <kaityo02@gmail.com>
Date: Thu, 3 Dec 2015 10:53:40 -0800
Subject: [PATCH 0235/1411] fixed mardown formatting of ListView

Summary:
about renderRow and renderSeparator.
insert a new line before description.
Closes https://github.com/facebook/react-native/pull/4532

Reviewed By: svcscm

Differential Revision: D2718764

Pulled By: androidtrunkagent

fb-gh-sync-id: eeefd16617fcb5e5ca21f6fd0cf29d63cb3b1f1c
---
 Libraries/CustomComponents/ListView/ListView.js | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js
index 5706ff0f91b2..fa29da5d87ee 100644
--- a/Libraries/CustomComponents/ListView/ListView.js
+++ b/Libraries/CustomComponents/ListView/ListView.js
@@ -116,6 +116,7 @@ var ListView = React.createClass({
     dataSource: PropTypes.instanceOf(ListViewDataSource).isRequired,
     /**
      * (sectionID, rowID, adjacentRowHighlighted) => renderable
+     *
      * If provided, a renderable component to be rendered as the separator
      * below each row but not the last row if there is a section header below.
      * Take a sectionID and rowID of the row above and whether its adjacent row
@@ -124,6 +125,7 @@ var ListView = React.createClass({
     renderSeparator: PropTypes.func,
     /**
      * (rowData, sectionID, rowID, highlightRow) => renderable
+     *
      * Takes a data entry from the data source and its ids and should return
      * a renderable component to be rendered as the row.  By default the data
      * is exactly what was put into the data source, but it's also possible to

From 70f0dfc0e67d8f3489ab31deeec12524bfde57fb Mon Sep 17 00:00:00 2001
From: Dan Witte <dwitte@fb.com>
Date: Thu, 3 Dec 2015 16:04:34 -0800
Subject: [PATCH 0236/1411] revert D2707930

Reviewed By: fkgozali

Differential Revision: D2720828

fb-gh-sync-id: 53113fb33150b42a7b597a7dfd04bb9885def029
---
 .../ReactNative/ReactNativeBaseComponent.js   |  15 +--
 .../ReactNative/ReactNativeDOMIDOperations.js |   1 -
 Libraries/ReactNative/ReactNativeMount.js     |  10 --
 React/Modules/RCTUIManager.m                  | 101 +++++-------------
 4 files changed, 32 insertions(+), 95 deletions(-)

diff --git a/Libraries/ReactNative/ReactNativeBaseComponent.js b/Libraries/ReactNative/ReactNativeBaseComponent.js
index c7b4b42a8e1c..266c7b30fbf6 100644
--- a/Libraries/ReactNative/ReactNativeBaseComponent.js
+++ b/Libraries/ReactNative/ReactNativeBaseComponent.js
@@ -104,11 +104,11 @@ ReactNativeBaseComponent.Mixin = {
     // no children - let's avoid calling out to the native bridge for a large
     // portion of the children.
     if (mountImages.length) {
-      
+      var indexes = cachedIndexArray(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++) {
+      for (var i = 0; i < mountImages.length; i++) {
         var mountImage = mountImages[i];
         var childTag = mountImage.tag;
         var childID = mountImage.rootNodeID;
@@ -122,15 +122,8 @@ ReactNativeBaseComponent.Mixin = {
         );
         createdTags[i] = mountImage.tag;
       }
-      
-      // Fast path for iOS
-      if (UIManager.addChildren) {
-        UIManager.addChildren(containerTag, createdTags);
-        return; 
-      }
-      
-      var indexes = cachedIndexArray(mountImages.length);
-      UIManager.manageChildren(containerTag, null, null, createdTags, indexes, null);
+      UIManager
+        .manageChildren(containerTag, null, null, createdTags, indexes, null);
     }
   },
 
diff --git a/Libraries/ReactNative/ReactNativeDOMIDOperations.js b/Libraries/ReactNative/ReactNativeDOMIDOperations.js
index a3ef1cc36f2c..fbf90db50337 100644
--- a/Libraries/ReactNative/ReactNativeDOMIDOperations.js
+++ b/Libraries/ReactNative/ReactNativeDOMIDOperations.js
@@ -53,7 +53,6 @@ var dangerouslyProcessChildrenUpdates = function(childrenUpdates, markupList) {
       (updates.addChildTags || (updates.addChildTags = [])).push(tag);
     }
   }
-  
   // Note this enumeration order will be different on V8!  Move `byContainerTag`
   // to a sparse array as soon as we confirm there are not horrible perf
   // penalties.
diff --git a/Libraries/ReactNative/ReactNativeMount.js b/Libraries/ReactNative/ReactNativeMount.js
index 758fe1e5c174..1f6dab51b8a4 100644
--- a/Libraries/ReactNative/ReactNativeMount.js
+++ b/Libraries/ReactNative/ReactNativeMount.js
@@ -188,16 +188,6 @@ var ReactNativeMount = {
         mountImage.rootNodeID,
         mountImage.tag
       );
-      
-      // Fast path for iOS
-      if (UIManager.addChildren) {
-        UIManager.addChildren(
-          ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(containerID),
-          [mountImage.tag]
-        );
-        return;
-      }
-      
       var addChildTags = [mountImage.tag];
       var addAtIndices = [0];
       UIManager.manageChildren(
diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m
index 96ed3aa4e9cb..c3c1ea58917b 100644
--- a/React/Modules/RCTUIManager.m
+++ b/React/Modules/RCTUIManager.m
@@ -720,33 +720,6 @@ - (void)_removeChildren:(NSArray<id<RCTComponent>> *)children
         removeAtIndices:removeAtIndices];
 }
 
-RCT_EXPORT_METHOD(addChildren:(nonnull NSNumber *)containerTag
-                  reactTags:(NSNumberArray *)reactTags)
-{
-  RCTAddChildren(containerTag, reactTags,
-                 (NSDictionary<NSNumber *, id<RCTComponent>> *)_shadowViewRegistry);
-
-  [self addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry){
-
-    RCTAddChildren(containerTag, reactTags,
-                   (NSDictionary<NSNumber *, id<RCTComponent>> *)viewRegistry);
-  }];
-}
-
-static void RCTAddChildren(NSNumber *containerTag,
-                           NSArray<NSNumber *> *reactTags,
-                           NSDictionary<NSNumber *, id<RCTComponent>> *registry)
-{
-  id<RCTComponent> container = registry[containerTag];
-  NSInteger index = [container reactSubviews].count;
-  for (NSNumber *reactTag in reactTags) {
-    id<RCTComponent> view = registry[reactTag];
-    if (view) {
-      [container insertReactSubview:view atIndex:index++];
-    }
-  }
-}
-
 RCT_EXPORT_METHOD(manageChildren:(nonnull NSNumber *)containerReactTag
                   moveFromIndices:(NSNumberArray *)moveFromIndices
                   moveToIndices:(NSNumberArray *)moveToIndices
@@ -781,57 +754,39 @@ - (void)_manageChildren:(NSNumber *)containerReactTag
         removeAtIndices:(NSArray<NSNumber *> *)removeAtIndices
                registry:(NSMutableDictionary<NSNumber *, id<RCTComponent>> *)registry
 {
-  RCTAssert(moveFromIndices.count == moveToIndices.count,
-            @"moveFromIndices had size %tu, moveToIndices had size %tu",
-            moveFromIndices.count, moveToIndices.count);
+  id<RCTComponent> container = registry[containerReactTag];
+  RCTAssert(moveFromIndices.count == moveToIndices.count, @"moveFromIndices had size %tu, moveToIndices had size %tu", moveFromIndices.count, moveToIndices.count);
+  RCTAssert(addChildReactTags.count == addAtIndices.count, @"there should be at least one React child to add");
 
-  RCTAssert(addChildReactTags.count == addAtIndices.count,
-            @"addChildReactTags had size %tu, addAtIndices had size %tu",
-            addChildReactTags.count, addAtIndices.count);
+  // Removes (both permanent and temporary moves) are using "before" indices
+  NSArray<id<RCTComponent>> *permanentlyRemovedChildren =
+    [self _childrenToRemoveFromContainer:container atIndices:removeAtIndices];
+  NSArray<id<RCTComponent>> *temporarilyRemovedChildren =
+    [self _childrenToRemoveFromContainer:container atIndices:moveFromIndices];
+  [self _removeChildren:permanentlyRemovedChildren fromContainer:container];
+  [self _removeChildren:temporarilyRemovedChildren fromContainer:container];
 
-  id<RCTComponent> container = registry[containerReactTag];
-  NSArray<id<RCTComponent>> *views = [container reactSubviews];
-
-  // Get indices to insert/remove
-  NSUInteger purgeCount = removeAtIndices.count;
-  NSUInteger moveCount = moveFromIndices.count;
-  NSUInteger insertCount = addAtIndices.count;
-  NSUInteger removeCount = purgeCount + moveCount;
-  NSMutableArray<id<RCTComponent>> *toRemove = removeCount ? [NSMutableArray new] : nil;
-  NSMutableDictionary *toInsert = insertCount ? [NSMutableDictionary new] : nil;
-  for (NSNumber *index in removeAtIndices) {
-    id<RCTComponent> view = views[index.integerValue];
-    [toRemove addObject:view];
-    RCTTraverseViewNodes(registry[view.reactTag], ^(id<RCTComponent> subview) {
-      RCTAssert(![subview isReactRootView], @"Root views should not be unregistered");
-      if ([subview conformsToProtocol:@protocol(RCTInvalidating)]) {
-        [(id<RCTInvalidating>)subview invalidate];
-      }
-      [registry removeObjectForKey:subview.reactTag];
-      [_bridgeTransactionListeners removeObject:subview];
-    });
-  }
-  NSInteger i = 0;
-  for (NSNumber *index in moveFromIndices) {
-    id<RCTComponent> view = views[index.integerValue];
-    [toRemove addObject:view];
-    toInsert[moveToIndices[i]] = view;
-    i++;
-  }
-  i = 0;
-  for (NSNumber *reactTag in addChildReactTags) {
-    toInsert[addAtIndices[i]] = registry[reactTag];
-    i++;
-  }
+  [self _purgeChildren:permanentlyRemovedChildren fromRegistry:registry];
+
+  // TODO (#5906496): optimize all these loops - constantly calling array.count is not efficient
 
-  // Remove old views
-  for (id<RCTComponent> view in toRemove) {
-    [container removeReactSubview:view];
+  // Figure out what to insert - merge temporary inserts and adds
+  NSMutableDictionary *destinationsToChildrenToAdd = [NSMutableDictionary dictionary];
+  for (NSInteger index = 0, length = temporarilyRemovedChildren.count; index < length; index++) {
+    destinationsToChildrenToAdd[moveToIndices[index]] = temporarilyRemovedChildren[index];
+  }
+  for (NSInteger index = 0, length = addAtIndices.count; index < length; index++) {
+    id<RCTComponent> view = registry[addChildReactTags[index]];
+    if (view) {
+      destinationsToChildrenToAdd[addAtIndices[index]] = view;
+    }
   }
 
-  // Insert new views in ascending order
-  for (NSNumber *index in [toInsert.allKeys sortedArrayUsingSelector:@selector(compare:)]) {
-    [container insertReactSubview:toInsert[index] atIndex:index.integerValue];
+  NSArray<NSNumber *> *sortedIndices =
+    [destinationsToChildrenToAdd.allKeys sortedArrayUsingSelector:@selector(compare:)];
+  for (NSNumber *reactIndex in sortedIndices) {
+    [container insertReactSubview:destinationsToChildrenToAdd[reactIndex]
+                          atIndex:reactIndex.integerValue];
   }
 }
 

From 4661e59d1a9639f0a5c62d2c0dc88a6a19591b21 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Fri, 4 Dec 2015 03:22:43 -0800
Subject: [PATCH 0237/1411] For clippedSubViews, pass down the opportunity for
 children views to update their clipping if they intersect at all

Reviewed By: astreet

Differential Revision: D2717903

fb-gh-sync-id: 8852a6d3ac3a329c4cad663e7f9f7093f9b6ae16
---
 .../java/com/facebook/react/views/view/ReactViewGroup.java    | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
index 9e2728db4e1e..478208fab215 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
@@ -304,8 +304,8 @@ private void updateSubviewClipStatus(Rect clippingRect, int idx, int clippedSoFa
       super.addViewInLayout(child, idx - clippedSoFar, sDefaultLayoutParam, true);
       invalidate();
       needUpdateClippingRecursive = true;
-    } else if (intersects && !clippingRect.contains(sHelperRect)) {
-      // View is partially clipped.
+    } else if (intersects) {
+      // If there is any intersection we need to inform the child to update its clipping rect
       needUpdateClippingRecursive = true;
     }
     if (needUpdateClippingRecursive) {

From c1849e7f4b0a36692ff45cf8cbcfd7b37aba74c4 Mon Sep 17 00:00:00 2001
From: Matt Revell <mattrevell82@me.com>
Date: Fri, 4 Dec 2015 06:56:41 -0800
Subject: [PATCH 0238/1411] Fix an issue with unsafe picker access to
 setNativeProps.

Summary:
Fixing an issue where PickerIOS and DatePicker are being accessed unsafely, As a side effect we are also using ref callbacks as oppose to strings.

Fixed after spotting an issue in our app where the picker is closed and the callback attempts to update native props for an item that no longer exists.
Closes https://github.com/facebook/react-native/pull/3920

Reviewed By: svcscm

Differential Revision: D2663634

Pulled By: nicklockwood

fb-gh-sync-id: 813b32a038f59864401d5d3985c7ea32f5e13301
---
 Libraries/Components/DatePicker/DatePickerIOS.ios.js | 8 +++-----
 Libraries/Picker/PickerIOS.ios.js                    | 8 +++-----
 2 files changed, 6 insertions(+), 10 deletions(-)

diff --git a/Libraries/Components/DatePicker/DatePickerIOS.ios.js b/Libraries/Components/DatePicker/DatePickerIOS.ios.js
index ede2500ee5c2..e42b6ac59956 100644
--- a/Libraries/Components/DatePicker/DatePickerIOS.ios.js
+++ b/Libraries/Components/DatePicker/DatePickerIOS.ios.js
@@ -22,8 +22,6 @@ var View = require('View');
 
 var requireNativeComponent = require('requireNativeComponent');
 
-var DATEPICKER = 'datepicker';
-
 type DefaultProps = {
   mode: 'date' | 'time' | 'datetime';
 };
@@ -108,8 +106,8 @@ var DatePickerIOS = React.createClass({
     // certain values. In other words, the embedder of this component should
     // be the source of truth, not the native component.
     var propsTimeStamp = this.props.date.getTime();
-    if (nativeTimeStamp !== propsTimeStamp) {
-      this.refs[DATEPICKER].setNativeProps({
+    if (this._picker && nativeTimeStamp !== propsTimeStamp) {
+      this._picker.setNativeProps({
         date: propsTimeStamp,
       });
     }
@@ -120,7 +118,7 @@ var DatePickerIOS = React.createClass({
     return (
       <View style={props.style}>
         <RCTDatePickerIOS
-          ref={DATEPICKER}
+          ref={ picker => this._picker = picker }
           style={styles.datePickerIOS}
           date={props.date.getTime()}
           maximumDate={
diff --git a/Libraries/Picker/PickerIOS.ios.js b/Libraries/Picker/PickerIOS.ios.js
index 5c245397d0b0..ffda1f57d174 100644
--- a/Libraries/Picker/PickerIOS.ios.js
+++ b/Libraries/Picker/PickerIOS.ios.js
@@ -21,8 +21,6 @@ var View = require('View');
 
 var requireNativeComponent = require('requireNativeComponent');
 
-var PICKER = 'picker';
-
 var PickerIOS = React.createClass({
   mixins: [NativeMethodsMixin],
 
@@ -57,7 +55,7 @@ var PickerIOS = React.createClass({
     return (
       <View style={this.props.style}>
         <RCTPickerIOS
-          ref={PICKER}
+          ref={ picker => this._picker = picker }
           style={styles.pickerIOS}
           items={this.state.items}
           selectedIndex={this.state.selectedIndex}
@@ -81,8 +79,8 @@ var PickerIOS = React.createClass({
     // disallow/undo/mutate the selection of certain values. In other
     // words, the embedder of this component should be the source of
     // truth, not the native component.
-    if (this.state.selectedIndex !== event.nativeEvent.newIndex) {
-      this.refs[PICKER].setNativeProps({
+    if (this._picker && this.state.selectedIndex !== event.nativeEvent.newIndex) {
+      this._picker.setNativeProps({
         selectedIndex: this.state.selectedIndex
       });
     }

From dff8f53664009f49756c79f5f7c4982eaa39a5c3 Mon Sep 17 00:00:00 2001
From: James Ide <ide@jameside.com>
Date: Fri, 4 Dec 2015 06:43:03 -0800
Subject: [PATCH 0239/1411] Support plugins that conform to ES6 modules

Summary:
ES6 modules export an object with a property called `default`. See Babel itself for how this is handled: https://github.com/babel/babel/commit/b5b7e346a04c99da8793e2c65cc3b3c7c720253d
Closes https://github.com/facebook/react-native/pull/4513

Reviewed By: svcscm

Differential Revision: D2715512

Pulled By: mkonicek

fb-gh-sync-id: 40e5ea35adcdb66806a4895578d637cd72538619
---
 packager/transformer.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/packager/transformer.js b/packager/transformer.js
index 4700407c9368..70dde7702c28 100644
--- a/packager/transformer.js
+++ b/packager/transformer.js
@@ -48,6 +48,7 @@ function transform(src, filename, options) {
     // Only resolve the plugin if it's a string reference.
     if (typeof plugin[0] === 'string') {
       plugin[0] = require(`babel-plugin-${plugin[0]}`);
+      plugin[0] = plugin[0].__esModule ? plugin[0].default : plugin[0];
     }
     return plugin;
   });

From dde55c30eaf549f1bbab9812a469c42863ea082a Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Fri, 4 Dec 2015 06:59:14 -0800
Subject: [PATCH 0240/1411] This Fixes scroll to top and resigning first
 responder

Reviewed By: tadeuzagallo

Differential Revision: D2713488

fb-gh-sync-id: 99b2646f7bf8a3ee889bbb856c298beed6817321
---
 Libraries/Text/RCTTextView.m | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Libraries/Text/RCTTextView.m b/Libraries/Text/RCTTextView.m
index eda22a421e0c..6c62006927a5 100644
--- a/Libraries/Text/RCTTextView.m
+++ b/Libraries/Text/RCTTextView.m
@@ -81,6 +81,7 @@ - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
     _textView.delegate = self;
 
     _scrollView = [[UIScrollView alloc] initWithFrame:CGRectZero];
+    _scrollView.scrollsToTop = NO;
     [_scrollView addSubview:_textView];
 
     _previousSelectionRange = _textView.selectedTextRange;

From c71811e49100ea12e08e609d90d74868f4b06d5b Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Fri, 4 Dec 2015 07:28:09 -0800
Subject: [PATCH 0241/1411] Added Circle CI integration to run Android unit
 tests

Summary:
A few caveats before accepting:
- Do I need to squash commits?
- Need to set up new Circle CI account connected to FB react-native repo
- After that replace tokens and links to the new ones

Setting up Integration tests should be straight forward next week https://circleci.com/docs/android
Closes https://github.com/facebook/react-native/pull/4566

Reviewed By: svcscm

Differential Revision: D2723119

Pulled By: androidtrunkagent

fb-gh-sync-id: 2c4a46b206f15f36d94d1b10ff9e339f5182782b
---
 circle.yml | 12 ++++++++++++
 1 file changed, 12 insertions(+)
 create mode 100644 circle.yml

diff --git a/circle.yml b/circle.yml
new file mode 100644
index 000000000000..51feb2c00a29
--- /dev/null
+++ b/circle.yml
@@ -0,0 +1,12 @@
+machine:
+  node:
+    version: 5.1.0
+
+dependencies:
+  pre:
+  - npm install -g npm@3.2
+
+test:
+  override:
+    # gradle is flaky in CI envs, found a solution here http://stackoverflow.com/questions/28409608/gradle-assembledebug-and-predexdebug-fail-with-circleci
+    - TERM=dumb ./gradlew cleanTest test -PpreDexEnable=false -Pcom.android.build.threadPoolSize=1 -Dorg.gradle.parallel=false -Dorg.gradle.jvmargs="-Xms512m -Xmx512m" -Dorg.gradle.daemon=false

From f4c286f7ac0665edc3027e952d3b445703918c9c Mon Sep 17 00:00:00 2001
From: SangYeob Bono Yu <deminoth@gmail.com>
Date: Fri, 4 Dec 2015 08:05:11 -0800
Subject: [PATCH 0242/1411] Add support for Universal Links

Summary:
Adds support for [Universal Links](https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/AppSearch/UniversalLinks.html).
Closes https://github.com/facebook/react-native/pull/4109

Reviewed By: svcscm

Differential Revision: D2658105

Pulled By: nicklockwood

fb-gh-sync-id: 7d94564f64cda7d31c79cf8f4c450ed2387057be
---
 Libraries/LinkingIOS/LinkingIOS.js       | 21 +++++++++++++++++----
 Libraries/LinkingIOS/RCTLinkingManager.h |  4 ++++
 Libraries/LinkingIOS/RCTLinkingManager.m | 17 ++++++++++++++++-
 3 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/Libraries/LinkingIOS/LinkingIOS.js b/Libraries/LinkingIOS/LinkingIOS.js
index 7ee6ace38ce0..1d186ccbf21c 100644
--- a/Libraries/LinkingIOS/LinkingIOS.js
+++ b/Libraries/LinkingIOS/LinkingIOS.js
@@ -43,9 +43,22 @@ var DEVICE_NOTIF_EVENT = 'openURL';
  * execution you'll need to add the following lines to you `*AppDelegate.m`:
  *
  * ```
- * - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
- *   return [RCTLinkingManager application:application openURL:url sourceApplication:sourceApplication annotation:annotation];
+ * - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
+ *   sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
+ * {
+ *   return [RCTLinkingManager application:application openURL:url
+ *                       sourceApplication:sourceApplication annotation:annotation];
  * }
+ *
+ * // Only if your app is using [Universal Links](https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/AppSearch/UniversalLinks.html).
+ * - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity
+ *  restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
+ * {
+ *  return [RCTLinkingManager application:application
+ *                   continueUserActivity:userActivity
+ *                     restorationHandler:restorationHandler];
+ * }
+ *
  * ```
  *
  * And then on your React component you'll be able to listen to the events on
@@ -71,7 +84,7 @@ var DEVICE_NOTIF_EVENT = 'openURL';
  * LinkingIOS.openURL(url)
  * ```
  *
- * If you want to check if any installed app can handle a given URL beforehand you can call
+ * If you want to check if any installed app can handle a given URL beforehand, call
  * ```
  * LinkingIOS.canOpenURL(url, (supported) => {
  *   if (!supported) {
@@ -130,7 +143,7 @@ class LinkingIOS {
    * Determine whether or not an installed app can handle a given URL.
    * The callback function will be called with `bool supported` as the only argument
    *
-   * NOTE: As of iOS 9, your app needs to provide a `LSApplicationQueriesSchemes` key
+   * NOTE: As of iOS 9, your app needs to provide the `LSApplicationQueriesSchemes` key
    * inside `Info.plist`.
    */
   static canOpenURL(url: string, callback: Function) {
diff --git a/Libraries/LinkingIOS/RCTLinkingManager.h b/Libraries/LinkingIOS/RCTLinkingManager.h
index caa3aa2a3a92..092ca990b8a1 100644
--- a/Libraries/LinkingIOS/RCTLinkingManager.h
+++ b/Libraries/LinkingIOS/RCTLinkingManager.h
@@ -18,4 +18,8 @@
   sourceApplication:(NSString *)sourceApplication
          annotation:(id)annotation;
 
++ (BOOL)application:(UIApplication *)application
+continueUserActivity:(NSUserActivity *)userActivity
+  restorationHandler:(void (^)(NSArray *))restorationHandler;
+
 @end
diff --git a/Libraries/LinkingIOS/RCTLinkingManager.m b/Libraries/LinkingIOS/RCTLinkingManager.m
index 96c01ca2c47c..749d2c27ad30 100644
--- a/Libraries/LinkingIOS/RCTLinkingManager.m
+++ b/Libraries/LinkingIOS/RCTLinkingManager.m
@@ -54,6 +54,19 @@ + (BOOL)application:(UIApplication *)application
   return YES;
 }
 
++ (BOOL)application:(UIApplication *)application
+continueUserActivity:(NSUserActivity *)userActivity
+  restorationHandler:(void (^)(NSArray *))restorationHandler
+{
+  if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
+    NSDictionary *payload = @{@"url": userActivity.webpageURL.absoluteString};
+    [[NSNotificationCenter defaultCenter] postNotificationName:RCTOpenURLNotification
+                                                        object:self
+                                                      userInfo:payload];
+  }
+  return YES;
+}
+
 - (void)handleOpenURLNotification:(NSNotification *)notification
 {
   [_bridge.eventDispatcher sendDeviceEventWithName:@"openURL"
@@ -62,6 +75,7 @@ - (void)handleOpenURLNotification:(NSNotification *)notification
 
 RCT_EXPORT_METHOD(openURL:(NSURL *)URL)
 {
+  // TODO: we should really return success/failure via a callback here
   // Doesn't really matter what thread we call this on since it exits the app
   [RCTSharedApplication() openURL:URL];
 }
@@ -72,7 +86,8 @@ - (void)handleOpenURLNotification:(NSNotification *)notification
   if (RCTRunningInAppExtension()) {
     // Technically Today widgets can open urls, but supporting that would require
     // a reference to the NSExtensionContext
-    callback(@[@(NO)]);
+    callback(@[@NO]);
+    return;
   }
 
   // This can be expensive, so we deliberately don't call on main thread

From 383d991c40d8d4402405f5a427584cc6abf3dd24 Mon Sep 17 00:00:00 2001
From: "glevi@fb.com" <glevi@fb.com>
Date: Fri, 4 Dec 2015 11:52:05 -0800
Subject: [PATCH 0243/1411] Fix flow errors in fbobjc

Reviewed By: jeffmo

Differential Revision: D2724169

fb-gh-sync-id: d2736ce2550fe8bf45c18bce7d89a9cb5c98cb87
---
 Libraries/Components/DatePicker/DatePickerIOS.ios.js | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Libraries/Components/DatePicker/DatePickerIOS.ios.js b/Libraries/Components/DatePicker/DatePickerIOS.ios.js
index e42b6ac59956..3516ae35d003 100644
--- a/Libraries/Components/DatePicker/DatePickerIOS.ios.js
+++ b/Libraries/Components/DatePicker/DatePickerIOS.ios.js
@@ -36,6 +36,9 @@ type Event = Object;
  * source of truth.
  */
 var DatePickerIOS = React.createClass({
+  // TOOD: Put a better type for _picker
+  _picker: (undefined: ?$FlowFixMe),
+
   mixins: [NativeMethodsMixin],
 
   propTypes: {

From fa884ee5e656b8cb03d000d49f1b1456a7b21784 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Fri, 4 Dec 2015 20:42:19 -0800
Subject: [PATCH 0244/1411] Fix Y-coord on touches

Summary:
public

D2670028 updated the x/y positions of touch events to be relative to the window, but measure still uses the location on the screen. Therefore, in Touchable.js, we were seeing taps get inproperly invalidated because they were erroneously considered outside of the touch rect. This diff moves back to the old version of pageX/Y on touch events that's compatible with the current version of measure.

Reviewed By: nicklockwood

Differential Revision: D2724917

fb-gh-sync-id: 978ae26fcaa23c47a4f619e2b7ff2d078388ae95
---
 .../react/uimanager/events/TouchesHelper.java | 42 +++++++------------
 1 file changed, 16 insertions(+), 26 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchesHelper.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchesHelper.java
index d312a402026b..e431fa7aeaeb 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchesHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchesHelper.java
@@ -35,35 +35,25 @@
    * given {@param event} instance. This method use {@param reactTarget} parameter to set as a
    * target view id associated with current gesture.
    */
-  private static WritableArray createsPointersArray(int reactTarget, TouchEvent event) {
+  private static WritableArray createsPointersArray(int reactTarget, TouchEvent touchEvent) {
+    MotionEvent event = touchEvent.getMotionEvent();
+
     WritableArray touches = Arguments.createArray();
-    MotionEvent motionEvent = event.getMotionEvent();
-
-    // Calculate the coordinates for the target view.
-    // The MotionEvent contains the X,Y of the touch in the coordinate space of the root view
-    // The TouchEvent contains the X,Y of the touch in the coordinate space of the target view
-    // Subtracting them allows us to get the coordinates of the target view's top left corner
-    // We then use this when computing the view specific touches below
-    // Since only one view is actually handling even multiple touches, the values are all relative
-    // to this one target view.
-    float targetViewCoordinateX = motionEvent.getX() - event.getViewX();
-    float targetViewCoordinateY = motionEvent.getY() - event.getViewY();
-
-    for (int index = 0; index < motionEvent.getPointerCount(); index++) {
+
+    // Calculate raw-to-relative offset as getRawX() and getRawY() can only return values for the
+    // pointer at index 0. We use those value to calculate "raw" coordinates for other pointers
+    float offsetX = event.getRawX() - event.getX();
+    float offsetY = event.getRawY() - event.getY();
+
+    for (int index = 0; index < event.getPointerCount(); index++) {
       WritableMap touch = Arguments.createMap();
-      // pageX,Y values are relative to the RootReactView
-      // the motionEvent already contains coordinates in that view
-      touch.putDouble(PAGE_X_KEY, PixelUtil.toDIPFromPixel(motionEvent.getX(index)));
-      touch.putDouble(PAGE_Y_KEY, PixelUtil.toDIPFromPixel(motionEvent.getY(index)));
-      // locationX,Y values are relative to the target view
-      // To compute the values for the view, we subtract that views location from the event X,Y
-      float locationX = motionEvent.getX(index) - targetViewCoordinateX;
-      float locationY = motionEvent.getY(index) - targetViewCoordinateY;
-      touch.putDouble(LOCATION_X_KEY, PixelUtil.toDIPFromPixel(locationX));
-      touch.putDouble(LOCATION_Y_KEY, PixelUtil.toDIPFromPixel(locationY));
+      touch.putDouble(PAGE_X_KEY, PixelUtil.toDIPFromPixel(event.getX(index) + offsetX));
+      touch.putDouble(PAGE_Y_KEY, PixelUtil.toDIPFromPixel(event.getY(index) + offsetY));
+      touch.putDouble(LOCATION_X_KEY, PixelUtil.toDIPFromPixel(event.getX(index)));
+      touch.putDouble(LOCATION_Y_KEY, PixelUtil.toDIPFromPixel(event.getY(index)));
       touch.putInt(TARGET_KEY, reactTarget);
-      touch.putDouble(TIMESTAMP_KEY, motionEvent.getEventTime());
-      touch.putDouble(POINTER_IDENTIFIER_KEY, motionEvent.getPointerId(index));
+      touch.putDouble(TIMESTAMP_KEY, event.getEventTime());
+      touch.putDouble(POINTER_IDENTIFIER_KEY, event.getPointerId(index));
       touches.pushMap(touch);
     }
 

From b89e14ab95098fb13d87fa69e16576ce104f8ac6 Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Sat, 5 Dec 2015 10:46:08 +0530
Subject: [PATCH 0245/1411] Improve docs for Building from source

---
 docs/AndroidBuildingFromSource.md | 24 +++++++++++++++++++-----
 1 file changed, 19 insertions(+), 5 deletions(-)

diff --git a/docs/AndroidBuildingFromSource.md b/docs/AndroidBuildingFromSource.md
index b0fd0896a590..b09c53811208 100644
--- a/docs/AndroidBuildingFromSource.md
+++ b/docs/AndroidBuildingFromSource.md
@@ -37,7 +37,9 @@ ndk.dir=/Users/your_unix_name/android-ndk/android-ndk-r10e
 
 ## Building the source
 
-1. Install `react-native` from your fork. For example, to install the master branch from the offcial repo, run the following:
+#### 1. Installing the fork
+
+First, you need to install `react-native` from your fork. For example, to install the master branch from the official repo, run the following:
 
 ```sh
 npm install --save github:facebook/react-native#master
@@ -45,7 +47,10 @@ npm install --save github:facebook/react-native#master
 
 Alternatively, you can clone the repo to your `node_modules` directory and run `npm install` inside the cloned repo.
 
-2. Add `gradle-download-task` as dependency in `android/build.gradle`:
+
+#### 2. Adding missing dependencies
+
+Add `gradle-download-task` as dependency in `android/build.gradle`:
 
 ```gradle
 ...
@@ -59,7 +64,10 @@ Alternatively, you can clone the repo to your `node_modules` directory and run `
 ...
 ```
 
-3. Add the `:ReactAndroid` project in `android/settings.gradle`:
+
+#### 3. Adding the `:ReactAndroid` project
+
+Add the `:ReactAndroid` project in `android/settings.gradle`:
 
 ```gradle
 ...
@@ -69,7 +77,8 @@ project(':ReactAndroid').projectDir = new File(rootProject.projectDir, '../node_
 ...
 ```
 
-4. Modify your `android/app/build.gradle` to use the `:ReactAndroid` project instead of the pre-compiled library, e.g. - replace `compile 'com.facebook.react:react-native:0.16.+'` with `compile project(':ReactAndroid')`:
+
+Modify your `android/app/build.gradle` to use the `:ReactAndroid` project instead of the pre-compiled library, e.g. - replace `compile 'com.facebook.react:react-native:0.16.+'` with `compile project(':ReactAndroid')`:
 
 ```gradle
 ...
@@ -84,7 +93,12 @@ dependencies {
 ...
 ```
 
-5. If you use 3rd-party React Native modules, modify your `android/app/build.gradle` to override their dependencies so that they don't bundle the pre-compiled library, e.g. - replace `compile project(':react-native-custom-module')` with:
+
+#### 4. Making 3rd-party modules use your fork
+
+If you use 3rd-party React Native modules, you need to override their dependencies so that they don't bundle the pre-compiled library. Otherwise you'll get an error while compiling - `Error: more than one library with package name 'com.facebook.react'`.
+
+Modify your `android/app/build.gradle` and replace `compile project(':react-native-custom-module')` with:
 
 ```gradle
 compile(project(':react-native-custom-module')) {

From 55d1db6768c9b39a316b0a6054e768e85cdcf8ee Mon Sep 17 00:00:00 2001
From: Christopher Dro <hello@blick-labs.com>
Date: Sat, 5 Dec 2015 12:19:58 -0800
Subject: [PATCH 0246/1411] [Docs] Fix broken links for Testing.md - Closes
 #4582.

---
 docs/Testing.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/Testing.md b/docs/Testing.md
index 56ffd67892e4..436de2c95dca 100644
--- a/docs/Testing.md
+++ b/docs/Testing.md
@@ -56,12 +56,12 @@ Note: you may have to install/upgrade/link Node.js and other parts of your envir
 
 ## Integration Tests (iOS only)
 
-React Native provides facilities to make it easier to test integrated components that require both native and JS components to communicate across the bridge.  The two main components are `RCTTestRunner` and `RCTTestModule`.  `RCTTestRunner` sets up the ReactNative environment and provides facilities to run the tests as `XCTestCase`s in Xcode (`runTest:module` is the simplest method).  `RCTTestModule` is exported to JS as `NativeModules.TestModule`.  The tests themselves are written in JS, and must call `TestModule.markTestCompleted()` when they are done, otherwise the test will timeout and fail.  Test failures are primarily indicated by throwing a JS exception.  It is also possible to test error conditions with `runTest:module:initialProps:expectErrorRegex:` or `runTest:module:initialProps:expectErrorBlock:` which will expect an error to be thrown and verify the error matches the provided criteria.  See [`IntegrationTestHarnessTest.js`](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/UIExplorerIntegrationTests/js/IntegrationTestHarnessTest.js), [`IntegrationTests.m`](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/UIExplorerIntegrationTests/IntegrationTests.m), and [IntegrationTestsApp.js](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/UIExplorerIntegrationTests/js/IntegrationTestsApp.js) for example usage and integration points.
+React Native provides facilities to make it easier to test integrated components that require both native and JS components to communicate across the bridge.  The two main components are `RCTTestRunner` and `RCTTestModule`.  `RCTTestRunner` sets up the ReactNative environment and provides facilities to run the tests as `XCTestCase`s in Xcode (`runTest:module` is the simplest method).  `RCTTestModule` is exported to JS as `NativeModules.TestModule`.  The tests themselves are written in JS, and must call `TestModule.markTestCompleted()` when they are done, otherwise the test will timeout and fail.  Test failures are primarily indicated by throwing a JS exception.  It is also possible to test error conditions with `runTest:module:initialProps:expectErrorRegex:` or `runTest:module:initialProps:expectErrorBlock:` which will expect an error to be thrown and verify the error matches the provided criteria.  See [`IntegrationTestHarnessTest.js`](https://github.com/facebook/react-native/blob/master/IntegrationTests/IntegrationTestHarnessTest.js), [`UIExplorerIntegrationTests.m`](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerIntegrationTests.m), and [IntegrationTestsApp.js](https://github.com/facebook/react-native/blob/master/IntegrationTests/IntegrationTestsApp.js) for example usage and integration points.
 
 You can run integration tests locally with cmd+U in the IntegrationTest and UIExplorer apps in Xcode.
 
 ## Snapshot Tests (iOS only)
 
-A common type of integration test is the snapshot test.  These tests render a component, and verify snapshots of the screen against reference images using `TestModule.verifySnapshot()`, using the [`FBSnapshotTestCase`](https://github.com/facebook/ios-snapshot-test-case) library behind the scenes.  Reference images are recorded by setting `recordMode = YES` on the `RCTTestRunner`, then running the tests.  Snapshots will differ slightly between 32 and 64 bit, and various OS versions, so it's recommended that you enforce tests are run with the correct configuration.  It's also highly recommended that all network data be mocked out, along with other potentially troublesome dependencies.  See [`SimpleSnapshotTest`](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/UIExplorerIntegrationTests/js/SimpleSnapshotTest.js) for a basic example.
+A common type of integration test is the snapshot test.  These tests render a component, and verify snapshots of the screen against reference images using `TestModule.verifySnapshot()`, using the [`FBSnapshotTestCase`](https://github.com/facebook/ios-snapshot-test-case) library behind the scenes.  Reference images are recorded by setting `recordMode = YES` on the `RCTTestRunner`, then running the tests.  Snapshots will differ slightly between 32 and 64 bit, and various OS versions, so it's recommended that you enforce tests are run with the correct configuration.  It's also highly recommended that all network data be mocked out, along with other potentially troublesome dependencies.  See [`SimpleSnapshotTest`](https://github.com/facebook/react-native/blob/master/IntegrationTests/SimpleSnapshotTest.js) for a basic example.
 
 If you make a change that affects a snapshot test in a PR, such as adding a new example case to one of the examples that is snapshotted, you'll need to re-record the snapshotshot reference image.  To do this, simply change to `_runner.recordMode = YES;` in [UIExplorer/UIExplorerSnapshotTests.m](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerSnapshotTests.m#L42), re-run the failing tests, then flip record back to `NO` and submit/update your PR and wait to see if the Travis build passes.

From ba81517150e7770de97be89bbd5b5e78f44eb9ba Mon Sep 17 00:00:00 2001
From: jato <jatobrown@gmail.com>
Date: Sat, 5 Dec 2015 13:29:07 -0800
Subject: [PATCH 0247/1411] fixes minor typo

---
 docs/CommunicationIOS.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/CommunicationIOS.md b/docs/CommunicationIOS.md
index 686cf0059055..7b23c80eeb15 100644
--- a/docs/CommunicationIOS.md
+++ b/docs/CommunicationIOS.md
@@ -11,7 +11,7 @@ In [Integrating with Existing Apps guide](http://facebook.github.io/react-native
 
 ## Introduction
 
-React Native is inspired by React, so the basic idea of the information flow is similar. The flow in React is one-directional. We maintain a hierarchy of components, in which each component depends only on its parent and own internal state. We do this with properties: data is passed from a parent to its children in a top-down manner.If we have an ancestor component that rely on the state of its descendant, the recommended solution would be to pass down a callback that would be used by the descendant to update the ancestor.
+React Native is inspired by React, so the basic idea of the information flow is similar. The flow in React is one-directional. We maintain a hierarchy of components, in which each component depends only on its parent and own internal state. We do this with properties: data is passed from a parent to its children in a top-down manner. If we have an ancestor component that rely on the state of its descendant, the recommended solution would be to pass down a callback that would be used by the descendant to update the ancestor.
 
 The same concept applies to React Native. As long as we are building our application purely within the framework, we can drive our app with properties and callbacks. But, when we mix React Native and native components, we need some special, cross-language mechanisms that would allow us to pass information between them.
 

From 31125b2ed7be12c51e8b0308b3fecbaee567b884 Mon Sep 17 00:00:00 2001
From: Mihai Giurgeanu <mihaigiurgeanu@MacBook-Mihai.local>
Date: Sat, 5 Dec 2015 14:56:41 -0800
Subject: [PATCH 0248/1411] Android - Fixing #4392

Summary:
This is just an workaround for making UIExplorer work in Android.
Closes https://github.com/facebook/react-native/pull/4405

Reviewed By: svcscm

Differential Revision: D2727452

Pulled By: tadeuzagallo

fb-gh-sync-id: af48fb8c462ab04874cfdb96c0fd4409bf6d92c3
---
 Libraries/Components/MapView/MapView.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/Libraries/Components/MapView/MapView.js b/Libraries/Components/MapView/MapView.js
index 74f2774d68fc..012f5790f75a 100644
--- a/Libraries/Components/MapView/MapView.js
+++ b/Libraries/Components/MapView/MapView.js
@@ -15,7 +15,8 @@ var EdgeInsetsPropType = require('EdgeInsetsPropType');
 var Image = require('Image');
 var NativeMethodsMixin = require('NativeMethodsMixin');
 var Platform = require('Platform');
-var RCTMapConstants = require('NativeModules').UIManager.RCTMap.Constants;
+var RCTMap = require('UIManager').RCTMap;
+var RCTMapConstants = RCTMap && RCTMap.Constants;
 var React = require('React');
 var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
 var View = require('View');

From ca9f0adee22280f20ba96563be1553b7a975923f Mon Sep 17 00:00:00 2001
From: Atticus White <contact@atticuswhite.com>
Date: Sat, 5 Dec 2015 18:46:43 -0800
Subject: [PATCH 0249/1411] Improve Modal docs describing iOS only support

Summary:
Adds a note that the `Modal` component is only available in iOS.

I hit a bit of a pickle this weekend after realizing a handful of components I built will have to be rewritten. Unfortunately there's no notes in the documentation that the support is limited. Hopefully this can contribute towards avoiding those situations
Closes https://github.com/facebook/react-native/pull/4592

Reviewed By: svcscm

Differential Revision: D2727634

Pulled By: androidtrunkagent

fb-gh-sync-id: 2d0efcca8e17d16cf63d592e235261cea63e59ea
---
 Libraries/Modal/Modal.js | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Libraries/Modal/Modal.js b/Libraries/Modal/Modal.js
index dfbfdb685542..9df6208d7860 100644
--- a/Libraries/Modal/Modal.js
+++ b/Libraries/Modal/Modal.js
@@ -31,6 +31,8 @@ var RCTModalHostView = requireNativeComponent('RCTModalHostView', null);
  * Navigator instead of Modal. With a top-level Navigator, you have more control
  * over how to present the modal scene over the rest of your app by using the
  * configureScene property.
+ *
+ * This component is only available in iOS at this time.
  */
 class Modal extends React.Component {
   render(): ?ReactElement {

From fb4f05ed7b8a9129e97cbe6c25ce4310024816b7 Mon Sep 17 00:00:00 2001
From: Brent Vatne <brentvatne@gmail.com>
Date: Sun, 6 Dec 2015 15:09:22 -0800
Subject: [PATCH 0250/1411] Update KnownIssues.md

---
 docs/KnownIssues.md | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/docs/KnownIssues.md b/docs/KnownIssues.md
index ef7a9db61427..42d7528439c0 100644
--- a/docs/KnownIssues.md
+++ b/docs/KnownIssues.md
@@ -25,8 +25,7 @@ Our provisional plan for common views and modules includes:
 ART
 Maps
 Modal
-Spinner
-Swipe Refresh
+Spinner ([not a loading indicator](http://developer.android.com/guide/topics/ui/controls/spinner.html))
 Webview
 ```
 
@@ -38,7 +37,6 @@ App State
 Camera Roll
 Dialog
 Media
-Net Info
 Pasteboard
 PushNotificationIOS
 ```

From f1a575eb306872757f47b1f4007ad83f26c111f8 Mon Sep 17 00:00:00 2001
From: Brent Vatne <brentvatne@gmail.com>
Date: Sun, 6 Dec 2015 15:39:37 -0800
Subject: [PATCH 0251/1411] Update KnownIssues.md

---
 docs/KnownIssues.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/KnownIssues.md b/docs/KnownIssues.md
index 42d7528439c0..ad112ecce603 100644
--- a/docs/KnownIssues.md
+++ b/docs/KnownIssues.md
@@ -25,7 +25,7 @@ Our provisional plan for common views and modules includes:
 ART
 Maps
 Modal
-Spinner ([not a loading indicator](http://developer.android.com/guide/topics/ui/controls/spinner.html))
+Spinner (http://developer.android.com/guide/topics/ui/controls/spinner.html)
 Webview
 ```
 

From a38ce5c5705a18379d3f54297fad3b5b241611a0 Mon Sep 17 00:00:00 2001
From: Olivier Notteghem <oli@fb.com>
Date: Sun, 6 Dec 2015 15:44:47 -0800
Subject: [PATCH 0252/1411] match RN attachment images Feed experience with
 Native with spinner/fade in

Reviewed By: astreet

Differential Revision: D2722917

fb-gh-sync-id: a09b9a1a4b9a19b94471d8e93ec5bde53af7da06
---
 Libraries/Image/Image.android.js              | 16 +++++++++
 .../react/views/image/ReactImageManager.java  |  6 ++++
 .../react/views/image/ReactImageView.java     | 36 +++++++++++++++----
 3 files changed, 51 insertions(+), 7 deletions(-)

diff --git a/Libraries/Image/Image.android.js b/Libraries/Image/Image.android.js
index 9d9558c9687f..e73a68b84f0f 100644
--- a/Libraries/Image/Image.android.js
+++ b/Libraries/Image/Image.android.js
@@ -53,6 +53,7 @@ var resolveAssetSource = require('resolveAssetSource');
 
 var ImageViewAttributes = merge(ReactNativeViewAttributes.UIView, {
   src: true,
+  loadingIndicatorSrc: true,
   resizeMode: true,
   progressiveRenderingEnabled: true,
   fadeDuration: true,
@@ -74,6 +75,18 @@ var Image = React.createClass({
       // Opaque type returned by require('./image.jpg')
       PropTypes.number,
     ]).isRequired,
+    /**
+     * similarly to `source`, this property represents the resource used to render
+     * the loading indicator for the image, displayed until image is ready to be
+     * displayed, typically after when it got downloaded from network.
+     */
+    loadingIndicatorSource: PropTypes.oneOfType([
+      PropTypes.shape({
+        uri: PropTypes.string,
+      }),
+      // Opaque type returned by require('./image.jpg')
+      PropTypes.number,
+    ]),
     progressiveRenderingEnabled: PropTypes.bool,
     fadeDuration: PropTypes.number,
     /**
@@ -138,6 +151,7 @@ var Image = React.createClass({
 
   render: function() {
     var source = resolveAssetSource(this.props.source);
+    var loadingIndicatorSource = resolveAssetSource(this.props.loadingIndicatorSource);
 
     // As opposed to the ios version, here it render `null`
     // when no source or source.uri... so let's not break that.
@@ -155,6 +169,7 @@ var Image = React.createClass({
         style,
         shouldNotifyLoadEvents: !!(onLoadStart || onLoad || onLoadEnd),
         src: source.uri,
+        loadingIndicatorSrc: loadingIndicatorSource ? loadingIndicatorSource.uri : null,
       });
 
       if (nativeProps.children) {
@@ -197,6 +212,7 @@ var styles = StyleSheet.create({
 var cfg = {
   nativeOnly: {
     src: true,
+    loadingIndicatorSrc: true,
     defaultImageSrc: true,
     imageTag: true,
     progressHandlerRegistered: true,
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
index b0df41db0b3c..35cb706d3c00 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
@@ -73,6 +73,12 @@ public void setSource(ReactImageView view, @Nullable String source) {
     view.setSource(source);
   }
 
+  // In JS this is Image.props.loadingIndicatorSource.uri
+  @ReactProp(name = "loadingIndicatorSrc")
+  public void setLoadingIndicatorSource(ReactImageView view, @Nullable String source) {
+    view.setLoadingIndicatorSource(source);
+  }
+
   @ReactProp(name = "borderColor", customType = "Color")
   public void setBorderColor(ReactImageView view, @Nullable Integer borderColor) {
     if (borderColor == null) {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
index c889c81837da..b0c8b74267e0 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
@@ -15,6 +15,7 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Rect;
@@ -26,6 +27,7 @@
 
 import com.facebook.common.util.UriUtil;
 import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
+import com.facebook.drawee.drawable.AutoRotateDrawable;
 import com.facebook.drawee.controller.BaseControllerListener;
 import com.facebook.drawee.controller.ControllerListener;
 import com.facebook.drawee.controller.ForwardingControllerListener;
@@ -104,6 +106,7 @@ public void process(Bitmap output, Bitmap source) {
   }
 
   private @Nullable Uri mUri;
+  private @Nullable Drawable mLoadingImageDrawable;
   private int mBorderColor;
   private float mBorderWidth;
   private float mBorderRadius;
@@ -220,6 +223,13 @@ public void setSource(@Nullable String source) {
     mIsDirty = true;
   }
 
+  public void setLoadingIndicatorSource(@Nullable String name) {
+    Drawable drawable = getResourceDrawable(getContext(), name);
+    mLoadingImageDrawable =
+        drawable != null ? (Drawable) new AutoRotateDrawable(drawable, 1000) : null;
+    mIsDirty = true;
+  }
+
   public void setProgressiveRenderingEnabled(boolean enabled) {
     mProgressiveRenderingEnabled = enabled;
     // no worth marking as dirty if it already rendered..
@@ -244,6 +254,10 @@ public void maybeUpdateView() {
     GenericDraweeHierarchy hierarchy = getHierarchy();
     hierarchy.setActualImageScaleType(mScaleType);
 
+    if (mLoadingImageDrawable != null) {
+      hierarchy.setPlaceholderImage(mLoadingImageDrawable, ScalingUtils.ScaleType.CENTER);
+    }
+
     boolean usePostprocessorScaling =
         mScaleType != ScalingUtils.ScaleType.CENTER_CROP &&
         mScaleType != ScalingUtils.ScaleType.FOCUS_CROP;
@@ -322,18 +336,26 @@ private static boolean shouldResize(@Nullable Uri uri) {
     return uri != null && (UriUtil.isLocalContentUri(uri) || UriUtil.isLocalFileUri(uri));
   }
 
-  private static @Nullable Uri getResourceDrawableUri(Context context, @Nullable String name) {
+  private static int getResourceDrawableId(Context context, @Nullable String name) {
     if (name == null || name.isEmpty()) {
-      return null;
+      return 0;
     }
-    name = name.toLowerCase().replace("-", "_");
-    int resId = context.getResources().getIdentifier(
-        name,
+    return context.getResources().getIdentifier(
+        name.toLowerCase().replace("-", "_"),
         "drawable",
         context.getPackageName());
-    return new Uri.Builder()
+  }
+
+  private static @Nullable Drawable getResourceDrawable(Context context, @Nullable String name) {
+    int resId = getResourceDrawableId(context, name);
+    return resId > 0 ? context.getResources().getDrawable(resId) : null;
+  }
+
+  private static @Nullable Uri getResourceDrawableUri(Context context, @Nullable String name) {
+    int resId = getResourceDrawableId(context, name);
+    return resId > 0 ? new Uri.Builder()
         .scheme(UriUtil.LOCAL_RESOURCE_SCHEME)
         .path(String.valueOf(resId))
-        .build();
+        .build() : null;
   }
 }

From 69ce5ab5b822d0f789525772ba387d47e6a695cb Mon Sep 17 00:00:00 2001
From: Mike Armstrong <mikea@fb.com>
Date: Mon, 7 Dec 2015 03:47:39 -0800
Subject: [PATCH 0253/1411] JSC bindings for flow events

Reviewed By: astreet

Differential Revision: D2717887

fb-gh-sync-id: 40d03ac140669b8ebeb096917f2aba32fe260a1a
---
 .../src/main/jni/react/JSCTracing.cpp         | 134 ++++++++++++++----
 1 file changed, 109 insertions(+), 25 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/JSCTracing.cpp b/ReactAndroid/src/main/jni/react/JSCTracing.cpp
index fa786005ef62..d0bab2c420f0 100644
--- a/ReactAndroid/src/main/jni/react/JSCTracing.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCTracing.cpp
@@ -93,6 +93,7 @@ static JSValueRef nativeTraceBeginSection(
     JSValueRef* exception) {
   if (FBSYSTRACE_UNLIKELY(argumentCount < 2)) {
     // Could raise an exception here.
+    // TODO T9329825
     return JSValueMakeUndefined(ctx);
   }
 
@@ -129,6 +130,7 @@ static JSValueRef nativeTraceEndSection(
     JSValueRef* exception) {
   if (FBSYSTRACE_UNLIKELY(argumentCount < 1)) {
     // Could raise an exception here.
+    // TODO T9329825
     return JSValueMakeUndefined(ctx);
   }
 
@@ -160,6 +162,7 @@ static JSValueRef nativeTraceEndSection(
 
 static JSValueRef beginOrEndAsync(
     bool isEnd,
+    bool isFlow,
     JSContextRef ctx,
     JSObjectRef function,
     JSObjectRef thisObject,
@@ -168,6 +171,7 @@ static JSValueRef beginOrEndAsync(
     JSValueRef* exception) {
   if (FBSYSTRACE_UNLIKELY(argumentCount < 3)) {
     // Could raise an exception here.
+    // TODO T9329825
     return JSValueMakeUndefined(ctx);
   }
 
@@ -181,7 +185,7 @@ static JSValueRef beginOrEndAsync(
 
   // This uses an if-then-else instruction in ARMv7, which should be cheaper
   // than a full branch.
-  buf[pos++] = (isEnd ? 'F' : 'S');
+  buf[pos++] = ((isFlow) ? (isEnd ? 'f' : 's') : (isEnd ? 'F' : 'S'));
   pos += snprintf(buf + pos, sizeof(buf) - pos, "|%d|", getpid());
   // Skip the overflow check here because the int will be small.
   pos += copyTruncatedAsciiChars(buf + pos, sizeof(buf) - pos, ctx, arguments[1], FBSYSTRACE_MAX_SECTION_NAME_LENGTH);
@@ -190,7 +194,8 @@ static JSValueRef beginOrEndAsync(
   // I tried some trickery to avoid a branch here, but gcc did not cooperate.
   // We could consider changing the implementation to be lest branchy in the
   // future.
-  if (!isEnd) {
+  // This is not required for flow use an or to avoid introducing another branch
+  if (!(isEnd | isFlow)) {
     buf[pos++] = '<';
     buf[pos++] = '0';
     buf[pos++] = '>';
@@ -216,6 +221,44 @@ static JSValueRef beginOrEndAsync(
   return JSValueMakeUndefined(ctx);
 }
 
+static JSValueRef stageAsync(
+    bool isFlow,
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[],
+    JSValueRef* exception) {
+  if (FBSYSTRACE_UNLIKELY(argumentCount < 4)) {
+    // Could raise an exception here.
+    // TODO T9329825
+    return JSValueMakeUndefined(ctx);
+  }
+
+  uint64_t tag = tagFromJSValue(ctx, arguments[0], exception);
+  if (!fbsystrace_is_tracing(tag)) {
+    return JSValueMakeUndefined(ctx);
+  }
+
+  char buf[FBSYSTRACE_MAX_MESSAGE_LENGTH];
+  size_t pos = 0;
+
+  buf[pos++] = (isFlow ? 't' : 'T');
+  pos += snprintf(buf + pos, sizeof(buf) - pos, "|%d", getpid());
+  // Skip the overflow check here because the int will be small.
+
+  // Arguments are section name, cookie, and stage name.
+  // All added together, they still cannot cause an overflow.
+  for (int i = 1; i < 4; i++) {
+    buf[pos++] = '|';
+    pos += copyTruncatedAsciiChars(buf + pos, sizeof(buf) - pos, ctx, arguments[i], FBSYSTRACE_MAX_SECTION_NAME_LENGTH);
+  }
+
+  fbsystrace_trace_raw(buf, min(pos, sizeof(buf)-1));
+
+  return JSValueMakeUndefined(ctx);
+}
+
 static JSValueRef nativeTraceBeginAsyncSection(
     JSContextRef ctx,
     JSObjectRef function,
@@ -225,6 +268,7 @@ static JSValueRef nativeTraceBeginAsyncSection(
     JSValueRef* exception) {
   return beginOrEndAsync(
       false /* isEnd */,
+      false /* isFlow */,
       ctx,
       function,
       thisObject,
@@ -242,6 +286,7 @@ static JSValueRef nativeTraceEndAsyncSection(
     JSValueRef* exception) {
   return beginOrEndAsync(
       true /* isEnd */,
+      false /* isFlow */,
       ctx,
       function,
       thisObject,
@@ -257,32 +302,67 @@ static JSValueRef nativeTraceAsyncSectionStage(
     size_t argumentCount,
     const JSValueRef arguments[],
     JSValueRef* exception) {
-  if (FBSYSTRACE_UNLIKELY(argumentCount < 4)) {
-    // Could raise an exception here.
-    return JSValueMakeUndefined(ctx);
-  }
-
-  uint64_t tag = tagFromJSValue(ctx, arguments[0], exception);
-  if (!fbsystrace_is_tracing(tag)) {
-    return JSValueMakeUndefined(ctx);
-  }
-
-  char buf[FBSYSTRACE_MAX_MESSAGE_LENGTH];
-  size_t pos = 0;
-
-  pos += snprintf(buf + pos, sizeof(buf) - pos, "T|%d", getpid());
-  // Skip the overflow check here because the int will be small.
+  return stageAsync(
+      false /* isFlow */,
+      ctx,
+      function,
+      thisObject,
+      argumentCount,
+      arguments,
+      exception);
+}
 
-  // Arguments are section name, cookie, and stage name.
-  // All added together, they still cannot cause an overflow.
-  for (int i = 1; i < 4; i++) {
-    buf[pos++] = '|';
-    pos += copyTruncatedAsciiChars(buf + pos, sizeof(buf) - pos, ctx, arguments[i], FBSYSTRACE_MAX_SECTION_NAME_LENGTH);
-  }
+static JSValueRef nativeTraceBeginAsyncFlow(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[],
+    JSValueRef* exception) {
+  return beginOrEndAsync(
+      false /* isEnd */,
+      true /* isFlow */,
+      ctx,
+      function,
+      thisObject,
+      argumentCount,
+      arguments,
+      exception);
+}
 
-  fbsystrace_trace_raw(buf, min(pos, sizeof(buf)-1));
+static JSValueRef nativeTraceEndAsyncFlow(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[],
+    JSValueRef* exception) {
+  return beginOrEndAsync(
+      true /* isEnd */,
+      true /* isFlow */,
+      ctx,
+      function,
+      thisObject,
+      argumentCount,
+      arguments,
+      exception);
+}
 
-  return JSValueMakeUndefined(ctx);
+static JSValueRef nativeTraceAsyncFlowStage(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[],
+    JSValueRef* exception) {
+  return stageAsync(
+      true /* isFlow */,
+      ctx,
+      function,
+      thisObject,
+      argumentCount,
+      arguments,
+      exception);
 }
 
 static JSValueRef nativeTraceCounter(
@@ -294,6 +374,7 @@ static JSValueRef nativeTraceCounter(
     JSValueRef* exception) {
   if (FBSYSTRACE_UNLIKELY(argumentCount < 3)) {
     // Could raise an exception here.
+    // TODO T9329825
     return JSValueMakeUndefined(ctx);
   }
 
@@ -322,6 +403,9 @@ void addNativeTracingHooks(JSGlobalContextRef ctx) {
   installGlobalFunction(ctx, "nativeTraceBeginAsyncSection", nativeTraceBeginAsyncSection);
   installGlobalFunction(ctx, "nativeTraceEndAsyncSection", nativeTraceEndAsyncSection);
   installGlobalFunction(ctx, "nativeTraceAsyncSectionStage", nativeTraceAsyncSectionStage);
+  installGlobalFunction(ctx, "nativeTraceBeginAsyncFlow", nativeTraceBeginAsyncFlow);
+  installGlobalFunction(ctx, "nativeTraceEndAsyncFlow", nativeTraceEndAsyncFlow);
+  installGlobalFunction(ctx, "nativeTraceAsyncFlowStage", nativeTraceAsyncFlowStage);
   installGlobalFunction(ctx, "nativeTraceCounter", nativeTraceCounter);
 }
 

From 02ded6d0bb4f507db2cf637d49d291be3a38a3eb Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Mon, 7 Dec 2015 06:39:16 -0800
Subject: [PATCH 0254/1411] Preserve all return registers on x86_64 trampoline

Summary:
public

Only the first quad-word and floating point return registers were being preserved,
make sure to preserve the 2nd ones as well (`%rdx` and `%xmm1`)

Reviewed By: jspahrsummers

Differential Revision: D2727523

fb-gh-sync-id: d8176512d2dfb5f664f634ecaaf34510515506ea
---
 React/Profiler/RCTProfileTrampoline-x86_64.S | 27 ++++++++------------
 1 file changed, 11 insertions(+), 16 deletions(-)

diff --git a/React/Profiler/RCTProfileTrampoline-x86_64.S b/React/Profiler/RCTProfileTrampoline-x86_64.S
index 02fa010a4814..6d9c93fb7cd0 100644
--- a/React/Profiler/RCTProfileTrampoline-x86_64.S
+++ b/React/Profiler/RCTProfileTrampoline-x86_64.S
@@ -142,21 +142,14 @@ SYMBOL_NAME(RCTProfileTrampoline):
   // call the actual function and save the return value
   callq *%r11
   pushq %rax
-  subq $0x10+8, %rsp //16-bytes xmm register + 8-bytes for alignment
-  movdqa %xmm0, (%rsp)
-
-  // align stack
-  pushq %r12
-  movq %rsp, %r12
-  andq $-0x10, %rsp
+  pushq %rdx
+  subq $0x20, %rsp // 2 16-bytes xmm register
+  movdqa %xmm0, 0x00(%rsp)
+  movdqa %xmm1, 0x10(%rsp)
 
   // void RCTProfileTrampolineEnd(void) in RCTProfile.m - just ends this profile
   callq SYMBOL_NAME(RCTProfileTrampolineEnd)
 
-  // unalign stack and restore %r12
-  movq %r12, %rsp
-  popq %r12
-
   /**
    * Restore the initial value of the callee saved registers, saved in the
    * memory allocated.
@@ -167,7 +160,7 @@ SYMBOL_NAME(RCTProfileTrampoline):
   movq 0x8(%r14), %r14
 
   /**
-   * Save caller address and actual function return (previously in the allocated
+   * save caller address and actual function return (previously in the allocated
    * memory) and align the stack
    */
   pushq %rcx
@@ -183,12 +176,14 @@ SYMBOL_NAME(RCTProfileTrampoline):
   popq %r12
 
   /**
-   * pop the caller address to %rcx and the actual function return value to
-   * %rax, so it's the return value of RCTProfileTrampoline
+   * pop the caller address to %rcx and the actual function return value(s)
+   * so it's the return value of RCTProfileTrampoline
    */
   popq %rcx
-  movdqa (%rsp), %xmm0
-  addq $0x10+8, %rsp
+  movdqa 0x00(%rsp), %xmm0
+  movdqa 0x10(%rsp), %xmm1
+  addq $0x20, %rsp
+  popq %rdx
   popq %rax
 
   // jump to caller

From 611e0619caf7323b5d06f29efbc2febd0ad4eba7 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Mon, 7 Dec 2015 08:28:45 -0800
Subject: [PATCH 0255/1411] Rename PullToRefreshLayoutAndroid ->
 PullToRefreshViewAndroid

Summary:
The naming "Layout" is an Android-specific thing and not useful in JS. Let's stay consistent with naming like "ScrollView", "MapView" etc.

public

Reviewed By: bestander

Differential Revision: D2723163

fb-gh-sync-id: 6b86e5a649254c41e9d6b0ef6f1fe2ff4b9f3e9a
---
 ...js => PullToRefreshViewAndroidExample.android.js} | 12 ++++++------
 Examples/UIExplorer/UIExplorerList.android.js        |  2 +-
 ...ndroid.js => PullToRefreshViewAndroid.android.js} | 10 +++++-----
 ...ndroid.ios.js => PullToRefreshViewAndroid.ios.js} |  2 +-
 Libraries/react-native/react-native.js               |  2 +-
 5 files changed, 14 insertions(+), 14 deletions(-)
 rename Examples/UIExplorer/{PullToRefreshLayoutAndroidExample.android.js => PullToRefreshViewAndroidExample.android.js} (91%)
 rename Libraries/PullToRefresh/{PullToRefreshLayoutAndroid.android.js => PullToRefreshViewAndroid.android.js} (90%)
 rename Libraries/PullToRefresh/{PullToRefreshLayoutAndroid.ios.js => PullToRefreshViewAndroid.ios.js} (89%)

diff --git a/Examples/UIExplorer/PullToRefreshLayoutAndroidExample.android.js b/Examples/UIExplorer/PullToRefreshViewAndroidExample.android.js
similarity index 91%
rename from Examples/UIExplorer/PullToRefreshLayoutAndroidExample.android.js
rename to Examples/UIExplorer/PullToRefreshViewAndroidExample.android.js
index 06a39c7ccd86..c309c90288b9 100644
--- a/Examples/UIExplorer/PullToRefreshLayoutAndroidExample.android.js
+++ b/Examples/UIExplorer/PullToRefreshViewAndroidExample.android.js
@@ -18,7 +18,7 @@ const React = require('react-native');
 const {
   ScrollView,
   StyleSheet,
-  PullToRefreshLayoutAndroid,
+  PullToRefreshViewAndroid,
   Text,
   TouchableWithoutFeedback,
   View,
@@ -61,9 +61,9 @@ const Row = React.createClass({
     );
   },
 });
-const PullToRefreshLayoutAndroidExample = React.createClass({
+const PullToRefreshViewAndroidExample = React.createClass({
   statics: {
-    title: '<PullToRefreshLayoutAndroid>',
+    title: '<PullToRefreshViewAndroid>',
     description: 'Container that adds pull-to-refresh support to its child view.'
   },
 
@@ -88,7 +88,7 @@ const PullToRefreshLayoutAndroidExample = React.createClass({
       return <Row data={row} onClick={this._onClick}/>;
     });
     return (
-      <PullToRefreshLayoutAndroid
+      <PullToRefreshViewAndroid
         style={styles.layout}
         refreshing={this.state.isRefreshing}
         onRefresh={this._onRefresh}
@@ -98,7 +98,7 @@ const PullToRefreshLayoutAndroidExample = React.createClass({
         <ScrollView style={styles.scrollview}>
           {rows}
         </ScrollView>
-      </PullToRefreshLayoutAndroid>
+      </PullToRefreshViewAndroid>
     );
   },
 
@@ -124,4 +124,4 @@ const PullToRefreshLayoutAndroidExample = React.createClass({
 });
 
 
-module.exports = PullToRefreshLayoutAndroidExample;
+module.exports = PullToRefreshViewAndroidExample;
diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index b3b0fc4d50ff..6445eff49905 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -27,7 +27,7 @@ var COMPONENTS = [
   require('./ProgressBarAndroidExample'),
   require('./ScrollViewSimpleExample'),
   require('./SwitchAndroidExample'),
-  require('./PullToRefreshLayoutAndroidExample.android'),
+  require('./PullToRefreshViewAndroidExample.android'),
   require('./TextExample.android'),
   require('./TextInputExample.android'),
   require('./ToolbarAndroidExample'),
diff --git a/Libraries/PullToRefresh/PullToRefreshLayoutAndroid.android.js b/Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js
similarity index 90%
rename from Libraries/PullToRefresh/PullToRefreshLayoutAndroid.android.js
rename to Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js
index a1d69c353e8d..40842d0a2715 100644
--- a/Libraries/PullToRefresh/PullToRefreshLayoutAndroid.android.js
+++ b/Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js
@@ -6,7 +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.
  *
- * @providesModule PullToRefreshLayoutAndroid
+ * @providesModule PullToRefreshViewAndroid
  */
 'use strict';
 
@@ -24,7 +24,7 @@ var NATIVE_REF = 'native_swiperefreshlayout';
  * React view that supports a single scrollable child view (e.g. `ScrollView`). When this child
  * view is at `scrollY: 0`, swiping down triggers an `onRefresh` event.
  */
-var PullToRefreshLayoutAndroid = React.createClass({
+var PullToRefreshViewAndroid = React.createClass({
   statics: {
     SIZE: RefreshLayoutConsts.SIZE,
   },
@@ -48,7 +48,7 @@ var PullToRefreshLayoutAndroid = React.createClass({
      */
     refreshing: React.PropTypes.bool,
     /**
-     * Size of the refresh indicator, see PullToRefreshLayoutAndroid.SIZE
+     * Size of the refresh indicator, see PullToRefreshViewAndroid.SIZE
      */
     size: React.PropTypes.oneOf(RefreshLayoutConsts.SIZE.DEFAULT, RefreshLayoutConsts.SIZE.LARGE),
   },
@@ -81,7 +81,7 @@ var PullToRefreshLayoutAndroid = React.createClass({
 
 var NativePullToRefresh = requireNativeComponent(
   'AndroidSwipeRefreshLayout',
-  PullToRefreshLayoutAndroid
+  PullToRefreshViewAndroid
 );
 
-module.exports = PullToRefreshLayoutAndroid;
+module.exports = PullToRefreshViewAndroid;
diff --git a/Libraries/PullToRefresh/PullToRefreshLayoutAndroid.ios.js b/Libraries/PullToRefresh/PullToRefreshViewAndroid.ios.js
similarity index 89%
rename from Libraries/PullToRefresh/PullToRefreshLayoutAndroid.ios.js
rename to Libraries/PullToRefresh/PullToRefreshViewAndroid.ios.js
index eea4dbae7695..2a16f851b827 100644
--- a/Libraries/PullToRefresh/PullToRefreshLayoutAndroid.ios.js
+++ b/Libraries/PullToRefresh/PullToRefreshViewAndroid.ios.js
@@ -6,7 +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.
  *
- * @providesModule PullToRefreshLayoutAndroid
+ * @providesModule PullToRefreshViewAndroid
  */
  'use strict';
 
diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js
index 2264fa5c6657..99bda63a9f9b 100644
--- a/Libraries/react-native/react-native.js
+++ b/Libraries/react-native/react-native.js
@@ -37,7 +37,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
   SliderIOS: require('SliderIOS'),
   SnapshotViewIOS: require('SnapshotViewIOS'),
   Switch: require('Switch'),
-  PullToRefreshLayoutAndroid: require('PullToRefreshLayoutAndroid'),
+  PullToRefreshViewAndroid: require('PullToRefreshViewAndroid'),
   SwitchAndroid: require('SwitchAndroid'),
   SwitchIOS: require('SwitchIOS'),
   TabBarIOS: require('TabBarIOS'),

From 510d50fc17157f186a593c2c02b3fcf610889c77 Mon Sep 17 00:00:00 2001
From: Alexander Blom <blom@fb.com>
Date: Mon, 7 Dec 2015 08:43:24 -0800
Subject: [PATCH 0256/1411] Trigger GC and drop compiled code on low memory

Reviewed By: astreet

Differential Revision: D2658693

fb-gh-sync-id: 8cba49b67ac45a2dbf8b4c9c404d6fb9c97693f6
---
 .../facebook/react/MemoryPressureRouter.java  | 93 +++++++++++++++++++
 .../react/ReactInstanceManagerImpl.java       |  5 +
 .../react/bridge/CatalystInstance.java        |  4 +-
 .../react/bridge/CatalystInstanceImpl.java    |  5 +
 .../facebook/react/bridge/MemoryPressure.java |  8 ++
 .../facebook/react/bridge/ReactBridge.java    | 15 +++
 ReactAndroid/src/main/jni/react/Bridge.cpp    | 16 ++++
 ReactAndroid/src/main/jni/react/Bridge.h      |  2 +
 ReactAndroid/src/main/jni/react/Executor.h    |  4 +
 .../src/main/jni/react/JSCExecutor.cpp        | 16 ++++
 ReactAndroid/src/main/jni/react/JSCExecutor.h |  4 +-
 .../src/main/jni/react/jni/OnLoad.cpp         | 13 +++
 12 files changed, 182 insertions(+), 3 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/MemoryPressureRouter.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/MemoryPressure.java

diff --git a/ReactAndroid/src/main/java/com/facebook/react/MemoryPressureRouter.java b/ReactAndroid/src/main/java/com/facebook/react/MemoryPressureRouter.java
new file mode 100644
index 000000000000..58f2833110e2
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/MemoryPressureRouter.java
@@ -0,0 +1,93 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react;
+
+import javax.annotation.Nullable;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.ComponentCallbacks2;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.Build;
+
+import com.facebook.react.bridge.CatalystInstance;
+import com.facebook.react.bridge.MemoryPressure;
+import com.facebook.react.bridge.ReactContext;
+
+import static android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
+import static android.content.ComponentCallbacks2.TRIM_MEMORY_MODERATE;
+import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
+
+/**
+ * Translates and routes memory pressure events to the current catalyst instance.
+ */
+public class MemoryPressureRouter {
+  // Trigger this by sending an intent to your activity with adb shell:
+  // am start -a "com.facebook.catalyst.ACTION_TRIM_MEMORY" --activity-single-top -n <activity>
+  private static final String ACTION_TRIM_MEMORY ="com.facebook.catalyst.ACTION_TRIM_MEMORY";
+
+  private @Nullable CatalystInstance mCatalystInstance;
+  private final ComponentCallbacks2 mCallbacks = new ComponentCallbacks2() {
+    @Override
+    public void onTrimMemory(int level) {
+      trimMemory(level);
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+    }
+
+    @Override
+    public void onLowMemory() {
+    }
+  };
+
+  @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
+  public static boolean handleDebugIntent(Activity activity, String action) {
+    switch (action) {
+      case ACTION_TRIM_MEMORY:
+        simulateTrimMemory(activity, TRIM_MEMORY_MODERATE);
+        break;
+      default:
+        return false;
+    }
+
+    return true;
+  }
+
+  MemoryPressureRouter(Context context) {
+    context.getApplicationContext().registerComponentCallbacks(mCallbacks);
+  }
+
+  public void onNewReactContextCreated(ReactContext reactContext) {
+    mCatalystInstance = reactContext.getCatalystInstance();
+  }
+
+  public void onReactInstanceDestroyed() {
+    mCatalystInstance = null;
+  }
+
+  public void destroy(Context context) {
+    context.getApplicationContext().unregisterComponentCallbacks(mCallbacks);
+  }
+
+  private void trimMemory(int level) {
+    if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
+      dispatchMemoryPressure(MemoryPressure.CRITICAL);
+    } else if (level >= TRIM_MEMORY_BACKGROUND || level == TRIM_MEMORY_RUNNING_CRITICAL) {
+      dispatchMemoryPressure(MemoryPressure.MODERATE);
+    }
+  }
+
+  private void dispatchMemoryPressure(MemoryPressure level) {
+    if (mCatalystInstance != null) {
+      mCatalystInstance.handleMemoryPressure(level);
+    }
+  }
+
+  private static void simulateTrimMemory(Activity activity, int level) {
+    activity.getApplication().onTrimMemory(level);
+    activity.onTrimMemory(level);
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index 1eecb403269b..1169034ee116 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -100,6 +100,7 @@
       new ConcurrentLinkedQueue<>();
   private volatile boolean mHasStartedCreatingInitialContext = false;
   private final UIImplementationProvider mUIImplementationProvider;
+  private final MemoryPressureRouter mMemoryPressureRouter;
 
   private final ReactInstanceDevCommandsHandler mDevInterface =
       new ReactInstanceDevCommandsHandler() {
@@ -215,6 +216,7 @@ protected void onPostExecute(ReactApplicationContext reactContext) {
     mBridgeIdleDebugListener = bridgeIdleDebugListener;
     mLifecycleState = initialLifecycleState;
     mUIImplementationProvider = uiImplementationProvider;
+    mMemoryPressureRouter = new MemoryPressureRouter(applicationContext);
   }
 
   @Override
@@ -400,6 +402,7 @@ public void onResume(Activity activity, DefaultHardwareBackBtnHandler defaultBac
   public void onDestroy() {
     UiThreadUtil.assertOnUiThread();
 
+    mMemoryPressureRouter.destroy(mApplicationContext);
     if (mUseDeveloperSupport) {
       mDevSupportManager.setDevSupportEnabled(false);
     }
@@ -539,6 +542,7 @@ private void setupReactContext(ReactApplicationContext reactContext) {
 
     catalystInstance.initialize();
     mDevSupportManager.onNewReactContextCreated(reactContext);
+    mMemoryPressureRouter.onNewReactContextCreated(reactContext);
     moveReactContextToCurrentLifecycleState(reactContext);
 
     for (ReactRootView rootView : mAttachedRootViews) {
@@ -591,6 +595,7 @@ private void tearDownReactContext(ReactContext reactContext) {
     }
     reactContext.onDestroy();
     mDevSupportManager.onReactInstanceDestroyed(reactContext);
+    mMemoryPressureRouter.onReactInstanceDestroyed();
   }
 
   /**
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
index 7e5afc3a47ff..e9240eb88815 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
@@ -9,8 +9,6 @@
 
 package com.facebook.react.bridge;
 
-import javax.annotation.Nullable;
-
 import java.util.Collection;
 
 import com.facebook.react.bridge.queue.CatalystQueueConfiguration;
@@ -49,6 +47,8 @@ public interface CatalystInstance {
   <T extends NativeModule> T getNativeModule(Class<T> nativeModuleInterface);
   Collection<NativeModule> getNativeModules();
 
+  void handleMemoryPressure(MemoryPressure level);
+
   /**
    * Adds a idle listener for this Catalyst instance. The listener will receive notifications
    * whenever the bridge transitions from idle to busy and vice-versa, where the busy state is
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
index 6929ea3d7e75..06d53a85efca 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
@@ -314,6 +314,11 @@ public Collection<NativeModule> getNativeModules() {
     return mJavaRegistry.getAllModules();
   }
 
+  @Override
+  public void handleMemoryPressure(MemoryPressure level) {
+    Assertions.assertNotNull(mBridge).handleMemoryPressure(level);
+  }
+
   /**
    * Adds a idle listener for this Catalyst instance. The listener will receive notifications
    * whenever the bridge transitions from idle to busy and vice-versa, where the busy state is
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/MemoryPressure.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/MemoryPressure.java
new file mode 100644
index 000000000000..c947782efe40
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/MemoryPressure.java
@@ -0,0 +1,8 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.bridge;
+
+public enum MemoryPressure {
+  MODERATE,
+  CRITICAL
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java
index d84c7b844917..b809e680b6a8 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java
@@ -56,6 +56,19 @@ public void dispose() {
     super.dispose();
   }
 
+  public void handleMemoryPressure(MemoryPressure level) {
+    switch (level) {
+      case MODERATE:
+        handleMemoryPressureModerate();
+        break;
+      case CRITICAL:
+        handleMemoryPressureCritical();
+        break;
+      default:
+        throw new IllegalArgumentException("Unknown level: " + level);
+    }
+  }
+
   private native void initialize(
       JavaScriptExecutor jsExecutor,
       ReactCallback callback,
@@ -72,4 +85,6 @@ private native void initialize(
   public native boolean supportsProfiling();
   public native void startProfiler(String title);
   public native void stopProfiler(String title, String filename);
+  private native void handleMemoryPressureModerate();
+  private native void handleMemoryPressureCritical();
 }
diff --git a/ReactAndroid/src/main/jni/react/Bridge.cpp b/ReactAndroid/src/main/jni/react/Bridge.cpp
index e3643e6cf41c..84fb525b00b5 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.cpp
+++ b/ReactAndroid/src/main/jni/react/Bridge.cpp
@@ -51,6 +51,14 @@ class JSThreadState {
     m_jsExecutor->stopProfiler(title, filename);
   }
 
+  void handleMemoryPressureModerate() {
+    m_jsExecutor->handleMemoryPressureModerate();
+  }
+
+  void handleMemoryPressureCritical() {
+    m_jsExecutor->handleMemoryPressureCritical();
+  }
+
 private:
   std::unique_ptr<JSExecutor> m_jsExecutor;
   Bridge::Callback m_callback;
@@ -109,4 +117,12 @@ void Bridge::stopProfiler(const std::string& title, const std::string& filename)
   m_threadState->stopProfiler(title, filename);
 }
 
+void Bridge::handleMemoryPressureModerate() {
+  m_threadState->handleMemoryPressureModerate();
+}
+
+void Bridge::handleMemoryPressureCritical() {
+  m_threadState->handleMemoryPressureCritical();
+}
+
 } }
diff --git a/ReactAndroid/src/main/jni/react/Bridge.h b/ReactAndroid/src/main/jni/react/Bridge.h
index 9f81f529d9d3..23843de42940 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.h
+++ b/ReactAndroid/src/main/jni/react/Bridge.h
@@ -38,6 +38,8 @@ class Bridge : public Countable {
   bool supportsProfiling();
   void startProfiler(const std::string& title);
   void stopProfiler(const std::string& title, const std::string& filename);
+  void handleMemoryPressureModerate();
+  void handleMemoryPressureCritical();
 private:
   Callback m_callback;
   std::unique_ptr<JSThreadState> m_threadState;
diff --git a/ReactAndroid/src/main/jni/react/Executor.h b/ReactAndroid/src/main/jni/react/Executor.h
index 1f4f54cc5a89..6a59bff420a0 100644
--- a/ReactAndroid/src/main/jni/react/Executor.h
+++ b/ReactAndroid/src/main/jni/react/Executor.h
@@ -43,6 +43,10 @@ class JSExecutor {
   };
   virtual void startProfiler(const std::string &titleString) {};
   virtual void stopProfiler(const std::string &titleString, const std::string &filename) {};
+  virtual void handleMemoryPressureModerate() {};
+  virtual void handleMemoryPressureCritical() {
+    handleMemoryPressureModerate();
+  };
   virtual ~JSExecutor() {};
 };
 
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index 5e6caae2630e..93bb17fbad13 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -18,6 +18,10 @@
 #include <JavaScriptCore/API/JSProfilerPrivate.h>
 #endif
 
+#ifdef WITH_JSC_MEMORY_PRESSURE
+#include <jsc_memory.h>
+#endif
+
 #ifdef WITH_FBSYSTRACE
 #include <fbsystrace.h>
 using fbsystrace::FbSystraceSection;
@@ -182,6 +186,18 @@ void JSCExecutor::stopProfiler(const std::string &titleString, const std::string
   #endif
 }
 
+void JSCExecutor::handleMemoryPressureModerate() {
+  #ifdef WITH_JSC_MEMORY_PRESSURE
+  JSHandleMemoryPressure(this, m_context, JSMemoryPressure::MODERATE);
+  #endif
+}
+
+void JSCExecutor::handleMemoryPressureCritical() {
+  #ifdef WITH_JSC_MEMORY_PRESSURE
+  JSHandleMemoryPressure(this, m_context, JSMemoryPressure::CRITICAL);
+  #endif
+}
+
 void JSCExecutor::flushQueueImmediate(std::string queueJSON) {
   m_flushImmediateCallback(queueJSON);
 }
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.h b/ReactAndroid/src/main/jni/react/JSCExecutor.h
index 849148bfaec8..a319a9036574 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.h
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.h
@@ -31,7 +31,9 @@ class JSCExecutor : public JSExecutor {
   virtual bool supportsProfiling() override;
   virtual void startProfiler(const std::string &titleString) override;
   virtual void stopProfiler(const std::string &titleString, const std::string &filename) override;
-  
+  virtual void handleMemoryPressureModerate() override;
+  virtual void handleMemoryPressureCritical() override;
+
   void flushQueueImmediate(std::string queueJSON);
   void installNativeHook(const char *name, JSObjectCallAsFunctionCallback callback);
 
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 6afa306da05e..610cd160d4ab 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -729,6 +729,16 @@ static void stopProfiler(JNIEnv* env, jobject obj, jstring title, jstring filena
   bridge->stopProfiler(fromJString(env, title), fromJString(env, filename));
 }
 
+static void handleMemoryPressureModerate(JNIEnv* env, jobject obj) {
+  auto bridge = extractRefPtr<Bridge>(env, obj);
+  bridge->handleMemoryPressureModerate();
+}
+
+static void handleMemoryPressureCritical(JNIEnv* env, jobject obj) {
+  auto bridge = extractRefPtr<Bridge>(env, obj);
+  bridge->handleMemoryPressureCritical();
+}
+
 } // namespace bridge
 
 namespace executors {
@@ -840,6 +850,9 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
         makeNativeMethod("supportsProfiling", bridge::supportsProfiling),
         makeNativeMethod("startProfiler", bridge::startProfiler),
         makeNativeMethod("stopProfiler", bridge::stopProfiler),
+        makeNativeMethod("handleMemoryPressureModerate", bridge::handleMemoryPressureModerate),
+        makeNativeMethod("handleMemoryPressureCritical", bridge::handleMemoryPressureCritical),
+
     });
 
     jclass nativeRunnableClass = env->FindClass("com/facebook/react/bridge/queue/NativeRunnable");

From 7600909caf2e3673c688857fa62263674d38ae1d Mon Sep 17 00:00:00 2001
From: Pratham Agrawal <mail@prath.am>
Date: Mon, 7 Dec 2015 23:03:12 +0530
Subject: [PATCH 0257/1411] Added Hubhopper to the showcase.

---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 89b74d7033f2..4fbcb58ef3a0 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -204,6 +204,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/hsk-level-1-chinese-flashcards/id936639994',
     author: 'HS Schaaf',
   },
+  {
+    name: 'Hubhopper',
+    icon: 'http://hubhopper.com/images/h_logo.jpg',
+    link: 'https://play.google.com/store/apps/details?id=com.hubhopper',
+    author: 'Soch Technologies',
+  },
   {
     name: 'Kakapo',
     icon: 'http://a2.mzstatic.com/eu/r30/Purple3/v4/12/ab/2a/12ab2a01-3a3c-9482-b8df-ab38ad281165/icon175x175.png',

From abea6c30b440b349d072038e756154ade16457fe Mon Sep 17 00:00:00 2001
From: sathis <sathis@genwi.com>
Date: Mon, 7 Dec 2015 10:44:41 -0800
Subject: [PATCH 0258/1411] Make style property available in Image.android.js
 like Image.ios.js

Summary:
Thanks ahanriat for pointing out  :)
Closes https://github.com/facebook/react-native/pull/4618

Reviewed By: svcscm

Differential Revision: D2729582

Pulled By: androidtrunkagent

fb-gh-sync-id: df7b9af24cc035c7a9618a7850d628961fcd776b
---
 Libraries/Image/Image.android.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/Libraries/Image/Image.android.js b/Libraries/Image/Image.android.js
index e73a68b84f0f..3cf5ae1f66eb 100644
--- a/Libraries/Image/Image.android.js
+++ b/Libraries/Image/Image.android.js
@@ -63,7 +63,8 @@ var ImageViewAttributes = merge(ReactNativeViewAttributes.UIView, {
 var Image = React.createClass({
   propTypes: {
     ...View.propTypes,
-    /**
+    style: StyleSheetPropType(ImageStylePropTypes), 
+   /**
      * `uri` is a string representing the resource identifier for the image, which
      * could be an http address, a local file path, or the name of a static image
      * resource (which should be wrapped in the `require('image!name')` function).

From 7605d2d8cdf0b5b230d116d39adb371eb404b263 Mon Sep 17 00:00:00 2001
From: Nick Baugh <niftylettuce@gmail.com>
Date: Thu, 3 Dec 2015 01:03:36 -0500
Subject: [PATCH 0259/1411] Switched recommendation from superagent to frisbee,
 Moved XMLHTTPRequest to bottom of doc page

Resolves issues per recommendations by @ide

Added axios reference
---
 docs/Network.md | 64 ++++++++++++++++++++++++-------------------------
 1 file changed, 32 insertions(+), 32 deletions(-)

diff --git a/docs/Network.md b/docs/Network.md
index d0366e646992..ce2755983593 100644
--- a/docs/Network.md
+++ b/docs/Network.md
@@ -9,45 +9,19 @@ next: timers
 
 One of React Native's goals is to be a playground where we can experiment with different architectures and crazy ideas. Since browsers are not flexible enough, we had no choice but to reimplement the entire stack. In the places that we did not intend to change anything, we tried to be as faithful as possible to the browser APIs. The networking stack is a great example.
 
-## XMLHttpRequest
-
-XMLHttpRequest API is implemented on-top of [iOS networking apis](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/URLLoadingSystem/URLLoadingSystem.html). The notable difference from web is the security model: you can read from arbitrary websites on the internet since there is no concept of [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing).
-
-```javascript
-var request = new XMLHttpRequest();
-request.onreadystatechange = (e) => {
-  if (request.readyState !== 4) {
-    return;
-  }
-
-  if (request.status === 200) {
-    console.log('success', request.responseText);
-  } else {
-    console.warn('error');
-  }
-};
-
-request.open('GET', 'https://mywebsite.com/endpoint.php');
-request.send();
-```
-
-Please follow the [MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) for a complete description of the API.
-
-As a developer, you're probably not going to use XMLHttpRequest directly as its API is very tedious to work with. But the fact that it is implemented and compatible with the browser API gives you the ability to use third-party libraries such as [Parse]( https://parse.com/products/javascript) or [super-agent](https://github.com/visionmedia/superagent) directly from npm.
-
 ## Fetch
 
 [fetch](https://fetch.spec.whatwg.org/) is a better networking API being worked on by the standards committee and is already available in Chrome. It is available in React Native by default.
 
 #### Usage
 
-```javascript
+```js
 fetch('https://mywebsite.com/endpoint/')
 ```
 
 Include a request object as the optional second argument to customize the HTTP request:
 
-```javascript
+```js
 fetch('https://mywebsite.com/endpoint/', {
   method: 'POST',
   headers: {
@@ -62,11 +36,12 @@ fetch('https://mywebsite.com/endpoint/', {
 ```
 
 #### Async
+
 `fetch` returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) that can be processed in two ways:
 
 1.  Using `then` and `catch` in synchronous code:
 
-```javascript
+```js
 fetch('https://mywebsite.com/endpoint.php')
   .then((response) => response.text())
   .then((responseText) => {
@@ -79,7 +54,7 @@ fetch('https://mywebsite.com/endpoint.php')
 
 2.  Called within an asynchronous function using ES7 `async`/`await` syntax:
 
-```javascript
+```js
 async getUsersFromApi() {
   try {
     let response = await fetch('https://mywebsite.com/endpoint/');
@@ -92,12 +67,11 @@ async getUsersFromApi() {
 
 - Note: Errors thrown by rejected Promises need to be caught, or they will be swallowed silently
 
-
 ## WebSocket
 
 WebSocket is a protocol providing full-duplex communication channels over a single TCP connection.
 
-```javascript
+```js
 var ws = new WebSocket('ws://host.com/path');
 
 ws.on('open', function() {
@@ -120,3 +94,29 @@ ws.on('close', function(e) {
   console.log(e.code, e.reason);
 });
 ```
+
+## XMLHttpRequest
+
+XMLHttpRequest API is implemented on-top of [iOS networking apis](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/URLLoadingSystem/URLLoadingSystem.html). The notable difference from web is the security model: you can read from arbitrary websites on the internet since there is no concept of [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing).
+
+```js
+var request = new XMLHttpRequest();
+request.onreadystatechange = (e) => {
+  if (request.readyState !== 4) {
+    return;
+  }
+
+  if (request.status === 200) {
+    console.log('success', request.responseText);
+  } else {
+    console.warn('error');
+  }
+};
+
+request.open('GET', 'https://mywebsite.com/endpoint.php');
+request.send();
+```
+
+Please follow the [MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) for a complete description of the API.
+
+As a developer, you're probably not going to use XMLHttpRequest directly as its API is very tedious to work with. But the fact that it is implemented and compatible with the browser API gives you the ability to use third-party libraries such as [Parse](https://parse.com/products/javascript), [frisbee](https://github.com/niftylettuce/frisbee), or [axios](https://github.com/mzabriskie/axios) directly from npm.

From 93f9a4a7ee34ec17d61853f8ff7f5ae7a520bc58 Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Mon, 7 Dec 2015 11:25:50 -0800
Subject: [PATCH 0260/1411] Fix for flow
 (https://github.com/facebook/flow/tree/v0.19.0)

Summary:
From flow release notes (https://github.com/facebook/flow/releases),
> import type * as Foo is now disallowed in favor of import type Foo
Closes https://github.com/facebook/react-native/pull/4565

Reviewed By: svcscm

Differential Revision: D2723280

Pulled By: mkonicek

fb-gh-sync-id: 57074ab893c3e2eae3cefc3002853bfdfed91734
---
 .../CustomComponents/Navigator/Navigation/NavigationContext.js  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/CustomComponents/Navigator/Navigation/NavigationContext.js b/Libraries/CustomComponents/Navigator/Navigation/NavigationContext.js
index 6d17fe1256df..7024081d2079 100644
--- a/Libraries/CustomComponents/Navigator/Navigation/NavigationContext.js
+++ b/Libraries/CustomComponents/Navigator/Navigation/NavigationContext.js
@@ -36,7 +36,7 @@ var Set = require('Set');
 var emptyFunction = require('emptyFunction');
 var invariant = require('invariant');
 
-import type * as EventSubscription from 'EventSubscription';
+import type EventSubscription from 'EventSubscription';
 
 var {
   AT_TARGET,

From 0f98dedefe5769be39a298efd14e92cd7dc472e9 Mon Sep 17 00:00:00 2001
From: Mike Armstrong <mikea@fb.com>
Date: Mon, 7 Dec 2015 15:21:05 -0800
Subject: [PATCH 0261/1411] More markers for view operations

Reviewed By: astreet

Differential Revision: D2679126

fb-gh-sync-id: 882e815a7551d23b4594fdc2dd257b4f1cdbbab7
---
 .../uimanager/NativeViewHierarchyManager.java | 108 +++++++++++-------
 .../react/uimanager/UIViewOperationQueue.java |   4 +
 2 files changed, 69 insertions(+), 43 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
index 752ffaf291bc..ad195004333d 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
@@ -34,6 +34,8 @@
 import com.facebook.react.bridge.UiThreadUtil;
 import com.facebook.react.touch.JSResponderHandler;
 import com.facebook.react.uimanager.layoutanimation.LayoutAnimationController;
+import com.facebook.systrace.Systrace;
+import com.facebook.systrace.SystraceMessage;
 
 /**
  * Delegate of {@link UIManagerModule} that owns the native view hierarchy and mapping between
@@ -128,40 +130,50 @@ public void updateLayout(
       int width,
       int height) {
     UiThreadUtil.assertOnUiThread();
-
-    View viewToUpdate = resolveView(tag);
-
-    // Even though we have exact dimensions, we still call measure because some platform views (e.g.
-    // Switch) assume that method will always be called before onLayout and onDraw. They use it to
-    // calculate and cache information used in the draw pass. For most views, onMeasure can be
-    // stubbed out to only call setMeasuredDimensions. For ViewGroups, onLayout should be stubbed
-    // out to not recursively call layout on its children: React Native already handles doing that.
-    //
-    // Also, note measure and layout need to be called *after* all View properties have been updated
-    // because of caching and calculation that may occur in onMeasure and onLayout. Layout
-    // operations should also follow the native view hierarchy and go top to bottom for consistency
-    // with standard layout passes (some views may depend on this).
-
-    viewToUpdate.measure(
-        View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
-        View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
-
-    // Check if the parent of the view has to layout the view, or the child has to lay itself out.
-    if (!mRootTags.get(parentTag)) {
-      ViewManager parentViewManager = mTagsToViewManagers.get(parentTag);
-      ViewGroupManager parentViewGroupManager;
-      if (parentViewManager instanceof ViewGroupManager) {
-        parentViewGroupManager = (ViewGroupManager) parentViewManager;
+    SystraceMessage.beginSection(
+        Systrace.TRACE_TAG_REACT_VIEW,
+        "NativeViewHierarchyManager_updateLayout")
+        .arg("parentTag", parentTag)
+        .arg("tag", tag)
+        .flush();
+    try {
+      View viewToUpdate = resolveView(tag);
+
+      // Even though we have exact dimensions, we still call measure because some platform views (e.g.
+      // Switch) assume that method will always be called before onLayout and onDraw. They use it to
+      // calculate and cache information used in the draw pass. For most views, onMeasure can be
+      // stubbed out to only call setMeasuredDimensions. For ViewGroups, onLayout should be stubbed
+      // out to not recursively call layout on its children: React Native already handles doing that.
+      //
+      // Also, note measure and layout need to be called *after* all View properties have been updated
+      // because of caching and calculation that may occur in onMeasure and onLayout. Layout
+      // operations should also follow the native view hierarchy and go top to bottom for consistency
+      // with standard layout passes (some views may depend on this).
+
+      viewToUpdate.measure(
+          View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
+          View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
+
+      // Check if the parent of the view has to layout the view, or the child has to lay itself out.
+      if (!mRootTags.get(parentTag)) {
+        ViewManager parentViewManager = mTagsToViewManagers.get(parentTag);
+        ViewGroupManager parentViewGroupManager;
+        if (parentViewManager instanceof ViewGroupManager) {
+          parentViewGroupManager = (ViewGroupManager) parentViewManager;
+        } else {
+          throw new IllegalViewOperationException(
+              "Trying to use view with tag " + tag +
+                  " as a parent, but its Manager doesn't extends ViewGroupManager");
+        }
+        if (parentViewGroupManager != null
+            && !parentViewGroupManager.needsCustomLayoutForChildren()) {
+          updateLayout(viewToUpdate, x, y, width, height);
+        }
       } else {
-        throw new IllegalViewOperationException("Trying to use view with tag " + tag +
-            " as a parent, but its Manager doesn't extends ViewGroupManager");
-      }
-      if (parentViewGroupManager != null
-          && !parentViewGroupManager.needsCustomLayoutForChildren()) {
         updateLayout(viewToUpdate, x, y, width, height);
       }
-    } else {
-      updateLayout(viewToUpdate, x, y, width, height);
+    } finally {
+      Systrace.endSection(Systrace.TRACE_TAG_REACT_VIEW);
     }
   }
 
@@ -180,18 +192,28 @@ public void createView(
       String className,
       @Nullable CatalystStylesDiffMap initialProps) {
     UiThreadUtil.assertOnUiThread();
-    ViewManager viewManager = mViewManagers.get(className);
-
-    View view = viewManager.createView(themedContext, mJSResponderHandler);
-    mTagsToViews.put(tag, view);
-    mTagsToViewManagers.put(tag, viewManager);
-
-    // Use android View id field to store React tag. This is possible since we don't inflate
-    // React views from layout xmls. Thus it is easier to just reuse that field instead of
-    // creating another (potentially much more expensive) mapping from view to React tag
-    view.setId(tag);
-    if (initialProps != null) {
-      viewManager.updateProperties(view, initialProps);
+    SystraceMessage.beginSection(
+        Systrace.TRACE_TAG_REACT_VIEW,
+        "NativeViewHierarchyManager_createView")
+        .arg("tag", tag)
+        .arg("className", className)
+        .flush();
+    try {
+      ViewManager viewManager = mViewManagers.get(className);
+
+      View view = viewManager.createView(themedContext, mJSResponderHandler);
+      mTagsToViews.put(tag, view);
+      mTagsToViewManagers.put(tag, viewManager);
+
+      // Use android View id field to store React tag. This is possible since we don't inflate
+      // React views from layout xmls. Thus it is easier to just reuse that field instead of
+      // creating another (potentially much more expensive) mapping from view to React tag
+      view.setId(tag);
+      if (initialProps != null) {
+        viewManager.updateProperties(view, initialProps);
+      }
+    } finally {
+      Systrace.endSection(Systrace.TRACE_TAG_REACT_VIEW);
     }
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
index 5fc65cd64a23..ac2798333609 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
@@ -113,10 +113,12 @@ public UpdateLayoutOperation(
       mY = y;
       mWidth = width;
       mHeight = height;
+      Systrace.startAsyncFlow(Systrace.TRACE_TAG_REACT_VIEW, "updateLayout", mTag);
     }
 
     @Override
     public void execute() {
+      Systrace.endAsyncFlow(Systrace.TRACE_TAG_REACT_VIEW, "updateLayout", mTag);
       mNativeViewHierarchyManager.updateLayout(mParentTag, mTag, mX, mY, mWidth, mHeight);
     }
   }
@@ -136,10 +138,12 @@ public CreateViewOperation(
       mThemedContext = themedContext;
       mClassName = className;
       mInitialProps = initialProps;
+      Systrace.startAsyncFlow(Systrace.TRACE_TAG_REACT_VIEW, "createView", mTag);
     }
 
     @Override
     public void execute() {
+      Systrace.endAsyncFlow(Systrace.TRACE_TAG_REACT_VIEW, "createView", mTag);
       mNativeViewHierarchyManager.createView(
           mThemedContext,
           mTag,

From f9b744d50137de25357994fe2e829f98104e2242 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Mon, 7 Dec 2015 16:54:18 -0800
Subject: [PATCH 0262/1411] Use lazy getters to reduce
 `require('react-native')` overhead

Summary:
public

In the open source React Native implementation, the recommended approach for importing modules is by importing a the `ReactNative` object, which includes all available modules.

This is rather inefficient because it ends up initializing all the JS modules, even if you don't use them.

This diff switches the properties of the `ReactNative ` object to lazy getter functions, which defers the `require` until the module is actually requested.

This doesn't prevent unused modules from being included in the JS bundle, but it will prevent them from being initialized unless/until they are used.

Reviewed By: vjeux

Differential Revision: D2722993

fb-gh-sync-id: 0e9a2beb3aa6cd087a0592bd59a8f9242040be0c
---
 Libraries/react-native/react-native.js | 174 +++++++++++++------------
 1 file changed, 89 insertions(+), 85 deletions(-)

diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js
index 99bda63a9f9b..9eb675a8425f 100644
--- a/Libraries/react-native/react-native.js
+++ b/Libraries/react-native/react-native.js
@@ -6,110 +6,114 @@
  * LICENSE file in 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
+ * @noflow - get/set properties not yet supported by flow. also `...require(x)` is broken #6560135
  */
 'use strict';
 
 // Export React, plus some native additions.
-//
-// The use of Object.create/assign is to work around a Flow bug (#6560135).
-// Once that is fixed, change this back to
-//
-//   var ReactNative = {...require('React'), /* additions */}
-//
-var ReactNative = Object.assign(Object.create(require('React')), {
+var ReactNative = {
   // Components
-  ActivityIndicatorIOS: require('ActivityIndicatorIOS'),
-  ART: require('ReactNativeART'),
-  DatePickerIOS: require('DatePickerIOS'),
-  DrawerLayoutAndroid: require('DrawerLayoutAndroid'),
-  Image: require('Image'),
-  ListView: require('ListView'),
-  MapView: require('MapView'),
-  Modal: require('Modal'),
-  Navigator: require('Navigator'),
-  NavigatorIOS: require('NavigatorIOS'),
-  PickerIOS: require('PickerIOS'),
-  ProgressBarAndroid: require('ProgressBarAndroid'),
-  ProgressViewIOS: require('ProgressViewIOS'),
-  ScrollView: require('ScrollView'),
-  SegmentedControlIOS: require('SegmentedControlIOS'),
-  SliderIOS: require('SliderIOS'),
-  SnapshotViewIOS: require('SnapshotViewIOS'),
-  Switch: require('Switch'),
-  PullToRefreshViewAndroid: require('PullToRefreshViewAndroid'),
-  SwitchAndroid: require('SwitchAndroid'),
-  SwitchIOS: require('SwitchIOS'),
-  TabBarIOS: require('TabBarIOS'),
-  Text: require('Text'),
-  TextInput: require('TextInput'),
-  ToastAndroid: require('ToastAndroid'),
-  ToolbarAndroid: require('ToolbarAndroid'),
-  Touchable: require('Touchable'),
-  TouchableHighlight: require('TouchableHighlight'),
-  TouchableNativeFeedback: require('TouchableNativeFeedback'),
-  TouchableOpacity: require('TouchableOpacity'),
-  TouchableWithoutFeedback: require('TouchableWithoutFeedback'),
-  View: require('View'),
-  ViewPagerAndroid: require('ViewPagerAndroid'),
-  WebView: require('WebView'),
+  get ActivityIndicatorIOS() { return require('ActivityIndicatorIOS'); },
+  get ART() { return require('ReactNativeART'); },
+  get DatePickerIOS() { return require('DatePickerIOS'); },
+  get DrawerLayoutAndroid() { return require('DrawerLayoutAndroid'); },
+  get Image() { return require('Image'); },
+  get ListView() { return require('ListView'); },
+  get MapView() { return require('MapView'); },
+  get Modal() { return require('Modal'); },
+  get Navigator() { return require('Navigator'); },
+  get NavigatorIOS() { return require('NavigatorIOS'); },
+  get PickerIOS() { return require('PickerIOS'); },
+  get ProgressBarAndroid() { return require('ProgressBarAndroid'); },
+  get ProgressViewIOS() { return require('ProgressViewIOS'); },
+  get ScrollView() { return require('ScrollView'); },
+  get SegmentedControlIOS() { return require('SegmentedControlIOS'); },
+  get SliderIOS() { return require('SliderIOS'); },
+  get SnapshotViewIOS() { return require('SnapshotViewIOS'); },
+  get Switch() { return require('Switch'); },
+  get PullToRefreshViewAndroid() { return require('PullToRefreshViewAndroid'); },
+  get SwitchAndroid() { return require('SwitchAndroid'); },
+  get SwitchIOS() { return require('SwitchIOS'); },
+  get TabBarIOS() { return require('TabBarIOS'); },
+  get Text() { return require('Text'); },
+  get TextInput() { return require('TextInput'); },
+  get ToastAndroid() { return require('ToastAndroid'); },
+  get ToolbarAndroid() { return require('ToolbarAndroid'); },
+  get Touchable() { return require('Touchable'); },
+  get TouchableHighlight() { return require('TouchableHighlight'); },
+  get TouchableNativeFeedback() { return require('TouchableNativeFeedback'); },
+  get TouchableOpacity() { return require('TouchableOpacity'); },
+  get TouchableWithoutFeedback() { return require('TouchableWithoutFeedback'); },
+  get View() { return require('View'); },
+  get ViewPagerAndroid() { return require('ViewPagerAndroid'); },
+  get WebView() { return require('WebView'); },
 
   // APIs
-  ActionSheetIOS: require('ActionSheetIOS'),
-  AdSupportIOS: require('AdSupportIOS'),
-  AlertIOS: require('AlertIOS'),
-  Animated: require('Animated'),
-  AppRegistry: require('AppRegistry'),
-  AppStateIOS: require('AppStateIOS'),
-  AsyncStorage: require('AsyncStorage'),
-  BackAndroid: require('BackAndroid'),
-  CameraRoll: require('CameraRoll'),
-  Dimensions: require('Dimensions'),
-  Easing: require('Easing'),
-  ImagePickerIOS: require('ImagePickerIOS'),
-  IntentAndroid: require('IntentAndroid'),
-  InteractionManager: require('InteractionManager'),
-  LayoutAnimation: require('LayoutAnimation'),
-  LinkingIOS: require('LinkingIOS'),
-  NetInfo: require('NetInfo'),
-  PanResponder: require('PanResponder'),
-  PixelRatio: require('PixelRatio'),
-  PushNotificationIOS: require('PushNotificationIOS'),
-  Settings: require('Settings'),
-  StatusBarIOS: require('StatusBarIOS'),
-  StyleSheet: require('StyleSheet'),
-  UIManager: require('UIManager'),
-  VibrationIOS: require('VibrationIOS'),
+  get ActionSheetIOS() { return require('ActionSheetIOS'); },
+  get AdSupportIOS() { return require('AdSupportIOS'); },
+  get AlertIOS() { return require('AlertIOS'); },
+  get Animated() { return require('Animated'); },
+  get AppRegistry() { return require('AppRegistry'); },
+  get AppStateIOS() { return require('AppStateIOS'); },
+  get AsyncStorage() { return require('AsyncStorage'); },
+  get BackAndroid() { return require('BackAndroid'); },
+  get CameraRoll() { return require('CameraRoll'); },
+  get Dimensions() { return require('Dimensions'); },
+  get Easing() { return require('Easing'); },
+  get ImagePickerIOS() { return require('ImagePickerIOS'); },
+  get IntentAndroid() { return require('IntentAndroid'); },
+  get InteractionManager() { return require('InteractionManager'); },
+  get LayoutAnimation() { return require('LayoutAnimation'); },
+  get LinkingIOS() { return require('LinkingIOS'); },
+  get NetInfo() { return require('NetInfo'); },
+  get PanResponder() { return require('PanResponder'); },
+  get PixelRatio() { return require('PixelRatio'); },
+  get PushNotificationIOS() { return require('PushNotificationIOS'); },
+  get Settings() { return require('Settings'); },
+  get StatusBarIOS() { return require('StatusBarIOS'); },
+  get StyleSheet() { return require('StyleSheet'); },
+  get UIManager() { return require('UIManager'); },
+  get VibrationIOS() { return require('VibrationIOS'); },
 
   // Plugins
-  DeviceEventEmitter: require('RCTDeviceEventEmitter'),
-  NativeAppEventEmitter: require('RCTNativeAppEventEmitter'),
-  NativeModules: require('NativeModules'),
-  Platform: require('Platform'),
-  processColor: require('processColor'),
-  requireNativeComponent: require('requireNativeComponent'),
+  get DeviceEventEmitter() { return require('RCTDeviceEventEmitter'); },
+  get NativeAppEventEmitter() { return require('RCTNativeAppEventEmitter'); },
+  get NativeModules() { return require('NativeModules'); },
+  get Platform() { return require('Platform'); },
+  get processColor() { return require('processColor'); },
+  get requireNativeComponent() { return require('requireNativeComponent'); },
 
   // Prop Types
-  EdgeInsetsPropType: require('EdgeInsetsPropType'),
-  PointPropType: require('PointPropType'),
+  get EdgeInsetsPropType() { return require('EdgeInsetsPropType'); },
+  get PointPropType() { return require('PointPropType'); },
 
   // See http://facebook.github.io/react/docs/addons.html
   addons: {
-    LinkedStateMixin: require('LinkedStateMixin'),
+    get LinkedStateMixin() { return require('LinkedStateMixin'); },
     Perf: undefined,
-    PureRenderMixin: require('ReactComponentWithPureRenderMixin'),
-    TestModule: require('NativeModules').TestModule,
+    get PureRenderMixin() { return require('ReactComponentWithPureRenderMixin'); },
+    get TestModule() { return require('NativeModules').TestModule; },
     TestUtils: undefined,
-    batchedUpdates: require('ReactUpdates').batchedUpdates,
-    cloneWithProps: require('cloneWithProps'),
-    createFragment: require('ReactFragment').create,
-    update: require('update'),
+    get batchedUpdates() { return require('ReactUpdates').batchedUpdates; },
+    get cloneWithProps() { return require('cloneWithProps'); },
+    get createFragment() { return require('ReactFragment').create; },
+    get update() { return require('update'); },
   },
-});
+  
+  // Note: this must be placed last to prevent eager
+  // evaluation of the getter-wrapped submodules above
+  ...require('React'),
+};
 
 if (__DEV__) {
-  ReactNative.addons.Perf = require('ReactDefaultPerf');
-  ReactNative.addons.TestUtils = require('ReactTestUtils');
+  Object.defineProperty(ReactNative.addons, 'Perf', {
+    enumerable: true, 
+    get: () => require('ReactDefaultPerf'),
+  });
+  Object.defineProperty(ReactNative.addons, 'TestUtils', {
+    enumerable: true, 
+    get: () => require('ReactTestUtils'),
+  });
 }
 
 module.exports = ReactNative;

From 61272e69e935fd96029c922487d1fac0c463c5af Mon Sep 17 00:00:00 2001
From: Sam Swarr <swarr@fb.com>
Date: Mon, 7 Dec 2015 19:22:52 -0800
Subject: [PATCH 0263/1411] Fix race condition in packager list dependencies

Reviewed By: martinbigio

Differential Revision: D2732655

fb-gh-sync-id: 6d3d730b499c183d3f6977a30ec37a799cc17c33
---
 local-cli/dependencies/dependencies.js | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/local-cli/dependencies/dependencies.js b/local-cli/dependencies/dependencies.js
index 54c1b004f8ab..6a8fbb31091d 100644
--- a/local-cli/dependencies/dependencies.js
+++ b/local-cli/dependencies/dependencies.js
@@ -104,7 +104,9 @@ function _dependencies(argv, config, resolve, reject) {
             outStream.write(modulePath + '\n');
           }
         });
-        writeToFile && outStream.end();
+        return writeToFile
+          ? Promise.denodeify(outStream.end).bind(outStream)()
+          : Promise.resolve();
         // log('Wrote dependencies to output file');
       });
   }));

From 17428982eb5e584a40f1b19d9b6780ee5e13c604 Mon Sep 17 00:00:00 2001
From: Christopher Dro <hello@blick-labs.com>
Date: Mon, 7 Dec 2015 23:06:04 -0800
Subject: [PATCH 0264/1411] [Docs] Typo fix for adb reverse command in
 Debugging.md

---
 docs/Debugging.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/Debugging.md b/docs/Debugging.md
index 26a7ca44703f..259f6ca7d992 100644
--- a/docs/Debugging.md
+++ b/docs/Debugging.md
@@ -31,7 +31,7 @@ In Chrome, press `⌘ + option + i` or select `View` → `Developer` → `Develo
 To debug on a real device:
 
 1. On iOS - open the file `RCTWebSocketExecutor.m` and change `localhost` to the IP address of your computer. Shake the device to open the development menu with the option to start debugging.
-2. On Android, if you're running Android 5.0+ device connected via USB you can use `adb` command line tool to setup port forwarding from the device to your computer. For that run: `adb reverse 8081 8081` (see [this link](http://developer.android.com/tools/help/adb.html) for help on `adb` command). Alternatively, you can [open dev menu](#debugging-react-native-apps) on the device and select `Dev Settings`, then update `Debug server host for device` setting to the IP address of your computer.
+2. On Android, if you're running Android 5.0+ device connected via USB you can use `adb` command line tool to setup port forwarding from the device to your computer. For that run: `adb reverse tcp:8081 tcp:8081` (see [this link](http://developer.android.com/tools/help/adb.html) for help on `adb` command). Alternatively, you can [open dev menu](#debugging-react-native-apps) on the device and select `Dev Settings`, then update `Debug server host for device` setting to the IP address of your computer.
 
 #### React Developer Tools (optional)
 Install the [React Developer Tools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en) extension for Google Chrome. This will allow you to navigate the component hierarchy via the `React` in the developer tools (see [facebook/react-devtools](https://github.com/facebook/react-devtools) for more information).

From 4ce03582a0013e60417dedbf2f760d00e687e540 Mon Sep 17 00:00:00 2001
From: Spencer Ahrens <sahrens@fb.com>
Date: Mon, 7 Dec 2015 23:08:26 -0800
Subject: [PATCH 0265/1411] Improve Text perf

Summary:
public

Most apps create tons of text components but they are actually quite heavy because of the the Touchable mixin which requires binding tons of functions for every instance created.

This diff makes the binding lazy, so that the main handlers are only bound if there is a valid touch action configured (e.g. onPress), and the Touchable mixin functions are only bound the first time the node is actually touched and becomes the responder.

ScanLab testing shows 5-10% win on render time and memory for various products.

Reviewed By: sebmarkbage

Differential Revision: D2716823

fb-gh-sync-id: 30adb2ed2231c5635c9336369616cf31c776b930
---
 Libraries/Text/Text.js | 238 +++++++++++++++++++++--------------------
 1 file changed, 120 insertions(+), 118 deletions(-)

diff --git a/Libraries/Text/Text.js b/Libraries/Text/Text.js
index c9ca8357d952..69dc800ded6f 100644
--- a/Libraries/Text/Text.js
+++ b/Libraries/Text/Text.js
@@ -11,22 +11,22 @@
  */
 'use strict';
 
-var NativeMethodsMixin = require('NativeMethodsMixin');
-var Platform = require('Platform');
-var React = require('React');
-var ReactInstanceMap = require('ReactInstanceMap');
-var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
-var StyleSheetPropType = require('StyleSheetPropType');
-var TextStylePropTypes = require('TextStylePropTypes');
-var Touchable = require('Touchable');
-
-var createReactNativeComponentClass =
+const NativeMethodsMixin = require('NativeMethodsMixin');
+const Platform = require('Platform');
+const React = require('React');
+const ReactInstanceMap = require('ReactInstanceMap');
+const ReactNativeViewAttributes = require('ReactNativeViewAttributes');
+const StyleSheetPropType = require('StyleSheetPropType');
+const TextStylePropTypes = require('TextStylePropTypes');
+const Touchable = require('Touchable');
+
+const createReactNativeComponentClass =
   require('createReactNativeComponentClass');
-var merge = require('merge');
+const merge = require('merge');
 
-var stylePropType = StyleSheetPropType(TextStylePropTypes);
+const stylePropType = StyleSheetPropType(TextStylePropTypes);
 
-var viewConfig = {
+const viewConfig = {
   validAttributes: merge(ReactNativeViewAttributes.UIView, {
     isHighlighted: true,
     numberOfLines: true,
@@ -68,10 +68,7 @@ var viewConfig = {
  * ```
  */
 
-var Text = React.createClass({
-
-  mixins: [Touchable.Mixin, NativeMethodsMixin],
-
+const Text = React.createClass({
   propTypes: {
     /**
      * Used to truncate the text with an elipsis after computing the text
@@ -105,121 +102,126 @@ var Text = React.createClass({
      */
     allowFontScaling: React.PropTypes.bool,
   },
-
-  viewConfig: viewConfig,
-
-  getInitialState: function(): Object {
-    return merge(this.touchableGetInitialState(), {
-      isHighlighted: false,
-    });
-  },
-  getDefaultProps: function(): Object {
+  getDefaultProps(): Object {
     return {
+      accessible: true,
       allowFontScaling: true,
     };
   },
-
-  onStartShouldSetResponder: function(): bool {
-    var shouldSetFromProps = this.props.onStartShouldSetResponder &&
-      this.props.onStartShouldSetResponder();
-    return shouldSetFromProps || !!this.props.onPress;
-  },
-
-  /*
-   * Returns true to allow responder termination
-   */
-  handleResponderTerminationRequest: function(): bool {
-    // Allow touchable or props.onResponderTerminationRequest to deny
-    // the request
-    var allowTermination = this.touchableHandleResponderTerminationRequest();
-    if (allowTermination && this.props.onResponderTerminationRequest) {
-      allowTermination = this.props.onResponderTerminationRequest();
-    }
-    return allowTermination;
-  },
-
-  handleResponderGrant: function(e: SyntheticEvent, dispatchID: string) {
-    this.touchableHandleResponderGrant(e, dispatchID);
-    this.props.onResponderGrant &&
-      this.props.onResponderGrant.apply(this, arguments);
-  },
-
-  handleResponderMove: function(e: SyntheticEvent) {
-    this.touchableHandleResponderMove(e);
-    this.props.onResponderMove &&
-      this.props.onResponderMove.apply(this, arguments);
-  },
-
-  handleResponderRelease: function(e: SyntheticEvent) {
-    this.touchableHandleResponderRelease(e);
-    this.props.onResponderRelease &&
-      this.props.onResponderRelease.apply(this, arguments);
-  },
-
-  handleResponderTerminate: function(e: SyntheticEvent) {
-    this.touchableHandleResponderTerminate(e);
-    this.props.onResponderTerminate &&
-      this.props.onResponderTerminate.apply(this, arguments);
-  },
-
-  touchableHandleActivePressIn: function() {
-    if (this.props.suppressHighlighting || !this.props.onPress) {
-      return;
-    }
-    this.setState({
-      isHighlighted: true,
-    });
-  },
-
-  touchableHandleActivePressOut: function() {
-    if (this.props.suppressHighlighting || !this.props.onPress) {
-      return;
-    }
-    this.setState({
+  getInitialState: function(): Object {
+    return merge(Touchable.Mixin.touchableGetInitialState(), {
       isHighlighted: false,
     });
   },
-
-  touchableHandlePress: function() {
-    this.props.onPress && this.props.onPress();
-  },
-
-  touchableGetPressRectOffset: function(): RectOffset {
-    return PRESS_RECT_OFFSET;
-  },
-
-  getChildContext: function(): Object {
+  mixins: [NativeMethodsMixin],
+  viewConfig: viewConfig,
+  getChildContext(): Object {
     return {isInAParentText: true};
   },
-
   childContextTypes: {
     isInAParentText: React.PropTypes.bool
   },
-
-  render: function() {
-    var props = {};
-    for (var key in this.props) {
-      props[key] = this.props[key];
-    }
-    // Text is accessible by default
-    if (props.accessible !== false) {
-      props.accessible = true;
+  contextTypes: {
+    isInAParentText: React.PropTypes.bool
+  },
+  /**
+   * Only assigned if touch is needed.
+   */
+  _handlers: (null: ?Object),
+  /**
+   * These are assigned lazily the first time the responder is set to make plain
+   * text nodes as cheap as possible.
+   */
+  touchableHandleActivePressIn: (null: ?Function),
+  touchableHandleActivePressOut: (null: ?Function),
+  touchableHandlePress: (null: ?Function),
+  touchableGetPressRectOffset: (null: ?Function),
+  render(): ReactElement {
+    let newProps = this.props;
+    if (this.props.onStartShouldSetResponder || this.props.onPress) {
+      if (!this._handlers) {
+        this._handlers = {
+          onStartShouldSetResponder: (): bool => {
+            const shouldSetFromProps = this.props.onStartShouldSetResponder &&
+                this.props.onStartShouldSetResponder();
+            const setResponder = shouldSetFromProps || !!this.props.onPress;
+            if (setResponder && !this.touchableHandleActivePressIn) {
+              // Attach and bind all the other handlers only the first time a touch
+              // actually happens.
+              for (let key in Touchable.Mixin) {
+                if (typeof Touchable.Mixin[key] === 'function') {
+                  (this: any)[key] = Touchable.Mixin[key].bind(this);
+                }
+              }
+              this.touchableHandleActivePressIn = () => {
+                if (this.props.suppressHighlighting || !this.props.onPress) {
+                  return;
+                }
+                this.setState({
+                  isHighlighted: true,
+                });
+              };
+
+              this.touchableHandleActivePressOut = () => {
+                if (this.props.suppressHighlighting || !this.props.onPress) {
+                  return;
+                }
+                this.setState({
+                  isHighlighted: false,
+                });
+              };
+
+              this.touchableHandlePress = () => {
+                this.props.onPress && this.props.onPress();
+              };
+
+              this.touchableGetPressRectOffset = function(): RectOffset {
+                return PRESS_RECT_OFFSET;
+              };
+            }
+            return setResponder;
+          },
+          onResponderGrant: (e: SyntheticEvent, dispatchID: string) => {
+            this.touchableHandleResponderGrant(e, dispatchID);
+            this.props.onResponderGrant &&
+              this.props.onResponderGrant.apply(this, arguments);
+          },
+          onResponderMove: (e: SyntheticEvent) => {
+            this.touchableHandleResponderMove(e);
+            this.props.onResponderMove &&
+              this.props.onResponderMove.apply(this, arguments);
+          },
+          onResponderRelease: (e: SyntheticEvent) => {
+            this.touchableHandleResponderRelease(e);
+            this.props.onResponderRelease &&
+              this.props.onResponderRelease.apply(this, arguments);
+          },
+          onResponderTerminate: (e: SyntheticEvent) => {
+            this.touchableHandleResponderTerminate(e);
+            this.props.onResponderTerminate &&
+              this.props.onResponderTerminate.apply(this, arguments);
+          },
+          onResponderTerminationRequest: (): bool => {
+            // Allow touchable or props.onResponderTerminationRequest to deny
+            // the request
+            var allowTermination = this.touchableHandleResponderTerminationRequest();
+            if (allowTermination && this.props.onResponderTerminationRequest) {
+              allowTermination = this.props.onResponderTerminationRequest();
+            }
+            return allowTermination;
+          },
+        };
+      }
+      newProps = {
+        ...this.props,
+        ...this._handlers,
+        isHighlighted: this.state.isHighlighted,
+      };
     }
-    props.isHighlighted = this.state.isHighlighted;
-    props.onStartShouldSetResponder = this.onStartShouldSetResponder;
-    props.onResponderTerminationRequest =
-      this.handleResponderTerminationRequest;
-    props.onResponderGrant = this.handleResponderGrant;
-    props.onResponderMove = this.handleResponderMove;
-    props.onResponderRelease = this.handleResponderRelease;
-    props.onResponderTerminate = this.handleResponderTerminate;
-
-    // TODO: Switch to use contextTypes and this.context after React upgrade
-    var context = ReactInstanceMap.get(this)._context;
-    if (context.isInAParentText) {
-      return <RCTVirtualText {...props} />;
+    if (this.context.isInAParentText) {
+      return <RCTVirtualText {...newProps} />;
     } else {
-      return <RCTText {...props} />;
+      return <RCTText {...newProps} />;
     }
   },
 });

From c031ccdc57b7a3321c1753f15b2f44053072a102 Mon Sep 17 00:00:00 2001
From: James Ide <ide+github@jameside.com>
Date: Mon, 7 Dec 2015 23:23:26 -0800
Subject: [PATCH 0266/1411] JSX style

Wrote some notes on the standard JSX / XHP style
---
 CONTRIBUTING.md | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index aebef40cc862..fbb114cc3cb0 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -67,6 +67,14 @@ Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe
 * Do not use the optional parameters of `setTimeout` and `setInterval`
 * 80 character line length
 
+#### JSX
+
+* Prefer `'` over `"` for string literal props
+* When wrapping opening tags over multiple lines, place one prop per line
+* `{}` of props should hug their values (no spaces)
+* Place the closing `>` of opening tags on the same line as the last prop
+* Place the closing `/>` of self-closing tags on their own line and left-align them wih the opening `<`
+
 #### Objective-C
 
 * Space after `@property` declarations

From a659c9346ced1540beca151b049207b958bd3135 Mon Sep 17 00:00:00 2001
From: James Ide <ide+github@jameside.com>
Date: Mon, 7 Dec 2015 23:24:23 -0800
Subject: [PATCH 0267/1411] [Docs] Fix up small typo in code style docs

---
 CONTRIBUTING.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index fbb114cc3cb0..530c84098e85 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -73,7 +73,7 @@ Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe
 * When wrapping opening tags over multiple lines, place one prop per line
 * `{}` of props should hug their values (no spaces)
 * Place the closing `>` of opening tags on the same line as the last prop
-* Place the closing `/>` of self-closing tags on their own line and left-align them wih the opening `<`
+* Place the closing `/>` of self-closing tags on their own line and left-align them with the opening `<`
 
 #### Objective-C
 

From dcebe8cd374d149dd9d870f77967554b0d1f3802 Mon Sep 17 00:00:00 2001
From: Mike Armstrong <mikea@fb.com>
Date: Tue, 8 Dec 2015 01:35:57 -0800
Subject: [PATCH 0268/1411] Use ascii characters to construct JSStringRef

Reviewed By: astreet

Differential Revision: D2700781

fb-gh-sync-id: be790600ea3d4c0238553efe69a0979c177ddb2d
---
 ReactAndroid/src/main/jni/react/JSCExecutor.cpp |  3 +--
 ReactAndroid/src/main/jni/react/Value.h         | 11 +++++++++++
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index 93bb17fbad13..5f23c2b880df 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -117,9 +117,8 @@ void JSCExecutor::executeApplicationScript(
   jstring endStringMarker = env->NewStringUTF("executeApplicationScript_endStringConvert");
 
   env->CallStaticVoidMethod(markerClass, logMarkerMethod, startStringMarker);
-  String jsScript(script.c_str());
+  String jsScript = String::createExpectingAscii(script);
   env->CallStaticVoidMethod(markerClass, logMarkerMethod, endStringMarker);
-
   env->DeleteLocalRef(startStringMarker);
   env->DeleteLocalRef(endStringMarker);
 
diff --git a/ReactAndroid/src/main/jni/react/Value.h b/ReactAndroid/src/main/jni/react/Value.h
index bb10f9a85713..b39bdef304db 100644
--- a/ReactAndroid/src/main/jni/react/Value.h
+++ b/ReactAndroid/src/main/jni/react/Value.h
@@ -8,6 +8,9 @@
 #include <JavaScriptCore/JSStringRef.h>
 #include <JavaScriptCore/JSValueRef.h>
 #include <fb/noncopyable.h>
+#if WITH_FBJSCEXTENSIONS
+#include <jsc_stringref.h>
+#endif
 
 namespace facebook {
 namespace react {
@@ -53,6 +56,14 @@ class String : public noncopyable {
     return JSStringIsEqualToUTF8CString(m_string.get(), utf8);
   }
 
+  static String createExpectingAscii(std::string const &utf8) {
+  #if WITH_FBJSCEXTENSIONS
+    return String(Adopt, JSStringCreateWithUTF8CStringExpectAscii(utf8.c_str(), utf8.size()));
+  #else
+    return String(Adopt, JSStringCreateWithUTF8CString(utf8.c_str()));
+  #endif
+  }
+
   static String ref(JSStringRef string) {
     return String(string);
   }

From b67229485834113674b25bda193a7426bf44cfc8 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Tue, 8 Dec 2015 03:29:08 -0800
Subject: [PATCH 0269/1411] Added RCTImageSource

Summary:
public

The +[RCTConvert UIImage:] function, while convenient, is inherently limited by being synchronous, which means that it cannot be used to load remote images, and may not be efficient for local images either. It's also unable to access the bridge, which means that it cannot take advantage of the modular image-loading pipeline.

This diff introduces a new RCTImageSource class which can be used to pass image source objects over the bridge and defer loading until later.

I've also added automatic application of the `resolveAssetSource()` function based on prop type, and fixed up the image logic in NavigatorIOS and TabBarIOS.

Reviewed By: javache

Differential Revision: D2631541

fb-gh-sync-id: 6604635e8bb5394425102487f1ee7cd729321877
---
 .../Components/Navigation/NavigatorIOS.ios.js |  39 ++---
 .../Components/TabBarIOS/TabBarItemIOS.ios.js |  28 +---
 Libraries/Image/Image.ios.js                  |  41 ++---
 Libraries/Image/RCTImageUtils.m               |  11 +-
 Libraries/Image/RCTImageView.h                |   3 +-
 Libraries/Image/RCTImageView.m                |  72 ++++----
 Libraries/Image/RCTImageViewManager.m         |  18 +-
 Libraries/Image/RCTShadowVirtualImage.h       |   3 +-
 Libraries/Image/RCTShadowVirtualImage.m       |  36 ++--
 Libraries/Image/RCTVirtualImageManager.m      |   2 +-
 Libraries/ReactIOS/requireNativeComponent.js  |   5 +
 React/Base/RCTConvert.h                       |  15 +-
 React/Base/RCTConvert.m                       | 156 ++++++++++--------
 React/Base/RCTImageSource.h                   |  43 +++++
 React/Base/RCTImageSource.m                   |  83 ++++++++++
 React/Base/RCTLog.m                           |   3 +
 React/React.xcodeproj/project.pbxproj         |   8 +-
 React/Views/RCTNavItem.h                      |   4 +-
 React/Views/RCTNavItem.m                      |  20 +--
 React/Views/RCTNavItemManager.m               |   4 +-
 React/Views/RCTTabBarItem.h                   |   4 +-
 React/Views/RCTTabBarItem.m                   | 107 ++++++------
 React/Views/RCTTabBarItemManager.m            |   5 +-
 23 files changed, 434 insertions(+), 276 deletions(-)
 create mode 100644 React/Base/RCTImageSource.h
 create mode 100644 React/Base/RCTImageSource.m

diff --git a/Libraries/Components/Navigation/NavigatorIOS.ios.js b/Libraries/Components/Navigation/NavigatorIOS.ios.js
index 6d86930b7a6f..87f49232bffe 100644
--- a/Libraries/Components/Navigation/NavigatorIOS.ios.js
+++ b/Libraries/Components/Navigation/NavigatorIOS.ios.js
@@ -312,6 +312,12 @@ var NavigatorIOS = React.createClass({
     this.navigationContext = new NavigationContext();
   },
 
+  getDefaultProps: function(): Object {
+    return {
+      translucent: true,
+    };
+  },
+
   getInitialState: function(): State {
     return {
       idStack: [getuid()],
@@ -591,37 +597,26 @@ var NavigatorIOS = React.createClass({
   },
 
   _routeToStackItem: function(route: Route, i: number) {
-    var Component = route.component;
-    var shouldUpdateChild = this.state.updatingAllIndicesAtOrBeyond != null &&
+    var {component, wrapperStyle, passProps, ...route} = route;
+    var {itemWrapperStyle, ...props} = this.props;
+    var shouldUpdateChild =
+      this.state.updatingAllIndicesAtOrBeyond &&
       this.state.updatingAllIndicesAtOrBeyond >= i;
-
+    var Component = component;
     return (
       <StaticContainer key={'nav' + i} shouldUpdate={shouldUpdateChild}>
         <RCTNavigatorItem
-          title={route.title}
+          {...route}
+          {...props}
           style={[
             styles.stackItem,
-            this.props.itemWrapperStyle,
-            route.wrapperStyle
-          ]}
-          backButtonIcon={resolveAssetSource(route.backButtonIcon)}
-          backButtonTitle={route.backButtonTitle}
-          leftButtonIcon={resolveAssetSource(route.leftButtonIcon)}
-          leftButtonTitle={route.leftButtonTitle}
-          onNavLeftButtonTap={route.onLeftButtonPress}
-          rightButtonIcon={resolveAssetSource(route.rightButtonIcon)}
-          rightButtonTitle={route.rightButtonTitle}
-          onNavRightButtonTap={route.onRightButtonPress}
-          navigationBarHidden={this.props.navigationBarHidden}
-          shadowHidden={this.props.shadowHidden}
-          tintColor={this.props.tintColor}
-          barTintColor={this.props.barTintColor}
-          translucent={this.props.translucent !== false}
-          titleTextColor={this.props.titleTextColor}>
+            itemWrapperStyle,
+            wrapperStyle
+          ]}>
           <Component
             navigator={this.navigator}
             route={route}
-            {...route.passProps}
+            {...passProps}
           />
         </RCTNavigatorItem>
       </StaticContainer>
diff --git a/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js b/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js
index 20e0cf624066..f3fb6964ca7f 100644
--- a/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js
+++ b/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js
@@ -16,7 +16,6 @@ var React = require('React');
 var StaticContainer = require('StaticContainer.react');
 var StyleSheet = require('StyleSheet');
 var View = require('View');
-var resolveAssetSource = require('resolveAssetSource');
 
 var requireNativeComponent = require('requireNativeComponent');
 
@@ -52,10 +51,7 @@ var TabBarItemIOS = React.createClass({
     /**
      * A custom icon for the tab. It is ignored when a system icon is defined.
      */
-    icon: React.PropTypes.oneOfType([
-      React.PropTypes.string,
-      Image.propTypes.source,
-    ]),
+    icon: Image.propTypes.source,
     /**
      * A custom icon when the tab is selected. It is ignored when a system
      * icon is defined. If left empty, the icon will be tinted in blue.
@@ -101,29 +97,23 @@ var TabBarItemIOS = React.createClass({
   },
 
   render: function() {
-    var tabContents = null;
+    var {style, children, ...props} = this.props;
+
     // if the tab has already been shown once, always continue to show it so we
     // preserve state between tab transitions
     if (this.state.hasBeenSelected) {
-      tabContents =
+      var tabContents =
         <StaticContainer shouldUpdate={this.props.selected}>
-          {this.props.children}
+          {children}
         </StaticContainer>;
     } else {
-      tabContents = <View />;
+      var tabContents = <View />;
     }
-
-    var badge = typeof this.props.badge === 'number' ?
-      '' + this.props.badge :
-      this.props.badge;
-
+    
     return (
       <RCTTabBarItem
-        {...this.props}
-        icon={this.props.systemIcon || resolveAssetSource(this.props.icon)}
-        selectedIcon={resolveAssetSource(this.props.selectedIcon)}
-        badge={badge}
-        style={[styles.tab, this.props.style]}>
+        {...props}
+        style={[styles.tab, style]}>
         {tabContents}
       </RCTTabBarItem>
     );
diff --git a/Libraries/Image/Image.ios.js b/Libraries/Image/Image.ios.js
index 6943bf909e33..2b649bf9cc6f 100644
--- a/Libraries/Image/Image.ios.js
+++ b/Libraries/Image/Image.ios.js
@@ -69,13 +69,16 @@ var Image = React.createClass({
       PropTypes.number,
     ]),
     /**
-     * A static image to display while downloading the final image off the
-     * network.
+     * A static image to display while loading the image source.
      * @platform ios
      */
-    defaultSource: PropTypes.shape({
-      uri: PropTypes.string,
-    }),
+    defaultSource: PropTypes.oneOfType([
+      PropTypes.shape({
+        uri: PropTypes.string,
+      }),
+      // Opaque type returned by require('./image.jpg')
+      PropTypes.number,
+    ]),
     /**
      * When true, indicates the image is an accessibility element.
      * @platform ios
@@ -155,23 +158,10 @@ var Image = React.createClass({
   },
 
   render: function() {
-    for (var prop in cfg.nativeOnly) {
-      if (this.props[prop] !== undefined) {
-        console.warn('Prop `' + prop + ' = ' + this.props[prop] + '` should ' +
-          'not be set directly on Image.');
-      }
-    }
     var source = resolveAssetSource(this.props.source) || {};
-    var defaultSource = (this.props.defaultSource && resolveAssetSource(this.props.defaultSource)) || {};
-
     var {width, height} = source;
     var style = flattenStyle([{width, height}, styles.base, this.props.style]) || {};
 
-    if (source.uri === '') {
-      console.warn('source.uri should not be an empty string');
-      return <View {...this.props} style={style} />;
-    }
-
     var isNetwork = source.uri && source.uri.match(/^https?:/);
     var RawImage = isNetwork ? RCTNetworkImageView : RCTImageView;
     var resizeMode = this.props.resizeMode || (style || {}).resizeMode || 'cover'; // Workaround for flow bug t7737108
@@ -192,8 +182,7 @@ var Image = React.createClass({
           style={style}
           resizeMode={resizeMode}
           tintColor={tintColor}
-          src={source.uri}
-          defaultImageSrc={defaultSource.uri}
+          source={source}
         />
       );
     }
@@ -206,16 +195,8 @@ var styles = StyleSheet.create({
   },
 });
 
-var cfg = {
-  nativeOnly: {
-    src: true,
-    defaultImageSrc: true,
-    imageTag: true,
-    progressHandlerRegistered: true,
-  },
-};
-var RCTImageView = requireNativeComponent('RCTImageView', Image, cfg);
-var RCTNetworkImageView = NativeModules.NetworkImageViewManager ? requireNativeComponent('RCTNetworkImageView', Image, cfg) : RCTImageView;
+var RCTImageView = requireNativeComponent('RCTImageView', Image);
+var RCTNetworkImageView = NativeModules.NetworkImageViewManager ? requireNativeComponent('RCTNetworkImageView', Image) : RCTImageView;
 var RCTVirtualImage = requireNativeComponent('RCTVirtualImage', Image);
 
 module.exports = Image;
diff --git a/Libraries/Image/RCTImageUtils.m b/Libraries/Image/RCTImageUtils.m
index 3146a5b5611d..a6c2ccd46098 100644
--- a/Libraries/Image/RCTImageUtils.m
+++ b/Libraries/Image/RCTImageUtils.m
@@ -231,6 +231,11 @@ CGSize RCTSizeInPixels(CGSize pointSize, CGFloat scale)
 
   if (CGSizeEqualToSize(destSize, CGSizeZero)) {
     destSize = sourceSize;
+    if (!destScale) {
+      destScale = 1;
+    }
+  } else if (!destScale) {
+    destScale = RCTScreenScale();
   }
 
   // calculate target size
@@ -253,13 +258,9 @@ CGSize RCTSizeInPixels(CGSize pointSize, CGFloat scale)
     return nil;
   }
 
-  // adjust scale
-  size_t actualWidth = CGImageGetWidth(imageRef);
-  CGFloat scale = actualWidth / targetSize.width * destScale;
-
   // return image
   UIImage *image = [UIImage imageWithCGImage:imageRef
-                                       scale:scale
+                                       scale:destScale
                                  orientation:UIImageOrientationUp];
   CGImageRelease(imageRef);
   return image;
diff --git a/Libraries/Image/RCTImageView.h b/Libraries/Image/RCTImageView.h
index a561c0f7f938..8b5b993a731a 100644
--- a/Libraries/Image/RCTImageView.h
+++ b/Libraries/Image/RCTImageView.h
@@ -11,6 +11,7 @@
 #import "RCTImageComponent.h"
 
 @class RCTBridge;
+@class RCTImageSource;
 
 @interface RCTImageView : UIImageView <RCTImageComponent>
 
@@ -19,6 +20,6 @@
 @property (nonatomic, assign) UIEdgeInsets capInsets;
 @property (nonatomic, strong) UIImage *defaultImage;
 @property (nonatomic, assign) UIImageRenderingMode renderingMode;
-@property (nonatomic, copy) NSString *src;
+@property (nonatomic, strong) RCTImageSource *source;
 
 @end
diff --git a/Libraries/Image/RCTImageView.m b/Libraries/Image/RCTImageView.m
index 246220840614..656dd61e896e 100644
--- a/Libraries/Image/RCTImageView.m
+++ b/Libraries/Image/RCTImageView.m
@@ -13,6 +13,7 @@
 #import "RCTConvert.h"
 #import "RCTEventDispatcher.h"
 #import "RCTImageLoader.h"
+#import "RCTImageSource.h"
 #import "RCTImageUtils.h"
 #import "RCTUtils.h"
 
@@ -107,6 +108,12 @@ - (void)setCapInsets:(UIEdgeInsets)capInsets
   }
 }
 
+- (void)setTintColor:(UIColor *)tintColor
+{
+  super.tintColor = tintColor;
+  self.renderingMode = tintColor ? UIImageRenderingModeAlwaysTemplate : UIImageRenderingModeAlwaysOriginal;
+}
+
 - (void)setRenderingMode:(UIImageRenderingMode)renderingMode
 {
   if (_renderingMode != renderingMode) {
@@ -115,28 +122,29 @@ - (void)setRenderingMode:(UIImageRenderingMode)renderingMode
   }
 }
 
-- (void)setSrc:(NSString *)src
+- (void)setSource:(RCTImageSource *)source
 {
-  if (![src isEqual:_src]) {
-    _src = [src copy];
+  if (![source isEqual:_source]) {
+    _source = source;
     [self reloadImage];
   }
 }
 
-+ (BOOL)srcNeedsReload:(NSString *)src
+- (BOOL)sourceNeedsReload
 {
+  NSString *scheme = _source.imageURL.scheme;
   return
-    [src hasPrefix:@"http://"] ||
-    [src hasPrefix:@"https://"] ||
-    [src hasPrefix:@"assets-library://"] ||
-    [src hasPrefix:@"ph://"];
+    [scheme isEqualToString:@"http"] ||
+    [scheme isEqualToString:@"https"] ||
+    [scheme isEqualToString:@"assets-library"] ||
+    [scheme isEqualToString:@"ph"];
 }
 
 - (void)setContentMode:(UIViewContentMode)contentMode
 {
   if (self.contentMode != contentMode) {
     super.contentMode = contentMode;
-    if ([RCTImageView srcNeedsReload:_src]) {
+    if ([self sourceNeedsReload]) {
       [self reloadImage];
     }
   }
@@ -162,7 +170,7 @@ - (void)reloadImage
 {
   [self cancelImageLoad];
 
-  if (_src && self.frame.size.width > 0 && self.frame.size.height > 0) {
+  if (_source && self.frame.size.width > 0 && self.frame.size.height > 0) {
     if (_onLoadStart) {
       _onLoadStart(nil);
     }
@@ -177,31 +185,37 @@ - (void)reloadImage
       };
     }
 
-    _reloadImageCancellationBlock = [_bridge.imageLoader loadImageWithTag:_src
+    RCTImageSource *source = _source;
+    __weak RCTImageView *weakSelf = self;
+    _reloadImageCancellationBlock = [_bridge.imageLoader loadImageWithTag:_source.imageURL.absoluteString
                                                                      size:self.bounds.size
                                                                     scale:RCTScreenScale()
                                                                resizeMode:self.contentMode
                                                             progressBlock:progressHandler
                                                           completionBlock:^(NSError *error, UIImage *image) {
-      if (error) {
-        if (_onError) {
-          _onError(@{ @"error": error.localizedDescription });
-        }
-      } else {
-        if (_onLoad) {
-          _onLoad(nil);
-        }
-      }
-      if (_onLoadEnd) {
-         _onLoadEnd(nil);
-      }
-
       dispatch_async(dispatch_get_main_queue(), ^{
+        RCTImageView *strongSelf = weakSelf;
+        if (![source isEqual:strongSelf.source]) {
+          // Bail out if source has changed since we started loading
+          return;
+        }
         if (image.reactKeyframeAnimation) {
-          [self.layer addAnimation:image.reactKeyframeAnimation forKey:@"contents"];
+          [strongSelf.layer addAnimation:image.reactKeyframeAnimation forKey:@"contents"];
         } else {
-          [self.layer removeAnimationForKey:@"contents"];
-          self.image = image;
+          [strongSelf.layer removeAnimationForKey:@"contents"];
+          strongSelf.image = image;
+        }
+        if (error) {
+          if (strongSelf->_onError) {
+            strongSelf->_onError(@{ @"error": error.localizedDescription });
+          }
+        } else {
+          if (strongSelf->_onLoad) {
+            strongSelf->_onLoad(nil);
+          }
+        }
+        if (strongSelf->_onLoadEnd) {
+           strongSelf->_onLoadEnd(nil);
         }
       });
     }];
@@ -217,13 +231,13 @@ - (void)reactSetFrame:(CGRect)frame
   if (!self.image || self.image == _defaultImage) {
     _targetSize = frame.size;
     [self reloadImage];
-  } else if ([RCTImageView srcNeedsReload:_src]) {
+  } else if ([self sourceNeedsReload]) {
     CGSize imageSize = self.image.size;
     CGSize idealSize = RCTTargetSize(imageSize, self.image.scale, frame.size, RCTScreenScale(), self.contentMode, YES);
 
     if (RCTShouldReloadImageForSizeChange(imageSize, idealSize)) {
       if (RCTShouldReloadImageForSizeChange(_targetSize, idealSize)) {
-        RCTLogInfo(@"[PERF IMAGEVIEW] Reloading image %@ as size %@", _src, NSStringFromCGSize(idealSize));
+        RCTLogInfo(@"[PERF IMAGEVIEW] Reloading image %@ as size %@", _source.imageURL, NSStringFromCGSize(idealSize));
 
         // If the existing image or an image being loaded are not the right size, reload the asset in case there is a
         // better size available.
diff --git a/Libraries/Image/RCTImageViewManager.m b/Libraries/Image/RCTImageViewManager.m
index bcf2f0bdb4d0..c2067889539d 100644
--- a/Libraries/Image/RCTImageViewManager.m
+++ b/Libraries/Image/RCTImageViewManager.m
@@ -12,6 +12,7 @@
 #import <UIKit/UIKit.h>
 
 #import "RCTConvert.h"
+#import "RCTImageSource.h"
 #import "RCTImageView.h"
 
 @implementation RCTImageViewManager
@@ -24,23 +25,14 @@ - (UIView *)view
 }
 
 RCT_EXPORT_VIEW_PROPERTY(capInsets, UIEdgeInsets)
-RCT_REMAP_VIEW_PROPERTY(defaultImageSrc, defaultImage, UIImage)
-RCT_REMAP_VIEW_PROPERTY(resizeMode, contentMode, UIViewContentMode)
-RCT_EXPORT_VIEW_PROPERTY(src, NSString)
+RCT_REMAP_VIEW_PROPERTY(defaultSource, defaultImage, UIImage)
 RCT_EXPORT_VIEW_PROPERTY(onLoadStart, RCTDirectEventBlock)
 RCT_EXPORT_VIEW_PROPERTY(onProgress, RCTDirectEventBlock)
 RCT_EXPORT_VIEW_PROPERTY(onError, RCTDirectEventBlock)
 RCT_EXPORT_VIEW_PROPERTY(onLoad, RCTDirectEventBlock)
 RCT_EXPORT_VIEW_PROPERTY(onLoadEnd, RCTDirectEventBlock)
-RCT_CUSTOM_VIEW_PROPERTY(tintColor, UIColor, RCTImageView)
-{
-  if (json) {
-    view.renderingMode = UIImageRenderingModeAlwaysTemplate;
-    view.tintColor = [RCTConvert UIColor:json];
-  } else {
-    view.renderingMode = defaultView.renderingMode;
-    view.tintColor = defaultView.tintColor;
-  }
-}
+RCT_REMAP_VIEW_PROPERTY(resizeMode, contentMode, UIViewContentMode)
+RCT_EXPORT_VIEW_PROPERTY(source, RCTImageSource)
+RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
 
 @end
diff --git a/Libraries/Image/RCTShadowVirtualImage.h b/Libraries/Image/RCTShadowVirtualImage.h
index 841c215e2b4f..bd8bb51ae024 100644
--- a/Libraries/Image/RCTShadowVirtualImage.h
+++ b/Libraries/Image/RCTShadowVirtualImage.h
@@ -9,6 +9,7 @@
 
 #import "RCTShadowView.h"
 #import "RCTImageComponent.h"
+#import "RCTImageSource.h"
 
 @class RCTBridge;
 
@@ -20,6 +21,6 @@
 
 - (instancetype)initWithBridge:(RCTBridge *)bridge;
 
-@property (nonatomic, copy) NSDictionary *source;
+@property (nonatomic, strong) RCTImageSource *source;
 
 @end
diff --git a/Libraries/Image/RCTShadowVirtualImage.m b/Libraries/Image/RCTShadowVirtualImage.m
index 431fbac07afe..f3486f9a2f7a 100644
--- a/Libraries/Image/RCTShadowVirtualImage.m
+++ b/Libraries/Image/RCTShadowVirtualImage.m
@@ -16,6 +16,7 @@
 @implementation RCTShadowVirtualImage
 {
   RCTBridge *_bridge;
+  RCTImageLoaderCancellationBlock _cancellationBlock;
 }
 
 @synthesize image = _image;
@@ -30,23 +31,31 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
 
 RCT_NOT_IMPLEMENTED(-(instancetype)init)
 
-- (void)setSource:(NSDictionary *)source
+- (void)setSource:(RCTImageSource *)source
 {
   if (![source isEqual:_source]) {
-    _source = [source copy];
-    NSString *imageTag = [RCTConvert NSString:_source[@"uri"]];
-    CGFloat scale = [RCTConvert CGFloat:_source[@"scale"]] ?: 1;
+
+    // Cancel previous request
+    if (_cancellationBlock) {
+      _cancellationBlock();
+    }
+
+    _source = source;
 
     __weak RCTShadowVirtualImage *weakSelf = self;
-    [_bridge.imageLoader loadImageWithTag:imageTag
-                                     size:CGSizeZero
-                                    scale:scale
-                               resizeMode:UIViewContentModeScaleToFill
-                            progressBlock:nil
-                          completionBlock:^(NSError *error, UIImage *image) {
+    _cancellationBlock = [_bridge.imageLoader loadImageWithTag:source.imageURL.absoluteString
+                                                          size:source.size
+                                                         scale:source.scale
+                                                    resizeMode:UIViewContentModeScaleToFill
+                                                 progressBlock:nil
+                                               completionBlock:^(NSError *error, UIImage *image) {
 
       dispatch_async(_bridge.uiManager.methodQueue, ^{
         RCTShadowVirtualImage *strongSelf = weakSelf;
+        if (![source isEqual:strongSelf.source]) {
+          // Bail out if source has changed since we started loading
+          return;
+        }
         strongSelf->_image = image;
         [strongSelf dirtyText];
       });
@@ -54,4 +63,11 @@ - (void)setSource:(NSDictionary *)source
   }
 }
 
+- (void)dealloc
+{
+  if (_cancellationBlock) {
+    _cancellationBlock();
+  }
+}
+
 @end
diff --git a/Libraries/Image/RCTVirtualImageManager.m b/Libraries/Image/RCTVirtualImageManager.m
index 2800a92b0d8b..d497026ab740 100644
--- a/Libraries/Image/RCTVirtualImageManager.m
+++ b/Libraries/Image/RCTVirtualImageManager.m
@@ -19,6 +19,6 @@ - (RCTShadowView *)shadowView
   return [[RCTShadowVirtualImage alloc] initWithBridge:self.bridge];
 }
 
-RCT_EXPORT_SHADOW_PROPERTY(source, NSDictionary)
+RCT_EXPORT_SHADOW_PROPERTY(source, RCTImageSource)
 
 @end
diff --git a/Libraries/ReactIOS/requireNativeComponent.js b/Libraries/ReactIOS/requireNativeComponent.js
index a046fcbd1498..84789e6cf61d 100644
--- a/Libraries/ReactIOS/requireNativeComponent.js
+++ b/Libraries/ReactIOS/requireNativeComponent.js
@@ -16,10 +16,12 @@ var UIManager = require('UIManager');
 var UnimplementedView = require('UnimplementedView');
 
 var createReactNativeComponentClass = require('createReactNativeComponentClass');
+
 var insetsDiffer = require('insetsDiffer');
 var pointsDiffer = require('pointsDiffer');
 var matricesDiffer = require('matricesDiffer');
 var processColor = require('processColor');
+var resolveAssetSource = require('resolveAssetSource');
 var sizesDiffer = require('sizesDiffer');
 var verifyPropTypes = require('verifyPropTypes');
 var warning = require('warning');
@@ -110,6 +112,9 @@ var TypeToProcessorMap = {
   CGColorArray: processColor,
   UIColor: processColor,
   UIColorArray: processColor,
+  CGImage: resolveAssetSource,
+  UIImage: resolveAssetSource,
+  RCTImageSource: resolveAssetSource,
   // Android Types
   Color: processColor,
 };
diff --git a/React/Base/RCTConvert.h b/React/Base/RCTConvert.h
index 3d1c4291d11a..6347cc9cab70 100644
--- a/React/Base/RCTConvert.h
+++ b/React/Base/RCTConvert.h
@@ -85,9 +85,6 @@ typedef NSURL RCTFileURL;
 + (UIColor *)UIColor:(id)json;
 + (CGColorRef)CGColor:(id)json CF_RETURNS_NOT_RETAINED;
 
-+ (UIImage *)UIImage:(id)json;
-+ (CGImageRef)CGImage:(id)json CF_RETURNS_NOT_RETAINED;
-
 + (UIFont *)UIFont:(id)json;
 + (UIFont *)UIFont:(UIFont *)font withSize:(id)json;
 + (UIFont *)UIFont:(UIFont *)font withWeight:(id)json;
@@ -146,6 +143,18 @@ typedef BOOL css_clip_t, css_backface_visibility_t;
 
 @end
 
+@interface RCTConvert (Deprecated)
+
+/**
+ * Synchronous image loading is generally a bad idea for performance reasons.
+ * If you need to pass image references, try to use `RCTImageSource` and then
+ * `RCTImageLoader` instead of converting directly to a UIImage.
+ */
++ (UIImage *)UIImage:(id)json;
++ (CGImageRef)CGImage:(id)json CF_RETURNS_NOT_RETAINED;
+
+@end
+
 /**
  * Underlying implementations of RCT_XXX_CONVERTER macros. Ignore these.
  */
diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m
index b2c033b38dbc..244fe6c0af29 100644
--- a/React/Base/RCTConvert.m
+++ b/React/Base/RCTConvert.m
@@ -12,6 +12,7 @@
 #import <objc/message.h>
 
 #import "RCTDefines.h"
+#import "RCTImageSource.h"
 #import "RCTUtils.h"
 
 @implementation RCTConvert
@@ -421,7 +422,7 @@ + (UIColor *)UIColor:(id)json
     CGFloat b = (argb & 0xFF) / 255.0;
     return [UIColor colorWithRed:r green:g blue:b alpha:a];
   } else {
-    RCTLogConvertError(json, @"a color");
+    RCTLogConvertError(json, @"a UIColor. Did you forget to call processColor() on the JS side?");
     return nil;
   }
 }
@@ -431,78 +432,6 @@ + (CGColorRef)CGColor:(id)json
   return [self UIColor:json].CGColor;
 }
 
-/* This method is only used when loading images synchronously, e.g. for tabbar icons */
-+ (UIImage *)UIImage:(id)json
-{
-  // TODO: we might as well cache the result of these checks (and possibly the
-  // image itself) so as to reduce overhead on subsequent checks of the same input
-
-  if (!json) {
-    return nil;
-  }
-
-  __block UIImage *image;
-  if (![NSThread isMainThread]) {
-    // It seems that none of the UIImage loading methods can be guaranteed
-    // thread safe, so we'll pick the lesser of two evils here and block rather
-    // than run the risk of crashing
-    RCTLogWarn(@"Calling [RCTConvert UIImage:] on a background thread is not recommended");
-    dispatch_sync(dispatch_get_main_queue(), ^{
-      image = [self UIImage:json];
-    });
-    return image;
-  }
-
-  NSString *path;
-  CGFloat scale = 0.0;
-  BOOL isPackagerAsset = NO;
-  if ([json isKindOfClass:[NSString class]]) {
-    path = json;
-  } else if ([json isKindOfClass:[NSDictionary class]]) {
-    if (!(path = [self NSString:json[@"uri"]])) {
-      return nil;
-    }
-    scale = [self CGFloat:json[@"scale"]];
-    isPackagerAsset = [self BOOL:json[@"__packager_asset"]];
-  } else {
-    RCTLogConvertError(json, @"an image");
-    return nil;
-  }
-
-  NSURL *URL = [self NSURL:path];
-  NSString *scheme = URL.scheme.lowercaseString;
-  if ([scheme isEqualToString:@"file"]) {
-    NSString *assetName = RCTBundlePathForURL(URL);
-    image = [UIImage imageNamed:assetName];
-    if (!image) {
-      // Attempt to load from the file system
-      NSString *filePath = URL.path;
-      if (filePath.pathExtension.length == 0) {
-        filePath = [filePath stringByAppendingPathExtension:@"png"];
-      }
-      image = [UIImage imageWithContentsOfFile:filePath];
-    }
-  } else if ([scheme isEqualToString:@"data"]) {
-    image = [UIImage imageWithData:[NSData dataWithContentsOfURL:URL]];
-  } else if ([scheme isEqualToString:@"http"] && isPackagerAsset) {
-    image = [UIImage imageWithData:[NSData dataWithContentsOfURL:URL]];
-  } else {
-    RCTLogConvertError(json, @"an image. Only local files or data URIs are supported");
-  }
-
-  if (scale > 0) {
-    image = [UIImage imageWithCGImage:image.CGImage
-                                scale:scale
-                          orientation:image.imageOrientation];
-  }
-  return image;
-}
-
-+ (CGImageRef)CGImage:(id)json
-{
-  return [self UIImage:json].CGImage;
-}
-
 #if !defined(__IPHONE_8_2) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_2
 
 // These constants are defined in iPhone SDK 8.2, but the app cannot run on
@@ -860,3 +789,84 @@ + (NSPropertyList)NSPropertyList:(id)json
 }), RCTAnimationTypeEaseInEaseOut, integerValue)
 
 @end
+
+@interface RCTImageSource (Packager)
+
+@property (nonatomic, assign) BOOL packagerAsset;
+
+@end
+
+@implementation RCTConvert (Deprecated)
+
+/* This method is only used when loading images synchronously, e.g. for tabbar icons */
++ (UIImage *)UIImage:(id)json
+{
+  if (!json) {
+    return nil;
+  }
+
+  RCTImageSource *imageSource = [self RCTImageSource:json];
+  if (!imageSource) {
+    return nil;
+  }
+
+  __block UIImage *image;
+  if (![NSThread isMainThread]) {
+    // It seems that none of the UIImage loading methods can be guaranteed
+    // thread safe, so we'll pick the lesser of two evils here and block rather
+    // than run the risk of crashing
+    RCTLogWarn(@"Calling [RCTConvert UIImage:] on a background thread is not recommended");
+    dispatch_sync(dispatch_get_main_queue(), ^{
+      image = [self UIImage:json];
+    });
+    return image;
+  }
+
+  NSURL *URL = imageSource.imageURL;
+  NSString *scheme = URL.scheme.lowercaseString;
+  if ([scheme isEqualToString:@"file"]) {
+    NSString *assetName = RCTBundlePathForURL(URL);
+    image = [UIImage imageNamed:assetName];
+    if (!image) {
+      // Attempt to load from the file system
+      NSString *filePath = URL.path;
+      if (filePath.pathExtension.length == 0) {
+        filePath = [filePath stringByAppendingPathExtension:@"png"];
+      }
+      image = [UIImage imageWithContentsOfFile:filePath];
+    }
+  } else if ([scheme isEqualToString:@"data"]) {
+    image = [UIImage imageWithData:[NSData dataWithContentsOfURL:URL]];
+  } else if ([scheme isEqualToString:@"http"] && imageSource.packagerAsset) {
+    image = [UIImage imageWithData:[NSData dataWithContentsOfURL:URL]];
+  } else {
+    RCTLogConvertError(json, @"an image. Only local files or data URIs are supported");
+  }
+
+  CGFloat scale = imageSource.scale;
+  if (!scale && imageSource.size.width) {
+    // If no scale provided, set scale to image width / source width
+    scale = CGImageGetWidth(image.CGImage) / imageSource.size.width;
+  }
+
+  if (scale) {
+    image = [UIImage imageWithCGImage:image.CGImage
+                                scale:scale
+                          orientation:image.imageOrientation];
+  }
+
+  if (!CGSizeEqualToSize(imageSource.size, CGSizeZero) &&
+      !CGSizeEqualToSize(imageSource.size, image.size)) {
+    RCTLogError(@"Image source size %@ does not match loaded image size %@.",
+                NSStringFromCGSize(imageSource.size), NSStringFromCGSize(image.size));
+  }
+
+  return image;
+}
+
++ (CGImageRef)CGImage:(id)json
+{
+  return [self UIImage:json].CGImage;
+}
+
+@end
diff --git a/React/Base/RCTImageSource.h b/React/Base/RCTImageSource.h
new file mode 100644
index 000000000000..efcefaa2b89f
--- /dev/null
+++ b/React/Base/RCTImageSource.h
@@ -0,0 +1,43 @@
+/**
+ * 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "RCTConvert.h"
+
+/**
+ * Object containing an image URL and associated metadata.
+ */
+@interface RCTImageSource : NSObject
+
+@property (nonatomic, strong, readonly) NSURL *imageURL;
+@property (nonatomic, assign, readonly) CGSize size;
+@property (nonatomic, assign, readonly) CGFloat scale;
+
+/**
+ * Create a new image source object.
+ * Pass a size of CGSizeZero if you do not know or wish to specify the image
+ * size. Pass a scale of zero if you do not know or wish to specify the scale.
+ */
+- (instancetype)initWithURL:(NSURL *)url
+                       size:(CGSize)size
+                      scale:(CGFloat)scale;
+
+/**
+ * Create a copy of the image source with the specified size and scale.
+ */
+- (instancetype)imageSourceWithSize:(CGSize)size scale:(CGFloat)scale;
+
+@end
+
+@interface RCTConvert (ImageSource)
+
++ (RCTImageSource *)RCTImageSource:(id)json;
+
+@end
diff --git a/React/Base/RCTImageSource.m b/React/Base/RCTImageSource.m
new file mode 100644
index 000000000000..3392385f8134
--- /dev/null
+++ b/React/Base/RCTImageSource.m
@@ -0,0 +1,83 @@
+/**
+ * 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.
+ */
+
+#import "RCTImageSource.h"
+
+@interface RCTImageSource ()
+
+@property (nonatomic, assign) BOOL packagerAsset;
+
+@end
+
+@implementation RCTImageSource
+
+- (instancetype)initWithURL:(NSURL *)url size:(CGSize)size scale:(CGFloat)scale
+{
+  if ((self = [super init])) {
+    _imageURL  = url;
+    _size = size;
+    _scale = scale;
+  }
+  return self;
+}
+
+- (instancetype)imageSourceWithSize:(CGSize)size scale:(CGFloat)scale
+{
+  RCTImageSource *imageSource = [[RCTImageSource alloc] initWithURL:_imageURL
+                                                               size:size
+                                                              scale:scale];
+  imageSource.packagerAsset = _packagerAsset;
+  return imageSource;
+}
+
+- (BOOL)isEqual:(RCTImageSource *)object
+{
+  if (![object isKindOfClass:[RCTImageSource class]]) {
+    return NO;
+  }
+  return [_imageURL isEqual:object.imageURL] && _scale == object.scale &&
+  (CGSizeEqualToSize(_size, object.size) || CGSizeEqualToSize(object.size, CGSizeZero));
+}
+
+@end
+
+@implementation RCTConvert (ImageSource)
+
++ (RCTImageSource *)RCTImageSource:(id)json
+{
+  if (!json) {
+    return nil;
+  }
+
+  NSURL *imageURL;
+  CGSize size = CGSizeZero;
+  CGFloat scale = 1.0;
+  BOOL packagerAsset = NO;
+  if ([json isKindOfClass:[NSDictionary class]]) {
+    if (!(imageURL = [self NSURL:json[@"uri"]])) {
+      return nil;
+    }
+    size = [self CGSize:json];
+    scale = [self CGFloat:json[@"scale"]] ?: [self BOOL:json[@"deprecated"]] ? 0.0 : 1.0;
+    packagerAsset = [self BOOL:json[@"__packager_asset"]];
+  } else if ([json isKindOfClass:[NSString class]]) {
+    imageURL = [self NSURL:json];
+  } else {
+    RCTLogConvertError(json, @"an image. Did you forget to call resolveAssetSource() on the JS side?");
+    return nil;
+  }
+
+  RCTImageSource *imageSource = [[RCTImageSource alloc] initWithURL:imageURL
+                                                               size:size
+                                                              scale:scale];
+  imageSource.packagerAsset = packagerAsset;
+  return imageSource;
+}
+
+@end
diff --git a/React/Base/RCTLog.m b/React/Base/RCTLog.m
index 86392db1f999..f09aff78b93f 100644
--- a/React/Base/RCTLog.m
+++ b/React/Base/RCTLog.m
@@ -206,6 +206,7 @@ void _RCTLogNativeInternal(RCTLogLevel level, const char *fileName, int lineNumb
     }
 
 #if RCT_DEBUG
+
     // Log to red box in debug mode.
     if ([UIApplication sharedApplication] && level >= RCTLOG_REDBOX_LEVEL) {
       NSArray<NSString *> *stackSymbols = [NSThread callStackSymbols];
@@ -233,7 +234,9 @@ void _RCTLogNativeInternal(RCTLogLevel level, const char *fileName, int lineNumb
 
     // Log to JS executor
     [[RCTBridge currentBridge] logMessage:message level:level ? @(RCTLogLevels[level]) : @"info"];
+
 #endif
+
   }
 }
 
diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj
index 6d671d58b4b4..53a11ed1d6d8 100644
--- a/React/React.xcodeproj/project.pbxproj
+++ b/React/React.xcodeproj/project.pbxproj
@@ -38,6 +38,7 @@
 		13B0801D1A69489C00A75B9A /* RCTNavItemManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B080131A69489C00A75B9A /* RCTNavItemManager.m */; };
 		13B080201A69489C00A75B9A /* RCTActivityIndicatorViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B080191A69489C00A75B9A /* RCTActivityIndicatorViewManager.m */; };
 		13B080261A694A8400A75B9A /* RCTWrapperViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B080241A694A8400A75B9A /* RCTWrapperViewController.m */; };
+		13BB3D021BECD54500932C10 /* RCTImageSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 13BB3D011BECD54500932C10 /* RCTImageSource.m */; };
 		13B202011BFB945300C07393 /* RCTPasteboard.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B202001BFB945300C07393 /* RCTPasteboard.m */; };
 		13B202041BFB948C00C07393 /* RCTMapAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B202031BFB948C00C07393 /* RCTMapAnnotation.m */; };
 		13C156051AB1A2840079392D /* RCTWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13C156021AB1A2840079392D /* RCTWebView.m */; };
@@ -173,7 +174,9 @@
 		13B080191A69489C00A75B9A /* RCTActivityIndicatorViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTActivityIndicatorViewManager.m; sourceTree = "<group>"; };
 		13B080231A694A8400A75B9A /* RCTWrapperViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWrapperViewController.h; sourceTree = "<group>"; };
 		13B080241A694A8400A75B9A /* RCTWrapperViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWrapperViewController.m; sourceTree = "<group>"; };
-		13B201FF1BFB945300C07393 /* RCTPasteboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPasteboard.h; sourceTree = "<group>"; };
+		13BB3D001BECD54500932C10 /* RCTImageSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImageSource.h; sourceTree = "<group>"; };
+		13BB3D011BECD54500932C10 /* RCTImageSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageSource.m; sourceTree = "<group>"; };
+	13B201FF1BFB945300C07393 /* RCTPasteboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPasteboard.h; sourceTree = "<group>"; };
 		13B202001BFB945300C07393 /* RCTPasteboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPasteboard.m; sourceTree = "<group>"; };
 		13B202021BFB948C00C07393 /* RCTMapAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTMapAnnotation.h; sourceTree = "<group>"; };
 		13B202031BFB948C00C07393 /* RCTMapAnnotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTMapAnnotation.m; sourceTree = "<group>"; };
@@ -526,6 +529,8 @@
 				1345A83B1B265A0E00583190 /* RCTURLRequestHandler.h */,
 				83CBBA4F1A601E3B00E9B192 /* RCTUtils.h */,
 				83CBBA501A601E3B00E9B192 /* RCTUtils.m */,
+				13BB3D001BECD54500932C10 /* RCTImageSource.h */,
+				13BB3D011BECD54500932C10 /* RCTImageSource.m */,
 			);
 			path = Base;
 			sourceTree = "<group>";
@@ -645,6 +650,7 @@
 				14F3620E1AABD06A001CE568 /* RCTSwitchManager.m in Sources */,
 				13B080201A69489C00A75B9A /* RCTActivityIndicatorViewManager.m in Sources */,
 				13E067561A70F44B002CDEE1 /* RCTViewManager.m in Sources */,
+				13BB3D021BECD54500932C10 /* RCTImageSource.m in Sources */,
 				58C571C11AA56C1900CDF9C8 /* RCTDatePickerManager.m in Sources */,
 				1450FF8A1BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S in Sources */,
 				14F7A0EC1BDA3B3C003C6C10 /* RCTPerfMonitor.m in Sources */,
diff --git a/React/Views/RCTNavItem.h b/React/Views/RCTNavItem.h
index 418d5c5c97cf..fdfeb66e4f98 100644
--- a/React/Views/RCTNavItem.h
+++ b/React/Views/RCTNavItem.h
@@ -31,7 +31,7 @@
 @property (nonatomic, readonly) UIBarButtonItem *leftButtonItem;
 @property (nonatomic, readonly) UIBarButtonItem *rightButtonItem;
 
-@property (nonatomic, copy) RCTBubblingEventBlock onNavLeftButtonTap;
-@property (nonatomic, copy) RCTBubblingEventBlock onNavRightButtonTap;
+@property (nonatomic, copy) RCTBubblingEventBlock onLeftButtonPress;
+@property (nonatomic, copy) RCTBubblingEventBlock onRightButtonPress;
 
 @end
diff --git a/React/Views/RCTNavItem.m b/React/Views/RCTNavItem.m
index 5e4043f8495f..5fa8005c94f9 100644
--- a/React/Views/RCTNavItem.m
+++ b/React/Views/RCTNavItem.m
@@ -67,14 +67,14 @@ - (UIBarButtonItem *)leftButtonItem
       [[UIBarButtonItem alloc] initWithImage:_leftButtonIcon
                                        style:UIBarButtonItemStylePlain
                                       target:self
-                                      action:@selector(handleNavLeftButtonTapped)];
+                                      action:@selector(handleLeftButtonPress)];
 
     } else if (_leftButtonTitle.length) {
       _leftButtonItem =
       [[UIBarButtonItem alloc] initWithTitle:_leftButtonTitle
                                        style:UIBarButtonItemStylePlain
                                       target:self
-                                      action:@selector(handleNavLeftButtonTapped)];
+                                      action:@selector(handleLeftButtonPress)];
     } else {
       _leftButtonItem = nil;
     }
@@ -82,10 +82,10 @@ - (UIBarButtonItem *)leftButtonItem
   return _leftButtonItem;
 }
 
-- (void)handleNavLeftButtonTapped
+- (void)handleLeftButtonPress
 {
-  if (_onNavLeftButtonTap) {
-    _onNavLeftButtonTap(nil);
+  if (_onLeftButtonPress) {
+    _onLeftButtonPress(nil);
   }
 }
 
@@ -109,14 +109,14 @@ - (UIBarButtonItem *)rightButtonItem
       [[UIBarButtonItem alloc] initWithImage:_rightButtonIcon
                                        style:UIBarButtonItemStylePlain
                                       target:self
-                                      action:@selector(handleNavRightButtonTapped)];
+                                      action:@selector(handleRightButtonPress)];
 
     } else if (_rightButtonTitle.length) {
       _rightButtonItem =
       [[UIBarButtonItem alloc] initWithTitle:_rightButtonTitle
                                        style:UIBarButtonItemStylePlain
                                       target:self
-                                      action:@selector(handleNavRightButtonTapped)];
+                                      action:@selector(handleRightButtonPress)];
     } else {
       _rightButtonItem = nil;
     }
@@ -124,10 +124,10 @@ - (UIBarButtonItem *)rightButtonItem
   return _rightButtonItem;
 }
 
-- (void)handleNavRightButtonTapped
+- (void)handleRightButtonPress
 {
-  if (_onNavRightButtonTap) {
-    _onNavRightButtonTap(nil);
+  if (_onRightButtonPress) {
+    _onRightButtonPress(nil);
   }
 }
 
diff --git a/React/Views/RCTNavItemManager.m b/React/Views/RCTNavItemManager.m
index 040b7ffceac5..be4f879dde6d 100644
--- a/React/Views/RCTNavItemManager.m
+++ b/React/Views/RCTNavItemManager.m
@@ -39,7 +39,7 @@ - (UIView *)view
 RCT_EXPORT_VIEW_PROPERTY(rightButtonIcon, UIImage)
 RCT_EXPORT_VIEW_PROPERTY(rightButtonTitle, NSString)
 
-RCT_EXPORT_VIEW_PROPERTY(onNavLeftButtonTap, RCTBubblingEventBlock)
-RCT_EXPORT_VIEW_PROPERTY(onNavRightButtonTap, RCTBubblingEventBlock)
+RCT_EXPORT_VIEW_PROPERTY(onLeftButtonPress, RCTBubblingEventBlock)
+RCT_EXPORT_VIEW_PROPERTY(onRightButtonPress, RCTBubblingEventBlock)
 
 @end
diff --git a/React/Views/RCTTabBarItem.h b/React/Views/RCTTabBarItem.h
index def1abf6c347..cee2df982e47 100644
--- a/React/Views/RCTTabBarItem.h
+++ b/React/Views/RCTTabBarItem.h
@@ -13,7 +13,9 @@
 
 @interface RCTTabBarItem : UIView
 
-@property (nonatomic, copy) id icon;
+@property (nonatomic, copy) id /* NSString or NSNumber */ badge;
+@property (nonatomic, strong) UIImage *icon;
+@property (nonatomic, assign) UITabBarSystemItem systemIcon;
 @property (nonatomic, assign, getter=isSelected) BOOL selected;
 @property (nonatomic, readonly) UITabBarItem *barItem;
 @property (nonatomic, copy) RCTBubblingEventBlock onPress;
diff --git a/React/Views/RCTTabBarItem.m b/React/Views/RCTTabBarItem.m
index 8699ff96d71a..a05ae75ee0af 100644
--- a/React/Views/RCTTabBarItem.m
+++ b/React/Views/RCTTabBarItem.m
@@ -13,73 +13,78 @@
 #import "RCTLog.h"
 #import "UIView+React.h"
 
+@implementation RCTConvert (UITabBarSystemItem)
+
+RCT_ENUM_CONVERTER(UITabBarSystemItem, (@{
+  @"bookmarks": @(UITabBarSystemItemBookmarks),
+  @"contacts": @(UITabBarSystemItemContacts),
+  @"downloads": @(UITabBarSystemItemDownloads),
+  @"favorites": @(UITabBarSystemItemFavorites),
+  @"featured": @(UITabBarSystemItemFeatured),
+  @"history": @(UITabBarSystemItemHistory),
+  @"more": @(UITabBarSystemItemMore),
+  @"most-recent": @(UITabBarSystemItemMostRecent),
+  @"most-viewed": @(UITabBarSystemItemMostViewed),
+  @"recents": @(UITabBarSystemItemRecents),
+  @"search": @(UITabBarSystemItemSearch),
+  @"top-rated": @(UITabBarSystemItemTopRated),
+}), NSNotFound, integerValue)
+
+@end
+
 @implementation RCTTabBarItem
 
 @synthesize barItem = _barItem;
 
+- (instancetype)initWithFrame:(CGRect)frame
+{
+  if ((self = [super initWithFrame:frame])) {
+    _systemIcon = NSNotFound;
+  }
+  return self;
+}
+
 - (UITabBarItem *)barItem
 {
   if (!_barItem) {
     _barItem = [UITabBarItem new];
+    _systemIcon = NSNotFound;
   }
   return _barItem;
 }
 
-- (void)setIcon:(id)icon
+- (void)setBadge:(id)badge
 {
-  static NSDictionary *systemIcons;
-  static dispatch_once_t onceToken;
-  dispatch_once(&onceToken, ^{
-    systemIcons = @{
-      @"bookmarks": @(UITabBarSystemItemBookmarks),
-      @"contacts": @(UITabBarSystemItemContacts),
-      @"downloads": @(UITabBarSystemItemDownloads),
-      @"favorites": @(UITabBarSystemItemFavorites),
-      @"featured": @(UITabBarSystemItemFeatured),
-      @"history": @(UITabBarSystemItemHistory),
-      @"more": @(UITabBarSystemItemMore),
-      @"most-recent": @(UITabBarSystemItemMostRecent),
-      @"most-viewed": @(UITabBarSystemItemMostViewed),
-      @"recents": @(UITabBarSystemItemRecents),
-      @"search": @(UITabBarSystemItemSearch),
-      @"top-rated": @(UITabBarSystemItemTopRated),
-    };
-  });
-
-  // Update icon
-  BOOL wasSystemIcon = (systemIcons[_icon] != nil);
-  _icon = [icon copy];
+  _badge = [badge copy];
+  self.barItem.badgeValue = [badge description];
+}
 
-  // Check if string matches any custom images first
-  UIImage *image = [RCTConvert UIImage:_icon];
-  UITabBarItem *oldItem = _barItem;
-  if (image) {
-    // Recreate barItem if previous item was a system icon. Calling self.barItem
-    // creates a new instance if it wasn't set yet.
-    if (wasSystemIcon) {
-      _barItem = nil;
-      self.barItem.image = image;
-    } else {
-      self.barItem.image = image;
-      return;
-    }
-  } else if ([icon isKindOfClass:[NSString class]] && [icon length] > 0) {
-    // Not a custom image, may be a system item?
-    NSNumber *systemIcon = systemIcons[icon];
-    if (!systemIcon) {
-      RCTLogError(@"The tab bar icon '%@' did not match any known image or system icon", icon);
-      return;
-    }
-    _barItem = [[UITabBarItem alloc] initWithTabBarSystemItem:systemIcon.integerValue tag:oldItem.tag];
-  } else {
-    self.barItem.image = nil;
+- (void)setSystemIcon:(UITabBarSystemItem)systemIcon
+{
+  if (_systemIcon != systemIcon) {
+    _systemIcon = systemIcon;
+    UITabBarItem *oldItem = _barItem;
+    _barItem = [[UITabBarItem alloc] initWithTabBarSystemItem:_systemIcon
+                                                          tag:oldItem.tag];
+    _barItem.title = oldItem.title;
+    _barItem.imageInsets = oldItem.imageInsets;
+    _barItem.badgeValue = oldItem.badgeValue;
   }
+}
 
-  // Reapply previous properties
-  _barItem.title = oldItem.title;
-  _barItem.imageInsets = oldItem.imageInsets;
-  _barItem.selectedImage = oldItem.selectedImage;
-  _barItem.badgeValue = oldItem.badgeValue;
+- (void)setIcon:(UIImage *)icon
+{
+  _icon = icon;
+  if (_icon && _systemIcon != NSNotFound) {
+    _systemIcon = NSNotFound;
+    UITabBarItem *oldItem = _barItem;
+    _barItem = [UITabBarItem new];
+    _barItem.title = oldItem.title;
+    _barItem.imageInsets = oldItem.imageInsets;
+    _barItem.selectedImage = oldItem.selectedImage;
+    _barItem.badgeValue = oldItem.badgeValue;
+  }
+  self.barItem.image = _icon;
 }
 
 - (UIViewController *)reactViewController
diff --git a/React/Views/RCTTabBarItemManager.m b/React/Views/RCTTabBarItemManager.m
index a926a54f343f..d92e3a2d95e9 100644
--- a/React/Views/RCTTabBarItemManager.m
+++ b/React/Views/RCTTabBarItemManager.m
@@ -21,10 +21,11 @@ - (UIView *)view
   return [RCTTabBarItem new];
 }
 
+RCT_EXPORT_VIEW_PROPERTY(badge, id /* NSString or NSNumber */)
 RCT_EXPORT_VIEW_PROPERTY(selected, BOOL)
-RCT_EXPORT_VIEW_PROPERTY(icon, id)
+RCT_EXPORT_VIEW_PROPERTY(icon, UIImage)
 RCT_REMAP_VIEW_PROPERTY(selectedIcon, barItem.selectedImage, UIImage)
-RCT_REMAP_VIEW_PROPERTY(badge, barItem.badgeValue, NSString)
+RCT_EXPORT_VIEW_PROPERTY(systemIcon, UITabBarSystemItem)
 RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
 RCT_CUSTOM_VIEW_PROPERTY(title, NSString, RCTTabBarItem)
 {

From 5aef380609925922fa23f9fa12b46c8af0f9f3ef Mon Sep 17 00:00:00 2001
From: Andrei Coman <andreic@fb.com>
Date: Tue, 8 Dec 2015 04:53:17 -0800
Subject: [PATCH 0270/1411] Refactor NetInfo

Reviewed By: foghina

Differential Revision: D2718059

fb-gh-sync-id: 5c4e946991be27c5ae2bcc3eec32b5bc596545bd
---
 .../modules/netinfo/ConnectivityModule.java   | 36 +++++--------------
 1 file changed, 8 insertions(+), 28 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/ConnectivityModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/ConnectivityModule.java
index 00414d86a688..acf6060b1af5 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/ConnectivityModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/ConnectivityModule.java
@@ -2,8 +2,6 @@
 
 package com.facebook.react.modules.netinfo;
 
-import javax.annotation.Nullable;
-
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -13,11 +11,10 @@
 import android.support.v4.net.ConnectivityManagerCompat;
 
 import com.facebook.react.bridge.Callback;
+import com.facebook.react.bridge.LifecycleEventListener;
 import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReactContextBaseJavaModule;
 import com.facebook.react.bridge.ReactMethod;
-import com.facebook.react.bridge.LifecycleEventListener;
 import com.facebook.react.bridge.WritableMap;
 import com.facebook.react.bridge.WritableNativeMap;
 
@@ -34,27 +31,26 @@ public class ConnectivityModule extends ReactContextBaseJavaModule
 
   private final ConnectivityManager mConnectivityManager;
   private final ConnectivityManagerCompat mConnectivityManagerCompat;
+  private final ConnectivityBroadcastReceiver mConnectivityBroadcastReceiver;
 
-  private String mConnectivity;
-  private @Nullable ConnectivityBroadcastReceiver mConnectivityBroadcastReceiver;
+  private String mConnectivity = "";
 
   public ConnectivityModule(ReactApplicationContext reactContext) {
     super(reactContext);
     mConnectivityManager =
         (ConnectivityManager) reactContext.getSystemService(Context.CONNECTIVITY_SERVICE);
     mConnectivityManagerCompat = new ConnectivityManagerCompat();
-    mConnectivity = "";
+    mConnectivityBroadcastReceiver = new ConnectivityBroadcastReceiver();
   }
 
   @Override
   public void onHostResume() {
-    maybeRegisterReceiver();
-    updateAndSendConnectionType();
+    registerReceiver();
   }
 
   @Override
   public void onHostPause() {
-    maybeUnregisterReceiver();
+    unregisterReceiver();
   }
 
   @Override
@@ -64,13 +60,6 @@ public void onHostDestroy() {
   @Override
   public void initialize() {
     getReactApplicationContext().addLifecycleEventListener(this);
-    maybeRegisterReceiver();
-    updateAndSendConnectionType();
-  }
-
-  @Override
-  public void onCatalystInstanceDestroy() {
-    maybeUnregisterReceiver();
   }
 
   @Override
@@ -88,23 +77,14 @@ public void isConnectionMetered(Callback successCallback) {
     successCallback.invoke(mConnectivityManagerCompat.isActiveNetworkMetered(mConnectivityManager));
   }
 
-  private void maybeRegisterReceiver() {
-    if (mConnectivityBroadcastReceiver != null) {
-      return;
-    }
-    mConnectivityBroadcastReceiver = new ConnectivityBroadcastReceiver();
+  private void registerReceiver() {
     IntentFilter filter = new IntentFilter();
     filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
     getReactApplicationContext().registerReceiver(mConnectivityBroadcastReceiver, filter);
   }
 
-  private void maybeUnregisterReceiver() {
-    if (mConnectivityBroadcastReceiver == null) {
-      return;
-    }
+  private void unregisterReceiver() {
     getReactApplicationContext().unregisterReceiver(mConnectivityBroadcastReceiver);
-    mConnectivityBroadcastReceiver = null;
-    mConnectivity = "";
   }
 
   private void updateAndSendConnectionType() {

From e7a4b20d7567056ae6e718be90a29b4035158f7e Mon Sep 17 00:00:00 2001
From: Mike Armstrong <mikea@fb.com>
Date: Tue, 8 Dec 2015 06:10:58 -0800
Subject: [PATCH 0271/1411] exceptions generated from incorrect arg usage on
 JSC trace and LegacyProfile functions

Reviewed By: astreet

Differential Revision: D2729015

fb-gh-sync-id: a3f56554ff6e77170e07aaf93934f93522b3a81b
---
 .../src/main/jni/react/JSCHelpers.cpp         |  9 +++++
 ReactAndroid/src/main/jni/react/JSCHelpers.h  |  4 +++
 .../src/main/jni/react/JSCLegacyProfiler.cpp  | 12 +++++--
 .../src/main/jni/react/JSCTracing.cpp         | 35 +++++++++++++------
 4 files changed, 48 insertions(+), 12 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/JSCHelpers.cpp b/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
index b3ef3aa57c73..b1edc73dc2c7 100644
--- a/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
@@ -19,4 +19,13 @@ void installGlobalFunction(
   JSStringRelease(jsName);
 }
 
+JSValueRef makeJSCException(
+    JSContextRef ctx,
+    const char* exception_text) {
+  JSStringRef message = JSStringCreateWithUTF8CString(exception_text);
+  JSValueRef exceptionString = JSValueMakeString(ctx, message);
+  JSStringRelease(message);
+  return JSValueToObject(ctx, exceptionString, NULL);
+}
+
 } }
diff --git a/ReactAndroid/src/main/jni/react/JSCHelpers.h b/ReactAndroid/src/main/jni/react/JSCHelpers.h
index 7209b2ce3a1b..ba3f8525a341 100644
--- a/ReactAndroid/src/main/jni/react/JSCHelpers.h
+++ b/ReactAndroid/src/main/jni/react/JSCHelpers.h
@@ -13,4 +13,8 @@ void installGlobalFunction(
     const char* name,
     JSObjectCallAsFunctionCallback callback);
 
+JSValueRef makeJSCException(
+    JSContextRef ctx,
+    const char* exception_text);
+
 } }
diff --git a/ReactAndroid/src/main/jni/react/JSCLegacyProfiler.cpp b/ReactAndroid/src/main/jni/react/JSCLegacyProfiler.cpp
index 5d2a7e499e18..74222c2efe28 100644
--- a/ReactAndroid/src/main/jni/react/JSCLegacyProfiler.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCLegacyProfiler.cpp
@@ -17,7 +17,11 @@ static JSValueRef nativeProfilerStart(
     const JSValueRef arguments[],
     JSValueRef* exception) {
   if (argumentCount < 1) {
-    // Could raise an exception here.
+    if (exception) {
+      *exception = facebook::react::makeJSCException(
+        ctx,
+        "nativeProfilerStart: requires at least 1 argument");
+    }
     return JSValueMakeUndefined(ctx);
   }
 
@@ -35,7 +39,11 @@ static JSValueRef nativeProfilerEnd(
     const JSValueRef arguments[],
     JSValueRef* exception) {
   if (argumentCount < 1) {
-    // Could raise an exception here.
+    if (exception) {
+      *exception = facebook::react::makeJSCException(
+        ctx,
+        "nativeProfilerEnd: requires at least 1 argument");
+    }
     return JSValueMakeUndefined(ctx);
   }
 
diff --git a/ReactAndroid/src/main/jni/react/JSCTracing.cpp b/ReactAndroid/src/main/jni/react/JSCTracing.cpp
index d0bab2c420f0..945d6fe72bc4 100644
--- a/ReactAndroid/src/main/jni/react/JSCTracing.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCTracing.cpp
@@ -92,8 +92,11 @@ static JSValueRef nativeTraceBeginSection(
     const JSValueRef arguments[],
     JSValueRef* exception) {
   if (FBSYSTRACE_UNLIKELY(argumentCount < 2)) {
-    // Could raise an exception here.
-    // TODO T9329825
+    if (exception) {
+      *exception = facebook::react::makeJSCException(
+        ctx,
+        "nativeTraceBeginSection: requires at least 2 arguments");
+    }
     return JSValueMakeUndefined(ctx);
   }
 
@@ -129,8 +132,11 @@ static JSValueRef nativeTraceEndSection(
     const JSValueRef arguments[],
     JSValueRef* exception) {
   if (FBSYSTRACE_UNLIKELY(argumentCount < 1)) {
-    // Could raise an exception here.
-    // TODO T9329825
+    if (exception) {
+      *exception = facebook::react::makeJSCException(
+        ctx,
+        "nativeTraceEndSection: requires at least 1 argument");
+    }
     return JSValueMakeUndefined(ctx);
   }
 
@@ -170,8 +176,11 @@ static JSValueRef beginOrEndAsync(
     const JSValueRef arguments[],
     JSValueRef* exception) {
   if (FBSYSTRACE_UNLIKELY(argumentCount < 3)) {
-    // Could raise an exception here.
-    // TODO T9329825
+    if (exception) {
+      *exception = facebook::react::makeJSCException(
+        ctx,
+        "beginOrEndAsync: requires at least 3 arguments");
+    }
     return JSValueMakeUndefined(ctx);
   }
 
@@ -230,8 +239,11 @@ static JSValueRef stageAsync(
     const JSValueRef arguments[],
     JSValueRef* exception) {
   if (FBSYSTRACE_UNLIKELY(argumentCount < 4)) {
-    // Could raise an exception here.
-    // TODO T9329825
+    if (exception) {
+      *exception = facebook::react::makeJSCException(
+        ctx,
+        "stageAsync: requires at least 4 arguments");
+    }
     return JSValueMakeUndefined(ctx);
   }
 
@@ -373,8 +385,11 @@ static JSValueRef nativeTraceCounter(
     const JSValueRef arguments[],
     JSValueRef* exception) {
   if (FBSYSTRACE_UNLIKELY(argumentCount < 3)) {
-    // Could raise an exception here.
-    // TODO T9329825
+    if (exception) {
+      *exception = facebook::react::makeJSCException(
+        ctx,
+        "nativeTraceCounter: requires at least 3 arguments");
+    }
     return JSValueMakeUndefined(ctx);
   }
 

From e2c35dddbac6ce305f1ed7b445e92fd392b42865 Mon Sep 17 00:00:00 2001
From: Emilio Rodriguez <emiliorodriguez@gmail.com>
Date: Tue, 8 Dec 2015 07:44:56 -0800
Subject: [PATCH 0272/1411] Added support for styling the PickerIOS

Summary:
 - PickerIOS accepts now a new prop: style
 - this prop modifies the native style of the RCTPicker allowing to modify the font size of the items (fontSize), color of the items (color, only 6 char HEX values for now) and alignment of the items (textAlign)
Closes https://github.com/facebook/react-native/pull/4490

Reviewed By: svcscm

Differential Revision: D2723190

Pulled By: nicklockwood

fb-gh-sync-id: ab9188192f1d0d087787dfed8c128073bfaa3235
---
 Examples/UIExplorer/PickerIOSExample.js | 54 +++++++++++++++++++------
 Libraries/Picker/PickerIOS.ios.js       | 16 ++++++--
 React/Views/RCTPicker.h                 |  5 +++
 React/Views/RCTPicker.m                 | 37 ++++++++++++-----
 React/Views/RCTPickerManager.m          | 18 +++++++++
 5 files changed, 104 insertions(+), 26 deletions(-)

diff --git a/Examples/UIExplorer/PickerIOSExample.js b/Examples/UIExplorer/PickerIOSExample.js
index b0cc5cb9729d..d38ef54e9f3b 100644
--- a/Examples/UIExplorer/PickerIOSExample.js
+++ b/Examples/UIExplorer/PickerIOSExample.js
@@ -87,24 +87,21 @@ var PickerExample = React.createClass({
               key={carMake}
               value={carMake}
               label={CAR_MAKES_AND_MODELS[carMake].name}
-              />
-            )
-          )}
+            />
+          ))}
         </PickerIOS>
         <Text>Please choose a model of {make.name}:</Text>
         <PickerIOS
           selectedValue={this.state.modelIndex}
           key={this.state.carMake}
           onValueChange={(modelIndex) => this.setState({modelIndex})}>
-          {CAR_MAKES_AND_MODELS[this.state.carMake].models.map(
-            (modelName, modelIndex) => (
-              <PickerItemIOS
-                key={this.state.carMake + '_' + modelIndex}
-                value={modelIndex}
-                label={modelName}
-              />
-            ))
-          }
+          {CAR_MAKES_AND_MODELS[this.state.carMake].models.map((modelName, modelIndex) => (
+            <PickerItemIOS
+              key={this.state.carMake + '_' + modelIndex}
+              value={modelIndex}
+              label={modelName}
+            />
+          ))}
         </PickerIOS>
         <Text>You selected: {selectionString}</Text>
       </View>
@@ -112,6 +109,33 @@ var PickerExample = React.createClass({
   },
 });
 
+var PickerStyleExample = React.createClass({
+  getInitialState: function() {
+    return {
+      carMake: 'cadillac',
+    };
+  },
+  
+  render: function() {
+    var make = CAR_MAKES_AND_MODELS[this.state.carMake];
+    var selectionString = make.name + ' ' + make.models[this.state.modelIndex];
+    return (
+      <PickerIOS
+        itemStyle={{fontSize: 25, color: 'red', textAlign: 'left', fontWeight: 'bold'}}
+        selectedValue={this.state.carMake}
+        onValueChange={(carMake) => this.setState({carMake, modelIndex: 0})}>
+        {Object.keys(CAR_MAKES_AND_MODELS).map((carMake) => (
+          <PickerItemIOS
+            key={carMake}
+            value={carMake}
+            label={CAR_MAKES_AND_MODELS[carMake].name}
+          />
+        ))}
+      </PickerIOS>
+    );
+  },
+});
+
 exports.displayName = (undefined: ?string);
 exports.title = '<PickerIOS>';
 exports.description = 'Render lists of selectable options with UIPickerView.';
@@ -121,4 +145,10 @@ exports.examples = [
   render: function(): ReactElement {
     return <PickerExample />;
   },
+},
+{
+  title: '<PickerIOS> with custom styling',
+  render: function(): ReactElement {
+    return <PickerStyleExample />;
+  },
 }];
diff --git a/Libraries/Picker/PickerIOS.ios.js b/Libraries/Picker/PickerIOS.ios.js
index ffda1f57d174..0aa82bb5f8f8 100644
--- a/Libraries/Picker/PickerIOS.ios.js
+++ b/Libraries/Picker/PickerIOS.ios.js
@@ -17,8 +17,11 @@ var React = require('React');
 var ReactChildren = require('ReactChildren');
 var RCTPickerIOSConsts = require('NativeModules').UIManager.RCTPicker.Constants;
 var StyleSheet = require('StyleSheet');
+var StyleSheetPropType = require('StyleSheetPropType');
+var TextStylePropTypes = require('TextStylePropTypes');
 var View = require('View');
 
+var itemStylePropType = StyleSheetPropType(TextStylePropTypes);
 var requireNativeComponent = require('requireNativeComponent');
 
 var PickerIOS = React.createClass({
@@ -26,6 +29,7 @@ var PickerIOS = React.createClass({
 
   propTypes: {
     ...View.propTypes,
+    itemStyle: itemStylePropType,
     onValueChange: React.PropTypes.func,
     selectedValue: React.PropTypes.any, // string or integer basically
   },
@@ -50,13 +54,13 @@ var PickerIOS = React.createClass({
     });
     return {selectedIndex, items};
   },
-
+  
   render: function() {
     return (
       <View style={this.props.style}>
         <RCTPickerIOS
-          ref={ picker => this._picker = picker }
-          style={styles.pickerIOS}
+          ref={picker => this._picker = picker}
+          style={[styles.pickerIOS, this.props.itemStyle]}
           items={this.state.items}
           selectedIndex={this.state.selectedIndex}
           onChange={this._onChange}
@@ -108,7 +112,11 @@ var styles = StyleSheet.create({
   },
 });
 
-var RCTPickerIOS = requireNativeComponent('RCTPicker', PickerIOS, {
+var RCTPickerIOS = requireNativeComponent('RCTPicker', {
+  propTypes: {
+    style: itemStylePropType,
+  },
+}, {
   nativeOnly: {
     items: true,
     onChange: true,
diff --git a/React/Views/RCTPicker.h b/React/Views/RCTPicker.h
index 8fb39b5a5de3..0066d140f8e4 100644
--- a/React/Views/RCTPicker.h
+++ b/React/Views/RCTPicker.h
@@ -15,6 +15,11 @@
 
 @property (nonatomic, copy) NSArray<NSDictionary *> *items;
 @property (nonatomic, assign) NSInteger selectedIndex;
+
+@property (nonatomic, strong) UIColor *color;
+@property (nonatomic, strong) UIFont *font;
+@property (nonatomic, assign) NSTextAlignment textAlign;
+
 @property (nonatomic, copy) RCTBubblingEventBlock onChange;
 
 @end
diff --git a/React/Views/RCTPicker.m b/React/Views/RCTPicker.m
index f979c2116b77..b83a9667cbf0 100644
--- a/React/Views/RCTPicker.m
+++ b/React/Views/RCTPicker.m
@@ -9,6 +9,7 @@
 
 #import "RCTPicker.h"
 
+#import "RCTConvert.h"
 #import "RCTUtils.h"
 
 @interface RCTPicker() <UIPickerViewDataSource, UIPickerViewDelegate>
@@ -19,7 +20,10 @@ @implementation RCTPicker
 - (instancetype)initWithFrame:(CGRect)frame
 {
   if ((self = [super initWithFrame:frame])) {
+    _color = [UIColor blackColor];
+    _font = [UIFont systemFontOfSize:21]; // TODO: selected title default should be 23.5
     _selectedIndex = NSNotFound;
+    _textAlign = NSTextAlignmentCenter;
     self.delegate = self;
   }
   return self;
@@ -59,20 +63,33 @@ - (NSInteger)pickerView:(__unused UIPickerView *)pickerView
 
 #pragma mark - UIPickerViewDelegate methods
 
-- (NSDictionary *)itemForRow:(NSInteger)row
+- (NSString *)pickerView:(__unused UIPickerView *)pickerView
+             titleForRow:(NSInteger)row
+            forComponent:(__unused NSInteger)component
 {
-  return _items[row];
+  return [RCTConvert NSString:_items[row][@"label"]];
 }
 
-- (id)valueForRow:(NSInteger)row
+- (UIView *)pickerView:(UIPickerView *)pickerView
+            viewForRow:(NSInteger)row
+          forComponent:(NSInteger)component
+           reusingView:(UILabel *)label
 {
-  return [self itemForRow:row][@"value"];
-}
+  if (!label) {
+    label = [[UILabel alloc] initWithFrame:(CGRect){
+      CGPointZero,
+      {
+        [pickerView rowSizeForComponent:component].width,
+        [pickerView rowSizeForComponent:component].height,
+      }
+    }];
+  }
 
-- (NSString *)pickerView:(__unused UIPickerView *)pickerView
-             titleForRow:(NSInteger)row forComponent:(__unused NSInteger)component
-{
-  return [self itemForRow:row][@"label"];
+  label.font = _font;
+  label.textColor = _color;
+  label.textAlignment = _textAlign;
+  label.text = [self pickerView:pickerView titleForRow:row forComponent:component];
+  return label;
 }
 
 - (void)pickerView:(__unused UIPickerView *)pickerView
@@ -82,7 +99,7 @@ - (void)pickerView:(__unused UIPickerView *)pickerView
   if (_onChange) {
     _onChange(@{
       @"newIndex": @(row),
-      @"newValue": [self valueForRow:row]
+      @"newValue": RCTNullIfNil(_items[row][@"value"]),
     });
   }
 }
diff --git a/React/Views/RCTPickerManager.m b/React/Views/RCTPickerManager.m
index 79d9c4758a63..759a05b6d8ad 100644
--- a/React/Views/RCTPickerManager.m
+++ b/React/Views/RCTPickerManager.m
@@ -25,6 +25,24 @@ - (UIView *)view
 RCT_EXPORT_VIEW_PROPERTY(items, NSDictionaryArray)
 RCT_EXPORT_VIEW_PROPERTY(selectedIndex, NSInteger)
 RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock)
+RCT_EXPORT_VIEW_PROPERTY(color, UIColor)
+RCT_EXPORT_VIEW_PROPERTY(textAlign, NSTextAlignment)
+RCT_CUSTOM_VIEW_PROPERTY(fontSize, CGFloat, RCTPicker)
+{
+  view.font = [RCTConvert UIFont:view.font withSize:json ?: @(defaultView.font.pointSize)];
+}
+RCT_CUSTOM_VIEW_PROPERTY(fontWeight, NSString, __unused RCTPicker)
+{
+  view.font = [RCTConvert UIFont:view.font withWeight:json]; // defaults to normal
+}
+RCT_CUSTOM_VIEW_PROPERTY(fontStyle, NSString, __unused RCTPicker)
+{
+  view.font = [RCTConvert UIFont:view.font withStyle:json]; // defaults to normal
+}
+RCT_CUSTOM_VIEW_PROPERTY(fontFamily, NSString, RCTPicker)
+{
+  view.font = [RCTConvert UIFont:view.font withFamily:json ?: defaultView.font.familyName];
+}
 
 - (NSDictionary<NSString *, id> *)constantsToExport
 {

From c9d796fc6a07199314452e79c1cc97b3ba789bd3 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Tue, 8 Dec 2015 09:30:07 -0800
Subject: [PATCH 0273/1411] NetInfo: Cleaned up code and examples

Reviewed By: andreicoman11

Differential Revision: D2723578

fb-gh-sync-id: b7bb9ce69f24ff5dcf38409de92d57f53da003fa
---
 Examples/UIExplorer/NetInfoExample.android.js | 158 ---------------
 Examples/UIExplorer/NetInfoExample.ios.js     | 147 --------------
 Examples/UIExplorer/NetInfoExample.js         | 182 ++++++++++++++++++
 Examples/UIExplorer/UIExplorerList.android.js |   2 +-
 Examples/UIExplorer/UIExplorerList.ios.js     |   2 +-
 Libraries/Network/NetInfo.js                  |  75 ++++----
 6 files changed, 220 insertions(+), 346 deletions(-)
 delete mode 100644 Examples/UIExplorer/NetInfoExample.android.js
 delete mode 100644 Examples/UIExplorer/NetInfoExample.ios.js
 create mode 100644 Examples/UIExplorer/NetInfoExample.js

diff --git a/Examples/UIExplorer/NetInfoExample.android.js b/Examples/UIExplorer/NetInfoExample.android.js
deleted file mode 100644
index 41d77232195f..000000000000
--- a/Examples/UIExplorer/NetInfoExample.android.js
+++ /dev/null
@@ -1,158 +0,0 @@
-/**
- * The examples provided by Facebook are for non-commercial testing and
- * evaluation purposes only.
- *
- * Facebook reserves all rights not expressly granted.
- *
- * 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 NON INFRINGEMENT. IN NO EVENT SHALL
- * FACEBOOK 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.
- *
- * @flow
- */
-'use strict';
-
-const React = require('react-native');
-const {
-  NetInfo, // requires android.permission.ACCESS_NETWORK_STATE
-  Text,
-  View
-} = React;
-const TouchableWithoutFeedback = require('TouchableWithoutFeedback');
-
-const ConnectionSubscription = React.createClass({
-  getInitialState() {
-    return {
-      connectionHistory: [],
-    };
-  },
-  componentDidMount: function() {
-    NetInfo.addEventListener(
-      'change',
-      this._handleConnectionChange
-    );
-  },
-  componentWillUnmount: function() {
-    NetInfo.removeEventListener(
-      'change',
-      this._handleConnectionChange
-    );
-  },
-  _handleConnectionChange: function(netInfo) {
-    var connectionHistory = this.state.connectionHistory.slice();
-    connectionHistory.push(netInfo);
-    this.setState({
-      connectionHistory,
-    });
-  },
-  render() {
-    return (
-      <Text>{JSON.stringify(this.state.connectionHistory)}</Text>
-    );
-  }
-});
-
-const ConnectionCurrent = React.createClass({
-  getInitialState() {
-    return {
-      netInfo: null,
-    };
-  },
-  componentDidMount: function() {
-    NetInfo.addEventListener(
-      'change',
-      this._handleConnectionChange
-    );
-    NetInfo.fetch().done(
-      (netInfo) => { this.setState({netInfo}); }
-    );
-  },
-  componentWillUnmount: function() {
-    NetInfo.removeEventListener(
-      'change',
-      this._handleConnectionChange
-    );
-  },
-  _handleConnectionChange: function(netInfo) {
-    this.setState({
-      netInfo,
-    });
-  },
-  render() {
-    return (
-      <Text>{JSON.stringify(this.state.netInfo)}</Text>
-    );
-  }
-});
-
-const IsConnected = React.createClass({
-  getInitialState() {
-    return {
-      isConnected: null,
-    };
-  },
-  componentDidMount: function() {
-    NetInfo.isConnected.addEventListener(
-      'change',
-      this._handleConnectivityChange
-    );
-    NetInfo.isConnected.fetch().done(
-      (isConnected) => { this.setState({isConnected}); }
-    );
-  },
-  componentWillUnmount: function() {
-    NetInfo.isConnected.removeEventListener(
-      'change',
-      this._handleConnectivityChange
-    );
-  },
-  _handleConnectivityChange: function(isConnected) {
-    this.setState({
-      isConnected,
-    });
-  },
-  render() {
-    return (
-      <Text>{this.state.isConnected ? 'Online' : 'Offline'}</Text>
-    );
-  }
-});
-
-const NetInfoExample = React.createClass({
-  statics: {
-    title: '<NetInfo>',
-    description: 'Monitor network status.'
-  },
-
-  getInitialState() {
-    return {
-      isMetered: null,
-    };
-  },
-  render() {
-    return (
-      <View >
-        <Text> Is Connected: <IsConnected /> </Text>
-        <Text> Current Connection Type: <ConnectionCurrent /> </Text>
-        <Text> Connection History: <ConnectionSubscription /> </Text>
-        <TouchableWithoutFeedback onPress={this.isConnectionMetered}>
-          <View>
-            <Text>Click to see if connection is metered: {this.state.isMetered}</Text>
-          </View>
-        </TouchableWithoutFeedback>
-      </View>
-    );
-  },
-  isConnectionMetered: function() {
-    NetInfo.isConnectionMetered((isConnectionMetered) => {
-      this.setState({
-        isMetered: isConnectionMetered ? 'Is Metered' : 'Is Not Metered',
-      });
-    });
-  }
-});
-
-module.exports = NetInfoExample;
diff --git a/Examples/UIExplorer/NetInfoExample.ios.js b/Examples/UIExplorer/NetInfoExample.ios.js
deleted file mode 100644
index 6ab1805dfee4..000000000000
--- a/Examples/UIExplorer/NetInfoExample.ios.js
+++ /dev/null
@@ -1,147 +0,0 @@
-/**
- * The examples provided by Facebook are for non-commercial testing and
- * evaluation purposes only.
- *
- * Facebook reserves all rights not expressly granted.
- *
- * 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 NON INFRINGEMENT. IN NO EVENT SHALL
- * FACEBOOK 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.
- *
- * @flow
- */
-'use strict';
-
-var React = require('react-native');
-var {
-  NetInfo,
-  Text,
-  View
-} = React;
-
-var ReachabilitySubscription = React.createClass({
-  getInitialState() {
-    return {
-      reachabilityHistory: [],
-    };
-  },
-  componentDidMount: function() {
-    NetInfo.addEventListener(
-      'change',
-      this._handleReachabilityChange
-    );
-  },
-  componentWillUnmount: function() {
-    NetInfo.removeEventListener(
-      'change',
-      this._handleReachabilityChange
-    );
-  },
-  _handleReachabilityChange: function(reachability) {
-    var reachabilityHistory = this.state.reachabilityHistory.slice();
-    reachabilityHistory.push(reachability);
-    this.setState({
-      reachabilityHistory,
-    });
-  },
-  render() {
-    return (
-      <View>
-        <Text>{JSON.stringify(this.state.reachabilityHistory)}</Text>
-      </View>
-    );
-  }
-});
-
-var ReachabilityCurrent = React.createClass({
-  getInitialState() {
-    return {
-      reachability: null,
-    };
-  },
-  componentDidMount: function() {
-    NetInfo.addEventListener(
-      'change',
-      this._handleReachabilityChange
-    );
-    NetInfo.fetch().done(
-      (reachability) => { this.setState({reachability}); }
-    );
-  },
-  componentWillUnmount: function() {
-    NetInfo.removeEventListener(
-      'change',
-      this._handleReachabilityChange
-    );
-  },
-  _handleReachabilityChange: function(reachability) {
-    this.setState({
-      reachability,
-    });
-  },
-  render() {
-    return (
-      <View>
-        <Text>{this.state.reachability}</Text>
-      </View>
-    );
-  }
-});
-
-var IsConnected = React.createClass({
-  getInitialState() {
-    return {
-      isConnected: null,
-    };
-  },
-  componentDidMount: function() {
-    NetInfo.isConnected.addEventListener(
-      'change',
-      this._handleConnectivityChange
-    );
-    NetInfo.isConnected.fetch().done(
-      (isConnected) => { this.setState({isConnected}); }
-    );
-  },
-  componentWillUnmount: function() {
-    NetInfo.isConnected.removeEventListener(
-      'change',
-      this._handleConnectivityChange
-    );
-  },
-  _handleConnectivityChange: function(isConnected) {
-    this.setState({
-      isConnected,
-    });
-  },
-  render() {
-    return (
-      <View>
-        <Text>{this.state.isConnected ? 'Online' : 'Offline'}</Text>
-      </View>
-    );
-  }
-});
-
-exports.title = 'NetInfo';
-exports.description = 'Monitor network status';
-exports.examples = [
-  {
-    title: 'NetInfo.isConnected',
-    description: 'Asynchronously load and observe connectivity',
-    render(): ReactElement { return <IsConnected />; }
-  },
-  {
-    title: 'NetInfo.reachabilityIOS',
-    description: 'Asynchronously load and observe iOS reachability',
-    render(): ReactElement { return <ReachabilityCurrent />; }
-  },
-  {
-    title: 'NetInfo.reachabilityIOS',
-    description: 'Observed updates to iOS reachability',
-    render(): ReactElement { return <ReachabilitySubscription />; }
-  },
-];
diff --git a/Examples/UIExplorer/NetInfoExample.js b/Examples/UIExplorer/NetInfoExample.js
new file mode 100644
index 000000000000..acbbb26733af
--- /dev/null
+++ b/Examples/UIExplorer/NetInfoExample.js
@@ -0,0 +1,182 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ *
+ * @flow
+ */
+'use strict';
+
+const React = require('react-native');
+const {
+  NetInfo,
+  Text,
+  View,
+  TouchableWithoutFeedback,
+} = React;
+
+const ConnectionInfoSubscription = React.createClass({
+  getInitialState() {
+    return {
+      connectionInfoHistory: [],
+    };
+  },
+  componentDidMount: function() {
+    NetInfo.addEventListener(
+        'change',
+        this._handleConnectionInfoChange
+    );
+  },
+  componentWillUnmount: function() {
+    NetInfo.removeEventListener(
+        'change',
+        this._handleConnectionInfoChange
+    );
+  },
+  _handleConnectionInfoChange: function(connectionInfo) {
+    const connectionInfoHistory = this.state.connectionInfoHistory.slice();
+    connectionInfoHistory.push(connectionInfo);
+    this.setState({
+      connectionInfoHistory,
+    });
+  },
+  render() {
+    return (
+        <View>
+          <Text>{JSON.stringify(this.state.connectionInfoHistory)}</Text>
+        </View>
+    );
+  }
+});
+
+const ConnectionInfoCurrent = React.createClass({
+  getInitialState() {
+    return {
+      connectionInfo: null,
+    };
+  },
+  componentDidMount: function() {
+    NetInfo.addEventListener(
+        'change',
+        this._handleConnectionInfoChange
+    );
+    NetInfo.fetch().done(
+        (connectionInfo) => { this.setState({connectionInfo}); }
+    );
+  },
+  componentWillUnmount: function() {
+    NetInfo.removeEventListener(
+        'change',
+        this._handleConnectionInfoChange
+    );
+  },
+  _handleConnectionInfoChange: function(connectionInfo) {
+    this.setState({
+      connectionInfo,
+    });
+  },
+  render() {
+    return (
+        <View>
+          <Text>{this.state.connectionInfo}</Text>
+        </View>
+    );
+  }
+});
+
+const IsConnected = React.createClass({
+  getInitialState() {
+    return {
+      isConnected: null,
+    };
+  },
+  componentDidMount: function() {
+    NetInfo.isConnected.addEventListener(
+        'change',
+        this._handleConnectivityChange
+    );
+    NetInfo.isConnected.fetch().done(
+        (isConnected) => { this.setState({isConnected}); }
+    );
+  },
+  componentWillUnmount: function() {
+    NetInfo.isConnected.removeEventListener(
+        'change',
+        this._handleConnectivityChange
+    );
+  },
+  _handleConnectivityChange: function(isConnected) {
+    this.setState({
+      isConnected,
+    });
+  },
+  render() {
+    return (
+        <View>
+          <Text>{this.state.isConnected ? 'Online' : 'Offline'}</Text>
+        </View>
+    );
+  }
+});
+
+const IsConnectionExpensive = React.createClass({
+  getInitialState() {
+    return {
+      isConnectionExpensive: null,
+    };
+  },
+  _checkIfExpensive() {
+    NetInfo.isConnectionExpensive(
+        (isConnectionExpensive) => { this.setState({isConnectionExpensive}); }
+    );
+  },
+  render() {
+    return (
+        <View>
+          <TouchableWithoutFeedback onPress={this._checkIfExpensive}>
+            <View>
+              <Text>Click to see if connection is expensive:
+                {this.state.isConnectionExpensive === true ? 'Expensive' :
+                this.state.isConnectionExpensive === false ? 'Not expensive'
+                : 'Unknown'}
+              </Text>
+            </View>
+          </TouchableWithoutFeedback>
+        </View>
+    );
+  }
+});
+
+exports.title = 'NetInfo';
+exports.description = 'Monitor network status';
+exports.examples = [
+  {
+    title: 'NetInfo.isConnected',
+    description: 'Asynchronously load and observe connectivity',
+    render(): ReactElement { return <IsConnected />; }
+  },
+  {
+    title: 'NetInfo.update',
+    description: 'Asynchronously load and observe connectionInfo',
+    render(): ReactElement { return <ConnectionInfoCurrent />; }
+  },
+  {
+    title: 'NetInfo.updateHistory',
+    description: 'Observed updates to connectionInfo',
+    render(): ReactElement { return <ConnectionInfoSubscription />; }
+  },
+  {
+    platform: 'android',
+    title: 'NetInfo.isConnectionExpensive (Android)',
+    description: 'Asycnronously check isConnectionExpensive',
+    render(): ReactElement { return <IsConnectionExpensive />; }
+  },
+];
diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index 6445eff49905..a2ff43096c55 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -43,7 +43,7 @@ var APIS = [
   require('./IntentAndroidExample.android'),
   require('./LayoutEventsExample'),
   require('./LayoutExample'),
-  require('./NetInfoExample.android'),
+  require('./NetInfoExample'),
   require('./PanResponderExample'),
   require('./PointerEventsExample'),
   require('./TimerExample'),
diff --git a/Examples/UIExplorer/UIExplorerList.ios.js b/Examples/UIExplorer/UIExplorerList.ios.js
index 2f937cbeb6be..940bd79ba42e 100644
--- a/Examples/UIExplorer/UIExplorerList.ios.js
+++ b/Examples/UIExplorer/UIExplorerList.ios.js
@@ -68,7 +68,7 @@ var APIS = [
   require('./CameraRollExample.ios'),
   require('./GeolocationExample'),
   require('./LayoutExample'),
-  require('./NetInfoExample.ios'),
+  require('./NetInfoExample'),
   require('./PanResponderExample'),
   require('./PointerEventsExample'),
   require('./PushNotificationIOSExample'),
diff --git a/Libraries/Network/NetInfo.js b/Libraries/Network/NetInfo.js
index c2099c9e3eac..2b17603adedf 100644
--- a/Libraries/Network/NetInfo.js
+++ b/Libraries/Network/NetInfo.js
@@ -11,13 +11,13 @@
  */
 'use strict';
 
-var Map = require('Map');
-var NativeModules = require('NativeModules');
-var Platform = require('Platform');
-var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
-var RCTNetInfo = NativeModules.NetInfo;
+const Map = require('Map');
+const NativeModules = require('NativeModules');
+const Platform = require('Platform');
+const RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
+const RCTNetInfo = NativeModules.NetInfo;
 
-var DEVICE_CONNECTIVITY_EVENT = 'networkStatusDidChange';
+const DEVICE_CONNECTIVITY_EVENT = 'networkStatusDidChange';
 
 type ChangeEventName = $Enum<{
   change: string;
@@ -54,24 +54,20 @@ type ConnectivityStateAndroid = $Enum<{
 }>;
 
 
-var _subscriptions = new Map();
+const _subscriptions = new Map();
 
+let _isConnected;
 if (Platform.OS === 'ios') {
-  var _isConnected = function(
-    reachability: ReachabilityStateIOS
-  ): bool {
-    return reachability !== 'none' &&
-      reachability !== 'unknown';
+  _isConnected = (reachability: ReachabilityStateIOS): bool => {
+    return reachability !== 'none' && reachability !== 'unknown';
   };
 } else if (Platform.OS === 'android') {
-  var _isConnected = function(
-      connectionType: ConnectivityStateAndroid
-    ): bool {
+  _isConnected = (connectionType: ConnectivityStateAndroid) : bool => {
     return connectionType !== 'NONE' && connectionType !== 'UNKNOWN';
   };
 }
 
-var _isConnectedSubscriptions = new Map();
+const _isConnectedSubscriptions = new Map();
 
 /**
  * NetInfo exposes info about online/offline status
@@ -128,15 +124,15 @@ var _isConnectedSubscriptions = new Map();
  *
  * The rest ConnectivityStates are hidden by the Android API, but can be used if necessary.
  *
- * ### isConnectionMetered
+ * ### isConnectionExpensive
  *
  * Available on Android. Detect if the current active connection is metered or not. A network is
  * classified as metered when the user is sensitive to heavy data usage on that connection due to
  * monetary costs, data limitations or battery/performance issues.
  *
  * ```
- * NetInfo.isConnectionMetered((isConnectionMetered) => {
- *   console.log('Connection is ' + (isConnectionMetered ? 'Metered' : 'Not Metered'));
+ * NetInfo.isConnectionExpensive((isConnectionExpensive) => {
+ *   console.log('Connection is ' + (isConnectionExpensive ? 'Expensive' : 'Not Expensive'));
  * });
  * ```
  *
@@ -162,12 +158,12 @@ var _isConnectedSubscriptions = new Map();
  * );
  * ```
  */
-var NetInfo = {
-  addEventListener: function (
+const NetInfo = {
+  addEventListener(
     eventName: ChangeEventName,
     handler: Function
   ): void {
-    var listener = RCTDeviceEventEmitter.addListener(
+    const listener = RCTDeviceEventEmitter.addListener(
       DEVICE_CONNECTIVITY_EVENT,
       (appStateData) => {
         handler(appStateData.network_info);
@@ -176,11 +172,11 @@ var NetInfo = {
     _subscriptions.set(handler, listener);
   },
 
-  removeEventListener: function(
+  removeEventListener(
     eventName: ChangeEventName,
     handler: Function
   ): void {
-    var listener = _subscriptions.get(handler);
+    const listener = _subscriptions.get(handler);
     if (!listener) {
       return;
     }
@@ -188,7 +184,7 @@ var NetInfo = {
     _subscriptions.delete(handler);
   },
 
-  fetch: function(): Promise {
+  fetch(): Promise {
     return new Promise((resolve, reject) => {
       RCTNetInfo.getCurrentConnectivity(
         function(resp) {
@@ -200,11 +196,11 @@ var NetInfo = {
   },
 
   isConnected: {
-    addEventListener: function (
+    addEventListener(
       eventName: ChangeEventName,
       handler: Function
     ): void {
-      var listener = (connection) => {
+      const listener = (connection) => {
         handler(_isConnected(connection));
       };
       _isConnectedSubscriptions.set(handler, listener);
@@ -214,11 +210,11 @@ var NetInfo = {
       );
     },
 
-    removeEventListener: function(
+    removeEventListener(
       eventName: ChangeEventName,
       handler: Function
     ): void {
-      var listener = _isConnectedSubscriptions.get(handler);
+      const listener = _isConnectedSubscriptions.get(handler);
       NetInfo.removeEventListener(
         eventName,
         listener
@@ -226,22 +222,23 @@ var NetInfo = {
       _isConnectedSubscriptions.delete(handler);
     },
 
-    fetch: function(): Promise {
+    fetch(): Promise {
       return NetInfo.fetch().then(
         (connection) => _isConnected(connection)
       );
     },
   },
 
-  isConnectionMetered: ({}: {} | (callback:Function) => void),
+  isConnectionExpensive(callback: (metered: ?boolean, error: string) => void): void {
+    if (Platform.OS === 'android') {
+      RCTNetInfo.isConnectionMetered((_isMetered) => {
+        callback(_isMetered);
+      });
+    } else {
+      // TODO t9296080 consider polyfill and more features later on
+      callback(null, "Unsupported");
+    }
+  },
 };
 
-if (Platform.OS === 'android') {
-  NetInfo.isConnectionMetered = function(callback): void {
-    RCTNetInfo.isConnectionMetered((_isMetered) => {
-      callback(_isMetered);
-    });
-  };
-}
-
 module.exports = NetInfo;

From c489660f264859a10fc89e8f9bf091ead5d59e15 Mon Sep 17 00:00:00 2001
From: Edvin Erikson <edvin@rocketblast.com>
Date: Tue, 8 Dec 2015 10:09:16 -0800
Subject: [PATCH 0274/1411] Inspecting stateless components.

Summary:
Fixes #4602

Fixes a bug where the app crashes when you try to inspect a stateless
component.
Fixed by replacing all occurrences of the getPublicInstance method in
Libraries/Inspector/Inspector.js with the _instance property instead.
Defaults to an empty object if _instance is falsy.
Closes https://github.com/facebook/react-native/pull/4642

Reviewed By: svcscm

Differential Revision: D2734491

Pulled By: androidtrunkagent

fb-gh-sync-id: 4ea753b7e0ef3fd05af2d80abadc365c5c787f98
---
 Libraries/Inspector/Inspector.js | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/Libraries/Inspector/Inspector.js b/Libraries/Inspector/Inspector.js
index 7dbec7443ace..c72da8e7e765 100644
--- a/Libraries/Inspector/Inspector.js
+++ b/Libraries/Inspector/Inspector.js
@@ -98,7 +98,9 @@ class Inspector extends React.Component {
 
   setSelection(i: number) {
     var instance = this.state.hierarchy[i];
-    var publicInstance = instance.getPublicInstance();
+    // if we inspect a stateless component we can't use the getPublicInstance method
+    // therefore we use the internal _instance property directly.
+    var publicInstance = instance._instance || {};
     UIManager.measure(React.findNodeHandle(instance), (x, y, width, height, left, top) => {
       this.setState({
         inspected: {
@@ -115,7 +117,9 @@ class Inspector extends React.Component {
       this.state.devtoolsAgent.selectFromReactInstance(instance, true);
     }
     var hierarchy = InspectorUtils.getOwnerHierarchy(instance);
-    var publicInstance = instance.getPublicInstance();
+    // if we inspect a stateless component we can't use the getPublicInstance method
+    // therefore we use the internal _instance property directly.
+    var publicInstance = instance._instance || {};
     var props = publicInstance.props || {};
     this.setState({
       panelPos: pointerY > Dimensions.get('window').height / 2 ? 'top' : 'bottom',

From d0135540835b7fe9e95336d800227c5f61a52721 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Tue, 8 Dec 2015 10:58:35 -0800
Subject: [PATCH 0275/1411] Prepend magic number to unbundle files

Summary:
In order to be able to reliable identify unbundles when loading files, prepend a magic number (0xFB0BD1E5)
public

Reviewed By: martinbigio

Differential Revision: D2734359

fb-gh-sync-id: b469e26459234e7f6270fffa0b872a93d137381d
---
 local-cli/bundle/output/unbundle.js | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/local-cli/bundle/output/unbundle.js b/local-cli/bundle/output/unbundle.js
index 65156dcca031..de265c7dfc39 100644
--- a/local-cli/bundle/output/unbundle.js
+++ b/local-cli/bundle/output/unbundle.js
@@ -12,6 +12,7 @@ const fs = require('fs');
 const Promise = require('promise');
 const writeFile = require('./writeFile');
 
+const MAGIC_UNBUNDLE_FILE_HEADER = 0xFB0BD1E5;
 const MAGIC_STARTUP_MODULE_ID = '';
 
 function buildBundle(packagerClient, requestOptions) {
@@ -49,6 +50,8 @@ function saveUnbundle(bundle, options, log) {
 }
 
 /* global Buffer: true */
+const fileHeader = Buffer(4);
+fileHeader.writeUInt32LE(MAGIC_UNBUNDLE_FILE_HEADER);
 const nullByteBuffer = Buffer(1).fill(0);
 
 const moduleToBuffer = ({name, code}, encoding) => ({
@@ -109,7 +112,7 @@ function buildModuleTable(buffers) {
 function buildTableAndContents(startupCode, modules, encoding) {
   const buffers = buildModuleBuffers(startupCode, modules, encoding);
   const table = buildModuleTable(buffers, encoding);
-  return [table].concat(buffers.map(({buffer}) => buffer));
+  return [fileHeader, table].concat(buffers.map(({buffer}) => buffer));
 }
 
 function writeBuffers(stream, buffers) {

From 7b13ce30f2ba070f8a11217779a937f27e083e9e Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Tue, 8 Dec 2015 11:53:55 -0800
Subject: [PATCH 0276/1411] Fix flow

Reviewed By: gabelevi

Differential Revision: D2734936

fb-gh-sync-id: 0c085c4968e52907a60bbd1d8af30dac6f449e46
---
 Examples/Movies/MovieCell.js   | 3 ---
 Examples/Movies/MovieScreen.js | 3 ---
 2 files changed, 6 deletions(-)

diff --git a/Examples/Movies/MovieCell.js b/Examples/Movies/MovieCell.js
index 62062cb2af22..85c616d329cc 100644
--- a/Examples/Movies/MovieCell.js
+++ b/Examples/Movies/MovieCell.js
@@ -45,9 +45,6 @@ var MovieCell = React.createClass({
           onShowUnderlay={this.props.onHighlight}
           onHideUnderlay={this.props.onUnhighlight}>
           <View style={styles.row}>
-            {/* $FlowIssue #7363964 - There's a bug in Flow where you cannot
-              * omit a property or set it to undefined if it's inside a shape,
-              * even if it isn't required */}
             <Image
               source={getImageSource(this.props.movie, 'det')}
               style={styles.cellImage}
diff --git a/Examples/Movies/MovieScreen.js b/Examples/Movies/MovieScreen.js
index 09d6544dff59..1f6d579e5f61 100644
--- a/Examples/Movies/MovieScreen.js
+++ b/Examples/Movies/MovieScreen.js
@@ -34,9 +34,6 @@ var MovieScreen = React.createClass({
     return (
       <ScrollView contentContainerStyle={styles.contentContainer}>
         <View style={styles.mainSection}>
-          {/* $FlowIssue #7363964 - There's a bug in Flow where you cannot
-            * omit a property or set it to undefined if it's inside a shape,
-            * even if it isn't required */}
           <Image
             source={getImageSource(this.props.movie, 'det')}
             style={styles.detailsImage}

From 56793e3f8dcd10adc95fe6325fcddd59269f359a Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Tue, 8 Dec 2015 12:02:17 -0800
Subject: [PATCH 0277/1411] Fixed Flow error

Reviewed By: gabelevi

Differential Revision: D2734738

fb-gh-sync-id: 5ba3d4285185cd220a5bf6a26cb3818311822e52
---
 Libraries/Network/NetInfo.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/Network/NetInfo.js b/Libraries/Network/NetInfo.js
index 2b17603adedf..d4295754f259 100644
--- a/Libraries/Network/NetInfo.js
+++ b/Libraries/Network/NetInfo.js
@@ -229,7 +229,7 @@ const NetInfo = {
     },
   },
 
-  isConnectionExpensive(callback: (metered: ?boolean, error: string) => void): void {
+  isConnectionExpensive(callback: (metered: ?boolean, error?: string) => void): void {
     if (Platform.OS === 'android') {
       RCTNetInfo.isConnectionMetered((_isMetered) => {
         callback(_isMetered);

From 202222504e3c92453c6e539ac2d57fd45157221a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Tue, 8 Dec 2015 12:23:41 -0800
Subject: [PATCH 0278/1411] Introduce `loadBundles`

Summary:
public

Introduce a new Polyfill module to load bundles. This polyfill contains the function to which System.import gets transformed into. It works similarly to require in the way it's registered. It keeps track of the bundles that have ever been requested using promises, either fulfilled or not. The use of promises makes the implementation quite easy as we don't need to differenciate whether the request has been started or not.

There're a couple of follow up steps that still need to get done:

- Included this polyfill on the ones we automatically include on the bundle.
- Modify the transform to include the modules the user is actually requesting and pipe that through loadBundles so that the promise, once resolved, has the ordered list of modules the user requested.
- Implement the actual native code that loads a bundle. This shouldn't be that taught  as native will be able to assume it will never receive the same request twice.

Reviewed By: davidaurelio

Differential Revision: D2727241

fb-gh-sync-id: 317d80754783caf43f10c71a34a4558a4d298d45
---
 .../polyfills/__tests__/loadBundles-test.js   | 64 +++++++++++++++++++
 .../src/Resolver/polyfills/loadBundles.js     | 50 +++++++++++++++
 2 files changed, 114 insertions(+)
 create mode 100644 packager/react-packager/src/Resolver/polyfills/__tests__/loadBundles-test.js
 create mode 100644 packager/react-packager/src/Resolver/polyfills/loadBundles.js

diff --git a/packager/react-packager/src/Resolver/polyfills/__tests__/loadBundles-test.js b/packager/react-packager/src/Resolver/polyfills/__tests__/loadBundles-test.js
new file mode 100644
index 000000000000..ad0dcf279473
--- /dev/null
+++ b/packager/react-packager/src/Resolver/polyfills/__tests__/loadBundles-test.js
@@ -0,0 +1,64 @@
+/**
+ * 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.
+ */
+'use strict';
+
+jest.dontMock('../loadBundles');
+jest.mock('NativeModules');
+
+let loadBundles;
+let loadBundlesCalls;
+
+describe('loadBundles', () => {
+  beforeEach(() => {
+    loadBundles = jest.genMockFunction();
+    loadBundlesCalls = loadBundles.mock.calls;
+    require('NativeModules').RCTBundlesLoader = {loadBundles};
+
+    require('../loadBundles');
+  });
+
+  it('should set `global.__loadBundles` function when polyfill is initialized', () => {
+    expect(typeof global.__loadBundles).toBe('function');
+  });
+
+  it('should return a promise', () => {
+    loadBundles.mockImpl((bundles, callback) => callback());
+    expect(global.__loadBundles(['bundle.0']) instanceof Promise).toBeTruthy();
+  });
+
+  pit('shouldn\'t request already loaded bundles', () => {
+    loadBundles.mockImpl((bundles, callback) => callback());
+    return global
+      .__loadBundles(['bundle.0'])
+      .then(() => global.__loadBundles(['bundle.0']))
+      .then(() => expect(loadBundlesCalls.length).toBe(1));
+  });
+
+  pit('shouldn\'n request inflight bundles', () => {
+    loadBundles.mockImpl((bundles, callback) => {
+      if (bundles.length === 1 && bundles[0] === 'bundle.0') {
+        setTimeout(callback, 1000);
+      } else if (bundles.length === 1 && bundles[0] === 'bundle.1') {
+        setTimeout(callback, 500);
+      }
+    });
+
+    const promises = Promise.all([
+      global.__loadBundles(['bundle.0']),
+      global.__loadBundles(['bundle.0', 'bundle.1']),
+    ]).then(() => {
+      expect(loadBundlesCalls.length).toBe(2);
+      expect(loadBundlesCalls[0][0][0]).toBe('bundle.0');
+      expect(loadBundlesCalls[1][0][0]).toBe('bundle.1');
+    });
+
+    jest.runAllTimers();
+    return promises;
+  });
+});
diff --git a/packager/react-packager/src/Resolver/polyfills/loadBundles.js b/packager/react-packager/src/Resolver/polyfills/loadBundles.js
new file mode 100644
index 000000000000..551d4cac22dc
--- /dev/null
+++ b/packager/react-packager/src/Resolver/polyfills/loadBundles.js
@@ -0,0 +1,50 @@
+/* eslint global-strict:0 */
+(global => {
+  let loadBundlesOnNative = (bundles) =>
+    new Promise((_, resolve) =>
+      require('NativeModules').RCTBundlesLoader.loadBundles(bundles, resolve));
+
+  let requestedBundles = Object.create(null);
+
+  /**
+   * Returns a promise that is fulfilled once all the indicated bundles are
+   * loaded into memory and injected into the JS engine.
+   * This invokation might need to go through the bridge
+   * and run native code to load some, if not all, the requested bundles.
+   * If all the bundles have already been loaded, the promise is resolved
+   * immediately. Otherwise, we'll determine which bundles still need to get
+   * loaded considering both, the ones already loaded, and the ones being
+   * currently asynchronously loaded by other invocations to `__loadBundles`,
+   * and return a promise that will get fulfilled once all these are finally
+   * loaded.
+   *
+   * Note this function should only be invoked by generated code.
+   */
+  global.__loadBundles = function(bundles) {
+    // split bundles by whether they've already been requested or not
+    const bundlesToRequest = bundles.filter(b => !requestedBundles[b]);
+    const bundlesAlreadyRequested = bundles.filter(b => !!requestedBundles[b]);
+
+    // keep a reference to the promise loading each bundle
+    if (bundlesToRequest.length > 0) {
+      const nativePromise = loadBundlesOnNative(bundlesToRequest);
+      bundlesToRequest.forEach(b => requestedBundles[b] = nativePromise);
+    }
+
+    return Promise.all(bundles.map(bundle => requestedBundles[bundle]));
+  };
+})(global);
+
+
+// turns a callback async based function into a promised based one
+function promisify(fn) {
+  return function() {
+    var self = this;
+    var args = Array.prototype.slice.call(arguments);
+
+    return new Promise((resolve, reject) => {
+      args.push(resolve);
+      fn.apply(self, args);
+    });
+  };
+}

From 066ebc021f2ac89b811305c3e8335e4b7c592bc6 Mon Sep 17 00:00:00 2001
From: "glevi@fb.com" <glevi@fb.com>
Date: Tue, 8 Dec 2015 13:23:01 -0800
Subject: [PATCH 0279/1411] Fix PickerIOSExample

Reviewed By: nicklockwood

Differential Revision: D2735834

fb-gh-sync-id: 8f2777ec2afe007523ea85cca27f40497910d2d1
---
 Examples/UIExplorer/PickerIOSExample.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/Examples/UIExplorer/PickerIOSExample.js b/Examples/UIExplorer/PickerIOSExample.js
index d38ef54e9f3b..51b8f9f30e76 100644
--- a/Examples/UIExplorer/PickerIOSExample.js
+++ b/Examples/UIExplorer/PickerIOSExample.js
@@ -113,9 +113,10 @@ var PickerStyleExample = React.createClass({
   getInitialState: function() {
     return {
       carMake: 'cadillac',
+      modelIndex: 0,
     };
   },
-  
+
   render: function() {
     var make = CAR_MAKES_AND_MODELS[this.state.carMake];
     var selectionString = make.name + ' ' + make.models[this.state.modelIndex];

From 16a29b0b8701697372ed40dfa4874d66edb6f77c Mon Sep 17 00:00:00 2001
From: Terry Yiu <tyiu@users.noreply.github.com>
Date: Tue, 8 Dec 2015 14:30:07 -0800
Subject: [PATCH 0280/1411] Fix EmbeddedAppIOS documentation

Fix with correct init call on RCTRootView due to change in method signature from commit 261f9434e54274a68d2cb50644c436197ef48baa
---
 docs/EmbeddedAppIOS.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/docs/EmbeddedAppIOS.md b/docs/EmbeddedAppIOS.md
index 655809fa044a..b82c608d1971 100644
--- a/docs/EmbeddedAppIOS.md
+++ b/docs/EmbeddedAppIOS.md
@@ -136,6 +136,7 @@ NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.b
 //   curl http://localhost:8081/index.ios.bundle -o main.jsbundle
 RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                     moduleName: @"SimpleApp"
+                                             initialProperties:nil
                                                  launchOptions:nil];
 ```
 

From 99bba8ca4e5731f6442fc0bf626b8ce2dd6127bb Mon Sep 17 00:00:00 2001
From: Gabe Levi <glevi@fb.com>
Date: Tue, 8 Dec 2015 14:47:09 -0800
Subject: [PATCH 0281/1411] Use .flow files to tell Flow about react-native
 module

Reviewed By: jeffmo

Differential Revision: D2735788

fb-gh-sync-id: 7a15caa5effb89b902bba7e0031822f534813c52
---
 Examples/Movies/MovieCell.js                |   3 +
 Examples/Movies/MovieScreen.js              |   3 +
 Examples/UIExplorer/NetInfoExample.js       |   2 +-
 Libraries/react-native/react-native.js.flow | 121 ++++++++++++++++++++
 4 files changed, 128 insertions(+), 1 deletion(-)
 create mode 100644 Libraries/react-native/react-native.js.flow

diff --git a/Examples/Movies/MovieCell.js b/Examples/Movies/MovieCell.js
index 85c616d329cc..62062cb2af22 100644
--- a/Examples/Movies/MovieCell.js
+++ b/Examples/Movies/MovieCell.js
@@ -45,6 +45,9 @@ var MovieCell = React.createClass({
           onShowUnderlay={this.props.onHighlight}
           onHideUnderlay={this.props.onUnhighlight}>
           <View style={styles.row}>
+            {/* $FlowIssue #7363964 - There's a bug in Flow where you cannot
+              * omit a property or set it to undefined if it's inside a shape,
+              * even if it isn't required */}
             <Image
               source={getImageSource(this.props.movie, 'det')}
               style={styles.cellImage}
diff --git a/Examples/Movies/MovieScreen.js b/Examples/Movies/MovieScreen.js
index 1f6d579e5f61..09d6544dff59 100644
--- a/Examples/Movies/MovieScreen.js
+++ b/Examples/Movies/MovieScreen.js
@@ -34,6 +34,9 @@ var MovieScreen = React.createClass({
     return (
       <ScrollView contentContainerStyle={styles.contentContainer}>
         <View style={styles.mainSection}>
+          {/* $FlowIssue #7363964 - There's a bug in Flow where you cannot
+            * omit a property or set it to undefined if it's inside a shape,
+            * even if it isn't required */}
           <Image
             source={getImageSource(this.props.movie, 'det')}
             style={styles.detailsImage}
diff --git a/Examples/UIExplorer/NetInfoExample.js b/Examples/UIExplorer/NetInfoExample.js
index acbbb26733af..af120c591153 100644
--- a/Examples/UIExplorer/NetInfoExample.js
+++ b/Examples/UIExplorer/NetInfoExample.js
@@ -130,7 +130,7 @@ const IsConnected = React.createClass({
 const IsConnectionExpensive = React.createClass({
   getInitialState() {
     return {
-      isConnectionExpensive: null,
+      isConnectionExpensive: (null : ?boolean),
     };
   },
   _checkIfExpensive() {
diff --git a/Libraries/react-native/react-native.js.flow b/Libraries/react-native/react-native.js.flow
new file mode 100644
index 000000000000..0f314456a486
--- /dev/null
+++ b/Libraries/react-native/react-native.js.flow
@@ -0,0 +1,121 @@
+/**
+ * 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.
+ *
+ * This file exists because react-native.js started using getters and setters
+ * and Flow doesn't have a good way to enable getters and setters for
+ * react-native without forcing all react-native users to also enable getters
+ * and setters. Until we solve that issue, we can use this .flow file to
+ * pretend like react-native doesn't use getters and setters 
+ *
+ * @flow
+ */
+'use strict';
+
+// Export React, plus some native additions.
+//
+// The use of Object.create/assign is to work around a Flow bug (#6560135).
+// Once that is fixed, change this back to
+//
+//   var ReactNative = {...require('React'), /* additions */}
+//
+var ReactNative = Object.assign(Object.create(require('React')), {
+  // Components
+  ActivityIndicatorIOS: require('ActivityIndicatorIOS'),
+  ART: require('ReactNativeART'),
+  DatePickerIOS: require('DatePickerIOS'),
+  DrawerLayoutAndroid: require('DrawerLayoutAndroid'),
+  Image: require('Image'),
+  ListView: require('ListView'),
+  MapView: require('MapView'),
+  Modal: require('Modal'),
+  Navigator: require('Navigator'),
+  NavigatorIOS: require('NavigatorIOS'),
+  PickerIOS: require('PickerIOS'),
+  ProgressBarAndroid: require('ProgressBarAndroid'),
+  ProgressViewIOS: require('ProgressViewIOS'),
+  ScrollView: require('ScrollView'),
+  SegmentedControlIOS: require('SegmentedControlIOS'),
+  SliderIOS: require('SliderIOS'),
+  SnapshotViewIOS: require('SnapshotViewIOS'),
+  Switch: require('Switch'),
+  PullToRefreshViewAndroid: require('PullToRefreshViewAndroid'),
+  SwitchAndroid: require('SwitchAndroid'),
+  SwitchIOS: require('SwitchIOS'),
+  TabBarIOS: require('TabBarIOS'),
+  Text: require('Text'),
+  TextInput: require('TextInput'),
+  ToastAndroid: require('ToastAndroid'),
+  ToolbarAndroid: require('ToolbarAndroid'),
+  Touchable: require('Touchable'),
+  TouchableHighlight: require('TouchableHighlight'),
+  TouchableNativeFeedback: require('TouchableNativeFeedback'),
+  TouchableOpacity: require('TouchableOpacity'),
+  TouchableWithoutFeedback: require('TouchableWithoutFeedback'),
+  View: require('View'),
+  ViewPagerAndroid: require('ViewPagerAndroid'),
+  WebView: require('WebView'),
+
+  // APIs
+  ActionSheetIOS: require('ActionSheetIOS'),
+  AdSupportIOS: require('AdSupportIOS'),
+  AlertIOS: require('AlertIOS'),
+  Animated: require('Animated'),
+  AppRegistry: require('AppRegistry'),
+  AppStateIOS: require('AppStateIOS'),
+  AsyncStorage: require('AsyncStorage'),
+  BackAndroid: require('BackAndroid'),
+  CameraRoll: require('CameraRoll'),
+  Dimensions: require('Dimensions'),
+  Easing: require('Easing'),
+  ImagePickerIOS: require('ImagePickerIOS'),
+  IntentAndroid: require('IntentAndroid'),
+  InteractionManager: require('InteractionManager'),
+  LayoutAnimation: require('LayoutAnimation'),
+  LinkingIOS: require('LinkingIOS'),
+  NetInfo: require('NetInfo'),
+  PanResponder: require('PanResponder'),
+  PixelRatio: require('PixelRatio'),
+  PushNotificationIOS: require('PushNotificationIOS'),
+  Settings: require('Settings'),
+  StatusBarIOS: require('StatusBarIOS'),
+  StyleSheet: require('StyleSheet'),
+  UIManager: require('UIManager'),
+  VibrationIOS: require('VibrationIOS'),
+
+  // Plugins
+  DeviceEventEmitter: require('RCTDeviceEventEmitter'),
+  NativeAppEventEmitter: require('RCTNativeAppEventEmitter'),
+  NativeModules: require('NativeModules'),
+  Platform: require('Platform'),
+  processColor: require('processColor'),
+  requireNativeComponent: require('requireNativeComponent'),
+
+  // Prop Types
+  EdgeInsetsPropType: require('EdgeInsetsPropType'),
+  PointPropType: require('PointPropType'),
+
+  // See http://facebook.github.io/react/docs/addons.html
+  addons: {
+    LinkedStateMixin: require('LinkedStateMixin'),
+    Perf: undefined,
+    PureRenderMixin: require('ReactComponentWithPureRenderMixin'),
+    TestModule: require('NativeModules').TestModule,
+    TestUtils: undefined,
+    batchedUpdates: require('ReactUpdates').batchedUpdates,
+    cloneWithProps: require('cloneWithProps'),
+    createFragment: require('ReactFragment').create,
+    update: require('update'),
+  },
+});
+
+if (__DEV__) {
+  ReactNative.addons.Perf = require('ReactDefaultPerf');
+  ReactNative.addons.TestUtils = require('ReactTestUtils');
+}
+
+module.exports = ReactNative;

From 8d397b4cbc05ad801cfafb421cee39bcfe89711d Mon Sep 17 00:00:00 2001
From: Sebastian Markbage <sema@fb.com>
Date: Tue, 8 Dec 2015 15:57:34 -0800
Subject: [PATCH 0282/1411] Decouple Module System from Native Calls

Summary:
The JavaScript ecosystem doesn't have the notion of a built-in native module loader. Even Node is decoupled from its module loader. The module loader system is just JS that runs on top of the global `process` object which has all the built-in goodies.

Additionally there is no such thing as a global require. That is something unique to our providesModule system. In other module systems such as node, every require is contextual. Even registered npm names are localized by version.

The only global namespace that is accessible to the host environment is the global object. Normally module systems attaches itself onto the hooks provided by the host environment on the global object.

Currently, we have two forms of dispatch that reaches directly into the module system. executeJSCall which reaches directly into require. Everything now calls through the BatchedBridge module (except one RCTLog edge case that I will fix). I propose that the executors calls directly onto `BatchedBridge` through an instance on the global so that everything is guaranteed to go through it. It becomes the main communication hub.

I also propose that we drop the dynamic requires inside of MessageQueue/BatchBridge and instead have the modules register themselves with the bridge.

executeJSCall was originally modeled after the XHP equivalent. The XHP equivalent was designed that way because the act of doing the call was the thing that defined a dependency on the module from the page. However, that is not how React Native works.

The JS side is driving the dependencies by virtue of requiring new modules and frameworks and the existence of dependencies is driven by the JS side, so this design doesn't make as much sense.

The main driver for this is to be able to introduce a new module system like Prepack's module system. However, it also unlocks the possibility to do dead module elimination even in our current module system. It is currently not possible because we don't know which module might be called from native.

Since the module system now becomes decoupled we could publish all our providesModule modules as npm/CommonJS modules using a rewrite script. That's what React Core does.

That way people could use any CommonJS bundler such as Webpack, Closure Compiler, Rollup or some new innovation to create a JS bundle.

This diff expands the executeJSCalls to the BatchedBridge's three individual pieces to make them first class instead of being dynamic. This removes one layer of abstraction. Hopefully we can also remove more of the things that register themselves with the BatchedBridge (various EventEmitters) and instead have everything go through the public protocol. ReactMethod/RCT_EXPORT_METHOD.

public

Reviewed By: vjeux

Differential Revision: D2717535

fb-gh-sync-id: 70114f05483124f5ac5c4570422bb91a60a727f6
---
 .../UIExplorerUnitTests/RCTBridgeTests.m      |  20 ++-
 .../RCTContextExecutorTests.m                 |  18 ++-
 IntegrationTests/LoggingTestModule.js         |  11 +-
 Libraries/AppRegistry/AppRegistry.js          |  17 +++
 Libraries/BatchedBridge/BatchedBridge.js      |  20 ++-
 .../BatchedBridgedModules/RCTEventEmitter.js  |   6 +
 .../RCTDebugComponentOwnership.js             |  10 +-
 Libraries/Device/RCTDeviceEventEmitter.js     |   6 +
 .../NativeApp/RCTNativeAppEventEmitter.js     |   6 +
 Libraries/Utilities/MessageQueue.js           |  26 +++-
 Libraries/Utilities/PerformanceLogger.js      |   6 +
 Libraries/Utilities/RCTLog.js                 |   7 +
 .../Utilities/__tests__/MessageQueue-test.js  |   5 +-
 Libraries/WebSocket/RCTWebSocketExecutor.m    |  26 +++-
 React/Base/RCTBatchedBridge.m                 | 135 ++++++++++++------
 React/Base/RCTBridge.m                        |   8 +-
 React/Base/RCTJavaScriptExecutor.h            |  28 +++-
 React/Base/RCTModuleMethod.m                  |  24 ++--
 React/Base/RCTRootView.m                      |   2 +-
 React/Executors/RCTContextExecutor.m          | 106 ++++++++------
 .../facebook/react/CoreModulesPackage.java    |   2 -
 .../react/ReactInstanceManagerImpl.java       |   5 +-
 .../bridge/JSDebuggerWebSocketClient.java     |   5 +-
 .../facebook/react/bridge/JavaJSExecutor.java |   3 +-
 .../bridge/WebsocketJavaScriptExecutor.java   |   3 +-
 .../facebook/react/uimanager/AppRegistry.java |   2 +
 .../facebook/react/uimanager/ReactNative.java |  19 ---
 ReactAndroid/src/main/jni/react/Bridge.cpp    |  43 ++++--
 ReactAndroid/src/main/jni/react/Bridge.h      |  20 ++-
 ReactAndroid/src/main/jni/react/Executor.h    |  26 +++-
 .../src/main/jni/react/JSCExecutor.cpp        |  59 +++++---
 ReactAndroid/src/main/jni/react/JSCExecutor.h |  13 +-
 .../src/main/jni/react/jni/OnLoad.cpp         |  22 ++-
 .../src/main/jni/react/jni/ProxyExecutor.cpp  |  45 ++++--
 .../src/main/jni/react/jni/ProxyExecutor.h    |  12 +-
 .../src/main/jni/react/test/jscexecutor.cpp   |  20 ++-
 local-cli/server/util/debugger.html           |  10 +-
 local-cli/server/util/debuggerWorker.js       |  23 ++-
 38 files changed, 545 insertions(+), 274 deletions(-)
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactNative.java

diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m
index c201f5799389..54a58787e108 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m
@@ -54,10 +54,22 @@ - (BOOL)isValid
   return YES;
 }
 
-- (void)executeJSCall:(__unused NSString *)name
-               method:(__unused NSString *)method
-            arguments:(__unused NSArray *)arguments
-             callback:(RCTJavaScriptCallback)onComplete
+- (void)flushedQueue:(RCTJavaScriptCallback)onComplete
+{
+  onComplete(nil, nil);
+}
+
+- (void)callFunctionOnModule:(NSString *)module
+                      method:(NSString *)method
+                   arguments:(NSArray *)args
+                    callback:(RCTJavaScriptCallback)onComplete
+{
+  onComplete(nil, nil);
+}
+
+- (void)invokeCallbackID:(NSNumber *)cbID
+               arguments:(NSArray *)args
+                callback:(RCTJavaScriptCallback)onComplete
 {
   onComplete(nil, nil);
 }
diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTContextExecutorTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTContextExecutorTests.m
index d00d650467bc..c1b96b13e52b 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTContextExecutorTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTContextExecutorTests.m
@@ -123,8 +123,13 @@ - (void)testJavaScriptCallSpeed
         } \
       } \
     }; \
+    var Bridge = { \
+      callFunctionReturnFlushedQueue: function(module, method, args) { \
+        modules[module].apply(modules[module], args); \
+      } \
+    }; \
     function require(module) { \
-      return modules[module]; \
+      return Bridge; \
     } \
   ";
 
@@ -138,12 +143,11 @@ function require(module) { \
       for (int j = 0; j < runs; j++) {
         @autoreleasepool {
           double start = _get_time_nanoseconds();
-          [_executor executeJSCall:@"module"
-                           method:@"method"
-                        arguments:params
-                         callback:^(id json, __unused NSError *unused) {
-                           XCTAssert([json isEqual:@YES], @"Invalid return");
-                         }];
+          [_executor callFunctionOnModule:@"module"
+                                   method:@"method"
+                                arguments:params
+                                 callback:^(__unused id json, __unused NSError *unused) {
+                                 }];
           double run = _get_time_nanoseconds() - start;
           if ((j % frequency) == frequency - 1) { // Warmup
             total += run;
diff --git a/IntegrationTests/LoggingTestModule.js b/IntegrationTests/LoggingTestModule.js
index 96e59298d8be..5d3073a37715 100644
--- a/IntegrationTests/LoggingTestModule.js
+++ b/IntegrationTests/LoggingTestModule.js
@@ -10,10 +10,12 @@
  */
 'use strict';
 
+var BatchedBridge = require('BatchedBridge');
+
 var warning = require('warning');
 var invariant = require('invariant');
 
-module.exports = {
+var LoggingTestModule = {
   logToConsole: function(str) {
     console.log(str);
   },
@@ -30,3 +32,10 @@ module.exports = {
     throw new Error(str);
   }
 };
+
+BatchedBridge.registerCallableModule(
+  'LoggingTestModule',
+  LoggingTestModule
+);
+
+module.exports = LoggingTestModule;
diff --git a/Libraries/AppRegistry/AppRegistry.js b/Libraries/AppRegistry/AppRegistry.js
index 3cf7f3ab04c8..57bafd2da85a 100644
--- a/Libraries/AppRegistry/AppRegistry.js
+++ b/Libraries/AppRegistry/AppRegistry.js
@@ -11,6 +11,9 @@
  */
 'use strict';
 
+var BatchedBridge = require('BatchedBridge');
+var ReactNative = require('ReactNative');
+
 var invariant = require('invariant');
 var renderApplication = require('renderApplication');
 
@@ -37,6 +40,10 @@ type AppConfig = {
  * for the app and then actually run the app when it's ready by invoking
  * `AppRegistry.runApplication`.
  *
+ * To "stop" an application when a view should be destroyed, call
+ * `AppRegistry.unmountApplicationComponentAtRootTag` with the tag that was
+ * pass into `runApplication`. These should always be used as a pair.
+ *
  * `AppRegistry` should be `require`d early in the `require` sequence to make
  * sure the JS execution environment is setup before other modules are
  * `require`d.
@@ -87,6 +94,16 @@ var AppRegistry = {
     );
     runnables[appKey].run(appParameters);
   },
+
+  unmountApplicationComponentAtRootTag: function(rootTag : number) {
+    ReactNative.unmountComponentAtNodeAndRemoveContainer(rootTag);
+  },
+
 };
 
+BatchedBridge.registerCallableModule(
+  'AppRegistry',
+  AppRegistry
+);
+
 module.exports = AppRegistry;
diff --git a/Libraries/BatchedBridge/BatchedBridge.js b/Libraries/BatchedBridge/BatchedBridge.js
index ea49b202fc01..e4269735afb5 100644
--- a/Libraries/BatchedBridge/BatchedBridge.js
+++ b/Libraries/BatchedBridge/BatchedBridge.js
@@ -10,11 +10,27 @@
  */
 'use strict';
 
-let MessageQueue = require('MessageQueue');
+const MessageQueue = require('MessageQueue');
 
-let BatchedBridge = new MessageQueue(
+const BatchedBridge = new MessageQueue(
   __fbBatchedBridgeConfig.remoteModuleConfig,
   __fbBatchedBridgeConfig.localModulesConfig,
 );
 
+// TODO: Move these around to solve the cycle in a cleaner way.
+
+const BridgeProfiling = require('BridgeProfiling');
+const JSTimersExecution = require('JSTimersExecution');
+
+BatchedBridge.registerCallableModule('BridgeProfiling', BridgeProfiling);
+BatchedBridge.registerCallableModule('JSTimersExecution', JSTimersExecution);
+
+// Wire up the batched bridge on the global object so that we can call into it.
+// Ideally, this would be the inverse relationship. I.e. the native environment
+// provides this global directly with its script embedded. Then this module
+// would export it. A possible fix would be to trim the dependencies in
+// MessageQueue to its minimal features and embed that in the native runtime.
+
+Object.defineProperty(global, '__fbBatchedBridge', { value: BatchedBridge });
+
 module.exports = BatchedBridge;
diff --git a/Libraries/BatchedBridge/BatchedBridgedModules/RCTEventEmitter.js b/Libraries/BatchedBridge/BatchedBridgedModules/RCTEventEmitter.js
index 8c66aac9aa7b..2b8f578e701a 100644
--- a/Libraries/BatchedBridge/BatchedBridgedModules/RCTEventEmitter.js
+++ b/Libraries/BatchedBridge/BatchedBridgedModules/RCTEventEmitter.js
@@ -11,7 +11,13 @@
  */
 'use strict';
 
+var BatchedBridge = require('BatchedBridge');
 var ReactNativeEventEmitter = require('ReactNativeEventEmitter');
 
+BatchedBridge.registerCallableModule(
+  'RCTEventEmitter',
+  ReactNativeEventEmitter
+);
+
 // Completely locally implemented - no native hooks.
 module.exports = ReactNativeEventEmitter;
diff --git a/Libraries/DebugComponentHierarchy/RCTDebugComponentOwnership.js b/Libraries/DebugComponentHierarchy/RCTDebugComponentOwnership.js
index 4ee5a1f03976..d7462bf23b62 100644
--- a/Libraries/DebugComponentHierarchy/RCTDebugComponentOwnership.js
+++ b/Libraries/DebugComponentHierarchy/RCTDebugComponentOwnership.js
@@ -15,6 +15,7 @@
 
 'use strict';
 
+var BatchedBridge = require('BatchedBridge');
 var DebugComponentOwnershipModule = require('NativeModules').DebugComponentOwnershipModule;
 var InspectorUtils = require('InspectorUtils');
 var ReactNativeTagHandles = require('ReactNativeTagHandles');
@@ -35,7 +36,7 @@ function getRootTagForTag(tag: number): ?number {
   return ReactNativeTagHandles.rootNodeIDToTag[rootID];
 }
 
-module.exports = {
+var RCTDebugComponentOwnership = {
 
   /**
    * Asynchronously returns the owner hierarchy as an array of strings. Request id is
@@ -53,3 +54,10 @@ module.exports = {
     DebugComponentOwnershipModule.receiveOwnershipHierarchy(requestID, tag, ownerHierarchy);
   },
 };
+
+BatchedBridge.registerCallableModule(
+  'RCTDebugComponentOwnership',
+  RCTDebugComponentOwnership
+);
+
+module.exports = RCTDebugComponentOwnership;
diff --git a/Libraries/Device/RCTDeviceEventEmitter.js b/Libraries/Device/RCTDeviceEventEmitter.js
index 586663e343a7..41e4d408f4f2 100644
--- a/Libraries/Device/RCTDeviceEventEmitter.js
+++ b/Libraries/Device/RCTDeviceEventEmitter.js
@@ -12,7 +12,13 @@
 'use strict';
 
 var EventEmitter = require('EventEmitter');
+var BatchedBridge = require('BatchedBridge');
 
 var RCTDeviceEventEmitter = new EventEmitter();
 
+BatchedBridge.registerCallableModule(
+  'RCTDeviceEventEmitter',
+  RCTDeviceEventEmitter
+);
+
 module.exports = RCTDeviceEventEmitter;
diff --git a/Libraries/NativeApp/RCTNativeAppEventEmitter.js b/Libraries/NativeApp/RCTNativeAppEventEmitter.js
index 38ccb0dcfdce..9d4de85f39e8 100644
--- a/Libraries/NativeApp/RCTNativeAppEventEmitter.js
+++ b/Libraries/NativeApp/RCTNativeAppEventEmitter.js
@@ -11,8 +11,14 @@
  */
 'use strict';
 
+var BatchedBridge = require('BatchedBridge');
 var EventEmitter = require('EventEmitter');
 
 var RCTNativeAppEventEmitter = new EventEmitter();
 
+BatchedBridge.registerCallableModule(
+  'RCTNativeAppEventEmitter',
+  RCTNativeAppEventEmitter
+);
+
 module.exports = RCTNativeAppEventEmitter;
diff --git a/Libraries/Utilities/MessageQueue.js b/Libraries/Utilities/MessageQueue.js
index 940b3b459997..b7dd38a24927 100644
--- a/Libraries/Utilities/MessageQueue.js
+++ b/Libraries/Utilities/MessageQueue.js
@@ -43,10 +43,10 @@ var guard = (fn) => {
 
 class MessageQueue {
 
-  constructor(remoteModules, localModules, customRequire) {
+  constructor(remoteModules, localModules) {
     this.RemoteModules = {};
 
-    this._require = customRequire || require;
+    this._callableModules = {};
     this._queue = [[],[],[]];
     this._moduleTable = {};
     this._methodTable = {};
@@ -154,8 +154,22 @@ class MessageQueue {
     if (__DEV__ && SPY_MODE) {
       console.log('N->JS : ' + module + '.' + method + '(' + JSON.stringify(args) + ')');
     }
-    module = this._require(module);
-    module[method].apply(module, args);
+    var moduleMethods = this._callableModules[module];
+    if (!moduleMethods) {
+      // TODO: Register all the remaining test modules and make this an invariant. #9317773
+      // Fallback to require temporarily. A follow up diff will clean up the remaining
+      // modules and make this an invariant.
+      console.warn('Module is not registered:', module);
+      moduleMethods = require(module);
+      /*
+      invariant(
+        !!moduleMethods,
+        'Module %s is not a registered callable module.',
+        module
+      );
+      */
+    }
+    moduleMethods[method].apply(moduleMethods, args);
     BridgeProfiling.profileEnd();
   }
 
@@ -337,6 +351,10 @@ class MessageQueue {
     return fn;
   }
 
+  registerCallableModule(name, methods) {
+    this._callableModules[name] = methods;
+  }
+
 }
 
 function moduleHasConstants(moduleArray: Array<Object|Array<>>): boolean {
diff --git a/Libraries/Utilities/PerformanceLogger.js b/Libraries/Utilities/PerformanceLogger.js
index daafe46a5663..e2d0e5c81ad2 100644
--- a/Libraries/Utilities/PerformanceLogger.js
+++ b/Libraries/Utilities/PerformanceLogger.js
@@ -10,6 +10,7 @@
  */
 'use strict';
 
+var BatchedBridge = require('BatchedBridge');
 
 var performanceNow = require('performanceNow');
 
@@ -140,4 +141,9 @@ var PerformanceLogger = {
   }
 };
 
+BatchedBridge.registerCallableModule(
+  'PerformanceLogger',
+  PerformanceLogger
+);
+
 module.exports = PerformanceLogger;
diff --git a/Libraries/Utilities/RCTLog.js b/Libraries/Utilities/RCTLog.js
index 5b280dd66631..65abc5883d03 100644
--- a/Libraries/Utilities/RCTLog.js
+++ b/Libraries/Utilities/RCTLog.js
@@ -11,6 +11,8 @@
  */
 'use strict';
 
+var BatchedBridge = require('BatchedBridge');
+
 var invariant = require('invariant');
 
 var levelsMap = {
@@ -39,4 +41,9 @@ class RCTLog {
   }
 }
 
+BatchedBridge.registerCallableModule(
+  'RCTLog',
+  RCTLog
+);
+
 module.exports = RCTLog;
diff --git a/Libraries/Utilities/__tests__/MessageQueue-test.js b/Libraries/Utilities/__tests__/MessageQueue-test.js
index dc0bab73b079..8b9b689fd8bc 100644
--- a/Libraries/Utilities/__tests__/MessageQueue-test.js
+++ b/Libraries/Utilities/__tests__/MessageQueue-test.js
@@ -39,10 +39,11 @@ describe('MessageQueue', () => {
   beforeEach(() => {
     queue = new MessageQueue(
       remoteModulesConfig,
-      localModulesConfig,
-      customRequire,
+      localModulesConfig
     );
 
+    queue.registerCallableModule('one', TestModule);
+
     TestModule.testHook1 = jasmine.createSpy();
     TestModule.testHook2 = jasmine.createSpy();
   });
diff --git a/Libraries/WebSocket/RCTWebSocketExecutor.m b/Libraries/WebSocket/RCTWebSocketExecutor.m
index 6ef4b4999fcd..c5813bc5c250 100644
--- a/Libraries/WebSocket/RCTWebSocketExecutor.m
+++ b/Libraries/WebSocket/RCTWebSocketExecutor.m
@@ -161,13 +161,31 @@ - (void)executeApplicationScript:(NSData *)script sourceURL:(NSURL *)URL onCompl
   }];
 }
 
-- (void)executeJSCall:(NSString *)name method:(NSString *)method arguments:(NSArray *)arguments callback:(RCTJavaScriptCallback)onComplete
+- (void)flushedQueue:(RCTJavaScriptCallback)onComplete
+{
+  [self _executeJSCall:@"flushedQueue" arguments:@[] callback:onComplete];
+}
+
+- (void)callFunctionOnModule:(NSString *)module
+                      method:(NSString *)method
+                   arguments:(NSArray *)args
+                    callback:(RCTJavaScriptCallback)onComplete
+{
+  [self _executeJSCall:@"callFunctionReturnFlushedQueue" arguments:@[module, method, args] callback:onComplete];
+}
+
+- (void)invokeCallbackID:(NSNumber *)cbID
+               arguments:(NSArray *)args
+                callback:(RCTJavaScriptCallback)onComplete
+{
+  [self _executeJSCall:@"invokeCallbackAndReturnFlushedQueue" arguments:@[cbID, args] callback:onComplete];
+}
+
+- (void)_executeJSCall:(NSString *)method arguments:(NSArray *)arguments callback:(RCTJavaScriptCallback)onComplete
 {
   RCTAssert(onComplete != nil, @"callback was missing for exec JS call");
   NSDictionary<NSString *, id> *message = @{
-    @"method": @"executeJSCall",
-    @"moduleName": name,
-    @"moduleMethod": method,
+    @"method": method,
     @"arguments": arguments
   };
   [self sendMessage:message waitForReply:^(NSError *socketError, NSDictionary<NSString *, id> *reply) {
diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index bb6aff8e4fee..696de22ad51b 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -63,7 +63,7 @@ @implementation RCTBatchedBridge
   BOOL _valid;
   BOOL _wasBatchActive;
   __weak id<RCTJavaScriptExecutor> _javaScriptExecutor;
-  NSMutableArray<NSArray *> *_pendingCalls;
+  NSMutableArray<dispatch_block_t> *_pendingCalls;
   NSMutableDictionary<NSString *, RCTModuleData *> *_moduleDataByName;
   NSArray<RCTModuleData *> *_moduleDataByID;
   NSDictionary<NSString *, id<RCTBridgeModule>> *_modulesByName_DEPRECATED;
@@ -436,10 +436,8 @@ - (void)didFinishLoading
 {
   _loading = NO;
   [_javaScriptExecutor executeBlockOnJavaScriptQueue:^{
-    for (NSArray *call in _pendingCalls) {
-      [self _actuallyInvokeAndProcessModule:call[0]
-                                     method:call[1]
-                                  arguments:call[2]];
+    for (dispatch_block_t call in _pendingCalls) {
+      call();
     }
   }];
 }
@@ -579,10 +577,8 @@ - (void)invalidate
 - (void)logMessage:(NSString *)message level:(NSString *)level
 {
   if (RCT_DEBUG) {
-    [_javaScriptExecutor executeJSCall:@"RCTLog"
-                                method:@"logIfNoNativeHook"
-                             arguments:@[level, message]
-                              callback:^(__unused id json, __unused NSError *error) {}];
+    [self enqueueJSCall:@"RCTLog.logIfNoNativeHook"
+                   args:@[level, message]];
   }
 }
 
@@ -593,11 +589,66 @@ - (void)logMessage:(NSString *)message level:(NSString *)level
  */
 - (void)enqueueJSCall:(NSString *)moduleDotMethod args:(NSArray *)args
 {
+  /**
+   * AnyThread
+   */
+
   NSArray<NSString *> *ids = [moduleDotMethod componentsSeparatedByString:@"."];
 
-  [self _invokeAndProcessModule:@"BatchedBridge"
-                         method:@"callFunctionReturnFlushedQueue"
-                      arguments:@[ids[0], ids[1], args ?: @[]]];
+  NSString *module = ids[0];
+  NSString *method = ids[1];
+
+  RCTProfileBeginFlowEvent();
+
+  __weak RCTBatchedBridge *weakSelf = self;
+  [_javaScriptExecutor executeBlockOnJavaScriptQueue:^{
+    RCTProfileEndFlowEvent();
+
+    RCTBatchedBridge *strongSelf = weakSelf;
+    if (!strongSelf || !strongSelf.valid) {
+      return;
+    }
+
+    if (strongSelf.loading) {
+      dispatch_block_t pendingCall = ^{
+        [weakSelf _actuallyInvokeAndProcessModule:module method:method arguments:args ?: @[]];
+      };
+      [strongSelf->_pendingCalls addObject:pendingCall];
+    } else {
+      [strongSelf _actuallyInvokeAndProcessModule:module method:method arguments:args ?: @[]];
+    }
+  }];
+}
+
+/**
+ * Called by RCTModuleMethod from any thread.
+ */
+- (void)enqueueCallback:(NSNumber *)cbID args:(NSArray *)args
+{
+  /**
+   * AnyThread
+   */
+
+  RCTProfileBeginFlowEvent();
+
+  __weak RCTBatchedBridge *weakSelf = self;
+  [_javaScriptExecutor executeBlockOnJavaScriptQueue:^{
+    RCTProfileEndFlowEvent();
+
+    RCTBatchedBridge *strongSelf = weakSelf;
+    if (!strongSelf || !strongSelf.valid) {
+      return;
+    }
+
+    if (strongSelf.loading) {
+      dispatch_block_t pendingCall = ^{
+        [weakSelf _actuallyInvokeCallback:cbID arguments:args ?: @[]];
+      };
+      [strongSelf->_pendingCalls addObject:pendingCall];
+    } else {
+      [strongSelf _actuallyInvokeCallback:cbID arguments:args];
+    }
+  }];
 }
 
 /**
@@ -608,9 +659,9 @@ - (void)_immediatelyCallTimer:(NSNumber *)timer
   RCTAssertJSThread();
 
   dispatch_block_t block = ^{
-    [self _actuallyInvokeAndProcessModule:@"BatchedBridge"
-                                   method:@"callFunctionReturnFlushedQueue"
-                                arguments:@[@"JSTimersExecution", @"callTimers", @[@[timer]]]];
+    [self _actuallyInvokeAndProcessModule:@"JSTimersExecution"
+                                   method:@"callTimers"
+                                arguments:@[@[timer]]];
   };
 
   if ([_javaScriptExecutor respondsToSelector:@selector(executeAsyncBlockOnJavaScriptQueue:)]) {
@@ -637,10 +688,7 @@ - (void)enqueueApplicationScript:(NSData *)script
     }
 
     RCT_PROFILE_BEGIN_EVENT(0, @"FetchApplicationScriptCallbacks", nil);
-    [_javaScriptExecutor executeJSCall:@"BatchedBridge"
-                                method:@"flushedQueue"
-                             arguments:@[]
-                              callback:^(id json, NSError *error)
+    [_javaScriptExecutor flushedQueue:^(id json, NSError *error)
      {
        RCT_PROFILE_END_EVENT(0, @"js_call,init", @{
          @"json": RCTNullIfNil(json),
@@ -656,38 +704,34 @@ - (void)enqueueApplicationScript:(NSData *)script
 
 #pragma mark - Payload Generation
 
-/**
- * Called by enqueueJSCall from any thread, or from _immediatelyCallTimer,
- * on the JS thread, but only in non-batched mode.
- */
-- (void)_invokeAndProcessModule:(NSString *)module method:(NSString *)method arguments:(NSArray *)args
+- (void)_actuallyInvokeAndProcessModule:(NSString *)module
+                                 method:(NSString *)method
+                              arguments:(NSArray *)args
 {
-  /**
-   * AnyThread
-   */
+  RCTAssertJSThread();
 
-  RCTProfileBeginFlowEvent();
+  [[NSNotificationCenter defaultCenter] postNotificationName:RCTEnqueueNotification object:nil userInfo:nil];
 
-  __weak RCTBatchedBridge *weakSelf = self;
-  [_javaScriptExecutor executeBlockOnJavaScriptQueue:^{
-    RCTProfileEndFlowEvent();
+  RCTJavaScriptCallback processResponse = ^(id json, NSError *error) {
+    if (error) {
+      RCTFatal(error);
+    }
 
-    RCTBatchedBridge *strongSelf = weakSelf;
-    if (!strongSelf || !strongSelf.valid) {
+    if (!self.isValid) {
       return;
     }
+    [[NSNotificationCenter defaultCenter] postNotificationName:RCTDequeueNotification object:nil userInfo:nil];
+    [self handleBuffer:json batchEnded:YES];
+  };
 
-    if (strongSelf.loading) {
-      [strongSelf->_pendingCalls addObject:@[module, method, args]];
-    } else {
-      [strongSelf _actuallyInvokeAndProcessModule:module method:method arguments:args];
-    }
-  }];
+  [_javaScriptExecutor callFunctionOnModule:module
+                                     method:method
+                                  arguments:args
+                                   callback:processResponse];
 }
 
-- (void)_actuallyInvokeAndProcessModule:(NSString *)module
-                                 method:(NSString *)method
-                              arguments:(NSArray *)args
+- (void)_actuallyInvokeCallback:(NSNumber *)cbID
+                      arguments:(NSArray *)args
 {
   RCTAssertJSThread();
 
@@ -705,10 +749,9 @@ - (void)_actuallyInvokeAndProcessModule:(NSString *)module
     [self handleBuffer:json batchEnded:YES];
   };
 
-  [_javaScriptExecutor executeJSCall:module
-                              method:method
-                           arguments:args
-                            callback:processResponse];
+  [_javaScriptExecutor invokeCallbackID:cbID
+                              arguments:args
+                               callback:processResponse];
 }
 
 #pragma mark - Payload Processing
diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m
index 013a541368c5..3e4a1bc5c0d1 100644
--- a/React/Base/RCTBridge.m
+++ b/React/Base/RCTBridge.m
@@ -310,9 +310,11 @@ - (void)enqueueJSCall:(NSString *)moduleDotMethod args:(NSArray *)args
   [self.batchedBridge enqueueJSCall:moduleDotMethod args:args];
 }
 
-RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(__unused NSString *)module
-                      method:(__unused NSString *)method
-                      arguments:(__unused NSArray *)args);
+- (void)enqueueCallback:(NSNumber *)cbID args:(NSArray *)args
+{
+  [self.batchedBridge enqueueCallback:cbID args:args];
+}
+
 @end
 
 @implementation RCTBridge(Deprecated)
diff --git a/React/Base/RCTJavaScriptExecutor.h b/React/Base/RCTJavaScriptExecutor.h
index 5506ddfa3187..832b78e3cdda 100644
--- a/React/Base/RCTJavaScriptExecutor.h
+++ b/React/Base/RCTJavaScriptExecutor.h
@@ -35,13 +35,29 @@ typedef void (^RCTJavaScriptCallback)(id json, NSError *error);
 @property (nonatomic, readonly, getter=isValid) BOOL valid;
 
 /**
- * Executes given method with arguments on JS thread and calls the given callback
- * with JSValue and JSContext as a result of the JS module call.
+ * Executes BatchedBridge.flushedQueue on JS thread and calls the given callback
+ * with JSValue, containing the next queue, and JSContext.
  */
-- (void)executeJSCall:(NSString *)name
-               method:(NSString *)method
-            arguments:(NSArray *)arguments
-             callback:(RCTJavaScriptCallback)onComplete;
+- (void)flushedQueue:(RCTJavaScriptCallback)onComplete;
+
+/**
+ * Executes BatchedBridge.callFunctionReturnFlushedQueue with the module name,
+ * method name and optional additional arguments on the JS thread and calls the
+ * given callback with JSValue, containing the next queue, and JSContext.
+ */
+- (void)callFunctionOnModule:(NSString *)module
+                      method:(NSString *)method
+                   arguments:(NSArray *)args
+                    callback:(RCTJavaScriptCallback)onComplete;
+
+/**
+ * Executes BatchedBridge.invokeCallbackAndReturnFlushedQueue with the cbID,
+ * and optional additional arguments on the JS thread and calls the
+ * given callback with JSValue, containing the next queue, and JSContext.
+ */
+- (void)invokeCallbackID:(NSNumber *)cbID
+               arguments:(NSArray *)args
+                callback:(RCTJavaScriptCallback)onComplete;
 
 /**
  * Runs an application script, and notifies of the script load being complete via `onComplete`.
diff --git a/React/Base/RCTModuleMethod.m b/React/Base/RCTModuleMethod.m
index c35017c982fd..0182fe93d858 100644
--- a/React/Base/RCTModuleMethod.m
+++ b/React/Base/RCTModuleMethod.m
@@ -37,9 +37,11 @@ - (instancetype)initWithType:(NSString *)type
 
 @interface RCTBridge (RCTModuleMethod)
 
-- (void)_invokeAndProcessModule:(NSString *)module
-                         method:(NSString *)method
-                      arguments:(NSArray *)args;
+/**
+ * This method is used to invoke a callback that was registered in the
+ * JavaScript application context. Safe to call from any thread.
+ */
+- (void)enqueueCallback:(NSNumber *)cbID args:(NSArray *)args;
 
 @end
 
@@ -191,9 +193,7 @@ - (void)processMethodSignature
       }
 
       RCT_BLOCK_ARGUMENT(^(NSArray *args) {
-        [bridge _invokeAndProcessModule:@"BatchedBridge"
-                                 method:@"invokeCallbackAndReturnFlushedQueue"
-                              arguments:@[json, args]];
+        [bridge enqueueCallback:json args:args];
       });
     )
   };
@@ -290,9 +290,7 @@ - (void)processMethodSignature
         }
 
         RCT_BLOCK_ARGUMENT(^(NSError *error) {
-          [bridge _invokeAndProcessModule:@"BatchedBridge"
-                                     method:@"invokeCallbackAndReturnFlushedQueue"
-                                arguments:@[json, @[RCTJSErrorFromNSError(error)]]];
+          [bridge enqueueCallback:json args:@[RCTJSErrorFromNSError(error)]];
         });
       )
     } else if ([typeName isEqualToString:@"RCTPromiseResolveBlock"]) {
@@ -306,9 +304,7 @@ - (void)processMethodSignature
         }
 
         RCT_BLOCK_ARGUMENT(^(id result) {
-          [bridge _invokeAndProcessModule:@"BatchedBridge"
-                                   method:@"invokeCallbackAndReturnFlushedQueue"
-                                arguments:@[json, result ? @[result] : @[]]];
+          [bridge enqueueCallback:json args:result ? @[result] : @[]];
         });
       )
     } else if ([typeName isEqualToString:@"RCTPromiseRejectBlock"]) {
@@ -323,9 +319,7 @@ - (void)processMethodSignature
 
         RCT_BLOCK_ARGUMENT(^(NSError *error) {
           NSDictionary *errorJSON = RCTJSErrorFromNSError(error);
-          [bridge _invokeAndProcessModule:@"BatchedBridge"
-                                   method:@"invokeCallbackAndReturnFlushedQueue"
-                                arguments:@[json, @[errorJSON]]];
+          [bridge enqueueCallback:json args:@[errorJSON]];
         });
       )
     } else {
diff --git a/React/Base/RCTRootView.m b/React/Base/RCTRootView.m
index 6be45621c43e..454e2e317768 100644
--- a/React/Base/RCTRootView.m
+++ b/React/Base/RCTRootView.m
@@ -350,7 +350,7 @@ - (void)invalidate
   if (self.userInteractionEnabled) {
     self.userInteractionEnabled = NO;
     [(RCTRootView *)self.superview contentViewInvalidated];
-    [_bridge enqueueJSCall:@"ReactNative.unmountComponentAtNodeAndRemoveContainer"
+    [_bridge enqueueJSCall:@"AppRegistry.unmountApplicationComponentAtRootTag"
                       args:@[self.reactTag]];
   }
 }
diff --git a/React/Executors/RCTContextExecutor.m b/React/Executors/RCTContextExecutor.m
index b666690f165d..42b0a37e14f8 100644
--- a/React/Executors/RCTContextExecutor.m
+++ b/React/Executors/RCTContextExecutor.m
@@ -394,6 +394,7 @@ - (void)toggleProfilingFlag:(NSNotification *)notification
 {
   [self executeBlockOnJavaScriptQueue:^{
     BOOL enabled = [notification.name isEqualToString:RCTProfileDidStartProfiling];
+    // TODO: Don't use require, go through the normal execution modes instead. #9317773
     NSString *script = [NSString stringWithFormat:@"var p = require('BridgeProfiling') || {}; p.setEnabled && p.setEnabled(%@)", enabled ? @"true" : @"false"];
     JSStringRef scriptJSRef = JSStringCreateWithUTF8CString(script.UTF8String);
     JSEvaluateScript(_context.ctx, scriptJSRef, NULL, NULL, 0, NULL);
@@ -435,10 +436,32 @@ - (void)dealloc
   [self invalidate];
 }
 
-- (void)executeJSCall:(NSString *)name
-               method:(NSString *)method
-            arguments:(NSArray *)arguments
-             callback:(RCTJavaScriptCallback)onComplete
+- (void)flushedQueue:(RCTJavaScriptCallback)onComplete
+{
+  // TODO: Make this function handle first class instead of dynamically dispatching it. #9317773
+  [self _executeJSCall:@"flushedQueue" arguments:@[] callback:onComplete];
+}
+
+- (void)callFunctionOnModule:(NSString *)module
+                      method:(NSString *)method
+                   arguments:(NSArray *)args
+                    callback:(RCTJavaScriptCallback)onComplete
+{
+  // TODO: Make this function handle first class instead of dynamically dispatching it. #9317773
+  [self _executeJSCall:@"callFunctionReturnFlushedQueue" arguments:@[module, method, args] callback:onComplete];
+}
+
+- (void)invokeCallbackID:(NSNumber *)cbID
+               arguments:(NSArray *)args
+                callback:(RCTJavaScriptCallback)onComplete
+{
+  // TODO: Make this function handle first class instead of dynamically dispatching it. #9317773
+  [self _executeJSCall:@"invokeCallbackAndReturnFlushedQueue" arguments:@[cbID, args] callback:onComplete];
+}
+
+- (void)_executeJSCall:(NSString *)method
+             arguments:(NSArray *)arguments
+              callback:(RCTJavaScriptCallback)onComplete
 {
   RCTAssert(onComplete != nil, @"onComplete block should not be nil");
   __weak RCTContextExecutor *weakSelf = self;
@@ -460,58 +483,49 @@ - (void)executeJSCall:(NSString *)name
     JSGlobalContextRef contextJSRef = JSContextGetGlobalContext(strongSelf->_context.ctx);
     JSObjectRef globalObjectJSRef = JSContextGetGlobalObject(strongSelf->_context.ctx);
 
-    // get require
-    JSStringRef requireNameJSStringRef = JSStringCreateWithUTF8CString("require");
-    JSValueRef requireJSRef = JSObjectGetProperty(contextJSRef, globalObjectJSRef, requireNameJSStringRef, &errorJSRef);
-    JSStringRelease(requireNameJSStringRef);
+    // get the BatchedBridge object
+    JSStringRef moduleNameJSStringRef = JSStringCreateWithUTF8CString("__fbBatchedBridge");
+    JSValueRef moduleJSRef = JSObjectGetProperty(contextJSRef, globalObjectJSRef, moduleNameJSStringRef, &errorJSRef);
+    JSStringRelease(moduleNameJSStringRef);
 
-    if (requireJSRef != NULL && !JSValueIsUndefined(contextJSRef, requireJSRef) && errorJSRef == NULL) {
+    if (moduleJSRef != NULL && errorJSRef == NULL && !JSValueIsUndefined(contextJSRef, moduleJSRef)) {
 
-      // get module
-      JSStringRef moduleNameJSStringRef = JSStringCreateWithCFString((__bridge CFStringRef)name);
-      JSValueRef moduleNameJSRef = JSValueMakeString(contextJSRef, moduleNameJSStringRef);
-      JSValueRef moduleJSRef = JSObjectCallAsFunction(contextJSRef, (JSObjectRef)requireJSRef, NULL, 1, (const JSValueRef *)&moduleNameJSRef, &errorJSRef);
-      JSStringRelease(moduleNameJSStringRef);
+      // get method
+      JSStringRef methodNameJSStringRef = JSStringCreateWithCFString((__bridge CFStringRef)method);
+      JSValueRef methodJSRef = JSObjectGetProperty(contextJSRef, (JSObjectRef)moduleJSRef, methodNameJSStringRef, &errorJSRef);
+      JSStringRelease(methodNameJSStringRef);
 
-      if (moduleJSRef != NULL && errorJSRef == NULL && !JSValueIsUndefined(contextJSRef, moduleJSRef)) {
+      if (methodJSRef != NULL && errorJSRef == NULL) {
 
-        // get method
-        JSStringRef methodNameJSStringRef = JSStringCreateWithCFString((__bridge CFStringRef)method);
-        JSValueRef methodJSRef = JSObjectGetProperty(contextJSRef, (JSObjectRef)moduleJSRef, methodNameJSStringRef, &errorJSRef);
-        JSStringRelease(methodNameJSStringRef);
+        // direct method invoke with no arguments
+        if (arguments.count == 0) {
+          resultJSRef = JSObjectCallAsFunction(contextJSRef, (JSObjectRef)methodJSRef, (JSObjectRef)moduleJSRef, 0, NULL, &errorJSRef);
+        }
 
-        if (methodJSRef != NULL && errorJSRef == NULL) {
+        // direct method invoke with 1 argument
+        else if(arguments.count == 1) {
+          JSStringRef argsJSStringRef = JSStringCreateWithCFString((__bridge CFStringRef)argsString);
+          JSValueRef argsJSRef = JSValueMakeFromJSONString(contextJSRef, argsJSStringRef);
+          resultJSRef = JSObjectCallAsFunction(contextJSRef, (JSObjectRef)methodJSRef, (JSObjectRef)moduleJSRef, 1, &argsJSRef, &errorJSRef);
+          JSStringRelease(argsJSStringRef);
 
-          // direct method invoke with no arguments
-          if (arguments.count == 0) {
-            resultJSRef = JSObjectCallAsFunction(contextJSRef, (JSObjectRef)methodJSRef, (JSObjectRef)moduleJSRef, 0, NULL, &errorJSRef);
-          }
+        } else {
+          // apply invoke with array of arguments
+          JSStringRef applyNameJSStringRef = JSStringCreateWithUTF8CString("apply");
+          JSValueRef applyJSRef = JSObjectGetProperty(contextJSRef, (JSObjectRef)methodJSRef, applyNameJSStringRef, &errorJSRef);
+          JSStringRelease(applyNameJSStringRef);
 
-          // direct method invoke with 1 argument
-          else if(arguments.count == 1) {
+          if (applyJSRef != NULL && errorJSRef == NULL) {
+            // invoke apply
             JSStringRef argsJSStringRef = JSStringCreateWithCFString((__bridge CFStringRef)argsString);
             JSValueRef argsJSRef = JSValueMakeFromJSONString(contextJSRef, argsJSStringRef);
-            resultJSRef = JSObjectCallAsFunction(contextJSRef, (JSObjectRef)methodJSRef, (JSObjectRef)moduleJSRef, 1, &argsJSRef, &errorJSRef);
-            JSStringRelease(argsJSStringRef);
-
-          } else {
-            // apply invoke with array of arguments
-            JSStringRef applyNameJSStringRef = JSStringCreateWithUTF8CString("apply");
-            JSValueRef applyJSRef = JSObjectGetProperty(contextJSRef, (JSObjectRef)methodJSRef, applyNameJSStringRef, &errorJSRef);
-            JSStringRelease(applyNameJSStringRef);
 
-            if (applyJSRef != NULL && errorJSRef == NULL) {
-              // invoke apply
-              JSStringRef argsJSStringRef = JSStringCreateWithCFString((__bridge CFStringRef)argsString);
-              JSValueRef argsJSRef = JSValueMakeFromJSONString(contextJSRef, argsJSStringRef);
+            JSValueRef args[2];
+            args[0] = JSValueMakeNull(contextJSRef);
+            args[1] = argsJSRef;
 
-              JSValueRef args[2];
-              args[0] = JSValueMakeNull(contextJSRef);
-              args[1] = argsJSRef;
-
-              resultJSRef = JSObjectCallAsFunction(contextJSRef, (JSObjectRef)applyJSRef, (JSObjectRef)methodJSRef, 2, args, &errorJSRef);
-              JSStringRelease(argsJSStringRef);
-            }
+            resultJSRef = JSObjectCallAsFunction(contextJSRef, (JSObjectRef)applyJSRef, (JSObjectRef)methodJSRef, 2, args, &errorJSRef);
+            JSStringRelease(argsJSStringRef);
           }
         }
       }
@@ -539,7 +553,7 @@ - (void)executeJSCall:(NSString *)name
     }
 
     onComplete(objcValue, nil);
-  }), 0, @"js_call", (@{@"module":name, @"method": method, @"args": arguments}))];
+  }), 0, @"js_call", (@{@"method": method, @"args": arguments}))];
 }
 
 - (void)executeApplicationScript:(NSData *)script
diff --git a/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java b/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java
index b770b3b756d9..28bc76f82406 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java
@@ -27,7 +27,6 @@
 import com.facebook.react.modules.debug.SourceCodeModule;
 import com.facebook.react.modules.systeminfo.AndroidInfoModule;
 import com.facebook.react.uimanager.AppRegistry;
-import com.facebook.react.uimanager.ReactNative;
 import com.facebook.react.uimanager.UIImplementationProvider;
 import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.ViewManager;
@@ -97,7 +96,6 @@ public List<Class<? extends JavaScriptModule>> createJSModules() {
         RCTNativeAppEventEmitter.class,
         AppRegistry.class,
         BridgeProfiling.class,
-        ReactNative.class,
         DebugComponentOwnershipModule.RCTDebugComponentOwnership.class);
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index 1169034ee116..7953691c0ad2 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -52,7 +52,6 @@
 import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
 import com.facebook.react.modules.core.DeviceEventManagerModule;
 import com.facebook.react.uimanager.AppRegistry;
-import com.facebook.react.uimanager.ReactNative;
 import com.facebook.react.uimanager.UIImplementationProvider;
 import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.ViewManager;
@@ -581,8 +580,8 @@ private void detachViewFromInstance(
       ReactRootView rootView,
       CatalystInstance catalystInstance) {
     UiThreadUtil.assertOnUiThread();
-    catalystInstance.getJSModule(ReactNative.class)
-        .unmountComponentAtNodeAndRemoveContainer(rootView.getId());
+    catalystInstance.getJSModule(AppRegistry.class)
+        .unmountApplicationComponentAtRootTag(rootView.getId());
   }
 
   private void tearDownReactContext(ReactContext reactContext) {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSDebuggerWebSocketClient.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSDebuggerWebSocketClient.java
index 8940ffc0860d..13c99c043d43 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSDebuggerWebSocketClient.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSDebuggerWebSocketClient.java
@@ -126,7 +126,6 @@ public void executeApplicationScript(
   }
 
   public void executeJSCall(
-      String moduleName,
       String methodName,
       String jsonArgsArray,
       JSDebuggerCallback callback) {
@@ -136,9 +135,7 @@ public void executeJSCall(
 
     try {
       JsonGenerator jg = startMessageObject(requestID);
-      jg.writeStringField("method","executeJSCall");
-      jg.writeStringField("moduleName", moduleName);
-      jg.writeStringField("moduleMethod", methodName);
+      jg.writeStringField("method", methodName);
       jg.writeFieldName("arguments");
       jg.writeRawValue(jsonArgsArray);
       sendMessage(requestID, endMessageObject(jg));
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaJSExecutor.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaJSExecutor.java
index 76b8a1cb5275..3c8eb4574b6b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaJSExecutor.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaJSExecutor.java
@@ -40,13 +40,12 @@ public ProxyExecutorException(Throwable cause) {
 
   /**
    * Execute javascript method within js context
-   * @param modulename name of the common-js like module to execute the method from
    * @param methodName name of the method to be executed
    * @param jsonArgsArray json encoded array of arguments provided for the method call
    * @return json encoded value returned from the method call
    */
   @DoNotStrip
-  String executeJSCall(String modulename, String methodName, String jsonArgsArray)
+  String executeJSCall(String methodName, String jsonArgsArray)
       throws ProxyExecutorException;
 
   @DoNotStrip
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/WebsocketJavaScriptExecutor.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/WebsocketJavaScriptExecutor.java
index e044ca8cd65f..0fba2b0a3bbf 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/WebsocketJavaScriptExecutor.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/WebsocketJavaScriptExecutor.java
@@ -160,11 +160,10 @@ public void executeApplicationScript(String script, String sourceURL)
   }
 
   @Override
-  public @Nullable String executeJSCall(String moduleName, String methodName, String jsonArgsArray)
+  public @Nullable String executeJSCall(String methodName, String jsonArgsArray)
       throws ProxyExecutorException {
     JSExecutorCallbackFuture callback = new JSExecutorCallbackFuture();
     Assertions.assertNotNull(mWebSocketClient).executeJSCall(
-        moduleName,
         methodName,
         jsonArgsArray,
         callback);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/AppRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/AppRegistry.java
index f0cd49855e84..d9a387b7f0db 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/AppRegistry.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/AppRegistry.java
@@ -18,4 +18,6 @@
 public interface AppRegistry extends JavaScriptModule {
 
   void runApplication(String appKey, WritableMap appParameters);
+  void unmountApplicationComponentAtRootTag(int rootNodeTag);
+
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactNative.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactNative.java
deleted file mode 100644
index 2d99e79f5698..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactNative.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * 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.
- */
-
-package com.facebook.react.uimanager;
-
-import com.facebook.react.bridge.JavaScriptModule;
-
-/**
- * JS module interface - used by UIManager to communicate with main React JS module methods
- */
-public interface ReactNative extends JavaScriptModule {
-  void unmountComponentAtNodeAndRemoveContainer(int rootNodeTag);
-}
diff --git a/ReactAndroid/src/main/jni/react/Bridge.cpp b/ReactAndroid/src/main/jni/react/Bridge.cpp
index 84fb525b00b5..90a50d098c18 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.cpp
+++ b/ReactAndroid/src/main/jni/react/Bridge.cpp
@@ -27,11 +27,18 @@ class JSThreadState {
     m_jsExecutor->executeApplicationScript(script, sourceURL);
   }
 
-  void executeJSCall(
-      const std::string& moduleName,
-      const std::string& methodName,
-      const std::vector<folly::dynamic>& arguments) {
-    auto returnedJSON = m_jsExecutor->executeJSCall(moduleName, methodName, arguments);
+  void flush() {
+    auto returnedJSON = m_jsExecutor->flush();
+    m_callback(parseMethodCalls(returnedJSON), true /* = isEndOfBatch */);
+  }
+
+  void callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) {
+    auto returnedJSON = m_jsExecutor->callFunction(moduleId, methodId, arguments);
+    m_callback(parseMethodCalls(returnedJSON), true /* = isEndOfBatch */);
+  }
+
+  void invokeCallback(const double callbackId, const folly::dynamic& arguments) {
+    auto returnedJSON = m_jsExecutor->invokeCallback(callbackId, arguments);
     m_callback(parseMethodCalls(returnedJSON), true /* = isEndOfBatch */);
   }
 
@@ -88,17 +95,31 @@ void Bridge::executeApplicationScript(const std::string& script, const std::stri
   m_threadState->executeApplicationScript(script, sourceURL);
 }
 
-void Bridge::executeJSCall(
-    const std::string& script,
-    const std::string& sourceURL,
-    const std::vector<folly::dynamic>& arguments) {
+void Bridge::flush() {
+  if (*m_destroyed) {
+    return;
+  }
+  m_threadState->flush();
+}
+
+void Bridge::callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) {
+  if (*m_destroyed) {
+    return;
+  }
+  #ifdef WITH_FBSYSTRACE
+  FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "Bridge.callFunction");
+  #endif
+  m_threadState->callFunction(moduleId, methodId, arguments);
+}
+
+void Bridge::invokeCallback(const double callbackId, const folly::dynamic& arguments) {
   if (*m_destroyed) {
     return;
   }
   #ifdef WITH_FBSYSTRACE
-  FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "Bridge.executeJSCall");
+  FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "Bridge.invokeCallback");
   #endif
-  m_threadState->executeJSCall(script, sourceURL, arguments);
+  m_threadState->invokeCallback(callbackId, arguments);
 }
 
 void Bridge::setGlobalVariable(const std::string& propName, const std::string& jsonValue) {
diff --git a/ReactAndroid/src/main/jni/react/Bridge.h b/ReactAndroid/src/main/jni/react/Bridge.h
index 23843de42940..1d0f159458be 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.h
+++ b/ReactAndroid/src/main/jni/react/Bridge.h
@@ -29,10 +29,22 @@ class Bridge : public Countable {
   Bridge(const RefPtr<JSExecutorFactory>& jsExecutorFactory, Callback callback);
   virtual ~Bridge();
 
-  void executeJSCall(
-    const std::string& moduleName,
-    const std::string& methodName,
-    const std::vector<folly::dynamic>& values);
+  /**
+   * Flush get the next queue of changes.
+   */
+  void flush();
+
+  /**
+   * Executes a function with the module ID and method ID and any additional
+   * arguments in JS.
+   */
+  void callFunction(const double moduleId, const double methodId, const folly::dynamic& args);
+
+  /**
+   * Invokes a callback with the cbID, and optional additional arguments in JS.
+   */
+  void invokeCallback(const double callbackId, const folly::dynamic& args);
+
   void executeApplicationScript(const std::string& script, const std::string& sourceURL);
   void setGlobalVariable(const std::string& propName, const std::string& jsonValue);
   bool supportsProfiling();
diff --git a/ReactAndroid/src/main/jni/react/Executor.h b/ReactAndroid/src/main/jni/react/Executor.h
index 6a59bff420a0..bef2d0724f39 100644
--- a/ReactAndroid/src/main/jni/react/Executor.h
+++ b/ReactAndroid/src/main/jni/react/Executor.h
@@ -28,13 +28,31 @@ class JSExecutorFactory : public Countable {
 
 class JSExecutor {
 public:
+  /**
+   * Execute an application script bundle in the JS context.
+   */
   virtual void executeApplicationScript(
     const std::string& script,
     const std::string& sourceURL) = 0;
-  virtual std::string executeJSCall(
-    const std::string& moduleName,
-    const std::string& methodName,
-    const std::vector<folly::dynamic>& arguments) = 0;
+
+  /**
+   * Executes BatchedBridge.flushedQueue in JS to get the next queue of changes.
+   */
+  virtual std::string flush() = 0;
+
+  /**
+   * Executes BatchedBridge.callFunctionReturnFlushedQueue with the module ID,
+   * method ID and optional additional arguments in JS, and returns the next
+   * queue.
+   */
+  virtual std::string callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) = 0;
+
+  /**
+   * Executes BatchedBridge.invokeCallbackAndReturnFlushedQueue with the cbID,
+   * and optional additional arguments in JS and returns the next queue.
+   */
+  virtual std::string invokeCallback(const double callbackId, const folly::dynamic& arguments) = 0;
+
   virtual void setGlobalVariable(
     const std::string& propName,
     const std::string& jsonValue) = 0;
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index 5f23c2b880df..de9dffc05eb2 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -80,6 +80,26 @@ static JSValueRef evaluateScriptWithJSC(
   return result;
 }
 
+static std::string executeJSCallWithJSC(
+    JSGlobalContextRef ctx,
+    const std::string& methodName,
+    const std::vector<folly::dynamic>& arguments) {
+  #ifdef WITH_FBSYSTRACE
+  FbSystraceSection s(
+      TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor.executeJSCall",
+      "method", methodName);
+  #endif
+
+  // Evaluate script with JSC
+  folly::dynamic jsonArgs(arguments.begin(), arguments.end());
+  auto js = folly::to<folly::fbstring>(
+      "__fbBatchedBridge.", methodName, ".apply(null, ",
+      folly::toJson(jsonArgs), ")");
+  auto result = evaluateScriptWithJSC(ctx, String(js.c_str()), nullptr);
+  JSValueProtect(ctx, result);
+  return Value(ctx, result).toJSONString();
+}
+
 std::unique_ptr<JSExecutor> JSCExecutorFactory::createJSExecutor(FlushImmediateCallback cb) {
   return std::unique_ptr<JSExecutor>(new JSCExecutor(cb));
 }
@@ -130,25 +150,28 @@ void JSCExecutor::executeApplicationScript(
   evaluateScriptWithJSC(m_context, jsScript, jsSourceURL);
 }
 
-std::string JSCExecutor::executeJSCall(
-    const std::string& moduleName,
-    const std::string& methodName,
-    const std::vector<folly::dynamic>& arguments) {
-  #ifdef WITH_FBSYSTRACE
-  FbSystraceSection s(
-      TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor.executeJSCall",
-      "module", moduleName,
-      "method", methodName);
-  #endif
+std::string JSCExecutor::flush() {
+  // TODO: Make this a first class function instead of evaling. #9317773
+  return executeJSCallWithJSC(m_context, "flushedQueue", std::vector<folly::dynamic>());
+}
 
-  // Evaluate script with JSC
-  folly::dynamic jsonArgs(arguments.begin(), arguments.end());
-  auto js = folly::to<folly::fbstring>(
-      "require('", moduleName, "').", methodName, ".apply(null, ",
-      folly::toJson(jsonArgs), ")");
-  auto result = evaluateScriptWithJSC(m_context, String(js.c_str()), nullptr);
-  JSValueProtect(m_context, result);
-  return Value(m_context, result).toJSONString();
+std::string JSCExecutor::callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) {
+  // TODO:  Make this a first class function instead of evaling. #9317773
+  std::vector<folly::dynamic> call{
+    (double) moduleId,
+    (double) methodId,
+    std::move(arguments),
+  };
+  return executeJSCallWithJSC(m_context, "callFunctionReturnFlushedQueue", std::move(call));
+}
+
+std::string JSCExecutor::invokeCallback(const double callbackId, const folly::dynamic& arguments) {
+  // TODO: Make this a first class function instead of evaling. #9317773
+  std::vector<folly::dynamic> call{
+    (double) callbackId,
+    std::move(arguments)
+  };
+  return executeJSCallWithJSC(m_context, "invokeCallbackAndReturnFlushedQueue", std::move(call));
 }
 
 void JSCExecutor::setGlobalVariable(const std::string& propName, const std::string& jsonValue) {
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.h b/ReactAndroid/src/main/jni/react/JSCExecutor.h
index a319a9036574..5074247356b4 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.h
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.h
@@ -18,13 +18,18 @@ class JSCExecutor : public JSExecutor {
 public:
   explicit JSCExecutor(FlushImmediateCallback flushImmediateCallback);
   ~JSCExecutor() override;
+
   virtual void executeApplicationScript(
     const std::string& script,
     const std::string& sourceURL) override;
-  virtual std::string executeJSCall(
-    const std::string& moduleName,
-    const std::string& methodName,
-    const std::vector<folly::dynamic>& arguments) override;
+  virtual std::string flush() override;
+  virtual std::string callFunction(
+    const double moduleId,
+    const double methodId,
+    const folly::dynamic& arguments) override;
+  virtual std::string invokeCallback(
+    const double callbackId,
+    const folly::dynamic& arguments) override;
   virtual void setGlobalVariable(
     const std::string& propName,
     const std::string& jsonValue) override;
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 610cd160d4ab..8867b0c9e0d8 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -628,7 +628,7 @@ static void executeApplicationScript(
   try {
     // Execute the application script and collect/dispatch any native calls that might have occured
     bridge->executeApplicationScript(script, sourceUri);
-    bridge->executeJSCall("BatchedBridge", "flushedQueue", std::vector<folly::dynamic>());
+    bridge->flush();
   } catch (...) {
     translatePendingCppExceptionToJavaException();
   }
@@ -682,13 +682,12 @@ static void callFunction(JNIEnv* env, jobject obj, jint moduleId, jint methodId,
                          NativeArray::jhybridobject args) {
   auto bridge = extractRefPtr<Bridge>(env, obj);
   auto arguments = cthis(wrap_alias(args));
-  std::vector<folly::dynamic> call{
-    (double) moduleId,
-    (double) methodId,
-    std::move(arguments->array),
-  };
   try {
-    bridge->executeJSCall("BatchedBridge", "callFunctionReturnFlushedQueue", std::move(call));
+    bridge->callFunction(
+      (double) moduleId,
+      (double) methodId,
+      std::move(arguments->array)
+    );
   } catch (...) {
     translatePendingCppExceptionToJavaException();
   }
@@ -698,12 +697,11 @@ static void invokeCallback(JNIEnv* env, jobject obj, jint callbackId,
                            NativeArray::jhybridobject args) {
   auto bridge = extractRefPtr<Bridge>(env, obj);
   auto arguments = cthis(wrap_alias(args));
-  std::vector<folly::dynamic> call{
-    (double) callbackId,
-    std::move(arguments->array)
-  };
   try {
-    bridge->executeJSCall("BatchedBridge", "invokeCallbackAndReturnFlushedQueue", std::move(call));
+    bridge->invokeCallback(
+      (double) callbackId,
+      std::move(arguments->array)
+    );
   } catch (...) {
     translatePendingCppExceptionToJavaException();
   }
diff --git a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
index ab86a669854f..ad4e245d188b 100644
--- a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
@@ -12,6 +12,20 @@ namespace react {
 
 const auto EXECUTOR_BASECLASS = "com/facebook/react/bridge/JavaJSExecutor";
 
+static std::string executeJSCallWithProxy(
+    jobject executor,
+    const std::string& methodName,
+    const std::vector<folly::dynamic>& arguments) {
+  static auto executeJSCall =
+    jni::findClassStatic(EXECUTOR_BASECLASS)->getMethod<jstring(jstring, jstring)>("executeJSCall");
+
+  auto result = executeJSCall(
+    executor,
+    jni::make_jstring(methodName).get(),
+    jni::make_jstring(folly::toJson(arguments).c_str()).get());
+  return result->toString();
+}
+
 std::unique_ptr<JSExecutor> ProxyExecutorOneTimeFactory::createJSExecutor(FlushImmediateCallback ignoredCallback) {
   FBASSERTMSGF(
     m_executor.get() != nullptr,
@@ -36,19 +50,26 @@ void ProxyExecutor::executeApplicationScript(
     jni::make_jstring(sourceURL).get());
 }
 
-std::string ProxyExecutor::executeJSCall(
-    const std::string& moduleName,
-    const std::string& methodName,
-    const std::vector<folly::dynamic>& arguments) {
-  static auto executeJSCall =
-    jni::findClassStatic(EXECUTOR_BASECLASS)->getMethod<jstring(jstring, jstring, jstring)>("executeJSCall");
 
-  auto result = executeJSCall(
-    m_executor.get(),
-    jni::make_jstring(moduleName).get(),
-    jni::make_jstring(methodName).get(),
-    jni::make_jstring(folly::toJson(arguments).c_str()).get());
-  return result->toString();
+std::string ProxyExecutor::flush() {
+  return executeJSCallWithProxy(m_executor.get(), "flushedQueue", std::vector<folly::dynamic>());
+}
+
+std::string ProxyExecutor::callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) {
+  std::vector<folly::dynamic> call{
+    (double) moduleId,
+    (double) methodId,
+    std::move(arguments),
+  };
+  return executeJSCallWithProxy(m_executor.get(), "callFunctionReturnFlushedQueue", std::move(call));
+}
+
+std::string ProxyExecutor::invokeCallback(const double callbackId, const folly::dynamic& arguments) {
+  std::vector<folly::dynamic> call{
+    (double) callbackId,
+    std::move(arguments)
+  };
+  return executeJSCallWithProxy(m_executor.get(), "invokeCallbackAndReturnFlushedQueue", std::move(call));
 }
 
 void ProxyExecutor::setGlobalVariable(const std::string& propName, const std::string& jsonValue) {
diff --git a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
index 805eda532b2f..2f5d21980d31 100644
--- a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
+++ b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
@@ -32,10 +32,14 @@ class ProxyExecutor : public JSExecutor {
   virtual void executeApplicationScript(
     const std::string& script,
     const std::string& sourceURL) override;
-  virtual std::string executeJSCall(
-    const std::string& moduleName,
-    const std::string& methodName,
-    const std::vector<folly::dynamic>& arguments) override;
+  virtual std::string flush() override;
+  virtual std::string callFunction(
+    const double moduleId,
+    const double methodId,
+    const folly::dynamic& arguments) override;
+  virtual std::string invokeCallback(
+    const double callbackId,
+    const folly::dynamic& arguments) override;
   virtual void setGlobalVariable(
     const std::string& propName,
     const std::string& jsonValue) override;
diff --git a/ReactAndroid/src/main/jni/react/test/jscexecutor.cpp b/ReactAndroid/src/main/jni/react/test/jscexecutor.cpp
index 40d21797485b..9091c1125055 100644
--- a/ReactAndroid/src/main/jni/react/test/jscexecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/test/jscexecutor.cpp
@@ -20,17 +20,13 @@ static std::vector<MethodCall> executeForMethodCalls(
     int moduleId,
     int methodId,
     std::vector<MethodArgument> args = std::vector<MethodArgument>()) {
-  std::vector<MethodArgument> call;
-  call.emplace_back((double) moduleId);
-  call.emplace_back((double) methodId);
-  call.emplace_back(std::move(args));
-  return parseMethodCalls(e.executeJSCall("Bridge", "callFunction", call));
+  return parseMethodCalls(e.callFunction(moduleId, methodId, std::move(args)));
 }
 
 TEST(JSCExecutor, CallFunction) {
   auto jsText = ""
   "var Bridge = {"
-  "  callFunction: function (module, method, args) {"
+  "  callFunctionReturnFlushedQueue: function (module, method, args) {"
   "    return [[module + 1], [method + 1], [args]];"
   "  },"
   "};"
@@ -58,7 +54,7 @@ TEST(JSCExecutor, CallFunction) {
 TEST(JSCExecutor, CallFunctionWithMap) {
   auto jsText = ""
   "var Bridge = {"
-  "  callFunction: function (module, method, args) {"
+  "  callFunctionReturnFlushedQueue: function (module, method, args) {"
   "    var s = args[0].foo + args[0].bar + args[0].baz;"
   "    return [[module], [method], [[s]]];"
   "  },"
@@ -85,7 +81,7 @@ TEST(JSCExecutor, CallFunctionWithMap) {
 TEST(JSCExecutor, CallFunctionReturningMap) {
   auto jsText = ""
   "var Bridge = {"
-  "  callFunction: function (module, method, args) {"
+  "  callFunctionReturnFlushedQueue: function (module, method, args) {"
   "    var s = { foo: 4, bar: true };"
   "    return [[module], [method], [[s]]];"
   "  },"
@@ -111,7 +107,7 @@ TEST(JSCExecutor, CallFunctionReturningMap) {
 TEST(JSCExecutor, CallFunctionWithArray) {
   auto jsText = ""
   "var Bridge = {"
-  "  callFunction: function (module, method, args) {"
+  "  callFunctionReturnFlushedQueue: function (module, method, args) {"
   "    var s = args[0][0]+ args[0][1] + args[0][2] + args[0].length;"
   "    return [[module], [method], [[s]]];"
   "  },"
@@ -138,7 +134,7 @@ TEST(JSCExecutor, CallFunctionWithArray) {
 TEST(JSCExecutor, CallFunctionReturningNumberArray) {
   auto jsText = ""
   "var Bridge = {"
-  "  callFunction: function (module, method, args) {"
+  "  callFunctionReturnFlushedQueue: function (module, method, args) {"
   "    var s = [3, 1, 4];"
   "    return [[module], [method], [[s]]];"
   "  },"
@@ -162,7 +158,7 @@ TEST(JSCExecutor, CallFunctionReturningNumberArray) {
 TEST(JSCExecutor, SetSimpleGlobalVariable) {
   auto jsText = ""
   "var Bridge = {"
-  "  callFunction: function (module, method, args) {"
+  "  callFunctionReturnFlushedQueue: function (module, method, args) {"
   "    return [[module], [method], [[__foo]]];"
   "  },"
   "};"
@@ -182,7 +178,7 @@ TEST(JSCExecutor, SetSimpleGlobalVariable) {
 TEST(JSCExecutor, SetObjectGlobalVariable) {
   auto jsText = ""
   "var Bridge = {"
-  "  callFunction: function (module, method, args) {"
+  "  callFunctionReturnFlushedQueue: function (module, method, args) {"
   "    return [[module], [method], [[__foo]]];"
   "  },"
   "};"
diff --git a/local-cli/server/util/debugger.html b/local-cli/server/util/debugger.html
index a69424ea98dd..289b1f53b304 100644
--- a/local-cli/server/util/debugger.html
+++ b/local-cli/server/util/debugger.html
@@ -58,12 +58,6 @@
     window.onbeforeunload = undefined;
     window.localStorage.setItem('sessionID', message.id);
     window.location.reload();
-  },
-  'executeApplicationScript': function(message) {
-    worker.postMessage(message);
-  },
-  'executeJSCall': function(message) {
-    worker.postMessage(message);
   }
 };
 
@@ -87,9 +81,11 @@
 
     var handler = messageHandlers[object.method];
     if (handler) {
+      // If we have a local handler, use it.
       handler(object);
     } else {
-      console.warn('Unknown method: ' + object.method);
+      // Otherwise, pass through to the worker.
+      worker.postMessage(object);
     }
   };
 
diff --git a/local-cli/server/util/debuggerWorker.js b/local-cli/server/util/debuggerWorker.js
index 94f3b7d58623..fc72c5713c16 100644
--- a/local-cli/server/util/debuggerWorker.js
+++ b/local-cli/server/util/debuggerWorker.js
@@ -6,7 +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.
  */
-/* global self, importScripts, postMessage, onmessage: true */
+/* global __fbBatchedBridge, self, importScripts, postMessage, onmessage: true */
 /* eslint no-unused-vars: 0 */
 'use strict';
 
@@ -17,16 +17,6 @@ var messageHandlers = {
     }
     importScripts(message.url);
     sendReply();
-  },
-  'executeJSCall': function(message, sendReply) {
-    var returnValue = [[], [], [], [], []];
-    try {
-      if (typeof require === 'function') {
-        returnValue = require(message.moduleName)[message.moduleMethod].apply(null, message.arguments);
-      }
-    } finally {
-      sendReply(JSON.stringify(returnValue));
-    }
   }
 };
 
@@ -39,8 +29,17 @@ onmessage = function(message) {
 
   var handler = messageHandlers[object.method];
   if (handler) {
+    // Special cased handlers
     handler(object, sendReply);
   } else {
-    console.warn('Unknown method: ' + object.method);
+    // Other methods get called on the bridge
+    var returnValue = [[], [], [], [], []];
+    try {
+      if (typeof __fbBatchedBridge === 'object') {
+        returnValue = __fbBatchedBridge[object.method].apply(null, object.arguments);
+      }
+    } finally {
+      sendReply(JSON.stringify(returnValue));
+    }
   }
 };

From 14478f6701520390f00810d574892d0825e5256c Mon Sep 17 00:00:00 2001
From: Martin Kralik <kralik@fb.com>
Date: Wed, 9 Dec 2015 04:04:23 -0800
Subject: [PATCH 0283/1411] better error message for `propTypes` check

Summary:
When you did a typo in declaring a prop type (like using `boolean` insteal of `bool`) you'd got a bit misleading error message:
{F27113768}
The truth is that the prop type is defined, but not correctly. So I've changed the message in this case to be more accurate:
{F27113627}

public

Reviewed By: sahrens

Differential Revision: D2729340

fb-gh-sync-id: dd12c10a4f3a1c9825293f86481a082908127a76
---
 Libraries/ReactIOS/verifyPropTypes.js | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/Libraries/ReactIOS/verifyPropTypes.js b/Libraries/ReactIOS/verifyPropTypes.js
index a7ccd210b6b1..1974716ba260 100644
--- a/Libraries/ReactIOS/verifyPropTypes.js
+++ b/Libraries/ReactIOS/verifyPropTypes.js
@@ -41,11 +41,16 @@ function verifyPropTypes(
     if (!componentInterface.propTypes[prop] &&
         !ReactNativeStyleAttributes[prop] &&
         (!nativePropsToIgnore || !nativePropsToIgnore[prop])) {
-      throw new Error(
-        '`' + componentName + '` has no propType for native prop `' +
+      var message;
+      if (componentInterface.propTypes.hasOwnProperty(prop)) {
+        message = '`' + componentName + '` has incorrectly defined propType for native prop `' +
+        viewConfig.uiViewClassName + '.' + prop + '` of native type `' + nativeProps[prop];
+      } else {
+        message = '`' + componentName + '` has no propType for native prop `' +
         viewConfig.uiViewClassName + '.' + prop + '` of native type `' +
-        nativeProps[prop] + '`'
-      );
+        nativeProps[prop] + '`';
+      };
+      throw new Error(message);
     }
   }
 }

From 54ec6e7cabbcb5aa56487d3633252564cd2a5c00 Mon Sep 17 00:00:00 2001
From: Harry Moreno <morenoh149@gmail.com>
Date: Wed, 9 Dec 2015 04:29:06 -0800
Subject: [PATCH 0284/1411] Docs warn navigator ios

Summary:
ping https://github.com/facebook/react-native/issues/795#issuecomment-139895307
Closes https://github.com/facebook/react-native/pull/3087

Reviewed By: svcscm

Differential Revision: D2738947

Pulled By: mkonicek

fb-gh-sync-id: e29dfd933a8da42551576bdb1fb5c270039722ee
---
 Libraries/Components/Navigation/NavigatorIOS.ios.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Libraries/Components/Navigation/NavigatorIOS.ios.js b/Libraries/Components/Navigation/NavigatorIOS.ios.js
index 87f49232bffe..37cc1899edd0 100644
--- a/Libraries/Components/Navigation/NavigatorIOS.ios.js
+++ b/Libraries/Components/Navigation/NavigatorIOS.ios.js
@@ -95,6 +95,12 @@ type Event = Object;
  * NavigatorIOS wraps UIKit navigation and allows you to add back-swipe
  * functionality across your app.
  *
+ * > **NOTE**: This Component is not maintained by Facebook
+ * >
+ * > This component is under community responsibility.
+ * > If a pure JavaScript solution fits your needs you may try the `Navigator`
+ * > component instead.
+ *
  * #### Routes
  * A route is an object used to describe each page in the navigator. The first
  * route is provided to NavigatorIOS as `initialRoute`:

From 0ce2bce201696daece2e1b57e328b18d307ced88 Mon Sep 17 00:00:00 2001
From: Brian Leonard <brian@bleonard.com>
Date: Wed, 9 Dec 2015 04:39:36 -0800
Subject: [PATCH 0285/1411] Allow other Xcode configurations with DEV=false

Summary:
Updates build script to fix https://github.com/facebook/react-native/issues/4362
Closes https://github.com/facebook/react-native/pull/4520

Reviewed By: svcscm

Differential Revision: D2730607

Pulled By: mkonicek

fb-gh-sync-id: 2fc4a9815f19ab867a6a3dc77cf1b6eac8a25616
---
 packager/react-native-xcode.sh | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/packager/react-native-xcode.sh b/packager/react-native-xcode.sh
index dfa413b80ad8..5c88fdad1c0e 100755
--- a/packager/react-native-xcode.sh
+++ b/packager/react-native-xcode.sh
@@ -14,16 +14,12 @@ case "$CONFIGURATION" in
   Debug)
     DEV=true
     ;;
-  Release)
-    DEV=false
-    ;;
   "")
     echo "$0 must be invoked by Xcode"
     exit 1
     ;;
   *)
-    echo "Unsupported value of \$CONFIGURATION=$CONFIGURATION"
-    exit 1
+    DEV=false
     ;;
 esac
 

From f8be78379858c5d78eaf81e8a00d5e276481b72f Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Wed, 9 Dec 2015 04:37:40 -0800
Subject: [PATCH 0286/1411] Document intentional retain cycle on
 RCTJavaScriptContext

Summary:
public

More people wanted to understand the motivation behind the intentional retain
cycle in `RCTJavaScriptContext`, add a small comment with some context.

Reviewed By: jspahrsummers

Differential Revision: D2738930

fb-gh-sync-id: d8c950778eb6bf3eaca627aabb6c98335d25d1fc
---
 React/Executors/RCTContextExecutor.m | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/React/Executors/RCTContextExecutor.m b/React/Executors/RCTContextExecutor.m
index 42b0a37e14f8..3c22398d5d3b 100644
--- a/React/Executors/RCTContextExecutor.m
+++ b/React/Executors/RCTContextExecutor.m
@@ -51,14 +51,22 @@ - (instancetype)initWithJSContext:(JSContext *)context NS_DESIGNATED_INITIALIZER
 
 @implementation RCTJavaScriptContext
 {
-  RCTJavaScriptContext *_self;
+  RCTJavaScriptContext *_selfReference;
 }
 
 - (instancetype)initWithJSContext:(JSContext *)context
 {
   if ((self = [super init])) {
     _context = context;
-    _self = self;
+
+    /**
+     * Explicitly introduce a retain cycle here - The RCTContextExecutor might
+     * be deallocated while there's still work enqueued in the JS thread, so
+     * we wouldn't be able kill the JSContext. Instead we create this retain
+     * cycle, and enqueue the -invalidate message in this object, it then
+     * releases the JSContext, breaks the cycle and stops the runloop.
+     */
+    _selfReference = self;
   }
   return self;
 }
@@ -79,7 +87,7 @@ - (void)invalidate
 {
   if (self.isValid) {
     _context = nil;
-    _self = nil;
+    _selfReference = nil;
   }
 }
 

From 86bb656e6fa52707b36b94fa04d7bec170badb72 Mon Sep 17 00:00:00 2001
From: Christopher Dro <hello@blick-labs.com>
Date: Wed, 9 Dec 2015 05:08:36 -0800
Subject: [PATCH 0287/1411] Add tintColor for buttons.

Summary:
Closes #3374
Closes https://github.com/facebook/react-native/pull/4590

Reviewed By: javache

Differential Revision: D2729616

Pulled By: mkonicek

fb-gh-sync-id: 4a3b6de10a09cad73dbd9d5d552adc3f6ba054e0
---
 Examples/UIExplorer/ActionSheetIOSExample.js  | 40 ++++++++++++++++++-
 Libraries/ActionSheetIOS/ActionSheetIOS.js    |  5 ++-
 .../ActionSheetIOS/RCTActionSheetManager.m    |  5 ++-
 3 files changed, 46 insertions(+), 4 deletions(-)

diff --git a/Examples/UIExplorer/ActionSheetIOSExample.js b/Examples/UIExplorer/ActionSheetIOSExample.js
index 1ef41c1edef7..ccc86fba4a50 100644
--- a/Examples/UIExplorer/ActionSheetIOSExample.js
+++ b/Examples/UIExplorer/ActionSheetIOSExample.js
@@ -27,7 +27,7 @@ var BUTTONS = [
   'Option 0',
   'Option 1',
   'Option 2',
-  'Destruct',
+  'Delete',
   'Cancel',
 ];
 var DESTRUCTIVE_INDEX = 3;
@@ -65,6 +65,40 @@ var ActionSheetExample = React.createClass({
   }
 });
 
+var ActionSheetTintExample = React.createClass({
+  getInitialState() {
+    return {
+      clicked: 'none',
+    };
+  },
+
+  render() {
+    return (
+      <View>
+        <Text onPress={this.showActionSheet} style={style.button}>
+          Click to show the ActionSheet
+        </Text>
+        <Text>
+          Clicked button: {this.state.clicked}
+        </Text>
+      </View>
+    );
+  },
+
+  showActionSheet() {
+    ActionSheetIOS.showActionSheetWithOptions({
+      options: BUTTONS,
+      cancelButtonIndex: CANCEL_INDEX,
+      destructiveButtonIndex: DESTRUCTIVE_INDEX,
+      tintColor: 'green',
+    },
+    (buttonIndex) => {
+      this.setState({ clicked: BUTTONS[buttonIndex] });
+    });
+  }
+});
+
+
 var ShareActionSheetExample = React.createClass({
   getInitialState() {
     return {
@@ -123,6 +157,10 @@ exports.examples = [
     title: 'Show Action Sheet',
     render(): ReactElement { return <ActionSheetExample />; }
   },
+  {
+    title: 'Show Action Sheet with tinted buttons',
+    render(): ReactElement { return <ActionSheetTintExample />; }
+  },
   {
     title: 'Show Share Action Sheet',
     render(): ReactElement { return <ShareActionSheetExample />; }
diff --git a/Libraries/ActionSheetIOS/ActionSheetIOS.js b/Libraries/ActionSheetIOS/ActionSheetIOS.js
index 155b7d74e2f4..c63618441bb0 100644
--- a/Libraries/ActionSheetIOS/ActionSheetIOS.js
+++ b/Libraries/ActionSheetIOS/ActionSheetIOS.js
@@ -14,6 +14,7 @@
 var RCTActionSheetManager = require('NativeModules').ActionSheetManager;
 
 var invariant = require('invariant');
+var processColor = require('processColor');
 
 var ActionSheetIOS = {
   showActionSheetWithOptions(options: Object, callback: Function) {
@@ -26,7 +27,7 @@ var ActionSheetIOS = {
       'Must provide a valid callback'
     );
     RCTActionSheetManager.showActionSheetWithOptions(
-      options,
+      {...options, tintColor: processColor(options.tintColor)},
       callback
     );
   },
@@ -49,7 +50,7 @@ var ActionSheetIOS = {
       'Must provide a valid successCallback'
     );
     RCTActionSheetManager.showShareActionSheetWithOptions(
-      options,
+      {...options, tintColor: processColor(options.tintColor)},
       failureCallback,
       successCallback
     );
diff --git a/Libraries/ActionSheetIOS/RCTActionSheetManager.m b/Libraries/ActionSheetIOS/RCTActionSheetManager.m
index 245493b0ceef..6d568a0a4498 100644
--- a/Libraries/ActionSheetIOS/RCTActionSheetManager.m
+++ b/Libraries/ActionSheetIOS/RCTActionSheetManager.m
@@ -16,7 +16,6 @@
 #import "RCTUIManager.h"
 
 @interface RCTActionSheetManager () <UIActionSheetDelegate>
-
 @end
 
 @implementation RCTActionSheetManager
@@ -139,6 +138,8 @@ - (CGRect)sourceRectInView:(UIView *)sourceView
       alertController.popoverPresentationController.permittedArrowDirections = 0;
     }
     [controller presentViewController:alertController animated:YES completion:nil];
+
+    alertController.view.tintColor = [RCTConvert UIColor:options[@"tintColor"]];
   }
 }
 
@@ -210,6 +211,8 @@ - (CGRect)sourceRectInView:(UIView *)sourceView
   }
 
   [controller presentViewController:shareController animated:YES completion:nil];
+
+  shareController.view.tintColor = [RCTConvert UIColor:options[@"tintColor"]];
 }
 
 #pragma mark UIActionSheetDelegate Methods

From cd4574498d27e1b71b7f77f554533997f8552481 Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Wed, 9 Dec 2015 09:53:00 -0800
Subject: [PATCH 0288/1411] Use actual CADisplayLink timestamp for VSYNC

Summary:
public

Use the actual timestamp provided through `CADisplayLink` instead of the time
the handler is called.

Reviewed By: jspahrsummers

Differential Revision: D2739121

fb-gh-sync-id: 1da28190bb25351dc3dd94efaff21d49279a570f
---
 React/Base/RCTBatchedBridge.m | 2 +-
 React/Profiler/RCTProfile.h   | 1 +
 React/Profiler/RCTProfile.m   | 6 +++---
 3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index 696de22ad51b..b3b290d72bde 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -943,7 +943,7 @@ - (void)_jsThreadUpdate:(CADisplayLink *)displayLink
   [self updateJSDisplayLinkState];
 
 
-  RCTProfileImmediateEvent(0, @"JS Thread Tick", 'g');
+  RCTProfileImmediateEvent(0, @"JS Thread Tick", displayLink.timestamp, 'g');
 
   RCT_PROFILE_END_EVENT(0, @"objc_call", nil);
 }
diff --git a/React/Profiler/RCTProfile.h b/React/Profiler/RCTProfile.h
index 2e6e921d3d26..a013a70703a3 100644
--- a/React/Profiler/RCTProfile.h
+++ b/React/Profiler/RCTProfile.h
@@ -124,6 +124,7 @@ RCT_EXTERN void RCTProfileEndAsyncEvent(uint64_t tag,
  */
 RCT_EXTERN void RCTProfileImmediateEvent(uint64_t tag,
                                          NSString *name,
+                                         NSTimeInterval time,
                                          char scope);
 
 /**
diff --git a/React/Profiler/RCTProfile.m b/React/Profiler/RCTProfile.m
index f311a35045d6..a47931e429c2 100644
--- a/React/Profiler/RCTProfile.m
+++ b/React/Profiler/RCTProfile.m
@@ -275,9 +275,9 @@ @interface RCTProfile : NSObject
 
 @implementation RCTProfile
 
-+ (void)vsync:(__unused CADisplayLink *)displayLink
++ (void)vsync:(CADisplayLink *)displayLink
 {
-  RCTProfileImmediateEvent(0, @"VSYNC", 'g');
+  RCTProfileImmediateEvent(0, @"VSYNC", displayLink.timestamp, 'g');
 }
 
 @end
@@ -513,6 +513,7 @@ void RCTProfileEndAsyncEvent(
 void RCTProfileImmediateEvent(
   uint64_t tag,
   NSString *name,
+  NSTimeInterval time,
   char scope
 ) {
   CHECK();
@@ -522,7 +523,6 @@ void RCTProfileImmediateEvent(
     return;
   }
 
-  NSTimeInterval time = CACurrentMediaTime();
   NSString *threadName = RCTCurrentThreadName();
 
   dispatch_async(RCTProfileGetQueue(), ^{

From 90c7ad112f9e53dc6c71c8f47ea2a31b41d06141 Mon Sep 17 00:00:00 2001
From: tantan <tan-tan.tan@schneider-electric.com>
Date: Wed, 9 Dec 2015 10:00:19 -0800
Subject: [PATCH 0289/1411] add Clipboard component for ios and android

Summary:
add Clipboard component for ios and android
 ```javascript
    import Clipboard from 'react-native'

    Clipboard.get((content)=>{
          console.log('here is content in clipboard:%s',content)
    });
    var content = 'here is a string';
    Clipboard.set(content);
```
Closes https://github.com/facebook/react-native/pull/4384

Reviewed By: svcscm

Differential Revision: D2738881

Pulled By: mkonicek

fb-gh-sync-id: a06df32d1eb2824cc9ca3de9d45e4e67fd2edbc9
---
 Examples/UIExplorer/ClipboardExample.js       | 60 +++++++++++++
 Examples/UIExplorer/UIExplorerList.android.js |  1 +
 Examples/UIExplorer/UIExplorerList.ios.js     |  1 +
 .../__mocks__/NativeModules.js                |  4 +-
 Libraries/Components/Clipboard/Clipboard.js   | 13 +++
 Libraries/react-native/react-native.js        |  1 +
 Libraries/react-native/react-native.js.flow   |  1 +
 .../{RCTPasteboard.h => RCTClipboard.h}       |  2 +-
 .../{RCTPasteboard.m => RCTClipboard.m}       | 17 +++-
 React/React.xcodeproj/project.pbxproj         | 18 ++--
 .../modules/clipboard/ClipboardModule.java    | 84 +++++++++++++++++++
 .../react/shell/MainReactPackage.java         |  2 +
 12 files changed, 188 insertions(+), 16 deletions(-)
 create mode 100644 Examples/UIExplorer/ClipboardExample.js
 create mode 100644 Libraries/Components/Clipboard/Clipboard.js
 rename React/Modules/{RCTPasteboard.h => RCTClipboard.h} (86%)
 rename React/Modules/{RCTPasteboard.m => RCTClipboard.m} (52%)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java

diff --git a/Examples/UIExplorer/ClipboardExample.js b/Examples/UIExplorer/ClipboardExample.js
new file mode 100644
index 000000000000..bcc53dfbb6e4
--- /dev/null
+++ b/Examples/UIExplorer/ClipboardExample.js
@@ -0,0 +1,60 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ *
+ * @flow
+ */
+'use strict';
+
+var React = require('react-native');
+var {
+  Clipboard,
+  View,
+  Text,
+} = React;
+
+var ClipboardExample = React.createClass({
+  getInitialState: function() {
+    return {
+      content: 'Content will appear here'
+    };
+  },
+  
+  _setContentToClipboard:function(){
+    Clipboard.setString('Hello World');
+    Clipboard.getString(content => {
+      this.setState({content});
+    });
+  },
+  
+  render() {
+    return (
+      <View>
+        <Text onPress={this._setContentToClipboard} style={{color: 'blue'}}>
+          Tap to put "Hello World" in the clipboard
+        </Text>
+        <Text style={{color: 'red', marginTop: 20}}>
+          {this.state.content}
+        </Text>
+      </View>
+    );
+  }
+});
+
+exports.title = 'Clipboard';
+exports.description = 'Show Clipboard contents.';
+exports.examples = [
+  {
+    title: 'Clipboard.setString() and getString()',
+    render(): ReactElement { return <ClipboardExample />; }
+  }
+];
diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index a2ff43096c55..36746c55861d 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -39,6 +39,7 @@ var COMPONENTS = [
 var APIS = [
   require('./AccessibilityAndroidExample.android'),
   require('./BorderExample'),
+  require('./ClipboardExample'),
   require('./GeolocationExample'),
   require('./IntentAndroidExample.android'),
   require('./LayoutEventsExample'),
diff --git a/Examples/UIExplorer/UIExplorerList.ios.js b/Examples/UIExplorer/UIExplorerList.ios.js
index 940bd79ba42e..61a213097909 100644
--- a/Examples/UIExplorer/UIExplorerList.ios.js
+++ b/Examples/UIExplorer/UIExplorerList.ios.js
@@ -66,6 +66,7 @@ var APIS = [
   require('./AsyncStorageExample'),
   require('./BorderExample'),
   require('./CameraRollExample.ios'),
+  require('./ClipboardExample'),
   require('./GeolocationExample'),
   require('./LayoutExample'),
   require('./NetInfoExample'),
diff --git a/Libraries/BatchedBridge/BatchedBridgedModules/__mocks__/NativeModules.js b/Libraries/BatchedBridge/BatchedBridgedModules/__mocks__/NativeModules.js
index 113a09262699..164508ddd038 100644
--- a/Libraries/BatchedBridge/BatchedBridgedModules/__mocks__/NativeModules.js
+++ b/Libraries/BatchedBridge/BatchedBridgedModules/__mocks__/NativeModules.js
@@ -54,8 +54,8 @@ var NativeModules = {
   AlertManager: {
     alertWithArgs: jest.genMockFunction(),
   },
-  Pasteboard: {
-    setPasteboardString: jest.genMockFunction(),
+  Clipboard: {
+    setString: jest.genMockFunction(),
   },
 };
 
diff --git a/Libraries/Components/Clipboard/Clipboard.js b/Libraries/Components/Clipboard/Clipboard.js
new file mode 100644
index 000000000000..fd8461ba4e86
--- /dev/null
+++ b/Libraries/Components/Clipboard/Clipboard.js
@@ -0,0 +1,13 @@
+/**
+ * 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 Clipboard
+ */
+'use strict';
+
+module.exports = require('NativeModules').Clipboard;
diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js
index 9eb675a8425f..be3dfd26a450 100644
--- a/Libraries/react-native/react-native.js
+++ b/Libraries/react-native/react-native.js
@@ -58,6 +58,7 @@ var ReactNative = {
   get AsyncStorage() { return require('AsyncStorage'); },
   get BackAndroid() { return require('BackAndroid'); },
   get CameraRoll() { return require('CameraRoll'); },
+  get Clipboard() { return require('Clipboard'); },
   get Dimensions() { return require('Dimensions'); },
   get Easing() { return require('Easing'); },
   get ImagePickerIOS() { return require('ImagePickerIOS'); },
diff --git a/Libraries/react-native/react-native.js.flow b/Libraries/react-native/react-native.js.flow
index 0f314456a486..d6c4aac73602 100644
--- a/Libraries/react-native/react-native.js.flow
+++ b/Libraries/react-native/react-native.js.flow
@@ -70,6 +70,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
   AsyncStorage: require('AsyncStorage'),
   BackAndroid: require('BackAndroid'),
   CameraRoll: require('CameraRoll'),
+  Clipboard: require('Clipboard'),
   Dimensions: require('Dimensions'),
   Easing: require('Easing'),
   ImagePickerIOS: require('ImagePickerIOS'),
diff --git a/React/Modules/RCTPasteboard.h b/React/Modules/RCTClipboard.h
similarity index 86%
rename from React/Modules/RCTPasteboard.h
rename to React/Modules/RCTClipboard.h
index d29a3fb1a434..bc65c62390dd 100644
--- a/React/Modules/RCTPasteboard.h
+++ b/React/Modules/RCTClipboard.h
@@ -9,6 +9,6 @@
 
 #import "RCTBridgeModule.h"
 
-@interface RCTPasteboard : NSObject <RCTBridgeModule>
+@interface RCTClipboard : NSObject <RCTBridgeModule>
 
 @end
diff --git a/React/Modules/RCTPasteboard.m b/React/Modules/RCTClipboard.m
similarity index 52%
rename from React/Modules/RCTPasteboard.m
rename to React/Modules/RCTClipboard.m
index 41ad7c044753..0a62f3f888a8 100644
--- a/React/Modules/RCTPasteboard.m
+++ b/React/Modules/RCTClipboard.m
@@ -7,11 +7,13 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  */
 
-#import "RCTPasteboard.h"
+#import "RCTClipboard.h"
+
+#import "RCTUtils.h"
 
 #import <UIKit/UIKit.h>
 
-@implementation RCTPasteboard
+@implementation RCTClipboard
 
 RCT_EXPORT_MODULE()
 
@@ -20,9 +22,16 @@ - (dispatch_queue_t)methodQueue
   return dispatch_get_main_queue();
 }
 
-RCT_EXPORT_METHOD(setPasteboardString:(NSString *)string)
+RCT_EXPORT_METHOD(getString:(RCTResponseSenderBlock)callback)
+{
+  UIPasteboard *clipboard = [UIPasteboard generalPasteboard];
+  callback(@[RCTNullIfNil(clipboard.string)]);
+}
+
+RCT_EXPORT_METHOD(setString:(NSString *)content)
 {
-  [[UIPasteboard generalPasteboard] setString:string];
+  UIPasteboard *clipboard = [UIPasteboard generalPasteboard];
+  clipboard.string = content;
 }
 
 @end
diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj
index 53a11ed1d6d8..d5ea0c76d5d4 100644
--- a/React/React.xcodeproj/project.pbxproj
+++ b/React/React.xcodeproj/project.pbxproj
@@ -38,12 +38,12 @@
 		13B0801D1A69489C00A75B9A /* RCTNavItemManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B080131A69489C00A75B9A /* RCTNavItemManager.m */; };
 		13B080201A69489C00A75B9A /* RCTActivityIndicatorViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B080191A69489C00A75B9A /* RCTActivityIndicatorViewManager.m */; };
 		13B080261A694A8400A75B9A /* RCTWrapperViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B080241A694A8400A75B9A /* RCTWrapperViewController.m */; };
-		13BB3D021BECD54500932C10 /* RCTImageSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 13BB3D011BECD54500932C10 /* RCTImageSource.m */; };
-		13B202011BFB945300C07393 /* RCTPasteboard.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B202001BFB945300C07393 /* RCTPasteboard.m */; };
 		13B202041BFB948C00C07393 /* RCTMapAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B202031BFB948C00C07393 /* RCTMapAnnotation.m */; };
+		13BB3D021BECD54500932C10 /* RCTImageSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 13BB3D011BECD54500932C10 /* RCTImageSource.m */; };
 		13C156051AB1A2840079392D /* RCTWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13C156021AB1A2840079392D /* RCTWebView.m */; };
 		13C156061AB1A2840079392D /* RCTWebViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13C156041AB1A2840079392D /* RCTWebViewManager.m */; };
 		13CC8A821B17642100940AE7 /* RCTBorderDrawing.m in Sources */ = {isa = PBXBuildFile; fileRef = 13CC8A811B17642100940AE7 /* RCTBorderDrawing.m */; };
+		13D033631C1837FE0021DC29 /* RCTClipboard.m in Sources */ = {isa = PBXBuildFile; fileRef = 13D033621C1837FE0021DC29 /* RCTClipboard.m */; };
 		13E0674A1A70F434002CDEE1 /* RCTUIManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E067491A70F434002CDEE1 /* RCTUIManager.m */; };
 		13E067551A70F44B002CDEE1 /* RCTShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E0674C1A70F44B002CDEE1 /* RCTShadowView.m */; };
 		13E067561A70F44B002CDEE1 /* RCTViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E0674E1A70F44B002CDEE1 /* RCTViewManager.m */; };
@@ -174,12 +174,10 @@
 		13B080191A69489C00A75B9A /* RCTActivityIndicatorViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTActivityIndicatorViewManager.m; sourceTree = "<group>"; };
 		13B080231A694A8400A75B9A /* RCTWrapperViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWrapperViewController.h; sourceTree = "<group>"; };
 		13B080241A694A8400A75B9A /* RCTWrapperViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWrapperViewController.m; sourceTree = "<group>"; };
-		13BB3D001BECD54500932C10 /* RCTImageSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImageSource.h; sourceTree = "<group>"; };
-		13BB3D011BECD54500932C10 /* RCTImageSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageSource.m; sourceTree = "<group>"; };
-	13B201FF1BFB945300C07393 /* RCTPasteboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPasteboard.h; sourceTree = "<group>"; };
-		13B202001BFB945300C07393 /* RCTPasteboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPasteboard.m; sourceTree = "<group>"; };
 		13B202021BFB948C00C07393 /* RCTMapAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTMapAnnotation.h; sourceTree = "<group>"; };
 		13B202031BFB948C00C07393 /* RCTMapAnnotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTMapAnnotation.m; sourceTree = "<group>"; };
+		13BB3D001BECD54500932C10 /* RCTImageSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImageSource.h; sourceTree = "<group>"; };
+		13BB3D011BECD54500932C10 /* RCTImageSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageSource.m; sourceTree = "<group>"; };
 		13C156011AB1A2840079392D /* RCTWebView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebView.h; sourceTree = "<group>"; };
 		13C156021AB1A2840079392D /* RCTWebView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWebView.m; sourceTree = "<group>"; };
 		13C156031AB1A2840079392D /* RCTWebViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebViewManager.h; sourceTree = "<group>"; };
@@ -189,6 +187,8 @@
 		13C325281AA63B6A0048765F /* RCTComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTComponent.h; sourceTree = "<group>"; };
 		13CC8A801B17642100940AE7 /* RCTBorderDrawing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBorderDrawing.h; sourceTree = "<group>"; };
 		13CC8A811B17642100940AE7 /* RCTBorderDrawing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBorderDrawing.m; sourceTree = "<group>"; };
+		13D033611C1837FE0021DC29 /* RCTClipboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTClipboard.h; sourceTree = "<group>"; };
+		13D033621C1837FE0021DC29 /* RCTClipboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTClipboard.m; sourceTree = "<group>"; };
 		13E067481A70F434002CDEE1 /* RCTUIManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTUIManager.h; sourceTree = "<group>"; };
 		13E067491A70F434002CDEE1 /* RCTUIManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTUIManager.m; sourceTree = "<group>"; };
 		13E0674B1A70F44B002CDEE1 /* RCTShadowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTShadowView.h; sourceTree = "<group>"; };
@@ -318,14 +318,14 @@
 				1372B7091AB030C200659ED6 /* RCTAppState.m */,
 				58114A4F1AAE93D500E7D092 /* RCTAsyncLocalStorage.h */,
 				58114A4E1AAE93D500E7D092 /* RCTAsyncLocalStorage.m */,
+				13D033611C1837FE0021DC29 /* RCTClipboard.h */,
+				13D033621C1837FE0021DC29 /* RCTClipboard.m */,
 				13A0C2851B74F71200B29F6F /* RCTDevLoadingView.h */,
 				13A0C2861B74F71200B29F6F /* RCTDevLoadingView.m */,
 				13A0C2871B74F71200B29F6F /* RCTDevMenu.h */,
 				13A0C2881B74F71200B29F6F /* RCTDevMenu.m */,
 				13B07FE91A69327A00A75B9A /* RCTExceptionsManager.h */,
 				13B07FEA1A69327A00A75B9A /* RCTExceptionsManager.m */,
-				13B201FF1BFB945300C07393 /* RCTPasteboard.h */,
-				13B202001BFB945300C07393 /* RCTPasteboard.m */,
 				13F17A831B8493E5007D4C75 /* RCTRedBox.h */,
 				13F17A841B8493E5007D4C75 /* RCTRedBox.m */,
 				000E6CE91AB0E97F000CDF4D /* RCTSourceCode.h */,
@@ -628,7 +628,6 @@
 				13723B501A82FD3C00F88898 /* RCTStatusBarManager.m in Sources */,
 				000E6CEB1AB0E980000CDF4D /* RCTSourceCode.m in Sources */,
 				133CAE8E1B8E5CFD00F6AD92 /* RCTDatePicker.m in Sources */,
-				13B202011BFB945300C07393 /* RCTPasteboard.m in Sources */,
 				14C2CA761B3AC64F00E6CBB2 /* RCTFrameUpdate.m in Sources */,
 				13B07FEF1A69327A00A75B9A /* RCTAlertManager.m in Sources */,
 				83CBBACC1A6023D300E9B192 /* RCTConvert.m in Sources */,
@@ -669,6 +668,7 @@
 				14C2CA781B3ACB0400E6CBB2 /* RCTBatchedBridge.m in Sources */,
 				13E067591A70F44B002CDEE1 /* UIView+React.m in Sources */,
 				14F484561AABFCE100FDF6B9 /* RCTSliderManager.m in Sources */,
+				13D033631C1837FE0021DC29 /* RCTClipboard.m in Sources */,
 				14C2CA741B3AC64300E6CBB2 /* RCTModuleData.m in Sources */,
 				142014191B32094000CC17BA /* RCTPerformanceLogger.m in Sources */,
 				83CBBA981A6020BB00E9B192 /* RCTTouchHandler.m in Sources */,
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java
new file mode 100644
index 000000000000..b3689f980d9b
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java
@@ -0,0 +1,84 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.modules.clipboard;
+
+import android.annotation.SuppressLint;
+import android.content.ClipboardManager;
+import android.content.ClipData;
+import android.os.Build;
+
+import com.facebook.common.logging.FLog;
+import com.facebook.react.bridge.Callback;
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.common.ReactConstants;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A module that allows JS to get/set clipboard contents.
+ */
+public class ClipboardModule extends ReactContextBaseJavaModule {
+
+  public ClipboardModule(ReactApplicationContext reactContext) {
+    super(reactContext);
+  }
+
+  @Override
+  public String getName() {
+    return "Clipboard";
+  }
+
+  private ClipboardManager getClipboardService() {
+    ReactApplicationContext reactContext = getReactApplicationContext(); 
+    return (ClipboardManager) reactContext.getSystemService(reactContext.CLIPBOARD_SERVICE);
+  }
+
+  @ReactMethod
+  public void getString(Callback cb) {
+    try {
+      ClipboardManager clipboard = getClipboardService();
+      ClipData clipData = clipboard.getPrimaryClip();
+      if (clipData == null) {
+        cb.invoke("");
+        return;
+      }
+      if (clipData.getItemCount() >= 1) {
+        ClipData.Item firstItem = clipboard.getPrimaryClip().getItemAt(0);
+        String text = "" + firstItem.getText();
+        cb.invoke(text);
+      } else {
+        cb.invoke("");
+      }
+    } catch(Exception e) {
+      FLog.w(ReactConstants.TAG, "Cannot get clipboard contents: " + e.getMessage());
+    }
+  }
+
+  @SuppressLint("DeprecatedMethod")
+  @ReactMethod
+  public void setString(String text) {
+    ReactApplicationContext reactContext = getReactApplicationContext();
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+      ClipData clipdata = ClipData.newPlainText(null, text);
+      ClipboardManager clipboard = getClipboardService();
+      clipboard.setPrimaryClip(clipdata);
+    } else {
+      ClipboardManager clipboard = getClipboardService();
+      clipboard.setText(text);
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
index bf91bade6ccd..973cfbd84c7d 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
@@ -41,6 +41,7 @@
 import com.facebook.react.views.view.ReactViewManager;
 import com.facebook.react.views.viewpager.ReactViewPagerManager;
 import com.facebook.react.views.swiperefresh.SwipeRefreshLayoutManager;
+import com.facebook.react.modules.clipboard.ClipboardModule;
 
 /**
  * Package defining basic modules and view managers.
@@ -51,6 +52,7 @@ public class MainReactPackage implements ReactPackage {
   public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
     return Arrays.<NativeModule>asList(
       new AsyncStorageModule(reactContext),
+      new ClipboardModule(reactContext),
       new FrescoModule(reactContext),
       new IntentModule(reactContext),
       new LocationModule(reactContext),

From e8659b36020ad8af1086d656359ce28c9e1fdfa5 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Wed, 9 Dec 2015 20:25:19 +0000
Subject: [PATCH 0290/1411] Remove all BUCK files

---
 .../src/main/java/com/facebook/csslayout/BUCK | 15 -----
 .../src/main/java/com/facebook/jni/BUCK       | 17 ------
 .../src/main/java/com/facebook/perftest/BUCK  | 11 ----
 .../com/facebook/proguard/annotations/BUCK    | 14 -----
 .../src/main/java/com/facebook/quicklog/BUCK  | 14 -----
 .../com/facebook/quicklog/identifiers/BUCK    | 11 ----
 .../src/main/java/com/facebook/react/BUCK     | 27 ---------
 .../java/com/facebook/react/animation/BUCK    | 18 ------
 .../main/java/com/facebook/react/bridge/BUCK  | 41 -------------
 .../main/java/com/facebook/react/common/BUCK  | 29 ----------
 .../java/com/facebook/react/devsupport/BUCK   | 31 ----------
 .../com/facebook/react/modules/common/BUCK    | 20 -------
 .../java/com/facebook/react/modules/core/BUCK | 22 -------
 .../com/facebook/react/modules/debug/BUCK     | 21 -------
 .../com/facebook/react/modules/fresco/BUCK    | 28 ---------
 .../com/facebook/react/modules/network/BUCK   | 24 --------
 .../com/facebook/react/modules/storage/BUCK   | 21 -------
 .../facebook/react/modules/systeminfo/BUCK    | 19 -------
 .../com/facebook/react/modules/toast/BUCK     | 19 -------
 .../com/facebook/react/modules/websocket/BUCK | 22 -------
 .../main/java/com/facebook/react/shell/BUCK   | 43 --------------
 .../main/java/com/facebook/react/touch/BUCK   | 17 ------
 .../java/com/facebook/react/uimanager/BUCK    | 25 --------
 .../java/com/facebook/react/views/drawer/BUCK | 22 -------
 .../java/com/facebook/react/views/image/BUCK  | 29 ----------
 .../com/facebook/react/views/progressbar/BUCK | 21 -------
 .../facebook/react/views/recyclerview/BUCK    | 25 --------
 .../java/com/facebook/react/views/scroll/BUCK | 23 --------
 .../com/facebook/react/views/switchview/BUCK  | 21 -------
 .../java/com/facebook/react/views/text/BUCK   | 21 -------
 .../com/facebook/react/views/textinput/BUCK   | 23 --------
 .../com/facebook/react/views/toolbar/BUCK     | 33 -----------
 .../java/com/facebook/react/views/view/BUCK   | 22 -------
 .../com/facebook/react/views/viewpager/BUCK   | 21 -------
 .../src/main/java/com/facebook/soloader/BUCK  | 20 -------
 .../src/main/java/com/facebook/systrace/BUCK  | 11 ----
 ReactAndroid/src/main/jni/react/BUCK          | 57 -------------------
 ReactAndroid/src/main/jni/react/jni/BUCK      | 53 -----------------
 .../src/main/jni/react/perftests/BUCK         | 21 -------
 ReactAndroid/src/main/res/BUCK                | 19 -------
 40 files changed, 951 deletions(-)
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/csslayout/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/jni/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/perftest/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/proguard/annotations/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/quicklog/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/quicklog/identifiers/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/animation/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/common/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/devsupport/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/common/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/core/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/debug/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/fresco/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/network/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/storage/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/toast/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/websocket/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/shell/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/touch/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/drawer/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/image/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/progressbar/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/scroll/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/textinput/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/view/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/viewpager/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/soloader/BUCK
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/systrace/BUCK
 delete mode 100644 ReactAndroid/src/main/jni/react/BUCK
 delete mode 100644 ReactAndroid/src/main/jni/react/jni/BUCK
 delete mode 100644 ReactAndroid/src/main/jni/react/perftests/BUCK
 delete mode 100644 ReactAndroid/src/main/res/BUCK

diff --git a/ReactAndroid/src/main/java/com/facebook/csslayout/BUCK b/ReactAndroid/src/main/java/com/facebook/csslayout/BUCK
deleted file mode 100644
index da7888de9298..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/csslayout/BUCK
+++ /dev/null
@@ -1,15 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'csslayout',
-  srcs = glob(['**/*.java']),
-  deps = [
-    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
-    react_native_dep('third-party/java/jsr-305:jsr-305'),
-  ],
-  visibility = ['PUBLIC'],
-)
-
-project_config(
-  src_target = ':csslayout',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/jni/BUCK b/ReactAndroid/src/main/java/com/facebook/jni/BUCK
deleted file mode 100644
index 220371dbaae6..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/jni/BUCK
+++ /dev/null
@@ -1,17 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'jni',
-  srcs = glob(['**/*.java']),
-  deps = [
-    react_native_dep('java/com/facebook/proguard/annotations:annotations'),
-    react_native_dep('libraries/soloader/java/com/facebook/soloader:soloader'),
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':jni',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/perftest/BUCK b/ReactAndroid/src/main/java/com/facebook/perftest/BUCK
deleted file mode 100644
index 655817f6e11b..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/perftest/BUCK
+++ /dev/null
@@ -1,11 +0,0 @@
-android_library(
-  name = 'perftest',
-  srcs = glob(['*.java']),
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':perftest',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/proguard/annotations/BUCK b/ReactAndroid/src/main/java/com/facebook/proguard/annotations/BUCK
deleted file mode 100644
index 27de0b88a9c7..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/proguard/annotations/BUCK
+++ /dev/null
@@ -1,14 +0,0 @@
-android_library(
-  name = 'annotations',
-  srcs = glob(['*.java']),
-  proguard_config = 'proguard_annotations.pro',
-  deps = [
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':annotations',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/quicklog/BUCK b/ReactAndroid/src/main/java/com/facebook/quicklog/BUCK
deleted file mode 100644
index 911bbd556733..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/quicklog/BUCK
+++ /dev/null
@@ -1,14 +0,0 @@
-android_library(
-  name = 'quicklog',
-  srcs = glob(['*.java']),
-  exported_deps = [
-    '//java/com/facebook/quicklog/identifiers:identifiers',
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':quicklog',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/quicklog/identifiers/BUCK b/ReactAndroid/src/main/java/com/facebook/quicklog/identifiers/BUCK
deleted file mode 100644
index 38d3b1bfa8dc..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/quicklog/identifiers/BUCK
+++ /dev/null
@@ -1,11 +0,0 @@
-android_library(
-  name = 'identifiers',
-  srcs = glob(['*.java']),
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':identifiers',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/BUCK b/ReactAndroid/src/main/java/com/facebook/react/BUCK
deleted file mode 100644
index 8102c187c31b..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/BUCK
+++ /dev/null
@@ -1,27 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'react',
-  srcs = glob(['*.java']),
-  deps = [
-    '//libraries/fbcore/src/main/java/com/facebook/common/logging:logging',
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/react/common:common'),
-    react_native_target('java/com/facebook/react/devsupport:devsupport'),
-    react_native_target('java/com/facebook/react/modules/core:core'),
-    react_native_target('java/com/facebook/react/modules/debug:debug'),
-    react_native_target('java/com/facebook/react/modules/systeminfo:systeminfo'),
-    react_native_target('java/com/facebook/react/modules/toast:toast'),
-    react_native_target('java/com/facebook/react/uimanager:uimanager'),
-    react_native_dep('libraries/soloader/java/com/facebook/soloader:soloader'),
-    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
-    react_native_dep('third-party/java/jsr-305:jsr-305'),
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':react',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/animation/BUCK b/ReactAndroid/src/main/java/com/facebook/react/animation/BUCK
deleted file mode 100644
index 6a3307d027a7..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/animation/BUCK
+++ /dev/null
@@ -1,18 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'animation',
-  srcs = glob(['**/*.java']),
-  deps = [
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
-    react_native_dep('third-party/java/jsr-305:jsr-305'),
-  ],
-  visibility = [
-    'PUBLIC'
-  ],
-)
-
-project_config(
-  src_target = ':animation',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/BUCK b/ReactAndroid/src/main/java/com/facebook/react/bridge/BUCK
deleted file mode 100644
index 9d8c59acd80d..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/BUCK
+++ /dev/null
@@ -1,41 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-# We package the JS files from the bundler and local directory into what we
-# pretend is an ordinary JAR file. By putting them under the assets/ directory
-# within the zip file and relying on Buck to merge its contents into the APK,
-# our JS bundles arrive in a place accessible by the AssetManager at runtime.
-
-python_binary(
-  name = 'package_js',
-  main = 'package_js.py',
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-android_library(
-  name = 'bridge',
-  srcs = glob(['**/*.java']),
-  deps = [
-    '//libraries/fbcore/src/main/java/com/facebook/common/logging:logging',
-    react_native_target('java/com/facebook/react/common:common'),
-    react_native_target('jni/react/jni:jni'),
-    react_native_dep('libraries/soloader/java/com/facebook/soloader:soloader'),
-    react_native_dep('java/com/facebook/systrace:systrace'),
-    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
-    react_native_dep('third-party/java/jackson:core'),
-    react_native_dep('third-party/java/jsr-305:jsr-305'),
-    react_native_dep('third-party/java/okhttp:okhttp-ws'),
-  ],
-  exported_deps = [
-    react_native_dep('java/com/facebook/jni:jni'),
-    react_native_dep('java/com/facebook/proguard/annotations:annotations'),
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':bridge',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/common/BUCK b/ReactAndroid/src/main/java/com/facebook/react/common/BUCK
deleted file mode 100644
index d034ce6ec68e..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/common/BUCK
+++ /dev/null
@@ -1,29 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'common',
-  srcs = glob(['**/*.java']),
-  deps = [
-    ':build_config',
-    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
-    react_native_dep('third-party/java/jsr-305:jsr-305'),
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-android_build_config(
-  name = 'build_config',
-  package = 'com.facebook.react',
-  visibility = [
-    'PUBLIC',
-  ],
-  values = [
-   'boolean IS_INTERNAL_BUILD = true',
-  ],
-)
-
-project_config(
-  src_target = ':common',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/BUCK b/ReactAndroid/src/main/java/com/facebook/react/devsupport/BUCK
deleted file mode 100644
index 06bf27bc42d8..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/BUCK
+++ /dev/null
@@ -1,31 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'devsupport',
-  manifest = 'AndroidManifest.xml',
-  srcs = glob(['**/*.java']),
-  deps = [
-    '//libraries/fbcore/src/main/java/com/facebook/common/logging:logging',
-    react_native_target('res:devsupport'),
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/react/common:common'),
-    react_native_target('java/com/facebook/react/modules/debug:debug'),
-    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
-    react_native_dep('third-party/java/jsr-305:jsr-305'),
-    react_native_dep('third-party/java/okhttp:okhttp'),
-    react_native_dep('third-party/java/okio:okio'),
-  ],
-  visibility = [
-    react_native_target('java/com/facebook/react/...'),
-    '//instrumentation_tests/com/facebook/catalyst/...',
-    '//java/com/facebook/catalyst/...',
-    '//java/com/facebook/groups/treehouse/react/...',
-    '//java/com/facebook/fbreact/...',
-    '//javatests/com/facebook/catalyst/...',
-    '//javatests/com/facebook/react/...',
-  ],
-)
-
-project_config(
-  src_target = ':devsupport',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/common/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/common/BUCK
deleted file mode 100644
index d099b3c2efd6..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/common/BUCK
+++ /dev/null
@@ -1,20 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'common',
-  srcs = glob(['**/*.java']),
-  deps = [
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/react/common:common'),
-    '//libraries/fbcore/src/main/java/com/facebook/common/logging:logging',
-    '//third-party/java/infer-annotations:infer-annotations',
-    '//third-party/java/jsr-305:jsr-305',
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':common',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/core/BUCK
deleted file mode 100644
index 5507ede15a6b..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/core/BUCK
+++ /dev/null
@@ -1,22 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'core',
-  srcs = glob(['**/*.java']),
-  deps = [
-    '//libraries/fbcore/src/main/java/com/facebook/common/logging:logging',
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/react/common:common'),
-    react_native_target('java/com/facebook/react/devsupport:devsupport'),
-    react_native_target('java/com/facebook/react/uimanager:uimanager'),
-    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
-    react_native_dep('third-party/java/jsr-305:jsr-305'),
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':core',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/debug/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/debug/BUCK
deleted file mode 100644
index 6f5d6b9b1500..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/debug/BUCK
+++ /dev/null
@@ -1,21 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'debug',
-  srcs = glob(['**/*.java']),
-  deps = [
-    '//libraries/fbcore/src/main/java/com/facebook/common/logging:logging',
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/react/common:common'),
-    react_native_target('java/com/facebook/react/uimanager:uimanager'),
-    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
-    react_native_dep('third-party/java/jsr-305:jsr-305'),
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':debug',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/BUCK
deleted file mode 100644
index 18e1e514c51a..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/BUCK
+++ /dev/null
@@ -1,28 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'fresco',
-  srcs = glob(['**/*.java']),
-  deps = [
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/react/modules/common:common'),
-    react_native_target('java/com/facebook/react/modules/network:network'),
-    react_native_dep('java/com/facebook/systrace:systrace'),
-    '//libraries/fbcore/src/main/java/com/facebook/common/internal:internal',
-    '//libraries/fbcore/src/main/java/com/facebook/common/soloader:soloader',
-    '//libraries/fresco/drawee-backends/drawee-pipeline/src/main/java/com/facebook/drawee/backends/pipeline:pipeline',
-    '//libraries/fresco/imagepipeline-backends/imagepipeline-okhttp/src/main/java/com/facebook/imagepipeline/backends/okhttp:okhttp',
-    '//libraries/imagepipeline/src/main/java/com/facebook/cache/common:common',
-    '//libraries/imagepipeline/src/main/java/com/facebook/cache/disk:disk',
-    '//libraries/imagepipeline/src/main/java/com/facebook/imagepipeline/core:core',
-    '//libraries/soloader/java/com/facebook/soloader:soloader',
-    '//third-party/java/okhttp:okhttp',
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':fresco',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/network/BUCK
deleted file mode 100644
index 2de89f0d35db..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/BUCK
+++ /dev/null
@@ -1,24 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'network',
-  srcs = glob(['**/*.java']),
-  deps = [
-    '//libraries/fbcore/src/main/java/com/facebook/common/logging:logging',
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/react/modules/core:core'),
-    react_native_target('java/com/facebook/react/common:common'),
-    '//third-party/java/android/support/v4:lib-support-v4',
-    '//third-party/java/infer-annotations:infer-annotations',
-    '//third-party/java/jsr-305:jsr-305',
-    '//third-party/java/okhttp:okhttp',
-    '//third-party/java/okio:okio',
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':network',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/storage/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/storage/BUCK
deleted file mode 100644
index 723db50f703d..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/storage/BUCK
+++ /dev/null
@@ -1,21 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'storage',
-  srcs = glob(['**/*.java']),
-  deps = [
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/react/common:common'),
-    react_native_target('java/com/facebook/react/modules/common:common'),
-    '//libraries/fbcore/src/main/java/com/facebook/common/logging:logging',
-    '//third-party/java/infer-annotations:infer-annotations',
-    '//third-party/java/jsr-305:jsr-305',
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':storage',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK
deleted file mode 100644
index deac058df538..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK
+++ /dev/null
@@ -1,19 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'systeminfo',
-  srcs = glob(['**/*.java']),
-  deps = [
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/react/common:common'),
-    '//third-party/java/infer-annotations:infer-annotations',
-    '//third-party/java/jsr-305:jsr-305',
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':systeminfo',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/toast/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/toast/BUCK
deleted file mode 100644
index 497ef5bd03c9..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/toast/BUCK
+++ /dev/null
@@ -1,19 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'toast',
-  srcs = glob(['**/*.java']),
-  deps = [
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/react/common:common'),
-    '//third-party/java/infer-annotations:infer-annotations',
-    '//third-party/java/jsr-305:jsr-305',
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':toast',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/BUCK
deleted file mode 100644
index 92ab5d859e68..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/BUCK
+++ /dev/null
@@ -1,22 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'websocket',
-  srcs = glob(['**/*.java']),
-  deps = [
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/react/common:common'),
-    react_native_target('java/com/facebook/react/modules/core:core'),
-    '//libraries/fbcore/src/main/java/com/facebook/common/logging:logging',
-    '//third-party/java/infer-annotations:infer-annotations',
-    '//third-party/java/jsr-305:jsr-305',
-    '//third-party/java/okhttp:okhttp-ws',
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':websocket',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK
deleted file mode 100644
index 7043f36df502..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK
+++ /dev/null
@@ -1,43 +0,0 @@
-include_defs('//instrumentation_tests/DEFS')
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'shell',
-  srcs = glob(['**/*.java']),
-  deps = [
-    react_native_target('res:shell'),
-    react_native_target('java/com/facebook/react:react'),
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/react/common:common'),
-    react_native_target('java/com/facebook/react/devsupport:devsupport'),
-    react_native_target('java/com/facebook/react/views/drawer:drawer'),
-    react_native_target('java/com/facebook/react/views/image:image'),
-    react_native_target('java/com/facebook/react/views/progressbar:progressbar'),
-    react_native_target('java/com/facebook/react/views/scroll:scroll'),
-    react_native_target('java/com/facebook/react/views/switchview:switchview'),
-    react_native_target('java/com/facebook/react/views/text:text'),
-    react_native_target('java/com/facebook/react/views/textinput:textinput'),
-    react_native_target('java/com/facebook/react/views/toolbar:toolbar'),
-    react_native_target('java/com/facebook/react/views/view:view'),
-    react_native_target('java/com/facebook/react/views/viewpager:viewpager'),
-    react_native_target('java/com/facebook/react/modules/core:core'),
-    react_native_target('java/com/facebook/react/modules/debug:debug'),
-    react_native_target('java/com/facebook/react/modules/fresco:fresco'),
-    react_native_target('java/com/facebook/react/modules/network:network'),
-    react_native_target('java/com/facebook/react/modules/storage:storage'),
-    react_native_target('java/com/facebook/react/modules/toast:toast'),
-    react_native_target('java/com/facebook/react/uimanager:uimanager'),
-    react_native_target('java/com/facebook/react/modules/websocket:websocket'),
-    react_native_dep('libraries/soloader/java/com/facebook/soloader:soloader'),
-    react_native_dep('third-party/java/android/support/v4:lib-support-v4'),
-    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
-    react_native_dep('third-party/java/jsr-305:jsr-305'),
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':shell',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/touch/BUCK b/ReactAndroid/src/main/java/com/facebook/react/touch/BUCK
deleted file mode 100644
index 44cea8fdce54..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/touch/BUCK
+++ /dev/null
@@ -1,17 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'touch',
-  srcs = glob(['**/*.java']),
-  deps = [
-    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
-    react_native_dep('third-party/java/jsr-305:jsr-305'),
-  ],
-  visibility = [
-    'PUBLIC'
-  ],
-)
-
-project_config(
-  src_target = ':touch',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK
deleted file mode 100644
index 128e87f67c69..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK
+++ /dev/null
@@ -1,25 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'uimanager',
-  srcs = glob(['**/*.java']),
-  deps = [
-    '//libraries/fbcore/src/main/java/com/facebook/common/logging:logging',
-    react_native_target('java/com/facebook/react/animation:animation'),
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/react/common:common'),
-    react_native_target('java/com/facebook/csslayout:csslayout'),
-    react_native_target('java/com/facebook/react/touch:touch'),
-    react_native_dep('java/com/facebook/systrace:systrace'),
-    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
-    react_native_dep('third-party/java/jsr-305:jsr-305'),
-    react_native_dep('third-party/java/android/support/v4:lib-support-v4'),
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':uimanager',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/drawer/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/drawer/BUCK
deleted file mode 100644
index 1bef740699d7..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/views/drawer/BUCK
+++ /dev/null
@@ -1,22 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'drawer',
-  srcs = glob(['**/*.java']),
-  deps = [
-    react_native_target('java/com/facebook/csslayout:csslayout'),
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/react/common:common'),
-    react_native_target('java/com/facebook/react/uimanager:uimanager'),
-    react_native_target('java/com/facebook/react/views/scroll:scroll'),
-    react_native_dep('third-party/java/jsr-305:jsr-305'),
-    '//third-party/java/android/support/v4:lib-support-v4',
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':drawer',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/image/BUCK
deleted file mode 100644
index 52c2e0b1e8d0..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/views/image/BUCK
+++ /dev/null
@@ -1,29 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'image',
-  srcs = glob(['*.java']),
-  deps = [
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/react/uimanager:uimanager'),
-    '//libraries/drawee/src/main/java/com/facebook/drawee/controller:controller',
-    '//libraries/drawee/src/main/java/com/facebook/drawee/drawable:drawable',
-    '//libraries/drawee/src/main/java/com/facebook/drawee/generic:generic',
-    '//libraries/drawee/src/main/java/com/facebook/drawee/interfaces:interfaces',
-    '//libraries/drawee/src/main/java/com/facebook/drawee/view:view',
-    '//libraries/fbcore/src/main/java/com/facebook/common/references:references',
-    '//libraries/fbcore/src/main/java/com/facebook/common/util:util',
-    '//libraries/fresco/drawee-backends/drawee-pipeline/src/main/java/com/facebook/drawee/backends/pipeline:pipeline',
-    '//libraries/imagepipeline/src/main/java/com/facebook/imagepipeline/bitmaps:bitmaps',
-    '//libraries/imagepipeline/src/main/java/com/facebook/imagepipeline/common:common',
-    '//libraries/imagepipeline/src/main/java/com/facebook/imagepipeline/request:request',
-    '//third-party/java/jsr-305:jsr-305',
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':image',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/BUCK
deleted file mode 100644
index ef7fc96092cd..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/BUCK
+++ /dev/null
@@ -1,21 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'progressbar',
-  srcs = glob(['*.java']),
-  deps = [
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/react/common:common'),
-    react_native_target('java/com/facebook/csslayout:csslayout'),
-    react_native_target('java/com/facebook/react/uimanager:uimanager'),
-    '//third-party/java/infer-annotations:infer-annotations',
-    '//third-party/java/jsr-305:jsr-305',
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':progressbar',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/BUCK
deleted file mode 100644
index 54414c312e23..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/BUCK
+++ /dev/null
@@ -1,25 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'recyclerview',
-  srcs = glob(['**/*.java']),
-  deps = [
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/react/common:common'),
-    react_native_target('java/com/facebook/react/touch:touch'),
-    react_native_target('java/com/facebook/react/uimanager:uimanager'),
-    react_native_target('java/com/facebook/react/views/scroll:scroll'),
-    react_native_target('java/com/facebook/react/views/view:view'),
-    '//third-party/android-support-v7/recyclerview:recyclerview',
-    '//third-party/java/android/support/v4:lib-support-v4',
-    '//third-party/java/infer-annotations:infer-annotations',
-    '//third-party/java/jsr-305:jsr-305',
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':recyclerview',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/BUCK
deleted file mode 100644
index d087195129da..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/BUCK
+++ /dev/null
@@ -1,23 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'scroll',
-  srcs = glob(['*.java']),
-  deps = [
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/react/common:common'),
-    react_native_target('java/com/facebook/react/views/view:view'),
-    react_native_target('java/com/facebook/react/touch:touch'),
-    react_native_target('java/com/facebook/react/uimanager:uimanager'),
-    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
-    react_native_dep('third-party/java/jsr-305:jsr-305'),
-    react_native_dep('third-party/java/android/support/v4:lib-support-v4'),
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':scroll',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK
deleted file mode 100644
index 6c353cbe81ba..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK
+++ /dev/null
@@ -1,21 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'switchview',
-  srcs = glob(['*.java']),
-  deps = [
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/csslayout:csslayout'),
-    react_native_target('java/com/facebook/react/uimanager:uimanager'),
-    '//third-party/android-support-for-standalone-apps/v7/appcompat:appcompat-23.1',
-    '//third-party/android-support-for-standalone-apps/v7/appcompat:res-for-react-native',
-    '//third-party/java/jsr-305:jsr-305',
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':switchview',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK
deleted file mode 100644
index cd0f60c1b3c5..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK
+++ /dev/null
@@ -1,21 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'text',
-  srcs = glob(['*.java']),
-  deps = [
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/react/common:common'),
-    react_native_target('java/com/facebook/csslayout:csslayout'),
-    react_native_target('java/com/facebook/react/uimanager:uimanager'),
-    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
-    react_native_dep('third-party/java/jsr-305:jsr-305'),
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':text',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/BUCK
deleted file mode 100644
index 4c7142f68d38..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/BUCK
+++ /dev/null
@@ -1,23 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'textinput',
-  srcs = glob(['*.java']),
-  deps = [
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/react/common:common'),
-    react_native_target('java/com/facebook/react/views/text:text'),
-    react_native_target('java/com/facebook/csslayout:csslayout'),
-    react_native_target('java/com/facebook/react/modules/core:core'),
-    react_native_target('java/com/facebook/react/uimanager:uimanager'),
-    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
-    react_native_dep('third-party/java/jsr-305:jsr-305'),
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':textinput',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK
deleted file mode 100644
index 35a06f331104..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK
+++ /dev/null
@@ -1,33 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'toolbar',
-  srcs = glob(['**/*.java']),
-  deps = [
-    react_native_target('java/com/facebook/csslayout:csslayout'),
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/react/uimanager:uimanager'),
-    react_native_target('java/com/facebook/react/common:common'),
-    react_native_dep('third-party/java/jsr-305:jsr-305'),
-    '//libraries/imagepipeline/src/main/java/com/facebook/imagepipeline/bitmaps:bitmaps',
-    '//libraries/imagepipeline/src/main/java/com/facebook/imagepipeline/common:common',
-    '//libraries/imagepipeline/src/main/java/com/facebook/imagepipeline/request:request',
-    '//libraries/imagepipeline/src/main/java/com/facebook/imagepipeline/image:image',
-    '//libraries/drawee/src/main/java/com/facebook/drawee/controller:controller',
-    '//libraries/drawee/src/main/java/com/facebook/drawee/drawable:drawable',
-    '//libraries/drawee/src/main/java/com/facebook/drawee/generic:generic',
-    '//libraries/drawee/src/main/java/com/facebook/drawee/interfaces:interfaces',
-    '//libraries/drawee/src/main/java/com/facebook/drawee/view:view',
-    '//libraries/fresco/drawee-backends/drawee-pipeline/src/main/java/com/facebook/drawee/backends/pipeline:pipeline',
-    '//third-party/android-support-for-standalone-apps/v7/appcompat:appcompat-23.1',
-    '//third-party/android-support-for-standalone-apps/v7/appcompat:res-for-react-native',
-    '//third-party/java/android/support/v4:lib-support-v4',
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':toolbar',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/view/BUCK
deleted file mode 100644
index 428372baa2e4..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/BUCK
+++ /dev/null
@@ -1,22 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'view',
-  srcs = glob(['*.java']),
-  deps = [
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/react/common:common'),
-    react_native_target('java/com/facebook/csslayout:csslayout'),
-    react_native_target('java/com/facebook/react/touch:touch'),
-    react_native_target('java/com/facebook/react/uimanager:uimanager'),
-    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
-    react_native_dep('third-party/java/jsr-305:jsr-305'),
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':view',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/BUCK
deleted file mode 100644
index 8b0b881fa0a4..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/BUCK
+++ /dev/null
@@ -1,21 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'viewpager',
-  srcs = glob(['**/*.java']),
-  deps = [
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('java/com/facebook/react/common:common'),
-    react_native_target('java/com/facebook/react/uimanager:uimanager'),
-    react_native_target('java/com/facebook/react/views/scroll:scroll'),
-    '//third-party/java/android/support/v4:lib-support-v4',
-    '//third-party/java/jsr-305:jsr-305',
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':viewpager',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/soloader/BUCK b/ReactAndroid/src/main/java/com/facebook/soloader/BUCK
deleted file mode 100644
index 322ba2204e20..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/soloader/BUCK
+++ /dev/null
@@ -1,20 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_library(
-  name = 'soloader',
-  srcs = glob(['*.java']),
-  proguard_config = 'soloader.pro',
-  deps = [
-    react_native_dep('third-party/java/jsr-305:jsr-305'),
-    # Be very careful adding new dependencies here, because this code
-    # has to run very early in the app startup process.
-    # Definitely do *not* depend on lib-base or guava.
-  ],
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':soloader',
-)
diff --git a/ReactAndroid/src/main/java/com/facebook/systrace/BUCK b/ReactAndroid/src/main/java/com/facebook/systrace/BUCK
deleted file mode 100644
index 6d222bb2a0f5..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/systrace/BUCK
+++ /dev/null
@@ -1,11 +0,0 @@
-android_library(
-  name = 'systrace',
-  srcs = glob(['*.java']),
-  visibility = [
-    'PUBLIC',
-  ],
-)
-
-project_config(
-  src_target = ':systrace',
-)
diff --git a/ReactAndroid/src/main/jni/react/BUCK b/ReactAndroid/src/main/jni/react/BUCK
deleted file mode 100644
index 14e7e8ffe550..000000000000
--- a/ReactAndroid/src/main/jni/react/BUCK
+++ /dev/null
@@ -1,57 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-# We depend on JSC, support the same platforms
-SUPPORTED_PLATFORMS = '^android-(armv7|x86)$'
-
-cxx_library(
-  name = 'react',
-  soname = 'libreactnative.so',
-  header_namespace = 'react',
-  supported_platforms_regex = SUPPORTED_PLATFORMS,
-  force_static = True,
-  srcs = [
-    'Bridge.cpp',
-    'Value.cpp',
-    'MethodCall.cpp',
-    'JSCHelpers.cpp',
-    'JSCExecutor.cpp',
-    'JSCTracing.cpp',
-    'JSCPerfLogging.cpp',
-    'JSCLegacyProfiler.cpp',
-  ],
-  headers = [
-    'JSCTracing.h',
-    'JSCPerfLogging.h',
-    'JSCLegacyProfiler.h',
-  ],
-  exported_headers = [
-    'Bridge.h',
-    'Executor.h',
-    'JSCExecutor.h',
-    'JSCHelpers.h',
-    'MethodCall.h',
-    'Value.h',
-  ],
-  preprocessor_flags = [
-    '-DLOG_TAG="ReactNative"',
-    '-DWITH_JSC_EXTRA_TRACING=1',
-    '-DWITH_FBSYSTRACE=1',
-  ],
-  compiler_flags = [
-    '-Wall',
-    '-std=c++11',
-    '-fexceptions',
-    '-fvisibility=hidden',
-  ],
-  visibility = [
-    react_native_target('jni/react/jni:jni'),
-  ],
-  deps = [
-    '//native/fb:fb',
-    '//xplat/fbsystrace:fbsystrace',
-    '//native/jni:jni',
-    '//native/third-party/jsc:jsc',
-    '//native/third-party/jsc:jsc_legacy_profiler',
-    '//xplat/folly:json',
-  ],
-)
diff --git a/ReactAndroid/src/main/jni/react/jni/BUCK b/ReactAndroid/src/main/jni/react/jni/BUCK
deleted file mode 100644
index b70ecf239e74..000000000000
--- a/ReactAndroid/src/main/jni/react/jni/BUCK
+++ /dev/null
@@ -1,53 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-# We depend on JSC, support the same platforms
-SUPPORTED_PLATFORMS = '^android-(armv7|x86)$'
-
-cxx_library(
-  name = 'jni',
-  soname = 'libreactnativejni.so',
-  header_namespace = 'react/jni',
-  supported_platforms_regex = SUPPORTED_PLATFORMS,
-  srcs = [
-    'NativeArray.cpp',
-    'OnLoad.cpp',
-    'ProxyExecutor.cpp',
-    'JSLoader.cpp',
-  ],
-  headers = [
-    'ProxyExecutor.h',
-    'JSLoader.h',
-  ],
-  exported_headers = [
-    'NativeArray.h',
-    'ReadableNativeArray.h',
-  ],
-  preprocessor_flags = [
-    '-DLOG_TAG="ReactNativeJNI"',
-    '-DWITH_FBSYSTRACE=1',
-  ],
-  compiler_flags = [
-    '-Wall',
-    '-Werror',
-    '-fexceptions',
-    '-std=c++11',
-    '-fvisibility=hidden',
-    '-frtti',
-  ],
-  visibility = [
-    react_native_target('java/com/facebook/react/bridge:bridge'),
-    react_native_target('jni/react/...'),
-    react_native_dep('native/react/...')
-  ],
-  deps = [
-    react_native_target('jni/react:react'),
-    '//native/jni:jni',
-    '//native/third-party/jsc:jsc',
-    '//native/third-party/jsc:jsc_legacy_profiler',
-    '//xplat/folly:json',
-  ],
-)
-
-project_config(
-  src_target = ':jni',
-)
diff --git a/ReactAndroid/src/main/jni/react/perftests/BUCK b/ReactAndroid/src/main/jni/react/perftests/BUCK
deleted file mode 100644
index 6358592fb5ee..000000000000
--- a/ReactAndroid/src/main/jni/react/perftests/BUCK
+++ /dev/null
@@ -1,21 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-cxx_library(
-  name = 'perftests',
-  srcs = [ 'OnLoad.cpp' ],
-  soname = 'libreactnativetests.so',
-  preprocessor_flags = [
-    '-DLOG_TAG=\"ReactPerftests\"',
-  ],
-  visibility = [
-    '//instrumentation_tests/com/facebook/catalyst/...',
-  ],
-  deps = [
-    '//native:base',
-    '//native/jni:jni',
-  ],
-)
-
-project_config(
-  src_target = ':perftests',
-)
diff --git a/ReactAndroid/src/main/res/BUCK b/ReactAndroid/src/main/res/BUCK
deleted file mode 100644
index 90f796a13ee2..000000000000
--- a/ReactAndroid/src/main/res/BUCK
+++ /dev/null
@@ -1,19 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-android_resource(
-  name = 'devsupport',
-  res = 'devsupport',
-  package = 'com.facebook.react',
-  visibility = [
-    react_native_target('java/com/facebook/react/devsupport/...'),
-  ],
-)
-
-android_resource(
-  name = 'shell',
-  res = 'shell',
-  package = 'com.facebook.react',
-  visibility = [
-    'PUBLIC',
-  ],
-)

From c0c8e7cfdf83b3a215f15257892f892604eff431 Mon Sep 17 00:00:00 2001
From: Denis Koroskin <dkoroskin@fb.com>
Date: Wed, 9 Dec 2015 12:34:24 -0800
Subject: [PATCH 0291/1411] Add support for `double` type in ReactPropGroup

Reviewed By: astreet

Differential Revision: D2735362

fb-gh-sync-id: a8eab400248fc4c8ad5d43e6a34cfd350dfb1d26
---
 .../com/facebook/react/uimanager/ReactPropGroup.java  | 10 +++++++++-
 .../react/uimanager/ViewManagersPropertyCache.java    | 11 +++++++++++
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactPropGroup.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactPropGroup.java
index 13c843314a04..9e2a17b6e6d0 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactPropGroup.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactPropGroup.java
@@ -26,7 +26,8 @@
  * group of the property being updated. Last, third argument represent the value that should be set.
  *
  *
- * Currently only {@code int}, {@code float} and {@link String} value types are supported.
+ * Currently only {@code int}, {@code float}, {@code double} and {@link String} value types are
+ * supported.
  *
  * In case when property has been removed from the corresponding react component annotated setter
  * will be called and default value will be provided as a value parameter. Default value can be
@@ -68,6 +69,13 @@
    */
   float defaultFloat() default 0.0f;
 
+  /**
+   * Default value for property of type {@code double}. This value will be provided to property
+   * setter method annotated with {@link ReactPropGroup} if property with a given name gets removed
+   * from the component description in JS
+   */
+  double defaultDouble() default 0.0;
+
   /**
    * Default value for property of type {@code int}. This value will be provided to property
    * setter method annotated with {@link ReactPropGroup} if property with a given name gets removed
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagersPropertyCache.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagersPropertyCache.java
index fd0ce6c41e49..0e2a33148d60 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagersPropertyCache.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagersPropertyCache.java
@@ -141,6 +141,11 @@ public DoublePropSetter(ReactProp prop, Method setter, double defaultValue) {
       mDefaultValue = defaultValue;
     }
 
+    public DoublePropSetter(ReactPropGroup prop, Method setter, int index, double defaultValue) {
+      super(prop, "number", setter, index);
+      mDefaultValue = defaultValue;
+    }
+
     @Override
     protected Object extractProperty(CatalystStylesDiffMap props) {
       return props.getDouble(mPropName, mDefaultValue);
@@ -366,6 +371,12 @@ private static void createPropSetters(
             names[i],
             new FloatPropSetter(annotation, method, i, annotation.defaultFloat()));
       }
+    } else if (propTypeClass == double.class) {
+      for (int i = 0; i < names.length; i++) {
+        props.put(
+            names[i],
+            new DoublePropSetter(annotation, method, i, annotation.defaultDouble()));
+      }
     } else if (propTypeClass == Integer.class) {
       for (int i = 0; i < names.length; i++) {
         props.put(

From 053a2294b872636ab65d8abdd433323158744c39 Mon Sep 17 00:00:00 2001
From: Thomas Parslow <tom@almostobsolete.net>
Date: Wed, 9 Dec 2015 12:58:52 -0800
Subject: [PATCH 0292/1411] Add taggedTemplateLiteral to babelHelpers

Summary:
Needed to support tagged template literals (which are already enabled in babel). Not having this helper means we get a runtime crash.
Closes https://github.com/facebook/react-native/pull/4680

Reviewed By: svcscm

Differential Revision: D2740233

Pulled By: spicyj

fb-gh-sync-id: 12729f670b7942ad7a04bd50ae1eca35d2b1e410
---
 .../src/Resolver/polyfills/babelHelpers.js             | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/packager/react-packager/src/Resolver/polyfills/babelHelpers.js b/packager/react-packager/src/Resolver/polyfills/babelHelpers.js
index a7fac6bcd6ab..e028a782000b 100644
--- a/packager/react-packager/src/Resolver/polyfills/babelHelpers.js
+++ b/packager/react-packager/src/Resolver/polyfills/babelHelpers.js
@@ -11,7 +11,7 @@
 /* eslint-disable strict */
 
 // Created by running:
-// require('babel-core').buildExternalHelpers('_extends classCallCheck createClass createRawReactElement defineProperty get inherits  interopRequireDefault interopRequireWildcard objectWithoutProperties possibleConstructorReturn slicedToArray toConsumableArray'.split(' '))
+// require('babel-core').buildExternalHelpers('_extends classCallCheck createClass createRawReactElement defineProperty get inherits  interopRequireDefault interopRequireWildcard objectWithoutProperties possibleConstructorReturn slicedToArray taggedTemplateLiteral toConsumableArray '.split(' '))
 // then replacing the `global` reference in the last line to also use `this`.
 //
 // actually, that's a lie, because babel6 omits _extends and createRawReactElement
@@ -207,6 +207,14 @@
       }
     };
   })();
+  
+  babelHelpers.taggedTemplateLiteral = function (strings, raw) {
+    return Object.freeze(Object.defineProperties(strings, {
+      raw: {
+        value: Object.freeze(raw)
+      }
+    }));
+  };
 
   babelHelpers.toConsumableArray = function (arr) {
     if (Array.isArray(arr)) {

From fe3686e126ee66adc6b2e44b46ba82e5ae6c434c Mon Sep 17 00:00:00 2001
From: David Anderson <github@davidanderson.io>
Date: Wed, 9 Dec 2015 14:06:16 -0800
Subject: [PATCH 0293/1411] Fix asset httpServerLocation on Windows.

Summary:
Functions from the path module return paths with the native file system path separator. generateAssetModule is using path.join and path.dirname to generate httpServerLocation.  That means that on Windows systems, the generated URL path has backslashes rather than forward slashes which breaks the app's ability to retrieve image assets using require('./image.png').  This change fixes this by checking path.sep and replacing backslashes with slashes on systems that require it.
Closes https://github.com/facebook/react-native/pull/4416

Reviewed By: svcscm

Differential Revision: D2740529

Pulled By: mkonicek

fb-gh-sync-id: edae0f6762c7dc1db7af078209e38a2feab1e0a1
---
 packager/react-packager/src/Bundler/index.js | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index ffe17735626d..470c6821c809 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -364,6 +364,12 @@ class Bundler {
 
   generateAssetModule(bundle, module, platform = null) {
     const relPath = getPathRelativeToRoot(this._projectRoots, module.path);
+    var assetUrlPath = path.join('/assets', path.dirname(relPath));
+    
+    // On Windows, change backslashes to slashes to get proper URL path from file path.
+    if (path.sep === '\\') {
+      assetUrlPath = assetUrlPath.replace(/\\/g, '/');
+    }
 
     return Promise.all([
       sizeOf(module.path),
@@ -374,7 +380,7 @@ class Bundler {
       const img = {
         __packager_asset: true,
         fileSystemLocation: path.dirname(module.path),
-        httpServerLocation: path.join('/assets', path.dirname(relPath)),
+        httpServerLocation: assetUrlPath,
         width: dimensions.width / module.resolution,
         height: dimensions.height / module.resolution,
         scales: assetData.scales,

From f9f123ba96fea76bce6b21aabb5da4d79ee26db7 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Wed, 9 Dec 2015 22:32:20 +0000
Subject: [PATCH 0294/1411] Sync internal shrinkwrap file to github

---
 npm-shrinkwrap.json | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index ae8e80071546..630e9cded87e 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -4377,9 +4377,9 @@
       }
     },
     "react-haste": {
-      "version": "0.14.0",
-      "from": "react-haste@0.14.0",
-      "resolved": "https://registry.npmjs.org/react-haste/-/react-haste-0.14.0.tgz"
+      "version": "0.14.2",
+      "from": "react-haste@0.14.2",
+      "resolved": "https://registry.npmjs.org/react-haste/-/react-haste-0.14.2.tgz"
     },
     "react-timer-mixin": {
       "version": "0.13.2",

From 139f9945dfdc37bd37709cfbdf3f54a72a056bdb Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Wed, 9 Dec 2015 14:51:43 -0800
Subject: [PATCH 0295/1411] Don't use arrow functions with Flow types to fix
 website generation

Summary:
Our custom jsdocs parser doesn't support the syntax yet.

public

Reviewed By: bestander

Differential Revision: D2739861

fb-gh-sync-id: eefc3c54b98e06597ca7d93396aa4fe3a92d4a58
---
 Examples/UIExplorer/NetInfoExample.js | 2 +-
 Libraries/Network/NetInfo.js          | 8 ++++++--
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/Examples/UIExplorer/NetInfoExample.js b/Examples/UIExplorer/NetInfoExample.js
index af120c591153..a79ed67e2043 100644
--- a/Examples/UIExplorer/NetInfoExample.js
+++ b/Examples/UIExplorer/NetInfoExample.js
@@ -176,7 +176,7 @@ exports.examples = [
   {
     platform: 'android',
     title: 'NetInfo.isConnectionExpensive (Android)',
-    description: 'Asycnronously check isConnectionExpensive',
+    description: 'Asynchronously check isConnectionExpensive',
     render(): ReactElement { return <IsConnectionExpensive />; }
   },
 ];
diff --git a/Libraries/Network/NetInfo.js b/Libraries/Network/NetInfo.js
index d4295754f259..fff16c59860f 100644
--- a/Libraries/Network/NetInfo.js
+++ b/Libraries/Network/NetInfo.js
@@ -58,11 +58,15 @@ const _subscriptions = new Map();
 
 let _isConnected;
 if (Platform.OS === 'ios') {
-  _isConnected = (reachability: ReachabilityStateIOS): bool => {
+  _isConnected = function(
+    reachability: ReachabilityStateIOS,
+  ): bool {
     return reachability !== 'none' && reachability !== 'unknown';
   };
 } else if (Platform.OS === 'android') {
-  _isConnected = (connectionType: ConnectivityStateAndroid) : bool => {
+  _isConnected = function(
+      connectionType: ConnectivityStateAndroid,
+    ): bool {
     return connectionType !== 'NONE' && connectionType !== 'UNKNOWN';
   };
 }

From 2aa3e0dd1a70c81a7d50361cb1b409dd2c3a1b16 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Wed, 9 Dec 2015 15:16:15 -0800
Subject: [PATCH 0296/1411] Use the new Android Clipboard module

Summary:
public

- Open source the unit test for `ClipboardModule`, start using the `ReactTestHelper` in two unit tests
- Fixes a few references to "pasteboard" in strings

Reviewed By: bestander

Differential Revision: D2739614

fb-gh-sync-id: e076940a3ae5c22314e181a37fe2c3f77a18cf85
---
 ...stTestHelper.java => ReactTestHelper.java} |  2 +-
 .../clipboard/ClipboardModuleTest.java        | 61 +++++++++++++++++++
 .../storage/AsyncStorageModuleTest.java       | 12 +---
 3 files changed, 64 insertions(+), 11 deletions(-)
 rename ReactAndroid/src/test/java/com/facebook/react/bridge/{CatalystTestHelper.java => ReactTestHelper.java} (98%)
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/modules/clipboard/ClipboardModuleTest.java

diff --git a/ReactAndroid/src/test/java/com/facebook/react/bridge/CatalystTestHelper.java b/ReactAndroid/src/test/java/com/facebook/react/bridge/ReactTestHelper.java
similarity index 98%
rename from ReactAndroid/src/test/java/com/facebook/react/bridge/CatalystTestHelper.java
rename to ReactAndroid/src/test/java/com/facebook/react/bridge/ReactTestHelper.java
index 27a1b7a9fee7..0aa236ddb9f6 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/bridge/CatalystTestHelper.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/bridge/ReactTestHelper.java
@@ -24,7 +24,7 @@
 /**
  * Utility for creating pre-configured instances of core react components for tests.
  */
-public class CatalystTestHelper {
+public class ReactTestHelper {
 
   /**
    * @return a ReactApplicationContext that has a CatalystInstance mock returned by
diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/clipboard/ClipboardModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/clipboard/ClipboardModuleTest.java
new file mode 100644
index 000000000000..0486ae79f82f
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/modules/clipboard/ClipboardModuleTest.java
@@ -0,0 +1,61 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.modules.clipboard;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.text.ClipboardManager;
+
+import com.facebook.react.bridge.ReactTestHelper;
+import com.facebook.react.modules.clipboard.ClipboardModule;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+@SuppressLint({"ClipboardManager", "DeprecatedClass"})
+@RunWith(RobolectricTestRunner.class)
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+public class ClipboardModuleTest {
+
+  private static final String TEST_CONTENT = "test";
+
+  private ClipboardModule mClipboardModule;
+  private ClipboardManager mClipboardManager;
+
+  @Before
+  public void setUp() {
+    mClipboardModule = new ClipboardModule(ReactTestHelper.createCatalystContextForTest());
+    mClipboardManager =
+        (ClipboardManager) RuntimeEnvironment.application.getSystemService(Context.CLIPBOARD_SERVICE);
+  }
+
+  @Test
+  public void testSetString() {
+    mClipboardModule.setString(TEST_CONTENT);
+    assertTrue(mClipboardManager.getText().equals(TEST_CONTENT));
+
+    mClipboardModule.setString(null);
+    assertFalse(mClipboardManager.hasText());
+
+    mClipboardModule.setString("");
+    assertFalse(mClipboardManager.hasText());
+
+    mClipboardModule.setString(" ");
+    assertTrue(mClipboardManager.hasText());
+  }
+}
diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/storage/AsyncStorageModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/storage/AsyncStorageModuleTest.java
index c11e9ba932a4..819aececc8f7 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/modules/storage/AsyncStorageModuleTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/modules/storage/AsyncStorageModuleTest.java
@@ -20,12 +20,12 @@
 import com.facebook.react.bridge.Arguments;
 import com.facebook.react.bridge.Callback;
 import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactTestHelper;
 import com.facebook.react.bridge.SimpleArray;
 import com.facebook.react.bridge.SimpleMap;
 import com.facebook.react.modules.storage.AsyncStorageModule;
 import com.facebook.react.modules.storage.ReactDatabaseSupplier;
 
-
 import org.json.JSONArray;
 import org.json.JSONObject;
 import org.junit.After;
@@ -60,13 +60,6 @@ public class AsyncStorageModuleTest {
   private AsyncStorageModule mStorage;
   private SimpleArray mEmptyArray;
 
-  private static class FakeFragmentContext extends ContextWrapper {
-
-    public FakeFragmentContext(Context base) {
-      super(base);
-    }
-  }
-
   @Rule
   public PowerMockRule rule = new PowerMockRule();
 
@@ -90,8 +83,7 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
      });
 
     // don't use Robolectric before initializing mocks
-    mStorage = new AsyncStorageModule(new ReactApplicationContext(
-      new FakeFragmentContext(RuntimeEnvironment.application)));
+    mStorage = new AsyncStorageModule(ReactTestHelper.createCatalystContextForTest());
     mEmptyArray = new SimpleArray();
   }
 

From 64a78ed74b20a93d1272d9958a1cbfd6060604ad Mon Sep 17 00:00:00 2001
From: Siddu Duddikunta <siddu@siddu.me>
Date: Wed, 9 Dec 2015 15:49:36 -0800
Subject: [PATCH 0297/1411] Fix bug in Android elevation implementation

Summary:
If border radius is not set or is zero, then elevation will not
work properly. This bug seems to have been introduced when the
style in facebook/react-native#4180 was modified slightly to
produce commit b65f1f223488b52963f80a67bb41956103263d27.
Closes https://github.com/facebook/react-native/pull/4555

Reviewed By: svcscm

Differential Revision: D2741203

Pulled By: mkonicek

fb-gh-sync-id: f4ee9ccdfc64374d58824a6e988409ac2b7532a4
---
 .../facebook/react/views/view/ReactViewBackgroundDrawable.java  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java
index 4a8805614e5c..6ded1123d4b6 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java
@@ -138,7 +138,7 @@ public void getOutline(Outline outline) {
               : 0;
       outline.setRoundRect(getBounds(), mBorderRadius + extraRadiusFromBorderWidth);
     } else {
-      super.getOutline(outline);
+      outline.setRect(getBounds());
     }
   }
 

From 96553cf553e26e48a87f83030e04aef788f2dfef Mon Sep 17 00:00:00 2001
From: Felipe Martim <felipe@martim.me>
Date: Wed, 9 Dec 2015 16:06:53 -0800
Subject: [PATCH 0298/1411] Add rotateX and rotateY transforms to Android Views
 .

Summary:
Setting rotateX and rotateY for Android Views.
Closes https://github.com/facebook/react-native/pull/4413

Reviewed By: svcscm

Differential Revision: D2741328

Pulled By: mkonicek

fb-gh-sync-id: 931027c006bc571ef374a7b82cc7074b8a34bc8d
---
 Libraries/Utilities/MatrixMath.js                         | 6 ++++--
 .../com/facebook/react/uimanager/BaseViewManager.java     | 8 ++++++++
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/Libraries/Utilities/MatrixMath.js b/Libraries/Utilities/MatrixMath.js
index e248ba75dc87..addc8660ef47 100755
--- a/Libraries/Utilities/MatrixMath.js
+++ b/Libraries/Utilities/MatrixMath.js
@@ -465,10 +465,10 @@ var MatrixMath = {
 
       // Solve the equation by inverting perspectiveMatrix and multiplying
       // rightHandSide by the inverse.
-      var inversePerspectiveMatrix = MatrixMath.inverse3x3(
+      var inversePerspectiveMatrix = MatrixMath.inverse(
         perspectiveMatrix
       );
-      var transposedInversePerspectiveMatrix = MatrixMath.transpose4x4(
+      var transposedInversePerspectiveMatrix = MatrixMath.transpose(
         inversePerspectiveMatrix
       );
       var perspective = MatrixMath.multiplyVectorByMatrix(
@@ -583,6 +583,8 @@ var MatrixMath = {
       translation,
 
       rotate: rotationDegrees[2],
+      rotateX: rotationDegrees[0],
+      rotateY: rotationDegrees[1],
       scaleX: scale[0],
       scaleY: scale[1],
       translateX: translation[0],
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java
index c5dcaa700736..201effea750e 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java
@@ -18,6 +18,8 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
   private static final String PROP_BACKGROUND_COLOR = ViewProps.BACKGROUND_COLOR;
   private static final String PROP_DECOMPOSED_MATRIX = "decomposedMatrix";
   private static final String PROP_DECOMPOSED_MATRIX_ROTATE = "rotate";
+  private static final String PROP_DECOMPOSED_MATRIX_ROTATE_X = "rotateX";
+  private static final String PROP_DECOMPOSED_MATRIX_ROTATE_Y = "rotateY";
   private static final String PROP_DECOMPOSED_MATRIX_SCALE_X = "scaleX";
   private static final String PROP_DECOMPOSED_MATRIX_SCALE_Y = "scaleY";
   private static final String PROP_DECOMPOSED_MATRIX_TRANSLATE_X = "translateX";
@@ -144,6 +146,10 @@ private static void setTransformMatrix(View view, ReadableMap matrix) {
             (float) matrix.getDouble(PROP_DECOMPOSED_MATRIX_TRANSLATE_Y)));
     view.setRotation(
         (float) matrix.getDouble(PROP_DECOMPOSED_MATRIX_ROTATE));
+    view.setRotationX(
+        (float) matrix.getDouble(PROP_DECOMPOSED_MATRIX_ROTATE_X));
+    view.setRotationY(
+        (float) matrix.getDouble(PROP_DECOMPOSED_MATRIX_ROTATE_Y));
     view.setScaleX(
         (float) matrix.getDouble(PROP_DECOMPOSED_MATRIX_SCALE_X));
     view.setScaleY(
@@ -154,6 +160,8 @@ private static void resetTransformMatrix(View view) {
     view.setTranslationX(PixelUtil.toPixelFromDIP(0));
     view.setTranslationY(PixelUtil.toPixelFromDIP(0));
     view.setRotation(0);
+    view.setRotationX(0);
+    view.setRotationY(0);
     view.setScaleX(1);
     view.setScaleY(1);
   }

From 96c9ce811a7bbd3287b668adf726923e600414f0 Mon Sep 17 00:00:00 2001
From: Spencer Ahrens <sahrens@fb.com>
Date: Wed, 9 Dec 2015 17:16:29 -0800
Subject: [PATCH 0299/1411] Fix Text + TouchableWithoutFeedback

Summary:
Arrow functions don't have `arguments`...whoops :(

public

Reviewed By: vjeux, ericvicenti

Differential Revision: D2741448

fb-gh-sync-id: 15e9fb0446909e4cbbbb5e30024dde58d872e725
---
 Libraries/Text/Text.js | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/Libraries/Text/Text.js b/Libraries/Text/Text.js
index 69dc800ded6f..8d9f68fba864 100644
--- a/Libraries/Text/Text.js
+++ b/Libraries/Text/Text.js
@@ -181,35 +181,35 @@ const Text = React.createClass({
             }
             return setResponder;
           },
-          onResponderGrant: (e: SyntheticEvent, dispatchID: string) => {
+          onResponderGrant: function(e: SyntheticEvent, dispatchID: string) {
             this.touchableHandleResponderGrant(e, dispatchID);
             this.props.onResponderGrant &&
               this.props.onResponderGrant.apply(this, arguments);
-          },
-          onResponderMove: (e: SyntheticEvent) => {
+          }.bind(this),
+          onResponderMove: function(e: SyntheticEvent) {
             this.touchableHandleResponderMove(e);
             this.props.onResponderMove &&
               this.props.onResponderMove.apply(this, arguments);
-          },
-          onResponderRelease: (e: SyntheticEvent) => {
+          }.bind(this),
+          onResponderRelease: function(e: SyntheticEvent) {
             this.touchableHandleResponderRelease(e);
             this.props.onResponderRelease &&
               this.props.onResponderRelease.apply(this, arguments);
-          },
-          onResponderTerminate: (e: SyntheticEvent) => {
+          }.bind(this),
+          onResponderTerminate: function(e: SyntheticEvent) {
             this.touchableHandleResponderTerminate(e);
             this.props.onResponderTerminate &&
               this.props.onResponderTerminate.apply(this, arguments);
-          },
-          onResponderTerminationRequest: (): bool => {
+          }.bind(this),
+          onResponderTerminationRequest: function(): bool {
             // Allow touchable or props.onResponderTerminationRequest to deny
             // the request
             var allowTermination = this.touchableHandleResponderTerminationRequest();
             if (allowTermination && this.props.onResponderTerminationRequest) {
-              allowTermination = this.props.onResponderTerminationRequest();
+              allowTermination = this.props.onResponderTerminationRequest.apply(this, arguments);
             }
             return allowTermination;
-          },
+          }.bind(this),
         };
       }
       newProps = {

From 423202072c31aaa5a952bff092a2b8307995a0cb Mon Sep 17 00:00:00 2001
From: Qiao Liang <qiaoliang89@gmail.com>
Date: Wed, 9 Dec 2015 22:38:28 -0800
Subject: [PATCH 0300/1411] fix android movie example by adding missing
 permission

Summary:
```log
12-10 04:15:40.321 1482-1482/com.facebook.react.movies E/AndroidRuntime: FATAL EXCEPTION: main
                                                                         Process: com.facebook.react.movies, PID: 1482
                                                                         java.lang.RuntimeException: Error receiving broadcast Intent { act=android.net.conn.CONNECTIVITY_CHANGE flg=0x4000010 (has extras) } in com.facebook.react.modules.netinfo.ConnectivityModule$ConnectivityBroadcastReceiver@529210a0
                                                                             at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:778)
                                                                             at android.os.Handler.handleCallback(Handler.java:733)
                                                                             at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                             at
Closes https://github.com/facebook/react-native/pull/4694

Reviewed By: svcscm

Differential Revision: D2743536

Pulled By: androidtrunkagent

fb-gh-sync-id: 7d93ca701c3d6b17add370ab13a68b150910e6a6
---
 Examples/Movies/android/app/src/main/AndroidManifest.xml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Examples/Movies/android/app/src/main/AndroidManifest.xml b/Examples/Movies/android/app/src/main/AndroidManifest.xml
index 2123d078fdf1..185ffa506021 100644
--- a/Examples/Movies/android/app/src/main/AndroidManifest.xml
+++ b/Examples/Movies/android/app/src/main/AndroidManifest.xml
@@ -2,6 +2,7 @@
     package="com.facebook.react.movies">
 
     <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
 
     <application
       android:allowBackup="true"

From 5775d9e1d00b4c919ee97bdf780c42bab7cb2d5e Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Thu, 10 Dec 2015 02:57:33 -0800
Subject: [PATCH 0301/1411] Update touch/measure/hotspot to all use same
 coordinate space

Reviewed By: astreet

Differential Revision: D2731165

fb-gh-sync-id: 729943233af66f139907cac2002fed4038b3fa6a
---
 .../uimanager/NativeViewHierarchyManager.java | 11 ++++-
 .../react/uimanager/events/TouchesHelper.java | 42 ++++++++++++-------
 .../react/views/view/ReactViewManager.java    |  6 +--
 3 files changed, 37 insertions(+), 22 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
index ad195004333d..dd40b7a16a95 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
@@ -466,8 +466,15 @@ public void measure(int tag, int[] outputBuffer) {
       throw new NoSuchNativeViewException("No native view for " + tag + " currently exists");
     }
 
-    // Puts x/y in outputBuffer[0]/[1]
-    v.getLocationOnScreen(outputBuffer);
+    View rootView = (View) RootViewUtil.getRootView(v);
+    rootView.getLocationInWindow(outputBuffer);
+    int rootX = outputBuffer[0];
+    int rootY = outputBuffer[1];
+
+    v.getLocationInWindow(outputBuffer);
+
+    outputBuffer[0] = outputBuffer[0] - rootX;
+    outputBuffer[1] = outputBuffer[1] - rootY;
     outputBuffer[2] = v.getWidth();
     outputBuffer[3] = v.getHeight();
   }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchesHelper.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchesHelper.java
index e431fa7aeaeb..d312a402026b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchesHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchesHelper.java
@@ -35,25 +35,35 @@
    * given {@param event} instance. This method use {@param reactTarget} parameter to set as a
    * target view id associated with current gesture.
    */
-  private static WritableArray createsPointersArray(int reactTarget, TouchEvent touchEvent) {
-    MotionEvent event = touchEvent.getMotionEvent();
-
+  private static WritableArray createsPointersArray(int reactTarget, TouchEvent event) {
     WritableArray touches = Arguments.createArray();
-
-    // Calculate raw-to-relative offset as getRawX() and getRawY() can only return values for the
-    // pointer at index 0. We use those value to calculate "raw" coordinates for other pointers
-    float offsetX = event.getRawX() - event.getX();
-    float offsetY = event.getRawY() - event.getY();
-
-    for (int index = 0; index < event.getPointerCount(); index++) {
+    MotionEvent motionEvent = event.getMotionEvent();
+
+    // Calculate the coordinates for the target view.
+    // The MotionEvent contains the X,Y of the touch in the coordinate space of the root view
+    // The TouchEvent contains the X,Y of the touch in the coordinate space of the target view
+    // Subtracting them allows us to get the coordinates of the target view's top left corner
+    // We then use this when computing the view specific touches below
+    // Since only one view is actually handling even multiple touches, the values are all relative
+    // to this one target view.
+    float targetViewCoordinateX = motionEvent.getX() - event.getViewX();
+    float targetViewCoordinateY = motionEvent.getY() - event.getViewY();
+
+    for (int index = 0; index < motionEvent.getPointerCount(); index++) {
       WritableMap touch = Arguments.createMap();
-      touch.putDouble(PAGE_X_KEY, PixelUtil.toDIPFromPixel(event.getX(index) + offsetX));
-      touch.putDouble(PAGE_Y_KEY, PixelUtil.toDIPFromPixel(event.getY(index) + offsetY));
-      touch.putDouble(LOCATION_X_KEY, PixelUtil.toDIPFromPixel(event.getX(index)));
-      touch.putDouble(LOCATION_Y_KEY, PixelUtil.toDIPFromPixel(event.getY(index)));
+      // pageX,Y values are relative to the RootReactView
+      // the motionEvent already contains coordinates in that view
+      touch.putDouble(PAGE_X_KEY, PixelUtil.toDIPFromPixel(motionEvent.getX(index)));
+      touch.putDouble(PAGE_Y_KEY, PixelUtil.toDIPFromPixel(motionEvent.getY(index)));
+      // locationX,Y values are relative to the target view
+      // To compute the values for the view, we subtract that views location from the event X,Y
+      float locationX = motionEvent.getX(index) - targetViewCoordinateX;
+      float locationY = motionEvent.getY(index) - targetViewCoordinateY;
+      touch.putDouble(LOCATION_X_KEY, PixelUtil.toDIPFromPixel(locationX));
+      touch.putDouble(LOCATION_Y_KEY, PixelUtil.toDIPFromPixel(locationY));
       touch.putInt(TARGET_KEY, reactTarget);
-      touch.putDouble(TIMESTAMP_KEY, event.getEventTime());
-      touch.putDouble(POINTER_IDENTIFIER_KEY, event.getPointerId(index));
+      touch.putDouble(TIMESTAMP_KEY, motionEvent.getEventTime());
+      touch.putDouble(POINTER_IDENTIFIER_KEY, motionEvent.getPointerId(index));
       touches.pushMap(touch);
     }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
index 6e002fb9f978..9b74294ad216 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
@@ -47,7 +47,6 @@ public class ReactViewManager extends ViewGroupManager<ReactViewGroup> {
   };
   private static final int CMD_HOTSPOT_UPDATE = 1;
   private static final int CMD_SET_PRESSED = 2;
-  private static final int[] sLocationBuf = new int[2];
 
   @ReactProp(name = "accessible")
   public void setAccessible(ReactViewGroup view, boolean accessible) {
@@ -160,9 +159,8 @@ public void receiveCommand(ReactViewGroup root, int commandId, @Nullable Readabl
               "Illegal number of arguments for 'updateHotspot' command");
         }
         if (Build.VERSION.SDK_INT >= 21) {
-          root.getLocationOnScreen(sLocationBuf);
-          float x = PixelUtil.toPixelFromDIP(args.getDouble(0)) - sLocationBuf[0];
-          float y = PixelUtil.toPixelFromDIP(args.getDouble(1)) - sLocationBuf[1];
+          float x = PixelUtil.toPixelFromDIP(args.getDouble(0));
+          float y = PixelUtil.toPixelFromDIP(args.getDouble(1));
           root.drawableHotspotChanged(x, y);
         }
         break;

From d138403c2e162a1fa76774a784e3364ae80b3273 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 10 Dec 2015 04:27:45 -0800
Subject: [PATCH 0302/1411] Added deferred module loading feature

Reviewed By: javache

Differential Revision: D2717687

fb-gh-sync-id: 4c03c721c794a2e7ac67a0b20474129fde7f0a0d
---
 .../BatchedBridgedModules/NativeModules.js    |  74 +++++++++++-
 Libraries/Utilities/MessageQueue.js           | 105 ++++++++----------
 .../Utilities/nativeModulePrefixNormalizer.js |  32 ------
 React/Base/RCTBatchedBridge.m                 |  51 +++++----
 React/Base/RCTModuleData.m                    |   7 ++
 React/Executors/RCTContextExecutor.m          |  24 +++-
 6 files changed, 175 insertions(+), 118 deletions(-)
 delete mode 100644 Libraries/Utilities/nativeModulePrefixNormalizer.js

diff --git a/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js b/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js
index e3a179887b6c..837534ac3517 100644
--- a/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js
+++ b/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js
@@ -11,10 +11,78 @@
  */
 'use strict';
 
-var NativeModules = require('BatchedBridge').RemoteModules;
+const BatchedBridge = require('BatchedBridge');
+const RemoteModules = BatchedBridge.RemoteModules;
 
-var nativeModulePrefixNormalizer = require('nativeModulePrefixNormalizer');
+function normalizePrefix(moduleName: string): string {
+  return moduleName.replace(/^(RCT|RK)/, '');
+}
 
-nativeModulePrefixNormalizer(NativeModules);
+/**
+ * Dirty hack to support old (RK) and new (RCT) native module name conventions.
+ */
+Object.keys(RemoteModules).forEach((moduleName) => {
+  const strippedName = normalizePrefix(moduleName);
+  if (RemoteModules['RCT' + strippedName] && RemoteModules['RK' + strippedName]) {
+    throw new Error(
+      'Module cannot be registered as both RCT and RK: ' + moduleName
+    );
+  }
+  if (strippedName !== moduleName) {
+    RemoteModules[strippedName] = RemoteModules[moduleName];
+    delete RemoteModules[moduleName];
+  }
+});
+
+/**
+ * Define lazy getters for each module.
+ * These will return the module if already loaded, or load it if not.
+ */
+const NativeModules = {};
+Object.keys(RemoteModules).forEach((moduleName) => {
+  Object.defineProperty(NativeModules, moduleName, {
+    enumerable: true, 
+    get: () => {
+      let module = RemoteModules[moduleName];
+      if (module && module.moduleID) {
+        const json = global.nativeRequireModuleConfig(moduleName);
+        const config = json && JSON.parse(json);
+        module = config && BatchedBridge.processModuleConfig(config, module.moduleID);
+        RemoteModules[moduleName] = module;
+      }
+      return module;
+    },
+  });
+});
+
+/**
+ * Copies the ViewManager constants into UIManager. This is only
+ * needed for iOS, which puts the constants in the ViewManager
+ * namespace instead of UIManager, unlike Android.
+ *
+ * We'll eventually move this logic to UIManager.js, once all
+ * the call sites accessing NativeModules.UIManager directly have
+ * been removed #9344445
+ */
+const UIManager = NativeModules.UIManager;
+UIManager && Object.keys(UIManager).forEach(viewName => {
+  const viewConfig = UIManager[viewName];
+  const constants = {};
+  if (viewConfig.Manager) {
+    Object.defineProperty(viewConfig, 'Constants', {
+      enumerable: true, 
+      get: () => {
+        const viewManager = NativeModules[normalizePrefix(viewConfig.Manager)];
+        viewManager && Object.keys(viewManager).forEach(key => {
+          const value = viewManager[key];
+          if (typeof value !== 'function') {
+            constants[key] = value;
+          }
+        });
+        return constants;
+      },
+    });
+  }
+});
 
 module.exports = NativeModules;
diff --git a/Libraries/Utilities/MessageQueue.js b/Libraries/Utilities/MessageQueue.js
index b7dd38a24927..adf9376e33e0 100644
--- a/Libraries/Utilities/MessageQueue.js
+++ b/Libraries/Utilities/MessageQueue.js
@@ -66,8 +66,6 @@ class MessageQueue {
       this._genModulesConfig(localModules),this._moduleTable, this._methodTable
     );
 
-    this._copyNativeComponentConstants(this.RemoteModules);
-
     this._debugInfo = {};
     this._remoteModuleTable = {};
     this._remoteMethodTable = {};
@@ -105,6 +103,12 @@ class MessageQueue {
     return queue[0].length ? queue : null;
   }
 
+  processModuleConfig(config, moduleID) {
+    const module = this._genModule(config, moduleID);
+    this._genLookup(config, moduleID, this._remoteModuleTable, this._remoteMethodTable)
+    return module;
+  }
+
   /**
    * "Private" methods
    */
@@ -200,30 +204,6 @@ class MessageQueue {
    * Private helper methods
    */
 
-  /**
-   * Copies the ViewManager constants into UIManager. This is only
-   * needed for iOS, which puts the constants in the ViewManager
-   * namespace instead of UIManager, unlike Android.
-   */
-  _copyNativeComponentConstants(remoteModules) {
-    let UIManager = remoteModules.RCTUIManager;
-    UIManager && Object.keys(UIManager).forEach(viewName => {
-      let viewConfig = UIManager[viewName];
-      if (viewConfig.Manager) {
-        const viewManager = remoteModules[viewConfig.Manager];
-        viewManager && Object.keys(viewManager).forEach(key => {
-          const value = viewManager[key];
-          if (typeof value !== 'function') {
-            if (!viewConfig.Constants) {
-              viewConfig.Constants = {};
-            }
-            viewConfig.Constants[key] = value;
-          }
-        });
-      }
-    });
-  }
-
   /**
    * Converts the old, object-based module structure to the new
    * array-based structure. TODO (t8823865) Removed this
@@ -269,55 +249,62 @@ class MessageQueue {
   }
 
   _genLookupTables(modulesConfig, moduleTable, methodTable) {
-    modulesConfig.forEach((module, moduleID) => {
-      if (!module) {
-        return;
-      }
-
-      let moduleName, methods;
-      if (moduleHasConstants(module)) {
-        [moduleName, , methods] = module;
-      } else {
-        [moduleName, methods] = module;
-      }
-
-      moduleTable[moduleID] = moduleName;
-      methodTable[moduleID] = Object.assign({}, methods);
+    modulesConfig.forEach((config, moduleID) => {
+      this._genLookup(config, moduleID, moduleTable, methodTable);
     });
   }
+  
+  _genLookup(config, moduleID, moduleTable, methodTable) {
+    if (!config) {
+      return;
+    }
 
-  _genModules(remoteModules) {
-    remoteModules.forEach((module, moduleID) => {
-      if (!module) {
-        return;
-      }
+    let moduleName, methods;
+    if (moduleHasConstants(config)) {
+      [moduleName, , methods] = config;
+    } else {
+      [moduleName, methods] = config;
+    }
 
-      let moduleName, constants, methods, asyncMethods;
-      if (moduleHasConstants(module)) {
-        [moduleName, constants, methods, asyncMethods] = module;
-      } else {
-        [moduleName, methods, asyncMethods] = module;
-      }
+    moduleTable[moduleID] = moduleName;
+    methodTable[moduleID] = Object.assign({}, methods);
+  }
 
-      const moduleConfig = {moduleID, constants, methods, asyncMethods};
-      this.RemoteModules[moduleName] = this._genModule({}, moduleConfig);
+  _genModules(remoteModules) {
+    remoteModules.forEach((config, moduleID) => {
+      this._genModule(config, moduleID);
     });
   }
 
-  _genModule(module, moduleConfig) {
-    const {moduleID, constants, methods = [], asyncMethods = []} = moduleConfig;
+  _genModule(config, moduleID) {
+    if (!config) {
+      return;
+    }
+
+    let moduleName, constants, methods, asyncMethods;
+    if (moduleHasConstants(config)) {
+      [moduleName, constants, methods, asyncMethods] = config;
+    } else {
+      [moduleName, methods, asyncMethods] = config;
+    }
 
-    methods.forEach((methodName, methodID) => {
+    let module = {};
+    methods && methods.forEach((methodName, methodID) => {
       const methodType =
-        arrayContains(asyncMethods, methodID) ?
+        asyncMethods && arrayContains(asyncMethods, methodID) ?
           MethodTypes.remoteAsync : MethodTypes.remote;
       module[methodName] = this._genMethod(moduleID, methodID, methodType);
     });
     Object.assign(module, constants);
-
+    
+    if (!constants && !methods && !asyncMethods) {
+      module.moduleID = moduleID;
+    }
+    
+    this.RemoteModules[moduleName] = module;
     return module;
   }
-
+  
   _genMethod(module, method, type) {
     let fn = null;
     let self = this;
diff --git a/Libraries/Utilities/nativeModulePrefixNormalizer.js b/Libraries/Utilities/nativeModulePrefixNormalizer.js
deleted file mode 100644
index 151417bc5acf..000000000000
--- a/Libraries/Utilities/nativeModulePrefixNormalizer.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * 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 nativeModulePrefixNormalizer
- * @flow
- */
-'use strict';
-
-// Dirty hack to support old (RK) and new (RCT) native module name conventions
-function nativeModulePrefixNormalizer(
-  modules: {[key: string]: any}
-): void {
-  Object.keys(modules).forEach((moduleName) => {
-    var strippedName = moduleName.replace(/^(RCT|RK)/, '');
-    if (modules['RCT' + strippedName] && modules['RK' + strippedName]) {
-      throw new Error(
-        'Module cannot be registered as both RCT and RK: ' + moduleName
-      );
-    }
-    if (strippedName !== moduleName) {
-      modules[strippedName] = modules[moduleName];
-      delete modules[moduleName];
-    }
-  });
-}
-
-module.exports = nativeModulePrefixNormalizer;
diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index b3b290d72bde..a0190a0ae521 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -128,7 +128,7 @@ - (void)start
     dispatch_group_leave(initModulesAndLoadSource);
   }];
 
-  // Synchronously initialize all native modules that cannot be deferred
+  // Synchronously initialize all native modules that cannot be loaded lazily
   [self initModules];
 
 #if RCT_DEBUG
@@ -236,16 +236,21 @@ - (void)loadSource:(RCTSourceLoadBlock)_onSourceLoad
 - (id)moduleForName:(NSString *)moduleName
 {
   RCTModuleData *moduleData = _moduleDataByName[moduleName];
-  if (RCT_DEBUG) {
-    Class moduleClass = moduleData.moduleClass;
-    if (!RCTBridgeModuleClassIsRegistered(moduleClass)) {
-      RCTLogError(@"Class %@ was not exported. Did you forget to use "
-                  "RCT_EXPORT_MODULE()?", moduleClass);
-    }
-  }
   return moduleData.instance;
 }
 
+- (NSArray *)configForModuleName:(NSString *)moduleName
+{
+  RCTModuleData *moduleData = _moduleDataByName[moduleName];
+  if (!moduleData) {
+    moduleData = _moduleDataByName[[@"RCT" stringByAppendingString:moduleName]];
+  }
+  if (moduleData) {
+    return moduleData.config;
+  }
+  return (id)kCFNull;
+}
+
 - (void)initModules
 {
   RCTAssertMainThread();
@@ -344,21 +349,29 @@ - (void)setUpExecutor
   [_javaScriptExecutor setUp];
 }
 
+- (void)registerModuleForFrameUpdates:(RCTModuleData *)moduleData
+{
+  if ([moduleData.moduleClass conformsToProtocol:@protocol(RCTFrameUpdateObserver)]) {
+    [_frameUpdateObservers addObject:moduleData];
+    id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)moduleData.instance;
+    __weak typeof(self) weakSelf = self;
+    __weak typeof(_javaScriptExecutor) weakJavaScriptExecutor = _javaScriptExecutor;
+    observer.pauseCallback = ^{
+      [weakJavaScriptExecutor executeBlockOnJavaScriptQueue:^{
+        [weakSelf updateJSDisplayLinkState];
+      }];
+    };
+  }
+}
+
 - (NSString *)moduleConfig
 {
   NSMutableArray<NSArray *> *config = [NSMutableArray new];
   for (RCTModuleData *moduleData in _moduleDataByID) {
-    [config addObject:RCTNullIfNil(moduleData.config)];
-    if ([moduleData.moduleClass conformsToProtocol:@protocol(RCTFrameUpdateObserver)]) {
-      [_frameUpdateObservers addObject:moduleData];
-      id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)moduleData.instance;
-      __weak typeof(self) weakSelf = self;
-      __weak typeof(_javaScriptExecutor) weakJavaScriptExecutor = _javaScriptExecutor;
-      observer.pauseCallback = ^{
-        [weakJavaScriptExecutor executeBlockOnJavaScriptQueue:^{
-          [weakSelf updateJSDisplayLinkState];
-        }];
-      };
+    if (self.executorClass == [RCTContextExecutor class]) {
+      [config addObject:@[moduleData.name]];
+    } else {
+      [config addObject:RCTNullIfNil(moduleData.config)];
     }
   }
 
diff --git a/React/Base/RCTModuleData.m b/React/Base/RCTModuleData.m
index 011159db829e..b8fa17049091 100644
--- a/React/Base/RCTModuleData.m
+++ b/React/Base/RCTModuleData.m
@@ -14,6 +14,12 @@
 #import "RCTLog.h"
 #import "RCTUtils.h"
 
+@interface RCTBridge (Private)
+
+- (void)registerModuleForFrameUpdates:(RCTModuleData *)moduleData;
+
+@end
+
 @implementation RCTModuleData
 {
   NSString *_queueName;
@@ -88,6 +94,7 @@ - (void)setBridgeForInstance:(RCTBridge *)bridge
                   "or provide your own setter method.", self.name);
     }
   }
+  [bridge registerModuleForFrameUpdates:self];
 }
 
 - (NSString *)name
diff --git a/React/Executors/RCTContextExecutor.m b/React/Executors/RCTContextExecutor.m
index 3c22398d5d3b..d37f6c7b9313 100644
--- a/React/Executors/RCTContextExecutor.m
+++ b/React/Executors/RCTContextExecutor.m
@@ -98,10 +98,11 @@ - (void)dealloc
 
 @end
 
-// Private bridge interface to allow middle-batch calls
+// Private bridge interface
 @interface RCTBridge (RCTContextExecutor)
 
 - (void)handleBuffer:(NSArray<NSArray *> *)buffer batchEnded:(BOOL)hasEnded;
+- (NSArray *)configForModuleName:(NSString *)moduleName;
 
 @end
 
@@ -351,13 +352,24 @@ - (void)setUp
     [strongSelf _addNativeHook:RCTNativeLoggingHook withName:"nativeLoggingHook"];
     [strongSelf _addNativeHook:RCTNoop withName:"noop"];
 
-    __weak RCTBridge *bridge = strongSelf->_bridge;
+    __weak RCTBridge *weakBridge = strongSelf->_bridge;
+
+    strongSelf->_context.context[@"nativeRequireModuleConfig"] = ^NSString *(NSString *moduleName) {
+      if (!weakSelf.valid) {
+        return nil;
+      }
+      NSArray *config = [weakBridge configForModuleName:moduleName];
+      if (config) {
+        return RCTJSONStringify(config, NULL);
+      }
+      return nil;
+    };
+
     strongSelf->_context.context[@"nativeFlushQueueImmediate"] = ^(NSArray<NSArray *> *calls){
       if (!weakSelf.valid || !calls) {
         return;
       }
-
-      [bridge handleBuffer:calls batchEnded:NO];
+      [weakBridge handleBuffer:calls batchEnded:NO];
     };
 
     strongSelf->_context.context[@"RCTPerformanceNow"] = ^{
@@ -365,6 +377,7 @@ - (void)setUp
     };
 
 #if RCT_DEV
+
     if (RCTProfileIsProfiling()) {
       strongSelf->_context.context[@"__RCTProfileIsProfiling"] = @YES;
     }
@@ -394,7 +407,9 @@ - (void)setUp
                                                    name:event
                                                  object:nil];
     }
+
 #endif
+
   }];
 }
 
@@ -417,7 +432,6 @@ - (void)_addNativeHook:(JSObjectCallAsFunctionCallback)hook withName:(const char
   JSStringRef JSName = JSStringCreateWithUTF8CString(name);
   JSObjectSetProperty(_context.ctx, globalObject, JSName, JSObjectMakeFunctionWithCallback(_context.ctx, JSName, hook), kJSPropertyAttributeNone, NULL);
   JSStringRelease(JSName);
-
 }
 
 - (void)invalidate

From 7f710f9050636a4c884052ec989037329f63ad65 Mon Sep 17 00:00:00 2001
From: Mike Armstrong <mikea@fb.com>
Date: Thu, 10 Dec 2015 04:36:23 -0800
Subject: [PATCH 0303/1411] Add fbsystrace markers using the legacyprofiler

Reviewed By: astreet

Differential Revision: D2728033

fb-gh-sync-id: 264d40930b8fec0262cbea36529bd8b11efcc58e
---
 Libraries/Utilities/BridgeProfiling.js        | 10 ++-
 .../src/main/jni/react/JSCExecutor.cpp        |  4 ++
 .../src/main/jni/react/JSCLegacyProfiler.cpp  |  4 ++
 .../src/main/jni/react/JSCTracing.cpp         | 65 +++++++++++++++++++
 4 files changed, 82 insertions(+), 1 deletion(-)

diff --git a/Libraries/Utilities/BridgeProfiling.js b/Libraries/Utilities/BridgeProfiling.js
index 8e60354f2a50..36cb86252f61 100644
--- a/Libraries/Utilities/BridgeProfiling.js
+++ b/Libraries/Utilities/BridgeProfiling.js
@@ -20,8 +20,9 @@ type RelayProfiler = {
 
 var GLOBAL = GLOBAL || this;
 var TRACE_TAG_REACT_APPS = 1 << 17;
+var TRACE_TAG_JSC_CALLS = 1 << 27;
 
-var _enabled;
+var _enabled = false;
 var _asyncCookie = 0;
 var _ReactPerf = null;
 function ReactPerf() {
@@ -33,6 +34,13 @@ function ReactPerf() {
 
 var BridgeProfiling = {
   setEnabled(enabled: boolean) {
+    if (_enabled !== enabled) {
+      if (enabled) {
+        global.nativeTraceBeginLegacy && global.nativeTraceBeginLegacy(TRACE_TAG_JSC_CALLS);
+      } else {
+        global.nativeTraceEndLegacy && global.nativeTraceEndLegacy(TRACE_TAG_JSC_CALLS);
+      }
+    }
     _enabled = enabled;
 
     ReactPerf().enableMeasure = enabled;
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index de9dffc05eb2..6e1f493e8cdd 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -195,7 +195,11 @@ bool JSCExecutor::supportsProfiling() {
 void JSCExecutor::startProfiler(const std::string &titleString) {
   #ifdef WITH_JSC_EXTRA_TRACING
   JSStringRef title = JSStringCreateWithUTF8CString(titleString.c_str());
+  #if WITH_JSC_INTERNAL
+  JSStartProfiling(m_context, title, false);
+  #else
   JSStartProfiling(m_context, title);
+  #endif
   JSStringRelease(title);
   #endif
 }
diff --git a/ReactAndroid/src/main/jni/react/JSCLegacyProfiler.cpp b/ReactAndroid/src/main/jni/react/JSCLegacyProfiler.cpp
index 74222c2efe28..e1e2d8b4bdcd 100644
--- a/ReactAndroid/src/main/jni/react/JSCLegacyProfiler.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCLegacyProfiler.cpp
@@ -26,7 +26,11 @@ static JSValueRef nativeProfilerStart(
   }
 
   JSStringRef title = JSValueToStringCopy(ctx, arguments[0], exception);
+  #if WITH_JSC_INTERNAL
+  JSStartProfiling(ctx, title, false);
+  #else
   JSStartProfiling(ctx, title);
+  #endif
   JSStringRelease(title);
   return JSValueMakeUndefined(ctx);
 }
diff --git a/ReactAndroid/src/main/jni/react/JSCTracing.cpp b/ReactAndroid/src/main/jni/react/JSCTracing.cpp
index 945d6fe72bc4..c607cc8c6ed9 100644
--- a/ReactAndroid/src/main/jni/react/JSCTracing.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCTracing.cpp
@@ -2,6 +2,7 @@
 
 #include <algorithm>
 #include <JavaScriptCore/JavaScript.h>
+#include <JavaScriptCore/API/JSProfilerPrivate.h>
 #include <fbsystrace.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -9,6 +10,8 @@
 
 using std::min;
 
+static const char *ENABLED_FBSYSTRACE_PROFILE_NAME = "__fbsystrace__";
+
 static uint64_t tagFromJSValue(
     JSContextRef ctx,
     JSValueRef value,
@@ -409,12 +412,74 @@ static JSValueRef nativeTraceCounter(
   return JSValueMakeUndefined(ctx);
 }
 
+static JSValueRef nativeTraceBeginLegacy(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[],
+    JSValueRef* exception) {
+  if (FBSYSTRACE_UNLIKELY(argumentCount < 1)) {
+    if (exception) {
+      *exception = facebook::react::makeJSCException(
+        ctx,
+        "nativeTraceBeginLegacy: requires TAG Argument");
+    }
+    return JSValueMakeUndefined(ctx);
+  }
+
+  uint64_t tag = tagFromJSValue(ctx, arguments[0], exception);
+  if (!fbsystrace_is_tracing(tag)) {
+    return JSValueMakeUndefined(ctx);
+  }
+
+  JSStringRef title = JSStringCreateWithUTF8CString(ENABLED_FBSYSTRACE_PROFILE_NAME);
+  #if WITH_JSC_INTERNAL
+  JSStartProfiling(ctx, title, true);
+  #else
+  JSStartProfiling(ctx, title);
+  #endif
+  JSStringRelease(title);
+
+  return JSValueMakeUndefined(ctx);
+}
+
+static JSValueRef nativeTraceEndLegacy(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[],
+    JSValueRef* exception) {
+  if (FBSYSTRACE_UNLIKELY(argumentCount < 1)) {
+    if (exception) {
+      *exception = facebook::react::makeJSCException(
+        ctx,
+        "nativeTraceBeginLegacy: requires TAG Argument");
+    }
+    return JSValueMakeUndefined(ctx);
+  }
+
+  uint64_t tag = tagFromJSValue(ctx, arguments[0], exception);
+  if (!fbsystrace_is_tracing(tag)) {
+    return JSValueMakeUndefined(ctx);
+  }
+
+  JSStringRef title = JSStringCreateWithUTF8CString(ENABLED_FBSYSTRACE_PROFILE_NAME);
+  JSEndProfiling(ctx, title);
+  JSStringRelease(title);
+
+  return JSValueMakeUndefined(ctx);
+}
+
 namespace facebook {
 namespace react {
 
 void addNativeTracingHooks(JSGlobalContextRef ctx) {
   installGlobalFunction(ctx, "nativeTraceBeginSection", nativeTraceBeginSection);
   installGlobalFunction(ctx, "nativeTraceEndSection", nativeTraceEndSection);
+  installGlobalFunction(ctx, "nativeTraceBeginLegacy", nativeTraceBeginLegacy);
+  installGlobalFunction(ctx, "nativeTraceEndLegacy", nativeTraceEndLegacy);
   installGlobalFunction(ctx, "nativeTraceBeginAsyncSection", nativeTraceBeginAsyncSection);
   installGlobalFunction(ctx, "nativeTraceEndAsyncSection", nativeTraceEndAsyncSection);
   installGlobalFunction(ctx, "nativeTraceAsyncSectionStage", nativeTraceAsyncSectionStage);

From ec5ca670449505a824d5626021b007d687d90ff1 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 10 Dec 2015 05:56:26 -0800
Subject: [PATCH 0304/1411] Fixed JS crash on Android when requiring a native
 module that doesn't exist

Summary:
public

NativeModule getters call the nativeRequireModuleConfig function to lazily load a module if it's not already available, but this crashes on Android since the nativeRequireModuleConfig hook hasn't been implemented yet. This diff checks that the hook exists before calling it.

Reviewed By: gsaraf

Differential Revision: D2744080

fb-gh-sync-id: cae9c8c45a4d3c80ceb8c10f3d4d59a8d9d3c7f8
---
 Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js b/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js
index 837534ac3517..5ef61e35fd0c 100644
--- a/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js
+++ b/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js
@@ -44,7 +44,7 @@ Object.keys(RemoteModules).forEach((moduleName) => {
     enumerable: true, 
     get: () => {
       let module = RemoteModules[moduleName];
-      if (module && module.moduleID) {
+      if (module && module.moduleID && global.nativeRequireModuleConfig) {
         const json = global.nativeRequireModuleConfig(moduleName);
         const config = json && JSON.parse(json);
         module = config && BatchedBridge.processModuleConfig(config, module.moduleID);

From da153d3928ff376eeb7effd02d60c5e9b1dc89b3 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 10 Dec 2015 07:09:08 -0800
Subject: [PATCH 0305/1411] Fixed bug where module with moduleID of zero
 wouldn't be loaded

Reviewed By: jspahrsummers

Differential Revision: D2744167

fb-gh-sync-id: b442af60618703ab19290d042b3614984cd9a3ae
---
 Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js b/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js
index 5ef61e35fd0c..af1540b75b5d 100644
--- a/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js
+++ b/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js
@@ -44,7 +44,7 @@ Object.keys(RemoteModules).forEach((moduleName) => {
     enumerable: true, 
     get: () => {
       let module = RemoteModules[moduleName];
-      if (module && module.moduleID && global.nativeRequireModuleConfig) {
+      if (module && typeof module.moduleID === 'number' && global.nativeRequireModuleConfig) {
         const json = global.nativeRequireModuleConfig(moduleName);
         const config = json && JSON.parse(json);
         module = config && BatchedBridge.processModuleConfig(config, module.moduleID);

From 651664b4ceda0afd668fbf293d66addb8eb061c6 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Thu, 10 Dec 2015 15:25:49 +0000
Subject: [PATCH 0306/1411] Update breaking-changes.md

---
 breaking-changes.md | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/breaking-changes.md b/breaking-changes.md
index 77f27ca393ea..0d8c5df65246 100644
--- a/breaking-changes.md
+++ b/breaking-changes.md
@@ -1,5 +1,7 @@
 # Breaking Changes
 
+## 0.17
+
 ## 0.16
 
 - Touch events on Android now have coordinates consistent with iOS: [0c2ee5](https://github.com/facebook/react-native/commit/0c2ee5d480e696f8621252c936a8773e8de9f8b6)

From f4e3512076f05b81ddc8047665b4526259ea4a03 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Thu, 10 Dec 2015 15:37:44 +0000
Subject: [PATCH 0307/1411] Add a guide for doing releases

---
 Releases.md | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)
 create mode 100644 Releases.md

diff --git a/Releases.md b/Releases.md
new file mode 100644
index 000000000000..89ab4f985424
--- /dev/null
+++ b/Releases.md
@@ -0,0 +1,56 @@
+The list of releases with notes can be found at:
+https://github.com/facebook/react-native/releases
+
+## Cut a release branch
+
+- Make sure iOS and Android Getting Started flow works on master.
+- Publish to Maven Central:
+  - Edit `ReactAndroid/gradle.properties`
+  - Edit `ReactAndroid/release.gradle` and uncomment Javadoc generation
+  - `./gradlew :ReactAndroid:installArchives` (`java -version` should print 1.7 which is currently needed for Javadoc generation)
+  - Log into Sonatype and go to [Staging upload](https://oss.sonatype.org/#staging-upload)
+  - Select Artifact(s) with a POM (to publish to a local Maven repo for testing run `./gradlew :ReactAndroid:installArchives`)
+  - Add all files: .aar, sources jar, javadoc jar, .asc for everything (including the POM file)
+- `git checkout -b 0.12-stable`
+- In `package.json`, set version to e.g. `0.12.0-rc`.
+- In `React.podspec`, set version to e.g. `0.12.0-rc`.
+- In `local-cli/generator-android/templates/src/app/build.gradle` update the dependency to e.g. `com.facebook.react:react-native:0.12.+`
+- `git push origin 0.12-stable`
+- `npm publish`
+
+## Do a release
+
+To release e.g. 0.12 to npm:
+
+(For admins, here's the command to promote someone)
+
+```
+npm owner add <user> react-native
+```
+
+When you are ready to do a new release.
+
+- Update package.json and React.podspec with the new number
+
+```
+git tag v0.6.0-rc 0.6-stable # don't forget the `v` at the beginning!
+git push --tags
+```
+
+- Publish to GitHub
+
+```
+git push git push origin 0.12-stable
+```
+
+- Publish to npm
+
+```
+npm publish
+npm dist-tag add react-native@0.12.0 latest
+```
+
+- Publish to CocoaPods (it takes several minutes to validate the podspec)
+- Upgrade tags to a release by going to https://github.com/facebook/react-native/tags
+- Click "Add Notes to release"
+- Click Publish
\ No newline at end of file

From e56efc7df8e9f4cdeca5e279492a83a21678e3f0 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Thu, 10 Dec 2015 16:29:19 +0000
Subject: [PATCH 0308/1411] Update Releases.md

---
 Releases.md | 86 ++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 59 insertions(+), 27 deletions(-)

diff --git a/Releases.md b/Releases.md
index 89ab4f985424..41d7c93d61b6 100644
--- a/Releases.md
+++ b/Releases.md
@@ -1,56 +1,88 @@
 The list of releases with notes can be found at:
 https://github.com/facebook/react-native/releases
 
+Future releases:
+
+- **0.17 branch cut**, 0.17.0-rc - beginning of **week of Dec 7**
+- 0.17.0 - Dec 17
+- (Holiday break)
+- **0.18 branch cut**, 0.18.0-rc - beginning of **week of Jan 4**
+- 0.18.0 - Jan 14
+- **0.19 branch cut**, 0.19.0-rc - beginning of **week of Jan 18**
+- 0.19.0 - Jan 28
+- ...
+
 ## Cut a release branch
 
-- Make sure iOS and Android Getting Started flow works on master.
-- Publish to Maven Central:
-  - Edit `ReactAndroid/gradle.properties`
-  - Edit `ReactAndroid/release.gradle` and uncomment Javadoc generation
-  - `./gradlew :ReactAndroid:installArchives` (`java -version` should print 1.7 which is currently needed for Javadoc generation)
-  - Log into Sonatype and go to [Staging upload](https://oss.sonatype.org/#staging-upload)
-  - Select Artifact(s) with a POM (to publish to a local Maven repo for testing run `./gradlew :ReactAndroid:installArchives`)
-  - Add all files: .aar, sources jar, javadoc jar, .asc for everything (including the POM file)
-- `git checkout -b 0.12-stable`
+Note: replace 0.12 in all the commands below with the version you're releasing :)
+
+First, set up Sinopia (only need to do this once): https://github.com/facebook/react-native/tree/master/react-native-cli
+
+Make absolutely sure basic iOS and Android workflow works on master:
+  - `cd react-native`
+  - `git pull`
+  - `git checkout -b 0.12-stable`
+  - Edit `ReactAndroid/gradle.properties`, set `VERSION_NAME=0.12.0`
+  - Edit `ReactAndroid/release.gradle`, uncomment Javadoc generation (the line `// archives androidJavadocJar`)
+  - Make sure `java -version` prints 1.7.x, this is currently needed for Javadoc generation and Javadocs are required by Maven Central (we should make it work with Java 8)
+  - Run `./gradlew :ReactAndroid:installArchives`, it will print a lot of Javadoc warnings, that's OK.
+  - Check the artifacts were generated: `ls -al ~/.m2/repository/com/facebook/react/react-native/0.12.0/` should contain:
+    - `react-native-0.17.0-javadoc.jar`, `react-native-0.17.0-sources.jar`, `react-native-0.17.0.aar`, `react-native-0.17.0.pom`
+    - For each of the above also `.asc` file
 - In `package.json`, set version to e.g. `0.12.0-rc`.
 - In `React.podspec`, set version to e.g. `0.12.0-rc`.
 - In `local-cli/generator-android/templates/src/app/build.gradle` update the dependency to e.g. `com.facebook.react:react-native:0.12.+`
-- `git push origin 0.12-stable`
-- `npm publish`
+- Publish to sinopia:
+  - `npm set registry http://localhost:4873/`, check that it worked: `npm config list` will show registry is set to localhost
+  - In a separate shell, start sinopia. Run `sinopia`. If started successfully it will print: http address - http://localhost:4873/.
+  - Make sure http://localhost:4873/ shows no old versions
+  - `npm publish`
+  - http://localhost:4873/ will show 0.12.0-rc
+- Test that everything works:
+  - `cd /tmp`
+  - `react-native init Zero12rc`
+  - `cd Zero12rc`
+  - Check that `package.json`, `android/app/build.gradle` have correct versions (`^0.12.0-rc`, `com.facebook.react:react-native:0.12.+`)
+  - `open ios/Zero12rc.xcodeproj`
+  - Hit the Run button in Xcode.
+  - Packager should open in a new window, you should see the Welcome to React Native screen, Reload JS, try Chrome debugging - put a breakpoint somewhere in `index.ios.js` and Reload JS, Chrome debugger should stop on the breakpoint (we don't have tests for Chrome debugging)
+  - Close the packager window, close Xcode
+  - Start an Android emulator (ideally Genymotion, it's faster and more reliable than Google emulators)
+  - `react-native run-android`
+  - Test is the same way as on iOS, including Chrome debugging
 
 ## Do a release
 
-To release e.g. 0.12 to npm:
-
-(For admins, here's the command to promote someone)
+- Revert the Javadoc change in `ReactAndroid/release.gradle`
+- `git commit -am` "[0.12-rc] Bump version numbers"
+- `git push origin 0.12-stable`
 
-```
-npm owner add <user> react-native
-```
+Publish to Maven Central (NOTE we could get rid of this whole section publishing binaries to npm instead):
+  - Log into Sonatype and go to [Staging upload](https://oss.sonatype.org/#staging-upload). You'll need to get permissions for this by filing a ticket explaining you're a core contributor to React Native. [Example ticket](https://issues.sonatype.org/browse/OSSRH-11885).
+  - Select Artifact(s) with a POM (to publish to a local Maven repo for testing run `./gradlew :ReactAndroid:installArchives`)
+  - Add all files: .aar, sources jar, javadoc jar, .asc for everything (including the POM file)
+  - Wait a few hours until you see the version has propagated to [JCenter](https://bintray.com/bintray/jcenter/com.facebook.react%3Areact-native/view)
 
-When you are ready to do a new release.
+To release 0.12-rc to npm:
 
-- Update package.json and React.podspec with the new number
+(You need to be a maintainer of the repo. For admins, here's the command to promote someone)
 
 ```
-git tag v0.6.0-rc 0.6-stable # don't forget the `v` at the beginning!
-git push --tags
+npm owner add <user> react-native
 ```
 
-- Publish to GitHub
-
 ```
-git push git push origin 0.12-stable
+git tag v0.12.0-rc 0.12-stable # don't forget the `v` at the beginning!
+git push --tags
 ```
 
 - Publish to npm
 
 ```
 npm publish
+# Only for non-rc releases:
 npm dist-tag add react-native@0.12.0 latest
 ```
-
-- Publish to CocoaPods (it takes several minutes to validate the podspec)
 - Upgrade tags to a release by going to https://github.com/facebook/react-native/tags
 - Click "Add Notes to release"
-- Click Publish
\ No newline at end of file
+- Click Publish

From 6355011d17062530193db2911b6f92f9c68ba6ea Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Thu, 10 Dec 2015 16:30:51 +0000
Subject: [PATCH 0309/1411] Update Releases.md

---
 Releases.md | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/Releases.md b/Releases.md
index 41d7c93d61b6..b014e5d36e86 100644
--- a/Releases.md
+++ b/Releases.md
@@ -16,6 +16,8 @@ Future releases:
 
 Note: replace 0.12 in all the commands below with the version you're releasing :)
 
+#### Check that everything works
+
 First, set up Sinopia (only need to do this once): https://github.com/facebook/react-native/tree/master/react-native-cli
 
 Make absolutely sure basic iOS and Android workflow works on master:
@@ -50,12 +52,14 @@ Make absolutely sure basic iOS and Android workflow works on master:
   - Start an Android emulator (ideally Genymotion, it's faster and more reliable than Google emulators)
   - `react-native run-android`
   - Test is the same way as on iOS, including Chrome debugging
+  
+#### Push to github
 
-## Do a release
+  - Revert the Javadoc change in `ReactAndroid/release.gradle`
+  - `git commit -am` "[0.12-rc] Bump version numbers"
+  - `git push origin 0.12-stable`
 
-- Revert the Javadoc change in `ReactAndroid/release.gradle`
-- `git commit -am` "[0.12-rc] Bump version numbers"
-- `git push origin 0.12-stable`
+## Do a release
 
 Publish to Maven Central (NOTE we could get rid of this whole section publishing binaries to npm instead):
   - Log into Sonatype and go to [Staging upload](https://oss.sonatype.org/#staging-upload). You'll need to get permissions for this by filing a ticket explaining you're a core contributor to React Native. [Example ticket](https://issues.sonatype.org/browse/OSSRH-11885).

From ce7c0b735f476a4618fd0d68fc39157a0bdb4f57 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 10 Dec 2015 09:06:02 -0800
Subject: [PATCH 0310/1411] Fixed image tinting

Summary:
public

A previous refactor introduced a bug where setting the tintColor of an <Image> to null no longer cleared the tint. This fixes it again.

Reviewed By: javache

Differential Revision: D2744279

fb-gh-sync-id: 1b5e0d546bf456d7b93e2ceee73c568c185c305c
---
 Libraries/Image/RCTImageView.m        | 6 ------
 Libraries/Image/RCTImageViewManager.m | 9 ++++++++-
 2 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/Libraries/Image/RCTImageView.m b/Libraries/Image/RCTImageView.m
index 656dd61e896e..712f7e7a56db 100644
--- a/Libraries/Image/RCTImageView.m
+++ b/Libraries/Image/RCTImageView.m
@@ -108,12 +108,6 @@ - (void)setCapInsets:(UIEdgeInsets)capInsets
   }
 }
 
-- (void)setTintColor:(UIColor *)tintColor
-{
-  super.tintColor = tintColor;
-  self.renderingMode = tintColor ? UIImageRenderingModeAlwaysTemplate : UIImageRenderingModeAlwaysOriginal;
-}
-
 - (void)setRenderingMode:(UIImageRenderingMode)renderingMode
 {
   if (_renderingMode != renderingMode) {
diff --git a/Libraries/Image/RCTImageViewManager.m b/Libraries/Image/RCTImageViewManager.m
index c2067889539d..d318d1f048a9 100644
--- a/Libraries/Image/RCTImageViewManager.m
+++ b/Libraries/Image/RCTImageViewManager.m
@@ -33,6 +33,13 @@ - (UIView *)view
 RCT_EXPORT_VIEW_PROPERTY(onLoadEnd, RCTDirectEventBlock)
 RCT_REMAP_VIEW_PROPERTY(resizeMode, contentMode, UIViewContentMode)
 RCT_EXPORT_VIEW_PROPERTY(source, RCTImageSource)
-RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
+RCT_CUSTOM_VIEW_PROPERTY(tintColor, UIColor, RCTImageView)
+{
+  // Default tintColor isn't nil - it's inherited from the superView - but we
+  // want to treat a null json value for `tintColor` as meaning 'disable tint',
+  // so we toggle `renderingMode` here instead of in `-[RCTImageView setTintColor:]`
+  view.tintColor = [RCTConvert UIColor:json] ?: defaultView.tintColor;
+  view.renderingMode = json ? UIImageRenderingModeAlwaysTemplate : defaultView.renderingMode;
+}
 
 @end

From 88ac40666cf0372fd9bb481c5b8b35c00a929475 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 10 Dec 2015 10:09:04 -0800
Subject: [PATCH 0311/1411] Replaced RegExp method parser with recursive
 descent
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Summary:
public

This diff replaces the RegEx module method parser with a handwritten recursive descent parser that's faster and easier to maintain.

The new parser is ~8 times faster when tested on the UIManager.managerChildren() method, and uses ~1/10 as much RAM.

The new parser also supports lightweight generics, and is more tolerant of white space.

(This means that you now can – and should – use types like `NSArray<NSString *> *` for your exported properties and method arguments, instead of `NSStringArray`).

Reviewed By: jspahrsummers

Differential Revision: D2736636

fb-gh-sync-id: f6a11431935fa8acc8ac36f3471032ec9a1c8490
---
 .../UIExplorerUnitTests/RCTAllocationTests.m  |   2 +-
 .../RCTMethodArgumentTests.m                  | 102 ++++++++----
 .../RCTModuleMethodTests.m                    |  56 +++----
 Libraries/Network/RCTNetworking.m             |   4 +-
 Libraries/Settings/RCTSettingsManager.m       |   2 +-
 React/Base/RCTConvert.h                       |  36 +++--
 React/Base/RCTConvert.m                       |   7 +
 React/Base/RCTModuleData.m                    |   6 +-
 React/Base/RCTModuleMethod.h                  |   9 +-
 React/Base/RCTModuleMethod.m                  | 145 +++++++++++-------
 React/Base/RCTNullability.h                   |  16 ++
 React/Base/RCTParserUtils.h                   |  31 ++++
 React/Base/RCTParserUtils.m                   | 118 ++++++++++++++
 React/Modules/RCTAsyncLocalStorage.m          |   8 +-
 React/Modules/RCTExceptionsManager.m          |   8 +-
 React/Modules/RCTUIManager.m                  |  10 +-
 React/React.xcodeproj/project.pbxproj         |   8 +
 React/Views/RCTComponentData.m                |   2 +-
 React/Views/RCTPickerManager.m                |   3 +-
 React/Views/RCTSegmentedControlManager.m      |   2 +-
 20 files changed, 409 insertions(+), 166 deletions(-)
 create mode 100644 React/Base/RCTNullability.h
 create mode 100644 React/Base/RCTParserUtils.h
 create mode 100644 React/Base/RCTParserUtils.m

diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m
index 4fe7294fb3e9..239973ca03e8 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m
@@ -132,7 +132,7 @@ - (void)testModuleMethodsAreDeallocated
 {
   __weak RCTModuleMethod *weakMethod;
   @autoreleasepool {
-    __autoreleasing RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithObjCMethodName:@"test:(NSString *)a :(nonnull NSNumber *)b :(RCTResponseSenderBlock)c :(RCTResponseErrorBlock)d" JSMethodName:@"" moduleClass:[AllocationTestModule class]];
+    __autoreleasing RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithMethodSignature:@"test:(NSString *)a :(nonnull NSNumber *)b :(RCTResponseSenderBlock)c :(RCTResponseErrorBlock)d" JSMethodName:@"" moduleClass:[AllocationTestModule class]];
     weakMethod = method;
     XCTAssertNotNil(method, @"RCTModuleMethod should have been created");
   }
diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTMethodArgumentTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTMethodArgumentTests.m
index 3f53812473e7..53d9d0f74336 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTMethodArgumentTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTMethodArgumentTests.m
@@ -23,14 +23,14 @@ @interface RCTMethodArgumentTests : XCTestCase
 
 @implementation RCTMethodArgumentTests
 
-extern void RCTParseObjCMethodName(NSString **objCMethodName, NSArray **argTypes);
+extern SEL RCTParseMethodSignature(NSString *methodSignature, NSArray **argTypes);
 
 - (void)testOneArgument
 {
   NSArray *arguments;
-  NSString *methodName = @"foo:(NSInteger)foo";
-  RCTParseObjCMethodName(&methodName, &arguments);
-  XCTAssertEqualObjects(methodName, @"foo:");
+  NSString *methodSignature = @"foo:(NSInteger)foo";
+  SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
+  XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:");
   XCTAssertEqual(arguments.count, (NSUInteger)1);
   XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger");
 }
@@ -38,9 +38,9 @@ - (void)testOneArgument
 - (void)testTwoArguments
 {
   NSArray *arguments;
-  NSString *methodName = @"foo:(NSInteger)foo bar:(BOOL)bar";
-  RCTParseObjCMethodName(&methodName, &arguments);
-  XCTAssertEqualObjects(methodName, @"foo:bar:");
+  NSString *methodSignature = @"foo:(NSInteger)foo bar:(BOOL)bar";
+  SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
+  XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:");
   XCTAssertEqual(arguments.count, (NSUInteger)2);
   XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger");
   XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL");
@@ -49,9 +49,9 @@ - (void)testTwoArguments
 - (void)testSpaces
 {
   NSArray *arguments;
-  NSString *methodName = @"foo : (NSInteger)foo bar : (BOOL) bar";
-  RCTParseObjCMethodName(&methodName, &arguments);
-  XCTAssertEqualObjects(methodName, @"foo:bar:");
+  NSString *methodSignature = @"foo : (NSInteger)foo bar : (BOOL) bar";
+  SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
+  XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:");
   XCTAssertEqual(arguments.count, (NSUInteger)2);
   XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger");
   XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL");
@@ -60,9 +60,9 @@ - (void)testSpaces
 - (void)testNewlines
 {
   NSArray *arguments;
-  NSString *methodName = @"foo : (NSInteger)foo\nbar : (BOOL) bar";
-  RCTParseObjCMethodName(&methodName, &arguments);
-  XCTAssertEqualObjects(methodName, @"foo:bar:");
+  NSString *methodSignature = @"foo : (NSInteger)foo\nbar : (BOOL) bar";
+  SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
+  XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:");
   XCTAssertEqual(arguments.count, (NSUInteger)2);
   XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger");
   XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL");
@@ -71,9 +71,9 @@ - (void)testNewlines
 - (void)testUnnamedArgs
 {
   NSArray *arguments;
-  NSString *methodName = @"foo:(NSInteger)foo:(BOOL)bar";
-  RCTParseObjCMethodName(&methodName, &arguments);
-  XCTAssertEqualObjects(methodName, @"foo::");
+  NSString *methodSignature = @"foo:(NSInteger)foo:(BOOL)bar";
+  SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
+  XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo::");
   XCTAssertEqual(arguments.count, (NSUInteger)2);
   XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSInteger");
   XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL");
@@ -82,9 +82,9 @@ - (void)testUnnamedArgs
 - (void)testUntypedUnnamedArgs
 {
   NSArray *arguments;
-  NSString *methodName = @"foo:foo:bar:bar";
-  RCTParseObjCMethodName(&methodName, &arguments);
-  XCTAssertEqualObjects(methodName, @"foo:::");
+  NSString *methodSignature = @"foo:foo:bar:bar";
+  SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
+  XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:::");
   XCTAssertEqual(arguments.count, (NSUInteger)3);
   XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"id");
   XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"id");
@@ -94,9 +94,9 @@ - (void)testUntypedUnnamedArgs
 - (void)testAttributes
 {
   NSArray *arguments;
-  NSString *methodName = @"foo:(__attribute__((nonnull)) NSString *)foo bar:(__unused BOOL)bar";
-  RCTParseObjCMethodName(&methodName, &arguments);
-  XCTAssertEqualObjects(methodName, @"foo:bar:");
+  NSString *methodSignature = @"foo:(__attribute__((unused)) NSString *)foo bar:(__unused BOOL)bar";
+  SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
+  XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:");
   XCTAssertEqual(arguments.count, (NSUInteger)2);
   XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSString");
   XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL");
@@ -105,9 +105,9 @@ - (void)testAttributes
 - (void)testNullability
 {
   NSArray *arguments;
-  NSString *methodName = @"foo:(nullable NSString *)foo bar:(nonnull NSNumber *)bar baz:(id)baz";
-  RCTParseObjCMethodName(&methodName, &arguments);
-  XCTAssertEqualObjects(methodName, @"foo:bar:baz:");
+  NSString *methodSignature = @"foo:(nullable NSString *)foo bar:(nonnull NSNumber *)bar baz:(id)baz";
+  SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
+  XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:baz:");
   XCTAssertEqual(arguments.count, (NSUInteger)3);
   XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSString");
   XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"NSNumber");
@@ -120,9 +120,9 @@ - (void)testNullability
 - (void)testSemicolonStripping
 {
   NSArray *arguments;
-  NSString *methodName = @"foo:(NSString *)foo bar:(BOOL)bar;";
-  RCTParseObjCMethodName(&methodName, &arguments);
-  XCTAssertEqualObjects(methodName, @"foo:bar:");
+  NSString *methodSignature = @"foo:(NSString *)foo bar:(BOOL)bar;";
+  SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
+  XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:");
   XCTAssertEqual(arguments.count, (NSUInteger)2);
   XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSString");
   XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"BOOL");
@@ -131,9 +131,9 @@ - (void)testSemicolonStripping
 - (void)testUnused
 {
   NSArray *arguments;
-  NSString *methodName = @"foo:(__unused NSString *)foo bar:(NSNumber *)bar";
-  RCTParseObjCMethodName(&methodName, &arguments);
-  XCTAssertEqualObjects(methodName, @"foo:bar:");
+  NSString *methodSignature = @"foo:(__unused NSString *)foo bar:(NSNumber *)bar";
+  SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
+  XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:bar:");
   XCTAssertEqual(arguments.count, (NSUInteger)2);
   XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSString");
   XCTAssertEqualObjects(((RCTMethodArgument *)arguments[1]).type, @"NSNumber");
@@ -141,4 +141,44 @@ - (void)testUnused
   XCTAssertFalse(((RCTMethodArgument *)arguments[1]).unused);
 }
 
+- (void)testGenericArray
+{
+  NSArray *arguments;
+  NSString *methodSignature = @"foo:(NSArray<NSString *> *)foo;";
+  SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
+  XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:");
+  XCTAssertEqual(arguments.count, (NSUInteger)1);
+  XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSStringArray");
+}
+
+- (void)testNestedGenericArray
+{
+  NSArray *arguments;
+  NSString *methodSignature = @"foo:(NSArray<NSArray<NSString *> *> *)foo;";
+  SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
+  XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:");
+  XCTAssertEqual(arguments.count, (NSUInteger)1);
+  XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSStringArrayArray");
+}
+
+- (void)testGenericSet
+{
+  NSArray *arguments;
+  NSString *methodSignature = @"foo:(NSSet<NSNumber *> *)foo;";
+  SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
+  XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:");
+  XCTAssertEqual(arguments.count, (NSUInteger)1);
+  XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSNumberSet");
+}
+
+- (void)testGenericDictionary
+{
+  NSArray *arguments;
+  NSString *methodSignature = @"foo:(NSDictionary<NSString *, NSNumber *> *)foo;";
+  SEL selector = RCTParseMethodSignature(methodSignature, &arguments);
+  XCTAssertEqualObjects(NSStringFromSelector(selector), @"foo:");
+  XCTAssertEqual(arguments.count, (NSUInteger)1);
+  XCTAssertEqualObjects(((RCTMethodArgument *)arguments[0]).type, @"NSNumberDictionary");
+}
+
 @end
diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleMethodTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleMethodTests.m
index 93ac3b5aa047..f247da4ffc75 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleMethodTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleMethodTests.m
@@ -47,10 +47,10 @@ - (void)doFooWithBar:(__unused NSString *)bar { }
 
 - (void)testNonnull
 {
-  NSString *methodName = @"doFooWithBar:(nonnull NSString *)bar";
-  RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithObjCMethodName:methodName
-                                                               JSMethodName:nil
-                                                                moduleClass:[self class]];
+  NSString *methodSignature = @"doFooWithBar:(nonnull NSString *)bar";
+  RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature
+                                                                JSMethodName:nil
+                                                                 moduleClass:[self class]];
   XCTAssertFalse(RCTLogsError(^{
     [method invokeWithBridge:nil module:self arguments:@[@"Hello World"]];
   }));
@@ -72,40 +72,40 @@ - (void)testNumbersNonnull
   {
     // Specifying an NSNumber param without nonnull isn't allowed
     XCTAssertTrue(RCTLogsError(^{
-      NSString *methodName = @"doFooWithNumber:(NSNumber *)n";
-      RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithObjCMethodName:methodName
-                                                                   JSMethodName:nil
-                                                                    moduleClass:[self class]];
+      NSString *methodSignature = @"doFooWithNumber:(NSNumber *)n";
+      RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature
+                                                                    JSMethodName:nil
+                                                                     moduleClass:[self class]];
       // Invoke method to trigger parsing
       [method invokeWithBridge:nil module:self arguments:@[@1]];
     }));
   }
 
   {
-    NSString *methodName = @"doFooWithNumber:(nonnull NSNumber *)n";
-    RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithObjCMethodName:methodName
-                                                                 JSMethodName:nil
-                                                                  moduleClass:[self class]];
+    NSString *methodSignature = @"doFooWithNumber:(nonnull NSNumber *)n";
+    RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature
+                                                                  JSMethodName:nil
+                                                                   moduleClass:[self class]];
     XCTAssertTrue(RCTLogsError(^{
       [method invokeWithBridge:nil module:self arguments:@[[NSNull null]]];
     }));
   }
 
   {
-    NSString *methodName = @"doFooWithDouble:(double)n";
-    RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithObjCMethodName:methodName
-                                                                 JSMethodName:nil
-                                                                  moduleClass:[self class]];
+    NSString *methodSignature = @"doFooWithDouble:(double)n";
+    RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature
+                                                                  JSMethodName:nil
+                                                                   moduleClass:[self class]];
     XCTAssertTrue(RCTLogsError(^{
       [method invokeWithBridge:nil module:self arguments:@[[NSNull null]]];
     }));
   }
 
   {
-    NSString *methodName = @"doFooWithInteger:(NSInteger)n";
-    RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithObjCMethodName:methodName
-                                                                 JSMethodName:nil
-                                                                  moduleClass:[self class]];
+    NSString *methodSignature = @"doFooWithInteger:(NSInteger)n";
+    RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature
+                                                                  JSMethodName:nil
+                                                                   moduleClass:[self class]];
     XCTAssertTrue(RCTLogsError(^{
       [method invokeWithBridge:nil module:self arguments:@[[NSNull null]]];
     }));
@@ -114,10 +114,10 @@ - (void)testNumbersNonnull
 
 - (void)testStructArgument
 {
-  NSString *methodName = @"doFooWithCGRect:(CGRect)s";
-  RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithObjCMethodName:methodName
-                                                               JSMethodName:nil
-                                                                moduleClass:[self class]];
+  NSString *methodSignature = @"doFooWithCGRect:(CGRect)s";
+  RCTModuleMethod *method = [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature
+                                                                JSMethodName:nil
+                                                                 moduleClass:[self class]];
 
   CGRect r = CGRectMake(10, 20, 30, 40);
   [method invokeWithBridge:nil module:self arguments:@[@[@10, @20, @30, @40]]];
@@ -126,13 +126,13 @@ - (void)testStructArgument
 
 - (void)testWhitespaceTolerance
 {
-  NSString *methodName = @"doFoo : \t (NSString *)foo";
+  NSString *methodSignature = @"doFoo : \t (NSString *)foo";
 
   __block RCTModuleMethod *method;
   XCTAssertFalse(RCTLogsError(^{
-    method = [[RCTModuleMethod alloc] initWithObjCMethodName:methodName
-                                                JSMethodName:nil
-                                                 moduleClass:[self class]];
+    method = [[RCTModuleMethod alloc] initWithMethodSignature:methodSignature
+                                                 JSMethodName:nil
+                                                  moduleClass:[self class]];
   }));
 
   XCTAssertEqualObjects(method.JSMethodName, @"doFoo");
diff --git a/Libraries/Network/RCTNetworking.m b/Libraries/Network/RCTNetworking.m
index 9afb0914ee80..0c5aeaecd7fa 100644
--- a/Libraries/Network/RCTNetworking.m
+++ b/Libraries/Network/RCTNetworking.m
@@ -56,7 +56,7 @@ @implementation RCTHTTPFormDataHelper
   return [[NSString alloc] initWithBytesNoCopy:bytes length:boundaryLength encoding:NSUTF8StringEncoding freeWhenDone:YES];
 }
 
-- (RCTURLRequestCancellationBlock)process:(NSDictionaryArray *)formData
+- (RCTURLRequestCancellationBlock)process:(NSArray<NSDictionary *> *)formData
                                  callback:(RCTHTTPQueryResult)callback
 {
   RCTAssertThread(_networker.methodQueue, @"process: must be called on method queue");
@@ -289,7 +289,7 @@ - (RCTURLRequestCancellationBlock)processDataForHTTPQuery:(nullable NSDictionary
       }
     };
   }
-  NSDictionaryArray *formData = [RCTConvert NSDictionaryArray:query[@"formData"]];
+  NSArray<NSDictionary *> *formData = [RCTConvert NSDictionaryArray:query[@"formData"]];
   if (formData) {
     RCTHTTPFormDataHelper *formDataHelper = [RCTHTTPFormDataHelper new];
     formDataHelper.networker = self;
diff --git a/Libraries/Settings/RCTSettingsManager.m b/Libraries/Settings/RCTSettingsManager.m
index 2ff4f3b4d770..c0c915df777c 100644
--- a/Libraries/Settings/RCTSettingsManager.m
+++ b/Libraries/Settings/RCTSettingsManager.m
@@ -90,7 +90,7 @@ - (void)userDefaultsDidChange:(NSNotification *)note
 /**
  * Remove some values from the settings.
  */
-RCT_EXPORT_METHOD(deleteValues:(NSStringArray *)keys)
+RCT_EXPORT_METHOD(deleteValues:(NSArray<NSString *> *)keys)
 {
   _ignoringUpdates = YES;
   for (NSString *key in keys) {
diff --git a/React/Base/RCTConvert.h b/React/Base/RCTConvert.h
index 6347cc9cab70..231f888c4821 100644
--- a/React/Base/RCTConvert.h
+++ b/React/Base/RCTConvert.h
@@ -94,28 +94,13 @@ typedef NSURL RCTFileURL;
               size:(id)size weight:(id)weight style:(id)style
    scaleMultiplier:(CGFloat)scaleMultiplier;
 
-typedef NSArray NSArrayArray;
 + (NSArray<NSArray *> *)NSArrayArray:(id)json;
-
-typedef NSArray NSStringArray;
 + (NSArray<NSString *> *)NSStringArray:(id)json;
-
-typedef NSArray NSStringArrayArray;
 + (NSArray<NSArray<NSString *> *> *)NSStringArrayArray:(id)json;
-
-typedef NSArray NSDictionaryArray;
 + (NSArray<NSDictionary *> *)NSDictionaryArray:(id)json;
-
-typedef NSArray NSURLArray;
 + (NSArray<NSURL *> *)NSURLArray:(id)json;
-
-typedef NSArray RCTFileURLArray;
-+ (NSArray<NSURL *> *)RCTFileURLArray:(id)json;
-
-typedef NSArray NSNumberArray;
++ (NSArray<RCTFileURL *> *)RCTFileURLArray:(id)json;
 + (NSArray<NSNumber *> *)NSNumberArray:(id)json;
-
-typedef NSArray UIColorArray;
 + (NSArray<UIColor *> *)UIColorArray:(id)json;
 
 typedef NSArray CGColorArray;
@@ -145,6 +130,18 @@ typedef BOOL css_clip_t, css_backface_visibility_t;
 
 @interface RCTConvert (Deprecated)
 
+/**
+ * Use lightweight generics syntax instead, e.g. NSArray<NSString *>
+ */
+typedef NSArray NSArrayArray __deprecated_msg("Use NSArray<NSArray *>");
+typedef NSArray NSStringArray __deprecated_msg("Use NSArray<NSString *>");
+typedef NSArray NSStringArrayArray __deprecated_msg("Use NSArray<NSArray<NSString *> *>");
+typedef NSArray NSDictionaryArray __deprecated_msg("Use NSArray<NSDictionary *>");
+typedef NSArray NSURLArray __deprecated_msg("Use NSArray<NSURL *>");
+typedef NSArray RCTFileURLArray __deprecated_msg("Use NSArray<RCTFileURL *>");
+typedef NSArray NSNumberArray __deprecated_msg("Use NSArray<NSNumber *>");
+typedef NSArray UIColorArray __deprecated_msg("Use NSArray<UIColor *>");
+
 /**
  * Synchronous image loading is generally a bad idea for performance reasons.
  * If you need to pass image references, try to use `RCTImageSource` and then
@@ -162,6 +159,11 @@ RCT_EXTERN NSNumber *RCTConvertEnumValue(const char *, NSDictionary *, NSNumber
 RCT_EXTERN NSNumber *RCTConvertMultiEnumValue(const char *, NSDictionary *, NSNumber *, id);
 RCT_EXTERN NSArray *RCTConvertArrayValue(SEL, id);
 
+/**
+ * Get the converter function for the specified type
+ */
+RCT_EXTERN SEL RCTConvertSelectorForType(NSString *type);
+
 /**
  * This macro is used for logging conversion errors. This is just used to
  * avoid repeating the same boilerplate for every error message.
@@ -238,7 +240,7 @@ RCT_CUSTOM_CONVERTER(type, type, [RCT_DEBUG ? [self NSNumber:json] : json getter
  * This macro is used for creating converter functions for typed arrays.
  */
 #define RCT_ARRAY_CONVERTER(type)                      \
-+ (NSArray<type *> *)type##Array:(id)json                      \
++ (NSArray<id> *)type##Array:(id)json                      \
 {                                                      \
   return RCTConvertArrayValue(@selector(type:), json); \
 }
diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m
index 244fe6c0af29..5860bbc59740 100644
--- a/React/Base/RCTConvert.m
+++ b/React/Base/RCTConvert.m
@@ -13,6 +13,7 @@
 
 #import "RCTDefines.h"
 #import "RCTImageSource.h"
+#import "RCTParserUtils.h"
 #import "RCTUtils.h"
 
 @implementation RCTConvert
@@ -649,6 +650,12 @@ + (UIFont *)UIFont:(UIFont *)font withFamily:(id)family
   return values;
 }
 
+SEL RCTConvertSelectorForType(NSString *type)
+{
+  const char *input = type.UTF8String;
+  return NSSelectorFromString([RCTParseType(&input) stringByAppendingString:@":"]);
+}
+
 RCT_ARRAY_CONVERTER(NSURL)
 RCT_ARRAY_CONVERTER(RCTFileURL)
 RCT_ARRAY_CONVERTER(UIColor)
diff --git a/React/Base/RCTModuleData.m b/React/Base/RCTModuleData.m
index b8fa17049091..d254509a765b 100644
--- a/React/Base/RCTModuleData.m
+++ b/React/Base/RCTModuleData.m
@@ -122,9 +122,9 @@ - (NSString *)name
         NSArray<NSString *> *entries =
           ((NSArray<NSString *> *(*)(id, SEL))imp)(_moduleClass, selector);
         id<RCTBridgeMethod> moduleMethod =
-          [[RCTModuleMethod alloc] initWithObjCMethodName:entries[1]
-                                             JSMethodName:entries[0]
-                                              moduleClass:_moduleClass];
+          [[RCTModuleMethod alloc] initWithMethodSignature:entries[1]
+                                              JSMethodName:entries[0]
+                                               moduleClass:_moduleClass];
 
         [moduleMethods addObject:moduleMethod];
       }
diff --git a/React/Base/RCTModuleMethod.h b/React/Base/RCTModuleMethod.h
index f450c412cea0..5572dba3a307 100644
--- a/React/Base/RCTModuleMethod.h
+++ b/React/Base/RCTModuleMethod.h
@@ -10,15 +10,10 @@
 #import <Foundation/Foundation.h>
 
 #import "RCTBridgeMethod.h"
+#import "RCTNullability.h"
 
 @class RCTBridge;
 
-typedef NS_ENUM(NSUInteger, RCTNullability) {
-  RCTNullabilityUnspecified,
-  RCTNullable,
-  RCTNonnullable,
-};
-
 @interface RCTMethodArgument : NSObject
 
 @property (nonatomic, copy, readonly) NSString *type;
@@ -32,7 +27,7 @@ typedef NS_ENUM(NSUInteger, RCTNullability) {
 @property (nonatomic, readonly) Class moduleClass;
 @property (nonatomic, readonly) SEL selector;
 
-- (instancetype)initWithObjCMethodName:(NSString *)objCMethodName
+- (instancetype)initWithMethodSignature:(NSString *)objCMethodName
                           JSMethodName:(NSString *)JSMethodName
                            moduleClass:(Class)moduleClass NS_DESIGNATED_INITIALIZER;
 
diff --git a/React/Base/RCTModuleMethod.m b/React/Base/RCTModuleMethod.m
index 0182fe93d858..407fed3dab80 100644
--- a/React/Base/RCTModuleMethod.m
+++ b/React/Base/RCTModuleMethod.m
@@ -15,6 +15,7 @@
 #import "RCTBridge.h"
 #import "RCTConvert.h"
 #import "RCTLog.h"
+#import "RCTParserUtils.h"
 #import "RCTUtils.h"
 
 typedef BOOL (^RCTArgumentBlock)(RCTBridge *, NSUInteger, id);
@@ -50,7 +51,7 @@ @implementation RCTModuleMethod
   Class _moduleClass;
   NSInvocation *_invocation;
   NSArray<RCTArgumentBlock> *_argumentBlocks;
-  NSString *_objCMethodName;
+  NSString *_methodSignature;
   SEL _selector;
   NSDictionary *_profileArgs;
 }
@@ -68,77 +69,106 @@ static void RCTLogArgumentError(RCTModuleMethod *method, NSUInteger index,
 
 RCT_NOT_IMPLEMENTED(- (instancetype)init)
 
-void RCTParseObjCMethodName(NSString **, NSArray<RCTMethodArgument *> **);
-void RCTParseObjCMethodName(NSString **objCMethodName, NSArray<RCTMethodArgument *> **arguments)
+// returns YES if the selector ends in a colon (indicating that there is at
+// least one argument, and maybe more selector parts) or NO if it doesn't.
+static BOOL RCTParseSelectorPart(const char **input, NSMutableString *selector)
 {
-  static NSRegularExpression *typeNameRegex;
-  static dispatch_once_t onceToken;
-  dispatch_once(&onceToken, ^{
-    NSString *unusedPattern = @"(?:__unused|__attribute__\\(\\(unused\\)\\))";
-    NSString *constPattern = @"(?:const)";
-    NSString *nullablePattern = @"(?:__nullable|nullable|__attribute__\\(\\(nullable\\)\\))";
-    NSString *nonnullPattern = @"(?:__nonnull|nonnull|__attribute__\\(\\(nonnull\\)\\))";
-    NSString *annotationPattern = [NSString stringWithFormat:@"(?:(?:(%@)|%@|(%@)|(%@))\\s*)",
-                                   unusedPattern, constPattern, nullablePattern, nonnullPattern];
-    NSString *pattern = [NSString stringWithFormat:@"(?<=:)(\\s*\\(%1$@?(\\w+?)(?:\\s*\\*)?%1$@?\\))?\\s*\\w+",
-                         annotationPattern];
-    typeNameRegex = [[NSRegularExpression alloc] initWithPattern:pattern options:0 error:NULL];
-  });
-
-  // Extract argument types
-  NSString *methodName = *objCMethodName;
-  NSRange methodRange = {0, methodName.length};
-  NSMutableArray *args = [NSMutableArray array];
-  [typeNameRegex enumerateMatchesInString:methodName options:0 range:methodRange usingBlock:^(NSTextCheckingResult *result, __unused NSMatchingFlags flags, __unused BOOL *stop) {
-    NSRange typeRange = [result rangeAtIndex:5];
-    NSString *type = typeRange.length ? [methodName substringWithRange:typeRange] : @"id";
-    BOOL unused = ([result rangeAtIndex:2].length > 0);
-    RCTNullability nullability = [result rangeAtIndex:3].length ? RCTNullable :
-      [result rangeAtIndex:4].length ? RCTNonnullable : RCTNullabilityUnspecified;
-    [args addObject:[[RCTMethodArgument alloc] initWithType:type
-                                                nullability:nullability
-                                                     unused:unused]];
-  }];
-  *arguments = [args copy];
+  NSString *selectorPart;
+  if (RCTParseIdentifier(input, &selectorPart)) {
+    [selector appendString:selectorPart];
+  }
+  RCTSkipWhitespace(input);
+  if (RCTReadChar(input, ':')) {
+    [selector appendString:@":"];
+    RCTSkipWhitespace(input);
+    return YES;
+  }
+  return NO;
+}
+
+static BOOL RCTParseUnused(const char **input)
+{
+  return RCTReadString(input, "__unused") ||
+         RCTReadString(input, "__attribute__((unused))");
+}
+
+static RCTNullability RCTParseNullability(const char **input)
+{
+  if (RCTReadString(input, "nullable")) {
+    return RCTNullable;
+  } else if (RCTReadString(input, "nonnull")) {
+    return RCTNonnullable;
+  }
+  return RCTNullabilityUnspecified;
+}
+
+SEL RCTParseMethodSignature(NSString *, NSArray<RCTMethodArgument *> **);
+SEL RCTParseMethodSignature(NSString *methodSignature, NSArray<RCTMethodArgument *> **arguments)
+{
+  const char *input = methodSignature.UTF8String;
+  RCTSkipWhitespace(&input);
+
+  NSMutableArray *args;
+  NSMutableString *selector = [NSMutableString new];
+  while (RCTParseSelectorPart(&input, selector)) {
+    if (!args) {
+      args = [NSMutableArray new];
+    }
+
+    // Parse type
+    if (RCTReadChar(&input, '(')) {
+      RCTSkipWhitespace(&input);
 
-  // Remove the parameter types and names
-  methodName = [typeNameRegex stringByReplacingMatchesInString:methodName options:0
-                                                         range:methodRange
-                                                  withTemplate:@""];
+      BOOL unused = RCTParseUnused(&input);
+      RCTSkipWhitespace(&input);
 
-  // Remove whitespace
-  methodName = [methodName stringByReplacingOccurrencesOfString:@"\n" withString:@""];
-  methodName = [methodName stringByReplacingOccurrencesOfString:@" " withString:@""];
+      RCTNullability nullability = RCTParseNullability(&input);
+      RCTSkipWhitespace(&input);
 
-  // Strip trailing semicolon
-  if ([methodName hasSuffix:@";"]) {
-    methodName = [methodName substringToIndex:methodName.length - 1];
+      NSString *type = RCTParseType(&input);
+      [args addObject:[[RCTMethodArgument alloc] initWithType:type
+                                                  nullability:nullability
+                                                       unused:unused]];
+      RCTSkipWhitespace(&input);
+      RCTReadChar(&input, ')');
+      RCTSkipWhitespace(&input);
+    } else {
+      // Type defaults to id if unspecified
+      [args addObject:[[RCTMethodArgument alloc] initWithType:@"id"
+                                                  nullability:RCTNullable
+                                                       unused:NO]];
+    }
+
+    // Argument name
+    RCTParseIdentifier(&input, NULL);
+    RCTSkipWhitespace(&input);
   }
 
-  *objCMethodName = methodName;
+  *arguments = [args copy];
+  return NSSelectorFromString(selector);
 }
 
-- (instancetype)initWithObjCMethodName:(NSString *)objCMethodName
-                          JSMethodName:(NSString *)JSMethodName
-                           moduleClass:(Class)moduleClass
+- (instancetype)initWithMethodSignature:(NSString *)methodSignature
+                           JSMethodName:(NSString *)JSMethodName
+                            moduleClass:(Class)moduleClass
 {
   if ((self = [super init])) {
 
     _moduleClass = moduleClass;
-    _objCMethodName = [objCMethodName copy];
+    _methodSignature = [methodSignature copy];
     _JSMethodName = JSMethodName.length > 0 ? JSMethodName : ({
-      NSString *methodName = objCMethodName;
+      NSString *methodName = methodSignature;
       NSRange colonRange = [methodName rangeOfString:@":"];
       if (colonRange.location != NSNotFound) {
         methodName = [methodName substringToIndex:colonRange.location];
       }
       methodName = [methodName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
       RCTAssert(methodName.length, @"%@ is not a valid JS function name, please"
-                " supply an alternative using RCT_REMAP_METHOD()", objCMethodName);
+                " supply an alternative using RCT_REMAP_METHOD()", methodSignature);
       methodName;
     });
 
-    if ([_objCMethodName rangeOfString:@"RCTPromise"].length) {
+    if ([_methodSignature rangeOfString:@"RCTPromise"].length) {
       _functionType = RCTFunctionTypePromise;
     } else {
       _functionType = RCTFunctionTypeNormal;
@@ -151,15 +181,12 @@ - (instancetype)initWithObjCMethodName:(NSString *)objCMethodName
 - (void)processMethodSignature
 {
   NSArray<RCTMethodArgument *> *arguments;
-  NSString *objCMethodName = _objCMethodName;
-  RCTParseObjCMethodName(&objCMethodName, &arguments);
-
-  _selector = NSSelectorFromString(objCMethodName);
-  RCTAssert(_selector, @"%@ is not a valid selector", objCMethodName);
+  _selector = RCTParseMethodSignature(_methodSignature, &arguments);
+  RCTAssert(_selector, @"%@ is not a valid selector", _methodSignature);
 
   // Create method invocation
   NSMethodSignature *methodSignature = [_moduleClass instanceMethodSignatureForSelector:_selector];
-  RCTAssert(methodSignature, @"%@ is not a recognized Objective-C method.", objCMethodName);
+  RCTAssert(methodSignature, @"%@ is not a recognized Objective-C method.", _methodSignature);
   NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
   invocation.selector = _selector;
   _invocation = invocation;
@@ -203,7 +230,7 @@ - (void)processMethodSignature
     BOOL isNullableType = NO;
     RCTMethodArgument *argument = arguments[i - 2];
     NSString *typeName = argument.type;
-    SEL selector = NSSelectorFromString([typeName stringByAppendingString:@":"]);
+    SEL selector = RCTConvertSelectorForType(typeName);
     if ([RCTConvert respondsToSelector:selector]) {
       switch (objcType[0]) {
 
@@ -296,7 +323,7 @@ - (void)processMethodSignature
     } else if ([typeName isEqualToString:@"RCTPromiseResolveBlock"]) {
       RCTAssert(i == numberOfArguments - 2,
                 @"The RCTPromiseResolveBlock must be the second to last parameter in -[%@ %@]",
-                _moduleClass, objCMethodName);
+                _moduleClass, _methodSignature);
       RCT_ARG_BLOCK(
         if (RCT_DEBUG && ![json isKindOfClass:[NSNumber class]]) {
           RCTLogArgumentError(weakSelf, index, json, "should be a promise resolver function");
@@ -310,7 +337,7 @@ - (void)processMethodSignature
     } else if ([typeName isEqualToString:@"RCTPromiseRejectBlock"]) {
       RCTAssert(i == numberOfArguments - 1,
                 @"The RCTPromiseRejectBlock must be the last parameter in -[%@ %@]",
-                _moduleClass, objCMethodName);
+                _moduleClass, _methodSignature);
       RCT_ARG_BLOCK(
         if (RCT_DEBUG && ![json isKindOfClass:[NSNumber class]]) {
           RCTLogArgumentError(weakSelf, index, json, "should be a promise rejecter function");
diff --git a/React/Base/RCTNullability.h b/React/Base/RCTNullability.h
new file mode 100644
index 000000000000..6d250ee4702e
--- /dev/null
+++ b/React/Base/RCTNullability.h
@@ -0,0 +1,16 @@
+/**
+ * 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+typedef NS_ENUM(NSUInteger, RCTNullability) {
+  RCTNullabilityUnspecified,
+  RCTNullable,
+  RCTNonnullable,
+};
diff --git a/React/Base/RCTParserUtils.h b/React/Base/RCTParserUtils.h
new file mode 100644
index 000000000000..dcbe413ef713
--- /dev/null
+++ b/React/Base/RCTParserUtils.h
@@ -0,0 +1,31 @@
+/**
+ * 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "RCTDefines.h"
+
+@interface RCTParserUtils : NSObject
+
+/**
+ * Generic utility functions for parsing Objective-C source code.
+ */
+RCT_EXTERN BOOL RCTReadChar(const char **input, char c);
+RCT_EXTERN BOOL RCTReadString(const char **input, const char *string);
+RCT_EXTERN void RCTSkipWhitespace(const char **input);
+RCT_EXTERN BOOL RCTParseIdentifier(const char **input, NSString **string);
+
+/**
+ * Parse an Objective-C type into a form that can be used by RCTConvert.
+ * This doesn't really belong here, but it's used by both RCTConvert and
+ * RCTModuleMethod, which makes it difficult to find a better home for it.
+ */
+RCT_EXTERN NSString *RCTParseType(const char **input);
+
+@end
diff --git a/React/Base/RCTParserUtils.m b/React/Base/RCTParserUtils.m
new file mode 100644
index 000000000000..5e9182a5fa45
--- /dev/null
+++ b/React/Base/RCTParserUtils.m
@@ -0,0 +1,118 @@
+/**
+ * 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.
+ */
+
+#import "RCTParserUtils.h"
+
+#import "RCTLog.h"
+
+@implementation RCTParserUtils
+
+BOOL RCTReadChar(const char **input, char c)
+{
+  if (**input == c) {
+    (*input)++;
+    return YES;
+  }
+  return NO;
+}
+
+BOOL RCTReadString(const char **input, const char *string)
+{
+  int i;
+  for (i = 0; string[i] != 0; i++) {
+    if (string[i] != (*input)[i]) {
+      return NO;
+    }
+  }
+  *input += i;
+  return YES;
+}
+
+void RCTSkipWhitespace(const char **input)
+{
+  while (isspace(**input)) {
+    (*input)++;
+  }
+}
+
+static BOOL RCTIsIdentifierHead(const char c)
+{
+  return isalpha(c) || c == '_';
+}
+
+static BOOL RCTIsIdentifierTail(const char c)
+{
+  return isalnum(c) || c == '_';
+}
+
+BOOL RCTParseIdentifier(const char **input, NSString **string)
+{
+  const char *start = *input;
+  if (!RCTIsIdentifierHead(**input)) {
+    return NO;
+  }
+  (*input)++;
+  while (RCTIsIdentifierTail(**input)) {
+    (*input)++;
+  }
+  if (string) {
+    *string = [[NSString alloc] initWithBytes:start
+                                       length:(NSInteger)(*input - start)
+                                     encoding:NSASCIIStringEncoding];
+  }
+  return YES;
+}
+
+static BOOL RCTIsCollectionType(NSString *type)
+{
+  static NSSet *collectionTypes;
+  static dispatch_once_t onceToken;
+  dispatch_once(&onceToken, ^{
+    collectionTypes = [[NSSet alloc] initWithObjects:
+                       @"NSArray", @"NSSet", @"NSDictionary", nil];
+  });
+  return [collectionTypes containsObject:type];
+}
+
+NSString *RCTParseType(const char **input)
+{
+  NSString *type;
+  RCTParseIdentifier(input, &type);
+  RCTSkipWhitespace(input);
+  if (RCTReadChar(input, '<')) {
+    RCTSkipWhitespace(input);
+    NSString *subtype = RCTParseType(input);
+    if (RCTIsCollectionType(type)) {
+      if ([type isEqualToString:@"NSDictionary"]) {
+        // Dictionaries have both a key *and* value type, but the key type has
+        // to be a string for JSON, so we only care about the value type
+        if (RCT_DEBUG && ![subtype isEqualToString:@"NSString"]) {
+          RCTLogError(@"%@ is not a valid key type for a JSON dictionary", subtype);
+        }
+        RCTSkipWhitespace(input);
+        RCTReadChar(input, ',');
+        RCTSkipWhitespace(input);
+        subtype = RCTParseType(input);
+      }
+      if (![subtype isEqualToString:@"id"]) {
+        type = [type stringByReplacingCharactersInRange:(NSRange){0, 2 /* "NS" */}
+                                             withString:subtype];
+      }
+    } else {
+      // It's a protocol rather than a generic collection - ignore it
+    }
+    RCTSkipWhitespace(input);
+    RCTReadChar(input, '>');
+  }
+  RCTSkipWhitespace(input);
+  RCTReadChar(input, '*');
+  return type;
+}
+
+@end
diff --git a/React/Modules/RCTAsyncLocalStorage.m b/React/Modules/RCTAsyncLocalStorage.m
index 273ef40c6bf8..344832b9aa04 100644
--- a/React/Modules/RCTAsyncLocalStorage.m
+++ b/React/Modules/RCTAsyncLocalStorage.m
@@ -319,7 +319,7 @@ - (NSDictionary *)_writeEntry:(NSArray<NSString *> *)entry changedManifest:(BOOL
 
 #pragma mark - Exported JS Functions
 
-RCT_EXPORT_METHOD(multiGet:(NSStringArray *)keys
+RCT_EXPORT_METHOD(multiGet:(NSArray<NSString *> *)keys
                   callback:(RCTResponseSenderBlock)callback)
 {
   NSDictionary *errorOut = [self _ensureSetup];
@@ -338,7 +338,7 @@ - (NSDictionary *)_writeEntry:(NSArray<NSString *> *)entry changedManifest:(BOOL
   callback(@[RCTNullIfNil(errors), result]);
 }
 
-RCT_EXPORT_METHOD(multiSet:(NSStringArrayArray *)kvPairs
+RCT_EXPORT_METHOD(multiSet:(NSArray<NSArray<NSString *> *> *)kvPairs
                   callback:(RCTResponseSenderBlock)callback)
 {
   NSDictionary *errorOut = [self _ensureSetup];
@@ -358,7 +358,7 @@ - (NSDictionary *)_writeEntry:(NSArray<NSString *> *)entry changedManifest:(BOOL
   callback(@[RCTNullIfNil(errors)]);
 }
 
-RCT_EXPORT_METHOD(multiMerge:(NSStringArrayArray *)kvPairs
+RCT_EXPORT_METHOD(multiMerge:(NSArray<NSArray<NSString *> *> *)kvPairs
                     callback:(RCTResponseSenderBlock)callback)
 {
   NSDictionary *errorOut = [self _ensureSetup];
@@ -394,7 +394,7 @@ - (NSDictionary *)_writeEntry:(NSArray<NSString *> *)entry changedManifest:(BOOL
   callback(@[RCTNullIfNil(errors)]);
 }
 
-RCT_EXPORT_METHOD(multiRemove:(NSStringArray *)keys
+RCT_EXPORT_METHOD(multiRemove:(NSArray<NSString *> *)keys
                   callback:(RCTResponseSenderBlock)callback)
 {
   NSDictionary *errorOut = [self _ensureSetup];
diff --git a/React/Modules/RCTExceptionsManager.m b/React/Modules/RCTExceptionsManager.m
index c536e20a10da..791c163f16dd 100644
--- a/React/Modules/RCTExceptionsManager.m
+++ b/React/Modules/RCTExceptionsManager.m
@@ -34,7 +34,7 @@ - (instancetype)initWithDelegate:(id<RCTExceptionsManagerDelegate>)delegate
 }
 
 RCT_EXPORT_METHOD(reportSoftException:(NSString *)message
-                  stack:(NSDictionaryArray *)stack
+                  stack:(NSArray<NSDictionary *> *)stack
                   exceptionId:(nonnull NSNumber *)exceptionId)
 {
   [_bridge.redBox showErrorMessage:message withStack:stack];
@@ -45,7 +45,7 @@ - (instancetype)initWithDelegate:(id<RCTExceptionsManagerDelegate>)delegate
 }
 
 RCT_EXPORT_METHOD(reportFatalException:(NSString *)message
-                  stack:(NSDictionaryArray *)stack
+                  stack:(NSArray<NSDictionary *> *)stack
                   exceptionId:(nonnull NSNumber *)exceptionId)
 {
   [_bridge.redBox showErrorMessage:message withStack:stack];
@@ -66,7 +66,7 @@ - (instancetype)initWithDelegate:(id<RCTExceptionsManagerDelegate>)delegate
 }
 
 RCT_EXPORT_METHOD(updateExceptionMessage:(NSString *)message
-                  stack:(NSDictionaryArray *)stack
+                  stack:(NSArray<NSDictionary *> *)stack
                   exceptionId:(nonnull NSNumber *)exceptionId)
 {
   [_bridge.redBox updateErrorMessage:message withStack:stack];
@@ -78,7 +78,7 @@ - (instancetype)initWithDelegate:(id<RCTExceptionsManagerDelegate>)delegate
 
 // Deprecated.  Use reportFatalException directly instead.
 RCT_EXPORT_METHOD(reportUnhandledException:(NSString *)message
-                  stack:(NSDictionaryArray *)stack)
+                  stack:(NSArray<NSDictionary *> *)stack)
 {
   [self reportFatalException:message stack:stack exceptionId:@-1];
 }
diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m
index c3c1ea58917b..4812a548ef8e 100644
--- a/React/Modules/RCTUIManager.m
+++ b/React/Modules/RCTUIManager.m
@@ -721,11 +721,11 @@ - (void)_removeChildren:(NSArray<id<RCTComponent>> *)children
 }
 
 RCT_EXPORT_METHOD(manageChildren:(nonnull NSNumber *)containerReactTag
-                  moveFromIndices:(NSNumberArray *)moveFromIndices
-                  moveToIndices:(NSNumberArray *)moveToIndices
-                  addChildReactTags:(NSNumberArray *)addChildReactTags
-                  addAtIndices:(NSNumberArray *)addAtIndices
-                  removeAtIndices:(NSNumberArray *)removeAtIndices)
+                  moveFromIndices:(NSArray<NSNumber *> *)moveFromIndices
+                  moveToIndices:(NSArray<NSNumber *> *)moveToIndices
+                  addChildReactTags:(NSArray<NSNumber *> *)addChildReactTags
+                  addAtIndices:(NSArray<NSNumber *> *)addAtIndices
+                  removeAtIndices:(NSArray<NSNumber *> *)removeAtIndices)
 {
   [self _manageChildren:containerReactTag
         moveFromIndices:moveFromIndices
diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj
index d5ea0c76d5d4..3bc1cb5cf899 100644
--- a/React/React.xcodeproj/project.pbxproj
+++ b/React/React.xcodeproj/project.pbxproj
@@ -24,6 +24,7 @@
 		13A0C2891B74F71200B29F6F /* RCTDevLoadingView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A0C2861B74F71200B29F6F /* RCTDevLoadingView.m */; };
 		13A0C28A1B74F71200B29F6F /* RCTDevMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A0C2881B74F71200B29F6F /* RCTDevMenu.m */; };
 		13A1F71E1A75392D00D3D453 /* RCTKeyCommands.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A1F71D1A75392D00D3D453 /* RCTKeyCommands.m */; };
+		13A6E20E1C19AA0C00845B82 /* RCTParserUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 13A6E20D1C19AA0C00845B82 /* RCTParserUtils.m */; };
 		13AB90C11B6FA36700713B4F /* RCTComponentData.m in Sources */ = {isa = PBXBuildFile; fileRef = 13AB90C01B6FA36700713B4F /* RCTComponentData.m */; };
 		13AF20451AE707F9005F5298 /* RCTSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = 13AF20441AE707F9005F5298 /* RCTSlider.m */; };
 		13AFBCA01C07247D00BBAEAA /* RCTMapOverlay.m in Sources */ = {isa = PBXBuildFile; fileRef = 13AFBC9F1C07247D00BBAEAA /* RCTMapOverlay.m */; };
@@ -141,6 +142,9 @@
 		13A0C2881B74F71200B29F6F /* RCTDevMenu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDevMenu.m; sourceTree = "<group>"; };
 		13A1F71C1A75392D00D3D453 /* RCTKeyCommands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTKeyCommands.h; sourceTree = "<group>"; };
 		13A1F71D1A75392D00D3D453 /* RCTKeyCommands.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTKeyCommands.m; sourceTree = "<group>"; };
+		13A6E20C1C19AA0C00845B82 /* RCTParserUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTParserUtils.h; sourceTree = "<group>"; };
+		13A6E20D1C19AA0C00845B82 /* RCTParserUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTParserUtils.m; sourceTree = "<group>"; };
+		13A6E20F1C19ABC700845B82 /* RCTNullability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTNullability.h; sourceTree = "<group>"; };
 		13AB90BF1B6FA36700713B4F /* RCTComponentData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTComponentData.h; sourceTree = "<group>"; };
 		13AB90C01B6FA36700713B4F /* RCTComponentData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTComponentData.m; sourceTree = "<group>"; };
 		13AF1F851AE6E777005F5298 /* RCTDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDefines.h; sourceTree = "<group>"; };
@@ -518,6 +522,9 @@
 				14C2CA731B3AC64300E6CBB2 /* RCTModuleData.m */,
 				14C2CA6F1B3AC63800E6CBB2 /* RCTModuleMethod.h */,
 				14C2CA701B3AC63800E6CBB2 /* RCTModuleMethod.m */,
+				13A6E20F1C19ABC700845B82 /* RCTNullability.h */,
+				13A6E20C1C19AA0C00845B82 /* RCTParserUtils.h */,
+				13A6E20D1C19AA0C00845B82 /* RCTParserUtils.m */,
 				142014181B32094000CC17BA /* RCTPerformanceLogger.h */,
 				142014171B32094000CC17BA /* RCTPerformanceLogger.m */,
 				830A229C1A66C68A008503DA /* RCTRootView.h */,
@@ -674,6 +681,7 @@
 				83CBBA981A6020BB00E9B192 /* RCTTouchHandler.m in Sources */,
 				83CBBA521A601E3B00E9B192 /* RCTLog.m in Sources */,
 				13B0801D1A69489C00A75B9A /* RCTNavItemManager.m in Sources */,
+				13A6E20E1C19AA0C00845B82 /* RCTParserUtils.m in Sources */,
 				13E067571A70F44B002CDEE1 /* RCTView.m in Sources */,
 				13AFBCA01C07247D00BBAEAA /* RCTMapOverlay.m in Sources */,
 				13456E931ADAD2DE009F94A7 /* RCTConvert+CoreLocation.m in Sources */,
diff --git a/React/Views/RCTComponentData.m b/React/Views/RCTComponentData.m
index 4a0b45ad1e1b..0f8287b72883 100644
--- a/React/Views/RCTComponentData.m
+++ b/React/Views/RCTComponentData.m
@@ -114,7 +114,7 @@ - (RCTPropBlock)propBlockForKey:(NSString *)name defaultView:(id)defaultView
     if ([managerClass respondsToSelector:selector]) {
       NSArray<NSString *> *typeAndKeyPath =
         ((NSArray<NSString *> *(*)(id, SEL))objc_msgSend)(managerClass, selector);
-      type = NSSelectorFromString([typeAndKeyPath[0] stringByAppendingString:@":"]);
+      type = RCTConvertSelectorForType(typeAndKeyPath[0]);
       keyPath = typeAndKeyPath.count > 1 ? typeAndKeyPath[1] : nil;
     } else {
       propBlock = ^(__unused id view, __unused id json) {};
diff --git a/React/Views/RCTPickerManager.m b/React/Views/RCTPickerManager.m
index 759a05b6d8ad..54d75f210c9c 100644
--- a/React/Views/RCTPickerManager.m
+++ b/React/Views/RCTPickerManager.m
@@ -10,7 +10,6 @@
 #import "RCTPickerManager.h"
 
 #import "RCTBridge.h"
-#import "RCTConvert.h"
 #import "RCTPicker.h"
 
 @implementation RCTPickerManager
@@ -22,7 +21,7 @@ - (UIView *)view
   return [RCTPicker new];
 }
 
-RCT_EXPORT_VIEW_PROPERTY(items, NSDictionaryArray)
+RCT_EXPORT_VIEW_PROPERTY(items, NSArray<NSDictionary *>)
 RCT_EXPORT_VIEW_PROPERTY(selectedIndex, NSInteger)
 RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock)
 RCT_EXPORT_VIEW_PROPERTY(color, UIColor)
diff --git a/React/Views/RCTSegmentedControlManager.m b/React/Views/RCTSegmentedControlManager.m
index e56be4cf0317..c44f822cf323 100644
--- a/React/Views/RCTSegmentedControlManager.m
+++ b/React/Views/RCTSegmentedControlManager.m
@@ -22,7 +22,7 @@ - (UIView *)view
   return [RCTSegmentedControl new];
 }
 
-RCT_EXPORT_VIEW_PROPERTY(values, NSStringArray)
+RCT_EXPORT_VIEW_PROPERTY(values, NSArray<NSString *>)
 RCT_EXPORT_VIEW_PROPERTY(selectedIndex, NSInteger)
 RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
 RCT_EXPORT_VIEW_PROPERTY(momentary, BOOL)

From ac783a8a1b92b59683af85dd87518acd9c582db4 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 10 Dec 2015 12:04:53 -0800
Subject: [PATCH 0312/1411] Fix retain cycle

Summary:
public

This fixes the following circular reference:

RCTComponentData
-> _bridge -> RCTBatchedBridge
-> _moduleDataByName -> __NSDictionaryI
-> RCTModuleData
-> _instance -> RCTUIManager
-> _componentDataByName -> __NSDictionaryI
-> RCTComponentData

Reviewed By: javache

Differential Revision: D2744742

fb-gh-sync-id: c282786f4dfb550185bc03d3e5e3d03048664c21
---
 React/Views/RCTComponentData.h | 2 +-
 React/Views/RCTComponentData.m | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/React/Views/RCTComponentData.h b/React/Views/RCTComponentData.h
index f7151c22b543..c52af36472af 100644
--- a/React/Views/RCTComponentData.h
+++ b/React/Views/RCTComponentData.h
@@ -21,7 +21,7 @@
 
 @property (nonatomic, readonly) Class managerClass;
 @property (nonatomic, copy, readonly) NSString *name;
-@property (nonatomic, strong, readonly) RCTViewManager *manager;
+@property (nonatomic, weak, readonly) RCTViewManager *manager;
 
 - (instancetype)initWithManagerClass:(Class)managerClass
                               bridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
diff --git a/React/Views/RCTComponentData.m b/React/Views/RCTComponentData.m
index 0f8287b72883..42d7506eef45 100644
--- a/React/Views/RCTComponentData.m
+++ b/React/Views/RCTComponentData.m
@@ -44,7 +44,7 @@ @implementation RCTComponentData
   RCTShadowView *_defaultShadowView;
   NSMutableDictionary<NSString *, RCTPropBlock> *_viewPropBlocks;
   NSMutableDictionary<NSString *, RCTPropBlock> *_shadowPropBlocks;
-  RCTBridge *_bridge;
+  __weak RCTBridge *_bridge;
 }
 
 @synthesize manager = _manager;

From 3cfcd401c1f3e3297ffa9a3abf8bc3a8f286fa33 Mon Sep 17 00:00:00 2001
From: Thomas Parslow <tom@almostobsolete.net>
Date: Thu, 10 Dec 2015 12:42:22 -0800
Subject: [PATCH 0313/1411] Support onLayout and onContentSizeChange attributes
 on ListView

Summary:
Docs say they're supported and presumably they should work exactly as for ScrollView but currently they are intercepted by the ListView
Closes https://github.com/facebook/react-native/pull/4712

Reviewed By: svcscm

Differential Revision: D2745080

Pulled By: vjeux

fb-gh-sync-id: 531907f03ae46d5200003cdb335c10b40c7d3bed
---
 Libraries/CustomComponents/ListView/ListView.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js
index fa29da5d87ee..5b1ef4db0c19 100644
--- a/Libraries/CustomComponents/ListView/ListView.js
+++ b/Libraries/CustomComponents/ListView/ListView.js
@@ -436,6 +436,9 @@ var ListView = React.createClass({
       height : width;
     this._updateVisibleRows();
     this._renderMoreRowsIfNeeded();
+    if (this.props.onContentSizeChange) {
+      this.props.onContentSizeChange(width, height);
+    }
   },
 
   _onLayout: function(event) {
@@ -444,6 +447,9 @@ var ListView = React.createClass({
       height : width;
     this._updateVisibleRows();
     this._renderMoreRowsIfNeeded();
+    if (this.props.onLayout) {
+      this.props.onLayout(event);
+    }
   },
 
   _setScrollVisibleLength: function(left, top, width, height) {

From 3eb32cbb0e7baf23d62605b98a4635808374252e Mon Sep 17 00:00:00 2001
From: Leland Richardson <leland.m.richardson@gmail.com>
Date: Thu, 10 Dec 2015 13:27:52 -0800
Subject: [PATCH 0314/1411] Animated.multiply and Animated.add to combine
 animated values

Summary:
This PR was created in response to feedback from an older PR: https://github.com/facebook/react-native/pull/2045

The `.interpolate()` API of Animated values is quite effective to accomplish transformations based on a single animated value, but currently there is a class of animations that is impossible: animations being driven by more than one value.

Usage would be like the following:

```js
getInitialState: function() {
  return {
    panY: new Animated.Value(0),
    offset: new Animated.Value(0),
  };
}
```

```js
var scale = Animated.add(panY, offset).interpolate({
  inputRange: [...],
  outputRange: [...],
});
```

I have a real use case for this, and I cannot think of any way to accomplish what I need without an API like this.

The animation I am trying to accomplish is I have a PanResponder being used to detect both x and y panning. The y-axis panning drives a 3d sroll-like animation (which we can call `panY`), and the x-axis panning is driving a "swipe-to-remove" animation (
Closes https://github.com/facebook/react-native/pull/4395

Reviewed By: svcscm

Differential Revision: D2731305

Pulled By: vjeux

fb-gh-sync-id: 3b9422f10c7e7f3b3ecd270aeed8ea92315a89e9
---
 .../Animated/src/AnimatedImplementation.js    | 83 +++++++++++++++++++
 1 file changed, 83 insertions(+)

diff --git a/Libraries/Animated/src/AnimatedImplementation.js b/Libraries/Animated/src/AnimatedImplementation.js
index 3039f887b47c..e7edc16a9645 100644
--- a/Libraries/Animated/src/AnimatedImplementation.js
+++ b/Libraries/Animated/src/AnimatedImplementation.js
@@ -840,6 +840,64 @@ class AnimatedInterpolation extends AnimatedWithChildren {
   }
 }
 
+class AnimatedAddition extends AnimatedWithChildren {
+  _a: Animated;
+  _b: Animated;
+
+  constructor(a: Animated, b: Animated) {
+    super();
+    this._a = a;
+    this._b = b;
+  }
+
+  __getValue(): number {
+    return this._a.__getValue() + this._b.__getValue();
+  }
+
+  interpolate(config: InterpolationConfigType): AnimatedInterpolation {
+    return new AnimatedInterpolation(this, Interpolation.create(config));
+  }
+
+  __attach(): void {
+    this._a.__addChild(this);
+    this._b.__addChild(this);
+  }
+
+  __detach(): void {
+    this._a.__removeChild(this);
+    this._b.__removeChild(this);
+  }
+}
+
+class AnimatedMultiplication extends AnimatedWithChildren {
+  _a: Animated;
+  _b: Animated;
+
+  constructor(a: Animated, b: Animated) {
+    super();
+    this._a = a;
+    this._b = b;
+  }
+
+  __getValue(): number {
+    return this._a.__getValue() * this._b.__getValue();
+  }
+
+  interpolate(config: InterpolationConfigType): AnimatedInterpolation {
+    return new AnimatedInterpolation(this, Interpolation.create(config));
+  }
+
+  __attach(): void {
+    this._a.__addChild(this);
+    this._b.__addChild(this);
+  }
+
+  __detach(): void {
+    this._a.__removeChild(this);
+    this._b.__removeChild(this);
+  }
+}
+
 class AnimatedTransform extends AnimatedWithChildren {
   _transforms: Array<Object>;
 
@@ -1161,6 +1219,20 @@ type CompositeAnimation = {
   stop: () => void;
 };
 
+var add = function(
+  a: Animated,
+  b: Animated
+): AnimatedAddition {
+  return new AnimatedAddition(a, b);
+};
+
+var multiply = function(
+  a: Animated,
+  b: Animated
+): AnimatedMultiplication {
+  return new AnimatedMultiplication(a, b);
+};
+
 var maybeVectorAnim = function(
   value: AnimatedValue | AnimatedValueXY,
   config: Object,
@@ -1521,6 +1593,17 @@ module.exports = {
    */
   spring,
 
+  /**
+   * Creates a new Animated value composed from two Animated values added
+   * together.
+   */
+  add,
+  /**
+   * Creates a new Animated value composed from two Animated values multiplied
+   * together.
+   */
+  multiply,
+
   /**
    * Starts an animation after the given delay.
    */

From c5c41d9d4c228d145b1a439c83e3802fbd903dab Mon Sep 17 00:00:00 2001
From: Brent Vatne <brentvatne@gmail.com>
Date: Thu, 10 Dec 2015 13:55:32 -0800
Subject: [PATCH 0315/1411] Update Animations.md - LayoutAnimation is no longer
 iOS only

---
 docs/Animations.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/Animations.md b/docs/Animations.md
index 22a5f1c0f514..af9ccf0e9981 100644
--- a/docs/Animations.md
+++ b/docs/Animations.md
@@ -248,7 +248,7 @@ concise, robust, and performant way.  Check out more example code in
 doesn't support what you need, and the following sections cover other animation
 systems.
 
-### LayoutAnimation (iOS only)
+### LayoutAnimation
 
 `LayoutAnimation` allows you to globally configure `create` and `update`
 animations that will be used for all views in the next render/layout cycle.

From 53825f520623b4abebb379fb4756b868a3c925ec Mon Sep 17 00:00:00 2001
From: "glevi@fb.com" <glevi@fb.com>
Date: Thu, 10 Dec 2015 13:47:32 -0800
Subject: [PATCH 0316/1411] Fix errors in fbobjc

Reviewed By: nicklockwood

Differential Revision: D2745907

fb-gh-sync-id: f4687313ad817bb1d5a56bb766d8efa4a2926da7
---
 .../BatchedBridgedModules/NativeModules.js      |  5 +++--
 .../BatchedBridgedModules/NativeModules.js.flow | 17 +++++++++++++++++
 2 files changed, 20 insertions(+), 2 deletions(-)
 create mode 100644 Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js.flow

diff --git a/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js b/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js
index af1540b75b5d..c6f54bcb9385 100644
--- a/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js
+++ b/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js
@@ -41,7 +41,7 @@ Object.keys(RemoteModules).forEach((moduleName) => {
 const NativeModules = {};
 Object.keys(RemoteModules).forEach((moduleName) => {
   Object.defineProperty(NativeModules, moduleName, {
-    enumerable: true, 
+    enumerable: true,
     get: () => {
       let module = RemoteModules[moduleName];
       if (module && typeof module.moduleID === 'number' && global.nativeRequireModuleConfig) {
@@ -69,8 +69,9 @@ UIManager && Object.keys(UIManager).forEach(viewName => {
   const viewConfig = UIManager[viewName];
   const constants = {};
   if (viewConfig.Manager) {
+    /* $FlowFixMe - nice try. Flow doesn't like getters */
     Object.defineProperty(viewConfig, 'Constants', {
-      enumerable: true, 
+      enumerable: true,
       get: () => {
         const viewManager = NativeModules[normalizePrefix(viewConfig.Manager)];
         viewManager && Object.keys(viewManager).forEach(key => {
diff --git a/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js.flow b/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js.flow
new file mode 100644
index 000000000000..f2181b965b08
--- /dev/null
+++ b/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js.flow
@@ -0,0 +1,17 @@
+/**
+ * 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 NativeModules
+ * @flow
+ */
+'use strict';
+
+const BatchedBridge = require('BatchedBridge');
+const RemoteModules = BatchedBridge.RemoteModules;
+
+module.exports = RemoteModules;

From 201a3d010a821b22e3f17b935de30e23fbad4918 Mon Sep 17 00:00:00 2001
From: Nader Dabit <dabit3@gmail.com>
Date: Thu, 10 Dec 2015 17:27:46 -0600
Subject: [PATCH 0317/1411] fixed various spelling errors

---
 docs/AndroidUIPerformance.md    | 2 +-
 docs/Animations.md              | 2 +-
 docs/DevelopmentSetupAndroid.md | 2 +-
 docs/LinkingLibraries.md        | 2 +-
 docs/NativeComponentsAndroid.md | 2 +-
 docs/NavigatorComparison.md     | 2 +-
 docs/RunningOnDeviceAndroid.md  | 2 +-
 7 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/docs/AndroidUIPerformance.md b/docs/AndroidUIPerformance.md
index 399bd09eefe0..321bb0c46bfe 100644
--- a/docs/AndroidUIPerformance.md
+++ b/docs/AndroidUIPerformance.md
@@ -41,7 +41,7 @@ Once the trace starts collecting, perform the animation or interaction you care
 
 ## Reading the trace
 
-After opening the trace in your browser (preferrably Chrome), you should see something like this:
+After opening the trace in your browser (preferably Chrome), you should see something like this:
 
 ![Example](/react-native/img/SystraceExample.png)
 
diff --git a/docs/Animations.md b/docs/Animations.md
index af9ccf0e9981..84c3f48510fc 100644
--- a/docs/Animations.md
+++ b/docs/Animations.md
@@ -309,7 +309,7 @@ for more information.
 familiar with. It accepts a function as its only argument and calls that
 function before the next repaint. It is an essential building block for
 animations that underlies all of the JavaScript-based animation APIs.  In
-general, you shouldn't need to call this yourself - the animation API's will
+general, you shouldn't need to call this yourself - the animation APIs will
 manage frame updates for you.
 
 ### react-tween-state (Not recommended - use [Animated](#animated) instead)
diff --git a/docs/DevelopmentSetupAndroid.md b/docs/DevelopmentSetupAndroid.md
index e7d1f8b36ac2..23bf6a6366e1 100644
--- a/docs/DevelopmentSetupAndroid.md
+++ b/docs/DevelopmentSetupAndroid.md
@@ -45,7 +45,7 @@ __NOTE__: You need to restart the Command Prompt (Windows) / Terminal Emulator (
 
 ### Use gradle daemon
 
-React Native Android use [gradle](https://docs.gradle.org) as a build system. We recommend to enable gradle daemon functionailty which may result in up to 50% improvement in incremental build times for changes in java code. Learn [here](https://docs.gradle.org/2.9/userguide/gradle_daemon.html) how to enable it for your platform.
+React Native Android use [gradle](https://docs.gradle.org) as a build system. We recommend to enable gradle daemon functionality which may result in up to 50% improvement in incremental build times for changes in java code. Learn [here](https://docs.gradle.org/2.9/userguide/gradle_daemon.html) how to enable it for your platform.
 
 ### Configure your SDK
 
diff --git a/docs/LinkingLibraries.md b/docs/LinkingLibraries.md
index db29a4bc2f4e..c5cf659cf883 100644
--- a/docs/LinkingLibraries.md
+++ b/docs/LinkingLibraries.md
@@ -54,7 +54,7 @@ This step is not necessary for libraries that we ship with React Native with the
 exception of `PushNotificationIOS` and `LinkingIOS`.
 
 In the case of the `PushNotificationIOS` for example, you have to call a method
-on the library from your `AppDelegate` every time a new push notifiation is
+on the library from your `AppDelegate` every time a new push notification is
 received.
 
 For that we need to know the library's headers. To achieve that you have to go
diff --git a/docs/NativeComponentsAndroid.md b/docs/NativeComponentsAndroid.md
index f70c32ee6188..3e729e18b4e8 100644
--- a/docs/NativeComponentsAndroid.md
+++ b/docs/NativeComponentsAndroid.md
@@ -57,7 +57,7 @@ Views are created in the `createViewInstance` method, the view should initialize
 
 ## 3. Expose view property setters using `@ReactProp` (or `@ReactPropGroup`) annotation
 
-Properties that are to be reflected in JavaScript needs to be exposed as setter method annotated with `@ReactProp` (or `@ReactPropGroup`). Setter method should take view to be updated (of the current view type) as a first argument and property value as a second argument. Setter should be declared as a `void` method and should be `public`. Property type sent to JS is determined automatically based on the type of value argumen of the setter. The following type of values are currently supported: `boolean`, `int`, `float`, `double`, `String`, `Boolean`, `Integer`, `ReadableArray`, `ReadableMap`. 
+Properties that are to be reflected in JavaScript needs to be exposed as setter method annotated with `@ReactProp` (or `@ReactPropGroup`). Setter method should take view to be updated (of the current view type) as a first argument and property value as a second argument. Setter should be declared as a `void` method and should be `public`. Property type sent to JS is determined automatically based on the type of value argument of the setter. The following type of values are currently supported: `boolean`, `int`, `float`, `double`, `String`, `Boolean`, `Integer`, `ReadableArray`, `ReadableMap`. 
 
 Annotation `@ReactProp` has one obligatory argument `name` of type `String`. Name assigned to the `@ReactProp` annotation linked to the setter method is used to reference the property on JS side.
 
diff --git a/docs/NavigatorComparison.md b/docs/NavigatorComparison.md
index 326ef98d1265..cc6c5c6c8bbd 100644
--- a/docs/NavigatorComparison.md
+++ b/docs/NavigatorComparison.md
@@ -41,7 +41,7 @@ between the two.
 - Development belongs to open-source community - not used by the React Native team on their apps.
   - A result of this is that there is currently a backlog of unresolved bugs, nobody who uses this has stepped up to take ownership for it yet.
 - Wraps UIKit, so it works exactly the same as it would on another native app. Lives in Objective-C and JavaScript.
-  - Consequently, you get the animations and behaviour that Apple has developed.
+  - Consequently, you get the animations and behavior that Apple has developed.
 - iOS only.
 - Includes a navigation bar by default; this navigation bar is not a React Native view component and the style can only be slightly modified.
 
diff --git a/docs/RunningOnDeviceAndroid.md b/docs/RunningOnDeviceAndroid.md
index 08bc5f8da75b..1b64faf22dd8 100644
--- a/docs/RunningOnDeviceAndroid.md
+++ b/docs/RunningOnDeviceAndroid.md
@@ -20,7 +20,7 @@ Check that your device has been **successfully connected** by running `adb devic
 
 Seeing **device** in the right column means the device is connected. Android - go figure :) You must have **only one device connected**.
 
-Now you can use `react-native run-android` to install and lauch your app on the device.
+Now you can use `react-native run-android` to install and launch your app on the device.
 
 ## Accessing development server from device
 

From 6e6a92eeeedfbad5fe5a0033bbfbbcadc2d16492 Mon Sep 17 00:00:00 2001
From: Cory Binnersley <cory.binnersley@gmail.com>
Date: Thu, 10 Dec 2015 15:36:52 -0800
Subject: [PATCH 0318/1411] Added Accio Delivery App to website showcase.

---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 4fbcb58ef3a0..953d9406205d 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -116,6 +116,12 @@ var featured = [
 ];
 
 var apps = [
+  {
+    name: 'Accio',
+    icon: 'http://a3.mzstatic.com/us/r30/Purple3/v4/03/a1/5b/03a15b9f-04d7-a70a-620a-9c9850a859aa/icon175x175.png',
+    link: 'https://itunes.apple.com/us/app/accio-on-demand-delivery/id1047060673?mt=8',
+    author: 'Accio Delivery Inc.',
+  },
   {
     name: 'Beetroot',
     icon: 'http://is1.mzstatic.com/image/pf/us/r30/Purple5/v4/66/fd/dd/66fddd70-f848-4fc5-43ee-4d52197ccab8/pr_source.png',

From a04e2bed5439220c39bbace3f1ad441787be7337 Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Thu, 10 Dec 2015 17:58:30 -0800
Subject: [PATCH 0319/1411] Update node-haste from upstream

Reviewed By: zpao

Differential Revision: D2747183

fb-gh-sync-id: f1b963b19cb6ea16945b16370d1bee26110bb329
---
 .../__tests__/DependencyGraph-test.js         | 74 +++++++++----------
 .../DependencyGraph/docblock.js               |  2 +-
 .../src/DependencyResolver/Package.js         |  2 +-
 .../src/DependencyResolver/replacePatterns.js | 15 ----
 4 files changed, 39 insertions(+), 54 deletions(-)
 delete mode 100644 packager/react-packager/src/DependencyResolver/replacePatterns.js

diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
index d830cc825dda..8b50c8b49c52 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
@@ -1362,19 +1362,19 @@ describe('DependencyGraph', function() {
       });
     });
 
-    testBrowserField('browser')
-    testBrowserField('react-native')
+    testBrowserField('browser');
+    testBrowserField('react-native');
 
-    function replaceBrowserField (json, fieldName) {
+    function replaceBrowserField(json, fieldName) {
       if (fieldName !== 'browser') {
-        json[fieldName] = json.browser
-        delete json.browser
+        json[fieldName] = json.browser;
+        delete json.browser;
       }
 
-      return json
+      return json;
     }
 
-    function testBrowserField (fieldName) {
+    function testBrowserField(fieldName) {
       pit('should support simple browser field in packages ("' + fieldName + '")', function() {
         var root = '/root';
         fs.__setMockFilesystem({
@@ -1393,8 +1393,8 @@ describe('DependencyGraph', function() {
               }, fieldName)),
               'main.js': 'some other code',
               'client.js': 'some code',
-            }
-          }
+            },
+          },
         });
 
         var dgraph = new DependencyGraph({
@@ -1448,8 +1448,8 @@ describe('DependencyGraph', function() {
               }, fieldName)),
               'main.js': 'some other code',
               'client.js': 'some code',
-            }
-          }
+            },
+          },
         });
 
         var dgraph = new DependencyGraph({
@@ -1503,8 +1503,8 @@ describe('DependencyGraph', function() {
               }, fieldName)),
               'main.js': 'some other code',
               'client.js': 'some code',
-            }
-          }
+            },
+          },
         });
 
         var dgraph = new DependencyGraph({
@@ -1559,8 +1559,8 @@ describe('DependencyGraph', function() {
               }, fieldName)),
               'main.js': 'some other code',
               'client.js': 'some code',
-            }
-          }
+            },
+          },
         });
 
         var dgraph = new DependencyGraph({
@@ -1630,15 +1630,15 @@ describe('DependencyGraph', function() {
               },
               'hello.js': 'hello',
               'bye.js': 'bye',
-            }
-          }
+            },
+          },
         });
 
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
+        const dgraph = new DependencyGraph({
+          ...defaults,
+          roots: [root],
+        });
+        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
           expect(deps)
             .toEqual([
               { id: 'index',
@@ -1716,7 +1716,7 @@ describe('DependencyGraph', function() {
                 name: 'aPackage',
                 browser: {
                   'node-package': 'browser-package',
-                }
+                },
               }, fieldName)),
               'index.js': 'require("node-package")',
               'node-package': {
@@ -1731,8 +1731,8 @@ describe('DependencyGraph', function() {
                 }),
                 'index.js': 'some browser code',
               },
-            }
-          }
+            },
+          },
         });
 
         var dgraph = new DependencyGraph({
@@ -1788,7 +1788,7 @@ describe('DependencyGraph', function() {
                 name: 'aPackage',
                 browser: {
                   'node-package': 'browser-package',
-                }
+                },
               }, fieldName)),
               'index.js': 'require("node-package")',
               'node-package': {
@@ -1803,8 +1803,8 @@ describe('DependencyGraph', function() {
                 }),
                 'index.js': 'some browser code',
               },
-            }
-          }
+            },
+          },
         });
 
         var dgraph = new DependencyGraph({
@@ -1861,13 +1861,13 @@ describe('DependencyGraph', function() {
               name: 'aPackage',
               'react-native': {
                 'node-package': 'rn-package',
-              }
+              },
             }),
             'index.js': 'require("node-package")',
             'node_modules': {
               'node-package': {
                 'package.json': JSON.stringify({
-                  'name': 'node-package'
+                  'name': 'node-package',
                 }),
                 'index.js': 'some node code',
               },
@@ -1875,8 +1875,8 @@ describe('DependencyGraph', function() {
                 'package.json': JSON.stringify({
                   'name': 'rn-package',
                   browser: {
-                    'nested-package': 'nested-browser-package'
-                  }
+                    'nested-package': 'nested-browser-package',
+                  },
                 }),
                 'index.js': 'require("nested-package")',
               },
@@ -1884,11 +1884,11 @@ describe('DependencyGraph', function() {
                 'package.json': JSON.stringify({
                   'name': 'nested-browser-package',
                 }),
-                'index.js': 'some code'
-              }
-            }
-          }
-        }
+                'index.js': 'some code',
+              },
+            },
+          },
+        },
       });
 
       var dgraph = new DependencyGraph({
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/docblock.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/docblock.js
index 131f09d1f6f2..d710112a9587 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/docblock.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/docblock.js
@@ -25,7 +25,7 @@ function extract(contents) {
 }
 
 
-var commentStartRe = /^\/\*\*?/;
+var commentStartRe = /^\/\*\*/;
 var commentEndRe = /\*\/$/;
 var wsRe = /[\t ]+/g;
 var stringStartRe = /(\r?\n|^) *\*/g;
diff --git a/packager/react-packager/src/DependencyResolver/Package.js b/packager/react-packager/src/DependencyResolver/Package.js
index 2117e3f1976a..ac7ee88c1a06 100644
--- a/packager/react-packager/src/DependencyResolver/Package.js
+++ b/packager/react-packager/src/DependencyResolver/Package.js
@@ -15,7 +15,7 @@ class Package {
 
   getMain() {
     return this._read().then(json => {
-      var replacements = getReplacements(json)
+      var replacements = getReplacements(json);
       if (typeof replacements === 'string') {
         return path.join(this.root, replacements);
       }
diff --git a/packager/react-packager/src/DependencyResolver/replacePatterns.js b/packager/react-packager/src/DependencyResolver/replacePatterns.js
deleted file mode 100644
index a4e563d2c67c..000000000000
--- a/packager/react-packager/src/DependencyResolver/replacePatterns.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * 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.
- */
-
-'use strict';
-
-exports.IMPORT_RE = /(\bimport\s+(?:[^'"]+\s+from\s+)??)(['"])([^'"]+)(\2)/g;
-exports.EXPORT_RE = /(\bexport\s+(?:[^'"]+\s+from\s+)??)(['"])([^'"]+)(\2)/g;
-exports.REQUIRE_RE = /(\brequire\s*?\(\s*?)(['"])([^'"]+)(\2\s*?\))/g;
-exports.SYSTEM_IMPORT_RE = /(\bSystem\.import\s*?\(\s*?)(['"])([^'"]+)(\2\s*?\))/g;

From b78b8f6cab4439ad32b8c322f59a11ee2abe6c62 Mon Sep 17 00:00:00 2001
From: Dave Sibiski <dsibiski@gmail.com>
Date: Thu, 10 Dec 2015 22:50:03 -0800
Subject: [PATCH 0320/1411] Fixes grammar in comment

Summary: Closes https://github.com/facebook/react-native/pull/4726

Reviewed By: svcscm

Differential Revision: D2748499

Pulled By: androidtrunkagent

fb-gh-sync-id: cbc6bc7b6692191bc68b8e1782897d17bc01bfa3
---
 React/Profiler/RCTProfile.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/React/Profiler/RCTProfile.h b/React/Profiler/RCTProfile.h
index a013a70703a3..1cd721ab7cd2 100644
--- a/React/Profiler/RCTProfile.h
+++ b/React/Profiler/RCTProfile.h
@@ -16,8 +16,8 @@
  *
  * This file provides a set of functions and macros for performance profiling
  *
- * NOTE: This API is a work in a work in progress, please consider carefully
- * before before using it.
+ * NOTE: This API is a work in progress, please consider carefully before
+ * using it.
  */
 
 RCT_EXTERN NSString *const RCTProfileDidStartProfiling;

From ae912a83d7e7ddf40beae3b79aabdaa1f54d4088 Mon Sep 17 00:00:00 2001
From: Sebastian Markbage <sema@fb.com>
Date: Thu, 10 Dec 2015 23:15:38 -0800
Subject: [PATCH 0321/1411] Codemod Internal Unit Tests and Remove Require
 Fallback

Summary:
MessageQueue no longer falls back to require. To do this we need to register all the modules in our internal unit tests. I did this codemod manually.

This is a bit unfortunate boilerplate but there are very few of these modules outside of unit tests. This boilerplate is only a hassle for these test files.

public

Reviewed By: spicyj

Differential Revision: D2736397

fb-gh-sync-id: 59fa4c4e75c538f3577bc9693b93e1b7c4d4d233
---
 Libraries/Utilities/MessageQueue.js | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/Libraries/Utilities/MessageQueue.js b/Libraries/Utilities/MessageQueue.js
index adf9376e33e0..888afea2a943 100644
--- a/Libraries/Utilities/MessageQueue.js
+++ b/Libraries/Utilities/MessageQueue.js
@@ -159,20 +159,11 @@ class MessageQueue {
       console.log('N->JS : ' + module + '.' + method + '(' + JSON.stringify(args) + ')');
     }
     var moduleMethods = this._callableModules[module];
-    if (!moduleMethods) {
-      // TODO: Register all the remaining test modules and make this an invariant. #9317773
-      // Fallback to require temporarily. A follow up diff will clean up the remaining
-      // modules and make this an invariant.
-      console.warn('Module is not registered:', module);
-      moduleMethods = require(module);
-      /*
-      invariant(
-        !!moduleMethods,
-        'Module %s is not a registered callable module.',
-        module
-      );
-      */
-    }
+    invariant(
+      !!moduleMethods,
+      'Module %s is not a registered callable module.',
+      module
+    );
     moduleMethods[method].apply(moduleMethods, args);
     BridgeProfiling.profileEnd();
   }

From 44cbec28bdf93ecb90d8a2f4e2c1e5f4888b1ae9 Mon Sep 17 00:00:00 2001
From: Justin Spahr-Summers <jspahrsummers@fb.com>
Date: Fri, 11 Dec 2015 01:42:17 -0800
Subject: [PATCH 0322/1411] Work around race condition in bridge deallocation

Reviewed By: tadeuzagallo, nicklockwood

Differential Revision: D2748820

fb-gh-sync-id: 40084ab4bcc606ccbde8b71c2389e602c4dd8e22
---
 React/Base/RCTBridge.m | 30 +++++++++++++++++++-----------
 1 file changed, 19 insertions(+), 11 deletions(-)

diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m
index 3e4a1bc5c0d1..70bd92688ef3 100644
--- a/React/Base/RCTBridge.m
+++ b/React/Base/RCTBridge.m
@@ -36,7 +36,11 @@ - (instancetype)initWithParentBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZ
 
 @interface RCTBridge ()
 
-@property (nonatomic, strong) RCTBatchedBridge *batchedBridge;
+// This property is mostly used on the main thread, but may be touched from
+// a background thread if the RCTBridge happens to deallocate on a background
+// thread. Therefore, we want all writes to it to be seen atomically.
+@property (atomic, strong) RCTBatchedBridge *batchedBridge;
+
 @property (nonatomic, copy, readonly) RCTBridgeModuleProviderBlock moduleProvider;
 
 @end
@@ -232,12 +236,12 @@ - (void)bindKeys
 
 - (NSArray<Class> *)moduleClasses
 {
-  return _batchedBridge.moduleClasses;
+  return self.batchedBridge.moduleClasses;
 }
 
 - (id)moduleForName:(NSString *)moduleName
 {
-  return [_batchedBridge moduleForName:moduleName];
+  return [self.batchedBridge moduleForName:moduleName];
 }
 
 - (id)moduleForClass:(Class)moduleClass
@@ -270,30 +274,34 @@ - (void)setUp
   // Sanitize the bundle URL
   _bundleURL = [RCTConvert NSURL:_bundleURL.absoluteString];
 
-  _batchedBridge = [[RCTBatchedBridge alloc] initWithParentBridge:self];
+  self.batchedBridge = [[RCTBatchedBridge alloc] initWithParentBridge:self];
 }
 
 - (BOOL)isLoading
 {
-  return _batchedBridge.loading;
+  return self.batchedBridge.loading;
 }
 
 - (BOOL)isValid
 {
-  return _batchedBridge.valid;
+  return self.batchedBridge.valid;
 }
 
 - (void)invalidate
 {
-  RCTAssertMainThread();
+  RCTBatchedBridge *batchedBridge = self.batchedBridge;
+  self.batchedBridge = nil;
 
-  [_batchedBridge invalidate];
-  _batchedBridge = nil;
+  if (batchedBridge) {
+    RCTExecuteOnMainThread(^{
+      [batchedBridge invalidate];
+    }, NO);
+  }
 }
 
 - (void)logMessage:(NSString *)message level:(NSString *)level
 {
-  [_batchedBridge logMessage:message level:level];
+  [self.batchedBridge logMessage:message level:level];
 }
 
 
@@ -321,7 +329,7 @@ @implementation RCTBridge(Deprecated)
 
 - (NSDictionary *)modules
 {
-  return _batchedBridge.modules;
+  return self.batchedBridge.modules;
 }
 
 @end

From 3549ff049c55feb151f454d9181c7d635f46a6ca Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Fri, 11 Dec 2015 03:49:15 -0800
Subject: [PATCH 0323/1411] Rename BridgeProfiling to Systrace for consistency

Summary:
public

Rename the `BridgeProfiling` JS module to `Systrace`, since it's actually just
an API to Systrace markers.

This should make it clearer as we add more perf tooling.

Reviewed By: jspahrsummers

Differential Revision: D2734001

fb-gh-sync-id: 642848fa7340c545067f2a7cf5cef8af1c8a69a2
---
 Libraries/BatchedBridge/BatchedBridge.js      |  4 +-
 .../InitializeJavaScriptAppEngine.js          |  4 +-
 .../System/JSTimers/JSTimersExecution.js      |  6 +--
 Libraries/Utilities/MessageQueue.js           | 22 +++++-----
 .../{BridgeProfiling.js => Systrace.js}       | 44 +++++++++----------
 React/Executors/RCTContextExecutor.m          |  2 +-
 .../facebook/react/CoreModulesPackage.java    |  3 +-
 .../react/bridge/CatalystInstanceImpl.java    |  4 +-
 .../{BridgeProfiling.java => Systrace.java}   |  4 +-
 .../src/Resolver/polyfills/require.js         | 14 +++---
 10 files changed, 53 insertions(+), 54 deletions(-)
 rename Libraries/Utilities/{BridgeProfiling.js => Systrace.js} (77%)
 rename ReactAndroid/src/main/java/com/facebook/react/bridge/{BridgeProfiling.java => Systrace.java} (66%)

diff --git a/Libraries/BatchedBridge/BatchedBridge.js b/Libraries/BatchedBridge/BatchedBridge.js
index e4269735afb5..6d25db30e217 100644
--- a/Libraries/BatchedBridge/BatchedBridge.js
+++ b/Libraries/BatchedBridge/BatchedBridge.js
@@ -19,10 +19,10 @@ const BatchedBridge = new MessageQueue(
 
 // TODO: Move these around to solve the cycle in a cleaner way.
 
-const BridgeProfiling = require('BridgeProfiling');
+const Systrace = require('Systrace');
 const JSTimersExecution = require('JSTimersExecution');
 
-BatchedBridge.registerCallableModule('BridgeProfiling', BridgeProfiling);
+BatchedBridge.registerCallableModule('Systrace', Systrace);
 BatchedBridge.registerCallableModule('JSTimersExecution', JSTimersExecution);
 
 // Wire up the batched bridge on the global object so that we can call into it.
diff --git a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
index 141ea7045cd7..cb6ba3275542 100644
--- a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
+++ b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
@@ -165,8 +165,8 @@ function setUpWebSockets() {
 
 function setUpProfile() {
   if (__DEV__) {
-    var BridgeProfiling = require('BridgeProfiling');
-    BridgeProfiling.swizzleReactPerf();
+    var Systrace = require('Systrace');
+    Systrace.swizzleReactPerf();
   }
 }
 
diff --git a/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimersExecution.js b/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimersExecution.js
index 07a324d41f4c..c85c155a7726 100644
--- a/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimersExecution.js
+++ b/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimersExecution.js
@@ -14,7 +14,7 @@ var invariant = require('invariant');
 var keyMirror = require('keyMirror');
 var performanceNow = require('performanceNow');
 var warning = require('warning');
-var BridgeProfiling = require('BridgeProfiling');
+var Systrace = require('Systrace');
 
 /**
  * JS implementation of timer functions. Must be completely driven by an
@@ -113,7 +113,7 @@ var JSTimersExecution = {
    * more immediates are queued up (can be used as a condition a while loop).
    */
   callImmediatesPass: function() {
-    BridgeProfiling.profile('JSTimersExecution.callImmediatesPass()');
+    Systrace.beginEvent('JSTimersExecution.callImmediatesPass()');
 
     // The main reason to extract a single pass is so that we can track
     // in the system trace
@@ -128,7 +128,7 @@ var JSTimersExecution = {
       }
     }
 
-    BridgeProfiling.profileEnd();
+    Systrace.endEvent();
 
     return JSTimersExecution.immediates.length > 0;
   },
diff --git a/Libraries/Utilities/MessageQueue.js b/Libraries/Utilities/MessageQueue.js
index 888afea2a943..10a41919a728 100644
--- a/Libraries/Utilities/MessageQueue.js
+++ b/Libraries/Utilities/MessageQueue.js
@@ -13,7 +13,7 @@
 
 'use strict';
 
-let BridgeProfiling = require('BridgeProfiling');
+let Systrace = require('Systrace');
 let ErrorUtils = require('ErrorUtils');
 let JSTimersExecution = require('JSTimersExecution');
 
@@ -114,9 +114,9 @@ class MessageQueue {
    */
 
   __callImmediates() {
-    BridgeProfiling.profile('JSTimersExecution.callImmediates()');
+    Systrace.beginEvent('JSTimersExecution.callImmediates()');
     guard(() => JSTimersExecution.callImmediates());
-    BridgeProfiling.profileEnd();
+    Systrace.endEvent();
   }
 
   __nativeCall(module, method, params, onFail, onSucc) {
@@ -154,7 +154,7 @@ class MessageQueue {
       method = this._methodTable[module][method];
       module = this._moduleTable[module];
     }
-    BridgeProfiling.profile(() => `${module}.${method}(${stringifySafe(args)})`);
+    Systrace.beginEvent(() => `${module}.${method}(${stringifySafe(args)})`);
     if (__DEV__ && SPY_MODE) {
       console.log('N->JS : ' + module + '.' + method + '(' + JSON.stringify(args) + ')');
     }
@@ -165,11 +165,11 @@ class MessageQueue {
       module
     );
     moduleMethods[method].apply(moduleMethods, args);
-    BridgeProfiling.profileEnd();
+    Systrace.endEvent();
   }
 
   __invokeCallback(cbID, args) {
-    BridgeProfiling.profile(
+    Systrace.beginEvent(
       () => `MessageQueue.invokeCallback(${cbID}, ${stringifySafe(args)})`);
     this._lastFlush = new Date().getTime();
     let callback = this._callbacks[cbID];
@@ -188,7 +188,7 @@ class MessageQueue {
     this._callbacks[cbID & ~1] = null;
     this._callbacks[cbID |  1] = null;
     callback.apply(null, args);
-    BridgeProfiling.profileEnd();
+    Systrace.endEvent();
   }
 
   /**
@@ -244,7 +244,7 @@ class MessageQueue {
       this._genLookup(config, moduleID, moduleTable, methodTable);
     });
   }
-  
+
   _genLookup(config, moduleID, moduleTable, methodTable) {
     if (!config) {
       return;
@@ -287,15 +287,15 @@ class MessageQueue {
       module[methodName] = this._genMethod(moduleID, methodID, methodType);
     });
     Object.assign(module, constants);
-    
+
     if (!constants && !methods && !asyncMethods) {
       module.moduleID = moduleID;
     }
-    
+
     this.RemoteModules[moduleName] = module;
     return module;
   }
-  
+
   _genMethod(module, method, type) {
     let fn = null;
     let self = this;
diff --git a/Libraries/Utilities/BridgeProfiling.js b/Libraries/Utilities/Systrace.js
similarity index 77%
rename from Libraries/Utilities/BridgeProfiling.js
rename to Libraries/Utilities/Systrace.js
index 36cb86252f61..826be67a1748 100644
--- a/Libraries/Utilities/BridgeProfiling.js
+++ b/Libraries/Utilities/Systrace.js
@@ -6,7 +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.
  *
- * @providesModule BridgeProfiling
+ * @providesModule Systrace
  * @flow
  */
 'use strict';
@@ -32,7 +32,7 @@ function ReactPerf() {
   return _ReactPerf;
 }
 
-var BridgeProfiling = {
+var Systrace = {
   setEnabled(enabled: boolean) {
     if (_enabled !== enabled) {
       if (enabled) {
@@ -47,9 +47,9 @@ var BridgeProfiling = {
   },
 
   /**
-   * profile/profileEnd for starting and then ending a profile within the same call stack frame
+   * beginEvent/endEvent for starting and then ending a profile within the same call stack frame
   **/
-  profile(profileName?: any) {
+  beginEvent(profileName?: any) {
     if (_enabled) {
       profileName = typeof profileName === 'function' ?
         profileName() : profileName;
@@ -57,18 +57,18 @@ var BridgeProfiling = {
     }
   },
 
-  profileEnd() {
+  endEvent() {
     if (_enabled) {
       global.nativeTraceEndSection(TRACE_TAG_REACT_APPS);
     }
   },
 
   /**
-   * profileAsync/profileAsyncEnd for starting and then ending a profile where the end can either
+   * beginAsyncEvent/endAsyncEvent for starting and then ending a profile where the end can either
    * occur on another thread or out of the current stack frame, eg await
-   * the returned cookie variable should be used as input into the asyncEnd call to end the profile
+   * the returned cookie variable should be used as input into the endAsyncEvent call to end the profile
   **/
-  profileAsync(profileName?: any): any {
+  beginAsyncEvent(profileName?: any): any {
     var cookie = _asyncCookie;
     if (_enabled) {
       _asyncCookie++;
@@ -79,7 +79,7 @@ var BridgeProfiling = {
     return cookie;
   },
 
-  profileAsyncEnd(profileName?: any, cookie?: any) {
+  endAsyncEvent(profileName?: any, cookie?: any) {
     if (_enabled) {
       profileName = typeof profileName === 'function' ?
         profileName() : profileName;
@@ -94,15 +94,15 @@ var BridgeProfiling = {
       }
 
       var name = objName === 'ReactCompositeComponent' && this.getName() || '';
-      BridgeProfiling.profile(`${objName}.${fnName}(${name})`);
+      Systrace.beginEvent(`${objName}.${fnName}(${name})`);
     var ret = func.apply(this, arguments);
-      BridgeProfiling.profileEnd();
+      Systrace.endEvent();
       return ret;
     };
   },
 
   swizzleReactPerf() {
-    ReactPerf().injection.injectMeasure(BridgeProfiling.reactPerfMeasure);
+    ReactPerf().injection.injectMeasure(Systrace.reactPerfMeasure);
   },
 
   /**
@@ -111,9 +111,9 @@ var BridgeProfiling = {
   **/
   attachToRelayProfiler(relayProfiler: RelayProfiler) {
     relayProfiler.attachProfileHandler('*', (name) => {
-      var cookie = BridgeProfiling.profileAsync(name);
+      var cookie = Systrace.beginAsyncEvent(name);
       return () => {
-        BridgeProfiling.profileAsyncEnd(name, cookie);
+        Systrace.endAsyncEvent(name, cookie);
       };
     });
   },
@@ -121,7 +121,7 @@ var BridgeProfiling = {
   /* This is not called by default due to perf overhead but it's useful
      if you want to find traces which spend too much time in JSON. */
   swizzleJSON() {
-    BridgeProfiling.measureMethods(JSON, 'JSON', [
+    Systrace.measureMethods(JSON, 'JSON', [
       'parse',
       'stringify'
     ]);
@@ -129,7 +129,7 @@ var BridgeProfiling = {
 
  /**
   * Measures multiple methods of a class. For example, you can do:
-  * BridgeProfiling.measureMethods(JSON, 'JSON', ['parse', 'stringify']);
+  * Systrace.measureMethods(JSON, 'JSON', ['parse', 'stringify']);
   *
   * @param object
   * @param objectName
@@ -141,7 +141,7 @@ var BridgeProfiling = {
    }
 
    methodNames.forEach(methodName => {
-     object[methodName] = BridgeProfiling.measure(
+     object[methodName] = Systrace.measure(
        objectName,
        methodName,
        object[methodName]
@@ -151,7 +151,7 @@ var BridgeProfiling = {
 
  /**
   * Returns an profiled version of the input function. For example, you can:
-  * JSON.parse = BridgeProfiling.measure('JSON', 'parse', JSON.parse);
+  * JSON.parse = Systrace.measure('JSON', 'parse', JSON.parse);
   *
   * @param objName
   * @param fnName
@@ -169,14 +169,14 @@ var BridgeProfiling = {
        return func.apply(this, arguments);
      }
 
-     BridgeProfiling.profile(profileName);
+     Systrace.beginEvent(profileName);
      var ret = func.apply(this, arguments);
-     BridgeProfiling.profileEnd();
+     Systrace.endEvent();
      return ret;
    };
  },
 };
 
-BridgeProfiling.setEnabled(global.__RCTProfileIsProfiling || false);
+Systrace.setEnabled(global.__RCTProfileIsProfiling || false);
 
-module.exports = BridgeProfiling;
+module.exports = Systrace;
diff --git a/React/Executors/RCTContextExecutor.m b/React/Executors/RCTContextExecutor.m
index d37f6c7b9313..55b0d506c35c 100644
--- a/React/Executors/RCTContextExecutor.m
+++ b/React/Executors/RCTContextExecutor.m
@@ -418,7 +418,7 @@ - (void)toggleProfilingFlag:(NSNotification *)notification
   [self executeBlockOnJavaScriptQueue:^{
     BOOL enabled = [notification.name isEqualToString:RCTProfileDidStartProfiling];
     // TODO: Don't use require, go through the normal execution modes instead. #9317773
-    NSString *script = [NSString stringWithFormat:@"var p = require('BridgeProfiling') || {}; p.setEnabled && p.setEnabled(%@)", enabled ? @"true" : @"false"];
+    NSString *script = [NSString stringWithFormat:@"var p = require('Systrace') || {}; p.setEnabled && p.setEnabled(%@)", enabled ? @"true" : @"false"];
     JSStringRef scriptJSRef = JSStringCreateWithUTF8CString(script.UTF8String);
     JSEvaluateScript(_context.ctx, scriptJSRef, NULL, NULL, 0, NULL);
     JSStringRelease(scriptJSRef);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java b/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java
index 28bc76f82406..07b18b066b30 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java
@@ -13,7 +13,6 @@
 import java.util.Arrays;
 import java.util.List;
 
-import com.facebook.react.bridge.BridgeProfiling;
 import com.facebook.react.bridge.JavaScriptModule;
 import com.facebook.react.bridge.NativeModule;
 import com.facebook.react.bridge.ReactApplicationContext;
@@ -95,7 +94,7 @@ public List<Class<? extends JavaScriptModule>> createJSModules() {
         RCTEventEmitter.class,
         RCTNativeAppEventEmitter.class,
         AppRegistry.class,
-        BridgeProfiling.class,
+        com.facebook.react.bridge.Systrace.class,
         DebugComponentOwnershipModule.RCTDebugComponentOwnership.class);
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
index 06d53a85efca..87ae11a2bb27 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
@@ -469,12 +469,12 @@ public void run() {
   private class JSProfilerTraceListener implements TraceListener {
     @Override
     public void onTraceStarted() {
-      getJSModule(BridgeProfiling.class).setEnabled(true);
+      getJSModule(com.facebook.react.bridge.Systrace.class).setEnabled(true);
     }
 
     @Override
     public void onTraceStopped() {
-      getJSModule(BridgeProfiling.class).setEnabled(false);
+      getJSModule(com.facebook.react.bridge.Systrace.class).setEnabled(false);
     }
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/BridgeProfiling.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/Systrace.java
similarity index 66%
rename from ReactAndroid/src/main/java/com/facebook/react/bridge/BridgeProfiling.java
rename to ReactAndroid/src/main/java/com/facebook/react/bridge/Systrace.java
index 50a3a72b984f..9f571e8651fa 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/BridgeProfiling.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/Systrace.java
@@ -5,10 +5,10 @@
 import com.facebook.proguard.annotations.DoNotStrip;
 
 /**
- * Interface to the JavaScript BridgeProfiling Module
+ * Interface to the JavaScript Systrace Module
  */
 @DoNotStrip
-public interface BridgeProfiling extends JavaScriptModule{
+public interface Systrace extends JavaScriptModule{
   @DoNotStrip
   void setEnabled(boolean enabled);
 }
diff --git a/packager/react-packager/src/Resolver/polyfills/require.js b/packager/react-packager/src/Resolver/polyfills/require.js
index ebaa8c406d75..506d38e02484 100644
--- a/packager/react-packager/src/Resolver/polyfills/require.js
+++ b/packager/react-packager/src/Resolver/polyfills/require.js
@@ -54,13 +54,13 @@
       // require cycles inside the factory from causing an infinite require loop.
       mod.isInitialized = true;
 
-      __DEV__ && BridgeProfiling().profile('JS_require_' + id);
+      __DEV__ && Systrace().beginEvent('JS_require_' + id);
 
       // keep args in sync with with defineModuleCode in
       // packager/react-packager/src/Resolver/index.js
       mod.factory.call(global, global, require, mod.module, mod.module.exports);
 
-      __DEV__ && BridgeProfiling().profileEnd();
+      __DEV__ && Systrace().endEvent();
     } catch (e) {
       mod.hasError = true;
       mod.isInitialized = false;
@@ -70,14 +70,14 @@
     return mod.module.exports;
   }
 
-  const BridgeProfiling = __DEV__ && (() => {
-    var _BridgeProfiling;
+  const Systrace = __DEV__ && (() => {
+    var _Systrace;
     try {
-      _BridgeProfiling = require('BridgeProfiling');
+      _Systrace = require('Systrace');
     } catch(e) {}
 
-    return _BridgeProfiling && _BridgeProfiling.profile ?
-      _BridgeProfiling : { profile: () => {}, profileEnd: () => {} };
+    return _Systrace && _Systrace.beginEvent ?
+      _Systrace : { beginEvent: () => {}, endEvent: () => {} };
   });
 
   global.__d = define;

From 73daa9595bdcf182493bb9fb72eb9e9e7b3109e1 Mon Sep 17 00:00:00 2001
From: Timm Preetz <timm@preetz.us>
Date: Fri, 11 Dec 2015 15:22:57 +0100
Subject: [PATCH 0324/1411] Fix typo in Testing.md

---
 docs/Testing.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/Testing.md b/docs/Testing.md
index 436de2c95dca..4c881b2d654a 100644
--- a/docs/Testing.md
+++ b/docs/Testing.md
@@ -64,4 +64,4 @@ You can run integration tests locally with cmd+U in the IntegrationTest and UIEx
 
 A common type of integration test is the snapshot test.  These tests render a component, and verify snapshots of the screen against reference images using `TestModule.verifySnapshot()`, using the [`FBSnapshotTestCase`](https://github.com/facebook/ios-snapshot-test-case) library behind the scenes.  Reference images are recorded by setting `recordMode = YES` on the `RCTTestRunner`, then running the tests.  Snapshots will differ slightly between 32 and 64 bit, and various OS versions, so it's recommended that you enforce tests are run with the correct configuration.  It's also highly recommended that all network data be mocked out, along with other potentially troublesome dependencies.  See [`SimpleSnapshotTest`](https://github.com/facebook/react-native/blob/master/IntegrationTests/SimpleSnapshotTest.js) for a basic example.
 
-If you make a change that affects a snapshot test in a PR, such as adding a new example case to one of the examples that is snapshotted, you'll need to re-record the snapshotshot reference image.  To do this, simply change to `_runner.recordMode = YES;` in [UIExplorer/UIExplorerSnapshotTests.m](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerSnapshotTests.m#L42), re-run the failing tests, then flip record back to `NO` and submit/update your PR and wait to see if the Travis build passes.
+If you make a change that affects a snapshot test in a PR, such as adding a new example case to one of the examples that is snapshotted, you'll need to re-record the snapshot reference image.  To do this, simply change to `_runner.recordMode = YES;` in [UIExplorer/UIExplorerSnapshotTests.m](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerSnapshotTests.m#L42), re-run the failing tests, then flip record back to `NO` and submit/update your PR and wait to see if the Travis build passes.

From a86171a48284c440226a79a26c6d6a4704d401e9 Mon Sep 17 00:00:00 2001
From: Martin Kralik <kralik@fb.com>
Date: Fri, 11 Dec 2015 06:54:56 -0800
Subject: [PATCH 0325/1411] exposed a way to trigger layout on the uimanager

Summary:
A component can be backed by native "node" that can change its internal state, which would result in a new UI after the next layout. Since js has no way of knowing that this has happened it wouldn't trigger a layout if nothing in js world has changed. Therefore we need a way how to trigger layout from native code.

This diff does it by adding methods `layoutIfNeeded` on the uimanager and `isBatchActive` on the bridge.
When `layoutIfNeeded` is called it checks whether a batch is in progress. If it is we do nothing, since at it's end layout happens. If a batch is not in progress we immidiately do layout.

I went with the easiest way how to implement this - `isBatchActive` is a public method on the bridge. It's not ideal, but consistent with other methods for modules.
public

Reviewed By: jspahrsummers, nicklockwood

Differential Revision: D2748896

fb-gh-sync-id: f3664c4af980d40a463b538e069b26c9ebad6300
---
 React/Base/RCTBatchedBridge.m |  5 +++++
 React/Base/RCTBridge.h        |  5 +++++
 React/Base/RCTBridge.m        |  5 +++++
 React/Modules/RCTUIManager.h  |  6 ++++++
 React/Modules/RCTUIManager.m  | 18 ++++++++++++++++++
 5 files changed, 39 insertions(+)

diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index a0190a0ae521..1999f32b026b 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -982,6 +982,11 @@ - (void)stopProfiling:(void (^)(NSData *))callback
   }];
 }
 
+- (BOOL)isBatchActive
+{
+  return _wasBatchActive;
+}
+
 @end
 
 @implementation RCTBatchedBridge(Deprecated)
diff --git a/React/Base/RCTBridge.h b/React/Base/RCTBridge.h
index 487773f5217a..f341b75aab7a 100644
--- a/React/Base/RCTBridge.h
+++ b/React/Base/RCTBridge.h
@@ -163,6 +163,11 @@ RCT_EXTERN BOOL RCTBridgeModuleClassIsRegistered(Class);
  */
 - (void)reload;
 
+/**
+ * Says whether bridge has started recieving calls from javascript.
+ */
+- (BOOL)isBatchActive;
+
 @end
 
 /**
diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m
index 70bd92688ef3..c0b89be0a22c 100644
--- a/React/Base/RCTBridge.m
+++ b/React/Base/RCTBridge.m
@@ -287,6 +287,11 @@ - (BOOL)isValid
   return self.batchedBridge.valid;
 }
 
+- (BOOL)isBatchActive
+{
+  return [_batchedBridge isBatchActive];
+}
+
 - (void)invalidate
 {
   RCTBatchedBridge *batchedBridge = self.batchedBridge;
diff --git a/React/Modules/RCTUIManager.h b/React/Modules/RCTUIManager.h
index dc0bcd9d985b..bdcf2e2c5350 100644
--- a/React/Modules/RCTUIManager.h
+++ b/React/Modules/RCTUIManager.h
@@ -88,6 +88,12 @@ RCT_EXTERN NSString *const RCTUIManagerRootViewKey;
  */
 @property (atomic, assign) BOOL unsafeFlushUIChangesBeforeBatchEnds;
 
+/**
+ * In some cases we might want to trigger layout from native side.
+ * React won't be aware of this, so we need to make sure it happens.
+ */
+- (void)setNeedsLayout;
+
 @end
 
 /**
diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m
index 4812a548ef8e..46c991e3c3c4 100644
--- a/React/Modules/RCTUIManager.m
+++ b/React/Modules/RCTUIManager.m
@@ -888,6 +888,15 @@ - (void)partialBatchDidFlush
 }
 
 - (void)batchDidComplete
+{
+  [self _layoutAndMount];
+}
+
+/**
+ * Sets up animations, computes layout, creates UI mounting blocks for computed layout,
+ * runs these blocks and all other already existing blocks.
+ */
+- (void)_layoutAndMount
 {
   // Gather blocks to be executed now that all view hierarchy manipulations have
   // been completed (note that these may still take place before layout has finished)
@@ -962,6 +971,15 @@ - (void)flushUIBlocks
   }
 }
 
+- (void)setNeedsLayout
+{
+  // If there is an active batch layout will happen when batch finished, so we will wait for that.
+  // Otherwise we immidiately trigger layout.
+  if (![_bridge isBatchActive]) {
+    [self _layoutAndMount];
+  }
+}
+
 RCT_EXPORT_METHOD(measure:(nonnull NSNumber *)reactTag
                   callback:(RCTResponseSenderBlock)callback)
 {

From 7003f8dbeb621242b217713451244a2eac43b74d Mon Sep 17 00:00:00 2001
From: Sharath Prabhal <sharathbose@gmail.com>
Date: Fri, 11 Dec 2015 10:09:31 -0500
Subject: [PATCH 0326/1411] Add 'Eat or Not' to showcase

---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 953d9406205d..ae6dc2e0959e 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -162,6 +162,12 @@ var apps = [
     link:  'https://itunes.apple.com/us/app/dropbot-phone-replacement/id1000855694?mt=8',
     author: 'Peach Labs',
   },
+  {
+    name: 'Eat or Not',
+    icon: 'http://a3.mzstatic.com/us/r30/Purple5/v4/51/be/34/51be3462-b015-ebf2-11c5-69165b37fadc/icon175x175.jpeg',
+    link: 'https://itunes.apple.com/us/app/eat-or-not/id1054565697?mt=8',
+    author: 'Sharath Prabhal',
+  },
   {
     name: 'Fan of it',
     icon: 'http://a4.mzstatic.com/us/r30/Purple3/v4/c9/3f/e8/c93fe8fb-9332-e744-f04a-0f4f78e42aa8/icon350x350.png',

From 1a9469865832121deeabb3dd0d84a6af58ce775f Mon Sep 17 00:00:00 2001
From: Mike Armstrong <mikea@fb.com>
Date: Fri, 11 Dec 2015 07:28:50 -0800
Subject: [PATCH 0327/1411] expose systemclock time to JS

Reviewed By: tadeuzagallo

Differential Revision: D2748749

fb-gh-sync-id: 4d1dbae61f69a07b7106cb57caff03cadfb85776
---
 .../src/main/jni/react/JSCExecutor.cpp        | 25 +++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index 6e1f493e8cdd..8b954f156835 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -9,6 +9,7 @@
 #include <folly/json.h>
 #include <folly/String.h>
 #include <jni/fbjni/Exceptions.h>
+#include <sys/time.h>
 #include "Value.h"
 #include "jni/OnLoad.h"
 
@@ -34,6 +35,9 @@ using fbsystrace::FbSystraceSection;
 #include <jsc_config_android.h>
 #endif
 
+static const int64_t NANOSECONDS_IN_SECOND = 1000000000LL;
+static const int64_t NANOSECONDS_IN_MILLISECOND = 1000000LL;
+
 using namespace facebook::jni;
 
 namespace facebook {
@@ -54,6 +58,13 @@ static JSValueRef nativeLoggingHook(
     size_t argumentCount,
     const JSValueRef arguments[],
     JSValueRef *exception);
+static JSValueRef nativePerformanceNow(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[],
+    JSValueRef *exception);
 
 static JSValueRef evaluateScriptWithJSC(
     JSGlobalContextRef ctx,
@@ -110,6 +121,7 @@ JSCExecutor::JSCExecutor(FlushImmediateCallback cb) :
   s_globalContextRefToJSCExecutor[m_context] = this;
   installGlobalFunction(m_context, "nativeFlushQueueImmediate", nativeFlushQueueImmediate);
   installGlobalFunction(m_context, "nativeLoggingHook", nativeLoggingHook);
+  installGlobalFunction(m_context, "nativePerformanceNow", nativePerformanceNow);
 
   #ifdef WITH_FB_JSC_TUNING
   configureJSCForAndroid();
@@ -283,4 +295,17 @@ static JSValueRef nativeLoggingHook(
   return JSValueMakeUndefined(ctx);
 }
 
+static JSValueRef nativePerformanceNow(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[], JSValueRef *exception) {
+  // This is equivalent to android.os.SystemClock.elapsedRealtime() in native
+  struct timespec now;
+  clock_gettime(CLOCK_MONOTONIC_RAW, &now);
+  int64_t nano = now.tv_sec * NANOSECONDS_IN_SECOND + now.tv_nsec;
+  return JSValueMakeNumber(ctx, (nano / (double)NANOSECONDS_IN_MILLISECOND));
+}
+
 } }

From eb3152a397f75cea7340b5ad60dd26433c4b4398 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Fri, 11 Dec 2015 15:44:13 +0000
Subject: [PATCH 0328/1411] Update Releases.md

---
 Releases.md | 32 ++++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/Releases.md b/Releases.md
index b014e5d36e86..8a63520b32d1 100644
--- a/Releases.md
+++ b/Releases.md
@@ -14,7 +14,7 @@ Future releases:
 
 ## Cut a release branch
 
-Note: replace 0.12 in all the commands below with the version you're releasing :)
+Note: replace 0.18 in all the commands below with the version you're releasing :)
 
 #### Check that everything works
 
@@ -23,28 +23,28 @@ First, set up Sinopia (only need to do this once): https://github.com/facebook/r
 Make absolutely sure basic iOS and Android workflow works on master:
   - `cd react-native`
   - `git pull`
-  - `git checkout -b 0.12-stable`
-  - Edit `ReactAndroid/gradle.properties`, set `VERSION_NAME=0.12.0`
+  - `git checkout -b 0.18-stable`
+  - Edit `ReactAndroid/gradle.properties`, set `VERSION_NAME=0.18.0`
   - Edit `ReactAndroid/release.gradle`, uncomment Javadoc generation (the line `// archives androidJavadocJar`)
   - Make sure `java -version` prints 1.7.x, this is currently needed for Javadoc generation and Javadocs are required by Maven Central (we should make it work with Java 8)
   - Run `./gradlew :ReactAndroid:installArchives`, it will print a lot of Javadoc warnings, that's OK.
-  - Check the artifacts were generated: `ls -al ~/.m2/repository/com/facebook/react/react-native/0.12.0/` should contain:
-    - `react-native-0.17.0-javadoc.jar`, `react-native-0.17.0-sources.jar`, `react-native-0.17.0.aar`, `react-native-0.17.0.pom`
+  - Check the artifacts were generated: `ls -al ~/.m2/repository/com/facebook/react/react-native/0.18.0/` should contain:
+    - `react-native-0.18.0-javadoc.jar`, `react-native-0.18.0-sources.jar`, `react-native-0.18.0.aar`, `react-native-0.18.0.pom`
     - For each of the above also `.asc` file
-- In `package.json`, set version to e.g. `0.12.0-rc`.
-- In `React.podspec`, set version to e.g. `0.12.0-rc`.
-- In `local-cli/generator-android/templates/src/app/build.gradle` update the dependency to e.g. `com.facebook.react:react-native:0.12.+`
+- In `package.json`, set version to e.g. `0.18.0-rc`.
+- In `React.podspec`, set version to e.g. `0.18.0-rc`.
+- In `local-cli/generator-android/templates/src/app/build.gradle` update the dependency to e.g. `com.facebook.react:react-native:0.18.+`
 - Publish to sinopia:
   - `npm set registry http://localhost:4873/`, check that it worked: `npm config list` will show registry is set to localhost
   - In a separate shell, start sinopia. Run `sinopia`. If started successfully it will print: http address - http://localhost:4873/.
   - Make sure http://localhost:4873/ shows no old versions
   - `npm publish`
-  - http://localhost:4873/ will show 0.12.0-rc
+  - http://localhost:4873/ will show 0.18.0-rc
 - Test that everything works:
   - `cd /tmp`
   - `react-native init Zero12rc`
   - `cd Zero12rc`
-  - Check that `package.json`, `android/app/build.gradle` have correct versions (`^0.12.0-rc`, `com.facebook.react:react-native:0.12.+`)
+  - Check that `package.json`, `android/app/build.gradle` have correct versions (`^0.18.0-rc`, `com.facebook.react:react-native:0.18.+`)
   - `open ios/Zero12rc.xcodeproj`
   - Hit the Run button in Xcode.
   - Packager should open in a new window, you should see the Welcome to React Native screen, Reload JS, try Chrome debugging - put a breakpoint somewhere in `index.ios.js` and Reload JS, Chrome debugger should stop on the breakpoint (we don't have tests for Chrome debugging)
@@ -56,8 +56,8 @@ Make absolutely sure basic iOS and Android workflow works on master:
 #### Push to github
 
   - Revert the Javadoc change in `ReactAndroid/release.gradle`
-  - `git commit -am` "[0.12-rc] Bump version numbers"
-  - `git push origin 0.12-stable`
+  - `git commit -am` "[0.18-rc] Bump version numbers"
+  - `git push origin 0.18-stable`
 
 ## Do a release
 
@@ -67,7 +67,7 @@ Publish to Maven Central (NOTE we could get rid of this whole section publishing
   - Add all files: .aar, sources jar, javadoc jar, .asc for everything (including the POM file)
   - Wait a few hours until you see the version has propagated to [JCenter](https://bintray.com/bintray/jcenter/com.facebook.react%3Areact-native/view)
 
-To release 0.12-rc to npm:
+To release 0.18-rc to npm:
 
 (You need to be a maintainer of the repo. For admins, here's the command to promote someone)
 
@@ -76,7 +76,7 @@ npm owner add <user> react-native
 ```
 
 ```
-git tag v0.12.0-rc 0.12-stable # don't forget the `v` at the beginning!
+git tag v0.18.0-rc 0.18-stable # don't forget the `v` at the beginning!
 git push --tags
 ```
 
@@ -84,8 +84,8 @@ git push --tags
 
 ```
 npm publish
-# Only for non-rc releases:
-npm dist-tag add react-native@0.12.0 latest
+# Only when doing a non-rc release:
+npm dist-tag add react-native@0.18.0 latest
 ```
 - Upgrade tags to a release by going to https://github.com/facebook/react-native/tags
 - Click "Add Notes to release"

From 9443a4e65f59b28620940aac43f236641a0a0df2 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Fri, 11 Dec 2015 16:14:31 +0000
Subject: [PATCH 0329/1411] Update Releases.md

---
 Releases.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Releases.md b/Releases.md
index 8a63520b32d1..d2c8c8812407 100644
--- a/Releases.md
+++ b/Releases.md
@@ -14,7 +14,7 @@ Future releases:
 
 ## Cut a release branch
 
-Note: replace 0.18 in all the commands below with the version you're releasing :)
+Note: Make sure you replace 0.18 in all the commands below with the version you're releasing :) For example, copy-paste all of this into an editor and replace 0.18.
 
 #### Check that everything works
 

From 339c114b96b6d04f790cf202dab77edb7694edf6 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Fri, 11 Dec 2015 16:15:14 +0000
Subject: [PATCH 0330/1411] Update Releases.md

---
 Releases.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Releases.md b/Releases.md
index d2c8c8812407..1ed509786e2e 100644
--- a/Releases.md
+++ b/Releases.md
@@ -61,7 +61,7 @@ Make absolutely sure basic iOS and Android workflow works on master:
 
 ## Do a release
 
-Publish to Maven Central (NOTE we could get rid of this whole section publishing binaries to npm instead):
+Publish to Maven Central (Note: We could get rid of this whole section publishing binaries to npm instead):
   - Log into Sonatype and go to [Staging upload](https://oss.sonatype.org/#staging-upload). You'll need to get permissions for this by filing a ticket explaining you're a core contributor to React Native. [Example ticket](https://issues.sonatype.org/browse/OSSRH-11885).
   - Select Artifact(s) with a POM (to publish to a local Maven repo for testing run `./gradlew :ReactAndroid:installArchives`)
   - Add all files: .aar, sources jar, javadoc jar, .asc for everything (including the POM file)

From 402fd067250d7628db256814bbfc5cabbe470a2d Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeux@fb.com>
Date: Wed, 9 Dec 2015 15:29:00 -0800
Subject: [PATCH 0331/1411] Introduce code-analysis bot

---
 .travis.yml               |   1 +
 bots/code-analysis-bot.js | 242 ++++++++++++++++++++++++++++++++++++++
 package.json              |   3 +-
 3 files changed, 245 insertions(+), 1 deletion(-)
 create mode 100644 bots/code-analysis-bot.js

diff --git a/.travis.yml b/.travis.yml
index ea84c8bc8ab5..d1baaddd5672 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -28,6 +28,7 @@ script:
   elif [ "$TEST_TYPE" = js ]
   then
 
+    cat <(echo eslint; npm run lint --silent -- --format=json; echo flow; flow --json) | GITHUB_TOKEN="af6ef0d15709bc91d""06a6217a5a826a226fb57b7" node bots/code-analysis-bot.js
     flow check && npm test -- '\/Libraries\/'
 
   elif [ "$TEST_TYPE" = packager ]
diff --git a/bots/code-analysis-bot.js b/bots/code-analysis-bot.js
new file mode 100644
index 000000000000..8fabcfb1e429
--- /dev/null
+++ b/bots/code-analysis-bot.js
@@ -0,0 +1,242 @@
+/**
+ * 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.
+ */
+'use strict';
+
+if (!process.env.TRAVIS_REPO_SLUG) {
+  console.error('Missing TRAVIS_REPO_SLUG. Example: facebook/react-native');
+  process.exit(1);
+}
+if (!process.env.GITHUB_TOKEN) {
+  console.error('Missing GITHUB_TOKEN. Example: 5fd88b964fa214c4be2b144dc5af5d486a2f8c1e');
+  process.exit(1);
+}
+if (!process.env.TRAVIS_PULL_REQUEST) {
+  console.error('Missing TRAVIS_PULL_REQUEST. Example: 4687');
+  process.exit(1);
+}
+
+var GitHubApi = require('github');
+var path = require('path');
+
+var github = new GitHubApi({
+  version: '3.0.0',
+});
+
+github.authenticate({
+  type: 'oauth',
+  token: process.env.GITHUB_TOKEN,
+});
+
+function push(arr, key, value) {
+  if (!arr[key]) {
+    arr[key] = [];
+  }
+  arr[key].push(value);
+}
+
+/**
+ * There is unfortunately no standard format to report an error, so we have
+ * to write a specific converter for each tool we want to support.
+ *
+ * Those functions take a json object as input and fill the output with the
+ * following format:
+ *
+ * { [ path: string ]: Array< { message: string, line: number }> }
+ *
+ * This is an object where the keys are the path of the files and values
+ * is an array of objects of the shape message and line.
+ */
+var converters = {
+  raw: function(output, input) {
+    for (var key in input) {
+      input[key].forEach(function(message) {
+        push(output, key, message);
+      });
+    }
+  },
+
+  flow: function(output, input) {
+    if (!input || !input.errors) {
+      return;
+    }
+
+    input.errors.forEach(function(error) {
+      push(output, error.message[0].path, {
+        message: error.message.map(message => message.descr).join(' '),
+        line: error.message[0].line,
+      });
+    });
+  },
+
+  eslint: function(output, input) {
+    if (!input) {
+      return;
+    }
+
+    input.forEach(function(file) {
+      file.messages.forEach(function(message) {
+        push(output, file.filePath, {
+          message: message.ruleId + ': ' + message.message,
+          line: message.line,
+        });
+      });
+    });
+  }
+};
+
+function getShaFromPullRequest(user, repo, number, callback) {
+  github.pullRequests.get({user, repo, number}, (error, res) => {
+    if (error) {
+      console.log(error);
+      return;
+    }
+    callback(res.head.sha);
+  });
+}
+
+function getFilesFromCommit(user, repo, sha, callback) {
+  github.repos.getCommit({user, repo, sha}, (error, res) => {
+    if (error) {
+      console.log(error);
+      return;
+    }
+    callback(res.files);
+  });
+}
+
+
+/**
+ * Sadly we can't just give the line number to github, we have to give the
+ * line number relative to the patch file which is super annoying. This
+ * little function builds a map of line number in the file to line number
+ * in the patch file
+ */
+function getLineMapFromPatch(patchString) {
+  var diffLineIndex = 0;
+  var fileLineIndex = 0;
+  var lineMap = {};
+
+  patchString.split('\n').forEach((line) => {
+    if (line.match(/^@@/)) {
+      fileLineIndex = line.match(/\+([0-9]+)/)[1] - 1;
+      return;
+    }
+
+    diffLineIndex++;
+    if (line[0] !== '-') {
+      fileLineIndex++;
+      if (line[0] === '+') {
+        lineMap[fileLineIndex] = diffLineIndex;
+      }
+    }
+  });
+
+  return lineMap;
+}
+
+function sendComment(user, repo, number, sha, filename, lineMap, message) {
+  if (!lineMap[message.line]) {
+    // Do not send messages on lines that did not change
+    return;
+  }
+
+  var opts = {
+    user,
+    repo,
+    number,
+    sha,
+    path: filename,
+    commit_id: sha,
+    body: message.message,
+    position: lineMap[message.line],
+  };
+  github.pullRequests.createComment(opts, function(error, res) {
+    if (error) {
+      console.log(error);
+      return;
+    }
+  });
+  console.log('Sending comment', opts);
+}
+
+function main(messages, user, repo, number) {
+  // No message, we don't need to do anything :)
+  if (Object.keys(messages).length === 0) {
+    return;
+  }
+
+  getShaFromPullRequest(user, repo, number, (sha) => {
+    getFilesFromCommit(user, repo, sha, (files) => {
+      files
+        .filter((file) => messages[file.filename])
+        .forEach((file) => {
+          var lineMap = getLineMapFromPatch(file.patch);
+          messages[file.filename].forEach((message) => {
+            sendComment(user, repo, number, sha, file.filename, lineMap, message);
+          });
+        });
+    });
+  });
+}
+
+var content = '';
+process.stdin.resume();
+process.stdin.on('data', function(buf) { content += buf.toString(); });
+process.stdin.on('end', function() {
+  var messages = {};
+
+  // Since we send a few http requests to setup the process, we don't want
+  // to run this file one time per code analysis tool. Instead, we write all
+  // the results in the same stdin stream.
+  // The format of this stream is
+  //
+  //   name-of-the-converter
+  //   {"json":"payload"}
+  //   name-of-the-other-converter
+  //   {"other": ["json", "payload"]}
+  //
+  // In order to generate such stream, here is a sample bash command:
+  //
+  //   cat <(echo eslint; npm run lint --silent -- --format=json; echo flow; flow --json) | node code-analysis-bot.js
+
+  var lines = content.trim().split('\n');
+  for (var i = 0; i < Math.ceil(lines.length / 2); ++i) {
+    var converter = converters[lines[i * 2]];
+    if (!converter) {
+      throw new Error('Unknown converter ' + lines[i * 2]);
+    }
+    var json;
+    try {
+      json = JSON.parse(lines[i * 2 + 1]);
+    } catch (e) {}
+
+    converter(messages, json);
+  }
+
+  // The paths are returned in absolute from code analysis tools but github works
+  // on paths relative from the root of the project. Doing the normalization here.
+  var pwd = path.resolve('.');
+  for (var absolutePath in messages) {
+    var relativePath = path.relative(pwd, absolutePath);
+    if (relativePath === absolutePath) {
+      continue;
+    }
+    messages[relativePath] = messages[absolutePath];
+    delete messages[absolutePath];
+  }
+
+  // TRAVIS_REPO_SLUG // 'facebook/react-native'
+  var user_repo = process.env.TRAVIS_REPO_SLUG.split('/');
+  var user = user_repo[0];
+  var repo = user_repo[1];
+  var number = process.env.TRAVIS_PULL_REQUEST;
+
+  // intentional lint warning to make sure that the bot is working :)
+  main(messages, user, repo, number)
+});
diff --git a/package.json b/package.json
index d2249d02e799..54af188aa0b0 100644
--- a/package.json
+++ b/package.json
@@ -46,7 +46,7 @@
   ],
   "scripts": {
     "test": "NODE_ENV=test jest",
-    "lint": "eslint Examples/ Libraries/",
+    "lint": "eslint Examples/ Libraries/ bots/code-analysis-bot.js",
     "start": "/usr/bin/env bash -c './packager/packager.sh \"$@\" || true' --"
   },
   "bin": {
@@ -122,6 +122,7 @@
     "yeoman-generator": "^0.20.3"
   },
   "devDependencies": {
+    "github": "^0.2.4",
     "jest-cli": "0.7.1",
     "babel-eslint": "4.1.4",
     "eslint": "1.3.1",

From f168fc335e8a120c8bb4c8e31398c6241e0c4f74 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Fri, 11 Dec 2015 10:22:37 -0800
Subject: [PATCH 0332/1411] Don't insta-crash when network permission is
 missing

Summary:
public

Rename the `ConnectivityModule` to `NetInfoModule` (there's
no need to name things differently in two places). Add exception
handling to the module in case the network permission is missing.

When the permission is missing, throw an actionable error from
all calls to `NetInfo`: http://imgur.com/zVIMxOV

Without this change, the app immediately crashes on startup:
`getCurrentConnectionType` is called from `Activity.onResume`.

Reviewed By: andreicoman11, bestander

Differential Revision: D2749230

fb-gh-sync-id: 1b752d21a8f28ffeaf60a3322cb76f869dc70a14
---
 ...ectivityModule.java => NetInfoModule.java} | 49 +++++++++++++++----
 .../react/shell/MainReactPackage.java         |  4 +-
 2 files changed, 42 insertions(+), 11 deletions(-)
 rename ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/{ConnectivityModule.java => NetInfoModule.java} (71%)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/ConnectivityModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java
similarity index 71%
rename from ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/ConnectivityModule.java
rename to ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java
index acf6060b1af5..bff80bf26b22 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/ConnectivityModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java
@@ -1,4 +1,11 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
+/**
+ * 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.
+ */
 
 package com.facebook.react.modules.netinfo;
 
@@ -10,6 +17,7 @@
 import android.net.NetworkInfo;
 import android.support.v4.net.ConnectivityManagerCompat;
 
+import com.facebook.common.logging.FLog;
 import com.facebook.react.bridge.Callback;
 import com.facebook.react.bridge.LifecycleEventListener;
 import com.facebook.react.bridge.ReactApplicationContext;
@@ -17,25 +25,30 @@
 import com.facebook.react.bridge.ReactMethod;
 import com.facebook.react.bridge.WritableMap;
 import com.facebook.react.bridge.WritableNativeMap;
+import com.facebook.react.common.ReactConstants;
 
 import static com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter;
 
 /**
  * Module that monitors and provides information about the connectivity state of the device.
  */
-public class ConnectivityModule extends ReactContextBaseJavaModule
+public class NetInfoModule extends ReactContextBaseJavaModule
     implements LifecycleEventListener {
 
   private static final String CONNECTION_TYPE_NONE = "NONE";
   private static final String CONNECTION_TYPE_UNKNOWN = "UNKNOWN";
+  private static final String MISSING_PERMISSION_MESSAGE =
+      "To use NetInfo on Android, add the following to your AndroidManifest.xml:\n" +
+      "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />";
 
   private final ConnectivityManager mConnectivityManager;
   private final ConnectivityManagerCompat mConnectivityManagerCompat;
   private final ConnectivityBroadcastReceiver mConnectivityBroadcastReceiver;
+  private boolean mNoNetworkPermission = false;
 
   private String mConnectivity = "";
 
-  public ConnectivityModule(ReactApplicationContext reactContext) {
+  public NetInfoModule(ReactApplicationContext reactContext) {
     super(reactContext);
     mConnectivityManager =
         (ConnectivityManager) reactContext.getSystemService(Context.CONNECTIVITY_SERVICE);
@@ -69,11 +82,23 @@ public String getName() {
 
   @ReactMethod
   public void getCurrentConnectivity(Callback successCallback, Callback errorCallback) {
+    if (mNoNetworkPermission) {
+      if (errorCallback == null) {
+        FLog.e(ReactConstants.TAG, MISSING_PERMISSION_MESSAGE);
+        return;
+      }
+      errorCallback.invoke(MISSING_PERMISSION_MESSAGE);
+      return;
+    }
     successCallback.invoke(createConnectivityEventMap());
   }
 
   @ReactMethod
   public void isConnectionMetered(Callback successCallback) {
+    if (mNoNetworkPermission) {
+      FLog.e(ReactConstants.TAG, MISSING_PERMISSION_MESSAGE);
+      return;
+    }
     successCallback.invoke(mConnectivityManagerCompat.isActiveNetworkMetered(mConnectivityManager));
   }
 
@@ -98,15 +123,21 @@ private void updateAndSendConnectionType() {
   }
 
   private String getCurrentConnectionType() {
-    NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo();
-    if (networkInfo == null || !networkInfo.isConnected()) {
-      return CONNECTION_TYPE_NONE;
-    } else if (ConnectivityManager.isNetworkTypeValid(networkInfo.getType())) {
-      return networkInfo.getTypeName().toUpperCase();
-    } else {
+    try {
+      NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo();
+      if (networkInfo == null || !networkInfo.isConnected()) {
+        return CONNECTION_TYPE_NONE;
+      } else if (ConnectivityManager.isNetworkTypeValid(networkInfo.getType())) {
+        return networkInfo.getTypeName().toUpperCase();
+      } else {
+        return CONNECTION_TYPE_UNKNOWN;
+      }
+    } catch (SecurityException e) {
+      mNoNetworkPermission = true;
       return CONNECTION_TYPE_UNKNOWN;
     }
   }
+
   private void sendConnectivityChangedEvent() {
     getReactApplicationContext().getJSModule(RCTDeviceEventEmitter.class)
         .emit("networkStatusDidChange", createConnectivityEventMap());
diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
index 973cfbd84c7d..d6d8e37fbb16 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
@@ -20,7 +20,7 @@
 import com.facebook.react.modules.fresco.FrescoModule;
 import com.facebook.react.modules.intent.IntentModule;
 import com.facebook.react.modules.location.LocationModule;
-import com.facebook.react.modules.netinfo.ConnectivityModule;
+import com.facebook.react.modules.netinfo.NetInfoModule;
 import com.facebook.react.modules.network.NetworkingModule;
 import com.facebook.react.modules.storage.AsyncStorageModule;
 import com.facebook.react.modules.toast.ToastModule;
@@ -57,7 +57,7 @@ public List<NativeModule> createNativeModules(ReactApplicationContext reactConte
       new IntentModule(reactContext),
       new LocationModule(reactContext),
       new NetworkingModule(reactContext),
-      new ConnectivityModule(reactContext),
+      new NetInfoModule(reactContext),
       new WebSocketModule(reactContext),
       new ToastModule(reactContext));
   }

From 836ba8fb38e8da0583ff531818222ddc46503364 Mon Sep 17 00:00:00 2001
From: Jan Kassens <jkassens@fb.com>
Date: Fri, 11 Dec 2015 11:38:19 -0800
Subject: [PATCH 0333/1411] BridgeProfiler: add sync Relay methods

Reviewed By: sahrens

Differential Revision: D2721549

fb-gh-sync-id: af6a83f8505a83e323af3992d9552654ea644324
---
 Libraries/Utilities/Systrace.js | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/Libraries/Utilities/Systrace.js b/Libraries/Utilities/Systrace.js
index 826be67a1748..ffd58715d4be 100644
--- a/Libraries/Utilities/Systrace.js
+++ b/Libraries/Utilities/Systrace.js
@@ -15,7 +15,12 @@ type RelayProfiler = {
   attachProfileHandler(
     name: string,
     handler: (name: string, state?: any) => () => void
-  ): void
+  ): void,
+
+  attachAggregateHandler(
+    name: string,
+    handler: (name: string, callback: () => void) => void
+  ): void,
 };
 
 var GLOBAL = GLOBAL || this;
@@ -116,6 +121,12 @@ var Systrace = {
         Systrace.endAsyncEvent(name, cookie);
       };
     });
+
+    relayProfiler.attachAggregateHandler('*', (name, callback) => {
+      Systrace.beginEvent(name);
+      callback();
+      Systrace.endEvent();
+    });
   },
 
   /* This is not called by default due to perf overhead but it's useful

From 2696f9440e456232cfedae65113d21991521c7d8 Mon Sep 17 00:00:00 2001
From: Sebastian Markbage <sema@fb.com>
Date: Fri, 11 Dec 2015 16:35:36 -0800
Subject: [PATCH 0334/1411] enqueueJSCall instead of global dynamic require

Summary:
BridgeProfiling.setEnabled used a one off eval. Let's use the bridge to do this like everything else. This is already what the Android equivalent is doing.

public

Reviewed By: tadeuzagallo

Differential Revision: D2745059

fb-gh-sync-id: 5b633365b8cfc8abc6b80255e82ef3053ead9b50
---
 React/Executors/RCTContextExecutor.m | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/React/Executors/RCTContextExecutor.m b/React/Executors/RCTContextExecutor.m
index 55b0d506c35c..2205a8d4846d 100644
--- a/React/Executors/RCTContextExecutor.m
+++ b/React/Executors/RCTContextExecutor.m
@@ -417,11 +417,7 @@ - (void)toggleProfilingFlag:(NSNotification *)notification
 {
   [self executeBlockOnJavaScriptQueue:^{
     BOOL enabled = [notification.name isEqualToString:RCTProfileDidStartProfiling];
-    // TODO: Don't use require, go through the normal execution modes instead. #9317773
-    NSString *script = [NSString stringWithFormat:@"var p = require('Systrace') || {}; p.setEnabled && p.setEnabled(%@)", enabled ? @"true" : @"false"];
-    JSStringRef scriptJSRef = JSStringCreateWithUTF8CString(script.UTF8String);
-    JSEvaluateScript(_context.ctx, scriptJSRef, NULL, NULL, 0, NULL);
-    JSStringRelease(scriptJSRef);
+    [_bridge enqueueJSCall:@"Systrace.setEnabled" args:@[enabled ? @YES : @NO]];
   }];
 }
 

From bd3cb3ae1d1955dc45a5b98df03b885197dec6ae Mon Sep 17 00:00:00 2001
From: Mark Oswald <markoswald123@googlemail.com>
Date: Fri, 11 Dec 2015 20:30:57 -0800
Subject: [PATCH 0335/1411] add quotes to handle pathnames with spaces in it

Summary:
fixes #3135
Closes https://github.com/facebook/react-native/pull/4369

Reviewed By: svcscm

Differential Revision: D2752708

Pulled By: androidtrunkagent

fb-gh-sync-id: ada11eecb6bd5b8519e30636d18aa6b8962198aa
---
 React/React.xcodeproj/project.pbxproj | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj
index 3bc1cb5cf899..c7f7294cc16c 100644
--- a/React/React.xcodeproj/project.pbxproj
+++ b/React/React.xcodeproj/project.pbxproj
@@ -608,7 +608,7 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "if nc -w 5 -z localhost 8081 ; then\n  if ! curl -s \"http://localhost:8081/status\" | grep -q \"packager-status:running\" ; then\n    echo \"Port 8081 already in use, packager is either not running or not running correctly\"\n    exit 2\n  fi\nelse\n  open $SRCROOT/../packager/launchPackager.command || echo \"Can't start packager automatically\"\nfi";
+			shellScript = "if nc -w 5 -z localhost 8081 ; then\n  if ! curl -s \"http://localhost:8081/status\" | grep -q \"packager-status:running\" ; then\n    echo \"Port 8081 already in use, packager is either not running or not running correctly\"\n    exit 2\n  fi\nelse\n  open \"$SRCROOT/../packager/launchPackager.command\" || echo \"Can't start packager automatically\"\nfi";
 		};
 		142C4F7F1B582EA6001F0B58 /* ShellScript */ = {
 			isa = PBXShellScriptBuildPhase;

From e4fe55708972c0b09674e99b4841830339620196 Mon Sep 17 00:00:00 2001
From: Christopher Dro <hello@blick-labs.com>
Date: Fri, 11 Dec 2015 21:21:02 -0800
Subject: [PATCH 0336/1411] Fix all warnings for missing keys.

Summary:
I had to go through each component while debugging for another issue and decided to clean these warnings up along the way.
Closes https://github.com/facebook/react-native/pull/4653

Reviewed By: svcscm

Differential Revision: D2752740

Pulled By: androidtrunkagent

fb-gh-sync-id: 94da8ad693cae04e353f33f540c15214f6f3e7d8
---
 Examples/UIExplorer/AnimatedExample.js            |  1 +
 Examples/UIExplorer/AsyncStorageExample.js        |  2 +-
 Examples/UIExplorer/CameraRollExample.ios.js      |  4 ++--
 .../PullToRefreshViewAndroidExample.android.js    |  4 ++--
 Examples/UIExplorer/StatusBarIOSExample.js        |  6 +++---
 Examples/UIExplorer/TextInputExample.ios.js       |  2 +-
 Examples/UIExplorer/TimerExample.js               | 15 +++++++++++++--
 7 files changed, 23 insertions(+), 11 deletions(-)

diff --git a/Examples/UIExplorer/AnimatedExample.js b/Examples/UIExplorer/AnimatedExample.js
index e417cacbefcc..5f6096338115 100644
--- a/Examples/UIExplorer/AnimatedExample.js
+++ b/Examples/UIExplorer/AnimatedExample.js
@@ -195,6 +195,7 @@ exports.examples = [
           {['Composite', 'Easing', 'Animations!'].map(
             (text, ii) => (
               <Animated.View
+                key={text}
                 style={[styles.content, {
                   left: this.anims[ii]
                 }]}>
diff --git a/Examples/UIExplorer/AsyncStorageExample.js b/Examples/UIExplorer/AsyncStorageExample.js
index a091c0caaede..a3ca76437474 100644
--- a/Examples/UIExplorer/AsyncStorageExample.js
+++ b/Examples/UIExplorer/AsyncStorageExample.js
@@ -80,7 +80,7 @@ var BasicStorageExample = React.createClass({
         </Text>
         <Text>{' '}</Text>
         <Text>Messages:</Text>
-        {this.state.messages.map((m) => <Text>{m}</Text>)}
+        {this.state.messages.map((m) => <Text key={m}>{m}</Text>)}
       </View>
     );
   },
diff --git a/Examples/UIExplorer/CameraRollExample.ios.js b/Examples/UIExplorer/CameraRollExample.ios.js
index d783d9d8e243..d1f3e96c909a 100644
--- a/Examples/UIExplorer/CameraRollExample.ios.js
+++ b/Examples/UIExplorer/CameraRollExample.ios.js
@@ -79,8 +79,8 @@ var CameraRollExample = React.createClass({
     var location = asset.node.location.longitude ?
       JSON.stringify(asset.node.location) : 'Unknown location';
     return (
-      <TouchableOpacity onPress={ this.loadAsset.bind( this, asset ) }>
-        <View key={asset} style={styles.row}>
+      <TouchableOpacity key={asset} onPress={ this.loadAsset.bind( this, asset ) }>
+        <View style={styles.row}>
           <Image
             source={asset.node.image}
             style={imageStyle}
diff --git a/Examples/UIExplorer/PullToRefreshViewAndroidExample.android.js b/Examples/UIExplorer/PullToRefreshViewAndroidExample.android.js
index c309c90288b9..307fe2cde5e6 100644
--- a/Examples/UIExplorer/PullToRefreshViewAndroidExample.android.js
+++ b/Examples/UIExplorer/PullToRefreshViewAndroidExample.android.js
@@ -84,8 +84,8 @@ const PullToRefreshViewAndroidExample = React.createClass({
   },
 
   render() {
-    const rows = this.state.rowData.map((row) => {
-      return <Row data={row} onClick={this._onClick}/>;
+    const rows = this.state.rowData.map((row, ii) => {
+      return <Row key={ii} data={row} onClick={this._onClick}/>;
     });
     return (
       <PullToRefreshViewAndroid
diff --git a/Examples/UIExplorer/StatusBarIOSExample.js b/Examples/UIExplorer/StatusBarIOSExample.js
index 28d5e2a7c076..a7765d8563ac 100644
--- a/Examples/UIExplorer/StatusBarIOSExample.js
+++ b/Examples/UIExplorer/StatusBarIOSExample.js
@@ -33,7 +33,7 @@ exports.examples = [{
     return (
       <View>
         {['default', 'light-content'].map((style) =>
-          <TouchableHighlight style={styles.wrapper}
+          <TouchableHighlight key={style} style={styles.wrapper}
             onPress={() => StatusBarIOS.setStyle(style)}>
             <View style={styles.button}>
               <Text>setStyle('{style}')</Text>
@@ -49,7 +49,7 @@ exports.examples = [{
     return (
       <View>
         {['default', 'light-content'].map((style) =>
-          <TouchableHighlight style={styles.wrapper}
+          <TouchableHighlight key={style} style={styles.wrapper}
             onPress={() => StatusBarIOS.setStyle(style, true)}>
             <View style={styles.button}>
               <Text>setStyle('{style}', true)</Text>
@@ -65,7 +65,7 @@ exports.examples = [{
     return (
       <View>
         {['none', 'fade', 'slide'].map((animation) =>
-          <View>
+          <View key={animation}>
             <TouchableHighlight style={styles.wrapper}
               onPress={() => StatusBarIOS.setHidden(true, animation)}>
               <View style={styles.button}>
diff --git a/Examples/UIExplorer/TextInputExample.ios.js b/Examples/UIExplorer/TextInputExample.ios.js
index 9efde2ea0aeb..2479e1d61aa3 100644
--- a/Examples/UIExplorer/TextInputExample.ios.js
+++ b/Examples/UIExplorer/TextInputExample.ios.js
@@ -158,7 +158,7 @@ class TokenizedTextExample extends React.Component {
     //highlight hashtags
     parts = parts.map((text) => {
       if (/^#/.test(text)) {
-        return <Text style={styles.hashtag}>{text}</Text>;
+        return <Text key={text} style={styles.hashtag}>{text}</Text>;
       } else {
         return text;
       }
diff --git a/Examples/UIExplorer/TimerExample.js b/Examples/UIExplorer/TimerExample.js
index 55272a8220af..51a8f1af557c 100644
--- a/Examples/UIExplorer/TimerExample.js
+++ b/Examples/UIExplorer/TimerExample.js
@@ -171,9 +171,20 @@ exports.examples = [
           }
           return (
             <View>
-              {timer}
+              {this.state.showTimer && this._renderTimer()}
               <UIExplorerButton onPress={this._toggleTimer}>
-                {toggleText}
+                {this.state.showTimer ? 'Unmount timer' : 'Mount new timer'}
+              </UIExplorerButton>
+            </View>
+          );
+        },
+
+        _renderTimer: function() {
+          return (
+            <View>
+              <TimerTester ref="interval" dt={25} type="setInterval" />
+              <UIExplorerButton onPress={() => this.refs.interval.clear() }>
+                Clear interval
               </UIExplorerButton>
             </View>
           );

From e0c724a4c36de8120986dd9491dfdcc34f6b92ce Mon Sep 17 00:00:00 2001
From: Huang Yu <huang@bitgo.com>
Date: Fri, 11 Dec 2015 23:00:48 -0800
Subject: [PATCH 0337/1411] fix lint warnings from DrawerLayoutAndroid

Summary:
fix 3 lint warnings from DrawerLayoutAndroid.android.js
Closes https://github.com/facebook/react-native/pull/4451

Reviewed By: svcscm

Differential Revision: D2715067

Pulled By: mkonicek

fb-gh-sync-id: 9cd0158087c8533950cdab85fdbfb137fcca20e4
---
 .../Components/DrawerAndroid/DrawerLayoutAndroid.android.js     | 2 --
 1 file changed, 2 deletions(-)

diff --git a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js
index 4b209bd41792..5a48ee9aba79 100644
--- a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js
+++ b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js
@@ -13,7 +13,6 @@
 var NativeMethodsMixin = require('NativeMethodsMixin');
 var React = require('React');
 var ReactPropTypes = require('ReactPropTypes');
-var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
 var StyleSheet = require('StyleSheet');
 var UIManager = require('UIManager');
 var View = require('View');
@@ -21,7 +20,6 @@ var View = require('View');
 var DrawerConsts = UIManager.AndroidDrawerLayout.Constants;
 
 var dismissKeyboard = require('dismissKeyboard');
-var merge = require('merge');
 var requireNativeComponent = require('requireNativeComponent');
 
 var RK_DRAWER_REF = 'drawerlayout';

From 0ad6f5ebf14c92d99ebdf896fcf22c29a49879c2 Mon Sep 17 00:00:00 2001
From: Alex Ledak <alex@ledak.ru>
Date: Sat, 12 Dec 2015 17:10:43 +0700
Subject: [PATCH 0338/1411] Add 'Thai Tone' to showcase

---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index ae6dc2e0959e..1e595b17f205 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -374,6 +374,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/tabtor-math/id1018651199?utm_source=ParentAppLP',
     author: 'PrazAs Learning Inc.',
   },
+  {
+    name: 'Thai Tone',
+    icon: 'http://a5.mzstatic.com/us/r30/Purple2/v4/b1/e6/2b/b1e62b3d-6747-0d0b-2a21-b6ba316a7890/icon175x175.png',
+    link: 'https://itunes.apple.com/us/app/thai-tone/id1064086189?mt=8',
+    author: 'Alexey Ledak',
+  },
   {
     name: 'Tong Xing Wang',
     icon: 'http://a3.mzstatic.com/us/r30/Purple1/v4/7d/52/a7/7d52a71f-9532-82a5-b92f-87076624fdb2/icon175x175.jpeg',

From e6c8848c07c907dd908fefcd0e7b58cc83047d93 Mon Sep 17 00:00:00 2001
From: zjlovezj <zjlovezj@gmail.com>
Date: Sat, 12 Dec 2015 19:21:31 +0800
Subject: [PATCH 0339/1411] fix sample code error by removing the extra chars

fix sample code error by removing the extra ',' and ')'
---
 docs/NativeModulesIOS.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/NativeModulesIOS.md b/docs/NativeModulesIOS.md
index b50b82a27ae1..ce1bf2e8660e 100644
--- a/docs/NativeModulesIOS.md
+++ b/docs/NativeModulesIOS.md
@@ -181,8 +181,8 @@ Refactoring the above code to use a promise instead of callbacks looks like this
 
 ```objective-c
 RCT_REMAP_METHOD(findEvents,
-                 resolver:(RCTPromiseResolveBlock)resolve,
-                 rejecter:(RCTPromiseRejectBlock)reject))
+                 resolver:(RCTPromiseResolveBlock)resolve
+                 rejecter:(RCTPromiseRejectBlock)reject)
 {
   NSArray *events = ...
   if (events) {

From 70b695922e784ce7d11930f8645300fcc664324d Mon Sep 17 00:00:00 2001
From: Arve Knudsen <arve.knudsen@gmail.com>
Date: Sat, 12 Dec 2015 13:10:36 +0100
Subject: [PATCH 0340/1411] Fix typo

---
 react-native-cli/index.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/react-native-cli/index.js b/react-native-cli/index.js
index ccddab423631..91e87000d1b2 100755
--- a/react-native-cli/index.js
+++ b/react-native-cli/index.js
@@ -138,7 +138,7 @@ function createAfterConfirmation(name, verbose) {
 
   var property = {
     name: 'yesno',
-    message: 'Directory ' + name + ' already exist. Continue?',
+    message: 'Directory ' + name + ' already exists. Continue?',
     validator: /y[es]*|n[o]?/,
     warning: 'Must respond yes or no',
     default: 'no'

From c60b581327e5f3c8aebb1ebd5ecb5550ba2ffa76 Mon Sep 17 00:00:00 2001
From: Qiao Liang <qiaoliang89@gmail.com>
Date: Sat, 12 Dec 2015 09:09:09 -0800
Subject: [PATCH 0341/1411] fix POST/PUT/PATCH has no body redbox, when xhr is
 used without body
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Summary:
… by passing a empty body
fix #3371
referring to https://github.com/square/okhttp/pull/1559/files
Closes https://github.com/facebook/react-native/pull/4518

Reviewed By: svcscm

Differential Revision: D2753086

Pulled By: lexs

fb-gh-sync-id: 5c486b127b194b29cd0f8a2cb9a1ef19449109e3
---
 .../react/modules/network/NetworkingModule.java      |  2 +-
 .../react/modules/network/RequestBodyUtil.java       | 12 ++++++++++++
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
index 1156aa2fd195..728acf7fe99f 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
@@ -136,7 +136,7 @@ public void sendRequest(
     requestBuilder.headers(requestHeaders);
 
     if (data == null) {
-      requestBuilder.method(method, null);
+      requestBuilder.method(method, RequestBodyUtil.getEmptyBody(method));
     } else if (data.hasKey(REQUEST_BODY_KEY_STRING)) {
       if (contentType == null) {
         onRequestError(requestId, "Payload is set but no content-type header specified");
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/RequestBodyUtil.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/RequestBodyUtil.java
index 7ce69c37e2d9..f834120acaf1 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/RequestBodyUtil.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/RequestBodyUtil.java
@@ -27,6 +27,7 @@
 import com.squareup.okhttp.RequestBody;
 import com.squareup.okhttp.internal.Util;
 import okio.BufferedSink;
+import okio.ByteString;
 import okio.Okio;
 import okio.Source;
 
@@ -112,4 +113,15 @@ public void writeTo(BufferedSink sink) throws IOException {
       }
     };
   }
+
+  /**
+   * Creates a empty RequestBody if required by the http method spec, otherwise use null
+   */
+  public static RequestBody getEmptyBody(String method) {
+    if (method.equals("POST") || method.equals("PUT") || method.equals("PATCH")) {
+      return RequestBody.create(null, ByteString.EMPTY);
+    } else {
+      return null;
+    }
+  }
 }

From d2907238456efeb3874c3b48e58d2cff4818c87e Mon Sep 17 00:00:00 2001
From: Billy Lamberta <b@lamberta.org>
Date: Sat, 12 Dec 2015 13:06:14 -0800
Subject: [PATCH 0342/1411] Add the npm global prefix to PATH.

Summary:
Related to issue https://github.com/facebook/react-native/issues/4034#issuecomment-164134543.
The npm global install path may be set to a non-standard location. `react-native` is assumed to be in `PATH` but doesn't take into account the user's environment so building in Xcode fails:
~~~
react-native bundle --entry-file index.ios.js --platform ios --dev true --bundle-output [...]

../node_modules/react-native/packager/react-native-xcode.sh: line 48: react-native: command not found
Command /bin/sh failed with exit code 127
~~~
This fix uses `npm prefix -g` to get the bin location and adds it to `PATH`.
Closes https://github.com/facebook/react-native/pull/4749

Reviewed By: svcscm

Differential Revision: D2753215

Pulled By: androidtrunkagent

fb-gh-sync-id: 964d1a71ac1bf204545a594a9fa433a7bc367f35
---
 packager/react-native-xcode.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/packager/react-native-xcode.sh b/packager/react-native-xcode.sh
index 5c88fdad1c0e..b0206be779f3 100755
--- a/packager/react-native-xcode.sh
+++ b/packager/react-native-xcode.sh
@@ -29,6 +29,9 @@ cd ..
 set -x
 DEST=$CONFIGURATION_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH
 
+# npm global install path may be a non-standard location
+PATH="$(npm prefix -g)/bin:$PATH"
+
 # Define NVM_DIR and source the nvm.sh setup script
 [ -z "$NVM_DIR" ] && export NVM_DIR="$HOME/.nvm"
 

From 8de172e92d393d5fcba43b806a69cdb0288b8862 Mon Sep 17 00:00:00 2001
From: Alexander Blom <blom@fb.com>
Date: Sat, 12 Dec 2015 14:19:16 -0800
Subject: [PATCH 0343/1411] Refactor so that mBridge can not be null and can be
 final

Reviewed By: astreet

Differential Revision: D2717983

fb-gh-sync-id: 969499eb062d54e0271f910c06c4539e2cb20030
---
 .../react/bridge/CatalystInstanceImpl.java    | 66 +++++++-----------
 .../bridge/queue/MessageQueueThread.java      | 10 +++
 .../bridge/queue/MessageQueueThreadImpl.java  | 35 +++++++++-
 .../common/futures/SimpleSettableFuture.java  | 67 ++++++++++++++-----
 4 files changed, 122 insertions(+), 56 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
index 87ae11a2bb27..dd7f89dc7e3c 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
@@ -14,6 +14,7 @@
 import java.io.IOException;
 import java.io.StringWriter;
 import java.util.Collection;
+import java.util.concurrent.Callable;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -63,7 +64,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
   private boolean mInitialized = false;
 
   // Access from JS thread
-  private @Nullable ReactBridge mBridge;
+  private final ReactBridge mBridge;
   private boolean mJSBundleHasLoaded;
 
   private CatalystInstanceImpl(
@@ -83,39 +84,34 @@ private CatalystInstanceImpl(
     mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
     mTraceListener = new JSProfilerTraceListener();
 
-    final CountDownLatch initLatch = new CountDownLatch(1);
-    mCatalystQueueConfiguration.getJSQueueThread().runOnQueue(
-        new Runnable() {
-          @Override
-          public void run() {
-            Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "initializeBridge");
-            try {
-              initializeBridge(jsExecutor, jsModulesConfig);
-              initLatch.countDown();
-            } finally {
-              Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
-            }
-          }
-        });
-
     try {
-      Assertions.assertCondition(
-          initLatch.await(BRIDGE_SETUP_TIMEOUT_MS, TimeUnit.MILLISECONDS),
-          "Timed out waiting for bridge to initialize!");
-    } catch (InterruptedException e) {
-      throw new RuntimeException(e);
+      mBridge = mCatalystQueueConfiguration.getJSQueueThread().callOnQueue(
+          new Callable<ReactBridge>() {
+            @Override
+            public ReactBridge call() throws Exception {
+              Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "initializeBridge");
+              try {
+                return initializeBridge(jsExecutor, jsModulesConfig);
+              } finally {
+                Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+              }
+            }
+          }).get(BRIDGE_SETUP_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+    } catch (Exception t) {
+      throw new RuntimeException("Failed to initialize bridge", t);
     }
   }
 
-  private void initializeBridge(
+  private ReactBridge initializeBridge(
       JavaScriptExecutor jsExecutor,
       JavaScriptModulesConfig jsModulesConfig) {
     mCatalystQueueConfiguration.getJSQueueThread().assertIsOnThread();
     Assertions.assertCondition(mBridge == null, "initializeBridge should be called once");
 
     Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ReactBridgeCtor");
+    ReactBridge bridge;
     try {
-      mBridge = new ReactBridge(
+      bridge = new ReactBridge(
           jsExecutor,
           new NativeModulesReactCallback(),
           mCatalystQueueConfiguration.getNativeModulesQueueThread());
@@ -125,15 +121,17 @@ private void initializeBridge(
 
     Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "setBatchedBridgeConfig");
     try {
-      mBridge.setGlobalVariable(
+      bridge.setGlobalVariable(
           "__fbBatchedBridgeConfig",
           buildModulesConfigJSONProperty(mJavaRegistry, jsModulesConfig));
-      mBridge.setGlobalVariable(
+      bridge.setGlobalVariable(
           "__RCTProfileIsProfiling",
           Systrace.isTracing(Systrace.TRACE_TAG_REACT_APPS) ? "true" : "false");
     } finally {
       Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
     }
+
+    return bridge;
   }
 
   @Override
@@ -260,13 +258,11 @@ public void destroy() {
       }
     }
 
-    if (mBridge != null) {
-      Systrace.unregisterListener(mTraceListener);
-    }
+    Systrace.unregisterListener(mTraceListener);
 
     // We can access the Bridge from any thread now because we know either we are on the JS thread
     // or the JS thread has finished via CatalystQueueConfiguration#destroy()
-    Assertions.assertNotNull(mBridge).dispose();
+    mBridge.dispose();
   }
 
   @Override
@@ -294,8 +290,7 @@ public CatalystQueueConfiguration getCatalystQueueConfiguration() {
   }
 
   @VisibleForTesting
-  public @Nullable
-  ReactBridge getBridge() {
+  public ReactBridge getBridge() {
     return mBridge;
   }
 
@@ -341,25 +336,16 @@ public void removeBridgeIdleDebugListener(NotThreadSafeBridgeIdleDebugListener l
 
   @Override
   public boolean supportsProfiling() {
-    if (mBridge == null) {
-      return false;
-    }
     return mBridge.supportsProfiling();
   }
 
   @Override
   public void startProfiler(String title) {
-    if (mBridge == null) {
-      return;
-    }
     mBridge.startProfiler(title);
   }
 
   @Override
   public void stopProfiler(String title, String filename) {
-    if (mBridge == null) {
-      return;
-    }
     mBridge.stopProfiler(title, filename);
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThread.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThread.java
index b04285a6f601..36b190a002f7 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThread.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThread.java
@@ -9,6 +9,9 @@
 
 package com.facebook.react.bridge.queue;
 
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+
 import com.facebook.proguard.annotations.DoNotStrip;
 
 /**
@@ -23,6 +26,13 @@ public interface MessageQueueThread {
   @DoNotStrip
   void runOnQueue(Runnable runnable);
 
+  /**
+   * Runs the given Callable on this Thread. It will be submitted to the end of the event queue even
+   * if it is being submitted from the same queue Thread.
+   */
+  @DoNotStrip
+  <T> Future<T> callOnQueue(final Callable<T> callable);
+
   /**
    * @return whether the current Thread is also the Thread associated with this MessageQueueThread.
    */
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java
index 5453e5355638..453351632bc1 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java
@@ -9,6 +9,10 @@
 
 package com.facebook.react.bridge.queue;
 
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
 import android.os.Looper;
 
 import com.facebook.common.logging.FLog;
@@ -45,6 +49,7 @@ private MessageQueueThreadImpl(
    * if it is being submitted from the same queue Thread.
    */
   @DoNotStrip
+  @Override
   public void runOnQueue(Runnable runnable) {
     if (mIsFinished) {
       FLog.w(
@@ -55,9 +60,29 @@ public void runOnQueue(Runnable runnable) {
     mHandler.post(runnable);
   }
 
+
+  @DoNotStrip
+  @Override
+  public <T> Future<T> callOnQueue(final Callable<T> callable) {
+    final SimpleSettableFuture<T> future = new SimpleSettableFuture<>();
+    runOnQueue(
+        new Runnable() {
+          @Override
+          public void run() {
+            try {
+              future.set(callable.call());
+            } catch (Exception e) {
+              future.setException(e);
+            }
+          }
+        });
+    return future;
+  }
+
   /**
    * @return whether the current Thread is also the Thread associated with this MessageQueueThread.
    */
+  @Override
   public boolean isOnThread() {
     return mLooper.getThread() == Thread.currentThread();
   }
@@ -66,6 +91,7 @@ public boolean isOnThread() {
    * Asserts {@link #isOnThread()}, throwing a {@link AssertionException} (NOT an
    * {@link AssertionError}) if the assertion fails.
    */
+  @Override
   public void assertIsOnThread() {
     SoftAssertions.assertCondition(isOnThread(), mAssertionErrorMessage);
   }
@@ -139,6 +165,13 @@ public void run() {
         }, "mqt_" + name);
     bgThread.start();
 
-    return new MessageQueueThreadImpl(name, simpleSettableFuture.get(5000), exceptionHandler);
+    try {
+      return new MessageQueueThreadImpl(
+          name,
+          simpleSettableFuture.get(5000, TimeUnit.MILLISECONDS),
+          exceptionHandler);
+    } catch (Throwable t) {
+      throw new RuntimeException(t);
+    }
   }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java b/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java
index a94a65cbc6e4..23619eccf947 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java
@@ -12,29 +12,61 @@
 import javax.annotation.Nullable;
 
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 /**
  * A super simple Future-like class that can safely notify another Thread when a value is ready.
- * Does not support setting errors or canceling.
+ * Does not support canceling.
  */
-public class SimpleSettableFuture<T> {
-
+public class SimpleSettableFuture<T> implements Future<T> {
   private final CountDownLatch mReadyLatch = new CountDownLatch(1);
-  private volatile @Nullable T mResult;
+  private @Nullable T mResult;
+  private @Nullable Exception mException;
 
   /**
    * Sets the result. If another thread has called {@link #get}, they will immediately receive the
-   * value. Must only be called once.
+   * value. set or setException must only be called once.
    */
   public void set(T result) {
-    if (mReadyLatch.getCount() == 0) {
-      throw new RuntimeException("Result has already been set!");
-    }
+    checkNotSet();
     mResult = result;
     mReadyLatch.countDown();
   }
 
+  /**
+   * Sets the eception. If another thread has called {@link #get}, they will immediately receive the
+   * exception. set or setException must only be called once.
+   */
+  public void setException(Exception exception) {
+    checkNotSet();
+    mException = exception;
+    mReadyLatch.countDown();
+  }
+
+  @Override
+  public boolean cancel(boolean mayInterruptIfRunning) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public boolean isCancelled() {
+    return false;
+  }
+
+  @Override
+  public boolean isDone() {
+    return mReadyLatch.getCount() == 0;
+  }
+
+  @Deprecated
+  @Override
+  public T get() throws InterruptedException, ExecutionException {
+    throw new UnsupportedOperationException("Must use a timeout");
+  }
+
   /**
    * Wait up to the timeout time for another Thread to set a value on this future. If a value has
    * already been set, this method will return immediately.
@@ -42,21 +74,26 @@ public void set(T result) {
    * NB: For simplicity, we catch and wrap InterruptedException. Do NOT use this class if you
    * are in the 1% of cases where you actually want to handle that.
    */
-  public @Nullable T get(long timeoutMS) {
+  @Override
+  public @Nullable T get(long timeout, TimeUnit unit) throws
+      InterruptedException, ExecutionException, TimeoutException {
     try {
-      if (!mReadyLatch.await(timeoutMS, TimeUnit.MILLISECONDS)) {
-        throw new TimeoutException();
+      if (!mReadyLatch.await(timeout, unit)) {
+        throw new TimeoutException("Timed out waiting for result");
       }
     } catch (InterruptedException e) {
       throw new RuntimeException(e);
     }
+    if (mException != null) {
+      throw new ExecutionException(mException);
+    }
+
     return mResult;
   }
 
-  public static class TimeoutException extends RuntimeException {
-
-    public TimeoutException() {
-      super("Timed out waiting for future");
+  private void checkNotSet() {
+    if (mReadyLatch.getCount() == 0) {
+      throw new RuntimeException("Result has already been set!");
     }
   }
 }

From 01e291751a35299a8059f6a14173c57000f7f6ac Mon Sep 17 00:00:00 2001
From: Alexander Blom <blom@fb.com>
Date: Sat, 12 Dec 2015 14:19:31 -0800
Subject: [PATCH 0344/1411] Use callOnQueue() instead of latch

Reviewed By: astreet

Differential Revision: D2717989

fb-gh-sync-id: 9770e773015838301f6e9520a1ca7a283f647de7
---
 .../react/bridge/CatalystInstanceImpl.java    | 20 +++++++------------
 1 file changed, 7 insertions(+), 13 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
index dd7f89dc7e3c..77264028578f 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
@@ -16,7 +16,6 @@
 import java.util.Collection;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -137,13 +136,11 @@ private ReactBridge initializeBridge(
   @Override
   public void runJSBundle() {
     try {
-      final CountDownLatch initLatch = new CountDownLatch(1);
-      mCatalystQueueConfiguration.getJSQueueThread().runOnQueue(
-          new Runnable() {
+      mJSBundleHasLoaded = mCatalystQueueConfiguration.getJSQueueThread().callOnQueue(
+          new Callable<Boolean>() {
             @Override
-            public void run() {
+            public Boolean call() throws Exception {
               Assertions.assertCondition(!mJSBundleHasLoaded, "JS bundle was already loaded!");
-              mJSBundleHasLoaded = true;
 
               incrementPendingJSCalls();
 
@@ -159,14 +156,11 @@ public void run() {
                 Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
               }
 
-              initLatch.countDown();
+              return true;
             }
-          });
-      Assertions.assertCondition(
-          initLatch.await(LOAD_JS_BUNDLE_TIMEOUT_MS, TimeUnit.MILLISECONDS),
-          "Timed out loading JS!");
-    } catch (InterruptedException e) {
-      throw new RuntimeException(e);
+          }).get(LOAD_JS_BUNDLE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+    } catch (Exception t) {
+      throw new RuntimeException(t);
     }
   }
 

From 2c7409b9ee10d429880e4c684a5b512a004800d9 Mon Sep 17 00:00:00 2001
From: WanderWang <wander.wang@egret.com>
Date: Sat, 12 Dec 2015 17:26:22 -0800
Subject: [PATCH 0345/1411] improve exception message when we can't find a file

Summary:
in ```fastfs.js ``` when ```getFile()``` got a exception it will print ``` Unable to find file with path: null ``` in terminal .

It's  confused
Closes https://github.com/facebook/react-native/pull/4737

Reviewed By: svcscm

Differential Revision: D2752888

Pulled By: androidtrunkagent

fb-gh-sync-id: a366da1eea27c691248dcb17019f4462a639ea70
---
 packager/react-packager/src/DependencyResolver/fastfs.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packager/react-packager/src/DependencyResolver/fastfs.js b/packager/react-packager/src/DependencyResolver/fastfs.js
index 17738744b7ab..3a6c3ee1386a 100644
--- a/packager/react-packager/src/DependencyResolver/fastfs.js
+++ b/packager/react-packager/src/DependencyResolver/fastfs.js
@@ -109,7 +109,7 @@ class Fastfs extends EventEmitter {
   readFile(filePath) {
     const file = this._getFile(filePath);
     if (!file) {
-      throw new Error(`Unable to find file with path: ${file}`);
+      throw new Error(`Unable to find file with path: ${filePath}`);
     }
     return file.read();
   }

From de677205ecd922ec787075eacb9c1caec81aa1d3 Mon Sep 17 00:00:00 2001
From: James Ide <ide+github@jameside.com>
Date: Sat, 12 Dec 2015 20:30:39 -0800
Subject: [PATCH 0346/1411] [Website] Add PullToRefreshViewAndroid to the web
 docs

---
 website/server/extractDocs.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/website/server/extractDocs.js b/website/server/extractDocs.js
index 8279a6f8d0e7..cdd69e9a0e37 100644
--- a/website/server/extractDocs.js
+++ b/website/server/extractDocs.js
@@ -198,6 +198,7 @@ var components = [
   '../Libraries/Picker/PickerIOS.ios.js',
   '../Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js',
   '../Libraries/Components/ProgressViewIOS/ProgressViewIOS.ios.js',
+  '../Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js',
   '../Libraries/Components/ScrollView/ScrollView.js',
   '../Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js',
   '../Libraries/Components/SliderIOS/SliderIOS.ios.js',

From 331fb61376b8e4775ca3d247fc2435901fa2cf76 Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Sun, 13 Dec 2015 17:29:18 +0800
Subject: [PATCH 0347/1411] update the way of using module Dimensions

---
 docs/Animations.md | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/docs/Animations.md b/docs/Animations.md
index 84c3f48510fc..0050b3d58576 100644
--- a/docs/Animations.md
+++ b/docs/Animations.md
@@ -529,7 +529,9 @@ make them customizable, React Native exposes a
 [NavigatorSceneConfigs](https://github.com/facebook/react-native/blob/master/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js) API.
 
 ```javascript
-var SCREEN_WIDTH = require('Dimensions').get('window').width;
+var React = require('react-native');
+var { Dimensions } = React;
+var SCREEN_WIDTH = Dimensions.get('window').width;
 var BaseConfig = Navigator.SceneConfigs.FloatFromRight;
 
 var CustomLeftToRightGesture = Object.assign({}, BaseConfig.gestures.pop, {

From 9cf2edb45876a6094a54d2412c85341d9949a467 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Sun, 13 Dec 2015 11:57:28 +0000
Subject: [PATCH 0348/1411] Update Releases.md

---
 Releases.md | 44 ++++++++++++++++++++++----------------------
 1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/Releases.md b/Releases.md
index 1ed509786e2e..01003c6e2f96 100644
--- a/Releases.md
+++ b/Releases.md
@@ -31,32 +31,32 @@ Make absolutely sure basic iOS and Android workflow works on master:
   - Check the artifacts were generated: `ls -al ~/.m2/repository/com/facebook/react/react-native/0.18.0/` should contain:
     - `react-native-0.18.0-javadoc.jar`, `react-native-0.18.0-sources.jar`, `react-native-0.18.0.aar`, `react-native-0.18.0.pom`
     - For each of the above also `.asc` file
-- In `package.json`, set version to e.g. `0.18.0-rc`.
-- In `React.podspec`, set version to e.g. `0.18.0-rc`.
-- In `local-cli/generator-android/templates/src/app/build.gradle` update the dependency to e.g. `com.facebook.react:react-native:0.18.+`
-- Publish to sinopia:
-  - `npm set registry http://localhost:4873/`, check that it worked: `npm config list` will show registry is set to localhost
-  - In a separate shell, start sinopia. Run `sinopia`. If started successfully it will print: http address - http://localhost:4873/.
-  - Make sure http://localhost:4873/ shows no old versions
-  - `npm publish`
-  - http://localhost:4873/ will show 0.18.0-rc
-- Test that everything works:
-  - `cd /tmp`
-  - `react-native init Zero12rc`
-  - `cd Zero12rc`
-  - Check that `package.json`, `android/app/build.gradle` have correct versions (`^0.18.0-rc`, `com.facebook.react:react-native:0.18.+`)
-  - `open ios/Zero12rc.xcodeproj`
-  - Hit the Run button in Xcode.
-  - Packager should open in a new window, you should see the Welcome to React Native screen, Reload JS, try Chrome debugging - put a breakpoint somewhere in `index.ios.js` and Reload JS, Chrome debugger should stop on the breakpoint (we don't have tests for Chrome debugging)
-  - Close the packager window, close Xcode
-  - Start an Android emulator (ideally Genymotion, it's faster and more reliable than Google emulators)
-  - `react-native run-android`
-  - Test is the same way as on iOS, including Chrome debugging
+  - In `package.json`, set version to e.g. `0.18.0-rc`.
+  - In `React.podspec`, set version to e.g. `0.18.0-rc`.
+  - In `local-cli/generator-android/templates/src/app/build.gradle` update the dependency to e.g. `com.facebook.react:react-native:0.18.+`
+  - Publish to sinopia:
+    - `npm set registry http://localhost:4873/`, check that it worked: `npm config list` will show registry is set to localhost
+    - In a separate shell, start sinopia. Run `sinopia`. If started successfully it will print: http address - http://localhost:4873/.
+    - Make sure http://localhost:4873/ shows no old versions
+    - `npm publish`
+    - http://localhost:4873/ will show 0.18.0-rc
+  - Test that everything works:
+    - `cd /tmp`
+    - `react-native init Zero12rc`
+    - `cd Zero12rc`
+    - Check that `package.json`, `android/app/build.gradle` have correct versions (`^0.18.0-rc`, `com.facebook.react:react-native:0.18.+`)
+    - `open ios/Zero12rc.xcodeproj`
+    - Hit the Run button in Xcode.
+    - Packager should open in a new window, you should see the Welcome to React Native screen, Reload JS, try Chrome debugging - put a breakpoint somewhere in `index.ios.js` and Reload JS, Chrome debugger should stop on the breakpoint (we don't have tests for Chrome debugging)
+    - Close the packager window, close Xcode
+    - Start an Android emulator (ideally Genymotion, it's faster and more reliable than Google emulators)
+    - `react-native run-android`
+    - Test is the same way as on iOS, including Chrome debugging
   
 #### Push to github
 
   - Revert the Javadoc change in `ReactAndroid/release.gradle`
-  - `git commit -am` "[0.18-rc] Bump version numbers"
+  - `git commit -am "[0.18-rc] Bump version numbers"`
   - `git push origin 0.18-stable`
 
 ## Do a release

From a5c0fd3272f0b6526262ceeeccaf270bda4c61ec Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Sun, 13 Dec 2015 12:06:43 +0000
Subject: [PATCH 0349/1411] Update Releases.md

---
 Releases.md | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/Releases.md b/Releases.md
index 01003c6e2f96..162f36ee52bf 100644
--- a/Releases.md
+++ b/Releases.md
@@ -12,6 +12,11 @@ Future releases:
 - 0.19.0 - Jan 28
 - ...
 
+## Ideas for improvements
+
+- A lot of these steps could be done by a script
+- We could simplify the process quite a bit by publishing the Android binaries to npm. This will increase the size of the npm package by about 3.3MB. To do that: after `installArchives`, move the binaries to somewhere where `npm publish` will pick them up. Then, change the `build.gradle` file(s) of your generated app so that Gradle will pick up the binaries from `node_modules`.
+
 ## Cut a release branch
 
 Note: Make sure you replace 0.18 in all the commands below with the version you're releasing :) For example, copy-paste all of this into an editor and replace 0.18.
@@ -61,7 +66,7 @@ Make absolutely sure basic iOS and Android workflow works on master:
 
 ## Do a release
 
-Publish to Maven Central (Note: We could get rid of this whole section publishing binaries to npm instead):
+Publish to Maven Central (Note: **We could get rid of this whole section by publishing binaries to npm instead**):
   - Log into Sonatype and go to [Staging upload](https://oss.sonatype.org/#staging-upload). You'll need to get permissions for this by filing a ticket explaining you're a core contributor to React Native. [Example ticket](https://issues.sonatype.org/browse/OSSRH-11885).
   - Select Artifact(s) with a POM (to publish to a local Maven repo for testing run `./gradlew :ReactAndroid:installArchives`)
   - Add all files: .aar, sources jar, javadoc jar, .asc for everything (including the POM file)

From 476b0af510c3d478a5e2f4c74af74fec7c7b17e2 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Sun, 13 Dec 2015 14:14:09 +0000
Subject: [PATCH 0350/1411] Update NewIssueGreeting.md

---
 bots/NewIssueGreeting.md | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/bots/NewIssueGreeting.md b/bots/NewIssueGreeting.md
index 87e421b499eb..8d22aec68d61 100644
--- a/bots/NewIssueGreeting.md
+++ b/bots/NewIssueGreeting.md
@@ -2,8 +2,8 @@ Hey {author}, thanks for reporting this issue!
 
 React Native, as you've probably heard, is getting really popular and truth is we're getting a bit overwhelmed by the activity surrounding it. There are just too many issues for us to manage properly.
 
-- If this is a feature request or a bug that you would like to be fixed by the team, please report it on [Product Pains](https://productpains.com/product/react-native/). It has a ranking feature that lets us focus on the most important issues the community is experiencing.
+- If you **don't know how to do something** or not sure whether some behavior is expected or a bug, please ask on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native) with the tag `react-native` or for more real time interactions, ask on [Discord](https://discord.gg/0ZcbPKXt5bZjGY5n) in the #react-native channel.
 
-- If you don't know how to do something or not sure whether some behavior is expected or a bug, please ask on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native) with the tag `react-native` or for more real time interactions, ask on [Discord](https://discord.gg/0ZcbPKXt5bZjGY5n) in the #react-native channel.
+- If this is a **feature request or a bug** that you would like to be fixed, please report it on [Product Pains](https://productpains.com/product/react-native/). It has a ranking feature that lets us focus on the most important issues the community is experiencing.
 
-- We welcome clear issues and PRs that are ready for in-depth discussion; thank you for your contributions!
+- We welcome clear issues and PRs that are ready for in-depth discussion. Please provide **screenshots** where appropriate and always mention the **version** of React Native you're using. Thank you for your contributions!

From 2f30acb5bcadc549eb9bb7affe8fa5a87a21d50e Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Sun, 13 Dec 2015 14:33:52 +0000
Subject: [PATCH 0351/1411] Update Releases.md

---
 Releases.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Releases.md b/Releases.md
index 162f36ee52bf..d3fe4184d6a9 100644
--- a/Releases.md
+++ b/Releases.md
@@ -15,7 +15,7 @@ Future releases:
 ## Ideas for improvements
 
 - A lot of these steps could be done by a script
-- We could simplify the process quite a bit by publishing the Android binaries to npm. This will increase the size of the npm package by about 3.3MB. To do that: after `installArchives`, move the binaries to somewhere where `npm publish` will pick them up. Then, change the `build.gradle` file(s) of your generated app so that Gradle will pick up the binaries from `node_modules`.
+- We could simplify the process quite a bit by publishing the Android binaries to npm. This will increase the size of the npm package by about 3.3MB. To do that: after `installArchives`, move the binaries to somewhere where `npm publish` will pick them up. Then, change the `build.gradle` file(s) of your generated app so that Gradle will pick up the binaries from `node_modules`. This might also **fix issues with incompatible versions of JS and Android binaries** (e.g. [#4488](https://github.com/facebook/react-native/issues/4488)).
 
 ## Cut a release branch
 

From 1280df0464714b5003c9bff6e907c59f535ac6c4 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Sun, 13 Dec 2015 14:34:57 +0000
Subject: [PATCH 0352/1411] Update Releases.md

---
 Releases.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Releases.md b/Releases.md
index d3fe4184d6a9..4356b2ecb4d8 100644
--- a/Releases.md
+++ b/Releases.md
@@ -15,7 +15,7 @@ Future releases:
 ## Ideas for improvements
 
 - A lot of these steps could be done by a script
-- We could simplify the process quite a bit by publishing the Android binaries to npm. This will increase the size of the npm package by about 3.3MB. To do that: after `installArchives`, move the binaries to somewhere where `npm publish` will pick them up. Then, change the `build.gradle` file(s) of your generated app so that Gradle will pick up the binaries from `node_modules`. This might also **fix issues with incompatible versions of JS and Android binaries** (e.g. [#4488](https://github.com/facebook/react-native/issues/4488)).
+- We could simplify the process quite a bit by publishing the Android binaries to npm. This will increase the size of the npm package by about 3.3MB. To do that: after `installArchives`, move the binaries to somewhere where `npm publish` will pick them up. Then, change the `build.gradle` file(s) of your generated app so that Gradle will pick up the binaries from `node_modules`. This will likely also **fix issues with incompatible versions of JS and Android binaries** (e.g. [#4488](https://github.com/facebook/react-native/issues/4488)).
 
 ## Cut a release branch
 

From 4373aa68228054916d55c0956ede6eeacd40241a Mon Sep 17 00:00:00 2001
From: Huang Yu <huang@bitgo.com>
Date: Sun, 13 Dec 2015 11:42:53 -0800
Subject: [PATCH 0353/1411] fix animated lint warnings

Summary:
fix lint warnings under 'Libraries/Animated' directory
Closes https://github.com/facebook/react-native/pull/4448

Reviewed By: svcscm

Differential Revision: D2753880

Pulled By: androidtrunkagent

fb-gh-sync-id: c6619c636ff67a74e6f063f70526327d756271db
---
 Libraries/Animated/src/Easing.js |  6 +++---
 Libraries/Animated/src/bezier.js | 22 ++++++++++++----------
 2 files changed, 15 insertions(+), 13 deletions(-)

diff --git a/Libraries/Animated/src/Easing.js b/Libraries/Animated/src/Easing.js
index 46c30aed0646..a8685a7182d6 100644
--- a/Libraries/Animated/src/Easing.js
+++ b/Libraries/Animated/src/Easing.js
@@ -72,14 +72,14 @@ class Easing {
   static elastic(bounciness: number = 1): (t: number) => number {
     var p = bounciness * Math.PI;
     return (t) => 1 - Math.pow(Math.cos(t * Math.PI / 2), 3) * Math.cos(t * p);
-  };
+  }
 
   static back(s: number): (t: number) => number {
     if (s === undefined) {
       s = 1.70158;
     }
     return (t) => t * t * ((s + 1) * t - s);
-  };
+  }
 
   static bounce(t: number): number {
     if (t < 1 / 2.75) {
@@ -98,7 +98,7 @@ class Easing {
 
     t -= 2.625 / 2.75;
     return 7.5625 * t * t + 0.984375;
-  };
+  }
 
   static bezier(
     x1: number,
diff --git a/Libraries/Animated/src/bezier.js b/Libraries/Animated/src/bezier.js
index 11b02f501c89..19cc855a4d95 100644
--- a/Libraries/Animated/src/bezier.js
+++ b/Libraries/Animated/src/bezier.js
@@ -42,7 +42,7 @@ module.exports = function(x1, y1, x2, y2, epsilon){
 
   var derivativeCurveX = function(t){
     var v = 1 - t;
-    return 3 * (2 * (t - 1) * t + v * v) * x1 + 3 * (- t * t * t + 2 * v * t) * x2;
+    return 3 * (2 * (t - 1) * t + v * v) * x1 + 3 * (-t * t * t + 2 * v * t) * x2;
   };
 
   return function(t){
@@ -52,24 +52,26 @@ module.exports = function(x1, y1, x2, y2, epsilon){
     // First try a few iterations of Newton's method -- normally very fast.
     for (t2 = x, i = 0; i < 8; i++){
       x2 = curveX(t2) - x;
-      if (Math.abs(x2) < epsilon) return curveY(t2);
+      if (Math.abs(x2) < epsilon) { return curveY(t2); }
       d2 = derivativeCurveX(t2);
-      if (Math.abs(d2) < 1e-6) break;
+      if (Math.abs(d2) < 1e-6) { break; }
       t2 = t2 - x2 / d2;
     }
 
-    t0 = 0, t1 = 1, t2 = x;
+    t0 = 0;
+    t1 = 1;
+    t2 = x;
 
-    if (t2 < t0) return curveY(t0);
-    if (t2 > t1) return curveY(t1);
+    if (t2 < t0) { return curveY(t0); }
+    if (t2 > t1) { return curveY(t1); }
 
     // Fallback to the bisection method for reliability.
     while (t0 < t1){
       x2 = curveX(t2);
-      if (Math.abs(x2 - x) < epsilon) return curveY(t2);
-      if (x > x2) t0 = t2;
-      else t1 = t2;
-      t2 = (t1 - t0) * .5 + t0;
+      if (Math.abs(x2 - x) < epsilon) { return curveY(t2); }
+      if (x > x2) { t0 = t2; }
+      else { t1 = t2; }
+      t2 = (t1 - t0) * 0.5 + t0;
     }
 
     // Failure

From a1077ba6e9eae571285db9ac561ecaf6550ec49e Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Mon, 14 Dec 2015 15:10:00 +0800
Subject: [PATCH 0354/1411] remove the undocumented @provideModules

Using relative file path
---
 docs/NativeModulesAndroid.md | 13 ++-----------
 1 file changed, 2 insertions(+), 11 deletions(-)

diff --git a/docs/NativeModulesAndroid.md b/docs/NativeModulesAndroid.md
index 8ce2ef3d2986..56a8c2f83a6d 100644
--- a/docs/NativeModulesAndroid.md
+++ b/docs/NativeModulesAndroid.md
@@ -125,12 +125,7 @@ mReactInstanceManager = ReactInstanceManager.builder()
 To make it simpler to access your new functionality from JavaScript, it is common to wrap the native module in a JavaScript module. This is not necessary but saves the consumers of your library the need to pull it off of `NativeModules` each time. This JavaScript file also becomes a good location for you to add any JavaScript side functionality.
 
 ```js
-/**
- * @providesModule ToastAndroid
- */
-
 'use strict';
-
 /**
  * This exposes the native ToastAndroid module as a JS module. This has a function 'show'
  * which takes the following parameters:
@@ -142,16 +137,12 @@ var { NativeModules } = require('react-native');
 module.exports = NativeModules.ToastAndroid;
 ```
 
-Save the above code into a file named "ToastAndroid.js". Now, from your other JavaScript file you can call the method like this:
+Now, from your other JavaScript file you can call the method like this:
 
 ```js
-// Suppose this js file is under the same directory as ToastAndroid.js. 
-// Otherwise change the require path.
 var ToastAndroid = require('./ToastAndroid'); 
-ToastAndroid.show('Awesome', ToastAndroid.SHORT);
 
-// Note: We require ToastAndroid without any relative filepath because
-// of the @providesModule directive. Using @providesModule is optional.
+ToastAndroid.show('Awesome', ToastAndroid.SHORT);
 ```
 
 ## Beyond Toasts

From b8f3730d8da89ab97b58e751018f3a37580a368e Mon Sep 17 00:00:00 2001
From: Dotan Nahum <jondotan@gmail.com>
Date: Mon, 14 Dec 2015 13:22:21 +0200
Subject: [PATCH 0355/1411] Adding Due to showcase (Apps)

---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 1e595b17f205..38fbf50b8699 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -422,6 +422,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/yazboz-batak-esli-batak-okey/id1048620855?ls=1&mt=8',
     author: 'Melih Mucuk',
   },
+  {
+    name: 'Due',
+    icon: 'http://a1.mzstatic.com/us/r30/Purple69/v4/a2/41/5d/a2415d5f-407a-c565-ffb4-4f27f23d8ac2/icon175x175.png',
+    link: 'https://itunes.apple.com/us/app/due-countdown-reminders-for/id1050909468?mt=8',
+    author: 'Dotan Nahum',
+  },
 ];
 
 var AppList = React.createClass({

From ff58629640ece8daf872b0ea43cd845b12045d41 Mon Sep 17 00:00:00 2001
From: Dotan Nahum <jondotan@gmail.com>
Date: Mon, 14 Dec 2015 14:13:58 +0200
Subject: [PATCH 0356/1411] Alphabetical ordering

---
 website/src/react-native/showcase.js | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 38fbf50b8699..fdd7a73a34a5 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -162,6 +162,12 @@ var apps = [
     link:  'https://itunes.apple.com/us/app/dropbot-phone-replacement/id1000855694?mt=8',
     author: 'Peach Labs',
   },
+  {
+    name: 'Due',
+    icon: 'http://a1.mzstatic.com/us/r30/Purple69/v4/a2/41/5d/a2415d5f-407a-c565-ffb4-4f27f23d8ac2/icon175x175.png',
+    link: 'https://itunes.apple.com/us/app/due-countdown-reminders-for/id1050909468?mt=8',
+    author: 'Dotan Nahum',
+  },
   {
     name: 'Eat or Not',
     icon: 'http://a3.mzstatic.com/us/r30/Purple5/v4/51/be/34/51be3462-b015-ebf2-11c5-69165b37fadc/icon175x175.jpeg',
@@ -422,12 +428,6 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/yazboz-batak-esli-batak-okey/id1048620855?ls=1&mt=8',
     author: 'Melih Mucuk',
   },
-  {
-    name: 'Due',
-    icon: 'http://a1.mzstatic.com/us/r30/Purple69/v4/a2/41/5d/a2415d5f-407a-c565-ffb4-4f27f23d8ac2/icon175x175.png',
-    link: 'https://itunes.apple.com/us/app/due-countdown-reminders-for/id1050909468?mt=8',
-    author: 'Dotan Nahum',
-  },
 ];
 
 var AppList = React.createClass({

From b33e091765ccaba164a57b03a6b9e7ce7b836ee7 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Mon, 14 Dec 2015 12:55:09 +0000
Subject: [PATCH 0357/1411] Update Releases.md

---
 Releases.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Releases.md b/Releases.md
index 4356b2ecb4d8..6e19390f672a 100644
--- a/Releases.md
+++ b/Releases.md
@@ -88,6 +88,7 @@ git push --tags
 - Publish to npm
 
 ```
+npm set registry https://registry.npmjs.org/
 npm publish
 # Only when doing a non-rc release:
 npm dist-tag add react-native@0.18.0 latest

From 1d71457934f7086f9438e06908c1c6d06e09b226 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Mon, 14 Dec 2015 14:32:25 +0000
Subject: [PATCH 0358/1411] Update AndroidBuildingFromSource.md

---
 docs/AndroidBuildingFromSource.md | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/docs/AndroidBuildingFromSource.md b/docs/AndroidBuildingFromSource.md
index b09c53811208..6a7cd37f1b0a 100644
--- a/docs/AndroidBuildingFromSource.md
+++ b/docs/AndroidBuildingFromSource.md
@@ -16,7 +16,7 @@ Assuming you have the Android SDK installed, run `android` to open the Android S
 Make sure you have the following installed:
 
 1. Android SDK version 23 (compileSdkVersion in [`build.gradle`](https://github.com/facebook/react-native/blob/master/ReactAndroid/build.gradle))
-2. SDK build tools version 23.0.1 (buildToolsVersion in [`build.gradle`](https://github.com/facebook/react-native/blob/master/ReactAndroid/build.gradle)])
+2. SDK build tools version 23.0.1 (buildToolsVersion in [`build.gradle`](https://github.com/facebook/react-native/blob/master/ReactAndroid/build.gradle))
 3. Android Support Repository >= 17 (for Android Support Library)
 4. Android NDK (download & extraction instructions [here](http://developer.android.com/ndk/downloads/index.html))
 
@@ -47,8 +47,7 @@ npm install --save github:facebook/react-native#master
 
 Alternatively, you can clone the repo to your `node_modules` directory and run `npm install` inside the cloned repo.
 
-
-#### 2. Adding missing dependencies
+#### 2. Adding gradle dependencies
 
 Add `gradle-download-task` as dependency in `android/build.gradle`:
 
@@ -64,7 +63,6 @@ Add `gradle-download-task` as dependency in `android/build.gradle`:
 ...
 ```
 
-
 #### 3. Adding the `:ReactAndroid` project
 
 Add the `:ReactAndroid` project in `android/settings.gradle`:
@@ -73,7 +71,8 @@ Add the `:ReactAndroid` project in `android/settings.gradle`:
 ...
 include ':ReactAndroid'
 
-project(':ReactAndroid').projectDir = new File(rootProject.projectDir, '../node_modules/react-native/ReactAndroid')
+project(':ReactAndroid').projectDir = new File(
+    rootProject.projectDir, '../node_modules/react-native/ReactAndroid')
 ...
 ```
 
@@ -109,7 +108,7 @@ compile(project(':react-native-custom-module')) {
 
 ## Additional notes
 
-Building from source can take a long time, especially for the first build, as it needs to download ~200 MB of files and compile JSC etc. Every time you update the `react-native` version from your repo, the build directory may get deleted, and all the files are re-downloaded. To avoid this, you might want to change your build directory path by editing the `~/.gradle/init.gradle ` file:
+Building from source can take a long time, especially for the first build, as it needs to download ~200 MB of artifacts and compile the native code. Every time you update the `react-native` version from your repo, the build directory may get deleted, and all the files are re-downloaded. To avoid this, you might want to change your build directory path by editing the `~/.gradle/init.gradle ` file:
 
 ```gradle
 gradle.projectsLoaded {

From 2f56c0c90a43288e64bb54d96e55e9067b8e2014 Mon Sep 17 00:00:00 2001
From: Krzysztof Magiera <krzys.magiera@gmail.com>
Date: Mon, 14 Dec 2015 06:23:06 -0800
Subject: [PATCH 0359/1411] Upgrade gradle to 2.9

Summary:
public

New version of gradle has a better support for zipTree copy task. Since we have a few of those including one for boost library which used to take very long, after upgrading we no longer need 6a656a1.

Also seems like many improvements made to gradle since 2.2 made it perform better on incremental builds (around 10% improvement on my laptop).

Command used to upgrade gradle version:

    gradle wrapper --gradle-version 2.9

Some of the plugins require updating as well since the previous versions were incompatible with gradle 2.9.

Closes https://github.com/facebook/react-native/pull/4462

Reviewed By: mkonicek

Differential Revision: D2754786

Pulled By: mkonicek

fb-gh-sync-id: 92c07d29aec6d5b4b2c55205b42b135c4d9479a9
---
 ReactAndroid/build.gradle                |  16 +++++-----------
 build.gradle                             |   4 ++--
 gradle/wrapper/gradle-wrapper.jar        | Bin 49896 -> 53636 bytes
 gradle/wrapper/gradle-wrapper.properties |   4 ++--
 gradlew                                  |  10 +++-------
 5 files changed, 12 insertions(+), 22 deletions(-)

diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle
index ef343d4a7fdf..464a2ad18a34 100644
--- a/ReactAndroid/build.gradle
+++ b/ReactAndroid/build.gradle
@@ -29,17 +29,11 @@ task downloadBoost(dependsOn: createNativeDepsDirectories, type: Download) {
     dest new File(downloadsDir, 'boost_1_57_0.zip')
 }
 
-task prepareBoost(dependsOn: downloadBoost) {
-    inputs.files downloadBoost.dest, 'src/main/jni/third-party/boost/Android.mk'
-    outputs.dir "$thirdPartyNdkDir/boost"
-    doLast {
-        copy {
-            from { zipTree(downloadBoost.dest) }
-            from 'src/main/jni/third-party/boost/Android.mk'
-            include 'boost_1_57_0/boost/**/*.hpp', 'Android.mk'
-            into "$thirdPartyNdkDir/boost"
-        }
-    }
+task prepareBoost(dependsOn: downloadBoost, type: Copy) {
+    from zipTree(downloadBoost.dest)
+    from 'src/main/jni/third-party/boost/Android.mk'
+    include 'boost_1_57_0/boost/**/*.hpp', 'Android.mk'
+    into "$thirdPartyNdkDir/boost"
 }
 
 task downloadDoubleConversion(dependsOn: createNativeDepsDirectories, type: Download) {
diff --git a/build.gradle b/build.gradle
index d87035a390a4..eed2379a8759 100644
--- a/build.gradle
+++ b/build.gradle
@@ -6,8 +6,8 @@ buildscript {
         mavenLocal()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:1.3.1'
-        classpath 'de.undercouch:gradle-download-task:1.2'
+        classpath 'com.android.tools.build:gradle:1.5.0'
+        classpath 'de.undercouch:gradle-download-task:2.0.0'
 
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 8c0fb64a8698b08ecc4158d828ca593c4928e9dd..941144813d241db74e1bf25b6804c679fbe7f0a3 100644
GIT binary patch
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0c71e760dc93..9881fc8cf8b3 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Wed Apr 10 15:27:10 PDT 2013
+#Mon Dec 14 14:06:01 GMT 2015
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.9-bin.zip
diff --git a/gradlew b/gradlew
index 91a7e269e19d..9d82f7891513 100755
--- a/gradlew
+++ b/gradlew
@@ -42,11 +42,6 @@ case "`uname`" in
     ;;
 esac
 
-# For Cygwin, ensure paths are in UNIX format before anything is touched.
-if $cygwin ; then
-    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
-fi
-
 # Attempt to set APP_HOME
 # Resolve links: $0 may be a link
 PRG="$0"
@@ -61,9 +56,9 @@ while [ -h "$PRG" ] ; do
     fi
 done
 SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >&-
+cd "`dirname \"$PRG\"`/" >/dev/null
 APP_HOME="`pwd -P`"
-cd "$SAVED" >&-
+cd "$SAVED" >/dev/null
 
 CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
 
@@ -114,6 +109,7 @@ fi
 if $cygwin ; then
     APP_HOME=`cygpath --path --mixed "$APP_HOME"`
     CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
 
     # We build the pattern for arguments to be converted via cygpath
     ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`

From c8108bdbe13590660d7f575d0747e100ea7bb866 Mon Sep 17 00:00:00 2001
From: Brent Vatne <brentvatne@gmail.com>
Date: Mon, 14 Dec 2015 06:41:45 -0800
Subject: [PATCH 0360/1411] Fixed controlled component on iOS and remove
 unnecessary code

Summary:
Closes #4290

`mostRecentEventCount` was always being set after `text` on iOS, so let's be really explicit about the order here as we were doing on Android: always call `setNativeProps` providing the `mostRecentEventCount` before we call `onChange` or `onChangeText`.

I also ripped out storing `mostRecentEventCount` in the state, which isn't necessary since we're always doing it through `setNativeProps`.
Closes https://github.com/facebook/react-native/pull/4588

Reviewed By: svcscm

Differential Revision: D2754565

Pulled By: nicklockwood

fb-gh-sync-id: a1401f39b4e19248095517c2a3503cd2af59fa47
---
 Examples/UIExplorer/TextInputExample.ios.js | 27 +++++++++++++
 Libraries/Components/TextInput/TextInput.js | 45 ++++++++-------------
 2 files changed, 43 insertions(+), 29 deletions(-)

diff --git a/Examples/UIExplorer/TextInputExample.ios.js b/Examples/UIExplorer/TextInputExample.ios.js
index 2479e1d61aa3..f8324c51af1d 100644
--- a/Examples/UIExplorer/TextInputExample.ios.js
+++ b/Examples/UIExplorer/TextInputExample.ios.js
@@ -125,6 +125,27 @@ class RewriteExample extends React.Component {
   }
 }
 
+class RewriteExampleInvalidCharacters extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {text: ''};
+  }
+  render() {
+    return (
+      <View style={styles.rewriteContainer}>
+        <TextInput
+          multiline={false}
+          onChangeText={(text) => {
+            this.setState({text: text.replace(/\s/g, '')});
+          }}
+          style={styles.default}
+          value={this.state.text}
+        />
+      </View>
+    );
+  }
+}
+
 class TokenizedTextExample extends React.Component {
   constructor(props) {
     super(props);
@@ -313,6 +334,12 @@ exports.examples = [
       return <RewriteExample />;
     }
   },
+  {
+    title: "Live Re-Write (no spaces allowed)",
+    render: function() {
+      return <RewriteExampleInvalidCharacters />;
+    }
+  },
   {
     title: 'Auto-capitalize',
     render: function() {
diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js
index 9f8f44ed75e9..fe62ec7fb2a7 100644
--- a/Libraries/Components/TextInput/TextInput.js
+++ b/Libraries/Components/TextInput/TextInput.js
@@ -329,12 +329,6 @@ var TextInput = React.createClass({
       React.findNodeHandle(this.refs.input);
   },
 
-  getInitialState: function() {
-    return {
-      mostRecentEventCount: 0,
-    };
-  },
-
   contextTypes: {
     onFocusRequested: React.PropTypes.func,
     focusEmitter: React.PropTypes.instanceOf(EventEmitter),
@@ -431,7 +425,6 @@ var TextInput = React.createClass({
           onSelectionChange={onSelectionChange}
           onSelectionChangeShouldSetResponder={emptyFunction.thatReturnsTrue}
           text={this._getText()}
-          mostRecentEventCount={this.state.mostRecentEventCount}
         />;
     } else {
       for (var propKey in notMultiline) {
@@ -460,7 +453,6 @@ var TextInput = React.createClass({
           ref="input"
           {...props}
           children={children}
-          mostRecentEventCount={this.state.mostRecentEventCount}
           onFocus={this._onFocus}
           onBlur={this._onBlur}
           onChange={this._onChange}
@@ -506,7 +498,7 @@ var TextInput = React.createClass({
         textAlign={textAlign}
         textAlignVertical={textAlignVertical}
         keyboardType={this.props.keyboardType}
-        mostRecentEventCount={this.state.mostRecentEventCount}
+        mostRecentEventCount={0}
         multiline={this.props.multiline}
         numberOfLines={this.props.numberOfLines}
         maxLength={this.props.maxLength}
@@ -548,29 +540,24 @@ var TextInput = React.createClass({
   },
 
   _onChange: function(event: Event) {
-    if (Platform.OS === 'android') {
-      // Android expects the event count to be updated as soon as possible.
-      this.refs.input.setNativeProps({
-        mostRecentEventCount: event.nativeEvent.eventCount,
-      });
-    }
+    // Make sure to fire the mostRecentEventCount first so it is already set on
+    // native when the text value is set.
+    this.refs.input.setNativeProps({
+      mostRecentEventCount: event.nativeEvent.eventCount,
+    });
+
     var text = event.nativeEvent.text;
-    var eventCount = event.nativeEvent.eventCount;
     this.props.onChange && this.props.onChange(event);
     this.props.onChangeText && this.props.onChangeText(text);
-    this.setState({mostRecentEventCount: eventCount}, () => {
-      // NOTE: this doesn't seem to be needed on iOS - keeping for now in case it's required on Android
-      if (Platform.OS === 'android') {
-        // This is a controlled component, so make sure to force the native value
-        // to match.  Most usage shouldn't need this, but if it does this will be
-        // more correct but might flicker a bit and/or cause the cursor to jump.
-        if (text !== this.props.value && typeof this.props.value === 'string') {
-          this.refs.input.setNativeProps({
-            text: this.props.value,
-          });
-        }
-      }
-    });
+
+    // This is necessary in case native updates the text and JS decides
+    // that the update should be ignored and we should stick with the value
+    // that we have in JS.
+    if (text !== this.props.value && typeof this.props.value === 'string') {
+      this.refs.input.setNativeProps({
+        text: this.props.value,
+      });
+    }
   },
 
   _onBlur: function(event: Event) {

From b6fce4ad52520fc911a6bebaa3424a16d739848d Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Mon, 14 Dec 2015 06:59:39 -0800
Subject: [PATCH 0361/1411] Prevent the profiler from hooking into stret
 methods

Summary:
public

In order to handle methods that returns struct in i386 and x86_64 we'd need to implement special methods (like objc_msgSend_stret),
but we'll just bail out for now, since there's very few usages.

Reviewed By: jspahrsummers

Differential Revision: D2754732

fb-gh-sync-id: d3585d244633d918770ef79a52dee9cdf87a53da
---
 React/Profiler/RCTProfile.m | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/React/Profiler/RCTProfile.m b/React/Profiler/RCTProfile.m
index a47931e429c2..cac086c055d1 100644
--- a/React/Profiler/RCTProfile.m
+++ b/React/Profiler/RCTProfile.m
@@ -232,7 +232,20 @@ void RCTProfileHookModules(RCTBridge *bridge)
       for (NSUInteger i = 0; i < methodCount; i++) {
         Method method = methods[i];
         SEL selector = method_getName(method);
-        if ([NSStringFromSelector(selector) hasPrefix:@"rct"] || [NSObject instancesRespondToSelector:selector]) {
+
+        /**
+         * Bail out on struct returns (except arm64) - we don't use it enough
+         * to justify writing a stret version
+         */
+#ifdef __arm64__
+        BOOL returnsStruct = NO;
+#else
+        const char *typeEncoding = method_getTypeEncoding(method);
+        // bail out on structs and unions (since they might contain structs)
+        BOOL returnsStruct = typeEncoding[0] == '{' || typeEncoding[0] == '(';
+#endif
+
+        if ([NSStringFromSelector(selector) hasPrefix:@"rct"] || [NSObject instancesRespondToSelector:selector] || returnsStruct) {
           continue;
         }
         const char *types = method_getTypeEncoding(method);

From 4626de9ba393d975413aae1bcea5ff8afbdbe556 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Mon, 14 Dec 2015 09:02:40 -0800
Subject: [PATCH 0362/1411] Update fbjs-haste

Reviewed By: bestander

Differential Revision: D2754889

fb-gh-sync-id: 5484fbd1079b1434b2853179e663eff30d03b82d
---
 npm-shrinkwrap.json | 6 +++---
 package.json        | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index 630e9cded87e..6ea6abf56eb9 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -1756,9 +1756,9 @@
       }
     },
     "fbjs-haste": {
-      "version": "0.3.2",
-      "from": "fbjs-haste@0.3.2",
-      "resolved": "https://registry.npmjs.org/fbjs-haste/-/fbjs-haste-0.3.2.tgz"
+      "version": "0.3.3",
+      "from": "fbjs-haste@0.3.3",
+      "resolved": "https://registry.npmjs.org/fbjs-haste/-/fbjs-haste-0.3.3.tgz"
     },
     "fbjs-scripts": {
       "version": "0.4.0",
diff --git a/package.json b/package.json
index 54af188aa0b0..3efa72e81bac 100644
--- a/package.json
+++ b/package.json
@@ -89,7 +89,7 @@
     "connect": "^2.8.3",
     "debug": "^2.2.0",
     "event-target-shim": "^1.0.5",
-    "fbjs-haste": "^0.3.2",
+    "fbjs-haste": "^0.3.3",
     "fbjs-scripts": "^0.4.0",
     "graceful-fs": "^4.1.2",
     "image-size": "^0.3.5",

From e35469e1db7f00cc296745b76d9a0024eb80c0de Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Mon, 14 Dec 2015 11:07:36 -0800
Subject: [PATCH 0363/1411] Upgrade fbjs-haste to 0.3.4

Summary:
public

Attempt to fix https://travis-ci.org/facebook/react-native/builds

Steps:

    cd .../react-native-github
    npm install fbjs-haste@0.3.4
    # manually update npm-shrinkwrap.json (normally done using npm shrinkwrap --dev but the shrinkwrap file is out of date)

Reviewed By: zpao

Differential Revision: D2755259

fb-gh-sync-id: c5237adcc14e9e21cc09dfad765eff16ddf28484
---
 npm-shrinkwrap.json | 6 +++---
 package.json        | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index 6ea6abf56eb9..6b0c320f615c 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -1756,9 +1756,9 @@
       }
     },
     "fbjs-haste": {
-      "version": "0.3.3",
-      "from": "fbjs-haste@0.3.3",
-      "resolved": "https://registry.npmjs.org/fbjs-haste/-/fbjs-haste-0.3.3.tgz"
+      "version": "0.3.4",
+      "from": "fbjs-haste@0.3.4",
+      "resolved": "https://registry.npmjs.org/fbjs-haste/-/fbjs-haste-0.3.4.tgz"
     },
     "fbjs-scripts": {
       "version": "0.4.0",
diff --git a/package.json b/package.json
index 3efa72e81bac..45913996d365 100644
--- a/package.json
+++ b/package.json
@@ -89,7 +89,7 @@
     "connect": "^2.8.3",
     "debug": "^2.2.0",
     "event-target-shim": "^1.0.5",
-    "fbjs-haste": "^0.3.3",
+    "fbjs-haste": "^0.3.4",
     "fbjs-scripts": "^0.4.0",
     "graceful-fs": "^4.1.2",
     "image-size": "^0.3.5",

From 537598d705b2391d0dfe0b46fe9072d4a62f6ac2 Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Mon, 14 Dec 2015 11:12:54 -0800
Subject: [PATCH 0364/1411] Move FileWatcher into node-haste

Reviewed By: davidaurelio

Differential Revision: D2752711

fb-gh-sync-id: e656a3019b95c7677d5b27e74dc921ef62ba5c83
---
 .../FileWatcher/__mocks__/sane.js             |  2 +-
 .../FileWatcher/__tests__/FileWatcher-test.js | 23 +++++++++++++------
 .../FileWatcher/index.js                      |  8 ++-----
 .../src/Server/__tests__/Server-test.js       |  2 +-
 packager/react-packager/src/Server/index.js   |  2 +-
 5 files changed, 21 insertions(+), 16 deletions(-)
 rename packager/react-packager/src/{ => DependencyResolver}/FileWatcher/__mocks__/sane.js (98%)
 rename packager/react-packager/src/{ => DependencyResolver}/FileWatcher/__tests__/FileWatcher-test.js (80%)
 rename packager/react-packager/src/{ => DependencyResolver}/FileWatcher/index.js (94%)

diff --git a/packager/react-packager/src/FileWatcher/__mocks__/sane.js b/packager/react-packager/src/DependencyResolver/FileWatcher/__mocks__/sane.js
similarity index 98%
rename from packager/react-packager/src/FileWatcher/__mocks__/sane.js
rename to packager/react-packager/src/DependencyResolver/FileWatcher/__mocks__/sane.js
index 9823a930d128..2a36bb39dc3b 100644
--- a/packager/react-packager/src/FileWatcher/__mocks__/sane.js
+++ b/packager/react-packager/src/DependencyResolver/FileWatcher/__mocks__/sane.js
@@ -9,5 +9,5 @@
 'use strict';
 
 module.exports = {
-  WatchmanWatcher: jest.genMockFromModule('sane/src/watchman_watcher')
+  WatchmanWatcher: jest.genMockFromModule('sane/src/watchman_watcher'),
 };
diff --git a/packager/react-packager/src/FileWatcher/__tests__/FileWatcher-test.js b/packager/react-packager/src/DependencyResolver/FileWatcher/__tests__/FileWatcher-test.js
similarity index 80%
rename from packager/react-packager/src/FileWatcher/__tests__/FileWatcher-test.js
rename to packager/react-packager/src/DependencyResolver/FileWatcher/__tests__/FileWatcher-test.js
index 973c4f7804bc..b0d2fd090bb7 100644
--- a/packager/react-packager/src/FileWatcher/__tests__/FileWatcher-test.js
+++ b/packager/react-packager/src/DependencyResolver/FileWatcher/__tests__/FileWatcher-test.js
@@ -12,28 +12,37 @@ jest
   .dontMock('util')
   .dontMock('events')
   .dontMock('../')
-  .dontMock('q')
   .setMock('child_process', {
     exec: function(cmd, cb) {
       cb(null, '/usr/bin/watchman');
-    }
+    },
   });
 
-var FileWatcher = require('../');
 var sane = require('sane');
 
 describe('FileWatcher', function() {
   var Watcher;
+  var FileWatcher;
+  var config;
 
   beforeEach(function() {
     Watcher = sane.WatchmanWatcher;
     Watcher.prototype.once.mockImplementation(function(type, callback) {
       callback();
     });
+    FileWatcher = require('../');
+
+    config = [{
+      dir: 'rootDir',
+      globs: [
+        '**/*.js',
+        '**/*.json',
+      ],
+    }];
   });
 
   pit('it should get the watcher instance when ready', function() {
-    var fileWatcher = new FileWatcher(['rootDir']);
+    var fileWatcher = new FileWatcher(config);
     return fileWatcher.getWatchers().then(function(watchers) {
       watchers.forEach(function(watcher) {
         expect(watcher instanceof Watcher).toBe(true);
@@ -46,10 +55,10 @@ describe('FileWatcher', function() {
     Watcher.prototype.on.mockImplementation(function(type, callback) {
       cb = callback;
     });
-    var fileWatcher = new FileWatcher(['rootDir']);
+    var fileWatcher = new FileWatcher(config);
     var handler = jest.genMockFn();
     fileWatcher.on('all', handler);
-    return fileWatcher.getWatchers().then(function(){
+    return fileWatcher.getWatchers().then(function() {
       cb(1, 2, 3, 4);
       jest.runAllTimers();
       expect(handler.mock.calls[0]).toEqual([1, 2, 3, 4]);
@@ -57,7 +66,7 @@ describe('FileWatcher', function() {
   });
 
   pit('it should end the watcher', function() {
-    var fileWatcher = new FileWatcher(['rootDir']);
+    var fileWatcher = new FileWatcher(config);
     Watcher.prototype.close.mockImplementation(function(callback) {
       callback();
     });
diff --git a/packager/react-packager/src/FileWatcher/index.js b/packager/react-packager/src/DependencyResolver/FileWatcher/index.js
similarity index 94%
rename from packager/react-packager/src/FileWatcher/index.js
rename to packager/react-packager/src/DependencyResolver/FileWatcher/index.js
index e32c36963ae5..227687e1c820 100644
--- a/packager/react-packager/src/FileWatcher/index.js
+++ b/packager/react-packager/src/DependencyResolver/FileWatcher/index.js
@@ -12,11 +12,10 @@ const EventEmitter  = require('events').EventEmitter;
 const sane = require('sane');
 const Promise = require('promise');
 const exec = require('child_process').exec;
-const _ = require('underscore');
 
 const MAX_WAIT_TIME = 25000;
 
-// TODO(amasad): can we use watchman version command instead?r
+// TODO(amasad): can we use watchman version command instead?
 const detectingWatcherClass = new Promise(function(resolve) {
   exec('which watchman', function(err, out) {
     if (err || out.length === 0) {
@@ -81,13 +80,10 @@ class FileWatcher extends EventEmitter {
   }
 
   static createDummyWatcher() {
-    const ev = new EventEmitter();
-    _.extend(ev, {
+    return Object.assign(new EventEmitter(), {
       isWatchman: () => Promise.resolve(false),
       end: () => Promise.resolve(),
     });
-
-    return ev;
   }
 }
 
diff --git a/packager/react-packager/src/Server/__tests__/Server-test.js b/packager/react-packager/src/Server/__tests__/Server-test.js
index b8fee5fad049..2fdb5e73845d 100644
--- a/packager/react-packager/src/Server/__tests__/Server-test.js
+++ b/packager/react-packager/src/Server/__tests__/Server-test.js
@@ -19,7 +19,7 @@ jest.setMock('worker-farm', function() { return () => {}; })
 const Promise = require('promise');
 
 var Bundler = require('../../Bundler');
-var FileWatcher = require('../../FileWatcher');
+var FileWatcher = require('../../DependencyResolver/FileWatcher');
 var Server = require('../');
 var Server = require('../../Server');
 var AssetServer = require('../../AssetServer');
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index b2ca6d73b66d..121dcddb87ed 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -10,7 +10,7 @@
 
 const Activity = require('../Activity');
 const AssetServer = require('../AssetServer');
-const FileWatcher = require('../FileWatcher');
+const FileWatcher = require('../DependencyResolver/FileWatcher');
 const getPlatformExtension = require('../DependencyResolver/lib/getPlatformExtension');
 const Bundler = require('../Bundler');
 const Promise = require('promise');

From dbc35b69fa0256920b3b3608c84b6ff844bca4b4 Mon Sep 17 00:00:00 2001
From: Andrei Coman <andreic@fb.com>
Date: Mon, 14 Dec 2015 12:04:38 -0800
Subject: [PATCH 0365/1411] Make it possible to set DB size

Reviewed By: oli

Differential Revision: D2749219

fb-gh-sync-id: 2165ed8a89c48687ad82cd1facf2b875d31ca997
---
 .../modules/storage/ReactDatabaseSupplier.java    | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/storage/ReactDatabaseSupplier.java b/ReactAndroid/src/main/java/com/facebook/react/modules/storage/ReactDatabaseSupplier.java
index 620d231461d9..87f9daf5c147 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/storage/ReactDatabaseSupplier.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/storage/ReactDatabaseSupplier.java
@@ -30,7 +30,6 @@ public class ReactDatabaseSupplier extends SQLiteOpenHelper {
 
   private static final int DATABASE_VERSION = 1;
   private static final int SLEEP_TIME_MS = 30;
-  private static final long DEFAULT_MAX_DB_SIZE = 6L * 1024L * 1024L; // 6 MB in bytes
 
   static final String TABLE_CATALYST = "catalystLocalStorage";
   static final String KEY_COLUMN = "key";
@@ -46,6 +45,7 @@ public class ReactDatabaseSupplier extends SQLiteOpenHelper {
 
   private Context mContext;
   private @Nullable SQLiteDatabase mDb;
+  private long mMaximumDatabaseSize =  6L * 1024L * 1024L; // 6 MB in bytes
 
   private ReactDatabaseSupplier(Context context) {
     super(context, DATABASE_NAME, null, DATABASE_VERSION);
@@ -105,7 +105,7 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
     // This is a sane limit to protect the user from the app storing too much data in the database.
     // This also protects the database from filling up the disk cache and becoming malformed
     // (endTransaction() calls will throw an exception, not rollback, and leave the db malformed).
-    mDb.setMaximumSize(DEFAULT_MAX_DB_SIZE);
+    mDb.setMaximumSize(mMaximumDatabaseSize);
     return true;
   }
 
@@ -137,6 +137,17 @@ public synchronized void clearAndCloseDatabase() throws RuntimeException {
     get().delete(TABLE_CATALYST, null, null);
   }
 
+  /**
+   * Sets the maximum size the database will grow to. The maximum size cannot
+   * be set below the current size.
+   */
+  public synchronized void setMaximumSize(long size) {
+    mMaximumDatabaseSize = size;
+    if (mDb != null) {
+      mDb.setMaximumSize(mMaximumDatabaseSize);
+    }
+  }
+
   private synchronized boolean deleteDatabase() {
     closeDatabase();
     return mContext.deleteDatabase(DATABASE_NAME);

From 7028206b973fc4b5019d6819c74e458b42749b3f Mon Sep 17 00:00:00 2001
From: James Ide <ide@jameside.com>
Date: Mon, 14 Dec 2015 12:28:34 -0800
Subject: [PATCH 0366/1411] Keep the original console as
 `global.originalConsole`

Summary:
If a console exists, keep the original as `global.originalConsole` before overwriting `global.console` with a polyfill. This matches what we do for XHR, fetch, and some other libraries.
Closes https://github.com/facebook/react-native/pull/3322

Reviewed By: svcscm

Differential Revision: D2755873

Pulled By: androidtrunkagent

fb-gh-sync-id: 4c23f807b73b79cfa9fbbd4e2814d76eecabd596
---
 .../src/Resolver/polyfills/console.js         | 21 ++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/packager/react-packager/src/Resolver/polyfills/console.js b/packager/react-packager/src/Resolver/polyfills/console.js
index 5461602b0ed4..6aa485508065 100644
--- a/packager/react-packager/src/Resolver/polyfills/console.js
+++ b/packager/react-packager/src/Resolver/polyfills/console.js
@@ -366,8 +366,6 @@
   };
 
   function setupConsole(global) {
-    var originalConsole = global.console;
-
     if (!global.nativeLoggingHook) {
       return;
     }
@@ -461,7 +459,14 @@
       global.nativeLoggingHook('\n' + table.join('\n'), LOG_LEVELS.info);
     }
 
-    global.console = {
+    // Preserve the original `console` as `originalConsole`
+    var originalConsole = global.console;
+    var descriptor = Object.getOwnPropertyDescriptor(global, 'console');
+    if (descriptor) {
+      Object.defineProperty(global, 'originalConsole', descriptor);
+    }
+
+    var console = {
       error: getNativeLogFunction(LOG_LEVELS.error),
       info: getNativeLogFunction(LOG_LEVELS.info),
       log: getNativeLogFunction(LOG_LEVELS.info),
@@ -469,17 +474,19 @@
       trace: getNativeLogFunction(LOG_LEVELS.trace),
       table: consoleTablePolyfill
     };
+    descriptor.value = console;
+    Object.defineProperty(global, 'console', descriptor);
 
     // If available, also call the original `console` method since that is
     // sometimes useful. Ex: on OS X, this will let you see rich output in
     // the Safari Web Inspector console.
     if (__DEV__ && originalConsole) {
-      Object.keys(global.console).forEach(methodName => {
-        var reactNativeMethod = global.console[methodName];
+      Object.keys(console).forEach(methodName => {
+        var reactNativeMethod = console[methodName];
         if (originalConsole[methodName]) {
-          global.console[methodName] = function() {
+          console[methodName] = function() {
             originalConsole[methodName](...arguments);
-            reactNativeMethod.apply(global.console, arguments);
+            reactNativeMethod.apply(console, arguments);
           };
         }
       });

From acf977a4815a65236e91005b4470a4a24b706c1a Mon Sep 17 00:00:00 2001
From: Jack Hsu <jack.hsu@gmail.com>
Date: Mon, 14 Dec 2015 12:53:22 -0800
Subject: [PATCH 0367/1411] Exposes `setNativeProps` method for
 PullToRefreshViewAndroid

Summary:
Keep `PullToRefreshViewAndroid` consistent with other components that allow optimization through `setNativeProps`.

Also updates the example to make sure it is working.
Closes https://github.com/facebook/react-native/pull/4771

Reviewed By: svcscm

Differential Revision: D2756033

Pulled By: androidtrunkagent

fb-gh-sync-id: a1f483a3809f01bca06a6a09498f9a89fd65f572
---
 Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js b/Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js
index 40842d0a2715..41acc8017db8 100644
--- a/Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js
+++ b/Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js
@@ -57,6 +57,10 @@ var PullToRefreshViewAndroid = React.createClass({
     return this.refs[NATIVE_REF];
   },
 
+  setNativeProps: function(props) {
+    return this.refs[NATIVE_REF].setNativeProps(props);
+  },
+
   render: function() {
     return (
       <NativePullToRefresh

From 230c180a12ecdf7f82ac648305404f0cf7eac77c Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Mon, 14 Dec 2015 13:07:24 -0800
Subject: [PATCH 0368/1411] Add profiler hooks to views

Summary:
public

The profiler currently only hooks into bridge modules, extend it so we also
log method calls on views.

Reviewed By: jspahrsummers

Differential Revision: D2755213

fb-gh-sync-id: e8ff224eec08898340d05e104772ff1626538bd5
---
 React/Profiler/RCTProfile.m | 163 +++++++++++++++++++++++++-----------
 1 file changed, 113 insertions(+), 50 deletions(-)

diff --git a/React/Profiler/RCTProfile.m b/React/Profiler/RCTProfile.m
index cac086c055d1..ab050a286231 100644
--- a/React/Profiler/RCTProfile.m
+++ b/React/Profiler/RCTProfile.m
@@ -20,10 +20,12 @@
 
 #import "RCTAssert.h"
 #import "RCTBridge.h"
+#import "RCTComponentData.h"
 #import "RCTDefines.h"
 #import "RCTLog.h"
 #import "RCTModuleData.h"
 #import "RCTUtils.h"
+#import "RCTUIManager.h"
 
 NSString *const RCTProfileDidStartProfiling = @"RCTProfileDidStartProfiling";
 NSString *const RCTProfileDidEndProfiling = @"RCTProfileDidEndProfiling";
@@ -196,7 +198,12 @@ IMP RCTProfileGetImplementation(id obj, SEL cmd)
 RCT_EXTERN void RCTProfileTrampolineStart(id, SEL);
 void RCTProfileTrampolineStart(id self, SEL cmd)
 {
-  RCT_PROFILE_BEGIN_EVENT(0, [NSString stringWithFormat:@"-[%s %s]", class_getName([self class]), sel_getName(cmd)], nil);
+  /**
+   * This call might be during dealloc, so we shouldn't retain the object in the
+   * block.
+   */
+  Class klass = [self class];
+  RCT_PROFILE_BEGIN_EVENT(0, [NSString stringWithFormat:@"-[%s %s]", class_getName(klass), sel_getName(cmd)], nil);
 }
 
 RCT_EXTERN void RCTProfileTrampolineEnd(void);
@@ -205,6 +212,85 @@ void RCTProfileTrampolineEnd(void)
   RCT_PROFILE_END_EVENT(0, @"objc_call,modules,auto", nil);
 }
 
+static void RCTProfileHookInstance(id instance)
+{
+  Class moduleClass = object_getClass(instance);
+
+  /**
+   * We swizzle the instance -class method to return the original class, but
+   * object_getClass will return the actual class.
+   *
+   * If they are different, it means that the object is returning the original
+   * class, but it's actual class is the proxy subclass we created.
+   */
+  if ([instance class] != moduleClass) {
+    return;
+  }
+
+  Class proxyClass = objc_allocateClassPair(moduleClass, RCTProfileProxyClassName(moduleClass), 0);
+
+  if (!proxyClass) {
+    proxyClass = objc_getClass(RCTProfileProxyClassName(moduleClass));
+    if (proxyClass) {
+      object_setClass(instance, proxyClass);
+    }
+    return;
+  }
+
+  unsigned int methodCount;
+  Method *methods = class_copyMethodList(moduleClass, &methodCount);
+  for (NSUInteger i = 0; i < methodCount; i++) {
+    Method method = methods[i];
+    SEL selector = method_getName(method);
+
+    /**
+     * Bail out on struct returns (except arm64) - we don't use it enough
+     * to justify writing a stret version
+     */
+#ifdef __arm64__
+    BOOL returnsStruct = NO;
+#else
+    const char *typeEncoding = method_getTypeEncoding(method);
+    // bail out on structs and unions (since they might contain structs)
+    BOOL returnsStruct = typeEncoding[0] == '{' || typeEncoding[0] == '(';
+#endif
+
+    /**
+     * Avoid hooking into NSObject methods, methods generated by React Native
+     * and special methods that start `.` (e.g. .cxx_destruct)
+     */
+    if ([NSStringFromSelector(selector) hasPrefix:@"rct"] || [NSObject instancesRespondToSelector:selector] || sel_getName(selector)[0] == '.' || returnsStruct) {
+      continue;
+    }
+
+    const char *types = method_getTypeEncoding(method);
+    class_addMethod(proxyClass, selector, (IMP)RCTProfileTrampoline, types);
+  }
+  free(methods);
+
+  class_replaceMethod(object_getClass(proxyClass), @selector(initialize), imp_implementationWithBlock(^{}), "v@:");
+
+  for (Class cls in @[proxyClass, object_getClass(proxyClass)]) {
+    Method oldImp = class_getInstanceMethod(cls, @selector(class));
+    class_replaceMethod(cls, @selector(class), imp_implementationWithBlock(^{ return moduleClass; }), method_getTypeEncoding(oldImp));
+  }
+
+  objc_registerClassPair(proxyClass);
+  object_setClass(instance, proxyClass);
+}
+
+static UIView *(*originalCreateView)(RCTComponentData *, SEL, NSNumber *, NSDictionary *);
+
+RCT_EXTERN UIView *RCTProfileCreateView(RCTComponentData *self, SEL _cmd, NSNumber *tag, NSDictionary *props);
+UIView *RCTProfileCreateView(RCTComponentData *self, SEL _cmd, NSNumber *tag, NSDictionary *props)
+{
+  UIView *view = originalCreateView(self, _cmd, tag, props);
+
+  RCTProfileHookInstance(view);
+
+  return view;
+}
+
 void RCTProfileHookModules(RCTBridge *bridge)
 {
 #pragma clang diagnostic push
@@ -216,54 +302,28 @@ void RCTProfileHookModules(RCTBridge *bridge)
 
   for (RCTModuleData *moduleData in [bridge valueForKey:@"moduleDataByID"]) {
     [bridge dispatchBlock:^{
-      Class moduleClass = moduleData.moduleClass;
-      Class proxyClass = objc_allocateClassPair(moduleClass, RCTProfileProxyClassName(moduleClass), 0);
-
-      if (!proxyClass) {
-        proxyClass = objc_getClass(RCTProfileProxyClassName(moduleClass));
-        if (proxyClass) {
-          object_setClass(moduleData.instance, proxyClass);
-        }
-        return;
-      }
-
-      unsigned int methodCount;
-      Method *methods = class_copyMethodList(moduleClass, &methodCount);
-      for (NSUInteger i = 0; i < methodCount; i++) {
-        Method method = methods[i];
-        SEL selector = method_getName(method);
-
-        /**
-         * Bail out on struct returns (except arm64) - we don't use it enough
-         * to justify writing a stret version
-         */
-#ifdef __arm64__
-        BOOL returnsStruct = NO;
-#else
-        const char *typeEncoding = method_getTypeEncoding(method);
-        // bail out on structs and unions (since they might contain structs)
-        BOOL returnsStruct = typeEncoding[0] == '{' || typeEncoding[0] == '(';
-#endif
-
-        if ([NSStringFromSelector(selector) hasPrefix:@"rct"] || [NSObject instancesRespondToSelector:selector] || returnsStruct) {
-          continue;
-        }
-        const char *types = method_getTypeEncoding(method);
+      RCTProfileHookInstance(moduleData.instance);
+    } queue:moduleData.methodQueue];
+  }
 
-        class_addMethod(proxyClass, selector, (IMP)RCTProfileTrampoline, types);
-      }
-      free(methods);
+  dispatch_async(dispatch_get_main_queue(), ^{
+    for (id view in [bridge.uiManager valueForKey:@"viewRegistry"]) {
+      RCTProfileHookInstance([bridge.uiManager viewForReactTag:view]);
+    }
 
-      class_replaceMethod(object_getClass(proxyClass), @selector(initialize), imp_implementationWithBlock(^{}), "v@:");
+    Method createView = class_getInstanceMethod([RCTComponentData class], @selector(createViewWithTag:props:));
 
-      for (Class cls in @[proxyClass, object_getClass(proxyClass)]) {
-        Method oldImp = class_getInstanceMethod(cls, @selector(class));
-        class_replaceMethod(cls, @selector(class), imp_implementationWithBlock(^{ return moduleClass; }), method_getTypeEncoding(oldImp));
-      }
+    if (method_getImplementation(createView) != (IMP)RCTProfileCreateView) {
+      originalCreateView = (typeof(originalCreateView))method_getImplementation(createView);
+      method_setImplementation(createView, (IMP)RCTProfileCreateView);
+    }
+  });
+}
 
-      objc_registerClassPair(proxyClass);
-      object_setClass(moduleData.instance, proxyClass);
-    } queue:moduleData.methodQueue];
+static void RCTProfileUnhookInstance(id instance)
+{
+  if ([instance class] != object_getClass(instance)) {
+    object_setClass(instance, [instance class]);
   }
 }
 
@@ -272,13 +332,16 @@ void RCTProfileUnhookModules(RCTBridge *bridge)
   dispatch_group_enter(RCTProfileGetUnhookGroup());
 
   for (RCTModuleData *moduleData in [bridge valueForKey:@"moduleDataByID"]) {
-    Class proxyClass = object_getClass(moduleData.instance);
-    if (moduleData.moduleClass != proxyClass) {
-      object_setClass(moduleData.instance, moduleData.moduleClass);
-    }
+    RCTProfileUnhookInstance(moduleData.instance);
   }
 
-  dispatch_group_leave(RCTProfileGetUnhookGroup());
+  dispatch_async(dispatch_get_main_queue(), ^{
+    for (id view in [bridge.uiManager valueForKey:@"viewRegistry"]) {
+      RCTProfileUnhookInstance(view);
+    }
+
+    dispatch_group_leave(RCTProfileGetUnhookGroup());
+  });
 }
 
 #pragma mark - Private ObjC class only used for the vSYNC CADisplayLink target

From e2b035acf2dc55d8410ebcfd47901d4b309f073a Mon Sep 17 00:00:00 2001
From: Nader Dabit <dabit3@gmail.com>
Date: Mon, 14 Dec 2015 15:10:46 -0600
Subject: [PATCH 0369/1411] fixed documentation error for native modules docs
 page

---
 docs/NativeModulesIOS.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/NativeModulesIOS.md b/docs/NativeModulesIOS.md
index ce1bf2e8660e..41266aad7b34 100644
--- a/docs/NativeModulesIOS.md
+++ b/docs/NativeModulesIOS.md
@@ -374,7 +374,7 @@ Then create a private implementation file that will register the required inform
 
 @interface RCT_EXTERN_MODULE(CalendarManager, NSObject)
 
-RCT_EXTERN_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(NSNumber *)date)
+RCT_EXTERN_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(nonnull NSNumber *)date)
 
 @end
 ```

From 328bb5907681df5544fa6f69b9a4145ed7e42e76 Mon Sep 17 00:00:00 2001
From: Baris Sencan <baris.sncn@gmail.com>
Date: Mon, 14 Dec 2015 14:11:35 -0800
Subject: [PATCH 0370/1411] [Showcase] Add `Movie Trailers by MovieLaLa`

---
 website/src/react-native/showcase.js | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index fdd7a73a34a5..a7019bb7323c 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -284,6 +284,13 @@ var apps = [
     link: 'https://itunes.apple.com/cn/app/mockingbot/id1050565468?l=en&mt=8',
     author: 'YuanYi Zhang (@mockingbot)',
   },
+  {
+    name: 'Movie Trailers by MovieLaLa',
+    icon: 'https://lh3.googleusercontent.com/16aug4m_6tvJB7QZden9w1SOMqpZgNp7rHqDhltZNvofw1a4V_ojGGXUMPGiK0dDCqzL=w300',
+    linkAppStore: 'https://itunes.apple.com/us/app/movie-trailers-by-movielala/id1001416601?mt=8',
+    linkPlayStore: 'https://play.google.com/store/apps/details?id=com.movielala.trailers',
+    author: 'MovieLaLa'
+  },
   {
     name: 'Mr. Dapper',
     icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple4/v4/e8/3f/7c/e83f7cb3-2602-f8e8-de9a-ce0a775a4a14/mzl.hmdjhfai.png',

From 7af12a1c5c6dd50bfe9e5149a734687c16d7f347 Mon Sep 17 00:00:00 2001
From: Brent Vatne <brentvatne@gmail.com>
Date: Mon, 14 Dec 2015 17:19:33 -0800
Subject: [PATCH 0371/1411] [Showcase] Promote MovieLaLa to featured

---
 website/src/react-native/showcase.js | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index a7019bb7323c..7b57b35f4e7c 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -63,6 +63,13 @@ var featured = [
     link: 'https://itunes.apple.com/us/app/lrn-learn-to-code-at-your/id1019622677',
     author: 'Lrn Labs, Inc',
   },
+  {
+    name: 'Movie Trailers by MovieLaLa',
+    icon: 'https://lh3.googleusercontent.com/16aug4m_6tvJB7QZden9w1SOMqpZgNp7rHqDhltZNvofw1a4V_ojGGXUMPGiK0dDCqzL=w300',
+    linkAppStore: 'https://itunes.apple.com/us/app/movie-trailers-by-movielala/id1001416601?mt=8',
+    linkPlayStore: 'https://play.google.com/store/apps/details?id=com.movielala.trailers',
+    author: 'MovieLaLa'
+  },
   {
     name: 'Myntra',
     icon: 'http://a5.mzstatic.com/us/r30/Purple6/v4/9c/78/df/9c78dfa6-0061-1af2-5026-3e1d5a073c94/icon350x350.png',
@@ -284,13 +291,6 @@ var apps = [
     link: 'https://itunes.apple.com/cn/app/mockingbot/id1050565468?l=en&mt=8',
     author: 'YuanYi Zhang (@mockingbot)',
   },
-  {
-    name: 'Movie Trailers by MovieLaLa',
-    icon: 'https://lh3.googleusercontent.com/16aug4m_6tvJB7QZden9w1SOMqpZgNp7rHqDhltZNvofw1a4V_ojGGXUMPGiK0dDCqzL=w300',
-    linkAppStore: 'https://itunes.apple.com/us/app/movie-trailers-by-movielala/id1001416601?mt=8',
-    linkPlayStore: 'https://play.google.com/store/apps/details?id=com.movielala.trailers',
-    author: 'MovieLaLa'
-  },
   {
     name: 'Mr. Dapper',
     icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple4/v4/e8/3f/7c/e83f7cb3-2602-f8e8-de9a-ce0a775a4a14/mzl.hmdjhfai.png',

From 934f4de16ecd06dca0c3fc7784142686f37d0bdc Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Tue, 15 Dec 2015 10:10:20 +0800
Subject: [PATCH 0372/1411] geolocation is now opensourced on android

---
 Libraries/Geolocation/Geolocation.js | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/Libraries/Geolocation/Geolocation.js b/Libraries/Geolocation/Geolocation.js
index 681a5f77b895..82bc1c9a059c 100644
--- a/Libraries/Geolocation/Geolocation.js
+++ b/Libraries/Geolocation/Geolocation.js
@@ -43,9 +43,6 @@ type GeoOptions = {
  *
  * `<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />`
  *
- * Geolocation support for Android is planned but not yet open sourced. See
- * [Known Issues](http://facebook.github.io/react-native/docs/known-issues.html#missing-modules-and-native-views).
- *
  */
 var Geolocation = {
 

From 484fe9155b9653959e0bccd9df76b34155b6679b Mon Sep 17 00:00:00 2001
From: zjlovezj <zjlovezj@gmail.com>
Date: Mon, 14 Dec 2015 18:56:32 -0800
Subject: [PATCH 0373/1411] add backfaceVisibility to ImageStylePropTypes

Summary:
to eliminate to yellow box.
ViewStylePropTypes also has this prop.
https://github.com/facebook/react-native/blob/0a3694ce48be8991839c42aab2586202a12d43aa/Libraries/Components/View/ViewStylePropTypes.js
Closes https://github.com/facebook/react-native/pull/4765

Reviewed By: svcscm

Differential Revision: D2754433

Pulled By: androidtrunkagent

fb-gh-sync-id: 4bb53213aea6f7d629b31e0e4d4a46ae980ff219
---
 Libraries/Image/ImageStylePropTypes.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Libraries/Image/ImageStylePropTypes.js b/Libraries/Image/ImageStylePropTypes.js
index c4ccfb57860a..6974bdc55c2a 100644
--- a/Libraries/Image/ImageStylePropTypes.js
+++ b/Libraries/Image/ImageStylePropTypes.js
@@ -20,6 +20,7 @@ var ImageStylePropTypes = {
   ...LayoutPropTypes,
   ...TransformPropTypes,
   resizeMode: ReactPropTypes.oneOf(Object.keys(ImageResizeMode)),
+  backfaceVisibility: ReactPropTypes.oneOf(['visible', 'hidden']),
   backgroundColor: ReactPropTypes.string,
   borderColor: ReactPropTypes.string,
   borderWidth: ReactPropTypes.number,

From f946d14fcce8f574d47c8db630b46e1cae9e245a Mon Sep 17 00:00:00 2001
From: Huang Yu <huang@bitgo.com>
Date: Mon, 14 Dec 2015 22:46:15 -0800
Subject: [PATCH 0374/1411] clean four MapView lint warnings

Summary:
clean four MapView lint warnings.
Closes https://github.com/facebook/react-native/pull/4778

Reviewed By: svcscm

Differential Revision: D2759161

Pulled By: androidtrunkagent

fb-gh-sync-id: c5b028d0400c5084436d636d3bf9a0072fa09571
---
 Libraries/Components/MapView/MapView.js | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/Libraries/Components/MapView/MapView.js b/Libraries/Components/MapView/MapView.js
index 012f5790f75a..b62b122df40f 100644
--- a/Libraries/Components/MapView/MapView.js
+++ b/Libraries/Components/MapView/MapView.js
@@ -18,12 +18,8 @@ var Platform = require('Platform');
 var RCTMap = require('UIManager').RCTMap;
 var RCTMapConstants = RCTMap && RCTMap.Constants;
 var React = require('React');
-var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
 var View = require('View');
 
-var deepDiffer = require('deepDiffer');
-var insetsDiffer = require('insetsDiffer');
-var merge = require('merge');
 var processColor = require('processColor');
 var resolveAssetSource = require('resolveAssetSource');
 var requireNativeComponent = require('requireNativeComponent');

From 0fe50055c45c9dd0afb22214fb88f2f341fff665 Mon Sep 17 00:00:00 2001
From: Milen Dzhumerov <mgd@fb.com>
Date: Tue, 15 Dec 2015 03:11:30 -0800
Subject: [PATCH 0375/1411] Introduce JSC profiler API

Summary:
Extract JSC profiler API which can now be used even if profiler is unavailable.

public

Reviewed By: tadeuzagallo

Differential Revision: D2749217

fb-gh-sync-id: 1ffa6f37323ea0ddbda3fdacfdf8a9b360185b2e
---
 React/Executors/RCTContextExecutor.m |  65 ++-----------
 React/Profiler/RCTJSCProfiler.h      |  22 +++++
 React/Profiler/RCTJSCProfiler.m      | 137 +++++++++++++++++++++++++++
 3 files changed, 168 insertions(+), 56 deletions(-)
 create mode 100644 React/Profiler/RCTJSCProfiler.h
 create mode 100644 React/Profiler/RCTJSCProfiler.m

diff --git a/React/Executors/RCTContextExecutor.m b/React/Executors/RCTContextExecutor.m
index 2205a8d4846d..b0fa841346aa 100644
--- a/React/Executors/RCTContextExecutor.m
+++ b/React/Executors/RCTContextExecutor.m
@@ -21,25 +21,10 @@
 #import "RCTProfile.h"
 #import "RCTPerformanceLogger.h"
 #import "RCTUtils.h"
-
-#ifndef RCT_JSC_PROFILER
-#if RCT_DEV
-#define RCT_JSC_PROFILER 1
-#else
-#define RCT_JSC_PROFILER 0
-#endif
-#endif
-
-#if RCT_JSC_PROFILER
-#include <dlfcn.h>
+#import "RCTJSCProfiler.h"
 
 static NSString *const RCTJSCProfilerEnabledDefaultsKey = @"RCTJSCProfilerEnabled";
 
-#ifndef RCT_JSC_PROFILER_DYLIB
-#define RCT_JSC_PROFILER_DYLIB [[[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"RCTJSCProfiler.ios%zd", [[[UIDevice currentDevice] systemVersion] integerValue]] ofType:@"dylib" inDirectory:@"RCTJSCProfiler"] UTF8String]
-#endif
-#endif
-
 @interface RCTJavaScriptContext : NSObject <RCTInvalidating>
 
 @property (nonatomic, strong, readonly) JSContext *context;
@@ -219,51 +204,19 @@ static JSValueRef RCTNativeTraceEndSection(JSContextRef context, __unused JSObje
 
 static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
 {
-#if RCT_JSC_PROFILER
-  void *JSCProfiler = dlopen(RCT_JSC_PROFILER_DYLIB, RTLD_NOW);
-  if (JSCProfiler != NULL) {
-    void (*nativeProfilerStart)(JSContextRef, const char *) =
-      (__typeof__(nativeProfilerStart))dlsym(JSCProfiler, "nativeProfilerStart");
-    void (*nativeProfilerEnd)(JSContextRef, const char *, const char *) =
-      (__typeof__(nativeProfilerEnd))dlsym(JSCProfiler, "nativeProfilerEnd");
-
-    if (nativeProfilerStart != NULL && nativeProfilerEnd != NULL) {
-      void (*nativeProfilerEnableBytecode)(void) =
-        (__typeof__(nativeProfilerEnableBytecode))dlsym(JSCProfiler, "nativeProfilerEnableBytecode");
-
-      if (nativeProfilerEnableBytecode != NULL) {
-        nativeProfilerEnableBytecode();
-      }
-
-      static BOOL isProfiling = NO;
-
-      if (isProfiling) {
-        nativeProfilerStart(context, "profile");
-      }
-
-      [bridge.devMenu addItem:[RCTDevMenuItem toggleItemWithKey:RCTJSCProfilerEnabledDefaultsKey title:@"Start Profiling" selectedTitle:@"Stop Profiling" handler:^(BOOL shouldStart) {
-
-        if (shouldStart == isProfiling) {
-          return;
-        }
-
-        isProfiling = shouldStart;
-
+  if (RCTJSCProfilerIsSupported()) {
+    [bridge.devMenu addItem:[RCTDevMenuItem toggleItemWithKey:RCTJSCProfilerEnabledDefaultsKey title:@"Start Profiling" selectedTitle:@"Stop Profiling" handler:^(BOOL shouldStart) {
+      if (shouldStart != RCTJSCProfilerIsProfiling(context)) {
         if (shouldStart) {
-          nativeProfilerStart(context, "profile");
+          RCTJSCProfilerStart(context);
         } else {
-          NSString *outputFile = [NSTemporaryDirectory() stringByAppendingPathComponent:@"cpu_profile.json"];
-          nativeProfilerEnd(context, "profile", outputFile.UTF8String);
-          NSData *profileData = [NSData dataWithContentsOfFile:outputFile
-                                                       options:NSDataReadingMappedIfSafe
-                                                         error:NULL];
-
+          NSString *outputFile = RCTJSCProfilerStop(context);
+          NSData *profileData = [NSData dataWithContentsOfFile:outputFile options:NSDataReadingMappedIfSafe error:NULL];
           RCTProfileSendResult(bridge, @"cpu-profile", profileData);
         }
-      }]];
-    }
+      }
+    }]];
   }
-#endif
 }
 
 #endif
diff --git a/React/Profiler/RCTJSCProfiler.h b/React/Profiler/RCTJSCProfiler.h
new file mode 100644
index 000000000000..5f8e23b178c2
--- /dev/null
+++ b/React/Profiler/RCTJSCProfiler.h
@@ -0,0 +1,22 @@
+/**
+ * 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.
+ */
+
+#import <JavaScriptCore/JavaScriptCore.h>
+
+#import "RCTDefines.h"
+
+/** The API is not thread-safe. */
+
+/** The context is not retained. */
+RCT_EXTERN void RCTJSCProfilerStart(JSContextRef ctx);
+/** Returns a file path containing the profiler data. */
+RCT_EXTERN NSString *RCTJSCProfilerStop(JSContextRef ctx);
+
+RCT_EXTERN BOOL RCTJSCProfilerIsProfiling(JSContextRef ctx);
+RCT_EXTERN BOOL RCTJSCProfilerIsSupported(void);
diff --git a/React/Profiler/RCTJSCProfiler.m b/React/Profiler/RCTJSCProfiler.m
new file mode 100644
index 000000000000..f808c1c5f432
--- /dev/null
+++ b/React/Profiler/RCTJSCProfiler.m
@@ -0,0 +1,137 @@
+/**
+ * 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.
+ */
+
+#import "RCTJSCProfiler.h"
+#import "RCTLog.h"
+#import <UIKit/UIKit.h>
+
+#ifndef RCT_JSC_PROFILER
+  #if RCT_DEV
+    #define RCT_JSC_PROFILER 1
+  #else
+    #define RCT_JSC_PROFILER 0
+  #endif
+#endif
+
+#if RCT_JSC_PROFILER
+
+#include <dlfcn.h>
+
+#ifndef RCT_JSC_PROFILER_DYLIB
+  #define RCT_JSC_PROFILER_DYLIB [[[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"RCTJSCProfiler.ios%zd", [[[UIDevice currentDevice] systemVersion] integerValue]] ofType:@"dylib" inDirectory:@"RCTJSCProfiler"] UTF8String]
+#endif
+
+static const char *const JSCProfileName = "profile";
+
+typedef void (*JSCProfilerStartFunctionType)(JSContextRef, const char *);
+typedef void (*JSCProfilerEndFunctionType)(JSContextRef, const char *, const char *);
+typedef void (*JSCProfilerEnableFunctionType)(void);
+
+static NSMutableDictionary<NSValue *, NSNumber *> *RCTJSCProfilerStateMap;
+
+static JSCProfilerStartFunctionType RCTNativeProfilerStart  = NULL;
+static JSCProfilerEndFunctionType RCTNativeProfilerEnd    = NULL;
+
+NS_INLINE NSValue *RCTJSContextRefKey(JSContextRef ref) {
+  return [NSValue valueWithPointer:ref];
+}
+
+static void RCTJSCProfilerStateInit()
+{
+  static dispatch_once_t onceToken;
+  dispatch_once(&onceToken, ^{
+    RCTJSCProfilerStateMap = [NSMutableDictionary new];
+
+    void *JSCProfiler = dlopen(RCT_JSC_PROFILER_DYLIB, RTLD_NOW);
+
+    RCTNativeProfilerStart = (JSCProfilerStartFunctionType)dlsym(JSCProfiler, "nativeProfilerStart");
+    RCTNativeProfilerEnd =  (JSCProfilerEndFunctionType)dlsym(JSCProfiler, "nativeProfilerEnd");
+    JSCProfilerEnableFunctionType enableBytecode = (__typeof__(enableBytecode))dlsym(JSCProfiler, "nativeProfilerEnableBytecode");
+
+    if (RCTNativeProfilerStart && RCTNativeProfilerEnd && enableBytecode) {
+      enableBytecode();
+      RCTLogInfo(@"JSC profiler is available.");
+    } else {
+      RCTNativeProfilerStart = NULL;
+      RCTNativeProfilerEnd = NULL;
+      RCTLogInfo(@"JSC profiler is not supported.");
+    }
+  });
+}
+
+#endif
+
+void RCTJSCProfilerStart(JSContextRef ctx)
+{
+#if RCT_JSC_PROFILER
+  if (ctx != NULL) {
+    if (RCTJSCProfilerIsSupported()) {
+      NSValue *key = RCTJSContextRefKey(ctx);
+      BOOL isProfiling = [RCTJSCProfilerStateMap[key] boolValue];
+      if (!isProfiling) {
+        RCTLogInfo(@"Starting JSC profiler for context: %p", ctx);
+        RCTJSCProfilerStateMap[key] = @YES;
+        RCTNativeProfilerStart(ctx, JSCProfileName);
+      } else {
+        RCTLogWarn(@"Trying to start JSC profiler on a context which is already profiled.");
+      }
+    } else {
+      RCTLogWarn(@"Cannot start JSC profiler as it's not supported.");
+    }
+  } else {
+    RCTLogWarn(@"Trying to start JSC profiler for NULL context.");
+  }
+#endif
+}
+
+NSString *RCTJSCProfilerStop(JSContextRef ctx)
+{
+  NSString *outputFile = nil;
+#if RCT_JSC_PROFILER
+  if (ctx != NULL) {
+    RCTJSCProfilerStateInit();
+    NSValue *key = RCTJSContextRefKey(ctx);
+    BOOL isProfiling = [RCTJSCProfilerStateMap[key] boolValue];
+    if (isProfiling) {
+      NSString *filename = [NSString stringWithFormat:@"cpu_profile_%ld.json", (long)CFAbsoluteTimeGetCurrent()];
+      outputFile = [NSTemporaryDirectory() stringByAppendingPathComponent:filename];
+      RCTNativeProfilerEnd(ctx, JSCProfileName, outputFile.UTF8String);
+      RCTLogInfo(@"Stopped JSC profiler for context: %p", ctx);
+    } else {
+      RCTLogWarn(@"Trying to stop JSC profiler on a context which is not being profiled.");
+    }
+    [RCTJSCProfilerStateMap removeObjectForKey:key];
+  } else {
+    RCTLogWarn(@"Trying to stop JSC profiler for NULL context.");
+  }
+#endif
+  return outputFile;
+}
+
+BOOL RCTJSCProfilerIsProfiling(JSContextRef ctx)
+{
+  BOOL isProfiling = NO;
+#if RCT_JSC_PROFILER
+  if (ctx != NULL) {
+    RCTJSCProfilerStateInit();
+    isProfiling = [RCTJSCProfilerStateMap[RCTJSContextRefKey(ctx)] boolValue];
+  }
+#endif
+  return isProfiling;
+}
+
+BOOL RCTJSCProfilerIsSupported(void)
+{
+  BOOL isSupported = NO;
+#if RCT_JSC_PROFILER
+  RCTJSCProfilerStateInit();
+  isSupported = (RCTNativeProfilerStart != NULL);
+#endif
+  return isSupported;
+}

From 2ac0157a24e2a5d77ac9d432ef1f7e51bf9d4167 Mon Sep 17 00:00:00 2001
From: Milen Dzhumerov <mgd@fb.com>
Date: Tue, 15 Dec 2015 03:57:26 -0800
Subject: [PATCH 0376/1411] Improve error message when profiler data cannot be
 uploaded

Summary:
Improve error message when profiling data cannot be sent to the packager

public

Reviewed By: tadeuzagallo

Differential Revision: D2749489

fb-gh-sync-id: 26bd56d05be5f3579e45c2407974dd2b885460fc
---
 React/Profiler/RCTProfile.m | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/React/Profiler/RCTProfile.m b/React/Profiler/RCTProfile.m
index ab050a286231..a51b099c2592 100644
--- a/React/Profiler/RCTProfile.m
+++ b/React/Profiler/RCTProfile.m
@@ -669,7 +669,7 @@ void _RCTProfileEndFlowEvent(NSNumber *flowID)
 void RCTProfileSendResult(RCTBridge *bridge, NSString *route, NSData *data)
 {
   if (![bridge.bundleURL.scheme hasPrefix:@"http"]) {
-    RCTLogError(@"Cannot upload profile information");
+    RCTLogWarn(@"Cannot upload profile information because you're not connected to the packager. The profiling data is still saved in the app container.");
     return;
   }
 

From c46936a00df96800fb19ec0823a339a1c13c4a09 Mon Sep 17 00:00:00 2001
From: Martin Kralik <kralik@fb.com>
Date: Tue, 15 Dec 2015 04:48:45 -0800
Subject: [PATCH 0377/1411] updated css-layout and fixed callsites

Reviewed By: foghina

Differential Revision: D2757965

fb-gh-sync-id: 061ff38ae59783edb36ff66516866e4a22fd6e25
---
 .../java/com/facebook/csslayout/CSSNode.java  | 10 ++--
 .../facebook/csslayout/CachedCSSLayout.java   |  3 +-
 .../com/facebook/csslayout/LayoutEngine.java  | 60 +++++++++++++++----
 .../main/java/com/facebook/csslayout/README   |  2 +-
 .../com/facebook/csslayout/README.facebook    |  2 +-
 .../progressbar/ProgressBarShadowNode.java    |  2 +-
 .../views/switchview/ReactSwitchManager.java  |  2 +-
 .../react/views/text/ReactTextShadowNode.java |  2 +-
 .../textinput/ReactTextInputShadowNode.java   |  2 +-
 9 files changed, 62 insertions(+), 23 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/csslayout/CSSNode.java b/ReactAndroid/src/main/java/com/facebook/csslayout/CSSNode.java
index a5519e129af8..46827fb92fdd 100644
--- a/ReactAndroid/src/main/java/com/facebook/csslayout/CSSNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/csslayout/CSSNode.java
@@ -7,7 +7,7 @@
  */
 
 // NOTE: this file is auto-copied from https://github.com/facebook/css-layout
-// @generated SignedSource<<4b95f0548441afa1e91e957a93fa6f0b>>
+// @generated SignedSource<<1f520d46cbfddbbea0661a8fb6a00748>>
 
 package com.facebook.csslayout;
 
@@ -56,7 +56,7 @@ public static interface MeasureFunction {
      *
      * NB: measure is NOT guaranteed to be threadsafe/re-entrant safe!
      */
-    public void measure(CSSNode node, float width, MeasureOutput measureOutput);
+    public void measure(CSSNode node, float width, float height, MeasureOutput measureOutput);
   }
 
   // VisibleForTesting
@@ -128,13 +128,13 @@ public boolean isMeasureDefined() {
     return mMeasureFunction != null;
   }
 
-  /*package*/ MeasureOutput measure(MeasureOutput measureOutput, float width) {
+  /*package*/ MeasureOutput measure(MeasureOutput measureOutput, float width, float height) {
     if (!isMeasureDefined()) {
       throw new RuntimeException("Measure function isn't defined!");
     }
     measureOutput.height = CSSConstants.UNDEFINED;
     measureOutput.width = CSSConstants.UNDEFINED;
-    Assertions.assertNotNull(mMeasureFunction).measure(this, width, measureOutput);
+    Assertions.assertNotNull(mMeasureFunction).measure(this, width, height, measureOutput);
     return measureOutput;
   }
 
@@ -143,7 +143,7 @@ public boolean isMeasureDefined() {
    */
   public void calculateLayout(CSSLayoutContext layoutContext) {
     layout.resetResult();
-    LayoutEngine.layoutNode(layoutContext, this, CSSConstants.UNDEFINED, null);
+    LayoutEngine.layoutNode(layoutContext, this, CSSConstants.UNDEFINED, CSSConstants.UNDEFINED, null);
   }
 
   /**
diff --git a/ReactAndroid/src/main/java/com/facebook/csslayout/CachedCSSLayout.java b/ReactAndroid/src/main/java/com/facebook/csslayout/CachedCSSLayout.java
index 97ef4886f360..6d631d37c945 100644
--- a/ReactAndroid/src/main/java/com/facebook/csslayout/CachedCSSLayout.java
+++ b/ReactAndroid/src/main/java/com/facebook/csslayout/CachedCSSLayout.java
@@ -7,7 +7,7 @@
  */
 
 // NOTE: this file is auto-copied from https://github.com/facebook/css-layout
-// @generated SignedSource<<8276834951a75286a0b6d4a980bc43ce>>
+// @generated SignedSource<<e2f8139d4c50e4d2a9281a4587f8c095>>
 
 package com.facebook.csslayout;
 
@@ -21,4 +21,5 @@ public class CachedCSSLayout extends CSSLayout {
   public float requestedWidth = CSSConstants.UNDEFINED;
   public float requestedHeight = CSSConstants.UNDEFINED;
   public float parentMaxWidth = CSSConstants.UNDEFINED;
+  public float parentMaxHeight = CSSConstants.UNDEFINED;
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/csslayout/LayoutEngine.java b/ReactAndroid/src/main/java/com/facebook/csslayout/LayoutEngine.java
index 30e14f052f61..711aed2ab2d5 100644
--- a/ReactAndroid/src/main/java/com/facebook/csslayout/LayoutEngine.java
+++ b/ReactAndroid/src/main/java/com/facebook/csslayout/LayoutEngine.java
@@ -7,7 +7,7 @@
  */
 
 // NOTE: this file is auto-copied from https://github.com/facebook/css-layout
-// @generated SignedSource<<c4feb337df98136c86629cf72c93f049>>
+// @generated SignedSource<<df03fd95c4520badeed398c76e70242d>>
 
 package com.facebook.csslayout;
 
@@ -19,7 +19,7 @@
 import static com.facebook.csslayout.CSSLayout.POSITION_TOP;
 
 /**
- * Calculates layouts based on CSS style. See {@link #layoutNode(CSSNode, float)}.
+ * Calculates layouts based on CSS style. See {@link #layoutNode(CSSNode, float, float)}.
  */
 public class LayoutEngine {
 
@@ -109,7 +109,7 @@ private static void setDimensionFromStyle(CSSNode node, int axis) {
       return;
     }
     // We only run if there's a width or height defined
-    if (Float.isNaN(node.style.dimensions[dim[axis]]) || 
+    if (Float.isNaN(node.style.dimensions[dim[axis]]) ||
         node.style.dimensions[dim[axis]] <= 0.0) {
       return;
     }
@@ -183,7 +183,7 @@ private static boolean isMeasureDefined(CSSNode node) {
     return node.isMeasureDefined();
   }
 
-  static boolean needsRelayout(CSSNode node, float parentMaxWidth) {
+  static boolean needsRelayout(CSSNode node, float parentMaxWidth, float parentMaxHeight) {
     return node.isDirty() ||
         !FloatUtil.floatsEqual(
             node.lastLayout.requestedHeight,
@@ -191,20 +191,23 @@ static boolean needsRelayout(CSSNode node, float parentMaxWidth) {
         !FloatUtil.floatsEqual(
             node.lastLayout.requestedWidth,
             node.layout.dimensions[DIMENSION_WIDTH]) ||
-        !FloatUtil.floatsEqual(node.lastLayout.parentMaxWidth, parentMaxWidth);
+        !FloatUtil.floatsEqual(node.lastLayout.parentMaxWidth, parentMaxWidth) ||
+        !FloatUtil.floatsEqual(node.lastLayout.parentMaxHeight, parentMaxHeight);
   }
 
   /*package*/ static void layoutNode(
       CSSLayoutContext layoutContext,
       CSSNode node,
       float parentMaxWidth,
+      float parentMaxHeight,
       CSSDirection parentDirection) {
-    if (needsRelayout(node, parentMaxWidth)) {
+    if (needsRelayout(node, parentMaxWidth, parentMaxHeight)) {
       node.lastLayout.requestedWidth = node.layout.dimensions[DIMENSION_WIDTH];
       node.lastLayout.requestedHeight = node.layout.dimensions[DIMENSION_HEIGHT];
       node.lastLayout.parentMaxWidth = parentMaxWidth;
+      node.lastLayout.parentMaxHeight = parentMaxHeight;
 
-      layoutNodeImpl(layoutContext, node, parentMaxWidth, parentDirection);
+      layoutNodeImpl(layoutContext, node, parentMaxWidth, parentMaxHeight, parentDirection);
       node.lastLayout.copy(node.layout);
     } else {
       node.layout.copy(node.lastLayout);
@@ -217,6 +220,7 @@ private static void layoutNodeImpl(
       CSSLayoutContext layoutContext,
       CSSNode node,
       float parentMaxWidth,
+      float parentMaxHeight,
       CSSDirection parentDirection) {
     for (int i = 0, childCount = node.getChildCount(); i < childCount; i++) {
       node.getChildAt(i).layout.resetResult();
@@ -251,6 +255,7 @@ private static void layoutNodeImpl(
     // invocations during the layout calculation.
     int childCount = node.getChildCount();
     float paddingAndBorderAxisResolvedRow = ((node.style.padding.getWithFallback(leadingSpacing[resolvedRowAxis], leading[resolvedRowAxis]) + node.style.border.getWithFallback(leadingSpacing[resolvedRowAxis], leading[resolvedRowAxis])) + (node.style.padding.getWithFallback(trailingSpacing[resolvedRowAxis], trailing[resolvedRowAxis]) + node.style.border.getWithFallback(trailingSpacing[resolvedRowAxis], trailing[resolvedRowAxis])));
+    float paddingAndBorderAxisColumn = ((node.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN])) + (node.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN])));
   
     if (isMeasureDefined(node)) {
       boolean isResolvedRowDimDefined = !Float.isNaN(node.layout.dimensions[dim[resolvedRowAxis]]);
@@ -266,6 +271,17 @@ private static void layoutNodeImpl(
       }
       width -= paddingAndBorderAxisResolvedRow;
   
+      float height = CSSConstants.UNDEFINED;
+      if ((!Float.isNaN(node.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]) && node.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
+        height = node.style.dimensions[DIMENSION_HEIGHT];
+      } else if (!Float.isNaN(node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]])) {
+        height = node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]];
+      } else {
+        height = parentMaxHeight -
+          (node.style.margin.getWithFallback(leadingSpacing[resolvedRowAxis], leading[resolvedRowAxis]) + node.style.margin.getWithFallback(trailingSpacing[resolvedRowAxis], trailing[resolvedRowAxis]));
+      }
+      height -= ((node.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN])) + (node.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN])));
+  
       // We only need to give a dimension for the text if we haven't got any
       // for it computed yet. It can either be from the style attribute or because
       // the element is flexible.
@@ -278,7 +294,8 @@ private static void layoutNodeImpl(
         MeasureOutput measureDim = node.measure(
           
           layoutContext.measureOutput,
-          width
+          width,
+          height
         );
         if (isRowUndefined) {
           node.layout.dimensions[DIMENSION_WIDTH] = measureDim.width +
@@ -286,7 +303,7 @@ private static void layoutNodeImpl(
         }
         if (isColumnUndefined) {
           node.layout.dimensions[DIMENSION_HEIGHT] = measureDim.height +
-            ((node.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN])) + (node.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN])));
+            paddingAndBorderAxisColumn;
         }
       }
       if (childCount == 0) {
@@ -367,6 +384,7 @@ private static void layoutNodeImpl(
       float crossDim = 0;
   
       float maxWidth;
+      float maxHeight;
       for (i = startLine; i < childCount; ++i) {
         child = node.getChildAt(i);
         child.lineIndex = linesCount;
@@ -447,6 +465,8 @@ private static void layoutNodeImpl(
   
         } else {
           maxWidth = CSSConstants.UNDEFINED;
+          maxHeight = CSSConstants.UNDEFINED;
+  
           if (!isMainRowDirection) {
             if ((!Float.isNaN(node.style.dimensions[dim[resolvedRowAxis]]) && node.style.dimensions[dim[resolvedRowAxis]] >= 0.0)) {
               maxWidth = node.layout.dimensions[dim[resolvedRowAxis]] -
@@ -456,11 +476,20 @@ private static void layoutNodeImpl(
                 (node.style.margin.getWithFallback(leadingSpacing[resolvedRowAxis], leading[resolvedRowAxis]) + node.style.margin.getWithFallback(trailingSpacing[resolvedRowAxis], trailing[resolvedRowAxis])) -
                 paddingAndBorderAxisResolvedRow;
             }
+          } else {
+            if ((!Float.isNaN(node.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]) && node.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
+              maxHeight = node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] -
+                  paddingAndBorderAxisColumn;
+            } else {
+              maxHeight = parentMaxHeight -
+                (node.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + node.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN])) -
+                paddingAndBorderAxisColumn;
+            }
           }
   
           // This is the main recursive call. We layout non flexible children.
           if (alreadyComputedNextLayout == 0) {
-            layoutNode(layoutContext, child, maxWidth, direction);
+            layoutNode(layoutContext, child, maxWidth, maxHeight, direction);
           }
   
           // Absolute positioned elements do not take part of the layout, so we
@@ -590,9 +619,18 @@ private static void layoutNodeImpl(
               (node.style.margin.getWithFallback(leadingSpacing[resolvedRowAxis], leading[resolvedRowAxis]) + node.style.margin.getWithFallback(trailingSpacing[resolvedRowAxis], trailing[resolvedRowAxis])) -
               paddingAndBorderAxisResolvedRow;
           }
+          maxHeight = CSSConstants.UNDEFINED;
+          if ((!Float.isNaN(node.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]) && node.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
+            maxHeight = node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] -
+              paddingAndBorderAxisColumn;
+          } else if (isMainRowDirection) {
+            maxHeight = parentMaxHeight -
+              (node.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + node.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN])) -
+              paddingAndBorderAxisColumn;
+          }
   
           // And we recursively call the layout algorithm for this child
-          layoutNode(layoutContext, currentFlexChild, maxWidth, direction);
+          layoutNode(layoutContext, currentFlexChild, maxWidth, maxHeight, direction);
   
           child = currentFlexChild;
           currentFlexChild = currentFlexChild.nextFlexChild;
diff --git a/ReactAndroid/src/main/java/com/facebook/csslayout/README b/ReactAndroid/src/main/java/com/facebook/csslayout/README
index 4916c22183a1..955473ba0b55 100644
--- a/ReactAndroid/src/main/java/com/facebook/csslayout/README
+++ b/ReactAndroid/src/main/java/com/facebook/csslayout/README
@@ -1,7 +1,7 @@
 The source of truth for css-layout is: https://github.com/facebook/css-layout
 
 The code here should be kept in sync with GitHub.
-HEAD at the time this code was synced: https://github.com/facebook/css-layout/commit/d3b702e1ad0925f8683ce3039be8e493abbf179b
+HEAD at the time this code was synced: https://github.com/facebook/css-layout/commit/219bdaed15c16bbf7c1f2bab17ad629d04cc4199
 
 There is generated code in:
  - README (this file)
diff --git a/ReactAndroid/src/main/java/com/facebook/csslayout/README.facebook b/ReactAndroid/src/main/java/com/facebook/csslayout/README.facebook
index b7b2a9e90972..8d78b2695779 100644
--- a/ReactAndroid/src/main/java/com/facebook/csslayout/README.facebook
+++ b/ReactAndroid/src/main/java/com/facebook/csslayout/README.facebook
@@ -1,7 +1,7 @@
 The source of truth for css-layout is: https://github.com/facebook/css-layout
 
 The code here should be kept in sync with GitHub.
-HEAD at the time this code was synced: https://github.com/facebook/css-layout/commit/d3b702e1ad0925f8683ce3039be8e493abbf179b
+HEAD at the time this code was synced: https://github.com/facebook/css-layout/commit/219bdaed15c16bbf7c1f2bab17ad629d04cc4199
 
 There is generated code in:
  - README.facebook (this file)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java
index dc49c4aa1327..28309d79b9b9 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java
@@ -51,7 +51,7 @@ public void setStyle(@Nullable String style) {
   }
 
   @Override
-  public void measure(CSSNode node, float width, MeasureOutput measureOutput) {
+  public void measure(CSSNode node, float width, float height, MeasureOutput measureOutput) {
     final int style = ReactProgressBarViewManager.getStyleFromString(getStyle());
     if (!mMeasured.contains(style)) {
       ProgressBar progressBar = new ProgressBar(getThemedContext(), null, style);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java
index 115cc9621cc6..60b71f0eb7ba 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java
@@ -45,7 +45,7 @@ private ReactSwitchShadowNode() {
     }
 
     @Override
-    public void measure(CSSNode node, float width, MeasureOutput measureOutput) {
+    public void measure(CSSNode node, float width, float height, MeasureOutput measureOutput) {
       if (!mMeasured) {
         // Create a switch with the default config and measure it; since we don't (currently)
         // support setting custom switch text, this is fine, as all switches will measure the same
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java
index 1e4286f78751..e6e19ad8cbf7 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java
@@ -194,7 +194,7 @@ protected static final Spannable fromTextCSSNode(ReactTextShadowNode textCSSNode
   private static final CSSNode.MeasureFunction TEXT_MEASURE_FUNCTION =
       new CSSNode.MeasureFunction() {
         @Override
-        public void measure(CSSNode node, float width, MeasureOutput measureOutput) {
+        public void measure(CSSNode node, float width, float height, MeasureOutput measureOutput) {
           // TODO(5578671): Handle text direction (see View#getTextDirectionHeuristic)
           ReactTextShadowNode reactCSSNode = (ReactTextShadowNode) node;
           TextPaint textPaint = sTextPaintInstance;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java
index 47b3f48fdba3..2a37f82f1e4d 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java
@@ -68,7 +68,7 @@ protected void setThemedContext(ThemedReactContext themedContext) {
   }
 
   @Override
-  public void measure(CSSNode node, float width, MeasureOutput measureOutput) {
+  public void measure(CSSNode node, float width, float height, MeasureOutput measureOutput) {
     // measure() should never be called before setThemedContext()
     EditText editText = Assertions.assertNotNull(mEditText);
 

From 03a0e4ee2ba144f121f6185d953df642ef103777 Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Tue, 15 Dec 2015 05:32:24 -0800
Subject: [PATCH 0378/1411] Use JSC block API

Summary:
public

Clean up the `RCTContextExecutor` a little bit by converting the exposed hooks to use the ObjC API.

Reviewed By: nicklockwood

Differential Revision: D2757363

fb-gh-sync-id: c6f5f53c5c1adb78af1cdb449268b6b3cc9740e8
---
 React/Executors/RCTContextExecutor.m | 121 +++++++--------------------
 1 file changed, 31 insertions(+), 90 deletions(-)

diff --git a/React/Executors/RCTContextExecutor.m b/React/Executors/RCTContextExecutor.m
index b0fa841346aa..0d2d181def9d 100644
--- a/React/Executors/RCTContextExecutor.m
+++ b/React/Executors/RCTContextExecutor.m
@@ -102,38 +102,6 @@ @implementation RCTContextExecutor
 
 RCT_EXPORT_MODULE()
 
-/**
- * The one tiny pure native hook that we implement is a native logging hook.
- * You could even argue that this is not necessary - we could plumb logging
- * calls through a batched bridge, but having the pure native hook allows
- * logging to successfully come through even in the event that a batched bridge
- * crashes.
- */
-
-static JSValueRef RCTNativeLoggingHook(JSContextRef context, __unused JSObjectRef object, __unused JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception)
-{
-  if (argumentCount > 0) {
-    NSString *message = RCTJSValueToNSString(context, arguments[0], exception);
-
-    RCTLogLevel level = RCTLogLevelInfo;
-    if (argumentCount > 1) {
-      level = MAX(level, JSValueToNumber(context, arguments[1], exception));
-    }
-
-    _RCTLogJavaScriptInternal(level, message);
-  }
-
-  return JSValueMakeUndefined(context);
-}
-
-// Do-very-little native hook for testing.
-static JSValueRef RCTNoop(JSContextRef context, __unused JSObjectRef object, __unused JSObjectRef thisObject, __unused size_t argumentCount, __unused const JSValueRef arguments[], __unused JSValueRef *exception)
-{
-  static int counter = 0;
-  counter++;
-  return JSValueMakeUndefined(context);
-}
-
 static NSString *RCTJSValueToNSString(JSContextRef context, JSValueRef value, JSValueRef *exception)
 {
   JSStringRef JSString = JSValueToStringCopy(context, value, exception);
@@ -165,43 +133,6 @@ static JSValueRef RCTNoop(JSContextRef context, __unused JSObjectRef object, __u
 
 #if RCT_DEV
 
-static JSValueRef RCTNativeTraceBeginSection(JSContextRef context, __unused JSObjectRef object, __unused JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception)
-{
-  static int profileCounter = 1;
-  NSString *profileName;
-  double tag = 0;
-
-  if (argumentCount > 0) {
-    if (JSValueIsNumber(context, arguments[0])) {
-      tag = JSValueToNumber(context, arguments[0], NULL);
-    } else {
-      profileName = RCTJSValueToNSString(context, arguments[0], exception);
-    }
-  } else {
-    profileName = [NSString stringWithFormat:@"Profile %d", profileCounter++];
-  }
-
-  if (argumentCount > 1 && JSValueIsString(context, arguments[1])) {
-    profileName = RCTJSValueToNSString(context, arguments[1], exception);
-  }
-
-  if (profileName) {
-    RCT_PROFILE_BEGIN_EVENT(tag, profileName, nil);
-  }
-
-  return JSValueMakeUndefined(context);
-}
-
-static JSValueRef RCTNativeTraceEndSection(JSContextRef context, __unused JSObjectRef object, __unused JSObjectRef thisObject, __unused size_t argumentCount, __unused const JSValueRef arguments[], JSValueRef *exception)
-{
-  if (argumentCount > 0) {
-    double tag = JSValueToNumber(context, arguments[0], exception);
-    RCT_PROFILE_END_EVENT((uint64_t)tag, @"console", nil);
-  }
-
-  return JSValueMakeUndefined(context);
-}
-
 static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
 {
   if (RCTJSCProfilerIsSupported()) {
@@ -298,16 +229,27 @@ - (void)setUp
     if (!strongSelf.isValid) {
       return;
     }
+
     if (!strongSelf->_context) {
       JSContext *context = [JSContext new];
       strongSelf->_context = [[RCTJavaScriptContext alloc] initWithJSContext:context];
     }
-    [strongSelf _addNativeHook:RCTNativeLoggingHook withName:"nativeLoggingHook"];
-    [strongSelf _addNativeHook:RCTNoop withName:"noop"];
 
     __weak RCTBridge *weakBridge = strongSelf->_bridge;
+    JSContext *context = strongSelf->_context.context;
+
+    context[@"noop"] = ^{};
+
+    context[@"nativeLoggingHook"] = ^(NSString *message, NSNumber *logLevel) {
+      RCTLogLevel level = RCTLogLevelInfo;
+      if (logLevel) {
+        level = MAX(level, logLevel.integerValue);
+      }
+
+      _RCTLogJavaScriptInternal(level, message);
+    };
 
-    strongSelf->_context.context[@"nativeRequireModuleConfig"] = ^NSString *(NSString *moduleName) {
+    context[@"nativeRequireModuleConfig"] = ^NSString *(NSString *moduleName) {
       if (!weakSelf.valid) {
         return nil;
       }
@@ -318,39 +260,47 @@ - (void)setUp
       return nil;
     };
 
-    strongSelf->_context.context[@"nativeFlushQueueImmediate"] = ^(NSArray<NSArray *> *calls){
+    context[@"nativeFlushQueueImmediate"] = ^(NSArray<NSArray *> *calls){
       if (!weakSelf.valid || !calls) {
         return;
       }
       [weakBridge handleBuffer:calls batchEnded:NO];
     };
 
-    strongSelf->_context.context[@"RCTPerformanceNow"] = ^{
+    context[@"RCTPerformanceNow"] = ^{
       return CACurrentMediaTime() * 1000 * 1000;
     };
 
 #if RCT_DEV
 
     if (RCTProfileIsProfiling()) {
-      strongSelf->_context.context[@"__RCTProfileIsProfiling"] = @YES;
+      context[@"__RCTProfileIsProfiling"] = @YES;
     }
 
     CFMutableDictionaryRef cookieMap = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
-    strongSelf->_context.context[@"nativeTraceBeginAsyncSection"] = ^(uint64_t tag, NSString *name, NSUInteger cookie) {
+    context[@"nativeTraceBeginAsyncSection"] = ^(uint64_t tag, NSString *name, NSUInteger cookie) {
       NSUInteger newCookie = RCTProfileBeginAsyncEvent(tag, name, nil);
       CFDictionarySetValue(cookieMap, (const void *)cookie, (const void *)newCookie);
-      return;
     };
 
-    strongSelf->_context.context[@"nativeTraceEndAsyncSection"] = ^(uint64_t tag, NSString *name, NSUInteger cookie) {
+    context[@"nativeTraceEndAsyncSection"] = ^(uint64_t tag, NSString *name, NSUInteger cookie) {
       NSUInteger newCookie = (NSUInteger)CFDictionaryGetValue(cookieMap, (const void *)cookie);
       RCTProfileEndAsyncEvent(tag, @"js,async", newCookie, name, nil);
       CFDictionaryRemoveValue(cookieMap, (const void *)cookie);
-      return;
     };
 
-    [strongSelf _addNativeHook:RCTNativeTraceBeginSection withName:"nativeTraceBeginSection"];
-    [strongSelf _addNativeHook:RCTNativeTraceEndSection withName:"nativeTraceEndSection"];
+    context[@"nativeTraceBeginSection"] = ^(NSNumber *tag, NSString *profileName){
+      static int profileCounter = 1;
+      if (!profileName) {
+        profileName = [NSString stringWithFormat:@"Profile %d", profileCounter++];
+      }
+
+      RCT_PROFILE_BEGIN_EVENT(tag.longLongValue, profileName, nil);
+    };
+
+    context[@"nativeTraceEndSection"] = ^(NSNumber *tag) {
+      RCT_PROFILE_END_EVENT(tag.longLongValue, @"console", nil);
+    };
 
     RCTInstallJSCProfiler(_bridge, strongSelf->_context.ctx);
 
@@ -374,15 +324,6 @@ - (void)toggleProfilingFlag:(NSNotification *)notification
   }];
 }
 
-- (void)_addNativeHook:(JSObjectCallAsFunctionCallback)hook withName:(const char *)name
-{
-  JSObjectRef globalObject = JSContextGetGlobalObject(_context.ctx);
-
-  JSStringRef JSName = JSStringCreateWithUTF8CString(name);
-  JSObjectSetProperty(_context.ctx, globalObject, JSName, JSObjectMakeFunctionWithCallback(_context.ctx, JSName, hook), kJSPropertyAttributeNone, NULL);
-  JSStringRelease(JSName);
-}
-
 - (void)invalidate
 {
   if (!self.isValid) {

From 2d61dfd9c1d40998be3375842c5fd9b3d186fe70 Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Tue, 15 Dec 2015 05:39:30 -0800
Subject: [PATCH 0379/1411] Replace private bridge categories with private
 header

Summary:
public

A lot of the core modules have to use private methods in the bridge, specially
since the `RCTBatchedBridge` interface is never exposed. That was leading to a
lot of different private bridge categories spread across different modules,
which makes harder to identify which modules are affected by private API changes.

Replace all the categories with a single private header.

Reviewed By: nicklockwood

Differential Revision: D2757564

fb-gh-sync-id: 793158b9082d542b74a6094ed0db4d5dc3a88f78
---
 .../UIExplorerUnitTests/RCTAllocationTests.m  |  7 +-
 .../UIExplorerUnitTests/RCTBridgeTests.m      | 10 +--
 React/Base/RCTBatchedBridge.m                 | 10 +--
 React/Base/RCTBridge+Private.h                | 88 +++++++++++++++++++
 React/Base/RCTBridge.m                        | 31 +------
 React/Base/RCTLog.m                           |  8 +-
 React/Base/RCTModuleData.m                    |  7 +-
 React/Base/RCTModuleMethod.m                  | 11 +--
 React/Base/RCTRootView.m                      |  8 +-
 React/Executors/RCTContextExecutor.m          |  9 +-
 React/Modules/RCTDevMenu.m                    |  9 +-
 React/Modules/RCTTiming.m                     | 10 +--
 React/Profiler/RCTProfile.m                   |  8 +-
 React/React.xcodeproj/project.pbxproj         |  2 +
 14 files changed, 103 insertions(+), 115 deletions(-)
 create mode 100644 React/Base/RCTBridge+Private.h

diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m
index 239973ca03e8..b90a384e4a76 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m
@@ -16,6 +16,7 @@
 #import <XCTest/XCTest.h>
 
 #import "RCTBridge.h"
+#import "RCTBridge+Private.h"
 #import "RCTContextExecutor.h"
 #import "RCTModuleMethod.h"
 #import "RCTRootView.h"
@@ -29,12 +30,6 @@
 } \
 _Pragma("clang diagnostic pop")
 
-@interface RCTBridge (RCTAllocationTests)
-
-@property (nonatomic, weak) RCTBridge *batchedBridge;
-
-@end
-
 @interface RCTJavaScriptContext : NSObject
 
 @property (nonatomic, assign, readonly) JSGlobalContextRef ctx;
diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m
index 54a58787e108..1a0afe0bfa49 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m
@@ -16,19 +16,11 @@
 #import <XCTest/XCTest.h>
 
 #import "RCTBridge.h"
+#import "RCTBridge+Private.h"
 #import "RCTBridgeModule.h"
 #import "RCTJavaScriptExecutor.h"
 #import "RCTUtils.h"
 
-@interface RCTBridge (Testing)
-
-@property (nonatomic, strong, readonly) RCTBridge *batchedBridge;
-
-- (void)handleBuffer:(id)buffer;
-- (void)setUp;
-
-@end
-
 @interface TestExecutor : NSObject <RCTJavaScriptExecutor>
 
 @property (nonatomic, readonly, copy) NSMutableDictionary<NSString *, id> *injectedStuff;
diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index 1999f32b026b..21d35a6e1606 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -11,6 +11,7 @@
 
 #import "RCTAssert.h"
 #import "RCTBridge.h"
+#import "RCTBridge+Private.h"
 #import "RCTBridgeMethod.h"
 #import "RCTConvert.h"
 #import "RCTContextExecutor.h"
@@ -42,15 +43,6 @@ typedef NS_ENUM(NSUInteger, RCTBridgeFields) {
 
 RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
 
-@interface RCTBridge ()
-
-+ (instancetype)currentBridge;
-+ (void)setCurrentBridge:(RCTBridge *)bridge;
-
-@property (nonatomic, copy, readonly) RCTBridgeModuleProviderBlock moduleProvider;
-
-@end
-
 @interface RCTBatchedBridge : RCTBridge
 
 @property (nonatomic, weak) RCTBridge *parentBridge;
diff --git a/React/Base/RCTBridge+Private.h b/React/Base/RCTBridge+Private.h
new file mode 100644
index 000000000000..bb87cc173f58
--- /dev/null
+++ b/React/Base/RCTBridge+Private.h
@@ -0,0 +1,88 @@
+/**
+ * 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.
+ */
+
+#import "RCTBridge.h"
+
+@class RCTModuleData;
+
+@interface RCTBridge ()
+
++ (instancetype)currentBridge;
++ (void)setCurrentBridge:(RCTBridge *)bridge;
+
+/**
+ * Bridge setup code - creates an instance of RCTBachedBridge. Exposed for
+ * test only
+ */
+- (void)setUp;
+
+/**
+ * This method is used to invoke a callback that was registered in the
+ * JavaScript application context. Safe to call from any thread.
+ */
+- (void)enqueueCallback:(NSNumber *)cbID args:(NSArray *)args;
+
+/**
+ * This property is mostly used on the main thread, but may be touched from
+ * a background thread if the RCTBridge happens to deallocate on a background
+ * thread. Therefore, we want all writes to it to be seen atomically.
+ */
+@property (atomic, strong) RCTBridge *batchedBridge;
+
+/**
+ * The block that creates the modules' instances to be added to the bridge.
+ * Exposed for the RCTBatchedBridge
+ */
+@property (nonatomic, copy, readonly) RCTBridgeModuleProviderBlock moduleProvider;
+
+@end
+
+@interface RCTBridge (RCTBatchedBridge)
+
+- (void)registerModuleForFrameUpdates:(RCTModuleData *)moduleData;
+
+/**
+ * Dispatch work to a module's queue - this is also suports the fake RCTJSThread
+ * queue. Exposed for the RCTProfiler
+ */
+- (void)dispatchBlock:(dispatch_block_t)block queue:(dispatch_queue_t)queue;
+
+/**
+ * Systrace profiler toggling methods exposed for the RCTDevMenu
+ */
+- (void)startProfiling;
+- (void)stopProfiling:(void (^)(NSData *))callback;
+
+/**
+ * Executes native calls sent by JavaScript. Exposed for testing purposes only
+ */
+- (void)handleBuffer:(NSArray<NSArray *> *)buffer;
+
+/**
+ * Exposed for the RCTContextExecutor for sending native methods called from
+ * JavaScript in the middle of a batch.
+ */
+- (void)handleBuffer:(NSArray<NSArray *> *)buffer batchEnded:(BOOL)hasEnded;
+
+/**
+ * Exposed for the RCTContextExecutor for lazily loading native modules
+ */
+- (NSArray *)configForModuleName:(NSString *)moduleName;
+
+/**
+ * Hook exposed for RCTLog to send logs to JavaScript when not running in JSC
+ */
+- (void)logMessage:(NSString *)message level:(NSString *)level;
+
+/**
+ * Allow super fast, one time, timers to skip the queue and be directly executed
+ */
+- (void)_immediatelyCallTimer:(NSNumber *)timer;
+
+@end
diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m
index c0b89be0a22c..1dfac45b339b 100644
--- a/React/Base/RCTBridge.m
+++ b/React/Base/RCTBridge.m
@@ -7,7 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  */
 
-#import "RCTBridge.h"
+#import "RCTBridge+Private.h"
 
 #import <objc/runtime.h>
 
@@ -24,8 +24,6 @@
 NSString *const RCTJavaScriptDidFailToLoadNotification = @"RCTJavaScriptDidFailToLoadNotification";
 NSString *const RCTDidCreateNativeModules = @"RCTDidCreateNativeModules";
 
-@class RCTBatchedBridge;
-
 @interface RCTBatchedBridge : RCTBridge <RCTInvalidating>
 
 @property (nonatomic, weak) RCTBridge *parentBridge;
@@ -34,17 +32,6 @@ - (instancetype)initWithParentBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZ
 
 @end
 
-@interface RCTBridge ()
-
-// This property is mostly used on the main thread, but may be touched from
-// a background thread if the RCTBridge happens to deallocate on a background
-// thread. Therefore, we want all writes to it to be seen atomically.
-@property (atomic, strong) RCTBatchedBridge *batchedBridge;
-
-@property (nonatomic, copy, readonly) RCTBridgeModuleProviderBlock moduleProvider;
-
-@end
-
 static NSMutableArray<Class> *RCTModuleClasses;
 NSArray<Class> *RCTGetModuleClasses(void);
 NSArray<Class> *RCTGetModuleClasses(void)
@@ -294,7 +281,7 @@ - (BOOL)isBatchActive
 
 - (void)invalidate
 {
-  RCTBatchedBridge *batchedBridge = self.batchedBridge;
+  RCTBatchedBridge *batchedBridge = (RCTBatchedBridge *)self.batchedBridge;
   self.batchedBridge = nil;
 
   if (batchedBridge) {
@@ -304,20 +291,6 @@ - (void)invalidate
   }
 }
 
-- (void)logMessage:(NSString *)message level:(NSString *)level
-{
-  [self.batchedBridge logMessage:message level:level];
-}
-
-
-#define RCT_INNER_BRIDGE_ONLY(...) \
-- (void)__VA_ARGS__ \
-{ \
-  NSString *errorMessage = [NSString stringWithFormat:@"Called method \"%@\" on top level bridge. \
-    This method should oly be called from bridge instance in a bridge module", @(__func__)]; \
-  RCTFatal(RCTErrorWithMessage(errorMessage)); \
-}
-
 - (void)enqueueJSCall:(NSString *)moduleDotMethod args:(NSArray *)args
 {
   [self.batchedBridge enqueueJSCall:moduleDotMethod args:args];
diff --git a/React/Base/RCTLog.m b/React/Base/RCTLog.m
index f09aff78b93f..28562bde23d6 100644
--- a/React/Base/RCTLog.m
+++ b/React/Base/RCTLog.m
@@ -13,16 +13,10 @@
 
 #import "RCTAssert.h"
 #import "RCTBridge.h"
+#import "RCTBridge+Private.h"
 #import "RCTDefines.h"
 #import "RCTRedBox.h"
 
-@interface RCTBridge ()
-
-+ (RCTBridge *)currentBridge;
-- (void)logMessage:(NSString *)message level:(NSString *)level;
-
-@end
-
 static NSString *const RCTLogFunctionStack = @"RCTLogFunctionStack";
 
 const char *RCTLogLevels[] = {
diff --git a/React/Base/RCTModuleData.m b/React/Base/RCTModuleData.m
index d254509a765b..d247f532f3e3 100644
--- a/React/Base/RCTModuleData.m
+++ b/React/Base/RCTModuleData.m
@@ -10,16 +10,11 @@
 #import "RCTModuleData.h"
 
 #import "RCTBridge.h"
+#import "RCTBridge+Private.h"
 #import "RCTModuleMethod.h"
 #import "RCTLog.h"
 #import "RCTUtils.h"
 
-@interface RCTBridge (Private)
-
-- (void)registerModuleForFrameUpdates:(RCTModuleData *)moduleData;
-
-@end
-
 @implementation RCTModuleData
 {
   NSString *_queueName;
diff --git a/React/Base/RCTModuleMethod.m b/React/Base/RCTModuleMethod.m
index 407fed3dab80..8f54f2d9e44a 100644
--- a/React/Base/RCTModuleMethod.m
+++ b/React/Base/RCTModuleMethod.m
@@ -13,6 +13,7 @@
 
 #import "RCTAssert.h"
 #import "RCTBridge.h"
+#import "RCTBridge+Private.h"
 #import "RCTConvert.h"
 #import "RCTLog.h"
 #import "RCTParserUtils.h"
@@ -36,16 +37,6 @@ - (instancetype)initWithType:(NSString *)type
 
 @end
 
-@interface RCTBridge (RCTModuleMethod)
-
-/**
- * This method is used to invoke a callback that was registered in the
- * JavaScript application context. Safe to call from any thread.
- */
-- (void)enqueueCallback:(NSNumber *)cbID args:(NSArray *)args;
-
-@end
-
 @implementation RCTModuleMethod
 {
   Class _moduleClass;
diff --git a/React/Base/RCTRootView.m b/React/Base/RCTRootView.m
index 454e2e317768..f53c278b30b3 100644
--- a/React/Base/RCTRootView.m
+++ b/React/Base/RCTRootView.m
@@ -14,7 +14,7 @@
 #import <objc/runtime.h>
 
 #import "RCTAssert.h"
-#import "RCTBridge.h"
+#import "RCTBridge+Private.h"
 #import "RCTEventDispatcher.h"
 #import "RCTKeyCommands.h"
 #import "RCTLog.h"
@@ -28,12 +28,6 @@
 
 NSString *const RCTContentDidAppearNotification = @"RCTContentDidAppearNotification";
 
-@interface RCTBridge (RCTRootView)
-
-@property (nonatomic, weak, readonly) RCTBridge *batchedBridge;
-
-@end
-
 @interface RCTUIManager (RCTRootView)
 
 - (NSNumber *)allocateRootTag;
diff --git a/React/Executors/RCTContextExecutor.m b/React/Executors/RCTContextExecutor.m
index 0d2d181def9d..5d8504fb24bc 100644
--- a/React/Executors/RCTContextExecutor.m
+++ b/React/Executors/RCTContextExecutor.m
@@ -15,6 +15,7 @@
 #import <UIKit/UIDevice.h>
 
 #import "RCTAssert.h"
+#import "RCTBridge+Private.h"
 #import "RCTDefines.h"
 #import "RCTDevMenu.h"
 #import "RCTLog.h"
@@ -83,14 +84,6 @@ - (void)dealloc
 
 @end
 
-// Private bridge interface
-@interface RCTBridge (RCTContextExecutor)
-
-- (void)handleBuffer:(NSArray<NSArray *> *)buffer batchEnded:(BOOL)hasEnded;
-- (NSArray *)configForModuleName:(NSString *)moduleName;
-
-@end
-
 @implementation RCTContextExecutor
 {
   RCTJavaScriptContext *_context;
diff --git a/React/Modules/RCTDevMenu.m b/React/Modules/RCTDevMenu.m
index dd66c900b2cd..5d98f8ad4b01 100644
--- a/React/Modules/RCTDevMenu.m
+++ b/React/Modules/RCTDevMenu.m
@@ -10,7 +10,7 @@
 #import "RCTDevMenu.h"
 
 #import "RCTAssert.h"
-#import "RCTBridge.h"
+#import "RCTBridge+Private.h"
 #import "RCTDefines.h"
 #import "RCTEventDispatcher.h"
 #import "RCTKeyCommands.h"
@@ -22,13 +22,6 @@
 
 #if RCT_DEV
 
-@interface RCTBridge (Profiling)
-
-- (void)startProfiling;
-- (void)stopProfiling:(void (^)(NSData *))callback;
-
-@end
-
 static NSString *const RCTShowDevMenuNotification = @"RCTShowDevMenuNotification";
 static NSString *const RCTDevMenuSettingsKey = @"RCTDevMenu";
 
diff --git a/React/Modules/RCTTiming.m b/React/Modules/RCTTiming.m
index fc2d9e716d4e..3aa084d3073f 100644
--- a/React/Modules/RCTTiming.m
+++ b/React/Modules/RCTTiming.m
@@ -11,18 +11,10 @@
 
 #import "RCTAssert.h"
 #import "RCTBridge.h"
+#import "RCTBridge+Private.h"
 #import "RCTLog.h"
 #import "RCTUtils.h"
 
-@interface RCTBridge (Private)
-
-/**
- * Allow super fast, one time, timers to skip the queue and be directly executed
- */
-- (void)_immediatelyCallTimer:(NSNumber *)timer;
-
-@end
-
 @interface RCTTimer : NSObject
 
 @property (nonatomic, strong, readonly) NSDate *target;
diff --git a/React/Profiler/RCTProfile.m b/React/Profiler/RCTProfile.m
index a51b099c2592..9cc0ae1d9b29 100644
--- a/React/Profiler/RCTProfile.m
+++ b/React/Profiler/RCTProfile.m
@@ -20,6 +20,7 @@
 
 #import "RCTAssert.h"
 #import "RCTBridge.h"
+#import "RCTBridge+Private.h"
 #import "RCTComponentData.h"
 #import "RCTDefines.h"
 #import "RCTLog.h"
@@ -32,13 +33,6 @@
 
 #if RCT_DEV
 
-@interface RCTBridge ()
-
-- (void)dispatchBlock:(dispatch_block_t)block
-                queue:(dispatch_queue_t)queue;
-
-@end
-
 #pragma mark - Constants
 
 NSString const *RCTProfileTraceEvents = @"traceEvents";
diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj
index c7f7294cc16c..fa4397f54725 100644
--- a/React/React.xcodeproj/project.pbxproj
+++ b/React/React.xcodeproj/project.pbxproj
@@ -221,6 +221,7 @@
 		1450FF831BCFF28A00208362 /* RCTProfileTrampoline-arm64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = "RCTProfileTrampoline-arm64.S"; sourceTree = "<group>"; };
 		1450FF851BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = "RCTProfileTrampoline-x86_64.S"; sourceTree = "<group>"; };
 		1482F9E61B55B927000ADFF3 /* RCTBridgeDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTBridgeDelegate.h; sourceTree = "<group>"; };
+		14A43DB81C1F849600794BC8 /* RCTBridge+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RCTBridge+Private.h"; sourceTree = "<group>"; };
 		14BF717F1C04793D00C97D0C /* RCTProfileTrampoline-i386.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = "RCTProfileTrampoline-i386.S"; sourceTree = "<group>"; };
 		14BF71811C04795500C97D0C /* RCTMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTMacros.h; sourceTree = "<group>"; };
 		14C2CA6F1B3AC63800E6CBB2 /* RCTModuleMethod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTModuleMethod.h; sourceTree = "<group>"; };
@@ -538,6 +539,7 @@
 				83CBBA501A601E3B00E9B192 /* RCTUtils.m */,
 				13BB3D001BECD54500932C10 /* RCTImageSource.h */,
 				13BB3D011BECD54500932C10 /* RCTImageSource.m */,
+				14A43DB81C1F849600794BC8 /* RCTBridge+Private.h */,
 			);
 			path = Base;
 			sourceTree = "<group>";

From f7edcda5d7670ed71c7c7ddc989cbfc539080a52 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Tue, 15 Dec 2015 05:42:45 -0800
Subject: [PATCH 0380/1411] Deprecated RCTDidCreateNativeModules notification

Summary:
public

Thanks to the new lazy initialization system for modules, `RCTDidCreateNativeModules` no longer does what the name implies.

Previously, `RCTDidCreateNativeModules` was fired after all native modules had been initialized. Now, it simply fires each time the bridge is reloaded. Modules are created on demand when they are needed, so most of the assumptions about when `RCTDidCreateNativeModules` will fire are now incorrect.

This diff deprecates `RCTDidCreateNativeModules`, and adds a new notification, `RCTDidInitializeModuleNotification`, which fires each time a module a new module is instantiated.

If you need to access a module at any time you can just call `-[bridge moduleForClass:]` and the module will be instantiated on demand. If you want to access a module *only* after it has already been instantiated, you can use the `RCTDidInitializeModuleNotification` notification.

Reviewed By: tadeuzagallo

Differential Revision: D2755036

fb-gh-sync-id: 25bab6d5eb6fcd35d43125ac45908035eea01487
---
 React/Base/RCTBatchedBridge.m | 48 +++++++++++++++++++++--------------
 React/Base/RCTBridge.h        | 34 ++++++++++++++++++++-----
 React/Base/RCTBridge.m        | 12 +++++----
 React/Base/RCTModuleData.m    |  7 +++++
 React/Modules/RCTUIManager.m  |  4 +--
 React/Profiler/RCTProfile.m   |  4 +--
 6 files changed, 75 insertions(+), 34 deletions(-)

diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index 21d35a6e1606..9aba7f9ff967 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -29,6 +29,9 @@
               [[[NSThread currentThread] name] isEqualToString:@"com.facebook.React.JavaScript"], \
             @"This method must be called on JS thread")
 
+/**
+ * Used by RKAnalyticsCPULogger
+ */
 NSString *const RCTEnqueueNotification = @"RCTEnqueueNotification";
 NSString *const RCTDequeueNotification = @"RCTDequeueNotification";
 
@@ -90,9 +93,9 @@ - (instancetype)initWithParentBridge:(RCTBridge *)bridge
 
     [RCTBridge setCurrentBridge:self];
 
-    [[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptWillStartLoadingNotification
-                                                        object:self
-                                                      userInfo:@{ @"bridge": self }];
+    [[NSNotificationCenter defaultCenter]
+     postNotificationName:RCTJavaScriptWillStartLoadingNotification
+     object:_parentBridge userInfo:@{@"bridge": self}];
 
     [self start];
   }
@@ -208,9 +211,9 @@ - (void)loadSource:(RCTSourceLoadBlock)_onSourceLoad
     // Allow testing without a script
     dispatch_async(dispatch_get_main_queue(), ^{
       [self didFinishLoading];
-      [[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidLoadNotification
-                                                          object:_parentBridge
-                                                        userInfo:@{ @"bridge": self }];
+      [[NSNotificationCenter defaultCenter]
+       postNotificationName:RCTJavaScriptDidLoadNotification
+       object:_parentBridge userInfo:@{@"bridge": self}];
     });
     onSourceLoad(nil, nil);
   }
@@ -331,8 +334,15 @@ - (void)initModules
     }
   }
 
-  [[NSNotificationCenter defaultCenter] postNotificationName:RCTDidCreateNativeModules
-                                                      object:self];
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+  [[NSNotificationCenter defaultCenter]
+   postNotificationName:RCTDidCreateNativeModules
+   object:self userInfo:@{@"bridge": self}];
+
+#pragma clang diagnostic pop
+
   RCTPerformanceLoggerEnd(RCTPLNativeModuleInit);
 }
 
@@ -429,10 +439,9 @@ - (void)executeSourceCode:(NSData *)sourceCode
     // timing issues with RCTRootView
     dispatch_async(dispatch_get_main_queue(), ^{
       [self didFinishLoading];
-
-      [[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidLoadNotification
-                                                          object:_parentBridge
-                                                        userInfo:@{ @"bridge": self }];
+      [[NSNotificationCenter defaultCenter]
+       postNotificationName:RCTJavaScriptDidLoadNotification
+       object:_parentBridge userInfo:@{@"bridge": self}];
     });
   }];
 }
@@ -457,9 +466,10 @@ - (void)stopLoadingWithError:(NSError *)error
 
   _loading = NO;
 
-  [[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidFailToLoadNotification
-                                                      object:_parentBridge
-                                                    userInfo:@{@"bridge": self, @"error": error}];
+  [[NSNotificationCenter defaultCenter]
+   postNotificationName:RCTJavaScriptDidFailToLoadNotification
+   object:_parentBridge userInfo:@{@"bridge": self, @"error": error}];
+
   RCTFatal(error);
 }
 
@@ -715,7 +725,7 @@ - (void)_actuallyInvokeAndProcessModule:(NSString *)module
 {
   RCTAssertJSThread();
 
-  [[NSNotificationCenter defaultCenter] postNotificationName:RCTEnqueueNotification object:nil userInfo:nil];
+  [[NSNotificationCenter defaultCenter] postNotificationName:RCTEnqueueNotification object:self userInfo:nil];
 
   RCTJavaScriptCallback processResponse = ^(id json, NSError *error) {
     if (error) {
@@ -725,7 +735,7 @@ - (void)_actuallyInvokeAndProcessModule:(NSString *)module
     if (!self.isValid) {
       return;
     }
-    [[NSNotificationCenter defaultCenter] postNotificationName:RCTDequeueNotification object:nil userInfo:nil];
+    [[NSNotificationCenter defaultCenter] postNotificationName:RCTDequeueNotification object:self userInfo:nil];
     [self handleBuffer:json batchEnded:YES];
   };
 
@@ -740,7 +750,7 @@ - (void)_actuallyInvokeCallback:(NSNumber *)cbID
 {
   RCTAssertJSThread();
 
-  [[NSNotificationCenter defaultCenter] postNotificationName:RCTEnqueueNotification object:nil userInfo:nil];
+  [[NSNotificationCenter defaultCenter] postNotificationName:RCTEnqueueNotification object:self userInfo:nil];
 
   RCTJavaScriptCallback processResponse = ^(id json, NSError *error) {
     if (error) {
@@ -750,7 +760,7 @@ - (void)_actuallyInvokeCallback:(NSNumber *)cbID
     if (!self.isValid) {
       return;
     }
-    [[NSNotificationCenter defaultCenter] postNotificationName:RCTDequeueNotification object:nil userInfo:nil];
+    [[NSNotificationCenter defaultCenter] postNotificationName:RCTDequeueNotification object:self userInfo:nil];
     [self handleBuffer:json batchEnded:YES];
   };
 
diff --git a/React/Base/RCTBridge.h b/React/Base/RCTBridge.h
index f341b75aab7a..a67176e9c72a 100644
--- a/React/Base/RCTBridge.h
+++ b/React/Base/RCTBridge.h
@@ -25,24 +25,28 @@
 RCT_EXTERN NSString *const RCTReloadNotification;
 
 /**
- * This notification fires when the bridge starts loading.
+ * This notification fires when the bridge starts loading the JS bundle.
  */
 RCT_EXTERN NSString *const RCTJavaScriptWillStartLoadingNotification;
 
 /**
- * This notification fires when the bridge has finished loading.
+ * This notification fires when the bridge has finished loading the JS bundle.
  */
 RCT_EXTERN NSString *const RCTJavaScriptDidLoadNotification;
 
 /**
- * This notification fires when the bridge failed to load.
+ * This notification fires when the bridge failed to load the JS bundle. The
+ * `error` key can be used to determine the error that occured.
  */
 RCT_EXTERN NSString *const RCTJavaScriptDidFailToLoadNotification;
 
 /**
- * This notification fires when the bridge created all registered native modules
+ * This notification fires each time a native module is instantiated. The
+ * `module` key will contain a reference to the newly-created module instance.
+ * Note that this notification may be fired before the module is available via
+ * the `[bridge moduleForClass:]` method.
  */
-RCT_EXTERN NSString *const RCTDidCreateNativeModules;
+RCT_EXTERN NSString *const RCTDidInitializeModuleNotification;
 
 /**
  * This block can be used to instantiate modules that require additional
@@ -171,10 +175,28 @@ RCT_EXTERN BOOL RCTBridgeModuleClassIsRegistered(Class);
 @end
 
 /**
- * These properties and methods are deprecated and should not be used
+ * These features are deprecated and should not be used.
  */
 @interface RCTBridge (Deprecated)
 
+/**
+ * This notification used to fire after all native modules has been initialized,
+ * but now that native modules are instantiated lazily on demand, its original
+ * purpose is meaningless.
+ *
+ * If you need to access a module, you can do so as soon as the bridge has been
+ * initialized, by calling `[bridge moduleForClass:]`. If you need to know when
+ * an individual module has been instantiated, use the `RCTDidInitializeModule`
+ * notification instead.
+ */
+RCT_EXTERN NSString *const RCTDidCreateNativeModules
+__deprecated_msg("Use RCTDidInitializeModule to observe init of individual modules");
+
+/**
+ * Accessing the modules property causes all modules to be eagerly initialized,
+ * which stalls the main thread. Use moduleClasses to enumerate through modules
+ * without causing them to be instantiated.
+ */
 @property (nonatomic, copy, readonly) NSDictionary *modules
 __deprecated_msg("Use moduleClasses and/or moduleForName: instead");
 
diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m
index 1dfac45b339b..6ba6b5c36f1a 100644
--- a/React/Base/RCTBridge.m
+++ b/React/Base/RCTBridge.m
@@ -22,7 +22,7 @@
 NSString *const RCTJavaScriptWillStartLoadingNotification = @"RCTJavaScriptWillStartLoadingNotification";
 NSString *const RCTJavaScriptDidLoadNotification = @"RCTJavaScriptDidLoadNotification";
 NSString *const RCTJavaScriptDidFailToLoadNotification = @"RCTJavaScriptDidFailToLoadNotification";
-NSString *const RCTDidCreateNativeModules = @"RCTDidCreateNativeModules";
+NSString *const RCTDidInitializeModuleNotification = @"RCTDidInitializeModuleNotification";
 
 @interface RCTBatchedBridge : RCTBridge <RCTInvalidating>
 
@@ -213,10 +213,10 @@ - (void)bindKeys
   [commands registerKeyCommandWithInput:@"r"
                           modifierFlags:UIKeyModifierCommand
                                  action:^(__unused UIKeyCommand *command) {
-                                    [[NSNotificationCenter defaultCenter] postNotificationName:RCTReloadNotification
-                                                                                        object:nil
-                                                                                      userInfo:nil];
-                                 }];
+    [[NSNotificationCenter defaultCenter] postNotificationName:RCTReloadNotification
+                                                        object:nil
+                                                      userInfo:nil];
+  }];
 
 #endif
 }
@@ -305,6 +305,8 @@ - (void)enqueueCallback:(NSNumber *)cbID args:(NSArray *)args
 
 @implementation RCTBridge(Deprecated)
 
+NSString *const RCTDidCreateNativeModules = @"RCTDidCreateNativeModules";
+
 - (NSDictionary *)modules
 {
   return self.batchedBridge.modules;
diff --git a/React/Base/RCTModuleData.m b/React/Base/RCTModuleData.m
index d247f532f3e3..9b28cd6570c4 100644
--- a/React/Base/RCTModuleData.m
+++ b/React/Base/RCTModuleData.m
@@ -79,6 +79,7 @@ - (void)cacheImplementedSelectors
 
 - (void)setBridgeForInstance:(RCTBridge *)bridge
 {
+  _bridge = bridge;
   if ([_instance respondsToSelector:@selector(bridge)]) {
     @try {
       [(id)_instance setValue:bridge forKey:@"bridge"];
@@ -198,6 +199,12 @@ - (dispatch_queue_t)methodQueue
         }
       }
     }
+
+    // Needs to be sent after bridge has been set for all module instances.
+    // Makes sense to put it here, since the same rules apply for methodQueue.
+    [[NSNotificationCenter defaultCenter]
+     postNotificationName:RCTDidInitializeModuleNotification
+                   object:_bridge userInfo:@{@"module": _instance}];
   }
   return _methodQueue;
 }
diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m
index 46c991e3c3c4..bf1c2ee59fac 100644
--- a/React/Modules/RCTUIManager.m
+++ b/React/Modules/RCTUIManager.m
@@ -347,7 +347,7 @@ - (void)registerRootView:(UIView *)rootView
 
   [[NSNotificationCenter defaultCenter] postNotificationName:RCTUIManagerDidRegisterRootViewNotification
                                                       object:self
-                                                    userInfo:@{ RCTUIManagerRootViewKey: rootView }];
+                                                    userInfo:@{RCTUIManagerRootViewKey: rootView}];
 }
 
 - (UIView *)viewForReactTag:(NSNumber *)reactTag
@@ -695,7 +695,7 @@ - (void)_removeChildren:(NSArray<id<RCTComponent>> *)children
 
     [[NSNotificationCenter defaultCenter] postNotificationName:RCTUIManagerDidRemoveRootViewNotification
                                                         object:uiManager
-                                                      userInfo:@{ RCTUIManagerRootViewKey: rootView }];
+                                                      userInfo:@{RCTUIManagerRootViewKey: rootView}];
   }];
 }
 
diff --git a/React/Profiler/RCTProfile.m b/React/Profiler/RCTProfile.m
index 9cc0ae1d9b29..122dcbe8fad4 100644
--- a/React/Profiler/RCTProfile.m
+++ b/React/Profiler/RCTProfile.m
@@ -403,7 +403,7 @@ void RCTProfileInit(RCTBridge *bridge)
                               forMode:NSRunLoopCommonModes];
 
   [[NSNotificationCenter defaultCenter] postNotificationName:RCTProfileDidStartProfiling
-                                                      object:nil];
+                                                      object:bridge];
 }
 
 void RCTProfileEnd(RCTBridge *bridge, void (^callback)(NSString *))
@@ -417,7 +417,7 @@ void RCTProfileEnd(RCTBridge *bridge, void (^callback)(NSString *))
   OSAtomicAnd32Barrier(0, &RCTProfileProfiling);
 
   [[NSNotificationCenter defaultCenter] postNotificationName:RCTProfileDidEndProfiling
-                                                      object:nil];
+                                                      object:bridge];
 
   [RCTProfileDisplayLink invalidate];
   RCTProfileDisplayLink = nil;

From cf94a9ea9599ff1325fb31ba34c3ab913f2bf964 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Tue, 15 Dec 2015 05:46:24 -0800
Subject: [PATCH 0381/1411] Avoid copying the JS bundle unnecessarily
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Summary:
public
When forwarding the unbundle code to the bridge, we’re passing the code by value.
This changes the affected method to take it by reference.

Reviewed By: astreet

Differential Revision: D2759569

fb-gh-sync-id: 508d4f4d56bcbdd5a7df5610cf9040121f8878ef
---
 ReactAndroid/src/main/jni/react/jni/OnLoad.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 8867b0c9e0d8..b5ad6a11f225 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -623,8 +623,8 @@ static void create(JNIEnv* env, jobject obj, jobject executor, jobject callback,
 
 static void executeApplicationScript(
     const RefPtr<Bridge>& bridge,
-    const std::string script,
-    const std::string sourceUri) {
+    const std::string& script,
+    const std::string& sourceUri) {
   try {
     // Execute the application script and collect/dispatch any native calls that might have occured
     bridge->executeApplicationScript(script, sourceUri);

From eb188c8d98fa08686c6b9335e3dcbefe3f524b7e Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Tue, 15 Dec 2015 06:26:51 -0800
Subject: [PATCH 0382/1411] Add deep linking support to IntentAndroid

Summary:
Add a method to handle URLs registered to the app,

```js
IntentAndroid.getInitialURL(url => {
    if (url) {
        // do stuff
    }
});
```

Refer - http://developer.android.com/training/app-indexing/deep-linking.html#adding-filters

The API cannot be same as the iOS API (i.e. as a constant), as the activity is not availble at the time of module initialization. Moreover, multiple activties can share the same bridge instance, and the activity itself is not a constant. Hence the initialURL can change.
Closes https://github.com/facebook/react-native/pull/4320

Reviewed By: svcscm

Differential Revision: D2759667

Pulled By: foghina

fb-gh-sync-id: b725231ae1401fa5565d444eee5a30d303e263ae
---
 .../Intent/IntentAndroid.android.js           | 34 ++++++++++++
 .../react/modules/intent/IntentModule.java    | 54 +++++++++++++++----
 2 files changed, 78 insertions(+), 10 deletions(-)

diff --git a/Libraries/Components/Intent/IntentAndroid.android.js b/Libraries/Components/Intent/IntentAndroid.android.js
index 75c620ee99fa..9dad6327bbab 100644
--- a/Libraries/Components/Intent/IntentAndroid.android.js
+++ b/Libraries/Components/Intent/IntentAndroid.android.js
@@ -16,6 +16,26 @@ var invariant = require('invariant');
 /**
  * `IntentAndroid` gives you a general interface to handle external links.
  *
+ * ### Basic Usage
+ *
+ * #### Handling deep links
+ *
+ * If your app was launched from an external url registered to your app you can
+ * access and handle it from any component you want with
+ *
+ * ```
+ * componentDidMount() {
+ *   var url = IntentAndroid.getInitialURL(url => {
+ *     if (url) {
+ *       console.log('Initial url is: ' + url);
+ *     }
+ *   });
+ * }
+ * ```
+ *
+ * NOTE: For instructions on how to add support for deep linking,
+ * refer [Enabling Deep Links for App Content - Add Intent Filters for Your Deep Links](http://developer.android.com/training/app-indexing/deep-linking.html#adding-filters).
+ *
  * #### Opening external links
  *
  * To start the corresponding activity for a link (web URL, email, contact etc.), call
@@ -75,6 +95,20 @@ class IntentAndroid {
     IntentAndroidModule.canOpenURL(url, callback);
   }
 
+  /**
+   * If the app launch was triggered by an app link with {@code Intent.ACTION_VIEW},
+   * it will give the link url, otherwise it will give `null`
+   *
+   * Refer http://developer.android.com/training/app-indexing/deep-linking.html#handling-intents
+   */
+  static getInitialURL(callback: Function) {
+    invariant(
+      typeof callback === 'function',
+      'A valid callback function is required'
+    );
+    IntentAndroidModule.getInitialURL(callback);
+  }
+
   static _validateURL(url: string) {
     invariant(
       typeof url === 'string',
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java
index e8e6322241b2..ce4681264193 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java
@@ -9,15 +9,15 @@
 
 package com.facebook.react.modules.intent;
 
+import android.app.Activity;
 import android.content.Intent;
 import android.net.Uri;
 
 import com.facebook.react.bridge.Callback;
+import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
 import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReactContextBaseJavaModule;
 import com.facebook.react.bridge.ReactMethod;
-import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
 
 /**
  * Intent module. Launch other activities or open URLs.
@@ -33,25 +33,58 @@ public String getName() {
     return "IntentAndroid";
   }
 
+  /**
+   * Return the URL the activity was started with
+   *
+   * @param callback a callback which is called with the initial URL
+   */
+  @ReactMethod
+  public void getInitialURL(Callback callback) {
+    try {
+      Activity currentActivity = getCurrentActivity();
+      String initialURL = null;
+
+      if (currentActivity != null) {
+        Intent intent = currentActivity.getIntent();
+        String action = intent.getAction();
+        Uri uri = intent.getData();
+
+        if (Intent.ACTION_VIEW.equals(action) && uri != null) {
+          initialURL = uri.toString();
+        }
+      }
+
+      callback.invoke(initialURL);
+    } catch (Exception e) {
+      throw new JSApplicationIllegalArgumentException(
+          "Could not get the initial URL : " + e.getMessage());
+    }
+  }
+
   /**
    * Starts a corresponding external activity for the given URL.
    *
    * For example, if the URL is "https://www.facebook.com", the system browser will be opened,
    * or the "choose application" dialog will be shown.
    *
-   * @param URL the URL to open
+   * @param url the URL to open
    */
   @ReactMethod
   public void openURL(String url) {
     if (url == null || url.isEmpty()) {
       throw new JSApplicationIllegalArgumentException("Invalid URL: " + url);
     }
+
     try {
+      Activity currentActivity = getCurrentActivity();
       Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
-      // We need Intent.FLAG_ACTIVITY_NEW_TASK since getReactApplicationContext() returns
-      // the ApplicationContext instead of the Activity context.
-      intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-      getReactApplicationContext().startActivity(intent);
+
+      if (currentActivity != null) {
+        currentActivity.startActivity(intent);
+      } else {
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        getReactApplicationContext().startActivity(intent);
+      }
     } catch (Exception e) {
       throw new JSApplicationIllegalArgumentException(
           "Could not open URL '" + url + "': " + e.getMessage());
@@ -61,21 +94,22 @@ public void openURL(String url) {
   /**
    * Determine whether or not an installed app can handle a given URL.
    *
-   * @param URL the URL to open
-   * @param promise a promise that is always resolved with a boolean argument
+   * @param url the URL to open
+   * @param callback a callback that is always called with a boolean argument
    */
   @ReactMethod
   public void canOpenURL(String url, Callback callback) {
     if (url == null || url.isEmpty()) {
       throw new JSApplicationIllegalArgumentException("Invalid URL: " + url);
     }
+
     try {
       Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
       // We need Intent.FLAG_ACTIVITY_NEW_TASK since getReactApplicationContext() returns
       // the ApplicationContext instead of the Activity context.
       intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
       boolean canOpen =
-          intent.resolveActivity(this.getReactApplicationContext().getPackageManager()) != null;
+          intent.resolveActivity(getReactApplicationContext().getPackageManager()) != null;
       callback.invoke(canOpen);
     } catch (Exception e) {
       throw new JSApplicationIllegalArgumentException(

From 9f48c004ba866aa24d17242a817929462a091179 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Tue, 15 Dec 2015 06:56:07 -0800
Subject: [PATCH 0383/1411] Added setChildren() function

Summary:
public
Most of the time - especially during app startup - when we call UIManager.manageChildren(), we are actually just adding the first set of children to a newly created view.

This case is already optimized for in the JS code, by memoizing index arrays at various sizes, but this is not especially efficient since it is still sending an array of indices with each call that could be easily inferred on the native side instead.

I've added a hybrid native/JS optimization that improves the performance for this case. It's not a huge win in terms of time saved, but benchmarks show improvements in the ~1% range for several of the app startup metrics.

Reviewed By: tadeuzagallo

Differential Revision: D2757388

fb-gh-sync-id: 74f0cdbba93af2c04d69b192a8c2cc5cf429fa09
---
 .../ReactNative/ReactNativeBaseComponent.js   | 32 ++-----------------
 Libraries/ReactNative/ReactNativeMount.js     | 10 ++----
 Libraries/Utilities/UIManager.js              | 29 +++++++++++++++++
 React/Modules/RCTUIManager.m                  | 27 ++++++++++++++++
 4 files changed, 61 insertions(+), 37 deletions(-)

diff --git a/Libraries/ReactNative/ReactNativeBaseComponent.js b/Libraries/ReactNative/ReactNativeBaseComponent.js
index 266c7b30fbf6..8b60d8682497 100644
--- a/Libraries/ReactNative/ReactNativeBaseComponent.js
+++ b/Libraries/ReactNative/ReactNativeBaseComponent.js
@@ -45,31 +45,6 @@ var ReactNativeBaseComponent = function(
   this.viewConfig = viewConfig;
 };
 
-/**
- * Generates and caches arrays of the form:
- *
- *    [0, 1, 2, 3]
- *    [0, 1, 2, 3, 4]
- *    [0, 1]
- *
- * @param {number} size Size of array to generate.
- * @return {Array<number>} Array with values that mirror the index.
- */
-var cachedIndexArray = function(size) {
-  var cachedResult = cachedIndexArray._cache[size];
-  if (!cachedResult) {
-    var arr = [];
-    for (var i = 0; i < size; i++) {
-      arr[i] = i;
-    }
-    cachedIndexArray._cache[size] = arr;
-    return arr;
-  } else {
-    return cachedResult;
-  }
-};
-cachedIndexArray._cache = {};
-
 /**
  * Mixin for containers that contain UIViews. NOTE: markup is rendered markup
  * which is a `viewID` ... see the return value for `mountComponent` !
@@ -104,11 +79,11 @@ ReactNativeBaseComponent.Mixin = {
     // no children - let's avoid calling out to the native bridge for a large
     // portion of the children.
     if (mountImages.length) {
-      var indexes = cachedIndexArray(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; i < mountImages.length; i++) {
+      for (var i = 0, l = mountImages.length; i < l; i++) {
         var mountImage = mountImages[i];
         var childTag = mountImage.tag;
         var childID = mountImage.rootNodeID;
@@ -122,8 +97,7 @@ ReactNativeBaseComponent.Mixin = {
         );
         createdTags[i] = mountImage.tag;
       }
-      UIManager
-        .manageChildren(containerTag, null, null, createdTags, indexes, null);
+      UIManager.setChildren(containerTag, createdTags);
     }
   },
 
diff --git a/Libraries/ReactNative/ReactNativeMount.js b/Libraries/ReactNative/ReactNativeMount.js
index 1f6dab51b8a4..2a38c3dbba8c 100644
--- a/Libraries/ReactNative/ReactNativeMount.js
+++ b/Libraries/ReactNative/ReactNativeMount.js
@@ -188,15 +188,9 @@ var ReactNativeMount = {
         mountImage.rootNodeID,
         mountImage.tag
       );
-      var addChildTags = [mountImage.tag];
-      var addAtIndices = [0];
-      UIManager.manageChildren(
+      UIManager.setChildren(
         ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(containerID),
-        null,         // moveFromIndices
-        null,         // moveToIndices
-        addChildTags,
-        addAtIndices,
-        null          // removeAtIndices
+        [mountImage.tag]
       );
     }
   ),
diff --git a/Libraries/Utilities/UIManager.js b/Libraries/Utilities/UIManager.js
index 3cdfb2e91db1..ff2fc23541de 100644
--- a/Libraries/Utilities/UIManager.js
+++ b/Libraries/Utilities/UIManager.js
@@ -13,4 +13,33 @@
 
 var UIManager = require('NativeModules').UIManager;
 
+if (!UIManager.setChildren) {
+
+  /**
+   * Index cache (used by setChildren())
+   */
+  UIManager._cachedIndexArray = function(size) {
+    var cachedResult = this._cachedIndexArray._cache[size];
+    if (!cachedResult) {
+      var arr = [];
+      for (var i = 0; i < size; i++) {
+        arr[i] = i;
+      }
+      this._cachedIndexArray._cache[size] = arr;
+      return arr;
+    } else {
+      return cachedResult;
+    }
+  };
+  UIManager._cachedIndexArray._cache = {};
+
+  /**
+   * Fallback setChildren() implementation for Android
+   */
+  UIManager.setChildren = function(containerTag, createdTags) {
+    var indexes = this._cachedIndexArray(createdTags.length);
+    UIManager.manageChildren(containerTag, null, null, createdTags, indexes, null);
+  } 
+}
+
 module.exports = UIManager;
diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m
index bf1c2ee59fac..3f60b3f53540 100644
--- a/React/Modules/RCTUIManager.m
+++ b/React/Modules/RCTUIManager.m
@@ -720,6 +720,33 @@ - (void)_removeChildren:(NSArray<id<RCTComponent>> *)children
         removeAtIndices:removeAtIndices];
 }
 
+RCT_EXPORT_METHOD(setChildren:(nonnull NSNumber *)containerTag
+                  reactTags:(NSArray<NSNumber *> *)reactTags)
+{
+  RCTSetChildren(containerTag, reactTags,
+                 (NSDictionary<NSNumber *, id<RCTComponent>> *)_shadowViewRegistry);
+
+  [self addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry){
+
+    RCTSetChildren(containerTag, reactTags,
+                   (NSDictionary<NSNumber *, id<RCTComponent>> *)viewRegistry);
+  }];
+}
+
+static void RCTSetChildren(NSNumber *containerTag,
+                           NSArray<NSNumber *> *reactTags,
+                           NSDictionary<NSNumber *, id<RCTComponent>> *registry)
+{
+  id<RCTComponent> container = registry[containerTag];
+  NSInteger index = 0;
+  for (NSNumber *reactTag in reactTags) {
+    id<RCTComponent> view = registry[reactTag];
+    if (view) {
+      [container insertReactSubview:view atIndex:index++];
+    }
+  }
+}
+
 RCT_EXPORT_METHOD(manageChildren:(nonnull NSNumber *)containerReactTag
                   moveFromIndices:(NSArray<NSNumber *> *)moveFromIndices
                   moveToIndices:(NSArray<NSNumber *> *)moveToIndices

From 4cb04315e7de835b52cbdc2ae3072ddaadb9283b Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Tue, 15 Dec 2015 07:45:41 -0800
Subject: [PATCH 0384/1411] Unbreak console reassignment on iOS7

Summary:
public
Unbreaks console assignment on iOS7 introduced in #3322

Reviewed By: alexeylang

Differential Revision: D2759689

fb-gh-sync-id: 28cccfdf1123245732fa5ba0337ee8d7bb43c822
---
 .../react-packager/src/Resolver/polyfills/console.js   | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/packager/react-packager/src/Resolver/polyfills/console.js b/packager/react-packager/src/Resolver/polyfills/console.js
index 6aa485508065..a8e5a72f41cf 100644
--- a/packager/react-packager/src/Resolver/polyfills/console.js
+++ b/packager/react-packager/src/Resolver/polyfills/console.js
@@ -474,8 +474,14 @@
       trace: getNativeLogFunction(LOG_LEVELS.trace),
       table: consoleTablePolyfill
     };
-    descriptor.value = console;
-    Object.defineProperty(global, 'console', descriptor);
+
+    // don't reassign to the original descriptor. breaks on ios7
+    Object.defineProperty(global, 'console', {
+      value: console,
+      configurable: descriptor ? descriptor.configurable : true,
+      enumerable: descriptor ? descriptor.enumerable : true,
+      writable: descriptor ? descriptor.writable : true,
+    });
 
     // If available, also call the original `console` method since that is
     // sometimes useful. Ex: on OS X, this will let you see rich output in

From 2f32cccce782c46705826ae4d8990bc680539b0f Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Tue, 15 Dec 2015 21:20:40 +0530
Subject: [PATCH 0385/1411] Add docs for 'IntentAndroid'

---
 docs/KnownIssues.md           | 4 ++--
 website/server/extractDocs.js | 1 +
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/docs/KnownIssues.md b/docs/KnownIssues.md
index ad112ecce603..8962584f0166 100644
--- a/docs/KnownIssues.md
+++ b/docs/KnownIssues.md
@@ -51,7 +51,7 @@ There are known cases where the APIs could be made more consistent across iOS an
 
 - `<AndroidViewPager>` and `<ScrollView pagingEnabled={true}>` on iOS do a similar thing. We might want to unify them to `<ViewPager>`.
 - `alert()` needs Android support (once the Dialogs module is open sourced)
-- It might be possible to bring `LinkingIOS` and `IntentAndroid` (to be open sourced) closer together.
+- It might be possible to bring `LinkingIOS` and `IntentAndroid` closer together.
 - `ActivityIndicator` could render a native spinning indicator on both platforms (currently this is done using `ActivityIndicatorIOS` on iOS and `ProgressBarAndroid` on Android).
 - `ProgressBar` could render a horizontal progress bar on both platforms (on iOS this is `ProgressViewIOS`, on Android it's `ProgressBarAndroid`).
 
@@ -63,7 +63,7 @@ Adding these to your apps should be made simpler. Here's [an example](https://gi
 
 ### The `overflow` style property defaults to `hidden` and cannot be changed on Android
 
-This is a result of how Android rendering works. This feature is not being worked on as it would be a significant undertaking and there are many more important tasks. 
+This is a result of how Android rendering works. This feature is not being worked on as it would be a significant undertaking and there are many more important tasks.
 
 Another issue with `overflow: 'hidden'` on Android: a view is not clipped by the parent's `borderRadius` even if the parent has `overflow: 'hidden'` enabled – the corners of the inner view will be visible outside of the rounded corners. This is only on Android; it works as expected on iOS. See a [demo of the bug](https://rnplay.org/apps/BlGjdQ) and the [corresponding issue](https://github.com/facebook/react-native/issues/3198).
 
diff --git a/website/server/extractDocs.js b/website/server/extractDocs.js
index cdd69e9a0e37..7ae599058a41 100644
--- a/website/server/extractDocs.js
+++ b/website/server/extractDocs.js
@@ -228,6 +228,7 @@ var apis = [
   '../Libraries/Utilities/BackAndroid.android.js',
   '../Libraries/CameraRoll/CameraRoll.js',
   '../Libraries/Utilities/Dimensions.js',
+  '../Libraries/Components/Intent/IntentAndroid.android.js',
   '../Libraries/Interaction/InteractionManager.js',
   '../Libraries/LayoutAnimation/LayoutAnimation.js',
   '../Libraries/LinkingIOS/LinkingIOS.js',

From 264ece1f725e4b35d3c7e5a9bfe8230b352c8ea3 Mon Sep 17 00:00:00 2001
From: Justas Brazauskas <brazauskasjustas@gmail.com>
Date: Tue, 15 Dec 2015 18:13:25 +0200
Subject: [PATCH 0386/1411] Fix typos in ./docs

---
 docs/Accessibility.md | 2 +-
 docs/Tutorial.md      | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/Accessibility.md b/docs/Accessibility.md
index 10ac5884afc6..b968642c8908 100644
--- a/docs/Accessibility.md
+++ b/docs/Accessibility.md
@@ -81,7 +81,7 @@ Assign this property to a custom function which will be called when someone perf
 
 #### accessibilityComponentType (Android)
 
-In some cases, we also want to alert the end user of the type of selected component (ie, that it is a “button”). If we were using native buttons, this would work automatically. Since we are using javascript, we need to provide a bit more context for TalkBack. To do so, you must specify the ‘accessibilityComponentType’ property for any UI component. For instances, we support ‘button’, ‘radiobutton_checked’ and ‘radiobutton_unchecked’ and so on.
+In some cases, we also want to alert the end user of the type of selected component (i.e., that it is a “button”). If we were using native buttons, this would work automatically. Since we are using javascript, we need to provide a bit more context for TalkBack. To do so, you must specify the ‘accessibilityComponentType’ property for any UI component. For instances, we support ‘button’, ‘radiobutton_checked’ and ‘radiobutton_unchecked’ and so on.
 
 ```javascript
 <TouchableWithoutFeedback accessibilityComponentType=”button”
diff --git a/docs/Tutorial.md b/docs/Tutorial.md
index d1d71a6631cd..c3b75cfb98cb 100644
--- a/docs/Tutorial.md
+++ b/docs/Tutorial.md
@@ -129,7 +129,7 @@ Great, we've rendered our data. Now let's make it look better. I'd like to put t
 +---------------------------------+
 ```
 
-We'll need to add another container in order to vertically lay out components within horizontally layed out components.
+We'll need to add another container in order to vertically lay out components within horizontally laid out components.
 
 ```javascript
       return (

From 7871abf907fcf24c4167be8a95854082cc5df5db Mon Sep 17 00:00:00 2001
From: Felix Oghina <foghina@fb.com>
Date: Tue, 15 Dec 2015 08:19:53 -0800
Subject: [PATCH 0387/1411] crash gracefully on fatal js errors

Reviewed By: AaaChiuuu

Differential Revision: D2739392

fb-gh-sync-id: bcc1171c076a4f6425184e7b9ffed204f5ce6f0e
---
 .../com/facebook/react/ReactInstanceManager.java  | 15 ++++++++++++++-
 .../facebook/react/ReactInstanceManagerImpl.java  | 11 +++++++++--
 2 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
index bdffdf261a53..e8793d241d46 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
@@ -19,6 +19,7 @@
 import android.content.Intent;
 
 import com.facebook.infer.annotation.Assertions;
+import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
 import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener;
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.ReactContext;
@@ -159,6 +160,7 @@ public static class Builder {
     protected boolean mUseDeveloperSupport;
     protected @Nullable LifecycleState mInitialLifecycleState;
     protected @Nullable UIImplementationProvider mUIImplementationProvider;
+    protected @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
 
     protected Builder() {
     }
@@ -242,6 +244,16 @@ public Builder setInitialLifecycleState(LifecycleState initialLifecycleState) {
       return this;
     }
 
+    /**
+     * Set the exception handler for all native module calls. If not set, the default
+     * {@link DevSupportManager} will be used, which shows a redbox in dev mode and rethrows
+     * (crashes the app) in prod mode.
+     */
+    public Builder setNativeModuleCallExceptionHandler(NativeModuleCallExceptionHandler handler) {
+      mNativeModuleCallExceptionHandler = handler;
+      return this;
+    }
+
     /**
      * Instantiates a new {@link ReactInstanceManagerImpl}.
      * Before calling {@code build}, the following must be called:
@@ -274,7 +286,8 @@ public ReactInstanceManager build() {
           mUseDeveloperSupport,
           mBridgeIdleDebugListener,
           Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"),
-          mUIImplementationProvider);
+          mUIImplementationProvider,
+          mNativeModuleCallExceptionHandler);
     }
   }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index 7953691c0ad2..e0ce3c97e47b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -35,6 +35,7 @@
 import com.facebook.react.bridge.JavaScriptModule;
 import com.facebook.react.bridge.JavaScriptModulesConfig;
 import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
 import com.facebook.react.bridge.NativeModuleRegistry;
 import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener;
 import com.facebook.react.bridge.ProxyJavaScriptExecutor;
@@ -100,6 +101,7 @@
   private volatile boolean mHasStartedCreatingInitialContext = false;
   private final UIImplementationProvider mUIImplementationProvider;
   private final MemoryPressureRouter mMemoryPressureRouter;
+  private final @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
 
   private final ReactInstanceDevCommandsHandler mDevInterface =
       new ReactInstanceDevCommandsHandler() {
@@ -195,7 +197,8 @@ protected void onPostExecute(ReactApplicationContext reactContext) {
       boolean useDeveloperSupport,
       @Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener,
       LifecycleState initialLifecycleState,
-      UIImplementationProvider uiImplementationProvider) {
+      UIImplementationProvider uiImplementationProvider,
+      NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
     initializeSoLoaderIfNecessary(applicationContext);
 
     mApplicationContext = applicationContext;
@@ -216,6 +219,7 @@ protected void onPostExecute(ReactApplicationContext reactContext) {
     mLifecycleState = initialLifecycleState;
     mUIImplementationProvider = uiImplementationProvider;
     mMemoryPressureRouter = new MemoryPressureRouter(applicationContext);
+    mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
   }
 
   @Override
@@ -652,13 +656,16 @@ private ReactApplicationContext createReactContext(
       Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
     }
 
+    NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null
+        ? mNativeModuleCallExceptionHandler
+        : mDevSupportManager;
     CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
         .setCatalystQueueConfigurationSpec(CatalystQueueConfigurationSpec.createDefault())
         .setJSExecutor(jsExecutor)
         .setRegistry(nativeModuleRegistry)
         .setJSModulesConfig(javaScriptModulesConfig)
         .setJSBundleLoader(jsBundleLoader)
-        .setNativeModuleCallExceptionHandler(mDevSupportManager);
+        .setNativeModuleCallExceptionHandler(exceptionHandler);
 
     Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstance");
     CatalystInstance catalystInstance;

From 7927f1eee5cef05962186a6935ee336dc27206f6 Mon Sep 17 00:00:00 2001
From: Kureev Alexey <kureev-mail@ya.ru>
Date: Tue, 15 Dec 2015 17:55:38 +0100
Subject: [PATCH 0388/1411] Add a section about linking process automation
 using rnpm

---
 docs/LinkingLibraries.md | 40 +++++++++++++++++++++++++++++++++++++---
 1 file changed, 37 insertions(+), 3 deletions(-)

diff --git a/docs/LinkingLibraries.md b/docs/LinkingLibraries.md
index c5cf659cf883..3ffe7b4b8986 100644
--- a/docs/LinkingLibraries.md
+++ b/docs/LinkingLibraries.md
@@ -24,7 +24,41 @@ error as soon as you try to use the library._
 
 ## Here the few steps to link your libraries that contain native code
 
-### Step 1
+### Automatic linking
+
+There is a way to link your native dependencies automatically by using [rnpm](http://github.com/rnpm/rnpm):
+
+#### Step 1
+
+Install `rnpm`:
+```bash
+$ npm install rnpm -g
+```
+
+**Note:** _`rnpm` requires `node` version 4.1 or higher_
+
+#### Step 2
+
+Install a library with native dependencies:
+```bash
+$ npm install library-with-native-dependencies --save
+```
+
+**Note:** _`--save` or `--save-dev` flag is very important for this step. `rnpm` will link
+your libs based on `dependencies` and `devDependencies` in your `package.json` file._
+
+#### Step 3
+
+Link your native dependencies:
+```bash
+$ rnpm link
+```
+
+Done! All libraries with a native dependencies should be successfully linked to your iOS/Android project.
+
+### Manual linking
+
+#### Step 1
 
 If the library has native code, there must be a `.xcodeproj` file inside it's
 folder.
@@ -33,7 +67,7 @@ on Xcode);
 
 ![](/react-native/img/AddToLibraries.png)
 
-### Step 2
+#### Step 2
 
 Click on your main project file (the one that represents the `.xcodeproj`)
 select `Build Phases` and drag the static library from the `Products` folder
@@ -41,7 +75,7 @@ inside the Library you are importing to `Link Binary With Libraries`
 
 ![](/react-native/img/AddToBuildPhases.png)
 
-### Step 3
+#### Step 3
 
 Not every library will need this step, what you need to consider is:
 

From 0e8b207cc34f230eb2cced3981734b522b601817 Mon Sep 17 00:00:00 2001
From: Justas Brazauskas <brazauskasjustas@gmail.com>
Date: Tue, 15 Dec 2015 09:08:39 -0800
Subject: [PATCH 0389/1411] Bugfix - Typos

Summary:
Fixed few typos in `./Examples` and `./Libraries` folders.
Closes https://github.com/facebook/react-native/pull/4788

Reviewed By: svcscm

Differential Revision: D2759918

Pulled By: androidtrunkagent

fb-gh-sync-id: d692b5c7f561822353e522f9d4dfde7e60b491cf
---
 Examples/2048/GameBoard.js                                | 2 +-
 .../UIExplorerUnitTests/LayoutSubviewsOrderingTest.m      | 4 ++--
 .../UIExplorerUnitTests/RCTContextExecutorTests.m         | 2 +-
 Examples/UIExplorer/WebViewExample.js                     | 2 +-
 Examples/UIExplorer/XHRExample.android.js                 | 2 +-
 Libraries/Animated/examples/demo.html                     | 2 +-
 Libraries/Animated/src/AnimatedImplementation.js          | 8 ++++----
 Libraries/CameraRoll/CameraRoll.js                        | 2 +-
 .../DrawerAndroid/DrawerLayoutAndroid.android.js          | 2 +-
 Libraries/Components/MapView/MapView.js                   | 6 +++---
 Libraries/Components/Navigation/NavigatorIOS.ios.js       | 2 +-
 .../ScrollView/RecyclerViewBackedScrollView.android.js    | 4 ++--
 Libraries/Components/ScrollView/ScrollView.js             | 4 ++--
 Libraries/Components/SliderIOS/SliderIOS.ios.js           | 2 +-
 Libraries/Components/Switch/Switch.js                     | 2 +-
 .../Components/SwitchAndroid/SwitchAndroid.android.js     | 2 +-
 Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js       | 4 ++--
 .../Components/ToolbarAndroid/ToolbarAndroid.android.js   | 2 +-
 Libraries/Components/Touchable/Position.js                | 3 +--
 Libraries/Components/Touchable/Touchable.js               | 4 ++--
 .../Components/ViewPager/ViewPagerAndroid.android.js      | 4 ++--
 Libraries/CustomComponents/ListView/ListView.js           | 2 +-
 Libraries/CustomComponents/ListView/ListViewDataSource.js | 2 +-
 Libraries/CustomComponents/Navigator/Navigator.js         | 2 +-
 Libraries/Image/ImageResizeMode.js                        | 2 +-
 Libraries/JavaScriptAppEngine/Initialization/SourceMap.js | 6 +++---
 Libraries/PushNotificationIOS/PushNotificationIOS.js      | 2 +-
 Libraries/RCTTest/FBSnapshotTestCase/FBSnapshotTestCase.h | 4 ++--
 .../RCTTest/FBSnapshotTestCase/FBSnapshotTestController.h | 2 +-
 Libraries/ReactNative/ReactNativeEventEmitter.js          | 8 ++++----
 Libraries/ReactNative/ReactNativeReconcileTransaction.js  | 4 ++--
 Libraries/StyleSheet/processColor.js                      | 2 +-
 Libraries/Text/RCTTextField.m                             | 2 +-
 Libraries/Text/Text.js                                    | 2 +-
 Libraries/Utilities/BackAndroid.android.js                | 2 +-
 Libraries/Utilities/CSSVarConfig.js                       | 2 +-
 Libraries/Utilities/buildStyleInterpolator.js             | 2 +-
 Libraries/Utilities/mergeIntoFast.js                      | 2 +-
 Libraries/Utilities/truncate.js                           | 2 +-
 39 files changed, 57 insertions(+), 58 deletions(-)

diff --git a/Examples/2048/GameBoard.js b/Examples/2048/GameBoard.js
index 1d7f34085b10..6ed92e6b578d 100644
--- a/Examples/2048/GameBoard.js
+++ b/Examples/2048/GameBoard.js
@@ -17,7 +17,7 @@
 'use strict';
 
 // NB: Taken straight from: https://github.com/IvanVergiliev/2048-react/blob/master/src/board.js
-//     with no modificiation except to format it for CommonJS and fix lint/flow errors
+//     with no modification except to format it for CommonJS and fix lint/flow errors
 
 var rotateLeft = function (matrix) {
   var rows = matrix.length;
diff --git a/Examples/UIExplorer/UIExplorerUnitTests/LayoutSubviewsOrderingTest.m b/Examples/UIExplorer/UIExplorerUnitTests/LayoutSubviewsOrderingTest.m
index fcd7961143c3..39c0404e0295 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/LayoutSubviewsOrderingTest.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/LayoutSubviewsOrderingTest.m
@@ -14,7 +14,7 @@ @implementation LayoutSubviewsOrderingTest
 /**
  * This test exists to insure that didLayoutSubviews is always called immediately after layoutSubviews for a VC:View
  * pair. In Catalyst we have multiple levels of ViewController containment, and we rely on this ordering
- * to insure that layoutGuides are set on RKViewControllers before Views further down in the heirarchy have
+ * to insure that layoutGuides are set on RKViewControllers before Views further down in the hierarchy have
  * their layoutSubviews called (and need to use the aforementioned layoutGuides)
  */
 - (void)testLayoutSubviewsOrdering
@@ -63,7 +63,7 @@ - (void)testLayoutSubviewsOrdering
     }
   }] viewDidLayoutSubviews];
 
-  // setup View heirarchy and force layout
+  // setup View hierarchy and force layout
   parentVC.view = parentView;
   childVC.view = childView;
   [parentVC addChildViewController:childVC];
diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTContextExecutorTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTContextExecutorTests.m
index c1b96b13e52b..07d1ebfb00b7 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTContextExecutorTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTContextExecutorTests.m
@@ -98,7 +98,7 @@ - (void)testJavaScriptCallSpeed
 {
 /**
  * Since we almost don't change the RCTContextExecutor logic, and this test is
- * very likely to become flaky (specially accross different devices) leave it
+ * very likely to become flaky (specially across different devices) leave it
  * to be run manually
  *
  * Previous Values: If you change the executor code, you should update this values
diff --git a/Examples/UIExplorer/WebViewExample.js b/Examples/UIExplorer/WebViewExample.js
index f8183b12b29b..c8c547f978e9 100644
--- a/Examples/UIExplorer/WebViewExample.js
+++ b/Examples/UIExplorer/WebViewExample.js
@@ -148,7 +148,7 @@ var WebViewExample = React.createClass({
         url: url,
       });
     }
-    // dismiss keyoard
+    // dismiss keyboard
     this.refs[TEXT_INPUT_REF].blur();
   },
 
diff --git a/Examples/UIExplorer/XHRExample.android.js b/Examples/UIExplorer/XHRExample.android.js
index ad4bbf772a90..0ee51a8e3039 100644
--- a/Examples/UIExplorer/XHRExample.android.js
+++ b/Examples/UIExplorer/XHRExample.android.js
@@ -30,7 +30,7 @@ var XHRExampleHeaders = require('./XHRExampleHeaders');
 var XHRExampleCookies = require('./XHRExampleCookies');
 
 
-// TODO t7093728 This is a simlified XHRExample.ios.js.
+// TODO t7093728 This is a simplified XHRExample.ios.js.
 // Once we have Camera roll, Toast, Intent (for opening URLs)
 // we should make this consistent with iOS.
 
diff --git a/Libraries/Animated/examples/demo.html b/Libraries/Animated/examples/demo.html
index bc4c85e1f462..4f95e114fa86 100644
--- a/Libraries/Animated/examples/demo.html
+++ b/Libraries/Animated/examples/demo.html
@@ -326,7 +326,7 @@ <h2>stopAnimation</h2>
 
 <p><code>Animated</code> can offload the animation to a different thread (CoreAnimation, CSS transitions, main thread...) and we don't have a good way to know the real value. If you try to query the value then modify it, you are going to be out of sync and the result will look terrible.</p>
 
-<p>There's however one exception: when you want to stop the current animation. You need to know where it stopped in order to continue from there. We cannot know the value synchronously so we give it via a callback in <code>stopAnimation</code>. It will not suffer from beign out of sync since the animation is no longer running.</p>
+<p>There's however one exception: when you want to stop the current animation. You need to know where it stopped in order to continue from there. We cannot know the value synchronously so we give it via a callback in <code>stopAnimation</code>. It will not suffer from being out of sync since the animation is no longer running.</p>
 
 <script type="text/jsx;harmony=true;stripTypes=true">
 examplify(React.createClass({
diff --git a/Libraries/Animated/src/AnimatedImplementation.js b/Libraries/Animated/src/AnimatedImplementation.js
index e7edc16a9645..09f95000da35 100644
--- a/Libraries/Animated/src/AnimatedImplementation.js
+++ b/Libraries/Animated/src/AnimatedImplementation.js
@@ -578,7 +578,7 @@ class AnimatedValue extends AnimatedWithChildren {
   /**
    * Adds an asynchronous listener to the value so you can observe updates from
    * animations or whathaveyou.  This is useful because there is no way to
-   * syncronously read the value because it might be driven natively.
+   * synchronously read the value because it might be driven natively.
    */
   addListener(callback: ValueListenerCallback): string {
     var id = String(_uniqueId++);
@@ -1485,7 +1485,7 @@ var event = function(
  * The simplest workflow is to create an `Animated.Value`, hook it up to one or
  * more style attributes of an animated component, and then drive updates either
  * via animations, such as `Animated.timing`, or by hooking into gestures like
- * panning or scolling via `Animated.event`.  `Animated.Value` can also bind to
+ * panning or scrolling via `Animated.event`.  `Animated.Value` can also bind to
  * props other than style, and can be interpolated as well.  Here is a basic
  * example of a container view that will fade in when it's mounted:
  *
@@ -1517,7 +1517,7 @@ var event = function(
  * Note that only animatable components can be animated.  `View`, `Text`, and
  * `Image` are already provided, and you can create custom ones with
  * `createAnimatedComponent`.  These special components do the magic of binding
- * the animated values to the properties, and do targetted native updates to
+ * the animated values to the properties, and do targeted native updates to
  * avoid the cost of the react render and reconciliation process on every frame.
  * They also handle cleanup on unmount so they are safe by default.
  *
@@ -1559,7 +1559,7 @@ var event = function(
  * Animation App, and [Animations documentation guide](http://facebook.github.io/react-native/docs/animations.html).
  *
  * Note that `Animated` is designed to be fully serializable so that animations
- * can be run in a high performace way, independent of the normal JavaScript
+ * can be run in a high performance way, independent of the normal JavaScript
  * event loop. This does influence the API, so keep that in mind when it seems a
  * little trickier to do something compared to a fully synchronous system.
  * Checkout `Animated.Value.addListener` as a way to work around some of these
diff --git a/Libraries/CameraRoll/CameraRoll.js b/Libraries/CameraRoll/CameraRoll.js
index c7e28d9510b3..48c3132191bf 100644
--- a/Libraries/CameraRoll/CameraRoll.js
+++ b/Libraries/CameraRoll/CameraRoll.js
@@ -128,7 +128,7 @@ class CameraRoll {
    *
    *   - local URI
    *   - assets-library tag
-   *   - a tag not maching any of the above, which means the image data will
+   *   - a tag not matching any of the above, which means the image data will
    * be stored in memory (and consume memory as long as the process is alive)
    *
    * @param successCallback Invoked with the value of `tag` on success.
diff --git a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js
index 5a48ee9aba79..4383f9f84d25 100644
--- a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js
+++ b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js
@@ -102,7 +102,7 @@ var DrawerLayoutAndroid = React.createClass({
     /**
      * Function called when the drawer state has changed. The drawer can be in 3 states:
      * - idle, meaning there is no interaction with the navigation view happening at the time
-     * - dragging, meaning there is currently an interation with the navigation view
+     * - dragging, meaning there is currently an interaction with the navigation view
      * - settling, meaning that there was an interaction with the navigation view, and the
      * navigation view is now finishing it's closing or opening animation
      */
diff --git a/Libraries/Components/MapView/MapView.js b/Libraries/Components/MapView/MapView.js
index b62b122df40f..747e366fcb70 100644
--- a/Libraries/Components/MapView/MapView.js
+++ b/Libraries/Components/MapView/MapView.js
@@ -150,7 +150,7 @@ var MapView = React.createClass({
      *
      * - standard: standard road map (default)
      * - satellite: satellite view
-     * - hybrid: satellite view with roads and points of interest overlayed
+     * - hybrid: satellite view with roads and points of interest overlaid
      */
     mapType: React.PropTypes.oneOf([
       'standard',
@@ -172,7 +172,7 @@ var MapView = React.createClass({
       longitude: React.PropTypes.number.isRequired,
 
       /**
-       * Distance between the minimun and the maximum latitude/longitude
+       * Distance between the minimum and the maximum latitude/longitude
        * to be displayed.
        */
       latitudeDelta: React.PropTypes.number.isRequired,
@@ -218,7 +218,7 @@ var MapView = React.createClass({
        * and custom pin images.
        *
        * Note that on iOS 8 and earlier, only the standard PinColor constants
-       * are supported for regualr pins. For custom pin images, any tintColor
+       * are supported for regular pins. For custom pin images, any tintColor
        * value is supported on all iOS versions.
        * @platform ios
        */
diff --git a/Libraries/Components/Navigation/NavigatorIOS.ios.js b/Libraries/Components/Navigation/NavigatorIOS.ios.js
index 37cc1899edd0..32d51ddc84af 100644
--- a/Libraries/Components/Navigation/NavigatorIOS.ios.js
+++ b/Libraries/Components/Navigation/NavigatorIOS.ios.js
@@ -119,7 +119,7 @@ type Event = Object;
  * },
  * ```
  *
- * Now MyView will be rendered by the navigator. It will recieve the route
+ * Now MyView will be rendered by the navigator. It will receive the route
  * object in the `route` prop, a navigator, and all of the props specified in
  * `passProps`.
  *
diff --git a/Libraries/Components/ScrollView/RecyclerViewBackedScrollView.android.js b/Libraries/Components/ScrollView/RecyclerViewBackedScrollView.android.js
index fa019c6be332..f8fecfdc3506 100644
--- a/Libraries/Components/ScrollView/RecyclerViewBackedScrollView.android.js
+++ b/Libraries/Components/ScrollView/RecyclerViewBackedScrollView.android.js
@@ -20,9 +20,9 @@ var INNERVIEW = 'InnerView';
  * Wrapper around android native recycler view.
  *
  * It simply renders rows passed as children in a separate recycler view cells
- * similarily to how `ScrollView` is doing it. Thanks to the fact that it uses
+ * similarly to how `ScrollView` is doing it. Thanks to the fact that it uses
  * native `RecyclerView` though, rows that are out of sight are going to be
- * automatically detached (similarily on how this would work with
+ * automatically detached (similarly on how this would work with
  * `removeClippedSubviews = true` on a `ScrollView.js`).
  *
  * CAUTION: This is an experimental component and should only be used together
diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js
index 8069b9647be5..5f6e08d86693 100644
--- a/Libraries/Components/ScrollView/ScrollView.js
+++ b/Libraries/Components/ScrollView/ScrollView.js
@@ -184,7 +184,7 @@ var ScrollView = React.createClass({
     minimumZoomScale: PropTypes.number,
     /**
      * Fires at most once per frame during scrolling. The frequency of the
-     * events can be contolled using the `scrollEventThrottle` prop.
+     * events can be controlled using the `scrollEventThrottle` prop.
      */
     onScroll: PropTypes.func,
     /**
@@ -438,7 +438,7 @@ var ScrollView = React.createClass({
 
     var onRefreshStart = this.props.onRefreshStart;
     // this is necessary because if we set it on props, even when empty,
-    // it'll trigger the default pull-to-refresh behaviour on native.
+    // it'll trigger the default pull-to-refresh behavior on native.
     props.onRefreshStart = onRefreshStart
       ? function() { onRefreshStart && onRefreshStart(this.endRefreshing); }.bind(this)
       : null;
diff --git a/Libraries/Components/SliderIOS/SliderIOS.ios.js b/Libraries/Components/SliderIOS/SliderIOS.ios.js
index 925f9ad60d34..aff67e6ef7e0 100644
--- a/Libraries/Components/SliderIOS/SliderIOS.ios.js
+++ b/Libraries/Components/SliderIOS/SliderIOS.ios.js
@@ -39,7 +39,7 @@ var SliderIOS = React.createClass({
      * Default value is 0.
      *
      * *This is not a controlled component*, e.g. if you don't update
-     * the value, the component won't be reset to its inital value.
+     * the value, the component won't be reset to its initial value.
      */
     value: PropTypes.number,
 
diff --git a/Libraries/Components/Switch/Switch.js b/Libraries/Components/Switch/Switch.js
index 450c0ff4fa08..ceab1f0baea0 100644
--- a/Libraries/Components/Switch/Switch.js
+++ b/Libraries/Components/Switch/Switch.js
@@ -36,7 +36,7 @@ var Switch = React.createClass({
      */
     disabled: React.PropTypes.bool,
     /**
-     * Invoked with the new value when the value chages.
+     * Invoked with the new value when the value changes.
      */
     onValueChange: React.PropTypes.func,
     /**
diff --git a/Libraries/Components/SwitchAndroid/SwitchAndroid.android.js b/Libraries/Components/SwitchAndroid/SwitchAndroid.android.js
index feba96b8d9c3..2cbfb87ddeff 100644
--- a/Libraries/Components/SwitchAndroid/SwitchAndroid.android.js
+++ b/Libraries/Components/SwitchAndroid/SwitchAndroid.android.js
@@ -36,7 +36,7 @@ var SwitchAndroid = React.createClass({
      */
     disabled: PropTypes.bool,
     /**
-     * Invoked with the new value when the value chages.
+     * Invoked with the new value when the value changes.
      */
     onValueChange: PropTypes.func,
     /**
diff --git a/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js b/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js
index f3fb6964ca7f..bfdae5433320 100644
--- a/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js
+++ b/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js
@@ -31,7 +31,7 @@ var TabBarItemIOS = React.createClass({
     ]),
     /**
      * Items comes with a few predefined system icons. Note that if you are
-     * using them, the title and selectedIcon will be overriden with the
+     * using them, the title and selectedIcon will be overridden with the
      * system ones.
      */
     systemIcon: React.PropTypes.oneOf([
@@ -109,7 +109,7 @@ var TabBarItemIOS = React.createClass({
     } else {
       var tabContents = <View />;
     }
-    
+
     return (
       <RCTTabBarItem
         {...props}
diff --git a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js
index 2658361a9403..844889da0bea 100644
--- a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js
+++ b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js
@@ -97,7 +97,7 @@ var ToolbarAndroid = React.createClass({
      */
     navIcon: optionalImageSource,
     /**
-     * Callback that is called when an action is selected. The only argument that is passeed to the
+     * Callback that is called when an action is selected. The only argument that is passed to the
      * callback is the position of the action in the actions array.
      */
     onActionSelected: ReactPropTypes.func,
diff --git a/Libraries/Components/Touchable/Position.js b/Libraries/Components/Touchable/Position.js
index 0de7372e9811..5287e929afb5 100644
--- a/Libraries/Components/Touchable/Position.js
+++ b/Libraries/Components/Touchable/Position.js
@@ -11,7 +11,7 @@ var twoArgumentPooler = PooledClass.twoArgumentPooler;
 /**
  * Position does not expose methods for construction via an `HTMLDOMElement`,
  * because it isn't meaningful to construct such a thing without first defining
- * a frame of refrence.
+ * a frame of reference.
  *
  * @param {number} windowStartKey Key that window starts at.
  * @param {number} windowEndKey Key that window ends at.
@@ -29,4 +29,3 @@ Position.prototype.destructor = function() {
 PooledClass.addPoolingTo(Position, twoArgumentPooler);
 
 module.exports = Position;
-
diff --git a/Libraries/Components/Touchable/Touchable.js b/Libraries/Components/Touchable/Touchable.js
index 9172739ebc47..c8d67ab3e176 100644
--- a/Libraries/Components/Touchable/Touchable.js
+++ b/Libraries/Components/Touchable/Touchable.js
@@ -31,7 +31,7 @@ var queryLayoutByID = require('queryLayoutByID');
  *
  * A good tap interaction isn't as simple as you might think. There should be a
  * slight delay before showing a highlight when starting a touch. If a
- * subsequent touch move exceeds the boundary of the elemement, it should
+ * subsequent touch move exceeds the boundary of the element, it should
  * unhighlight, but if that same touch is brought back within the boundary, it
  * should rehighlight again. A touch can move in and out of that boundary
  * several times, each time toggling highlighting, but a "press" is only
@@ -574,7 +574,7 @@ var TouchableMixin = {
         curState !== States.RESPONDER_ACTIVE_LONG_PRESS_IN) {
       console.error('Attempted to transition from state `' + curState + '` to `' +
         States.RESPONDER_ACTIVE_LONG_PRESS_IN + '`, which is not supported. This is ' +
-        'most likely due to `Touchable.longPressDelayTimeout` not being cancelled.');   
+        'most likely due to `Touchable.longPressDelayTimeout` not being cancelled.');
     } else {
       this._receiveSignal(Signals.LONG_PRESS_DETECTED, e);
     }
diff --git a/Libraries/Components/ViewPager/ViewPagerAndroid.android.js b/Libraries/Components/ViewPager/ViewPagerAndroid.android.js
index ec08841ec763..e5708d5ebaf0 100644
--- a/Libraries/Components/ViewPager/ViewPagerAndroid.android.js
+++ b/Libraries/Components/ViewPager/ViewPagerAndroid.android.js
@@ -22,7 +22,7 @@ var VIEWPAGER_REF = 'viewPager';
 /**
  * Container that allows to flip left and right between child views. Each
  * child view of the `ViewPagerAndroid` will be treated as a separate page
- * and will be streched to fill the `ViewPagerAndroid`.
+ * and will be stretched to fill the `ViewPagerAndroid`.
  *
  * It is important all children are `<View>`s and not composite components.
  * You can set style properties like `padding` or `backgroundColor` for each
@@ -79,7 +79,7 @@ var ViewPagerAndroid = React.createClass({
     onPageScroll: ReactPropTypes.func,
 
     /**
-     * This callback will be caleld once ViewPager finish navigating to selected page
+     * This callback will be called once ViewPager finish navigating to selected page
      * (when user swipes between pages). The `event.nativeEvent` object passed to this
      * callback will have following fields:
      *  - position - index of page that has been selected
diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js
index 5b1ef4db0c19..976967e64a34 100644
--- a/Libraries/CustomComponents/ListView/ListView.js
+++ b/Libraries/CustomComponents/ListView/ListView.js
@@ -137,7 +137,7 @@ var ListView = React.createClass({
     renderRow: PropTypes.func.isRequired,
     /**
      * How many rows to render on initial component mount.  Use this to make
-     * it so that the first screen worth of data apears at one time instead of
+     * it so that the first screen worth of data appears at one time instead of
      * over the course of multiple frames.
      */
     initialListSize: PropTypes.number,
diff --git a/Libraries/CustomComponents/ListView/ListViewDataSource.js b/Libraries/CustomComponents/ListView/ListViewDataSource.js
index 0b1f0ecd426a..0c18aa646c0b 100644
--- a/Libraries/CustomComponents/ListView/ListViewDataSource.js
+++ b/Libraries/CustomComponents/ListView/ListViewDataSource.js
@@ -141,7 +141,7 @@ class ListViewDataSource {
 
   /**
    * Clones this `ListViewDataSource` with the specified `dataBlob` and
-   * `rowIdentities`. The `dataBlob` is just an aribitrary blob of data. At
+   * `rowIdentities`. The `dataBlob` is just an arbitrary blob of data. At
    * construction an extractor to get the interesting information was defined
    * (or the default was used).
    *
diff --git a/Libraries/CustomComponents/Navigator/Navigator.js b/Libraries/CustomComponents/Navigator/Navigator.js
index 22bb84365235..1735d6f31401 100644
--- a/Libraries/CustomComponents/Navigator/Navigator.js
+++ b/Libraries/CustomComponents/Navigator/Navigator.js
@@ -50,7 +50,7 @@ var rebound = require('rebound');
 var PropTypes = React.PropTypes;
 
 // TODO: this is not ideal because there is no guarantee that the navigator
-// is full screen, hwoever we don't have a good way to measure the actual
+// is full screen, however we don't have a good way to measure the actual
 // size of the navigator right now, so this is the next best thing.
 var SCREEN_WIDTH = Dimensions.get('window').width;
 var SCREEN_HEIGHT = Dimensions.get('window').height;
diff --git a/Libraries/Image/ImageResizeMode.js b/Libraries/Image/ImageResizeMode.js
index b947b95258f3..538287258ffc 100644
--- a/Libraries/Image/ImageResizeMode.js
+++ b/Libraries/Image/ImageResizeMode.js
@@ -31,7 +31,7 @@ var ImageResizeMode = keyMirror({
   /**
    * stretch - The image will be stretched to fill the entire frame of the
    * view without clipping. This may change the aspect ratio of the image,
-   * distoring it.
+   * distorting it.
    */
   stretch: null,
 });
diff --git a/Libraries/JavaScriptAppEngine/Initialization/SourceMap.js b/Libraries/JavaScriptAppEngine/Initialization/SourceMap.js
index 53d08f8299d1..ce42bb6ced30 100644
--- a/Libraries/JavaScriptAppEngine/Initialization/SourceMap.js
+++ b/Libraries/JavaScriptAppEngine/Initialization/SourceMap.js
@@ -327,7 +327,7 @@ define('source-map/source-map-generator', ['require', 'exports', 'module' ,  'so
    * Applies the mappings of a sub-source-map for a specific source file to the
    * source map being generated. Each mapping to the supplied source file is
    * rewritten using the supplied source map. Note: The resolution for the
-   * resulting mappings is the minimium of this map and the supplied map.
+   * resulting mappings is the minimum of this map and the supplied map.
    *
    * @param aSourceMapConsumer The source map to be applied.
    * @param aSourceFile Optional. The filename of the source file.
@@ -1058,7 +1058,7 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' ,  'sou
    *
    *   - version: Which version of the source map spec this map is following.
    *   - sources: An array of URLs to the original source files.
-   *   - names: An array of identifiers which can be referrenced by individual mappings.
+   *   - names: An array of identifiers which can be referenced by individual mappings.
    *   - sourceRoot: Optional. The URL root from which all sources are relative.
    *   - sourcesContent: Optional. An array of contents of the original source files.
    *   - mappings: A string of base64 VLQs which contain the actual mappings.
@@ -1369,7 +1369,7 @@ define('source-map/source-map-consumer', ['require', 'exports', 'module' ,  'sou
   /**
    * Returns the original source content. The only argument is the url of the
    * original source file. Returns null if no original source content is
-   * availible.
+   * available.
    */
   SourceMapConsumer.prototype.sourceContentFor =
     function SourceMapConsumer_sourceContentFor(aSource) {
diff --git a/Libraries/PushNotificationIOS/PushNotificationIOS.js b/Libraries/PushNotificationIOS/PushNotificationIOS.js
index d4735fb417a6..74a8422d67bd 100644
--- a/Libraries/PushNotificationIOS/PushNotificationIOS.js
+++ b/Libraries/PushNotificationIOS/PushNotificationIOS.js
@@ -235,7 +235,7 @@ class PushNotificationIOS {
   }
 
   /**
-   * You will never need to instansiate `PushNotificationIOS` yourself.
+   * You will never need to instantiate `PushNotificationIOS` yourself.
    * Listening to the `notification` event and invoking
    * `popInitialNotification` is sufficient
    */
diff --git a/Libraries/RCTTest/FBSnapshotTestCase/FBSnapshotTestCase.h b/Libraries/RCTTest/FBSnapshotTestCase/FBSnapshotTestCase.h
index 063e32a48d67..a3ffe02b1755 100644
--- a/Libraries/RCTTest/FBSnapshotTestCase/FBSnapshotTestCase.h
+++ b/Libraries/RCTTest/FBSnapshotTestCase/FBSnapshotTestCase.h
@@ -71,7 +71,7 @@ FBSnapshotVerifyLayerWithReferenceDirectorySuffix(layer__, identifier__, @""); \
 @property (readwrite, nonatomic, assign) BOOL recordMode;
 
 /**
- Performs the comparisong or records a snapshot of the layer if recordMode is YES.
+ Performs the comparisons or records a snapshot of the layer if recordMode is YES.
  @param layer The Layer to snapshot
  @param referenceImagesDirectory The directory in which reference images are stored.
  @param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method.
@@ -84,7 +84,7 @@ FBSnapshotVerifyLayerWithReferenceDirectorySuffix(layer__, identifier__, @""); \
                          error:(NSError **)errorPtr;
 
 /**
- Performs the comparisong or records a snapshot of the view if recordMode is YES.
+ Performs the comparisons or records a snapshot of the view if recordMode is YES.
  @param view The view to snapshot
  @param referenceImagesDirectory The directory in which reference images are stored.
  @param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method.
diff --git a/Libraries/RCTTest/FBSnapshotTestCase/FBSnapshotTestController.h b/Libraries/RCTTest/FBSnapshotTestCase/FBSnapshotTestController.h
index 349384d8f8dd..449e3983a7b3 100644
--- a/Libraries/RCTTest/FBSnapshotTestCase/FBSnapshotTestController.h
+++ b/Libraries/RCTTest/FBSnapshotTestCase/FBSnapshotTestController.h
@@ -97,7 +97,7 @@ extern NSString *const FBReferenceImageFilePathKey;
 
 
 /**
- The directory in which referfence images are stored.
+ The directory in which reference images are stored.
  */
 @property (readwrite, nonatomic, copy) NSString *referenceImagesDirectory;
 
diff --git a/Libraries/ReactNative/ReactNativeEventEmitter.js b/Libraries/ReactNative/ReactNativeEventEmitter.js
index b0bb5659809b..ac8854b6cb65 100644
--- a/Libraries/ReactNative/ReactNativeEventEmitter.js
+++ b/Libraries/ReactNative/ReactNativeEventEmitter.js
@@ -107,7 +107,7 @@ var ReactNativeEventEmitter = merge(ReactEventEmitterMixin, {
    *
    * @see receiveEvent.
    *
-   * @param {rootNodeID} rootNodeID React root node ID that event occured on.
+   * @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.
    */
@@ -127,9 +127,9 @@ var ReactNativeEventEmitter = merge(ReactEventEmitterMixin, {
   },
 
   /**
-   * Publically exposed method on module for native objc to invoke when a top
+   * 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 occured on.
+   * @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.
    */
@@ -183,7 +183,7 @@ var ReactNativeEventEmitter = merge(ReactEventEmitterMixin, {
 
     for (var jj = 0; jj < changedTouches.length; jj++) {
       var touch = changedTouches[jj];
-      // Touch objects can fullfill the role of `DOM` `Event` objects if we set
+      // 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;
diff --git a/Libraries/ReactNative/ReactNativeReconcileTransaction.js b/Libraries/ReactNative/ReactNativeReconcileTransaction.js
index 309630e3cc36..b6721964988f 100644
--- a/Libraries/ReactNative/ReactNativeReconcileTransaction.js
+++ b/Libraries/ReactNative/ReactNativeReconcileTransaction.js
@@ -66,7 +66,7 @@ var Mixin = {
    * @see Transaction
    * @abstract
    * @final
-   * @return {array<object>} List of operation wrap proceedures.
+   * @return {array<object>} List of operation wrap procedures.
    *   TODO: convert to array<TransactionWrapper>
    */
   getTransactionWrappers: function() {
@@ -83,7 +83,7 @@ var Mixin = {
 
   /**
    * `PooledClass` looks for this, and will invoke this before allowing this
-   * instance to be resused.
+   * instance to be reused.
    */
   destructor: function() {
     CallbackQueue.release(this.reactMountReady);
diff --git a/Libraries/StyleSheet/processColor.js b/Libraries/StyleSheet/processColor.js
index e259113e3e80..09ea0369733c 100644
--- a/Libraries/StyleSheet/processColor.js
+++ b/Libraries/StyleSheet/processColor.js
@@ -30,7 +30,7 @@ function processColor(color) {
         // Android use 32 bit *signed* integer to represent the color
         // We utilize the fact that bitwise operations in JS also operates on
         // signed 32 bit integers, so that we can use those to convert from
-        // *unsiged* to *signed* 32bit int that way.
+        // *unsigned* to *signed* 32bit int that way.
         colorInt = colorInt | 0x0;
       }
       return colorInt;
diff --git a/Libraries/Text/RCTTextField.m b/Libraries/Text/RCTTextField.m
index b8d172cc2894..cb1aba3b91bc 100644
--- a/Libraries/Text/RCTTextField.m
+++ b/Libraries/Text/RCTTextField.m
@@ -58,7 +58,7 @@ - (void)sendKeyValueForString:(NSString *)string
                                eventCount:_nativeEventCount];
 }
 
-// This method is overriden for `onKeyPress`. The manager
+// This method is overridden for `onKeyPress`. The manager
 // will not send a keyPress for text that was pasted.
 - (void)paste:(id)sender
 {
diff --git a/Libraries/Text/Text.js b/Libraries/Text/Text.js
index 8d9f68fba864..e86f69fc195a 100644
--- a/Libraries/Text/Text.js
+++ b/Libraries/Text/Text.js
@@ -71,7 +71,7 @@ const viewConfig = {
 const Text = React.createClass({
   propTypes: {
     /**
-     * Used to truncate the text with an elipsis after computing the text
+     * Used to truncate the text with an ellipsis after computing the text
      * layout, including line wrapping, such that the total number of lines
      * does not exceed this number.
      */
diff --git a/Libraries/Utilities/BackAndroid.android.js b/Libraries/Utilities/BackAndroid.android.js
index d7f3a482be68..f828f2f7e8e9 100644
--- a/Libraries/Utilities/BackAndroid.android.js
+++ b/Libraries/Utilities/BackAndroid.android.js
@@ -36,7 +36,7 @@ RCTDeviceEventEmitter.addListener(DEVICE_BACK_EVENT, function() {
 });
 
 /**
- * Detect hardware back button presses, and programatically invoke the default back button
+ * Detect hardware back button presses, and programmatically invoke the default back button
  * functionality to exit the app if there are no listeners or if none of the listeners return true.
  *
  * Example:
diff --git a/Libraries/Utilities/CSSVarConfig.js b/Libraries/Utilities/CSSVarConfig.js
index cb018be0af59..d3177310ce9b 100644
--- a/Libraries/Utilities/CSSVarConfig.js
+++ b/Libraries/Utilities/CSSVarConfig.js
@@ -5,7 +5,7 @@
  */
 'use strict';
 
-// this a partial list of the contants in CSSConstants:: from PHP that are applicable to mobile
+// this a partial list of the constants in CSSConstants:: from PHP that are applicable to mobile
 
 module.exports = {
   'fbui-accent-blue': '#5890ff',
diff --git a/Libraries/Utilities/buildStyleInterpolator.js b/Libraries/Utilities/buildStyleInterpolator.js
index 1ff93d106400..0c0fa7fd1221 100644
--- a/Libraries/Utilities/buildStyleInterpolator.js
+++ b/Libraries/Utilities/buildStyleInterpolator.js
@@ -102,7 +102,7 @@ var ARGUMENT_NAMES_RE = /([^\s,]+)/g;
  *
  *  inline(inlineMe, ['hi', 'bye']);  // "hi = bye + bye;"
  *
- * @param {function} func Any simple function whos arguments can be replaced via a regex.
+ * @param {function} func Any simple function who's arguments can be replaced via a regex.
  * @param {array<string>} replaceWithArgs Corresponding names of variables
  * within an environment, to replace `func` args with.
  * @return {string} Resulting function body string.
diff --git a/Libraries/Utilities/mergeIntoFast.js b/Libraries/Utilities/mergeIntoFast.js
index 1a97d07b7b17..b7160875a453 100644
--- a/Libraries/Utilities/mergeIntoFast.js
+++ b/Libraries/Utilities/mergeIntoFast.js
@@ -13,7 +13,7 @@
 
 /**
  * Faster version of `mergeInto` that doesn't check its arguments and
- * also copies over prototye inherited properties.
+ * also copies over prototype inherited properties.
  *
  * @param {object} one Object to assign to.
  * @param {object} two Object to assign from.
diff --git a/Libraries/Utilities/truncate.js b/Libraries/Utilities/truncate.js
index a15da571bfde..462a023d130a 100644
--- a/Libraries/Utilities/truncate.js
+++ b/Libraries/Utilities/truncate.js
@@ -25,7 +25,7 @@ var defaultOptions = {
   elipsis: '...',
 };
 
-// maxChars (including elipsis)
+// maxChars (including ellipsis)
 var truncate = function(
   str: ?string,
   maxChars: number,

From 79799af418faf7b4a1084ba5e2139eb9ccf3894c Mon Sep 17 00:00:00 2001
From: Kureev Alexey <kureev-mail@ya.ru>
Date: Tue, 15 Dec 2015 18:45:08 +0100
Subject: [PATCH 0390/1411] Reword section description

---
 docs/LinkingLibraries.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/LinkingLibraries.md b/docs/LinkingLibraries.md
index 3ffe7b4b8986..eda6363bbe46 100644
--- a/docs/LinkingLibraries.md
+++ b/docs/LinkingLibraries.md
@@ -26,7 +26,7 @@ error as soon as you try to use the library._
 
 ### Automatic linking
 
-There is a way to link your native dependencies automatically by using [rnpm](http://github.com/rnpm/rnpm):
+"[rnpm](http://github.com/rnpm/rnpm)" is a community project that allows linking of native dependencies automatically:
 
 #### Step 1
 

From e6d498b99b984187a56991c112c6d5df160ad538 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Tue, 15 Dec 2015 10:42:08 -0800
Subject: [PATCH 0391/1411] Fix case where measure is called with a view that
 is now off screen (and removed from clipping)

Reviewed By: astreet

Differential Revision: D2760119

fb-gh-sync-id: cf2723ddc94de64bba961e9390ce54f39ca4651f
---
 .../facebook/react/uimanager/NativeViewHierarchyManager.java | 5 +++++
 .../main/java/com/facebook/react/uimanager/RootViewUtil.java | 4 +++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
index dd40b7a16a95..2193fa3d4837 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
@@ -467,6 +467,11 @@ public void measure(int tag, int[] outputBuffer) {
     }
 
     View rootView = (View) RootViewUtil.getRootView(v);
+    // It is possible that the RootView can't be found because this view is no longer on the screen
+    // and has been removed by clipping
+    if (rootView == null) {
+      throw new NoSuchNativeViewException("Native view " + tag + " is no longer on screen");
+    }
     rootView.getLocationInWindow(outputBuffer);
     int rootX = outputBuffer[0];
     int rootY = outputBuffer[1];
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/RootViewUtil.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/RootViewUtil.java
index e12a76488a88..f9076cbe45b8 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/RootViewUtil.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/RootViewUtil.java
@@ -26,7 +26,9 @@ public static RootView getRootView(View reactView) {
         return (RootView) current;
       }
       ViewParent next = current.getParent();
-      Assertions.assertNotNull(next);
+      if (next == null) {
+        return null;
+      }
       Assertions.assertCondition(next instanceof View);
       current = (View) next;
     }

From 12bec39da12d1acde94e620b67bcc29ee5982c6f Mon Sep 17 00:00:00 2001
From: Alexander Blom <blom@fb.com>
Date: Tue, 15 Dec 2015 10:42:54 -0800
Subject: [PATCH 0392/1411] Fix cxxbridge usage of SettableFuture

Reviewed By: mhorowitz

Differential Revision: D2759591

fb-gh-sync-id: 920b4a5c934c1bd9d196ccbeec0799a54001b85d
---
 .../facebook/react/bridge/queue/MessageQueueThreadImpl.java | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java
index 453351632bc1..48328da25abc 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java
@@ -10,8 +10,10 @@
 package com.facebook.react.bridge.queue;
 
 import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 import android.os.Looper;
 
@@ -170,8 +172,8 @@ public void run() {
           name,
           simpleSettableFuture.get(5000, TimeUnit.MILLISECONDS),
           exceptionHandler);
-    } catch (Throwable t) {
-      throw new RuntimeException(t);
+    } catch (InterruptedException | ExecutionException | TimeoutException e) {
+      throw new RuntimeException(e);
     }
   }
 }

From d03d28684a313bcc9c7fb59416c8af377cb6e363 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Tue, 15 Dec 2015 10:50:36 -0800
Subject: [PATCH 0393/1411] Simplified session management

Reviewed By: javache

Differential Revision: D2355911

fb-gh-sync-id: 57748dd6e5fe2ab6954c23526c2f5e8b46fd526b
---
 React/Base/RCTBridge.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/React/Base/RCTBridge.h b/React/Base/RCTBridge.h
index a67176e9c72a..06ae8e8ead9f 100644
--- a/React/Base/RCTBridge.h
+++ b/React/Base/RCTBridge.h
@@ -186,11 +186,11 @@ RCT_EXTERN BOOL RCTBridgeModuleClassIsRegistered(Class);
  *
  * If you need to access a module, you can do so as soon as the bridge has been
  * initialized, by calling `[bridge moduleForClass:]`. If you need to know when
- * an individual module has been instantiated, use the `RCTDidInitializeModule`
- * notification instead.
+ * an individual module has been instantiated, add an observer for the
+ * `RCTDidInitializeModuleNotification` instead.
  */
 RCT_EXTERN NSString *const RCTDidCreateNativeModules
-__deprecated_msg("Use RCTDidInitializeModule to observe init of individual modules");
+__deprecated_msg("Use RCTDidInitializeModuleNotification to observe init of individual modules");
 
 /**
  * Accessing the modules property causes all modules to be eagerly initialized,

From 7f92aea37118f39d742c98b5f86f0416ca1ff2fa Mon Sep 17 00:00:00 2001
From: Mike Armstrong <mikea@fb.com>
Date: Tue, 15 Dec 2015 10:52:41 -0800
Subject: [PATCH 0394/1411] JSC Heap snapshot and capture

Reviewed By: astreet

Differential Revision: D2699681

fb-gh-sync-id: 81617187abec6d9bc1ffe3da02513c6875d0b93b
---
 .../src/main/jni/react/JSCExecutor.cpp        |   3 +
 ReactAndroid/src/main/jni/react/JSCMemory.cpp | 157 ++++++++++++++++++
 ReactAndroid/src/main/jni/react/JSCMemory.h   |  11 ++
 3 files changed, 171 insertions(+)
 create mode 100644 ReactAndroid/src/main/jni/react/JSCMemory.cpp
 create mode 100644 ReactAndroid/src/main/jni/react/JSCMemory.h

diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index 8b954f156835..e38e1a6867d8 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -30,6 +30,7 @@ using fbsystrace::FbSystraceSection;
 
 // Add native performance markers support
 #include <react/JSCPerfLogging.h>
+#include <react/JSCMemory.h>
 
 #ifdef WITH_FB_JSC_TUNING
 #include <jsc_config_android.h>
@@ -132,6 +133,8 @@ JSCExecutor::JSCExecutor(FlushImmediateCallback cb) :
   addNativeProfilingHooks(m_context);
   addNativePerfLoggingHooks(m_context);
   #endif
+
+  addNativeMemoryHooks(m_context);
 }
 
 JSCExecutor::~JSCExecutor() {
diff --git a/ReactAndroid/src/main/jni/react/JSCMemory.cpp b/ReactAndroid/src/main/jni/react/JSCMemory.cpp
new file mode 100644
index 000000000000..585fd64c470b
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/JSCMemory.cpp
@@ -0,0 +1,157 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#include <stdio.h>
+#include <string.h>
+#include <JavaScriptCore/JavaScript.h>
+#include <JavaScriptCore/API/JSProfilerPrivate.h>
+#include "JSCHelpers.h"
+
+#include "Value.h"
+
+#if WITH_FB_MEMORY_PROFILING
+
+static JSValueRef nativeEnableAllocationTag(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[],
+    JSValueRef* exception) {
+
+  if (argumentCount < 1) {
+    if (exception) {
+      *exception = facebook::react::makeJSCException(
+        ctx,
+        "nativeEnableAllocationTag requires a single boolean argument");
+    }
+    return JSValueMakeUndefined(ctx);
+  }
+
+  JSEnableAllocationTag(ctx, JSValueToBoolean(ctx, arguments[0]));
+  return JSValueMakeUndefined(ctx);
+}
+
+static JSValueRef nativeAllocationPushTag(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[],
+    JSValueRef* exception) {
+  std::string marker;
+
+  if (argumentCount < 1) {
+    if (exception) {
+      *exception = facebook::react::makeJSCException(
+        ctx,
+        "nativeAllocationPushTag requires at least 1 argument");
+    }
+    return JSValueMakeUndefined(ctx);
+  }
+
+  JSStringRef tag = JSValueToStringCopy(ctx, arguments[0], exception);
+  JSPushAllocationTag(ctx, facebook::react::String::ref(tag).str().c_str());
+  JSStringRelease(tag);
+  return JSValueMakeUndefined(ctx);
+}
+
+static JSValueRef nativeAllocationPopTag(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[],
+    JSValueRef* exception) {
+  JSPopAllocationTag(ctx);
+  return JSValueMakeUndefined(ctx);
+}
+
+static JSValueRef nativeForceSyncGC(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[],
+    JSValueRef* exception) {
+  JSSynchronousGarbageCollectForDebugging(ctx);
+  return JSValueMakeUndefined(ctx);
+}
+
+static JSValueRef nativeCaptureStart(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[],
+    JSValueRef* exception) {
+  if (argumentCount < 1) {
+    if (exception) {
+      *exception = facebook::react::makeJSCException(
+        ctx,
+        "nativeCaptureStart requires at least 1 argument");
+    }
+    return JSValueMakeUndefined(ctx);
+  }
+
+  JSStringRef outputFilename = JSValueToStringCopy(ctx, arguments[0], exception);
+  std::string finalFilename =
+    std::string("/sdcard/") +
+    facebook::react::String::ref(outputFilename).str();
+  JSHeapCaptureStart(ctx, finalFilename.c_str());
+  JSStringRelease(outputFilename);
+  return JSValueMakeUndefined(ctx);
+}
+
+static JSValueRef nativeCaptureEnd(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[],
+    JSValueRef* exception) {
+  JSHeapCaptureEnd(ctx);
+  return JSValueMakeUndefined(ctx);
+}
+
+static JSValueRef nativeHeapDump(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[],
+    JSValueRef* exception) {
+  if (argumentCount < 1) {
+    if (exception) {
+      *exception = facebook::react::makeJSCException(
+        ctx,
+        "nativeHeapDump requires at least 1 argument");
+    }
+    return JSValueMakeUndefined(ctx);
+  }
+
+  JSStringRef outputFilename = JSValueToStringCopy(ctx, arguments[0], exception);
+  std::string finalFilename =
+    std::string("/sdcard/") +
+    facebook::react::String::ref(outputFilename).str();
+  JSHeapDump(ctx, finalFilename.c_str());
+  JSStringRelease(outputFilename);
+  return JSValueMakeUndefined(ctx);
+}
+#endif
+
+namespace facebook {
+namespace react {
+
+void addNativeMemoryHooks(JSGlobalContextRef ctx) {
+#if WITH_FB_MEMORY_PROFILING
+  installGlobalFunction(ctx, "nativeEnableAllocationTag", nativeEnableAllocationTag);
+  installGlobalFunction(ctx, "nativeAllocationPushTag", nativeAllocationPushTag);
+  installGlobalFunction(ctx, "nativeAllocationPopTag", nativeAllocationPopTag);
+  installGlobalFunction(ctx, "nativeForceSyncGC", nativeForceSyncGC);
+  installGlobalFunction(ctx, "nativeCaptureStart", nativeCaptureStart);
+  installGlobalFunction(ctx, "nativeCaptureEnd", nativeCaptureEnd);
+  installGlobalFunction(ctx, "nativeHeapDump", nativeHeapDump);
+#endif
+}
+
+} }
diff --git a/ReactAndroid/src/main/jni/react/JSCMemory.h b/ReactAndroid/src/main/jni/react/JSCMemory.h
new file mode 100644
index 000000000000..6e05bba709ec
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/JSCMemory.h
@@ -0,0 +1,11 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+#include <JavaScriptCore/JSContextRef.h>
+namespace facebook {
+namespace react {
+
+void addNativeMemoryHooks(JSGlobalContextRef ctx);
+
+} }

From db69004300faf1d850f8127a57859d88205450a7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= <renaudeau.gaetan@gmail.com>
Date: Tue, 15 Dec 2015 11:02:15 -0800
Subject: [PATCH 0395/1411] Fix events to go through the navigation bar layers

Summary:
Here is a showcase of 2 bugs that are fixed with this PR: touchability of title, touchability of overlapped top-right positionned (under the navbar).

(i'm using the inspector)

![bug](https://cloud.githubusercontent.com/assets/211411/11809475/7b6ba71a-a327-11e5-90cf-cbe58637c447.gif)

I have a navbar with a back button, a Title area with a **Green Circle**, a Right area with nothing inside.
In my Screen View, I've positioned in absolute a **Red Rectangle** just on the top-right corner under the navbar.

I want my **Green Circle** and **Red Rectangle** to be touchable but in current React Native version, this is not possible: as shown in the gif, the 3 LeftButton/Title/RightButton wrapper View are **catching the touch events**. My PR allows events to go through these wrapper View.

**After the fix:**

![nobug](https://cloud.githubusercontent.com/assets/211411/11809590/3b803994-a328-11e5-81f7-c1a3bab45e1b.gif)

Complementary Notes:
- in the case of the Red Rectangle, only the lower part of it i
Closes https://github.com/facebook/react-native/pull/4786

Reviewed By: svcscm

Differential Revision: D2760205

Pulled By: androidtrunkagent

fb-gh-sync-id: 55bb141c8f61ab537ff9e832b65b04cb904dfeb9
---
 Libraries/CustomComponents/Navigator/NavigatorNavigationBar.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Libraries/CustomComponents/Navigator/NavigatorNavigationBar.js b/Libraries/CustomComponents/Navigator/NavigatorNavigationBar.js
index b6fbcdc378e5..a5be41abf2d4 100644
--- a/Libraries/CustomComponents/Navigator/NavigatorNavigationBar.js
+++ b/Libraries/CustomComponents/Navigator/NavigatorNavigationBar.js
@@ -195,6 +195,7 @@ var NavigatorNavigationBar = React.createClass({
         ref={(ref) => {
           this._components[componentName] = this._components[componentName].set(route, ref);
         }}
+        pointerEvents="box-none"
         style={initialStage[componentName]}>
         {content}
       </View>

From adaadadde8ac8175f5b165b605e02d61db7a4fc2 Mon Sep 17 00:00:00 2001
From: Pedro Belo <pedro@heroku.com>
Date: Tue, 15 Dec 2015 11:32:56 -0800
Subject: [PATCH 0396/1411] showcase Lugg's android app

---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 7b57b35f4e7c..123d6c702477 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -254,6 +254,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/loaddocs/id1041596066',
     author: 'LoadDocs',
   },
+  {
+    name: 'Lugg – Your On-Demand Mover',
+    icon: 'http://lh3.googleusercontent.com/EV9z7kRRME2KPMBRNHnje7bBNEl_Why2CFq-MfKzBC88uSFJTYr1HO3-nPt-JuVJwKFb=w300-rw',
+    link: 'https://play.google.com/store/apps/details?id=com.lugg',
+    author: 'Lugg',
+  },
   {
     name: 'Lumpen Radio',
     icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple1/v4/46/43/00/464300b1-fae3-9640-d4a2-0eb050ea3ff2/mzl.xjjawige.png',

From 7377fb8baf4b78db9be121bc8189d99ff5f08efa Mon Sep 17 00:00:00 2001
From: Oleg Lokhvitsky <olegbl@fb.com>
Date: Tue, 15 Dec 2015 12:01:27 -0800
Subject: [PATCH 0397/1411] Fix Navigator.NavigationBar Title interactivity

Reviewed By: hedgerwang

Differential Revision: D2755832

fb-gh-sync-id: 22f937ba271703d49f54acf2e3cdbf1994fad878
---
 .../Navigator/NavigatorNavigationBar.js                | 10 +++++-----
 .../Navigator/NavigatorNavigationBarStylesIOS.js       |  6 +++---
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/Libraries/CustomComponents/Navigator/NavigatorNavigationBar.js b/Libraries/CustomComponents/Navigator/NavigatorNavigationBar.js
index a5be41abf2d4..17d36a14df7c 100644
--- a/Libraries/CustomComponents/Navigator/NavigatorNavigationBar.js
+++ b/Libraries/CustomComponents/Navigator/NavigatorNavigationBar.js
@@ -153,11 +153,11 @@ var NavigatorNavigationBar = React.createClass({
       height: this.props.navigationStyles.General.TotalNavHeight,
     };
     var navState = this.props.navState;
-    var components = COMPONENT_NAMES.map(function (componentName) {
-      return navState.routeStack.map(
-        this._getComponent.bind(this, componentName)
-      );
-    }, this);
+    var components = navState.routeStack.map((route, index) =>
+      COMPONENT_NAMES.map(componentName =>
+        this._getComponent(componentName, route, index)
+      )
+    );
 
     return (
       <View style={[styles.navBarContainer, navBarStyle, this.props.style]}>
diff --git a/Libraries/CustomComponents/Navigator/NavigatorNavigationBarStylesIOS.js b/Libraries/CustomComponents/Navigator/NavigatorNavigationBarStylesIOS.js
index 9e14677519a4..1ae2a94eaa0e 100644
--- a/Libraries/CustomComponents/Navigator/NavigatorNavigationBarStylesIOS.js
+++ b/Libraries/CustomComponents/Navigator/NavigatorNavigationBarStylesIOS.js
@@ -78,17 +78,17 @@ var Stages = {
   Left: {
     Title: merge(BASE_STYLES.Title, { left: -SCREEN_WIDTH / 2, opacity: 0 }),
     LeftButton: merge(BASE_STYLES.LeftButton, { left: -SCREEN_WIDTH / 3, opacity: 0 }),
-    RightButton: merge(BASE_STYLES.RightButton, { left: SCREEN_WIDTH / 3, opacity: 0 }),
+    RightButton: merge(BASE_STYLES.RightButton, { opacity: 0 }),
   },
   Center: {
     Title: merge(BASE_STYLES.Title, { left: 0, opacity: 1 }),
     LeftButton: merge(BASE_STYLES.LeftButton, { left: 0, opacity: 1 }),
-    RightButton: merge(BASE_STYLES.RightButton, { left: 2 * SCREEN_WIDTH / 3 - 0, opacity: 1 }),
+    RightButton: merge(BASE_STYLES.RightButton, { opacity: 1 }),
   },
   Right: {
     Title: merge(BASE_STYLES.Title, { left: SCREEN_WIDTH / 2, opacity: 0 }),
     LeftButton: merge(BASE_STYLES.LeftButton, { left: 0, opacity: 0 }),
-    RightButton: merge(BASE_STYLES.RightButton, { left: SCREEN_WIDTH, opacity: 0 }),
+    RightButton: merge(BASE_STYLES.RightButton, { opacity: 0 }),
   },
 };
 

From 3d4889b5cf2c97bdef55912ba9bb8ac5eb9c2976 Mon Sep 17 00:00:00 2001
From: Felix Oghina <foghina@fb.com>
Date: Tue, 15 Dec 2015 12:16:19 -0800
Subject: [PATCH 0398/1411] return packager URL instead of proxy URL when
 debugging

Summary:
JS relies on the URL returned by SourceCodeModule to load packager assets. Because we currently return localhost when debugging (because that's the URL Chrome uses), assets don't load when debugging. This makes it so SourceCodeModule still returns the package URL relative to the emulator / device even when debugging.

public

Reviewed By: astreet

Differential Revision: D2759710

fb-gh-sync-id: bab6a88ef044b8b4d971381e3b23c59fa9aa2ed0
---
 .../com/facebook/react/ReactInstanceManagerImpl.java   |  3 ++-
 .../java/com/facebook/react/bridge/JSBundleLoader.java | 10 +++++++---
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index e0ce3c97e47b..7fd3668093b4 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -507,7 +507,8 @@ private void onReloadWithJSDebugger(JavaJSExecutor jsExecutor) {
     recreateReactContextInBackground(
         new ProxyJavaScriptExecutor(jsExecutor),
         JSBundleLoader.createRemoteDebuggerBundleLoader(
-            mDevSupportManager.getJSBundleURLForRemoteDebugging()));
+            mDevSupportManager.getJSBundleURLForRemoteDebugging(),
+            mDevSupportManager.getSourceUrl()));
   }
 
   private void onJSBundleLoadedFromServer() {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java
index c784cd00791f..90d97e17ef85 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java
@@ -68,18 +68,22 @@ public String getSourceUrl() {
   /**
    * This loader is used when proxy debugging is enabled. In that case there is no point in fetching
    * the bundle from device as remote executor will have to do it anyway.
+   *
+   * @param proxySourceURL the URL to load the JS bundle from in Chrome
+   * @param realSourceURL the URL to report as the source URL, e.g. for asset loading
    */
   public static JSBundleLoader createRemoteDebuggerBundleLoader(
-      final String sourceURL) {
+      final String proxySourceURL,
+      final String realSourceURL) {
     return new JSBundleLoader() {
       @Override
       public void loadScript(ReactBridge bridge) {
-        bridge.loadScriptFromFile(null, sourceURL);
+        bridge.loadScriptFromFile(null, proxySourceURL);
       }
 
       @Override
       public String getSourceUrl() {
-        return sourceURL;
+        return realSourceURL;
       }
     };
   }

From f43e864ff612c8a42ad78aee79b9186532e14a1f Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Tue, 15 Dec 2015 13:38:48 -0800
Subject: [PATCH 0399/1411] Add RCTJSCProfiler to React.xcodeproj

Summary:
public

The `RCTJSCProfiler` was created but hadn't been added to the OSS xcodeproj, add it now.

Reviewed By: mgd

Differential Revision: D2761259

fb-gh-sync-id: 3287bb48c39cd2ff1a73fd03f53f67fe95aaac4b
---
 React/React.xcodeproj/project.pbxproj | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj
index fa4397f54725..39f3b8633319 100644
--- a/React/React.xcodeproj/project.pbxproj
+++ b/React/React.xcodeproj/project.pbxproj
@@ -60,6 +60,7 @@
 		1450FF871BCFF28A00208362 /* RCTProfileTrampoline-arm.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF821BCFF28A00208362 /* RCTProfileTrampoline-arm.S */; };
 		1450FF881BCFF28A00208362 /* RCTProfileTrampoline-arm64.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF831BCFF28A00208362 /* RCTProfileTrampoline-arm64.S */; };
 		1450FF8A1BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S in Sources */ = {isa = PBXBuildFile; fileRef = 1450FF851BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S */; };
+		14A43DF31C20B1C900794BC8 /* RCTJSCProfiler.m in Sources */ = {isa = PBXBuildFile; fileRef = 14A43DF21C20B1C900794BC8 /* RCTJSCProfiler.m */; };
 		14C2CA711B3AC63800E6CBB2 /* RCTModuleMethod.m in Sources */ = {isa = PBXBuildFile; fileRef = 14C2CA701B3AC63800E6CBB2 /* RCTModuleMethod.m */; };
 		14C2CA741B3AC64300E6CBB2 /* RCTModuleData.m in Sources */ = {isa = PBXBuildFile; fileRef = 14C2CA731B3AC64300E6CBB2 /* RCTModuleData.m */; };
 		14C2CA761B3AC64F00E6CBB2 /* RCTFrameUpdate.m in Sources */ = {isa = PBXBuildFile; fileRef = 14C2CA751B3AC64F00E6CBB2 /* RCTFrameUpdate.m */; };
@@ -222,6 +223,8 @@
 		1450FF851BCFF28A00208362 /* RCTProfileTrampoline-x86_64.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = "RCTProfileTrampoline-x86_64.S"; sourceTree = "<group>"; };
 		1482F9E61B55B927000ADFF3 /* RCTBridgeDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTBridgeDelegate.h; sourceTree = "<group>"; };
 		14A43DB81C1F849600794BC8 /* RCTBridge+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RCTBridge+Private.h"; sourceTree = "<group>"; };
+		14A43DF11C20B1C900794BC8 /* RCTJSCProfiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTJSCProfiler.h; sourceTree = "<group>"; };
+		14A43DF21C20B1C900794BC8 /* RCTJSCProfiler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTJSCProfiler.m; sourceTree = "<group>"; };
 		14BF717F1C04793D00C97D0C /* RCTProfileTrampoline-i386.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = "RCTProfileTrampoline-i386.S"; sourceTree = "<group>"; };
 		14BF71811C04795500C97D0C /* RCTMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTMacros.h; sourceTree = "<group>"; };
 		14C2CA6F1B3AC63800E6CBB2 /* RCTModuleMethod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTModuleMethod.h; sourceTree = "<group>"; };
@@ -445,6 +448,8 @@
 		1450FF7F1BCFF28A00208362 /* Profiler */ = {
 			isa = PBXGroup;
 			children = (
+				14A43DF11C20B1C900794BC8 /* RCTJSCProfiler.h */,
+				14A43DF21C20B1C900794BC8 /* RCTJSCProfiler.m */,
 				14BF71811C04795500C97D0C /* RCTMacros.h */,
 				14F7A0EB1BDA3B3C003C6C10 /* RCTPerfMonitor.m */,
 				14F7A0EE1BDA714B003C6C10 /* RCTFPSGraph.h */,
@@ -636,6 +641,7 @@
 				13456E961ADAD482009F94A7 /* RCTConvert+MapKit.m in Sources */,
 				13723B501A82FD3C00F88898 /* RCTStatusBarManager.m in Sources */,
 				000E6CEB1AB0E980000CDF4D /* RCTSourceCode.m in Sources */,
+				14A43DF31C20B1C900794BC8 /* RCTJSCProfiler.m in Sources */,
 				133CAE8E1B8E5CFD00F6AD92 /* RCTDatePicker.m in Sources */,
 				14C2CA761B3AC64F00E6CBB2 /* RCTFrameUpdate.m in Sources */,
 				13B07FEF1A69327A00A75B9A /* RCTAlertManager.m in Sources */,

From 055d4e29ee70f6d056b2716eb987742535829cd4 Mon Sep 17 00:00:00 2001
From: Harry Moreno <morenoh149@gmail.com>
Date: Tue, 15 Dec 2015 17:34:26 -0500
Subject: [PATCH 0400/1411] Add link to more info for ReadableMap and
 ReadableArray

---
 docs/NativeModulesAndroid.md | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/docs/NativeModulesAndroid.md b/docs/NativeModulesAndroid.md
index 56a8c2f83a6d..d75c60ceaf1f 100644
--- a/docs/NativeModulesAndroid.md
+++ b/docs/NativeModulesAndroid.md
@@ -86,6 +86,8 @@ ReadableMap -> Object
 ReadableArray -> Array
 ```
 
+Read more about [ReadableMap](https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableMap.java) and [ReadableArray](https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableArray.java)
+
 ### Register the Module
 
 The last step within Java is to register the Module; this happens in the `createNativeModules` of your apps package. If a module is not registered it will not be available from JavaScript.
@@ -140,7 +142,7 @@ module.exports = NativeModules.ToastAndroid;
 Now, from your other JavaScript file you can call the method like this:
 
 ```js
-var ToastAndroid = require('./ToastAndroid'); 
+var ToastAndroid = require('./ToastAndroid');
 
 ToastAndroid.show('Awesome', ToastAndroid.SHORT);
 ```

From e39657aaae47c1d9afee10c771d5c487d53efadb Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Tue, 15 Dec 2015 14:51:10 -0800
Subject: [PATCH 0401/1411] RCTPerformanceNow -> nativePerformanceNow

Summary:
public

Rename `RCTPerformanceNow` to `nativePerformanceNow` to be consistent with Android
and the pattern we've been following where the native functions exposed to JSC
are prefixed with `native`.

Also change it to return fractional milliseconds, as the web (`performance.now`)
does: https://developer.mozilla.org/en-US/docs/Web/API/Performance/now

Reviewed By: mikearmstrong001

Differential Revision: D2755287

fb-gh-sync-id: 2acada5673633858ae0bbcdcfae554183e36cb24
---
 React/Executors/RCTContextExecutor.m | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/React/Executors/RCTContextExecutor.m b/React/Executors/RCTContextExecutor.m
index 5d8504fb24bc..0bf9c0caf9ac 100644
--- a/React/Executors/RCTContextExecutor.m
+++ b/React/Executors/RCTContextExecutor.m
@@ -260,8 +260,8 @@ - (void)setUp
       [weakBridge handleBuffer:calls batchEnded:NO];
     };
 
-    context[@"RCTPerformanceNow"] = ^{
-      return CACurrentMediaTime() * 1000 * 1000;
+    context[@"nativePerformanceNow"] = ^{
+      return @(CACurrentMediaTime() * 1000);
     };
 
 #if RCT_DEV

From 67c6afd14b835f59832e7e19f95f22160c3f1abb Mon Sep 17 00:00:00 2001
From: Hedger Wang <hedger@fb.com>
Date: Tue, 15 Dec 2015 15:38:43 -0800
Subject: [PATCH 0402/1411] immediatelyResetRouteStack does not update
 Navigator's title

Summary:
re-render the whole navigation bar while calling immediatelyResetRouteStack
from navigator.

Reviewed By: zjj010104

Differential Revision: D2751922

fb-gh-sync-id: 79bcd1457a96eaf3ca94b81da9bfecbec7f8af46
---
 .../CustomComponents/Navigator/Navigator.js   |  1 +
 .../Navigator/NavigatorNavigationBar.js       | 24 +++++++++++++++----
 2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/Libraries/CustomComponents/Navigator/Navigator.js b/Libraries/CustomComponents/Navigator/Navigator.js
index 1735d6f31401..0050846fa80c 100644
--- a/Libraries/CustomComponents/Navigator/Navigator.js
+++ b/Libraries/CustomComponents/Navigator/Navigator.js
@@ -375,6 +375,7 @@ var Navigator = React.createClass({
       transitionQueue: [],
     }, () => {
       this._handleSpringUpdate();
+      this._navBar && this._navBar.immediatelyRefresh();
     });
   },
 
diff --git a/Libraries/CustomComponents/Navigator/NavigatorNavigationBar.js b/Libraries/CustomComponents/Navigator/NavigatorNavigationBar.js
index 17d36a14df7c..dd4a0e10b8ab 100644
--- a/Libraries/CustomComponents/Navigator/NavigatorNavigationBar.js
+++ b/Libraries/CustomComponents/Navigator/NavigatorNavigationBar.js
@@ -33,6 +33,8 @@ var Platform = require('Platform');
 var StyleSheet = require('StyleSheet');
 var View = require('View');
 
+var guid = require('guid');
+
 var { Map } = require('immutable');
 
 var COMPONENT_NAMES = ['Title', 'LeftButton', 'RightButton'];
@@ -78,6 +80,21 @@ var NavigatorNavigationBar = React.createClass({
   },
 
   componentWillMount: function() {
+    this._reset();
+  },
+
+  /**
+   * Stop transtion, immediately resets the cached state and re-render the
+   * whole view.
+   */
+  immediatelyRefresh() {
+    this._reset();
+    this.forceUpdate();
+  },
+
+  _reset() {
+    this._key = guid();
+    this._reusableProps = {};
     this._components = {};
     this._descriptors = {};
 
@@ -91,9 +108,6 @@ var NavigatorNavigationBar = React.createClass({
     /*string*/componentName,
     /*number*/index
   ) /*object*/ {
-    if (!this._reusableProps) {
-      this._reusableProps = {};
-    }
     var propStack = this._reusableProps[componentName];
     if (!propStack) {
       propStack = this._reusableProps[componentName] = [];
@@ -160,7 +174,9 @@ var NavigatorNavigationBar = React.createClass({
     );
 
     return (
-      <View style={[styles.navBarContainer, navBarStyle, this.props.style]}>
+      <View
+        key={this._key}
+        style={[styles.navBarContainer, navBarStyle, this.props.style]}>
         {components}
       </View>
     );

From ca263ac8a1b3f564d34837cd7d59b5ca3870b092 Mon Sep 17 00:00:00 2001
From: Harry Moreno <morenoh149@gmail.com>
Date: Tue, 15 Dec 2015 17:45:07 -0500
Subject: [PATCH 0403/1411] wrap javascript at 80 columns

---
 docs/NativeModulesAndroid.md | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/docs/NativeModulesAndroid.md b/docs/NativeModulesAndroid.md
index 56a8c2f83a6d..13d840cd9f2c 100644
--- a/docs/NativeModulesAndroid.md
+++ b/docs/NativeModulesAndroid.md
@@ -127,11 +127,12 @@ To make it simpler to access your new functionality from JavaScript, it is commo
 ```js
 'use strict';
 /**
- * This exposes the native ToastAndroid module as a JS module. This has a function 'show'
- * which takes the following parameters:
+ * This exposes the native ToastAndroid module as a JS module. This has a
+ * function 'show' which takes the following parameters:
  *
  * 1. String message: A string with the text to toast
- * 2. int duration: The duration of the toast. May be ToastAndroid.SHORT or ToastAndroid.LONG
+ * 2. int duration: The duration of the toast. May be ToastAndroid.SHORT or
+ *    ToastAndroid.LONG
  */
 var { NativeModules } = require('react-native');
 module.exports = NativeModules.ToastAndroid;
@@ -140,7 +141,7 @@ module.exports = NativeModules.ToastAndroid;
 Now, from your other JavaScript file you can call the method like this:
 
 ```js
-var ToastAndroid = require('./ToastAndroid'); 
+var ToastAndroid = require('./ToastAndroid');
 
 ToastAndroid.show('Awesome', ToastAndroid.SHORT);
 ```

From 53d18c83c8de220d3da5f30271a2e9a0765b8df2 Mon Sep 17 00:00:00 2001
From: Hedger Wang <hedger@fb.com>
Date: Tue, 15 Dec 2015 17:31:07 -0800
Subject: [PATCH 0404/1411] Fix app crash caused by TextInput.

Reviewed By: zjj010104

Differential Revision: D2761644

fb-gh-sync-id: 89241de2f8c84d569ec452871f740a0d655cc95e
---
 Libraries/Components/TextInput/TextInput.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js
index fe62ec7fb2a7..62ff5f2a8499 100644
--- a/Libraries/Components/TextInput/TextInput.js
+++ b/Libraries/Components/TextInput/TextInput.js
@@ -550,6 +550,12 @@ var TextInput = React.createClass({
     this.props.onChange && this.props.onChange(event);
     this.props.onChangeText && this.props.onChangeText(text);
 
+    if (!this.refs.input) {
+      // calling `this.props.onChange` or `this.props.onChangeText`
+      // may clean up the input itself. Exits here.
+      return;
+    }
+
     // This is necessary in case native updates the text and JS decides
     // that the update should be ignored and we should stick with the value
     // that we have in JS.

From edc318fcb9c2360e67dfa3d2d48462d6bacda3c0 Mon Sep 17 00:00:00 2001
From: Qiao Liang <qiaoliang89@gmail.com>
Date: Tue, 15 Dec 2015 17:33:37 -0800
Subject: [PATCH 0405/1411] added doc for image resizeMode

Summary:
based on https://github.com/facebook/react-native/blob/62e8ddc20561a39c3c839ab9f83c95493df117c0/ReactAndroid/src/main/java/com/facebook/react/views/image/ImageResizeMode.java  and http://developer.android.com/reference/android/widget/ImageView.ScaleType.html
Closes https://github.com/facebook/react-native/pull/4799

Reviewed By: svcscm

Differential Revision: D2762795

Pulled By: androidtrunkagent

fb-gh-sync-id: 2906c9f334f0afd4d58d4864a2b8472a5a871fc0
---
 Libraries/Image/Image.ios.js | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/Libraries/Image/Image.ios.js b/Libraries/Image/Image.ios.js
index 2b649bf9cc6f..8eda0cc8c9c9 100644
--- a/Libraries/Image/Image.ios.js
+++ b/Libraries/Image/Image.ios.js
@@ -102,6 +102,17 @@ var Image = React.createClass({
     /**
      * Determines how to resize the image when the frame doesn't match the raw
      * image dimensions.
+     *
+     * 'cover': Scale the image uniformly (maintain the image's aspect ratio)
+     * so that both dimensions (width and height) of the image will be equal
+     * to or larger than the corresponding dimension of the view (minus padding).
+     *
+     * 'contain': Scale the image uniformly (maintain the image's aspect ratio)
+     * so that both dimensions (width and height) of the image will be equal to
+     * or less than the corresponding dimension of the view (minus padding).
+     *
+     * 'stretch': Scale width and height independently, This may change the
+     * aspect ratio of the src.
      */
     resizeMode: PropTypes.oneOf(['cover', 'contain', 'stretch']),
     /**

From 75d81cfb10a7ab81e15cbb9844d688a6fbc6845b Mon Sep 17 00:00:00 2001
From: Baris Sencan <baris.sncn@gmail.com>
Date: Tue, 15 Dec 2015 18:34:19 -0800
Subject: [PATCH 0406/1411] [README] "find can more" -> "can find more"

---
 packager/README.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/packager/README.md b/packager/README.md
index 67bab1d9bb21..836839395ea1 100644
--- a/packager/README.md
+++ b/packager/README.md
@@ -144,5 +144,5 @@ is informed by React Native needs.
 ### Why didn't you use webpack?
 
 We love webpack, however, when we tried on our codebase it was slower
-than our developers would like it to be. You find can more discussion about
-the subject [here](https://github.com/facebook/react-native/issues/5)
+than our developers would like it to be. You can find more discussion about
+the subject [here](https://github.com/facebook/react-native/issues/5).

From 1fabd8604836f54764852bafdac41dd55a84b0ed Mon Sep 17 00:00:00 2001
From: Denis Koroskin <dkoroskin@fb.com>
Date: Tue, 15 Dec 2015 20:07:57 -0800
Subject: [PATCH 0407/1411] Add support for custom AndroidViews

Reviewed By: ahmedre

Differential Revision: D2751716

fb-gh-sync-id: 3007cc1eb0303bb2e9eab84836b486e1c2e21021
---
 .../java/com/facebook/react/uimanager/ReactShadowNode.java    | 2 +-
 .../java/com/facebook/react/uimanager/UIImplementation.java   | 4 ++++
 .../react/views/textinput/ReactTextInputShadowNode.java       | 2 +-
 3 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java
index 73134194fb1b..d0f204e186fb 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java
@@ -256,7 +256,7 @@ public ThemedReactContext getThemedContext() {
     return Assertions.assertNotNull(mThemedContext);
   }
 
-  protected void setThemedContext(ThemedReactContext themedContext) {
+  public void setThemedContext(ThemedReactContext themedContext) {
     mThemedContext = themedContext;
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
index 633c8dd43c9d..5fb38cf9796a 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
@@ -75,6 +75,10 @@ protected final ReactShadowNode resolveShadowNode(int reactTag) {
     return mShadowNodeRegistry.getNode(reactTag);
   }
 
+  protected final ViewManager resolveViewManager(String className) {
+    return mViewManagers.get(className);
+  }
+
   /**
    * Registers a root node with a given tag, size and ThemedReactContext
    * and adds it to a node registry.
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java
index 2a37f82f1e4d..6cc920b14e2b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java
@@ -48,7 +48,7 @@ public ReactTextInputShadowNode() {
   }
 
   @Override
-  protected void setThemedContext(ThemedReactContext themedContext) {
+  public void setThemedContext(ThemedReactContext themedContext) {
     super.setThemedContext(themedContext);
 
     // TODO #7120264: cache this stuff better

From fcf0431d252a9cb98ba14c0cee74d07be5303635 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Wed, 16 Dec 2015 00:47:43 -0800
Subject: [PATCH 0408/1411] Add support for more Scroll Events to Android

Summary:
public
This adds support for
onScrollBeginDrag/End
onMomentumScrolBegin/End

Reviewed By: astreet

Differential Revision: D2739035

fb-gh-sync-id: 2a49d1df54e5f5cd82008bdb0ffde0881ba39aff
---
 Libraries/Components/ScrollView/ScrollView.js |  8 ++++
 .../RecyclerViewBackedScrollView.java         |  2 +
 .../RecyclerViewBackedScrollViewManager.java  |  4 +-
 .../scroll/ReactHorizontalScrollView.java     | 48 ++++++++++++++++++-
 .../ReactHorizontalScrollViewManager.java     | 13 +++++
 .../react/views/scroll/ReactScrollView.java   | 48 ++++++++++++++++++-
 .../views/scroll/ReactScrollViewHelper.java   | 29 +++++++++--
 .../views/scroll/ReactScrollViewManager.java  | 25 +++++++---
 .../react/views/scroll/ScrollEvent.java       | 21 ++++++--
 .../react/views/scroll/ScrollEventType.java   | 32 +++++++++++++
 10 files changed, 214 insertions(+), 16 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/scroll/ScrollEventType.java

diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js
index 5f6e08d86693..a23b0a248fe8 100644
--- a/Libraries/Components/ScrollView/ScrollView.js
+++ b/Libraries/Components/ScrollView/ScrollView.js
@@ -234,6 +234,13 @@ var ScrollView = React.createClass({
      * @platform ios
      */
     scrollsToTop: PropTypes.bool,
+    /**
+     * When true, momentum events will be sent from Android
+     * This is internal and set automatically by the framework if you have
+     * onMomentumScrollBegin or onMomentumScrollEnd set on your ScrollView
+     * @platform android
+     */
+    sendMomentumEvents: PropTypes.bool,
     /**
      * When true, shows a horizontal scroll indicator.
      */
@@ -434,6 +441,7 @@ var ScrollView = React.createClass({
       onResponderTerminate: this.scrollResponderHandleTerminate,
       onResponderRelease: this.scrollResponderHandleResponderRelease,
       onResponderReject: this.scrollResponderHandleResponderReject,
+      sendMomentumEvents: (this.props.onMomentumScrollBegin || this.props.onMomentumScrollEnd) ? true : false,
     };
 
     var onRefreshStart = this.props.onRefreshStart;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollView.java
index 054a9522220b..6ebfb211c0b6 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollView.java
@@ -19,6 +19,7 @@
 import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.events.NativeGestureUtil;
 import com.facebook.react.views.scroll.ScrollEvent;
+import com.facebook.react.views.scroll.ScrollEventType;
 
 /**
  * Wraps {@link RecyclerView} providing interface similar to `ScrollView.js` where each children
@@ -311,6 +312,7 @@ protected void onScrollChanged(int l, int t, int oldl, int oldt) {
         .dispatchEvent(ScrollEvent.obtain(
                 getId(),
                 SystemClock.uptimeMillis(),
+                ScrollEventType.SCROLL,
                 0, /* offsetX = 0, horizontal scrolling only */
                 calculateAbsoluteOffset(),
                 getWidth(),
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollViewManager.java
index c49c26742ad1..4b34019808ab 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollViewManager.java
@@ -14,7 +14,7 @@
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.ViewGroupManager;
 import com.facebook.react.views.scroll.ReactScrollViewCommandHelper;
-import com.facebook.react.views.scroll.ScrollEvent;
+import com.facebook.react.views.scroll.ScrollEventType;
 
 /**
  * View manager for {@link RecyclerViewBackedScrollView}.
@@ -91,7 +91,7 @@ public void scrollWithoutAnimationTo(
   public @Nullable
   Map getExportedCustomDirectEventTypeConstants() {
     return MapBuilder.builder()
-        .put(ScrollEvent.EVENT_NAME, MapBuilder.of("registrationName", "onScroll"))
+        .put(ScrollEventType.SCROLL.getJSEventName(), MapBuilder.of("registrationName", "onScroll"))
         .put(
             ContentSizeChangeEvent.EVENT_NAME,
             MapBuilder.of("registrationName", "onContentSizeChange"))
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java
index ec528cedf287..298512c6d552 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java
@@ -23,10 +23,19 @@ public class ReactHorizontalScrollView extends HorizontalScrollView {
 
   private final OnScrollDispatchHelper mOnScrollDispatchHelper = new OnScrollDispatchHelper();
 
+  private boolean mSendMomentumEvents;
+  private boolean mDragging;
+  private boolean mFlinging;
+  private boolean mDoneFlinging;
+
   public ReactHorizontalScrollView(Context context) {
     super(context);
   }
 
+  public void setSendMomentumEvents(boolean sendMomentumEvents) {
+    mSendMomentumEvents = sendMomentumEvents;
+  }
+
   @Override
   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
     MeasureSpecAssertions.assertExplicitMeasureSpec(widthMeasureSpec, heightMeasureSpec);
@@ -47,7 +56,10 @@ protected void onScrollChanged(int x, int y, int oldX, int oldY) {
     super.onScrollChanged(x, y, oldX, oldY);
 
     if (mOnScrollDispatchHelper.onScrollChanged(x, y)) {
-      ReactScrollViewHelper.emitScrollEvent(this, x, y);
+      if (mFlinging) {
+        mDoneFlinging = false;
+      }
+      ReactScrollViewHelper.emitScrollEvent(this);
     }
   }
 
@@ -55,9 +67,43 @@ protected void onScrollChanged(int x, int y, int oldX, int oldY) {
   public boolean onInterceptTouchEvent(MotionEvent ev) {
     if (super.onInterceptTouchEvent(ev)) {
       NativeGestureUtil.notifyNativeGestureStarted(this, ev);
+      ReactScrollViewHelper.emitScrollBeginDragEvent(this);
+      mDragging = true;
       return true;
     }
 
     return false;
   }
+
+  @Override
+  public boolean onTouchEvent(MotionEvent ev) {
+    int action = ev.getAction() & MotionEvent.ACTION_MASK;
+    if (action == MotionEvent.ACTION_UP && mDragging) {
+      ReactScrollViewHelper.emitScrollEndDragEvent(this);
+      mDragging = false;
+    }
+    return super.onTouchEvent(ev);
+  }
+
+  @Override
+  public void fling(int velocityX) {
+    super.fling(velocityX);
+    if (mSendMomentumEvents) {
+      mFlinging = true;
+      ReactScrollViewHelper.emitScrollMomentumBeginEvent(this);
+      Runnable r = new Runnable() {
+        @Override
+        public void run() {
+          if (mDoneFlinging) {
+            mFlinging = false;
+            ReactScrollViewHelper.emitScrollMomentumEndEvent(ReactHorizontalScrollView.this);
+          } else {
+            mDoneFlinging = true;
+            ReactHorizontalScrollView.this.postOnAnimationDelayed(this, ReactScrollViewHelper.MOMENTUM_DELAY);
+          }
+        }
+      };
+      postOnAnimationDelayed(r, ReactScrollViewHelper.MOMENTUM_DELAY);
+    }
+  }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java
index e8ee9fff88e4..0d86a3346bf4 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java
@@ -43,6 +43,19 @@ public void setShowsHorizontalScrollIndicator(ReactHorizontalScrollView view, bo
     view.setHorizontalScrollBarEnabled(value);
   }
 
+  /**
+   * Computing momentum events is potentially expensive since we post a runnable on the UI thread
+   * to see when it is done.  We only do that if {@param sendMomentumEvents} is set to true.  This
+   * is handled automatically in js by checking if there is a listener on the momentum events.
+   *
+   * @param view
+   * @param sendMomentumEvents
+   */
+  @ReactProp(name = "sendMomentumEvents")
+  public void setSendMomentumEvents(ReactHorizontalScrollView view, boolean sendMomentumEvents) {
+    view.setSendMomentumEvents(sendMomentumEvents);
+  }
+
   @Override
   public void receiveCommand(
       ReactHorizontalScrollView scrollView,
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java
index cc8098efcd16..a6a813db9f95 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java
@@ -36,11 +36,19 @@ public class ReactScrollView extends ScrollView implements ReactClippingViewGrou
 
   private boolean mRemoveClippedSubviews;
   private @Nullable Rect mClippingRect;
+  private boolean mSendMomentumEvents;
+  private boolean mDragging;
+  private boolean mFlinging;
+  private boolean mDoneFlinging;
 
   public ReactScrollView(Context context) {
     super(context);
   }
 
+  public void setSendMomentumEvents(boolean sendMomentumEvents) {
+    mSendMomentumEvents = sendMomentumEvents;
+  }
+
   @Override
   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
     MeasureSpecAssertions.assertExplicitMeasureSpec(widthMeasureSpec, heightMeasureSpec);
@@ -73,7 +81,11 @@ protected void onScrollChanged(int x, int y, int oldX, int oldY) {
         updateClippingRect();
       }
 
-      ReactScrollViewHelper.emitScrollEvent(this, x, y);
+      if (mFlinging) {
+        mDoneFlinging = false;
+      }
+
+      ReactScrollViewHelper.emitScrollEvent(this);
     }
   }
 
@@ -81,12 +93,24 @@ protected void onScrollChanged(int x, int y, int oldX, int oldY) {
   public boolean onInterceptTouchEvent(MotionEvent ev) {
     if (super.onInterceptTouchEvent(ev)) {
       NativeGestureUtil.notifyNativeGestureStarted(this, ev);
+      ReactScrollViewHelper.emitScrollBeginDragEvent(this);
+      mDragging = true;
       return true;
     }
 
     return false;
   }
 
+  @Override
+  public boolean onTouchEvent(MotionEvent ev) {
+    int action = ev.getAction() & MotionEvent.ACTION_MASK;
+    if (action == MotionEvent.ACTION_UP && mDragging) {
+      ReactScrollViewHelper.emitScrollEndDragEvent(this);
+      mDragging = false;
+    }
+    return super.onTouchEvent(ev);
+  }
+
   @Override
   public void setRemoveClippedSubviews(boolean removeClippedSubviews) {
     if (removeClippedSubviews && mClippingRect == null) {
@@ -120,4 +144,26 @@ public void updateClippingRect() {
   public void getClippingRect(Rect outClippingRect) {
     outClippingRect.set(Assertions.assertNotNull(mClippingRect));
   }
+
+  @Override
+  public void fling(int velocityY) {
+    super.fling(velocityY);
+    if (mSendMomentumEvents) {
+      mFlinging = true;
+      ReactScrollViewHelper.emitScrollMomentumBeginEvent(this);
+      Runnable r = new Runnable() {
+        @Override
+        public void run() {
+          if (mDoneFlinging) {
+            mFlinging = false;
+            ReactScrollViewHelper.emitScrollMomentumEndEvent(ReactScrollView.this);
+          } else {
+            mDoneFlinging = true;
+            ReactScrollView.this.postOnAnimationDelayed(this, ReactScrollViewHelper.MOMENTUM_DELAY);
+          }
+        }
+      };
+      postOnAnimationDelayed(r, ReactScrollViewHelper.MOMENTUM_DELAY);
+    }
+  }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java
index c8e7fa22e5cb..1b9c3eb7d901 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java
@@ -21,18 +21,41 @@
  */
 public class ReactScrollViewHelper {
 
+  public static final long MOMENTUM_DELAY = 20;
+
   /**
    * Shared by {@link ReactScrollView} and {@link ReactHorizontalScrollView}.
    */
-  public static void emitScrollEvent(ViewGroup scrollView, int scrollX, int scrollY) {
+  public static void emitScrollEvent(ViewGroup scrollView) {
+    emitScrollEvent(scrollView, ScrollEventType.SCROLL);
+  }
+
+  public static void emitScrollBeginDragEvent(ViewGroup scrollView) {
+    emitScrollEvent(scrollView, ScrollEventType.BEGIN_DRAG);
+  }
+
+  public static void emitScrollEndDragEvent(ViewGroup scrollView) {
+    emitScrollEvent(scrollView, ScrollEventType.END_DRAG);
+  }
+
+  public static void emitScrollMomentumBeginEvent(ViewGroup scrollView) {
+    emitScrollEvent(scrollView, ScrollEventType.MOMENTUM_BEGIN);
+  }
+
+  public static void emitScrollMomentumEndEvent(ViewGroup scrollView) {
+    emitScrollEvent(scrollView, ScrollEventType.MOMENTUM_END);
+  }
+
+  private static void emitScrollEvent(ViewGroup scrollView, ScrollEventType scrollEventType) {
     View contentView = scrollView.getChildAt(0);
     ReactContext reactContext = (ReactContext) scrollView.getContext();
     reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(
         ScrollEvent.obtain(
             scrollView.getId(),
             SystemClock.uptimeMillis(),
-            scrollX,
-            scrollY,
+            scrollEventType,
+            scrollView.getScrollX(),
+            scrollView.getScrollY(),
             contentView.getWidth(),
             contentView.getHeight(),
             scrollView.getWidth(),
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java
index 6de7da6bcf3d..b45fac0af88f 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java
@@ -52,6 +52,19 @@ public void setRemoveClippedSubviews(ReactScrollView view, boolean removeClipped
     view.setRemoveClippedSubviews(removeClippedSubviews);
   }
 
+  /**
+   * Computing momentum events is potentially expensive since we post a runnable on the UI thread
+   * to see when it is done.  We only do that if {@param sendMomentumEvents} is set to true.  This
+   * is handled automatically in js by checking if there is a listener on the momentum events.
+   *
+   * @param view
+   * @param sendMomentumEvents
+   */
+  @ReactProp(name = "sendMomentumEvents")
+  public void setSendMomentumEvents(ReactScrollView view, boolean sendMomentumEvents) {
+    view.setSendMomentumEvents(sendMomentumEvents);
+  }
+
   @Override
   public @Nullable Map<String, Integer> getCommandsMap() {
     return ReactScrollViewCommandHelper.getCommandsMap();
@@ -86,12 +99,12 @@ public void scrollWithoutAnimationTo(
 
   public static Map createExportedCustomDirectEventTypeConstants() {
     return MapBuilder.builder()
-        .put(ScrollEvent.EVENT_NAME, MapBuilder.of("registrationName", "onScroll"))
-        .put("topScrollBeginDrag", MapBuilder.of("registrationName", "onScrollBeginDrag"))
-        .put("topScrollEndDrag", MapBuilder.of("registrationName", "onScrollEndDrag"))
-        .put("topScrollAnimationEnd", MapBuilder.of("registrationName", "onScrollAnimationEnd"))
-        .put("topMomentumScrollBegin", MapBuilder.of("registrationName", "onMomentumScrollBegin"))
-        .put("topMomentumScrollEnd", MapBuilder.of("registrationName", "onMomentumScrollEnd"))
+        .put(ScrollEventType.SCROLL.getJSEventName(), MapBuilder.of("registrationName", "onScroll"))
+        .put(ScrollEventType.BEGIN_DRAG.getJSEventName(), MapBuilder.of("registrationName", "onScrollBeginDrag"))
+        .put(ScrollEventType.END_DRAG.getJSEventName(), MapBuilder.of("registrationName", "onScrollEndDrag"))
+        .put(ScrollEventType.ANIMATION_END.getJSEventName(), MapBuilder.of("registrationName", "onScrollAnimationEnd"))
+        .put(ScrollEventType.MOMENTUM_BEGIN.getJSEventName(), MapBuilder.of("registrationName", "onMomentumScrollBegin"))
+        .put(ScrollEventType.MOMENTUM_END.getJSEventName(), MapBuilder.of("registrationName", "onMomentumScrollEnd"))
         .build();
   }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ScrollEvent.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ScrollEvent.java
index fdf8cd5a2faf..dde0a6018a27 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ScrollEvent.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ScrollEvent.java
@@ -9,10 +9,13 @@
 
 package com.facebook.react.views.scroll;
 
+import javax.annotation.Nullable;
+
 import java.lang.Override;
 
 import android.support.v4.util.Pools;
 
+import com.facebook.infer.annotation.Assertions;
 import com.facebook.react.bridge.Arguments;
 import com.facebook.react.bridge.WritableMap;
 import com.facebook.react.uimanager.PixelUtil;
@@ -27,18 +30,18 @@ public class ScrollEvent extends Event<ScrollEvent> {
   private static final Pools.SynchronizedPool<ScrollEvent> EVENTS_POOL =
       new Pools.SynchronizedPool<>(3);
 
-  public static final String EVENT_NAME = "topScroll";
-
   private int mScrollX;
   private int mScrollY;
   private int mContentWidth;
   private int mContentHeight;
   private int mScrollViewWidth;
   private int mScrollViewHeight;
+  private @Nullable ScrollEventType mScrollEventType;
 
   public static ScrollEvent obtain(
       int viewTag,
       long timestampMs,
+      ScrollEventType scrollEventType,
       int scrollX,
       int scrollY,
       int contentWidth,
@@ -52,6 +55,7 @@ public static ScrollEvent obtain(
     event.init(
         viewTag,
         timestampMs,
+        scrollEventType,
         scrollX,
         scrollY,
         contentWidth,
@@ -72,6 +76,7 @@ private ScrollEvent() {
   private void init(
       int viewTag,
       long timestampMs,
+      ScrollEventType scrollEventType,
       int scrollX,
       int scrollY,
       int contentWidth,
@@ -79,6 +84,7 @@ private void init(
       int scrollViewWidth,
       int scrollViewHeight) {
     super.init(viewTag, timestampMs);
+    mScrollEventType = scrollEventType;
     mScrollX = scrollX;
     mScrollY = scrollY;
     mContentWidth = contentWidth;
@@ -89,7 +95,7 @@ private void init(
 
   @Override
   public String getEventName() {
-    return EVENT_NAME;
+    return Assertions.assertNotNull(mScrollEventType).getJSEventName();
   }
 
   @Override
@@ -98,6 +104,15 @@ public short getCoalescingKey() {
     return 0;
   }
 
+  @Override
+  public boolean canCoalesce() {
+    // Only SCROLL events can be coalesced, all others can not be
+    if (mScrollEventType == ScrollEventType.SCROLL) {
+      return true;
+    }
+    return false;
+  }
+
   @Override
   public void dispatch(RCTEventEmitter rctEventEmitter) {
     rctEventEmitter.receiveEvent(getViewTag(), getEventName(), serializeEventData());
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ScrollEventType.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ScrollEventType.java
new file mode 100644
index 000000000000..db37f20d5db5
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ScrollEventType.java
@@ -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.
+ */
+
+package com.facebook.react.views.scroll;
+
+/**
+ * Scroll event types that JS module RCTEventEmitter can understand
+ */
+public enum ScrollEventType {
+  BEGIN_DRAG("topScrollBeginDrag"),
+  END_DRAG("topScrollEndDrag"),
+  SCROLL("topScroll"),
+  MOMENTUM_BEGIN("topMomentumScrollBegin"),
+  MOMENTUM_END("topMomentumScrollEnd"),
+  ANIMATION_END("topScrollAnimationEnd");
+
+  private final String mJSEventName;
+
+  ScrollEventType(String jsEventName) {
+    mJSEventName = jsEventName;
+  }
+
+  public String getJSEventName() {
+    return mJSEventName;
+  }
+}

From 8457a46e43cfb6086338fd92e1426541932a69b5 Mon Sep 17 00:00:00 2001
From: Tim Yung <yungsters@fb.com>
Date: Wed, 16 Dec 2015 01:47:47 -0800
Subject: [PATCH 0409/1411] RN: Install Updated `fbjs` Downstream

Reviewed By: cpojer

Differential Revision: D2754195

fb-gh-sync-id: 67b628fdfa34da379ab5fdad03b1baaf767c7f21
---
 packager/blacklist.js | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/packager/blacklist.js b/packager/blacklist.js
index bb64f75256f1..863e2a9acc25 100644
--- a/packager/blacklist.js
+++ b/packager/blacklist.js
@@ -63,9 +63,6 @@ var sharedBlacklist = [
   'downstream/core/invariant.js',
   'downstream/core/nativeRequestAnimationFrame.js',
   'downstream/core/toArray.js',
-  'downstream/functional/mapObject.js',
-  'downstream/key-mirror/keyMirror.js',
-  'downstream/key-mirror/keyOf.js',
 ];
 
 // Raw unescaped patterns in case you need to use wildcards

From f5673026f4212dbaa6f916ca67d788ee819f2ad3 Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Wed, 16 Dec 2015 02:12:33 -0800
Subject: [PATCH 0410/1411] Remove expensive args from profile markers

Summary:
public

We were adding all the arguments passed to all the JS functions and callbacks
called over the bridge to marker names, and this args can be huge, meaning a lot
of time spent stringifying arguments and therefore less accurate profile results

Reviewed By: nicklockwood

Differential Revision: D2761809

fb-gh-sync-id: 2d0b5b90cc9e59fe491c108b0360b84ab5fee5b7
---
 Libraries/Utilities/MessageQueue.js | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/Libraries/Utilities/MessageQueue.js b/Libraries/Utilities/MessageQueue.js
index 10a41919a728..43211c8650ed 100644
--- a/Libraries/Utilities/MessageQueue.js
+++ b/Libraries/Utilities/MessageQueue.js
@@ -154,7 +154,7 @@ class MessageQueue {
       method = this._methodTable[module][method];
       module = this._moduleTable[module];
     }
-    Systrace.beginEvent(() => `${module}.${method}(${stringifySafe(args)})`);
+    Systrace.beginEvent(`${module}.${method}()`);
     if (__DEV__ && SPY_MODE) {
       console.log('N->JS : ' + module + '.' + method + '(' + JSON.stringify(args) + ')');
     }
@@ -169,8 +169,7 @@ class MessageQueue {
   }
 
   __invokeCallback(cbID, args) {
-    Systrace.beginEvent(
-      () => `MessageQueue.invokeCallback(${cbID}, ${stringifySafe(args)})`);
+    Systrace.beginEvent(`MessageQueue.invokeCallback(${cbID})`);
     this._lastFlush = new Date().getTime();
     let callback = this._callbacks[cbID];
     if (!callback || __DEV__) {

From f8c125c64b741e723670e8a187b43a3cae042c2a Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Wed, 16 Dec 2015 02:30:27 -0800
Subject: [PATCH 0411/1411] Remove redundant profile events

Summary:
public

Remove some of the manual markers from the bridge since they will already be added dinamically.

Reviewed By: jspahrsummers

Differential Revision: D2761748

fb-gh-sync-id: 0c726373f9105258feb8230d30453559ed1e6a65
---
 React/Base/RCTBatchedBridge.m | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index 9aba7f9ff967..d9ee999f7cf7 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -908,8 +908,6 @@ - (BOOL)_handleRequestNumber:(NSUInteger)i
     return NO;
   }
 
-  RCT_PROFILE_BEGIN_EVENT(0, [NSString stringWithFormat:@"[%@ %@]", moduleData.name, method.JSMethodName], nil);
-
   @try {
     [method invokeWithBridge:self module:moduleData.instance arguments:params];
   }
@@ -925,13 +923,6 @@ - (BOOL)_handleRequestNumber:(NSUInteger)i
     RCTFatal(RCTErrorWithMessage(message));
   }
 
-  if (RCTProfileIsProfiling()) {
-    NSMutableDictionary *args = [method.profileArgs mutableCopy];
-    args[@"method"] = method.JSMethodName;
-    args[@"args"] = RCTJSONStringify(RCTNullIfNil(params), NULL);
-    RCT_PROFILE_END_EVENT(0, @"objc_call", args);
-  }
-
   return YES;
 }
 
@@ -948,9 +939,7 @@ - (void)_jsThreadUpdate:(CADisplayLink *)displayLink
 
       [self dispatchBlock:^{
         RCTProfileEndFlowEvent();
-        RCT_PROFILE_BEGIN_EVENT(0, [NSString stringWithFormat:@"[%@ didUpdateFrame:%f]", observer, displayLink.timestamp], nil);
         [observer didUpdateFrame:frameUpdate];
-        RCT_PROFILE_END_EVENT(0, @"objc_call,fps", nil);
       } queue:moduleData.methodQueue];
     }
   }

From 809627379b91477e94c26936736c2dd0201fc518 Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Wed, 16 Dec 2015 02:49:27 -0800
Subject: [PATCH 0412/1411] Rename RCTContextExecutor to RCTJSCExecutor

Summary:
public

Rename the executor to so it actually says something about the implementation.

Reviewed By: jspahrsummers, nicklockwood

Differential Revision: D2759688

fb-gh-sync-id: 5b1ac447e75109fbbc2ee71c804710d9926785aa
---
 .../UIExplorer.xcodeproj/project.pbxproj      | 14 ++++-----
 .../UIExplorerUnitTests/RCTAllocationTests.m  |  2 +-
 ...tExecutorTests.m => RCTJSCExecutorTests.m} | 12 ++++----
 Libraries/RCTTest/RCTTestRunner.m             |  4 +--
 React/Base/RCTBatchedBridge.m                 | 10 +++----
 React/Base/RCTBridge+Private.h                |  4 +--
 React/Base/RCTRootView.h                      |  2 +-
 ...{RCTContextExecutor.h => RCTJSCExecutor.h} |  4 +--
 ...{RCTContextExecutor.m => RCTJSCExecutor.m} | 30 +++++++++----------
 React/Profiler/RCTPerfMonitor.m               |  3 +-
 React/React.xcodeproj/project.pbxproj         | 12 ++++----
 11 files changed, 47 insertions(+), 50 deletions(-)
 rename Examples/UIExplorer/UIExplorerUnitTests/{RCTContextExecutorTests.m => RCTJSCExecutorTests.m} (95%)
 rename React/Executors/{RCTContextExecutor.h => RCTJSCExecutor.h} (88%)
 rename React/Executors/{RCTContextExecutor.m => RCTJSCExecutor.m} (96%)

diff --git a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
index 2f10b53ae305..ea9084cd77bb 100644
--- a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
+++ b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
@@ -16,7 +16,6 @@
 		13417FE91AA91432003F314A /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 13417FE81AA91428003F314A /* libRCTImage.a */; };
 		134180011AA9153C003F314A /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 13417FEF1AA914B8003F314A /* libRCTText.a */; };
 		1341802C1AA9178B003F314A /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1341802B1AA91779003F314A /* libRCTNetwork.a */; };
-		134366AF1BFD2C76000A2DE1 /* Thumbnails in Resources */ = {isa = PBXBuildFile; fileRef = 134366AE1BFD2C76000A2DE1 /* Thumbnails */; };
 		134454601AAFCABD003F0779 /* libRCTAdSupport.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1344545A1AAFCAAE003F0779 /* libRCTAdSupport.a */; };
 		134A8A2A1AACED7A00945AAE /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 134A8A251AACED6A00945AAE /* libRCTGeolocation.a */; };
 		138D6A181B53CD440074A87E /* RCTShadowViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 138D6A161B53CD440074A87E /* RCTShadowViewTests.m */; };
@@ -34,7 +33,7 @@
 		147CED4C1AB3532B00DA3E4C /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 147CED4B1AB34F8C00DA3E4C /* libRCTActionSheet.a */; };
 		1497CFAC1B21F5E400C1F8F2 /* RCTAllocationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFA41B21F5E400C1F8F2 /* RCTAllocationTests.m */; };
 		1497CFAD1B21F5E400C1F8F2 /* RCTBridgeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFA51B21F5E400C1F8F2 /* RCTBridgeTests.m */; };
-		1497CFAE1B21F5E400C1F8F2 /* RCTContextExecutorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFA61B21F5E400C1F8F2 /* RCTContextExecutorTests.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
+		1497CFAE1B21F5E400C1F8F2 /* RCTJSCExecutorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFA61B21F5E400C1F8F2 /* RCTJSCExecutorTests.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
 		1497CFAF1B21F5E400C1F8F2 /* RCTConvert_NSURLTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFA71B21F5E400C1F8F2 /* RCTConvert_NSURLTests.m */; };
 		1497CFB01B21F5E400C1F8F2 /* RCTConvert_UIFontTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFA81B21F5E400C1F8F2 /* RCTConvert_UIFontTests.m */; };
 		1497CFB11B21F5E400C1F8F2 /* RCTEventDispatcherTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFA91B21F5E400C1F8F2 /* RCTEventDispatcherTests.m */; };
@@ -56,8 +55,8 @@
 		14D6D7291B2222EF001FB087 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14AADF041AC3DB95002390C9 /* libReact.a */; };
 		14DC67F41AB71881001358AB /* libRCTPushNotification.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14DC67F11AB71876001358AB /* libRCTPushNotification.a */; };
 		272E6B3F1BEA849E001FCF37 /* UpdatePropertiesExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 272E6B3C1BEA849E001FCF37 /* UpdatePropertiesExampleView.m */; };
+		27B885561BED29AF00008352 /* RCTRootViewIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 27B885551BED29AF00008352 /* RCTRootViewIntegrationTests.m */; };
 		27F441EC1BEBE5030039B79C /* FlexibleSizeExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 27F441E81BEBE5030039B79C /* FlexibleSizeExampleView.m */; };
-		27B885561BED29AF00008352 /* RCTRootViewIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 27B885551BED29AF00008352 /* RCTRootViewIntegrationTests.m */; settings = {ASSET_TAGS = (); }; };
 		3578590A1B28D2CF00341EDB /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 357859011B28D2C500341EDB /* libRCTLinking.a */; };
 		3DB99D0C1BA0340600302749 /* UIExplorerIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DB99D0B1BA0340600302749 /* UIExplorerIntegrationTests.m */; };
 		834C36EC1AF8DED70019C93C /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 834C36D21AF8DA610019C93C /* libRCTSettings.a */; };
@@ -186,7 +185,6 @@
 		13417FE31AA91428003F314A /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = ../../Libraries/Image/RCTImage.xcodeproj; sourceTree = "<group>"; };
 		13417FEA1AA914B8003F314A /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = ../../Libraries/Text/RCTText.xcodeproj; sourceTree = "<group>"; };
 		134180261AA91779003F314A /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../../Libraries/Network/RCTNetwork.xcodeproj; sourceTree = "<group>"; };
-		134366AE1BFD2C76000A2DE1 /* Thumbnails */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Thumbnails; sourceTree = "<group>"; };
 		134454551AAFCAAE003F0779 /* RCTAdSupport.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAdSupport.xcodeproj; path = ../../Libraries/AdSupport/RCTAdSupport.xcodeproj; sourceTree = "<group>"; };
 		134A8A201AACED6A00945AAE /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = ../../Libraries/Geolocation/RCTGeolocation.xcodeproj; sourceTree = "<group>"; };
 		138D6A161B53CD440074A87E /* RCTShadowViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTShadowViewTests.m; sourceTree = "<group>"; };
@@ -216,7 +214,7 @@
 		144D21231B2204C5006DB32B /* RCTImageUtilTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageUtilTests.m; sourceTree = "<group>"; };
 		1497CFA41B21F5E400C1F8F2 /* RCTAllocationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAllocationTests.m; sourceTree = "<group>"; };
 		1497CFA51B21F5E400C1F8F2 /* RCTBridgeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBridgeTests.m; sourceTree = "<group>"; };
-		1497CFA61B21F5E400C1F8F2 /* RCTContextExecutorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTContextExecutorTests.m; sourceTree = "<group>"; };
+		1497CFA61B21F5E400C1F8F2 /* RCTJSCExecutorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTJSCExecutorTests.m; sourceTree = "<group>"; };
 		1497CFA71B21F5E400C1F8F2 /* RCTConvert_NSURLTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTConvert_NSURLTests.m; sourceTree = "<group>"; };
 		1497CFA81B21F5E400C1F8F2 /* RCTConvert_UIFontTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTConvert_UIFontTests.m; sourceTree = "<group>"; };
 		1497CFA91B21F5E400C1F8F2 /* RCTEventDispatcherTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTEventDispatcherTests.m; sourceTree = "<group>"; };
@@ -236,9 +234,9 @@
 		14E0EEC81AB118F7000DECC3 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = ../../Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj; sourceTree = "<group>"; };
 		272E6B3B1BEA849E001FCF37 /* UpdatePropertiesExampleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UpdatePropertiesExampleView.h; path = UIExplorer/NativeExampleViews/UpdatePropertiesExampleView.h; sourceTree = "<group>"; };
 		272E6B3C1BEA849E001FCF37 /* UpdatePropertiesExampleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = UpdatePropertiesExampleView.m; path = UIExplorer/NativeExampleViews/UpdatePropertiesExampleView.m; sourceTree = "<group>"; };
+		27B885551BED29AF00008352 /* RCTRootViewIntegrationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRootViewIntegrationTests.m; sourceTree = "<group>"; };
 		27F441E81BEBE5030039B79C /* FlexibleSizeExampleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FlexibleSizeExampleView.m; path = UIExplorer/NativeExampleViews/FlexibleSizeExampleView.m; sourceTree = "<group>"; };
 		27F441EA1BEBE5030039B79C /* FlexibleSizeExampleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FlexibleSizeExampleView.h; path = UIExplorer/NativeExampleViews/FlexibleSizeExampleView.h; sourceTree = "<group>"; };
-		27B885551BED29AF00008352 /* RCTRootViewIntegrationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRootViewIntegrationTests.m; sourceTree = "<group>"; };
 		357858F81B28D2C400341EDB /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = ../../Libraries/LinkingIOS/RCTLinking.xcodeproj; sourceTree = "<group>"; };
 		3DB99D0B1BA0340600302749 /* UIExplorerIntegrationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIExplorerIntegrationTests.m; sourceTree = "<group>"; };
 		58005BE41ABA80530062E044 /* RCTTest.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTTest.xcodeproj; path = ../../Libraries/RCTTest/RCTTest.xcodeproj; sourceTree = "<group>"; };
@@ -410,7 +408,7 @@
 			children = (
 				1497CFA41B21F5E400C1F8F2 /* RCTAllocationTests.m */,
 				1497CFA51B21F5E400C1F8F2 /* RCTBridgeTests.m */,
-				1497CFA61B21F5E400C1F8F2 /* RCTContextExecutorTests.m */,
+				1497CFA61B21F5E400C1F8F2 /* RCTJSCExecutorTests.m */,
 				1497CFA71B21F5E400C1F8F2 /* RCTConvert_NSURLTests.m */,
 				1497CFA81B21F5E400C1F8F2 /* RCTConvert_UIFontTests.m */,
 				1497CFA91B21F5E400C1F8F2 /* RCTEventDispatcherTests.m */,
@@ -880,7 +878,7 @@
 				1393D0381B68CD1300E1B601 /* RCTModuleMethodTests.m in Sources */,
 				1300627F1B59179B0043FE5A /* RCTGzipTests.m in Sources */,
 				1497CFAF1B21F5E400C1F8F2 /* RCTConvert_NSURLTests.m in Sources */,
-				1497CFAE1B21F5E400C1F8F2 /* RCTContextExecutorTests.m in Sources */,
+				1497CFAE1B21F5E400C1F8F2 /* RCTJSCExecutorTests.m in Sources */,
 				1497CFAD1B21F5E400C1F8F2 /* RCTBridgeTests.m in Sources */,
 				1497CFB11B21F5E400C1F8F2 /* RCTEventDispatcherTests.m in Sources */,
 				1497CFB31B21F5E400C1F8F2 /* RCTUIManagerTests.m in Sources */,
diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m
index b90a384e4a76..a3bcde2548a4 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m
@@ -17,7 +17,7 @@
 
 #import "RCTBridge.h"
 #import "RCTBridge+Private.h"
-#import "RCTContextExecutor.h"
+#import "RCTJSCExecutor.h"
 #import "RCTModuleMethod.h"
 #import "RCTRootView.h"
 
diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTContextExecutorTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTJSCExecutorTests.m
similarity index 95%
rename from Examples/UIExplorer/UIExplorerUnitTests/RCTContextExecutorTests.m
rename to Examples/UIExplorer/UIExplorerUnitTests/RCTJSCExecutorTests.m
index 07d1ebfb00b7..5d08f8f46f74 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTContextExecutorTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTJSCExecutorTests.m
@@ -16,24 +16,24 @@
 
 #import <XCTest/XCTest.h>
 
-#import "RCTContextExecutor.h"
+#import "RCTJSCExecutor.h"
 #import "RCTUtils.h"
 
 #define RUN_PERF_TESTS 0
 
-@interface RCTContextExecutorTests : XCTestCase
+@interface RCTJSCExecutorTests : XCTestCase
 
 @end
 
-@implementation RCTContextExecutorTests
+@implementation RCTJSCExecutorTests
 {
-  RCTContextExecutor *_executor;
+  RCTJSCExecutor *_executor;
 }
 
 - (void)setUp
 {
   [super setUp];
-  _executor = [RCTContextExecutor new];
+  _executor = [RCTJSCExecutor new];
   [_executor setUp];
 }
 
@@ -97,7 +97,7 @@ - (void)testDeserializationPerf
 - (void)testJavaScriptCallSpeed
 {
 /**
- * Since we almost don't change the RCTContextExecutor logic, and this test is
+ * Since we almost don't change the RCTJSCExecutor logic, and this test is
  * very likely to become flaky (specially across different devices) leave it
  * to be run manually
  *
diff --git a/Libraries/RCTTest/RCTTestRunner.m b/Libraries/RCTTest/RCTTestRunner.m
index 6c2e9b5d1675..e1c8e29a8416 100644
--- a/Libraries/RCTTest/RCTTestRunner.m
+++ b/Libraries/RCTTest/RCTTestRunner.m
@@ -15,7 +15,7 @@
 #import "RCTRootView.h"
 #import "RCTTestModule.h"
 #import "RCTUtils.h"
-#import "RCTContextExecutor.h"
+#import "RCTJSCExecutor.h"
 
 static const NSTimeInterval kTestTimeoutSeconds = 60;
 static const NSTimeInterval kTestTeardownTimeoutSeconds = 30;
@@ -135,7 +135,7 @@ - (void)runTest:(SEL)test module:(NSString *)moduleName
     // Take a weak reference to the JS context, so we track its deallocation later
     // (we can only do this now, since it's been lazily initialized)
     id jsExecutor = [bridge valueForKeyPath:@"batchedBridge.javaScriptExecutor"];
-    if ([jsExecutor isKindOfClass:[RCTContextExecutor class]]) {
+    if ([jsExecutor isKindOfClass:[RCTJSCExecutor class]]) {
       weakJSContext = [jsExecutor valueForKey:@"context"];
     }
     [rootView removeFromSuperview];
diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index d9ee999f7cf7..b4734ddd61ac 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -14,7 +14,7 @@
 #import "RCTBridge+Private.h"
 #import "RCTBridgeMethod.h"
 #import "RCTConvert.h"
-#import "RCTContextExecutor.h"
+#import "RCTJSCExecutor.h"
 #import "RCTFrameUpdate.h"
 #import "RCTJavaScriptLoader.h"
 #import "RCTLog.h"
@@ -25,7 +25,7 @@
 #import "RCTUtils.h"
 
 #define RCTAssertJSThread() \
-  RCTAssert(![NSStringFromClass([_javaScriptExecutor class]) isEqualToString:@"RCTContextExecutor"] || \
+  RCTAssert(![NSStringFromClass([_javaScriptExecutor class]) isEqualToString:@"RCTJSCExecutor"] || \
               [[[NSThread currentThread] name] isEqualToString:@"com.facebook.React.JavaScript"], \
             @"This method must be called on JS thread")
 
@@ -370,7 +370,7 @@ - (NSString *)moduleConfig
 {
   NSMutableArray<NSArray *> *config = [NSMutableArray new];
   for (RCTModuleData *moduleData in _moduleDataByID) {
-    if (self.executorClass == [RCTContextExecutor class]) {
+    if (self.executorClass == [RCTJSCExecutor class]) {
       [config addObject:@[moduleData.name]];
     } else {
       [config addObject:RCTNullIfNil(moduleData.config)];
@@ -432,7 +432,7 @@ - (void)executeSourceCode:(NSData *)sourceCode
     }
 
     // Register the display link to start sending js calls after everything is setup
-    NSRunLoop *targetRunLoop = [_javaScriptExecutor isKindOfClass:[RCTContextExecutor class]] ? [NSRunLoop currentRunLoop] : [NSRunLoop mainRunLoop];
+    NSRunLoop *targetRunLoop = [_javaScriptExecutor isKindOfClass:[RCTJSCExecutor class]] ? [NSRunLoop currentRunLoop] : [NSRunLoop mainRunLoop];
     [_jsDisplayLink addToRunLoop:targetRunLoop forMode:NSRunLoopCommonModes];
 
     // Perform the state update and notification on the main thread, so we can't run into
@@ -490,7 +490,7 @@ - (void)reload
 
 - (Class)executorClass
 {
-  return _parentBridge.executorClass ?: [RCTContextExecutor class];
+  return _parentBridge.executorClass ?: [RCTJSCExecutor class];
 }
 
 - (void)setExecutorClass:(Class)executorClass
diff --git a/React/Base/RCTBridge+Private.h b/React/Base/RCTBridge+Private.h
index bb87cc173f58..878014cdf468 100644
--- a/React/Base/RCTBridge+Private.h
+++ b/React/Base/RCTBridge+Private.h
@@ -65,13 +65,13 @@
 - (void)handleBuffer:(NSArray<NSArray *> *)buffer;
 
 /**
- * Exposed for the RCTContextExecutor for sending native methods called from
+ * Exposed for the RCTJSCExecutor for sending native methods called from
  * JavaScript in the middle of a batch.
  */
 - (void)handleBuffer:(NSArray<NSArray *> *)buffer batchEnded:(BOOL)hasEnded;
 
 /**
- * Exposed for the RCTContextExecutor for lazily loading native modules
+ * Exposed for the RCTJSCExecutor for lazily loading native modules
  */
 - (NSArray *)configForModuleName:(NSString *)moduleName;
 
diff --git a/React/Base/RCTRootView.h b/React/Base/RCTRootView.h
index 710711704000..b11881de9559 100644
--- a/React/Base/RCTRootView.h
+++ b/React/Base/RCTRootView.h
@@ -85,7 +85,7 @@ extern NSString *const RCTContentDidAppearNotification;
 
 /**
  * The class of the RCTJavaScriptExecutor to use with this view.
- * If not specified, it will default to using RCTContextExecutor.
+ * If not specified, it will default to using RCTJSCExecutor.
  * Changes will take effect next time the bundle is reloaded.
  */
 @property (nonatomic, strong) Class executorClass;
diff --git a/React/Executors/RCTContextExecutor.h b/React/Executors/RCTJSCExecutor.h
similarity index 88%
rename from React/Executors/RCTContextExecutor.h
rename to React/Executors/RCTJSCExecutor.h
index 3ad12683c20f..cbcf224fcd8a 100644
--- a/React/Executors/RCTContextExecutor.h
+++ b/React/Executors/RCTJSCExecutor.h
@@ -11,12 +11,10 @@
 
 #import "RCTJavaScriptExecutor.h"
 
-// TODO (#5906496): Might RCTJSCoreExecutor be a better name for this?
-
 /**
  * Uses a JavaScriptCore context as the execution engine.
  */
-@interface RCTContextExecutor : NSObject <RCTJavaScriptExecutor>
+@interface RCTJSCExecutor : NSObject <RCTJavaScriptExecutor>
 
 /**
  * Configures the executor to run JavaScript on a specific thread with a given JS context.
diff --git a/React/Executors/RCTContextExecutor.m b/React/Executors/RCTJSCExecutor.m
similarity index 96%
rename from React/Executors/RCTContextExecutor.m
rename to React/Executors/RCTJSCExecutor.m
index 0bf9c0caf9ac..1d52ae5c9522 100644
--- a/React/Executors/RCTContextExecutor.m
+++ b/React/Executors/RCTJSCExecutor.m
@@ -7,7 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  */
 
-#import "RCTContextExecutor.h"
+#import "RCTJSCExecutor.h"
 
 #import <pthread.h>
 
@@ -46,7 +46,7 @@ - (instancetype)initWithJSContext:(JSContext *)context
     _context = context;
 
     /**
-     * Explicitly introduce a retain cycle here - The RCTContextExecutor might
+     * Explicitly introduce a retain cycle here - The RCTJSCExecutor might
      * be deallocated while there's still work enqueued in the JS thread, so
      * we wouldn't be able kill the JSContext. Instead we create this retain
      * cycle, and enqueue the -invalidate message in this object, it then
@@ -84,7 +84,7 @@ - (void)dealloc
 
 @end
 
-@implementation RCTContextExecutor
+@implementation RCTJSCExecutor
 {
   RCTJavaScriptContext *_context;
   NSThread *_javaScriptThread;
@@ -186,14 +186,14 @@ - (instancetype)initWithJavaScriptThread:(NSThread *)javaScriptThread
                                  context:(JSContext *)context
 {
   RCTAssert(javaScriptThread != nil,
-            @"Can't initialize RCTContextExecutor without a javaScriptThread");
+            @"Can't initialize RCTJSCExecutor without a javaScriptThread");
 
   if ((self = [super init])) {
     _valid = YES;
     _javaScriptThread = javaScriptThread;
-    __weak RCTContextExecutor *weakSelf = self;
+    __weak RCTJSCExecutor *weakSelf = self;
     [self executeBlockOnJavaScriptQueue: ^{
-      RCTContextExecutor *strongSelf = weakSelf;
+      RCTJSCExecutor *strongSelf = weakSelf;
       if (!strongSelf) {
         return;
       }
@@ -216,9 +216,9 @@ - (instancetype)initWithJavaScriptThread:(NSThread *)javaScriptThread
 
 - (void)setUp
 {
-  __weak RCTContextExecutor *weakSelf = self;
+  __weak RCTJSCExecutor *weakSelf = self;
   [self executeBlockOnJavaScriptQueue:^{
-    RCTContextExecutor *strongSelf = weakSelf;
+    RCTJSCExecutor *strongSelf = weakSelf;
     if (!strongSelf.isValid) {
       return;
     }
@@ -369,9 +369,9 @@ - (void)_executeJSCall:(NSString *)method
               callback:(RCTJavaScriptCallback)onComplete
 {
   RCTAssert(onComplete != nil, @"onComplete block should not be nil");
-  __weak RCTContextExecutor *weakSelf = self;
+  __weak RCTJSCExecutor *weakSelf = self;
   [self executeBlockOnJavaScriptQueue:RCTProfileBlock((^{
-    RCTContextExecutor *strongSelf = weakSelf;
+    RCTJSCExecutor *strongSelf = weakSelf;
     if (!strongSelf || !strongSelf.isValid) {
       return;
     }
@@ -443,7 +443,7 @@ - (void)_executeJSCall:(NSString *)method
 
     // Looks like making lots of JSC API calls is slower than communicating by using a JSON
     // string. Also it ensures that data stuctures don't have cycles and non-serializable fields.
-    // see [RCTContextExecutorTests testDeserializationPerf]
+    // see [RCTJSCExecutorTests testDeserializationPerf]
     id objcValue;
     // We often return `null` from JS when there is nothing for native side. JSONKit takes an extra hundred microseconds
     // to handle this simple case, so we are adding a shortcut to make executeJSCall method even faster
@@ -468,9 +468,9 @@ - (void)executeApplicationScript:(NSData *)script
   RCTAssertParam(script);
   RCTAssertParam(sourceURL);
 
-  __weak RCTContextExecutor *weakSelf = self;
+  __weak RCTJSCExecutor *weakSelf = self;
   [self executeBlockOnJavaScriptQueue:RCTProfileBlock((^{
-    RCTContextExecutor *strongSelf = weakSelf;
+    RCTJSCExecutor *strongSelf = weakSelf;
     if (!strongSelf || !strongSelf.isValid) {
       return;
     }
@@ -532,9 +532,9 @@ - (void)injectJSONText:(NSString *)script
     RCTAssert(RCTJSONParse(script, NULL) != nil, @"%@ wasn't valid JSON!", script);
   }
 
-  __weak RCTContextExecutor *weakSelf = self;
+  __weak RCTJSCExecutor *weakSelf = self;
   [self executeBlockOnJavaScriptQueue:RCTProfileBlock((^{
-    RCTContextExecutor *strongSelf = weakSelf;
+    RCTJSCExecutor *strongSelf = weakSelf;
     if (!strongSelf || !strongSelf.isValid) {
       return;
     }
diff --git a/React/Profiler/RCTPerfMonitor.m b/React/Profiler/RCTPerfMonitor.m
index e91360198e29..93a6fd70a47d 100644
--- a/React/Profiler/RCTPerfMonitor.m
+++ b/React/Profiler/RCTPerfMonitor.m
@@ -20,6 +20,7 @@
 #import "RCTFPSGraph.h"
 #import "RCTInvalidating.h"
 #import "RCTJavaScriptExecutor.h"
+#import "RCTJSCExecutor.h"
 #import "RCTPerformanceLogger.h"
 #import "RCTRootView.h"
 #import "RCTUIManager.h"
@@ -311,7 +312,7 @@ - (void)show
                        forMode:NSRunLoopCommonModes];
 
   id<RCTJavaScriptExecutor> executor = [_bridge valueForKey:@"javaScriptExecutor"];
-  if ([executor isKindOfClass:NSClassFromString(@"RCTContextExecutor")]) {
+  if ([executor isKindOfClass:[RCTJSCExecutor class]]) {
     self.container.frame = (CGRect) {
       self.container.frame.origin, {
         self.container.frame.size.width + 44,
diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj
index 39f3b8633319..35a7a346bb88 100644
--- a/React/React.xcodeproj/project.pbxproj
+++ b/React/React.xcodeproj/project.pbxproj
@@ -13,7 +13,7 @@
 		133CAE8E1B8E5CFD00F6AD92 /* RCTDatePicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 133CAE8D1B8E5CFD00F6AD92 /* RCTDatePicker.m */; };
 		13456E931ADAD2DE009F94A7 /* RCTConvert+CoreLocation.m in Sources */ = {isa = PBXBuildFile; fileRef = 13456E921ADAD2DE009F94A7 /* RCTConvert+CoreLocation.m */; };
 		13456E961ADAD482009F94A7 /* RCTConvert+MapKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 13456E951ADAD482009F94A7 /* RCTConvert+MapKit.m */; };
-		134FCB3D1A6E7F0800051CC8 /* RCTContextExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 134FCB3A1A6E7F0800051CC8 /* RCTContextExecutor.m */; };
+		134FCB3D1A6E7F0800051CC8 /* RCTJSCExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 134FCB3A1A6E7F0800051CC8 /* RCTJSCExecutor.m */; };
 		13513F3C1B1F43F400FCE529 /* RCTProgressViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13513F3B1B1F43F400FCE529 /* RCTProgressViewManager.m */; };
 		13723B501A82FD3C00F88898 /* RCTStatusBarManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13723B4F1A82FD3C00F88898 /* RCTStatusBarManager.m */; };
 		1372B70A1AB030C200659ED6 /* RCTAppState.m in Sources */ = {isa = PBXBuildFile; fileRef = 1372B7091AB030C200659ED6 /* RCTAppState.m */; };
@@ -121,8 +121,8 @@
 		13456E951ADAD482009F94A7 /* RCTConvert+MapKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTConvert+MapKit.m"; sourceTree = "<group>"; };
 		1345A83A1B265A0E00583190 /* RCTURLRequestDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTURLRequestDelegate.h; sourceTree = "<group>"; };
 		1345A83B1B265A0E00583190 /* RCTURLRequestHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTURLRequestHandler.h; sourceTree = "<group>"; };
-		134FCB391A6E7F0800051CC8 /* RCTContextExecutor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTContextExecutor.h; sourceTree = "<group>"; };
-		134FCB3A1A6E7F0800051CC8 /* RCTContextExecutor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTContextExecutor.m; sourceTree = "<group>"; };
+		134FCB391A6E7F0800051CC8 /* RCTJSCExecutor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTJSCExecutor.h; sourceTree = "<group>"; };
+		134FCB3A1A6E7F0800051CC8 /* RCTJSCExecutor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTJSCExecutor.m; sourceTree = "<group>"; };
 		13513F3A1B1F43F400FCE529 /* RCTProgressViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTProgressViewManager.h; sourceTree = "<group>"; };
 		13513F3B1B1F43F400FCE529 /* RCTProgressViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTProgressViewManager.m; sourceTree = "<group>"; };
 		13723B4E1A82FD3C00F88898 /* RCTStatusBarManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTStatusBarManager.h; sourceTree = "<group>"; };
@@ -300,8 +300,8 @@
 		134FCB381A6E7F0800051CC8 /* Executors */ = {
 			isa = PBXGroup;
 			children = (
-				134FCB391A6E7F0800051CC8 /* RCTContextExecutor.h */,
-				134FCB3A1A6E7F0800051CC8 /* RCTContextExecutor.m */,
+				134FCB391A6E7F0800051CC8 /* RCTJSCExecutor.h */,
+				134FCB3A1A6E7F0800051CC8 /* RCTJSCExecutor.m */,
 			);
 			path = Executors;
 			sourceTree = "<group>";
@@ -679,7 +679,7 @@
 				13A0C2891B74F71200B29F6F /* RCTDevLoadingView.m in Sources */,
 				13B07FF21A69327A00A75B9A /* RCTTiming.m in Sources */,
 				1372B70A1AB030C200659ED6 /* RCTAppState.m in Sources */,
-				134FCB3D1A6E7F0800051CC8 /* RCTContextExecutor.m in Sources */,
+				134FCB3D1A6E7F0800051CC8 /* RCTJSCExecutor.m in Sources */,
 				14C2CA781B3ACB0400E6CBB2 /* RCTBatchedBridge.m in Sources */,
 				13E067591A70F44B002CDEE1 /* UIView+React.m in Sources */,
 				14F484561AABFCE100FDF6B9 /* RCTSliderManager.m in Sources */,

From 1304e781369a3b48b741f1b28c6f985785b1d87b Mon Sep 17 00:00:00 2001
From: Milen Dzhumerov <mgd@fb.com>
Date: Wed, 16 Dec 2015 04:01:41 -0800
Subject: [PATCH 0413/1411] Inline require ExceptionsManager dependencies

Summary:
Inline require `ExceptionsManager` dependencies which are eagerly loaded on app startup (via `setUpConsole()` which is called from `InitializeJavaScriptAppEngine.js`) even though it's necessary until an exception needs to be reported.

This can save about 30-40ms on an iOS device.

public

Reviewed By: nicklockwood, tadeuzagallo, jspahrsummers

Differential Revision: D2755161

fb-gh-sync-id: d4cbfebf04d861b3a70558346a395d3d3ee87cc6
---
 .../Initialization/ExceptionsManager.js               | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/Libraries/JavaScriptAppEngine/Initialization/ExceptionsManager.js b/Libraries/JavaScriptAppEngine/Initialization/ExceptionsManager.js
index 8e652caf0df3..f7537669fde9 100644
--- a/Libraries/JavaScriptAppEngine/Initialization/ExceptionsManager.js
+++ b/Libraries/JavaScriptAppEngine/Initialization/ExceptionsManager.js
@@ -11,12 +11,6 @@
  */
 'use strict';
 
-var RCTExceptionsManager = require('NativeModules').ExceptionsManager;
-
-var loadSourceMap = require('loadSourceMap');
-var parseErrorStack = require('parseErrorStack');
-var stringifySafe = require('stringifySafe');
-
 var sourceMapPromise;
 
 var exceptionID = 0;
@@ -25,6 +19,10 @@ var exceptionID = 0;
  * Handles the developer-visible aspect of errors and exceptions
  */
 function reportException(e: Error, isFatal: bool) {
+  var loadSourceMap = require('loadSourceMap');
+  var parseErrorStack = require('parseErrorStack');
+  var RCTExceptionsManager = require('NativeModules').ExceptionsManager;
+
   var currentExceptionID = ++exceptionID;
   if (RCTExceptionsManager) {
     var stack = parseErrorStack(e);
@@ -83,6 +81,7 @@ function installConsoleErrorReporter() {
     if (arguments[0] && arguments[0].stack) {
       reportException(arguments[0], /* isFatal */ false);
     } else {
+      var stringifySafe = require('stringifySafe');
       var str = Array.prototype.map.call(arguments, stringifySafe).join(', ');
       if (str.slice(0, 10) === '"Warning: ') {
         // React warnings use console.error so that a stack trace is shown, but

From 6ddcef8a2349a378e05172672528e2facd98c439 Mon Sep 17 00:00:00 2001
From: Elliot Hesp <elliot.hesp@gmail.com>
Date: Wed, 16 Dec 2015 05:16:15 -0800
Subject: [PATCH 0414/1411] Update to PullToRefreshViewAndroid docs

Summary:
As mentioned in https://github.com/facebook/react-native/issues/4793 it is not initially clear that the PullToRefreshViewAndroid component needs the `{flex: 1}` style in order for it's child component to function correctly (without examining the example). This will hopefully clear that up.
Closes https://github.com/facebook/react-native/pull/4814

Reviewed By: svcscm

Differential Revision: D2764534

Pulled By: androidtrunkagent

fb-gh-sync-id: ae1c529342e85f8348b4f683e42bf25df5dbea09
---
 Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js b/Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js
index 41acc8017db8..68d6de95d426 100644
--- a/Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js
+++ b/Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js
@@ -23,6 +23,9 @@ var NATIVE_REF = 'native_swiperefreshlayout';
 /**
  * React view that supports a single scrollable child view (e.g. `ScrollView`). When this child
  * view is at `scrollY: 0`, swiping down triggers an `onRefresh` event.
+ * 
+ * The style `{flex: 1}` might be required to ensure the expected behavior of the child component
+ * (e.g. when the child is expected to scroll with `ScrollView` or `ListView`).
  */
 var PullToRefreshViewAndroid = React.createClass({
   statics: {

From 0c09f38aa17666da3aa46545bee9992ab70fd88f Mon Sep 17 00:00:00 2001
From: Qiao Liang <qiaoliang89@gmail.com>
Date: Thu, 17 Dec 2015 00:09:49 +0800
Subject: [PATCH 0415/1411] embed more videos

---
 docs/Videos.md | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/docs/Videos.md b/docs/Videos.md
index 289f75a4c57f..488c16f1adcb 100644
--- a/docs/Videos.md
+++ b/docs/Videos.md
@@ -17,6 +17,10 @@ next: style
 
 <iframe width="650" height="315" src="//www.youtube.com/embed/hDviGU-57lU" frameborder="0" allowfullscreen></iframe>
 
+<iframe width="650" height="315" src="//www.youtube.com/embed/8N4f4h6SThc" frameborder="0" allowfullscreen></iframe>
+
+<iframe width="650" height="315" src="//www.youtube.com/embed/-XxSCi8TKuk" frameborder="0" allowfullscreen></iframe>
+
 ### [The Changelog #149](https://thechangelog.com/149/)
 With Christopher "vjeux" Chedeau and Spencer Ahrens
 

From d131fa0962ed7c241fb1b2e509225b89cca6f6b9 Mon Sep 17 00:00:00 2001
From: Tom Hastjarjanto <tom@intellicode.nl>
Date: Wed, 16 Dec 2015 17:30:43 +0100
Subject: [PATCH 0416/1411] Add Pimmr to showcase

---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 123d6c702477..8c34d6981c7f 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -333,6 +333,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/okanagan-news-reader-for-viewing/id1049147148?mt=8',
     author: 'Levi Cabral',
   },
+  {
+    name: 'Pimmr',
+    icon: 'http://a2.mzstatic.com/eu/r30/Purple69/v4/99/da/0e/99da0ee6-bc87-e1a6-1d95-7027c78f50e1/icon175x175.jpeg',
+    link: 'https://itunes.apple.com/nl/app/pimmr/id1023343303?mt=8&ign-mpt=uo%3D4',
+    author: 'Pimmr'
+  },
   {
     name: 'Posyt - Tinder for ideas',
     icon: 'http://a3.mzstatic.com/us/r30/Purple6/v4/a5/b3/86/a5b38618-a5e9-6089-7425-7fa51ecd5d30/icon175x175.jpeg',

From a38cd48737ec127a65ec8088d5c69437bb5a00a2 Mon Sep 17 00:00:00 2001
From: Tom Hastjarjanto <tom@intellicode.nl>
Date: Wed, 16 Dec 2015 17:32:27 +0100
Subject: [PATCH 0417/1411] Remove part of query string

---
 website/src/react-native/showcase.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 8c34d6981c7f..8e0d3955593c 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -336,7 +336,7 @@ var apps = [
   {
     name: 'Pimmr',
     icon: 'http://a2.mzstatic.com/eu/r30/Purple69/v4/99/da/0e/99da0ee6-bc87-e1a6-1d95-7027c78f50e1/icon175x175.jpeg',
-    link: 'https://itunes.apple.com/nl/app/pimmr/id1023343303?mt=8&ign-mpt=uo%3D4',
+    link: 'https://itunes.apple.com/nl/app/pimmr/id1023343303?mt=8',
     author: 'Pimmr'
   },
   {

From f48dbbecd658123e6fdaacf1b5762692d4d1d7f5 Mon Sep 17 00:00:00 2001
From: Marc Shilling <marc@chalkchisel.com>
Date: Wed, 16 Dec 2015 08:37:00 -0800
Subject: [PATCH 0418/1411] Fix getCurrentPosition

Summary:
Instantiates the _pendingRequests array before trying to add to it. As it currently stands, we try to add the pending request before the array is created. getCurrentPosition always fails on the first try.
Closes https://github.com/facebook/react-native/pull/4764

Reviewed By: svcscm

Differential Revision: D2764751

Pulled By: androidtrunkagent

fb-gh-sync-id: 411a03ff16d40725d8cc0909607632045eb5a27b
---
 Libraries/Geolocation/RCTLocationObserver.m | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Libraries/Geolocation/RCTLocationObserver.m b/Libraries/Geolocation/RCTLocationObserver.m
index 9f9d57aa247f..6ea912e45c1d 100644
--- a/Libraries/Geolocation/RCTLocationObserver.m
+++ b/Libraries/Geolocation/RCTLocationObserver.m
@@ -130,7 +130,6 @@ - (void)beginLocationUpdates
     _locationManager = [CLLocationManager new];
     _locationManager.distanceFilter = RCT_DEFAULT_LOCATION_ACCURACY;
     _locationManager.delegate = self;
-    _pendingRequests = [NSMutableArray new];
   }
 
   // Request location access permission
@@ -234,6 +233,9 @@ - (void)timeout:(NSTimer *)timer
                                                         selector:@selector(timeout:)
                                                         userInfo:request
                                                          repeats:NO];
+  if (!_pendingRequests) {
+    _pendingRequests = [NSMutableArray new];
+  }
   [_pendingRequests addObject:request];
 
   // Configure location manager and begin updating location

From 42a1620b1e439d5e991fcdb689232e4dd0ebeeaf Mon Sep 17 00:00:00 2001
From: Denis Koroskin <dkoroskin@fb.com>
Date: Wed, 16 Dec 2015 10:05:43 -0800
Subject: [PATCH 0419/1411] Remove referenced to dropped views

Reviewed By: ahmedre

Differential Revision: D2757310

fb-gh-sync-id: 2ac97476823879d60dac63920f5e7f086872888a
---
 .../facebook/react/uimanager/NativeViewHierarchyManager.java    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
index 2193fa3d4837..858b621db3e0 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
@@ -420,7 +420,7 @@ protected final void addRootViewGroup(
   /**
    * Releases all references to given native View.
    */
-  private void dropView(View view) {
+  protected final void dropView(View view) {
     UiThreadUtil.assertOnUiThread();
     if (!mRootTags.get(view.getId())) {
       // For non-root views we notify viewmanager with {@link ViewManager#onDropInstance}

From 1be5777265eced0ec96680dc88f9510f7a80e0b2 Mon Sep 17 00:00:00 2001
From: Mike Armstrong <mikea@fb.com>
Date: Wed, 16 Dec 2015 10:44:39 -0800
Subject: [PATCH 0420/1411] define out the memory heap jsc functions

Reviewed By: mkonicek

Differential Revision: D2764964

fb-gh-sync-id: 26eff3e29762287f3527de84b146cee90eccd580
---
 ReactAndroid/src/main/jni/react/JSCExecutor.cpp | 5 +++++
 ReactAndroid/src/main/jni/react/JSCMemory.cpp   | 4 ++--
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index e38e1a6867d8..b678aff4ced6 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -30,7 +30,10 @@ using fbsystrace::FbSystraceSection;
 
 // Add native performance markers support
 #include <react/JSCPerfLogging.h>
+
+#ifdef WITH_FB_MEMORY_PROFILING
 #include <react/JSCMemory.h>
+#endif
 
 #ifdef WITH_FB_JSC_TUNING
 #include <jsc_config_android.h>
@@ -134,7 +137,9 @@ JSCExecutor::JSCExecutor(FlushImmediateCallback cb) :
   addNativePerfLoggingHooks(m_context);
   #endif
 
+  #ifdef WITH_FB_MEMORY_PROFILING
   addNativeMemoryHooks(m_context);
+  #endif
 }
 
 JSCExecutor::~JSCExecutor() {
diff --git a/ReactAndroid/src/main/jni/react/JSCMemory.cpp b/ReactAndroid/src/main/jni/react/JSCMemory.cpp
index 585fd64c470b..f0316bd2a4a8 100644
--- a/ReactAndroid/src/main/jni/react/JSCMemory.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCMemory.cpp
@@ -8,7 +8,7 @@
 
 #include "Value.h"
 
-#if WITH_FB_MEMORY_PROFILING
+#ifdef WITH_FB_MEMORY_PROFILING
 
 static JSValueRef nativeEnableAllocationTag(
     JSContextRef ctx,
@@ -143,7 +143,7 @@ namespace facebook {
 namespace react {
 
 void addNativeMemoryHooks(JSGlobalContextRef ctx) {
-#if WITH_FB_MEMORY_PROFILING
+#ifdef WITH_FB_MEMORY_PROFILING
   installGlobalFunction(ctx, "nativeEnableAllocationTag", nativeEnableAllocationTag);
   installGlobalFunction(ctx, "nativeAllocationPushTag", nativeAllocationPushTag);
   installGlobalFunction(ctx, "nativeAllocationPopTag", nativeAllocationPopTag);

From 12778f3bc65d3582c0085287585c92df0610cc34 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Wed, 16 Dec 2015 11:59:22 -0800
Subject: [PATCH 0421/1411] fork unbundle output format per platform

Summary:
We decided to use different storage formats for android and ios. This diff changes the output format to asset files if the platform is `'android'`.

public

Reviewed By: martinbigio

Differential Revision: D2764739

fb-gh-sync-id: 4a5ac13ba7978112e9424573643e90cef2a1b75f
---
 local-cli/bundle/output/unbundle/as-assets.js | 103 ++++++++++++++++++
 .../as-indexed-file.js}                       |  63 +++++------
 local-cli/bundle/output/unbundle/index.js     |  29 +++++
 .../bundle/output/unbundle/write-sourcemap.js |  24 ++++
 4 files changed, 185 insertions(+), 34 deletions(-)
 create mode 100644 local-cli/bundle/output/unbundle/as-assets.js
 rename local-cli/bundle/output/{unbundle.js => unbundle/as-indexed-file.js} (82%)
 create mode 100644 local-cli/bundle/output/unbundle/index.js
 create mode 100644 local-cli/bundle/output/unbundle/write-sourcemap.js

diff --git a/local-cli/bundle/output/unbundle/as-assets.js b/local-cli/bundle/output/unbundle/as-assets.js
new file mode 100644
index 000000000000..f4f429c2969a
--- /dev/null
+++ b/local-cli/bundle/output/unbundle/as-assets.js
@@ -0,0 +1,103 @@
+/**
+ * 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.
+ */
+'use strict';
+
+const fs = require('fs');
+const mkdirp = require('mkdirp');
+const path = require('path');
+const Promise = require('promise');
+
+const writeFile = require('../writeFile');
+const writeSourceMap = require('./write-sourcemap');
+const MODULES_DIR = 'js-modules';
+
+/**
+ * Saves all JS modules of an app as single files
+ * The startup code (prelude, polyfills etc.) are written to the file
+ * designated by the `bundleOuput` option.
+ * All other modules go into a 'js-modules' folder that in the same parent
+ * directory as the startup file.
+ */
+function saveAsAssets(bundle, options, log) {
+  const {
+    'bundle-output': bundleOutput,
+    'bundle-encoding': encoding,
+    dev,
+    'sourcemap-output': sourcemapOutput,
+  } = options;
+
+  log('start');
+  const {startupCode, modules} = bundle.getUnbundle({minify: !dev});
+  log('finish');
+
+  log('Writing bundle output to:', bundleOutput);
+  const writeUnbundle =
+    Promise.all([
+      writeModules(path.dirname(bundleOutput), modules, encoding),
+      writeStartupFile(bundleOutput, startupCode, encoding)
+    ]);
+  writeUnbundle.then(() => log('Done writing unbundle output'));
+
+  return Promise.all([writeUnbundle, writeSourceMap(sourcemapOutput, '', log)]);
+}
+
+function createDir(dirName) {
+  return new Promise((resolve, reject) =>
+    mkdirp(dirName, error => error ? reject(error) : resolve()));
+}
+
+function createDirectoriesForModules(modulesDir, modules) {
+  const dirNames =
+    modules.map(name => {
+      // get all needed directory names
+      const dir = path.dirname(name);
+      return dir === '.' ? modulesDir : path.join(modulesDir, dir);
+    })
+    .filter(Boolean) // remove empty directories
+    .sort()
+    .filter((dir, i, dirs) => {
+      // remove parent directories. After sorting, parent directories are
+      // located before child directories
+      const next = dirs[i + 1];
+      return !next || next !== dir && !next.startsWith(dir + path.sep);
+    });
+
+  return dirNames.reduce(
+    (promise, dirName) =>
+      promise.then(() => createDir(dirName)), Promise.resolve());
+}
+
+function writeModuleFile(module, modulesDir, encoding) {
+  const {name, code} = module;
+  return writeFile(path.join(modulesDir, name + '.js'), code, encoding);
+}
+
+function writeModuleFiles(modules, modulesDir, encoding) {
+  const writeFiles =
+    modules.map(module => writeModuleFile(module, modulesDir, encoding));
+  return Promise.all(writeFiles);
+}
+
+function writeModules(assetsDest, modules, encoding) {
+  const modulesDir = path.join(assetsDest, MODULES_DIR);
+
+  return (
+    createDirectoriesForModules(modulesDir, modules.map(({name}) => name))
+      .then(() => writeModuleFiles(modules, modulesDir, encoding))
+  );
+}
+
+function writeStartupFile(outputFile, code, encoding) {
+  return new Promise((resolve, reject) => {
+    fs.createWriteStream(outputFile).
+      write(code, encoding, error => error ? reject(error) : resolve());
+  });
+}
+
+module.exports = saveAsAssets;
diff --git a/local-cli/bundle/output/unbundle.js b/local-cli/bundle/output/unbundle/as-indexed-file.js
similarity index 82%
rename from local-cli/bundle/output/unbundle.js
rename to local-cli/bundle/output/unbundle/as-indexed-file.js
index de265c7dfc39..65243375a06f 100644
--- a/local-cli/bundle/output/unbundle.js
+++ b/local-cli/bundle/output/unbundle/as-indexed-file.js
@@ -10,16 +10,19 @@
 
 const fs = require('fs');
 const Promise = require('promise');
-const writeFile = require('./writeFile');
+const writeSourceMap = require('./write-sourcemap');
 
 const MAGIC_UNBUNDLE_FILE_HEADER = 0xFB0BD1E5;
 const MAGIC_STARTUP_MODULE_ID = '';
 
-function buildBundle(packagerClient, requestOptions) {
-  return packagerClient.buildBundle({...requestOptions, unbundle: true});
-}
-
-function saveUnbundle(bundle, options, log) {
+/**
+ * Saves all JS modules of an app as a single file, separated with null bytes.
+ * The file begins with an offset table that contains module ids and their
+ * lengths/offsets.
+ * The module id for the startup code (prelude, polyfills etc.) is the
+ * empty string.
+ */
+function saveAsIndexedFile(bundle, options, log) {
   const {
     'bundle-output': bundleOutput,
     'bundle-encoding': encoding,
@@ -39,21 +42,24 @@ function saveUnbundle(bundle, options, log) {
 
   writeUnbundle.then(() => log('Done writing unbundle output'));
 
-  if (sourcemapOutput) {
-    log('Writing sourcemap output to:', sourcemapOutput);
-    const writeMap = writeFile(sourcemapOutput, '', null);
-    writeMap.then(() => log('Done writing sourcemap output'));
-    return Promise.all([writeUnbundle, writeMap]);
-  } else {
-    return writeUnbundle;
-  }
+  return Promise.all([writeUnbundle, writeSourceMap(sourcemapOutput, '', log)]);
 }
 
 /* global Buffer: true */
+
 const fileHeader = Buffer(4);
 fileHeader.writeUInt32LE(MAGIC_UNBUNDLE_FILE_HEADER);
 const nullByteBuffer = Buffer(1).fill(0);
 
+function writeBuffers(stream, buffers) {
+  buffers.forEach(buffer => stream.write(buffer));
+  return new Promise((resolve, reject) => {
+    stream.on('error', reject);
+    stream.on('finish', () => resolve());
+    stream.end();
+  });
+}
+
 const moduleToBuffer = ({name, code}, encoding) => ({
   name,
   buffer: Buffer.concat([
@@ -62,16 +68,9 @@ const moduleToBuffer = ({name, code}, encoding) => ({
   ])
 });
 
-function buildModuleBuffers(startupCode, modules, encoding) {
-  return (
-    [moduleToBuffer({name: '', code: startupCode}, encoding)]
-      .concat(modules.map(module => moduleToBuffer(module, encoding)))
-  );
-}
-
 function uInt32Buffer(n) {
   const buffer = Buffer(4);
-  buffer.writeUInt32LE(n, 0); // let's assume LE for now :)
+  buffer.writeUInt32LE(n, 0);
   return buffer;
 }
 
@@ -109,21 +108,17 @@ function buildModuleTable(buffers) {
   return Buffer.concat(offsetTable);
 }
 
+function buildModuleBuffers(startupCode, modules, encoding) {
+  return (
+    [moduleToBuffer({name: '', code: startupCode}, encoding)]
+      .concat(modules.map(module => moduleToBuffer(module, encoding)))
+  );
+}
+
 function buildTableAndContents(startupCode, modules, encoding) {
   const buffers = buildModuleBuffers(startupCode, modules, encoding);
   const table = buildModuleTable(buffers, encoding);
   return [fileHeader, table].concat(buffers.map(({buffer}) => buffer));
 }
 
-function writeBuffers(stream, buffers) {
-  buffers.forEach(buffer => stream.write(buffer));
-  return new Promise((resolve, reject) => {
-    stream.on('error', reject);
-    stream.on('finish', () => resolve());
-    stream.end();
-  });
-}
-
-exports.build = buildBundle;
-exports.save = saveUnbundle;
-exports.formatName = 'bundle';
+module.exports = saveAsIndexedFile;
diff --git a/local-cli/bundle/output/unbundle/index.js b/local-cli/bundle/output/unbundle/index.js
new file mode 100644
index 000000000000..eb34cbbbf174
--- /dev/null
+++ b/local-cli/bundle/output/unbundle/index.js
@@ -0,0 +1,29 @@
+/**
+ * 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.
+ */
+'use strict';
+
+const asIndexedFile = require('./as-indexed-file');
+const asAssets = require('./as-assets');
+
+function buildBundle(packagerClient, requestOptions) {
+  return packagerClient.buildBundle({...requestOptions, unbundle: true});
+}
+
+function saveUnbundle(bundle, options, log) {
+  // we fork here depending on the platform:
+  // while android is pretty good at loading individual assets, ios has a large
+  // overhead when reading hundreds pf assets from disk
+  return options.platform === 'android' ?
+    asAssets(bundle, options, log) :
+    asIndexedFile(bundle, options, log);
+}
+
+exports.build = buildBundle;
+exports.save = saveUnbundle;
+exports.formatName = 'bundle';
diff --git a/local-cli/bundle/output/unbundle/write-sourcemap.js b/local-cli/bundle/output/unbundle/write-sourcemap.js
new file mode 100644
index 000000000000..b194b99222e7
--- /dev/null
+++ b/local-cli/bundle/output/unbundle/write-sourcemap.js
@@ -0,0 +1,24 @@
+/**
+ * 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.
+ */
+'use strict';
+
+const Promise = require('promise');
+const writeFile = require('../writeFile');
+
+function writeSourcemap(fileName, contents, log) {
+  if (!fileName) {
+    return Promise.resolve();
+  }
+  log('Writing sourcemap output to:', fileName);
+  const writeMap = writeFile(fileName, '', null);
+  writeMap.then(() => log('Done writing sourcemap output'));
+  return writeMap;
+}
+
+module.exports = writeSourcemap;

From d52723efec30fcc0991dcacd513aeae3a6e1a224 Mon Sep 17 00:00:00 2001
From: James Ide <ide+github@jameside.com>
Date: Wed, 16 Dec 2015 14:24:22 -0800
Subject: [PATCH 0422/1411] [README] Add Circle CI status to the README

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index b7eff88088fc..4cc7c5273f80 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# React Native [![Build Status](https://travis-ci.org/facebook/react-native.svg?branch=master)](https://travis-ci.org/facebook/react-native)  [![npm version](https://badge.fury.io/js/react-native.svg)](http://badge.fury.io/js/react-native)
+# React Native [![Build Status](https://travis-ci.org/facebook/react-native.svg?branch=master)](https://travis-ci.org/facebook/react-native) [![Circle CI](https://circleci.com/gh/facebook/react-native.svg?style=svg)](https://circleci.com/gh/facebook/react-native) [![npm version](https://badge.fury.io/js/react-native.svg)](http://badge.fury.io/js/react-native)
 
 React Native enables you to build world-class application experiences on native platforms using a consistent developer experience based on JavaScript and [React](http://facebook.github.io/react). The focus of React Native is on developer efficiency across all the platforms you care about - learn once, write anywhere. Facebook uses React Native in multiple production apps and will continue investing in React Native.
 

From f48961388e7eb58a52164f7bf9809b5af11e4f43 Mon Sep 17 00:00:00 2001
From: Sameer Rahmani <lxsameer@gnu.org>
Date: Wed, 16 Dec 2015 15:05:26 -0800
Subject: [PATCH 0423/1411] =?UTF-8?q?FloatFromLeft=20scene=20configuration?=
 =?UTF-8?q?=20fixed.=20HorizontalSwipeJumpFromRight=E2=80=A6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Summary:
`FloatFromLeft` configuration was wrong. its animation was ok but the swipe back was wrong. for example you had to swipe from left to right for a `back` action which should be swipe from right to left.

`HorizontalSwipeJumpFromRight` is the same as `HorizontalSwipeJump` but for RTL layouts.
Closes https://github.com/facebook/react-native/pull/4815

Reviewed By: svcscm

Differential Revision: D2766720

Pulled By: androidtrunkagent

fb-gh-sync-id: 2b60f2d238a8f8e5b27dbfb307887934be477c81
---
 .../Navigator/NavigatorSceneConfigs.js        | 25 +++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js b/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js
index 32cd3363a2d3..4281fb194ae8 100644
--- a/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js
+++ b/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js
@@ -515,6 +515,9 @@ var NavigatorSceneConfigs = {
   },
   FloatFromLeft: {
     ...BaseConfig,
+    gestures: {
+      pop: BaseRightToLeftGesture,
+    },
     animationInterpolators: {
       into: buildStyleInterpolator(FromTheLeft),
       out: buildStyleInterpolator(FadeToTheRight),
@@ -574,6 +577,28 @@ var NavigatorSceneConfigs = {
       out: buildStyleInterpolator(ToTheLeft),
     },
   },
+  HorizontalSwipeJumpFromRight: {
+    ...BaseConfig,
+    gestures: {
+      jumpBack: {
+        ...BaseRightToLeftGesture,
+        overswipe: BaseOverswipeConfig,
+        edgeHitWidth: null,
+        isDetachable: true,
+      },
+      jumpForward: {
+        ...BaseLeftToRightGesture,
+        overswipe: BaseOverswipeConfig,
+        edgeHitWidth: null,
+        isDetachable: true,
+      },
+      pop: BaseRightToLeftGesture,
+    },
+    animationInterpolators: {
+      into: buildStyleInterpolator(FromTheLeft),
+      out: buildStyleInterpolator(FadeToTheRight),
+    },
+  },
   VerticalUpSwipeJump: {
     ...BaseConfig,
     gestures: {

From 2a241a242bf6b4f2b47eb2027e22784a0c28c737 Mon Sep 17 00:00:00 2001
From: Jorge Maroto <patoroco@gmail.com>
Date: Wed, 16 Dec 2015 15:59:55 -0800
Subject: [PATCH 0424/1411] Move Image.resizeMode to component

Summary:
Using resizeMode on Image component returns a warning, it needs to be passed by param
Closes https://github.com/facebook/react-native/pull/4791

Reviewed By: svcscm

Differential Revision: D2767093

Pulled By: spicyj

fb-gh-sync-id: 5ab6a2e949d4c68244b5e890a429aaf1f15118a9
---
 Examples/UIExplorer/ImageCapInsetsExample.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Examples/UIExplorer/ImageCapInsetsExample.js b/Examples/UIExplorer/ImageCapInsetsExample.js
index 8e17ac9285a7..8c6ab243e977 100644
--- a/Examples/UIExplorer/ImageCapInsetsExample.js
+++ b/Examples/UIExplorer/ImageCapInsetsExample.js
@@ -35,6 +35,7 @@ var ImageCapInsetsExample = React.createClass({
           <Image
             source={require('image!story-background')}
             style={styles.storyBackground}
+            resizeMode={Image.resizeMode.stretch}
             capInsets={{left: 0, right: 0, bottom: 0, top: 0}}
           />
         </View>
@@ -66,7 +67,6 @@ var styles = StyleSheet.create({
     width: 250,
     height: 150,
     borderWidth: 1,
-    resizeMode: Image.resizeMode.stretch,
   },
   text: {
     fontSize: 13.5,

From b40631b3ccd60daba390c5f6e646ea9ad8ac79ab Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Wed, 16 Dec 2015 16:15:38 -0800
Subject: [PATCH 0425/1411] Remove unused RKAnalyticsCPULogger

Reviewed By: bryceredd

Differential Revision: D2766801

fb-gh-sync-id: c5088c01bbae6a10b17317cc5ec2adcf157f415e
---
 React/Base/RCTBatchedBridge.m | 12 ------------
 1 file changed, 12 deletions(-)

diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index b4734ddd61ac..e235427731c8 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -29,12 +29,6 @@
               [[[NSThread currentThread] name] isEqualToString:@"com.facebook.React.JavaScript"], \
             @"This method must be called on JS thread")
 
-/**
- * Used by RKAnalyticsCPULogger
- */
-NSString *const RCTEnqueueNotification = @"RCTEnqueueNotification";
-NSString *const RCTDequeueNotification = @"RCTDequeueNotification";
-
 /**
  * Must be kept in sync with `MessageQueue.js`.
  */
@@ -725,8 +719,6 @@ - (void)_actuallyInvokeAndProcessModule:(NSString *)module
 {
   RCTAssertJSThread();
 
-  [[NSNotificationCenter defaultCenter] postNotificationName:RCTEnqueueNotification object:self userInfo:nil];
-
   RCTJavaScriptCallback processResponse = ^(id json, NSError *error) {
     if (error) {
       RCTFatal(error);
@@ -735,7 +727,6 @@ - (void)_actuallyInvokeAndProcessModule:(NSString *)module
     if (!self.isValid) {
       return;
     }
-    [[NSNotificationCenter defaultCenter] postNotificationName:RCTDequeueNotification object:self userInfo:nil];
     [self handleBuffer:json batchEnded:YES];
   };
 
@@ -750,8 +741,6 @@ - (void)_actuallyInvokeCallback:(NSNumber *)cbID
 {
   RCTAssertJSThread();
 
-  [[NSNotificationCenter defaultCenter] postNotificationName:RCTEnqueueNotification object:self userInfo:nil];
-
   RCTJavaScriptCallback processResponse = ^(id json, NSError *error) {
     if (error) {
       RCTFatal(error);
@@ -760,7 +749,6 @@ - (void)_actuallyInvokeCallback:(NSNumber *)cbID
     if (!self.isValid) {
       return;
     }
-    [[NSNotificationCenter defaultCenter] postNotificationName:RCTDequeueNotification object:self userInfo:nil];
     [self handleBuffer:json batchEnded:YES];
   };
 

From 5da0e135b6224a2ec9677da3494b8c1e90b06908 Mon Sep 17 00:00:00 2001
From: Pasindu Perera <perera.pasindu@gmail.com>
Date: Thu, 17 Dec 2015 14:00:45 +0530
Subject: [PATCH 0426/1411] npm progress shown on react init fixes #3771 for
 npm 5 and upwards

---
 react-native-cli/index.js | 33 ++++++++++-----------------------
 1 file changed, 10 insertions(+), 23 deletions(-)

diff --git a/react-native-cli/index.js b/react-native-cli/index.js
index 91e87000d1b2..ed9803adb798 100755
--- a/react-native-cli/index.js
+++ b/react-native-cli/index.js
@@ -180,37 +180,24 @@ function createProject(name, verbose) {
 
   console.log('Installing react-native package from npm...');
 
-  if (verbose) {
-    runVerbose(root, projectName);
-  } else {
-    run(root, projectName);
-  }
+  run(root, projectName, verbose);
 }
 
-function run(root, projectName) {
-  exec('npm install --save react-native', function(e, stdout, stderr) {
-    if (e) {
-      console.log(stdout);
-      console.error(stderr);
-      console.error('`npm install --save react-native` failed');
-      process.exit(1);
-    }
-
-    checkNodeVersion();
-
-    var cli = require(CLI_MODULE_PATH());
-    cli.init(root, projectName);
-  });
-}
-
-function runVerbose(root, projectName) {
-  var proc = spawn('npm', ['install', '--verbose', '--save', 'react-native'], {stdio: 'inherit'});
+function run(root, projectName, verbose) {
+  var args = ['install', '--save'];
+  if (verbose){
+    args.push('--verbose');
+  }
+  args.push('react-native');
+  var proc = spawn('npm', args, {stdio: 'inherit'});
   proc.on('close', function (code) {
     if (code !== 0) {
       console.error('`npm install --save react-native` failed');
       return;
     }
 
+    checkNodeVersion();
+
     cli = require(CLI_MODULE_PATH());
     cli.init(root, projectName);
   });

From f58f3913c03178861c4c344311c46d51bdfb6224 Mon Sep 17 00:00:00 2001
From: "luke.avery" <luke.avery@dubitlimited.com>
Date: Thu, 17 Dec 2015 11:30:17 +0000
Subject: [PATCH 0427/1411] added WEARVR app to showcase

---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 123d6c702477..421c20ed50b2 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -405,6 +405,12 @@ var apps = [
     link: 'https://itunes.apple.com/cn/app/tong-xing-wang/id914254459?mt=8',
     author: 'Ho Yin Tsun Eugene',
   },
+  {
+    name: 'WEARVR',
+    icon: 'http://a2.mzstatic.com/eu/r30/Purple69/v4/4f/5a/28/4f5a2876-9530-ef83-e399-c5ef5b2dab80/icon175x175.png',
+    link: 'https://itunes.apple.com/gb/app/wearvr/id1066288171?mt=8',
+    author: 'WEARVR LLC',
+  },
   {
     name: 'WOOP',
     icon: 'http://a4.mzstatic.com/us/r30/Purple6/v4/b0/44/f9/b044f93b-dbf3-9ae5-0f36-9b4956628cab/icon350x350.jpeg',

From f9dfb90a358ddda2d41830ece1876bd19fc03cfe Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 17 Dec 2015 06:45:53 -0800
Subject: [PATCH 0428/1411] Added ability to use a custom view for MapView
 annotations

Summary:
public
This diff adds the ability to specify a custom React component (aka view) to be displayed as a MapView pin.

This makes it possible to use remote images (using an <Image/> component), or text (using a <Text/> component), or anything else.

One consequence of this is that MapView can no longer support arbitrary subviews. To place views in front the map, add them to a separate container view.

Reviewed By: tadeuzagallo

Differential Revision: D2764790

fb-gh-sync-id: e16b44e866c2d76c76b0cb35ef9eefbfc68d6719
---
 Examples/UIExplorer/MapViewExample.js   | 217 +++++++---------------
 Libraries/Components/MapView/MapView.js | 227 ++++++++++++++----------
 React/Views/RCTConvert+MapKit.h         |   3 -
 React/Views/RCTConvert+MapKit.m         |  11 +-
 React/Views/RCTMap.h                    |   4 +-
 React/Views/RCTMap.m                    |  21 ++-
 React/Views/RCTMapAnnotation.h          |   4 +
 React/Views/RCTMapManager.m             | 149 +++++++++++-----
 8 files changed, 339 insertions(+), 297 deletions(-)

diff --git a/Examples/UIExplorer/MapViewExample.js b/Examples/UIExplorer/MapViewExample.js
index 44142a4af160..407e40f00511 100644
--- a/Examples/UIExplorer/MapViewExample.js
+++ b/Examples/UIExplorer/MapViewExample.js
@@ -17,10 +17,12 @@
 
 var React = require('react-native');
 var {
+  Image,
   MapView,
   StyleSheet,
   Text,
   TextInput,
+  TouchableOpacity,
   View,
 } = React;
 
@@ -239,14 +241,14 @@ var MapViewExample = React.createClass({
 
 });
 
-type CalloutMapViewExampleState = {
+type AnnotationExampleState = {
   isFirstLoad: boolean,
   annotations?: Annotations,
   mapRegion?: MapRegion,
 };
-var CalloutMapViewExample = React.createClass({
+var AnnotationExample = React.createClass({
 
-  getInitialState(): CalloutMapViewExampleState {
+  getInitialState(): AnnotationExampleState {
     return {
       isFirstLoad: true,
     };
@@ -260,91 +262,7 @@ var CalloutMapViewExample = React.createClass({
           annotations: [{
             longitude: region.longitude,
             latitude: region.latitude,
-            title: 'More Info...',
-            hasRightCallout: true,
-            onRightCalloutPress: () => {
-              alert('You Are Here');
-            },
-          }],
-        });
-      };
-    }
-
-    return (
-      <MapView
-        style={styles.map}
-        onRegionChangeComplete={onRegionChangeComplete}
-        region={this.state.mapRegion}
-        annotations={this.state.annotations}
-      />
-    );
-  },
-
-});
-
-type CustomPinColorMapViewExampleState = {
-  isFirstLoad: boolean,
-  annotations?: Annotations,
-  mapRegion?: MapRegion,
-};
-var CustomPinColorMapViewExample = React.createClass({
-
-  getInitialState(): CustomPinColorMapViewExampleState {
-    return {
-      isFirstLoad: true,
-    };
-  },
-
-  render() {
-    if (this.state.isFirstLoad) {
-      var onRegionChangeComplete = (region) => {
-        this.setState({
-          isFirstLoad: false,
-          annotations: [{
-            longitude: region.longitude,
-            latitude: region.latitude,
-            title: 'You Are Purple',
-            tintColor: MapView.PinColors.PURPLE,
-          }],
-        });
-      };
-    }
-
-    return (
-      <MapView
-        style={styles.map}
-        onRegionChangeComplete={onRegionChangeComplete}
-        region={this.state.mapRegion}
-        annotations={this.state.annotations}
-      />
-    );
-  },
-
-});
-
-type CustomPinImageMapViewExampleState = {
-  isFirstLoad: boolean,
-  annotations?: Annotations,
-  mapRegion?: MapRegion,
-};
-var CustomPinImageMapViewExample = React.createClass({
-
-  getInitialState(): CustomPinImageMapViewExampleState {
-    return {
-      isFirstLoad: true,
-    };
-  },
-
-  render() {
-    if (this.state.isFirstLoad) {
-      var onRegionChangeComplete = (region) => {
-        this.setState({
-          isFirstLoad: false,
-          annotations: [{
-            longitude: region.longitude,
-            latitude: region.latitude,
-            title: 'Thumbs Up!',
-            image: require('image!uie_thumb_big'),
+            ...this.props.annotation,
           }],
         });
       };
@@ -362,61 +280,6 @@ var CustomPinImageMapViewExample = React.createClass({
 
 });
 
-type Overlays = Array<{
-  coordinates?: Array<{
-    latitude: number,
-    longitude: number,
-  }>,
-  lineWidth?: number,
-  strokeColor?: string,
-  fillColor?: string,
-  id?: string,
-}>;
-type CustomOverlayMapViewExampleState = {
-  isFirstLoad: boolean,
-  overlays?: Overlays,
-  annotations?: Annotations,
-  mapRegion?: MapRegion,
-};
-var CustomOverlayMapViewExample = React.createClass({
-
-  getInitialState(): CustomOverlayMapViewExampleState {
-    return {
-      isFirstLoad: true,
-    };
-  },
-
-  render() {
-    if (this.state.isFirstLoad) {
-      var onRegionChangeComplete = (region) => {
-        this.setState({
-          isFirstLoad: false,
-          overlays: [{
-            coordinates:[
-              {latitude: 32.47, longitude: -107.85},
-              {latitude: 45.13, longitude: -94.48},
-              {latitude: 39.27, longitude: -83.25},
-              {latitude: 32.47, longitude: -107.85},
-            ],
-            strokeColor: '#f007',
-            lineWidth: 3,
-          }],
-        });
-      };
-    }
-
-    return (
-      <MapView
-        style={styles.map}
-        onRegionChangeComplete={onRegionChangeComplete}
-        region={this.state.mapRegion}
-        overlays={this.state.overlays}
-      />
-    );
-  },
-
-});
-
 var styles = StyleSheet.create({
   map: {
     height: 150,
@@ -451,36 +314,92 @@ exports.description = 'Base component to display maps';
 exports.examples = [
   {
     title: 'Map',
-    render(): ReactElement { return <MapViewExample />; }
+    render() {
+      return <MapViewExample />;
+    }
   },
   {
     title: 'Map shows user location',
     render() {
-      return  <MapView style={styles.map} showsUserLocation={true} />;
+      return <MapView style={styles.map} showsUserLocation={true} />;
     }
   },
   {
     title: 'Callout example',
     render() {
-      return  <CalloutMapViewExample style={styles.map} />;
+      return <AnnotationExample style={styles.map} annotation={{
+        title: 'More Info...',
+        rightCalloutView: (
+          <TouchableOpacity
+            onPress={() => {
+              alert('You Are Here');
+            }}>
+            <Image
+              style={{width:30, height:30}}
+              source={require('image!uie_thumb_selected')}
+            />
+          </TouchableOpacity>
+        ),
+      }}/>;
     }
   },
   {
     title: 'Custom pin color',
     render() {
-      return  <CustomPinColorMapViewExample style={styles.map} />;
+      return <AnnotationExample style={styles.map} annotation={{
+        title: 'You Are Purple',
+        tintColor: MapView.PinColors.PURPLE,
+      }}/>;
     }
   },
   {
     title: 'Custom pin image',
     render() {
-      return  <CustomPinImageMapViewExample style={styles.map} />;
+      return <AnnotationExample style={styles.map} annotation={{
+        title: 'Thumbs Up!',
+        image: require('image!uie_thumb_big'),
+      }}/>;
+    }
+  },
+  {
+    title: 'Custom pin view',
+    render() {
+      return <AnnotationExample style={styles.map} annotation={{
+        title: 'Thumbs Up!',
+        view: <View style={{
+          alignItems: 'center',
+        }}>
+          <Text style={{fontWeight: 'bold', color: '#f007'}}>
+            Thumbs Up!
+          </Text>
+          <Image
+            style={{width: 90, height: 65, resizeMode: 'cover'}}
+            source={require('image!uie_thumb_big')}
+          />
+        </View>,
+      }}/>;
     }
   },
   {
     title: 'Custom overlay',
     render() {
-      return  <CustomOverlayMapViewExample style={styles.map} />;
+      return <MapView
+        style={styles.map}
+        region={{
+          latitude: 39.06,
+          longitude: -95.22,
+        }}
+        overlays={[{
+          coordinates:[
+            {latitude: 32.47, longitude: -107.85},
+            {latitude: 45.13, longitude: -94.48},
+            {latitude: 39.27, longitude: -83.25},
+            {latitude: 32.47, longitude: -107.85},
+          ],
+          strokeColor: '#f007',
+          lineWidth: 3,
+        }]}
+      />;
     }
   },
 ];
diff --git a/Libraries/Components/MapView/MapView.js b/Libraries/Components/MapView/MapView.js
index 747e366fcb70..8fcddb77c39b 100644
--- a/Libraries/Components/MapView/MapView.js
+++ b/Libraries/Components/MapView/MapView.js
@@ -11,78 +11,31 @@
  */
 'use strict';
 
-var EdgeInsetsPropType = require('EdgeInsetsPropType');
-var Image = require('Image');
-var NativeMethodsMixin = require('NativeMethodsMixin');
-var Platform = require('Platform');
-var RCTMap = require('UIManager').RCTMap;
-var RCTMapConstants = RCTMap && RCTMap.Constants;
-var React = require('React');
-var View = require('View');
-
-var processColor = require('processColor');
-var resolveAssetSource = require('resolveAssetSource');
-var requireNativeComponent = require('requireNativeComponent');
+const EdgeInsetsPropType = require('EdgeInsetsPropType');
+const Image = require('Image');
+const NativeMethodsMixin = require('NativeMethodsMixin');
+const Platform = require('Platform');
+const RCTMapConfig = require('UIManager').RCTMap;
+const RCTMapConstants = RCTMapConfig && RCTMapConfig.Constants;
+const React = require('React');
+const StyleSheet = require('StyleSheet');
+const View = require('View');
+
+const processColor = require('processColor');
+const resolveAssetSource = require('resolveAssetSource');
+const requireNativeComponent = require('requireNativeComponent');
 
 type Event = Object;
 type MapRegion = {
   latitude: number;
   longitude: number;
-  latitudeDelta: number;
-  longitudeDelta: number;
+  latitudeDelta?: ?number;
+  longitudeDelta?: ?number;
 };
 
-var MapView = React.createClass({
+const MapView = React.createClass({
   mixins: [NativeMethodsMixin],
 
-  checkAnnotationIds: function (annotations: Array<Object>) {
-
-    var newAnnotations = annotations.map(function (annotation) {
-      if (!annotation.id) {
-        // TODO: add a base64 (or similar) encoder here
-        annotation.id = encodeURIComponent(JSON.stringify(annotation));
-      }
-      return annotation;
-    });
-
-    this.setState({
-      annotations: newAnnotations
-    });
-  },
-
-  checkOverlayIds: function (overlays: Array<Object>) {
-
-    var newOverlays = overlays.map(function (overlay) {
-      if (!overlay.id) {
-        // TODO: add a base64 (or similar) encoder here
-        overlay.id = encodeURIComponent(JSON.stringify(overlay));
-      }
-      return overlay;
-    });
-
-    this.setState({
-      overlays: newOverlays
-    });
-  },
-
-  componentWillMount: function() {
-    if (this.props.annotations) {
-      this.checkAnnotationIds(this.props.annotations);
-    }
-    if (this.props.overlays) {
-      this.checkOverlayIds(this.props.overlays);
-    }
-  },
-
-  componentWillReceiveProps: function(nextProps: Object) {
-    if (nextProps.annotations) {
-      this.checkAnnotationIds(nextProps.annotations);
-    }
-    if (nextProps.overlays) {
-      this.checkOverlayIds(nextProps.overlays);
-    }
-  },
-
   propTypes: {
     ...View.propTypes,
     /**
@@ -151,6 +104,8 @@ var MapView = React.createClass({
      * - standard: standard road map (default)
      * - satellite: satellite view
      * - hybrid: satellite view with roads and points of interest overlaid
+     *
+     * @platform ios
      */
     mapType: React.PropTypes.oneOf([
       'standard',
@@ -175,12 +130,13 @@ var MapView = React.createClass({
        * Distance between the minimum and the maximum latitude/longitude
        * to be displayed.
        */
-      latitudeDelta: React.PropTypes.number.isRequired,
-      longitudeDelta: React.PropTypes.number.isRequired,
+      latitudeDelta: React.PropTypes.number,
+      longitudeDelta: React.PropTypes.number,
     }),
 
     /**
      * Map annotations with title/subtitle.
+     * @platform ios
      */
     annotations: React.PropTypes.arrayOf(React.PropTypes.shape({
       /**
@@ -199,19 +155,14 @@ var MapView = React.createClass({
        */
       title: React.PropTypes.string,
       subtitle: React.PropTypes.string,
-
-      /**
-       * Whether the Annotation has callout buttons.
-       */
-      hasLeftCallout: React.PropTypes.bool,
-      hasRightCallout: React.PropTypes.bool,
-
+      
       /**
-       * Event handlers for callout buttons.
+       * Callout views.
        */
-      onLeftCalloutPress: React.PropTypes.func,
-      onRightCalloutPress: React.PropTypes.func,
-
+      leftCalloutView: React.PropTypes.element,
+      rightCalloutView: React.PropTypes.element,
+      detailCalloutView: React.PropTypes.element,
+      
       /**
        * The pin color. This can be any valid color string, or you can use one
        * of the predefined PinColors constants. Applies to both standard pins
@@ -220,24 +171,40 @@ var MapView = React.createClass({
        * Note that on iOS 8 and earlier, only the standard PinColor constants
        * are supported for regular pins. For custom pin images, any tintColor
        * value is supported on all iOS versions.
-       * @platform ios
        */
-      tintColor: React.PropTypes.string,
+      tintColor: React.PropTypes.oneOfType([
+        React.PropTypes.string,
+        React.PropTypes.number
+      ]),
 
       /**
        * Custom pin image. This must be a static image resource inside the app.
-       * @platform ios
        */
       image: Image.propTypes.source,
 
+      /**
+       * Custom pin view. If set, this replaces the pin or custom pin image.
+       */
+      view: React.PropTypes.element,
+
       /**
        * annotation id
        */
       id: React.PropTypes.string,
+            
+      /**
+       * Deprecated. Use the left/right/detailsCalloutView props instead.
+       */
+      hasLeftCallout: React.PropTypes.bool,
+      hasRightCallout: React.PropTypes.bool,
+      onLeftCalloutPress: React.PropTypes.func,
+      onRightCalloutPress: React.PropTypes.func,
+
     })),
 
     /**
      * Map overlays
+     * @platform ios
      */
     overlays: React.PropTypes.arrayOf(React.PropTypes.shape({
       /**
@@ -252,8 +219,14 @@ var MapView = React.createClass({
        * Line attributes
        */
       lineWidth: React.PropTypes.number,
-      strokeColor: React.PropTypes.string,
-      fillColor: React.PropTypes.string,
+      strokeColor: React.PropTypes.oneOfType([
+        React.PropTypes.string,
+        React.PropTypes.number
+      ]),
+      fillColor: React.PropTypes.oneOfType([
+        React.PropTypes.string,
+        React.PropTypes.number
+      ]),
 
       /**
        * Overlay id
@@ -263,17 +236,20 @@ var MapView = React.createClass({
 
     /**
      * Maximum size of area that can be displayed.
+     * @platform ios
      */
     maxDelta: React.PropTypes.number,
 
     /**
      * Minimum size of area that can be displayed.
+     * @platform ios
      */
     minDelta: React.PropTypes.number,
 
     /**
      * Insets for the map's legal label, originally at bottom left of the map.
      * See `EdgeInsetsPropType.js` for more information.
+     * @platform ios
      */
     legalLabelInsets: EdgeInsetsPropType,
 
@@ -299,22 +275,81 @@ var MapView = React.createClass({
   },
 
   render: function() {
-
-    let {annotations, overlays} = this.props;
-    annotations = annotations && annotations.map((annotation: Object) => {
-      let {tintColor, image} = annotation;
+    let children = [], {annotations, overlays} = this.props;
+    annotations = annotations && annotations.map((annotation: Object, index: number) => {
+      let {
+        id,
+        image,
+        tintColor,
+        view,
+        leftCalloutView,
+        rightCalloutView,
+        detailCalloutView,
+      } = annotation;
+      
+      if (!view && image && tintColor) {
+        view = <Image
+          style={{
+            tintColor: processColor(tintColor),
+          }}
+          source={image}
+        />;
+      }
+      if (view) {
+        var viewIndex = children.length;
+        children.push(React.cloneElement(view, {
+          style: [styles.annotationView, view.props.style || {}]
+        }));
+      }
+      if (leftCalloutView) {
+        var leftCalloutViewIndex = children.length;
+        children.push(React.cloneElement(leftCalloutView, {
+          style: [styles.calloutView, leftCalloutView.props.style || {}]
+        }));
+      }
+      if (rightCalloutView) {
+        var rightCalloutViewIndex = children.length;
+        children.push(React.cloneElement(rightCalloutView, {
+          style: [styles.calloutView, rightCalloutView.props.style || {}]
+        }));
+      }
+      if (detailCalloutView) {
+        var detailCalloutViewIndex = children.length;
+        children.push(React.cloneElement(detailCalloutView, {
+          style: [styles.calloutView, detailCalloutView.props.style || {}]
+        }));
+      }
+      ['hasLeftCallout', 'onLeftCalloutPress'].forEach(key => {
+        if (annotation[key]) {
+          console.warn('`' + key + '` is deprecated. Use leftCalloutView instead.');
+        }
+      });
+      ['hasRightCallout', 'onRightCalloutPress'].forEach(key => {
+        if (annotation[key]) {
+          console.warn('`' + key + '` is deprecated. Use rightCalloutView instead.');
+        }
+      });
       return {
         ...annotation,
         tintColor: tintColor && processColor(tintColor),
-        image: image && resolveAssetSource(image),
+        viewIndex,
+        leftCalloutViewIndex,
+        rightCalloutViewIndex,
+        detailCalloutViewIndex,
+        view: undefined,
+        leftCalloutView: undefined,
+        rightCalloutView: undefined,
+        detailCalloutView: undefined,
+        id: id || String(index),
       };
     });
-    overlays = overlays && overlays.map((overlay: Object) => {
-      let {strokeColor, fillColor} = overlay;
+    overlays = overlays && overlays.map((overlay: Object, index: number) => {
+      let {id, fillColor, strokeColor} = overlay;
       return {
         ...overlay,
         strokeColor: strokeColor && processColor(strokeColor),
         fillColor: fillColor && processColor(fillColor),
+        id: id || String(index),
       };
     });
 
@@ -364,6 +399,7 @@ var MapView = React.createClass({
       <RCTMap
         {...this.props}
         annotations={annotations}
+        children={children}
         overlays={overlays}
         onPress={onPress}
         onChange={onChange}
@@ -372,6 +408,17 @@ var MapView = React.createClass({
   },
 });
 
+const styles = StyleSheet.create({
+  annotationView: {
+    position: 'absolute',
+    backgroundColor: 'transparent',
+  },
+  calloutView: {
+    position: 'absolute',
+    backgroundColor: 'white',
+  },
+});
+
 /**
  * Standard iOS MapView pin color constants, to be used with the
  * `annotation.tintColor` property. On iOS 8 and earlier these are the
@@ -379,14 +426,14 @@ var MapView = React.createClass({
  * you are not obliged to use these, but they are useful for matching
  * the standard iOS look and feel.
  */
-let PinColors = RCTMapConstants && RCTMapConstants.PinColors;
+const PinColors = RCTMapConstants && RCTMapConstants.PinColors;
 MapView.PinColors = PinColors && {
   RED: PinColors.RED,
   GREEN: PinColors.GREEN,
   PURPLE: PinColors.PURPLE,
 };
 
-var RCTMap = requireNativeComponent('RCTMap', MapView, {
+const RCTMap = requireNativeComponent('RCTMap', MapView, {
   nativeOnly: {onChange: true, onPress: true}
 });
 
diff --git a/React/Views/RCTConvert+MapKit.h b/React/Views/RCTConvert+MapKit.h
index 42add42d9ede..46fddc8dc925 100644
--- a/React/Views/RCTConvert+MapKit.h
+++ b/React/Views/RCTConvert+MapKit.h
@@ -23,10 +23,7 @@
 + (RCTMapAnnotation *)RCTMapAnnotation:(id)json;
 + (RCTMapOverlay *)RCTMapOverlay:(id)json;
 
-typedef NSArray RCTMapAnnotationArray;
 + (NSArray<RCTMapAnnotation *> *)RCTMapAnnotationArray:(id)json;
-
-typedef NSArray RCTMapOverlayArray;
 + (NSArray<RCTMapOverlay *> *)RCTMapOverlayArray:(id)json;
 
 @end
diff --git a/React/Views/RCTConvert+MapKit.m b/React/Views/RCTConvert+MapKit.m
index 78729fe04568..369ec24469b8 100644
--- a/React/Views/RCTConvert+MapKit.m
+++ b/React/Views/RCTConvert+MapKit.m
@@ -50,9 +50,14 @@ + (RCTMapAnnotation *)RCTMapAnnotation:(id)json
   annotation.animateDrop = [RCTConvert BOOL:json[@"animateDrop"]];
   annotation.tintColor = [RCTConvert UIColor:json[@"tintColor"]];
   annotation.image = [RCTConvert UIImage:json[@"image"]];
-  if (annotation.tintColor && annotation.image) {
-    annotation.image = [annotation.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
-  }
+  annotation.viewIndex =
+    [RCTConvert NSInteger:json[@"viewIndex"] ?: @(NSNotFound)];
+  annotation.leftCalloutViewIndex =
+    [RCTConvert NSInteger:json[@"leftCalloutViewIndex"] ?: @(NSNotFound)];
+  annotation.rightCalloutViewIndex =
+    [RCTConvert NSInteger:json[@"rightCalloutViewIndex"] ?: @(NSNotFound)];
+  annotation.detailCalloutViewIndex =
+    [RCTConvert NSInteger:json[@"detailCalloutViewIndex"] ?: @(NSNotFound)];
   return annotation;
 }
 
diff --git a/React/Views/RCTMap.h b/React/Views/RCTMap.h
index a83bb93dad91..63e01473e75a 100644
--- a/React/Views/RCTMap.h
+++ b/React/Views/RCTMap.h
@@ -31,7 +31,7 @@ RCT_EXTERN const CGFloat RCTMapZoomBoundBuffer;
 @property (nonatomic, copy) RCTBubblingEventBlock onChange;
 @property (nonatomic, copy) RCTBubblingEventBlock onPress;
 
-- (void)setAnnotations:(RCTMapAnnotationArray *)annotations;
-- (void)setOverlays:(RCTMapOverlayArray *)overlays;
+- (void)setAnnotations:(NSArray<RCTMapAnnotation *> *)annotations;
+- (void)setOverlays:(NSArray<RCTMapOverlay *> *)overlays;
 
 @end
diff --git a/React/Views/RCTMap.m b/React/Views/RCTMap.m
index 4f542c4c4a30..6996eb2b3a7f 100644
--- a/React/Views/RCTMap.m
+++ b/React/Views/RCTMap.m
@@ -23,6 +23,7 @@ @implementation RCTMap
 {
   UIView *_legalLabel;
   CLLocationManager *_locationManager;
+  NSMutableArray<UIView *> *_reactSubviews;
 }
 
 - (instancetype)init
@@ -30,6 +31,7 @@ - (instancetype)init
   if ((self = [super init])) {
 
     _hasStartedRendering = NO;
+    _reactSubviews = [NSMutableArray new];
 
     // Find Apple link label
     for (UIView *subview in self.subviews) {
@@ -49,6 +51,21 @@ - (void)dealloc
   [_regionChangeObserveTimer invalidate];
 }
 
+- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex
+{
+  [_reactSubviews insertObject:subview atIndex:atIndex];
+}
+
+- (void)removeReactSubview:(UIView *)subview
+{
+  [_reactSubviews removeObject:subview];
+}
+
+- (NSArray<UIView *> *)reactSubviews
+{
+  return _reactSubviews;
+}
+
 - (void)layoutSubviews
 {
   [super layoutSubviews];
@@ -111,7 +128,7 @@ - (void)setRegion:(MKCoordinateRegion)region animated:(BOOL)animated
 
 // TODO: this doesn't preserve order. Should it? If so we should change the
 // algorithm. If not, it would be more efficient to use an NSSet
-- (void)setAnnotations:(RCTMapAnnotationArray *)annotations
+- (void)setAnnotations:(NSArray<RCTMapAnnotation *> *)annotations
 {
   NSMutableArray<NSString *> *newAnnotationIDs = [NSMutableArray new];
   NSMutableArray<RCTMapAnnotation *> *annotationsToDelete = [NSMutableArray new];
@@ -154,7 +171,7 @@ - (void)setAnnotations:(RCTMapAnnotationArray *)annotations
 
 // TODO: this doesn't preserve order. Should it? If so we should change the
 // algorithm. If not, it would be more efficient to use an NSSet
-- (void)setOverlays:(RCTMapOverlayArray *)overlays
+- (void)setOverlays:(NSArray<RCTMapOverlay *> *)overlays
 {
   NSMutableArray *newOverlayIDs = [NSMutableArray new];
   NSMutableArray *overlaysToDelete = [NSMutableArray new];
diff --git a/React/Views/RCTMapAnnotation.h b/React/Views/RCTMapAnnotation.h
index 0f4479c484bd..eb03ebaf9ca2 100644
--- a/React/Views/RCTMapAnnotation.h
+++ b/React/Views/RCTMapAnnotation.h
@@ -17,5 +17,9 @@
 @property (nonatomic, assign) BOOL animateDrop;
 @property (nonatomic, strong) UIColor *tintColor;
 @property (nonatomic, strong) UIImage *image;
+@property (nonatomic, assign) NSInteger viewIndex;
+@property (nonatomic, assign) NSInteger leftCalloutViewIndex;
+@property (nonatomic, assign) NSInteger rightCalloutViewIndex;
+@property (nonatomic, assign) NSInteger detailCalloutViewIndex;
 
 @end
diff --git a/React/Views/RCTMapManager.m b/React/Views/RCTMapManager.m
index e662d486829f..3ef674850507 100644
--- a/React/Views/RCTMapManager.m
+++ b/React/Views/RCTMapManager.m
@@ -67,8 +67,8 @@ - (UIView *)view
 RCT_EXPORT_VIEW_PROPERTY(minDelta, CGFloat)
 RCT_EXPORT_VIEW_PROPERTY(legalLabelInsets, UIEdgeInsets)
 RCT_EXPORT_VIEW_PROPERTY(mapType, MKMapType)
-RCT_EXPORT_VIEW_PROPERTY(annotations, RCTMapAnnotationArray)
-RCT_EXPORT_VIEW_PROPERTY(overlays, RCTMapOverlayArray)
+RCT_EXPORT_VIEW_PROPERTY(annotations, NSArray<RCTMapAnnotation *>)
+RCT_EXPORT_VIEW_PROPERTY(overlays, NSArray<RCTMapOverlay *>)
 RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock)
 RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
 RCT_CUSTOM_VIEW_PROPERTY(region, MKCoordinateRegion, RCTMap)
@@ -125,77 +125,124 @@ - (void)mapView:(RCTMap *)mapView didSelectAnnotationView:(MKAnnotationView *)vi
   }
 }
 
-- (MKAnnotationView *)mapView:(__unused MKMapView *)mapView viewForAnnotation:(RCTMapAnnotation *)annotation
+- (MKAnnotationView *)mapView:(RCTMap *)mapView
+            viewForAnnotation:(RCTMapAnnotation *)annotation
 {
   if (![annotation isKindOfClass:[RCTMapAnnotation class]]) {
     return nil;
   }
 
   MKAnnotationView *annotationView;
-  if (annotation.image) {
-    if (annotation.tintColor) {
-
-      NSString *const reuseIdentifier = @"RCTImageViewAnnotation";
-      NSInteger imageViewTag = 99;
-      annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseIdentifier];
-      if (!annotationView) {
-        annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
-        UIImageView *imageView = [UIImageView new];
-        imageView.tag = imageViewTag;
-        [annotationView addSubview:imageView];
-      }
+  annotationView.clipsToBounds = YES;
+  if (annotation.viewIndex != NSNotFound) {
+
+    NSString *const reuseIdentifier = @"RCTCustomViewAnnotation";
+    annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseIdentifier];
+    if (!annotationView) {
+      annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation
+                                                    reuseIdentifier:reuseIdentifier];
+    }
 
-      UIImageView *imageView = (UIImageView *)[annotationView viewWithTag:imageViewTag];
-      imageView.image = annotation.image;
-      imageView.tintColor = annotation.tintColor;
-      [imageView sizeToFit];
-      imageView.center = CGPointZero;
+    for (UIView *view in annotationView.subviews) {
+      [view removeFromSuperview];
+    }
+    UIView *reactView = mapView.reactSubviews[annotation.viewIndex];
+    annotationView.bounds = reactView.frame;
+    [annotationView addSubview:reactView];
 
-    } else {
+  } else if (annotation.image) {
 
-      NSString *reuseIdentifier = NSStringFromClass([MKAnnotationView class]);
-      annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseIdentifier] ?: [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
-      annotationView.image = annotation.image;
-    }
+    NSString *reuseIdentifier = NSStringFromClass([MKAnnotationView class]);
+    annotationView =
+      [mapView dequeueReusableAnnotationViewWithIdentifier:reuseIdentifier] ?:
+      [[MKAnnotationView alloc] initWithAnnotation:annotation
+                                   reuseIdentifier:reuseIdentifier];
+    annotationView.image = annotation.image;
 
   } else {
 
     NSString *reuseIdentifier = NSStringFromClass([MKPinAnnotationView class]);
-    annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseIdentifier] ?: [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
+    annotationView =
+      [mapView dequeueReusableAnnotationViewWithIdentifier:reuseIdentifier] ?:
+      [[MKPinAnnotationView alloc] initWithAnnotation:annotation
+                                      reuseIdentifier:reuseIdentifier];
     ((MKPinAnnotationView *)annotationView).animatesDrop = annotation.animateDrop;
 
 #if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0
 
     if (![annotationView respondsToSelector:@selector(pinTintColor)]) {
-      NSString *hexColor = annotation.tintColor ? RCTColorToHexString(annotation.tintColor.CGColor) : RCTMapPinRed;
-      ((MKPinAnnotationView *)annotationView).pinColor = [RCTConvert MKPinAnnotationColor:hexColor];
+      NSString *hexColor = annotation.tintColor ?
+        RCTColorToHexString(annotation.tintColor.CGColor) : RCTMapPinRed;
+      ((MKPinAnnotationView *)annotationView).pinColor =
+        [RCTConvert MKPinAnnotationColor:hexColor];
     } else
 
 #endif
 
     {
-      ((MKPinAnnotationView *)annotationView).pinTintColor = annotation.tintColor ?: [MKPinAnnotationView redPinColor];
+      ((MKPinAnnotationView *)annotationView).pinTintColor =
+        annotation.tintColor ?: [MKPinAnnotationView redPinColor];
     }
   }
   annotationView.canShowCallout = true;
 
-  annotationView.leftCalloutAccessoryView = nil;
-  if (annotation.hasLeftCallout) {
-    annotationView.leftCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
+  if (annotation.leftCalloutViewIndex != NSNotFound) {
+    annotationView.leftCalloutAccessoryView =
+      mapView.reactSubviews[annotation.leftCalloutViewIndex];
+  } else if (annotation.hasLeftCallout) {
+    annotationView.leftCalloutAccessoryView =
+      [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
+  } else {
+    annotationView.leftCalloutAccessoryView = nil;
   }
 
-  annotationView.rightCalloutAccessoryView = nil;
-  if (annotation.hasRightCallout) {
-    annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
+  if (annotation.rightCalloutViewIndex != NSNotFound) {
+    annotationView.rightCalloutAccessoryView =
+      mapView.reactSubviews[annotation.rightCalloutViewIndex];
+  } else if (annotation.hasRightCallout) {
+    annotationView.rightCalloutAccessoryView =
+      [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
+  } else {
+    annotationView.rightCalloutAccessoryView = nil;
+  }
+
+  //http://stackoverflow.com/questions/32581049/mapkit-ios-9-detailcalloutaccessoryview-usage
+  if ([annotationView respondsToSelector:@selector(detailCalloutAccessoryView)]) {
+    if (annotation.detailCalloutViewIndex != NSNotFound) {
+      UIView *calloutView = mapView.reactSubviews[annotation.detailCalloutViewIndex];
+      NSLayoutConstraint *widthConstraint =
+        [NSLayoutConstraint constraintWithItem:calloutView
+                                     attribute:NSLayoutAttributeWidth
+                                     relatedBy:NSLayoutRelationEqual
+                                        toItem:nil
+                                     attribute:NSLayoutAttributeNotAnAttribute
+                                    multiplier:1
+                                      constant:calloutView.frame.size.width];
+      [calloutView addConstraint:widthConstraint];
+      NSLayoutConstraint *heightConstraint =
+        [NSLayoutConstraint constraintWithItem:calloutView
+                                     attribute:NSLayoutAttributeHeight
+                                     relatedBy:NSLayoutRelationEqual
+                                        toItem:nil
+                                     attribute:NSLayoutAttributeNotAnAttribute
+                                    multiplier:1
+                                      constant:calloutView.frame.size.height];
+      [calloutView addConstraint:heightConstraint];
+      annotationView.detailCalloutAccessoryView = calloutView;
+    } else {
+      annotationView.detailCalloutAccessoryView = nil;
+    }
   }
 
   return annotationView;
 }
 
-- (MKOverlayRenderer *)mapView:(__unused MKMapView *)mapView rendererForOverlay:(RCTMapOverlay *)overlay
+- (MKOverlayRenderer *)mapView:(__unused MKMapView *)mapView
+            rendererForOverlay:(RCTMapOverlay *)overlay
 {
   if ([overlay isKindOfClass:[RCTMapOverlay class]]) {
-    MKPolylineRenderer *polylineRenderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay];
+    MKPolylineRenderer *polylineRenderer =
+      [[MKPolylineRenderer alloc] initWithPolyline:overlay];
     polylineRenderer.strokeColor = overlay.strokeColor;
     polylineRenderer.lineWidth = overlay.lineWidth;
     return polylineRenderer;
@@ -204,11 +251,12 @@ - (MKOverlayRenderer *)mapView:(__unused MKMapView *)mapView rendererForOverlay:
   }
 }
 
-- (void)mapView:(RCTMap *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
+- (void)mapView:(RCTMap *)mapView annotationView:(MKAnnotationView *)view
+                   calloutAccessoryControlTapped:(UIControl *)control
 {
   if (mapView.onPress) {
 
-    // Pass to js
+    // Pass to JS
     RCTMapAnnotation *annotation = (RCTMapAnnotation *)view.annotation;
     mapView.onPress(@{
       @"side": (control == view.leftCalloutAccessoryView) ? @"left" : @"right",
@@ -236,13 +284,15 @@ - (void)mapView:(RCTMap *)mapView regionWillChangeAnimated:(__unused BOOL)animat
 {
   [self _regionChanged:mapView];
 
-  mapView.regionChangeObserveTimer = [NSTimer timerWithTimeInterval:RCTMapRegionChangeObserveInterval
-                                                             target:self
-                                                           selector:@selector(_onTick:)
-                                                           userInfo:@{ RCTMapViewKey: mapView }
-                                                            repeats:YES];
+  mapView.regionChangeObserveTimer =
+    [NSTimer timerWithTimeInterval:RCTMapRegionChangeObserveInterval
+                            target:self
+                          selector:@selector(_onTick:)
+                          userInfo:@{ RCTMapViewKey: mapView }
+                           repeats:YES];
 
-  [[NSRunLoop mainRunLoop] addTimer:mapView.regionChangeObserveTimer forMode:NSRunLoopCommonModes];
+  [[NSRunLoop mainRunLoop] addTimer:mapView.regionChangeObserveTimer
+                            forMode:NSRunLoopCommonModes];
 }
 
 - (void)mapView:(RCTMap *)mapView regionDidChangeAnimated:(__unused BOOL)animated
@@ -288,15 +338,18 @@ - (void)_regionChanged:(RCTMap *)mapView
   // move, it's likely the map will auto zoom to max/min from time to time.
   // So let's try to make map zoom back to 99% max or 101% min so that there is
   // some buffer, and moving the map won't constantly hit the max/min bound.
-  if (mapView.maxDelta > FLT_EPSILON && region.span.longitudeDelta > mapView.maxDelta) {
+  if (mapView.maxDelta > FLT_EPSILON &&
+      region.span.longitudeDelta > mapView.maxDelta) {
     needZoom = YES;
     newLongitudeDelta = mapView.maxDelta * (1 - RCTMapZoomBoundBuffer);
-  } else if (mapView.minDelta > FLT_EPSILON && region.span.longitudeDelta < mapView.minDelta) {
+  } else if (mapView.minDelta > FLT_EPSILON &&
+             region.span.longitudeDelta < mapView.minDelta) {
     needZoom = YES;
     newLongitudeDelta = mapView.minDelta * (1 + RCTMapZoomBoundBuffer);
   }
   if (needZoom) {
-    region.span.latitudeDelta = region.span.latitudeDelta / region.span.longitudeDelta * newLongitudeDelta;
+    region.span.latitudeDelta =
+      region.span.latitudeDelta / region.span.longitudeDelta * newLongitudeDelta;
     region.span.longitudeDelta = newLongitudeDelta;
     mapView.region = region;
   }

From 521983480ad0c195143c895aa07009823520dcd2 Mon Sep 17 00:00:00 2001
From: Qiao Liang <qiaoliang89@gmail.com>
Date: Fri, 18 Dec 2015 00:11:00 +0800
Subject: [PATCH 0429/1411] updated deprecated sample code in animation doc

---
 Libraries/Animated/src/AnimatedImplementation.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Libraries/Animated/src/AnimatedImplementation.js b/Libraries/Animated/src/AnimatedImplementation.js
index 09f95000da35..9fdda5323fc5 100644
--- a/Libraries/Animated/src/AnimatedImplementation.js
+++ b/Libraries/Animated/src/AnimatedImplementation.js
@@ -1631,12 +1631,12 @@ module.exports = {
    *  then calls `setValue` on the mapped outputs.  e.g.
    *
    *```javascript
-   *  onScroll={this.AnimatedEvent(
+   *  onScroll={Animated.event(
    *    [{nativeEvent: {contentOffset: {x: this._scrollX}}}]
    *    {listener},          // Optional async listener
    *  )
    *  ...
-   *  onPanResponderMove: this.AnimatedEvent([
+   *  onPanResponderMove: Animated.event([
    *    null,                // raw event arg ignored
    *    {dx: this._panX},    // gestureState arg
    *  ]),

From 606b914209137beb6e48e50eabacd7d7e38e322b Mon Sep 17 00:00:00 2001
From: Nader Dabit <dabit3@gmail.com>
Date: Thu, 17 Dec 2015 10:35:16 -0600
Subject: [PATCH 0430/1411] fixed showcase to display well on mobile

---
 website/src/react-native/css/react-native.css | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/website/src/react-native/css/react-native.css b/website/src/react-native/css/react-native.css
index 8547254340e6..e9d22d1b4f7e 100644
--- a/website/src/react-native/css/react-native.css
+++ b/website/src/react-native/css/react-native.css
@@ -1214,3 +1214,11 @@ div[data-twttr-id] iframe {
     margin: 0;
   }
 }
+
+
+@media only screen and (max-device-width: 840px) {
+  .showcaseSection .inner-content {
+    width: 100%;
+  }
+}
+

From fe86771a229373030cddca421b92c7b1df5ee106 Mon Sep 17 00:00:00 2001
From: Andrew Crowell <andrewj.crowell@gmail.com>
Date: Thu, 17 Dec 2015 10:22:56 -0800
Subject: [PATCH 0431/1411] Maintain cursor position when TextInput value is
 changed programmatically

Summary:
This is useful for applying input masks in the onChange handler that you then need to propagate down to the native component. In our case, we add commas as the user enters a price. Without this change, the cursor will end up in the wrong place when the text is transformed in our onChange handler.
Closes https://github.com/facebook/react-native/pull/4716

Reviewed By: svcscm

Differential Revision: D2766236

Pulled By: nicklockwood

fb-gh-sync-id: c4057d77d62507ec9e09eb0242888bf2858d822f
---
 Libraries/Text/RCTTextField.m | 12 +++++++++++-
 Libraries/Text/RCTTextView.m  | 32 +++++++++++++++++++++++++++-----
 2 files changed, 38 insertions(+), 6 deletions(-)

diff --git a/Libraries/Text/RCTTextField.m b/Libraries/Text/RCTTextField.m
index cb1aba3b91bc..24b077baff10 100644
--- a/Libraries/Text/RCTTextField.m
+++ b/Libraries/Text/RCTTextField.m
@@ -71,8 +71,18 @@ - (void)setText:(NSString *)text
   NSInteger eventLag = _nativeEventCount - _mostRecentEventCount;
   if (eventLag == 0 && ![text isEqualToString:self.text]) {
     UITextRange *selection = self.selectedTextRange;
+    NSInteger oldTextLength = self.text.length;
+
     super.text = text;
-    self.selectedTextRange = selection; // maintain cursor position/selection - this is robust to out of bounds
+
+    if (selection.empty) {
+      // maintain cursor position relative to the end of the old text
+      NSInteger offsetStart = [self offsetFromPosition:self.beginningOfDocument toPosition:selection.start];
+      NSInteger offsetFromEnd = oldTextLength - offsetStart;
+      NSInteger newOffset = text.length - offsetFromEnd;
+      UITextPosition *position = [self positionFromPosition:self.beginningOfDocument offset:newOffset];
+      self.selectedTextRange = [self textRangeFromPosition:position toPosition:position];
+    }
   } else if (eventLag > RCTTextUpdateLagWarningThreshold) {
     RCTLogWarn(@"Native TextInput(%@) is %zd events ahead of JS - try to make your JS faster.", self.text, eventLag);
   }
diff --git a/Libraries/Text/RCTTextView.m b/Libraries/Text/RCTTextView.m
index 6c62006927a5..3a0ae8560694 100644
--- a/Libraries/Text/RCTTextView.m
+++ b/Libraries/Text/RCTTextView.m
@@ -163,10 +163,21 @@ - (void)performPendingTextUpdate
   // we temporarily block all textShouldChange events so they are not applied.
   _blockTextShouldChange = YES;
 
-  NSRange range = _textView.selectedRange;
+  UITextRange *selection = _textView.selectedTextRange;
+  NSInteger oldTextLength = _textView.attributedText.length;
+
   _textView.attributedText = _pendingAttributedText;
   _pendingAttributedText = nil;
-  _textView.selectedRange = range;
+
+  if (selection.empty) {
+    // maintain cursor position relative to the end of the old text
+    NSInteger start = [_textView offsetFromPosition:_textView.beginningOfDocument toPosition:selection.start];
+    NSInteger offsetFromEnd = oldTextLength - start;
+    NSInteger newOffset = _textView.attributedText.length - offsetFromEnd;
+    UITextPosition *position = [_textView positionFromPosition:_textView.beginningOfDocument offset:newOffset];
+    _textView.selectedTextRange = [_textView textRangeFromPosition:position toPosition:position];
+  }
+
   [_textView layoutIfNeeded];
 
   [self _setPlaceholderVisibility];
@@ -341,8 +352,8 @@ - (void)textViewDidChangeSelection:(RCTUITextView *)textView
     _previousSelectionRange = textView.selectedTextRange;
 
     UITextRange *selection = textView.selectedTextRange;
-    NSInteger start = [textView offsetFromPosition:[textView beginningOfDocument] toPosition:selection.start];
-    NSInteger end = [textView offsetFromPosition:[textView beginningOfDocument] toPosition:selection.end];
+    NSInteger start = [textView offsetFromPosition:textView.beginningOfDocument toPosition:selection.start];
+    NSInteger end = [textView offsetFromPosition:textView.beginningOfDocument toPosition:selection.end];
     _onSelectionChange(@{
       @"selection": @{
         @"start": @(start),
@@ -357,9 +368,20 @@ - (void)setText:(NSString *)text
   NSInteger eventLag = _nativeEventCount - _mostRecentEventCount;
   if (eventLag == 0 && ![text isEqualToString:_textView.text]) {
     UITextRange *selection = _textView.selectedTextRange;
+    NSInteger oldTextLength = _textView.text.length;
+
     _textView.text = text;
+
+    if (selection.empty) {
+      // maintain cursor position relative to the end of the old text
+      NSInteger start = [_textView offsetFromPosition:_textView.beginningOfDocument toPosition:selection.start];
+      NSInteger offsetFromEnd = oldTextLength - start;
+      NSInteger newOffset = text.length - offsetFromEnd;
+      UITextPosition *position = [_textView positionFromPosition:_textView.beginningOfDocument offset:newOffset];
+      _textView.selectedTextRange = [_textView textRangeFromPosition:position toPosition:position];
+    }
+
     [self _setPlaceholderVisibility];
-    _textView.selectedTextRange = selection; // maintain cursor position/selection - this is robust to out of bounds
   } else if (eventLag > RCTTextUpdateLagWarningThreshold) {
     RCTLogWarn(@"Native TextInput(%@) is %zd events ahead of JS - try to make your JS faster.", self.text, eventLag);
   }

From 3a3af8a385583c7aabfad5f8ff5daa69aa29953f Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Thu, 17 Dec 2015 11:09:22 -0800
Subject: [PATCH 0432/1411] Open souce the Android Dialog module

Summary:
public

The `DialogModule` requires `android.support.v4.app.FragmentManager` which means
every app that wants to use Dialogs would need to have its Activity extend the legacy
`android.support.v4.app.FragmentActivity`.

This diff makes the `DialogModule` work with both the Support `FragmentManager`
(for AdsManager & potentially other fb apps) and the `android.app.FragmentManager`
(for new apps with no legacy dependencies).

Also wrap the native module in the same `Alert` API that we have on iOS and provide
a cross-platform example. In my opinion the iOS Alert API is quite nice and easy to use.

We still keep `AlertIOS` around because of its `prompt` function which is iOS-specific
and also for backwards compatibility.

Reviewed By: foghina

Differential Revision: D2647000

fb-gh-sync-id: e2280451890bff58bd9c933ab53cd99055403858
---
 Examples/UIExplorer/AlertExample.js           | 137 ++++++++++
 Examples/UIExplorer/AlertIOSExample.js        |  68 +----
 Examples/UIExplorer/UIExplorerList.android.js |   1 +
 Libraries/Utilities/Alert.js                  | 126 +++++++++
 Libraries/Utilities/AlertIOS.js               |  11 +-
 Libraries/react-native/react-native.js        |   1 +
 ReactAndroid/build.gradle                     |   2 +-
 .../facebook/react/ReactInstanceManager.java  |   2 +-
 .../react/modules/dialog/AlertFragment.java   |  77 ++++++
 .../react/modules/dialog/DialogModule.java    | 255 ++++++++++++++++++
 .../modules/dialog/SupportAlertFragment.java  |  52 ++++
 .../react/shell/MainReactPackage.java         |   2 +
 .../modules/dialog/DialogModuleTest.java      | 170 ++++++++++++
 13 files changed, 831 insertions(+), 73 deletions(-)
 create mode 100644 Examples/UIExplorer/AlertExample.js
 create mode 100644 Libraries/Utilities/Alert.js
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/dialog/AlertFragment.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/dialog/DialogModule.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/dialog/SupportAlertFragment.java
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/modules/dialog/DialogModuleTest.java

diff --git a/Examples/UIExplorer/AlertExample.js b/Examples/UIExplorer/AlertExample.js
new file mode 100644
index 000000000000..702c49a6c921
--- /dev/null
+++ b/Examples/UIExplorer/AlertExample.js
@@ -0,0 +1,137 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ *
+ */
+
+'use strict';
+
+var React = require('react-native');
+var {
+  Alert,
+  Platform,
+  StyleSheet,
+  Text,
+  TouchableHighlight,
+  View,
+} = React;
+
+var UIExplorerBlock = require('./UIExplorerBlock');
+
+// corporate ipsum > lorem ipsum
+var alertMessage = 'Credibly reintermediate next-generation potentialities after goal-oriented ' +
+                   'catalysts for change. Dynamically revolutionize.';
+
+/**
+ * Simple alert examples.
+ */
+var SimpleAlertExampleBlock = React.createClass({
+
+  render: function() {
+    return (
+      <View>
+        <TouchableHighlight style={styles.wrapper}
+          onPress={() => Alert.alert(
+            'Alert Title',
+            alertMessage,
+          )}>
+          <View style={styles.button}>
+            <Text>Alert with message and default button</Text>
+          </View>
+        </TouchableHighlight>
+        <TouchableHighlight style={styles.wrapper}
+          onPress={() => Alert.alert(
+            'Alert Title',
+            alertMessage,
+            [
+              {text: 'OK', onPress: () => console.log('OK Pressed!')},
+            ]
+          )}>
+          <View style={styles.button}>
+            <Text>Alert with one button</Text>
+          </View>
+        </TouchableHighlight>
+        <TouchableHighlight style={styles.wrapper}
+          onPress={() => Alert.alert(
+            'Alert Title',
+            alertMessage,
+            [
+              {text: 'Cancel', onPress: () => console.log('Cancel Pressed!')},
+              {text: 'OK', onPress: () => console.log('OK Pressed!')},
+            ]
+          )}>
+          <View style={styles.button}>
+            <Text>Alert with two buttons</Text>
+          </View>
+        </TouchableHighlight>
+        <TouchableHighlight style={styles.wrapper}
+          onPress={() => Alert.alert(
+            'Alert Title',
+            null,
+            [
+              {text: 'Foo', onPress: () => console.log('Foo Pressed!')},
+              {text: 'Bar', onPress: () => console.log('Bar Pressed!')},
+              {text: 'Baz', onPress: () => console.log('Baz Pressed!')},
+            ]
+          )}>
+          <View style={styles.button}>
+            <Text>Alert with three buttons</Text>
+          </View>
+        </TouchableHighlight>
+        <TouchableHighlight style={styles.wrapper}
+          onPress={() => Alert.alert(
+            'Foo Title',
+            alertMessage,
+            '..............'.split('').map((dot, index) => ({
+              text: 'Button ' + index,
+              onPress: () => console.log('Pressed ' + index)
+            }))
+          )}>
+          <View style={styles.button}>
+            <Text>Alert with too many buttons</Text>
+          </View>
+        </TouchableHighlight>
+      </View>
+    );
+  },
+});
+
+var AlertExample = React.createClass({
+  statics: {
+    title: 'Alert',
+    description: 'Alerts display a concise and informative message ' +
+    'and prompt the user to make a decision.',
+  },
+  render: function() {
+    return (
+      <UIExplorerBlock title={'Alert'}>
+        <SimpleAlertExampleBlock />
+      </UIExplorerBlock>
+    );
+  }
+});
+
+var styles = StyleSheet.create({
+  wrapper: {
+    borderRadius: 5,
+    marginBottom: 5,
+  },
+  button: {
+    backgroundColor: '#eeeeee',
+    padding: 10,
+  },
+});
+
+module.exports = {
+  AlertExample,
+  SimpleAlertExampleBlock,
+}
diff --git a/Examples/UIExplorer/AlertIOSExample.js b/Examples/UIExplorer/AlertIOSExample.js
index 8666d5ba9bcc..7532e4151bab 100644
--- a/Examples/UIExplorer/AlertIOSExample.js
+++ b/Examples/UIExplorer/AlertIOSExample.js
@@ -24,77 +24,15 @@ var {
   AlertIOS,
 } = React;
 
+var { SimpleAlertExampleBlock } = require('./AlertExample');
+
 exports.framework = 'React';
 exports.title = 'AlertIOS';
 exports.description = 'iOS alerts and action sheets';
 exports.examples = [{
   title: 'Alerts',
   render() {
-    return (
-      <View>
-        <TouchableHighlight style={styles.wrapper}
-          onPress={() => AlertIOS.alert(
-            'Foo Title',
-            'My Alert Msg'
-          )}>
-          <View style={styles.button}>
-            <Text>Alert with message and default button</Text>
-          </View>
-        </TouchableHighlight>
-        <TouchableHighlight style={styles.wrapper}
-          onPress={() => AlertIOS.alert(
-            'Foo Title',
-            null,
-            [
-              {text: 'Button', onPress: () => console.log('Button Pressed!')},
-            ]
-          )}>
-          <View style={styles.button}>
-            <Text>Alert with only one button</Text>
-          </View>
-        </TouchableHighlight>
-        <TouchableHighlight style={styles.wrapper}
-          onPress={() => AlertIOS.alert(
-            'Foo Title',
-            'My Alert Msg',
-            [
-              {text: 'Foo', onPress: () => console.log('Foo Pressed!')},
-              {text: 'Bar', onPress: () => console.log('Bar Pressed!')},
-            ]
-          )}>
-          <View style={styles.button}>
-            <Text>Alert with two buttons</Text>
-          </View>
-        </TouchableHighlight>
-        <TouchableHighlight style={styles.wrapper}
-          onPress={() => AlertIOS.alert(
-            'Foo Title',
-            null,
-            [
-              {text: 'Foo', onPress: () => console.log('Foo Pressed!')},
-              {text: 'Bar', onPress: () => console.log('Bar Pressed!')},
-              {text: 'Baz', onPress: () => console.log('Baz Pressed!')},
-            ]
-          )}>
-          <View style={styles.button}>
-            <Text>Alert with 3 buttons</Text>
-          </View>
-        </TouchableHighlight>
-        <TouchableHighlight style={styles.wrapper}
-          onPress={() => AlertIOS.alert(
-            'Foo Title',
-            'My Alert Msg',
-            '..............'.split('').map((dot, index) => ({
-              text: 'Button ' + index,
-              onPress: () => console.log('Pressed ' + index)
-            }))
-          )}>
-          <View style={styles.button}>
-            <Text>Alert with too many buttons</Text>
-          </View>
-        </TouchableHighlight>
-      </View>
-    );
+    return <SimpleAlertExampleBlock />;
   }
 },
 {
diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index 36746c55861d..e3d05a2b15b3 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -38,6 +38,7 @@ var COMPONENTS = [
 
 var APIS = [
   require('./AccessibilityAndroidExample.android'),
+  require('./AlertExample').AlertExample,
   require('./BorderExample'),
   require('./ClipboardExample'),
   require('./GeolocationExample'),
diff --git a/Libraries/Utilities/Alert.js b/Libraries/Utilities/Alert.js
new file mode 100644
index 000000000000..de434c987df0
--- /dev/null
+++ b/Libraries/Utilities/Alert.js
@@ -0,0 +1,126 @@
+/**
+ * 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 Alert
+ * @flow
+ */
+'use strict';
+
+var AlertIOS = require('AlertIOS');
+var Platform = require('Platform');
+var DialogModuleAndroid = require('NativeModules').DialogManagerAndroid;
+
+import type { AlertType, AlertButtonStyle } from 'AlertIOS';
+
+type Buttons = Array<{
+  text?: string;
+  onPress?: ?Function;
+  style?: AlertButtonStyle;
+}>;
+
+/**
+ * Launches an alert dialog with the specified title and message.
+ *
+ * Optionally provide a list of buttons. Tapping any button will fire the
+ * respective onPress callback and dismiss the alert. By default, the only
+ * button will be an 'OK' button.
+ *
+ * The last button in the list will be considered the 'Primary' button.
+ *
+ * ## iOS
+ *
+ * On iOS you can specify any number of buttons. Each button can optionally
+ * specify a style and you can also specify type of the alert.
+ * Refer to `AlertIOS` for details.
+ *
+ * ## Android
+ * 
+ * On Android at most three buttons can be specified. Android has a concept
+ * of a 'neutral', 'negative' and a 'positive' button:
+ *
+ *   - If you specify one button, it will be the 'positive' one (such as 'OK')
+ *   - Two buttons mean 'negative', 'positive' (such as 'Cancel', 'OK')
+ *   - Three buttons mean 'neutral', 'negative', 'positive' (such as 'Later', 'Cancel', 'OK')
+ *
+ * ```
+ * Alert.alert(
+ *   'Alert Title',
+ *   'My Alert Msg',
+ *   [
+ *     {text: 'Ask me later', onPress: () => console.log('Ask me later pressed')},
+ *     {text: 'Cancel', onPress: () => console.log('Cancel Pressed')},
+ *     {text: 'OK', onPress: () => console.log('OK Pressed')},
+ *   ]
+ * )
+ * ```
+ */
+class Alert {
+
+  static alert(
+    title: ?string,
+    message?: ?string,
+    buttons?: Buttons,
+    type?: AlertType
+  ): void {
+    if (Platform.OS === 'ios') {
+      AlertIOS.alert(title, message, buttons, type);
+    } else if (Platform.OS === 'android') {
+      AlertAndroid.alert(title, message, buttons);
+    }
+  }
+}
+
+/**
+ * Wrapper around the Android native module.
+ */
+class AlertAndroid {
+
+  static alert(
+    title: ?string,
+    message?: ?string,
+    buttons?: Buttons,
+  ): void {
+    var config = {
+      title: title || '',
+      message: message || '',
+    };
+    // At most three buttons (neutral, negative, positive). Ignore rest.
+    // The text 'OK' should be probably localized. iOS Alert does that in native.
+    var validButtons: Buttons = buttons ? buttons.slice(0, 3) : [{text: 'OK'}];
+    var buttonPositive = validButtons.pop();
+    var buttonNegative = validButtons.pop();
+    var buttonNeutral = validButtons.pop();
+    if (buttonNeutral) {
+      config = {...config, buttonNeutral: buttonNeutral.text || '' }
+    }
+    if (buttonNegative) {
+      config = {...config, buttonNegative: buttonNegative.text || '' }
+    }
+    if (buttonPositive) {
+      config = {...config, buttonPositive: buttonPositive.text || '' }
+    }
+    DialogModuleAndroid.showAlert(
+      config,
+      (errorMessage) => console.warn(message),
+      (action, buttonKey) => {
+        if (action !== DialogModuleAndroid.buttonClicked) {
+          return;
+        }
+        if (buttonKey === DialogModuleAndroid.buttonNeutral) {
+          buttonNeutral.onPress && buttonNeutral.onPress();
+        } else if (buttonKey === DialogModuleAndroid.buttonNegative) {
+          buttonNegative.onPress && buttonNegative.onPress();
+        } else if (buttonKey === DialogModuleAndroid.buttonPositive) {
+          buttonPositive.onPress && buttonPositive.onPress();
+        }
+      }
+    );
+  }
+}
+
+module.exports = Alert;
diff --git a/Libraries/Utilities/AlertIOS.js b/Libraries/Utilities/AlertIOS.js
index 2bd1a3223680..38fd0f88c475 100644
--- a/Libraries/Utilities/AlertIOS.js
+++ b/Libraries/Utilities/AlertIOS.js
@@ -14,14 +14,14 @@
 var RCTAlertManager = require('NativeModules').AlertManager;
 var invariant = require('invariant');
 
-type AlertType = $Enum<{
+export type AlertType = $Enum<{
   'default': string;
   'plain-text': string;
   'secure-text': string;
   'login-password': string;
 }>;
 
-type AlertButtonStyle = $Enum<{
+export type AlertButtonStyle = $Enum<{
   'default': string;
   'cancel': string;
   'destructive': string;
@@ -32,20 +32,19 @@ type AlertButtonStyle = $Enum<{
  *
  * Optionally provide a list of buttons. Tapping any button will fire the
  * respective onPress callback and dismiss the alert. By default, the only
- * button will be an 'OK' button
+ * button will be an 'OK' button.
  *
  * ```
  * AlertIOS.alert(
  *   'Foo Title',
  *   'My Alert Msg',
  *   [
- *     {text: 'OK', onPress: () => console.log('OK Pressed!')},
- *     {text: 'Cancel', onPress: () => console.log('Cancel Pressed!'), style: 'cancel'},
+ *     {text: 'OK', onPress: () => console.log('OK Pressed')},
+ *     {text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
  *   ]
  * )
  * ```
  */
-
 class AlertIOS {
   static alert(
     title: ?string,
diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js
index be3dfd26a450..130c4439a446 100644
--- a/Libraries/react-native/react-native.js
+++ b/Libraries/react-native/react-native.js
@@ -51,6 +51,7 @@ var ReactNative = {
   // APIs
   get ActionSheetIOS() { return require('ActionSheetIOS'); },
   get AdSupportIOS() { return require('AdSupportIOS'); },
+  get Alert() { return require('Alert'); },
   get AlertIOS() { return require('AlertIOS'); },
   get Animated() { return require('Animated'); },
   get AppRegistry() { return require('AppRegistry'); },
diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle
index 464a2ad18a34..850d2f41f9a8 100644
--- a/ReactAndroid/build.gradle
+++ b/ReactAndroid/build.gradle
@@ -257,7 +257,7 @@ dependencies {
     testCompile "org.powermock:powermock-classloading-xstream:${POWERMOCK_VERSION}"
     testCompile "org.mockito:mockito-core:${MOCKITO_CORE_VERSION}"
     testCompile "org.easytesting:fest-assert-core:${FEST_ASSERT_CORE_VERSION}"
-    testCompile("org.robolectric:robolectric:${ROBOLECTRIC_VERSION}")
+    testCompile "org.robolectric:robolectric:${ROBOLECTRIC_VERSION}"
 }
 
 apply from: 'release.gradle'
diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
index e8793d241d46..17fb538b826d 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
@@ -186,7 +186,7 @@ public Builder setBundleAssetName(String bundleAssetName) {
     /**
      * Path to the JS bundle file to be loaded from the file system.
      *
-     * Example: {@code "assets://index.android.js" or "/sdcard/main.jsbundle}
+     * Example: {@code "assets://index.android.js" or "/sdcard/main.jsbundle"}
      */
     public Builder setJSBundleFile(String jsBundleFile) {
       mJSBundleFile = jsBundleFile;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/AlertFragment.java b/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/AlertFragment.java
new file mode 100644
index 000000000000..04d6d421a973
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/AlertFragment.java
@@ -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.
+ */
+
+package com.facebook.react.modules.dialog;
+
+import javax.annotation.Nullable;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.content.Context;
+import android.os.Bundle;
+
+/**
+ * A fragment used to display the dialog.
+ */
+/* package */ class AlertFragment extends DialogFragment implements DialogInterface.OnClickListener {
+
+  /* package */ static final String ARG_TITLE = "title";
+  /* package */ static final String ARG_MESSAGE = "message";
+  /* package */ static final String ARG_BUTTON_POSITIVE = "button_positive";
+  /* package */ static final String ARG_BUTTON_NEGATIVE = "button_negative";
+  /* package */ static final String ARG_BUTTON_NEUTRAL = "button_neutral";
+
+  private final @Nullable DialogModule.AlertFragmentListener mListener;
+
+  public AlertFragment(@Nullable DialogModule.AlertFragmentListener listener, Bundle arguments) {
+    mListener = listener;
+    setArguments(arguments);
+  }
+
+  public static Dialog createDialog(
+      Context activityContext, Bundle arguments, DialogInterface.OnClickListener fragment) {
+    AlertDialog.Builder builder = new AlertDialog.Builder(activityContext)
+        .setTitle(arguments.getString(ARG_TITLE))
+        .setMessage(arguments.getString(ARG_MESSAGE));
+
+    if (arguments.containsKey(ARG_BUTTON_POSITIVE)) {
+      builder.setPositiveButton(arguments.getString(ARG_BUTTON_POSITIVE), fragment);
+    }
+    if (arguments.containsKey(ARG_BUTTON_NEGATIVE)) {
+      builder.setNegativeButton(arguments.getString(ARG_BUTTON_NEGATIVE), fragment);
+    }
+    if (arguments.containsKey(ARG_BUTTON_NEUTRAL)) {
+      builder.setNeutralButton(arguments.getString(ARG_BUTTON_NEUTRAL), fragment);
+    }
+
+    return builder.create();
+  }
+
+  @Override
+  public Dialog onCreateDialog(Bundle savedInstanceState) {
+    return createDialog(getActivity(), getArguments(), this);
+  }
+
+  @Override
+  public void onClick(DialogInterface dialog, int which) {
+    if (mListener != null) {
+      mListener.onClick(dialog, which);
+    }
+  }
+
+  @Override
+  public void onDismiss(DialogInterface dialog) {
+    super.onDismiss(dialog);
+    if (mListener != null) {
+      mListener.onDismiss(dialog);
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/DialogModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/DialogModule.java
new file mode 100644
index 000000000000..10dfbc8d4760
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/DialogModule.java
@@ -0,0 +1,255 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.modules.dialog;
+
+import javax.annotation.Nullable;
+
+import java.util.Map;
+
+import android.app.Activity;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.DialogInterface.OnDismissListener;
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.facebook.infer.annotation.Assertions;
+import com.facebook.react.bridge.Callback;
+import com.facebook.react.bridge.LifecycleEventListener;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.common.MapBuilder;
+
+public class DialogModule extends ReactContextBaseJavaModule implements LifecycleEventListener {
+
+  /* package */ static final String FRAGMENT_TAG =
+      "com.facebook.catalyst.react.dialog.DialogModule";
+
+  /* package */ static final String NAME = "DialogManagerAndroid";
+
+  /* package */ static final String ACTION_BUTTON_CLICKED = "buttonClicked";
+  /* package */ static final String ACTION_DISMISSED = "dismissed";
+  /* package */ static final String KEY_TITLE = "title";
+  /* package */ static final String KEY_MESSAGE = "message";
+  /* package */ static final String KEY_BUTTON_POSITIVE = "buttonPositive";
+  /* package */ static final String KEY_BUTTON_NEGATIVE = "buttonNegative";
+  /* package */ static final String KEY_BUTTON_NEUTRAL = "buttonNeutral";
+
+  /* package */ static final Map<String, Object> CONSTANTS = MapBuilder.<String, Object>of(
+      ACTION_BUTTON_CLICKED, ACTION_BUTTON_CLICKED,
+      ACTION_DISMISSED, ACTION_DISMISSED,
+      KEY_BUTTON_POSITIVE, DialogInterface.BUTTON_POSITIVE,
+      KEY_BUTTON_NEGATIVE, DialogInterface.BUTTON_NEGATIVE,
+      KEY_BUTTON_NEUTRAL, DialogInterface.BUTTON_NEUTRAL);
+
+  private boolean mIsInForeground;
+
+  public DialogModule(ReactApplicationContext reactContext) {
+    super(reactContext);
+  }
+
+  @Override
+  public String getName() {
+    return NAME;
+  }
+
+  /**
+   * Helper to allow this module to work with both the standard FragmentManager
+   * and the Support FragmentManager (for apps that need to use it for legacy reasons).
+   * Since the two APIs don't share a common interface there's unfortunately some
+   * code duplication.
+   */
+  private class FragmentManagerHelper {
+
+    // Exactly one of the two is null
+    private final @Nullable android.app.FragmentManager mFragmentManager;
+    private final @Nullable android.support.v4.app.FragmentManager mSupportFragmentManager;
+
+    private @Nullable Object mFragmentToShow;
+
+    private boolean isUsingSupportLibrary() {
+      return mSupportFragmentManager != null;
+    }
+
+    public FragmentManagerHelper(android.support.v4.app.FragmentManager supportFragmentManager) {
+      mFragmentManager = null;
+      mSupportFragmentManager = supportFragmentManager;
+    }
+    public FragmentManagerHelper(android.app.FragmentManager fragmentManager) {
+      mFragmentManager = fragmentManager;
+      mSupportFragmentManager = null;
+    }
+
+    public void showPendingAlert() {
+      if (mFragmentToShow == null) {
+        return;
+      }
+      if (isUsingSupportLibrary()) {
+        ((SupportAlertFragment) mFragmentToShow).show(mSupportFragmentManager, FRAGMENT_TAG);
+      } else {
+        ((AlertFragment) mFragmentToShow).show(mFragmentManager, FRAGMENT_TAG);
+      }
+      mFragmentToShow = null;
+    }
+
+    private void dismissExisting() {
+      if (isUsingSupportLibrary()) {
+        SupportAlertFragment oldFragment =
+            (SupportAlertFragment) mSupportFragmentManager.findFragmentByTag(FRAGMENT_TAG);
+        if (oldFragment != null) {
+          oldFragment.dismiss();
+        }
+      } else {
+        AlertFragment oldFragment =
+            (AlertFragment) mFragmentManager.findFragmentByTag(FRAGMENT_TAG);
+        if (oldFragment != null) {
+          oldFragment.dismiss();
+        }
+      }
+    }
+
+    public void showNewAlert(boolean isInForeground, Bundle arguments, Callback actionCallback) {
+      dismissExisting();
+
+      AlertFragmentListener actionListener =
+          actionCallback != null ? new AlertFragmentListener(actionCallback) : null;
+
+      if (isUsingSupportLibrary()) {
+        SupportAlertFragment alertFragment = new SupportAlertFragment(actionListener, arguments);
+        if (isInForeground) {
+          alertFragment.show(mSupportFragmentManager, FRAGMENT_TAG);
+        } else {
+          mFragmentToShow = alertFragment;
+        }
+      } else {
+        AlertFragment alertFragment = new AlertFragment(actionListener, arguments);
+        if (isInForeground) {
+          alertFragment.show(mFragmentManager, FRAGMENT_TAG);
+        } else {
+          mFragmentToShow = alertFragment;
+        }
+      }
+    }
+  }
+
+  /* package */ class AlertFragmentListener implements OnClickListener, OnDismissListener {
+
+    private final Callback mCallback;
+    private boolean mCallbackConsumed = false;
+
+    public AlertFragmentListener(Callback callback) {
+      mCallback = callback;
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+      if (!mCallbackConsumed) {
+        if (getReactApplicationContext().hasActiveCatalystInstance()) {
+          mCallback.invoke(ACTION_BUTTON_CLICKED, which);
+          mCallbackConsumed = true;
+        }
+      }
+    }
+
+    @Override
+    public void onDismiss(DialogInterface dialog) {
+      if (!mCallbackConsumed) {
+        if (getReactApplicationContext().hasActiveCatalystInstance()) {
+          mCallback.invoke(ACTION_DISMISSED);
+          mCallbackConsumed = true;
+        }
+      }
+    }
+  }
+
+  @Override
+  public Map<String, Object> getConstants() {
+    return CONSTANTS;
+  }
+
+  @Override
+  public void initialize() {
+    getReactApplicationContext().addLifecycleEventListener(this);
+  }
+
+  @Override
+  public void onHostPause() {
+    // Don't show the dialog if the host is paused.
+    mIsInForeground = false;
+  }
+
+  @Override
+  public void onHostDestroy() {
+  }
+
+  @Override
+  public void onHostResume() {
+    mIsInForeground = true;
+    // Check if a dialog has been created while the host was paused, so that we can show it now.
+    FragmentManagerHelper fragmentManagerHelper = getFragmentManagerHelper();
+    Assertions.assertNotNull(
+        fragmentManagerHelper,
+        "Attached DialogModule to host with pending alert but no FragmentManager " +
+        "(not attached to an Activity).");
+    fragmentManagerHelper.showPendingAlert();
+  }
+
+  @ReactMethod
+  public void showAlert(
+      ReadableMap options,
+      Callback errorCallback,
+      Callback actionCallback) {
+    FragmentManagerHelper fragmentManagerHelper = getFragmentManagerHelper();
+    if (fragmentManagerHelper == null) {
+      errorCallback.invoke("Tried to show an alert while not attached to an Activity");
+      return;
+    }
+
+    final Bundle args = new Bundle();
+    if (options.hasKey(KEY_TITLE)) {
+      args.putString(AlertFragment.ARG_TITLE, options.getString(KEY_TITLE));
+    }
+    if (options.hasKey(KEY_MESSAGE)) {
+      args.putString(AlertFragment.ARG_MESSAGE, options.getString(KEY_MESSAGE));
+    }
+    if (options.hasKey(KEY_BUTTON_POSITIVE)) {
+      args.putString(AlertFragment.ARG_BUTTON_POSITIVE, options.getString(KEY_BUTTON_POSITIVE));
+    }
+    if (options.hasKey(KEY_BUTTON_NEGATIVE)) {
+      args.putString(AlertFragment.ARG_BUTTON_NEGATIVE, options.getString(KEY_BUTTON_NEGATIVE));
+    }
+    if (options.hasKey(KEY_BUTTON_NEUTRAL)) {
+      args.putString(AlertFragment.ARG_BUTTON_NEUTRAL, options.getString(KEY_BUTTON_NEUTRAL));
+    }
+
+    fragmentManagerHelper.showNewAlert(mIsInForeground, args, actionCallback);
+  }
+
+  /**
+   * Creates a new helper to work with either the FragmentManager or the legacy support
+   * FragmentManager transparently. Returns null if we're not attached to an Activity.
+   *
+   * DO NOT HOLD LONG-LIVED REFERENCES TO THE OBJECT RETURNED BY THIS METHOD, AS THIS WILL CAUSE
+   * MEMORY LEAKS.
+   */
+  private @Nullable FragmentManagerHelper getFragmentManagerHelper() {
+    Activity activity = getCurrentActivity();
+    if (activity == null) {
+      return null;
+    }
+    if (activity instanceof FragmentActivity) {
+      return new FragmentManagerHelper(((FragmentActivity) activity).getSupportFragmentManager());
+    } else {
+      return new FragmentManagerHelper(activity.getFragmentManager());
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/SupportAlertFragment.java b/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/SupportAlertFragment.java
new file mode 100644
index 000000000000..fb987cd05996
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/SupportAlertFragment.java
@@ -0,0 +1,52 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.modules.dialog;
+
+import javax.annotation.Nullable;
+
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+
+import android.support.v4.app.DialogFragment;
+
+/**
+ * {@link AlertFragment} for apps that use the Support FragmentActivity and FragmentManager
+ * for legacy reasons.
+ */
+/* package */ class SupportAlertFragment extends DialogFragment implements DialogInterface.OnClickListener {
+
+  private final @Nullable DialogModule.AlertFragmentListener mListener;
+
+  public SupportAlertFragment(@Nullable DialogModule.AlertFragmentListener listener, Bundle arguments) {
+    mListener = listener;
+    setArguments(arguments);
+  }
+
+  @Override
+  public Dialog onCreateDialog(Bundle savedInstanceState) {
+    return AlertFragment.createDialog(getActivity(), getArguments(), this);
+  }
+
+  @Override
+  public void onClick(DialogInterface dialog, int which) {
+    if (mListener != null) {
+      mListener.onClick(dialog, which);
+    }
+  }
+
+  @Override
+  public void onDismiss(DialogInterface dialog) {
+    super.onDismiss(dialog);
+    if (mListener != null) {
+      mListener.onDismiss(dialog);
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
index d6d8e37fbb16..aae0e93224db 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
@@ -17,6 +17,7 @@
 import com.facebook.react.bridge.JavaScriptModule;
 import com.facebook.react.bridge.NativeModule;
 import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.modules.dialog.DialogModule;
 import com.facebook.react.modules.fresco.FrescoModule;
 import com.facebook.react.modules.intent.IntentModule;
 import com.facebook.react.modules.location.LocationModule;
@@ -53,6 +54,7 @@ public List<NativeModule> createNativeModules(ReactApplicationContext reactConte
     return Arrays.<NativeModule>asList(
       new AsyncStorageModule(reactContext),
       new ClipboardModule(reactContext),
+      new DialogModule(reactContext),
       new FrescoModule(reactContext),
       new IntentModule(reactContext),
       new LocationModule(reactContext),
diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/dialog/DialogModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/dialog/DialogModuleTest.java
new file mode 100644
index 000000000000..f0ae5dc3acfd
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/modules/dialog/DialogModuleTest.java
@@ -0,0 +1,170 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.modules.dialog;
+
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.app.Activity;
+
+import com.facebook.react.bridge.Callback;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.SimpleMap;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.util.ActivityController;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+@RunWith(RobolectricTestRunner.class)
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+public class DialogModuleTest {
+
+  private ActivityController<Activity> mActivityController;
+  private Activity mActivity;
+  private DialogModule mDialogModule;
+
+  final static class SimpleCallback implements Callback {
+    private Object[] mArgs;
+    private int mCalls;
+
+    @Override
+    public void invoke(Object... args) {
+      mCalls++;
+      mArgs = args;
+    }
+
+    public int getCalls() {
+      return mCalls;
+    }
+
+    public Object[] getArgs() {
+      return mArgs;
+    }
+  }
+
+  @Before
+  public void setUp() throws Exception {
+    mActivityController = Robolectric.buildActivity(Activity.class);
+    mActivity = mActivityController
+        .create()
+        .start()
+        .resume()
+        .get();
+
+    final ReactApplicationContext context = PowerMockito.mock(ReactApplicationContext.class);
+    PowerMockito.when(context.hasActiveCatalystInstance()).thenReturn(true);
+    PowerMockito.when(context, "getCurrentActivity").thenReturn(mActivity);
+
+    mDialogModule = new DialogModule(context);
+    mDialogModule.onHostResume();
+  }
+
+  @After
+  public void tearDown() {
+    mActivityController.pause().stop().destroy();
+
+    mActivityController = null;
+    mDialogModule = null;
+  }
+
+  @Test
+  public void testAllOptions() {
+    final SimpleMap options = new SimpleMap();
+    options.putString("title", "Title");
+    options.putString("message", "Message");
+    options.putString("buttonPositive", "OK");
+    options.putString("buttonNegative", "Cancel");
+    options.putString("buttonNeutral", "Later");
+
+    mDialogModule.showAlert(options, null, null);
+
+    final AlertFragment fragment = getFragment();
+    assertNotNull("Fragment was not displayed", fragment);
+
+    final AlertDialog dialog = (AlertDialog) fragment.getDialog();
+    assertEquals("OK", dialog.getButton(DialogInterface.BUTTON_POSITIVE).getText().toString());
+    assertEquals("Cancel", dialog.getButton(DialogInterface.BUTTON_NEGATIVE).getText().toString());
+    assertEquals("Later", dialog.getButton(DialogInterface.BUTTON_NEUTRAL).getText().toString());
+  }
+
+  @Test
+  public void testCallbackPositive() {
+    final SimpleMap options = new SimpleMap();
+    options.putString("buttonPositive", "OK");
+
+    final SimpleCallback actionCallback = new SimpleCallback();
+    mDialogModule.showAlert(options, null, actionCallback);
+
+    final AlertDialog dialog = (AlertDialog) getFragment().getDialog();
+    dialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick();
+
+    assertEquals(1, actionCallback.getCalls());
+    assertEquals(DialogModule.ACTION_BUTTON_CLICKED, actionCallback.getArgs()[0]);
+    assertEquals(DialogInterface.BUTTON_POSITIVE, actionCallback.getArgs()[1]);
+  }
+
+  @Test
+  public void testCallbackNegative() {
+    final SimpleMap options = new SimpleMap();
+    options.putString("buttonNegative", "Cancel");
+
+    final SimpleCallback actionCallback = new SimpleCallback();
+    mDialogModule.showAlert(options, null, actionCallback);
+
+    final AlertDialog dialog = (AlertDialog) getFragment().getDialog();
+    dialog.getButton(DialogInterface.BUTTON_NEGATIVE).performClick();
+
+    assertEquals(1, actionCallback.getCalls());
+    assertEquals(DialogModule.ACTION_BUTTON_CLICKED, actionCallback.getArgs()[0]);
+    assertEquals(DialogInterface.BUTTON_NEGATIVE, actionCallback.getArgs()[1]);
+  }
+
+  @Test
+  public void testCallbackNeutral() {
+    final SimpleMap options = new SimpleMap();
+    options.putString("buttonNeutral", "Later");
+
+    final SimpleCallback actionCallback = new SimpleCallback();
+    mDialogModule.showAlert(options, null, actionCallback);
+
+    final AlertDialog dialog = (AlertDialog) getFragment().getDialog();
+    dialog.getButton(DialogInterface.BUTTON_NEUTRAL).performClick();
+
+    assertEquals(1, actionCallback.getCalls());
+    assertEquals(DialogModule.ACTION_BUTTON_CLICKED, actionCallback.getArgs()[0]);
+    assertEquals(DialogInterface.BUTTON_NEUTRAL, actionCallback.getArgs()[1]);
+  }
+
+  @Test
+  public void testCallbackDismiss() {
+    final SimpleMap options = new SimpleMap();
+
+    final SimpleCallback actionCallback = new SimpleCallback();
+    mDialogModule.showAlert(options, null, actionCallback);
+
+    getFragment().getDialog().dismiss();
+
+    assertEquals(1, actionCallback.getCalls());
+    assertEquals(DialogModule.ACTION_DISMISSED, actionCallback.getArgs()[0]);
+  }
+
+  private AlertFragment getFragment() {
+    return (AlertFragment) mActivity.getFragmentManager()
+        .findFragmentByTag(DialogModule.FRAGMENT_TAG);
+  }
+}

From 8cd7730080976deeb9a94046717b0cbe32e494f7 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Thu, 17 Dec 2015 11:47:37 -0800
Subject: [PATCH 0433/1411] Open source Android WebView

Summary:
Keep `WebView.android.js` and `WebView.ios.js`, there are
some small differences. Use the same example on both platforms.

public

Reviewed By: bestander

Differential Revision: D2769446

fb-gh-sync-id: be3d0afcbfd6ddcbaa49f70555063b3081ba03cb
---
 Examples/UIExplorer/UIExplorerList.android.js |   1 +
 .../Components/WebView/WebView.android.js     |  17 +-
 Libraries/Components/WebView/WebView.ios.js   |  19 +-
 .../react/shell/MainReactPackage.java         |   4 +-
 .../views/webview/ReactWebViewManager.java    | 325 ++++++++++++++++++
 .../react/views/webview/WebViewConfig.java    |  21 ++
 .../webview/events/TopLoadingErrorEvent.java  |  49 +++
 .../webview/events/TopLoadingFinishEvent.java |  49 +++
 .../webview/events/TopLoadingStartEvent.java  |  49 +++
 9 files changed, 522 insertions(+), 12 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/webview/WebViewConfig.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/webview/events/TopLoadingErrorEvent.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/webview/events/TopLoadingFinishEvent.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/webview/events/TopLoadingStartEvent.java

diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index e3d05a2b15b3..327bf457bf19 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -34,6 +34,7 @@ var COMPONENTS = [
   require('./TouchableExample'),
   require('./ViewExample'),
   require('./ViewPagerAndroidExample.android'),
+  require('./WebViewExample'),
 ];
 
 var APIS = [
diff --git a/Libraries/Components/WebView/WebView.android.js b/Libraries/Components/WebView/WebView.android.js
index d5569dcad39d..f4bc520457bf 100644
--- a/Libraries/Components/WebView/WebView.android.js
+++ b/Libraries/Components/WebView/WebView.android.js
@@ -32,15 +32,14 @@ var WebViewState = keyMirror({
 });
 
 /**
- * Note that WebView is only supported on iOS for now,
- * see https://facebook.github.io/react-native/docs/known-issues.html
+ * Renders a native WebView.
  */
 var WebView = React.createClass({
 
   propTypes: {
     ...View.propTypes,
-    renderError: PropTypes.func, // view to show if there's an error
-    renderLoading: PropTypes.func, // loading indicator to show
+    renderError: PropTypes.func, 
+    renderLoading: PropTypes.func,
     url: PropTypes.string,
     html: PropTypes.string,
     automaticallyAdjustContentInsets: PropTypes.bool,
@@ -48,6 +47,11 @@ var WebView = React.createClass({
     onNavigationStateChange: PropTypes.func,
     startInLoadingState: PropTypes.bool, // force WebView to show loadingView on first load
     style: View.propTypes.style,
+
+    /**
+     * Used on Android only, JS is enabled by default for WebView on iOS
+     * @platform android
+     */
     javaScriptEnabledAndroid: PropTypes.bool,
 
     /**
@@ -56,10 +60,11 @@ var WebView = React.createClass({
     injectedJavaScript: PropTypes.string,
 
     /**
-     * Sets the user-agent for this WebView. The user-agent can also be set in native through
-     * WebViewConfig, but this can and will overwrite that config.
+     * Sets the user-agent for this WebView. The user-agent can also be set in native using
+     * WebViewConfig. This prop will overwrite that config.
      */
     userAgent: PropTypes.string,
+
     /**
      * Used to locate this view in end-to-end tests.
      */
diff --git a/Libraries/Components/WebView/WebView.ios.js b/Libraries/Components/WebView/WebView.ios.js
index 0e5452c9dd08..a51ed3fceb8a 100644
--- a/Libraries/Components/WebView/WebView.ios.js
+++ b/Libraries/Components/WebView/WebView.ios.js
@@ -77,9 +77,6 @@ var defaultRenderError = (errorDomain, errorCode, errorDesc) => (
 
 /**
  * Renders a native WebView.
- *
- * Note that WebView is only supported on iOS for now,
- * see https://facebook.github.io/react-native/docs/known-issues.html
  */
 var WebView = React.createClass({
   statics: {
@@ -91,9 +88,21 @@ var WebView = React.createClass({
     ...View.propTypes,
     url: PropTypes.string,
     html: PropTypes.string,
+    /**
+     * Function that returns a view to show if there's an error.
+     */
     renderError: PropTypes.func, // view to show if there's an error
-    renderLoading: PropTypes.func, // loading indicator to show
+    /**
+     * Function that returns a loading indicator.
+     */
+    renderLoading: PropTypes.func,
+    /**
+     * @platform ios
+     */
     bounces: PropTypes.bool,
+    /**
+     * @platform ios
+     */
     scrollEnabled: PropTypes.bool,
     automaticallyAdjustContentInsets: PropTypes.bool,
     contentInset: EdgeInsetsPropType,
@@ -102,7 +111,7 @@ var WebView = React.createClass({
     style: View.propTypes.style,
 
     /**
-     * Used for android only, JS is enabled by default for WebView on iOS
+     * Used on Android only, JS is enabled by default for WebView on iOS
      * @platform android
      */
     javaScriptEnabledAndroid: PropTypes.bool,
diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
index aae0e93224db..51ca4de448ca 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
@@ -42,6 +42,7 @@
 import com.facebook.react.views.view.ReactViewManager;
 import com.facebook.react.views.viewpager.ReactViewPagerManager;
 import com.facebook.react.views.swiperefresh.SwipeRefreshLayoutManager;
+import com.facebook.react.views.webview.ReactWebViewManager;
 import com.facebook.react.modules.clipboard.ClipboardModule;
 
 /**
@@ -86,6 +87,7 @@ public List<ViewManager> createViewManagers(ReactApplicationContext reactContext
       new ReactViewPagerManager(),
       new ReactTextInlineImageViewManager(),
       new ReactVirtualTextViewManager(),
-      new SwipeRefreshLayoutManager());
+      new SwipeRefreshLayoutManager(),
+      new ReactWebViewManager());
   }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
new file mode 100644
index 000000000000..05f50dcfb1e3
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
@@ -0,0 +1,325 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.webview;
+
+import javax.annotation.Nullable;
+
+import java.util.Map;
+
+import android.graphics.Bitmap;
+import android.os.Build;
+import android.os.SystemClock;
+import android.text.TextUtils;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import com.facebook.catalyst.views.webview.events.TopLoadingErrorEvent;
+import com.facebook.catalyst.views.webview.events.TopLoadingFinishEvent;
+import com.facebook.catalyst.views.webview.events.TopLoadingStartEvent;
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.LifecycleEventListener;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.common.MapBuilder;
+import com.facebook.react.common.build.ReactBuildConfig;
+import com.facebook.react.uimanager.ReactProp;
+import com.facebook.react.uimanager.SimpleViewManager;
+import com.facebook.react.uimanager.ThemedReactContext;
+import com.facebook.react.uimanager.UIManagerModule;
+import com.facebook.react.uimanager.events.EventDispatcher;
+
+/**
+ * Manages instances of {@link WebView}
+ *
+ * Can accept following commands:
+ *  - GO_BACK
+ *  - GO_FORWARD
+ *  - RELOAD
+ *
+ * {@link WebView} instances could emit following direct events:
+ *  - topLoadingFinish
+ *  - topLoadingStart
+ *  - topLoadingError
+ *
+ * Each event will carry the following properties:
+ *  - target - view's react tag
+ *  - url - url set for the webview
+ *  - loading - whether webview is in a loading state
+ *  - title - title of the current page
+ *  - canGoBack - boolean, whether there is anything on a history stack to go back
+ *  - canGoForward - boolean, whether it is possible to request GO_FORWARD command
+ */
+public class ReactWebViewManager extends SimpleViewManager<WebView> {
+
+  private static final String REACT_CLASS = "RCTWebView";
+
+  private static final String HTML_ENCODING = "UTF-8";
+  private static final String HTML_MIME_TYPE = "text/html";
+
+  public static final int COMMAND_GO_BACK = 1;
+  public static final int COMMAND_GO_FORWARD = 2;
+  public static final int COMMAND_RELOAD = 3;
+
+  // Use `webView.loadUrl("about:blank")` to reliably reset the view
+  // state and release page resources (including any running JavaScript).
+  private static final String BLANK_URL = "about:blank";
+
+  private WebViewConfig mWebViewConfig;
+
+  static {
+    if (ReactBuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+      WebView.setWebContentsDebuggingEnabled(true);
+    }
+  }
+
+  private static class ReactWebViewClient extends WebViewClient {
+
+    private boolean mLastLoadFailed = false;
+
+    @Override
+    public void onPageFinished(WebView webView, String url) {
+      super.onPageFinished(webView, url);
+
+      if (!mLastLoadFailed) {
+        ReactWebView reactWebView = (ReactWebView) webView;
+        reactWebView.callInjectedJavaScript();
+        emitFinishEvent(webView);
+      }
+    }
+
+    @Override
+    public void onPageStarted(WebView webView, String url, Bitmap favicon) {
+      super.onPageStarted(webView, url, favicon);
+      mLastLoadFailed = false;
+
+      ReactContext reactContext = (ReactContext) ((ReactWebView) webView).getContext();
+      EventDispatcher eventDispatcher =
+          reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
+      eventDispatcher.dispatchEvent(
+          new TopLoadingStartEvent(
+              webView.getId(),
+              SystemClock.uptimeMillis(),
+              createWebViewEvent(webView)));
+    }
+
+    @Override
+    public void onReceivedError(
+        WebView webView,
+        int errorCode,
+        String description,
+        String failingUrl) {
+      super.onReceivedError(webView, errorCode, description, failingUrl);
+      mLastLoadFailed = true;
+
+      // In case of an error JS side expect to get a finish event first, and then get an error event
+      // Android WebView does it in the oposite way, so we need to simulate that behavior
+      emitFinishEvent(webView);
+
+      ReactContext reactContext = (ReactContext) ((ReactWebView) webView).getContext();
+      WritableMap eventData = createWebViewEvent(webView);
+      eventData.putDouble("code", errorCode);
+      eventData.putString("description", description);
+
+      EventDispatcher eventDispatcher =
+          reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
+      eventDispatcher.dispatchEvent(
+          new TopLoadingErrorEvent(webView.getId(), SystemClock.uptimeMillis(), eventData));
+    }
+
+    @Override
+    public void doUpdateVisitedHistory(WebView webView, String url, boolean isReload) {
+      super.doUpdateVisitedHistory(webView, url, isReload);
+
+      ReactContext reactContext = (ReactContext) webView.getContext();
+      EventDispatcher eventDispatcher =
+          reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
+      eventDispatcher.dispatchEvent(
+          new TopLoadingStartEvent(
+              webView.getId(),
+              SystemClock.uptimeMillis(),
+              createWebViewEvent(webView)));
+    }
+
+    private void emitFinishEvent(WebView webView) {
+      ReactContext reactContext = (ReactContext) webView.getContext();
+
+      EventDispatcher eventDispatcher =
+          reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
+      eventDispatcher.dispatchEvent(
+          new TopLoadingFinishEvent(
+              webView.getId(),
+              SystemClock.uptimeMillis(),
+              createWebViewEvent(webView)));
+    }
+
+    private WritableMap createWebViewEvent(WebView webView) {
+      WritableMap event = Arguments.createMap();
+      event.putDouble("target", webView.getId());
+      event.putString("url", webView.getUrl());
+      event.putBoolean("loading", !mLastLoadFailed && webView.getProgress() != 100);
+      event.putString("title", webView.getTitle());
+      event.putBoolean("canGoBack", webView.canGoBack());
+      event.putBoolean("canGoForward", webView.canGoForward());
+      return event;
+    }
+  }
+
+  /**
+   * Subclass of {@link WebView} that implements {@link LifecycleEventListener} interface in order
+   * to call {@link WebView#destroy} on activty destroy event and also to clear the client
+   */
+  private static class ReactWebView extends WebView implements LifecycleEventListener {
+    private @Nullable String injectedJS;
+
+    /**
+     * WebView must be created with an context of the current activity
+     *
+     * Activity Context is required for creation of dialogs internally by WebView
+     * Reactive Native needed for access to ReactNative internal system functionality
+     *
+     */
+    public ReactWebView(ThemedReactContext reactContext) {
+      super(reactContext);
+    }
+
+    @Override
+    public void onHostResume() {
+      // do nothing
+    }
+
+    @Override
+    public void onHostPause() {
+      // do nothing
+    }
+
+    @Override
+    public void onHostDestroy() {
+      cleanupCallbacksAndDestroy();
+    }
+
+    public void setInjectedJavaScript(@Nullable String js) {
+      injectedJS = js;
+    }
+
+    public void callInjectedJavaScript() {
+      if (
+          getSettings().getJavaScriptEnabled() &&
+              injectedJS != null &&
+              !TextUtils.isEmpty(injectedJS)) {
+        loadUrl("javascript:(function() {\n" + injectedJS + ";\n})();");
+      }
+    }
+
+    private void cleanupCallbacksAndDestroy() {
+      setWebViewClient(null);
+      destroy();
+    }
+  }
+
+  public ReactWebViewManager() {
+    mWebViewConfig = new WebViewConfig() {
+      public void configWebView(WebView webView) {
+      }
+    };
+  }
+
+  public ReactWebViewManager(WebViewConfig webViewConfig) {
+    mWebViewConfig = webViewConfig;
+  }
+
+  @Override
+  public String getName() {
+    return REACT_CLASS;
+  }
+
+  @Override
+  protected WebView createViewInstance(ThemedReactContext reactContext) {
+    ReactWebView webView = new ReactWebView(reactContext);
+    reactContext.addLifecycleEventListener(webView);
+    mWebViewConfig.configWebView(webView);
+    return webView;
+  }
+
+  @ReactProp(name = "javaScriptEnabledAndroid")
+  public void setJavaScriptEnabled(WebView view, boolean enabled) {
+    view.getSettings().setJavaScriptEnabled(enabled);
+  }
+
+  @ReactProp(name = "userAgent")
+  public void setUserAgent(WebView view, @Nullable String userAgent) {
+    if (userAgent != null) {
+      // TODO(8496850): Fix incorrect behavior when property is unset (uA == null)
+      view.getSettings().setUserAgentString(userAgent);
+    }
+  }
+
+  @ReactProp(name = "injectedJavaScript")
+  public void setInjectedJavaScript(WebView view, @Nullable String injectedJavaScript) {
+    ((ReactWebView) view).setInjectedJavaScript(injectedJavaScript);
+  }
+
+  @ReactProp(name = "html")
+  public void setHtml(WebView view, @Nullable String html) {
+    if (html != null) {
+      view.loadData(html, HTML_MIME_TYPE, HTML_ENCODING);
+    } else {
+      view.loadUrl(BLANK_URL);
+    }
+  }
+
+  @ReactProp(name = "url")
+  public void setUrl(WebView view, @Nullable String url) {
+    // TODO(8495359): url and html are coupled as they both call loadUrl, therefore in case when
+    // property url is removed in favor of property html being added in single transaction we may
+    // end up in a state when blank url is loaded as it depends onthe oreder of update operations!
+    if (url != null) {
+      view.loadUrl(url);
+    } else {
+      view.loadUrl(BLANK_URL);
+    }
+  }
+
+  @Override
+  protected void addEventEmitters(ThemedReactContext reactContext, WebView view) {
+    // Do not register default touch emitter and let WebView implementation handle touches
+    view.setWebViewClient(new ReactWebViewClient());
+  }
+
+  @Override
+  public @Nullable Map<String, Integer> getCommandsMap() {
+    return MapBuilder.of(
+        "goBack", COMMAND_GO_BACK,
+        "goForward", COMMAND_GO_FORWARD,
+        "reload", COMMAND_RELOAD);
+  }
+
+  @Override
+  public void receiveCommand(WebView root, int commandId, @Nullable ReadableArray args) {
+    switch (commandId) {
+      case COMMAND_GO_BACK:
+        root.goBack();
+        break;
+      case COMMAND_GO_FORWARD:
+        root.goForward();
+        break;
+      case COMMAND_RELOAD:
+        root.reload();
+        break;
+    }
+  }
+
+  @Override
+  public void onDropViewInstance(ThemedReactContext reactContext, WebView webView) {
+    super.onDropViewInstance(reactContext, webView);
+    reactContext.removeLifecycleEventListener((ReactWebView) webView);
+    ((ReactWebView) webView).cleanupCallbacksAndDestroy();
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/WebViewConfig.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/WebViewConfig.java
new file mode 100644
index 000000000000..7b2f1241efad
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/WebViewConfig.java
@@ -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.
+ */
+
+package com.facebook.react.views.webview;
+
+import android.webkit.WebView;
+
+/**
+ * Implement this interface in order to config your {@link WebView}. An instance of that
+ * implementation will have to be given as a constructor argument to {@link ReactWebViewManager}.
+ */
+public interface WebViewConfig {
+
+  void configWebView(WebView webView);
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/events/TopLoadingErrorEvent.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/events/TopLoadingErrorEvent.java
new file mode 100644
index 000000000000..f97b30e9007a
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/events/TopLoadingErrorEvent.java
@@ -0,0 +1,49 @@
+/**
+ * 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.
+ */
+
+package com.facebook.catalyst.views.webview.events;
+
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.uimanager.events.Event;
+import com.facebook.react.uimanager.events.RCTEventEmitter;
+
+/**
+ * Event emitted when there is an error in loading.
+ */
+public class TopLoadingErrorEvent extends Event<TopLoadingErrorEvent> {
+
+  public static final String EVENT_NAME = "topLoadingError";
+  private WritableMap mEventData;
+
+  public TopLoadingErrorEvent(int viewId, long timestampMs, WritableMap eventData) {
+    super(viewId, timestampMs);
+    mEventData = eventData;
+  }
+
+  @Override
+  public String getEventName() {
+    return EVENT_NAME;
+  }
+
+  @Override
+  public boolean canCoalesce() {
+    return false;
+  }
+
+  @Override
+  public short getCoalescingKey() {
+    // All events for a given view can be coalesced.
+    return 0;
+  }
+
+  @Override
+  public void dispatch(RCTEventEmitter rctEventEmitter) {
+    rctEventEmitter.receiveEvent(getViewTag(), getEventName(), mEventData);
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/events/TopLoadingFinishEvent.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/events/TopLoadingFinishEvent.java
new file mode 100644
index 000000000000..b03447043cbe
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/events/TopLoadingFinishEvent.java
@@ -0,0 +1,49 @@
+/**
+ * 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.
+ */
+
+package com.facebook.catalyst.views.webview.events;
+
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.uimanager.events.Event;
+import com.facebook.react.uimanager.events.RCTEventEmitter;
+
+/**
+ * Event emitted when loading is completed.
+ */
+public class TopLoadingFinishEvent extends Event<TopLoadingFinishEvent> {
+
+  public static final String EVENT_NAME = "topLoadingFinish";
+  private WritableMap mEventData;
+
+  public TopLoadingFinishEvent(int viewId, long timestampMs, WritableMap eventData) {
+    super(viewId, timestampMs);
+    mEventData = eventData;
+  }
+
+  @Override
+  public String getEventName() {
+    return EVENT_NAME;
+  }
+
+  @Override
+  public boolean canCoalesce() {
+    return false;
+  }
+
+  @Override
+  public short getCoalescingKey() {
+    // All events for a given view can be coalesced.
+    return 0;
+  }
+
+  @Override
+  public void dispatch(RCTEventEmitter rctEventEmitter) {
+    rctEventEmitter.receiveEvent(getViewTag(), getEventName(), mEventData);
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/events/TopLoadingStartEvent.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/events/TopLoadingStartEvent.java
new file mode 100644
index 000000000000..5154ab807747
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/events/TopLoadingStartEvent.java
@@ -0,0 +1,49 @@
+/**
+ * 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.
+ */
+
+package com.facebook.catalyst.views.webview.events;
+
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.uimanager.events.Event;
+import com.facebook.react.uimanager.events.RCTEventEmitter;
+
+/**
+ * Event emitted when loading has started
+ */
+public class TopLoadingStartEvent extends Event<TopLoadingStartEvent> {
+
+  public static final String EVENT_NAME = "topLoadingStart";
+  private WritableMap mEventData;
+
+  public TopLoadingStartEvent(int viewId, long timestampMs, WritableMap eventData) {
+    super(viewId, timestampMs);
+    mEventData = eventData;
+  }
+
+  @Override
+  public String getEventName() {
+    return EVENT_NAME;
+  }
+
+  @Override
+  public boolean canCoalesce() {
+    return false;
+  }
+
+  @Override
+  public short getCoalescingKey() {
+    // All events for a given view can be coalesced.
+    return 0;
+  }
+
+  @Override
+  public void dispatch(RCTEventEmitter rctEventEmitter) {
+    rctEventEmitter.receiveEvent(getViewTag(), getEventName(), mEventData);
+  }
+}

From 022eac9bd8c437d38d0877d76448813656416f8b Mon Sep 17 00:00:00 2001
From: Jing Chen <jingc@fb.com>
Date: Thu, 17 Dec 2015 12:53:34 -0800
Subject: [PATCH 0434/1411] Revert D2739392 to fix events dash loading on
 android

Reviewed By: andreicoman11

Differential Revision: D2770201

fb-gh-sync-id: 6391936f41ba18606637c801645c3177ed1da9ea
---
 .../com/facebook/react/ReactInstanceManager.java  | 15 +--------------
 .../facebook/react/ReactInstanceManagerImpl.java  | 11 ++---------
 2 files changed, 3 insertions(+), 23 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
index 17fb538b826d..f3544cb81899 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
@@ -19,7 +19,6 @@
 import android.content.Intent;
 
 import com.facebook.infer.annotation.Assertions;
-import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
 import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener;
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.ReactContext;
@@ -160,7 +159,6 @@ public static class Builder {
     protected boolean mUseDeveloperSupport;
     protected @Nullable LifecycleState mInitialLifecycleState;
     protected @Nullable UIImplementationProvider mUIImplementationProvider;
-    protected @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
 
     protected Builder() {
     }
@@ -244,16 +242,6 @@ public Builder setInitialLifecycleState(LifecycleState initialLifecycleState) {
       return this;
     }
 
-    /**
-     * Set the exception handler for all native module calls. If not set, the default
-     * {@link DevSupportManager} will be used, which shows a redbox in dev mode and rethrows
-     * (crashes the app) in prod mode.
-     */
-    public Builder setNativeModuleCallExceptionHandler(NativeModuleCallExceptionHandler handler) {
-      mNativeModuleCallExceptionHandler = handler;
-      return this;
-    }
-
     /**
      * Instantiates a new {@link ReactInstanceManagerImpl}.
      * Before calling {@code build}, the following must be called:
@@ -286,8 +274,7 @@ public ReactInstanceManager build() {
           mUseDeveloperSupport,
           mBridgeIdleDebugListener,
           Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"),
-          mUIImplementationProvider,
-          mNativeModuleCallExceptionHandler);
+          mUIImplementationProvider);
     }
   }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index 7fd3668093b4..6061074cd7b6 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -35,7 +35,6 @@
 import com.facebook.react.bridge.JavaScriptModule;
 import com.facebook.react.bridge.JavaScriptModulesConfig;
 import com.facebook.react.bridge.NativeModule;
-import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
 import com.facebook.react.bridge.NativeModuleRegistry;
 import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener;
 import com.facebook.react.bridge.ProxyJavaScriptExecutor;
@@ -101,7 +100,6 @@
   private volatile boolean mHasStartedCreatingInitialContext = false;
   private final UIImplementationProvider mUIImplementationProvider;
   private final MemoryPressureRouter mMemoryPressureRouter;
-  private final @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
 
   private final ReactInstanceDevCommandsHandler mDevInterface =
       new ReactInstanceDevCommandsHandler() {
@@ -197,8 +195,7 @@ protected void onPostExecute(ReactApplicationContext reactContext) {
       boolean useDeveloperSupport,
       @Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener,
       LifecycleState initialLifecycleState,
-      UIImplementationProvider uiImplementationProvider,
-      NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
+      UIImplementationProvider uiImplementationProvider) {
     initializeSoLoaderIfNecessary(applicationContext);
 
     mApplicationContext = applicationContext;
@@ -219,7 +216,6 @@ protected void onPostExecute(ReactApplicationContext reactContext) {
     mLifecycleState = initialLifecycleState;
     mUIImplementationProvider = uiImplementationProvider;
     mMemoryPressureRouter = new MemoryPressureRouter(applicationContext);
-    mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
   }
 
   @Override
@@ -657,16 +653,13 @@ private ReactApplicationContext createReactContext(
       Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
     }
 
-    NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null
-        ? mNativeModuleCallExceptionHandler
-        : mDevSupportManager;
     CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
         .setCatalystQueueConfigurationSpec(CatalystQueueConfigurationSpec.createDefault())
         .setJSExecutor(jsExecutor)
         .setRegistry(nativeModuleRegistry)
         .setJSModulesConfig(javaScriptModulesConfig)
         .setJSBundleLoader(jsBundleLoader)
-        .setNativeModuleCallExceptionHandler(exceptionHandler);
+        .setNativeModuleCallExceptionHandler(mDevSupportManager);
 
     Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstance");
     CatalystInstance catalystInstance;

From ad74dabb68e62bd3ccbb63ab5bc024f78b3a4b5d Mon Sep 17 00:00:00 2001
From: Denis Koroskin <dkoroskin@fb.com>
Date: Thu, 17 Dec 2015 13:30:35 -0800
Subject: [PATCH 0435/1411] Turn FlatViewManager into ViewGroupManager

Reviewed By: ahmedre

Differential Revision: D2768667

fb-gh-sync-id: 39298e4033aab5ca8230516f98da252790811f14
---
 .../java/com/facebook/react/uimanager/ViewGroupManager.java     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewGroupManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewGroupManager.java
index 4091eb8d8cbb..153f7b815f82 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewGroupManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewGroupManager.java
@@ -24,7 +24,7 @@ public LayoutShadowNode createShadowNodeInstance() {
   }
 
   @Override
-  public Class<LayoutShadowNode> getShadowNodeClass() {
+  public Class<? extends LayoutShadowNode> getShadowNodeClass() {
     return LayoutShadowNode.class;
   }
 

From c9410d06737a5f634aea6980989ef27b3ce48c3b Mon Sep 17 00:00:00 2001
From: Louis Pilfold <louis@lpil.uk>
Date: Thu, 17 Dec 2015 14:09:40 -0800
Subject: [PATCH 0436/1411] Add support for nodenv with xcode

Summary:
Hello!

I'm a fan of the *env family of version managers over the *vm family as I find them simpler and less obtrusive, but it seems that they don't currently work so well with react-native on OSX. See #4645

I've made a small addition to the xcode script that resolves the issue for me. Hopefully others will find this useful too :)

If I've not made the right move here, what is the correct way to get react-native projects building in xcode when the binary is not in the $PATH used by the script?

Cheers,
Louis
Closes https://github.com/facebook/react-native/pull/4801

Reviewed By: svcscm

Differential Revision: D2770726

Pulled By: androidtrunkagent

fb-gh-sync-id: 3b0f9e466549b3012a68c94738d2556173f4c21e
---
 packager/react-native-xcode.sh | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/packager/react-native-xcode.sh b/packager/react-native-xcode.sh
index b0206be779f3..b655222f222b 100755
--- a/packager/react-native-xcode.sh
+++ b/packager/react-native-xcode.sh
@@ -41,6 +41,11 @@ elif [[ -x "$(command -v brew)" && -s "$(brew --prefix nvm)/nvm.sh" ]]; then
   . "$(brew --prefix nvm)/nvm.sh"
 fi
 
+# Set up the nodenv node version manager if present
+if [[ -x "$HOME/.nodenv/bin/nodenv" ]]; then
+  eval "$($HOME/.nodenv/bin/nodenv init -)"
+fi
+
 react-native bundle \
   --entry-file index.ios.js \
   --platform ios \

From 18d21779892d456e20b04670be9d4fe9efd4c124 Mon Sep 17 00:00:00 2001
From: Denis Koroskin <dkoroskin@fb.com>
Date: Thu, 17 Dec 2015 15:02:54 -0800
Subject: [PATCH 0437/1411] Implement @ReactProp nativeBackgroundAndroid in
 RCTView

Reviewed By: ahmedre

Differential Revision: D2768671

fb-gh-sync-id: cb3ae29f1cecfaec103708cbc82cf4b57dc80d1a
---
 .../java/com/facebook/react/views/view/ReactDrawableHelper.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactDrawableHelper.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactDrawableHelper.java
index 8cf2d3e26b65..a4dda0d9d3d8 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactDrawableHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactDrawableHelper.java
@@ -27,7 +27,7 @@
  * Utility class that helps with converting android drawable description used in JS to an actual
  * instance of {@link Drawable}.
  */
-/* package */ class ReactDrawableHelper {
+public class ReactDrawableHelper {
 
   private static final TypedValue sResolveOutValue = new TypedValue();
 

From ba3a5f0eecb5eb22d3a70e35c31dd0fd5a24ca27 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 17 Dec 2015 16:33:15 -0800
Subject: [PATCH 0438/1411] Removed overly-strict typing in MapViewExample

Summary:
public

While it's nice to see such a masterclass in strict typing with Flow, having it an example serves no useful purpose, and makes the example unnecessarily fragile with respect to API changes.

Reviewed By: gabelevi

Differential Revision: D2769981

fb-gh-sync-id: db5550d5674bf32ef8d331861751a4e6aa1f6536
---
 Examples/UIExplorer/MapViewExample.js   | 45 +++----------------------
 Libraries/Components/MapView/MapView.js |  4 +--
 2 files changed, 6 insertions(+), 43 deletions(-)

diff --git a/Examples/UIExplorer/MapViewExample.js b/Examples/UIExplorer/MapViewExample.js
index 407e40f00511..2a7bd8b92547 100644
--- a/Examples/UIExplorer/MapViewExample.js
+++ b/Examples/UIExplorer/MapViewExample.js
@@ -33,17 +33,6 @@ var regionText = {
   longitudeDelta: '0',
 };
 
-type MapRegion = {
-  latitude: number,
-  longitude: number,
-  latitudeDelta: number,
-  longitudeDelta: number,
-};
-
-type MapRegionInputState = {
-  region: MapRegion,
-};
-
 var MapRegionInput = React.createClass({
 
   propTypes: {
@@ -56,7 +45,7 @@ var MapRegionInput = React.createClass({
     onChange: React.PropTypes.func.isRequired,
   },
 
-  getInitialState(): MapRegionInputState {
+  getInitialState() {
     return {
       region: {
         latitude: 0,
@@ -160,30 +149,9 @@ var MapRegionInput = React.createClass({
 
 });
 
-type Annotations = Array<{
-  animateDrop?: boolean,
-  latitude: number,
-  longitude: number,
-  title?: string,
-  subtitle?: string,
-  hasLeftCallout?: boolean,
-  hasRightCallout?: boolean,
-  onLeftCalloutPress?: Function,
-  onRightCalloutPress?: Function,
-  tintColor?: string,
-  image?: any,
-  id?: string,
-}>;
-type MapViewExampleState = {
-  isFirstLoad: boolean,
-  mapRegion?: MapRegion,
-  mapRegionInput?: MapRegion,
-  annotations?: Annotations,
-};
-
 var MapViewExample = React.createClass({
 
-  getInitialState(): MapViewExampleState {
+  getInitialState() {
     return {
       isFirstLoad: true,
     };
@@ -207,7 +175,7 @@ var MapViewExample = React.createClass({
     );
   },
 
-  _getAnnotations(region): Annotations {
+  _getAnnotations(region) {
     return [{
       longitude: region.longitude,
       latitude: region.latitude,
@@ -241,14 +209,9 @@ var MapViewExample = React.createClass({
 
 });
 
-type AnnotationExampleState = {
-  isFirstLoad: boolean,
-  annotations?: Annotations,
-  mapRegion?: MapRegion,
-};
 var AnnotationExample = React.createClass({
 
-  getInitialState(): AnnotationExampleState {
+  getInitialState() {
     return {
       isFirstLoad: true,
     };
diff --git a/Libraries/Components/MapView/MapView.js b/Libraries/Components/MapView/MapView.js
index 8fcddb77c39b..13d5642806b2 100644
--- a/Libraries/Components/MapView/MapView.js
+++ b/Libraries/Components/MapView/MapView.js
@@ -29,8 +29,8 @@ type Event = Object;
 type MapRegion = {
   latitude: number;
   longitude: number;
-  latitudeDelta?: ?number;
-  longitudeDelta?: ?number;
+  latitudeDelta?: number;
+  longitudeDelta?: number;
 };
 
 const MapView = React.createClass({

From 5b4e873c68be9a788ac8cc3f67199fbaacb58921 Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Thu, 17 Dec 2015 17:26:12 -0800
Subject: [PATCH 0439/1411] Guard against invalid JS bundle

Reviewed By: tadeuzagallo

Differential Revision: D2767961

fb-gh-sync-id: 4e9162ddbb2986a56dd129743e316d6e83bb8cb3
---
 .../UIExplorerUnitTests/RCTAllocationTests.m  | 51 ++++++++++++++-----
 React/Executors/RCTJSCExecutor.m              | 23 ++++++---
 2 files changed, 55 insertions(+), 19 deletions(-)

diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m
index a3bcde2548a4..81ccffa35b40 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m
@@ -69,13 +69,40 @@ - (void)invalidate
 @interface RCTAllocationTests : XCTestCase
 @end
 
-@implementation RCTAllocationTests
+@implementation RCTAllocationTests {
+  NSURL *_bundleURL;
+}
+
+- (void)setUp
+{
+  [super setUp];
+
+  NSString *bundleContents =
+  @"var __fbBatchedBridge = {"
+   "  callFunctionReturnFlushedQueue: function() {},"
+   "  invokeCallbackAndReturnFlushedQueue: function() {},"
+   "  flushedQueue: function() {},"
+   "};";
+
+  NSURL *tempDir = [NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES];
+  [[NSFileManager defaultManager] createDirectoryAtURL:tempDir withIntermediateDirectories:YES attributes:nil error:NULL];
+
+  _bundleURL = [tempDir URLByAppendingPathComponent:@"rctallocationtests-bundle.js"];
+  [bundleContents writeToURL:_bundleURL atomically:YES encoding:NSUTF8StringEncoding error:NULL];
+}
+
+- (void)tearDown
+{
+  [super tearDown];
+
+  [[NSFileManager defaultManager] removeItemAtURL:_bundleURL error:NULL];
+}
 
 - (void)testBridgeIsDeallocated
 {
   __weak RCTBridge *weakBridge;
   @autoreleasepool {
-    RCTRootView *view = [[RCTRootView alloc] initWithBundleURL:nil
+    RCTRootView *view = [[RCTRootView alloc] initWithBundleURL:_bundleURL
                                                     moduleName:@""
                                              initialProperties:nil
                                                  launchOptions:nil];
@@ -91,7 +118,7 @@ - (void)testModulesAreInvalidated
 {
   AllocationTestModule *module = [AllocationTestModule new];
   @autoreleasepool {
-    RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil
+    RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL
                                               moduleProvider:^{
                                                 return @[module];
                                               }
@@ -109,11 +136,11 @@ - (void)testModulesAreDeallocated
   __weak AllocationTestModule *weakModule;
   @autoreleasepool {
     AllocationTestModule *module = [AllocationTestModule new];
-    RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil
-                                moduleProvider:^{
-                                  return @[module];
-                                }
-                                 launchOptions:nil];
+    RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL
+                                              moduleProvider:^{
+                                                return @[module];
+                                              }
+                                               launchOptions:nil];
     weakModule = module;
     XCTAssertNotNil(weakModule, @"AllocationTestModule should have been created");
     (void)bridge;
@@ -140,7 +167,7 @@ - (void)testJavaScriptExecutorIsDeallocated
 {
   __weak id<RCTJavaScriptExecutor> weakExecutor;
   @autoreleasepool {
-    RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil
+    RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL
                                               moduleProvider:nil
                                                launchOptions:nil];
     weakExecutor = [bridge.batchedBridge valueForKey:@"javaScriptExecutor"];
@@ -156,7 +183,7 @@ - (void)testJavaScriptContextIsDeallocated
 {
   __weak id weakContext;
   @autoreleasepool {
-    RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil
+    RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL
                                               moduleProvider:nil
                                                launchOptions:nil];
     id executor = [bridge.batchedBridge valueForKey:@"javaScriptExecutor"];
@@ -171,7 +198,7 @@ - (void)testJavaScriptContextIsDeallocated
 
 - (void)testContentViewIsInvalidated
 {
-  RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil
+  RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL
                                             moduleProvider:nil
                                              launchOptions:nil];
   __weak UIView *rootContentView;
@@ -190,7 +217,7 @@ - (void)testUnderlyingBridgeIsDeallocated
   RCTBridge *bridge;
   __weak id batchedBridge;
   @autoreleasepool {
-    bridge = [[RCTBridge alloc] initWithBundleURL:nil moduleProvider:nil launchOptions:nil];
+    bridge = [[RCTBridge alloc] initWithBundleURL:_bundleURL moduleProvider:nil launchOptions:nil];
     batchedBridge = bridge.batchedBridge;
     XCTAssertTrue([batchedBridge isValid], @"RCTBatchedBridge should be valid");
     [bridge reload];
diff --git a/React/Executors/RCTJSCExecutor.m b/React/Executors/RCTJSCExecutor.m
index 1d52ae5c9522..b2d432be3883 100644
--- a/React/Executors/RCTJSCExecutor.m
+++ b/React/Executors/RCTJSCExecutor.m
@@ -119,8 +119,8 @@ @implementation RCTJSCExecutor
 
 static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
 {
-  NSString *errorMessage = jsError ? RCTJSValueToNSString(context, jsError, NULL) : @"unknown JS error";
-  NSString *details = jsError ? RCTJSValueToJSONString(context, jsError, NULL, 2) : @"no details";
+  NSString *errorMessage = jsError ? RCTJSValueToNSString(context, jsError, NULL) : @"Unknown JS error";
+  NSString *details = jsError ? RCTJSValueToJSONString(context, jsError, NULL, 2) : @"No details";
   return [NSError errorWithDomain:@"JS" code:1 userInfo:@{NSLocalizedDescriptionKey: errorMessage, NSLocalizedFailureReasonErrorKey: details}];
 }
 
@@ -394,14 +394,12 @@ - (void)_executeJSCall:(NSString *)method
     JSStringRelease(moduleNameJSStringRef);
 
     if (moduleJSRef != NULL && errorJSRef == NULL && !JSValueIsUndefined(contextJSRef, moduleJSRef)) {
-
       // get method
       JSStringRef methodNameJSStringRef = JSStringCreateWithCFString((__bridge CFStringRef)method);
       JSValueRef methodJSRef = JSObjectGetProperty(contextJSRef, (JSObjectRef)moduleJSRef, methodNameJSStringRef, &errorJSRef);
       JSStringRelease(methodNameJSStringRef);
 
-      if (methodJSRef != NULL && errorJSRef == NULL) {
-
+      if (methodJSRef != NULL && errorJSRef == NULL && !JSValueIsUndefined(contextJSRef, methodJSRef)) {
         // direct method invoke with no arguments
         if (arguments.count == 0) {
           resultJSRef = JSObjectCallAsFunction(contextJSRef, (JSObjectRef)methodJSRef, (JSObjectRef)moduleJSRef, 0, NULL, &errorJSRef);
@@ -433,11 +431,22 @@ - (void)_executeJSCall:(NSString *)method
             JSStringRelease(argsJSStringRef);
           }
         }
+      } else {
+        if (!errorJSRef && JSValueIsUndefined(contextJSRef, methodJSRef)) {
+          error = RCTErrorWithMessage([NSString stringWithFormat:@"Unable to execute JS call: method %@ is undefined", method]);
+        }
+      }
+    } else {
+      if (!errorJSRef && JSValueIsUndefined(contextJSRef, moduleJSRef)) {
+        error = RCTErrorWithMessage(@"Unable to execute JS call: __fbBatchedBridge is undefined");
       }
     }
 
-    if (errorJSRef) {
-      onComplete(nil, RCTNSErrorFromJSError(contextJSRef, errorJSRef));
+    if (errorJSRef || error) {
+      if (!error) {
+        error = RCTNSErrorFromJSError(contextJSRef, errorJSRef);
+      }
+      onComplete(nil, error);
       return;
     }
 

From 56fd138fd35b4af2c1a1d1713621c4414f448fbf Mon Sep 17 00:00:00 2001
From: Denis Koroskin <dkoroskin@fb.com>
Date: Thu, 17 Dec 2015 18:45:45 -0800
Subject: [PATCH 0440/1411] Dispatch OnLayoutEvent when node gets re-laid out

Reviewed By: ahmedre

Differential Revision: D2768625

fb-gh-sync-id: 4a9862e4c7ada218565fcd87cae25414a0bd5181
---
 .../main/java/com/facebook/react/uimanager/OnLayoutEvent.java   | 2 +-
 .../main/java/com/facebook/react/uimanager/ReactShadowNode.java | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/OnLayoutEvent.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/OnLayoutEvent.java
index 393ccdf8da95..155776b71573 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/OnLayoutEvent.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/OnLayoutEvent.java
@@ -20,7 +20,7 @@
 /**
  * Event used to notify JS component about changes of its position or dimensions
  */
-/* package */ class OnLayoutEvent extends Event<OnLayoutEvent> {
+public class OnLayoutEvent extends Event<OnLayoutEvent> {
 
   private static final Pools.SynchronizedPool<OnLayoutEvent> EVENTS_POOL =
       new Pools.SynchronizedPool<>(20);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java
index d0f204e186fb..21a88835d7a1 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java
@@ -264,7 +264,7 @@ public void setShouldNotifyOnLayout(boolean shouldNotifyOnLayout) {
     mShouldNotifyOnLayout = shouldNotifyOnLayout;
   }
 
-  /* package */ boolean shouldNotifyOnLayout() {
+  public boolean shouldNotifyOnLayout() {
     return mShouldNotifyOnLayout;
   }
 

From 9901bf20e1932d6e13df4f552797c91b03b97486 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Fri, 18 Dec 2015 00:49:29 -0800
Subject: [PATCH 0441/1411] Fixed image source for MapView annotations

Summary:
public
resolveAssetSource was not being called on MapView image any more, resulting in an error when using `require(./imagename.png)` syntax.

Reviewed By: fredliu

Differential Revision: D2772560

fb-gh-sync-id: 0a50a9c3ba727406343a0f47c84941e95df9cadd
---
 Libraries/Components/MapView/MapView.js | 27 ++++++++++++++++---------
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/Libraries/Components/MapView/MapView.js b/Libraries/Components/MapView/MapView.js
index 13d5642806b2..d6f0205d005a 100644
--- a/Libraries/Components/MapView/MapView.js
+++ b/Libraries/Components/MapView/MapView.js
@@ -294,8 +294,12 @@ const MapView = React.createClass({
           }}
           source={image}
         />;
+        image = undefined;
       }
       if (view) {
+        if (image) {
+          console.warn('`image` and `view` both set on annotation. Image will be ignored.');
+        }
         var viewIndex = children.length;
         children.push(React.cloneElement(view, {
           style: [styles.annotationView, view.props.style || {}]
@@ -319,19 +323,22 @@ const MapView = React.createClass({
           style: [styles.calloutView, detailCalloutView.props.style || {}]
         }));
       }
-      ['hasLeftCallout', 'onLeftCalloutPress'].forEach(key => {
-        if (annotation[key]) {
-          console.warn('`' + key + '` is deprecated. Use leftCalloutView instead.');
-        }
-      });
-      ['hasRightCallout', 'onRightCalloutPress'].forEach(key => {
-        if (annotation[key]) {
-          console.warn('`' + key + '` is deprecated. Use rightCalloutView instead.');
-        }
-      });
+      if (__DEV__) {
+        ['hasLeftCallout', 'onLeftCalloutPress'].forEach(key => {
+          if (annotation[key]) {
+            console.warn('`' + key + '` is deprecated. Use leftCalloutView instead.');
+          }
+        });
+        ['hasRightCallout', 'onRightCalloutPress'].forEach(key => {
+          if (annotation[key]) {
+            console.warn('`' + key + '` is deprecated. Use rightCalloutView instead.');
+          }
+        });
+      }
       return {
         ...annotation,
         tintColor: tintColor && processColor(tintColor),
+        image: image && resolveAssetSource(image),
         viewIndex,
         leftCalloutViewIndex,
         rightCalloutViewIndex,

From 98b57f8fd2ffb004f84a76608dd959432b5468b7 Mon Sep 17 00:00:00 2001
From: "luke.avery" <luke.avery@dubitlimited.com>
Date: Fri, 18 Dec 2015 09:45:06 +0000
Subject: [PATCH 0442/1411] added WEARVR android version to showcase

---
 website/src/react-native/showcase.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 421c20ed50b2..317b4bb0f2ec 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -408,7 +408,8 @@ var apps = [
   {
     name: 'WEARVR',
     icon: 'http://a2.mzstatic.com/eu/r30/Purple69/v4/4f/5a/28/4f5a2876-9530-ef83-e399-c5ef5b2dab80/icon175x175.png',
-    link: 'https://itunes.apple.com/gb/app/wearvr/id1066288171?mt=8',
+    linkAppStore: 'https://itunes.apple.com/gb/app/wearvr/id1066288171?mt=8',
+    linkPlayStore: 'https://play.google.com/store/apps/details?id=com.wearvr.app',
     author: 'WEARVR LLC',
   },
   {

From f47c79c113c8d71ec7776926837c956ac98d1e06 Mon Sep 17 00:00:00 2001
From: Justin Spahr-Summers <jspahrsummers@fb.com>
Date: Fri, 18 Dec 2015 02:03:17 -0800
Subject: [PATCH 0443/1411] Disable
 RCTAllocationTests:testUnderlyingBridgeIsDeallocated by hand

fb-gh-sync-id: e584ac013468763b2844112f27af9ef82065bd66
---
 Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m
index 81ccffa35b40..c642953768d5 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m
@@ -212,6 +212,8 @@ - (void)testContentViewIsInvalidated
   XCTAssertFalse(rootContentView.userInteractionEnabled, @"RCTContentView should have been invalidated");
 }
 
+// This test is flaky, and needs to be fixed before re-enabling. See t9456702.
+#if 0
 - (void)testUnderlyingBridgeIsDeallocated
 {
   RCTBridge *bridge;
@@ -228,5 +230,6 @@ - (void)testUnderlyingBridgeIsDeallocated
   XCTAssertNotNil(bridge, @"RCTBridge should not have been deallocated");
   XCTAssertNil(batchedBridge, @"RCTBatchedBridge should have been deallocated");
 }
+#endif
 
 @end

From a3d16c0178d3794991f1cb2f656b66078efa2a26 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Fri, 18 Dec 2015 11:33:32 +0000
Subject: [PATCH 0444/1411] Fix gitignore

build/ is too generic, ignores valid paths.

Test plan:
- Built Android UI explorer, ReactAndroid, iOS UIExplorer, iOS React
- Git still ignores build output files correctly
---
 .gitignore                                    |  6 +++--
 .../react/common/build/ReactBuildConfig.java  | 24 +++++++++++++++++++
 2 files changed, 28 insertions(+), 2 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/common/build/ReactBuildConfig.java

diff --git a/.gitignore b/.gitignore
index c4b7a9b476d9..d6b303279320 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,8 +21,10 @@ DerivedData
 *.xcuserstate
 project.xcworkspace
 
-# Xcode, Gradle
-build/
+# Gradle
+/build/
+/Examples/**/android/app/build/
+/ReactAndroid/build
 
 # Android
 .idea
diff --git a/ReactAndroid/src/main/java/com/facebook/react/common/build/ReactBuildConfig.java b/ReactAndroid/src/main/java/com/facebook/react/common/build/ReactBuildConfig.java
new file mode 100644
index 000000000000..6fcec141fc51
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/common/build/ReactBuildConfig.java
@@ -0,0 +1,24 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.common.build;
+
+import com.facebook.react.BuildConfig;
+
+/**
+ * Convenience class for accessing auto-generated BuildConfig so that a) other modules can just
+ * depend on this module instead of having to manually depend on generating their own build config
+ * and b) we don't have to deal with IntelliJ getting confused about the autogenerated BuildConfig
+ * class all over the place.
+ */
+public class ReactBuildConfig {
+
+  public static final boolean DEBUG = BuildConfig.DEBUG;
+  public static final boolean IS_INTERNAL_BUILD = BuildConfig.IS_INTERNAL_BUILD;
+}

From 85e8a463f238c1b5daa7ee973a614f51329fb5d5 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Fri, 18 Dec 2015 11:37:46 +0000
Subject: [PATCH 0445/1411] Fix typo

---
 .gitignore | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.gitignore b/.gitignore
index d6b303279320..74ab1dc77337 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,7 +24,7 @@ project.xcworkspace
 # Gradle
 /build/
 /Examples/**/android/app/build/
-/ReactAndroid/build
+/ReactAndroid/build/
 
 # Android
 .idea

From b436943a279f116fc8f376a377afc04aa7c5a774 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Fri, 18 Dec 2015 03:40:51 -0800
Subject: [PATCH 0446/1411] Pass the correct URL to Android WebView events

Summary:
`WebView.getUrl()` doesn't return the correct value in WebView callbacks
(e.g. `onPageFinished`).
For example, when navigating to a URL, we report that loading finished,
but still with the old URL. This diff fixes that.

public

Reviewed By: andreicoman11

Differential Revision: D2769597

fb-gh-sync-id: f14bdd405290469ac0a20d0fb89aa2a27d33e758
---
 .../views/webview/ReactWebViewManager.java    | 24 ++++++++++---------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
index 05f50dcfb1e3..f16520e60765 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
@@ -91,7 +91,7 @@ public void onPageFinished(WebView webView, String url) {
       if (!mLastLoadFailed) {
         ReactWebView reactWebView = (ReactWebView) webView;
         reactWebView.callInjectedJavaScript();
-        emitFinishEvent(webView);
+        emitFinishEvent(webView, url);
       }
     }
 
@@ -107,7 +107,7 @@ public void onPageStarted(WebView webView, String url, Bitmap favicon) {
           new TopLoadingStartEvent(
               webView.getId(),
               SystemClock.uptimeMillis(),
-              createWebViewEvent(webView)));
+              createWebViewEvent(webView, url)));
     }
 
     @Override
@@ -120,11 +120,11 @@ public void onReceivedError(
       mLastLoadFailed = true;
 
       // In case of an error JS side expect to get a finish event first, and then get an error event
-      // Android WebView does it in the oposite way, so we need to simulate that behavior
-      emitFinishEvent(webView);
+      // Android WebView does it in the opposite way, so we need to simulate that behavior
+      emitFinishEvent(webView, failingUrl);
 
       ReactContext reactContext = (ReactContext) ((ReactWebView) webView).getContext();
-      WritableMap eventData = createWebViewEvent(webView);
+      WritableMap eventData = createWebViewEvent(webView, failingUrl);
       eventData.putDouble("code", errorCode);
       eventData.putString("description", description);
 
@@ -145,10 +145,10 @@ public void doUpdateVisitedHistory(WebView webView, String url, boolean isReload
           new TopLoadingStartEvent(
               webView.getId(),
               SystemClock.uptimeMillis(),
-              createWebViewEvent(webView)));
+              createWebViewEvent(webView, url)));
     }
 
-    private void emitFinishEvent(WebView webView) {
+    private void emitFinishEvent(WebView webView, String url) {
       ReactContext reactContext = (ReactContext) webView.getContext();
 
       EventDispatcher eventDispatcher =
@@ -157,13 +157,15 @@ private void emitFinishEvent(WebView webView) {
           new TopLoadingFinishEvent(
               webView.getId(),
               SystemClock.uptimeMillis(),
-              createWebViewEvent(webView)));
+              createWebViewEvent(webView, url)));
     }
 
-    private WritableMap createWebViewEvent(WebView webView) {
+    private WritableMap createWebViewEvent(WebView webView, String url) {
       WritableMap event = Arguments.createMap();
       event.putDouble("target", webView.getId());
-      event.putString("url", webView.getUrl());
+      // Don't use webView.getUrl() here, the URL isn't updated to the new value yet in callbacks
+      // like onPageFinished
+      event.putString("url", url);
       event.putBoolean("loading", !mLastLoadFailed && webView.getProgress() != 100);
       event.putString("title", webView.getTitle());
       event.putBoolean("canGoBack", webView.canGoBack());
@@ -279,7 +281,7 @@ public void setHtml(WebView view, @Nullable String html) {
   public void setUrl(WebView view, @Nullable String url) {
     // TODO(8495359): url and html are coupled as they both call loadUrl, therefore in case when
     // property url is removed in favor of property html being added in single transaction we may
-    // end up in a state when blank url is loaded as it depends onthe oreder of update operations!
+    // end up in a state when blank url is loaded as it depends on the order of update operations!
     if (url != null) {
       view.loadUrl(url);
     } else {

From 920f71da578ef9ace7e51f3665bb2cce11dc2bcb Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Fri, 18 Dec 2015 06:10:09 -0800
Subject: [PATCH 0447/1411] Alert docs

Reviewed By: bestander

Differential Revision: D2773540

fb-gh-sync-id: 8baf08aa6a50955c5c9c806e8b93230086b504af
---
 Libraries/Utilities/Alert.js    | 13 ++++++++-----
 Libraries/Utilities/AlertIOS.js | 17 ++++++++++++-----
 2 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/Libraries/Utilities/Alert.js b/Libraries/Utilities/Alert.js
index de434c987df0..3768be64d9da 100644
--- a/Libraries/Utilities/Alert.js
+++ b/Libraries/Utilities/Alert.js
@@ -30,30 +30,33 @@ type Buttons = Array<{
  * respective onPress callback and dismiss the alert. By default, the only
  * button will be an 'OK' button.
  *
- * The last button in the list will be considered the 'Primary' button.
+ * This is an API that works both on iOS and Android and can show static
+ * alerts. To show an alert that prompts the user to enter some information,
+ * see `AlertIOS`; entering text in an alert is common on iOS only.
  *
  * ## iOS
  *
  * On iOS you can specify any number of buttons. Each button can optionally
- * specify a style and you can also specify type of the alert.
- * Refer to `AlertIOS` for details.
+ * specify a style and you can also specify type of the alert. Refer to
+ * `AlertIOS` for details.
  *
  * ## Android
  * 
  * On Android at most three buttons can be specified. Android has a concept
- * of a 'neutral', 'negative' and a 'positive' button:
+ * of a neutral, negative and a positive button:
  *
  *   - If you specify one button, it will be the 'positive' one (such as 'OK')
  *   - Two buttons mean 'negative', 'positive' (such as 'Cancel', 'OK')
  *   - Three buttons mean 'neutral', 'negative', 'positive' (such as 'Later', 'Cancel', 'OK')
  *
  * ```
+ * // Works on both iOS and Android
  * Alert.alert(
  *   'Alert Title',
  *   'My Alert Msg',
  *   [
  *     {text: 'Ask me later', onPress: () => console.log('Ask me later pressed')},
- *     {text: 'Cancel', onPress: () => console.log('Cancel Pressed')},
+ *     {text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
  *     {text: 'OK', onPress: () => console.log('OK Pressed')},
  *   ]
  * )
diff --git a/Libraries/Utilities/AlertIOS.js b/Libraries/Utilities/AlertIOS.js
index 38fd0f88c475..2413f38d2ca4 100644
--- a/Libraries/Utilities/AlertIOS.js
+++ b/Libraries/Utilities/AlertIOS.js
@@ -34,14 +34,18 @@ export type AlertButtonStyle = $Enum<{
  * respective onPress callback and dismiss the alert. By default, the only
  * button will be an 'OK' button.
  *
+ * Use this API for iOS-specific features, such as prompting the user to enter
+ * some information. In other cases, especially to show static alerts, use
+ * the cross-platform `Alert` API.
+ *
  * ```
  * AlertIOS.alert(
- *   'Foo Title',
- *   'My Alert Msg',
+ *   'Enter password',
+ *   null,
  *   [
- *     {text: 'OK', onPress: () => console.log('OK Pressed')},
- *     {text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
- *   ]
+ *     {text: 'Submit', onPress: (text) => console.log('Password: ' + text)},
+ *   ],
+ *   'secure-text'
  * )
  * ```
  */
@@ -86,6 +90,9 @@ class AlertIOS {
     });
   }
 
+  /**
+   * Prompt the user to enter some text.
+   */
   static prompt(
     title: string,
     value?: string,

From dfdafdb733ac55f69bd59216ce5e81ec8c282562 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Fri, 18 Dec 2015 06:36:14 -0800
Subject: [PATCH 0448/1411] Add magic indicator file to FS unbundles

Reviewed By: tadeuzagallo

Differential Revision: D2773427

fb-gh-sync-id: 8724f5c6e300f456e5a9c434c14e8e74b2792cf9
---
 local-cli/bundle/output/unbundle/as-assets.js | 35 ++++++++++---------
 .../bundle/output/unbundle/as-indexed-file.js |  2 +-
 .../bundle/output/unbundle/magic-number.js    | 11 ++++++
 3 files changed, 31 insertions(+), 17 deletions(-)
 create mode 100644 local-cli/bundle/output/unbundle/magic-number.js

diff --git a/local-cli/bundle/output/unbundle/as-assets.js b/local-cli/bundle/output/unbundle/as-assets.js
index f4f429c2969a..873b1334885c 100644
--- a/local-cli/bundle/output/unbundle/as-assets.js
+++ b/local-cli/bundle/output/unbundle/as-assets.js
@@ -8,13 +8,14 @@
  */
 'use strict';
 
-const fs = require('fs');
 const mkdirp = require('mkdirp');
 const path = require('path');
 const Promise = require('promise');
 
 const writeFile = require('../writeFile');
 const writeSourceMap = require('./write-sourcemap');
+const MAGIC_UNBUNDLE_NUMBER = require('./magic-number');
+const MAGIC_UNBUNDLE_FILENAME = '.unbundle';
 const MODULES_DIR = 'js-modules';
 
 /**
@@ -37,11 +38,15 @@ function saveAsAssets(bundle, options, log) {
   log('finish');
 
   log('Writing bundle output to:', bundleOutput);
+  const modulesDir = path.join(path.dirname(bundleOutput), MODULES_DIR);
   const writeUnbundle =
-    Promise.all([
-      writeModules(path.dirname(bundleOutput), modules, encoding),
-      writeStartupFile(bundleOutput, startupCode, encoding)
-    ]);
+    createDir(modulesDir).then( // create the modules directory first
+      Promise.all([
+        writeModules(modulesDir, modules, encoding),
+        writeFile(bundleOutput, startupCode, encoding),
+        writeMagicFlagFile(modulesDir),
+      ])
+    );
   writeUnbundle.then(() => log('Done writing unbundle output'));
 
   return Promise.all([writeUnbundle, writeSourceMap(sourcemapOutput, '', log)]);
@@ -57,13 +62,13 @@ function createDirectoriesForModules(modulesDir, modules) {
     modules.map(name => {
       // get all needed directory names
       const dir = path.dirname(name);
-      return dir === '.' ? modulesDir : path.join(modulesDir, dir);
+      return dir === '.' || dir === '' ? null : path.join(modulesDir, dir);
     })
     .filter(Boolean) // remove empty directories
     .sort()
     .filter((dir, i, dirs) => {
-      // remove parent directories. After sorting, parent directories are
-      // located before child directories
+      // remove parent directories and dedupe.
+      // After sorting, parent directories are located before child directories
       const next = dirs[i + 1];
       return !next || next !== dir && !next.startsWith(dir + path.sep);
     });
@@ -84,20 +89,18 @@ function writeModuleFiles(modules, modulesDir, encoding) {
   return Promise.all(writeFiles);
 }
 
-function writeModules(assetsDest, modules, encoding) {
-  const modulesDir = path.join(assetsDest, MODULES_DIR);
-
+function writeModules(modulesDir, modules, encoding) {
   return (
     createDirectoriesForModules(modulesDir, modules.map(({name}) => name))
       .then(() => writeModuleFiles(modules, modulesDir, encoding))
   );
 }
 
-function writeStartupFile(outputFile, code, encoding) {
-  return new Promise((resolve, reject) => {
-    fs.createWriteStream(outputFile).
-      write(code, encoding, error => error ? reject(error) : resolve());
-  });
+function writeMagicFlagFile(outputDir) {
+  /* global Buffer: true */
+  const buffer = Buffer(4);
+  buffer.writeUInt32LE(MAGIC_UNBUNDLE_NUMBER);
+  return writeFile(path.join(outputDir, MAGIC_UNBUNDLE_FILENAME), buffer);
 }
 
 module.exports = saveAsAssets;
diff --git a/local-cli/bundle/output/unbundle/as-indexed-file.js b/local-cli/bundle/output/unbundle/as-indexed-file.js
index 65243375a06f..7b27970816a4 100644
--- a/local-cli/bundle/output/unbundle/as-indexed-file.js
+++ b/local-cli/bundle/output/unbundle/as-indexed-file.js
@@ -12,7 +12,7 @@ const fs = require('fs');
 const Promise = require('promise');
 const writeSourceMap = require('./write-sourcemap');
 
-const MAGIC_UNBUNDLE_FILE_HEADER = 0xFB0BD1E5;
+const MAGIC_UNBUNDLE_FILE_HEADER = require('./magic-number');
 const MAGIC_STARTUP_MODULE_ID = '';
 
 /**
diff --git a/local-cli/bundle/output/unbundle/magic-number.js b/local-cli/bundle/output/unbundle/magic-number.js
new file mode 100644
index 000000000000..6e6a9d3759d6
--- /dev/null
+++ b/local-cli/bundle/output/unbundle/magic-number.js
@@ -0,0 +1,11 @@
+/**
+ * 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.
+ */
+'use strict';
+
+module.exports = 0xFB0BD1E5;

From 7567a92ca75081ee8a2025661127d048b7916627 Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Fri, 18 Dec 2015 23:50:43 +0800
Subject: [PATCH 0449/1411] fix a typo of a prop name

---
 docs/CommunicationIOS.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/CommunicationIOS.md b/docs/CommunicationIOS.md
index 7b23c80eeb15..3e430636f05b 100644
--- a/docs/CommunicationIOS.md
+++ b/docs/CommunicationIOS.md
@@ -54,7 +54,7 @@ class ImageBrowserApp extends React.Component {
   render() {
     return (
       <View>
-        {this.props.imageList.map(this.renderImage)}
+        {this.props.images.map(this.renderImage)}
       </View>
     );
   }

From 4769bdc01327b0ea9ad1828a7881d3adf85c6e5b Mon Sep 17 00:00:00 2001
From: Jan Kassens <jkassens@fb.com>
Date: Fri, 18 Dec 2015 10:51:50 -0800
Subject: [PATCH 0450/1411] disable debugging of web views

Reviewed By: andreicoman11

Differential Revision: D2773171

fb-gh-sync-id: 41b1313c2ec3d3a22cf56ee15e452b978adf5a78
---
 .../com/facebook/react/views/webview/ReactWebViewManager.java  | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
index f16520e60765..588eb928ff3e 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
@@ -76,7 +76,8 @@ public class ReactWebViewManager extends SimpleViewManager<WebView> {
 
   static {
     if (ReactBuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
-      WebView.setWebContentsDebuggingEnabled(true);
+      // TODO(T9455950): re-enable debugging
+      // WebView.setWebContentsDebuggingEnabled(true);
     }
   }
 

From 57a76c0c014eacb9c138ab8faf9aaabd964e416d Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Fri, 18 Dec 2015 11:00:25 -0800
Subject: [PATCH 0451/1411] Fix the sourceMap url on minified bundles

Summary:
public

The minified bundle was always being generated with the `bundle.js` as the source map url.

Reviewed By: martinbigio

Differential Revision: D2773725

fb-gh-sync-id: 02cda95eb172fc373ce4e605418cbfcec22f433d
---
 packager/react-packager/src/Bundler/Bundle.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packager/react-packager/src/Bundler/Bundle.js b/packager/react-packager/src/Bundler/Bundle.js
index f94c8ff581f5..b945dd42864b 100644
--- a/packager/react-packager/src/Bundler/Bundle.js
+++ b/packager/react-packager/src/Bundler/Bundle.js
@@ -188,7 +188,7 @@ class Bundle {
       const minifyActivity = Activity.startEvent('minify');
       this._minifiedSourceAndMap = UglifyJS.minify(source, {
         fromString: true,
-        outSourceMap: 'bundle.js',
+        outSourceMap: this._sourceMapUrl,
         inSourceMap: this.getSourceMap(),
         output: {ascii_only: true},
       });

From dc6ca95c3aae11b675c50b296b4560418042e9f5 Mon Sep 17 00:00:00 2001
From: "glevi@fb.com" <glevi@fb.com>
Date: Fri, 18 Dec 2015 11:16:40 -0800
Subject: [PATCH 0452/1411] Fixed Flow errors

Reviewed By: nicklockwood

Differential Revision: D2773940

fb-gh-sync-id: 3d632c57c411ddaf428c1d96d145da62dd115a14
---
 Examples/UIExplorer/MapViewExample.js   | 61 +++++++++++++++++++++----
 Libraries/Components/MapView/MapView.js | 14 ++----
 2 files changed, 57 insertions(+), 18 deletions(-)

diff --git a/Examples/UIExplorer/MapViewExample.js b/Examples/UIExplorer/MapViewExample.js
index 2a7bd8b92547..3df5d4ded06a 100644
--- a/Examples/UIExplorer/MapViewExample.js
+++ b/Examples/UIExplorer/MapViewExample.js
@@ -33,19 +33,30 @@ var regionText = {
   longitudeDelta: '0',
 };
 
+type MapRegion = {
+  latitude: number,
+  longitude: number,
+  latitudeDelta?: number,
+  longitudeDelta?: number,
+};
+
+type MapRegionInputState = {
+  region: MapRegion,
+};
+
 var MapRegionInput = React.createClass({
 
   propTypes: {
     region: React.PropTypes.shape({
       latitude: React.PropTypes.number.isRequired,
       longitude: React.PropTypes.number.isRequired,
-      latitudeDelta: React.PropTypes.number.isRequired,
-      longitudeDelta: React.PropTypes.number.isRequired,
+      latitudeDelta: React.PropTypes.number,
+      longitudeDelta: React.PropTypes.number,
     }),
     onChange: React.PropTypes.func.isRequired,
   },
 
-  getInitialState() {
+  getInitialState(): MapRegionInputState {
     return {
       region: {
         latitude: 0,
@@ -93,7 +104,9 @@ var MapRegionInput = React.createClass({
             {'Latitude delta'}
           </Text>
           <TextInput
-            value={'' + region.latitudeDelta}
+            value={
+              region.latitudeDelta == null ? '' : String(region.latitudeDelta)
+            }
             style={styles.textInput}
             onChange={this._onChangeLatitudeDelta}
             selectTextOnFocus={true}
@@ -104,7 +117,9 @@ var MapRegionInput = React.createClass({
             {'Longitude delta'}
           </Text>
           <TextInput
-            value={'' + region.longitudeDelta}
+            value={
+              region.longitudeDelta == null ? '' : String(region.longitudeDelta)
+            }
             style={styles.textInput}
             onChange={this._onChangeLongitudeDelta}
             selectTextOnFocus={true}
@@ -149,9 +164,34 @@ var MapRegionInput = React.createClass({
 
 });
 
+type Annotations = Array<{
+  animateDrop?: boolean,
+  latitude: number,
+  longitude: number,
+  title?: string,
+  subtitle?: string,
+  hasLeftCallout?: boolean,
+  hasRightCallout?: boolean,
+  onLeftCalloutPress?: Function,
+  onRightCalloutPress?: Function,
+  tintColor?: number | string,
+  image?: any,
+  id?: string,
+  view?: ReactElement,
+  leftCalloutView?: ReactElement,
+  rightCalloutView?: ReactElement,
+  detailCalloutView?: ReactElement,
+}>;
+type MapViewExampleState = {
+  isFirstLoad: boolean,
+  mapRegion?: MapRegion,
+  mapRegionInput?: MapRegion,
+  annotations?: Annotations,
+};
+
 var MapViewExample = React.createClass({
 
-  getInitialState() {
+  getInitialState(): MapViewExampleState {
     return {
       isFirstLoad: true,
     };
@@ -175,7 +215,7 @@ var MapViewExample = React.createClass({
     );
   },
 
-  _getAnnotations(region) {
+  _getAnnotations(region): Annotations {
     return [{
       longitude: region.longitude,
       latitude: region.latitude,
@@ -209,9 +249,14 @@ var MapViewExample = React.createClass({
 
 });
 
+type AnnotationExampleState = {
+  isFirstLoad: boolean,
+  annotations?: Annotations,
+  mapRegion?: MapRegion,
+};
 var AnnotationExample = React.createClass({
 
-  getInitialState() {
+  getInitialState(): AnnotationExampleState {
     return {
       isFirstLoad: true,
     };
diff --git a/Libraries/Components/MapView/MapView.js b/Libraries/Components/MapView/MapView.js
index d6f0205d005a..c32875369225 100644
--- a/Libraries/Components/MapView/MapView.js
+++ b/Libraries/Components/MapView/MapView.js
@@ -26,12 +26,6 @@ const resolveAssetSource = require('resolveAssetSource');
 const requireNativeComponent = require('requireNativeComponent');
 
 type Event = Object;
-type MapRegion = {
-  latitude: number;
-  longitude: number;
-  latitudeDelta?: number;
-  longitudeDelta?: number;
-};
 
 const MapView = React.createClass({
   mixins: [NativeMethodsMixin],
@@ -155,14 +149,14 @@ const MapView = React.createClass({
        */
       title: React.PropTypes.string,
       subtitle: React.PropTypes.string,
-      
+
       /**
        * Callout views.
        */
       leftCalloutView: React.PropTypes.element,
       rightCalloutView: React.PropTypes.element,
       detailCalloutView: React.PropTypes.element,
-      
+
       /**
        * The pin color. This can be any valid color string, or you can use one
        * of the predefined PinColors constants. Applies to both standard pins
@@ -191,7 +185,7 @@ const MapView = React.createClass({
        * annotation id
        */
       id: React.PropTypes.string,
-            
+
       /**
        * Deprecated. Use the left/right/detailsCalloutView props instead.
        */
@@ -286,7 +280,7 @@ const MapView = React.createClass({
         rightCalloutView,
         detailCalloutView,
       } = annotation;
-      
+
       if (!view && image && tintColor) {
         view = <Image
           style={{

From ae9aaf81fbe68f0856abef55955d6f30f04fad8b Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Fri, 18 Dec 2015 15:51:58 -0800
Subject: [PATCH 0453/1411] Switched over to OSS RCTTextView by default

Reviewed By: javache

Differential Revision: D2697267

fb-gh-sync-id: 275dded8425e2a81598a6055d830bc80b28177ad
---
 React/Base/RCTBatchedBridge.m | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index e235427731c8..ce9bfb763fea 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -278,23 +278,23 @@ - (void)initModules
           [moduleClass instancesRespondToSelector:setBridgeSelector]) {
         module = [moduleClass new];
         if (!module) {
-          module = [NSNull null];
+          module = (id)kCFNull;
         }
       }
     }
 
     // Check for module name collisions.
     // It's OK to have a name collision as long as the second instance is null.
-    if (module != [NSNull class] && _moduleDataByName[moduleName]) {
+    if (module != (id)kCFNull && moduleDataByName[moduleName] && !preregisteredModules[moduleName]) {
       RCTLogError(@"Attempted to register RCTBridgeModule class %@ for the name "
                   "'%@', but name was already registered by class %@", moduleClass,
-                  moduleName, _moduleDataByName[moduleName]);
+                  moduleName, moduleDataByName[moduleName].moduleClass);
     }
 
     // Instantiate moduleData (TODO: defer this until config generation)
     RCTModuleData *moduleData;
     if (module) {
-      if (module != [NSNull null]) {
+      if (module != (id)kCFNull) {
         moduleData = [[RCTModuleData alloc] initWithModuleInstance:module];
       }
     } else {

From b201aeb9f7a675215cda6a208334ad072fc7abd6 Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Fri, 18 Dec 2015 16:13:25 -0800
Subject: [PATCH 0454/1411] Move Cache into DependencyGraph

Reviewed By: martinbigio

Differential Revision: D2758776

fb-gh-sync-id: 15fb232e00267698e386d5422cb70e2091dabcdd
---
 packager/react-packager/src/Bundler/index.js  | 23 +++--
 .../__tests__/BundlesLayout-test.js           |  2 +-
 .../BundlesLayoutIntegration-test.js          |  4 +-
 .../react-packager/src/BundlesLayout/index.js |  6 +-
 .../Cache/__mocks__/index.js                  |  0
 .../Cache/__tests__/Cache-test.js             | 87 ++++++++-----------
 .../{ => DependencyResolver}/Cache/index.js   | 84 ++++++------------
 .../Cache}/lib/getCacheFilePath.js            | 11 +--
 .../Cache}/lib/loadCacheSync.js               |  0
 .../__tests__/Transformer-test.js             |  2 +-
 10 files changed, 91 insertions(+), 128 deletions(-)
 rename packager/react-packager/src/{ => DependencyResolver}/Cache/__mocks__/index.js (100%)
 rename packager/react-packager/src/{ => DependencyResolver}/Cache/__tests__/Cache-test.js (80%)
 rename packager/react-packager/src/{ => DependencyResolver}/Cache/index.js (73%)
 rename packager/react-packager/src/{ => DependencyResolver/Cache}/lib/getCacheFilePath.js (65%)
 rename packager/react-packager/src/{ => DependencyResolver/Cache}/lib/loadCacheSync.js (100%)

diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index 470c6821c809..31794a9bc04f 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -14,7 +14,7 @@ const path = require('path');
 const Promise = require('promise');
 const ProgressBar = require('progress');
 const BundlesLayout = require('../BundlesLayout');
-const Cache = require('../Cache');
+const Cache = require('../DependencyResolver/Cache');
 const Transformer = require('../JSTransformer');
 const Resolver = require('../Resolver');
 const Bundle = require('./Bundle');
@@ -23,6 +23,7 @@ const Activity = require('../Activity');
 const ModuleTransport = require('../lib/ModuleTransport');
 const declareOpts = require('../lib/declareOpts');
 const imageSize = require('image-size');
+const version = require('../../../../package.json').version;
 
 const sizeOf = Promise.denodeify(imageSize);
 const readFile = Promise.denodeify(fs.readFile);
@@ -88,11 +89,23 @@ class Bundler {
 
     opts.projectRoots.forEach(verifyRootExists);
 
+    let mtime;
+    try {
+      ({mtime} = fs.statSync(opts.transformModulePath));
+      mtime = String(mtime.getTime());
+    } catch (error) {
+      mtime = '';
+    }
+
     this._cache = new Cache({
       resetCache: opts.resetCache,
-      cacheVersion: opts.cacheVersion,
-      projectRoots: opts.projectRoots,
-      transformModulePath: opts.transformModulePath,
+      cacheKey: [
+        'react-packager-cache',
+        version,
+        opts.cacheVersion,
+        opts.projectRoots.join(',').split(path.sep).join('-'),
+        mtime
+      ].join('$'),
     });
 
     this._resolver = new Resolver({
@@ -365,7 +378,7 @@ class Bundler {
   generateAssetModule(bundle, module, platform = null) {
     const relPath = getPathRelativeToRoot(this._projectRoots, module.path);
     var assetUrlPath = path.join('/assets', path.dirname(relPath));
-    
+
     // On Windows, change backslashes to slashes to get proper URL path from file path.
     if (path.sep === '\\') {
       assetUrlPath = assetUrlPath.replace(/\\/g, '/');
diff --git a/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayout-test.js b/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayout-test.js
index bc4fac8afd7e..dafdb3680ae1 100644
--- a/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayout-test.js
+++ b/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayout-test.js
@@ -14,7 +14,7 @@ jest.dontMock('../index')
 var Promise = require('promise');
 var BundlesLayout = require('../index');
 var Resolver = require('../../Resolver');
-var loadCacheSync = require('../../lib/loadCacheSync');
+var loadCacheSync = require('../../DependencyResolver/Cache/lib/loadCacheSync');
 
 describe('BundlesLayout', () => {
   function newBundlesLayout(options) {
diff --git a/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js b/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js
index 1cade30c4b45..37701392aba7 100644
--- a/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js
+++ b/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js
@@ -10,7 +10,7 @@
 
 jest
   .autoMockOff()
-  .mock('../../Cache')
+  .mock('../../DependencyResolver/Cache')
   .mock('../../Activity');
 
 const Promise = require('promise');
@@ -19,7 +19,7 @@ const path = require('path');
 jest.mock('fs');
 
 var BundlesLayout = require('../index');
-var Cache = require('../../Cache');
+var Cache = require('../../DependencyResolver/Cache');
 var Resolver = require('../../Resolver');
 var fs = require('fs');
 
diff --git a/packager/react-packager/src/BundlesLayout/index.js b/packager/react-packager/src/BundlesLayout/index.js
index d946cefe1cea..2fd906232af5 100644
--- a/packager/react-packager/src/BundlesLayout/index.js
+++ b/packager/react-packager/src/BundlesLayout/index.js
@@ -13,10 +13,11 @@ const Activity = require('../Activity');
 const _ = require('underscore');
 const declareOpts = require('../lib/declareOpts');
 const fs = require('fs');
-const getCacheFilePath = require('../lib/getCacheFilePath');
-const loadCacheSync = require('../lib/loadCacheSync');
+const getCacheFilePath = require('../DependencyResolver/Cache/lib/getCacheFilePath');
+const loadCacheSync = require('../DependencyResolver/Cache/lib/loadCacheSync');
 const version = require('../../../../package.json').version;
 const path = require('path');
+const tmpdir = require('os').tmpDir();
 
 const validateOpts = declareOpts({
   dependencyResolver: {
@@ -189,6 +190,7 @@ class BundlesLayout {
 
   _getCacheFilePath(options) {
     return getCacheFilePath(
+      tmpdir,
       'react-packager-bundles-cache-',
       version,
       options.projectRoots.join(',').split(path.sep).join('-'),
diff --git a/packager/react-packager/src/Cache/__mocks__/index.js b/packager/react-packager/src/DependencyResolver/Cache/__mocks__/index.js
similarity index 100%
rename from packager/react-packager/src/Cache/__mocks__/index.js
rename to packager/react-packager/src/DependencyResolver/Cache/__mocks__/index.js
diff --git a/packager/react-packager/src/Cache/__tests__/Cache-test.js b/packager/react-packager/src/DependencyResolver/Cache/__tests__/Cache-test.js
similarity index 80%
rename from packager/react-packager/src/Cache/__tests__/Cache-test.js
rename to packager/react-packager/src/DependencyResolver/Cache/__tests__/Cache-test.js
index ee06dd221a8c..62220f6b0172 100644
--- a/packager/react-packager/src/Cache/__tests__/Cache-test.js
+++ b/packager/react-packager/src/DependencyResolver/Cache/__tests__/Cache-test.js
@@ -9,38 +9,35 @@
 'use strict';
 
 jest
-  .dontMock('underscore')
   .dontMock('absolute-path')
   .dontMock('../')
-  .dontMock('../../lib/loadCacheSync')
-  .dontMock('../../lib/getCacheFilePath');
+  .dontMock('../lib/loadCacheSync')
+  .dontMock('../lib/getCacheFilePath');
 
 jest
   .mock('fs')
   .setMock('os', {
-    tmpDir() { return 'tmpDir'; }
+    tmpDir() { return 'tmpDir'; },
   });
 
 var Promise = require('promise');
 var fs = require('fs');
-var _ = require('underscore');
 
 var Cache = require('../');
 
-describe('JSTransformer Cache', () => {
+describe('Cache', () => {
   describe('getting/setting', () => {
     pit('calls loader callback for uncached file', () => {
       fs.stat.mockImpl((file, callback) => {
         callback(null, {
           mtime: {
-            getTime: () => {}
-          }
+            getTime: () => {},
+          },
         });
       });
 
       var cache = new Cache({
-        projectRoots: ['/rootDir'],
-        transformModulePath: 'x.js',
+        cacheKey: 'cache',
       });
       var loaderCb = jest.genMockFn().mockImpl(() => Promise.resolve());
 
@@ -55,14 +52,13 @@ describe('JSTransformer Cache', () => {
       fs.stat.mockImpl((file, callback) => {
         callback(null, {
           mtime: {
-            getTime: () => {}
-          }
+            getTime: () => {},
+          },
         });
       });
 
       var cache = new Cache({
-        projectRoots: ['/rootDir'],
-        transformModulePath: 'x.js',
+        cacheKey: 'cache',
       });
       var index = 0;
       var loaderCb = jest.genMockFn().mockImpl(() =>
@@ -83,14 +79,13 @@ describe('JSTransformer Cache', () => {
       fs.stat.mockImpl((file, callback) =>
         callback(null, {
           mtime: {
-            getTime: () => {}
-          }
+            getTime: () => {},
+          },
         })
       );
 
       var cache = new Cache({
-        projectRoots: ['/rootDir'],
-        transformModulePath: 'x.js',
+        cacheKey: 'cache',
       });
       var loaderCb = jest.genMockFn().mockImpl(() =>
         Promise.resolve('lol')
@@ -105,14 +100,13 @@ describe('JSTransformer Cache', () => {
       fs.stat.mockImpl((file, callback) => {
         callback(null, {
           mtime: {
-            getTime: () => {}
-          }
+            getTime: () => {},
+          },
         });
       });
 
       var cache = new Cache({
-        projectRoots: ['/rootDir'],
-        transformModulePath: 'x.js',
+        cacheKey: 'cache',
       });
       var loaderCb = jest.genMockFn().mockImpl(() =>
         Promise.resolve('lol')
@@ -135,14 +129,13 @@ describe('JSTransformer Cache', () => {
       fs.stat.mockImpl((file, callback) => {
         callback(null, {
           mtime: {
-            getTime: () => mtime++
-          }
+            getTime: () => mtime++,
+          },
         });
       });
 
       var cache = new Cache({
-        projectRoots: ['/rootDir'],
-        transformModulePath: 'x.js',
+        cacheKey: 'cache',
       });
       var loaderCb = jest.genMockFn().mockImpl(() =>
         Promise.resolve('lol' + mtime)
@@ -167,14 +160,14 @@ describe('JSTransformer Cache', () => {
       fileStats = {
         '/rootDir/someFile': {
           mtime: {
-            getTime: () => 22
-          }
+            getTime: () => 22,
+          },
         },
         '/rootDir/foo': {
           mtime: {
-            getTime: () => 11
-          }
-        }
+            getTime: () => 11,
+          },
+        },
       };
 
       fs.existsSync.mockImpl(() => true);
@@ -189,14 +182,13 @@ describe('JSTransformer Cache', () => {
         '/rootDir/foo': {
           metadata: {mtime: 11},
           data: {field: 'lol wat'},
-        }
+        },
       }));
     });
 
     pit('should load cache from disk', () => {
       var cache = new Cache({
-        projectRoots: ['/rootDir'],
-        transformModulePath: 'x.js',
+        cacheKey: 'cache',
       });
       var loaderCb = jest.genMockFn();
 
@@ -219,16 +211,15 @@ describe('JSTransformer Cache', () => {
       fs.stat.mockImpl((file, callback) =>
         callback(null, {
           mtime: {
-            getTime: () => {}
-          }
+            getTime: () => {},
+          },
         })
       );
 
       fileStats['/rootDir/foo'].mtime.getTime = () => 123;
 
       var cache = new Cache({
-        projectRoots: ['/rootDir'],
-        transformModulePath: 'x.js',
+        cacheKey: 'cache',
       });
       var loaderCb = jest.genMockFn().mockImpl(() =>
         Promise.resolve('new value')
@@ -254,26 +245,17 @@ describe('JSTransformer Cache', () => {
     it('should write cache to disk', () => {
       var index = 0;
       var mtimes = [10, 20, 30];
-      var debounceIndex = 0;
-      _.debounce = callback => {
-        return () => {
-          if (++debounceIndex === 3) {
-            callback();
-          }
-        };
-      };
 
       fs.stat.mockImpl((file, callback) =>
         callback(null, {
           mtime: {
-            getTime: () => mtimes[index++]
-          }
+            getTime: () => mtimes[index++],
+          },
         })
       );
 
       var cache = new Cache({
-        projectRoots: ['/rootDir'],
-        transformModulePath: 'x.js',
+        cacheKey: 'cache',
       });
 
       cache.get('/rootDir/bar', 'field', () =>
@@ -286,7 +268,10 @@ describe('JSTransformer Cache', () => {
         Promise.resolve('baz value')
       );
 
-      jest.runAllTicks();
+      // jest has some trouble with promises and timeouts within promises :(
+      jest.runAllTimers();
+      jest.runAllTimers();
+
       expect(fs.writeFile).toBeCalled();
     });
   });
diff --git a/packager/react-packager/src/Cache/index.js b/packager/react-packager/src/DependencyResolver/Cache/index.js
similarity index 73%
rename from packager/react-packager/src/Cache/index.js
rename to packager/react-packager/src/DependencyResolver/Cache/index.js
index cbd9e2150fa0..8552e0dcf086 100644
--- a/packager/react-packager/src/Cache/index.js
+++ b/packager/react-packager/src/DependencyResolver/Cache/index.js
@@ -9,50 +9,37 @@
 'use strict';
 
 const Promise = require('promise');
-const _ = require('underscore');
-const declareOpts = require('../lib/declareOpts');
 const fs = require('fs');
-const getCacheFilePath = require('../lib/getCacheFilePath');
+const getCacheFilePath = require('./lib/getCacheFilePath');
 const isAbsolutePath = require('absolute-path');
-const loadCacheSync = require('../lib/loadCacheSync');
-const path = require('path');
-const version = require('../../../../package.json').version;
-
-const validateOpts = declareOpts({
-  resetCache: {
-    type: 'boolean',
-    default: false,
-  },
-  cacheVersion: {
-    type: 'string',
-    default: '1.0',
-  },
-  projectRoots: {
-    type: 'array',
-    required: true,
-  },
-  transformModulePath: {
-    type:'string',
-    required: true,
-  },
-});
-
-// TODO: move to Packager directory
-class Cache {
-  constructor(options) {
-    var opts = validateOpts(options);
+const loadCacheSync = require('./lib/loadCacheSync');
+const tmpdir = require('os').tmpDir();
 
-    this._cacheFilePath = this._getCacheFilePath(opts);
+function getObjectValues(object) {
+  return Object.keys(object).map(key => object[key]);
+}
 
-    var data;
-    if (!opts.resetCache) {
-      data = this._loadCacheSync(this._cacheFilePath);
+function debounce(fn, delay) {
+  var timeout;
+  return () => {
+    clearTimeout(timeout);
+    timeout = setTimeout(fn, delay);
+  };
+}
+
+class Cache {
+  constructor({
+    resetCache,
+    cacheKey,
+  }) {
+    this._cacheFilePath = getCacheFilePath(tmpdir, cacheKey);
+    if (!resetCache) {
+      this._data = this._loadCacheSync(this._cacheFilePath);
     } else {
-      data = Object.create(null);
+      this._data = Object.create(null);
     }
-    this._data = data;
 
-    this._persistEventually = _.debounce(
+    this._persistEventually = debounce(
       this._persistCache.bind(this),
       2000,
     );
@@ -124,10 +111,10 @@ class Cache {
     var data = this._data;
     var cacheFilepath = this._cacheFilePath;
 
-    var allPromises = _.values(data)
+    var allPromises = getObjectValues(data)
       .map(record => {
         var fieldNames = Object.keys(record.data);
-        var fieldValues = _.values(record.data);
+        var fieldValues = getObjectValues(record.data);
 
         return Promise
           .all(fieldValues)
@@ -187,25 +174,6 @@ class Cache {
 
     return ret;
   }
-
-  _getCacheFilePath(options) {
-    let mtime;
-    try {
-      ({mtime} = fs.statSync(options.transformModulePath));
-      mtime = String(mtime.getTime());
-    } catch (error) {
-      mtime = '';
-    }
-
-    return getCacheFilePath(
-      'react-packager-cache-',
-      version,
-      options.projectRoots.join(',').split(path.sep).join('-'),
-      options.cacheVersion || '0',
-      options.transformModulePath,
-      mtime
-    );
-  }
 }
 
 module.exports = Cache;
diff --git a/packager/react-packager/src/lib/getCacheFilePath.js b/packager/react-packager/src/DependencyResolver/Cache/lib/getCacheFilePath.js
similarity index 65%
rename from packager/react-packager/src/lib/getCacheFilePath.js
rename to packager/react-packager/src/DependencyResolver/Cache/lib/getCacheFilePath.js
index 1d8585297271..3975b65a34b2 100644
--- a/packager/react-packager/src/lib/getCacheFilePath.js
+++ b/packager/react-packager/src/DependencyResolver/Cache/lib/getCacheFilePath.js
@@ -10,16 +10,11 @@
 
 const crypto = require('crypto');
 const path = require('path');
-const tmpdir = require('os').tmpDir();
 
-function getCacheFilePath(...args) {
-  args = Array.prototype.slice.call(args);
-  const prefix = args.shift();
-
-  let hash = crypto.createHash('md5');
+function getCacheFilePath(tmpdir, ...args) {
+  const hash = crypto.createHash('md5');
   args.forEach(arg => hash.update(arg));
-
-  return path.join(tmpdir, prefix + hash.digest('hex'));
+  return path.join(tmpdir, hash.digest('hex'));
 }
 
 module.exports = getCacheFilePath;
diff --git a/packager/react-packager/src/lib/loadCacheSync.js b/packager/react-packager/src/DependencyResolver/Cache/lib/loadCacheSync.js
similarity index 100%
rename from packager/react-packager/src/lib/loadCacheSync.js
rename to packager/react-packager/src/DependencyResolver/Cache/lib/loadCacheSync.js
diff --git a/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js b/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js
index b182e1eb2aa8..83275f142907 100644
--- a/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js
+++ b/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js
@@ -14,7 +14,7 @@ jest
 
 jest.mock('fs');
 
-var Cache = require('../../Cache');
+var Cache = require('../../DependencyResolver/Cache');
 var Transformer = require('../');
 var fs = require('fs');
 

From ca17ed3b50908e74c64c505b6452de44dd8071d6 Mon Sep 17 00:00:00 2001
From: Gabe Levi <glevi@fb.com>
Date: Fri, 18 Dec 2015 17:03:59 -0800
Subject: [PATCH 0455/1411] Deploy v0.20.1

Reviewed By: mroch

Differential Revision: D2775901

fb-gh-sync-id: ef4fa402a930e4b5c82513dc5cc05553fa539116
---
 .flowconfig                                          | 6 +++---
 Libraries/Network/FormData.js                        | 1 +
 Libraries/ReactNative/ReactNativeAttributePayload.js | 2 +-
 3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/.flowconfig b/.flowconfig
index 08acf4e61aeb..503e5a92572b 100644
--- a/.flowconfig
+++ b/.flowconfig
@@ -55,9 +55,9 @@ suppress_type=$FlowIssue
 suppress_type=$FlowFixMe
 suppress_type=$FixMe
 
-suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
-suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)? #[0-9]+
+suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-0]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
+suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-0]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
 suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
 
 [version]
-0.19.0
+0.20.1
diff --git a/Libraries/Network/FormData.js b/Libraries/Network/FormData.js
index b2c4eda5a076..f6a4c4e2eacd 100644
--- a/Libraries/Network/FormData.js
+++ b/Libraries/Network/FormData.js
@@ -64,6 +64,7 @@ class FormData {
   getParts(): Array<FormDataPart> {
     return this._parts.map(([name, value]) => {
       var contentDisposition = 'form-data; name="' + name + '"';
+      /* $FlowIssue(>=0.20.1) #9463928 */
       var headers: Headers = {'content-disposition': contentDisposition};
       if (typeof value === 'string') {
         return {string: value, headers, fieldName: name};
diff --git a/Libraries/ReactNative/ReactNativeAttributePayload.js b/Libraries/ReactNative/ReactNativeAttributePayload.js
index 8ee8378c1054..74aa45cd75bc 100644
--- a/Libraries/ReactNative/ReactNativeAttributePayload.js
+++ b/Libraries/ReactNative/ReactNativeAttributePayload.js
@@ -143,7 +143,7 @@ function diffProperties(
   nextProps : Object,
   validAttributes : AttributeConfiguration
 ): ?Object {
-  var attributeConfig : ?AttributeConfiguration;
+  var attributeConfig : ?(CustomAttributeConfiguration | AttributeConfiguration);
   var nextProp;
   var prevProp;
 

From 73b2c529caea0697456cff1d9071ec3733ea4897 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Fri, 18 Dec 2015 14:15:22 +0000
Subject: [PATCH 0456/1411] Add alert docs

---
 website/server/extractDocs.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/website/server/extractDocs.js b/website/server/extractDocs.js
index 7ae599058a41..72efab86d0dc 100644
--- a/website/server/extractDocs.js
+++ b/website/server/extractDocs.js
@@ -220,6 +220,7 @@ var components = [
 
 var apis = [
   '../Libraries/ActionSheetIOS/ActionSheetIOS.js',
+  '../Libraries/Utilities/Alert.js',
   '../Libraries/Utilities/AlertIOS.js',
   '../Libraries/Animated/src/AnimatedImplementation.js',
   '../Libraries/AppRegistry/AppRegistry.js',

From 04f38d381a143dc3242db598d4b83ea25f343a27 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Sat, 19 Dec 2015 02:13:20 +0100
Subject: [PATCH 0457/1411] Update KnownIssues.md

---
 docs/KnownIssues.md | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/docs/KnownIssues.md b/docs/KnownIssues.md
index 8962584f0166..07b995c1cd71 100644
--- a/docs/KnownIssues.md
+++ b/docs/KnownIssues.md
@@ -26,18 +26,14 @@ ART
 Maps
 Modal
 Spinner (http://developer.android.com/guide/topics/ui/controls/spinner.html)
-Webview
 ```
 
 #### Modules
 
 ```
-Alert
 App State
 Camera Roll
-Dialog
 Media
-Pasteboard
 PushNotificationIOS
 ```
 

From 97fe0eae6b1365f7c9be8fba83f1396190cec131 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Sat, 19 Dec 2015 09:15:38 -0800
Subject: [PATCH 0458/1411] Fix map annotation view layout bug

Summary:
public
When using the custom view option for MapView annotations, the view would sometimes be top-left-aligned on the coordinate instead of centered on it. This fixes that.

Reviewed By: fredliu

Differential Revision: D2776380

fb-gh-sync-id: 793bfd1c3f5b1c923caf031e01b1f6c90e544472
---
 Libraries/Components/MapView/MapView.js | 17 ++++++-----
 React/Views/RCTMapManager.m             | 39 +++++++++++++++++++------
 2 files changed, 40 insertions(+), 16 deletions(-)

diff --git a/Libraries/Components/MapView/MapView.js b/Libraries/Components/MapView/MapView.js
index c32875369225..e10efa32be60 100644
--- a/Libraries/Components/MapView/MapView.js
+++ b/Libraries/Components/MapView/MapView.js
@@ -270,7 +270,7 @@ const MapView = React.createClass({
 
   render: function() {
     let children = [], {annotations, overlays} = this.props;
-    annotations = annotations && annotations.map((annotation: Object, index: number) => {
+    annotations = annotations && annotations.map((annotation: Object) => {
       let {
         id,
         image,
@@ -329,10 +329,10 @@ const MapView = React.createClass({
           }
         });
       }
-      return {
+      let result = {
         ...annotation,
         tintColor: tintColor && processColor(tintColor),
-        image: image && resolveAssetSource(image),
+        image,
         viewIndex,
         leftCalloutViewIndex,
         rightCalloutViewIndex,
@@ -341,17 +341,20 @@ const MapView = React.createClass({
         leftCalloutView: undefined,
         rightCalloutView: undefined,
         detailCalloutView: undefined,
-        id: id || String(index),
       };
+      result.id = id || encodeURIComponent(JSON.stringify(result));
+      result.image = image && resolveAssetSource(image);
+      return result;
     });
-    overlays = overlays && overlays.map((overlay: Object, index: number) => {
+    overlays = overlays && overlays.map((overlay: Object) => {
       let {id, fillColor, strokeColor} = overlay;
-      return {
+      let result = {
         ...overlay,
         strokeColor: strokeColor && processColor(strokeColor),
         fillColor: fillColor && processColor(fillColor),
-        id: id || String(index),
       };
+      result.id = id || encodeURIComponent(JSON.stringify(result));
+      return result;
     });
 
     // TODO: these should be separate events, to reduce bridge traffic
diff --git a/React/Views/RCTMapManager.m b/React/Views/RCTMapManager.m
index 3ef674850507..6718adde114c 100644
--- a/React/Views/RCTMapManager.m
+++ b/React/Views/RCTMapManager.m
@@ -41,6 +41,32 @@ @implementation RCTConvert (MKPinAnnotationColor)
 
 #endif
 
+@interface RCTMapAnnotationView : MKAnnotationView
+
+@property (nonatomic, strong) UIView *contentView;
+
+@end
+
+@implementation RCTMapAnnotationView
+
+- (void)setContentView:(UIView *)contentView
+{
+  [_contentView removeFromSuperview];
+  _contentView = contentView;
+  [self addSubview:_contentView];
+}
+
+- (void)layoutSubviews
+{
+  [super layoutSubviews];
+  self.bounds = (CGRect){
+    CGPointZero,
+    _contentView.frame.size,
+  };
+}
+
+@end
+
 @interface RCTMapManager() <MKMapViewDelegate>
 
 @end
@@ -136,19 +162,14 @@ - (MKAnnotationView *)mapView:(RCTMap *)mapView
   annotationView.clipsToBounds = YES;
   if (annotation.viewIndex != NSNotFound) {
 
-    NSString *const reuseIdentifier = @"RCTCustomViewAnnotation";
+    NSString *reuseIdentifier = NSStringFromClass([RCTMapAnnotationView class]);
     annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseIdentifier];
     if (!annotationView) {
-      annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation
-                                                    reuseIdentifier:reuseIdentifier];
-    }
-
-    for (UIView *view in annotationView.subviews) {
-      [view removeFromSuperview];
+      annotationView = [[RCTMapAnnotationView alloc] initWithAnnotation:annotation
+                                                        reuseIdentifier:reuseIdentifier];
     }
     UIView *reactView = mapView.reactSubviews[annotation.viewIndex];
-    annotationView.bounds = reactView.frame;
-    [annotationView addSubview:reactView];
+    ((RCTMapAnnotationView *)annotationView).contentView = reactView;
 
   } else if (annotation.image) {
 

From 174d37c1d96128978c0004a43f659ca9b1e4e768 Mon Sep 17 00:00:00 2001
From: olivier notteghem <oli@fb.com>
Date: Sat, 19 Dec 2015 17:12:56 -0800
Subject: [PATCH 0459/1411] fix listview inefficiency for tail-fetching
 scenarios (part2)

Reviewed By: sahrens

Differential Revision: D2775293

fb-gh-sync-id: a18a2fd6f64b5c979267a21ecdac8c3d97d9e007
---
 .../CustomComponents/ListView/ListView.js     | 20 +++++++------------
 1 file changed, 7 insertions(+), 13 deletions(-)

diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js
index 976967e64a34..5f771816528c 100644
--- a/Libraries/CustomComponents/ListView/ListView.js
+++ b/Libraries/CustomComponents/ListView/ListView.js
@@ -248,7 +248,6 @@ var ListView = React.createClass({
   getInitialState: function() {
     return {
       curRenderedRowsCount: this.props.initialListSize,
-      prevRenderedRowsCount: 0,
       highlightedRow: {},
     };
   },
@@ -266,6 +265,7 @@ var ListView = React.createClass({
     };
     this._childFrames = [];
     this._visibleRows = {};
+    this._prevRenderedRowsCount = 0;
   },
 
   componentDidMount: function() {
@@ -283,8 +283,8 @@ var ListView = React.createClass({
           state.curRenderedRowsCount + props.pageSize,
           props.dataSource.getRowCount()
         );
+        this._prevRenderedRowsCount = 0;
         return {
-          prevRenderedRowsCount: 0,
           curRenderedRowsCount: rowsToRender,
         };
       });
@@ -321,7 +321,7 @@ var ListView = React.createClass({
       }
 
       if (this.props.renderSectionHeader) {
-        var shouldUpdateHeader = rowCount >= this.state.prevRenderedRowsCount &&
+        var shouldUpdateHeader = rowCount >= this._prevRenderedRowsCount &&
           dataSource.sectionHeaderShouldUpdate(sectionIdx);
         bodyComponents.push(
           <StaticRenderer
@@ -340,7 +340,7 @@ var ListView = React.createClass({
       for (var rowIdx = 0; rowIdx < rowIDs.length; rowIdx++) {
         var rowID = rowIDs[rowIdx];
         var comboID = sectionID + '_' + rowID;
-        var shouldUpdateRow = rowCount >= this.state.prevRenderedRowsCount &&
+        var shouldUpdateRow = rowCount >= this._prevRenderedRowsCount &&
           dataSource.rowShouldUpdate(sectionIdx, rowIdx);
         var row =
           <StaticRenderer
@@ -427,7 +427,7 @@ var ListView = React.createClass({
     RCTScrollViewManager && RCTScrollViewManager.calculateChildFrames &&
       RCTScrollViewManager.calculateChildFrames(
         React.findNodeHandle(scrollComponent),
-        this._updateChildFrames,
+        this._updateVisibleRows,
       );
   },
 
@@ -459,10 +459,6 @@ var ListView = React.createClass({
     this._renderMoreRowsIfNeeded();
   },
 
-  _updateChildFrames: function(childFrames) {
-    this._updateVisibleRows(childFrames);
-  },
-
   _maybeCallOnEndReached: function(event) {
     if (this.props.onEndReached &&
         this.scrollProperties.contentLength !== this._sentEndForContentLength &&
@@ -495,15 +491,13 @@ var ListView = React.createClass({
         state.curRenderedRowsCount + props.pageSize,
         props.dataSource.getRowCount()
       );
+      this._prevRenderedRowsCount = state.curRenderedRowsCount;
       return {
-        prevRenderedRowsCount: state.curRenderedRowsCount,
         curRenderedRowsCount: rowsToRender
       };
     }, () => {
       this._measureAndUpdateScrollProps();
-      this.setState(state => ({
-        prevRenderedRowsCount: state.curRenderedRowsCount,
-      }));
+      this._prevRenderedRowsCount = this.state.curRenderedRowsCount;
     });
   },
 

From 574a5851e692690f64b37920a04fc6d0709799f6 Mon Sep 17 00:00:00 2001
From: Brian Douglas <ilikerobot@gmail.com>
Date: Sat, 19 Dec 2015 23:40:09 -0800
Subject: [PATCH 0460/1411] adds sample library distinction

---
 docs/LinkingLibraries.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/LinkingLibraries.md b/docs/LinkingLibraries.md
index eda6363bbe46..8fc6fe6e582b 100644
--- a/docs/LinkingLibraries.md
+++ b/docs/LinkingLibraries.md
@@ -41,7 +41,7 @@ $ npm install rnpm -g
 
 Install a library with native dependencies:
 ```bash
-$ npm install library-with-native-dependencies --save
+$ npm install <library-with-native-dependencies> --save
 ```
 
 **Note:** _`--save` or `--save-dev` flag is very important for this step. `rnpm` will link

From 289d9f250ff0597b1313e206f810c781d2a7d4c1 Mon Sep 17 00:00:00 2001
From: Qiao Liang <qiaoliang89@gmail.com>
Date: Sun, 20 Dec 2015 16:17:57 +0800
Subject: [PATCH 0461/1411] fix comment by shifting to seperate line

---
 docs/Animations.md | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/docs/Animations.md b/docs/Animations.md
index 0050b3d58576..c4686814c3f7 100644
--- a/docs/Animations.md
+++ b/docs/Animations.md
@@ -169,9 +169,9 @@ already implemented in the
 [`Easing`](https://github.com/facebook/react-native/blob/master/Libraries/Animation/Animated/Easing.js)
 class including quadratic, exponential, and bezier curves as well as functions
 like step and bounce. `interpolation` also has configurable behavior for
-extrapolating the `outputRange`. You can set the extrapolation by setting the `extrapolate`, 
-`extrapolateLeft` or `extrapolateRight` options. The default value is 
-`extend` but you can use `clamp` to prevent the output value from exceeding 
+extrapolating the `outputRange`. You can set the extrapolation by setting the `extrapolate`,
+`extrapolateLeft` or `extrapolateRight` options. The default value is
+`extend` but you can use `clamp` to prevent the output value from exceeding
 `outputRange`.
 
 #### Tracking Dynamic Values
@@ -212,11 +212,14 @@ respectively (`gestureState` is the second arg passed to the `PanResponder` hand
 
 ```javascript
 onScroll={Animated.event(
-  [{nativeEvent: {contentOffset: {x: scrollX}}}]   // scrollX = e.nativeEvent.contentOffset.x
+  // scrollX = e.nativeEvent.contentOffset.x
+  [{nativeEvent: {contentOffset: {x: scrollX}}}]   
 )}
 onPanResponderMove={Animated.event([
   null,                                          // ignore the native event
-  {dx: pan.x, dy: pan.y}                         // extract dx and dy from gestureState
+  // extract dx and dy from gestureState
+  // like 'pan.x = gestureState.dx, pan.y = gestureState.dy'
+  {dx: pan.x, dy: pan.y}                         
 ]);
 ```
 

From da850be6f0e0452b92e10a787d85b67b315b690c Mon Sep 17 00:00:00 2001
From: Qiao Liang <qiaoliang89@gmail.com>
Date: Sun, 20 Dec 2015 16:20:01 +0800
Subject: [PATCH 0462/1411] add doc for native event in doc

---
 .../browser/eventPlugins/PanResponder.js      | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/Libraries/vendor/react/browser/eventPlugins/PanResponder.js b/Libraries/vendor/react/browser/eventPlugins/PanResponder.js
index f71a645675de..afeba8a481f2 100644
--- a/Libraries/vendor/react/browser/eventPlugins/PanResponder.js
+++ b/Libraries/vendor/react/browser/eventPlugins/PanResponder.js
@@ -25,7 +25,24 @@ var currentCentroidY = TouchHistoryMath.currentCentroidY;
  * It provides a predictable wrapper of the responder handlers provided by the
  * [gesture responder system](/react-native/docs/gesture-responder-system.html).
  * For each handler, it provides a new `gestureState` object alongside the
- * normal event.
+ * native event object:
+ *
+ * ```
+ * onPanResponderMove: (event, gestureState) => {}
+ * ```
+ *
+ * A native event is a synthetic touch event with the following form:
+ *
+ *  - `nativeEvent`
+ *      + `changedTouches` - Array of all touch events that have changed since the last event
+ *      + `identifier` - The ID of the touch
+ *      + `locationX` - The X position of the touch, relative to the element
+ *      + `locationY` - The Y position of the touch, relative to the element
+ *      + `pageX` - The X position of the touch, relative to the root element
+ *      + `pageY` - The Y position of the touch, relative to the root element
+ *      + `target` - The node id of the element receiving the touch event
+ *      + `timestamp` - A time identifier for the touch, useful for velocity calculation
+ *      + `touches` - Array of all current touches on the screen
  *
  * A `gestureState` object has the following:
  *

From cec45957ac597eda04dbe8b5b1bc0dbf8e5ddff2 Mon Sep 17 00:00:00 2001
From: Qiao Liang <qiaoliang89@gmail.com>
Date: Mon, 21 Dec 2015 01:56:07 +0800
Subject: [PATCH 0463/1411] remove outdated info

---
 docs/KnownIssues.md | 1 -
 1 file changed, 1 deletion(-)

diff --git a/docs/KnownIssues.md b/docs/KnownIssues.md
index 07b995c1cd71..127cba3702d3 100644
--- a/docs/KnownIssues.md
+++ b/docs/KnownIssues.md
@@ -46,7 +46,6 @@ There are properties that work on one platform only, either because they can inh
 There are known cases where the APIs could be made more consistent across iOS and Android:
 
 - `<AndroidViewPager>` and `<ScrollView pagingEnabled={true}>` on iOS do a similar thing. We might want to unify them to `<ViewPager>`.
-- `alert()` needs Android support (once the Dialogs module is open sourced)
 - It might be possible to bring `LinkingIOS` and `IntentAndroid` closer together.
 - `ActivityIndicator` could render a native spinning indicator on both platforms (currently this is done using `ActivityIndicatorIOS` on iOS and `ProgressBarAndroid` on Android).
 - `ProgressBar` could render a horizontal progress bar on both platforms (on iOS this is `ProgressViewIOS`, on Android it's `ProgressBarAndroid`).

From 040909904c5dfef579ec85000423b8f417dfd2ae Mon Sep 17 00:00:00 2001
From: olivier notteghem <oli@fb.com>
Date: Mon, 21 Dec 2015 08:40:52 -0800
Subject: [PATCH 0464/1411] fix listview inefficiency for tail-fetching
 scenarios (part1)

Reviewed By: sahrens

Differential Revision: D2775226

fb-gh-sync-id: 13cc895d8cde4ab1baf527ab468d6c7b47158aef
---
 Libraries/CustomComponents/ListView/ListView.js | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js
index 5f771816528c..fa4548f73883 100644
--- a/Libraries/CustomComponents/ListView/ListView.js
+++ b/Libraries/CustomComponents/ListView/ListView.js
@@ -37,6 +37,7 @@ var TimerMixin = require('react-timer-mixin');
 var isEmpty = require('isEmpty');
 var logError = require('logError');
 var merge = require('merge');
+var shallowEqual = require('shallowEqual');
 
 var PropTypes = React.PropTypes;
 
@@ -266,6 +267,8 @@ var ListView = React.createClass({
     this._childFrames = [];
     this._visibleRows = {};
     this._prevRenderedRowsCount = 0;
+    this._sentEndForContentLength = null;
+    this._lastScrollPropertiesCheckedForPaging = null;
   },
 
   componentDidMount: function() {
@@ -452,13 +455,6 @@ var ListView = React.createClass({
     }
   },
 
-  _setScrollVisibleLength: function(left, top, width, height) {
-    this.scrollProperties.visibleLength = !this.props.horizontal ?
-      height : width;
-    this._updateVisibleRows();
-    this._renderMoreRowsIfNeeded();
-  },
-
   _maybeCallOnEndReached: function(event) {
     if (this.props.onEndReached &&
         this.scrollProperties.contentLength !== this._sentEndForContentLength &&
@@ -479,6 +475,12 @@ var ListView = React.createClass({
       return;
     }
 
+    if (shallowEqual(this._lastScrollPropertiesCheckedForPaging, this.scrollProperties)) {
+      // distance from end of feed hasn't changed since last check, avoid paging twice..
+      return;
+    }
+    this._lastScrollPropertiesCheckedForPaging = {...this.scrollProperties};
+
     var distanceFromEnd = this._getDistanceFromEnd(this.scrollProperties);
     if (distanceFromEnd < this.props.scrollRenderAheadDistance) {
       this._pageInNewRows();

From a99c5160eeeedec0d08afca1a7cda235418765f4 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Mon, 21 Dec 2015 09:37:27 -0800
Subject: [PATCH 0465/1411] Android Instrumentations tests are ready to be run
 in github/CI open source environment

Reviewed By: mkonicek

Differential Revision: D2769217

fb-gh-sync-id: 7469af816241d8b642753cca21f6542b971e9572
---
 ReactAndroid/build.gradle                     |   4 +
 .../src/androidTest/AndroidManifest.xml       |  17 ++
 .../assets/ScrollViewTestModule.js            | 136 ++++++++++
 .../src/androidTest/assets/TestBundle.js      |  30 +++
 .../testing/AbstractScrollViewTestCase.java   | 114 +++++++++
 .../facebook/react/testing/AssertModule.java  |  57 +++++
 .../react/testing/FakeAsyncLocalStorage.java  |  58 +++++
 .../facebook/react/testing/IdleWaiter.java    |  17 ++
 .../testing/InstanceSpecForTestPackage.java   |  49 ++++
 .../testing/JSIntegrationTestChecker.java     |  59 +++++
 .../testing/MultipleFailureException.java     |  47 ++++
 .../testing/NetworkRecordingModuleMock.java   | 138 ++++++++++
 .../ReactAppInstrumentationTestCase.java      | 166 ++++++++++++
 .../react/testing/ReactAppTestActivity.java   | 236 ++++++++++++++++++
 .../testing/ReactBridgeIdleSignaler.java      |  62 +++++
 .../react/testing/ReactIdleDetectionUtil.java | 125 ++++++++++
 .../testing/ReactInstanceSpecForTest.java     |  69 +++++
 .../testing/ReactIntegrationTestCase.java     | 212 ++++++++++++++++
 .../react/testing/ReactSettingsForTests.java  |  32 +++
 .../react/testing/ReactTestHelper.java        | 129 ++++++++++
 .../testing/ScreenshotingFrameLayout.java     |  71 ++++++
 .../testing/SingleTouchGestureGenerator.java  | 161 ++++++++++++
 .../react/testing/StringRecordingModule.java  |  42 ++++
 .../ReactHorizontalScrollViewTestCase.java    | 134 ++++++++++
 .../react/tests/ReactScrollViewTestCase.java  | 136 ++++++++++
 circle.yml                                    |   6 +-
 26 files changed, 2306 insertions(+), 1 deletion(-)
 create mode 100644 ReactAndroid/src/androidTest/AndroidManifest.xml
 create mode 100644 ReactAndroid/src/androidTest/assets/ScrollViewTestModule.js
 create mode 100644 ReactAndroid/src/androidTest/assets/TestBundle.js
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/AbstractScrollViewTestCase.java
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/AssertModule.java
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/FakeAsyncLocalStorage.java
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/IdleWaiter.java
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/InstanceSpecForTestPackage.java
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/JSIntegrationTestChecker.java
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/MultipleFailureException.java
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/NetworkRecordingModuleMock.java
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppInstrumentationTestCase.java
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactBridgeIdleSignaler.java
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIdleDetectionUtil.java
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstanceSpecForTest.java
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactSettingsForTests.java
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/ScreenshotingFrameLayout.java
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/SingleTouchGestureGenerator.java
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/StringRecordingModule.java
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/tests/ReactHorizontalScrollViewTestCase.java
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/tests/ReactScrollViewTestCase.java

diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle
index 850d2f41f9a8..ae79f43cb6e4 100644
--- a/ReactAndroid/build.gradle
+++ b/ReactAndroid/build.gradle
@@ -217,6 +217,8 @@ android {
         }
 
         buildConfigField 'boolean', 'IS_INTERNAL_BUILD', 'false'
+        testApplicationId "com.facebook.react.tests"
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
     }
 
     sourceSets.main {
@@ -258,6 +260,8 @@ dependencies {
     testCompile "org.mockito:mockito-core:${MOCKITO_CORE_VERSION}"
     testCompile "org.easytesting:fest-assert-core:${FEST_ASSERT_CORE_VERSION}"
     testCompile "org.robolectric:robolectric:${ROBOLECTRIC_VERSION}"
+
+    androidTestCompile "com.android.support.test:testing-support-lib:0.1"
 }
 
 apply from: 'release.gradle'
diff --git a/ReactAndroid/src/androidTest/AndroidManifest.xml b/ReactAndroid/src/androidTest/AndroidManifest.xml
new file mode 100644
index 000000000000..2363aff11566
--- /dev/null
+++ b/ReactAndroid/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.facebook.react.tests"
+          android:versionCode="1"
+          android:versionName="1.0" >
+  <application>
+    <activity
+            android:name="com.facebook.react.testing.ReactAppTestActivity"
+            android:theme="@style/Theme.ReactNative.AppCompat.Light.NoActionBar.FullScreen"/>
+  </application>
+  <uses-sdk android:targetSdkVersion="7" />
+  <supports-screens android:anyDensity="true" />
+  <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+  <!-- needed for screenshot tests -->
+  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+</manifest>
diff --git a/ReactAndroid/src/androidTest/assets/ScrollViewTestModule.js b/ReactAndroid/src/androidTest/assets/ScrollViewTestModule.js
new file mode 100644
index 000000000000..0a2f5143a148
--- /dev/null
+++ b/ReactAndroid/src/androidTest/assets/ScrollViewTestModule.js
@@ -0,0 +1,136 @@
+/**
+ * @providesModule ScrollViewTestModule
+ * @jsx React.DOM
+ */
+
+'use strict';
+
+var BatchedBridge = require('BatchedBridge');
+var React = require('React');
+var View = require('View');
+var ScrollView = require('ScrollView');
+var Text = require('Text');
+var StyleSheet = require('StyleSheet');
+var TouchableWithoutFeedback = require('TouchableWithoutFeedback');
+var ScrollListener = require('NativeModules').ScrollListener;
+
+var NUM_ITEMS = 100;
+
+// Shared by integration tests for ScrollView and HorizontalScrollView
+
+var scrollViewApp;
+
+var Item = React.createClass({
+  render: function() {
+    return (
+      <TouchableWithoutFeedback onPress={this.props.onPress}>
+        <View style={styles.item_container}>
+          <Text style={styles.item_text}>{this.props.text}</Text>
+        </View>
+      </TouchableWithoutFeedback>
+    );
+  },
+});
+
+var getInitialState = function() {
+  var data = [];
+  for (var i = 0; i < NUM_ITEMS; i++) {
+    data[i] = {text: 'Item ' + i + '!'};
+  }
+  return {
+    data: data,
+  };
+};
+
+var onScroll = function(e) {
+  ScrollListener.onScroll(e.nativeEvent.contentOffset.x, e.nativeEvent.contentOffset.y);
+};
+
+var onScrollBeginDrag = function(e) {
+  ScrollListener.onScrollBeginDrag(e.nativeEvent.contentOffset.x, e.nativeEvent.contentOffset.y);
+};
+
+var onScrollEndDrag = function(e) {
+  ScrollListener.onScrollEndDrag(e.nativeEvent.contentOffset.x, e.nativeEvent.contentOffset.y);
+};
+
+var onItemPress = function(itemNumber) {
+  ScrollListener.onItemPress(itemNumber);
+};
+
+var ScrollViewTestApp = React.createClass({
+  getInitialState: getInitialState,
+  onScroll: onScroll,
+  onItemPress: onItemPress,
+  onScrollBeginDrag: onScrollBeginDrag,
+  onScrollEndDrag: onScrollEndDrag,
+
+  scrollTo: function(destX, destY) {
+    this.refs.scrollView.scrollTo(destY, destX);
+  },
+
+  render: function() {
+    scrollViewApp = this;
+    var children = this.state.data.map((item, index) => (
+      <Item
+        key={index} text={item.text}
+        onPress={this.onItemPress.bind(this, index)} />
+    ));
+    return (
+      <ScrollView onScroll={this.onScroll} onScrollBeginDrag={this.onScrollBeginDrag} onScrollEndDrag={this.onScrollEndDrag} ref="scrollView">
+        {children}
+      </ScrollView>
+    );
+  },
+});
+
+var HorizontalScrollViewTestApp = React.createClass({
+  getInitialState: getInitialState,
+  onScroll: onScroll,
+  onItemPress: onItemPress,
+
+  scrollTo: function(destX, destY) {
+    this.refs.scrollView.scrollTo(destY, destX);
+  },
+
+  render: function() {
+    scrollViewApp = this;
+    var children = this.state.data.map((item, index) => (
+      <Item
+        key={index} text={item.text}
+        onPress={this.onItemPress.bind(this, index)} />
+    ));
+    return (
+      <ScrollView horizontal={true} onScroll={this.onScroll} ref="scrollView">
+        {children}
+      </ScrollView>
+    );
+  },
+});
+
+var styles = StyleSheet.create({
+  item_container: {
+    padding: 30,
+    backgroundColor: '#ffffff',
+  },
+  item_text: {
+    flex: 1,
+    fontSize: 18,
+    alignSelf: 'center',
+  },
+});
+
+var ScrollViewTestModule = {
+  ScrollViewTestApp: ScrollViewTestApp,
+  HorizontalScrollViewTestApp: HorizontalScrollViewTestApp,
+  scrollTo: function(destX, destY) {
+    scrollViewApp.scrollTo(destX, destY);
+  },
+};
+
+BatchedBridge.registerCallableModule(
+  'ScrollViewTestModule',
+  ScrollViewTestModule
+);
+
+module.exports = ScrollViewTestModule;
diff --git a/ReactAndroid/src/androidTest/assets/TestBundle.js b/ReactAndroid/src/androidTest/assets/TestBundle.js
new file mode 100644
index 000000000000..1bbdad7348e0
--- /dev/null
+++ b/ReactAndroid/src/androidTest/assets/TestBundle.js
@@ -0,0 +1,30 @@
+/**
+ * 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';
+
+// Disable YellowBox so we do not have to mock its dependencies
+console.disableYellowBox = true;
+
+// Include modules used by integration tests
+require('ScrollViewTestModule');
+
+// Define catalyst test apps used in integration tests
+var AppRegistry = require('AppRegistry');
+
+var apps = [
+{
+    appKey: 'ScrollViewTestApp',
+    component: () => require('ScrollViewTestModule').ScrollViewTestApp
+},
+{
+  appKey: 'HorizontalScrollViewTestApp',
+  component: () => require('ScrollViewTestModule').HorizontalScrollViewTestApp
+},
+];
+
+AppRegistry.registerConfig(apps);
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/AbstractScrollViewTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/AbstractScrollViewTestCase.java
new file mode 100644
index 000000000000..afdf4bc903d5
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/AbstractScrollViewTestCase.java
@@ -0,0 +1,114 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.testing;
+
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import com.facebook.react.bridge.BaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.bridge.JavaScriptModule;
+import com.facebook.react.testing.ReactInstanceSpecForTest;
+import com.facebook.react.testing.ReactAppInstrumentationTestCase;
+
+/**
+ * Shared by {@link ReactScrollViewTestCase} and {@link ReactHorizontalScrollViewTestCase}.
+ * See also ScrollViewTestModule.js
+ */
+public abstract class AbstractScrollViewTestCase extends ReactAppInstrumentationTestCase {
+
+  protected ScrollListenerModule mScrollListenerModule;
+
+  protected static interface ScrollViewTestModule extends JavaScriptModule {
+    public void scrollTo(float destX, float destY);
+  }
+
+  @Override
+  protected void tearDown() throws Exception {
+    waitForBridgeAndUIIdle(60000);
+    super.tearDown();
+  }
+
+  @Override
+  protected ReactInstanceSpecForTest createReactInstanceSpecForTest() {
+    mScrollListenerModule = new ScrollListenerModule();
+    return super.createReactInstanceSpecForTest()
+        .addNativeModule(mScrollListenerModule)
+        .addJSModule(ScrollViewTestModule.class);
+  }
+
+  // See ScrollViewListenerModule.js
+  protected static class ScrollListenerModule extends BaseJavaModule {
+
+    private final ArrayList<Double> mXOffsets = new ArrayList<Double>();
+    private final ArrayList<Double> mYOffsets = new ArrayList<Double>();
+    private final ArrayList<Integer> mItemsPressed = new ArrayList<Integer>();
+    private final Semaphore mScrollSignaler = new Semaphore(0);
+    private boolean mScrollBeginDragCalled;
+    private boolean mScrollEndDragCalled;
+
+    // Matches ScrollViewListenerModule.js
+    @Override
+    public String getName() {
+      return "ScrollListener";
+    }
+
+    @ReactMethod
+    public void onScroll(double x, double y) {
+      mXOffsets.add(x);
+      mYOffsets.add(y);
+      mScrollSignaler.release();
+    }
+
+    @ReactMethod
+    public void onItemPress(int itemNumber) {
+      mItemsPressed.add(itemNumber);
+    }
+
+    @ReactMethod
+    public void onScrollBeginDrag(double x, double y) {
+      mScrollBeginDragCalled = true;
+    }
+
+    @ReactMethod
+    public void onScrollEndDrag(double x, double y) {
+      mScrollEndDragCalled = true;
+    }
+
+    public void waitForScrollIdle() {
+      while (true) {
+        try {
+          boolean gotScrollSignal = mScrollSignaler.tryAcquire(1000, TimeUnit.MILLISECONDS);
+          if (!gotScrollSignal) {
+            return;
+          }
+        } catch (InterruptedException e) {
+          throw new RuntimeException(e);
+        }
+      }
+    }
+
+    public ArrayList<Double> getXOffsets() {
+      return mXOffsets;
+    }
+
+    public ArrayList<Double> getYOffsets() {
+      return mYOffsets;
+    }
+
+    public ArrayList<Integer> getItemsPressed() {
+      return mItemsPressed;
+    }
+
+    public boolean dragEventsMatch() {
+      return mScrollBeginDragCalled && mScrollEndDragCalled;
+    }
+  }
+}
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/AssertModule.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/AssertModule.java
new file mode 100644
index 000000000000..4379470164fc
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/AssertModule.java
@@ -0,0 +1,57 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.testing;
+
+import javax.annotation.Nullable;
+
+import com.facebook.react.bridge.BaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+/**
+ * NativeModule for tests that allows assertions from JS to propagate to Java.
+ */
+public class AssertModule extends BaseJavaModule {
+
+  private boolean mGotSuccess;
+  private boolean mGotFailure;
+  private @Nullable String mFirstFailureStackTrace;
+
+  @Override
+  public String getName() {
+    return "Assert";
+  }
+
+  @ReactMethod
+  public void fail(String stackTrace) {
+    if (!mGotFailure) {
+      mGotFailure = true;
+      mFirstFailureStackTrace = stackTrace;
+    }
+  }
+
+  @ReactMethod
+  public void success() {
+    mGotSuccess = true;
+  }
+
+  /**
+   * Allows the user of this module to verify that asserts are actually being called from JS and
+   * that none of them failed.
+   */
+  public void verifyAssertsAndReset() {
+    assertFalse("First failure: " + mFirstFailureStackTrace, mGotFailure);
+    assertTrue("Received no assertions during the test!", mGotSuccess);
+    mGotFailure = false;
+    mGotSuccess = false;
+    mFirstFailureStackTrace = null;
+  }
+}
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/FakeAsyncLocalStorage.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/FakeAsyncLocalStorage.java
new file mode 100644
index 000000000000..e62d09ecb0c1
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/FakeAsyncLocalStorage.java
@@ -0,0 +1,58 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.testing;
+
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.BaseJavaModule;
+import com.facebook.react.bridge.Callback;
+import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.WritableMap;
+
+/**
+ * Dummy implementation of storage module, used for testing
+ */
+public final class FakeAsyncLocalStorage extends BaseJavaModule {
+
+  private static WritableMap errorMessage;
+  static {
+    errorMessage = Arguments.createMap();
+    errorMessage.putString("message", "Fake Async Local Storage");
+  }
+
+  @Override
+  public String getName() {
+    return "AsyncSQLiteDBStorage";
+  }
+
+  @ReactMethod
+  public void multiGet(final ReadableArray keys, final Callback callback) {
+    callback.invoke(errorMessage, null);
+  }
+
+  @ReactMethod
+  public void multiSet(final ReadableArray keyValueArray, final Callback callback) {
+    callback.invoke(errorMessage);
+  }
+
+  @ReactMethod
+  public void multiRemove(final ReadableArray keys, final Callback callback) {
+    callback.invoke(errorMessage);
+  }
+
+  @ReactMethod
+  public void clear(Callback callback) {
+    callback.invoke(errorMessage);
+  }
+
+  @ReactMethod
+  public void getAllKeys(final Callback callback) {
+    callback.invoke(errorMessage, null);
+  }
+}
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/IdleWaiter.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/IdleWaiter.java
new file mode 100644
index 000000000000..98884c1033a3
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/IdleWaiter.java
@@ -0,0 +1,17 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.testing;
+
+/**
+ * Interface for something that knows how to wait for bridge and UI idle.
+ */
+public interface IdleWaiter {
+
+  void waitForBridgeAndUIIdle();
+}
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/InstanceSpecForTestPackage.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/InstanceSpecForTestPackage.java
new file mode 100644
index 000000000000..cb7bbf3153a7
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/InstanceSpecForTestPackage.java
@@ -0,0 +1,49 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.testing;
+
+import java.util.List;
+
+import android.view.View;
+
+import com.facebook.react.ReactPackage;
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.JavaScriptModule;
+import com.facebook.react.uimanager.ViewManager;
+import com.facebook.react.ReactPackage;
+
+/**
+ * This class wraps {@class ReactInstanceSpecForTest} in {@class ReactPackage} interface.
+ * TODO(6788898): Refactor test code to use ReactPackage instead of SpecForTest
+ */
+public class InstanceSpecForTestPackage implements ReactPackage {
+
+  private final ReactInstanceSpecForTest mSpecForTest;
+
+  public InstanceSpecForTestPackage(ReactInstanceSpecForTest specForTest) {
+    mSpecForTest = specForTest;
+  }
+
+  @Override
+  public List<NativeModule> createNativeModules(
+      ReactApplicationContext catalystApplicationContext) {
+    return mSpecForTest.getExtraNativeModulesForTest();
+  }
+
+  @Override
+  public List<Class<? extends JavaScriptModule>> createJSModules() {
+    return mSpecForTest.getExtraJSModulesForTest();
+  }
+
+  @Override
+  public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
+    return mSpecForTest.getExtraViewManagers();
+  }
+}
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/JSIntegrationTestChecker.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/JSIntegrationTestChecker.java
new file mode 100644
index 000000000000..1ddf186c90de
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/JSIntegrationTestChecker.java
@@ -0,0 +1,59 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.testing;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import com.facebook.react.bridge.BaseJavaModule;
+import com.facebook.react.bridge.Callback;
+import com.facebook.react.bridge.ReactMethod;
+
+/**
+ * This class is used to verify that some JS integration tests have completed successfully.
+ * The JS integration tests can be started from a ReactIntegrationTestCase and upon
+ * finishing successfully the {@link JSIntegrationTestChecker#testDone()} method will be called.
+ * To verify if the test has completed successfully, call {#link JSIntegrationTestChecker#await()}
+ * to wait for the test to run, and {#link JSIntegrationTestChecker#isTestDone()} to check if it
+ * completed successfully.
+ */
+public class JSIntegrationTestChecker extends BaseJavaModule {
+
+  private final CountDownLatch mLatch;
+
+  public JSIntegrationTestChecker() {
+    mLatch = new CountDownLatch(1);
+  }
+
+  @Override
+  public String getName() {
+    return "TestModule";
+  }
+
+  @ReactMethod
+  public void markTestCompleted() {
+    mLatch.countDown();
+  }
+
+  @ReactMethod
+  public void verifySnapshot(Callback callback) {
+  }
+
+  public boolean await(long ms) {
+    try {
+      return mLatch.await(ms, TimeUnit.MILLISECONDS);
+    } catch (InterruptedException ignore) {
+      return false;
+    }
+  }
+
+  public boolean isTestDone() {
+    return mLatch.getCount() == 0;
+  }
+}
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/MultipleFailureException.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/MultipleFailureException.java
new file mode 100644
index 000000000000..a996403d44f3
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/MultipleFailureException.java
@@ -0,0 +1,47 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.testing;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.List;
+
+/**
+ * Custom implementation of {@link org.junit.runners.model.MultipleFailureException} that includes
+ * stack information of collected exception as a part of the message.
+ */
+public class MultipleFailureException extends org.junit.runners.model.MultipleFailureException {
+
+  public MultipleFailureException(List<Throwable> errors) {
+    super(errors);
+  }
+
+  @Override
+  public String getMessage() {
+    StringBuilder sb = new StringBuilder();
+    List<Throwable> errors = getFailures();
+
+    sb.append(String.format("There were %d errors:", errors.size()));
+
+    int i = 0;
+    for (Throwable e : errors) {
+      sb.append(String.format("%n---- Error #%d", i));
+      sb.append("\n" + getStackTraceAsString(e));
+      i++;
+    }
+    sb.append("\n");
+    return sb.toString();
+  }
+
+  private static String getStackTraceAsString(Throwable throwable) {
+    StringWriter stringWriter = new StringWriter();
+    throwable.printStackTrace(new PrintWriter(stringWriter));
+    return stringWriter.toString();
+  }
+}
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/NetworkRecordingModuleMock.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/NetworkRecordingModuleMock.java
new file mode 100644
index 000000000000..b23ba1e738ce
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/NetworkRecordingModuleMock.java
@@ -0,0 +1,138 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.testing;
+
+import javax.annotation.Nullable;
+
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.Callback;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.WritableArray;
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.modules.core.DeviceEventManagerModule;
+
+/**
+ * Mock Networking module that records last request received by {@link #sendRequest} method and
+ * returns reponse code and body that should be set with {@link #setResponse}
+ */
+public class NetworkRecordingModuleMock extends ReactContextBaseJavaModule {
+
+  public int mRequestCount = 0;
+  public @Nullable String mRequestMethod;
+  public @Nullable String mRequestURL;
+  public @Nullable ReadableArray mRequestHeaders;
+  public @Nullable ReadableMap mRequestData;
+  public int mLastRequestId;
+  public boolean mAbortedRequest;
+
+  private final boolean mCompleteRequest;
+
+  public NetworkRecordingModuleMock(ReactApplicationContext reactContext) {
+    this(reactContext, true);
+  }
+
+  public NetworkRecordingModuleMock(ReactApplicationContext reactContext, boolean completeRequest) {
+    super(reactContext);
+    mCompleteRequest = completeRequest;
+  }
+
+  public static interface RequestListener {
+    public void onRequest(String method, String url, ReadableArray header, ReadableMap data);
+  }
+
+  private int mResponseCode;
+  private @Nullable String mResponseBody;
+  private @Nullable RequestListener mRequestListener;
+
+  public void setResponse(int code, String body) {
+    mResponseCode = code;
+    mResponseBody = body;
+  }
+
+  public void setRequestListener(RequestListener requestListener) {
+    mRequestListener = requestListener;
+  }
+
+  @Override
+  public final String getName() {
+    return "RCTNetworking";
+  }
+
+  private void fireReactCallback(
+      Callback callback,
+      int status,
+      @Nullable String headers,
+      @Nullable String body) {
+    callback.invoke(status, headers, body);
+  }
+
+  @ReactMethod
+  public final void sendRequest(
+      String method,
+      String url,
+      int requestId,
+      ReadableArray headers,
+      ReadableMap data,
+      boolean incrementalUpdates) {
+    mLastRequestId = requestId;
+    mRequestCount++;
+    mRequestMethod = method;
+    mRequestURL = url;
+    mRequestHeaders = headers;
+    mRequestData = data;
+    if (mRequestListener != null) {
+      mRequestListener.onRequest(method, url, headers, data);
+    }
+    if (mCompleteRequest) {
+      onResponseReceived(requestId, mResponseCode, null);
+      onDataReceived(requestId, mResponseBody);
+      onRequestComplete(requestId, null);
+    }
+  }
+
+  @ReactMethod
+  public void abortRequest(int requestId) {
+    mLastRequestId = requestId;
+    mAbortedRequest = true;
+  }
+
+  private void onDataReceived(int requestId, String data) {
+    WritableArray args = Arguments.createArray();
+    args.pushInt(requestId);
+    args.pushString(data);
+
+    getEventEmitter().emit("didReceiveNetworkData", args);
+  }
+
+  private void onRequestComplete(int requestId, @Nullable String error) {
+    WritableArray args = Arguments.createArray();
+    args.pushInt(requestId);
+    args.pushString(error);
+
+    getEventEmitter().emit("didCompleteNetworkResponse", args);
+  }
+
+  private void onResponseReceived(int requestId, int code, WritableMap headers) {
+    WritableArray args = Arguments.createArray();
+    args.pushInt(requestId);
+    args.pushInt(code);
+    args.pushMap(headers);
+
+    getEventEmitter().emit("didReceiveNetworkResponse", args);
+  }
+
+  private DeviceEventManagerModule.RCTDeviceEventEmitter getEventEmitter() {
+    return getReactApplicationContext()
+        .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class);
+  }
+}
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppInstrumentationTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppInstrumentationTestCase.java
new file mode 100644
index 000000000000..aaba651def94
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppInstrumentationTestCase.java
@@ -0,0 +1,166 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.testing;
+
+import javax.annotation.Nullable;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import android.graphics.Bitmap;
+import android.test.ActivityInstrumentationTestCase2;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.facebook.infer.annotation.Assertions;
+import com.facebook.react.bridge.ReactContext;
+
+/**
+ * Base class for instrumentation tests that runs React based react application in UI mode
+ */
+public abstract class ReactAppInstrumentationTestCase extends
+    ActivityInstrumentationTestCase2<ReactAppTestActivity> implements IdleWaiter {
+
+  public ReactAppInstrumentationTestCase() {
+    super(ReactAppTestActivity.class);
+  }
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+
+    final ReactAppTestActivity activity = getActivity();
+    try {
+      runTestOnUiThread(new Runnable() {
+        @Override
+        public void run() {
+          activity.loadApp(
+              getReactApplicationKeyUnderTest(),
+              createReactInstanceSpecForTest(),
+              getEnableDevSupport());
+        }
+      });
+    } catch (Throwable t) {
+      throw new Exception("Unable to load react app", t);
+    }
+    waitForBridgeAndUIIdle();
+    assertTrue("Layout never occurred!", activity.waitForLayout(5000));
+    waitForBridgeAndUIIdle();
+  }
+
+  @Override
+  protected void tearDown() throws Exception {
+    ReactAppTestActivity activity = getActivity();
+    super.tearDown();
+    activity.waitForDestroy(5000);
+  }
+
+  public ViewGroup getRootView() {
+    return (ViewGroup) getActivity().getRootView();
+  }
+
+  /**
+   * This method isn't safe since it doesn't factor in layout-only view removal. Use
+   * {@link #getViewByTestId(String)} instead.
+   */
+  @Deprecated
+  public <T extends View> T getViewAtPath(int... path) {
+    return ReactTestHelper.getViewAtPath((ViewGroup) getRootView().getParent(), path);
+  }
+
+  public <T extends View> T getViewByTestId(String testID) {
+    return (T) ReactTestHelper
+        .getViewWithReactTestId((ViewGroup) getRootView().getParent(), testID);
+  }
+
+  public SingleTouchGestureGenerator createGestureGenerator() {
+    return new SingleTouchGestureGenerator(getRootView(), this);
+  }
+
+  public void waitForBridgeAndUIIdle() {
+    getActivity().waitForBridgeAndUIIdle();
+  }
+
+  public void waitForBridgeAndUIIdle(long timeoutMs) {
+    getActivity().waitForBridgeAndUIIdle(timeoutMs);
+  }
+
+  protected Bitmap getScreenshot() {
+    // Wait for the UI to settle. If the UI is doing animations, this may be unsafe!
+    getInstrumentation().waitForIdleSync();
+
+    final CountDownLatch latch = new CountDownLatch(1);
+    final BitmapHolder bitmapHolder = new BitmapHolder();
+    final Runnable getScreenshotRunnable = new Runnable() {
+
+      private static final int MAX_TRIES = 1000;
+      // This is the constant used in the support library for APIs that don't have Choreographer
+      private static final int FRAME_DELAY_MS = 10;
+
+      private int mNumRuns = 0;
+
+      @Override
+      public void run() {
+        mNumRuns++;
+        ReactAppTestActivity activity = getActivity();
+        if (!activity.isScreenshotReady()) {
+          if (mNumRuns > MAX_TRIES) {
+            throw new RuntimeException(
+                "Waited " + MAX_TRIES + " frames to get screenshot but it's still not ready!");
+          }
+          activity.postDelayed(this, FRAME_DELAY_MS);
+          return;
+        }
+
+        bitmapHolder.bitmap = getActivity().getCurrentScreenshot();
+        latch.countDown();
+      }
+    };
+
+
+    getActivity().runOnUiThread(getScreenshotRunnable);
+    try {
+      if (!latch.await(5000, TimeUnit.MILLISECONDS)) {
+        throw new RuntimeException("Timed out waiting for screenshot runnable to run!");
+      }
+    } catch (InterruptedException e) {
+      throw new RuntimeException(e);
+    }
+    return Assertions.assertNotNull(bitmapHolder.bitmap);
+  }
+
+  /**
+   * Implement this method to provide application key to be launched. List of available
+   * application is located in TestBundle.js file
+   */
+  protected abstract String getReactApplicationKeyUnderTest();
+
+  protected boolean getEnableDevSupport() {
+    return false;
+  }
+
+  /**
+   * Override this method to provide extra native modules to be loaded before the app starts
+   */
+  protected ReactInstanceSpecForTest createReactInstanceSpecForTest() {
+    return new ReactInstanceSpecForTest();
+  }
+
+  protected ReactContext getReactContext() {
+    return getActivity().getReactContext();
+  }
+
+  /**
+   * Helper class to pass the bitmap between execution scopes in {@link #getScreenshot()}.
+   */
+  private static class BitmapHolder {
+
+    public @Nullable volatile Bitmap bitmap;
+  }
+}
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java
new file mode 100644
index 000000000000..734cdfd2cdd9
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java
@@ -0,0 +1,236 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.testing;
+
+import javax.annotation.Nullable;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.widget.FrameLayout;
+
+import com.facebook.infer.annotation.Assertions;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.LifecycleState;
+import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
+import com.facebook.react.ReactInstanceManager;
+import com.facebook.react.ReactPackage;
+import com.facebook.react.ReactRootView;
+import com.facebook.react.shell.MainReactPackage;
+
+
+public class ReactAppTestActivity extends FragmentActivity implements
+    DefaultHardwareBackBtnHandler
+{
+
+  private static final String DEFAULT_BUNDLE_NAME = "AndroidTestBundle.js";
+  private static final int ROOT_VIEW_ID = 8675309;
+  private static final long IDLE_TIMEOUT_MS = 15000;
+
+  private CountDownLatch mLayoutEvent = new CountDownLatch(1);
+  private @Nullable ReactBridgeIdleSignaler mBridgeIdleSignaler;
+  private ScreenshotingFrameLayout mScreenshotingFrameLayout;
+  private final CountDownLatch mDestroyCountDownLatch = new CountDownLatch(1);
+  private @Nullable ReactInstanceManager mReactInstanceManager;
+  private @Nullable ReactRootView mReactRootView;
+  private LifecycleState mLifecycleState = LifecycleState.BEFORE_RESUME;
+
+  @Override
+  protected void onCreate(Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+
+    overridePendingTransition(0, 0);
+
+    // We wrap screenshot layout in another FrameLayout in order to handle custom dimensions of the
+    // screenshot view set through {@link #setScreenshotDimensions}
+    FrameLayout rootView = new FrameLayout(this);
+    setContentView(rootView);
+
+    mScreenshotingFrameLayout = new ScreenshotingFrameLayout(this);
+    mScreenshotingFrameLayout.setId(ROOT_VIEW_ID);
+    rootView.addView(mScreenshotingFrameLayout);
+
+    mReactRootView = new ReactRootView(this);
+    mScreenshotingFrameLayout.addView(mReactRootView);
+  }
+
+  @Override
+  protected void onPause() {
+    super.onPause();
+
+    mLifecycleState = LifecycleState.BEFORE_RESUME;
+
+    overridePendingTransition(0, 0);
+
+    if (mReactInstanceManager != null) {
+      mReactInstanceManager.onPause();
+    }
+  }
+
+  @Override
+  protected void onResume() {
+    super.onResume();
+
+    mLifecycleState = LifecycleState.RESUMED;
+
+    if (mReactInstanceManager != null) {
+      mReactInstanceManager.onResume(this, this);
+    }
+  }
+
+  @Override
+  protected void onDestroy() {
+    super.onDestroy();
+    mDestroyCountDownLatch.countDown();
+
+    if (mReactInstanceManager != null) {
+      mReactInstanceManager.onDestroy();
+    }
+  }
+
+  public void waitForDestroy(long timeoutMs) throws InterruptedException {
+    mDestroyCountDownLatch.await(timeoutMs, TimeUnit.MILLISECONDS);
+  }
+
+  public void loadApp(String appKey, ReactInstanceSpecForTest spec, boolean enableDevSupport) {
+    loadApp(appKey, spec, null, DEFAULT_BUNDLE_NAME, enableDevSupport);
+  }
+
+  public void loadApp(String appKey, ReactInstanceSpecForTest spec, String bundleName) {
+    loadApp(appKey, spec, null, bundleName, false /* = useDevSupport */);
+  }
+
+  public void resetRootViewForScreenshotTests() {
+    if (mReactInstanceManager != null) {
+      mReactInstanceManager.onDestroy();
+      mReactInstanceManager = null;
+    }
+    mReactRootView = new ReactRootView(this);
+    mScreenshotingFrameLayout.removeAllViews();
+    mScreenshotingFrameLayout.addView(mReactRootView);
+  }
+
+  public void loadApp(
+      String appKey,
+      ReactInstanceSpecForTest spec,
+      @Nullable Bundle initialProps,
+      String bundleName,
+      boolean useDevSupport) {
+
+    final CountDownLatch currentLayoutEvent = mLayoutEvent = new CountDownLatch(1);
+    mBridgeIdleSignaler = new ReactBridgeIdleSignaler();
+
+    ReactInstanceManager.Builder builder = ReactInstanceManager.builder()
+        .setApplication(getApplication())
+        .setBundleAssetName(bundleName)
+        // By not setting a JS module name, we force the bundle to be always loaded from
+        // assets, not the devserver, even if dev mode is enabled (such as when testing redboxes).
+        // This makes sense because we never run the devserver in tests.
+        //.setJSMainModuleName()
+        .addPackage(spec.getAlternativeReactPackageForTest() != null ?
+            spec.getAlternativeReactPackageForTest() : new MainReactPackage())
+        .addPackage(new InstanceSpecForTestPackage(spec))
+        .setUseDeveloperSupport(useDevSupport)
+        .setBridgeIdleDebugListener(mBridgeIdleSignaler)
+        .setInitialLifecycleState(mLifecycleState);
+
+    mReactInstanceManager = builder.build();
+    mReactInstanceManager.onResume(this, this);
+
+    Assertions.assertNotNull(mReactRootView).getViewTreeObserver().addOnGlobalLayoutListener(
+        new ViewTreeObserver.OnGlobalLayoutListener() {
+          @Override
+          public void onGlobalLayout() {
+            currentLayoutEvent.countDown();
+          }
+        });
+    Assertions.assertNotNull(mReactRootView)
+        .startReactApplication(mReactInstanceManager, appKey, initialProps);
+  }
+
+  public boolean waitForLayout(long millis) throws InterruptedException {
+    return mLayoutEvent.await(millis, TimeUnit.MILLISECONDS);
+  }
+
+  public void waitForBridgeAndUIIdle() {
+    waitForBridgeAndUIIdle(IDLE_TIMEOUT_MS);
+  }
+
+  public void waitForBridgeAndUIIdle(long timeoutMs) {
+    ReactIdleDetectionUtil.waitForBridgeAndUIIdle(
+        Assertions.assertNotNull(mBridgeIdleSignaler),
+        getReactContext(),
+        timeoutMs);
+  }
+
+  public View getRootView() {
+    return Assertions.assertNotNull(mReactRootView);
+  }
+
+  public ReactContext getReactContext() {
+    return waitForReactContext();
+  }
+
+  // Because react context is created asynchronously, we may have to wait until it is available.
+  // It's simpler than exposing synchronosition mechanism to notify listener than react context
+  // creation has completed.
+  private ReactContext waitForReactContext() {
+    Assertions.assertNotNull(mReactInstanceManager);
+
+    try {
+      while (true) {
+        ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();
+        if (reactContext != null) {
+           return reactContext;
+        }
+        Thread.sleep(100);
+      }
+    } catch (InterruptedException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  public void postDelayed(Runnable r, int delayMS) {
+    getRootView().postDelayed(r, delayMS);
+  }
+
+  /**
+   * Does not ensure that this is run on the UI thread or that the UI Looper is idle like
+   * {@link ReactAppInstrumentationTestCase#getScreenshot()}. You probably want to use that
+   * instead.
+   */
+  public Bitmap getCurrentScreenshot() {
+    return mScreenshotingFrameLayout.getLastDrawnBitmap();
+  }
+
+  public boolean isScreenshotReady() {
+    return mScreenshotingFrameLayout.isScreenshotReady();
+  }
+
+  public void setScreenshotDimensions(int width, int height) {
+    mScreenshotingFrameLayout.setLayoutParams(new FrameLayout.LayoutParams(width, height));
+  }
+
+  @Override
+  public void invokeDefaultOnBackPressed() {
+    super.onBackPressed();
+  }
+
+  @Override
+  public void onRequestPermissionsResult(
+      int requestCode,
+      String[] permissions,
+      int[] grantResults) {
+  }
+}
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactBridgeIdleSignaler.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactBridgeIdleSignaler.java
new file mode 100644
index 000000000000..ffd941f9a228
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactBridgeIdleSignaler.java
@@ -0,0 +1,62 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.testing;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener;
+
+/**
+ * Utility class that uses {@link NotThreadSafeBridgeIdleDebugListener} interface to allow callers
+ * to wait for the bridge to be idle.
+ */
+public class ReactBridgeIdleSignaler implements NotThreadSafeBridgeIdleDebugListener {
+
+  // Starts at 1 since bridge starts idle. The logic here is that the semaphore is only acquirable
+  // if the bridge is idle.
+  private final Semaphore mBridgeIdleSemaphore = new Semaphore(1);
+
+  private volatile boolean mIsBridgeIdle = true;
+
+  @Override
+  public void onTransitionToBridgeIdle() {
+    mIsBridgeIdle = true;
+    mBridgeIdleSemaphore.release();
+  }
+
+  @Override
+  public void onTransitionToBridgeBusy() {
+    mIsBridgeIdle = false;
+    try {
+      if (!mBridgeIdleSemaphore.tryAcquire(15000, TimeUnit.MILLISECONDS)) {
+        throw new RuntimeException(
+            "Timed out waiting to acquire the test idle listener semaphore. Deadlock?");
+      }
+    } catch (InterruptedException e) {
+      throw new RuntimeException("Got interrupted", e);
+    }
+  }
+
+  public boolean isBridgeIdle() {
+    return mIsBridgeIdle;
+  }
+
+  public boolean waitForIdle(long millis) {
+    try {
+      if (mBridgeIdleSemaphore.tryAcquire(millis, TimeUnit.MILLISECONDS)) {
+        mBridgeIdleSemaphore.release();
+        return true;
+      }
+      return false;
+    } catch (InterruptedException e) {
+      throw new RuntimeException("Got interrupted", e);
+    }
+  }
+}
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIdleDetectionUtil.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIdleDetectionUtil.java
new file mode 100644
index 000000000000..bd09d2133530
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIdleDetectionUtil.java
@@ -0,0 +1,125 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.testing;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import android.app.Instrumentation;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.view.Choreographer;
+
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.UiThreadUtil;
+
+public class ReactIdleDetectionUtil {
+
+  /**
+   * Waits for both the UI thread and bridge to be idle. It determines this by waiting for the
+   * bridge to become idle, then waiting for the UI thread to become idle, then checking if the
+   * bridge is idle again (if the bridge was idle before and is still idle after running the UI
+   * thread to idle, then there are no more events to process in either place).
+   * <p/>
+   * Also waits for any Choreographer callbacks to run after the initial sync since things like UI
+   * events are initiated from Choreographer callbacks.
+   */
+  public static void waitForBridgeAndUIIdle(
+      ReactBridgeIdleSignaler idleSignaler,
+      final ReactContext reactContext,
+      long timeoutMs) {
+    UiThreadUtil.assertNotOnUiThread();
+
+    long startTime = SystemClock.elapsedRealtime();
+    waitInner(idleSignaler, timeoutMs);
+
+    long timeToWait = Math.max(1, timeoutMs - (SystemClock.elapsedRealtime() - startTime));
+    waitForChoreographer(timeToWait);
+    waitForJSIdle(reactContext);
+
+    timeToWait = Math.max(1, timeoutMs - (SystemClock.elapsedRealtime() - startTime));
+    waitInner(idleSignaler, timeToWait);
+    timeToWait = Math.max(1, timeoutMs - (SystemClock.elapsedRealtime() - startTime));
+    waitForChoreographer(timeToWait);
+  }
+
+  private static void waitForChoreographer(long timeToWait) {
+    final int waitFrameCount = 2;
+    final CountDownLatch latch = new CountDownLatch(1);
+    UiThreadUtil.runOnUiThread(
+        new Runnable() {
+          @Override
+          public void run() {
+            Choreographer.getInstance().postFrameCallback(
+                new Choreographer.FrameCallback() {
+
+                  private int frameCount = 0;
+
+                  @Override
+                  public void doFrame(long frameTimeNanos) {
+                    frameCount++;
+                    if (frameCount == waitFrameCount) {
+                      latch.countDown();
+                    } else {
+                      Choreographer.getInstance().postFrameCallback(this);
+                    }
+                  }
+                });
+          }
+        });
+    try {
+      if (!latch.await(timeToWait, TimeUnit.MILLISECONDS)) {
+        throw new RuntimeException("Timed out waiting for Choreographer");
+      }
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  private static void waitForJSIdle(ReactContext reactContext) {
+    if (!reactContext.hasActiveCatalystInstance()) {
+      return;
+    }
+    final CountDownLatch latch = new CountDownLatch(1);
+
+    reactContext.runOnJSQueueThread(
+        new Runnable() {
+          @Override
+          public void run() {
+            latch.countDown();
+          }
+        });
+
+    try {
+      if (!latch.await(5000, TimeUnit.MILLISECONDS)) {
+        throw new RuntimeException("Timed out waiting for JS thread");
+      }
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  private static void waitInner(ReactBridgeIdleSignaler idleSignaler, long timeToWait) {
+    // TODO gets broken in gradle, do we need it?
+    Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+    long startTime = SystemClock.elapsedRealtime();
+    boolean bridgeWasIdle = false;
+    while (SystemClock.elapsedRealtime() - startTime < timeToWait) {
+      boolean bridgeIsIdle = idleSignaler.isBridgeIdle();
+      if (bridgeIsIdle && bridgeWasIdle) {
+        return;
+      }
+      bridgeWasIdle = bridgeIsIdle;
+      long newTimeToWait = Math.max(1, timeToWait - (SystemClock.elapsedRealtime() - startTime));
+      idleSignaler.waitForIdle(newTimeToWait);
+      instrumentation.waitForIdleSync();
+    }
+    throw new RuntimeException("Timed out waiting for bridge and UI idle!");
+  }
+}
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstanceSpecForTest.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstanceSpecForTest.java
new file mode 100644
index 000000000000..b9de7a1e7726
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstanceSpecForTest.java
@@ -0,0 +1,69 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.testing;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.annotation.SuppressLint;
+
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.JavaScriptModule;
+import com.facebook.react.uimanager.ViewManager;
+import com.facebook.react.ReactPackage;
+
+/**
+ * A spec that allows a test to add additional NativeModules/JS modules to the ReactInstance. This
+ * can also be used to stub out existing native modules by adding another module with the same name
+ * as a built-in module.
+ */
+@SuppressLint("JavatestsIncorrectFolder")
+public class ReactInstanceSpecForTest {
+
+  private final List<NativeModule> mNativeModules = new ArrayList<>();
+  private final List<Class<? extends JavaScriptModule>> mJSModuleSpecs = new ArrayList<>();
+  private final List<ViewManager> mViewManagers = new ArrayList<>();
+  private ReactPackage mReactPackage = null;
+
+  public ReactInstanceSpecForTest addNativeModule(NativeModule module) {
+    mNativeModules.add(module);
+    return this;
+  }
+
+  public ReactInstanceSpecForTest addJSModule(Class jsClass) {
+    mJSModuleSpecs.add(jsClass);
+    return this;
+  }
+
+  public ReactInstanceSpecForTest setPackage(ReactPackage reactPackage) {
+    mReactPackage = reactPackage;
+    return this;
+  }
+
+  public ReactInstanceSpecForTest addViewManager(ViewManager viewManager) {
+    mViewManagers.add(viewManager);
+    return this;
+  }
+
+  public List<NativeModule> getExtraNativeModulesForTest() {
+    return mNativeModules;
+  }
+
+  public List<Class<? extends JavaScriptModule>> getExtraJSModulesForTest() {
+    return mJSModuleSpecs;
+  }
+
+  public ReactPackage getAlternativeReactPackageForTest() {
+    return mReactPackage;
+  }
+
+  public List<ViewManager> getExtraViewManagers() {
+    return mViewManagers;
+  }
+}
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java
new file mode 100644
index 000000000000..e70a8428bbfe
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java
@@ -0,0 +1,212 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.testing;
+
+import javax.annotation.Nullable;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import android.support.test.InstrumentationRegistry;
+import android.test.AndroidTestCase;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.facebook.infer.annotation.Assertions;
+import com.facebook.react.bridge.BaseJavaModule;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.CatalystInstanceImpl;
+import com.facebook.react.bridge.LifecycleEventListener;
+import com.facebook.react.bridge.SoftAssertions;
+import com.facebook.react.bridge.UiThreadUtil;
+import com.facebook.react.common.futures.SimpleSettableFuture;
+import com.facebook.react.modules.core.Timing;
+
+/**
+ * Use this class for writing integration tests of catalyst. This class will run all JNI call
+ * within separate android looper, thus you don't need to care about starting your own looper.
+ *
+ * Keep in mind that all JS remote method calls and script load calls are asynchronous and you
+ * should not expect them to return results immediately.
+ *
+ * In order to write catalyst integration:
+ *  1) Make {@link ReactIntegrationTestCase} a base class of your test case
+ *  2) Use {@link ReactIntegrationTestCase.ReactTestInstanceBuilder}
+ *  instead of {@link com.facebook.react.bridge.CatalystInstanceImpl.Builder} to build catalyst
+ *  instance for testing purposes
+ *
+ */
+public abstract class ReactIntegrationTestCase extends AndroidTestCase {
+
+  private static final long SETUP_TIMEOUT_MS = 5000;
+  private static final long IDLE_TIMEOUT_MS = 15000;
+
+  private @Nullable CatalystInstanceImpl mInstance;
+  private @Nullable ReactBridgeIdleSignaler mBridgeIdleSignaler;
+  private @Nullable ReactApplicationContext mReactContext;
+
+  @Override
+  public ReactApplicationContext getContext() {
+    if (mReactContext == null) {
+      mReactContext = new ReactApplicationContext(super.getContext());
+      Assertions.assertNotNull(mReactContext);
+    }
+
+    return mReactContext;
+  }
+
+  public void shutDownContext() {
+    if (mInstance != null) {
+      final ReactContext contextToDestroy = mReactContext;
+      mReactContext = null;
+      mInstance = null;
+
+      UiThreadUtil.runOnUiThread(new Runnable() {
+        @Override
+        public void run() {
+          if (contextToDestroy != null) {
+            contextToDestroy.onDestroy();
+          }
+        }
+      });
+    }
+  }
+
+  /**
+   * This method isn't safe since it doesn't factor in layout-only view removal. Use
+   * {@link #getViewByTestId} instead.
+   */
+  @Deprecated
+  public <T extends View> T getViewAtPath(ViewGroup rootView, int... path) {
+    return ReactTestHelper.getViewAtPath(rootView, path);
+  }
+
+  public <T extends View> T getViewByTestId(ViewGroup rootView, String testID) {
+    return (T) ReactTestHelper.getViewWithReactTestId(rootView, testID);
+  }
+
+  public static class Event {
+    private final CountDownLatch mLatch;
+
+    public Event() {
+      this(1);
+    }
+
+    public Event(int counter) {
+      mLatch = new CountDownLatch(counter);
+    }
+
+    public void occur() {
+      mLatch.countDown();
+    }
+
+    public boolean didOccur() {
+      return mLatch.getCount() == 0;
+    }
+
+    public boolean await(long millis) {
+      try {
+        return mLatch.await(millis, TimeUnit.MILLISECONDS);
+      } catch (InterruptedException ignore) {
+        return false;
+      }
+    }
+  }
+
+  /**
+   * Timing module needs to be created on the main thread so that it gets the correct Choreographer.
+   */
+  protected Timing createTimingModule() {
+    final SimpleSettableFuture<Timing> simpleSettableFuture = new SimpleSettableFuture<Timing>();
+    UiThreadUtil.runOnUiThread(
+        new Runnable() {
+          @Override
+          public void run() {
+            Timing timing = new Timing(getContext());
+            simpleSettableFuture.set(timing);
+          }
+        });
+    try {
+      return simpleSettableFuture.get(5000, TimeUnit.MILLISECONDS);
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  public class ReactTestInstanceBuilder extends CatalystInstanceImpl.Builder {
+
+    @Override
+    public CatalystInstanceImpl build() {
+      // Call build in separate looper and wait for it to finish before returning
+      final Event setupEvent = new Event();
+      UiThreadUtil.runOnUiThread(
+          new Runnable() {
+            @Override
+            public void run() {
+              mInstance = ReactTestInstanceBuilder.super.build();
+              mBridgeIdleSignaler = new ReactBridgeIdleSignaler();
+              mInstance.addBridgeIdleDebugListener(mBridgeIdleSignaler);
+              getContext().initializeWithInstance(mInstance);
+              setupEvent.occur();
+            }
+          });
+
+      if (!setupEvent.await(SETUP_TIMEOUT_MS)) {
+        throw new RuntimeException(
+            "Instance setup should take less than " + SETUP_TIMEOUT_MS + "ms");
+      }
+      return mInstance;
+    }
+  }
+
+  public boolean waitForBridgeIdle(long millis) {
+    return Assertions.assertNotNull(mBridgeIdleSignaler).waitForIdle(millis);
+  }
+
+  public void waitForIdleSync() {
+    InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+  }
+
+  public void waitForBridgeAndUIIdle() {
+    ReactIdleDetectionUtil.waitForBridgeAndUIIdle(
+        Assertions.assertNotNull(mBridgeIdleSignaler),
+        getContext(),
+        IDLE_TIMEOUT_MS);
+  }
+
+  @Override
+  protected void tearDown() throws Exception {
+    super.tearDown();
+    shutDownContext();
+  }
+
+  protected static void initializeJavaModule(final BaseJavaModule javaModule) {
+    final Semaphore semaphore = new Semaphore(0);
+    UiThreadUtil.runOnUiThread(
+        new Runnable() {
+          @Override
+          public void run() {
+            javaModule.initialize();
+            if (javaModule instanceof LifecycleEventListener) {
+              ((LifecycleEventListener) javaModule).onHostResume();
+            }
+            semaphore.release();
+          }
+        });
+    try {
+      SoftAssertions.assertCondition(
+          semaphore.tryAcquire(5000, TimeUnit.MILLISECONDS),
+          "Timed out initializing timing module");
+    } catch (InterruptedException e) {
+      throw new RuntimeException(e);
+    }
+  }
+}
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactSettingsForTests.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactSettingsForTests.java
new file mode 100644
index 000000000000..2b6ae8057215
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactSettingsForTests.java
@@ -0,0 +1,32 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.testing;
+
+import com.facebook.react.modules.debug.DeveloperSettings;
+
+/**
+ * Default ReactSettings for tests.
+ */
+public class ReactSettingsForTests implements DeveloperSettings {
+
+  @Override
+  public boolean isFpsDebugEnabled() {
+    return false;
+  }
+
+  @Override
+  public boolean isAnimationFpsDebugEnabled() {
+    return false;
+  }
+
+  @Override
+  public boolean isJSDevModeEnabled() {
+    return true;
+  }
+}
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java
new file mode 100644
index 000000000000..5b9949ade916
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java
@@ -0,0 +1,129 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.testing;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.facebook.react.bridge.CatalystInstanceImpl;
+import com.facebook.react.bridge.JSBundleLoader;
+import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
+import com.facebook.react.bridge.JSCJavaScriptExecutor;
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.NativeModuleRegistry;
+import com.facebook.react.bridge.JavaScriptModulesConfig;
+import com.facebook.react.bridge.queue.CatalystQueueConfigurationSpec;
+
+import com.android.internal.util.Predicate;
+
+public class ReactTestHelper {
+
+  public static class ReactInstanceEasyBuilder {
+
+    private final ReactIntegrationTestCase mTestCase;
+    private final NativeModuleRegistry.Builder mNativeModuleRegistryBuilder;
+    private final JavaScriptModulesConfig.Builder mJSModulesConfigBuilder;
+
+    private ReactInstanceEasyBuilder(ReactIntegrationTestCase testCase) {
+      mTestCase = testCase;
+      mNativeModuleRegistryBuilder = new NativeModuleRegistry.Builder();
+      mJSModulesConfigBuilder = new JavaScriptModulesConfig.Builder();
+    }
+
+    public CatalystInstanceImpl build() {
+      CatalystInstanceImpl instance = mTestCase.new ReactTestInstanceBuilder()
+          .setCatalystQueueConfigurationSpec(CatalystQueueConfigurationSpec.createDefault())
+          .setJSExecutor(new JSCJavaScriptExecutor())
+          .setRegistry(mNativeModuleRegistryBuilder.build())
+          .setJSModulesConfig(mJSModulesConfigBuilder.build())
+          .setJSBundleLoader(JSBundleLoader.createFileLoader(
+                  mTestCase.getContext(),
+                  "assets://AndroidTestBundle.js"))
+          .setNativeModuleCallExceptionHandler(
+              new NativeModuleCallExceptionHandler() {
+                @Override
+                public void handleException(Exception e) {
+                  throw new RuntimeException(e);
+                }
+              })
+          .build();
+      instance.runJSBundle();
+      mTestCase.waitForBridgeAndUIIdle();
+      return instance;
+    }
+
+    public ReactInstanceEasyBuilder addNativeModule(NativeModule module) {
+      mNativeModuleRegistryBuilder.add(module);
+      return this;
+    }
+
+    public ReactInstanceEasyBuilder addJSModule(Class moduleInterfaceClass) {
+      mJSModulesConfigBuilder.add(moduleInterfaceClass);
+      return this;
+    }
+  }
+
+  public static ReactInstanceEasyBuilder catalystInstanceBuilder(
+      ReactIntegrationTestCase testCase) {
+    return new ReactInstanceEasyBuilder(testCase);
+  }
+
+  /**
+   * Gets the view at given path in the UI hierarchy, ignoring modals.
+   */
+  public static <T extends View> T getViewAtPath(ViewGroup rootView, int... path) {
+    // The application root element is wrapped in a helper view in order
+    // to be able to display modals. See renderApplication.js.
+    ViewGroup appWrapperView = rootView;
+    View view = appWrapperView.getChildAt(0);
+    for (int i = 0; i < path.length; i++) {
+      view = ((ViewGroup) view).getChildAt(path[i]);
+    }
+    return (T) view;
+  }
+
+  /**
+   * Gets the view with a given react test ID in the UI hierarchy. React test ID is currently
+   * propagated into view content description.
+   */
+  public static View getViewWithReactTestId(View rootView, String testId) {
+    return findChild(rootView, hasTagValue(testId));
+  }
+
+  public static String getTestId(View view) {
+    return view.getTag() instanceof String ? (String) view.getTag() : null;
+  }
+
+  private static View findChild(View root, Predicate<View> predicate) {
+    if (predicate.apply(root)) {
+      return root;
+    }
+    if (root instanceof ViewGroup) {
+      ViewGroup viewGroup = (ViewGroup) root;
+      for (int i = 0; i < viewGroup.getChildCount(); i++) {
+        View child = viewGroup.getChildAt(i);
+        View result = findChild(child, predicate);
+        if (result != null) {
+          return result;
+        }
+      }
+    }
+    return null;
+  }
+
+  private static Predicate<View> hasTagValue(final String tagValue) {
+    return new Predicate<View>() {
+      @Override
+      public boolean apply(View view) {
+        Object tag = view.getTag();
+        return tag != null && tag.equals(tagValue);
+      }
+    };
+  }
+}
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ScreenshotingFrameLayout.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ScreenshotingFrameLayout.java
new file mode 100644
index 000000000000..ffc648e79157
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ScreenshotingFrameLayout.java
@@ -0,0 +1,71 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.testing;
+
+import javax.annotation.Nullable;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.os.Looper;
+import android.widget.FrameLayout;
+
+/**
+ * A FrameLayout that allows you to access the result of the last time its hierarchy was drawn. It
+ * accomplishes this by drawing its hierarchy into a software Canvas, saving the resulting Bitmap
+ * and then drawing that Bitmap to the actual Canvas provided by the system.
+ */
+public class ScreenshotingFrameLayout extends FrameLayout {
+
+  private @Nullable Bitmap mBitmap;
+  private Canvas mCanvas;
+
+  public ScreenshotingFrameLayout(Context context) {
+    super(context);
+    mCanvas = new Canvas();
+  }
+
+  @Override
+  protected void dispatchDraw(Canvas canvas) {
+    if (mBitmap == null) {
+      mBitmap = createNewBitmap(canvas);
+      mCanvas.setBitmap(mBitmap);
+    } else if (mBitmap.getWidth() != canvas.getWidth() ||
+        mBitmap.getHeight() != canvas.getHeight()) {
+      mBitmap.recycle();
+      mBitmap = createNewBitmap(canvas);
+      mCanvas.setBitmap(mBitmap);
+    }
+
+    super.dispatchDraw(mCanvas);
+    canvas.drawBitmap(mBitmap, 0, 0, null);
+  }
+
+  private static Bitmap createNewBitmap(Canvas canvas) {
+    return Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
+  }
+
+  public Bitmap getLastDrawnBitmap() {
+    if (mBitmap == null) {
+      throw new RuntimeException("View has not been drawn yet!");
+    }
+    if (Looper.getMainLooper() != Looper.myLooper()) {
+      throw new RuntimeException(
+          "Must access screenshots from main thread or you may get partially drawn Bitmaps");
+    }
+    if (!isScreenshotReady()) {
+      throw new RuntimeException("Trying to get screenshot, but the view is dirty or needs layout");
+    }
+    return Bitmap.createBitmap(mBitmap);
+  }
+
+  public boolean isScreenshotReady() {
+    return !isDirty() && !isLayoutRequested();
+  }
+}
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/SingleTouchGestureGenerator.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/SingleTouchGestureGenerator.java
new file mode 100644
index 000000000000..278facbcb280
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/SingleTouchGestureGenerator.java
@@ -0,0 +1,161 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.testing;
+
+import android.os.SystemClock;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+
+/**
+ * Provides methods for generating touch events and dispatching them directly to a given view.
+ * Events scenarios are based on {@link android.test.TouchUtils} but they get gets dispatched
+ * directly through the view hierarchy using {@link View#dispatchTouchEvent} method instead of
+ * using instrumentation API.
+ * <p>
+ * All the events for a gesture are dispatched immediately which makes tests run very fast.
+ * The eventTime for each event is still set correctly. Android's gesture recognizers check
+ * eventTime in order to figure out gesture speed, and therefore scroll vs fling is recognized.
+ */
+public class SingleTouchGestureGenerator {
+
+  private static final long DEFAULT_DELAY_MS = 20;
+
+  private View mDispatcherView;
+  private IdleWaiter mIdleWaiter;
+  private long mLastDownTime;
+  private long mEventTime;
+  private float mLastX;
+  private float mLastY;
+
+  private ViewConfiguration mViewConfig;
+
+  public SingleTouchGestureGenerator(View view, IdleWaiter idleWaiter) {
+    mDispatcherView = view;
+    mIdleWaiter = idleWaiter;
+    mViewConfig = ViewConfiguration.get(view.getContext());
+  }
+
+  private SingleTouchGestureGenerator dispatchEvent(
+      final int action,
+      final float x,
+      final float y,
+      long eventTime) {
+    mEventTime = eventTime;
+    if (action == MotionEvent.ACTION_DOWN) {
+      mLastDownTime = eventTime;
+    }
+    mLastX = x;
+    mLastY = y;
+    mDispatcherView.post(
+        new Runnable() {
+          @Override
+          public void run() {
+            MotionEvent event = MotionEvent.obtain(mLastDownTime, mEventTime, action, x, y, 0);
+            mDispatcherView.dispatchTouchEvent(event);
+            event.recycle();
+          }
+        });
+    mIdleWaiter.waitForBridgeAndUIIdle();
+    return this;
+  }
+
+  private float getViewCenterX(View view) {
+    int[] xy = new int[2];
+    view.getLocationOnScreen(xy);
+    int viewWidth = view.getWidth();
+    return xy[0] + (viewWidth / 2.0f);
+  }
+
+  private float getViewCenterY(View view) {
+    int[] xy = new int[2];
+    view.getLocationOnScreen(xy);
+    int viewHeight = view.getHeight();
+    return xy[1] + (viewHeight / 2.0f);
+  }
+
+  public SingleTouchGestureGenerator startGesture(float x, float y) {
+    return dispatchEvent(MotionEvent.ACTION_DOWN, x, y, SystemClock.uptimeMillis());
+  }
+
+  public SingleTouchGestureGenerator startGesture(View view) {
+    return startGesture(getViewCenterX(view), getViewCenterY(view));
+  }
+
+  private SingleTouchGestureGenerator dispatchDelayedEvent(
+      int action,
+      float x,
+      float y,
+      long delay) {
+    return dispatchEvent(action, x, y, mEventTime + delay);
+  }
+
+  public SingleTouchGestureGenerator endGesture(float x, float y, long delay) {
+    return dispatchDelayedEvent(MotionEvent.ACTION_UP, x, y, delay);
+  }
+
+  public SingleTouchGestureGenerator endGesture(float x, float y) {
+    return endGesture(x, y, DEFAULT_DELAY_MS);
+  }
+
+  public SingleTouchGestureGenerator endGesture() {
+    return endGesture(mLastX, mLastY);
+  }
+
+  public SingleTouchGestureGenerator moveGesture(float x, float y, long delay) {
+    return dispatchDelayedEvent(MotionEvent.ACTION_MOVE, x, y, delay);
+  }
+
+  public SingleTouchGestureGenerator moveBy(float dx, float dy, long delay) {
+    return moveGesture(mLastX + dx, mLastY + dy, delay);
+  }
+
+  public SingleTouchGestureGenerator moveBy(float dx, float dy) {
+    return moveBy(dx, dy, DEFAULT_DELAY_MS);
+  }
+
+  public SingleTouchGestureGenerator clickViewAt(float x, float y) {
+    float touchSlop = mViewConfig.getScaledTouchSlop();
+    return startGesture(x, y).moveBy(touchSlop / 2.0f, touchSlop / 2.0f).endGesture();
+  }
+
+  public SingleTouchGestureGenerator drag(
+      float fromX,
+      float fromY,
+      float toX,
+      float toY,
+      int stepCount,
+      long totalDelay) {
+
+    float xStep = (toX - fromX) / stepCount;
+    float yStep = (toY - fromY) / stepCount;
+
+    float x = fromX;
+    float y = fromY;
+
+    for (int i = 0; i < stepCount; i++) {
+      x += xStep;
+      y += yStep;
+      moveGesture(x, y, totalDelay / stepCount);
+    }
+    return this;
+  }
+
+  public SingleTouchGestureGenerator dragTo(float toX, float toY, int stepCount, long totalDelay) {
+    return drag(mLastX, mLastY, toX, toY, stepCount, totalDelay);
+  }
+
+  public SingleTouchGestureGenerator dragTo(View view, int stepCount, long totalDelay) {
+    return dragTo(getViewCenterX(view), getViewCenterY(view), stepCount, totalDelay);
+  }
+
+  public SingleTouchGestureGenerator dragTo(View view, int stepCount) {
+    return dragTo(view, stepCount, stepCount * DEFAULT_DELAY_MS);
+  }
+}
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/StringRecordingModule.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/StringRecordingModule.java
new file mode 100644
index 000000000000..8caa3b8f7117
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/StringRecordingModule.java
@@ -0,0 +1,42 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.testing;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.facebook.react.bridge.BaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+
+/**
+ * Native module provides single method {@link #record} which records its single string argument
+ * in calls array
+ */
+public class StringRecordingModule extends BaseJavaModule {
+
+  private final List<String> mCalls = new ArrayList<String>();
+
+  @Override
+  public String getName() {
+    return "Recording";
+  }
+
+  @ReactMethod
+  public void record(String text) {
+    mCalls.add(text);
+  }
+
+  public void reset() {
+    mCalls.clear();
+  }
+
+  public List<String> getCalls() {
+    return mCalls;
+  }
+}
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/ReactHorizontalScrollViewTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/ReactHorizontalScrollViewTestCase.java
new file mode 100644
index 000000000000..963442d47062
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/ReactHorizontalScrollViewTestCase.java
@@ -0,0 +1,134 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.tests;
+
+import java.util.ArrayList;
+
+import android.view.View;
+import android.widget.HorizontalScrollView;
+
+import com.facebook.react.testing.AbstractScrollViewTestCase;
+import com.facebook.react.testing.SingleTouchGestureGenerator;
+import com.facebook.react.uimanager.PixelUtil;
+
+/**
+ * Integration test for horizontal ScrollView.
+ * See ScrollViewTestModule.js
+ */
+public class ReactHorizontalScrollViewTestCase extends AbstractScrollViewTestCase {
+
+  @Override
+  protected String getReactApplicationKeyUnderTest() {
+    return "HorizontalScrollViewTestApp";
+  }
+
+  private void dragLeft() {
+    dragLeft(200);
+  }
+
+  private void dragLeft(int durationMs) {
+    createGestureGenerator()
+        .startGesture(150, 50)
+        .dragTo(50, 60, 10, durationMs)
+        .endGesture(50, 60);
+  }
+
+  public void testScrolling() {
+    HorizontalScrollView scrollView = getViewAtPath(0);
+    assertNotNull(scrollView);
+    assertEquals(0, scrollView.getScrollX());
+
+    dragLeft();
+
+    assertTrue("Expected to scroll by at least 50 pixels", scrollView.getScrollX() >= 50);
+  }
+
+  public void testScrollEvents() {
+    HorizontalScrollView scrollView = getViewAtPath(0);
+
+    dragLeft();
+
+    waitForBridgeAndUIIdle();
+    mScrollListenerModule.waitForScrollIdle();
+    waitForBridgeAndUIIdle();
+
+    ArrayList<Double> xOffsets = mScrollListenerModule.getXOffsets();
+    assertFalse("Expected to receive at least one scroll event", xOffsets.isEmpty());
+    assertTrue("Expected offset to be greater than 0", xOffsets.get(xOffsets.size() - 1) > 0);
+    assertTrue(
+        "Expected no item click event fired",
+        mScrollListenerModule.getItemsPressed().isEmpty());
+    assertEquals(
+        "Expected last offset to be offset of scroll view",
+        PixelUtil.toDIPFromPixel(scrollView.getScrollX()),
+        xOffsets.get(xOffsets.size() - 1).doubleValue(),
+        1e-5);
+  }
+
+  public void testScrollAndClick() throws Exception {
+    SingleTouchGestureGenerator gestureGenerator = createGestureGenerator();
+
+    // Slowly drag the ScrollView to prevent fling
+    dragLeft(15000);
+
+    waitForBridgeAndUIIdle();
+    getInstrumentation().waitForIdleSync();
+
+    // Find visible item to be clicked
+    View visibleItem = null;
+    int visibleItemNumber = 0;
+    for (; visibleItemNumber < 100; visibleItemNumber++) {
+      visibleItem = getViewAtPath(0, 0, visibleItemNumber);
+      int pos[] = new int[2];
+      visibleItem.getLocationInWindow(pos);
+      if (pos[0] >= 0) {
+        break;
+      }
+    }
+
+    // Click first visible item
+    gestureGenerator.startGesture(visibleItem).endGesture();
+    waitForBridgeAndUIIdle();
+
+    ArrayList<Double> xOffsets = mScrollListenerModule.getXOffsets();
+    ArrayList<Integer> itemIds = mScrollListenerModule.getItemsPressed();
+    assertFalse("Expected to receive at least one scroll event", xOffsets.isEmpty());
+    assertTrue("Expected offset to be greater than 0", xOffsets.get(xOffsets.size() - 1) > 0);
+    assertEquals("Expected to receive exactly one item click event", 1, itemIds.size());
+    assertEquals(visibleItemNumber, (int) itemIds.get(0));
+  }
+
+  /**
+   * Verify that 'scrollTo' command makes ScrollView start scrolling
+   */
+  public void testScrollToCommand() throws Exception {
+    HorizontalScrollView scrollView = getViewAtPath(0);
+    ScrollViewTestModule jsModule =
+        getReactContext().getCatalystInstance().getJSModule(ScrollViewTestModule.class);
+
+    assertEquals(0, scrollView.getScrollX());
+
+    jsModule.scrollTo(300, 0);
+    waitForBridgeAndUIIdle();
+    getInstrumentation().waitForIdleSync();
+
+    // Unfortunately we need to use timeouts here in order to wait for scroll animation to happen
+    // there is no better way (yet) for waiting for scroll animation to finish
+    long timeout = 10000;
+    long interval = 50;
+    long start = System.currentTimeMillis();
+    while (System.currentTimeMillis() - start < timeout) {
+      if (scrollView.getScrollX() > 0) {
+        break;
+      }
+      Thread.sleep(interval);
+    }
+    assertNotSame(0, scrollView.getScrollX());
+  }
+}
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/ReactScrollViewTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/ReactScrollViewTestCase.java
new file mode 100644
index 000000000000..45a47a67383e
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/ReactScrollViewTestCase.java
@@ -0,0 +1,136 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.tests;
+
+import java.util.ArrayList;
+
+import android.view.View;
+import android.widget.ScrollView;
+
+import com.facebook.react.testing.AbstractScrollViewTestCase;
+import com.facebook.react.testing.SingleTouchGestureGenerator;
+import com.facebook.react.uimanager.PixelUtil;
+
+/**
+ * Integration test for vertical ScrollView.
+ * See ScrollViewTestModule.js
+ */
+public class ReactScrollViewTestCase extends AbstractScrollViewTestCase {
+
+  @Override
+  protected String getReactApplicationKeyUnderTest() {
+    return "ScrollViewTestApp";
+  }
+
+  private void dragUp() {
+    dragUp(200);
+  }
+
+  private void dragUp(int durationMs) {
+    createGestureGenerator()
+        .startGesture(200, 200)
+        .dragTo(180, 100, 10, durationMs)
+        .endGesture(180, 100);
+  }
+
+  public void testScrolling() {
+    ScrollView scrollView = getViewAtPath(0);
+    assertNotNull(scrollView);
+    assertEquals(0, scrollView.getScrollY());
+
+    dragUp();
+
+    assertTrue("Expected to scroll by at least 50 pixels", scrollView.getScrollY() >= 50);
+  }
+
+  public void testScrollEvents() {
+    ScrollView scrollView = getViewAtPath(0);
+
+    dragUp();
+
+    waitForBridgeAndUIIdle();
+    mScrollListenerModule.waitForScrollIdle();
+    waitForBridgeAndUIIdle();
+
+    ArrayList<Double> yOffsets = mScrollListenerModule.getYOffsets();
+    assertFalse("Expected to receive at least one scroll event", yOffsets.isEmpty());
+    assertTrue("Expected offset to be greater than 0", yOffsets.get(yOffsets.size() - 1) > 0);
+    assertTrue(
+        "Expected no item click event fired",
+        mScrollListenerModule.getItemsPressed().isEmpty());
+    assertEquals(
+        "Expected last offset to be offset of scroll view",
+        PixelUtil.toDIPFromPixel(scrollView.getScrollY()),
+        yOffsets.get(yOffsets.size() - 1).doubleValue(),
+        1e-5);
+    assertTrue("Begin and End Drag should be called", mScrollListenerModule.dragEventsMatch());
+  }
+
+  public void testScrollAndClick() throws Exception {
+    SingleTouchGestureGenerator gestureGenerator = createGestureGenerator();
+
+    // Slowly drag the ScrollView to prevent fling
+    dragUp(15000);
+
+    waitForBridgeAndUIIdle();
+    getInstrumentation().waitForIdleSync();
+
+    // Find visible item to be clicked
+    View visibleItem = null;
+    int visibleItemNumber = 0;
+    for (; visibleItemNumber < 100; visibleItemNumber++) {
+      visibleItem = getViewAtPath(0, 0, visibleItemNumber);
+      int pos[] = new int[2];
+      visibleItem.getLocationInWindow(pos);
+      if (pos[1] >= 0) {
+        break;
+      }
+    }
+
+    // Click first visible item
+    gestureGenerator.startGesture(visibleItem).endGesture();
+    waitForBridgeAndUIIdle();
+
+    ArrayList<Double> yOffsets = mScrollListenerModule.getYOffsets();
+    ArrayList<Integer> itemIds = mScrollListenerModule.getItemsPressed();
+    assertFalse("Expected to receive at least one scroll event", yOffsets.isEmpty());
+    assertTrue("Expected offset to be greater than 0", yOffsets.get(yOffsets.size() - 1) > 0);
+    assertEquals("Expected to receive exactly one item click event", 1, itemIds.size());
+    assertEquals(visibleItemNumber, (int) itemIds.get(0));
+  }
+
+  /**
+   * Verify that 'scrollTo' command makes ScrollView start scrolling
+   */
+  public void testScrollToCommand() throws Exception {
+    ScrollView scrollView = getViewAtPath(0);
+    ScrollViewTestModule jsModule =
+        getReactContext().getCatalystInstance().getJSModule(ScrollViewTestModule.class);
+
+    assertEquals(0, scrollView.getScrollY());
+
+    jsModule.scrollTo(0, 300);
+    waitForBridgeAndUIIdle();
+    getInstrumentation().waitForIdleSync();
+
+    // Unfortunately we need to use timeouts here in order to wait for scroll animation to happen
+    // there is no better way (yet) for waiting for scroll animation to finish
+    long timeout = 10000;
+    long interval = 50;
+    long start = System.currentTimeMillis();
+    while (System.currentTimeMillis() - start < timeout) {
+      if (scrollView.getScrollY() > 0) {
+        break;
+      }
+      Thread.sleep(interval);
+    }
+    assertNotSame(0, scrollView.getScrollY());
+    assertFalse("Drag should not be called with scrollTo", mScrollListenerModule.dragEventsMatch());
+  }
+}
diff --git a/circle.yml b/circle.yml
index 51feb2c00a29..ff3c01145ede 100644
--- a/circle.yml
+++ b/circle.yml
@@ -9,4 +9,8 @@ dependencies:
 test:
   override:
     # gradle is flaky in CI envs, found a solution here http://stackoverflow.com/questions/28409608/gradle-assembledebug-and-predexdebug-fail-with-circleci
-    - TERM=dumb ./gradlew cleanTest test -PpreDexEnable=false -Pcom.android.build.threadPoolSize=1 -Dorg.gradle.parallel=false -Dorg.gradle.jvmargs="-Xms512m -Xmx512m" -Dorg.gradle.daemon=false
+    - TERM=dumb ./gradlew testDebugUnitTest -PpreDexEnable=false -Pcom.android.build.threadPoolSize=1 -Dorg.gradle.parallel=false -Dorg.gradle.jvmargs="-Xms512m -Xmx512m" -Dorg.gradle.daemon=false
+    # build JS bundle
+    - node local-cli/cli.js bundle --platform android --dev true --entry-file ReactAndroid/src/androidTest/assets/TestBundle.js --bundle-output ReactAndroid/src/androidTest/assets/AndroidTestBundle.js
+    # run instrumentation tests on device
+    - TERM=dumb ./gradlew connectedCheck

From f940e7c4a61e6c29d88cf01b91f8fff1afe68b85 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= <renaudeau.gaetan@gmail.com>
Date: Mon, 21 Dec 2015 10:03:59 -0800
Subject: [PATCH 0466/1411] iOS: Fix Image source={{ uri: null }} to crash

Summary:
this is a recent regression because the error appeared in my app (from 0.16 to 0.17).

```
<Image source={{ uri: null }} />
```

will make an error:

```
[RCTConvert.m:55] Error setting property 'source' of RCTImageView with tag #317: JSON value '<null>' of type NSNull cannot be converted to NSString
```

The solution attached is to check that uri is a NSString and return nil if not (the same way nil is returned in case of invalid url).
Closes https://github.com/facebook/react-native/pull/4902

Reviewed By: svcscm

Differential Revision: D2779789

Pulled By: nicklockwood

fb-gh-sync-id: cfe429ec5e53e63b7b368c06e693424ca8aaa11e
---
 React/Base/RCTImageSource.m | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/React/Base/RCTImageSource.m b/React/Base/RCTImageSource.m
index 3392385f8134..07518edf928a 100644
--- a/React/Base/RCTImageSource.m
+++ b/React/Base/RCTImageSource.m
@@ -8,6 +8,7 @@
  */
 
 #import "RCTImageSource.h"
+#import "RCTUtils.h"
 
 @interface RCTImageSource ()
 
@@ -60,7 +61,7 @@ + (RCTImageSource *)RCTImageSource:(id)json
   CGFloat scale = 1.0;
   BOOL packagerAsset = NO;
   if ([json isKindOfClass:[NSDictionary class]]) {
-    if (!(imageURL = [self NSURL:json[@"uri"]])) {
+    if (!(imageURL = [self NSURL:RCTNilIfNull(json[@"uri"])])) {
       return nil;
     }
     size = [self CGSize:json];

From d359c01f53e0af4111831661206ba7078e04b1ff Mon Sep 17 00:00:00 2001
From: Martin Kralik <kralik@fb.com>
Date: Mon, 21 Dec 2015 10:17:32 -0800
Subject: [PATCH 0467/1411] updated css-layout and fixed callsites

Reviewed By: mmahoney, nicklockwood

Differential Revision: D2759669

fb-gh-sync-id: 0b099f9c7d68bbcb62a38d2a3e355dfb6c61eb4e
---
 Libraries/Text/RCTShadowText.m |  2 +-
 React/Layout/Layout.c          | 59 ++++++++++++++++++++++++++++------
 React/Layout/Layout.h          |  6 ++--
 React/Views/RCTShadowView.m    |  2 +-
 4 files changed, 56 insertions(+), 13 deletions(-)

diff --git a/Libraries/Text/RCTShadowText.m b/Libraries/Text/RCTShadowText.m
index a8087b1da476..9139c187d58a 100644
--- a/Libraries/Text/RCTShadowText.m
+++ b/Libraries/Text/RCTShadowText.m
@@ -30,7 +30,7 @@ @implementation RCTShadowText
   CGFloat _effectiveLetterSpacing;
 }
 
-static css_dim_t RCTMeasure(void *context, float width)
+static css_dim_t RCTMeasure(void *context, float width, float height)
 {
   RCTShadowText *shadowText = (__bridge RCTShadowText *)context;
   NSTextStorage *textStorage = [shadowText buildTextStorageForWidth:width];
diff --git a/React/Layout/Layout.c b/React/Layout/Layout.c
index 0a429529eee8..317f69bb6dfb 100644
--- a/React/Layout/Layout.c
+++ b/React/Layout/Layout.c
@@ -9,6 +9,7 @@
  * !! 3) Copy the file from github to here                       !!
  * !!    (don't forget to keep this header)                      !!
  * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * @generated
  *
  * Copyright (c) 2014, Facebook, Inc.
  * All rights reserved.
@@ -87,6 +88,7 @@ void init_css_node(css_node_t *node) {
   node->layout.last_requested_dimensions[CSS_WIDTH] = -1;
   node->layout.last_requested_dimensions[CSS_HEIGHT] = -1;
   node->layout.last_parent_max_width = -1;
+  node->layout.last_parent_max_height = -1;
   node->layout.last_direction = (css_direction_t)-1;
   node->layout.should_update = true;
 }
@@ -527,7 +529,7 @@ static float getRelativePosition(css_node_t *node, css_flex_direction_t axis) {
   return -getPosition(node, trailing[axis]);
 }
 
-static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction_t parentDirection) {
+static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, float parentMaxHeight, css_direction_t parentDirection) {
   /** START_GENERATED **/
   css_direction_t direction = resolveDirection(node, parentDirection);
   css_flex_direction_t mainAxis = resolveAxis(getFlexDirection(node), direction);
@@ -556,6 +558,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
   // invocations during the layout calculation.
   int childCount = node->children_count;
   float paddingAndBorderAxisResolvedRow = getPaddingAndBorderAxis(node, resolvedRowAxis);
+  float paddingAndBorderAxisColumn = getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN);
 
   if (isMeasureDefined(node)) {
     bool isResolvedRowDimDefined = !isUndefined(node->layout.dimensions[dim[resolvedRowAxis]]);
@@ -571,6 +574,17 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
     }
     width -= paddingAndBorderAxisResolvedRow;
 
+    float height = CSS_UNDEFINED;
+    if (isDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) {
+      height = node->style.dimensions[CSS_HEIGHT];
+    } else if (!isUndefined(node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]])) {
+      height = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]];
+    } else {
+      height = parentMaxHeight -
+        getMarginAxis(node, resolvedRowAxis);
+    }
+    height -= getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN);
+
     // We only need to give a dimension for the text if we haven't got any
     // for it computed yet. It can either be from the style attribute or because
     // the element is flexible.
@@ -582,8 +596,9 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
     if (isRowUndefined || isColumnUndefined) {
       css_dim_t measureDim = node->measure(
         node->context,
-
-        width
+        
+        width,
+        height
       );
       if (isRowUndefined) {
         node->layout.dimensions[CSS_WIDTH] = measureDim.dimensions[CSS_WIDTH] +
@@ -591,7 +606,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
       }
       if (isColumnUndefined) {
         node->layout.dimensions[CSS_HEIGHT] = measureDim.dimensions[CSS_HEIGHT] +
-          getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN);
+          paddingAndBorderAxisColumn;
       }
     }
     if (childCount == 0) {
@@ -672,6 +687,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
     float crossDim = 0;
 
     float maxWidth;
+    float maxHeight;
     for (i = startLine; i < childCount; ++i) {
       child = node->get_child(node->context, i);
       child->line_index = linesCount;
@@ -752,6 +768,8 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
 
       } else {
         maxWidth = CSS_UNDEFINED;
+        maxHeight = CSS_UNDEFINED;
+
         if (!isMainRowDirection) {
           if (isDimDefined(node, resolvedRowAxis)) {
             maxWidth = node->layout.dimensions[dim[resolvedRowAxis]] -
@@ -761,11 +779,20 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
               getMarginAxis(node, resolvedRowAxis) -
               paddingAndBorderAxisResolvedRow;
           }
+        } else {
+          if (isDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) {
+            maxHeight = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] -
+                paddingAndBorderAxisColumn;
+          } else {
+            maxHeight = parentMaxHeight -
+              getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN) -
+              paddingAndBorderAxisColumn;
+          }
         }
 
         // This is the main recursive call. We layout non flexible children.
         if (alreadyComputedNextLayout == 0) {
-          layoutNode(child, maxWidth, direction);
+          layoutNode(child, maxWidth, maxHeight, direction);
         }
 
         // Absolute positioned elements do not take part of the layout, so we
@@ -895,9 +922,18 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
             getMarginAxis(node, resolvedRowAxis) -
             paddingAndBorderAxisResolvedRow;
         }
+        maxHeight = CSS_UNDEFINED;
+        if (isDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) {
+          maxHeight = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] -
+            paddingAndBorderAxisColumn;
+        } else if (isMainRowDirection) {
+          maxHeight = parentMaxHeight -
+            getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN) -
+            paddingAndBorderAxisColumn;
+        }
 
         // And we recursively call the layout algorithm for this child
-        layoutNode(currentFlexChild, maxWidth, direction);
+        layoutNode(currentFlexChild, maxWidth, maxHeight, direction);
 
         child = currentFlexChild;
         currentFlexChild = currentFlexChild->next_flex_child;
@@ -1000,11 +1036,14 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
         // For a relative children, we're either using alignItems (parent) or
         // alignSelf (child) in order to determine the position in the cross axis
         if (child->style.position_type == CSS_POSITION_RELATIVE) {
+          /*eslint-disable */
+          // This variable is intentionally re-defined as the code is transpiled to a block scope language
           css_align_t alignItem = getAlignItem(node, child);
+          /*eslint-enable */
           if (alignItem == CSS_ALIGN_STRETCH) {
             // You can only stretch if the dimension has not already been set
             // previously.
-            if (!isDimDefined(child, crossAxis)) {
+            if (isUndefined(child->layout.dimensions[dim[crossAxis]])) {
               child->layout.dimensions[dim[crossAxis]] = fmaxf(
                 boundAxis(child, crossAxis, containerCrossAxis -
                   paddingAndBorderAxisCross - getMarginAxis(child, crossAxis)),
@@ -1213,7 +1252,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
   /** END_GENERATED **/
 }
 
-void layoutNode(css_node_t *node, float parentMaxWidth, css_direction_t parentDirection) {
+void layoutNode(css_node_t *node, float parentMaxWidth, float parentMaxHeight, css_direction_t parentDirection) {
   css_layout_t *layout = &node->layout;
   css_direction_t direction = node->style.direction;
   layout->should_update = true;
@@ -1223,6 +1262,7 @@ void layoutNode(css_node_t *node, float parentMaxWidth, css_direction_t parentDi
     eq(layout->last_requested_dimensions[CSS_WIDTH], layout->dimensions[CSS_WIDTH]) &&
     eq(layout->last_requested_dimensions[CSS_HEIGHT], layout->dimensions[CSS_HEIGHT]) &&
     eq(layout->last_parent_max_width, parentMaxWidth);
+    eq(layout->last_parent_max_height, parentMaxHeight);
     eq(layout->last_direction, direction);
 
   if (skipLayout) {
@@ -1234,9 +1274,10 @@ void layoutNode(css_node_t *node, float parentMaxWidth, css_direction_t parentDi
     layout->last_requested_dimensions[CSS_WIDTH] = layout->dimensions[CSS_WIDTH];
     layout->last_requested_dimensions[CSS_HEIGHT] = layout->dimensions[CSS_HEIGHT];
     layout->last_parent_max_width = parentMaxWidth;
+    layout->last_parent_max_height = parentMaxHeight;
     layout->last_direction = direction;
 
-    layoutNodeImpl(node, parentMaxWidth, parentDirection);
+    layoutNodeImpl(node, parentMaxWidth, parentMaxHeight, parentDirection);
 
     layout->last_dimensions[CSS_WIDTH] = layout->dimensions[CSS_WIDTH];
     layout->last_dimensions[CSS_HEIGHT] = layout->dimensions[CSS_HEIGHT];
diff --git a/React/Layout/Layout.h b/React/Layout/Layout.h
index f1d2e3833589..be37c9393966 100644
--- a/React/Layout/Layout.h
+++ b/React/Layout/Layout.h
@@ -9,6 +9,7 @@
  * !! 3) Copy the file from github to here                       !!
  * !!    (don't forget to keep this header)                      !!
  * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * @generated 
  *
  * Copyright (c) 2014, Facebook, Inc.
  * All rights reserved.
@@ -102,6 +103,7 @@ typedef struct {
   bool should_update;
   float last_requested_dimensions[2];
   float last_parent_max_width;
+  float last_parent_max_height;
   float last_dimensions[2];
   float last_position[2];
   css_direction_t last_direction;
@@ -150,7 +152,7 @@ struct css_node {
   css_node_t* next_absolute_child;
   css_node_t* next_flex_child;
 
-  css_dim_t (*measure)(void *context, float width);
+  css_dim_t (*measure)(void *context, float width, float height);
   void (*print)(void *context);
   struct css_node* (*get_child)(void *context, int i);
   bool (*is_dirty)(void *context);
@@ -172,7 +174,7 @@ typedef enum {
 void print_css_node(css_node_t *node, css_print_options_t options);
 
 // Function that computes the layout!
-void layoutNode(css_node_t *node, float maxWidth, css_direction_t parentDirection);
+void layoutNode(css_node_t *node, float maxWidth, float maxHeight, css_direction_t parentDirection);
 bool isUndefined(float value);
 
 #endif
diff --git a/React/Views/RCTShadowView.m b/React/Views/RCTShadowView.m
index f6c775f2ad75..dd1720cd6995 100644
--- a/React/Views/RCTShadowView.m
+++ b/React/Views/RCTShadowView.m
@@ -241,7 +241,7 @@ - (void)applySizeConstraints
   [self applySizeConstraints];
 
   [self fillCSSNode:_cssNode];
-  layoutNode(_cssNode, CSS_UNDEFINED, CSS_DIRECTION_INHERIT);
+  layoutNode(_cssNode, CSS_UNDEFINED, CSS_UNDEFINED, CSS_DIRECTION_INHERIT);
 
   NSMutableSet<RCTShadowView *> *viewsWithNewFrame = [NSMutableSet set];
   [self applyLayoutNode:_cssNode viewsWithNewFrame:viewsWithNewFrame absolutePosition:CGPointZero];

From 45e0423b4ea1f29d6f86803057b94c710f8b9835 Mon Sep 17 00:00:00 2001
From: Martin Kralik <kralik@fb.com>
Date: Mon, 21 Dec 2015 10:17:33 -0800
Subject: [PATCH 0468/1411] removed `viewWithProps:` from `RCTViewManager`

Summary:
public

An option to create a different view based on passed in props is no longer necessary.
I'm removing it, since the idea of creating a view based on set of initial properies is a bit flawed, since we cannot change it to another view later when props are changed.
(This API really made sense mostly in case where some of the props on component were not meant to be changed later, which is a bit weird limitation on a prop.)

Reviewed By: nicklockwood

Differential Revision: D2769206

fb-gh-sync-id: 190a4f5f31ee84085b1ec945b5d99746f39e8e4b
---
 React/Views/RCTComponentData.m | 2 +-
 React/Views/RCTViewManager.h   | 9 ---------
 React/Views/RCTViewManager.m   | 5 -----
 3 files changed, 1 insertion(+), 15 deletions(-)

diff --git a/React/Views/RCTComponentData.m b/React/Views/RCTComponentData.m
index 42d7506eef45..9b224c29c475 100644
--- a/React/Views/RCTComponentData.m
+++ b/React/Views/RCTComponentData.m
@@ -81,7 +81,7 @@ - (UIView *)createViewWithTag:(NSNumber *)tag props:(NSDictionary<NSString *, id
 {
   RCTAssertMainThread();
 
-  UIView *view = (UIView *)(props ? [self.manager viewWithProps:props] : [_manager view]);
+  UIView *view = [_manager view];
   view.reactTag = tag;
   view.multipleTouchEnabled = YES;
   view.userInteractionEnabled = YES; // required for touch handling
diff --git a/React/Views/RCTViewManager.h b/React/Views/RCTViewManager.h
index 235f52a7b2ee..c570b93ff738 100644
--- a/React/Views/RCTViewManager.h
+++ b/React/Views/RCTViewManager.h
@@ -41,15 +41,6 @@ typedef void (^RCTViewManagerUIBlock)(RCTUIManager *uiManager, NSDictionary<NSNu
  */
 - (UIView *)view;
 
-/**
- * This method instantiates a native view using the props passed into the component.
- * This method should be used when you need to know about specific props in order to
- * initialize a view. By default, this just calls the -view method. Each prop will
- * still be set individually, after the view is created. Like the -view method,
- * -viewWithProps: should return a fresh instance each time it is called.
- */
-- (UIView *)viewWithProps:(NSDictionary<NSString *, id> *)props;
-
 /**
  * This method instantiates a shadow view to be managed by the module. If omitted,
  * an ordinary RCTShadowView instance will be created, which is typically fine for
diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m
index 379adecdc02f..bbbca7da1061 100644
--- a/React/Views/RCTViewManager.m
+++ b/React/Views/RCTViewManager.m
@@ -55,11 +55,6 @@ - (dispatch_queue_t)methodQueue
   return _bridge.uiManager.methodQueue;
 }
 
-- (UIView *)viewWithProps:(__unused NSDictionary<NSString *, id> *)props
-{
-  return [self view];
-}
-
 - (UIView *)view
 {
   return [RCTView new];

From 41875eec470c15b4c94c5c9cd03732ce948d8deb Mon Sep 17 00:00:00 2001
From: Andrei Coman <andreic@fb.com>
Date: Mon, 21 Dec 2015 10:23:27 -0800
Subject: [PATCH 0469/1411] Add cold start events dashboard ctscan test

Reviewed By: AaaChiuuu

Differential Revision: D2765609

fb-gh-sync-id: 1ac6b76dfad2cd01e52908c31e5391897aa2d99f
---
 .../main/java/com/facebook/react/ReactInstanceManagerImpl.java | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index 6061074cd7b6..d7b375cfb6cd 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -40,6 +40,7 @@
 import com.facebook.react.bridge.ProxyJavaScriptExecutor;
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.ReactMarker;
 import com.facebook.react.bridge.UiThreadUtil;
 import com.facebook.react.bridge.WritableMap;
 import com.facebook.react.bridge.WritableNativeMap;
@@ -605,6 +606,7 @@ private ReactApplicationContext createReactContext(
       JavaScriptExecutor jsExecutor,
       JSBundleLoader jsBundleLoader) {
     FLog.i(ReactConstants.TAG, "Creating react context.");
+    ReactMarker.logMarker("CREATE_REACT_CONTEXT_START");
     mSourceUrl = jsBundleLoader.getSourceUrl();
     NativeModuleRegistry.Builder nativeRegistryBuilder = new NativeModuleRegistry.Builder();
     JavaScriptModulesConfig.Builder jsModulesBuilder = new JavaScriptModulesConfig.Builder();
@@ -682,6 +684,7 @@ private ReactApplicationContext createReactContext(
       Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
     }
 
+    ReactMarker.logMarker("CREATE_REACT_CONTEXT_END");
     return reactContext;
   }
 

From 4cb775286cfc40219bb0b3666b663213f8cd140c Mon Sep 17 00:00:00 2001
From: Christopher Dro <hello@blick-labs.com>
Date: Mon, 21 Dec 2015 10:29:21 -0800
Subject: [PATCH 0470/1411] Add option for both min/max track image.

Summary:
This is a followup to PR #3850 but now separates min/max track images into different properties.
Closes #4476

Add examples for `minimumTrackTintColor`, `maximumTrackTintColor`, `minimumTrackImage`, `maximumTrackImage` to UIExplorer.
Closes https://github.com/facebook/react-native/pull/4586

Reviewed By: svcscm

Differential Revision: D2779193

Pulled By: nicklockwood

fb-gh-sync-id: 0510a0f496816baacdd0d4be0f3cd3a63a5a9865
---
 Examples/UIExplorer/SliderIOSExample.js       |  32 ++++++++++++-
 .../UIExplorer/Images.xcassets/Contents.json  |   6 +++
 Examples/UIExplorer/slider-left.png           | Bin 0 -> 1395 bytes
 Examples/UIExplorer/slider-left@2x.png        | Bin 0 -> 1684 bytes
 Examples/UIExplorer/slider-right.png          | Bin 0 -> 1398 bytes
 Examples/UIExplorer/slider-right@2x.png       | Bin 0 -> 1671 bytes
 Examples/UIExplorer/slider.png                | Bin 0 -> 1562 bytes
 Examples/UIExplorer/slider@2x.png             | Bin 0 -> 1988 bytes
 .../Components/SliderIOS/SliderIOS.ios.js     |  41 +++++++++--------
 React/Views/RCTSlider.h                       |   3 ++
 React/Views/RCTSlider.m                       |  43 +++++++++++++++---
 React/Views/RCTSliderManager.m                |   2 +
 12 files changed, 100 insertions(+), 27 deletions(-)
 create mode 100644 Examples/UIExplorer/UIExplorer/Images.xcassets/Contents.json
 create mode 100644 Examples/UIExplorer/slider-left.png
 create mode 100644 Examples/UIExplorer/slider-left@2x.png
 create mode 100644 Examples/UIExplorer/slider-right.png
 create mode 100644 Examples/UIExplorer/slider-right@2x.png
 create mode 100644 Examples/UIExplorer/slider.png
 create mode 100644 Examples/UIExplorer/slider@2x.png

diff --git a/Examples/UIExplorer/SliderIOSExample.js b/Examples/UIExplorer/SliderIOSExample.js
index 9b3c584db151..baee69ae8f02 100644
--- a/Examples/UIExplorer/SliderIOSExample.js
+++ b/Examples/UIExplorer/SliderIOSExample.js
@@ -84,10 +84,38 @@ exports.examples = [
       return <SliderExample step={0.25} />;
     }
   },
+  {
+    title: 'Custom min/max track tint color',
+    render(): ReactElement {
+      return (
+        <SliderExample
+          minimumTrackTintColor={'red'}
+          maximumTrackTintColor={'green'}
+        />
+      );
+    }
+  },
   {
     title: 'Custom thumb image',
     render(): ReactElement {
-      return <SliderExample thumbImage={require('image!uie_thumb_big')} />;
+      return <SliderExample thumbImage={require('./uie_thumb_big.png')} />;
     }
-  }
+  },
+  {
+    title: 'Custom track image',
+    render(): ReactElement {
+      return <SliderExample trackImage={require('./slider.png')} />;
+    }
+  },
+  {
+    title: 'Custom min/max track image',
+    render(): ReactElement {
+      return (
+        <SliderExample
+          minimumTrackImage={require('./slider-left.png')}
+          maximumTrackImage={require('./slider-right.png')}
+        />
+      );
+    }
+  },
 ];
diff --git a/Examples/UIExplorer/UIExplorer/Images.xcassets/Contents.json b/Examples/UIExplorer/UIExplorer/Images.xcassets/Contents.json
new file mode 100644
index 000000000000..da4a164c9186
--- /dev/null
+++ b/Examples/UIExplorer/UIExplorer/Images.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
\ No newline at end of file
diff --git a/Examples/UIExplorer/slider-left.png b/Examples/UIExplorer/slider-left.png
new file mode 100644
index 0000000000000000000000000000000000000000..dff4e11e19d642707f7f6c93024972100d669b4c
GIT binary patch
diff --git a/Examples/UIExplorer/slider-left@2x.png b/Examples/UIExplorer/slider-left@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..83c6dd8204eb68213e273684f69ce05e832a3555
GIT binary patch
diff --git a/Examples/UIExplorer/slider-right.png b/Examples/UIExplorer/slider-right.png
new file mode 100644
index 0000000000000000000000000000000000000000..57e8c7d3fe5637cebe5f874bda48dbc65ba4900a
GIT binary patch
diff --git a/Examples/UIExplorer/slider-right@2x.png b/Examples/UIExplorer/slider-right@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..8546ba8c9446c180fe06e4ac3f62f62745dc015e
GIT binary patch
diff --git a/Examples/UIExplorer/slider.png b/Examples/UIExplorer/slider.png
new file mode 100644
index 0000000000000000000000000000000000000000..9141991010c997c6e805e0468aae121524324c06
GIT binary patch
diff --git a/Examples/UIExplorer/slider@2x.png b/Examples/UIExplorer/slider@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..396614fa9b9bd202635f83c57147e86520af1e49
GIT binary patch
diff --git a/Libraries/Components/SliderIOS/SliderIOS.ios.js b/Libraries/Components/SliderIOS/SliderIOS.ios.js
index aff67e6ef7e0..fa1ed2246502 100644
--- a/Libraries/Components/SliderIOS/SliderIOS.ios.js
+++ b/Libraries/Components/SliderIOS/SliderIOS.ios.js
@@ -78,11 +78,24 @@ var SliderIOS = React.createClass({
      */
     disabled: PropTypes.bool,
 
-   /**
-     * Sets an image for the track. It only supports images that are included as assets
+    /**
+     * Assigns a single image for the track. Only static images are supported.
+     * The center pixel of the image will be stretched to fill the track.
      */
     trackImage: Image.propTypes.source,
 
+    /**
+     * Assigns a minimum track image. Only static images are supported. The
+     * rightmost pixel of the image will be stretched to fill the track.
+     */
+    minimumTrackImage: Image.propTypes.source,
+
+    /**
+     * Assigns a maximum track image. Only static images are supported. The
+     * leftmost pixel of the image will be stretched to fill the track.
+     */
+    maximumTrackImage: Image.propTypes.source,
+
     /**
      * Sets an image for the thumb. It only supports static images.
      */
@@ -107,28 +120,18 @@ var SliderIOS = React.createClass({
   },
 
   render: function() {
+    let {style, onValueChange, onSlidingComplete, ...props} = this.props;
+    props.style = [styles.slider, style];
 
-    let onValueChange = this.props.onValueChange && ((event: Event) => {
-      this.props.onValueChange &&
-        this.props.onValueChange(event.nativeEvent.value);
+    props.onValueChange = onValueChange && ((event: Event) => {
+      onValueChange && onValueChange(event.nativeEvent.value);
     });
 
-    let onSlidingComplete = this.props.onSlidingComplete && ((event: Event) => {
-      this.props.onSlidingComplete &&
-        this.props.onSlidingComplete(event.nativeEvent.value);
+    props.onSlidingComplete = onSlidingComplete && ((event: Event) => {
+      onSlidingComplete && onSlidingComplete(event.nativeEvent.value);
     });
 
-    let {style, ...props} = this.props;
-    style = [styles.slider, style];
-
-    return (
-      <RCTSlider
-        {...props}
-        style={style}
-        onValueChange={onValueChange}
-        onSlidingComplete={onSlidingComplete}
-      />
-    );
+    return <RCTSlider {...props}/>;
   }
 });
 
diff --git a/React/Views/RCTSlider.h b/React/Views/RCTSlider.h
index 83e3d7eadfb1..c84593c50c33 100644
--- a/React/Views/RCTSlider.h
+++ b/React/Views/RCTSlider.h
@@ -20,6 +20,9 @@
 @property (nonatomic, assign) float lastValue;
 
 @property (nonatomic, strong) UIImage *trackImage;
+@property (nonatomic, strong) UIImage *minimumTrackImage;
+@property (nonatomic, strong) UIImage *maximumTrackImage;
+
 @property (nonatomic, strong) UIImage *thumbImage;
 
 
diff --git a/React/Views/RCTSlider.m b/React/Views/RCTSlider.m
index d95f4d6879a4..4032794eb19b 100644
--- a/React/Views/RCTSlider.m
+++ b/React/Views/RCTSlider.m
@@ -9,6 +9,8 @@
 
 #import "RCTSlider.h"
 
+#import <tgmath.h>
+
 @implementation RCTSlider
 {
   float _unclippedValue;
@@ -36,15 +38,44 @@ - (void)setTrackImage:(UIImage *)trackImage
 {
   if (trackImage != _trackImage) {
     _trackImage = trackImage;
+    CGFloat width = trackImage.size.width / 2;
+    UIImage *minimumTrackImage = [trackImage resizableImageWithCapInsets:(UIEdgeInsets){
+      0, width, 0, width
+    } resizingMode:UIImageResizingModeStretch];
+    UIImage *maximumTrackImage = [trackImage resizableImageWithCapInsets:(UIEdgeInsets){
+      0, width, 0, width
+    } resizingMode:UIImageResizingModeStretch];
+    [self setMinimumTrackImage:minimumTrackImage forState:UIControlStateNormal];
+    [self setMaximumTrackImage:maximumTrackImage forState:UIControlStateNormal];
+  }
+}
 
-    CGFloat width = trackImage.size.width;
+- (void)setMinimumTrackImage:(UIImage *)minimumTrackImage
+{
+  _trackImage = nil;
+  minimumTrackImage = [minimumTrackImage resizableImageWithCapInsets:(UIEdgeInsets){
+    0, minimumTrackImage.size.width, 0, 0
+  } resizingMode:UIImageResizingModeStretch];
+  [self setMinimumTrackImage:minimumTrackImage forState:UIControlStateNormal];
+}
+
+- (UIImage *)minimumTrackImage
+{
+  return [self thumbImageForState:UIControlStateNormal];
+}
 
-    UIImage *minimumTrackImage = [trackImage resizableImageWithCapInsets:(UIEdgeInsets){0, width, 0, 0}];
-    UIImage *maximumTrackImage = [trackImage resizableImageWithCapInsets:(UIEdgeInsets){0, 0, 0, width}];
+- (void)setMaximumTrackImage:(UIImage *)maximumTrackImage
+{
+  _trackImage = nil;
+  maximumTrackImage = [maximumTrackImage resizableImageWithCapInsets:(UIEdgeInsets){
+    0, 0, 0, maximumTrackImage.size.width
+  } resizingMode:UIImageResizingModeStretch];
+  [self setMaximumTrackImage:maximumTrackImage forState:UIControlStateNormal];
+}
 
-    [super setMinimumTrackImage:minimumTrackImage forState:UIControlStateNormal];
-    [super setMaximumTrackImage:maximumTrackImage forState:UIControlStateNormal];
-  }
+- (UIImage *)maximumTrackImage
+{
+  return [self thumbImageForState:UIControlStateNormal];
 }
 
 - (void)setThumbImage:(UIImage *)thumbImage
diff --git a/React/Views/RCTSliderManager.m b/React/Views/RCTSliderManager.m
index bdb89ab06f51..50638f2cb9c2 100644
--- a/React/Views/RCTSliderManager.m
+++ b/React/Views/RCTSliderManager.m
@@ -77,6 +77,8 @@ - (void)sliderTouchEnd:(RCTSlider *)sender
 RCT_EXPORT_VIEW_PROPERTY(value, float);
 RCT_EXPORT_VIEW_PROPERTY(step, float);
 RCT_EXPORT_VIEW_PROPERTY(trackImage, UIImage);
+RCT_EXPORT_VIEW_PROPERTY(minimumTrackImage, UIImage);
+RCT_EXPORT_VIEW_PROPERTY(maximumTrackImage, UIImage);
 RCT_EXPORT_VIEW_PROPERTY(minimumValue, float);
 RCT_EXPORT_VIEW_PROPERTY(maximumValue, float);
 RCT_EXPORT_VIEW_PROPERTY(minimumTrackTintColor, UIColor);

From 6c02d5b14b7ef0ab4a2f94fb714550b2e8ec5431 Mon Sep 17 00:00:00 2001
From: Bhuwan Khattar <voideanvalue@fb.com>
Date: Mon, 21 Dec 2015 12:14:33 -0800
Subject: [PATCH 0471/1411] getTransformOptions based on bundle and module

Summary:
Currently, the app server accepts `transformModulePath` which allows us to use different transformation variants. However, these options persist through the lifetime of the server. So we cannot conditionally transform a module differently for two bundles without restarting the server with different options.

`getTransformOptions` basically allows us to change the options to the transformer at runtime based on the bundle and module being transformed.

These options are also used as a cache key for the transformedSource to ensure that if a file is transformed with different options, caching doesn't cause any inconsistencies.

public

Reviewed By: martinbigio

Differential Revision: D2776399

fb-gh-sync-id: 1e0f34d8fa7f0377fcf81f23eb6f3236bd397d56
---
 packager/README.md                                         | 2 ++
 packager/react-packager/src/Bundler/Bundle.js              | 4 ++++
 .../react-packager/src/Bundler/__tests__/Bundler-test.js   | 1 +
 packager/react-packager/src/Bundler/index.js               | 5 ++++-
 packager/react-packager/src/JSTransformer/index.js         | 7 +++++--
 packager/react-packager/src/Server/index.js                | 4 ++++
 6 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/packager/README.md b/packager/README.md
index 836839395ea1..d14ae0320463 100644
--- a/packager/README.md
+++ b/packager/README.md
@@ -112,6 +112,8 @@ middleware. Takes the following options:
   should be used as a persistent deamon to watch files and update
   itself
 * `assetRoots` array: Where should the packager look for assets
+* `getTransformOptions` function: Middleware to get custom options for the
+  transformer based on the bundle and module being transformed.
 
 ### ReactPackager.buildPackageFromUrl(options, url)
 
diff --git a/packager/react-packager/src/Bundler/Bundle.js b/packager/react-packager/src/Bundler/Bundle.js
index b945dd42864b..007dca29327b 100644
--- a/packager/react-packager/src/Bundler/Bundle.js
+++ b/packager/react-packager/src/Bundler/Bundle.js
@@ -58,6 +58,10 @@ class Bundle {
     return this._modules;
   }
 
+  getMainModuleId() {
+    return this._mainModuleId;
+  }
+
   setNumPrependedModules(n) {
     this._numPrependedModules = n;
   }
diff --git a/packager/react-packager/src/Bundler/__tests__/Bundler-test.js b/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
index ccdc84961d4c..37d200f2555f 100644
--- a/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
+++ b/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
@@ -81,6 +81,7 @@ describe('Bundler', function() {
     bundler = new Bundler({
       projectRoots: ['/root'],
       assetServer: assetServer,
+      getTransformOptions: () => ({}),
     });
 
     modules = [
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index 31794a9bc04f..19174129d70d 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -135,6 +135,8 @@ class Bundler {
 
     this._projectRoots = opts.projectRoots;
     this._assetServer = opts.assetServer;
+
+    this._getTransformOptions = opts.getTransformOptions;
   }
 
   kill() {
@@ -322,7 +324,8 @@ class Bundler {
       return generateJSONModule(module);
     } else {
       return this._transformer.loadFileAndTransform(
-        path.resolve(module.path)
+        path.resolve(module.path),
+        this._getTransformOptions({bundle, module, platform})
       );
     }
   }
diff --git a/packager/react-packager/src/JSTransformer/index.js b/packager/react-packager/src/JSTransformer/index.js
index 5c819381caf8..07225252943c 100644
--- a/packager/react-packager/src/JSTransformer/index.js
+++ b/packager/react-packager/src/JSTransformer/index.js
@@ -82,16 +82,18 @@ class Transformer {
     this._cache.invalidate(filePath);
   }
 
-  loadFileAndTransform(filePath) {
+  loadFileAndTransform(filePath, options) {
     if (this._transform == null) {
       return Promise.reject(new Error('No transfrom module'));
     }
 
     debug('transforming file', filePath);
 
+    const optionsJSON = JSON.stringify(options);
+
     return this._cache.get(
       filePath,
-      'transformedSource',
+      'transformedSource-' + optionsJSON,
       // TODO: use fastfs to avoid reading file from disk again
       () => readFile(filePath).then(
         buffer => {
@@ -100,6 +102,7 @@ class Transformer {
           return this._transform({
             sourceCode,
             filename: filePath,
+            options,
           }).then(res => {
             if (res.error) {
               console.warn(
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index 121dcddb87ed..a1fb415a475c 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -64,6 +64,10 @@ const validateOpts = declareOpts({
     type: 'number',
     required: false,
   },
+  getTransformOptions: {
+    type: 'function',
+    default: () => ({}),
+  }
 });
 
 const bundleOpts = declareOpts({

From 3ff39870ce776c653823e1733363be0401896294 Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Mon, 21 Dec 2015 17:52:20 -0800
Subject: [PATCH 0472/1411] Update open source env

Summary:
We weren't exposing a mock for the batched bridge, which resulted in the WebSocket test failure but only in the open source copy of react-native.

public

Reviewed By: voideanvalue, vjeux

Differential Revision: D2782151

fb-gh-sync-id: e896097dd6060bc26963bc4c23db87b7277b3eba
---
 jestSupport/env.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/jestSupport/env.js b/jestSupport/env.js
index 963d75e14f59..933419d36ee4 100644
--- a/jestSupport/env.js
+++ b/jestSupport/env.js
@@ -10,3 +10,9 @@
 
 require('../packager/react-packager/src/Resolver/polyfills/babelHelpers.js');
 global.__DEV__ = true;
+global.__fbBatchedBridgeConfig = {
+  remoteModuleConfig: [],
+  localModulesConfig: [],
+};
+
+global.Promise = require('promise');

From fef686fb467f0c08b195596af7dc5950c2fe519c Mon Sep 17 00:00:00 2001
From: Ravi Vagadia <ravirdv@gmail.com>
Date: Tue, 22 Dec 2015 14:12:17 +0530
Subject: [PATCH 0473/1411] Add 'Koza Gujarati Dictionary' to showcase

Added 'Koza Gujarati Dictionary' to showcase
---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 6974ca69636c..c986b8682abc 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -242,6 +242,12 @@ var apps = [
     linkPlayStore: 'https://play.google.com/store/apps/details?id=com.kakaponative',
     author: 'Daniel Levitt',
   },
+  {
+    name: 'Koza Gujarati Dictionary',
+    icon: 'http://a1.mzstatic.com/us/r30/Purple69/v4/77/95/83/77958377-05ae-4754-684a-3c9dbb67b517/icon175x175.jpeg',
+    link: 'https://itunes.apple.com/in/app/koza-english-to-gujarati-dictionary/id982752928?mt=8',
+    author: 'KozaApps',
+  },
   {
     name: 'Leanpub',
     icon: 'http://a2.mzstatic.com/us/r30/Purple6/v4/9f/4a/6f/9f4a6f8c-8951-ed89-4083-74ace23df9ef/icon350x350.jpeg',

From 8dab7f46e5ec9ef36f416ad3680afbe9676e87d3 Mon Sep 17 00:00:00 2001
From: Genki Takiuchi <genki@s21g.com>
Date: Fri, 4 Dec 2015 19:17:01 +0900
Subject: [PATCH 0474/1411] DockMan app added to showcase

---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index c986b8682abc..985eb1dae0d5 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -163,6 +163,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/dareu-dare-your-friends-dare/id1046434563?mt=8',
     author: 'Rishabh Mehan',
   },
+  {
+    name: 'DockMan',
+    icon: 'http://a1.mzstatic.com/us/r30/Purple49/v4/91/b5/75/91b57552-d9bc-d8bc-10a1-617de920aaa6/icon175x175.png',
+    link: 'http://www.s21g.com/DockMan.html',
+    author: 'Genki Takiuchi (s21g Inc.)',
+  },
   {
     name: 'DropBot',
     icon: 'http://a2.mzstatic.com/us/r30/Purple69/v4/fb/df/73/fbdf73e0-22d2-c936-3115-1defa195acba/icon175x175.png',

From ae9d2ce35c151332b5105208be04e150cee79e58 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Tue, 22 Dec 2015 17:34:17 +0100
Subject: [PATCH 0475/1411] Add example of getting window dimensions to
 Dimensions docs

By @calvinf

Closes https://github.com/facebook/react-native/pull/4211
---
 Libraries/Utilities/Dimensions.js | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Libraries/Utilities/Dimensions.js b/Libraries/Utilities/Dimensions.js
index 319aa84622e3..93e2cc21aa15 100644
--- a/Libraries/Utilities/Dimensions.js
+++ b/Libraries/Utilities/Dimensions.js
@@ -57,6 +57,8 @@ class Dimensions {
    * than caching the value (for example, using inline styles rather than
    * setting a value in a `StyleSheet`).
    *
+   * Example: `var {height, width} = Dimensions.get('window');`
+   *
    * @param {string} dim Name of dimension as defined when calling `set`.
    * @returns {Object?} Value for the dimension.
    */

From 5384c47d9a7e19ff065369e242f58c58ffa0e440 Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeuxx@gmail.com>
Date: Tue, 22 Dec 2015 10:32:20 -0800
Subject: [PATCH 0476/1411] Revert package.json change

---
 package.json | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 45913996d365..55e7302677de 100644
--- a/package.json
+++ b/package.json
@@ -46,7 +46,7 @@
   ],
   "scripts": {
     "test": "NODE_ENV=test jest",
-    "lint": "eslint Examples/ Libraries/ bots/code-analysis-bot.js",
+    "lint": "eslint Examples/ Libraries/",
     "start": "/usr/bin/env bash -c './packager/packager.sh \"$@\" || true' --"
   },
   "bin": {
@@ -122,7 +122,6 @@
     "yeoman-generator": "^0.20.3"
   },
   "devDependencies": {
-    "github": "^0.2.4",
     "jest-cli": "0.7.1",
     "babel-eslint": "4.1.4",
     "eslint": "1.3.1",

From d5f238638a52bdc1e7f33e6c96b158a9d2d0dee0 Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Wed, 23 Dec 2015 05:34:56 +0530
Subject: [PATCH 0477/1411] Ask to specify the platform in new issue greeting

---
 bots/NewIssueGreeting.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bots/NewIssueGreeting.md b/bots/NewIssueGreeting.md
index 8d22aec68d61..f564e47296dd 100644
--- a/bots/NewIssueGreeting.md
+++ b/bots/NewIssueGreeting.md
@@ -6,4 +6,4 @@ React Native, as you've probably heard, is getting really popular and truth is w
 
 - If this is a **feature request or a bug** that you would like to be fixed, please report it on [Product Pains](https://productpains.com/product/react-native/). It has a ranking feature that lets us focus on the most important issues the community is experiencing.
 
-- We welcome clear issues and PRs that are ready for in-depth discussion. Please provide **screenshots** where appropriate and always mention the **version** of React Native you're using. Thank you for your contributions!
+- We welcome clear issues and PRs that are ready for in-depth discussion. Please provide **screenshots** where appropriate and always mention the **version** of React Native you're using, as well as the **platform** you're on e.g.- Android, iOS. Thank you for your contributions!

From d9c582ed64bfa686ced91de6dbe5943d23500dda Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeuxx@gmail.com>
Date: Wed, 23 Dec 2015 10:06:50 -0800
Subject: [PATCH 0478/1411] Revert dimensions.js change

To unbreak the sync
---
 Libraries/Utilities/Dimensions.js | 2 --
 1 file changed, 2 deletions(-)

diff --git a/Libraries/Utilities/Dimensions.js b/Libraries/Utilities/Dimensions.js
index 93e2cc21aa15..319aa84622e3 100644
--- a/Libraries/Utilities/Dimensions.js
+++ b/Libraries/Utilities/Dimensions.js
@@ -57,8 +57,6 @@ class Dimensions {
    * than caching the value (for example, using inline styles rather than
    * setting a value in a `StyleSheet`).
    *
-   * Example: `var {height, width} = Dimensions.get('window');`
-   *
    * @param {string} dim Name of dimension as defined when calling `set`.
    * @returns {Object?} Value for the dimension.
    */

From 699d748bb37a1b078c452826432eba6c59cef02f Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Mon, 21 Dec 2015 18:02:56 -0800
Subject: [PATCH 0479/1411] Upgrade jest to 0.8.2

Reviewed By: vjeux

Differential Revision: D2781488

fb-gh-sync-id: f70c2cab9533ae64a98fc39b6aa9f7c2127d6fde
---
 npm-shrinkwrap.json | 2069 +++++++++++++++++++------------------------
 package.json        |    2 +-
 2 files changed, 914 insertions(+), 1157 deletions(-)

diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index 6b0c320f615c..3820eda08025 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -118,16 +118,21 @@
       "from": "babel@>=5.4.7 <6.0.0",
       "resolved": "https://registry.npmjs.org/babel/-/babel-5.8.29.tgz",
       "dependencies": {
-        "ast-types": {
-          "version": "0.8.12",
-          "from": "ast-types@0.8.12",
-          "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz"
-        },
         "babel-core": {
           "version": "5.8.33",
           "from": "babel-core@>=5.6.21 <6.0.0",
           "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-5.8.33.tgz"
         },
+        "source-map": {
+          "version": "0.5.3",
+          "from": "source-map@>=0.5.0 <0.6.0",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz"
+        },
+        "ast-types": {
+          "version": "0.8.12",
+          "from": "ast-types@0.8.12",
+          "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz"
+        },
         "babylon": {
           "version": "5.8.29",
           "from": "babylon@>=5.8.29 <6.0.0",
@@ -146,25 +151,20 @@
           "from": "globals@>=6.4.0 <7.0.0",
           "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
         },
-        "js-tokens": {
-          "version": "1.0.1",
-          "from": "js-tokens@1.0.1",
-          "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
-        },
         "recast": {
           "version": "0.10.33",
           "from": "recast@0.10.33",
           "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
         },
+        "js-tokens": {
+          "version": "1.0.1",
+          "from": "js-tokens@1.0.1",
+          "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
+        },
         "regenerator": {
           "version": "0.8.40",
           "from": "regenerator@0.8.40",
           "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
-        },
-        "source-map": {
-          "version": "0.5.3",
-          "from": "source-map@>=0.5.0 <0.6.0",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz"
         }
       }
     },
@@ -215,6 +215,16 @@
           "from": "babylon@>=6.1.20 <7.0.0",
           "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.1.21.tgz"
         },
+        "regenerator": {
+          "version": "0.8.35",
+          "from": "regenerator@0.8.35",
+          "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.35.tgz"
+        },
+        "source-map": {
+          "version": "0.5.3",
+          "from": "source-map@>=0.5.0 <0.6.0",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz"
+        },
         "esprima-fb": {
           "version": "15001.1.0-dev-harmony-fb",
           "from": "esprima-fb@>=15001.1.0-dev-harmony-fb <15001.2.0",
@@ -231,16 +241,6 @@
               "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz"
             }
           }
-        },
-        "regenerator": {
-          "version": "0.8.35",
-          "from": "regenerator@0.8.35",
-          "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.35.tgz"
-        },
-        "source-map": {
-          "version": "0.5.3",
-          "from": "source-map@>=0.5.0 <0.6.0",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz"
         }
       }
     },
@@ -249,11 +249,6 @@
       "from": "babel-eslint@*",
       "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-4.1.4.tgz",
       "dependencies": {
-        "ast-types": {
-          "version": "0.8.12",
-          "from": "ast-types@0.8.12",
-          "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz"
-        },
         "babel-core": {
           "version": "5.8.33",
           "from": "babel-core@>=5.8.33 <6.0.0",
@@ -269,6 +264,11 @@
             }
           }
         },
+        "ast-types": {
+          "version": "0.8.12",
+          "from": "ast-types@0.8.12",
+          "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz"
+        },
         "babylon": {
           "version": "5.8.29",
           "from": "babylon@>=5.8.29 <6.0.0",
@@ -311,29 +311,29 @@
       "from": "babel-generator@>=6.1.20 <7.0.0",
       "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.1.20.tgz",
       "dependencies": {
-        "babel-code-frame": {
-          "version": "6.1.18",
-          "from": "babel-code-frame@>=6.1.18 <7.0.0"
-        },
         "babel-messages": {
           "version": "6.1.18",
           "from": "babel-messages@>=6.1.18 <7.0.0"
         },
-        "babel-traverse": {
-          "version": "6.1.20",
-          "from": "babel-traverse@>=6.1.18 <7.0.0"
-        },
         "babel-types": {
           "version": "6.1.18",
           "from": "babel-types@>=6.1.18 <7.0.0"
         },
-        "babylon": {
-          "version": "6.1.21",
-          "from": "babylon@>=6.1.20 <7.0.0"
-        },
         "source-map": {
           "version": "0.5.3",
           "from": "source-map@>=0.5.0 <0.6.0"
+        },
+        "babel-code-frame": {
+          "version": "6.1.18",
+          "from": "babel-code-frame@>=6.1.18 <7.0.0"
+        },
+        "babel-traverse": {
+          "version": "6.1.20",
+          "from": "babel-traverse@>=6.1.18 <7.0.0"
+        },
+        "babylon": {
+          "version": "6.1.21",
+          "from": "babylon@>=6.1.20 <7.0.0"
         }
       }
     },
@@ -382,6 +382,10 @@
       "from": "babel-helpers@>=6.1.20 <7.0.0",
       "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.1.20.tgz",
       "dependencies": {
+        "babel-template": {
+          "version": "6.1.18",
+          "from": "babel-template@>=6.1.18 <7.0.0"
+        },
         "babel-code-frame": {
           "version": "6.1.18",
           "from": "babel-code-frame@>=6.1.18 <7.0.0"
@@ -390,10 +394,6 @@
           "version": "6.1.18",
           "from": "babel-messages@>=6.1.18 <7.0.0"
         },
-        "babel-template": {
-          "version": "6.1.18",
-          "from": "babel-template@>=6.1.18 <7.0.0"
-        },
         "babel-traverse": {
           "version": "6.1.20",
           "from": "babel-traverse@>=6.1.18 <7.0.0"
@@ -782,54 +782,30 @@
       "from": "connect@2.8.3",
       "resolved": "https://registry.npmjs.org/connect/-/connect-2.8.3.tgz",
       "dependencies": {
-        "buffer-crc32": {
-          "version": "0.2.1",
-          "from": "buffer-crc32@0.2.1",
-          "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.1.tgz"
-        },
-        "bytes": {
-          "version": "0.2.0",
-          "from": "bytes@0.2.0",
-          "resolved": "https://registry.npmjs.org/bytes/-/bytes-0.2.0.tgz"
+        "qs": {
+          "version": "0.6.5",
+          "from": "qs@0.6.5",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-0.6.5.tgz"
         },
-        "cookie": {
-          "version": "0.1.0",
-          "from": "cookie@0.1.0",
-          "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.0.tgz"
+        "formidable": {
+          "version": "1.0.14",
+          "from": "formidable@1.0.14",
+          "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.0.14.tgz"
         },
         "cookie-signature": {
           "version": "1.0.1",
           "from": "cookie-signature@1.0.1",
           "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.1.tgz"
         },
-        "debug": {
-          "version": "2.2.0",
-          "from": "debug@*"
-        },
-        "formidable": {
-          "version": "1.0.14",
-          "from": "formidable@1.0.14",
-          "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.0.14.tgz"
+        "buffer-crc32": {
+          "version": "0.2.1",
+          "from": "buffer-crc32@0.2.1",
+          "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.1.tgz"
         },
-        "fresh": {
+        "cookie": {
           "version": "0.1.0",
-          "from": "fresh@0.1.0",
-          "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.1.0.tgz"
-        },
-        "methods": {
-          "version": "0.0.1",
-          "from": "methods@0.0.1",
-          "resolved": "https://registry.npmjs.org/methods/-/methods-0.0.1.tgz"
-        },
-        "pause": {
-          "version": "0.0.1",
-          "from": "pause@0.0.1",
-          "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz"
-        },
-        "qs": {
-          "version": "0.6.5",
-          "from": "qs@0.6.5",
-          "resolved": "https://registry.npmjs.org/qs/-/qs-0.6.5.tgz"
+          "from": "cookie@0.1.0",
+          "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.0.tgz"
         },
         "send": {
           "version": "0.1.2",
@@ -848,10 +824,34 @@
             }
           }
         },
+        "bytes": {
+          "version": "0.2.0",
+          "from": "bytes@0.2.0",
+          "resolved": "https://registry.npmjs.org/bytes/-/bytes-0.2.0.tgz"
+        },
+        "fresh": {
+          "version": "0.1.0",
+          "from": "fresh@0.1.0",
+          "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.1.0.tgz"
+        },
+        "pause": {
+          "version": "0.0.1",
+          "from": "pause@0.0.1",
+          "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz"
+        },
         "uid2": {
           "version": "0.0.2",
           "from": "uid2@0.0.2",
           "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.2.tgz"
+        },
+        "debug": {
+          "version": "2.2.0",
+          "from": "debug@*"
+        },
+        "methods": {
+          "version": "0.0.1",
+          "from": "methods@0.0.1",
+          "resolved": "https://registry.npmjs.org/methods/-/methods-0.0.1.tgz"
         }
       }
     },
@@ -953,6 +953,11 @@
               "from": "inherits@>=2.0.1 <2.1.0",
               "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
             },
+            "typedarray": {
+              "version": "0.0.6",
+              "from": "typedarray@>=0.0.5 <0.1.0",
+              "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
+            },
             "readable-stream": {
               "version": "2.0.2",
               "from": "readable-stream@>=2.0.0 <2.1.0",
@@ -984,11 +989,6 @@
                   "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.1.tgz"
                 }
               }
-            },
-            "typedarray": {
-              "version": "0.0.6",
-              "from": "typedarray@>=0.0.5 <0.1.0",
-              "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
             }
           }
         },
@@ -1645,35 +1645,35 @@
           "from": "optionator@>=0.5.0 <0.6.0",
           "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz",
           "dependencies": {
+            "prelude-ls": {
+              "version": "1.1.2",
+              "from": "prelude-ls@>=1.1.1 <1.2.0",
+              "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz"
+            },
             "deep-is": {
               "version": "0.1.3",
               "from": "deep-is@>=0.1.2 <0.2.0",
               "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz"
             },
-            "fast-levenshtein": {
-              "version": "1.0.7",
-              "from": "fast-levenshtein@>=1.0.0 <1.1.0",
-              "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz"
-            },
-            "levn": {
-              "version": "0.2.5",
-              "from": "levn@>=0.2.5 <0.3.0",
-              "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz"
-            },
-            "prelude-ls": {
-              "version": "1.1.2",
-              "from": "prelude-ls@>=1.1.1 <1.2.0",
-              "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz"
+            "wordwrap": {
+              "version": "0.0.3",
+              "from": "wordwrap@>=0.0.2 <0.1.0",
+              "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
             },
             "type-check": {
               "version": "0.3.1",
               "from": "type-check@>=0.3.1 <0.4.0",
               "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz"
             },
-            "wordwrap": {
-              "version": "0.0.3",
-              "from": "wordwrap@>=0.0.2 <0.1.0",
-              "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
+            "levn": {
+              "version": "0.2.5",
+              "from": "levn@>=0.2.5 <0.3.0",
+              "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz"
+            },
+            "fast-levenshtein": {
+              "version": "1.0.7",
+              "from": "fast-levenshtein@>=1.0.0 <1.1.0",
+              "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz"
             }
           }
         },
@@ -1813,6 +1813,18 @@
       "from": "fsevents@>=1.0.0 <2.0.0",
       "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.0.5.tgz",
       "dependencies": {
+        "node-pre-gyp": {
+          "version": "0.6.15",
+          "from": "node-pre-gyp@latest",
+          "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.6.15.tgz",
+          "dependencies": {
+            "nopt": {
+              "version": "3.0.4",
+              "from": "nopt@>=3.0.1 <3.1.0",
+              "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.4.tgz"
+            }
+          }
+        },
         "abbrev": {
           "version": "1.0.7",
           "from": "abbrev@1",
@@ -1843,16 +1855,16 @@
           "from": "asn1@0.1.11",
           "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
         },
-        "assert-plus": {
-          "version": "0.1.5",
-          "from": "assert-plus@^0.1.5",
-          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
-        },
         "async": {
           "version": "1.5.0",
           "from": "async@^1.4.0",
           "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz"
         },
+        "assert-plus": {
+          "version": "0.1.5",
+          "from": "assert-plus@^0.1.5",
+          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
+        },
         "aws-sign2": {
           "version": "0.6.0",
           "from": "aws-sign2@~0.6.0",
@@ -1863,65 +1875,21 @@
           "from": "balanced-match@>=0.2.0 <0.3.0",
           "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.1.tgz"
         },
-        "bl": {
-          "version": "1.0.0",
-          "from": "bl@~1.0.0",
-          "resolved": "https://registry.npmjs.org/bl/-/bl-1.0.0.tgz",
-          "dependencies": {
-            "readable-stream": {
-              "version": "2.0.4",
-              "from": "readable-stream@~2.0.0",
-              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.4.tgz",
-              "dependencies": {
-                "core-util-is": {
-                  "version": "1.0.1",
-                  "from": "core-util-is@~1.0.0",
-                  "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-                },
-                "inherits": {
-                  "version": "2.0.1",
-                  "from": "inherits@~2.0.1",
-                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                },
-                "isarray": {
-                  "version": "0.0.1",
-                  "from": "isarray@0.0.1",
-                  "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
-                },
-                "process-nextick-args": {
-                  "version": "1.0.3",
-                  "from": "process-nextick-args@~1.0.0",
-                  "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.3.tgz"
-                },
-                "string_decoder": {
-                  "version": "0.10.31",
-                  "from": "string_decoder@~0.10.x",
-                  "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
-                },
-                "util-deprecate": {
-                  "version": "1.0.2",
-                  "from": "util-deprecate@~1.0.1",
-                  "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
-                }
-              }
-            }
-          }
-        },
         "block-stream": {
           "version": "0.0.8",
           "from": "block-stream@*",
           "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.8.tgz"
         },
-        "boom": {
-          "version": "2.10.1",
-          "from": "boom@^2.8.x",
-          "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz"
-        },
         "brace-expansion": {
           "version": "1.1.1",
           "from": "brace-expansion@>=1.0.0 <2.0.0",
           "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz"
         },
+        "boom": {
+          "version": "2.10.1",
+          "from": "boom@^2.8.x",
+          "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz"
+        },
         "caseless": {
           "version": "0.11.0",
           "from": "caseless@~0.11.0",
@@ -1977,16 +1945,16 @@
           "from": "delayed-stream@~1.0.0",
           "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
         },
-        "delegates": {
-          "version": "0.1.0",
-          "from": "delegates@^0.1.0",
-          "resolved": "https://registry.npmjs.org/delegates/-/delegates-0.1.0.tgz"
-        },
         "escape-string-regexp": {
           "version": "1.0.3",
           "from": "escape-string-regexp@^1.0.2",
           "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz"
         },
+        "delegates": {
+          "version": "0.1.0",
+          "from": "delegates@^0.1.0",
+          "resolved": "https://registry.npmjs.org/delegates/-/delegates-0.1.0.tgz"
+        },
         "extend": {
           "version": "3.0.0",
           "from": "extend@~3.0.0",
@@ -2007,17 +1975,6 @@
           "from": "fstream@^1.0.2",
           "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.8.tgz"
         },
-        "fstream-ignore": {
-          "version": "1.0.3",
-          "from": "fstream-ignore@~1.0.3",
-          "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.3.tgz",
-          "dependencies": {
-            "minimatch": {
-              "version": "3.0.0",
-              "from": "minimatch@>=3.0.0 <4.0.0"
-            }
-          }
-        },
         "gauge": {
           "version": "1.2.2",
           "from": "gauge@~1.2.0",
@@ -2053,16 +2010,16 @@
           "from": "has-ansi@^2.0.0",
           "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
         },
-        "has-unicode": {
-          "version": "1.0.1",
-          "from": "has-unicode@^1.0.0",
-          "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-1.0.1.tgz"
-        },
         "hawk": {
           "version": "3.1.0",
           "from": "hawk@~3.1.0",
           "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.0.tgz"
         },
+        "has-unicode": {
+          "version": "1.0.1",
+          "from": "has-unicode@^1.0.0",
+          "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-1.0.1.tgz"
+        },
         "hoek": {
           "version": "2.16.3",
           "from": "hoek@2.x.x",
@@ -2073,27 +2030,16 @@
           "from": "http-signature@~0.11.0",
           "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.11.0.tgz"
         },
-        "inflight": {
-          "version": "1.0.4",
-          "from": "inflight@>=1.0.4 <2.0.0",
-          "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz",
-          "dependencies": {
-            "once": {
-              "version": "1.3.2",
-              "from": "once@>=1.3.0 <2.0.0"
-            }
-          }
+        "ini": {
+          "version": "1.3.4",
+          "from": "ini@~1.3.0",
+          "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz"
         },
         "inherits": {
           "version": "2.0.1",
           "from": "inherits@*",
           "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
         },
-        "ini": {
-          "version": "1.3.4",
-          "from": "ini@~1.3.0",
-          "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz"
-        },
         "is-my-json-valid": {
           "version": "2.12.2",
           "from": "is-my-json-valid@^2.12.2",
@@ -2174,18 +2120,6 @@
           "from": "mkdirp@>=0.3.0 <0.4.0||>=0.4.0 <0.5.0||>=0.5.0 <0.6.0",
           "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz"
         },
-        "node-pre-gyp": {
-          "version": "0.6.15",
-          "from": "node-pre-gyp@latest",
-          "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.6.15.tgz",
-          "dependencies": {
-            "nopt": {
-              "version": "3.0.4",
-              "from": "nopt@>=3.0.1 <3.1.0",
-              "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.4.tgz"
-            }
-          }
-        },
         "node-uuid": {
           "version": "1.4.3",
           "from": "node-uuid@~1.4.3",
@@ -2216,75 +2150,41 @@
           "from": "pinkie@^1.0.0",
           "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
         },
-        "pinkie-promise": {
-          "version": "1.0.0",
-          "from": "pinkie-promise@^1.0.0",
-          "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz"
-        },
         "qs": {
           "version": "5.2.0",
           "from": "qs@~5.2.0",
           "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz"
         },
-        "rc": {
-          "version": "1.1.2",
-          "from": "rc@~1.1.0",
-          "resolved": "https://registry.npmjs.org/rc/-/rc-1.1.2.tgz",
-          "dependencies": {
-            "minimist": {
-              "version": "1.2.0",
-              "from": "minimist@^1.1.2",
-              "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
-            }
-          }
-        },
-        "readable-stream": {
-          "version": "1.1.13",
-          "from": "readable-stream@^1.1.13",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz"
+        "pinkie-promise": {
+          "version": "1.0.0",
+          "from": "pinkie-promise@^1.0.0",
+          "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz"
         },
         "request": {
           "version": "2.65.0",
           "from": "request@2.x",
           "resolved": "https://registry.npmjs.org/request/-/request-2.65.0.tgz"
         },
-        "rimraf": {
-          "version": "2.4.3",
-          "from": "rimraf@~2.4.0",
-          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.3.tgz",
-          "dependencies": {
-            "glob": {
-              "version": "5.0.15",
-              "from": "glob@>=5.0.14 <6.0.0",
-              "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz"
-            },
-            "minimatch": {
-              "version": "3.0.0",
-              "from": "minimatch@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.0.tgz"
-            },
-            "once": {
-              "version": "1.3.2",
-              "from": "once@>=1.3.0 <2.0.0",
-              "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz"
-            }
-          }
+        "readable-stream": {
+          "version": "1.1.13",
+          "from": "readable-stream@^1.1.13",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz"
         },
         "semver": {
           "version": "5.0.3",
           "from": "semver@~5.0.1",
           "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
         },
-        "sntp": {
-          "version": "1.0.9",
-          "from": "sntp@1.x.x",
-          "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
-        },
         "string_decoder": {
           "version": "0.10.31",
           "from": "string_decoder@~0.10.x",
           "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
         },
+        "sntp": {
+          "version": "1.0.9",
+          "from": "sntp@1.x.x",
+          "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
+        },
         "stringstream": {
           "version": "0.0.5",
           "from": "stringstream@~0.0.4",
@@ -2310,55 +2210,16 @@
           "from": "tar@~2.2.0",
           "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz"
         },
-        "tar-pack": {
-          "version": "3.1.0",
-          "from": "tar-pack@~3.1.0",
-          "resolved": "https://registry.npmjs.org/tar-pack/-/tar-pack-3.1.0.tgz",
-          "dependencies": {
-            "readable-stream": {
-              "version": "1.0.33",
-              "from": "readable-stream@~1.0.2",
-              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz",
-              "dependencies": {
-                "core-util-is": {
-                  "version": "1.0.1",
-                  "from": "core-util-is@~1.0.0",
-                  "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-                },
-                "inherits": {
-                  "version": "2.0.1",
-                  "from": "inherits@~2.0.1",
-                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                },
-                "isarray": {
-                  "version": "0.0.1",
-                  "from": "isarray@0.0.1",
-                  "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
-                },
-                "string_decoder": {
-                  "version": "0.10.31",
-                  "from": "string_decoder@~0.10.x",
-                  "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
-                }
-              }
-            },
-            "rimraf": {
-              "version": "2.2.8",
-              "from": "rimraf@~2.2.0",
-              "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz"
-            }
-          }
+        "tunnel-agent": {
+          "version": "0.4.1",
+          "from": "tunnel-agent@~0.4.1",
+          "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz"
         },
         "tough-cookie": {
           "version": "2.2.0",
           "from": "tough-cookie@~2.2.0",
           "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.0.tgz"
         },
-        "tunnel-agent": {
-          "version": "0.4.1",
-          "from": "tunnel-agent@~0.4.1",
-          "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz"
-        },
         "uid-number": {
           "version": "0.0.3",
           "from": "uid-number@0.0.3",
@@ -2373,57 +2234,196 @@
           "version": "4.0.1",
           "from": "xtend@^4.0.0",
           "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz"
-        }
-      }
-    },
-    "get-stdin": {
-      "version": "4.0.1",
-      "from": "get-stdin@>=4.0.1 <5.0.0",
-      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz"
-    },
-    "glob": {
-      "version": "5.0.15",
-      "from": "glob@>=5.0.15 <6.0.0",
-      "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz"
-    },
-    "glob-base": {
-      "version": "0.3.0",
-      "from": "glob-base@>=0.3.0 <0.4.0",
-      "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz"
-    },
-    "glob-parent": {
-      "version": "2.0.0",
-      "from": "glob-parent@>=2.0.0 <3.0.0",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz"
-    },
-    "globals": {
-      "version": "8.11.0",
-      "from": "globals@>=8.3.0 <9.0.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-8.11.0.tgz"
-    },
-    "glogg": {
-      "version": "1.0.0",
-      "from": "glogg@>=1.0.0 <2.0.0",
-      "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.0.tgz"
-    },
-    "graceful-fs": {
-      "version": "4.1.2",
-      "from": "graceful-fs@>=4.1.2 <5.0.0",
-      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.2.tgz"
-    },
-    "graceful-readlink": {
-      "version": "1.0.1",
-      "from": "graceful-readlink@>=1.0.0",
-      "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
-    },
-    "gulp-util": {
-      "version": "3.0.7",
-      "from": "gulp-util@>=3.0.4 <4.0.0",
-      "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.7.tgz",
-      "dependencies": {
-        "chalk": {
-          "version": "1.1.1",
-          "from": "chalk@>=1.0.0 <2.0.0"
+        },
+        "fstream-ignore": {
+          "version": "1.0.3",
+          "from": "fstream-ignore@~1.0.3",
+          "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.3.tgz",
+          "dependencies": {
+            "minimatch": {
+              "version": "3.0.0",
+              "from": "minimatch@>=3.0.0 <4.0.0"
+            }
+          }
+        },
+        "inflight": {
+          "version": "1.0.4",
+          "from": "inflight@>=1.0.4 <2.0.0",
+          "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz",
+          "dependencies": {
+            "once": {
+              "version": "1.3.2",
+              "from": "once@>=1.3.0 <2.0.0"
+            }
+          }
+        },
+        "rc": {
+          "version": "1.1.2",
+          "from": "rc@~1.1.0",
+          "resolved": "https://registry.npmjs.org/rc/-/rc-1.1.2.tgz",
+          "dependencies": {
+            "minimist": {
+              "version": "1.2.0",
+              "from": "minimist@^1.1.2",
+              "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
+            }
+          }
+        },
+        "rimraf": {
+          "version": "2.4.3",
+          "from": "rimraf@~2.4.0",
+          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.3.tgz",
+          "dependencies": {
+            "glob": {
+              "version": "5.0.15",
+              "from": "glob@>=5.0.14 <6.0.0",
+              "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz"
+            },
+            "minimatch": {
+              "version": "3.0.0",
+              "from": "minimatch@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0",
+              "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.0.tgz"
+            },
+            "once": {
+              "version": "1.3.2",
+              "from": "once@>=1.3.0 <2.0.0",
+              "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz"
+            }
+          }
+        },
+        "bl": {
+          "version": "1.0.0",
+          "from": "bl@~1.0.0",
+          "resolved": "https://registry.npmjs.org/bl/-/bl-1.0.0.tgz",
+          "dependencies": {
+            "readable-stream": {
+              "version": "2.0.4",
+              "from": "readable-stream@~2.0.0",
+              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.4.tgz",
+              "dependencies": {
+                "core-util-is": {
+                  "version": "1.0.1",
+                  "from": "core-util-is@~1.0.0",
+                  "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
+                },
+                "inherits": {
+                  "version": "2.0.1",
+                  "from": "inherits@~2.0.1",
+                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
+                },
+                "isarray": {
+                  "version": "0.0.1",
+                  "from": "isarray@0.0.1",
+                  "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
+                },
+                "process-nextick-args": {
+                  "version": "1.0.3",
+                  "from": "process-nextick-args@~1.0.0",
+                  "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.3.tgz"
+                },
+                "string_decoder": {
+                  "version": "0.10.31",
+                  "from": "string_decoder@~0.10.x",
+                  "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
+                },
+                "util-deprecate": {
+                  "version": "1.0.2",
+                  "from": "util-deprecate@~1.0.1",
+                  "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
+                }
+              }
+            }
+          }
+        },
+        "tar-pack": {
+          "version": "3.1.0",
+          "from": "tar-pack@~3.1.0",
+          "resolved": "https://registry.npmjs.org/tar-pack/-/tar-pack-3.1.0.tgz",
+          "dependencies": {
+            "readable-stream": {
+              "version": "1.0.33",
+              "from": "readable-stream@~1.0.2",
+              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz",
+              "dependencies": {
+                "core-util-is": {
+                  "version": "1.0.1",
+                  "from": "core-util-is@~1.0.0",
+                  "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
+                },
+                "inherits": {
+                  "version": "2.0.1",
+                  "from": "inherits@~2.0.1",
+                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
+                },
+                "isarray": {
+                  "version": "0.0.1",
+                  "from": "isarray@0.0.1",
+                  "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
+                },
+                "string_decoder": {
+                  "version": "0.10.31",
+                  "from": "string_decoder@~0.10.x",
+                  "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
+                }
+              }
+            },
+            "rimraf": {
+              "version": "2.2.8",
+              "from": "rimraf@~2.2.0",
+              "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz"
+            }
+          }
+        }
+      }
+    },
+    "get-stdin": {
+      "version": "4.0.1",
+      "from": "get-stdin@>=4.0.1 <5.0.0",
+      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz"
+    },
+    "glob": {
+      "version": "5.0.15",
+      "from": "glob@>=5.0.15 <6.0.0",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz"
+    },
+    "glob-base": {
+      "version": "0.3.0",
+      "from": "glob-base@>=0.3.0 <0.4.0",
+      "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz"
+    },
+    "glob-parent": {
+      "version": "2.0.0",
+      "from": "glob-parent@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz"
+    },
+    "globals": {
+      "version": "8.11.0",
+      "from": "globals@>=8.3.0 <9.0.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-8.11.0.tgz"
+    },
+    "glogg": {
+      "version": "1.0.0",
+      "from": "glogg@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.0.tgz"
+    },
+    "graceful-fs": {
+      "version": "4.1.2",
+      "from": "graceful-fs@>=4.1.2 <5.0.0",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.2.tgz"
+    },
+    "graceful-readlink": {
+      "version": "1.0.1",
+      "from": "graceful-readlink@>=1.0.0",
+      "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
+    },
+    "gulp-util": {
+      "version": "3.0.7",
+      "from": "gulp-util@>=3.0.4 <4.0.0",
+      "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.7.tgz",
+      "dependencies": {
+        "chalk": {
+          "version": "1.1.1",
+          "from": "chalk@>=1.0.0 <2.0.0"
         },
         "object-assign": {
           "version": "3.0.0",
@@ -2585,8 +2585,8 @@
       "resolved": "https://registry.npmjs.org/isobject/-/isobject-1.0.2.tgz"
     },
     "jest-cli": {
-      "version": "0.7.1",
-      "from": "jest-cli@0.7.1",
+      "version": "0.8.2",
+      "from": "jest-cli@0.8.2",
       "dependencies": {
         "cover": {
           "version": "0.2.9",
@@ -2623,13 +2623,9 @@
           }
         },
         "diff": {
-          "version": "2.2.0",
+          "version": "2.2.1",
           "from": "diff@>=2.1.1 <3.0.0",
-          "resolved": "https://registry.npmjs.org/diff/-/diff-2.2.0.tgz"
-        },
-        "graceful-fs": {
-          "version": "4.1.2",
-          "from": "graceful-fs@>=4.1.2 <5.0.0"
+          "resolved": "https://registry.npmjs.org/diff/-/diff-2.2.1.tgz"
         },
         "istanbul": {
           "version": "0.3.22",
@@ -2647,73 +2643,61 @@
               "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz"
             },
             "escodegen": {
-              "version": "1.7.0",
+              "version": "1.7.1",
               "from": "escodegen@>=1.7.0 <1.8.0",
-              "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.0.tgz",
+              "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.1.tgz",
               "dependencies": {
-                "esprima": {
-                  "version": "1.2.5",
-                  "from": "esprima@>=1.2.2 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz"
-                },
                 "estraverse": {
                   "version": "1.9.3",
                   "from": "estraverse@>=1.9.1 <2.0.0",
                   "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz"
                 },
-                "esutils": {
-                  "version": "2.0.2",
-                  "from": "esutils@>=2.0.2 <3.0.0",
-                  "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz"
+                "esprima": {
+                  "version": "1.2.5",
+                  "from": "esprima@>=1.2.2 <2.0.0",
+                  "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz"
                 },
                 "optionator": {
                   "version": "0.5.0",
                   "from": "optionator@>=0.5.0 <0.6.0",
                   "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz",
                   "dependencies": {
+                    "prelude-ls": {
+                      "version": "1.1.2",
+                      "from": "prelude-ls@>=1.1.1 <1.2.0",
+                      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz"
+                    },
                     "deep-is": {
                       "version": "0.1.3",
                       "from": "deep-is@>=0.1.2 <0.2.0",
                       "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz"
                     },
-                    "fast-levenshtein": {
-                      "version": "1.0.7",
-                      "from": "fast-levenshtein@>=1.0.0 <1.1.0",
-                      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz"
-                    },
-                    "levn": {
-                      "version": "0.2.5",
-                      "from": "levn@>=0.2.5 <0.3.0",
-                      "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz"
-                    },
-                    "prelude-ls": {
-                      "version": "1.1.2",
-                      "from": "prelude-ls@>=1.1.1 <1.2.0",
-                      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz"
+                    "wordwrap": {
+                      "version": "0.0.3",
+                      "from": "wordwrap@>=0.0.2 <0.1.0",
+                      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
                     },
                     "type-check": {
                       "version": "0.3.1",
                       "from": "type-check@>=0.3.1 <0.4.0",
                       "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz"
                     },
-                    "wordwrap": {
-                      "version": "0.0.3",
-                      "from": "wordwrap@>=0.0.2 <0.1.0",
-                      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
+                    "levn": {
+                      "version": "0.2.5",
+                      "from": "levn@>=0.2.5 <0.3.0",
+                      "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz"
+                    },
+                    "fast-levenshtein": {
+                      "version": "1.0.7",
+                      "from": "fast-levenshtein@>=1.0.0 <1.1.0",
+                      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz"
                     }
                   }
                 },
                 "source-map": {
                   "version": "0.2.0",
                   "from": "source-map@>=0.2.0 <0.3.0",
-                  "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz",
-                  "dependencies": {
-                    "amdefine": {
-                      "version": "1.0.0",
-                      "from": "amdefine@>=0.0.4",
-                      "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz"
-                    }
-                  }
+                  "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz"
                 }
               }
             },
@@ -2725,56 +2709,42 @@
             "fileset": {
               "version": "0.2.1",
               "from": "fileset@>=0.2.0 <0.3.0",
-              "resolved": "https://registry.npmjs.org/fileset/-/fileset-0.2.1.tgz",
+              "resolved": "https://registry.npmjs.org/fileset/-/fileset-0.2.1.tgz"
+            },
+            "handlebars": {
+              "version": "4.0.5",
+              "from": "handlebars@>=4.0.1 <5.0.0",
+              "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.5.tgz",
               "dependencies": {
-                "glob": {
-                  "version": "5.0.15",
-                  "from": "glob@>=5.0.0 <6.0.0",
-                  "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
+                "uglify-js": {
+                  "version": "2.6.1",
+                  "from": "uglify-js@>=2.6.0 <3.0.0",
+                  "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.1.tgz",
                   "dependencies": {
-                    "inflight": {
-                      "version": "1.0.4",
-                      "from": "inflight@>=1.0.4 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz",
-                      "dependencies": {
-                        "wrappy": {
-                          "version": "1.0.1",
-                          "from": "wrappy@>=1.0.0 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
-                        }
-                      }
+                    "async": {
+                      "version": "0.2.10",
+                      "from": "async@>=0.2.6 <0.3.0",
+                      "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz"
                     },
-                    "inherits": {
-                      "version": "2.0.1",
-                      "from": "inherits@>=2.0.0 <3.0.0",
-                      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
+                    "source-map": {
+                      "version": "0.5.3",
+                      "from": "source-map@>=0.5.1 <0.6.0",
+                      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz"
                     },
-                    "path-is-absolute": {
-                      "version": "1.0.0",
-                      "from": "path-is-absolute@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz"
-                    }
-                  }
-                },
-                "minimatch": {
-                  "version": "2.0.10",
-                  "from": "minimatch@>=2.0.0 <3.0.0",
-                  "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz",
-                  "dependencies": {
-                    "brace-expansion": {
-                      "version": "1.1.1",
-                      "from": "brace-expansion@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz",
+                    "uglify-to-browserify": {
+                      "version": "1.0.2",
+                      "from": "uglify-to-browserify@>=1.0.0 <1.1.0",
+                      "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz"
+                    },
+                    "yargs": {
+                      "version": "3.10.0",
+                      "from": "yargs@>=3.10.0 <3.11.0",
+                      "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
                       "dependencies": {
-                        "balanced-match": {
-                          "version": "0.2.1",
-                          "from": "balanced-match@>=0.2.0 <0.3.0",
-                          "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.1.tgz"
-                        },
-                        "concat-map": {
-                          "version": "0.0.1",
-                          "from": "concat-map@0.0.1",
-                          "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
+                        "window-size": {
+                          "version": "0.1.0",
+                          "from": "window-size@0.1.0",
+                          "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz"
                         }
                       }
                     }
@@ -2782,32 +2752,16 @@
                 }
               }
             },
-            "handlebars": {
-              "version": "4.0.4",
-              "from": "handlebars@>=4.0.1 <5.0.0",
-              "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.4.tgz",
-              "dependencies": {
-                "source-map": {
-                  "version": "0.4.4",
-                  "from": "source-map@>=0.4.4 <0.5.0"
-                }
-              }
-            },
             "js-yaml": {
-              "version": "3.4.3",
+              "version": "3.4.6",
               "from": "js-yaml@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.4.3.tgz",
+              "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.4.6.tgz",
               "dependencies": {
                 "argparse": {
                   "version": "1.0.3",
                   "from": "argparse@>=1.0.2 <2.0.0",
                   "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.3.tgz",
                   "dependencies": {
-                    "lodash": {
-                      "version": "3.10.1",
-                      "from": "lodash@>=3.2.0 <4.0.0",
-                      "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz"
-                    },
                     "sprintf-js": {
                       "version": "1.0.3",
                       "from": "sprintf-js@>=1.0.2 <1.1.0",
@@ -2816,28 +2770,21 @@
                   }
                 },
                 "esprima": {
-                  "version": "2.7.0",
+                  "version": "2.7.1",
                   "from": "esprima@>=2.6.0 <3.0.0",
-                  "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.0.tgz"
+                  "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.1.tgz"
+                },
+                "inherit": {
+                  "version": "2.2.2",
+                  "from": "inherit@>=2.2.2 <3.0.0",
+                  "resolved": "https://registry.npmjs.org/inherit/-/inherit-2.2.2.tgz"
                 }
               }
             },
             "nopt": {
-              "version": "3.0.4",
+              "version": "3.0.6",
               "from": "nopt@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.4.tgz"
-            },
-            "once": {
-              "version": "1.3.2",
-              "from": "once@>=1.0.0 <2.0.0",
-              "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz",
-              "dependencies": {
-                "wrappy": {
-                  "version": "1.0.1",
-                  "from": "wrappy@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
-                }
-              }
+              "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz"
             },
             "supports-color": {
               "version": "3.1.2",
@@ -2853,36 +2800,26 @@
             }
           }
         },
-        "jasmine-pit": {
-          "version": "2.0.2",
-          "from": "jasmine-pit@>=2.0.2 <3.0.0",
-          "resolved": "https://registry.npmjs.org/jasmine-pit/-/jasmine-pit-2.0.2.tgz"
-        },
         "jsdom": {
-          "version": "7.0.2",
-          "from": "jsdom@7.0.2",
-          "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-7.0.2.tgz",
+          "version": "7.2.1",
+          "from": "jsdom@>=7.2.0 <8.0.0",
+          "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-7.2.1.tgz",
           "dependencies": {
             "abab": {
-              "version": "1.0.0",
+              "version": "1.0.1",
               "from": "abab@>=1.0.0 <2.0.0",
-              "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.0.tgz"
+              "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.1.tgz"
             },
             "acorn": {
-              "version": "2.5.2",
+              "version": "2.6.4",
               "from": "acorn@>=2.4.0 <3.0.0",
-              "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.5.2.tgz"
+              "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.6.4.tgz"
             },
             "acorn-globals": {
               "version": "1.0.9",
               "from": "acorn-globals@>=1.0.4 <2.0.0",
               "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz"
             },
-            "browser-request": {
-              "version": "0.3.3",
-              "from": "browser-request@>=0.3.1 <0.4.0",
-              "resolved": "https://registry.npmjs.org/browser-request/-/browser-request-0.3.3.tgz"
-            },
             "cssom": {
               "version": "0.3.0",
               "from": "cssom@>=0.3.0 <0.4.0",
@@ -2894,230 +2831,89 @@
               "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.30.tgz"
             },
             "escodegen": {
-              "version": "1.7.0",
+              "version": "1.7.1",
               "from": "escodegen@>=1.6.1 <2.0.0",
-              "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.0.tgz",
+              "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.1.tgz",
               "dependencies": {
-                "esprima": {
-                  "version": "1.2.5",
-                  "from": "esprima@>=1.2.2 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz"
-                },
                 "estraverse": {
                   "version": "1.9.3",
                   "from": "estraverse@>=1.9.1 <2.0.0",
                   "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz"
                 },
-                "esutils": {
-                  "version": "2.0.2",
-                  "from": "esutils@>=2.0.2 <3.0.0",
-                  "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz"
+                "esprima": {
+                  "version": "1.2.5",
+                  "from": "esprima@>=1.2.2 <2.0.0",
+                  "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz"
                 },
                 "optionator": {
                   "version": "0.5.0",
                   "from": "optionator@>=0.5.0 <0.6.0",
                   "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz",
                   "dependencies": {
+                    "prelude-ls": {
+                      "version": "1.1.2",
+                      "from": "prelude-ls@>=1.1.1 <1.2.0",
+                      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz"
+                    },
                     "deep-is": {
                       "version": "0.1.3",
                       "from": "deep-is@>=0.1.2 <0.2.0",
                       "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz"
                     },
-                    "fast-levenshtein": {
-                      "version": "1.0.7",
-                      "from": "fast-levenshtein@>=1.0.0 <1.1.0",
-                      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz"
-                    },
-                    "levn": {
-                      "version": "0.2.5",
-                      "from": "levn@>=0.2.5 <0.3.0",
-                      "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz"
-                    },
-                    "prelude-ls": {
-                      "version": "1.1.2",
-                      "from": "prelude-ls@>=1.1.1 <1.2.0",
-                      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz"
+                    "wordwrap": {
+                      "version": "0.0.3",
+                      "from": "wordwrap@>=0.0.2 <0.1.0",
+                      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
                     },
                     "type-check": {
                       "version": "0.3.1",
                       "from": "type-check@>=0.3.1 <0.4.0",
                       "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz"
                     },
-                    "wordwrap": {
-                      "version": "0.0.3",
-                      "from": "wordwrap@>=0.0.2 <0.1.0",
-                      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
+                    "levn": {
+                      "version": "0.2.5",
+                      "from": "levn@>=0.2.5 <0.3.0",
+                      "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz"
+                    },
+                    "fast-levenshtein": {
+                      "version": "1.0.7",
+                      "from": "fast-levenshtein@>=1.0.0 <1.1.0",
+                      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz"
                     }
                   }
                 },
                 "source-map": {
                   "version": "0.2.0",
                   "from": "source-map@>=0.2.0 <0.3.0",
-                  "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz",
-                  "dependencies": {
-                    "amdefine": {
-                      "version": "1.0.0",
-                      "from": "amdefine@>=0.0.4",
-                      "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz"
-                    }
-                  }
-                }
-              }
-            },
-            "htmlparser2": {
-              "version": "3.8.3",
-              "from": "htmlparser2@>=3.7.3 <4.0.0",
-              "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz",
-              "dependencies": {
-                "domelementtype": {
-                  "version": "1.3.0",
-                  "from": "domelementtype@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz"
-                },
-                "domhandler": {
-                  "version": "2.3.0",
-                  "from": "domhandler@>=2.3.0 <2.4.0",
-                  "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz"
-                },
-                "domutils": {
-                  "version": "1.5.1",
-                  "from": "domutils@>=1.5.0 <1.6.0",
-                  "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
-                  "dependencies": {
-                    "dom-serializer": {
-                      "version": "0.1.0",
-                      "from": "dom-serializer@>=0.0.0 <1.0.0",
-                      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
-                      "dependencies": {
-                        "domelementtype": {
-                          "version": "1.1.3",
-                          "from": "domelementtype@>=1.1.1 <1.2.0",
-                          "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz"
-                        },
-                        "entities": {
-                          "version": "1.1.1",
-                          "from": "entities@>=1.1.1 <1.2.0",
-                          "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz"
-                        }
-                      }
-                    }
-                  }
-                },
-                "entities": {
-                  "version": "1.0.0",
-                  "from": "entities@>=1.0.0 <1.1.0",
-                  "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz"
-                },
-                "readable-stream": {
-                  "version": "1.1.13",
-                  "from": "readable-stream@>=1.1.0 <1.2.0",
-                  "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz",
-                  "dependencies": {
-                    "core-util-is": {
-                      "version": "1.0.1",
-                      "from": "core-util-is@>=1.0.0 <1.1.0",
-                      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-                    },
-                    "inherits": {
-                      "version": "2.0.1",
-                      "from": "inherits@>=2.0.1 <2.1.0",
-                      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                    },
-                    "isarray": {
-                      "version": "0.0.1",
-                      "from": "isarray@0.0.1",
-                      "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
-                    },
-                    "string_decoder": {
-                      "version": "0.10.31",
-                      "from": "string_decoder@>=0.10.0 <0.11.0",
-                      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
-                    }
-                  }
+                  "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz"
                 }
               }
             },
             "nwmatcher": {
-              "version": "1.3.6",
-              "from": "nwmatcher@>=1.3.6 <2.0.0",
-              "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.3.6.tgz"
+              "version": "1.3.7",
+              "from": "nwmatcher@>=1.3.7 <2.0.0",
+              "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.3.7.tgz"
             },
             "parse5": {
-              "version": "1.5.0",
-              "from": "parse5@>=1.4.2 <2.0.0",
-              "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.0.tgz"
+              "version": "1.5.1",
+              "from": "parse5@>=1.5.1 <2.0.0",
+              "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz"
             },
             "request": {
-              "version": "2.65.0",
+              "version": "2.67.0",
               "from": "request@>=2.55.0 <3.0.0",
-              "resolved": "https://registry.npmjs.org/request/-/request-2.65.0.tgz",
+              "resolved": "https://registry.npmjs.org/request/-/request-2.67.0.tgz",
               "dependencies": {
-                "aws-sign2": {
-                  "version": "0.6.0",
-                  "from": "aws-sign2@>=0.6.0 <0.7.0",
-                  "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
-                },
                 "bl": {
                   "version": "1.0.0",
                   "from": "bl@>=1.0.0 <1.1.0",
-                  "resolved": "https://registry.npmjs.org/bl/-/bl-1.0.0.tgz",
-                  "dependencies": {
-                    "readable-stream": {
-                      "version": "2.0.4",
-                      "from": "readable-stream@>=2.0.0 <2.1.0",
-                      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.4.tgz",
-                      "dependencies": {
-                        "core-util-is": {
-                          "version": "1.0.1",
-                          "from": "core-util-is@>=1.0.0 <1.1.0",
-                          "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-                        },
-                        "inherits": {
-                          "version": "2.0.1",
-                          "from": "inherits@>=2.0.1 <2.1.0",
-                          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                        },
-                        "isarray": {
-                          "version": "0.0.1",
-                          "from": "isarray@0.0.1",
-                          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
-                        },
-                        "process-nextick-args": {
-                          "version": "1.0.3",
-                          "from": "process-nextick-args@>=1.0.0 <1.1.0",
-                          "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.3.tgz"
-                        },
-                        "string_decoder": {
-                          "version": "0.10.31",
-                          "from": "string_decoder@>=0.10.0 <0.11.0",
-                          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
-                        },
-                        "util-deprecate": {
-                          "version": "1.0.2",
-                          "from": "util-deprecate@>=1.0.1 <1.1.0",
-                          "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
-                        }
-                      }
-                    }
-                  }
+                  "resolved": "https://registry.npmjs.org/bl/-/bl-1.0.0.tgz"
                 },
                 "caseless": {
                   "version": "0.11.0",
                   "from": "caseless@>=0.11.0 <0.12.0",
                   "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
                 },
-                "combined-stream": {
-                  "version": "1.0.5",
-                  "from": "combined-stream@>=1.0.5 <1.1.0",
-                  "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
-                  "dependencies": {
-                    "delayed-stream": {
-                      "version": "1.0.0",
-                      "from": "delayed-stream@>=1.0.0 <1.1.0",
-                      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
-                    }
-                  }
-                },
                 "extend": {
                   "version": "3.0.0",
                   "from": "extend@>=3.0.0 <3.1.0",
@@ -3140,83 +2936,139 @@
                     }
                   }
                 },
-                "har-validator": {
-                  "version": "2.0.2",
-                  "from": "har-validator@>=2.0.2 <2.1.0",
-                  "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.2.tgz",
+                "json-stringify-safe": {
+                  "version": "5.0.1",
+                  "from": "json-stringify-safe@>=5.0.1 <5.1.0",
+                  "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
+                },
+                "mime-types": {
+                  "version": "2.1.8",
+                  "from": "mime-types@>=2.1.7 <2.2.0",
+                  "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.8.tgz",
                   "dependencies": {
-                    "chalk": {
-                      "version": "1.1.1",
-                      "from": "chalk@>=1.1.1 <2.0.0"
+                    "mime-db": {
+                      "version": "1.20.0",
+                      "from": "mime-db@>=1.20.0 <1.21.0",
+                      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.20.0.tgz"
+                    }
+                  }
+                },
+                "node-uuid": {
+                  "version": "1.4.7",
+                  "from": "node-uuid@>=1.4.7 <1.5.0",
+                  "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz"
+                },
+                "qs": {
+                  "version": "5.2.0",
+                  "from": "qs@>=5.2.0 <5.3.0",
+                  "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz"
+                },
+                "tunnel-agent": {
+                  "version": "0.4.2",
+                  "from": "tunnel-agent@>=0.4.1 <0.5.0",
+                  "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.2.tgz"
+                },
+                "http-signature": {
+                  "version": "1.1.0",
+                  "from": "http-signature@>=1.1.0 <1.2.0",
+                  "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.0.tgz",
+                  "dependencies": {
+                    "assert-plus": {
+                      "version": "0.1.5",
+                      "from": "assert-plus@>=0.1.5 <0.2.0",
+                      "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
                     },
-                    "commander": {
-                      "version": "2.9.0",
-                      "from": "commander@>=2.8.1 <3.0.0",
-                      "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
+                    "jsprim": {
+                      "version": "1.2.2",
+                      "from": "jsprim@>=1.2.2 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.2.2.tgz",
                       "dependencies": {
-                        "graceful-readlink": {
-                          "version": "1.0.1",
-                          "from": "graceful-readlink@>=1.0.0",
-                          "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
+                        "extsprintf": {
+                          "version": "1.0.2",
+                          "from": "extsprintf@1.0.2",
+                          "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz"
+                        },
+                        "json-schema": {
+                          "version": "0.2.2",
+                          "from": "json-schema@0.2.2",
+                          "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.2.tgz"
+                        },
+                        "verror": {
+                          "version": "1.3.6",
+                          "from": "verror@1.3.6",
+                          "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz"
                         }
                       }
                     },
-                    "is-my-json-valid": {
-                      "version": "2.12.2",
-                      "from": "is-my-json-valid@>=2.12.2 <3.0.0",
-                      "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.2.tgz",
+                    "sshpk": {
+                      "version": "1.7.1",
+                      "from": "sshpk@>=1.7.0 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.7.1.tgz",
                       "dependencies": {
-                        "generate-function": {
-                          "version": "2.0.0",
-                          "from": "generate-function@>=2.0.0 <3.0.0",
-                          "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz"
+                        "asn1": {
+                          "version": "0.2.3",
+                          "from": "asn1@>=0.2.3 <0.3.0",
+                          "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz"
                         },
-                        "generate-object-property": {
-                          "version": "1.2.0",
-                          "from": "generate-object-property@>=1.1.0 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
+                        "assert-plus": {
+                          "version": "0.2.0",
+                          "from": "assert-plus@>=0.2.0 <0.3.0",
+                          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz"
+                        },
+                        "dashdash": {
+                          "version": "1.10.1",
+                          "from": "dashdash@>=1.10.1 <2.0.0",
+                          "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.10.1.tgz",
                           "dependencies": {
-                            "is-property": {
-                              "version": "1.0.2",
-                              "from": "is-property@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz"
+                            "assert-plus": {
+                              "version": "0.1.5",
+                              "from": "assert-plus@>=0.1.0 <0.2.0",
+                              "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
                             }
                           }
                         },
-                        "jsonpointer": {
-                          "version": "2.0.0",
-                          "from": "jsonpointer@2.0.0",
-                          "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
+                        "jsbn": {
+                          "version": "0.1.0",
+                          "from": "jsbn@>=0.1.0 <0.2.0",
+                          "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz"
                         },
-                        "xtend": {
-                          "version": "4.0.1",
-                          "from": "xtend@>=4.0.0 <5.0.0",
-                          "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz"
-                        }
-                      }
-                    },
-                    "pinkie-promise": {
-                      "version": "1.0.0",
-                      "from": "pinkie-promise@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz",
-                      "dependencies": {
-                        "pinkie": {
-                          "version": "1.0.0",
-                          "from": "pinkie@>=1.0.0 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
+                        "tweetnacl": {
+                          "version": "0.13.2",
+                          "from": "tweetnacl@>=0.13.0 <1.0.0",
+                          "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.13.2.tgz"
+                        },
+                        "jodid25519": {
+                          "version": "1.0.2",
+                          "from": "jodid25519@>=1.0.0 <2.0.0",
+                          "resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz"
+                        },
+                        "ecc-jsbn": {
+                          "version": "0.1.1",
+                          "from": "ecc-jsbn@>=0.0.1 <1.0.0",
+                          "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz"
                         }
                       }
                     }
                   }
                 },
+                "oauth-sign": {
+                  "version": "0.8.0",
+                  "from": "oauth-sign@>=0.8.0 <0.9.0",
+                  "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.0.tgz"
+                },
                 "hawk": {
-                  "version": "3.1.0",
+                  "version": "3.1.2",
                   "from": "hawk@>=3.1.0 <3.2.0",
-                  "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.0.tgz",
+                  "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.2.tgz",
                   "dependencies": {
+                    "hoek": {
+                      "version": "2.16.3",
+                      "from": "hoek@>=2.0.0 <3.0.0",
+                      "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz"
+                    },
                     "boom": {
                       "version": "2.10.1",
-                      "from": "boom@>=2.8.0 <3.0.0",
+                      "from": "boom@>=2.0.0 <3.0.0",
                       "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz"
                     },
                     "cryptiles": {
@@ -3224,11 +3076,6 @@
                       "from": "cryptiles@>=2.0.0 <3.0.0",
                       "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz"
                     },
-                    "hoek": {
-                      "version": "2.16.3",
-                      "from": "hoek@>=2.0.0 <3.0.0",
-                      "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz"
-                    },
                     "sntp": {
                       "version": "1.0.9",
                       "from": "sntp@>=1.0.0 <2.0.0",
@@ -3236,25 +3083,25 @@
                     }
                   }
                 },
-                "http-signature": {
-                  "version": "0.11.0",
-                  "from": "http-signature@>=0.11.0 <0.12.0",
-                  "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.11.0.tgz",
+                "aws-sign2": {
+                  "version": "0.6.0",
+                  "from": "aws-sign2@>=0.6.0 <0.7.0",
+                  "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
+                },
+                "stringstream": {
+                  "version": "0.0.5",
+                  "from": "stringstream@>=0.0.4 <0.1.0",
+                  "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
+                },
+                "combined-stream": {
+                  "version": "1.0.5",
+                  "from": "combined-stream@>=1.0.5 <1.1.0",
+                  "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
                   "dependencies": {
-                    "asn1": {
-                      "version": "0.1.11",
-                      "from": "asn1@0.1.11",
-                      "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
-                    },
-                    "assert-plus": {
-                      "version": "0.1.5",
-                      "from": "assert-plus@>=0.1.5 <0.2.0",
-                      "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
-                    },
-                    "ctype": {
-                      "version": "0.5.3",
-                      "from": "ctype@0.5.3",
-                      "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz"
+                    "delayed-stream": {
+                      "version": "1.0.0",
+                      "from": "delayed-stream@>=1.0.0 <1.1.0",
+                      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
                     }
                   }
                 },
@@ -3263,64 +3110,80 @@
                   "from": "isstream@>=0.1.2 <0.2.0",
                   "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
                 },
-                "json-stringify-safe": {
-                  "version": "5.0.1",
-                  "from": "json-stringify-safe@>=5.0.1 <5.1.0",
-                  "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
+                "is-typedarray": {
+                  "version": "1.0.0",
+                  "from": "is-typedarray@>=1.0.0 <1.1.0",
+                  "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz"
                 },
-                "mime-types": {
-                  "version": "2.1.7",
-                  "from": "mime-types@>=2.1.7 <2.2.0",
-                  "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.7.tgz",
+                "har-validator": {
+                  "version": "2.0.3",
+                  "from": "har-validator@>=2.0.2 <2.1.0",
+                  "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.3.tgz",
                   "dependencies": {
-                    "mime-db": {
-                      "version": "1.19.0",
-                      "from": "mime-db@>=1.19.0 <1.20.0",
-                      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.19.0.tgz"
+                    "is-my-json-valid": {
+                      "version": "2.12.3",
+                      "from": "is-my-json-valid@>=2.12.3 <3.0.0",
+                      "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.3.tgz",
+                      "dependencies": {
+                        "generate-function": {
+                          "version": "2.0.0",
+                          "from": "generate-function@>=2.0.0 <3.0.0",
+                          "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz"
+                        },
+                        "generate-object-property": {
+                          "version": "1.2.0",
+                          "from": "generate-object-property@>=1.1.0 <2.0.0",
+                          "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
+                          "dependencies": {
+                            "is-property": {
+                              "version": "1.0.2",
+                              "from": "is-property@>=1.0.0 <2.0.0",
+                              "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz"
+                            }
+                          }
+                        },
+                        "jsonpointer": {
+                          "version": "2.0.0",
+                          "from": "jsonpointer@2.0.0",
+                          "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
+                        }
+                      }
+                    },
+                    "pinkie-promise": {
+                      "version": "2.0.0",
+                      "from": "pinkie-promise@>=2.0.0 <3.0.0",
+                      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.0.tgz",
+                      "dependencies": {
+                        "pinkie": {
+                          "version": "2.0.1",
+                          "from": "pinkie@>=2.0.0 <3.0.0",
+                          "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.1.tgz"
+                        }
+                      }
                     }
                   }
-                },
-                "node-uuid": {
-                  "version": "1.4.3",
-                  "from": "node-uuid@>=1.4.3 <1.5.0",
-                  "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.3.tgz"
-                },
-                "oauth-sign": {
-                  "version": "0.8.0",
-                  "from": "oauth-sign@>=0.8.0 <0.9.0",
-                  "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.0.tgz"
-                },
-                "qs": {
-                  "version": "5.2.0",
-                  "from": "qs@>=5.2.0 <5.3.0",
-                  "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz"
-                },
-                "stringstream": {
-                  "version": "0.0.5",
-                  "from": "stringstream@>=0.0.4 <0.1.0",
-                  "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
-                },
-                "tunnel-agent": {
-                  "version": "0.4.1",
-                  "from": "tunnel-agent@>=0.4.1 <0.5.0",
-                  "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz"
                 }
               }
             },
+            "sax": {
+              "version": "1.1.4",
+              "from": "sax@>=1.1.4 <2.0.0",
+              "resolved": "https://registry.npmjs.org/sax/-/sax-1.1.4.tgz"
+            },
             "symbol-tree": {
-              "version": "3.1.3",
+              "version": "3.1.4",
               "from": "symbol-tree@>=3.1.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.1.3.tgz"
+              "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.1.4.tgz"
             },
             "tough-cookie": {
-              "version": "2.2.0",
+              "version": "2.2.1",
               "from": "tough-cookie@>=2.2.0 <3.0.0",
-              "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.0.tgz"
+              "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.1.tgz"
             },
             "webidl-conversions": {
-              "version": "2.0.0",
+              "version": "2.0.1",
               "from": "webidl-conversions@>=2.0.0 <3.0.0",
-              "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-2.0.0.tgz"
+              "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-2.0.1.tgz"
             },
             "whatwg-url-compat": {
               "version": "0.6.5",
@@ -3353,87 +3216,6 @@
             }
           }
         },
-        "lodash.template": {
-          "version": "3.6.2",
-          "from": "lodash.template@>=3.6.2 <4.0.0",
-          "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz",
-          "dependencies": {
-            "lodash._basecopy": {
-              "version": "3.0.1",
-              "from": "lodash._basecopy@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz"
-            },
-            "lodash._basetostring": {
-              "version": "3.0.1",
-              "from": "lodash._basetostring@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz"
-            },
-            "lodash._basevalues": {
-              "version": "3.0.0",
-              "from": "lodash._basevalues@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz"
-            },
-            "lodash._isiterateecall": {
-              "version": "3.0.9",
-              "from": "lodash._isiterateecall@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz"
-            },
-            "lodash._reinterpolate": {
-              "version": "3.0.0",
-              "from": "lodash._reinterpolate@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz"
-            },
-            "lodash.escape": {
-              "version": "3.0.0",
-              "from": "lodash.escape@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.0.0.tgz"
-            },
-            "lodash.keys": {
-              "version": "3.1.2",
-              "from": "lodash.keys@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",
-              "dependencies": {
-                "lodash._getnative": {
-                  "version": "3.9.1",
-                  "from": "lodash._getnative@>=3.0.0 <4.0.0",
-                  "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz"
-                },
-                "lodash.isarguments": {
-                  "version": "3.0.4",
-                  "from": "lodash.isarguments@>=3.0.0 <4.0.0",
-                  "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.4.tgz"
-                },
-                "lodash.isarray": {
-                  "version": "3.0.4",
-                  "from": "lodash.isarray@>=3.0.0 <4.0.0",
-                  "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz"
-                }
-              }
-            },
-            "lodash.restparam": {
-              "version": "3.6.1",
-              "from": "lodash.restparam@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz"
-            },
-            "lodash.templatesettings": {
-              "version": "3.1.0",
-              "from": "lodash.templatesettings@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.0.tgz"
-            }
-          }
-        },
-        "mkdirp": {
-          "version": "0.5.1",
-          "from": "mkdirp@>=0.5.1 <0.6.0",
-          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
-          "dependencies": {
-            "minimist": {
-              "version": "0.0.8",
-              "from": "minimist@0.0.8",
-              "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
-            }
-          }
-        },
         "node-haste": {
           "version": "1.2.8",
           "from": "node-haste@>=1.2.8 <2.0.0",
@@ -3446,21 +3228,6 @@
             }
           }
         },
-        "object-assign": {
-          "version": "4.0.1",
-          "from": "object-assign@>=4.0.1 <5.0.0",
-          "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.0.1.tgz"
-        },
-        "resolve": {
-          "version": "1.1.6",
-          "from": "resolve@>=1.1.6 <2.0.0",
-          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.6.tgz"
-        },
-        "through": {
-          "version": "2.3.8",
-          "from": "through@>=2.3.8 <3.0.0",
-          "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
-        },
         "which": {
           "version": "1.2.0",
           "from": "which@>=1.1.1 <2.0.0",
@@ -3492,6 +3259,11 @@
           "from": "hoek@>=2.2.0 <3.0.0",
           "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.14.0.tgz"
         },
+        "topo": {
+          "version": "1.0.3",
+          "from": "topo@>=1.0.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/topo/-/topo-1.0.3.tgz"
+        },
         "isemail": {
           "version": "1.1.1",
           "from": "isemail@>=1.0.0 <2.0.0",
@@ -3501,11 +3273,6 @@
           "version": "2.10.6",
           "from": "moment@>=2.0.0 <3.0.0",
           "resolved": "https://registry.npmjs.org/moment/-/moment-2.10.6.tgz"
-        },
-        "topo": {
-          "version": "1.0.3",
-          "from": "topo@>=1.0.0 <2.0.0",
-          "resolved": "https://registry.npmjs.org/topo/-/topo-1.0.3.tgz"
         }
       }
     },
@@ -3539,11 +3306,38 @@
           "from": "commoner@>=0.10.1 <0.11.0",
           "resolved": "https://registry.npmjs.org/commoner/-/commoner-0.10.3.tgz",
           "dependencies": {
+            "q": {
+              "version": "1.1.2",
+              "from": "q@>=1.1.2 <1.2.0",
+              "resolved": "https://registry.npmjs.org/q/-/q-1.1.2.tgz"
+            },
+            "recast": {
+              "version": "0.10.32",
+              "from": "recast@>=0.10.0 <0.11.0",
+              "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.32.tgz",
+              "dependencies": {
+                "esprima-fb": {
+                  "version": "15001.1001.0-dev-harmony-fb",
+                  "from": "esprima-fb@>=15001.1001.0-dev-harmony-fb <15001.1002.0",
+                  "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz"
+                },
+                "ast-types": {
+                  "version": "0.8.11",
+                  "from": "ast-types@0.8.11",
+                  "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.11.tgz"
+                }
+              }
+            },
             "commander": {
               "version": "2.5.1",
               "from": "commander@>=2.5.0 <2.6.0",
               "resolved": "https://registry.npmjs.org/commander/-/commander-2.5.1.tgz"
             },
+            "graceful-fs": {
+              "version": "3.0.8",
+              "from": "graceful-fs@>=3.0.4 <3.1.0",
+              "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.8.tgz"
+            },
             "glob": {
               "version": "4.2.2",
               "from": "glob@>=4.2.1 <4.3.0",
@@ -3597,21 +3391,6 @@
                 }
               }
             },
-            "graceful-fs": {
-              "version": "3.0.8",
-              "from": "graceful-fs@>=3.0.4 <3.1.0",
-              "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.8.tgz"
-            },
-            "iconv-lite": {
-              "version": "0.4.11",
-              "from": "iconv-lite@>=0.4.5 <0.5.0",
-              "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.11.tgz"
-            },
-            "install": {
-              "version": "0.1.8",
-              "from": "install@>=0.1.7 <0.2.0",
-              "resolved": "https://registry.npmjs.org/install/-/install-0.1.8.tgz"
-            },
             "mkdirp": {
               "version": "0.5.1",
               "from": "mkdirp@>=0.5.0 <0.6.0",
@@ -3629,27 +3408,15 @@
               "from": "private@>=0.1.6 <0.2.0",
               "resolved": "https://registry.npmjs.org/private/-/private-0.1.6.tgz"
             },
-            "q": {
-              "version": "1.1.2",
-              "from": "q@>=1.1.2 <1.2.0",
-              "resolved": "https://registry.npmjs.org/q/-/q-1.1.2.tgz"
+            "install": {
+              "version": "0.1.8",
+              "from": "install@>=0.1.7 <0.2.0",
+              "resolved": "https://registry.npmjs.org/install/-/install-0.1.8.tgz"
             },
-            "recast": {
-              "version": "0.10.32",
-              "from": "recast@>=0.10.0 <0.11.0",
-              "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.32.tgz",
-              "dependencies": {
-                "ast-types": {
-                  "version": "0.8.11",
-                  "from": "ast-types@0.8.11",
-                  "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.11.tgz"
-                },
-                "esprima-fb": {
-                  "version": "15001.1001.0-dev-harmony-fb",
-                  "from": "esprima-fb@>=15001.1001.0-dev-harmony-fb <15001.1002.0",
-                  "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz"
-                }
-              }
+            "iconv-lite": {
+              "version": "0.4.11",
+              "from": "iconv-lite@>=0.4.5 <0.5.0",
+              "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.11.tgz"
             }
           }
         },
@@ -3860,11 +3627,6 @@
       "from": "loud-rejection@>=1.0.0 <2.0.0",
       "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.0.0.tgz"
     },
-    "lru-cache": {
-      "version": "2.7.0",
-      "from": "lru-cache@>=2.0.0 <3.0.0",
-      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.0.tgz"
-    },
     "map-obj": {
       "version": "1.0.1",
       "from": "map-obj@>=1.0.0 <2.0.0",
@@ -3907,6 +3669,23 @@
       "from": "module-deps@3.9.1",
       "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-3.9.1.tgz",
       "dependencies": {
+        "JSONStream": {
+          "version": "1.0.4",
+          "from": "JSONStream@>=1.0.3 <2.0.0",
+          "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.0.4.tgz",
+          "dependencies": {
+            "jsonparse": {
+              "version": "1.0.0",
+              "from": "jsonparse@>=1.0.0 <1.1.0",
+              "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.0.0.tgz"
+            },
+            "through": {
+              "version": "2.3.8",
+              "from": "through@>=2.2.7 <3.0.0",
+              "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
+            }
+          }
+        },
         "browser-resolve": {
           "version": "1.9.1",
           "from": "browser-resolve@>=1.7.0 <2.0.0",
@@ -3944,11 +3723,6 @@
               "from": "escodegen@>=1.4.1 <2.0.0",
               "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.6.1.tgz",
               "dependencies": {
-                "esprima": {
-                  "version": "1.2.5",
-                  "from": "esprima@>=1.2.2 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz"
-                },
                 "estraverse": {
                   "version": "1.9.3",
                   "from": "estraverse@>=1.9.1 <2.0.0",
@@ -3959,40 +3733,45 @@
                   "from": "esutils@>=1.1.6 <2.0.0",
                   "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz"
                 },
+                "esprima": {
+                  "version": "1.2.5",
+                  "from": "esprima@>=1.2.2 <2.0.0",
+                  "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz"
+                },
                 "optionator": {
                   "version": "0.5.0",
                   "from": "optionator@>=0.5.0 <0.6.0",
                   "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz",
                   "dependencies": {
+                    "prelude-ls": {
+                      "version": "1.1.2",
+                      "from": "prelude-ls@>=1.1.1 <1.2.0",
+                      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz"
+                    },
                     "deep-is": {
                       "version": "0.1.3",
                       "from": "deep-is@>=0.1.2 <0.2.0",
                       "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz"
                     },
-                    "fast-levenshtein": {
-                      "version": "1.0.7",
-                      "from": "fast-levenshtein@>=1.0.0 <1.1.0",
-                      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz"
-                    },
-                    "levn": {
-                      "version": "0.2.5",
-                      "from": "levn@>=0.2.5 <0.3.0",
-                      "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz"
-                    },
-                    "prelude-ls": {
-                      "version": "1.1.2",
-                      "from": "prelude-ls@>=1.1.1 <1.2.0",
-                      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz"
+                    "wordwrap": {
+                      "version": "0.0.3",
+                      "from": "wordwrap@>=0.0.2 <0.1.0",
+                      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
                     },
                     "type-check": {
                       "version": "0.3.1",
                       "from": "type-check@>=0.3.1 <0.4.0",
                       "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz"
                     },
-                    "wordwrap": {
-                      "version": "0.0.3",
-                      "from": "wordwrap@>=0.0.2 <0.1.0",
-                      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
+                    "levn": {
+                      "version": "0.2.5",
+                      "from": "levn@>=0.2.5 <0.3.0",
+                      "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz"
+                    },
+                    "fast-levenshtein": {
+                      "version": "1.0.7",
+                      "from": "fast-levenshtein@>=1.0.0 <1.1.0",
+                      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz"
                     }
                   }
                 },
@@ -4022,23 +3801,6 @@
           "from": "inherits@>=2.0.1 <3.0.0",
           "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
         },
-        "JSONStream": {
-          "version": "1.0.4",
-          "from": "JSONStream@>=1.0.3 <2.0.0",
-          "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.0.4.tgz",
-          "dependencies": {
-            "jsonparse": {
-              "version": "1.0.0",
-              "from": "jsonparse@>=1.0.0 <1.1.0",
-              "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.0.0.tgz"
-            },
-            "through": {
-              "version": "2.3.8",
-              "from": "through@>=2.2.7 <3.0.0",
-              "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
-            }
-          }
-        },
         "parents": {
           "version": "1.0.1",
           "from": "parents@>=1.0.0 <2.0.0",
@@ -4230,15 +3992,15 @@
       "from": "optimist@0.6.1",
       "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
       "dependencies": {
-        "minimist": {
-          "version": "0.0.10",
-          "from": "minimist@>=0.0.1 <0.1.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz"
-        },
         "wordwrap": {
           "version": "0.0.3",
           "from": "wordwrap@>=0.0.2 <0.1.0",
           "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
+        },
+        "minimist": {
+          "version": "0.0.10",
+          "from": "minimist@>=0.0.1 <0.1.0",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz"
         }
       }
     },
@@ -4454,11 +4216,21 @@
           "from": "commoner@>=0.10.0 <0.11.0",
           "resolved": "https://registry.npmjs.org/commoner/-/commoner-0.10.3.tgz",
           "dependencies": {
+            "q": {
+              "version": "1.1.2",
+              "from": "q@>=1.1.2 <1.2.0",
+              "resolved": "https://registry.npmjs.org/q/-/q-1.1.2.tgz"
+            },
             "commander": {
               "version": "2.5.1",
               "from": "commander@>=2.5.0 <2.6.0",
               "resolved": "https://registry.npmjs.org/commander/-/commander-2.5.1.tgz"
             },
+            "graceful-fs": {
+              "version": "3.0.8",
+              "from": "graceful-fs@>=3.0.4 <3.1.0",
+              "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.8.tgz"
+            },
             "glob": {
               "version": "4.2.2",
               "from": "glob@>=4.2.1 <4.3.0",
@@ -4512,21 +4284,6 @@
                 }
               }
             },
-            "graceful-fs": {
-              "version": "3.0.8",
-              "from": "graceful-fs@>=3.0.4 <3.1.0",
-              "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.8.tgz"
-            },
-            "iconv-lite": {
-              "version": "0.4.11",
-              "from": "iconv-lite@>=0.4.5 <0.5.0",
-              "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.11.tgz"
-            },
-            "install": {
-              "version": "0.1.8",
-              "from": "install@>=0.1.7 <0.2.0",
-              "resolved": "https://registry.npmjs.org/install/-/install-0.1.8.tgz"
-            },
             "mkdirp": {
               "version": "0.5.1",
               "from": "mkdirp@>=0.5.0 <0.6.0",
@@ -4539,10 +4296,15 @@
                 }
               }
             },
-            "q": {
-              "version": "1.1.2",
-              "from": "q@>=1.1.2 <1.2.0",
-              "resolved": "https://registry.npmjs.org/q/-/q-1.1.2.tgz"
+            "install": {
+              "version": "0.1.8",
+              "from": "install@>=0.1.7 <0.2.0",
+              "resolved": "https://registry.npmjs.org/install/-/install-0.1.8.tgz"
+            },
+            "iconv-lite": {
+              "version": "0.4.11",
+              "from": "iconv-lite@>=0.4.5 <0.5.0",
+              "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.11.tgz"
             }
           }
         },
@@ -4625,14 +4387,14 @@
           "from": "recast@0.10.25",
           "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.25.tgz",
           "dependencies": {
+            "source-map": {
+              "version": "0.4.4",
+              "from": "source-map@>=0.4.1 <0.5.0"
+            },
             "ast-types": {
               "version": "0.8.5",
               "from": "ast-types@0.8.5",
               "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.5.tgz"
-            },
-            "source-map": {
-              "version": "0.4.4",
-              "from": "source-map@>=0.4.1 <0.5.0"
             }
           }
         },
@@ -4780,11 +4542,6 @@
       "from": "shebang-regex@>=1.0.0 <2.0.0",
       "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz"
     },
-    "sigmund": {
-      "version": "1.0.1",
-      "from": "sigmund@>=1.0.0 <1.1.0",
-      "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz"
-    },
     "simple-fmt": {
       "version": "0.1.0",
       "from": "simple-fmt@>=0.1.0 <0.2.0",
@@ -5069,6 +4826,16 @@
       "from": "ws@0.8.0",
       "resolved": "https://registry.npmjs.org/ws/-/ws-0.8.0.tgz",
       "dependencies": {
+        "options": {
+          "version": "0.0.6",
+          "from": "options@>=0.0.5",
+          "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz"
+        },
+        "ultron": {
+          "version": "1.0.2",
+          "from": "ultron@>=1.0.0 <1.1.0",
+          "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz"
+        },
         "bufferutil": {
           "version": "1.2.1",
           "from": "bufferutil@>=1.2.0 <1.3.0",
@@ -5086,16 +4853,6 @@
             }
           }
         },
-        "options": {
-          "version": "0.0.6",
-          "from": "options@>=0.0.5",
-          "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz"
-        },
-        "ultron": {
-          "version": "1.0.2",
-          "from": "ultron@>=1.0.0 <1.1.0",
-          "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz"
-        },
         "utf-8-validate": {
           "version": "1.2.1",
           "from": "utf-8-validate@>=1.2.0 <1.3.0",
@@ -5468,11 +5225,6 @@
                       "from": "core-util-is@>=1.0.0 <1.1.0",
                       "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
                     },
-                    "inherits": {
-                      "version": "2.0.1",
-                      "from": "inherits@>=2.0.1 <2.1.0",
-                      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                    },
                     "isarray": {
                       "version": "0.0.1",
                       "from": "isarray@0.0.1",
@@ -5482,6 +5234,11 @@
                       "version": "0.10.31",
                       "from": "string_decoder@>=0.10.0 <0.11.0",
                       "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
+                    },
+                    "inherits": {
+                      "version": "2.0.1",
+                      "from": "inherits@>=2.0.1 <2.1.0",
+                      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
                     }
                   }
                 },
@@ -5676,6 +5433,11 @@
                       "from": "inherits@>=2.0.1 <2.1.0",
                       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
                     },
+                    "typedarray": {
+                      "version": "0.0.6",
+                      "from": "typedarray@>=0.0.5 <0.1.0",
+                      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
+                    },
                     "readable-stream": {
                       "version": "2.0.2",
                       "from": "readable-stream@>=2.0.0 <2.1.0",
@@ -5707,11 +5469,6 @@
                           "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
                         }
                       }
-                    },
-                    "typedarray": {
-                      "version": "0.0.6",
-                      "from": "typedarray@>=0.0.5 <0.1.0",
-                      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
                     }
                   }
                 },
@@ -6053,25 +5810,25 @@
                       "from": "rc@>=0.5.5 <0.6.0",
                       "resolved": "https://registry.npmjs.org/rc/-/rc-0.5.5.tgz",
                       "dependencies": {
-                        "deep-extend": {
-                          "version": "0.2.11",
-                          "from": "deep-extend@>=0.2.5 <0.3.0",
-                          "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.2.11.tgz"
-                        },
-                        "ini": {
-                          "version": "1.3.4",
-                          "from": "ini@>=1.3.0 <1.4.0",
-                          "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz"
-                        },
                         "minimist": {
                           "version": "0.0.10",
                           "from": "minimist@>=0.0.7 <0.1.0",
                           "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz"
                         },
+                        "deep-extend": {
+                          "version": "0.2.11",
+                          "from": "deep-extend@>=0.2.5 <0.3.0",
+                          "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.2.11.tgz"
+                        },
                         "strip-json-comments": {
                           "version": "0.1.3",
                           "from": "strip-json-comments@>=0.1.0 <0.2.0",
                           "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
+                        },
+                        "ini": {
+                          "version": "1.3.4",
+                          "from": "ini@>=1.3.0 <1.4.0",
+                          "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz"
                         }
                       }
                     }
@@ -6104,14 +5861,14 @@
                   "from": "inherits@>=2.0.1 <2.1.0",
                   "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
                 },
-                "readable-stream": {
-                  "version": "2.0.4",
-                  "from": "readable-stream@>=2.0.0 <2.1.0"
-                },
                 "typedarray": {
                   "version": "0.0.6",
                   "from": "typedarray@>=0.0.5 <0.1.0",
                   "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
+                },
+                "readable-stream": {
+                  "version": "2.0.4",
+                  "from": "readable-stream@>=2.0.0 <2.1.0"
                 }
               }
             },
@@ -6721,11 +6478,6 @@
                                   "from": "core-util-is@>=1.0.0 <1.1.0",
                                   "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
                                 },
-                                "inherits": {
-                                  "version": "2.0.1",
-                                  "from": "inherits@>=2.0.1 <2.1.0",
-                                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                                },
                                 "isarray": {
                                   "version": "0.0.1",
                                   "from": "isarray@0.0.1",
@@ -6735,6 +6487,11 @@
                                   "version": "0.10.31",
                                   "from": "string_decoder@>=0.10.0 <0.11.0",
                                   "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
+                                },
+                                "inherits": {
+                                  "version": "2.0.1",
+                                  "from": "inherits@>=2.0.1 <2.1.0",
+                                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
                                 }
                               }
                             },
@@ -6887,11 +6644,6 @@
                                   "from": "core-util-is@>=1.0.0 <1.1.0",
                                   "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
                                 },
-                                "inherits": {
-                                  "version": "2.0.1",
-                                  "from": "inherits@>=2.0.1 <2.1.0",
-                                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                                },
                                 "isarray": {
                                   "version": "0.0.1",
                                   "from": "isarray@0.0.1",
@@ -6901,6 +6653,11 @@
                                   "version": "0.10.31",
                                   "from": "string_decoder@>=0.10.0 <0.11.0",
                                   "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
+                                },
+                                "inherits": {
+                                  "version": "2.0.1",
+                                  "from": "inherits@>=2.0.1 <2.1.0",
+                                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
                                 }
                               }
                             },
@@ -7034,11 +6791,6 @@
                                   "from": "core-util-is@>=1.0.0 <1.1.0",
                                   "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
                                 },
-                                "inherits": {
-                                  "version": "2.0.1",
-                                  "from": "inherits@>=2.0.1 <2.1.0",
-                                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                                },
                                 "isarray": {
                                   "version": "0.0.1",
                                   "from": "isarray@0.0.1",
@@ -7048,6 +6800,11 @@
                                   "version": "0.10.31",
                                   "from": "string_decoder@>=0.10.0 <0.11.0",
                                   "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
+                                },
+                                "inherits": {
+                                  "version": "2.0.1",
+                                  "from": "inherits@>=2.0.1 <2.1.0",
+                                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
                                 }
                               }
                             },
@@ -7558,11 +7315,6 @@
                                   "from": "core-util-is@>=1.0.0 <1.1.0",
                                   "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
                                 },
-                                "inherits": {
-                                  "version": "2.0.1",
-                                  "from": "inherits@>=2.0.1 <2.1.0",
-                                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                                },
                                 "isarray": {
                                   "version": "0.0.1",
                                   "from": "isarray@0.0.1",
@@ -7572,6 +7324,11 @@
                                   "version": "0.10.31",
                                   "from": "string_decoder@>=0.10.0 <0.11.0",
                                   "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
+                                },
+                                "inherits": {
+                                  "version": "2.0.1",
+                                  "from": "inherits@>=2.0.1 <2.1.0",
+                                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
                                 }
                               }
                             }
@@ -7692,11 +7449,6 @@
                           "from": "core-util-is@>=1.0.0 <1.1.0",
                           "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
                         },
-                        "inherits": {
-                          "version": "2.0.1",
-                          "from": "inherits@>=2.0.1 <2.1.0",
-                          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                        },
                         "isarray": {
                           "version": "0.0.1",
                           "from": "isarray@0.0.1",
@@ -7706,6 +7458,11 @@
                           "version": "0.10.31",
                           "from": "string_decoder@>=0.10.0 <0.11.0",
                           "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
+                        },
+                        "inherits": {
+                          "version": "2.0.1",
+                          "from": "inherits@>=2.0.1 <2.1.0",
+                          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
                         }
                       }
                     }
@@ -7726,11 +7483,6 @@
                           "from": "core-util-is@>=1.0.0 <1.1.0",
                           "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
                         },
-                        "inherits": {
-                          "version": "2.0.1",
-                          "from": "inherits@>=2.0.1 <2.1.0",
-                          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                        },
                         "isarray": {
                           "version": "0.0.1",
                           "from": "isarray@0.0.1",
@@ -7740,6 +7492,11 @@
                           "version": "0.10.31",
                           "from": "string_decoder@>=0.10.0 <0.11.0",
                           "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
+                        },
+                        "inherits": {
+                          "version": "2.0.1",
+                          "from": "inherits@>=2.0.1 <2.1.0",
+                          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
                         }
                       }
                     },
@@ -7850,18 +7607,6 @@
                         }
                       }
                     },
-                    "glob2base": {
-                      "version": "0.0.12",
-                      "from": "glob2base@>=0.0.12 <0.0.13",
-                      "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz",
-                      "dependencies": {
-                        "find-index": {
-                          "version": "0.1.1",
-                          "from": "find-index@>=0.1.1 <0.2.0",
-                          "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz"
-                        }
-                      }
-                    },
                     "minimatch": {
                       "version": "2.0.10",
                       "from": "minimatch@>=2.0.1 <3.0.0",
@@ -7891,6 +7636,18 @@
                       "from": "ordered-read-streams@>=0.1.0 <0.2.0",
                       "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz"
                     },
+                    "glob2base": {
+                      "version": "0.0.12",
+                      "from": "glob2base@>=0.0.12 <0.0.13",
+                      "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz",
+                      "dependencies": {
+                        "find-index": {
+                          "version": "0.1.1",
+                          "from": "find-index@>=0.1.1 <0.2.0",
+                          "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz"
+                        }
+                      }
+                    },
                     "unique-stream": {
                       "version": "2.2.0",
                       "from": "unique-stream@>=2.0.2 <3.0.0",
@@ -7938,6 +7695,11 @@
                           "from": "globule@>=0.1.0 <0.2.0",
                           "resolved": "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz",
                           "dependencies": {
+                            "lodash": {
+                              "version": "1.0.2",
+                              "from": "lodash@>=1.0.1 <1.1.0",
+                              "resolved": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz"
+                            },
                             "glob": {
                               "version": "3.1.21",
                               "from": "glob@>=3.1.21 <3.2.0",
@@ -7955,11 +7717,6 @@
                                 }
                               }
                             },
-                            "lodash": {
-                              "version": "1.0.2",
-                              "from": "lodash@>=1.0.1 <1.1.0",
-                              "resolved": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz"
-                            },
                             "minimatch": {
                               "version": "0.2.14",
                               "from": "minimatch@>=0.2.11 <0.3.0",
@@ -8030,11 +7787,6 @@
                           "from": "core-util-is@>=1.0.0 <1.1.0",
                           "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
                         },
-                        "inherits": {
-                          "version": "2.0.1",
-                          "from": "inherits@>=2.0.1 <2.1.0",
-                          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                        },
                         "isarray": {
                           "version": "0.0.1",
                           "from": "isarray@0.0.1",
@@ -8044,6 +7796,11 @@
                           "version": "0.10.31",
                           "from": "string_decoder@>=0.10.0 <0.11.0",
                           "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
+                        },
+                        "inherits": {
+                          "version": "2.0.1",
+                          "from": "inherits@>=2.0.1 <2.1.0",
+                          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
                         }
                       }
                     },
@@ -8699,11 +8456,6 @@
                   "from": "escodegen@>=1.6.0 <2.0.0",
                   "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.0.tgz",
                   "dependencies": {
-                    "esprima": {
-                      "version": "1.2.5",
-                      "from": "esprima@>=1.2.2 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz"
-                    },
                     "estraverse": {
                       "version": "1.9.3",
                       "from": "estraverse@>=1.9.1 <2.0.0",
@@ -8714,40 +8466,45 @@
                       "from": "esutils@>=2.0.2 <3.0.0",
                       "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz"
                     },
+                    "esprima": {
+                      "version": "1.2.5",
+                      "from": "esprima@>=1.2.2 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz"
+                    },
                     "optionator": {
                       "version": "0.5.0",
                       "from": "optionator@>=0.5.0 <0.6.0",
                       "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz",
                       "dependencies": {
+                        "prelude-ls": {
+                          "version": "1.1.2",
+                          "from": "prelude-ls@>=1.1.1 <1.2.0",
+                          "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz"
+                        },
                         "deep-is": {
                           "version": "0.1.3",
                           "from": "deep-is@>=0.1.2 <0.2.0",
                           "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz"
                         },
-                        "fast-levenshtein": {
-                          "version": "1.0.7",
-                          "from": "fast-levenshtein@>=1.0.0 <1.1.0",
-                          "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz"
-                        },
-                        "levn": {
-                          "version": "0.2.5",
-                          "from": "levn@>=0.2.5 <0.3.0",
-                          "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz"
-                        },
-                        "prelude-ls": {
-                          "version": "1.1.2",
-                          "from": "prelude-ls@>=1.1.1 <1.2.0",
-                          "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz"
+                        "wordwrap": {
+                          "version": "0.0.3",
+                          "from": "wordwrap@>=0.0.2 <0.1.0",
+                          "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
                         },
                         "type-check": {
                           "version": "0.3.1",
                           "from": "type-check@>=0.3.1 <0.4.0",
                           "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz"
                         },
-                        "wordwrap": {
-                          "version": "0.0.3",
-                          "from": "wordwrap@>=0.0.2 <0.1.0",
-                          "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
+                        "levn": {
+                          "version": "0.2.5",
+                          "from": "levn@>=0.2.5 <0.3.0",
+                          "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz"
+                        },
+                        "fast-levenshtein": {
+                          "version": "1.0.7",
+                          "from": "fast-levenshtein@>=1.0.0 <1.1.0",
+                          "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz"
                         }
                       }
                     },
@@ -8794,11 +8551,6 @@
                   "from": "css-select@>=1.0.0 <1.1.0",
                   "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.0.0.tgz",
                   "dependencies": {
-                    "boolbase": {
-                      "version": "1.0.0",
-                      "from": "boolbase@>=1.0.0 <1.1.0",
-                      "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz"
-                    },
                     "css-what": {
                       "version": "1.0.0",
                       "from": "css-what@>=1.0.0 <1.1.0",
@@ -8816,6 +8568,11 @@
                         }
                       }
                     },
+                    "boolbase": {
+                      "version": "1.0.0",
+                      "from": "boolbase@>=1.0.0 <1.1.0",
+                      "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz"
+                    },
                     "nth-check": {
                       "version": "1.0.1",
                       "from": "nth-check@>=1.0.0 <1.1.0",
@@ -8823,18 +8580,6 @@
                     }
                   }
                 },
-                "dom-serializer": {
-                  "version": "0.1.0",
-                  "from": "dom-serializer@>=0.1.0 <0.2.0",
-                  "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
-                  "dependencies": {
-                    "domelementtype": {
-                      "version": "1.1.3",
-                      "from": "domelementtype@>=1.1.1 <1.2.0",
-                      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz"
-                    }
-                  }
-                },
                 "entities": {
                   "version": "1.1.1",
                   "from": "entities@>=1.1.1 <1.2.0",
@@ -8845,11 +8590,6 @@
                   "from": "htmlparser2@>=3.8.1 <3.9.0",
                   "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz",
                   "dependencies": {
-                    "domelementtype": {
-                      "version": "1.3.0",
-                      "from": "domelementtype@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz"
-                    },
                     "domhandler": {
                       "version": "2.3.0",
                       "from": "domhandler@>=2.3.0 <2.4.0",
@@ -8860,10 +8600,10 @@
                       "from": "domutils@>=1.5.0 <1.6.0",
                       "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz"
                     },
-                    "entities": {
-                      "version": "1.0.0",
-                      "from": "entities@>=1.0.0 <1.1.0",
-                      "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz"
+                    "domelementtype": {
+                      "version": "1.3.0",
+                      "from": "domelementtype@>=1.0.0 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz"
                     },
                     "readable-stream": {
                       "version": "1.1.13",
@@ -8875,11 +8615,6 @@
                           "from": "core-util-is@>=1.0.0 <1.1.0",
                           "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
                         },
-                        "inherits": {
-                          "version": "2.0.1",
-                          "from": "inherits@>=2.0.1 <2.1.0",
-                          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                        },
                         "isarray": {
                           "version": "0.0.1",
                           "from": "isarray@0.0.1",
@@ -8889,8 +8624,30 @@
                           "version": "0.10.31",
                           "from": "string_decoder@>=0.10.0 <0.11.0",
                           "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
+                        },
+                        "inherits": {
+                          "version": "2.0.1",
+                          "from": "inherits@>=2.0.1 <2.1.0",
+                          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
                         }
                       }
+                    },
+                    "entities": {
+                      "version": "1.0.0",
+                      "from": "entities@>=1.0.0 <1.1.0",
+                      "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz"
+                    }
+                  }
+                },
+                "dom-serializer": {
+                  "version": "0.1.0",
+                  "from": "dom-serializer@>=0.1.0 <0.2.0",
+                  "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
+                  "dependencies": {
+                    "domelementtype": {
+                      "version": "1.1.3",
+                      "from": "domelementtype@>=1.1.1 <1.2.0",
+                      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz"
                     }
                   }
                 }
@@ -8969,15 +8726,15 @@
           "from": "istextorbinary@>=1.0.2 <2.0.0",
           "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-1.0.2.tgz",
           "dependencies": {
-            "binaryextensions": {
-              "version": "1.0.0",
-              "from": "binaryextensions@>=1.0.0 <1.1.0",
-              "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-1.0.0.tgz"
-            },
             "textextensions": {
               "version": "1.0.1",
               "from": "textextensions@>=1.0.0 <1.1.0",
               "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-1.0.1.tgz"
+            },
+            "binaryextensions": {
+              "version": "1.0.0",
+              "from": "binaryextensions@>=1.0.0 <1.1.0",
+              "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-1.0.0.tgz"
             }
           }
         },
@@ -9454,16 +9211,6 @@
               "from": "formatio@1.1.1",
               "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz"
             },
-            "lolex": {
-              "version": "1.3.2",
-              "from": "lolex@1.3.2",
-              "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.3.2.tgz"
-            },
-            "samsam": {
-              "version": "1.1.2",
-              "from": "samsam@1.1.2",
-              "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.2.tgz"
-            },
             "util": {
               "version": "0.10.3",
               "from": "util@>=0.10.3 <1.0.0",
@@ -9475,6 +9222,16 @@
                   "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
                 }
               }
+            },
+            "lolex": {
+              "version": "1.3.2",
+              "from": "lolex@1.3.2",
+              "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.3.2.tgz"
+            },
+            "samsam": {
+              "version": "1.1.2",
+              "from": "samsam@1.1.2",
+              "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.2.tgz"
             }
           }
         },
diff --git a/package.json b/package.json
index 55e7302677de..739f72859941 100644
--- a/package.json
+++ b/package.json
@@ -122,7 +122,7 @@
     "yeoman-generator": "^0.20.3"
   },
   "devDependencies": {
-    "jest-cli": "0.7.1",
+    "jest-cli": "0.8.2",
     "babel-eslint": "4.1.4",
     "eslint": "1.3.1",
     "eslint-plugin-react": "3.3.1",

From 7b62dc22adce16900ab473deb6400448a46b2999 Mon Sep 17 00:00:00 2001
From: Calvin Freitas <freitas@amazon.com>
Date: Tue, 22 Dec 2015 04:57:45 -0800
Subject: [PATCH 0480/1411] Add example of getting window dimensions to
 Dimensions docs.

Summary:
This pull request adds an example to the Dimensions documentations.  Specifically, it gives an example of how to get the height and width from the window.

I'm submitting this documentation because discovering this information cost me some time and my hope is to save other folks time by having this info right in the docs generated from the comments in this file.

Let me know if you need anything else.
Closes https://github.com/facebook/react-native/pull/4211

Reviewed By: svcscm

Differential Revision: D2719953

Pulled By: androidtrunkagent

fb-gh-sync-id: 86d18e3847066211a013a50ce2f2a3e2032f5052
---
 Libraries/Utilities/Dimensions.js | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Libraries/Utilities/Dimensions.js b/Libraries/Utilities/Dimensions.js
index 319aa84622e3..93e2cc21aa15 100644
--- a/Libraries/Utilities/Dimensions.js
+++ b/Libraries/Utilities/Dimensions.js
@@ -57,6 +57,8 @@ class Dimensions {
    * than caching the value (for example, using inline styles rather than
    * setting a value in a `StyleSheet`).
    *
+   * Example: `var {height, width} = Dimensions.get('window');`
+   *
    * @param {string} dim Name of dimension as defined when calling `set`.
    * @returns {Object?} Value for the dimension.
    */

From 4472bb54c97c3284cf959e1671729d6b6cb60ff1 Mon Sep 17 00:00:00 2001
From: Ryan Gomba <ryan@ryangomba.com>
Date: Tue, 22 Dec 2015 06:48:29 -0800
Subject: [PATCH 0481/1411] Use font name for weight if no weight property
 available

Summary:
Some custom fonts don't return a UIFontWeightTrait that is representative of their actual weight. For example, "AktivGrotesk-Light" and "AktivGrotesk-Medium" both return UIFontWeightTrait 0. While this is of course an issue with the font files themselves, licensing issues can make it difficult to modify them directly. When using these fonts, specifying weights in JS has no effect. I propose that if no weight information is available, we inspect the name of the font for weighting.
Closes https://github.com/facebook/react-native/pull/2113

Reviewed By: svcscm

Differential Revision: D2783383

Pulled By: nicklockwood

fb-gh-sync-id: 2a9caf99b6af74b7013ecc85417322b56c2dea20
---
 React/Base/RCTConvert.m | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m
index 5860bbc59740..fdd8ccc43237 100644
--- a/React/Base/RCTConvert.m
+++ b/React/Base/RCTConvert.m
@@ -475,8 +475,34 @@ + (CGColorRef)CGColor:(id)json
 
 static RCTFontWeight RCTWeightOfFont(UIFont *font)
 {
+  static NSDictionary *nameToWeight;
+  static dispatch_once_t onceToken;
+  dispatch_once(&onceToken, ^{
+    nameToWeight = @{
+      @"normal": @(UIFontWeightRegular),
+      @"bold": @(UIFontWeightBold),
+      @"ultralight": @(UIFontWeightUltraLight),
+      @"thin": @(UIFontWeightThin),
+      @"light": @(UIFontWeightLight),
+      @"regular": @(UIFontWeightRegular),
+      @"medium": @(UIFontWeightMedium),
+      @"semibold": @(UIFontWeightSemibold),
+      @"bold": @(UIFontWeightBold),
+      @"heavy": @(UIFontWeightHeavy),
+      @"black": @(UIFontWeightBlack),
+    };
+  });
+
   NSDictionary *traits = [font.fontDescriptor objectForKey:UIFontDescriptorTraitsAttribute];
-  return [traits[UIFontWeightTrait] doubleValue];
+  RCTFontWeight weight = [traits[UIFontWeightTrait] doubleValue];
+  if (weight == 0.0) {
+    for (NSString *name in nameToWeight) {
+      if ([font.fontName.lowercaseString hasSuffix:name]) {
+        return [nameToWeight[name] doubleValue];
+      }
+    }
+  }
+  return weight;
 }
 
 static BOOL RCTFontIsItalic(UIFont *font)

From 15aa146255dc141f66d2e499e4a77d74f316b344 Mon Sep 17 00:00:00 2001
From: Milen Dzhumerov <mgd@fb.com>
Date: Tue, 22 Dec 2015 08:30:00 -0800
Subject: [PATCH 0482/1411] Support dashed and dotted border styles on iOS

Summary:
Support dashed and dotted border styles on iOS

public

Reviewed By: nicklockwood

Differential Revision: D2773579

fb-gh-sync-id: f4b99943f38e849602295a86bdb1780c0abbc8e8
---
 .../testViewExample_1@2x.png                  | Bin 100353 -> 156654 bytes
 Examples/UIExplorer/ViewExample.js            |  10 -
 React/Views/RCTBorderDrawing.h                |  12 +-
 React/Views/RCTBorderDrawing.m                | 196 ++++++++++++++++--
 React/Views/RCTView.m                         |  23 +-
 5 files changed, 202 insertions(+), 39 deletions(-)

diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testViewExample_1@2x.png b/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testViewExample_1@2x.png
index 8ec70eb0ce8e806d44ea3cfe01edf7b6c12b7559..4df43bb79e185259978d025f9dd28c3baaf96fab 100644
GIT binary patch
diff --git a/Examples/UIExplorer/ViewExample.js b/Examples/UIExplorer/ViewExample.js
index c20d7e11996a..deed55067e20 100644
--- a/Examples/UIExplorer/ViewExample.js
+++ b/Examples/UIExplorer/ViewExample.js
@@ -40,16 +40,6 @@ var ViewBorderStyleExample = React.createClass({
   },
 
   render() {
-    if (Platform.OS !== 'android') {
-      return (
-        <View style={{backgroundColor: 'red'}}>
-          <Text style={{color: 'white'}}>
-            borderStyle is only supported on android for now.
-          </Text>
-        </View>
-      );
-    }
-
     return (
       <TouchableWithoutFeedback onPress={this._handlePress}>
         <View>
diff --git a/React/Views/RCTBorderDrawing.h b/React/Views/RCTBorderDrawing.h
index b67074337e7a..52e3b4a86df4 100644
--- a/React/Views/RCTBorderDrawing.h
+++ b/React/Views/RCTBorderDrawing.h
@@ -9,6 +9,8 @@
 
 #import <UIKit/UIKit.h>
 
+#import "RCTBorderStyle.h"
+
 typedef struct {
   CGFloat topLeft;
   CGFloat topRight;
@@ -39,6 +41,7 @@ BOOL RCTBorderColorsAreEqual(RCTBorderColors borderColors);
 
 /**
  * Convert RCTCornerRadii to RCTCornerInsets by applying border insets.
+ * Effectively, returns radius - inset, with a lower bound of 0.0.
  */
 RCTCornerInsets RCTGetCornerInsets(RCTCornerRadii cornerRadii,
                                    UIEdgeInsets borderInsets);
@@ -52,9 +55,14 @@ CGPathRef RCTPathCreateWithRoundedRect(CGRect bounds,
                                        const CGAffineTransform *transform);
 
 /**
- * Draw a CSS-compliant border as a scalable image.
+ * Draw a CSS-compliant border as an image. You can determine if it's scalable
+ * by inspecting the image's `capInsets`.
+ *
+ * `borderInsets` defines the border widths for each edge.
  */
-UIImage *RCTGetBorderImage(RCTCornerRadii cornerRadii,
+UIImage *RCTGetBorderImage(RCTBorderStyle borderStyle,
+                           CGSize viewSize,
+                           RCTCornerRadii cornerRadii,
                            UIEdgeInsets borderInsets,
                            RCTBorderColors borderColors,
                            CGColorRef backgroundColor,
diff --git a/React/Views/RCTBorderDrawing.m b/React/Views/RCTBorderDrawing.m
index 8d9e7c0d4e23..e7f236bf698b 100644
--- a/React/Views/RCTBorderDrawing.m
+++ b/React/Views/RCTBorderDrawing.m
@@ -8,6 +8,7 @@
  */
 
 #import "RCTBorderDrawing.h"
+#import "RCTLog.h"
 
 static const CGFloat RCTViewBorderThreshold = 0.001;
 
@@ -150,18 +151,35 @@ static void RCTEllipseGetIntersectionsWithLine(CGRect ellipseBounds,
   intersections[1] = (CGPoint){x2 + ellipseCenter.x, y2 + ellipseCenter.y};
 }
 
-UIImage *RCTGetBorderImage(RCTCornerRadii cornerRadii,
-                           UIEdgeInsets borderInsets,
-                           RCTBorderColors borderColors,
-                           CGColorRef backgroundColor,
-                           BOOL drawToEdge)
-{
-  const BOOL hasCornerRadii =
-  cornerRadii.topLeft > RCTViewBorderThreshold ||
-  cornerRadii.topRight > RCTViewBorderThreshold ||
-  cornerRadii.bottomLeft > RCTViewBorderThreshold ||
-  cornerRadii.bottomRight > RCTViewBorderThreshold;
+NS_INLINE BOOL RCTCornerRadiiAreAboveThreshold(RCTCornerRadii cornerRadii) {
+  return (cornerRadii.topLeft > RCTViewBorderThreshold ||
+    cornerRadii.topRight > RCTViewBorderThreshold      ||
+    cornerRadii.bottomLeft > RCTViewBorderThreshold    ||
+    cornerRadii.bottomRight > RCTViewBorderThreshold);
+}
+
+static CGPathRef RCTPathCreateOuterOutline(BOOL drawToEdge, CGRect rect, RCTCornerRadii cornerRadii) {
+  if (drawToEdge) {
+    return CGPathCreateWithRect(rect, NULL);
+  }
+
+  return RCTPathCreateWithRoundedRect(rect, RCTGetCornerInsets(cornerRadii, UIEdgeInsetsZero), NULL);
+}
+
+static CGContextRef RCTUIGraphicsBeginImageContext(CGSize size, CGColorRef backgroundColor, BOOL hasCornerRadii, BOOL drawToEdge) {
+  const CGFloat alpha = CGColorGetAlpha(backgroundColor);
+  const BOOL opaque = (drawToEdge || !hasCornerRadii) && alpha == 1.0;
+  UIGraphicsBeginImageContextWithOptions(size, opaque, 0.0);
+  return UIGraphicsGetCurrentContext();
+}
 
+static UIImage *RCTGetSolidBorderImage(RCTCornerRadii cornerRadii,
+                                       UIEdgeInsets borderInsets,
+                                       RCTBorderColors borderColors,
+                                       CGColorRef backgroundColor,
+                                       BOOL drawToEdge)
+{
+  const BOOL hasCornerRadii = RCTCornerRadiiAreAboveThreshold(cornerRadii);
   const RCTCornerInsets cornerInsets = RCTGetCornerInsets(cornerRadii, borderInsets);
 
   const UIEdgeInsets edgeInsets = (UIEdgeInsets){
@@ -172,23 +190,14 @@ static void RCTEllipseGetIntersectionsWithLine(CGRect ellipseBounds,
   };
 
   const CGSize size = (CGSize){
+    // 1pt for the middle stretchable area along each axis
     edgeInsets.left + 1 + edgeInsets.right,
     edgeInsets.top + 1 + edgeInsets.bottom
   };
 
-  const CGFloat alpha = CGColorGetAlpha(backgroundColor);
-  const BOOL opaque = (drawToEdge || !hasCornerRadii) && alpha == 1.0;
-  UIGraphicsBeginImageContextWithOptions(size, opaque, 0.0);
-
-  CGContextRef ctx = UIGraphicsGetCurrentContext();
+  CGContextRef ctx = RCTUIGraphicsBeginImageContext(size, backgroundColor, hasCornerRadii, drawToEdge);
   const CGRect rect = {.size = size};
-
-  CGPathRef path;
-  if (drawToEdge) {
-    path = CGPathCreateWithRect(rect, NULL);
-  } else {
-    path = RCTPathCreateWithRoundedRect(rect, RCTGetCornerInsets(cornerRadii, UIEdgeInsetsZero), NULL);
-  }
+  CGPathRef path = RCTPathCreateOuterOutline(drawToEdge, rect, cornerRadii);
 
   if (backgroundColor) {
     CGContextSetFillColorWithColor(ctx, backgroundColor);
@@ -329,3 +338,144 @@ static void RCTEllipseGetIntersectionsWithLine(CGRect ellipseBounds,
 
   return [image resizableImageWithCapInsets:edgeInsets];
 }
+
+// Currently, the dashed / dotted implementation only supports a single colour +
+// single width, as that's currently required and supported on Android.
+//
+// Supporting individual widths + colours on each side is possible by modifying
+// the current implementation. The idea is that we will draw four different lines
+// and clip appropriately for each side (might require adjustment of phase so that
+// they line up but even browsers don't do a good job at that).
+//
+// Firstly, create two paths for the outer and inner paths. The inner path is
+// generated exactly the same way as the outer, just given an inset rect, derived
+// from the insets on each side. Then clip using the odd-even rule
+// (CGContextEOClip()). This will give us a nice rounded (possibly) clip mask.
+//
+// +----------------------------------+
+// |@@@@@@@@  Clipped Space  @@@@@@@@@|
+// |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
+// |@@+----------------------+@@@@@@@@|
+// |@@|                      |@@@@@@@@|
+// |@@|                      |@@@@@@@@|
+// |@@|                      |@@@@@@@@|
+// |@@+----------------------+@@@@@@@@|
+// |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
+// +----------------------------------+
+//
+// Afterwards, we create a clip path for each border side (CGContextSaveGState()
+// and CGContextRestoreGState() when drawing each side). The clip mask for each
+// segment is a trapezoid connecting corresponding edges of the inner and outer
+// rects. For example, in the case of the top edge, the points would be:
+// - (MinX(outer), MinY(outer))
+// - (MaxX(outer), MinY(outer))
+// - (MinX(inner) + topLeftRadius, MinY(inner) + topLeftRadius)
+// - (MaxX(inner) - topRightRadius, MinY(inner) + topRightRadius)
+//
+//         +------------------+
+//         |\                /|
+//         | \              / |
+//         |  \    top     /  |
+//         |   \          /   |
+//         |    \        /    |
+//         |     +------+     |
+//         |     |      |     |
+//         |     |      |     |
+//         |     |      |     |
+//         |left |      |right|
+//         |     |      |     |
+//         |     |      |     |
+//         |     +------+     |
+//         |    /        \    |
+//         |   /          \   |
+//         |  /            \  |
+//         | /    bottom    \ |
+//         |/                \|
+//         +------------------+
+//
+//
+// Note that this approach will produce discontinous colour changes at the edge
+// (which is okay). The reason is that Quartz does not currently support drawing
+// of gradients _along_ a path (NB: clipping a path and drawing a linear gradient
+// is _not_ equivalent).
+
+static UIImage *RCTGetDashedOrDottedBorderImage(RCTBorderStyle borderStyle,
+                                                RCTCornerRadii cornerRadii,
+                                                CGSize viewSize,
+                                                UIEdgeInsets borderInsets,
+                                                RCTBorderColors borderColors,
+                                                CGColorRef backgroundColor,
+                                                BOOL drawToEdge)
+{
+  NSCParameterAssert(borderStyle == RCTBorderStyleDashed || borderStyle == RCTBorderStyleDotted);
+
+  if (!RCTBorderColorsAreEqual(borderColors) || !RCTBorderInsetsAreEqual(borderInsets)) {
+    RCTLogWarn(@"Unsupported dashed / dotted border style");
+    return nil;
+  }
+
+  const CGFloat lineWidth = borderInsets.top;
+  if (lineWidth <= 0.0) {
+    return nil;
+  }
+
+  const BOOL hasCornerRadii = RCTCornerRadiiAreAboveThreshold(cornerRadii);
+  CGContextRef ctx = RCTUIGraphicsBeginImageContext(viewSize, backgroundColor, hasCornerRadii, drawToEdge);
+  const CGRect rect = {.size = viewSize};
+
+  if (backgroundColor) {
+    CGPathRef outerPath = RCTPathCreateOuterOutline(drawToEdge, rect, cornerRadii);
+    CGContextAddPath(ctx, outerPath);
+    CGPathRelease(outerPath);
+
+    CGContextSetFillColorWithColor(ctx, backgroundColor);
+    CGContextFillPath(ctx);
+  }
+
+  // Stroking means that the width is divided in half and grows in both directions
+  // perpendicular to the path, that's why we inset by half the width, so that it
+  // reaches the edge of the rect.
+  CGRect pathRect = CGRectInset(rect, lineWidth / 2.0, lineWidth / 2.0);
+  CGPathRef path = RCTPathCreateWithRoundedRect(pathRect, RCTGetCornerInsets(cornerRadii, UIEdgeInsetsZero), NULL);
+
+  CGFloat dashLengths[2];
+  dashLengths[0] = dashLengths[1] = (borderStyle == RCTBorderStyleDashed ? 3 : 1) * lineWidth;
+
+  CGContextSetLineWidth(ctx, lineWidth);
+  CGContextSetLineDash(ctx, 0, dashLengths, sizeof(dashLengths) / sizeof(*dashLengths));
+
+  CGContextSetStrokeColorWithColor(ctx, [UIColor yellowColor].CGColor);
+
+  CGContextAddPath(ctx, path);
+  CGContextSetStrokeColorWithColor(ctx, borderColors.top);
+  CGContextStrokePath(ctx);
+
+  CGPathRelease(path);
+
+  UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
+  UIGraphicsEndImageContext();
+
+  return image;
+}
+
+UIImage *RCTGetBorderImage(RCTBorderStyle borderStyle,
+                           CGSize viewSize,
+                           RCTCornerRadii cornerRadii,
+                           UIEdgeInsets borderInsets,
+                           RCTBorderColors borderColors,
+                           CGColorRef backgroundColor,
+                           BOOL drawToEdge)
+{
+
+  switch (borderStyle) {
+    case RCTBorderStyleSolid:
+      return RCTGetSolidBorderImage(cornerRadii, borderInsets, borderColors, backgroundColor, drawToEdge);
+    case RCTBorderStyleDashed:
+    case RCTBorderStyleDotted:
+      return RCTGetDashedOrDottedBorderImage(borderStyle, cornerRadii, viewSize, borderInsets, borderColors, backgroundColor, drawToEdge);
+    case RCTBorderStyleUnset:
+      break;
+  }
+
+  return nil;
+}
diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m
index 3a3ea732548a..b2cd7a25083f 100644
--- a/React/Views/RCTView.m
+++ b/React/Views/RCTView.m
@@ -533,12 +533,22 @@ - (void)displayLayer:(CALayer *)layer
     return;
   }
 
-  UIImage *image = RCTGetBorderImage(cornerRadii,
+  UIImage *image = RCTGetBorderImage(_borderStyle,
+                                     layer.bounds.size,
+                                     cornerRadii,
                                      borderInsets,
                                      borderColors,
                                      _backgroundColor.CGColor,
                                      self.clipsToBounds);
 
+  layer.backgroundColor = NULL;
+
+  if (image == nil) {
+    layer.contents = nil;
+    layer.needsDisplayOnBoundsChange = NO;
+    return;
+  }
+
   CGRect contentsCenter = ({
     CGSize size = image.size;
     UIEdgeInsets insets = image.capInsets;
@@ -559,12 +569,17 @@ - (void)displayLayer:(CALayer *)layer
     contentsCenter = CGRectMake(0, 0, 1, 1);
   }
 
-  layer.backgroundColor = NULL;
   layer.contents = (id)image.CGImage;
-  layer.contentsCenter = contentsCenter;
   layer.contentsScale = image.scale;
-  layer.magnificationFilter = kCAFilterNearest;
   layer.needsDisplayOnBoundsChange = YES;
+  layer.magnificationFilter = kCAFilterNearest;
+
+  const BOOL isResizable = !UIEdgeInsetsEqualToEdgeInsets(image.capInsets, UIEdgeInsetsZero);
+  if (isResizable) {
+    layer.contentsCenter = contentsCenter;
+  } else {
+    layer.contentsCenter = CGRectMake(0.0, 0.0, 1.0, 1.0);
+  }
 
   [self updateClippingForLayer:layer];
 }

From 6df737d1e76046b492c9ed53f4a5e5a7dbb36181 Mon Sep 17 00:00:00 2001
From: Brent Vatne <brentvatne@gmail.com>
Date: Tue, 22 Dec 2015 09:02:12 -0800
Subject: [PATCH 0483/1411] Expose in public interface

Summary:
Allows you to do:
```
var { RecyclerViewBackedScrollView } = require('react-native')
```

Rather than:
```
var RecyclerViewBackedScrollView = require('react-native/Libraries/Components/ScrollView/RecyclerViewBackedScrollView')
```

Also...

- Export `ScrollView` by default rather than `UnimplementedView` for `RecyclerViewBackedScrollView` on iOS -- this makes it easier on the user, so you don't have to always do a conditional for: `if IOS then use ScrollView else use RecyclerViewBackedScrollView`. I can't think of a case where this would lead to undesirable behaviour.
- Add `RecyclerViewBackedScrollView` to `MainReactPackage`
- Fix an issue with `MapView` that threw a red-screen when trying to access constants on Android because there is no `MapView` in open source and MapView.js doesn't have a platform extension.
Closes https://github.com/facebook/react-native/pull/4514

Reviewed By: svcscm

Differential Revision: D2753466

Pulled By: mkonicek

fb-gh-sync-id: 0b6e2133975c911d5117e7531cb9093faf314c52
---
 Examples/UIExplorer/ListViewExample.js        | 30 +++++++++----------
 Examples/UIExplorer/UIExplorerList.android.js |  1 +
 .../RecyclerViewBackedScrollView.ios.js       |  2 +-
 Libraries/react-native/react-native.js        |  7 +++--
 Libraries/react-native/react-native.js.flow   |  1 +
 .../react/shell/MainReactPackage.java         |  2 ++
 6 files changed, 24 insertions(+), 19 deletions(-)

diff --git a/Examples/UIExplorer/ListViewExample.js b/Examples/UIExplorer/ListViewExample.js
index 6e18c6fb6553..420ed6ef70a1 100644
--- a/Examples/UIExplorer/ListViewExample.js
+++ b/Examples/UIExplorer/ListViewExample.js
@@ -21,6 +21,7 @@ var {
   ListView,
   TouchableHighlight,
   StyleSheet,
+  RecyclerViewBackedScrollView,
   Text,
   View,
 } = React;
@@ -55,6 +56,7 @@ var ListViewSimpleExample = React.createClass({
         <ListView
           dataSource={this.state.dataSource}
           renderRow={this._renderRow}
+          renderScrollComponent={props => <RecyclerViewBackedScrollView {...props} />}
         />
       </UIExplorerPage>
     );
@@ -62,9 +64,7 @@ var ListViewSimpleExample = React.createClass({
 
   _renderRow: function(rowData: string, sectionID: number, rowID: number) {
     var rowHash = Math.abs(hashCode(rowData));
-    var imgSource = {
-      uri: THUMB_URLS[rowHash % THUMB_URLS.length],
-    };
+    var imgSource = THUMB_URLS[rowHash % THUMB_URLS.length];
     return (
       <TouchableHighlight onPress={() => this._pressRow(rowID)}>
         <View>
@@ -98,18 +98,18 @@ var ListViewSimpleExample = React.createClass({
 });
 
 var THUMB_URLS = [
-  'Thumbnails/like.png',
-  'Thumbnails/dislike.png',
-  'Thumbnails/call.png',
-  'Thumbnails/fist.png',
-  'Thumbnails/bandaged.png',
-  'Thumbnails/flowers.png',
-  'Thumbnails/heart.png',
-  'Thumbnails/liking.png',
-  'Thumbnails/party.png',
-  'Thumbnails/poke.png',
-  'Thumbnails/superlike.png',
-  'Thumbnails/victory.png',
+  require('./Thumbnails/like.png'),
+  require('./Thumbnails/dislike.png'),
+  require('./Thumbnails/call.png'),
+  require('./Thumbnails/fist.png'),
+  require('./Thumbnails/bandaged.png'),
+  require('./Thumbnails/flowers.png'),
+  require('./Thumbnails/heart.png'),
+  require('./Thumbnails/liking.png'),
+  require('./Thumbnails/party.png'),
+  require('./Thumbnails/poke.png'),
+  require('./Thumbnails/superlike.png'),
+  require('./Thumbnails/victory.png'),
   ];
 var LOREM_IPSUM = 'Lorem ipsum dolor sit amet, ius ad pertinax oportere accommodare, an vix civibus corrumpit referrentur. Te nam case ludus inciderint, te mea facilisi adipiscing. Sea id integre luptatum. In tota sale consequuntur nec. Erat ocurreret mei ei. Eu paulo sapientem vulputate est, vel an accusam intellegam interesset. Nam eu stet pericula reprimique, ea vim illud modus, putant invidunt reprehendunt ne qui.';
 
diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index 327bf457bf19..7aa70c516339 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -24,6 +24,7 @@ var UIExplorerListBase = require('./UIExplorerListBase');
 
 var COMPONENTS = [
   require('./ImageExample'),
+  require('./ListViewExample'),
   require('./ProgressBarAndroidExample'),
   require('./ScrollViewSimpleExample'),
   require('./SwitchAndroidExample'),
diff --git a/Libraries/Components/ScrollView/RecyclerViewBackedScrollView.ios.js b/Libraries/Components/ScrollView/RecyclerViewBackedScrollView.ios.js
index 651fac1deb12..a84377e54d72 100644
--- a/Libraries/Components/ScrollView/RecyclerViewBackedScrollView.ios.js
+++ b/Libraries/Components/ScrollView/RecyclerViewBackedScrollView.ios.js
@@ -5,4 +5,4 @@
  */
 'use strict';
 
-module.exports = require('UnimplementedView');
+module.exports = require('ScrollView');
diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js
index 130c4439a446..68876a712968 100644
--- a/Libraries/react-native/react-native.js
+++ b/Libraries/react-native/react-native.js
@@ -32,6 +32,7 @@ var ReactNative = {
   get SnapshotViewIOS() { return require('SnapshotViewIOS'); },
   get Switch() { return require('Switch'); },
   get PullToRefreshViewAndroid() { return require('PullToRefreshViewAndroid'); },
+  get RecyclerViewBackedScrollView() { return require('RecyclerViewBackedScrollView'); },
   get SwitchAndroid() { return require('SwitchAndroid'); },
   get SwitchIOS() { return require('SwitchIOS'); },
   get TabBarIOS() { return require('TabBarIOS'); },
@@ -101,7 +102,7 @@ var ReactNative = {
     get createFragment() { return require('ReactFragment').create; },
     get update() { return require('update'); },
   },
-  
+
   // Note: this must be placed last to prevent eager
   // evaluation of the getter-wrapped submodules above
   ...require('React'),
@@ -109,11 +110,11 @@ var ReactNative = {
 
 if (__DEV__) {
   Object.defineProperty(ReactNative.addons, 'Perf', {
-    enumerable: true, 
+    enumerable: true,
     get: () => require('ReactDefaultPerf'),
   });
   Object.defineProperty(ReactNative.addons, 'TestUtils', {
-    enumerable: true, 
+    enumerable: true,
     get: () => require('ReactTestUtils'),
   });
 }
diff --git a/Libraries/react-native/react-native.js.flow b/Libraries/react-native/react-native.js.flow
index d6c4aac73602..c3d841e5a778 100644
--- a/Libraries/react-native/react-native.js.flow
+++ b/Libraries/react-native/react-native.js.flow
@@ -44,6 +44,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
   SnapshotViewIOS: require('SnapshotViewIOS'),
   Switch: require('Switch'),
   PullToRefreshViewAndroid: require('PullToRefreshViewAndroid'),
+  RecyclerViewBackedScrollView: require('RecyclerViewBackedScrollView'),
   SwitchAndroid: require('SwitchAndroid'),
   SwitchIOS: require('SwitchIOS'),
   TabBarIOS: require('TabBarIOS'),
diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
index 51ca4de448ca..6cd3e9effca6 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
@@ -30,6 +30,7 @@
 import com.facebook.react.views.drawer.ReactDrawerLayoutManager;
 import com.facebook.react.views.image.ReactImageManager;
 import com.facebook.react.views.progressbar.ReactProgressBarViewManager;
+import com.facebook.react.views.recyclerview.RecyclerViewBackedScrollViewManager;
 import com.facebook.react.views.scroll.ReactHorizontalScrollViewManager;
 import com.facebook.react.views.scroll.ReactScrollViewManager;
 import com.facebook.react.views.switchview.ReactSwitchManager;
@@ -78,6 +79,7 @@ public List<ViewManager> createViewManagers(ReactApplicationContext reactContext
       new ReactImageManager(),
       new ReactProgressBarViewManager(),
       new ReactRawTextManager(),
+      new RecyclerViewBackedScrollViewManager(),
       new ReactScrollViewManager(),
       new ReactSwitchManager(),
       new ReactTextInputManager(),

From afbff9bf880704bea93b3c071ba0d5a9f1f303f6 Mon Sep 17 00:00:00 2001
From: Johan Lindskogen <johan.lindskogen@gmail.com>
Date: Tue, 22 Dec 2015 09:22:01 -0800
Subject: [PATCH 0484/1411] Add support for binary type data (ArrayBuffer)

Summary:
Entirely based on https://github.com/facebook/react-native/pull/1829
I just updated the diff to be compatible with the current master branch.
Closes https://github.com/facebook/react-native/pull/4483

Reviewed By: svcscm

Differential Revision: D2783425

Pulled By: nicklockwood

fb-gh-sync-id: 1cc67c0741cff3b071530877d688f6b8c1061e3f
---
 Libraries/WebSocket/RCTWebSocketModule.m |   4 +-
 Libraries/WebSocket/WebSocket.js         |   4 +-
 npm-shrinkwrap.json                      | 113 ++++++++++++-----------
 package.json                             |   1 +
 4 files changed, 66 insertions(+), 56 deletions(-)

diff --git a/Libraries/WebSocket/RCTWebSocketModule.m b/Libraries/WebSocket/RCTWebSocketModule.m
index a19335331941..7afa7dace773 100644
--- a/Libraries/WebSocket/RCTWebSocketModule.m
+++ b/Libraries/WebSocket/RCTWebSocketModule.m
@@ -76,8 +76,10 @@ - (void)dealloc
 
 - (void)webSocket:(RCTSRWebSocket *)webSocket didReceiveMessage:(id)message
 {
+  BOOL binary = [message isKindOfClass:[NSData class]];
   [_bridge.eventDispatcher sendDeviceEventWithName:@"websocketMessage" body:@{
-    @"data": message,
+    @"data": binary ? [message base64EncodedStringWithOptions:0] : message,
+    @"type": binary ? @"binary" : @"text",
     @"id": webSocket.reactTag
   }];
 }
diff --git a/Libraries/WebSocket/WebSocket.js b/Libraries/WebSocket/WebSocket.js
index 3ce40bc67728..515a6ad5cfda 100644
--- a/Libraries/WebSocket/WebSocket.js
+++ b/Libraries/WebSocket/WebSocket.js
@@ -17,6 +17,8 @@ var Platform = require('Platform');
 var WebSocketBase = require('WebSocketBase');
 var WebSocketEvent = require('WebSocketEvent');
 
+var base64 = require('base64-js');
+
 var WebSocketId = 0;
 var CLOSE_NORMAL = 1000;
 
@@ -79,7 +81,7 @@ class WebSocket extends WebSocketBase {
           return;
         }
         var event = new WebSocketEvent('message', {
-          data: ev.data
+          data: (ev.type === 'binary') ? base64.toByteArray(ev.data).buffer : ev.data
         });
         this.onmessage && this.onmessage(event);
         this.dispatchEvent(event);
diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index 3820eda08025..96c371e0f30a 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -151,16 +151,16 @@
           "from": "globals@>=6.4.0 <7.0.0",
           "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
         },
-        "recast": {
-          "version": "0.10.33",
-          "from": "recast@0.10.33",
-          "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
-        },
         "js-tokens": {
           "version": "1.0.1",
           "from": "js-tokens@1.0.1",
           "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
         },
+        "recast": {
+          "version": "0.10.33",
+          "from": "recast@0.10.33",
+          "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
+        },
         "regenerator": {
           "version": "0.8.40",
           "from": "regenerator@0.8.40",
@@ -284,16 +284,16 @@
           "from": "globals@>=6.4.0 <7.0.0",
           "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
         },
-        "js-tokens": {
-          "version": "1.0.1",
-          "from": "js-tokens@1.0.1",
-          "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
-        },
         "recast": {
           "version": "0.10.33",
           "from": "recast@0.10.33",
           "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
         },
+        "js-tokens": {
+          "version": "1.0.1",
+          "from": "js-tokens@1.0.1",
+          "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
+        },
         "regenerator": {
           "version": "0.8.40",
           "from": "regenerator@0.8.40",
@@ -663,6 +663,11 @@
       "from": "balanced-match@>=0.2.0 <0.3.0",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.1.tgz"
     },
+    "base64-js": {
+      "version": "0.0.8",
+      "from": "base64-js@0.0.8",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz"
+    },
     "beeper": {
       "version": "1.1.0",
       "from": "beeper@>=1.0.0 <2.0.0",
@@ -1855,16 +1860,16 @@
           "from": "asn1@0.1.11",
           "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
         },
-        "async": {
-          "version": "1.5.0",
-          "from": "async@^1.4.0",
-          "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz"
-        },
         "assert-plus": {
           "version": "0.1.5",
           "from": "assert-plus@^0.1.5",
           "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
         },
+        "async": {
+          "version": "1.5.0",
+          "from": "async@^1.4.0",
+          "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz"
+        },
         "aws-sign2": {
           "version": "0.6.0",
           "from": "aws-sign2@~0.6.0",
@@ -1880,16 +1885,16 @@
           "from": "block-stream@*",
           "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.8.tgz"
         },
-        "brace-expansion": {
-          "version": "1.1.1",
-          "from": "brace-expansion@>=1.0.0 <2.0.0",
-          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz"
-        },
         "boom": {
           "version": "2.10.1",
           "from": "boom@^2.8.x",
           "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz"
         },
+        "brace-expansion": {
+          "version": "1.1.1",
+          "from": "brace-expansion@>=1.0.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz"
+        },
         "caseless": {
           "version": "0.11.0",
           "from": "caseless@~0.11.0",
@@ -1945,16 +1950,16 @@
           "from": "delayed-stream@~1.0.0",
           "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
         },
-        "escape-string-regexp": {
-          "version": "1.0.3",
-          "from": "escape-string-regexp@^1.0.2",
-          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz"
-        },
         "delegates": {
           "version": "0.1.0",
           "from": "delegates@^0.1.0",
           "resolved": "https://registry.npmjs.org/delegates/-/delegates-0.1.0.tgz"
         },
+        "escape-string-regexp": {
+          "version": "1.0.3",
+          "from": "escape-string-regexp@^1.0.2",
+          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz"
+        },
         "extend": {
           "version": "3.0.0",
           "from": "extend@~3.0.0",
@@ -2010,16 +2015,16 @@
           "from": "has-ansi@^2.0.0",
           "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
         },
-        "hawk": {
-          "version": "3.1.0",
-          "from": "hawk@~3.1.0",
-          "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.0.tgz"
-        },
         "has-unicode": {
           "version": "1.0.1",
           "from": "has-unicode@^1.0.0",
           "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-1.0.1.tgz"
         },
+        "hawk": {
+          "version": "3.1.0",
+          "from": "hawk@~3.1.0",
+          "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.0.tgz"
+        },
         "hoek": {
           "version": "2.16.3",
           "from": "hoek@2.x.x",
@@ -2030,16 +2035,16 @@
           "from": "http-signature@~0.11.0",
           "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.11.0.tgz"
         },
-        "ini": {
-          "version": "1.3.4",
-          "from": "ini@~1.3.0",
-          "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz"
-        },
         "inherits": {
           "version": "2.0.1",
           "from": "inherits@*",
           "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
         },
+        "ini": {
+          "version": "1.3.4",
+          "from": "ini@~1.3.0",
+          "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz"
+        },
         "is-my-json-valid": {
           "version": "2.12.2",
           "from": "is-my-json-valid@^2.12.2",
@@ -2150,41 +2155,41 @@
           "from": "pinkie@^1.0.0",
           "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
         },
-        "qs": {
-          "version": "5.2.0",
-          "from": "qs@~5.2.0",
-          "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz"
-        },
         "pinkie-promise": {
           "version": "1.0.0",
           "from": "pinkie-promise@^1.0.0",
           "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz"
         },
-        "request": {
-          "version": "2.65.0",
-          "from": "request@2.x",
-          "resolved": "https://registry.npmjs.org/request/-/request-2.65.0.tgz"
+        "qs": {
+          "version": "5.2.0",
+          "from": "qs@~5.2.0",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz"
         },
         "readable-stream": {
           "version": "1.1.13",
           "from": "readable-stream@^1.1.13",
           "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz"
         },
+        "request": {
+          "version": "2.65.0",
+          "from": "request@2.x",
+          "resolved": "https://registry.npmjs.org/request/-/request-2.65.0.tgz"
+        },
         "semver": {
           "version": "5.0.3",
           "from": "semver@~5.0.1",
           "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
         },
-        "string_decoder": {
-          "version": "0.10.31",
-          "from": "string_decoder@~0.10.x",
-          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
-        },
         "sntp": {
           "version": "1.0.9",
           "from": "sntp@1.x.x",
           "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
         },
+        "string_decoder": {
+          "version": "0.10.31",
+          "from": "string_decoder@~0.10.x",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
+        },
         "stringstream": {
           "version": "0.0.5",
           "from": "stringstream@~0.0.4",
@@ -2210,16 +2215,16 @@
           "from": "tar@~2.2.0",
           "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz"
         },
-        "tunnel-agent": {
-          "version": "0.4.1",
-          "from": "tunnel-agent@~0.4.1",
-          "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz"
-        },
         "tough-cookie": {
           "version": "2.2.0",
           "from": "tough-cookie@~2.2.0",
           "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.0.tgz"
         },
+        "tunnel-agent": {
+          "version": "0.4.1",
+          "from": "tunnel-agent@~0.4.1",
+          "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz"
+        },
         "uid-number": {
           "version": "0.0.3",
           "from": "uid-number@0.0.3",
diff --git a/package.json b/package.json
index 739f72859941..7f47f5a9b618 100644
--- a/package.json
+++ b/package.json
@@ -84,6 +84,7 @@
     "babel-polyfill": "^6.0.16",
     "babel-types": "^6.1.2",
     "babylon": "^6.1.2",
+    "base64-js": "^0.0.8",
     "bser": "^1.0.2",
     "chalk": "^1.1.1",
     "connect": "^2.8.3",

From 935cbb76c02cffd378a8f391c6e7443a3da13adc Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Tue, 22 Dec 2015 09:56:52 -0800
Subject: [PATCH 0485/1411] Add a base activity for React Native apps. Fixes
 #4043

Summary:
Having a base activity allows us to add new features and fixes without having to change the generated `MainActivity` file.

cc mkonicek arbesfeld
Closes https://github.com/facebook/react-native/pull/4827

Reviewed By: bestander

Differential Revision: D2783527

Pulled By: mkonicek

fb-gh-sync-id: 707b82839809ca2e1775f5d3ac022a6d00bcac5a
---
 .../com/facebook/react/ReactActivity.java     | 215 ++++++++++++++++++
 .../templates/package/MainActivity.java       |  85 ++-----
 2 files changed, 236 insertions(+), 64 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java b/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java
new file mode 100644
index 000000000000..064c3b8b3fdb
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java
@@ -0,0 +1,215 @@
+package com.facebook.react;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.provider.Settings;
+import android.view.KeyEvent;
+import android.widget.EditText;
+import android.widget.Toast;
+
+import com.facebook.common.logging.FLog;
+import com.facebook.react.common.ReactConstants;
+import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
+
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+/**
+ * Base Activity for React Native applications.
+ */
+public abstract class ReactActivity extends Activity implements DefaultHardwareBackBtnHandler {
+
+  private static final String REDBOX_PERMISSION_MESSAGE =
+      "Overlay permissions needs to be granted in order for react native apps to run in dev mode";
+
+  private @Nullable ReactInstanceManager mReactInstanceManager;
+  private LifecycleState mLifecycleState = LifecycleState.BEFORE_RESUME;
+  private boolean mDoRefresh = false;
+
+  /**
+   * Returns the name of the bundle in assets. If this is null, and no file path is specified for
+   * the bundle, the app will only work with {@code getUseDeveloperSupport} enabled and will
+   * always try to load the JS bundle from the packager server.
+   * e.g. "index.android.bundle"
+   */
+  protected @Nullable String getBundleAssetName() {
+    return "index.android.bundle";
+  };
+
+  /**
+   * Returns a custom path of the bundle file. This is used in cases the bundle should be loaded
+   * from a custom path. By default it is loaded from Android assets, from a path specified
+   * by {@link getBundleAssetName}.
+   * e.g. "file://sdcard/myapp_cache/index.android.bundle"
+   */
+  protected @Nullable String getJSBundleFile() {
+    return null;
+  }
+
+  /**
+   * Returns the name of the main module. Determines the URL used to fetch the JS bundle
+   * from the packager server. It is only used when dev support is enabled.
+   * This is the first file to be executed once the {@link ReactInstanceManager} is created.
+   * e.g. "index.android"
+   */
+  protected String getJSMainModuleName() {
+    return "index.android";
+  }
+
+  /**
+   * Returns the name of the main component registered from JavaScript.
+   * This is used to schedule rendering of the component.
+   * e.g. "MoviesApp"
+   */
+  protected abstract String getMainComponentName();
+
+  /**
+   * Returns whether dev mode should be enabled. This enables e.g. the dev menu.
+   */
+  protected abstract boolean getUseDeveloperSupport();
+
+  /**
+   * Returns a list of {@link ReactPackage} used by the app.
+   * You'll most likely want to return at least the {@code MainReactPackage}.
+   * If your app uses additional views or modules besides the default ones,
+   * you'll want to include more packages here.
+   */
+  protected abstract List<ReactPackage> getPackages();
+
+  /**
+   * A subclass may override this method if it needs to use a custom instance.
+   */
+  protected ReactInstanceManager createReactInstanceManager() {
+    ReactInstanceManager.Builder builder = ReactInstanceManager.builder()
+        .setApplication(getApplication())
+        .setJSMainModuleName(getJSMainModuleName())
+        .setUseDeveloperSupport(getUseDeveloperSupport())
+        .setInitialLifecycleState(mLifecycleState);
+
+    for (ReactPackage reactPackage : getPackages()) {
+      builder.addPackage(reactPackage);
+    }
+
+    String jsBundleFile = getJSBundleFile();
+
+    if (jsBundleFile != null) {
+      builder.setJSBundleFile(jsBundleFile);
+    } else {
+      builder.setBundleAssetName(getBundleAssetName());
+    }
+
+    return builder.build();
+  }
+
+  /**
+   * A subclass may override this method if it needs to use a custom {@link ReactRootView}.
+   */
+  protected ReactRootView createRootView() {
+    return new ReactRootView(this);
+  }
+
+  @Override
+  protected void onCreate(Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+
+    if (getUseDeveloperSupport() && Build.VERSION.SDK_INT >= 23) {
+      // Get permission to show redbox in dev builds.
+      if (!Settings.canDrawOverlays(this)) {
+        Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
+        startActivity(serviceIntent);
+        FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE);
+        Toast.makeText(this, REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show();
+      }
+    }
+
+    mReactInstanceManager = createReactInstanceManager();
+    ReactRootView mReactRootView = createRootView();
+    mReactRootView.startReactApplication(mReactInstanceManager, getMainComponentName());
+    setContentView(mReactRootView);
+  }
+
+  @Override
+  protected void onPause() {
+    super.onPause();
+
+    mLifecycleState = LifecycleState.BEFORE_RESUME;
+
+    if (mReactInstanceManager != null) {
+      mReactInstanceManager.onPause();
+    }
+  }
+
+  @Override
+  protected void onResume() {
+    super.onResume();
+
+    mLifecycleState = LifecycleState.RESUMED;
+
+    if (mReactInstanceManager != null) {
+      mReactInstanceManager.onResume(this, this);
+    }
+  }
+
+  @Override
+  protected void onDestroy() {
+    super.onDestroy();
+
+    if (mReactInstanceManager != null) {
+      mReactInstanceManager.onDestroy();
+    }
+  }
+
+  @Override
+  public void onActivityResult(int requestCode, int resultCode, Intent data) {
+    if (mReactInstanceManager != null) {
+      mReactInstanceManager.onActivityResult(requestCode, resultCode, data);
+    }
+  }
+
+  @Override
+  public boolean onKeyUp(int keyCode, KeyEvent event) {
+    if (mReactInstanceManager != null &&
+        mReactInstanceManager.getDevSupportManager().getDevSupportEnabled()) {
+      if (keyCode == KeyEvent.KEYCODE_MENU) {
+        mReactInstanceManager.showDevOptionsDialog();
+        return true;
+      }
+      if (keyCode == KeyEvent.KEYCODE_R && !(getCurrentFocus() instanceof EditText)) {
+        // Enable double-tap-R-to-reload
+        if (mDoRefresh) {
+          mReactInstanceManager.getDevSupportManager().handleReloadJS();
+          mDoRefresh = false;
+        } else {
+          mDoRefresh = true;
+          new Handler().postDelayed(
+              new Runnable() {
+                @Override
+                public void run() {
+                  mDoRefresh = false;
+                }
+              },
+              200);
+        }
+      }
+    }
+    return super.onKeyUp(keyCode, event);
+  }
+
+  @Override
+  public void onBackPressed() {
+    if (mReactInstanceManager != null) {
+      mReactInstanceManager.onBackPressed();
+    } else {
+      super.onBackPressed();
+    }
+  }
+
+  @Override
+  public void invokeDefaultOnBackPressed() {
+    super.onBackPressed();
+  }
+}
diff --git a/local-cli/generator-android/templates/package/MainActivity.java b/local-cli/generator-android/templates/package/MainActivity.java
index 1e2b912f9414..ab8626844bbb 100644
--- a/local-cli/generator-android/templates/package/MainActivity.java
+++ b/local-cli/generator-android/templates/package/MainActivity.java
@@ -1,78 +1,35 @@
 package <%= package %>;
 
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.KeyEvent;
-
-import com.facebook.react.LifecycleState;
-import com.facebook.react.ReactInstanceManager;
-import com.facebook.react.ReactRootView;
-import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
+import com.facebook.react.ReactActivity;
 import com.facebook.react.shell.MainReactPackage;
-import com.facebook.soloader.SoLoader;
-
-public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler {
-
-    private ReactInstanceManager mReactInstanceManager;
-    private ReactRootView mReactRootView;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        mReactRootView = new ReactRootView(this);
-
-        mReactInstanceManager = ReactInstanceManager.builder()
-                .setApplication(getApplication())
-                .setBundleAssetName("index.android.bundle")
-                .setJSMainModuleName("index.android")
-                .addPackage(new MainReactPackage())
-                .setUseDeveloperSupport(BuildConfig.DEBUG)
-                .setInitialLifecycleState(LifecycleState.RESUMED)
-                .build();
-
-        mReactRootView.startReactApplication(mReactInstanceManager, "<%= name %>", null);
-
-        setContentView(mReactRootView);
-    }
-
-    @Override
-    public boolean onKeyUp(int keyCode, KeyEvent event) {
-        if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
-            mReactInstanceManager.showDevOptionsDialog();
-            return true;
-        }
-        return super.onKeyUp(keyCode, event);
-    }
 
-    @Override
-    public void onBackPressed() {
-      if (mReactInstanceManager != null) {
-        mReactInstanceManager.onBackPressed();
-      } else {
-        super.onBackPressed();
-      }
-    }
+public class MainActivity extends ReactActivity {
 
+    /**
+     * Returns the name of the main component registered from JavaScript.
+     * This is used to schedule rendering of the component.
+     */
     @Override
-    public void invokeDefaultOnBackPressed() {
-      super.onBackPressed();
+    protected String getMainComponentName() {
+        return "<%= name %>";
     }
 
+    /**
+     * Returns whether dev mode should be enabled.
+     * This enables e.g. the dev menu.
+     */
     @Override
-    protected void onPause() {
-        super.onPause();
-
-        if (mReactInstanceManager != null) {
-            mReactInstanceManager.onPause();
-        }
+    protected boolean getUseDeveloperSupport() {
+        return BuildConfig.DEBUG;
     }
 
+   /**
+   * A list of packages used by the app. If the app uses additional views
+   * or modules besides the default ones, add more packages here.
+   */
     @Override
-    protected void onResume() {
-        super.onResume();
-
-        if (mReactInstanceManager != null) {
-            mReactInstanceManager.onResume(this, this);
-        }
+    protected abstract List<ReactPackage> getPackages() {
+      return Arrays.<ReactPackage>asList(
+        new MainReactPackage());
     }
 }

From c866a0a6d0978e252fbb5164a797bc7ef194973c Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Tue, 22 Dec 2015 09:58:31 -0800
Subject: [PATCH 0486/1411] use a filename for the magic unbundle file that
 will end up in the apk

Reviewed By: martinbigio

Differential Revision: D2774022

fb-gh-sync-id: 5ccafe606e586c55213a10e00013c6feecc9dbcd
---
 local-cli/bundle/output/unbundle/as-assets.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/local-cli/bundle/output/unbundle/as-assets.js b/local-cli/bundle/output/unbundle/as-assets.js
index 873b1334885c..5f98521461ae 100644
--- a/local-cli/bundle/output/unbundle/as-assets.js
+++ b/local-cli/bundle/output/unbundle/as-assets.js
@@ -15,7 +15,7 @@ const Promise = require('promise');
 const writeFile = require('../writeFile');
 const writeSourceMap = require('./write-sourcemap');
 const MAGIC_UNBUNDLE_NUMBER = require('./magic-number');
-const MAGIC_UNBUNDLE_FILENAME = '.unbundle';
+const MAGIC_UNBUNDLE_FILENAME = 'UNBUNDLE'; // must not start with a dot, as that won't go into the apk
 const MODULES_DIR = 'js-modules';
 
 /**

From c34ef25ec50cb724bcd47b2971412d38aa6fb9ed Mon Sep 17 00:00:00 2001
From: John Ku <john.cmyk@gmail.com>
Date: Tue, 22 Dec 2015 10:02:47 -0800
Subject: [PATCH 0487/1411] fix incorrect count for layoutAnimation callback

Summary:
fixes #3106
Having -1 would trigger callback one frame early causing it to be ignored on the next frame.
Closes https://github.com/facebook/react-native/pull/3190

Reviewed By: svcscm

Differential Revision: D2783700

Pulled By: mkonicek

fb-gh-sync-id: 02070f70915055aec3b1543a8d553f2680438611
---
 React/Modules/RCTUIManager.m | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m
index 3f60b3f53540..2e63a461ae3d 100644
--- a/React/Modules/RCTUIManager.m
+++ b/React/Modules/RCTUIManager.m
@@ -553,7 +553,7 @@ - (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTShadowView *)roo
 
       void (^completion)(BOOL) = ^(BOOL finished) {
         completionsCalled++;
-        if (callback && completionsCalled == frames.count - 1) {
+        if (callback && completionsCalled == frames.count) {
           callback(@[@(finished)]);
         }
       };

From 43ca8a0da41bd804329c056d6c5ac7cea931d5e4 Mon Sep 17 00:00:00 2001
From: Brent Vatne <brentvatne@gmail.com>
Date: Tue, 22 Dec 2015 11:35:07 -0800
Subject: [PATCH 0488/1411] Add TransformExample to UIExplorerList.ios.js

Summary:
It wasn't in UIExplorerList.ios.js (only in UIExplorerList.js) so it was not being pulled in on the iOS UIExplorer.
Closes https://github.com/facebook/react-native/pull/2196

Reviewed By: majak

Differential Revision: D2780150

Pulled By: nicklockwood

fb-gh-sync-id: f111ec6e29465c4c7f22ca8faec8fc17a96a80cb
---
 Examples/UIExplorer/UIExplorerList.ios.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Examples/UIExplorer/UIExplorerList.ios.js b/Examples/UIExplorer/UIExplorerList.ios.js
index 61a213097909..c2ba81752099 100644
--- a/Examples/UIExplorer/UIExplorerList.ios.js
+++ b/Examples/UIExplorer/UIExplorerList.ios.js
@@ -76,6 +76,7 @@ var APIS = [
   require('./RCTRootViewIOSExample'),
   require('./StatusBarIOSExample'),
   require('./TimerExample'),
+  require('./TransformExample'),
   require('./VibrationIOSExample'),
   require('./XHRExample.ios'),
   require('./ImageEditingExample'),

From b7e939b38d59f0516771c3111d15bcd09ddb7bbd Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Tue, 22 Dec 2015 11:40:16 -0800
Subject: [PATCH 0489/1411] Update all tests to use Jasmine 2

Reviewed By: vjeux

Differential Revision: D2782581

fb-gh-sync-id: 1d938a2bbdd8670c917c1793234dfdcb29fd4511
---
 Libraries/Utilities/__tests__/MatrixMath-test.js | 16 ++++++++++------
 .../Utilities/__tests__/MessageQueue-test.js     | 10 +++++-----
 package.json                                     |  1 +
 .../polyfills/__tests__/loadBundles-test.js      |  3 +--
 .../src/Resolver/polyfills/loadBundles.js        |  2 +-
 5 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/Libraries/Utilities/__tests__/MatrixMath-test.js b/Libraries/Utilities/__tests__/MatrixMath-test.js
index 4ca108e39251..5bfa1e9d7b81 100644
--- a/Libraries/Utilities/__tests__/MatrixMath-test.js
+++ b/Libraries/Utilities/__tests__/MatrixMath-test.js
@@ -17,6 +17,10 @@ function degreesToRadians(degrees) {
   return degrees * Math.PI / 180;
 }
 
+function convertZeroes(degrees) {
+  return degrees.map(value => value === -0 ? 0 : value);
+}
+
 describe('MatrixMath', () => {
 
   it('decomposes a 4x4 matrix to produce accurate Z-axis angles', () => {
@@ -26,11 +30,11 @@ describe('MatrixMath', () => {
 
     [30, 45, 60, 75, 90, 100, 115, 120, 133, 167].forEach(angle => {
       var mat = MatrixMath.createRotateZ(degreesToRadians(angle));
-      expect(MatrixMath.decomposeMatrix(mat).rotationDegrees)
+      expect(convertZeroes(MatrixMath.decomposeMatrix(mat).rotationDegrees))
         .toEqual([0, 0, angle]);
 
       mat = MatrixMath.createRotateZ(degreesToRadians(-angle));
-      expect(MatrixMath.decomposeMatrix(mat).rotationDegrees)
+      expect(convertZeroes(MatrixMath.decomposeMatrix(mat).rotationDegrees))
         .toEqual([0, 0, -angle]);
     });
 
@@ -51,7 +55,7 @@ describe('MatrixMath', () => {
     // 360 is expressed as 0
     expect(MatrixMath.decomposeMatrix(
       MatrixMath.createRotateZ(degreesToRadians(360))
-    ).rotationDegrees).toEqual([0, 0, 0]);
+    ).rotationDegrees).toEqual([0, 0, -0]);
 
     expect(MatrixMath.decomposeMatrix(
       MatrixMath.createRotateZ(degreesToRadians(33.33333333))
@@ -83,12 +87,12 @@ describe('MatrixMath', () => {
     [30, 45, 60, 75, 90, 100, 110, 120, 133, 167].forEach(angle => {
       mat = MatrixMath.createIdentityMatrix();
       MatrixMath.reuseRotateYCommand(mat, degreesToRadians(angle));
-      expect(MatrixMath.decomposeMatrix(mat).rotationDegrees)
+      expect(convertZeroes(MatrixMath.decomposeMatrix(mat).rotationDegrees))
         .toEqual([0, angle, 0]);
 
       mat = MatrixMath.createIdentityMatrix();
       MatrixMath.reuseRotateYCommand(mat, degreesToRadians(-angle));
-      expect(MatrixMath.decomposeMatrix(mat).rotationDegrees)
+      expect(convertZeroes(MatrixMath.decomposeMatrix(mat).rotationDegrees))
         .toEqual([0, -angle, 0]);
     });
 
@@ -115,7 +119,7 @@ describe('MatrixMath', () => {
     [30, 45, 60, 75, 90, 100, 110, 120, 133, 167].forEach(angle => {
       mat = MatrixMath.createIdentityMatrix();
       MatrixMath.reuseRotateXCommand(mat, degreesToRadians(angle));
-      expect(MatrixMath.decomposeMatrix(mat).rotationDegrees)
+      expect(convertZeroes(MatrixMath.decomposeMatrix(mat).rotationDegrees))
         .toEqual([angle, 0, 0]);
     });
 
diff --git a/Libraries/Utilities/__tests__/MessageQueue-test.js b/Libraries/Utilities/__tests__/MessageQueue-test.js
index 8b9b689fd8bc..64c4c1c1aa31 100644
--- a/Libraries/Utilities/__tests__/MessageQueue-test.js
+++ b/Libraries/Utilities/__tests__/MessageQueue-test.js
@@ -55,15 +55,15 @@ describe('MessageQueue', () => {
   });
 
   it('should call a local function with id', () => {
-    expect(TestModule.testHook1.callCount).toEqual(0);
+    expect(TestModule.testHook1.calls.count()).toEqual(0);
     queue.__callFunction(0, 0, [1]);
-    expect(TestModule.testHook1.callCount).toEqual(1);
+    expect(TestModule.testHook1.calls.count()).toEqual(1);
   });
 
   it('should call a local function with the function name', () => {
-    expect(TestModule.testHook2.callCount).toEqual(0);
+    expect(TestModule.testHook2.calls.count()).toEqual(0);
     queue.__callFunction('one', 'testHook2', [2]);
-    expect(TestModule.testHook2.callCount).toEqual(1);
+    expect(TestModule.testHook2.calls.count()).toEqual(1);
   });
 
   it('should generate native modules', () => {
@@ -78,7 +78,7 @@ describe('MessageQueue', () => {
     assertQueue(flushedQueue, 0, 0, 1, ['foo', 0, 1]);
   });
 
-  it('should call the stored callback', (done) => {
+  it('should call the stored callback', () => {
     var done = false;
     queue.RemoteModules.one.remoteMethod1(() => { done = true; });
     queue.__invokeCallback(1);
diff --git a/package.json b/package.json
index 7f47f5a9b618..b36379dd237f 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,7 @@
       "^image![a-zA-Z0-9$_-]+$": "GlobalImageStub",
       "^[./a-zA-Z0-9$_-]+\\.png$": "RelativeImageStub"
     },
+    "testRunner": "<rootDir>/node_modules/jest-cli/src/testRunners/jasmine/jasmine2.js",
     "testPathIgnorePatterns": [
       "/node_modules/"
     ],
diff --git a/packager/react-packager/src/Resolver/polyfills/__tests__/loadBundles-test.js b/packager/react-packager/src/Resolver/polyfills/__tests__/loadBundles-test.js
index ad0dcf279473..39d687881885 100644
--- a/packager/react-packager/src/Resolver/polyfills/__tests__/loadBundles-test.js
+++ b/packager/react-packager/src/Resolver/polyfills/__tests__/loadBundles-test.js
@@ -34,8 +34,7 @@ describe('loadBundles', () => {
 
   pit('shouldn\'t request already loaded bundles', () => {
     loadBundles.mockImpl((bundles, callback) => callback());
-    return global
-      .__loadBundles(['bundle.0'])
+    return global.__loadBundles(['bundle.0'])
       .then(() => global.__loadBundles(['bundle.0']))
       .then(() => expect(loadBundlesCalls.length).toBe(1));
   });
diff --git a/packager/react-packager/src/Resolver/polyfills/loadBundles.js b/packager/react-packager/src/Resolver/polyfills/loadBundles.js
index 551d4cac22dc..4e893eda9cb2 100644
--- a/packager/react-packager/src/Resolver/polyfills/loadBundles.js
+++ b/packager/react-packager/src/Resolver/polyfills/loadBundles.js
@@ -1,7 +1,7 @@
 /* eslint global-strict:0 */
 (global => {
   let loadBundlesOnNative = (bundles) =>
-    new Promise((_, resolve) =>
+    new Promise((resolve) =>
       require('NativeModules').RCTBundlesLoader.loadBundles(bundles, resolve));
 
   let requestedBundles = Object.create(null);

From 83c2e0303b108371b9fa2d41180bce8da9e1dd5c Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Tue, 22 Dec 2015 13:36:37 -0800
Subject: [PATCH 0490/1411] Added JS wrappers for ImageStore and ImageEditor

Summary:
public
Added JS wrappers for ImageStore(Manager) and ImageEditor(Manager) so they can be required in the normal way instead of accessed directly via NativeModules.

Reviewed By: dmmiller

Differential Revision: D2773822

fb-gh-sync-id: 6eeafd3f80a87b1b91a04a2aebad6e2fd31b0e98
---
 Examples/UIExplorer/ImageEditingExample.js  | 22 +++---
 Examples/UIExplorer/TransformExample.js     |  1 +
 Libraries/Image/ImageEditor.js              | 72 ++++++++++++++++++
 Libraries/Image/ImageStore.js               | 83 +++++++++++++++++++++
 Libraries/Image/RCTImageEditingManager.m    | 23 ++----
 Libraries/Image/RCTImageStoreManager.m      |  6 ++
 Libraries/react-native/react-native.js      |  2 +
 Libraries/react-native/react-native.js.flow |  2 +
 8 files changed, 186 insertions(+), 25 deletions(-)
 create mode 100644 Libraries/Image/ImageEditor.js
 create mode 100644 Libraries/Image/ImageStore.js

diff --git a/Examples/UIExplorer/ImageEditingExample.js b/Examples/UIExplorer/ImageEditingExample.js
index 56ab1c4ba342..29b2dfd84166 100644
--- a/Examples/UIExplorer/ImageEditingExample.js
+++ b/Examples/UIExplorer/ImageEditingExample.js
@@ -20,6 +20,7 @@ var React = require('react-native');
 var {
   CameraRoll,
   Image,
+  ImageEditor,
   NativeModules,
   ScrollView,
   StyleSheet,
@@ -28,7 +29,7 @@ var {
   UIManager,
   View,
 } = React;
-var ImageEditingManager = NativeModules.ImageEditingManager;
+
 var RCTScrollViewConsts = UIManager.RCTScrollView.Constants;
 
 var PAGE_SIZE = 20;
@@ -43,14 +44,16 @@ type ImageSize = {
   height: number;
 };
 
-type TransformData = {
+type ImageCropData = {
   offset: ImageOffset;
   size: ImageSize;
-}
+  displaySize?: ?ImageSize;
+  resizeMode?: ?any; 
+};
 
 class SquareImageCropper extends React.Component {
   _isMounted: boolean;
-  _transformData: TransformData;
+  _transformData: ImageCropData;
 
   constructor(props) {
     super(props);
@@ -167,7 +170,7 @@ class SquareImageCropper extends React.Component {
   }
 
   _crop() {
-    ImageEditingManager.cropImage(
+    ImageEditor.cropImage(
       this.state.randomPhoto.uri,
       this._transformData,
       (croppedImageURI) => this.setState({croppedImageURI}),
@@ -231,7 +234,7 @@ class ImageCropper extends React.Component {
     var sizeRatioX = croppedImageSize.width / scaledImageSize.width;
     var sizeRatioY = croppedImageSize.height / scaledImageSize.height;
 
-    this.props.onTransformDataChange && this.props.onTransformDataChange({
+    var cropData: ImageCropData = {
       offset: {
         x: this.props.image.width * offsetRatioX,
         y: this.props.image.height * offsetRatioY,
@@ -240,7 +243,8 @@ class ImageCropper extends React.Component {
         width: this.props.image.width * sizeRatioX,
         height: this.props.image.height * sizeRatioY,
       },
-    });
+    };
+    this.props.onTransformDataChange && this.props.onTransformDataChange(cropData);
   }
 
   render() {
@@ -271,8 +275,8 @@ class ImageCropper extends React.Component {
 }
 
 exports.framework = 'React';
-exports.title = 'ImageEditingManager';
-exports.description = 'Cropping and scaling with ImageEditingManager';
+exports.title = 'ImageEditor';
+exports.description = 'Cropping and scaling with ImageEditor';
 exports.examples = [{
   title: 'Image Cropping',
   render() {
diff --git a/Examples/UIExplorer/TransformExample.js b/Examples/UIExplorer/TransformExample.js
index 7da9eb5ac4e4..01a2813d41c5 100644
--- a/Examples/UIExplorer/TransformExample.js
+++ b/Examples/UIExplorer/TransformExample.js
@@ -10,6 +10,7 @@
  * FACEBOOK 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.
+ * @flow
  */
 'use strict';
 
diff --git a/Libraries/Image/ImageEditor.js b/Libraries/Image/ImageEditor.js
new file mode 100644
index 000000000000..4ea15349dd54
--- /dev/null
+++ b/Libraries/Image/ImageEditor.js
@@ -0,0 +1,72 @@
+/**
+ * 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 ImageEditor
+ * @flow
+ */
+'use strict';
+
+const RCTImageEditingManager = require('NativeModules').ImageEditingManager;
+
+type ImageCropData = {
+  /**
+   * The top-left corner of the cropped image, specified in the original
+   * image's coordinate space.
+   */
+  offset: {
+    x: number;
+    y: number;
+  };
+  /**
+   * The size (dimensions) of the cropped image, specified in the original
+   * image's coordinate space.
+   */
+  size: {
+    width: number;
+    height: number; 
+  };
+  /**
+   * (Optional) size to scale the cropped image to.
+   */
+  displaySize?: ?{
+    width: number;
+    height: number;
+  };
+  /**
+   * (Optional) the resizing mode to use when scaling the image. If the
+   * `displaySize` param is not specified, this has no effect.
+   */
+  resizeMode?: ?$Enum<{
+    contain: string;
+    cover: string;
+    stretch: string;
+  }>;
+};
+
+class ImageEditor {
+  /**
+   * Crop the image specified by the URI param. If URI points to a remote
+   * image, it will be downloaded automatically. If the image cannot be
+   * loaded/downloaded, the failure callback will be called. 
+   *
+   * If the cropping process is successful, the resultant cropped image
+   * will be stored in the ImageStore, and the URI returned in the success
+   * callback will point to the image in the store. Remember to delete the
+   * cropped image from the ImageStore when you are done with it.
+   */
+  static cropImage(
+    uri: string,
+    cropData: ImageCropData,
+    success: (uri: string) => void,
+    failure: (error: Object) => void
+  ) {
+    RCTImageEditingManager.cropImage(uri, cropData, success, failure);
+  }
+}
+
+module.exports = ImageEditor;
diff --git a/Libraries/Image/ImageStore.js b/Libraries/Image/ImageStore.js
new file mode 100644
index 000000000000..e4006a73d9b9
--- /dev/null
+++ b/Libraries/Image/ImageStore.js
@@ -0,0 +1,83 @@
+/**
+ * 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 ImageStore
+ * @flow
+ */
+'use strict';
+
+const RCTImageStoreManager = require('NativeModules').ImageStoreManager;
+
+class ImageStore {
+  /**
+   * Check if the ImageStore contains image data for the specified URI.
+   * @platform ios
+   */
+  static hasImageForTag(uri: string, callback: (hasImage: bool) => void) {
+    if (RCTImageStoreManager.hasImageForTag) {
+      RCTImageStoreManager.hasImageForTag(uri, callback);
+    } else {
+      console.warn('hasImageForTag() not implemented');
+    }
+  }
+
+  /**
+   * Delete an image from the ImageStore. Images are stored in memory and
+   * must be manually removed when you are finished with them, otherwise they
+   * will continue to use up RAM until the app is terminated. It is safe to
+   * call `removeImageForTag()` without first calling `hasImageForTag()`, it
+   * will simply fail silently.
+   * @platform ios
+   */
+  static removeImageForTag(uri: string) {
+    if (RCTImageStoreManager.removeImageForTag) {
+      RCTImageStoreManager.removeImageForTag(uri);
+    } else {
+      console.warn('removeImageForTag() not implemented');
+    }
+  }
+
+  /**
+   * Stores a base64-encoded image in the ImageStore, and returns a URI that
+   * can be used to access or display the image later. Images are stored in
+   * memory only, and must be manually deleted when you are finished with
+   * them by calling `removeImageForTag()`.
+   *
+   * Note that it is very inefficient to transfer large quantities of binary
+   * data between JS and native code, so you should avoid calling this more
+   * than necessary.
+   */
+  static addImageFromBase64(
+    base64ImageData: string,
+    success: (uri: string) => void,
+    failure: (error: any) => void
+  ) {
+    RCTImageStoreManager.addImageFromBase64(base64ImageData, success, failure);
+  }
+
+  /**
+   * Retrieves the base64-encoded data for an image in the ImageStore. If the
+   * specified URI does not match an image in the store, the failure callback
+   * will be called.
+   *
+   * Note that it is very inefficient to transfer large quantities of binary
+   * data between JS and native code, so you should avoid calling this more
+   * than necessary. To display an image in the ImageStore, you can just pass
+   * the URI to an `<Image/>` component; there is no need to retrieve the
+   * base64 data.
+   */
+  static getBase64ForTag(
+    uri: string,
+    success: (base64ImageData: string) => void,
+    failure: (error: any) => void
+  ) {
+    RCTImageStoreManager.getBase64ForTag(uri, success, failure);
+  }
+}
+
+module.exports = ImageStore;
\ No newline at end of file
diff --git a/Libraries/Image/RCTImageEditingManager.m b/Libraries/Image/RCTImageEditingManager.m
index cd81bbfbeed7..76fbc2703571 100644
--- a/Libraries/Image/RCTImageEditingManager.m
+++ b/Libraries/Image/RCTImageEditingManager.m
@@ -39,27 +39,18 @@ @implementation RCTImageEditingManager
                   successCallback:(RCTResponseSenderBlock)successCallback
                   errorCallback:(RCTResponseErrorBlock)errorCallback)
 {
-  NSDictionary *offset = cropData[@"offset"];
-  NSDictionary *size = cropData[@"size"];
-  NSDictionary *displaySize = cropData[@"displaySize"];
-  NSString *resizeMode = cropData[@"resizeMode"] ?: @"contain";
+  CGRect rect = {
+    [RCTConvert CGPoint:cropData[@"offset"]],
+    [RCTConvert CGSize:cropData[@"size"]]
+  };
 
-  if (!offset[@"x"] || !offset[@"y"] || !size[@"width"] || !size[@"height"]) {
-    NSString *errorMessage = [NSString stringWithFormat:@"Invalid cropData: %@", cropData];
-    RCTLogError(@"%@", errorMessage);
-    errorCallback(RCTErrorWithMessage(errorMessage));
-    return;
-  }
+  NSString *resizeMode = cropData[@"resizeMode"] ?: @"contain";
 
   [_bridge.imageLoader loadImageWithTag:imageTag callback:^(NSError *error, UIImage *image) {
     if (error) {
       errorCallback(error);
       return;
     }
-    CGRect rect = (CGRect){
-      [RCTConvert CGPoint:offset],
-      [RCTConvert CGSize:size]
-    };
 
     // Crop image
     CGRect rectToDrawIn = {{-rect.origin.x, -rect.origin.y}, image.size};
@@ -68,8 +59,8 @@ @implementation RCTImageEditingManager
     UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext();
     UIGraphicsEndImageContext();
 
-    if (displaySize && displaySize[@"width"] && displaySize[@"height"]) {
-      CGSize targetSize = [RCTConvert CGSize:displaySize];
+    if (cropData[@"displaySize"]) {
+      CGSize targetSize = [RCTConvert CGSize:cropData[@"displaySize"]];
       croppedImage = [self scaleImage:croppedImage targetSize:targetSize resizeMode:resizeMode];
     }
 
diff --git a/Libraries/Image/RCTImageStoreManager.m b/Libraries/Image/RCTImageStoreManager.m
index 3bda2df35abe..1827bd285a71 100644
--- a/Libraries/Image/RCTImageStoreManager.m
+++ b/Libraries/Image/RCTImageStoreManager.m
@@ -86,6 +86,12 @@ - (void)storeImage:(UIImage *)image withBlock:(void (^)(NSString *imageTag))bloc
   [_store removeObjectForKey:imageTag];
 }
 
+RCT_EXPORT_METHOD(hasImageForTag:(NSString *)imageTag
+                  callback:(RCTResponseSenderBlock)callback)
+{
+  callback(@[@(_store[imageTag] != nil)]);
+}
+
 // TODO (#5906496): Name could be more explicit - something like getBase64EncodedDataForTag:?
 RCT_EXPORT_METHOD(getBase64ForTag:(NSString *)imageTag
                   successCallback:(RCTResponseSenderBlock)successCallback
diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js
index 68876a712968..f2313318b949 100644
--- a/Libraries/react-native/react-native.js
+++ b/Libraries/react-native/react-native.js
@@ -18,6 +18,8 @@ var ReactNative = {
   get DatePickerIOS() { return require('DatePickerIOS'); },
   get DrawerLayoutAndroid() { return require('DrawerLayoutAndroid'); },
   get Image() { return require('Image'); },
+  get ImageEditor() { return require('ImageEditor'); },
+  get ImageStore() { return require('ImageStore'); },
   get ListView() { return require('ListView'); },
   get MapView() { return require('MapView'); },
   get Modal() { return require('Modal'); },
diff --git a/Libraries/react-native/react-native.js.flow b/Libraries/react-native/react-native.js.flow
index c3d841e5a778..bc7d05513a51 100644
--- a/Libraries/react-native/react-native.js.flow
+++ b/Libraries/react-native/react-native.js.flow
@@ -30,6 +30,8 @@ var ReactNative = Object.assign(Object.create(require('React')), {
   DatePickerIOS: require('DatePickerIOS'),
   DrawerLayoutAndroid: require('DrawerLayoutAndroid'),
   Image: require('Image'),
+  ImageEditor: require('ImageEditor'),
+  ImageStore: require('ImageStore'),
   ListView: require('ListView'),
   MapView: require('MapView'),
   Modal: require('Modal'),

From d0de0767e3c2a034aca4d4cf5330b0937ea0dd9f Mon Sep 17 00:00:00 2001
From: Denis Koroskin <dkoroskin@fb.com>
Date: Tue, 22 Dec 2015 13:43:18 -0800
Subject: [PATCH 0491/1411] Implement touch intercepting in RCTView

Summary:
public React allows excluding certain elements from touch handling by assigning `PointerEvents` filter to them, such as BOX_NONE - this element will not receive touch but its children will, BOX_ONLY - only this element will receive pointer event and not children, NONE - neither this element nor its children will receive pointer events, and AUTO - pointer events are allowed for both this element and its children.

This diff adds PointerEvents support to flat RCTView. Most of the implementation is copied from ReactViewManager/ReactViewGroup. One small change is made to TouchTargetHelper to ensure that it works correctly with virtual nodes when their parent has PointerEvents set to PointerEvents.BOX_NONE.

Reviewed By: ahmedre

Differential Revision: D2784208

fb-gh-sync-id: 4b831f9b1bfb8014a99d7b33534ae7ff7b4ab498
---
 .../react/uimanager/TouchTargetHelper.java     | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java
index 8564258babe7..9635d5bf6f1f 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java
@@ -173,7 +173,23 @@ private static boolean isTransformedTouchPointInView(
       // This view can't be the target, but its children might
       if (view instanceof ViewGroup) {
         View targetView = findTouchTargetView(eventCoords, (ViewGroup) view);
-        return targetView != view ? targetView : null;
+        if (targetView != view) {
+          return targetView;
+        }
+
+        // PointerEvents.BOX_NONE means that this react element cannot receive pointer events.
+        // However, there might be virtual children that can receive pointer events, in which case
+        // we still want to return this View and dispatch a pointer event to the virtual element.
+        // Note that this currently only applies to Nodes/FlatViewGroup as it's the only class that
+        // is both a ViewGroup and ReactCompoundView (ReactTextView is a ReactCompoundView but not a
+        // ViewGroup).
+        if (view instanceof ReactCompoundView) {
+          int reactTag = ((ReactCompoundView)view).reactTagForTouch(eventCoords[0], eventCoords[1]);
+          if (reactTag != view.getId()) {
+            // make sure we exclude the View itself because of the PointerEvents.BOX_NONE
+            return view;
+          }
+        }
       }
       return null;
 

From c74d6403f5c37bfc8291825850a3146e2a72c85d Mon Sep 17 00:00:00 2001
From: Christopher Dro <hello@blick-labs.com>
Date: Tue, 22 Dec 2015 15:09:27 -0800
Subject: [PATCH 0492/1411] Update dev menu to keep track of element inspector.

Summary:
This PR makes the android dev menu consistent with iOS where toggling the inspector will update the button label accordingly.
Closes https://github.com/facebook/react-native/pull/4628

Reviewed By: svcscm

Differential Revision: D2740549

Pulled By: mkonicek

fb-gh-sync-id: 02458d09b84e1592dcf245290ee2bbfb2863060d
---
 .../facebook/react/testing/ReactSettingsForTests.java    | 8 +++++---
 .../facebook/react/devsupport/DevInternalSettings.java   | 9 +++++++++
 .../com/facebook/react/devsupport/DevSupportManager.java | 5 ++++-
 .../facebook/react/modules/debug/DeveloperSettings.java  | 5 +++++
 .../src/main/res/devsupport/values-cs/strings.xml        | 2 +-
 .../src/main/res/devsupport/values-da/strings.xml        | 2 +-
 .../src/main/res/devsupport/values-de/strings.xml        | 2 +-
 .../src/main/res/devsupport/values-el/strings.xml        | 2 +-
 .../src/main/res/devsupport/values-en-rGB/strings.xml    | 2 +-
 .../src/main/res/devsupport/values-es-rES/strings.xml    | 2 +-
 .../src/main/res/devsupport/values-es/strings.xml        | 2 +-
 .../src/main/res/devsupport/values-fb-rLL/strings.xml    | 2 +-
 .../src/main/res/devsupport/values-fb/strings.xml        | 2 +-
 .../src/main/res/devsupport/values-fi/strings.xml        | 2 +-
 .../src/main/res/devsupport/values-fr/strings.xml        | 2 +-
 .../src/main/res/devsupport/values-hu/strings.xml        | 2 +-
 .../src/main/res/devsupport/values-in/strings.xml        | 2 +-
 .../src/main/res/devsupport/values-it/strings.xml        | 2 +-
 .../src/main/res/devsupport/values-ja/strings.xml        | 2 +-
 .../src/main/res/devsupport/values-ko/strings.xml        | 2 +-
 .../src/main/res/devsupport/values-nb/strings.xml        | 2 +-
 .../src/main/res/devsupport/values-nl/strings.xml        | 2 +-
 .../src/main/res/devsupport/values-pl/strings.xml        | 2 +-
 .../src/main/res/devsupport/values-pt-rPT/strings.xml    | 2 +-
 .../src/main/res/devsupport/values-pt/strings.xml        | 2 +-
 .../src/main/res/devsupport/values-ro/strings.xml        | 2 +-
 .../src/main/res/devsupport/values-ru/strings.xml        | 2 +-
 .../src/main/res/devsupport/values-sv/strings.xml        | 2 +-
 .../src/main/res/devsupport/values-th/strings.xml        | 2 +-
 .../src/main/res/devsupport/values-tr/strings.xml        | 2 +-
 .../src/main/res/devsupport/values-vi/strings.xml        | 2 +-
 .../src/main/res/devsupport/values-zh-rCN/strings.xml    | 2 +-
 .../src/main/res/devsupport/values-zh-rHK/strings.xml    | 2 +-
 .../src/main/res/devsupport/values-zh-rTW/strings.xml    | 2 +-
 ReactAndroid/src/main/res/devsupport/values/strings.xml  | 3 ++-
 35 files changed, 55 insertions(+), 35 deletions(-)

diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactSettingsForTests.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactSettingsForTests.java
index 2b6ae8057215..417638dd2a8f 100644
--- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactSettingsForTests.java
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactSettingsForTests.java
@@ -10,9 +10,6 @@
 
 import com.facebook.react.modules.debug.DeveloperSettings;
 
-/**
- * Default ReactSettings for tests.
- */
 public class ReactSettingsForTests implements DeveloperSettings {
 
   @Override
@@ -29,4 +26,9 @@ public boolean isAnimationFpsDebugEnabled() {
   public boolean isJSDevModeEnabled() {
     return true;
   }
+
+  @Override
+  public boolean isElementInspectorEnabled() {
+    return false;
+  }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java
index 9c3454fe8f97..291f63adc5ec 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java
@@ -33,6 +33,7 @@ public class DevInternalSettings implements
   private static final String PREFS_DEBUG_SERVER_HOST_KEY = "debug_http_host";
   private static final String PREFS_ANIMATIONS_DEBUG_KEY = "animations_debug";
   private static final String PREFS_RELOAD_ON_JS_CHANGE_KEY = "reload_on_js_change";
+  private static final String PREFS_INSPECTOR_DEBUG_KEY = "inspector_debug";
 
   private final SharedPreferences mPreferences;
   private final DevSupportManager mDebugManager;
@@ -83,4 +84,12 @@ public boolean isReloadOnJSChangeEnabled() {
   public void setReloadOnJSChangeEnabled(boolean enabled) {
     mPreferences.edit().putBoolean(PREFS_RELOAD_ON_JS_CHANGE_KEY, enabled).apply();
   }
+
+  public boolean isElementInspectorEnabled() {
+    return mPreferences.getBoolean(PREFS_INSPECTOR_DEBUG_KEY, false);
+  }
+
+  public void setElementInspectorEnabled(boolean enabled) {
+    mPreferences.edit().putBoolean(PREFS_INSPECTOR_DEBUG_KEY, enabled).apply();
+  }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
index 0a5d1da14651..3e38a19fb974 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
@@ -265,10 +265,13 @@ public void onOptionSelected() {
           }
         });
     options.put(
-        mApplicationContext.getString(R.string.catalyst_inspect_element),
+        mDevSettings.isElementInspectorEnabled()
+          ? mApplicationContext.getString(R.string.catalyst_element_inspector_off)
+          : mApplicationContext.getString(R.string.catalyst_element_inspector),
         new DevOptionHandler() {
           @Override
           public void onOptionSelected() {
+            mDevSettings.setElementInspectorEnabled(!mDevSettings.isElementInspectorEnabled());
             mReactInstanceCommandsHandler.toggleElementInspector();
           }
         });
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/debug/DeveloperSettings.java b/ReactAndroid/src/main/java/com/facebook/react/modules/debug/DeveloperSettings.java
index 13a230fc35e5..5ff8dfbf76f9 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/debug/DeveloperSettings.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/debug/DeveloperSettings.java
@@ -28,4 +28,9 @@ public interface DeveloperSettings {
    * @return Whether dev mode should be enabled in JS bundles.
    */
   boolean isJSDevModeEnabled();
+
+  /**
+   * @return Whether element inspector is enabled.
+   */
+  boolean isElementInspectorEnabled();
 }
diff --git a/ReactAndroid/src/main/res/devsupport/values-cs/strings.xml b/ReactAndroid/src/main/res/devsupport/values-cs/strings.xml
index c3432a9a8c09..426afdffd3be 100644
--- a/ReactAndroid/src/main/res/devsupport/values-cs/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-cs/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">Čekejte prosím...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">Prozkoumat prvek</string>
+    <string name="catalyst_element_inspector">Prozkoumat prvek</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-da/strings.xml b/ReactAndroid/src/main/res/devsupport/values-da/strings.xml
index 1d91235a5114..0456813b0f2e 100644
--- a/ReactAndroid/src/main/res/devsupport/values-da/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-da/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">Vent venligst...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">Inspicer element</string>
+    <string name="catalyst_element_inspector">Inspicer element</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-de/strings.xml b/ReactAndroid/src/main/res/devsupport/values-de/strings.xml
index 993f9ef5de8f..3f3831ac5683 100644
--- a/ReactAndroid/src/main/res/devsupport/values-de/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-de/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">Bitte warten Sie ...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">Element untersuchen</string>
+    <string name="catalyst_element_inspector">Element untersuchen</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-el/strings.xml b/ReactAndroid/src/main/res/devsupport/values-el/strings.xml
index 4686909c1034..d441a14fb1eb 100644
--- a/ReactAndroid/src/main/res/devsupport/values-el/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-el/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">Περιμένετε...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">Εξέταση στοιχείου</string>
+    <string name="catalyst_element_inspector">Εξέταση στοιχείου</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-en-rGB/strings.xml b/ReactAndroid/src/main/res/devsupport/values-en-rGB/strings.xml
index ff57f514337c..de9b5103cbee 100644
--- a/ReactAndroid/src/main/res/devsupport/values-en-rGB/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-en-rGB/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">Please wait...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">Inspect Element</string>
+    <string name="catalyst_element_inspector">Show Inspector</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-es-rES/strings.xml b/ReactAndroid/src/main/res/devsupport/values-es-rES/strings.xml
index 79c6256d89ee..babdb30d2237 100644
--- a/ReactAndroid/src/main/res/devsupport/values-es-rES/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-es-rES/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">Espera...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">Inspeccionar elemento</string>
+    <string name="catalyst_element_inspector">Inspeccionar elemento</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-es/strings.xml b/ReactAndroid/src/main/res/devsupport/values-es/strings.xml
index f83b2b96e876..770fd6d0cf0c 100644
--- a/ReactAndroid/src/main/res/devsupport/values-es/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-es/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">Espera...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">Inspeccionar elemento</string>
+    <string name="catalyst_element_inspector">Inspeccionar elemento</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-fb-rLL/strings.xml b/ReactAndroid/src/main/res/devsupport/values-fb-rLL/strings.xml
index cf7e56e351fc..2b4f0a2ab6ce 100644
--- a/ReactAndroid/src/main/res/devsupport/values-fb-rLL/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-fb-rLL/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">(অনুগ্রহ করে অপেক্ষা করুন….)</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">(तत्व निरीक्षण गर्नुहोस्)</string>
+    <string name="catalyst_element_inspector">(तत्व निरीक्षण गर्नुहोस्)</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-fb/strings.xml b/ReactAndroid/src/main/res/devsupport/values-fb/strings.xml
index 4a3ea031ea4f..9af8d4bad19a 100644
--- a/ReactAndroid/src/main/res/devsupport/values-fb/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-fb/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">[Please wait...#71bad104a80f916d3bfb1ffa23a487af:1]</string>
     <string name="catalyst_jsload_message">[Fetching JS bundle#0de4127d4fc6e7d1e265e07433f26e25:1]</string>
     <string name="catalyst_jsload_error">[Unable to download JS bundle#51057ecd2555f91873cce4c452e1ea03:1]</string>
-    <string name="catalyst_inspect_element">[Inspect Element#c1b106c92869437ebd88f326d632b973:1]</string>
+    <string name="catalyst_element_inspector">[Show Inspector#c1b106c92869437ebd88f326d632b973:1]</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-fi/strings.xml b/ReactAndroid/src/main/res/devsupport/values-fi/strings.xml
index 2468d372e8c0..6499928f2f0c 100644
--- a/ReactAndroid/src/main/res/devsupport/values-fi/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-fi/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">Odota…</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">Tarkista elementti</string>
+    <string name="catalyst_element_inspector">Tarkista elementti</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-fr/strings.xml b/ReactAndroid/src/main/res/devsupport/values-fr/strings.xml
index f9fcf21a057c..d805db875c33 100644
--- a/ReactAndroid/src/main/res/devsupport/values-fr/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-fr/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">Veuillez patienter...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">Inspecter l’élément</string>
+    <string name="catalyst_element_inspector">Inspecter l’élément</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-hu/strings.xml b/ReactAndroid/src/main/res/devsupport/values-hu/strings.xml
index d44f8dc8f1d8..cfa294b08f7a 100644
--- a/ReactAndroid/src/main/res/devsupport/values-hu/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-hu/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">Kérjük, várj...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">Elem megtekintése</string>
+    <string name="catalyst_element_inspector">Elem megtekintése</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-in/strings.xml b/ReactAndroid/src/main/res/devsupport/values-in/strings.xml
index fe3b189a51a5..0b5a2dbb9462 100644
--- a/ReactAndroid/src/main/res/devsupport/values-in/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-in/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">Harap tunggu...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">Periksa Elemen</string>
+    <string name="catalyst_element_inspector">Periksa Elemen</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-it/strings.xml b/ReactAndroid/src/main/res/devsupport/values-it/strings.xml
index d9fe2dddf218..0ee3764be8fc 100644
--- a/ReactAndroid/src/main/res/devsupport/values-it/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-it/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">Attendi...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">Esamina elemento</string>
+    <string name="catalyst_element_inspector">Esamina elemento</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-ja/strings.xml b/ReactAndroid/src/main/res/devsupport/values-ja/strings.xml
index 3ae3b6917e3d..25e5291e82dc 100644
--- a/ReactAndroid/src/main/res/devsupport/values-ja/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-ja/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">しばらくお待ちください</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">要素を確認</string>
+    <string name="catalyst_element_inspector">要素を確認</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-ko/strings.xml b/ReactAndroid/src/main/res/devsupport/values-ko/strings.xml
index 21384a3a79ba..8f0d6633895f 100644
--- a/ReactAndroid/src/main/res/devsupport/values-ko/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-ko/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">기다려주세요...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">요소 검사</string>
+    <string name="catalyst_element_inspector">요소 검사</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-nb/strings.xml b/ReactAndroid/src/main/res/devsupport/values-nb/strings.xml
index 24f646c972c5..88450696a1db 100644
--- a/ReactAndroid/src/main/res/devsupport/values-nb/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-nb/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">Vent litt ...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">Inspiser element</string>
+    <string name="catalyst_element_inspector">Inspiser element</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-nl/strings.xml b/ReactAndroid/src/main/res/devsupport/values-nl/strings.xml
index 85d5d70f95aa..3fe195b32826 100644
--- a/ReactAndroid/src/main/res/devsupport/values-nl/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-nl/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">Even geduld...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">Element inspecteren</string>
+    <string name="catalyst_element_inspector">Element inspecteren</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-pl/strings.xml b/ReactAndroid/src/main/res/devsupport/values-pl/strings.xml
index b96d4f04fa03..88e9de7a19dc 100644
--- a/ReactAndroid/src/main/res/devsupport/values-pl/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-pl/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">Zaczekaj...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">Zbadaj element</string>
+    <string name="catalyst_element_inspector">Zbadaj element</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-pt-rPT/strings.xml b/ReactAndroid/src/main/res/devsupport/values-pt-rPT/strings.xml
index 98d7879bb9aa..1c5354bdc966 100644
--- a/ReactAndroid/src/main/res/devsupport/values-pt-rPT/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-pt-rPT/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">Aguarda...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">Inspect Element</string>
+    <string name="catalyst_element_inspector">Show Inspector</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-pt/strings.xml b/ReactAndroid/src/main/res/devsupport/values-pt/strings.xml
index ec3284c279f5..aca1d88b01ed 100644
--- a/ReactAndroid/src/main/res/devsupport/values-pt/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-pt/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">Aguarde...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">Inspect Element</string>
+    <string name="catalyst_element_inspector">Show Inspector</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-ro/strings.xml b/ReactAndroid/src/main/res/devsupport/values-ro/strings.xml
index 021a3fa34f2c..71b20b37ef66 100644
--- a/ReactAndroid/src/main/res/devsupport/values-ro/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-ro/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">Please wait...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">Inspect Element</string>
+    <string name="catalyst_element_inspector">Show Inspector</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-ru/strings.xml b/ReactAndroid/src/main/res/devsupport/values-ru/strings.xml
index 6d2ea955af2c..ee462ab36eec 100644
--- a/ReactAndroid/src/main/res/devsupport/values-ru/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-ru/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">Подождите...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">Проверить элемент</string>
+    <string name="catalyst_element_inspector">Проверить элемент</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-sv/strings.xml b/ReactAndroid/src/main/res/devsupport/values-sv/strings.xml
index da23a64ea98f..03440336834c 100644
--- a/ReactAndroid/src/main/res/devsupport/values-sv/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-sv/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">Vänta ...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">Inspektionselement</string>
+    <string name="catalyst_element_inspector">Inspektionselement</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-th/strings.xml b/ReactAndroid/src/main/res/devsupport/values-th/strings.xml
index 57ecdc141d3a..da3454ae4b91 100644
--- a/ReactAndroid/src/main/res/devsupport/values-th/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-th/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">โปรดรอ...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">ตรวจสอบอิลิเมนต์</string>
+    <string name="catalyst_element_inspector">ตรวจสอบอิลิเมนต์</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-tr/strings.xml b/ReactAndroid/src/main/res/devsupport/values-tr/strings.xml
index 62b5118494b0..afeccc0b7030 100644
--- a/ReactAndroid/src/main/res/devsupport/values-tr/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-tr/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">Lütfen bekleyin...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">Öğeyi Denetle</string>
+    <string name="catalyst_element_inspector">Öğeyi Denetle</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-vi/strings.xml b/ReactAndroid/src/main/res/devsupport/values-vi/strings.xml
index 2f35967da51a..0e37ac1bc54f 100644
--- a/ReactAndroid/src/main/res/devsupport/values-vi/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-vi/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">Vui lòng đợi...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">Kiểm tra phần tử</string>
+    <string name="catalyst_element_inspector">Kiểm tra phần tử</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-zh-rCN/strings.xml b/ReactAndroid/src/main/res/devsupport/values-zh-rCN/strings.xml
index 021308f2dc8c..ab8a485d5f61 100644
--- a/ReactAndroid/src/main/res/devsupport/values-zh-rCN/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-zh-rCN/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">请稍等...</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">检查元素</string>
+    <string name="catalyst_element_inspector">检查元素</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-zh-rHK/strings.xml b/ReactAndroid/src/main/res/devsupport/values-zh-rHK/strings.xml
index cd2c73c36715..68be2f34cd76 100644
--- a/ReactAndroid/src/main/res/devsupport/values-zh-rHK/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-zh-rHK/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">請稍候……</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">檢查項目</string>
+    <string name="catalyst_element_inspector">檢查項目</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values-zh-rTW/strings.xml b/ReactAndroid/src/main/res/devsupport/values-zh-rTW/strings.xml
index bad914ff30a9..e8e3a392e00d 100644
--- a/ReactAndroid/src/main/res/devsupport/values-zh-rTW/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values-zh-rTW/strings.xml
@@ -12,5 +12,5 @@
     <string name="catalyst_jsload_title">請稍候……</string>
     <string name="catalyst_jsload_message">Fetching JS bundle</string>
     <string name="catalyst_jsload_error">Unable to download JS bundle</string>
-    <string name="catalyst_inspect_element">檢查元素</string>
+    <string name="catalyst_element_inspector">檢查元素</string>
 </resources>
diff --git a/ReactAndroid/src/main/res/devsupport/values/strings.xml b/ReactAndroid/src/main/res/devsupport/values/strings.xml
index 8969fe61ea5c..1e60598d34dc 100644
--- a/ReactAndroid/src/main/res/devsupport/values/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values/strings.xml
@@ -14,7 +14,8 @@
   <string name="catalyst_jsload_error" project="catalyst" translatable="false">Unable to download JS bundle. Did you forget to start the development server or connect your device?</string>
   <string name="catalyst_remotedbg_message" project="catalyst" translatable="false">Connecting to remote debugger</string>
   <string name="catalyst_remotedbg_error" project="catalyst" translatable="false">Unable to connect with remote debugger</string>
-  <string name="catalyst_inspect_element" project="catalyst" translatable="false">Inspect Element</string>
+  <string name="catalyst_element_inspector" project="catalyst" translatable="false">Show Inspector</string>
+  <string name="catalyst_element_inspector_off" project="catalyst" translatable="false">Hide Inspector</string>
   <string name="catalyst_start_profile" project="catalyst" translatable="false">Start Profile</string>
   <string name="catalyst_stop_profile" project="catalyst" translatable="false">Stop Profile</string>
 </resources>

From 1b80007236409b024e09e3110ee50f8cdc813173 Mon Sep 17 00:00:00 2001
From: Philipp von Weitershausen <philipp@weitershausen.de>
Date: Tue, 22 Dec 2015 15:16:46 -0800
Subject: [PATCH 0493/1411] Improvements to the packager for very large
 projects

Summary:
Here are some small fixes for issues we've encountered with very large RN projects (mostly huge dependency trees in `node_modules`).

cc amasad martinbigio
Closes https://github.com/facebook/react-native/pull/4880

Reviewed By: svcscm

Differential Revision: D2782834

Pulled By: mkonicek

fb-gh-sync-id: e316a62b84ba796b80ac819431414ebf27f7b566
---
 local-cli/server/runServer.js                                 | 4 ++++
 .../src/DependencyResolver/FileWatcher/index.js               | 2 +-
 packager/react-packager/src/DependencyResolver/fastfs.js      | 4 ++--
 3 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/local-cli/server/runServer.js b/local-cli/server/runServer.js
index 47e5e73a2944..a05b0e2e5e0d 100644
--- a/local-cli/server/runServer.js
+++ b/local-cli/server/runServer.js
@@ -49,6 +49,10 @@ function runServer(args, config, readyCallback) {
       readyCallback();
     }
   );
+  // Disable any kind of automatic timeout behavior for incoming
+  // requests in case it takes the packager more than the default
+  // timeout of 120 seconds to respond to a request.
+  serverInstance.timeout = 0;
 }
 
 function getAppMiddleware(args, config) {
diff --git a/packager/react-packager/src/DependencyResolver/FileWatcher/index.js b/packager/react-packager/src/DependencyResolver/FileWatcher/index.js
index 227687e1c820..6c8a07093463 100644
--- a/packager/react-packager/src/DependencyResolver/FileWatcher/index.js
+++ b/packager/react-packager/src/DependencyResolver/FileWatcher/index.js
@@ -13,7 +13,7 @@ const sane = require('sane');
 const Promise = require('promise');
 const exec = require('child_process').exec;
 
-const MAX_WAIT_TIME = 25000;
+const MAX_WAIT_TIME = 120000;
 
 // TODO(amasad): can we use watchman version command instead?
 const detectingWatcherClass = new Promise(function(resolve) {
diff --git a/packager/react-packager/src/DependencyResolver/fastfs.js b/packager/react-packager/src/DependencyResolver/fastfs.js
index 3a6c3ee1386a..5bff24379378 100644
--- a/packager/react-packager/src/DependencyResolver/fastfs.js
+++ b/packager/react-packager/src/DependencyResolver/fastfs.js
@@ -293,11 +293,11 @@ class File {
   }
 
   getFiles() {
-    const files = [];
+    let files = [];
     Object.keys(this.children).forEach(key => {
       const file = this.children[key];
       if (file.isDir) {
-        files.push(...file.getFiles());
+        files = files.concat(file.getFiles());
       } else {
         files.push(file);
       }

From 134dd57cd651e12d70e4f34e051e291ca5f2c577 Mon Sep 17 00:00:00 2001
From: Mike Fowler <mike@mikefowler.me>
Date: Tue, 22 Dec 2015 16:24:07 -0800
Subject: [PATCH 0494/1411] Update ToolbarAndroid.android.js

Summary:
Updates the documentation for `ToolbarAndroid.android.js` with proper asset system syntax.
Closes https://github.com/facebook/react-native/pull/4908

Reviewed By: svcscm

Differential Revision: D2783113

Pulled By: mkonicek

fb-gh-sync-id: 321d79cb80025d7a065ccf012678ecebccb35bae
---
 .../Components/ToolbarAndroid/ToolbarAndroid.android.js     | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js
index 844889da0bea..26f03f7c9090 100644
--- a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js
+++ b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js
@@ -49,9 +49,9 @@ var optionalImageSource = ReactPropTypes.oneOfType([
  * render: function() {
  *   return (
  *     <ToolbarAndroid
- *       logo={require('image!app_logo')}
+ *       logo={require('./app_logo.png')}
  *       title="AwesomeApp"
- *       actions={[{title: 'Settings', icon: require('image!icon_settings'), show: 'always'}]}
+ *       actions={[{title: 'Settings', icon: require('./icon_settings.png'), show: 'always'}]}
  *       onActionSelected={this.onActionSelected} />
  *   )
  * },
@@ -77,7 +77,7 @@ var ToolbarAndroid = React.createClass({
      * This property takes an array of objects, where each object has the following keys:
      *
      * * `title`: **required**, the title of this action
-     * * `icon`: the icon for this action, e.g. `require('image!some_icon')`
+     * * `icon`: the icon for this action, e.g. `require('./some_icon.png')`
      * * `show`: when to show this action as an icon or hide it in the overflow menu: `always`,
      * `ifRoom` or `never`
      * * `showWithText`: boolean, whether to show text alongside the icon or not

From 7164c755cb18c01697cedc40c214389d247f5e85 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andreas=20Stu=CC=88tz?= <andreas.stuetz@runtastic.com>
Date: Tue, 22 Dec 2015 16:45:14 -0800
Subject: [PATCH 0495/1411] Add props for content insets

Summary:
This PR adds a contentInsetStart and a contentInsetEnd property to ToolbarAndroid, allowing offsetting Toolbar contents to different keylines
Closes https://github.com/facebook/react-native/pull/4699

Reviewed By: svcscm

Differential Revision: D2759294

Pulled By: mkonicek

fb-gh-sync-id: f22aa255f07929ad7a99ac7568981d35e848065b
---
 .../ToolbarAndroid/ToolbarAndroid.android.js  | 18 ++++++++
 .../views/toolbar/ReactToolbarManager.java    | 45 +++++++++++++++++++
 2 files changed, 63 insertions(+)

diff --git a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js
index 26f03f7c9090..ba5541e8a1ea 100644
--- a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js
+++ b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js
@@ -125,6 +125,24 @@ var ToolbarAndroid = React.createClass({
      * Sets the toolbar title color.
      */
     titleColor: ReactPropTypes.string,
+    /**
+     * Sets the content inset for the toolbar starting edge.
+     *
+     * The content inset affects the valid area for Toolbar content other than
+     * the navigation button and menu. Insets define the minimum margin for
+     * these components and can be used to effectively align Toolbar content
+     * along well-known gridlines.
+     */
+    contentInsetStart: ReactPropTypes.number,
+    /**
+     * Sets the content inset for the toolbar ending edge.
+     *
+     * The content inset affects the valid area for Toolbar content other than
+     * the navigation button and menu. Insets define the minimum margin for
+     * these components and can be used to effectively align Toolbar content
+     * along well-known gridlines.
+     */
+    contentInsetEnd: ReactPropTypes.number,
     /**
      * Used to set the toolbar direction to RTL.
      * In addition to this property you need to add
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java
index 36aac87e73ef..0a157d099931 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java
@@ -26,6 +26,7 @@
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.bridge.ReadableMap;
 import com.facebook.react.common.MapBuilder;
+import com.facebook.react.uimanager.PixelUtil;
 import com.facebook.react.uimanager.ReactProp;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.UIManagerModule;
@@ -100,6 +101,22 @@ public void setTitleColor(ReactToolbar view, @Nullable Integer titleColor) {
     }
   }
 
+  @ReactProp(name = "contentInsetStart", defaultFloat = Float.NaN)
+  public void setContentInsetStart(ReactToolbar view, float insetStart) {
+    int inset = Float.isNaN(insetStart) ?
+        getDefaultContentInsets(view.getContext())[0] :
+        Math.round(PixelUtil.toPixelFromDIP(insetStart));
+    view.setContentInsetsRelative(inset, view.getContentInsetEnd());
+  }
+
+  @ReactProp(name = "contentInsetEnd", defaultFloat = Float.NaN)
+  public void setContentInsetEnd(ReactToolbar view, float insetEnd) {
+    int inset = Float.isNaN(insetEnd) ?
+        getDefaultContentInsets(view.getContext())[1] :
+        Math.round(PixelUtil.toPixelFromDIP(insetEnd));
+    view.setContentInsetsRelative(view.getContentInsetStart(), inset);
+  }
+
   @ReactProp(name = "nativeActions")
   public void setActions(ReactToolbar view, @Nullable ReadableArray actions) {
     view.setActions(actions);
@@ -148,6 +165,34 @@ public boolean needsCustomLayoutForChildren() {
     return true;
   }
 
+  private int[] getDefaultContentInsets(Context context) {
+    Resources.Theme theme = context.getTheme();
+    TypedArray toolbarStyle = null;
+    TypedArray contentInsets = null;
+
+    try {
+      toolbarStyle = theme
+              .obtainStyledAttributes(new int[]{R.attr.toolbarStyle});
+
+      int toolbarStyleResId = toolbarStyle.getResourceId(0, 0);
+
+      contentInsets = theme.obtainStyledAttributes(
+              toolbarStyleResId, new int[]{
+                      R.attr.contentInsetStart,
+                      R.attr.contentInsetEnd,
+              });
+
+      int contentInsetStart = contentInsets.getDimensionPixelSize(0, 0);
+      int contentInsetEnd = contentInsets.getDimensionPixelSize(1, 0);
+
+      return new int[] {contentInsetStart, contentInsetEnd};
+    } finally {
+      recycleQuietly(toolbarStyle);
+      recycleQuietly(contentInsets);
+    }
+
+  }
+
   private static int[] getDefaultColors(Context context) {
     Resources.Theme theme = context.getTheme();
     TypedArray toolbarStyle = null;

From a162f72655505e5da28e4033b2ef1d49cfcf067f Mon Sep 17 00:00:00 2001
From: StefanT <shtefanntz@yahoo.com>
Date: Tue, 22 Dec 2015 19:29:01 -0800
Subject: [PATCH 0496/1411] Added ColorPropType

Summary:
Problem: https://github.com/facebook/react-native/issues/4708

Solution: Added a ColorPropType that validates the color used by the dev

Notes:
1) I'm working a Win8.1 machine and couldn't build the react-native using the github repo. As soon as I figure that out, I'll probably figure how to run the tests and how to add some for this feature.
2) It's my first pull request. Be gentle :)
Closes https://github.com/facebook/react-native/pull/4866

Reviewed By: bestander, svcscm

Differential Revision: D2783672

Pulled By: nicklockwood

fb-gh-sync-id: ca22aa3c0999188075681b5d20fff0631496e238
---
 Libraries/Components/MapView/MapView.js       | 16 +++------
 .../ProgressBarAndroid.android.js             |  3 +-
 Libraries/Components/Switch/Switch.js         |  9 ++---
 .../Components/SwitchIOS/SwitchIOS.ios.js     |  7 ++--
 .../Components/TabBarIOS/TabBarIOS.ios.js     |  5 +--
 .../ToolbarAndroid/ToolbarAndroid.android.js  |  5 +--
 .../Touchable/TouchableHighlight.js           |  3 +-
 .../Components/View/ViewStylePropTypes.js     | 15 ++++----
 Libraries/Image/ImageStylePropTypes.js        |  7 ++--
 .../PullToRefreshViewAndroid.android.js       |  7 ++--
 Libraries/StyleSheet/ColorPropType.js         | 34 +++++++++++++++++++
 Libraries/Text/TextStylePropTypes.js          |  5 +--
 Libraries/react-native/react-native.js        |  1 +
 Libraries/react-native/react-native.js.flow   |  1 +
 14 files changed, 78 insertions(+), 40 deletions(-)
 create mode 100644 Libraries/StyleSheet/ColorPropType.js

diff --git a/Libraries/Components/MapView/MapView.js b/Libraries/Components/MapView/MapView.js
index e10efa32be60..29257d1db421 100644
--- a/Libraries/Components/MapView/MapView.js
+++ b/Libraries/Components/MapView/MapView.js
@@ -11,6 +11,7 @@
  */
 'use strict';
 
+const ColorPropType = require('ColorPropType');
 const EdgeInsetsPropType = require('EdgeInsetsPropType');
 const Image = require('Image');
 const NativeMethodsMixin = require('NativeMethodsMixin');
@@ -166,10 +167,7 @@ const MapView = React.createClass({
        * are supported for regular pins. For custom pin images, any tintColor
        * value is supported on all iOS versions.
        */
-      tintColor: React.PropTypes.oneOfType([
-        React.PropTypes.string,
-        React.PropTypes.number
-      ]),
+      tintColor: ColorPropType,
 
       /**
        * Custom pin image. This must be a static image resource inside the app.
@@ -213,14 +211,8 @@ const MapView = React.createClass({
        * Line attributes
        */
       lineWidth: React.PropTypes.number,
-      strokeColor: React.PropTypes.oneOfType([
-        React.PropTypes.string,
-        React.PropTypes.number
-      ]),
-      fillColor: React.PropTypes.oneOfType([
-        React.PropTypes.string,
-        React.PropTypes.number
-      ]),
+      strokeColor: ColorPropType,
+      fillColor: ColorPropType,
 
       /**
        * Overlay id
diff --git a/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js b/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js
index fb2175b9962e..974eaf97d030 100644
--- a/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js
+++ b/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js
@@ -15,6 +15,7 @@ var React = require('React');
 var ReactPropTypes = require('ReactPropTypes');
 var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
 var View = require('View');
+var ColorPropType = require('ColorPropType');
 
 var requireNativeComponent = require('requireNativeComponent');
 
@@ -88,7 +89,7 @@ var ProgressBarAndroid = React.createClass({
     /**
      * Color of the progress bar.
      */
-    color: ReactPropTypes.string,
+    color: ColorPropType,
     /**
      * Used to locate this view in end-to-end tests.
      */
diff --git a/Libraries/Components/Switch/Switch.js b/Libraries/Components/Switch/Switch.js
index ceab1f0baea0..31ec91ef5eae 100644
--- a/Libraries/Components/Switch/Switch.js
+++ b/Libraries/Components/Switch/Switch.js
@@ -6,6 +6,7 @@
  */
 'use strict';
 
+var ColorPropType = require('ColorPropType');
 var NativeMethodsMixin = require('NativeMethodsMixin');
 var Platform = require('Platform');
 var React = require('React');
@@ -43,22 +44,22 @@ var Switch = React.createClass({
      * Used to locate this view in end-to-end tests.
      */
     testID: React.PropTypes.string,
-
+    
     /**
      * Background color when the switch is turned off.
      * @platform ios
      */
-    tintColor: React.PropTypes.string,
+    tintColor: ColorPropType,
     /**
      * Background color when the switch is turned on.
      * @platform ios
      */
-    onTintColor: React.PropTypes.string,
+    onTintColor: ColorPropType,
     /**
      * Color of the foreground switch grip.
      * @platform ios
      */
-    thumbTintColor: React.PropTypes.string,
+    thumbTintColor: ColorPropType,
   },
 
   getDefaultProps: function(): DefaultProps {
diff --git a/Libraries/Components/SwitchIOS/SwitchIOS.ios.js b/Libraries/Components/SwitchIOS/SwitchIOS.ios.js
index 35514f66fe11..798529c58535 100644
--- a/Libraries/Components/SwitchIOS/SwitchIOS.ios.js
+++ b/Libraries/Components/SwitchIOS/SwitchIOS.ios.js
@@ -13,6 +13,7 @@
  */
 'use strict';
 
+var ColorPropType = require('ColorPropType');
 var NativeMethodsMixin = require('NativeMethodsMixin');
 var PropTypes = require('ReactPropTypes');
 var React = require('React');
@@ -62,17 +63,17 @@ var SwitchIOS = React.createClass({
     /**
      * Background color when the switch is turned on.
      */
-    onTintColor: PropTypes.string,
+    onTintColor: ColorPropType,
 
     /**
      * Background color for the switch round button.
      */
-    thumbTintColor: PropTypes.string,
+    thumbTintColor: ColorPropType,
 
     /**
      * Background color when the switch is turned off.
      */
-    tintColor: PropTypes.string,
+    tintColor: ColorPropType,
   },
 
   getDefaultProps: function(): DefaultProps {
diff --git a/Libraries/Components/TabBarIOS/TabBarIOS.ios.js b/Libraries/Components/TabBarIOS/TabBarIOS.ios.js
index 660c8c62a137..3d168509fd60 100644
--- a/Libraries/Components/TabBarIOS/TabBarIOS.ios.js
+++ b/Libraries/Components/TabBarIOS/TabBarIOS.ios.js
@@ -11,6 +11,7 @@
  */
 'use strict';
 
+var ColorPropType = require('ColorPropType');
 var React = require('React');
 var StyleSheet = require('StyleSheet');
 var TabBarItemIOS = require('TabBarItemIOS');
@@ -29,11 +30,11 @@ var TabBarIOS = React.createClass({
     /**
      * Color of the currently selected tab icon
      */
-    tintColor: React.PropTypes.string,
+    tintColor: ColorPropType,
     /**
      * Background color of the tab bar
      */
-    barTintColor: React.PropTypes.string,
+    barTintColor: ColorPropType,
     /**
      * A Boolean value that indicates whether the tab bar is translucent
      */
diff --git a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js
index ba5541e8a1ea..060c6a1d0e48 100644
--- a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js
+++ b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js
@@ -18,6 +18,7 @@ var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
 var ReactPropTypes = require('ReactPropTypes');
 var UIManager = require('UIManager');
 var View = require('View');
+var ColorPropType = require('ColorPropType');
 
 var requireNativeComponent = require('requireNativeComponent');
 var resolveAssetSource = require('resolveAssetSource');
@@ -116,7 +117,7 @@ var ToolbarAndroid = React.createClass({
     /**
      * Sets the toolbar subtitle color.
      */
-    subtitleColor: ReactPropTypes.string,
+    subtitleColor: ColorPropType,
     /**
      * Sets the toolbar title.
      */
@@ -124,7 +125,7 @@ var ToolbarAndroid = React.createClass({
     /**
      * Sets the toolbar title color.
      */
-    titleColor: ReactPropTypes.string,
+    titleColor: ColorPropType,
     /**
      * Sets the content inset for the toolbar starting edge.
      *
diff --git a/Libraries/Components/Touchable/TouchableHighlight.js b/Libraries/Components/Touchable/TouchableHighlight.js
index 67c1e55a0b85..929c43dfcbfb 100644
--- a/Libraries/Components/Touchable/TouchableHighlight.js
+++ b/Libraries/Components/Touchable/TouchableHighlight.js
@@ -13,6 +13,7 @@
 
 // Note (avik): add @flow when Flow supports spread properties in propTypes
 
+var ColorPropType = require('ColorPropType');
 var NativeMethodsMixin = require('NativeMethodsMixin');
 var React = require('React');
 var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
@@ -76,7 +77,7 @@ var TouchableHighlight = React.createClass({
      * The color of the underlay that will show through when the touch is
      * active.
      */
-    underlayColor: React.PropTypes.string,
+    underlayColor: ColorPropType,
     style: View.propTypes.style,
     /**
      * Called immediately after the underlay is shown
diff --git a/Libraries/Components/View/ViewStylePropTypes.js b/Libraries/Components/View/ViewStylePropTypes.js
index 95767970510d..cb193be1e9cf 100644
--- a/Libraries/Components/View/ViewStylePropTypes.js
+++ b/Libraries/Components/View/ViewStylePropTypes.js
@@ -13,6 +13,7 @@
 
 var LayoutPropTypes = require('LayoutPropTypes');
 var ReactPropTypes = require('ReactPropTypes');
+var ColorPropType = require('ColorPropType');
 var TransformPropTypes = require('TransformPropTypes');
 
 /**
@@ -22,12 +23,12 @@ var ViewStylePropTypes = {
   ...LayoutPropTypes,
   ...TransformPropTypes,
   backfaceVisibility: ReactPropTypes.oneOf(['visible', 'hidden']),
-  backgroundColor: ReactPropTypes.string,
-  borderColor: ReactPropTypes.string,
-  borderTopColor: ReactPropTypes.string,
-  borderRightColor: ReactPropTypes.string,
-  borderBottomColor: ReactPropTypes.string,
-  borderLeftColor: ReactPropTypes.string,
+  backgroundColor: ColorPropType,
+  borderColor: ColorPropType,
+  borderTopColor: ColorPropType,
+  borderRightColor: ColorPropType,
+  borderBottomColor: ColorPropType,
+  borderLeftColor: ColorPropType,
   borderRadius: ReactPropTypes.number,
   borderTopLeftRadius: ReactPropTypes.number,
   borderTopRightRadius: ReactPropTypes.number,
@@ -41,7 +42,7 @@ var ViewStylePropTypes = {
   borderLeftWidth: ReactPropTypes.number,
   opacity: ReactPropTypes.number,
   overflow: ReactPropTypes.oneOf(['visible', 'hidden']),
-  shadowColor: ReactPropTypes.string,
+  shadowColor: ColorPropType,
   shadowOffset: ReactPropTypes.shape(
     {width: ReactPropTypes.number, height: ReactPropTypes.number}
   ),
diff --git a/Libraries/Image/ImageStylePropTypes.js b/Libraries/Image/ImageStylePropTypes.js
index 6974bdc55c2a..ec806b1b85cb 100644
--- a/Libraries/Image/ImageStylePropTypes.js
+++ b/Libraries/Image/ImageStylePropTypes.js
@@ -14,6 +14,7 @@
 var ImageResizeMode = require('ImageResizeMode');
 var LayoutPropTypes = require('LayoutPropTypes');
 var ReactPropTypes = require('ReactPropTypes');
+var ColorPropType = require('ColorPropType');
 var TransformPropTypes = require('TransformPropTypes');
 
 var ImageStylePropTypes = {
@@ -21,15 +22,15 @@ var ImageStylePropTypes = {
   ...TransformPropTypes,
   resizeMode: ReactPropTypes.oneOf(Object.keys(ImageResizeMode)),
   backfaceVisibility: ReactPropTypes.oneOf(['visible', 'hidden']),
-  backgroundColor: ReactPropTypes.string,
-  borderColor: ReactPropTypes.string,
+  backgroundColor: ColorPropType,
+  borderColor: ColorPropType,
   borderWidth: ReactPropTypes.number,
   borderRadius: ReactPropTypes.number,
   overflow: ReactPropTypes.oneOf(['visible', 'hidden']),
 
   // iOS-Specific style to "tint" an image.
   // It changes the color of all the non-transparent pixels to the tintColor
-  tintColor: ReactPropTypes.string,
+  tintColor: ColorPropType,
   opacity: ReactPropTypes.number,
 };
 
diff --git a/Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js b/Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js
index 68d6de95d426..1c37d2ec9058 100644
--- a/Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js
+++ b/Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js
@@ -10,8 +10,9 @@
  */
 'use strict';
 
+var ColorPropType = require('ColorPropType');
 var React = require('React');
-var RefreshLayoutConsts = require('NativeModules').UIManager.AndroidSwipeRefreshLayout.Constants;
+var RefreshLayoutConsts = require('UIManager').AndroidSwipeRefreshLayout.Constants;
 var View = require('View');
 
 var onlyChild = require('onlyChild');
@@ -41,11 +42,11 @@ var PullToRefreshViewAndroid = React.createClass({
     /**
      * The colors (at least one) that will be used to draw the refresh indicator
      */
-    colors: React.PropTypes.arrayOf(React.PropTypes.string),
+    colors: React.PropTypes.arrayOf(ColorPropType),
     /**
      * The background color of the refresh indicator
      */
-    progressBackgroundColor: React.PropTypes.string,
+    progressBackgroundColor: ColorPropType,
     /**
      * Whether the view should be indicating an active refresh
      */
diff --git a/Libraries/StyleSheet/ColorPropType.js b/Libraries/StyleSheet/ColorPropType.js
new file mode 100644
index 000000000000..753b65c2d320
--- /dev/null
+++ b/Libraries/StyleSheet/ColorPropType.js
@@ -0,0 +1,34 @@
+ /**
+  * 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 ColorPropType
+  */
+'use strict';
+var ReactPropTypes = require('ReactPropTypes');
+var tinycolor = require('tinycolor');
+
+var colorValidator = function (props, propName) {
+  var selectedColor = props[propName];
+  if (selectedColor === null || selectedColor === undefined || selectedColor.toString().trim() === '') {
+    return new Error(
+      `Invalid argument supplied to ${propName}.Expected a string like #123ADF or 'red'.`
+    );
+  }
+
+  if (tinycolor(selectedColor.toString().trim()).isValid()) {
+    return null;
+  }
+
+  return new Error(
+    `Invalid argument supplied to ${propName}.Expected a string like #123ADF or 'red'.`
+  );
+};
+
+var ColorPropType = ReactPropTypes.oneOfType([colorValidator, ReactPropTypes.number]);
+
+module.exports = ColorPropType;
diff --git a/Libraries/Text/TextStylePropTypes.js b/Libraries/Text/TextStylePropTypes.js
index cbd6249360f9..ce1044277164 100644
--- a/Libraries/Text/TextStylePropTypes.js
+++ b/Libraries/Text/TextStylePropTypes.js
@@ -12,11 +12,12 @@
 'use strict';
 
 var ReactPropTypes = require('ReactPropTypes');
+var ColorPropType = require('ColorPropType');
 var ViewStylePropTypes = require('ViewStylePropTypes');
 
 // TODO: use spread instead of Object.assign/create after #6560135 is fixed
 var TextStylePropTypes = Object.assign(Object.create(ViewStylePropTypes), {
-  color: ReactPropTypes.string,
+  color: ColorPropType,
   fontFamily: ReactPropTypes.string,
   fontSize: ReactPropTypes.number,
   fontStyle: ReactPropTypes.oneOf(['normal', 'italic']),
@@ -55,7 +56,7 @@ var TextStylePropTypes = Object.assign(Object.create(ViewStylePropTypes), {
   /**
    * @platform ios
    */
-  textDecorationColor: ReactPropTypes.string,
+  textDecorationColor: ColorPropType,
   /**
    * @platform ios
    */
diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js
index f2313318b949..5b33bd36341f 100644
--- a/Libraries/react-native/react-native.js
+++ b/Libraries/react-native/react-native.js
@@ -89,6 +89,7 @@ var ReactNative = {
   get requireNativeComponent() { return require('requireNativeComponent'); },
 
   // Prop Types
+  get ColorPropType() { return require('ColorPropType'); },
   get EdgeInsetsPropType() { return require('EdgeInsetsPropType'); },
   get PointPropType() { return require('PointPropType'); },
 
diff --git a/Libraries/react-native/react-native.js.flow b/Libraries/react-native/react-native.js.flow
index bc7d05513a51..a250e57b0e4b 100644
--- a/Libraries/react-native/react-native.js.flow
+++ b/Libraries/react-native/react-native.js.flow
@@ -100,6 +100,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
   requireNativeComponent: require('requireNativeComponent'),
 
   // Prop Types
+  ColorPropType: require('ColorPropType'),
   EdgeInsetsPropType: require('EdgeInsetsPropType'),
   PointPropType: require('PointPropType'),
 

From d1e5fb814484c0a24112ac1141b22923e6d884c3 Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeuxx@gmail.com>
Date: Wed, 23 Dec 2015 10:29:43 -0800
Subject: [PATCH 0497/1411] Update .travis.yml

---
 .travis.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.travis.yml b/.travis.yml
index d1baaddd5672..d29d91f3bbb8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -28,6 +28,7 @@ script:
   elif [ "$TEST_TYPE" = js ]
   then
 
+    npm install github@0.2.4
     cat <(echo eslint; npm run lint --silent -- --format=json; echo flow; flow --json) | GITHUB_TOKEN="af6ef0d15709bc91d""06a6217a5a826a226fb57b7" node bots/code-analysis-bot.js
     flow check && npm test -- '\/Libraries\/'
 

From 3872e5fd9396259f1e6b4999c52ae5741c1bd218 Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Wed, 23 Dec 2015 11:38:02 -0800
Subject: [PATCH 0498/1411] Use //# instead of //@ for sourceMappingURL comment

Summary:
I had an issue debugging in chrome 48 on windows where source maps didn't work. I tried changing the sourceMappingURL comment to use the //# syntax instead and it fixed the problem.

According to https://developers.google.com/web/updates/2013/06/sourceMappingURL-and-sourceURL-syntax-changed?hl=en the //@ syntax was deprecated for //#.
Closes https://github.com/facebook/react-native/pull/4892

Reviewed By: martinbigio

Differential Revision: D2781046

Pulled By: davidaurelio

fb-gh-sync-id: 3b85f6153692a2e23509029ecf18dc51d35ba921
---
 packager/react-packager/src/Bundler/Bundle.js                | 2 +-
 packager/react-packager/src/Bundler/__tests__/Bundle-test.js | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/packager/react-packager/src/Bundler/Bundle.js b/packager/react-packager/src/Bundler/Bundle.js
index 007dca29327b..11a892f79920 100644
--- a/packager/react-packager/src/Bundler/Bundle.js
+++ b/packager/react-packager/src/Bundler/Bundle.js
@@ -14,7 +14,7 @@ const UglifyJS = require('uglify-js');
 const ModuleTransport = require('../lib/ModuleTransport');
 const Activity = require('../Activity');
 
-const SOURCEMAPPING_URL = '\n\/\/@ sourceMappingURL=';
+const SOURCEMAPPING_URL = '\n\/\/# sourceMappingURL=';
 
 const minifyCode = code =>
   UglifyJS.minify(code, {fromString: true, ascii_only: true}).code;
diff --git a/packager/react-packager/src/Bundler/__tests__/Bundle-test.js b/packager/react-packager/src/Bundler/__tests__/Bundle-test.js
index 46b57741a125..6dd3d3b7c4c3 100644
--- a/packager/react-packager/src/Bundler/__tests__/Bundle-test.js
+++ b/packager/react-packager/src/Bundler/__tests__/Bundle-test.js
@@ -43,7 +43,7 @@ describe('Bundle', function() {
       expect(bundle.getSource({dev: true})).toBe([
         'transformed foo;',
         'transformed bar;',
-        '\/\/@ sourceMappingURL=test_url'
+        '\/\/# sourceMappingURL=test_url'
       ].join('\n'));
     });
 
@@ -90,7 +90,7 @@ describe('Bundle', function() {
         'transformed bar;',
         ';require("bar");',
         ';require("foo");',
-        '\/\/@ sourceMappingURL=test_url',
+        '\/\/# sourceMappingURL=test_url',
       ].join('\n'));
     });
 

From ae2f556c71ff1e83690ca082604c30cac574f340 Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Wed, 23 Dec 2015 12:39:15 -0800
Subject: [PATCH 0499/1411] Fix scroll-to-top in MarketPlace

Reviewed By: weicool

Differential Revision: D2779979

fb-gh-sync-id: 72982a8f3142fa2cfd60fe4f68bbe1a42fc793c2
---
 Libraries/ReactIOS/YellowBox.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/ReactIOS/YellowBox.js b/Libraries/ReactIOS/YellowBox.js
index 012515cc48c1..762428ee2098 100644
--- a/Libraries/ReactIOS/YellowBox.js
+++ b/Libraries/ReactIOS/YellowBox.js
@@ -262,7 +262,7 @@ class YellowBox extends React.Component {
     ];
     return (
       <View style={inspector ? styles.fullScreen : listStyle}>
-        <ScrollView style={listStyle}>
+        <ScrollView style={listStyle} scrollsToTop={false}>
           {rows}
         </ScrollView>
         {inspector}

From 0cfe76399c3f38d8120e83e634475d00a55a718a Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Wed, 23 Dec 2015 13:31:44 -0800
Subject: [PATCH 0500/1411] Improve red boxes coming from RCTWebSocketExecutor

Reviewed By: tadeuzagallo

Differential Revision: D2775452

fb-gh-sync-id: b709e0e725ab76468700466b804237eed9158bfd
---
 Libraries/WebSocket/RCTWebSocketExecutor.m | 14 +++++++++-----
 React/Base/RCTBatchedBridge.m              |  2 +-
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/Libraries/WebSocket/RCTWebSocketExecutor.m b/Libraries/WebSocket/RCTWebSocketExecutor.m
index c5813bc5c250..e84539a73004 100644
--- a/Libraries/WebSocket/RCTWebSocketExecutor.m
+++ b/Libraries/WebSocket/RCTWebSocketExecutor.m
@@ -66,9 +66,9 @@ - (void)setUp
   [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:startDevToolsURL] delegate:nil];
 
   if (![self connectToProxy]) {
-    RCTLogError(@"Connection to %@ timed out. Are you running node proxy? If \
-                you are running on the device, check if you have the right IP \
-                address in `RCTWebSocketExecutor.m`.", _url);
+    RCTLogError(@"Connection to %@ timed out. Are you running node proxy? If "
+                 "you are running on the device, check if you have the right IP "
+                 "address in `RCTWebSocketExecutor.m`.", _url);
     [self invalidate];
     return;
   }
@@ -81,7 +81,7 @@ - (void)setUp
   }
   if (!runtimeIsReady) {
     RCTLogError(@"Runtime is not ready. Make sure Chrome is running and not "
-                "paused on a breakpoint or exception and try reloading again.");
+                 "paused on a breakpoint or exception and try reloading again.");
     [self invalidate];
     return;
   }
@@ -125,7 +125,11 @@ - (void)webSocketDidOpen:(RCTSRWebSocket *)webSocket
 
 - (void)webSocket:(RCTSRWebSocket *)webSocket didFailWithError:(NSError *)error
 {
-  RCTLogError(@"WebSocket connection failed with error %@", error);
+  dispatch_semaphore_signal(_socketOpenSemaphore);
+  dispatch_async(dispatch_get_main_queue(), ^{
+    // Give the setUp method an opportunity to report an error first
+    RCTLogError(@"WebSocket connection failed with error %@", error);
+  });
 }
 
 - (void)sendMessage:(NSDictionary<NSString *, id> *)message waitForReply:(RCTWSMessageCallback)callback
diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index ce9bfb763fea..8e00e93f7367 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -585,7 +585,7 @@ - (void)invalidate
 
 - (void)logMessage:(NSString *)message level:(NSString *)level
 {
-  if (RCT_DEBUG) {
+  if (RCT_DEBUG && [_javaScriptExecutor isValid]) {
     [self enqueueJSCall:@"RCTLog.logIfNoNativeHook"
                    args:@[level, message]];
   }

From 4fde511f5c4a8bb7d11a1ccfe6a6b06ff36fa208 Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Wed, 23 Dec 2015 14:41:39 -0800
Subject: [PATCH 0501/1411] Remove warnings in RCTBridgeTests

Reviewed By: majak

Differential Revision: D2771228

fb-gh-sync-id: dd935094ceeff196c272565bf7efea5112059a1a
---
 .../UIExplorerUnitTests/RCTBridgeTests.m      | 19 +++++++++++--------
 React/Base/RCTBatchedBridge.m                 |  5 +----
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m
index 1a0afe0bfa49..fe2f48c5c70d 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m
@@ -51,16 +51,16 @@ - (void)flushedQueue:(RCTJavaScriptCallback)onComplete
   onComplete(nil, nil);
 }
 
-- (void)callFunctionOnModule:(NSString *)module
-                      method:(NSString *)method
-                   arguments:(NSArray *)args
+- (void)callFunctionOnModule:(__unused NSString *)module
+                      method:(__unused NSString *)method
+                   arguments:(__unused NSArray *)args
                     callback:(RCTJavaScriptCallback)onComplete
 {
   onComplete(nil, nil);
 }
 
-- (void)invokeCallbackID:(NSNumber *)cbID
-               arguments:(NSArray *)args
+- (void)invokeCallbackID:(__unused NSNumber *)cbID
+               arguments:(__unused NSArray *)args
                 callback:(RCTJavaScriptCallback)onComplete
 {
   onComplete(nil, nil);
@@ -121,7 +121,9 @@ - (void)setUp
 - (void)tearDown
 {
   [super tearDown];
+
   [_bridge invalidate];
+  _testMethodCalled = NO;
 }
 
 #define RUN_RUNLOOP_WHILE(CONDITION) \
@@ -169,21 +171,22 @@ - (void)testCallNativeMethod
   RUN_RUNLOOP_WHILE(!(injectedStuff = executor.injectedStuff[@"__fbBatchedBridgeConfig"]));
 
   __block NSNumber *testModuleID = nil;
-  __block NSDictionary<NSString *, id> *testConstants = nil;
   __block NSNumber *testMethodID = nil;
 
   NSArray *remoteModuleConfig = RCTJSONParse(injectedStuff, NULL)[@"remoteModuleConfig"];
   [remoteModuleConfig enumerateObjectsUsingBlock:^(id moduleConfig, NSUInteger i, __unused BOOL *stop) {
     if ([moduleConfig isKindOfClass:[NSArray class]] && [moduleConfig[0] isEqualToString:@"TestModule"]) {
       testModuleID = @(i);
-      testConstants = moduleConfig[1];
       testMethodID = @([moduleConfig[2] indexOfObject:@"testMethod"]);
       *stop = YES;
     }
   }];
 
+  XCTAssertNotNil(testModuleID);
+  XCTAssertNotNil(testMethodID);
+
   NSArray *args = @[@1234, @5678, @"stringy", @{@"a": @1}, @42];
-  NSArray *buffer = @[@[testModuleID], @[testMethodID], @[args], @[], @1234567];
+  NSArray *buffer = @[@[testModuleID], @[testMethodID], @[args]];
 
   [_bridge.batchedBridge handleBuffer:buffer];
 
diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index 8e00e93f7367..4946cd01258d 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -818,10 +818,7 @@ - (void)handleBuffer:(NSArray<NSArray *> *)buffer
     dispatch_block_t block = ^{
       RCTProfileEndFlowEvent();
 
-#if RCT_DEV
-      NSString *_threadName = RCTCurrentThreadName();
-      RCT_PROFILE_BEGIN_EVENT(0, _threadName, nil);
-#endif
+      RCT_PROFILE_BEGIN_EVENT(0, RCTCurrentThreadName(), nil);
 
       NSOrderedSet *calls = [buckets objectForKey:queue];
       @autoreleasepool {

From 176d45633a1a8024b4c2cada5ad7eeed0151f1b6 Mon Sep 17 00:00:00 2001
From: toomass <tcoyle@fantasymoguls.com>
Date: Wed, 23 Dec 2015 15:35:14 -0800
Subject: [PATCH 0502/1411] Added CBS Sports Franchise Football to Showcase

Adding CBS Sports Franchise Football to the React Native showcase,
---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 985eb1dae0d5..9c13a1ee57d6 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -148,6 +148,12 @@ var apps = [
     linkPlayStore: 'https://play.google.com/store/apps/details?id=com.canddi',
     author: 'CANDDi LTD.',
   },
+  {
+    name: 'CBS Sports Franchise Football',
+    icon: 'http://a2.mzstatic.com/us/r30/Purple69/v4/7b/0c/a0/7b0ca007-885a-7cfc-9fa2-2ec4394c2ecc/icon175x175.png',
+    link: 'https://play.google.com/store/apps/details?id=com.cbssports.fantasy.franchisefootball2015',
+    author: 'CBS Sports',
+  },  
   {
     name: 'Company name search',
     icon: 'http://a4.mzstatic.com/us/r30/Purple69/v4/fd/47/53/fd47537c-5861-e208-d1d1-1e26b5e45a36/icon350x350.jpeg',

From 09702478f1214e729be329f4d9f329a5a42fb67c Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Thu, 24 Dec 2015 01:08:13 +0100
Subject: [PATCH 0503/1411] Update NewIssueGreeting.md

---
 bots/NewIssueGreeting.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bots/NewIssueGreeting.md b/bots/NewIssueGreeting.md
index f564e47296dd..8d22aec68d61 100644
--- a/bots/NewIssueGreeting.md
+++ b/bots/NewIssueGreeting.md
@@ -6,4 +6,4 @@ React Native, as you've probably heard, is getting really popular and truth is w
 
 - If this is a **feature request or a bug** that you would like to be fixed, please report it on [Product Pains](https://productpains.com/product/react-native/). It has a ranking feature that lets us focus on the most important issues the community is experiencing.
 
-- We welcome clear issues and PRs that are ready for in-depth discussion. Please provide **screenshots** where appropriate and always mention the **version** of React Native you're using, as well as the **platform** you're on e.g.- Android, iOS. Thank you for your contributions!
+- We welcome clear issues and PRs that are ready for in-depth discussion. Please provide **screenshots** where appropriate and always mention the **version** of React Native you're using. Thank you for your contributions!

From f7de9678d46a5b69b4d687b6ecf3c6095b6ac212 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Thu, 24 Dec 2015 01:10:21 +0100
Subject: [PATCH 0504/1411] Update NewIssueGreeting.md

---
 bots/NewIssueGreeting.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bots/NewIssueGreeting.md b/bots/NewIssueGreeting.md
index 8d22aec68d61..c8c6aa23b2d4 100644
--- a/bots/NewIssueGreeting.md
+++ b/bots/NewIssueGreeting.md
@@ -2,7 +2,7 @@ Hey {author}, thanks for reporting this issue!
 
 React Native, as you've probably heard, is getting really popular and truth is we're getting a bit overwhelmed by the activity surrounding it. There are just too many issues for us to manage properly.
 
-- If you **don't know how to do something** or not sure whether some behavior is expected or a bug, please ask on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native) with the tag `react-native` or for more real time interactions, ask on [Discord](https://discord.gg/0ZcbPKXt5bZjGY5n) in the #react-native channel.
+- If you **don't know how to do something** or **something is not working as you expect but not sure it's a bug**, please ask on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native) with the tag `react-native` or for more real time interactions, ask on [Discord](https://discord.gg/0ZcbPKXt5bZjGY5n) in the #react-native channel.
 
 - If this is a **feature request or a bug** that you would like to be fixed, please report it on [Product Pains](https://productpains.com/product/react-native/). It has a ranking feature that lets us focus on the most important issues the community is experiencing.
 

From 893a54d0cde592e1cd77203efd597e3d961417ba Mon Sep 17 00:00:00 2001
From: Spencer Ahrens <sahrens@fb.com>
Date: Wed, 23 Dec 2015 16:10:39 -0800
Subject: [PATCH 0505/1411] Add yieldy, chained async task support to
 InteractionManager

Summary:
Default behavior should be unchanged.

If we queue up a bunch of expensive tasks during an interaction, the default
`InteractionManager` behavior would execute them all in one synchronous loop at
the end the JS event loop via one `setImmediate` call, blocking the JS thread
the entire time.

The `setDeadline` addition in this diff enables an option to only execute tasks
until the `eventLoopRunningTime` is hit (added to MessageQueue/BatchedBridge),
allowing the queue execution to be paused if an interaction starts in between
tasks, making the app more responsive.

Additionally, if a task ends up generating a bunch of additional tasks
asynchronously, the previous implementation would execute these new tasks after
already scheduled tasks. This is often fine, but I want it to fully resolve
async tasks and all their dependencies before making progress in the rest of the
queue, so I added support for `type PromiseTask = {gen: () => Promise}` to do
just this. It works by building a stack of queues each time a `PromiseTask` is
started, and pops them off the stack once they are resolved and the queues are
processed.

I also pulled all of the actual queue logic out of `InteractionManager` and into
a new `TaskQueue` class to isolate concerns a bit.

public

Reviewed By: josephsavona

Differential Revision: D2754311

fb-gh-sync-id: bfd6d0c54e6410cb261aa1d2c5024dd91a3959e6
---
 Libraries/Interaction/InteractionManager.js   |  95 ++++--
 Libraries/Interaction/TaskQueue.js            | 148 +++++++++
 .../__tests__/InteractionManager-test.js      | 288 ++++++++++++++++++
 .../__tests__/InteractionMixin-test.js        |  44 +++
 .../Interaction/__tests__/TaskQueue-test.js   | 121 ++++++++
 Libraries/Utilities/MessageQueue.js           |   7 +
 6 files changed, 673 insertions(+), 30 deletions(-)
 create mode 100644 Libraries/Interaction/TaskQueue.js
 create mode 100644 Libraries/Interaction/__tests__/InteractionManager-test.js
 create mode 100644 Libraries/Interaction/__tests__/InteractionMixin-test.js
 create mode 100644 Libraries/Interaction/__tests__/TaskQueue-test.js

diff --git a/Libraries/Interaction/InteractionManager.js b/Libraries/Interaction/InteractionManager.js
index fd4ab67c39b3..8fac8edb8a64 100644
--- a/Libraries/Interaction/InteractionManager.js
+++ b/Libraries/Interaction/InteractionManager.js
@@ -11,23 +11,19 @@
  */
 'use strict';
 
-var ErrorUtils = require('ErrorUtils');
-var EventEmitter = require('EventEmitter');
-var Set = require('Set');
+const BatchedBridge = require('BatchedBridge');
+const EventEmitter = require('EventEmitter');
+const Set = require('Set');
+const TaskQueue = require('TaskQueue');
 
-var invariant = require('invariant');
-var keyMirror = require('keyMirror');
-var setImmediate = require('setImmediate');
+const invariant = require('invariant');
+const keyMirror = require('keyMirror');
+const setImmediate = require('setImmediate');
 
 type Handle = number;
+import type {Task} from 'TaskQueue';
 
-var _emitter = new EventEmitter();
-var _interactionSet = new Set();
-var _addInteractionSet = new Set();
-var _deleteInteractionSet = new Set();
-var _nextUpdateHandle = null;
-var _queue = [];
-var _inc = 0;
+const _emitter = new EventEmitter();
 
 /**
  * InteractionManager allows long-running work to be scheduled after any
@@ -63,6 +59,20 @@ var _inc = 0;
  * InteractionManager.clearInteractionHandle(handle);
  * // queued tasks run if all handles were cleared
  * ```
+ *
+ * `runAfterInteractions` takes either a plain callback function, or a
+ * `PromiseTask` object with a `gen` method that returns a `Promise`.  If a
+ * `PromiseTask` is supplied, then it is fully resolved (including asynchronous
+ * dependencies that also schedule more tasks via `runAfterInteractions`) before
+ * starting on the next task that might have been queued up synchronously
+ * earlier.
+ *
+ * By default, queued tasks are executed together in a loop in one
+ * `setImmediate` batch. If `setDeadline` is called with a positive number, then
+ * tasks will only be executed until the deadline (in terms of js event loop run
+ * time) approaches, at which point execution will yield via setTimeout,
+ * allowing events such as touches to start interactions and block queued tasks
+ * from executing, making apps more responsive.
  */
 var InteractionManager = {
   Events: keyMirror({
@@ -73,13 +83,14 @@ var InteractionManager = {
   /**
    * Schedule a function to run after all interactions have completed.
    */
-  runAfterInteractions(callback: ?Function): Promise {
+  runAfterInteractions(task: ?Task): Promise {
     return new Promise(resolve => {
-      scheduleUpdate();
-      if (callback) {
-        _queue.push(callback);
+      _scheduleUpdate();
+      if (task) {
+        _taskQueue.enqueue(task);
       }
-      _queue.push(resolve);
+      const name = task && task.name || '?';
+      _taskQueue.enqueue({run: resolve, name: 'resolve ' + name});
     });
   },
 
@@ -87,7 +98,7 @@ var InteractionManager = {
    * Notify manager that an interaction has started.
    */
   createInteractionHandle(): Handle {
-    scheduleUpdate();
+    _scheduleUpdate();
     var handle = ++_inc;
     _addInteractionSet.add(handle);
     return handle;
@@ -101,28 +112,49 @@ var InteractionManager = {
       !!handle,
       'Must provide a handle to clear.'
     );
-    scheduleUpdate();
+    _scheduleUpdate();
     _addInteractionSet.delete(handle);
     _deleteInteractionSet.add(handle);
   },
 
   addListener: _emitter.addListener.bind(_emitter),
+
+  /**
+   * A positive number will use setTimeout to schedule any tasks after the
+   * eventLoopRunningTime hits the deadline value, otherwise all tasks will be
+   * executed in one setImmediate batch (default).
+   */
+  setDeadline(deadline: number) {
+    _deadline = deadline;
+  },
 };
 
+const _interactionSet = new Set();
+const _addInteractionSet = new Set();
+const _deleteInteractionSet = new Set();
+const _taskQueue = new TaskQueue({onMoreTasks: _scheduleUpdate});
+let _nextUpdateHandle = 0;
+let _inc = 0;
+let _deadline = -1;
+
 /**
  * Schedule an asynchronous update to the interaction state.
  */
-function scheduleUpdate() {
+function _scheduleUpdate() {
   if (!_nextUpdateHandle) {
-    _nextUpdateHandle = setImmediate(processUpdate);
+    if (_deadline > 0) {
+      _nextUpdateHandle = setTimeout(_processUpdate, 0);
+    } else {
+      _nextUpdateHandle = setImmediate(_processUpdate);
+    }
   }
 }
 
 /**
  * Notify listeners, process queue, etc
  */
-function processUpdate() {
-  _nextUpdateHandle = null;
+function _processUpdate() {
+  _nextUpdateHandle = 0;
 
   var interactionCount = _interactionSet.size;
   _addInteractionSet.forEach(handle =>
@@ -143,13 +175,16 @@ function processUpdate() {
 
   // process the queue regardless of a transition
   if (nextInteractionCount === 0) {
-    var queue = _queue;
-    _queue = [];
-    queue.forEach(callback => {
-      ErrorUtils.applyWithGuard(callback);
-    });
+    while (_taskQueue.hasTasksToProcess()) {
+      _taskQueue.processNext();
+      if (_deadline > 0 &&
+          BatchedBridge.getEventLoopRunningTime() >= _deadline) {
+        // Hit deadline before processing all tasks, so process more later.
+        _scheduleUpdate();
+        break;
+      }
+    }
   }
-
   _addInteractionSet.clear();
   _deleteInteractionSet.clear();
 }
diff --git a/Libraries/Interaction/TaskQueue.js b/Libraries/Interaction/TaskQueue.js
new file mode 100644
index 000000000000..8ef7a37047b2
--- /dev/null
+++ b/Libraries/Interaction/TaskQueue.js
@@ -0,0 +1,148 @@
+/**
+ * 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 TaskQueue
+ * @flow
+ */
+'use strict';
+
+const ErrorUtils = require('ErrorUtils');
+
+const invariant = require('invariant');
+
+type SimpleTask = {
+  name: string;
+  run: () => void;
+};
+type PromiseTask = {
+  name: string;
+  gen: () => Promise;
+};
+export type Task = Function | SimpleTask | PromiseTask;
+
+/**
+ * TaskQueue - A system for queueing and executing a mix of simple callbacks and
+ * trees of dependent tasks based on Promises. No tasks are executed unless
+ * `processNext` is called.
+ *
+ * `enqueue` takes a Task object with either a simple `run` callback, or a
+ * `gen` function that returns a `Promise` and puts it in the queue.  If a gen
+ * function is supplied, then the promise it returns will block execution of
+ * tasks already in the queue until it resolves. This can be used to make sure
+ * the first task is fully resolved (including asynchronous dependencies that
+ * also schedule more tasks via `enqueue`) before starting on the next task that
+ * might have been queued up earlier. The `onMoreTasks` constructor argument is
+ * used to inform the owner that an async task has resolved and that the queue
+ * should be processed again.
+ *
+ * Note: Tasks are only actually executed with explicit calls to `processNext`.
+ */
+class TaskQueue {
+  /**
+   * TaskQueue instances are self contained and independent, so multiple tasks
+   * of varying semantics and priority can operate together.
+   *
+   * `onMoreTasks` is invoked when `PromiseTask`s resolve if there are more
+   * tasks to process.
+   */
+  constructor({onMoreTasks}: {onMoreTasks: () => void}) {
+    this._onMoreTasks = onMoreTasks;
+    this._queueStack = [{tasks: [], popable: false}];
+  }
+
+  /**
+   * Add a task to the queue.  It is recommended to name your tasks for easier
+   * async debugging. Tasks will not be executed until `processNext` is called
+   * explicitly.
+   */
+  enqueue(task: Task): void {
+    this._getCurrentQueue().push(task);
+  }
+
+  /**
+   * Check to see if `processNext` should be called.
+   *
+   * @returns {boolean} Returns true if there are tasks that are ready to be
+   * processed with `processNext`, or returns false if there are no more tasks
+   * to be processed right now, although there may be tasks in the queue that
+   * are blocked by earlier `PromiseTask`s that haven't resolved yet.
+   * `onMoreTasks` will be called after each `PromiseTask` resolves if there are
+   * tasks ready to run at that point.
+   */
+  hasTasksToProcess(): bool {
+    return this._getCurrentQueue().length > 0;
+  }
+
+  /**
+   * Executes the next task in the queue.
+   */
+  processNext(): void {
+    let queue = this._getCurrentQueue();
+    if (queue.length) {
+      const task = queue.shift();
+      try {
+        if (task.gen) {
+          this._genPromise((task: any)); // Rather than annoying tagged union
+        } else if (task.run) {
+          task.run();
+        } else {
+          invariant(
+            typeof task === 'function',
+            'Expected Function, SimpleTask, or PromiseTask, but got: ' +
+              JSON.stringify(task)
+          );
+          task();
+        }
+      } catch (e) {
+        e.message = 'TaskQueue: Error with task' + (task.name || ' ') + ': ' +
+          e.message;
+        ErrorUtils.reportError(e);
+      }
+    }
+  }
+
+  _queueStack: Array<{tasks: Array<Task>, popable: bool}>;
+  _onMoreTasks: () => void;
+
+  _getCurrentQueue(): Array<Task> {
+    const stackIdx = this._queueStack.length - 1;
+    const queue = this._queueStack[stackIdx];
+    if (queue.popable &&
+        queue.tasks.length === 0 &&
+        this._queueStack.length > 1) {
+      this._queueStack.pop();
+      return this._getCurrentQueue();
+    } else {
+      return queue.tasks;
+    }
+  }
+
+  _genPromise(task: PromiseTask) {
+    // Each async task pushes it's own queue onto the queue stack. This
+    // effectively defers execution of previously queued tasks until the promise
+    // resolves, at which point we allow the new queue to be popped, which
+    // happens once it is fully processed.
+    this._queueStack.push({tasks: [], popable: false});
+    const stackIdx = this._queueStack.length - 1;
+    ErrorUtils.applyWithGuard(task.gen)
+      .then(() => {
+        this._queueStack[stackIdx].popable = true;
+        this.hasTasksToProcess() && this._onMoreTasks();
+      })
+      .catch((ex) => {
+        console.warn(
+          'TaskQueue: Error resolving Promise in task ' + task.name,
+          ex
+        );
+        throw ex;
+      });
+  }
+}
+
+
+module.exports = TaskQueue;
diff --git a/Libraries/Interaction/__tests__/InteractionManager-test.js b/Libraries/Interaction/__tests__/InteractionManager-test.js
new file mode 100644
index 000000000000..f02701d7f632
--- /dev/null
+++ b/Libraries/Interaction/__tests__/InteractionManager-test.js
@@ -0,0 +1,288 @@
+/**
+ * Copyright 2004-present Facebook. All Rights Reserved.
+ */
+
+'use strict';
+
+jest
+  .dontMock('InteractionManager')
+  .dontMock('TaskQueue')
+  .dontMock('invariant');
+
+function expectToBeCalledOnce(fn) {
+  expect(fn.mock.calls.length).toBe(1);
+}
+
+describe('InteractionManager', () => {
+  let InteractionManager;
+  let interactionStart;
+  let interactionComplete;
+
+  beforeEach(() => {
+    jest.resetModuleRegistry();
+    InteractionManager = require('InteractionManager');
+
+    interactionStart = jest.genMockFunction();
+    interactionComplete = jest.genMockFunction();
+
+    InteractionManager.addListener(
+      InteractionManager.Events.interactionStart,
+      interactionStart
+    );
+    InteractionManager.addListener(
+      InteractionManager.Events.interactionComplete,
+      interactionComplete
+    );
+  });
+
+  it('throws when clearing an undefined handle', () => {
+    expect(() => InteractionManager.clearInteractionHandle()).toThrow();
+  });
+
+  it('notifies asynchronously when interaction starts', () => {
+    InteractionManager.createInteractionHandle();
+    expect(interactionStart).not.toBeCalled();
+
+    jest.runAllTimers();
+    expect(interactionStart).toBeCalled();
+    expect(interactionComplete).not.toBeCalled();
+  });
+
+  it('notifies asynchronously when interaction stops', () => {
+    var handle = InteractionManager.createInteractionHandle();
+    jest.runAllTimers();
+    interactionStart.mockClear();
+    InteractionManager.clearInteractionHandle(handle);
+    expect(interactionComplete).not.toBeCalled();
+
+    jest.runAllTimers();
+    expect(interactionStart).not.toBeCalled();
+    expect(interactionComplete).toBeCalled();
+  });
+
+  it('does not notify when started & stopped in same event loop', () => {
+    var handle = InteractionManager.createInteractionHandle();
+    InteractionManager.clearInteractionHandle(handle);
+
+    jest.runAllTimers();
+    expect(interactionStart).not.toBeCalled();
+    expect(interactionComplete).not.toBeCalled();
+  });
+
+  it('does not notify when going from two -> one active interactions', () => {
+    InteractionManager.createInteractionHandle();
+    var handle = InteractionManager.createInteractionHandle();
+    jest.runAllTimers();
+
+    interactionStart.mockClear();
+    interactionComplete.mockClear();
+
+    InteractionManager.clearInteractionHandle(handle);
+    jest.runAllTimers();
+    expect(interactionStart).not.toBeCalled();
+    expect(interactionComplete).not.toBeCalled();
+  });
+
+  it('runs tasks asynchronously when there are interactions', () => {
+    var task = jest.genMockFunction();
+    InteractionManager.runAfterInteractions(task);
+    expect(task).not.toBeCalled();
+
+    jest.runAllTimers();
+    expect(task).toBeCalled();
+  });
+
+  it('runs tasks when interactions complete', () => {
+    var task = jest.genMockFunction();
+    var handle = InteractionManager.createInteractionHandle();
+    InteractionManager.runAfterInteractions(task);
+
+    jest.runAllTimers();
+    InteractionManager.clearInteractionHandle(handle);
+    expect(task).not.toBeCalled();
+
+    jest.runAllTimers();
+    expect(task).toBeCalled();
+  });
+
+  it('does not run tasks twice', () => {
+    var task1 = jest.genMockFunction();
+    var task2 = jest.genMockFunction();
+    InteractionManager.runAfterInteractions(task1);
+    jest.runAllTimers();
+
+    InteractionManager.runAfterInteractions(task2);
+    jest.runAllTimers();
+
+    expectToBeCalledOnce(task1);
+  });
+
+  it('runs tasks added while processing previous tasks', () => {
+    var task1 = jest.genMockFunction().mockImplementation(() => {
+      InteractionManager.runAfterInteractions(task2);
+    });
+    var task2 = jest.genMockFunction();
+
+    InteractionManager.runAfterInteractions(task1);
+    expect(task2).not.toBeCalled();
+
+    jest.runAllTimers();
+
+    expect(task1).toBeCalled();
+    expect(task2).toBeCalled();
+  });
+});
+
+describe('promise tasks', () => {
+  let InteractionManager;
+  let BatchedBridge;
+  let sequenceId;
+  function createSequenceTask(expectedSequenceId) {
+    return jest.genMockFunction().mockImplementation(() => {
+      expect(++sequenceId).toBe(expectedSequenceId);
+    });
+  }
+  beforeEach(() => {
+    jest.resetModuleRegistry();
+    InteractionManager = require('InteractionManager');
+    BatchedBridge = require('BatchedBridge');
+    sequenceId = 0;
+  });
+
+
+  it('should run a basic promise task', () => {
+    const task1 = jest.genMockFunction().mockImplementation(() => {
+      expect(++sequenceId).toBe(1);
+      return new Promise(resolve => resolve());
+    });
+    InteractionManager.runAfterInteractions({gen: task1, name: 'gen1'});
+    jest.runAllTimers();
+    expectToBeCalledOnce(task1);
+  });
+
+  it('should handle nested promises', () => {
+    const task1 = jest.genMockFunction().mockImplementation(() => {
+      expect(++sequenceId).toBe(1);
+      return new Promise(resolve => {
+        InteractionManager.runAfterInteractions({gen: task2, name: 'gen2'})
+          .then(resolve);
+      });
+    });
+    const task2 = jest.genMockFunction().mockImplementation(() => {
+      expect(++sequenceId).toBe(2);
+      return new Promise(resolve => resolve());
+    });
+    InteractionManager.runAfterInteractions({gen: task1, name: 'gen1'});
+    jest.runAllTimers();
+    expectToBeCalledOnce(task1);
+    expectToBeCalledOnce(task2);
+  });
+
+  it('should pause promise tasks during interactions then resume', () => {
+    const task1 = createSequenceTask(1);
+    const task2 = jest.genMockFunction().mockImplementation(() => {
+      expect(++sequenceId).toBe(2);
+      return new Promise(resolve => {
+        setTimeout(() => {
+          InteractionManager.runAfterInteractions(task3).then(resolve);
+        }, 1);
+      });
+    });
+    const task3 = createSequenceTask(3);
+    InteractionManager.runAfterInteractions(task1);
+    InteractionManager.runAfterInteractions({gen: task2, name: 'gen2'});
+    jest.runOnlyPendingTimers();
+    expectToBeCalledOnce(task1);
+    expectToBeCalledOnce(task2);
+    const handle = InteractionManager.createInteractionHandle();
+    jest.runAllTimers();
+    jest.runAllTimers(); // Just to be sure...
+    expect(task3).not.toBeCalled();
+    InteractionManager.clearInteractionHandle(handle);
+    jest.runAllTimers();
+    expectToBeCalledOnce(task3);
+  });
+
+  it('should execute tasks in loop within deadline', () => {
+    InteractionManager.setDeadline(100);
+    BatchedBridge.getEventLoopRunningTime.mockReturnValue(10);
+    const task1 = createSequenceTask(1);
+    const task2 = createSequenceTask(2);
+    InteractionManager.runAfterInteractions(task1);
+    InteractionManager.runAfterInteractions(task2);
+
+    jest.runOnlyPendingTimers();
+
+    expectToBeCalledOnce(task1);
+    expectToBeCalledOnce(task2);
+  });
+
+  it('should execute tasks one at a time if deadline exceeded', () => {
+    InteractionManager.setDeadline(100);
+    BatchedBridge.getEventLoopRunningTime.mockReturnValue(200);
+    const task1 = createSequenceTask(1);
+    const task2 = createSequenceTask(2);
+    InteractionManager.runAfterInteractions(task1);
+    InteractionManager.runAfterInteractions(task2);
+
+    jest.runOnlyPendingTimers();
+
+    expectToBeCalledOnce(task1);
+    expect(task2).not.toBeCalled();
+
+    jest.runOnlyPendingTimers(); // resolve1
+    jest.runOnlyPendingTimers(); // task2
+
+    expectToBeCalledOnce(task2);
+  });
+
+  const bigAsyncTest = () => {
+    const task1 = createSequenceTask(1);
+    const task2 = jest.genMockFunction().mockImplementation(() => {
+      expect(++sequenceId).toBe(2);
+      return new Promise(resolve => {
+        InteractionManager.runAfterInteractions(task3);
+        setTimeout(() => {
+          InteractionManager.runAfterInteractions({gen: task4, name: 'gen4'})
+            .then(resolve);
+        }, 1);
+      });
+    });
+    const task3 = createSequenceTask(3);
+    const task4 = jest.genMockFunction().mockImplementation(() => {
+      expect(++sequenceId).toBe(4);
+      return new Promise(resolve => {
+        InteractionManager.runAfterInteractions(task5).then(resolve);
+      });
+    });
+    const task5 = createSequenceTask(5);
+    const task6 = createSequenceTask(6);
+
+    InteractionManager.runAfterInteractions(task1);
+    InteractionManager.runAfterInteractions({gen: task2, name: 'gen2'});
+    InteractionManager.runAfterInteractions(task6);
+
+    jest.runAllTimers();
+    // runAllTimers doesn't actually run all timers with nested timer functions
+    // inside Promises, so we have to call it extra times.
+    jest.runAllTimers();
+    jest.runAllTimers();
+
+    expectToBeCalledOnce(task1);
+    expectToBeCalledOnce(task2);
+    expectToBeCalledOnce(task3);
+    expectToBeCalledOnce(task4);
+    expectToBeCalledOnce(task5);
+    expectToBeCalledOnce(task6);
+  };
+
+  it('resolves async tasks recusively before other queued tasks', () => {
+    bigAsyncTest();
+  });
+
+  it('should also work with a deadline', () => {
+    InteractionManager.setDeadline(100);
+    BatchedBridge.getEventLoopRunningTime.mockReturnValue(200);
+    bigAsyncTest();
+  });
+});
diff --git a/Libraries/Interaction/__tests__/InteractionMixin-test.js b/Libraries/Interaction/__tests__/InteractionMixin-test.js
new file mode 100644
index 000000000000..c1cc7f54da4d
--- /dev/null
+++ b/Libraries/Interaction/__tests__/InteractionMixin-test.js
@@ -0,0 +1,44 @@
+/**
+ * Copyright 2004-present Facebook. All Rights Reserved.
+ */
+'use strict';
+
+jest.dontMock('InteractionMixin');
+
+describe('InteractionMixin', () => {
+  var InteractionManager;
+  var InteractionMixin;
+  var component;
+
+  beforeEach(() => {
+    jest.resetModuleRegistry();
+    InteractionManager = require('InteractionManager');
+    InteractionMixin = require('InteractionMixin');
+
+    component = Object.create(InteractionMixin);
+  });
+
+  it('should start interactions', () => {
+    var timeout = 123;
+    component.createInteractionHandle(timeout);
+    expect(InteractionManager.createInteractionHandle).toBeCalled(timeout);
+  });
+
+  it('should end interactions', () => {
+    var handle = {};
+    component.clearInteractionHandle(handle);
+    expect(InteractionManager.clearInteractionHandle).toBeCalledWith(handle);
+  });
+
+  it('should schedule tasks', () => {
+    var task = jest.genMockFunction();
+    component.runAfterInteractions(task);
+    expect(InteractionManager.runAfterInteractions).toBeCalledWith(task);
+  });
+
+  it('should end unfinished interactions in componentWillUnmount', () => {
+    var handle = component.createInteractionHandle();
+    component.componentWillUnmount();
+    expect(InteractionManager.clearInteractionHandle).toBeCalledWith(handle);
+  });
+});
diff --git a/Libraries/Interaction/__tests__/TaskQueue-test.js b/Libraries/Interaction/__tests__/TaskQueue-test.js
new file mode 100644
index 000000000000..9b36783db552
--- /dev/null
+++ b/Libraries/Interaction/__tests__/TaskQueue-test.js
@@ -0,0 +1,121 @@
+/**
+ * Copyright 2004-present Facebook. All Rights Reserved.
+ */
+
+'use strict';
+
+jest.dontMock('TaskQueue');
+
+function expectToBeCalledOnce(fn) {
+  expect(fn.mock.calls.length).toBe(1);
+}
+
+function clearTaskQueue(taskQueue) {
+  do {
+    jest.runAllTimers();
+    taskQueue.processNext();
+    jest.runAllTimers();
+  } while (taskQueue.hasTasksToProcess())
+}
+
+describe('TaskQueue', () => {
+  let taskQueue;
+  let onMoreTasks;
+  let sequenceId;
+  function createSequenceTask(expectedSequenceId) {
+    return jest.genMockFunction().mockImplementation(() => {
+      expect(++sequenceId).toBe(expectedSequenceId);
+    });
+  }
+  beforeEach(() => {
+    jest.resetModuleRegistry();
+    onMoreTasks = jest.genMockFunction();
+    const TaskQueue = require('TaskQueue');
+    taskQueue = new TaskQueue({onMoreTasks});
+    sequenceId = 0;
+  });
+
+
+  it('should run a basic task', () => {
+    const task1 = createSequenceTask(1);
+    taskQueue.enqueue({run: task1, name: 'run1'});
+    expect(taskQueue.hasTasksToProcess()).toBe(true);
+    taskQueue.processNext();
+    expectToBeCalledOnce(task1);
+  });
+
+  it('should handle blocking promise task', () => {
+    const task1 = jest.genMockFunction().mockImplementation(() => {
+      return new Promise(resolve => {
+        setTimeout(() => {
+          expect(++sequenceId).toBe(1);
+          resolve();
+        }, 1);
+      });
+    });
+    const task2 = createSequenceTask(2);
+    taskQueue.enqueue({gen: task1, name: 'gen1'});
+    taskQueue.enqueue({run: task2, name: 'run2'});
+
+    taskQueue.processNext();
+
+    expectToBeCalledOnce(task1);
+    expect(task2).not.toBeCalled();
+    expect(onMoreTasks).not.toBeCalled();
+    expect(taskQueue.hasTasksToProcess()).toBe(false);
+
+    clearTaskQueue(taskQueue);
+
+    expectToBeCalledOnce(onMoreTasks);
+    expectToBeCalledOnce(task2);
+  });
+
+  it('should handle nested simple tasks', () => {
+    const task1 = jest.genMockFunction().mockImplementation(() => {
+      expect(++sequenceId).toBe(1);
+      taskQueue.enqueue({run: task3, name: 'run3'});
+    });
+    const task2 = createSequenceTask(2);
+    const task3 = createSequenceTask(3);
+    taskQueue.enqueue({run: task1, name: 'run1'});
+    taskQueue.enqueue({run: task2, name: 'run2'}); // not blocked by task 1
+
+    clearTaskQueue(taskQueue);
+
+    expectToBeCalledOnce(task1);
+    expectToBeCalledOnce(task2);
+    expectToBeCalledOnce(task3);
+  });
+
+  it('should handle nested promises', () => {
+    const task1 = jest.genMockFunction().mockImplementation(() => {
+      return new Promise(resolve => {
+        setTimeout(() => {
+          expect(++sequenceId).toBe(1);
+          taskQueue.enqueue({gen: task2, name: 'gen2'});
+          taskQueue.enqueue({run: resolve, name: 'resolve1'});
+        }, 1);
+      });
+    });
+    const task2 = jest.genMockFunction().mockImplementation(() => {
+      return new Promise(resolve => {
+        setTimeout(() => {
+          expect(++sequenceId).toBe(2);
+          taskQueue.enqueue({run: task3, name: 'run3'});
+          taskQueue.enqueue({run: resolve, name: 'resolve2'});
+        }, 1);
+      });
+    });
+    const task3 = createSequenceTask(3);
+    const task4 = createSequenceTask(4);
+    taskQueue.enqueue({gen: task1, name: 'gen1'});
+    taskQueue.enqueue({run: task4, name: 'run4'}); // blocked by task 1 promise
+
+    clearTaskQueue(taskQueue);
+
+    expectToBeCalledOnce(task1);
+    expectToBeCalledOnce(task2);
+    expectToBeCalledOnce(task3);
+    expectToBeCalledOnce(task4);
+  });
+});
diff --git a/Libraries/Utilities/MessageQueue.js b/Libraries/Utilities/MessageQueue.js
index 43211c8650ed..e95dcb38599d 100644
--- a/Libraries/Utilities/MessageQueue.js
+++ b/Libraries/Utilities/MessageQueue.js
@@ -53,6 +53,7 @@ class MessageQueue {
     this._callbacks = [];
     this._callbackID = 0;
     this._lastFlush = 0;
+    this._eventLoopStartTime = new Date().getTime();
 
     [
       'invokeCallbackAndReturnFlushedQueue',
@@ -109,6 +110,10 @@ class MessageQueue {
     return module;
   }
 
+  getEventLoopRunningTime() {
+    return new Date().getTime() - this._eventLoopStartTime;
+  }
+
   /**
    * "Private" methods
    */
@@ -150,6 +155,7 @@ class MessageQueue {
 
   __callFunction(module, method, args) {
     this._lastFlush = new Date().getTime();
+    this._eventLoopStartTime = this._lastFlush;
     if (isFinite(module)) {
       method = this._methodTable[module][method];
       module = this._moduleTable[module];
@@ -171,6 +177,7 @@ class MessageQueue {
   __invokeCallback(cbID, args) {
     Systrace.beginEvent(`MessageQueue.invokeCallback(${cbID})`);
     this._lastFlush = new Date().getTime();
+    this._eventLoopStartTime = this._lastFlush;
     let callback = this._callbacks[cbID];
     if (!callback || __DEV__) {
       let debug = this._debugInfo[cbID >> 1];

From 7035fbc58d122d2ac8ef1e2f775064529347ed58 Mon Sep 17 00:00:00 2001
From: Bhuwan Khattar <voideanvalue@fb.com>
Date: Thu, 24 Dec 2015 01:01:18 -0800
Subject: [PATCH 0506/1411] getTransformOptionsModulePath

Summary:
Passing around a `getTransformOptions` function doesn't really work with the CLI utils, so I'm changing this to `getTransformOptionsModulePath` instead, which can easily be injected in through `rn-cli.config.js`.

public

Reviewed By: martinbigio

Differential Revision: D2785789

fb-gh-sync-id: c9fdc358cb5d0db27e0d02496e44c013c77f3d5f
---
 local-cli/bundle/buildBundle.js                            | 1 +
 local-cli/dependencies/dependencies.js                     | 1 +
 local-cli/server/runServer.js                              | 1 +
 packager/README.md                                         | 5 +++--
 .../react-packager/src/Bundler/__tests__/Bundler-test.js   | 1 -
 packager/react-packager/src/Bundler/index.js               | 7 +++++--
 packager/react-packager/src/Server/index.js                | 6 +++---
 7 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/local-cli/bundle/buildBundle.js b/local-cli/bundle/buildBundle.js
index f2f1e3291ec1..6c946a8851a7 100644
--- a/local-cli/bundle/buildBundle.js
+++ b/local-cli/bundle/buildBundle.js
@@ -25,6 +25,7 @@ function buildBundle(args, config, output = outputBundle) {
       projectRoots: config.getProjectRoots(),
       assetRoots: config.getAssetRoots(),
       blacklistRE: config.getBlacklistRE(),
+      getTransformOptionsModulePath: config.getTransformOptionsModulePath,
       transformModulePath: args.transformer,
       verbose: args.verbose,
     };
diff --git a/local-cli/dependencies/dependencies.js b/local-cli/dependencies/dependencies.js
index 6a8fbb31091d..adc1e8897011 100644
--- a/local-cli/dependencies/dependencies.js
+++ b/local-cli/dependencies/dependencies.js
@@ -60,6 +60,7 @@ function _dependencies(argv, config, resolve, reject) {
     projectRoots: config.getProjectRoots(),
     assetRoots: config.getAssetRoots(),
     blacklistRE: config.getBlacklistRE(args.platform),
+    getTransformOptionsModulePath: config.getTransformOptionsModulePath,
     transformModulePath: args.transformer,
     verbose: config.verbose,
   };
diff --git a/local-cli/server/runServer.js b/local-cli/server/runServer.js
index a05b0e2e5e0d..b4a690f4c170 100644
--- a/local-cli/server/runServer.js
+++ b/local-cli/server/runServer.js
@@ -66,6 +66,7 @@ function getAppMiddleware(args, config) {
     projectRoots: args.projectRoots,
     blacklistRE: config.getBlacklistRE(),
     cacheVersion: '3',
+    getTransformOptionsModulePath: config.getTransformOptionsModulePath,
     transformModulePath: transformerPath,
     assetRoots: args.assetRoots,
     assetExts: ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'webp'],
diff --git a/packager/README.md b/packager/README.md
index d14ae0320463..039865ba6e14 100644
--- a/packager/README.md
+++ b/packager/README.md
@@ -112,8 +112,9 @@ middleware. Takes the following options:
   should be used as a persistent deamon to watch files and update
   itself
 * `assetRoots` array: Where should the packager look for assets
-* `getTransformOptions` function: Middleware to get custom options for the
-  transformer based on the bundle and module being transformed.
+* `getTransformOptionsModulePath` string: Path to module that exports a function
+  that acts as a middleware for generating options to pass to the transformer
+  based on the bundle and module being transformed.
 
 ### ReactPackager.buildPackageFromUrl(options, url)
 
diff --git a/packager/react-packager/src/Bundler/__tests__/Bundler-test.js b/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
index 37d200f2555f..ccdc84961d4c 100644
--- a/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
+++ b/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
@@ -81,7 +81,6 @@ describe('Bundler', function() {
     bundler = new Bundler({
       projectRoots: ['/root'],
       assetServer: assetServer,
-      getTransformOptions: () => ({}),
     });
 
     modules = [
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index 19174129d70d..824331c492b1 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -136,7 +136,9 @@ class Bundler {
     this._projectRoots = opts.projectRoots;
     this._assetServer = opts.assetServer;
 
-    this._getTransformOptions = opts.getTransformOptions;
+    if (opts.getTransformOptionsModulePath) {
+      this._getTransformOptions = require(opts.getTransformOptionsModulePath);
+    }
   }
 
   kill() {
@@ -325,7 +327,8 @@ class Bundler {
     } else {
       return this._transformer.loadFileAndTransform(
         path.resolve(module.path),
-        this._getTransformOptions({bundle, module, platform})
+        this._getTransformOptions ?
+          this._getTransformOptions({bundle, module, platform}) : {}
       );
     }
   }
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index a1fb415a475c..c1bc5ce194f0 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -64,9 +64,9 @@ const validateOpts = declareOpts({
     type: 'number',
     required: false,
   },
-  getTransformOptions: {
-    type: 'function',
-    default: () => ({}),
+  getTransformOptionsModulePath: {
+    type: 'string',
+    required: false,
   }
 });
 

From 3a76f83f7b7018eb2680fb10920fc06de84fb8f3 Mon Sep 17 00:00:00 2001
From: Max <contact@mstoiber.com>
Date: Thu, 24 Dec 2015 08:33:56 +0100
Subject: [PATCH 0507/1411] Add mention of the license comment in
 CONTRIBUTING.md

See this comment of PR #4866: https://github.com/facebook/react-native/pull/4866#issuecomment-166612075
---
 CONTRIBUTING.md | 26 ++++++++++++++++++++++----
 1 file changed, 22 insertions(+), 4 deletions(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 530c84098e85..3171208c89d3 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -19,10 +19,28 @@ The core team will be monitoring for pull requests. When we get one, we'll run s
 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 tests pass on Travis.
-5. Make sure your code lints (`node linter.js <files touched>`).
-6. Squash your commits (`git rebase -i`).
-7. If you haven't already, complete the CLA.
+4. Add the copyright notice to the top of any new files you've added.
+5. Ensure tests pass on Travis and Circle CI.
+6. Make sure your code lints (`node linter.js <files touched>`).
+7. Squash your commits (`git rebase -i`).
+8. If you haven't already, sign the [CLA](https://code.facebook.com/cla).
+
+#### Copyright Notice for files
+
+Copy and paste this to the top of your new file(s):
+
+```JS
+/**
+ * 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.
+ */
+```
+
+If you've added a new module, add a `@providesModule <moduleName>` at the end of the comment. This will allow the haste package manager to find it.
 
 ### Contributor License Agreement (CLA)
 

From 6cec263ca3e006e05494ecc72ca0e1cc0230bbcc Mon Sep 17 00:00:00 2001
From: Adam Miskiewicz <adam.skevy@mac.com>
Date: Thu, 24 Dec 2015 08:31:17 -0800
Subject: [PATCH 0508/1411] Fix @providesModule not being ignored properly

Summary:
There's quite a bit of code scattered around the packager regarding ignoring the `providesModule` Haste pragma in any file that isn't in `react-native`, `react-tools` or `parse`. There is even a (passing) test case.

However, there's an edge case.

Take, for example, `fbjs`. It has a module inside of it called `ErrorUtils`. `react-relay` requires this file normally, in Common.JS style, by doing `require('fbjs/libs/ErrorUtils')`. But when `react-native` attempts to require `ErrorUtils` using the HasteModule format (in it's JavaScript initialization), it resolves the `fbjs` `ErrorUtils` module, instead of RN's `ErrorUtils`.

This happens, it turns out, because when a module is read (in `Module._read`), it's not caring about whether or not it should pay attention to `providesModule`, and is just assigning the `providesModule` value as the id of the module no matter what. Then when `Module.getName` is called, it will always use that `data.id` that was set, thus creating the wrong dependency tree.

This
Closes https://github.com/facebook/react-native/pull/3625

Reviewed By: svcscm

Differential Revision: D2632317

Pulled By: vjeux

fb-gh-sync-id: efd8066eaf6f18fcf79698beab36cab90bf5cd6d
---
 .../src/DependencyResolver/AssetModule.js     |  2 +-
 .../{Helpers.js => DependencyGraphHelpers.js} |  4 +-
 .../DependencyGraph/DeprecatedAssetMap.js     |  2 +-
 .../__tests__/DependencyGraph-test.js         | 77 ++++++++++++++++++-
 .../DependencyGraph/index.js                  |  7 +-
 .../src/DependencyResolver/Module.js          | 23 ++++--
 .../src/DependencyResolver/ModuleCache.js     | 40 +++++-----
 .../src/DependencyResolver/Package.js         | 12 +--
 .../src/DependencyResolver/Polyfill.js        |  2 +-
 .../__tests__/Module-test.js                  | 23 +++---
 .../src/Resolver/__tests__/Resolver-test.js   |  2 +-
 11 files changed, 140 insertions(+), 54 deletions(-)
 rename packager/react-packager/src/DependencyResolver/DependencyGraph/{Helpers.js => DependencyGraphHelpers.js} (94%)

diff --git a/packager/react-packager/src/DependencyResolver/AssetModule.js b/packager/react-packager/src/DependencyResolver/AssetModule.js
index 1e5ff7d44b4f..f5555facd744 100644
--- a/packager/react-packager/src/DependencyResolver/AssetModule.js
+++ b/packager/react-packager/src/DependencyResolver/AssetModule.js
@@ -25,7 +25,7 @@ class AssetModule extends Module {
     return Promise.resolve([]);
   }
 
-  _read() {
+  read() {
     return Promise.resolve({});
   }
 
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/Helpers.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/DependencyGraphHelpers.js
similarity index 94%
rename from packager/react-packager/src/DependencyResolver/DependencyGraph/Helpers.js
rename to packager/react-packager/src/DependencyResolver/DependencyGraph/DependencyGraphHelpers.js
index fda5600777a1..d7d9f20e578e 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/Helpers.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/DependencyGraphHelpers.js
@@ -10,7 +10,7 @@
 
 const path = require('path');
 
-class Helpers {
+class DependencyGraphHelpers {
   constructor({ providesModuleNodeModules, assetExts }) {
     this._providesModuleNodeModules = providesModuleNodeModules;
     this._assetExts = assetExts;
@@ -46,4 +46,4 @@ class Helpers {
   }
 }
 
-module.exports = Helpers;
+module.exports = DependencyGraphHelpers;
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/DeprecatedAssetMap.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/DeprecatedAssetMap.js
index aedfa4ce0aa0..5f18875ae1fd 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/DeprecatedAssetMap.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/DeprecatedAssetMap.js
@@ -92,7 +92,7 @@ class DeprecatedAssetMap {
         debug('Conflcting assets', name);
       }
 
-      this._map[name] = new AssetModule_DEPRECATED(file);
+      this._map[name] = new AssetModule_DEPRECATED({ file });
     }
   }
 
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
index 8b50c8b49c52..b99d60655cca 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
@@ -2362,6 +2362,7 @@ describe('DependencyGraph', function() {
 
     pit('should selectively ignore providesModule in node_modules', function() {
       var root = '/root';
+      var otherRoot = '/anotherRoot';
       fs.__setMockFilesystem({
         'root': {
           'index.js': [
@@ -2371,6 +2372,9 @@ describe('DependencyGraph', function() {
             'require("shouldWork");',
             'require("dontWork");',
             'require("wontWork");',
+            'require("ember");',
+            'require("internalVendoredPackage");',
+            'require("anotherIndex");',
           ].join('\n'),
           'node_modules': {
             'react-haste': {
@@ -2378,6 +2382,7 @@ describe('DependencyGraph', function() {
                 name: 'react-haste',
                 main: 'main.js',
               }),
+              // @providesModule should not be ignored here, because react-haste is whitelisted
               'main.js': [
                 '/**',
                 ' * @providesModule shouldWork',
@@ -2390,6 +2395,7 @@ describe('DependencyGraph', function() {
                     name: 'bar',
                     main: 'main.js',
                   }),
+                  // @providesModule should be ignored here, because it's not whitelisted
                   'main.js':[
                     '/**',
                     ' * @providesModule dontWork',
@@ -2411,20 +2417,48 @@ describe('DependencyGraph', function() {
                 name: 'ember',
                 main: 'main.js',
               }),
+              // @providesModule should be ignored here, because it's not whitelisted,
+              // and also, the modules "id" should be ember/main.js, not it's haste name
               'main.js':[
                 '/**',
                 ' * @providesModule wontWork',
                 ' */',
                 'hi();',
-              ].join('\n'),
+              ].join('\n')
             },
           },
+          // This part of the dep graph is meant to emulate internal facebook infra.
+          // By whitelisting `vendored_modules`, haste should still work.
+          'vendored_modules': {
+            'a-vendored-package': {
+              'package.json': JSON.stringify({
+                name: 'a-vendored-package',
+                main: 'main.js',
+              }),
+              // @providesModule should _not_ be ignored here, because it's whitelisted.
+              'main.js':[
+                '/**',
+                ' * @providesModule internalVendoredPackage',
+                ' */',
+                'hiFromInternalPackage();',
+              ].join('\n'),
+            }
+          },
         },
+        // we need to support multiple roots and using haste between them
+        'anotherRoot': {
+          'index.js': [
+            '/**',
+            ' * @providesModule anotherIndex',
+            ' */',
+            'wazup()',
+          ].join('\n'),
+        }
       });
 
       var dgraph = new DependencyGraph({
         ...defaults,
-        roots: [root],
+        roots: [root, otherRoot],
       });
       return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
         expect(deps)
@@ -2432,7 +2466,14 @@ describe('DependencyGraph', function() {
             {
               id: 'index',
               path: '/root/index.js',
-              dependencies: ['shouldWork', 'dontWork', 'wontWork'],
+              dependencies: [
+                'shouldWork',
+                'dontWork',
+                'wontWork',
+                'ember',
+                'internalVendoredPackage',
+                'anotherIndex'
+              ],
               isAsset: false,
               isAsset_DEPRECATED: false,
               isJSON: false,
@@ -2459,6 +2500,36 @@ describe('DependencyGraph', function() {
               isPolyfill: false,
               resolution: undefined,
             },
+            {
+              id: 'ember/main.js',
+              path: '/root/node_modules/ember/main.js',
+              dependencies: [],
+              isAsset: false,
+              isAsset_DEPRECATED: false,
+              isJSON: false,
+              isPolyfill: false,
+              resolution: undefined,
+            },
+            {
+              id: 'internalVendoredPackage',
+              path: '/root/vendored_modules/a-vendored-package/main.js',
+              dependencies: [],
+              isAsset: false,
+              isAsset_DEPRECATED: false,
+              isJSON: false,
+              isPolyfill: false,
+              resolution: undefined,
+            },
+            {
+              id: 'anotherIndex',
+              path: '/anotherRoot/index.js',
+              dependencies: [],
+              isAsset: false,
+              isAsset_DEPRECATED: false,
+              isJSON: false,
+              isPolyfill: false,
+              resolution: undefined,
+            },
           ]);
       });
     });
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
index 9f87dcbc2ebf..69072339f2e1 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
@@ -16,7 +16,7 @@ const getPlatformExtension = require('../lib/getPlatformExtension');
 const isAbsolutePath = require('absolute-path');
 const path = require('path');
 const util = require('util');
-const Helpers = require('./Helpers');
+const DependencyGraphHelpers = require('./DependencyGraphHelpers');
 const ResolutionRequest = require('./ResolutionRequest');
 const ResolutionResponse = require('./ResolutionResponse');
 const HasteMap = require('./HasteMap');
@@ -57,7 +57,7 @@ class DependencyGraph {
       extractRequires,
     };
     this._cache = this._opts.cache;
-    this._helpers = new Helpers(this._opts);
+    this._helpers = new DependencyGraphHelpers(this._opts);
     this.load().catch((err) => {
       // This only happens at initialization. Live errors are easier to recover from.
       console.error('Error building DependencyGraph:\n', err.stack);
@@ -97,7 +97,8 @@ class DependencyGraph {
     this._moduleCache = new ModuleCache(
       this._fastfs,
       this._cache,
-      this._opts.extractRequires
+      this._opts.extractRequires,
+      this._helpers
     );
 
     this._hasteMap = new HasteMap({
diff --git a/packager/react-packager/src/DependencyResolver/Module.js b/packager/react-packager/src/DependencyResolver/Module.js
index a6112082027f..3fcd63f08791 100644
--- a/packager/react-packager/src/DependencyResolver/Module.js
+++ b/packager/react-packager/src/DependencyResolver/Module.js
@@ -15,7 +15,7 @@ const extractRequires = require('./lib/extractRequires');
 
 class Module {
 
-  constructor(file, fastfs, moduleCache, cache, extractor) {
+  constructor({ file, fastfs, moduleCache, cache, extractor, depGraphHelpers }) {
     if (!isAbsolutePath(file)) {
       throw new Error('Expected file to be absolute path but got ' + file);
     }
@@ -27,17 +27,18 @@ class Module {
     this._moduleCache = moduleCache;
     this._cache = cache;
     this._extractor = extractor;
+    this._depGraphHelpers = depGraphHelpers;
   }
 
   isHaste() {
-    return this._read().then(data => !!data.id);
+    return this.read().then(data => !!data.id);
   }
 
   getName() {
     return this._cache.get(
       this.path,
       'name',
-      () => this._read().then(data => {
+      () => this.read().then(data => {
         if (data.id) {
           return data.id;
         }
@@ -66,23 +67,31 @@ class Module {
   }
 
   getDependencies() {
-    return this._read().then(data => data.dependencies);
+    return this.read().then(data => data.dependencies);
   }
 
   getAsyncDependencies() {
-    return this._read().then(data => data.asyncDependencies);
+    return this.read().then(data => data.asyncDependencies);
   }
 
   invalidate() {
     this._cache.invalidate(this.path);
   }
 
-  _read() {
+  read() {
     if (!this._reading) {
       this._reading = this._fastfs.readFile(this.path).then(content => {
         const data = {};
+
+        // Set an id on the module if it's using @providesModule syntax
+        // and if it's NOT in node_modules (and not a whitelisted node_module).
+        // This handles the case where a project may have a dep that has @providesModule
+        // docblock comments, but doesn't want it to conflict with whitelisted @providesModule
+        // modules, such as react-haste, fbjs-haste, or react-native or with non-dependency,
+        // project-specific code that is using @providesModule.
         const moduleDocBlock = docblock.parseAsObject(content);
-        if (moduleDocBlock.providesModule || moduleDocBlock.provides) {
+        if (!this._depGraphHelpers.isNodeModulesDir(this.path) &&
+            (moduleDocBlock.providesModule || moduleDocBlock.provides)) {
           data.id = /^(\S*)/.exec(
             moduleDocBlock.providesModule || moduleDocBlock.provides
           )[1];
diff --git a/packager/react-packager/src/DependencyResolver/ModuleCache.js b/packager/react-packager/src/DependencyResolver/ModuleCache.js
index a889143972a4..0fba47a90412 100644
--- a/packager/react-packager/src/DependencyResolver/ModuleCache.js
+++ b/packager/react-packager/src/DependencyResolver/ModuleCache.js
@@ -7,25 +7,27 @@ const path = require('path');
 
 class ModuleCache {
 
-  constructor(fastfs, cache, extractRequires) {
+  constructor(fastfs, cache, extractRequires, depGraphHelpers) {
     this._moduleCache = Object.create(null);
     this._packageCache = Object.create(null);
     this._fastfs = fastfs;
     this._cache = cache;
     this._extractRequires = extractRequires;
+    this._depGraphHelpers = depGraphHelpers;
     fastfs.on('change', this._processFileChange.bind(this));
   }
 
   getModule(filePath) {
     filePath = path.resolve(filePath);
     if (!this._moduleCache[filePath]) {
-      this._moduleCache[filePath] = new Module(
-        filePath,
-        this._fastfs,
-        this,
-        this._cache,
-        this._extractRequires
-      );
+      this._moduleCache[filePath] = new Module({
+        file: filePath,
+        fastfs: this._fastfs,
+        moduleCache: this,
+        cache: this._cache,
+        extractor: this._extractRequires,
+        depGraphHelpers: this._depGraphHelpers
+      });
     }
     return this._moduleCache[filePath];
   }
@@ -33,12 +35,12 @@ class ModuleCache {
   getAssetModule(filePath) {
     filePath = path.resolve(filePath);
     if (!this._moduleCache[filePath]) {
-      this._moduleCache[filePath] = new AssetModule(
-        filePath,
-        this._fastfs,
-        this,
-        this._cache,
-      );
+      this._moduleCache[filePath] = new AssetModule({
+        file: filePath,
+        fastfs: this._fastfs,
+        moduleCache: this,
+        cache: this._cache,
+      });
     }
     return this._moduleCache[filePath];
   }
@@ -46,11 +48,11 @@ class ModuleCache {
   getPackage(filePath) {
     filePath = path.resolve(filePath);
     if (!this._packageCache[filePath]) {
-      this._packageCache[filePath] = new Package(
-        filePath,
-        this._fastfs,
-        this._cache,
-      );
+      this._packageCache[filePath] = new Package({
+        file: filePath,
+        fastfs: this._fastfs,
+        cache: this._cache,
+      });
     }
     return this._packageCache[filePath];
   }
diff --git a/packager/react-packager/src/DependencyResolver/Package.js b/packager/react-packager/src/DependencyResolver/Package.js
index ac7ee88c1a06..e88b0640ccbc 100644
--- a/packager/react-packager/src/DependencyResolver/Package.js
+++ b/packager/react-packager/src/DependencyResolver/Package.js
@@ -5,7 +5,7 @@ const path = require('path');
 
 class Package {
 
-  constructor(file, fastfs, cache) {
+  constructor({ file, fastfs, cache }) {
     this.path = path.resolve(file);
     this.root = path.dirname(this.path);
     this._fastfs = fastfs;
@@ -14,7 +14,7 @@ class Package {
   }
 
   getMain() {
-    return this._read().then(json => {
+    return this.read().then(json => {
       var replacements = getReplacements(json);
       if (typeof replacements === 'string') {
         return path.join(this.root, replacements);
@@ -36,13 +36,13 @@ class Package {
 
   isHaste() {
     return this._cache.get(this.path, 'package-haste', () =>
-      this._read().then(json => !!json.name)
+      this.read().then(json => !!json.name)
     );
   }
 
   getName() {
     return this._cache.get(this.path, 'package-name', () =>
-      this._read().then(json => json.name)
+      this.read().then(json => json.name)
     );
   }
 
@@ -51,7 +51,7 @@ class Package {
   }
 
   redirectRequire(name) {
-    return this._read().then(json => {
+    return this.read().then(json => {
       var replacements = getReplacements(json);
 
       if (!replacements || typeof replacements !== 'object') {
@@ -81,7 +81,7 @@ class Package {
     });
   }
 
-  _read() {
+  read() {
     if (!this._reading) {
       this._reading = this._fastfs.readFile(this.path)
         .then(jsonStr => JSON.parse(jsonStr));
diff --git a/packager/react-packager/src/DependencyResolver/Polyfill.js b/packager/react-packager/src/DependencyResolver/Polyfill.js
index 752b864b894e..97c57adb7e9c 100644
--- a/packager/react-packager/src/DependencyResolver/Polyfill.js
+++ b/packager/react-packager/src/DependencyResolver/Polyfill.js
@@ -5,7 +5,7 @@ const Module = require('./Module');
 
 class Polyfill extends Module {
   constructor({ path, id, dependencies }) {
-    super(path);
+    super({ file: path });
     this._id = id;
     this._dependencies = dependencies;
   }
diff --git a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js b/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
index 656a1b003807..7938ca791586 100644
--- a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
+++ b/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
@@ -22,6 +22,7 @@ jest
 const Fastfs = require('../fastfs');
 const Module = require('../Module');
 const ModuleCache = require('../ModuleCache');
+const DependencyGraphHelpers = require('../DependencyGraph/DependencyGraphHelpers');
 const Promise = require('promise');
 const fs = require('fs');
 
@@ -50,12 +51,13 @@ describe('Module', () => {
       const cache = new Cache();
 
       return fastfs.build().then(() => {
-        const module = new Module(
-          '/root/index.js',
+        const module = new Module({
+          file: '/root/index.js',
           fastfs,
-          new ModuleCache(fastfs, cache),
-          cache
-        );
+          moduleCache: new ModuleCache(fastfs, cache),
+          cache: cache,
+          depGraphHelpers: new DependencyGraphHelpers()
+        });
 
         return module.getAsyncDependencies().then(actual =>
           expect(actual).toEqual(expected)
@@ -122,13 +124,14 @@ describe('Module', () => {
       const cache = new Cache();
 
       return fastfs.build().then(() => {
-        return new Module(
-          '/root/index.js',
+        return new Module({
+          file: '/root/index.js',
           fastfs,
-          new ModuleCache(fastfs, cache),
+          moduleCache: new ModuleCache(fastfs, cache),
           cache,
-          extractor
-        );
+          extractor,
+          depGraphHelpers: new DependencyGraphHelpers()
+        });
       });
     }
 
diff --git a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
index 1de9905b9a40..6712f00b4a45 100644
--- a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
+++ b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
@@ -51,7 +51,7 @@ describe('Resolver', function() {
   }
 
   function createModule(id, dependencies) {
-    var module = new Module();
+    var module = new Module({});
     module.getName.mockImpl(() => Promise.resolve(id));
     module.getDependencies.mockImpl(() => Promise.resolve(dependencies));
     return module;

From c972cce405564af80ae00701280355033441e07d Mon Sep 17 00:00:00 2001
From: Adam Miskiewicz <adam.skevy@mac.com>
Date: Thu, 24 Dec 2015 09:23:39 -0800
Subject: [PATCH 0509/1411] Fix InteractionManager-test.js

Summary:
Rather than specifying what not to mock, turn off autoMock for this test suite, and only mock BatchedBridge.

Fixes #4965
Closes https://github.com/facebook/react-native/pull/4967

Reviewed By: svcscm

Differential Revision: D2789079

Pulled By: androidtrunkagent

fb-gh-sync-id: 0d7024f92b630a3c0643ea2e1fde8d673fcdf6e1
---
 Libraries/Interaction/__tests__/InteractionManager-test.js | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/Libraries/Interaction/__tests__/InteractionManager-test.js b/Libraries/Interaction/__tests__/InteractionManager-test.js
index f02701d7f632..736fc93c585f 100644
--- a/Libraries/Interaction/__tests__/InteractionManager-test.js
+++ b/Libraries/Interaction/__tests__/InteractionManager-test.js
@@ -5,9 +5,8 @@
 'use strict';
 
 jest
-  .dontMock('InteractionManager')
-  .dontMock('TaskQueue')
-  .dontMock('invariant');
+  .autoMockOff()
+  .mock('BatchedBridge');
 
 function expectToBeCalledOnce(fn) {
   expect(fn.mock.calls.length).toBe(1);

From 308612314e19404971474d21a1b85472763cbae8 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Thu, 24 Dec 2015 10:39:19 -0800
Subject: [PATCH 0510/1411] added emulator support to circle.ci

Summary: Closes https://github.com/facebook/react-native/pull/4911

Reviewed By: svcscm

Differential Revision: D2789142

Pulled By: androidtrunkagent

fb-gh-sync-id: 9fd9520c27fc9acb7b139de6843a71ca3f918249
---
 ReactAndroid/build.gradle                     |  2 +-
 .../react/testing/ReactAppTestActivity.java   |  3 +-
 circle.yml                                    | 30 +++++++++++++++----
 3 files changed, 28 insertions(+), 7 deletions(-)

diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle
index ae79f43cb6e4..1ea9ab37d665 100644
--- a/ReactAndroid/build.gradle
+++ b/ReactAndroid/build.gradle
@@ -187,7 +187,7 @@ task buildReactNdkLib(dependsOn: [prepareJSC, prepareBoost, prepareDoubleConvers
             "NDK_LIBS_OUT=$buildDir/react-ndk/all",
             "THIRD_PARTY_NDK_DIR=$buildDir/third-party-ndk",
             '-C', file('src/main/jni/react/jni').absolutePath,
-            '--jobs', Runtime.runtime.availableProcessors()
+            '--jobs', project.hasProperty("jobs") ? project.property("jobs") : Runtime.runtime.availableProcessors()
 }
 
 task cleanReactNdkLib(type: Exec) {
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java
index 734cdfd2cdd9..d63110551603 100644
--- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java
@@ -36,7 +36,8 @@ public class ReactAppTestActivity extends FragmentActivity implements
 
   private static final String DEFAULT_BUNDLE_NAME = "AndroidTestBundle.js";
   private static final int ROOT_VIEW_ID = 8675309;
-  private static final long IDLE_TIMEOUT_MS = 15000;
+  // we need a bigger timeout for CI builds because they run on a slow emulator
+  private static final long IDLE_TIMEOUT_MS = 60000;
 
   private CountDownLatch mLayoutEvent = new CountDownLatch(1);
   private @Nullable ReactBridgeIdleSignaler mBridgeIdleSignaler;
diff --git a/circle.yml b/circle.yml
index ff3c01145ede..3077d7ba9554 100644
--- a/circle.yml
+++ b/circle.yml
@@ -1,16 +1,36 @@
 machine:
   node:
     version: 5.1.0
+  environment:
+    PATH: "~/$CIRCLE_PROJECT_REPONAME/gradle-2.9/bin:$PATH"
+    TERM: "dumb"
+    ADB_INSTALL_TIMEOUT: "10"
+    GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx512m -XX:+HeapDumpOnOutOfMemoryError"'
 
 dependencies:
   pre:
   - npm install -g npm@3.2
-
+  - wget "https://services.gradle.org/distributions/gradle-2.9-bin.zip"; unzip gradle-2.9-bin.zip
 test:
+  pre:
+    # starting emulator in advance because it takes very long to boot
+    # the side effect is that we loose 1GB of RAM for all the following commands
+    # if builds are running out of memory move the emulator start right before `wait-for-boot`
+    - emulator -avd circleci-android22 -no-audio -no-window:
+              background: true
+              parallel: true
   override:
-    # gradle is flaky in CI envs, found a solution here http://stackoverflow.com/questions/28409608/gradle-assembledebug-and-predexdebug-fail-with-circleci
-    - TERM=dumb ./gradlew testDebugUnitTest -PpreDexEnable=false -Pcom.android.build.threadPoolSize=1 -Dorg.gradle.parallel=false -Dorg.gradle.jvmargs="-Xms512m -Xmx512m" -Dorg.gradle.daemon=false
-    # build JS bundle
+    # build ndkreactlib first because it consumes memory and downloads stuff
+    - ./gradlew :ReactAndroid:buildReactNdkLib -PdisablePreDex -Pjobs=1
+    # unit tests
+    - ./gradlew :ReactAndroid:testDebugUnitTest -PdisablePreDex
+    # build JS bundle for instrumentation tests
     - node local-cli/cli.js bundle --platform android --dev true --entry-file ReactAndroid/src/androidTest/assets/TestBundle.js --bundle-output ReactAndroid/src/androidTest/assets/AndroidTestBundle.js
     # run instrumentation tests on device
-    - TERM=dumb ./gradlew connectedCheck
+    - circle-android wait-for-boot
+    - sleep 5
+    # unlock the emulator screen
+    - adb shell input keyevent 82
+    - sleep 5
+    # run tests on the emulator
+    - ./gradlew :ReactAndroid:connectedAndroidTest -PdisablePreDex --stacktrace

From 36d26c7d3b09cc7f241ceb3d5f5be26a8c88f213 Mon Sep 17 00:00:00 2001
From: Wesley Ellis <tahnok@gmail.com>
Date: Thu, 24 Dec 2015 13:12:17 -0800
Subject: [PATCH 0511/1411] Don't set height to avoid clipping textinput for
 XHRExample on android

Summary:
When adding fields to the multipart/form-data Upload section the two `TextInput` fields have a height set that is causing them to be clipped on my Nexus 5 (5.1.1) like so:

![screenshot_2015-09-15-16-50-41](https://cloud.githubusercontent.com/assets/362769/9889808/485a080c-5bca-11e5-9858-6aa51823928b.png)

I've removed the height property, so now it looks like:

![screenshot_2015-09-15-16-50-22](https://cloud.githubusercontent.com/assets/362769/9889806/484f416a-5bca-11e5-9a54-255f0cfc1051.png)
Closes https://github.com/facebook/react-native/pull/2730

Reviewed By: svcscm

Differential Revision: D2789188

Pulled By: androidtrunkagent

fb-gh-sync-id: 4a9ec9bc88d6af8f1db1a6208f138ff05f4eb392
---
 Examples/UIExplorer/XHRExample.android.js | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Examples/UIExplorer/XHRExample.android.js b/Examples/UIExplorer/XHRExample.android.js
index 0ee51a8e3039..1dfb9a32cfe8 100644
--- a/Examples/UIExplorer/XHRExample.android.js
+++ b/Examples/UIExplorer/XHRExample.android.js
@@ -320,7 +320,6 @@ var styles = StyleSheet.create({
     borderRadius: 3,
     borderColor: 'grey',
     borderWidth: 1,
-    height: 30,
     paddingLeft: 8,
   },
   equalSign: {

From e4272b456e6948c0942c610d3bc65bc29f0a7be6 Mon Sep 17 00:00:00 2001
From: SangYeob Bono Yu <deminoth@gmail.com>
Date: Thu, 24 Dec 2015 17:18:15 -0800
Subject: [PATCH 0512/1411] Set encoding to UTF-8 in Android. Fixes #4873

Summary: Closes https://github.com/facebook/react-native/pull/4938

Reviewed By: svcscm

Differential Revision: D2789328

Pulled By: androidtrunkagent

fb-gh-sync-id: c0a0b385be0d832cd052b2495def431cf2c51c8c
---
 .../com/facebook/react/views/webview/ReactWebViewManager.java   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
index 588eb928ff3e..a8eb4d65b50b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
@@ -62,7 +62,7 @@ public class ReactWebViewManager extends SimpleViewManager<WebView> {
   private static final String REACT_CLASS = "RCTWebView";
 
   private static final String HTML_ENCODING = "UTF-8";
-  private static final String HTML_MIME_TYPE = "text/html";
+  private static final String HTML_MIME_TYPE = "text/html; charset=utf-8";
 
   public static final int COMMAND_GO_BACK = 1;
   public static final int COMMAND_GO_FORWARD = 2;

From a47fcd44f9b8bcb6f6eb0629d2e68d1fd5c3807d Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Thu, 24 Dec 2015 19:34:15 -0800
Subject: [PATCH 0513/1411] Confusing description about task queue

Summary:
Just can't get the point. What does `the next task that might have been queued up earlier` mean? Earlier than what? `The first task`? Please correct me if I missed something.
Closes https://github.com/facebook/react-native/pull/4970

Reviewed By: svcscm

Differential Revision: D2789390

Pulled By: sahrens

fb-gh-sync-id: 3078fb6cbc7940d26d2dc393ba9448f132721ea2
---
 Libraries/Interaction/TaskQueue.js | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/Libraries/Interaction/TaskQueue.js b/Libraries/Interaction/TaskQueue.js
index 8ef7a37047b2..a2783bea0e39 100644
--- a/Libraries/Interaction/TaskQueue.js
+++ b/Libraries/Interaction/TaskQueue.js
@@ -35,10 +35,9 @@ export type Task = Function | SimpleTask | PromiseTask;
  * function is supplied, then the promise it returns will block execution of
  * tasks already in the queue until it resolves. This can be used to make sure
  * the first task is fully resolved (including asynchronous dependencies that
- * also schedule more tasks via `enqueue`) before starting on the next task that
- * might have been queued up earlier. The `onMoreTasks` constructor argument is
- * used to inform the owner that an async task has resolved and that the queue
- * should be processed again.
+ * also schedule more tasks via `enqueue`) before starting on the next task. 
+ * The `onMoreTasks` constructor argument is used to inform the owner that an 
+ * async task has resolved and that the queue should be processed again.
  *
  * Note: Tasks are only actually executed with explicit calls to `processNext`.
  */

From bde2f304744f4f01260ae083ef9116c5a1dbd189 Mon Sep 17 00:00:00 2001
From: Patrick Puritscher <blackout289@gmail.com>
Date: Fri, 25 Dec 2015 02:16:36 -0800
Subject: [PATCH 0514/1411] Update templates to ES2015

Summary:
I don't know the reasons, why the templates are written with the `react.createClass`method. Today I see lot's of examples using the **ES6 way**. In my own projects I'm using this way, too.

I removed `use strict`, since *Module code is always strict mode code*, according to the [spec](http://www.ecma-international.org/ecma-262/6.0/#sec-strict-mode-code).

Maybe we should **discuss** the usage of ES6 in the templates.
Closes https://github.com/facebook/react-native/pull/4891

Reviewed By: svcscm

Differential Revision: D2789493

Pulled By: androidtrunkagent

fb-gh-sync-id: 90e70f787017c61dc64cbc9f0beb02331fa749ec
---
 local-cli/generator/templates/index.android.js | 17 ++++++++---------
 local-cli/generator/templates/index.ios.js     | 17 ++++++++---------
 2 files changed, 16 insertions(+), 18 deletions(-)

diff --git a/local-cli/generator/templates/index.android.js b/local-cli/generator/templates/index.android.js
index ab6226614f7a..ce565390a48f 100644
--- a/local-cli/generator/templates/index.android.js
+++ b/local-cli/generator/templates/index.android.js
@@ -3,17 +3,16 @@
  * https://github.com/facebook/react-native
  */
 'use strict';
-
-var React = require('react-native');
-var {
+import React, {
   AppRegistry,
+  Component,
   StyleSheet,
   Text,
-  View,
-} = React;
+  View
+} from 'react-native';
 
-var <%= name %> = React.createClass({
-  render: function() {
+class <%= name %> extends Component {
+  render() {
     return (
       <View style={styles.container}>
         <Text style={styles.welcome}>
@@ -28,9 +27,9 @@ var <%= name %> = React.createClass({
       </View>
     );
   }
-});
+}
 
-var styles = StyleSheet.create({
+const styles = StyleSheet.create({
   container: {
     flex: 1,
     justifyContent: 'center',
diff --git a/local-cli/generator/templates/index.ios.js b/local-cli/generator/templates/index.ios.js
index f37d0df804b3..de44bc2534c1 100644
--- a/local-cli/generator/templates/index.ios.js
+++ b/local-cli/generator/templates/index.ios.js
@@ -3,17 +3,16 @@
  * https://github.com/facebook/react-native
  */
 'use strict';
-
-var React = require('react-native');
-var {
+import React, {
   AppRegistry,
+  Component,
   StyleSheet,
   Text,
-  View,
-} = React;
+  View
+} from 'react-native';
 
-var <%= name %> = React.createClass({
-  render: function() {
+class <%= name %> extends Component {
+  render() {
     return (
       <View style={styles.container}>
         <Text style={styles.welcome}>
@@ -29,9 +28,9 @@ var <%= name %> = React.createClass({
       </View>
     );
   }
-});
+}
 
-var styles = StyleSheet.create({
+const styles = StyleSheet.create({
   container: {
     flex: 1,
     justifyContent: 'center',

From 70c89fa0d272105e826754464a10cd75d21e7ab0 Mon Sep 17 00:00:00 2001
From: Hosain <hosainnet@users.noreply.github.com>
Date: Fri, 25 Dec 2015 21:32:39 +0000
Subject: [PATCH 0515/1411] Update incorrect WebSocket example in Network.md
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Using the provided WebSocket example under react-native 0.17, the sample code throws the following error:

"TypeError: ws.on is not a function(…)"

It's listening on ".on" which does not exist, rather than assigning a function to onopen, onmessage, onerror and onclose.

See: https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
---
 docs/Network.md | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/docs/Network.md b/docs/Network.md
index ce2755983593..1997e47f3265 100644
--- a/docs/Network.md
+++ b/docs/Network.md
@@ -74,25 +74,25 @@ WebSocket is a protocol providing full-duplex communication channels over a sing
 ```js
 var ws = new WebSocket('ws://host.com/path');
 
-ws.on('open', function() {
+ws.onopen = () => {
   // connection opened
   ws.send('something');
-});
+};
 
-ws.on('message', function(e) {
+ws.onmessage = (e) => {
   // a message was received
   console.log(e.data);
-});
+};
 
-ws.on('error', function(e) {
+ws.onerror = (e) => {
   // an error occurred
   console.log(e.message);
-});
+};
 
-ws.on('close', function(e) {
+ws.onclose = (e) => {
   // connection closed
   console.log(e.code, e.reason);
-});
+};
 ```
 
 ## XMLHttpRequest

From 1dea58c7dfa187a63ecfd17850b2c279e6e34716 Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Sat, 26 Dec 2015 22:23:08 +0800
Subject: [PATCH 0516/1411] add react-native version output for -v/--version

---
 react-native-cli/index.js | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/react-native-cli/index.js b/react-native-cli/index.js
index ed9803adb798..a3676c379db1 100755
--- a/react-native-cli/index.js
+++ b/react-native-cli/index.js
@@ -221,8 +221,12 @@ function checkNodeVersion() {
 
 function checkForVersionArgument() {
   if (process.argv.indexOf('-v') >= 0 || process.argv.indexOf('--version') >= 0) {
-    var pjson = require('./package.json');
-    console.log(pjson.version);
+    console.log('react-native-cli: ' + require('./package.json').version);
+    try {
+      console.log('react-native: ' + require(REACT_NATIVE_PACKAGE_JSON_PATH()).version);
+    } catch (e) {
+      console.log('react-native: n/a - not inside a React Native project directory')
+    }
     process.exit();
   }
 }

From 019c564941aa160819c28ffbe392f4d94230d461 Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Thu, 24 Dec 2015 14:56:49 +0800
Subject: [PATCH 0517/1411] use a better way to update react-native package

---
 docs/Upgrading.md | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/docs/Upgrading.md b/docs/Upgrading.md
index aca07b075806..51b46bfe737e 100644
--- a/docs/Upgrading.md
+++ b/docs/Upgrading.md
@@ -15,15 +15,14 @@ version of React Native:
 
 ## 1. Upgrade the `react-native` dependency
 
-Note the latest version of the `react-native` npm package from here:
+Note the latest version of the `react-native` npm package from here (or use `npm info react-native` to check):
 
 * https://www.npmjs.com/package/react-native
 
-Open your `package.json` file and update the version of `react-native` under `dependencies` to the
-latest version. Now, in a terminal run:
+Now install that version of `react-native` in your project with `npm install --save`. For example, to upgrade to the version `0.18`, in a terminal run:
 
 ```sh
-$ npm install
+$ npm install --save react-native@0.18
 ```
 
 ## 2. Upgrade your project templates

From 1eb12b2fbf596fe0819d5b6a606ef95a1ed40950 Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Sat, 26 Dec 2015 23:52:18 +0800
Subject: [PATCH 0518/1411] add community translation links

add community translation links to help spreading react-native!
---
 website/src/react-native/support.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/support.js b/website/src/react-native/support.js
index 721faed999a7..abf51306be98 100644
--- a/website/src/react-native/support.js
+++ b/website/src/react-native/support.js
@@ -28,6 +28,12 @@ var support = React.createClass({
               questions.
             </p>
 
+            <H2>Community translation</H2>
+            <p>The following is a list of translated docs offered by community volunteers. Send a pull request to fill the list!</p>
+            <ul>
+              <li><a href="http://reactnative.cn">Chinese</a> (<a href="https://github.com/reactnativecn/react-native-docs-cn">source</a>)</li>
+            </ul>
+            
             <H2>Stack Overflow</H2>
             <p>Many members of the community use Stack Overflow to ask questions. Read through the <a href="http://stackoverflow.com/questions/tagged/react-native">existing questions</a> tagged with <strong>react-native</strong> or <a href="http://stackoverflow.com/questions/ask">ask your own</a>!</p>
 

From f546dc3790edd4e0b310caccdc273f31a717258c Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Sun, 27 Dec 2015 06:00:39 -0800
Subject: [PATCH 0519/1411] Move WPO to the minify step

Summary:
public

The Whole Program Optimisation (WPO) pass is quite slow, and can make it painful
to iterate when having `dev=false`. Move it to happen only when both `dev=false` and `minify=true`.

Reviewed By: davidaurelio

Differential Revision: D2773941

fb-gh-sync-id: ac5ca4e1286e233c2d175eecdbf7494d5d3497b2
---
 packager/react-packager/src/Bundler/Bundle.js | 38 +++++++++----------
 1 file changed, 18 insertions(+), 20 deletions(-)

diff --git a/packager/react-packager/src/Bundler/Bundle.js b/packager/react-packager/src/Bundler/Bundle.js
index 11a892f79920..b5e591c8f0d4 100644
--- a/packager/react-packager/src/Bundler/Bundle.js
+++ b/packager/react-packager/src/Bundler/Bundle.js
@@ -109,24 +109,6 @@ class Bundle {
     }
 
     this._source = _.pluck(this._modules, 'code').join('\n');
-
-    if (dev) {
-      return this._source;
-    }
-
-    const wpoActivity = Activity.startEvent('Whole Program Optimisations');
-    const result = require('babel-core').transform(this._source, {
-      retainLines: true,
-      compact: true,
-      plugins: require('../transforms/whole-program-optimisations'),
-      inputSourceMap: this.getSourceMap(),
-    });
-
-    this._source = result.code;
-    this._sourceMap = result.map;
-
-    Activity.endEvent(wpoActivity);
-
     return this._source;
   }
 
@@ -187,13 +169,29 @@ class Bundle {
       return this._minifiedSourceAndMap;
     }
 
-    const source = this._getSource(dev);
+    let source = this._getSource(dev);
+    let map = this.getSourceMap();
+
+    if (!dev) {
+      const wpoActivity = Activity.startEvent('Whole Program Optimisations');
+      const wpoResult = require('babel-core').transform(source, {
+        retainLines: true,
+        compact: true,
+        plugins: require('../transforms/whole-program-optimisations'),
+        inputSourceMap: map,
+      });
+      Activity.endEvent(wpoActivity);
+
+      source = wpoResult.code;
+      map = wpoResult.map;
+    }
+
     try {
       const minifyActivity = Activity.startEvent('minify');
       this._minifiedSourceAndMap = UglifyJS.minify(source, {
         fromString: true,
         outSourceMap: this._sourceMapUrl,
-        inSourceMap: this.getSourceMap(),
+        inSourceMap: map,
         output: {ascii_only: true},
       });
       Activity.endEvent(minifyActivity);

From 315180dd901a0f391fb79d87f51b3a919b9d574a Mon Sep 17 00:00:00 2001
From: Genki Takiuchi <genki@s21g.com>
Date: Mon, 28 Dec 2015 16:39:50 +0900
Subject: [PATCH 0520/1411] Update showcase.js

Added a link to android app of DockMan.
---
 website/src/react-native/showcase.js | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 9c13a1ee57d6..71f2e7d09318 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -172,7 +172,11 @@ var apps = [
   {
     name: 'DockMan',
     icon: 'http://a1.mzstatic.com/us/r30/Purple49/v4/91/b5/75/91b57552-d9bc-d8bc-10a1-617de920aaa6/icon175x175.png',
-    link: 'http://www.s21g.com/DockMan.html',
+    linkAppStore: 'https://itunes.apple.com/app/dockman/id1061469696',
+    linkPlayStore: 'https://play.google.com/store/apps/details?id=com.s21g.DockMan',
+    blogs: [
+      'http://www.s21g.com/DockMan.html',
+    ],
     author: 'Genki Takiuchi (s21g Inc.)',
   },
   {

From 58bbd7bc5b3d8cb538a15d7f0bd7b6202b4a2900 Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Mon, 28 Dec 2015 06:39:11 -0800
Subject: [PATCH 0521/1411] Hint for passing navigator in renderScene

Summary: Closes https://github.com/facebook/react-native/pull/4999

Reviewed By: svcscm

Differential Revision: D2790687

Pulled By: androidtrunkagent

fb-gh-sync-id: af055123b351e37081a37d6153333666a878113c
---
 Libraries/CustomComponents/Navigator/Navigator.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/CustomComponents/Navigator/Navigator.js b/Libraries/CustomComponents/Navigator/Navigator.js
index 0050846fa80c..11d7f3984f45 100644
--- a/Libraries/CustomComponents/Navigator/Navigator.js
+++ b/Libraries/CustomComponents/Navigator/Navigator.js
@@ -203,7 +203,7 @@ var Navigator = React.createClass({
      *
      * ```
      * (route, navigator) =>
-     *   <MySceneComponent title={route.title} />
+     *   <MySceneComponent title={route.title} navigator={navigator} />
      * ```
      */
     renderScene: PropTypes.func.isRequired,

From 8080583f528b048f5b2a9fa86580e1055611ce38 Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Mon, 28 Dec 2015 07:55:39 -0800
Subject: [PATCH 0522/1411] update description about removeClippedSubviews

Summary: Closes https://github.com/facebook/react-native/pull/4998

Reviewed By: svcscm

Differential Revision: D2790689

Pulled By: androidtrunkagent

fb-gh-sync-id: 2db476eabe067fd770b6acce47b62607df348052
---
 Libraries/CustomComponents/ListView/ListView.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js
index fa4548f73883..a2406236cf13 100644
--- a/Libraries/CustomComponents/ListView/ListView.js
+++ b/Libraries/CustomComponents/ListView/ListView.js
@@ -199,9 +199,9 @@ var ListView = React.createClass({
      */
     onChangeVisibleRows: React.PropTypes.func,
     /**
-     * An experimental performance optimization for improving scroll perf of
+     * A performance optimization for improving scroll perf of
      * large lists, used in conjunction with overflow: 'hidden' on the row
-     * containers.  Use at your own risk.
+     * containers.  This is enabled by default.
      */
     removeClippedSubviews: React.PropTypes.bool,
   },

From dfa541a050ac7e7fd7d162fc28955baf4795d218 Mon Sep 17 00:00:00 2001
From: Noah Jorgenson <noah.m.jorgenson@gmail.com>
Date: Mon, 28 Dec 2015 12:47:09 -0800
Subject: [PATCH 0523/1411] Docs for website setup

- always start website/setup.sh in website
- use setup.sh in website README
---
 website/README.md | 16 +++++-----------
 website/setup.sh  |  4 +++-
 2 files changed, 8 insertions(+), 12 deletions(-)

diff --git a/website/README.md b/website/README.md
index 37afeadb9832..5c162aab6fee 100644
--- a/website/README.md
+++ b/website/README.md
@@ -2,13 +2,13 @@
 
 The first time, get all the dependencies loaded via
 
-```
+```sh
 npm install
 ```
 
 Then, run the server via
 
-```
+```sh
 npm start
 open http://localhost:8079/react-native/index.html
 ```
@@ -19,18 +19,12 @@ Anytime you change the contents, just refresh the page and it's going to be upda
 
 First setup your environment by having two folders, one `react-native` and one `react-native-gh-pages`. The publish script expects those exact names.
 
-```
-cd ../../
-git clone git@github.com:facebook/react-native.git react-native-gh-pages
-cd react-native-gh-pages
-git checkout origin/gh-pages
-git checkout -b gh-pages
-git push --set-upstream origin gh-pages
-cd ../react-native/website
+```sh
+./setup.sh
 ```
 
 Then, after you've done changes, just run the command and it'll automatically build the static version of the site and publish it to gh-pages.
 
-```
+```sh
 ./publish.sh
 ```
diff --git a/website/setup.sh b/website/setup.sh
index 094926583d9e..9c496abf69d3 100755
--- a/website/setup.sh
+++ b/website/setup.sh
@@ -7,6 +7,9 @@
 # LICENSE file in the root directory of this source tree. An additional grant
 # of patent rights can be found in the PATENTS file in the same directory.
 
+# Start in website/ even if run from root directory
+cd "$(dirname "$0")"
+
 cd ../../
 if [ "$TRAVIS" ]; then
   git clone "https://reactjs-bot@github.com/facebook/react-native.git" react-native-gh-pages
@@ -18,4 +21,3 @@ git checkout origin/gh-pages
 git checkout -b gh-pages
 git branch --set-upstream-to=origin/gh-pages
 cd ../react-native/website
-

From 90781d3067efba046cb15a6c606449ff3d837e53 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Mon, 28 Dec 2015 16:43:08 -0800
Subject: [PATCH 0524/1411] Introduce Packager and App HMR WebSocket connection

Summary:
public

This diff adds infra to both the Packager and the running app to have a WebSocket based connection between them. This connection is toggled by a new dev menu item, namely `Enable/Disable Hot Loading`.

Reviewed By: vjeux

Differential Revision: D2787621

fb-gh-sync-id: d1dee769348e4830c28782e7b650d025f2b3a786
---
 Libraries/BatchedBridge/BatchedBridge.js    |  5 +++
 Libraries/Utilities/HMRClient.js            | 40 ++++++++++++++++++
 React/Executors/RCTJSCExecutor.m            | 11 +++++
 local-cli/server/util/attachHMRServer.js    | 47 +++++++++++++++++++++
 packager/react-packager/src/Server/index.js |  6 +++
 5 files changed, 109 insertions(+)
 create mode 100644 Libraries/Utilities/HMRClient.js
 create mode 100644 local-cli/server/util/attachHMRServer.js

diff --git a/Libraries/BatchedBridge/BatchedBridge.js b/Libraries/BatchedBridge/BatchedBridge.js
index 6d25db30e217..82ca82de1cfc 100644
--- a/Libraries/BatchedBridge/BatchedBridge.js
+++ b/Libraries/BatchedBridge/BatchedBridge.js
@@ -25,6 +25,11 @@ const JSTimersExecution = require('JSTimersExecution');
 BatchedBridge.registerCallableModule('Systrace', Systrace);
 BatchedBridge.registerCallableModule('JSTimersExecution', JSTimersExecution);
 
+if (__DEV__) {
+  const HMRClient = require('HMRClient');
+  BatchedBridge.registerCallableModule('HMRClient', HMRClient);
+}
+
 // Wire up the batched bridge on the global object so that we can call into it.
 // Ideally, this would be the inverse relationship. I.e. the native environment
 // provides this global directly with its script embedded. Then this module
diff --git a/Libraries/Utilities/HMRClient.js b/Libraries/Utilities/HMRClient.js
new file mode 100644
index 000000000000..1671b1850035
--- /dev/null
+++ b/Libraries/Utilities/HMRClient.js
@@ -0,0 +1,40 @@
+/**
+ * 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 HMRClient
+ */
+'use strict';
+
+let _activeWS;
+
+/**
+ * HMR Client that receives from the server HMR updates and propagates them
+ * runtime to reflects those changes.
+ */
+const HMRClient = {
+  setEnabled(enabled) {
+    if (_activeWS && _activeWS) {
+      _activeWS.close();
+      _activeWS = null;
+    }
+
+    if (enabled) {
+      // TODO(martinb): parametrize the url and receive entryFile to minimize 
+      // the number of updates we want to receive from the server.
+      _activeWS = new WebSocket('ws://localhost:8081/hot');
+      _activeWS.onerror = (e) => {
+        console.error('[Hot Module Replacement] Unexpected error', e);
+      };
+      _activeWS.onmessage = (m) => {
+        // TODO(martinb): inject HMR update
+      };
+    }
+  },
+};
+
+module.exports = HMRClient;
diff --git a/React/Executors/RCTJSCExecutor.m b/React/Executors/RCTJSCExecutor.m
index b2d432be3883..d71b1a351c9f 100644
--- a/React/Executors/RCTJSCExecutor.m
+++ b/React/Executors/RCTJSCExecutor.m
@@ -25,6 +25,7 @@
 #import "RCTJSCProfiler.h"
 
 static NSString *const RCTJSCProfilerEnabledDefaultsKey = @"RCTJSCProfilerEnabled";
+static NSString *const RCTHotLoadingEnabledDefaultsKey = @"RCTHotLoadingEnabled";
 
 @interface RCTJavaScriptContext : NSObject <RCTInvalidating>
 
@@ -143,6 +144,15 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
   }
 }
 
+static void RCTInstallHotLoading(RCTBridge *bridge, RCTJSCExecutor *executor)
+{
+  [bridge.devMenu addItem:[RCTDevMenuItem toggleItemWithKey:RCTHotLoadingEnabledDefaultsKey title:@"Enable Hot Loading" selectedTitle:@"Disable Hot Loading" handler:^(BOOL enabled) {
+    [executor executeBlockOnJavaScriptQueue:^{
+      [bridge enqueueJSCall:@"HMRClient.setEnabled" args:@[enabled ? @YES : @NO]];
+    }];
+  }]];
+}
+
 #endif
 
 + (void)runRunLoopThread
@@ -296,6 +306,7 @@ - (void)setUp
     };
 
     RCTInstallJSCProfiler(_bridge, strongSelf->_context.ctx);
+    RCTInstallHotLoading(_bridge, strongSelf);
 
     for (NSString *event in @[RCTProfileDidStartProfiling, RCTProfileDidEndProfiling]) {
       [[NSNotificationCenter defaultCenter] addObserver:strongSelf
diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js
new file mode 100644
index 000000000000..ae3110296e4a
--- /dev/null
+++ b/local-cli/server/util/attachHMRServer.js
@@ -0,0 +1,47 @@
+/**
+ * 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.
+ */
+'use strict';
+
+/**
+ * Attaches a WebSocket based connection to the Packager to expose
+ * Hot Module Replacement updates to the simulator.
+ */
+function attachHMRServer({httpServer, path, packagerServer}) {
+  let activeWS;
+  packagerServer.addFileChangeListener(filename => {
+    if (!activeWS) {
+      return;
+    }
+
+    // TODO(martinb): send HMR update
+  });
+
+  const WebSocketServer = require('ws').Server;
+  const wss = new WebSocketServer({
+    server: httpServer,
+    path: path,
+  });
+
+  console.log('[Hot Module Replacement] Server listening on', path);
+  wss.on('connection', ws => {
+    console.log('[Hot Module Replacement] Client connected');
+    activeWS = ws;
+
+    ws.on('error', e => {
+      console.error('[Hot Module Replacement] Unexpected error', e);
+    });
+
+    ws.on('close', () => {
+      console.log('[Hot Module Replacement] Client disconnected');
+      activeWS = null;
+    });
+  });
+}
+
+module.exports = attachHMRServer;
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index c1bc5ce194f0..c2acd305c79e 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -134,6 +134,7 @@ class Server {
     this._projectRoots = opts.projectRoots;
     this._bundles = Object.create(null);
     this._changeWatchers = [];
+    this._fileChangeListeners = [];
 
     const assetGlobs = opts.assetExts.map(ext => '**/*.' + ext);
 
@@ -175,6 +176,7 @@ class Server {
     this._fileWatcher.on('all', this._onFileChange.bind(this));
 
     this._debouncedFileChangeHandler = _.debounce(filePath => {
+      this._fileChangeListeners.forEach(listener => listener(filePath));
       this._rebuildBundles(filePath);
       this._informChangeWatchers();
     }, 50);
@@ -187,6 +189,10 @@ class Server {
     ]);
   }
 
+  addFileChangeListener(listener) {
+    this._fileChangeListeners.push(listener);
+  }
+
   buildBundle(options) {
     return Promise.resolve().then(() => {
       if (!options.platform) {

From ac9c3c548db93d4d20d113de45165a71f6a8c0a9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Mon, 28 Dec 2015 16:43:15 -0800
Subject: [PATCH 0525/1411] Make Packager send fresh modules through HMR
 interface

Reviewed By: frantic

Differential Revision: D2787951

fb-gh-sync-id: 63c04710b60d99b5161ef9a40b116ba2f72df745
---
 local-cli/server/util/attachHMRServer.js     |  7 +++++-
 packager/react-packager/src/Bundler/index.js | 23 ++++++++++++++++++++
 packager/react-packager/src/Server/index.js  | 22 +++++++++++++++++++
 3 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js
index ae3110296e4a..9554f0ff0901 100644
--- a/local-cli/server/util/attachHMRServer.js
+++ b/local-cli/server/util/attachHMRServer.js
@@ -19,7 +19,12 @@ function attachHMRServer({httpServer, path, packagerServer}) {
       return;
     }
 
-    // TODO(martinb): send HMR update
+    packagerServer.buildBundleForHMR({
+      entryFile: filename,
+      // TODO(martinb): receive platform on query string when client connects
+      platform: 'ios',
+    })
+    .then(bundle => activeWS.send(bundle));
   });
 
   const WebSocketServer = require('ws').Server;
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index 824331c492b1..87e97d06142e 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -277,6 +277,29 @@ class Bundler {
     });
   }
 
+  bundleForHMR({
+    entryFile,
+    platform,
+  }) {
+    return this.getDependencies(entryFile, /*isDev*/true, platform).then(response => {
+      const module = response.dependencies.filter(module => module.path === entryFile)[0];
+
+      return Promise.all([
+        module.getName(),
+        this._transformer.loadFileAndTransform(path.resolve(entryFile)),
+      ]).then(([moduleName, transformedSource]) => {
+        return (`
+          __accept(
+            '${moduleName}', 
+            function(global, require, module, exports) { 
+              ${transformedSource.code}
+            }
+          );
+        `);
+      });
+    });
+  }
+
   invalidateFile(filePath) {
     this._transformer.invalidateFile(filePath);
   }
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index c2acd305c79e..668d38782cbe 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -112,6 +112,17 @@ const bundleOpts = declareOpts({
   }
 });
 
+const hmrBundleOpts = declareOpts({
+  entryFile: {
+    type: 'string',
+    required: true,
+  },
+  platform: {
+    type: 'string',
+    required: true,
+  },
+});
+
 const dependencyOpts = declareOpts({
   platform: {
     type: 'string',
@@ -220,6 +231,17 @@ class Server {
     return this.buildBundle(options);
   }
 
+  buildBundleForHMR(options) {
+    return Promise.resolve().then(() => {
+      if (!options.platform) {
+        options.platform = getPlatformExtension(options.entryFile);
+      }
+
+      const opts = hmrBundleOpts(options);
+      return this._bundler.bundleForHMR(opts);
+    });
+  }
+
   getDependencies(options) {
     return Promise.resolve().then(() => {
       if (!options.platform) {

From 245065be87934924ab80103c490951a88807c2d5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Mon, 28 Dec 2015 16:43:16 -0800
Subject: [PATCH 0526/1411] Introduce HMR runtime

Summary:
public

Add a very simple runtime for self-accepting modules. The API is the same one as Webpacks's one for now.
The new infra will be end-to-end tested on a follow up diff.

Reviewed By: vjeux

Differential Revision: D2789428

fb-gh-sync-id: c39524814d53c6e4ec9d9d011081ea81089b00b6
---
 .../src/Resolver/polyfills/require.js         | 31 +++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/packager/react-packager/src/Resolver/polyfills/require.js b/packager/react-packager/src/Resolver/polyfills/require.js
index 506d38e02484..73e54e5969de 100644
--- a/packager/react-packager/src/Resolver/polyfills/require.js
+++ b/packager/react-packager/src/Resolver/polyfills/require.js
@@ -10,6 +10,17 @@
       isInitialized: false,
       hasError: false,
     };
+
+    if (__DEV__) { // HMR
+      Object.assign(modules[id].module, {
+        hot: {
+          acceptCallback: null,
+          accept: function(callback) {
+            this.acceptCallback = callback;
+          }
+        }
+      });
+    }
   }
 
   function require(id) {
@@ -82,4 +93,24 @@
 
   global.__d = define;
   global.require = require;
+
+  if (__DEV__) { // HMR
+    function accept(id, factory) {
+      var mod = modules[id];
+      if (mod.module.hot.acceptCallback) {
+        mod.factory = factory;
+        mod.isInitialized = false;
+        require(id);
+
+        mod.hot.acceptCallback();
+      } else {
+        console.log(
+          '[HMR] Module `' + id + '` cannot be accepted. ' +
+          'Please reload bundle to get the updates.'
+        );
+      }
+    }
+
+    global.__accept = accept;
+  }
 })(this);

From 24c908e79486dd73ac924de6338fa4676befe37d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Mon, 28 Dec 2015 16:43:18 -0800
Subject: [PATCH 0527/1411] Dependencies for Hot Loading

Reviewed By: vjeux

Differential Revision: D2789683

fb-gh-sync-id: 6c8f5a601040505eb597db3d6f50ec6abaa6cd6e
---
 package.json | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/package.json b/package.json
index b36379dd237f..5e5e4ff1a705 100644
--- a/package.json
+++ b/package.json
@@ -129,6 +129,8 @@
     "eslint": "1.3.1",
     "eslint-plugin-react": "3.3.1",
     "portfinder": "0.4.0",
-    "temp": "0.8.3"
+    "temp": "0.8.3",
+    "babel-plugin-react-transform": "2.0.0-beta1",
+    "react-transform-hmr": "1.0.1"
   }
 }

From 4ffb24164712c0f0cafc7c097a0cdbc80e2c04d1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Mon, 28 Dec 2015 16:43:21 -0800
Subject: [PATCH 0528/1411] Hot Loading E2E basic flow

Summary:
public

Implement all the necessary glue code for several diffs submitted before to get Hot Loading work end to end:

- Simplify `HMRClient`: we don't need to make it stateful allowing to enable and disable it because both when we enable and disable the interface we need to reload the bundle.
- On the native side we introduced a singleton to process the bundle URL. This new class might alter the url to include the `hot` attribute. I'm not 100% sure this is the best way to implement this but we cannot use `CTLSettings` for this as it's are not available on oss and I didn't want to contaminate `RCTBridge` with something specific to hot loading. Also, we could potentially use this processor for other things in the future. Please let me know if you don't like this approach or you have a better idea :).
- Use this processor to alter the default bundle URL and request a `hot` bundle when hot loading is enabled. Also make sure to enable the HMR interface when the client activates it on the dev menu.
- Add packager `hot` option.
- Include gaeron's `react-transform` on Facebook's JS transformer.

The current implementation couples a bit React Native to this feature because `react-transform-hmr` is required on `InitializeJavaScriptAppEngine`. Ideally, the packager should accept an additional list of requires and include them on the bundle among all their dependencies. Note this is not the same as the option `runBeforeMainModule` as that one only adds a require to the provided module but doesn't include all the dependencies that module amy have that the entry point doesn't. I'll address this in a follow up task to enable asap hot loading (9536142)

I had to remove 2 `.babelrc` files from `react-proxy` and `react-deep-force-update`. There's an internal task for fixing the underlaying issue to avoid doing this horrible hack (t9515889).

Reviewed By: vjeux

Differential Revision: D2790806

fb-gh-sync-id: d4b78a2acfa071d6b3accc2e6716ef5611ad4fda
---
 Libraries/BatchedBridge/BatchedBridge.js      |  3 +-
 .../InitializeJavaScriptAppEngine.js          |  5 ++
 Libraries/Utilities/HMRClient.js              | 32 ++++----
 React/Base/RCTBridge.m                        |  2 +
 React/Base/RCTBundleURLProcessor.h            | 18 +++++
 React/Base/RCTBundleURLProcessor.m            | 73 +++++++++++++++++++
 React/Executors/RCTJSCExecutor.m              | 16 +++-
 local-cli/server/util/attachHMRServer.js      | 11 ++-
 packager/react-packager/src/Bundler/index.js  | 32 ++++++--
 packager/react-packager/src/Resolver/index.js |  1 +
 .../src/Resolver/polyfills/require.js         | 20 ++++-
 packager/react-packager/src/Server/index.js   |  7 +-
 12 files changed, 183 insertions(+), 37 deletions(-)
 create mode 100644 React/Base/RCTBundleURLProcessor.h
 create mode 100644 React/Base/RCTBundleURLProcessor.m

diff --git a/Libraries/BatchedBridge/BatchedBridge.js b/Libraries/BatchedBridge/BatchedBridge.js
index 82ca82de1cfc..5b582be4036d 100644
--- a/Libraries/BatchedBridge/BatchedBridge.js
+++ b/Libraries/BatchedBridge/BatchedBridge.js
@@ -26,8 +26,7 @@ BatchedBridge.registerCallableModule('Systrace', Systrace);
 BatchedBridge.registerCallableModule('JSTimersExecution', JSTimersExecution);
 
 if (__DEV__) {
-  const HMRClient = require('HMRClient');
-  BatchedBridge.registerCallableModule('HMRClient', HMRClient);
+  BatchedBridge.registerCallableModule('HMRClient', require('HMRClient'));
 }
 
 // Wire up the batched bridge on the global object so that we can call into it.
diff --git a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
index cb6ba3275542..e1dcea29d76d 100644
--- a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
+++ b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
@@ -216,3 +216,8 @@ if (__DEV__) {
 }
 require('RCTDeviceEventEmitter');
 require('PerformanceLogger');
+
+if (__DEV__) {
+  // include this transform and it's dependencies on the bundle on dev mode
+  require('react-transform-hmr');
+}
diff --git a/Libraries/Utilities/HMRClient.js b/Libraries/Utilities/HMRClient.js
index 1671b1850035..7ce2f24b62ed 100644
--- a/Libraries/Utilities/HMRClient.js
+++ b/Libraries/Utilities/HMRClient.js
@@ -10,30 +10,26 @@
  */
 'use strict';
 
-let _activeWS;
-
 /**
  * HMR Client that receives from the server HMR updates and propagates them
  * runtime to reflects those changes.
  */
 const HMRClient = {
-  setEnabled(enabled) {
-    if (_activeWS && _activeWS) {
-      _activeWS.close();
-      _activeWS = null;
-    }
+  enable() {
+    // need to require WebSocket inside of `enable` function because the
+    // this module is defined as a `polyfillGlobal`.
+    // See `InitializeJavascriptAppEngine.js`
+    const WebSocket = require('WebSocket');
 
-    if (enabled) {
-      // TODO(martinb): parametrize the url and receive entryFile to minimize 
-      // the number of updates we want to receive from the server.
-      _activeWS = new WebSocket('ws://localhost:8081/hot');
-      _activeWS.onerror = (e) => {
-        console.error('[Hot Module Replacement] Unexpected error', e);
-      };
-      _activeWS.onmessage = (m) => {
-        // TODO(martinb): inject HMR update
-      };
-    }
+    // TODO(martinb): parametrize the url and receive entryFile to minimize
+    // the number of updates we want to receive from the server.
+    const activeWS = new WebSocket('ws://localhost:8081/hot');
+    activeWS.onerror = (e) => {
+      console.error('[Hot Module Replacement] Unexpected error', e);
+    };
+    activeWS.onmessage = (m) => {
+      eval(m.data); // eslint-disable-line no-eval
+    };
   },
 };
 
diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m
index 6ba6b5c36f1a..65e36ee2536d 100644
--- a/React/Base/RCTBridge.m
+++ b/React/Base/RCTBridge.m
@@ -17,6 +17,7 @@
 #import "RCTLog.h"
 #import "RCTPerformanceLogger.h"
 #import "RCTUtils.h"
+#import "RCTBundleURLProcessor.h"
 
 NSString *const RCTReloadNotification = @"RCTReloadNotification";
 NSString *const RCTJavaScriptWillStartLoadingNotification = @"RCTJavaScriptWillStartLoadingNotification";
@@ -257,6 +258,7 @@ - (void)setUp
   RCTAssertMainThread();
 
   _bundleURL = [self.delegate sourceURLForBridge:self] ?: _bundleURL;
+  _bundleURL = [[RCTBundleURLProcessor sharedProcessor] process: _bundleURL];
 
   // Sanitize the bundle URL
   _bundleURL = [RCTConvert NSURL:_bundleURL.absoluteString];
diff --git a/React/Base/RCTBundleURLProcessor.h b/React/Base/RCTBundleURLProcessor.h
new file mode 100644
index 000000000000..89587aa17b6e
--- /dev/null
+++ b/React/Base/RCTBundleURLProcessor.h
@@ -0,0 +1,18 @@
+/**
+ * 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.
+ */
+
+@interface RCTBundleURLProcessor : NSObject
+
++ (id)sharedProcessor;
+
+- (NSString *)getQueryStringValue:(NSString *)attribute;
+- (void)setQueryStringValue:(NSString *)value forAttribute:(NSString *)attribute;
+- (NSURL *)process:(NSURL *)url;
+
+@end
diff --git a/React/Base/RCTBundleURLProcessor.m b/React/Base/RCTBundleURLProcessor.m
new file mode 100644
index 000000000000..35c49a9d5813
--- /dev/null
+++ b/React/Base/RCTBundleURLProcessor.m
@@ -0,0 +1,73 @@
+/**
+ * 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "RCTBundleURLProcessor.h"
+
+@implementation RCTBundleURLProcessor
+
+NSDictionary *_qsAttributes;
+
++ (id)sharedProcessor
+{
+  static RCTBundleURLProcessor *sharedProcessor = nil;
+  static dispatch_once_t onceToken;
+  dispatch_once(&onceToken, ^{
+    sharedProcessor = [self new];
+  });
+  return sharedProcessor;
+}
+
+- (instancetype)init
+{
+  // dictionary with additional query string attributes that will get appended
+  // to the bundle URL
+  _qsAttributes = [NSMutableDictionary new];
+  return self;
+}
+
+- (NSString *)getQueryStringValue:(NSString *)attribute
+{
+  return [_qsAttributes valueForKey:attribute];
+}
+
+- (void)setQueryStringValue:(NSString *)value forAttribute:(NSString *)attribute
+{
+  [_qsAttributes setValue:value forKey:attribute];
+}
+
+- (NSURL *)process:(NSURL *)url
+{
+  if (url.isFileURL || [_qsAttributes count] == 0) {
+    return url;
+  }
+
+  // append either `?` or `&` depending on whether there are query string
+  // attibutes or not.
+  NSString *urlString = url.absoluteString;
+  if ([urlString rangeOfString:@"?"].location == NSNotFound) {
+    urlString = [urlString stringByAppendingString:@"?"];
+  } else {
+    urlString = [urlString stringByAppendingString:@"&"];
+  }
+
+  // array with new query string attributes
+  NSMutableArray *parts = [NSMutableArray new];
+  for (id attribute in _qsAttributes) {
+    if ([urlString rangeOfString:[NSString stringWithFormat:@"%@=", attribute]].location != NSNotFound) {
+      [NSException raise:@"Cannot override attribute" format:@"Attribute %@ is already present in url: %@", attribute, url.absoluteString];
+    }
+    [parts addObject:[NSString stringWithFormat:@"%@=%@", attribute, _qsAttributes[attribute]]];
+  }
+
+  return [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", urlString, [parts componentsJoinedByString:@"&"]]];
+}
+
+@end
diff --git a/React/Executors/RCTJSCExecutor.m b/React/Executors/RCTJSCExecutor.m
index d71b1a351c9f..b46886133fea 100644
--- a/React/Executors/RCTJSCExecutor.m
+++ b/React/Executors/RCTJSCExecutor.m
@@ -23,6 +23,7 @@
 #import "RCTPerformanceLogger.h"
 #import "RCTUtils.h"
 #import "RCTJSCProfiler.h"
+#import "RCTBundleURLProcessor.h"
 
 static NSString *const RCTJSCProfilerEnabledDefaultsKey = @"RCTJSCProfilerEnabled";
 static NSString *const RCTHotLoadingEnabledDefaultsKey = @"RCTHotLoadingEnabled";
@@ -146,9 +147,20 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
 
 static void RCTInstallHotLoading(RCTBridge *bridge, RCTJSCExecutor *executor)
 {
-  [bridge.devMenu addItem:[RCTDevMenuItem toggleItemWithKey:RCTHotLoadingEnabledDefaultsKey title:@"Enable Hot Loading" selectedTitle:@"Disable Hot Loading" handler:^(BOOL enabled) {
+  [bridge.devMenu addItem:[RCTDevMenuItem toggleItemWithKey:RCTHotLoadingEnabledDefaultsKey title:@"Enable Hot Loading" selectedTitle:@"Disable Hot Loading" handler:^(BOOL enabledOnCurrentBundle) {
     [executor executeBlockOnJavaScriptQueue:^{
-      [bridge enqueueJSCall:@"HMRClient.setEnabled" args:@[enabled ? @YES : @NO]];
+      NSString *enabledQS = [[RCTBundleURLProcessor sharedProcessor] getQueryStringValue:@"hot"];
+      BOOL enabledOnConfig = (enabledQS != nil && [enabledQS isEqualToString:@"true"]) ? YES : NO;
+
+      // reload bundle when user change Hot Loading setting
+      if (enabledOnConfig != enabledOnCurrentBundle) {
+        [[RCTBundleURLProcessor sharedProcessor] setQueryStringValue:enabledOnCurrentBundle ? @"true" : @"false" forAttribute:@"hot"];
+        [bridge reload];
+      }
+
+      if (enabledOnCurrentBundle) {
+        [bridge enqueueJSCall:@"HMRClient.enable" args:@[@YES]];
+      }
     }];
   }]];
 }
diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js
index 9554f0ff0901..bca1fe41b8d9 100644
--- a/local-cli/server/util/attachHMRServer.js
+++ b/local-cli/server/util/attachHMRServer.js
@@ -14,6 +14,11 @@
  */
 function attachHMRServer({httpServer, path, packagerServer}) {
   let activeWS;
+
+  function disconnect() {
+    activeWS = null;
+  }
+
   packagerServer.addFileChangeListener(filename => {
     if (!activeWS) {
       return;
@@ -40,12 +45,10 @@ function attachHMRServer({httpServer, path, packagerServer}) {
 
     ws.on('error', e => {
       console.error('[Hot Module Replacement] Unexpected error', e);
+      disconnect();
     });
 
-    ws.on('close', () => {
-      console.log('[Hot Module Replacement] Client disconnected');
-      activeWS = null;
-    });
+    ws.on('close', () => disconnect());
   });
 }
 
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index 87e97d06142e..a2fd93be44b4 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -137,7 +137,7 @@ class Bundler {
     this._assetServer = opts.assetServer;
 
     if (opts.getTransformOptionsModulePath) {
-      this._getTransformOptions = require(opts.getTransformOptionsModulePath);
+      this._getTransformOptionsModule = require(opts.getTransformOptionsModulePath);
     }
   }
 
@@ -158,6 +158,7 @@ class Bundler {
     dev: isDev,
     platform,
     unbundle: isUnbundle,
+    hot: hot,
   }) {
     // Const cannot have the same name as the method (babel/babel#2834)
     const bbundle = new Bundle(sourceMapUrl);
@@ -194,7 +195,8 @@ class Bundler {
             bbundle,
             response,
             module,
-            platform
+            platform,
+            hot,
           ).then(transformed => {
             if (bar) {
               bar.tick();
@@ -286,12 +288,16 @@ class Bundler {
 
       return Promise.all([
         module.getName(),
-        this._transformer.loadFileAndTransform(path.resolve(entryFile)),
+        this._transformer.loadFileAndTransform(
+          path.resolve(entryFile),
+          // TODO(martinb): pass non null main (t9527509)
+          this._getTransformOptions({main: null}, {hot: true}),
+        ),
       ]).then(([moduleName, transformedSource]) => {
         return (`
           __accept(
-            '${moduleName}', 
-            function(global, require, module, exports) { 
+            '${moduleName}',
+            function(global, require, module, exports) {
               ${transformedSource.code}
             }
           );
@@ -340,7 +346,7 @@ class Bundler {
     );
   }
 
-  _transformModule(bundle, response, module, platform = null) {
+  _transformModule(bundle, response, module, platform = null, hot = false) {
     if (module.isAsset_DEPRECATED()) {
       return this.generateAssetModule_DEPRECATED(bundle, module);
     } else if (module.isAsset()) {
@@ -350,8 +356,10 @@ class Bundler {
     } else {
       return this._transformer.loadFileAndTransform(
         path.resolve(module.path),
-        this._getTransformOptions ?
-          this._getTransformOptions({bundle, module, platform}) : {}
+        this._getTransformOptions(
+          {bundleEntry: bundle.getMainModuleId(), modulePath: module.path},
+          {hot: hot},
+        ),
       );
     }
   }
@@ -445,6 +453,14 @@ class Bundler {
       });
     });
   }
+
+  _getTransformOptions(config, options) {
+    const transformerOptions = this._getTransformOptionsModule
+      ? this._getTransformOptionsModule(config)
+      : null;
+
+    return {...options, ...transformerOptions};
+  }
 }
 
 function generateJSONModule(module) {
diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index 8e8dd315c529..be7e8a5ebbfb 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -89,6 +89,7 @@ class Resolver {
         // should work after this release and we can
         // remove it from here.
         'parse',
+        'react-transform-hmr',
       ],
       platforms: ['ios', 'android'],
       fileWatcher: opts.fileWatcher,
diff --git a/packager/react-packager/src/Resolver/polyfills/require.js b/packager/react-packager/src/Resolver/polyfills/require.js
index 73e54e5969de..022a4831ab1a 100644
--- a/packager/react-packager/src/Resolver/polyfills/require.js
+++ b/packager/react-packager/src/Resolver/polyfills/require.js
@@ -16,7 +16,7 @@
         hot: {
           acceptCallback: null,
           accept: function(callback) {
-            this.acceptCallback = callback;
+            modules[id].module.hot.acceptCallback = callback;
           }
         }
       });
@@ -97,12 +97,28 @@
   if (__DEV__) { // HMR
     function accept(id, factory) {
       var mod = modules[id];
+
+      if (!mod) {
+        console.error(
+          'Cannot accept unknown module `' + id + '`. Make sure you\'re not ' +
+          'trying to modify something else other than a module ' +
+          '(i.e.: a polyfill).'
+        );
+      }
+
+      if (!mod.module.hot) {
+        console.error(
+          'Cannot accept module because Hot Module Replacement ' +
+          'API was not installed.'
+        );
+      }
+
       if (mod.module.hot.acceptCallback) {
         mod.factory = factory;
         mod.isInitialized = false;
         require(id);
 
-        mod.hot.acceptCallback();
+        mod.module.hot.acceptCallback();
       } else {
         console.log(
           '[HMR] Module `' + id + '` cannot be accepted. ' +
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index 668d38782cbe..915203958d50 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -109,7 +109,11 @@ const bundleOpts = declareOpts({
   unbundle: {
     type: 'boolean',
     default: false,
-  }
+  },
+  hot: {
+    type: 'boolean',
+    default: false,
+  },
 });
 
 const hmrBundleOpts = declareOpts({
@@ -501,6 +505,7 @@ class Server {
       entryFile: entryFile,
       dev: this._getBoolOptionFromQuery(urlObj.query, 'dev', true),
       minify: this._getBoolOptionFromQuery(urlObj.query, 'minify'),
+      hot: this._getBoolOptionFromQuery(urlObj.query, 'hot', false),
       runModule: this._getBoolOptionFromQuery(urlObj.query, 'runModule', true),
       inlineSourceMap: this._getBoolOptionFromQuery(
         urlObj.query,

From e43e2146d9c8efbd4eee9ba5d3ec54d8dda2b52e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Mon, 28 Dec 2015 16:43:22 -0800
Subject: [PATCH 0529/1411] Gate Hot Loading

Summary:
public

Until we support this fature on OSS, don't show the menu option.

Reviewed By: vjeux

Differential Revision: D2791198

fb-gh-sync-id: 11b66d467c1ab784bbf549b893d0a3abd69e2741
---
 React/Base/RCTBridgeDelegate.h                              | 6 ++++++
 React/Executors/RCTJSCExecutor.m                            | 5 ++++-
 packager/react-packager/src/Server/__tests__/Server-test.js | 4 ++++
 3 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/React/Base/RCTBridgeDelegate.h b/React/Base/RCTBridgeDelegate.h
index d8606c8d953a..4c1a52f091da 100644
--- a/React/Base/RCTBridgeDelegate.h
+++ b/React/Base/RCTBridgeDelegate.h
@@ -47,4 +47,10 @@ typedef void (^RCTSourceLoadBlock)(NSError *error, NSData *source);
 - (void)loadSourceForBridge:(RCTBridge *)bridge
                   withBlock:(RCTSourceLoadBlock)loadCallback;
 
+/**
+ * Indicates wheather Hot Loading is supported or not.
+ * Note this method will get removed soon, once we support Hot Loading on OSS.
+ */
+- (BOOL)isHotLoadingEnabled;
+
 @end
diff --git a/React/Executors/RCTJSCExecutor.m b/React/Executors/RCTJSCExecutor.m
index b46886133fea..2adcdbb01493 100644
--- a/React/Executors/RCTJSCExecutor.m
+++ b/React/Executors/RCTJSCExecutor.m
@@ -318,7 +318,10 @@ - (void)setUp
     };
 
     RCTInstallJSCProfiler(_bridge, strongSelf->_context.ctx);
-    RCTInstallHotLoading(_bridge, strongSelf);
+
+    if ([self.bridge.delegate respondsToSelector:@selector(isHotLoadingEnabled)] && [self.bridge.delegate isHotLoadingEnabled]) {
+      RCTInstallHotLoading(_bridge, strongSelf);
+    }
 
     for (NSString *event in @[RCTProfileDidStartProfiling, RCTProfileDidEndProfiling]) {
       [[NSNotificationCenter defaultCenter] addObserver:strongSelf
diff --git a/packager/react-packager/src/Server/__tests__/Server-test.js b/packager/react-packager/src/Server/__tests__/Server-test.js
index 2fdb5e73845d..107f275034f4 100644
--- a/packager/react-packager/src/Server/__tests__/Server-test.js
+++ b/packager/react-packager/src/Server/__tests__/Server-test.js
@@ -110,6 +110,7 @@ describe('processRequest', () => {
         entryFile: 'index.ios.js',
         inlineSourceMap: false,
         minify: false,
+        hot: false,
         runModule: true,
         sourceMapUrl: 'index.ios.includeRequire.map',
         dev: true,
@@ -130,6 +131,7 @@ describe('processRequest', () => {
         entryFile: 'index.js',
         inlineSourceMap: false,
         minify: false,
+        hot: false,
         runModule: true,
         sourceMapUrl: 'index.map?platform=ios',
         dev: true,
@@ -272,6 +274,7 @@ describe('processRequest', () => {
           entryFile: 'foo file',
           inlineSourceMap: false,
           minify: false,
+          hot: false,
           runModule: true,
           dev: true,
           platform: undefined,
@@ -290,6 +293,7 @@ describe('processRequest', () => {
             entryFile: 'path/to/foo.js',
             inlineSourceMap: false,
             minify: false,
+            hot: false,
             runModule: false,
             sourceMapUrl: '/path/to/foo.map?dev=false&runModule=false',
             dev: false,

From 33d6293c607340836372201b0e7b26d7bddba0c8 Mon Sep 17 00:00:00 2001
From: Brent Vatne <brentvatne@gmail.com>
Date: Mon, 28 Dec 2015 17:51:30 -0800
Subject: [PATCH 0530/1411] Update KnownIssues.md

---
 docs/KnownIssues.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/docs/KnownIssues.md b/docs/KnownIssues.md
index 127cba3702d3..e0fa28958246 100644
--- a/docs/KnownIssues.md
+++ b/docs/KnownIssues.md
@@ -26,6 +26,7 @@ ART
 Maps
 Modal
 Spinner (http://developer.android.com/guide/topics/ui/controls/spinner.html)
+Slider (known as SeekBar)
 ```
 
 #### Modules

From 52b248426ece4593ff89964a3ad41c08b9d956f3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Tue, 29 Dec 2015 09:10:22 -0800
Subject: [PATCH 0531/1411] Fix Shrinkwrap & package.json

Reviewed By: vjeux

Differential Revision: D2791699

fb-gh-sync-id: 180687718ded0f4c4078ccf56ca0eb114966c8bf
---
 npm-shrinkwrap.json | 133 +++++++++++++++++++++++++++++++-------------
 package.json        |   4 +-
 2 files changed, 96 insertions(+), 41 deletions(-)

diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index 96c371e0f30a..59e358b96610 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -156,15 +156,15 @@
           "from": "js-tokens@1.0.1",
           "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
         },
-        "recast": {
-          "version": "0.10.33",
-          "from": "recast@0.10.33",
-          "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
-        },
         "regenerator": {
           "version": "0.8.40",
           "from": "regenerator@0.8.40",
           "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
+        },
+        "recast": {
+          "version": "0.10.33",
+          "from": "recast@0.10.33",
+          "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
         }
       }
     },
@@ -284,16 +284,16 @@
           "from": "globals@>=6.4.0 <7.0.0",
           "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
         },
-        "recast": {
-          "version": "0.10.33",
-          "from": "recast@0.10.33",
-          "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
-        },
         "js-tokens": {
           "version": "1.0.1",
           "from": "js-tokens@1.0.1",
           "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
         },
+        "recast": {
+          "version": "0.10.33",
+          "from": "recast@0.10.33",
+          "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
+        },
         "regenerator": {
           "version": "0.8.40",
           "from": "regenerator@0.8.40",
@@ -386,14 +386,14 @@
           "version": "6.1.18",
           "from": "babel-template@>=6.1.18 <7.0.0"
         },
-        "babel-code-frame": {
-          "version": "6.1.18",
-          "from": "babel-code-frame@>=6.1.18 <7.0.0"
-        },
         "babel-messages": {
           "version": "6.1.18",
           "from": "babel-messages@>=6.1.18 <7.0.0"
         },
+        "babel-code-frame": {
+          "version": "6.1.18",
+          "from": "babel-code-frame@>=6.1.18 <7.0.0"
+        },
         "babel-traverse": {
           "version": "6.1.20",
           "from": "babel-traverse@>=6.1.18 <7.0.0"
@@ -468,6 +468,18 @@
       "from": "babel-plugin-react-display-name@>=1.0.3 <2.0.0",
       "resolved": "https://registry.npmjs.org/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz"
     },
+    "babel-plugin-react-transform": {
+      "version": "2.0.0-beta1",
+      "from": "babel-plugin-react-transform@2.0.0-beta1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-react-transform/-/babel-plugin-react-transform-2.0.0-beta1.tgz",
+      "dependencies": {
+        "array-find": {
+          "version": "1.0.0",
+          "from": "array-find@>=1.0.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/array-find/-/array-find-1.0.0.tgz"
+        }
+      }
+    },
     "babel-plugin-remove-console": {
       "version": "1.0.1",
       "from": "babel-plugin-remove-console@>=1.0.1 <2.0.0",
@@ -1840,16 +1852,16 @@
           "from": "ansi@~0.3.0",
           "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.0.tgz"
         },
-        "ansi-regex": {
-          "version": "2.0.0",
-          "from": "ansi-regex@^2.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
-        },
         "ansi-styles": {
           "version": "2.1.0",
           "from": "ansi-styles@^2.1.0",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz"
         },
+        "ansi-regex": {
+          "version": "2.0.0",
+          "from": "ansi-regex@^2.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
+        },
         "are-we-there-yet": {
           "version": "1.0.4",
           "from": "are-we-there-yet@~1.0.0",
@@ -1920,16 +1932,16 @@
           "from": "concat-map@0.0.1",
           "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
         },
-        "core-util-is": {
-          "version": "1.0.1",
-          "from": "core-util-is@~1.0.0",
-          "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-        },
         "cryptiles": {
           "version": "2.0.5",
           "from": "cryptiles@2.x.x",
           "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz"
         },
+        "core-util-is": {
+          "version": "1.0.1",
+          "from": "core-util-is@~1.0.0",
+          "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
+        },
         "ctype": {
           "version": "0.5.3",
           "from": "ctype@0.5.3",
@@ -1955,16 +1967,16 @@
           "from": "delegates@^0.1.0",
           "resolved": "https://registry.npmjs.org/delegates/-/delegates-0.1.0.tgz"
         },
-        "escape-string-regexp": {
-          "version": "1.0.3",
-          "from": "escape-string-regexp@^1.0.2",
-          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz"
-        },
         "extend": {
           "version": "3.0.0",
           "from": "extend@~3.0.0",
           "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz"
         },
+        "escape-string-regexp": {
+          "version": "1.0.3",
+          "from": "escape-string-regexp@^1.0.2",
+          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz"
+        },
         "forever-agent": {
           "version": "0.6.1",
           "from": "forever-agent@~0.6.1",
@@ -2150,16 +2162,16 @@
           "from": "path-is-absolute@>=1.0.0 <2.0.0",
           "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz"
         },
-        "pinkie": {
-          "version": "1.0.0",
-          "from": "pinkie@^1.0.0",
-          "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
-        },
         "pinkie-promise": {
           "version": "1.0.0",
           "from": "pinkie-promise@^1.0.0",
           "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz"
         },
+        "pinkie": {
+          "version": "1.0.0",
+          "from": "pinkie@^1.0.0",
+          "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
+        },
         "qs": {
           "version": "5.2.0",
           "from": "qs@~5.2.0",
@@ -2175,11 +2187,6 @@
           "from": "request@2.x",
           "resolved": "https://registry.npmjs.org/request/-/request-2.65.0.tgz"
         },
-        "semver": {
-          "version": "5.0.3",
-          "from": "semver@~5.0.1",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
-        },
         "sntp": {
           "version": "1.0.9",
           "from": "sntp@1.x.x",
@@ -2195,6 +2202,11 @@
           "from": "stringstream@~0.0.4",
           "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
         },
+        "semver": {
+          "version": "5.0.3",
+          "from": "semver@~5.0.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
+        },
         "strip-ansi": {
           "version": "3.0.0",
           "from": "strip-ansi@^3.0.0",
@@ -4153,6 +4165,49 @@
       "from": "react-timer-mixin@>=0.13.1 <0.14.0",
       "resolved": "https://registry.npmjs.org/react-timer-mixin/-/react-timer-mixin-0.13.2.tgz"
     },
+    "react-transform-hmr": {
+      "version": "1.0.1",
+      "from": "react-transform-hmr@1.0.1",
+      "resolved": "https://registry.npmjs.org/react-transform-hmr/-/react-transform-hmr-1.0.1.tgz",
+      "dependencies": {
+        "global": {
+          "version": "4.3.0",
+          "from": "global@>=4.3.0 <5.0.0",
+          "resolved": "https://registry.npmjs.org/global/-/global-4.3.0.tgz",
+          "dependencies": {
+            "min-document": {
+              "version": "2.17.0",
+              "from": "min-document@>=2.6.1 <3.0.0",
+              "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.17.0.tgz",
+              "dependencies": {
+                "dom-walk": {
+                  "version": "0.1.1",
+                  "from": "dom-walk@>=0.1.0 <0.2.0",
+                  "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz"
+                }
+              }
+            },
+            "process": {
+              "version": "0.5.2",
+              "from": "process@>=0.5.1 <0.6.0",
+              "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz"
+            }
+          }
+        },
+        "react-proxy": {
+          "version": "1.1.1",
+          "from": "react-proxy@>=1.1.1 <2.0.0",
+          "resolved": "https://registry.npmjs.org/react-proxy/-/react-proxy-1.1.1.tgz",
+          "dependencies": {
+            "react-deep-force-update": {
+              "version": "1.0.0",
+              "from": "react-deep-force-update@>=1.0.0 <2.0.0",
+              "resolved": "https://registry.npmjs.org/react-deep-force-update/-/react-deep-force-update-1.0.0.tgz"
+            }
+          }
+        }
+      }
+    },
     "read-pkg": {
       "version": "1.1.0",
       "from": "read-pkg@>=1.0.0 <2.0.0",
diff --git a/package.json b/package.json
index 5e5e4ff1a705..fd6062f65ee3 100644
--- a/package.json
+++ b/package.json
@@ -99,7 +99,7 @@
     "joi": "^6.6.1",
     "json5": "^0.4.0",
     "jstransform": "^11.0.3",
-    "mkdirp": "^0.5.0",
+    "mkdirp": "^0.5.1",
     "module-deps": "^3.9.1",
     "node-fetch": "^1.3.3",
     "opn": "^3.0.2",
@@ -111,7 +111,7 @@
     "rebound": "^0.0.13",
     "regenerator": "^0.8.36",
     "sane": "^1.2.0",
-    "semver": "^5.0.1",
+    "semver": "^5.0.3",
     "source-map": "^0.4.4",
     "stacktrace-parser": "^0.1.3",
     "uglify-js": "^2.4.24",

From 4963225295d22a9c5aaa30e1fc51292652c78b02 Mon Sep 17 00:00:00 2001
From: Adam Miskiewicz <adam.skevy@mac.com>
Date: Tue, 29 Dec 2015 12:42:49 -0500
Subject: [PATCH 0532/1411] [Website] Fixing JS error

---
 website/src/react-native/js/scripts.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/js/scripts.js b/website/src/react-native/js/scripts.js
index 85e92a78c3bd..9bed77965b3c 100644
--- a/website/src/react-native/js/scripts.js
+++ b/website/src/react-native/js/scripts.js
@@ -8,6 +8,8 @@
 
   function init() {
     var backdrop = document.querySelector('.modal-backdrop');
+    if (!backdrop) return;
+
     var modalButtonOpenList = document.querySelectorAll('.modal-button-open');
     var modalButtonClose = document.querySelector('.modal-button-close');
 
@@ -22,6 +24,8 @@
 
   function showModal(e) {
     var backdrop = document.querySelector('.modal-backdrop');
+    if (!backdrop) return;
+
     var modal = document.querySelector('.modal');
 
     backdrop.classList.add('modal-open');
@@ -30,6 +34,8 @@
 
   function hideModal(e) {
     var backdrop = document.querySelector('.modal-backdrop');
+    if (!backdrop) return;
+
     var modal = document.querySelector('.modal');
 
     backdrop.classList.remove('modal-open');

From cc1bad54ea83d9e8b7df8ca74f120c007c152c2c Mon Sep 17 00:00:00 2001
From: Adam Miskiewicz <adam.skevy@mac.com>
Date: Tue, 29 Dec 2015 12:43:40 -0500
Subject: [PATCH 0533/1411] [Website] First pass at Algolia Doc Search
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

It’s not yet responsive :(
---
 website/core/AlgoliaDocSearch.js              |  22 ++++
 website/core/HeaderLinks.js                   |   4 +
 website/core/Site.js                          |   3 +
 website/src/react-native/css/react-native.css |  94 ++++++++++++++++++
 website/src/react-native/img/search.png       | Bin 0 -> 1378 bytes
 website/src/react-native/js/scripts.js        |   7 ++
 6 files changed, 130 insertions(+)
 create mode 100644 website/core/AlgoliaDocSearch.js
 create mode 100644 website/src/react-native/img/search.png

diff --git a/website/core/AlgoliaDocSearch.js b/website/core/AlgoliaDocSearch.js
new file mode 100644
index 000000000000..b65e7e303bb4
--- /dev/null
+++ b/website/core/AlgoliaDocSearch.js
@@ -0,0 +1,22 @@
+/**
+ * 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 AlgoliaDocSearch
+ */
+
+var AlgoliaDocSearch = React.createClass({
+  render: function() {
+    return (
+      <div className="algolia-search-wrapper">
+        <input id="algolia-doc-search" type="text" placeholder="Search docs..." />
+      </div>
+    );
+  }
+});
+
+module.exports = AlgoliaDocSearch;
diff --git a/website/core/HeaderLinks.js b/website/core/HeaderLinks.js
index c70b3c92d4be..afee22f2406b 100644
--- a/website/core/HeaderLinks.js
+++ b/website/core/HeaderLinks.js
@@ -10,6 +10,7 @@
  */
 
 var React = require('React');
+var AlgoliaDocSearch = require('AlgoliaDocSearch');
 
 var HeaderLinks = React.createClass({
   linksInternal: [
@@ -44,6 +45,9 @@ var HeaderLinks = React.createClass({
         <ul className="nav-site nav-site-internal">
           {this.makeLinks(this.linksInternal)}
         </ul>
+
+        <AlgoliaDocSearch />
+
         <ul className="nav-site nav-site-external">
           {this.makeLinks(this.linksExternal)}
         </ul>
diff --git a/website/core/Site.js b/website/core/Site.js
index e855a9666a78..eface427c5bb 100644
--- a/website/core/Site.js
+++ b/website/core/Site.js
@@ -29,6 +29,8 @@ var Site = React.createClass({
           <meta property="og:image" content="http://facebook.github.io/react-native/img/opengraph.png?2" />
           <meta property="og:description" content="A framework for building native apps using React" />
 
+          <link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.css" />
+
           <link rel="shortcut icon" href="/react-native/img/favicon.png?2" />
           <link rel="stylesheet" href="/react-native/css/react-native.css" />
 
@@ -68,6 +70,7 @@ var Site = React.createClass({
             ){js=d.createElement(s);js.id=id;js.src="https://platform.twitter.com/widgets.js";
             fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");
           `}} />
+          <script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.js"></script>
           <script src="/react-native/js/scripts.js" />
         </body>
       </html>
diff --git a/website/src/react-native/css/react-native.css b/website/src/react-native/css/react-native.css
index e9d22d1b4f7e..a08f351d6bde 100644
--- a/website/src/react-native/css/react-native.css
+++ b/website/src/react-native/css/react-native.css
@@ -1222,3 +1222,97 @@ div[data-twttr-id] iframe {
   }
 }
 
+/** Algolia Doc Search **/
+
+
+div.algolia-search-wrapper {
+  display: inline-block;
+  vertical-align: top;
+  margin-left: 15px;
+}
+
+@media screen and (max-width: 960px) {
+  div.algolia-search-wrapper {
+    display: none;
+  }
+}
+
+input#algolia-doc-search {
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-family: proxima-nova, "Helvetica Neue", Helvetica, Arial, sans-serif;
+
+  background: transparent url('/react-native/img/search.png') no-repeat left center;
+  background-size: 16px 16px;
+
+  padding-left: 30px;
+  font-size: 16px;
+  line-height: 20px;
+  background-color: #3B3738;
+  border-bottom: solid 3px #3B3738;
+  color: white;
+  outline: none;
+  width: 130px;
+  height: 53px;
+
+  transition: border-color .2s ease, width .2s ease;
+  -webkit-transition: border-color .2s ease, width .2s ease;
+  -moz-transition: border-color .2s ease, width .2s ease;
+  -o-transition: border-color .2s ease, width .2s ease;
+}
+
+input#algolia-doc-search:focus {
+  border-color: #05A5D1;
+  width: 240px;
+}
+
+@media screen and (max-width: 1085px) {
+  input#algolia-doc-search:focus {
+    width: 178px;
+  }
+}
+
+.algolia-autocomplete {
+  vertical-align: top;
+  height: 53px;
+
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-family: proxima-nova, "Helvetica Neue", Helvetica, Arial, sans-serif;
+}
+
+/* Bottom border of each suggestion */
+.algolia-docsearch-suggestion {
+  border-bottom-color: #05A5D1;
+}
+/* Main category headers */
+.algolia-docsearch-suggestion--category-header {
+  background-color: #3B3738;
+}
+/* Highlighted search terms */
+.algolia-docsearch-suggestion--highlight {
+  color: #05A5D1;
+}
+/* Highligted search terms in the main category headers */
+.algolia-docsearch-suggestion--category-header .algolia-docsearch-suggestion--highlight  {
+  background-color: #05A5D1;
+}
+/* Currently selected suggestion */
+.aa-cursor .algolia-docsearch-suggestion--content {
+  color: #05A5D1;
+}
+.aa-cursor .algolia-docsearch-suggestion {
+  background: hsl(198, 100%, 96%);
+}
+
+/* For bigger screens, when displaying results in two columns */
+@media (min-width: 768px) {
+  /* Bottom border of each suggestion */
+  .algolia-docsearch-suggestion {
+    border-bottom-color: hsl(198, 100%, 94%);
+  }
+  /* Left column, with secondary category header */
+  .algolia-docsearch-suggestion--subcategory-column {
+    border-right-color: hsl(198, 100%, 94%);
+    background-color: hsl(198, 100%, 96%);
+    color: #3B3738;
+  }
+}
diff --git a/website/src/react-native/img/search.png b/website/src/react-native/img/search.png
new file mode 100644
index 0000000000000000000000000000000000000000..222fb660dae6c3cb2bba7502f64e61dd84ce1044
GIT binary patch
diff --git a/website/src/react-native/js/scripts.js b/website/src/react-native/js/scripts.js
index 9bed77965b3c..8e3d9d440a70 100644
--- a/website/src/react-native/js/scripts.js
+++ b/website/src/react-native/js/scripts.js
@@ -42,4 +42,11 @@
     modal.classList.remove('modal-open');
   }
 
+  // Algolia
+  docsearch({
+    apiKey: 'e3d767b736584dbe6d4c35f7cf7d4633',
+    indexName: 'react-native',
+    inputSelector: '#algolia-doc-search'
+  });
+
 }());

From 041b1c5e5297ce0d4807fbfae927d2d8599aa732 Mon Sep 17 00:00:00 2001
From: Martin Bigio <martinb@fb.com>
Date: Tue, 29 Dec 2015 11:04:45 -0800
Subject: [PATCH 0534/1411] Add `RCTBundleURLProcessor` files to Xcode project

Summary: Closes https://github.com/facebook/react-native/pull/5028

Reviewed By: svcscm

Differential Revision: D2793266

Pulled By: martinbigio

fb-gh-sync-id: 6d9ca5bf0391a47d25948ce29282f21c0930db3a
---
 React/React.xcodeproj/project.pbxproj | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj
index 35a7a346bb88..141bed35aa22 100644
--- a/React/React.xcodeproj/project.pbxproj
+++ b/React/React.xcodeproj/project.pbxproj
@@ -70,6 +70,7 @@
 		14F484561AABFCE100FDF6B9 /* RCTSliderManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F484551AABFCE100FDF6B9 /* RCTSliderManager.m */; };
 		14F7A0EC1BDA3B3C003C6C10 /* RCTPerfMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F7A0EB1BDA3B3C003C6C10 /* RCTPerfMonitor.m */; };
 		14F7A0F01BDA714B003C6C10 /* RCTFPSGraph.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F7A0EF1BDA714B003C6C10 /* RCTFPSGraph.m */; };
+		1BCBD4A71C32FA0B006FC476 /* RCTBundleURLProcessor.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BCBD4A61C32FA0B006FC476 /* RCTBundleURLProcessor.m */; };
 		58114A161AAE854800E7D092 /* RCTPicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A131AAE854800E7D092 /* RCTPicker.m */; };
 		58114A171AAE854800E7D092 /* RCTPickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A151AAE854800E7D092 /* RCTPickerManager.m */; };
 		58114A501AAE93D500E7D092 /* RCTAsyncLocalStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A4E1AAE93D500E7D092 /* RCTAsyncLocalStorage.m */; };
@@ -242,6 +243,8 @@
 		14F7A0EB1BDA3B3C003C6C10 /* RCTPerfMonitor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPerfMonitor.m; sourceTree = "<group>"; };
 		14F7A0EE1BDA714B003C6C10 /* RCTFPSGraph.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTFPSGraph.h; sourceTree = "<group>"; };
 		14F7A0EF1BDA714B003C6C10 /* RCTFPSGraph.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTFPSGraph.m; sourceTree = "<group>"; };
+		1BCBD4A51C32FA0B006FC476 /* RCTBundleURLProcessor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBundleURLProcessor.h; sourceTree = "<group>"; };
+		1BCBD4A61C32FA0B006FC476 /* RCTBundleURLProcessor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBundleURLProcessor.m; sourceTree = "<group>"; };
 		58114A121AAE854800E7D092 /* RCTPicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPicker.h; sourceTree = "<group>"; };
 		58114A131AAE854800E7D092 /* RCTPicker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPicker.m; sourceTree = "<group>"; };
 		58114A141AAE854800E7D092 /* RCTPickerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPickerManager.h; sourceTree = "<group>"; };
@@ -513,6 +516,8 @@
 				83CBBA651A601EF300E9B192 /* RCTEventDispatcher.h */,
 				83CBBA661A601EF300E9B192 /* RCTEventDispatcher.m */,
 				1436DD071ADE7AA000A5ED7D /* RCTFrameUpdate.h */,
+				1BCBD4A51C32FA0B006FC476 /* RCTBundleURLProcessor.h */,
+				1BCBD4A61C32FA0B006FC476 /* RCTBundleURLProcessor.m */,
 				14C2CA751B3AC64F00E6CBB2 /* RCTFrameUpdate.m */,
 				83CBBA4C1A601E3B00E9B192 /* RCTInvalidating.h */,
 				83CBBA631A601ECA00E9B192 /* RCTJavaScriptExecutor.h */,
@@ -672,6 +677,7 @@
 				13E41EEB1C05CA0B00CD8DAC /* RCTProfileTrampoline-i386.S in Sources */,
 				13B080061A6947C200A75B9A /* RCTScrollViewManager.m in Sources */,
 				14200DAA1AC179B3008EE6BA /* RCTJavaScriptLoader.m in Sources */,
+				1BCBD4A71C32FA0B006FC476 /* RCTBundleURLProcessor.m in Sources */,
 				137327EA1AA5CF210034F82E /* RCTTabBarManager.m in Sources */,
 				13B080261A694A8400A75B9A /* RCTWrapperViewController.m in Sources */,
 				13B080051A6947C200A75B9A /* RCTScrollView.m in Sources */,

From d1864fa43613bac18b55aaa8b2970bd411bb6657 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Tue, 29 Dec 2015 11:35:48 -0800
Subject: [PATCH 0535/1411] Improve error wording

Reviewed By: frantic

Differential Revision: D2793300

fb-gh-sync-id: f3f9403ee332d193b8a6c4a6dfb89d636dc48875
---
 packager/react-packager/src/Resolver/polyfills/require.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/packager/react-packager/src/Resolver/polyfills/require.js b/packager/react-packager/src/Resolver/polyfills/require.js
index 022a4831ab1a..15f8cf551484 100644
--- a/packager/react-packager/src/Resolver/polyfills/require.js
+++ b/packager/react-packager/src/Resolver/polyfills/require.js
@@ -121,8 +121,8 @@
         mod.module.hot.acceptCallback();
       } else {
         console.log(
-          '[HMR] Module `' + id + '` cannot be accepted. ' +
-          'Please reload bundle to get the updates.'
+          '[HMR] Module `' + id + '` can\'t be hot reloaded because it ' +
+          'doesn\'t provide accept callback hook. Reload the app to get the updates.'
         );
       }
     }

From fef01ed394da7548b96f7b01c3bf268a94651c22 Mon Sep 17 00:00:00 2001
From: Brent Vatne <brentvatne@gmail.com>
Date: Tue, 29 Dec 2015 12:41:34 -0800
Subject: [PATCH 0536/1411] ScrollWithouth => ScrollWithout

Summary:
Oops!
Closes https://github.com/facebook/react-native/pull/5029

Reviewed By: svcscm

Differential Revision: D2793490

Pulled By: vjeux

fb-gh-sync-id: 0115d3ef38cad3e838241937263308827e56f25f
---
 Libraries/Components/ScrollResponder.js       | 2 +-
 Libraries/Components/ScrollView/ScrollView.js | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Libraries/Components/ScrollResponder.js b/Libraries/Components/ScrollResponder.js
index 3374cf22d53e..d6e7f6150ba8 100644
--- a/Libraries/Components/ScrollResponder.js
+++ b/Libraries/Components/ScrollResponder.js
@@ -370,7 +370,7 @@ var ScrollResponderMixin = {
    * Like `scrollResponderScrollTo` but immediately scrolls to the given
    * position
    */
-  scrollResponderScrollWithouthAnimationTo: function(offsetX: number, offsetY: number) {
+  scrollResponderScrollWithoutAnimationTo: function(offsetX: number, offsetY: number) {
     if (Platform.OS === 'android') {
       UIManager.dispatchViewManagerCommand(
         React.findNodeHandle(this),
diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js
index a23b0a248fe8..870044ecaa13 100644
--- a/Libraries/Components/ScrollView/ScrollView.js
+++ b/Libraries/Components/ScrollView/ScrollView.js
@@ -346,7 +346,7 @@ var ScrollView = React.createClass({
 
   scrollWithoutAnimationTo: function(destY?: number, destX?: number) {
     // $FlowFixMe - Don't know how to pass Mixin correctly. Postpone for now
-    this.getScrollResponder().scrollResponderScrollWithouthAnimationTo(
+    this.getScrollResponder().scrollResponderScrollWithoutAnimationTo(
       destX || 0,
       destY || 0,
     );

From 5f850fbede20202167561c1d73662d48f58af29a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Tue, 29 Dec 2015 18:24:06 -0800
Subject: [PATCH 0537/1411] Pipe `platform` and `bundleEntry` through WebSocket
 connection

Reviewed By: vjeux

Differential Revision: D2793572

fb-gh-sync-id: 6ce2467b8d528d1a91c1b4fc51741f2502674022
---
 Libraries/Utilities/HMRClient.js         | 12 +++++++++--
 React/Executors/RCTJSCExecutor.m         | 22 +++++++++++++------
 local-cli/server/util/attachHMRServer.js | 27 +++++++++++++++---------
 3 files changed, 42 insertions(+), 19 deletions(-)

diff --git a/Libraries/Utilities/HMRClient.js b/Libraries/Utilities/HMRClient.js
index 7ce2f24b62ed..31fad171ee68 100644
--- a/Libraries/Utilities/HMRClient.js
+++ b/Libraries/Utilities/HMRClient.js
@@ -10,12 +10,17 @@
  */
 'use strict';
 
+const invariant = require('invariant');
+
 /**
  * HMR Client that receives from the server HMR updates and propagates them
  * runtime to reflects those changes.
  */
 const HMRClient = {
-  enable() {
+  enable(platform, bundleEntry) {
+    invariant(platform, 'Missing required parameter `platform`');
+    invariant(bundleEntry, 'Missing required paramenter `bundleEntry`');
+
     // need to require WebSocket inside of `enable` function because the
     // this module is defined as a `polyfillGlobal`.
     // See `InitializeJavascriptAppEngine.js`
@@ -23,7 +28,10 @@ const HMRClient = {
 
     // TODO(martinb): parametrize the url and receive entryFile to minimize
     // the number of updates we want to receive from the server.
-    const activeWS = new WebSocket('ws://localhost:8081/hot');
+    const activeWS = new WebSocket(
+      'ws://localhost:8081/hot?platform=' + platform + '&bundleEntry=' +
+      bundleEntry.replace('.bundle', '.js')
+    );
     activeWS.onerror = (e) => {
       console.error('[Hot Module Replacement] Unexpected error', e);
     };
diff --git a/React/Executors/RCTJSCExecutor.m b/React/Executors/RCTJSCExecutor.m
index 2adcdbb01493..e808caa3ccbe 100644
--- a/React/Executors/RCTJSCExecutor.m
+++ b/React/Executors/RCTJSCExecutor.m
@@ -90,6 +90,7 @@ @implementation RCTJSCExecutor
 {
   RCTJavaScriptContext *_context;
   NSThread *_javaScriptThread;
+  NSURL *_bundleURL;
 }
 
 @synthesize valid = _valid;
@@ -145,22 +146,22 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
   }
 }
 
+static BOOL isHotLoadingEnabled()
+{
+  NSString *enabledQS = [[RCTBundleURLProcessor sharedProcessor] getQueryStringValue:@"hot"];
+  return (enabledQS != nil && [enabledQS isEqualToString:@"true"]) ? YES : NO;
+}
+
 static void RCTInstallHotLoading(RCTBridge *bridge, RCTJSCExecutor *executor)
 {
   [bridge.devMenu addItem:[RCTDevMenuItem toggleItemWithKey:RCTHotLoadingEnabledDefaultsKey title:@"Enable Hot Loading" selectedTitle:@"Disable Hot Loading" handler:^(BOOL enabledOnCurrentBundle) {
     [executor executeBlockOnJavaScriptQueue:^{
-      NSString *enabledQS = [[RCTBundleURLProcessor sharedProcessor] getQueryStringValue:@"hot"];
-      BOOL enabledOnConfig = (enabledQS != nil && [enabledQS isEqualToString:@"true"]) ? YES : NO;
-
+      BOOL enabledOnConfig = isHotLoadingEnabled();
       // reload bundle when user change Hot Loading setting
       if (enabledOnConfig != enabledOnCurrentBundle) {
         [[RCTBundleURLProcessor sharedProcessor] setQueryStringValue:enabledOnCurrentBundle ? @"true" : @"false" forAttribute:@"hot"];
         [bridge reload];
       }
-
-      if (enabledOnCurrentBundle) {
-        [bridge enqueueJSCall:@"HMRClient.enable" args:@[@YES]];
-      }
     }];
   }]];
 }
@@ -534,6 +535,13 @@ - (void)executeApplicationScript:(NSData *)script
       onComplete(error);
     }
   }), 0, @"js_call", (@{ @"url": sourceURL.absoluteString }))];
+
+  #if RCT_DEV
+  if (isHotLoadingEnabled()) {
+    // strip initial slash
+    [_bridge enqueueJSCall:@"HMRClient.enable" args:@[@"ios", [sourceURL.path substringFromIndex: 1]]];
+  }
+  #endif
 }
 
 - (void)executeBlockOnJavaScriptQueue:(dispatch_block_t)block
diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js
index bca1fe41b8d9..30c86f8f6da5 100644
--- a/local-cli/server/util/attachHMRServer.js
+++ b/local-cli/server/util/attachHMRServer.js
@@ -8,28 +8,30 @@
  */
 'use strict';
 
+const querystring = require('querystring');
+const url = require('url');
+
 /**
  * Attaches a WebSocket based connection to the Packager to expose
  * Hot Module Replacement updates to the simulator.
  */
 function attachHMRServer({httpServer, path, packagerServer}) {
-  let activeWS;
+  let client = null;
 
   function disconnect() {
-    activeWS = null;
+    client = null;
   }
 
   packagerServer.addFileChangeListener(filename => {
-    if (!activeWS) {
+    if (!client) {
       return;
     }
 
     packagerServer.buildBundleForHMR({
       entryFile: filename,
-      // TODO(martinb): receive platform on query string when client connects
-      platform: 'ios',
+      platform: client.platform,
     })
-    .then(bundle => activeWS.send(bundle));
+    .then(bundle => client.ws.send(bundle));
   });
 
   const WebSocketServer = require('ws').Server;
@@ -41,14 +43,19 @@ function attachHMRServer({httpServer, path, packagerServer}) {
   console.log('[Hot Module Replacement] Server listening on', path);
   wss.on('connection', ws => {
     console.log('[Hot Module Replacement] Client connected');
-    activeWS = ws;
-
-    ws.on('error', e => {
+    const params = querystring.parse(url.parse(ws.upgradeReq.url).query);
+    client = {
+      ws,
+      platform: params.platform,
+      bundleEntry: params.bundleEntry,
+    };
+
+    client.ws.on('error', e => {
       console.error('[Hot Module Replacement] Unexpected error', e);
       disconnect();
     });
 
-    ws.on('close', () => disconnect());
+    client.ws.on('close', () => disconnect());
   });
 }
 

From b5081abae37f8599ed8902eb8a9770d31bf168ee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Tue, 29 Dec 2015 18:24:08 -0800
Subject: [PATCH 0538/1411] Send HMR updates only for files on the bundle

Summary:
public

Compute the dependencies of the bundle entry file just before sending HMR updates. In case the file that was changed doesn't belong to the bundle bail.

Reviewed By: vjeux

Differential Revision: D2793736

fb-gh-sync-id: f858e71b0dd5fe4f5b2307a22c6cef627eb66a22
---
 local-cli/server/util/attachHMRServer.js      | 110 +++++++++++++++---
 packager/react-packager/src/Bundler/index.js  |   4 +
 .../DependencyGraph/index.js                  |   8 ++
 packager/react-packager/src/Resolver/index.js |   4 +
 packager/react-packager/src/Server/index.js   |   4 +
 5 files changed, 114 insertions(+), 16 deletions(-)

diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js
index 30c86f8f6da5..572d3792afc7 100644
--- a/local-cli/server/util/attachHMRServer.js
+++ b/local-cli/server/util/attachHMRServer.js
@@ -22,16 +22,76 @@ function attachHMRServer({httpServer, path, packagerServer}) {
     client = null;
   }
 
+  // Returns a promise with the full list of dependencies and the shallow
+  // dependencies each file on the dependency list has for the give platform
+  // and entry file.
+  function getDependencies(platform, bundleEntry) {
+    return packagerServer.getDependencies({
+      platform: platform,
+      dev: true,
+      entryFile: bundleEntry,
+    }).then(response => {
+      // for each dependency builds the object:
+      // `{path: '/a/b/c.js', deps: ['modA', 'modB', ...]}`
+      return Promise.all(Object.values(response.dependencies).map(dep => {
+        if (dep.isAsset() || dep.isAsset_DEPRECATED() || dep.isJSON()) {
+          return Promise.resolve({path: dep.path, deps: []});
+        }
+        return packagerServer.getShallowDependencies(dep.path)
+          .then(deps => {
+            return {
+              path: dep.path,
+              deps,
+            };
+          });
+      }))
+      .then(deps => {
+        // list with all the dependencies the bundle entry has
+        const dependenciesCache = response.dependencies.map(dep => dep.path);
+
+        // map that indicates the shallow dependency each file included on the
+        // bundle has
+        const shallowDependencies = {};
+        deps.forEach(dep => shallowDependencies[dep.path] = dep.deps);
+
+        return {dependenciesCache, shallowDependencies};
+      });
+    });
+  }
+
   packagerServer.addFileChangeListener(filename => {
     if (!client) {
       return;
     }
 
-    packagerServer.buildBundleForHMR({
-      entryFile: filename,
-      platform: client.platform,
-    })
-    .then(bundle => client.ws.send(bundle));
+    packagerServer.getShallowDependencies(filename)
+      .then(deps => {
+        // if the file dependencies have change we need to invalidate the
+        // dependencies caches because the list of files we need to send to the
+        // client may have changed
+        if (arrayEquals(deps, client.shallowDependencies[filename])) {
+          return Promise.resolve();
+        }
+        return getDependencies(client.platform, client.bundleEntry)
+          .then(({dependenciesCache, shallowDependencies}) => {
+            // invalidate caches
+            client.dependenciesCache = dependenciesCache;
+            client.shallowDependencies = shallowDependencies;
+          });
+      })
+      .then(() => {
+        // make sure the file was modified is part of the bundle
+        if (!client.shallowDependencies[filename]) {
+          return;
+        }
+
+        return packagerServer.buildBundleForHMR({
+          platform: client.platform,
+          entryFile: filename,
+        })
+        .then(bundle => client.ws.send(bundle));
+      })
+      .done();
   });
 
   const WebSocketServer = require('ws').Server;
@@ -44,19 +104,37 @@ function attachHMRServer({httpServer, path, packagerServer}) {
   wss.on('connection', ws => {
     console.log('[Hot Module Replacement] Client connected');
     const params = querystring.parse(url.parse(ws.upgradeReq.url).query);
-    client = {
-      ws,
-      platform: params.platform,
-      bundleEntry: params.bundleEntry,
-    };
-
-    client.ws.on('error', e => {
-      console.error('[Hot Module Replacement] Unexpected error', e);
-      disconnect();
-    });
 
-    client.ws.on('close', () => disconnect());
+    getDependencies(params.platform, params.bundleEntry)
+      .then(({dependenciesCache, shallowDependencies}) => {
+        client = {
+          ws,
+          platform: params.platform,
+          bundleEntry: params.bundleEntry,
+          dependenciesCache,
+          shallowDependencies,
+        };
+
+        client.ws.on('error', e => {
+          console.error('[Hot Module Replacement] Unexpected error', e);
+          disconnect();
+        });
+
+        client.ws.on('close', () => disconnect());
+      })
+    .done();
   });
 }
 
+function arrayEquals(arrayA, arrayB) {
+  arrayA = arrayA || [];
+  arrayB = arrayB || [];
+  return (
+    arrayA.length === arrayB.length &&
+    arrayA.every((element, index) => {
+      return element === arrayB[index];
+    })
+  );
+}
+
 module.exports = attachHMRServer;
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index a2fd93be44b4..dc76a267f589 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -310,6 +310,10 @@ class Bundler {
     this._transformer.invalidateFile(filePath);
   }
 
+  getShallowDependencies(entryFile) {
+    return this._resolver.getShallowDependencies(entryFile);
+  }
+
   getDependencies(main, isDev, platform) {
     return this._resolver.getDependencies(main, { dev: isDev, platform });
   }
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
index 69072339f2e1..ac88a2e37c99 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
@@ -133,6 +133,14 @@ class DependencyGraph {
     return this._loading;
   }
 
+  /**
+   * Returns a promise with the direct dependencies the module associated to
+   * the given entryPath has.
+   */
+  getShallowDependencies(entryPath) {
+    return this._moduleCache.getModule(entryPath).getDependencies();
+  }
+
   getDependencies(entryPath, platform) {
     return this.load().then(() => {
       platform = this._getRequestPlatform(entryPath, platform);
diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index be7e8a5ebbfb..d0f9228569f4 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -99,6 +99,10 @@ class Resolver {
     this._polyfillModuleNames = opts.polyfillModuleNames || [];
   }
 
+  getShallowDependencies(entryFile) {
+    return this._depGraph.getShallowDependencies(entryFile);
+  }
+
   getDependencies(main, options) {
     const opts = getDependenciesValidateOpts(options);
 
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index 915203958d50..a6bb6b3447be 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -246,6 +246,10 @@ class Server {
     });
   }
 
+  getShallowDependencies(entryFile) {
+    return this._bundler.getShallowDependencies(entryFile);
+  }
+
   getDependencies(options) {
     return Promise.resolve().then(() => {
       if (!options.platform) {

From e75e861116b99de0d1815ecf5eb025e125177e06 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Tue, 29 Dec 2015 18:24:10 -0800
Subject: [PATCH 0539/1411] Make Hot Loading faster

Summary:
public

Before this this when a file was changed besides sending the HMR update we rebuild every single bundle that the packager had build (to serve it faster when the user hit cmd+r). Since when hot loading is enabled we don't do cmd+r all this work was pointless (except for when you're developing multiple apps using the same packager instance at the same time, which we can assume is very uncommon). As a consequence, the HMR update was competing with the rebundling job making HMR quite slow (i.e.: on one huge internal app it took up to 6s for the HMR changes to get applied).

So, this diff tweaks the file change listener so that we don't rebundle nor invoke the fileWatchers (use for live reload which is also useless when hot load is enabled) when hot loading is enabled. Also, it makes the HMR listener more high pri than the other listeners so that the HMR dev experience is as good as it can get.

Reviewed By: vjeux

Differential Revision: D2793827

fb-gh-sync-id: 724930db9f44974c15ad3f562910b0885e44efde
---
 local-cli/server/util/attachHMRServer.js    | 70 ++++++++++-----------
 packager/react-packager/src/Server/index.js | 14 +++++
 2 files changed, 49 insertions(+), 35 deletions(-)

diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js
index 572d3792afc7..e039edef5701 100644
--- a/local-cli/server/util/attachHMRServer.js
+++ b/local-cli/server/util/attachHMRServer.js
@@ -20,6 +20,7 @@ function attachHMRServer({httpServer, path, packagerServer}) {
 
   function disconnect() {
     client = null;
+    packagerServer.setHMRFileChangeListener(null);
   }
 
   // Returns a promise with the full list of dependencies and the shallow
@@ -59,41 +60,6 @@ function attachHMRServer({httpServer, path, packagerServer}) {
     });
   }
 
-  packagerServer.addFileChangeListener(filename => {
-    if (!client) {
-      return;
-    }
-
-    packagerServer.getShallowDependencies(filename)
-      .then(deps => {
-        // if the file dependencies have change we need to invalidate the
-        // dependencies caches because the list of files we need to send to the
-        // client may have changed
-        if (arrayEquals(deps, client.shallowDependencies[filename])) {
-          return Promise.resolve();
-        }
-        return getDependencies(client.platform, client.bundleEntry)
-          .then(({dependenciesCache, shallowDependencies}) => {
-            // invalidate caches
-            client.dependenciesCache = dependenciesCache;
-            client.shallowDependencies = shallowDependencies;
-          });
-      })
-      .then(() => {
-        // make sure the file was modified is part of the bundle
-        if (!client.shallowDependencies[filename]) {
-          return;
-        }
-
-        return packagerServer.buildBundleForHMR({
-          platform: client.platform,
-          entryFile: filename,
-        })
-        .then(bundle => client.ws.send(bundle));
-      })
-      .done();
-  });
-
   const WebSocketServer = require('ws').Server;
   const wss = new WebSocketServer({
     server: httpServer,
@@ -115,6 +81,40 @@ function attachHMRServer({httpServer, path, packagerServer}) {
           shallowDependencies,
         };
 
+        packagerServer.setHMRFileChangeListener(filename => {
+          if (!client) {
+            return Promise.resolve();
+          }
+
+          return packagerServer.getShallowDependencies(filename)
+            .then(deps => {
+              // if the file dependencies have change we need to invalidate the
+              // dependencies caches because the list of files we need to send
+              // to the client may have changed
+              if (arrayEquals(deps, client.shallowDependencies[filename])) {
+                return Promise.resolve();
+              }
+              return getDependencies(client.platform, client.bundleEntry)
+                .then(({dependenciesCache, shallowDependencies}) => {
+                  // invalidate caches
+                  client.dependenciesCache = dependenciesCache;
+                  client.shallowDependencies = shallowDependencies;
+                });
+            })
+            .then(() => {
+              // make sure the file was modified is part of the bundle
+              if (!client.shallowDependencies[filename]) {
+                return;
+              }
+
+              return packagerServer.buildBundleForHMR({
+                platform: client.platform,
+                entryFile: filename,
+              })
+              .then(bundle => client.ws.send(bundle));
+            });
+        });
+
         client.ws.on('error', e => {
           console.error('[Hot Module Replacement] Unexpected error', e);
           disconnect();
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index a6bb6b3447be..717ef9e17101 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -191,6 +191,16 @@ class Server {
     this._fileWatcher.on('all', this._onFileChange.bind(this));
 
     this._debouncedFileChangeHandler = _.debounce(filePath => {
+      // if Hot Loading is enabled avoid rebuilding bundles and sending live
+      // updates. Instead, send the HMR updates right away and once that
+      // finishes, invoke any other file change listener.
+      if (this._hmrFileChangeListener) {
+        this._hmrFileChangeListener(filePath).then(() => {
+          this._fileChangeListeners.forEach(listener => listener(filePath));
+        }).done();
+        return;
+      }
+
       this._fileChangeListeners.forEach(listener => listener(filePath));
       this._rebuildBundles(filePath);
       this._informChangeWatchers();
@@ -208,6 +218,10 @@ class Server {
     this._fileChangeListeners.push(listener);
   }
 
+  setHMRFileChangeListener(listener) {
+    this._hmrFileChangeListener = listener;
+  }
+
   buildBundle(options) {
     return Promise.resolve().then(() => {
       if (!options.platform) {

From a68f8f4224d977d6845ffd82c1d592bd3536681a Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Tue, 29 Dec 2015 19:47:20 -0800
Subject: [PATCH 0540/1411] WebWorkers: Add APIs for working with JSObjectRef

Reviewed By: lexs

Differential Revision: D2779267

fb-gh-sync-id: 5c5a49988a1d501f15e5033b2dd5b528d97d96ed
---
 ReactAndroid/src/main/jni/react/JSCHelpers.h |  2 +
 ReactAndroid/src/main/jni/react/Value.cpp    | 51 ++++++++++++++--
 ReactAndroid/src/main/jni/react/Value.h      | 62 +++++++++++++++++++-
 3 files changed, 108 insertions(+), 7 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/JSCHelpers.h b/ReactAndroid/src/main/jni/react/JSCHelpers.h
index ba3f8525a341..f17374f18f85 100644
--- a/ReactAndroid/src/main/jni/react/JSCHelpers.h
+++ b/ReactAndroid/src/main/jni/react/JSCHelpers.h
@@ -5,6 +5,8 @@
 #include <JavaScriptCore/JSContextRef.h>
 #include <JavaScriptCore/JSObjectRef.h>
 
+#define throwJSExecutionException(...) jni::throwNewJavaException("com/facebook/react/bridge/JSExecutionException", __VA_ARGS__)
+
 namespace facebook {
 namespace react {
 
diff --git a/ReactAndroid/src/main/jni/react/Value.cpp b/ReactAndroid/src/main/jni/react/Value.cpp
index 7d2d8667396f..0859ca452d0a 100644
--- a/ReactAndroid/src/main/jni/react/Value.cpp
+++ b/ReactAndroid/src/main/jni/react/Value.cpp
@@ -5,6 +5,8 @@
 #include <jni/fbjni.h>
 #include <fb/log.h>
 
+#include "JSCHelpers.h"
+
 namespace facebook {
 namespace react {
 
@@ -37,17 +39,54 @@ std::string Value::toJSONString(unsigned indent) const {
   if (stringToAdopt == nullptr) {
     JSValueProtect(m_context, exn);
     std::string exceptionText = Value(m_context, exn).toString().str();
-    jni::throwNewJavaException(
-        "java/lang/IllegalArgumentException",
-        "Exception creating JSON string: %s",
-        exceptionText.c_str());
+    throwJSExecutionException("Exception creating JSON string: %s", exceptionText.c_str());
   }
   return String::adopt(stringToAdopt).str();
 }
 
 /* static */
-Value Value::fromJSON(JSContextRef& ctx, const String& json) {
-  return Value(ctx, JSValueMakeFromJSONString(ctx, json));
+Value Value::fromJSON(JSContextRef ctx, const String& json) {
+  auto result = JSValueMakeFromJSONString(ctx, json);
+  if (!result) {
+    throwJSExecutionException("Failed to create String from JSON");
+  }
+  return Value(ctx, result);
+}
+
+Object Value::asObject() {
+  JSValueRef exn;
+  JSObjectRef jsObj = JSValueToObject(context(), m_value, &exn);
+  if (!jsObj) {
+    std::string exceptionText = Value(m_context, exn).toString().str();
+    throwJSExecutionException("Failed to convert to object: %s", exceptionText.c_str());
+  }
+  Object ret = Object(context(), jsObj);
+  m_value = nullptr;
+  return std::move(ret);
+}
+
+Value Object::callAsFunction(int nArgs, JSValueRef args[]) {
+  JSValueRef exn;
+  JSValueRef result = JSObjectCallAsFunction(m_context, m_obj, NULL, nArgs, args, &exn);
+  if (!result) {
+    std::string exceptionText = Value(m_context, exn).toString().str();
+    throwJSExecutionException("Exception calling JS function: %s", exceptionText.c_str());
+  }
+  return Value(m_context, result);
+}
+
+Value Object::getProperty(String propName) const {
+  JSValueRef exn;
+  JSValueRef property = JSObjectGetProperty(m_context, m_obj, propName, &exn);
+  if (!property) {
+    std::string exceptionText = Value(m_context, exn).toString().str();
+    throwJSExecutionException("Failed to get property: %s", exceptionText.c_str());
+  }
+  return Value(m_context, property);
+}
+
+Value Object::getProperty(const char *propName) const {
+  return getProperty(String(propName));
 }
 
 } }
diff --git a/ReactAndroid/src/main/jni/react/Value.h b/ReactAndroid/src/main/jni/react/Value.h
index b39bdef304db..c237bda1827d 100644
--- a/ReactAndroid/src/main/jni/react/Value.h
+++ b/ReactAndroid/src/main/jni/react/Value.h
@@ -4,6 +4,7 @@
 
 #include <memory>
 #include <sstream>
+#include <JavaScriptCore/JSObjectRef.h>
 #include <JavaScriptCore/JSRetainPtr.h>
 #include <JavaScriptCore/JSStringRef.h>
 #include <JavaScriptCore/JSValueRef.h>
@@ -15,6 +16,7 @@
 namespace facebook {
 namespace react {
 
+class Value;
 class Context;
 
 class String : public noncopyable {
@@ -84,6 +86,58 @@ class String : public noncopyable {
   JSRetainPtr<JSStringRef> m_string;
 };
 
+class Object : public noncopyable {
+public:
+  Object(JSContextRef context, JSObjectRef obj) :
+    m_context(context),
+    m_obj(obj)
+  {}
+
+  Object(Object&& other) :
+      m_context(other.m_context),
+      m_obj(other.m_obj),
+      m_isProtected(other.m_isProtected) {
+    other.m_obj = nullptr;
+    other.m_isProtected = false;
+  }
+
+  ~Object() {
+    if (m_isProtected && m_obj) {
+      JSValueUnprotect(m_context, m_obj);
+    }
+  }
+
+  operator JSObjectRef() const {
+    return m_obj;
+  }
+
+  bool isFunction() const {
+    return JSObjectIsFunction(m_context, m_obj);
+  }
+
+  Value callAsFunction(int nArgs, JSValueRef args[]);
+
+  Value getProperty(String propName) const;
+  Value getProperty(const char *propName) const;
+
+  void makeProtected() {
+    if (!m_isProtected && m_obj) {
+      JSValueProtect(m_context, m_obj);
+      m_isProtected = true;
+    }
+  }
+
+  static Object getGlobalObject(JSContextRef ctx) {
+    auto globalObj = JSContextGetGlobalObject(ctx);
+    return Object(ctx, globalObj);
+  }
+
+private:
+  JSContextRef m_context;
+  JSObjectRef m_obj;
+  bool m_isProtected = false;
+};
+
 class Value : public noncopyable {
 public:
   Value(JSContextRef context, JSValueRef value);
@@ -110,6 +164,10 @@ class Value : public noncopyable {
     return JSValueIsNull(context(), m_value);
   }
 
+  bool isUndefined() const {
+    return JSValueIsUndefined(context(), m_value);
+  }
+
   double asNumber() const {
     if (isNumber()) {
       return JSValueToNumber(context(), m_value, nullptr);
@@ -130,6 +188,8 @@ class Value : public noncopyable {
     return JSValueIsObject(context(), m_value);
   }
 
+  Object asObject();
+
   bool isString() const {
     return JSValueIsString(context(), m_value);
   }
@@ -139,7 +199,7 @@ class Value : public noncopyable {
   }
 
   std::string toJSONString(unsigned indent = 0) const;
-  static Value fromJSON(JSContextRef& ctx, const String& json);
+  static Value fromJSON(JSContextRef ctx, const String& json);
 protected:
   JSContextRef context() const;
   JSContextRef m_context;

From 690eb08e63ef699b3cd74a65ba3b64b26099b461 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Tue, 29 Dec 2015 19:47:22 -0800
Subject: [PATCH 0541/1411] WebWorkers: Extract evaluateScript logic to
 JSCHelpers

Reviewed By: lexs

Differential Revision: D2779277

fb-gh-sync-id: ab9a040193f36f40a4a34229a4a90199537253aa
---
 .../src/main/jni/react/JSCExecutor.cpp        | 29 ++-----------------
 .../src/main/jni/react/JSCHelpers.cpp         | 24 +++++++++++++++
 ReactAndroid/src/main/jni/react/JSCHelpers.h  |  3 ++
 3 files changed, 29 insertions(+), 27 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index b678aff4ced6..b12021d41890 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -70,31 +70,6 @@ static JSValueRef nativePerformanceNow(
     const JSValueRef arguments[],
     JSValueRef *exception);
 
-static JSValueRef evaluateScriptWithJSC(
-    JSGlobalContextRef ctx,
-    JSStringRef script,
-    JSStringRef sourceURL) {
-  JSValueRef exn;
-  auto result = JSEvaluateScript(ctx, script, nullptr, sourceURL, 0, &exn);
-  if (result == nullptr) {
-    JSValueProtect(ctx, exn);
-    std::string exceptionText = Value(ctx, exn).toString().str();
-    FBLOGE("Got JS Exception: %s", exceptionText.c_str());
-    auto line = Value(ctx, JSObjectGetProperty(ctx,
-      JSValueToObject(ctx, exn, nullptr),
-      JSStringCreateWithUTF8CString("line"), nullptr
-    ));
-    std::ostringstream lineInfo;
-    if (line != nullptr && line.isNumber()) {
-      lineInfo << " (line " << line.asInteger() << " in the generated bundle)";
-    } else {
-      lineInfo << " (no line info)";
-    }
-    throwNewJavaException("com/facebook/react/bridge/JSExecutionException", (exceptionText + lineInfo.str()).c_str());
-  }
-  return result;
-}
-
 static std::string executeJSCallWithJSC(
     JSGlobalContextRef ctx,
     const std::string& methodName,
@@ -110,7 +85,7 @@ static std::string executeJSCallWithJSC(
   auto js = folly::to<folly::fbstring>(
       "__fbBatchedBridge.", methodName, ".apply(null, ",
       folly::toJson(jsonArgs), ")");
-  auto result = evaluateScriptWithJSC(ctx, String(js.c_str()), nullptr);
+  auto result = evaluateScript(ctx, String(js.c_str()), nullptr);
   JSValueProtect(ctx, result);
   return Value(ctx, result).toJSONString();
 }
@@ -167,7 +142,7 @@ void JSCExecutor::executeApplicationScript(
   FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor::executeApplicationScript",
     "sourceURL", sourceURL);
   #endif
-  evaluateScriptWithJSC(m_context, jsScript, jsSourceURL);
+  evaluateScript(m_context, jsScript, jsSourceURL);
 }
 
 std::string JSCExecutor::flush() {
diff --git a/ReactAndroid/src/main/jni/react/JSCHelpers.cpp b/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
index b1edc73dc2c7..12702d03aaeb 100644
--- a/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
@@ -3,6 +3,10 @@
 #include "JSCHelpers.h"
 
 #include <JavaScriptCore/JSStringRef.h>
+#include <fb/log.h>
+#include <jni/fbjni/Exceptions.h>
+
+#include "Value.h"
 
 namespace facebook {
 namespace react {
@@ -28,4 +32,24 @@ JSValueRef makeJSCException(
   return JSValueToObject(ctx, exceptionString, NULL);
 }
 
+JSValueRef evaluateScript(JSContextRef context, JSStringRef script, JSStringRef source) {
+  JSValueRef exn;
+  auto result = JSEvaluateScript(context, script, NULL, source, 0, &exn);
+  if (result == nullptr) {
+    Value exception = Value(context, exn);
+    std::string exceptionText = exception.toString().str();
+    FBLOGE("Got JS Exception: %s", exceptionText.c_str());
+    auto line = exception.asObject().getProperty("line");
+
+    std::ostringstream lineInfo;
+    if (line != nullptr && line.isNumber()) {
+      lineInfo << " (line " << line.asInteger() << " in the generated bundle)";
+    } else {
+      lineInfo << " (no line info)";
+    }
+    throwJSExecutionException("%s%s", exceptionText.c_str(), lineInfo.str().c_str());
+  }
+  return result;
+}
+
 } }
diff --git a/ReactAndroid/src/main/jni/react/JSCHelpers.h b/ReactAndroid/src/main/jni/react/JSCHelpers.h
index f17374f18f85..fd19c48cc458 100644
--- a/ReactAndroid/src/main/jni/react/JSCHelpers.h
+++ b/ReactAndroid/src/main/jni/react/JSCHelpers.h
@@ -4,6 +4,7 @@
 
 #include <JavaScriptCore/JSContextRef.h>
 #include <JavaScriptCore/JSObjectRef.h>
+#include <JavaScriptCore/JSValueRef.h>
 
 #define throwJSExecutionException(...) jni::throwNewJavaException("com/facebook/react/bridge/JSExecutionException", __VA_ARGS__)
 
@@ -19,4 +20,6 @@ JSValueRef makeJSCException(
     JSContextRef ctx,
     const char* exception_text);
 
+JSValueRef evaluateScript(JSContextRef context, JSStringRef script, JSStringRef source);
+
 } }

From 322a77340c715199380103986e2a2242ac901df1 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Tue, 29 Dec 2015 19:50:56 -0800
Subject: [PATCH 0542/1411] WebWorkers: Add APIs for working with JSObjectRef

Reviewed By: lexs

Differential Revision: D2779267

fb-gh-sync-id: 8aee2aee3ca4d1119576494caa39010e854b92a6
---
 ReactAndroid/src/main/jni/react/JSCHelpers.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/ReactAndroid/src/main/jni/react/JSCHelpers.h b/ReactAndroid/src/main/jni/react/JSCHelpers.h
index fd19c48cc458..2d125f4af32f 100644
--- a/ReactAndroid/src/main/jni/react/JSCHelpers.h
+++ b/ReactAndroid/src/main/jni/react/JSCHelpers.h
@@ -8,6 +8,8 @@
 
 #define throwJSExecutionException(...) jni::throwNewJavaException("com/facebook/react/bridge/JSExecutionException", __VA_ARGS__)
 
+#define throwJSExecutionException(...) jni::throwNewJavaException("com/facebook/react/bridge/JSExecutionException", __VA_ARGS__)
+
 namespace facebook {
 namespace react {
 

From dfcc4f8ad5cdf73a0828395ddd298f708ff377f0 Mon Sep 17 00:00:00 2001
From: Mike Armstrong <mikea@fb.com>
Date: Tue, 29 Dec 2015 22:11:40 -0800
Subject: [PATCH 0543/1411] Log Memory tags using LegacyProfiler

Reviewed By: jspahrsummers

Differential Revision: D2789647

fb-gh-sync-id: 220a0fc4eccccd92a6b8f45b07b32735a7054614
---
 .../src/main/jni/react/JSCTracing.cpp         | 30 +++++--------------
 1 file changed, 8 insertions(+), 22 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/JSCTracing.cpp b/ReactAndroid/src/main/jni/react/JSCTracing.cpp
index c607cc8c6ed9..70d79d478691 100644
--- a/ReactAndroid/src/main/jni/react/JSCTracing.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCTracing.cpp
@@ -419,18 +419,11 @@ static JSValueRef nativeTraceBeginLegacy(
     size_t argumentCount,
     const JSValueRef arguments[],
     JSValueRef* exception) {
-  if (FBSYSTRACE_UNLIKELY(argumentCount < 1)) {
-    if (exception) {
-      *exception = facebook::react::makeJSCException(
-        ctx,
-        "nativeTraceBeginLegacy: requires TAG Argument");
+  if (FBSYSTRACE_LIKELY(argumentCount >= 1)) {
+    uint64_t tag = tagFromJSValue(ctx, arguments[0], exception);
+    if (!fbsystrace_is_tracing(tag)) {
+      return JSValueMakeUndefined(ctx);
     }
-    return JSValueMakeUndefined(ctx);
-  }
-
-  uint64_t tag = tagFromJSValue(ctx, arguments[0], exception);
-  if (!fbsystrace_is_tracing(tag)) {
-    return JSValueMakeUndefined(ctx);
   }
 
   JSStringRef title = JSStringCreateWithUTF8CString(ENABLED_FBSYSTRACE_PROFILE_NAME);
@@ -451,18 +444,11 @@ static JSValueRef nativeTraceEndLegacy(
     size_t argumentCount,
     const JSValueRef arguments[],
     JSValueRef* exception) {
-  if (FBSYSTRACE_UNLIKELY(argumentCount < 1)) {
-    if (exception) {
-      *exception = facebook::react::makeJSCException(
-        ctx,
-        "nativeTraceBeginLegacy: requires TAG Argument");
+  if (FBSYSTRACE_LIKELY(argumentCount >= 1)) {
+    uint64_t tag = tagFromJSValue(ctx, arguments[0], exception);
+    if (!fbsystrace_is_tracing(tag)) {
+      return JSValueMakeUndefined(ctx);
     }
-    return JSValueMakeUndefined(ctx);
-  }
-
-  uint64_t tag = tagFromJSValue(ctx, arguments[0], exception);
-  if (!fbsystrace_is_tracing(tag)) {
-    return JSValueMakeUndefined(ctx);
   }
 
   JSStringRef title = JSStringCreateWithUTF8CString(ENABLED_FBSYSTRACE_PROFILE_NAME);

From fe07a9c576b0eb704e8451b51d8f165d52b2c4b9 Mon Sep 17 00:00:00 2001
From: Ben Alpert <ben@benalpert.com>
Date: Tue, 29 Dec 2015 23:08:53 -0800
Subject: [PATCH 0544/1411] Update Object.assign non-object error message

Summary:
These are the sources, not the target. Copy pasta from above.
Closes https://github.com/facebook/react-native/pull/4989

Reviewed By: svcscm

Differential Revision: D2795198

Pulled By: spicyj

fb-gh-sync-id: 61c52add02cb877284fbf62a4344361b5bf44515
---
 packager/react-packager/src/Resolver/polyfills/polyfills.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/packager/react-packager/src/Resolver/polyfills/polyfills.js b/packager/react-packager/src/Resolver/polyfills/polyfills.js
index 84bf2d3d2f9b..9698b4911dbd 100644
--- a/packager/react-packager/src/Resolver/polyfills/polyfills.js
+++ b/packager/react-packager/src/Resolver/polyfills/polyfills.js
@@ -39,7 +39,7 @@ Object.assign = function(target, sources) {
       if (typeof nextSource !== 'object' &&
           typeof nextSource !== 'function') {
         throw new TypeError(
-          'In this environment the target of assign MUST be an object.' +
+          'In this environment the sources for assign MUST be an object.' +
           'This error is a performance optimization and not spec compliant.'
         );
       }
@@ -54,7 +54,7 @@ Object.assign = function(target, sources) {
         var hasOwnProperty = Object.prototype.hasOwnProperty;
         if (!hasOwnProperty.call(nextSource, key)) {
           throw new TypeError(
-            'One of the sources to assign has an enumerable key on the ' +
+            'One of the sources for assign has an enumerable key on the ' +
             'prototype chain. This is an edge case that we do not support. ' +
             'This error is a performance optimization and not spec compliant.'
           );

From 8cabdbae1e7b78cde00d9727838c9093812bcd55 Mon Sep 17 00:00:00 2001
From: Mike Armstrong <mikea@fb.com>
Date: Tue, 29 Dec 2015 23:36:34 -0800
Subject: [PATCH 0545/1411] Report jsc memory information to fbsystrace

Reviewed By: jspahrsummers

Differential Revision: D2789593

fb-gh-sync-id: e31d5f174b9cf896ce3be6431d81264d1d240fdb
---
 Libraries/Utilities/MessageQueue.js |  1 +
 Libraries/Utilities/Systrace.js     | 12 ++++++++++++
 2 files changed, 13 insertions(+)

diff --git a/Libraries/Utilities/MessageQueue.js b/Libraries/Utilities/MessageQueue.js
index e95dcb38599d..1bd46424d2eb 100644
--- a/Libraries/Utilities/MessageQueue.js
+++ b/Libraries/Utilities/MessageQueue.js
@@ -147,6 +147,7 @@ class MessageQueue {
       this._queue = [[],[],[]];
       this._lastFlush = now;
     }
+    Systrace.counterEvent('pending_js_to_native_queue', this._queue[0].length);
     if (__DEV__ && SPY_MODE && isFinite(module)) {
       console.log('JS->N : ' + this._remoteModuleTable[module] + '.' +
         this._remoteMethodTable[module][method] + '(' + JSON.stringify(params) + ')');
diff --git a/Libraries/Utilities/Systrace.js b/Libraries/Utilities/Systrace.js
index ffd58715d4be..0e11e8942bf6 100644
--- a/Libraries/Utilities/Systrace.js
+++ b/Libraries/Utilities/Systrace.js
@@ -92,6 +92,18 @@ var Systrace = {
     }
   },
 
+  /**
+   * counterEvent registers the value to the profileName on the systrace timeline
+  **/
+  counterEvent(profileName?: any, value?: any) {
+    if (_enabled) {
+      profileName = typeof profileName === 'function' ?
+        profileName() : profileName;
+      global.nativeTraceCounter &&
+        global.nativeTraceCounter(TRACE_TAG_REACT_APPS, profileName, value);
+    }
+  },
+
   reactPerfMeasure(objName: string, fnName: string, func: any): any {
     return function (component) {
       if (!_enabled) {

From 5bc45f1881b8aaba8324bb5fc86893e4fed46519 Mon Sep 17 00:00:00 2001
From: olivier notteghem <oli@fb.com>
Date: Wed, 30 Dec 2015 04:52:34 -0800
Subject: [PATCH 0546/1411] improve navigation and tail fetch logging

Reviewed By: nspaun

Differential Revision: D2791366

fb-gh-sync-id: 5cacc34ef29630437e82b1fab18c928c8794d551
---
 .../CustomComponents/ListView/ListView.js     | 36 ++++++++-----------
 1 file changed, 14 insertions(+), 22 deletions(-)

diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js
index a2406236cf13..366971f3fbd9 100644
--- a/Libraries/CustomComponents/ListView/ListView.js
+++ b/Libraries/CustomComponents/ListView/ListView.js
@@ -37,7 +37,6 @@ var TimerMixin = require('react-timer-mixin');
 var isEmpty = require('isEmpty');
 var logError = require('logError');
 var merge = require('merge');
-var shallowEqual = require('shallowEqual');
 
 var PropTypes = React.PropTypes;
 
@@ -268,7 +267,6 @@ var ListView = React.createClass({
     this._visibleRows = {};
     this._prevRenderedRowsCount = 0;
     this._sentEndForContentLength = null;
-    this._lastScrollPropertiesCheckedForPaging = null;
   },
 
   componentDidMount: function() {
@@ -435,24 +433,24 @@ var ListView = React.createClass({
   },
 
   _onContentSizeChange: function(width, height) {
-    this.scrollProperties.contentLength = !this.props.horizontal ?
-      height : width;
-    this._updateVisibleRows();
-    this._renderMoreRowsIfNeeded();
-    if (this.props.onContentSizeChange) {
-      this.props.onContentSizeChange(width, height);
+    var contentLength = !this.props.horizontal ? height : width;
+    if (contentLength !== this.scrollProperties.contentLength) {
+      this.scrollProperties.contentLength = contentLength;
+      this._updateVisibleRows();
+      this._renderMoreRowsIfNeeded();
     }
+    this.props.onContentSizeChange && this.props.onContentSizeChange(width, height);
   },
 
   _onLayout: function(event) {
     var {width, height} = event.nativeEvent.layout;
-    this.scrollProperties.visibleLength = !this.props.horizontal ?
-      height : width;
-    this._updateVisibleRows();
-    this._renderMoreRowsIfNeeded();
-    if (this.props.onLayout) {
-      this.props.onLayout(event);
-    }
+    var visibleLength = !this.props.horizontal ? height : width;
+    if (visibleLength !== this.scrollProperties.visibleLength) {
+      this.scrollProperties.visibleLength = visibleLength;
+      this._updateVisibleRows();
+      this._renderMoreRowsIfNeeded();
+    } 
+    this.props.onLayout && this.props.onLayout(event);
   },
 
   _maybeCallOnEndReached: function(event) {
@@ -474,13 +472,7 @@ var ListView = React.createClass({
       this._maybeCallOnEndReached();
       return;
     }
-
-    if (shallowEqual(this._lastScrollPropertiesCheckedForPaging, this.scrollProperties)) {
-      // distance from end of feed hasn't changed since last check, avoid paging twice..
-      return;
-    }
-    this._lastScrollPropertiesCheckedForPaging = {...this.scrollProperties};
-
+ 
     var distanceFromEnd = this._getDistanceFromEnd(this.scrollProperties);
     if (distanceFromEnd < this.props.scrollRenderAheadDistance) {
       this._pageInNewRows();

From 494d607e2855e09669be4bc8065d476df90463de Mon Sep 17 00:00:00 2001
From: wvengen <dev-js@willem.engen.nl>
Date: Wed, 30 Dec 2015 08:18:45 -0800
Subject: [PATCH 0547/1411] Improve watcher timeout error message (fixes #5005)

Summary: Closes https://github.com/facebook/react-native/pull/5022

Reviewed By: svcscm

Differential Revision: D2793185

Pulled By: milend

fb-gh-sync-id: ec49d27d6e405924269a48f32cce401b1ce380f6
---
 .../DependencyResolver/FileWatcher/index.js   | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/FileWatcher/index.js b/packager/react-packager/src/DependencyResolver/FileWatcher/index.js
index 6c8a07093463..d75e02119c80 100644
--- a/packager/react-packager/src/DependencyResolver/FileWatcher/index.js
+++ b/packager/react-packager/src/DependencyResolver/FileWatcher/index.js
@@ -96,11 +96,7 @@ function createWatcher(rootConfig) {
 
     return new Promise(function(resolve, reject) {
       const rejectTimeout = setTimeout(function() {
-        reject(new Error([
-          'Watcher took too long to load',
-          'Try running `watchman version` from your terminal',
-          'https://facebook.github.io/watchman/docs/troubleshooting.html',
-        ].join('\n')));
+        reject(new Error(timeoutMessage(Watcher)));
       }, MAX_WAIT_TIME);
 
       watcher.once('ready', function() {
@@ -111,4 +107,17 @@ function createWatcher(rootConfig) {
   });
 }
 
+function timeoutMessage(Watcher) {
+  const lines = [
+    'Watcher took too long to load (' + Watcher.name + ')',
+  ];
+  if (Watcher === sane.WatchmanWatcher) {
+    lines.push(
+      'Try running `watchman version` from your terminal',
+      'https://facebook.github.io/watchman/docs/troubleshooting.html',
+    );
+  }
+  return lines.join('\n');
+}
+
 module.exports = FileWatcher;

From e798817e5a1f95d88070bdf9f71c2348a5df78b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Wed, 30 Dec 2015 10:07:55 -0800
Subject: [PATCH 0548/1411] Yellow boxes for HMR errors

Reviewed By: vjeux

Differential Revision: D2795143

fb-gh-sync-id: fd5c92af511258bb1252d991e994a8c37657644e
---
 packager/react-packager/src/Resolver/polyfills/require.js | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/packager/react-packager/src/Resolver/polyfills/require.js b/packager/react-packager/src/Resolver/polyfills/require.js
index 15f8cf551484..afcda4ca139d 100644
--- a/packager/react-packager/src/Resolver/polyfills/require.js
+++ b/packager/react-packager/src/Resolver/polyfills/require.js
@@ -99,18 +99,20 @@
       var mod = modules[id];
 
       if (!mod) {
-        console.error(
+        console.warn(
           'Cannot accept unknown module `' + id + '`. Make sure you\'re not ' +
           'trying to modify something else other than a module ' +
           '(i.e.: a polyfill).'
         );
+        return;
       }
 
       if (!mod.module.hot) {
-        console.error(
+        console.warn(
           'Cannot accept module because Hot Module Replacement ' +
           'API was not installed.'
         );
+        return;
       }
 
       if (mod.module.hot.acceptCallback) {
@@ -120,7 +122,7 @@
 
         mod.module.hot.acceptCallback();
       } else {
-        console.log(
+        console.warn(
           '[HMR] Module `' + id + '` can\'t be hot reloaded because it ' +
           'doesn\'t provide accept callback hook. Reload the app to get the updates.'
         );

From f9ad70bd81164acaa7c014c6842af9bfae16460d Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Wed, 30 Dec 2015 10:42:19 -0800
Subject: [PATCH 0549/1411] Fix UIExplorer list

Summary:
public
On fresh install, UIExplorer produces a blank list due to the search text being null. This fixes that by replacing the null with an empty string.

Reviewed By: milend

Differential Revision: D2795411

fb-gh-sync-id: 4bdde5d4f9e88dd933c7946dcbfb8b591a54baf6
---
 Examples/UIExplorer/UIExplorerListBase.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Examples/UIExplorer/UIExplorerListBase.js b/Examples/UIExplorer/UIExplorerListBase.js
index c4b55f6d0ab3..71ce0031f75e 100644
--- a/Examples/UIExplorer/UIExplorerListBase.js
+++ b/Examples/UIExplorer/UIExplorerListBase.js
@@ -40,7 +40,7 @@ class UIExplorerListBase extends React.Component {
         components: [],
         apis: [],
       }),
-      searchText: this.props.searchText,
+      searchText: this.props.searchText || '',
     };
   }
 

From 88baaa1239362c6213e413fff6e99c5152f97349 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Wed, 30 Dec 2015 11:38:13 -0800
Subject: [PATCH 0550/1411] increased stability of circleCI e2e tests

Summary:
Out of 57 builds in the 5 days during Christmas only 15 were successful.
15 of the failed ones were caused by `com.android.ddmlib.ShellCommandUnresponsiveException` when running unstrumentation tests.
Another 10 were because of crashes probably related to memory usage.

This PR follows ideas from https://github.com/Originate/guide/blob/master/android/guide/Continuous%20Integration.md

So far I've made 6 successful builds with this setup.
Need to run it for a few more days to get accurate stats.
Closes https://github.com/facebook/react-native/pull/5021

Reviewed By: svcscm

Differential Revision: D2795713

Pulled By: androidtrunkagent

fb-gh-sync-id: 33373fed7ca7c5fb83b35cf551f8501286e33d7b
---
 ReactAndroid/build.gradle          |  2 ++
 circle.yml                         | 36 +++++++++++++++++-------------
 scripts/circle-ci-android-setup.sh | 22 ++++++++++++++++++
 3 files changed, 44 insertions(+), 16 deletions(-)
 create mode 100644 scripts/circle-ci-android-setup.sh

diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle
index 1ea9ab37d665..a20c71937953 100644
--- a/ReactAndroid/build.gradle
+++ b/ReactAndroid/build.gradle
@@ -24,6 +24,8 @@ task createNativeDepsDirectories {
 task downloadBoost(dependsOn: createNativeDepsDirectories, type: Download) {
     // Use ZIP version as it's faster this way to selectively extract some parts of the archive
     src 'https://downloads.sourceforge.net/project/boost/boost/1.57.0/boost_1_57_0.zip'
+    // alternative
+    // src 'http://mirror.nienbo.com/boost/boost_1_57_0.zip'
     onlyIfNewer true
     overwrite false
     dest new File(downloadsDir, 'boost_1_57_0.zip')
diff --git a/circle.yml b/circle.yml
index 3077d7ba9554..a0e5d4a8791d 100644
--- a/circle.yml
+++ b/circle.yml
@@ -4,33 +4,37 @@ machine:
   environment:
     PATH: "~/$CIRCLE_PROJECT_REPONAME/gradle-2.9/bin:$PATH"
     TERM: "dumb"
-    ADB_INSTALL_TIMEOUT: "10"
+    ADB_INSTALL_TIMEOUT: 10
     GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx512m -XX:+HeapDumpOnOutOfMemoryError"'
 
 dependencies:
   pre:
+  # using npm@3 because of problems with shrink-wrapped optional deps installs on linux
   - npm install -g npm@3.2
-  - wget "https://services.gradle.org/distributions/gradle-2.9-bin.zip"; unzip gradle-2.9-bin.zip
+  - source scripts/circle-ci-android-setup.sh && getAndroidSDK
+  - ./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog
+  cache_directories:
+  - "ReactAndroid/build/downloads"
 test:
   pre:
     # starting emulator in advance because it takes very long to boot
-    # the side effect is that we loose 1GB of RAM for all the following commands
-    # if builds are running out of memory move the emulator start right before `wait-for-boot`
-    - emulator -avd circleci-android22 -no-audio -no-window:
-              background: true
-              parallel: true
+    - $ANDROID_HOME/tools/emulator -avd testAVD -no-skin -no-audio -no-window:
+            background: true
+    # assemble done separately because it requires quite a lot of memory and also gives time for emulator to load
+    - ./gradlew :ReactAndroid:assembleDebug -PdisablePreDex -Pjobs=1:
+            timeout: 360
+    - source scripts/circle-ci-android-setup.sh && waitForAVD
   override:
-    # build ndkreactlib first because it consumes memory and downloads stuff
-    - ./gradlew :ReactAndroid:buildReactNdkLib -PdisablePreDex -Pjobs=1
     # unit tests
     - ./gradlew :ReactAndroid:testDebugUnitTest -PdisablePreDex
     # build JS bundle for instrumentation tests
     - node local-cli/cli.js bundle --platform android --dev true --entry-file ReactAndroid/src/androidTest/assets/TestBundle.js --bundle-output ReactAndroid/src/androidTest/assets/AndroidTestBundle.js
-    # run instrumentation tests on device
-    - circle-android wait-for-boot
-    - sleep 5
-    # unlock the emulator screen
-    - adb shell input keyevent 82
-    - sleep 5
     # run tests on the emulator
-    - ./gradlew :ReactAndroid:connectedAndroidTest -PdisablePreDex --stacktrace
+    - ./gradlew :ReactAndroid:connectedAndroidTest -PdisablePreDex --stacktrace --info:
+        timeout: 360
+  post:
+    # copy test report for Circle CI to display
+    - mkdir -p $CIRCLE_TEST_REPORTS/junit/
+    - find . -type f -regex ".*/build/test-results/debug/.*xml" -exec cp {} $CIRCLE_TEST_REPORTS/junit/ \;
+    - find . -type f -regex ".*/outputs/androidTest-results/connected/.*xml" -exec cp {} $CIRCLE_TEST_REPORTS/junit/ \;
+
diff --git a/scripts/circle-ci-android-setup.sh b/scripts/circle-ci-android-setup.sh
new file mode 100644
index 000000000000..2697ed9925e7
--- /dev/null
+++ b/scripts/circle-ci-android-setup.sh
@@ -0,0 +1,22 @@
+# inspired by https://github.com/Originate/guide/blob/master/android/guide/Continuous%20Integration.md
+
+function getAndroidSDK {
+  export PATH="$ANDROID_HOME/platform-tools:$ANDROID_HOME/tools:$PATH"
+
+  DEPS="$ANDROID_HOME/installed-dependencies"
+
+  if [ ! -e $DEPS ]; then
+    echo no | android create avd -n testAVD -f -t android-19 --abi default/armeabi-v7a &&
+    touch $DEPS
+  fi
+}
+
+function waitForAVD {
+  local bootanim=""
+  export PATH=$(dirname $(dirname $(which android)))/platform-tools:$PATH
+  until [[ "$bootanim" =~ "stopped" ]]; do
+    sleep 5
+    bootanim=$(adb -e shell getprop init.svc.bootanim 2>&1)
+    echo "emulator status=$bootanim"
+  done
+}

From 5bf1f4c05ef0f3ee1cbf6e38164d58dbeee6637d Mon Sep 17 00:00:00 2001
From: Ben Alpert <balpert@fb.com>
Date: Wed, 30 Dec 2015 11:38:35 -0800
Subject: [PATCH 0551/1411] Install fbjs@0.6.0, react@0.14.4

Reviewed By: zpao

Differential Revision: D2794354

fb-gh-sync-id: 57f5bc4ded5cc7eee17debdac76dc2934071dd54
---
 npm-shrinkwrap.json | 155 ++++++++++++++++++++++++++++----------------
 package.json        |   4 +-
 2 files changed, 101 insertions(+), 58 deletions(-)

diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index 59e358b96610..f88dce93c4fc 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -156,15 +156,15 @@
           "from": "js-tokens@1.0.1",
           "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
         },
-        "regenerator": {
-          "version": "0.8.40",
-          "from": "regenerator@0.8.40",
-          "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
-        },
         "recast": {
           "version": "0.10.33",
           "from": "recast@0.10.33",
           "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
+        },
+        "regenerator": {
+          "version": "0.8.40",
+          "from": "regenerator@0.8.40",
+          "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
         }
       }
     },
@@ -284,11 +284,6 @@
           "from": "globals@>=6.4.0 <7.0.0",
           "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
         },
-        "js-tokens": {
-          "version": "1.0.1",
-          "from": "js-tokens@1.0.1",
-          "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
-        },
         "recast": {
           "version": "0.10.33",
           "from": "recast@0.10.33",
@@ -299,6 +294,11 @@
           "from": "regenerator@0.8.40",
           "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
         },
+        "js-tokens": {
+          "version": "1.0.1",
+          "from": "js-tokens@1.0.1",
+          "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
+        },
         "source-map": {
           "version": "0.5.3",
           "from": "source-map@>=0.5.0 <0.6.0",
@@ -386,14 +386,14 @@
           "version": "6.1.18",
           "from": "babel-template@>=6.1.18 <7.0.0"
         },
-        "babel-messages": {
-          "version": "6.1.18",
-          "from": "babel-messages@>=6.1.18 <7.0.0"
-        },
         "babel-code-frame": {
           "version": "6.1.18",
           "from": "babel-code-frame@>=6.1.18 <7.0.0"
         },
+        "babel-messages": {
+          "version": "6.1.18",
+          "from": "babel-messages@>=6.1.18 <7.0.0"
+        },
         "babel-traverse": {
           "version": "6.1.20",
           "from": "babel-traverse@>=6.1.18 <7.0.0"
@@ -1772,10 +1772,22 @@
         }
       }
     },
-    "fbjs-haste": {
-      "version": "0.3.4",
-      "from": "fbjs-haste@0.3.4",
-      "resolved": "https://registry.npmjs.org/fbjs-haste/-/fbjs-haste-0.3.4.tgz"
+    "fbjs": {
+      "version": "0.6.0",
+      "from": "fbjs@>=0.6.0 <0.7.0",
+      "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.6.0.tgz",
+      "dependencies": {
+        "ua-parser-js": {
+          "version": "0.7.10",
+          "from": "ua-parser-js@>=0.7.9 <0.8.0",
+          "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.10.tgz"
+        },
+        "whatwg-fetch": {
+          "version": "0.9.0",
+          "from": "whatwg-fetch@>=0.9.0 <0.10.0",
+          "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz"
+        }
+      }
     },
     "fbjs-scripts": {
       "version": "0.4.0",
@@ -1842,16 +1854,16 @@
             }
           }
         },
-        "abbrev": {
-          "version": "1.0.7",
-          "from": "abbrev@1",
-          "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz"
-        },
         "ansi": {
           "version": "0.3.0",
           "from": "ansi@~0.3.0",
           "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.0.tgz"
         },
+        "abbrev": {
+          "version": "1.0.7",
+          "from": "abbrev@1",
+          "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz"
+        },
         "ansi-styles": {
           "version": "2.1.0",
           "from": "ansi-styles@^2.1.0",
@@ -1877,16 +1889,16 @@
           "from": "assert-plus@^0.1.5",
           "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
         },
-        "async": {
-          "version": "1.5.0",
-          "from": "async@^1.4.0",
-          "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz"
-        },
         "aws-sign2": {
           "version": "0.6.0",
           "from": "aws-sign2@~0.6.0",
           "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
         },
+        "async": {
+          "version": "1.5.0",
+          "from": "async@^1.4.0",
+          "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz"
+        },
         "balanced-match": {
           "version": "0.2.1",
           "from": "balanced-match@>=0.2.0 <0.3.0",
@@ -1932,16 +1944,16 @@
           "from": "concat-map@0.0.1",
           "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
         },
-        "cryptiles": {
-          "version": "2.0.5",
-          "from": "cryptiles@2.x.x",
-          "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz"
-        },
         "core-util-is": {
           "version": "1.0.1",
           "from": "core-util-is@~1.0.0",
           "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
         },
+        "cryptiles": {
+          "version": "2.0.5",
+          "from": "cryptiles@2.x.x",
+          "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz"
+        },
         "ctype": {
           "version": "0.5.3",
           "from": "ctype@0.5.3",
@@ -1967,16 +1979,16 @@
           "from": "delegates@^0.1.0",
           "resolved": "https://registry.npmjs.org/delegates/-/delegates-0.1.0.tgz"
         },
-        "extend": {
-          "version": "3.0.0",
-          "from": "extend@~3.0.0",
-          "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz"
-        },
         "escape-string-regexp": {
           "version": "1.0.3",
           "from": "escape-string-regexp@^1.0.2",
           "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz"
         },
+        "extend": {
+          "version": "3.0.0",
+          "from": "extend@~3.0.0",
+          "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz"
+        },
         "forever-agent": {
           "version": "0.6.1",
           "from": "forever-agent@~0.6.1",
@@ -2162,16 +2174,16 @@
           "from": "path-is-absolute@>=1.0.0 <2.0.0",
           "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz"
         },
-        "pinkie-promise": {
-          "version": "1.0.0",
-          "from": "pinkie-promise@^1.0.0",
-          "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz"
-        },
         "pinkie": {
           "version": "1.0.0",
           "from": "pinkie@^1.0.0",
           "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
         },
+        "pinkie-promise": {
+          "version": "1.0.0",
+          "from": "pinkie-promise@^1.0.0",
+          "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz"
+        },
         "qs": {
           "version": "5.2.0",
           "from": "qs@~5.2.0",
@@ -2192,6 +2204,11 @@
           "from": "sntp@1.x.x",
           "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
         },
+        "semver": {
+          "version": "5.0.3",
+          "from": "semver@~5.0.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
+        },
         "string_decoder": {
           "version": "0.10.31",
           "from": "string_decoder@~0.10.x",
@@ -2202,10 +2219,10 @@
           "from": "stringstream@~0.0.4",
           "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
         },
-        "semver": {
-          "version": "5.0.3",
-          "from": "semver@~5.0.1",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
+        "supports-color": {
+          "version": "2.0.0",
+          "from": "supports-color@^2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
         },
         "strip-ansi": {
           "version": "3.0.0",
@@ -2217,11 +2234,6 @@
           "from": "strip-json-comments@0.1.x",
           "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
         },
-        "supports-color": {
-          "version": "2.0.0",
-          "from": "supports-color@^2.0.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
-        },
         "tar": {
           "version": "2.2.1",
           "from": "tar@~2.2.0",
@@ -4155,10 +4167,41 @@
         }
       }
     },
-    "react-haste": {
-      "version": "0.14.2",
-      "from": "react-haste@0.14.2",
-      "resolved": "https://registry.npmjs.org/react-haste/-/react-haste-0.14.2.tgz"
+    "react": {
+      "version": "0.14.5",
+      "from": "react@>=0.14.5 <0.15.0",
+      "resolved": "file:build/packages/react.tgz",
+      "dependencies": {
+        "envify": {
+          "version": "3.4.0",
+          "from": "envify@>=3.0.0 <4.0.0",
+          "resolved": "https://registry.npmjs.org/envify/-/envify-3.4.0.tgz",
+          "dependencies": {
+            "jstransform": {
+              "version": "10.1.0",
+              "from": "jstransform@>=10.0.1 <11.0.0",
+              "resolved": "https://registry.npmjs.org/jstransform/-/jstransform-10.1.0.tgz",
+              "dependencies": {
+                "base62": {
+                  "version": "0.1.1",
+                  "from": "base62@0.1.1",
+                  "resolved": "https://registry.npmjs.org/base62/-/base62-0.1.1.tgz"
+                },
+                "esprima-fb": {
+                  "version": "13001.1001.0-dev-harmony-fb",
+                  "from": "esprima-fb@13001.1001.0-dev-harmony-fb",
+                  "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-13001.1001.0-dev-harmony-fb.tgz"
+                },
+                "source-map": {
+                  "version": "0.1.31",
+                  "from": "source-map@0.1.31",
+                  "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.31.tgz"
+                }
+              }
+            }
+          }
+        }
+      }
     },
     "react-timer-mixin": {
       "version": "0.13.2",
diff --git a/package.json b/package.json
index fd6062f65ee3..7e3623a7c75d 100644
--- a/package.json
+++ b/package.json
@@ -91,7 +91,7 @@
     "connect": "^2.8.3",
     "debug": "^2.2.0",
     "event-target-shim": "^1.0.5",
-    "fbjs-haste": "^0.3.4",
+    "fbjs": "^0.6.0",
     "fbjs-scripts": "^0.4.0",
     "graceful-fs": "^4.1.2",
     "image-size": "^0.3.5",
@@ -106,7 +106,7 @@
     "optimist": "^0.6.1",
     "progress": "^1.1.8",
     "promise": "^7.0.4",
-    "react-haste": "^0.14.2",
+    "react": "^0.14.5",
     "react-timer-mixin": "^0.13.2",
     "rebound": "^0.0.13",
     "regenerator": "^0.8.36",

From 6a838a4201f99ae5e88b3684bb798d363815dd53 Mon Sep 17 00:00:00 2001
From: Ben Alpert <balpert@fb.com>
Date: Wed, 30 Dec 2015 11:38:44 -0800
Subject: [PATCH 0552/1411] Consume react, fbjs from npm
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Summary:
We don't (yet) treat these the same as any other modules because we still have special resolution rules for them in the packager allowing the use of `providesModule`, but I believe this allows people to use npm react in their RN projects and not have duplicate copies of React. Fixes facebook/react-native#2985.

This relies on fbjs 0.6, which includes `.flow` files alongside the `.js` files to allow them to be typechecked without additional configuration. This also uses react 0.14.5, which shims a couple of files (as `.native.js`) to avoid DOM-specific bits. Once we fix these in React, we will use the same code on web and native. Hopefully we can also remove the packager support I'm adding here for `.native.js`.

This diff is not the desired end state for us – ideally the packager would know nothing of react or fbjs, and we'll get there eventually by not relying on `providesModule` in order to load react and fbjs modules. (fbjs change posted here but not merged yet: https://github.com/facebook/fbjs/pull/84.)

This should also allow relay to work seamlessly with RN, but I haven't verified this.

public

Reviewed By: sebmarkbage

Differential Revision: D2786197

fb-gh-sync-id: ff50f28445e949edc9501f4b599df7970813870d
---
 .flowconfig                                   |  24 +-
 .../RCTLoggingTests.m                         |   2 +-
 .../eventPlugins/ResponderEventPlugin.js      | 612 ------------------
 packager/blacklist.js                         |  77 ++-
 .../DependencyGraph/HasteMap.js               |  33 +-
 .../DependencyGraph/ResolutionRequest.js      |   5 +
 .../DependencyGraph/index.js                  |   5 +-
 packager/react-packager/src/Resolver/index.js |   5 +-
 8 files changed, 89 insertions(+), 674 deletions(-)
 delete mode 100644 Libraries/vendor/react/browser/eventPlugins/ResponderEventPlugin.js

diff --git a/.flowconfig b/.flowconfig
index 503e5a92572b..53bfd25208fb 100644
--- a/.flowconfig
+++ b/.flowconfig
@@ -14,17 +14,19 @@
 
 # Ignore react and fbjs where there are overlaps, but don't ignore
 # anything that react-native relies on
-.*/node_modules/fbjs-haste/.*/__tests__/.*
-.*/node_modules/fbjs-haste/__forks__/Map.js
-.*/node_modules/fbjs-haste/__forks__/Promise.js
-.*/node_modules/fbjs-haste/__forks__/fetch.js
-.*/node_modules/fbjs-haste/core/ExecutionEnvironment.js
-.*/node_modules/fbjs-haste/core/isEmpty.js
-.*/node_modules/fbjs-haste/crypto/crc32.js
-.*/node_modules/fbjs-haste/stubs/ErrorUtils.js
-.*/node_modules/react-haste/React.js
-.*/node_modules/react-haste/renderers/dom/ReactDOM.js
-.*/node_modules/react-haste/renderers/shared/event/eventPlugins/ResponderEventPlugin.js
+.*/node_modules/fbjs/lib/Map.js
+.*/node_modules/fbjs/lib/Promise.js
+.*/node_modules/fbjs/lib/fetch.js
+.*/node_modules/fbjs/lib/ExecutionEnvironment.js
+.*/node_modules/fbjs/lib/isEmpty.js
+.*/node_modules/fbjs/lib/crc32.js
+.*/node_modules/fbjs/lib/ErrorUtils.js
+
+# Flow has a built-in definition for the 'react' module which we prefer to use
+# over the currently-untyped source
+.*/node_modules/react/react.js
+.*/node_modules/react/lib/React.js
+.*/node_modules/react/lib/ReactDOM.js
 
 # Ignore commoner tests
 .*/node_modules/commoner/test/.*
diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/RCTLoggingTests.m b/Examples/UIExplorer/UIExplorerIntegrationTests/RCTLoggingTests.m
index 0011b0524cf4..0f34cfb26e54 100644
--- a/Examples/UIExplorer/UIExplorerIntegrationTests/RCTLoggingTests.m
+++ b/Examples/UIExplorer/UIExplorerIntegrationTests/RCTLoggingTests.m
@@ -89,7 +89,7 @@ - (void)testLogging
 
   XCTAssertEqual(_lastLogLevel, RCTLogLevelError);
   XCTAssertEqual(_lastLogSource, RCTLogSourceJavaScript);
-  XCTAssertEqualObjects(_lastLogMessage, @"Invariant Violation: Invariant failed");
+  XCTAssertEqualObjects(_lastLogMessage, @"Invariant failed");
 
   [_bridge enqueueJSCall:@"LoggingTestModule.logErrorToConsole" args:@[@"Invoking console.error"]];
   dispatch_semaphore_wait(_logSem, DISPATCH_TIME_FOREVER);
diff --git a/Libraries/vendor/react/browser/eventPlugins/ResponderEventPlugin.js b/Libraries/vendor/react/browser/eventPlugins/ResponderEventPlugin.js
deleted file mode 100644
index b84985e6ba10..000000000000
--- a/Libraries/vendor/react/browser/eventPlugins/ResponderEventPlugin.js
+++ /dev/null
@@ -1,612 +0,0 @@
-/**
- * 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 ResponderEventPlugin
- */
-
-'use strict';
-
-var EventConstants = require('EventConstants');
-var EventPluginUtils = require('EventPluginUtils');
-var EventPropagators = require('EventPropagators');
-var ReactInstanceHandles = require('ReactInstanceHandles');
-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;
-var isEndish = EventPluginUtils.isEndish;
-var executeDirectDispatch = EventPluginUtils.executeDirectDispatch;
-var hasDispatches = EventPluginUtils.hasDispatches;
-var executeDispatchesInOrderStopAtTrue =
-  EventPluginUtils.executeDispatchesInOrderStopAtTrue;
-
-/**
- * ID of element that should respond to touch/move types of interactions, as
- * indicated explicitly by relevant callbacks.
- */
-var responderID = null;
-
-/**
- * Count of current touches. A textInput should become responder iff the
- * the selection changes while there is a touch on the screen.
- */
-var trackedTouchCount = 0;
-
-/**
- * Last reported number of active touches.
- */
-var previousActiveTouches = 0;
-
-var changeResponder = function(nextResponderID, blockNativeResponder) {
-  var oldResponderID = responderID;
-  responderID = nextResponderID;
-  if (ResponderEventPlugin.GlobalResponderHandler !== null) {
-    ResponderEventPlugin.GlobalResponderHandler.onChange(
-      oldResponderID,
-      nextResponderID,
-      blockNativeResponder
-    );
-  }
-};
-
-var eventTypes = {
-  /**
-   * On a `touchStart`/`mouseDown`, is it desired that this element become the
-   * responder?
-   */
-  startShouldSetResponder: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onStartShouldSetResponder: null}),
-      captured: keyOf({onStartShouldSetResponderCapture: null}),
-    },
-  },
-
-  /**
-   * On a `scroll`, is it desired that this element become the responder? This
-   * is usually not needed, but should be used to retroactively infer that a
-   * `touchStart` had occured during momentum scroll. During a momentum scroll,
-   * a touch start will be immediately followed by a scroll event if the view is
-   * currently scrolling.
-   *
-   * TODO: This shouldn't bubble.
-   */
-  scrollShouldSetResponder: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onScrollShouldSetResponder: null}),
-      captured: keyOf({onScrollShouldSetResponderCapture: null}),
-    },
-  },
-
-  /**
-   * On text selection change, should this element become the responder? This
-   * is needed for text inputs or other views with native selection, so the
-   * JS view can claim the responder.
-   *
-   * TODO: This shouldn't bubble.
-   */
-  selectionChangeShouldSetResponder: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onSelectionChangeShouldSetResponder: null}),
-      captured: keyOf({onSelectionChangeShouldSetResponderCapture: null}),
-    },
-  },
-
-  /**
-   * On a `touchMove`/`mouseMove`, is it desired that this element become the
-   * responder?
-   */
-  moveShouldSetResponder: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onMoveShouldSetResponder: null}),
-      captured: keyOf({onMoveShouldSetResponderCapture: null}),
-    },
-  },
-
-  /**
-   * 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})},
-  responderTerminationRequest: {
-    registrationName: keyOf({onResponderTerminationRequest: null}),
-  },
-  responderGrant: {registrationName: keyOf({onResponderGrant: null})},
-  responderReject: {registrationName: keyOf({onResponderReject: null})},
-  responderTerminate: {registrationName: keyOf({onResponderTerminate: null})},
-};
-
-/**
- *
- * Responder System:
- * ----------------
- *
- * - A global, solitary "interaction lock" on a view.
- * - If a node becomes the responder, it should convey visual feedback
- *   immediately to indicate so, either by highlighting or moving accordingly.
- * - To be the responder means, that touches are exclusively important to that
- *   responder view, and no other view.
- * - While touches are still occuring, the responder lock can be transfered to
- *   a new view, but only to increasingly "higher" views (meaning ancestors of
- *   the current responder).
- *
- * Responder being granted:
- * ------------------------
- *
- * - Touch starts, moves, and scrolls can cause an ID to become the responder.
- * - We capture/bubble `startShouldSetResponder`/`moveShouldSetResponder` to
- *   the "appropriate place".
- * - If nothing is currently the responder, the "appropriate place" is the
- *   initiating event's `targetID`.
- * - If something *is* already the responder, the "appropriate place" is the
- *   first common ancestor of the event target and the current `responderID`.
- * - Some negotiation happens: See the timing diagram below.
- * - Scrolled views automatically become responder. The reasoning is that a
- *   platform scroll view that isn't built on top of the responder system has
- *   began scrolling, and the active responder must now be notified that the
- *   interaction is no longer locked to it - the system has taken over.
- *
- * - Responder being released:
- *   As soon as no more touches that *started* inside of descendents of the
- *   *current* responderID, an `onResponderRelease` event is dispatched to the
- *   current responder, and the responder lock is released.
- *
- * TODO:
- * - on "end", a callback hook for `onResponderEndShouldRemainResponder` that
- *   determines if the responder lock should remain.
- * - If a view shouldn't "remain" the responder, any active touches should by
- *   default be considered "dead" and do not influence future negotiations or
- *   bubble paths. It should be as if those touches do not exist.
- * -- For multitouch: Usually a translate-z will choose to "remain" responder
- *  after one out of many touches ended. For translate-y, usually the view
- *  doesn't wish to "remain" responder after one of many touches end.
- * - Consider building this on top of a `stopPropagation` model similar to
- *   `W3C` events.
- * - Ensure that `onResponderTerminate` is called on touch cancels, whether or
- *   not `onResponderTerminationRequest` returns `true` or `false`.
- *
- */
-
-/*                                             Negotiation Performed
-                                             +-----------------------+
-                                            /                         \
-Process low level events to    +     Current Responder      +   wantsResponderID
-determine who to perform negot-|   (if any exists at all)   |
-iation/transition              | Otherwise just pass through|
--------------------------------+----------------------------+------------------+
-Bubble to find first ID        |                            |
-to return true:wantsResponderID|                            |
-                               |                            |
-     +-------------+           |                            |
-     | onTouchStart|           |                            |
-     +------+------+     none  |                            |
-            |            return|                            |
-+-----------v-------------+true| +------------------------+ |
-|onStartShouldSetResponder|----->|onResponderStart (cur)  |<-----------+
-+-----------+-------------+    | +------------------------+ |          |
-            |                  |                            | +--------+-------+
-            | returned true for|       false:REJECT +-------->|onResponderReject
-            | wantsResponderID |                    |       | +----------------+
-            | (now attempt     | +------------------+-----+ |
-            |  handoff)        | |   onResponder          | |
-            +------------------->|      TerminationRequest| |
-                               | +------------------+-----+ |
-                               |                    |       | +----------------+
-                               |         true:GRANT +-------->|onResponderGrant|
-                               |                            | +--------+-------+
-                               | +------------------------+ |          |
-                               | |   onResponderTerminate |<-----------+
-                               | +------------------+-----+ |
-                               |                    |       | +----------------+
-                               |                    +-------->|onResponderStart|
-                               |                            | +----------------+
-Bubble to find first ID        |                            |
-to return true:wantsResponderID|                            |
-                               |                            |
-     +-------------+           |                            |
-     | onTouchMove |           |                            |
-     +------+------+     none  |                            |
-            |            return|                            |
-+-----------v-------------+true| +------------------------+ |
-|onMoveShouldSetResponder |----->|onResponderMove (cur)   |<-----------+
-+-----------+-------------+    | +------------------------+ |          |
-            |                  |                            | +--------+-------+
-            | returned true for|       false:REJECT +-------->|onResponderRejec|
-            | wantsResponderID |                    |       | +----------------+
-            | (now attempt     | +------------------+-----+ |
-            |  handoff)        | |   onResponder          | |
-            +------------------->|      TerminationRequest| |
-                               | +------------------+-----+ |
-                               |                    |       | +----------------+
-                               |         true:GRANT +-------->|onResponderGrant|
-                               |                            | +--------+-------+
-                               | +------------------------+ |          |
-                               | |   onResponderTerminate |<-----------+
-                               | +------------------+-----+ |
-                               |                    |       | +----------------+
-                               |                    +-------->|onResponderMove |
-                               |                            | +----------------+
-                               |                            |
-                               |                            |
-      Some active touch started|                            |
-      inside current responder | +------------------------+ |
-      +------------------------->|      onResponderEnd    | |
-      |                        | +------------------------+ |
-  +---+---------+              |                            |
-  | onTouchEnd  |              |                            |
-  +---+---------+              |                            |
-      |                        | +------------------------+ |
-      +------------------------->|     onResponderEnd     | |
-      No active touches started| +-----------+------------+ |
-      inside current responder |             |              |
-                               |             v              |
-                               | +------------------------+ |
-                               | |    onResponderRelease  | |
-                               | +------------------------+ |
-                               |                            |
-                               +                            + */
-
-
-
-/**
- * A note about event ordering in the `EventPluginHub`.
- *
- * Suppose plugins are injected in the following order:
- *
- * `[R, S, C]`
- *
- * To help illustrate the example, assume `S` is `SimpleEventPlugin` (for
- * `onClick` etc) and `R` is `ResponderEventPlugin`.
- *
- * "Deferred-Dispatched Events":
- *
- * - The current event plugin system will traverse the list of injected plugins,
- *   in order, and extract events by collecting the plugin's return value of
- *   `extractEvents()`.
- * - These events that are returned from `extractEvents` are "deferred
- *   dispatched events".
- * - When returned from `extractEvents`, deferred-dispatched events contain an
- *   "accumulation" of deferred dispatches.
- * - These deferred dispatches are accumulated/collected before they are
- *   returned, but processed at a later time by the `EventPluginHub` (hence the
- *   name deferred).
- *
- * In the process of returning their deferred-dispatched events, event plugins
- * themselves can dispatch events on-demand without returning them from
- * `extractEvents`. Plugins might want to do this, so that they can use event
- * dispatching as a tool that helps them decide which events should be extracted
- * in the first place.
- *
- * "On-Demand-Dispatched Events":
- *
- * - On-demand-dispatched events are not returned from `extractEvents`.
- * - On-demand-dispatched events are dispatched during the process of returning
- *   the deferred-dispatched events.
- * - They should not have side effects.
- * - They should be avoided, and/or eventually be replaced with another
- *   abstraction that allows event plugins to perform multiple "rounds" of event
- *   extraction.
- *
- * Therefore, the sequence of event dispatches becomes:
- *
- * - `R`s on-demand events (if any)   (dispatched by `R` on-demand)
- * - `S`s on-demand events (if any)   (dispatched by `S` on-demand)
- * - `C`s on-demand events (if any)   (dispatched by `C` on-demand)
- * - `R`s extracted events (if any)   (dispatched by `EventPluginHub`)
- * - `S`s extracted events (if any)   (dispatched by `EventPluginHub`)
- * - `C`s extracted events (if any)   (dispatched by `EventPluginHub`)
- *
- * In the case of `ResponderEventPlugin`: If the `startShouldSetResponder`
- * on-demand dispatch returns `true` (and some other details are satisfied) the
- * `onResponderGrant` deferred dispatched event is returned from
- * `extractEvents`. The sequence of dispatch executions in this case
- * will appear as follows:
- *
- * - `startShouldSetResponder` (`ResponderEventPlugin` dispatches on-demand)
- * - `touchStartCapture`       (`EventPluginHub` dispatches as usual)
- * - `touchStart`              (`EventPluginHub` dispatches as usual)
- * - `responderGrant/Reject`   (`EventPluginHub` dispatches as usual)
- *
- * @param {string} topLevelType Record from `EventConstants`.
- * @param {string} topLevelTargetID ID of deepest React rendered element.
- * @param {object} nativeEvent Native browser event.
- * @return {*} An accumulation of synthetic events.
- */
-function setResponderAndExtractTransfer(
-    topLevelType,
-    topLevelTargetID,
-    nativeEvent,
-    nativeEventTarget) {
-  var shouldSetEventType =
-    isStartish(topLevelType) ? eventTypes.startShouldSetResponder :
-    isMoveish(topLevelType) ? eventTypes.moveShouldSetResponder :
-    topLevelType === EventConstants.topLevelTypes.topSelectionChange ?
-      eventTypes.selectionChangeShouldSetResponder :
-    eventTypes.scrollShouldSetResponder;
-
-  // TODO: stop one short of the the current responder.
-  var bubbleShouldSetFrom = !responderID ?
-    topLevelTargetID :
-    ReactInstanceHandles.getFirstCommonAncestorID(responderID, topLevelTargetID);
-
-  // When capturing/bubbling the "shouldSet" event, we want to skip the target
-  // (deepest ID) if it happens to be the current responder. The reasoning:
-  // It's strange to get an `onMoveShouldSetResponder` when you're *already*
-  // the responder.
-  var skipOverBubbleShouldSetFrom = bubbleShouldSetFrom === responderID;
-  var shouldSetEvent = ResponderSyntheticEvent.getPooled(
-    shouldSetEventType,
-    bubbleShouldSetFrom,
-    nativeEvent,
-    nativeEventTarget
-  );
-  shouldSetEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
-  if (skipOverBubbleShouldSetFrom) {
-    EventPropagators.accumulateTwoPhaseDispatchesSkipTarget(shouldSetEvent);
-  } else {
-    EventPropagators.accumulateTwoPhaseDispatches(shouldSetEvent);
-  }
-  var wantsResponderID = executeDispatchesInOrderStopAtTrue(shouldSetEvent);
-  if (!shouldSetEvent.isPersistent()) {
-    shouldSetEvent.constructor.release(shouldSetEvent);
-  }
-
-  if (!wantsResponderID || wantsResponderID === responderID) {
-    return null;
-  }
-  var extracted;
-  var grantEvent = ResponderSyntheticEvent.getPooled(
-    eventTypes.responderGrant,
-    wantsResponderID,
-    nativeEvent,
-    nativeEventTarget
-  );
-  grantEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
-
-  EventPropagators.accumulateDirectDispatches(grantEvent);
-  var blockNativeResponder = executeDirectDispatch(grantEvent) === true;
-  if (responderID) {
-
-    var terminationRequestEvent = ResponderSyntheticEvent.getPooled(
-      eventTypes.responderTerminationRequest,
-      responderID,
-      nativeEvent,
-      nativeEventTarget
-    );
-    terminationRequestEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
-    EventPropagators.accumulateDirectDispatches(terminationRequestEvent);
-    var shouldSwitch = !hasDispatches(terminationRequestEvent) ||
-      executeDirectDispatch(terminationRequestEvent);
-    if (!terminationRequestEvent.isPersistent()) {
-      terminationRequestEvent.constructor.release(terminationRequestEvent);
-    }
-
-    if (shouldSwitch) {
-      var terminateType = eventTypes.responderTerminate;
-      var terminateEvent = ResponderSyntheticEvent.getPooled(
-        terminateType,
-        responderID,
-        nativeEvent,
-        nativeEventTarget
-      );
-      terminateEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
-      EventPropagators.accumulateDirectDispatches(terminateEvent);
-      extracted = accumulate(extracted, [grantEvent, terminateEvent]);
-      changeResponder(wantsResponderID, blockNativeResponder);
-    } else {
-      var rejectEvent = ResponderSyntheticEvent.getPooled(
-        eventTypes.responderReject,
-        wantsResponderID,
-        nativeEvent,
-        nativeEventTarget
-      );
-      rejectEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
-      EventPropagators.accumulateDirectDispatches(rejectEvent);
-      extracted = accumulate(extracted, rejectEvent);
-    }
-  } else {
-    extracted = accumulate(extracted, grantEvent);
-    changeResponder(wantsResponderID, blockNativeResponder);
-  }
-  return extracted;
-}
-
-/**
- * A transfer is a negotiation between a currently set responder and the next
- * element to claim responder status. Any start event could trigger a transfer
- * of responderID. Any move event could trigger a transfer.
- *
- * @param {string} topLevelType Record from `EventConstants`.
- * @return {boolean} True if a transfer of responder could possibly occur.
- */
-function canTriggerTransfer(topLevelType, topLevelTargetID, nativeEvent) {
-  return topLevelTargetID && (
-    // 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)
-  );
-}
-
-/**
- * Returns whether or not this touch end event makes it such that there are no
- * longer any touches that started inside of the current `responderID`.
- *
- * @param {NativeEvent} nativeEvent Native touch end event.
- * @return {boolean} Whether or not this touch end event ends the responder.
- */
-function noResponderTouches(nativeEvent) {
-  var touches = nativeEvent.touches;
-  if (!touches || touches.length === 0) {
-    return true;
-  }
-  for (var i = 0; i < touches.length; i++) {
-    var activeTouch = touches[i];
-    var target = activeTouch.target;
-    if (target !== null && target !== undefined && target !== 0) {
-      // Is the original touch location inside of the current responder?
-      var isAncestor =
-        ReactInstanceHandles.isAncestorIDOf(
-          responderID,
-          EventPluginUtils.getID(target)
-        );
-      if (isAncestor) {
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-
-var ResponderEventPlugin = {
-
-  getResponderID: function() {
-    return responderID;
-  },
-
-  eventTypes: eventTypes,
-
-  /**
-   * We must be resilient to `topLevelTargetID` being `undefined` on
-   * `touchMove`, or `touchEnd`. On certain platforms, this means that a native
-   * scroll has assumed control and the original touch targets are destroyed.
-   *
-   * @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 (isStartish(topLevelType)) {
-      trackedTouchCount += 1;
-    } else if (isEndish(topLevelType)) {
-      trackedTouchCount -= 1;
-      invariant(
-        trackedTouchCount >= 0,
-        'Ended a touch event which was not counted in trackedTouchCount.'
-      );
-    }
-
-    ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent, nativeEventTarget);
-
-    var extracted = canTriggerTransfer(topLevelType, topLevelTargetID, nativeEvent) ?
-      setResponderAndExtractTransfer(
-        topLevelType,
-        topLevelTargetID,
-        nativeEvent,
-        nativeEventTarget) :
-      null;
-    // Responder may or may not have transfered 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
-    // `onResponderMove/Start/End`. These will be called for *every* additional
-    // finger that move/start/end, dispatched directly to whoever is the
-    // current responder at that moment, until the responder is "released".
-    //
-    // These multiple individual change touch events are are always bookended
-    // by `onResponderGrant`, and one of
-    // (`onResponderRelease/onResponderTerminate`).
-    var isResponderTouchStart = responderID && isStartish(topLevelType);
-    var isResponderTouchMove = responderID && isMoveish(topLevelType);
-    var isResponderTouchEnd = responderID && isEndish(topLevelType);
-    var incrementalTouch =
-      isResponderTouchStart ? eventTypes.responderStart :
-      isResponderTouchMove ? eventTypes.responderMove :
-      isResponderTouchEnd ? eventTypes.responderEnd :
-      null;
-
-    if (incrementalTouch) {
-      var gesture =
-        ResponderSyntheticEvent.getPooled(
-          incrementalTouch,
-          responderID,
-          nativeEvent,
-          nativeEventTarget
-        );
-      gesture.touchHistory = ResponderTouchHistoryStore.touchHistory;
-      EventPropagators.accumulateDirectDispatches(gesture);
-      extracted = accumulate(extracted, gesture);
-    }
-
-    var isResponderTerminate =
-      responderID &&
-      topLevelType === EventConstants.topLevelTypes.topTouchCancel;
-    var isResponderRelease =
-      responderID &&
-      !isResponderTerminate &&
-      isEndish(topLevelType) &&
-      noResponderTouches(nativeEvent);
-    var finalTouch =
-      isResponderTerminate ? eventTypes.responderTerminate :
-      isResponderRelease ? eventTypes.responderRelease :
-      null;
-    if (finalTouch) {
-      var finalEvent =
-        ResponderSyntheticEvent.getPooled(finalTouch, responderID, nativeEvent, nativeEventTarget);
-      finalEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
-      EventPropagators.accumulateDirectDispatches(finalEvent);
-      extracted = accumulate(extracted, finalEvent);
-      changeResponder(null);
-    }
-
-    var numberActiveTouches =
-      ResponderTouchHistoryStore.touchHistory.numberActiveTouches;
-    if (ResponderEventPlugin.GlobalInteractionHandler &&
-      numberActiveTouches !== previousActiveTouches) {
-      ResponderEventPlugin.GlobalInteractionHandler.onChange(
-        numberActiveTouches
-      );
-    }
-    previousActiveTouches = numberActiveTouches;
-
-    return extracted;
-  },
-
-  GlobalResponderHandler: null,
-  GlobalInteractionHandler: null,
-
-  injection: {
-    /**
-     * @param {{onChange: (ReactID, ReactID) => void} GlobalResponderHandler
-     * Object that handles any change in responder. Use this to inject
-     * integration with an existing touch handling system etc.
-     */
-    injectGlobalResponderHandler: function(GlobalResponderHandler) {
-      ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler;
-    },
-
-    /**
-     * @param {{onChange: (numberActiveTouches) => void} GlobalInteractionHandler
-     * Object that handles any change in the number of active touches.
-     */
-    injectGlobalInteractionHandler: function(GlobalInteractionHandler) {
-      ResponderEventPlugin.GlobalInteractionHandler = GlobalInteractionHandler;
-    },
-  },
-};
-
-module.exports = ResponderEventPlugin;
diff --git a/packager/blacklist.js b/packager/blacklist.js
index 863e2a9acc25..05973c286e9e 100644
--- a/packager/blacklist.js
+++ b/packager/blacklist.js
@@ -13,36 +13,41 @@ var path = require('path');
 // Don't forget to everything listed here to `testConfig.json`
 // modulePathIgnorePatterns.
 var sharedBlacklist = [
-  'node_modules/react-haste/renderers/shared/event/eventPlugins/ResponderEventPlugin.js',
-  'node_modules/react-haste/React.js',
-  'node_modules/react-haste/renderers/dom/ReactDOM.js',
+  /node_modules[/\\]react[/\\]dist[/\\].*/,
+  'node_modules/react/lib/React.js',
+  'node_modules/react/lib/ReactDOM.js',
 
   // For each of these fbjs files (especially the non-forks/stubs), we should
   // consider deleting the conflicting copy and just using the fbjs version.
-  'node_modules/fbjs-haste/__forks__/Map.js',
-  'node_modules/fbjs-haste/__forks__/Promise.js',
-  'node_modules/fbjs-haste/__forks__/fetch.js',
-  'node_modules/fbjs-haste/core/Deferred.js',
-  'node_modules/fbjs-haste/core/PromiseMap.js',
-  'node_modules/fbjs-haste/core/areEqual.js',
-  'node_modules/fbjs-haste/core/flattenArray.js',
-  'node_modules/fbjs-haste/core/isEmpty.js',
-  'node_modules/fbjs-haste/core/removeFromArray.js',
-  'node_modules/fbjs-haste/core/resolveImmediate.js',
-  'node_modules/fbjs-haste/core/sprintf.js',
-  'node_modules/fbjs-haste/crypto/crc32.js',
-  'node_modules/fbjs-haste/fetch/fetchWithRetries.js',
-  'node_modules/fbjs-haste/functional/everyObject.js',
-  'node_modules/fbjs-haste/functional/filterObject.js',
-  'node_modules/fbjs-haste/functional/forEachObject.js',
-  'node_modules/fbjs-haste/functional/someObject.js',
-  'node_modules/fbjs-haste/request/xhrSimpleDataSerializer.js',
-  'node_modules/fbjs-haste/stubs/ErrorUtils.js',
-  'node_modules/fbjs-haste/stubs/URI.js',
-  'node_modules/fbjs-haste/useragent/UserAgent.js',
-  'node_modules/fbjs-haste/utils/nullthrows.js',
+  //
+  // fbjs forks:
+  'node_modules/fbjs/lib/Map.js',
+  'node_modules/fbjs/lib/Promise.js',
+  'node_modules/fbjs/lib/fetch.js',
+  // fbjs stubs:
+  'node_modules/fbjs/lib/ErrorUtils.js',
+  'node_modules/fbjs/lib/URI.js',
+  // fbjs modules:
+  'node_modules/fbjs/lib/Deferred.js',
+  'node_modules/fbjs/lib/PromiseMap.js',
+  'node_modules/fbjs/lib/UserAgent.js',
+  'node_modules/fbjs/lib/areEqual.js',
+  'node_modules/fbjs/lib/base62.js',
+  'node_modules/fbjs/lib/crc32.js',
+  'node_modules/fbjs/lib/everyObject.js',
+  'node_modules/fbjs/lib/fetchWithRetries.js',
+  'node_modules/fbjs/lib/filterObject.js',
+  'node_modules/fbjs/lib/flattenArray.js',
+  'node_modules/fbjs/lib/forEachObject.js',
+  'node_modules/fbjs/lib/isEmpty.js',
+  'node_modules/fbjs/lib/nullthrows.js',
+  'node_modules/fbjs/lib/removeFromArray.js',
+  'node_modules/fbjs/lib/resolveImmediate.js',
+  'node_modules/fbjs/lib/someObject.js',
+  'node_modules/fbjs/lib/sprintf.js',
+  'node_modules/fbjs/lib/xhrSimpleDataSerializer.js',
 
-  // Those conflicts with the ones in fbjs-haste/. We need to blacklist the
+  // Those conflicts with the ones in fbjs/. We need to blacklist the
   // internal version otherwise they won't work in open source.
   'downstream/core/CSSCore.js',
   'downstream/core/TouchEventUtils.js',
@@ -63,11 +68,8 @@ var sharedBlacklist = [
   'downstream/core/invariant.js',
   'downstream/core/nativeRequestAnimationFrame.js',
   'downstream/core/toArray.js',
-];
 
-// Raw unescaped patterns in case you need to use wildcards
-var sharedBlacklistWildcards = [
-  'website\/node_modules\/.*',
+  /website\/node_modules\/.*/,
 ];
 
 var platformBlacklists = {
@@ -85,10 +87,16 @@ var platformBlacklists = {
   ],
 };
 
-function escapeRegExp(str) {
-  var escaped = str.replace(/[\-\[\]\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
-  // convert the '/' into an escaped local file separator
-  return escaped.replace(/\//g,'\\' + path.sep);
+function escapeRegExp(pattern) {
+  if (Object.prototype.toString.call(pattern) === '[object RegExp]') {
+    return pattern.source;
+  } else if (typeof pattern === 'string') {
+    var escaped = pattern.replace(/[\-\[\]\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
+    // convert the '/' into an escaped local file separator
+    return escaped.replace(/\//g,'\\' + path.sep);
+  } else {
+    throw new Error('Unexpected packager blacklist pattern: ' + pattern);
+  }
 }
 
 function blacklist(platform, additionalBlacklist) {
@@ -96,7 +104,6 @@ function blacklist(platform, additionalBlacklist) {
     (additionalBlacklist || []).concat(sharedBlacklist)
       .concat(platformBlacklists[platform] || [])
       .map(escapeRegExp)
-      .concat(sharedBlacklistWildcards)
       .join('|') +
     ')$'
   );
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/HasteMap.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/HasteMap.js
index 38d27e3e3b66..2f0b26af4773 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/HasteMap.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/HasteMap.js
@@ -12,12 +12,20 @@ const getPlatformExtension = require('../lib/getPlatformExtension');
 const Promise = require('promise');
 
 const GENERIC_PLATFORM = 'generic';
+const NATIVE_PLATFORM = 'native';
 
 class HasteMap {
-  constructor({ extensions, fastfs, moduleCache, helpers }) {
+  constructor({
+    extensions,
+    fastfs,
+    moduleCache,
+    preferNativePlatform,
+    helpers,
+  }) {
     this._extensions = extensions;
     this._fastfs = fastfs;
     this._moduleCache = moduleCache;
+    this._preferNativePlatform = preferNativePlatform;
     this._helpers = helpers;
   }
 
@@ -73,18 +81,19 @@ class HasteMap {
       return null;
     }
 
-    // If no platform is given we choose the generic platform module list.
-    // If a platform is given and no modules exist we fallback
-    // to the generic platform module list.
-    if (platform == null) {
-      return modulesMap[GENERIC_PLATFORM];
-    } else {
-      let module = modulesMap[platform];
-      if (module == null) {
-        module = modulesMap[GENERIC_PLATFORM];
-      }
-      return module;
+    // If platform is 'ios', we prefer .ios.js to .native.js which we prefer to
+    // a plain .js file.
+    let module = undefined;
+    if (module == null && platform != null) {
+      module = modulesMap[platform];
+    }
+    if (module == null && this._preferNativePlatform) {
+      module = modulesMap[NATIVE_PLATFORM];
+    }
+    if (module == null) {
+      module = modulesMap[GENERIC_PLATFORM];
     }
+    return module;
   }
 
   _processHasteModule(file) {
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
index 2125b97f8602..f896de27c80c 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
@@ -18,6 +18,7 @@ const Promise = require('promise');
 class ResolutionRequest {
   constructor({
     platform,
+    preferNativePlatform,
     entryPath,
     hasteMap,
     deprecatedAssetMap,
@@ -26,6 +27,7 @@ class ResolutionRequest {
     fastfs,
   }) {
     this._platform = platform;
+    this._preferNativePlatform = preferNativePlatform;
     this._entryPath = entryPath;
     this._hasteMap = hasteMap;
     this._deprecatedAssetMap = deprecatedAssetMap;
@@ -329,6 +331,9 @@ class ResolutionRequest {
       } else if (this._platform != null &&
                  this._fastfs.fileExists(potentialModulePath + '.' + this._platform + '.js')) {
         file = potentialModulePath + '.' + this._platform + '.js';
+      } else if (this._preferNativePlatform &&
+                 this._fastfs.fileExists(potentialModulePath + '.native.js')) {
+        file = potentialModulePath + '.native.js';
       } else if (this._fastfs.fileExists(potentialModulePath + '.js')) {
         file = potentialModulePath + '.js';
       } else if (this._fastfs.fileExists(potentialModulePath + '.json')) {
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
index ac88a2e37c99..c4e983ad9072 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
@@ -37,6 +37,7 @@ class DependencyGraph {
     assetExts,
     providesModuleNodeModules,
     platforms,
+    preferNativePlatform,
     cache,
     extensions,
     mocksPattern,
@@ -51,6 +52,7 @@ class DependencyGraph {
       assetExts: assetExts || [],
       providesModuleNodeModules,
       platforms: platforms || [],
+      preferNativePlatform: preferNativePlatform || false,
       cache,
       extensions: extensions || ['js', 'json'],
       mocksPattern,
@@ -105,7 +107,7 @@ class DependencyGraph {
       fastfs: this._fastfs,
       extensions: this._opts.extensions,
       moduleCache: this._moduleCache,
-      assetExts: this._opts.exts,
+      preferNativePlatform: this._opts.preferNativePlatform,
       helpers: this._helpers,
     });
 
@@ -147,6 +149,7 @@ class DependencyGraph {
       const absPath = this._getAbsolutePath(entryPath);
       const req = new ResolutionRequest({
         platform,
+        preferNativePlatform: this._opts.preferNativePlatform,
         entryPath: absPath,
         deprecatedAssetMap: this._deprecatedAssetMap,
         hasteMap: this._hasteMap,
diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index d0f9228569f4..ecc9eeebeb62 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -81,8 +81,8 @@ class Resolver {
           (opts.blacklistRE && opts.blacklistRE.test(filepath));
       },
       providesModuleNodeModules: [
-        'fbjs-haste',
-        'react-haste',
+        'fbjs',
+        'react',
         'react-native',
         // Parse requires AsyncStorage. They will
         // change that to require('react-native') which
@@ -92,6 +92,7 @@ class Resolver {
         'react-transform-hmr',
       ],
       platforms: ['ios', 'android'],
+      preferNativePlatform: true,
       fileWatcher: opts.fileWatcher,
       cache: opts.cache,
     });

From 71723ec3ec7521336b9c1923de40b88e9d0e9739 Mon Sep 17 00:00:00 2001
From: Ben Alpert <balpert@fb.com>
Date: Wed, 30 Dec 2015 13:07:42 -0800
Subject: [PATCH 0553/1411] Fix path to react in shrinkwrap

Summary:
Oops. This breaks npm install in OSS.

public

Reviewed By: bestander

Differential Revision: D2795946

fb-gh-sync-id: 949755feafdd00482ba58b9553d07886e21625f0
---
 npm-shrinkwrap.json | 104 ++++++++++++++++++++++----------------------
 1 file changed, 52 insertions(+), 52 deletions(-)

diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index f88dce93c4fc..2b98efba245b 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -146,11 +146,6 @@
           "version": "2.2.0",
           "from": "debug@>=2.1.1 <3.0.0"
         },
-        "globals": {
-          "version": "6.4.1",
-          "from": "globals@>=6.4.0 <7.0.0",
-          "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
-        },
         "js-tokens": {
           "version": "1.0.1",
           "from": "js-tokens@1.0.1",
@@ -161,6 +156,11 @@
           "from": "recast@0.10.33",
           "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
         },
+        "globals": {
+          "version": "6.4.1",
+          "from": "globals@>=6.4.0 <7.0.0",
+          "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
+        },
         "regenerator": {
           "version": "0.8.40",
           "from": "regenerator@0.8.40",
@@ -274,15 +274,20 @@
           "from": "babylon@>=5.8.29 <6.0.0",
           "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz"
         },
+        "globals": {
+          "version": "6.4.1",
+          "from": "globals@>=6.4.0 <7.0.0",
+          "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
+        },
         "esprima-fb": {
           "version": "15001.1001.0-dev-harmony-fb",
           "from": "esprima-fb@>=15001.1001.0-dev-harmony-fb <15001.1002.0",
           "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz"
         },
-        "globals": {
-          "version": "6.4.1",
-          "from": "globals@>=6.4.0 <7.0.0",
-          "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
+        "js-tokens": {
+          "version": "1.0.1",
+          "from": "js-tokens@1.0.1",
+          "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
         },
         "recast": {
           "version": "0.10.33",
@@ -294,11 +299,6 @@
           "from": "regenerator@0.8.40",
           "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
         },
-        "js-tokens": {
-          "version": "1.0.1",
-          "from": "js-tokens@1.0.1",
-          "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
-        },
         "source-map": {
           "version": "0.5.3",
           "from": "source-map@>=0.5.0 <0.6.0",
@@ -1854,35 +1854,40 @@
             }
           }
         },
+        "abbrev": {
+          "version": "1.0.7",
+          "from": "abbrev@1",
+          "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz"
+        },
         "ansi": {
           "version": "0.3.0",
           "from": "ansi@~0.3.0",
           "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.0.tgz"
         },
-        "abbrev": {
-          "version": "1.0.7",
-          "from": "abbrev@1",
-          "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz"
+        "ansi-regex": {
+          "version": "2.0.0",
+          "from": "ansi-regex@^2.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
         },
         "ansi-styles": {
           "version": "2.1.0",
           "from": "ansi-styles@^2.1.0",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz"
         },
-        "ansi-regex": {
-          "version": "2.0.0",
-          "from": "ansi-regex@^2.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
+        "asn1": {
+          "version": "0.1.11",
+          "from": "asn1@0.1.11",
+          "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
         },
         "are-we-there-yet": {
           "version": "1.0.4",
           "from": "are-we-there-yet@~1.0.0",
           "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.4.tgz"
         },
-        "asn1": {
-          "version": "0.1.11",
-          "from": "asn1@0.1.11",
-          "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
+        "async": {
+          "version": "1.5.0",
+          "from": "async@^1.4.0",
+          "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz"
         },
         "assert-plus": {
           "version": "0.1.5",
@@ -1894,11 +1899,6 @@
           "from": "aws-sign2@~0.6.0",
           "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
         },
-        "async": {
-          "version": "1.5.0",
-          "from": "async@^1.4.0",
-          "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz"
-        },
         "balanced-match": {
           "version": "0.2.1",
           "from": "balanced-match@>=0.2.0 <0.3.0",
@@ -2154,16 +2154,16 @@
           "from": "node-uuid@~1.4.3",
           "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.3.tgz"
         },
-        "npmlog": {
-          "version": "1.2.1",
-          "from": "npmlog@~1.2.0",
-          "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz"
-        },
         "oauth-sign": {
           "version": "0.8.0",
           "from": "oauth-sign@~0.8.0",
           "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.0.tgz"
         },
+        "npmlog": {
+          "version": "1.2.1",
+          "from": "npmlog@~1.2.0",
+          "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz"
+        },
         "once": {
           "version": "1.1.1",
           "from": "once@~1.1.1",
@@ -2174,16 +2174,16 @@
           "from": "path-is-absolute@>=1.0.0 <2.0.0",
           "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz"
         },
-        "pinkie": {
-          "version": "1.0.0",
-          "from": "pinkie@^1.0.0",
-          "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
-        },
         "pinkie-promise": {
           "version": "1.0.0",
           "from": "pinkie-promise@^1.0.0",
           "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz"
         },
+        "pinkie": {
+          "version": "1.0.0",
+          "from": "pinkie@^1.0.0",
+          "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
+        },
         "qs": {
           "version": "5.2.0",
           "from": "qs@~5.2.0",
@@ -2199,16 +2199,16 @@
           "from": "request@2.x",
           "resolved": "https://registry.npmjs.org/request/-/request-2.65.0.tgz"
         },
-        "sntp": {
-          "version": "1.0.9",
-          "from": "sntp@1.x.x",
-          "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
-        },
         "semver": {
           "version": "5.0.3",
           "from": "semver@~5.0.1",
           "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
         },
+        "sntp": {
+          "version": "1.0.9",
+          "from": "sntp@1.x.x",
+          "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
+        },
         "string_decoder": {
           "version": "0.10.31",
           "from": "string_decoder@~0.10.x",
@@ -2219,11 +2219,6 @@
           "from": "stringstream@~0.0.4",
           "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
         },
-        "supports-color": {
-          "version": "2.0.0",
-          "from": "supports-color@^2.0.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
-        },
         "strip-ansi": {
           "version": "3.0.0",
           "from": "strip-ansi@^3.0.0",
@@ -2234,6 +2229,11 @@
           "from": "strip-json-comments@0.1.x",
           "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
         },
+        "supports-color": {
+          "version": "2.0.0",
+          "from": "supports-color@^2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
+        },
         "tar": {
           "version": "2.2.1",
           "from": "tar@~2.2.0",
@@ -4170,7 +4170,7 @@
     "react": {
       "version": "0.14.5",
       "from": "react@>=0.14.5 <0.15.0",
-      "resolved": "file:build/packages/react.tgz",
+      "resolved": "https://registry.npmjs.org/react/-/react-0.14.5.tgz",
       "dependencies": {
         "envify": {
           "version": "3.4.0",

From f93cf6ca1921b8bd252866c40b52cb2a6a20ae2f Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Wed, 30 Dec 2015 13:22:35 -0800
Subject: [PATCH 0554/1411] Fix android activity template. Fixes #5030

Summary: Closes https://github.com/facebook/react-native/pull/5033

Reviewed By: svcscm

Differential Revision: D2794157

Pulled By: androidtrunkagent

fb-gh-sync-id: 9d30b3a661b18be31d246dc3f55c429cc4b51a8a
---
 .../generator-android/templates/package/MainActivity.java   | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/local-cli/generator-android/templates/package/MainActivity.java b/local-cli/generator-android/templates/package/MainActivity.java
index ab8626844bbb..33741846563b 100644
--- a/local-cli/generator-android/templates/package/MainActivity.java
+++ b/local-cli/generator-android/templates/package/MainActivity.java
@@ -1,8 +1,12 @@
 package <%= package %>;
 
 import com.facebook.react.ReactActivity;
+import com.facebook.react.ReactPackage;
 import com.facebook.react.shell.MainReactPackage;
 
+import java.util.Arrays;
+import java.util.List;
+
 public class MainActivity extends ReactActivity {
 
     /**
@@ -28,7 +32,7 @@ protected boolean getUseDeveloperSupport() {
    * or modules besides the default ones, add more packages here.
    */
     @Override
-    protected abstract List<ReactPackage> getPackages() {
+    protected List<ReactPackage> getPackages() {
       return Arrays.<ReactPackage>asList(
         new MainReactPackage());
     }

From 3955bebb74f10e6585713a0633cc64aca8df9271 Mon Sep 17 00:00:00 2001
From: DougBanksPersonal <doug@zeemee.com>
Date: Wed, 16 Dec 2015 10:50:40 -0800
Subject: [PATCH 0555/1411] Update EmbeddedAppIOS.md

---
 docs/EmbeddedAppIOS.md | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/docs/EmbeddedAppIOS.md b/docs/EmbeddedAppIOS.md
index b82c608d1971..4c4b9995286e 100644
--- a/docs/EmbeddedAppIOS.md
+++ b/docs/EmbeddedAppIOS.md
@@ -15,7 +15,11 @@ Since React makes no assumptions about the rest of your technology stack – it
 - [Node.js](http://nodejs.org)
   - Install **nvm** with [its setup instructions here](https://github.com/creationix/nvm#installation). Then run `nvm install node && nvm alias default node`, which installs the latest version of Node.js and sets up your terminal so you can run it by typing `node`.  With nvm you can install multiple versions of Node.js and easily switch between them.
   - If you are using Node 5.0 or newer, we recommend installing npm 2, which is much faster than npm 3. After installing Node, run `npm install -g npm@2`
-- Install your copy of React Native under your `node_modules` directory where your JS resides.
+- Install the `react-native` package from npm by running the following command in the root directory of your project:
+  - `npm install react-native`
+
+At this point you should have the React Native package installed under a directory named `node_modules` as a sibling to your `.xcodeproj` file.
+
 
 ## Install React Native Using CocoaPods
 
@@ -26,7 +30,7 @@ When you are ready to work with CocoaPods, add the following lines to `Podfile`.
 ```ruby
 # Depending on how your project is organized, your node_modules directory may be
 # somewhere else; tell CocoaPods where you've installed react-native from npm
-pod 'React', :path => '../node_modules/react-native', :subspecs => [
+pod 'React', :path => './node_modules/react-native', :subspecs => [
   'Core',
   'RCTImage',
   'RCTNetwork',
@@ -126,7 +130,7 @@ Ready for the most interesting part? Now we shall create the `RCTRootView`, wher
 In `ReactView.m`, we need to first initiate `RCTRootView` with the URI of your `index.ios.bundle`. `index.ios.bundle` will be created by packager and served by React Native server, which will be discussed later on.
 
 ```
-NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle"];
+NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios"];
 // For production use, this `NSURL` could instead point to a pre-bundled file on disk:
 //
 //   NSURL *jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
@@ -152,7 +156,7 @@ rootView.frame = self.bounds;
 In root directory, we need to start React Native development server.
 
 ```
-(JS_DIR=`pwd`/ReactComponent; cd Pods/React; npm run start -- --root $JS_DIR)
+(JS_DIR=`pwd`/ReactComponent; cd node_modules/react-native; npm run start -- --root $JS_DIR)
 ```
 
 This command will start up a React Native development server within our CocoaPods dependency to build our bundled script. The `--root` option indicates the root of your React Native apps – this will be our `ReactComponents` directory containing the single `index.ios.js` file. This running server will package up the `index.ios.bundle` file accessible via `http://localhost:8081/index.ios.bundle`.
@@ -163,7 +167,7 @@ Now compile and run your app. You shall now see your React Native app running in
 
 ![Example](/react-native/img/EmbeddedAppExample.png)
 
-Live reload works from the simulator, too! You’ve got a simple React component totally encapsulated behind an Objective-C `UIView` subclass.
+Live reload and all of the debugging tools will work from the simulator (make sure that DEBUG=1 is set under Build Settings -> Preprocessor Macros).  You've got a simple React component totally encapsulated behind an Objective-C `UIView` subclass.
 
 ## Conclusion
 

From d7ad393f22e3ba9b1425f2f0c97b185372b5b0a7 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Wed, 30 Dec 2015 14:15:38 -0800
Subject: [PATCH 0556/1411] Fix unused argument warnings

Reviewed By: milend

Differential Revision: D2795407

fb-gh-sync-id: 83f5cc10b115eef3becb4ebab56b366f1a12a3ad
---
 React/Modules/RCTUIManager.m   | 2 +-
 React/Profiler/RCTProfile.m    | 2 +-
 React/Views/RCTComponentData.h | 2 +-
 React/Views/RCTComponentData.m | 4 ++--
 4 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m
index 2e63a461ae3d..4758d51b8eb2 100644
--- a/React/Modules/RCTUIManager.m
+++ b/React/Modules/RCTUIManager.m
@@ -840,7 +840,7 @@ - (void)_manageChildren:(NSNumber *)containerReactTag
   UIColor *backgroundColor = shadowView.backgroundColor;
 
   [self addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry){
-    UIView *view = [componentData createViewWithTag:reactTag props:props];
+    UIView *view = [componentData createViewWithTag:reactTag];
     if (view) {
       if ([view respondsToSelector:@selector(setBackgroundColor:)]) {
         ((UIView *)view).backgroundColor = backgroundColor;
diff --git a/React/Profiler/RCTProfile.m b/React/Profiler/RCTProfile.m
index 122dcbe8fad4..60ea0b157b0e 100644
--- a/React/Profiler/RCTProfile.m
+++ b/React/Profiler/RCTProfile.m
@@ -305,7 +305,7 @@ void RCTProfileHookModules(RCTBridge *bridge)
       RCTProfileHookInstance([bridge.uiManager viewForReactTag:view]);
     }
 
-    Method createView = class_getInstanceMethod([RCTComponentData class], @selector(createViewWithTag:props:));
+    Method createView = class_getInstanceMethod([RCTComponentData class], @selector(createViewWithTag:));
 
     if (method_getImplementation(createView) != (IMP)RCTProfileCreateView) {
       originalCreateView = (typeof(originalCreateView))method_getImplementation(createView);
diff --git a/React/Views/RCTComponentData.h b/React/Views/RCTComponentData.h
index c52af36472af..38b242602d83 100644
--- a/React/Views/RCTComponentData.h
+++ b/React/Views/RCTComponentData.h
@@ -26,7 +26,7 @@
 - (instancetype)initWithManagerClass:(Class)managerClass
                               bridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
 
-- (UIView *)createViewWithTag:(NSNumber *)tag props:(NSDictionary<NSString *, id> *)props;
+- (UIView *)createViewWithTag:(NSNumber *)tag;
 - (RCTShadowView *)createShadowViewWithTag:(NSNumber *)tag;
 - (void)setProps:(NSDictionary<NSString *, id> *)props forView:(id<RCTComponent>)view;
 - (void)setProps:(NSDictionary<NSString *, id> *)props forShadowView:(RCTShadowView *)shadowView;
diff --git a/React/Views/RCTComponentData.m b/React/Views/RCTComponentData.m
index 9b224c29c475..78952700603b 100644
--- a/React/Views/RCTComponentData.m
+++ b/React/Views/RCTComponentData.m
@@ -77,7 +77,7 @@ - (RCTViewManager *)manager
 
 RCT_NOT_IMPLEMENTED(- (instancetype)init)
 
-- (UIView *)createViewWithTag:(NSNumber *)tag props:(NSDictionary<NSString *, id> *)props
+- (UIView *)createViewWithTag:(NSNumber *)tag
 {
   RCTAssertMainThread();
 
@@ -296,7 +296,7 @@ - (void)setProps:(NSDictionary<NSString *, id> *)props forView:(id<RCTComponent>
   }
 
   if (!_defaultView) {
-    _defaultView = [self createViewWithTag:nil props:nil];
+    _defaultView = [self createViewWithTag:nil];
   }
 
   [props enumerateKeysAndObjectsUsingBlock:^(NSString *key, id json, __unused BOOL *stop) {

From 596109fa0a5d078f59852dea2e174ac55cc96f93 Mon Sep 17 00:00:00 2001
From: Satvik Jagannath <satvik.jagannath7@gmail.com>
Date: Wed, 30 Dec 2015 14:49:13 -0800
Subject: [PATCH 0557/1411] Fix THUMBNAILS to follow the require Syntax

Summary:
The THUMB_URLS is following the older syntax.
Fixed THUMBNAILS to follows require Syntax. And now you see the thumbnails appearing in the Sample app.
Closes https://github.com/facebook/react-native/pull/4995

Reviewed By: svcscm

Differential Revision: D2796019

Pulled By: nicklockwood

fb-gh-sync-id: c7be50d4dea73fc383db1c6b5a6afa7444505889
---
 .../UIExplorer/ListViewGridLayoutExample.js   | 28 ++++++++--------
 Examples/UIExplorer/ListViewPagingExample.js  | 32 +++++++++----------
 2 files changed, 29 insertions(+), 31 deletions(-)

diff --git a/Examples/UIExplorer/ListViewGridLayoutExample.js b/Examples/UIExplorer/ListViewGridLayoutExample.js
index 6af00aa8a947..ac7d56b86112 100644
--- a/Examples/UIExplorer/ListViewGridLayoutExample.js
+++ b/Examples/UIExplorer/ListViewGridLayoutExample.js
@@ -26,18 +26,18 @@ var {
 } = React;
 
 var THUMB_URLS = [
-  'Thumbnails/like.png',
-  'Thumbnails/dislike.png',
-  'Thumbnails/call.png',
-  'Thumbnails/fist.png',
-  'Thumbnails/bandaged.png',
-  'Thumbnails/flowers.png',
-  'Thumbnails/heart.png',
-  'Thumbnails/liking.png',
-  'Thumbnails/party.png',
-  'Thumbnails/poke.png',
-  'Thumbnails/superlike.png',
-  'Thumbnails/victory.png',
+  require('./Thumbnails/like.png'),
+  require('./Thumbnails/dislike.png'),
+  require('./Thumbnails/call.png'),
+  require('./Thumbnails/fist.png'),
+  require('./Thumbnails/bandaged.png'),
+  require('./Thumbnails/flowers.png'),
+  require('./Thumbnails/heart.png'),
+  require('./Thumbnails/liking.png'),
+  require('./Thumbnails/party.png'),
+  require('./Thumbnails/poke.png'),
+  require('./Thumbnails/superlike.png'),
+  require('./Thumbnails/victory.png'),
 ];
 
 var ListViewGridLayoutExample = React.createClass({
@@ -74,9 +74,7 @@ var ListViewGridLayoutExample = React.createClass({
 
   _renderRow: function(rowData: string, sectionID: number, rowID: number) {
     var rowHash = Math.abs(hashCode(rowData));
-    var imgSource = {
-      uri: THUMB_URLS[rowHash % THUMB_URLS.length],
-    };
+    var imgSource = THUMB_URLS[rowHash % THUMB_URLS.length];
     return (
       <TouchableHighlight onPress={() => this._pressRow(rowID)} underlayColor="transparent">
         <View>
diff --git a/Examples/UIExplorer/ListViewPagingExample.js b/Examples/UIExplorer/ListViewPagingExample.js
index 7d0ac98f2bfd..f6cdcae62aa4 100644
--- a/Examples/UIExplorer/ListViewPagingExample.js
+++ b/Examples/UIExplorer/ListViewPagingExample.js
@@ -34,19 +34,19 @@ var {
 
 var PAGE_SIZE = 4;
 var THUMB_URLS = [
-  'Thumbnails/like.png',
-  'Thumbnails/dislike.png',
-  'Thumbnails/call.png',
-  'Thumbnails/fist.png',
-  'Thumbnails/bandaged.png',
-  'Thumbnails/flowers.png',
-  'Thumbnails/heart.png',
-  'Thumbnails/liking.png',
-  'Thumbnails/party.png',
-  'Thumbnails/poke.png',
-  'Thumbnails/superlike.png',
-  'Thumbnails/victory.png',
-  ];
+  require('./Thumbnails/like.png'),
+  require('./Thumbnails/dislike.png'),
+  require('./Thumbnails/call.png'),
+  require('./Thumbnails/fist.png'),
+  require('./Thumbnails/bandaged.png'),
+  require('./Thumbnails/flowers.png'),
+  require('./Thumbnails/heart.png'),
+  require('./Thumbnails/liking.png'),
+  require('./Thumbnails/party.png'),
+  require('./Thumbnails/poke.png'),
+  require('./Thumbnails/superlike.png'),
+  require('./Thumbnails/victory.png'),
+];
 var NUM_SECTIONS = 100;
 var NUM_ROWS_PER_SECTION = 10;
 
@@ -74,9 +74,9 @@ var Thumb = React.createClass({
       <TouchableOpacity
         onPress={this._onPressThumb}
         style={[styles.buttonContents, {flexDirection: this.state.dir}]}>
-        <Image style={styles.img} source={{uri: THUMB_URLS[this.state.thumbIndex]}} />
-        <Image style={styles.img} source={{uri: THUMB_URLS[this.state.thumbIndex]}} />
-        <Image style={styles.img} source={{uri: THUMB_URLS[this.state.thumbIndex]}} />
+        <Image style={styles.img} source={THUMB_URLS[this.state.thumbIndex]} />
+        <Image style={styles.img} source={THUMB_URLS[this.state.thumbIndex]} />
+        <Image style={styles.img} source={THUMB_URLS[this.state.thumbIndex]} />
         {this.state.dir === 'column' ?
           <Text>
             Oooo, look at this new text!  So awesome it may just be crazy.

From bec91104f8fd4d3eb0c5b562d0179595f625dcb6 Mon Sep 17 00:00:00 2001
From: Ben Alpert <balpert@fb.com>
Date: Wed, 30 Dec 2015 19:08:52 -0800
Subject: [PATCH 0558/1411] Re-shrinkwrap to get react-proxy 1.1.2

Reviewed By: vjeux

Differential Revision: D2796203

fb-gh-sync-id: 8c0538a0270feb51e9b14ffdbe8243ea4ed62845
---
 npm-shrinkwrap.json | 128 ++++++++++++++++++++++----------------------
 1 file changed, 64 insertions(+), 64 deletions(-)

diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index 2b98efba245b..bcab7d34f4a8 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -146,6 +146,11 @@
           "version": "2.2.0",
           "from": "debug@>=2.1.1 <3.0.0"
         },
+        "globals": {
+          "version": "6.4.1",
+          "from": "globals@>=6.4.0 <7.0.0",
+          "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
+        },
         "js-tokens": {
           "version": "1.0.1",
           "from": "js-tokens@1.0.1",
@@ -156,11 +161,6 @@
           "from": "recast@0.10.33",
           "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
         },
-        "globals": {
-          "version": "6.4.1",
-          "from": "globals@>=6.4.0 <7.0.0",
-          "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
-        },
         "regenerator": {
           "version": "0.8.40",
           "from": "regenerator@0.8.40",
@@ -274,16 +274,16 @@
           "from": "babylon@>=5.8.29 <6.0.0",
           "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz"
         },
-        "globals": {
-          "version": "6.4.1",
-          "from": "globals@>=6.4.0 <7.0.0",
-          "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
-        },
         "esprima-fb": {
           "version": "15001.1001.0-dev-harmony-fb",
           "from": "esprima-fb@>=15001.1001.0-dev-harmony-fb <15001.1002.0",
           "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz"
         },
+        "globals": {
+          "version": "6.4.1",
+          "from": "globals@>=6.4.0 <7.0.0",
+          "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
+        },
         "js-tokens": {
           "version": "1.0.1",
           "from": "js-tokens@1.0.1",
@@ -1874,26 +1874,26 @@
           "from": "ansi-styles@^2.1.0",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz"
         },
-        "asn1": {
-          "version": "0.1.11",
-          "from": "asn1@0.1.11",
-          "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
-        },
         "are-we-there-yet": {
           "version": "1.0.4",
           "from": "are-we-there-yet@~1.0.0",
           "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.4.tgz"
         },
-        "async": {
-          "version": "1.5.0",
-          "from": "async@^1.4.0",
-          "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz"
+        "asn1": {
+          "version": "0.1.11",
+          "from": "asn1@0.1.11",
+          "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
         },
         "assert-plus": {
           "version": "0.1.5",
           "from": "assert-plus@^0.1.5",
           "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
         },
+        "async": {
+          "version": "1.5.0",
+          "from": "async@^1.4.0",
+          "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz"
+        },
         "aws-sign2": {
           "version": "0.6.0",
           "from": "aws-sign2@~0.6.0",
@@ -1944,11 +1944,6 @@
           "from": "concat-map@0.0.1",
           "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
         },
-        "core-util-is": {
-          "version": "1.0.1",
-          "from": "core-util-is@~1.0.0",
-          "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-        },
         "cryptiles": {
           "version": "2.0.5",
           "from": "cryptiles@2.x.x",
@@ -1959,6 +1954,11 @@
           "from": "ctype@0.5.3",
           "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz"
         },
+        "core-util-is": {
+          "version": "1.0.1",
+          "from": "core-util-is@~1.0.0",
+          "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
+        },
         "debug": {
           "version": "0.7.4",
           "from": "debug@~0.7.2",
@@ -2064,16 +2064,16 @@
           "from": "inherits@*",
           "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
         },
-        "ini": {
-          "version": "1.3.4",
-          "from": "ini@~1.3.0",
-          "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz"
-        },
         "is-my-json-valid": {
           "version": "2.12.2",
           "from": "is-my-json-valid@^2.12.2",
           "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.2.tgz"
         },
+        "ini": {
+          "version": "1.3.4",
+          "from": "ini@~1.3.0",
+          "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz"
+        },
         "is-property": {
           "version": "1.0.2",
           "from": "is-property@^1.0.0",
@@ -2109,26 +2109,26 @@
           "from": "lodash._createpadding@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash._createpadding/-/lodash._createpadding-3.6.1.tgz"
         },
-        "lodash.pad": {
-          "version": "3.1.1",
-          "from": "lodash.pad@^3.0.0",
-          "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-3.1.1.tgz"
-        },
         "lodash.padleft": {
           "version": "3.1.1",
           "from": "lodash.padleft@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash.padleft/-/lodash.padleft-3.1.1.tgz"
         },
-        "lodash.padright": {
+        "lodash.pad": {
           "version": "3.1.1",
-          "from": "lodash.padright@^3.0.0",
-          "resolved": "https://registry.npmjs.org/lodash.padright/-/lodash.padright-3.1.1.tgz"
+          "from": "lodash.pad@^3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-3.1.1.tgz"
         },
         "lodash.repeat": {
           "version": "3.0.1",
           "from": "lodash.repeat@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash.repeat/-/lodash.repeat-3.0.1.tgz"
         },
+        "lodash.padright": {
+          "version": "3.1.1",
+          "from": "lodash.padright@^3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash.padright/-/lodash.padright-3.1.1.tgz"
+        },
         "mime-db": {
           "version": "1.19.0",
           "from": "mime-db@~1.19.0",
@@ -2149,6 +2149,11 @@
           "from": "mkdirp@>=0.3.0 <0.4.0||>=0.4.0 <0.5.0||>=0.5.0 <0.6.0",
           "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz"
         },
+        "npmlog": {
+          "version": "1.2.1",
+          "from": "npmlog@~1.2.0",
+          "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz"
+        },
         "node-uuid": {
           "version": "1.4.3",
           "from": "node-uuid@~1.4.3",
@@ -2159,11 +2164,6 @@
           "from": "oauth-sign@~0.8.0",
           "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.0.tgz"
         },
-        "npmlog": {
-          "version": "1.2.1",
-          "from": "npmlog@~1.2.0",
-          "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz"
-        },
         "once": {
           "version": "1.1.1",
           "from": "once@~1.1.1",
@@ -2219,40 +2219,40 @@
           "from": "stringstream@~0.0.4",
           "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
         },
+        "strip-json-comments": {
+          "version": "0.1.3",
+          "from": "strip-json-comments@0.1.x",
+          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
+        },
         "strip-ansi": {
           "version": "3.0.0",
           "from": "strip-ansi@^3.0.0",
           "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz"
         },
-        "strip-json-comments": {
-          "version": "0.1.3",
-          "from": "strip-json-comments@0.1.x",
-          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
+        "tunnel-agent": {
+          "version": "0.4.1",
+          "from": "tunnel-agent@~0.4.1",
+          "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz"
         },
         "supports-color": {
           "version": "2.0.0",
           "from": "supports-color@^2.0.0",
           "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
         },
-        "tar": {
-          "version": "2.2.1",
-          "from": "tar@~2.2.0",
-          "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz"
+        "uid-number": {
+          "version": "0.0.3",
+          "from": "uid-number@0.0.3",
+          "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.3.tgz"
         },
         "tough-cookie": {
           "version": "2.2.0",
           "from": "tough-cookie@~2.2.0",
           "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.0.tgz"
         },
-        "tunnel-agent": {
-          "version": "0.4.1",
-          "from": "tunnel-agent@~0.4.1",
-          "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz"
-        },
-        "uid-number": {
-          "version": "0.0.3",
-          "from": "uid-number@0.0.3",
-          "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.3.tgz"
+        "tar": {
+          "version": "2.2.1",
+          "from": "tar@~2.2.0",
+          "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz"
         },
         "wrappy": {
           "version": "1.0.1",
@@ -4210,7 +4210,7 @@
     },
     "react-transform-hmr": {
       "version": "1.0.1",
-      "from": "react-transform-hmr@1.0.1",
+      "from": "https://registry.npmjs.org/react-transform-hmr/-/react-transform-hmr-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/react-transform-hmr/-/react-transform-hmr-1.0.1.tgz",
       "dependencies": {
         "global": {
@@ -4238,14 +4238,14 @@
           }
         },
         "react-proxy": {
-          "version": "1.1.1",
+          "version": "1.1.2",
           "from": "react-proxy@>=1.1.1 <2.0.0",
-          "resolved": "https://registry.npmjs.org/react-proxy/-/react-proxy-1.1.1.tgz",
+          "resolved": "https://registry.npmjs.org/react-proxy/-/react-proxy-1.1.2.tgz",
           "dependencies": {
             "react-deep-force-update": {
-              "version": "1.0.0",
+              "version": "1.0.1",
               "from": "react-deep-force-update@>=1.0.0 <2.0.0",
-              "resolved": "https://registry.npmjs.org/react-deep-force-update/-/react-deep-force-update-1.0.0.tgz"
+              "resolved": "https://registry.npmjs.org/react-deep-force-update/-/react-deep-force-update-1.0.1.tgz"
             }
           }
         }

From 72a08c11c67a3f664873480f6b1e8526cc46af3b Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Thu, 31 Dec 2015 11:41:49 +0800
Subject: [PATCH 0559/1411] remove broken link

---
 docs/NativeComponentsIOS.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/NativeComponentsIOS.md b/docs/NativeComponentsIOS.md
index e506bc6c4203..ebdbc2f71f80 100644
--- a/docs/NativeComponentsIOS.md
+++ b/docs/NativeComponentsIOS.md
@@ -267,7 +267,7 @@ RCT_EXPORT_MODULE()
 }
 ```
 
-You can see we're setting the manager as the delegate for every view that it vends, then in the delegate method `-mapView:regionDidChangeAnimated:` the region is combined with the `reactTag` target to make an event that is dispatched to the corresponding React component instance in your application via `sendInputEventWithName:body:`.  The event name `@"topChange"` maps to the `onChange` callback prop in JavaScript (mappings are [here](https://github.com/facebook/react-native/blob/master/React/Modules/RCTUIManager.m#L1165)).  This callback is invoked with the raw event, which we typically process in the wrapper component to make a simpler API:
+You can see we're setting the manager as the delegate for every view that it vends, then in the delegate method `-mapView:regionDidChangeAnimated:` the region is combined with the `reactTag` target to make an event that is dispatched to the corresponding React component instance in your application via `sendInputEventWithName:body:`.  The event name `@"topChange"` maps to the `onChange` callback prop in JavaScript.  This callback is invoked with the raw event, which we typically process in the wrapper component to make a simpler API:
 
 ```javascript
 // MapView.js

From dcc01b04f1edbad290493a258ac8a671659aa6b1 Mon Sep 17 00:00:00 2001
From: Alessandro Nadalin <alessandro.nadalin@gmail.com>
Date: Thu, 31 Dec 2015 12:26:10 +0400
Subject: [PATCH 0560/1411] Fixed typo

---
 ReactAndroid/DevExperience.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ReactAndroid/DevExperience.md b/ReactAndroid/DevExperience.md
index 2defb472032e..ccb1f629fc4c 100644
--- a/ReactAndroid/DevExperience.md
+++ b/ReactAndroid/DevExperience.md
@@ -8,7 +8,7 @@ Make sure you have the following installed:
 - SDK build tools version 23
 - Android Support Repository 17 (for Android Support Library)
 
-Follow steps on https://github.com/facebook/react-native/blob/master/react-native-cli/CONTRIBUTING.md, but be sure to bump the verison of react-native in package.json to some version > 0.9 (latest published npm version) or set up proxying properly for react-native
+Follow steps on https://github.com/facebook/react-native/blob/master/react-native-cli/CONTRIBUTING.md, but be sure to bump the version of react-native in package.json to some version > 0.9 (latest published npm version) or set up proxying properly for react-native
   
 - From the react-native-android repo:
   - `./gradlew :ReactAndroid:installArchives`

From e09378d92dbaef3e3a9bb32e70b5482cc39eb48b Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Thu, 31 Dec 2015 21:11:47 +0800
Subject: [PATCH 0561/1411] remove Precomputing style

---
 docs/DirectManipulation.md | 31 -------------------------------
 1 file changed, 31 deletions(-)

diff --git a/docs/DirectManipulation.md b/docs/DirectManipulation.md
index 77551e590ded..a47a39fe2cbd 100644
--- a/docs/DirectManipulation.md
+++ b/docs/DirectManipulation.md
@@ -161,37 +161,6 @@ that call back to the `TouchableOpacity` component.
 `TouchableHighlight`, in contrast, is backed by a native view and only
 requires that we implement `setNativeProps`.
 
-## Precomputing style
-
-We learned above that `setNativeProps` is a wrapper around
-`RCTUIManager.updateView`, which is also used internally by React to
-perform updates on re-render. One important difference is that
-`setNativeProps` does not call `precomputeStyle`, which is done
-internally by React, and so the `transform` property will not work if
-you try to update it manually with `setNativeProps`. To fix this,
-you can call `precomputeStyle` on your object first:
-
-```javascript
-var precomputeStyle = require('precomputeStyle');
-
-var App = React.createClass({
-  componentDidMount() {
-    var nativeProps = precomputeStyle({transform: [{rotate: '45deg'}]});
-    this._root.setNativeProps(nativeProps);
-  },
-
-  render() {
-    return (
-      <View ref={component => this._root = component}
-            style={styles.container}>
-        <Text>Precompute style!</Text>
-      </View>
-    )
-  },
-});
-```
-[Run this example](https://rnplay.org/apps/8_mIAA)
-
 ## setNativeProps to clear TextInput value
 
 Another very common use case of `setNativeProps` is to clear the value

From 55fe7ac9ae418d07b62af28ef80e0aa07b5277dc Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 31 Dec 2015 07:47:39 -0800
Subject: [PATCH 0562/1411] Fix flow errors

Reviewed By: gabelevi

Differential Revision: D2796260

fb-gh-sync-id: 8425e57a313326afb6f6ae5bb8b86a569f462b06
---
 Libraries/Image/ImageSource.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/Image/ImageSource.js b/Libraries/Image/ImageSource.js
index 66ae67c72ead..963192ea212a 100644
--- a/Libraries/Image/ImageSource.js
+++ b/Libraries/Image/ImageSource.js
@@ -11,6 +11,6 @@
  */
 'use strict';
 
-type ImageSource = {
+export type ImageSource = {
   uri: string;
 };

From 67931284350ebd2b60d1e11870690272079b1726 Mon Sep 17 00:00:00 2001
From: odino <alessandro.nadalin@gmail.com>
Date: Thu, 31 Dec 2015 18:03:37 -0800
Subject: [PATCH 0563/1411] Allowing turning on / off DOM storage on android
 webviews

Summary:
Was developing on a WebView and couldnt get it to run. Turns out its JS code mostly depends on `localStorage` and I realized it wasnt turned on in RN. This PR adds a prop, similar to `javascriptEnabledAndroid` to be able to turn DOM storage on / off.

TBH I dont really know how it works on IOS, so I created an android specific thingy. I assume DOM storage is enabled by default on IOS.
Closes https://github.com/facebook/react-native/pull/5065

Reviewed By: svcscm

Differential Revision: D2797735

Pulled By: androidtrunkagent

fb-gh-sync-id: cd60cfa4d24d80fb82e4f54f387a4517a99e75ab
---
 Examples/UIExplorer/WebViewExample.js                    | 1 +
 Libraries/Components/WebView/WebView.android.js          | 9 ++++++++-
 Libraries/Components/WebView/WebView.ios.js              | 6 ++++++
 .../react/views/webview/ReactWebViewManager.java         | 5 +++++
 4 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/Examples/UIExplorer/WebViewExample.js b/Examples/UIExplorer/WebViewExample.js
index c8c547f978e9..ce489effe4bd 100644
--- a/Examples/UIExplorer/WebViewExample.js
+++ b/Examples/UIExplorer/WebViewExample.js
@@ -95,6 +95,7 @@ var WebViewExample = React.createClass({
           style={styles.webView}
           url={this.state.url}
           javaScriptEnabledAndroid={true}
+          domStorageEnabledAndroid={true}
           onNavigationStateChange={this.onNavigationStateChange}
           onShouldStartLoadWithRequest={this.onShouldStartLoadWithRequest}
           startInLoadingState={true}
diff --git a/Libraries/Components/WebView/WebView.android.js b/Libraries/Components/WebView/WebView.android.js
index f4bc520457bf..7b227aef35b4 100644
--- a/Libraries/Components/WebView/WebView.android.js
+++ b/Libraries/Components/WebView/WebView.android.js
@@ -38,7 +38,7 @@ var WebView = React.createClass({
 
   propTypes: {
     ...View.propTypes,
-    renderError: PropTypes.func, 
+    renderError: PropTypes.func,
     renderLoading: PropTypes.func,
     url: PropTypes.string,
     html: PropTypes.string,
@@ -54,6 +54,12 @@ var WebView = React.createClass({
      */
     javaScriptEnabledAndroid: PropTypes.bool,
 
+    /**
+     * Used on Android only, controls whether DOM Storage is enabled or not
+     * @platform android
+     */
+    domStorageEnabledAndroid: PropTypes.bool,
+
     /**
      * Sets the JS to be injected when the webpage loads.
      */
@@ -117,6 +123,7 @@ var WebView = React.createClass({
         injectedJavaScript={this.props.injectedJavaScript}
         userAgent={this.props.userAgent}
         javaScriptEnabledAndroid={this.props.javaScriptEnabledAndroid}
+        domStorageEnabledAndroid={this.props.domStorageEnabledAndroid}
         contentInset={this.props.contentInset}
         automaticallyAdjustContentInsets={this.props.automaticallyAdjustContentInsets}
         onLoadingStart={this.onLoadingStart}
diff --git a/Libraries/Components/WebView/WebView.ios.js b/Libraries/Components/WebView/WebView.ios.js
index a51ed3fceb8a..6713c84c978a 100644
--- a/Libraries/Components/WebView/WebView.ios.js
+++ b/Libraries/Components/WebView/WebView.ios.js
@@ -116,6 +116,12 @@ var WebView = React.createClass({
      */
     javaScriptEnabledAndroid: PropTypes.bool,
 
+    /**
+     * Used on Android only, controls whether DOM Storage is enabled or not
+     * @platform android
+     */
+    domStorageEnabledAndroid: PropTypes.bool,
+
     /**
      * Sets the JS to be injected when the webpage loads.
      */
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
index a8eb4d65b50b..57c2d09e3b30 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
@@ -256,6 +256,11 @@ public void setJavaScriptEnabled(WebView view, boolean enabled) {
     view.getSettings().setJavaScriptEnabled(enabled);
   }
 
+  @ReactProp(name = "domStorageEnabledAndroid")
+  public void setDomStorageEnabled(WebView view, boolean enabled) {
+    view.getSettings().setDomStorageEnabled(enabled);
+  }
+
   @ReactProp(name = "userAgent")
   public void setUserAgent(WebView view, @Nullable String userAgent) {
     if (userAgent != null) {

From 718cd7953f6a30338882c4b56bd11c83fb311d7f Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 31 Dec 2015 18:50:26 -0800
Subject: [PATCH 0564/1411] Added getImageSize method

Summary:
public

This diff adds a `getSize()` method to `Image` to retrieve the width and height of an image prior to displaying it. This is useful when working with images from uncontrolled sources, and has been a much-requested feature.

In order to retrieve the image dimensions, the image may first need to be loaded or downloaded, after which it will be cached. This means that in principle you could use this method to preload images, however it is not optimized for that purpose, and may in future be implemented in a way that does not fully load/download the image data.

A fully supported way to preload images will be provided in a future diff.

The API (separate success and failure callbacks) is far from ideal, but until we agree on a unified standard, this was the most conventional way I could think of to implement it. If it returned a promise or something similar, it would be unique among all such APIS in the framework.

Please note that this has been a long time coming, in part due to much bikeshedding about what the API should look like, so while it's not unlikely that the API may change in future, I think having *some* way to do this is better than waiting until we can define the "perfect" way.

Reviewed By: vjeux

Differential Revision: D2797365

fb-gh-sync-id: 11eb1b8547773b1f8be0bc55ddf6dfedebf7fc0a
---
 Examples/UIExplorer/ImageExample.js   |  40 +++++++++-
 Libraries/Image/Image.ios.js          |  33 ++++++++-
 Libraries/Image/RCTImageLoader.h      |   7 ++
 Libraries/Image/RCTImageLoader.m      | 103 +++++++++++++++++++++-----
 Libraries/Image/RCTImageUtils.h       |   6 ++
 Libraries/Image/RCTImageUtils.m       |  14 +++-
 Libraries/Image/RCTImageViewManager.m |  15 ++++
 7 files changed, 191 insertions(+), 27 deletions(-)

diff --git a/Examples/UIExplorer/ImageExample.js b/Examples/UIExplorer/ImageExample.js
index 50c96ffd285e..163396f89a9c 100644
--- a/Examples/UIExplorer/ImageExample.js
+++ b/Examples/UIExplorer/ImageExample.js
@@ -68,8 +68,6 @@ var NetworkImageCallbackExample = React.createClass({
 });
 
 var NetworkImageExample = React.createClass({
-  watchID: (null: ?number),
-
   getInitialState: function() {
     return {
       error: false,
@@ -97,6 +95,38 @@ var NetworkImageExample = React.createClass({
   }
 });
 
+var ImageSizeExample = React.createClass({
+  getInitialState: function() {
+    return {
+      width: 0,
+      height: 0,
+    };
+  },
+  componentDidMount: function() {
+    Image.getSize(this.props.source.uri, (width, height) => {
+      this.setState({width, height});
+    });
+  },
+  render: function() {
+    return (
+      <View style={{flexDirection: 'row'}}>
+        <Image
+          style={{
+            width: 60,
+            height: 60,
+            backgroundColor: 'transparent',
+            marginRight: 10,
+          }}
+          source={this.props.source} />
+        <Text>
+          Actual dimensions:{'\n'}
+          Width: {this.state.width}, Height: {this.state.height}
+        </Text>
+      </View>
+    );
+  },
+});
+
 exports.displayName = (undefined: ?string);
 exports.framework = 'React';
 exports.title = '<Image>';
@@ -408,6 +438,12 @@ exports.examples = [
     },
     platform: 'ios',
   },
+  {
+    title: 'Image Size',
+    render: function() {
+      return <ImageSizeExample source={fullImage} />; 
+    }
+  },
 ];
 
 var fullImage = {uri: 'http://facebook.github.io/react/img/logo_og.png'};
diff --git a/Libraries/Image/Image.ios.js b/Libraries/Image/Image.ios.js
index 8eda0cc8c9c9..91293c07f615 100644
--- a/Libraries/Image/Image.ios.js
+++ b/Libraries/Image/Image.ios.js
@@ -15,7 +15,6 @@ var EdgeInsetsPropType = require('EdgeInsetsPropType');
 var ImageResizeMode = require('ImageResizeMode');
 var ImageStylePropTypes = require('ImageStylePropTypes');
 var NativeMethodsMixin = require('NativeMethodsMixin');
-var NativeModules = require('NativeModules');
 var PropTypes = require('ReactPropTypes');
 var React = require('React');
 var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
@@ -29,6 +28,11 @@ var requireNativeComponent = require('requireNativeComponent');
 var resolveAssetSource = require('resolveAssetSource');
 var warning = require('warning');
 
+var {
+  ImageViewManager,
+  NetworkImageViewManager,
+} = require('NativeModules');
+
 /**
  * A React component for displaying different types of images,
  * including network images, static resources, temporary local images, and
@@ -197,7 +201,7 @@ var Image = React.createClass({
         />
       );
     }
-  }
+  },
 });
 
 var styles = StyleSheet.create({
@@ -207,7 +211,30 @@ var styles = StyleSheet.create({
 });
 
 var RCTImageView = requireNativeComponent('RCTImageView', Image);
-var RCTNetworkImageView = NativeModules.NetworkImageViewManager ? requireNativeComponent('RCTNetworkImageView', Image) : RCTImageView;
+var RCTNetworkImageView = NetworkImageViewManager ? requireNativeComponent('RCTNetworkImageView', Image) : RCTImageView;
 var RCTVirtualImage = requireNativeComponent('RCTVirtualImage', Image);
 
+/**
+ * Retrieve the width and height (in pixels) of an image prior to displaying it.
+ * This method can fail if the image cannot be found, or fails to download.
+ *
+ * In order to retrieve the image dimensions, the image may first need to be
+ * loaded or downloaded, after which it will be cached. This means that in
+ * principle you could use this method to preload images, however it is not
+ * optimized for that purpose, and may in future be implemented in a way that
+ * does not fully load/download the image data. A proper, supported way to
+ * preload images will be provided as a separate API.
+ *
+ * @platform ios
+ */
+Image.getSize = function(
+  uri: string,
+  success: (width: number, height: number) => void,
+  failure: (error: any) => void,
+) {
+  ImageViewManager.getSize(uri, success, failure || function() {
+    console.warn('Failed to get size for image: ' + uri);
+  });
+};
+
 module.exports = Image;
diff --git a/Libraries/Image/RCTImageLoader.h b/Libraries/Image/RCTImageLoader.h
index 770747452608..c9bea5437777 100644
--- a/Libraries/Image/RCTImageLoader.h
+++ b/Libraries/Image/RCTImageLoader.h
@@ -55,6 +55,13 @@ typedef void (^RCTImageLoaderCancellationBlock)(void);
                                         resizeMode:(UIViewContentMode)resizeMode
                                    completionBlock:(RCTImageLoaderCompletionBlock)completionBlock;
 
+/**
+ * Get image size, in pixels. This method will do the least work possible to get
+ * the information, and won't decode the image if it doesn't have to.
+ */
+- (RCTImageLoaderCancellationBlock)getImageSize:(NSString *)imageTag
+                                          block:(void(^)(NSError *error, CGSize size))completionBlock;
+
 @end
 
 @interface RCTBridge (RCTImageLoader)
diff --git a/Libraries/Image/RCTImageLoader.m b/Libraries/Image/RCTImageLoader.m
index acee9dbecea4..cd681b113114 100644
--- a/Libraries/Image/RCTImageLoader.m
+++ b/Libraries/Image/RCTImageLoader.m
@@ -11,6 +11,7 @@
 
 #import <libkern/OSAtomic.h>
 #import <UIKit/UIKit.h>
+#import <ImageIO/ImageIO.h>
 
 #import "RCTConvert.h"
 #import "RCTDefines.h"
@@ -183,29 +184,34 @@ - (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag
                 completionBlock:callback];
 }
 
-- (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag
-                                               size:(CGSize)size
-                                              scale:(CGFloat)scale
-                                         resizeMode:(UIViewContentMode)resizeMode
-                                      progressBlock:(RCTImageLoaderProgressBlock)progressHandler
-                                    completionBlock:(RCTImageLoaderCompletionBlock)completionBlock
+/**
+ * This returns either an image, or raw image data, depending on the loading
+ * path taken. This is useful if you want to skip decoding, e.g. when preloading
+ * the image, or retrieving metadata.
+ */
+- (RCTImageLoaderCancellationBlock)loadImageOrDataWithTag:(NSString *)imageTag
+                                                     size:(CGSize)size
+                                                    scale:(CGFloat)scale
+                                               resizeMode:(UIViewContentMode)resizeMode
+                                            progressBlock:(RCTImageLoaderProgressBlock)progressHandler
+                                          completionBlock:(void (^)(NSError *error, id imageOrData))completionBlock
 {
   __block volatile uint32_t cancelled = 0;
   __block void(^cancelLoad)(void) = nil;
   __weak RCTImageLoader *weakSelf = self;
 
-  RCTImageLoaderCompletionBlock completionHandler = ^(NSError *error, UIImage *image) {
+  void (^completionHandler)(NSError *error, id imageOrData) = ^(NSError *error, id imageOrData) {
     if ([NSThread isMainThread]) {
 
       // Most loaders do not return on the main thread, so caller is probably not
       // expecting it, and may do expensive post-processing in the callback
       dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
         if (!cancelled) {
-          completionBlock(error, image);
+          completionBlock(error, imageOrData);
         }
       });
     } else if (!cancelled) {
-      completionBlock(error, image);
+      completionBlock(error, imageOrData);
     }
   };
 
@@ -259,7 +265,6 @@ - (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag
     }
 
     // Use networking module to load image
-    __block RCTImageLoaderCancellationBlock cancelDecode = nil;
     RCTURLRequestCompletionBlock processResponse =
     ^(NSURLResponse *response, NSData *data, NSError *error) {
 
@@ -283,12 +288,8 @@ - (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag
         }
       }
 
-      // Decode image
-      cancelDecode = [strongSelf decodeImageData:data
-                                            size:size
-                                           scale:scale
-                                      resizeMode:resizeMode
-                                 completionBlock:completionHandler];
+      // Call handler
+      completionHandler(nil, data);
     };
 
     // Add missing png extension
@@ -325,7 +326,6 @@ - (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag
                                               userInfo:nil
                                          storagePolicy:isHTTPRequest ? NSURLCacheStorageAllowed: NSURLCacheStorageAllowedInMemoryOnly]
                                         forRequest:request];
-
         // Process image data
         processResponse(response, data, nil);
 
@@ -337,9 +337,6 @@ - (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag
 
     cancelLoad = ^{
       [task cancel];
-      if (cancelDecode) {
-        cancelDecode();
-      }
     };
 
   });
@@ -352,6 +349,45 @@ - (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag
   };
 }
 
+- (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag
+                                               size:(CGSize)size
+                                              scale:(CGFloat)scale
+                                         resizeMode:(UIViewContentMode)resizeMode
+                                      progressBlock:(RCTImageLoaderProgressBlock)progressHandler
+                                    completionBlock:(RCTImageLoaderCompletionBlock)completionBlock
+{
+  __block volatile uint32_t cancelled = 0;
+  __block void(^cancelLoad)(void) = nil;
+  __weak RCTImageLoader *weakSelf = self;
+
+  void (^completionHandler)(NSError *error, id imageOrData) = ^(NSError *error, id imageOrData) {
+    if (!cancelled) {
+      if (!imageOrData || [imageOrData isKindOfClass:[UIImage class]]) {
+        completionBlock(error, imageOrData);
+      } else {
+        cancelLoad = [weakSelf decodeImageData:imageOrData
+                                          size:size
+                                         scale:scale
+                                    resizeMode:resizeMode
+                               completionBlock:completionBlock] ?: ^{};
+      }
+    }
+  };
+
+  cancelLoad = [self loadImageOrDataWithTag:imageTag
+                                       size:size
+                                      scale:scale
+                                 resizeMode:resizeMode
+                              progressBlock:progressHandler
+                            completionBlock:completionHandler] ?: ^{};
+  return ^{
+    if (cancelLoad) {
+      cancelLoad();
+    }
+    OSAtomicOr32Barrier(1, &cancelled);
+  };
+}
+
 - (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)data
                                               size:(CGSize)size
                                              scale:(CGFloat)scale
@@ -394,6 +430,33 @@ - (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)data
   }
 }
 
+- (RCTImageLoaderCancellationBlock)getImageSize:(NSString *)imageTag
+                                          block:(void(^)(NSError *error, CGSize size))completionBlock
+{
+  return [self loadImageOrDataWithTag:imageTag
+                                 size:CGSizeZero
+                                scale:1
+                           resizeMode:UIViewContentModeScaleToFill
+                        progressBlock:nil
+                      completionBlock:^(NSError *error, id imageOrData) {
+                        CGSize size;
+                        if ([imageOrData isKindOfClass:[NSData class]]) {
+                          NSDictionary *meta = RCTGetImageMetadata(imageOrData);
+                          size = (CGSize){
+                            [meta[(id)kCGImagePropertyPixelWidth] doubleValue],
+                            [meta[(id)kCGImagePropertyPixelHeight] doubleValue],
+                          };
+                        } else {
+                          UIImage *image = imageOrData;
+                          size = (CGSize){
+                            image.size.width * image.scale,
+                            image.size.height * image.scale,
+                          };
+                        }
+                        completionBlock(error, size);
+                      }];
+}
+
 #pragma mark - RCTURLRequestHandler
 
 - (BOOL)canHandleRequest:(NSURLRequest *)request
diff --git a/Libraries/Image/RCTImageUtils.h b/Libraries/Image/RCTImageUtils.h
index 901a876ab027..b9a118ec1711 100644
--- a/Libraries/Image/RCTImageUtils.h
+++ b/Libraries/Image/RCTImageUtils.h
@@ -58,6 +58,12 @@ RCT_EXTERN UIImage *RCTDecodeImageWithData(NSData *data,
                                            CGFloat destScale,
                                            UIViewContentMode resizeMode);
 
+/**
+ * This function takes the source data for an image and decodes just the
+ * metadata, without decompressing the image itself.
+ */
+RCT_EXTERN NSDictionary<NSString *, id> *RCTGetImageMetadata(NSData *data);
+
 /**
  * Convert an image back into data. Images with an alpha channel will be
  * converted to lossless PNG data. Images without alpha will be converted to
diff --git a/Libraries/Image/RCTImageUtils.m b/Libraries/Image/RCTImageUtils.m
index a6c2ccd46098..a9476ff51e79 100644
--- a/Libraries/Image/RCTImageUtils.m
+++ b/Libraries/Image/RCTImageUtils.m
@@ -218,7 +218,6 @@ CGSize RCTSizeInPixels(CGSize pointSize, CGFloat scale)
   }
 
   // get original image size
-  CGSize sourceSize;
   CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(sourceRef, 0, NULL);
   if (!imageProperties) {
     CFRelease(sourceRef);
@@ -226,7 +225,7 @@ CGSize RCTSizeInPixels(CGSize pointSize, CGFloat scale)
   }
   NSNumber *width = CFDictionaryGetValue(imageProperties, kCGImagePropertyPixelWidth);
   NSNumber *height = CFDictionaryGetValue(imageProperties, kCGImagePropertyPixelHeight);
-  sourceSize = (CGSize){width.doubleValue, height.doubleValue};
+  CGSize sourceSize = {width.doubleValue, height.doubleValue};
   CFRelease(imageProperties);
 
   if (CGSizeEqualToSize(destSize, CGSizeZero)) {
@@ -266,6 +265,17 @@ CGSize RCTSizeInPixels(CGSize pointSize, CGFloat scale)
   return image;
 }
 
+NSDictionary<NSString *, id> *RCTGetImageMetadata(NSData *data)
+{
+  CGImageSourceRef sourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
+  if (!sourceRef) {
+    return nil;
+  }
+  CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(sourceRef, 0, NULL);
+  CFRelease(sourceRef);
+  return (__bridge_transfer id)imageProperties;
+}
+
 NSData *RCTGetImageData(CGImageRef image, float quality)
 {
   NSDictionary *properties;
diff --git a/Libraries/Image/RCTImageViewManager.m b/Libraries/Image/RCTImageViewManager.m
index d318d1f048a9..7ef593195aa4 100644
--- a/Libraries/Image/RCTImageViewManager.m
+++ b/Libraries/Image/RCTImageViewManager.m
@@ -12,6 +12,7 @@
 #import <UIKit/UIKit.h>
 
 #import "RCTConvert.h"
+#import "RCTImageLoader.h"
 #import "RCTImageSource.h"
 #import "RCTImageView.h"
 
@@ -42,4 +43,18 @@ - (UIView *)view
   view.renderingMode = json ? UIImageRenderingModeAlwaysTemplate : defaultView.renderingMode;
 }
 
+RCT_EXPORT_METHOD(getSize:(NSURL *)imageURL
+                  successBlock:(RCTResponseSenderBlock)successBlock
+                  errorBlock:(RCTResponseErrorBlock)errorBlock)
+{
+  [self.bridge.imageLoader getImageSize:imageURL.absoluteString
+                                  block:^(NSError *error, CGSize size) {
+                                    if (error) {
+                                      errorBlock(error);
+                                    } else {
+                                      successBlock(@[@(size.width), @(size.height)]);
+                                    }
+                                  }];
+}
+
 @end

From 4972cabaa5f12a1633c74fca1be901d01f16faf9 Mon Sep 17 00:00:00 2001
From: Kudo Chien <ckchien@gmail.com>
Date: Fri, 1 Jan 2016 09:32:59 -0800
Subject: [PATCH 0565/1411] Add <Text> shadow support

Summary:
Add three new TextStylePropTypes for \<Text>
- textShadowOffset
- textShadowRadius
- textShadowColor
Closes https://github.com/facebook/react-native/pull/4975

Reviewed By: svcscm

Differential Revision: D2796278

Pulled By: nicklockwood

fb-gh-sync-id: f8c3fa210e664428b029b9fba8eca4a8eb81c08d
---
 Examples/UIExplorer/TextExample.android.js    |  5 ++
 Examples/UIExplorer/TextExample.ios.js        | 11 ++++
 .../View/ReactNativeStyleAttributes.js        |  1 +
 Libraries/Text/RCTShadowText.h                |  3 ++
 Libraries/Text/RCTShadowText.m                | 22 ++++++--
 Libraries/Text/RCTTextManager.m               |  3 ++
 Libraries/Text/TextStylePropTypes.js          |  5 ++
 .../react/views/text/ReactTextShadowNode.java | 52 ++++++++++++++++++-
 .../react/views/text/ShadowStyleSpan.java     | 31 +++++++++++
 9 files changed, 126 insertions(+), 7 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/text/ShadowStyleSpan.java

diff --git a/Examples/UIExplorer/TextExample.android.js b/Examples/UIExplorer/TextExample.android.js
index 18defae27027..7c0c7868f4c4 100644
--- a/Examples/UIExplorer/TextExample.android.js
+++ b/Examples/UIExplorer/TextExample.android.js
@@ -365,6 +365,11 @@ var TextExample = React.createClass({
             This text contains an inline image <Image source={require('./flux.png')}/>. Neat, huh?
           </Text>
         </UIExplorerBlock>
+        <UIExplorerBlock title="Text shadow">
+          <Text style={{fontSize: 20, textShadowOffset: {width: 2, height: 2}, textShadowRadius: 1, textShadowColor: '#00cccc'}}>
+            Demo text shadow
+          </Text>
+        </UIExplorerBlock>
       </UIExplorerPage>
     );
   }
diff --git a/Examples/UIExplorer/TextExample.ios.js b/Examples/UIExplorer/TextExample.ios.js
index 57a2f032cdbf..fbf434cdeccb 100644
--- a/Examples/UIExplorer/TextExample.ios.js
+++ b/Examples/UIExplorer/TextExample.ios.js
@@ -424,6 +424,17 @@ exports.examples = [
       </View>
     );
   },
+}, {
+  title: 'Text shadow',
+  render: function() {
+    return (
+      <View>
+        <Text style={{fontSize: 20, textShadowOffset: {width: 2, height: 2}, textShadowRadius: 1, textShadowColor: '#00cccc'}}>
+          Demo text shadow
+        </Text>
+      </View>
+    );
+  },
 }];
 
 var styles = StyleSheet.create({
diff --git a/Libraries/Components/View/ReactNativeStyleAttributes.js b/Libraries/Components/View/ReactNativeStyleAttributes.js
index ffeff5420d2e..d26e01615f27 100644
--- a/Libraries/Components/View/ReactNativeStyleAttributes.js
+++ b/Libraries/Components/View/ReactNativeStyleAttributes.js
@@ -46,5 +46,6 @@ ReactNativeStyleAttributes.color = colorAttributes;
 ReactNativeStyleAttributes.shadowColor = colorAttributes;
 ReactNativeStyleAttributes.textDecorationColor = colorAttributes;
 ReactNativeStyleAttributes.tintColor = colorAttributes;
+ReactNativeStyleAttributes.textShadowColor = colorAttributes;
 
 module.exports = ReactNativeStyleAttributes;
diff --git a/Libraries/Text/RCTShadowText.h b/Libraries/Text/RCTShadowText.h
index 1ded47c93f4f..5d793916bb1d 100644
--- a/Libraries/Text/RCTShadowText.h
+++ b/Libraries/Text/RCTShadowText.h
@@ -33,6 +33,9 @@ extern NSString *const RCTReactTagAttributeName;
 @property (nonatomic, assign) CGFloat fontSizeMultiplier;
 @property (nonatomic, assign) BOOL allowFontScaling;
 @property (nonatomic, assign) CGFloat opacity;
+@property (nonatomic, assign) CGSize textShadowOffset;
+@property (nonatomic, assign) CGFloat textShadowRadius;
+@property (nonatomic, strong) UIColor *textShadowColor;
 
 - (void)recomputeText;
 
diff --git a/Libraries/Text/RCTShadowText.m b/Libraries/Text/RCTShadowText.m
index 9139c187d58a..4d4380d428d1 100644
--- a/Libraries/Text/RCTShadowText.m
+++ b/Libraries/Text/RCTShadowText.m
@@ -305,22 +305,31 @@ - (void)_setParagraphStyleOnAttributedString:(NSMutableAttributedString *)attrib
   }
 
   // Text decoration
-  if(_textDecorationLine == RCTTextDecorationLineTypeUnderline ||
-     _textDecorationLine == RCTTextDecorationLineTypeUnderlineStrikethrough) {
+  if (_textDecorationLine == RCTTextDecorationLineTypeUnderline ||
+      _textDecorationLine == RCTTextDecorationLineTypeUnderlineStrikethrough) {
     [self _addAttribute:NSUnderlineStyleAttributeName withValue:@(_textDecorationStyle)
      toAttributedString:attributedString];
   }
-  if(_textDecorationLine == RCTTextDecorationLineTypeStrikethrough ||
-     _textDecorationLine == RCTTextDecorationLineTypeUnderlineStrikethrough){
+  if (_textDecorationLine == RCTTextDecorationLineTypeStrikethrough ||
+      _textDecorationLine == RCTTextDecorationLineTypeUnderlineStrikethrough){
     [self _addAttribute:NSStrikethroughStyleAttributeName withValue:@(_textDecorationStyle)
      toAttributedString:attributedString];
   }
-  if(_textDecorationColor) {
+  if (_textDecorationColor) {
     [self _addAttribute:NSStrikethroughColorAttributeName withValue:_textDecorationColor
      toAttributedString:attributedString];
     [self _addAttribute:NSUnderlineColorAttributeName withValue:_textDecorationColor
      toAttributedString:attributedString];
   }
+
+  // Text shadow
+  if (!CGSizeEqualToSize(_textShadowOffset, CGSizeZero)) {
+    NSShadow *shadow = [NSShadow new];
+    shadow.shadowOffset = _textShadowOffset;
+    shadow.shadowBlurRadius = _textShadowRadius;
+    shadow.shadowColor = _textShadowColor;
+    [self _addAttribute:NSShadowAttributeName withValue:shadow toAttributedString:attributedString];
+  }
 }
 
 - (void)fillCSSNode:(css_node_t *)node
@@ -371,6 +380,9 @@ - (void)set##setProp:(type)value;              \
 RCT_TEXT_PROPERTY(TextDecorationStyle, _textDecorationStyle, NSUnderlineStyle);
 RCT_TEXT_PROPERTY(WritingDirection, _writingDirection, NSWritingDirection)
 RCT_TEXT_PROPERTY(Opacity, _opacity, CGFloat)
+RCT_TEXT_PROPERTY(TextShadowOffset, _textShadowOffset, CGSize);
+RCT_TEXT_PROPERTY(TextShadowRadius, _textShadowRadius, CGFloat);
+RCT_TEXT_PROPERTY(TextShadowColor, _textShadowColor, UIColor *);
 
 - (void)setAllowFontScaling:(BOOL)allowFontScaling
 {
diff --git a/Libraries/Text/RCTTextManager.m b/Libraries/Text/RCTTextManager.m
index 5496b3b80521..7a28ab92875f 100644
--- a/Libraries/Text/RCTTextManager.m
+++ b/Libraries/Text/RCTTextManager.m
@@ -59,6 +59,9 @@ - (RCTShadowView *)shadowView
 RCT_EXPORT_SHADOW_PROPERTY(writingDirection, NSWritingDirection)
 RCT_EXPORT_SHADOW_PROPERTY(allowFontScaling, BOOL)
 RCT_EXPORT_SHADOW_PROPERTY(opacity, CGFloat)
+RCT_EXPORT_SHADOW_PROPERTY(textShadowOffset, CGSize)
+RCT_EXPORT_SHADOW_PROPERTY(textShadowRadius, CGFloat)
+RCT_EXPORT_SHADOW_PROPERTY(textShadowColor, UIColor)
 
 - (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(NSDictionary<NSNumber *, RCTShadowView *> *)shadowViewRegistry
 {
diff --git a/Libraries/Text/TextStylePropTypes.js b/Libraries/Text/TextStylePropTypes.js
index ce1044277164..edcf428396c7 100644
--- a/Libraries/Text/TextStylePropTypes.js
+++ b/Libraries/Text/TextStylePropTypes.js
@@ -30,6 +30,11 @@ var TextStylePropTypes = Object.assign(Object.create(ViewStylePropTypes), {
     ['normal' /*default*/, 'bold',
      '100', '200', '300', '400', '500', '600', '700', '800', '900']
   ),
+  textShadowOffset: ReactPropTypes.shape(
+    {width: ReactPropTypes.number, height: ReactPropTypes.number}
+  ),
+  textShadowRadius: ReactPropTypes.number,
+  textShadowColor: ColorPropType,
   /**
    * @platform ios
    */
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java
index e6e19ad8cbf7..315052660662 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java
@@ -32,6 +32,7 @@
 import com.facebook.csslayout.CSSNode;
 import com.facebook.csslayout.MeasureOutput;
 import com.facebook.infer.annotation.Assertions;
+import com.facebook.react.bridge.ReadableMap;
 import com.facebook.react.common.annotations.VisibleForTesting;
 import com.facebook.react.uimanager.IllegalViewOperationException;
 import com.facebook.react.uimanager.LayoutShadowNode;
@@ -63,6 +64,11 @@ public class ReactTextShadowNode extends LayoutShadowNode {
   @VisibleForTesting
   public static final String PROP_TEXT = "text";
 
+  public static final String PROP_SHADOW_OFFSET = "textShadowOffset";
+  public static final String PROP_SHADOW_RADIUS = "textShadowRadius";
+  public static final String PROP_SHADOW_COLOR = "textShadowColor";
+  public static final int DEFAULT_TEXT_SHADOW_COLOR = 0x55000000;
+
   private static final TextPaint sTextPaintInstance = new TextPaint();
 
   static {
@@ -114,8 +120,7 @@ private static final void buildSpannedFromTextCSSNode(
         ops.add(new SetSpanOperation(start, end, new ForegroundColorSpan(textCSSNode.mColor)));
       }
       if (textCSSNode.mIsBackgroundColorSet) {
-        ops.add(
-            new SetSpanOperation(
+        ops.add(new SetSpanOperation(
                 start,
                 end,
                 new BackgroundColorSpan(textCSSNode.mBackgroundColor)));
@@ -135,6 +140,16 @@ private static final void buildSpannedFromTextCSSNode(
                     textCSSNode.mFontFamily,
                     textCSSNode.getThemedContext().getAssets())));
       }
+      if (textCSSNode.mTextShadowOffsetDx != 0 || textCSSNode.mTextShadowOffsetDy != 0) {
+        ops.add(new SetSpanOperation(
+                start,
+                end,
+                new ShadowStyleSpan(
+                    textCSSNode.mTextShadowOffsetDx,
+                    textCSSNode.mTextShadowOffsetDy,
+                    textCSSNode.mTextShadowRadius,
+                    textCSSNode.mTextShadowColor)));
+      }
       ops.add(new SetSpanOperation(start, end, new ReactTagSpan(textCSSNode.getReactTag())));
     }
   }
@@ -279,6 +294,11 @@ private static int parseNumericFontWeight(String fontWeightString) {
   protected int mNumberOfLines = UNSET;
   protected int mFontSize = UNSET;
 
+  private float mTextShadowOffsetDx = 0;
+  private float mTextShadowOffsetDy = 0;
+  private float mTextShadowRadius = 1;
+  private int mTextShadowColor = DEFAULT_TEXT_SHADOW_COLOR;
+
   /**
    * mFontStyle can be {@link Typeface#NORMAL} or {@link Typeface#ITALIC}.
    * mFontWeight can be {@link Typeface#NORMAL} or {@link Typeface#BOLD}.
@@ -413,6 +433,34 @@ public void setFontStyle(@Nullable String fontStyleString) {
     }
   }
 
+  @ReactProp(name = PROP_SHADOW_OFFSET)
+  public void setTextShadowOffset(ReadableMap offsetMap) {
+    if (offsetMap == null) {
+      mTextShadowOffsetDx = 0;
+      mTextShadowOffsetDy = 0;
+    } else {
+      mTextShadowOffsetDx = PixelUtil.toPixelFromDIP(offsetMap.getDouble("width"));
+      mTextShadowOffsetDy = PixelUtil.toPixelFromDIP(offsetMap.getDouble("height"));
+    }
+    markUpdated();
+  }
+
+  @ReactProp(name = PROP_SHADOW_RADIUS, defaultInt = 1)
+  public void setTextShadowRadius(float textShadowRadius) {
+    if (textShadowRadius != mTextShadowRadius) {
+      mTextShadowRadius = textShadowRadius;
+      markUpdated();
+    }
+  }
+
+  @ReactProp(name = PROP_SHADOW_COLOR, defaultInt = DEFAULT_TEXT_SHADOW_COLOR, customType = "Color")
+  public void setTextShadowColor(int textShadowColor) {
+    if (textShadowColor != mTextShadowColor) {
+      mTextShadowColor = textShadowColor;
+      markUpdated();
+    }
+  }
+
   @Override
   public boolean isVirtualAnchor() {
     return !mIsVirtual;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ShadowStyleSpan.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ShadowStyleSpan.java
new file mode 100644
index 000000000000..9e030f838ca9
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ShadowStyleSpan.java
@@ -0,0 +1,31 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.text;
+
+
+import android.text.TextPaint;
+import android.text.style.CharacterStyle;
+
+public class ShadowStyleSpan extends CharacterStyle {
+  private final float mDx, mDy, mRadius;
+  private final int mColor;
+
+  public ShadowStyleSpan(float dx, float dy, float radius, int color) {
+    mDx = dx;
+    mDy = dy;
+    mRadius = radius;
+    mColor = color;
+  }
+
+  @Override
+  public void updateDrawState(TextPaint textPaint) {
+    textPaint.setShadowLayer(mRadius, mDx, mDy, mColor);
+  }
+}

From 2d50ac359c05f1a845329cc0a975f884cca74057 Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Sat, 2 Jan 2016 03:56:32 -0500
Subject: [PATCH 0566/1411] Fix issues running the website locally on windows
 with npm3

---
 packager/blacklist.js     |  2 +-
 website/core/H2.js        |  4 +---
 website/core/Marked.js    | 11 +++++++----
 website/package.json      |  2 +-
 website/server/convert.js | 11 ++++++-----
 5 files changed, 16 insertions(+), 14 deletions(-)

diff --git a/packager/blacklist.js b/packager/blacklist.js
index 05973c286e9e..4fdca23c41a2 100644
--- a/packager/blacklist.js
+++ b/packager/blacklist.js
@@ -89,7 +89,7 @@ var platformBlacklists = {
 
 function escapeRegExp(pattern) {
   if (Object.prototype.toString.call(pattern) === '[object RegExp]') {
-    return pattern.source;
+    return pattern.source.replace(/\//g, path.sep);
   } else if (typeof pattern === 'string') {
     var escaped = pattern.replace(/[\-\[\]\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
     // convert the '/' into an escaped local file separator
diff --git a/website/core/H2.js b/website/core/H2.js
index 02cd417329c5..7bf4e9278850 100644
--- a/website/core/H2.js
+++ b/website/core/H2.js
@@ -14,9 +14,7 @@ var Header = require('Header');
 
 var H2 = React.createClass({
   render: function() {
-    return this.transferPropsTo(
-      <Header level={2}>{this.props.children}</Header>
-    );
+    return <Header {...this.props} level={2}>{this.props.children}</Header>;
   }
 });
 
diff --git a/website/core/Marked.js b/website/core/Marked.js
index c769ad5c55db..e8608e995200 100644
--- a/website/core/Marked.js
+++ b/website/core/Marked.js
@@ -811,13 +811,16 @@ Parser.prototype.tok = function() {
       return React.DOM.hr(null, null);
     }
     case 'heading': {
-      return Header(
-        {level: this.token.depth, toSlug: this.token.text},
-        this.inline.output(this.token.text)
+      return (
+        <Header
+          level={this.token.depth}
+          toSlug={this.token.text}>
+          {this.inline.output(this.token.text)}
+        </Header>
       );
     }
     case 'code': {
-      return Prism(null, this.token.text);
+      return <Prism>{this.token.text}</Prism>;
     }
     case 'table': {
       var table = []
diff --git a/website/package.json b/website/package.json
index 587e54060929..a653d6b4d94f 100644
--- a/website/package.json
+++ b/website/package.json
@@ -11,7 +11,7 @@
     "jstransform": "latest",
     "mkdirp": "latest",
     "optimist": "0.6.0",
-    "react": "~0.12.0",
+    "react": "~0.13.0",
     "react-docgen": "^2.0.1",
     "react-page-middleware": "git://github.com/facebook/react-page-middleware.git",
     "request": "latest"
diff --git a/website/server/convert.js b/website/server/convert.js
index 8edc1b190ba3..e3b95f0ba1f5 100644
--- a/website/server/convert.js
+++ b/website/server/convert.js
@@ -16,7 +16,7 @@ var extractDocs = require('./extractDocs');
 var argv = optimist.argv;
 
 function splitHeader(content) {
-  var lines = content.split('\n');
+  var lines = content.split(/\r?\n/);
   for (var i = 1; i < lines.length - 1; ++i) {
     if (lines[i] === '---') {
       break;
@@ -87,15 +87,16 @@ function execute() {
       ' * @jsx React.DOM\n' +
       ' */\n' +
       'var React = require("React");\n' +
-      'var layout = require("' + layout + '");\n' +
+      'var Layout = require("' + layout + '");\n' +
       'var content = ' + backtickify(both.content) + '\n' +
       'var Post = React.createClass({\n' +
+      '  statics: {\n' +
+      '    content: content\n' +
+      '  },\n' +
       '  render: function() {\n' +
-      '    return layout({metadata: ' + JSON.stringify(metadata) + '}, content);\n' +
+      '    return <Layout metadata={' + JSON.stringify(metadata) + '}>{content}</Layout>;\n' +
       '  }\n' +
       '});\n' +
-      // TODO: Use React statics after upgrading React
-      'Post.content = content;\n' +
       'module.exports = Post;\n'
     );
 

From 5fa33f3d07f8595a188f6fe04d6168a6ede1e721 Mon Sep 17 00:00:00 2001
From: yuanyan <yuanyan@users.noreply.github.com>
Date: Sat, 2 Jan 2016 19:33:50 +0800
Subject: [PATCH 0567/1411] Fix the 404 status url.

---
 docs/LinuxWindowsSupport.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/LinuxWindowsSupport.md b/docs/LinuxWindowsSupport.md
index 18c4ea9db68c..65bc9e851eb1 100644
--- a/docs/LinuxWindowsSupport.md
+++ b/docs/LinuxWindowsSupport.md
@@ -22,6 +22,6 @@ On Windows the packager won't be started automatically when you run `react-nativ
     cd MyAwesomeApp
     react-native start
 
-If you hit a `ERROR  Watcher took too long to load` on Windows, try increasing the timeout in [this file](https://github.com/facebook/react-native/blob/master/packager/react-packager/src/FileWatcher/index.js#L17) (under your node_modules/react-native).
+If you hit a `ERROR  Watcher took too long to load` on Windows, try increasing the timeout in [this file](https://github.com/facebook/react-native/blob/master/packager/react-packager/src/DependencyResolver/FileWatcher/index.js#L16) (under your node_modules/react-native).
 
 

From 4d403efab3a63d0bdf450f63e109ffe541a4e12b Mon Sep 17 00:00:00 2001
From: Sharath Prabhal <sharathbose@gmail.com>
Date: Sun, 3 Jan 2016 00:13:17 -0500
Subject: [PATCH 0568/1411] Add 'Eat or Not' play store link

---
 website/src/react-native/showcase.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 71f2e7d09318..5abaaedec9a2 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -194,7 +194,8 @@ var apps = [
   {
     name: 'Eat or Not',
     icon: 'http://a3.mzstatic.com/us/r30/Purple5/v4/51/be/34/51be3462-b015-ebf2-11c5-69165b37fadc/icon175x175.jpeg',
-    link: 'https://itunes.apple.com/us/app/eat-or-not/id1054565697?mt=8',
+    linkAppStore: 'https://itunes.apple.com/us/app/eat-or-not/id1054565697?mt=8',
+    linkPlayStore: 'https://play.google.com/store/apps/details?id=com.eon',
     author: 'Sharath Prabhal',
   },
   {

From d8e138770f20e6fe5c6ba86840c9ec0d74400011 Mon Sep 17 00:00:00 2001
From: Qiao Liang <qiaoliang89@gmail.com>
Date: Sun, 3 Jan 2016 14:48:07 +0800
Subject: [PATCH 0569/1411] added easy tasks to README

---
 README.md | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/README.md b/README.md
index 4cc7c5273f80..7f36a8b69573 100644
--- a/README.md
+++ b/README.md
@@ -90,6 +90,8 @@ The GitHub issues are intended for bug reports and feature requests. For help an
 
 For more information about contributing PRs and issues, see our [Contribution Guidelines](https://github.com/facebook/react-native/blob/master/CONTRIBUTING.md).
 
+[Good First Task](https://github.com/facebook/react-native/labels/Good%20First%20Task) is a great starting point for PRs.
+
 We encourage the community to ask and answer questions on Stack Overflow with [the react-native tag](https://stackoverflow.com/questions/tagged/react-native). It's a great way to help out and be involved!
 
 ## License

From e62471b7c3cdcabca182f3e194b5d95c4f500c75 Mon Sep 17 00:00:00 2001
From: Jay Salvat <jay@jaysalvat.com>
Date: Sat, 2 Jan 2016 22:51:02 -0800
Subject: [PATCH 0570/1411] Fix pop method to properly refresh the navigatorBar

Summary:
When using nativator.pop() the navigatorBar doesn't refresh properly if we change navigationBarHidden.

When navigator.pop() is called, the navbar doesn't show up, even avec navigationBarHidden set back to true. See between Statusbar and Movie poster in the example below.

![bad](https://cloud.githubusercontent.com/assets/55496/8683849/77effa30-2a75-11e5-9f32-9be6fa87efac.gif)

    // Not actually updating the indices yet until we get the native
    // `onNavigationComplete`.
    updatingAllIndicesAtOrBeyond: null,

https://github.com/facebook/react-native/blob/master/Libraries/Components/Navigation/NavigatorIOS.ios.js#L510-L512

The View need to be refreshed in pop method anyway.

    updatingAllIndicesAtOrBeyond: this.state.requestedTopOfStack - n,

Now, navbar appears properly.

![good](https://cloud.githubusercontent.com/assets/55496/8683907/be9d2714-2a75-11e5-8fda-653e68869076.gif)
Closes https://github.com/facebook/react-native/pull/1989

Reviewed By: svcscm

Differential Revision: D2798515

Pulled By: androidtrunkagent

fb-gh-sync-id: 9d554c9d88b87628488a8cebb7e3bbe4dd9c017d
---
 Libraries/Components/Navigation/NavigatorIOS.ios.js | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/Libraries/Components/Navigation/NavigatorIOS.ios.js b/Libraries/Components/Navigation/NavigatorIOS.ios.js
index 32d51ddc84af..135ad6f12c44 100644
--- a/Libraries/Components/Navigation/NavigatorIOS.ios.js
+++ b/Libraries/Components/Navigation/NavigatorIOS.ios.js
@@ -492,9 +492,7 @@ var NavigatorIOS = React.createClass({
           this.setState({
             requestedTopOfStack: newRequestedTopOfStack,
             makingNavigatorRequest: true,
-            // Not actually updating the indices yet until we get the native
-            // `onNavigationComplete`.
-            updatingAllIndicesAtOrBeyond: null,
+            updatingAllIndicesAtOrBeyond: this.state.requestedTopOfStack - n,
           });
         });
       }

From 2af06b3c0863d2de1d9de75c57b0fb24a81d3120 Mon Sep 17 00:00:00 2001
From: lvwang2002 <lvwang2002@gmail.com>
Date: Mon, 4 Jan 2016 12:34:57 +0800
Subject: [PATCH 0571/1411] Update showcase.js

all the function of android version made by react native
the function of search of iOS version made by react native.
---
 website/src/react-native/showcase.js | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 5abaaedec9a2..9414b95cf9e3 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -477,6 +477,13 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/yazboz-batak-esli-batak-okey/id1048620855?ls=1&mt=8',
     author: 'Melih Mucuk',
   },
+  {
+    name:'天才段子手',
+    icon:'http://pp.myapp.com/ma_icon/0/icon_12236104_1451810987/96',
+    linkAppStore: 'https://itunes.apple.com/us/app/tian-cai-duan-zi-shou-shen/id992312701?l=zh&ls=1&mt=8',
+    linkPlayStore: 'https://play.google.com/store/apps/details?id=com.geniusJokeWriter.app',
+    author:'Ran Zhao&Ji Zhao'
+  }
 ];
 
 var AppList = React.createClass({

From e42c6d4446dd1b5b9f68b1dfd2822c79036c2c3c Mon Sep 17 00:00:00 2001
From: Mike Armstrong <mikea@fb.com>
Date: Mon, 4 Jan 2016 02:15:19 -0800
Subject: [PATCH 0572/1411] Flows between RN Threads

Reviewed By: tadeuzagallo

Differential Revision: D2743733

fb-gh-sync-id: df4ae69a3501a37e08286857a8d4be3cd27c0ac3
---
 Libraries/Utilities/MessageQueue.js           | 39 ++++++++++++-------
 React/Base/RCTBatchedBridge.m                 | 13 +++----
 .../react/bridge/CatalystInstanceImpl.java    | 23 +++++++++++
 .../react/uimanager/events/Event.java         | 10 +++++
 .../uimanager/events/EventDispatcher.java     | 18 +++++++++
 .../src/main/jni/react/MethodCall.cpp         | 18 ++++++++-
 ReactAndroid/src/main/jni/react/MethodCall.h  |  6 ++-
 .../src/main/jni/react/jni/OnLoad.cpp         |  4 ++
 8 files changed, 106 insertions(+), 25 deletions(-)

diff --git a/Libraries/Utilities/MessageQueue.js b/Libraries/Utilities/MessageQueue.js
index 1bd46424d2eb..1eb3c5c65795 100644
--- a/Libraries/Utilities/MessageQueue.js
+++ b/Libraries/Utilities/MessageQueue.js
@@ -24,8 +24,11 @@ let stringifySafe = require('stringifySafe');
 let MODULE_IDS = 0;
 let METHOD_IDS = 1;
 let PARAMS = 2;
+let CALL_IDS = 3;
 let MIN_TIME_BETWEEN_FLUSHES_MS = 5;
 
+let TRACE_TAG_REACT_APPS = 1 << 17;
+
 let SPY_MODE = false;
 
 let MethodTypes = keyMirror({
@@ -47,11 +50,12 @@ class MessageQueue {
     this.RemoteModules = {};
 
     this._callableModules = {};
-    this._queue = [[],[],[]];
+    this._queue = [[], [], [], 0];
     this._moduleTable = {};
     this._methodTable = {};
     this._callbacks = [];
     this._callbackID = 0;
+    this._callID = 0;
     this._lastFlush = 0;
     this._eventLoopStartTime = new Date().getTime();
 
@@ -100,7 +104,7 @@ class MessageQueue {
     this.__callImmediates();
 
     let queue = this._queue;
-    this._queue = [[],[],[]];
+    this._queue = [[], [], [], this._callID];
     return queue[0].length ? queue : null;
   }
 
@@ -136,6 +140,11 @@ class MessageQueue {
       onSucc && params.push(this._callbackID);
       this._callbacks[this._callbackID++] = onSucc;
     }
+
+    global.nativeTraceBeginAsyncFlow &&
+      global.nativeTraceBeginAsyncFlow(TRACE_TAG_REACT_APPS, 'native', this._callID);
+    this._callID++;
+
     this._queue[MODULE_IDS].push(module);
     this._queue[METHOD_IDS].push(method);
     this._queue[PARAMS].push(params);
@@ -144,7 +153,7 @@ class MessageQueue {
     if (global.nativeFlushQueueImmediate &&
         now - this._lastFlush >= MIN_TIME_BETWEEN_FLUSHES_MS) {
       global.nativeFlushQueueImmediate(this._queue);
-      this._queue = [[],[],[]];
+      this._queue = [[], [], [], this._callID];
       this._lastFlush = now;
     }
     Systrace.counterEvent('pending_js_to_native_queue', this._queue[0].length);
@@ -176,22 +185,22 @@ class MessageQueue {
   }
 
   __invokeCallback(cbID, args) {
-    Systrace.beginEvent(`MessageQueue.invokeCallback(${cbID})`);
     this._lastFlush = new Date().getTime();
     this._eventLoopStartTime = this._lastFlush;
     let callback = this._callbacks[cbID];
-    if (!callback || __DEV__) {
-      let debug = this._debugInfo[cbID >> 1];
-      let module = debug && this._remoteModuleTable[debug[0]];
-      let method = debug && this._remoteMethodTable[debug[0]][debug[1]];
-      invariant(
-        callback,
-        `Callback with id ${cbID}: ${module}.${method}() not found`
-      );
-      if (callback && SPY_MODE) {
-        console.log('N->JS : <callback for ' + module + '.' + method + '>(' + JSON.stringify(args) + ')');
-      }
+    let debug = this._debugInfo[cbID >> 1];
+    let module = debug && this._remoteModuleTable[debug[0]];
+    let method = debug && this._remoteMethodTable[debug[0]][debug[1]];
+    invariant(
+      callback,
+      `Callback with id ${cbID}: ${module}.${method}() not found`
+    );
+    let profileName = debug ? '<callback for ' + module + '.' + method + '>' : cbID;
+    if (callback && SPY_MODE && __DEV__) {
+      console.log('N->JS : ' + profileName + '(' + JSON.stringify(args) + ')');
     }
+    Systrace.beginEvent(
+      `MessageQueue.invokeCallback(${profileName}, ${stringifySafe(args)})`);
     this._callbacks[cbID & ~1] = null;
     this._callbacks[cbID |  1] = null;
     callback.apply(null, args);
diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index 4946cd01258d..f4ac4e2c10f7 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -778,19 +778,18 @@ - (void)handleBuffer:(id)buffer batchEnded:(BOOL)batchEnded
   }
 }
 
-- (void)handleBuffer:(NSArray<NSArray *> *)buffer
+- (void)handleBuffer:(NSArray *)buffer
 {
-  NSArray<NSArray *> *requestsArray = [RCTConvert NSArrayArray:buffer];
-
+  NSArray *requestsArray = [RCTConvert NSArray:buffer];
   if (RCT_DEBUG && requestsArray.count <= RCTBridgeFieldParamss) {
     RCTLogError(@"Buffer should contain at least %tu sub-arrays. Only found %tu",
-                RCTBridgeFieldParamss + 1, requestsArray.count);
+              RCTBridgeFieldParamss + 1, requestsArray.count);
     return;
   }
 
-  NSArray<NSNumber *> *moduleIDs = requestsArray[RCTBridgeFieldRequestModuleIDs];
-  NSArray<NSNumber *> *methodIDs = requestsArray[RCTBridgeFieldMethodIDs];
-  NSArray<NSArray *> *paramsArrays = requestsArray[RCTBridgeFieldParamss];
+  NSArray<NSNumber *> *moduleIDs = [RCTConvert NSNumberArray:requestsArray[RCTBridgeFieldRequestModuleIDs]];
+  NSArray<NSNumber *> *methodIDs = [RCTConvert NSNumberArray:requestsArray[RCTBridgeFieldMethodIDs]];
+  NSArray<NSArray *> *paramsArrays = [RCTConvert NSArrayArray:requestsArray[RCTBridgeFieldParamss]];
 
   if (RCT_DEBUG && (moduleIDs.count != methodIDs.count || moduleIDs.count != paramsArrays.count)) {
     RCTLogError(@"Invalid data message - all must be length: %zd", moduleIDs.count);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
index 77264028578f..da3750cfe941 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
@@ -56,6 +56,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
   private final TraceListener mTraceListener;
   private final JavaScriptModuleRegistry mJSModuleRegistry;
   private final JSBundleLoader mJSBundleLoader;
+  private volatile int mTraceID = 0;
 
   // Access from native modules thread
   private final NativeModuleRegistry mJavaRegistry;
@@ -176,12 +177,23 @@ public Boolean call() throws Exception {
 
     incrementPendingJSCalls();
 
+    final int traceID = mTraceID++;
+    Systrace.startAsyncFlow(
+        Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
+        tracingName,
+        traceID);
+
     mCatalystQueueConfiguration.getJSQueueThread().runOnQueue(
         new Runnable() {
           @Override
           public void run() {
             mCatalystQueueConfiguration.getJSQueueThread().assertIsOnThread();
 
+            Systrace.endAsyncFlow(
+                Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
+                tracingName,
+                traceID);
+
             if (mDestroyed) {
               return;
             }
@@ -208,12 +220,23 @@ public void invokeCallback(final int callbackID, final NativeArray arguments) {
 
     incrementPendingJSCalls();
 
+    final int traceID = mTraceID++;
+    Systrace.startAsyncFlow(
+        Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
+        "<callback>",
+        traceID);
+
     mCatalystQueueConfiguration.getJSQueueThread().runOnQueue(
         new Runnable() {
           @Override
           public void run() {
             mCatalystQueueConfiguration.getJSQueueThread().assertIsOnThread();
 
+            Systrace.endAsyncFlow(
+                Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
+                "<callback>",
+                traceID);
+
             if (mDestroyed) {
               return;
             }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/Event.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/Event.java
index 58dd958a6993..40c2845c8adb 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/Event.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/Event.java
@@ -18,9 +18,12 @@
  */
 public abstract class Event<T extends Event> {
 
+  private static int sUniqueID = 0;
+
   private boolean mInitialized;
   private int mViewTag;
   private long mTimestampMs;
+  private int mUniqueID = sUniqueID++;
 
   protected Event() {
   }
@@ -80,6 +83,13 @@ public short getCoalescingKey() {
     return 0;
   }
 
+  /**
+   * @return The unique id of this event.
+   */
+  public int getUniqueID() {
+    return mUniqueID;
+  }
+
   /**
    * Called when the EventDispatcher is done with an event, either because it was dispatched or
    * because it was coalesced with another Event.
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java
index 35c0a2897e4b..c8635d051588 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java
@@ -100,6 +100,7 @@ public int compare(Event lhs, Event rhs) {
   private volatile @Nullable ScheduleDispatchFrameCallback mCurrentFrameCallback;
   private short mNextEventTypeId = 0;
   private volatile boolean mHasDispatchScheduled = false;
+  private volatile int mHasDispatchScheduledCount = 0;
 
   public EventDispatcher(ReactApplicationContext reactContext) {
     mReactContext = reactContext;
@@ -113,6 +114,10 @@ public void dispatchEvent(Event event) {
     Assertions.assertCondition(event.isInitialized(), "Dispatched event hasn't been initialized");
     synchronized (mEventsStagingLock) {
       mEventStaging.add(event);
+      Systrace.startAsyncFlow(
+          Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
+          event.getEventName(),
+          event.getUniqueID());
     }
   }
 
@@ -242,6 +247,10 @@ public void doFrame(long frameTimeNanos) {
 
         if (!mHasDispatchScheduled) {
           mHasDispatchScheduled = true;
+          Systrace.startAsyncFlow(
+              Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
+              "ScheduleDispatchFrameCallback",
+              mHasDispatchScheduledCount);
           mReactContext.runOnJSQueueThread(mDispatchEventsRunnable);
         }
 
@@ -263,7 +272,12 @@ private class DispatchEventsRunnable implements Runnable {
     public void run() {
       Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "DispatchEventsRunnable");
       try {
+        Systrace.endAsyncFlow(
+            Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
+            "ScheduleDispatchFrameCallback",
+            mHasDispatchScheduledCount);
         mHasDispatchScheduled = false;
+        mHasDispatchScheduledCount++;
         Assertions.assertNotNull(mRCTEventEmitter);
         synchronized (mEventsToDispatchLock) {
           // We avoid allocating an array and iterator, and "sorting" if we don't need to.
@@ -277,6 +291,10 @@ public void run() {
             if (event == null) {
               continue;
             }
+            Systrace.endAsyncFlow(
+                Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
+                event.getEventName(),
+                event.getUniqueID());
             event.dispatch(mRCTEventEmitter);
             event.dispose();
           }
diff --git a/ReactAndroid/src/main/jni/react/MethodCall.cpp b/ReactAndroid/src/main/jni/react/MethodCall.cpp
index ce12d368381e..ac9b13edd57f 100644
--- a/ReactAndroid/src/main/jni/react/MethodCall.cpp
+++ b/ReactAndroid/src/main/jni/react/MethodCall.cpp
@@ -12,6 +12,7 @@ namespace react {
 #define REQUEST_MODULE_IDS 0
 #define REQUEST_METHOD_IDS 1
 #define REQUEST_PARAMSS 2
+#define REQUEST_CALLID 3
 
 std::vector<MethodCall> parseMethodCalls(const std::string& json) {
   folly::dynamic jsonData = folly::parseJson(json);
@@ -33,6 +34,7 @@ std::vector<MethodCall> parseMethodCalls(const std::string& json) {
   auto moduleIds = jsonData[REQUEST_MODULE_IDS];
   auto methodIds = jsonData[REQUEST_METHOD_IDS];
   auto params = jsonData[REQUEST_PARAMSS];
+  int  callId = -1;
 
   if (!moduleIds.isArray() || !methodIds.isArray() || !params.isArray()) {
     jni::throwNewJavaException(jni::gJavaLangIllegalArgumentException,
@@ -40,6 +42,16 @@ std::vector<MethodCall> parseMethodCalls(const std::string& json) {
                                json.c_str());
   }
 
+  if (jsonData.size() > REQUEST_CALLID) {
+    if (!jsonData[REQUEST_CALLID].isInt()) {
+      jni::throwNewJavaException(jni::gJavaLangIllegalArgumentException,
+                               "Did not get valid calls back from JS: %s",
+                               json.c_str());
+    } else {
+      callId = jsonData[REQUEST_CALLID].getInt();
+    }
+  }
+
   std::vector<MethodCall> methodCalls;
   for (size_t i = 0; i < moduleIds.size(); i++) {
     auto paramsValue = params[i];
@@ -51,7 +63,11 @@ std::vector<MethodCall> parseMethodCalls(const std::string& json) {
     methodCalls.emplace_back(
       moduleIds[i].getInt(),
       methodIds[i].getInt(),
-      std::move(params[i]));
+      std::move(params[i]),
+      callId);
+
+    // only incremement callid if contains valid callid as callid is optional
+    callId += (callId != -1) ? 1 : 0;
   }
 
   return methodCalls;
diff --git a/ReactAndroid/src/main/jni/react/MethodCall.h b/ReactAndroid/src/main/jni/react/MethodCall.h
index 7bb47dca9d7c..02e86eb98760 100644
--- a/ReactAndroid/src/main/jni/react/MethodCall.h
+++ b/ReactAndroid/src/main/jni/react/MethodCall.h
@@ -15,11 +15,13 @@ struct MethodCall {
   int moduleId;
   int methodId;
   folly::dynamic arguments;
+  int callId;
 
-  MethodCall(int mod, int meth, folly::dynamic args)
+  MethodCall(int mod, int meth, folly::dynamic args, int cid)
     : moduleId(mod)
     , methodId(meth)
-    , arguments(std::move(args)) {}
+    , arguments(std::move(args))
+    , callId(cid) {}
 };
 
 std::vector<MethodCall> parseMethodCalls(const std::string& json);
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index b5ad6a11f225..e4368d682ef3 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -17,6 +17,7 @@
 #include "ReadableNativeArray.h"
 #include "ProxyExecutor.h"
 #include "OnLoad.h"
+#include <algorithm>
 
 #ifdef WITH_FBSYSTRACE
 #include <fbsystrace.h>
@@ -561,6 +562,9 @@ static void makeJavaCall(JNIEnv* env, jobject callback, MethodCall&& call) {
   if (call.arguments.isNull()) {
     return;
   }
+  if (call.callId != -1) {
+    fbsystrace_end_async_flow(TRACE_TAG_REACT_APPS, "native", call.callId);
+  }
   auto newArray = ReadableNativeArray::newObjectCxxArgs(std::move(call.arguments));
   env->CallVoidMethod(callback, gCallbackMethod, call.moduleId, call.methodId, newArray.get());
 }

From 52220a96f9b212e91d187bef9e79cf34fc57f51e Mon Sep 17 00:00:00 2001
From: Jed Lau <jedlau@samsara.com>
Date: Mon, 4 Jan 2016 04:30:37 -0800
Subject: [PATCH 0573/1411] Export method to get current status bar height

Summary:
Addresses #2515 .
Closes https://github.com/facebook/react-native/pull/5039

Reviewed By: svcscm

Differential Revision: D2799224

Pulled By: nicklockwood

fb-gh-sync-id: 8f0a0f229a1588b1033b0121868c1f82e4dc6684
---
 React/Modules/RCTStatusBarManager.m | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/React/Modules/RCTStatusBarManager.m b/React/Modules/RCTStatusBarManager.m
index dd29a078992d..026d1901209c 100644
--- a/React/Modules/RCTStatusBarManager.m
+++ b/React/Modules/RCTStatusBarManager.m
@@ -89,6 +89,13 @@ - (void)applicationWillChangeStatusBarFrame:(NSNotification *)notification
   [self emitEvent:@"statusBarFrameWillChange" forNotification:notification];
 }
 
+RCT_EXPORT_METHOD(getHeight:(RCTResponseSenderBlock)callback)
+{
+  callback(@[@{
+    @"height": @([UIApplication sharedApplication].statusBarFrame.size.height),
+  }]);
+}
+
 RCT_EXPORT_METHOD(setStyle:(UIStatusBarStyle)statusBarStyle
                   animated:(BOOL)animated)
 {

From 40d9918f5def8e68f8f07f1e0a791972ad1e0f6b Mon Sep 17 00:00:00 2001
From: Mike Armstrong <mikea@fb.com>
Date: Mon, 4 Jan 2016 05:12:08 -0800
Subject: [PATCH 0574/1411] Fix systrace use in OSS

Reviewed By: bestander

Differential Revision: D2799222

fb-gh-sync-id: 8002c7f94eedffdf05bb134ced14809a78757bb0
---
 ReactAndroid/src/main/jni/react/jni/OnLoad.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index e4368d682ef3..5ef5c28aaba5 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -562,9 +562,13 @@ static void makeJavaCall(JNIEnv* env, jobject callback, MethodCall&& call) {
   if (call.arguments.isNull()) {
     return;
   }
+
+  #ifdef WITH_FBSYSTRACE
   if (call.callId != -1) {
     fbsystrace_end_async_flow(TRACE_TAG_REACT_APPS, "native", call.callId);
   }
+  #endif
+
   auto newArray = ReadableNativeArray::newObjectCxxArgs(std::move(call.arguments));
   env->CallVoidMethod(callback, gCallbackMethod, call.moduleId, call.methodId, newArray.get());
 }

From c91f9ce5764482ddd32e5805e12858ae9a6ed091 Mon Sep 17 00:00:00 2001
From: Alexey Vasiliev <le0pard@users.noreply.github.com>
Date: Mon, 4 Jan 2016 15:13:13 +0200
Subject: [PATCH 0575/1411] Add RWpodPlayer as showcase for React Native apps

---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 5abaaedec9a2..10f204e8a497 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -404,6 +404,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/rota-worker-shifts-on-demand/id1042111289?mt=8',
     author: 'Rota',
   },
+  {
+    name: 'RWpodPlayer - audio player for RWpod podcast',
+    icon: 'http://a1.mzstatic.com/us/r30/Purple69/v4/a8/c0/b1/a8c0b130-e44b-742d-6458-0c89fcc15b6b/icon175x175.png',
+    link: 'https://itunes.apple.com/us/app/rwpodplayer/id1053885042?mt=8',
+    author: 'Alexey Vasiliev aka leopard',
+  },
   {
     name: 'SG Toto 4d',
     icon: 'http://a4.mzstatic.com/us/r30/Purple7/v4/d2/bc/46/d2bc4696-84d6-9681-a49f-7f660d6b04a7/icon175x175.jpeg',

From 64edddadccecb8a6b062c16253daac403486cbcb Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Mon, 4 Jan 2016 06:23:51 -0800
Subject: [PATCH 0576/1411] Fixed race condition in RCTModuleData.methodQueue

Summary:
public
The implementation of the `methodQueue` lazy initializer in `RCTModuleData` could result in the queue being set twice, because calling `methodQueue` for a module that hasn't been instantiated would call `RCTModuleData.instance` to create the module, which itself calls `methodQueue`.

It's not clear if this was causing a bug, but it may be related to an occasional bug where the `RCTViewManager.methodQueue` returns nil.

Reviewed By: majak

Differential Revision: D2783320

fb-gh-sync-id: 9194da0fd7392f63825da1f5c450363dd300b635
---
 React/Base/RCTBatchedBridge.m |   4 +-
 React/Base/RCTBridgeModule.h  |   2 +-
 React/Base/RCTModuleData.m    | 110 ++++++++++++++++++++--------------
 3 files changed, 69 insertions(+), 47 deletions(-)

diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index f4ac4e2c10f7..de9142e58269 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -319,7 +319,9 @@ - (void)initModules
   _javaScriptExecutor = [self moduleForClass:self.executorClass];
 
   for (RCTModuleData *moduleData in _moduleDataByID) {
-    [moduleData setBridgeForInstance:self];
+    if (moduleData.hasInstance) {
+      [moduleData setBridgeForInstance:self];
+    }
   }
 
   for (RCTModuleData *moduleData in _moduleDataByID) {
diff --git a/React/Base/RCTBridgeModule.h b/React/Base/RCTBridgeModule.h
index dd6dda34cf18..39c7acad4aee 100644
--- a/React/Base/RCTBridgeModule.h
+++ b/React/Base/RCTBridgeModule.h
@@ -94,7 +94,7 @@ RCT_EXTERN void RCTRegisterModule(Class); \
  * }
  *
  * If you don't want to specify the queue yourself, but you need to use it
- * inside your class (e.g. if you have internal methods that need to disaptch
+ * inside your class (e.g. if you have internal methods that need to dispatch
  * onto that queue), you can just add `@synthesize methodQueue = _methodQueue;`
  * and the bridge will populate the methodQueue property for you automatically
  * when it initializes the module.
diff --git a/React/Base/RCTModuleData.m b/React/Base/RCTModuleData.m
index 9b28cd6570c4..71f5dd2f91fb 100644
--- a/React/Base/RCTModuleData.m
+++ b/React/Base/RCTModuleData.m
@@ -48,37 +48,82 @@ - (instancetype)initWithModuleInstance:(id<RCTBridgeModule>)instance
 
 RCT_NOT_IMPLEMENTED(- (instancetype)init);
 
-- (BOOL)hasInstance
+- (void)cacheImplementedSelectors
 {
-  return _instance != nil;
+  _implementsBatchDidComplete = [_instance respondsToSelector:@selector(batchDidComplete)];
+  _implementsPartialBatchDidFlush = [_instance respondsToSelector:@selector(partialBatchDidFlush)];
 }
 
-- (id<RCTBridgeModule>)instance
+- (void)setUpMethodQueue
 {
-  if (!_instance) {
-    _instance = [_moduleClass new];
+  RCTAssert(!_methodQueue, @"Method queue is already set up");
+  RCTAssert(_instance, @"Instance is not yet set up");
 
-    // Bridge must be set before methodQueue is set up, as methodQueue
-    // initialization requires it (View Managers get their queue by calling
-    // self.bridge.uiManager.methodQueue)
-    [self setBridgeForInstance:_bridge];
+  BOOL implementsMethodQueue = [_instance respondsToSelector:@selector(methodQueue)];
+  if (implementsMethodQueue) {
+    _methodQueue = _instance.methodQueue;
+  }
+  if (!_methodQueue) {
 
-    // Initialize queue
-    [self methodQueue];
+    // Create new queue (store queueName, as it isn't retained by dispatch_queue)
+    _queueName = [NSString stringWithFormat:@"com.facebook.React.%@Queue", self.name];
+    _methodQueue = dispatch_queue_create(_queueName.UTF8String, DISPATCH_QUEUE_SERIAL);
 
-    [self cacheImplementedSelectors];
+    // assign it to the module
+    if (implementsMethodQueue) {
+      @try {
+        [(id)_instance setValue:_methodQueue forKey:@"methodQueue"];
+      }
+      @catch (NSException *exception) {
+        RCTLogError(@"%@ is returning nil for it's methodQueue, which is not "
+                    "permitted. You must either return a pre-initialized "
+                    "queue, or @synthesize the methodQueue to let the bridge "
+                    "create a queue for you.", self.name);
+      }
+    }
   }
-  return _instance;
+
+  // Needs to be sent after bridge has been set for all module instances.
+  // Makes sense to put it here, since the same rules apply for methodQueue.
+  [[NSNotificationCenter defaultCenter]
+   postNotificationName:RCTDidInitializeModuleNotification
+   object:_bridge userInfo:@{@"module": _instance}];
 }
 
-- (void)cacheImplementedSelectors
+- (void)setUpInstance
 {
-  _implementsBatchDidComplete = [_instance respondsToSelector:@selector(batchDidComplete)];
-  _implementsPartialBatchDidFlush = [_instance respondsToSelector:@selector(partialBatchDidFlush)];
+  RCTAssert(!_instance, @"Instance is already set up");
+
+  _instance = [_moduleClass new];
+
+  // Bridge must be set before methodQueue is set up, as methodQueue
+  // initialization requires it (View Managers get their queue by calling
+  // self.bridge.uiManager.methodQueue)
+  [self setBridgeForInstance:_bridge];
+
+  // Initialize queue
+  [self setUpMethodQueue];
+
+  [self cacheImplementedSelectors];
+}
+
+- (BOOL)hasInstance
+{
+  return _instance != nil;
+}
+
+- (id<RCTBridgeModule>)instance
+{
+  if (!_instance) {
+    [self setUpInstance];
+  }
+  return _instance;
 }
 
 - (void)setBridgeForInstance:(RCTBridge *)bridge
 {
+  RCTAssert(_instance, @"setBridgeForInstance called before module was initialized");
+
   _bridge = bridge;
   if ([_instance respondsToSelector:@selector(bridge)]) {
     @try {
@@ -175,36 +220,11 @@ - (NSArray *)config
 
 - (dispatch_queue_t)methodQueue
 {
+  if (!_instance) {
+    [self setUpInstance];
+  }
   if (!_methodQueue) {
-    BOOL implementsMethodQueue = [self.instance respondsToSelector:@selector(methodQueue)];
-    if (implementsMethodQueue) {
-      _methodQueue = _instance.methodQueue;
-    }
-    if (!_methodQueue) {
-
-      // Create new queue (store queueName, as it isn't retained by dispatch_queue)
-      _queueName = [NSString stringWithFormat:@"com.facebook.React.%@Queue", self.name];
-      _methodQueue = dispatch_queue_create(_queueName.UTF8String, DISPATCH_QUEUE_SERIAL);
-
-      // assign it to the module
-      if (implementsMethodQueue) {
-        @try {
-          [(id)_instance setValue:_methodQueue forKey:@"methodQueue"];
-        }
-        @catch (NSException *exception) {
-          RCTLogError(@"%@ is returning nil for it's methodQueue, which is not "
-                      "permitted. You must either return a pre-initialized "
-                      "queue, or @synthesize the methodQueue to let the bridge "
-                      "create a queue for you.", self.name);
-        }
-      }
-    }
-
-    // Needs to be sent after bridge has been set for all module instances.
-    // Makes sense to put it here, since the same rules apply for methodQueue.
-    [[NSNotificationCenter defaultCenter]
-     postNotificationName:RCTDidInitializeModuleNotification
-                   object:_bridge userInfo:@{@"module": _instance}];
+    [self setUpMethodQueue];
   }
   return _methodQueue;
 }

From b8aac8b77a6b0737c23fd7d68c7b83ff068f5c4c Mon Sep 17 00:00:00 2001
From: Jason Brown <browniefed@gmail.com>
Date: Mon, 4 Jan 2016 06:37:15 -0800
Subject: [PATCH 0577/1411] Implement draggable annotations on MapView. Closes
 #2512

Summary: Closes https://github.com/facebook/react-native/pull/4441

Reviewed By: svcscm

Differential Revision: D2707897

Pulled By: nicklockwood

fb-gh-sync-id: 6f67f711c1ec1f821d03b9b1ea5cc39859d28fd1
---
 Examples/UIExplorer/ImageExample.js     |  3 +-
 Examples/UIExplorer/MapViewExample.js   | 80 +++++++++----------------
 Libraries/Components/MapView/MapView.js | 46 +++++++++++++-
 React/Views/RCTConvert+MapKit.m         | 35 +++++------
 React/Views/RCTMap.h                    |  1 +
 React/Views/RCTMapAnnotation.h          |  1 +
 React/Views/RCTMapManager.m             | 31 +++++++++-
 7 files changed, 122 insertions(+), 75 deletions(-)

diff --git a/Examples/UIExplorer/ImageExample.js b/Examples/UIExplorer/ImageExample.js
index 163396f89a9c..60fc38dabe2e 100644
--- a/Examples/UIExplorer/ImageExample.js
+++ b/Examples/UIExplorer/ImageExample.js
@@ -442,7 +442,8 @@ exports.examples = [
     title: 'Image Size',
     render: function() {
       return <ImageSizeExample source={fullImage} />; 
-    }
+    },
+    platform: 'ios',
   },
 ];
 
diff --git a/Examples/UIExplorer/MapViewExample.js b/Examples/UIExplorer/MapViewExample.js
index 3df5d4ded06a..498a5f83df0d 100644
--- a/Examples/UIExplorer/MapViewExample.js
+++ b/Examples/UIExplorer/MapViewExample.js
@@ -19,6 +19,7 @@ var React = require('react-native');
 var {
   Image,
   MapView,
+  PropTypes,
   StyleSheet,
   Text,
   TextInput,
@@ -33,36 +34,23 @@ var regionText = {
   longitudeDelta: '0',
 };
 
-type MapRegion = {
-  latitude: number,
-  longitude: number,
-  latitudeDelta?: number,
-  longitudeDelta?: number,
-};
-
-type MapRegionInputState = {
-  region: MapRegion,
-};
-
 var MapRegionInput = React.createClass({
 
   propTypes: {
-    region: React.PropTypes.shape({
-      latitude: React.PropTypes.number.isRequired,
-      longitude: React.PropTypes.number.isRequired,
-      latitudeDelta: React.PropTypes.number,
-      longitudeDelta: React.PropTypes.number,
+    region: PropTypes.shape({
+      latitude: PropTypes.number.isRequired,
+      longitude: PropTypes.number.isRequired,
+      latitudeDelta: PropTypes.number,
+      longitudeDelta: PropTypes.number,
     }),
-    onChange: React.PropTypes.func.isRequired,
+    onChange: PropTypes.func.isRequired,
   },
 
-  getInitialState(): MapRegionInputState {
+  getInitialState() {
     return {
       region: {
         latitude: 0,
         longitude: 0,
-        latitudeDelta: 0,
-        longitudeDelta: 0,
       }
     };
   },
@@ -164,36 +152,14 @@ var MapRegionInput = React.createClass({
 
 });
 
-type Annotations = Array<{
-  animateDrop?: boolean,
-  latitude: number,
-  longitude: number,
-  title?: string,
-  subtitle?: string,
-  hasLeftCallout?: boolean,
-  hasRightCallout?: boolean,
-  onLeftCalloutPress?: Function,
-  onRightCalloutPress?: Function,
-  tintColor?: number | string,
-  image?: any,
-  id?: string,
-  view?: ReactElement,
-  leftCalloutView?: ReactElement,
-  rightCalloutView?: ReactElement,
-  detailCalloutView?: ReactElement,
-}>;
-type MapViewExampleState = {
-  isFirstLoad: boolean,
-  mapRegion?: MapRegion,
-  mapRegionInput?: MapRegion,
-  annotations?: Annotations,
-};
-
 var MapViewExample = React.createClass({
 
-  getInitialState(): MapViewExampleState {
+  getInitialState() {
     return {
       isFirstLoad: true,
+      mapRegion: undefined,
+      mapRegionInput: undefined,
+      annotations: [],
     };
   },
 
@@ -215,7 +181,7 @@ var MapViewExample = React.createClass({
     );
   },
 
-  _getAnnotations(region): Annotations {
+  _getAnnotations(region) {
     return [{
       longitude: region.longitude,
       latitude: region.latitude,
@@ -249,16 +215,13 @@ var MapViewExample = React.createClass({
 
 });
 
-type AnnotationExampleState = {
-  isFirstLoad: boolean,
-  annotations?: Annotations,
-  mapRegion?: MapRegion,
-};
 var AnnotationExample = React.createClass({
 
-  getInitialState(): AnnotationExampleState {
+  getInitialState() {
     return {
       isFirstLoad: true,
+      annotations: [],
+      mapRegion: undefined,
     };
   },
 
@@ -351,6 +314,17 @@ exports.examples = [
       }}/>;
     }
   },
+  {
+    title: 'Draggable pin',
+    render() {
+      return <AnnotationExample style={styles.map} annotation={{
+        draggable: true,
+        onDragStateChange: (event) => {
+          console.log('Drag state: ' + event.state);
+        },
+      }}/>;
+    }
+  },
   {
     title: 'Custom pin color',
     render() {
diff --git a/Libraries/Components/MapView/MapView.js b/Libraries/Components/MapView/MapView.js
index 29257d1db421..2ccb4b8cb4d5 100644
--- a/Libraries/Components/MapView/MapView.js
+++ b/Libraries/Components/MapView/MapView.js
@@ -28,7 +28,16 @@ const requireNativeComponent = require('requireNativeComponent');
 
 type Event = Object;
 
+export type AnnotationDragState = $Enum<{
+  idle: string;
+  starting: string;
+  dragging: string;
+  canceling: string;
+  ending: string;
+}>;
+
 const MapView = React.createClass({
+
   mixins: [NativeMethodsMixin],
 
   propTypes: {
@@ -144,6 +153,18 @@ const MapView = React.createClass({
        * Whether the pin drop should be animated or not
        */
       animateDrop: React.PropTypes.bool,
+      
+      /**
+       * Whether the pin should be draggable or not
+       * @platform ios
+       */
+      draggable: React.PropTypes.bool,
+
+      /**
+       * Event that fires when the annotation drag state changes.
+       * @platform ios
+       */  
+      onDragStateChange: React.PropTypes.func,
 
       /**
        * Annotation title/subtile.
@@ -376,6 +397,24 @@ const MapView = React.createClass({
           }
         }
       };
+      var onAnnotationDragStateChange = (event: Event) => {
+        if (!annotations) {
+          return;
+        }
+        // Find the annotation with the id that was pressed
+        for (let i = 0, l = annotations.length; i < l; i++) {
+          let annotation = annotations[i];
+          if (annotation.id === event.nativeEvent.annotationId) {
+            // Update location
+            annotation.latitude = event.nativeEvent.latitude;
+            annotation.longitude = event.nativeEvent.longitude;
+            // Call callback
+            annotation.onDragStateChange &&
+              annotation.onDragStateChange(event.nativeEvent);
+            break;
+          }
+        }
+      }
     }
 
     // TODO: these should be separate events, to reduce bridge traffic
@@ -399,6 +438,7 @@ const MapView = React.createClass({
         overlays={overlays}
         onPress={onPress}
         onChange={onChange}
+        onAnnotationDragStateChange={onAnnotationDragStateChange}
       />
     );
   },
@@ -430,7 +470,11 @@ MapView.PinColors = PinColors && {
 };
 
 const RCTMap = requireNativeComponent('RCTMap', MapView, {
-  nativeOnly: {onChange: true, onPress: true}
+  nativeOnly: {
+    onAnnotationDragStateChange: true,
+    onChange: true,
+    onPress: true
+  }
 });
 
 module.exports = MapView;
diff --git a/React/Views/RCTConvert+MapKit.m b/React/Views/RCTConvert+MapKit.m
index 369ec24469b8..354b133b6780 100644
--- a/React/Views/RCTConvert+MapKit.m
+++ b/React/Views/RCTConvert+MapKit.m
@@ -42,22 +42,23 @@ + (RCTMapAnnotation *)RCTMapAnnotation:(id)json
   json = [self NSDictionary:json];
   RCTMapAnnotation *annotation = [RCTMapAnnotation new];
   annotation.coordinate = [self CLLocationCoordinate2D:json];
-  annotation.title = [RCTConvert NSString:json[@"title"]];
-  annotation.subtitle = [RCTConvert NSString:json[@"subtitle"]];
-  annotation.identifier = [RCTConvert NSString:json[@"id"]];
-  annotation.hasLeftCallout = [RCTConvert BOOL:json[@"hasLeftCallout"]];
-  annotation.hasRightCallout = [RCTConvert BOOL:json[@"hasRightCallout"]];
-  annotation.animateDrop = [RCTConvert BOOL:json[@"animateDrop"]];
-  annotation.tintColor = [RCTConvert UIColor:json[@"tintColor"]];
-  annotation.image = [RCTConvert UIImage:json[@"image"]];
+  annotation.draggable = [self BOOL:json[@"draggable"]];
+  annotation.title = [self NSString:json[@"title"]];
+  annotation.subtitle = [self NSString:json[@"subtitle"]];
+  annotation.identifier = [self NSString:json[@"id"]];
+  annotation.hasLeftCallout = [self BOOL:json[@"hasLeftCallout"]];
+  annotation.hasRightCallout = [self BOOL:json[@"hasRightCallout"]];
+  annotation.animateDrop = [self BOOL:json[@"animateDrop"]];
+  annotation.tintColor = [self UIColor:json[@"tintColor"]];
+  annotation.image = [self UIImage:json[@"image"]];
   annotation.viewIndex =
-    [RCTConvert NSInteger:json[@"viewIndex"] ?: @(NSNotFound)];
+    [self NSInteger:json[@"viewIndex"] ?: @(NSNotFound)];
   annotation.leftCalloutViewIndex =
-    [RCTConvert NSInteger:json[@"leftCalloutViewIndex"] ?: @(NSNotFound)];
+    [self NSInteger:json[@"leftCalloutViewIndex"] ?: @(NSNotFound)];
   annotation.rightCalloutViewIndex =
-    [RCTConvert NSInteger:json[@"rightCalloutViewIndex"] ?: @(NSNotFound)];
+    [self NSInteger:json[@"rightCalloutViewIndex"] ?: @(NSNotFound)];
   annotation.detailCalloutViewIndex =
-    [RCTConvert NSInteger:json[@"detailCalloutViewIndex"] ?: @(NSNotFound)];
+    [self NSInteger:json[@"detailCalloutViewIndex"] ?: @(NSNotFound)];
   return annotation;
 }
 
@@ -66,19 +67,19 @@ + (RCTMapAnnotation *)RCTMapAnnotation:(id)json
 + (RCTMapOverlay *)RCTMapOverlay:(id)json
 {
   json = [self NSDictionary:json];
-  NSArray<NSDictionary *> *locations = [RCTConvert NSDictionaryArray:json[@"coordinates"]];
+  NSArray<NSDictionary *> *locations = [self NSDictionaryArray:json[@"coordinates"]];
   CLLocationCoordinate2D coordinates[locations.count];
   NSUInteger index = 0;
   for (NSDictionary *location in locations) {
-    coordinates[index++] = [RCTConvert CLLocationCoordinate2D:location];
+    coordinates[index++] = [self CLLocationCoordinate2D:location];
   }
 
   RCTMapOverlay *overlay = [RCTMapOverlay polylineWithCoordinates:coordinates
                                                             count:locations.count];
 
-  overlay.strokeColor = [RCTConvert UIColor:json[@"strokeColor"]];
-  overlay.identifier = [RCTConvert NSString:json[@"id"]];
-  overlay.lineWidth = [RCTConvert CGFloat:json[@"lineWidth"] ?: @1];
+  overlay.strokeColor = [self UIColor:json[@"strokeColor"]];
+  overlay.identifier = [self NSString:json[@"id"]];
+  overlay.lineWidth = [self CGFloat:json[@"lineWidth"] ?: @1];
   return overlay;
 }
 
diff --git a/React/Views/RCTMap.h b/React/Views/RCTMap.h
index 63e01473e75a..e7a0768107a1 100644
--- a/React/Views/RCTMap.h
+++ b/React/Views/RCTMap.h
@@ -30,6 +30,7 @@ RCT_EXTERN const CGFloat RCTMapZoomBoundBuffer;
 
 @property (nonatomic, copy) RCTBubblingEventBlock onChange;
 @property (nonatomic, copy) RCTBubblingEventBlock onPress;
+@property (nonatomic, copy) RCTBubblingEventBlock onAnnotationDragStateChange;
 
 - (void)setAnnotations:(NSArray<RCTMapAnnotation *> *)annotations;
 - (void)setOverlays:(NSArray<RCTMapOverlay *> *)overlays;
diff --git a/React/Views/RCTMapAnnotation.h b/React/Views/RCTMapAnnotation.h
index eb03ebaf9ca2..ec5b4edc32ad 100644
--- a/React/Views/RCTMapAnnotation.h
+++ b/React/Views/RCTMapAnnotation.h
@@ -21,5 +21,6 @@
 @property (nonatomic, assign) NSInteger leftCalloutViewIndex;
 @property (nonatomic, assign) NSInteger rightCalloutViewIndex;
 @property (nonatomic, assign) NSInteger detailCalloutViewIndex;
+@property (nonatomic, assign) BOOL draggable;
 
 @end
diff --git a/React/Views/RCTMapManager.m b/React/Views/RCTMapManager.m
index 6718adde114c..f12705b283e2 100644
--- a/React/Views/RCTMapManager.m
+++ b/React/Views/RCTMapManager.m
@@ -95,6 +95,7 @@ - (UIView *)view
 RCT_EXPORT_VIEW_PROPERTY(mapType, MKMapType)
 RCT_EXPORT_VIEW_PROPERTY(annotations, NSArray<RCTMapAnnotation *>)
 RCT_EXPORT_VIEW_PROPERTY(overlays, NSArray<RCTMapOverlay *>)
+RCT_EXPORT_VIEW_PROPERTY(onAnnotationDragStateChange, RCTBubblingEventBlock)
 RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock)
 RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
 RCT_CUSTOM_VIEW_PROPERTY(region, MKCoordinateRegion, RCTMap)
@@ -136,7 +137,6 @@ - (UIView *)view
 - (void)mapView:(RCTMap *)mapView didSelectAnnotationView:(MKAnnotationView *)view
 {
   if (mapView.onPress && [view.annotation isKindOfClass:[RCTMapAnnotation class]]) {
-
     RCTMapAnnotation *annotation = (RCTMapAnnotation *)view.annotation;
     mapView.onPress(@{
       @"action": @"annotation-click",
@@ -151,6 +151,30 @@ - (void)mapView:(RCTMap *)mapView didSelectAnnotationView:(MKAnnotationView *)vi
   }
 }
 
+- (void)mapView:(RCTMap *)mapView annotationView:(MKAnnotationView *)view
+                              didChangeDragState:(MKAnnotationViewDragState)newState
+                                    fromOldState:(MKAnnotationViewDragState)oldState
+{
+  static NSArray *states;
+  static dispatch_once_t onceToken;
+  dispatch_once(&onceToken, ^{
+    states = @[@"idle", @"starting", @"dragging", @"canceling", @"ending"];
+  });
+
+  if ([view.annotation isKindOfClass:[RCTMapAnnotation class]]) {
+    RCTMapAnnotation *annotation = (RCTMapAnnotation *)view.annotation;
+    if (mapView.onAnnotationDragStateChange) {
+      mapView.onAnnotationDragStateChange(@{
+        @"state": states[newState],
+        @"oldState": states[oldState],
+        @"annotationId": annotation.identifier,
+        @"latitude": @(annotation.coordinate.latitude),
+        @"longitude": @(annotation.coordinate.longitude),
+      });
+    }
+  }
+}
+
 - (MKAnnotationView *)mapView:(RCTMap *)mapView
             viewForAnnotation:(RCTMapAnnotation *)annotation
 {
@@ -159,7 +183,6 @@ - (MKAnnotationView *)mapView:(RCTMap *)mapView
   }
 
   MKAnnotationView *annotationView;
-  annotationView.clipsToBounds = YES;
   if (annotation.viewIndex != NSNotFound) {
 
     NSString *reuseIdentifier = NSStringFromClass([RCTMapAnnotationView class]);
@@ -205,7 +228,7 @@ - (MKAnnotationView *)mapView:(RCTMap *)mapView
         annotation.tintColor ?: [MKPinAnnotationView redPinColor];
     }
   }
-  annotationView.canShowCallout = true;
+  annotationView.canShowCallout = (annotation.title.length > 0);
 
   if (annotation.leftCalloutViewIndex != NSNotFound) {
     annotationView.leftCalloutAccessoryView =
@@ -255,6 +278,8 @@ - (MKAnnotationView *)mapView:(RCTMap *)mapView
     }
   }
 
+  annotationView.draggable = annotation.draggable;
+
   return annotationView;
 }
 

From 68147cf39ce62c79e7745d0df754cd3f1d2b2146 Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Mon, 4 Jan 2016 07:40:15 -0800
Subject: [PATCH 0578/1411] Update references to `image!` to use require syntax

Summary: Closes https://github.com/facebook/react-native/pull/5089

Reviewed By: svcscm

Differential Revision: D2798548

Pulled By: androidtrunkagent

fb-gh-sync-id: 9e561fcfc103102d4c4bfbebc463eadb2fdd561a
---
 Libraries/Image/Image.ios.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Libraries/Image/Image.ios.js b/Libraries/Image/Image.ios.js
index 91293c07f615..e48b25baf7a8 100644
--- a/Libraries/Image/Image.ios.js
+++ b/Libraries/Image/Image.ios.js
@@ -46,7 +46,7 @@ var {
  *     <View>
  *       <Image
  *         style={styles.icon}
- *         source={require('image!myIcon')}
+ *         source={require('./myIcon.png')}
  *       />
  *       <Image
  *         style={styles.logo}
@@ -63,7 +63,7 @@ var Image = React.createClass({
     /**
      * `uri` is a string representing the resource identifier for the image, which
      * could be an http address, a local file path, or the name of a static image
-     * resource (which should be wrapped in the `require('image!name')` function).
+     * resource (which should be wrapped in the `require('./path/to/image.png')` function).
      */
     source: PropTypes.oneOfType([
       PropTypes.shape({

From 86af597c2ee78a9885046f29555b56d0cc5dc155 Mon Sep 17 00:00:00 2001
From: Katrina Nova <katrina.a.nova@gmail.com>
Date: Mon, 4 Jan 2016 07:41:46 -0800
Subject: [PATCH 0579/1411] Update NavigatorIOS.ios.js

Summary:
Allow props passed to the route object to overwrite props passed to the navigator.
Closes https://github.com/facebook/react-native/pull/5101

Reviewed By: svcscm

Differential Revision: D2799379

Pulled By: androidtrunkagent

fb-gh-sync-id: 147b6ba4b309657f03d7bda38f8958c4599c38c3
---
 .../Components/Navigation/NavigatorIOS.ios.js | 49 ++++++++++++++++---
 1 file changed, 42 insertions(+), 7 deletions(-)

diff --git a/Libraries/Components/Navigation/NavigatorIOS.ios.js b/Libraries/Components/Navigation/NavigatorIOS.ios.js
index 135ad6f12c44..e21cc6d85271 100644
--- a/Libraries/Components/Navigation/NavigatorIOS.ios.js
+++ b/Libraries/Components/Navigation/NavigatorIOS.ios.js
@@ -172,6 +172,11 @@ type Event = Object;
  * });
  * ```
  *
+ * Props passed to the NavigatorIOS component will set the default configuration
+ * for the navigation bar. Props passed as properties to a route object will set
+ * the configuration for that route's navigation bar, overriding any props
+ * passed to the NavigatorIOS component.
+ *
  */
 var NavigatorIOS = React.createClass({
 
@@ -248,15 +253,45 @@ var NavigatorIOS = React.createClass({
        */
       wrapperStyle: View.propTypes.style,
 
+      /**
+       * A Boolean value that indicates whether the navigation bar is hidden
+       */
+      navigationBarHidden: PropTypes.bool,
+
+      /**
+       * A Boolean value that indicates whether to hide the 1px hairline shadow
+       */
+      shadowHidden: PropTypes.bool,
+
+      /**
+       * The color used for buttons in the navigation bar
+       */
+      tintColor: PropTypes.string,
+
+      /**
+       * The background color of the navigation bar
+       */
+      barTintColor: PropTypes.string,
+
+       /**
+       * The text color of the navigation bar title
+       */
+      titleTextColor: PropTypes.string,
+
+       /**
+       * A Boolean value that indicates whether the navigation bar is translucent
+       */
+      translucent: PropTypes.bool,
+
     }).isRequired,
 
     /**
-     * A Boolean value that indicates whether the navigation bar is hidden
+     * A Boolean value that indicates whether the navigation bar is hidden by default
      */
     navigationBarHidden: PropTypes.bool,
 
     /**
-     * A Boolean value that indicates whether to hide the 1px hairline shadow
+     * A Boolean value that indicates whether to hide the 1px hairline shadow by default
      */
     shadowHidden: PropTypes.bool,
 
@@ -267,22 +302,22 @@ var NavigatorIOS = React.createClass({
     itemWrapperStyle: View.propTypes.style,
 
     /**
-     * The color used for buttons in the navigation bar
+     * The default color used for buttons in the navigation bar
      */
     tintColor: PropTypes.string,
 
     /**
-     * The background color of the navigation bar
+     * The default background color of the navigation bar
      */
     barTintColor: PropTypes.string,
 
     /**
-     * The text color of the navigation bar title
+     * The default text color of the navigation bar title
      */
     titleTextColor: PropTypes.string,
 
     /**
-     * A Boolean value that indicates whether the navigation bar is translucent
+     * A Boolean value that indicates whether the navigation bar is translucent by default
      */
     translucent: PropTypes.bool,
 
@@ -610,8 +645,8 @@ var NavigatorIOS = React.createClass({
     return (
       <StaticContainer key={'nav' + i} shouldUpdate={shouldUpdateChild}>
         <RCTNavigatorItem
-          {...route}
           {...props}
+          {...route}
           style={[
             styles.stackItem,
             itemWrapperStyle,

From 44f7a00e95af91dbdfc9feb4f097558b85a8917b Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Mon, 4 Jan 2016 07:59:10 -0800
Subject: [PATCH 0580/1411] Cross platform PullToRefreshView component

Summary:
Both iOS and Android currently support some sort of native pull to refresh control but the API was very different. I tried implementing a component based on PullToRefreshViewAndroid but that works on both platforms.

I liked the idea of wrapping the ListView or ScrollView with the PullToRefreshView component and allow styling the refresh view with platform specific props if needed. I also like the fact that 'refreshing' is a controlled prop so there is no need to keep a ref to the component or to the stopRefreshing function.

It is a pretty rough start so I'm looking for feedback and ideas to improve on the API before cleaning up everything.

On iOS we could probably deprecate the onRefreshStart property of the ScrollView and implement the native stuff in a PullToRefreshViewManager. We could then add props to customize the look of the UIRefreshControl (tintColor). We could also deprecate the Android only component and remove it later.
Closes https://github.com/facebook/react-native/pull/4915

Reviewed By: svcscm

Differential Revision: D2799246

Pulled By: nicklockwood

fb-gh-sync-id: 75872c12143ddbc05cc91900ab4612e477ca5765
---
 Examples/UIExplorer/RefreshControlExample.js  | 125 ++++++++++++++++++
 Examples/UIExplorer/UIExplorerList.android.js |   1 +
 Examples/UIExplorer/UIExplorerList.ios.js     |   1 +
 .../RefreshControl/RefreshControl.js          |  96 ++++++++++++++
 Libraries/Components/ScrollView/ScrollView.js |  58 +++++---
 Libraries/react-native/react-native.js        |   1 +
 Libraries/react-native/react-native.js.flow   |   3 +-
 React/React.xcodeproj/project.pbxproj         |  12 ++
 React/Views/RCTRefreshControl.h               |  19 +++
 React/Views/RCTRefreshControl.m               |  54 ++++++++
 React/Views/RCTRefreshControlManager.h        |  14 ++
 React/Views/RCTRefreshControlManager.m        |  28 ++++
 React/Views/RCTScrollView.m                   |  24 +++-
 13 files changed, 414 insertions(+), 22 deletions(-)
 create mode 100644 Examples/UIExplorer/RefreshControlExample.js
 create mode 100644 Libraries/Components/RefreshControl/RefreshControl.js
 create mode 100644 React/Views/RCTRefreshControl.h
 create mode 100644 React/Views/RCTRefreshControl.m
 create mode 100644 React/Views/RCTRefreshControlManager.h
 create mode 100644 React/Views/RCTRefreshControlManager.m

diff --git a/Examples/UIExplorer/RefreshControlExample.js b/Examples/UIExplorer/RefreshControlExample.js
new file mode 100644
index 000000000000..b8feefb661db
--- /dev/null
+++ b/Examples/UIExplorer/RefreshControlExample.js
@@ -0,0 +1,125 @@
+/**
+* The examples provided by Facebook are for non-commercial testing and
+* evaluation purposes only.
+*
+* Facebook reserves all rights not expressly granted.
+*
+* 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 NON INFRINGEMENT. IN NO EVENT SHALL
+* FACEBOOK 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.
+*
+*/
+'use strict';
+
+const React = require('react-native');
+const {
+  ScrollView,
+  StyleSheet,
+  RefreshControl,
+  Text,
+  TouchableWithoutFeedback,
+  View,
+} = React;
+
+const styles = StyleSheet.create({
+  row: {
+    borderColor: 'grey',
+    borderWidth: 1,
+    padding: 20,
+    backgroundColor: '#3a5795',
+    margin: 5,
+  },
+  text: {
+    alignSelf: 'center',
+    color: '#fff',
+  },
+  scrollview: {
+    flex: 1,
+  },
+});
+
+const Row = React.createClass({
+  _onClick: function() {
+    this.props.onClick(this.props.data);
+  },
+  render: function() {
+    return (
+     <TouchableWithoutFeedback onPress={this._onClick} >
+        <View style={styles.row}>
+          <Text style={styles.text}>
+            {this.props.data.text + ' (' + this.props.data.clicks + ' clicks)'}
+          </Text>
+        </View>
+      </TouchableWithoutFeedback>
+    );
+  },
+});
+
+const RefreshControlExample = React.createClass({
+  statics: {
+    title: '<RefreshControl>',
+    description: 'Adds pull-to-refresh support to a scrollview.'
+  },
+
+  getInitialState() {
+    return {
+      isRefreshing: false,
+      loaded: 0,
+      rowData: Array.from(new Array(20)).map(
+        (val, i) => ({text: 'Initial row' + i, clicks: 0})),
+    };
+  },
+
+  _onClick(row) {
+    row.clicks++;
+    this.setState({
+      rowData: this.state.rowData,
+    });
+  },
+
+  render() {
+    const rows = this.state.rowData.map((row, ii) => {
+      return <Row key={ii} data={row} onClick={this._onClick}/>;
+    });
+    return (
+      <ScrollView
+        style={styles.scrollview}
+        refreshControl={
+          <RefreshControl
+            refreshing={this.state.isRefreshing}
+            onRefresh={this._onRefresh}
+            tintColor="#ff0000"
+            title="Loading..."
+            colors={['#ff0000', '#00ff00', '#0000ff']}
+            progressBackgroundColor="#ffff00"
+          />
+        }>
+        {rows}
+      </ScrollView>
+    );
+  },
+
+  _onRefresh() {
+    this.setState({isRefreshing: true});
+    setTimeout(() => {
+      // prepend 10 items
+      const rowData = Array.from(new Array(10))
+      .map((val, i) => ({
+        text: 'Loaded row' + (+this.state.loaded + i),
+        clicks: 0,
+      }))
+      .concat(this.state.rowData);
+
+      this.setState({
+        loaded: this.state.loaded + 10,
+        isRefreshing: false,
+        rowData: rowData,
+      });
+    }, 5000);
+  },
+});
+
+module.exports = RefreshControlExample;
diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index 7aa70c516339..81442e0b982e 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -28,6 +28,7 @@ var COMPONENTS = [
   require('./ProgressBarAndroidExample'),
   require('./ScrollViewSimpleExample'),
   require('./SwitchAndroidExample'),
+  require('./RefreshControlExample'),
   require('./PullToRefreshViewAndroidExample.android'),
   require('./TextExample.android'),
   require('./TextInputExample.android'),
diff --git a/Examples/UIExplorer/UIExplorerList.ios.js b/Examples/UIExplorer/UIExplorerList.ios.js
index c2ba81752099..1d96b2d49ce8 100644
--- a/Examples/UIExplorer/UIExplorerList.ios.js
+++ b/Examples/UIExplorer/UIExplorerList.ios.js
@@ -42,6 +42,7 @@ var COMPONENTS = [
   require('./NavigatorIOSExample'),
   require('./PickerIOSExample'),
   require('./ProgressViewIOSExample'),
+  require('./RefreshControlExample'),
   require('./ScrollViewExample'),
   require('./SegmentedControlIOSExample'),
   require('./SliderIOSExample'),
diff --git a/Libraries/Components/RefreshControl/RefreshControl.js b/Libraries/Components/RefreshControl/RefreshControl.js
new file mode 100644
index 000000000000..319f054c38eb
--- /dev/null
+++ b/Libraries/Components/RefreshControl/RefreshControl.js
@@ -0,0 +1,96 @@
+/**
+ * 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 RefreshControl
+ */
+'use strict';
+
+const React = require('React');
+const Platform = require('Platform');
+const ColorPropType = require('ColorPropType');
+
+const requireNativeComponent = require('requireNativeComponent');
+
+if (Platform.OS === 'ios') {
+  var RefreshLayoutConsts = {SIZE: {}};
+} else if (Platform.OS === 'android') {
+  var RefreshLayoutConsts = require('NativeModules').UIManager.AndroidSwipeRefreshLayout.Constants;
+}
+
+/**
+ * This component is used inside a ScrollView to add pull to refresh
+ * functionality. When the ScrollView is at `scrollY: 0`, swiping down
+ * triggers an `onRefresh` event.
+ */
+const RefreshControl = React.createClass({
+  statics: {
+    SIZE: RefreshLayoutConsts.SIZE,
+  },
+
+  propTypes: {
+    /**
+     * Called when the view starts refreshing.
+     */
+    onRefresh: React.PropTypes.func,
+    /**
+     * Whether the view should be indicating an active refresh.
+     */
+    refreshing: React.PropTypes.bool,
+    /**
+     * The color of the refresh indicator.
+     * @platform ios
+     */
+    tintColor: ColorPropType,
+    /**
+     * The title displayed under the refresh indicator.
+     * @platform ios
+     */
+    title: React.PropTypes.string,
+    /**
+     * Whether the pull to refresh functionality is enabled.
+     * @platform android
+     */
+    enabled: React.PropTypes.bool,
+    /**
+     * The colors (at least one) that will be used to draw the refresh indicator.
+     * @platform android
+     */
+    colors: React.PropTypes.arrayOf(ColorPropType),
+    /**
+     * The background color of the refresh indicator.
+     * @platform android
+     */
+    progressBackgroundColor: ColorPropType,
+    /**
+     * Size of the refresh indicator, see RefreshControl.SIZE.
+     * @platform android
+     */
+    size: React.PropTypes.oneOf(RefreshLayoutConsts.SIZE.DEFAULT, RefreshLayoutConsts.SIZE.LARGE),
+  },
+
+  render() {
+    if (Platform.OS === 'ios') {
+      return <NativeRefreshControl {...this.props}/>;
+    } else {
+      // On Android the ScrollView is wrapped so this component doesn't render
+      // anything and only acts as a way to configure the wrapper view.
+      // ScrollView will wrap itself in a AndroidSwipeRefreshLayout using props
+      // from this.
+      return null;
+    }
+  },
+});
+
+if (Platform.OS === 'ios') {
+  var NativeRefreshControl = requireNativeComponent(
+    'RCTRefreshControl',
+    RefreshControl
+  );
+}
+
+module.exports = RefreshControl;
diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js
index 870044ecaa13..a5d87e082a46 100644
--- a/Libraries/Components/ScrollView/ScrollView.js
+++ b/Libraries/Components/ScrollView/ScrollView.js
@@ -31,6 +31,7 @@ var insetsDiffer = require('insetsDiffer');
 var invariant = require('invariant');
 var pointsDiffer = require('pointsDiffer');
 var requireNativeComponent = require('requireNativeComponent');
+var processColor = require('processColor');
 
 var PropTypes = React.PropTypes;
 
@@ -294,19 +295,16 @@ var ScrollView = React.createClass({
     zoomScale: PropTypes.number,
 
     /**
-     * When defined, displays a UIRefreshControl.
-     * Invoked with a function to stop refreshing when the UIRefreshControl is animating.
-     *
-     * ```
-     * (endRefreshing) => {
-     *      endRefreshing();
-     * }
-     * ```
-     *
+     * A RefreshControl component, used to provide pull-to-refresh
+     * functionality for the ScrollView.
+     */
+    refreshControl: PropTypes.element,
+
+    /**
+     * Deprecated - use `refreshControl` property instead.
      * @platform ios
      */
     onRefreshStart: PropTypes.func,
-
   },
 
   mixins: [ScrollResponder.Mixin],
@@ -445,11 +443,13 @@ var ScrollView = React.createClass({
     };
 
     var onRefreshStart = this.props.onRefreshStart;
-    // this is necessary because if we set it on props, even when empty,
-    // it'll trigger the default pull-to-refresh behavior on native.
-    props.onRefreshStart = onRefreshStart
-      ? function() { onRefreshStart && onRefreshStart(this.endRefreshing); }.bind(this)
-      : null;
+    if (onRefreshStart) {
+      console.warn('onRefreshStart is deprecated. Use the refreshControl prop instead.');
+      // this is necessary because if we set it on props, even when empty,
+      // it'll trigger the default pull-to-refresh behavior on native.
+      props.onRefreshStart =
+        function() { onRefreshStart && onRefreshStart(this.endRefreshing); }.bind(this);
+    }
 
     var ScrollViewClass;
     if (Platform.OS === 'ios') {
@@ -466,6 +466,33 @@ var ScrollView = React.createClass({
       'ScrollViewClass must not be undefined'
     );
 
+    var refreshControl = this.props.refreshControl;
+    if (refreshControl) {
+      if (Platform.OS === 'ios') {
+        // On iOS the RefreshControl is a child of the ScrollView.
+        return (
+          <ScrollViewClass {...props} ref={SCROLLVIEW}>
+            {refreshControl}
+            {contentContainer}
+          </ScrollViewClass>
+        );
+      } else if (Platform.OS === 'android') {
+        // On Android wrap the ScrollView with a AndroidSwipeRefreshLayout.
+        // Since the ScrollView is wrapped add the style props to the
+        // AndroidSwipeRefreshLayout and use flex: 1 for the ScrollView.
+        var refreshProps = refreshControl.props;
+        return (
+          <AndroidSwipeRefreshLayout
+            {...refreshProps}
+            colors={refreshProps.colors && refreshProps.colors.map(processColor)}
+            style={props.style}>
+            <ScrollViewClass {...props} style={styles.base} ref={SCROLLVIEW}>
+              {contentContainer}
+            </ScrollViewClass>
+          </AndroidSwipeRefreshLayout>
+        );
+      }
+    }
     return (
       <ScrollViewClass {...props} ref={SCROLLVIEW}>
         {contentContainer}
@@ -519,6 +546,7 @@ if (Platform.OS === 'android') {
     'AndroidHorizontalScrollView',
     ScrollView
   );
+  var AndroidSwipeRefreshLayout = requireNativeComponent('AndroidSwipeRefreshLayout');
 } else if (Platform.OS === 'ios') {
   var RCTScrollView = requireNativeComponent('RCTScrollView', ScrollView);
 }
diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js
index 5b33bd36341f..b28f255d9c35 100644
--- a/Libraries/react-native/react-native.js
+++ b/Libraries/react-native/react-native.js
@@ -35,6 +35,7 @@ var ReactNative = {
   get Switch() { return require('Switch'); },
   get PullToRefreshViewAndroid() { return require('PullToRefreshViewAndroid'); },
   get RecyclerViewBackedScrollView() { return require('RecyclerViewBackedScrollView'); },
+  get RefreshControl() { return require('RefreshControl'); },
   get SwitchAndroid() { return require('SwitchAndroid'); },
   get SwitchIOS() { return require('SwitchIOS'); },
   get TabBarIOS() { return require('TabBarIOS'); },
diff --git a/Libraries/react-native/react-native.js.flow b/Libraries/react-native/react-native.js.flow
index a250e57b0e4b..7773b27c0281 100644
--- a/Libraries/react-native/react-native.js.flow
+++ b/Libraries/react-native/react-native.js.flow
@@ -10,7 +10,7 @@
  * and Flow doesn't have a good way to enable getters and setters for
  * react-native without forcing all react-native users to also enable getters
  * and setters. Until we solve that issue, we can use this .flow file to
- * pretend like react-native doesn't use getters and setters 
+ * pretend like react-native doesn't use getters and setters
  *
  * @flow
  */
@@ -47,6 +47,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
   Switch: require('Switch'),
   PullToRefreshViewAndroid: require('PullToRefreshViewAndroid'),
   RecyclerViewBackedScrollView: require('RecyclerViewBackedScrollView'),
+  RefreshControl: require('RefreshControl'),
   SwitchAndroid: require('SwitchAndroid'),
   SwitchIOS: require('SwitchIOS'),
   TabBarIOS: require('TabBarIOS'),
diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj
index 141bed35aa22..a1802c9444e0 100644
--- a/React/React.xcodeproj/project.pbxproj
+++ b/React/React.xcodeproj/project.pbxproj
@@ -71,6 +71,8 @@
 		14F7A0EC1BDA3B3C003C6C10 /* RCTPerfMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F7A0EB1BDA3B3C003C6C10 /* RCTPerfMonitor.m */; };
 		14F7A0F01BDA714B003C6C10 /* RCTFPSGraph.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F7A0EF1BDA714B003C6C10 /* RCTFPSGraph.m */; };
 		1BCBD4A71C32FA0B006FC476 /* RCTBundleURLProcessor.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BCBD4A61C32FA0B006FC476 /* RCTBundleURLProcessor.m */; };
+		191E3EBE1C29D9AF00C180A6 /* RCTRefreshControlManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 191E3EBD1C29D9AF00C180A6 /* RCTRefreshControlManager.m */; };
+		191E3EC11C29DC3800C180A6 /* RCTRefreshControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 191E3EC01C29DC3800C180A6 /* RCTRefreshControl.m */; };
 		58114A161AAE854800E7D092 /* RCTPicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A131AAE854800E7D092 /* RCTPicker.m */; };
 		58114A171AAE854800E7D092 /* RCTPickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A151AAE854800E7D092 /* RCTPickerManager.m */; };
 		58114A501AAE93D500E7D092 /* RCTAsyncLocalStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A4E1AAE93D500E7D092 /* RCTAsyncLocalStorage.m */; };
@@ -245,6 +247,10 @@
 		14F7A0EF1BDA714B003C6C10 /* RCTFPSGraph.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTFPSGraph.m; sourceTree = "<group>"; };
 		1BCBD4A51C32FA0B006FC476 /* RCTBundleURLProcessor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBundleURLProcessor.h; sourceTree = "<group>"; };
 		1BCBD4A61C32FA0B006FC476 /* RCTBundleURLProcessor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBundleURLProcessor.m; sourceTree = "<group>"; };
+		191E3EBC1C29D9AF00C180A6 /* RCTRefreshControlManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRefreshControlManager.h; sourceTree = "<group>"; };
+		191E3EBD1C29D9AF00C180A6 /* RCTRefreshControlManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRefreshControlManager.m; sourceTree = "<group>"; };
+		191E3EBF1C29DC3800C180A6 /* RCTRefreshControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRefreshControl.h; sourceTree = "<group>"; };
+		191E3EC01C29DC3800C180A6 /* RCTRefreshControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRefreshControl.m; sourceTree = "<group>"; };
 		58114A121AAE854800E7D092 /* RCTPicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPicker.h; sourceTree = "<group>"; };
 		58114A131AAE854800E7D092 /* RCTPicker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPicker.m; sourceTree = "<group>"; };
 		58114A141AAE854800E7D092 /* RCTPickerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPickerManager.h; sourceTree = "<group>"; };
@@ -401,6 +407,10 @@
 				13442BF31AA90E0B0037E5B0 /* RCTPointerEvents.h */,
 				13513F3A1B1F43F400FCE529 /* RCTProgressViewManager.h */,
 				13513F3B1B1F43F400FCE529 /* RCTProgressViewManager.m */,
+				191E3EBF1C29DC3800C180A6 /* RCTRefreshControl.h */,
+				191E3EC01C29DC3800C180A6 /* RCTRefreshControl.m */,
+				191E3EBC1C29D9AF00C180A6 /* RCTRefreshControlManager.h */,
+				191E3EBD1C29D9AF00C180A6 /* RCTRefreshControlManager.m */,
 				13C325271AA63B6A0048765F /* RCTScrollableProtocol.h */,
 				13B07FF61A6947C200A75B9A /* RCTScrollView.h */,
 				13B07FF71A6947C200A75B9A /* RCTScrollView.m */,
@@ -703,6 +713,7 @@
 				13A1F71E1A75392D00D3D453 /* RCTKeyCommands.m in Sources */,
 				83CBBA531A601E3B00E9B192 /* RCTUtils.m in Sources */,
 				14435CE61AAC4AE100FC20F4 /* RCTMapManager.m in Sources */,
+				191E3EC11C29DC3800C180A6 /* RCTRefreshControl.m in Sources */,
 				13C156051AB1A2840079392D /* RCTWebView.m in Sources */,
 				83CBBA601A601EAA00E9B192 /* RCTBridge.m in Sources */,
 				13C156061AB1A2840079392D /* RCTWebViewManager.m in Sources */,
@@ -713,6 +724,7 @@
 				1450FF871BCFF28A00208362 /* RCTProfileTrampoline-arm.S in Sources */,
 				131B6AF51AF1093D00FFC3E0 /* RCTSegmentedControlManager.m in Sources */,
 				58114A171AAE854800E7D092 /* RCTPickerManager.m in Sources */,
+				191E3EBE1C29D9AF00C180A6 /* RCTRefreshControlManager.m in Sources */,
 				13B0801A1A69489C00A75B9A /* RCTNavigator.m in Sources */,
 				137327E71AA5CF210034F82E /* RCTTabBar.m in Sources */,
 				13F17A851B8493E5007D4C75 /* RCTRedBox.m in Sources */,
diff --git a/React/Views/RCTRefreshControl.h b/React/Views/RCTRefreshControl.h
new file mode 100644
index 000000000000..4316576aab96
--- /dev/null
+++ b/React/Views/RCTRefreshControl.h
@@ -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.
+ */
+
+#import <UIKit/UIKit.h>
+
+#import "RCTComponent.h"
+
+@interface RCTRefreshControl : UIRefreshControl
+
+@property (nonatomic, copy) NSString *title;
+@property (nonatomic, copy) RCTDirectEventBlock onRefresh;
+
+@end
diff --git a/React/Views/RCTRefreshControl.m b/React/Views/RCTRefreshControl.m
new file mode 100644
index 000000000000..d3fc0e7f9bf6
--- /dev/null
+++ b/React/Views/RCTRefreshControl.m
@@ -0,0 +1,54 @@
+/**
+ * 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.
+ */
+
+#import "RCTRefreshControl.h"
+
+#import "RCTUtils.h"
+
+@implementation RCTRefreshControl
+
+- (instancetype)init
+{
+  if ((self = [super init])) {
+    [self addTarget:self action:@selector(refreshControlValueChanged) forControlEvents:UIControlEventValueChanged];
+  }
+  return self;
+}
+
+RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
+
+- (NSString *)title
+{
+  return self.attributedTitle.string;
+}
+
+- (void)setTitle:(NSString *)title
+{
+  self.attributedTitle = [[NSAttributedString alloc] initWithString:title];
+}
+
+- (void)setRefreshing:(BOOL)refreshing
+{
+  if (super.refreshing != refreshing) {
+    if (refreshing) {
+      [self beginRefreshing];
+    } else {
+      [self endRefreshing];
+    }
+  }
+}
+
+- (void)refreshControlValueChanged
+{
+  if (_onRefresh) {
+    _onRefresh(nil);
+  }
+}
+
+@end
diff --git a/React/Views/RCTRefreshControlManager.h b/React/Views/RCTRefreshControlManager.h
new file mode 100644
index 000000000000..8d1c3f961668
--- /dev/null
+++ b/React/Views/RCTRefreshControlManager.h
@@ -0,0 +1,14 @@
+/**
+ * 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.
+ */
+
+#import "RCTViewManager.h"
+
+@interface RCTRefreshControlManager : RCTViewManager
+
+@end
diff --git a/React/Views/RCTRefreshControlManager.m b/React/Views/RCTRefreshControlManager.m
new file mode 100644
index 000000000000..bc479a150ebc
--- /dev/null
+++ b/React/Views/RCTRefreshControlManager.m
@@ -0,0 +1,28 @@
+/**
+ * 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.
+ */
+
+#import "RCTRefreshControlManager.h"
+
+#import "RCTRefreshControl.h"
+
+@implementation RCTRefreshControlManager
+
+RCT_EXPORT_MODULE()
+
+- (UIView *)view
+{
+  return [RCTRefreshControl new];
+}
+
+RCT_EXPORT_VIEW_PROPERTY(onRefresh, RCTDirectEventBlock)
+RCT_EXPORT_VIEW_PROPERTY(refreshing, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
+RCT_EXPORT_VIEW_PROPERTY(title, NSString)
+
+@end
diff --git a/React/Views/RCTScrollView.m b/React/Views/RCTScrollView.m
index 5ae7fb05a6b5..de9bcb273d53 100644
--- a/React/Views/RCTScrollView.m
+++ b/React/Views/RCTScrollView.m
@@ -14,6 +14,7 @@
 #import "RCTConvert.h"
 #import "RCTEventDispatcher.h"
 #import "RCTLog.h"
+#import "RCTRefreshControl.h"
 #import "RCTUIManager.h"
 #import "RCTUtils.h"
 #import "UIView+Private.h"
@@ -410,20 +411,31 @@ - (void)setRemoveClippedSubviews:(__unused BOOL)removeClippedSubviews
 
 - (void)insertReactSubview:(UIView *)view atIndex:(__unused NSInteger)atIndex
 {
-  RCTAssert(_contentView == nil, @"RCTScrollView may only contain a single subview");
-  _contentView = view;
-  [_scrollView addSubview:view];
+  if ([view isKindOfClass:[RCTRefreshControl class]]) {
+    _scrollView.refreshControl = (RCTRefreshControl*)view;
+  } else {
+    RCTAssert(_contentView == nil, @"RCTScrollView may only contain a single subview");
+    _contentView = view;
+    [_scrollView addSubview:view];
+  }
 }
 
 - (void)removeReactSubview:(UIView *)subview
 {
-  RCTAssert(_contentView == subview, @"Attempted to remove non-existent subview");
-  _contentView = nil;
-  [subview removeFromSuperview];
+  if ([subview isKindOfClass:[RCTRefreshControl class]]) {
+    _scrollView.refreshControl = nil;
+  } else {
+    RCTAssert(_contentView == subview, @"Attempted to remove non-existent subview");
+    _contentView = nil;
+    [subview removeFromSuperview];
+  }
 }
 
 - (NSArray<UIView *> *)reactSubviews
 {
+  if (_contentView && _scrollView.refreshControl) {
+    return @[_contentView, _scrollView.refreshControl];
+  }
   return _contentView ? @[_contentView] : @[];
 }
 

From 54f25867353a00e687c70aa410f376fb32d04bc7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Mon, 4 Jan 2016 09:55:09 -0800
Subject: [PATCH 0581/1411] Improve error message when devserver is not running

Summary:
public

If Hot Loading is enabled bu the packager server is not running, as the user updates files he'll see red boxes caused by the HMR runtime. The error those red boxes show is pretty weird for the end user. Lets improve the feedback we give!.

Reviewed By: vjeux

Differential Revision: D2795534

fb-gh-sync-id: dcc39e6682e0603bf10d0f5e623433262b745660
---
 Libraries/Utilities/HMRClient.js | 23 ++++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/Libraries/Utilities/HMRClient.js b/Libraries/Utilities/HMRClient.js
index 31fad171ee68..0a29f53ab1a7 100644
--- a/Libraries/Utilities/HMRClient.js
+++ b/Libraries/Utilities/HMRClient.js
@@ -21,19 +21,32 @@ const HMRClient = {
     invariant(platform, 'Missing required parameter `platform`');
     invariant(bundleEntry, 'Missing required paramenter `bundleEntry`');
 
+    // TODO(martinb) receive host and port as parameters
+    const host = 'localhost';
+    const port = '8081';
+
     // need to require WebSocket inside of `enable` function because the
     // this module is defined as a `polyfillGlobal`.
     // See `InitializeJavascriptAppEngine.js`
     const WebSocket = require('WebSocket');
 
-    // TODO(martinb): parametrize the url and receive entryFile to minimize
-    // the number of updates we want to receive from the server.
     const activeWS = new WebSocket(
-      'ws://localhost:8081/hot?platform=' + platform + '&bundleEntry=' +
-      bundleEntry.replace('.bundle', '.js')
+      `ws://${host}:${port}/hot?platform=${platform}&` +
+      `bundleEntry=${bundleEntry.replace('.bundle', '.js')}`
     );
     activeWS.onerror = (e) => {
-      console.error('[Hot Module Replacement] Unexpected error', e);
+      throw new Error(
+`Hot loading isn't working because it cannot connect to the development server.
+
+Ensure the following:
+- Node server is running and available on the same network
+- run 'npm start' from react-native root
+- Node server URL is correctly set in AppDelegate
+
+URL: ${host}:${port}
+
+Error: ${e.message}`
+      );
     };
     activeWS.onmessage = (m) => {
       eval(m.data); // eslint-disable-line no-eval

From ed4478a4ffb311b65e693a3f6ba8245644ee3b6b Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Mon, 4 Jan 2016 10:39:07 -0800
Subject: [PATCH 0582/1411] Refactor hot loading implementation on iOS

Reviewed By: milend

Differential Revision: D2795580

fb-gh-sync-id: ad33ba152e40b622b10bfa0122afd6edc28a11bf
---
 .../UIExplorer.xcodeproj/project.pbxproj      |  4 +
 .../UIExplorerUnitTests/RCTURLUtilsTests.m    | 75 +++++++++++++++++++
 React/Base/RCTBatchedBridge.m                 | 10 +++
 React/Base/RCTBridge+Private.h                |  5 ++
 React/Base/RCTBridge.h                        |  6 +-
 React/Base/RCTBridge.m                        | 12 ++-
 React/Base/RCTBridgeDelegate.h                |  6 +-
 React/Base/RCTBundleURLProcessor.h            | 18 -----
 React/Base/RCTBundleURLProcessor.m            | 73 ------------------
 React/Base/RCTUtils.h                         |  4 +
 React/Base/RCTUtils.m                         | 47 +++++++++++-
 React/Executors/RCTJSCExecutor.m              | 33 --------
 React/Modules/RCTDevMenu.h                    |  5 ++
 React/Modules/RCTDevMenu.m                    | 34 ++++++++-
 React/React.xcodeproj/project.pbxproj         |  6 --
 15 files changed, 193 insertions(+), 145 deletions(-)
 create mode 100644 Examples/UIExplorer/UIExplorerUnitTests/RCTURLUtilsTests.m
 delete mode 100644 React/Base/RCTBundleURLProcessor.h
 delete mode 100644 React/Base/RCTBundleURLProcessor.m

diff --git a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
index ea9084cd77bb..e6dfc36585b7 100644
--- a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
+++ b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
@@ -26,6 +26,7 @@
 		13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
 		13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
 		13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
+		13B6C1A31C34225900D3FAF5 /* RCTURLUtilsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B6C1A21C34225900D3FAF5 /* RCTURLUtilsTests.m */; };
 		13DB03481B5D2ED500C27245 /* RCTJSONTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 13DB03471B5D2ED500C27245 /* RCTJSONTests.m */; };
 		13DF61B61B67A45000EDB188 /* RCTMethodArgumentTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 13DF61B51B67A45000EDB188 /* RCTMethodArgumentTests.m */; };
 		143BC5A11B21E45C00462512 /* UIExplorerSnapshotTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 143BC5A01B21E45C00462512 /* UIExplorerSnapshotTests.m */; };
@@ -198,6 +199,7 @@
 		13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = UIExplorer/Images.xcassets; sourceTree = "<group>"; };
 		13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = UIExplorer/Info.plist; sourceTree = "<group>"; };
 		13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = UIExplorer/main.m; sourceTree = "<group>"; };
+		13B6C1A21C34225900D3FAF5 /* RCTURLUtilsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTURLUtilsTests.m; sourceTree = "<group>"; };
 		13CC9D481AEED2B90020D1C2 /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = ../../Libraries/Settings/RCTSettings.xcodeproj; sourceTree = "<group>"; };
 		13DB03471B5D2ED500C27245 /* RCTJSONTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTJSONTests.m; sourceTree = "<group>"; };
 		13DF61B51B67A45000EDB188 /* RCTMethodArgumentTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTMethodArgumentTests.m; sourceTree = "<group>"; };
@@ -406,6 +408,7 @@
 		143BC57C1B21E18100462512 /* UIExplorerUnitTests */ = {
 			isa = PBXGroup;
 			children = (
+				13B6C1A21C34225900D3FAF5 /* RCTURLUtilsTests.m */,
 				1497CFA41B21F5E400C1F8F2 /* RCTAllocationTests.m */,
 				1497CFA51B21F5E400C1F8F2 /* RCTBridgeTests.m */,
 				1497CFA61B21F5E400C1F8F2 /* RCTJSCExecutorTests.m */,
@@ -886,6 +889,7 @@
 				1497CFAC1B21F5E400C1F8F2 /* RCTAllocationTests.m in Sources */,
 				13DF61B61B67A45000EDB188 /* RCTMethodArgumentTests.m in Sources */,
 				138D6A181B53CD440074A87E /* RCTShadowViewTests.m in Sources */,
+				13B6C1A31C34225900D3FAF5 /* RCTURLUtilsTests.m in Sources */,
 				8385CF041B87479200C6273E /* RCTImageLoaderHelpers.m in Sources */,
 				8385CEF51B873B5C00C6273E /* RCTImageLoaderTests.m in Sources */,
 			);
diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTURLUtilsTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTURLUtilsTests.m
new file mode 100644
index 000000000000..bb22b7eb41c5
--- /dev/null
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTURLUtilsTests.m
@@ -0,0 +1,75 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ */
+
+#import <XCTest/XCTest.h>
+#import "RCTUtils.h"
+
+@interface RCTURLUtilsTests : XCTestCase
+
+@end
+
+@implementation RCTURLUtilsTests
+
+- (void)testGetQueryParam
+{
+  NSURL *URL = [NSURL URLWithString:@"http://example.com?foo=bar&bar=foo"];
+  NSString *foo = RCTGetURLQueryParam(URL, @"foo");
+  NSString *bar = RCTGetURLQueryParam(URL, @"bar");
+  XCTAssertEqualObjects(foo, @"bar");
+  XCTAssertEqualObjects(bar, @"foo");
+}
+
+- (void)testQueryParamNotFound
+{
+  NSURL *URL = [NSURL URLWithString:@"http://example.com?foo=bar"];
+  NSString *bar = RCTGetURLQueryParam(URL, @"bar");
+  XCTAssertNil(bar);
+}
+
+- (void)testDuplicateParamTakesLatter
+{
+  NSURL *URL = [NSURL URLWithString:@"http://example.com?foo=bar&foo=foo"];
+  NSString *foo = RCTGetURLQueryParam(URL, @"foo");
+  XCTAssertEqualObjects(foo, @"foo");
+}
+
+- (void)testNilURLGetQueryParam
+{
+  NSURL *URL = nil;
+  NSString *foo = RCTGetURLQueryParam(URL, @"foo");
+  XCTAssertNil(foo);
+}
+
+- (void)testReplaceParam
+{
+  NSURL *URL = [NSURL URLWithString:@"http://example.com?foo=bar&bar=foo"];
+  NSURL *result = RCTURLByReplacingQueryParam(URL, @"foo", @"foo");
+  XCTAssertEqualObjects(result.absoluteString, @"http://example.com?foo=foo&bar=foo");
+}
+
+- (void)testAppendParam
+{
+  NSURL *URL = [NSURL URLWithString:@"http://example.com?bar=foo"];
+  NSURL *result = RCTURLByReplacingQueryParam(URL, @"foo", @"bar");
+  XCTAssertEqualObjects(result.absoluteString, @"http://example.com?bar=foo&foo=bar");
+}
+
+- (void)testNilURLAppendQueryParam
+{
+  NSURL *URL = nil;
+  NSURL *result = RCTURLByReplacingQueryParam(URL, @"foo", @"bar");
+  XCTAssertNil(result);
+}
+
+@end
diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index de9142e58269..65db384323a5 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -440,6 +440,16 @@ - (void)executeSourceCode:(NSData *)sourceCode
        object:_parentBridge userInfo:@{@"bridge": self}];
     });
   }];
+
+#if RCT_DEV
+
+  if (RCTGetURLQueryParam(self.bundleURL, @"hot")) {
+    NSString *path = [self.bundleURL.path substringFromIndex:1]; // strip initial slash
+    [self enqueueJSCall:@"HMRClient.enable" args:@[@"ios", path]];
+  }
+
+#endif
+
 }
 
 - (void)didFinishLoading
diff --git a/React/Base/RCTBridge+Private.h b/React/Base/RCTBridge+Private.h
index 878014cdf468..91675efa5943 100644
--- a/React/Base/RCTBridge+Private.h
+++ b/React/Base/RCTBridge+Private.h
@@ -41,6 +41,11 @@
  */
 @property (nonatomic, copy, readonly) RCTBridgeModuleProviderBlock moduleProvider;
 
+/**
+ * Used by RCTDevMenu to override the `hot` param of the current bundleURL.
+ */
+@property (nonatomic, strong, readwrite) NSURL *bundleURL;
+
 @end
 
 @interface RCTBridge (RCTBatchedBridge)
diff --git a/React/Base/RCTBridge.h b/React/Base/RCTBridge.h
index 06ae8e8ead9f..0b9fc6960560 100644
--- a/React/Base/RCTBridge.h
+++ b/React/Base/RCTBridge.h
@@ -123,11 +123,11 @@ RCT_EXTERN BOOL RCTBridgeModuleClassIsRegistered(Class);
 /**
  * URL of the script that was loaded into the bridge.
  */
-@property (nonatomic, strong) NSURL *bundleURL;
+@property (nonatomic, strong, readonly) NSURL *bundleURL;
 
 /**
- * The class of the executor currently being used *or* to be used after the next
- * reload.
+ * The class of the executor currently being used. Changes to this value will
+ * take effect after the bridge is reloaded.
  */
 @property (nonatomic, strong) Class executorClass;
 
diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m
index 65e36ee2536d..c751fca96716 100644
--- a/React/Base/RCTBridge.m
+++ b/React/Base/RCTBridge.m
@@ -17,7 +17,6 @@
 #import "RCTLog.h"
 #import "RCTPerformanceLogger.h"
 #import "RCTUtils.h"
-#import "RCTBundleURLProcessor.h"
 
 NSString *const RCTReloadNotification = @"RCTReloadNotification";
 NSString *const RCTJavaScriptWillStartLoadingNotification = @"RCTJavaScriptWillStartLoadingNotification";
@@ -88,6 +87,9 @@ BOOL RCTBridgeModuleClassIsRegistered(Class cls)
 }
 
 @implementation RCTBridge
+{
+  NSURL *_delegateBundleURL;
+}
 
 dispatch_queue_t RCTJSThread;
 
@@ -257,8 +259,12 @@ - (void)setUp
 {
   RCTAssertMainThread();
 
-  _bundleURL = [self.delegate sourceURLForBridge:self] ?: _bundleURL;
-  _bundleURL = [[RCTBundleURLProcessor sharedProcessor] process: _bundleURL];
+  // Only update bundleURL from delegate if delegate bundleURL has changed
+  NSURL *previousDelegateURL = _delegateBundleURL;
+  _delegateBundleURL = [self.delegate sourceURLForBridge:self];
+  if (_delegateBundleURL && ![_delegateBundleURL isEqual:previousDelegateURL]) {
+    _bundleURL = _delegateBundleURL;
+  }
 
   // Sanitize the bundle URL
   _bundleURL = [RCTConvert NSURL:_bundleURL.absoluteString];
diff --git a/React/Base/RCTBridgeDelegate.h b/React/Base/RCTBridgeDelegate.h
index 4c1a52f091da..e29dc64a6e96 100644
--- a/React/Base/RCTBridgeDelegate.h
+++ b/React/Base/RCTBridgeDelegate.h
@@ -48,9 +48,9 @@ typedef void (^RCTSourceLoadBlock)(NSError *error, NSData *source);
                   withBlock:(RCTSourceLoadBlock)loadCallback;
 
 /**
- * Indicates wheather Hot Loading is supported or not.
- * Note this method will get removed soon, once we support Hot Loading on OSS.
+ * Indicates whether Hot Loading is supported or not.
+ * Note: this method will be removed soon, once Hot Loading is supported on OSS.
  */
-- (BOOL)isHotLoadingEnabled;
+- (BOOL)bridgeSupportsHotLoading:(RCTBridge *)bridge;
 
 @end
diff --git a/React/Base/RCTBundleURLProcessor.h b/React/Base/RCTBundleURLProcessor.h
deleted file mode 100644
index 89587aa17b6e..000000000000
--- a/React/Base/RCTBundleURLProcessor.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * 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.
- */
-
-@interface RCTBundleURLProcessor : NSObject
-
-+ (id)sharedProcessor;
-
-- (NSString *)getQueryStringValue:(NSString *)attribute;
-- (void)setQueryStringValue:(NSString *)value forAttribute:(NSString *)attribute;
-- (NSURL *)process:(NSURL *)url;
-
-@end
diff --git a/React/Base/RCTBundleURLProcessor.m b/React/Base/RCTBundleURLProcessor.m
deleted file mode 100644
index 35c49a9d5813..000000000000
--- a/React/Base/RCTBundleURLProcessor.m
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * 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.
- */
-
-#import <Foundation/Foundation.h>
-
-#import "RCTBundleURLProcessor.h"
-
-@implementation RCTBundleURLProcessor
-
-NSDictionary *_qsAttributes;
-
-+ (id)sharedProcessor
-{
-  static RCTBundleURLProcessor *sharedProcessor = nil;
-  static dispatch_once_t onceToken;
-  dispatch_once(&onceToken, ^{
-    sharedProcessor = [self new];
-  });
-  return sharedProcessor;
-}
-
-- (instancetype)init
-{
-  // dictionary with additional query string attributes that will get appended
-  // to the bundle URL
-  _qsAttributes = [NSMutableDictionary new];
-  return self;
-}
-
-- (NSString *)getQueryStringValue:(NSString *)attribute
-{
-  return [_qsAttributes valueForKey:attribute];
-}
-
-- (void)setQueryStringValue:(NSString *)value forAttribute:(NSString *)attribute
-{
-  [_qsAttributes setValue:value forKey:attribute];
-}
-
-- (NSURL *)process:(NSURL *)url
-{
-  if (url.isFileURL || [_qsAttributes count] == 0) {
-    return url;
-  }
-
-  // append either `?` or `&` depending on whether there are query string
-  // attibutes or not.
-  NSString *urlString = url.absoluteString;
-  if ([urlString rangeOfString:@"?"].location == NSNotFound) {
-    urlString = [urlString stringByAppendingString:@"?"];
-  } else {
-    urlString = [urlString stringByAppendingString:@"&"];
-  }
-
-  // array with new query string attributes
-  NSMutableArray *parts = [NSMutableArray new];
-  for (id attribute in _qsAttributes) {
-    if ([urlString rangeOfString:[NSString stringWithFormat:@"%@=", attribute]].location != NSNotFound) {
-      [NSException raise:@"Cannot override attribute" format:@"Attribute %@ is already present in url: %@", attribute, url.absoluteString];
-    }
-    [parts addObject:[NSString stringWithFormat:@"%@=%@", attribute, _qsAttributes[attribute]]];
-  }
-
-  return [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", urlString, [parts componentsJoinedByString:@"&"]]];
-}
-
-@end
diff --git a/React/Base/RCTUtils.h b/React/Base/RCTUtils.h
index 251167e0ba34..5e6815c4e03f 100644
--- a/React/Base/RCTUtils.h
+++ b/React/Base/RCTUtils.h
@@ -105,3 +105,7 @@ RCT_EXTERN NSString *RCTColorToHexString(CGColorRef color);
 
 // Get standard localized string (if it exists)
 RCT_EXTERN NSString *RCTUIKitLocalizedString(NSString *string);
+
+// URL manipulation
+RCT_EXTERN NSString *RCTGetURLQueryParam(NSURL *URL, NSString *param);
+RCT_EXTERN NSURL *RCTURLByReplacingQueryParam(NSURL *URL, NSString *param, NSString *value);
diff --git a/React/Base/RCTUtils.m b/React/Base/RCTUtils.m
index d1254a98abbd..b3a7a6e41b54 100644
--- a/React/Base/RCTUtils.m
+++ b/React/Base/RCTUtils.m
@@ -576,10 +576,53 @@ static void RCTGetRGBAColorComponents(CGColorRef color, CGFloat rgba[4])
   }
 }
 
-
 // (https://github.com/0xced/XCDFormInputAccessoryView/blob/master/XCDFormInputAccessoryView/XCDFormInputAccessoryView.m#L10-L14)
-RCT_EXTERN NSString *RCTUIKitLocalizedString(NSString *string)
+NSString *RCTUIKitLocalizedString(NSString *string)
 {
   NSBundle *UIKitBundle = [NSBundle bundleForClass:[UIApplication class]];
   return UIKitBundle ? [UIKitBundle localizedStringForKey:string value:string table:nil] : string;
 }
+
+NSString *RCTGetURLQueryParam(NSURL *URL, NSString *param)
+{
+  RCTAssertParam(param);
+  if (!URL) {
+    return nil;
+  }
+  NSURLComponents *components = [NSURLComponents componentsWithURL:URL
+                                           resolvingAgainstBaseURL:YES];
+  for (NSURLQueryItem *item in components.queryItems.reverseObjectEnumerator) {
+    if ([item.name isEqualToString:param]) {
+      return item.value;
+    }
+  }
+  return nil;
+}
+
+NSURL *RCTURLByReplacingQueryParam(NSURL *URL, NSString *param, NSString *value)
+{
+  RCTAssertParam(param);
+  if (!URL) {
+    return nil;
+  }
+  NSURLComponents *components = [NSURLComponents componentsWithURL:URL
+                                           resolvingAgainstBaseURL:YES];
+  __block NSInteger paramIndex = NSNotFound;
+  NSMutableArray *queryItems = [components.queryItems mutableCopy];
+  [queryItems enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:
+   ^(NSURLQueryItem *item, NSUInteger i, BOOL *stop) {
+     if ([item.name isEqualToString:param]) {
+       paramIndex = i;
+       *stop = YES;
+     }
+   }];
+
+  NSURLQueryItem *newItem = [NSURLQueryItem queryItemWithName:param value:value];
+  if (paramIndex == NSNotFound) {
+    [queryItems addObject:newItem];
+  } else {
+    [queryItems replaceObjectAtIndex:paramIndex withObject:newItem];
+  }
+  components.queryItems = queryItems;
+  return components.URL;
+}
diff --git a/React/Executors/RCTJSCExecutor.m b/React/Executors/RCTJSCExecutor.m
index e808caa3ccbe..a586fd07e079 100644
--- a/React/Executors/RCTJSCExecutor.m
+++ b/React/Executors/RCTJSCExecutor.m
@@ -23,10 +23,8 @@
 #import "RCTPerformanceLogger.h"
 #import "RCTUtils.h"
 #import "RCTJSCProfiler.h"
-#import "RCTBundleURLProcessor.h"
 
 static NSString *const RCTJSCProfilerEnabledDefaultsKey = @"RCTJSCProfilerEnabled";
-static NSString *const RCTHotLoadingEnabledDefaultsKey = @"RCTHotLoadingEnabled";
 
 @interface RCTJavaScriptContext : NSObject <RCTInvalidating>
 
@@ -146,26 +144,6 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
   }
 }
 
-static BOOL isHotLoadingEnabled()
-{
-  NSString *enabledQS = [[RCTBundleURLProcessor sharedProcessor] getQueryStringValue:@"hot"];
-  return (enabledQS != nil && [enabledQS isEqualToString:@"true"]) ? YES : NO;
-}
-
-static void RCTInstallHotLoading(RCTBridge *bridge, RCTJSCExecutor *executor)
-{
-  [bridge.devMenu addItem:[RCTDevMenuItem toggleItemWithKey:RCTHotLoadingEnabledDefaultsKey title:@"Enable Hot Loading" selectedTitle:@"Disable Hot Loading" handler:^(BOOL enabledOnCurrentBundle) {
-    [executor executeBlockOnJavaScriptQueue:^{
-      BOOL enabledOnConfig = isHotLoadingEnabled();
-      // reload bundle when user change Hot Loading setting
-      if (enabledOnConfig != enabledOnCurrentBundle) {
-        [[RCTBundleURLProcessor sharedProcessor] setQueryStringValue:enabledOnCurrentBundle ? @"true" : @"false" forAttribute:@"hot"];
-        [bridge reload];
-      }
-    }];
-  }]];
-}
-
 #endif
 
 + (void)runRunLoopThread
@@ -320,10 +298,6 @@ - (void)setUp
 
     RCTInstallJSCProfiler(_bridge, strongSelf->_context.ctx);
 
-    if ([self.bridge.delegate respondsToSelector:@selector(isHotLoadingEnabled)] && [self.bridge.delegate isHotLoadingEnabled]) {
-      RCTInstallHotLoading(_bridge, strongSelf);
-    }
-
     for (NSString *event in @[RCTProfileDidStartProfiling, RCTProfileDidEndProfiling]) {
       [[NSNotificationCenter defaultCenter] addObserver:strongSelf
                                                selector:@selector(toggleProfilingFlag:)
@@ -535,13 +509,6 @@ - (void)executeApplicationScript:(NSData *)script
       onComplete(error);
     }
   }), 0, @"js_call", (@{ @"url": sourceURL.absoluteString }))];
-
-  #if RCT_DEV
-  if (isHotLoadingEnabled()) {
-    // strip initial slash
-    [_bridge enqueueJSCall:@"HMRClient.enable" args:@[@"ios", [sourceURL.path substringFromIndex: 1]]];
-  }
-  #endif
 }
 
 - (void)executeBlockOnJavaScriptQueue:(dispatch_block_t)block
diff --git a/React/Modules/RCTDevMenu.h b/React/Modules/RCTDevMenu.h
index f3d70661b3ad..ef2230e80d69 100644
--- a/React/Modules/RCTDevMenu.h
+++ b/React/Modules/RCTDevMenu.h
@@ -36,6 +36,11 @@
  */
 @property (nonatomic, assign) BOOL liveReloadEnabled;
 
+/**
+ * Enables hot loading. Currently not supported in open source.
+ */
+@property (nonatomic, assign) BOOL hotLoadingEnabled;
+
 /**
  * Shows the FPS monitor for the JS and Main threads.
  */
diff --git a/React/Modules/RCTDevMenu.m b/React/Modules/RCTDevMenu.m
index 5d98f8ad4b01..22d01416db7f 100644
--- a/React/Modules/RCTDevMenu.m
+++ b/React/Modules/RCTDevMenu.m
@@ -267,6 +267,7 @@ - (void)updateSettings:(NSDictionary *)settings
   self.shakeToShow = [_settings[@"shakeToShow"] ?: @YES boolValue];
   self.profilingEnabled = [_settings[@"profilingEnabled"] ?: @NO boolValue];
   self.liveReloadEnabled = [_settings[@"liveReloadEnabled"] ?: @NO boolValue];
+  self.hotLoadingEnabled = [_settings[@"hotLoadingEnabled"] ?: @YES boolValue];
   self.showFPS = [_settings[@"showFPS"] ?: @NO boolValue];
   self.executorClass = NSClassFromString(_executorOverride ?: _settings[@"executorClass"]);
 }
@@ -321,7 +322,7 @@ - (void)jsLoaded:(NSNotification *)notification
     } else {
       RCTLogWarn(@"RCTSourceCode module scriptURL has not been set");
     }
-  } else if (!(sourceCodeModule.scriptURL).fileURL) {
+  } else if (!sourceCodeModule.scriptURL.fileURL) {
     // Live reloading is disabled when running from bundled JS file
     _liveReloadURL = [[NSURL alloc] initWithString:@"/onchange" relativeToURL:sourceCodeModule.scriptURL];
   }
@@ -420,6 +421,13 @@ - (void)addItem:(RCTDevMenuItem *)item
     }]];
   }
 
+  if ([self hotLoadingAvailable]) {
+    NSString *hotLoadingTitle = _hotLoadingEnabled ? @"Disable Hot Loading" : @"Enable Hot Loading";
+    [items addObject:[RCTDevMenuItem buttonItemWithTitle:hotLoadingTitle handler:^{
+      weakSelf.hotLoadingEnabled = !_hotLoadingEnabled;
+    }]];
+  }
+
   [items addObjectsFromArray:_extraMenuItems];
 
   return items;
@@ -483,8 +491,6 @@ - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger
 
 RCT_EXPORT_METHOD(reload)
 {
-  _jsLoaded = NO;
-  _liveReloadURL = nil;
   [_bridge reload];
 }
 
@@ -523,6 +529,26 @@ - (void)setLiveReloadEnabled:(BOOL)enabled
   }
 }
 
+- (BOOL)hotLoadingAvailable
+{
+  return !_bridge.bundleURL.fileURL // Only works when running from server
+  && [_bridge.delegate respondsToSelector:@selector(bridgeSupportsHotLoading:)]
+  && [_bridge.delegate bridgeSupportsHotLoading:_bridge];
+}
+
+- (void)setHotLoadingEnabled:(BOOL)enabled
+{
+  _hotLoadingEnabled = enabled;
+  [self updateSetting:@"hotLoadingEnabled" value:@(_hotLoadingEnabled)];
+
+  BOOL actuallyEnabled = [self hotLoadingAvailable] && _hotLoadingEnabled;
+  if (RCTGetURLQueryParam(_bridge.bundleURL, @"hot").boolValue != actuallyEnabled) {
+    _bridge.bundleURL = RCTURLByReplacingQueryParam(_bridge.bundleURL, @"hot",
+                                                    actuallyEnabled ? @"true" : @"false");
+    [_bridge reload];
+  }
+}
+
 - (void)setExecutorClass:(Class)executorClass
 {
   if (_executorClass != executorClass) {
@@ -543,7 +569,7 @@ - (void)setExecutorClass:(Class)executorClass
     }
 
     _bridge.executorClass = executorClass;
-    [self reload];
+    [_bridge reload];
   }
 }
 
diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj
index a1802c9444e0..3a9f0334a55b 100644
--- a/React/React.xcodeproj/project.pbxproj
+++ b/React/React.xcodeproj/project.pbxproj
@@ -70,7 +70,6 @@
 		14F484561AABFCE100FDF6B9 /* RCTSliderManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F484551AABFCE100FDF6B9 /* RCTSliderManager.m */; };
 		14F7A0EC1BDA3B3C003C6C10 /* RCTPerfMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F7A0EB1BDA3B3C003C6C10 /* RCTPerfMonitor.m */; };
 		14F7A0F01BDA714B003C6C10 /* RCTFPSGraph.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F7A0EF1BDA714B003C6C10 /* RCTFPSGraph.m */; };
-		1BCBD4A71C32FA0B006FC476 /* RCTBundleURLProcessor.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BCBD4A61C32FA0B006FC476 /* RCTBundleURLProcessor.m */; };
 		191E3EBE1C29D9AF00C180A6 /* RCTRefreshControlManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 191E3EBD1C29D9AF00C180A6 /* RCTRefreshControlManager.m */; };
 		191E3EC11C29DC3800C180A6 /* RCTRefreshControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 191E3EC01C29DC3800C180A6 /* RCTRefreshControl.m */; };
 		58114A161AAE854800E7D092 /* RCTPicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A131AAE854800E7D092 /* RCTPicker.m */; };
@@ -245,8 +244,6 @@
 		14F7A0EB1BDA3B3C003C6C10 /* RCTPerfMonitor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPerfMonitor.m; sourceTree = "<group>"; };
 		14F7A0EE1BDA714B003C6C10 /* RCTFPSGraph.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTFPSGraph.h; sourceTree = "<group>"; };
 		14F7A0EF1BDA714B003C6C10 /* RCTFPSGraph.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTFPSGraph.m; sourceTree = "<group>"; };
-		1BCBD4A51C32FA0B006FC476 /* RCTBundleURLProcessor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBundleURLProcessor.h; sourceTree = "<group>"; };
-		1BCBD4A61C32FA0B006FC476 /* RCTBundleURLProcessor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBundleURLProcessor.m; sourceTree = "<group>"; };
 		191E3EBC1C29D9AF00C180A6 /* RCTRefreshControlManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRefreshControlManager.h; sourceTree = "<group>"; };
 		191E3EBD1C29D9AF00C180A6 /* RCTRefreshControlManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRefreshControlManager.m; sourceTree = "<group>"; };
 		191E3EBF1C29DC3800C180A6 /* RCTRefreshControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRefreshControl.h; sourceTree = "<group>"; };
@@ -526,8 +523,6 @@
 				83CBBA651A601EF300E9B192 /* RCTEventDispatcher.h */,
 				83CBBA661A601EF300E9B192 /* RCTEventDispatcher.m */,
 				1436DD071ADE7AA000A5ED7D /* RCTFrameUpdate.h */,
-				1BCBD4A51C32FA0B006FC476 /* RCTBundleURLProcessor.h */,
-				1BCBD4A61C32FA0B006FC476 /* RCTBundleURLProcessor.m */,
 				14C2CA751B3AC64F00E6CBB2 /* RCTFrameUpdate.m */,
 				83CBBA4C1A601E3B00E9B192 /* RCTInvalidating.h */,
 				83CBBA631A601ECA00E9B192 /* RCTJavaScriptExecutor.h */,
@@ -687,7 +682,6 @@
 				13E41EEB1C05CA0B00CD8DAC /* RCTProfileTrampoline-i386.S in Sources */,
 				13B080061A6947C200A75B9A /* RCTScrollViewManager.m in Sources */,
 				14200DAA1AC179B3008EE6BA /* RCTJavaScriptLoader.m in Sources */,
-				1BCBD4A71C32FA0B006FC476 /* RCTBundleURLProcessor.m in Sources */,
 				137327EA1AA5CF210034F82E /* RCTTabBarManager.m in Sources */,
 				13B080261A694A8400A75B9A /* RCTWrapperViewController.m in Sources */,
 				13B080051A6947C200A75B9A /* RCTScrollView.m in Sources */,

From 89ae0e040d9c85d9f1adcd1f7df0f67b54ac7a7c Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Mon, 4 Jan 2016 11:05:14 -0800
Subject: [PATCH 0583/1411] Expose flow events to JS + add JS -> Native flows

Summary:
public

Expose JS hooks to create flow events in systrace (the nice arrows to show async work flow) +
add support to the showing all the work enqueued from the JS thread as added in D2743733

Depends on D2743733

Reviewed By: jspahrsummers

Differential Revision: D2773664

fb-gh-sync-id: 4a8854b17b4741b882f5f2cc425e4237a5e4b3eb
---
 React/Base/RCTBatchedBridge.m    | 29 +++++++++++++++++++++++++----
 React/Base/RCTBridge+Private.h   |  4 ++++
 React/Executors/RCTJSCExecutor.m | 14 ++++++++++++++
 React/Profiler/RCTProfile.h      |  2 +-
 4 files changed, 44 insertions(+), 5 deletions(-)

diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index 65db384323a5..8ec30748cbc9 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -35,7 +35,8 @@
 typedef NS_ENUM(NSUInteger, RCTBridgeFields) {
   RCTBridgeFieldRequestModuleIDs = 0,
   RCTBridgeFieldMethodIDs,
-  RCTBridgeFieldParamss,
+  RCTBridgeFieldParams,
+  RCTBridgeFieldCallID,
 };
 
 RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
@@ -65,6 +66,9 @@ @implementation RCTBatchedBridge
   NSUInteger _asyncInitializedModules;
 }
 
+@synthesize flowID = _flowID;
+@synthesize flowIDMap = _flowIDMap;
+
 - (instancetype)initWithParentBridge:(RCTBridge *)bridge
 {
   RCTAssertMainThread();
@@ -591,6 +595,9 @@ - (void)invalidate
       _modulesByName_DEPRECATED = nil;
       _frameUpdateObservers = nil;
 
+      if (_flowIDMap != NULL) {
+        CFRelease(_flowIDMap);
+      }
     }];
   });
 }
@@ -793,15 +800,22 @@ - (void)handleBuffer:(id)buffer batchEnded:(BOOL)batchEnded
 - (void)handleBuffer:(NSArray *)buffer
 {
   NSArray *requestsArray = [RCTConvert NSArray:buffer];
-  if (RCT_DEBUG && requestsArray.count <= RCTBridgeFieldParamss) {
+
+  if (RCT_DEBUG && requestsArray.count <= RCTBridgeFieldParams) {
     RCTLogError(@"Buffer should contain at least %tu sub-arrays. Only found %tu",
-              RCTBridgeFieldParamss + 1, requestsArray.count);
+                RCTBridgeFieldParams + 1, requestsArray.count);
     return;
   }
 
   NSArray<NSNumber *> *moduleIDs = [RCTConvert NSNumberArray:requestsArray[RCTBridgeFieldRequestModuleIDs]];
   NSArray<NSNumber *> *methodIDs = [RCTConvert NSNumberArray:requestsArray[RCTBridgeFieldMethodIDs]];
-  NSArray<NSArray *> *paramsArrays = [RCTConvert NSArrayArray:requestsArray[RCTBridgeFieldParamss]];
+  NSArray<NSArray *> *paramsArrays = [RCTConvert NSArrayArray:requestsArray[RCTBridgeFieldParams]];
+
+  int64_t callID = -1;
+
+  if (requestsArray.count > 3) {
+    callID = [requestsArray[RCTBridgeFieldCallID] longLongValue];
+  }
 
   if (RCT_DEBUG && (moduleIDs.count != methodIDs.count || moduleIDs.count != paramsArrays.count)) {
     RCTLogError(@"Invalid data message - all must be length: %zd", moduleIDs.count);
@@ -835,6 +849,11 @@ - (void)handleBuffer:(NSArray *)buffer
       @autoreleasepool {
         for (NSNumber *indexObj in calls) {
           NSUInteger index = indexObj.unsignedIntegerValue;
+          if (callID != -1) {
+            int64_t newFlowID = (int64_t)CFDictionaryGetValue(_flowIDMap, (const void *)(_flowID + index));
+            _RCTProfileEndFlowEvent(@(newFlowID));
+            CFDictionaryRemoveValue(_flowIDMap, (const void *)(_flowID + index));
+          }
           [self _handleRequestNumber:index
                             moduleID:[moduleIDs[index] integerValue]
                             methodID:[methodIDs[index] integerValue]
@@ -853,6 +872,8 @@ - (void)handleBuffer:(NSArray *)buffer
       dispatch_async(queue, block);
     }
   }
+
+  _flowID = callID;
 }
 
 - (void)partialBatchDidFlush
diff --git a/React/Base/RCTBridge+Private.h b/React/Base/RCTBridge+Private.h
index 91675efa5943..649771656877 100644
--- a/React/Base/RCTBridge+Private.h
+++ b/React/Base/RCTBridge+Private.h
@@ -13,6 +13,10 @@
 
 @interface RCTBridge ()
 
+// Used for the profiler flow events between JS and native
+@property (nonatomic, assign) int64_t flowID;
+@property (nonatomic, assign) CFMutableDictionaryRef flowIDMap;
+
 + (instancetype)currentBridge;
 + (void)setCurrentBridge:(RCTBridge *)bridge;
 
diff --git a/React/Executors/RCTJSCExecutor.m b/React/Executors/RCTJSCExecutor.m
index a586fd07e079..25ed23e21344 100644
--- a/React/Executors/RCTJSCExecutor.m
+++ b/React/Executors/RCTJSCExecutor.m
@@ -283,6 +283,20 @@ - (void)setUp
       CFDictionaryRemoveValue(cookieMap, (const void *)cookie);
     };
 
+#ifndef __clang_analyzer__
+    weakBridge.flowIDMap = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
+#endif
+    context[@"nativeTraceBeginAsyncFlow"] = ^(__unused uint64_t tag, __unused NSString *name, int64_t cookie) {
+      int64_t newCookie = [_RCTProfileBeginFlowEvent() longLongValue];
+      CFDictionarySetValue(weakBridge.flowIDMap, (const void *)cookie, (const void *)newCookie);
+    };
+
+    context[@"nativeTraceEndAsyncFlow"] = ^(__unused uint64_t tag, __unused NSString *name, int64_t cookie) {
+      int64_t newCookie = (int64_t)CFDictionaryGetValue(weakBridge.flowIDMap, (const void *)cookie);
+      _RCTProfileEndFlowEvent(@(newCookie));
+      CFDictionaryRemoveValue(weakBridge.flowIDMap, (const void *)cookie);
+    };
+
     context[@"nativeTraceBeginSection"] = ^(NSNumber *tag, NSString *profileName){
       static int profileCounter = 1;
       if (!profileName) {
diff --git a/React/Profiler/RCTProfile.h b/React/Profiler/RCTProfile.h
index 1cd721ab7cd2..7b888dc6a955 100644
--- a/React/Profiler/RCTProfile.h
+++ b/React/Profiler/RCTProfile.h
@@ -190,7 +190,7 @@ RCT_EXTERN void RCTProfileRegisterCallbacks(RCTProfileCallbacks *);
 #define _RCTProfileBeginFlowEvent() @0
 
 #define RCTProfileEndFlowEvent()
-#define _RCTProfileEndFlowEvent()
+#define _RCTProfileEndFlowEvent(...)
 
 #define RCTProfileIsProfiling(...) NO
 #define RCTProfileInit(...)

From 8c9c7e6286dcf2df2c17b616c692c526b868776b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Mon, 4 Jan 2016 11:31:48 -0800
Subject: [PATCH 0584/1411] Introduce transforms pipeline

Summary:
public

This diff introduces an internal transforms pipeline that integrates with the external one. This has been a feature we've been looking to implement for a long time to use babel instead of `replace` with regexps on many parts of the packager.

Also, to split the bundle we'll need to run one transform. Internally for Facebook we can run the system-import transform altogether withe the other ones. For OSS we offer `transformer.js` which people can use out of the box if they're writing ES6 code. For those people, `transformer.js` will also run the internal transforms`. However they might want to tune the transforms, or even write the code on another language that compiles to Javascript and use a complete different transformer. On those cases we'll need to run the external transforms first and pipe the output through the internal transforms. Note that the order it's important as the internal transforms assume the code is written in JS, though the original code could be on other scripting languages (CoffeeScript, TypeScript, etc).

Reviewed By: davidaurelio

Differential Revision: D2725109

fb-gh-sync-id: d764e209c78743419c4cb97068495c771372ab90
---
 local-cli/server/runServer.js                 |  1 +
 local-cli/server/server.js                    |  4 +
 packager/react-packager/index.js              |  2 +
 packager/react-packager/src/Bundler/index.js  |  5 +
 .../react-packager/src/JSTransformer/index.js | 16 ++-
 .../src/JSTransformer/worker.js               | 71 +++++++++++---
 packager/react-packager/src/Server/index.js   |  4 +
 .../src/SocketInterface/index.js              |  4 +-
 .../babel-plugin-system-import/index.js       | 98 +++++++++----------
 .../react-packager/src/transforms/index.js    | 16 +++
 packager/transformer.js                       |  6 +-
 11 files changed, 157 insertions(+), 70 deletions(-)
 create mode 100644 packager/react-packager/src/transforms/index.js

diff --git a/local-cli/server/runServer.js b/local-cli/server/runServer.js
index b4a690f4c170..871cea102b0d 100644
--- a/local-cli/server/runServer.js
+++ b/local-cli/server/runServer.js
@@ -68,6 +68,7 @@ function getAppMiddleware(args, config) {
     cacheVersion: '3',
     getTransformOptionsModulePath: config.getTransformOptionsModulePath,
     transformModulePath: transformerPath,
+    enableInternalTransforms: args['enable-internal-transforms'],
     assetRoots: args.assetRoots,
     assetExts: ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'webp'],
     resetCache: args.resetCache || args['reset-cache'],
diff --git a/local-cli/server/server.js b/local-cli/server/server.js
index 3abffb5beef4..a5ffe43f2d39 100644
--- a/local-cli/server/server.js
+++ b/local-cli/server/server.js
@@ -53,6 +53,10 @@ function _server(argv, config, resolve, reject) {
     type: 'string',
     default: require.resolve('../../packager/transformer'),
     description: 'Specify a custom transformer to be used (absolute path)'
+  }, {
+    command: 'enable-internal-transforms',
+    type: 'boolean',
+    default: false
   }, {
     command: 'resetCache',
     description: 'Removes cached files',
diff --git a/packager/react-packager/index.js b/packager/react-packager/index.js
index 5b28e7741a2b..367f23f3df8e 100644
--- a/packager/react-packager/index.js
+++ b/packager/react-packager/index.js
@@ -15,6 +15,7 @@ useGracefulFs();
 var debug = require('debug');
 var omit = require('underscore').omit;
 var Activity = require('./src/Activity');
+var Transforms = require('./src/transforms');
 
 exports.createServer = createServer;
 exports.middleware = function(options) {
@@ -23,6 +24,7 @@ exports.middleware = function(options) {
 };
 
 exports.Activity = Activity;
+exports.getTransforms = Transforms.getAll;
 
 // Renamed "package" to "bundle". But maintain backwards
 // compat.
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index dc76a267f589..7fdbe911db56 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -56,6 +56,10 @@ const validateOpts = declareOpts({
     type:'string',
     required: false,
   },
+  enableInternalTransforms: {
+    type: 'boolean',
+    default: false,
+  },
   nonPersistent: {
     type: 'boolean',
     default: false,
@@ -131,6 +135,7 @@ class Bundler {
       blacklistRE: opts.blacklistRE,
       cache: this._cache,
       transformModulePath: opts.transformModulePath,
+      enableInternalTransforms: opts.enableInternalTransforms,
     });
 
     this._projectRoots = opts.projectRoots;
diff --git a/packager/react-packager/src/JSTransformer/index.js b/packager/react-packager/src/JSTransformer/index.js
index 07225252943c..89f311628532 100644
--- a/packager/react-packager/src/JSTransformer/index.js
+++ b/packager/react-packager/src/JSTransformer/index.js
@@ -52,7 +52,11 @@ const validateOpts = declareOpts({
   transformTimeoutInterval: {
     type: 'number',
     default: DEFAULT_MAX_CALL_TIME,
-  }
+  },
+  enableInternalTransforms: {
+    type: 'boolean',
+    default: false,
+  },
 });
 
 class Transformer {
@@ -60,6 +64,8 @@ class Transformer {
     const opts = this._opts = validateOpts(options);
 
     this._cache = opts.cache;
+    this._transformModulePath = opts.transformModulePath;
+    this._enableInternalTransforms = opts.enableInternalTransforms;
 
     if (opts.transformModulePath != null) {
       this._workers = workerFarm({
@@ -68,7 +74,7 @@ class Transformer {
         maxCallsPerWorker: MAX_CALLS_PER_WORKER,
         maxCallTime: opts.transformTimeoutInterval,
         maxRetries: MAX_RETRIES,
-      }, opts.transformModulePath);
+      }, require.resolve('./worker'));
 
       this._transform = Promise.denodeify(this._workers);
     }
@@ -102,7 +108,11 @@ class Transformer {
           return this._transform({
             sourceCode,
             filename: filePath,
-            options,
+            options: {
+              ...options,
+              externalTransformModulePath: this._transformModulePath,
+              enableInternalTransforms: this._enableInternalTransforms,
+            },
           }).then(res => {
             if (res.error) {
               console.warn(
diff --git a/packager/react-packager/src/JSTransformer/worker.js b/packager/react-packager/src/JSTransformer/worker.js
index b6b4f363d56e..77a24938e598 100644
--- a/packager/react-packager/src/JSTransformer/worker.js
+++ b/packager/react-packager/src/JSTransformer/worker.js
@@ -8,27 +8,66 @@
  */
 'use strict';
 
-var transformer = require('./transformer');
+var babel = require('babel-core');
+var Transforms = require('../transforms');
 
-module.exports = function (data, callback) {
+// Runs internal transforms on the given sourceCode. Note that internal
+// transforms should be run after the external ones to ensure that they run on
+// Javascript code
+function internalTransforms(sourceCode, filename, options) {
+  var result = babel.transform(sourceCode, {
+    retainLines: true,
+    compact: true,
+    comments: false,
+    filename: filename,
+    sourceFileName: filename,
+    sourceMaps: false,
+    plugins: Transforms.getAll()
+  });
+
+  return {
+    code: result.code,
+    filename: filename,
+  };
+}
+
+function onExternalTransformDone(data, callback, error, externalOutput) {
   var result;
-  try {
-    result = transformer.transform(
-      data.transformSets,
-      data.sourceCode,
+  if (data.options.enableInternalTransforms) {
+    result = internalTransforms(
+      externalOutput.code,
+      externalOutput.filename,
       data.options
     );
-  } catch (e) {
-    return callback(null, {
-      error: {
-        lineNumber: e.lineNumber,
-        column: e.column,
-        message: e.message,
-        stack: e.stack,
-        description: e.description
-      }
-    });
+  } else {
+    result = externalOutput;
   }
 
   callback(null, result);
+}
+
+module.exports = function(data, callback) {
+  try {
+    if (data.options.externalTransformModulePath) {
+      var externalTransformModule = require(
+        data.options.externalTransformModulePath
+      );
+      externalTransformModule(
+        data,
+        onExternalTransformDone.bind(null, data, callback)
+      );
+    } else {
+      onExternalTransformDone(
+        data,
+        callback,
+        null,
+        {
+          code: data.sourceCode,
+          filename: data.filename
+        }
+      );
+    }
+  } catch (e) {
+    callback(e);
+  }
 };
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index 717ef9e17101..3e18a23cde43 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -52,6 +52,10 @@ const validateOpts = declareOpts({
     type: 'boolean',
     default: false,
   },
+  enableInternalTransforms: {
+    type: 'boolean',
+    default: false,
+  },
   assetRoots: {
     type: 'array',
     required: false,
diff --git a/packager/react-packager/src/SocketInterface/index.js b/packager/react-packager/src/SocketInterface/index.js
index 32e3688c333f..e2d70bbf6f57 100644
--- a/packager/react-packager/src/SocketInterface/index.js
+++ b/packager/react-packager/src/SocketInterface/index.js
@@ -30,7 +30,9 @@ const SocketInterface = {
         const value = options[key];
         if (value) {
           hash.update(
-            typeof value === 'string' ? value : JSON.stringify(value)
+            options[key] != null && typeof value === 'string'
+              ? value
+              : JSON.stringify(value)
           );
         }
       });
diff --git a/packager/react-packager/src/transforms/babel-plugin-system-import/index.js b/packager/react-packager/src/transforms/babel-plugin-system-import/index.js
index 8a6cbcf0c2e6..7cf0f0a08524 100644
--- a/packager/react-packager/src/transforms/babel-plugin-system-import/index.js
+++ b/packager/react-packager/src/transforms/babel-plugin-system-import/index.js
@@ -1,63 +1,63 @@
- /**
-  * 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.
-  *
-  */
+/**
+ * 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.
+ *
+ */
 /*jslint node: true */
 'use strict';
 
 const t = require('babel-types');
 
 /**
- * Transforms asynchronous module importing into a function call
- * that includes which bundle needs to be loaded
- *
- * Transforms:
- *
- *  System.import('moduleA')
- *
- * to:
- *
- *  loadBundles('bundleA')
- */
+* Transforms asynchronous module importing into a function call
+* that includes which bundle needs to be loaded
+*
+* Transforms:
+*
+*  System.import('moduleA')
+*
+* to:
+*
+*  loadBundles('bundleA')
+*/
 module.exports = function() {
-  return {
-    visitor: {
-      CallExpression: function (path, state) {
-        if (!isAppropriateSystemImportCall(path.node)) {
-          return;
-        }
+ return {
+   visitor: {
+     CallExpression: function (path, state) {
+       if (!isAppropriateSystemImportCall(path.node)) {
+         return;
+       }
 
-        var bundlesLayout = state.opts.bundlesLayout;
-        var bundleID = bundlesLayout.getBundleIDForModule(
-          path.node.arguments[0].value
-        );
+       var bundlesLayout = state.opts.bundlesLayout;
+       var bundleID = bundlesLayout.getBundleIDForModule(
+         path.node.arguments[0].value
+       );
 
-        var bundles = bundleID.split('.');
-        bundles.splice(0, 1);
-        bundles = bundles.map(function(id) {
-          return t.stringLiteral('bundle.' + id);
-        });
+       var bundles = bundleID.split('.');
+       bundles.splice(0, 1);
+       bundles = bundles.map(function(id) {
+         return t.stringLiteral('bundle.' + id);
+       });
 
-        path.replaceWith(t.callExpression(
-          t.identifier('loadBundles'),
-          [t.arrayExpression(bundles)]
-        ));
-      },
-    },
-  };
+       path.replaceWith(t.callExpression(
+         t.identifier('loadBundles'),
+         [t.arrayExpression(bundles)]
+       ));
+     },
+   },
+ };
 };
 
 function isAppropriateSystemImportCall(node) {
-  return (
-    node.callee.type === 'MemberExpression' &&
-    node.callee.object.name === 'System' &&
-    node.callee.property.name === 'import' &&
-    node.arguments.length === 1 &&
-    node.arguments[0].type === 'StringLiteral'
-  );
+ return (
+   node.callee.type === 'MemberExpression' &&
+   node.callee.object.name === 'System' &&
+   node.callee.property.name === 'import' &&
+   node.arguments.length === 1 &&
+   node.arguments[0].type === 'StringLiteral'
+ );
 }
diff --git a/packager/react-packager/src/transforms/index.js b/packager/react-packager/src/transforms/index.js
new file mode 100644
index 000000000000..1e55a34b3701
--- /dev/null
+++ b/packager/react-packager/src/transforms/index.js
@@ -0,0 +1,16 @@
+/**
+ * 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.
+ */
+'use strict';
+
+exports.getAll = function() {
+  return [
+    require('./babel-plugin-system-import'),
+  ];
+};
+
diff --git a/packager/transformer.js b/packager/transformer.js
index 70dde7702c28..512686065a06 100644
--- a/packager/transformer.js
+++ b/packager/transformer.js
@@ -15,6 +15,7 @@ const fs = require('fs');
 const inlineRequires = require('fbjs-scripts/babel-6/inline-requires');
 const json5 = require('json5');
 const path = require('path');
+const ReactPackager = require('./react-packager');
 
 const babelRC =
   json5.parse(
@@ -53,10 +54,13 @@ function transform(src, filename, options) {
     return plugin;
   });
 
+  config.plugins = config.plugins.concat(ReactPackager.getTransforms());
+
   const result = babel.transform(src, Object.assign({}, babelRC, config));
 
   return {
-    code: result.code
+    code: result.code,
+    filename: filename,
   };
 }
 

From 42e5b2a5bc8b4730c25852de3dcf6ba344a93bbb Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Mon, 4 Jan 2016 12:00:18 -0800
Subject: [PATCH 0585/1411] WebWorkers: Add MessageQueueThreadRegistry

Summary:
public

It is helpful to be able to access the current MessageQueueThread like you would the current Looper. I would do this exactly as Looper does it, but we have forked implementations of MQT for the native bridge and MQT is an interface that can't hold private members.

Reviewed By: lexs

Differential Revision: D2779072

fb-gh-sync-id: 0ff841d8c490b971697c8e5d45f9c0a57668376b
---
 .../bridge/queue/MessageQueueThreadImpl.java  | 48 ++++++++++++-------
 .../queue/MessageQueueThreadRegistry.java     | 38 +++++++++++++++
 .../common/futures/SimpleSettableFuture.java  | 12 +++++
 3 files changed, 82 insertions(+), 16 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadRegistry.java

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java
index 48328da25abc..c0961b0c6144 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java
@@ -10,10 +10,8 @@
 package com.facebook.react.bridge.queue;
 
 import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
 
 import android.os.Looper;
 
@@ -21,6 +19,7 @@
 import com.facebook.proguard.annotations.DoNotStrip;
 import com.facebook.react.bridge.AssertionException;
 import com.facebook.react.bridge.SoftAssertions;
+import com.facebook.react.bridge.UiThreadUtil;
 import com.facebook.react.common.ReactConstants;
 import com.facebook.react.common.futures.SimpleSettableFuture;
 
@@ -28,7 +27,7 @@
  * Encapsulates a Thread that has a {@link Looper} running on it that can accept Runnables.
  */
 @DoNotStrip
-/* package */ class MessageQueueThreadImpl implements MessageQueueThread {
+public class MessageQueueThreadImpl implements MessageQueueThread {
 
   private final String mName;
   private final Looper mLooper;
@@ -142,7 +141,25 @@ private static MessageQueueThreadImpl createForMainThread(
       String name,
       QueueThreadExceptionHandler exceptionHandler) {
     Looper mainLooper = Looper.getMainLooper();
-    return new MessageQueueThreadImpl(name, mainLooper, exceptionHandler);
+    final MessageQueueThreadImpl mqt =
+        new MessageQueueThreadImpl(name, mainLooper, exceptionHandler);
+
+    // Ensure that the MQT is registered by the time this method returns
+    if (UiThreadUtil.isOnUiThread()) {
+      MessageQueueThreadRegistry.register(mqt);
+    } else {
+      final SimpleSettableFuture<Void> registrationFuture = new SimpleSettableFuture<>();
+      UiThreadUtil.runOnUiThread(
+          new Runnable() {
+            @Override
+            public void run() {
+              MessageQueueThreadRegistry.register(mqt);
+              registrationFuture.set(null);
+            }
+          });
+      registrationFuture.getOrThrow(5000, TimeUnit.MILLISECONDS);
+    }
+    return mqt;
   }
 
   /**
@@ -150,30 +167,29 @@ private static MessageQueueThreadImpl createForMainThread(
    * running on it. Give it a name for easier debugging. When this method exits, the new
    * MessageQueueThreadImpl is ready to receive events.
    */
-  private static MessageQueueThreadImpl startNewBackgroundThread(
-      String name,
+  public static MessageQueueThreadImpl startNewBackgroundThread(
+      final String name,
       QueueThreadExceptionHandler exceptionHandler) {
-    final SimpleSettableFuture<Looper> simpleSettableFuture = new SimpleSettableFuture<>();
+    final SimpleSettableFuture<Looper> looperFuture = new SimpleSettableFuture<>();
+    final SimpleSettableFuture<MessageQueueThread> mqtFuture = new SimpleSettableFuture<>();
     Thread bgThread = new Thread(
         new Runnable() {
           @Override
           public void run() {
             Looper.prepare();
 
-            simpleSettableFuture.set(Looper.myLooper());
+            looperFuture.set(Looper.myLooper());
+            MessageQueueThreadRegistry.register(mqtFuture.getOrThrow(5000, TimeUnit.MILLISECONDS));
 
             Looper.loop();
           }
         }, "mqt_" + name);
     bgThread.start();
 
-    try {
-      return new MessageQueueThreadImpl(
-          name,
-          simpleSettableFuture.get(5000, TimeUnit.MILLISECONDS),
-          exceptionHandler);
-    } catch (InterruptedException | ExecutionException | TimeoutException e) {
-      throw new RuntimeException(e);
-    }
+    Looper myLooper = looperFuture.getOrThrow(5000, TimeUnit.MILLISECONDS);
+    MessageQueueThreadImpl mqt = new MessageQueueThreadImpl(name, myLooper, exceptionHandler);
+    mqtFuture.set(mqt);
+
+    return mqt;
   }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadRegistry.java
new file mode 100644
index 000000000000..b924fd88bc1a
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadRegistry.java
@@ -0,0 +1,38 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.bridge.queue;
+
+import com.facebook.infer.annotation.Assertions;
+import com.facebook.proguard.annotations.DoNotStrip;
+
+/**
+ * A utility for getting the MessageQueueThread for the current thread. Once there is only one
+ * implementation of MessageQueueThread, this should move to that class.
+ */
+@DoNotStrip
+public class MessageQueueThreadRegistry {
+
+  private static ThreadLocal<MessageQueueThread> sMyMessageQueueThread = new ThreadLocal<>();
+
+  /*package*/ static void register(MessageQueueThread mqt) {
+    mqt.assertIsOnThread();
+    sMyMessageQueueThread.set(mqt);
+  }
+
+  /**
+   * @return the MessageQueueThread that owns the current Thread.
+   */
+  public static MessageQueueThread myMessageQueueThread() {
+    return Assertions.assertNotNull(
+        sMyMessageQueueThread.get(),
+        "This thread doesn't have a MessageQueueThread registered to it!");
+  }
+}
+
diff --git a/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java b/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java
index 23619eccf947..b2809ae37089 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java
@@ -91,6 +91,18 @@ public T get() throws InterruptedException, ExecutionException {
     return mResult;
   }
 
+  /**
+   * Convenience wrapper for {@link #get(long, TimeUnit)} that re-throws get()'s Exceptions as
+   * RuntimeExceptions.
+   */
+  public @Nullable T getOrThrow(long timeout, TimeUnit unit) {
+    try {
+      return get(timeout, unit);
+    } catch (InterruptedException | ExecutionException | TimeoutException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
   private void checkNotSet() {
     if (mReadyLatch.getCount() == 0) {
       throw new RuntimeException("Result has already been set!");

From ba2fcd39d140b336bd6dbb9cff9b1eea0dcd1bcf Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Mon, 4 Jan 2016 12:07:52 -0800
Subject: [PATCH 0586/1411] WebWorkers: Add JSLoader API for loading script
 from assets with AssetLoader reference

Summary:
public

Adds the ability to load files from assets without threading through an AssetManager. After the bridge is unforked, we should move to passing through an Environment object instead.

Reviewed By: lexs

Differential Revision: D2779079

fb-gh-sync-id: 82b47ecdf48b724076d87f4879ec40601e21e6bc
---
 .../react/ReactInstanceManagerImpl.java       |  5 +++
 .../react/common/ApplicationHolder.java       | 36 +++++++++++++++++++
 .../src/main/jni/react/jni/JSLoader.cpp       | 26 +++++++++++++-
 .../src/main/jni/react/jni/JSLoader.h         |  8 +++++
 .../src/main/jni/react/jni/OnLoad.cpp         |  1 +
 5 files changed, 75 insertions(+), 1 deletion(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/common/ApplicationHolder.java

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index d7b375cfb6cd..66ce1a2e8004 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -17,6 +17,7 @@
 import java.util.concurrent.ConcurrentLinkedQueue;
 
 import android.app.Activity;
+import android.app.Application;
 import android.content.Context;
 import android.content.Intent;
 import android.os.AsyncTask;
@@ -45,6 +46,7 @@
 import com.facebook.react.bridge.WritableMap;
 import com.facebook.react.bridge.WritableNativeMap;
 import com.facebook.react.bridge.queue.CatalystQueueConfigurationSpec;
+import com.facebook.react.common.ApplicationHolder;
 import com.facebook.react.common.ReactConstants;
 import com.facebook.react.common.annotations.VisibleForTesting;
 import com.facebook.react.devsupport.DevServerHelper;
@@ -199,6 +201,9 @@ protected void onPostExecute(ReactApplicationContext reactContext) {
       UIImplementationProvider uiImplementationProvider) {
     initializeSoLoaderIfNecessary(applicationContext);
 
+    // TODO(9577825): remove this
+    ApplicationHolder.setApplication((Application) applicationContext.getApplicationContext());
+
     mApplicationContext = applicationContext;
     mJSBundleFile = jsBundleFile;
     mJSMainModuleName = jsMainModuleName;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/common/ApplicationHolder.java b/ReactAndroid/src/main/java/com/facebook/react/common/ApplicationHolder.java
new file mode 100644
index 000000000000..535b81597c8a
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/common/ApplicationHolder.java
@@ -0,0 +1,36 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.common;
+
+import android.app.Application;
+
+import com.facebook.infer.annotation.Assertions;
+import com.facebook.proguard.annotations.DoNotStrip;
+
+/**
+ * Holds the current Application Object.
+ *
+ * TODO(9577825): This is a bad pattern, we should thread through an Environment object instead.
+ * Remove once bridge is unforked.
+ */
+@DoNotStrip
+@Deprecated
+public class ApplicationHolder {
+
+  private static Application sApplication;
+
+  public static void setApplication(Application application) {
+    sApplication = application;
+  }
+
+  public static Application getApplication() {
+    return Assertions.assertNotNull(sApplication);
+  }
+}
diff --git a/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp b/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp
index 416640a371de..db8b4d980e63 100644
--- a/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp
@@ -4,6 +4,7 @@
 
 #include <android/asset_manager.h>
 #include <android/asset_manager_jni.h>
+#include <jni/Environment.h>
 #include <fstream>
 #include <sstream>
 #include <streambuf>
@@ -18,6 +19,19 @@ using fbsystrace::FbSystraceSection;
 namespace facebook {
 namespace react {
 
+static jclass gApplicationHolderClass;
+static jmethodID gGetApplicationMethod;
+static jmethodID gGetAssetManagerMethod;
+
+std::string loadScriptFromAssets(std::string assetName) {
+  JNIEnv *env = jni::Environment::current();
+  jobject application = env->CallStaticObjectMethod(
+    gApplicationHolderClass,
+    gGetApplicationMethod);
+  jobject assetManager = env->CallObjectMethod(application, gGetAssetManagerMethod);
+  return loadScriptFromAssets(env, assetManager, assetName);
+}
+
 std::string loadScriptFromAssets(
     JNIEnv *env,
     jobject assetManager,
@@ -71,4 +85,14 @@ std::string loadScriptFromFile(std::string fileName) {
   return "";
 }
 
-} }
\ No newline at end of file
+void registerJSLoaderNatives() {
+  JNIEnv *env = jni::Environment::current();
+  jclass applicationHolderClass = env->FindClass("com/facebook/react/common/ApplicationHolder");
+  gApplicationHolderClass = (jclass)env->NewGlobalRef(applicationHolderClass);
+  gGetApplicationMethod = env->GetStaticMethodID(applicationHolderClass, "getApplication", "()Landroid/app/Application;");
+  
+  jclass appClass = env->FindClass("android/app/Application");
+  gGetAssetManagerMethod = env->GetMethodID(appClass, "getAssets", "()Landroid/content/res/AssetManager;");
+}
+
+} }
diff --git a/ReactAndroid/src/main/jni/react/jni/JSLoader.h b/ReactAndroid/src/main/jni/react/jni/JSLoader.h
index c7381fe7e8f7..25dab510d7a2 100644
--- a/ReactAndroid/src/main/jni/react/jni/JSLoader.h
+++ b/ReactAndroid/src/main/jni/react/jni/JSLoader.h
@@ -8,6 +8,12 @@
 namespace facebook {
 namespace react {
 
+/**
+ * Helper method for loading a JS script from Android assets without
+ * a reference to an AssetManager.
+ */
+std::string loadScriptFromAssets(std::string assetName);
+
 /**
  * Helper method for loading JS script from android asset
  */
@@ -18,4 +24,6 @@ std::string loadScriptFromAssets(JNIEnv *env, jobject assetManager, std::string
  */
 std::string loadScriptFromFile(std::string fileName);
 
+void registerJSLoaderNatives();
+
 } }
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 5ef5c28aaba5..6eb6d523e343 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -780,6 +780,7 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
     NativeArray::registerNatives();
     ReadableNativeArray::registerNatives();
     WritableNativeArray::registerNatives();
+    registerJSLoaderNatives();
 
     registerNatives("com/facebook/react/bridge/NativeMap", {
         makeNativeMethod("initialize", map::initialize),

From f2bdb7978260720f48b4b082e17b4474721a3ec1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Mon, 4 Jan 2016 13:01:28 -0800
Subject: [PATCH 0587/1411] Make HMR server send full list modules that changed

Summary:
public

Before this diff we were only accepting the module that was modified but the user. This works fine as long as the user doesn't modify the dependencies a module has but once he starts doing so the HMR runtime may fail when updating modules' code because they might might a few dependencies. For instance, if the user changes the `src` a `Image` has to reference an image (using the new asset system) that wasn't on the original bundle the user will get a red box. This diff addresses this by diffing the modules the app currently has with the new ones it should have and including all of them on the HMR update. Note this diffing is only done when the we realize the module that was modified changed it's dependencies so there's no additional overhead on this change.

Reviewed By: vjeux

Differential Revision: D2796325

fb-gh-sync-id: cac95f2e995310634c221bbbb09d9f3e7bc03e8d
---
 local-cli/server/util/attachHMRServer.js      | 96 ++++++++++++++-----
 packager/react-packager/src/Bundler/index.js  | 52 +++++-----
 .../DependencyGraph/index.js                  |  7 ++
 packager/react-packager/src/Resolver/index.js |  4 +
 .../src/Resolver/polyfills/require.js         |  8 +-
 packager/react-packager/src/Server/index.js   | 35 ++-----
 6 files changed, 118 insertions(+), 84 deletions(-)

diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js
index e039edef5701..2b1ff4334520 100644
--- a/local-cli/server/util/attachHMRServer.js
+++ b/local-cli/server/util/attachHMRServer.js
@@ -35,27 +35,47 @@ function attachHMRServer({httpServer, path, packagerServer}) {
       // for each dependency builds the object:
       // `{path: '/a/b/c.js', deps: ['modA', 'modB', ...]}`
       return Promise.all(Object.values(response.dependencies).map(dep => {
-        if (dep.isAsset() || dep.isAsset_DEPRECATED() || dep.isJSON()) {
-          return Promise.resolve({path: dep.path, deps: []});
-        }
-        return packagerServer.getShallowDependencies(dep.path)
-          .then(deps => {
-            return {
-              path: dep.path,
-              deps,
-            };
-          });
+        return dep.getName().then(depName => {
+          if (dep.isAsset() || dep.isAsset_DEPRECATED() || dep.isJSON()) {
+            return Promise.resolve({path: dep.path, deps: []});
+          }
+          return packagerServer.getShallowDependencies(dep.path)
+            .then(deps => {
+              return {
+                path: dep.path,
+                name: depName,
+                deps,
+              };
+            });
+        });
       }))
       .then(deps => {
-        // list with all the dependencies the bundle entry has
+        // list with all the dependencies' filenames the bundle entry has
         const dependenciesCache = response.dependencies.map(dep => dep.path);
 
+        // map from module name to path
+        const moduleToFilenameCache = Object.create(null);
+        deps.forEach(dep => moduleToFilenameCache[dep.name] = dep.path);
+
         // map that indicates the shallow dependency each file included on the
         // bundle has
-        const shallowDependencies = {};
+        const shallowDependencies = Object.create(null);
         deps.forEach(dep => shallowDependencies[dep.path] = dep.deps);
 
-        return {dependenciesCache, shallowDependencies};
+        // map from module name to the modules' dependencies the bundle entry
+        // has
+        const dependenciesModulesCache = Object.create(null);
+        return Promise.all(response.dependencies.map(dep => {
+          return dep.getName().then(depName => {
+            dependenciesModulesCache[depName] = dep;
+          });
+        })).then(() => {
+          return {
+            dependenciesCache,
+            dependenciesModulesCache,
+            shallowDependencies,
+          };
+        });
       });
     });
   }
@@ -72,18 +92,23 @@ function attachHMRServer({httpServer, path, packagerServer}) {
     const params = querystring.parse(url.parse(ws.upgradeReq.url).query);
 
     getDependencies(params.platform, params.bundleEntry)
-      .then(({dependenciesCache, shallowDependencies}) => {
+      .then(({
+        dependenciesCache,
+        dependenciesModulesCache,
+        shallowDependencies,
+      }) => {
         client = {
           ws,
           platform: params.platform,
           bundleEntry: params.bundleEntry,
           dependenciesCache,
+          dependenciesModulesCache,
           shallowDependencies,
         };
 
         packagerServer.setHMRFileChangeListener(filename => {
           if (!client) {
-            return Promise.resolve();
+            return;
           }
 
           return packagerServer.getShallowDependencies(filename)
@@ -91,28 +116,49 @@ function attachHMRServer({httpServer, path, packagerServer}) {
               // if the file dependencies have change we need to invalidate the
               // dependencies caches because the list of files we need to send
               // to the client may have changed
-              if (arrayEquals(deps, client.shallowDependencies[filename])) {
-                return Promise.resolve();
+              const oldDependencies = client.shallowDependencies[filename];
+              if (arrayEquals(deps, oldDependencies)) {
+                return [packagerServer.getModuleForPath(filename)];
               }
+
+              // if there're new dependencies compare the full list of
+              // dependencies we used to have with the one we now have
               return getDependencies(client.platform, client.bundleEntry)
-                .then(({dependenciesCache, shallowDependencies}) => {
+                .then(({
+                  dependenciesCache,
+                  dependenciesModulesCache,
+                  shallowDependencies,
+                }) => {
+                  // build list of modules for which we'll send HMR updates
+                  const modulesToUpdate = [];
+                  Object.keys(dependenciesModulesCache).forEach(module => {
+                    if (!client.dependenciesModulesCache[module]) {
+                      modulesToUpdate.push(dependenciesModulesCache[module]);
+                    }
+                  });
+
                   // invalidate caches
                   client.dependenciesCache = dependenciesCache;
+                  client.dependenciesModulesCache = dependenciesModulesCache;
                   client.shallowDependencies = shallowDependencies;
+
+                  return modulesToUpdate;
                 });
             })
-            .then(() => {
+            .then(modulesToUpdate => {
               // make sure the file was modified is part of the bundle
               if (!client.shallowDependencies[filename]) {
                 return;
               }
 
-              return packagerServer.buildBundleForHMR({
-                platform: client.platform,
-                entryFile: filename,
-              })
-              .then(bundle => client.ws.send(bundle));
-            });
+              return packagerServer.buildBundleForHMR(modulesToUpdate);
+            })
+            .then(bundle => {
+              if (bundle) {
+                client.ws.send(bundle);
+              }
+            })
+            .done();
         });
 
         client.ws.on('error', e => {
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index 7fdbe911db56..bbb4d3bb49c5 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -284,31 +284,29 @@ class Bundler {
     });
   }
 
-  bundleForHMR({
-    entryFile,
-    platform,
-  }) {
-    return this.getDependencies(entryFile, /*isDev*/true, platform).then(response => {
-      const module = response.dependencies.filter(module => module.path === entryFile)[0];
-
-      return Promise.all([
-        module.getName(),
-        this._transformer.loadFileAndTransform(
-          path.resolve(entryFile),
-          // TODO(martinb): pass non null main (t9527509)
-          this._getTransformOptions({main: null}, {hot: true}),
-        ),
-      ]).then(([moduleName, transformedSource]) => {
-        return (`
-          __accept(
-            '${moduleName}',
-            function(global, require, module, exports) {
-              ${transformedSource.code}
-            }
-          );
-        `);
-      });
-    });
+  bundleForHMR(modules) {
+    return Promise.all(
+      modules.map(module => {
+        return Promise.all([
+          module.getName(),
+          this._transformer.loadFileAndTransform(
+            module.path,
+            // TODO(martinb): pass non null main (t9527509)
+            this._getTransformOptions({main: null}, {hot: true}),
+          ),
+        ]).then(([moduleName, transformedSource]) => {
+          return (`
+            __accept(
+              '${moduleName}',
+              function(global, require, module, exports) {
+                ${transformedSource.code}
+              }
+            );
+          `);
+        });
+      })
+    )
+    .then(code => code.join('\n'));
   }
 
   invalidateFile(filePath) {
@@ -319,6 +317,10 @@ class Bundler {
     return this._resolver.getShallowDependencies(entryFile);
   }
 
+  getModuleForPath(entryFile) {
+    return this._resolver.getModuleForPath(entryFile);
+  }
+
   getDependencies(main, isDev, platform) {
     return this._resolver.getDependencies(main, { dev: isDev, platform });
   }
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
index c4e983ad9072..ec0d964e0eaf 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
@@ -143,6 +143,13 @@ class DependencyGraph {
     return this._moduleCache.getModule(entryPath).getDependencies();
   }
 
+  /**
+   * Returns the module object for the given path.
+   */
+  getModuleForPath(entryFile) {
+    return this._moduleCache.getModule(entryFile);
+  }
+
   getDependencies(entryPath, platform) {
     return this.load().then(() => {
       platform = this._getRequestPlatform(entryPath, platform);
diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index ecc9eeebeb62..efa61d576aa7 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -104,6 +104,10 @@ class Resolver {
     return this._depGraph.getShallowDependencies(entryFile);
   }
 
+  getModuleForPath(entryFile) {
+    return this._depGraph.getModuleForPath(entryFile);
+  }
+
   getDependencies(main, options) {
     const opts = getDependenciesValidateOpts(options);
 
diff --git a/packager/react-packager/src/Resolver/polyfills/require.js b/packager/react-packager/src/Resolver/polyfills/require.js
index afcda4ca139d..36c2b6b90d32 100644
--- a/packager/react-packager/src/Resolver/polyfills/require.js
+++ b/packager/react-packager/src/Resolver/polyfills/require.js
@@ -99,12 +99,8 @@
       var mod = modules[id];
 
       if (!mod) {
-        console.warn(
-          'Cannot accept unknown module `' + id + '`. Make sure you\'re not ' +
-          'trying to modify something else other than a module ' +
-          '(i.e.: a polyfill).'
-        );
-        return;
+        define(id, factory);
+        return; // new modules don't need to be accepted
       }
 
       if (!mod.module.hot) {
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index 3e18a23cde43..858bc0e4f915 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -120,17 +120,6 @@ const bundleOpts = declareOpts({
   },
 });
 
-const hmrBundleOpts = declareOpts({
-  entryFile: {
-    type: 'string',
-    required: true,
-  },
-  platform: {
-    type: 'string',
-    required: true,
-  },
-});
-
 const dependencyOpts = declareOpts({
   platform: {
     type: 'string',
@@ -199,13 +188,10 @@ class Server {
       // updates. Instead, send the HMR updates right away and once that
       // finishes, invoke any other file change listener.
       if (this._hmrFileChangeListener) {
-        this._hmrFileChangeListener(filePath).then(() => {
-          this._fileChangeListeners.forEach(listener => listener(filePath));
-        }).done();
+        this._hmrFileChangeListener(filePath);
         return;
       }
 
-      this._fileChangeListeners.forEach(listener => listener(filePath));
       this._rebuildBundles(filePath);
       this._informChangeWatchers();
     }, 50);
@@ -218,10 +204,6 @@ class Server {
     ]);
   }
 
-  addFileChangeListener(listener) {
-    this._fileChangeListeners.push(listener);
-  }
-
   setHMRFileChangeListener(listener) {
     this._hmrFileChangeListener = listener;
   }
@@ -253,21 +235,18 @@ class Server {
     return this.buildBundle(options);
   }
 
-  buildBundleForHMR(options) {
-    return Promise.resolve().then(() => {
-      if (!options.platform) {
-        options.platform = getPlatformExtension(options.entryFile);
-      }
-
-      const opts = hmrBundleOpts(options);
-      return this._bundler.bundleForHMR(opts);
-    });
+  buildBundleForHMR(modules) {
+    return this._bundler.bundleForHMR(modules);
   }
 
   getShallowDependencies(entryFile) {
     return this._bundler.getShallowDependencies(entryFile);
   }
 
+  getModuleForPath(entryFile) {
+    return this._bundler.getModuleForPath(entryFile);
+  }
+
   getDependencies(options) {
     return Promise.resolve().then(() => {
       if (!options.platform) {

From 4866ec27675c44818c0e892b310965eaeb1d09f9 Mon Sep 17 00:00:00 2001
From: Felix Oghina <foghina@fb.com>
Date: Mon, 4 Jan 2016 13:16:58 -0800
Subject: [PATCH 0588/1411] crash gracefully on fatal js errors (take two)

Reviewed By: AaaChiuuu

Differential Revision: D2773513

fb-gh-sync-id: f8e50ad12e808caf1d85c6c7859c04fcabdaaeae
---
 .../facebook/react/ReactInstanceManager.java  | 15 ++++++++++++-
 .../react/ReactInstanceManagerImpl.java       | 11 ++++++++--
 .../react/devsupport/DevSupportManager.java   | 21 +++++++++----------
 3 files changed, 33 insertions(+), 14 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
index f3544cb81899..17fb538b826d 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
@@ -19,6 +19,7 @@
 import android.content.Intent;
 
 import com.facebook.infer.annotation.Assertions;
+import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
 import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener;
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.ReactContext;
@@ -159,6 +160,7 @@ public static class Builder {
     protected boolean mUseDeveloperSupport;
     protected @Nullable LifecycleState mInitialLifecycleState;
     protected @Nullable UIImplementationProvider mUIImplementationProvider;
+    protected @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
 
     protected Builder() {
     }
@@ -242,6 +244,16 @@ public Builder setInitialLifecycleState(LifecycleState initialLifecycleState) {
       return this;
     }
 
+    /**
+     * Set the exception handler for all native module calls. If not set, the default
+     * {@link DevSupportManager} will be used, which shows a redbox in dev mode and rethrows
+     * (crashes the app) in prod mode.
+     */
+    public Builder setNativeModuleCallExceptionHandler(NativeModuleCallExceptionHandler handler) {
+      mNativeModuleCallExceptionHandler = handler;
+      return this;
+    }
+
     /**
      * Instantiates a new {@link ReactInstanceManagerImpl}.
      * Before calling {@code build}, the following must be called:
@@ -274,7 +286,8 @@ public ReactInstanceManager build() {
           mUseDeveloperSupport,
           mBridgeIdleDebugListener,
           Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"),
-          mUIImplementationProvider);
+          mUIImplementationProvider,
+          mNativeModuleCallExceptionHandler);
     }
   }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index 66ce1a2e8004..ad10a6e7c68e 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -36,6 +36,7 @@
 import com.facebook.react.bridge.JavaScriptModule;
 import com.facebook.react.bridge.JavaScriptModulesConfig;
 import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
 import com.facebook.react.bridge.NativeModuleRegistry;
 import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener;
 import com.facebook.react.bridge.ProxyJavaScriptExecutor;
@@ -103,6 +104,7 @@
   private volatile boolean mHasStartedCreatingInitialContext = false;
   private final UIImplementationProvider mUIImplementationProvider;
   private final MemoryPressureRouter mMemoryPressureRouter;
+  private final @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
 
   private final ReactInstanceDevCommandsHandler mDevInterface =
       new ReactInstanceDevCommandsHandler() {
@@ -198,7 +200,8 @@ protected void onPostExecute(ReactApplicationContext reactContext) {
       boolean useDeveloperSupport,
       @Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener,
       LifecycleState initialLifecycleState,
-      UIImplementationProvider uiImplementationProvider) {
+      UIImplementationProvider uiImplementationProvider,
+      NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
     initializeSoLoaderIfNecessary(applicationContext);
 
     // TODO(9577825): remove this
@@ -222,6 +225,7 @@ protected void onPostExecute(ReactApplicationContext reactContext) {
     mLifecycleState = initialLifecycleState;
     mUIImplementationProvider = uiImplementationProvider;
     mMemoryPressureRouter = new MemoryPressureRouter(applicationContext);
+    mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
   }
 
   @Override
@@ -660,13 +664,16 @@ private ReactApplicationContext createReactContext(
       Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
     }
 
+    NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null
+        ? mNativeModuleCallExceptionHandler
+        : mDevSupportManager;
     CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
         .setCatalystQueueConfigurationSpec(CatalystQueueConfigurationSpec.createDefault())
         .setJSExecutor(jsExecutor)
         .setRegistry(nativeModuleRegistry)
         .setJSModulesConfig(javaScriptModulesConfig)
         .setJSBundleLoader(jsBundleLoader)
-        .setNativeModuleCallExceptionHandler(mDevSupportManager);
+        .setNativeModuleCallExceptionHandler(exceptionHandler);
 
     Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstance");
     CatalystInstance catalystInstance;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
index 3e38a19fb974..bcc094062c02 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
@@ -155,7 +155,7 @@ public void onReceive(Context context, Intent intent) {
   public void handleException(Exception e) {
     if (mIsDevSupportEnabled) {
       FLog.e(ReactConstants.TAG, "Exception in native call from JS", e);
-      showNewError(e.getMessage(), StackTraceHelper.convertJavaStackTrace(e), JAVA_ERROR_COOKIE);
+      showNewJavaError(e.getMessage(), e);
     } else {
       if (e instanceof RuntimeException) {
         // Because we are rethrowing the original exception, the original stacktrace will be
@@ -167,6 +167,10 @@ public void handleException(Exception e) {
     }
   }
 
+  public void showNewJavaError(String message, Throwable e) {
+    showNewError(message, StackTraceHelper.convertJavaStackTrace(e), JAVA_ERROR_COOKIE);
+  }
+
   /**
    * Add option item to dev settings dialog displayed by this manager. In the case user select given
    * option from that dialog, the appropriate handler passed as {@param optionHandler} will be
@@ -555,10 +559,9 @@ public void onFailure(final Throwable cause) {
                 new Runnable() {
                   @Override
                   public void run() {
-                    showNewError(
+                    showNewJavaError(
                         mApplicationContext.getString(R.string.catalyst_remotedbg_error),
-                        StackTraceHelper.convertJavaStackTrace(cause),
-                        JAVA_ERROR_COOKIE);
+                        cause);
                   }
                 });
           }
@@ -590,15 +593,11 @@ public void onFailure(final Exception cause) {
                   public void run() {
                     if (cause instanceof DebugServerException) {
                       DebugServerException debugServerException = (DebugServerException) cause;
-                      showNewError(
-                          debugServerException.description,
-                          StackTraceHelper.convertJavaStackTrace(cause),
-                          JAVA_ERROR_COOKIE);
+                      showNewJavaError(debugServerException.description, cause);
                     } else {
-                      showNewError(
+                      showNewJavaError(
                           mApplicationContext.getString(R.string.catalyst_jsload_error),
-                          StackTraceHelper.convertJavaStackTrace(cause),
-                          JAVA_ERROR_COOKIE);
+                          cause);
                     }
                   }
                 });

From a6bca4041bc95eb9fe43a61e1f4552c5551d9575 Mon Sep 17 00:00:00 2001
From: James Zhang <jamesfzhang@gmail.com>
Date: Mon, 4 Jan 2016 13:37:19 -0800
Subject: [PATCH 0589/1411] Fix AlertIOS Examples

Summary:
This fixes the examples that are out of date.
Closes https://github.com/facebook/react-native/pull/5116

Reviewed By: svcscm

Differential Revision: D2800319

Pulled By: androidtrunkagent

fb-gh-sync-id: da1810c6146950be4be670fc69b9da32fb266303
---
 Examples/UIExplorer/AlertIOSExample.js | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/Examples/UIExplorer/AlertIOSExample.js b/Examples/UIExplorer/AlertIOSExample.js
index 7532e4151bab..117c4cfe3329 100644
--- a/Examples/UIExplorer/AlertIOSExample.js
+++ b/Examples/UIExplorer/AlertIOSExample.js
@@ -46,9 +46,8 @@ exports.examples = [{
             'Hello World',
             null,
             [
-              {text: 'OK', onPress: (text) => console.log('OK pressed')},
-            ],
-            'default'
+              {text: 'OK', onPress: (text) => console.log('OK pressed'), type: 'default'}
+            ]
           )}>
 
           <View style={styles.button}>
@@ -64,9 +63,9 @@ exports.examples = [{
             'Plain Text Entry',
             null,
             [
-              {text: 'Submit', onPress: (text) => console.log('Text: ' + text)},
-            ],
-            'plain-text'
+              {text: 'Submit', onPress: (text) => console.log('Text: ' + text), type: 'plain-text'},
+              {text: 'Cancel', onPress: () => console.log('Cancel'), style: 'cancel'}
+            ]
           )}>
 
           <View style={styles.button}>
@@ -82,9 +81,9 @@ exports.examples = [{
             'Secure Text Entry',
             null,
             [
-              {text: 'Submit', onPress: (text) => console.log('Password: ' + text)},
-            ],
-            'secure-text'
+              {text: 'Submit', onPress: (text) => console.log('Password: ' + text), type: 'secure-text'},
+              {text: 'Cancel', onPress: () => console.log('Cancel'), style: 'cancel'}
+            ]
           )}>
 
           <View style={styles.button}>
@@ -100,9 +99,9 @@ exports.examples = [{
             'Login & Password',
             null,
             [
-              {text: 'Submit', onPress: (details) => console.log('Login: ' + details.login + '; Password: ' + details.password)},
-            ],
-            'login-password'
+              {text: 'Submit', onPress: (details) => console.log('Login: ' + details.login + '; Password: ' + details.password), type: 'login-password'},
+              {text: 'Cancel', onPress: () => console.log('Cancel'), style: 'cancel'}
+            ]
           )}>
 
           <View style={styles.button}>

From 7100df0062ca31ac986a2d6cab051b9f39bc5de7 Mon Sep 17 00:00:00 2001
From: James Ide <ide@jameside.com>
Date: Mon, 4 Jan 2016 15:13:37 -0800
Subject: [PATCH 0590/1411] Move react-transform-hmr dep to "dependencies"

Summary:
It is required from the RN app JS, so it needs to be in prod dependencies.

cc martinbigio
Closes https://github.com/facebook/react-native/pull/5091

Reviewed By: svcscm

Differential Revision: D2798891

Pulled By: martinbigio

fb-gh-sync-id: 976ccf4d96338c8e3d7e457710559be51c4f7405
---
 npm-shrinkwrap.json | 128 ++++++++++++++++++++++----------------------
 package.json        |   4 +-
 2 files changed, 66 insertions(+), 66 deletions(-)

diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index bcab7d34f4a8..c08e18f6a90b 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -1874,16 +1874,16 @@
           "from": "ansi-styles@^2.1.0",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz"
         },
-        "are-we-there-yet": {
-          "version": "1.0.4",
-          "from": "are-we-there-yet@~1.0.0",
-          "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.4.tgz"
-        },
         "asn1": {
           "version": "0.1.11",
           "from": "asn1@0.1.11",
           "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
         },
+        "are-we-there-yet": {
+          "version": "1.0.4",
+          "from": "are-we-there-yet@~1.0.0",
+          "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.4.tgz"
+        },
         "assert-plus": {
           "version": "0.1.5",
           "from": "assert-plus@^0.1.5",
@@ -1914,16 +1914,16 @@
           "from": "boom@^2.8.x",
           "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz"
         },
-        "brace-expansion": {
-          "version": "1.1.1",
-          "from": "brace-expansion@>=1.0.0 <2.0.0",
-          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz"
-        },
         "caseless": {
           "version": "0.11.0",
           "from": "caseless@~0.11.0",
           "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
         },
+        "brace-expansion": {
+          "version": "1.1.1",
+          "from": "brace-expansion@>=1.0.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz"
+        },
         "chalk": {
           "version": "1.1.1",
           "from": "chalk@^1.1.1",
@@ -1944,6 +1944,11 @@
           "from": "concat-map@0.0.1",
           "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
         },
+        "core-util-is": {
+          "version": "1.0.1",
+          "from": "core-util-is@~1.0.0",
+          "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
+        },
         "cryptiles": {
           "version": "2.0.5",
           "from": "cryptiles@2.x.x",
@@ -1954,11 +1959,6 @@
           "from": "ctype@0.5.3",
           "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz"
         },
-        "core-util-is": {
-          "version": "1.0.1",
-          "from": "core-util-is@~1.0.0",
-          "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-        },
         "debug": {
           "version": "0.7.4",
           "from": "debug@~0.7.2",
@@ -2009,11 +2009,6 @@
           "from": "gauge@~1.2.0",
           "resolved": "https://registry.npmjs.org/gauge/-/gauge-1.2.2.tgz"
         },
-        "generate-function": {
-          "version": "2.0.0",
-          "from": "generate-function@^2.0.0",
-          "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz"
-        },
         "generate-object-property": {
           "version": "1.2.0",
           "from": "generate-object-property@^1.1.0",
@@ -2024,16 +2019,21 @@
           "from": "graceful-fs@4.1",
           "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.2.tgz"
         },
-        "graceful-readlink": {
-          "version": "1.0.1",
-          "from": "graceful-readlink@>= 1.0.0",
-          "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
+        "generate-function": {
+          "version": "2.0.0",
+          "from": "generate-function@^2.0.0",
+          "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz"
         },
         "har-validator": {
           "version": "2.0.2",
           "from": "har-validator@~2.0.2",
           "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.2.tgz"
         },
+        "graceful-readlink": {
+          "version": "1.0.1",
+          "from": "graceful-readlink@>= 1.0.0",
+          "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
+        },
         "has-ansi": {
           "version": "2.0.0",
           "from": "has-ansi@^2.0.0",
@@ -2064,16 +2064,16 @@
           "from": "inherits@*",
           "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
         },
-        "is-my-json-valid": {
-          "version": "2.12.2",
-          "from": "is-my-json-valid@^2.12.2",
-          "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.2.tgz"
-        },
         "ini": {
           "version": "1.3.4",
           "from": "ini@~1.3.0",
           "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz"
         },
+        "is-my-json-valid": {
+          "version": "2.12.2",
+          "from": "is-my-json-valid@^2.12.2",
+          "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.2.tgz"
+        },
         "is-property": {
           "version": "1.0.2",
           "from": "is-property@^1.0.0",
@@ -2109,26 +2109,26 @@
           "from": "lodash._createpadding@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash._createpadding/-/lodash._createpadding-3.6.1.tgz"
         },
+        "lodash.pad": {
+          "version": "3.1.1",
+          "from": "lodash.pad@^3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-3.1.1.tgz"
+        },
         "lodash.padleft": {
           "version": "3.1.1",
           "from": "lodash.padleft@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash.padleft/-/lodash.padleft-3.1.1.tgz"
         },
-        "lodash.pad": {
+        "lodash.padright": {
           "version": "3.1.1",
-          "from": "lodash.pad@^3.0.0",
-          "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-3.1.1.tgz"
+          "from": "lodash.padright@^3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash.padright/-/lodash.padright-3.1.1.tgz"
         },
         "lodash.repeat": {
           "version": "3.0.1",
           "from": "lodash.repeat@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash.repeat/-/lodash.repeat-3.0.1.tgz"
         },
-        "lodash.padright": {
-          "version": "3.1.1",
-          "from": "lodash.padright@^3.0.0",
-          "resolved": "https://registry.npmjs.org/lodash.padright/-/lodash.padright-3.1.1.tgz"
-        },
         "mime-db": {
           "version": "1.19.0",
           "from": "mime-db@~1.19.0",
@@ -2149,16 +2149,16 @@
           "from": "mkdirp@>=0.3.0 <0.4.0||>=0.4.0 <0.5.0||>=0.5.0 <0.6.0",
           "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz"
         },
-        "npmlog": {
-          "version": "1.2.1",
-          "from": "npmlog@~1.2.0",
-          "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz"
-        },
         "node-uuid": {
           "version": "1.4.3",
           "from": "node-uuid@~1.4.3",
           "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.3.tgz"
         },
+        "npmlog": {
+          "version": "1.2.1",
+          "from": "npmlog@~1.2.0",
+          "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz"
+        },
         "oauth-sign": {
           "version": "0.8.0",
           "from": "oauth-sign@~0.8.0",
@@ -2174,16 +2174,16 @@
           "from": "path-is-absolute@>=1.0.0 <2.0.0",
           "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz"
         },
-        "pinkie-promise": {
-          "version": "1.0.0",
-          "from": "pinkie-promise@^1.0.0",
-          "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz"
-        },
         "pinkie": {
           "version": "1.0.0",
           "from": "pinkie@^1.0.0",
           "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
         },
+        "pinkie-promise": {
+          "version": "1.0.0",
+          "from": "pinkie-promise@^1.0.0",
+          "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz"
+        },
         "qs": {
           "version": "5.2.0",
           "from": "qs@~5.2.0",
@@ -2219,40 +2219,40 @@
           "from": "stringstream@~0.0.4",
           "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
         },
-        "strip-json-comments": {
-          "version": "0.1.3",
-          "from": "strip-json-comments@0.1.x",
-          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
-        },
         "strip-ansi": {
           "version": "3.0.0",
           "from": "strip-ansi@^3.0.0",
           "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz"
         },
-        "tunnel-agent": {
-          "version": "0.4.1",
-          "from": "tunnel-agent@~0.4.1",
-          "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz"
+        "strip-json-comments": {
+          "version": "0.1.3",
+          "from": "strip-json-comments@0.1.x",
+          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
         },
         "supports-color": {
           "version": "2.0.0",
           "from": "supports-color@^2.0.0",
           "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
         },
-        "uid-number": {
-          "version": "0.0.3",
-          "from": "uid-number@0.0.3",
-          "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.3.tgz"
+        "tar": {
+          "version": "2.2.1",
+          "from": "tar@~2.2.0",
+          "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz"
         },
         "tough-cookie": {
           "version": "2.2.0",
           "from": "tough-cookie@~2.2.0",
           "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.0.tgz"
         },
-        "tar": {
-          "version": "2.2.1",
-          "from": "tar@~2.2.0",
-          "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz"
+        "tunnel-agent": {
+          "version": "0.4.1",
+          "from": "tunnel-agent@~0.4.1",
+          "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz"
+        },
+        "uid-number": {
+          "version": "0.0.3",
+          "from": "uid-number@0.0.3",
+          "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.3.tgz"
         },
         "wrappy": {
           "version": "1.0.1",
diff --git a/package.json b/package.json
index 7e3623a7c75d..ea1449c01bc2 100644
--- a/package.json
+++ b/package.json
@@ -108,6 +108,7 @@
     "promise": "^7.0.4",
     "react": "^0.14.5",
     "react-timer-mixin": "^0.13.2",
+    "react-transform-hmr": "^1.0.1",
     "rebound": "^0.0.13",
     "regenerator": "^0.8.36",
     "sane": "^1.2.0",
@@ -130,7 +131,6 @@
     "eslint-plugin-react": "3.3.1",
     "portfinder": "0.4.0",
     "temp": "0.8.3",
-    "babel-plugin-react-transform": "2.0.0-beta1",
-    "react-transform-hmr": "1.0.1"
+    "babel-plugin-react-transform": "2.0.0-beta1"
   }
 }

From d87d1274020eeb62ff6b9c14f04aaaeef93c9da2 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Mon, 4 Jan 2016 23:36:38 +0000
Subject: [PATCH 0591/1411] [global-cli] Fix npm start

Before releasing new react-native-cli, need to look into
suppressing output from 'npm install', added in
https://github.com/facebook/react-native/commit/5da0e135b6224a2ec9677da3494b8c1e90b06908
---
 react-native-cli/index.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/react-native-cli/index.js b/react-native-cli/index.js
index a3676c379db1..522ec26a005c 100755
--- a/react-native-cli/index.js
+++ b/react-native-cli/index.js
@@ -172,7 +172,7 @@ function createProject(name, verbose) {
     version: '0.0.1',
     private: true,
     scripts: {
-      start: 'react-native start'
+      start: 'node node_modules/react-native/local-cli/cli.js start'
     }
   };
   fs.writeFileSync(path.join(root, 'package.json'), JSON.stringify(packageJson));

From 84adb6c8ccbe796c76fbd9937244c081c12573b8 Mon Sep 17 00:00:00 2001
From: James Ide <ide@jameside.com>
Date: Fri, 30 Oct 2015 12:56:54 -0700
Subject: [PATCH 0592/1411] [Node 5] Run Travis CI tests with Node 5 and npm 3

Updates the Travis CI environment to install Node 5.
---
 .travis.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index d29d91f3bbb8..25221640fccd 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,7 +12,7 @@ install:
   - mkdir -p .nvm
   - export NVM_DIR="$PWD/.nvm"
   - source $(brew --prefix nvm)/nvm.sh
-  - nvm install 4
+  - nvm install 5
   - rm -Rf "${TMPDIR}/jest_preprocess_cache"
   - npm config set spin=false
   - npm install -g flow-bin@`node -p "require('fs').readFileSync('.flowconfig', 'utf8').split('[version]')[1].trim()"`

From 27ac04742ab4665cd529fe63fd68a30db9293b76 Mon Sep 17 00:00:00 2001
From: Ben Alpert <balpert@fb.com>
Date: Mon, 4 Jan 2016 18:58:31 -0800
Subject: [PATCH 0593/1411] Open-source ART for Android

Summary:
This is already open-source on iOS, albeit badly documented. Now Android too!

Tested in open source by adding a `import com.facebook.react.ARTPackage;` and `.addPackage(new ARTPackage())` to UIExplorerActivity.java, running

```
./gradlew :Examples:UIExplorer:android:app:installDebug
```

and copying VectorWidget into the UIExplorer JS code as described in http://browniefed.com/blog/2015/05/03/getting-react-art-running-on-react-native/.

public

Reviewed By: foghina

Differential Revision: D2700481

fb-gh-sync-id: 2a5308b022869ecc1868a46dbecf397581ddbe04
---
 .../react/shell/MainReactPackage.java         |   6 +
 .../react/views/art/ARTGroupShadowNode.java   |  37 +++
 .../views/art/ARTRenderableViewManager.java   |  88 ++++++
 .../react/views/art/ARTShapeShadowNode.java   | 251 ++++++++++++++++++
 .../react/views/art/ARTSurfaceView.java       |  45 ++++
 .../views/art/ARTSurfaceViewManager.java      |  61 +++++
 .../views/art/ARTSurfaceViewShadowNode.java   |  56 ++++
 .../react/views/art/ARTTextShadowNode.java    | 141 ++++++++++
 .../react/views/art/ARTVirtualNode.java       | 114 ++++++++
 .../facebook/react/views/art/PropHelper.java  |  54 ++++
 10 files changed, 853 insertions(+)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/art/ARTGroupShadowNode.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/art/ARTRenderableViewManager.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/art/ARTShapeShadowNode.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceView.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewManager.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewShadowNode.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/art/ARTTextShadowNode.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/art/ARTVirtualNode.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/art/PropHelper.java

diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
index 6cd3e9effca6..e636cd1c08a5 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
@@ -27,6 +27,8 @@
 import com.facebook.react.modules.toast.ToastModule;
 import com.facebook.react.modules.websocket.WebSocketModule;
 import com.facebook.react.uimanager.ViewManager;
+import com.facebook.react.views.art.ARTRenderableViewManager;
+import com.facebook.react.views.art.ARTSurfaceViewManager;
 import com.facebook.react.views.drawer.ReactDrawerLayoutManager;
 import com.facebook.react.views.image.ReactImageManager;
 import com.facebook.react.views.progressbar.ReactProgressBarViewManager;
@@ -74,6 +76,10 @@ public List<Class<? extends JavaScriptModule>> createJSModules() {
   @Override
   public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
     return Arrays.<ViewManager>asList(
+      ARTRenderableViewManager.createARTGroupViewManager(),
+      ARTRenderableViewManager.createARTShapeViewManager(),
+      ARTRenderableViewManager.createARTTextViewManager(),
+      new ARTSurfaceViewManager(),
       new ReactDrawerLayoutManager(),
       new ReactHorizontalScrollViewManager(),
       new ReactImageManager(),
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTGroupShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTGroupShadowNode.java
new file mode 100644
index 000000000000..9586a7b0f88b
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTGroupShadowNode.java
@@ -0,0 +1,37 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.art;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+
+/**
+ * Shadow node for virtual ARTGroup view
+ */
+public class ARTGroupShadowNode extends ARTVirtualNode {
+
+  @Override
+  public boolean isVirtual() {
+    return true;
+  }
+
+  public void draw(Canvas canvas, Paint paint, float opacity) {
+    opacity *= mOpacity;
+    if (opacity > MIN_OPACITY_FOR_DRAW) {
+      saveAndSetupCanvas(canvas);
+      // TODO(6352006): apply clipping (iOS doesn't do it yet, it seems to cause issues)
+      for (int i = 0; i < getChildCount(); i++) {
+        ARTVirtualNode child = (ARTVirtualNode) getChildAt(i);
+        child.draw(canvas, paint, opacity);
+        child.markUpdateSeen();
+      }
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTRenderableViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTRenderableViewManager.java
new file mode 100644
index 000000000000..bd6a7df907c8
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTRenderableViewManager.java
@@ -0,0 +1,88 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.art;
+
+import android.view.View;
+
+import com.facebook.react.uimanager.CatalystStylesDiffMap;
+import com.facebook.react.uimanager.ReactShadowNode;
+import com.facebook.react.uimanager.ThemedReactContext;
+import com.facebook.react.uimanager.ViewManager;
+
+/**
+ * ViewManager for all shadowed ART views: Group, Shape and Text. Since these never get rendered
+ * into native views and don't need any logic (all the logic is in {@link ARTSurfaceView}), this
+ * "stubbed" ViewManager is used for all of them.
+ */
+public class ARTRenderableViewManager extends ViewManager<View, ReactShadowNode> {
+
+  /* package */ static final String CLASS_GROUP = "ARTGroup";
+  /* package */ static final String CLASS_SHAPE = "ARTShape";
+  /* package */ static final String CLASS_TEXT = "ARTText";
+
+  private final String mClassName;
+
+  public static ARTRenderableViewManager createARTGroupViewManager() {
+    return new ARTRenderableViewManager(CLASS_GROUP);
+  }
+
+  public static ARTRenderableViewManager createARTShapeViewManager() {
+    return new ARTRenderableViewManager(CLASS_SHAPE);
+  }
+
+  public static ARTRenderableViewManager createARTTextViewManager() {
+    return new ARTRenderableViewManager(CLASS_TEXT);
+  }
+
+  private ARTRenderableViewManager(String className) {
+    mClassName = className;
+  }
+
+  @Override
+  public String getName() {
+    return mClassName;
+  }
+
+  @Override
+  public ReactShadowNode createShadowNodeInstance() {
+    if (mClassName == CLASS_GROUP) {
+      return new ARTGroupShadowNode();
+    } else if (mClassName == CLASS_SHAPE) {
+      return new ARTShapeShadowNode();
+    } else if (mClassName == CLASS_TEXT) {
+      return new ARTTextShadowNode();
+    } else {
+      throw new IllegalStateException("Unexpected type " + mClassName);
+    }
+  }
+
+  @Override
+  public Class<? extends ReactShadowNode> getShadowNodeClass() {
+    if (mClassName == CLASS_GROUP) {
+      return ARTGroupShadowNode.class;
+    } else if (mClassName == CLASS_SHAPE) {
+      return ARTShapeShadowNode.class;
+    } else if (mClassName == CLASS_TEXT) {
+      return ARTTextShadowNode.class;
+    } else {
+      throw new IllegalStateException("Unexpected type " + mClassName);
+    }
+  }
+
+  @Override
+  protected View createViewInstance(ThemedReactContext reactContext) {
+    throw new IllegalStateException("ARTShape does not map into a native view");
+  }
+
+  @Override
+  public void updateExtraData(View root, Object extraData) {
+    throw new IllegalStateException("ARTShape does not map into a native view");
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTShapeShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTShapeShadowNode.java
new file mode 100644
index 000000000000..76a64f726d5f
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTShapeShadowNode.java
@@ -0,0 +1,251 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.art;
+
+import javax.annotation.Nullable;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.RectF;
+
+import com.facebook.common.logging.FLog;
+import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.common.ReactConstants;
+import com.facebook.react.uimanager.ReactProp;
+
+/**
+ * Shadow node for virtual ARTShape view
+ */
+public class ARTShapeShadowNode extends ARTVirtualNode {
+
+  private static final int CAP_BUTT = 0;
+  private static final int CAP_ROUND = 1;
+  private static final int CAP_SQUARE = 2;
+
+  private static final int JOIN_BEVEL = 2;
+  private static final int JOIN_MITER = 0;
+  private static final int JOIN_ROUND = 1;
+
+  private static final int PATH_TYPE_ARC = 4;
+  private static final int PATH_TYPE_CLOSE = 1;
+  private static final int PATH_TYPE_CURVETO = 3;
+  private static final int PATH_TYPE_LINETO = 2;
+  private static final int PATH_TYPE_MOVETO = 0;
+
+  protected @Nullable Path mPath;
+  private @Nullable float[] mStrokeColor;
+  private @Nullable float[] mFillColor;
+  private @Nullable float[] mStrokeDash;
+  private float mStrokeWidth = 1;
+  private int mStrokeCap = CAP_ROUND;
+  private int mStrokeJoin = JOIN_ROUND;
+
+  @ReactProp(name = "d")
+  public void setShapePath(@Nullable ReadableArray shapePath) {
+    float[] pathData = PropHelper.toFloatArray(shapePath);
+    mPath = createPath(pathData);
+    markUpdated();
+  }
+
+  @ReactProp(name = "stroke")
+  public void setStroke(@Nullable ReadableArray strokeColors) {
+    mStrokeColor = PropHelper.toFloatArray(strokeColors);
+    markUpdated();
+  }
+
+  @ReactProp(name = "strokeDash")
+  public void setStrokeDash(@Nullable ReadableArray strokeDash) {
+    mStrokeDash = PropHelper.toFloatArray(strokeDash);
+    markUpdated();
+  }
+
+  @ReactProp(name = "fill")
+  public void setFill(@Nullable ReadableArray fillColors) {
+    mFillColor = PropHelper.toFloatArray(fillColors);
+    markUpdated();
+  }
+
+  @ReactProp(name = "strokeWidth", defaultFloat = 1f)
+  public void setStrokeWidth(float strokeWidth) {
+    mStrokeWidth = strokeWidth;
+    markUpdated();
+  }
+
+  @ReactProp(name = "strokeCap", defaultInt = CAP_ROUND)
+  public void setStrokeCap(int strokeCap) {
+    mStrokeCap = strokeCap;
+    markUpdated();
+  }
+
+  @ReactProp(name = "strokeJoin", defaultInt = JOIN_ROUND)
+  public void setStrokeJoin(int strokeJoin) {
+    mStrokeJoin = strokeJoin;
+    markUpdated();
+  }
+
+  @Override
+  public void draw(Canvas canvas, Paint paint, float opacity) {
+    opacity *= mOpacity;
+    if (opacity > MIN_OPACITY_FOR_DRAW) {
+      saveAndSetupCanvas(canvas);
+      if (mPath == null) {
+        throw new JSApplicationIllegalArgumentException(
+            "Shapes should have a valid path (d) prop");
+      }
+      if (setupStrokePaint(paint, opacity)) {
+        canvas.drawPath(mPath, paint);
+      }
+      if (setupFillPaint(paint, opacity)) {
+        canvas.drawPath(mPath, paint);
+      }
+      restoreCanvas(canvas);
+    }
+    markUpdateSeen();
+  }
+
+  /**
+   * Sets up {@link #mPaint} according to the props set on a shadow view. Returns {@code true}
+   * if the stroke should be drawn, {@code false} if not.
+   */
+  protected boolean setupStrokePaint(Paint paint, float opacity) {
+    if (mStrokeWidth == 0 || mStrokeColor == null || mStrokeColor.length == 0) {
+      return false;
+    }
+    paint.reset();
+    paint.setFlags(Paint.ANTI_ALIAS_FLAG);
+    paint.setStyle(Paint.Style.STROKE);
+    switch (mStrokeCap) {
+      case CAP_BUTT:
+        paint.setStrokeCap(Paint.Cap.BUTT);
+        break;
+      case CAP_SQUARE:
+        paint.setStrokeCap(Paint.Cap.SQUARE);
+        break;
+      case CAP_ROUND:
+        paint.setStrokeCap(Paint.Cap.ROUND);
+        break;
+      default:
+        throw new JSApplicationIllegalArgumentException(
+            "strokeCap " + mStrokeCap + " unrecognized");
+    }
+    switch (mStrokeJoin) {
+      case JOIN_MITER:
+        paint.setStrokeJoin(Paint.Join.MITER);
+        break;
+      case JOIN_BEVEL:
+        paint.setStrokeJoin(Paint.Join.BEVEL);
+        break;
+      case JOIN_ROUND:
+        paint.setStrokeJoin(Paint.Join.ROUND);
+        break;
+      default:
+        throw new JSApplicationIllegalArgumentException(
+            "strokeJoin " + mStrokeJoin + " unrecognized");
+    }
+    paint.setStrokeWidth(mStrokeWidth * mScale);
+    paint.setARGB(
+        (int) (mStrokeColor.length > 3 ? mStrokeColor[3] * opacity * 255 : opacity * 255),
+        (int) (mStrokeColor[0] * 255),
+        (int) (mStrokeColor[1] * 255),
+        (int) (mStrokeColor[2] * 255));
+    if (mStrokeDash != null && mStrokeDash.length > 0) {
+      // TODO(6352067): Support dashes
+      FLog.w(ReactConstants.TAG, "ART: Dashes are not supported yet!");
+    }
+    return true;
+  }
+
+  /**
+   * Sets up {@link #mPaint} according to the props set on a shadow view. Returns {@code true}
+   * if the fill should be drawn, {@code false} if not.
+   */
+  protected boolean setupFillPaint(Paint paint, float opacity) {
+    if (mFillColor != null && mFillColor.length > 0) {
+      paint.reset();
+      paint.setFlags(Paint.ANTI_ALIAS_FLAG);
+      paint.setStyle(Paint.Style.FILL);
+      int colorType = (int) mFillColor[0];
+      switch (colorType) {
+        case 0:
+          paint.setARGB(
+              (int) (mFillColor.length > 4 ? mFillColor[4] * opacity * 255 : opacity * 255),
+              (int) (mFillColor[1] * 255),
+              (int) (mFillColor[2] * 255),
+              (int) (mFillColor[3] * 255));
+          break;
+        default:
+          // TODO(6352048): Support gradients etc.
+          FLog.w(ReactConstants.TAG, "ART: Color type " + colorType + " not supported!");
+      }
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * Creates a {@link Path} from an array of instructions constructed by JS
+   * (see ARTSerializablePath.js). Each instruction starts with a type (see PATH_TYPE_*) followed
+   * by arguments for that instruction. For example, to create a line the instruction will be
+   * 2 (PATH_LINE_TO), x, y. This will draw a line from the last draw point (or 0,0) to x,y.
+   *
+   * @param data the array of instructions
+   * @return the {@link Path} that can be drawn to a canvas
+   */
+  private Path createPath(float[] data) {
+    Path path = new Path();
+    path.moveTo(0, 0);
+    int i = 0;
+    while (i < data.length) {
+      int type = (int) data[i++];
+      switch (type) {
+        case PATH_TYPE_MOVETO:
+          path.moveTo(data[i++] * mScale, data[i++] * mScale);
+          break;
+        case PATH_TYPE_CLOSE:
+          path.close();
+          break;
+        case PATH_TYPE_LINETO:
+          path.lineTo(data[i++] * mScale, data[i++] * mScale);
+          break;
+        case PATH_TYPE_CURVETO:
+          path.cubicTo(
+              data[i++] * mScale,
+              data[i++] * mScale,
+              data[i++] * mScale,
+              data[i++] * mScale,
+              data[i++] * mScale,
+              data[i++] * mScale);
+          break;
+        case PATH_TYPE_ARC:
+        {
+          float x = data[i++] * mScale;
+          float y = data[i++] * mScale;
+          float r = data[i++] * mScale;
+          float start = (float) Math.toDegrees(data[i++]);
+          float end = (float) Math.toDegrees(data[i++]);
+          boolean clockwise = data[i++] == 0f;
+          if (!clockwise) {
+            end = 360 - end;
+          }
+          float sweep = start - end;
+          RectF oval = new RectF(x - r, y - r, x + r, y + r);
+          path.addArc(oval, start, sweep);
+          break;
+        }
+        default:
+          throw new JSApplicationIllegalArgumentException(
+              "Unrecognized drawing instruction " + type);
+      }
+    }
+    return path;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceView.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceView.java
new file mode 100644
index 000000000000..42aecf3927e1
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceView.java
@@ -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.
+ */
+
+package com.facebook.react.views.art;
+
+import javax.annotation.Nullable;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.view.View;
+
+/**
+ * Custom {@link View} implementation that draws an ARTSurface React view and its children.
+ */
+public class ARTSurfaceView extends View {
+
+  private @Nullable Bitmap mBitmap;
+
+  public ARTSurfaceView(Context context) {
+    super(context);
+  }
+
+  public void setBitmap(Bitmap bitmap) {
+    if (mBitmap != null) {
+      mBitmap.recycle();
+    }
+    mBitmap = bitmap;
+    invalidate();
+  }
+
+  @Override
+  protected void onDraw(Canvas canvas) {
+    super.onDraw(canvas);
+    if (mBitmap != null) {
+      canvas.drawBitmap(mBitmap, 0, 0, null);
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewManager.java
new file mode 100644
index 000000000000..98fc5293b54d
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewManager.java
@@ -0,0 +1,61 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.art;
+
+import android.graphics.Bitmap;
+
+import com.facebook.csslayout.CSSNode;
+import com.facebook.csslayout.MeasureOutput;
+import com.facebook.react.uimanager.BaseViewManager;
+import com.facebook.react.uimanager.ThemedReactContext;
+
+/**
+ * ViewManager for ARTSurfaceView React views. Renders as a {@link ARTSurfaceView} and handles
+ * invalidating the native view on shadow view updates happening in the underlying tree.
+ */
+public class ARTSurfaceViewManager extends
+    BaseViewManager<ARTSurfaceView, ARTSurfaceViewShadowNode> {
+
+  private static final String REACT_CLASS = "ARTSurfaceView";
+
+  private static final CSSNode.MeasureFunction MEASURE_FUNCTION = new CSSNode.MeasureFunction() {
+    @Override
+    public void measure(CSSNode node, float width, float height, MeasureOutput measureOutput) {
+      throw new IllegalStateException("SurfaceView should have explicit width and height set");
+    }
+  };
+
+  @Override
+  public String getName() {
+    return REACT_CLASS;
+  }
+
+  @Override
+  public ARTSurfaceViewShadowNode createShadowNodeInstance() {
+    ARTSurfaceViewShadowNode node = new ARTSurfaceViewShadowNode();
+    node.setMeasureFunction(MEASURE_FUNCTION);
+    return node;
+  }
+
+  @Override
+  public Class<ARTSurfaceViewShadowNode> getShadowNodeClass() {
+    return ARTSurfaceViewShadowNode.class;
+  }
+
+  @Override
+  protected ARTSurfaceView createViewInstance(ThemedReactContext reactContext) {
+    return new ARTSurfaceView(reactContext);
+  }
+
+  @Override
+  public void updateExtraData(ARTSurfaceView root, Object extraData) {
+    root.setBitmap((Bitmap) extraData);
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewShadowNode.java
new file mode 100644
index 000000000000..b6004efa88b2
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTSurfaceViewShadowNode.java
@@ -0,0 +1,56 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.art;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+
+import com.facebook.react.uimanager.LayoutShadowNode;
+import com.facebook.react.uimanager.UIViewOperationQueue;
+
+/**
+ * Shadow node for ART virtual tree root - ARTSurfaceView
+ */
+public class ARTSurfaceViewShadowNode extends LayoutShadowNode {
+
+  @Override
+  public boolean isVirtual() {
+    return false;
+  }
+
+  @Override
+  public boolean isVirtualAnchor() {
+    return true;
+  }
+
+  @Override
+  public void onCollectExtraUpdates(UIViewOperationQueue uiUpdater) {
+    super.onCollectExtraUpdates(uiUpdater);
+    uiUpdater.enqueueUpdateExtraData(getReactTag(), drawOutput());
+  }
+
+  private Object drawOutput() {
+    // TODO(7255985): Use TextureView and pass Surface from the view to draw on it asynchronously
+    // instead of passing the bitmap (which is inefficient especially in terms of memory usage)
+    Bitmap bitmap = Bitmap.createBitmap(
+        (int) getLayoutWidth(),
+        (int) getLayoutHeight(),
+        Bitmap.Config.ARGB_8888);
+    Canvas canvas = new Canvas(bitmap);
+    Paint paint = new Paint();
+    for (int i = 0; i < getChildCount(); i++) {
+      ARTVirtualNode child = (ARTVirtualNode) getChildAt(i);
+      child.draw(canvas, paint, 1f);
+      child.markUpdateSeen();
+    }
+    return bitmap;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTTextShadowNode.java
new file mode 100644
index 000000000000..80be1a729f57
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTTextShadowNode.java
@@ -0,0 +1,141 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.art;
+
+import javax.annotation.Nullable;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.text.TextUtils;
+
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.uimanager.ReactProp;
+
+/**
+ * Shadow node for virtual ARTText view
+ */
+public class ARTTextShadowNode extends ARTShapeShadowNode {
+
+  private static final String PROP_LINES = "lines";
+
+  private static final String PROP_FONT = "font";
+  private static final String PROP_FONT_FAMILY = "fontFamily";
+  private static final String PROP_FONT_SIZE = "fontSize";
+  private static final String PROP_FONT_STYLE = "fontStyle";
+  private static final String PROP_FONT_WEIGHT = "fontWeight";
+
+  private static final int DEFAULT_FONT_SIZE = 12;
+
+  private static final int TEXT_ALIGNMENT_CENTER = 2;
+  private static final int TEXT_ALIGNMENT_LEFT = 0;
+  private static final int TEXT_ALIGNMENT_RIGHT = 1;
+
+  private @Nullable ReadableMap mFrame;
+  private int mTextAlignment = TEXT_ALIGNMENT_LEFT;
+
+  @ReactProp(name = "frame")
+  public void setFrame(@Nullable ReadableMap frame) {
+    mFrame = frame;
+  }
+
+  @ReactProp(name = "alignment", defaultInt = TEXT_ALIGNMENT_LEFT)
+  public void setAlignment(int alignment) {
+    mTextAlignment = alignment;
+  }
+
+  @Override
+  public void draw(Canvas canvas, Paint paint, float opacity) {
+    if (mFrame == null) {
+      return;
+    }
+    opacity *= mOpacity;
+    if (opacity <= MIN_OPACITY_FOR_DRAW) {
+      return;
+    }
+    if (!mFrame.hasKey(PROP_LINES)) {
+      return;
+    }
+    ReadableArray linesProp = mFrame.getArray(PROP_LINES);
+    if (linesProp == null || linesProp.size() == 0) {
+      return;
+    }
+
+    // only set up the canvas if we have something to draw
+    saveAndSetupCanvas(canvas);
+    String[] lines = new String[linesProp.size()];
+    for (int i = 0; i < lines.length; i++) {
+      lines[i] = linesProp.getString(i);
+    }
+    String text = TextUtils.join("\n", lines);
+    if (setupStrokePaint(paint, opacity)) {
+      applyTextPropertiesToPaint(paint);
+      if (mPath == null) {
+        canvas.drawText(text, 0, -paint.ascent(), paint);
+      } else {
+        canvas.drawTextOnPath(text, mPath, 0, 0, paint);
+      }
+    }
+    if (setupFillPaint(paint, opacity)) {
+      applyTextPropertiesToPaint(paint);
+      if (mPath == null) {
+        canvas.drawText(text, 0, -paint.ascent(), paint);
+      } else {
+        canvas.drawTextOnPath(text, mPath, 0, 0, paint);
+      }
+    }
+    restoreCanvas(canvas);
+    markUpdateSeen();
+  }
+
+  private void applyTextPropertiesToPaint(Paint paint) {
+    int alignment = mTextAlignment;
+    switch (alignment) {
+      case TEXT_ALIGNMENT_LEFT:
+        paint.setTextAlign(Paint.Align.LEFT);
+        break;
+      case TEXT_ALIGNMENT_RIGHT:
+        paint.setTextAlign(Paint.Align.RIGHT);
+        break;
+      case TEXT_ALIGNMENT_CENTER:
+        paint.setTextAlign(Paint.Align.CENTER);
+        break;
+    }
+    if (mFrame != null) {
+      if (mFrame.hasKey(PROP_FONT)) {
+        ReadableMap font = mFrame.getMap(PROP_FONT);
+        if (font != null) {
+          float fontSize = DEFAULT_FONT_SIZE;
+          if (font.hasKey(PROP_FONT_SIZE)) {
+            fontSize = (float) font.getDouble(PROP_FONT_SIZE);
+          }
+          paint.setTextSize(fontSize * mScale);
+          boolean isBold =
+              font.hasKey(PROP_FONT_WEIGHT) && "bold".equals(font.getString(PROP_FONT_WEIGHT));
+          boolean isItalic =
+              font.hasKey(PROP_FONT_STYLE) && "italic".equals(font.getString(PROP_FONT_STYLE));
+          int fontStyle;
+          if (isBold && isItalic) {
+            fontStyle = Typeface.BOLD_ITALIC;
+          } else if (isBold) {
+            fontStyle = Typeface.BOLD;
+          } else if (isItalic) {
+            fontStyle = Typeface.ITALIC;
+          } else {
+            fontStyle = Typeface.NORMAL;
+          }
+          // NB: if the font family is null / unsupported, the default one will be used
+          paint.setTypeface(Typeface.create(font.getString(PROP_FONT_FAMILY), fontStyle));
+        }
+      }
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTVirtualNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTVirtualNode.java
new file mode 100644
index 000000000000..b894e984594e
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTVirtualNode.java
@@ -0,0 +1,114 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.art;
+
+import javax.annotation.Nullable;
+
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+
+import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.uimanager.CatalystStylesDiffMap;
+import com.facebook.react.uimanager.DisplayMetricsHolder;
+import com.facebook.react.uimanager.ReactProp;
+import com.facebook.react.uimanager.ReactShadowNode;
+
+/**
+ * Base class for ARTView virtual nodes: {@link ARTGroupShadowNode}, {@link ARTShapeShadowNode} and
+ * indirectly for {@link ARTTextShadowNode}.
+ */
+public abstract class ARTVirtualNode extends ReactShadowNode {
+
+  protected static final float MIN_OPACITY_FOR_DRAW = 0.01f;
+
+  private static final float[] sMatrixData = new float[9];
+  private static final float[] sRawMatrix = new float[9];
+
+  protected float mOpacity = 1f;
+  private @Nullable Matrix mMatrix = new Matrix();
+
+  protected final float mScale;
+
+  public ARTVirtualNode() {
+    mScale = DisplayMetricsHolder.getDisplayMetrics().density;
+  }
+
+  @Override
+  public boolean isVirtual() {
+    return true;
+  }
+
+  public abstract void draw(Canvas canvas, Paint paint, float opacity);
+
+  /**
+   * Sets up the transform matrix on the canvas before an element is drawn.
+   *
+   * NB: for perf reasons this does not apply opacity, as that would mean creating a new canvas
+   * layer (which allocates an offscreen bitmap) and having it composited afterwards. Instead, the
+   * drawing code should apply opacity recursively.
+   *
+   * @param canvas the canvas to set up
+   */
+  protected final void saveAndSetupCanvas(Canvas canvas) {
+    canvas.save();
+    if (mMatrix != null) {
+      canvas.concat(mMatrix);
+    }
+  }
+
+  /**
+   * Restore the canvas after an element was drawn. This is always called in mirror with
+   * {@link #saveAndSetupCanvas}.
+   *
+   * @param canvas the canvas to restore
+   */
+  protected void restoreCanvas(Canvas canvas) {
+    canvas.restore();
+  }
+
+  @ReactProp(name = "opacity", defaultFloat = 1f)
+  public void setOpacity(float opacity) {
+    mOpacity = opacity;
+    markUpdated();
+  }
+
+  @ReactProp(name = "transform")
+  public void setTransform(@Nullable ReadableArray transformArray) {
+    if (transformArray != null) {
+      int matrixSize = PropHelper.toFloatArray(transformArray, sMatrixData);
+      if (matrixSize == 6) {
+        setupMatrix();
+      } else if (matrixSize != -1) {
+        throw new JSApplicationIllegalArgumentException("Transform matrices must be of size 6");
+      }
+    } else {
+      mMatrix = null;
+    }
+    markUpdated();
+  }
+
+  protected void setupMatrix() {
+    sRawMatrix[0] = sMatrixData[0];
+    sRawMatrix[1] = sMatrixData[2];
+    sRawMatrix[2] = sMatrixData[4] * mScale;
+    sRawMatrix[3] = sMatrixData[1];
+    sRawMatrix[4] = sMatrixData[3];
+    sRawMatrix[5] = sMatrixData[5] * mScale;
+    sRawMatrix[6] = 0;
+    sRawMatrix[7] = 0;
+    sRawMatrix[8] = 1;
+    if (mMatrix == null) {
+      mMatrix = new Matrix();
+    }
+    mMatrix.setValues(sRawMatrix);
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/PropHelper.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/PropHelper.java
new file mode 100644
index 000000000000..b8bc6246a12e
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/PropHelper.java
@@ -0,0 +1,54 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.art;
+
+import javax.annotation.Nullable;
+
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.uimanager.CatalystStylesDiffMap;
+
+/**
+ * Contains static helper methods for accessing props.
+ */
+/* package */ class PropHelper {
+
+  /**
+   * Converts {@link ReadableArray} to an array of {@code float}. Returns newly created array.
+   *
+   * @return a {@code float[]} if converted successfully, or {@code null} if {@param value} was
+   * {@code null}.
+   */
+  /*package*/ static @Nullable float[] toFloatArray(@Nullable ReadableArray value) {
+    if (value != null) {
+      float[] result = new float[value.size()];
+      toFloatArray(value, result);
+      return result;
+    }
+    return null;
+  }
+
+  /**
+   * Converts given {@link ReadableArray} to an array of {@code float}. Writes result to the array
+   * passed in {@param into}. This method will write to the output array up to the number of items
+   * from the input array. If the input array is longer than output the remaining part of the input
+   * will not be converted.
+   *
+   * @param value input array
+   * @param into output array
+   * @return number of items copied from input to the output array
+   */
+  /*package*/ static int toFloatArray(ReadableArray value, float[] into) {
+    int length = value.size() > into.length ? into.length : value.size();
+    for (int i = 0; i < length; i++) {
+      into[i] = (float) value.getDouble(i);
+    }
+    return value.size();
+  }
+}

From 18cdead76bb76fa3faa81975f55c89a52da0970a Mon Sep 17 00:00:00 2001
From: Fada Chen <chenfada@fb.com>
Date: Mon, 4 Jan 2016 23:48:33 -0800
Subject: [PATCH 0594/1411] revert D2773664

Reviewed By: dwitte

Differential Revision: D2802582

fb-gh-sync-id: 39d59be297f0f23e6a4e40175ad30284766349cb
---
 React/Base/RCTBatchedBridge.m    | 29 ++++-------------------------
 React/Base/RCTBridge+Private.h   |  4 ----
 React/Executors/RCTJSCExecutor.m | 14 --------------
 React/Profiler/RCTProfile.h      |  2 +-
 4 files changed, 5 insertions(+), 44 deletions(-)

diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index 8ec30748cbc9..65db384323a5 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -35,8 +35,7 @@
 typedef NS_ENUM(NSUInteger, RCTBridgeFields) {
   RCTBridgeFieldRequestModuleIDs = 0,
   RCTBridgeFieldMethodIDs,
-  RCTBridgeFieldParams,
-  RCTBridgeFieldCallID,
+  RCTBridgeFieldParamss,
 };
 
 RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
@@ -66,9 +65,6 @@ @implementation RCTBatchedBridge
   NSUInteger _asyncInitializedModules;
 }
 
-@synthesize flowID = _flowID;
-@synthesize flowIDMap = _flowIDMap;
-
 - (instancetype)initWithParentBridge:(RCTBridge *)bridge
 {
   RCTAssertMainThread();
@@ -595,9 +591,6 @@ - (void)invalidate
       _modulesByName_DEPRECATED = nil;
       _frameUpdateObservers = nil;
 
-      if (_flowIDMap != NULL) {
-        CFRelease(_flowIDMap);
-      }
     }];
   });
 }
@@ -800,22 +793,15 @@ - (void)handleBuffer:(id)buffer batchEnded:(BOOL)batchEnded
 - (void)handleBuffer:(NSArray *)buffer
 {
   NSArray *requestsArray = [RCTConvert NSArray:buffer];
-
-  if (RCT_DEBUG && requestsArray.count <= RCTBridgeFieldParams) {
+  if (RCT_DEBUG && requestsArray.count <= RCTBridgeFieldParamss) {
     RCTLogError(@"Buffer should contain at least %tu sub-arrays. Only found %tu",
-                RCTBridgeFieldParams + 1, requestsArray.count);
+              RCTBridgeFieldParamss + 1, requestsArray.count);
     return;
   }
 
   NSArray<NSNumber *> *moduleIDs = [RCTConvert NSNumberArray:requestsArray[RCTBridgeFieldRequestModuleIDs]];
   NSArray<NSNumber *> *methodIDs = [RCTConvert NSNumberArray:requestsArray[RCTBridgeFieldMethodIDs]];
-  NSArray<NSArray *> *paramsArrays = [RCTConvert NSArrayArray:requestsArray[RCTBridgeFieldParams]];
-
-  int64_t callID = -1;
-
-  if (requestsArray.count > 3) {
-    callID = [requestsArray[RCTBridgeFieldCallID] longLongValue];
-  }
+  NSArray<NSArray *> *paramsArrays = [RCTConvert NSArrayArray:requestsArray[RCTBridgeFieldParamss]];
 
   if (RCT_DEBUG && (moduleIDs.count != methodIDs.count || moduleIDs.count != paramsArrays.count)) {
     RCTLogError(@"Invalid data message - all must be length: %zd", moduleIDs.count);
@@ -849,11 +835,6 @@ - (void)handleBuffer:(NSArray *)buffer
       @autoreleasepool {
         for (NSNumber *indexObj in calls) {
           NSUInteger index = indexObj.unsignedIntegerValue;
-          if (callID != -1) {
-            int64_t newFlowID = (int64_t)CFDictionaryGetValue(_flowIDMap, (const void *)(_flowID + index));
-            _RCTProfileEndFlowEvent(@(newFlowID));
-            CFDictionaryRemoveValue(_flowIDMap, (const void *)(_flowID + index));
-          }
           [self _handleRequestNumber:index
                             moduleID:[moduleIDs[index] integerValue]
                             methodID:[methodIDs[index] integerValue]
@@ -872,8 +853,6 @@ - (void)handleBuffer:(NSArray *)buffer
       dispatch_async(queue, block);
     }
   }
-
-  _flowID = callID;
 }
 
 - (void)partialBatchDidFlush
diff --git a/React/Base/RCTBridge+Private.h b/React/Base/RCTBridge+Private.h
index 649771656877..91675efa5943 100644
--- a/React/Base/RCTBridge+Private.h
+++ b/React/Base/RCTBridge+Private.h
@@ -13,10 +13,6 @@
 
 @interface RCTBridge ()
 
-// Used for the profiler flow events between JS and native
-@property (nonatomic, assign) int64_t flowID;
-@property (nonatomic, assign) CFMutableDictionaryRef flowIDMap;
-
 + (instancetype)currentBridge;
 + (void)setCurrentBridge:(RCTBridge *)bridge;
 
diff --git a/React/Executors/RCTJSCExecutor.m b/React/Executors/RCTJSCExecutor.m
index 25ed23e21344..a586fd07e079 100644
--- a/React/Executors/RCTJSCExecutor.m
+++ b/React/Executors/RCTJSCExecutor.m
@@ -283,20 +283,6 @@ - (void)setUp
       CFDictionaryRemoveValue(cookieMap, (const void *)cookie);
     };
 
-#ifndef __clang_analyzer__
-    weakBridge.flowIDMap = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
-#endif
-    context[@"nativeTraceBeginAsyncFlow"] = ^(__unused uint64_t tag, __unused NSString *name, int64_t cookie) {
-      int64_t newCookie = [_RCTProfileBeginFlowEvent() longLongValue];
-      CFDictionarySetValue(weakBridge.flowIDMap, (const void *)cookie, (const void *)newCookie);
-    };
-
-    context[@"nativeTraceEndAsyncFlow"] = ^(__unused uint64_t tag, __unused NSString *name, int64_t cookie) {
-      int64_t newCookie = (int64_t)CFDictionaryGetValue(weakBridge.flowIDMap, (const void *)cookie);
-      _RCTProfileEndFlowEvent(@(newCookie));
-      CFDictionaryRemoveValue(weakBridge.flowIDMap, (const void *)cookie);
-    };
-
     context[@"nativeTraceBeginSection"] = ^(NSNumber *tag, NSString *profileName){
       static int profileCounter = 1;
       if (!profileName) {
diff --git a/React/Profiler/RCTProfile.h b/React/Profiler/RCTProfile.h
index 7b888dc6a955..1cd721ab7cd2 100644
--- a/React/Profiler/RCTProfile.h
+++ b/React/Profiler/RCTProfile.h
@@ -190,7 +190,7 @@ RCT_EXTERN void RCTProfileRegisterCallbacks(RCTProfileCallbacks *);
 #define _RCTProfileBeginFlowEvent() @0
 
 #define RCTProfileEndFlowEvent()
-#define _RCTProfileEndFlowEvent(...)
+#define _RCTProfileEndFlowEvent()
 
 #define RCTProfileIsProfiling(...) NO
 #define RCTProfileInit(...)

From ee82bad3f7fe8fe692ea85d95d4388a5e690fbc5 Mon Sep 17 00:00:00 2001
From: Fada Chen <chenfada@fb.com>
Date: Tue, 5 Jan 2016 00:40:54 -0800
Subject: [PATCH 0595/1411] revert D2779079

Reviewed By: zjj010104

Differential Revision: D2802728

fb-gh-sync-id: 9e09f00d1d7facd2091fe60eee8565c4bf599b1d
---
 .../react/ReactInstanceManagerImpl.java       |  5 ---
 .../react/common/ApplicationHolder.java       | 36 -------------------
 .../src/main/jni/react/jni/JSLoader.cpp       | 26 +-------------
 .../src/main/jni/react/jni/JSLoader.h         |  8 -----
 .../src/main/jni/react/jni/OnLoad.cpp         |  1 -
 5 files changed, 1 insertion(+), 75 deletions(-)
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/common/ApplicationHolder.java

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index ad10a6e7c68e..0baef21f20d6 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -17,7 +17,6 @@
 import java.util.concurrent.ConcurrentLinkedQueue;
 
 import android.app.Activity;
-import android.app.Application;
 import android.content.Context;
 import android.content.Intent;
 import android.os.AsyncTask;
@@ -47,7 +46,6 @@
 import com.facebook.react.bridge.WritableMap;
 import com.facebook.react.bridge.WritableNativeMap;
 import com.facebook.react.bridge.queue.CatalystQueueConfigurationSpec;
-import com.facebook.react.common.ApplicationHolder;
 import com.facebook.react.common.ReactConstants;
 import com.facebook.react.common.annotations.VisibleForTesting;
 import com.facebook.react.devsupport.DevServerHelper;
@@ -204,9 +202,6 @@ protected void onPostExecute(ReactApplicationContext reactContext) {
       NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
     initializeSoLoaderIfNecessary(applicationContext);
 
-    // TODO(9577825): remove this
-    ApplicationHolder.setApplication((Application) applicationContext.getApplicationContext());
-
     mApplicationContext = applicationContext;
     mJSBundleFile = jsBundleFile;
     mJSMainModuleName = jsMainModuleName;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/common/ApplicationHolder.java b/ReactAndroid/src/main/java/com/facebook/react/common/ApplicationHolder.java
deleted file mode 100644
index 535b81597c8a..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/common/ApplicationHolder.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * 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.
- */
-
-package com.facebook.react.common;
-
-import android.app.Application;
-
-import com.facebook.infer.annotation.Assertions;
-import com.facebook.proguard.annotations.DoNotStrip;
-
-/**
- * Holds the current Application Object.
- *
- * TODO(9577825): This is a bad pattern, we should thread through an Environment object instead.
- * Remove once bridge is unforked.
- */
-@DoNotStrip
-@Deprecated
-public class ApplicationHolder {
-
-  private static Application sApplication;
-
-  public static void setApplication(Application application) {
-    sApplication = application;
-  }
-
-  public static Application getApplication() {
-    return Assertions.assertNotNull(sApplication);
-  }
-}
diff --git a/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp b/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp
index db8b4d980e63..416640a371de 100644
--- a/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp
@@ -4,7 +4,6 @@
 
 #include <android/asset_manager.h>
 #include <android/asset_manager_jni.h>
-#include <jni/Environment.h>
 #include <fstream>
 #include <sstream>
 #include <streambuf>
@@ -19,19 +18,6 @@ using fbsystrace::FbSystraceSection;
 namespace facebook {
 namespace react {
 
-static jclass gApplicationHolderClass;
-static jmethodID gGetApplicationMethod;
-static jmethodID gGetAssetManagerMethod;
-
-std::string loadScriptFromAssets(std::string assetName) {
-  JNIEnv *env = jni::Environment::current();
-  jobject application = env->CallStaticObjectMethod(
-    gApplicationHolderClass,
-    gGetApplicationMethod);
-  jobject assetManager = env->CallObjectMethod(application, gGetAssetManagerMethod);
-  return loadScriptFromAssets(env, assetManager, assetName);
-}
-
 std::string loadScriptFromAssets(
     JNIEnv *env,
     jobject assetManager,
@@ -85,14 +71,4 @@ std::string loadScriptFromFile(std::string fileName) {
   return "";
 }
 
-void registerJSLoaderNatives() {
-  JNIEnv *env = jni::Environment::current();
-  jclass applicationHolderClass = env->FindClass("com/facebook/react/common/ApplicationHolder");
-  gApplicationHolderClass = (jclass)env->NewGlobalRef(applicationHolderClass);
-  gGetApplicationMethod = env->GetStaticMethodID(applicationHolderClass, "getApplication", "()Landroid/app/Application;");
-  
-  jclass appClass = env->FindClass("android/app/Application");
-  gGetAssetManagerMethod = env->GetMethodID(appClass, "getAssets", "()Landroid/content/res/AssetManager;");
-}
-
-} }
+} }
\ No newline at end of file
diff --git a/ReactAndroid/src/main/jni/react/jni/JSLoader.h b/ReactAndroid/src/main/jni/react/jni/JSLoader.h
index 25dab510d7a2..c7381fe7e8f7 100644
--- a/ReactAndroid/src/main/jni/react/jni/JSLoader.h
+++ b/ReactAndroid/src/main/jni/react/jni/JSLoader.h
@@ -8,12 +8,6 @@
 namespace facebook {
 namespace react {
 
-/**
- * Helper method for loading a JS script from Android assets without
- * a reference to an AssetManager.
- */
-std::string loadScriptFromAssets(std::string assetName);
-
 /**
  * Helper method for loading JS script from android asset
  */
@@ -24,6 +18,4 @@ std::string loadScriptFromAssets(JNIEnv *env, jobject assetManager, std::string
  */
 std::string loadScriptFromFile(std::string fileName);
 
-void registerJSLoaderNatives();
-
 } }
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 6eb6d523e343..5ef5c28aaba5 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -780,7 +780,6 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
     NativeArray::registerNatives();
     ReadableNativeArray::registerNatives();
     WritableNativeArray::registerNatives();
-    registerJSLoaderNatives();
 
     registerNatives("com/facebook/react/bridge/NativeMap", {
         makeNativeMethod("initialize", map::initialize),

From 1dc5dca604c9973179e137f226418ca89e28b58a Mon Sep 17 00:00:00 2001
From: Michelle Todd <michelle@khanacademy.org>
Date: Tue, 5 Jan 2016 02:42:18 -0800
Subject: [PATCH 0596/1411] Rename methods in RCTPushNotificationManager so app
 store doesn't warn

Summary:
Including RCTPushNotificationManager is required for local notifications, which don't require a Push Notifications entitlement on your provisioning profile. However, if you don't have the entitlement, the app store warns you when you push an app build that contains `application:didRegisterForRemoteNotificationsWithDeviceToken:`, even if it isn't being called. This renames the methods so they have different names from the ones on UIApplication so the app store doesn't warn about them.
Closes https://github.com/facebook/react-native/pull/4897

Reviewed By: spicyj

Differential Revision: D2780533

Pulled By: nicklockwood

fb-gh-sync-id: 1a688f1ebd3cc9f86ba340ce453fdbfb46949839
---
 Libraries/PushNotificationIOS/PushNotificationIOS.js  | 11 ++++++++---
 .../PushNotificationIOS/RCTPushNotificationManager.h  |  6 +++---
 .../PushNotificationIOS/RCTPushNotificationManager.m  | 10 +++++-----
 3 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/Libraries/PushNotificationIOS/PushNotificationIOS.js b/Libraries/PushNotificationIOS/PushNotificationIOS.js
index 74a8422d67bd..aa3e13fd1d2f 100644
--- a/Libraries/PushNotificationIOS/PushNotificationIOS.js
+++ b/Libraries/PushNotificationIOS/PushNotificationIOS.js
@@ -39,15 +39,20 @@ var NOTIF_REGISTER_EVENT = 'remoteNotificationsRegistered';
  * And then in your AppDelegate implementation add the following:
  *
  *   ```
- *   // Required for the register event.
+ *    // Required to register for notifications
+ *    - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
+ *    {
+ *     [RCTPushNotificationManager didRegisterUserNotificationSettings:notificationSettings];
+ *    }
+ *    // Required for the register event.
  *    - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
  *    {
- *     [RCTPushNotificationManager application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
+ *     [RCTPushNotificationManager didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
  *    }
  *    // Required for the notification event.
  *    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification
  *    {
- *     [RCTPushNotificationManager application:application didReceiveRemoteNotification:notification];
+ *     [RCTPushNotificationManager didReceiveRemoteNotification:notification];
  *    }
  *   ```
  */
diff --git a/Libraries/PushNotificationIOS/RCTPushNotificationManager.h b/Libraries/PushNotificationIOS/RCTPushNotificationManager.h
index 194bbc5ddeed..dd18b95183e4 100644
--- a/Libraries/PushNotificationIOS/RCTPushNotificationManager.h
+++ b/Libraries/PushNotificationIOS/RCTPushNotificationManager.h
@@ -13,8 +13,8 @@
 
 @interface RCTPushNotificationManager : NSObject <RCTBridgeModule>
 
-+ (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings;
-+ (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
-+ (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification;
++ (void)didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings;
++ (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
++ (void)didReceiveRemoteNotification:(NSDictionary *)notification;
 
 @end
diff --git a/Libraries/PushNotificationIOS/RCTPushNotificationManager.m b/Libraries/PushNotificationIOS/RCTPushNotificationManager.m
index 0fda6ee10f0a..761a1377eb3b 100644
--- a/Libraries/PushNotificationIOS/RCTPushNotificationManager.m
+++ b/Libraries/PushNotificationIOS/RCTPushNotificationManager.m
@@ -71,14 +71,14 @@ - (void)setBridge:(RCTBridge *)bridge
   return @{@"initialNotification": RCTNullIfNil(initialNotification)};
 }
 
-+ (void)application:(__unused UIApplication *)application didRegisterUserNotificationSettings:(__unused UIUserNotificationSettings *)notificationSettings
++ (void)didRegisterUserNotificationSettings:(__unused UIUserNotificationSettings *)notificationSettings
 {
-  if ([application respondsToSelector:@selector(registerForRemoteNotifications)]) {
-    [application registerForRemoteNotifications];
+  if ([UIApplication instancesRespondToSelector:@selector(registerForRemoteNotifications)]) {
+    [[UIApplication sharedApplication] registerForRemoteNotifications];
   }
 }
 
-+ (void)application:(__unused UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
++ (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
 {
   NSMutableString *hexString = [NSMutableString string];
   NSUInteger deviceTokenLength = deviceToken.length;
@@ -94,7 +94,7 @@ + (void)application:(__unused UIApplication *)application didRegisterForRemoteNo
                                                     userInfo:userInfo];
 }
 
-+ (void)application:(__unused UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification
++ (void)didReceiveRemoteNotification:(NSDictionary *)notification
 {
   [[NSNotificationCenter defaultCenter] postNotificationName:RCTRemoteNotificationReceived
                                                       object:self

From 3507bc61a5b77a1b75cb6fafab61e5470550744f Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Tue, 5 Jan 2016 03:44:53 -0800
Subject: [PATCH 0597/1411] added branch to ignore for CI tests

Summary:
every push to gh-pages renders an error in tests https://circleci.com/gh/facebook/react-native/995?utm_campaign=build-failed&utm_medium=email&utm_source=notification
Closes https://github.com/facebook/react-native/pull/5109

Reviewed By: svcscm

Differential Revision: D2802873

Pulled By: androidtrunkagent

fb-gh-sync-id: 8043f47ccfce322ae26ac5e85604bcc2c79d9cb4
---
 circle.yml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/circle.yml b/circle.yml
index a0e5d4a8791d..c50783716fd6 100644
--- a/circle.yml
+++ b/circle.yml
@@ -1,3 +1,7 @@
+general:
+  branches:
+    ignore:
+      - gh-pages # list of branches to ignore
 machine:
   node:
     version: 5.1.0

From 1c1d7006c2df3509aaef871cfcfeb5c77fd58884 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Tue, 5 Jan 2016 04:57:51 -0800
Subject: [PATCH 0598/1411] Remove extra JSUnprotect call

Summary:
public
Value doesn't protect it's value, so it shouldn't be unprotecting them in its destructor.

I'm also pretty sure we don't need to Protect the exception while it's on the stack according to the JSValueProtect docs: https://developer.apple.com/library/mac/documentation/JavaScriptCore/Reference/JSValueRef_header_reference/index.html#//apple_ref/c/func/JSValueProtect

Reviewed By: lexs

Differential Revision: D2779255

fb-gh-sync-id: 7d5df34639c8e7c41e92d3b8d652b93443d194a1
---
 ReactAndroid/src/main/jni/react/JSCExecutor.cpp | 2 --
 ReactAndroid/src/main/jni/react/Value.cpp       | 7 -------
 ReactAndroid/src/main/jni/react/Value.h         | 1 -
 3 files changed, 10 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index b12021d41890..a657a72f1375 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -86,7 +86,6 @@ static std::string executeJSCallWithJSC(
       "__fbBatchedBridge.", methodName, ".apply(null, ",
       folly::toJson(jsonArgs), ")");
   auto result = evaluateScript(ctx, String(js.c_str()), nullptr);
-  JSValueProtect(ctx, result);
   return Value(ctx, result).toJSONString();
 }
 
@@ -247,7 +246,6 @@ static JSValueRef nativeFlushQueueImmediate(
     return JSValueMakeUndefined(ctx);
   }
 
-  JSValueProtect(ctx, arguments[0]);
   std::string resStr = Value(ctx, arguments[0]).toJSONString();
 
   executor->flushQueueImmediate(resStr);
diff --git a/ReactAndroid/src/main/jni/react/Value.cpp b/ReactAndroid/src/main/jni/react/Value.cpp
index 0859ca452d0a..0acbc38c8843 100644
--- a/ReactAndroid/src/main/jni/react/Value.cpp
+++ b/ReactAndroid/src/main/jni/react/Value.cpp
@@ -23,12 +23,6 @@ Value::Value(Value&& other) :
   other.m_value = nullptr;
 }
 
-Value::~Value() {
-  if (m_value) {
-    JSValueUnprotect(m_context, m_value);
-  }
-}
-
 JSContextRef Value::context() const {
   return m_context;
 }
@@ -37,7 +31,6 @@ std::string Value::toJSONString(unsigned indent) const {
   JSValueRef exn;
   auto stringToAdopt = JSValueCreateJSONString(m_context, m_value, indent, &exn);
   if (stringToAdopt == nullptr) {
-    JSValueProtect(m_context, exn);
     std::string exceptionText = Value(m_context, exn).toString().str();
     throwJSExecutionException("Exception creating JSON string: %s", exceptionText.c_str());
   }
diff --git a/ReactAndroid/src/main/jni/react/Value.h b/ReactAndroid/src/main/jni/react/Value.h
index c237bda1827d..8a845ebfe513 100644
--- a/ReactAndroid/src/main/jni/react/Value.h
+++ b/ReactAndroid/src/main/jni/react/Value.h
@@ -142,7 +142,6 @@ class Value : public noncopyable {
 public:
   Value(JSContextRef context, JSValueRef value);
   Value(Value&&);
-  ~Value();
 
   operator JSValueRef() const {
     return m_value;

From a5d82c282336c80addf1225db1346c764b6794f7 Mon Sep 17 00:00:00 2001
From: Justin Spahr-Summers <jspahrsummers@fb.com>
Date: Tue, 5 Jan 2016 07:59:54 -0800
Subject: [PATCH 0599/1411] Add context executor API for sync hooks

Summary:
public

This exposes a proper API for adding synchronous callbacks to JS, as an optional feature of the executor.

This is based on nicklockwood's work in D2764492, but avoids refactoring bridge/executor interactions for the time being, since we agree on this API and can move the actual callsites around later.

Reviewed By: nicklockwood

Differential Revision: D2799506

fb-gh-sync-id: af209d9a0be927f3404205feb16e59745cc37aec
---
 .../UIExplorerUnitTests/RCTAllocationTests.m  |   2 +-
 Libraries/RCTTest/RCTTestRunner.m             |   2 +-
 React/Base/RCTJavaScriptExecutor.h            |   6 +
 React/Executors/RCTJSCExecutor.m              | 156 ++++++++++--------
 4 files changed, 93 insertions(+), 73 deletions(-)

diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m
index c642953768d5..dd53ee8ec1cc 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m
@@ -187,7 +187,7 @@ - (void)testJavaScriptContextIsDeallocated
                                               moduleProvider:nil
                                                launchOptions:nil];
     id executor = [bridge.batchedBridge valueForKey:@"javaScriptExecutor"];
-    RUN_RUNLOOP_WHILE(!(weakContext = [executor valueForKey:@"context"]));
+    RUN_RUNLOOP_WHILE(!(weakContext = [executor valueForKey:@"_context"]));
     XCTAssertNotNil(weakContext, @"RCTJavaScriptContext should have been created");
     (void)bridge;
   }
diff --git a/Libraries/RCTTest/RCTTestRunner.m b/Libraries/RCTTest/RCTTestRunner.m
index e1c8e29a8416..46a3a2abee4a 100644
--- a/Libraries/RCTTest/RCTTestRunner.m
+++ b/Libraries/RCTTest/RCTTestRunner.m
@@ -136,7 +136,7 @@ - (void)runTest:(SEL)test module:(NSString *)moduleName
     // (we can only do this now, since it's been lazily initialized)
     id jsExecutor = [bridge valueForKeyPath:@"batchedBridge.javaScriptExecutor"];
     if ([jsExecutor isKindOfClass:[RCTJSCExecutor class]]) {
-      weakJSContext = [jsExecutor valueForKey:@"context"];
+      weakJSContext = [jsExecutor valueForKey:@"_context"];
     }
     [rootView removeFromSuperview];
 
diff --git a/React/Base/RCTJavaScriptExecutor.h b/React/Base/RCTJavaScriptExecutor.h
index 832b78e3cdda..2e0b80860d00 100644
--- a/React/Base/RCTJavaScriptExecutor.h
+++ b/React/Base/RCTJavaScriptExecutor.h
@@ -85,4 +85,10 @@ typedef void (^RCTJavaScriptCallback)(id json, NSError *error);
  */
 - (void)executeAsyncBlockOnJavaScriptQueue:(dispatch_block_t)block;
 
+/**
+ * For executors that support it, this method can be used to add a synchronous
+ * callback function for communicating with the javascript context.
+ */
+- (void)addSynchronousHookWithName:(NSString *)name usingBlock:(id)block;
+
 @end
diff --git a/React/Executors/RCTJSCExecutor.m b/React/Executors/RCTJSCExecutor.m
index a586fd07e079..6e5736a9f9f1 100644
--- a/React/Executors/RCTJSCExecutor.m
+++ b/React/Executors/RCTJSCExecutor.m
@@ -215,99 +215,113 @@ - (instancetype)initWithJavaScriptThread:(NSThread *)javaScriptThread
   return [self initWithJavaScriptThread:javaScriptThread context:context];
 }
 
-- (void)setUp
+- (RCTJavaScriptContext *)context
+{
+  RCTAssertThread(_javaScriptThread, @"Must be called on JS thread.");
+
+  if (!self.isValid) {
+    return nil;
+  }
+
+  if (!_context) {
+    JSContext *context = [JSContext new];
+    _context = [[RCTJavaScriptContext alloc] initWithJSContext:context];
+  }
+
+  return _context;
+}
+
+- (void)addSynchronousHookWithName:(NSString *)name usingBlock:(id)block
 {
   __weak RCTJSCExecutor *weakSelf = self;
   [self executeBlockOnJavaScriptQueue:^{
-    RCTJSCExecutor *strongSelf = weakSelf;
-    if (!strongSelf.isValid) {
-      return;
-    }
+    weakSelf.context.context[name] = block;
+  }];
+}
+
+- (void)setUp
+{
+  __weak RCTJSCExecutor *weakSelf = self;
+  [self addSynchronousHookWithName:@"noop" usingBlock:^{}];
 
-    if (!strongSelf->_context) {
-      JSContext *context = [JSContext new];
-      strongSelf->_context = [[RCTJavaScriptContext alloc] initWithJSContext:context];
+  [self addSynchronousHookWithName:@"nativeLoggingHook" usingBlock:^(NSString *message, NSNumber *logLevel) {
+    RCTLogLevel level = RCTLogLevelInfo;
+    if (logLevel) {
+      level = MAX(level, logLevel.integerValue);
     }
 
-    __weak RCTBridge *weakBridge = strongSelf->_bridge;
-    JSContext *context = strongSelf->_context.context;
+    _RCTLogJavaScriptInternal(level, message);
+  }];
 
-    context[@"noop"] = ^{};
+  [self addSynchronousHookWithName:@"nativeRequireModuleConfig" usingBlock:^NSString *(NSString *moduleName) {
+    RCTJSCExecutor *strongSelf = weakSelf;
+    if (!strongSelf.valid) {
+      return nil;
+    }
 
-    context[@"nativeLoggingHook"] = ^(NSString *message, NSNumber *logLevel) {
-      RCTLogLevel level = RCTLogLevelInfo;
-      if (logLevel) {
-        level = MAX(level, logLevel.integerValue);
-      }
+    NSArray *config = [strongSelf->_bridge configForModuleName:moduleName];
+    if (config) {
+      return RCTJSONStringify(config, NULL);
+    }
 
-      _RCTLogJavaScriptInternal(level, message);
-    };
+    return nil;
+  }];
 
-    context[@"nativeRequireModuleConfig"] = ^NSString *(NSString *moduleName) {
-      if (!weakSelf.valid) {
-        return nil;
-      }
-      NSArray *config = [weakBridge configForModuleName:moduleName];
-      if (config) {
-        return RCTJSONStringify(config, NULL);
-      }
-      return nil;
-    };
+  [self addSynchronousHookWithName:@"nativeFlushQueueImmediate" usingBlock:^(NSArray<NSArray *> *calls){
+    RCTJSCExecutor *strongSelf = weakSelf;
+    if (!strongSelf.valid || !calls) {
+      return;
+    }
 
-    context[@"nativeFlushQueueImmediate"] = ^(NSArray<NSArray *> *calls){
-      if (!weakSelf.valid || !calls) {
-        return;
-      }
-      [weakBridge handleBuffer:calls batchEnded:NO];
-    };
+    [strongSelf->_bridge handleBuffer:calls batchEnded:NO];
+  }];
 
-    context[@"nativePerformanceNow"] = ^{
-      return @(CACurrentMediaTime() * 1000);
-    };
+  [self addSynchronousHookWithName:@"nativePerformanceNow" usingBlock:^{
+    return @(CACurrentMediaTime() * 1000);
+  }];
 
 #if RCT_DEV
+  if (RCTProfileIsProfiling()) {
+    // Cheating, since it's not a "hook", but meh
+    [self addSynchronousHookWithName:@"__RCTProfileIsProfiling" usingBlock:@YES];
+  }
 
-    if (RCTProfileIsProfiling()) {
-      context[@"__RCTProfileIsProfiling"] = @YES;
-    }
+  CFMutableDictionaryRef cookieMap = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
+  [self addSynchronousHookWithName:@"nativeTraceBeginAsyncSection" usingBlock:^(uint64_t tag, NSString *name, NSUInteger cookie) {
+    NSUInteger newCookie = RCTProfileBeginAsyncEvent(tag, name, nil);
+    CFDictionarySetValue(cookieMap, (const void *)cookie, (const void *)newCookie);
+  }];
 
-    CFMutableDictionaryRef cookieMap = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
-    context[@"nativeTraceBeginAsyncSection"] = ^(uint64_t tag, NSString *name, NSUInteger cookie) {
-      NSUInteger newCookie = RCTProfileBeginAsyncEvent(tag, name, nil);
-      CFDictionarySetValue(cookieMap, (const void *)cookie, (const void *)newCookie);
-    };
-
-    context[@"nativeTraceEndAsyncSection"] = ^(uint64_t tag, NSString *name, NSUInteger cookie) {
-      NSUInteger newCookie = (NSUInteger)CFDictionaryGetValue(cookieMap, (const void *)cookie);
-      RCTProfileEndAsyncEvent(tag, @"js,async", newCookie, name, nil);
-      CFDictionaryRemoveValue(cookieMap, (const void *)cookie);
-    };
-
-    context[@"nativeTraceBeginSection"] = ^(NSNumber *tag, NSString *profileName){
-      static int profileCounter = 1;
-      if (!profileName) {
-        profileName = [NSString stringWithFormat:@"Profile %d", profileCounter++];
-      }
+  [self addSynchronousHookWithName:@"nativeTraceEndAsyncSection" usingBlock:^(uint64_t tag, NSString *name, NSUInteger cookie) {
+    NSUInteger newCookie = (NSUInteger)CFDictionaryGetValue(cookieMap, (const void *)cookie);
+    RCTProfileEndAsyncEvent(tag, @"js,async", newCookie, name, nil);
+    CFDictionaryRemoveValue(cookieMap, (const void *)cookie);
+  }];
 
-      RCT_PROFILE_BEGIN_EVENT(tag.longLongValue, profileName, nil);
-    };
+  [self addSynchronousHookWithName:@"nativeTraceBeginSection" usingBlock:^(NSNumber *tag, NSString *profileName){
+    static int profileCounter = 1;
+    if (!profileName) {
+      profileName = [NSString stringWithFormat:@"Profile %d", profileCounter++];
+    }
 
-    context[@"nativeTraceEndSection"] = ^(NSNumber *tag) {
-      RCT_PROFILE_END_EVENT(tag.longLongValue, @"console", nil);
-    };
+    RCT_PROFILE_BEGIN_EVENT(tag.longLongValue, profileName, nil);
+  }];
 
-    RCTInstallJSCProfiler(_bridge, strongSelf->_context.ctx);
+  [self addSynchronousHookWithName:@"nativeTraceEndSection" usingBlock:^(NSNumber *tag) {
+    RCT_PROFILE_END_EVENT(tag.longLongValue, @"console", nil);
+  }];
 
-    for (NSString *event in @[RCTProfileDidStartProfiling, RCTProfileDidEndProfiling]) {
-      [[NSNotificationCenter defaultCenter] addObserver:strongSelf
-                                               selector:@selector(toggleProfilingFlag:)
-                                                   name:event
-                                                 object:nil];
-    }
+  [self executeBlockOnJavaScriptQueue:^{
+    RCTInstallJSCProfiler(_bridge, self.context.ctx);
+  }];
 
+  for (NSString *event in @[RCTProfileDidStartProfiling, RCTProfileDidEndProfiling]) {
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(toggleProfilingFlag:)
+                                                 name:event
+                                               object:nil];
+  }
 #endif
-
-  }];
 }
 
 - (void)toggleProfilingFlag:(NSNotification *)notification

From 6af7ae55b1ccffd185eb269b81f9ed1ee9f77cc7 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Tue, 5 Jan 2016 16:48:38 +0000
Subject: [PATCH 0600/1411] [global-cli] react-native init [--debug|verbose]

`npm install` prints a lot of junk like gyp warnings
and the rest of the output is not super useful for
tracking progress.

Supress the output by default, show the output with
--debug, and show verbose output with --verbose.
---
 react-native-cli/index.js     | 35 ++++++++++++++++++++++-------------
 react-native-cli/package.json |  2 +-
 2 files changed, 23 insertions(+), 14 deletions(-)

diff --git a/react-native-cli/index.js b/react-native-cli/index.js
index 522ec26a005c..01c8f0e64a3a 100755
--- a/react-native-cli/index.js
+++ b/react-native-cli/index.js
@@ -83,11 +83,16 @@ if (cli) {
   switch (args[0]) {
   case 'init':
     if (args[1]) {
-      var verbose = process.argv.indexOf('--verbose') >= 0;
-      init(args[1], verbose);
+      var logLevel = '';
+      if (process.argv.indexOf('--verbose') >= 0) {
+        logLevel = 'verbose';
+      } else if (process.argv.indexOf('--debug') >= 0) {
+        logLevel = 'debug';
+      }
+      init(args[1], logLevel);
     } else {
       console.error(
-        'Usage: react-native init <ProjectName> [--verbose]'
+        'Usage: react-native init <ProjectName> [--debug|--verbose]'
       );
       process.exit(1);
     }
@@ -123,17 +128,17 @@ function validatePackageName(name) {
   }
 }
 
-function init(name, verbose) {
+function init(name, logLevel) {
   validatePackageName(name);
 
   if (fs.existsSync(name)) {
-    createAfterConfirmation(name, verbose);
+    createAfterConfirmation(name, logLevel);
   } else {
-    createProject(name, verbose);
+    createProject(name, logLevel);
   }
 }
 
-function createAfterConfirmation(name, verbose) {
+function createAfterConfirmation(name, logLevel) {
   prompt.start();
 
   var property = {
@@ -146,7 +151,7 @@ function createAfterConfirmation(name, verbose) {
 
   prompt.get(property, function (err, result) {
     if (result.yesno[0] === 'y') {
-      createProject(name, verbose);
+      createProject(name, logLevel);
     } else {
       console.log('Project initialization canceled');
       process.exit();
@@ -154,7 +159,7 @@ function createAfterConfirmation(name, verbose) {
   });
 }
 
-function createProject(name, verbose) {
+function createProject(name, logLevel) {
   var root = path.resolve(name);
   var projectName = path.basename(root);
 
@@ -180,16 +185,20 @@ function createProject(name, verbose) {
 
   console.log('Installing react-native package from npm...');
 
-  run(root, projectName, verbose);
+  run(root, projectName, logLevel);
 }
 
-function run(root, projectName, verbose) {
+function run(root, projectName, logLevel) {
   var args = ['install', '--save'];
-  if (verbose){
+  if (logLevel === 'verbose') {
     args.push('--verbose');
   }
   args.push('react-native');
-  var proc = spawn('npm', args, {stdio: 'inherit'});
+  var spawnArgs = {};
+  if (logLevel === 'debug' || logLevel === 'verbose') {
+    spawnArgs = {stdio: 'inherit'};
+  }
+  var proc = spawn('npm', args, spawnArgs);
   proc.on('close', function (code) {
     if (code !== 0) {
       console.error('`npm install --save react-native` failed');
diff --git a/react-native-cli/package.json b/react-native-cli/package.json
index 6c6bd533c56d..7b76d4e79ac6 100644
--- a/react-native-cli/package.json
+++ b/react-native-cli/package.json
@@ -1,6 +1,6 @@
 {
   "name": "react-native-cli",
-  "version": "0.1.7",
+  "version": "0.1.8",
   "license" : "BSD-3-Clause",
   "description": "The React Native CLI tools",
   "main": "index.js",

From 1b766ddd2c740b9671b75326d61f163ad9a3c0f6 Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Tue, 5 Jan 2016 16:59:43 +0000
Subject: [PATCH 0601/1411] Add a script for making releases easier

---
 scripts/release.sh | 122 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 122 insertions(+)
 create mode 100755 scripts/release.sh

diff --git a/scripts/release.sh b/scripts/release.sh
new file mode 100755
index 000000000000..70b24c478d13
--- /dev/null
+++ b/scripts/release.sh
@@ -0,0 +1,122 @@
+#! /bin/bash
+
+RELEASE="$1"
+JAVA_VERSION="1.7"
+
+RED="\033[0;31m"
+GREEN="\033[0;32m"
+BLUE="\033[0;35m"
+ENDCOLOR="\033[0m"
+
+error() {
+    echo -e $RED"$@"$ENDCOLOR
+    exit 1
+}
+
+success() {
+    echo -e $GREEN"$@"$ENDCOLOR
+}
+
+info() {
+    echo -e $BLUE"$@"$ENDCOLOR
+}
+
+[[ -z $RELEASE ]] && error "Please specify a version. Example usage: release.sh 0.18"
+
+repo_root=$(pwd)
+
+git branch | grep -o ${RELEASE}-stable && error "Branch already exists"
+java -version 2>&1 | grep ${JAVA_VERSION} || error "Java version must be 1.7.x in order to generate Javadoc. Check: java -version"
+
+git pull || error "Couldn't pull from remote repository"
+git checkout -b ${RELEASE}-stable || error "Couldn't create branch"
+
+success "Created release branch: ${RELEASE}-stable"
+
+sed -i.bak s/^VERSION_NAME=[0-9\.]*-SNAPSHOT/VERSION_NAME=${RELEASE}.0/g "ReactAndroid/gradle.properties" || error "Couldn't update version for Gradle"
+# Uncomment Javadoc generation
+sed -i.bak s:\/\/\ archives\ androidJavadocJar:archives\ androidJavadocJar:g "ReactAndroid/release.gradle" || error "Couldn't enable Javadoc generation"
+./gradlew :ReactAndroid:installArchives || error "Couldn't generate artifacts"
+# Revert Javadoc generation
+sed -i.bak s:archives\ androidJavadocJar:\/\/\ archives\ androidJavadocJar:g "ReactAndroid/release.gradle" || error "Couldn't enable Javadoc generation"
+
+artifacts_list=( -javadoc.jar -sources.jar .aar .pom )
+artifacts_dir=~/.m2/repository/com/facebook/react/react-native/${RELEASE}.0
+
+for i in "${artifacts_list[@]}"; do
+   artifact_file="${artifacts_dir}/react-native-${RELEASE}.0${i}"
+
+   [ -e "${artifact_file}" ] || error "Couldn't find file: ${artifact_file}"
+   [ -e "${artifact_file}.asc" ] || error "Couldn't find file: ${artifact_file}.asc"
+done
+
+success "Generated artifacts for Maven"
+
+sed -i.bak -E "s/(\"version\":[[:space:]]*\").+(\")/\"version\": \"${RELEASE}.0-rc\"/g" "package.json" || error "Couldn't update version for npm"
+sed -i.bak -E "s/(s.version[[:space:]]{13}=[[:space:]].+)/s.version             = \"${RELEASE}.0-rc\"/g" "React.podspec" || error "Couldn't update version for CocoaPods"
+sed -i.bak -E "s/\"com\.facebook\.react:react-native:.+\"/\"com.facebook.react:react-native:${RELEASE}.+\"/g" "local-cli/generator-android/templates/src/app/build.gradle" || error "Couldn't update version in Android template's build.gradle"
+
+success "Updated version numbers"
+
+npm_registry="http://localhost:4873/"
+
+npm set registry "${npm_registry}" && [[ $(npm config list | grep registry) == "registry = \"${npm_registry}\"" ]] || error "Couldn't set registry to ${npm_registry}"
+
+info "npm registry set. Run 'sinopia' in a new Terminal"
+info "   - Make sure it prints 'http address - ${npm_registry}'"
+info "   - Make sure ${npm_registry} shows no old versions"
+info ""
+info "Press any key to continue"
+read -n 1
+
+npm unpublish --force || error "Couldn't unpublish package from sinopia (${npm_registry})"
+npm publish || error "Couldn't publish package to sinopia (${npm_registry})"
+
+success "Published package to sinopia (${npm_registry})"
+
+project_name="RNTestProject"
+
+cd /tmp/
+rm -rf "$project_name"
+react-native init "$project_name"
+grep "\"react-native\": \"\^${RELEASE}.0-rc\"" "/tmp/${project_name}/package.json" || error "Incorrect version number in /tmp/${project_name}/package.json"
+grep "com.facebook.react:react-native:${RELEASE}.+" "${project_name}/android/app/build.gradle" || error "Incorrect version number in /tmp/${project_name}/android/app/build.gradle"
+
+success "New sample project generated at /tmp/${project_name}"
+
+info "Test the following both on Android and iOS:"
+info "   - Verify that packager opens in new Window"
+info "   - Verify that you see the 'Welcome to React Native' screen"
+info "   - Verify 'Reload JS' works"
+info "   - Test Chrome debugger by adding breakpoints (we don't have tests for Chrome debugging)"
+info ""
+
+info "Press any key to run the sample in Android emulator/device"
+read -n 1
+cd "${project_name}" && react-native run-android
+
+info "Press any key to open the project in XCode"
+read -n 1
+open "/tmp/${project_name}/ios/${project_name}.xcodeproj"
+
+cd "$repo_root"
+
+info "Press any key to view the diff"
+read -n 1
+git diff
+
+info "Press any key to commit changes"
+read -n 1
+git commit -am "[${RELEASE}.0-rc] Bump version numbers"
+
+find . -path "*.bak" | xargs rm
+
+info "Next steps:"
+info "   - Release to Maven Central: https://github.com/facebook/react-native/blob/master/Releases.md#do-a-release"
+info "   - git push origin ${RELEASE}-stable"
+info "   - git tag v${RELEASE}.0-rc ${RELEASE}-stable"
+info "   - git push --tags"
+info "   - Once the change propagates to JCenter:"
+info "     - npm set registry https://registry.npmjs.org/"
+info "     - npm publish"
+info "     - Only when doing a non-rc release: npm dist-tag add react-native@${RELEASE}.0 latest"

From fc98956b65edda40de5cb12f07ba53bf20198813 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Tue, 5 Jan 2016 09:04:08 -0800
Subject: [PATCH 0602/1411] Fix race conditions in RCTModuleData

Summary:
public
The logic inside RCTBatchedBridge contained some race conditions that would occasionally cause an error if modules were loaded in the wrong order. This improves that logic and makes it safer by adding a lock to prevent concurrency.

Reviewed By: jspahrsummers

Differential Revision: D2802930

fb-gh-sync-id: d1ad25fa578649363dcaac029cb24dc3a453ae67
---
 React/Base/RCTBatchedBridge.m  |  40 +++++----
 React/Base/RCTBridge+Private.h |   7 +-
 React/Base/RCTModuleData.h     |   5 +-
 React/Base/RCTModuleData.m     | 146 +++++++++++++++------------------
 4 files changed, 103 insertions(+), 95 deletions(-)

diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index 65db384323a5..7ae745a391d0 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -295,7 +295,8 @@ - (void)initModules
     RCTModuleData *moduleData;
     if (module) {
       if (module != (id)kCFNull) {
-        moduleData = [[RCTModuleData alloc] initWithModuleInstance:module];
+        moduleData = [[RCTModuleData alloc] initWithModuleInstance:module
+                                                            bridge:self];
       }
     } else {
        moduleData = [[RCTModuleData alloc] initWithModuleClass:moduleClass
@@ -320,7 +321,7 @@ - (void)initModules
 
   for (RCTModuleData *moduleData in _moduleDataByID) {
     if (moduleData.hasInstance) {
-      [moduleData setBridgeForInstance:self];
+      [moduleData setBridgeForInstance];
     }
   }
 
@@ -330,6 +331,13 @@ - (void)initModules
     }
   }
 
+  for (RCTModuleData *moduleData in _moduleDataByID) {
+    if (moduleData.hasInstance) {
+      [self registerModuleForFrameUpdates:moduleData.instance
+                           withModuleData:moduleData];
+    }
+  }
+
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
 
@@ -347,18 +355,22 @@ - (void)setUpExecutor
   [_javaScriptExecutor setUp];
 }
 
-- (void)registerModuleForFrameUpdates:(RCTModuleData *)moduleData
-{
-  if ([moduleData.moduleClass conformsToProtocol:@protocol(RCTFrameUpdateObserver)]) {
-    [_frameUpdateObservers addObject:moduleData];
-    id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)moduleData.instance;
-    __weak typeof(self) weakSelf = self;
-    __weak typeof(_javaScriptExecutor) weakJavaScriptExecutor = _javaScriptExecutor;
-    observer.pauseCallback = ^{
-      [weakJavaScriptExecutor executeBlockOnJavaScriptQueue:^{
-        [weakSelf updateJSDisplayLinkState];
-      }];
-    };
+- (void)registerModuleForFrameUpdates:(id<RCTBridgeModule>)module
+                       withModuleData:(RCTModuleData *)moduleData
+{
+  if (![_frameUpdateObservers containsObject:moduleData]) {
+    if ([moduleData.moduleClass conformsToProtocol:@protocol(RCTFrameUpdateObserver)]) {
+      [_frameUpdateObservers addObject:moduleData];
+      // Don't access the module instance via moduleData, as this will cause deadlock
+      id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)module;
+      __weak typeof(self) weakSelf = self;
+      __weak typeof(_javaScriptExecutor) weakJavaScriptExecutor = _javaScriptExecutor;
+      observer.pauseCallback = ^{
+        [weakJavaScriptExecutor executeBlockOnJavaScriptQueue:^{
+          [weakSelf updateJSDisplayLinkState];
+        }];
+      };
+    }
   }
 }
 
diff --git a/React/Base/RCTBridge+Private.h b/React/Base/RCTBridge+Private.h
index 91675efa5943..ddeddeaa4eff 100644
--- a/React/Base/RCTBridge+Private.h
+++ b/React/Base/RCTBridge+Private.h
@@ -50,7 +50,12 @@
 
 @interface RCTBridge (RCTBatchedBridge)
 
-- (void)registerModuleForFrameUpdates:(RCTModuleData *)moduleData;
+/**
+ * Used by RCTModuleData to register the module for frame updates after it is
+ * lazily initialized.
+ */
+- (void)registerModuleForFrameUpdates:(id<RCTBridgeModule>)module
+                       withModuleData:(RCTModuleData *)moduleData;
 
 /**
  * Dispatch work to a module's queue - this is also suports the fake RCTJSThread
diff --git a/React/Base/RCTModuleData.h b/React/Base/RCTModuleData.h
index 79752ba292ab..bf55892fd802 100644
--- a/React/Base/RCTModuleData.h
+++ b/React/Base/RCTModuleData.h
@@ -20,14 +20,15 @@
 - (instancetype)initWithModuleClass:(Class)moduleClass
                              bridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
 
-- (instancetype)initWithModuleInstance:(id<RCTBridgeModule>)instance NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithModuleInstance:(id<RCTBridgeModule>)instance
+                                bridge:(RCTBridge *)bridge;
 
 /**
  * Sets the bridge for the module instance. This is only needed when using the
  * `initWithModuleID:instance:` constructor. Otherwise, the bridge will be set
  * automatically when the module is first accessed.
  */
-- (void)setBridgeForInstance:(RCTBridge *)bridge;
+- (void)setBridgeForInstance;
 
 @property (nonatomic, strong, readonly) Class moduleClass;
 @property (nonatomic, copy, readonly) NSString *name;
diff --git a/React/Base/RCTModuleData.m b/React/Base/RCTModuleData.m
index 71f5dd2f91fb..2e290ce6c91b 100644
--- a/React/Base/RCTModuleData.m
+++ b/React/Base/RCTModuleData.m
@@ -19,6 +19,8 @@ @implementation RCTModuleData
 {
   NSString *_queueName;
   __weak RCTBridge *_bridge;
+  NSLock *_instanceLock;
+  BOOL _setupComplete;
 }
 
 @synthesize methods = _methods;
@@ -31,81 +33,80 @@ - (instancetype)initWithModuleClass:(Class)moduleClass
   if ((self = [super init])) {
     _moduleClass = moduleClass;
     _bridge = bridge;
+
+    _implementsBatchDidComplete = [_moduleClass instancesRespondToSelector:@selector(batchDidComplete)];
+    _implementsPartialBatchDidFlush = [_moduleClass instancesRespondToSelector:@selector(partialBatchDidFlush)];
+
+    _instanceLock = [NSLock new];
   }
   return self;
 }
 
 - (instancetype)initWithModuleInstance:(id<RCTBridgeModule>)instance
+                                bridge:(RCTBridge *)bridge
 {
-  if ((self = [super init])) {
+  if ((self = [self initWithModuleClass:[instance class] bridge:bridge])) {
     _instance = instance;
-    _moduleClass = [instance class];
-
-    [self cacheImplementedSelectors];
   }
   return self;
 }
 
 RCT_NOT_IMPLEMENTED(- (instancetype)init);
 
-- (void)cacheImplementedSelectors
+#pragma mark - private setup methods
+
+- (void)setBridgeForInstance
 {
-  _implementsBatchDidComplete = [_instance respondsToSelector:@selector(batchDidComplete)];
-  _implementsPartialBatchDidFlush = [_instance respondsToSelector:@selector(partialBatchDidFlush)];
+  RCTAssert(_instance, @"setBridgeForInstance called before %@ initialized", self.name);
+  if ([_instance respondsToSelector:@selector(bridge)] && !_instance.bridge) {
+    @try {
+      [(id)_instance setValue:_bridge forKey:@"bridge"];
+    }
+    @catch (NSException *exception) {
+      RCTLogError(@"%@ has no setter or ivar for its bridge, which is not "
+                  "permitted. You must either @synthesize the bridge property, "
+                  "or provide your own setter method.", self.name);
+    }
+  }
 }
 
 - (void)setUpMethodQueue
 {
-  RCTAssert(!_methodQueue, @"Method queue is already set up");
-  RCTAssert(_instance, @"Instance is not yet set up");
-
-  BOOL implementsMethodQueue = [_instance respondsToSelector:@selector(methodQueue)];
-  if (implementsMethodQueue) {
-    _methodQueue = _instance.methodQueue;
-  }
   if (!_methodQueue) {
-
-    // Create new queue (store queueName, as it isn't retained by dispatch_queue)
-    _queueName = [NSString stringWithFormat:@"com.facebook.React.%@Queue", self.name];
-    _methodQueue = dispatch_queue_create(_queueName.UTF8String, DISPATCH_QUEUE_SERIAL);
-
-    // assign it to the module
+    RCTAssert(_instance, @"setUpMethodQueue called before %@ initialized", self.name);
+    BOOL implementsMethodQueue = [_instance respondsToSelector:@selector(methodQueue)];
     if (implementsMethodQueue) {
-      @try {
-        [(id)_instance setValue:_methodQueue forKey:@"methodQueue"];
-      }
-      @catch (NSException *exception) {
-        RCTLogError(@"%@ is returning nil for it's methodQueue, which is not "
-                    "permitted. You must either return a pre-initialized "
-                    "queue, or @synthesize the methodQueue to let the bridge "
-                    "create a queue for you.", self.name);
+      _methodQueue = _instance.methodQueue;
+    }
+    if (!_methodQueue) {
+
+      // Create new queue (store queueName, as it isn't retained by dispatch_queue)
+      _queueName = [NSString stringWithFormat:@"com.facebook.React.%@Queue", self.name];
+      _methodQueue = dispatch_queue_create(_queueName.UTF8String, DISPATCH_QUEUE_SERIAL);
+
+      // assign it to the module
+      if (implementsMethodQueue) {
+        @try {
+          [(id)_instance setValue:_methodQueue forKey:@"methodQueue"];
+        }
+        @catch (NSException *exception) {
+          RCTLogError(@"%@ is returning nil for it's methodQueue, which is not "
+                      "permitted. You must either return a pre-initialized "
+                      "queue, or @synthesize the methodQueue to let the bridge "
+                      "create a queue for you.", self.name);
+        }
       }
     }
-  }
 
-  // Needs to be sent after bridge has been set for all module instances.
-  // Makes sense to put it here, since the same rules apply for methodQueue.
-  [[NSNotificationCenter defaultCenter]
-   postNotificationName:RCTDidInitializeModuleNotification
-   object:_bridge userInfo:@{@"module": _instance}];
+    // Needs to be sent after bridge has been set for all module instances.
+    // Makes sense to put it here, since the same rules apply for methodQueue.
+    [[NSNotificationCenter defaultCenter]
+     postNotificationName:RCTDidInitializeModuleNotification
+     object:_bridge userInfo:@{@"module": _instance}];
+  }
 }
 
-- (void)setUpInstance
-{
-  RCTAssert(!_instance, @"Instance is already set up");
-
-  _instance = [_moduleClass new];
-
-  // Bridge must be set before methodQueue is set up, as methodQueue
-  // initialization requires it (View Managers get their queue by calling
-  // self.bridge.uiManager.methodQueue)
-  [self setBridgeForInstance:_bridge];
-
-  // Initialize queue
-  [self setUpMethodQueue];
-
-  [self cacheImplementedSelectors];
-}
+#pragma mark - public getters
 
 - (BOOL)hasInstance
 {
@@ -114,28 +115,21 @@ - (BOOL)hasInstance
 
 - (id<RCTBridgeModule>)instance
 {
-  if (!_instance) {
-    [self setUpInstance];
-  }
-  return _instance;
-}
-
-- (void)setBridgeForInstance:(RCTBridge *)bridge
-{
-  RCTAssert(_instance, @"setBridgeForInstance called before module was initialized");
-
-  _bridge = bridge;
-  if ([_instance respondsToSelector:@selector(bridge)]) {
-    @try {
-      [(id)_instance setValue:bridge forKey:@"bridge"];
-    }
-    @catch (NSException *exception) {
-      RCTLogError(@"%@ has no setter or ivar for its bridge, which is not "
-                  "permitted. You must either @synthesize the bridge property, "
-                  "or provide your own setter method.", self.name);
+  [_instanceLock lock];
+  if (!_setupComplete) {
+    if (!_instance) {
+      _instance = [_moduleClass new];
     }
+    // Bridge must be set before methodQueue is set up, as methodQueue
+    // initialization requires it (View Managers get their queue by calling
+    // self.bridge.uiManager.methodQueue)
+    [self setBridgeForInstance];
+    [self setUpMethodQueue];
+    [_bridge registerModuleForFrameUpdates:_instance withModuleData:self];
+    _setupComplete = YES;
   }
-  [bridge registerModuleForFrameUpdates:self];
+  [_instanceLock unlock];
+  return _instance;
 }
 
 - (NSString *)name
@@ -148,7 +142,8 @@ - (NSString *)name
   if (!_methods) {
     NSMutableArray<id<RCTBridgeMethod>> *moduleMethods = [NSMutableArray new];
 
-    if ([_instance respondsToSelector:@selector(methodsToExport)]) {
+    if ([_moduleClass instancesRespondToSelector:@selector(methodsToExport)]) {
+      [self instance];
       [moduleMethods addObjectsFromArray:[_instance methodsToExport]];
     }
 
@@ -182,7 +177,7 @@ - (NSArray *)config
 {
   __block NSDictionary<NSString *, id> *constants;
   if (RCTClassOverridesInstanceMethod(_moduleClass, @selector(constantsToExport))) {
-    [self instance]; // Initialize instance
+    [self instance];
     RCTExecuteOnMainThread(^{
       constants = [_instance constantsToExport];
     }, YES);
@@ -220,12 +215,7 @@ - (NSArray *)config
 
 - (dispatch_queue_t)methodQueue
 {
-  if (!_instance) {
-    [self setUpInstance];
-  }
-  if (!_methodQueue) {
-    [self setUpMethodQueue];
-  }
+  [self instance];
   return _methodQueue;
 }
 

From 6d9096fb3f915117703c19c8cee7acd9d11bc378 Mon Sep 17 00:00:00 2001
From: Alexander Blom <blom@fb.com>
Date: Tue, 5 Jan 2016 09:26:54 -0800
Subject: [PATCH 0603/1411] Fix deadlock when recreating websocket connection

Summary:
When you reload code while using the Chrome debugger we used to create a new websocket connection before closing
the old one. This sometimes would cause a in-flight call to not get a response. This in turn would deadlock the JS thread
because we try to shut it down before killing the websocket connection.

This change instead makes sure to close the old connection before creating a new one. This is done by using a factory for
creating the JavascriptExecutor so we can defer the creation until after the old Bridge has been torn down.

public

Reviewed By: astreet

Differential Revision: D2735011

fb-gh-sync-id: 0ce0f35abaeef5457bad8d6b8d10122281192af4
---
 .../react/ReactInstanceManagerImpl.java       | 81 ++++++++++++++-----
 .../react/bridge/JSCJavaScriptExecutor.java   |  6 ++
 .../facebook/react/bridge/JavaJSExecutor.java |  6 +-
 .../react/bridge/JavaScriptExecutor.java      |  3 +
 .../react/bridge/ProxyJavaScriptExecutor.java | 12 +++
 .../bridge/WebsocketJavaScriptExecutor.java   | 24 ++++--
 .../react/devsupport/DevSupportManager.java   | 77 ++++++++++--------
 .../ReactInstanceDevCommandsHandler.java      |  2 +-
 8 files changed, 152 insertions(+), 59 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index 0baef21f20d6..780cdb12392d 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -108,8 +108,8 @@
       new ReactInstanceDevCommandsHandler() {
 
         @Override
-        public void onReloadWithJSDebugger(JavaJSExecutor jsExecutor) {
-          ReactInstanceManagerImpl.this.onReloadWithJSDebugger(jsExecutor);
+        public void onReloadWithJSDebugger(JavaJSExecutor.Factory jsExecutorFactory) {
+          ReactInstanceManagerImpl.this.onReloadWithJSDebugger(jsExecutorFactory);
         }
 
         @Override
@@ -132,18 +132,18 @@ public void invokeDefaultOnBackPressed() {
       };
 
   private class ReactContextInitParams {
-    private final JavaScriptExecutor mJsExecutor;
+    private final JavaScriptExecutor.Factory mJsExecutorFactory;
     private final JSBundleLoader mJsBundleLoader;
 
     public ReactContextInitParams(
-        JavaScriptExecutor jsExecutor,
+        JavaScriptExecutor.Factory jsExecutorFactory,
         JSBundleLoader jsBundleLoader) {
-      mJsExecutor = Assertions.assertNotNull(jsExecutor);
+      mJsExecutorFactory = Assertions.assertNotNull(jsExecutorFactory);
       mJsBundleLoader = Assertions.assertNotNull(jsBundleLoader);
     }
 
-    public JavaScriptExecutor getJsExecutor() {
-      return mJsExecutor;
+    public JavaScriptExecutor.Factory getJsExecutorFactory() {
+      return mJsExecutorFactory;
     }
 
     public JSBundleLoader getJsBundleLoader() {
@@ -156,8 +156,7 @@ public JSBundleLoader getJsBundleLoader() {
    * be executing one at time, see {@link #recreateReactContextInBackground()}.
    */
   private final class ReactContextInitAsyncTask extends
-      AsyncTask<ReactContextInitParams, Void, ReactApplicationContext> {
-
+      AsyncTask<ReactContextInitParams, Void, Result<ReactApplicationContext>> {
     @Override
     protected void onPreExecute() {
       if (mCurrentReactContext != null) {
@@ -167,15 +166,23 @@ protected void onPreExecute() {
     }
 
     @Override
-    protected ReactApplicationContext doInBackground(ReactContextInitParams... params) {
+    protected Result<ReactApplicationContext> doInBackground(ReactContextInitParams... params) {
       Assertions.assertCondition(params != null && params.length > 0 && params[0] != null);
-      return createReactContext(params[0].getJsExecutor(), params[0].getJsBundleLoader());
+      try {
+        JavaScriptExecutor jsExecutor = params[0].getJsExecutorFactory().create();
+        return Result.of(createReactContext(jsExecutor, params[0].getJsBundleLoader()));
+      } catch (Exception e) {
+        // Pass exception to onPostExecute() so it can be handled on the main thread
+        return Result.of(e);
+      }
     }
 
     @Override
-    protected void onPostExecute(ReactApplicationContext reactContext) {
+    protected void onPostExecute(Result<ReactApplicationContext> result) {
       try {
-        setupReactContext(reactContext);
+        setupReactContext(result.get());
+      } catch (Exception e) {
+        mDevSupportManager.handleException(e);
       } finally {
         mIsContextInitAsyncTaskRunning = false;
       }
@@ -183,13 +190,46 @@ protected void onPostExecute(ReactApplicationContext reactContext) {
       // Handle enqueued request to re-initialize react context.
       if (mPendingReactContextInitParams != null) {
         recreateReactContextInBackground(
-            mPendingReactContextInitParams.getJsExecutor(),
+            mPendingReactContextInitParams.getJsExecutorFactory(),
             mPendingReactContextInitParams.getJsBundleLoader());
         mPendingReactContextInitParams = null;
       }
     }
   }
 
+  private static class Result<T> {
+    @Nullable private final T mResult;
+    @Nullable private final Exception mException;
+
+    public static <T, U extends T> Result<T> of(U result) {
+      return new Result<T>(result);
+    }
+
+    public static <T> Result<T> of(Exception exception) {
+      return new Result<>(exception);
+    }
+
+    private Result(T result) {
+      mException = null;
+      mResult = result;
+    }
+
+    private Result(Exception exception) {
+      mException = exception;
+      mResult = null;
+    }
+
+    public T get() throws Exception {
+      if (mException != null) {
+        throw mException;
+      }
+
+      Assertions.assertNotNull(mResult);
+
+      return mResult;
+    }
+  }
+
   /* package */ ReactInstanceManagerImpl(
       Context applicationContext,
       @Nullable String jsBundleFile,
@@ -311,7 +351,7 @@ public void run() {
 
   private void recreateReactContextInBackgroundFromBundleFile() {
     recreateReactContextInBackground(
-        new JSCJavaScriptExecutor(),
+        new JSCJavaScriptExecutor.Factory(),
         JSBundleLoader.createFileLoader(mApplicationContext, mJSBundleFile));
   }
 
@@ -504,9 +544,9 @@ public void addReactInstanceEventListener(ReactInstanceEventListener listener) {
     return mCurrentReactContext;
   }
 
-  private void onReloadWithJSDebugger(JavaJSExecutor jsExecutor) {
+  private void onReloadWithJSDebugger(JavaJSExecutor.Factory jsExecutorFactory) {
     recreateReactContextInBackground(
-        new ProxyJavaScriptExecutor(jsExecutor),
+        new ProxyJavaScriptExecutor.Factory(jsExecutorFactory),
         JSBundleLoader.createRemoteDebuggerBundleLoader(
             mDevSupportManager.getJSBundleURLForRemoteDebugging(),
             mDevSupportManager.getSourceUrl()));
@@ -514,18 +554,19 @@ private void onReloadWithJSDebugger(JavaJSExecutor jsExecutor) {
 
   private void onJSBundleLoadedFromServer() {
     recreateReactContextInBackground(
-        new JSCJavaScriptExecutor(),
+        new JSCJavaScriptExecutor.Factory(),
         JSBundleLoader.createCachedBundleFromNetworkLoader(
             mDevSupportManager.getSourceUrl(),
             mDevSupportManager.getDownloadedJSBundleFile()));
   }
 
   private void recreateReactContextInBackground(
-      JavaScriptExecutor jsExecutor,
+      JavaScriptExecutor.Factory jsExecutorFactory,
       JSBundleLoader jsBundleLoader) {
     UiThreadUtil.assertOnUiThread();
 
-    ReactContextInitParams initParams = new ReactContextInitParams(jsExecutor, jsBundleLoader);
+    ReactContextInitParams initParams =
+        new ReactContextInitParams(jsExecutorFactory, jsBundleLoader);
     if (!mIsContextInitAsyncTaskRunning) {
       // No background task to create react context is currently running, create and execute one.
       ReactContextInitAsyncTask initTask = new ReactContextInitAsyncTask();
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSCJavaScriptExecutor.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSCJavaScriptExecutor.java
index d371cf5be621..32b2619309f3 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSCJavaScriptExecutor.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSCJavaScriptExecutor.java
@@ -14,6 +14,12 @@
 
 @DoNotStrip
 public class JSCJavaScriptExecutor extends JavaScriptExecutor {
+  public static class Factory implements JavaScriptExecutor.Factory {
+    @Override
+    public JavaScriptExecutor create() throws Exception {
+      return new JSCJavaScriptExecutor();
+    }
+  }
 
   static {
     SoLoader.loadLibrary(ReactBridge.REACT_NATIVE_LIB);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaJSExecutor.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaJSExecutor.java
index 3c8eb4574b6b..5c1b01b2222e 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaJSExecutor.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaJSExecutor.java
@@ -18,7 +18,11 @@
  */
 @DoNotStrip
 public interface JavaJSExecutor {
-  public static class ProxyExecutorException extends Exception {
+  interface Factory {
+    JavaJSExecutor create() throws Exception;
+  }
+
+  class ProxyExecutorException extends Exception {
     public ProxyExecutorException(Throwable cause) {
       super(cause);
     }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptExecutor.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptExecutor.java
index 2bc5e26c5c53..bdf7e4fc6136 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptExecutor.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptExecutor.java
@@ -14,6 +14,9 @@
 
 @DoNotStrip
 public abstract class JavaScriptExecutor extends Countable {
+  public interface Factory {
+    JavaScriptExecutor create() throws Exception;
+  }
 
   /**
    * Close this executor and cleanup any resources that it was using. No further calls are
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ProxyJavaScriptExecutor.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ProxyJavaScriptExecutor.java
index f9e58869b3f5..80cd6f4b3259 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ProxyJavaScriptExecutor.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ProxyJavaScriptExecutor.java
@@ -24,6 +24,18 @@
  */
 @DoNotStrip
 public class ProxyJavaScriptExecutor extends JavaScriptExecutor {
+  public static class Factory implements JavaScriptExecutor.Factory {
+    private final JavaJSExecutor.Factory mJavaJSExecutorFactory;
+
+    public Factory(JavaJSExecutor.Factory javaJSExecutorFactory) {
+      mJavaJSExecutorFactory = javaJSExecutorFactory;
+    }
+
+    @Override
+    public JavaScriptExecutor create() throws Exception {
+      return new ProxyJavaScriptExecutor(mJavaJSExecutorFactory.create());
+    }
+  }
 
   static {
     SoLoader.loadLibrary(ReactBridge.REACT_NATIVE_LIB);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/WebsocketJavaScriptExecutor.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/WebsocketJavaScriptExecutor.java
index 0fba2b0a3bbf..cddadba00744 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/WebsocketJavaScriptExecutor.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/WebsocketJavaScriptExecutor.java
@@ -13,10 +13,10 @@
 
 import java.util.HashMap;
 import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import android.os.Handler;
+import android.os.Looper;
 
 import com.facebook.infer.annotation.Assertions;
 
@@ -97,9 +97,13 @@ private void connectInternal(
       String webSocketServerUrl,
       final JSExecutorConnectCallback callback) {
     final JSDebuggerWebSocketClient client = new JSDebuggerWebSocketClient();
-    final Handler timeoutHandler = new Handler();
+    final Handler timeoutHandler = new Handler(Looper.getMainLooper());
     client.connect(
         webSocketServerUrl, new JSDebuggerWebSocketClient.JSDebuggerCallback() {
+          // It's possible that both callbacks can fire on an error so make sure we only
+          // dispatch results once to our callback.
+          private boolean didSendResult = false;
+
           @Override
           public void onSuccess(@Nullable String response) {
             client.prepareJSRuntime(
@@ -108,20 +112,30 @@ public void onSuccess(@Nullable String response) {
                   public void onSuccess(@Nullable String response) {
                     timeoutHandler.removeCallbacksAndMessages(null);
                     mWebSocketClient = client;
-                    callback.onSuccess();
+                    if (!didSendResult) {
+                      callback.onSuccess();
+                      didSendResult = true;
+                    }
                   }
 
                   @Override
                   public void onFailure(Throwable cause) {
                     timeoutHandler.removeCallbacksAndMessages(null);
-                    callback.onFailure(cause);
+                    if (!didSendResult) {
+                      callback.onFailure(cause);
+                      didSendResult = true;
+                    }
                   }
                 });
           }
 
           @Override
           public void onFailure(Throwable cause) {
-            callback.onFailure(cause);
+            timeoutHandler.removeCallbacksAndMessages(null);
+            if (!didSendResult) {
+              callback.onFailure(cause);
+              didSendResult = true;
+            }
           }
         });
     timeoutHandler.postDelayed(
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
index bcc094062c02..ce60e861c7db 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
@@ -15,6 +15,9 @@
 import java.io.IOException;
 import java.util.LinkedHashMap;
 import java.util.Locale;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 import android.app.AlertDialog;
 import android.app.ProgressDialog;
@@ -35,14 +38,15 @@
 import com.facebook.infer.annotation.Assertions;
 import com.facebook.react.R;
 import com.facebook.react.bridge.CatalystInstance;
+import com.facebook.react.bridge.JavaJSExecutor;
 import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
-import com.facebook.react.bridge.ProxyJavaScriptExecutor;
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.bridge.UiThreadUtil;
 import com.facebook.react.bridge.WebsocketJavaScriptExecutor;
 import com.facebook.react.common.ReactConstants;
 import com.facebook.react.common.ShakeDetector;
+import com.facebook.react.common.futures.SimpleSettableFuture;
 import com.facebook.react.devsupport.StackTraceHelper.StackFrame;
 import com.facebook.react.modules.debug.DeveloperSettings;
 
@@ -534,38 +538,47 @@ private void reloadJSInProxyMode(final ProgressDialog progressDialog) {
     // anyway
     mDevServerHelper.launchChromeDevtools();
 
-    final WebsocketJavaScriptExecutor webSocketJSExecutor = new WebsocketJavaScriptExecutor();
-    webSocketJSExecutor.connect(
-        mDevServerHelper.getWebsocketProxyURL(),
-        new WebsocketJavaScriptExecutor.JSExecutorConnectCallback() {
-          @Override
-          public void onSuccess() {
-            progressDialog.dismiss();
-            UiThreadUtil.runOnUiThread(
-                new Runnable() {
-                  @Override
-                  public void run() {
-                    mReactInstanceCommandsHandler.onReloadWithJSDebugger(
-                        webSocketJSExecutor);
-                  }
-                });
-          }
+    JavaJSExecutor.Factory factory = new JavaJSExecutor.Factory() {
+      @Override
+      public JavaJSExecutor create() throws Exception {
+        WebsocketJavaScriptExecutor executor = new WebsocketJavaScriptExecutor();
+        SimpleSettableFuture<Boolean> future = new SimpleSettableFuture<>();
+        executor.connect(
+            mDevServerHelper.getWebsocketProxyURL(),
+            getExecutorConnectCallback(progressDialog, future));
+        // TODO(t9349129) Don't use timeout
+        try {
+          future.get(90, TimeUnit.SECONDS);
+          return executor;
+        } catch (ExecutionException e) {
+          throw (Exception) e.getCause();
+        } catch (InterruptedException | TimeoutException e) {
+          throw new RuntimeException(e);
+        }
+      }
+    };
+    mReactInstanceCommandsHandler.onReloadWithJSDebugger(factory);
+  }
 
-          @Override
-          public void onFailure(final Throwable cause) {
-            progressDialog.dismiss();
-            FLog.e(ReactConstants.TAG, "Unable to connect to remote debugger", cause);
-            UiThreadUtil.runOnUiThread(
-                new Runnable() {
-                  @Override
-                  public void run() {
-                    showNewJavaError(
-                        mApplicationContext.getString(R.string.catalyst_remotedbg_error),
-                        cause);
-                  }
-                });
-          }
-        });
+  private WebsocketJavaScriptExecutor.JSExecutorConnectCallback getExecutorConnectCallback(
+      final ProgressDialog progressDialog,
+      final SimpleSettableFuture<Boolean> future) {
+    return new WebsocketJavaScriptExecutor.JSExecutorConnectCallback() {
+      @Override
+      public void onSuccess() {
+        future.set(true);
+        progressDialog.dismiss();
+      }
+
+      @Override
+      public void onFailure(final Throwable cause) {
+        progressDialog.dismiss();
+        FLog.e(ReactConstants.TAG, "Unable to connect to remote debugger", cause);
+        future.setException(
+            new IOException(
+                mApplicationContext.getString(R.string.catalyst_remotedbg_error), cause));
+      }
+    };
   }
 
   private void reloadJSFromServer(final ProgressDialog progressDialog) {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/ReactInstanceDevCommandsHandler.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/ReactInstanceDevCommandsHandler.java
index e97b16f7d70f..ce3639be86ef 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/ReactInstanceDevCommandsHandler.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/ReactInstanceDevCommandsHandler.java
@@ -20,7 +20,7 @@ public interface ReactInstanceDevCommandsHandler {
   /**
    * Request react instance recreation with JS debugging enabled.
    */
-  void onReloadWithJSDebugger(JavaJSExecutor proxyExecutor);
+  void onReloadWithJSDebugger(JavaJSExecutor.Factory proxyExecutorFactory);
 
   /**
    * Notify react instance manager about new JS bundle version downloaded from the server.

From 80bf431f988a36e1f4b665a8340dac6ac251f6d3 Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Tue, 5 Jan 2016 09:57:31 -0800
Subject: [PATCH 0604/1411] Add warnings while upgrading RN with `react-native
 upgrade`

Summary: Closes https://github.com/facebook/react-native/pull/4854

Reviewed By: svcscm

Differential Revision: D2803252

Pulled By: foghina

fb-gh-sync-id: e6b05b19cf45773d7683ae8ae35643f400e51692
---
 local-cli/upgrade/upgrade.js | 59 +++++++++++++++++++++++++++++++++---
 1 file changed, 55 insertions(+), 4 deletions(-)

diff --git a/local-cli/upgrade/upgrade.js b/local-cli/upgrade/upgrade.js
index daecd0ba5240..4038bc6aaee4 100644
--- a/local-cli/upgrade/upgrade.js
+++ b/local-cli/upgrade/upgrade.js
@@ -9,16 +9,67 @@
 'use strict';
 
 const fs = require('fs');
+const chalk = require('chalk');
 const path = require('path');
 const Promise = require('promise');
 const yeoman = require('yeoman-environment');
+const semver = require('semver');
 
 module.exports = function upgrade(args, config) {
   args = args || process.argv;
-  let env = yeoman.createEnv();
-  let name = JSON.parse(fs.readFileSync('package.json', 'utf8')).name;
-  let generatorPath = path.join(__dirname, '..', 'generator');
+  const env = yeoman.createEnv();
+  const pak = JSON.parse(fs.readFileSync('package.json', 'utf8'));
+  const version = pak.dependencies['react-native'];
+
+  if (version) {
+    if (version === 'latest' || version === '*') {
+      console.warn(
+        chalk.yellow(
+          'Major releases are most likely to introduce breaking changes.\n' +
+          'Use a proper version number in your \'package.json\' file to avoid breakage.\n' +
+          'e.g. - ^0.18.0'
+        )
+      );
+    } else {
+      const installed = JSON.parse(fs.readFileSync('node_modules/react-native/package.json', 'utf8'));
+
+      if (semver.satisfies(installed.version, version)) {
+        const v = version.replace(/^(~|\^|=)/, '').replace(/x/i, '0');
+
+        if (semver.valid(v)) {
+          console.log(
+            'Upgrading project to react-native v' + installed.version + '\n' +
+            'Be sure to read the release notes and breaking changes:\n' +
+            chalk.blue(
+              'https://github.com/facebook/react-native/releases/tag/v' + semver.major(v) + '.' + semver.minor(v) + '.0'
+            )
+          );
+        } else {
+          console.log(
+            chalk.yellow(
+              'A valid version number for \'react-native\' is not specified your \'package.json\' file.'
+            )
+          );
+        }
+      } else {
+        console.warn(
+          chalk.yellow(
+            'react-native version in \'package.json\' doesn\'t match the installed version in \'node_modules\'.\n' +
+            'Try running \'npm install\' to fix the issue.'
+          )
+        );
+      }
+    }
+  } else {
+    console.warn(
+      chalk.yellow(
+        'Your \'package.json\' file doesn\'t seem to have \'react-native\' as a dependency.'
+      )
+    );
+  }
+
+  const generatorPath = path.join(__dirname, '..', 'generator');
   env.register(generatorPath, 'react:app');
-  let generatorArgs = ['react:app', name].concat(args);
+  const generatorArgs = ['react:app', pak.name].concat(args);
   return new Promise((resolve) => env.run(generatorArgs, {upgrade: true}, resolve));
 };

From af24619592b0f0612bec262e13c8645cd32fb5cd Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Tue, 5 Jan 2016 10:00:37 -0800
Subject: [PATCH 0605/1411] Increased RCTInlineValueThreshold for
 asynclocalstorage

Reviewed By: tadeuzagallo

Differential Revision: D2641694

fb-gh-sync-id: e35df5408730ce9ec267cbeeb556f8eba154df1f
---
 React/Modules/RCTAsyncLocalStorage.m | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/React/Modules/RCTAsyncLocalStorage.m b/React/Modules/RCTAsyncLocalStorage.m
index 344832b9aa04..46d062224d02 100644
--- a/React/Modules/RCTAsyncLocalStorage.m
+++ b/React/Modules/RCTAsyncLocalStorage.m
@@ -20,7 +20,7 @@
 
 static NSString *const RCTStorageDirectory = @"RCTAsyncLocalStorage_V1";
 static NSString *const RCTManifestFileName = @"manifest.json";
-static const NSUInteger RCTInlineValueThreshold = 100;
+static const NSUInteger RCTInlineValueThreshold = 1024;
 
 #pragma mark - Static helper functions
 

From 6edcebef9c2a6f271ec7aaca97addcaf7545e48c Mon Sep 17 00:00:00 2001
From: odino <alessandro.nadalin@gmail.com>
Date: Tue, 5 Jan 2016 10:31:42 -0800
Subject: [PATCH 0606/1411] Stop using platform-specific names for props

Summary:
Follows up on [this comment](https://github.com/facebook/react-native/pull/5065#issuecomment-168353782) by nicklockwood in #5065.

Rely on using the platform annotation and keep the API / naming less redundant.
Closes https://github.com/facebook/react-native/pull/5081

Reviewed By: svcscm

Differential Revision: D2803143

Pulled By: nicklockwood

fb-gh-sync-id: 9bdf028f5022ef46fcb63aa6c3fc931fdcc46f2b
---
 Examples/UIExplorer/WebViewExample.js          |  4 ++--
 .../Components/WebView/WebView.android.js      | 18 ++++++++++++++----
 Libraries/Components/WebView/WebView.ios.js    | 14 ++++++++++++--
 .../views/webview/ReactWebViewManager.java     |  4 ++--
 4 files changed, 30 insertions(+), 10 deletions(-)

diff --git a/Examples/UIExplorer/WebViewExample.js b/Examples/UIExplorer/WebViewExample.js
index ce489effe4bd..96f60b13110a 100644
--- a/Examples/UIExplorer/WebViewExample.js
+++ b/Examples/UIExplorer/WebViewExample.js
@@ -94,8 +94,8 @@ var WebViewExample = React.createClass({
           automaticallyAdjustContentInsets={false}
           style={styles.webView}
           url={this.state.url}
-          javaScriptEnabledAndroid={true}
-          domStorageEnabledAndroid={true}
+          javaScriptEnabled={true}
+          domStorageEnabled={true}
           onNavigationStateChange={this.onNavigationStateChange}
           onShouldStartLoadWithRequest={this.onShouldStartLoadWithRequest}
           startInLoadingState={true}
diff --git a/Libraries/Components/WebView/WebView.android.js b/Libraries/Components/WebView/WebView.android.js
index 7b227aef35b4..19e1a4f1a1a6 100644
--- a/Libraries/Components/WebView/WebView.android.js
+++ b/Libraries/Components/WebView/WebView.android.js
@@ -52,13 +52,13 @@ var WebView = React.createClass({
      * Used on Android only, JS is enabled by default for WebView on iOS
      * @platform android
      */
-    javaScriptEnabledAndroid: PropTypes.bool,
+    javaScriptEnabled: PropTypes.bool,
 
     /**
      * Used on Android only, controls whether DOM Storage is enabled or not
      * @platform android
      */
-    domStorageEnabledAndroid: PropTypes.bool,
+    domStorageEnabled: PropTypes.bool,
 
     /**
      * Sets the JS to be injected when the webpage loads.
@@ -113,6 +113,16 @@ var WebView = React.createClass({
       webViewStyles.push(styles.hidden);
     }
 
+    var {javaScriptEnabled, domStorageEnabled} = this.props;
+    if (this.props.javaScriptEnabledAndroid) {
+      console.warn('javaScriptEnabledAndroid is deprecated. Use javaScriptEnabled instead');
+      javaScriptEnabled = this.props.javaScriptEnabledAndroid;
+    }
+    if (this.props.domStorageEnabledAndroid) {
+      console.warn('domStorageEnabledAndroid is deprecated. Use domStorageEnabled instead');
+      domStorageEnabled = this.props.domStorageEnabledAndroid;
+    }
+
     var webView =
       <RCTWebView
         ref={RCT_WEBVIEW_REF}
@@ -122,8 +132,8 @@ var WebView = React.createClass({
         html={this.props.html}
         injectedJavaScript={this.props.injectedJavaScript}
         userAgent={this.props.userAgent}
-        javaScriptEnabledAndroid={this.props.javaScriptEnabledAndroid}
-        domStorageEnabledAndroid={this.props.domStorageEnabledAndroid}
+        javaScriptEnabled={javaScriptEnabled}
+        domStorageEnabled={domStorageEnabled}
         contentInset={this.props.contentInset}
         automaticallyAdjustContentInsets={this.props.automaticallyAdjustContentInsets}
         onLoadingStart={this.onLoadingStart}
diff --git a/Libraries/Components/WebView/WebView.ios.js b/Libraries/Components/WebView/WebView.ios.js
index 6713c84c978a..229df820b67e 100644
--- a/Libraries/Components/WebView/WebView.ios.js
+++ b/Libraries/Components/WebView/WebView.ios.js
@@ -114,13 +114,13 @@ var WebView = React.createClass({
      * Used on Android only, JS is enabled by default for WebView on iOS
      * @platform android
      */
-    javaScriptEnabledAndroid: PropTypes.bool,
+    javaScriptEnabled: PropTypes.bool,
 
     /**
      * Used on Android only, controls whether DOM Storage is enabled or not
      * @platform android
      */
-    domStorageEnabledAndroid: PropTypes.bool,
+    domStorageEnabled: PropTypes.bool,
 
     /**
      * Sets the JS to be injected when the webpage loads.
@@ -201,6 +201,16 @@ var WebView = React.createClass({
       RCTWebViewManager.startLoadWithResult(!!shouldStart, event.nativeEvent.lockIdentifier);
     });
 
+    var {javaScriptEnabled, domStorageEnabled} = this.props;
+    if (this.props.javaScriptEnabledAndroid) {
+      console.warn('javaScriptEnabledAndroid is deprecated. Use javaScriptEnabled instead');
+      javaScriptEnabled = this.props.javaScriptEnabledAndroid;
+    }
+    if (this.props.domStorageEnabledAndroid) {
+      console.warn('domStorageEnabledAndroid is deprecated. Use domStorageEnabled instead');
+      domStorageEnabled = this.props.domStorageEnabledAndroid;
+    }
+
     var webView =
       <RCTWebView
         ref={RCT_WEBVIEW_REF}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
index 57c2d09e3b30..22b6c01d9d09 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
@@ -251,12 +251,12 @@ protected WebView createViewInstance(ThemedReactContext reactContext) {
     return webView;
   }
 
-  @ReactProp(name = "javaScriptEnabledAndroid")
+  @ReactProp(name = "javaScriptEnabled")
   public void setJavaScriptEnabled(WebView view, boolean enabled) {
     view.getSettings().setJavaScriptEnabled(enabled);
   }
 
-  @ReactProp(name = "domStorageEnabledAndroid")
+  @ReactProp(name = "domStorageEnabled")
   public void setDomStorageEnabled(WebView view, boolean enabled) {
     view.getSettings().setDomStorageEnabled(enabled);
   }

From 0cb63bb97172e0cca4e207eed264613d6112eac4 Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Tue, 5 Jan 2016 10:45:00 -0800
Subject: [PATCH 0607/1411] Fix lint warnings in the resolver

Reviewed By: martinbigio

Differential Revision: D2803192

fb-gh-sync-id: 721821ed9ce8dd846f90ec09e7e1f36abf322b5a
---
 .../DependencyGraph/__tests__/DependencyGraph-test.js     | 8 ++++----
 .../react-packager/src/DependencyResolver/ModuleCache.js  | 2 +-
 .../src/DependencyResolver/__tests__/Module-test.js       | 4 ++--
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
index b99d60655cca..cd434a1d2098 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
@@ -2424,7 +2424,7 @@ describe('DependencyGraph', function() {
                 ' * @providesModule wontWork',
                 ' */',
                 'hi();',
-              ].join('\n')
+              ].join('\n'),
             },
           },
           // This part of the dep graph is meant to emulate internal facebook infra.
@@ -2442,7 +2442,7 @@ describe('DependencyGraph', function() {
                 ' */',
                 'hiFromInternalPackage();',
               ].join('\n'),
-            }
+            },
           },
         },
         // we need to support multiple roots and using haste between them
@@ -2453,7 +2453,7 @@ describe('DependencyGraph', function() {
             ' */',
             'wazup()',
           ].join('\n'),
-        }
+        },
       });
 
       var dgraph = new DependencyGraph({
@@ -2472,7 +2472,7 @@ describe('DependencyGraph', function() {
                 'wontWork',
                 'ember',
                 'internalVendoredPackage',
-                'anotherIndex'
+                'anotherIndex',
               ],
               isAsset: false,
               isAsset_DEPRECATED: false,
diff --git a/packager/react-packager/src/DependencyResolver/ModuleCache.js b/packager/react-packager/src/DependencyResolver/ModuleCache.js
index 0fba47a90412..a4836d0afb81 100644
--- a/packager/react-packager/src/DependencyResolver/ModuleCache.js
+++ b/packager/react-packager/src/DependencyResolver/ModuleCache.js
@@ -26,7 +26,7 @@ class ModuleCache {
         moduleCache: this,
         cache: this._cache,
         extractor: this._extractRequires,
-        depGraphHelpers: this._depGraphHelpers
+        depGraphHelpers: this._depGraphHelpers,
       });
     }
     return this._moduleCache[filePath];
diff --git a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js b/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
index 7938ca791586..ea95c43ab603 100644
--- a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
+++ b/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
@@ -56,7 +56,7 @@ describe('Module', () => {
           fastfs,
           moduleCache: new ModuleCache(fastfs, cache),
           cache: cache,
-          depGraphHelpers: new DependencyGraphHelpers()
+          depGraphHelpers: new DependencyGraphHelpers(),
         });
 
         return module.getAsyncDependencies().then(actual =>
@@ -130,7 +130,7 @@ describe('Module', () => {
           moduleCache: new ModuleCache(fastfs, cache),
           cache,
           extractor,
-          depGraphHelpers: new DependencyGraphHelpers()
+          depGraphHelpers: new DependencyGraphHelpers(),
         });
       });
     }

From a5d6e46fa82f3b0561bd1b3c77cea60e2d30d435 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Tue, 5 Jan 2016 18:51:50 +0000
Subject: [PATCH 0608/1411] Tweak the release script

---
 scripts/release.sh | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/scripts/release.sh b/scripts/release.sh
index 70b24c478d13..f2cb68e6ddc7 100755
--- a/scripts/release.sh
+++ b/scripts/release.sh
@@ -79,6 +79,8 @@ project_name="RNTestProject"
 cd /tmp/
 rm -rf "$project_name"
 react-native init "$project_name"
+
+info "Double checking the versions in package.json and build.gradle are correct:"
 grep "\"react-native\": \"\^${RELEASE}.0-rc\"" "/tmp/${project_name}/package.json" || error "Incorrect version number in /tmp/${project_name}/package.json"
 grep "com.facebook.react:react-native:${RELEASE}.+" "${project_name}/android/app/build.gradle" || error "Incorrect version number in /tmp/${project_name}/android/app/build.gradle"
 
@@ -88,7 +90,7 @@ info "Test the following both on Android and iOS:"
 info "   - Verify that packager opens in new Window"
 info "   - Verify that you see the 'Welcome to React Native' screen"
 info "   - Verify 'Reload JS' works"
-info "   - Test Chrome debugger by adding breakpoints (we don't have tests for Chrome debugging)"
+info "   - Test Chrome debugger by adding breakpoints. We don't have tests for Chrome debugging."
 info ""
 
 info "Press any key to run the sample in Android emulator/device"
@@ -101,10 +103,6 @@ open "/tmp/${project_name}/ios/${project_name}.xcodeproj"
 
 cd "$repo_root"
 
-info "Press any key to view the diff"
-read -n 1
-git diff
-
 info "Press any key to commit changes"
 read -n 1
 git commit -am "[${RELEASE}.0-rc] Bump version numbers"

From 6663726b6e3481b9295b89fcbe9d0e768b2b11ab Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Tue, 5 Jan 2016 19:24:48 +0000
Subject: [PATCH 0609/1411] small hack to have circle.yml in gh-pages generated
 branch

---
 website/publish.sh | 1 +
 1 file changed, 1 insertion(+)

diff --git a/website/publish.sh b/website/publish.sh
index 7d34e18758f7..28ec151e9e9a 100755
--- a/website/publish.sh
+++ b/website/publish.sh
@@ -21,6 +21,7 @@ rm -Rf *
 cd ../react-native/website
 node server/generate.js
 cp -R build/react-native/* ../../react-native-gh-pages/
+cp ../circle.yml ../../react-native-gh-pages/
 rm -Rf build/
 cd ../../react-native-gh-pages
 git status

From 2462c8f87d19906bdc994032402b1fdd9acba19e Mon Sep 17 00:00:00 2001
From: odino <alessandro.nadalin@gmail.com>
Date: Tue, 5 Jan 2016 11:39:53 -0800
Subject: [PATCH 0610/1411] Enables webview debugging

Summary:
2 things that I want to clarify / ask for feedback:

* do we really need to make sure we're running on the UI thread? I guess `onPageStarted` maybe already runs there? Couldnt find anything [here](http://developer.android.com/reference/android/webkit/WebView.html) though
* everytime a page starts we re-enable debugging -- it's a bit useless but I also don't think it's a huge problem, as debugging should only be enabled in dev

Relates to issue #4857, where we switched debugging off as, in some circumstances, it would crash the application as debugging was invoked outside the UI thread.
Closes https://github.com/facebook/react-native/pull/5071

Reviewed By: svcscm

Differential Revision: D2803649

Pulled By: astreet

fb-gh-sync-id: 523d3b442b196d6c54b14ba0c2b29601095c3363
---
 .../react/views/webview/ReactWebViewManager.java     | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
index 22b6c01d9d09..5400210d6748 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
@@ -74,13 +74,6 @@ public class ReactWebViewManager extends SimpleViewManager<WebView> {
 
   private WebViewConfig mWebViewConfig;
 
-  static {
-    if (ReactBuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
-      // TODO(T9455950): re-enable debugging
-      // WebView.setWebContentsDebuggingEnabled(true);
-    }
-  }
-
   private static class ReactWebViewClient extends WebViewClient {
 
     private boolean mLastLoadFailed = false;
@@ -248,6 +241,11 @@ protected WebView createViewInstance(ThemedReactContext reactContext) {
     ReactWebView webView = new ReactWebView(reactContext);
     reactContext.addLifecycleEventListener(webView);
     mWebViewConfig.configWebView(webView);
+
+    if (ReactBuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+      WebView.setWebContentsDebuggingEnabled(true);
+    }
+
     return webView;
   }
 

From 180fc06b7a54cd48a9ed7ace661cc4cdd262a689 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Tue, 5 Jan 2016 12:50:25 -0800
Subject: [PATCH 0611/1411] Fixed iOS 7 support for URL query functions

Summary:
public
Unfortunately, it turns out that NSURLComponents.queryItems only works on iOS 8 and above. This diff re-implements the RCTGetURLQueryParam and RCTURLByReplacingQueryParam functions using functionality available in iOS 7.

Reviewed By: javache

Differential Revision: D2803679

fb-gh-sync-id: 56f10bef4894d16197975b6023b7aa5ab106d8cb
---
 .../UIExplorerUnitTests/RCTURLUtilsTests.m    | 14 +++++++
 React/Base/RCTUtils.m                         | 40 +++++++++++++++----
 2 files changed, 46 insertions(+), 8 deletions(-)

diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTURLUtilsTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTURLUtilsTests.m
index bb22b7eb41c5..2c23af2b9926 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTURLUtilsTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTURLUtilsTests.m
@@ -30,6 +30,13 @@ - (void)testGetQueryParam
   XCTAssertEqualObjects(bar, @"foo");
 }
 
+- (void)testGetEncodedParam
+{
+  NSURL *URL = [NSURL URLWithString:@"http://example.com?foo=You%20%26%20Me"];
+  NSString *foo = RCTGetURLQueryParam(URL, @"foo");
+  XCTAssertEqualObjects(foo, @"You & Me");
+}
+
 - (void)testQueryParamNotFound
 {
   NSURL *URL = [NSURL URLWithString:@"http://example.com?foo=bar"];
@@ -58,6 +65,13 @@ - (void)testReplaceParam
   XCTAssertEqualObjects(result.absoluteString, @"http://example.com?foo=foo&bar=foo");
 }
 
+- (void)testReplaceEncodedParam
+{
+  NSURL *URL = [NSURL URLWithString:@"http://example.com?foo=You%20%26%20Me"];
+  NSURL *result = RCTURLByReplacingQueryParam(URL, @"foo", @"Me & You");
+  XCTAssertEqualObjects(result.absoluteString, @"http://example.com?foo=Me%20%26%20You");
+}
+
 - (void)testAppendParam
 {
   NSURL *URL = [NSURL URLWithString:@"http://example.com?bar=foo"];
diff --git a/React/Base/RCTUtils.m b/React/Base/RCTUtils.m
index b3a7a6e41b54..5a83b8adb029 100644
--- a/React/Base/RCTUtils.m
+++ b/React/Base/RCTUtils.m
@@ -591,9 +591,13 @@ static void RCTGetRGBAColorComponents(CGColorRef color, CGFloat rgba[4])
   }
   NSURLComponents *components = [NSURLComponents componentsWithURL:URL
                                            resolvingAgainstBaseURL:YES];
-  for (NSURLQueryItem *item in components.queryItems.reverseObjectEnumerator) {
-    if ([item.name isEqualToString:param]) {
-      return item.value;
+
+  // TODO: use NSURLComponents.queryItems once we drop support for iOS 7
+  for (NSString *item in [components.percentEncodedQuery componentsSeparatedByString:@"&"].reverseObjectEnumerator) {
+    NSArray *keyValue = [item componentsSeparatedByString:@"="];
+    NSString *key = [keyValue.firstObject stringByRemovingPercentEncoding];
+    if ([key isEqualToString:param]) {
+      return [keyValue.lastObject stringByRemovingPercentEncoding];
     }
   }
   return nil;
@@ -607,22 +611,42 @@ static void RCTGetRGBAColorComponents(CGColorRef color, CGFloat rgba[4])
   }
   NSURLComponents *components = [NSURLComponents componentsWithURL:URL
                                            resolvingAgainstBaseURL:YES];
+
+  // TODO: use NSURLComponents.queryItems once we drop support for iOS 7
+
+  // Unhelpfully, iOS doesn't provide this set as a constant
+  static NSCharacterSet *URLParamCharacterSet;
+  static dispatch_once_t onceToken;
+  dispatch_once(&onceToken, ^{
+    NSMutableCharacterSet *characterSet = [NSMutableCharacterSet new];
+    [characterSet formUnionWithCharacterSet:[NSCharacterSet URLQueryAllowedCharacterSet]];
+    [characterSet removeCharactersInString:@"&=?"];
+    URLParamCharacterSet = [characterSet copy];
+  });
+
+  NSString *encodedParam =
+  [param stringByAddingPercentEncodingWithAllowedCharacters:URLParamCharacterSet];
+
   __block NSInteger paramIndex = NSNotFound;
-  NSMutableArray *queryItems = [components.queryItems mutableCopy];
+  NSMutableArray *queryItems = [[components.percentEncodedQuery componentsSeparatedByString:@"&"] mutableCopy];
   [queryItems enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:
-   ^(NSURLQueryItem *item, NSUInteger i, BOOL *stop) {
-     if ([item.name isEqualToString:param]) {
+   ^(NSString *item, NSUInteger i, BOOL *stop) {
+     NSArray *keyValue = [item componentsSeparatedByString:@"="];
+     if ([keyValue.firstObject isEqualToString:encodedParam]) {
        paramIndex = i;
        *stop = YES;
      }
    }];
 
-  NSURLQueryItem *newItem = [NSURLQueryItem queryItemWithName:param value:value];
+  NSString *encodedValue =
+  [value stringByAddingPercentEncodingWithAllowedCharacters:URLParamCharacterSet];
+
+  NSString *newItem = [encodedParam stringByAppendingFormat:@"=%@", encodedValue];
   if (paramIndex == NSNotFound) {
     [queryItems addObject:newItem];
   } else {
     [queryItems replaceObjectAtIndex:paramIndex withObject:newItem];
   }
-  components.queryItems = queryItems;
+  components.percentEncodedQuery = [queryItems componentsJoinedByString:@"&"];
   return components.URL;
 }

From ec762717153bbe434e4b8188898f35e3491c88ed Mon Sep 17 00:00:00 2001
From: Alex Kotliarskyi <alex.frantic@gmail.com>
Date: Tue, 5 Jan 2016 15:21:25 -0800
Subject: [PATCH 0612/1411] Return non-zero exit code from wrong-react-native

Summary:
When used in automation, `wrong-react-native` can cause problems because it does not
report the issue via exit code.
Closes https://github.com/facebook/react-native/pull/5114

Reviewed By: svcscm

Differential Revision: D2799995

Pulled By: frantic

fb-gh-sync-id: 23c32dac9b0fcdbeaf48b94e9cb220c6c1b344aa
---
 local-cli/wrong-react-native.js | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/local-cli/wrong-react-native.js b/local-cli/wrong-react-native.js
index bbc0a02919cb..44759e4b2bb7 100755
--- a/local-cli/wrong-react-native.js
+++ b/local-cli/wrong-react-native.js
@@ -15,3 +15,5 @@ console.error([
   'npm uninstall -g react-native',
   'npm install -g react-native-cli'
 ].join('\n'));
+
+process.exit(1);

From 8772a6a542ad07f06ef4048a8e06240a3a612aa0 Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Tue, 5 Jan 2016 15:29:23 -0800
Subject: [PATCH 0613/1411] Wait for JSExecutor to tear down in RCTBridgeTests

Reviewed By: tadeuzagallo

Differential Revision: D2803092

fb-gh-sync-id: 71ccac2c13221bfbcb2f09a14d48ac2d2901d04e
---
 .../UIExplorerUnitTests/RCTBridgeTests.m      | 42 ++++++++++++-------
 Libraries/RCTTest/RCTTestRunner.m             |  3 +-
 2 files changed, 28 insertions(+), 17 deletions(-)

diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m
index fe2f48c5c70d..d428fb441819 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m
@@ -21,6 +21,16 @@
 #import "RCTJavaScriptExecutor.h"
 #import "RCTUtils.h"
 
+
+#define RUN_RUNLOOP_WHILE(CONDITION) \
+_Pragma("clang diagnostic push") \
+_Pragma("clang diagnostic ignored \"-Wshadow\"") \
+NSDate *timeout = [[NSDate date] dateByAddingTimeInterval:0.1]; \
+while ((CONDITION) && [timeout timeIntervalSinceNow] > 0) { \
+[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:timeout]; \
+} \
+_Pragma("clang diagnostic pop")
+
 @interface TestExecutor : NSObject <RCTJavaScriptExecutor>
 
 @property (nonatomic, readonly, copy) NSMutableDictionary<NSString *, id> *injectedStuff;
@@ -93,6 +103,8 @@ - (void)invalidate {}
 @interface RCTBridgeTests : XCTestCase <RCTBridgeModule>
 {
   RCTBridge *_bridge;
+  __weak TestExecutor *_jsExecutor;
+
   BOOL _testMethodCalled;
 }
 @end
@@ -112,35 +124,34 @@ - (void)setUp
                                    launchOptions:nil];
 
   _bridge.executorClass = [TestExecutor class];
+
   // Force to recreate the executor with the new class
   // - reload: doesn't work here since bridge hasn't loaded yet.
   [_bridge invalidate];
   [_bridge setUp];
+
+  _jsExecutor = [_bridge.batchedBridge valueForKey:@"javaScriptExecutor"];
+  XCTAssertNotNil(_jsExecutor);
 }
 
 - (void)tearDown
 {
   [super tearDown];
 
-  [_bridge invalidate];
   _testMethodCalled = NO;
-}
 
-#define RUN_RUNLOOP_WHILE(CONDITION) \
-_Pragma("clang diagnostic push") \
-_Pragma("clang diagnostic ignored \"-Wshadow\"") \
-NSDate *timeout = [[NSDate date] dateByAddingTimeInterval:0.1]; \
-while ((CONDITION) && [timeout timeIntervalSinceNow] > 0) { \
-  [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:timeout]; \
-} \
-_Pragma("clang diagnostic pop")
+  [_bridge invalidate];
+  _bridge = nil;
+
+  RUN_RUNLOOP_WHILE(_jsExecutor != nil);
+  XCTAssertNotNil(_jsExecutor);
+}
 
 - (void)testHookRegistration
 {
-  TestExecutor *executor =  [_bridge.batchedBridge valueForKey:@"_javaScriptExecutor"];
-
   NSString *injectedStuff;
-  RUN_RUNLOOP_WHILE(!(injectedStuff = executor.injectedStuff[@"__fbBatchedBridgeConfig"]));
+  RUN_RUNLOOP_WHILE(!(injectedStuff = _jsExecutor.injectedStuff[@"__fbBatchedBridgeConfig"]));
+  XCTAssertNotNil(injectedStuff);
 
   __block NSNumber *testModuleID = nil;
   __block NSDictionary<NSString *, id> *testConstants = nil;
@@ -165,10 +176,9 @@ - (void)testHookRegistration
 
 - (void)testCallNativeMethod
 {
-  TestExecutor *executor =  [_bridge.batchedBridge valueForKey:@"_javaScriptExecutor"];
-
   NSString *injectedStuff;
-  RUN_RUNLOOP_WHILE(!(injectedStuff = executor.injectedStuff[@"__fbBatchedBridgeConfig"]));
+  RUN_RUNLOOP_WHILE(!(injectedStuff = _jsExecutor.injectedStuff[@"__fbBatchedBridgeConfig"]));
+  XCTAssertNotNil(injectedStuff);
 
   __block NSNumber *testModuleID = nil;
   __block NSNumber *testMethodID = nil;
diff --git a/Libraries/RCTTest/RCTTestRunner.m b/Libraries/RCTTest/RCTTestRunner.m
index 46a3a2abee4a..6203d0f1dbf3 100644
--- a/Libraries/RCTTest/RCTTestRunner.m
+++ b/Libraries/RCTTest/RCTTestRunner.m
@@ -16,6 +16,7 @@
 #import "RCTTestModule.h"
 #import "RCTUtils.h"
 #import "RCTJSCExecutor.h"
+#import "RCTBridge+Private.h"
 
 static const NSTimeInterval kTestTimeoutSeconds = 60;
 static const NSTimeInterval kTestTeardownTimeoutSeconds = 30;
@@ -134,7 +135,7 @@ - (void)runTest:(SEL)test module:(NSString *)moduleName
 
     // Take a weak reference to the JS context, so we track its deallocation later
     // (we can only do this now, since it's been lazily initialized)
-    id jsExecutor = [bridge valueForKeyPath:@"batchedBridge.javaScriptExecutor"];
+    id jsExecutor = [bridge.batchedBridge valueForKey:@"javaScriptExecutor"];
     if ([jsExecutor isKindOfClass:[RCTJSCExecutor class]]) {
       weakJSContext = [jsExecutor valueForKey:@"_context"];
     }

From 9490c2c759fc2d88907a7a450d307be7f717853a Mon Sep 17 00:00:00 2001
From: Alex Kotliarskyi <alex.frantic@gmail.com>
Date: Tue, 5 Jan 2016 17:11:53 -0800
Subject: [PATCH 0614/1411] Added `react-native run-ios`

Summary:
Works the same way as `react-native run-android`, but targets iOS simulator instead. Under the hood, it uses `xcodebuild` to compile the app and store it in `ios/build` folder, then triggers `instruments` and `simctl` to install and launch the app on simulator.

Since Facebook relies on BUCK to build and run iOS app, we probably won't use `run-ios` internally. That's why I'm putting this as public PR instead of internal diff.

To test this, I hacked global `react-native` script to install react native from my local checkout instead of from npm, cd into the folder and ran `react-native run-ios`.
Closes https://github.com/facebook/react-native/pull/5119

Reviewed By: svcscm

Differential Revision: D2805199

Pulled By: frantic

fb-gh-sync-id: 423a45ba885cb5e48a16ac22095d757d8cca7e37
---
 local-cli/cli.js                              |  2 +
 local-cli/generator-ios/index.js              |  3 +
 .../runIOS/__tests__/findXcodeProject-test.js | 57 +++++++++++
 .../__tests__/parseIOSSimulatorsList-test.js  | 53 +++++++++++
 local-cli/runIOS/findXcodeProject.js          | 43 +++++++++
 local-cli/runIOS/parseIOSSimulatorsList.js    | 49 ++++++++++
 local-cli/runIOS/runIOS.js                    | 95 +++++++++++++++++++
 7 files changed, 302 insertions(+)
 create mode 100644 local-cli/runIOS/__tests__/findXcodeProject-test.js
 create mode 100644 local-cli/runIOS/__tests__/parseIOSSimulatorsList-test.js
 create mode 100644 local-cli/runIOS/findXcodeProject.js
 create mode 100644 local-cli/runIOS/parseIOSSimulatorsList.js
 create mode 100644 local-cli/runIOS/runIOS.js

diff --git a/local-cli/cli.js b/local-cli/cli.js
index 9fd1fda7f1a5..767c642476d3 100644
--- a/local-cli/cli.js
+++ b/local-cli/cli.js
@@ -25,6 +25,7 @@ var link = require('./library/link');
 var path = require('path');
 var Promise = require('promise');
 var runAndroid = require('./runAndroid/runAndroid');
+var runIOS = require('./runIOS/runIOS');
 var server = require('./server/server');
 var TerminalAdapter = require('yeoman-environment/lib/adapter.js');
 var yeoman = require('yeoman-environment');
@@ -46,6 +47,7 @@ var documentedCommands = {
   'link': [link, 'Adds a third-party library to your project. Example: react-native link awesome-camera'],
   'android': [generateWrapper, 'generates an Android project for your app'],
   'run-android': [runAndroid, 'builds your app and starts it on a connected Android emulator or device'],
+  'run-ios': [runIOS, 'builds your app and starts it on iOS simulator'],
   'upgrade': [upgrade, 'upgrade your app\'s template files to the latest version; run this after ' +
                        'updating the react-native version in your package.json and running npm install']
 };
diff --git a/local-cli/generator-ios/index.js b/local-cli/generator-ios/index.js
index 1e1afb67b78e..28e3c442d787 100644
--- a/local-cli/generator-ios/index.js
+++ b/local-cli/generator-ios/index.js
@@ -49,6 +49,9 @@ module.exports = yeoman.generators.NamedBase.extend({
   end: function() {
     var projectPath = path.resolve(this.destinationRoot(), 'ios', this.name);
     this.log(chalk.white.bold('To run your app on iOS:'));
+    this.log(chalk.white('   cd ' + this.destinationRoot()));
+    this.log(chalk.white('   react-native run-ios'));
+    this.log(chalk.white('   - or -'));
     this.log(chalk.white('   Open ' + projectPath + '.xcodeproj in Xcode'));
     this.log(chalk.white('   Hit the Run button'));
   }
diff --git a/local-cli/runIOS/__tests__/findXcodeProject-test.js b/local-cli/runIOS/__tests__/findXcodeProject-test.js
new file mode 100644
index 000000000000..d0e3832be54e
--- /dev/null
+++ b/local-cli/runIOS/__tests__/findXcodeProject-test.js
@@ -0,0 +1,57 @@
+/**
+ * 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.
+ */
+'use strict';
+
+jest.dontMock('../findXcodeProject');
+
+const findXcodeProject = require('../findXcodeProject');
+
+describe('findXcodeProject', () => {
+  it('should find *.xcodeproj file', () => {
+    expect(findXcodeProject([
+      '.DS_Store',
+      'AwesomeApp',
+      'AwesomeApp.xcodeproj',
+      'AwesomeAppTests',
+      'PodFile',
+      'Podfile.lock',
+      'Pods'
+    ])).toEqual({
+      name: 'AwesomeApp.xcodeproj',
+      isWorkspace: false,
+    });
+  });
+
+  it('should prefer *.xcworkspace', () => {
+    expect(findXcodeProject([
+      '.DS_Store',
+      'AwesomeApp',
+      'AwesomeApp.xcodeproj',
+      'AwesomeApp.xcworkspace',
+      'AwesomeAppTests',
+      'PodFile',
+      'Podfile.lock',
+      'Pods'
+    ])).toEqual({
+      name: 'AwesomeApp.xcworkspace',
+      isWorkspace: true,
+    });
+  });
+
+  it('should return null if nothing found', () => {
+    expect(findXcodeProject([
+      '.DS_Store',
+      'AwesomeApp',
+      'AwesomeAppTests',
+      'PodFile',
+      'Podfile.lock',
+      'Pods'
+    ])).toEqual(null);
+  });
+});
diff --git a/local-cli/runIOS/__tests__/parseIOSSimulatorsList-test.js b/local-cli/runIOS/__tests__/parseIOSSimulatorsList-test.js
new file mode 100644
index 000000000000..92396fe4a82a
--- /dev/null
+++ b/local-cli/runIOS/__tests__/parseIOSSimulatorsList-test.js
@@ -0,0 +1,53 @@
+/**
+ * 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.
+ */
+
+'use strict';
+
+jest.dontMock('../parseIOSSimulatorsList');
+var parseIOSSimulatorsList = require('../parseIOSSimulatorsList');
+
+describe('parseIOSSimulatorsList', () => {
+  it('parses typical output', () => {
+    var simulators = parseIOSSimulatorsList([
+      '== Devices ==',
+      '-- iOS 8.1 --',
+      '    iPhone 4s (4FE43B33-EF13-49A5-B6A6-658D32F20988) (Shutdown)',
+      '-- iOS 8.4 --',
+      '    iPhone 4s (EAB622C7-8ADE-4FAE-A911-94C0CA4709BB) (Shutdown)',
+      '    iPhone 5 (AE1CD3D0-A85B-4A73-B320-9CA7BA4FAEB0) (Shutdown)',
+    ].join('\n'));
+
+    expect(simulators).toEqual([
+      {name: 'iPhone 4s', udid: '4FE43B33-EF13-49A5-B6A6-658D32F20988', version: '8.1'},
+      {name: 'iPhone 4s', udid: 'EAB622C7-8ADE-4FAE-A911-94C0CA4709BB', version: '8.4'},
+      {name: 'iPhone 5',  udid: 'AE1CD3D0-A85B-4A73-B320-9CA7BA4FAEB0', version: '8.4'},
+    ]);
+  });
+
+  it('ignores unavailable simulators', () => {
+    var simulators = parseIOSSimulatorsList([
+      '== Devices ==',
+      '-- iOS 8.1 --',
+      '    iPhone 4s (4FE43B33-EF13-49A5-B6A6-658D32F20988) (Shutdown)',
+      '-- Unavailable: com.apple.CoreSimulator.SimRuntime.iOS-8-3 --',
+      '    iPhone 5s (EAB622C7-8ADE-4FAE-A911-94C0CA4709BB) (Shutdown)',
+    ].join('\n'));
+
+    expect(simulators).toEqual([{
+      name: 'iPhone 4s',
+      udid: '4FE43B33-EF13-49A5-B6A6-658D32F20988',
+      version: '8.1',
+    }]);
+
+  });
+
+  it('ignores garbage', () => {
+    expect(parseIOSSimulatorsList('Something went terribly wrong (-42)')).toEqual([]);
+  });
+});
diff --git a/local-cli/runIOS/findXcodeProject.js b/local-cli/runIOS/findXcodeProject.js
new file mode 100644
index 000000000000..0d6cd302c6d0
--- /dev/null
+++ b/local-cli/runIOS/findXcodeProject.js
@@ -0,0 +1,43 @@
+/**
+ * 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
+ */
+'use strict';
+
+const path = require('path');
+
+type ProjectInfo = {
+  name: string;
+  isWorkspace: boolean;
+}
+
+function findXcodeProject(files: Array<string>): ?ProjectInfo {
+  const sortedFiles = files.sort();
+  for (let i = sortedFiles.length - 1; i >= 0; i--) {
+    const fileName = files[i];
+    const ext = path.extname(fileName);
+
+    if (ext === '.xcworkspace') {
+      return {
+        name: fileName,
+        isWorkspace: true,
+      };
+    }
+    if (ext === '.xcodeproj') {
+      return {
+        name: fileName,
+        isWorkspace: false,
+      };
+    }
+  }
+
+  return null;
+}
+
+module.exports = findXcodeProject;
diff --git a/local-cli/runIOS/parseIOSSimulatorsList.js b/local-cli/runIOS/parseIOSSimulatorsList.js
new file mode 100644
index 000000000000..66f0d0ffaf62
--- /dev/null
+++ b/local-cli/runIOS/parseIOSSimulatorsList.js
@@ -0,0 +1,49 @@
+/**
+ * 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
+ */
+'use strict';
+
+type IOSSimulatorInfo = {
+  name: string;
+  udid: string;
+  version: string;
+}
+
+/**
+ * Parses the output of `xcrun simctl list devices` command
+ */
+function parseIOSSimulatorsList(text: string): Array<IOSSimulatorInfo> {
+  const devices = [];
+  var currentOS = null;
+
+  text.split('\n').forEach((line) => {
+    var section = line.match(/^-- (.+) --$/);
+    if (section) {
+      var header = section[1].match(/^iOS (.+)$/);
+      if (header) {
+        currentOS = header[1];
+      } else {
+        currentOS = null;
+      }
+      return;
+    }
+
+    const device = line.match(/^[ ]*([^()]+) \(([^()]+)\)/);
+    if (device && currentOS) {
+      var name = device[1];
+      var udid = device[2];
+      devices.push({udid, name, version: currentOS});
+    }
+  });
+
+  return devices;
+}
+
+module.exports = parseIOSSimulatorsList;
diff --git a/local-cli/runIOS/runIOS.js b/local-cli/runIOS/runIOS.js
new file mode 100644
index 000000000000..00249820e0d1
--- /dev/null
+++ b/local-cli/runIOS/runIOS.js
@@ -0,0 +1,95 @@
+/**
+ * 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.
+ */
+'use strict';
+
+const child_process = require('child_process');
+const fs = require('fs');
+const path = require('path');
+const parseCommandLine = require('../util/parseCommandLine');
+const findXcodeProject = require('./findXcodeProject');
+const parseIOSSimulatorsList = require('./parseIOSSimulatorsList');
+const Promise = require('promise');
+
+/**
+ * Starts the app on iOS simulator
+ */
+function runIOS(argv, config) {
+  return new Promise((resolve, reject) => {
+    _runIOS(argv, config, resolve, reject);
+    resolve();
+  });
+}
+
+function _runIOS(argv, config, resolve, reject) {
+  const args = parseCommandLine([{
+    command: 'simulator',
+    description: 'Explicitly set simulator to use',
+    type: 'string',
+    required: false,
+    default: 'iPhone 6',
+  }], argv);
+
+  process.chdir('ios');
+  const xcodeProject = findXcodeProject(fs.readdirSync('.'));
+  if (!xcodeProject) {
+    throw new Error(`Could not find Xcode project files in ios folder`);
+  }
+
+  const inferredSchemeName = path.basename(xcodeProject.name, path.extname(xcodeProject.name));
+  console.log(`Found Xcode ${xcodeProject.isWorkspace ? 'workspace' : 'project'} ${xcodeProject.name}`);
+
+  const simulators = parseIOSSimulatorsList(
+    child_process.execFileSync('xcrun', ['simctl', 'list', 'devices'], {encoding: 'utf8'})
+  );
+  const selectedSimulator = matchingSimulator(simulators, args.simulator);
+  if (!selectedSimulator) {
+    throw new Error(`Cound't find ${args.simulator} simulator`);
+  }
+
+  const simulatorFullName = `${selectedSimulator.name} (${selectedSimulator.version})`;
+  console.log(`Launching ${simulatorFullName}...`);
+  try {
+    child_process.spawnSync('xcrun', ['instruments', '-w', simulatorFullName]);
+  } catch(e) {
+    // instruments always fail with 255 because it expects more arguments,
+    // but we want it to only launch the simulator
+  }
+
+  const xcodebuildArgs = [
+    xcodeProject.isWorkspace ? '-workspace' : '-project', xcodeProject.name,
+    '-scheme', inferredSchemeName,
+    '-destination', `id=${selectedSimulator.udid}`,
+    '-derivedDataPath', 'build',
+  ];
+  console.log(`Building using "xcodebuild ${xcodebuildArgs.join(' ')}"`);
+  child_process.spawnSync('xcodebuild', xcodebuildArgs, {stdio: 'inherit'});
+
+  const appPath = `build/Build/Products/Debug-iphonesimulator/${inferredSchemeName}.app`;
+  console.log(`Installing ${appPath}`);
+  child_process.spawnSync('xcrun', ['simctl', 'install', 'booted', appPath], {stdio: 'inherit'});
+
+  const bundleID = child_process.execFileSync(
+    '/usr/libexec/PlistBuddy',
+    ['-c', 'Print:CFBundleIdentifier', path.join(appPath, 'Info.plist')],
+    {encoding: 'utf8'}
+  ).trim();
+
+  console.log(`Launching ${bundleID}`);
+  child_process.spawnSync('xcrun', ['simctl', 'launch', 'booted', bundleID], {stdio: 'inherit'});
+}
+
+function matchingSimulator(simulators, simulatorName) {
+  for (let i = simulators.length - 1; i >= 0; i--) {
+    if (simulators[i].name === simulatorName) {
+      return simulators[i];
+    }
+  }
+}
+
+module.exports = runIOS;

From 5a4ee0bfaa6e6db7a105362a06fb903efa5f58a4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Tue, 5 Jan 2016 21:56:41 -0800
Subject: [PATCH 0615/1411] Pipe transforms errors through transformation
 pipelines

Summary:
public

Fixes an issue on the transforms pipeline which caused not to pipe errors that occured on the external transformer to JSTransformer.

Reviewed By: yungsters

Differential Revision: D2806498

fb-gh-sync-id: c9347d1957a3a9320b3f177ff9b19bf3802087a0
---
 packager/react-packager/src/JSTransformer/worker.js | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/packager/react-packager/src/JSTransformer/worker.js b/packager/react-packager/src/JSTransformer/worker.js
index 77a24938e598..ef4a529c97bd 100644
--- a/packager/react-packager/src/JSTransformer/worker.js
+++ b/packager/react-packager/src/JSTransformer/worker.js
@@ -32,6 +32,11 @@ function internalTransforms(sourceCode, filename, options) {
 }
 
 function onExternalTransformDone(data, callback, error, externalOutput) {
+  if (error) {
+    callback(error);
+    return;
+  }
+
   var result;
   if (data.options.enableInternalTransforms) {
     result = internalTransforms(

From f421d2b0565513e947ceef46e44980fbc9ff86dc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Tue, 5 Jan 2016 22:02:14 -0800
Subject: [PATCH 0616/1411] Fix cache errors

Reviewed By: yungsters

Differential Revision: D2806495

fb-gh-sync-id: 4c1088cde8f0b88070f31b3a130b66f20a2a07cb
---
 packager/react-packager/src/DependencyResolver/Cache/index.js | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/packager/react-packager/src/DependencyResolver/Cache/index.js b/packager/react-packager/src/DependencyResolver/Cache/index.js
index 8552e0dcf086..84b7524d7538 100644
--- a/packager/react-packager/src/DependencyResolver/Cache/index.js
+++ b/packager/react-packager/src/DependencyResolver/Cache/index.js
@@ -135,6 +135,10 @@ class Cache {
       .then(values => {
         var json = Object.create(null);
         Object.keys(data).forEach((key, i) => {
+          if (!values[i]) {
+            return;
+          }
+
           json[key] = Object.create(null);
           json[key].metadata = data[key].metadata;
           json[key].data = values[i].data;

From 216725e565b08568146b3aceb1e7122385243c71 Mon Sep 17 00:00:00 2001
From: SangYeob Bono Yu <deminoth@gmail.com>
Date: Wed, 6 Jan 2016 18:18:43 +0900
Subject: [PATCH 0617/1411] added ShareHows app to showcase

---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 0fe4a9f19998..0036dd053cb8 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -416,6 +416,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/sg-toto-4d/id1006371481?mt=8',
     author: 'Steve Ng'
   },
+  {
+    name: 'ShareHows',
+    icon: 'http://a4.mzstatic.com/us/r30/Purple5/v4/78/1c/83/781c8325-a1e1-4afc-f106-a629bcf3c6ef/icon175x175.png',
+    link: 'https://itunes.apple.com/kr/app/sweeohauseu-sesang-ui-modeun/id1060914858?mt=8',
+    author: 'Dobbit Co., Ltd.'
+  },
   {
     name: 'Spero for Cancer',
     icon: 'https://s3-us-west-1.amazonaws.com/cancerspot/site_images/Spero1024.png',

From 7d70b86a7bd46734d44ca47c58a15a9372e66a89 Mon Sep 17 00:00:00 2001
From: Milen Dzhumerov <mgd@fb.com>
Date: Wed, 6 Jan 2016 03:54:25 -0800
Subject: [PATCH 0618/1411] RCTImageUtils Obj-C nullability annotations

Summary:
Add Objective-C nullability annotations to RCTImageUtils

public

Reviewed By: nicklockwood

Differential Revision: D2797310

fb-gh-sync-id: 08329f70d1a09bf47865c9e7e76d7b4340eb6e80
---
 Libraries/Image/RCTImageUtils.h | 16 ++++++++++------
 Libraries/Image/RCTImageUtils.m | 12 ++++++------
 2 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/Libraries/Image/RCTImageUtils.h b/Libraries/Image/RCTImageUtils.h
index b9a118ec1711..cb65449db973 100644
--- a/Libraries/Image/RCTImageUtils.h
+++ b/Libraries/Image/RCTImageUtils.h
@@ -12,6 +12,8 @@
 
 #import "RCTDefines.h"
 
+NS_ASSUME_NONNULL_BEGIN
+
 /**
  * This function takes an input content size (typically from an image), a target
  * size and scale that it will be drawn at (typically in a CGContext) and then
@@ -53,16 +55,16 @@ RCT_EXTERN CGSize RCTSizeInPixels(CGSize pointSize, CGFloat scale);
  * width/height of the returned image is guaranteed to be >= destSize.
  * Pass a destSize of CGSizeZero to decode the image at its original size.
  */
-RCT_EXTERN UIImage *RCTDecodeImageWithData(NSData *data,
-                                           CGSize destSize,
-                                           CGFloat destScale,
-                                           UIViewContentMode resizeMode);
+RCT_EXTERN UIImage *__nullable RCTDecodeImageWithData(NSData *data,
+                                                      CGSize destSize,
+                                                      CGFloat destScale,
+                                                      UIViewContentMode resizeMode);
 
 /**
  * This function takes the source data for an image and decodes just the
  * metadata, without decompressing the image itself.
  */
-RCT_EXTERN NSDictionary<NSString *, id> *RCTGetImageMetadata(NSData *data);
+RCT_EXTERN NSDictionary<NSString *, id> *__nullable RCTGetImageMetadata(NSData *data);
 
 /**
  * Convert an image back into data. Images with an alpha channel will be
@@ -71,4 +73,6 @@ RCT_EXTERN NSDictionary<NSString *, id> *RCTGetImageMetadata(NSData *data);
  * conversion, with 1.0 being maximum quality. It has no effect for images
  * using PNG compression.
  */
-RCT_EXTERN NSData *RCTGetImageData(CGImageRef image, float quality);
+RCT_EXTERN NSData *__nullable RCTGetImageData(CGImageRef image, float quality);
+
+NS_ASSUME_NONNULL_END
diff --git a/Libraries/Image/RCTImageUtils.m b/Libraries/Image/RCTImageUtils.m
index a9476ff51e79..0b51eca7241d 100644
--- a/Libraries/Image/RCTImageUtils.m
+++ b/Libraries/Image/RCTImageUtils.m
@@ -207,10 +207,10 @@ CGSize RCTSizeInPixels(CGSize pointSize, CGFloat scale)
   };
 }
 
-UIImage *RCTDecodeImageWithData(NSData *data,
-                                CGSize destSize,
-                                CGFloat destScale,
-                                UIViewContentMode resizeMode)
+UIImage *__nullable RCTDecodeImageWithData(NSData *data,
+                                           CGSize destSize,
+                                           CGFloat destScale,
+                                           UIViewContentMode resizeMode)
 {
   CGImageSourceRef sourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
   if (!sourceRef) {
@@ -265,7 +265,7 @@ CGSize RCTSizeInPixels(CGSize pointSize, CGFloat scale)
   return image;
 }
 
-NSDictionary<NSString *, id> *RCTGetImageMetadata(NSData *data)
+NSDictionary<NSString *, id> *__nullable RCTGetImageMetadata(NSData *data)
 {
   CGImageSourceRef sourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
   if (!sourceRef) {
@@ -276,7 +276,7 @@ CGSize RCTSizeInPixels(CGSize pointSize, CGFloat scale)
   return (__bridge_transfer id)imageProperties;
 }
 
-NSData *RCTGetImageData(CGImageRef image, float quality)
+NSData *__nullable RCTGetImageData(CGImageRef image, float quality)
 {
   NSDictionary *properties;
   CGImageDestinationRef destination;

From cf350a69de0e87ea4169f034407e559ea201c90e Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Wed, 6 Jan 2016 04:16:44 -0800
Subject: [PATCH 0619/1411] WebWorkers: New c++ interface for NativeRunnable

Reviewed By: mhorowitz, lexs

Differential Revision: D2779083

fb-gh-sync-id: dc36b71504b4e74b1671bb48f72d001c9c87721b
---
 .../react/bridge/queue/NativeRunnable.java    | 13 +++---
 .../queue/NativeRunnableDeprecated.java       | 27 ++++++++++++
 .../src/main/jni/react/jni/JNativeRunnable.h  | 44 +++++++++++++++++++
 .../src/main/jni/react/jni/OnLoad.cpp         |  4 +-
 4 files changed, 80 insertions(+), 8 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/queue/NativeRunnableDeprecated.java
 create mode 100644 ReactAndroid/src/main/jni/react/jni/JNativeRunnable.h

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/NativeRunnable.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/NativeRunnable.java
index 23eb266d4381..d724405a99cb 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/NativeRunnable.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/NativeRunnable.java
@@ -9,20 +9,19 @@
 
 package com.facebook.react.bridge.queue;
 
-import com.facebook.jni.Countable;
+import com.facebook.jni.HybridData;
 import com.facebook.proguard.annotations.DoNotStrip;
 
 /**
  * A Runnable that has a native run implementation.
  */
 @DoNotStrip
-public class NativeRunnable extends Countable implements Runnable {
+public class NativeRunnable implements Runnable {
 
-  /**
-   * Should only be instantiated via native (JNI) code.
-   */
-  @DoNotStrip
-  private NativeRunnable() {
+  private final HybridData mHybridData;
+
+  private NativeRunnable(HybridData hybridData) {
+    mHybridData = hybridData;
   }
 
   public native void run();
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/NativeRunnableDeprecated.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/NativeRunnableDeprecated.java
new file mode 100644
index 000000000000..9e77c7eb88c7
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/NativeRunnableDeprecated.java
@@ -0,0 +1,27 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.bridge.queue;
+
+import com.facebook.jni.Countable;
+import com.facebook.jni.HybridData;
+import com.facebook.proguard.annotations.DoNotStrip;
+
+/**
+ * A Runnable that has a native run implementation.
+ */
+@DoNotStrip
+public class NativeRunnableDeprecated extends Countable implements Runnable {
+
+  @DoNotStrip
+  private NativeRunnableDeprecated() {
+  }
+
+  public native void run();
+}
diff --git a/ReactAndroid/src/main/jni/react/jni/JNativeRunnable.h b/ReactAndroid/src/main/jni/react/jni/JNativeRunnable.h
new file mode 100644
index 000000000000..5550af34299b
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/jni/JNativeRunnable.h
@@ -0,0 +1,44 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+#include <functional>
+
+#include <jni.h>
+
+using namespace facebook::jni;
+
+namespace facebook {
+namespace react {
+
+class Runnable : public JavaClass<Runnable> {
+public:
+  static constexpr auto kJavaDescriptor = "Ljava/lang/Runnable;";
+};
+
+/**
+ * The c++ interface for the Java NativeRunnable class
+ */
+class JNativeRunnable : public HybridClass<JNativeRunnable, Runnable> {
+public:
+  static auto constexpr kJavaDescriptor = "Lcom/facebook/react/bridge/queue/NativeRunnable;";
+
+  void run() {
+    m_runnable();
+  }
+
+  static void registerNatives() {
+    javaClassStatic()->registerNatives({
+        makeNativeMethod("run", JNativeRunnable::run),
+    });
+  }
+private:
+  friend HybridBase;
+
+  JNativeRunnable(std::function<void()> runnable)
+      : m_runnable(std::move(runnable)) {}
+
+  std::function<void()> m_runnable;
+};
+
+} }
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 5ef5c28aaba5..07e6549b9bc6 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -13,6 +13,7 @@
 #include <react/Bridge.h>
 #include <react/Executor.h>
 #include <react/JSCExecutor.h>
+#include "JNativeRunnable.h"
 #include "JSLoader.h"
 #include "ReadableNativeArray.h"
 #include "ProxyExecutor.h"
@@ -780,6 +781,7 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
     NativeArray::registerNatives();
     ReadableNativeArray::registerNatives();
     WritableNativeArray::registerNatives();
+    JNativeRunnable::registerNatives();
 
     registerNatives("com/facebook/react/bridge/NativeMap", {
         makeNativeMethod("initialize", map::initialize),
@@ -861,7 +863,7 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
 
     });
 
-    jclass nativeRunnableClass = env->FindClass("com/facebook/react/bridge/queue/NativeRunnable");
+    jclass nativeRunnableClass = env->FindClass("com/facebook/react/bridge/queue/NativeRunnableDeprecated");
     runnable::gNativeRunnableClass = (jclass)env->NewGlobalRef(nativeRunnableClass);
     runnable::gNativeRunnableCtor = env->GetMethodID(nativeRunnableClass, "<init>", "()V");
     wrap_alias(nativeRunnableClass)->registerNatives({

From 28c0240361de2ce88f69822c3a8400f0edafe7a9 Mon Sep 17 00:00:00 2001
From: Alex Kotliarskyi <alex.frantic@gmail.com>
Date: Wed, 6 Jan 2016 05:57:13 -0800
Subject: [PATCH 0620/1411] Fix `background` warning in TouchableNativeFeedback

Summary:
The problem: no matter what value `background` prop has, it always triggers a warning

![screen shot 2016-01-05 at 1 20 35 pm](https://cloud.githubusercontent.com/assets/192222/12128053/c0a8754a-b3af-11e5-92c6-921e2e0c7cc4.png)

Looks like this happens because we use `createStrictShapeTypeChecker` prop types inside `PropTypes.oneOfType` instead of `PropTypes.shape`.
Closes https://github.com/facebook/react-native/pull/5132

Reviewed By: svcscm

Differential Revision: D2804478

Pulled By: mkonicek

fb-gh-sync-id: 32ce964047bddd9d92c214baaff5422dbcfd7e90
---
 .../Components/Touchable/TouchableNativeFeedback.android.js  | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js
index bc875eda531c..240b2482a056 100644
--- a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js
+++ b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js
@@ -17,19 +17,18 @@ var Touchable = require('Touchable');
 var TouchableWithoutFeedback = require('TouchableWithoutFeedback');
 var UIManager = require('UIManager');
 
-var createStrictShapeTypeChecker = require('createStrictShapeTypeChecker');
 var ensurePositiveDelayProps = require('ensurePositiveDelayProps');
 var onlyChild = require('onlyChild');
 var processColor = require('processColor');
 var requireNativeComponent = require('requireNativeComponent');
 
-var rippleBackgroundPropType = createStrictShapeTypeChecker({
+var rippleBackgroundPropType = PropTypes.shape({
   type: React.PropTypes.oneOf(['RippleAndroid']),
   color: PropTypes.number,
   borderless: PropTypes.bool,
 });
 
-var themeAttributeBackgroundPropType = createStrictShapeTypeChecker({
+var themeAttributeBackgroundPropType = PropTypes.shape({
   type: React.PropTypes.oneOf(['ThemeAttrAndroid']),
   attribute: PropTypes.string.isRequired,
 });

From 17df595e3242524761518d389d16867aaaa99b7f Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Wed, 6 Jan 2016 05:57:25 -0800
Subject: [PATCH 0621/1411] Implement Android's dispatchViewManagerCommand
 interface on iOS

Summary:
public
Android implement ViewManager methods via a dispatch method on UIManager, whereas iOS implements them by exposing the methods on the view manager modules directly.

This diff polyfills Android's implementation on top of the iOS implementation, allowing the same JS API to be used for both.

Reviewed By: javache

Differential Revision: D2803020

fb-gh-sync-id: 0da0544e593dc936467d16ce957a77f7ca41355b
---
 .../BatchedBridgedModules/NativeModules.js    | 29 +++++++++++++++++--
 Libraries/Components/WebView/WebView.ios.js   | 19 ++++++++++--
 React/Base/RCTBatchedBridge.m                 |  8 +++++
 React/Base/RCTBridge+Private.h                |  6 ++++
 React/Base/RCTModuleMethod.h                  |  4 ---
 React/Modules/RCTUIManager.m                  | 17 +++++++++++
 6 files changed, 73 insertions(+), 10 deletions(-)

diff --git a/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js b/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js
index c6f54bcb9385..5d9cf603aac5 100644
--- a/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js
+++ b/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js
@@ -56,8 +56,8 @@ Object.keys(RemoteModules).forEach((moduleName) => {
 });
 
 /**
- * Copies the ViewManager constants into UIManager. This is only
- * needed for iOS, which puts the constants in the ViewManager
+ * Copies the ViewManager constants and commands into UIManager. This is
+ * only needed for iOS, which puts the constants in the ViewManager
  * namespace instead of UIManager, unlike Android.
  *
  * We'll eventually move this logic to UIManager.js, once all
@@ -67,12 +67,16 @@ Object.keys(RemoteModules).forEach((moduleName) => {
 const UIManager = NativeModules.UIManager;
 UIManager && Object.keys(UIManager).forEach(viewName => {
   const viewConfig = UIManager[viewName];
-  const constants = {};
   if (viewConfig.Manager) {
+    let constants;
     /* $FlowFixMe - nice try. Flow doesn't like getters */
     Object.defineProperty(viewConfig, 'Constants', {
       enumerable: true,
       get: () => {
+        if (constants) {
+          return constants;
+        }
+        constants = {};
         const viewManager = NativeModules[normalizePrefix(viewConfig.Manager)];
         viewManager && Object.keys(viewManager).forEach(key => {
           const value = viewManager[key];
@@ -83,6 +87,25 @@ UIManager && Object.keys(UIManager).forEach(viewName => {
         return constants;
       },
     });
+    let commands;
+    /* $FlowFixMe - nice try. Flow doesn't like getters */
+    Object.defineProperty(viewConfig, 'Commands', {
+      enumerable: true,
+      get: () => {
+        if (commands) {
+          return commands;
+        }
+        commands = {};
+        const viewManager = NativeModules[normalizePrefix(viewConfig.Manager)];
+        viewManager && Object.keys(viewManager).forEach((key, index) => {
+          const value = viewManager[key];
+          if (typeof value === 'function') {
+            commands[key] = index;
+          }
+        });
+        return commands;
+      },
+    });
   }
 });
 
diff --git a/Libraries/Components/WebView/WebView.ios.js b/Libraries/Components/WebView/WebView.ios.js
index 229df820b67e..d97326667c6b 100644
--- a/Libraries/Components/WebView/WebView.ios.js
+++ b/Libraries/Components/WebView/WebView.ios.js
@@ -16,6 +16,7 @@ var EdgeInsetsPropType = require('EdgeInsetsPropType');
 var React = require('React');
 var StyleSheet = require('StyleSheet');
 var Text = require('Text');
+var UIManager = require('UIManager');
 var View = require('View');
 
 var invariant = require('invariant');
@@ -240,15 +241,27 @@ var WebView = React.createClass({
   },
 
   goForward: function() {
-    RCTWebViewManager.goForward(this.getWebViewHandle());
+    UIManager.dispatchViewManagerCommand(
+      this.getWebViewHandle(),
+      UIManager.RCTWebView.Commands.goForward,
+      null
+    );
   },
 
   goBack: function() {
-    RCTWebViewManager.goBack(this.getWebViewHandle());
+    UIManager.dispatchViewManagerCommand(
+      this.getWebViewHandle(),
+      UIManager.RCTWebView.Commands.goBack,
+      null
+    );
   },
 
   reload: function() {
-    RCTWebViewManager.reload(this.getWebViewHandle());
+    UIManager.dispatchViewManagerCommand(
+      this.getWebViewHandle(),
+      UIManager.RCTWebView.Commands.reload,
+      null
+    );
   },
 
   /**
diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index 7ae745a391d0..3031c1a54afe 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -222,6 +222,14 @@ - (void)loadSource:(RCTSourceLoadBlock)_onSourceLoad
   return _moduleClassesByID;
 }
 
+/**
+ * Used by RCTUIManager
+ */
+- (RCTModuleData *)moduleDataForName:(NSString *)moduleName
+{
+  return _moduleDataByName[moduleName];
+}
+
 - (id)moduleForName:(NSString *)moduleName
 {
   RCTModuleData *moduleData = _moduleDataByName[moduleName];
diff --git a/React/Base/RCTBridge+Private.h b/React/Base/RCTBridge+Private.h
index ddeddeaa4eff..8e673a6b05ec 100644
--- a/React/Base/RCTBridge+Private.h
+++ b/React/Base/RCTBridge+Private.h
@@ -63,6 +63,12 @@
  */
 - (void)dispatchBlock:(dispatch_block_t)block queue:(dispatch_queue_t)queue;
 
+/**
+ * Get the module data for a given module name. Used by UIManager to implement
+ * the `dispatchViewManagerCommand` method.
+ */
+- (RCTModuleData *)moduleDataForName:(NSString *)moduleName;
+
 /**
  * Systrace profiler toggling methods exposed for the RCTDevMenu
  */
diff --git a/React/Base/RCTModuleMethod.h b/React/Base/RCTModuleMethod.h
index 5572dba3a307..ab525e030274 100644
--- a/React/Base/RCTModuleMethod.h
+++ b/React/Base/RCTModuleMethod.h
@@ -31,8 +31,4 @@
                           JSMethodName:(NSString *)JSMethodName
                            moduleClass:(Class)moduleClass NS_DESIGNATED_INITIALIZER;
 
-- (void)invokeWithBridge:(RCTBridge *)bridge
-                  module:(id)module
-               arguments:(NSArray *)arguments;
-
 @end
diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m
index 4758d51b8eb2..9d0ea2502437 100644
--- a/React/Modules/RCTUIManager.m
+++ b/React/Modules/RCTUIManager.m
@@ -16,12 +16,15 @@
 #import "RCTAnimationType.h"
 #import "RCTAssert.h"
 #import "RCTBridge.h"
+#import "RCTBridge+Private.h"
 #import "RCTComponent.h"
 #import "RCTComponentData.h"
 #import "RCTConvert.h"
 #import "RCTDefines.h"
 #import "RCTEventDispatcher.h"
 #import "RCTLog.h"
+#import "RCTModuleData.h"
+#import "RCTModuleMethod.h"
 #import "RCTProfile.h"
 #import "RCTRootView.h"
 #import "RCTRootViewInternal.h"
@@ -907,6 +910,20 @@ - (void)_manageChildren:(NSNumber *)containerReactTag
   }];
 }
 
+RCT_EXPORT_METHOD(dispatchViewManagerCommand:(nonnull NSNumber *)reactTag
+                  commandID:(NSInteger)commandID
+                  commandArgs:(NSArray<id> *)commandArgs)
+{
+  RCTShadowView *shadowView = _shadowViewRegistry[reactTag];
+  RCTComponentData *componentData = _componentDataByName[shadowView.viewName];
+  Class managerClass = componentData.managerClass;
+  RCTModuleData *moduleData = [_bridge moduleDataForName:RCTBridgeModuleNameForClass(managerClass)];
+  id<RCTBridgeMethod> method = moduleData.methods[commandID];
+
+  NSArray *args = [@[reactTag] arrayByAddingObjectsFromArray:commandArgs];
+  [method invokeWithBridge:_bridge module:componentData.manager arguments:args];
+}
+
 - (void)partialBatchDidFlush
 {
   if (self.unsafeFlushUIChangesBeforeBatchEnds) {

From 1bfd267acb8a4f82aa5e1724aee37b4f8747f050 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Wed, 6 Jan 2016 06:29:11 -0800
Subject: [PATCH 0622/1411] Resubmit: [react_native] WebWorkers: Add JSLoader
 API for loading script from assets with AssetLoader reference

Summary:
public

Adds the ability to load files from assets without threading through an AssetManager. After the bridge is unforked, we should move to passing through an Environment object instead.

Resubmit: previous version was reverted due to adsmanager crash

Reviewed By: foghina

Differential Revision: D2802899

fb-gh-sync-id: 3d850256fc22f7e9eb21fa71f6adb09cacc839c4
---
 .../react/ReactInstanceManagerImpl.java       |  5 +++
 .../react/common/ApplicationHolder.java       | 37 +++++++++++++++++++
 .../src/main/jni/react/jni/JSLoader.cpp       | 26 ++++++++++++-
 .../src/main/jni/react/jni/JSLoader.h         |  8 ++++
 .../src/main/jni/react/jni/OnLoad.cpp         |  1 +
 5 files changed, 76 insertions(+), 1 deletion(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/common/ApplicationHolder.java

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index 780cdb12392d..c9bf17c610ce 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -17,6 +17,7 @@
 import java.util.concurrent.ConcurrentLinkedQueue;
 
 import android.app.Activity;
+import android.app.Application;
 import android.content.Context;
 import android.content.Intent;
 import android.os.AsyncTask;
@@ -46,6 +47,7 @@
 import com.facebook.react.bridge.WritableMap;
 import com.facebook.react.bridge.WritableNativeMap;
 import com.facebook.react.bridge.queue.CatalystQueueConfigurationSpec;
+import com.facebook.react.common.ApplicationHolder;
 import com.facebook.react.common.ReactConstants;
 import com.facebook.react.common.annotations.VisibleForTesting;
 import com.facebook.react.devsupport.DevServerHelper;
@@ -242,6 +244,9 @@ public T get() throws Exception {
       NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
     initializeSoLoaderIfNecessary(applicationContext);
 
+    // TODO(9577825): remove this
+    ApplicationHolder.setApplication((Application) applicationContext.getApplicationContext());
+
     mApplicationContext = applicationContext;
     mJSBundleFile = jsBundleFile;
     mJSMainModuleName = jsMainModuleName;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/common/ApplicationHolder.java b/ReactAndroid/src/main/java/com/facebook/react/common/ApplicationHolder.java
new file mode 100644
index 000000000000..f35d1a18d0ad
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/common/ApplicationHolder.java
@@ -0,0 +1,37 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.common;
+
+import android.app.Application;
+
+import com.facebook.infer.annotation.Assertions;
+import com.facebook.proguard.annotations.DoNotStrip;
+
+/**
+ * Holds the current Application Object.
+ *
+ * TODO(9577825): This is a bad pattern, we should thread through an Environment object instead.
+ * Remove once bridge is unforked.
+ */
+@DoNotStrip
+@Deprecated
+public class ApplicationHolder {
+
+  private static Application sApplication;
+
+  public static void setApplication(Application application) {
+    sApplication = application;
+  }
+
+  @DoNotStrip
+  public static Application getApplication() {
+    return Assertions.assertNotNull(sApplication);
+  }
+}
diff --git a/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp b/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp
index 416640a371de..db8b4d980e63 100644
--- a/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp
@@ -4,6 +4,7 @@
 
 #include <android/asset_manager.h>
 #include <android/asset_manager_jni.h>
+#include <jni/Environment.h>
 #include <fstream>
 #include <sstream>
 #include <streambuf>
@@ -18,6 +19,19 @@ using fbsystrace::FbSystraceSection;
 namespace facebook {
 namespace react {
 
+static jclass gApplicationHolderClass;
+static jmethodID gGetApplicationMethod;
+static jmethodID gGetAssetManagerMethod;
+
+std::string loadScriptFromAssets(std::string assetName) {
+  JNIEnv *env = jni::Environment::current();
+  jobject application = env->CallStaticObjectMethod(
+    gApplicationHolderClass,
+    gGetApplicationMethod);
+  jobject assetManager = env->CallObjectMethod(application, gGetAssetManagerMethod);
+  return loadScriptFromAssets(env, assetManager, assetName);
+}
+
 std::string loadScriptFromAssets(
     JNIEnv *env,
     jobject assetManager,
@@ -71,4 +85,14 @@ std::string loadScriptFromFile(std::string fileName) {
   return "";
 }
 
-} }
\ No newline at end of file
+void registerJSLoaderNatives() {
+  JNIEnv *env = jni::Environment::current();
+  jclass applicationHolderClass = env->FindClass("com/facebook/react/common/ApplicationHolder");
+  gApplicationHolderClass = (jclass)env->NewGlobalRef(applicationHolderClass);
+  gGetApplicationMethod = env->GetStaticMethodID(applicationHolderClass, "getApplication", "()Landroid/app/Application;");
+  
+  jclass appClass = env->FindClass("android/app/Application");
+  gGetAssetManagerMethod = env->GetMethodID(appClass, "getAssets", "()Landroid/content/res/AssetManager;");
+}
+
+} }
diff --git a/ReactAndroid/src/main/jni/react/jni/JSLoader.h b/ReactAndroid/src/main/jni/react/jni/JSLoader.h
index c7381fe7e8f7..25dab510d7a2 100644
--- a/ReactAndroid/src/main/jni/react/jni/JSLoader.h
+++ b/ReactAndroid/src/main/jni/react/jni/JSLoader.h
@@ -8,6 +8,12 @@
 namespace facebook {
 namespace react {
 
+/**
+ * Helper method for loading a JS script from Android assets without
+ * a reference to an AssetManager.
+ */
+std::string loadScriptFromAssets(std::string assetName);
+
 /**
  * Helper method for loading JS script from android asset
  */
@@ -18,4 +24,6 @@ std::string loadScriptFromAssets(JNIEnv *env, jobject assetManager, std::string
  */
 std::string loadScriptFromFile(std::string fileName);
 
+void registerJSLoaderNatives();
+
 } }
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 07e6549b9bc6..7b66505c49e0 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -782,6 +782,7 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
     ReadableNativeArray::registerNatives();
     WritableNativeArray::registerNatives();
     JNativeRunnable::registerNatives();
+    registerJSLoaderNatives();
 
     registerNatives("com/facebook/react/bridge/NativeMap", {
         makeNativeMethod("initialize", map::initialize),

From daa93a622273873cdee53c546f6d876f4e271e70 Mon Sep 17 00:00:00 2001
From: SangYeob Bono Yu <deminoth@gmail.com>
Date: Wed, 6 Jan 2016 06:56:49 -0800
Subject: [PATCH 0623/1411] Change the signature of onDropViewInstance. issue
 #5053

Summary:
https://github.com/facebook/react-native/issues/5053
Closes https://github.com/facebook/react-native/pull/5125

Reviewed By: svcscm

Differential Revision: D2807202

Pulled By: foghina

fb-gh-sync-id: 1e268c940a08aa7bf243971ba91d4595973f12af
---
 .../react/uimanager/NativeViewHierarchyManager.java         | 4 +---
 .../main/java/com/facebook/react/uimanager/ViewManager.java | 2 +-
 .../facebook/react/views/webview/ReactWebViewManager.java   | 6 +++---
 3 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
index 858b621db3e0..e5e79eaf2a1e 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
@@ -424,9 +424,7 @@ protected final void dropView(View view) {
     UiThreadUtil.assertOnUiThread();
     if (!mRootTags.get(view.getId())) {
       // For non-root views we notify viewmanager with {@link ViewManager#onDropInstance}
-      resolveViewManager(view.getId()).onDropViewInstance(
-          (ThemedReactContext) view.getContext(),
-          view);
+      resolveViewManager(view.getId()).onDropViewInstance(view);
     }
     ViewManager viewManager = mTagsToViewManagers.get(view.getId());
     if (view instanceof ViewGroup && viewManager instanceof ViewGroupManager) {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java
index f9b5e1293dad..816eda3b6a97 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java
@@ -92,7 +92,7 @@ public final T createView(
    * Called when view is detached from view hierarchy and allows for some additional cleanup by
    * the {@link ViewManager} subclass.
    */
-  public void onDropViewInstance(ThemedReactContext reactContext, T view) {
+  public void onDropViewInstance(T view) {
   }
 
   /**
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
index 5400210d6748..f7577f5b3117 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
@@ -323,9 +323,9 @@ public void receiveCommand(WebView root, int commandId, @Nullable ReadableArray
   }
 
   @Override
-  public void onDropViewInstance(ThemedReactContext reactContext, WebView webView) {
-    super.onDropViewInstance(reactContext, webView);
-    reactContext.removeLifecycleEventListener((ReactWebView) webView);
+  public void onDropViewInstance(WebView webView) {
+    super.onDropViewInstance(webView);
+    ((ThemedReactContext) webView.getContext()).removeLifecycleEventListener((ReactWebView) webView);
     ((ReactWebView) webView).cleanupCallbacksAndDestroy();
   }
 }

From 5b3cb05fa8b1d100dff15af2bb63c2cfe5e0d17a Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Wed, 6 Jan 2016 07:05:00 -0800
Subject: [PATCH 0624/1411] Add a menu item for HMR

Summary:
cc martinbigio
Closes https://github.com/facebook/react-native/pull/5092

Reviewed By: svcscm

Differential Revision: D2807241

Pulled By: mkonicek

fb-gh-sync-id: e4418eeb4944d795f30f94be94b80648b4d7034c
---
 .../react/devsupport/DevInternalSettings.java |  9 +++++++
 .../react/devsupport/DevServerHelper.java     | 25 ++++++++++++-------
 .../react/devsupport/DevSupportManager.java   | 11 ++++++++
 .../main/res/devsupport/values/strings.xml    |  2 ++
 4 files changed, 38 insertions(+), 9 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java
index 291f63adc5ec..825bc1c59843 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java
@@ -34,6 +34,7 @@ public class DevInternalSettings implements
   private static final String PREFS_ANIMATIONS_DEBUG_KEY = "animations_debug";
   private static final String PREFS_RELOAD_ON_JS_CHANGE_KEY = "reload_on_js_change";
   private static final String PREFS_INSPECTOR_DEBUG_KEY = "inspector_debug";
+  private static final String PREFS_HOT_MODULE_REPLACEMENT_KEY = "hot_module_replacement";
 
   private final SharedPreferences mPreferences;
   private final DevSupportManager mDebugManager;
@@ -77,6 +78,14 @@ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Strin
     }
   }
 
+  public boolean isHotModuleReplacementEnabled() {
+    return mPreferences.getBoolean(PREFS_HOT_MODULE_REPLACEMENT_KEY, false);
+  }
+
+  public void setHotModuleReplacementEnabled(boolean enabled) {
+    mPreferences.edit().putBoolean(PREFS_HOT_MODULE_REPLACEMENT_KEY, enabled).apply();
+  }
+
   public boolean isReloadOnJSChangeEnabled() {
     return mPreferences.getBoolean(PREFS_RELOAD_ON_JS_CHANGE_KEY, false);
   }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java
index 1ba9b96e3727..3439eaf2d748 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java
@@ -25,7 +25,6 @@
 import com.facebook.infer.annotation.Assertions;
 import com.facebook.react.bridge.UiThreadUtil;
 import com.facebook.react.common.ReactConstants;
-
 import com.squareup.okhttp.Call;
 import com.squareup.okhttp.Callback;
 import com.squareup.okhttp.ConnectionPool;
@@ -33,6 +32,7 @@
 import com.squareup.okhttp.Request;
 import com.squareup.okhttp.Response;
 import com.squareup.okhttp.ResponseBody;
+
 import okio.Okio;
 import okio.Sink;
 
@@ -55,7 +55,7 @@ public class DevServerHelper {
   private static final String DEVICE_LOCALHOST = "localhost:8081";
 
   private static final String BUNDLE_URL_FORMAT =
-      "http://%s/%s.bundle?platform=android&dev=%s";
+      "http://%s/%s.bundle?platform=android&dev=%s&hot=%s";
   private static final String SOURCE_MAP_URL_FORMAT =
       BUNDLE_URL_FORMAT.replaceFirst("\\.bundle", ".map");
   private static final String LAUNCH_CHROME_DEVTOOLS_COMMAND_URL_FORMAT =
@@ -120,12 +120,19 @@ private static String getHostForJSProxy() {
   }
 
   /**
-   * @return whether we should enabled dev mode or not when requesting JS bundles.
+   * @return whether we should enable dev mode when requesting JS bundles.
    */
   private boolean getDevMode() {
     return mSettings.isJSDevModeEnabled();
   }
 
+  /**
+   * @return whether we should enabled HMR when requesting JS bundles.
+   */
+  private boolean getHMR() {
+    return mSettings.isHotModuleReplacementEnabled();
+  }
+
   /**
    * @return the host to use when connecting to the bundle server.
    */
@@ -160,15 +167,15 @@ private boolean isRunningOnStockEmulator() {
     return Build.FINGERPRINT.contains("generic");
   }
 
-  private static String createBundleURL(String host, String jsModulePath, boolean devMode) {
-    return String.format(Locale.US, BUNDLE_URL_FORMAT, host, jsModulePath, devMode);
+  private static String createBundleURL(String host, String jsModulePath, boolean devMode, boolean hmr) {
+    return String.format(Locale.US, BUNDLE_URL_FORMAT, host, jsModulePath, devMode, hmr);
   }
 
   public void downloadBundleFromURL(
       final BundleDownloadCallback callback,
       final String jsModulePath,
       final File outputFile) {
-    final String bundleURL = createBundleURL(getDebugServerHost(), jsModulePath, getDevMode());
+    final String bundleURL = createBundleURL(getDebugServerHost(), jsModulePath, getDevMode(), getHMR());
     Request request = new Request.Builder()
         .url(bundleURL)
         .build();
@@ -354,17 +361,17 @@ public void onResponse(Response response) throws IOException {
   }
 
   public String getSourceMapUrl(String mainModuleName) {
-    return String.format(Locale.US, SOURCE_MAP_URL_FORMAT, getDebugServerHost(), mainModuleName, getDevMode());
+    return String.format(Locale.US, SOURCE_MAP_URL_FORMAT, getDebugServerHost(), mainModuleName, getDevMode(), getHMR());
   }
 
   public String getSourceUrl(String mainModuleName) {
-    return String.format(Locale.US, BUNDLE_URL_FORMAT, getDebugServerHost(), mainModuleName, getDevMode());
+    return String.format(Locale.US, BUNDLE_URL_FORMAT, getDebugServerHost(), mainModuleName, getDevMode(), getHMR());
   }
 
   public String getJSBundleURLForRemoteDebugging(String mainModuleName) {
     // The host IP we use when connecting to the JS bundle server from the emulator is not the
     // same as the one needed to connect to the same server from the Chrome proxy running on the
     // host itself.
-    return createBundleURL(getHostForJSProxy(), mainModuleName, getDevMode());
+    return createBundleURL(getHostForJSProxy(), mainModuleName, getDevMode(), getHMR());
   }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
index ce60e861c7db..2625bec62956 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
@@ -262,6 +262,17 @@ public void onOptionSelected() {
             handleReloadJS();
           }
         });
+    options.put(
+            mDevSettings.isHotModuleReplacementEnabled()
+                    ? mApplicationContext.getString(R.string.catalyst_hot_module_replacement_off)
+                    : mApplicationContext.getString(R.string.catalyst_hot_module_replacement),
+            new DevOptionHandler() {
+              @Override
+              public void onOptionSelected() {
+                mDevSettings.setHotModuleReplacementEnabled(!mDevSettings.isHotModuleReplacementEnabled());
+                handleReloadJS();
+              }
+            });
     options.put(
         mDevSettings.isReloadOnJSChangeEnabled()
             ? mApplicationContext.getString(R.string.catalyst_live_reload_off)
diff --git a/ReactAndroid/src/main/res/devsupport/values/strings.xml b/ReactAndroid/src/main/res/devsupport/values/strings.xml
index 1e60598d34dc..d56ca71d1cec 100644
--- a/ReactAndroid/src/main/res/devsupport/values/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values/strings.xml
@@ -3,6 +3,8 @@
   <string name="catalyst_reloadjs" project="catalyst" translatable="false">Reload JS</string>
   <string name="catalyst_debugjs" project="catalyst" translatable="false">Debug in Chrome</string>
   <string name="catalyst_debugjs_off" project="catalyst" translatable="false">Stop Chrome Debugging</string>
+  <string name="catalyst_hot_module_replacement" project="catalyst" translatable="false">Enable Hot Module Replacement</string>
+  <string name="catalyst_hot_module_replacement_off" project="catalyst" translatable="false">Disable Hot Module Replacement</string>
   <string name="catalyst_live_reload" project="catalyst" translatable="false">Enable Live Reload</string>
   <string name="catalyst_live_reload_off" project="catalyst" translatable="false">Disable Live Reload</string>
   <string name="catalyst_perf_monitor" project="catalyst" translatable="false">Enable Perf Monitor</string>

From 0d4cfa00f922584f6ae31799e9e1c9a0a84b55cf Mon Sep 17 00:00:00 2001
From: Martin Bigio <martinb@fb.com>
Date: Wed, 6 Jan 2016 07:14:20 -0800
Subject: [PATCH 0625/1411] Increase worker-farm timeout

Reviewed By: davidaurelio

Differential Revision: D2806738

fb-gh-sync-id: a165578002415388af830f77bd96f4888143028f
---
 packager/react-packager/src/JSTransformer/index.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/packager/react-packager/src/JSTransformer/index.js b/packager/react-packager/src/JSTransformer/index.js
index 89f311628532..1bb845d7afd3 100644
--- a/packager/react-packager/src/JSTransformer/index.js
+++ b/packager/react-packager/src/JSTransformer/index.js
@@ -24,10 +24,10 @@ const readFile = Promise.denodeify(fs.readFile);
 const MAX_CALLS_PER_WORKER = 600;
 
 // Worker will timeout if one of the callers timeout.
-const DEFAULT_MAX_CALL_TIME = 120000;
+const DEFAULT_MAX_CALL_TIME = 300000;
 
 // How may times can we tolerate failures from the worker.
-const MAX_RETRIES = 3;
+const MAX_RETRIES = 2;
 
 const validateOpts = declareOpts({
   projectRoots: {

From a3d9fadc78c601a6886db0fda824455cc72d1ea7 Mon Sep 17 00:00:00 2001
From: Christopher Dro <hello@blick-labs.com>
Date: Wed, 6 Jan 2016 07:41:13 -0800
Subject: [PATCH 0626/1411] Remove fixed size for Android. Fixes #3785

Summary:
Fixed #3785
Closes https://github.com/facebook/react-native/pull/4298

Reviewed By: svcscm

Differential Revision: D2807289

Pulled By: mkonicek

fb-gh-sync-id: 6f161e4f8b04597726183fdcf8bc22c682557958
---
 Libraries/Components/Switch/Switch.js | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/Libraries/Components/Switch/Switch.js b/Libraries/Components/Switch/Switch.js
index 31ec91ef5eae..9816db385c92 100644
--- a/Libraries/Components/Switch/Switch.js
+++ b/Libraries/Components/Switch/Switch.js
@@ -92,7 +92,7 @@ var Switch = React.createClass({
     if (Platform.OS === 'android') {
       props.enabled = !this.props.disabled;
       props.on = this.props.value;
-      props.style = [styles.rctSwitchAndroid, this.props.style];
+      props.style = this.props.style;
     } else if (Platform.OS === 'ios') {
       props.style = [styles.rctSwitchIOS, this.props.style];
     }
@@ -110,11 +110,7 @@ var styles = StyleSheet.create({
   rctSwitchIOS: {
     height: 31,
     width: 51,
-  },
-  rctSwitchAndroid: {
-    height: 27,
-    width: 40,
-  },
+  }
 });
 
 if (Platform.OS === 'android') {

From e730a9fdd08e63eabf75963ed9cdc17564cf0bfb Mon Sep 17 00:00:00 2001
From: Geoffrey Goh <kg422@cornell.edu>
Date: Wed, 6 Jan 2016 08:45:34 -0800
Subject: [PATCH 0627/1411] Load assets from same folder as JSbundle (Android)

Summary:
https://github.com/facebook/react-native/issues/3679 was only partially fixed as the behaviour only works on iOS. This implements the same behaviour for Android. If the JSBundle was loaded from the assets folder, this will load images from the built-in resources. Else, load the image from the same folder as the JS bundle.

EDIT: For added clarity:

On iOS,
Bundle Location: 'file:///Path/To/Sample.app/main.bundle'
httpServerLocation: '/assets/module/a/'
Name: 'logo'
type: 'png'
**Resolved Asset location: '/Path/To/Sample.app/assets/module/a/logo.png'**

On Android,
Bundle Location: 'file:///sdcard/Path/To/main.bundle'
httpServerLocation: '/assets/module/a/',
name: 'logo'
type: 'png'
**Resolved Asset location: 'file:///sdcard/Path/To/drawable_mdpi/module_a_logo.png'**
Closes https://github.com/facebook/react-native/pull/4527

Reviewed By: svcscm

Differential Revision: D2788005

Pulled By: mkonicek

fb-gh-sync-id: 3f6462a7ee6370a92dd6727ac422c5de346c3ff1
---
 .../__tests__/resolveAssetSource-test.js      | 35 +++++++++++-
 Libraries/Image/resolveAssetSource.js         | 42 +++++++-------
 .../facebook/react/bridge/JSBundleLoader.java |  2 +-
 .../__tests__/getAssetDestPathAndroid-test.js |  4 +-
 local-cli/bundle/assetPathUtils.js            | 56 +++++++++++++++++++
 local-cli/bundle/getAssetDestPathAndroid.js   | 29 +---------
 6 files changed, 115 insertions(+), 53 deletions(-)
 create mode 100644 local-cli/bundle/assetPathUtils.js

diff --git a/Libraries/Image/__tests__/resolveAssetSource-test.js b/Libraries/Image/__tests__/resolveAssetSource-test.js
index 81fdb2b08dc9..b406316a1a90 100644
--- a/Libraries/Image/__tests__/resolveAssetSource-test.js
+++ b/Libraries/Image/__tests__/resolveAssetSource-test.js
@@ -10,7 +10,8 @@
 
 jest
   .dontMock('AssetRegistry')
-  .dontMock('../resolveAssetSource');
+  .dontMock('../resolveAssetSource')
+  .dontMock('../../../local-cli/bundle/assetPathUtils');
 
 var AssetRegistry = require('AssetRegistry');
 var Platform = require('Platform');
@@ -132,10 +133,10 @@ describe('resolveAssetSource', () => {
     });
   });
 
-  describe('bundle was loaded from file on Android', () => {
+  describe('bundle was loaded from assets on Android', () => {
     beforeEach(() => {
       NativeModules.SourceCode.scriptURL =
-        'file:///Path/To/Simulator/main.bundle';
+        'assets://Path/To/Simulator/main.bundle';
       Platform.OS = 'android';
     });
 
@@ -159,6 +160,34 @@ describe('resolveAssetSource', () => {
       });
     });
   });
+  
+  describe('bundle was loaded from file on Android', () => {
+    beforeEach(() => {
+      NativeModules.SourceCode.scriptURL =
+        'file:///sdcard/Path/To/Simulator/main.bundle';
+      Platform.OS = 'android';
+    });
+
+    it('uses pre-packed image', () => {
+      expectResolvesAsset({
+        __packager_asset: true,
+        fileSystemLocation: '/root/app/module/a',
+        httpServerLocation: '/assets/AwesomeModule/Subdir',
+        width: 100,
+        height: 200,
+        scales: [1],
+        hash: '5b6f00f',
+        name: '!@Logo#1_€',
+        type: 'png',
+      }, {
+        __packager_asset: true,
+        width: 100,
+        height: 200,
+        uri: 'file:///sdcard/Path/To/Simulator/drawable-mdpi/awesomemodule_subdir_logo1_.png',
+        scale: 1,
+      });
+    });
+  });
 
 });
 
diff --git a/Libraries/Image/resolveAssetSource.js b/Libraries/Image/resolveAssetSource.js
index 638b72ce06e4..6527e91df096 100644
--- a/Libraries/Image/resolveAssetSource.js
+++ b/Libraries/Image/resolveAssetSource.js
@@ -25,6 +25,7 @@ var AssetRegistry = require('AssetRegistry');
 var PixelRatio = require('PixelRatio');
 var Platform = require('Platform');
 var SourceCode = require('NativeModules').SourceCode;
+var assetPathUtils = require('../../local-cli/bundle/assetPathUtils');
 
 var _serverURL, _offlinePath;
 
@@ -62,18 +63,18 @@ function getOfflinePath() {
  * Returns the path at which the asset can be found in the archive
  */
 function getPathInArchive(asset) {
+  var offlinePath = getOfflinePath();
   if (Platform.OS === 'android') {
-    var assetDir = getBasePath(asset);
+    if (offlinePath) {
+      // E.g. 'file:///sdcard/AwesomeModule/drawable-mdpi/icon.png'
+      return 'file://' + offlinePath + getAssetPathInDrawableFolder(asset);
+    }
     // E.g. 'assets_awesomemodule_icon'
     // The Android resource system picks the correct scale.
-    return (assetDir + '/' + asset.name)
-      .toLowerCase()
-      .replace(/\//g, '_')           // Encode folder structure in file name
-      .replace(/([^a-z0-9_])/g, '')  // Remove illegal chars
-      .replace(/^assets_/, '');      // Remove "assets_" prefix
+    return assetPathUtils.getAndroidResourceIdentifier(asset);
   } else {
-    // E.g. 'assets/AwesomeModule/icon@2x.png'
-    return getOfflinePath() + getScaledAssetPath(asset);
+    // E.g. '/assets/AwesomeModule/icon@2x.png'
+    return offlinePath + getScaledAssetPath(asset);
   }
 }
 
@@ -86,29 +87,26 @@ function getPathOnDevserver(devServerUrl, asset) {
     '&hash=' + asset.hash;
 }
 
-/**
- * Returns a path like 'assets/AwesomeModule'
- */
-function getBasePath(asset) {
-  // TODO(frantic): currently httpServerLocation is used both as
-  // path in http URL and path within IPA. Should we have zipArchiveLocation?
-  var path = asset.httpServerLocation;
-  if (path[0] === '/') {
-    path = path.substr(1);
-  }
-  return path;
-}
-
 /**
  * Returns a path like 'assets/AwesomeModule/icon@2x.png'
  */
 function getScaledAssetPath(asset) {
   var scale = pickScale(asset.scales, PixelRatio.get());
   var scaleSuffix = scale === 1 ? '' : '@' + scale + 'x';
-  var assetDir = getBasePath(asset);
+  var assetDir = assetPathUtils.getBasePath(asset);
   return assetDir + '/' + asset.name + scaleSuffix + '.' + asset.type;
 }
 
+/**
+ * Returns a path like 'drawable-mdpi/icon.png'
+ */
+function getAssetPathInDrawableFolder(asset) {
+  var scale = pickScale(asset.scales, PixelRatio.get());
+  var drawbleFolder = assetPathUtils.getAndroidDrawableFolderName(asset, scale);
+  var fileName =  assetPathUtils.getAndroidResourceIdentifier(asset);
+  return drawbleFolder + '/' + fileName + '.' + asset.type;
+}
+
 function pickScale(scales: Array<number>, deviceScale: number): number {
   // Packager guarantees that `scales` array is sorted
   for (var i = 0; i < scales.length; i++) {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java
index 90d97e17ef85..db9fb05df8eb 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java
@@ -37,7 +37,7 @@ public void loadScript(ReactBridge bridge) {
 
       @Override
       public String getSourceUrl() {
-        return fileName;
+        return (fileName.startsWith("assets://") ? "" : "file://") + fileName;
       }
     };
   }
diff --git a/local-cli/bundle/__tests__/getAssetDestPathAndroid-test.js b/local-cli/bundle/__tests__/getAssetDestPathAndroid-test.js
index 1613b5b3656a..3f58299549cc 100644
--- a/local-cli/bundle/__tests__/getAssetDestPathAndroid-test.js
+++ b/local-cli/bundle/__tests__/getAssetDestPathAndroid-test.js
@@ -8,7 +8,9 @@
  */
 'use strict';
 
-jest.dontMock('../getAssetDestPathAndroid');
+jest
+  .dontMock('../getAssetDestPathAndroid')
+  .dontMock('../assetPathUtils');
 
 const getAssetDestPathAndroid = require('../getAssetDestPathAndroid');
 
diff --git a/local-cli/bundle/assetPathUtils.js b/local-cli/bundle/assetPathUtils.js
new file mode 100644
index 000000000000..cf14b2c62cf0
--- /dev/null
+++ b/local-cli/bundle/assetPathUtils.js
@@ -0,0 +1,56 @@
+/**
+ * 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.
+ */
+'use strict';
+
+function getAndroidAssetSuffix(scale) {
+  switch (scale) {
+    case 0.75: return 'ldpi';
+    case 1: return 'mdpi';
+    case 1.5: return 'hdpi';
+    case 2: return 'xhdpi';
+    case 3: return 'xxhdpi';
+    case 4: return 'xxxhdpi';
+  }
+}
+
+function getAndroidDrawableFolderName(asset, scale) {
+  var suffix = getAndroidAssetSuffix(scale);
+  if (!suffix) {
+    throw new Error(
+      'Don\'t know which android drawable suffix to use for asset: ' +
+      JSON.stringify(asset)
+    );
+  }
+  const androidFolder = 'drawable-' + suffix;
+  return androidFolder;
+}
+
+function getAndroidResourceIdentifier(asset) {
+  var folderPath = getBasePath(asset);
+  return (folderPath + '/' + asset.name)
+    .toLowerCase()
+    .replace(/\//g, '_')           // Encode folder structure in file name
+    .replace(/([^a-z0-9_])/g, '')  // Remove illegal chars
+    .replace(/^assets_/, '');      // Remove "assets_" prefix
+}
+
+function getBasePath(asset) {
+  var basePath = asset.httpServerLocation;
+  if (basePath[0] === '/') {
+    basePath = basePath.substr(1);
+  }
+  return basePath;
+}
+
+module.exports = {
+  getAndroidAssetSuffix: getAndroidAssetSuffix,
+  getAndroidDrawableFolderName: getAndroidDrawableFolderName,
+  getAndroidResourceIdentifier: getAndroidResourceIdentifier,
+  getBasePath: getBasePath
+};
\ No newline at end of file
diff --git a/local-cli/bundle/getAssetDestPathAndroid.js b/local-cli/bundle/getAssetDestPathAndroid.js
index 3e039f54fd5e..f462ba5e81d1 100644
--- a/local-cli/bundle/getAssetDestPathAndroid.js
+++ b/local-cli/bundle/getAssetDestPathAndroid.js
@@ -9,34 +9,11 @@
 'use strict';
 
 const path = require('path');
-
-function getAndroidAssetSuffix(scale) {
-  switch (scale) {
-    case 0.75: return 'ldpi';
-    case 1: return 'mdpi';
-    case 1.5: return 'hdpi';
-    case 2: return 'xhdpi';
-    case 3: return 'xxhdpi';
-    case 4: return 'xxxhdpi';
-  }
-}
+const assetPathUtils = require('./assetPathUtils');
 
 function getAssetDestPathAndroid(asset, scale) {
-  var suffix = getAndroidAssetSuffix(scale);
-  if (!suffix) {
-    throw new Error(
-      'Don\'t know which android drawable suffix to use for asset: ' +
-      JSON.stringify(asset)
-    );
-  }
-  const androidFolder = 'drawable-' + suffix;
-  // TODO: reuse this logic from https://fburl.com/151101135
-  const fileName = (asset.httpServerLocation.substr(1) + '/' + asset.name)
-    .toLowerCase()
-    .replace(/\//g, '_')           // Encode folder structure in file name
-    .replace(/([^a-z0-9_])/g, '')  // Remove illegal chars
-    .replace(/^assets_/, '');      // Remove "assets_" prefix
-
+  const androidFolder = assetPathUtils.getAndroidDrawableFolderName(asset, scale);
+  const fileName =  assetPathUtils.getAndroidResourceIdentifier(asset);
   return path.join(androidFolder, fileName + '.' + asset.type);
 }
 

From 435efadbba319f63b4267eb322a4eda3c70c21ef Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Wed, 6 Jan 2016 09:02:55 -0800
Subject: [PATCH 0628/1411] Re-enable testUnderlyingBridgeIsDeallocated

Reviewed By: jspahrsummers

Differential Revision: D2803543

fb-gh-sync-id: d62b68b1e23fad2a0b3d4e490459b1f38ca2dca1
---
 .../UIExplorerUnitTests/RCTAllocationTests.m  | 25 +++++++++++--------
 .../UIExplorerUnitTests/RCTBridgeTests.m      | 14 +++++------
 .../UIExplorerUnitTests/RCTGzipTests.m        | 13 +++++-----
 React/Base/RCTBatchedBridge.m                 |  7 +++---
 4 files changed, 31 insertions(+), 28 deletions(-)

diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m
index dd53ee8ec1cc..a52400ffcb3f 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTAllocationTests.m
@@ -22,13 +22,12 @@
 #import "RCTRootView.h"
 
 #define RUN_RUNLOOP_WHILE(CONDITION) \
-_Pragma("clang diagnostic push") \
-_Pragma("clang diagnostic ignored \"-Wshadow\"") \
-NSDate *timeout = [[NSDate date] dateByAddingTimeInterval:5]; \
-while ((CONDITION) && [timeout timeIntervalSinceNow] > 0) { \
-  [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:timeout]; \
-} \
-_Pragma("clang diagnostic pop")
+{ \
+  NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:5]; \
+  while ((CONDITION) && [timeout timeIntervalSinceNow] > 0) { \
+    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; \
+  } \
+}
 
 @interface RCTJavaScriptContext : NSObject
 
@@ -212,8 +211,6 @@ - (void)testContentViewIsInvalidated
   XCTAssertFalse(rootContentView.userInteractionEnabled, @"RCTContentView should have been invalidated");
 }
 
-// This test is flaky, and needs to be fixed before re-enabling. See t9456702.
-#if 0
 - (void)testUnderlyingBridgeIsDeallocated
 {
   RCTBridge *bridge;
@@ -229,7 +226,15 @@ - (void)testUnderlyingBridgeIsDeallocated
 
   XCTAssertNotNil(bridge, @"RCTBridge should not have been deallocated");
   XCTAssertNil(batchedBridge, @"RCTBatchedBridge should have been deallocated");
+
+  // Wait to complete the test until the new batchedbridge is also deallocated
+  @autoreleasepool {
+    batchedBridge = bridge.batchedBridge;
+    bridge = nil;
+  }
+
+  RUN_RUNLOOP_WHILE(batchedBridge != nil);
+  XCTAssertNil(batchedBridge);
 }
-#endif
 
 @end
diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m
index d428fb441819..31fc8f74ee9e 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m
@@ -21,15 +21,13 @@
 #import "RCTJavaScriptExecutor.h"
 #import "RCTUtils.h"
 
-
 #define RUN_RUNLOOP_WHILE(CONDITION) \
-_Pragma("clang diagnostic push") \
-_Pragma("clang diagnostic ignored \"-Wshadow\"") \
-NSDate *timeout = [[NSDate date] dateByAddingTimeInterval:0.1]; \
-while ((CONDITION) && [timeout timeIntervalSinceNow] > 0) { \
-[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:timeout]; \
-} \
-_Pragma("clang diagnostic pop")
+{ \
+  NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:5]; \
+  while ((CONDITION) && [timeout timeIntervalSinceNow] > 0) { \
+    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; \
+  } \
+}
 
 @interface TestExecutor : NSObject <RCTJavaScriptExecutor>
 
diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTGzipTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTGzipTests.m
index 55b53e48dbd1..9d5814c56a5b 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTGzipTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTGzipTests.m
@@ -17,13 +17,12 @@
 #import "RCTNetworking.h"
 
 #define RUN_RUNLOOP_WHILE(CONDITION) \
-_Pragma("clang diagnostic push") \
-_Pragma("clang diagnostic ignored \"-Wshadow\"") \
-NSDate *timeout = [[NSDate date] dateByAddingTimeInterval:5]; \
-while ((CONDITION) && [timeout timeIntervalSinceNow] > 0) { \
-  [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:timeout]; \
-} \
-_Pragma("clang diagnostic pop")
+{ \
+  NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:5]; \
+  while ((CONDITION) && [timeout timeIntervalSinceNow] > 0) { \
+    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; \
+  } \
+}
 
 extern BOOL RCTIsGzippedData(NSData *data);
 
diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index 3031c1a54afe..185d6379eb3c 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -175,9 +175,7 @@ - (void)start
   dispatch_group_notify(initModulesAndLoadSource, dispatch_get_main_queue(), ^{
     RCTBatchedBridge *strongSelf = weakSelf;
     if (sourceCode && strongSelf.loading) {
-      dispatch_async(bridgeQueue, ^{
-        [weakSelf executeSourceCode:sourceCode];
-      });
+      [strongSelf executeSourceCode:sourceCode];
     }
   });
 }
@@ -570,6 +568,7 @@ - (void)invalidate
   }
 
   RCTAssertMainThread();
+  RCTAssert(_javaScriptExecutor != nil, @"Can't complete invalidation without a JS executor");
 
   _loading = NO;
   _valid = NO;
@@ -605,11 +604,13 @@ - (void)invalidate
       if (RCTProfileIsProfiling()) {
         RCTProfileUnhookModules(self);
       }
+
       _moduleDataByName = nil;
       _moduleDataByID = nil;
       _moduleClassesByID = nil;
       _modulesByName_DEPRECATED = nil;
       _frameUpdateObservers = nil;
+      _pendingCalls = nil;
 
     }];
   });

From adfc573a75977fbc7c69c23db7a65af78f05112a Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieter.debaets@gmail.com>
Date: Wed, 6 Jan 2016 10:50:08 +0000
Subject: [PATCH 0629/1411] Move tests to iOS9.2

---
 .travis.yml          | 2 +-
 scripts/e2e-test.sh  | 4 ++--
 scripts/objc-test.sh | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 25221640fccd..67ac1cc42ecd 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,6 @@
 language: objective-c
 
-osx_image: xcode7
+osx_image: xcode7.2
 
 cache:
     directories:
diff --git a/scripts/e2e-test.sh b/scripts/e2e-test.sh
index e51a40827222..731a96edf7b2 100755
--- a/scripts/e2e-test.sh
+++ b/scripts/e2e-test.sh
@@ -2,6 +2,7 @@
 
 # Abort the mission if any command fails
 set -e
+set -x
 
 SCRIPTS=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
 ROOT=$(dirname $SCRIPTS)
@@ -58,9 +59,8 @@ npm unpublish react-native-cli --force
 npm publish $ROOT
 npm publish $ROOT/react-native-cli
 
-
 npm install -g react-native-cli
-react-native init EndToEndTest
+react-native init EndToEndTest --verbose
 cd EndToEndTest/ios
 
 # Make sure we installed local version of react-native
diff --git a/scripts/objc-test.sh b/scripts/objc-test.sh
index 7a68e2107e72..ce41e798d6e8 100755
--- a/scripts/objc-test.sh
+++ b/scripts/objc-test.sh
@@ -28,5 +28,5 @@ trap cleanup EXIT
 SERVER_PID=$!
 xctool \
   -project Examples/UIExplorer/UIExplorer.xcodeproj \
-  -scheme UIExplorer -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 5,OS=9.0' \
+  -scheme UIExplorer -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 5,OS=9.2' \
   test

From 4bc425c521a9de7e07e5ce7e469e94cb53ea2670 Mon Sep 17 00:00:00 2001
From: Alex Rothberg <agrothberg@gmail.com>
Date: Wed, 6 Jan 2016 09:16:40 -0800
Subject: [PATCH 0630/1411] Added stickyHeaderIndices to ListView

Summary:
Closes #3870

Alternatively I could make this a bool `stickyheader` that just adds `0` to  the `stickyHeaderIndices` passed down to the ScrollView.
Closes https://github.com/facebook/react-native/pull/4213

Reviewed By: svcscm

Differential Revision: D2807414

Pulled By: androidtrunkagent

fb-gh-sync-id: 091b6c6c91cebe175181f57b5c2785395b5db19b
---
 Libraries/CustomComponents/ListView/ListView.js | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js
index 366971f3fbd9..db1cbaee1014 100644
--- a/Libraries/CustomComponents/ListView/ListView.js
+++ b/Libraries/CustomComponents/ListView/ListView.js
@@ -203,6 +203,15 @@ var ListView = React.createClass({
      * containers.  This is enabled by default.
      */
     removeClippedSubviews: React.PropTypes.bool,
+    /**
+     * An array of child indices determining which children get docked to the
+     * top of the screen when scrolling. For example, passing
+     * `stickyHeaderIndices={[0]}` will cause the first child to be fixed to the
+     * top of the scroll view. This property is not supported in conjunction
+     * with `horizontal={true}`.
+     * @platform ios
+     */
+    stickyHeaderIndices: PropTypes.arrayOf(PropTypes.number),
   },
 
   /**
@@ -242,6 +251,7 @@ var ListView = React.createClass({
       renderScrollComponent: props => <ScrollView {...props} />,
       scrollRenderAheadDistance: DEFAULT_SCROLL_RENDER_AHEAD,
       onEndReachedThreshold: DEFAULT_END_REACHED_THRESHOLD,
+      stickyHeaderIndices: [],
     };
   },
 
@@ -394,7 +404,7 @@ var ListView = React.createClass({
     }
     Object.assign(props, {
       onScroll: this._onScroll,
-      stickyHeaderIndices: sectionHeaderIndices,
+      stickyHeaderIndices: this.props.stickyHeaderIndices.concat(sectionHeaderIndices),
 
       // Do not pass these events downstream to ScrollView since they will be
       // registered in ListView's own ScrollResponder.Mixin

From 49b020a776b74ed4e9b2de4fca2759972526bf52 Mon Sep 17 00:00:00 2001
From: Nick Baugh <niftylettuce@gmail.com>
Date: Tue, 5 Jan 2016 23:39:50 -0500
Subject: [PATCH 0631/1411] Added reference to Frappe, a tool for OS X that
 easily lets you reload developer tools menu with menubar/tray and hotkey

Adjusted sentence per https://github.com/facebook/react-native/pull/5137#discussion_r48966919
---
 docs/Debugging.md               |  2 +-
 docs/DevelopmentSetupAndroid.md | 14 +++++++-------
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/docs/Debugging.md b/docs/Debugging.md
index 259f6ca7d992..6391d516a35e 100644
--- a/docs/Debugging.md
+++ b/docs/Debugging.md
@@ -11,7 +11,7 @@ next: testing
 To access the in-app developer menu:
 
 1. On iOS shake the device or press `control + ⌘ + z` in the simulator.
-2. On Android shake the device or press hardware menu button (available on older devices and in most of the emulators, e.g. in [genymotion](https://www.genymotion.com) you can press `⌘ + m` to simulate hardware menu button click)
+2. On Android shake the device or press hardware menu button (available on older devices and in most of the emulators, e.g. in [genymotion](https://www.genymotion.com) you can press `⌘ + m` to simulate hardware menu button click). You can also install [Frappé](http://getfrappe.com), a tool for OS X, which allows you to emulate shaking of devices remotely. You can use `⌘ + Shift + R` as a shortcut to trigger a **shake** from Frappé.
 
 > Hint
 
diff --git a/docs/DevelopmentSetupAndroid.md b/docs/DevelopmentSetupAndroid.md
index 23bf6a6366e1..bf7ec1e20888 100644
--- a/docs/DevelopmentSetupAndroid.md
+++ b/docs/DevelopmentSetupAndroid.md
@@ -7,7 +7,7 @@ permalink: docs/android-setup.html
 next: linux-windows-support
 ---
 
-This guide describes basic steps of the Android development environment setup that are required to run React Native android apps on an android emulator. We don't discuss developer tool configuration such as IDEs here.  
+This guide describes basic steps of the Android development environment setup that are required to run React Native android apps on an android emulator. We don't discuss developer tool configuration such as IDEs here.
 
 ### Install Git
 
@@ -17,8 +17,8 @@ This guide describes basic steps of the Android development environment setup th
 
   - **On Linux**, install Git [via your package manager](https://git-scm.com/download/linux).
 
-  - **On Windows**, download and install [Git for Windows](https://git-for-windows.github.io/). During the setup process, choose "Run Git from Windows Command Prompt", which will add Git to your `PATH` environment variable.  
-  
+  - **On Windows**, download and install [Git for Windows](https://git-for-windows.github.io/). During the setup process, choose "Run Git from Windows Command Prompt", which will add Git to your `PATH` environment variable.
+
 ### Install the Android SDK (unless you have it)
 
 1. [Install the latest JDK](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
@@ -35,11 +35,11 @@ __IMPORTANT__: Make sure the `ANDROID_HOME` environment variable points to your
         # If you installed the SDK via Homebrew, otherwise ~/Library/Android/sdk
         export ANDROID_HOME=/usr/local/opt/android-sdk
   - **On Linux**, add this to your `~/.bashrc`, `~/.bash_profile` or whatever your shell uses:
-        
+
         export ANDROID_HOME=<path_where_you_unpacked_android_sdk>
 
-  - **On Windows**, go to `Control Panel` -> `System and Security` -> `System` -> `Change settings` -> `Advanced` -> `Environment variables` -> `New`   
-   
+  - **On Windows**, go to `Control Panel` -> `System and Security` -> `System` -> `Change settings` -> `Advanced` -> `Environment variables` -> `New`
+
 __NOTE__: You need to restart the Command Prompt (Windows) / Terminal Emulator (Mac OS X, Linux) to apply the new Environment variables.
 
 
@@ -77,4 +77,4 @@ Genymotion is much easier to set up than stock Google emulators. However, it's o
   1. Run `android avd` and click on **Create...**
   ![Create AVD dialog](/react-native/img/CreateAVD.png)
   2. With the new AVD selected, click `Start...`
-5. To bring up the developer menu press F2
+5. To bring up the developer menu press F2 (or install [Frappé](http://getfrappe.com))

From d875aac3c8dab83786c99e0638c51bd50aa67c88 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Wed, 6 Jan 2016 09:46:56 -0800
Subject: [PATCH 0632/1411] Resolve requires on HMR

Summary:
public

Requires are transformed when building the bundle but we forgot doing so when building the HMR one.

Reviewed By: vjeux

Differential Revision: D2801319

fb-gh-sync-id: ae70612945ab81a05154b14d6b756ef390770542
---
 local-cli/server/util/attachHMRServer.js      |  6 ++-
 packager/react-packager/src/Bundler/index.js  | 52 +++++++++++--------
 packager/react-packager/src/Resolver/index.js | 18 +++++--
 3 files changed, 50 insertions(+), 26 deletions(-)

diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js
index 2b1ff4334520..81d186ef7a43 100644
--- a/local-cli/server/util/attachHMRServer.js
+++ b/local-cli/server/util/attachHMRServer.js
@@ -151,7 +151,11 @@ function attachHMRServer({httpServer, path, packagerServer}) {
                 return;
               }
 
-              return packagerServer.buildBundleForHMR(modulesToUpdate);
+              return packagerServer.buildBundleForHMR({
+                entryFile: client.bundleEntry,
+                platform: client.platform,
+                modules: modulesToUpdate,
+              });
             })
             .then(bundle => {
               if (bundle) {
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index bbb4d3bb49c5..23cf71a9a0cf 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -284,29 +284,37 @@ class Bundler {
     });
   }
 
-  bundleForHMR(modules) {
-    return Promise.all(
-      modules.map(module => {
-        return Promise.all([
-          module.getName(),
-          this._transformer.loadFileAndTransform(
-            module.path,
-            // TODO(martinb): pass non null main (t9527509)
-            this._getTransformOptions({main: null}, {hot: true}),
-          ),
-        ]).then(([moduleName, transformedSource]) => {
-          return (`
-            __accept(
-              '${moduleName}',
-              function(global, require, module, exports) {
-                ${transformedSource.code}
-              }
-            );
-          `);
-        });
+  bundleForHMR({entryFile, platform, modules}) {
+    return this.getDependencies(entryFile, /*isDev*/true, platform)
+      .then(response => {
+        return Promise.all(
+          modules.map(module => {
+            return Promise.all([
+              module.getName(),
+              this._transformer.loadFileAndTransform(
+                module.path,
+                // TODO(martinb): pass non null main (t9527509)
+                this._getTransformOptions({main: null}, {hot: true}),
+              ),
+            ]).then(([moduleName, transformed]) => {
+              return this._resolver.resolveRequires(response,
+                module,
+                transformed.code,
+              ).then(({name, code}) => {
+                return (`
+                  __accept(
+                    '${moduleName}',
+                    function(global, require, module, exports) {
+                      ${code}
+                    }
+                  );
+                `);
+              });
+            });
+          })
+        );
       })
-    )
-    .then(code => code.join('\n'));
+      .then(modules => modules.join('\n'));
   }
 
   invalidateFile(filePath) {
diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index efa61d576aa7..8726233e8c55 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -165,7 +165,7 @@ class Resolver {
     );
   }
 
-  wrapModule(resolutionResponse, module, code) {
+  resolveRequires(resolutionResponse, module, code) {
     return Promise.resolve().then(() => {
       if (module.isPolyfill()) {
         return Promise.resolve({code});
@@ -200,12 +200,24 @@ class Resolver {
           .replace(replacePatterns.EXPORT_RE, relativizeCode)
           .replace(replacePatterns.REQUIRE_RE, relativizeCode);
 
-        return module.getName().then(name =>
-          ({name, code: defineModuleCode(name, code)}));
+        return module.getName().then(name => {
+          return {name, code};
+        });
       });
     });
   }
 
+  wrapModule(resolutionResponse, module, code) {
+    if (module.isPolyfill()) {
+      return Promise.resolve({code});
+    }
+
+    return this.resolveRequires(resolutionResponse, module, code).then(
+      ({name, code}) => {
+        return {name, code: defineModuleCode(name, code)};
+      });
+  }
+
   getDebugInfo() {
     return this._depGraph.getDebugInfo();
   }

From 51d8ed92d5c491b1be945f4d86c6e583a77abe38 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Wed, 6 Jan 2016 09:46:59 -0800
Subject: [PATCH 0633/1411] Move HMR to internal transform

Summary:
public

We want to support Hot Loading on the packager itself instead of on the transformer. This will allow us to enable it on OSS (and for any scripting language, yay!).

For now to enable Hot Loading the packager's internals transforms need to be manually enabled (start packager with `--enable-internal-transforms`). I think the internal pipeline should always be enabled as it doesn't affect performance if there're no transforms and the user can disable Hot Loading through the setting on the app though. I'll tweak this on a follow up commit.

Reviewed By: vjeux

Differential Revision: D2801343

fb-gh-sync-id: 563984d77b10c3925fda6fd5616b814cdbea2c66
---
 local-cli/server/runServer.js                 |  1 -
 local-cli/server/server.js                    |  4 ---
 packager/react-packager/src/Bundler/index.js  |  5 ----
 .../react-packager/src/JSTransformer/index.js |  6 -----
 .../src/JSTransformer/worker.js               | 17 +++++--------
 packager/react-packager/src/Server/index.js   |  4 ---
 .../react-packager/src/transforms/index.js    | 25 ++++++++++++++++---
 packager/transformer.js                       |  2 --
 8 files changed, 27 insertions(+), 37 deletions(-)

diff --git a/local-cli/server/runServer.js b/local-cli/server/runServer.js
index 871cea102b0d..b4a690f4c170 100644
--- a/local-cli/server/runServer.js
+++ b/local-cli/server/runServer.js
@@ -68,7 +68,6 @@ function getAppMiddleware(args, config) {
     cacheVersion: '3',
     getTransformOptionsModulePath: config.getTransformOptionsModulePath,
     transformModulePath: transformerPath,
-    enableInternalTransforms: args['enable-internal-transforms'],
     assetRoots: args.assetRoots,
     assetExts: ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'webp'],
     resetCache: args.resetCache || args['reset-cache'],
diff --git a/local-cli/server/server.js b/local-cli/server/server.js
index a5ffe43f2d39..3abffb5beef4 100644
--- a/local-cli/server/server.js
+++ b/local-cli/server/server.js
@@ -53,10 +53,6 @@ function _server(argv, config, resolve, reject) {
     type: 'string',
     default: require.resolve('../../packager/transformer'),
     description: 'Specify a custom transformer to be used (absolute path)'
-  }, {
-    command: 'enable-internal-transforms',
-    type: 'boolean',
-    default: false
   }, {
     command: 'resetCache',
     description: 'Removes cached files',
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index 23cf71a9a0cf..26de31301ad9 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -56,10 +56,6 @@ const validateOpts = declareOpts({
     type:'string',
     required: false,
   },
-  enableInternalTransforms: {
-    type: 'boolean',
-    default: false,
-  },
   nonPersistent: {
     type: 'boolean',
     default: false,
@@ -135,7 +131,6 @@ class Bundler {
       blacklistRE: opts.blacklistRE,
       cache: this._cache,
       transformModulePath: opts.transformModulePath,
-      enableInternalTransforms: opts.enableInternalTransforms,
     });
 
     this._projectRoots = opts.projectRoots;
diff --git a/packager/react-packager/src/JSTransformer/index.js b/packager/react-packager/src/JSTransformer/index.js
index 1bb845d7afd3..2688e14cf47c 100644
--- a/packager/react-packager/src/JSTransformer/index.js
+++ b/packager/react-packager/src/JSTransformer/index.js
@@ -53,10 +53,6 @@ const validateOpts = declareOpts({
     type: 'number',
     default: DEFAULT_MAX_CALL_TIME,
   },
-  enableInternalTransforms: {
-    type: 'boolean',
-    default: false,
-  },
 });
 
 class Transformer {
@@ -65,7 +61,6 @@ class Transformer {
 
     this._cache = opts.cache;
     this._transformModulePath = opts.transformModulePath;
-    this._enableInternalTransforms = opts.enableInternalTransforms;
 
     if (opts.transformModulePath != null) {
       this._workers = workerFarm({
@@ -111,7 +106,6 @@ class Transformer {
             options: {
               ...options,
               externalTransformModulePath: this._transformModulePath,
-              enableInternalTransforms: this._enableInternalTransforms,
             },
           }).then(res => {
             if (res.error) {
diff --git a/packager/react-packager/src/JSTransformer/worker.js b/packager/react-packager/src/JSTransformer/worker.js
index ef4a529c97bd..5e6e953b970e 100644
--- a/packager/react-packager/src/JSTransformer/worker.js
+++ b/packager/react-packager/src/JSTransformer/worker.js
@@ -22,7 +22,7 @@ function internalTransforms(sourceCode, filename, options) {
     filename: filename,
     sourceFileName: filename,
     sourceMaps: false,
-    plugins: Transforms.getAll()
+    plugins: Transforms.getAll(options)
   });
 
   return {
@@ -37,16 +37,11 @@ function onExternalTransformDone(data, callback, error, externalOutput) {
     return;
   }
 
-  var result;
-  if (data.options.enableInternalTransforms) {
-    result = internalTransforms(
-      externalOutput.code,
-      externalOutput.filename,
-      data.options
-    );
-  } else {
-    result = externalOutput;
-  }
+  var result = internalTransforms(
+    externalOutput.code,
+    externalOutput.filename,
+    data.options
+  );
 
   callback(null, result);
 }
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index 858bc0e4f915..f5c5b34ec099 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -52,10 +52,6 @@ const validateOpts = declareOpts({
     type: 'boolean',
     default: false,
   },
-  enableInternalTransforms: {
-    type: 'boolean',
-    default: false,
-  },
   assetRoots: {
     type: 'array',
     required: false,
diff --git a/packager/react-packager/src/transforms/index.js b/packager/react-packager/src/transforms/index.js
index 1e55a34b3701..33cb24622d1d 100644
--- a/packager/react-packager/src/transforms/index.js
+++ b/packager/react-packager/src/transforms/index.js
@@ -8,9 +8,26 @@
  */
 'use strict';
 
-exports.getAll = function() {
-  return [
-    require('./babel-plugin-system-import'),
-  ];
+exports.getAll = function(options) {
+  var plugins = [];
+  if (options.hot) {
+    plugins = plugins.concat([
+      [
+        'react-transform',
+        {
+          transforms: [{
+            transform: 'react-transform-hmr/lib/index.js',
+            imports: ['React'],
+            locals: ['module'],
+          }]
+        },
+      ],
+      'transform-es2015-block-scoping',
+      'transform-es2015-constants',
+      ['transform-es2015-modules-commonjs', {strict: false, allowTopLevelThis: true}],
+    ]);
+  }
+
+  return plugins;
 };
 
diff --git a/packager/transformer.js b/packager/transformer.js
index 512686065a06..8a178c86997c 100644
--- a/packager/transformer.js
+++ b/packager/transformer.js
@@ -54,8 +54,6 @@ function transform(src, filename, options) {
     return plugin;
   });
 
-  config.plugins = config.plugins.concat(ReactPackager.getTransforms());
-
   const result = babel.transform(src, Object.assign({}, babelRC, config));
 
   return {

From 385fa00af882f642bb6e1c9eb4bb98386b69d80f Mon Sep 17 00:00:00 2001
From: Noah Jorgenson <noah.m.jorgenson@gmail.com>
Date: Wed, 6 Jan 2016 10:19:09 -0800
Subject: [PATCH 0634/1411] Docs for manual linking in PushNotificationsIOS

Summary:
close #3831
Closes https://github.com/facebook/react-native/pull/5008

Reviewed By: svcscm

Differential Revision: D2794281

Pulled By: bestander

fb-gh-sync-id: 7bf367233fa562b5772fae51511b47cd29030ba2
---
 Libraries/PushNotificationIOS/PushNotificationIOS.js | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/Libraries/PushNotificationIOS/PushNotificationIOS.js b/Libraries/PushNotificationIOS/PushNotificationIOS.js
index aa3e13fd1d2f..45ade9478dc5 100644
--- a/Libraries/PushNotificationIOS/PushNotificationIOS.js
+++ b/Libraries/PushNotificationIOS/PushNotificationIOS.js
@@ -30,7 +30,13 @@ var NOTIF_REGISTER_EVENT = 'remoteNotificationsRegistered';
  * To get up and running, [configure your notifications with Apple](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/AddingCapabilities/AddingCapabilities.html#//apple_ref/doc/uid/TP40012582-CH26-SW6)
  * and your server-side system. To get an idea, [this is the Parse guide](https://parse.com/tutorials/ios-push-notifications).
  *
- * To enable support for `notification` and `register` events you need to augment your AppDelegate.
+ * [Manually link](https://facebook.github.io/react-native/docs/linking-libraries-ios.html#manual-linking) the PushNotificationIOS library
+ *
+ * - Be sure to add the following to your `Header Search Paths`:
+ * `$(SRCROOT)/../node_modules/react-native/Libraries/PushNotificationIOS`
+ * - Set the search to `recursive`
+ *
+ * Finally, to enable support for `notification` and `register` events you need to augment your AppDelegate.
  *
  * At the top of your `AppDelegate.m`:
  *

From 33e05a11f00d1455f39b6dfef1c76c4130df02e5 Mon Sep 17 00:00:00 2001
From: Emilio Rodriguez <emiliorodriguez@gmail.com>
Date: Wed, 6 Jan 2016 10:24:48 -0800
Subject: [PATCH 0635/1411] Added scrollTo method to ListView

Summary: Closes https://github.com/facebook/react-native/pull/4781

Reviewed By: svcscm

Differential Revision: D2803479

Pulled By: mkonicek

fb-gh-sync-id: 7da41eb0bdfb0f90b4f81d1006eaf00446820827
---
 Libraries/CustomComponents/ListView/ListView.js | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js
index db1cbaee1014..9f0ae724e98a 100644
--- a/Libraries/CustomComponents/ListView/ListView.js
+++ b/Libraries/CustomComponents/ListView/ListView.js
@@ -236,6 +236,10 @@ var ListView = React.createClass({
       this.refs[SCROLLVIEW_REF].getScrollResponder();
   },
 
+  scrollTo: function(destY, destX) {
+    this.getScrollResponder().scrollResponderScrollTo(destX || 0, destY || 0);
+  },
+
   setNativeProps: function(props) {
     this.refs[SCROLLVIEW_REF].setNativeProps(props);
   },

From 7b63b225a50f7e38300b898ec63ac8af434c009b Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Wed, 6 Jan 2016 10:32:13 -0800
Subject: [PATCH 0636/1411] remove a typo

Summary:
I can't guess the point. Just simply removed this typo.
Closes https://github.com/facebook/react-native/pull/4943

Reviewed By: svcscm

Differential Revision: D2786863

Pulled By: bestander

fb-gh-sync-id: 0f36f796cae23bacb86ffe224b6b05915e228f47
---
 Libraries/Animated/src/AnimatedImplementation.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/Animated/src/AnimatedImplementation.js b/Libraries/Animated/src/AnimatedImplementation.js
index 9fdda5323fc5..87602fc778f3 100644
--- a/Libraries/Animated/src/AnimatedImplementation.js
+++ b/Libraries/Animated/src/AnimatedImplementation.js
@@ -577,7 +577,7 @@ class AnimatedValue extends AnimatedWithChildren {
 
   /**
    * Adds an asynchronous listener to the value so you can observe updates from
-   * animations or whathaveyou.  This is useful because there is no way to
+   * animations.  This is useful because there is no way to
    * synchronously read the value because it might be driven natively.
    */
   addListener(callback: ValueListenerCallback): string {

From 61025a9b33c1f835526748f2a06c9773c3bfddb6 Mon Sep 17 00:00:00 2001
From: Ognen Ivanovski <ognen.ivanovski@netcetera.com>
Date: Wed, 6 Jan 2016 10:32:23 -0800
Subject: [PATCH 0637/1411] bugfix: NavigatoriOS doesn't update any scenes when
 0th scene is replaced

Summary:
Calling navigator.replace(0, scene) has no effect.

This is because 0 is false in Javascript so when

    this.state.updatingAllIndicesAtOrBeyond == 0

(meaning update all indices starting with 0)

The whole expression evaluates to 0, i.e. false ->  therefore no update
happens.

Explicitly checking for not-equal to null (!= will convert undefined to null automatically) fixes the issue.
Closes https://github.com/facebook/react-native/pull/5155

Reviewed By: svcscm

Differential Revision: D2807397

Pulled By: nicklockwood

fb-gh-sync-id: 519a4ab35c86b0b608808b36593f5f8c2ecd1561
---
 Libraries/Components/Navigation/NavigatorIOS.ios.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/Components/Navigation/NavigatorIOS.ios.js b/Libraries/Components/Navigation/NavigatorIOS.ios.js
index e21cc6d85271..6635a25bb8a9 100644
--- a/Libraries/Components/Navigation/NavigatorIOS.ios.js
+++ b/Libraries/Components/Navigation/NavigatorIOS.ios.js
@@ -639,7 +639,7 @@ var NavigatorIOS = React.createClass({
     var {component, wrapperStyle, passProps, ...route} = route;
     var {itemWrapperStyle, ...props} = this.props;
     var shouldUpdateChild =
-      this.state.updatingAllIndicesAtOrBeyond &&
+      this.state.updatingAllIndicesAtOrBeyond != null &&
       this.state.updatingAllIndicesAtOrBeyond >= i;
     var Component = component;
     return (

From 3d0ff69e40f0262e0ffc6f6023ec958b52eeb986 Mon Sep 17 00:00:00 2001
From: Quentin Valmori <quentin.valmori@gmail.com>
Date: Wed, 6 Jan 2016 11:00:15 -0800
Subject: [PATCH 0638/1411] Map follow user location

Summary:
Fix #3105

It's the same PR as #3119 but as I force-pushed in my branch, I can't reopen the PR. I added an example.
![capture d ecran 2016-01-05 a 07 15 37](https://cloud.githubusercontent.com/assets/1107936/12108841/2727f504-b37c-11e5-8250-b53785930aba.png)
Closes https://github.com/facebook/react-native/pull/5126

Reviewed By: svcscm

Differential Revision: D2803052

Pulled By: nicklockwood

fb-gh-sync-id: 2e8978ff1b293d699462a8290b45fa74cc16b4dd
---
 Examples/UIExplorer/MapViewExample.js   | 10 +++++++--
 Libraries/Components/MapView/MapView.js | 27 +++++++++++++++++--------
 React/Views/RCTMap.m                    |  4 ----
 React/Views/RCTMapManager.m             |  4 +---
 4 files changed, 28 insertions(+), 17 deletions(-)

diff --git a/Examples/UIExplorer/MapViewExample.js b/Examples/UIExplorer/MapViewExample.js
index 498a5f83df0d..bd1173a83fea 100644
--- a/Examples/UIExplorer/MapViewExample.js
+++ b/Examples/UIExplorer/MapViewExample.js
@@ -290,9 +290,15 @@ exports.examples = [
     }
   },
   {
-    title: 'Map shows user location',
+    title: 'showsUserLocation + followUserLocation',
     render() {
-      return <MapView style={styles.map} showsUserLocation={true} />;
+      return (
+        <MapView
+          style={styles.map}
+          showsUserLocation={true}
+          followUserLocation={true}
+        />
+      );
     }
   },
   {
diff --git a/Libraries/Components/MapView/MapView.js b/Libraries/Components/MapView/MapView.js
index 2ccb4b8cb4d5..ec25733039be 100644
--- a/Libraries/Components/MapView/MapView.js
+++ b/Libraries/Components/MapView/MapView.js
@@ -49,15 +49,22 @@ const MapView = React.createClass({
     style: View.propTypes.style,
 
     /**
-     * If `true` the app will ask for the user's location and focus on it.
-     * Default value is `false`.
+     * If `true` the app will ask for the user's location and display it on
+     * the map. Default value is `false`.
      *
-     * **NOTE**: You need to add NSLocationWhenInUseUsageDescription key in
-     * Info.plist to enable geolocation, otherwise it is going
-     * to *fail silently*!
+     * **NOTE**: on iOS, you need to add the `NSLocationWhenInUseUsageDescription`
+     * key in Info.plist to enable geolocation, otherwise it will fail silently.
      */
     showsUserLocation: React.PropTypes.bool,
 
+    /**
+     * If `true` the map will follow the user's location whenever it changes.
+     * Note that this has no effect unless `showsUserLocation` is enabled.
+     * Default value is `true`.
+     * @platform ios
+     */
+    followUserLocation: React.PropTypes.bool,
+    
     /**
      * If `false` points of interest won't be displayed on the map.
      * Default value is `true`.
@@ -156,13 +163,11 @@ const MapView = React.createClass({
       
       /**
        * Whether the pin should be draggable or not
-       * @platform ios
        */
       draggable: React.PropTypes.bool,
 
       /**
        * Event that fires when the annotation drag state changes.
-       * @platform ios
        */  
       onDragStateChange: React.PropTypes.func,
 
@@ -282,7 +287,7 @@ const MapView = React.createClass({
   },
 
   render: function() {
-    let children = [], {annotations, overlays} = this.props;
+    let children = [], {annotations, overlays, followUserLocation} = this.props;
     annotations = annotations && annotations.map((annotation: Object) => {
       let {
         id,
@@ -430,11 +435,17 @@ const MapView = React.createClass({
       };
     }
 
+    // followUserLocation defaults to true if showUserLocation is set
+    if (followUserLocation === undefined) {
+      followUserLocation = this.props.showUserLocation;
+    }
+
     return (
       <RCTMap
         {...this.props}
         annotations={annotations}
         children={children}
+        followUserLocation={followUserLocation}
         overlays={overlays}
         onPress={onPress}
         onChange={onChange}
diff --git a/React/Views/RCTMap.m b/React/Views/RCTMap.m
index 6996eb2b3a7f..0d8e56c806fa 100644
--- a/React/Views/RCTMap.m
+++ b/React/Views/RCTMap.m
@@ -100,10 +100,6 @@ - (void)setShowsUserLocation:(BOOL)showsUserLocation
       }
     }
     super.showsUserLocation = showsUserLocation;
-
-    // If it needs to show user location, force map view centered
-    // on user's current location on user location updates
-    _followUserLocation = showsUserLocation;
   }
 }
 
diff --git a/React/Views/RCTMapManager.m b/React/Views/RCTMapManager.m
index f12705b283e2..74517b4c40db 100644
--- a/React/Views/RCTMapManager.m
+++ b/React/Views/RCTMapManager.m
@@ -85,6 +85,7 @@ - (UIView *)view
 RCT_EXPORT_VIEW_PROPERTY(showsUserLocation, BOOL)
 RCT_EXPORT_VIEW_PROPERTY(showsPointsOfInterest, BOOL)
 RCT_EXPORT_VIEW_PROPERTY(showsCompass, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(followUserLocation, BOOL)
 RCT_EXPORT_VIEW_PROPERTY(zoomEnabled, BOOL)
 RCT_EXPORT_VIEW_PROPERTY(rotateEnabled, BOOL)
 RCT_EXPORT_VIEW_PROPERTY(pitchEnabled, BOOL)
@@ -320,9 +321,6 @@ - (void)mapView:(RCTMap *)mapView didUpdateUserLocation:(MKUserLocation *)locati
     region.span.longitudeDelta = RCTMapDefaultSpan;
     region.center = location.coordinate;
     [mapView setRegion:region animated:YES];
-
-    // Move to user location only for the first time it loads up.
-    mapView.followUserLocation = NO;
   }
 }
 

From 7ecb6936bc9b4e03325fd7906540a62089bc30d7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Henrik=20Kok=20J=C3=B8rgensen?= <henrikj@me.com>
Date: Wed, 6 Jan 2016 11:02:35 -0800
Subject: [PATCH 0639/1411] Dont call npm before node is available

Summary:
This fixes an error introduced in `0.18.0-rc`

`node` and `npm` isn't available if the developer is using `nvm` or `nodeenv`. XCode throws an error because of the call to `npm`. Simple move the line to after `node` and `npm` has been setup.
Closes https://github.com/facebook/react-native/pull/5156

Reviewed By: svcscm

Differential Revision: D2807589

Pulled By: androidtrunkagent

fb-gh-sync-id: 30c33145b2cb6f30ff67f6648153d5aa67fb74ed
---
 packager/react-native-xcode.sh | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/packager/react-native-xcode.sh b/packager/react-native-xcode.sh
index b655222f222b..898862618acd 100755
--- a/packager/react-native-xcode.sh
+++ b/packager/react-native-xcode.sh
@@ -29,9 +29,6 @@ cd ..
 set -x
 DEST=$CONFIGURATION_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH
 
-# npm global install path may be a non-standard location
-PATH="$(npm prefix -g)/bin:$PATH"
-
 # Define NVM_DIR and source the nvm.sh setup script
 [ -z "$NVM_DIR" ] && export NVM_DIR="$HOME/.nvm"
 
@@ -46,6 +43,9 @@ if [[ -x "$HOME/.nodenv/bin/nodenv" ]]; then
   eval "$($HOME/.nodenv/bin/nodenv init -)"
 fi
 
+# npm global install path may be a non-standard location
+PATH="$(npm prefix -g)/bin:$PATH"
+
 react-native bundle \
   --entry-file index.ios.js \
   --platform ios \

From 37b724eaa62c1d55cf43161c46f97b4e2c2a918d Mon Sep 17 00:00:00 2001
From: gitim <timur.gbd@gmail.com>
Date: Wed, 6 Jan 2016 11:11:43 -0800
Subject: [PATCH 0640/1411] Fix missing keys in animation example

Summary:
There were two warnings about missing keys, fixed them.
Closes https://github.com/facebook/react-native/pull/5153

Reviewed By: svcscm

Differential Revision: D2807602

Pulled By: androidtrunkagent

fb-gh-sync-id: ef7a5eecd297e89b7338fdec65639785a1232f13
---
 Examples/UIExplorer/AnimatedGratuitousApp/AnExBobble.js  | 1 +
 Examples/UIExplorer/AnimatedGratuitousApp/AnExChained.js | 1 +
 2 files changed, 2 insertions(+)

diff --git a/Examples/UIExplorer/AnimatedGratuitousApp/AnExBobble.js b/Examples/UIExplorer/AnimatedGratuitousApp/AnExBobble.js
index bebad819d5c5..d3e603738c34 100644
--- a/Examples/UIExplorer/AnimatedGratuitousApp/AnExBobble.js
+++ b/Examples/UIExplorer/AnimatedGratuitousApp/AnExBobble.js
@@ -95,6 +95,7 @@ class AnExBobble extends React.Component {
           return (
             <Animated.Image
               {...handlers}
+              key={i}
               source={{uri: BOBBLE_IMGS[j]}}
               style={[styles.circle, {
                 backgroundColor: randColor(),                             // re-renders are obvious
diff --git a/Examples/UIExplorer/AnimatedGratuitousApp/AnExChained.js b/Examples/UIExplorer/AnimatedGratuitousApp/AnExChained.js
index cf4083cff8c1..f2c932a2449c 100644
--- a/Examples/UIExplorer/AnimatedGratuitousApp/AnExChained.js
+++ b/Examples/UIExplorer/AnimatedGratuitousApp/AnExChained.js
@@ -77,6 +77,7 @@ class AnExChained extends React.Component {
           return (
             <Animated.Image
               {...handlers}
+              key={i}
               source={{uri: CHAIN_IMGS[j]}}
               style={[styles.sticker, {
                 transform: this.state.stickers[j].getTranslateTransform(), // simple conversion

From d6513ca03f14c39fb4825598564297e29f5ca5be Mon Sep 17 00:00:00 2001
From: Elliot Hesp <elliot.hesp@gmail.com>
Date: Wed, 6 Jan 2016 11:51:34 -0800
Subject: [PATCH 0641/1411] Add "Only supports one child" to
 TouchableWithoutFeedback

Summary: Closes https://github.com/facebook/react-native/pull/4985

Reviewed By: svcscm

Differential Revision: D2794384

Pulled By: bestander

fb-gh-sync-id: 7332a83df635619d1d6bfacbf6e9c71af90179d9
---
 Libraries/Components/Touchable/TouchableWithoutFeedback.js | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Libraries/Components/Touchable/TouchableWithoutFeedback.js b/Libraries/Components/Touchable/TouchableWithoutFeedback.js
index 8c04c945709c..96bcb6bf9ed8 100755
--- a/Libraries/Components/Touchable/TouchableWithoutFeedback.js
+++ b/Libraries/Components/Touchable/TouchableWithoutFeedback.js
@@ -29,6 +29,10 @@ var PRESS_RETENTION_OFFSET = {top: 20, left: 20, right: 20, bottom: 30};
  * Do not use unless you have a very good reason. All the elements that
  * respond to press should have a visual feedback when touched. This is
  * one of the primary reason a "web" app doesn't feel "native".
+ * 
+ * > **NOTE**: TouchableWithoutFeedback supports only one child
+ * >
+ * > If you wish to have several child components, wrap them in a View.
  */
 var TouchableWithoutFeedback = React.createClass({
   mixins: [TimerMixin, Touchable.Mixin],

From 0f9c88514c1ff5ee66106f198a0ccd365c542070 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Wed, 6 Jan 2016 11:54:25 -0800
Subject: [PATCH 0642/1411] Remove `hot` query string attribut when HL is
 disabled

Summary:
public

By doing this we fix 2 problems:

1. We use the same url, both the first time the simulator starts with Hot Loading disabled (no `hot` attribute), and after HL has been enabled and then disabled ('hot=false'). By doing so, the packager will rebuild more than one bundle as file changes. We could have ignored this attribute on the packager but I'd rather not contaminate the server with it and instead make the clients send only 2 types of URLs.

2. The code on `RCTBatchedBridge.m` that decides whether or not to enable HMR does so by looking at presence of the query string parameter `hot`. If the parameter is present, even when it's false, it will try to enable HL, which is wrong.

Reviewed By: nicklockwood

Differential Revision: D2807512

fb-gh-sync-id: 728b680c2383c328d8967d34c10e7a6288e455ac
---
 .../UIExplorerUnitTests/RCTURLUtilsTests.m    |  7 +++++++
 React/Base/RCTUtils.m                         | 20 ++++++++++++-------
 React/Modules/RCTDevMenu.m                    |  2 +-
 3 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTURLUtilsTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTURLUtilsTests.m
index 2c23af2b9926..c2f6db568765 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTURLUtilsTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTURLUtilsTests.m
@@ -79,6 +79,13 @@ - (void)testAppendParam
   XCTAssertEqualObjects(result.absoluteString, @"http://example.com?bar=foo&foo=bar");
 }
 
+- (void)testRemoveParam
+{
+  NSURL *URL = [NSURL URLWithString:@"http://example.com?bar=foo&foo=bar"];
+  NSURL *result = RCTURLByReplacingQueryParam(URL, @"bar", nil);
+  XCTAssertEqualObjects(result.absoluteString, @"http://example.com?foo=bar");
+}
+
 - (void)testNilURLAppendQueryParam
 {
   NSURL *URL = nil;
diff --git a/React/Base/RCTUtils.m b/React/Base/RCTUtils.m
index 5a83b8adb029..48e1fea08d26 100644
--- a/React/Base/RCTUtils.m
+++ b/React/Base/RCTUtils.m
@@ -638,14 +638,20 @@ static void RCTGetRGBAColorComponents(CGColorRef color, CGFloat rgba[4])
      }
    }];
 
-  NSString *encodedValue =
-  [value stringByAddingPercentEncodingWithAllowedCharacters:URLParamCharacterSet];
-
-  NSString *newItem = [encodedParam stringByAppendingFormat:@"=%@", encodedValue];
-  if (paramIndex == NSNotFound) {
-    [queryItems addObject:newItem];
+  if (!value) {
+    if (paramIndex != NSNotFound) {
+      [queryItems removeObjectAtIndex:paramIndex];
+    }
   } else {
-    [queryItems replaceObjectAtIndex:paramIndex withObject:newItem];
+    NSString *encodedValue =
+    [value stringByAddingPercentEncodingWithAllowedCharacters:URLParamCharacterSet];
+
+    NSString *newItem = [encodedParam stringByAppendingFormat:@"=%@", encodedValue];
+    if (paramIndex == NSNotFound) {
+      [queryItems addObject:newItem];
+    } else {
+      [queryItems replaceObjectAtIndex:paramIndex withObject:newItem];
+    }
   }
   components.percentEncodedQuery = [queryItems componentsJoinedByString:@"&"];
   return components.URL;
diff --git a/React/Modules/RCTDevMenu.m b/React/Modules/RCTDevMenu.m
index 22d01416db7f..a9e92e6cf30e 100644
--- a/React/Modules/RCTDevMenu.m
+++ b/React/Modules/RCTDevMenu.m
@@ -544,7 +544,7 @@ - (void)setHotLoadingEnabled:(BOOL)enabled
   BOOL actuallyEnabled = [self hotLoadingAvailable] && _hotLoadingEnabled;
   if (RCTGetURLQueryParam(_bridge.bundleURL, @"hot").boolValue != actuallyEnabled) {
     _bridge.bundleURL = RCTURLByReplacingQueryParam(_bridge.bundleURL, @"hot",
-                                                    actuallyEnabled ? @"true" : @"false");
+                                                    actuallyEnabled ? @"true" : nil);
     [_bridge reload];
   }
 }

From 0b15418d92dbbbc22bdf6fe0655d27ea0473c522 Mon Sep 17 00:00:00 2001
From: Michael Lee <mzlee@fb.com>
Date: Wed, 6 Jan 2016 13:01:24 -0800
Subject: [PATCH 0643/1411] snprintf off by one.

Summary:
According to `man snprintf`

    Upon successful return, these functions return the number of
    characters printed (not including the trailing '\0' used to end
    output to strings).

Or am I misunderstanding something about what's going on here?

public

Reviewed By: zlern2k, dcolascione

Differential Revision: D2805759

fb-gh-sync-id: f20908f80cdfff9677fe38c7c1cf733f0f5b1c5e
---
 ReactAndroid/src/main/jni/first-party/jni/fbjni/Exceptions.cpp | 2 +-
 ReactAndroid/src/main/jni/first-party/jni/fbjni/Exceptions.h   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/Exceptions.cpp b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Exceptions.cpp
index 20925ae80724..710a6836f1ca 100644
--- a/ReactAndroid/src/main/jni/first-party/jni/fbjni/Exceptions.cpp
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Exceptions.cpp
@@ -193,7 +193,7 @@ void setNewJavaException(jclass exceptionClass, const char* fmt, ARGS... args) {
   JNIEnv* env = internal::getEnv();
 
   try {
-    char *msg = (char*) alloca(msgSize);
+    char *msg = (char*) alloca(msgSize + 1);
     snprintf(msg, kMaxExceptionMessageBufferSize, fmt, args...);
     env->ThrowNew(exceptionClass, msg);
   } catch (...) {
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/Exceptions.h b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Exceptions.h
index 9ba9367f67e5..1892fd49c87b 100644
--- a/ReactAndroid/src/main/jni/first-party/jni/fbjni/Exceptions.h
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Exceptions.h
@@ -114,7 +114,7 @@ template<typename... Args>
   assertIfExceptionsNotInitialized();
   int msgSize = snprintf(nullptr, 0, fmt, args...);
 
-  char *msg = (char*) alloca(msgSize);
+  char *msg = (char*) alloca(msgSize + 1);
   snprintf(msg, kMaxExceptionMessageBufferSize, fmt, args...);
   throwNewJavaException(throwableName, msg);
 }

From bdbadfd96657df925b0fc65a893915254b9c78e8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Wed, 6 Jan 2016 13:28:58 -0800
Subject: [PATCH 0644/1411] Make sure client is still connected while computing
 HMR update

Reviewed By: vjeux

Differential Revision: D2803506

fb-gh-sync-id: a182343947d52724e48709a8114fa48e8c97a7e2
---
 local-cli/server/util/attachHMRServer.js | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js
index 81d186ef7a43..dd22f5303c7d 100644
--- a/local-cli/server/util/attachHMRServer.js
+++ b/local-cli/server/util/attachHMRServer.js
@@ -113,6 +113,10 @@ function attachHMRServer({httpServer, path, packagerServer}) {
 
           return packagerServer.getShallowDependencies(filename)
             .then(deps => {
+              if (!client) {
+                return [];
+              }
+
               // if the file dependencies have change we need to invalidate the
               // dependencies caches because the list of files we need to send
               // to the client may have changed
@@ -129,6 +133,10 @@ function attachHMRServer({httpServer, path, packagerServer}) {
                   dependenciesModulesCache,
                   shallowDependencies,
                 }) => {
+                  if (!client) {
+                    return [];
+                  }
+
                   // build list of modules for which we'll send HMR updates
                   const modulesToUpdate = [];
                   Object.keys(dependenciesModulesCache).forEach(module => {
@@ -146,6 +154,10 @@ function attachHMRServer({httpServer, path, packagerServer}) {
                 });
             })
             .then(modulesToUpdate => {
+              if (!client) {
+                return;
+              }
+
               // make sure the file was modified is part of the bundle
               if (!client.shallowDependencies[filename]) {
                 return;
@@ -158,6 +170,11 @@ function attachHMRServer({httpServer, path, packagerServer}) {
               });
             })
             .then(bundle => {
+              if (!client) {
+                return;
+              }
+
+              // check we actually want to send an HMR update
               if (bundle) {
                 client.ws.send(bundle);
               }

From 0b9f623cd07ebe2518125101a7731a7135e526e4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Wed, 6 Jan 2016 14:50:18 -0800
Subject: [PATCH 0645/1411] babel-plugin-react-transform should be a regular
 dependency

Reviewed By: vjeux

Differential Revision: D2803782

fb-gh-sync-id: 58c3660dde226479dbfd180ce6a83f91b5a15465
---
 npm-shrinkwrap.json | 174 ++++++++++++++++++++++----------------------
 package.json        |   4 +-
 2 files changed, 89 insertions(+), 89 deletions(-)

diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index c08e18f6a90b..9cc1229db7cc 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -269,6 +269,11 @@
           "from": "ast-types@0.8.12",
           "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz"
         },
+        "globals": {
+          "version": "6.4.1",
+          "from": "globals@>=6.4.0 <7.0.0",
+          "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
+        },
         "babylon": {
           "version": "5.8.29",
           "from": "babylon@>=5.8.29 <6.0.0",
@@ -279,11 +284,6 @@
           "from": "esprima-fb@>=15001.1001.0-dev-harmony-fb <15001.1002.0",
           "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz"
         },
-        "globals": {
-          "version": "6.4.1",
-          "from": "globals@>=6.4.0 <7.0.0",
-          "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
-        },
         "js-tokens": {
           "version": "1.0.1",
           "from": "js-tokens@1.0.1",
@@ -1869,6 +1869,11 @@
           "from": "ansi-regex@^2.0.0",
           "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
         },
+        "are-we-there-yet": {
+          "version": "1.0.4",
+          "from": "are-we-there-yet@~1.0.0",
+          "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.4.tgz"
+        },
         "ansi-styles": {
           "version": "2.1.0",
           "from": "ansi-styles@^2.1.0",
@@ -1879,66 +1884,61 @@
           "from": "asn1@0.1.11",
           "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
         },
-        "are-we-there-yet": {
-          "version": "1.0.4",
-          "from": "are-we-there-yet@~1.0.0",
-          "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.4.tgz"
+        "async": {
+          "version": "1.5.0",
+          "from": "async@^1.4.0",
+          "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz"
         },
         "assert-plus": {
           "version": "0.1.5",
           "from": "assert-plus@^0.1.5",
           "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
         },
-        "async": {
-          "version": "1.5.0",
-          "from": "async@^1.4.0",
-          "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz"
-        },
         "aws-sign2": {
           "version": "0.6.0",
           "from": "aws-sign2@~0.6.0",
           "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
         },
-        "balanced-match": {
-          "version": "0.2.1",
-          "from": "balanced-match@>=0.2.0 <0.3.0",
-          "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.1.tgz"
-        },
         "block-stream": {
           "version": "0.0.8",
           "from": "block-stream@*",
           "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.8.tgz"
         },
+        "balanced-match": {
+          "version": "0.2.1",
+          "from": "balanced-match@>=0.2.0 <0.3.0",
+          "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.1.tgz"
+        },
         "boom": {
           "version": "2.10.1",
           "from": "boom@^2.8.x",
           "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz"
         },
-        "caseless": {
-          "version": "0.11.0",
-          "from": "caseless@~0.11.0",
-          "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
-        },
         "brace-expansion": {
           "version": "1.1.1",
           "from": "brace-expansion@>=1.0.0 <2.0.0",
           "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz"
         },
+        "caseless": {
+          "version": "0.11.0",
+          "from": "caseless@~0.11.0",
+          "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
+        },
         "chalk": {
           "version": "1.1.1",
           "from": "chalk@^1.1.1",
           "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz"
         },
-        "combined-stream": {
-          "version": "1.0.5",
-          "from": "combined-stream@~1.0.5",
-          "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz"
-        },
         "commander": {
           "version": "2.9.0",
           "from": "commander@^2.8.1",
           "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz"
         },
+        "combined-stream": {
+          "version": "1.0.5",
+          "from": "combined-stream@~1.0.5",
+          "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz"
+        },
         "concat-map": {
           "version": "0.0.1",
           "from": "concat-map@0.0.1",
@@ -1949,16 +1949,16 @@
           "from": "core-util-is@~1.0.0",
           "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
         },
-        "cryptiles": {
-          "version": "2.0.5",
-          "from": "cryptiles@2.x.x",
-          "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz"
-        },
         "ctype": {
           "version": "0.5.3",
           "from": "ctype@0.5.3",
           "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz"
         },
+        "cryptiles": {
+          "version": "2.0.5",
+          "from": "cryptiles@2.x.x",
+          "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz"
+        },
         "debug": {
           "version": "0.7.4",
           "from": "debug@~0.7.2",
@@ -1969,16 +1969,16 @@
           "from": "deep-extend@~0.2.5",
           "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.2.11.tgz"
         },
-        "delayed-stream": {
-          "version": "1.0.0",
-          "from": "delayed-stream@~1.0.0",
-          "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
-        },
         "delegates": {
           "version": "0.1.0",
           "from": "delegates@^0.1.0",
           "resolved": "https://registry.npmjs.org/delegates/-/delegates-0.1.0.tgz"
         },
+        "delayed-stream": {
+          "version": "1.0.0",
+          "from": "delayed-stream@~1.0.0",
+          "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
+        },
         "escape-string-regexp": {
           "version": "1.0.3",
           "from": "escape-string-regexp@^1.0.2",
@@ -2009,6 +2009,11 @@
           "from": "gauge@~1.2.0",
           "resolved": "https://registry.npmjs.org/gauge/-/gauge-1.2.2.tgz"
         },
+        "generate-function": {
+          "version": "2.0.0",
+          "from": "generate-function@^2.0.0",
+          "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz"
+        },
         "generate-object-property": {
           "version": "1.2.0",
           "from": "generate-object-property@^1.1.0",
@@ -2019,16 +2024,6 @@
           "from": "graceful-fs@4.1",
           "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.2.tgz"
         },
-        "generate-function": {
-          "version": "2.0.0",
-          "from": "generate-function@^2.0.0",
-          "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz"
-        },
-        "har-validator": {
-          "version": "2.0.2",
-          "from": "har-validator@~2.0.2",
-          "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.2.tgz"
-        },
         "graceful-readlink": {
           "version": "1.0.1",
           "from": "graceful-readlink@>= 1.0.0",
@@ -2039,16 +2034,21 @@
           "from": "has-ansi@^2.0.0",
           "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
         },
-        "has-unicode": {
-          "version": "1.0.1",
-          "from": "has-unicode@^1.0.0",
-          "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-1.0.1.tgz"
+        "har-validator": {
+          "version": "2.0.2",
+          "from": "har-validator@~2.0.2",
+          "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.2.tgz"
         },
         "hawk": {
           "version": "3.1.0",
           "from": "hawk@~3.1.0",
           "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.0.tgz"
         },
+        "has-unicode": {
+          "version": "1.0.1",
+          "from": "has-unicode@^1.0.0",
+          "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-1.0.1.tgz"
+        },
         "hoek": {
           "version": "2.16.3",
           "from": "hoek@2.x.x",
@@ -2064,16 +2064,16 @@
           "from": "inherits@*",
           "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
         },
-        "ini": {
-          "version": "1.3.4",
-          "from": "ini@~1.3.0",
-          "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz"
-        },
         "is-my-json-valid": {
           "version": "2.12.2",
           "from": "is-my-json-valid@^2.12.2",
           "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.2.tgz"
         },
+        "ini": {
+          "version": "1.3.4",
+          "from": "ini@~1.3.0",
+          "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz"
+        },
         "is-property": {
           "version": "1.0.2",
           "from": "is-property@^1.0.0",
@@ -2084,26 +2084,21 @@
           "from": "isarray@0.0.1",
           "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
         },
-        "isstream": {
-          "version": "0.1.2",
-          "from": "isstream@~0.1.2",
-          "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
-        },
         "json-stringify-safe": {
           "version": "5.0.1",
           "from": "json-stringify-safe@~5.0.1",
           "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
         },
+        "isstream": {
+          "version": "0.1.2",
+          "from": "isstream@~0.1.2",
+          "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
+        },
         "jsonpointer": {
           "version": "2.0.0",
           "from": "jsonpointer@2.0.0",
           "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
         },
-        "lodash._basetostring": {
-          "version": "3.0.1",
-          "from": "lodash._basetostring@^3.0.0",
-          "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz"
-        },
         "lodash._createpadding": {
           "version": "3.6.1",
           "from": "lodash._createpadding@^3.0.0",
@@ -2114,6 +2109,11 @@
           "from": "lodash.pad@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-3.1.1.tgz"
         },
+        "lodash._basetostring": {
+          "version": "3.0.1",
+          "from": "lodash._basetostring@^3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz"
+        },
         "lodash.padleft": {
           "version": "3.1.1",
           "from": "lodash.padleft@^3.0.0",
@@ -2149,16 +2149,16 @@
           "from": "mkdirp@>=0.3.0 <0.4.0||>=0.4.0 <0.5.0||>=0.5.0 <0.6.0",
           "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz"
         },
-        "node-uuid": {
-          "version": "1.4.3",
-          "from": "node-uuid@~1.4.3",
-          "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.3.tgz"
-        },
         "npmlog": {
           "version": "1.2.1",
           "from": "npmlog@~1.2.0",
           "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz"
         },
+        "node-uuid": {
+          "version": "1.4.3",
+          "from": "node-uuid@~1.4.3",
+          "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.3.tgz"
+        },
         "oauth-sign": {
           "version": "0.8.0",
           "from": "oauth-sign@~0.8.0",
@@ -2179,16 +2179,16 @@
           "from": "pinkie@^1.0.0",
           "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
         },
-        "pinkie-promise": {
-          "version": "1.0.0",
-          "from": "pinkie-promise@^1.0.0",
-          "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz"
-        },
         "qs": {
           "version": "5.2.0",
           "from": "qs@~5.2.0",
           "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz"
         },
+        "pinkie-promise": {
+          "version": "1.0.0",
+          "from": "pinkie-promise@^1.0.0",
+          "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz"
+        },
         "readable-stream": {
           "version": "1.1.13",
           "from": "readable-stream@^1.1.13",
@@ -2199,25 +2199,25 @@
           "from": "request@2.x",
           "resolved": "https://registry.npmjs.org/request/-/request-2.65.0.tgz"
         },
-        "semver": {
-          "version": "5.0.3",
-          "from": "semver@~5.0.1",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
-        },
         "sntp": {
           "version": "1.0.9",
           "from": "sntp@1.x.x",
           "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
         },
+        "stringstream": {
+          "version": "0.0.5",
+          "from": "stringstream@~0.0.4",
+          "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
+        },
         "string_decoder": {
           "version": "0.10.31",
           "from": "string_decoder@~0.10.x",
           "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
         },
-        "stringstream": {
-          "version": "0.0.5",
-          "from": "stringstream@~0.0.4",
-          "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
+        "semver": {
+          "version": "5.0.3",
+          "from": "semver@~5.0.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
         },
         "strip-ansi": {
           "version": "3.0.0",
diff --git a/package.json b/package.json
index ea1449c01bc2..37e7a79c1c4b 100644
--- a/package.json
+++ b/package.json
@@ -109,6 +109,7 @@
     "react": "^0.14.5",
     "react-timer-mixin": "^0.13.2",
     "react-transform-hmr": "^1.0.1",
+    "babel-plugin-react-transform": "2.0.0-beta1",
     "rebound": "^0.0.13",
     "regenerator": "^0.8.36",
     "sane": "^1.2.0",
@@ -130,7 +131,6 @@
     "eslint": "1.3.1",
     "eslint-plugin-react": "3.3.1",
     "portfinder": "0.4.0",
-    "temp": "0.8.3",
-    "babel-plugin-react-transform": "2.0.0-beta1"
+    "temp": "0.8.3"
   }
 }

From 472fafa86c475f0b0748f399b4b48a238c287d7e Mon Sep 17 00:00:00 2001
From: Jack Hsu <jack.hsu@gmail.com>
Date: Wed, 6 Jan 2016 21:25:49 -0500
Subject: [PATCH 0646/1411] Adds alternative method of opening the dev menu
 using `adb shell input keyevent 82`

---
 docs/RunningOnDeviceAndroid.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/RunningOnDeviceAndroid.md b/docs/RunningOnDeviceAndroid.md
index 1b64faf22dd8..845c91599b6f 100644
--- a/docs/RunningOnDeviceAndroid.md
+++ b/docs/RunningOnDeviceAndroid.md
@@ -28,7 +28,7 @@ You can also iterate quickly on device using the development server. Follow one
 
 > Hint
 >
-> Most modern android devices don't have a hardware menu button, which we use to trigger the developer menu. In that case you can shake the device to open the dev menu (to reload, debug, etc.)
+> Most modern android devices don't have a hardware menu button, which we use to trigger the developer menu. In that case you can shake the device to open the dev menu (to reload, debug, etc.). Alternatively, you can run the command `adb shell input keyevent 82` to open the dev menu (82 being the [Menu](http://developer.android.com/reference/android/view/KeyEvent.html#KEYCODE_MENU) key code).
 
 ### Using adb reverse
 

From b75c939d59dad8ff9939c0b7882ef0f4f10e9b8e Mon Sep 17 00:00:00 2001
From: Olivier Notteghem <oli@fb.com>
Date: Wed, 6 Jan 2016 19:15:16 -0800
Subject: [PATCH 0647/1411] Fix corner case bug in ListView

Reviewed By: sahrens

Differential Revision: D2802885

fb-gh-sync-id: e4bb82e3c63ded2af46f5b078b712636d3afa156
---
 .../CustomComponents/ListView/ListView.js     | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js
index 9f0ae724e98a..fb1210304467 100644
--- a/Libraries/CustomComponents/ListView/ListView.js
+++ b/Libraries/CustomComponents/ListView/ListView.js
@@ -294,13 +294,22 @@ var ListView = React.createClass({
   componentWillReceiveProps: function(nextProps) {
     if (this.props.dataSource !== nextProps.dataSource) {
       this.setState((state, props) => {
-        var rowsToRender = Math.min(
-          state.curRenderedRowsCount + props.pageSize,
-          props.dataSource.getRowCount()
-        );
         this._prevRenderedRowsCount = 0;
         return {
-          curRenderedRowsCount: rowsToRender,
+          curRenderedRowsCount: Math.min(
+            state.curRenderedRowsCount + props.pageSize,
+            props.dataSource.getRowCount()
+          ),
+        };
+      });
+    }
+    if (this.props.initialListSize !== nextProps.initialListSize) {
+      this.setState((state, props) => {
+        return {
+          curRenderedRowsCount: Math.max(
+            state.curRenderedRowsCount,
+            props.initialListSize
+          ),
         };
       });
     }

From dee984d1ddc8e2cdb0eef51bd0470744c92058eb Mon Sep 17 00:00:00 2001
From: DengYun <tdzl2003>
Date: Thu, 7 Jan 2016 11:43:01 +0800
Subject: [PATCH 0648/1411] Do some dirty for windows compatible

---
 react-native-cli/index.js | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/react-native-cli/index.js b/react-native-cli/index.js
index 01c8f0e64a3a..306191bccd95 100755
--- a/react-native-cli/index.js
+++ b/react-native-cli/index.js
@@ -42,6 +42,7 @@ var spawn = require('child_process').spawn;
 var chalk = require('chalk');
 var prompt = require('prompt');
 var semver = require('semver');
+var os = require('os');
 
 var CLI_MODULE_PATH = function() {
   return path.resolve(
@@ -198,7 +199,14 @@ function run(root, projectName, logLevel) {
   if (logLevel === 'debug' || logLevel === 'verbose') {
     spawnArgs = {stdio: 'inherit'};
   }
-  var proc = spawn('npm', args, spawnArgs);
+  var proc;
+  if (os.platform() === 'win32'){
+    args.unshift('npm');
+    args.unshift('/c');
+    proc = spawn('cmd', args, spawnArgs);
+  } else {
+    proc = spawn('npm', args, spawnArgs);
+  }
   proc.on('close', function (code) {
     if (code !== 0) {
       console.error('`npm install --save react-native` failed');

From 7bb60449bd550055f7c1d05527191c6d3cb4b6ba Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Wed, 6 Jan 2016 20:03:30 -0800
Subject: [PATCH 0649/1411] Bail internal transforms if there're no transforms
 to run

Reviewed By: sam-swarr

Differential Revision: D2810474

fb-gh-sync-id: d5ba48922c91c3dbacfccb0d087cc1deac14fa1c
---
 packager/react-packager/src/JSTransformer/worker.js | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/packager/react-packager/src/JSTransformer/worker.js b/packager/react-packager/src/JSTransformer/worker.js
index 5e6e953b970e..27542274a370 100644
--- a/packager/react-packager/src/JSTransformer/worker.js
+++ b/packager/react-packager/src/JSTransformer/worker.js
@@ -15,6 +15,14 @@ var Transforms = require('../transforms');
 // transforms should be run after the external ones to ensure that they run on
 // Javascript code
 function internalTransforms(sourceCode, filename, options) {
+  var plugins = Transforms.getAll(options);
+  if (plugins.length === 0) {
+    return {
+      code: sourceCode,
+      filename: filename,
+    };
+  }
+
   var result = babel.transform(sourceCode, {
     retainLines: true,
     compact: true,
@@ -22,7 +30,7 @@ function internalTransforms(sourceCode, filename, options) {
     filename: filename,
     sourceFileName: filename,
     sourceMaps: false,
-    plugins: Transforms.getAll(options)
+    plugins: plugins,
   });
 
   return {

From 9037d374e1f90ebc4adfe2c678b8288b9def8b49 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Wed, 6 Jan 2016 22:37:08 -0800
Subject: [PATCH 0650/1411] Remove Hot Loading option from Dev Menu

Reviewed By: jingc

Differential Revision: D2810788

fb-gh-sync-id: cda3b802ee2b744b76253ec48bbd0c6e45c36d9f
---
 React/Modules/RCTDevMenu.m | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/React/Modules/RCTDevMenu.m b/React/Modules/RCTDevMenu.m
index a9e92e6cf30e..23f2184f4594 100644
--- a/React/Modules/RCTDevMenu.m
+++ b/React/Modules/RCTDevMenu.m
@@ -531,9 +531,7 @@ - (void)setLiveReloadEnabled:(BOOL)enabled
 
 - (BOOL)hotLoadingAvailable
 {
-  return !_bridge.bundleURL.fileURL // Only works when running from server
-  && [_bridge.delegate respondsToSelector:@selector(bridgeSupportsHotLoading:)]
-  && [_bridge.delegate bridgeSupportsHotLoading:_bridge];
+  return false;
 }
 
 - (void)setHotLoadingEnabled:(BOOL)enabled

From 23cd9febbc63b633f8ef8be25387df21c1c52b7e Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 7 Jan 2016 01:29:43 -0800
Subject: [PATCH 0651/1411] Fixed deadlock in RCTModuleData

Summary:
public
Fixed a potential deadlock issue if code attempted to access a module via [bridge moduleForName/Class:] while it was being initialized.

Reviewed By: lry

Differential Revision: D2807827

fb-gh-sync-id: 58cafe9b92c094dde632d17245fb9b342a0fe9e0
---
 React/Base/RCTBatchedBridge.m |  9 +--------
 React/Base/RCTModuleData.h    |  9 ++++++++-
 React/Base/RCTModuleData.m    | 26 ++++++++++++++++----------
 3 files changed, 25 insertions(+), 19 deletions(-)

diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index 185d6379eb3c..e619c67d7494 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -333,14 +333,7 @@ - (void)initModules
 
   for (RCTModuleData *moduleData in _moduleDataByID) {
     if (moduleData.hasInstance) {
-      [moduleData methodQueue]; // initialize the queue
-    }
-  }
-
-  for (RCTModuleData *moduleData in _moduleDataByID) {
-    if (moduleData.hasInstance) {
-      [self registerModuleForFrameUpdates:moduleData.instance
-                           withModuleData:moduleData];
+      [moduleData finishSetupForInstance];
     }
   }
 
diff --git a/React/Base/RCTModuleData.h b/React/Base/RCTModuleData.h
index bf55892fd802..ec922c8042c9 100644
--- a/React/Base/RCTModuleData.h
+++ b/React/Base/RCTModuleData.h
@@ -25,11 +25,18 @@
 
 /**
  * Sets the bridge for the module instance. This is only needed when using the
- * `initWithModuleID:instance:` constructor. Otherwise, the bridge will be set
+ * `initWithModuleInstance:bridge:` constructor. Otherwise, the bridge will be set
  * automatically when the module is first accessed.
  */
 - (void)setBridgeForInstance;
 
+/**
+ * Sets the methodQueue and performs the remaining setup for the module. This is
+ * only needed when using the `initWithModuleInstance:bridge:` constructor.
+ * Otherwise it will be done automatically when the module is first accessed.
+ */
+- (void)finishSetupForInstance;
+
 @property (nonatomic, strong, readonly) Class moduleClass;
 @property (nonatomic, copy, readonly) NSString *name;
 
diff --git a/React/Base/RCTModuleData.m b/React/Base/RCTModuleData.m
index 2e290ce6c91b..d87edf430786 100644
--- a/React/Base/RCTModuleData.m
+++ b/React/Base/RCTModuleData.m
@@ -70,6 +70,18 @@ - (void)setBridgeForInstance
   }
 }
 
+- (void)finishSetupForInstance
+{
+  if (!_setupComplete) {
+    _setupComplete = YES;
+    [self setUpMethodQueue];
+    [_bridge registerModuleForFrameUpdates:_instance withModuleData:self];
+    [[NSNotificationCenter defaultCenter] postNotificationName:RCTDidInitializeModuleNotification
+                                                        object:_bridge
+                                                      userInfo:@{@"module": _instance}];
+  }
+}
+
 - (void)setUpMethodQueue
 {
   if (!_methodQueue) {
@@ -90,19 +102,13 @@ - (void)setUpMethodQueue
           [(id)_instance setValue:_methodQueue forKey:@"methodQueue"];
         }
         @catch (NSException *exception) {
-          RCTLogError(@"%@ is returning nil for it's methodQueue, which is not "
+          RCTLogError(@"%@ is returning nil for its methodQueue, which is not "
                       "permitted. You must either return a pre-initialized "
                       "queue, or @synthesize the methodQueue to let the bridge "
                       "create a queue for you.", self.name);
         }
       }
     }
-
-    // Needs to be sent after bridge has been set for all module instances.
-    // Makes sense to put it here, since the same rules apply for methodQueue.
-    [[NSNotificationCenter defaultCenter]
-     postNotificationName:RCTDidInitializeModuleNotification
-     object:_bridge userInfo:@{@"module": _instance}];
   }
 }
 
@@ -124,11 +130,11 @@ - (BOOL)hasInstance
     // initialization requires it (View Managers get their queue by calling
     // self.bridge.uiManager.methodQueue)
     [self setBridgeForInstance];
-    [self setUpMethodQueue];
-    [_bridge registerModuleForFrameUpdates:_instance withModuleData:self];
-    _setupComplete = YES;
   }
   [_instanceLock unlock];
+
+  [self finishSetupForInstance];
+
   return _instance;
 }
 

From c1b7a369af7ca457819d682b15f47fae7e2732fc Mon Sep 17 00:00:00 2001
From: Alexander Blom <blom@fb.com>
Date: Thu, 7 Jan 2016 03:51:22 -0800
Subject: [PATCH 0652/1411] Move UIManager annotations to separate package

Summary:
Moves ReactProp and ReactPropGroup to `com.facebook.react.uimanager.annotations`. This is needed
so that future annotation processor can run on code inside the com.facebook.react.uimanager package.

public

Reviewed By: astreet

Differential Revision: D2754842

fb-gh-sync-id: 3808c3e3f6c45e5897ecab88cd4175573c0c24e6
---
 .../com/facebook/react/uimanager/BaseViewManager.java    | 1 +
 .../com/facebook/react/uimanager/LayoutShadowNode.java   | 2 ++
 .../java/com/facebook/react/uimanager/ViewManager.java   | 2 ++
 .../react/uimanager/ViewManagersPropertyCache.java       | 2 ++
 .../react/uimanager/{ => annotations}/ReactProp.java     | 9 +++++----
 .../uimanager/{ => annotations}/ReactPropGroup.java      | 9 +++++----
 .../com/facebook/react/views/art/ARTShapeShadowNode.java | 2 +-
 .../com/facebook/react/views/art/ARTTextShadowNode.java  | 2 +-
 .../com/facebook/react/views/art/ARTVirtualNode.java     | 2 +-
 .../react/views/drawer/ReactDrawerLayoutManager.java     | 2 +-
 .../facebook/react/views/image/ReactImageManager.java    | 2 +-
 .../react/views/progressbar/ProgressBarShadowNode.java   | 2 +-
 .../views/progressbar/ReactProgressBarViewManager.java   | 2 +-
 .../RecyclerViewBackedScrollViewManager.java             | 2 +-
 .../views/scroll/ReactHorizontalScrollViewManager.java   | 2 +-
 .../react/views/scroll/ReactScrollViewManager.java       | 2 +-
 .../views/swiperefresh/SwipeRefreshLayoutManager.java    | 2 +-
 .../react/views/switchview/ReactSwitchManager.java       | 3 +--
 .../react/views/text/ReactTextInlineImageShadowNode.java | 2 +-
 .../facebook/react/views/text/ReactTextShadowNode.java   | 2 +-
 .../facebook/react/views/text/ReactTextViewManager.java  | 2 +-
 .../react/views/textinput/ReactTextInputManager.java     | 2 +-
 .../react/views/textinput/ReactTextInputShadowNode.java  | 2 +-
 .../react/views/toolbar/ReactToolbarManager.java         | 2 +-
 .../com/facebook/react/views/view/ReactViewManager.java  | 6 ++----
 .../react/views/webview/ReactWebViewManager.java         | 2 +-
 26 files changed, 38 insertions(+), 32 deletions(-)
 rename ReactAndroid/src/main/java/com/facebook/react/uimanager/{ => annotations}/ReactProp.java (95%)
 rename ReactAndroid/src/main/java/com/facebook/react/uimanager/{ => annotations}/ReactPropGroup.java (93%)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java
index 201effea750e..26e8adaad0b1 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java
@@ -7,6 +7,7 @@
 import android.view.View;
 
 import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.uimanager.annotations.ReactProp;
 
 /**
  * Base class that should be suitable for the majority of subclasses of {@link ViewManager}.
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java
index 31670c7165e3..97d83ea143de 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java
@@ -12,6 +12,8 @@
 import com.facebook.csslayout.CSSJustify;
 import com.facebook.csslayout.CSSPositionType;
 import com.facebook.csslayout.CSSWrap;
+import com.facebook.react.uimanager.annotations.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactPropGroup;
 
 /**
  * Supply setters for base view layout properties such as width, height, flex properties,
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java
index 816eda3b6a97..ab14daa10d24 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java
@@ -20,6 +20,8 @@
 import com.facebook.react.bridge.ReadableMapKeySetIterator;
 import com.facebook.react.touch.CatalystInterceptingViewGroup;
 import com.facebook.react.touch.JSResponderHandler;
+import com.facebook.react.uimanager.annotations.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactPropGroup;
 
 /**
  * Class responsible for knowing how to create and update catalyst Views of a given type. It is also
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagersPropertyCache.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagersPropertyCache.java
index 0e2a33148d60..ea1af2e550f4 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagersPropertyCache.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagersPropertyCache.java
@@ -15,6 +15,8 @@
 import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.uimanager.annotations.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactPropGroup;
 
 /**
  * This class is responsible for holding view manager property setters and is used in a process of
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactProp.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/annotations/ReactProp.java
similarity index 95%
rename from ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactProp.java
rename to ReactAndroid/src/main/java/com/facebook/react/uimanager/annotations/ReactProp.java
index d387fa71b244..ada7fc7f6aeb 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactProp.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/annotations/ReactProp.java
@@ -1,6 +1,6 @@
 // Copyright 2004-present Facebook. All Rights Reserved.
 
-package com.facebook.react.uimanager;
+package com.facebook.react.uimanager.annotations;
 
 import javax.annotation.Nullable;
 
@@ -12,7 +12,8 @@
 
 /**
  * Use this annotation to annotate properties of native views that should be exposed to JS. This
- * annotation should only be used for setter methods of subclasses of {@link ViewManager}.
+ * annotation should only be used for setter methods of subclasses of
+ * {@link com.facebook.react.uimanager.ViewManager}.
  *
  * Each annotated method should return {@code void} and take exactly two arguments: first being
  * a view instance to be updated and second a value that should be set.
@@ -21,8 +22,8 @@
  *  - primitives (int, boolean, double, float)
  *  - {@link String}
  *  - {@link Boolean}
- *  - {@link ReadableArray}
- *  - {@link ReadableMap}
+ *  - {@link com.facebook.react.bridge.ReadableArray}
+ *  - {@link com.facebook.react.bridge.ReadableMap}
  *
  * When property gets removed from the corresponding component in React, annotated setter will be
  * called with {@code null} in case of non-primitive value type or with a default value in case when
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactPropGroup.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/annotations/ReactPropGroup.java
similarity index 93%
rename from ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactPropGroup.java
rename to ReactAndroid/src/main/java/com/facebook/react/uimanager/annotations/ReactPropGroup.java
index 9e2a17b6e6d0..fa9e0d9948ea 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactPropGroup.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/annotations/ReactPropGroup.java
@@ -1,6 +1,6 @@
 // Copyright 2004-present Facebook. All Rights Reserved.
 
-package com.facebook.react.uimanager;
+package com.facebook.react.uimanager.annotations;
 
 import javax.annotation.Nullable;
 
@@ -12,9 +12,10 @@
 
 /**
  * Use this annotation to annotate group of properties of native views that should be exposed to JS.
- * This annotation should only be used for setter methods of subclasses of {@link ViewManager}. It's
- * a batched version of {@link ReactProp} annotation (please see documentation of {@link ReactProp}
- * for more details about how this annotation can be used).
+ * This annotation should only be used for setter methods of subclasses of
+ * {@link com.facebook.react.uimanager.ViewManager}. It's a batched version of {@link ReactProp}
+ * annotation (please see documentation of {@link ReactProp} for more details about how this
+ * annotation can be used).
  *
  * This annotation is meant to be used for a group of similar properties. That's why it support only
  * a set of properties of the same type. A good example is supporting "border", where we have 7
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTShapeShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTShapeShadowNode.java
index 76a64f726d5f..b66066b41e49 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTShapeShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTShapeShadowNode.java
@@ -20,7 +20,7 @@
 import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.common.ReactConstants;
-import com.facebook.react.uimanager.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactProp;
 
 /**
  * Shadow node for virtual ARTShape view
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTTextShadowNode.java
index 80be1a729f57..d6e1583529cc 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTTextShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTTextShadowNode.java
@@ -18,7 +18,7 @@
 
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.bridge.ReadableMap;
-import com.facebook.react.uimanager.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactProp;
 
 /**
  * Shadow node for virtual ARTText view
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTVirtualNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTVirtualNode.java
index b894e984594e..5027c5cbdbdd 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTVirtualNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTVirtualNode.java
@@ -19,7 +19,7 @@
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.uimanager.CatalystStylesDiffMap;
 import com.facebook.react.uimanager.DisplayMetricsHolder;
-import com.facebook.react.uimanager.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.ReactShadowNode;
 
 /**
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/drawer/ReactDrawerLayoutManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/drawer/ReactDrawerLayoutManager.java
index 75ab360c3aad..37062918158e 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/drawer/ReactDrawerLayoutManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/drawer/ReactDrawerLayoutManager.java
@@ -22,7 +22,7 @@
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.common.MapBuilder;
 import com.facebook.react.uimanager.PixelUtil;
-import com.facebook.react.uimanager.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.ViewGroupManager;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
index 35cb706d3c00..812fd4118fc6 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
@@ -18,7 +18,7 @@
 import com.facebook.drawee.backends.pipeline.Fresco;
 import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
 import com.facebook.react.common.MapBuilder;
-import com.facebook.react.uimanager.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.SimpleViewManager;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.ViewProps;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java
index 28309d79b9b9..fffba6ab867d 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ProgressBarShadowNode.java
@@ -22,7 +22,7 @@
 import com.facebook.csslayout.CSSNode;
 import com.facebook.csslayout.MeasureOutput;
 import com.facebook.react.uimanager.LayoutShadowNode;
-import com.facebook.react.uimanager.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactProp;
 
 /**
  * Node responsible for holding the style of the ProgressBar, see under
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ReactProgressBarViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ReactProgressBarViewManager.java
index 01aa4a0b8c8a..7f5bae7b3700 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ReactProgressBarViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ReactProgressBarViewManager.java
@@ -13,7 +13,7 @@
 
 import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
 import com.facebook.react.uimanager.BaseViewManager;
-import com.facebook.react.uimanager.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.ViewProps;
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollViewManager.java
index 4b34019808ab..cafd71de8824 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollViewManager.java
@@ -10,7 +10,7 @@
 
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.common.MapBuilder;
-import com.facebook.react.uimanager.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.ViewGroupManager;
 import com.facebook.react.views.scroll.ReactScrollViewCommandHelper;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java
index 0d86a3346bf4..972a88acd0b6 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java
@@ -12,7 +12,7 @@
 import javax.annotation.Nullable;
 
 import com.facebook.react.bridge.ReadableArray;
-import com.facebook.react.uimanager.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.ViewGroupManager;
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java
index b45fac0af88f..6289ce22dc79 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java
@@ -15,7 +15,7 @@
 
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.common.MapBuilder;
-import com.facebook.react.uimanager.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.ViewGroupManager;
 import com.facebook.react.views.view.ReactClippingViewGroupHelper;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/SwipeRefreshLayoutManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/SwipeRefreshLayoutManager.java
index 1520dc1f987c..d6b3a36629e3 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/SwipeRefreshLayoutManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/SwipeRefreshLayoutManager.java
@@ -20,7 +20,7 @@
 
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.common.MapBuilder;
-import com.facebook.react.uimanager.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.ViewGroupManager;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java
index 60b71f0eb7ba..a47b262ccc1f 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java
@@ -19,8 +19,7 @@
 import com.facebook.csslayout.MeasureOutput;
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.uimanager.LayoutShadowNode;
-import com.facebook.react.uimanager.ReactProp;
-import com.facebook.react.uimanager.ReactShadowNode;
+import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.SimpleViewManager;
 import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.ThemedReactContext;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextInlineImageShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextInlineImageShadowNode.java
index dbe716020fd2..3a4eed131906 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextInlineImageShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextInlineImageShadowNode.java
@@ -19,7 +19,7 @@
 import com.facebook.common.util.UriUtil;
 import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
 import com.facebook.react.uimanager.LayoutShadowNode;
-import com.facebook.react.uimanager.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.ReactShadowNode;
 
 /**
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java
index 315052660662..693e52b4d0bb 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java
@@ -37,7 +37,7 @@
 import com.facebook.react.uimanager.IllegalViewOperationException;
 import com.facebook.react.uimanager.LayoutShadowNode;
 import com.facebook.react.uimanager.PixelUtil;
-import com.facebook.react.uimanager.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.ReactShadowNode;
 import com.facebook.react.uimanager.UIViewOperationQueue;
 import com.facebook.react.uimanager.ViewDefaults;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewManager.java
index 68a1a7ea8cd1..2bffd39695fa 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewManager.java
@@ -19,7 +19,7 @@
 import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
 import com.facebook.react.uimanager.BaseViewManager;
 import com.facebook.react.uimanager.PixelUtil;
-import com.facebook.react.uimanager.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.ViewDefaults;
 import com.facebook.react.uimanager.ViewProps;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
index 6e4a3f449701..65a32d5855e8 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
@@ -34,7 +34,7 @@
 import com.facebook.react.common.MapBuilder;
 import com.facebook.react.uimanager.BaseViewManager;
 import com.facebook.react.uimanager.PixelUtil;
-import com.facebook.react.uimanager.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.ViewDefaults;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java
index 6cc920b14e2b..6172770dd3e2 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java
@@ -23,7 +23,7 @@
 import com.facebook.infer.annotation.Assertions;
 import com.facebook.react.common.annotations.VisibleForTesting;
 import com.facebook.react.uimanager.PixelUtil;
-import com.facebook.react.uimanager.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.UIViewOperationQueue;
 import com.facebook.react.uimanager.ViewDefaults;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java
index 0a157d099931..321d872c82eb 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java
@@ -27,7 +27,7 @@
 import com.facebook.react.bridge.ReadableMap;
 import com.facebook.react.common.MapBuilder;
 import com.facebook.react.uimanager.PixelUtil;
-import com.facebook.react.uimanager.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.ViewGroupManager;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
index 9b74294ad216..1c271fb31037 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
@@ -14,7 +14,6 @@
 import java.util.Locale;
 import java.util.Map;
 
-import android.graphics.Color;
 import android.os.Build;
 import android.view.View;
 
@@ -25,11 +24,10 @@
 import com.facebook.react.bridge.ReadableMap;
 import com.facebook.react.common.MapBuilder;
 import com.facebook.react.common.annotations.VisibleForTesting;
-import com.facebook.react.uimanager.CatalystStylesDiffMap;
 import com.facebook.react.uimanager.PixelUtil;
 import com.facebook.react.uimanager.PointerEvents;
-import com.facebook.react.uimanager.ReactProp;
-import com.facebook.react.uimanager.ReactPropGroup;
+import com.facebook.react.uimanager.annotations.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactPropGroup;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.ViewGroupManager;
 import com.facebook.react.uimanager.ViewProps;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
index f7577f5b3117..6d7a883bb82f 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
@@ -30,7 +30,7 @@
 import com.facebook.react.bridge.WritableMap;
 import com.facebook.react.common.MapBuilder;
 import com.facebook.react.common.build.ReactBuildConfig;
-import com.facebook.react.uimanager.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.SimpleViewManager;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.UIManagerModule;

From 57f6cbb3dc12d2dcc3eedd9712c36bb3d39149a5 Mon Sep 17 00:00:00 2001
From: Alexander Blom <blom@fb.com>
Date: Thu, 7 Jan 2016 03:51:28 -0800
Subject: [PATCH 0653/1411] Add annotation processor for @ReactProp

Summary:
The annotation processor finds subclasses of ViewManager and ShadowNode and generates classes that can both provide a mapping of property names to their type as well as a way of setting these properties.

This avoids having to do reflection to find the properties.

The annotation processor is currently not working when building with Gradle.

public

Reviewed By: astreet

Differential Revision: D2748958

fb-gh-sync-id: ded5b072d236ebf19fb43eaf704fc7f221a82c26
---
 ReactAndroid/build.gradle                     |   3 +
 .../processing/ReactPropertyProcessor.java    | 691 ++++++++++++++++++
 .../react/uimanager/ReactShadowNode.java      |  17 +-
 .../facebook/react/uimanager/ViewManager.java |  18 +-
 .../uimanager/ViewManagerPropertyUpdater.java | 163 +++++
 .../annotations/ReactPropertyHolder.java      |  15 +
 .../views/switchview/ReactSwitchManager.java  |   2 +-
 .../react/views/view/ReactViewManager.java    |   8 -
 8 files changed, 880 insertions(+), 37 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/processing/ReactPropertyProcessor.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerPropertyUpdater.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/annotations/ReactPropertyHolder.java

diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle
index a20c71937953..9721ee4dd6d4 100644
--- a/ReactAndroid/build.gradle
+++ b/ReactAndroid/build.gradle
@@ -227,6 +227,9 @@ android {
         jni.srcDirs = []
         jniLibs.srcDir "$buildDir/react-ndk/exported"
         res.srcDirs = ['src/main/res/devsupport', 'src/main/res/shell']
+        java {
+          exclude 'com/facebook/react/processing'
+        }
     }
 
     tasks.withType(JavaCompile) {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/processing/ReactPropertyProcessor.java b/ReactAndroid/src/main/java/com/facebook/react/processing/ReactPropertyProcessor.java
new file mode 100644
index 000000000000..bee08f38722d
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/processing/ReactPropertyProcessor.java
@@ -0,0 +1,691 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.processing;
+
+import javax.annotation.Nullable;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.Messager;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import com.facebook.infer.annotation.SuppressFieldNotInitialized;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.uimanager.annotations.ReactPropertyHolder;
+import com.facebook.react.uimanager.annotations.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactPropGroup;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeName;
+import com.squareup.javapoet.TypeSpec;
+import com.squareup.javapoet.TypeVariableName;
+
+import static javax.lang.model.element.Modifier.*;
+import static javax.tools.Diagnostic.Kind.ERROR;
+import static javax.tools.Diagnostic.Kind.WARNING;
+
+/**
+ * This annotation processor crawls subclasses of ReactShadowNode and ViewManager and finds their
+ * exported properties with the @ReactProp or @ReactGroupProp annotation. It generates a class
+ * per shadow node/view manager that is named {@code <classname>$$PropSetter}. This class contains methods
+ * to retrieve the name and type of all methods and a way to set these properties without
+ * reflection.
+ */
+@SupportedAnnotationTypes("com.facebook.react.uimanager.annotations.ReactPropertyHolder")
+@SupportedSourceVersion(SourceVersion.RELEASE_7)
+public class ReactPropertyProcessor extends AbstractProcessor {
+  private static final Map<TypeName, String> DEFAULT_TYPES;
+  private static final Set<TypeName> BOXED_PRIMITIVES;
+
+  private static final TypeName PROPS_TYPE =
+      ClassName.get("com.facebook.react.uimanager", "CatalystStylesDiffMap");
+  private static final TypeName STRING_TYPE = TypeName.get(String.class);
+  private static final TypeName READABLE_MAP_TYPE = TypeName.get(ReadableMap.class);
+  private static final TypeName READABLE_ARRAY_TYPE = TypeName.get(ReadableArray.class);
+
+  private static final TypeName VIEW_MANAGER_TYPE =
+      ClassName.get("com.facebook.react.uimanager", "ViewManager");
+  private static final TypeName SHADOW_NODE_TYPE =
+      ClassName.get("com.facebook.react.uimanager", "ReactShadowNode");
+
+  private static final ClassName VIEW_MANAGER_SETTER_TYPE =
+      ClassName.get(
+          "com.facebook.react.uimanager",
+          "ViewManagerPropertyUpdater",
+          "ViewManagerSetter");
+  private static final ClassName SHADOW_NODE_SETTER_TYPE =
+      ClassName.get(
+          "com.facebook.react.uimanager",
+          "ViewManagerPropertyUpdater",
+          "ShadowNodeSetter");
+
+  private static final TypeName PROPERTY_MAP_TYPE =
+      ParameterizedTypeName.get(Map.class, String.class, String.class);
+  private static final TypeName CONCRETE_PROPERTY_MAP_TYPE =
+      ParameterizedTypeName.get(HashMap.class, String.class, String.class);
+
+  private static final TypeName MAPPINGS_MAP_TYPE =
+      ParameterizedTypeName.get(Map.class, String.class, Integer.class);
+  private static final TypeName CONCRETE_MAPPINGS_MAP_TYPE =
+      ParameterizedTypeName.get(HashMap.class, String.class, Integer.class);
+
+  private final Map<ClassName, ClassInfo> mClasses;
+
+  @SuppressFieldNotInitialized
+  private Filer mFiler;
+  @SuppressFieldNotInitialized
+  private Messager mMessager;
+  @SuppressFieldNotInitialized
+  private Elements mElements;
+  @SuppressFieldNotInitialized
+  private Types mTypes;
+
+  static {
+    DEFAULT_TYPES = new HashMap<>();
+
+    // Primitives
+    DEFAULT_TYPES.put(TypeName.BOOLEAN, "boolean");
+    DEFAULT_TYPES.put(TypeName.DOUBLE, "number");
+    DEFAULT_TYPES.put(TypeName.FLOAT, "number");
+    DEFAULT_TYPES.put(TypeName.INT, "number");
+
+    // Boxed primitives
+    DEFAULT_TYPES.put(TypeName.BOOLEAN.box(), "boolean");
+    DEFAULT_TYPES.put(TypeName.INT.box(), "number");
+
+    // Class types
+    DEFAULT_TYPES.put(STRING_TYPE, "String");
+    DEFAULT_TYPES.put(READABLE_ARRAY_TYPE, "Array");
+    DEFAULT_TYPES.put(READABLE_MAP_TYPE, "Map");
+
+    BOXED_PRIMITIVES = new HashSet<>();
+    BOXED_PRIMITIVES.add(TypeName.BOOLEAN.box());
+    BOXED_PRIMITIVES.add(TypeName.FLOAT.box());
+    BOXED_PRIMITIVES.add(TypeName.INT.box());
+  }
+
+  public ReactPropertyProcessor() {
+    mClasses = new HashMap<>();
+  }
+
+  @Override
+  public synchronized void init(ProcessingEnvironment processingEnv) {
+    super.init(processingEnv);
+
+    mFiler = processingEnv.getFiler();
+    mMessager = processingEnv.getMessager();
+    mElements = processingEnv.getElementUtils();
+    mTypes = processingEnv.getTypeUtils();
+  }
+
+  @Override
+  public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+    // Clear properties from previous rounds
+    mClasses.clear();
+
+    Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(ReactPropertyHolder.class);
+    for (Element element : elements) {
+      try {
+        TypeElement classType = (TypeElement) element;
+        ClassName className = ClassName.get(classType);
+        mClasses.put(className, parseClass(className, classType));
+      } catch (Exception e) {
+        error(element, e.getMessage());
+      }
+    }
+
+    for (ClassInfo classInfo : mClasses.values()) {
+      try {
+        if (!shouldIgnoreClass(classInfo)) {
+          generateCode(classInfo, classInfo.mProperties);
+        } else if (shouldWarnClass(classInfo)) {
+          warning(classInfo.mElement, "Class was skipped. Classes need to be non-private.");
+        }
+      } catch (IOException e) {
+        error(e.getMessage());
+      } catch (ReactPropertyException e) {
+        error(e.element, e.getMessage());
+      } catch (Exception e) {
+        error(classInfo.mElement, e.getMessage());
+      }
+    }
+
+    return true;
+  }
+
+  private ClassInfo parseClass(ClassName className, TypeElement typeElement) {
+    TypeName targetType = getTargetType(typeElement.asType());
+    TypeName viewType = targetType.equals(SHADOW_NODE_TYPE) ? null : targetType;
+
+    ClassInfo classInfo = new ClassInfo(className, typeElement, viewType);
+
+    PropertyInfo.Builder propertyBuilder = new PropertyInfo.Builder(mTypes, mElements, classInfo);
+    for (Element element : mElements.getAllMembers(typeElement)) {
+      ReactProp prop = element.getAnnotation(ReactProp.class);
+      ReactPropGroup propGroup = element.getAnnotation(ReactPropGroup.class);
+
+      try {
+        if (prop != null || propGroup != null) {
+          checkElement(element);
+        }
+
+        if (prop != null) {
+          classInfo.addProperty(propertyBuilder.build(element, new RegularProperty(prop)));
+        } else if (propGroup != null) {
+          for (int i = 0, size = propGroup.names().length; i < size; i++) {
+            classInfo.addProperty(propertyBuilder.build(element, new GroupProperty(propGroup, i)));
+          }
+        }
+      } catch (ReactPropertyException e) {
+        error(e.element, e.getMessage());
+      }
+    }
+    return classInfo;
+  }
+
+  private TypeName getTargetType(TypeMirror mirror) {
+    TypeName typeName = TypeName.get(mirror);
+    if (typeName instanceof ParameterizedTypeName) {
+      ParameterizedTypeName parameterizedTypeName = (ParameterizedTypeName) typeName;
+      if (parameterizedTypeName.rawType.equals(VIEW_MANAGER_TYPE)) {
+        return parameterizedTypeName.typeArguments.get(0);
+      }
+    } else if (typeName.equals(SHADOW_NODE_TYPE)) {
+      return SHADOW_NODE_TYPE;
+    } else if (typeName.equals(TypeName.OBJECT)) {
+      throw new IllegalArgumentException("Could not find target type");
+    }
+
+    List<? extends TypeMirror> types = mTypes.directSupertypes(mirror);
+    return getTargetType(types.get(0));
+  }
+
+  private void generateCode(ClassInfo classInfo, List<PropertyInfo> properties)
+      throws IOException, ReactPropertyException {
+    MethodSpec getMethods = MethodSpec.methodBuilder("getProperties")
+        .addModifiers(PUBLIC)
+        .addAnnotation(Override.class)
+        .returns(PROPERTY_MAP_TYPE)
+        .addCode(generateGetProperties(properties))
+        .build();
+
+    TypeName superType = getSuperType(classInfo);
+    ClassName className = classInfo.mClassName;
+
+    String holderClassName =
+        getClassName((TypeElement) classInfo.mElement, className.packageName()) + "$$PropsSetter";
+    TypeSpec holderClass = TypeSpec.classBuilder(holderClassName)
+        .addSuperinterface(superType)
+        .addModifiers(PUBLIC)
+        .addField(MAPPINGS_MAP_TYPE, "mappings", PRIVATE, STATIC, FINAL)
+        .addStaticBlock(generatePropertyMappings(properties))
+        .addMethod(generateSetPropertySpec(classInfo, properties))
+        .addMethod(getMethods)
+        .build();
+
+    JavaFile javaFile = JavaFile.builder(className.packageName(), holderClass)
+        .addFileComment("Generated by " + getClass().getName())
+        .build();
+
+    javaFile.writeTo(mFiler);
+  }
+
+  private String getClassName(TypeElement type, String packageName) {
+    int packageLen = packageName.length() + 1;
+    return type.getQualifiedName().toString().substring(packageLen).replace('.', '$');
+  }
+
+  private static TypeName getSuperType(ClassInfo classInfo) {
+    switch (classInfo.getType()) {
+      case VIEW_MANAGER:
+        return ParameterizedTypeName.get(
+            VIEW_MANAGER_SETTER_TYPE,
+            classInfo.mClassName,
+            classInfo.mViewType);
+      case SHADOW_NODE:
+        return ParameterizedTypeName.get(SHADOW_NODE_SETTER_TYPE, classInfo.mClassName);
+      default:
+        throw new IllegalArgumentException();
+    }
+  }
+
+  private static CodeBlock generatePropertyMappings(List<PropertyInfo> properties) {
+    if (properties.isEmpty()) {
+      return CodeBlock.builder()
+          .addStatement("mappings = $T.emptyMap()", Collections.class)
+          .build();
+    }
+
+    CodeBlock.Builder builder = CodeBlock.builder()
+        .addStatement("mappings = new $T($L)", CONCRETE_MAPPINGS_MAP_TYPE, properties.size());
+
+    for (int i = 0, size = properties.size(); i < size; i++) {
+      PropertyInfo propertyInfo = properties.get(i);
+      builder.addStatement("mappings.put($S, $L)", propertyInfo.mProperty.name(), i);
+    }
+
+    return builder.build();
+  }
+
+  private static MethodSpec generateSetPropertySpec(
+      ClassInfo classInfo,
+      List<PropertyInfo> properties) {
+    MethodSpec.Builder builder = MethodSpec.methodBuilder("setProperty")
+        .addModifiers(PUBLIC)
+        .addAnnotation(Override.class)
+        .returns(TypeName.VOID);
+
+    switch (classInfo.getType()) {
+      case VIEW_MANAGER:
+        builder
+            .addParameter(classInfo.mClassName, "manager")
+            .addParameter(classInfo.mViewType, "view");
+        break;
+      case SHADOW_NODE:
+        builder
+            .addParameter(classInfo.mClassName, "node");
+        break;
+    }
+
+    return builder
+        .addParameter(STRING_TYPE, "name")
+        .addParameter(PROPS_TYPE, "props")
+        .addCode(generateSetProperty(classInfo, properties))
+        .build();
+  }
+
+  private static CodeBlock generateSetProperty(ClassInfo info, List<PropertyInfo> properties) {
+    if (properties.isEmpty()) {
+      return CodeBlock.builder().build();
+    }
+
+    CodeBlock.Builder builder = CodeBlock.builder()
+        .addStatement("Integer id = mappings.get(name)")
+        .addStatement("if (id == null) return");
+
+    builder.add("switch (id) {\n").indent();
+    for (int i = 0, size = properties.size(); i < size; i++) {
+      PropertyInfo propertyInfo = properties.get(i);
+      builder
+          .add("case $L:\n", i)
+          .indent();
+
+      switch (info.getType()) {
+        case VIEW_MANAGER:
+          builder.add("manager.$L(view, ", propertyInfo.methodName);
+          break;
+        case SHADOW_NODE:
+          builder.add("node.$L(", propertyInfo.methodName);
+          break;
+      }
+      if (propertyInfo.mProperty instanceof GroupProperty) {
+        builder.add("$L, ", ((GroupProperty) propertyInfo.mProperty).mGroupIndex);
+      }
+      if (BOXED_PRIMITIVES.contains(propertyInfo.propertyType)) {
+        builder.add("props.isNull(name) ? null : ");
+      }
+      getPropertyExtractor(propertyInfo, builder);
+      builder.addStatement(")");
+
+      builder
+          .addStatement("break")
+          .unindent();
+    }
+    builder.unindent().add("}\n");
+
+    return builder.build();
+  }
+
+  private static CodeBlock.Builder getPropertyExtractor(
+      PropertyInfo info,
+      CodeBlock.Builder builder) {
+    TypeName propertyType = info.propertyType;
+    if (propertyType.equals(STRING_TYPE)) {
+      return builder.add("props.getString(name)");
+    } else if (propertyType.equals(READABLE_ARRAY_TYPE)) {
+      return builder.add("props.getArray(name)");
+    } else if (propertyType.equals(READABLE_MAP_TYPE)) {
+      return builder.add("props.getMap(name)");
+    }
+
+    if (BOXED_PRIMITIVES.contains(propertyType)) {
+      propertyType = propertyType.unbox();
+    }
+
+    if (propertyType.equals(TypeName.BOOLEAN)) {
+      return builder.add("props.getBoolean(name, $L)", info.mProperty.defaultBoolean());
+    } if (propertyType.equals(TypeName.DOUBLE)) {
+      double defaultDouble = info.mProperty.defaultDouble();
+      if (Double.isNaN(defaultDouble)) {
+        return builder.add("props.getDouble(name, $T.NaN)", Double.class);
+      } else {
+        return builder.add("props.getDouble(name, $Lf)", defaultDouble);
+      }
+    }
+    if (propertyType.equals(TypeName.FLOAT)) {
+      float defaultFloat = info.mProperty.defaultFloat();
+      if (Float.isNaN(defaultFloat)) {
+        return builder.add("props.getFloat(name, $T.NaN)", Float.class);
+      } else {
+        return builder.add("props.getFloat(name, $Lf)", defaultFloat);
+      }
+    }
+    if (propertyType.equals(TypeName.INT)) {
+      return builder.add("props.getInt(name, $L)", info.mProperty.defaultInt());
+    }
+
+    throw new IllegalArgumentException();
+  }
+
+  private static CodeBlock generateGetProperties(List<PropertyInfo> properties)
+      throws ReactPropertyException {
+    if (properties.isEmpty()) {
+      return CodeBlock.builder()
+          .addStatement("return $T.emptyMap()", Collections.class)
+          .build();
+    }
+
+    CodeBlock.Builder builder = CodeBlock.builder()
+        .addStatement(
+            "$T props = new $T($L)",
+            PROPERTY_MAP_TYPE,
+            CONCRETE_PROPERTY_MAP_TYPE,
+            properties.size());
+
+    for (PropertyInfo propertyInfo : properties) {
+      try {
+        String typeName = getPropertypTypeName(propertyInfo.mProperty, propertyInfo.propertyType);
+        builder.addStatement("props.put($S, $S)", propertyInfo.mProperty.name(), typeName);
+      } catch (IllegalArgumentException e) {
+        throw new ReactPropertyException(e.getMessage(), propertyInfo);
+      }
+    }
+
+    return builder
+        .addStatement("return props")
+        .build();
+  }
+
+  private static String getPropertypTypeName(Property property, TypeName propertyType) {
+    String defaultType = DEFAULT_TYPES.get(propertyType);
+    String useDefaultType = property instanceof RegularProperty ?
+        ReactProp.USE_DEFAULT_TYPE : ReactPropGroup.USE_DEFAULT_TYPE;
+    return useDefaultType.equals(property.customType()) ? defaultType : property.customType();
+  }
+
+  private static void checkElement(Element element) throws ReactPropertyException {
+    if (element.getKind() == ElementKind.METHOD
+        && element.getModifiers().contains(PUBLIC)) {
+      return;
+    }
+
+    throw new ReactPropertyException(
+        "@ReactProp and @ReachPropGroup annotation must be on a public method",
+        element);
+  }
+
+  private static boolean shouldIgnoreClass(ClassInfo classInfo) {
+    return classInfo.mElement.getModifiers().contains(PRIVATE)
+        || classInfo.mElement.getModifiers().contains(ABSTRACT)
+        || classInfo.mViewType instanceof TypeVariableName;
+  }
+
+  private static boolean shouldWarnClass(ClassInfo classInfo) {
+    return classInfo.mElement.getModifiers().contains(PRIVATE);
+  }
+
+  private void error(Element element, String message) {
+    mMessager.printMessage(ERROR, message, element);
+  }
+
+  private void error(String message) {
+    mMessager.printMessage(ERROR, message);
+  }
+
+  private void warning(Element element, String message) {
+    mMessager.printMessage(WARNING, message, element);
+  }
+
+  private interface Property {
+    String name();
+    String customType();
+    double defaultDouble();
+    float defaultFloat();
+    int defaultInt();
+    boolean defaultBoolean();
+  }
+
+  private static class RegularProperty implements Property {
+    private final ReactProp mProp;
+
+    public RegularProperty(ReactProp prop) {
+      mProp = prop;
+    }
+
+    @Override
+    public String name() {
+      return mProp.name();
+    }
+
+    @Override
+    public String customType() {
+      return mProp.customType();
+    }
+
+    @Override
+    public double defaultDouble() {
+      return mProp.defaultDouble();
+    }
+
+    @Override
+    public float defaultFloat() {
+      return mProp.defaultFloat();
+    }
+
+    @Override
+    public int defaultInt() {
+      return mProp.defaultInt();
+    }
+
+    @Override
+    public boolean defaultBoolean() {
+      return mProp.defaultBoolean();
+    }
+  }
+
+  private static class GroupProperty implements Property {
+    private final ReactPropGroup mProp;
+    private final int mGroupIndex;
+
+    public GroupProperty(ReactPropGroup prop, int groupIndex) {
+      mProp = prop;
+      mGroupIndex = groupIndex;
+    }
+
+    @Override
+    public String name() {
+      return mProp.names()[mGroupIndex];
+    }
+
+    @Override
+    public String customType() {
+      return mProp.customType();
+    }
+
+    @Override
+    public double defaultDouble() {
+      return mProp.defaultDouble();
+    }
+
+    @Override
+    public float defaultFloat() {
+      return mProp.defaultFloat();
+    }
+
+    @Override
+    public int defaultInt() {
+      return mProp.defaultInt();
+    }
+
+    @Override
+    public boolean defaultBoolean() {
+      throw new UnsupportedOperationException();
+    }
+  }
+
+  private enum SettableType {
+    VIEW_MANAGER,
+    SHADOW_NODE
+  }
+
+  private static class ClassInfo {
+    public final ClassName mClassName;
+    public final Element mElement;
+    public final @Nullable TypeName mViewType;
+    public final List<PropertyInfo> mProperties;
+
+    public ClassInfo(ClassName className, TypeElement element, @Nullable TypeName viewType) {
+      mClassName = className;
+      mElement = element;
+      mViewType = viewType;
+      mProperties = new ArrayList<>();
+    }
+
+    public SettableType getType() {
+      return mViewType == null ? SettableType.SHADOW_NODE : SettableType.VIEW_MANAGER;
+    }
+
+    public void addProperty(PropertyInfo propertyInfo) throws ReactPropertyException {
+      String name = propertyInfo.mProperty.name();
+      if (checkPropertyExists(name)) {
+        throw new ReactPropertyException(
+            "Module " + mClassName + " has already registered a property named \"" +
+                name + '"', propertyInfo);
+      }
+
+      mProperties.add(propertyInfo);
+    }
+
+    private boolean checkPropertyExists(String name) {
+      for (PropertyInfo propertyInfo : mProperties) {
+        if (propertyInfo.mProperty.name().equals(name)) {
+          return true;
+        }
+      }
+
+      return false;
+    }
+  }
+
+  private static class PropertyInfo {
+    public final String methodName;
+    public final TypeName propertyType;
+    public final Element element;
+    public final Property mProperty;
+
+    private PropertyInfo(
+        String methodName,
+        TypeName propertyType,
+        Element element,
+        Property property) {
+      this.methodName = methodName;
+      this.propertyType = propertyType;
+      this.element = element;
+      mProperty = property;
+    }
+
+    public static class Builder {
+      private final Types mTypes;
+      private final Elements mElements;
+      private final ClassInfo mClassInfo;
+
+      public Builder(Types types, Elements elements, ClassInfo classInfo) {
+        mTypes = types;
+        mElements = elements;
+        mClassInfo = classInfo;
+      }
+
+      public PropertyInfo build(Element element, Property property)
+          throws ReactPropertyException {
+        String methodName = element.getSimpleName().toString();
+
+        ExecutableElement method = (ExecutableElement) element;
+        List<? extends VariableElement> parameters = method.getParameters();
+
+        if (parameters.size() != getArgCount(mClassInfo.getType(), property)) {
+          throw new ReactPropertyException("Wrong number of args", element);
+        }
+
+        int index = 0;
+        if (mClassInfo.getType() == SettableType.VIEW_MANAGER) {
+          TypeMirror mirror = parameters.get(index++).asType();
+          if (!mTypes.isSubtype(mirror, mElements.getTypeElement("android.view.View").asType())) {
+            throw new ReactPropertyException("First argument must be a subclass of View", element);
+          }
+        }
+
+        if (property instanceof GroupProperty) {
+          TypeName indexType = TypeName.get(parameters.get(index++).asType());
+          if (!indexType.equals(TypeName.INT)) {
+            throw new ReactPropertyException(
+                "Argument " + index + " must be an int for @ReactPropGroup",
+                element);
+          }
+        }
+
+        TypeName propertyType = TypeName.get(parameters.get(index++).asType());
+        if (!DEFAULT_TYPES.containsKey(propertyType)) {
+          throw new ReactPropertyException(
+              "Argument " + index + " must be of a supported type",
+              element);
+        }
+
+        return new PropertyInfo(methodName, propertyType, element, property);
+      }
+
+      private static int getArgCount(SettableType type, Property property) {
+        int baseCount = type == SettableType.SHADOW_NODE ? 1 : 2;
+        return property instanceof GroupProperty ? baseCount + 1 : baseCount;
+      }
+    }
+  }
+
+  private static class ReactPropertyException extends Exception {
+    public final Element element;
+
+    public ReactPropertyException(String message, PropertyInfo propertyInfo) {
+      super(message);
+      this.element = propertyInfo.element;
+    }
+
+    public ReactPropertyException(String message, Element element) {
+      super(message);
+      this.element = element;
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java
index 21a88835d7a1..de9ca3cf65a3 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java
@@ -12,12 +12,10 @@
 import javax.annotation.Nullable;
 
 import java.util.ArrayList;
-import java.util.Map;
 
 import com.facebook.csslayout.CSSNode;
 import com.facebook.infer.annotation.Assertions;
-import com.facebook.react.bridge.ReadableMap;
-import com.facebook.react.bridge.ReadableMapKeySetIterator;
+import com.facebook.react.uimanager.annotations.ReactPropertyHolder;
 
 /**
  * Base node class for representing virtual tree of React nodes. Shadow nodes are used primarily
@@ -42,6 +40,7 @@
  * children (e.g. {@link #getNativeChildCount()}). See {@link NativeViewHierarchyOptimizer} for more
  * information.
  */
+@ReactPropertyHolder
 public class ReactShadowNode extends CSSNode {
 
   private int mReactTag;
@@ -170,17 +169,7 @@ public void onBeforeLayout() {
   }
 
   public final void updateProperties(CatalystStylesDiffMap props) {
-    Map<String, ViewManagersPropertyCache.PropSetter> propSetters =
-        ViewManagersPropertyCache.getNativePropSettersForShadowNodeClass(getClass());
-    ReadableMap propMap = props.mBackingMap;
-    ReadableMapKeySetIterator iterator = propMap.keySetIterator();
-    while (iterator.hasNextKey()) {
-      String key = iterator.nextKey();
-      ViewManagersPropertyCache.PropSetter setter = propSetters.get(key);
-      if (setter != null) {
-        setter.updateShadowNodeProp(this, props);
-      }
-    }
+    ViewManagerPropertyUpdater.updateProps(this, props);
     onAfterUpdateTransaction();
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java
index ab14daa10d24..ca9fd66d3fe0 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java
@@ -16,32 +16,22 @@
 import android.view.View;
 
 import com.facebook.react.bridge.ReadableArray;
-import com.facebook.react.bridge.ReadableMap;
-import com.facebook.react.bridge.ReadableMapKeySetIterator;
 import com.facebook.react.touch.CatalystInterceptingViewGroup;
 import com.facebook.react.touch.JSResponderHandler;
 import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.annotations.ReactPropGroup;
+import com.facebook.react.uimanager.annotations.ReactPropertyHolder;
 
 /**
  * Class responsible for knowing how to create and update catalyst Views of a given type. It is also
  * responsible for creating and updating CSSNode subclasses used for calculating position and size
  * for the corresponding native view.
  */
+@ReactPropertyHolder
 public abstract class ViewManager<T extends View, C extends ReactShadowNode> {
 
   public final void updateProperties(T viewToUpdate, CatalystStylesDiffMap props) {
-    Map<String, ViewManagersPropertyCache.PropSetter> propSetters =
-        ViewManagersPropertyCache.getNativePropSettersForViewManagerClass(getClass());
-    ReadableMap propMap = props.mBackingMap;
-    ReadableMapKeySetIterator iterator = propMap.keySetIterator();
-    while (iterator.hasNextKey()) {
-      String key = iterator.nextKey();
-      ViewManagersPropertyCache.PropSetter setter = propSetters.get(key);
-      if (setter != null) {
-        setter.updateViewProp(this, viewToUpdate, props);
-      }
-    }
+    ViewManagerPropertyUpdater.updateProps(this, viewToUpdate, props);
     onAfterUpdateTransaction(viewToUpdate);
   }
 
@@ -206,6 +196,6 @@ public void receiveCommand(T root, int commandId, @Nullable ReadableArray args)
   }
 
   public Map<String, String> getNativeProps() {
-    return ViewManagersPropertyCache.getNativePropsForView(getClass(), getShadowNodeClass());
+    return ViewManagerPropertyUpdater.getNativeProps(getClass(), getShadowNodeClass());
   }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerPropertyUpdater.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerPropertyUpdater.java
new file mode 100644
index 000000000000..9c8bdc5e5d3a
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerPropertyUpdater.java
@@ -0,0 +1,163 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import android.view.View;
+
+import com.facebook.common.logging.FLog;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.ReadableMapKeySetIterator;
+
+public class ViewManagerPropertyUpdater {
+  public interface Settable {
+    Map<String, String> getProperties();
+  }
+
+  public interface ViewManagerSetter<T extends ViewManager, V extends View> extends Settable {
+    void setProperty(T manager, V view, String name, CatalystStylesDiffMap props);
+  }
+
+  public interface ShadowNodeSetter<T extends ReactShadowNode> extends Settable {
+    void setProperty(T node, String name, CatalystStylesDiffMap props);
+  }
+
+  private static final String TAG = "ViewManagerPropertyUpdater";
+
+  private static final Map<Class<?>, ViewManagerSetter<?, ?>> VIEW_MANAGER_SETTER_MAP =
+      new HashMap<>();
+  private static final Map<Class<?>, ShadowNodeSetter<?>> SHADOW_NODE_SETTER_MAP = new HashMap<>();
+
+  public static <T extends ViewManager, V extends View> void updateProps(
+      T manager,
+      V v,
+      CatalystStylesDiffMap props) {
+    ViewManagerSetter<T, V> setter = findManagerSetter(manager.getClass());
+    ReadableMap propMap = props.mBackingMap;
+    ReadableMapKeySetIterator iterator = propMap.keySetIterator();
+    while (iterator.hasNextKey()) {
+      String key = iterator.nextKey();
+      setter.setProperty(manager, v, key, props);
+    }
+  }
+
+  public static <T extends ReactShadowNode> void updateProps(T node, CatalystStylesDiffMap props) {
+    ShadowNodeSetter<T> setter = findNodeSetter(node.getClass());
+    ReadableMap propMap = props.mBackingMap;
+    ReadableMapKeySetIterator iterator = propMap.keySetIterator();
+    while (iterator.hasNextKey()) {
+      String key = iterator.nextKey();
+      setter.setProperty(node, key, props);
+    }
+  }
+
+  public static Map<String, String> getNativeProps(
+      Class<? extends ViewManager> viewManagerTopClass,
+      Class<? extends ReactShadowNode> shadowNodeTopClass) {
+    Map<String, String> props = new HashMap<>();
+    props.putAll(findManagerSetter(viewManagerTopClass).getProperties());
+    props.putAll(findNodeSetter(shadowNodeTopClass).getProperties());
+    return props;
+  }
+
+  private static <T extends ViewManager, V extends View> ViewManagerSetter<T, V> findManagerSetter(
+      Class<? extends ViewManager> managerClass) {
+    @SuppressWarnings("unchecked")
+    ViewManagerSetter<T, V> setter =
+        (ViewManagerSetter<T, V>) VIEW_MANAGER_SETTER_MAP.get(managerClass);
+    if (setter == null) {
+      setter = findGeneratedSetter(managerClass);
+      if (setter == null) {
+        setter = new FallbackViewManagerSetter<>(managerClass);
+      }
+      VIEW_MANAGER_SETTER_MAP.put(managerClass, setter);
+    }
+
+    return setter;
+  }
+
+  private static <T extends ReactShadowNode> ShadowNodeSetter<T> findNodeSetter(
+      Class<? extends ReactShadowNode> nodeClass) {
+    @SuppressWarnings("unchecked")
+    ShadowNodeSetter<T> setter = (ShadowNodeSetter<T>) SHADOW_NODE_SETTER_MAP.get(nodeClass);
+    if (setter == null) {
+      setter = findGeneratedSetter(nodeClass);
+      if (setter == null) {
+        setter = new FallbackShadowNodeSetter<>(nodeClass);
+      }
+      SHADOW_NODE_SETTER_MAP.put(nodeClass, setter);
+    }
+
+    return setter;
+  }
+
+  private static <T> T findGeneratedSetter(Class<?> cls) {
+    String clsName = cls.getName();
+    try {
+      Class<?> setterClass = Class.forName(clsName + "$$PropsSetter");
+      //noinspection unchecked
+      return (T) setterClass.newInstance();
+    } catch (ClassNotFoundException e) {
+      FLog.w(TAG, "Could not find generated setter for " + cls);
+      return null;
+    } catch (InstantiationException | IllegalAccessException e) {
+      throw new RuntimeException("Unable to instantiate methods getter for " + clsName, e);
+    }
+  }
+
+  private static class FallbackViewManagerSetter<T extends ViewManager, V extends View>
+      implements ViewManagerSetter<T, V> {
+    private final Map<String, ViewManagersPropertyCache.PropSetter> mPropSetters;
+
+    private FallbackViewManagerSetter(Class<? extends ViewManager> viewManagerClass) {
+      mPropSetters =
+          ViewManagersPropertyCache.getNativePropSettersForViewManagerClass(viewManagerClass);
+    }
+
+    @Override
+    public void setProperty(T manager, V v, String name, CatalystStylesDiffMap props) {
+      ViewManagersPropertyCache.PropSetter setter = mPropSetters.get(name);
+      if (setter != null) {
+        setter.updateViewProp(manager, v, props);
+      }
+    }
+
+    @Override
+    public Map<String, String> getProperties() {
+      Map<String, String> nativeProps = new HashMap<>();
+      for (ViewManagersPropertyCache.PropSetter setter : mPropSetters.values()) {
+        nativeProps.put(setter.getPropName(), setter.getPropType());
+      }
+      return nativeProps;
+    }
+  }
+
+  private static class FallbackShadowNodeSetter<T extends ReactShadowNode>
+      implements ShadowNodeSetter<T> {
+    private final Map<String, ViewManagersPropertyCache.PropSetter> mPropSetters;
+
+    private FallbackShadowNodeSetter(Class<? extends ReactShadowNode> shadowNodeClass) {
+      mPropSetters =
+          ViewManagersPropertyCache.getNativePropSettersForShadowNodeClass(shadowNodeClass);
+    }
+
+    @Override
+    public void setProperty(ReactShadowNode node, String name, CatalystStylesDiffMap props) {
+      ViewManagersPropertyCache.PropSetter setter = mPropSetters.get(name);
+      if (setter != null) {
+        setter.updateShadowNodeProp(node, props);
+      }
+    }
+
+    @Override
+    public Map<String, String> getProperties() {
+      Map<String, String> nativeProps = new HashMap<>();
+      for (ViewManagersPropertyCache.PropSetter setter : mPropSetters.values()) {
+        nativeProps.put(setter.getPropName(), setter.getPropType());
+      }
+      return nativeProps;
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/annotations/ReactPropertyHolder.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/annotations/ReactPropertyHolder.java
new file mode 100644
index 000000000000..f676e7e0c69c
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/annotations/ReactPropertyHolder.java
@@ -0,0 +1,15 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.uimanager.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Inherited
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.TYPE)
+public @interface ReactPropertyHolder {
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java
index a47b262ccc1f..14d9fc0d6766 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java
@@ -32,7 +32,7 @@ public class ReactSwitchManager extends SimpleViewManager<ReactSwitch> {
 
   private static final String REACT_CLASS = "AndroidSwitch";
 
-  private static class ReactSwitchShadowNode extends LayoutShadowNode implements
+  static class ReactSwitchShadowNode extends LayoutShadowNode implements
       CSSNode.MeasureFunction {
 
     private int mWidth;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
index 1c271fb31037..0f3973bd2bb0 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
@@ -84,14 +84,6 @@ public void setNativeBackground(ReactViewGroup view, @Nullable ReadableMap bg) {
             null : ReactDrawableHelper.createDrawableFromJSDescription(view.getContext(), bg));
   }
 
-  @ReactProp(name = ViewProps.BORDER_WIDTH, defaultFloat = CSSConstants.UNDEFINED)
-  public void setBorderWidth(ReactViewGroup view, float width) {
-    if (!CSSConstants.isUndefined(width)) {
-      width = PixelUtil.toPixelFromDIP(width);
-    }
-    view.setBorderWidth(Spacing.ALL, width);
-  }
-
   @ReactProp(name = ReactClippingViewGroupHelper.PROP_REMOVE_CLIPPED_SUBVIEWS)
   public void setRemoveClippedSubviews(ReactViewGroup view, boolean removeClippedSubviews) {
     view.setRemoveClippedSubviews(removeClippedSubviews);

From 571e646543a2c1d20518399f62de37d76fe1be28 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 7 Jan 2016 04:00:15 -0800
Subject: [PATCH 0654/1411] Improved null url handling

Summary:
public
Attempting to load an undefined URL via XMLHttpRequest produced a confusing error deep within the network layer. This diff improves the networking stack to catch such errors earlier, and also adds a helpful error in the JS layer.

Fixes https://github.com/facebook/react-native/issues/4558

Reviewed By: javache

Differential Revision: D2811080

fb-gh-sync-id: 1837427e1080a0308f2c4f9a8a42bce2e041fb48
---
 Libraries/Network/RCTNetworking.m       | 4 ++++
 Libraries/Network/XMLHttpRequestBase.js | 3 +++
 React/Base/RCTUtils.m                   | 6 +++++-
 3 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/Libraries/Network/RCTNetworking.m b/Libraries/Network/RCTNetworking.m
index 0c5aeaecd7fa..6bbea21b1f27 100644
--- a/Libraries/Network/RCTNetworking.m
+++ b/Libraries/Network/RCTNetworking.m
@@ -136,6 +136,10 @@ @implementation RCTNetworking
 
 - (id<RCTURLRequestHandler>)handlerForRequest:(NSURLRequest *)request
 {
+  if (!request.URL) {
+    return nil;
+  }
+
   if (!_handlers) {
 
     // get handlers
diff --git a/Libraries/Network/XMLHttpRequestBase.js b/Libraries/Network/XMLHttpRequestBase.js
index 6c7bb8b48631..4cdc424721fb 100644
--- a/Libraries/Network/XMLHttpRequestBase.js
+++ b/Libraries/Network/XMLHttpRequestBase.js
@@ -179,6 +179,9 @@ class XMLHttpRequestBase {
       // async is default
       throw new Error('Synchronous http requests are not supported');
     }
+    if (!url) {
+      throw new Error('Cannot load an empty url');
+    }
     this._reset();
     this._method = method;
     this._url = url;
diff --git a/React/Base/RCTUtils.m b/React/Base/RCTUtils.m
index 48e1fea08d26..e6ebdb8061b3 100644
--- a/React/Base/RCTUtils.m
+++ b/React/Base/RCTUtils.m
@@ -494,7 +494,11 @@ BOOL RCTIsGzippedData(NSData *data)
     // Not a bundle-relative file
     return nil;
   }
-  return [path substringFromIndex:bundlePath.length + 1];
+  path = [path substringFromIndex:bundlePath.length];
+  if ([path hasPrefix:@"/"]) {
+    path = [path substringFromIndex:1];
+  }
+  return path;
 }
 
 BOOL RCTIsXCAssetURL(NSURL *imageURL)

From 811079ede2dd32bca4b5891ea42c27dbdb488da0 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Thu, 7 Jan 2016 17:03:45 +0000
Subject: [PATCH 0655/1411] [global-cli] Bump version to 0.1.9

To release a new version with the fix for Windows:
https://github.com/facebook/react-native/pull/5171

Thanks a lot @tdzl2003!

Tweaked the platform check to use `process.platform`
as that's more common in the codebase. No strong preference,
just for consistency.
---
 react-native-cli/index.js     | 2 +-
 react-native-cli/package.json | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/react-native-cli/index.js b/react-native-cli/index.js
index 306191bccd95..83d0a6bc9d11 100755
--- a/react-native-cli/index.js
+++ b/react-native-cli/index.js
@@ -200,7 +200,7 @@ function run(root, projectName, logLevel) {
     spawnArgs = {stdio: 'inherit'};
   }
   var proc;
-  if (os.platform() === 'win32'){
+  if (/^win/.test(process.platform)) {
     args.unshift('npm');
     args.unshift('/c');
     proc = spawn('cmd', args, spawnArgs);
diff --git a/react-native-cli/package.json b/react-native-cli/package.json
index 7b76d4e79ac6..3195fc42686f 100644
--- a/react-native-cli/package.json
+++ b/react-native-cli/package.json
@@ -1,6 +1,6 @@
 {
   "name": "react-native-cli",
-  "version": "0.1.8",
+  "version": "0.1.9",
   "license" : "BSD-3-Clause",
   "description": "The React Native CLI tools",
   "main": "index.js",

From ac72611bb1c41765a59c8249cc4332110341deb1 Mon Sep 17 00:00:00 2001
From: pecheriere <pecheriere@example.com>
Date: Thu, 7 Jan 2016 05:01:11 -0800
Subject: [PATCH 0656/1411] Add soundName config for UILocalNotification

Summary:
Current version wasn't triggering any sound when a local notification was fired. I added the possibility to provide a custom sound and fallback to the default iOS sound if not provided.
Closes https://github.com/facebook/react-native/pull/4836

Reviewed By: svcscm

Differential Revision: D2807381

Pulled By: bestander

fb-gh-sync-id: c25e8f3c30a0714a5d9558c0c1fe344d0e93321e
---
 Libraries/PushNotificationIOS/PushNotificationIOS.js       | 2 ++
 Libraries/PushNotificationIOS/RCTPushNotificationManager.m | 1 +
 2 files changed, 3 insertions(+)

diff --git a/Libraries/PushNotificationIOS/PushNotificationIOS.js b/Libraries/PushNotificationIOS/PushNotificationIOS.js
index 45ade9478dc5..4432f7ea1892 100644
--- a/Libraries/PushNotificationIOS/PushNotificationIOS.js
+++ b/Libraries/PushNotificationIOS/PushNotificationIOS.js
@@ -74,6 +74,7 @@ class PushNotificationIOS {
    * details is an object containing:
    *
    * - `alertBody` : The message displayed in the notification alert.
+   * - `soundName` : The sound played when the notification is fired (optional).
    *
    */
   static presentLocalNotification(details: Object) {
@@ -87,6 +88,7 @@ class PushNotificationIOS {
    *
    * - `fireDate` : The date and time when the system should deliver the notification.
    * - `alertBody` : The message displayed in the notification alert.
+   * - `soundName` : The sound played when the notification is fired (optional).
    *
    */
   static scheduleLocalNotification(details: Object) {
diff --git a/Libraries/PushNotificationIOS/RCTPushNotificationManager.m b/Libraries/PushNotificationIOS/RCTPushNotificationManager.m
index 761a1377eb3b..33de7ba627ff 100644
--- a/Libraries/PushNotificationIOS/RCTPushNotificationManager.m
+++ b/Libraries/PushNotificationIOS/RCTPushNotificationManager.m
@@ -35,6 +35,7 @@ + (UILocalNotification *)UILocalNotification:(id)json
   UILocalNotification *notification = [UILocalNotification new];
   notification.fireDate = [RCTConvert NSDate:details[@"fireDate"]] ?: [NSDate date];
   notification.alertBody = [RCTConvert NSString:details[@"alertBody"]];
+  notification.soundName = [RCTConvert NSString:details[@"soundName"]] ?: UILocalNotificationDefaultSoundName;
   return notification;
 }
 

From 4f9086f0e79b3594bcf0d8291e50cb0e94e93017 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= <renaudeau.gaetan@gmail.com>
Date: Thu, 7 Jan 2016 05:24:32 -0800
Subject: [PATCH 0657/1411] Fixes error when navigationBar is set back to null

Summary:
This fixes a regression introduced in https://github.com/facebook/react-native/commit/df70005c12e3be14bfbdf0b32f9ea0a5c052deba

If you set navigationBar props (on Navigator) and then later set it back to null, it will crashes.
(N.B. this should be possible as navigationBar is optional)

cc satya164
Closes https://github.com/facebook/react-native/pull/4941

Reviewed By: svcscm

Differential Revision: D2788889

Pulled By: bestander

fb-gh-sync-id: f8f1cd6cc2ce13b1b1b86fa76d3b22c26a8adb5b
---
 Libraries/CustomComponents/Navigator/Navigator.js | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/Libraries/CustomComponents/Navigator/Navigator.js b/Libraries/CustomComponents/Navigator/Navigator.js
index 11d7f3984f45..607416244a68 100644
--- a/Libraries/CustomComponents/Navigator/Navigator.js
+++ b/Libraries/CustomComponents/Navigator/Navigator.js
@@ -1084,13 +1084,16 @@ var Navigator = React.createClass({
   },
 
   _renderNavigationBar: function() {
-    if (!this.props.navigationBar) {
+    let { navigationBar } = this.props;
+    if (!navigationBar) {
       return null;
     }
-    return React.cloneElement(this.props.navigationBar, {
+    return React.cloneElement(navigationBar, {
       ref: (navBar) => {
-        this.props.navigationBar.ref instanceof Function && this.props.navigationBar.ref(navBar);
         this._navBar = navBar;
+        if (navigationBar && typeof navigationBar.ref === 'function') {
+          navigationBar.ref(navBar);
+        }
       },
       navigator: this._navigationBarNavigator,
       navState: this.state,

From 6579b705e99c925ddaed10ddcdb7ba303ccb771f Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Thu, 7 Jan 2016 06:13:14 -0800
Subject: [PATCH 0658/1411] Add option to throw/not throw when module can't
 resolve

Reviewed By: martinbigio

Differential Revision: D2808973

fb-gh-sync-id: 2e06355d1e0dd3c1ea297273c44858ec4ed574ee
---
 .../DependencyGraph/ResolutionRequest.js                  | 8 ++++++--
 .../DependencyGraph/__tests__/DependencyGraph-test.js     | 1 +
 .../src/DependencyResolver/DependencyGraph/index.js       | 3 +++
 packager/react-packager/src/Resolver/index.js             | 1 +
 4 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
index f896de27c80c..f4b200007787 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
@@ -25,6 +25,7 @@ class ResolutionRequest {
     helpers,
     moduleCache,
     fastfs,
+    shouldThrowOnUnresolvedErrors,
   }) {
     this._platform = platform;
     this._preferNativePlatform = preferNativePlatform;
@@ -34,6 +35,7 @@ class ResolutionRequest {
     this._helpers = helpers;
     this._moduleCache = moduleCache;
     this._fastfs = fastfs;
+    this._shouldThrowOnUnresolvedErrors = shouldThrowOnUnresolvedErrors;
     this._resetResolutionCache();
   }
 
@@ -67,8 +69,10 @@ class ResolutionRequest {
     };
 
     const forgive = (error) => {
-      if (error.type !== 'UnableToResolveError' ||
-        this._platform === 'ios') {
+      if (
+        error.type !== 'UnableToResolveError' ||
+        this._shouldThrowOnUnresolvedErrors(this._entryPath, this._platform)
+      ) {
         throw error;
       }
 
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
index cd434a1d2098..184ea71fc5fc 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
@@ -70,6 +70,7 @@ describe('DependencyGraph', function() {
         'parse',
       ],
       platforms: ['ios', 'android'],
+      shouldThrowOnUnresolvedErrors: () => false,
     };
   });
 
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
index ec0d964e0eaf..634cf5dab12d 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
@@ -42,6 +42,7 @@ class DependencyGraph {
     extensions,
     mocksPattern,
     extractRequires,
+    shouldThrowOnUnresolvedErrors = () => true,
   }) {
     this._opts = {
       activity: activity || defaultActivity,
@@ -57,6 +58,7 @@ class DependencyGraph {
       extensions: extensions || ['js', 'json'],
       mocksPattern,
       extractRequires,
+      shouldThrowOnUnresolvedErrors,
     };
     this._cache = this._opts.cache;
     this._helpers = new DependencyGraphHelpers(this._opts);
@@ -163,6 +165,7 @@ class DependencyGraph {
         helpers: this._helpers,
         moduleCache: this._moduleCache,
         fastfs: this._fastfs,
+        shouldThrowOnUnresolvedErrors: this._opts.shouldThrowOnUnresolvedErrors,
       });
 
       const response = new ResolutionResponse();
diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index 8726233e8c55..b2466dcc1359 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -95,6 +95,7 @@ class Resolver {
       preferNativePlatform: true,
       fileWatcher: opts.fileWatcher,
       cache: opts.cache,
+      shouldThrowOnUnresolvedErrors: (_, platform) => platform === 'ios',
     });
 
     this._polyfillModuleNames = opts.polyfillModuleNames || [];

From 857dd59340ec3436a098627e948cb5f909c6fafb Mon Sep 17 00:00:00 2001
From: Lauri Lehmijoki <lauri.lehmijoki@iki.fi>
Date: Thu, 7 Jan 2016 06:18:26 -0800
Subject: [PATCH 0659/1411] Fix minor typo in PanResponder

Summary:
Replaces https://github.com/facebook/react-native/pull/4469
Closes https://github.com/facebook/react-native/pull/4487

Reviewed By: svcscm

Differential Revision: D2713948

Pulled By: bestander

fb-gh-sync-id: b072379ad99b8891168ce64defeebfaf5442e394
---
 Libraries/vendor/react/browser/eventPlugins/PanResponder.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/vendor/react/browser/eventPlugins/PanResponder.js b/Libraries/vendor/react/browser/eventPlugins/PanResponder.js
index afeba8a481f2..36490a843026 100644
--- a/Libraries/vendor/react/browser/eventPlugins/PanResponder.js
+++ b/Libraries/vendor/react/browser/eventPlugins/PanResponder.js
@@ -56,7 +56,7 @@ var currentCentroidY = TouchHistoryMath.currentCentroidY;
  *  - `dy` - accumulated distance of the gesture since the touch started
  *  - `vx` - current velocity of the gesture
  *  - `vy` - current velocity of the gesture
- *  - `numberActiveTouches` - Number of touches currently on screeen
+ *  - `numberActiveTouches` - Number of touches currently on screen
  *
  * ### Basic Usage
  *

From 6dc6794881846f635e496bb14c7acaccc56db986 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Thu, 7 Jan 2016 07:36:51 -0800
Subject: [PATCH 0660/1411] Add onSelectionChange for Android TextInput

Summary:
public

Add an onSelectionChange method to TextInput that works on Android same as iOS

Reviewed By: andreicoman11

Differential Revision: D2780131

fb-gh-sync-id: 9b3b8fbd9ea653d43e3107a338e4bc08bde2e8c6
---
 Libraries/Components/TextInput/TextInput.js   | 17 ++++++
 .../react/views/textinput/ReactEditText.java  | 25 +++++++-
 .../textinput/ReactTextInputManager.java      | 43 ++++++++++++++
 .../ReactTextInputSelectionEvent.java         | 58 +++++++++++++++++++
 .../views/textinput/SelectionWatcher.java     | 18 ++++++
 5 files changed, 160 insertions(+), 1 deletion(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputSelectionEvent.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/textinput/SelectionWatcher.java

diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js
index 62ff5f2a8499..53bc6235d040 100644
--- a/Libraries/Components/TextInput/TextInput.js
+++ b/Libraries/Components/TextInput/TextInput.js
@@ -216,6 +216,10 @@ var TextInput = React.createClass({
      * Callback that is called when text input ends.
      */
     onEndEditing: PropTypes.func,
+    /**
+     * Callback that is called when the text input selection is changed
+     */
+    onSelectionChange: PropTypes.func,
     /**
      * Callback that is called when the text input's submit button is pressed.
      * Invalid if multiline={true} is specified.
@@ -474,6 +478,17 @@ var TextInput = React.createClass({
   },
 
   _renderAndroid: function() {
+    var onSelectionChange;
+    if (this.props.selectionState || this.props.onSelectionChange) {
+      onSelectionChange = (event: Event) => {
+        if (this.props.selectionState) {
+          var selection = event.nativeEvent.selection;
+          this.props.selectionState.update(selection.start, selection.end);
+        }
+        this.props.onSelectionChange && this.props.onSelectionChange(event);
+      };
+    }
+
     var autoCapitalize = UIManager.UIText.AutocapitalizationType[this.props.autoCapitalize];
     var textAlign =
       UIManager.AndroidTextInput.Constants.TextAlign[this.props.textAlign];
@@ -489,6 +504,7 @@ var TextInput = React.createClass({
     if (childCount > 1) {
       children = <Text>{children}</Text>;
     }
+
     var textContainer =
       <AndroidTextInput
         ref="input"
@@ -505,6 +521,7 @@ var TextInput = React.createClass({
         onFocus={this._onFocus}
         onBlur={this._onBlur}
         onChange={this._onChange}
+        onSelectionChange={onSelectionChange}
         onTextInput={this._onTextInput}
         onEndEditing={this.props.onEndEditing}
         onSubmitEditing={this.props.onSubmitEditing}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
index 3ac44ed41fb7..de7178d76a0e 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
@@ -64,6 +64,7 @@ public class ReactEditText extends EditText {
   private @Nullable TextWatcherDelegator mTextWatcherDelegator;
   private int mStagedInputType;
   private boolean mContainsImages;
+  private @Nullable SelectionWatcher mSelectionWatcher;
 
   public ReactEditText(Context context) {
     super(context);
@@ -150,6 +151,27 @@ public void removeTextChangedListener(TextWatcher watcher) {
     }
   }
 
+  @Override
+  protected void onSelectionChanged(int selStart, int selEnd) {
+    super.onSelectionChanged(selStart, selEnd);
+    if (mSelectionWatcher != null && hasFocus()) {
+      mSelectionWatcher.onSelectionChanged(selStart, selEnd);
+    }
+  }
+
+  @Override
+  protected void onFocusChanged(
+      boolean focused, int direction, Rect previouslyFocusedRect) {
+    super.onFocusChanged(focused, direction, previouslyFocusedRect);
+    if (focused && mSelectionWatcher != null) {
+      mSelectionWatcher.onSelectionChanged(getSelectionStart(), getSelectionEnd());
+    }
+  }
+
+  public void setSelectionWatcher(SelectionWatcher selectionWatcher) {
+    mSelectionWatcher = selectionWatcher;
+  }
+
   /*protected*/ int getStagedInputType() {
     return mStagedInputType;
   }
@@ -170,7 +192,8 @@ public void setInputType(int type) {
     mStagedInputType = type;
   }
 
-  /* package */ void requestFocusFromJS() {
+  // VisibleForTesting from {@link TextInputEventsTestCase}.
+  public void requestFocusFromJS() {
     mIsJSSettingFocus = true;
     requestFocus();
     mIsJSSettingFocus = false;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
index 65a32d5855e8..7df5f52a5728 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
@@ -166,6 +166,15 @@ public void setFontSize(ReactEditText view, float fontSize) {
         (int) Math.ceil(PixelUtil.toPixelFromSP(fontSize)));
   }
 
+  @ReactProp(name = "onSelectionChange", defaultBoolean = false)
+  public void setOnSelectionChange(final ReactEditText view, boolean onSelectionChange) {
+    if (onSelectionChange) {
+      view.setSelectionWatcher(new ReactSelectionWatcher(view));
+    } else {
+      view.setSelectionWatcher(null);
+    }
+  }
+
   @ReactProp(name = "placeholder")
   public void setPlaceholder(ReactEditText view, @Nullable String placeholder) {
     view.setHint(placeholder);
@@ -418,6 +427,40 @@ public boolean onEditorAction(TextView v, int actionId, KeyEvent keyEvent) {
         });
   }
 
+  private class ReactSelectionWatcher implements SelectionWatcher {
+
+    private ReactEditText mReactEditText;
+    private EventDispatcher mEventDispatcher;
+    private int mPreviousSelectionStart;
+    private int mPreviousSelectionEnd;
+
+    public ReactSelectionWatcher(ReactEditText editText) {
+      mReactEditText = editText;
+      ReactContext reactContext = (ReactContext) editText.getContext();
+      mEventDispatcher = reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
+    }
+
+    @Override
+    public void onSelectionChanged(int start, int end) {
+      // Android will call us back for both the SELECTION_START span and SELECTION_END span in text
+      // To prevent double calling back into js we cache the result of the previous call and only
+      // forward it on if we have new values
+      if (mPreviousSelectionStart != start || mPreviousSelectionEnd != end) {
+        mEventDispatcher.dispatchEvent(
+            new ReactTextInputSelectionEvent(
+                mReactEditText.getId(),
+                SystemClock.uptimeMillis(),
+                start,
+                end
+            )
+        );
+
+        mPreviousSelectionStart = start;
+        mPreviousSelectionEnd = end;
+      }
+    }
+  }
+
   @Override
   public @Nullable Map getExportedViewConstants() {
     return MapBuilder.of(
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputSelectionEvent.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputSelectionEvent.java
new file mode 100644
index 000000000000..8c6b18d9ba6b
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputSelectionEvent.java
@@ -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.
+ */
+
+package com.facebook.react.views.textinput;
+
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.uimanager.events.Event;
+import com.facebook.react.uimanager.events.RCTEventEmitter;
+
+/**
+ * Event emitted by EditText native view when the text selection changes.
+ */
+/* package */ class ReactTextInputSelectionEvent
+    extends Event<ReactTextInputSelectionEvent> {
+
+  private static final String EVENT_NAME = "topSelectionChange";
+
+  private int mSelectionStart;
+  private int mSelectionEnd;
+
+  public ReactTextInputSelectionEvent(
+      int viewId,
+      long timestampMs,
+      int selectionStart,
+      int selectionEnd) {
+    super(viewId, timestampMs);
+    mSelectionStart = selectionStart;
+    mSelectionEnd = selectionEnd;
+  }
+
+  @Override
+  public String getEventName() {
+    return EVENT_NAME;
+  }
+
+  @Override
+  public void dispatch(RCTEventEmitter rctEventEmitter) {
+    rctEventEmitter.receiveEvent(getViewTag(), getEventName(), serializeEventData());
+  }
+
+  private WritableMap serializeEventData() {
+    WritableMap eventData = Arguments.createMap();
+
+    WritableMap selectionData = Arguments.createMap();
+    selectionData.putInt("start", mSelectionStart);
+    selectionData.putInt("end", mSelectionEnd);
+
+    eventData.putMap("selection", selectionData);
+    return eventData;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/SelectionWatcher.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/SelectionWatcher.java
new file mode 100644
index 000000000000..f569067ab916
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/SelectionWatcher.java
@@ -0,0 +1,18 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.textinput;
+
+/**
+ * Implement this interface to be informed of selection changes in the ReactTextEdit
+ * This is used by the ReactTextInputManager to forward events from the EditText to JS
+ */
+interface SelectionWatcher {
+  public void onSelectionChanged(int start, int end);
+}

From cb94d997ca0815b720cbe2c6e591358634d8a9d3 Mon Sep 17 00:00:00 2001
From: Felix Oghina <foghina@fb.com>
Date: Thu, 7 Jan 2016 08:33:30 -0800
Subject: [PATCH 0661/1411] allow cancelling reload requests

Summary:
Make the ProgressDialog cancelable and cancel the network request / websocket connection when the user presses back.

public

Reviewed By: andreicoman11

Differential Revision: D2764788

fb-gh-sync-id: 0fdb87ba9431be5a3c453422724cd364292eff61
---
 .../react/devsupport/DevServerHelper.java     | 26 +++++++++++++++++--
 .../react/devsupport/DevSupportManager.java   |  7 +++++
 2 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java
index 3439eaf2d748..515cab3a517b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java
@@ -91,6 +91,7 @@ public interface PackagerStatusCallback {
   private boolean mOnChangePollingEnabled;
   private @Nullable OkHttpClient mOnChangePollingClient;
   private @Nullable OnServerContentChangeListener mOnServerContentChangeListener;
+  private @Nullable Call mDownloadBundleFromURLCall;
 
   public DevServerHelper(DevInternalSettings settings) {
     mSettings = settings;
@@ -179,15 +180,29 @@ public void downloadBundleFromURL(
     Request request = new Request.Builder()
         .url(bundleURL)
         .build();
-    Call call = mClient.newCall(request);
-    call.enqueue(new Callback() {
+    mDownloadBundleFromURLCall = Assertions.assertNotNull(mClient.newCall(request));
+    mDownloadBundleFromURLCall.enqueue(new Callback() {
       @Override
       public void onFailure(Request request, IOException e) {
+        // ignore callback if call was cancelled
+        if (mDownloadBundleFromURLCall == null || mDownloadBundleFromURLCall.isCanceled()) {
+          mDownloadBundleFromURLCall = null;
+          return;
+        }
+        mDownloadBundleFromURLCall = null;
+
         callback.onFailure(e);
       }
 
       @Override
       public void onResponse(Response response) throws IOException {
+        // ignore callback if call was cancelled
+        if (mDownloadBundleFromURLCall == null || mDownloadBundleFromURLCall.isCanceled()) {
+          mDownloadBundleFromURLCall = null;
+          return;
+        }
+        mDownloadBundleFromURLCall = null;
+
         // Check for server errors. If the server error has the expected form, fail with more info.
         if (!response.isSuccessful()) {
           String body = response.body().string();
@@ -214,6 +229,13 @@ public void onResponse(Response response) throws IOException {
     });
   }
 
+  public void cancelDownloadBundleFromURL() {
+    if (mDownloadBundleFromURLCall != null) {
+      mDownloadBundleFromURLCall.cancel();
+      mDownloadBundleFromURLCall = null;
+    }
+  }
+
   public void isPackagerRunning(final PackagerStatusCallback callback) {
     String statusURL = createPackagerStatusURL(getDebugServerHost());
     Request request = new Request.Builder()
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
index 2625bec62956..cf86bd3b3547 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
@@ -629,6 +629,13 @@ public void run() {
         },
         Assertions.assertNotNull(mJSAppBundleName),
         mJSBundleTempFile);
+    progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+      @Override
+      public void onCancel(DialogInterface dialog) {
+        mDevServerHelper.cancelDownloadBundleFromURL();
+      }
+    });
+    progressDialog.setCancelable(true);
   }
 
   private void reload() {

From 5f3d08d5248b47954d2739aca45c8cbbb68fc38e Mon Sep 17 00:00:00 2001
From: tdzl2003 <tdzl2003@gmail.com>
Date: Thu, 7 Jan 2016 08:35:17 -0800
Subject: [PATCH 0662/1411] Fix build error and runtime error after proguard
 enabled.

Summary:
Fix:
1. :app:packageRelease FAILED caused by proguard exception: `java.io.IOException: Please correct the above warnings first.`
2. Fix runtime exception
```
java.lang.ExceptionInInitializerError
   at com.facebook.react.ReactInstanceManagerImpl.recreateReactContextInBackgroundFromBundleFile(ReactInstanceManagerImpl.java:308)
```
Closes https://github.com/facebook/react-native/pull/5146

Reviewed By: svcscm

Differential Revision: D2807252

Pulled By: mkonicek

fb-gh-sync-id: 03d004405c7cca14a71230086b95351cfacbc055
---
 .../generator-android/templates/src/app/proguard-rules.pro | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/local-cli/generator-android/templates/src/app/proguard-rules.pro b/local-cli/generator-android/templates/src/app/proguard-rules.pro
index ffa8c9f64b62..35840261d7cc 100644
--- a/local-cli/generator-android/templates/src/app/proguard-rules.pro
+++ b/local-cli/generator-android/templates/src/app/proguard-rules.pro
@@ -40,10 +40,13 @@
 
 -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
 -keep class * extends com.facebook.react.bridge.NativeModule { *; }
+-keepclassmembers,includedescriptorclasses class * { native <methods>; }
 -keepclassmembers class *  { @com.facebook.react.uimanager.UIProp <fields>; }
 -keepclassmembers class *  { @com.facebook.react.uimanager.ReactProp <methods>; }
 -keepclassmembers class *  { @com.facebook.react.uimanager.ReactPropGroup <methods>; }
 
+-dontwarn com.facebook.react.**
+
 # okhttp
 
 -keepattributes Signature
@@ -58,3 +61,7 @@
 -dontwarn java.nio.file.*
 -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
 -dontwarn okio.**
+
+# stetho
+
+-dontwarn com.facebook.stetho.**

From a45219966c0e6ec58e87009dba046622aef8427e Mon Sep 17 00:00:00 2001
From: realaboo <realaboo@gmail.com>
Date: Thu, 7 Jan 2016 08:44:14 -0800
Subject: [PATCH 0663/1411] ProgressBarAndroid: default value for styleAttr

Summary:
Current default value of ProgressBarAndroid's styleAttr is "Large" which sets the ProgressBar's style to [Widget_ProgressBar_Large](http://developer.android.com/reference/android/R.style.html#Widget_ProgressBar_Large) at native side. But large is not the default style for the native side ProgressBar.

For example, the size of the ProgressBar is 48dip for default style, but 76dip for large and 16dip for small as in the Material themes. Although the size of ProgressBarAndroid could be set in JS, it'll be better to have the same default style as in native side themes.

My PR adds a "Normal" value for styleAttr prop and makes it the default value.
Closes https://github.com/facebook/react-native/pull/4974

Reviewed By: svcscm

Differential Revision: D2811229

Pulled By: bestander

fb-gh-sync-id: 087f68d1919fe933d86e5194112bf7a5f5b3f3c6
---
 Examples/UIExplorer/ProgressBarAndroidExample.android.js      | 4 ++++
 .../ProgressBarAndroid/ProgressBarAndroid.android.js          | 4 +++-
 .../react/views/progressbar/ReactProgressBarViewManager.java  | 4 +++-
 3 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/Examples/UIExplorer/ProgressBarAndroidExample.android.js b/Examples/UIExplorer/ProgressBarAndroidExample.android.js
index b58cd73ca586..19b182bc7692 100644
--- a/Examples/UIExplorer/ProgressBarAndroidExample.android.js
+++ b/Examples/UIExplorer/ProgressBarAndroidExample.android.js
@@ -60,6 +60,10 @@ var ProgressBarAndroidExample = React.createClass({
           <ProgressBar />
         </UIExplorerBlock>
 
+        <UIExplorerBlock title="Normal ProgressBar">
+          <ProgressBar styleAttr="Normal" />
+        </UIExplorerBlock>
+
         <UIExplorerBlock title="Small ProgressBar">
           <ProgressBar styleAttr="Small" />
         </UIExplorerBlock>
diff --git a/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js b/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js
index 974eaf97d030..95e5504a4499 100644
--- a/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js
+++ b/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js
@@ -21,6 +21,7 @@ var requireNativeComponent = require('requireNativeComponent');
 
 var STYLE_ATTRIBUTES = [
   'Horizontal',
+  'Normal',
   'Small',
   'Large',
   'Inverse',
@@ -70,6 +71,7 @@ var ProgressBarAndroid = React.createClass({
      * Style of the ProgressBar. One of:
      *
      * - Horizontal
+     * - Normal (default)
      * - Small
      * - Large
      * - Inverse
@@ -98,7 +100,7 @@ var ProgressBarAndroid = React.createClass({
 
   getDefaultProps: function() {
     return {
-      styleAttr: 'Large',
+      styleAttr: 'Normal',
       indeterminate: true
     };
   },
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ReactProgressBarViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ReactProgressBarViewManager.java
index 7f5bae7b3700..82601ceddcc2 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ReactProgressBarViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/ReactProgressBarViewManager.java
@@ -31,7 +31,7 @@ public class ReactProgressBarViewManager extends
   /* package */ static final String PROP_PROGRESS = "progress";
 
   /* package */ static final String REACT_CLASS = "AndroidProgressBar";
-  /* package */ static final String DEFAULT_STYLE = "Large";
+  /* package */ static final String DEFAULT_STYLE = "Normal";
 
   @Override
   public String getName() {
@@ -99,6 +99,8 @@ protected void onAfterUpdateTransaction(ProgressBarContainerView view) {
       return android.R.attr.progressBarStyleSmallInverse;
     } else if (styleStr.equals("LargeInverse")) {
       return android.R.attr.progressBarStyleLargeInverse;
+    } else if (styleStr.equals("Normal")) {
+      return android.R.attr.progressBarStyle;
     } else {
       throw new JSApplicationIllegalArgumentException("Unknown ProgressBar style: " + styleStr);
     }

From 2b09614068bfe81515a9259405d59288f1e9d422 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Thu, 7 Jan 2016 08:48:39 -0800
Subject: [PATCH 0664/1411] Skip file removal on HMR interface

Summary:
public

We're not planning to accept file removals in the short term on the HMR interface so lets bail when a file is removed (before this this we were throwing when trying to get the shallow dependencies).

Reviewed By: yungsters

Differential Revision: D2810534

fb-gh-sync-id: f2733382f4a2619e22bdf1163aa4180694fff9f8
---
 local-cli/server/util/attachHMRServer.js      | 135 +++++++++---------
 packager/react-packager/src/Bundler/index.js  |   4 +
 .../DependencyGraph/index.js                  |   4 +
 packager/react-packager/src/Resolver/index.js |   4 +
 packager/react-packager/src/Server/index.js   |   2 +-
 5 files changed, 83 insertions(+), 66 deletions(-)

diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js
index dd22f5303c7d..a7244655b83a 100644
--- a/local-cli/server/util/attachHMRServer.js
+++ b/local-cli/server/util/attachHMRServer.js
@@ -106,80 +106,85 @@ function attachHMRServer({httpServer, path, packagerServer}) {
           shallowDependencies,
         };
 
-        packagerServer.setHMRFileChangeListener(filename => {
+        packagerServer.setHMRFileChangeListener((filename, stat) => {
           if (!client) {
             return;
           }
 
-          return packagerServer.getShallowDependencies(filename)
-            .then(deps => {
-              if (!client) {
-                return [];
-              }
-
-              // if the file dependencies have change we need to invalidate the
-              // dependencies caches because the list of files we need to send
-              // to the client may have changed
-              const oldDependencies = client.shallowDependencies[filename];
-              if (arrayEquals(deps, oldDependencies)) {
-                return [packagerServer.getModuleForPath(filename)];
-              }
-
-              // if there're new dependencies compare the full list of
-              // dependencies we used to have with the one we now have
-              return getDependencies(client.platform, client.bundleEntry)
-                .then(({
-                  dependenciesCache,
-                  dependenciesModulesCache,
-                  shallowDependencies,
-                }) => {
-                  if (!client) {
-                    return [];
-                  }
-
-                  // build list of modules for which we'll send HMR updates
-                  const modulesToUpdate = [];
-                  Object.keys(dependenciesModulesCache).forEach(module => {
-                    if (!client.dependenciesModulesCache[module]) {
-                      modulesToUpdate.push(dependenciesModulesCache[module]);
+          stat.then(() => {
+            return packagerServer.getShallowDependencies(filename)
+              .then(deps => {
+                if (!client) {
+                  return [];
+                }
+
+                // if the file dependencies have change we need to invalidate the
+                // dependencies caches because the list of files we need to send
+                // to the client may have changed
+                const oldDependencies = client.shallowDependencies[filename];
+                if (arrayEquals(deps, oldDependencies)) {
+                  return [packagerServer.getModuleForPath(filename)];
+                }
+
+                // if there're new dependencies compare the full list of
+                // dependencies we used to have with the one we now have
+                return getDependencies(client.platform, client.bundleEntry)
+                  .then(({
+                    dependenciesCache,
+                    dependenciesModulesCache,
+                    shallowDependencies,
+                  }) => {
+                    if (!client) {
+                      return [];
                     }
-                  });
 
-                  // invalidate caches
-                  client.dependenciesCache = dependenciesCache;
-                  client.dependenciesModulesCache = dependenciesModulesCache;
-                  client.shallowDependencies = shallowDependencies;
+                    // build list of modules for which we'll send HMR updates
+                    const modulesToUpdate = [];
+                    Object.keys(dependenciesModulesCache).forEach(module => {
+                      if (!client.dependenciesModulesCache[module]) {
+                        modulesToUpdate.push(dependenciesModulesCache[module]);
+                      }
+                    });
 
-                  return modulesToUpdate;
+                    // invalidate caches
+                    client.dependenciesCache = dependenciesCache;
+                    client.dependenciesModulesCache = dependenciesModulesCache;
+                    client.shallowDependencies = shallowDependencies;
+
+                    return modulesToUpdate;
+                  });
+              })
+              .then(modulesToUpdate => {
+                if (!client) {
+                  return;
+                }
+
+                // make sure the file was modified is part of the bundle
+                if (!client.shallowDependencies[filename]) {
+                  return;
+                }
+
+                return packagerServer.buildBundleForHMR({
+                  entryFile: client.bundleEntry,
+                  platform: client.platform,
+                  modules: modulesToUpdate,
                 });
-            })
-            .then(modulesToUpdate => {
-              if (!client) {
-                return;
-              }
-
-              // make sure the file was modified is part of the bundle
-              if (!client.shallowDependencies[filename]) {
-                return;
-              }
-
-              return packagerServer.buildBundleForHMR({
-                entryFile: client.bundleEntry,
-                platform: client.platform,
-                modules: modulesToUpdate,
+              })
+              .then(bundle => {
+                if (!client) {
+                  return;
+                }
+
+                // check we actually want to send an HMR update
+                if (bundle) {
+                  client.ws.send(bundle);
+                }
               });
-            })
-            .then(bundle => {
-              if (!client) {
-                return;
-              }
-
-              // check we actually want to send an HMR update
-              if (bundle) {
-                client.ws.send(bundle);
-              }
-            })
-            .done();
+            },
+            () => {
+              // do nothing, file was removed
+            },
+          ).done();
         });
 
         client.ws.on('error', e => {
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index 26de31301ad9..e7cb033dbb9f 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -320,6 +320,10 @@ class Bundler {
     return this._resolver.getShallowDependencies(entryFile);
   }
 
+  stat(filePath) {
+    return this._resolver.stat(filePath);
+  }
+
   getModuleForPath(entryFile) {
     return this._resolver.getModuleForPath(entryFile);
   }
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
index 634cf5dab12d..1192159b308d 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
@@ -145,6 +145,10 @@ class DependencyGraph {
     return this._moduleCache.getModule(entryPath).getDependencies();
   }
 
+  stat(filePath) {
+    return this._fastfs.stat(filePath);
+  }
+
   /**
    * Returns the module object for the given path.
    */
diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index b2466dcc1359..cf021e16f968 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -105,6 +105,10 @@ class Resolver {
     return this._depGraph.getShallowDependencies(entryFile);
   }
 
+  stat(filePath) {
+    return this._depGraph.stat(filePath);
+  }
+
   getModuleForPath(entryFile) {
     return this._depGraph.getModuleForPath(entryFile);
   }
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index f5c5b34ec099..a8d363e7220b 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -184,7 +184,7 @@ class Server {
       // updates. Instead, send the HMR updates right away and once that
       // finishes, invoke any other file change listener.
       if (this._hmrFileChangeListener) {
-        this._hmrFileChangeListener(filePath);
+        this._hmrFileChangeListener(filePath, this._bundler.stat(filePath));
         return;
       }
 

From b0640946873945ee95d2cab8f549c915dbfffd70 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Thu, 7 Jan 2016 09:30:14 -0800
Subject: [PATCH 0665/1411] Add support for promise rejection tracking

Summary:
Adds support for tracking unhandled rejections with `console.warn` (= yellow box).

I will create a follow-up with proper error stack formatting.

related: #4971
fixes: #4045, #4142

public

{F59857438}

{F59857439}

Reviewed By: bestander

Differential Revision: D2803126

fb-gh-sync-id: 376b33e42a967675a04338cbff3ec315a77d1037
---
 Libraries/Promise.js |  20 +++++
 npm-shrinkwrap.json  | 202 +++++++++++++++++++++----------------------
 package.json         |   2 +-
 3 files changed, 122 insertions(+), 102 deletions(-)

diff --git a/Libraries/Promise.js b/Libraries/Promise.js
index 7cef2042332e..004741948e4d 100644
--- a/Libraries/Promise.js
+++ b/Libraries/Promise.js
@@ -25,6 +25,26 @@
 global.setImmediate = require('setImmediate');
 var Promise = require('promise/setimmediate/es6-extensions');
 require('promise/setimmediate/done');
+if (__DEV__) {
+  require('promise/setimmediate/rejection-tracking').enable({
+    allRejections: true,
+    onUnhandled: (id, error) => {
+      const {message, stack} = error;
+      const warning =
+        `Possible Unhandled Promise Rejection (id: ${id}):\n` +
+        (message == null ? '' : `${message}\n`) +
+        (stack == null ? '' : stack);
+      console.warn(warning);
+    },
+    onHandled: (id) => {
+      const warning =
+        `Promise Rejection Handled (id: ${id})\n` +
+        'This means you can ignore any previous messages of the form ' +
+        `"Possible Unhandled Promise Rejection (id: ${id}):"`;
+      console.warn(warning);
+    },
+  });
+}
 
 /**
  * Handle either fulfillment or rejection with the same callback.
diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index 9cc1229db7cc..be4e7c0d843e 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -146,16 +146,16 @@
           "version": "2.2.0",
           "from": "debug@>=2.1.1 <3.0.0"
         },
-        "globals": {
-          "version": "6.4.1",
-          "from": "globals@>=6.4.0 <7.0.0",
-          "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
-        },
         "js-tokens": {
           "version": "1.0.1",
           "from": "js-tokens@1.0.1",
           "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
         },
+        "globals": {
+          "version": "6.4.1",
+          "from": "globals@>=6.4.0 <7.0.0",
+          "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
+        },
         "recast": {
           "version": "0.10.33",
           "from": "recast@0.10.33",
@@ -264,26 +264,26 @@
             }
           }
         },
-        "ast-types": {
-          "version": "0.8.12",
-          "from": "ast-types@0.8.12",
-          "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz"
-        },
-        "globals": {
-          "version": "6.4.1",
-          "from": "globals@>=6.4.0 <7.0.0",
-          "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
-        },
         "babylon": {
           "version": "5.8.29",
           "from": "babylon@>=5.8.29 <6.0.0",
           "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz"
         },
+        "ast-types": {
+          "version": "0.8.12",
+          "from": "ast-types@0.8.12",
+          "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz"
+        },
         "esprima-fb": {
           "version": "15001.1001.0-dev-harmony-fb",
           "from": "esprima-fb@>=15001.1001.0-dev-harmony-fb <15001.1002.0",
           "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz"
         },
+        "globals": {
+          "version": "6.4.1",
+          "from": "globals@>=6.4.0 <7.0.0",
+          "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
+        },
         "js-tokens": {
           "version": "1.0.1",
           "from": "js-tokens@1.0.1",
@@ -1869,46 +1869,46 @@
           "from": "ansi-regex@^2.0.0",
           "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
         },
-        "are-we-there-yet": {
-          "version": "1.0.4",
-          "from": "are-we-there-yet@~1.0.0",
-          "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.4.tgz"
-        },
         "ansi-styles": {
           "version": "2.1.0",
           "from": "ansi-styles@^2.1.0",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz"
         },
+        "are-we-there-yet": {
+          "version": "1.0.4",
+          "from": "are-we-there-yet@~1.0.0",
+          "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.4.tgz"
+        },
         "asn1": {
           "version": "0.1.11",
           "from": "asn1@0.1.11",
           "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
         },
-        "async": {
-          "version": "1.5.0",
-          "from": "async@^1.4.0",
-          "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz"
-        },
         "assert-plus": {
           "version": "0.1.5",
           "from": "assert-plus@^0.1.5",
           "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
         },
+        "async": {
+          "version": "1.5.0",
+          "from": "async@^1.4.0",
+          "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz"
+        },
         "aws-sign2": {
           "version": "0.6.0",
           "from": "aws-sign2@~0.6.0",
           "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
         },
-        "block-stream": {
-          "version": "0.0.8",
-          "from": "block-stream@*",
-          "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.8.tgz"
-        },
         "balanced-match": {
           "version": "0.2.1",
           "from": "balanced-match@>=0.2.0 <0.3.0",
           "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.1.tgz"
         },
+        "block-stream": {
+          "version": "0.0.8",
+          "from": "block-stream@*",
+          "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.8.tgz"
+        },
         "boom": {
           "version": "2.10.1",
           "from": "boom@^2.8.x",
@@ -1929,16 +1929,16 @@
           "from": "chalk@^1.1.1",
           "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz"
         },
-        "commander": {
-          "version": "2.9.0",
-          "from": "commander@^2.8.1",
-          "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz"
-        },
         "combined-stream": {
           "version": "1.0.5",
           "from": "combined-stream@~1.0.5",
           "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz"
         },
+        "commander": {
+          "version": "2.9.0",
+          "from": "commander@^2.8.1",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz"
+        },
         "concat-map": {
           "version": "0.0.1",
           "from": "concat-map@0.0.1",
@@ -1949,16 +1949,16 @@
           "from": "core-util-is@~1.0.0",
           "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
         },
-        "ctype": {
-          "version": "0.5.3",
-          "from": "ctype@0.5.3",
-          "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz"
-        },
         "cryptiles": {
           "version": "2.0.5",
           "from": "cryptiles@2.x.x",
           "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz"
         },
+        "ctype": {
+          "version": "0.5.3",
+          "from": "ctype@0.5.3",
+          "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz"
+        },
         "debug": {
           "version": "0.7.4",
           "from": "debug@~0.7.2",
@@ -1969,16 +1969,16 @@
           "from": "deep-extend@~0.2.5",
           "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.2.11.tgz"
         },
-        "delegates": {
-          "version": "0.1.0",
-          "from": "delegates@^0.1.0",
-          "resolved": "https://registry.npmjs.org/delegates/-/delegates-0.1.0.tgz"
-        },
         "delayed-stream": {
           "version": "1.0.0",
           "from": "delayed-stream@~1.0.0",
           "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
         },
+        "delegates": {
+          "version": "0.1.0",
+          "from": "delegates@^0.1.0",
+          "resolved": "https://registry.npmjs.org/delegates/-/delegates-0.1.0.tgz"
+        },
         "escape-string-regexp": {
           "version": "1.0.3",
           "from": "escape-string-regexp@^1.0.2",
@@ -2029,26 +2029,26 @@
           "from": "graceful-readlink@>= 1.0.0",
           "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
         },
-        "has-ansi": {
-          "version": "2.0.0",
-          "from": "has-ansi@^2.0.0",
-          "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
-        },
         "har-validator": {
           "version": "2.0.2",
           "from": "har-validator@~2.0.2",
           "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.2.tgz"
         },
-        "hawk": {
-          "version": "3.1.0",
-          "from": "hawk@~3.1.0",
-          "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.0.tgz"
+        "has-ansi": {
+          "version": "2.0.0",
+          "from": "has-ansi@^2.0.0",
+          "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
         },
         "has-unicode": {
           "version": "1.0.1",
           "from": "has-unicode@^1.0.0",
           "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-1.0.1.tgz"
         },
+        "hawk": {
+          "version": "3.1.0",
+          "from": "hawk@~3.1.0",
+          "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.0.tgz"
+        },
         "hoek": {
           "version": "2.16.3",
           "from": "hoek@2.x.x",
@@ -2064,16 +2064,16 @@
           "from": "inherits@*",
           "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
         },
-        "is-my-json-valid": {
-          "version": "2.12.2",
-          "from": "is-my-json-valid@^2.12.2",
-          "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.2.tgz"
-        },
         "ini": {
           "version": "1.3.4",
           "from": "ini@~1.3.0",
           "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz"
         },
+        "is-my-json-valid": {
+          "version": "2.12.2",
+          "from": "is-my-json-valid@^2.12.2",
+          "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.2.tgz"
+        },
         "is-property": {
           "version": "1.0.2",
           "from": "is-property@^1.0.0",
@@ -2084,21 +2084,26 @@
           "from": "isarray@0.0.1",
           "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
         },
-        "json-stringify-safe": {
-          "version": "5.0.1",
-          "from": "json-stringify-safe@~5.0.1",
-          "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
-        },
         "isstream": {
           "version": "0.1.2",
           "from": "isstream@~0.1.2",
           "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
         },
+        "json-stringify-safe": {
+          "version": "5.0.1",
+          "from": "json-stringify-safe@~5.0.1",
+          "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
+        },
         "jsonpointer": {
           "version": "2.0.0",
           "from": "jsonpointer@2.0.0",
           "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
         },
+        "lodash._basetostring": {
+          "version": "3.0.1",
+          "from": "lodash._basetostring@^3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz"
+        },
         "lodash._createpadding": {
           "version": "3.6.1",
           "from": "lodash._createpadding@^3.0.0",
@@ -2109,11 +2114,6 @@
           "from": "lodash.pad@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-3.1.1.tgz"
         },
-        "lodash._basetostring": {
-          "version": "3.0.1",
-          "from": "lodash._basetostring@^3.0.0",
-          "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz"
-        },
         "lodash.padleft": {
           "version": "3.1.1",
           "from": "lodash.padleft@^3.0.0",
@@ -2149,16 +2149,16 @@
           "from": "mkdirp@>=0.3.0 <0.4.0||>=0.4.0 <0.5.0||>=0.5.0 <0.6.0",
           "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz"
         },
-        "npmlog": {
-          "version": "1.2.1",
-          "from": "npmlog@~1.2.0",
-          "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz"
-        },
         "node-uuid": {
           "version": "1.4.3",
           "from": "node-uuid@~1.4.3",
           "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.3.tgz"
         },
+        "npmlog": {
+          "version": "1.2.1",
+          "from": "npmlog@~1.2.0",
+          "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz"
+        },
         "oauth-sign": {
           "version": "0.8.0",
           "from": "oauth-sign@~0.8.0",
@@ -2179,16 +2179,16 @@
           "from": "pinkie@^1.0.0",
           "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
         },
-        "qs": {
-          "version": "5.2.0",
-          "from": "qs@~5.2.0",
-          "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz"
-        },
         "pinkie-promise": {
           "version": "1.0.0",
           "from": "pinkie-promise@^1.0.0",
           "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz"
         },
+        "qs": {
+          "version": "5.2.0",
+          "from": "qs@~5.2.0",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz"
+        },
         "readable-stream": {
           "version": "1.1.13",
           "from": "readable-stream@^1.1.13",
@@ -2199,56 +2199,56 @@
           "from": "request@2.x",
           "resolved": "https://registry.npmjs.org/request/-/request-2.65.0.tgz"
         },
+        "semver": {
+          "version": "5.0.3",
+          "from": "semver@~5.0.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
+        },
         "sntp": {
           "version": "1.0.9",
           "from": "sntp@1.x.x",
           "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
         },
-        "stringstream": {
-          "version": "0.0.5",
-          "from": "stringstream@~0.0.4",
-          "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
-        },
         "string_decoder": {
           "version": "0.10.31",
           "from": "string_decoder@~0.10.x",
           "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
         },
-        "semver": {
-          "version": "5.0.3",
-          "from": "semver@~5.0.1",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
+        "stringstream": {
+          "version": "0.0.5",
+          "from": "stringstream@~0.0.4",
+          "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
         },
         "strip-ansi": {
           "version": "3.0.0",
           "from": "strip-ansi@^3.0.0",
           "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz"
         },
-        "strip-json-comments": {
-          "version": "0.1.3",
-          "from": "strip-json-comments@0.1.x",
-          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
-        },
         "supports-color": {
           "version": "2.0.0",
           "from": "supports-color@^2.0.0",
           "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
         },
+        "strip-json-comments": {
+          "version": "0.1.3",
+          "from": "strip-json-comments@0.1.x",
+          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
+        },
         "tar": {
           "version": "2.2.1",
           "from": "tar@~2.2.0",
           "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz"
         },
-        "tough-cookie": {
-          "version": "2.2.0",
-          "from": "tough-cookie@~2.2.0",
-          "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.0.tgz"
-        },
         "tunnel-agent": {
           "version": "0.4.1",
           "from": "tunnel-agent@~0.4.1",
           "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz"
         },
+        "tough-cookie": {
+          "version": "2.2.0",
+          "from": "tough-cookie@~2.2.0",
+          "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.0.tgz"
+        },
         "uid-number": {
           "version": "0.0.3",
           "from": "uid-number@0.0.3",
@@ -4139,9 +4139,9 @@
       "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz"
     },
     "promise": {
-      "version": "7.0.4",
-      "from": "promise@>=7.0.3 <8.0.0",
-      "resolved": "https://registry.npmjs.org/promise/-/promise-7.0.4.tgz",
+      "version": "7.1.1",
+      "from": "https://registry.npmjs.org/promise/-/promise-7.1.1.tgz",
+      "resolved": "https://registry.npmjs.org/promise/-/promise-7.1.1.tgz",
       "dependencies": {
         "asap": {
           "version": "2.0.3",
diff --git a/package.json b/package.json
index 37e7a79c1c4b..e7faf110b169 100644
--- a/package.json
+++ b/package.json
@@ -105,7 +105,7 @@
     "opn": "^3.0.2",
     "optimist": "^0.6.1",
     "progress": "^1.1.8",
-    "promise": "^7.0.4",
+    "promise": "^7.1.1",
     "react": "^0.14.5",
     "react-timer-mixin": "^0.13.2",
     "react-transform-hmr": "^1.0.1",

From abb81eb2702a01c103018b0d943fe5fec6c17ea3 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Thu, 7 Jan 2016 09:32:46 -0800
Subject: [PATCH 0666/1411] Add support for split build per architecture

Summary:
This allows everyone to deploy significantly smaller APKs to they Play Store by building separate APKs for ARM, x86 architectures.

For a simple app, a release APK minified with Produard:
- Universal APK is **7MB**
- x86 APK is **4.6MB** (34% reduction)
- ARM APK is **3.7MB** (47% reduction)

Created a sample project, uncommented `// include "armeabi-v7a", 'x86'`:

    cd android
    ./gradlew assembleDebug

Three APKs were created, unzipped each: one has only x86 binaries,
one has ARM binaries, one has both.

    ./gradlew assembleRelease

Three APKs were created, JS bundle is correcly added to assets.

    react-native run-android

The correct APK is installed on the emulator and the app runs fine
(Gradle output: "Installing APK 'app-x86-debug.apk'").

With the line commented out the behavior is exactly the same as before,
only one universal APK is built.

Checked that version codes are set correctly as described in
http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
http://developer.android.com/intl/ru/google/play/publishing/multiple-apks.html

Closes https://github.com/facebook/react-native/pull/5160

Reviewed By: svcscm

Differential Revision: D2811443

Pulled By: mkonicek

fb-gh-sync-id: 97b22b9cd567e53b8adac36669b90768458b7a55
---
 .../templates/src/app/build.gradle            | 41 ++++++++++++++++++-
 .../templates/src/app/react.gradle            | 23 ++++++++++-
 2 files changed, 61 insertions(+), 3 deletions(-)

diff --git a/local-cli/generator-android/templates/src/app/build.gradle b/local-cli/generator-android/templates/src/app/build.gradle
index 1298bb3f474c..b68fc50c515e 100644
--- a/local-cli/generator-android/templates/src/app/build.gradle
+++ b/local-cli/generator-android/templates/src/app/build.gradle
@@ -1,5 +1,7 @@
 apply plugin: "com.android.application"
 
+import com.android.build.OutputFile
+
 /**
  * The react.gradle file registers two tasks: bundleDebugJsAndAssets and bundleReleaseJsAndAssets.
  * These basically call `react-native bundle` with the correct arguments during the Android build
@@ -49,6 +51,22 @@ apply plugin: "com.android.application"
 
 apply from: "react.gradle"
 
+/**
+ * Set this to true to create three separate APKs instead of one:
+ *   - A universal APK that works on all devices
+ *   - An APK that only works on ARM devices
+ *   - An APK that only works on x86 devices
+ * The advantage is the size of the APK is reduced by about 4MB.
+ * Upload all the APKs to the Play Store and people will download
+ * the correct one based on the CPU architecture of their device.
+ */
+def enableSeparateBuildPerCPUArchitecture = false
+
+/**
+ * Run Proguard to shrink the Java bytecode in release builds.
+ */
+def enableProguardInReleaseBuilds = true
+
 android {
     compileSdkVersion 23
     buildToolsVersion "23.0.1"
@@ -63,12 +81,33 @@ android {
             abiFilters "armeabi-v7a", "x86"
         }
     }
+    splits {
+        abi {
+            enable enableSeparateBuildPerCPUArchitecture
+            universalApk true
+            reset()
+            include "armeabi-v7a", "x86"
+        }
+    }
     buildTypes {
         release {
-            minifyEnabled false  // Set this to true to enable Proguard
+            minifyEnabled enableProguardInReleaseBuilds
             proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
         }
     }
+    // applicationVariants are e.g. debug, release
+    applicationVariants.all { variant ->
+        variant.outputs.each { output ->
+            // For each separate APK per architecture, set a unique version code as described here:
+            // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
+            def versionCodes = ["armeabi-v7a":1, "x86":2]
+            def abi = output.getFilter(OutputFile.ABI)
+            if (abi != null) {  // null for the universal-debug, universal-release variants
+                output.versionCodeOverride =
+                        versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
+            }
+        }
+    }
 }
 
 dependencies {
diff --git a/local-cli/generator-android/templates/src/app/react.gradle b/local-cli/generator-android/templates/src/app/react.gradle
index 1e08b00f13b9..f2152d1f6848 100644
--- a/local-cli/generator-android/templates/src/app/react.gradle
+++ b/local-cli/generator-android/templates/src/app/react.gradle
@@ -74,14 +74,33 @@ task bundleReleaseJsAndAssets(type: Exec) {
     enabled config.bundleInRelease ?: true
 }
 
+void runBefore(String dependentTaskName, Task task) {
+    Task dependentTask = tasks.findByPath(dependentTaskName);
+    if (dependentTask != null) {
+        dependentTask.dependsOn task
+    }
+}
+
 gradle.projectsEvaluated {
+
     // hook bundleDebugJsAndAssets into the android build process
+
     bundleDebugJsAndAssets.dependsOn mergeDebugResources
     bundleDebugJsAndAssets.dependsOn mergeDebugAssets
-    processDebugResources.dependsOn bundleDebugJsAndAssets
+
+    runBefore('processArmeabi-v7aDebugResources', bundleDebugJsAndAssets)
+    runBefore('processX86DebugResources', bundleDebugJsAndAssets)
+    runBefore('processUniversalDebugResources', bundleDebugJsAndAssets)
+    runBefore('processDebugResources', bundleDebugJsAndAssets)
 
     // hook bundleReleaseJsAndAssets into the android build process
+
     bundleReleaseJsAndAssets.dependsOn mergeReleaseResources
     bundleReleaseJsAndAssets.dependsOn mergeReleaseAssets
-    processReleaseResources.dependsOn bundleReleaseJsAndAssets
+
+    runBefore('processArmeabi-v7aReleaseResources', bundleReleaseJsAndAssets)
+    runBefore('processX86ReleaseResources', bundleReleaseJsAndAssets)
+    runBefore('processUniversalReleaseResources', bundleReleaseJsAndAssets)
+    runBefore('processReleaseResources', bundleReleaseJsAndAssets)
+
 }

From b115277d00f54fa7af5d61062c9e3cf362b7c5da Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 7 Jan 2016 09:48:15 -0800
Subject: [PATCH 0667/1411] Fixed border smearing issue

Summary:
public
The iOS border rendering code did not follow the CSS spec in cases where the sum of adjacent border radii was greater than the width of the view, resulting in drawing glitches such as pixel smear and borders appearing stretched or squashed.

This diff brings our implementation closer to spec-compliance in these cases. I also fixed a longstanding issue with ghostly diagonal lines appearing at the corners due to antialiasing rounding errors!

Fixes

https://github.com/facebook/react-native/issues/1572
https://github.com/facebook/react-native/issues/2089
https://github.com/facebook/react-native/issues/4604

Reviewed By: tadeuzagallo

Differential Revision: D2811249

fb-gh-sync-id: c3dd2721e0a01a432fa4dc78daa05680595edd08
---
 .../testLayoutExample_1@2x.png                | Bin 75072 -> 130700 bytes
 .../testSwitchExample_1@2x.png                | Bin 89411 -> 150432 bytes
 .../testTextExample_1@2x.png                  | Bin 283241 -> 368668 bytes
 .../testViewExample_1@2x.png                  | Bin 156654 -> 156634 bytes
 React/Views/RCTBorderDrawing.m                |  72 ++++++++++++++----
 React/Views/RCTView.m                         |  29 +++++--
 6 files changed, 78 insertions(+), 23 deletions(-)

diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testLayoutExample_1@2x.png b/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testLayoutExample_1@2x.png
index 5786896ee94950e74ea402f5a411ea373e7ee898..2c6573453937f42ef6c48247dd04c95989933439 100644
GIT binary patch
diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testSwitchExample_1@2x.png b/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testSwitchExample_1@2x.png
index bfd5872677fdd3bc1a46333a4f97d56394e44c04..f5b29ca7874c29701a7e8b227e0db763270d4a31 100644
GIT binary patch
diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testTextExample_1@2x.png b/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testTextExample_1@2x.png
index 43718fb495b2e7f5dde4d910e28b0a660d7a83d8..71d9849217254c17cd3bc24b733e54b2eb8aee3f 100644
GIT binary patch
diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testViewExample_1@2x.png b/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testViewExample_1@2x.png
index 4df43bb79e185259978d025f9dd28c3baaf96fab..c27b9cd19e7478674c3a9980d3681d6cc8cb5b17 100644
GIT binary patch
diff --git a/React/Views/RCTBorderDrawing.m b/React/Views/RCTBorderDrawing.m
index e7f236bf698b..2c661a2e36d2 100644
--- a/React/Views/RCTBorderDrawing.m
+++ b/React/Views/RCTBorderDrawing.m
@@ -96,10 +96,22 @@ CGPathRef RCTPathCreateWithRoundedRect(CGRect bounds,
   const CGFloat maxX = CGRectGetMaxX(bounds);
   const CGFloat maxY = CGRectGetMaxY(bounds);
 
-  const CGSize topLeft = cornerInsets.topLeft;
-  const CGSize topRight = cornerInsets.topRight;
-  const CGSize bottomLeft = cornerInsets.bottomLeft;
-  const CGSize bottomRight = cornerInsets.bottomRight;
+  const CGSize topLeft = {
+    MAX(0, MIN(cornerInsets.topLeft.width, bounds.size.width - cornerInsets.topRight.width)),
+    MAX(0, MIN(cornerInsets.topLeft.height, bounds.size.height - cornerInsets.bottomLeft.height)),
+  };
+  const CGSize topRight = {
+    MAX(0, MIN(cornerInsets.topRight.width, bounds.size.width - cornerInsets.topLeft.width)),
+    MAX(0, MIN(cornerInsets.topRight.height, bounds.size.height - cornerInsets.bottomRight.height)),
+  };
+  const CGSize bottomLeft = {
+    MAX(0, MIN(cornerInsets.bottomLeft.width, bounds.size.width - cornerInsets.bottomRight.width)),
+    MAX(0, MIN(cornerInsets.bottomLeft.height, bounds.size.height - cornerInsets.topLeft.height)),
+  };
+  const CGSize bottomRight = {
+    MAX(0, MIN(cornerInsets.bottomRight.width, bounds.size.width - cornerInsets.bottomLeft.width)),
+    MAX(0, MIN(cornerInsets.bottomRight.height, bounds.size.height - cornerInsets.topRight.height)),
+  };
 
   CGMutablePathRef path = CGPathCreateMutable();
   RCTPathAddEllipticArc(path, transform, (CGPoint){
@@ -174,6 +186,7 @@ static CGContextRef RCTUIGraphicsBeginImageContext(CGSize size, CGColorRef backg
 }
 
 static UIImage *RCTGetSolidBorderImage(RCTCornerRadii cornerRadii,
+                                       CGSize viewSize,
                                        UIEdgeInsets borderInsets,
                                        RCTBorderColors borderColors,
                                        CGColorRef backgroundColor,
@@ -182,6 +195,16 @@ static CGContextRef RCTUIGraphicsBeginImageContext(CGSize size, CGColorRef backg
   const BOOL hasCornerRadii = RCTCornerRadiiAreAboveThreshold(cornerRadii);
   const RCTCornerInsets cornerInsets = RCTGetCornerInsets(cornerRadii, borderInsets);
 
+  const BOOL makeStretchable =
+  (borderInsets.left + cornerInsets.topLeft.width +
+   borderInsets.right + cornerInsets.bottomRight.width <= viewSize.width) &&
+  (borderInsets.left + cornerInsets.bottomLeft.width +
+   borderInsets.right + cornerInsets.topRight.width <= viewSize.width) &&
+  (borderInsets.top + cornerInsets.topLeft.height +
+   borderInsets.bottom + cornerInsets.bottomRight.height <= viewSize.height) &&
+  (borderInsets.top + cornerInsets.topRight.height +
+   borderInsets.bottom + cornerInsets.bottomLeft.height <= viewSize.height);
+
   const UIEdgeInsets edgeInsets = (UIEdgeInsets){
     borderInsets.top + MAX(cornerInsets.topLeft.height, cornerInsets.topRight.height),
     borderInsets.left + MAX(cornerInsets.topLeft.width, cornerInsets.bottomLeft.width),
@@ -189,11 +212,11 @@ static CGContextRef RCTUIGraphicsBeginImageContext(CGSize size, CGColorRef backg
     borderInsets.right + MAX(cornerInsets.bottomRight.width, cornerInsets.topRight.width)
   };
 
-  const CGSize size = (CGSize){
+  const CGSize size = makeStretchable ? (CGSize){
     // 1pt for the middle stretchable area along each axis
     edgeInsets.left + 1 + edgeInsets.right,
     edgeInsets.top + 1 + edgeInsets.bottom
-  };
+  } : viewSize;
 
   CGContextRef ctx = RCTUIGraphicsBeginImageContext(size, backgroundColor, hasCornerRadii, drawToEdge);
   const CGRect rect = {.size = size};
@@ -270,6 +293,8 @@ static CGContextRef RCTUIGraphicsBeginImageContext(CGSize size, CGColorRef backg
       }
     }
 
+    CGColorRef currentColor = NULL;
+
     // RIGHT
     if (borderInsets.right > 0) {
 
@@ -280,9 +305,8 @@ static CGContextRef RCTUIGraphicsBeginImageContext(CGSize size, CGColorRef backg
         (CGPoint){size.width, size.height},
       };
 
-      CGContextSetFillColorWithColor(ctx, borderColors.right);
+      currentColor = borderColors.right;
       CGContextAddLines(ctx, points, sizeof(points)/sizeof(*points));
-      CGContextFillPath(ctx);
     }
 
     // BOTTOM
@@ -295,9 +319,12 @@ static CGContextRef RCTUIGraphicsBeginImageContext(CGSize size, CGColorRef backg
         (CGPoint){size.width, size.height},
       };
 
-      CGContextSetFillColorWithColor(ctx, borderColors.bottom);
+      if (!CGColorEqualToColor(currentColor, borderColors.bottom)) {
+        CGContextSetFillColorWithColor(ctx, currentColor);
+        CGContextFillPath(ctx);
+        currentColor = borderColors.bottom;
+      }
       CGContextAddLines(ctx, points, sizeof(points)/sizeof(*points));
-      CGContextFillPath(ctx);
     }
 
     // LEFT
@@ -310,9 +337,12 @@ static CGContextRef RCTUIGraphicsBeginImageContext(CGSize size, CGColorRef backg
         (CGPoint){0, size.height},
       };
 
-      CGContextSetFillColorWithColor(ctx, borderColors.left);
+      if (!CGColorEqualToColor(currentColor, borderColors.left)) {
+        CGContextSetFillColorWithColor(ctx, currentColor);
+        CGContextFillPath(ctx);
+        currentColor = borderColors.left;
+      }
       CGContextAddLines(ctx, points, sizeof(points)/sizeof(*points));
-      CGContextFillPath(ctx);
     }
 
     // TOP
@@ -325,10 +355,16 @@ static CGContextRef RCTUIGraphicsBeginImageContext(CGSize size, CGColorRef backg
         (CGPoint){size.width, 0},
       };
 
-      CGContextSetFillColorWithColor(ctx, borderColors.top);
+      if (!CGColorEqualToColor(currentColor, borderColors.top)) {
+        CGContextSetFillColorWithColor(ctx, currentColor);
+        CGContextFillPath(ctx);
+        currentColor = borderColors.top;
+      }
       CGContextAddLines(ctx, points, sizeof(points)/sizeof(*points));
-      CGContextFillPath(ctx);
     }
+
+    CGContextSetFillColorWithColor(ctx, currentColor);
+    CGContextFillPath(ctx);
   }
 
   CGPathRelease(insetPath);
@@ -336,7 +372,11 @@ static CGContextRef RCTUIGraphicsBeginImageContext(CGSize size, CGColorRef backg
   UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
   UIGraphicsEndImageContext();
 
-  return [image resizableImageWithCapInsets:edgeInsets];
+  if (makeStretchable) {
+    image = [image resizableImageWithCapInsets:edgeInsets];
+  }
+
+  return image;
 }
 
 // Currently, the dashed / dotted implementation only supports a single colour +
@@ -469,7 +509,7 @@ static CGContextRef RCTUIGraphicsBeginImageContext(CGSize size, CGColorRef backg
 
   switch (borderStyle) {
     case RCTBorderStyleSolid:
-      return RCTGetSolidBorderImage(cornerRadii, borderInsets, borderColors, backgroundColor, drawToEdge);
+      return RCTGetSolidBorderImage(cornerRadii, viewSize, borderInsets, borderColors, backgroundColor, drawToEdge);
     case RCTBorderStyleDashed:
     case RCTBorderStyleDotted:
       return RCTGetDashedOrDottedBorderImage(borderStyle, cornerRadii, viewSize, borderInsets, borderColors, backgroundColor, drawToEdge);
diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m
index b2cd7a25083f..9b35bbe4fb03 100644
--- a/React/Views/RCTView.m
+++ b/React/Views/RCTView.m
@@ -477,15 +477,26 @@ - (UIEdgeInsets)bordersAsInsets
 
 - (RCTCornerRadii)cornerRadii
 {
-  const CGRect bounds = self.bounds;
-  const CGFloat maxRadius = MIN(bounds.size.height, bounds.size.width);
+  // Get corner radii
   const CGFloat radius = MAX(0, _borderRadius);
-
+  const CGFloat topLeftRadius = _borderTopLeftRadius >= 0 ? _borderTopLeftRadius : radius;
+  const CGFloat topRightRadius = _borderTopRightRadius >= 0 ? _borderTopRightRadius : radius;
+  const CGFloat bottomLeftRadius = _borderBottomLeftRadius >= 0 ? _borderBottomLeftRadius : radius;
+  const CGFloat bottomRightRadius = _borderBottomRightRadius >= 0 ? _borderBottomRightRadius : radius;
+
+  // Get scale factors required to prevent radii from overlapping
+  const CGSize size = self.bounds.size;
+  const CGFloat topScaleFactor = MIN(1, size.width / (topLeftRadius + topRightRadius));
+  const CGFloat bottomScaleFactor = MIN(1, size.width / (bottomLeftRadius + bottomRightRadius));
+  const CGFloat rightScaleFactor = MIN(1, size.height / (topRightRadius + bottomRightRadius));
+  const CGFloat leftScaleFactor = MIN(1, size.height / (topLeftRadius + bottomLeftRadius));
+
+  // Return scaled radii
   return (RCTCornerRadii){
-    MIN(_borderTopLeftRadius >= 0 ? _borderTopLeftRadius : radius, maxRadius),
-    MIN(_borderTopRightRadius >= 0 ? _borderTopRightRadius : radius, maxRadius),
-    MIN(_borderBottomLeftRadius >= 0 ? _borderBottomLeftRadius : radius, maxRadius),
-    MIN(_borderBottomRightRadius >= 0 ? _borderBottomRightRadius : radius, maxRadius),
+    topLeftRadius * MIN(topScaleFactor, leftScaleFactor),
+    topRightRadius * MIN(topScaleFactor, rightScaleFactor),
+    bottomLeftRadius * MIN(bottomScaleFactor, leftScaleFactor),
+    bottomRightRadius * MIN(bottomScaleFactor, rightScaleFactor),
   };
 }
 
@@ -501,6 +512,10 @@ - (RCTBorderColors)borderColors
 
 - (void)displayLayer:(CALayer *)layer
 {
+  if (CGSizeEqualToSize(layer.bounds.size, CGSizeZero)) {
+    return;
+  }
+
   const RCTCornerRadii cornerRadii = [self cornerRadii];
   const UIEdgeInsets borderInsets = [self bordersAsInsets];
   const RCTBorderColors borderColors = [self borderColors];

From 0fa1f8d94fde3305ae72eef6c3e6436d4b12da28 Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Thu, 7 Jan 2016 10:15:45 -0800
Subject: [PATCH 0668/1411] Fix extra native modules missing bridge after
 reload

Summary:
public

Since we don't actually recreate our native modules every time (will fix in follow-up), we'd never update the reference after reloading the bridge, and all navigation would fail.

Reviewed By: majak

Differential Revision: D2811406

fb-gh-sync-id: 4f4fd73bbdecfe510e1e1554668b2354181f22a8
---
 React/Base/RCTModuleData.m | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/React/Base/RCTModuleData.m b/React/Base/RCTModuleData.m
index d87edf430786..9d4b57539250 100644
--- a/React/Base/RCTModuleData.m
+++ b/React/Base/RCTModuleData.m
@@ -58,7 +58,7 @@ - (instancetype)initWithModuleInstance:(id<RCTBridgeModule>)instance
 - (void)setBridgeForInstance
 {
   RCTAssert(_instance, @"setBridgeForInstance called before %@ initialized", self.name);
-  if ([_instance respondsToSelector:@selector(bridge)] && !_instance.bridge) {
+  if ([_instance respondsToSelector:@selector(bridge)] && _instance.bridge != _bridge) {
     @try {
       [(id)_instance setValue:_bridge forKey:@"bridge"];
     }

From 473f9bca192a15e21946316a87b29001deccd5bf Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Thu, 7 Jan 2016 10:21:39 -0800
Subject: [PATCH 0669/1411] Update createView C function on profiler

Summary:
public

The props argument of the `-[RCTComponentData createView:props:]` method was removed,
but the C function used to swizzle it in the profiler wasn't updated.

Reviewed By: majak

Differential Revision: D2811228

fb-gh-sync-id: 8896638c77370142e29913b5fb80e7fd748254b5
---
 React/Profiler/RCTProfile.m | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/React/Profiler/RCTProfile.m b/React/Profiler/RCTProfile.m
index 60ea0b157b0e..8bcf2a56e3cf 100644
--- a/React/Profiler/RCTProfile.m
+++ b/React/Profiler/RCTProfile.m
@@ -35,8 +35,8 @@
 
 #pragma mark - Constants
 
-NSString const *RCTProfileTraceEvents = @"traceEvents";
-NSString const *RCTProfileSamples = @"samples";
+NSString *const RCTProfileTraceEvents = @"traceEvents";
+NSString *const RCTProfileSamples = @"samples";
 NSString *const RCTProfilePrefix = @"rct_profile_";
 
 #pragma mark - Variables
@@ -273,12 +273,12 @@ static void RCTProfileHookInstance(id instance)
   object_setClass(instance, proxyClass);
 }
 
-static UIView *(*originalCreateView)(RCTComponentData *, SEL, NSNumber *, NSDictionary *);
+static UIView *(*originalCreateView)(RCTComponentData *, SEL, NSNumber *);
 
-RCT_EXTERN UIView *RCTProfileCreateView(RCTComponentData *self, SEL _cmd, NSNumber *tag, NSDictionary *props);
-UIView *RCTProfileCreateView(RCTComponentData *self, SEL _cmd, NSNumber *tag, NSDictionary *props)
+RCT_EXTERN UIView *RCTProfileCreateView(RCTComponentData *self, SEL _cmd, NSNumber *tag);
+UIView *RCTProfileCreateView(RCTComponentData *self, SEL _cmd, NSNumber *tag)
 {
-  UIView *view = originalCreateView(self, _cmd, tag, props);
+  UIView *view = originalCreateView(self, _cmd, tag);
 
   RCTProfileHookInstance(view);
 

From b659d7f0d1a321a6a881ff96cb3a94665518a4d7 Mon Sep 17 00:00:00 2001
From: realaboo <realaboo@gmail.com>
Date: Thu, 7 Jan 2016 10:25:56 -0800
Subject: [PATCH 0670/1411] Get response url from XMLHttpRequest

Summary:
An HTTP request may be redirected to another URL, sometimes we need to know the URL where the  response comes from.

If the server is in control, we can add an HTTP header X-Request-URL for the redirect URL. However there will be cases that 3rd party services are used.

This PR retrieves the response URL from native networking module and passes to it XMLHttpRequest. The fetch API built on XMLHttpRequest also benefits from this feature.
Closes https://github.com/facebook/react-native/pull/4981

Reviewed By: svcscm

Differential Revision: D2811392

Pulled By: lexs

fb-gh-sync-id: 3ec356fb92f8011b6a243d6879172877a3dc498a
---
 Examples/UIExplorer/XHRExample.android.js     |   6 +
 Examples/UIExplorer/XHRExample.ios.js         |  68 +----------
 Examples/UIExplorer/XHRExampleFetch.js        | 112 ++++++++++++++++++
 Libraries/Network/RCTNetworking.m             |   3 +-
 Libraries/Network/XMLHttpRequestBase.js       |   9 +-
 .../modules/network/NetworkingModule.java     |   1 +
 6 files changed, 132 insertions(+), 67 deletions(-)
 create mode 100644 Examples/UIExplorer/XHRExampleFetch.js

diff --git a/Examples/UIExplorer/XHRExample.android.js b/Examples/UIExplorer/XHRExample.android.js
index 1dfb9a32cfe8..5a46d8dd9751 100644
--- a/Examples/UIExplorer/XHRExample.android.js
+++ b/Examples/UIExplorer/XHRExample.android.js
@@ -28,6 +28,7 @@ var {
 
 var XHRExampleHeaders = require('./XHRExampleHeaders');
 var XHRExampleCookies = require('./XHRExampleCookies');
+var XHRExampleFetch = require('./XHRExampleFetch');
 
 
 // TODO t7093728 This is a simplified XHRExample.ios.js.
@@ -281,6 +282,11 @@ exports.examples = [{
   render() {
     return <FormUploader/>;
   }
+}, {
+  title: 'Fetch Test',
+  render() {
+    return <XHRExampleFetch/>;
+  }
 }, {
   title: 'Headers',
   render() {
diff --git a/Examples/UIExplorer/XHRExample.ios.js b/Examples/UIExplorer/XHRExample.ios.js
index cc83ccf5837c..d8d370319aa8 100644
--- a/Examples/UIExplorer/XHRExample.ios.js
+++ b/Examples/UIExplorer/XHRExample.ios.js
@@ -31,6 +31,7 @@ var {
 } = React;
 
 var XHRExampleHeaders = require('./XHRExampleHeaders');
+var XHRExampleFetch = require('./XHRExampleFetch');
 
 class Downloader extends React.Component {
 
@@ -304,54 +305,6 @@ class FormUploader extends React.Component {
   }
 }
 
-class FetchTest extends React.Component {
-
-  constructor(props) {
-    super(props);
-    this.state = {
-     responseText: null,
-    };
-  }
-
-  submit(uri: String) {
-    fetch(uri).then((response) => {
-      return response.text();
-    }).then((body) => {
-      this.setState({responseText: body});
-    });
-  }
-
-  render() {
-
-    var response = this.state.responseText ? (
-      <View style={{marginTop: 10}}>
-        <Text style={styles.label}>Server response:</Text>
-        <TextInput
-          editable={false}
-          multiline={true}
-          defaultValue={this.state.responseText}
-          style={styles.textOutput}
-        />
-      </View>
-    ) : null;
-
-    return (
-      <View>
-        <Text style={styles.label}>Edit URL to submit:</Text>
-        <TextInput
-          returnKeyType="go"
-          defaultValue="http://www.posttestserver.com/post.php"
-          onSubmitEditing={(event)=> {
-            this.submit(event.nativeEvent.text);
-          }}
-          style={styles.textInput}
-        />
-        {response}
-      </View>
-    );
-  }
-}
-
 exports.framework = 'React';
 exports.title = 'XMLHttpRequest';
 exports.description = 'XMLHttpRequest';
@@ -366,9 +319,9 @@ exports.examples = [{
     return <FormUploader/>;
   }
 }, {
-  title: 'fetch test',
+  title: 'Fetch Test',
   render() {
-    return <FetchTest/>;
+    return <XHRExampleFetch/>;
   }
 }, {
   title: 'Headers',
@@ -432,19 +385,4 @@ var styles = StyleSheet.create({
     fontSize: 16,
     fontWeight: '500',
   },
-  label: {
-    flex: 1,
-    color: '#aaa',
-    fontWeight: '500',
-    height: 20,
-  },
-  textOutput: {
-    flex: 1,
-    fontSize: 17,
-    borderRadius: 3,
-    borderColor: 'grey',
-    borderWidth: 1,
-    height: 200,
-    paddingLeft: 8,
-  },
 });
diff --git a/Examples/UIExplorer/XHRExampleFetch.js b/Examples/UIExplorer/XHRExampleFetch.js
new file mode 100644
index 000000000000..893dd7591201
--- /dev/null
+++ b/Examples/UIExplorer/XHRExampleFetch.js
@@ -0,0 +1,112 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ *
+ * @flow
+ */
+'use strict';
+
+var React = require('react-native');
+var {
+  StyleSheet,
+  Text,
+  TextInput,
+  View,
+  Platform,
+} = React;
+
+
+class XHRExampleFetch extends React.Component {
+
+  constructor(props: any) {
+    super(props);
+    this.state = {
+     responseText: null,
+    };
+    this.responseURL = null;
+  }
+
+  submit(uri: String) {
+    fetch(uri).then((response) => {
+      this.responseURL = response.url;
+      return response.text();
+    }).then((body) => {
+      this.setState({responseText: body});
+    });
+  }
+
+  render() {
+
+    var responseURL = this.responseURL ? (
+      <View style={{marginTop: 10}}>
+        <Text style={styles.label}>Server response URL:</Text>
+        <Text>{this.responseURL}</Text>
+      </View>
+    ) : null;
+
+    var response = this.state.responseText ? (
+      <View style={{marginTop: 10}}>
+        <Text style={styles.label}>Server response:</Text>
+        <TextInput
+          editable={false}
+          multiline={true}
+          defaultValue={this.state.responseText}
+          style={styles.textOutput}
+        />
+      </View>
+    ) : null;
+
+    return (
+      <View>
+        <Text style={styles.label}>Edit URL to submit:</Text>
+        <TextInput
+          returnKeyType="go"
+          defaultValue="http://www.posttestserver.com/post.php"
+          onSubmitEditing={(event)=> {
+            this.submit(event.nativeEvent.text);
+          }}
+          style={styles.textInput}
+        />
+        {responseURL}
+        {response}
+      </View>
+    );
+  }
+}
+
+var styles = StyleSheet.create({
+  textInput: {
+    flex: 1,
+    borderRadius: 3,
+    borderColor: 'grey',
+    borderWidth: 1,
+    height: Platform.OS === 'android' ? 44 : 30,
+    paddingLeft: 8,
+  },
+  label: {
+    flex: 1,
+    color: '#aaa',
+    fontWeight: '500',
+    height: 20,
+  },
+  textOutput: {
+    flex: 1,
+    fontSize: 17,
+    borderRadius: 3,
+    borderColor: 'grey',
+    borderWidth: 1,
+    height: 200,
+    paddingLeft: 8,
+  },
+});
+
+module.exports = XHRExampleFetch;
diff --git a/Libraries/Network/RCTNetworking.m b/Libraries/Network/RCTNetworking.m
index 6bbea21b1f27..749541991002 100644
--- a/Libraries/Network/RCTNetworking.m
+++ b/Libraries/Network/RCTNetworking.m
@@ -375,7 +375,8 @@ - (void)sendRequest:(NSURLRequest *)request
         headers = response.MIMEType ? @{@"Content-Type": response.MIMEType} : @{};
         status = 200;
       }
-      NSArray<id> *responseJSON = @[task.requestID, @(status), headers];
+      id responseURL = response.URL ? response.URL.absoluteString : [NSNull null];
+      NSArray<id> *responseJSON = @[task.requestID, @(status), headers, responseURL];
       [_bridge.eventDispatcher sendDeviceEventWithName:@"didReceiveNetworkResponse"
                                                   body:responseJSON];
     });
diff --git a/Libraries/Network/XMLHttpRequestBase.js b/Libraries/Network/XMLHttpRequestBase.js
index 4cdc424721fb..f4c8bc5e246a 100644
--- a/Libraries/Network/XMLHttpRequestBase.js
+++ b/Libraries/Network/XMLHttpRequestBase.js
@@ -32,6 +32,7 @@ class XMLHttpRequestBase {
   responseHeaders: ?Object;
   responseText: ?string;
   status: number;
+  responseURL: ?string;
 
   upload: ?{
     onprogress?: (event: Object) => void;
@@ -69,6 +70,7 @@ class XMLHttpRequestBase {
     this.responseHeaders = undefined;
     this.responseText = '';
     this.status = 0;
+    delete this.responseURL;
 
     this._requestId = null;
 
@@ -110,11 +112,16 @@ class XMLHttpRequestBase {
     }
   }
 
-  _didReceiveResponse(requestId: number, status: number, responseHeaders: ?Object): void {
+  _didReceiveResponse(requestId: number, status: number, responseHeaders: ?Object, responseURL: ?string): void {
     if (requestId === this._requestId) {
       this.status = status;
       this.setResponseHeaders(responseHeaders);
       this.setReadyState(this.HEADERS_RECEIVED);
+      if (responseURL || responseURL === '') {
+        this.responseURL = responseURL;
+      } else {
+        delete this.responseURL;
+      }
     }
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
index 728acf7fe99f..d1f32616e6a4 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
@@ -289,6 +289,7 @@ private void onResponseReceived(int requestId, Response response) {
     args.pushInt(requestId);
     args.pushInt(response.code());
     args.pushMap(headers);
+    args.pushString(response.request().urlString());
 
     getEventEmitter().emit("didReceiveNetworkResponse", args);
   }

From b9c5f753aaac7b387e671e0df3cef4cc19c088f4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Thu, 7 Jan 2016 10:39:13 -0800
Subject: [PATCH 0671/1411] Fixes Hot Loading re-loading bug

Summary:
public

Fixes a terrible bug due to which when Hot Loading enabled when the user reloads we'll serve them the first `hot` bundle he requested. This happened because when HMR enabled we bailed out after sending the HMR updates and didn't rebuild any of the bundles the user requested before. As a consequence, when they reload we'd sent him the first and only one we ever built.

The fix is to tweak the hmr listener to return a promise. This way we can run the remaining code on the file change listener just after the HMR stuff finishes. We need to do it this way to avoid the remaining stuff to compete for CPU with the HMR one and give the best possible experience when HMR is enabled.

Reviewed By: davidaurelio

Differential Revision: D2811382

fb-gh-sync-id: 906932d71f35467485cf8a865a8d59f4d2ff41a0
---
 local-cli/server/util/attachHMRServer.js    |  6 +++---
 packager/react-packager/src/Server/index.js | 13 ++++++++++---
 2 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js
index a7244655b83a..56912e804fbb 100644
--- a/local-cli/server/util/attachHMRServer.js
+++ b/local-cli/server/util/attachHMRServer.js
@@ -108,10 +108,10 @@ function attachHMRServer({httpServer, path, packagerServer}) {
 
         packagerServer.setHMRFileChangeListener((filename, stat) => {
           if (!client) {
-            return;
+            return Promise.resolve();
           }
 
-          stat.then(() => {
+          return stat.then(() => {
             return packagerServer.getShallowDependencies(filename)
               .then(deps => {
                 if (!client) {
@@ -184,7 +184,7 @@ function attachHMRServer({httpServer, path, packagerServer}) {
             () => {
               // do nothing, file was removed
             },
-          ).done();
+          );
         });
 
         client.ws.on('error', e => {
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index a8d363e7220b..f5d284f2223a 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -180,16 +180,23 @@ class Server {
     this._fileWatcher.on('all', this._onFileChange.bind(this));
 
     this._debouncedFileChangeHandler = _.debounce(filePath => {
+      const onFileChange = () => {
+        this._rebuildBundles(filePath);
+        this._informChangeWatchers();
+      };
+
       // if Hot Loading is enabled avoid rebuilding bundles and sending live
       // updates. Instead, send the HMR updates right away and once that
       // finishes, invoke any other file change listener.
       if (this._hmrFileChangeListener) {
-        this._hmrFileChangeListener(filePath, this._bundler.stat(filePath));
+        this._hmrFileChangeListener(
+          filePath,
+          this._bundler.stat(filePath),
+        ).then(onFileChange).done();
         return;
       }
 
-      this._rebuildBundles(filePath);
-      this._informChangeWatchers();
+      onFileChange();
     }, 50);
   }
 

From e46736219cb7555df87afa8f32220ec1c86c5db6 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Thu, 7 Jan 2016 12:34:44 -0800
Subject: [PATCH 0672/1411] Tweak formatting in Android template

Reviewed By: mkonicek

Differential Revision:D2812482
Ninja: Doesn't affect any fb apps or code, purely for open source

fb-gh-sync-id: 4d190354112e3f002405686769dcc409e3394c3c
---
 .../generator-android/templates/package/MainActivity.java      | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/local-cli/generator-android/templates/package/MainActivity.java b/local-cli/generator-android/templates/package/MainActivity.java
index 33741846563b..6d5cb73f3021 100644
--- a/local-cli/generator-android/templates/package/MainActivity.java
+++ b/local-cli/generator-android/templates/package/MainActivity.java
@@ -34,6 +34,7 @@ protected boolean getUseDeveloperSupport() {
     @Override
     protected List<ReactPackage> getPackages() {
       return Arrays.<ReactPackage>asList(
-        new MainReactPackage());
+        new MainReactPackage()
+      );
     }
 }

From fe77ce1c62d6c6dc2a2eb6a3e532bbf39482b0d3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Thu, 7 Jan 2016 13:14:18 -0800
Subject: [PATCH 0673/1411] Show red boxes on HL mode

Summary:
public

We should further improve this on the future by showing the actual stacktrace instead of the `HMRClient` one. Also, we need to integrate this with the dev plugin that opens in the default editor the file/line the user clicks on.

Reviewed By: vjeux

Differential Revision: D2798889

fb-gh-sync-id: 2392966908c493e86e11b0d024e7b68156c9066c
---
 Libraries/Utilities/HMRClient.js         | 12 ++++++--
 local-cli/server/util/attachHMRServer.js | 36 ++++++++++++++++++++++++
 2 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/Libraries/Utilities/HMRClient.js b/Libraries/Utilities/HMRClient.js
index 0a29f53ab1a7..f500748d5139 100644
--- a/Libraries/Utilities/HMRClient.js
+++ b/Libraries/Utilities/HMRClient.js
@@ -48,8 +48,16 @@ URL: ${host}:${port}
 Error: ${e.message}`
       );
     };
-    activeWS.onmessage = (m) => {
-      eval(m.data); // eslint-disable-line no-eval
+    activeWS.onmessage = ({data}) => {
+      data = JSON.parse(data);
+      if (data.type === 'update') {
+        eval(data.body); // eslint-disable-line no-eval
+        return;
+      }
+
+      // TODO: add support for opening filename by clicking on the stacktrace
+      const error = data.body;
+      throw new Error(error.type + ' ' + error.description);
     };
   },
 };
diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js
index 56912e804fbb..5de18b977787 100644
--- a/local-cli/server/util/attachHMRServer.js
+++ b/local-cli/server/util/attachHMRServer.js
@@ -170,6 +170,42 @@ function attachHMRServer({httpServer, path, packagerServer}) {
                   modules: modulesToUpdate,
                 });
               })
+              .then(update => {
+                if (!client) {
+                  return;
+                }
+
+                // check we actually want to send an HMR update
+                if (update) {
+                  return JSON.stringify({
+                    type: 'update',
+                    body: update,
+                  });
+                }
+              })
+              .catch(error => {
+                // send errors to the client instead of killing packager server
+                let body;
+                if (error.type === 'TransformError' ||
+                    error.type === 'NotFoundError' ||
+                    error.type === 'UnableToResolveError') {
+                  body = {
+                    type: error.type,
+                    description: error.description,
+                    filename: error.filename,
+                    lineNumber: error.lineNumber,
+                  };
+                } else {
+                  console.error(error.stack || error);
+                  body = {
+                    type: 'InternalError',
+                    description: 'react-packager has encountered an internal error, ' +
+                      'please check your terminal error output for more details',
+                  };
+                }
+
+                return JSON.stringify({type: 'error', body});
+              })
               .then(bundle => {
                 if (!client) {
                   return;

From cc449b394e9cd3300343016a5d6a3c924823cd2b Mon Sep 17 00:00:00 2001
From: Andrei Coman <andreic@fb.com>
Date: Thu, 7 Jan 2016 13:39:27 -0800
Subject: [PATCH 0674/1411] Refactor text input keyboards

Reviewed By: foghina

Differential Revision: D2807491

fb-gh-sync-id: e7e5fb8c235f3637f619b2f44053749c51f379f0
---
 Libraries/Components/TextInput/TextInput.js   |  7 ++-
 .../uimanager/UIManagerModuleConstants.java   | 14 -----
 .../textinput/ReactTextInputManager.java      | 61 ++++++++++++-------
 3 files changed, 43 insertions(+), 39 deletions(-)

diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js
index 53bc6235d040..8d69fd589554 100644
--- a/Libraries/Components/TextInput/TextInput.js
+++ b/Libraries/Components/TextInput/TextInput.js
@@ -489,11 +489,12 @@ var TextInput = React.createClass({
       };
     }
 
-    var autoCapitalize = UIManager.UIText.AutocapitalizationType[this.props.autoCapitalize];
-    var textAlign =
-      UIManager.AndroidTextInput.Constants.TextAlign[this.props.textAlign];
+    var autoCapitalize =
+      UIManager.AndroidTextInput.Constants.AutoCapitalizationType[this.props.autoCapitalize];
+    var textAlign = UIManager.AndroidTextInput.Constants.TextAlign[this.props.textAlign];
     var textAlignVertical =
       UIManager.AndroidTextInput.Constants.TextAlignVertical[this.props.textAlignVertical];
+
     var children = this.props.children;
     var childCount = 0;
     ReactChildren.forEach(children, () => ++childCount);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java
index 3287ebf7854c..476a2673bf21 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java
@@ -92,20 +92,6 @@ public static Map<String, Object> getConstants(DisplayMetrics displayMetrics) {
                 "ScaleAspectFill",
                 ImageView.ScaleType.CENTER_CROP.ordinal())));
 
-    constants.put(
-        "UIText",
-        MapBuilder.of(
-            "AutocapitalizationType",
-            MapBuilder.of(
-                "none",
-                InputType.TYPE_CLASS_TEXT,
-                "characters",
-                InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS,
-                "words",
-                InputType.TYPE_TEXT_FLAG_CAP_WORDS,
-                "sentences",
-                InputType.TYPE_TEXT_FLAG_CAP_SENTENCES)));
-
     constants.put(
         "Dimensions",
         MapBuilder.of(
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
index 7df5f52a5728..ebb9a31bfc9a 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
@@ -16,6 +16,7 @@
 import android.graphics.PorterDuff;
 import android.os.SystemClock;
 import android.text.Editable;
+import android.text.InputFilter;
 import android.text.InputType;
 import android.text.Spannable;
 import android.text.TextWatcher;
@@ -25,10 +26,8 @@
 import android.view.View;
 import android.view.inputmethod.EditorInfo;
 import android.widget.TextView;
-import android.text.InputFilter;
 
 import com.facebook.infer.annotation.Assertions;
-import com.facebook.react.bridge.JSApplicationCausedNativeException;
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.common.MapBuilder;
@@ -55,6 +54,10 @@ public class ReactTextInputManager extends
   private static final int FOCUS_TEXT_INPUT = 1;
   private static final int BLUR_TEXT_INPUT = 2;
 
+  private static final int INPUT_TYPE_KEYBOARD_NUMBERED =
+      InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL |
+          InputType.TYPE_NUMBER_FLAG_SIGNED;
+
   private static final String KEYBOARD_TYPE_EMAIL_ADDRESS = "email-address";
   private static final String KEYBOARD_TYPE_NUMERIC = "numeric";
   private static final InputFilter[] EMPTY_FILTERS = new InputFilter[0];
@@ -253,43 +256,35 @@ public void setMultiline(ReactEditText view, boolean multiline) {
   public void setPassword(ReactEditText view, boolean password) {
     updateStagedInputTypeFlag(
         view,
-        password ? 0 : InputType.TYPE_TEXT_VARIATION_PASSWORD,
+        password ? 0 :
+            InputType.TYPE_NUMBER_VARIATION_PASSWORD | InputType.TYPE_TEXT_VARIATION_PASSWORD,
         password ? InputType.TYPE_TEXT_VARIATION_PASSWORD : 0);
+    checkPasswordType(view);
   }
 
-  @ReactProp(name = "autoCapitalize", defaultInt = InputType.TYPE_CLASS_TEXT)
+  @ReactProp(name = "autoCapitalize")
   public void setAutoCapitalize(ReactEditText view, int autoCapitalize) {
-    int flagsToSet = 0;
-    switch (autoCapitalize) {
-      case InputType.TYPE_TEXT_FLAG_CAP_SENTENCES:
-      case InputType.TYPE_TEXT_FLAG_CAP_WORDS:
-      case InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS:
-      case InputType.TYPE_CLASS_TEXT:
-        flagsToSet = autoCapitalize;
-        break;
-      default:
-        throw new
-            JSApplicationCausedNativeException("Invalid autoCapitalize value: " + autoCapitalize);
-    }
     updateStagedInputTypeFlag(
         view,
         InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_TEXT_FLAG_CAP_WORDS |
             InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS,
-        flagsToSet);
+        autoCapitalize);
   }
 
   @ReactProp(name = "keyboardType")
   public void setKeyboardType(ReactEditText view, @Nullable String keyboardType) {
-    int flagsToSet = 0;
+    int flagsToSet = InputType.TYPE_CLASS_TEXT;
     if (KEYBOARD_TYPE_NUMERIC.equalsIgnoreCase(keyboardType)) {
-      flagsToSet = InputType.TYPE_CLASS_NUMBER;
+      flagsToSet = INPUT_TYPE_KEYBOARD_NUMBERED;
     } else if (KEYBOARD_TYPE_EMAIL_ADDRESS.equalsIgnoreCase(keyboardType)) {
-      flagsToSet = InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
+      flagsToSet = InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS | InputType.TYPE_CLASS_TEXT;
     }
     updateStagedInputTypeFlag(
         view,
-        InputType.TYPE_CLASS_NUMBER | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS,
+        INPUT_TYPE_KEYBOARD_NUMBERED | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS |
+            InputType.TYPE_CLASS_TEXT,
         flagsToSet);
+    checkPasswordType(view);
   }
 
   @Override
@@ -298,6 +293,18 @@ protected void onAfterUpdateTransaction(ReactEditText view) {
     view.commitStagedInputType();
   }
 
+  // Sets the correct password type, since numeric and text passwords have different types
+  private static void checkPasswordType(ReactEditText view) {
+    if ((view.getStagedInputType() & INPUT_TYPE_KEYBOARD_NUMBERED) != 0 &&
+        (view.getStagedInputType() & InputType.TYPE_TEXT_VARIATION_PASSWORD) != 0) {
+      // Text input type is numbered password, remove text password variation, add numeric one
+      updateStagedInputTypeFlag(
+          view,
+          InputType.TYPE_TEXT_VARIATION_PASSWORD,
+          InputType.TYPE_NUMBER_VARIATION_PASSWORD);
+    }
+  }
+
   private static void updateStagedInputTypeFlag(
       ReactEditText view,
       int flagsToUnset,
@@ -473,6 +480,16 @@ public void onSelectionChanged(int start, int end) {
         MapBuilder.of(
             "top", Gravity.TOP,
             "center", Gravity.CENTER_VERTICAL,
-            "bottom", Gravity.BOTTOM));
+            "bottom", Gravity.BOTTOM),
+        "AutoCapitalizationType",
+        MapBuilder.of(
+            "none",
+            0,
+            "characters",
+            InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS,
+            "words",
+            InputType.TYPE_TEXT_FLAG_CAP_WORDS,
+            "sentences",
+            InputType.TYPE_TEXT_FLAG_CAP_SENTENCES));
   }
 }

From 47d0e3c2885aae83a53c8ce4a96dfe3818687873 Mon Sep 17 00:00:00 2001
From: olivier notteghem <oli@fb.com>
Date: Thu, 7 Jan 2016 18:17:34 -0800
Subject: [PATCH 0675/1411] introduce custom listview to be experimented in
 groups that fixes tail-fetch and improve skipped frame

Reviewed By: nspaun

Differential Revision: D2810265

fb-gh-sync-id: b5b312858f9096f82f14e2262d205d0580ac9e46
---
 .../ListView/THFeedListView.js                | 443 ++++++++++++++++++
 1 file changed, 443 insertions(+)
 create mode 100644 Libraries/CustomComponents/ListView/THFeedListView.js

diff --git a/Libraries/CustomComponents/ListView/THFeedListView.js b/Libraries/CustomComponents/ListView/THFeedListView.js
new file mode 100644
index 000000000000..e473a2e8e22a
--- /dev/null
+++ b/Libraries/CustomComponents/ListView/THFeedListView.js
@@ -0,0 +1,443 @@
+/**
+ * Copyright (c) 2015, Facebook, Inc.  All rights reserved.
+ *
+ * Facebook, Inc. ("Facebook") owns all right, title and interest, including
+ * all intellectual property and other proprietary rights, in and to the React
+ * Native CustomComponents software (the "Software").  Subject to your
+ * compliance with these terms, you are hereby granted a non-exclusive,
+ * worldwide, royalty-free copyright license to (1) use and copy the Software;
+ * and (2) reproduce and distribute the Software as part of your own software
+ * ("Your Software").  Facebook reserves all rights not expressly granted to
+ * you in this license agreement.
+ *
+ * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "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 FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
+ * EMPLOYEES 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 THE SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @providesModule THFeedListView
+ */
+'use strict';
+
+var ListViewDataSource = require('ListViewDataSource');
+var React = require('React');
+var RCTScrollViewManager = require('NativeModules').ScrollViewManager;
+var ScrollView = require('ScrollView');
+var ScrollResponder = require('ScrollResponder');
+var StaticRenderer = require('StaticRenderer');
+var TimerMixin = require('TimerMixin');
+
+var isEmpty = require('isEmpty');
+var logError = require('logError');
+var merge = require('merge');
+var performanceNow = require('performanceNow');
+
+var PropTypes = React.PropTypes;
+
+var DEFAULT_PAGE_SIZE = 1;
+var DEFAULT_INITIAL_ROWS = 10;
+var DEFAULT_END_REACHED_THRESHOLD = 1000;
+var DEFAULT_SCROLL_CALLBACK_THROTTLE = 50;
+var DEFAULT_TICK_FREQUENCY = 200;
+var DEFAULT_ROWS_YIELD_TIME = 100;
+var DEFAULT_END_SCROLL_TIMEOUT = 100;
+var SCROLLVIEW_REF = 'listviewscroll';
+
+/**
+ * Simpler version of `ListView`, optimized for smooth scrolling in feed. This is
+ * achieved by skipping unecessary processing caused by race condition (with paging
+ * and handling view resize callback) and, more importantly, handling heavier 
+ * computation (i.e rendering more rows, possibly fetching more data when end of 
+ * feed is reached) only once current scroll gesture completes. 
+ *
+ * Internally, listview uses an periodic tick callback that will render ahead each time
+ * additionl row(s), the number of which is controlled by `pageSize` props, until 
+ * no more rows are available in data source.
+ * 
+ */
+
+var THFeedListView = React.createClass({
+  mixins: [ScrollResponder.Mixin, TimerMixin],
+
+  statics: {
+    DataSource: ListViewDataSource,
+  },
+
+  /**
+   * You must provide a renderRow function. If you omit any of the other render
+   * functions, ListView will simply skip rendering them.
+   *
+   * - renderRow(rowData, sectionID, rowID, highlightRow);
+   */
+  propTypes: {
+    ...ScrollView.propTypes,
+
+    dataSource: PropTypes.instanceOf(ListViewDataSource).isRequired,
+    /**
+     * (sectionID, rowID, adjacentRowHighlighted) => renderable
+     *
+     * If provided, a renderable component to be rendered as the separator
+     * below each row but not the last row if there is a section header below.
+     * Take a sectionID and rowID of the row above and whether its adjacent row
+     * is highlighted.
+     */
+    renderSeparator: PropTypes.func,
+    /**
+     * (rowData, sectionID, rowID, highlightRow) => renderable
+     *
+     * Takes a data entry from the data source and its ids and should return
+     * a renderable component to be rendered as the row.  By default the data
+     * is exactly what was put into the data source, but it's also possible to
+     * provide custom extractors. ListView can be notified when a row is
+     * being highlighted by calling highlightRow function. The separators above and
+     * below will be hidden when a row is highlighted. The highlighted state of
+     * a row can be reset by calling highlightRow(null).
+     */
+    renderRow: PropTypes.func.isRequired,
+    /**
+     * How many rows to render on initial component mount.  Use this to make
+     * it so that the first screen worth of data appears at one time instead of
+     * over the course of multiple frames.
+     */
+    initialListSize: PropTypes.number,
+    /**
+     * Called when all rows have been rendered and the list has been scrolled
+     * to within onEndReachedThreshold of the bottom.  The native scroll
+     * event is provided.
+     */
+    onEndReached: PropTypes.func,
+    /**
+     * Threshold in pixels for onEndReached.
+     */
+    onEndReachedThreshold: PropTypes.number,
+    /**
+     * Number of rows to render per event loop.
+     */
+    pageSize: PropTypes.number,
+    /**
+     * () => renderable
+     *
+     * The header and footer are always rendered (if these props are provided)
+     * on every render pass.  If they are expensive to re-render, wrap them
+     * in StaticContainer or other mechanism as appropriate.  Footer is always
+     * at the bottom of the list, and header at the top, on every render pass.
+     */
+    renderFooter: PropTypes.func,
+    renderHeader: PropTypes.func,
+    /**
+     * (props) => renderable
+     *
+     * A function that returns the scrollable component in which the list rows
+     * are rendered. Defaults to returning a ScrollView with the given props.
+     */
+    renderScrollComponent: React.PropTypes.func.isRequired,
+    /**
+     * (visibleRows, changedRows) => void
+     *
+     * Called when the set of visible rows changes.  `visibleRows` maps
+     * { sectionID: { rowID: true }} for all the visible rows, and
+     * `changedRows` maps { sectionID: { rowID: true | false }} for the rows
+     * that have changed their visibility, with true indicating visible, and
+     * false indicating the view has moved out of view.
+     */
+    onChangeVisibleRows: React.PropTypes.func,
+    /**
+     * A performance optimization for improving scroll perf of
+     * large lists, used in conjunction with overflow: 'hidden' on the row
+     * containers.  This is enabled by default.
+     */
+    removeClippedSubviews: React.PropTypes.bool,
+  },
+
+  /**
+   * Exports some data, e.g. for perf investigations or analytics.
+   */
+  getMetrics: function() {
+    return {
+      contentLength: this._scrollProperties.contentLength,
+      totalRows: this.props.dataSource.getRowCount(),
+      renderedRows: this.state.curRenderedRowsCount,
+      visibleRows: Object.keys(this._visibleRows).length,
+    };
+  },
+
+  /**
+   * Provides a handle to the underlying scroll responder to support operations
+   * such as scrollTo.
+   */
+  getScrollResponder: function() {
+    return this.refs[SCROLLVIEW_REF] &&
+      this.refs[SCROLLVIEW_REF].getScrollResponder &&
+      this.refs[SCROLLVIEW_REF].getScrollResponder();
+  },
+
+  getInnerViewNode: function() {
+    return this.refs[SCROLLVIEW_REF] &&
+      this.refs[SCROLLVIEW_REF].getInnerViewNode();
+  },
+
+  setNativeProps: function(props) {
+    this.refs[SCROLLVIEW_REF] && 
+      this.refs[SCROLLVIEW_REF].setNativeProps(props);
+  },
+
+  scrollTo: function(destY, destX) {
+    this.getScrollResponder().scrollResponderScrollTo(destX || 0, destY || 0);
+  },
+
+  /**
+   * React life cycle hooks.
+   */
+
+  getDefaultProps: function() {
+    return {
+      initialListSize: DEFAULT_INITIAL_ROWS,
+      pageSize: DEFAULT_PAGE_SIZE,
+      onEndReachedThreshold: DEFAULT_END_REACHED_THRESHOLD,
+    };
+  },
+
+  getInitialState: function() {
+    return {
+      curRenderedRowsCount: this.props.initialListSize,
+      highlightedRow: {},
+    };
+  },
+
+  componentWillMount: function() {
+    // this data should never trigger a render pass, so don't put in state
+    this._scrollProperties = {
+      visibleLength: null,
+      contentLength: null,
+      offset: 0
+    };
+    this._childFrames = [];
+    this._visibleRows = {};
+    this._prevRenderedRowsCount = 0;
+    this._lastEndReachedContentLength = null;
+    this._lastScrollEventTime = 0; // TODO(9622421): use native scroll events when available
+    this._lastUpdateEventTime = 0;
+  },
+
+  componentDidMount: function() {
+    // potentially trigger fetching additional data as soon as possible.
+    this._callOnEndReachedIfNeeded();
+
+    // schedule periodic check to check if we have more rows to render or need to feth more rows
+    this.setInterval(this.onTick, DEFAULT_TICK_FREQUENCY);
+  },
+
+  componentWillReceiveProps: function(nextProps) {
+    if (this.props.dataSource !== nextProps.dataSource) {
+      this._prevRenderedRowsCount = 0;
+    }
+    if (this.props.initialListSize !== nextProps.initialListSize) {
+      this.setState((state, props) => {
+        return {
+          curRenderedRowsCount: Math.max(
+            state.curRenderedRowsCount,
+            props.initialListSize
+          ),
+        };
+      });
+    }
+  },
+
+  componentDidUpdate: function () {
+    this._lastUpdateEventTime = performanceNow();
+  },
+
+  onRowHighlighted: function(sectionID, rowID) {
+    this.setState({highlightedRow: {sectionID, rowID}});
+  },
+
+  onTick: function() {
+    if (!this.isMounted()) {
+      return;
+    }
+    if (performanceNow() < this._lastScrollEventTime + DEFAULT_END_SCROLL_TIMEOUT) {
+      // listview is currently scrolling, skip any work until scroll completes
+      return;
+    }
+    if (performanceNow() < this._lastUpdateEventTime + DEFAULT_ROWS_YIELD_TIME) {
+      // ensure at least enough time has elapsed between 2 row rendering
+      return;
+    }
+    this._callOnEndReachedIfNeeded();
+    this._renderMoreRowsIfAvailable();
+  },
+
+  render: function() {
+    var dataSource = this.props.dataSource;
+    var allRowIDs = dataSource.rowIdentities;
+    var rowCount = 0;
+    var header = this.props.renderHeader && this.props.renderHeader();
+    var footer = this.props.renderFooter && this.props.renderFooter();
+    var totalIndex = header ? 1 : 0;
+
+    var bodyComponents = [];
+    for (var sectionIdx = 0; sectionIdx < allRowIDs.length; sectionIdx++) {
+      var sectionID = dataSource.sectionIdentities[sectionIdx];
+      var rowIDs = allRowIDs[sectionIdx];
+      if (rowIDs.length === 0) {
+        continue;
+      }
+
+      for (var rowIdx = 0; rowIdx < rowIDs.length; rowIdx++) {
+        var rowID = rowIDs[rowIdx];
+        var comboID = sectionID + '_' + rowID;
+        var shouldUpdateRow = rowCount >= this._prevRenderedRowsCount &&
+          dataSource.rowShouldUpdate(sectionIdx, rowIdx);
+        var row =
+          <StaticRenderer
+            key={'r_' + comboID}
+            shouldUpdate={!!shouldUpdateRow}
+            render={this.props.renderRow.bind(
+              null,
+              dataSource.getRowData(sectionIdx, rowIdx),
+              sectionID,
+              rowID,
+              this.onRowHighlighted
+            )}
+          />;
+        bodyComponents.push(row);
+        totalIndex++;
+
+        if (this.props.renderSeparator &&
+            (rowIdx !== rowIDs.length - 1 || sectionIdx === allRowIDs.length - 1)) {
+          var adjacentRowHighlighted =
+            this.state.highlightedRow.sectionID === sectionID && (
+              this.state.highlightedRow.rowID === rowID ||
+              this.state.highlightedRow.rowID === rowIDs[rowIdx + 1]
+            );
+          var separator = this.props.renderSeparator(
+            sectionID,
+            rowID,
+            adjacentRowHighlighted
+          );
+          bodyComponents.push(separator);
+          totalIndex++;
+        }
+        if (++rowCount === this.state.curRenderedRowsCount) {
+          break;
+        }
+      }
+      if (rowCount >= this.state.curRenderedRowsCount) {
+        break;
+      }
+    }
+
+    var {
+      renderScrollComponent,
+      ...props,
+    } = this.props;
+    if (!props.scrollEventThrottle) {
+      props.scrollEventThrottle = DEFAULT_SCROLL_CALLBACK_THROTTLE;
+    }
+    if (props.removeClippedSubviews === undefined) {
+      props.removeClippedSubviews = true;
+    }
+    Object.assign(props, {
+      onScroll: this._onScroll,
+
+      // Do not pass these events downstream to ScrollView since they will be
+      // registered in ListView's own ScrollResponder.Mixin
+      onKeyboardWillShow: undefined,
+      onKeyboardWillHide: undefined,
+      onKeyboardDidShow: undefined,
+      onKeyboardDidHide: undefined,
+    });
+
+    // TODO(ide): Use function refs so we can compose with the scroll
+    // component's original ref instead of clobbering it
+    return React.cloneElement(renderScrollComponent(props), {
+      ref: SCROLLVIEW_REF,
+      onContentSizeChange: this._onContentSizeChange,
+      onLayout: this._onLayout,
+    }, header, bodyComponents, footer);
+  },
+
+  /**
+   * Private methods
+   */
+
+  _onContentSizeChange: function(width, height) {
+    var contentLength = !this.props.horizontal ? height : width;
+    this._scrollProperties.contentLength = contentLength;
+    this.props.onContentSizeChange && this.props.onContentSizeChange(width, height);
+  },
+
+  _onLayout: function(event) {
+    var {width, height} = event.nativeEvent.layout;
+    var visibleLength = !this.props.horizontal ? height : width;
+    this._scrollProperties.visibleLength = visibleLength;
+    this.props.onLayout && this.props.onLayout(event);
+  },
+
+  _onScroll: function(e) {
+    var data = e.nativeEvent;
+    var isVertical = !this.props.horizontal;
+    this._scrollProperties.visibleLength = data.layoutMeasurement[isVertical ? 'height' : 'width'];
+    this._scrollProperties.contentLength = data.contentSize[isVertical ? 'height' : 'width'];
+    this._scrollProperties.offset = data.contentOffset[isVertical ? 'y' : 'x'];
+    this._lastScrollEventTime = performanceNow();
+    this.props.onScroll && this.props.onScroll(e);
+  },
+
+  _callOnEndReachedIfNeeded: function() {
+    if (!this.props.onEndReached) {
+      // skip any processing if parent not interested in end of feed callbacks
+      return;
+    }
+    if (this._getDistanceFromEnd() > this.props.onEndReachedThreshold) {
+      // Scrolled out of the end zone, so it should be able to trigger again.
+      this._lastEndReachedContentLength = null;
+      return;
+    }
+    if (this.state.curRenderedRowsCount !== this.props.dataSource.getRowCount()) {
+      // we have more rows to render, so we haven't reached end of feed
+      return;
+    }
+    if (this._scrollProperties.contentLength && 
+        this._scrollProperties.contentLength === this._lastEndReachedContentLength) {
+      // we have already invoked end of feed callback for this given position in feed
+      return;
+    }
+    this._lastEndReachedContentLength = this._scrollProperties.contentLength;
+    this.props.onEndReached();
+  },
+
+  _renderMoreRowsIfAvailable: function() {
+    if (this.state.curRenderedRowsCount !== this.props.dataSource.getRowCount()) {
+      this.setState((state, props) => {
+        var curRenderedRowsCount = Math.min(
+          state.curRenderedRowsCount + props.pageSize,
+          props.dataSource.getRowCount()
+        );
+        this._prevRenderedRowsCount = state.curRenderedRowsCount;
+        return {curRenderedRowsCount};
+      }, () => {
+        this._prevRenderedRowsCount = this.state.curRenderedRowsCount;
+      });
+    }
+  },
+
+  _getDistanceFromEnd: function() {
+    var scrollProperties = this._scrollProperties;
+    var maxLength = Math.max(
+      scrollProperties.contentLength,
+      scrollProperties.visibleLength
+    );
+    return maxLength - scrollProperties.visibleLength - scrollProperties.offset;
+  },
+
+});
+
+module.exports = THFeedListView;

From 648364594c5b289a895ab5479fe83e8ba8308f82 Mon Sep 17 00:00:00 2001
From: Aaron Chiu <aaronechiu@fb.com>
Date: Fri, 8 Jan 2016 00:47:44 -0800
Subject: [PATCH 0676/1411] Don't create DevSupportManager when not in Dev mode

Summary:
public

1. fixes I/O on UI Thread diffusion/FA/browse/master/java/com/facebook/catalyst/js/react-native-github/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java;e6819b923967f9380dd6c10bfa8f1f40be558e2f$149 in prod builds
2. Less calls to Choreographer (i.e. https://fburl.com/188102408 in AutoProfiler) ==> better newsfeed scroll perf
3. Lower Memory footprint in prod

Reviewed By: astreet

Differential Revision: D2759498

fb-gh-sync-id: 4f593ba9219febb7045f4e470a14995e995ebbb1
---
 .../react/ReactInstanceManagerImpl.java       |  20 +-
 ...faultNativeModuleCallExceptionHandler.java |  27 +
 .../react/devsupport/DevSupportManager.java   | 710 +----------------
 .../devsupport/DevSupportManagerImpl.java     | 722 ++++++++++++++++++
 .../devsupport/DisabledDevSupportManager.java | 116 +++
 5 files changed, 899 insertions(+), 696 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/DefaultNativeModuleCallExceptionHandler.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/devsupport/DisabledDevSupportManager.java

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index c9bf17c610ce..adb039d7ffee 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -52,6 +52,8 @@
 import com.facebook.react.common.annotations.VisibleForTesting;
 import com.facebook.react.devsupport.DevServerHelper;
 import com.facebook.react.devsupport.DevSupportManager;
+import com.facebook.react.devsupport.DevSupportManagerImpl;
+import com.facebook.react.devsupport.DisabledDevSupportManager;
 import com.facebook.react.devsupport.ReactInstanceDevCommandsHandler;
 import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
 import com.facebook.react.modules.core.DeviceEventManagerModule;
@@ -252,15 +254,15 @@ public T get() throws Exception {
     mJSMainModuleName = jsMainModuleName;
     mPackages = packages;
     mUseDeveloperSupport = useDeveloperSupport;
-    // We need to instantiate DevSupportManager regardless to the useDeveloperSupport option,
-    // although will prevent dev support manager from displaying any options or dialogs by
-    // checking useDeveloperSupport option before calling setDevSupportEnabled on this manager
-    // TODO(6803830): Don't instantiate devsupport manager when useDeveloperSupport is false
-    mDevSupportManager = new DevSupportManager(
-        applicationContext,
-        mDevInterface,
-        mJSMainModuleName,
-        useDeveloperSupport);
+    if (mUseDeveloperSupport) {
+      mDevSupportManager = new DevSupportManagerImpl(
+          applicationContext,
+          mDevInterface,
+          mJSMainModuleName,
+          useDeveloperSupport);
+    } else {
+      mDevSupportManager = new DisabledDevSupportManager();
+    }
     mBridgeIdleDebugListener = bridgeIdleDebugListener;
     mLifecycleState = initialLifecycleState;
     mUIImplementationProvider = uiImplementationProvider;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/DefaultNativeModuleCallExceptionHandler.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/DefaultNativeModuleCallExceptionHandler.java
new file mode 100644
index 000000000000..4d47156c7479
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/DefaultNativeModuleCallExceptionHandler.java
@@ -0,0 +1,27 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.bridge;
+
+/**
+ * Crashy crashy exception handler.
+ */
+public class DefaultNativeModuleCallExceptionHandler implements NativeModuleCallExceptionHandler {
+
+  @Override
+  public void handleException(Exception e) {
+    if (e instanceof RuntimeException) {
+      // Because we are rethrowing the original exception, the original stacktrace will be
+      // preserved.
+      throw (RuntimeException) e;
+    } else {
+      throw new RuntimeException(e);
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
index cf86bd3b3547..4f114ded6099 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
@@ -9,698 +9,34 @@
 
 package com.facebook.react.devsupport;
 
-import javax.annotation.Nullable;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.LinkedHashMap;
-import java.util.Locale;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import android.app.AlertDialog;
-import android.app.ProgressDialog;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.hardware.SensorManager;
-import android.os.Debug;
-import android.os.Environment;
-import android.view.WindowManager;
-import android.widget.Toast;
-
-import com.facebook.common.logging.FLog;
-import com.facebook.infer.annotation.Assertions;
-import com.facebook.react.R;
-import com.facebook.react.bridge.CatalystInstance;
-import com.facebook.react.bridge.JavaJSExecutor;
 import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReadableArray;
-import com.facebook.react.bridge.UiThreadUtil;
-import com.facebook.react.bridge.WebsocketJavaScriptExecutor;
-import com.facebook.react.common.ReactConstants;
-import com.facebook.react.common.ShakeDetector;
-import com.facebook.react.common.futures.SimpleSettableFuture;
-import com.facebook.react.devsupport.StackTraceHelper.StackFrame;
 import com.facebook.react.modules.debug.DeveloperSettings;
 
 /**
- * Interface for accessing and interacting with development features. Following features
- * are supported through this manager class:
- * 1) Displaying JS errors (aka RedBox)
- * 2) Displaying developers menu (Reload JS, Debug JS)
- * 3) Communication with developer server in order to download updated JS bundle
- * 4) Starting/stopping broadcast receiver for js reload signals
- * 5) Starting/stopping motion sensor listener that recognize shake gestures which in turn may
- *    trigger developers menu.
- * 6) Launching developers settings view
- *
- * This class automatically monitors the state of registered views and activities to which they are
- * bound to make sure that we don't display overlay or that we we don't listen for sensor events
- * when app is backgrounded.
- *
- * {@link ReactInstanceDevCommandsHandler} implementation is responsible for instantiating this
- * instance and for populating with an instance of {@link CatalystInstance} whenever instance
- * manager recreates it (through {@link #onNewCatalystContextCreated}). Also, instance manager is
- * responsible for enabling/disabling dev support in case when app is backgrounded or when all the
- * views has been detached from the instance (through {@link #setDevSupportEnabled} method).
- *
- * IMPORTANT: In order for developer support to work correctly it is required that the
- * manifest of your application contain the following entries:
- * {@code <activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>}
- * {@code <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>}
+ * Interface for accessing and interacting with development features.
+ * In dev mode, use the implementation {@link DevSupportManagerImpl}.
+ * In production mode, use the dummy implementation {@link DisabledDevSupportManager}.
  */
-public class DevSupportManager implements NativeModuleCallExceptionHandler {
-
-  private static final int JAVA_ERROR_COOKIE = -1;
-  private static final String JS_BUNDLE_FILE_NAME = "ReactNativeDevBundle.js";
-
-  private static final String EXOPACKAGE_LOCATION_FORMAT
-      = "/data/local/tmp/exopackage/%s//secondary-dex";
-
-  private static final int JAVA_SAMPLING_PROFILE_MEMORY_BYTES = 8 * 1024 * 1024;
-  private static final int JAVA_SAMPLING_PROFILE_DELTA_US = 100;
-
-  private final Context mApplicationContext;
-  private final ShakeDetector mShakeDetector;
-  private final BroadcastReceiver mReloadAppBroadcastReceiver;
-  private final DevServerHelper mDevServerHelper;
-  private final LinkedHashMap<String, DevOptionHandler> mCustomDevOptions =
-      new LinkedHashMap<>();
-  private final ReactInstanceDevCommandsHandler mReactInstanceCommandsHandler;
-  private final @Nullable String mJSAppBundleName;
-  private final File mJSBundleTempFile;
-
-  private @Nullable RedBoxDialog mRedBoxDialog;
-  private @Nullable AlertDialog mDevOptionsDialog;
-  private @Nullable DebugOverlayController mDebugOverlayController;
-  private @Nullable ReactContext mCurrentContext;
-  private DevInternalSettings mDevSettings;
-  private boolean mIsUsingJSProxy = false;
-  private boolean mIsReceiverRegistered = false;
-  private boolean mIsShakeDetectorStarted = false;
-  private boolean mIsDevSupportEnabled = false;
-  private boolean mIsCurrentlyProfiling = false;
-  private int     mProfileIndex = 0;
-
-  public DevSupportManager(
-      Context applicationContext,
-      ReactInstanceDevCommandsHandler reactInstanceCommandsHandler,
-      @Nullable String packagerPathForJSBundleName,
-      boolean enableOnCreate) {
-    mReactInstanceCommandsHandler = reactInstanceCommandsHandler;
-    mApplicationContext = applicationContext;
-    mJSAppBundleName = packagerPathForJSBundleName;
-    mDevSettings = new DevInternalSettings(applicationContext, this);
-    mDevServerHelper = new DevServerHelper(mDevSettings);
-
-    // Prepare shake gesture detector (will be started/stopped from #reload)
-    mShakeDetector = new ShakeDetector(new ShakeDetector.ShakeListener() {
-      @Override
-      public void onShake() {
-        showDevOptionsDialog();
-      }
-    });
-
-    // Prepare reload APP broadcast receiver (will be registered/unregistered from #reload)
-    mReloadAppBroadcastReceiver = new BroadcastReceiver() {
-      @Override
-      public void onReceive(Context context, Intent intent) {
-        String action = intent.getAction();
-        if (DevServerHelper.getReloadAppAction(context).equals(action)) {
-          if (intent.getBooleanExtra(DevServerHelper.RELOAD_APP_EXTRA_JS_PROXY, false)) {
-            mIsUsingJSProxy = true;
-            mDevServerHelper.launchChromeDevtools();
-          } else {
-            mIsUsingJSProxy = false;
-          }
-          handleReloadJS();
-        }
-      }
-    };
-
-    // We store JS bundle loaded from dev server in a single destination in app's data dir.
-    // In case when someone schedule 2 subsequent reloads it may happen that JS thread will
-    // start reading first reload output while the second reload starts writing to the same
-    // file. As this should only be the case in dev mode we leave it as it is.
-    // TODO(6418010): Fix readers-writers problem in debug reload from HTTP server
-    mJSBundleTempFile = new File(applicationContext.getFilesDir(), JS_BUNDLE_FILE_NAME);
-
-    setDevSupportEnabled(enableOnCreate);
-  }
-
-  @Override
-  public void handleException(Exception e) {
-    if (mIsDevSupportEnabled) {
-      FLog.e(ReactConstants.TAG, "Exception in native call from JS", e);
-      showNewJavaError(e.getMessage(), e);
-    } else {
-      if (e instanceof RuntimeException) {
-        // Because we are rethrowing the original exception, the original stacktrace will be
-        // preserved
-        throw (RuntimeException) e;
-      } else {
-        throw new RuntimeException(e);
-      }
-    }
-  }
-
-  public void showNewJavaError(String message, Throwable e) {
-    showNewError(message, StackTraceHelper.convertJavaStackTrace(e), JAVA_ERROR_COOKIE);
-  }
-
-  /**
-   * Add option item to dev settings dialog displayed by this manager. In the case user select given
-   * option from that dialog, the appropriate handler passed as {@param optionHandler} will be
-   * called.
-   */
-  public void addCustomDevOption(
-      String optionName,
-      DevOptionHandler optionHandler) {
-    mCustomDevOptions.put(optionName, optionHandler);
-  }
-
-  public void showNewJSError(String message, ReadableArray details, int errorCookie) {
-    showNewError(message, StackTraceHelper.convertJsStackTrace(details), errorCookie);
-  }
-
-  public void updateJSError(
-      final String message,
-      final ReadableArray details,
-      final int errorCookie) {
-    UiThreadUtil.runOnUiThread(
-        new Runnable() {
-          @Override
-          public void run() {
-            // Since we only show the first JS error in a succession of JS errors, make sure we only
-            // update the error message for that error message. This assumes that updateJSError
-            // belongs to the most recent showNewJSError
-            if (mRedBoxDialog == null ||
-                !mRedBoxDialog.isShowing() ||
-                errorCookie != mRedBoxDialog.getErrorCookie()) {
-              return;
-            }
-            mRedBoxDialog.setExceptionDetails(
-                message,
-                StackTraceHelper.convertJsStackTrace(details));
-            mRedBoxDialog.show();
-          }
-        });
-  }
-
-  private void showNewError(
-      final String message,
-      final StackFrame[] stack,
-      final int errorCookie) {
-    UiThreadUtil.runOnUiThread(
-        new Runnable() {
-          @Override
-          public void run() {
-            if (mRedBoxDialog == null) {
-              mRedBoxDialog = new RedBoxDialog(mApplicationContext, DevSupportManager.this);
-              mRedBoxDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
-            }
-            if (mRedBoxDialog.isShowing()) {
-              // Sometimes errors cause multiple errors to be thrown in JS in quick succession. Only
-              // show the first and most actionable one.
-              return;
-            }
-            mRedBoxDialog.setExceptionDetails(message, stack);
-            mRedBoxDialog.setErrorCookie(errorCookie);
-            mRedBoxDialog.show();
-          }
-        });
-  }
-
-  public void showDevOptionsDialog() {
-    if (mDevOptionsDialog != null || !mIsDevSupportEnabled) {
-      return;
-    }
-    LinkedHashMap<String, DevOptionHandler> options = new LinkedHashMap<>();
-    /* register standard options */
-    options.put(
-        mApplicationContext.getString(R.string.catalyst_reloadjs), new DevOptionHandler() {
-          @Override
-          public void onOptionSelected() {
-            handleReloadJS();
-          }
-        });
-    options.put(
-        mIsUsingJSProxy ?
-            mApplicationContext.getString(R.string.catalyst_debugjs_off) :
-            mApplicationContext.getString(R.string.catalyst_debugjs),
-        new DevOptionHandler() {
-          @Override
-          public void onOptionSelected() {
-            mIsUsingJSProxy = !mIsUsingJSProxy;
-            handleReloadJS();
-          }
-        });
-    options.put(
-            mDevSettings.isHotModuleReplacementEnabled()
-                    ? mApplicationContext.getString(R.string.catalyst_hot_module_replacement_off)
-                    : mApplicationContext.getString(R.string.catalyst_hot_module_replacement),
-            new DevOptionHandler() {
-              @Override
-              public void onOptionSelected() {
-                mDevSettings.setHotModuleReplacementEnabled(!mDevSettings.isHotModuleReplacementEnabled());
-                handleReloadJS();
-              }
-            });
-    options.put(
-        mDevSettings.isReloadOnJSChangeEnabled()
-            ? mApplicationContext.getString(R.string.catalyst_live_reload_off)
-            : mApplicationContext.getString(R.string.catalyst_live_reload),
-        new DevOptionHandler() {
-          @Override
-          public void onOptionSelected() {
-            mDevSettings.setReloadOnJSChangeEnabled(!mDevSettings.isReloadOnJSChangeEnabled());
-          }
-        });
-    options.put(
-        mDevSettings.isElementInspectorEnabled()
-          ? mApplicationContext.getString(R.string.catalyst_element_inspector_off)
-          : mApplicationContext.getString(R.string.catalyst_element_inspector),
-        new DevOptionHandler() {
-          @Override
-          public void onOptionSelected() {
-            mDevSettings.setElementInspectorEnabled(!mDevSettings.isElementInspectorEnabled());
-            mReactInstanceCommandsHandler.toggleElementInspector();
-          }
-        });
-    options.put(
-        mDevSettings.isFpsDebugEnabled()
-            ? mApplicationContext.getString(R.string.catalyst_perf_monitor_off)
-            : mApplicationContext.getString(R.string.catalyst_perf_monitor),
-        new DevOptionHandler() {
-          @Override
-          public void onOptionSelected() {
-            mDevSettings.setFpsDebugEnabled(!mDevSettings.isFpsDebugEnabled());
-          }
-        });
-    if (mCurrentContext != null &&
-        mCurrentContext.getCatalystInstance() != null &&
-        !mCurrentContext.getCatalystInstance().isDestroyed() &&
-        mCurrentContext.getCatalystInstance().supportsProfiling()) {
-      options.put(
-          mApplicationContext.getString(
-              mIsCurrentlyProfiling ? R.string.catalyst_stop_profile :
-                  R.string.catalyst_start_profile),
-          new DevOptionHandler() {
-            @Override
-            public void onOptionSelected() {
-              if (mCurrentContext != null && mCurrentContext.hasActiveCatalystInstance()) {
-                String profileName = (Environment.getExternalStorageDirectory().getPath() +
-                    "/profile_" + mProfileIndex + ".json");
-                if (mIsCurrentlyProfiling) {
-                  mIsCurrentlyProfiling = false;
-                  mProfileIndex++;
-                  Debug.stopMethodTracing();
-                  mCurrentContext.getCatalystInstance()
-                      .stopProfiler("profile", profileName);
-                  Toast.makeText(
-                      mCurrentContext,
-                      "Profile output to " + profileName,
-                      Toast.LENGTH_LONG).show();
-                } else {
-                  mIsCurrentlyProfiling = true;
-                  mCurrentContext.getCatalystInstance().startProfiler("profile");
-                  Debug.startMethodTracingSampling(
-                      profileName,
-                      JAVA_SAMPLING_PROFILE_MEMORY_BYTES,
-                      JAVA_SAMPLING_PROFILE_DELTA_US);
-                }
-              }
-            }
-          });
-    }
-    options.put(
-        mApplicationContext.getString(R.string.catalyst_settings), new DevOptionHandler() {
-          @Override
-          public void onOptionSelected() {
-            Intent intent = new Intent(mApplicationContext, DevSettingsActivity.class);
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            mApplicationContext.startActivity(intent);
-          }
-        });
-
-    if (mCustomDevOptions.size() > 0) {
-      options.putAll(mCustomDevOptions);
-    }
-
-    final DevOptionHandler[] optionHandlers = options.values().toArray(new DevOptionHandler[0]);
-
-    mDevOptionsDialog =
-        new AlertDialog.Builder(mApplicationContext)
-            .setItems(
-                options.keySet().toArray(new String[0]),
-                new DialogInterface.OnClickListener() {
-                  @Override
-                  public void onClick(DialogInterface dialog, int which) {
-                    optionHandlers[which].onOptionSelected();
-                    mDevOptionsDialog = null;
-                  }
-                })
-            .setOnCancelListener(new DialogInterface.OnCancelListener() {
-              @Override
-              public void onCancel(DialogInterface dialog) {
-                mDevOptionsDialog = null;
-              }
-            })
-            .create();
-    mDevOptionsDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
-    mDevOptionsDialog.show();
-  }
-
-  /**
-   * {@link ReactInstanceDevCommandsHandler} is responsible for
-   * enabling/disabling dev support when a React view is attached/detached
-   * or when application state changes (e.g. the application is backgrounded).
-   */
-  public void setDevSupportEnabled(boolean isDevSupportEnabled) {
-    mIsDevSupportEnabled = isDevSupportEnabled;
-    reload();
-  }
-
-  public boolean getDevSupportEnabled() {
-    return mIsDevSupportEnabled;
-  }
-
-  public DeveloperSettings getDevSettings() {
-    return mDevSettings;
-  }
-
-  public void onNewReactContextCreated(ReactContext reactContext) {
-    resetCurrentContext(reactContext);
-  }
-
-  public void onReactInstanceDestroyed(ReactContext reactContext) {
-    if (reactContext == mCurrentContext) {
-      // only call reset context when the destroyed context matches the one that is currently set
-      // for this manager
-      resetCurrentContext(null);
-    }
-  }
-
-  public String getSourceMapUrl() {
-    if (mJSAppBundleName == null) {
-      return "";
-    }
-
-    return mDevServerHelper.getSourceMapUrl(Assertions.assertNotNull(mJSAppBundleName));
-  }
-
-  public String getSourceUrl() {
-    if (mJSAppBundleName == null) {
-      return "";
-    }
-
-    return mDevServerHelper.getSourceUrl(Assertions.assertNotNull(mJSAppBundleName));
-  }
-
-  public String getJSBundleURLForRemoteDebugging() {
-    return mDevServerHelper.getJSBundleURLForRemoteDebugging(
-        Assertions.assertNotNull(mJSAppBundleName));
-  }
-
-  public String getDownloadedJSBundleFile() {
-    return mJSBundleTempFile.getAbsolutePath();
-  }
-
-  /**
-   * @return {@code true} if {@link ReactInstanceManager} should use downloaded JS bundle file
-   * instead of using JS file from assets. This may happen when app has not been updated since
-   * the last time we fetched the bundle.
-   */
-  public boolean hasUpToDateJSBundleInCache() {
-    if (mIsDevSupportEnabled && mJSBundleTempFile.exists()) {
-      try {
-        String packageName = mApplicationContext.getPackageName();
-        PackageInfo thisPackage = mApplicationContext.getPackageManager()
-            .getPackageInfo(packageName, 0);
-        if (mJSBundleTempFile.lastModified() > thisPackage.lastUpdateTime) {
-          // Base APK has not been updated since we donwloaded JS, but if app is using exopackage
-          // it may only be a single dex that has been updated. We check for exopackage dir update
-          // time in that case.
-          File exopackageDir = new File(
-              String.format(Locale.US, EXOPACKAGE_LOCATION_FORMAT, packageName));
-          if (exopackageDir.exists()) {
-            return mJSBundleTempFile.lastModified() > exopackageDir.lastModified();
-          }
-          return true;
-        }
-      } catch (PackageManager.NameNotFoundException e) {
-        // Ignore this error and just fallback to loading JS from assets
-        FLog.e(ReactConstants.TAG, "DevSupport is unable to get current app info");
-      }
-    }
-    return false;
-  }
-
-  /**
-   * @return {@code true} if JS bundle {@param bundleAssetName} exists, in that case
-   * {@link ReactInstanceManager} should use that file from assets instead of downloading bundle
-   * from dev server
-   */
-  public boolean hasBundleInAssets(String bundleAssetName) {
-    try {
-      String[] assets = mApplicationContext.getAssets().list("");
-      for (int i = 0; i < assets.length; i++) {
-        if (assets[i].equals(bundleAssetName)) {
-          return true;
-        }
-      }
-    } catch (IOException e) {
-      // Ignore this error and just fallback to downloading JS from devserver
-      FLog.e(ReactConstants.TAG, "Error while loading assets list");
-    }
-    return false;
-  }
-
-  private void resetCurrentContext(@Nullable ReactContext reactContext) {
-    if (mCurrentContext == reactContext) {
-      // new context is the same as the old one - do nothing
-      return;
-    }
-
-    // if currently profiling stop and write the profile file
-    if (mIsCurrentlyProfiling) {
-      mIsCurrentlyProfiling = false;
-      String profileName = (Environment.getExternalStorageDirectory().getPath() +
-          "/profile_" + mProfileIndex + ".json");
-      mProfileIndex++;
-      Debug.stopMethodTracing();
-      mCurrentContext.getCatalystInstance().stopProfiler("profile", profileName);
-    }
-
-    mCurrentContext = reactContext;
-
-    // Recreate debug overlay controller with new CatalystInstance object
-    if (mDebugOverlayController != null) {
-      mDebugOverlayController.setFpsDebugViewVisible(false);
-    }
-    if (reactContext != null) {
-      mDebugOverlayController = new DebugOverlayController(reactContext);
-    }
-
-    reloadSettings();
-  }
-
-  /* package */ void reloadSettings() {
-    reload();
-  }
-
-  public void handleReloadJS() {
-    UiThreadUtil.assertOnUiThread();
-
-    // dismiss redbox if exists
-    if (mRedBoxDialog != null) {
-      mRedBoxDialog.dismiss();
-    }
-
-    ProgressDialog progressDialog = new ProgressDialog(mApplicationContext);
-    progressDialog.setTitle(R.string.catalyst_jsload_title);
-    progressDialog.setMessage(mApplicationContext.getString(
-        mIsUsingJSProxy ? R.string.catalyst_remotedbg_message : R.string.catalyst_jsload_message));
-    progressDialog.setIndeterminate(true);
-    progressDialog.setCancelable(false);
-    progressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
-    progressDialog.show();
-
-    if (mIsUsingJSProxy) {
-      reloadJSInProxyMode(progressDialog);
-    } else {
-      reloadJSFromServer(progressDialog);
-    }
-  }
-
-  public void isPackagerRunning(DevServerHelper.PackagerStatusCallback callback) {
-    mDevServerHelper.isPackagerRunning(callback);
-  }
-
-  private void reloadJSInProxyMode(final ProgressDialog progressDialog) {
-    // When using js proxy, there is no need to fetch JS bundle as proxy executor will do that
-    // anyway
-    mDevServerHelper.launchChromeDevtools();
-
-    JavaJSExecutor.Factory factory = new JavaJSExecutor.Factory() {
-      @Override
-      public JavaJSExecutor create() throws Exception {
-        WebsocketJavaScriptExecutor executor = new WebsocketJavaScriptExecutor();
-        SimpleSettableFuture<Boolean> future = new SimpleSettableFuture<>();
-        executor.connect(
-            mDevServerHelper.getWebsocketProxyURL(),
-            getExecutorConnectCallback(progressDialog, future));
-        // TODO(t9349129) Don't use timeout
-        try {
-          future.get(90, TimeUnit.SECONDS);
-          return executor;
-        } catch (ExecutionException e) {
-          throw (Exception) e.getCause();
-        } catch (InterruptedException | TimeoutException e) {
-          throw new RuntimeException(e);
-        }
-      }
-    };
-    mReactInstanceCommandsHandler.onReloadWithJSDebugger(factory);
-  }
-
-  private WebsocketJavaScriptExecutor.JSExecutorConnectCallback getExecutorConnectCallback(
-      final ProgressDialog progressDialog,
-      final SimpleSettableFuture<Boolean> future) {
-    return new WebsocketJavaScriptExecutor.JSExecutorConnectCallback() {
-      @Override
-      public void onSuccess() {
-        future.set(true);
-        progressDialog.dismiss();
-      }
-
-      @Override
-      public void onFailure(final Throwable cause) {
-        progressDialog.dismiss();
-        FLog.e(ReactConstants.TAG, "Unable to connect to remote debugger", cause);
-        future.setException(
-            new IOException(
-                mApplicationContext.getString(R.string.catalyst_remotedbg_error), cause));
-      }
-    };
-  }
-
-  private void reloadJSFromServer(final ProgressDialog progressDialog) {
-    mDevServerHelper.downloadBundleFromURL(
-        new DevServerHelper.BundleDownloadCallback() {
-          @Override
-          public void onSuccess() {
-            progressDialog.dismiss();
-            UiThreadUtil.runOnUiThread(
-                new Runnable() {
-                  @Override
-                  public void run() {
-                    mReactInstanceCommandsHandler.onJSBundleLoadedFromServer();
-                  }
-                });
-          }
-
-          @Override
-          public void onFailure(final Exception cause) {
-            progressDialog.dismiss();
-            FLog.e(ReactConstants.TAG, "Unable to download JS bundle", cause);
-            UiThreadUtil.runOnUiThread(
-                new Runnable() {
-                  @Override
-                  public void run() {
-                    if (cause instanceof DebugServerException) {
-                      DebugServerException debugServerException = (DebugServerException) cause;
-                      showNewJavaError(debugServerException.description, cause);
-                    } else {
-                      showNewJavaError(
-                          mApplicationContext.getString(R.string.catalyst_jsload_error),
-                          cause);
-                    }
-                  }
-                });
-          }
-        },
-        Assertions.assertNotNull(mJSAppBundleName),
-        mJSBundleTempFile);
-    progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
-      @Override
-      public void onCancel(DialogInterface dialog) {
-        mDevServerHelper.cancelDownloadBundleFromURL();
-      }
-    });
-    progressDialog.setCancelable(true);
-  }
-
-  private void reload() {
-    // reload settings, show/hide debug overlay if required & start/stop shake detector
-    if (mIsDevSupportEnabled) {
-      // update visibility of FPS debug overlay depending on the settings
-      if (mDebugOverlayController != null) {
-        mDebugOverlayController.setFpsDebugViewVisible(mDevSettings.isFpsDebugEnabled());
-      }
-
-      // start shake gesture detector
-      if (!mIsShakeDetectorStarted) {
-        mShakeDetector.start(
-            (SensorManager) mApplicationContext.getSystemService(Context.SENSOR_SERVICE));
-        mIsShakeDetectorStarted = true;
-      }
-
-      // register reload app broadcast receiver
-      if (!mIsReceiverRegistered) {
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(DevServerHelper.getReloadAppAction(mApplicationContext));
-        mApplicationContext.registerReceiver(mReloadAppBroadcastReceiver, filter);
-        mIsReceiverRegistered = true;
-      }
-
-      if (mDevSettings.isReloadOnJSChangeEnabled()) {
-        mDevServerHelper.startPollingOnChangeEndpoint(
-            new DevServerHelper.OnServerContentChangeListener() {
-          @Override
-          public void onServerContentChanged() {
-            handleReloadJS();
-          }
-        });
-      } else {
-        mDevServerHelper.stopPollingOnChangeEndpoint();
-      }
-    } else {
-      // hide FPS debug overlay
-      if (mDebugOverlayController != null) {
-        mDebugOverlayController.setFpsDebugViewVisible(false);
-      }
-
-      // stop shake gesture detector
-      if (mIsShakeDetectorStarted) {
-        mShakeDetector.stop();
-        mIsShakeDetectorStarted = false;
-      }
-
-      // unregister app reload broadcast receiver
-      if (mIsReceiverRegistered) {
-        mApplicationContext.unregisterReceiver(mReloadAppBroadcastReceiver);
-        mIsReceiverRegistered = false;
-      }
-
-      // hide redbox dialog
-      if (mRedBoxDialog != null) {
-        mRedBoxDialog.dismiss();
-      }
-
-      // hide dev options dialog
-      if (mDevOptionsDialog != null) {
-        mDevOptionsDialog.dismiss();
-      }
-
-      mDevServerHelper.stopPollingOnChangeEndpoint();
-    }
-  }
+public interface DevSupportManager extends NativeModuleCallExceptionHandler {
+
+  void showNewJavaError(String message, Throwable e);
+  void addCustomDevOption(String optionName, DevOptionHandler optionHandler);
+  void showNewJSError(String message, ReadableArray details, int errorCookie);
+  void updateJSError(final String message, final ReadableArray details, final int errorCookie);
+  void showDevOptionsDialog();
+  void setDevSupportEnabled(boolean isDevSupportEnabled);
+  boolean getDevSupportEnabled();
+  DeveloperSettings getDevSettings();
+  void onNewReactContextCreated(ReactContext reactContext);
+  void onReactInstanceDestroyed(ReactContext reactContext);
+  String getSourceMapUrl();
+  String getSourceUrl();
+  String getJSBundleURLForRemoteDebugging();
+  String getDownloadedJSBundleFile();
+  boolean hasUpToDateJSBundleInCache();
+  void reloadSettings();
+  void handleReloadJS();
+  void isPackagerRunning(DevServerHelper.PackagerStatusCallback callback);
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java
new file mode 100644
index 000000000000..7bdeea2d7ce5
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java
@@ -0,0 +1,722 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.devsupport;
+
+import javax.annotation.Nullable;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.hardware.SensorManager;
+import android.os.Debug;
+import android.os.Environment;
+import android.view.WindowManager;
+import android.widget.Toast;
+
+import com.facebook.common.logging.FLog;
+import com.facebook.infer.annotation.Assertions;
+import com.facebook.react.R;
+import com.facebook.react.bridge.CatalystInstance;
+import com.facebook.react.bridge.DefaultNativeModuleCallExceptionHandler;
+import com.facebook.react.bridge.JavaJSExecutor;
+import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.UiThreadUtil;
+import com.facebook.react.bridge.WebsocketJavaScriptExecutor;
+import com.facebook.react.common.ReactConstants;
+import com.facebook.react.common.ShakeDetector;
+import com.facebook.react.common.futures.SimpleSettableFuture;
+import com.facebook.react.devsupport.StackTraceHelper.StackFrame;
+import com.facebook.react.modules.debug.DeveloperSettings;
+
+/**
+ * Interface for accessing and interacting with development features. Following features
+ * are supported through this manager class:
+ * 1) Displaying JS errors (aka RedBox)
+ * 2) Displaying developers menu (Reload JS, Debug JS)
+ * 3) Communication with developer server in order to download updated JS bundle
+ * 4) Starting/stopping broadcast receiver for js reload signals
+ * 5) Starting/stopping motion sensor listener that recognize shake gestures which in turn may
+ *    trigger developers menu.
+ * 6) Launching developers settings view
+ *
+ * This class automatically monitors the state of registered views and activities to which they are
+ * bound to make sure that we don't display overlay or that we we don't listen for sensor events
+ * when app is backgrounded.
+ *
+ * {@link ReactInstanceDevCommandsHandler} implementation is responsible for instantiating this
+ * instance and for populating with an instance of {@link CatalystInstance} whenever instance
+ * manager recreates it (through {@link #onNewCatalystContextCreated}). Also, instance manager is
+ * responsible for enabling/disabling dev support in case when app is backgrounded or when all the
+ * views has been detached from the instance (through {@link #setDevSupportEnabled} method).
+ *
+ * IMPORTANT: In order for developer support to work correctly it is required that the
+ * manifest of your application contain the following entries:
+ * {@code <activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>}
+ * {@code <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>}
+ */
+public class DevSupportManagerImpl implements DevSupportManager {
+
+  private static final int JAVA_ERROR_COOKIE = -1;
+  private static final String JS_BUNDLE_FILE_NAME = "ReactNativeDevBundle.js";
+
+  private static final String EXOPACKAGE_LOCATION_FORMAT
+      = "/data/local/tmp/exopackage/%s//secondary-dex";
+
+  private static final int JAVA_SAMPLING_PROFILE_MEMORY_BYTES = 8 * 1024 * 1024;
+  private static final int JAVA_SAMPLING_PROFILE_DELTA_US = 100;
+
+  private final Context mApplicationContext;
+  private final ShakeDetector mShakeDetector;
+  private final BroadcastReceiver mReloadAppBroadcastReceiver;
+  private final DevServerHelper mDevServerHelper;
+  private final LinkedHashMap<String, DevOptionHandler> mCustomDevOptions =
+      new LinkedHashMap<>();
+  private final ReactInstanceDevCommandsHandler mReactInstanceCommandsHandler;
+  private final @Nullable String mJSAppBundleName;
+  private final File mJSBundleTempFile;
+  private final DefaultNativeModuleCallExceptionHandler mDefaultNativeModuleCallExceptionHandler;
+
+  private @Nullable RedBoxDialog mRedBoxDialog;
+  private @Nullable AlertDialog mDevOptionsDialog;
+  private @Nullable DebugOverlayController mDebugOverlayController;
+  private @Nullable ReactContext mCurrentContext;
+  private DevInternalSettings mDevSettings;
+  private boolean mIsUsingJSProxy = false;
+  private boolean mIsReceiverRegistered = false;
+  private boolean mIsShakeDetectorStarted = false;
+  private boolean mIsDevSupportEnabled = false;
+  private boolean mIsCurrentlyProfiling = false;
+  private int     mProfileIndex = 0;
+
+  public DevSupportManagerImpl(
+      Context applicationContext,
+      ReactInstanceDevCommandsHandler reactInstanceCommandsHandler,
+      @Nullable String packagerPathForJSBundleName,
+      boolean enableOnCreate) {
+    mReactInstanceCommandsHandler = reactInstanceCommandsHandler;
+    mApplicationContext = applicationContext;
+    mJSAppBundleName = packagerPathForJSBundleName;
+    mDevSettings = new DevInternalSettings(applicationContext, this);
+    mDevServerHelper = new DevServerHelper(mDevSettings);
+
+    // Prepare shake gesture detector (will be started/stopped from #reload)
+    mShakeDetector = new ShakeDetector(new ShakeDetector.ShakeListener() {
+      @Override
+      public void onShake() {
+        showDevOptionsDialog();
+      }
+    });
+
+    // Prepare reload APP broadcast receiver (will be registered/unregistered from #reload)
+    mReloadAppBroadcastReceiver = new BroadcastReceiver() {
+      @Override
+      public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+        if (DevServerHelper.getReloadAppAction(context).equals(action)) {
+          if (intent.getBooleanExtra(DevServerHelper.RELOAD_APP_EXTRA_JS_PROXY, false)) {
+            mIsUsingJSProxy = true;
+            mDevServerHelper.launchChromeDevtools();
+          } else {
+            mIsUsingJSProxy = false;
+          }
+          handleReloadJS();
+        }
+      }
+    };
+
+    // We store JS bundle loaded from dev server in a single destination in app's data dir.
+    // In case when someone schedule 2 subsequent reloads it may happen that JS thread will
+    // start reading first reload output while the second reload starts writing to the same
+    // file. As this should only be the case in dev mode we leave it as it is.
+    // TODO(6418010): Fix readers-writers problem in debug reload from HTTP server
+    mJSBundleTempFile = new File(applicationContext.getFilesDir(), JS_BUNDLE_FILE_NAME);
+
+    mDefaultNativeModuleCallExceptionHandler = new DefaultNativeModuleCallExceptionHandler();
+
+    setDevSupportEnabled(enableOnCreate);
+  }
+
+  @Override
+  public void handleException(Exception e) {
+    if (mIsDevSupportEnabled) {
+      FLog.e(ReactConstants.TAG, "Exception in native call from JS", e);
+      showNewJavaError(e.getMessage(), e);
+    } else {
+      mDefaultNativeModuleCallExceptionHandler.handleException(e);
+    }
+  }
+
+  @Override
+  public void showNewJavaError(String message, Throwable e) {
+    showNewError(message, StackTraceHelper.convertJavaStackTrace(e), JAVA_ERROR_COOKIE);
+  }
+
+  /**
+   * Add option item to dev settings dialog displayed by this manager. In the case user select given
+   * option from that dialog, the appropriate handler passed as {@param optionHandler} will be
+   * called.
+   */
+  @Override
+  public void addCustomDevOption(
+      String optionName,
+      DevOptionHandler optionHandler) {
+    mCustomDevOptions.put(optionName, optionHandler);
+  }
+
+  @Override
+  public void showNewJSError(String message, ReadableArray details, int errorCookie) {
+    showNewError(message, StackTraceHelper.convertJsStackTrace(details), errorCookie);
+  }
+
+  @Override
+  public void updateJSError(
+      final String message,
+      final ReadableArray details,
+      final int errorCookie) {
+    UiThreadUtil.runOnUiThread(
+        new Runnable() {
+          @Override
+          public void run() {
+            // Since we only show the first JS error in a succession of JS errors, make sure we only
+            // update the error message for that error message. This assumes that updateJSError
+            // belongs to the most recent showNewJSError
+            if (mRedBoxDialog == null ||
+                !mRedBoxDialog.isShowing() ||
+                errorCookie != mRedBoxDialog.getErrorCookie()) {
+              return;
+            }
+            mRedBoxDialog.setExceptionDetails(
+                message,
+                StackTraceHelper.convertJsStackTrace(details));
+            mRedBoxDialog.show();
+          }
+        });
+  }
+
+  private void showNewError(
+      final String message,
+      final StackFrame[] stack,
+      final int errorCookie) {
+    UiThreadUtil.runOnUiThread(
+        new Runnable() {
+          @Override
+          public void run() {
+            if (mRedBoxDialog == null) {
+              mRedBoxDialog = new RedBoxDialog(mApplicationContext, DevSupportManagerImpl.this);
+              mRedBoxDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+            }
+            if (mRedBoxDialog.isShowing()) {
+              // Sometimes errors cause multiple errors to be thrown in JS in quick succession. Only
+              // show the first and most actionable one.
+              return;
+            }
+            mRedBoxDialog.setExceptionDetails(message, stack);
+            mRedBoxDialog.setErrorCookie(errorCookie);
+            mRedBoxDialog.show();
+          }
+        });
+  }
+
+  @Override
+  public void showDevOptionsDialog() {
+    if (mDevOptionsDialog != null || !mIsDevSupportEnabled) {
+      return;
+    }
+    LinkedHashMap<String, DevOptionHandler> options = new LinkedHashMap<>();
+    /* register standard options */
+    options.put(
+        mApplicationContext.getString(R.string.catalyst_reloadjs), new DevOptionHandler() {
+          @Override
+          public void onOptionSelected() {
+            handleReloadJS();
+          }
+        });
+    options.put(
+        mIsUsingJSProxy ?
+            mApplicationContext.getString(R.string.catalyst_debugjs_off) :
+            mApplicationContext.getString(R.string.catalyst_debugjs),
+        new DevOptionHandler() {
+          @Override
+          public void onOptionSelected() {
+            mIsUsingJSProxy = !mIsUsingJSProxy;
+            handleReloadJS();
+          }
+        });
+    options.put(
+            mDevSettings.isHotModuleReplacementEnabled()
+                    ? mApplicationContext.getString(R.string.catalyst_hot_module_replacement_off)
+                    : mApplicationContext.getString(R.string.catalyst_hot_module_replacement),
+            new DevOptionHandler() {
+              @Override
+              public void onOptionSelected() {
+                mDevSettings.setHotModuleReplacementEnabled(!mDevSettings.isHotModuleReplacementEnabled());
+                handleReloadJS();
+              }
+            });
+    options.put(
+        mDevSettings.isReloadOnJSChangeEnabled()
+            ? mApplicationContext.getString(R.string.catalyst_live_reload_off)
+            : mApplicationContext.getString(R.string.catalyst_live_reload),
+        new DevOptionHandler() {
+          @Override
+          public void onOptionSelected() {
+            mDevSettings.setReloadOnJSChangeEnabled(!mDevSettings.isReloadOnJSChangeEnabled());
+          }
+        });
+    options.put(
+        mDevSettings.isElementInspectorEnabled()
+          ? mApplicationContext.getString(R.string.catalyst_element_inspector_off)
+          : mApplicationContext.getString(R.string.catalyst_element_inspector),
+        new DevOptionHandler() {
+          @Override
+          public void onOptionSelected() {
+            mDevSettings.setElementInspectorEnabled(!mDevSettings.isElementInspectorEnabled());
+            mReactInstanceCommandsHandler.toggleElementInspector();
+          }
+        });
+    options.put(
+        mDevSettings.isFpsDebugEnabled()
+            ? mApplicationContext.getString(R.string.catalyst_perf_monitor_off)
+            : mApplicationContext.getString(R.string.catalyst_perf_monitor),
+        new DevOptionHandler() {
+          @Override
+          public void onOptionSelected() {
+            mDevSettings.setFpsDebugEnabled(!mDevSettings.isFpsDebugEnabled());
+          }
+        });
+    if (mCurrentContext != null &&
+        mCurrentContext.getCatalystInstance() != null &&
+        !mCurrentContext.getCatalystInstance().isDestroyed() &&
+        mCurrentContext.getCatalystInstance().supportsProfiling()) {
+      options.put(
+          mApplicationContext.getString(
+              mIsCurrentlyProfiling ? R.string.catalyst_stop_profile :
+                  R.string.catalyst_start_profile),
+          new DevOptionHandler() {
+            @Override
+            public void onOptionSelected() {
+              if (mCurrentContext != null && mCurrentContext.hasActiveCatalystInstance()) {
+                String profileName = (Environment.getExternalStorageDirectory().getPath() +
+                    "/profile_" + mProfileIndex + ".json");
+                if (mIsCurrentlyProfiling) {
+                  mIsCurrentlyProfiling = false;
+                  mProfileIndex++;
+                  Debug.stopMethodTracing();
+                  mCurrentContext.getCatalystInstance()
+                      .stopProfiler("profile", profileName);
+                  Toast.makeText(
+                      mCurrentContext,
+                      "Profile output to " + profileName,
+                      Toast.LENGTH_LONG).show();
+                } else {
+                  mIsCurrentlyProfiling = true;
+                  mCurrentContext.getCatalystInstance().startProfiler("profile");
+                  Debug.startMethodTracingSampling(
+                      profileName,
+                      JAVA_SAMPLING_PROFILE_MEMORY_BYTES,
+                      JAVA_SAMPLING_PROFILE_DELTA_US);
+                }
+              }
+            }
+          });
+    }
+    options.put(
+        mApplicationContext.getString(R.string.catalyst_settings), new DevOptionHandler() {
+          @Override
+          public void onOptionSelected() {
+            Intent intent = new Intent(mApplicationContext, DevSettingsActivity.class);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            mApplicationContext.startActivity(intent);
+          }
+        });
+
+    if (mCustomDevOptions.size() > 0) {
+      options.putAll(mCustomDevOptions);
+    }
+
+    final DevOptionHandler[] optionHandlers = options.values().toArray(new DevOptionHandler[0]);
+
+    mDevOptionsDialog =
+        new AlertDialog.Builder(mApplicationContext)
+            .setItems(
+                options.keySet().toArray(new String[0]),
+                new DialogInterface.OnClickListener() {
+                  @Override
+                  public void onClick(DialogInterface dialog, int which) {
+                    optionHandlers[which].onOptionSelected();
+                    mDevOptionsDialog = null;
+                  }
+                })
+            .setOnCancelListener(new DialogInterface.OnCancelListener() {
+              @Override
+              public void onCancel(DialogInterface dialog) {
+                mDevOptionsDialog = null;
+              }
+            })
+            .create();
+    mDevOptionsDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+    mDevOptionsDialog.show();
+  }
+
+  /**
+   * {@link ReactInstanceDevCommandsHandler} is responsible for
+   * enabling/disabling dev support when a React view is attached/detached
+   * or when application state changes (e.g. the application is backgrounded).
+   */
+  @Override
+  public void setDevSupportEnabled(boolean isDevSupportEnabled) {
+    mIsDevSupportEnabled = isDevSupportEnabled;
+    reload();
+  }
+
+  @Override
+  public boolean getDevSupportEnabled() {
+    return mIsDevSupportEnabled;
+  }
+
+  @Override
+  public DeveloperSettings getDevSettings() {
+    return mDevSettings;
+  }
+
+  @Override
+  public void onNewReactContextCreated(ReactContext reactContext) {
+    resetCurrentContext(reactContext);
+  }
+
+  @Override
+  public void onReactInstanceDestroyed(ReactContext reactContext) {
+    if (reactContext == mCurrentContext) {
+      // only call reset context when the destroyed context matches the one that is currently set
+      // for this manager
+      resetCurrentContext(null);
+    }
+  }
+
+  @Override
+  public String getSourceMapUrl() {
+    if (mJSAppBundleName == null) {
+      return "";
+    }
+
+    return mDevServerHelper.getSourceMapUrl(Assertions.assertNotNull(mJSAppBundleName));
+  }
+
+  @Override
+  public String getSourceUrl() {
+    if (mJSAppBundleName == null) {
+      return "";
+    }
+
+    return mDevServerHelper.getSourceUrl(Assertions.assertNotNull(mJSAppBundleName));
+  }
+
+  @Override
+  public String getJSBundleURLForRemoteDebugging() {
+    return mDevServerHelper.getJSBundleURLForRemoteDebugging(
+        Assertions.assertNotNull(mJSAppBundleName));
+  }
+
+  @Override
+  public String getDownloadedJSBundleFile() {
+    return mJSBundleTempFile.getAbsolutePath();
+  }
+
+  /**
+   * @return {@code true} if {@link ReactInstanceManager} should use downloaded JS bundle file
+   * instead of using JS file from assets. This may happen when app has not been updated since
+   * the last time we fetched the bundle.
+   */
+  @Override
+  public boolean hasUpToDateJSBundleInCache() {
+    if (mIsDevSupportEnabled && mJSBundleTempFile.exists()) {
+      try {
+        String packageName = mApplicationContext.getPackageName();
+        PackageInfo thisPackage = mApplicationContext.getPackageManager()
+            .getPackageInfo(packageName, 0);
+        if (mJSBundleTempFile.lastModified() > thisPackage.lastUpdateTime) {
+          // Base APK has not been updated since we donwloaded JS, but if app is using exopackage
+          // it may only be a single dex that has been updated. We check for exopackage dir update
+          // time in that case.
+          File exopackageDir = new File(
+              String.format(Locale.US, EXOPACKAGE_LOCATION_FORMAT, packageName));
+          if (exopackageDir.exists()) {
+            return mJSBundleTempFile.lastModified() > exopackageDir.lastModified();
+          }
+          return true;
+        }
+      } catch (PackageManager.NameNotFoundException e) {
+        // Ignore this error and just fallback to loading JS from assets
+        FLog.e(ReactConstants.TAG, "DevSupport is unable to get current app info");
+      }
+    }
+    return false;
+  }
+
+  /**
+   * @return {@code true} if JS bundle {@param bundleAssetName} exists, in that case
+   * {@link ReactInstanceManager} should use that file from assets instead of downloading bundle
+   * from dev server
+   */
+  public boolean hasBundleInAssets(String bundleAssetName) {
+    try {
+      String[] assets = mApplicationContext.getAssets().list("");
+      for (int i = 0; i < assets.length; i++) {
+        if (assets[i].equals(bundleAssetName)) {
+          return true;
+        }
+      }
+    } catch (IOException e) {
+      // Ignore this error and just fallback to downloading JS from devserver
+      FLog.e(ReactConstants.TAG, "Error while loading assets list");
+    }
+    return false;
+  }
+
+  private void resetCurrentContext(@Nullable ReactContext reactContext) {
+    if (mCurrentContext == reactContext) {
+      // new context is the same as the old one - do nothing
+      return;
+    }
+
+    // if currently profiling stop and write the profile file
+    if (mIsCurrentlyProfiling) {
+      mIsCurrentlyProfiling = false;
+      String profileName = (Environment.getExternalStorageDirectory().getPath() +
+          "/profile_" + mProfileIndex + ".json");
+      mProfileIndex++;
+      Debug.stopMethodTracing();
+      mCurrentContext.getCatalystInstance().stopProfiler("profile", profileName);
+    }
+
+    mCurrentContext = reactContext;
+
+    // Recreate debug overlay controller with new CatalystInstance object
+    if (mDebugOverlayController != null) {
+      mDebugOverlayController.setFpsDebugViewVisible(false);
+    }
+    if (reactContext != null) {
+      mDebugOverlayController = new DebugOverlayController(reactContext);
+    }
+
+    reloadSettings();
+  }
+
+  @Override
+  public void reloadSettings() {
+    reload();
+  }
+
+  @Override
+  public void handleReloadJS() {
+    UiThreadUtil.assertOnUiThread();
+
+    // dismiss redbox if exists
+    if (mRedBoxDialog != null) {
+      mRedBoxDialog.dismiss();
+    }
+
+    ProgressDialog progressDialog = new ProgressDialog(mApplicationContext);
+    progressDialog.setTitle(R.string.catalyst_jsload_title);
+    progressDialog.setMessage(mApplicationContext.getString(
+        mIsUsingJSProxy ? R.string.catalyst_remotedbg_message : R.string.catalyst_jsload_message));
+    progressDialog.setIndeterminate(true);
+    progressDialog.setCancelable(false);
+    progressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+    progressDialog.show();
+
+    if (mIsUsingJSProxy) {
+      reloadJSInProxyMode(progressDialog);
+    } else {
+      reloadJSFromServer(progressDialog);
+    }
+  }
+
+  @Override
+  public void isPackagerRunning(DevServerHelper.PackagerStatusCallback callback) {
+    mDevServerHelper.isPackagerRunning(callback);
+  }
+
+  private void reloadJSInProxyMode(final ProgressDialog progressDialog) {
+    // When using js proxy, there is no need to fetch JS bundle as proxy executor will do that
+    // anyway
+    mDevServerHelper.launchChromeDevtools();
+
+    JavaJSExecutor.Factory factory = new JavaJSExecutor.Factory() {
+      @Override
+      public JavaJSExecutor create() throws Exception {
+        WebsocketJavaScriptExecutor executor = new WebsocketJavaScriptExecutor();
+        SimpleSettableFuture<Boolean> future = new SimpleSettableFuture<>();
+        executor.connect(
+            mDevServerHelper.getWebsocketProxyURL(),
+            getExecutorConnectCallback(progressDialog, future));
+        // TODO(t9349129) Don't use timeout
+        try {
+          future.get(90, TimeUnit.SECONDS);
+          return executor;
+        } catch (ExecutionException e) {
+          throw (Exception) e.getCause();
+        } catch (InterruptedException | TimeoutException e) {
+          throw new RuntimeException(e);
+        }
+      }
+    };
+    mReactInstanceCommandsHandler.onReloadWithJSDebugger(factory);
+  }
+
+  private WebsocketJavaScriptExecutor.JSExecutorConnectCallback getExecutorConnectCallback(
+      final ProgressDialog progressDialog,
+      final SimpleSettableFuture<Boolean> future) {
+    return new WebsocketJavaScriptExecutor.JSExecutorConnectCallback() {
+      @Override
+      public void onSuccess() {
+        future.set(true);
+        progressDialog.dismiss();
+      }
+
+      @Override
+      public void onFailure(final Throwable cause) {
+        progressDialog.dismiss();
+        FLog.e(ReactConstants.TAG, "Unable to connect to remote debugger", cause);
+        future.setException(
+            new IOException(
+                mApplicationContext.getString(R.string.catalyst_remotedbg_error), cause));
+      }
+    };
+  }
+
+  private void reloadJSFromServer(final ProgressDialog progressDialog) {
+    mDevServerHelper.downloadBundleFromURL(
+        new DevServerHelper.BundleDownloadCallback() {
+          @Override
+          public void onSuccess() {
+            progressDialog.dismiss();
+            UiThreadUtil.runOnUiThread(
+                new Runnable() {
+                  @Override
+                  public void run() {
+                    mReactInstanceCommandsHandler.onJSBundleLoadedFromServer();
+                  }
+                });
+          }
+
+          @Override
+          public void onFailure(final Exception cause) {
+            progressDialog.dismiss();
+            FLog.e(ReactConstants.TAG, "Unable to download JS bundle", cause);
+            UiThreadUtil.runOnUiThread(
+                new Runnable() {
+                  @Override
+                  public void run() {
+                    if (cause instanceof DebugServerException) {
+                      DebugServerException debugServerException = (DebugServerException) cause;
+                      showNewJavaError(debugServerException.description, cause);
+                    } else {
+                      showNewJavaError(
+                          mApplicationContext.getString(R.string.catalyst_jsload_error),
+                          cause);
+                    }
+                  }
+                });
+          }
+        },
+        Assertions.assertNotNull(mJSAppBundleName),
+        mJSBundleTempFile);
+    progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+      @Override
+      public void onCancel(DialogInterface dialog) {
+        mDevServerHelper.cancelDownloadBundleFromURL();
+      }
+    });
+    progressDialog.setCancelable(true);
+  }
+
+  private void reload() {
+    // reload settings, show/hide debug overlay if required & start/stop shake detector
+    if (mIsDevSupportEnabled) {
+      // update visibility of FPS debug overlay depending on the settings
+      if (mDebugOverlayController != null) {
+        mDebugOverlayController.setFpsDebugViewVisible(mDevSettings.isFpsDebugEnabled());
+      }
+
+      // start shake gesture detector
+      if (!mIsShakeDetectorStarted) {
+        mShakeDetector.start(
+            (SensorManager) mApplicationContext.getSystemService(Context.SENSOR_SERVICE));
+        mIsShakeDetectorStarted = true;
+      }
+
+      // register reload app broadcast receiver
+      if (!mIsReceiverRegistered) {
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(DevServerHelper.getReloadAppAction(mApplicationContext));
+        mApplicationContext.registerReceiver(mReloadAppBroadcastReceiver, filter);
+        mIsReceiverRegistered = true;
+      }
+
+      if (mDevSettings.isReloadOnJSChangeEnabled()) {
+        mDevServerHelper.startPollingOnChangeEndpoint(
+            new DevServerHelper.OnServerContentChangeListener() {
+          @Override
+          public void onServerContentChanged() {
+            handleReloadJS();
+          }
+        });
+      } else {
+        mDevServerHelper.stopPollingOnChangeEndpoint();
+      }
+    } else {
+      // hide FPS debug overlay
+      if (mDebugOverlayController != null) {
+        mDebugOverlayController.setFpsDebugViewVisible(false);
+      }
+
+      // stop shake gesture detector
+      if (mIsShakeDetectorStarted) {
+        mShakeDetector.stop();
+        mIsShakeDetectorStarted = false;
+      }
+
+      // unregister app reload broadcast receiver
+      if (mIsReceiverRegistered) {
+        mApplicationContext.unregisterReceiver(mReloadAppBroadcastReceiver);
+        mIsReceiverRegistered = false;
+      }
+
+      // hide redbox dialog
+      if (mRedBoxDialog != null) {
+        mRedBoxDialog.dismiss();
+      }
+
+      // hide dev options dialog
+      if (mDevOptionsDialog != null) {
+        mDevOptionsDialog.dismiss();
+      }
+
+      mDevServerHelper.stopPollingOnChangeEndpoint();
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DisabledDevSupportManager.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DisabledDevSupportManager.java
new file mode 100644
index 000000000000..44edbc8866ec
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DisabledDevSupportManager.java
@@ -0,0 +1,116 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.devsupport;
+
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.modules.debug.DeveloperSettings;
+
+/**
+ * A dummy implementation of {@link DevSupportManager} to be used in production mode where
+ * development features aren't needed.
+ */
+public class DisabledDevSupportManager implements DevSupportManager {
+
+  @Override
+  public void showNewJavaError(String message, Throwable e) {
+
+  }
+
+  @Override
+  public void addCustomDevOption(String optionName, DevOptionHandler optionHandler) {
+
+  }
+
+  @Override
+  public void showNewJSError(String message, ReadableArray details, int errorCookie) {
+
+  }
+
+  @Override
+  public void updateJSError(String message, ReadableArray details, int errorCookie) {
+
+  }
+
+  @Override
+  public void showDevOptionsDialog() {
+
+  }
+
+  @Override
+  public void setDevSupportEnabled(boolean isDevSupportEnabled) {
+
+  }
+
+  @Override
+  public boolean getDevSupportEnabled() {
+    return false;
+  }
+
+  @Override
+  public DeveloperSettings getDevSettings() {
+    return null;
+  }
+
+  @Override
+  public void onNewReactContextCreated(ReactContext reactContext) {
+
+  }
+
+  @Override
+  public void onReactInstanceDestroyed(ReactContext reactContext) {
+
+  }
+
+  @Override
+  public String getSourceMapUrl() {
+    return null;
+  }
+
+  @Override
+  public String getSourceUrl() {
+    return null;
+  }
+
+  @Override
+  public String getJSBundleURLForRemoteDebugging() {
+    return null;
+  }
+
+  @Override
+  public String getDownloadedJSBundleFile() {
+    return null;
+  }
+
+  @Override
+  public boolean hasUpToDateJSBundleInCache() {
+    return false;
+  }
+
+  @Override
+  public void reloadSettings() {
+
+  }
+
+  @Override
+  public void handleReloadJS() {
+
+  }
+
+  @Override
+  public void isPackagerRunning(DevServerHelper.PackagerStatusCallback callback) {
+
+  }
+
+  @Override
+  public void handleException(Exception e) {
+
+  }
+}

From 73417068848aa363e01ddf55096140452f5dc645 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Fri, 8 Jan 2016 03:37:25 -0800
Subject: [PATCH 0677/1411] Disable background color propagation for everything
 except text nodes

Summary:
public
Blending semitransparent pixels against their background is fairly a fairly expensive operation on mobile GPUs. To reduce blending, React Native has a system called "background color propagation", where the background color of parent views is automatically inherited by child views unless explicitly overridden. This means that translucent pixels can be blended directly against a known background color, avoiding the need to do this dynamically on the GPU.

In practice, this is only useful for views that do their own drawing, which is basically just `<Image/>` and `<Text/>` components, and for image components it only really matters when the image has an alpha component.

The automatic background propagation is a bit of a hack, and often does the wrong thing - for example if a view overflows its bounds, or if it overlaps a sibling, the background color will often be incorrect and need to be manually disabled. Because the only place that it provides a significant performance benefit is for text, this diff disables the behavior for everything except `<Text/>` nodes. It might still be useful for `<Image/>` nodes too, but looking through the examples in UIExplorer, the number of places where it does the wrong thing for images outnumbers the cases where it provides significant reduction in blending.

Note that this diff does not prevent you from eliminating blending on image components by manually setting an opaque background color, nor does it stop you from disabling color propagation on text components by manually setting a transparent background.

Reviewed By: javache

Differential Revision: D2811031

fb-gh-sync-id: 2eb08918c9031c582a3dd2d40e04b27a663dac82
---
 .../testSwitchExample_1@2x.png                | Bin 150432 -> 150379 bytes
 .../testViewExample_1@2x.png                  | Bin 156634 -> 156641 bytes
 Libraries/Text/RCTText.m                      |   5 +++++
 React/Views/UIView+React.m                    |   2 +-
 4 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testSwitchExample_1@2x.png b/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testSwitchExample_1@2x.png
index f5b29ca7874c29701a7e8b227e0db763270d4a31..a1d8b69dc7d9621330115b7c00e79309bbeabdd2 100644
GIT binary patch
diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testViewExample_1@2x.png b/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testViewExample_1@2x.png
index c27b9cd19e7478674c3a9980d3681d6cc8cb5b17..bf417eb6f461ef5544a85444692ce388b3ef6286 100644
GIT binary patch
diff --git a/Libraries/Text/RCTText.m b/Libraries/Text/RCTText.m
index c45287917db9..a4f110ed63e8 100644
--- a/Libraries/Text/RCTText.m
+++ b/Libraries/Text/RCTText.m
@@ -52,6 +52,11 @@ - (void)reactSetFrame:(CGRect)frame
   }];
 }
 
+- (void)reactSetInheritedBackgroundColor:(UIColor *)inheritedBackgroundColor
+{
+  self.backgroundColor = inheritedBackgroundColor;
+}
+
 - (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex
 {
   [_reactSubviews insertObject:subview atIndex:atIndex];
diff --git a/React/Views/UIView+React.m b/React/Views/UIView+React.m
index 89291236434e..fae5e021acf2 100644
--- a/React/Views/UIView+React.m
+++ b/React/Views/UIView+React.m
@@ -84,7 +84,7 @@ - (void)reactSetFrame:(CGRect)frame
 
 - (void)reactSetInheritedBackgroundColor:(UIColor *)inheritedBackgroundColor
 {
-  self.backgroundColor = inheritedBackgroundColor;
+  // Does nothing by default
 }
 
 - (UIViewController *)reactViewController

From 5a3b272f7e989bb0e574d14c5080966a9188b674 Mon Sep 17 00:00:00 2001
From: Lukas Benes <bender@false.cz>
Date: Fri, 8 Jan 2016 04:35:24 -0800
Subject: [PATCH 0678/1411] Fix missing Alert in react-native.js.flow

Summary: Closes https://github.com/facebook/react-native/pull/5192

Reviewed By: svcscm

Differential Revision: D2815060

Pulled By: androidtrunkagent

fb-gh-sync-id: cbf9058e4e6b36584d8487fc132faa2a5c52bbe0
---
 Libraries/react-native/react-native.js.flow | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Libraries/react-native/react-native.js.flow b/Libraries/react-native/react-native.js.flow
index 7773b27c0281..a178f69cf436 100644
--- a/Libraries/react-native/react-native.js.flow
+++ b/Libraries/react-native/react-native.js.flow
@@ -67,6 +67,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
   // APIs
   ActionSheetIOS: require('ActionSheetIOS'),
   AdSupportIOS: require('AdSupportIOS'),
+  Alert: require('Alert'),
   AlertIOS: require('AlertIOS'),
   Animated: require('Animated'),
   AppRegistry: require('AppRegistry'),

From 8ecd352bbf92ec51bd913b5a95e1c52590549be5 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Fri, 8 Jan 2016 05:04:26 -0800
Subject: [PATCH 0679/1411] Fix the 'end' value in the onTextInput callback for
 onscreen keyboard

Summary:
public
The 'end' value in the onTextInput callback was incorrectly computed.  It now is correct.  The value of start and end are relative to the entirety of the entire prechange text in the text input.

Reviewed By: andreicoman11

Differential Revision: D2815064

fb-gh-sync-id: e9f9c84cc5836042d0ffcccc991df72b725ab994
---
 .../facebook/react/views/textinput/ReactTextInputManager.java   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
index ebb9a31bfc9a..9184c661763e 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
@@ -376,7 +376,7 @@ public void onTextChanged(CharSequence s, int start, int before, int count) {
               newText,
               oldText,
               start,
-              count > 0 ? start + count - 1 : start + before));
+              start + before));
     }
 
     @Override

From b84ad2ab0da26d8285986a4519b2d824f520ce65 Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Fri, 8 Jan 2016 06:51:45 -0800
Subject: [PATCH 0680/1411] Updates for haste2 inside of jest

Summary:
I'm working on deploying haste2 with jest. This updates all the files that require changes for this to work and they are backwards compatible with the current version of jest.

* package.json was just outdated. I think haste1's liberal handling with collisions made this a "non-issue"
* env.js didn't properly set up ErrorUtils, also unsure why that isn't a problem in jest right now already?
* some things were mocking things they shouldn't
* Because of the regex that matches against providesModule and System.import, it isn't possible to list module names more than once. We have multiple tests reusing the same providesModule ids and using System.import with modules that only exist virtually within that test. Splitting up the strings makes the regexes work (we do the same kind of splitting on www sometimes if we need to) and using different providesModule names in different test files fixes the problem. I think the BundlesLayoutIntegration-test is going to be deleted, so this doesn't even matter.

public

Reviewed By: voideanvalue

Differential Revision: D2809681

fb-gh-sync-id: 8fe6ed8b5a1be28ba141e9001de143e502693281
---
 .../__tests__/NavigationTreeNode-test.js      |   1 -
 Libraries/Interaction/TaskQueue.js            |   4 +-
 .../Utilities/__tests__/MessageQueue-test.js  |  10 +-
 jestSupport/env.js                            |   2 +
 package.json                                  |  51 ++++++++
 packager/blacklist.js                         |   2 +-
 .../BundlesLayoutIntegration-test.js          | 112 +++++++++---------
 .../__tests__/DependencyGraph-test.js         |   2 +-
 .../__tests__/Module-test.js                  |  10 +-
 .../babel-plugin-system-import-test.js        |   6 +-
 10 files changed, 123 insertions(+), 77 deletions(-)

diff --git a/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationTreeNode-test.js b/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationTreeNode-test.js
index e89da6a80d29..7a00f72ddc5e 100644
--- a/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationTreeNode-test.js
+++ b/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationTreeNode-test.js
@@ -5,7 +5,6 @@
 'use strict';
 
 jest
-  .dontMock('Map')
   .dontMock('NavigationTreeNode')
   .dontMock('invariant')
   .dontMock('immutable');
diff --git a/Libraries/Interaction/TaskQueue.js b/Libraries/Interaction/TaskQueue.js
index a2783bea0e39..91698470dfc3 100644
--- a/Libraries/Interaction/TaskQueue.js
+++ b/Libraries/Interaction/TaskQueue.js
@@ -35,8 +35,8 @@ export type Task = Function | SimpleTask | PromiseTask;
  * function is supplied, then the promise it returns will block execution of
  * tasks already in the queue until it resolves. This can be used to make sure
  * the first task is fully resolved (including asynchronous dependencies that
- * also schedule more tasks via `enqueue`) before starting on the next task. 
- * The `onMoreTasks` constructor argument is used to inform the owner that an 
+ * also schedule more tasks via `enqueue`) before starting on the next task.
+ * The `onMoreTasks` constructor argument is used to inform the owner that an
  * async task has resolved and that the queue should be processed again.
  *
  * Note: Tasks are only actually executed with explicit calls to `processNext`.
diff --git a/Libraries/Utilities/__tests__/MessageQueue-test.js b/Libraries/Utilities/__tests__/MessageQueue-test.js
index 64c4c1c1aa31..ab04d0fe54cf 100644
--- a/Libraries/Utilities/__tests__/MessageQueue-test.js
+++ b/Libraries/Utilities/__tests__/MessageQueue-test.js
@@ -8,12 +8,8 @@
  */
 'use strict';
 
-jest.setMock('ReactUpdates', {
-  batchedUpdates: fn => fn()
-});
-
-jest.dontMock('MessageQueue');
-jest.dontMock('keyMirror');
+jest.dontMock('MessageQueue')
+  .dontMock('keyMirror');
 var MessageQueue = require('MessageQueue');
 
 let MODULE_IDS = 0;
@@ -24,8 +20,6 @@ let TestModule = {
   testHook1(){}, testHook2(){},
 };
 
-let customRequire = (moduleName) => TestModule;
-
 let assertQueue = (flushedQueue, index, moduleID, methodID, params) => {
   expect(flushedQueue[MODULE_IDS][index]).toEqual(moduleID);
   expect(flushedQueue[METHOD_IDS][index]).toEqual(methodID);
diff --git a/jestSupport/env.js b/jestSupport/env.js
index 933419d36ee4..0d3a757d9bd4 100644
--- a/jestSupport/env.js
+++ b/jestSupport/env.js
@@ -16,3 +16,5 @@ global.__fbBatchedBridgeConfig = {
 };
 
 global.Promise = require('promise');
+
+jest.setMock('ErrorUtils', require('ErrorUtils'));
diff --git a/package.json b/package.json
index e7faf110b169..cd893d1fa41e 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,57 @@
     "testPathIgnorePatterns": [
       "/node_modules/"
     ],
+    "modulePathIgnorePatterns": [
+      "node_modules/react/lib/React.js",
+      "node_modules/react/lib/ReactDOM.js",
+
+      "node_modules/fbjs/lib/Map.js",
+      "node_modules/fbjs/lib/Promise.js",
+      "node_modules/fbjs/lib/fetch.js",
+      "node_modules/fbjs/lib/ErrorUtils.js",
+      "node_modules/fbjs/lib/URI.js",
+      "node_modules/fbjs/lib/Deferred.js",
+      "node_modules/fbjs/lib/PromiseMap.js",
+      "node_modules/fbjs/lib/UserAgent.js",
+      "node_modules/fbjs/lib/areEqual.js",
+      "node_modules/fbjs/lib/base62.js",
+      "node_modules/fbjs/lib/crc32.js",
+      "node_modules/fbjs/lib/everyObject.js",
+      "node_modules/fbjs/lib/fetchWithRetries.js",
+      "node_modules/fbjs/lib/filterObject.js",
+      "node_modules/fbjs/lib/flattenArray.js",
+      "node_modules/fbjs/lib/forEachObject.js",
+      "node_modules/fbjs/lib/isEmpty.js",
+      "node_modules/fbjs/lib/nullthrows.js",
+      "node_modules/fbjs/lib/removeFromArray.js",
+      "node_modules/fbjs/lib/resolveImmediate.js",
+      "node_modules/fbjs/lib/someObject.js",
+      "node_modules/fbjs/lib/sprintf.js",
+      "node_modules/fbjs/lib/xhrSimpleDataSerializer.js",
+
+      "downstream/core/CSSCore.js",
+      "downstream/core/TouchEventUtils.js",
+      "downstream/core/camelize.js",
+      "downstream/core/createArrayFromMixed.js",
+      "downstream/core/createNodesFromMarkup.js",
+      "downstream/core/dom/containsNode.js",
+      "downstream/core/dom/focusNode.js",
+      "downstream/core/dom/getActiveElement.js",
+      "downstream/core/dom/getUnboundedScrollPosition.js",
+      "downstream/core/dom/isNode.js",
+      "downstream/core/dom/isTextNode.js",
+      "downstream/core/emptyFunction.js",
+      "downstream/core/emptyObject.js",
+      "downstream/core/getMarkupWrap.js",
+      "downstream/core/hyphenate.js",
+      "downstream/core/hyphenateStyleName.js",
+      "downstream/core/invariant.js",
+      "downstream/core/nativeRequestAnimationFrame.js",
+      "downstream/core/toArray.js",
+
+      "node_modules/jest-cli",
+      "node_modules/react/dist"
+    ],
     "testFileExtensions": [
       "js"
     ],
diff --git a/packager/blacklist.js b/packager/blacklist.js
index 4fdca23c41a2..f3c652034014 100644
--- a/packager/blacklist.js
+++ b/packager/blacklist.js
@@ -10,7 +10,7 @@
 
 var path = require('path');
 
-// Don't forget to everything listed here to `testConfig.json`
+// Don't forget to everything listed here to `package.json`
 // modulePathIgnorePatterns.
 var sharedBlacklist = [
   /node_modules[/\\]react[/\\]dist[/\\].*/,
diff --git a/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js b/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js
index 37701392aba7..fe4481a0955e 100644
--- a/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js
+++ b/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js
@@ -95,7 +95,7 @@ describe('BundlesLayout', () => {
         'root': {
           'index.js': `
             /**
-             * @providesModule index
+             * @providesModule xindex
              */`,
         }
       });
@@ -116,12 +116,12 @@ describe('BundlesLayout', () => {
         'root': {
           'index.js': `
             /**
-             * @providesModule index
+             * @providesModule xindex
              */
-            require("a");`,
+            require("xa");`,
           'a.js': `
             /**
-             * @providesModule a
+             * @providesModule xa
              */`,
         }
       });
@@ -142,12 +142,12 @@ describe('BundlesLayout', () => {
         'root': {
           'index.js': `
             /**
-             * @providesModule index
+             * @providesModule xindex
              */
-            System.import("a");`,
+            ${'System.import'}("xa");`,
           'a.js': `
             /**,
-             * @providesModule a
+             * @providesModule xa
              */`,
         }
       });
@@ -172,17 +172,17 @@ describe('BundlesLayout', () => {
         'root': {
           'index.js': `
             /**
-             * @providesModule index
+             * @providesModule xindex
              */
-            System.import("a");
-            System.import("b");`,
+            ${'System.import'}("xa");
+            ${'System.import'}("xb");`,
           'a.js': `
             /**,
-             * @providesModule a
+             * @providesModule xa
              */`,
           'b.js': `
             /**
-             * @providesModule b
+             * @providesModule xb
              */`,
         }
       });
@@ -213,17 +213,17 @@ describe('BundlesLayout', () => {
         'root': {
           'index.js': `
             /**
-             * @providesModule index
+             * @providesModule xindex
              */
-            require("a");
-            System.import("b");`,
+            require("xa");
+            ${'System.import'}("xb");`,
           'a.js': `
             /**,
-             * @providesModule a
+             * @providesModule xa
              */`,
           'b.js': `
             /**
-             * @providesModule b
+             * @providesModule xb
              */`,
         }
       });
@@ -248,22 +248,22 @@ describe('BundlesLayout', () => {
         'root': {
           'index.js': `
             /**
-             * @providesModule index
+             * @providesModule xindex
              */
-            System.import("a");`,
+            ${'System.import'}("xa");`,
           'a.js': `
             /**,
-             * @providesModule a
+             * @providesModule xa
              */,
-            require("b");`,
+            require("xb");`,
           'b.js': `
             /**
-             * @providesModule b
+             * @providesModule xb
              */
-            require("c");`,
+            require("xc");`,
           'c.js': `
             /**
-             * @providesModule c
+             * @providesModule xc
              */`,
         }
       });
@@ -288,23 +288,23 @@ describe('BundlesLayout', () => {
         'root': {
           'index.js': `
             /**
-             * @providesModule index
+             * @providesModule xindex
              */
-            System.import("a");
-            System.import("b");`,
+            ${'System.import'}("xa");
+            ${'System.import'}("xb");`,
           'a.js': `
             /**,
-             * @providesModule a
+             * @providesModule xa
              */,
-            require("c");`,
+            require("xc");`,
           'b.js': `
             /**
-             * @providesModule b
+             * @providesModule xb
              */
-            require("c");`,
+            require("xc");`,
           'c.js': `
             /**
-             * @providesModule c
+             * @providesModule xc
              */`,
         }
       });
@@ -336,22 +336,22 @@ describe('BundlesLayout', () => {
         'root': {
           'index.js': `
             /**
-             * @providesModule index
+             * @providesModule xindex
              */
-            System.import("a");`,
+            ${'System.import'}("xa");`,
           'a.js': `
             /**,
-             * @providesModule a
+             * @providesModule xa
              */,
-            System.import("b");`,
+            ${'System.import'}("xb");`,
           'b.js': `
             /**
-             * @providesModule b
+             * @providesModule xb
              */
-            require("c");`,
+            require("xc");`,
           'c.js': `
             /**
-             * @providesModule c
+             * @providesModule xc
              */`,
         }
       });
@@ -382,12 +382,12 @@ describe('BundlesLayout', () => {
         'root': {
           'index.js': `
             /**
-             * @providesModule index
+             * @providesModule xindex
              */
-            System.import("a");`,
+            ${'System.import'}("xa");`,
           'a.js':`
             /**,
-             * @providesModule a
+             * @providesModule xa
              */,
             require("./img.png");`,
           'img.png': '',
@@ -414,18 +414,18 @@ describe('BundlesLayout', () => {
         'root': {
           'index.js': `
             /**
-             * @providesModule index
+             * @providesModule xindex
              */
-            System.import("a");
-            System.import("b");`,
+            ${'System.import'}("xa");
+            ${'System.import'}("xb");`,
           'a.js':`
             /**,
-             * @providesModule a
+             * @providesModule xa
              */,
             require("./img.png");`,
           'b.js':`
             /**,
-             * @providesModule b
+             * @providesModule xb
              */,
             require("./img.png");`,
           'img.png': '',
@@ -459,9 +459,9 @@ describe('BundlesLayout', () => {
         'root': {
           'index.js': `
             /**
-             * @providesModule index
+             * @providesModule xindex
              */
-            System.import("./img.png");`,
+            ${'System.import'}("./img.png");`,
           'img.png': '',
         }
       });
@@ -486,12 +486,12 @@ describe('BundlesLayout', () => {
         'root': {
           'index.js': `
             /**
-             * @providesModule index
+             * @providesModule xindex
              */
-            System.import("a");`,
+            ${'System.import'}("xa");`,
           'a.js':`
             /**,
-             * @providesModule a
+             * @providesModule xa
              */,
             require("image!img");`,
           'img.png': '',
@@ -518,9 +518,9 @@ describe('BundlesLayout', () => {
         'root': {
           'index.js': `
             /**
-             * @providesModule index
+             * @providesModule xindex
              */
-            System.import("image!img");`,
+            ${'System.import'}("image!img");`,
           'img.png': '',
         }
       });
@@ -545,9 +545,9 @@ describe('BundlesLayout', () => {
         'root': {
           'index.js': `
             /**
-             * @providesModule index
+             * @providesModule xindex
              */
-            System.import("aPackage");`,
+            ${'System.import'}("aPackage");`,
           'aPackage': {
             'package.json': JSON.stringify({
               name: 'aPackage',
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
index 184ea71fc5fc..80cafd5569ba 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
@@ -3934,7 +3934,7 @@ describe('DependencyGraph', function() {
             '/**',
             ' * @providesModule index',
             ' */',
-            'System.import("a")',
+            'System.' + 'import("a")',
           ].join('\n'),
           'a.js': [
             '/**',
diff --git a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js b/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
index ea95c43ab603..29a3e8420d6f 100644
--- a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
+++ b/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
@@ -68,7 +68,7 @@ describe('Module', () => {
     pit('should recognize single dependency', () => {
       fs.__setMockFilesystem({
         'root': {
-          'index.js': 'System.import("dep1")',
+          'index.js': 'System.' + 'import("dep1")',
         },
       });
 
@@ -78,7 +78,7 @@ describe('Module', () => {
     pit('should parse single quoted dependencies', () => {
       fs.__setMockFilesystem({
         'root': {
-          'index.js': 'System.import(\'dep1\')',
+          'index.js': 'System.' + 'import(\'dep1\')',
         },
       });
 
@@ -89,8 +89,8 @@ describe('Module', () => {
       fs.__setMockFilesystem({
         'root': {
           'index.js': [
-            'System.import("dep1")',
-            'System.import("dep2")',
+            'System.' + 'import("dep1")',
+            'System.' + 'import("dep2")',
           ].join('\n'),
         },
       });
@@ -104,7 +104,7 @@ describe('Module', () => {
     pit('parse fine new lines', () => {
       fs.__setMockFilesystem({
         'root': {
-          'index.js': 'System.import(\n"dep1"\n)',
+          'index.js': 'System.' + 'import(\n"dep1"\n)',
         },
       });
 
diff --git a/packager/react-packager/src/transforms/babel-plugin-system-import/__tests__/babel-plugin-system-import-test.js b/packager/react-packager/src/transforms/babel-plugin-system-import/__tests__/babel-plugin-system-import-test.js
index 43aa4b56b8b1..b29f1bd55be6 100644
--- a/packager/react-packager/src/transforms/babel-plugin-system-import/__tests__/babel-plugin-system-import-test.js
+++ b/packager/react-packager/src/transforms/babel-plugin-system-import/__tests__/babel-plugin-system-import-test.js
@@ -14,17 +14,17 @@ const BundlesLayout = require('../../../BundlesLayout');
 
 const testData = {
   isolated: {
-    input:  'System.import("moduleA");',
+    input:  'System.' + 'import("moduleA");',
     output: 'loadBundles(["bundle.0"]);'
   },
   single: {
-    input:  'System.import("moduleA").then(function (bundleA) {});',
+    input:  'System.' + 'import("moduleA").then(function (bundleA) {});',
     output: 'loadBundles(["bundle.0"]).then(function (bundleA) {});'
   },
   multiple: {
     input: [
       'Promise.all([',
-        'System.import("moduleA"), System.import("moduleB"),',
+        'System.' + 'import("moduleA"), System.' + 'import("moduleB"),',
       ']).then(function (bundlesA, bundlesB) {});',
     ].join('\n'),
     output: [

From 83ddd74ac767e14732ce52c098053339465457e5 Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Fri, 8 Jan 2016 06:55:38 -0800
Subject: [PATCH 0681/1411] Make Cache dir configurable

Reviewed By: davidaurelio

Differential Revision: D2811278

fb-gh-sync-id: 77c03a8f806135fff56914bac60c156d10b05ea4
---
 .../react-packager/src/DependencyResolver/Cache/index.js     | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/Cache/index.js b/packager/react-packager/src/DependencyResolver/Cache/index.js
index 84b7524d7538..89925fe24544 100644
--- a/packager/react-packager/src/DependencyResolver/Cache/index.js
+++ b/packager/react-packager/src/DependencyResolver/Cache/index.js
@@ -13,7 +13,7 @@ const fs = require('fs');
 const getCacheFilePath = require('./lib/getCacheFilePath');
 const isAbsolutePath = require('absolute-path');
 const loadCacheSync = require('./lib/loadCacheSync');
-const tmpdir = require('os').tmpDir();
+const tmpDir = require('os').tmpDir();
 
 function getObjectValues(object) {
   return Object.keys(object).map(key => object[key]);
@@ -31,8 +31,9 @@ class Cache {
   constructor({
     resetCache,
     cacheKey,
+    cacheDirectory = tmpDir,
   }) {
-    this._cacheFilePath = getCacheFilePath(tmpdir, cacheKey);
+    this._cacheFilePath = getCacheFilePath(cacheDirectory, cacheKey);
     if (!resetCache) {
       this._data = this._loadCacheSync(this._cacheFilePath);
     } else {

From 324493edae0094fb078d8fecf570385df32e576b Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Fri, 8 Jan 2016 08:34:52 -0800
Subject: [PATCH 0682/1411] Require transform file eagerly in transform worker

Summary:
One consequence we didn't predict after introducing the Internal Transform Pipeline, was that when the workers would get started, we won't require the external transformer the user specified up until the first time each worker received a job. There're 2 visible consequences of this: (1) the transform progress bar seems to get stuck for about 5 seconds the first time the packager receives a request and (2) the first N (# of cores) HMR requests take way longer (about 4 seconds with FB's transformer instead of << 1 second) as we need to require lots of modules.

This diff creates a temporary file for the js transformer workers that requires the user-specified transform file eagerly.
That makes sure workers have imported babel and the transforms before receiving the first request.

There are better ways to do this, like adding an `init()` method to the workers and call that eagerly. I will follow with another diff doing that.

public

Reviewed By: javache

Differential Revision: D2812153

fb-gh-sync-id: 15be316b792d1acd878ed9303bea398aa0b52e1d
---
 package.json                                      |  4 ++--
 .../JSTransformer/__tests__/Transformer-test.js   |  1 +
 .../react-packager/src/JSTransformer/index.js     | 15 ++++++++++++++-
 3 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/package.json b/package.json
index cd893d1fa41e..a52208af4c37 100644
--- a/package.json
+++ b/package.json
@@ -167,6 +167,7 @@
     "semver": "^5.0.3",
     "source-map": "^0.4.4",
     "stacktrace-parser": "^0.1.3",
+    "temp": "0.8.3",
     "uglify-js": "^2.4.24",
     "underscore": "^1.8.3",
     "wordwrap": "^1.0.0",
@@ -181,7 +182,6 @@
     "babel-eslint": "4.1.4",
     "eslint": "1.3.1",
     "eslint-plugin-react": "3.3.1",
-    "portfinder": "0.4.0",
-    "temp": "0.8.3"
+    "portfinder": "0.4.0"
   }
 }
diff --git a/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js b/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js
index 83275f142907..7e12976895df 100644
--- a/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js
+++ b/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js
@@ -13,6 +13,7 @@ jest
   .dontMock('../');
 
 jest.mock('fs');
+jest.setMock('temp', {path: () => '/arbitrary/path'});
 
 var Cache = require('../../DependencyResolver/Cache');
 var Transformer = require('../');
diff --git a/packager/react-packager/src/JSTransformer/index.js b/packager/react-packager/src/JSTransformer/index.js
index 2688e14cf47c..6cba12e51934 100644
--- a/packager/react-packager/src/JSTransformer/index.js
+++ b/packager/react-packager/src/JSTransformer/index.js
@@ -12,6 +12,7 @@ const ModuleTransport = require('../lib/ModuleTransport');
 const Promise = require('promise');
 const declareOpts = require('../lib/declareOpts');
 const fs = require('fs');
+const temp = require('temp');
 const util = require('util');
 const workerFarm = require('worker-farm');
 const debug = require('debug')('ReactNativePackager:JStransformer');
@@ -63,13 +64,22 @@ class Transformer {
     this._transformModulePath = opts.transformModulePath;
 
     if (opts.transformModulePath != null) {
+      this._workerWrapperPath = temp.path();
+      fs.writeFileSync(
+        this._workerWrapperPath,
+        `
+        module.exports = require(${JSON.stringify(require.resolve('./worker'))});
+        require(${JSON.stringify(String(opts.transformModulePath))});
+        `
+      );
+
       this._workers = workerFarm({
         autoStart: true,
         maxConcurrentCallsPerWorker: 1,
         maxCallsPerWorker: MAX_CALLS_PER_WORKER,
         maxCallTime: opts.transformTimeoutInterval,
         maxRetries: MAX_RETRIES,
-      }, require.resolve('./worker'));
+      }, this._workerWrapperPath);
 
       this._transform = Promise.denodeify(this._workers);
     }
@@ -77,6 +87,9 @@ class Transformer {
 
   kill() {
     this._workers && workerFarm.end(this._workers);
+    if (typeof this._workerWrapperPath === 'string') {
+      fs.unlink(this._workerWrapperPath, () => {}); // we don't care about potential errors here
+    }
   }
 
   invalidateFile(filePath) {

From 36dbe86208cbf89c68921bdbb3f2d2acd9281162 Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Fri, 8 Jan 2016 08:36:14 -0800
Subject: [PATCH 0683/1411] Use graceful-fs directly

Reviewed By: davidaurelio

Differential Revision: D2811784

fb-gh-sync-id: 95e4fd1538f4cd468288dc65e83f1d6ca98ce791
---
 .../DependencyResolver/Cache/__tests__/Cache-test.js  |  2 +-
 .../src/DependencyResolver/Cache/index.js             |  2 +-
 .../src/DependencyResolver/Cache/lib/loadCacheSync.js |  2 +-
 .../DependencyGraph/__tests__/DependencyGraph-test.js |  2 +-
 .../src/DependencyResolver/__tests__/Module-test.js   |  2 +-
 .../src/DependencyResolver/crawlers/node.js           |  2 +-
 .../react-packager/src/DependencyResolver/fastfs.js   |  2 +-
 packager/react-packager/src/__mocks__/graceful-fs.js  | 11 +++++++++++
 8 files changed, 18 insertions(+), 7 deletions(-)
 create mode 100644 packager/react-packager/src/__mocks__/graceful-fs.js

diff --git a/packager/react-packager/src/DependencyResolver/Cache/__tests__/Cache-test.js b/packager/react-packager/src/DependencyResolver/Cache/__tests__/Cache-test.js
index 62220f6b0172..f4c0f4309563 100644
--- a/packager/react-packager/src/DependencyResolver/Cache/__tests__/Cache-test.js
+++ b/packager/react-packager/src/DependencyResolver/Cache/__tests__/Cache-test.js
@@ -21,7 +21,7 @@ jest
   });
 
 var Promise = require('promise');
-var fs = require('fs');
+var fs = require('graceful-fs');
 
 var Cache = require('../');
 
diff --git a/packager/react-packager/src/DependencyResolver/Cache/index.js b/packager/react-packager/src/DependencyResolver/Cache/index.js
index 89925fe24544..3f601bd491e9 100644
--- a/packager/react-packager/src/DependencyResolver/Cache/index.js
+++ b/packager/react-packager/src/DependencyResolver/Cache/index.js
@@ -9,7 +9,7 @@
 'use strict';
 
 const Promise = require('promise');
-const fs = require('fs');
+const fs = require('graceful-fs');
 const getCacheFilePath = require('./lib/getCacheFilePath');
 const isAbsolutePath = require('absolute-path');
 const loadCacheSync = require('./lib/loadCacheSync');
diff --git a/packager/react-packager/src/DependencyResolver/Cache/lib/loadCacheSync.js b/packager/react-packager/src/DependencyResolver/Cache/lib/loadCacheSync.js
index d04ec093688b..87d6944c1267 100644
--- a/packager/react-packager/src/DependencyResolver/Cache/lib/loadCacheSync.js
+++ b/packager/react-packager/src/DependencyResolver/Cache/lib/loadCacheSync.js
@@ -8,7 +8,7 @@
  */
 'use strict';
 
-const fs = require('fs');
+const fs = require('graceful-fs');
 
 function loadCacheSync(cachePath) {
   if (!fs.existsSync(cachePath)) {
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
index 80cafd5569ba..8f41d88c2dbd 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
@@ -16,7 +16,7 @@ jest
   .mock('fs');
 
 var DependencyGraph = require('../index');
-var fs = require('fs');
+var fs = require('graceful-fs');
 
 describe('DependencyGraph', function() {
   let defaults;
diff --git a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js b/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
index 29a3e8420d6f..f0c9cbd2358f 100644
--- a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
+++ b/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
@@ -24,7 +24,7 @@ const Module = require('../Module');
 const ModuleCache = require('../ModuleCache');
 const DependencyGraphHelpers = require('../DependencyGraph/DependencyGraphHelpers');
 const Promise = require('promise');
-const fs = require('fs');
+const fs = require('graceful-fs');
 
 describe('Module', () => {
   const fileWatcher = {
diff --git a/packager/react-packager/src/DependencyResolver/crawlers/node.js b/packager/react-packager/src/DependencyResolver/crawlers/node.js
index 528cd5e7648e..88e32d8843c2 100644
--- a/packager/react-packager/src/DependencyResolver/crawlers/node.js
+++ b/packager/react-packager/src/DependencyResolver/crawlers/node.js
@@ -2,7 +2,7 @@
 
 const Promise = require('promise');
 const debug = require('debug')('ReactNativePackager:DependencyGraph');
-const fs = require('fs');
+const fs = require('graceful-fs');
 const path = require('path');
 
 const readDir = Promise.denodeify(fs.readdir);
diff --git a/packager/react-packager/src/DependencyResolver/fastfs.js b/packager/react-packager/src/DependencyResolver/fastfs.js
index 5bff24379378..ca01b86c8964 100644
--- a/packager/react-packager/src/DependencyResolver/fastfs.js
+++ b/packager/react-packager/src/DependencyResolver/fastfs.js
@@ -11,7 +11,7 @@
 const Promise = require('promise');
 const {EventEmitter} = require('events');
 
-const fs = require('fs');
+const fs = require('graceful-fs');
 const path = require('path');
 
 const readFile = Promise.denodeify(fs.readFile);
diff --git a/packager/react-packager/src/__mocks__/graceful-fs.js b/packager/react-packager/src/__mocks__/graceful-fs.js
new file mode 100644
index 000000000000..c6b9a53e068d
--- /dev/null
+++ b/packager/react-packager/src/__mocks__/graceful-fs.js
@@ -0,0 +1,11 @@
+/**
+ * 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.
+ */
+'use strict';
+
+module.exports = require('fs');

From 1dc56a6758c58ae7608bdc130afb7b831194f7ed Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Fri, 8 Jan 2016 10:11:46 -0800
Subject: [PATCH 0684/1411] Add support for global alert() on Android

Summary:
Use the new cross-platform [`Alert`](https://github.com/facebook/react-native/blob/master/Libraries/Utilities/Alert.js) API to implement global `alert()`.

public

Reviewed By: vjeux

Differential Revision: D2773589

fb-gh-sync-id: 4297c5dce6a55391af89d2675f2b9ac4dc715bb6
---
 .../Initialization/InitializeJavaScriptAppEngine.js    | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
index e1dcea29d76d..5f5f2e491be4 100644
--- a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
+++ b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
@@ -117,15 +117,11 @@ function setUpTimers() {
 }
 
 function setUpAlert() {
-  var RCTAlertManager = require('NativeModules').AlertManager;
   if (!GLOBAL.alert) {
     GLOBAL.alert = function(text) {
-      var alertOpts = {
-        title: 'Alert',
-        message: '' + text,
-        buttons: [{'cancel': 'OK'}],
-      };
-      RCTAlertManager.alertWithArgs(alertOpts, function () {});
+      // Require Alert on demand. Requiring it too early can lead to issues
+      // with things like Platform not being fully initialized.
+      require('Alert').alert('Alert', '' + text);
     };
   }
 }

From 8604bd1812e11987054912102a2c27bba21ea5c0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Fri, 8 Jan 2016 11:09:17 -0800
Subject: [PATCH 0685/1411] Add option to disable internal transforms

Reviewed By: davidaurelio

Differential Revision: D2815307

fb-gh-sync-id: 17ed8f13de7b4c41111efa4a5f2af5283e6ef3e0
---
 local-cli/bundle/buildBundle.js               |  1 +
 packager/react-packager/src/Bundler/index.js  |  5 +++
 .../react-packager/src/JSTransformer/index.js | 31 +++++++++++++------
 packager/react-packager/src/Server/index.js   |  6 +++-
 4 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/local-cli/bundle/buildBundle.js b/local-cli/bundle/buildBundle.js
index 6c946a8851a7..a5fea2d4f559 100644
--- a/local-cli/bundle/buildBundle.js
+++ b/local-cli/bundle/buildBundle.js
@@ -28,6 +28,7 @@ function buildBundle(args, config, output = outputBundle) {
       getTransformOptionsModulePath: config.getTransformOptionsModulePath,
       transformModulePath: args.transformer,
       verbose: args.verbose,
+      disableInternalTransforms: true,
     };
 
     const requestOpts = {
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index e7cb033dbb9f..3380a3ce0283 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -80,6 +80,10 @@ const validateOpts = declareOpts({
     type: 'number',
     required: false,
   },
+  disableInternalTransforms: {
+    type: 'boolean',
+    default: false,
+  },
 });
 
 class Bundler {
@@ -131,6 +135,7 @@ class Bundler {
       blacklistRE: opts.blacklistRE,
       cache: this._cache,
       transformModulePath: opts.transformModulePath,
+      disableInternalTransforms: opts.disableInternalTransforms,
     });
 
     this._projectRoots = opts.projectRoots;
diff --git a/packager/react-packager/src/JSTransformer/index.js b/packager/react-packager/src/JSTransformer/index.js
index 6cba12e51934..24de2fa2487f 100644
--- a/packager/react-packager/src/JSTransformer/index.js
+++ b/packager/react-packager/src/JSTransformer/index.js
@@ -54,6 +54,10 @@ const validateOpts = declareOpts({
     type: 'number',
     default: DEFAULT_MAX_CALL_TIME,
   },
+  disableInternalTransforms: {
+    type: 'boolean',
+    default: false,
+  },
 });
 
 class Transformer {
@@ -64,14 +68,20 @@ class Transformer {
     this._transformModulePath = opts.transformModulePath;
 
     if (opts.transformModulePath != null) {
-      this._workerWrapperPath = temp.path();
-      fs.writeFileSync(
-        this._workerWrapperPath,
-        `
-        module.exports = require(${JSON.stringify(require.resolve('./worker'))});
-        require(${JSON.stringify(String(opts.transformModulePath))});
-        `
-      );
+      let transformer;
+
+      if (opts.disableInternalTransforms) {
+        transformer = opts.transformModulePath;
+      } else {
+        transformer = this._workerWrapperPath = temp.path();
+        fs.writeFileSync(
+          this._workerWrapperPath,
+          `
+          module.exports = require(${JSON.stringify(require.resolve('./worker'))});
+          require(${JSON.stringify(String(opts.transformModulePath))});
+          `
+        );
+      }
 
       this._workers = workerFarm({
         autoStart: true,
@@ -79,7 +89,7 @@ class Transformer {
         maxCallsPerWorker: MAX_CALLS_PER_WORKER,
         maxCallTime: opts.transformTimeoutInterval,
         maxRetries: MAX_RETRIES,
-      }, this._workerWrapperPath);
+      }, transformer);
 
       this._transform = Promise.denodeify(this._workers);
     }
@@ -87,7 +97,8 @@ class Transformer {
 
   kill() {
     this._workers && workerFarm.end(this._workers);
-    if (typeof this._workerWrapperPath === 'string') {
+    if (this._workerWrapperPath &&
+        typeof this._workerWrapperPath === 'string') {
       fs.unlink(this._workerWrapperPath, () => {}); // we don't care about potential errors here
     }
   }
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index f5d284f2223a..fe7294bbcc8c 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -67,7 +67,11 @@ const validateOpts = declareOpts({
   getTransformOptionsModulePath: {
     type: 'string',
     required: false,
-  }
+  },
+  disableInternalTransforms: {
+    type: 'boolean',
+    default: false,
+  },
 });
 
 const bundleOpts = declareOpts({

From de392b5351494675220e0ef5176d8a8f3d473477 Mon Sep 17 00:00:00 2001
From: Oleg Lokhvitsky <olegbl@fb.com>
Date: Fri, 8 Jan 2016 11:41:30 -0800
Subject: [PATCH 0686/1411] Fix Network::FormData to support non-string,
 non-object values

Reviewed By: pvulgaris, nicklockwood

Differential Revision: D2805463

fb-gh-sync-id: 30e847760be1fe557497080adb8fa372f19f00c3
---
 Libraries/Network/FormData.js | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Libraries/Network/FormData.js b/Libraries/Network/FormData.js
index f6a4c4e2eacd..bbceb303f3c3 100644
--- a/Libraries/Network/FormData.js
+++ b/Libraries/Network/FormData.js
@@ -64,6 +64,11 @@ class FormData {
   getParts(): Array<FormDataPart> {
     return this._parts.map(([name, value]) => {
       var contentDisposition = 'form-data; name="' + name + '"';
+      // Convert non-object values to strings as per FormData.append() spec
+      if (typeof value !== 'object') {
+        value = '' + value;
+      }
+
       /* $FlowIssue(>=0.20.1) #9463928 */
       var headers: Headers = {'content-disposition': contentDisposition};
       if (typeof value === 'string') {

From bd7d10e5aace9eaee620409a1451356f02b837cc Mon Sep 17 00:00:00 2001
From: Andrew Jack <me@andrewjack.uk>
Date: Fri, 8 Jan 2016 12:11:34 -0800
Subject: [PATCH 0687/1411] Add support for Build Variants to react.gradle

Summary:
This PR adds support for Android Gradle [Build Variants](https://sites.google.com/a/android.com/tools/tech-docs/new-build-system/user-guide#TOC-Build-Variants) when generating the JS bundle.

**Before**: only supported "bundleDebugJsAndAssets" and "bundleReleaseJsAndAssets"

**Now**: all variants are supported
Examples: "bundleDevDebugJsAndAssets", "bundleStageAlphaJsAndAssets", or "bundleBetaJsAndAssets"

The Gradle script will automatically create bundle tasks for each build variant found in a project.
Closes https://github.com/facebook/react-native/pull/4686

Reviewed By: svcscm

Differential Revision: D2815856

Pulled By: foghina

fb-gh-sync-id: 4518de70d178205bc3e5044d2446b56c40298da2
---
 .../templates/src/app/build.gradle            |  10 +-
 .../templates/src/app/react.gradle            | 154 ++++++++----------
 2 files changed, 81 insertions(+), 83 deletions(-)

diff --git a/local-cli/generator-android/templates/src/app/build.gradle b/local-cli/generator-android/templates/src/app/build.gradle
index b68fc50c515e..68f2f417ff04 100644
--- a/local-cli/generator-android/templates/src/app/build.gradle
+++ b/local-cli/generator-android/templates/src/app/build.gradle
@@ -3,7 +3,8 @@ apply plugin: "com.android.application"
 import com.android.build.OutputFile
 
 /**
- * The react.gradle file registers two tasks: bundleDebugJsAndAssets and bundleReleaseJsAndAssets.
+ * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
+ * and bundleReleaseJsAndAssets).
  * These basically call `react-native bundle` with the correct arguments during the Android build
  * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
  * bundle directly from the development server. Below you can see all the possible configurations
@@ -23,6 +24,13 @@ import com.android.build.OutputFile
  *   // whether to bundle JS and assets in release mode
  *   bundleInRelease: true,
  *
+ *   // whether to bundle JS and assets in another build variant (if configured).
+ *   // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
+ *   // The configuration property is in the format 'bundleIn${productFlavor}${buildType}'
+ *   // bundleInFreeDebug: true,
+ *   // bundleInPaidRelease: true,
+ *   // bundleInBeta: true,
+ *
  *   // the root of your project, i.e. where "package.json" lives
  *   root: "../../",
  *
diff --git a/local-cli/generator-android/templates/src/app/react.gradle b/local-cli/generator-android/templates/src/app/react.gradle
index f2152d1f6848..4b43bf910cc8 100644
--- a/local-cli/generator-android/templates/src/app/react.gradle
+++ b/local-cli/generator-android/templates/src/app/react.gradle
@@ -11,69 +11,8 @@ def elvisFile(thing) {
 }
 
 def reactRoot = elvisFile(config.root) ?: file("../../")
-def jsBundleDirDebug = elvisFile(config.jsBundleDirDebug) ?:
-        file("$buildDir/intermediates/assets/debug")
-def jsBundleDirRelease = elvisFile(config.jsBundleDirRelease) ?:
-        file("$buildDir/intermediates/assets/release")
-def resourcesDirDebug = elvisFile(config.resourcesDirDebug) ?:
-        file("$buildDir/intermediates/res/merged/debug")
-def resourcesDirRelease = elvisFile(config.resourcesDirRelease) ?:
-        file("$buildDir/intermediates/res/merged/release")
 def inputExcludes = config.inputExcludes ?: ["android/**", "ios/**"]
 
-def jsBundleFileDebug = file("$jsBundleDirDebug/$bundleAssetName")
-def jsBundleFileRelease = file("$jsBundleDirRelease/$bundleAssetName")
-
-task bundleDebugJsAndAssets(type: Exec) {
-    // create dirs if they are not there (e.g. the "clean" task just ran)
-    doFirst {
-        jsBundleDirDebug.mkdirs()
-        resourcesDirDebug.mkdirs()
-    }
-
-    // set up inputs and outputs so gradle can cache the result
-    inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
-    outputs.dir jsBundleDirDebug
-    outputs.dir resourcesDirDebug
-
-    // set up the call to the react-native cli
-    workingDir reactRoot
-    if (Os.isFamily(Os.FAMILY_WINDOWS)) {
-        commandLine "cmd", "/c", "react-native", "bundle", "--platform", "android", "--dev", "true", "--entry-file",
-            entryFile, "--bundle-output", jsBundleFileDebug, "--assets-dest", resourcesDirDebug
-    } else {
-        commandLine "react-native", "bundle", "--platform", "android", "--dev", "true", "--entry-file",
-            entryFile, "--bundle-output", jsBundleFileDebug, "--assets-dest", resourcesDirDebug
-    }
-
-    enabled config.bundleInDebug ?: false
-}
-
-task bundleReleaseJsAndAssets(type: Exec) {
-    // create dirs if they are not there (e.g. the "clean" task just ran)
-    doFirst {
-        jsBundleDirRelease.mkdirs()
-        resourcesDirRelease.mkdirs()
-    }
-
-    // set up inputs and outputs so gradle can cache the result
-    inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
-    outputs.dir jsBundleDirRelease
-    outputs.dir resourcesDirRelease
-
-    // set up the call to the react-native cli
-    workingDir reactRoot
-    if (Os.isFamily(Os.FAMILY_WINDOWS)) {
-        commandLine "cmd","/c", "react-native", "bundle", "--platform", "android", "--dev", "false", "--entry-file",
-            entryFile, "--bundle-output", jsBundleFileRelease, "--assets-dest", resourcesDirRelease
-    } else {
-        commandLine "react-native", "bundle", "--platform", "android", "--dev", "false", "--entry-file",
-            entryFile, "--bundle-output", jsBundleFileRelease, "--assets-dest", resourcesDirRelease
-    }
-
-    enabled config.bundleInRelease ?: true
-}
-
 void runBefore(String dependentTaskName, Task task) {
     Task dependentTask = tasks.findByPath(dependentTaskName);
     if (dependentTask != null) {
@@ -82,25 +21,76 @@ void runBefore(String dependentTaskName, Task task) {
 }
 
 gradle.projectsEvaluated {
-
-    // hook bundleDebugJsAndAssets into the android build process
-
-    bundleDebugJsAndAssets.dependsOn mergeDebugResources
-    bundleDebugJsAndAssets.dependsOn mergeDebugAssets
-
-    runBefore('processArmeabi-v7aDebugResources', bundleDebugJsAndAssets)
-    runBefore('processX86DebugResources', bundleDebugJsAndAssets)
-    runBefore('processUniversalDebugResources', bundleDebugJsAndAssets)
-    runBefore('processDebugResources', bundleDebugJsAndAssets)
-
-    // hook bundleReleaseJsAndAssets into the android build process
-
-    bundleReleaseJsAndAssets.dependsOn mergeReleaseResources
-    bundleReleaseJsAndAssets.dependsOn mergeReleaseAssets
-
-    runBefore('processArmeabi-v7aReleaseResources', bundleReleaseJsAndAssets)
-    runBefore('processX86ReleaseResources', bundleReleaseJsAndAssets)
-    runBefore('processUniversalReleaseResources', bundleReleaseJsAndAssets)
-    runBefore('processReleaseResources', bundleReleaseJsAndAssets)
-
+    // Grab all build types and product flavors
+    def buildTypes = android.buildTypes.collect { type -> type.name }
+    def productFlavors = android.productFlavors.collect { flavor -> flavor.name }
+
+    // When no product flavors defined, use empty
+    if (!productFlavors) productFlavors.add('')
+
+    productFlavors.each { productFlavorName ->
+        buildTypes.each { buildTypeName ->
+            // Create variant and source names
+            def sourceName = "${buildTypeName}"
+            def targetName = "${sourceName.capitalize()}"
+            if (productFlavorName) {
+                sourceName = "${productFlavorName}${targetName}"
+            }
+
+            // React js bundle directories
+            def jsBundleDirConfigName = "jsBundleDir${targetName}"
+            def jsBundleDir = elvisFile(config."$jsBundleDirConfigName") ?:
+                    file("$buildDir/intermediates/assets/${sourceName}")
+
+            def resourcesDirConfigName = "jsBundleDir${targetName}"
+            def resourcesDir = elvisFile(config."${resourcesDirConfigName}") ?:
+                    file("$buildDir/intermediates/res/merged/${sourceName}")
+            def jsBundleFile = file("$jsBundleDir/$bundleAssetName")
+
+            // Bundle task name for variant
+            def bundleJsAndAssetsTaskName = "bundle${targetName}JsAndAssets"
+
+            def currentBundleTask = tasks.create(
+                    name: bundleJsAndAssetsTaskName,
+                    type: Exec) {
+                group = "react"
+                description = "bundle JS and assets for ${targetName}."
+
+                // Create dirs if they are not there (e.g. the "clean" task just ran)
+                doFirst {
+                    jsBundleDir.mkdirs()
+                    resourcesDir.mkdirs()
+                }
+
+                // Set up inputs and outputs so gradle can cache the result
+                inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
+                outputs.dir jsBundleDir
+                outputs.dir resourcesDir
+
+                // Set up the call to the react-native cli
+                workingDir reactRoot
+
+                // Set up dev mode
+                def devEnabled = !targetName.toLowerCase().contains("release")
+                if (Os.isFamily(Os.FAMILY_WINDOWS)) {
+                    commandLine "cmd", "/c", "react-native", "bundle", "--platform", "android", "--dev", "${devEnabled}",
+                            "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir
+                } else {
+                    commandLine "react-native", "bundle", "--platform", "android", "--dev", "${devEnabled}",
+                            "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir
+                }
+
+                enabled config."bundleIn${targetName}" ?: targetName.toLowerCase().contains("release")
+            }
+
+            // Hook bundle${productFlavor}${buildType}JsAndAssets into the android build process
+            currentBundleTask.dependsOn("merge${targetName}Resources")
+            currentBundleTask.dependsOn("merge${targetName}Assets")
+
+            runBefore("processArmeabi-v7a${targetName}Resources", currentBundleTask)
+            runBefore("processX86${targetName}Resources", currentBundleTask)
+            runBefore("processUniversal${targetName}Resources", currentBundleTask)
+            runBefore("process${targetName}Resources", currentBundleTask)
+        }
+    }
 }

From 2f3f84eecd54224a72242152056e588278aacbed Mon Sep 17 00:00:00 2001
From: Martin Bigio <martinb@fb.com>
Date: Fri, 8 Jan 2016 13:38:30 -0800
Subject: [PATCH 0688/1411] Bump timeout to track intermittent error

Reviewed By: sam-swarr

Differential Revision: D2816605

fb-gh-sync-id: 3d05746493f0ff97c396c82eb30d9a49537a0473
---
 packager/react-packager/src/JSTransformer/index.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packager/react-packager/src/JSTransformer/index.js b/packager/react-packager/src/JSTransformer/index.js
index 24de2fa2487f..14886d062438 100644
--- a/packager/react-packager/src/JSTransformer/index.js
+++ b/packager/react-packager/src/JSTransformer/index.js
@@ -25,7 +25,7 @@ const readFile = Promise.denodeify(fs.readFile);
 const MAX_CALLS_PER_WORKER = 600;
 
 // Worker will timeout if one of the callers timeout.
-const DEFAULT_MAX_CALL_TIME = 300000;
+const DEFAULT_MAX_CALL_TIME = 301000;
 
 // How may times can we tolerate failures from the worker.
 const MAX_RETRIES = 2;

From b6ef42299e22079c74a79a03e7e5165bb54246f4 Mon Sep 17 00:00:00 2001
From: Jiajie Zhu <zhujj04@fb.com>
Date: Fri, 8 Jan 2016 13:45:33 -0800
Subject: [PATCH 0689/1411] revert D2759498 to unbreak AMA release build

Reviewed By: AaaChiuuu

Differential Revision: D2816377

fb-gh-sync-id: 2b8821e4fcbde2bbd9e33d0175f49fdc794441fc
---
 .../react/ReactInstanceManagerImpl.java       |  20 +-
 ...faultNativeModuleCallExceptionHandler.java |  27 -
 .../react/devsupport/DevSupportManager.java   | 710 ++++++++++++++++-
 .../devsupport/DevSupportManagerImpl.java     | 722 ------------------
 .../devsupport/DisabledDevSupportManager.java | 116 ---
 5 files changed, 696 insertions(+), 899 deletions(-)
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/DefaultNativeModuleCallExceptionHandler.java
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java
 delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/devsupport/DisabledDevSupportManager.java

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index adb039d7ffee..c9bf17c610ce 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -52,8 +52,6 @@
 import com.facebook.react.common.annotations.VisibleForTesting;
 import com.facebook.react.devsupport.DevServerHelper;
 import com.facebook.react.devsupport.DevSupportManager;
-import com.facebook.react.devsupport.DevSupportManagerImpl;
-import com.facebook.react.devsupport.DisabledDevSupportManager;
 import com.facebook.react.devsupport.ReactInstanceDevCommandsHandler;
 import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
 import com.facebook.react.modules.core.DeviceEventManagerModule;
@@ -254,15 +252,15 @@ public T get() throws Exception {
     mJSMainModuleName = jsMainModuleName;
     mPackages = packages;
     mUseDeveloperSupport = useDeveloperSupport;
-    if (mUseDeveloperSupport) {
-      mDevSupportManager = new DevSupportManagerImpl(
-          applicationContext,
-          mDevInterface,
-          mJSMainModuleName,
-          useDeveloperSupport);
-    } else {
-      mDevSupportManager = new DisabledDevSupportManager();
-    }
+    // We need to instantiate DevSupportManager regardless to the useDeveloperSupport option,
+    // although will prevent dev support manager from displaying any options or dialogs by
+    // checking useDeveloperSupport option before calling setDevSupportEnabled on this manager
+    // TODO(6803830): Don't instantiate devsupport manager when useDeveloperSupport is false
+    mDevSupportManager = new DevSupportManager(
+        applicationContext,
+        mDevInterface,
+        mJSMainModuleName,
+        useDeveloperSupport);
     mBridgeIdleDebugListener = bridgeIdleDebugListener;
     mLifecycleState = initialLifecycleState;
     mUIImplementationProvider = uiImplementationProvider;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/DefaultNativeModuleCallExceptionHandler.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/DefaultNativeModuleCallExceptionHandler.java
deleted file mode 100644
index 4d47156c7479..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/DefaultNativeModuleCallExceptionHandler.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * 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.
- */
-
-package com.facebook.react.bridge;
-
-/**
- * Crashy crashy exception handler.
- */
-public class DefaultNativeModuleCallExceptionHandler implements NativeModuleCallExceptionHandler {
-
-  @Override
-  public void handleException(Exception e) {
-    if (e instanceof RuntimeException) {
-      // Because we are rethrowing the original exception, the original stacktrace will be
-      // preserved.
-      throw (RuntimeException) e;
-    } else {
-      throw new RuntimeException(e);
-    }
-  }
-}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
index 4f114ded6099..cf86bd3b3547 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
@@ -9,34 +9,698 @@
 
 package com.facebook.react.devsupport;
 
+import javax.annotation.Nullable;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.hardware.SensorManager;
+import android.os.Debug;
+import android.os.Environment;
+import android.view.WindowManager;
+import android.widget.Toast;
+
+import com.facebook.common.logging.FLog;
+import com.facebook.infer.annotation.Assertions;
+import com.facebook.react.R;
+import com.facebook.react.bridge.CatalystInstance;
+import com.facebook.react.bridge.JavaJSExecutor;
 import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.UiThreadUtil;
+import com.facebook.react.bridge.WebsocketJavaScriptExecutor;
+import com.facebook.react.common.ReactConstants;
+import com.facebook.react.common.ShakeDetector;
+import com.facebook.react.common.futures.SimpleSettableFuture;
+import com.facebook.react.devsupport.StackTraceHelper.StackFrame;
 import com.facebook.react.modules.debug.DeveloperSettings;
 
 /**
- * Interface for accessing and interacting with development features.
- * In dev mode, use the implementation {@link DevSupportManagerImpl}.
- * In production mode, use the dummy implementation {@link DisabledDevSupportManager}.
+ * Interface for accessing and interacting with development features. Following features
+ * are supported through this manager class:
+ * 1) Displaying JS errors (aka RedBox)
+ * 2) Displaying developers menu (Reload JS, Debug JS)
+ * 3) Communication with developer server in order to download updated JS bundle
+ * 4) Starting/stopping broadcast receiver for js reload signals
+ * 5) Starting/stopping motion sensor listener that recognize shake gestures which in turn may
+ *    trigger developers menu.
+ * 6) Launching developers settings view
+ *
+ * This class automatically monitors the state of registered views and activities to which they are
+ * bound to make sure that we don't display overlay or that we we don't listen for sensor events
+ * when app is backgrounded.
+ *
+ * {@link ReactInstanceDevCommandsHandler} implementation is responsible for instantiating this
+ * instance and for populating with an instance of {@link CatalystInstance} whenever instance
+ * manager recreates it (through {@link #onNewCatalystContextCreated}). Also, instance manager is
+ * responsible for enabling/disabling dev support in case when app is backgrounded or when all the
+ * views has been detached from the instance (through {@link #setDevSupportEnabled} method).
+ *
+ * IMPORTANT: In order for developer support to work correctly it is required that the
+ * manifest of your application contain the following entries:
+ * {@code <activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>}
+ * {@code <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>}
  */
-public interface DevSupportManager extends NativeModuleCallExceptionHandler {
-
-  void showNewJavaError(String message, Throwable e);
-  void addCustomDevOption(String optionName, DevOptionHandler optionHandler);
-  void showNewJSError(String message, ReadableArray details, int errorCookie);
-  void updateJSError(final String message, final ReadableArray details, final int errorCookie);
-  void showDevOptionsDialog();
-  void setDevSupportEnabled(boolean isDevSupportEnabled);
-  boolean getDevSupportEnabled();
-  DeveloperSettings getDevSettings();
-  void onNewReactContextCreated(ReactContext reactContext);
-  void onReactInstanceDestroyed(ReactContext reactContext);
-  String getSourceMapUrl();
-  String getSourceUrl();
-  String getJSBundleURLForRemoteDebugging();
-  String getDownloadedJSBundleFile();
-  boolean hasUpToDateJSBundleInCache();
-  void reloadSettings();
-  void handleReloadJS();
-  void isPackagerRunning(DevServerHelper.PackagerStatusCallback callback);
+public class DevSupportManager implements NativeModuleCallExceptionHandler {
+
+  private static final int JAVA_ERROR_COOKIE = -1;
+  private static final String JS_BUNDLE_FILE_NAME = "ReactNativeDevBundle.js";
+
+  private static final String EXOPACKAGE_LOCATION_FORMAT
+      = "/data/local/tmp/exopackage/%s//secondary-dex";
+
+  private static final int JAVA_SAMPLING_PROFILE_MEMORY_BYTES = 8 * 1024 * 1024;
+  private static final int JAVA_SAMPLING_PROFILE_DELTA_US = 100;
+
+  private final Context mApplicationContext;
+  private final ShakeDetector mShakeDetector;
+  private final BroadcastReceiver mReloadAppBroadcastReceiver;
+  private final DevServerHelper mDevServerHelper;
+  private final LinkedHashMap<String, DevOptionHandler> mCustomDevOptions =
+      new LinkedHashMap<>();
+  private final ReactInstanceDevCommandsHandler mReactInstanceCommandsHandler;
+  private final @Nullable String mJSAppBundleName;
+  private final File mJSBundleTempFile;
+
+  private @Nullable RedBoxDialog mRedBoxDialog;
+  private @Nullable AlertDialog mDevOptionsDialog;
+  private @Nullable DebugOverlayController mDebugOverlayController;
+  private @Nullable ReactContext mCurrentContext;
+  private DevInternalSettings mDevSettings;
+  private boolean mIsUsingJSProxy = false;
+  private boolean mIsReceiverRegistered = false;
+  private boolean mIsShakeDetectorStarted = false;
+  private boolean mIsDevSupportEnabled = false;
+  private boolean mIsCurrentlyProfiling = false;
+  private int     mProfileIndex = 0;
+
+  public DevSupportManager(
+      Context applicationContext,
+      ReactInstanceDevCommandsHandler reactInstanceCommandsHandler,
+      @Nullable String packagerPathForJSBundleName,
+      boolean enableOnCreate) {
+    mReactInstanceCommandsHandler = reactInstanceCommandsHandler;
+    mApplicationContext = applicationContext;
+    mJSAppBundleName = packagerPathForJSBundleName;
+    mDevSettings = new DevInternalSettings(applicationContext, this);
+    mDevServerHelper = new DevServerHelper(mDevSettings);
+
+    // Prepare shake gesture detector (will be started/stopped from #reload)
+    mShakeDetector = new ShakeDetector(new ShakeDetector.ShakeListener() {
+      @Override
+      public void onShake() {
+        showDevOptionsDialog();
+      }
+    });
+
+    // Prepare reload APP broadcast receiver (will be registered/unregistered from #reload)
+    mReloadAppBroadcastReceiver = new BroadcastReceiver() {
+      @Override
+      public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+        if (DevServerHelper.getReloadAppAction(context).equals(action)) {
+          if (intent.getBooleanExtra(DevServerHelper.RELOAD_APP_EXTRA_JS_PROXY, false)) {
+            mIsUsingJSProxy = true;
+            mDevServerHelper.launchChromeDevtools();
+          } else {
+            mIsUsingJSProxy = false;
+          }
+          handleReloadJS();
+        }
+      }
+    };
+
+    // We store JS bundle loaded from dev server in a single destination in app's data dir.
+    // In case when someone schedule 2 subsequent reloads it may happen that JS thread will
+    // start reading first reload output while the second reload starts writing to the same
+    // file. As this should only be the case in dev mode we leave it as it is.
+    // TODO(6418010): Fix readers-writers problem in debug reload from HTTP server
+    mJSBundleTempFile = new File(applicationContext.getFilesDir(), JS_BUNDLE_FILE_NAME);
+
+    setDevSupportEnabled(enableOnCreate);
+  }
+
+  @Override
+  public void handleException(Exception e) {
+    if (mIsDevSupportEnabled) {
+      FLog.e(ReactConstants.TAG, "Exception in native call from JS", e);
+      showNewJavaError(e.getMessage(), e);
+    } else {
+      if (e instanceof RuntimeException) {
+        // Because we are rethrowing the original exception, the original stacktrace will be
+        // preserved
+        throw (RuntimeException) e;
+      } else {
+        throw new RuntimeException(e);
+      }
+    }
+  }
+
+  public void showNewJavaError(String message, Throwable e) {
+    showNewError(message, StackTraceHelper.convertJavaStackTrace(e), JAVA_ERROR_COOKIE);
+  }
+
+  /**
+   * Add option item to dev settings dialog displayed by this manager. In the case user select given
+   * option from that dialog, the appropriate handler passed as {@param optionHandler} will be
+   * called.
+   */
+  public void addCustomDevOption(
+      String optionName,
+      DevOptionHandler optionHandler) {
+    mCustomDevOptions.put(optionName, optionHandler);
+  }
+
+  public void showNewJSError(String message, ReadableArray details, int errorCookie) {
+    showNewError(message, StackTraceHelper.convertJsStackTrace(details), errorCookie);
+  }
+
+  public void updateJSError(
+      final String message,
+      final ReadableArray details,
+      final int errorCookie) {
+    UiThreadUtil.runOnUiThread(
+        new Runnable() {
+          @Override
+          public void run() {
+            // Since we only show the first JS error in a succession of JS errors, make sure we only
+            // update the error message for that error message. This assumes that updateJSError
+            // belongs to the most recent showNewJSError
+            if (mRedBoxDialog == null ||
+                !mRedBoxDialog.isShowing() ||
+                errorCookie != mRedBoxDialog.getErrorCookie()) {
+              return;
+            }
+            mRedBoxDialog.setExceptionDetails(
+                message,
+                StackTraceHelper.convertJsStackTrace(details));
+            mRedBoxDialog.show();
+          }
+        });
+  }
+
+  private void showNewError(
+      final String message,
+      final StackFrame[] stack,
+      final int errorCookie) {
+    UiThreadUtil.runOnUiThread(
+        new Runnable() {
+          @Override
+          public void run() {
+            if (mRedBoxDialog == null) {
+              mRedBoxDialog = new RedBoxDialog(mApplicationContext, DevSupportManager.this);
+              mRedBoxDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+            }
+            if (mRedBoxDialog.isShowing()) {
+              // Sometimes errors cause multiple errors to be thrown in JS in quick succession. Only
+              // show the first and most actionable one.
+              return;
+            }
+            mRedBoxDialog.setExceptionDetails(message, stack);
+            mRedBoxDialog.setErrorCookie(errorCookie);
+            mRedBoxDialog.show();
+          }
+        });
+  }
+
+  public void showDevOptionsDialog() {
+    if (mDevOptionsDialog != null || !mIsDevSupportEnabled) {
+      return;
+    }
+    LinkedHashMap<String, DevOptionHandler> options = new LinkedHashMap<>();
+    /* register standard options */
+    options.put(
+        mApplicationContext.getString(R.string.catalyst_reloadjs), new DevOptionHandler() {
+          @Override
+          public void onOptionSelected() {
+            handleReloadJS();
+          }
+        });
+    options.put(
+        mIsUsingJSProxy ?
+            mApplicationContext.getString(R.string.catalyst_debugjs_off) :
+            mApplicationContext.getString(R.string.catalyst_debugjs),
+        new DevOptionHandler() {
+          @Override
+          public void onOptionSelected() {
+            mIsUsingJSProxy = !mIsUsingJSProxy;
+            handleReloadJS();
+          }
+        });
+    options.put(
+            mDevSettings.isHotModuleReplacementEnabled()
+                    ? mApplicationContext.getString(R.string.catalyst_hot_module_replacement_off)
+                    : mApplicationContext.getString(R.string.catalyst_hot_module_replacement),
+            new DevOptionHandler() {
+              @Override
+              public void onOptionSelected() {
+                mDevSettings.setHotModuleReplacementEnabled(!mDevSettings.isHotModuleReplacementEnabled());
+                handleReloadJS();
+              }
+            });
+    options.put(
+        mDevSettings.isReloadOnJSChangeEnabled()
+            ? mApplicationContext.getString(R.string.catalyst_live_reload_off)
+            : mApplicationContext.getString(R.string.catalyst_live_reload),
+        new DevOptionHandler() {
+          @Override
+          public void onOptionSelected() {
+            mDevSettings.setReloadOnJSChangeEnabled(!mDevSettings.isReloadOnJSChangeEnabled());
+          }
+        });
+    options.put(
+        mDevSettings.isElementInspectorEnabled()
+          ? mApplicationContext.getString(R.string.catalyst_element_inspector_off)
+          : mApplicationContext.getString(R.string.catalyst_element_inspector),
+        new DevOptionHandler() {
+          @Override
+          public void onOptionSelected() {
+            mDevSettings.setElementInspectorEnabled(!mDevSettings.isElementInspectorEnabled());
+            mReactInstanceCommandsHandler.toggleElementInspector();
+          }
+        });
+    options.put(
+        mDevSettings.isFpsDebugEnabled()
+            ? mApplicationContext.getString(R.string.catalyst_perf_monitor_off)
+            : mApplicationContext.getString(R.string.catalyst_perf_monitor),
+        new DevOptionHandler() {
+          @Override
+          public void onOptionSelected() {
+            mDevSettings.setFpsDebugEnabled(!mDevSettings.isFpsDebugEnabled());
+          }
+        });
+    if (mCurrentContext != null &&
+        mCurrentContext.getCatalystInstance() != null &&
+        !mCurrentContext.getCatalystInstance().isDestroyed() &&
+        mCurrentContext.getCatalystInstance().supportsProfiling()) {
+      options.put(
+          mApplicationContext.getString(
+              mIsCurrentlyProfiling ? R.string.catalyst_stop_profile :
+                  R.string.catalyst_start_profile),
+          new DevOptionHandler() {
+            @Override
+            public void onOptionSelected() {
+              if (mCurrentContext != null && mCurrentContext.hasActiveCatalystInstance()) {
+                String profileName = (Environment.getExternalStorageDirectory().getPath() +
+                    "/profile_" + mProfileIndex + ".json");
+                if (mIsCurrentlyProfiling) {
+                  mIsCurrentlyProfiling = false;
+                  mProfileIndex++;
+                  Debug.stopMethodTracing();
+                  mCurrentContext.getCatalystInstance()
+                      .stopProfiler("profile", profileName);
+                  Toast.makeText(
+                      mCurrentContext,
+                      "Profile output to " + profileName,
+                      Toast.LENGTH_LONG).show();
+                } else {
+                  mIsCurrentlyProfiling = true;
+                  mCurrentContext.getCatalystInstance().startProfiler("profile");
+                  Debug.startMethodTracingSampling(
+                      profileName,
+                      JAVA_SAMPLING_PROFILE_MEMORY_BYTES,
+                      JAVA_SAMPLING_PROFILE_DELTA_US);
+                }
+              }
+            }
+          });
+    }
+    options.put(
+        mApplicationContext.getString(R.string.catalyst_settings), new DevOptionHandler() {
+          @Override
+          public void onOptionSelected() {
+            Intent intent = new Intent(mApplicationContext, DevSettingsActivity.class);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            mApplicationContext.startActivity(intent);
+          }
+        });
+
+    if (mCustomDevOptions.size() > 0) {
+      options.putAll(mCustomDevOptions);
+    }
+
+    final DevOptionHandler[] optionHandlers = options.values().toArray(new DevOptionHandler[0]);
+
+    mDevOptionsDialog =
+        new AlertDialog.Builder(mApplicationContext)
+            .setItems(
+                options.keySet().toArray(new String[0]),
+                new DialogInterface.OnClickListener() {
+                  @Override
+                  public void onClick(DialogInterface dialog, int which) {
+                    optionHandlers[which].onOptionSelected();
+                    mDevOptionsDialog = null;
+                  }
+                })
+            .setOnCancelListener(new DialogInterface.OnCancelListener() {
+              @Override
+              public void onCancel(DialogInterface dialog) {
+                mDevOptionsDialog = null;
+              }
+            })
+            .create();
+    mDevOptionsDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+    mDevOptionsDialog.show();
+  }
+
+  /**
+   * {@link ReactInstanceDevCommandsHandler} is responsible for
+   * enabling/disabling dev support when a React view is attached/detached
+   * or when application state changes (e.g. the application is backgrounded).
+   */
+  public void setDevSupportEnabled(boolean isDevSupportEnabled) {
+    mIsDevSupportEnabled = isDevSupportEnabled;
+    reload();
+  }
+
+  public boolean getDevSupportEnabled() {
+    return mIsDevSupportEnabled;
+  }
+
+  public DeveloperSettings getDevSettings() {
+    return mDevSettings;
+  }
+
+  public void onNewReactContextCreated(ReactContext reactContext) {
+    resetCurrentContext(reactContext);
+  }
+
+  public void onReactInstanceDestroyed(ReactContext reactContext) {
+    if (reactContext == mCurrentContext) {
+      // only call reset context when the destroyed context matches the one that is currently set
+      // for this manager
+      resetCurrentContext(null);
+    }
+  }
+
+  public String getSourceMapUrl() {
+    if (mJSAppBundleName == null) {
+      return "";
+    }
+
+    return mDevServerHelper.getSourceMapUrl(Assertions.assertNotNull(mJSAppBundleName));
+  }
+
+  public String getSourceUrl() {
+    if (mJSAppBundleName == null) {
+      return "";
+    }
+
+    return mDevServerHelper.getSourceUrl(Assertions.assertNotNull(mJSAppBundleName));
+  }
+
+  public String getJSBundleURLForRemoteDebugging() {
+    return mDevServerHelper.getJSBundleURLForRemoteDebugging(
+        Assertions.assertNotNull(mJSAppBundleName));
+  }
+
+  public String getDownloadedJSBundleFile() {
+    return mJSBundleTempFile.getAbsolutePath();
+  }
+
+  /**
+   * @return {@code true} if {@link ReactInstanceManager} should use downloaded JS bundle file
+   * instead of using JS file from assets. This may happen when app has not been updated since
+   * the last time we fetched the bundle.
+   */
+  public boolean hasUpToDateJSBundleInCache() {
+    if (mIsDevSupportEnabled && mJSBundleTempFile.exists()) {
+      try {
+        String packageName = mApplicationContext.getPackageName();
+        PackageInfo thisPackage = mApplicationContext.getPackageManager()
+            .getPackageInfo(packageName, 0);
+        if (mJSBundleTempFile.lastModified() > thisPackage.lastUpdateTime) {
+          // Base APK has not been updated since we donwloaded JS, but if app is using exopackage
+          // it may only be a single dex that has been updated. We check for exopackage dir update
+          // time in that case.
+          File exopackageDir = new File(
+              String.format(Locale.US, EXOPACKAGE_LOCATION_FORMAT, packageName));
+          if (exopackageDir.exists()) {
+            return mJSBundleTempFile.lastModified() > exopackageDir.lastModified();
+          }
+          return true;
+        }
+      } catch (PackageManager.NameNotFoundException e) {
+        // Ignore this error and just fallback to loading JS from assets
+        FLog.e(ReactConstants.TAG, "DevSupport is unable to get current app info");
+      }
+    }
+    return false;
+  }
+
+  /**
+   * @return {@code true} if JS bundle {@param bundleAssetName} exists, in that case
+   * {@link ReactInstanceManager} should use that file from assets instead of downloading bundle
+   * from dev server
+   */
+  public boolean hasBundleInAssets(String bundleAssetName) {
+    try {
+      String[] assets = mApplicationContext.getAssets().list("");
+      for (int i = 0; i < assets.length; i++) {
+        if (assets[i].equals(bundleAssetName)) {
+          return true;
+        }
+      }
+    } catch (IOException e) {
+      // Ignore this error and just fallback to downloading JS from devserver
+      FLog.e(ReactConstants.TAG, "Error while loading assets list");
+    }
+    return false;
+  }
+
+  private void resetCurrentContext(@Nullable ReactContext reactContext) {
+    if (mCurrentContext == reactContext) {
+      // new context is the same as the old one - do nothing
+      return;
+    }
+
+    // if currently profiling stop and write the profile file
+    if (mIsCurrentlyProfiling) {
+      mIsCurrentlyProfiling = false;
+      String profileName = (Environment.getExternalStorageDirectory().getPath() +
+          "/profile_" + mProfileIndex + ".json");
+      mProfileIndex++;
+      Debug.stopMethodTracing();
+      mCurrentContext.getCatalystInstance().stopProfiler("profile", profileName);
+    }
+
+    mCurrentContext = reactContext;
+
+    // Recreate debug overlay controller with new CatalystInstance object
+    if (mDebugOverlayController != null) {
+      mDebugOverlayController.setFpsDebugViewVisible(false);
+    }
+    if (reactContext != null) {
+      mDebugOverlayController = new DebugOverlayController(reactContext);
+    }
+
+    reloadSettings();
+  }
+
+  /* package */ void reloadSettings() {
+    reload();
+  }
+
+  public void handleReloadJS() {
+    UiThreadUtil.assertOnUiThread();
+
+    // dismiss redbox if exists
+    if (mRedBoxDialog != null) {
+      mRedBoxDialog.dismiss();
+    }
+
+    ProgressDialog progressDialog = new ProgressDialog(mApplicationContext);
+    progressDialog.setTitle(R.string.catalyst_jsload_title);
+    progressDialog.setMessage(mApplicationContext.getString(
+        mIsUsingJSProxy ? R.string.catalyst_remotedbg_message : R.string.catalyst_jsload_message));
+    progressDialog.setIndeterminate(true);
+    progressDialog.setCancelable(false);
+    progressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+    progressDialog.show();
+
+    if (mIsUsingJSProxy) {
+      reloadJSInProxyMode(progressDialog);
+    } else {
+      reloadJSFromServer(progressDialog);
+    }
+  }
+
+  public void isPackagerRunning(DevServerHelper.PackagerStatusCallback callback) {
+    mDevServerHelper.isPackagerRunning(callback);
+  }
+
+  private void reloadJSInProxyMode(final ProgressDialog progressDialog) {
+    // When using js proxy, there is no need to fetch JS bundle as proxy executor will do that
+    // anyway
+    mDevServerHelper.launchChromeDevtools();
+
+    JavaJSExecutor.Factory factory = new JavaJSExecutor.Factory() {
+      @Override
+      public JavaJSExecutor create() throws Exception {
+        WebsocketJavaScriptExecutor executor = new WebsocketJavaScriptExecutor();
+        SimpleSettableFuture<Boolean> future = new SimpleSettableFuture<>();
+        executor.connect(
+            mDevServerHelper.getWebsocketProxyURL(),
+            getExecutorConnectCallback(progressDialog, future));
+        // TODO(t9349129) Don't use timeout
+        try {
+          future.get(90, TimeUnit.SECONDS);
+          return executor;
+        } catch (ExecutionException e) {
+          throw (Exception) e.getCause();
+        } catch (InterruptedException | TimeoutException e) {
+          throw new RuntimeException(e);
+        }
+      }
+    };
+    mReactInstanceCommandsHandler.onReloadWithJSDebugger(factory);
+  }
+
+  private WebsocketJavaScriptExecutor.JSExecutorConnectCallback getExecutorConnectCallback(
+      final ProgressDialog progressDialog,
+      final SimpleSettableFuture<Boolean> future) {
+    return new WebsocketJavaScriptExecutor.JSExecutorConnectCallback() {
+      @Override
+      public void onSuccess() {
+        future.set(true);
+        progressDialog.dismiss();
+      }
+
+      @Override
+      public void onFailure(final Throwable cause) {
+        progressDialog.dismiss();
+        FLog.e(ReactConstants.TAG, "Unable to connect to remote debugger", cause);
+        future.setException(
+            new IOException(
+                mApplicationContext.getString(R.string.catalyst_remotedbg_error), cause));
+      }
+    };
+  }
+
+  private void reloadJSFromServer(final ProgressDialog progressDialog) {
+    mDevServerHelper.downloadBundleFromURL(
+        new DevServerHelper.BundleDownloadCallback() {
+          @Override
+          public void onSuccess() {
+            progressDialog.dismiss();
+            UiThreadUtil.runOnUiThread(
+                new Runnable() {
+                  @Override
+                  public void run() {
+                    mReactInstanceCommandsHandler.onJSBundleLoadedFromServer();
+                  }
+                });
+          }
+
+          @Override
+          public void onFailure(final Exception cause) {
+            progressDialog.dismiss();
+            FLog.e(ReactConstants.TAG, "Unable to download JS bundle", cause);
+            UiThreadUtil.runOnUiThread(
+                new Runnable() {
+                  @Override
+                  public void run() {
+                    if (cause instanceof DebugServerException) {
+                      DebugServerException debugServerException = (DebugServerException) cause;
+                      showNewJavaError(debugServerException.description, cause);
+                    } else {
+                      showNewJavaError(
+                          mApplicationContext.getString(R.string.catalyst_jsload_error),
+                          cause);
+                    }
+                  }
+                });
+          }
+        },
+        Assertions.assertNotNull(mJSAppBundleName),
+        mJSBundleTempFile);
+    progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+      @Override
+      public void onCancel(DialogInterface dialog) {
+        mDevServerHelper.cancelDownloadBundleFromURL();
+      }
+    });
+    progressDialog.setCancelable(true);
+  }
+
+  private void reload() {
+    // reload settings, show/hide debug overlay if required & start/stop shake detector
+    if (mIsDevSupportEnabled) {
+      // update visibility of FPS debug overlay depending on the settings
+      if (mDebugOverlayController != null) {
+        mDebugOverlayController.setFpsDebugViewVisible(mDevSettings.isFpsDebugEnabled());
+      }
+
+      // start shake gesture detector
+      if (!mIsShakeDetectorStarted) {
+        mShakeDetector.start(
+            (SensorManager) mApplicationContext.getSystemService(Context.SENSOR_SERVICE));
+        mIsShakeDetectorStarted = true;
+      }
+
+      // register reload app broadcast receiver
+      if (!mIsReceiverRegistered) {
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(DevServerHelper.getReloadAppAction(mApplicationContext));
+        mApplicationContext.registerReceiver(mReloadAppBroadcastReceiver, filter);
+        mIsReceiverRegistered = true;
+      }
+
+      if (mDevSettings.isReloadOnJSChangeEnabled()) {
+        mDevServerHelper.startPollingOnChangeEndpoint(
+            new DevServerHelper.OnServerContentChangeListener() {
+          @Override
+          public void onServerContentChanged() {
+            handleReloadJS();
+          }
+        });
+      } else {
+        mDevServerHelper.stopPollingOnChangeEndpoint();
+      }
+    } else {
+      // hide FPS debug overlay
+      if (mDebugOverlayController != null) {
+        mDebugOverlayController.setFpsDebugViewVisible(false);
+      }
+
+      // stop shake gesture detector
+      if (mIsShakeDetectorStarted) {
+        mShakeDetector.stop();
+        mIsShakeDetectorStarted = false;
+      }
+
+      // unregister app reload broadcast receiver
+      if (mIsReceiverRegistered) {
+        mApplicationContext.unregisterReceiver(mReloadAppBroadcastReceiver);
+        mIsReceiverRegistered = false;
+      }
+
+      // hide redbox dialog
+      if (mRedBoxDialog != null) {
+        mRedBoxDialog.dismiss();
+      }
+
+      // hide dev options dialog
+      if (mDevOptionsDialog != null) {
+        mDevOptionsDialog.dismiss();
+      }
+
+      mDevServerHelper.stopPollingOnChangeEndpoint();
+    }
+  }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java
deleted file mode 100644
index 7bdeea2d7ce5..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java
+++ /dev/null
@@ -1,722 +0,0 @@
-/**
- * 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.
- */
-
-package com.facebook.react.devsupport;
-
-import javax.annotation.Nullable;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.LinkedHashMap;
-import java.util.Locale;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import android.app.AlertDialog;
-import android.app.ProgressDialog;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.hardware.SensorManager;
-import android.os.Debug;
-import android.os.Environment;
-import android.view.WindowManager;
-import android.widget.Toast;
-
-import com.facebook.common.logging.FLog;
-import com.facebook.infer.annotation.Assertions;
-import com.facebook.react.R;
-import com.facebook.react.bridge.CatalystInstance;
-import com.facebook.react.bridge.DefaultNativeModuleCallExceptionHandler;
-import com.facebook.react.bridge.JavaJSExecutor;
-import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
-import com.facebook.react.bridge.ReactContext;
-import com.facebook.react.bridge.ReadableArray;
-import com.facebook.react.bridge.UiThreadUtil;
-import com.facebook.react.bridge.WebsocketJavaScriptExecutor;
-import com.facebook.react.common.ReactConstants;
-import com.facebook.react.common.ShakeDetector;
-import com.facebook.react.common.futures.SimpleSettableFuture;
-import com.facebook.react.devsupport.StackTraceHelper.StackFrame;
-import com.facebook.react.modules.debug.DeveloperSettings;
-
-/**
- * Interface for accessing and interacting with development features. Following features
- * are supported through this manager class:
- * 1) Displaying JS errors (aka RedBox)
- * 2) Displaying developers menu (Reload JS, Debug JS)
- * 3) Communication with developer server in order to download updated JS bundle
- * 4) Starting/stopping broadcast receiver for js reload signals
- * 5) Starting/stopping motion sensor listener that recognize shake gestures which in turn may
- *    trigger developers menu.
- * 6) Launching developers settings view
- *
- * This class automatically monitors the state of registered views and activities to which they are
- * bound to make sure that we don't display overlay or that we we don't listen for sensor events
- * when app is backgrounded.
- *
- * {@link ReactInstanceDevCommandsHandler} implementation is responsible for instantiating this
- * instance and for populating with an instance of {@link CatalystInstance} whenever instance
- * manager recreates it (through {@link #onNewCatalystContextCreated}). Also, instance manager is
- * responsible for enabling/disabling dev support in case when app is backgrounded or when all the
- * views has been detached from the instance (through {@link #setDevSupportEnabled} method).
- *
- * IMPORTANT: In order for developer support to work correctly it is required that the
- * manifest of your application contain the following entries:
- * {@code <activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>}
- * {@code <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>}
- */
-public class DevSupportManagerImpl implements DevSupportManager {
-
-  private static final int JAVA_ERROR_COOKIE = -1;
-  private static final String JS_BUNDLE_FILE_NAME = "ReactNativeDevBundle.js";
-
-  private static final String EXOPACKAGE_LOCATION_FORMAT
-      = "/data/local/tmp/exopackage/%s//secondary-dex";
-
-  private static final int JAVA_SAMPLING_PROFILE_MEMORY_BYTES = 8 * 1024 * 1024;
-  private static final int JAVA_SAMPLING_PROFILE_DELTA_US = 100;
-
-  private final Context mApplicationContext;
-  private final ShakeDetector mShakeDetector;
-  private final BroadcastReceiver mReloadAppBroadcastReceiver;
-  private final DevServerHelper mDevServerHelper;
-  private final LinkedHashMap<String, DevOptionHandler> mCustomDevOptions =
-      new LinkedHashMap<>();
-  private final ReactInstanceDevCommandsHandler mReactInstanceCommandsHandler;
-  private final @Nullable String mJSAppBundleName;
-  private final File mJSBundleTempFile;
-  private final DefaultNativeModuleCallExceptionHandler mDefaultNativeModuleCallExceptionHandler;
-
-  private @Nullable RedBoxDialog mRedBoxDialog;
-  private @Nullable AlertDialog mDevOptionsDialog;
-  private @Nullable DebugOverlayController mDebugOverlayController;
-  private @Nullable ReactContext mCurrentContext;
-  private DevInternalSettings mDevSettings;
-  private boolean mIsUsingJSProxy = false;
-  private boolean mIsReceiverRegistered = false;
-  private boolean mIsShakeDetectorStarted = false;
-  private boolean mIsDevSupportEnabled = false;
-  private boolean mIsCurrentlyProfiling = false;
-  private int     mProfileIndex = 0;
-
-  public DevSupportManagerImpl(
-      Context applicationContext,
-      ReactInstanceDevCommandsHandler reactInstanceCommandsHandler,
-      @Nullable String packagerPathForJSBundleName,
-      boolean enableOnCreate) {
-    mReactInstanceCommandsHandler = reactInstanceCommandsHandler;
-    mApplicationContext = applicationContext;
-    mJSAppBundleName = packagerPathForJSBundleName;
-    mDevSettings = new DevInternalSettings(applicationContext, this);
-    mDevServerHelper = new DevServerHelper(mDevSettings);
-
-    // Prepare shake gesture detector (will be started/stopped from #reload)
-    mShakeDetector = new ShakeDetector(new ShakeDetector.ShakeListener() {
-      @Override
-      public void onShake() {
-        showDevOptionsDialog();
-      }
-    });
-
-    // Prepare reload APP broadcast receiver (will be registered/unregistered from #reload)
-    mReloadAppBroadcastReceiver = new BroadcastReceiver() {
-      @Override
-      public void onReceive(Context context, Intent intent) {
-        String action = intent.getAction();
-        if (DevServerHelper.getReloadAppAction(context).equals(action)) {
-          if (intent.getBooleanExtra(DevServerHelper.RELOAD_APP_EXTRA_JS_PROXY, false)) {
-            mIsUsingJSProxy = true;
-            mDevServerHelper.launchChromeDevtools();
-          } else {
-            mIsUsingJSProxy = false;
-          }
-          handleReloadJS();
-        }
-      }
-    };
-
-    // We store JS bundle loaded from dev server in a single destination in app's data dir.
-    // In case when someone schedule 2 subsequent reloads it may happen that JS thread will
-    // start reading first reload output while the second reload starts writing to the same
-    // file. As this should only be the case in dev mode we leave it as it is.
-    // TODO(6418010): Fix readers-writers problem in debug reload from HTTP server
-    mJSBundleTempFile = new File(applicationContext.getFilesDir(), JS_BUNDLE_FILE_NAME);
-
-    mDefaultNativeModuleCallExceptionHandler = new DefaultNativeModuleCallExceptionHandler();
-
-    setDevSupportEnabled(enableOnCreate);
-  }
-
-  @Override
-  public void handleException(Exception e) {
-    if (mIsDevSupportEnabled) {
-      FLog.e(ReactConstants.TAG, "Exception in native call from JS", e);
-      showNewJavaError(e.getMessage(), e);
-    } else {
-      mDefaultNativeModuleCallExceptionHandler.handleException(e);
-    }
-  }
-
-  @Override
-  public void showNewJavaError(String message, Throwable e) {
-    showNewError(message, StackTraceHelper.convertJavaStackTrace(e), JAVA_ERROR_COOKIE);
-  }
-
-  /**
-   * Add option item to dev settings dialog displayed by this manager. In the case user select given
-   * option from that dialog, the appropriate handler passed as {@param optionHandler} will be
-   * called.
-   */
-  @Override
-  public void addCustomDevOption(
-      String optionName,
-      DevOptionHandler optionHandler) {
-    mCustomDevOptions.put(optionName, optionHandler);
-  }
-
-  @Override
-  public void showNewJSError(String message, ReadableArray details, int errorCookie) {
-    showNewError(message, StackTraceHelper.convertJsStackTrace(details), errorCookie);
-  }
-
-  @Override
-  public void updateJSError(
-      final String message,
-      final ReadableArray details,
-      final int errorCookie) {
-    UiThreadUtil.runOnUiThread(
-        new Runnable() {
-          @Override
-          public void run() {
-            // Since we only show the first JS error in a succession of JS errors, make sure we only
-            // update the error message for that error message. This assumes that updateJSError
-            // belongs to the most recent showNewJSError
-            if (mRedBoxDialog == null ||
-                !mRedBoxDialog.isShowing() ||
-                errorCookie != mRedBoxDialog.getErrorCookie()) {
-              return;
-            }
-            mRedBoxDialog.setExceptionDetails(
-                message,
-                StackTraceHelper.convertJsStackTrace(details));
-            mRedBoxDialog.show();
-          }
-        });
-  }
-
-  private void showNewError(
-      final String message,
-      final StackFrame[] stack,
-      final int errorCookie) {
-    UiThreadUtil.runOnUiThread(
-        new Runnable() {
-          @Override
-          public void run() {
-            if (mRedBoxDialog == null) {
-              mRedBoxDialog = new RedBoxDialog(mApplicationContext, DevSupportManagerImpl.this);
-              mRedBoxDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
-            }
-            if (mRedBoxDialog.isShowing()) {
-              // Sometimes errors cause multiple errors to be thrown in JS in quick succession. Only
-              // show the first and most actionable one.
-              return;
-            }
-            mRedBoxDialog.setExceptionDetails(message, stack);
-            mRedBoxDialog.setErrorCookie(errorCookie);
-            mRedBoxDialog.show();
-          }
-        });
-  }
-
-  @Override
-  public void showDevOptionsDialog() {
-    if (mDevOptionsDialog != null || !mIsDevSupportEnabled) {
-      return;
-    }
-    LinkedHashMap<String, DevOptionHandler> options = new LinkedHashMap<>();
-    /* register standard options */
-    options.put(
-        mApplicationContext.getString(R.string.catalyst_reloadjs), new DevOptionHandler() {
-          @Override
-          public void onOptionSelected() {
-            handleReloadJS();
-          }
-        });
-    options.put(
-        mIsUsingJSProxy ?
-            mApplicationContext.getString(R.string.catalyst_debugjs_off) :
-            mApplicationContext.getString(R.string.catalyst_debugjs),
-        new DevOptionHandler() {
-          @Override
-          public void onOptionSelected() {
-            mIsUsingJSProxy = !mIsUsingJSProxy;
-            handleReloadJS();
-          }
-        });
-    options.put(
-            mDevSettings.isHotModuleReplacementEnabled()
-                    ? mApplicationContext.getString(R.string.catalyst_hot_module_replacement_off)
-                    : mApplicationContext.getString(R.string.catalyst_hot_module_replacement),
-            new DevOptionHandler() {
-              @Override
-              public void onOptionSelected() {
-                mDevSettings.setHotModuleReplacementEnabled(!mDevSettings.isHotModuleReplacementEnabled());
-                handleReloadJS();
-              }
-            });
-    options.put(
-        mDevSettings.isReloadOnJSChangeEnabled()
-            ? mApplicationContext.getString(R.string.catalyst_live_reload_off)
-            : mApplicationContext.getString(R.string.catalyst_live_reload),
-        new DevOptionHandler() {
-          @Override
-          public void onOptionSelected() {
-            mDevSettings.setReloadOnJSChangeEnabled(!mDevSettings.isReloadOnJSChangeEnabled());
-          }
-        });
-    options.put(
-        mDevSettings.isElementInspectorEnabled()
-          ? mApplicationContext.getString(R.string.catalyst_element_inspector_off)
-          : mApplicationContext.getString(R.string.catalyst_element_inspector),
-        new DevOptionHandler() {
-          @Override
-          public void onOptionSelected() {
-            mDevSettings.setElementInspectorEnabled(!mDevSettings.isElementInspectorEnabled());
-            mReactInstanceCommandsHandler.toggleElementInspector();
-          }
-        });
-    options.put(
-        mDevSettings.isFpsDebugEnabled()
-            ? mApplicationContext.getString(R.string.catalyst_perf_monitor_off)
-            : mApplicationContext.getString(R.string.catalyst_perf_monitor),
-        new DevOptionHandler() {
-          @Override
-          public void onOptionSelected() {
-            mDevSettings.setFpsDebugEnabled(!mDevSettings.isFpsDebugEnabled());
-          }
-        });
-    if (mCurrentContext != null &&
-        mCurrentContext.getCatalystInstance() != null &&
-        !mCurrentContext.getCatalystInstance().isDestroyed() &&
-        mCurrentContext.getCatalystInstance().supportsProfiling()) {
-      options.put(
-          mApplicationContext.getString(
-              mIsCurrentlyProfiling ? R.string.catalyst_stop_profile :
-                  R.string.catalyst_start_profile),
-          new DevOptionHandler() {
-            @Override
-            public void onOptionSelected() {
-              if (mCurrentContext != null && mCurrentContext.hasActiveCatalystInstance()) {
-                String profileName = (Environment.getExternalStorageDirectory().getPath() +
-                    "/profile_" + mProfileIndex + ".json");
-                if (mIsCurrentlyProfiling) {
-                  mIsCurrentlyProfiling = false;
-                  mProfileIndex++;
-                  Debug.stopMethodTracing();
-                  mCurrentContext.getCatalystInstance()
-                      .stopProfiler("profile", profileName);
-                  Toast.makeText(
-                      mCurrentContext,
-                      "Profile output to " + profileName,
-                      Toast.LENGTH_LONG).show();
-                } else {
-                  mIsCurrentlyProfiling = true;
-                  mCurrentContext.getCatalystInstance().startProfiler("profile");
-                  Debug.startMethodTracingSampling(
-                      profileName,
-                      JAVA_SAMPLING_PROFILE_MEMORY_BYTES,
-                      JAVA_SAMPLING_PROFILE_DELTA_US);
-                }
-              }
-            }
-          });
-    }
-    options.put(
-        mApplicationContext.getString(R.string.catalyst_settings), new DevOptionHandler() {
-          @Override
-          public void onOptionSelected() {
-            Intent intent = new Intent(mApplicationContext, DevSettingsActivity.class);
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            mApplicationContext.startActivity(intent);
-          }
-        });
-
-    if (mCustomDevOptions.size() > 0) {
-      options.putAll(mCustomDevOptions);
-    }
-
-    final DevOptionHandler[] optionHandlers = options.values().toArray(new DevOptionHandler[0]);
-
-    mDevOptionsDialog =
-        new AlertDialog.Builder(mApplicationContext)
-            .setItems(
-                options.keySet().toArray(new String[0]),
-                new DialogInterface.OnClickListener() {
-                  @Override
-                  public void onClick(DialogInterface dialog, int which) {
-                    optionHandlers[which].onOptionSelected();
-                    mDevOptionsDialog = null;
-                  }
-                })
-            .setOnCancelListener(new DialogInterface.OnCancelListener() {
-              @Override
-              public void onCancel(DialogInterface dialog) {
-                mDevOptionsDialog = null;
-              }
-            })
-            .create();
-    mDevOptionsDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
-    mDevOptionsDialog.show();
-  }
-
-  /**
-   * {@link ReactInstanceDevCommandsHandler} is responsible for
-   * enabling/disabling dev support when a React view is attached/detached
-   * or when application state changes (e.g. the application is backgrounded).
-   */
-  @Override
-  public void setDevSupportEnabled(boolean isDevSupportEnabled) {
-    mIsDevSupportEnabled = isDevSupportEnabled;
-    reload();
-  }
-
-  @Override
-  public boolean getDevSupportEnabled() {
-    return mIsDevSupportEnabled;
-  }
-
-  @Override
-  public DeveloperSettings getDevSettings() {
-    return mDevSettings;
-  }
-
-  @Override
-  public void onNewReactContextCreated(ReactContext reactContext) {
-    resetCurrentContext(reactContext);
-  }
-
-  @Override
-  public void onReactInstanceDestroyed(ReactContext reactContext) {
-    if (reactContext == mCurrentContext) {
-      // only call reset context when the destroyed context matches the one that is currently set
-      // for this manager
-      resetCurrentContext(null);
-    }
-  }
-
-  @Override
-  public String getSourceMapUrl() {
-    if (mJSAppBundleName == null) {
-      return "";
-    }
-
-    return mDevServerHelper.getSourceMapUrl(Assertions.assertNotNull(mJSAppBundleName));
-  }
-
-  @Override
-  public String getSourceUrl() {
-    if (mJSAppBundleName == null) {
-      return "";
-    }
-
-    return mDevServerHelper.getSourceUrl(Assertions.assertNotNull(mJSAppBundleName));
-  }
-
-  @Override
-  public String getJSBundleURLForRemoteDebugging() {
-    return mDevServerHelper.getJSBundleURLForRemoteDebugging(
-        Assertions.assertNotNull(mJSAppBundleName));
-  }
-
-  @Override
-  public String getDownloadedJSBundleFile() {
-    return mJSBundleTempFile.getAbsolutePath();
-  }
-
-  /**
-   * @return {@code true} if {@link ReactInstanceManager} should use downloaded JS bundle file
-   * instead of using JS file from assets. This may happen when app has not been updated since
-   * the last time we fetched the bundle.
-   */
-  @Override
-  public boolean hasUpToDateJSBundleInCache() {
-    if (mIsDevSupportEnabled && mJSBundleTempFile.exists()) {
-      try {
-        String packageName = mApplicationContext.getPackageName();
-        PackageInfo thisPackage = mApplicationContext.getPackageManager()
-            .getPackageInfo(packageName, 0);
-        if (mJSBundleTempFile.lastModified() > thisPackage.lastUpdateTime) {
-          // Base APK has not been updated since we donwloaded JS, but if app is using exopackage
-          // it may only be a single dex that has been updated. We check for exopackage dir update
-          // time in that case.
-          File exopackageDir = new File(
-              String.format(Locale.US, EXOPACKAGE_LOCATION_FORMAT, packageName));
-          if (exopackageDir.exists()) {
-            return mJSBundleTempFile.lastModified() > exopackageDir.lastModified();
-          }
-          return true;
-        }
-      } catch (PackageManager.NameNotFoundException e) {
-        // Ignore this error and just fallback to loading JS from assets
-        FLog.e(ReactConstants.TAG, "DevSupport is unable to get current app info");
-      }
-    }
-    return false;
-  }
-
-  /**
-   * @return {@code true} if JS bundle {@param bundleAssetName} exists, in that case
-   * {@link ReactInstanceManager} should use that file from assets instead of downloading bundle
-   * from dev server
-   */
-  public boolean hasBundleInAssets(String bundleAssetName) {
-    try {
-      String[] assets = mApplicationContext.getAssets().list("");
-      for (int i = 0; i < assets.length; i++) {
-        if (assets[i].equals(bundleAssetName)) {
-          return true;
-        }
-      }
-    } catch (IOException e) {
-      // Ignore this error and just fallback to downloading JS from devserver
-      FLog.e(ReactConstants.TAG, "Error while loading assets list");
-    }
-    return false;
-  }
-
-  private void resetCurrentContext(@Nullable ReactContext reactContext) {
-    if (mCurrentContext == reactContext) {
-      // new context is the same as the old one - do nothing
-      return;
-    }
-
-    // if currently profiling stop and write the profile file
-    if (mIsCurrentlyProfiling) {
-      mIsCurrentlyProfiling = false;
-      String profileName = (Environment.getExternalStorageDirectory().getPath() +
-          "/profile_" + mProfileIndex + ".json");
-      mProfileIndex++;
-      Debug.stopMethodTracing();
-      mCurrentContext.getCatalystInstance().stopProfiler("profile", profileName);
-    }
-
-    mCurrentContext = reactContext;
-
-    // Recreate debug overlay controller with new CatalystInstance object
-    if (mDebugOverlayController != null) {
-      mDebugOverlayController.setFpsDebugViewVisible(false);
-    }
-    if (reactContext != null) {
-      mDebugOverlayController = new DebugOverlayController(reactContext);
-    }
-
-    reloadSettings();
-  }
-
-  @Override
-  public void reloadSettings() {
-    reload();
-  }
-
-  @Override
-  public void handleReloadJS() {
-    UiThreadUtil.assertOnUiThread();
-
-    // dismiss redbox if exists
-    if (mRedBoxDialog != null) {
-      mRedBoxDialog.dismiss();
-    }
-
-    ProgressDialog progressDialog = new ProgressDialog(mApplicationContext);
-    progressDialog.setTitle(R.string.catalyst_jsload_title);
-    progressDialog.setMessage(mApplicationContext.getString(
-        mIsUsingJSProxy ? R.string.catalyst_remotedbg_message : R.string.catalyst_jsload_message));
-    progressDialog.setIndeterminate(true);
-    progressDialog.setCancelable(false);
-    progressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
-    progressDialog.show();
-
-    if (mIsUsingJSProxy) {
-      reloadJSInProxyMode(progressDialog);
-    } else {
-      reloadJSFromServer(progressDialog);
-    }
-  }
-
-  @Override
-  public void isPackagerRunning(DevServerHelper.PackagerStatusCallback callback) {
-    mDevServerHelper.isPackagerRunning(callback);
-  }
-
-  private void reloadJSInProxyMode(final ProgressDialog progressDialog) {
-    // When using js proxy, there is no need to fetch JS bundle as proxy executor will do that
-    // anyway
-    mDevServerHelper.launchChromeDevtools();
-
-    JavaJSExecutor.Factory factory = new JavaJSExecutor.Factory() {
-      @Override
-      public JavaJSExecutor create() throws Exception {
-        WebsocketJavaScriptExecutor executor = new WebsocketJavaScriptExecutor();
-        SimpleSettableFuture<Boolean> future = new SimpleSettableFuture<>();
-        executor.connect(
-            mDevServerHelper.getWebsocketProxyURL(),
-            getExecutorConnectCallback(progressDialog, future));
-        // TODO(t9349129) Don't use timeout
-        try {
-          future.get(90, TimeUnit.SECONDS);
-          return executor;
-        } catch (ExecutionException e) {
-          throw (Exception) e.getCause();
-        } catch (InterruptedException | TimeoutException e) {
-          throw new RuntimeException(e);
-        }
-      }
-    };
-    mReactInstanceCommandsHandler.onReloadWithJSDebugger(factory);
-  }
-
-  private WebsocketJavaScriptExecutor.JSExecutorConnectCallback getExecutorConnectCallback(
-      final ProgressDialog progressDialog,
-      final SimpleSettableFuture<Boolean> future) {
-    return new WebsocketJavaScriptExecutor.JSExecutorConnectCallback() {
-      @Override
-      public void onSuccess() {
-        future.set(true);
-        progressDialog.dismiss();
-      }
-
-      @Override
-      public void onFailure(final Throwable cause) {
-        progressDialog.dismiss();
-        FLog.e(ReactConstants.TAG, "Unable to connect to remote debugger", cause);
-        future.setException(
-            new IOException(
-                mApplicationContext.getString(R.string.catalyst_remotedbg_error), cause));
-      }
-    };
-  }
-
-  private void reloadJSFromServer(final ProgressDialog progressDialog) {
-    mDevServerHelper.downloadBundleFromURL(
-        new DevServerHelper.BundleDownloadCallback() {
-          @Override
-          public void onSuccess() {
-            progressDialog.dismiss();
-            UiThreadUtil.runOnUiThread(
-                new Runnable() {
-                  @Override
-                  public void run() {
-                    mReactInstanceCommandsHandler.onJSBundleLoadedFromServer();
-                  }
-                });
-          }
-
-          @Override
-          public void onFailure(final Exception cause) {
-            progressDialog.dismiss();
-            FLog.e(ReactConstants.TAG, "Unable to download JS bundle", cause);
-            UiThreadUtil.runOnUiThread(
-                new Runnable() {
-                  @Override
-                  public void run() {
-                    if (cause instanceof DebugServerException) {
-                      DebugServerException debugServerException = (DebugServerException) cause;
-                      showNewJavaError(debugServerException.description, cause);
-                    } else {
-                      showNewJavaError(
-                          mApplicationContext.getString(R.string.catalyst_jsload_error),
-                          cause);
-                    }
-                  }
-                });
-          }
-        },
-        Assertions.assertNotNull(mJSAppBundleName),
-        mJSBundleTempFile);
-    progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
-      @Override
-      public void onCancel(DialogInterface dialog) {
-        mDevServerHelper.cancelDownloadBundleFromURL();
-      }
-    });
-    progressDialog.setCancelable(true);
-  }
-
-  private void reload() {
-    // reload settings, show/hide debug overlay if required & start/stop shake detector
-    if (mIsDevSupportEnabled) {
-      // update visibility of FPS debug overlay depending on the settings
-      if (mDebugOverlayController != null) {
-        mDebugOverlayController.setFpsDebugViewVisible(mDevSettings.isFpsDebugEnabled());
-      }
-
-      // start shake gesture detector
-      if (!mIsShakeDetectorStarted) {
-        mShakeDetector.start(
-            (SensorManager) mApplicationContext.getSystemService(Context.SENSOR_SERVICE));
-        mIsShakeDetectorStarted = true;
-      }
-
-      // register reload app broadcast receiver
-      if (!mIsReceiverRegistered) {
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(DevServerHelper.getReloadAppAction(mApplicationContext));
-        mApplicationContext.registerReceiver(mReloadAppBroadcastReceiver, filter);
-        mIsReceiverRegistered = true;
-      }
-
-      if (mDevSettings.isReloadOnJSChangeEnabled()) {
-        mDevServerHelper.startPollingOnChangeEndpoint(
-            new DevServerHelper.OnServerContentChangeListener() {
-          @Override
-          public void onServerContentChanged() {
-            handleReloadJS();
-          }
-        });
-      } else {
-        mDevServerHelper.stopPollingOnChangeEndpoint();
-      }
-    } else {
-      // hide FPS debug overlay
-      if (mDebugOverlayController != null) {
-        mDebugOverlayController.setFpsDebugViewVisible(false);
-      }
-
-      // stop shake gesture detector
-      if (mIsShakeDetectorStarted) {
-        mShakeDetector.stop();
-        mIsShakeDetectorStarted = false;
-      }
-
-      // unregister app reload broadcast receiver
-      if (mIsReceiverRegistered) {
-        mApplicationContext.unregisterReceiver(mReloadAppBroadcastReceiver);
-        mIsReceiverRegistered = false;
-      }
-
-      // hide redbox dialog
-      if (mRedBoxDialog != null) {
-        mRedBoxDialog.dismiss();
-      }
-
-      // hide dev options dialog
-      if (mDevOptionsDialog != null) {
-        mDevOptionsDialog.dismiss();
-      }
-
-      mDevServerHelper.stopPollingOnChangeEndpoint();
-    }
-  }
-}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DisabledDevSupportManager.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DisabledDevSupportManager.java
deleted file mode 100644
index 44edbc8866ec..000000000000
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DisabledDevSupportManager.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
- * 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.
- */
-
-package com.facebook.react.devsupport;
-
-import com.facebook.react.bridge.ReactContext;
-import com.facebook.react.bridge.ReadableArray;
-import com.facebook.react.modules.debug.DeveloperSettings;
-
-/**
- * A dummy implementation of {@link DevSupportManager} to be used in production mode where
- * development features aren't needed.
- */
-public class DisabledDevSupportManager implements DevSupportManager {
-
-  @Override
-  public void showNewJavaError(String message, Throwable e) {
-
-  }
-
-  @Override
-  public void addCustomDevOption(String optionName, DevOptionHandler optionHandler) {
-
-  }
-
-  @Override
-  public void showNewJSError(String message, ReadableArray details, int errorCookie) {
-
-  }
-
-  @Override
-  public void updateJSError(String message, ReadableArray details, int errorCookie) {
-
-  }
-
-  @Override
-  public void showDevOptionsDialog() {
-
-  }
-
-  @Override
-  public void setDevSupportEnabled(boolean isDevSupportEnabled) {
-
-  }
-
-  @Override
-  public boolean getDevSupportEnabled() {
-    return false;
-  }
-
-  @Override
-  public DeveloperSettings getDevSettings() {
-    return null;
-  }
-
-  @Override
-  public void onNewReactContextCreated(ReactContext reactContext) {
-
-  }
-
-  @Override
-  public void onReactInstanceDestroyed(ReactContext reactContext) {
-
-  }
-
-  @Override
-  public String getSourceMapUrl() {
-    return null;
-  }
-
-  @Override
-  public String getSourceUrl() {
-    return null;
-  }
-
-  @Override
-  public String getJSBundleURLForRemoteDebugging() {
-    return null;
-  }
-
-  @Override
-  public String getDownloadedJSBundleFile() {
-    return null;
-  }
-
-  @Override
-  public boolean hasUpToDateJSBundleInCache() {
-    return false;
-  }
-
-  @Override
-  public void reloadSettings() {
-
-  }
-
-  @Override
-  public void handleReloadJS() {
-
-  }
-
-  @Override
-  public void isPackagerRunning(DevServerHelper.PackagerStatusCallback callback) {
-
-  }
-
-  @Override
-  public void handleException(Exception e) {
-
-  }
-}

From 909aa1c92952ff77bc46e0c0b6a1a644e23a04ac Mon Sep 17 00:00:00 2001
From: Seth Ladd <sethladd@gmail.com>
Date: Fri, 8 Jan 2016 14:15:33 -0800
Subject: [PATCH 0690/1411] Link to iOS device docs

Spent an hour trying to find this doc. Hope this helps the next person!
---
 docs/GettingStarted.md | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/docs/GettingStarted.md b/docs/GettingStarted.md
index 714e06e7bd24..5c44b389d86d 100644
--- a/docs/GettingStarted.md
+++ b/docs/GettingStarted.md
@@ -42,6 +42,8 @@ _NOTE:_ There is experimental [Windows and Linux support](/react-native/docs/lin
 - Open `index.ios.js` in your text editor of choice and edit some lines.
 - Hit ⌘-R in your iOS simulator to reload the app and see your change!
 
+_Note: If you are using an iOS device, see the [Running on iOS Device page](http://facebook.github.io/react-native/docs/running-on-device-ios.html#content)._
+
 **To run the Android app:**
 
 - `$ cd AwesomeProject`
@@ -50,7 +52,7 @@ _NOTE:_ There is experimental [Windows and Linux support](/react-native/docs/lin
 - Press the menu button (F2 by default, or ⌘-M in Genymotion) and select *Reload JS* to see your change!
 - Run `adb logcat *:S ReactNative:V ReactNativeJS:V` in a terminal to see your app's logs
 
-_Note: If you are using a device, see the [Running on Device page](http://facebook.github.io/react-native/docs/running-on-device-android.html#content)._
+_Note: If you are using an Android device, see the [Running on Android Device page](http://facebook.github.io/react-native/docs/running-on-device-android.html#content)._
 
 Congratulations! You've successfully run and modified your first React Native app.
 

From 336984214f65ddc5cfb007383b4428a9fb7b293b Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Fri, 8 Jan 2016 15:41:52 -0800
Subject: [PATCH 0691/1411] Fixed ART background color

Summary:
public
Disabling background color propagation had the unexpected effect of turning ART views black. This diff re-enabled propagation for ART views.

Reviewed By: jingc

Differential Revision: D2816402

fb-gh-sync-id: f2a4c44f3b4a16e04cbf6051391bb8fb1c0a7ed2
---
 Libraries/ART/ARTSurfaceView.m | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Libraries/ART/ARTSurfaceView.m b/Libraries/ART/ARTSurfaceView.m
index 8949e43c349d..f5c13651bf02 100644
--- a/Libraries/ART/ARTSurfaceView.m
+++ b/Libraries/ART/ARTSurfaceView.m
@@ -27,4 +27,9 @@ - (void)drawRect:(CGRect)rect
   }
 }
 
+- (void)reactSetInheritedBackgroundColor:(UIColor *)inheritedBackgroundColor
+{
+  self.backgroundColor = inheritedBackgroundColor;
+}
+
 @end

From c16095ed854bae561849cce7844a97da6eec82be Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Fri, 8 Jan 2016 16:14:20 -0800
Subject: [PATCH 0692/1411] Fixed border collapse bug

Summary:
public
The fix for border smearing introduced a bug where borders + background would sometimes not be rendered if the view was created at a small size (e.g. zero) and then resized.

This diff fixes that by redrawing the border if the view size changes. There is some opportunity to optimize this in future by performing some logic up-front to detect if the redrawing is necessary, but I thought I'd keep it simple for this bug fix rather than risk introducing further bugs.

Reviewed By: jingc

Differential Revision: D2817365

fb-gh-sync-id: eca164e8ce03a66598677c9e05496791230b5210
---
 React/Views/RCTView.m | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m
index 9b35bbe4fb03..7c773691eeb1 100644
--- a/React/Views/RCTView.m
+++ b/React/Views/RCTView.m
@@ -486,10 +486,10 @@ - (RCTCornerRadii)cornerRadii
 
   // Get scale factors required to prevent radii from overlapping
   const CGSize size = self.bounds.size;
-  const CGFloat topScaleFactor = MIN(1, size.width / (topLeftRadius + topRightRadius));
-  const CGFloat bottomScaleFactor = MIN(1, size.width / (bottomLeftRadius + bottomRightRadius));
-  const CGFloat rightScaleFactor = MIN(1, size.height / (topRightRadius + bottomRightRadius));
-  const CGFloat leftScaleFactor = MIN(1, size.height / (topLeftRadius + bottomLeftRadius));
+  const CGFloat topScaleFactor = RCTZeroIfNaN(MIN(1, size.width / (topLeftRadius + topRightRadius)));
+  const CGFloat bottomScaleFactor = RCTZeroIfNaN(MIN(1, size.width / (bottomLeftRadius + bottomRightRadius)));
+  const CGFloat rightScaleFactor = RCTZeroIfNaN(MIN(1, size.height / (topRightRadius + bottomRightRadius)));
+  const CGFloat leftScaleFactor = RCTZeroIfNaN(MIN(1, size.height / (topLeftRadius + bottomLeftRadius)));
 
   // Return scaled radii
   return (RCTCornerRadii){
@@ -510,6 +510,15 @@ - (RCTBorderColors)borderColors
   };
 }
 
+- (void)reactSetFrame:(CGRect)frame
+{
+  // If frame is zero, or below the threshold where the border radii can
+  // be rendered as a stretchable image, we'll need to re-render.
+  // TODO: detect up-front if re-rendering is necessary
+  [super reactSetFrame:frame];
+  [self.layer setNeedsDisplay];
+}
+
 - (void)displayLayer:(CALayer *)layer
 {
   if (CGSizeEqualToSize(layer.bounds.size, CGSizeZero)) {

From e14b24936d157bbfd27e622e403bf903cb9c4bae Mon Sep 17 00:00:00 2001
From: Olivier Notteghem <oli@fb.com>
Date: Fri, 8 Jan 2016 16:37:23 -0800
Subject: [PATCH 0693/1411] Move THFeedListView to right location

Reviewed By: hnery

Differential Revision: D2815711

fb-gh-sync-id: 261343ea6c57786beb9c02917c56a3bef544d85b
---
 .../ListView/THFeedListView.js                | 443 ------------------
 1 file changed, 443 deletions(-)
 delete mode 100644 Libraries/CustomComponents/ListView/THFeedListView.js

diff --git a/Libraries/CustomComponents/ListView/THFeedListView.js b/Libraries/CustomComponents/ListView/THFeedListView.js
deleted file mode 100644
index e473a2e8e22a..000000000000
--- a/Libraries/CustomComponents/ListView/THFeedListView.js
+++ /dev/null
@@ -1,443 +0,0 @@
-/**
- * Copyright (c) 2015, Facebook, Inc.  All rights reserved.
- *
- * Facebook, Inc. ("Facebook") owns all right, title and interest, including
- * all intellectual property and other proprietary rights, in and to the React
- * Native CustomComponents software (the "Software").  Subject to your
- * compliance with these terms, you are hereby granted a non-exclusive,
- * worldwide, royalty-free copyright license to (1) use and copy the Software;
- * and (2) reproduce and distribute the Software as part of your own software
- * ("Your Software").  Facebook reserves all rights not expressly granted to
- * you in this license agreement.
- *
- * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "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 FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
- * EMPLOYEES 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 THE SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * @providesModule THFeedListView
- */
-'use strict';
-
-var ListViewDataSource = require('ListViewDataSource');
-var React = require('React');
-var RCTScrollViewManager = require('NativeModules').ScrollViewManager;
-var ScrollView = require('ScrollView');
-var ScrollResponder = require('ScrollResponder');
-var StaticRenderer = require('StaticRenderer');
-var TimerMixin = require('TimerMixin');
-
-var isEmpty = require('isEmpty');
-var logError = require('logError');
-var merge = require('merge');
-var performanceNow = require('performanceNow');
-
-var PropTypes = React.PropTypes;
-
-var DEFAULT_PAGE_SIZE = 1;
-var DEFAULT_INITIAL_ROWS = 10;
-var DEFAULT_END_REACHED_THRESHOLD = 1000;
-var DEFAULT_SCROLL_CALLBACK_THROTTLE = 50;
-var DEFAULT_TICK_FREQUENCY = 200;
-var DEFAULT_ROWS_YIELD_TIME = 100;
-var DEFAULT_END_SCROLL_TIMEOUT = 100;
-var SCROLLVIEW_REF = 'listviewscroll';
-
-/**
- * Simpler version of `ListView`, optimized for smooth scrolling in feed. This is
- * achieved by skipping unecessary processing caused by race condition (with paging
- * and handling view resize callback) and, more importantly, handling heavier 
- * computation (i.e rendering more rows, possibly fetching more data when end of 
- * feed is reached) only once current scroll gesture completes. 
- *
- * Internally, listview uses an periodic tick callback that will render ahead each time
- * additionl row(s), the number of which is controlled by `pageSize` props, until 
- * no more rows are available in data source.
- * 
- */
-
-var THFeedListView = React.createClass({
-  mixins: [ScrollResponder.Mixin, TimerMixin],
-
-  statics: {
-    DataSource: ListViewDataSource,
-  },
-
-  /**
-   * You must provide a renderRow function. If you omit any of the other render
-   * functions, ListView will simply skip rendering them.
-   *
-   * - renderRow(rowData, sectionID, rowID, highlightRow);
-   */
-  propTypes: {
-    ...ScrollView.propTypes,
-
-    dataSource: PropTypes.instanceOf(ListViewDataSource).isRequired,
-    /**
-     * (sectionID, rowID, adjacentRowHighlighted) => renderable
-     *
-     * If provided, a renderable component to be rendered as the separator
-     * below each row but not the last row if there is a section header below.
-     * Take a sectionID and rowID of the row above and whether its adjacent row
-     * is highlighted.
-     */
-    renderSeparator: PropTypes.func,
-    /**
-     * (rowData, sectionID, rowID, highlightRow) => renderable
-     *
-     * Takes a data entry from the data source and its ids and should return
-     * a renderable component to be rendered as the row.  By default the data
-     * is exactly what was put into the data source, but it's also possible to
-     * provide custom extractors. ListView can be notified when a row is
-     * being highlighted by calling highlightRow function. The separators above and
-     * below will be hidden when a row is highlighted. The highlighted state of
-     * a row can be reset by calling highlightRow(null).
-     */
-    renderRow: PropTypes.func.isRequired,
-    /**
-     * How many rows to render on initial component mount.  Use this to make
-     * it so that the first screen worth of data appears at one time instead of
-     * over the course of multiple frames.
-     */
-    initialListSize: PropTypes.number,
-    /**
-     * Called when all rows have been rendered and the list has been scrolled
-     * to within onEndReachedThreshold of the bottom.  The native scroll
-     * event is provided.
-     */
-    onEndReached: PropTypes.func,
-    /**
-     * Threshold in pixels for onEndReached.
-     */
-    onEndReachedThreshold: PropTypes.number,
-    /**
-     * Number of rows to render per event loop.
-     */
-    pageSize: PropTypes.number,
-    /**
-     * () => renderable
-     *
-     * The header and footer are always rendered (if these props are provided)
-     * on every render pass.  If they are expensive to re-render, wrap them
-     * in StaticContainer or other mechanism as appropriate.  Footer is always
-     * at the bottom of the list, and header at the top, on every render pass.
-     */
-    renderFooter: PropTypes.func,
-    renderHeader: PropTypes.func,
-    /**
-     * (props) => renderable
-     *
-     * A function that returns the scrollable component in which the list rows
-     * are rendered. Defaults to returning a ScrollView with the given props.
-     */
-    renderScrollComponent: React.PropTypes.func.isRequired,
-    /**
-     * (visibleRows, changedRows) => void
-     *
-     * Called when the set of visible rows changes.  `visibleRows` maps
-     * { sectionID: { rowID: true }} for all the visible rows, and
-     * `changedRows` maps { sectionID: { rowID: true | false }} for the rows
-     * that have changed their visibility, with true indicating visible, and
-     * false indicating the view has moved out of view.
-     */
-    onChangeVisibleRows: React.PropTypes.func,
-    /**
-     * A performance optimization for improving scroll perf of
-     * large lists, used in conjunction with overflow: 'hidden' on the row
-     * containers.  This is enabled by default.
-     */
-    removeClippedSubviews: React.PropTypes.bool,
-  },
-
-  /**
-   * Exports some data, e.g. for perf investigations or analytics.
-   */
-  getMetrics: function() {
-    return {
-      contentLength: this._scrollProperties.contentLength,
-      totalRows: this.props.dataSource.getRowCount(),
-      renderedRows: this.state.curRenderedRowsCount,
-      visibleRows: Object.keys(this._visibleRows).length,
-    };
-  },
-
-  /**
-   * Provides a handle to the underlying scroll responder to support operations
-   * such as scrollTo.
-   */
-  getScrollResponder: function() {
-    return this.refs[SCROLLVIEW_REF] &&
-      this.refs[SCROLLVIEW_REF].getScrollResponder &&
-      this.refs[SCROLLVIEW_REF].getScrollResponder();
-  },
-
-  getInnerViewNode: function() {
-    return this.refs[SCROLLVIEW_REF] &&
-      this.refs[SCROLLVIEW_REF].getInnerViewNode();
-  },
-
-  setNativeProps: function(props) {
-    this.refs[SCROLLVIEW_REF] && 
-      this.refs[SCROLLVIEW_REF].setNativeProps(props);
-  },
-
-  scrollTo: function(destY, destX) {
-    this.getScrollResponder().scrollResponderScrollTo(destX || 0, destY || 0);
-  },
-
-  /**
-   * React life cycle hooks.
-   */
-
-  getDefaultProps: function() {
-    return {
-      initialListSize: DEFAULT_INITIAL_ROWS,
-      pageSize: DEFAULT_PAGE_SIZE,
-      onEndReachedThreshold: DEFAULT_END_REACHED_THRESHOLD,
-    };
-  },
-
-  getInitialState: function() {
-    return {
-      curRenderedRowsCount: this.props.initialListSize,
-      highlightedRow: {},
-    };
-  },
-
-  componentWillMount: function() {
-    // this data should never trigger a render pass, so don't put in state
-    this._scrollProperties = {
-      visibleLength: null,
-      contentLength: null,
-      offset: 0
-    };
-    this._childFrames = [];
-    this._visibleRows = {};
-    this._prevRenderedRowsCount = 0;
-    this._lastEndReachedContentLength = null;
-    this._lastScrollEventTime = 0; // TODO(9622421): use native scroll events when available
-    this._lastUpdateEventTime = 0;
-  },
-
-  componentDidMount: function() {
-    // potentially trigger fetching additional data as soon as possible.
-    this._callOnEndReachedIfNeeded();
-
-    // schedule periodic check to check if we have more rows to render or need to feth more rows
-    this.setInterval(this.onTick, DEFAULT_TICK_FREQUENCY);
-  },
-
-  componentWillReceiveProps: function(nextProps) {
-    if (this.props.dataSource !== nextProps.dataSource) {
-      this._prevRenderedRowsCount = 0;
-    }
-    if (this.props.initialListSize !== nextProps.initialListSize) {
-      this.setState((state, props) => {
-        return {
-          curRenderedRowsCount: Math.max(
-            state.curRenderedRowsCount,
-            props.initialListSize
-          ),
-        };
-      });
-    }
-  },
-
-  componentDidUpdate: function () {
-    this._lastUpdateEventTime = performanceNow();
-  },
-
-  onRowHighlighted: function(sectionID, rowID) {
-    this.setState({highlightedRow: {sectionID, rowID}});
-  },
-
-  onTick: function() {
-    if (!this.isMounted()) {
-      return;
-    }
-    if (performanceNow() < this._lastScrollEventTime + DEFAULT_END_SCROLL_TIMEOUT) {
-      // listview is currently scrolling, skip any work until scroll completes
-      return;
-    }
-    if (performanceNow() < this._lastUpdateEventTime + DEFAULT_ROWS_YIELD_TIME) {
-      // ensure at least enough time has elapsed between 2 row rendering
-      return;
-    }
-    this._callOnEndReachedIfNeeded();
-    this._renderMoreRowsIfAvailable();
-  },
-
-  render: function() {
-    var dataSource = this.props.dataSource;
-    var allRowIDs = dataSource.rowIdentities;
-    var rowCount = 0;
-    var header = this.props.renderHeader && this.props.renderHeader();
-    var footer = this.props.renderFooter && this.props.renderFooter();
-    var totalIndex = header ? 1 : 0;
-
-    var bodyComponents = [];
-    for (var sectionIdx = 0; sectionIdx < allRowIDs.length; sectionIdx++) {
-      var sectionID = dataSource.sectionIdentities[sectionIdx];
-      var rowIDs = allRowIDs[sectionIdx];
-      if (rowIDs.length === 0) {
-        continue;
-      }
-
-      for (var rowIdx = 0; rowIdx < rowIDs.length; rowIdx++) {
-        var rowID = rowIDs[rowIdx];
-        var comboID = sectionID + '_' + rowID;
-        var shouldUpdateRow = rowCount >= this._prevRenderedRowsCount &&
-          dataSource.rowShouldUpdate(sectionIdx, rowIdx);
-        var row =
-          <StaticRenderer
-            key={'r_' + comboID}
-            shouldUpdate={!!shouldUpdateRow}
-            render={this.props.renderRow.bind(
-              null,
-              dataSource.getRowData(sectionIdx, rowIdx),
-              sectionID,
-              rowID,
-              this.onRowHighlighted
-            )}
-          />;
-        bodyComponents.push(row);
-        totalIndex++;
-
-        if (this.props.renderSeparator &&
-            (rowIdx !== rowIDs.length - 1 || sectionIdx === allRowIDs.length - 1)) {
-          var adjacentRowHighlighted =
-            this.state.highlightedRow.sectionID === sectionID && (
-              this.state.highlightedRow.rowID === rowID ||
-              this.state.highlightedRow.rowID === rowIDs[rowIdx + 1]
-            );
-          var separator = this.props.renderSeparator(
-            sectionID,
-            rowID,
-            adjacentRowHighlighted
-          );
-          bodyComponents.push(separator);
-          totalIndex++;
-        }
-        if (++rowCount === this.state.curRenderedRowsCount) {
-          break;
-        }
-      }
-      if (rowCount >= this.state.curRenderedRowsCount) {
-        break;
-      }
-    }
-
-    var {
-      renderScrollComponent,
-      ...props,
-    } = this.props;
-    if (!props.scrollEventThrottle) {
-      props.scrollEventThrottle = DEFAULT_SCROLL_CALLBACK_THROTTLE;
-    }
-    if (props.removeClippedSubviews === undefined) {
-      props.removeClippedSubviews = true;
-    }
-    Object.assign(props, {
-      onScroll: this._onScroll,
-
-      // Do not pass these events downstream to ScrollView since they will be
-      // registered in ListView's own ScrollResponder.Mixin
-      onKeyboardWillShow: undefined,
-      onKeyboardWillHide: undefined,
-      onKeyboardDidShow: undefined,
-      onKeyboardDidHide: undefined,
-    });
-
-    // TODO(ide): Use function refs so we can compose with the scroll
-    // component's original ref instead of clobbering it
-    return React.cloneElement(renderScrollComponent(props), {
-      ref: SCROLLVIEW_REF,
-      onContentSizeChange: this._onContentSizeChange,
-      onLayout: this._onLayout,
-    }, header, bodyComponents, footer);
-  },
-
-  /**
-   * Private methods
-   */
-
-  _onContentSizeChange: function(width, height) {
-    var contentLength = !this.props.horizontal ? height : width;
-    this._scrollProperties.contentLength = contentLength;
-    this.props.onContentSizeChange && this.props.onContentSizeChange(width, height);
-  },
-
-  _onLayout: function(event) {
-    var {width, height} = event.nativeEvent.layout;
-    var visibleLength = !this.props.horizontal ? height : width;
-    this._scrollProperties.visibleLength = visibleLength;
-    this.props.onLayout && this.props.onLayout(event);
-  },
-
-  _onScroll: function(e) {
-    var data = e.nativeEvent;
-    var isVertical = !this.props.horizontal;
-    this._scrollProperties.visibleLength = data.layoutMeasurement[isVertical ? 'height' : 'width'];
-    this._scrollProperties.contentLength = data.contentSize[isVertical ? 'height' : 'width'];
-    this._scrollProperties.offset = data.contentOffset[isVertical ? 'y' : 'x'];
-    this._lastScrollEventTime = performanceNow();
-    this.props.onScroll && this.props.onScroll(e);
-  },
-
-  _callOnEndReachedIfNeeded: function() {
-    if (!this.props.onEndReached) {
-      // skip any processing if parent not interested in end of feed callbacks
-      return;
-    }
-    if (this._getDistanceFromEnd() > this.props.onEndReachedThreshold) {
-      // Scrolled out of the end zone, so it should be able to trigger again.
-      this._lastEndReachedContentLength = null;
-      return;
-    }
-    if (this.state.curRenderedRowsCount !== this.props.dataSource.getRowCount()) {
-      // we have more rows to render, so we haven't reached end of feed
-      return;
-    }
-    if (this._scrollProperties.contentLength && 
-        this._scrollProperties.contentLength === this._lastEndReachedContentLength) {
-      // we have already invoked end of feed callback for this given position in feed
-      return;
-    }
-    this._lastEndReachedContentLength = this._scrollProperties.contentLength;
-    this.props.onEndReached();
-  },
-
-  _renderMoreRowsIfAvailable: function() {
-    if (this.state.curRenderedRowsCount !== this.props.dataSource.getRowCount()) {
-      this.setState((state, props) => {
-        var curRenderedRowsCount = Math.min(
-          state.curRenderedRowsCount + props.pageSize,
-          props.dataSource.getRowCount()
-        );
-        this._prevRenderedRowsCount = state.curRenderedRowsCount;
-        return {curRenderedRowsCount};
-      }, () => {
-        this._prevRenderedRowsCount = this.state.curRenderedRowsCount;
-      });
-    }
-  },
-
-  _getDistanceFromEnd: function() {
-    var scrollProperties = this._scrollProperties;
-    var maxLength = Math.max(
-      scrollProperties.contentLength,
-      scrollProperties.visibleLength
-    );
-    return maxLength - scrollProperties.visibleLength - scrollProperties.offset;
-  },
-
-});
-
-module.exports = THFeedListView;

From bb73e985133ac863edc1441f9cab147b737f1335 Mon Sep 17 00:00:00 2001
From: Aaron Chiu <aaronechiu@fb.com>
Date: Fri, 8 Jan 2016 19:53:54 -0800
Subject: [PATCH 0694/1411] revert the revert (D2816377)

Reviewed By: zjj010104

Differential Revision: D2816742

fb-gh-sync-id: 2b3b46e54055cfd4b7a137a1f21a330cecd7d663
---
 .../react/ReactInstanceManagerImpl.java       |  20 +-
 ...faultNativeModuleCallExceptionHandler.java |  27 +
 .../react/devsupport/DevSupportManager.java   | 710 +----------------
 .../devsupport/DevSupportManagerImpl.java     | 722 ++++++++++++++++++
 .../devsupport/DisabledDevSupportManager.java | 116 +++
 5 files changed, 899 insertions(+), 696 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/DefaultNativeModuleCallExceptionHandler.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/devsupport/DisabledDevSupportManager.java

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index c9bf17c610ce..adb039d7ffee 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -52,6 +52,8 @@
 import com.facebook.react.common.annotations.VisibleForTesting;
 import com.facebook.react.devsupport.DevServerHelper;
 import com.facebook.react.devsupport.DevSupportManager;
+import com.facebook.react.devsupport.DevSupportManagerImpl;
+import com.facebook.react.devsupport.DisabledDevSupportManager;
 import com.facebook.react.devsupport.ReactInstanceDevCommandsHandler;
 import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
 import com.facebook.react.modules.core.DeviceEventManagerModule;
@@ -252,15 +254,15 @@ public T get() throws Exception {
     mJSMainModuleName = jsMainModuleName;
     mPackages = packages;
     mUseDeveloperSupport = useDeveloperSupport;
-    // We need to instantiate DevSupportManager regardless to the useDeveloperSupport option,
-    // although will prevent dev support manager from displaying any options or dialogs by
-    // checking useDeveloperSupport option before calling setDevSupportEnabled on this manager
-    // TODO(6803830): Don't instantiate devsupport manager when useDeveloperSupport is false
-    mDevSupportManager = new DevSupportManager(
-        applicationContext,
-        mDevInterface,
-        mJSMainModuleName,
-        useDeveloperSupport);
+    if (mUseDeveloperSupport) {
+      mDevSupportManager = new DevSupportManagerImpl(
+          applicationContext,
+          mDevInterface,
+          mJSMainModuleName,
+          useDeveloperSupport);
+    } else {
+      mDevSupportManager = new DisabledDevSupportManager();
+    }
     mBridgeIdleDebugListener = bridgeIdleDebugListener;
     mLifecycleState = initialLifecycleState;
     mUIImplementationProvider = uiImplementationProvider;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/DefaultNativeModuleCallExceptionHandler.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/DefaultNativeModuleCallExceptionHandler.java
new file mode 100644
index 000000000000..4d47156c7479
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/DefaultNativeModuleCallExceptionHandler.java
@@ -0,0 +1,27 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.bridge;
+
+/**
+ * Crashy crashy exception handler.
+ */
+public class DefaultNativeModuleCallExceptionHandler implements NativeModuleCallExceptionHandler {
+
+  @Override
+  public void handleException(Exception e) {
+    if (e instanceof RuntimeException) {
+      // Because we are rethrowing the original exception, the original stacktrace will be
+      // preserved.
+      throw (RuntimeException) e;
+    } else {
+      throw new RuntimeException(e);
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
index cf86bd3b3547..4f114ded6099 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
@@ -9,698 +9,34 @@
 
 package com.facebook.react.devsupport;
 
-import javax.annotation.Nullable;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.LinkedHashMap;
-import java.util.Locale;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import android.app.AlertDialog;
-import android.app.ProgressDialog;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.hardware.SensorManager;
-import android.os.Debug;
-import android.os.Environment;
-import android.view.WindowManager;
-import android.widget.Toast;
-
-import com.facebook.common.logging.FLog;
-import com.facebook.infer.annotation.Assertions;
-import com.facebook.react.R;
-import com.facebook.react.bridge.CatalystInstance;
-import com.facebook.react.bridge.JavaJSExecutor;
 import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReadableArray;
-import com.facebook.react.bridge.UiThreadUtil;
-import com.facebook.react.bridge.WebsocketJavaScriptExecutor;
-import com.facebook.react.common.ReactConstants;
-import com.facebook.react.common.ShakeDetector;
-import com.facebook.react.common.futures.SimpleSettableFuture;
-import com.facebook.react.devsupport.StackTraceHelper.StackFrame;
 import com.facebook.react.modules.debug.DeveloperSettings;
 
 /**
- * Interface for accessing and interacting with development features. Following features
- * are supported through this manager class:
- * 1) Displaying JS errors (aka RedBox)
- * 2) Displaying developers menu (Reload JS, Debug JS)
- * 3) Communication with developer server in order to download updated JS bundle
- * 4) Starting/stopping broadcast receiver for js reload signals
- * 5) Starting/stopping motion sensor listener that recognize shake gestures which in turn may
- *    trigger developers menu.
- * 6) Launching developers settings view
- *
- * This class automatically monitors the state of registered views and activities to which they are
- * bound to make sure that we don't display overlay or that we we don't listen for sensor events
- * when app is backgrounded.
- *
- * {@link ReactInstanceDevCommandsHandler} implementation is responsible for instantiating this
- * instance and for populating with an instance of {@link CatalystInstance} whenever instance
- * manager recreates it (through {@link #onNewCatalystContextCreated}). Also, instance manager is
- * responsible for enabling/disabling dev support in case when app is backgrounded or when all the
- * views has been detached from the instance (through {@link #setDevSupportEnabled} method).
- *
- * IMPORTANT: In order for developer support to work correctly it is required that the
- * manifest of your application contain the following entries:
- * {@code <activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>}
- * {@code <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>}
+ * Interface for accessing and interacting with development features.
+ * In dev mode, use the implementation {@link DevSupportManagerImpl}.
+ * In production mode, use the dummy implementation {@link DisabledDevSupportManager}.
  */
-public class DevSupportManager implements NativeModuleCallExceptionHandler {
-
-  private static final int JAVA_ERROR_COOKIE = -1;
-  private static final String JS_BUNDLE_FILE_NAME = "ReactNativeDevBundle.js";
-
-  private static final String EXOPACKAGE_LOCATION_FORMAT
-      = "/data/local/tmp/exopackage/%s//secondary-dex";
-
-  private static final int JAVA_SAMPLING_PROFILE_MEMORY_BYTES = 8 * 1024 * 1024;
-  private static final int JAVA_SAMPLING_PROFILE_DELTA_US = 100;
-
-  private final Context mApplicationContext;
-  private final ShakeDetector mShakeDetector;
-  private final BroadcastReceiver mReloadAppBroadcastReceiver;
-  private final DevServerHelper mDevServerHelper;
-  private final LinkedHashMap<String, DevOptionHandler> mCustomDevOptions =
-      new LinkedHashMap<>();
-  private final ReactInstanceDevCommandsHandler mReactInstanceCommandsHandler;
-  private final @Nullable String mJSAppBundleName;
-  private final File mJSBundleTempFile;
-
-  private @Nullable RedBoxDialog mRedBoxDialog;
-  private @Nullable AlertDialog mDevOptionsDialog;
-  private @Nullable DebugOverlayController mDebugOverlayController;
-  private @Nullable ReactContext mCurrentContext;
-  private DevInternalSettings mDevSettings;
-  private boolean mIsUsingJSProxy = false;
-  private boolean mIsReceiverRegistered = false;
-  private boolean mIsShakeDetectorStarted = false;
-  private boolean mIsDevSupportEnabled = false;
-  private boolean mIsCurrentlyProfiling = false;
-  private int     mProfileIndex = 0;
-
-  public DevSupportManager(
-      Context applicationContext,
-      ReactInstanceDevCommandsHandler reactInstanceCommandsHandler,
-      @Nullable String packagerPathForJSBundleName,
-      boolean enableOnCreate) {
-    mReactInstanceCommandsHandler = reactInstanceCommandsHandler;
-    mApplicationContext = applicationContext;
-    mJSAppBundleName = packagerPathForJSBundleName;
-    mDevSettings = new DevInternalSettings(applicationContext, this);
-    mDevServerHelper = new DevServerHelper(mDevSettings);
-
-    // Prepare shake gesture detector (will be started/stopped from #reload)
-    mShakeDetector = new ShakeDetector(new ShakeDetector.ShakeListener() {
-      @Override
-      public void onShake() {
-        showDevOptionsDialog();
-      }
-    });
-
-    // Prepare reload APP broadcast receiver (will be registered/unregistered from #reload)
-    mReloadAppBroadcastReceiver = new BroadcastReceiver() {
-      @Override
-      public void onReceive(Context context, Intent intent) {
-        String action = intent.getAction();
-        if (DevServerHelper.getReloadAppAction(context).equals(action)) {
-          if (intent.getBooleanExtra(DevServerHelper.RELOAD_APP_EXTRA_JS_PROXY, false)) {
-            mIsUsingJSProxy = true;
-            mDevServerHelper.launchChromeDevtools();
-          } else {
-            mIsUsingJSProxy = false;
-          }
-          handleReloadJS();
-        }
-      }
-    };
-
-    // We store JS bundle loaded from dev server in a single destination in app's data dir.
-    // In case when someone schedule 2 subsequent reloads it may happen that JS thread will
-    // start reading first reload output while the second reload starts writing to the same
-    // file. As this should only be the case in dev mode we leave it as it is.
-    // TODO(6418010): Fix readers-writers problem in debug reload from HTTP server
-    mJSBundleTempFile = new File(applicationContext.getFilesDir(), JS_BUNDLE_FILE_NAME);
-
-    setDevSupportEnabled(enableOnCreate);
-  }
-
-  @Override
-  public void handleException(Exception e) {
-    if (mIsDevSupportEnabled) {
-      FLog.e(ReactConstants.TAG, "Exception in native call from JS", e);
-      showNewJavaError(e.getMessage(), e);
-    } else {
-      if (e instanceof RuntimeException) {
-        // Because we are rethrowing the original exception, the original stacktrace will be
-        // preserved
-        throw (RuntimeException) e;
-      } else {
-        throw new RuntimeException(e);
-      }
-    }
-  }
-
-  public void showNewJavaError(String message, Throwable e) {
-    showNewError(message, StackTraceHelper.convertJavaStackTrace(e), JAVA_ERROR_COOKIE);
-  }
-
-  /**
-   * Add option item to dev settings dialog displayed by this manager. In the case user select given
-   * option from that dialog, the appropriate handler passed as {@param optionHandler} will be
-   * called.
-   */
-  public void addCustomDevOption(
-      String optionName,
-      DevOptionHandler optionHandler) {
-    mCustomDevOptions.put(optionName, optionHandler);
-  }
-
-  public void showNewJSError(String message, ReadableArray details, int errorCookie) {
-    showNewError(message, StackTraceHelper.convertJsStackTrace(details), errorCookie);
-  }
-
-  public void updateJSError(
-      final String message,
-      final ReadableArray details,
-      final int errorCookie) {
-    UiThreadUtil.runOnUiThread(
-        new Runnable() {
-          @Override
-          public void run() {
-            // Since we only show the first JS error in a succession of JS errors, make sure we only
-            // update the error message for that error message. This assumes that updateJSError
-            // belongs to the most recent showNewJSError
-            if (mRedBoxDialog == null ||
-                !mRedBoxDialog.isShowing() ||
-                errorCookie != mRedBoxDialog.getErrorCookie()) {
-              return;
-            }
-            mRedBoxDialog.setExceptionDetails(
-                message,
-                StackTraceHelper.convertJsStackTrace(details));
-            mRedBoxDialog.show();
-          }
-        });
-  }
-
-  private void showNewError(
-      final String message,
-      final StackFrame[] stack,
-      final int errorCookie) {
-    UiThreadUtil.runOnUiThread(
-        new Runnable() {
-          @Override
-          public void run() {
-            if (mRedBoxDialog == null) {
-              mRedBoxDialog = new RedBoxDialog(mApplicationContext, DevSupportManager.this);
-              mRedBoxDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
-            }
-            if (mRedBoxDialog.isShowing()) {
-              // Sometimes errors cause multiple errors to be thrown in JS in quick succession. Only
-              // show the first and most actionable one.
-              return;
-            }
-            mRedBoxDialog.setExceptionDetails(message, stack);
-            mRedBoxDialog.setErrorCookie(errorCookie);
-            mRedBoxDialog.show();
-          }
-        });
-  }
-
-  public void showDevOptionsDialog() {
-    if (mDevOptionsDialog != null || !mIsDevSupportEnabled) {
-      return;
-    }
-    LinkedHashMap<String, DevOptionHandler> options = new LinkedHashMap<>();
-    /* register standard options */
-    options.put(
-        mApplicationContext.getString(R.string.catalyst_reloadjs), new DevOptionHandler() {
-          @Override
-          public void onOptionSelected() {
-            handleReloadJS();
-          }
-        });
-    options.put(
-        mIsUsingJSProxy ?
-            mApplicationContext.getString(R.string.catalyst_debugjs_off) :
-            mApplicationContext.getString(R.string.catalyst_debugjs),
-        new DevOptionHandler() {
-          @Override
-          public void onOptionSelected() {
-            mIsUsingJSProxy = !mIsUsingJSProxy;
-            handleReloadJS();
-          }
-        });
-    options.put(
-            mDevSettings.isHotModuleReplacementEnabled()
-                    ? mApplicationContext.getString(R.string.catalyst_hot_module_replacement_off)
-                    : mApplicationContext.getString(R.string.catalyst_hot_module_replacement),
-            new DevOptionHandler() {
-              @Override
-              public void onOptionSelected() {
-                mDevSettings.setHotModuleReplacementEnabled(!mDevSettings.isHotModuleReplacementEnabled());
-                handleReloadJS();
-              }
-            });
-    options.put(
-        mDevSettings.isReloadOnJSChangeEnabled()
-            ? mApplicationContext.getString(R.string.catalyst_live_reload_off)
-            : mApplicationContext.getString(R.string.catalyst_live_reload),
-        new DevOptionHandler() {
-          @Override
-          public void onOptionSelected() {
-            mDevSettings.setReloadOnJSChangeEnabled(!mDevSettings.isReloadOnJSChangeEnabled());
-          }
-        });
-    options.put(
-        mDevSettings.isElementInspectorEnabled()
-          ? mApplicationContext.getString(R.string.catalyst_element_inspector_off)
-          : mApplicationContext.getString(R.string.catalyst_element_inspector),
-        new DevOptionHandler() {
-          @Override
-          public void onOptionSelected() {
-            mDevSettings.setElementInspectorEnabled(!mDevSettings.isElementInspectorEnabled());
-            mReactInstanceCommandsHandler.toggleElementInspector();
-          }
-        });
-    options.put(
-        mDevSettings.isFpsDebugEnabled()
-            ? mApplicationContext.getString(R.string.catalyst_perf_monitor_off)
-            : mApplicationContext.getString(R.string.catalyst_perf_monitor),
-        new DevOptionHandler() {
-          @Override
-          public void onOptionSelected() {
-            mDevSettings.setFpsDebugEnabled(!mDevSettings.isFpsDebugEnabled());
-          }
-        });
-    if (mCurrentContext != null &&
-        mCurrentContext.getCatalystInstance() != null &&
-        !mCurrentContext.getCatalystInstance().isDestroyed() &&
-        mCurrentContext.getCatalystInstance().supportsProfiling()) {
-      options.put(
-          mApplicationContext.getString(
-              mIsCurrentlyProfiling ? R.string.catalyst_stop_profile :
-                  R.string.catalyst_start_profile),
-          new DevOptionHandler() {
-            @Override
-            public void onOptionSelected() {
-              if (mCurrentContext != null && mCurrentContext.hasActiveCatalystInstance()) {
-                String profileName = (Environment.getExternalStorageDirectory().getPath() +
-                    "/profile_" + mProfileIndex + ".json");
-                if (mIsCurrentlyProfiling) {
-                  mIsCurrentlyProfiling = false;
-                  mProfileIndex++;
-                  Debug.stopMethodTracing();
-                  mCurrentContext.getCatalystInstance()
-                      .stopProfiler("profile", profileName);
-                  Toast.makeText(
-                      mCurrentContext,
-                      "Profile output to " + profileName,
-                      Toast.LENGTH_LONG).show();
-                } else {
-                  mIsCurrentlyProfiling = true;
-                  mCurrentContext.getCatalystInstance().startProfiler("profile");
-                  Debug.startMethodTracingSampling(
-                      profileName,
-                      JAVA_SAMPLING_PROFILE_MEMORY_BYTES,
-                      JAVA_SAMPLING_PROFILE_DELTA_US);
-                }
-              }
-            }
-          });
-    }
-    options.put(
-        mApplicationContext.getString(R.string.catalyst_settings), new DevOptionHandler() {
-          @Override
-          public void onOptionSelected() {
-            Intent intent = new Intent(mApplicationContext, DevSettingsActivity.class);
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            mApplicationContext.startActivity(intent);
-          }
-        });
-
-    if (mCustomDevOptions.size() > 0) {
-      options.putAll(mCustomDevOptions);
-    }
-
-    final DevOptionHandler[] optionHandlers = options.values().toArray(new DevOptionHandler[0]);
-
-    mDevOptionsDialog =
-        new AlertDialog.Builder(mApplicationContext)
-            .setItems(
-                options.keySet().toArray(new String[0]),
-                new DialogInterface.OnClickListener() {
-                  @Override
-                  public void onClick(DialogInterface dialog, int which) {
-                    optionHandlers[which].onOptionSelected();
-                    mDevOptionsDialog = null;
-                  }
-                })
-            .setOnCancelListener(new DialogInterface.OnCancelListener() {
-              @Override
-              public void onCancel(DialogInterface dialog) {
-                mDevOptionsDialog = null;
-              }
-            })
-            .create();
-    mDevOptionsDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
-    mDevOptionsDialog.show();
-  }
-
-  /**
-   * {@link ReactInstanceDevCommandsHandler} is responsible for
-   * enabling/disabling dev support when a React view is attached/detached
-   * or when application state changes (e.g. the application is backgrounded).
-   */
-  public void setDevSupportEnabled(boolean isDevSupportEnabled) {
-    mIsDevSupportEnabled = isDevSupportEnabled;
-    reload();
-  }
-
-  public boolean getDevSupportEnabled() {
-    return mIsDevSupportEnabled;
-  }
-
-  public DeveloperSettings getDevSettings() {
-    return mDevSettings;
-  }
-
-  public void onNewReactContextCreated(ReactContext reactContext) {
-    resetCurrentContext(reactContext);
-  }
-
-  public void onReactInstanceDestroyed(ReactContext reactContext) {
-    if (reactContext == mCurrentContext) {
-      // only call reset context when the destroyed context matches the one that is currently set
-      // for this manager
-      resetCurrentContext(null);
-    }
-  }
-
-  public String getSourceMapUrl() {
-    if (mJSAppBundleName == null) {
-      return "";
-    }
-
-    return mDevServerHelper.getSourceMapUrl(Assertions.assertNotNull(mJSAppBundleName));
-  }
-
-  public String getSourceUrl() {
-    if (mJSAppBundleName == null) {
-      return "";
-    }
-
-    return mDevServerHelper.getSourceUrl(Assertions.assertNotNull(mJSAppBundleName));
-  }
-
-  public String getJSBundleURLForRemoteDebugging() {
-    return mDevServerHelper.getJSBundleURLForRemoteDebugging(
-        Assertions.assertNotNull(mJSAppBundleName));
-  }
-
-  public String getDownloadedJSBundleFile() {
-    return mJSBundleTempFile.getAbsolutePath();
-  }
-
-  /**
-   * @return {@code true} if {@link ReactInstanceManager} should use downloaded JS bundle file
-   * instead of using JS file from assets. This may happen when app has not been updated since
-   * the last time we fetched the bundle.
-   */
-  public boolean hasUpToDateJSBundleInCache() {
-    if (mIsDevSupportEnabled && mJSBundleTempFile.exists()) {
-      try {
-        String packageName = mApplicationContext.getPackageName();
-        PackageInfo thisPackage = mApplicationContext.getPackageManager()
-            .getPackageInfo(packageName, 0);
-        if (mJSBundleTempFile.lastModified() > thisPackage.lastUpdateTime) {
-          // Base APK has not been updated since we donwloaded JS, but if app is using exopackage
-          // it may only be a single dex that has been updated. We check for exopackage dir update
-          // time in that case.
-          File exopackageDir = new File(
-              String.format(Locale.US, EXOPACKAGE_LOCATION_FORMAT, packageName));
-          if (exopackageDir.exists()) {
-            return mJSBundleTempFile.lastModified() > exopackageDir.lastModified();
-          }
-          return true;
-        }
-      } catch (PackageManager.NameNotFoundException e) {
-        // Ignore this error and just fallback to loading JS from assets
-        FLog.e(ReactConstants.TAG, "DevSupport is unable to get current app info");
-      }
-    }
-    return false;
-  }
-
-  /**
-   * @return {@code true} if JS bundle {@param bundleAssetName} exists, in that case
-   * {@link ReactInstanceManager} should use that file from assets instead of downloading bundle
-   * from dev server
-   */
-  public boolean hasBundleInAssets(String bundleAssetName) {
-    try {
-      String[] assets = mApplicationContext.getAssets().list("");
-      for (int i = 0; i < assets.length; i++) {
-        if (assets[i].equals(bundleAssetName)) {
-          return true;
-        }
-      }
-    } catch (IOException e) {
-      // Ignore this error and just fallback to downloading JS from devserver
-      FLog.e(ReactConstants.TAG, "Error while loading assets list");
-    }
-    return false;
-  }
-
-  private void resetCurrentContext(@Nullable ReactContext reactContext) {
-    if (mCurrentContext == reactContext) {
-      // new context is the same as the old one - do nothing
-      return;
-    }
-
-    // if currently profiling stop and write the profile file
-    if (mIsCurrentlyProfiling) {
-      mIsCurrentlyProfiling = false;
-      String profileName = (Environment.getExternalStorageDirectory().getPath() +
-          "/profile_" + mProfileIndex + ".json");
-      mProfileIndex++;
-      Debug.stopMethodTracing();
-      mCurrentContext.getCatalystInstance().stopProfiler("profile", profileName);
-    }
-
-    mCurrentContext = reactContext;
-
-    // Recreate debug overlay controller with new CatalystInstance object
-    if (mDebugOverlayController != null) {
-      mDebugOverlayController.setFpsDebugViewVisible(false);
-    }
-    if (reactContext != null) {
-      mDebugOverlayController = new DebugOverlayController(reactContext);
-    }
-
-    reloadSettings();
-  }
-
-  /* package */ void reloadSettings() {
-    reload();
-  }
-
-  public void handleReloadJS() {
-    UiThreadUtil.assertOnUiThread();
-
-    // dismiss redbox if exists
-    if (mRedBoxDialog != null) {
-      mRedBoxDialog.dismiss();
-    }
-
-    ProgressDialog progressDialog = new ProgressDialog(mApplicationContext);
-    progressDialog.setTitle(R.string.catalyst_jsload_title);
-    progressDialog.setMessage(mApplicationContext.getString(
-        mIsUsingJSProxy ? R.string.catalyst_remotedbg_message : R.string.catalyst_jsload_message));
-    progressDialog.setIndeterminate(true);
-    progressDialog.setCancelable(false);
-    progressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
-    progressDialog.show();
-
-    if (mIsUsingJSProxy) {
-      reloadJSInProxyMode(progressDialog);
-    } else {
-      reloadJSFromServer(progressDialog);
-    }
-  }
-
-  public void isPackagerRunning(DevServerHelper.PackagerStatusCallback callback) {
-    mDevServerHelper.isPackagerRunning(callback);
-  }
-
-  private void reloadJSInProxyMode(final ProgressDialog progressDialog) {
-    // When using js proxy, there is no need to fetch JS bundle as proxy executor will do that
-    // anyway
-    mDevServerHelper.launchChromeDevtools();
-
-    JavaJSExecutor.Factory factory = new JavaJSExecutor.Factory() {
-      @Override
-      public JavaJSExecutor create() throws Exception {
-        WebsocketJavaScriptExecutor executor = new WebsocketJavaScriptExecutor();
-        SimpleSettableFuture<Boolean> future = new SimpleSettableFuture<>();
-        executor.connect(
-            mDevServerHelper.getWebsocketProxyURL(),
-            getExecutorConnectCallback(progressDialog, future));
-        // TODO(t9349129) Don't use timeout
-        try {
-          future.get(90, TimeUnit.SECONDS);
-          return executor;
-        } catch (ExecutionException e) {
-          throw (Exception) e.getCause();
-        } catch (InterruptedException | TimeoutException e) {
-          throw new RuntimeException(e);
-        }
-      }
-    };
-    mReactInstanceCommandsHandler.onReloadWithJSDebugger(factory);
-  }
-
-  private WebsocketJavaScriptExecutor.JSExecutorConnectCallback getExecutorConnectCallback(
-      final ProgressDialog progressDialog,
-      final SimpleSettableFuture<Boolean> future) {
-    return new WebsocketJavaScriptExecutor.JSExecutorConnectCallback() {
-      @Override
-      public void onSuccess() {
-        future.set(true);
-        progressDialog.dismiss();
-      }
-
-      @Override
-      public void onFailure(final Throwable cause) {
-        progressDialog.dismiss();
-        FLog.e(ReactConstants.TAG, "Unable to connect to remote debugger", cause);
-        future.setException(
-            new IOException(
-                mApplicationContext.getString(R.string.catalyst_remotedbg_error), cause));
-      }
-    };
-  }
-
-  private void reloadJSFromServer(final ProgressDialog progressDialog) {
-    mDevServerHelper.downloadBundleFromURL(
-        new DevServerHelper.BundleDownloadCallback() {
-          @Override
-          public void onSuccess() {
-            progressDialog.dismiss();
-            UiThreadUtil.runOnUiThread(
-                new Runnable() {
-                  @Override
-                  public void run() {
-                    mReactInstanceCommandsHandler.onJSBundleLoadedFromServer();
-                  }
-                });
-          }
-
-          @Override
-          public void onFailure(final Exception cause) {
-            progressDialog.dismiss();
-            FLog.e(ReactConstants.TAG, "Unable to download JS bundle", cause);
-            UiThreadUtil.runOnUiThread(
-                new Runnable() {
-                  @Override
-                  public void run() {
-                    if (cause instanceof DebugServerException) {
-                      DebugServerException debugServerException = (DebugServerException) cause;
-                      showNewJavaError(debugServerException.description, cause);
-                    } else {
-                      showNewJavaError(
-                          mApplicationContext.getString(R.string.catalyst_jsload_error),
-                          cause);
-                    }
-                  }
-                });
-          }
-        },
-        Assertions.assertNotNull(mJSAppBundleName),
-        mJSBundleTempFile);
-    progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
-      @Override
-      public void onCancel(DialogInterface dialog) {
-        mDevServerHelper.cancelDownloadBundleFromURL();
-      }
-    });
-    progressDialog.setCancelable(true);
-  }
-
-  private void reload() {
-    // reload settings, show/hide debug overlay if required & start/stop shake detector
-    if (mIsDevSupportEnabled) {
-      // update visibility of FPS debug overlay depending on the settings
-      if (mDebugOverlayController != null) {
-        mDebugOverlayController.setFpsDebugViewVisible(mDevSettings.isFpsDebugEnabled());
-      }
-
-      // start shake gesture detector
-      if (!mIsShakeDetectorStarted) {
-        mShakeDetector.start(
-            (SensorManager) mApplicationContext.getSystemService(Context.SENSOR_SERVICE));
-        mIsShakeDetectorStarted = true;
-      }
-
-      // register reload app broadcast receiver
-      if (!mIsReceiverRegistered) {
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(DevServerHelper.getReloadAppAction(mApplicationContext));
-        mApplicationContext.registerReceiver(mReloadAppBroadcastReceiver, filter);
-        mIsReceiverRegistered = true;
-      }
-
-      if (mDevSettings.isReloadOnJSChangeEnabled()) {
-        mDevServerHelper.startPollingOnChangeEndpoint(
-            new DevServerHelper.OnServerContentChangeListener() {
-          @Override
-          public void onServerContentChanged() {
-            handleReloadJS();
-          }
-        });
-      } else {
-        mDevServerHelper.stopPollingOnChangeEndpoint();
-      }
-    } else {
-      // hide FPS debug overlay
-      if (mDebugOverlayController != null) {
-        mDebugOverlayController.setFpsDebugViewVisible(false);
-      }
-
-      // stop shake gesture detector
-      if (mIsShakeDetectorStarted) {
-        mShakeDetector.stop();
-        mIsShakeDetectorStarted = false;
-      }
-
-      // unregister app reload broadcast receiver
-      if (mIsReceiverRegistered) {
-        mApplicationContext.unregisterReceiver(mReloadAppBroadcastReceiver);
-        mIsReceiverRegistered = false;
-      }
-
-      // hide redbox dialog
-      if (mRedBoxDialog != null) {
-        mRedBoxDialog.dismiss();
-      }
-
-      // hide dev options dialog
-      if (mDevOptionsDialog != null) {
-        mDevOptionsDialog.dismiss();
-      }
-
-      mDevServerHelper.stopPollingOnChangeEndpoint();
-    }
-  }
+public interface DevSupportManager extends NativeModuleCallExceptionHandler {
+
+  void showNewJavaError(String message, Throwable e);
+  void addCustomDevOption(String optionName, DevOptionHandler optionHandler);
+  void showNewJSError(String message, ReadableArray details, int errorCookie);
+  void updateJSError(final String message, final ReadableArray details, final int errorCookie);
+  void showDevOptionsDialog();
+  void setDevSupportEnabled(boolean isDevSupportEnabled);
+  boolean getDevSupportEnabled();
+  DeveloperSettings getDevSettings();
+  void onNewReactContextCreated(ReactContext reactContext);
+  void onReactInstanceDestroyed(ReactContext reactContext);
+  String getSourceMapUrl();
+  String getSourceUrl();
+  String getJSBundleURLForRemoteDebugging();
+  String getDownloadedJSBundleFile();
+  boolean hasUpToDateJSBundleInCache();
+  void reloadSettings();
+  void handleReloadJS();
+  void isPackagerRunning(DevServerHelper.PackagerStatusCallback callback);
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java
new file mode 100644
index 000000000000..7bdeea2d7ce5
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java
@@ -0,0 +1,722 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.devsupport;
+
+import javax.annotation.Nullable;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.hardware.SensorManager;
+import android.os.Debug;
+import android.os.Environment;
+import android.view.WindowManager;
+import android.widget.Toast;
+
+import com.facebook.common.logging.FLog;
+import com.facebook.infer.annotation.Assertions;
+import com.facebook.react.R;
+import com.facebook.react.bridge.CatalystInstance;
+import com.facebook.react.bridge.DefaultNativeModuleCallExceptionHandler;
+import com.facebook.react.bridge.JavaJSExecutor;
+import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.UiThreadUtil;
+import com.facebook.react.bridge.WebsocketJavaScriptExecutor;
+import com.facebook.react.common.ReactConstants;
+import com.facebook.react.common.ShakeDetector;
+import com.facebook.react.common.futures.SimpleSettableFuture;
+import com.facebook.react.devsupport.StackTraceHelper.StackFrame;
+import com.facebook.react.modules.debug.DeveloperSettings;
+
+/**
+ * Interface for accessing and interacting with development features. Following features
+ * are supported through this manager class:
+ * 1) Displaying JS errors (aka RedBox)
+ * 2) Displaying developers menu (Reload JS, Debug JS)
+ * 3) Communication with developer server in order to download updated JS bundle
+ * 4) Starting/stopping broadcast receiver for js reload signals
+ * 5) Starting/stopping motion sensor listener that recognize shake gestures which in turn may
+ *    trigger developers menu.
+ * 6) Launching developers settings view
+ *
+ * This class automatically monitors the state of registered views and activities to which they are
+ * bound to make sure that we don't display overlay or that we we don't listen for sensor events
+ * when app is backgrounded.
+ *
+ * {@link ReactInstanceDevCommandsHandler} implementation is responsible for instantiating this
+ * instance and for populating with an instance of {@link CatalystInstance} whenever instance
+ * manager recreates it (through {@link #onNewCatalystContextCreated}). Also, instance manager is
+ * responsible for enabling/disabling dev support in case when app is backgrounded or when all the
+ * views has been detached from the instance (through {@link #setDevSupportEnabled} method).
+ *
+ * IMPORTANT: In order for developer support to work correctly it is required that the
+ * manifest of your application contain the following entries:
+ * {@code <activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>}
+ * {@code <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>}
+ */
+public class DevSupportManagerImpl implements DevSupportManager {
+
+  private static final int JAVA_ERROR_COOKIE = -1;
+  private static final String JS_BUNDLE_FILE_NAME = "ReactNativeDevBundle.js";
+
+  private static final String EXOPACKAGE_LOCATION_FORMAT
+      = "/data/local/tmp/exopackage/%s//secondary-dex";
+
+  private static final int JAVA_SAMPLING_PROFILE_MEMORY_BYTES = 8 * 1024 * 1024;
+  private static final int JAVA_SAMPLING_PROFILE_DELTA_US = 100;
+
+  private final Context mApplicationContext;
+  private final ShakeDetector mShakeDetector;
+  private final BroadcastReceiver mReloadAppBroadcastReceiver;
+  private final DevServerHelper mDevServerHelper;
+  private final LinkedHashMap<String, DevOptionHandler> mCustomDevOptions =
+      new LinkedHashMap<>();
+  private final ReactInstanceDevCommandsHandler mReactInstanceCommandsHandler;
+  private final @Nullable String mJSAppBundleName;
+  private final File mJSBundleTempFile;
+  private final DefaultNativeModuleCallExceptionHandler mDefaultNativeModuleCallExceptionHandler;
+
+  private @Nullable RedBoxDialog mRedBoxDialog;
+  private @Nullable AlertDialog mDevOptionsDialog;
+  private @Nullable DebugOverlayController mDebugOverlayController;
+  private @Nullable ReactContext mCurrentContext;
+  private DevInternalSettings mDevSettings;
+  private boolean mIsUsingJSProxy = false;
+  private boolean mIsReceiverRegistered = false;
+  private boolean mIsShakeDetectorStarted = false;
+  private boolean mIsDevSupportEnabled = false;
+  private boolean mIsCurrentlyProfiling = false;
+  private int     mProfileIndex = 0;
+
+  public DevSupportManagerImpl(
+      Context applicationContext,
+      ReactInstanceDevCommandsHandler reactInstanceCommandsHandler,
+      @Nullable String packagerPathForJSBundleName,
+      boolean enableOnCreate) {
+    mReactInstanceCommandsHandler = reactInstanceCommandsHandler;
+    mApplicationContext = applicationContext;
+    mJSAppBundleName = packagerPathForJSBundleName;
+    mDevSettings = new DevInternalSettings(applicationContext, this);
+    mDevServerHelper = new DevServerHelper(mDevSettings);
+
+    // Prepare shake gesture detector (will be started/stopped from #reload)
+    mShakeDetector = new ShakeDetector(new ShakeDetector.ShakeListener() {
+      @Override
+      public void onShake() {
+        showDevOptionsDialog();
+      }
+    });
+
+    // Prepare reload APP broadcast receiver (will be registered/unregistered from #reload)
+    mReloadAppBroadcastReceiver = new BroadcastReceiver() {
+      @Override
+      public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+        if (DevServerHelper.getReloadAppAction(context).equals(action)) {
+          if (intent.getBooleanExtra(DevServerHelper.RELOAD_APP_EXTRA_JS_PROXY, false)) {
+            mIsUsingJSProxy = true;
+            mDevServerHelper.launchChromeDevtools();
+          } else {
+            mIsUsingJSProxy = false;
+          }
+          handleReloadJS();
+        }
+      }
+    };
+
+    // We store JS bundle loaded from dev server in a single destination in app's data dir.
+    // In case when someone schedule 2 subsequent reloads it may happen that JS thread will
+    // start reading first reload output while the second reload starts writing to the same
+    // file. As this should only be the case in dev mode we leave it as it is.
+    // TODO(6418010): Fix readers-writers problem in debug reload from HTTP server
+    mJSBundleTempFile = new File(applicationContext.getFilesDir(), JS_BUNDLE_FILE_NAME);
+
+    mDefaultNativeModuleCallExceptionHandler = new DefaultNativeModuleCallExceptionHandler();
+
+    setDevSupportEnabled(enableOnCreate);
+  }
+
+  @Override
+  public void handleException(Exception e) {
+    if (mIsDevSupportEnabled) {
+      FLog.e(ReactConstants.TAG, "Exception in native call from JS", e);
+      showNewJavaError(e.getMessage(), e);
+    } else {
+      mDefaultNativeModuleCallExceptionHandler.handleException(e);
+    }
+  }
+
+  @Override
+  public void showNewJavaError(String message, Throwable e) {
+    showNewError(message, StackTraceHelper.convertJavaStackTrace(e), JAVA_ERROR_COOKIE);
+  }
+
+  /**
+   * Add option item to dev settings dialog displayed by this manager. In the case user select given
+   * option from that dialog, the appropriate handler passed as {@param optionHandler} will be
+   * called.
+   */
+  @Override
+  public void addCustomDevOption(
+      String optionName,
+      DevOptionHandler optionHandler) {
+    mCustomDevOptions.put(optionName, optionHandler);
+  }
+
+  @Override
+  public void showNewJSError(String message, ReadableArray details, int errorCookie) {
+    showNewError(message, StackTraceHelper.convertJsStackTrace(details), errorCookie);
+  }
+
+  @Override
+  public void updateJSError(
+      final String message,
+      final ReadableArray details,
+      final int errorCookie) {
+    UiThreadUtil.runOnUiThread(
+        new Runnable() {
+          @Override
+          public void run() {
+            // Since we only show the first JS error in a succession of JS errors, make sure we only
+            // update the error message for that error message. This assumes that updateJSError
+            // belongs to the most recent showNewJSError
+            if (mRedBoxDialog == null ||
+                !mRedBoxDialog.isShowing() ||
+                errorCookie != mRedBoxDialog.getErrorCookie()) {
+              return;
+            }
+            mRedBoxDialog.setExceptionDetails(
+                message,
+                StackTraceHelper.convertJsStackTrace(details));
+            mRedBoxDialog.show();
+          }
+        });
+  }
+
+  private void showNewError(
+      final String message,
+      final StackFrame[] stack,
+      final int errorCookie) {
+    UiThreadUtil.runOnUiThread(
+        new Runnable() {
+          @Override
+          public void run() {
+            if (mRedBoxDialog == null) {
+              mRedBoxDialog = new RedBoxDialog(mApplicationContext, DevSupportManagerImpl.this);
+              mRedBoxDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+            }
+            if (mRedBoxDialog.isShowing()) {
+              // Sometimes errors cause multiple errors to be thrown in JS in quick succession. Only
+              // show the first and most actionable one.
+              return;
+            }
+            mRedBoxDialog.setExceptionDetails(message, stack);
+            mRedBoxDialog.setErrorCookie(errorCookie);
+            mRedBoxDialog.show();
+          }
+        });
+  }
+
+  @Override
+  public void showDevOptionsDialog() {
+    if (mDevOptionsDialog != null || !mIsDevSupportEnabled) {
+      return;
+    }
+    LinkedHashMap<String, DevOptionHandler> options = new LinkedHashMap<>();
+    /* register standard options */
+    options.put(
+        mApplicationContext.getString(R.string.catalyst_reloadjs), new DevOptionHandler() {
+          @Override
+          public void onOptionSelected() {
+            handleReloadJS();
+          }
+        });
+    options.put(
+        mIsUsingJSProxy ?
+            mApplicationContext.getString(R.string.catalyst_debugjs_off) :
+            mApplicationContext.getString(R.string.catalyst_debugjs),
+        new DevOptionHandler() {
+          @Override
+          public void onOptionSelected() {
+            mIsUsingJSProxy = !mIsUsingJSProxy;
+            handleReloadJS();
+          }
+        });
+    options.put(
+            mDevSettings.isHotModuleReplacementEnabled()
+                    ? mApplicationContext.getString(R.string.catalyst_hot_module_replacement_off)
+                    : mApplicationContext.getString(R.string.catalyst_hot_module_replacement),
+            new DevOptionHandler() {
+              @Override
+              public void onOptionSelected() {
+                mDevSettings.setHotModuleReplacementEnabled(!mDevSettings.isHotModuleReplacementEnabled());
+                handleReloadJS();
+              }
+            });
+    options.put(
+        mDevSettings.isReloadOnJSChangeEnabled()
+            ? mApplicationContext.getString(R.string.catalyst_live_reload_off)
+            : mApplicationContext.getString(R.string.catalyst_live_reload),
+        new DevOptionHandler() {
+          @Override
+          public void onOptionSelected() {
+            mDevSettings.setReloadOnJSChangeEnabled(!mDevSettings.isReloadOnJSChangeEnabled());
+          }
+        });
+    options.put(
+        mDevSettings.isElementInspectorEnabled()
+          ? mApplicationContext.getString(R.string.catalyst_element_inspector_off)
+          : mApplicationContext.getString(R.string.catalyst_element_inspector),
+        new DevOptionHandler() {
+          @Override
+          public void onOptionSelected() {
+            mDevSettings.setElementInspectorEnabled(!mDevSettings.isElementInspectorEnabled());
+            mReactInstanceCommandsHandler.toggleElementInspector();
+          }
+        });
+    options.put(
+        mDevSettings.isFpsDebugEnabled()
+            ? mApplicationContext.getString(R.string.catalyst_perf_monitor_off)
+            : mApplicationContext.getString(R.string.catalyst_perf_monitor),
+        new DevOptionHandler() {
+          @Override
+          public void onOptionSelected() {
+            mDevSettings.setFpsDebugEnabled(!mDevSettings.isFpsDebugEnabled());
+          }
+        });
+    if (mCurrentContext != null &&
+        mCurrentContext.getCatalystInstance() != null &&
+        !mCurrentContext.getCatalystInstance().isDestroyed() &&
+        mCurrentContext.getCatalystInstance().supportsProfiling()) {
+      options.put(
+          mApplicationContext.getString(
+              mIsCurrentlyProfiling ? R.string.catalyst_stop_profile :
+                  R.string.catalyst_start_profile),
+          new DevOptionHandler() {
+            @Override
+            public void onOptionSelected() {
+              if (mCurrentContext != null && mCurrentContext.hasActiveCatalystInstance()) {
+                String profileName = (Environment.getExternalStorageDirectory().getPath() +
+                    "/profile_" + mProfileIndex + ".json");
+                if (mIsCurrentlyProfiling) {
+                  mIsCurrentlyProfiling = false;
+                  mProfileIndex++;
+                  Debug.stopMethodTracing();
+                  mCurrentContext.getCatalystInstance()
+                      .stopProfiler("profile", profileName);
+                  Toast.makeText(
+                      mCurrentContext,
+                      "Profile output to " + profileName,
+                      Toast.LENGTH_LONG).show();
+                } else {
+                  mIsCurrentlyProfiling = true;
+                  mCurrentContext.getCatalystInstance().startProfiler("profile");
+                  Debug.startMethodTracingSampling(
+                      profileName,
+                      JAVA_SAMPLING_PROFILE_MEMORY_BYTES,
+                      JAVA_SAMPLING_PROFILE_DELTA_US);
+                }
+              }
+            }
+          });
+    }
+    options.put(
+        mApplicationContext.getString(R.string.catalyst_settings), new DevOptionHandler() {
+          @Override
+          public void onOptionSelected() {
+            Intent intent = new Intent(mApplicationContext, DevSettingsActivity.class);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            mApplicationContext.startActivity(intent);
+          }
+        });
+
+    if (mCustomDevOptions.size() > 0) {
+      options.putAll(mCustomDevOptions);
+    }
+
+    final DevOptionHandler[] optionHandlers = options.values().toArray(new DevOptionHandler[0]);
+
+    mDevOptionsDialog =
+        new AlertDialog.Builder(mApplicationContext)
+            .setItems(
+                options.keySet().toArray(new String[0]),
+                new DialogInterface.OnClickListener() {
+                  @Override
+                  public void onClick(DialogInterface dialog, int which) {
+                    optionHandlers[which].onOptionSelected();
+                    mDevOptionsDialog = null;
+                  }
+                })
+            .setOnCancelListener(new DialogInterface.OnCancelListener() {
+              @Override
+              public void onCancel(DialogInterface dialog) {
+                mDevOptionsDialog = null;
+              }
+            })
+            .create();
+    mDevOptionsDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+    mDevOptionsDialog.show();
+  }
+
+  /**
+   * {@link ReactInstanceDevCommandsHandler} is responsible for
+   * enabling/disabling dev support when a React view is attached/detached
+   * or when application state changes (e.g. the application is backgrounded).
+   */
+  @Override
+  public void setDevSupportEnabled(boolean isDevSupportEnabled) {
+    mIsDevSupportEnabled = isDevSupportEnabled;
+    reload();
+  }
+
+  @Override
+  public boolean getDevSupportEnabled() {
+    return mIsDevSupportEnabled;
+  }
+
+  @Override
+  public DeveloperSettings getDevSettings() {
+    return mDevSettings;
+  }
+
+  @Override
+  public void onNewReactContextCreated(ReactContext reactContext) {
+    resetCurrentContext(reactContext);
+  }
+
+  @Override
+  public void onReactInstanceDestroyed(ReactContext reactContext) {
+    if (reactContext == mCurrentContext) {
+      // only call reset context when the destroyed context matches the one that is currently set
+      // for this manager
+      resetCurrentContext(null);
+    }
+  }
+
+  @Override
+  public String getSourceMapUrl() {
+    if (mJSAppBundleName == null) {
+      return "";
+    }
+
+    return mDevServerHelper.getSourceMapUrl(Assertions.assertNotNull(mJSAppBundleName));
+  }
+
+  @Override
+  public String getSourceUrl() {
+    if (mJSAppBundleName == null) {
+      return "";
+    }
+
+    return mDevServerHelper.getSourceUrl(Assertions.assertNotNull(mJSAppBundleName));
+  }
+
+  @Override
+  public String getJSBundleURLForRemoteDebugging() {
+    return mDevServerHelper.getJSBundleURLForRemoteDebugging(
+        Assertions.assertNotNull(mJSAppBundleName));
+  }
+
+  @Override
+  public String getDownloadedJSBundleFile() {
+    return mJSBundleTempFile.getAbsolutePath();
+  }
+
+  /**
+   * @return {@code true} if {@link ReactInstanceManager} should use downloaded JS bundle file
+   * instead of using JS file from assets. This may happen when app has not been updated since
+   * the last time we fetched the bundle.
+   */
+  @Override
+  public boolean hasUpToDateJSBundleInCache() {
+    if (mIsDevSupportEnabled && mJSBundleTempFile.exists()) {
+      try {
+        String packageName = mApplicationContext.getPackageName();
+        PackageInfo thisPackage = mApplicationContext.getPackageManager()
+            .getPackageInfo(packageName, 0);
+        if (mJSBundleTempFile.lastModified() > thisPackage.lastUpdateTime) {
+          // Base APK has not been updated since we donwloaded JS, but if app is using exopackage
+          // it may only be a single dex that has been updated. We check for exopackage dir update
+          // time in that case.
+          File exopackageDir = new File(
+              String.format(Locale.US, EXOPACKAGE_LOCATION_FORMAT, packageName));
+          if (exopackageDir.exists()) {
+            return mJSBundleTempFile.lastModified() > exopackageDir.lastModified();
+          }
+          return true;
+        }
+      } catch (PackageManager.NameNotFoundException e) {
+        // Ignore this error and just fallback to loading JS from assets
+        FLog.e(ReactConstants.TAG, "DevSupport is unable to get current app info");
+      }
+    }
+    return false;
+  }
+
+  /**
+   * @return {@code true} if JS bundle {@param bundleAssetName} exists, in that case
+   * {@link ReactInstanceManager} should use that file from assets instead of downloading bundle
+   * from dev server
+   */
+  public boolean hasBundleInAssets(String bundleAssetName) {
+    try {
+      String[] assets = mApplicationContext.getAssets().list("");
+      for (int i = 0; i < assets.length; i++) {
+        if (assets[i].equals(bundleAssetName)) {
+          return true;
+        }
+      }
+    } catch (IOException e) {
+      // Ignore this error and just fallback to downloading JS from devserver
+      FLog.e(ReactConstants.TAG, "Error while loading assets list");
+    }
+    return false;
+  }
+
+  private void resetCurrentContext(@Nullable ReactContext reactContext) {
+    if (mCurrentContext == reactContext) {
+      // new context is the same as the old one - do nothing
+      return;
+    }
+
+    // if currently profiling stop and write the profile file
+    if (mIsCurrentlyProfiling) {
+      mIsCurrentlyProfiling = false;
+      String profileName = (Environment.getExternalStorageDirectory().getPath() +
+          "/profile_" + mProfileIndex + ".json");
+      mProfileIndex++;
+      Debug.stopMethodTracing();
+      mCurrentContext.getCatalystInstance().stopProfiler("profile", profileName);
+    }
+
+    mCurrentContext = reactContext;
+
+    // Recreate debug overlay controller with new CatalystInstance object
+    if (mDebugOverlayController != null) {
+      mDebugOverlayController.setFpsDebugViewVisible(false);
+    }
+    if (reactContext != null) {
+      mDebugOverlayController = new DebugOverlayController(reactContext);
+    }
+
+    reloadSettings();
+  }
+
+  @Override
+  public void reloadSettings() {
+    reload();
+  }
+
+  @Override
+  public void handleReloadJS() {
+    UiThreadUtil.assertOnUiThread();
+
+    // dismiss redbox if exists
+    if (mRedBoxDialog != null) {
+      mRedBoxDialog.dismiss();
+    }
+
+    ProgressDialog progressDialog = new ProgressDialog(mApplicationContext);
+    progressDialog.setTitle(R.string.catalyst_jsload_title);
+    progressDialog.setMessage(mApplicationContext.getString(
+        mIsUsingJSProxy ? R.string.catalyst_remotedbg_message : R.string.catalyst_jsload_message));
+    progressDialog.setIndeterminate(true);
+    progressDialog.setCancelable(false);
+    progressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+    progressDialog.show();
+
+    if (mIsUsingJSProxy) {
+      reloadJSInProxyMode(progressDialog);
+    } else {
+      reloadJSFromServer(progressDialog);
+    }
+  }
+
+  @Override
+  public void isPackagerRunning(DevServerHelper.PackagerStatusCallback callback) {
+    mDevServerHelper.isPackagerRunning(callback);
+  }
+
+  private void reloadJSInProxyMode(final ProgressDialog progressDialog) {
+    // When using js proxy, there is no need to fetch JS bundle as proxy executor will do that
+    // anyway
+    mDevServerHelper.launchChromeDevtools();
+
+    JavaJSExecutor.Factory factory = new JavaJSExecutor.Factory() {
+      @Override
+      public JavaJSExecutor create() throws Exception {
+        WebsocketJavaScriptExecutor executor = new WebsocketJavaScriptExecutor();
+        SimpleSettableFuture<Boolean> future = new SimpleSettableFuture<>();
+        executor.connect(
+            mDevServerHelper.getWebsocketProxyURL(),
+            getExecutorConnectCallback(progressDialog, future));
+        // TODO(t9349129) Don't use timeout
+        try {
+          future.get(90, TimeUnit.SECONDS);
+          return executor;
+        } catch (ExecutionException e) {
+          throw (Exception) e.getCause();
+        } catch (InterruptedException | TimeoutException e) {
+          throw new RuntimeException(e);
+        }
+      }
+    };
+    mReactInstanceCommandsHandler.onReloadWithJSDebugger(factory);
+  }
+
+  private WebsocketJavaScriptExecutor.JSExecutorConnectCallback getExecutorConnectCallback(
+      final ProgressDialog progressDialog,
+      final SimpleSettableFuture<Boolean> future) {
+    return new WebsocketJavaScriptExecutor.JSExecutorConnectCallback() {
+      @Override
+      public void onSuccess() {
+        future.set(true);
+        progressDialog.dismiss();
+      }
+
+      @Override
+      public void onFailure(final Throwable cause) {
+        progressDialog.dismiss();
+        FLog.e(ReactConstants.TAG, "Unable to connect to remote debugger", cause);
+        future.setException(
+            new IOException(
+                mApplicationContext.getString(R.string.catalyst_remotedbg_error), cause));
+      }
+    };
+  }
+
+  private void reloadJSFromServer(final ProgressDialog progressDialog) {
+    mDevServerHelper.downloadBundleFromURL(
+        new DevServerHelper.BundleDownloadCallback() {
+          @Override
+          public void onSuccess() {
+            progressDialog.dismiss();
+            UiThreadUtil.runOnUiThread(
+                new Runnable() {
+                  @Override
+                  public void run() {
+                    mReactInstanceCommandsHandler.onJSBundleLoadedFromServer();
+                  }
+                });
+          }
+
+          @Override
+          public void onFailure(final Exception cause) {
+            progressDialog.dismiss();
+            FLog.e(ReactConstants.TAG, "Unable to download JS bundle", cause);
+            UiThreadUtil.runOnUiThread(
+                new Runnable() {
+                  @Override
+                  public void run() {
+                    if (cause instanceof DebugServerException) {
+                      DebugServerException debugServerException = (DebugServerException) cause;
+                      showNewJavaError(debugServerException.description, cause);
+                    } else {
+                      showNewJavaError(
+                          mApplicationContext.getString(R.string.catalyst_jsload_error),
+                          cause);
+                    }
+                  }
+                });
+          }
+        },
+        Assertions.assertNotNull(mJSAppBundleName),
+        mJSBundleTempFile);
+    progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+      @Override
+      public void onCancel(DialogInterface dialog) {
+        mDevServerHelper.cancelDownloadBundleFromURL();
+      }
+    });
+    progressDialog.setCancelable(true);
+  }
+
+  private void reload() {
+    // reload settings, show/hide debug overlay if required & start/stop shake detector
+    if (mIsDevSupportEnabled) {
+      // update visibility of FPS debug overlay depending on the settings
+      if (mDebugOverlayController != null) {
+        mDebugOverlayController.setFpsDebugViewVisible(mDevSettings.isFpsDebugEnabled());
+      }
+
+      // start shake gesture detector
+      if (!mIsShakeDetectorStarted) {
+        mShakeDetector.start(
+            (SensorManager) mApplicationContext.getSystemService(Context.SENSOR_SERVICE));
+        mIsShakeDetectorStarted = true;
+      }
+
+      // register reload app broadcast receiver
+      if (!mIsReceiverRegistered) {
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(DevServerHelper.getReloadAppAction(mApplicationContext));
+        mApplicationContext.registerReceiver(mReloadAppBroadcastReceiver, filter);
+        mIsReceiverRegistered = true;
+      }
+
+      if (mDevSettings.isReloadOnJSChangeEnabled()) {
+        mDevServerHelper.startPollingOnChangeEndpoint(
+            new DevServerHelper.OnServerContentChangeListener() {
+          @Override
+          public void onServerContentChanged() {
+            handleReloadJS();
+          }
+        });
+      } else {
+        mDevServerHelper.stopPollingOnChangeEndpoint();
+      }
+    } else {
+      // hide FPS debug overlay
+      if (mDebugOverlayController != null) {
+        mDebugOverlayController.setFpsDebugViewVisible(false);
+      }
+
+      // stop shake gesture detector
+      if (mIsShakeDetectorStarted) {
+        mShakeDetector.stop();
+        mIsShakeDetectorStarted = false;
+      }
+
+      // unregister app reload broadcast receiver
+      if (mIsReceiverRegistered) {
+        mApplicationContext.unregisterReceiver(mReloadAppBroadcastReceiver);
+        mIsReceiverRegistered = false;
+      }
+
+      // hide redbox dialog
+      if (mRedBoxDialog != null) {
+        mRedBoxDialog.dismiss();
+      }
+
+      // hide dev options dialog
+      if (mDevOptionsDialog != null) {
+        mDevOptionsDialog.dismiss();
+      }
+
+      mDevServerHelper.stopPollingOnChangeEndpoint();
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DisabledDevSupportManager.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DisabledDevSupportManager.java
new file mode 100644
index 000000000000..44edbc8866ec
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DisabledDevSupportManager.java
@@ -0,0 +1,116 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.devsupport;
+
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.modules.debug.DeveloperSettings;
+
+/**
+ * A dummy implementation of {@link DevSupportManager} to be used in production mode where
+ * development features aren't needed.
+ */
+public class DisabledDevSupportManager implements DevSupportManager {
+
+  @Override
+  public void showNewJavaError(String message, Throwable e) {
+
+  }
+
+  @Override
+  public void addCustomDevOption(String optionName, DevOptionHandler optionHandler) {
+
+  }
+
+  @Override
+  public void showNewJSError(String message, ReadableArray details, int errorCookie) {
+
+  }
+
+  @Override
+  public void updateJSError(String message, ReadableArray details, int errorCookie) {
+
+  }
+
+  @Override
+  public void showDevOptionsDialog() {
+
+  }
+
+  @Override
+  public void setDevSupportEnabled(boolean isDevSupportEnabled) {
+
+  }
+
+  @Override
+  public boolean getDevSupportEnabled() {
+    return false;
+  }
+
+  @Override
+  public DeveloperSettings getDevSettings() {
+    return null;
+  }
+
+  @Override
+  public void onNewReactContextCreated(ReactContext reactContext) {
+
+  }
+
+  @Override
+  public void onReactInstanceDestroyed(ReactContext reactContext) {
+
+  }
+
+  @Override
+  public String getSourceMapUrl() {
+    return null;
+  }
+
+  @Override
+  public String getSourceUrl() {
+    return null;
+  }
+
+  @Override
+  public String getJSBundleURLForRemoteDebugging() {
+    return null;
+  }
+
+  @Override
+  public String getDownloadedJSBundleFile() {
+    return null;
+  }
+
+  @Override
+  public boolean hasUpToDateJSBundleInCache() {
+    return false;
+  }
+
+  @Override
+  public void reloadSettings() {
+
+  }
+
+  @Override
+  public void handleReloadJS() {
+
+  }
+
+  @Override
+  public void isPackagerRunning(DevServerHelper.PackagerStatusCallback callback) {
+
+  }
+
+  @Override
+  public void handleException(Exception e) {
+
+  }
+}

From 73be933d09cc279474102820859b757ba8f9987c Mon Sep 17 00:00:00 2001
From: Aaron Chiu <aaronechiu@fb.com>
Date: Fri, 8 Jan 2016 20:58:47 -0800
Subject: [PATCH 0695/1411] fix release builds throwing errors / accessing null
 objects

Reviewed By: zjj010104

Differential Revision: D2816705

fb-gh-sync-id: 0873fd26b3b34fb56abf5ed033198f1b1d84057f
---
 .../react/devsupport/DisabledDevSupportManager.java      | 9 ++++++++-
 .../react/modules/debug/AnimationsDebugModule.java       | 5 +++--
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DisabledDevSupportManager.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DisabledDevSupportManager.java
index 44edbc8866ec..54f5335cd21b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DisabledDevSupportManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DisabledDevSupportManager.java
@@ -9,6 +9,7 @@
 
 package com.facebook.react.devsupport;
 
+import com.facebook.react.bridge.DefaultNativeModuleCallExceptionHandler;
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.modules.debug.DeveloperSettings;
@@ -19,6 +20,12 @@
  */
 public class DisabledDevSupportManager implements DevSupportManager {
 
+  private final DefaultNativeModuleCallExceptionHandler mDefaultNativeModuleCallExceptionHandler;
+
+  public DisabledDevSupportManager() {
+    mDefaultNativeModuleCallExceptionHandler = new DefaultNativeModuleCallExceptionHandler();
+  }
+
   @Override
   public void showNewJavaError(String message, Throwable e) {
 
@@ -111,6 +118,6 @@ public void isPackagerRunning(DevServerHelper.PackagerStatusCallback callback) {
 
   @Override
   public void handleException(Exception e) {
-
+    mDefaultNativeModuleCallExceptionHandler.handleException(e);
   }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/debug/AnimationsDebugModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/debug/AnimationsDebugModule.java
index 6b914aae2690..dc96645815cf 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/debug/AnimationsDebugModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/debug/AnimationsDebugModule.java
@@ -31,7 +31,7 @@
 public class AnimationsDebugModule extends ReactContextBaseJavaModule {
 
   private @Nullable FpsDebugFrameCallback mFrameCallback;
-  private final DeveloperSettings mCatalystSettings;
+  private @Nullable final DeveloperSettings mCatalystSettings;
 
   public AnimationsDebugModule(
       ReactApplicationContext reactContext,
@@ -47,7 +47,8 @@ public String getName() {
 
   @ReactMethod
   public void startRecordingFps() {
-    if (!mCatalystSettings.isAnimationFpsDebugEnabled()) {
+    if (mCatalystSettings == null ||
+        !mCatalystSettings.isAnimationFpsDebugEnabled()) {
       return;
     }
 

From d8830fb2b8177ae793b7d0ab18a140363b2a3460 Mon Sep 17 00:00:00 2001
From: trave7er <mathew.park.yu@gmail.com>
Date: Sat, 9 Jan 2016 01:34:27 -0800
Subject: [PATCH 0696/1411] fix lint warnings: white spaces and es6 arrow func

Summary:
fixed some lint warnings: semi-colons, white spaces, and es6 arrow function syntax
Closes https://github.com/facebook/react-native/pull/5218

Reviewed By: svcscm

Differential Revision: D2818388

Pulled By: androidtrunkagent

fb-gh-sync-id: 812792dfae87d117fd7a5ffc6faa375c161c3b15
---
 Examples/UIExplorer/AlertIOSExample.js                 | 10 +++++-----
 .../PullToRefreshViewAndroidExample.android.js         |  7 ++++---
 2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/Examples/UIExplorer/AlertIOSExample.js b/Examples/UIExplorer/AlertIOSExample.js
index 117c4cfe3329..015d68a18a95 100644
--- a/Examples/UIExplorer/AlertIOSExample.js
+++ b/Examples/UIExplorer/AlertIOSExample.js
@@ -55,7 +55,7 @@ exports.examples = [{
               {'default'}
             </Text>
           </View>
-          
+
         </TouchableHighlight>
         <TouchableHighlight
           style={styles.wrapper}
@@ -73,7 +73,7 @@ exports.examples = [{
               plain-text
             </Text>
           </View>
-          
+
         </TouchableHighlight>
         <TouchableHighlight
           style={styles.wrapper}
@@ -91,7 +91,7 @@ exports.examples = [{
               secure-text
             </Text>
           </View>
-          
+
         </TouchableHighlight>
         <TouchableHighlight
           style={styles.wrapper}
@@ -109,7 +109,7 @@ exports.examples = [{
               login-password
             </Text>
           </View>
-          
+
         </TouchableHighlight>
       </View>
     );
@@ -118,7 +118,7 @@ exports.examples = [{
 {
   title: 'Prompt',
   render(): React.Component {
-    return <PromptExample />
+    return <PromptExample />;
   }
 }];
 
diff --git a/Examples/UIExplorer/PullToRefreshViewAndroidExample.android.js b/Examples/UIExplorer/PullToRefreshViewAndroidExample.android.js
index 307fe2cde5e6..3d22f7608e93 100644
--- a/Examples/UIExplorer/PullToRefreshViewAndroidExample.android.js
+++ b/Examples/UIExplorer/PullToRefreshViewAndroidExample.android.js
@@ -72,7 +72,8 @@ const PullToRefreshViewAndroidExample = React.createClass({
       isRefreshing: false,
       loaded: 0,
       rowData: Array.from(new Array(20)).map(
-        (val, i) => {return {text: 'Initial row' + i, clicks: 0}}),
+        (val, i) => ({text: 'Initial row' + i, clicks: 0})
+      ),
     };
   },
 
@@ -107,10 +108,10 @@ const PullToRefreshViewAndroidExample = React.createClass({
     setTimeout(() => {
       // prepend 10 items
       const rowData = Array.from(new Array(10))
-      .map((val, i) => {return {
+      .map((val, i) => ({
         text: 'Loaded row' + (+this.state.loaded + i),
         clicks: 0,
-      }})
+      }))
       .concat(this.state.rowData);
 
       this.setState({

From 521bd03f0a94df35e21d368a3416599f5f01f5dc Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Sat, 9 Jan 2016 15:26:29 +0000
Subject: [PATCH 0697/1411] Revert 5da0e135b6224a2ec9677da3494b8c1e90b06908

It caused problems on Windows unfortunately and when we tried to
fix it we got: https://github.com/facebook/react-native/issues/5159

Reverting to unblock people. In the future we'll do careful rc
releases of the CLI. We should try to make the change again without
breaking anyone, regardless of OS (OSX, Linux, Windows) or npm version.
---
 react-native-cli/index.js     | 68 +++++++++++++++++------------------
 react-native-cli/package.json |  2 +-
 2 files changed, 33 insertions(+), 37 deletions(-)

diff --git a/react-native-cli/index.js b/react-native-cli/index.js
index 83d0a6bc9d11..37a7b2b42dd8 100755
--- a/react-native-cli/index.js
+++ b/react-native-cli/index.js
@@ -42,7 +42,6 @@ var spawn = require('child_process').spawn;
 var chalk = require('chalk');
 var prompt = require('prompt');
 var semver = require('semver');
-var os = require('os');
 
 var CLI_MODULE_PATH = function() {
   return path.resolve(
@@ -84,16 +83,11 @@ if (cli) {
   switch (args[0]) {
   case 'init':
     if (args[1]) {
-      var logLevel = '';
-      if (process.argv.indexOf('--verbose') >= 0) {
-        logLevel = 'verbose';
-      } else if (process.argv.indexOf('--debug') >= 0) {
-        logLevel = 'debug';
-      }
-      init(args[1], logLevel);
+      var verbose = process.argv.indexOf('--verbose') >= 0;
+      init(args[1], verbose);
     } else {
       console.error(
-        'Usage: react-native init <ProjectName> [--debug|--verbose]'
+        'Usage: react-native init <ProjectName> [--verbose]'
       );
       process.exit(1);
     }
@@ -129,17 +123,17 @@ function validatePackageName(name) {
   }
 }
 
-function init(name, logLevel) {
+function init(name, verbose) {
   validatePackageName(name);
 
   if (fs.existsSync(name)) {
-    createAfterConfirmation(name, logLevel);
+    createAfterConfirmation(name, verbose);
   } else {
-    createProject(name, logLevel);
+    createProject(name, verbose);
   }
 }
 
-function createAfterConfirmation(name, logLevel) {
+function createAfterConfirmation(name, verbose) {
   prompt.start();
 
   var property = {
@@ -152,7 +146,7 @@ function createAfterConfirmation(name, logLevel) {
 
   prompt.get(property, function (err, result) {
     if (result.yesno[0] === 'y') {
-      createProject(name, logLevel);
+      createProject(name, verbose);
     } else {
       console.log('Project initialization canceled');
       process.exit();
@@ -160,7 +154,7 @@ function createAfterConfirmation(name, logLevel) {
   });
 }
 
-function createProject(name, logLevel) {
+function createProject(name, verbose) {
   var root = path.resolve(name);
   var projectName = path.basename(root);
 
@@ -186,35 +180,37 @@ function createProject(name, logLevel) {
 
   console.log('Installing react-native package from npm...');
 
-  run(root, projectName, logLevel);
-}
-
-function run(root, projectName, logLevel) {
-  var args = ['install', '--save'];
-  if (logLevel === 'verbose') {
-    args.push('--verbose');
-  }
-  args.push('react-native');
-  var spawnArgs = {};
-  if (logLevel === 'debug' || logLevel === 'verbose') {
-    spawnArgs = {stdio: 'inherit'};
-  }
-  var proc;
-  if (/^win/.test(process.platform)) {
-    args.unshift('npm');
-    args.unshift('/c');
-    proc = spawn('cmd', args, spawnArgs);
+  if (verbose) {
+    runVerbose(root, projectName);
   } else {
-    proc = spawn('npm', args, spawnArgs);
+    run(root, projectName);
   }
+}
+
+function run(root, projectName) {
+  exec('npm install --save react-native', function(e, stdout, stderr) {
+    if (e) {
+      console.log(stdout);
+      console.error(stderr);
+      console.error('`npm install --save react-native` failed');
+      process.exit(1);
+    }
+
+    checkNodeVersion();
+
+    var cli = require(CLI_MODULE_PATH());
+    cli.init(root, projectName);
+  });
+}
+
+function runVerbose(root, projectName) {
+  var proc = spawn('npm', ['install', '--verbose', '--save', 'react-native'], {stdio: 'inherit'});
   proc.on('close', function (code) {
     if (code !== 0) {
       console.error('`npm install --save react-native` failed');
       return;
     }
 
-    checkNodeVersion();
-
     cli = require(CLI_MODULE_PATH());
     cli.init(root, projectName);
   });
diff --git a/react-native-cli/package.json b/react-native-cli/package.json
index 3195fc42686f..d1de18e2d205 100644
--- a/react-native-cli/package.json
+++ b/react-native-cli/package.json
@@ -1,6 +1,6 @@
 {
   "name": "react-native-cli",
-  "version": "0.1.9",
+  "version": "0.1.10",
   "license" : "BSD-3-Clause",
   "description": "The React Native CLI tools",
   "main": "index.js",

From b34f6c9f7451421678d7e4785bab9e6dad819d53 Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Sat, 9 Jan 2016 10:43:02 -0500
Subject: [PATCH 0698/1411] Add doc for RefreshControl

---
 website/server/extractDocs.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/website/server/extractDocs.js b/website/server/extractDocs.js
index 52ff2b8ae780..e9b25cd4e7ca 100644
--- a/website/server/extractDocs.js
+++ b/website/server/extractDocs.js
@@ -199,6 +199,7 @@ var components = [
   '../Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js',
   '../Libraries/Components/ProgressViewIOS/ProgressViewIOS.ios.js',
   '../Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js',
+  '../Libraries/Components/RefreshControl/RefreshControl.js',
   '../Libraries/Components/ScrollView/ScrollView.js',
   '../Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js',
   '../Libraries/Components/SliderIOS/SliderIOS.ios.js',

From 2d6db6caa873711859e9d0e30fe23c0843d565e6 Mon Sep 17 00:00:00 2001
From: BerndWessels <wesselsbernd@gmail.com>
Date: Mon, 11 Jan 2016 09:14:59 +1300
Subject: [PATCH 0699/1411] Added Hyper-V Android Emulator Setup Instructions.
 Closes #3234

---
 docs/DevelopmentSetupAndroid.md | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/docs/DevelopmentSetupAndroid.md b/docs/DevelopmentSetupAndroid.md
index bf7ec1e20888..4b0b8fe93ad6 100644
--- a/docs/DevelopmentSetupAndroid.md
+++ b/docs/DevelopmentSetupAndroid.md
@@ -78,3 +78,20 @@ Genymotion is much easier to set up than stock Google emulators. However, it's o
   ![Create AVD dialog](/react-native/img/CreateAVD.png)
   2. With the new AVD selected, click `Start...`
 5. To bring up the developer menu press F2 (or install [Frappé](http://getfrappe.com))
+
+### Windows Hyper-V Alternative
+
+The [Visual Studio Emulator for Android](https://www.visualstudio.com/en-us/features/msft-android-emulator-vs.aspx) is a free android emulator that is hardware accelerated via Hyper-V. It doesn't require you to install Visual Studio at all.
+
+To use it with react-native you just have to add a key and value to your registry:
+
+1. Open the Run Command (Windows+R)
+2. Enter `regedit.exe`
+3. In the Registry Editor navigate to `HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Android SDK Tools`
+4. Right Click on `Android SDK Tools` and choose `New > String Value`
+5. Set the name to `Path`
+6. Double Click the new `Path` Key and set the value to `C:\Program Files\Android\sdk`. The path value might be different on your machine.
+
+You will also need to run the command `adb reverse tcp:8081 tcp:8081` with this emulator.
+
+Then restart the emulator and when it runs you can just do `react-native run-android` as usual.

From 09250aa1842d1c0cd34d5ed415f2e0d7495e2304 Mon Sep 17 00:00:00 2001
From: Ben <narychen@yeah.net>
Date: Mon, 11 Jan 2016 03:32:28 -0800
Subject: [PATCH 0700/1411] multiline textinput view not wrapping in multiline
 on ios

Summary:
It's because the view doesn't update itself after setText.
Closes https://github.com/facebook/react-native/pull/5247

Reviewed By: svcscm

Differential Revision: D2819520

Pulled By: nicklockwood

fb-gh-sync-id: 06f5342d94f242fc63f862dac738da9b96842183
---
 Libraries/Text/RCTTextView.m | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Libraries/Text/RCTTextView.m b/Libraries/Text/RCTTextView.m
index 3a0ae8560694..ed1acffde4c9 100644
--- a/Libraries/Text/RCTTextView.m
+++ b/Libraries/Text/RCTTextView.m
@@ -382,6 +382,8 @@ - (void)setText:(NSString *)text
     }
 
     [self _setPlaceholderVisibility];
+    [self updateContentSize]; //keep the text wrapping when the length of
+    //the textline has been extended longer than the length of textinputView
   } else if (eventLag > RCTTextUpdateLagWarningThreshold) {
     RCTLogWarn(@"Native TextInput(%@) is %zd events ahead of JS - try to make your JS faster.", self.text, eventLag);
   }

From c9fa7c1ce8a5bdfbf3636e3cec1eb2850bb0a94e Mon Sep 17 00:00:00 2001
From: Ian Wang <gogoenwon@gmail.com>
Date: Mon, 11 Jan 2016 21:55:08 +0800
Subject: [PATCH 0701/1411] add Codementor to showcase

---
 website/src/react-native/showcase.js | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 0036dd053cb8..5dc731777e08 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -153,7 +153,13 @@ var apps = [
     icon: 'http://a2.mzstatic.com/us/r30/Purple69/v4/7b/0c/a0/7b0ca007-885a-7cfc-9fa2-2ec4394c2ecc/icon175x175.png',
     link: 'https://play.google.com/store/apps/details?id=com.cbssports.fantasy.franchisefootball2015',
     author: 'CBS Sports',
-  },  
+  },
+  {
+    name: 'Codementor - Live 1:1 Expert Developer Help',
+    icon: 'http://a1.mzstatic.com/us/r30/Purple3/v4/db/cf/35/dbcf3523-bac7-0f54-c6a8-a80bf4f43c38/icon175x175.jpeg',
+    link: 'https://www.codementor.io/downloads',
+    author: 'Codementor',
+  },
   {
     name: 'Company name search',
     icon: 'http://a4.mzstatic.com/us/r30/Purple69/v4/fd/47/53/fd47537c-5861-e208-d1d1-1e26b5e45a36/icon350x350.jpeg',

From cb91d652fa062f36e107d252a51b6b71caa7799d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Mon, 11 Jan 2016 09:37:50 -0800
Subject: [PATCH 0702/1411] Include socket interface logs when timing out on
 transformer

Reviewed By: davidaurelio

Differential Revision: D2819820

fb-gh-sync-id: 066fd1191c459cf3434899de6326e25f798c4b07
---
 .../react-packager/src/SocketInterface/SocketClient.js   | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/packager/react-packager/src/SocketInterface/SocketClient.js b/packager/react-packager/src/SocketInterface/SocketClient.js
index a344f5d97aee..c0016e17d5b0 100644
--- a/packager/react-packager/src/SocketInterface/SocketClient.js
+++ b/packager/react-packager/src/SocketInterface/SocketClient.js
@@ -136,9 +136,12 @@ class SocketClient {
     delete this._resolvers[message.id];
 
     if (message.type === 'error') {
-      resolver.reject(new Error(
-        message.data + '\n' + 'See logs ' + LOG_PATH
-      ));
+      const errorLog =
+        message.data && message.data.indexOf('TimeoutError') === -1
+          ? 'See logs ' + LOG_PATH
+          : getServerLogs();
+
+      resolver.reject(new Error(message.data + '\n' + errorLog));
     } else {
       resolver.resolve(message.data);
     }

From 05f31a0cbfaad33d8f67e2932f29bfc05556968a Mon Sep 17 00:00:00 2001
From: Andreas Drivenes <andreas.drivenes@gmail.com>
Date: Mon, 11 Jan 2016 12:45:17 -0800
Subject: [PATCH 0703/1411] Update examples for the converged Switch component

Reviewed By: mkonicek

Differential Revision: D2811302

Pulled By: bestander

fb-gh-sync-id: 069dc618510124d6978464979774828c46670124
---
 .../SwitchAndroidExample.android.js           |  70 ------------------
 .../{SwitchIOSExample.js => SwitchExample.js} |  45 ++++++-----
 .../testSwitchExample_1@2x.png                | Bin 150379 -> 150405 bytes
 Examples/UIExplorer/UIExplorerList.android.js |   2 +-
 Examples/UIExplorer/UIExplorerList.ios.js     |   2 +-
 5 files changed, 27 insertions(+), 92 deletions(-)
 delete mode 100644 Examples/UIExplorer/SwitchAndroidExample.android.js
 rename Examples/UIExplorer/{SwitchIOSExample.js => SwitchExample.js} (91%)

diff --git a/Examples/UIExplorer/SwitchAndroidExample.android.js b/Examples/UIExplorer/SwitchAndroidExample.android.js
deleted file mode 100644
index 7b6f38e1602c..000000000000
--- a/Examples/UIExplorer/SwitchAndroidExample.android.js
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * Copyright 2004-present Facebook. All Rights Reserved.
- */
-'use strict';
-
-var React = require('React');
-
-var SwitchAndroid = require('SwitchAndroid');
-var Text = require('Text');
-var UIExplorerBlock = require('UIExplorerBlock');
-var UIExplorerPage = require('UIExplorerPage');
-
-var SwitchAndroidExample = React.createClass({
-  statics: {
-    title: '<SwitchAndroid>',
-    description: 'Standard Android two-state toggle component.'
-  },
-
-  getInitialState : function() {
-    return {
-      trueSwitchIsOn: true,
-      falseSwitchIsOn: false,
-      colorTrueSwitchIsOn: true,
-      colorFalseSwitchIsOn: false,
-      eventSwitchIsOn: false,
-    };
-  },
-
-  render: function() {
-    return (
-      <UIExplorerPage title="<SwitchAndroid>">
-        <UIExplorerBlock title="Switches can be set to true or false">
-          <SwitchAndroid
-            onValueChange={(value) => this.setState({falseSwitchIsOn: value})}
-            style={{marginBottom: 10}}
-            value={this.state.falseSwitchIsOn} />
-          <SwitchAndroid
-            onValueChange={(value) => this.setState({trueSwitchIsOn: value})}
-            value={this.state.trueSwitchIsOn} />
-        </UIExplorerBlock>
-        <UIExplorerBlock title="Switches can be disabled">
-          <SwitchAndroid
-            disabled={true}
-            style={{marginBottom: 10}}
-            value={true} />
-          <SwitchAndroid
-            disabled={true}
-            value={false} />
-        </UIExplorerBlock>
-        <UIExplorerBlock title="Change events can be detected">
-          <SwitchAndroid
-            onValueChange={(value) => this.setState({eventSwitchIsOn: value})}
-            style={{marginBottom: 10}}
-            value={this.state.eventSwitchIsOn} />
-          <SwitchAndroid
-            onValueChange={(value) => this.setState({eventSwitchIsOn: value})}
-            style={{marginBottom: 10}}
-            value={this.state.eventSwitchIsOn} />
-          <Text>{this.state.eventSwitchIsOn ? 'On' : 'Off'}</Text>
-        </UIExplorerBlock>
-        <UIExplorerBlock title="Switches are controlled components">
-          <SwitchAndroid />
-          <SwitchAndroid value={true} />
-        </UIExplorerBlock>
-      </UIExplorerPage>
-    );
-  }
-});
-
-module.exports = SwitchAndroidExample;
diff --git a/Examples/UIExplorer/SwitchIOSExample.js b/Examples/UIExplorer/SwitchExample.js
similarity index 91%
rename from Examples/UIExplorer/SwitchIOSExample.js
rename to Examples/UIExplorer/SwitchExample.js
index feedfbff3ad2..5ab41fe15a2f 100644
--- a/Examples/UIExplorer/SwitchIOSExample.js
+++ b/Examples/UIExplorer/SwitchExample.js
@@ -17,7 +17,7 @@
 
 var React = require('react-native');
 var {
-  SwitchIOS,
+  Switch,
   Text,
   View
 } = React;
@@ -32,11 +32,11 @@ var BasicSwitchExample = React.createClass({
   render() {
     return (
       <View>
-        <SwitchIOS
+        <Switch
           onValueChange={(value) => this.setState({falseSwitchIsOn: value})}
           style={{marginBottom: 10}}
           value={this.state.falseSwitchIsOn} />
-        <SwitchIOS
+        <Switch
           onValueChange={(value) => this.setState({trueSwitchIsOn: value})}
           value={this.state.trueSwitchIsOn} />
       </View>
@@ -48,11 +48,11 @@ var DisabledSwitchExample = React.createClass({
   render() {
     return (
       <View>
-        <SwitchIOS
+        <Switch
           disabled={true}
           style={{marginBottom: 10}}
           value={true} />
-        <SwitchIOS
+        <Switch
           disabled={true}
           value={false} />
       </View>
@@ -70,14 +70,14 @@ var ColorSwitchExample = React.createClass({
   render() {
     return (
       <View>
-        <SwitchIOS
+        <Switch
           onValueChange={(value) => this.setState({colorFalseSwitchIsOn: value})}
           onTintColor="#00ff00"
           style={{marginBottom: 10}}
           thumbTintColor="#0000ff"
           tintColor="#ff0000"
           value={this.state.colorFalseSwitchIsOn} />
-        <SwitchIOS
+        <Switch
           onValueChange={(value) => this.setState({colorTrueSwitchIsOn: value})}
           onTintColor="#00ff00"
           thumbTintColor="#0000ff"
@@ -99,22 +99,22 @@ var EventSwitchExample = React.createClass({
     return (
       <View style={{ flexDirection: 'row', justifyContent: 'space-around' }}>
         <View>
-          <SwitchIOS
+          <Switch
             onValueChange={(value) => this.setState({eventSwitchIsOn: value})}
             style={{marginBottom: 10}}
             value={this.state.eventSwitchIsOn} />
-          <SwitchIOS
+          <Switch
             onValueChange={(value) => this.setState({eventSwitchIsOn: value})}
             style={{marginBottom: 10}}
             value={this.state.eventSwitchIsOn} />
             <Text>{this.state.eventSwitchIsOn ? 'On' : 'Off'}</Text>
         </View>
         <View>
-          <SwitchIOS
+          <Switch
             onValueChange={(value) => this.setState({eventSwitchRegressionIsOn: value})}
             style={{marginBottom: 10}}
             value={this.state.eventSwitchRegressionIsOn} />
-          <SwitchIOS
+          <Switch
             onValueChange={(value) => this.setState({eventSwitchRegressionIsOn: value})}
             style={{marginBottom: 10}}
             value={this.state.eventSwitchRegressionIsOn} />
@@ -125,10 +125,7 @@ var EventSwitchExample = React.createClass({
   }
 });
 
-exports.title = '<SwitchIOS>';
-exports.displayName = 'SwitchExample';
-exports.description = 'Native boolean input';
-exports.examples = [
+var examples = [
   {
     title: 'Switches can be set to true or false',
     render(): ReactElement { return <BasicSwitchExample />; }
@@ -137,16 +134,24 @@ exports.examples = [
     title: 'Switches can be disabled',
     render(): ReactElement { return <DisabledSwitchExample />; }
   },
-  {
-    title: 'Custom colors can be provided',
-    render(): ReactElement { return <ColorSwitchExample />; }
-  },
   {
     title: 'Change events can be detected',
     render(): ReactElement { return <EventSwitchExample />; }
   },
   {
     title: 'Switches are controlled components',
-    render(): ReactElement { return <SwitchIOS />; }
+    render(): ReactElement { return <Switch />; }
   }
 ];
+
+if (React.Platform.OS === 'ios') {
+  examples.push({
+    title: 'Custom colors can be provided',
+    render(): ReactElement { return <ColorSwitchExample />; }
+  });
+}
+
+exports.title = '<Switch>';
+exports.displayName = 'SwitchExample';
+exports.description = 'Native boolean input';
+exports.examples = examples;
diff --git a/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testSwitchExample_1@2x.png b/Examples/UIExplorer/UIExplorerIntegrationTests/ReferenceImages/Examples-UIExplorer-UIExplorerApp.ios/testSwitchExample_1@2x.png
index a1d8b69dc7d9621330115b7c00e79309bbeabdd2..f57db959a03a7a9db4a0a98c2f8b75c2bd20902f 100644
GIT binary patch
diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index 81442e0b982e..607f581fbfc8 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -27,7 +27,7 @@ var COMPONENTS = [
   require('./ListViewExample'),
   require('./ProgressBarAndroidExample'),
   require('./ScrollViewSimpleExample'),
-  require('./SwitchAndroidExample'),
+  require('./SwitchExample'),
   require('./RefreshControlExample'),
   require('./PullToRefreshViewAndroidExample.android'),
   require('./TextExample.android'),
diff --git a/Examples/UIExplorer/UIExplorerList.ios.js b/Examples/UIExplorer/UIExplorerList.ios.js
index 1d96b2d49ce8..512b033accd8 100644
--- a/Examples/UIExplorer/UIExplorerList.ios.js
+++ b/Examples/UIExplorer/UIExplorerList.ios.js
@@ -46,7 +46,7 @@ var COMPONENTS = [
   require('./ScrollViewExample'),
   require('./SegmentedControlIOSExample'),
   require('./SliderIOSExample'),
-  require('./SwitchIOSExample'),
+  require('./SwitchExample'),
   require('./TabBarIOSExample'),
   require('./TextExample.ios'),
   require('./TextInputExample.ios'),

From e08a7f35876cf102a6453273a71d8664debfb55c Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Mon, 11 Jan 2016 13:27:00 -0800
Subject: [PATCH 0704/1411] Fix launching text editor from a redbox stacktrace
 on windows

Summary:
Launch the editor with cmd on windows.
Closes https://github.com/facebook/react-native/pull/5238

Reviewed By: svcscm

Differential Revision: D2819943

Pulled By: pcottle

fb-gh-sync-id: a38f88bb9be72871cc3a37367973371176799d9e
---
 local-cli/server/util/launchEditor.js | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/local-cli/server/util/launchEditor.js b/local-cli/server/util/launchEditor.js
index a456eda59d26..ee8445294132 100644
--- a/local-cli/server/util/launchEditor.js
+++ b/local-cli/server/util/launchEditor.js
@@ -125,7 +125,13 @@ function launchEditor(fileName, lineNumber) {
     _childProcess.kill('SIGKILL');
   }
 
-  _childProcess = child_process.spawn(editor, args, {stdio: 'inherit'});
+  if (process.platform === 'win32') {
+    // On Windows, launch the editor in a shell because spawn can only
+    // launch .exe files.
+    _childProcess = child_process.spawn('cmd.exe', ['/C', editor].concat(args), {stdio: 'inherit'});
+  } else {
+    _childProcess = child_process.spawn(editor, args, {stdio: 'inherit'});
+  }
   _childProcess.on('exit', function(errorCode) {
     _childProcess = null;
 

From 97dcc66e7aeb9e8dddf30cbbe366301aa745d29c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Mon, 11 Jan 2016 15:30:45 -0800
Subject: [PATCH 0705/1411] Use same options on dependencies and bundle
 commands

Reviewed By: sam-swarr

Differential Revision: D2821362

fb-gh-sync-id: c07c2f74f237ab95ad4f4a89b7e35af4ca9e8c6b
---
 local-cli/dependencies/dependencies.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/local-cli/dependencies/dependencies.js b/local-cli/dependencies/dependencies.js
index adc1e8897011..8ada423cf262 100644
--- a/local-cli/dependencies/dependencies.js
+++ b/local-cli/dependencies/dependencies.js
@@ -63,6 +63,7 @@ function _dependencies(argv, config, resolve, reject) {
     getTransformOptionsModulePath: config.getTransformOptionsModulePath,
     transformModulePath: args.transformer,
     verbose: config.verbose,
+    disableInternalTransforms: true,
   };
 
   const relativePath = packageOpts.projectRoots.map(root =>

From 6623e482b2f14df1d379a124f876e297d49477e8 Mon Sep 17 00:00:00 2001
From: Sebastian Gronewold <sebastian@elbstack.com>
Date: Tue, 12 Jan 2016 03:11:00 -0800
Subject: [PATCH 0706/1411] See issue #4886

Summary:
brentvatne this is the pull request you requested
See issue #4886

On iOS the plist key NSLocationAlwaysUsageDescription was ignored and the location could not be retreived when using this key. Now both keys NSLocationWhenInUseUsageDescription and NSLocationAlwaysUsageDescription are supported. If NSLocationAlwaysUsageDescription is set, NSLocationWhenInUseUsageDescription will be simply ignored according to https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW18

I read the contribution guidelines regarding the Objective-C coding standards. Hopefully my line length breaks are okay - otherwise just give me a shout and I will fix that. Didn't write any line of Objective-C before so^^
Closes https://github.com/facebook/react-native/pull/5093

Reviewed By: svcscm

Differential Revision: D2823206

Pulled By: nicklockwood

fb-gh-sync-id: dd856a18416796749025e4b32d9c72895401916d
---
 Libraries/Geolocation/RCTLocationObserver.m | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/Libraries/Geolocation/RCTLocationObserver.m b/Libraries/Geolocation/RCTLocationObserver.m
index 6ea912e45c1d..63ceb7c9d95d 100644
--- a/Libraries/Geolocation/RCTLocationObserver.m
+++ b/Libraries/Geolocation/RCTLocationObserver.m
@@ -133,7 +133,11 @@ - (void)beginLocationUpdates
   }
 
   // Request location access permission
-  if ([_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
+  if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"] &&
+    [_locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
+    [_locationManager requestAlwaysAuthorization];
+  } else if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] &&
+    [_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
     [_locationManager requestWhenInUseAuthorization];
   }
 
@@ -327,8 +331,9 @@ - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *
 
 - (void)checkLocationConfig
 {
-  if (![[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"]) {
-    RCTLogError(@"NSLocationWhenInUseUsageDescription key must be present in Info.plist to use geolocation.");
+  if (!([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] ||
+    [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"])) {
+    RCTLogError(@"Either NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription key must be present in Info.plist to use geolocation.");
   }
 }
 

From 43dcdaffe2caa8a6a8a38932a3e97ccb172bbc13 Mon Sep 17 00:00:00 2001
From: Morgan Pretty <morgan@homepass.com>
Date: Tue, 12 Jan 2016 03:13:21 -0800
Subject: [PATCH 0707/1411] ActionSheetIOS support for presentation from modal
 view controller

Summary:
Currently the RCTActionSheetManager attempts to present itself from the 'rootViewController' of the key window, presenting a modal from a view controller which is already presenting a modal is not allowed on iOS and this fails with the following error appearing in the XCode debugger (but not the chrome debugger):

```
Warning: Attempt to present <UIAlertController: 0x7fca85b14f40> on <UINavigationController: 0x7fca84812000> whose view is not in the window hierarchy!
```

This change recursively looks through modally presented view controllers until it finds the top one and then uses that to present the action sheet.
Closes https://github.com/facebook/react-native/pull/5263

Reviewed By: svcscm

Differential Revision: D2823201

Pulled By: nicklockwood

fb-gh-sync-id: aad1ad88115563f633fd9aaea8e27d1d155a6c27
---
 Libraries/ActionSheetIOS/RCTActionSheetManager.m | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Libraries/ActionSheetIOS/RCTActionSheetManager.m b/Libraries/ActionSheetIOS/RCTActionSheetManager.m
index 6d568a0a4498..ab1a8c8d05be 100644
--- a/Libraries/ActionSheetIOS/RCTActionSheetManager.m
+++ b/Libraries/ActionSheetIOS/RCTActionSheetManager.m
@@ -66,6 +66,10 @@ - (CGRect)sourceRectInView:(UIView *)sourceView
   NSInteger cancelButtonIndex = options[@"cancelButtonIndex"] ? [RCTConvert NSInteger:options[@"cancelButtonIndex"]] : -1;
 
   UIViewController *controller = RCTKeyWindow().rootViewController;
+  while (controller.presentedViewController) {
+    controller = controller.presentedViewController;
+  }
+    
   if (controller == nil) {
     RCTLogError(@"Tried to display action sheet but there is no application window. options: %@", options);
     return;

From 5061fde3173e6228d544b5df1ce8ce4e2a7dd2a4 Mon Sep 17 00:00:00 2001
From: Aleksei Androsov <aandrosov@yandex-team.ru>
Date: Tue, 12 Jan 2016 03:24:42 -0800
Subject: [PATCH 0708/1411] FormData can append only string or object with uri

Summary:
I fix FormData type checking.

Simple test case:
```js
var fd = new FormData();

// JS Error.
// Because all non-string values threaded as "blob"
fd.append('number', 1);
```
Closes https://github.com/facebook/react-native/pull/4390

Reviewed By: svcscm

Differential Revision: D2818377

Pulled By: nicklockwood

fb-gh-sync-id: 8b3f27476af21c5fd65b844034579372172ea73c
---
 Libraries/Network/FormData.js | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/Libraries/Network/FormData.js b/Libraries/Network/FormData.js
index bbceb303f3c3..f3b261365865 100644
--- a/Libraries/Network/FormData.js
+++ b/Libraries/Network/FormData.js
@@ -71,21 +71,22 @@ class FormData {
 
       /* $FlowIssue(>=0.20.1) #9463928 */
       var headers: Headers = {'content-disposition': contentDisposition};
-      if (typeof value === 'string') {
-        return {string: value, headers, fieldName: name};
-      }
 
       // The body part is a "blob", which in React Native just means
       // an object with a `uri` attribute. Optionally, it can also
       // have a `name` and `type` attribute to specify filename and
       // content type (cf. web Blob interface.)
-      if (typeof value.name === 'string') {
-        headers['content-disposition'] += '; filename="' + value.name + '"';
-      }
-      if (typeof value.type === 'string') {
-        headers['content-type'] = value.type;
+      if (typeof value === 'object') {
+        if (typeof value.name === 'string') {
+          headers['content-disposition'] += '; filename="' + value.name + '"';
+        }
+        if (typeof value.type === 'string') {
+          headers['content-type'] = value.type;
+        }
+        return {...value, headers, fieldName: name};
       }
-      return {...value, headers, fieldName: name};
+      // Cast to string all other values
+      return {string: String(value), headers, fieldName: name};
     });
   }
 }

From 5fb19665094dd8064e4414d7fe6e5a4e16ce8ace Mon Sep 17 00:00:00 2001
From: Eric Raio <ericraio@gmail.com>
Date: Tue, 12 Jan 2016 04:46:20 -0800
Subject: [PATCH 0709/1411] Adding `resetTo` documentation in Navigator methods

Summary: Closes https://github.com/facebook/react-native/pull/5220

Reviewed By: svcscm

Differential Revision: D2818993

Pulled By: bestander

fb-gh-sync-id: 0bc0feb68e6c6f6132203daef586d78489047731
---
 Libraries/CustomComponents/Navigator/Navigator.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Libraries/CustomComponents/Navigator/Navigator.js b/Libraries/CustomComponents/Navigator/Navigator.js
index 607416244a68..47349d7698cd 100644
--- a/Libraries/CustomComponents/Navigator/Navigator.js
+++ b/Libraries/CustomComponents/Navigator/Navigator.js
@@ -175,6 +175,7 @@ var GESTURE_ACTIONS = [
  *  - `replace(route)` - Replace the current scene with a new route
  *  - `replaceAtIndex(route, index)` - Replace a scene as specified by an index
  *  - `replacePrevious(route)` - Replace the previous scene
+ *  - `resetTo(route)` - Navigate to a new scene and reset route stack
  *  - `immediatelyResetRouteStack(routeStack)` - Reset every scene with an
  *     array of routes
  *  - `popToRoute(route)` - Pop to a particular scene, as specified by its

From dd609647367459341bc805dd3c3a3ae71c3abf0c Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Tue, 12 Jan 2016 04:51:12 -0800
Subject: [PATCH 0710/1411] WebWorkers: Add c++ API for working with
 MessageQueueThread

Summary:
public

Adds a fbjni API similar to JNativeRunnable so that you can post ##std::function<void()>## to MessageQueueThreads.

Reviewed By: lexs

Differential Revision: D2779094

fb-gh-sync-id: 8f873fc93fb6b817268e9422c0b6f85c3e453676
---
 .../queue/MessageQueueThreadRegistry.java     |  1 +
 .../jni/react/jni/JMessageQueueThread.cpp     | 32 +++++++++++++++
 .../main/jni/react/jni/JMessageQueueThread.h  | 41 +++++++++++++++++++
 3 files changed, 74 insertions(+)
 create mode 100644 ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.cpp
 create mode 100644 ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.h

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadRegistry.java
index b924fd88bc1a..fd0602a93751 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadRegistry.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadRegistry.java
@@ -29,6 +29,7 @@ public class MessageQueueThreadRegistry {
   /**
    * @return the MessageQueueThread that owns the current Thread.
    */
+  @DoNotStrip
   public static MessageQueueThread myMessageQueueThread() {
     return Assertions.assertNotNull(
         sMyMessageQueueThread.get(),
diff --git a/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.cpp b/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.cpp
new file mode 100644
index 000000000000..0202f4a4dd97
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.cpp
@@ -0,0 +1,32 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#include "JMessageQueueThread.h"
+
+#include <fb/log.h>
+#include <folly/Memory.h>
+#include <jni/fbjni.h>
+
+#include "JNativeRunnable.h"
+
+namespace facebook {
+namespace react {
+
+JMessageQueueThread::JMessageQueueThread(alias_ref<MessageQueueThread::javaobject> jobj) :
+    m_jobj(make_global(jobj)) {
+}
+
+void JMessageQueueThread::runOnQueue(std::function<void()>&& runnable) {
+  static auto method = MessageQueueThread::javaClassStatic()->
+    getMethod<void(Runnable::javaobject)>("runOnQueue");
+  method(m_jobj, JNativeRunnable::newObjectCxxArgs(runnable).get());
+}
+
+/* static */
+std::unique_ptr<JMessageQueueThread> JMessageQueueThread::currentMessageQueueThread() {
+  static auto method = MessageQueueThreadRegistry::javaClassStatic()->
+      getStaticMethod<MessageQueueThread::javaobject()>("myMessageQueueThread");
+  return folly::make_unique<JMessageQueueThread>(method(MessageQueueThreadRegistry::javaClassStatic()));
+}
+
+} }
+
diff --git a/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.h b/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.h
new file mode 100644
index 000000000000..1a0f52bc9e29
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.h
@@ -0,0 +1,41 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+#include <functional>
+
+#include <jni/fbjni.h>
+
+using namespace facebook::jni;
+
+namespace facebook {
+namespace react {
+
+class MessageQueueThread : public jni::JavaClass<MessageQueueThread> {
+public:
+  static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/queue/MessageQueueThread;";
+};
+
+class JMessageQueueThread {
+public:
+  JMessageQueueThread(alias_ref<MessageQueueThread::javaobject> jobj);
+
+  /**
+   * Enqueues the given function to run on this MessageQueueThread.
+   */
+  void runOnQueue(std::function<void()>&& runnable);
+
+  /**
+   * Returns the current MessageQueueThread that owns this thread.
+   */
+  static std::unique_ptr<JMessageQueueThread> currentMessageQueueThread();
+private:
+  global_ref<MessageQueueThread::javaobject> m_jobj;
+};
+
+class MessageQueueThreadRegistry : public jni::JavaClass<MessageQueueThreadRegistry> {
+public:
+  static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/queue/MessageQueueThreadRegistry;";
+};
+
+} }

From 72d1826ae3a8847ba1e4fd33621a02d495258496 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Tue, 12 Jan 2016 04:51:13 -0800
Subject: [PATCH 0711/1411] WebWorkers: Implement initial WebWorkers API

Summary:
public

Implements a basic WebWorkers API that allows posting messages between the main JS thread and a worker background thread. It follows the existing webworkers API from JS. Currently passed memory needs to be JSON serializable and is copied (unfortunately, this is what webkit does as well, but with a more advanced serialization/deserialization process).

There are a lot of TODO's: I'll add tasks for them once this is accepted.

Reviewed By: lexs

Differential Revision: D2779349

fb-gh-sync-id: 8ed04c115d36acf0264ef1f6a12a65dd0c14ff18
---
 .../react/bridge/CatalystInstanceImpl.java    |   3 +-
 .../ProxyQueueThreadExceptionHandler.java     |  34 ++++++
 .../react/bridge/webworkers/WebWorkers.java   |  29 +++++
 ReactAndroid/src/main/jni/react/Bridge.cpp    |   2 +-
 ReactAndroid/src/main/jni/react/Executor.h    |   2 +-
 .../src/main/jni/react/JSCExecutor.cpp        | 110 ++++++++++++++++-
 ReactAndroid/src/main/jni/react/JSCExecutor.h |  34 +++++-
 .../src/main/jni/react/JSCWebWorker.cpp       | 115 ++++++++++++++++++
 .../src/main/jni/react/JSCWebWorker.h         |  84 +++++++++++++
 .../main/jni/react/jni/JMessageQueueThread.h  |   4 +
 .../src/main/jni/react/jni/WebWorkers.h       |  29 +++++
 11 files changed, 441 insertions(+), 5 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/queue/ProxyQueueThreadExceptionHandler.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/webworkers/WebWorkers.java
 create mode 100644 ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
 create mode 100644 ReactAndroid/src/main/jni/react/JSCWebWorker.h
 create mode 100644 ReactAndroid/src/main/jni/react/jni/WebWorkers.h

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
index da3750cfe941..70af8e3804f7 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
@@ -402,7 +402,8 @@ private void incrementPendingJSCalls() {
 
   private void decrementPendingJSCalls() {
     int newPendingCalls = mPendingJSCalls.decrementAndGet();
-    Assertions.assertCondition(newPendingCalls >= 0);
+    // TODO(9604406): handle case of web workers injecting messages to main thread
+    //Assertions.assertCondition(newPendingCalls >= 0);
     boolean isNowIdle = newPendingCalls == 0;
     Systrace.traceCounter(
         Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/ProxyQueueThreadExceptionHandler.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/ProxyQueueThreadExceptionHandler.java
new file mode 100644
index 000000000000..1be2d8a3c3c8
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/ProxyQueueThreadExceptionHandler.java
@@ -0,0 +1,34 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.bridge.queue;
+
+/**
+ * An Exception handler that posts the Exception to be thrown on the given delegate
+ * MessageQueueThread.
+ */
+public class ProxyQueueThreadExceptionHandler implements QueueThreadExceptionHandler {
+
+  private final MessageQueueThread mDelegateThread;
+
+  public ProxyQueueThreadExceptionHandler(MessageQueueThread delegateThread) {
+    mDelegateThread = delegateThread;
+  }
+
+  @Override
+  public void handleException(final Exception e) {
+    mDelegateThread.runOnQueue(
+        new Runnable() {
+          @Override
+          public void run() {
+            throw new RuntimeException(e);
+          }
+        });
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/webworkers/WebWorkers.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/webworkers/WebWorkers.java
new file mode 100644
index 000000000000..1cc874e9cb32
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/webworkers/WebWorkers.java
@@ -0,0 +1,29 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.bridge.webworkers;
+
+import com.facebook.proguard.annotations.DoNotStrip;
+import com.facebook.react.bridge.queue.MessageQueueThread;
+import com.facebook.react.bridge.queue.MessageQueueThreadImpl;
+import com.facebook.react.bridge.queue.ProxyQueueThreadExceptionHandler;
+
+@DoNotStrip
+public class WebWorkers {
+
+  /**
+   * Creates a new MessageQueueThread for a background web worker owned by the JS thread with the
+   * given MessageQueueThread.
+   */
+  public static MessageQueueThread createWebWorkerThread(int id, MessageQueueThread ownerThread) {
+    return MessageQueueThreadImpl.startNewBackgroundThread(
+        "web-worker-" + id,
+        new ProxyQueueThreadExceptionHandler(ownerThread));
+  }
+}
diff --git a/ReactAndroid/src/main/jni/react/Bridge.cpp b/ReactAndroid/src/main/jni/react/Bridge.cpp
index 90a50d098c18..b9b0580c4a34 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.cpp
+++ b/ReactAndroid/src/main/jni/react/Bridge.cpp
@@ -18,7 +18,7 @@ class JSThreadState {
   JSThreadState(const RefPtr<JSExecutorFactory>& jsExecutorFactory, Bridge::Callback&& callback) :
     m_callback(callback)
   {
-    m_jsExecutor = jsExecutorFactory->createJSExecutor([this, callback] (std::string queueJSON) {
+    m_jsExecutor = jsExecutorFactory->createJSExecutor([this, callback] (std::string queueJSON, bool isEndOfBatch) {
       m_callback(parseMethodCalls(queueJSON), false /* = isEndOfBatch */);
     });
   }
diff --git a/ReactAndroid/src/main/jni/react/Executor.h b/ReactAndroid/src/main/jni/react/Executor.h
index bef2d0724f39..dd09d59069bf 100644
--- a/ReactAndroid/src/main/jni/react/Executor.h
+++ b/ReactAndroid/src/main/jni/react/Executor.h
@@ -18,7 +18,7 @@ namespace react {
 
 class JSExecutor;
 
-typedef std::function<void(std::string)> FlushImmediateCallback;
+typedef std::function<void(std::string, bool)> FlushImmediateCallback;
 
 class JSExecutorFactory : public Countable {
 public:
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index a657a72f1375..aa11022942c3 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -3,6 +3,7 @@
 #include "JSCExecutor.h"
 
 #include <algorithm>
+#include <atomic>
 #include <sstream>
 #include <string>
 #include <fb/log.h>
@@ -11,6 +12,7 @@
 #include <jni/fbjni/Exceptions.h>
 #include <sys/time.h>
 #include "Value.h"
+#include "jni/JMessageQueueThread.h"
 #include "jni/OnLoad.h"
 
 #ifdef WITH_JSC_EXTRA_TRACING
@@ -48,6 +50,7 @@ namespace facebook {
 namespace react {
 
 static std::unordered_map<JSContextRef, JSCExecutor*> s_globalContextRefToJSCExecutor;
+
 static JSValueRef nativeFlushQueueImmediate(
     JSContextRef ctx,
     JSObjectRef function,
@@ -96,10 +99,13 @@ std::unique_ptr<JSExecutor> JSCExecutorFactory::createJSExecutor(FlushImmediateC
 JSCExecutor::JSCExecutor(FlushImmediateCallback cb) :
     m_flushImmediateCallback(cb) {
   m_context = JSGlobalContextCreateInGroup(nullptr, nullptr);
+  m_messageQueueThread = JMessageQueueThread::currentMessageQueueThread();
   s_globalContextRefToJSCExecutor[m_context] = this;
   installGlobalFunction(m_context, "nativeFlushQueueImmediate", nativeFlushQueueImmediate);
   installGlobalFunction(m_context, "nativeLoggingHook", nativeLoggingHook);
   installGlobalFunction(m_context, "nativePerformanceNow", nativePerformanceNow);
+  installGlobalFunction(m_context, "nativeStartWorker", nativeStartWorker);
+  installGlobalFunction(m_context, "nativePostMessageToWorker", nativePostMessageToWorker);
 
   #ifdef WITH_FB_JSC_TUNING
   configureJSCForAndroid();
@@ -219,13 +225,55 @@ void JSCExecutor::handleMemoryPressureCritical() {
 }
 
 void JSCExecutor::flushQueueImmediate(std::string queueJSON) {
-  m_flushImmediateCallback(queueJSON);
+  m_flushImmediateCallback(queueJSON, false);
+}
+
+// WebWorker impl
+
+JSGlobalContextRef JSCExecutor::getContext() {
+  return m_context;
+}
+
+std::shared_ptr<JMessageQueueThread> JSCExecutor::getMessageQueueThread() {
+  return m_messageQueueThread;
+}
+
+void JSCExecutor::onMessageReceived(int workerId, const std::string& json) {
+  Value rebornJSMsg = Value::fromJSON(m_context, String(json.c_str()));
+  JSValueRef args[] = { rebornJSMsg };
+  Object& worker = m_webWorkerJSObjs.at(workerId);
+
+  Value onmessageValue = worker.getProperty("onmessage");
+  if (onmessageValue.isUndefined()) {
+    return;
+  }
+  onmessageValue.asObject().callAsFunction(1, args);
+
+  m_flushImmediateCallback(flush(), true);
+}
+
+int JSCExecutor::addWebWorker(const std::string& script, JSValueRef workerRef) {
+  static std::atomic_int nextWorkerId(0);
+  int workerId = nextWorkerId++;
+
+  m_webWorkers.emplace(std::piecewise_construct, std::forward_as_tuple(workerId), std::forward_as_tuple(workerId, this, script));
+  Object workerObj = Value(m_context, workerRef).asObject();
+  workerObj.makeProtected();
+  m_webWorkerJSObjs.emplace(workerId, std::move(workerObj));
+  return workerId;
+}
+
+void JSCExecutor::postMessageToWebWorker(int workerId, JSValueRef message, JSValueRef *exn) {
+  JSCWebWorker& worker = m_webWorkers.at(workerId);
+  worker.postMessage(message);
 }
 
 static JSValueRef createErrorString(JSContextRef ctx, const char *msg) {
   return JSValueMakeString(ctx, String(msg));
 }
 
+// Native JS hooks
+
 static JSValueRef nativeFlushQueueImmediate(
     JSContextRef ctx,
     JSObjectRef function,
@@ -253,6 +301,66 @@ static JSValueRef nativeFlushQueueImmediate(
   return JSValueMakeUndefined(ctx);
 }
 
+JSValueRef JSCExecutor::nativeStartWorker(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[],
+    JSValueRef *exception) {
+  if (argumentCount != 2) {
+    *exception = createErrorString(ctx, "Got wrong number of args");
+    return JSValueMakeUndefined(ctx);
+  }
+
+  std::string scriptFile = Value(ctx, arguments[0]).toString().str();
+
+  JSValueRef worker = arguments[1];
+
+  JSCExecutor *executor;
+  try {
+    executor = s_globalContextRefToJSCExecutor.at(JSContextGetGlobalContext(ctx));
+  } catch (std::out_of_range& e) {
+    *exception = createErrorString(ctx, "Global JS context didn't map to a valid executor");
+    return JSValueMakeUndefined(ctx);
+  }
+
+  int workerId = executor->addWebWorker(scriptFile, worker);
+
+  return JSValueMakeNumber(ctx, workerId);
+}
+
+JSValueRef JSCExecutor::nativePostMessageToWorker(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[],
+    JSValueRef *exception) {
+  if (argumentCount != 2) {
+    *exception = createErrorString(ctx, "Got wrong number of args");
+    return JSValueMakeUndefined(ctx);
+  }
+
+  double workerDouble = JSValueToNumber(ctx, arguments[0], exception);
+  if (workerDouble != workerDouble) {
+    *exception = createErrorString(ctx, "Got invalid worker id");
+    return JSValueMakeUndefined(ctx);
+  }
+
+  JSCExecutor *executor;
+  try {
+    executor = s_globalContextRefToJSCExecutor.at(JSContextGetGlobalContext(ctx));
+  } catch (std::out_of_range& e) {
+    *exception = createErrorString(ctx, "Global JS context didn't map to a valid executor");
+    return JSValueMakeUndefined(ctx);
+  }
+
+  executor->postMessageToWebWorker((int) workerDouble, arguments[1], exception);
+
+  return JSValueMakeUndefined(ctx);
+}
+
 static JSValueRef nativeLoggingHook(
     JSContextRef ctx,
     JSObjectRef function,
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.h b/ReactAndroid/src/main/jni/react/JSCExecutor.h
index 5074247356b4..030648bb9601 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.h
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.h
@@ -2,20 +2,28 @@
 
 #pragma once
 
+#include <memory>
+#include <unordered_map>
 #include <JavaScriptCore/JSContextRef.h>
 #include "Executor.h"
 #include "JSCHelpers.h"
+#include "JSCWebWorker.h"
 
 namespace facebook {
 namespace react {
 
+class JMessageQueueThread;
+
 class JSCExecutorFactory : public JSExecutorFactory {
 public:
   virtual std::unique_ptr<JSExecutor> createJSExecutor(FlushImmediateCallback cb) override;
 };
 
-class JSCExecutor : public JSExecutor {
+class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
 public:
+  /**
+   * Should be invoked from the JS thread.
+   */
   explicit JSCExecutor(FlushImmediateCallback flushImmediateCallback);
   ~JSCExecutor() override;
 
@@ -41,10 +49,34 @@ class JSCExecutor : public JSExecutor {
 
   void flushQueueImmediate(std::string queueJSON);
   void installNativeHook(const char *name, JSObjectCallAsFunctionCallback callback);
+  virtual void onMessageReceived(int workerId, const std::string& message) override;
+  virtual JSGlobalContextRef getContext() override;
+  virtual std::shared_ptr<JMessageQueueThread> getMessageQueueThread() override;
 
 private:
   JSGlobalContextRef m_context;
   FlushImmediateCallback m_flushImmediateCallback;
+  std::unordered_map<int, JSCWebWorker> m_webWorkers;
+  std::unordered_map<int, Object> m_webWorkerJSObjs;
+  std::shared_ptr<JMessageQueueThread> m_messageQueueThread;
+
+  int addWebWorker(const std::string& script, JSValueRef workerRef);
+  void postMessageToWebWorker(int worker, JSValueRef message, JSValueRef *exn);
+
+  static JSValueRef nativeStartWorker(
+      JSContextRef ctx,
+      JSObjectRef function,
+      JSObjectRef thisObject,
+      size_t argumentCount,
+      const JSValueRef arguments[],
+      JSValueRef *exception);
+  static JSValueRef nativePostMessageToWorker(
+      JSContextRef ctx,
+      JSObjectRef function,
+      JSObjectRef thisObject,
+      size_t argumentCount,
+      const JSValueRef arguments[],
+      JSValueRef *exception);
 };
 
 } }
diff --git a/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp b/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
new file mode 100644
index 000000000000..b385c1472058
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
@@ -0,0 +1,115 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#include <unistd.h>
+#include <mutex>
+#include <pthread.h>
+#include <unordered_map>
+
+#include <fb/assert.h>
+#include <fb/log.h>
+#include <folly/Memory.h>
+#include <jni/fbjni/Exceptions.h>
+#include <jni/LocalReference.h>
+
+#include "JSCWebWorker.h"
+#include "JSCHelpers.h"
+#include "jni/JMessageQueueThread.h"
+#include "jni/JSLoader.h"
+#include "jni/WebWorkers.h"
+#include "Value.h"
+
+#include <JavaScriptCore/JSValueRef.h>
+
+using namespace facebook::jni;
+
+namespace facebook {
+namespace react {
+
+// TODO(9604425): thread safety
+static std::unordered_map<JSContextRef, JSCWebWorker*> s_globalContextRefToJSCWebWorker;
+
+JSCWebWorker::JSCWebWorker(int id, JSCWebWorkerOwner *owner, std::string scriptSrc) :
+    id_(id),
+    scriptName_(std::move(scriptSrc)),
+    owner_(owner) {
+  ownerMessageQueueThread_ = owner->getMessageQueueThread();
+  FBASSERTMSGF(ownerMessageQueueThread_, "Owner MessageQueueThread must not be null");
+  workerMessageQueueThread_ = WebWorkers::createWebWorkerThread(id, ownerMessageQueueThread_.get());
+  FBASSERTMSGF(workerMessageQueueThread_, "Failed to create worker thread");
+
+  workerMessageQueueThread_->runOnQueue([this] () {
+    initJSVMAndLoadScript();
+  });
+}
+
+JSCWebWorker::~JSCWebWorker() {
+  // TODO(9604430): Implement tear down
+}
+
+void JSCWebWorker::postMessage(JSValueRef msg) {
+  std::string msgString = Value(owner_->getContext(), msg).toJSONString();
+
+  workerMessageQueueThread_->runOnQueue([this, msgString] () {
+    if (isFinished()) {
+      return;
+    }
+    Value rebornJSMsg = Value::fromJSON(context_, String(msgString.c_str()));
+    JSValueRef args[] = { rebornJSMsg };
+    Value onmessageValue = Object::getGlobalObject(context_).getProperty("onmessage");
+    onmessageValue.asObject().callAsFunction(1, args);
+  });
+}
+
+void JSCWebWorker::finish() {
+  isFinished_ = true;
+  // TODO(9604430): Implement tear down
+}
+
+bool JSCWebWorker::isFinished() {
+  return isFinished_;
+}
+
+void JSCWebWorker::initJSVMAndLoadScript() {
+  FBASSERTMSGF(!isFinished(), "Worker was already finished!");
+  FBASSERTMSGF(!context_, "Worker JS VM was already created!");
+
+  context_ = JSGlobalContextCreateInGroup(
+      NULL, // use default JS 'global' object
+      NULL // create new group (i.e. new VM)
+  ); 
+  s_globalContextRefToJSCWebWorker[context_] = this;
+  
+  // TODO(9604438): Protect against script does not exist
+  std::string script = loadScriptFromAssets(scriptName_);
+  evaluateScript(context_, String(script.c_str()), String(scriptName_.c_str()));
+
+  installGlobalFunction(context_, "postMessage", nativePostMessage);
+}
+
+void JSCWebWorker::postMessageToOwner(JSValueRef msg) {
+  std::string msgString = Value(context_, msg).toJSONString();
+  ownerMessageQueueThread_->runOnQueue([this, msgString] () {
+      owner_->onMessageReceived(id_, msgString);
+  });
+}
+
+JSValueRef JSCWebWorker::nativePostMessage(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[],
+    JSValueRef *exception) {
+  if (argumentCount != 1) {
+    *exception = makeJSCException(ctx, "postMessage got wrong number of arguments");
+    return JSValueMakeUndefined(ctx);
+  }
+  JSValueRef msg = arguments[0];
+  JSCWebWorker *webWorker = s_globalContextRefToJSCWebWorker.at(JSContextGetGlobalContext(ctx));
+  webWorker->postMessageToOwner(msg);
+  
+  return JSValueMakeUndefined(ctx);
+}
+
+}
+}
diff --git a/ReactAndroid/src/main/jni/react/JSCWebWorker.h b/ReactAndroid/src/main/jni/react/JSCWebWorker.h
new file mode 100644
index 000000000000..b4a45ef97f53
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/JSCWebWorker.h
@@ -0,0 +1,84 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#include <functional>
+#include <mutex>
+#include <string>
+#include <thread>
+#include <queue>
+
+#include <JavaScriptCore/JSValueRef.h>
+
+#include "Value.h"
+
+using namespace facebook::jni;
+
+namespace facebook {
+namespace react {
+
+class JMessageQueueThread;
+
+/**
+ * A class that can own the lifecycle, receive messages from, and dispatch messages
+ * to JSCWebWorkers.
+ */
+class JSCWebWorkerOwner {
+public:
+  /**
+   * Called when a worker has posted a message with `postMessage`.
+   */
+  virtual void onMessageReceived(int workerId, const std::string& message) = 0;
+  virtual JSGlobalContextRef getContext() = 0;
+
+  /**
+   * Should return the owner's MessageQueueThread. Calls to onMessageReceived will be enqueued
+   * on this thread.
+   */
+  virtual std::shared_ptr<JMessageQueueThread> getMessageQueueThread() = 0;
+};
+
+/**
+ * Implementation of a web worker for JSC. The web worker should be created from the owner's
+ * (e.g., owning JSCExecutor instance) JS MessageQueueThread. The worker is responsible for
+ * creating its own MessageQueueThread.
+ *
+ * During operation, the JSCExecutor should call postMessage **from its own MessageQueueThread**
+ * to send messages to the worker. The worker will handle enqueueing those messages on its own
+ * MessageQueueThread as appropriate. When the worker has a message to post to the owner, it will
+ * enqueue a call to owner->onMessageReceived on the owner's MessageQueueThread.
+ */
+class JSCWebWorker {
+public:
+  explicit JSCWebWorker(int id, JSCWebWorkerOwner *owner, std::string script);
+  ~JSCWebWorker();
+
+  /**
+   * Post a message to be received by the worker on its thread. This must be called from 
+   * ownerMessageQueueThread_.
+   */
+  void postMessage(JSValueRef msg);
+  void finish();
+  bool isFinished();
+private:
+  void initJSVMAndLoadScript();
+  void postRunnableToEventLoop(std::function<void()>&& runnable);
+  void postMessageToOwner(JSValueRef result);
+
+  int id_;
+  bool isFinished_ = false;
+  std::string scriptName_;
+  JSCWebWorkerOwner *owner_ = nullptr;
+  std::shared_ptr<JMessageQueueThread> ownerMessageQueueThread_;
+  std::unique_ptr<JMessageQueueThread> workerMessageQueueThread_;
+  JSGlobalContextRef context_ = nullptr;
+
+  static JSValueRef nativePostMessage(
+      JSContextRef ctx,
+      JSObjectRef function,
+      JSObjectRef thisObject,
+      size_t argumentCount,
+      const JSValueRef arguments[],
+      JSValueRef *exception);
+};
+
+}
+}
diff --git a/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.h b/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.h
index 1a0f52bc9e29..c2c875a6dc28 100644
--- a/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.h
+++ b/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.h
@@ -25,6 +25,10 @@ class JMessageQueueThread {
    */
   void runOnQueue(std::function<void()>&& runnable);
 
+  MessageQueueThread::javaobject jobj() {
+    return m_jobj.get();
+  }
+
   /**
    * Returns the current MessageQueueThread that owns this thread.
    */
diff --git a/ReactAndroid/src/main/jni/react/jni/WebWorkers.h b/ReactAndroid/src/main/jni/react/jni/WebWorkers.h
new file mode 100644
index 000000000000..2a506280a629
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/jni/WebWorkers.h
@@ -0,0 +1,29 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+#include <memory>
+
+#include <jni.h>
+#include <folly/Memory.h>
+
+#include "JMessageQueueThread.h"
+
+using namespace facebook::jni;
+
+namespace facebook {
+namespace react {
+
+class WebWorkers : public JavaClass<WebWorkers> {
+public:
+  static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/webworkers/WebWorkers;";
+
+  static std::unique_ptr<JMessageQueueThread> createWebWorkerThread(int id, JMessageQueueThread *ownerMessageQueueThread) {
+    static auto method = WebWorkers::javaClassStatic()->
+        getStaticMethod<MessageQueueThread::javaobject(jint, MessageQueueThread::javaobject)>("createWebWorkerThread");
+    auto res = method(WebWorkers::javaClassStatic(), id, ownerMessageQueueThread->jobj());
+    return folly::make_unique<JMessageQueueThread>(res);
+  }
+};
+
+} }

From b0519c8280e572b0c41ccfa8ac4b4167d5eb09a2 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Tue, 12 Jan 2016 04:51:15 -0800
Subject: [PATCH 0712/1411] Update WebWorkers API to return message object in
 onmessage

Summary:
public

I wasn't obeying the web workers API correctly: I had missed that the message isn't sent directly but is attached to a message object in a data field.

Reviewed By: lexs

Differential Revision: D2811247

fb-gh-sync-id: 8e51414766e0cfe382ee9bdde8f0d66e269cb83a
---
 .../src/main/jni/react/JSCExecutor.cpp        |  4 +--
 .../src/main/jni/react/JSCWebWorker.cpp       | 12 ++++++--
 .../src/main/jni/react/JSCWebWorker.h         |  2 ++
 ReactAndroid/src/main/jni/react/Value.cpp     | 28 ++++++++++++++++++-
 ReactAndroid/src/main/jni/react/Value.h       | 11 +++++++-
 5 files changed, 51 insertions(+), 6 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index aa11022942c3..499bbbc3765f 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -239,14 +239,14 @@ std::shared_ptr<JMessageQueueThread> JSCExecutor::getMessageQueueThread() {
 }
 
 void JSCExecutor::onMessageReceived(int workerId, const std::string& json) {
-  Value rebornJSMsg = Value::fromJSON(m_context, String(json.c_str()));
-  JSValueRef args[] = { rebornJSMsg };
   Object& worker = m_webWorkerJSObjs.at(workerId);
 
   Value onmessageValue = worker.getProperty("onmessage");
   if (onmessageValue.isUndefined()) {
     return;
   }
+
+  JSValueRef args[] = { JSCWebWorker::createMessageObject(m_context, json) };
   onmessageValue.asObject().callAsFunction(1, args);
 
   m_flushImmediateCallback(flush(), true);
diff --git a/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp b/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
index b385c1472058..2357ddce4a16 100644
--- a/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
@@ -53,8 +53,8 @@ void JSCWebWorker::postMessage(JSValueRef msg) {
     if (isFinished()) {
       return;
     }
-    Value rebornJSMsg = Value::fromJSON(context_, String(msgString.c_str()));
-    JSValueRef args[] = { rebornJSMsg };
+
+    JSValueRef args[] = { createMessageObject(context_, msgString) };
     Value onmessageValue = Object::getGlobalObject(context_).getProperty("onmessage");
     onmessageValue.asObject().callAsFunction(1, args);
   });
@@ -111,5 +111,13 @@ JSValueRef JSCWebWorker::nativePostMessage(
   return JSValueMakeUndefined(ctx);
 }
 
+/*static*/
+Object JSCWebWorker::createMessageObject(JSContextRef context, const std::string& msgJson) {
+  Value rebornJSMsg = Value::fromJSON(context, String(msgJson.c_str()));
+  Object messageObject = Object::create(context);
+  messageObject.setProperty("data", rebornJSMsg);
+  return std::move(messageObject);
+}
+
 }
 }
diff --git a/ReactAndroid/src/main/jni/react/JSCWebWorker.h b/ReactAndroid/src/main/jni/react/JSCWebWorker.h
index b4a45ef97f53..5e4070d84878 100644
--- a/ReactAndroid/src/main/jni/react/JSCWebWorker.h
+++ b/ReactAndroid/src/main/jni/react/JSCWebWorker.h
@@ -58,6 +58,8 @@ class JSCWebWorker {
   void postMessage(JSValueRef msg);
   void finish();
   bool isFinished();
+
+  static Object createMessageObject(JSContextRef context, const std::string& msgData);
 private:
   void initJSVMAndLoadScript();
   void postRunnableToEventLoop(std::function<void()>&& runnable);
diff --git a/ReactAndroid/src/main/jni/react/Value.cpp b/ReactAndroid/src/main/jni/react/Value.cpp
index 0acbc38c8843..ca292c0de2b5 100644
--- a/ReactAndroid/src/main/jni/react/Value.cpp
+++ b/ReactAndroid/src/main/jni/react/Value.cpp
@@ -58,6 +58,10 @@ Object Value::asObject() {
   return std::move(ret);
 }
 
+Object::operator Value() const {
+  return Value(m_context, m_obj);
+}
+
 Value Object::callAsFunction(int nArgs, JSValueRef args[]) {
   JSValueRef exn;
   JSValueRef result = JSObjectCallAsFunction(m_context, m_obj, NULL, nArgs, args, &exn);
@@ -68,7 +72,7 @@ Value Object::callAsFunction(int nArgs, JSValueRef args[]) {
   return Value(m_context, result);
 }
 
-Value Object::getProperty(String propName) const {
+Value Object::getProperty(const String& propName) const {
   JSValueRef exn;
   JSValueRef property = JSObjectGetProperty(m_context, m_obj, propName, &exn);
   if (!property) {
@@ -82,4 +86,26 @@ Value Object::getProperty(const char *propName) const {
   return getProperty(String(propName));
 }
 
+void Object::setProperty(const String& propName, const Value& value) const {
+  JSValueRef exn = NULL;
+  JSObjectSetProperty(m_context, m_obj, propName, value, kJSPropertyAttributeNone, &exn);
+  if (exn) {
+    std::string exceptionText = Value(m_context, exn).toString().str();
+    throwJSExecutionException("Failed to set property: %s", exceptionText.c_str());
+  }
+}
+
+void Object::setProperty(const char *propName, const Value& value) const {
+  setProperty(String(propName), value);
+}
+
+/* static */
+Object Object::create(JSContextRef ctx) {
+  JSObjectRef newObj = JSObjectMake(
+      ctx,
+      NULL, // create instance of default object class
+      NULL); // no private data
+  return Object(ctx, newObj);
+}
+
 } }
diff --git a/ReactAndroid/src/main/jni/react/Value.h b/ReactAndroid/src/main/jni/react/Value.h
index 8a845ebfe513..fb02fe50ab8f 100644
--- a/ReactAndroid/src/main/jni/react/Value.h
+++ b/ReactAndroid/src/main/jni/react/Value.h
@@ -111,14 +111,18 @@ class Object : public noncopyable {
     return m_obj;
   }
 
+  operator Value() const;
+
   bool isFunction() const {
     return JSObjectIsFunction(m_context, m_obj);
   }
 
   Value callAsFunction(int nArgs, JSValueRef args[]);
 
-  Value getProperty(String propName) const;
+  Value getProperty(const String& propName) const;
   Value getProperty(const char *propName) const;
+  void setProperty(const String& propName, const Value& value) const;
+  void setProperty(const char *propName, const Value& value) const;
 
   void makeProtected() {
     if (!m_isProtected && m_obj) {
@@ -132,6 +136,11 @@ class Object : public noncopyable {
     return Object(ctx, globalObj);
   }
 
+  /**
+   * Creates an instance of the default object class.
+   */
+  static Object create(JSContextRef ctx);
+
 private:
   JSContextRef m_context;
   JSObjectRef m_obj;

From 0be36a2c808b12963e2a56f5951d21ca7694ced4 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Tue, 12 Jan 2016 04:51:16 -0800
Subject: [PATCH 0713/1411] WebWorkers: implement tear down and terminate()

Summary:
public
Previously we did no cleanup when the executor was torn down and didn't expose a way to tear down the worker from JS. Now we do.

Termination happens synchronously and waits the the worker's MessageQueueThread to finish and join.

Reviewed By: mhorowitz

Differential Revision: D2815240

fb-gh-sync-id: 786beb30d4d64556586b91727f32e379c667a965
---
 .../bridge/queue/MessageQueueThread.java      |  7 +++
 .../bridge/queue/MessageQueueThreadImpl.java  |  1 +
 .../src/main/jni/react/JSCExecutor.cpp        | 50 ++++++++++++++++++
 ReactAndroid/src/main/jni/react/JSCExecutor.h |  8 +++
 .../src/main/jni/react/JSCWebWorker.cpp       | 52 +++++++++++++++----
 .../src/main/jni/react/JSCWebWorker.h         | 16 ++++--
 .../jni/react/jni/JMessageQueueThread.cpp     | 12 +++++
 .../main/jni/react/jni/JMessageQueueThread.h  | 11 ++++
 8 files changed, 145 insertions(+), 12 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThread.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThread.java
index 36b190a002f7..9829ddfc5cfc 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThread.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThread.java
@@ -43,4 +43,11 @@ public interface MessageQueueThread {
    * {@link AssertionError}) if the assertion fails.
    */
   void assertIsOnThread();
+
+  /**
+   * Quits this MessageQueueThread. If called from this MessageQueueThread, this will be the last
+   * thing the thread runs. If called from a separate thread, this will block until the thread can
+   * be quit and joined.
+   */
+  void quitSynchronous();
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java
index c0961b0c6144..62184512652d 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java
@@ -101,6 +101,7 @@ public void assertIsOnThread() {
    * Quits this queue's Looper. If that Looper was running on a different Thread than the current
    * Thread, also waits for the last message being processed to finish and the Thread to die.
    */
+  @Override
   public void quitSynchronous() {
     mIsFinished = true;
     mLooper.quit();
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index 499bbbc3765f..f13c085e2fe5 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -106,6 +106,7 @@ JSCExecutor::JSCExecutor(FlushImmediateCallback cb) :
   installGlobalFunction(m_context, "nativePerformanceNow", nativePerformanceNow);
   installGlobalFunction(m_context, "nativeStartWorker", nativeStartWorker);
   installGlobalFunction(m_context, "nativePostMessageToWorker", nativePostMessageToWorker);
+  installGlobalFunction(m_context, "nativeTerminateWorker", nativeTerminateWorker);
 
   #ifdef WITH_FB_JSC_TUNING
   configureJSCForAndroid();
@@ -123,6 +124,15 @@ JSCExecutor::JSCExecutor(FlushImmediateCallback cb) :
 }
 
 JSCExecutor::~JSCExecutor() {
+  // terminateWebWorker mutates m_webWorkers so collect all the workers to terminate first
+  std::vector<int> workerIds;
+  for (auto it = m_webWorkers.begin(); it != m_webWorkers.end(); it++) {
+    workerIds.push_back(it->first);
+  }
+  for (int workerId : workerIds) {
+    terminateWebWorker(workerId);
+  }
+
   s_globalContextRefToJSCExecutor.erase(m_context);
   JSGlobalContextRelease(m_context);
 }
@@ -268,6 +278,15 @@ void JSCExecutor::postMessageToWebWorker(int workerId, JSValueRef message, JSVal
   worker.postMessage(message);
 }
 
+void JSCExecutor::terminateWebWorker(int workerId) {
+  JSCWebWorker& worker = m_webWorkers.at(workerId);
+
+  worker.terminate();
+
+  m_webWorkers.erase(workerId);
+  m_webWorkerJSObjs.erase(workerId);
+}
+
 static JSValueRef createErrorString(JSContextRef ctx, const char *msg) {
   return JSValueMakeString(ctx, String(msg));
 }
@@ -361,6 +380,37 @@ JSValueRef JSCExecutor::nativePostMessageToWorker(
   return JSValueMakeUndefined(ctx);
 }
 
+JSValueRef JSCExecutor::nativeTerminateWorker(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[],
+    JSValueRef *exception) {
+  if (argumentCount != 1) {
+    *exception = createErrorString(ctx, "Got wrong number of args");
+    return JSValueMakeUndefined(ctx);
+  }
+
+  double workerDouble = JSValueToNumber(ctx, arguments[0], exception);
+  if (workerDouble != workerDouble) {
+    *exception = createErrorString(ctx, "Got invalid worker id");
+    return JSValueMakeUndefined(ctx);
+  }
+
+  JSCExecutor *executor;
+  try {
+    executor = s_globalContextRefToJSCExecutor.at(JSContextGetGlobalContext(ctx));
+  } catch (std::out_of_range& e) {
+    *exception = createErrorString(ctx, "Global JS context didn't map to a valid executor");
+    return JSValueMakeUndefined(ctx);
+  }
+
+  executor->terminateWebWorker((int) workerDouble);
+
+  return JSValueMakeUndefined(ctx);
+}
+
 static JSValueRef nativeLoggingHook(
     JSContextRef ctx,
     JSObjectRef function,
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.h b/ReactAndroid/src/main/jni/react/JSCExecutor.h
index 030648bb9601..3a9a6a0ea694 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.h
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.h
@@ -62,6 +62,7 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
 
   int addWebWorker(const std::string& script, JSValueRef workerRef);
   void postMessageToWebWorker(int worker, JSValueRef message, JSValueRef *exn);
+  void terminateWebWorker(int worker);
 
   static JSValueRef nativeStartWorker(
       JSContextRef ctx,
@@ -77,6 +78,13 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
       size_t argumentCount,
       const JSValueRef arguments[],
       JSValueRef *exception);
+  static JSValueRef nativeTerminateWorker(
+      JSContextRef ctx,
+      JSObjectRef function,
+      JSObjectRef thisObject,
+      size_t argumentCount,
+      const JSValueRef arguments[],
+      JSValueRef *exception);
 };
 
 } }
diff --git a/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp b/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
index 2357ddce4a16..c0313c4eba21 100644
--- a/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
@@ -1,8 +1,8 @@
 // Copyright 2004-present Facebook. All Rights Reserved.
 
 #include <unistd.h>
+#include <condition_variable>
 #include <mutex>
-#include <pthread.h>
 #include <unordered_map>
 
 #include <fb/assert.h>
@@ -43,14 +43,14 @@ JSCWebWorker::JSCWebWorker(int id, JSCWebWorkerOwner *owner, std::string scriptS
 }
 
 JSCWebWorker::~JSCWebWorker() {
-  // TODO(9604430): Implement tear down
+  FBASSERTMSGF(isTerminated(), "Didn't terminate the web worker before releasing it!");
 }
 
 void JSCWebWorker::postMessage(JSValueRef msg) {
   std::string msgString = Value(owner_->getContext(), msg).toJSONString();
 
   workerMessageQueueThread_->runOnQueue([this, msgString] () {
-    if (isFinished()) {
+    if (isTerminated()) {
       return;
     }
 
@@ -60,17 +60,46 @@ void JSCWebWorker::postMessage(JSValueRef msg) {
   });
 }
 
-void JSCWebWorker::finish() {
-  isFinished_ = true;
-  // TODO(9604430): Implement tear down
+void JSCWebWorker::terminate() {
+  if (isTerminated()) {
+    return;
+  }
+  isTerminated_.store(true, std::memory_order_release);
+
+  if (workerMessageQueueThread_->isOnThread()) {
+    terminateOnWorkerThread();
+  } else {
+    std::mutex signalMutex;
+    std::condition_variable signalCv;
+    bool terminationComplete = false;
+
+    workerMessageQueueThread_->runOnQueue([&] () mutable {
+      std::lock_guard<std::mutex> lock(signalMutex);
+
+      terminateOnWorkerThread();
+      terminationComplete = true;
+
+      signalCv.notify_one();
+    });
+
+    std::unique_lock<std::mutex> lock(signalMutex);
+    signalCv.wait(lock, [&terminationComplete] { return terminationComplete; });
+  }
 }
 
-bool JSCWebWorker::isFinished() {
-  return isFinished_;
+void JSCWebWorker::terminateOnWorkerThread() {
+  s_globalContextRefToJSCWebWorker.erase(context_);
+  JSGlobalContextRelease(context_);
+  context_ = nullptr;
+  workerMessageQueueThread_->quitSynchronous();
+}
+
+bool JSCWebWorker::isTerminated() {
+  return isTerminated_.load(std::memory_order_acquire);
 }
 
 void JSCWebWorker::initJSVMAndLoadScript() {
-  FBASSERTMSGF(!isFinished(), "Worker was already finished!");
+  FBASSERTMSGF(!isTerminated(), "Worker was already finished!");
   FBASSERTMSGF(!context_, "Worker JS VM was already created!");
 
   context_ = JSGlobalContextCreateInGroup(
@@ -106,6 +135,11 @@ JSValueRef JSCWebWorker::nativePostMessage(
   }
   JSValueRef msg = arguments[0];
   JSCWebWorker *webWorker = s_globalContextRefToJSCWebWorker.at(JSContextGetGlobalContext(ctx));
+
+  if (webWorker->isTerminated()) {
+    return JSValueMakeUndefined(ctx);
+  }
+
   webWorker->postMessageToOwner(msg);
   
   return JSValueMakeUndefined(ctx);
diff --git a/ReactAndroid/src/main/jni/react/JSCWebWorker.h b/ReactAndroid/src/main/jni/react/JSCWebWorker.h
index 5e4070d84878..e8bda56f11f9 100644
--- a/ReactAndroid/src/main/jni/react/JSCWebWorker.h
+++ b/ReactAndroid/src/main/jni/react/JSCWebWorker.h
@@ -1,5 +1,6 @@
 // Copyright 2004-present Facebook. All Rights Reserved.
 
+#include <atomic>
 #include <functional>
 #include <mutex>
 #include <string>
@@ -56,17 +57,26 @@ class JSCWebWorker {
    * ownerMessageQueueThread_.
    */
   void postMessage(JSValueRef msg);
-  void finish();
-  bool isFinished();
+
+  /**
+   * Synchronously quits the current worker and cleans up its VM.
+   */
+  void terminate();
+
+  /**
+   * Whether terminate() has been called on this worker.
+   */
+  bool isTerminated();
 
   static Object createMessageObject(JSContextRef context, const std::string& msgData);
 private:
   void initJSVMAndLoadScript();
   void postRunnableToEventLoop(std::function<void()>&& runnable);
   void postMessageToOwner(JSValueRef result);
+  void terminateOnWorkerThread();
 
   int id_;
-  bool isFinished_ = false;
+  std::atomic_bool isTerminated_ = ATOMIC_VAR_INIT(false);
   std::string scriptName_;
   JSCWebWorkerOwner *owner_ = nullptr;
   std::shared_ptr<JMessageQueueThread> ownerMessageQueueThread_;
diff --git a/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.cpp b/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.cpp
index 0202f4a4dd97..8499f7b1c615 100644
--- a/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.cpp
@@ -21,6 +21,18 @@ void JMessageQueueThread::runOnQueue(std::function<void()>&& runnable) {
   method(m_jobj, JNativeRunnable::newObjectCxxArgs(runnable).get());
 }
 
+bool JMessageQueueThread::isOnThread() {
+  static auto method = MessageQueueThread::javaClassStatic()->
+    getMethod<jboolean()>("isOnThread");
+  return method(m_jobj);
+}
+
+void JMessageQueueThread::quitSynchronous() {
+  static auto method = MessageQueueThread::javaClassStatic()->
+    getMethod<void()>("quitSynchronous");
+  method(m_jobj);
+}
+
 /* static */
 std::unique_ptr<JMessageQueueThread> JMessageQueueThread::currentMessageQueueThread() {
   static auto method = MessageQueueThreadRegistry::javaClassStatic()->
diff --git a/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.h b/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.h
index c2c875a6dc28..1a75f819af7e 100644
--- a/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.h
+++ b/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.h
@@ -25,6 +25,17 @@ class JMessageQueueThread {
    */
   void runOnQueue(std::function<void()>&& runnable);
 
+  /**
+   * Returns whether the currently executing thread is this MessageQueueThread.
+   */
+  bool isOnThread();
+
+  /**
+   * Synchronously quits the current MessageQueueThread. Can be called from any thread, but will
+   * block if not called on this MessageQueueThread.
+   */
+  void quitSynchronous();
+
   MessageQueueThread::javaobject jobj() {
     return m_jobj.get();
   }

From e29eaaddc86965fd3cc3124fb7d37b1ef54a90c3 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Tue, 12 Jan 2016 04:51:17 -0800
Subject: [PATCH 0714/1411] WebWorkers: Add simple integration test

Summary:
public

Adds a simple integration test that verifies that a message can be posted to/from the worker andthat it's torn down properly.

Reviewed By: lexs

Differential Revision: D2815244

fb-gh-sync-id: 00c0d8933d785b2913d378c0589b2fbabf0d0edb
---
 .../react/testing/IntRecordingModule.java     | 56 +++++++++++++++++++
 .../testing/ReactIntegrationTestCase.java     |  3 +
 2 files changed, 59 insertions(+)
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/IntRecordingModule.java

diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/IntRecordingModule.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/IntRecordingModule.java
new file mode 100644
index 000000000000..5cf7e4373ef6
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/IntRecordingModule.java
@@ -0,0 +1,56 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.testing;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import com.facebook.react.bridge.BaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+
+/**
+ * Native module provides single method {@link #record} which records its single int argument
+ * in calls array
+ */
+public class IntRecordingModule extends BaseJavaModule {
+
+  private final List<Integer> mCalls = new ArrayList<>();
+  private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
+
+  @Override
+  public String getName() {
+    return "Recording";
+  }
+
+  @ReactMethod
+  public void record(int i) {
+    mCalls.add(i);
+    mCountDownLatch.countDown();
+  }
+
+  public void reset() {
+    mCalls.clear();
+  }
+
+  public List<Integer> getCalls() {
+    return mCalls;
+  }
+
+  public void waitForFirstCall() {
+    try {
+      if (!mCountDownLatch.await(15000, TimeUnit.MILLISECONDS)) {
+        throw new RuntimeException("Timed out waiting for first call");
+      }
+    } catch (InterruptedException e) {
+      throw new RuntimeException(e);
+    }
+  }
+}
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java
index e70a8428bbfe..58173647f0ad 100644
--- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java
@@ -14,6 +14,7 @@
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 
+import android.app.Application;
 import android.support.test.InstrumentationRegistry;
 import android.test.AndroidTestCase;
 import android.view.View;
@@ -27,6 +28,7 @@
 import com.facebook.react.bridge.LifecycleEventListener;
 import com.facebook.react.bridge.SoftAssertions;
 import com.facebook.react.bridge.UiThreadUtil;
+import com.facebook.react.common.ApplicationHolder;
 import com.facebook.react.common.futures.SimpleSettableFuture;
 import com.facebook.react.modules.core.Timing;
 
@@ -155,6 +157,7 @@ public void run() {
               mBridgeIdleSignaler = new ReactBridgeIdleSignaler();
               mInstance.addBridgeIdleDebugListener(mBridgeIdleSignaler);
               getContext().initializeWithInstance(mInstance);
+              ApplicationHolder.setApplication((Application) getContext().getApplicationContext());
               setupEvent.occur();
             }
           });

From 9bbcb5baf7a0bc31f7ff392bee2cc03df9840f88 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Tue, 12 Jan 2016 15:11:24 +0000
Subject: [PATCH 0715/1411] Update bots/README.md

---
 bots/README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bots/README.md b/bots/README.md
index 20311de2f500..8ee9530bef79 100644
--- a/bots/README.md
+++ b/bots/README.md
@@ -1 +1 @@
-These are the comments inserted by the Facebook github bot to new issues.
+Github bots and messages used by the Facebook Github bot.

From bfcce36efbe64b5bc064dac090b8de68b0337664 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Tue, 12 Jan 2016 07:40:50 -0800
Subject: [PATCH 0716/1411] Update Android.mk files to fix github build

Summary:
public

Since we don't use BUCK in OSS, we also have to update the Android.mk files :(

Reviewed By: bestander

Differential Revision: D2823434

fb-gh-sync-id: 4feef307f8f158653ef8e76d72447d79f47c329a
---
 ReactAndroid/src/main/jni/react/Android.mk     | 9 +++++----
 ReactAndroid/src/main/jni/react/jni/Android.mk | 7 ++++---
 2 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/Android.mk b/ReactAndroid/src/main/jni/react/Android.mk
index e0fff007099b..cf522d8df70a 100644
--- a/ReactAndroid/src/main/jni/react/Android.mk
+++ b/ReactAndroid/src/main/jni/react/Android.mk
@@ -6,10 +6,11 @@ LOCAL_MODULE := libreactnative
 
 LOCAL_SRC_FILES := \
   Bridge.cpp \
-  Value.cpp \
-  MethodCall.cpp \
-  JSCHelpers.cpp \
   JSCExecutor.cpp \
+  JSCHelpers.cpp \
+  JSCWebWorker.cpp \
+  MethodCall.cpp \
+  Value.cpp \
 
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/..
 LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
@@ -29,4 +30,4 @@ include $(BUILD_STATIC_LIBRARY)
 $(call import-module,fb)
 $(call import-module,jni)
 $(call import-module,folly)
-$(call import-module,jsc)
\ No newline at end of file
+$(call import-module,jsc)
diff --git a/ReactAndroid/src/main/jni/react/jni/Android.mk b/ReactAndroid/src/main/jni/react/jni/Android.mk
index 1a829fad5aa4..bb051ddafa99 100644
--- a/ReactAndroid/src/main/jni/react/jni/Android.mk
+++ b/ReactAndroid/src/main/jni/react/jni/Android.mk
@@ -5,10 +5,11 @@ include $(CLEAR_VARS)
 LOCAL_MODULE := reactnativejni
 
 LOCAL_SRC_FILES := \
+  JMessageQueueThread.cpp \
+  JSLoader.cpp \
+  NativeArray.cpp \
   OnLoad.cpp \
   ProxyExecutor.cpp \
-  NativeArray.cpp \
-  JSLoader.cpp \
 
 LOCAL_C_INCLUDES := $(LOCAL_PATH)
 
@@ -27,4 +28,4 @@ $(call import-module,react)
 $(call import-module,jsc)
 $(call import-module,folly)
 $(call import-module,jni)
-$(call import-module,jsc)
\ No newline at end of file
+$(call import-module,jsc)

From 48cb144c2df0d2974bef8f85cf809d56d8db2259 Mon Sep 17 00:00:00 2001
From: trave7er <mathew.park.yu@gmail.com>
Date: Tue, 12 Jan 2016 08:17:49 -0800
Subject: [PATCH 0717/1411] fix lint warnings: single/double quotes, and
 semi-colons

Summary:
fixed lint warnings for TextInputExample.ios.js file
Closes https://github.com/facebook/react-native/pull/5216

Reviewed By: svcscm

Differential Revision: D2818390

Pulled By: mkonicek

fb-gh-sync-id: 8ada7038a1ca73f8c158945264cf6dbfe1c23fcc
---
 Examples/UIExplorer/TextInputExample.ios.js | 44 ++++++++++-----------
 1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/Examples/UIExplorer/TextInputExample.ios.js b/Examples/UIExplorer/TextInputExample.ios.js
index f8324c51af1d..486cf411bfb1 100644
--- a/Examples/UIExplorer/TextInputExample.ios.js
+++ b/Examples/UIExplorer/TextInputExample.ios.js
@@ -202,52 +202,52 @@ class TokenizedTextExample extends React.Component {
 
 var BlurOnSubmitExample = React.createClass({
   focusNextField(nextField) {
-    this.refs[nextField].focus()
+    this.refs[nextField].focus();
   },
 
   render: function() {
     return (
       <View>
         <TextInput
-          ref='1'
+          ref="1"
           style={styles.default}
-          placeholder='blurOnSubmit = false'
-          returnKeyType='next'
+          placeholder="blurOnSubmit = false"
+          returnKeyType="next"
           blurOnSubmit={false}
           onSubmitEditing={() => this.focusNextField('2')}
         />
         <TextInput
-          ref='2'
+          ref="2"
           style={styles.default}
-          keyboardType='email-address'
-          placeholder='blurOnSubmit = false'
-          returnKeyType='next'
+          keyboardType="email-address"
+          placeholder="blurOnSubmit = false"
+          returnKeyType="next"
           blurOnSubmit={false}
           onSubmitEditing={() => this.focusNextField('3')}
         />
         <TextInput
-          ref='3'
+          ref="3"
           style={styles.default}
-          keyboardType='url'
-          placeholder='blurOnSubmit = false'
-          returnKeyType='next'
+          keyboardType="url"
+          placeholder="blurOnSubmit = false"
+          returnKeyType="next"
           blurOnSubmit={false}
           onSubmitEditing={() => this.focusNextField('4')}
         />
         <TextInput
-          ref='4'
+          ref="4"
           style={styles.default}
-          keyboardType='numeric'
-          placeholder='blurOnSubmit = false'
+          keyboardType="numeric"
+          placeholder="blurOnSubmit = false"
           blurOnSubmit={false}
           onSubmitEditing={() => this.focusNextField('5')}
         />
         <TextInput
-          ref='5'
+          ref="5"
           style={styles.default}
-          keyboardType='numbers-and-punctuation'
-          placeholder='blurOnSubmit = true'
-          returnKeyType='done'
+          keyboardType="numbers-and-punctuation"
+          placeholder="blurOnSubmit = true"
+          returnKeyType="done"
         />
       </View>
     );
@@ -335,7 +335,7 @@ exports.examples = [
     }
   },
   {
-    title: "Live Re-Write (no spaces allowed)",
+    title: 'Live Re-Write (no spaces allowed)',
     render: function() {
       return <RewriteExampleInvalidCharacters />;
     }
@@ -582,8 +582,8 @@ exports.examples = [
         <View>
           <TextInput
             style={styles.multiline}
-            placeholder='blurOnSubmit = true'
-            returnKeyType='next'
+            placeholder="blurOnSubmit = true"
+            returnKeyType="next"
             blurOnSubmit={true}
             multiline={true}
             onSubmitEditing={event => alert(event.nativeEvent.text)}

From 888749220dac26382412f2c38ac5f9205cc842e5 Mon Sep 17 00:00:00 2001
From: Kelvin De Moya <kdemoya17@gmail.com>
Date: Tue, 12 Jan 2016 08:24:42 -0800
Subject: [PATCH 0718/1411] Enable JSX files extension

Summary:
JSX extension is much used in React, this would be a natural addition for React Native.
See: https://github.com/facebook/react-native/issues/2303
Closes https://github.com/facebook/react-native/pull/5233

Reviewed By: svcscm

Differential Revision: D2818888

Pulled By: mkonicek

fb-gh-sync-id: 856d1b8ba9ff88ba08a00923174e3284f359d774
---
 .../src/DependencyResolver/DependencyGraph/ResolutionRequest.js | 2 ++
 .../src/DependencyResolver/DependencyGraph/index.js             | 2 +-
 packager/react-packager/src/Server/index.js                     | 1 +
 3 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
index f4b200007787..4414862f431c 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
@@ -340,6 +340,8 @@ class ResolutionRequest {
         file = potentialModulePath + '.native.js';
       } else if (this._fastfs.fileExists(potentialModulePath + '.js')) {
         file = potentialModulePath + '.js';
+      } else if (this._fastfs.fileExists(potentialModulePath + '.jsx')) {
+        file = potentialModulePath + '.jsx';
       } else if (this._fastfs.fileExists(potentialModulePath + '.json')) {
         file = potentialModulePath + '.json';
       } else {
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
index 1192159b308d..1278d2ce8544 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
@@ -55,7 +55,7 @@ class DependencyGraph {
       platforms: platforms || [],
       preferNativePlatform: preferNativePlatform || false,
       cache,
-      extensions: extensions || ['js', 'json'],
+      extensions: extensions || ['js', 'jsx', 'json'],
       mocksPattern,
       extractRequires,
       shouldThrowOnUnresolvedErrors,
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index fe7294bbcc8c..63432090570c 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -151,6 +151,7 @@ class Server {
         dir: dir,
         globs: [
           '**/*.js',
+          '**/*.jsx',
           '**/*.json',
         ].concat(assetGlobs),
       };

From 44cd2e0e73593eb7b97c4854c14f854a20a5d8d0 Mon Sep 17 00:00:00 2001
From: Denis Koroskin <dkoroskin@fb.com>
Date: Tue, 12 Jan 2016 11:51:43 -0800
Subject: [PATCH 0719/1411] In ReactPropertyProcessor, use switch over key
 String instead of HashMap<String,Integer> lookup followed by a switch over
 int.

Summary: public Switch over a String is essentially a switch(string.hashCode()) and it is faster than a HashMap lookup. It also doesn't use extra memory, and doesn't require static initialization (startup penalty). Plus I believe this way the generated code looks more readable.

Reviewed By: lexs

Differential Revision: D2818223

fb-gh-sync-id: d9100ec0f8ad556c347681cbe1433d066076d3e5
---
 .../processing/ReactPropertyProcessor.java    | 33 ++-----------------
 1 file changed, 3 insertions(+), 30 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/processing/ReactPropertyProcessor.java b/ReactAndroid/src/main/java/com/facebook/react/processing/ReactPropertyProcessor.java
index bee08f38722d..19641f633dcd 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/processing/ReactPropertyProcessor.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/processing/ReactPropertyProcessor.java
@@ -89,11 +89,6 @@ public class ReactPropertyProcessor extends AbstractProcessor {
   private static final TypeName CONCRETE_PROPERTY_MAP_TYPE =
       ParameterizedTypeName.get(HashMap.class, String.class, String.class);
 
-  private static final TypeName MAPPINGS_MAP_TYPE =
-      ParameterizedTypeName.get(Map.class, String.class, Integer.class);
-  private static final TypeName CONCRETE_MAPPINGS_MAP_TYPE =
-      ParameterizedTypeName.get(HashMap.class, String.class, Integer.class);
-
   private final Map<ClassName, ClassInfo> mClasses;
 
   @SuppressFieldNotInitialized
@@ -242,8 +237,6 @@ private void generateCode(ClassInfo classInfo, List<PropertyInfo> properties)
     TypeSpec holderClass = TypeSpec.classBuilder(holderClassName)
         .addSuperinterface(superType)
         .addModifiers(PUBLIC)
-        .addField(MAPPINGS_MAP_TYPE, "mappings", PRIVATE, STATIC, FINAL)
-        .addStaticBlock(generatePropertyMappings(properties))
         .addMethod(generateSetPropertySpec(classInfo, properties))
         .addMethod(getMethods)
         .build();
@@ -274,24 +267,6 @@ private static TypeName getSuperType(ClassInfo classInfo) {
     }
   }
 
-  private static CodeBlock generatePropertyMappings(List<PropertyInfo> properties) {
-    if (properties.isEmpty()) {
-      return CodeBlock.builder()
-          .addStatement("mappings = $T.emptyMap()", Collections.class)
-          .build();
-    }
-
-    CodeBlock.Builder builder = CodeBlock.builder()
-        .addStatement("mappings = new $T($L)", CONCRETE_MAPPINGS_MAP_TYPE, properties.size());
-
-    for (int i = 0, size = properties.size(); i < size; i++) {
-      PropertyInfo propertyInfo = properties.get(i);
-      builder.addStatement("mappings.put($S, $L)", propertyInfo.mProperty.name(), i);
-    }
-
-    return builder.build();
-  }
-
   private static MethodSpec generateSetPropertySpec(
       ClassInfo classInfo,
       List<PropertyInfo> properties) {
@@ -324,15 +299,13 @@ private static CodeBlock generateSetProperty(ClassInfo info, List<PropertyInfo>
       return CodeBlock.builder().build();
     }
 
-    CodeBlock.Builder builder = CodeBlock.builder()
-        .addStatement("Integer id = mappings.get(name)")
-        .addStatement("if (id == null) return");
+    CodeBlock.Builder builder = CodeBlock.builder();
 
-    builder.add("switch (id) {\n").indent();
+    builder.add("switch (name) {\n").indent();
     for (int i = 0, size = properties.size(); i < size; i++) {
       PropertyInfo propertyInfo = properties.get(i);
       builder
-          .add("case $L:\n", i)
+          .add("case \"$L\":\n", propertyInfo.mProperty.name())
           .indent();
 
       switch (info.getType()) {

From 2ed199fa2bd7b68546a0c688437657653e7dad03 Mon Sep 17 00:00:00 2001
From: Brent Vatne <brentvatne@gmail.com>
Date: Tue, 12 Jan 2016 12:02:48 -0800
Subject: [PATCH 0720/1411] Update KnownIssues.md

---
 docs/KnownIssues.md | 1 -
 1 file changed, 1 deletion(-)

diff --git a/docs/KnownIssues.md b/docs/KnownIssues.md
index e0fa28958246..cc9de7dd6d3b 100644
--- a/docs/KnownIssues.md
+++ b/docs/KnownIssues.md
@@ -22,7 +22,6 @@ Our provisional plan for common views and modules includes:
 #### Views
 
 ```
-ART
 Maps
 Modal
 Spinner (http://developer.android.com/guide/topics/ui/controls/spinner.html)

From e2641a237a453b27bed72815d5c14d251fd491a3 Mon Sep 17 00:00:00 2001
From: Alexander Blom <blom@fb.com>
Date: Tue, 12 Jan 2016 13:40:25 -0800
Subject: [PATCH 0721/1411] Scan parent class' methods for @ReactProp and
 @ReactPropGroup annotations

Summary:
When class A declares a ReactProp method foo() and class B that extends from A overrides foo(), it loses the annotation so it has to be duplicated. To allow "inheriting" annotation on Override, we need to scan parent class methods for annotation as well. This diff implements the required logic.

public

Reviewed By: dkoroskin

Differential Revision: D2818278

fb-gh-sync-id: 7e9ae728cc70ce2345db7bc48b3857a0e91c4ca3
---
 .../processing/ReactPropertyProcessor.java    | 50 +++++++++++++------
 1 file changed, 35 insertions(+), 15 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/processing/ReactPropertyProcessor.java b/ReactAndroid/src/main/java/com/facebook/react/processing/ReactPropertyProcessor.java
index 19641f633dcd..bffd3f5dffa5 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/processing/ReactPropertyProcessor.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/processing/ReactPropertyProcessor.java
@@ -23,6 +23,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -157,6 +158,14 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
     for (ClassInfo classInfo : mClasses.values()) {
       try {
         if (!shouldIgnoreClass(classInfo)) {
+          // Sort by name
+          Collections.sort(
+              classInfo.mProperties, new Comparator<PropertyInfo>() {
+                @Override
+                public int compare(PropertyInfo a, PropertyInfo b) {
+                  return a.mProperty.name().compareTo(b.mProperty.name());
+                }
+              });
           generateCode(classInfo, classInfo.mProperties);
         } else if (shouldWarnClass(classInfo)) {
           warning(classInfo.mElement, "Class was skipped. Classes need to be non-private.");
@@ -178,29 +187,40 @@ private ClassInfo parseClass(ClassName className, TypeElement typeElement) {
     TypeName viewType = targetType.equals(SHADOW_NODE_TYPE) ? null : targetType;
 
     ClassInfo classInfo = new ClassInfo(className, typeElement, viewType);
+    findProperties(classInfo, typeElement);
 
+    return classInfo;
+  }
+
+  private void findProperties(ClassInfo classInfo, TypeElement typeElement) {
     PropertyInfo.Builder propertyBuilder = new PropertyInfo.Builder(mTypes, mElements, classInfo);
-    for (Element element : mElements.getAllMembers(typeElement)) {
-      ReactProp prop = element.getAnnotation(ReactProp.class);
-      ReactPropGroup propGroup = element.getAnnotation(ReactPropGroup.class);
 
-      try {
-        if (prop != null || propGroup != null) {
-          checkElement(element);
-        }
+    // Recursively search class hierarchy
+    while (typeElement != null) {
+      for (Element element : typeElement.getEnclosedElements()) {
+        ReactProp prop = element.getAnnotation(ReactProp.class);
+        ReactPropGroup propGroup = element.getAnnotation(ReactPropGroup.class);
 
-        if (prop != null) {
-          classInfo.addProperty(propertyBuilder.build(element, new RegularProperty(prop)));
-        } else if (propGroup != null) {
-          for (int i = 0, size = propGroup.names().length; i < size; i++) {
-            classInfo.addProperty(propertyBuilder.build(element, new GroupProperty(propGroup, i)));
+        try {
+          if (prop != null || propGroup != null) {
+            checkElement(element);
           }
+
+          if (prop != null) {
+            classInfo.addProperty(propertyBuilder.build(element, new RegularProperty(prop)));
+          } else if (propGroup != null) {
+            for (int i = 0, size = propGroup.names().length; i < size; i++) {
+              classInfo
+                  .addProperty(propertyBuilder.build(element, new GroupProperty(propGroup, i)));
+            }
+          }
+        } catch (ReactPropertyException e) {
+          error(e.element, e.getMessage());
         }
-      } catch (ReactPropertyException e) {
-        error(e.element, e.getMessage());
       }
+
+      typeElement = (TypeElement) mTypes.asElement(typeElement.getSuperclass());
     }
-    return classInfo;
   }
 
   private TypeName getTargetType(TypeMirror mirror) {

From 801b83da2d37e6cdd97d6e4e8e157293fb9dbd84 Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Tue, 12 Jan 2016 15:33:00 -0800
Subject: [PATCH 0722/1411] Support "free" mocks.

Summary:
It's possible that a mock doesn't have an associated real module that it maps to. This is actually very common in www, where we have JS mocks for dynamic PHP JS modules. The implementation I chose seems like the smartest one for now: if a module cannot be resolved, we look up whether we have a mock with the same id. If we do, we just resolve it. That's it! And it also only does the minimum amount of resolution necessary.

public

Reviewed By: martinbigio

Differential Revision: D2822277

fb-gh-sync-id: 7c9fbb6f69a0c0c85157c0650f5719d94a02410e
---
 .../DependencyGraph/ResolutionRequest.js      | 14 +++-
 .../__tests__/DependencyGraph-test.js         | 84 +++++++++++++++++--
 2 files changed, 88 insertions(+), 10 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
index 4414862f431c..50a590256bb1 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
@@ -135,15 +135,25 @@ class ResolutionRequest {
           const filteredPairs = [];
 
           dependencies.forEach((modDep, i) => {
+            const name = depNames[i];
             if (modDep == null) {
+              // It is possible to require mocks that don't have a real
+              // module backing them. If a dependency cannot be found but there
+              // exists a mock with the desired ID, resolve it and add it as
+              // a dependency.
+              if (mocks && mocks[name]) {
+                const mockModule = this._moduleCache.getModule(mocks[name]);
+                return filteredPairs.push([name, mockModule]);
+              }
+
               debug(
                 'WARNING: Cannot find required module `%s` from module `%s`',
-                depNames[i],
+                name,
                 mod.path
               );
               return false;
             }
-            return filteredPairs.push([depNames[i], modDep]);
+            return filteredPairs.push([name, modDep]);
           });
 
           response.setResolvedDependencyPairs(mod, filteredPairs);
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
index 8f41d88c2dbd..b1126a4cc3e3 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
@@ -10,13 +10,13 @@
 
 jest.autoMockOff();
 
-const Promise = require('promise');
+jest.mock('fs');
 
-jest
-  .mock('fs');
+const Promise = require('promise');
+const DependencyGraph = require('../index');
+const fs = require('graceful-fs');
 
-var DependencyGraph = require('../index');
-var fs = require('graceful-fs');
+const mocksPattern = /(?:[\\/]|^)__mocks__[\\/]([^\/]+)\.js$/;
 
 describe('DependencyGraph', function() {
   let defaults;
@@ -4024,7 +4024,7 @@ describe('DependencyGraph', function() {
       var root = '/root';
       fs.__setMockFilesystem({
         'root': {
-          '__mocks': {
+          '__mocks__': {
             'A.js': '',
           },
           'index.js': '',
@@ -4061,7 +4061,7 @@ describe('DependencyGraph', function() {
       var dgraph = new DependencyGraph({
         ...defaults,
         roots: [root],
-        mocksPattern: /(?:[\\/]|^)__mocks__[\\/]([^\/]+)\.js$/,
+        mocksPattern,
       });
 
       return dgraph.getDependencies('/root/b.js')
@@ -4101,7 +4101,7 @@ describe('DependencyGraph', function() {
       var dgraph = new DependencyGraph({
         ...defaults,
         roots: [root],
-        mocksPattern: /(?:[\\/]|^)__mocks__[\\/]([^\/]+)\.js$/,
+        mocksPattern,
       });
 
       return getOrderedDependenciesAsJSON(dgraph, '/root/A.js')
@@ -4134,6 +4134,74 @@ describe('DependencyGraph', function() {
               id: '/root/__mocks__/A.js',
               dependencies: ['b'],
             },
+            {
+              path: '/root/__mocks__/b.js',
+              isJSON: false,
+              isAsset: false,
+              isAsset_DEPRECATED: false,
+              isPolyfill: false,
+              id: '/root/__mocks__/b.js',
+              dependencies: [],
+            },
+          ]);
+        });
+    });
+
+    pit('resolves mocks that do not have a real module associated with them', () => {
+      var root = '/root';
+      fs.__setMockFilesystem({
+        'root': {
+          '__mocks__': {
+            'foo.js': [
+              'require("b");',
+            ].join('\n'),
+            'b.js': '',
+          },
+          'A.js': [
+            '/**',
+            ' * @providesModule A',
+            ' */',
+            'require("foo");',
+          ].join('\n'),
+        },
+      });
+
+      var dgraph = new DependencyGraph({
+        ...defaults,
+        roots: [root],
+        mocksPattern,
+      });
+
+      return getOrderedDependenciesAsJSON(dgraph, '/root/A.js')
+        .then(deps => {
+          expect(deps).toEqual([
+            {
+              path: '/root/A.js',
+              isJSON: false,
+              isAsset: false,
+              isAsset_DEPRECATED: false,
+              isPolyfill: false,
+              id: 'A',
+              dependencies: ['foo'],
+            },
+            {
+              path: '/root/__mocks__/foo.js',
+              isJSON: false,
+              isAsset: false,
+              isAsset_DEPRECATED: false,
+              isPolyfill: false,
+              id: '/root/__mocks__/foo.js',
+              dependencies: ['b'],
+            },
+            {
+              path: '/root/__mocks__/b.js',
+              isJSON: false,
+              isAsset: false,
+              isAsset_DEPRECATED: false,
+              isPolyfill: false,
+              id: '/root/__mocks__/b.js',
+              dependencies: [],
+            },
           ]);
         });
     });

From 51621b14cbd53dcd3b16c6dbf67dd42b51934612 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Tue, 12 Jan 2016 16:44:18 -0800
Subject: [PATCH 0723/1411] Get rid of deprecated `fs.existSync`

Reviewed By: mmahoney

Differential Revision: D2824569

fb-gh-sync-id: efed6e88f566110b8286ea59563c2904b3dd8059
---
 packager/react-packager/src/SocketInterface/index.js | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/packager/react-packager/src/SocketInterface/index.js b/packager/react-packager/src/SocketInterface/index.js
index e2d70bbf6f57..69b52a4f9579 100644
--- a/packager/react-packager/src/SocketInterface/index.js
+++ b/packager/react-packager/src/SocketInterface/index.js
@@ -49,7 +49,7 @@ const SocketInterface = {
         sockPath = '\\\\.\\pipe\\' + sockPath
       }
 
-      if (fs.existsSync(sockPath)) {
+      if (existsSync(sockPath)) {
         var sock = net.connect(sockPath);
         sock.on('connect', () => {
           SocketClient.create(sockPath).then(
@@ -135,4 +135,13 @@ function createServer(resolve, reject, options, sockPath) {
   });
 }
 
+function existsSync(filename) {
+  try {
+    fs.accessSync(filename);
+    return true;
+  } catch(ex) {
+    return false;
+  }
+}
+
 module.exports = SocketInterface;

From 0359046af12797da290bd2b673cd3b510052e274 Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Wed, 13 Jan 2016 11:35:01 +0800
Subject: [PATCH 0724/1411] give a more detailed bundle example

---
 docs/RunningOnDeviceIOS.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/RunningOnDeviceIOS.md b/docs/RunningOnDeviceIOS.md
index 5dae7ccc4a05..84d57c54175b 100644
--- a/docs/RunningOnDeviceIOS.md
+++ b/docs/RunningOnDeviceIOS.md
@@ -28,7 +28,7 @@ You can also pack all the JavaScript code within the app itself. This way you ca
 1. Open `AwesomeApp/ios/AwesomeApp/AppDelegate.m`
 2. Follow the instructions for "OPTION 2":
   * Uncomment `jsCodeLocation = [[NSBundle mainBundle] ...`
-  * Run the `react-native bundle` command in terminal from the root directory of your app
+  * Run the `react-native bundle --platform ios --dev false --entry-file index.ios.js --bundle-output iOS/main.jsbundle` command in terminal from the root directory of your app
 
 The bundle script supports a couple of flags:
 

From 963f26cea8b921caba1f98d45e91992d00e96664 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= <renaudeau.gaetan@gmail.com>
Date: Wed, 13 Jan 2016 02:54:19 -0800
Subject: [PATCH 0725/1411] add ScrollResponder#scrollResponderZoomTo animated
 second argument

Summary:
ScrollResponder was missing a non animated version for zoomToRect.

- scrollResponderScrollTo <> scrollResponderScrollWithoutAnimationTo
- ~~scrollResponderZoomTo <> :new: **scrollResponderZoomWithoutAnimationTo**~~
- `scrollResponderZoomTo(rect, animated = true)`
Closes https://github.com/facebook/react-native/pull/5268

Reviewed By: svcscm

Differential Revision: D2823311

Pulled By: nicklockwood

fb-gh-sync-id: ea409d332963f56e8b58ec2c086db3f6815058f7
---
 Libraries/Components/ScrollResponder.js | 5 +++--
 React/Views/RCTScrollViewManager.m      | 4 ++--
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/Libraries/Components/ScrollResponder.js b/Libraries/Components/ScrollResponder.js
index d6e7f6150ba8..088f7b2c99c9 100644
--- a/Libraries/Components/ScrollResponder.js
+++ b/Libraries/Components/ScrollResponder.js
@@ -388,12 +388,13 @@ var ScrollResponderMixin = {
   /**
    * A helper function to zoom to a specific rect in the scrollview.
    * @param {object} rect Should have shape {x, y, width, height}
+   * @param {bool} animated Specify whether zoom is instant or animated
    */
-  scrollResponderZoomTo: function(rect: { x: number; y: number; width: number; height: number; }) {
+  scrollResponderZoomTo: function(rect: { x: number; y: number; width: number; height: number; }, animated: boolean = true) {
     if (Platform.OS === 'android') {
       invariant('zoomToRect is not implemented');
     } else {
-      ScrollViewManager.zoomToRect(React.findNodeHandle(this), rect);
+      ScrollViewManager.zoomToRect(React.findNodeHandle(this), rect, animated);
     }
   },
 
diff --git a/React/Views/RCTScrollViewManager.m b/React/Views/RCTScrollViewManager.m
index 702b75043944..7381e4223991 100644
--- a/React/Views/RCTScrollViewManager.m
+++ b/React/Views/RCTScrollViewManager.m
@@ -152,12 +152,12 @@ - (UIView *)view
     }];
 }
 
-RCT_EXPORT_METHOD(zoomToRect:(nonnull NSNumber *)reactTag withRect:(CGRect)rect)
+RCT_EXPORT_METHOD(zoomToRect:(nonnull NSNumber *)reactTag withRect:(CGRect)rect animated:(BOOL)animated)
 {
   [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry){
     UIView *view = viewRegistry[reactTag];
     if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
-      [(id<RCTScrollableProtocol>)view zoomToRect:rect animated:YES];
+      [(id<RCTScrollableProtocol>)view zoomToRect:rect animated:animated];
     } else {
       RCTLogError(@"tried to zoomToRect: on non-RCTScrollableProtocol view %@ with tag #%@", view, reactTag);
     }

From c95cfe890eae40e270748bcb3a795d25bc3539f9 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Wed, 13 Jan 2016 14:14:26 +0000
Subject: [PATCH 0726/1411] Remove extra newline in npm-shrinkwrap.json

---
 npm-shrinkwrap.json | 1 -
 1 file changed, 1 deletion(-)

diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index be4e7c0d843e..c01193cfbf02 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -1,4 +1,3 @@
-
 {
   "name": "react-native",
   "version": "0.12.0",

From 66cd8f71ebd66e9db9cc7680a4b594e942efc574 Mon Sep 17 00:00:00 2001
From: James Ide <ide@jameside.com>
Date: Wed, 13 Jan 2016 04:57:14 -0800
Subject: [PATCH 0727/1411] Set the versions in package.json and React.podspec
 to 0.0.0-master

Summary:
The current versions in these files is 0.12.0, which is out of date. Better to claim no version than the wrong version, so this diff changes the versions to 0.0.0-master.

Release branches will still have the correct versions.
Closes https://github.com/facebook/react-native/pull/5241

Reviewed By: svcscm

Differential Revision: D2819277

Pulled By: javache

fb-gh-sync-id: 99d4682e5d1f571e241f306caf309b2944483909
---
 React.podspec       | 2 +-
 npm-shrinkwrap.json | 2 +-
 package.json        | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/React.podspec b/React.podspec
index 8083357a2b59..4891cb3b247f 100644
--- a/React.podspec
+++ b/React.podspec
@@ -1,6 +1,6 @@
 Pod::Spec.new do |s|
   s.name                = "React"
-  s.version             = "0.15.0"
+  s.version             = "0.0.0-master"
   s.summary             = "Build high quality mobile apps using React."
   s.description         = <<-DESC
                             React Native apps are built using the React JS
diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index c01193cfbf02..0fc1c377b728 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -1,6 +1,6 @@
 {
   "name": "react-native",
-  "version": "0.12.0",
+  "version": "0.0.0-master",
   "dependencies": {
     "absolute-path": {
       "version": "0.0.0",
diff --git a/package.json b/package.json
index a52208af4c37..88fdbc580c0b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "react-native",
-  "version": "0.12.0",
+  "version": "0.0.0-master",
   "description": "A framework for building native apps using React",
   "license": "BSD-3-Clause",
   "repository": {

From f8f5cb1fcf893397ccb8172921e8dfaad8ff6150 Mon Sep 17 00:00:00 2001
From: Brent Vatne <brentvatne@gmail.com>
Date: Wed, 13 Jan 2016 07:30:20 -0800
Subject: [PATCH 0728/1411] Fix content offset calculations when scrolling up

Summary:
The offset is cached so it doesn't need to calculate the entire height on each scroll, but the cached value was being thrown away when you scroll up -- this fixes that. Found this because it was breaking an infinite scroll view that depended on the contentOffset.y value reported from onScroll.
Closes https://github.com/facebook/react-native/pull/5278

Reviewed By: svcscm

Differential Revision: D2827556

Pulled By: dmmiller

fb-gh-sync-id: 0897b89de427cada7389113991444f57c970f980
---
 .../recyclerview/RecyclerViewBackedScrollView.java  | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollView.java
index 6ebfb211c0b6..919764f8481b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollView.java
@@ -117,16 +117,17 @@ public int getTopOffsetForItem(int index) {
       if (mLastRequestedPosition != index) {
         int sum = 0;
         int startIndex = 0;
+
+        if (mLastRequestedPosition != -1) {
+          sum = mOffsetForLastPosition;
+          startIndex = mLastRequestedPosition;
+        }
+
         if (mLastRequestedPosition < index) {
-          if (mLastRequestedPosition != -1) {
-            sum = mOffsetForLastPosition;
-            startIndex = mLastRequestedPosition;
-          }
           for (int i = startIndex; i < index; i++) {
             sum += mReactListAdapter.mViews.get(i).getMeasuredHeight();
           }
-        }
-        else {
+        } else {
           if (index < (mLastRequestedPosition - index)) {
             for (int i = 0; i < index; i++) {
               sum += mReactListAdapter.mViews.get(i).getMeasuredHeight();

From f5062d0840edff52c6a4c96ab14bb950a9bea018 Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Wed, 13 Jan 2016 11:33:37 -0800
Subject: [PATCH 0729/1411] Add doc for RefreshControl on the website

Summary:
Exposes the doc for RefreshControl and add a link to the component page in ScrollView.
Closes https://github.com/facebook/react-native/pull/5209

Reviewed By: svcscm

Differential Revision: D2818217

Pulled By: mkonicek

fb-gh-sync-id: eb1ae70103e6a02af3a12866509f68eacc413dfd
---
 Libraries/Components/ScrollView/ScrollView.js | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js
index a5d87e082a46..d2f54fa3e415 100644
--- a/Libraries/Components/ScrollView/ScrollView.js
+++ b/Libraries/Components/ScrollView/ScrollView.js
@@ -297,6 +297,8 @@ var ScrollView = React.createClass({
     /**
      * A RefreshControl component, used to provide pull-to-refresh
      * functionality for the ScrollView.
+     *
+     * See [RefreshControl](http://facebook.github.io/react-native/docs/refreshcontrol.html).
      */
     refreshControl: PropTypes.element,
 

From edf30065ea3544611af66c5319f47e46ee31b721 Mon Sep 17 00:00:00 2001
From: Oleg Lokhvitsky <olegbl@gmail.com>
Date: Wed, 13 Jan 2016 11:46:26 -0800
Subject: [PATCH 0730/1411] Add details about undoing require() image sizing

It can be overridden with undefined to scale dynamically
---
 docs/Images.md | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/docs/Images.md b/docs/Images.md
index 4dad3998a445..12ab24fe2fdf 100644
--- a/docs/Images.md
+++ b/docs/Images.md
@@ -60,6 +60,8 @@ var icon = this.props.active ? require('./my-icon-active.png') : require('./my-i
 <Image source={icon} />
 ```
 
+Note that image sources required this way include size (width, height) info for the Image. If you need to scale the image dynamically (i.e. via flex), you may need to manually set { width: undefined, height: undefined } on the style attribute.
+
 **Available React Native 0.14+**. If you've generated your project with 0.13 or earlier, read this. The new asset system relies on build hooks for [Xcode](https://github.com/facebook/react-native/pull/3523) and [Gradle](https://github.com/facebook/react-native/commit/9dc036d2b99e6233297c55a3490bfc308e34e75f) that are included in new projects generated with `react-native init`. If you generated your projects before that, you'll have to manually add them to your projects to use the new images asset system. See [Upgrading](/react-native/docs/upgrading.html) for instructions on how to do this.
 
 ## Images From Hybrid App's Resources

From 00659864bc42f127efa07a98fe3e2bd5d4ba1d58 Mon Sep 17 00:00:00 2001
From: Adam Miskiewicz <adam.skevy@mac.com>
Date: Wed, 13 Jan 2016 12:53:06 -0800
Subject: [PATCH 0731/1411] Fixing CLI to pass "sourcemap-output" option to
 bundler.

Summary:
Currently, the CLI is not passing the sourceMapURL option to the bundler, so source maps are output as "null".
Closes https://github.com/facebook/react-native/pull/5288

Reviewed By: svcscm

Differential Revision: D2828092

Pulled By: androidtrunkagent

fb-gh-sync-id: 2e464ddf65f0d4fcbff3c50281391cb30b5c799c
---
 local-cli/bundle/buildBundle.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/local-cli/bundle/buildBundle.js b/local-cli/bundle/buildBundle.js
index a5fea2d4f559..5b75ca3fb687 100644
--- a/local-cli/bundle/buildBundle.js
+++ b/local-cli/bundle/buildBundle.js
@@ -33,6 +33,7 @@ function buildBundle(args, config, output = outputBundle) {
 
     const requestOpts = {
       entryFile: args['entry-file'],
+      sourceMapUrl: args['sourcemap-output'],
       dev: args.dev,
       minify: !args.dev,
       platform: args.platform,

From 1abd12b68be6358761411272117c830c1afd306a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= <renaudeau.gaetan@gmail.com>
Date: Wed, 13 Jan 2016 13:26:59 -0800
Subject: [PATCH 0732/1411] configureScene: add routeStack in second argument

Summary:
Giving routeStack in second parameter of configureScene allows to do more advanced scene configuration.
I have use-case where I can only determine the scene config from the navigation context (not only from the route object but also from where it's located).
Closes https://github.com/facebook/react-native/pull/5254

Reviewed By: svcscm

Differential Revision: D2828415

Pulled By: androidtrunkagent

fb-gh-sync-id: 27b6c79b24cbc194e080541e9202ca84c55a0bc4
---
 Libraries/CustomComponents/Navigator/Navigator.js | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/Libraries/CustomComponents/Navigator/Navigator.js b/Libraries/CustomComponents/Navigator/Navigator.js
index 47349d7698cd..b87532e5867d 100644
--- a/Libraries/CustomComponents/Navigator/Navigator.js
+++ b/Libraries/CustomComponents/Navigator/Navigator.js
@@ -189,11 +189,11 @@ var Navigator = React.createClass({
   propTypes: {
     /**
      * Optional function that allows configuration about scene animations and
-     * gestures. Will be invoked with the route and should return a scene
-     * configuration object
+     * gestures. Will be invoked with the route and the routeStack and should
+     * return a scene configuration object
      *
      * ```
-     * (route) => Navigator.SceneConfigs.FloatFromRight
+     * (route, routeStack) => Navigator.SceneConfigs.FloatFromRight
      * ```
      */
     configureScene: PropTypes.func,
@@ -293,7 +293,7 @@ var Navigator = React.createClass({
     }
     return {
       sceneConfigStack: routeStack.map(
-        (route) => this.props.configureScene(route)
+        (route) => this.props.configureScene(route, routeStack)
       ),
       routeStack,
       presentedIndex: initialRouteIndex,
@@ -368,7 +368,7 @@ var Navigator = React.createClass({
     this.setState({
       routeStack: nextRouteStack,
       sceneConfigStack: nextRouteStack.map(
-        this.props.configureScene
+        route => this.props.configureScene(route, nextRouteStack)
       ),
       presentedIndex: destIndex,
       activeGesture: null,
@@ -913,7 +913,7 @@ var Navigator = React.createClass({
     var nextStack = activeStack.concat([route]);
     var destIndex = nextStack.length - 1;
     var nextAnimationConfigStack = activeAnimationConfigStack.concat([
-      this.props.configureScene(route),
+      this.props.configureScene(route, nextStack),
     ]);
     this._emitWillFocus(nextStack[destIndex]);
     this.setState({
@@ -981,7 +981,7 @@ var Navigator = React.createClass({
     var nextRouteStack = this.state.routeStack.slice();
     var nextAnimationModeStack = this.state.sceneConfigStack.slice();
     nextRouteStack[index] = route;
-    nextAnimationModeStack[index] = this.props.configureScene(route);
+    nextAnimationModeStack[index] = this.props.configureScene(route, nextRouteStack);
 
     if (index === this.state.presentedIndex) {
       this._emitWillFocus(route);

From f903625df17889021b648dc1251def0426e4dd50 Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Thu, 14 Jan 2016 16:53:56 +0800
Subject: [PATCH 0733/1411] Update React Native dependency version

---
 docs/EmbeddedAppAndroid.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/EmbeddedAppAndroid.md b/docs/EmbeddedAppAndroid.md
index 27a0bfddb1cb..376cf1ecce9c 100644
--- a/docs/EmbeddedAppAndroid.md
+++ b/docs/EmbeddedAppAndroid.md
@@ -18,7 +18,7 @@ Since React makes no assumptions about the rest of your technology stack, it's e
 
 In your app's `build.gradle` file add the React Native dependency:
 
-    compile 'com.facebook.react:react-native:0.13.0'
+    compile 'com.facebook.react:react-native:0.17.+'
 
 You can find the latest version of the react-native library on [Maven Central](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.facebook.react%22%20AND%20a%3A%22react-native%22). Next, make sure you have the Internet permission in your `AndroidManifest.xml`:
 

From 5835d26a7519054c90a4233ba210e9c4631e744b Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Thu, 14 Jan 2016 20:01:40 +0800
Subject: [PATCH 0734/1411] update onResume arguments

---
 docs/EmbeddedAppAndroid.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/EmbeddedAppAndroid.md b/docs/EmbeddedAppAndroid.md
index 376cf1ecce9c..88122d52ac86 100644
--- a/docs/EmbeddedAppAndroid.md
+++ b/docs/EmbeddedAppAndroid.md
@@ -77,7 +77,7 @@ protected void onResume() {
     super.onResume();
 
     if (mReactInstanceManager != null) {
-        mReactInstanceManager.onResume(this);
+        mReactInstanceManager.onResume(this, this);
     }
 }
 ```

From 393adacfa61d6500f8ad285ed136320cf713fcbd Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Thu, 14 Jan 2016 04:27:33 -0800
Subject: [PATCH 0735/1411] Fix WebView not to double load the URL

Reviewed By: andreicoman11

Differential Revision: D2823397

fb-gh-sync-id: deb04ab22bee7022bc8bcb61fa4c24f86eddbaa8
---
 .../facebook/react/views/webview/ReactWebViewManager.java   | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
index 6d7a883bb82f..bb259d65b6f8 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
@@ -286,6 +286,12 @@ public void setUrl(WebView view, @Nullable String url) {
     // TODO(8495359): url and html are coupled as they both call loadUrl, therefore in case when
     // property url is removed in favor of property html being added in single transaction we may
     // end up in a state when blank url is loaded as it depends on the order of update operations!
+
+    String currentUrl = view.getUrl();
+    if (currentUrl != null && currentUrl.equals(url)) {
+      // We are already loading it so no need to stomp over it and start again
+      return;
+    }
     if (url != null) {
       view.loadUrl(url);
     } else {

From f8c384ffddc79b9590c5c6cddbc27ee2057e87fe Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Thu, 14 Jan 2016 04:30:04 -0800
Subject: [PATCH 0736/1411] Consolidate event dispatch to one method that gets
 the context and event dispatcher

Reviewed By: andreicoman11

Differential Revision: D2827596

fb-gh-sync-id: 3971237aa5eb08934a341e1486c7130381252c99
---
 .../views/webview/ReactWebViewManager.java    | 37 +++++++++----------
 1 file changed, 18 insertions(+), 19 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
index bb259d65b6f8..7e756c782b14 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
@@ -34,6 +34,7 @@
 import com.facebook.react.uimanager.SimpleViewManager;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.UIManagerModule;
+import com.facebook.react.uimanager.events.Event;
 import com.facebook.react.uimanager.events.EventDispatcher;
 
 /**
@@ -94,10 +95,8 @@ public void onPageStarted(WebView webView, String url, Bitmap favicon) {
       super.onPageStarted(webView, url, favicon);
       mLastLoadFailed = false;
 
-      ReactContext reactContext = (ReactContext) ((ReactWebView) webView).getContext();
-      EventDispatcher eventDispatcher =
-          reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
-      eventDispatcher.dispatchEvent(
+      dispatchEvent(
+          webView,
           new TopLoadingStartEvent(
               webView.getId(),
               SystemClock.uptimeMillis(),
@@ -117,14 +116,12 @@ public void onReceivedError(
       // Android WebView does it in the opposite way, so we need to simulate that behavior
       emitFinishEvent(webView, failingUrl);
 
-      ReactContext reactContext = (ReactContext) ((ReactWebView) webView).getContext();
       WritableMap eventData = createWebViewEvent(webView, failingUrl);
       eventData.putDouble("code", errorCode);
       eventData.putString("description", description);
 
-      EventDispatcher eventDispatcher =
-          reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
-      eventDispatcher.dispatchEvent(
+      dispatchEvent(
+          webView,
           new TopLoadingErrorEvent(webView.getId(), SystemClock.uptimeMillis(), eventData));
     }
 
@@ -132,26 +129,28 @@ public void onReceivedError(
     public void doUpdateVisitedHistory(WebView webView, String url, boolean isReload) {
       super.doUpdateVisitedHistory(webView, url, isReload);
 
-      ReactContext reactContext = (ReactContext) webView.getContext();
-      EventDispatcher eventDispatcher =
-          reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
-      eventDispatcher.dispatchEvent(
+      dispatchEvent(
+          webView,
           new TopLoadingStartEvent(
+            webView.getId(),
+            SystemClock.uptimeMillis(),
+            createWebViewEvent(webView, url)));
+    }
+
+    private void emitFinishEvent(WebView webView, String url) {
+      dispatchEvent(
+          webView,
+          new TopLoadingFinishEvent(
               webView.getId(),
               SystemClock.uptimeMillis(),
               createWebViewEvent(webView, url)));
     }
 
-    private void emitFinishEvent(WebView webView, String url) {
+    private static void dispatchEvent(WebView webView, Event event) {
       ReactContext reactContext = (ReactContext) webView.getContext();
-
       EventDispatcher eventDispatcher =
           reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
-      eventDispatcher.dispatchEvent(
-          new TopLoadingFinishEvent(
-              webView.getId(),
-              SystemClock.uptimeMillis(),
-              createWebViewEvent(webView, url)));
+      eventDispatcher.dispatchEvent(event);
     }
 
     private WritableMap createWebViewEvent(WebView webView, String url) {

From 892497408c14b61687cb823a144bd80996023404 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Thu, 14 Jan 2016 04:31:51 -0800
Subject: [PATCH 0737/1411] Open sourced Camera Roll module

Reviewed By: mkonicek

Differential Revision: D2827804

fb-gh-sync-id: c1f06f148855bc4f69da8e19b8445988f1b022b3
---
 ...ollExample.ios.js => CameraRollExample.js} |  45 +-
 ...ameraRollView.ios.js => CameraRollView.js} |   5 +
 Examples/UIExplorer/UIExplorerList.android.js |   1 +
 Examples/UIExplorer/UIExplorerList.ios.js     |   2 +-
 .../modules/camera/CameraRollManager.java     | 444 ++++++++++++++++++
 .../react/shell/MainReactPackage.java         |   2 +
 6 files changed, 477 insertions(+), 22 deletions(-)
 rename Examples/UIExplorer/{CameraRollExample.ios.js => CameraRollExample.js} (75%)
 rename Examples/UIExplorer/{CameraRollView.ios.js => CameraRollView.js} (97%)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/camera/CameraRollManager.java

diff --git a/Examples/UIExplorer/CameraRollExample.ios.js b/Examples/UIExplorer/CameraRollExample.js
similarity index 75%
rename from Examples/UIExplorer/CameraRollExample.ios.js
rename to Examples/UIExplorer/CameraRollExample.js
index d1f3e96c909a..d431560722f2 100644
--- a/Examples/UIExplorer/CameraRollExample.ios.js
+++ b/Examples/UIExplorer/CameraRollExample.js
@@ -15,24 +15,25 @@
  */
 'use strict';
 
-var React = require('react-native');
-var {
+const React = require('react-native');
+const {
   CameraRoll,
   Image,
   SliderIOS,
   StyleSheet,
-  SwitchIOS,
+  Switch,
   Text,
   View,
   TouchableOpacity
 } = React;
 
-var CameraRollView = require('./CameraRollView.ios');
-var AssetScaledImageExampleView = require('./AssetScaledImageExample');
+const CameraRollView = require('./CameraRollView');
 
-var CAMERA_ROLL_VIEW = 'camera_roll_view';
+const AssetScaledImageExampleView = require('./AssetScaledImageExample');
 
-var CameraRollExample = React.createClass({
+const CAMERA_ROLL_VIEW = 'camera_roll_view';
+
+const CameraRollExample = React.createClass({
 
   getInitialState() {
     return {
@@ -45,7 +46,7 @@ var CameraRollExample = React.createClass({
   render() {
     return (
       <View>
-        <SwitchIOS
+        <Switch
           onValueChange={this._onSwitchChange}
           value={this.state.bigImages} />
         <Text>{(this.state.bigImages ? 'Big' : 'Small') + ' Images'}</Text>
@@ -65,18 +66,20 @@ var CameraRollExample = React.createClass({
   },
 
   loadAsset(asset){
-    this.props.navigator.push({
-      title: 'Camera Roll Image',
-      component: AssetScaledImageExampleView,
-      backButtonTitle: 'Back',
-      passProps: { asset: asset },
-    });
+    if (this.props.navigator) {
+      this.props.navigator.push({
+        title: 'Camera Roll Image',
+        component: AssetScaledImageExampleView,
+        backButtonTitle: 'Back',
+        passProps: { asset: asset },
+      });
+    }
   },
 
   _renderImage(asset) {
-    var imageSize = this.state.bigImages ? 150 : 75;
-    var imageStyle = [styles.image, {width: imageSize, height: imageSize}];
-    var location = asset.node.location.longitude ?
+    const imageSize = this.state.bigImages ? 150 : 75;
+    const imageStyle = [styles.image, {width: imageSize, height: imageSize}];
+    const location = asset.node.location.longitude ?
       JSON.stringify(asset.node.location) : 'Unknown location';
     return (
       <TouchableOpacity key={asset} onPress={ this.loadAsset.bind( this, asset ) }>
@@ -97,9 +100,9 @@ var CameraRollExample = React.createClass({
   },
 
   _onSliderChange(value) {
-    var options = CameraRoll.GroupTypesOptions;
-    var index = Math.floor(value * options.length * 0.99);
-    var groupTypes = options[index];
+    const options = CameraRoll.GroupTypesOptions;
+    const index = Math.floor(value * options.length * 0.99);
+    const groupTypes = options[index];
     if (groupTypes !== this.state.groupTypes) {
       this.setState({groupTypes: groupTypes});
     }
@@ -111,7 +114,7 @@ var CameraRollExample = React.createClass({
   }
 });
 
-var styles = StyleSheet.create({
+const styles = StyleSheet.create({
   row: {
     flexDirection: 'row',
     flex: 1,
diff --git a/Examples/UIExplorer/CameraRollView.ios.js b/Examples/UIExplorer/CameraRollView.js
similarity index 97%
rename from Examples/UIExplorer/CameraRollView.ios.js
rename to Examples/UIExplorer/CameraRollView.js
index 74507aa2c1b5..a8824d048462 100644
--- a/Examples/UIExplorer/CameraRollView.ios.js
+++ b/Examples/UIExplorer/CameraRollView.js
@@ -22,6 +22,7 @@ var {
   CameraRoll,
   Image,
   ListView,
+  Platform,
   StyleSheet,
   View,
 } = React;
@@ -139,6 +140,10 @@ var CameraRollView = React.createClass({
       groupTypes: this.props.groupTypes,
       assetType: this.props.assetType,
     };
+    if (Platform.OS === "android") {
+      // not supported in android
+      delete fetchParams.groupTypes;
+    }
     if (this.state.lastCursor) {
       fetchParams.after = this.state.lastCursor;
     }
diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index 607f581fbfc8..1976128b116f 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -43,6 +43,7 @@ var APIS = [
   require('./AccessibilityAndroidExample.android'),
   require('./AlertExample').AlertExample,
   require('./BorderExample'),
+  require('./CameraRollExample'),
   require('./ClipboardExample'),
   require('./GeolocationExample'),
   require('./IntentAndroidExample.android'),
diff --git a/Examples/UIExplorer/UIExplorerList.ios.js b/Examples/UIExplorer/UIExplorerList.ios.js
index 512b033accd8..0c1e9e2e7153 100644
--- a/Examples/UIExplorer/UIExplorerList.ios.js
+++ b/Examples/UIExplorer/UIExplorerList.ios.js
@@ -66,7 +66,7 @@ var APIS = [
   require('./AppStateIOSExample'),
   require('./AsyncStorageExample'),
   require('./BorderExample'),
-  require('./CameraRollExample.ios'),
+  require('./CameraRollExample'),
   require('./ClipboardExample'),
   require('./GeolocationExample'),
   require('./LayoutExample'),
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/CameraRollManager.java b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/CameraRollManager.java
new file mode 100644
index 000000000000..289a045bfdba
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/CameraRollManager.java
@@ -0,0 +1,444 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.modules.camera;
+
+import javax.annotation.Nullable;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.database.Cursor;
+import android.graphics.BitmapFactory;
+import android.media.MediaScannerConnection;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Environment;
+import android.provider.MediaStore;
+import android.provider.MediaStore.Images;
+import android.text.TextUtils;
+
+import com.facebook.common.logging.FLog;
+import com.facebook.react.bridge.Callback;
+import com.facebook.react.bridge.GuardedAsyncTask;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.WritableArray;
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.bridge.WritableNativeArray;
+import com.facebook.react.bridge.WritableNativeMap;
+import com.facebook.react.common.ReactConstants;
+
+// TODO #6015104: rename to something less iOSish
+/**
+ * {@link NativeModule} that allows JS to interact with the photos on the device (i.e.
+ * {@link MediaStore.Images}).
+ */
+public class CameraRollManager extends ReactContextBaseJavaModule {
+
+  private static final String TAG = "Catalyst/CameraRollManager";
+
+  public static final boolean IS_JELLY_BEAN_OR_LATER =
+      Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
+
+  private static final String[] PROJECTION;
+  static {
+    if (IS_JELLY_BEAN_OR_LATER) {
+      PROJECTION = new String[] {
+          Images.Media._ID,
+          Images.Media.MIME_TYPE,
+          Images.Media.BUCKET_DISPLAY_NAME,
+          Images.Media.DATE_TAKEN,
+          Images.Media.WIDTH,
+          Images.Media.HEIGHT,
+          Images.Media.LONGITUDE,
+          Images.Media.LATITUDE
+      };
+    } else {
+      PROJECTION = new String[] {
+          Images.Media._ID,
+          Images.Media.MIME_TYPE,
+          Images.Media.BUCKET_DISPLAY_NAME,
+          Images.Media.DATE_TAKEN,
+          Images.Media.LONGITUDE,
+          Images.Media.LATITUDE
+      };
+    }
+  }
+
+  private static final String SELECTION_BUCKET = Images.Media.BUCKET_DISPLAY_NAME + " = ?";
+  private static final String SELECTION_DATE_TAKEN = Images.Media.DATE_TAKEN + " < ?";
+
+  public CameraRollManager(ReactApplicationContext reactContext) {
+    super(reactContext);
+  }
+
+  @Override
+  public String getName() {
+    return "RKCameraRollManager";
+  }
+
+  @Override
+  public Map<String, Object> getConstants() {
+    return Collections.emptyMap();
+  }
+
+  /**
+   * Save an image to the gallery (i.e. {@link MediaStore.Images}). This copies the original file
+   * from wherever it may be to the external storage pictures directory, so that it can be scanned
+   * by the MediaScanner.
+   *
+   * @param uri the file:// URI of the image to save
+   * @param success callback to be invoked on successful save to gallery; the only argument passed
+   *        to this callback is the MediaStore content:// URI of the new image.
+   * @param error callback to be invoked on error (e.g. can't copy file, external storage not
+   *        available etc.)
+   */
+  @ReactMethod
+  public void saveImageWithTag(String uri, final Callback success, final Callback error) {
+    new SaveImageTag(getReactApplicationContext(), Uri.parse(uri), success, error)
+        .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+  }
+
+  private static class SaveImageTag extends GuardedAsyncTask<Void, Void> {
+
+    private final Context mContext;
+    private final Uri mUri;
+    private final Callback mSuccess;
+    private final Callback mError;
+
+    public SaveImageTag(ReactContext context, Uri uri, Callback success, Callback error) {
+      super(context);
+      mContext = context;
+      mUri = uri;
+      mSuccess = success;
+      mError = error;
+    }
+
+    @Override
+    protected void doInBackgroundGuarded(Void... params) {
+      File source = new File(mUri.getPath());
+      FileChannel input = null, output = null;
+      try {
+        File pictures =
+            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
+        pictures.mkdirs();
+        if (!pictures.isDirectory()) {
+          mError.invoke("External storage pictures directory not available");
+          return;
+        }
+        File dest = new File(pictures, source.getName());
+        int n = 0;
+        String fullSourceName = source.getName();
+        String sourceName, sourceExt;
+        if (fullSourceName.indexOf('.') >= 0) {
+          sourceName = fullSourceName.substring(0, fullSourceName.lastIndexOf('.'));
+          sourceExt = fullSourceName.substring(fullSourceName.lastIndexOf('.'));
+        } else {
+          sourceName = fullSourceName;
+          sourceExt = "";
+        }
+        while (!dest.createNewFile()) {
+          dest = new File(pictures, sourceName + "_" + (n++) + sourceExt);
+        }
+        input = new FileInputStream(source).getChannel();
+        output = new FileOutputStream(dest).getChannel();
+        output.transferFrom(input, 0, input.size());
+        input.close();
+        output.close();
+
+        MediaScannerConnection.scanFile(
+            mContext,
+            new String[]{dest.getAbsolutePath()},
+            null,
+            new MediaScannerConnection.OnScanCompletedListener() {
+              @Override
+              public void onScanCompleted(String path, Uri uri) {
+                if (uri != null) {
+                  mSuccess.invoke(uri.toString());
+                } else {
+                  mError.invoke("Could not add image to gallery");
+                }
+              }
+            });
+      } catch (IOException e) {
+        mError.invoke(e.getMessage());
+      } finally {
+        if (input != null && input.isOpen()) {
+          try {
+            input.close();
+          } catch (IOException e) {
+            FLog.e(ReactConstants.TAG, "Could not close input channel", e);
+          }
+        }
+        if (output != null && output.isOpen()) {
+          try {
+            output.close();
+          } catch (IOException e) {
+            FLog.e(ReactConstants.TAG, "Could not close output channel", e);
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Get photos from {@link MediaStore.Images}, most recent first.
+   *
+   * @param params a map containing the following keys:
+   *        <ul>
+   *          <li>first (mandatory): a number representing the number of photos to fetch</li>
+   *          <li>
+   *            after (optional): a cursor that matches page_info[end_cursor] returned by a
+   *            previous call to {@link #getPhotos}
+   *          </li>
+   *          <li>groupName (optional): an album name</li>
+   *          <li>
+   *            mimeType (optional): restrict returned images to a specific mimetype (e.g.
+   *            image/jpeg)
+   *          </li>
+   *        </ul>
+   * @param success the callback to be called when the photos are loaded; for a format of the
+   *        parameters passed to this callback, see {@code getPhotosReturnChecker} in CameraRoll.js
+   * @param error the callback to be called on error
+   */
+  @ReactMethod
+  public void getPhotos(final ReadableMap params, final Callback success, Callback error) {
+    int first = params.getInt("first");
+    String after = params.hasKey("after") ? params.getString("after") : null;
+    String groupName = params.hasKey("groupName") ? params.getString("groupName") : null;
+    ReadableArray mimeTypes = params.hasKey("mimeTypes")
+        ? params.getArray("mimeTypes")
+        : null;
+    if (params.hasKey("groupTypes")) {
+      throw new JSApplicationIllegalArgumentException("groupTypes is not supported on Android");
+    }
+
+    new GetPhotosTask(
+          getReactApplicationContext(),
+          first,
+          after,
+          groupName,
+          mimeTypes,
+          success,
+          error)
+          .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+  }
+
+  private static class GetPhotosTask extends GuardedAsyncTask<Void, Void> {
+    private final Context mContext;
+    private final int mFirst;
+    private final @Nullable String mAfter;
+    private final @Nullable String mGroupName;
+    private final @Nullable ReadableArray mMimeTypes;
+    private final Callback mSuccess;
+    private final Callback mError;
+
+    private GetPhotosTask(
+        ReactContext context,
+        int first,
+        @Nullable String after,
+        @Nullable String groupName,
+        @Nullable ReadableArray mimeTypes,
+        Callback success,
+        Callback error) {
+      super(context);
+      mContext = context;
+      mFirst = first;
+      mAfter = after;
+      mGroupName = groupName;
+      mMimeTypes = mimeTypes;
+      mSuccess = success;
+      mError = error;
+    }
+
+    @Override
+    protected void doInBackgroundGuarded(Void... params) {
+      StringBuilder selection = new StringBuilder("1");
+      List<String> selectionArgs = new ArrayList<>();
+      if (!TextUtils.isEmpty(mAfter)) {
+        selection.append(" AND " + SELECTION_DATE_TAKEN);
+        selectionArgs.add(mAfter);
+      }
+      if (!TextUtils.isEmpty(mGroupName)) {
+        selection.append(" AND " + SELECTION_BUCKET);
+        selectionArgs.add(mGroupName);
+      }
+      if (mMimeTypes != null && mMimeTypes.size() > 0) {
+        selection.append(" AND " + Images.Media.MIME_TYPE + " IN (");
+        for (int i = 0; i < mMimeTypes.size(); i++) {
+          selection.append("?,");
+          selectionArgs.add(mMimeTypes.getString(i));
+        }
+        selection.replace(selection.length() - 1, selection.length(), ")");
+      }
+      WritableMap response = new WritableNativeMap();
+      ContentResolver resolver = mContext.getContentResolver();
+      // using LIMIT in the sortOrder is not explicitly supported by the SDK (which does not support
+      // setting a limit at all), but it works because this specific ContentProvider is backed by
+      // an SQLite DB and forwards parameters to it without doing any parsing / validation.
+      try {
+        Cursor photos = resolver.query(
+            Images.Media.EXTERNAL_CONTENT_URI,
+            PROJECTION,
+            selection.toString(),
+            selectionArgs.toArray(new String[selectionArgs.size()]),
+            Images.Media.DATE_TAKEN + " DESC, " + Images.Media.DATE_MODIFIED + " DESC LIMIT " +
+                (mFirst + 1)); // set LIMIT to first + 1 so that we know how to populate page_info
+        if (photos == null) {
+          mError.invoke("Could not get photos");
+        } else {
+          try {
+            putEdges(resolver, photos, response, mFirst);
+            putPageInfo(photos, response, mFirst);
+          } finally {
+            photos.close();
+            mSuccess.invoke(response);
+          }
+        }
+      } catch (SecurityException e) {
+        mError.invoke("Could not get photos: need READ_EXTERNAL_STORAGE permission");
+      }
+    }
+  }
+
+  private static void putPageInfo(Cursor photos, WritableMap response, int limit) {
+    WritableMap pageInfo = new WritableNativeMap();
+    pageInfo.putBoolean("has_next_page", limit < photos.getCount());
+    if (limit < photos.getCount()) {
+      photos.moveToPosition(limit - 1);
+      pageInfo.putString(
+          "end_cursor",
+          photos.getString(photos.getColumnIndex(Images.Media.DATE_TAKEN)));
+    }
+    response.putMap("page_info", pageInfo);
+  }
+
+  private static void putEdges(
+      ContentResolver resolver,
+      Cursor photos,
+      WritableMap response,
+      int limit) {
+    WritableArray edges = new WritableNativeArray();
+    photos.moveToFirst();
+    int idIndex = photos.getColumnIndex(Images.Media._ID);
+    int mimeTypeIndex = photos.getColumnIndex(Images.Media.MIME_TYPE);
+    int groupNameIndex = photos.getColumnIndex(Images.Media.BUCKET_DISPLAY_NAME);
+    int dateTakenIndex = photos.getColumnIndex(Images.Media.DATE_TAKEN);
+    int widthIndex = IS_JELLY_BEAN_OR_LATER ? photos.getColumnIndex(Images.Media.WIDTH) : -1;
+    int heightIndex = IS_JELLY_BEAN_OR_LATER ? photos.getColumnIndex(Images.Media.HEIGHT) : -1;
+    int longitudeIndex = photos.getColumnIndex(Images.Media.LONGITUDE);
+    int latitudeIndex = photos.getColumnIndex(Images.Media.LATITUDE);
+
+    for (int i = 0; i < limit && !photos.isAfterLast(); i++) {
+      WritableMap edge = new WritableNativeMap();
+      WritableMap node = new WritableNativeMap();
+      boolean imageInfoSuccess =
+          putImageInfo(resolver, photos, node, idIndex, widthIndex, heightIndex);
+      if (imageInfoSuccess) {
+        putBasicNodeInfo(photos, node, mimeTypeIndex, groupNameIndex, dateTakenIndex);
+        putLocationInfo(photos, node, longitudeIndex, latitudeIndex);
+
+        edge.putMap("node", node);
+        edges.pushMap(edge);
+      } else {
+        // we skipped an image because we couldn't get its details (e.g. width/height), so we
+        // decrement i in order to correctly reach the limit, if the cursor has enough rows
+        i--;
+      }
+      photos.moveToNext();
+    }
+    response.putArray("edges", edges);
+  }
+
+  private static void putBasicNodeInfo(
+      Cursor photos,
+      WritableMap node,
+      int mimeTypeIndex,
+      int groupNameIndex,
+      int dateTakenIndex) {
+    node.putString("type", photos.getString(mimeTypeIndex));
+    node.putString("group_name", photos.getString(groupNameIndex));
+    node.putDouble("timestamp", photos.getLong(dateTakenIndex) / 1000d);
+  }
+
+  private static boolean putImageInfo(
+      ContentResolver resolver,
+      Cursor photos,
+      WritableMap node,
+      int idIndex,
+      int widthIndex,
+      int heightIndex) {
+    WritableMap image = new WritableNativeMap();
+    Uri photoUri = Uri.withAppendedPath(
+        Images.Media.EXTERNAL_CONTENT_URI,
+        photos.getString(idIndex));
+    image.putString("uri", photoUri.toString());
+    float width = -1;
+    float height = -1;
+    if (IS_JELLY_BEAN_OR_LATER) {
+      width = photos.getInt(widthIndex);
+      height = photos.getInt(heightIndex);
+    }
+    if (width <= 0 || height <= 0) {
+      try {
+        AssetFileDescriptor photoDescriptor = resolver.openAssetFileDescriptor(photoUri, "r");
+        BitmapFactory.Options options = new BitmapFactory.Options();
+        // Set inJustDecodeBounds to true so we don't actually load the Bitmap, but only get its
+        // dimensions instead.
+        options.inJustDecodeBounds = true;
+        BitmapFactory.decodeFileDescriptor(photoDescriptor.getFileDescriptor(), null, options);
+        photoDescriptor.close();
+
+        width = options.outWidth;
+        height = options.outHeight;
+      } catch (IOException e) {
+        FLog.e(TAG, "Could not get width/height for " + photoUri.toString(), e);
+        return false;
+      }
+    }
+    image.putDouble("width", width);
+    image.putDouble("height", height);
+    node.putMap("image", image);
+    return true;
+  }
+
+  private static void putLocationInfo(
+      Cursor photos,
+      WritableMap node,
+      int longitudeIndex,
+      int latitudeIndex) {
+    double longitude = photos.getDouble(longitudeIndex);
+    double latitude = photos.getDouble(latitudeIndex);
+    if (longitude > 0 || latitude > 0) {
+      WritableMap location = new WritableNativeMap();
+      location.putDouble("longitude", longitude);
+      location.putDouble("latitude", latitude);
+      node.putMap("location", location);
+    }
+  }
+
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
index e636cd1c08a5..6d98ea60a65b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
@@ -17,6 +17,7 @@
 import com.facebook.react.bridge.JavaScriptModule;
 import com.facebook.react.bridge.NativeModule;
 import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.modules.camera.CameraRollManager;
 import com.facebook.react.modules.dialog.DialogModule;
 import com.facebook.react.modules.fresco.FrescoModule;
 import com.facebook.react.modules.intent.IntentModule;
@@ -57,6 +58,7 @@ public class MainReactPackage implements ReactPackage {
   public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
     return Arrays.<NativeModule>asList(
       new AsyncStorageModule(reactContext),
+      new CameraRollManager(reactContext),
       new ClipboardModule(reactContext),
       new DialogModule(reactContext),
       new FrescoModule(reactContext),

From ff6a2c39989121b8671ab7cf74a90d048fdc9acf Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 14 Jan 2016 07:41:24 -0800
Subject: [PATCH 0738/1411] Deprecated
 `scrollResponderScrollWithoutAnimationTo`

Summary:
public

This diff deprecates `scrollResponderScrollWithoutAnimationTo` and replaces it with an optional `animated` param in `scrollResponderScrollTo`. This is more consistent with our other APIs.

Using the old `ScrollResponder.scrollResponderScrollWithoutAnimationTo` or  `ScrollView.scrollWithoutAnimationTo` functions will still work, but will trigger a warning.

Reviewed By: javache

Differential Revision: D2823479

fb-gh-sync-id: 259966512104ca7b3995c9586144812a91b8d3e9
---
 Libraries/Components/ScrollResponder.js       | 26 ++++-------
 Libraries/Components/ScrollView/ScrollView.js | 16 +++----
 React/Views/RCTScrollViewManager.m            | 45 +++++++++----------
 3 files changed, 38 insertions(+), 49 deletions(-)

diff --git a/Libraries/Components/ScrollResponder.js b/Libraries/Components/ScrollResponder.js
index 088f7b2c99c9..eb1475ce8770 100644
--- a/Libraries/Components/ScrollResponder.js
+++ b/Libraries/Components/ScrollResponder.js
@@ -348,41 +348,31 @@ var ScrollResponderMixin = {
 
   /**
    * A helper function to scroll to a specific point  in the scrollview.
-   * This is currently used to help focus on child textview's, but this
+   * This is currently used to help focus on child textviews, but this
    * can also be used to quickly scroll to any element we want to focus
    */
-  scrollResponderScrollTo: function(offsetX: number, offsetY: number) {
+  scrollResponderScrollTo: function(offsetX: number, offsetY: number, animated: boolean = true) {
     if (Platform.OS === 'android') {
       UIManager.dispatchViewManagerCommand(
         React.findNodeHandle(this),
-        UIManager.RCTScrollView.Commands.scrollTo,
+        UIManager.RCTScrollView.Commands[animated ? 'scrollTo' : 'scrollWithoutAnimationTo'],
         [Math.round(offsetX), Math.round(offsetY)],
       );
     } else {
       ScrollViewManager.scrollTo(
         React.findNodeHandle(this),
-        { x: offsetX, y: offsetY }
+        { x: offsetX, y: offsetY },
+        animated
       );
     }
   },
 
   /**
-   * Like `scrollResponderScrollTo` but immediately scrolls to the given
-   * position
+   * Deprecated, do not use.
    */
   scrollResponderScrollWithoutAnimationTo: function(offsetX: number, offsetY: number) {
-    if (Platform.OS === 'android') {
-      UIManager.dispatchViewManagerCommand(
-        React.findNodeHandle(this),
-        UIManager.RCTScrollView.Commands.scrollWithoutAnimationTo,
-        [offsetX, offsetY],
-      );
-    } else {
-      ScrollViewManager.scrollWithoutAnimationTo(
-        React.findNodeHandle(this),
-        { x: offsetX, y: offsetY }
-      );
-    }
+    console.warn('`scrollResponderScrollWithoutAnimationTo` is deprecated. Use `scrollResponderScrollTo` instead');
+    self.scrollResponderScrollTo(offsetX, offsetY, false);
   },
 
   /**
diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js
index d2f54fa3e415..7556e9c71edb 100644
--- a/Libraries/Components/ScrollView/ScrollView.js
+++ b/Libraries/Components/ScrollView/ScrollView.js
@@ -339,17 +339,17 @@ var ScrollView = React.createClass({
     return React.findNodeHandle(this.refs[INNERVIEW]);
   },
 
-  scrollTo: function(destY?: number, destX?: number) {
+  scrollTo: function(destY: number = 0, destX: number = 0, animated: boolean = true) {
     // $FlowFixMe - Don't know how to pass Mixin correctly. Postpone for now
-    this.getScrollResponder().scrollResponderScrollTo(destX || 0, destY || 0);
+    this.getScrollResponder().scrollResponderScrollTo(destX, destY, animated);
   },
 
-  scrollWithoutAnimationTo: function(destY?: number, destX?: number) {
-    // $FlowFixMe - Don't know how to pass Mixin correctly. Postpone for now
-    this.getScrollResponder().scrollResponderScrollWithoutAnimationTo(
-      destX || 0,
-      destY || 0,
-    );
+  /**
+   * Deprecated, do not use.
+   */
+  scrollWithoutAnimationTo: function(destY: number = 0, destX: number = 0) {
+    console.warn('`scrollWithoutAnimationTo` is deprecated. Use `scrollTo` instead');
+    this.scrollTo(destX, destY, false);
   },
 
   handleScroll: function(e: Object) {
diff --git a/React/Views/RCTScrollViewManager.m b/React/Views/RCTScrollViewManager.m
index 7381e4223991..549bc1fac824 100644
--- a/React/Views/RCTScrollViewManager.m
+++ b/React/Views/RCTScrollViewManager.m
@@ -80,7 +80,8 @@ - (UIView *)view
 RCT_EXPORT_METHOD(getContentSize:(nonnull NSNumber *)reactTag
                   callback:(RCTResponseSenderBlock)callback)
 {
-  [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTScrollView *> *viewRegistry) {
+  [self.bridge.uiManager addUIBlock:
+   ^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTScrollView *> *viewRegistry) {
 
     RCTScrollView *view = viewRegistry[reactTag];
     if (!view || ![view isKindOfClass:[RCTScrollView class]]) {
@@ -97,9 +98,10 @@ - (UIView *)view
 }
 
 RCT_EXPORT_METHOD(calculateChildFrames:(nonnull NSNumber *)reactTag
-                    callback:(RCTResponseSenderBlock)callback)
+                  callback:(RCTResponseSenderBlock)callback)
 {
-  [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTScrollView *> *viewRegistry) {
+  [self.bridge.uiManager addUIBlock:
+   ^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTScrollView *> *viewRegistry) {
 
     RCTScrollView *view = viewRegistry[reactTag];
     if (!view || ![view isKindOfClass:[RCTScrollView class]]) {
@@ -116,7 +118,8 @@ - (UIView *)view
 
 RCT_EXPORT_METHOD(endRefreshing:(nonnull NSNumber *)reactTag)
 {
-  [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTScrollView *> *viewRegistry) {
+  [self.bridge.uiManager addUIBlock:
+   ^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTScrollView *> *viewRegistry) {
 
     RCTScrollView *view = viewRegistry[reactTag];
     if (!view || ![view isKindOfClass:[RCTScrollView class]]) {
@@ -128,38 +131,34 @@ - (UIView *)view
   }];
 }
 
-RCT_EXPORT_METHOD(scrollTo:(nonnull NSNumber *)reactTag withOffset:(CGPoint)offset)
+RCT_EXPORT_METHOD(scrollTo:(nonnull NSNumber *)reactTag
+                  withOffset:(CGPoint)offset
+                  animated:(BOOL)animated)
 {
-  [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry){
+  [self.bridge.uiManager addUIBlock:
+   ^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry){
     UIView *view = viewRegistry[reactTag];
     if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
-      [(id<RCTScrollableProtocol>)view scrollToOffset:offset animated:YES];
+      [(id<RCTScrollableProtocol>)view scrollToOffset:offset animated:animated];
     } else {
-      RCTLogError(@"tried to scrollToOffset: on non-RCTScrollableProtocol view %@ with tag #%@", view, reactTag);
+      RCTLogError(@"tried to scrollTo: on non-RCTScrollableProtocol view %@ "
+                  "with tag #%@", view, reactTag);
     }
   }];
 }
 
-RCT_EXPORT_METHOD(scrollWithoutAnimationTo:(nonnull NSNumber *)reactTag withOffset:(CGPoint)offset)
-{
-    [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry){
-        UIView *view = viewRegistry[reactTag];
-        if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
-          [(id<RCTScrollableProtocol>)view scrollToOffset:offset animated:NO];
-        } else {
-          RCTLogError(@"tried to scrollToOffset: on non-RCTScrollableProtocol view %@ with tag #%@", view, reactTag);
-        }
-    }];
-}
-
-RCT_EXPORT_METHOD(zoomToRect:(nonnull NSNumber *)reactTag withRect:(CGRect)rect animated:(BOOL)animated)
+RCT_EXPORT_METHOD(zoomToRect:(nonnull NSNumber *)reactTag
+                  withRect:(CGRect)rect
+                  animated:(BOOL)animated)
 {
-  [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry){
+  [self.bridge.uiManager addUIBlock:
+   ^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry){
     UIView *view = viewRegistry[reactTag];
     if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
       [(id<RCTScrollableProtocol>)view zoomToRect:rect animated:animated];
     } else {
-      RCTLogError(@"tried to zoomToRect: on non-RCTScrollableProtocol view %@ with tag #%@", view, reactTag);
+      RCTLogError(@"tried to zoomToRect: on non-RCTScrollableProtocol view %@ "
+                  "with tag #%@", view, reactTag);
     }
   }];
 }

From e5381072dd5e6a74287805197ad8ae29020a6fe6 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 14 Jan 2016 09:55:13 -0800
Subject: [PATCH 0739/1411] Fixed transparent border around UIExplorer headers

Summary:
public

This was caused by the change to background color propagation, but was actually due to having an unnecessary wrapper view around the headers, which was itself a workaround for a padding bug that was fixed some time ago :-)

Reviewed By: tadeuzagallo

Differential Revision: D2830890

fb-gh-sync-id: b64e701dedb90b357ed7c463b745de021f38637b
---
 Examples/UIExplorer/UIExplorerListBase.js | 14 +++++---------
 Libraries/Text/TextStylePropTypes.js      | 15 ---------------
 2 files changed, 5 insertions(+), 24 deletions(-)

diff --git a/Examples/UIExplorer/UIExplorerListBase.js b/Examples/UIExplorer/UIExplorerListBase.js
index 71ce0031f75e..b4af76e60ed5 100644
--- a/Examples/UIExplorer/UIExplorerListBase.js
+++ b/Examples/UIExplorer/UIExplorerListBase.js
@@ -87,11 +87,9 @@ class UIExplorerListBase extends React.Component {
 
   _renderSectionHeader(data: any, section: string) {
     return (
-      <View style={styles.sectionHeader}>
-        <Text style={styles.sectionHeaderTitle}>
-          {section.toUpperCase()}
-        </Text>
-      </View>
+      <Text style={styles.sectionHeader}>
+        {section.toUpperCase()}
+      </Text>
     );
   }
 
@@ -148,14 +146,12 @@ var styles = StyleSheet.create({
   },
   sectionHeader: {
     padding: 5,
+    fontWeight: '500',
+    fontSize: 11,
   },
   group: {
     backgroundColor: 'white',
   },
-  sectionHeaderTitle: {
-    fontWeight: '500',
-    fontSize: 11,
-  },
   row: {
     backgroundColor: 'white',
     justifyContent: 'center',
diff --git a/Libraries/Text/TextStylePropTypes.js b/Libraries/Text/TextStylePropTypes.js
index edcf428396c7..3db900fd712a 100644
--- a/Libraries/Text/TextStylePropTypes.js
+++ b/Libraries/Text/TextStylePropTypes.js
@@ -70,19 +70,4 @@ var TextStylePropTypes = Object.assign(Object.create(ViewStylePropTypes), {
   ),
 });
 
-// Text doesn't support padding correctly (#4841912)
-var unsupportedProps = Object.keys({
-  padding: null,
-  paddingTop: null,
-  paddingLeft: null,
-  paddingRight: null,
-  paddingBottom: null,
-  paddingVertical: null,
-  paddingHorizontal: null,
-});
-
-for (var ii = 0; ii < unsupportedProps.length; ii++) {
-  delete TextStylePropTypes[unsupportedProps[ii]];
-}
-
 module.exports = TextStylePropTypes;

From 469bb7fbfd61af324a81d589145edfb8ae111f96 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Thu, 14 Jan 2016 10:01:39 -0800
Subject: [PATCH 0740/1411] Improve error wording when fail to launch debugger

Reviewed By: javache

Differential Revision: D2829484

fb-gh-sync-id: a3402ece1f5cd19e8408fa3ab89adf7a26c66de9
---
 Libraries/WebSocket/RCTWebSocketExecutor.m | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/Libraries/WebSocket/RCTWebSocketExecutor.m b/Libraries/WebSocket/RCTWebSocketExecutor.m
index e84539a73004..bc8d2b7fd88c 100644
--- a/Libraries/WebSocket/RCTWebSocketExecutor.m
+++ b/Libraries/WebSocket/RCTWebSocketExecutor.m
@@ -80,8 +80,9 @@ - (void)setUp
     retries--;
   }
   if (!runtimeIsReady) {
-    RCTLogError(@"Runtime is not ready. Make sure Chrome is running and not "
-                 "paused on a breakpoint or exception and try reloading again.");
+    RCTLogError(@"Runtime is not ready for debugging.\n "
+                 "- Make sure Packager server is running.\n"
+                 "- Make sure Chrome is running and not paused on a breakpoint or exception and try reloading again.");
     [self invalidate];
     return;
   }

From aeec3f3b818b03d7d941a254d9d5669dd42ded13 Mon Sep 17 00:00:00 2001
From: James Zhang <jamesfzhang@gmail.com>
Date: Thu, 14 Jan 2016 10:47:50 -0800
Subject: [PATCH 0741/1411] Add Jukebox app to showcase

---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 5dc731777e08..5e503d0a421d 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -258,6 +258,12 @@ var apps = [
     link: 'https://play.google.com/store/apps/details?id=com.hubhopper',
     author: 'Soch Technologies',
   },
+  {
+    name: 'Jukebox',
+    icon: 'https://s3.amazonaws.com/theartistunion-production/Jukebox-logo.png',
+    link: 'https://itunes.apple.com/us/app/jukebox-offline-music-player/id1072583255?ls=1&mt=8',
+    author: 'The Beat Drop Inc'
+  },
   {
     name: 'Kakapo',
     icon: 'http://a2.mzstatic.com/eu/r30/Purple3/v4/12/ab/2a/12ab2a01-3a3c-9482-b8df-ab38ad281165/icon175x175.png',

From 25c3dd140f4bd82991797c9e9cc95674dfc9a460 Mon Sep 17 00:00:00 2001
From: Andrei Coman <andreic@fb.com>
Date: Thu, 14 Jan 2016 11:41:10 -0800
Subject: [PATCH 0742/1411] Add phone-pad keyboard

Summary:
With the numeric keyboard now being an actual numeric keyboard (before
it was actually phone-pad), we need a proper phone-pad keyboard as well.

public

Reviewed By: dmmiller

Differential Revision: D2830707

fb-gh-sync-id: 80a1d314eac730e691de73a31342c014a2fa5ba6
---
 Examples/UIExplorer/TextInputExample.android.js               | 1 +
 Libraries/Components/TextInput/TextInput.js                   | 4 ++--
 .../facebook/react/views/textinput/ReactTextInputManager.java | 3 +++
 3 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/Examples/UIExplorer/TextInputExample.android.js b/Examples/UIExplorer/TextInputExample.android.js
index 31156b50d5f8..9bccf5256a83 100644
--- a/Examples/UIExplorer/TextInputExample.android.js
+++ b/Examples/UIExplorer/TextInputExample.android.js
@@ -242,6 +242,7 @@ exports.examples = [
         'default',
         'email-address',
         'numeric',
+        'phone-pad',
       ];
       var examples = keyboardTypes.map((type) => {
         return (
diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js
index 8d69fd589554..b029db359b03 100644
--- a/Libraries/Components/TextInput/TextInput.js
+++ b/Libraries/Components/TextInput/TextInput.js
@@ -134,14 +134,14 @@ var TextInput = React.createClass({
     keyboardType: PropTypes.oneOf([
       // Cross-platform
       'default',
-      'numeric',
       'email-address',
+      'numeric',
+      'phone-pad',
       // iOS-only
       'ascii-capable',
       'numbers-and-punctuation',
       'url',
       'number-pad',
-      'phone-pad',
       'name-phone-pad',
       'decimal-pad',
       'twitter',
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
index 9184c661763e..8b6396ff2bd5 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
@@ -60,6 +60,7 @@ public class ReactTextInputManager extends
 
   private static final String KEYBOARD_TYPE_EMAIL_ADDRESS = "email-address";
   private static final String KEYBOARD_TYPE_NUMERIC = "numeric";
+  private static final String KEYBOARD_TYPE_PHONE_PAD = "phone-pad";
   private static final InputFilter[] EMPTY_FILTERS = new InputFilter[0];
 
   @Override
@@ -278,6 +279,8 @@ public void setKeyboardType(ReactEditText view, @Nullable String keyboardType) {
       flagsToSet = INPUT_TYPE_KEYBOARD_NUMBERED;
     } else if (KEYBOARD_TYPE_EMAIL_ADDRESS.equalsIgnoreCase(keyboardType)) {
       flagsToSet = InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS | InputType.TYPE_CLASS_TEXT;
+    } else if (KEYBOARD_TYPE_PHONE_PAD.equalsIgnoreCase(keyboardType)) {
+      flagsToSet = InputType.TYPE_CLASS_PHONE;
     }
     updateStagedInputTypeFlag(
         view,

From 4074b7980e87df6b1b172e63b9fb64c6a0d526fa Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Thu, 14 Jan 2016 13:47:31 -0800
Subject: [PATCH 0743/1411] Cache all module data

Summary:
We used to only cache the `dependencies` and `name` of a Module but we were actually accessing two more fields (async dependencies and the `isHaste` field) which meant we were always reading every single file from disk. In D2644383 I noticed that but realized that the Promise was cached, meaning we would read every file once *per instance* and I didn't think about cross-instance reads over time. My initial version added more caching (but also missed the `isHaste` field) but then I got rid of the cache call for `dependencies`. So my change from before didn't make anything worse but it also didn't make anything better. This change now caches everything until the contents of the file actually changes.

public

Reviewed By: martinbigio

Differential Revision: D2831569

fb-gh-sync-id: 74081abc0ce3ca96b4e56c3c9b6d24aa84f7496c
---
 .../src/DependencyResolver/Module.js           | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/Module.js b/packager/react-packager/src/DependencyResolver/Module.js
index 3fcd63f08791..f6eb72beefc3 100644
--- a/packager/react-packager/src/DependencyResolver/Module.js
+++ b/packager/react-packager/src/DependencyResolver/Module.js
@@ -31,7 +31,11 @@ class Module {
   }
 
   isHaste() {
-    return this.read().then(data => !!data.id);
+    return this._cache.get(
+      this.path,
+      'isHaste',
+      () => this.read().then(data => !!data.id)
+    );
   }
 
   getName() {
@@ -67,11 +71,19 @@ class Module {
   }
 
   getDependencies() {
-    return this.read().then(data => data.dependencies);
+    return this._cache.get(
+      this.path,
+      'dependencies',
+      () => this.read().then(data => data.dependencies)
+    );
   }
 
   getAsyncDependencies() {
-    return this.read().then(data => data.asyncDependencies);
+    return this._cache.get(
+      this.path,
+      'asyncDependencies',
+      () => this.read().then(data => data.asyncDependencies)
+    );
   }
 
   invalidate() {

From e4c53c28aea7e067e48f5c8c0100c7cafc031b06 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 14 Jan 2016 14:03:31 -0800
Subject: [PATCH 0744/1411] Improved shadow performance

Summary:
public
React Native currently exposes the iOS layer shadow properties more-or-less directly, however there are a number of problems with this:

1) Performance when using these properties is poor by default. That's because iOS calculates the shadow by getting the exact pixel mask of the view, including any tranlucent content, and all of its subviews, which is very CPU and GPU-intensive.
2) The iOS shadow properties do not match the syntax or semantics of the CSS box-shadow standard, and are unlikely to be possible to implement on Android.
3) We don't expose the `layer.shadowPath` property, which is crucial to getting good performance out of layer shadows.

This diff solves problem number 1) by implementing a default `shadowPath` that matches the view border for views with an opaque background. This improves the performance of shadows by optimizing for the common usage case. I've also reinstated background color propagation for views which have shadow props - this should help ensure that this best-case scenario occurs more often.

For views with an explicit transparent background, the shadow will continue to work as it did before ( `shadowPath` will be left unset, and the shadow will be derived exactly from the pixels of the view and its subviews). This is the worst-case path for performance, however, so you should avoid it unless absolutely necessary. **Support for this may be disabled by default in future, or dropped altogether.**

For translucent images, it is suggested that you bake the shadow into the image itself, or use another mechanism to pre-generate the shadow. For text shadows, you should use the textShadow properties, which work cross-platform and have much better performance.

Problem number 2) will be solved in a future diff, possibly by renaming the iOS shadowXXX properties to boxShadowXXX, and changing the syntax and semantics to match the CSS standards.

Problem number 3) is now mostly moot, since we generate the shadowPath automatically. In future, we may provide an iOS-specific prop to set the path explicitly if there's a demand for more precise control of the shadow.

Reviewed By: weicool

Differential Revision: D2827581

fb-gh-sync-id: 853aa018e1d61d5f88304c6fc1b78f9d7e739804
---
 Examples/UIExplorer/BoxShadowExample.js       | 85 +++++++++++++++++++
 Examples/UIExplorer/UIExplorerList.ios.js     |  1 +
 .../Components/View/ShadowPropTypesIOS.js     | 42 +++++++++
 .../Components/View/ViewStylePropTypes.js     |  8 +-
 Libraries/Image/ImageStylePropTypes.js        |  2 +
 Libraries/Text/RCTShadowText.m                |  1 -
 Libraries/Text/RCTTextManager.m               |  1 -
 React/Views/RCTView.m                         | 59 +++++++++++--
 8 files changed, 183 insertions(+), 16 deletions(-)
 create mode 100644 Examples/UIExplorer/BoxShadowExample.js
 create mode 100644 Libraries/Components/View/ShadowPropTypesIOS.js

diff --git a/Examples/UIExplorer/BoxShadowExample.js b/Examples/UIExplorer/BoxShadowExample.js
new file mode 100644
index 000000000000..12568c1b67bc
--- /dev/null
+++ b/Examples/UIExplorer/BoxShadowExample.js
@@ -0,0 +1,85 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ */
+'use strict';
+
+var React = require('react-native');
+var {
+  Image,
+  StyleSheet,
+  View
+} = React;
+
+var styles = StyleSheet.create({
+  box: {
+    width: 100,
+    height: 100,
+    borderWidth: 2,
+  },
+  shadow1: {
+    shadowOpacity: 0.5,
+    shadowRadius: 3,
+    shadowOffset: {width: 2, height: 2},
+  },
+  shadow2: {
+    shadowOpacity: 1.0,
+    shadowColor: 'red',
+    shadowRadius: 0,
+    shadowOffset: {width: 3, height: 3},
+  },
+});
+
+exports.title = 'Box Shadow';
+exports.description = 'Demonstrates some of the shadow styles available to Views.';
+exports.examples = [
+  {
+    title: 'Basic shadow',
+    description: 'shadowOpacity: 0.5, shadowOffset: {2, 2}',
+    render() {
+      return <View style={[styles.box, styles.shadow1]} />;
+    }
+  },
+  {
+    title: 'Colored shadow',
+    description: 'shadowColor: \'red\', shadowRadius: 0',
+    render() {
+      return <View style={[styles.box, styles.shadow2]} />;
+    }
+  },
+  {
+    title: 'Shaped shadow',
+    description: 'borderRadius: 50',
+    render() {
+      return <View style={[styles.box, styles.shadow1, {borderRadius: 50}]} />;
+    }
+  },
+  {
+    title: 'Image shadow',
+    description: 'Image shadows are derived exactly from the pixels.',
+    render() {
+      return <Image
+        source={require('./hawk.png')}
+        style={[styles.box, styles.shadow1, {borderWidth: 0, overflow: 'visible'}]}
+      />;
+    }
+  },
+  {
+    title: 'Child shadow',
+    description: 'For views without an opaque background color, shadow will be derived from the subviews.',
+    render() {
+      return <View style={[styles.box, styles.shadow1, {backgroundColor: 'transparent'}]}>
+        <View style={[styles.box, {width: 80, height: 80, borderRadius: 40, margin: 8, backgroundColor: 'red'}]}/>
+      </View>;
+    }
+  },
+];
diff --git a/Examples/UIExplorer/UIExplorerList.ios.js b/Examples/UIExplorer/UIExplorerList.ios.js
index 0c1e9e2e7153..92f0f0bad1b8 100644
--- a/Examples/UIExplorer/UIExplorerList.ios.js
+++ b/Examples/UIExplorer/UIExplorerList.ios.js
@@ -66,6 +66,7 @@ var APIS = [
   require('./AppStateIOSExample'),
   require('./AsyncStorageExample'),
   require('./BorderExample'),
+  require('./BoxShadowExample'),
   require('./CameraRollExample'),
   require('./ClipboardExample'),
   require('./GeolocationExample'),
diff --git a/Libraries/Components/View/ShadowPropTypesIOS.js b/Libraries/Components/View/ShadowPropTypesIOS.js
new file mode 100644
index 000000000000..c770ca9ed267
--- /dev/null
+++ b/Libraries/Components/View/ShadowPropTypesIOS.js
@@ -0,0 +1,42 @@
+/**
+ * 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 ShadowPropTypesIOS
+ * @flow
+ */
+'use strict';
+
+var ColorPropType = require('ColorPropType');
+var ReactPropTypes = require('ReactPropTypes');
+
+var ShadowPropTypesIOS = {
+  /**
+   * Sets the drop shadow color
+   * @platform ios
+   */
+  shadowColor: ColorPropType,
+  /**
+   * Sets the drop shadow offset
+   * @platform ios
+   */
+  shadowOffset: ReactPropTypes.shape(
+    {width: ReactPropTypes.number, height: ReactPropTypes.number}
+  ),
+  /**
+   * Sets the drop shadow opacity (multiplied by the color's alpha component)
+   * @platform ios
+   */
+  shadowOpacity: ReactPropTypes.number,
+  /**
+   * Sets the drop shadow blur radius
+   * @platform ios
+   */
+  shadowRadius: ReactPropTypes.number,
+};
+
+module.exports = ShadowPropTypesIOS;
diff --git a/Libraries/Components/View/ViewStylePropTypes.js b/Libraries/Components/View/ViewStylePropTypes.js
index cb193be1e9cf..619df34c8d96 100644
--- a/Libraries/Components/View/ViewStylePropTypes.js
+++ b/Libraries/Components/View/ViewStylePropTypes.js
@@ -14,6 +14,7 @@
 var LayoutPropTypes = require('LayoutPropTypes');
 var ReactPropTypes = require('ReactPropTypes');
 var ColorPropType = require('ColorPropType');
+var ShadowPropTypesIOS = require('ShadowPropTypesIOS');
 var TransformPropTypes = require('TransformPropTypes');
 
 /**
@@ -21,6 +22,7 @@ var TransformPropTypes = require('TransformPropTypes');
  */
 var ViewStylePropTypes = {
   ...LayoutPropTypes,
+  ...ShadowPropTypesIOS,
   ...TransformPropTypes,
   backfaceVisibility: ReactPropTypes.oneOf(['visible', 'hidden']),
   backgroundColor: ColorPropType,
@@ -42,12 +44,6 @@ var ViewStylePropTypes = {
   borderLeftWidth: ReactPropTypes.number,
   opacity: ReactPropTypes.number,
   overflow: ReactPropTypes.oneOf(['visible', 'hidden']),
-  shadowColor: ColorPropType,
-  shadowOffset: ReactPropTypes.shape(
-    {width: ReactPropTypes.number, height: ReactPropTypes.number}
-  ),
-  shadowOpacity: ReactPropTypes.number,
-  shadowRadius: ReactPropTypes.number,
   /**
    * (Android-only) Sets the elevation of a view, using Android's underlying
    * [elevation API](https://developer.android.com/training/material/shadows-clipping.html#Elevation).
diff --git a/Libraries/Image/ImageStylePropTypes.js b/Libraries/Image/ImageStylePropTypes.js
index ec806b1b85cb..5e99a54b08c0 100644
--- a/Libraries/Image/ImageStylePropTypes.js
+++ b/Libraries/Image/ImageStylePropTypes.js
@@ -15,10 +15,12 @@ var ImageResizeMode = require('ImageResizeMode');
 var LayoutPropTypes = require('LayoutPropTypes');
 var ReactPropTypes = require('ReactPropTypes');
 var ColorPropType = require('ColorPropType');
+var ShadowPropTypesIOS = require('ShadowPropTypesIOS');
 var TransformPropTypes = require('TransformPropTypes');
 
 var ImageStylePropTypes = {
   ...LayoutPropTypes,
+  ...ShadowPropTypesIOS,
   ...TransformPropTypes,
   resizeMode: ReactPropTypes.oneOf(Object.keys(ImageResizeMode)),
   backfaceVisibility: ReactPropTypes.oneOf(['visible', 'hidden']),
diff --git a/Libraries/Text/RCTShadowText.m b/Libraries/Text/RCTShadowText.m
index 4d4380d428d1..eebbc9c32b98 100644
--- a/Libraries/Text/RCTShadowText.m
+++ b/Libraries/Text/RCTShadowText.m
@@ -373,7 +373,6 @@ - (void)set##setProp:(type)value;              \
 RCT_TEXT_PROPERTY(LetterSpacing, _letterSpacing, CGFloat)
 RCT_TEXT_PROPERTY(LineHeight, _lineHeight, CGFloat)
 RCT_TEXT_PROPERTY(NumberOfLines, _numberOfLines, NSUInteger)
-RCT_TEXT_PROPERTY(ShadowOffset, _shadowOffset, CGSize)
 RCT_TEXT_PROPERTY(TextAlign, _textAlign, NSTextAlignment)
 RCT_TEXT_PROPERTY(TextDecorationColor, _textDecorationColor, UIColor *);
 RCT_TEXT_PROPERTY(TextDecorationLine, _textDecorationLine, RCTTextDecorationLineType);
diff --git a/Libraries/Text/RCTTextManager.m b/Libraries/Text/RCTTextManager.m
index 7a28ab92875f..2a7e4d98b472 100644
--- a/Libraries/Text/RCTTextManager.m
+++ b/Libraries/Text/RCTTextManager.m
@@ -51,7 +51,6 @@ - (RCTShadowView *)shadowView
 RCT_EXPORT_SHADOW_PROPERTY(letterSpacing, CGFloat)
 RCT_EXPORT_SHADOW_PROPERTY(lineHeight, CGFloat)
 RCT_EXPORT_SHADOW_PROPERTY(numberOfLines, NSUInteger)
-RCT_EXPORT_SHADOW_PROPERTY(shadowOffset, CGSize)
 RCT_EXPORT_SHADOW_PROPERTY(textAlign, NSTextAlignment)
 RCT_EXPORT_SHADOW_PROPERTY(textDecorationStyle, NSUnderlineStyle)
 RCT_EXPORT_SHADOW_PROPERTY(textDecorationColor, UIColor)
diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m
index 7c773691eeb1..010c62c49293 100644
--- a/React/Views/RCTView.m
+++ b/React/Views/RCTView.m
@@ -515,8 +515,11 @@ - (void)reactSetFrame:(CGRect)frame
   // If frame is zero, or below the threshold where the border radii can
   // be rendered as a stretchable image, we'll need to re-render.
   // TODO: detect up-front if re-rendering is necessary
+  CGSize oldSize = self.bounds.size;
   [super reactSetFrame:frame];
-  [self.layer setNeedsDisplay];
+  if (!CGSizeEqualToSize(self.bounds.size, oldSize)) {
+    [self.layer setNeedsDisplay];
+  }
 }
 
 - (void)displayLayer:(CALayer *)layer
@@ -525,6 +528,8 @@ - (void)displayLayer:(CALayer *)layer
     return;
   }
 
+  RCTUpdateShadowPathForView(self);
+
   const RCTCornerRadii cornerRadii = [self cornerRadii];
   const UIEdgeInsets borderInsets = [self bordersAsInsets];
   const RCTBorderColors borderColors = [self borderColors];
@@ -608,6 +613,44 @@ - (void)displayLayer:(CALayer *)layer
   [self updateClippingForLayer:layer];
 }
 
+static BOOL RCTLayerHasShadow(CALayer *layer)
+{
+  return layer.shadowOpacity * CGColorGetAlpha(layer.shadowColor) > 0;
+}
+
+- (void)reactSetInheritedBackgroundColor:(UIColor *)inheritedBackgroundColor
+{
+  // Inherit background color if a shadow has been set, as an optimization
+  if (RCTLayerHasShadow(self.layer)) {
+    self.backgroundColor = inheritedBackgroundColor;
+  }
+}
+
+static void RCTUpdateShadowPathForView(RCTView *view)
+{
+  if (RCTLayerHasShadow(view.layer)) {
+    if (CGColorGetAlpha(view.backgroundColor.CGColor) > 0.999) {
+
+      // If view has a solid background color, calculate shadow path from border
+      const RCTCornerRadii cornerRadii = [view cornerRadii];
+      const RCTCornerInsets cornerInsets = RCTGetCornerInsets(cornerRadii, UIEdgeInsetsZero);
+      CGPathRef shadowPath = RCTPathCreateWithRoundedRect(view.bounds, cornerInsets, NULL);
+      view.layer.shadowPath = shadowPath;
+      CGPathRelease(shadowPath);
+
+    } else {
+
+      // Can't accurately calculate box shadow, so fall back to pixel-based shadow
+      view.layer.shadowPath = nil;
+
+      RCTLogWarn(@"View #%@ of type %@ has a shadow set but cannot calculate "
+                 "shadow efficiently. Consider setting a background color to "
+                 "fix this, or apply the shadow to a more specific component.",
+                 view.reactTag, [view class]);
+    }
+  }
+}
+
 - (void)updateClippingForLayer:(CALayer *)layer
 {
   CALayer *mask = nil;
@@ -691,14 +734,14 @@ - (void)setBorder##side##Radius:(CGFloat)radius \
 
 #pragma mark - Border Style
 
-#define setBorderStyle(side)                                   \
+#define setBorderStyle(side)                           \
   - (void)setBorder##side##Style:(RCTBorderStyle)style \
-  {                                                            \
-    if (_border##side##Style == style) {                       \
-      return;                                                  \
-    }                                                          \
-    _border##side##Style = style;                              \
-    [self.layer setNeedsDisplay];                              \
+  {                                                    \
+    if (_border##side##Style == style) {               \
+      return;                                          \
+    }                                                  \
+    _border##side##Style = style;                      \
+    [self.layer setNeedsDisplay];                      \
   }
 
 setBorderStyle()

From 66158ab2bf35dd3e4740ae444163f982305e0c10 Mon Sep 17 00:00:00 2001
From: Philipp von Weitershausen <philikon@silklabs.com>
Date: Thu, 14 Jan 2016 16:12:27 -0800
Subject: [PATCH 0745/1411] Make the RCTSRWebSocketDelegate protocol part of
 RCTWebSocketModule public

Summary:
This allows consumers to subclass and extend `RCTWebSocketModule` and make use of the `RCTSRWebSocketDelegate` methods.

The use case here is to do some pre-processing of WebSocket data before handing it off to JS. Consumers could that in the following way:

```

interface MyWebSocketModule : RCTWebSocketModule
end

implementation MyWebSocketModule

// Don't use RCT_EXPORT_MODULE macro for this so we replace the existing RCTWebSocketModule.
+ (NSString *)moduleName { return @"RCTWebSocketModule"; }

RCT_EXTERN_METHOD(connect:(NSURL *)URL socketID:(nonnull NSNumber *)socketID)
RCT_EXTERN_METHOD(send:(NSString *)message socketID:(nonnull NSNumber *)socketID)
RCT_EXTERN_METHOD(close:(nonnull NSNumber *)socketID)

- (void)webSocket:(RCTSRWebSocket *)webSocket didReceiveMessage:(id)message
{
  [super webSocket:webSocket didReceiveMessage:[DoSomethingWith message]];
}

end
```

... and then returning a `MyWebSocketModule` ins
Closes https://github.com/facebook/react-native/pull/5321

Reviewed By: svcscm

Differential Revision: D2832374

Pulled By: nicklockwood

fb-gh-sync-id: f208516b2b2f76276223ffc972871d96afe87e27
---
 Libraries/WebSocket/RCTWebSocketModule.h | 3 ++-
 Libraries/WebSocket/RCTWebSocketModule.m | 5 -----
 2 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/Libraries/WebSocket/RCTWebSocketModule.h b/Libraries/WebSocket/RCTWebSocketModule.h
index ee176a9f246d..082122e00248 100644
--- a/Libraries/WebSocket/RCTWebSocketModule.h
+++ b/Libraries/WebSocket/RCTWebSocketModule.h
@@ -8,7 +8,8 @@
  */
 
 #import "RCTBridgeModule.h"
+#import "RCTSRWebSocket.h"
 
-@interface RCTWebSocketModule : NSObject <RCTBridgeModule>
+@interface RCTWebSocketModule : NSObject <RCTBridgeModule, RCTSRWebSocketDelegate>
 
 @end
diff --git a/Libraries/WebSocket/RCTWebSocketModule.m b/Libraries/WebSocket/RCTWebSocketModule.m
index 7afa7dace773..e16f3067c9d8 100644
--- a/Libraries/WebSocket/RCTWebSocketModule.m
+++ b/Libraries/WebSocket/RCTWebSocketModule.m
@@ -11,7 +11,6 @@
 
 #import "RCTBridge.h"
 #import "RCTEventDispatcher.h"
-#import "RCTSRWebSocket.h"
 #import "RCTUtils.h"
 
 @implementation RCTSRWebSocket (React)
@@ -28,10 +27,6 @@ - (void)setReactTag:(NSNumber *)reactTag
 
 @end
 
-@interface RCTWebSocketModule () <RCTSRWebSocketDelegate>
-
-@end
-
 @implementation RCTWebSocketModule
 {
     NSMutableDictionary<NSNumber *, RCTSRWebSocket *> *_sockets;

From 0185df57bdd21e89d3ce548bbb740e124e7331bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Thu, 14 Jan 2016 19:32:16 -0800
Subject: [PATCH 0746/1411] Tweak Hot Loading gating code

Reviewed By: mmahoney

Differential Revision: D2815537

fb-gh-sync-id: d0a4d5c2a831c52cf3be6051a348ae9ba996f545
---
 React/Modules/RCTDevMenu.m | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/React/Modules/RCTDevMenu.m b/React/Modules/RCTDevMenu.m
index 23f2184f4594..a9e92e6cf30e 100644
--- a/React/Modules/RCTDevMenu.m
+++ b/React/Modules/RCTDevMenu.m
@@ -531,7 +531,9 @@ - (void)setLiveReloadEnabled:(BOOL)enabled
 
 - (BOOL)hotLoadingAvailable
 {
-  return false;
+  return !_bridge.bundleURL.fileURL // Only works when running from server
+  && [_bridge.delegate respondsToSelector:@selector(bridgeSupportsHotLoading:)]
+  && [_bridge.delegate bridgeSupportsHotLoading:_bridge];
 }
 
 - (void)setHotLoadingEnabled:(BOOL)enabled

From bba35f0415fa6868e4ce6744e4d044d60cb8a041 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Thu, 14 Jan 2016 19:32:17 -0800
Subject: [PATCH 0747/1411] Make Hot Loading work on OSS

Summary:
public

- Tweak OSS server to enable the HMR connection
- Remove client gating code.
- Resolve internal transforms plugins

After this diff, Hot Loading should work on OSS.

Reviewed By: javache

Differential Revision: D2803620

fb-gh-sync-id: b678180c884d2bfaf454edf9e7abe6b3b3b32ebe
---
 local-cli/server/runServer.js                 | 14 ++++++--
 .../src/JSTransformer/resolvePlugins.js       | 32 +++++++++++++++++++
 .../src/JSTransformer/worker.js               |  3 +-
 packager/transformer.js                       | 19 ++---------
 4 files changed, 47 insertions(+), 21 deletions(-)
 create mode 100644 packager/react-packager/src/JSTransformer/resolvePlugins.js

diff --git a/local-cli/server/runServer.js b/local-cli/server/runServer.js
index b4a690f4c170..c3a39a15a9d1 100644
--- a/local-cli/server/runServer.js
+++ b/local-cli/server/runServer.js
@@ -8,6 +8,7 @@
  */
 'use strict';
 
+const attachHMRServer = require('./util/attachHMRServer');
 const connect = require('connect');
 const cpuProfilerMiddleware = require('./middleware/cpuProfilerMiddleware');
 const getDevToolsMiddleware = require('./middleware/getDevToolsMiddleware');
@@ -23,6 +24,7 @@ const webSocketProxy = require('./util/webSocketProxy.js');
 
 function runServer(args, config, readyCallback) {
   var wsProxy = null;
+  const packagerServer = getPackagerServer(args, config);
   const app = connect()
     .use(loadRawBodyMiddleware)
     .use(connect.compress())
@@ -33,7 +35,7 @@ function runServer(args, config, readyCallback) {
     .use(cpuProfilerMiddleware)
     // Temporarily disable flow check until it's more stable
     //.use(getFlowTypeCheckMiddleware(args))
-    .use(getAppMiddleware(args, config));
+    .use(packagerServer.processRequest.bind(packagerServer));
 
   args.projectRoots.forEach(root => app.use(connect.static(root)));
 
@@ -44,6 +46,12 @@ function runServer(args, config, readyCallback) {
     args.port,
     '::',
     function() {
+      attachHMRServer({
+        httpServer: serverInstance,
+        path: '/hot',
+        packagerServer,
+      });
+
       wsProxy = webSocketProxy.attachToServer(serverInstance, '/debugger-proxy');
       webSocketProxy.attachToServer(serverInstance, '/devtools');
       readyCallback();
@@ -55,13 +63,13 @@ function runServer(args, config, readyCallback) {
   serverInstance.timeout = 0;
 }
 
-function getAppMiddleware(args, config) {
+function getPackagerServer(args, config) {
   let transformerPath = args.transformer;
   if (!isAbsolutePath(transformerPath)) {
     transformerPath = path.resolve(process.cwd(), transformerPath);
   }
 
-  return ReactPackager.middleware({
+  return ReactPackager.createServer({
     nonPersistent: args.nonPersistent,
     projectRoots: args.projectRoots,
     blacklistRE: config.getBlacklistRE(),
diff --git a/packager/react-packager/src/JSTransformer/resolvePlugins.js b/packager/react-packager/src/JSTransformer/resolvePlugins.js
new file mode 100644
index 000000000000..742ea0a78a15
--- /dev/null
+++ b/packager/react-packager/src/JSTransformer/resolvePlugins.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.
+ */
+'use strict';
+
+/**
+ * Manually resolve all default Babel plugins.
+ * `babel.transform` will attempt to resolve all base plugins relative to
+ * the file it's compiling. This makes sure that we're using the plugins
+ * installed in the react-native package.
+ */
+function resolvePlugins(plugins) {
+  return plugins.map(function(plugin) {
+    // Normalise plugin to an array.
+    if (!Array.isArray(plugin)) {
+      plugin = [plugin];
+    }
+    // Only resolve the plugin if it's a string reference.
+    if (typeof plugin[0] === 'string') {
+      plugin[0] = require('babel-plugin-' + plugin[0]);
+      plugin[0] = plugin[0].__esModule ? plugin[0].default : plugin[0];
+    }
+    return plugin;
+  });
+}
+
+module.exports = resolvePlugins;
diff --git a/packager/react-packager/src/JSTransformer/worker.js b/packager/react-packager/src/JSTransformer/worker.js
index 27542274a370..b33b4ae51869 100644
--- a/packager/react-packager/src/JSTransformer/worker.js
+++ b/packager/react-packager/src/JSTransformer/worker.js
@@ -9,13 +9,14 @@
 'use strict';
 
 var babel = require('babel-core');
+var resolvePlugins = require('./resolvePlugins');
 var Transforms = require('../transforms');
 
 // Runs internal transforms on the given sourceCode. Note that internal
 // transforms should be run after the external ones to ensure that they run on
 // Javascript code
 function internalTransforms(sourceCode, filename, options) {
-  var plugins = Transforms.getAll(options);
+  var plugins = resolvePlugins(Transforms.getAll(options));
   if (plugins.length === 0) {
     return {
       code: sourceCode,
diff --git a/packager/transformer.js b/packager/transformer.js
index 8a178c86997c..df6009bd7f81 100644
--- a/packager/transformer.js
+++ b/packager/transformer.js
@@ -16,6 +16,7 @@ const inlineRequires = require('fbjs-scripts/babel-6/inline-requires');
 const json5 = require('json5');
 const path = require('path');
 const ReactPackager = require('./react-packager');
+const resolvePlugins = require('./react-packager/src/JSTransformer/resolvePlugins');
 
 const babelRC =
   json5.parse(
@@ -36,23 +37,7 @@ function transform(src, filename, options) {
   if (options.inlineRequires) {
     extraPlugins.push(inlineRequires);
   }
-  config.plugins = extraPlugins.concat(config.plugins);
-
-  // Manually resolve all default Babel plugins. babel.transform will attempt to resolve
-  // all base plugins relative to the file it's compiling. This makes sure that we're
-  // using the plugins installed in the react-native package.
-  config.plugins = config.plugins.map(function(plugin) {
-    // Normalise plugin to an array.
-    if (!Array.isArray(plugin)) {
-      plugin = [plugin];
-    }
-    // Only resolve the plugin if it's a string reference.
-    if (typeof plugin[0] === 'string') {
-      plugin[0] = require(`babel-plugin-${plugin[0]}`);
-      plugin[0] = plugin[0].__esModule ? plugin[0].default : plugin[0];
-    }
-    return plugin;
-  });
+  config.plugins = resolvePlugins(extraPlugins.concat(config.plugins));
 
   const result = babel.transform(src, Object.assign({}, babelRC, config));
 

From 538307d179d98e38e263cadfc3655e536b7bdfab Mon Sep 17 00:00:00 2001
From: scott <cgyqqcgy@gmail.com>
Date: Thu, 14 Jan 2016 15:37:27 +0800
Subject: [PATCH 0748/1411] add nzaom app

change the key to `link `

format code stuff

format code stuff
---
 website/src/react-native/showcase.js | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 5e503d0a421d..09da35e12813 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -502,11 +502,17 @@ var apps = [
     author: 'Melih Mucuk',
   },
   {
-    name:'天才段子手',
-    icon:'http://pp.myapp.com/ma_icon/0/icon_12236104_1451810987/96',
+    name: '天才段子手',
+    icon: 'http://pp.myapp.com/ma_icon/0/icon_12236104_1451810987/96',
     linkAppStore: 'https://itunes.apple.com/us/app/tian-cai-duan-zi-shou-shen/id992312701?l=zh&ls=1&mt=8',
     linkPlayStore: 'https://play.google.com/store/apps/details?id=com.geniusJokeWriter.app',
-    author:'Ran Zhao&Ji Zhao'
+    author: 'Ran Zhao&Ji Zhao'
+  },
+  {
+    name: '你造么',
+    icon: 'http://7xk1ez.com2.z0.glb.qiniucdn.com/logo-mobile-0114logo_welcom.png',
+    link: 'https://itunes.apple.com/us/app/ni-zao-me/id1025294933?l=zh&ls=1&mt=8',
+    author: 'Scott Chen(@NZAOM)'
   }
 ];
 

From cd89016ee7168bb6971f800779e0878e9a70206f Mon Sep 17 00:00:00 2001
From: Kyle Corbitt <kyle@corbt.com>
Date: Fri, 15 Jan 2016 05:14:27 -0800
Subject: [PATCH 0749/1411] PixelRatio.pixel()

Summary:
This implements #5073. It adds a static method `PixelRatio.pixel()` which returns the smallest drawable line width, primarily for use in styles.

It also updates the example apps to use the new function.
Closes https://github.com/facebook/react-native/pull/5076

Reviewed By: svcscm

Differential Revision: D2799849

Pulled By: nicklockwood

fb-gh-sync-id: b83a77790601fe882affbf65531114e7c5cf4bdf
---
 Examples/Movies/MovieCell.js                  |  4 +-
 Examples/Movies/MovieScreen.js                |  3 +-
 .../Navigator/BreadcrumbNavSample.js          |  3 +-
 .../UIExplorer/Navigator/JumpingNavSample.js  |  3 +-
 .../Navigator/NavigationBarSample.js          |  3 +-
 .../UIExplorer/Navigator/NavigatorExample.js  |  3 +-
 Examples/UIExplorer/NavigatorIOSExample.js    |  5 +--
 Examples/UIExplorer/TouchableExample.js       |  4 +-
 Examples/UIExplorer/UIExplorerListBase.js     |  3 +-
 Examples/UIExplorer/XHRExample.android.js     |  3 +-
 Examples/UIExplorer/XHRExample.ios.js         |  3 +-
 Libraries/StyleSheet/StyleSheet.js            | 44 ++++++++++++++-----
 Libraries/Utilities/PixelRatio.js             | 25 +++++------
 React/Views/UIView+React.m                    |  2 +-
 .../src/Resolver/__tests__/Resolver-test.js   |  1 +
 15 files changed, 60 insertions(+), 49 deletions(-)

diff --git a/Examples/Movies/MovieCell.js b/Examples/Movies/MovieCell.js
index 62062cb2af22..c90931c08768 100644
--- a/Examples/Movies/MovieCell.js
+++ b/Examples/Movies/MovieCell.js
@@ -18,7 +18,6 @@
 var React = require('react-native');
 var {
   Image,
-  PixelRatio,
   Platform,
   StyleSheet,
   Text,
@@ -99,8 +98,7 @@ var styles = StyleSheet.create({
   },
   cellBorder: {
     backgroundColor: 'rgba(0, 0, 0, 0.1)',
-    // Trick to get the thinest line the device can display
-    height: 1 / PixelRatio.get(),
+    height: StyleSheet.hairlineWidth,
     marginLeft: 4,
   },
 });
diff --git a/Examples/Movies/MovieScreen.js b/Examples/Movies/MovieScreen.js
index 09d6544dff59..ff228a8a3e7c 100644
--- a/Examples/Movies/MovieScreen.js
+++ b/Examples/Movies/MovieScreen.js
@@ -18,7 +18,6 @@
 var React = require('react-native');
 var {
   Image,
-  PixelRatio,
   ScrollView,
   StyleSheet,
   Text,
@@ -152,7 +151,7 @@ var styles = StyleSheet.create({
   },
   separator: {
     backgroundColor: 'rgba(0, 0, 0, 0.1)',
-    height: 1 / PixelRatio.get(),
+    height: StyleSheet.hairlineWidth,
     marginVertical: 10,
   },
   castTitle: {
diff --git a/Examples/UIExplorer/Navigator/BreadcrumbNavSample.js b/Examples/UIExplorer/Navigator/BreadcrumbNavSample.js
index 62196e5f2f4d..e05a8c39e839 100644
--- a/Examples/UIExplorer/Navigator/BreadcrumbNavSample.js
+++ b/Examples/UIExplorer/Navigator/BreadcrumbNavSample.js
@@ -15,7 +15,6 @@
 
 var React = require('react-native');
 var {
-  PixelRatio,
   Navigator,
   StyleSheet,
   ScrollView,
@@ -131,7 +130,7 @@ var styles = StyleSheet.create({
   button: {
     backgroundColor: 'white',
     padding: 15,
-    borderBottomWidth: 1 / PixelRatio.get(),
+    borderBottomWidth: StyleSheet.hairlineWidth,
     borderBottomColor: '#CDCDCD',
   },
   buttonText: {
diff --git a/Examples/UIExplorer/Navigator/JumpingNavSample.js b/Examples/UIExplorer/Navigator/JumpingNavSample.js
index eecabcbce9ca..54fe312c2202 100644
--- a/Examples/UIExplorer/Navigator/JumpingNavSample.js
+++ b/Examples/UIExplorer/Navigator/JumpingNavSample.js
@@ -16,7 +16,6 @@
 var React = require('react-native');
 var {
   Navigator,
-  PixelRatio,
   StyleSheet,
   ScrollView,
   TabBarIOS,
@@ -185,7 +184,7 @@ var styles = StyleSheet.create({
   button: {
     backgroundColor: 'white',
     padding: 15,
-    borderBottomWidth: 1 / PixelRatio.get(),
+    borderBottomWidth: StyleSheet.hairlineWidth,
     borderBottomColor: '#CDCDCD',
   },
   buttonText: {
diff --git a/Examples/UIExplorer/Navigator/NavigationBarSample.js b/Examples/UIExplorer/Navigator/NavigationBarSample.js
index 77e0740028a7..25f45f0ab303 100644
--- a/Examples/UIExplorer/Navigator/NavigationBarSample.js
+++ b/Examples/UIExplorer/Navigator/NavigationBarSample.js
@@ -16,7 +16,6 @@
 
 var React = require('react-native');
 var {
-  PixelRatio,
   Navigator,
   ScrollView,
   StyleSheet,
@@ -164,7 +163,7 @@ var styles = StyleSheet.create({
   button: {
     backgroundColor: 'white',
     padding: 15,
-    borderBottomWidth: 1 / PixelRatio.get(),
+    borderBottomWidth: StyleSheet.hairlineWidth,
     borderBottomColor: '#CDCDCD',
   },
   buttonText: {
diff --git a/Examples/UIExplorer/Navigator/NavigatorExample.js b/Examples/UIExplorer/Navigator/NavigatorExample.js
index aa156410933c..d15939886f06 100644
--- a/Examples/UIExplorer/Navigator/NavigatorExample.js
+++ b/Examples/UIExplorer/Navigator/NavigatorExample.js
@@ -16,7 +16,6 @@
 var React = require('react-native');
 var {
   Navigator,
-  PixelRatio,
   ScrollView,
   StyleSheet,
   Text,
@@ -190,7 +189,7 @@ var styles = StyleSheet.create({
   button: {
     backgroundColor: 'white',
     padding: 15,
-    borderBottomWidth: 1 / PixelRatio.get(),
+    borderBottomWidth: StyleSheet.hairlineWidth,
     borderBottomColor: '#CDCDCD',
   },
   buttonText: {
diff --git a/Examples/UIExplorer/NavigatorIOSExample.js b/Examples/UIExplorer/NavigatorIOSExample.js
index 4a2011a65461..08d227c3f0a0 100644
--- a/Examples/UIExplorer/NavigatorIOSExample.js
+++ b/Examples/UIExplorer/NavigatorIOSExample.js
@@ -20,7 +20,6 @@ var ViewExample = require('./ViewExample');
 var createExamplePage = require('./createExamplePage');
 var {
   AlertIOS,
-  PixelRatio,
   ScrollView,
   StyleSheet,
   Text,
@@ -227,7 +226,7 @@ var styles = StyleSheet.create({
   },
   line: {
     backgroundColor: '#bbbbbb',
-    height: 1 / PixelRatio.get(),
+    height: StyleSheet.hairlineWidth,
   },
   row: {
     backgroundColor: 'white',
@@ -236,7 +235,7 @@ var styles = StyleSheet.create({
     paddingVertical: 15,
   },
   separator: {
-    height: 1 / PixelRatio.get(),
+    height: StyleSheet.hairlineWidth,
     backgroundColor: '#bbbbbb',
     marginLeft: 15,
   },
diff --git a/Examples/UIExplorer/TouchableExample.js b/Examples/UIExplorer/TouchableExample.js
index f8ced267db8a..7b0bf2c0b333 100644
--- a/Examples/UIExplorer/TouchableExample.js
+++ b/Examples/UIExplorer/TouchableExample.js
@@ -229,7 +229,7 @@ var styles = StyleSheet.create({
   logBox: {
     padding: 20,
     margin: 10,
-    borderWidth: 1 / PixelRatio.get(),
+    borderWidth: StyleSheet.hairlineWidth,
     borderColor: '#f0f0f0',
     backgroundColor: '#f9f9f9',
   },
@@ -237,7 +237,7 @@ var styles = StyleSheet.create({
     padding: 10,
     margin: 10,
     height: 120,
-    borderWidth: 1 / PixelRatio.get(),
+    borderWidth: StyleSheet.hairlineWidth,
     borderColor: '#f0f0f0',
     backgroundColor: '#f9f9f9',
   },
diff --git a/Examples/UIExplorer/UIExplorerListBase.js b/Examples/UIExplorer/UIExplorerListBase.js
index b4af76e60ed5..17ecd8dc2c02 100644
--- a/Examples/UIExplorer/UIExplorerListBase.js
+++ b/Examples/UIExplorer/UIExplorerListBase.js
@@ -18,7 +18,6 @@
 var React = require('react-native');
 var {
   ListView,
-  PixelRatio,
   StyleSheet,
   Text,
   TextInput,
@@ -159,7 +158,7 @@ var styles = StyleSheet.create({
     paddingVertical: 8,
   },
   separator: {
-    height: 1 / PixelRatio.get(),
+    height: StyleSheet.hairlineWidth,
     backgroundColor: '#bbbbbb',
     marginLeft: 15,
   },
diff --git a/Examples/UIExplorer/XHRExample.android.js b/Examples/UIExplorer/XHRExample.android.js
index 5a46d8dd9751..55b1a51787c8 100644
--- a/Examples/UIExplorer/XHRExample.android.js
+++ b/Examples/UIExplorer/XHRExample.android.js
@@ -17,7 +17,6 @@
 
 var React = require('react-native');
 var {
-  PixelRatio,
   ProgressBarAndroid,
   StyleSheet,
   Text,
@@ -312,7 +311,7 @@ var styles = StyleSheet.create({
     flexDirection: 'row',
     paddingVertical: 8,
     alignItems: 'center',
-    borderBottomWidth: 1 / PixelRatio.get(),
+    borderBottomWidth: StyleSheet.hairlineWidth,
     borderBottomColor: 'grey',
   },
   textButton: {
diff --git a/Examples/UIExplorer/XHRExample.ios.js b/Examples/UIExplorer/XHRExample.ios.js
index d8d370319aa8..5d909b3cb7e2 100644
--- a/Examples/UIExplorer/XHRExample.ios.js
+++ b/Examples/UIExplorer/XHRExample.ios.js
@@ -21,7 +21,6 @@ var {
   CameraRoll,
   Image,
   LinkingIOS,
-  PixelRatio,
   ProgressViewIOS,
   StyleSheet,
   Text,
@@ -343,7 +342,7 @@ var styles = StyleSheet.create({
     flexDirection: 'row',
     paddingVertical: 8,
     alignItems: 'center',
-    borderBottomWidth: 1 / PixelRatio.get(),
+    borderBottomWidth: StyleSheet.hairlineWidth,
     borderBottomColor: 'grey',
   },
   photoLabel: {
diff --git a/Libraries/StyleSheet/StyleSheet.js b/Libraries/StyleSheet/StyleSheet.js
index aa997b0a4884..5774d2663b85 100644
--- a/Libraries/StyleSheet/StyleSheet.js
+++ b/Libraries/StyleSheet/StyleSheet.js
@@ -11,9 +11,16 @@
  */
 'use strict';
 
+var PixelRatio = require('PixelRatio');
 var StyleSheetRegistry = require('StyleSheetRegistry');
 var StyleSheetValidation = require('StyleSheetValidation');
-var flattenStyle = require('flattenStyle');
+
+var flatten = require('flattenStyle');
+
+var hairlineWidth = PixelRatio.roundToNearestPixel(0.4);
+if (hairlineWidth === 0) {
+  hairlineWidth = 1 / PixelRatio.get();
+}
 
 /**
  * A StyleSheet is an abstraction similar to CSS StyleSheets
@@ -59,10 +66,32 @@ var flattenStyle = require('flattenStyle');
  *  - It also allows to send the style only once through the bridge. All
  * subsequent uses are going to refer an id (not implemented yet).
  */
-class StyleSheet {
-  static flatten: typeof flattenStyle;
+module.exports = {
+  /**
+   * This is defined as the width of a thin line on the platform. It can be
+   * used as the thickness of a border or division between two elements.
+   * Example:
+   * ```
+   *   {
+   *     borderBottomColor: '#bbb',
+   *     borderBottomWidth: StyleSheet.hairlineWidth
+   *   }
+   * ```
+   *
+   * This constant will always be a round number of pixels (so a line defined
+   * by it look crisp) and will try to match the standard width of a thin line
+   * on the underlying platform. However, you should not rely on it being a
+   * constant size, because on different platforms and screen densities its
+   * value may be calculated differently.
+   */
+  hairlineWidth,
+
+  flatten,
 
-  static create(obj: {[key: string]: any}): {[key: string]: number} {
+  /**
+   * Creates a StyleSheet style reference from the given object.
+   */
+  create(obj: {[key: string]: any}): {[key: string]: number} {
     var result = {};
     for (var key in obj) {
       StyleSheetValidation.validateStyle(key, obj);
@@ -70,9 +99,4 @@ class StyleSheet {
     }
     return result;
   }
-}
-
-/* TODO(brentvatne) docs are needed for this */
-StyleSheet.flatten = flattenStyle;
-
-module.exports = StyleSheet;
+};
diff --git a/Libraries/Utilities/PixelRatio.js b/Libraries/Utilities/PixelRatio.js
index 940890ccec00..e7ab32ca5685 100644
--- a/Libraries/Utilities/PixelRatio.js
+++ b/Libraries/Utilities/PixelRatio.js
@@ -16,20 +16,6 @@ var Dimensions = require('Dimensions');
 /**
  * PixelRatio class gives access to the device pixel density.
  *
- * There are a few use cases for using PixelRatio:
- *
- * ### Displaying a line that's as thin as the device permits
- *
- * A width of 1 is actually pretty thick on devices with high pixel density
- * (such as iPhone 4+ and many Android devices), we can make one that's
- * thinner using a width of `1 / PixelRatio.get()`.
- * It's a technique that works on all the devices independent of their
- * pixel density.
- *
- * ```
- * style={{ borderWidth: 1 / PixelRatio.get() }}
- * ```
- *
  * ### Fetching a correctly sized image
  *
  * You should get a higher resolution image if you are on a high pixel density
@@ -91,6 +77,17 @@ class PixelRatio {
     return Math.round(layoutSize * PixelRatio.get());
   }
 
+  /**
+   * Rounds a layout size (dp) to the nearest layout size that corresponds to
+   * an integer number of pixels. For example, on a device with a PixelRatio
+   * of 3, `PixelRatio.roundToNearestPixel(8.4) = 8.33`, which corresponds to
+   * exactly (8.33 * 3) = 25 pixels.
+   */
+  static roundToNearestPixel(layoutSize: number): number {
+    var ratio = PixelRatio.get();
+    return Math.round(layoutSize * ratio) / ratio;
+  }
+
   // No-op for iOS, but used on the web. Should not be documented.
   static startDetecting() {}
 }
diff --git a/React/Views/UIView+React.m b/React/Views/UIView+React.m
index fae5e021acf2..bbc74901e30d 100644
--- a/React/Views/UIView+React.m
+++ b/React/Views/UIView+React.m
@@ -82,7 +82,7 @@ - (void)reactSetFrame:(CGRect)frame
   self.bounds = bounds;
 }
 
-- (void)reactSetInheritedBackgroundColor:(UIColor *)inheritedBackgroundColor
+- (void)reactSetInheritedBackgroundColor:(__unused UIColor *)inheritedBackgroundColor
 {
   // Does nothing by default
 }
diff --git a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
index 6712f00b4a45..82184c61bb33 100644
--- a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
+++ b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
@@ -10,6 +10,7 @@
 
 jest.dontMock('../')
   .dontMock('underscore')
+  .dontMock('PixelRatio')
   .dontMock('../../DependencyResolver/lib/extractRequires')
   .dontMock('../../DependencyResolver/lib/replacePatterns');
 

From 18437093f2664beedd3239bb525d7daa3f2bcdbd Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Fri, 15 Jan 2016 06:23:15 -0800
Subject: [PATCH 0750/1411] Open sourced spinner aka picker aka drop down for
 android

Reviewed By: mkonicek

Differential Revision: D2830803

fb-gh-sync-id: e6b6fcdbe33d942180cf2c1041076ad71d0473ce
---
 Examples/UIExplorer/PickerAndroidExample.js   | 142 ++++++++++++
 Examples/UIExplorer/UIExplorerList.android.js |   1 +
 .../Components/PickerAndroid/PickerAndroid.js | 213 ++++++++++++++++++
 Libraries/react-native/react-native.js        |   1 +
 Libraries/react-native/react-native.js.flow   |   1 +
 .../react/shell/MainReactPackage.java         |   4 +
 .../picker/ReactDialogPickerManager.java      |  32 +++
 .../picker/ReactDropdownPickerManager.java    |  32 +++
 .../react/views/picker/ReactPicker.java       | 148 ++++++++++++
 .../views/picker/ReactPickerManager.java      | 163 ++++++++++++++
 .../picker/events/PickerItemSelectEvent.java  |  42 ++++
 11 files changed, 779 insertions(+)
 create mode 100644 Examples/UIExplorer/PickerAndroidExample.js
 create mode 100644 Libraries/Components/PickerAndroid/PickerAndroid.js
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactDialogPickerManager.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactDropdownPickerManager.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactPicker.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactPickerManager.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/picker/events/PickerItemSelectEvent.java

diff --git a/Examples/UIExplorer/PickerAndroidExample.js b/Examples/UIExplorer/PickerAndroidExample.js
new file mode 100644
index 000000000000..91a2bd5a405e
--- /dev/null
+++ b/Examples/UIExplorer/PickerAndroidExample.js
@@ -0,0 +1,142 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ *
+ * @flow
+ */
+'use strict';
+
+const React = require('react-native');
+const UIExplorerBlock = require('UIExplorerBlock');
+const UIExplorerPage = require('UIExplorerPage');
+
+const {
+  PickerAndroid,
+  Text,
+  TouchableWithoutFeedback,
+} = React;
+const Item = PickerAndroid.Item;
+
+const PickerAndroidExample = React.createClass({
+  getInitialState: function() {
+    return {
+      selected1: 'key1',
+      selected2: 'key1',
+      selected3: 'key1',
+      selected4: 'key1',
+      color: 'red',
+      mode: PickerAndroid.MODE_DIALOG,
+    };
+  },
+
+  displayName: 'Android Picker',
+
+  render: function() {
+    return (
+      <UIExplorerPage title="<PickerAndroid>">
+        <UIExplorerBlock title="Basic Picker">
+          <PickerAndroid
+            style={{width: 100, height: 56}}
+            onSelect={this.onSelect.bind(this, 'selected1')}>
+            <Item text="hello" value="key0" selected={this.state.selected1 === 'key0'} />
+            <Item text="world" value="key1" selected={this.state.selected1 === 'key1'} />
+          </PickerAndroid>
+        </UIExplorerBlock>
+        <UIExplorerBlock title="Disabled picker">
+          <PickerAndroid style={{width: 100, height: 56}} enabled={false}>
+            <Item text="hello" value="key0" selected={this.state.selected1 === 'key0'} />
+            <Item text="world" value="key1" selected={this.state.selected1 === 'key1'} />
+          </PickerAndroid>
+        </UIExplorerBlock>
+        <UIExplorerBlock title="Dropdown Picker">
+          <PickerAndroid
+            style={{width: 100, height: 56}}
+            onSelect={this.onSelect.bind(this, 'selected2')}
+            mode="dropdown">
+            <Item text="hello" value="key0" selected={this.state.selected2 === 'key0'} />
+            <Item text="world" value="key1" selected={this.state.selected2 === 'key1'} />
+          </PickerAndroid>
+        </UIExplorerBlock>
+        <UIExplorerBlock title="Alternating Picker">
+          <PickerAndroid
+            style={{width: 100, height: 56}}
+            onSelect={this.onSelect.bind(this, 'selected3')}
+            mode={this.state.mode}>
+            <Item text="hello" value="key0" selected={this.state.selected3 === 'key0'} />
+            <Item text="world" value="key1" selected={this.state.selected3 === 'key1'} />
+          </PickerAndroid>
+          <TouchableWithoutFeedback onPress={this.changeMode}>
+            <Text>Tap here to switch between dialog/dropdown.</Text>
+          </TouchableWithoutFeedback>
+        </UIExplorerBlock>
+        <UIExplorerBlock title="Picker with prompt message">
+          <PickerAndroid
+            style={{width: 100, height: 56}}
+            onSelect={this.onSelect.bind(this, 'selected4')}
+            prompt="Pick one, just one">
+            <Item text="hello" value="key0" selected={this.state.selected4 === 'key0'} />
+            <Item text="world" value="key1" selected={this.state.selected4 === 'key1'} />
+          </PickerAndroid>
+        </UIExplorerBlock>
+        <UIExplorerBlock title="Picker with no listener">
+          <PickerAndroid style={{width: 100, height: 56}}>
+            <Item text="hello" value="key0" />
+            <Item text="world" value="key1" />
+          </PickerAndroid>
+          <Text>
+            You can not change the value of this picker because it doesn't set a selected prop on
+            its items.
+          </Text>
+        </UIExplorerBlock>
+        <UIExplorerBlock title="Colorful pickers">
+          <PickerAndroid style={{width: 100, height: 56, color: 'black'}}
+            onSelect={this.onSelect.bind(this, 'color')}
+            mode="dropdown">
+            <Item text="red" color="red" value="red" selected={this.state.color === 'red'}/>
+            <Item text="green" color="green" value="green" selected={this.state.color === 'green'}/>
+            <Item text="blue" color="blue" value="blue" selected={this.state.color === 'blue'}/>
+          </PickerAndroid>
+          <PickerAndroid style={{width: 100, height: 56}}
+            onSelect={this.onSelect.bind(this, 'color')}
+            mode="dialog">
+            <Item text="red" color="red" value="red" selected={this.state.color === 'red'}/>
+            <Item text="green" color="green" value="green" selected={this.state.color === 'green'}/>
+            <Item text="blue" color="blue" value="blue" selected={this.state.color === 'blue'} />
+          </PickerAndroid>
+        </UIExplorerBlock>
+      </UIExplorerPage>
+    );
+  },
+
+  changeMode: function() {
+    const newMode = this.state.mode === PickerAndroid.MODE_DIALOG
+        ? PickerAndroid.MODE_DROPDOWN
+        : PickerAndroid.MODE_DIALOG;
+    this.setState({mode: newMode});
+  },
+
+  onSelect: function(key, value) {
+    const newState = {};
+    newState[key] = value;
+    this.setState(newState);
+  },
+});
+
+exports.title = '<PickerAndroid>';
+exports.displayName = 'PickerAndroidExample';
+exports.description = 'The Android Picker component provides multiple options to choose from';
+exports.examples = [
+  {
+    title: 'PickerAndroidExample',
+    render(): ReactElement { return <PickerAndroidExample />; }
+  },
+];
diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index 1976128b116f..7d56b94f87df 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -29,6 +29,7 @@ var COMPONENTS = [
   require('./ScrollViewSimpleExample'),
   require('./SwitchExample'),
   require('./RefreshControlExample'),
+  require('./PickerAndroidExample'),
   require('./PullToRefreshViewAndroidExample.android'),
   require('./TextExample.android'),
   require('./TextInputExample.android'),
diff --git a/Libraries/Components/PickerAndroid/PickerAndroid.js b/Libraries/Components/PickerAndroid/PickerAndroid.js
new file mode 100644
index 000000000000..1ec105ca45e1
--- /dev/null
+++ b/Libraries/Components/PickerAndroid/PickerAndroid.js
@@ -0,0 +1,213 @@
+/**
+ * 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 PickerAndroid
+ * @flow
+ */
+
+'use strict';
+
+var ColorPropType = require('ColorPropType');
+var React = require('React');
+var ReactChildren = require('ReactChildren');
+var ReactPropTypes = require('ReactPropTypes');
+var StyleSheetPropType = require('StyleSheetPropType');
+var View = require('View');
+var ViewStylePropTypes = require('ViewStylePropTypes');
+
+var processColor = require('processColor');
+var requireNativeComponent = require('requireNativeComponent');
+
+var MODE_DIALOG = 'dialog';
+var MODE_DROPDOWN = 'dropdown';
+var REF_PICKER = 'picker';
+
+var pickerStyleType = StyleSheetPropType({
+  ...ViewStylePropTypes,
+  color: ColorPropType,
+});
+
+type Items = {
+  selected: number;
+  items: any[];
+};
+
+type Event = Object;
+
+/**
+ * Individual selectable item in a Picker.
+ */
+var Item = React.createClass({
+
+  propTypes: {
+    /**
+     * Color of this item's text.
+     */
+    color: ColorPropType,
+    /**
+     * Text to display for this item.
+     */
+    text: ReactPropTypes.string.isRequired,
+    /**
+     * The value to be passed to picker's `onSelect` callback when this item is selected.
+     */
+    value: ReactPropTypes.string,
+    /**
+     * If `true`, this item is selected and shown in the picker.
+     * Usually this is set based on state.
+     */
+    selected: ReactPropTypes.bool,
+    /**
+     * Used to locate this view in end-to-end tests.
+     */
+    testID: ReactPropTypes.string,
+  },
+
+  render: function() {
+    throw new Error('Picker items should never be rendered');
+  },
+
+});
+
+/**
+ * <PickerAndroid> - A React component that renders the native Picker widget on Android. The items
+ * that can be selected are specified as children views of type Item. Example usage:
+ *
+ *     <PickerAndroid>
+ *       <PickerAndroid.Item text="Java" value="js" />
+ *       <PickerAndroid.Item text="JavaScript" value="java" selected={true} />
+ *     </PickerAndroid>
+ */
+var PickerAndroid = React.createClass({
+
+  propTypes: {
+    ...View.propTypes,
+    style: pickerStyleType,
+    /**
+     * If set to false, the picker will be disabled, i.e. the user will not be able to make a
+     * selection.
+     */
+    enabled: ReactPropTypes.bool,
+    /**
+     * Specifies how to display the selection items when the user taps on the picker:
+     *
+     * - dialog: Show a modal dialog
+     * - dropdown: Shows a dropdown anchored to the picker view
+     */
+    mode: ReactPropTypes.oneOf([MODE_DIALOG, MODE_DROPDOWN]),
+    /**
+     * Callback for when an item is selected. This is called with the following parameters:
+     *
+     * - `itemValue`: the `value` prop of the item that was selected
+     * - `itemPosition`: the index of the selected item in this picker
+     */
+    onSelect: ReactPropTypes.func,
+    /**
+     * Prompt string for this picker, currently only used in `dialog` mode as the title of the
+     * dialog.
+     */
+    prompt: ReactPropTypes.string,
+    /**
+     * Used to locate this view in end-to-end tests.
+     */
+    testID: ReactPropTypes.string,
+  },
+
+  statics: {
+    Item: Item,
+    MODE_DIALOG: MODE_DIALOG,
+    MODE_DROPDOWN: MODE_DROPDOWN,
+  },
+
+  getDefaultProps: function() {
+    return {
+      mode: MODE_DIALOG,
+    };
+  },
+
+  render: function() {
+    var Picker = this.props.mode === MODE_DROPDOWN ? DropdownPicker : DialogPicker;
+
+    var { selected, items } = this._getItems();
+
+    var nativeProps = {
+      enabled: this.props.enabled,
+      items: items,
+      mode: this.props.mode,
+      onSelect: this._onSelect,
+      prompt: this.props.prompt,
+      selected: selected,
+      style: this.props.style,
+      testID: this.props.testID,
+    };
+
+    return <Picker ref={REF_PICKER} {...nativeProps} />;
+  },
+
+  /**
+   * Transform this view's children into an array of items to be passed to the native component.
+   * Since we're traversing the children, also determine the selected position.
+   *
+   * @returns an object with two keys:
+   *
+   * - `selected` (number) - the index of the selected item
+   * - `items` (array) - the items of this picker, as an array of strings
+   */
+  _getItems: function(): Items {
+    var items = [];
+    var selected = 0;
+    ReactChildren.forEach(this.props.children, function(child, index) {
+      var childProps = Object.assign({}, child.props);
+      if (childProps.color) {
+        childProps.color = processColor(childProps.color);
+      }
+      items.push(childProps);
+      if (childProps.selected) {
+        selected = index;
+      }
+    });
+    return {
+      selected: selected,
+      items: items,
+    };
+  },
+
+  _onSelect: function(event: Event) {
+    if (this.props.onSelect) {
+      var position = event.nativeEvent.position;
+      if (position >= 0) {
+        var value = this.props.children[position].props.value;
+        this.props.onSelect(value, position);
+      } else {
+        this.props.onSelect(null, position);
+      }
+    }
+
+    // The native Picker has changed, but the props haven't (yet). If
+    // the handler decides to not accept the new value or do something
+    // else with it we might end up in a bad state, so we reset the
+    // selection on the native component.
+    // tl;dr: PickerAndroid is a controlled component.
+    var { selected } = this._getItems();
+    if (this.refs[REF_PICKER]) {
+      this.refs[REF_PICKER].setNativeProps({selected: selected});
+    }
+  },
+
+});
+
+var cfg = {
+  nativeOnly: {
+    items: true,
+    selected: true,
+  }
+}
+var DropdownPicker = requireNativeComponent('AndroidDropdownPicker', PickerAndroid, cfg);
+var DialogPicker = requireNativeComponent('AndroidDialogPicker', PickerAndroid, cfg);
+
+module.exports = PickerAndroid;
diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js
index b28f255d9c35..16ca8ad82bcd 100644
--- a/Libraries/react-native/react-native.js
+++ b/Libraries/react-native/react-native.js
@@ -25,6 +25,7 @@ var ReactNative = {
   get Modal() { return require('Modal'); },
   get Navigator() { return require('Navigator'); },
   get NavigatorIOS() { return require('NavigatorIOS'); },
+  get PickerAndroid() { return require('PickerAndroid'); },
   get PickerIOS() { return require('PickerIOS'); },
   get ProgressBarAndroid() { return require('ProgressBarAndroid'); },
   get ProgressViewIOS() { return require('ProgressViewIOS'); },
diff --git a/Libraries/react-native/react-native.js.flow b/Libraries/react-native/react-native.js.flow
index a178f69cf436..2eb844c4d9b3 100644
--- a/Libraries/react-native/react-native.js.flow
+++ b/Libraries/react-native/react-native.js.flow
@@ -37,6 +37,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
   Modal: require('Modal'),
   Navigator: require('Navigator'),
   NavigatorIOS: require('NavigatorIOS'),
+  PickerAndroid: require('PickerAndroid'),
   PickerIOS: require('PickerIOS'),
   ProgressBarAndroid: require('ProgressBarAndroid'),
   ProgressViewIOS: require('ProgressViewIOS'),
diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
index 6d98ea60a65b..5f0d2d4ead99 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
@@ -32,6 +32,8 @@
 import com.facebook.react.views.art.ARTSurfaceViewManager;
 import com.facebook.react.views.drawer.ReactDrawerLayoutManager;
 import com.facebook.react.views.image.ReactImageManager;
+import com.facebook.react.views.picker.ReactDialogPickerManager;
+import com.facebook.react.views.picker.ReactDropdownPickerManager;
 import com.facebook.react.views.progressbar.ReactProgressBarViewManager;
 import com.facebook.react.views.recyclerview.RecyclerViewBackedScrollViewManager;
 import com.facebook.react.views.scroll.ReactHorizontalScrollViewManager;
@@ -82,7 +84,9 @@ public List<ViewManager> createViewManagers(ReactApplicationContext reactContext
       ARTRenderableViewManager.createARTShapeViewManager(),
       ARTRenderableViewManager.createARTTextViewManager(),
       new ARTSurfaceViewManager(),
+      new ReactDialogPickerManager(),
       new ReactDrawerLayoutManager(),
+      new ReactDropdownPickerManager(),
       new ReactHorizontalScrollViewManager(),
       new ReactImageManager(),
       new ReactProgressBarViewManager(),
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactDialogPickerManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactDialogPickerManager.java
new file mode 100644
index 000000000000..c86709467177
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactDialogPickerManager.java
@@ -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.
+ */
+
+package com.facebook.react.views.picker;
+
+import android.widget.Spinner;
+
+import com.facebook.react.uimanager.ThemedReactContext;
+
+/**
+ * {@link ReactPickerManager} for {@link ReactPicker} with {@link Spinner#MODE_DIALOG}.
+ */
+public class ReactDialogPickerManager extends ReactPickerManager {
+
+  private static final String REACT_CLASS = "AndroidDialogPicker";
+
+  @Override
+  public String getName() {
+    return REACT_CLASS;
+  }
+
+  @Override
+  protected ReactPicker createViewInstance(ThemedReactContext reactContext) {
+    return new ReactPicker(reactContext, Spinner.MODE_DIALOG);
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactDropdownPickerManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactDropdownPickerManager.java
new file mode 100644
index 000000000000..c8be5600265c
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactDropdownPickerManager.java
@@ -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.
+ */
+
+package com.facebook.react.views.picker;
+
+import android.widget.Spinner;
+
+import com.facebook.react.uimanager.ThemedReactContext;
+
+/**
+ * {@link ReactPickerManager} for {@link ReactPicker} with {@link Spinner#MODE_DROPDOWN}.
+ */
+public class ReactDropdownPickerManager extends ReactPickerManager {
+
+  private static final String REACT_CLASS = "AndroidDropdownPicker";
+
+  @Override
+  public String getName() {
+    return REACT_CLASS;
+  }
+
+  @Override
+  protected ReactPicker createViewInstance(ThemedReactContext reactContext) {
+    return new ReactPicker(reactContext, Spinner.MODE_DROPDOWN);
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactPicker.java b/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactPicker.java
new file mode 100644
index 000000000000..2871cd21286b
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactPicker.java
@@ -0,0 +1,148 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.picker;
+
+import javax.annotation.Nullable;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.Spinner;
+
+import com.facebook.react.common.annotations.VisibleForTesting;
+
+public class ReactPicker extends Spinner {
+
+  private int mMode = MODE_DIALOG;
+  private @Nullable Integer mPrimaryColor;
+  private boolean mSuppressNextEvent;
+  private @Nullable OnSelectListener mOnSelectListener;
+  private @Nullable Integer mStagedSelection;
+
+  /**
+   * Listener interface for ReactPicker events.
+   */
+  public interface OnSelectListener {
+    void onItemSelected(int position);
+  }
+
+  public ReactPicker(Context context) {
+    super(context);
+  }
+
+  public ReactPicker(Context context, int mode) {
+    super(context, mode);
+    mMode = mode;
+  }
+
+  public ReactPicker(Context context, AttributeSet attrs) {
+    super(context, attrs);
+  }
+
+  public ReactPicker(Context context, AttributeSet attrs, int defStyle) {
+    super(context, attrs, defStyle);
+  }
+
+  public ReactPicker(Context context, AttributeSet attrs, int defStyle, int mode) {
+    super(context, attrs, defStyle, mode);
+    mMode = mode;
+  }
+
+  private final Runnable measureAndLayout = new Runnable() {
+    @Override
+    public void run() {
+      measure(
+          MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY),
+          MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY));
+      layout(getLeft(), getTop(), getRight(), getBottom());
+    }
+  };
+
+  @Override
+  public void requestLayout() {
+    super.requestLayout();
+
+    // The spinner relies on a measure + layout pass happening after it calls requestLayout().
+    // Without this, the widget never actually changes the selection and doesn't call the
+    // appropriate listeners. Since we override onLayout in our ViewGroups, a layout pass never
+    // happens after a call to requestLayout, so we simulate one here.
+    post(measureAndLayout);
+  }
+
+  public void setOnSelectListener(@Nullable OnSelectListener onSelectListener) {
+    if (getOnItemSelectedListener() == null) {
+      setOnItemSelectedListener(
+          new OnItemSelectedListener() {
+            @Override
+            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+              if (!mSuppressNextEvent && mOnSelectListener != null) {
+                mOnSelectListener.onItemSelected(position);
+              }
+              mSuppressNextEvent = false;
+            }
+
+            @Override
+            public void onNothingSelected(AdapterView<?> parent) {
+              if (!mSuppressNextEvent && mOnSelectListener != null) {
+                mOnSelectListener.onItemSelected(-1);
+              }
+              mSuppressNextEvent = false;
+            }
+          });
+    }
+    mOnSelectListener = onSelectListener;
+  }
+
+  @Nullable public OnSelectListener getOnSelectListener() {
+    return mOnSelectListener;
+  }
+
+  /**
+   * Will cache "selection" value locally and set it only once {@link #updateStagedSelection} is
+   * called
+   */
+  public void setStagedSelection(int selection) {
+    mStagedSelection = selection;
+  }
+
+  public void updateStagedSelection() {
+    if (mStagedSelection != null) {
+      setSelectionWithSuppressEvent(mStagedSelection);
+      mStagedSelection = null;
+    }
+  }
+
+  /**
+   * Set the selection while suppressing the follow-up {@link OnSelectListener#onItemSelected(int)}
+   * event. This is used so we don't get an event when changing the selection ourselves.
+   *
+   * @param position the position of the selected item
+   */
+  private void setSelectionWithSuppressEvent(int position) {
+    if (position != getSelectedItemPosition()) {
+      mSuppressNextEvent = true;
+      setSelection(position);
+    }
+  }
+
+  public @Nullable Integer getPrimaryColor() {
+    return mPrimaryColor;
+  }
+
+  public void setPrimaryColor(@Nullable Integer primaryColor) {
+    mPrimaryColor = primaryColor;
+  }
+
+  @VisibleForTesting
+  public int getMode() {
+    return mMode;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactPickerManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactPickerManager.java
new file mode 100644
index 000000000000..fe2f23cd020c
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactPickerManager.java
@@ -0,0 +1,163 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.picker;
+
+import javax.annotation.Nullable;
+
+import android.content.Context;
+import android.os.SystemClock;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import com.facebook.infer.annotation.Assertions;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.uimanager.annotations.ReactProp;
+import com.facebook.react.uimanager.SimpleViewManager;
+import com.facebook.react.uimanager.ThemedReactContext;
+import com.facebook.react.uimanager.UIManagerModule;
+import com.facebook.react.uimanager.ViewProps;
+import com.facebook.react.uimanager.events.EventDispatcher;
+import com.facebook.react.views.picker.events.PickerItemSelectEvent;
+
+/**
+ * {@link ViewManager} for the {@link ReactPicker} view. This is abstract because the
+ * {@link Spinner} doesn't support setting the mode (dropdown/dialog) outside the constructor, so
+ * that is delegated to the separate {@link ReactDropdownPickerManager} and
+ * {@link ReactDialogPickerManager} components. These are merged back on the JS side into one
+ * React component.
+ */
+public abstract class ReactPickerManager extends SimpleViewManager<ReactPicker> {
+
+  @ReactProp(name = "items")
+  public void setItems(ReactPicker view, @Nullable ReadableArray items) {
+    if (items != null) {
+      ReadableMap[] data = new ReadableMap[items.size()];
+      for (int i = 0; i < items.size(); i++) {
+        data[i] = items.getMap(i);
+      }
+      ReactPickerAdapter adapter = new ReactPickerAdapter(view.getContext(), data);
+      adapter.setPrimaryTextColor(view.getPrimaryColor());
+      view.setAdapter(adapter);
+    } else {
+      view.setAdapter(null);
+    }
+  }
+
+  @ReactProp(name = ViewProps.COLOR, customType = "Color")
+  public void setColor(ReactPicker view, @Nullable Integer color) {
+    view.setPrimaryColor(color);
+    ReactPickerAdapter adapter = (ReactPickerAdapter) view.getAdapter();
+    if (adapter != null) {
+      adapter.setPrimaryTextColor(color);
+    }
+  }
+
+  @ReactProp(name = "prompt")
+  public void setPrompt(ReactPicker view, @Nullable String prompt) {
+    view.setPrompt(prompt);
+  }
+
+  @ReactProp(name = ViewProps.ENABLED, defaultBoolean = true)
+  public void setEnabled(ReactPicker view, boolean enabled) {
+    view.setEnabled(enabled);
+  }
+
+  @ReactProp(name = "selected")
+  public void setSelected(ReactPicker view, int selected) {
+    view.setStagedSelection(selected);
+  }
+
+  @Override
+  protected void onAfterUpdateTransaction(ReactPicker view) {
+    super.onAfterUpdateTransaction(view);
+    view.updateStagedSelection();
+  }
+
+  @Override
+  protected void addEventEmitters(
+      final ThemedReactContext reactContext,
+      final ReactPicker picker) {
+    picker.setOnSelectListener(
+            new PickerEventEmitter(
+                    picker,
+                    reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher()));
+  }
+
+  private static class ReactPickerAdapter extends ArrayAdapter<ReadableMap> {
+
+    private final LayoutInflater mInflater;
+    private @Nullable Integer mPrimaryTextColor;
+
+    public ReactPickerAdapter(Context context, ReadableMap[] data) {
+      super(context, 0, data);
+
+      mInflater = (LayoutInflater) Assertions.assertNotNull(
+          context.getSystemService(Context.LAYOUT_INFLATER_SERVICE));
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+      return getView(position, convertView, parent, false);
+    }
+
+    @Override
+    public View getDropDownView(int position, View convertView, ViewGroup parent) {
+      return getView(position, convertView, parent, true);
+    }
+
+    private View getView(int position, View convertView, ViewGroup parent, boolean isDropdown) {
+      ReadableMap item = getItem(position);
+
+      if (convertView == null) {
+        int layoutResId = isDropdown
+            ? android.R.layout.simple_spinner_dropdown_item
+            : android.R.layout.simple_spinner_item;
+        convertView = mInflater.inflate(layoutResId, parent, false);
+      }
+
+      TextView textView = (TextView) convertView;
+      textView.setText(item.getString("text"));
+      if (!isDropdown && mPrimaryTextColor != null) {
+        textView.setTextColor(mPrimaryTextColor);
+      } else if (item.hasKey("color") && !item.isNull("color")) {
+        textView.setTextColor(item.getInt("color"));
+      }
+
+      return convertView;
+    }
+
+    public void setPrimaryTextColor(@Nullable Integer primaryTextColor) {
+      mPrimaryTextColor = primaryTextColor;
+      notifyDataSetChanged();
+    }
+  }
+
+  private static class PickerEventEmitter implements ReactPicker.OnSelectListener {
+
+    private final ReactPicker mReactPicker;
+    private final EventDispatcher mEventDispatcher;
+
+    public PickerEventEmitter(ReactPicker reactPicker, EventDispatcher eventDispatcher) {
+      mReactPicker = reactPicker;
+      mEventDispatcher = eventDispatcher;
+    }
+
+    @Override
+    public void onItemSelected(int position) {
+      mEventDispatcher.dispatchEvent( new PickerItemSelectEvent(
+              mReactPicker.getId(), SystemClock.uptimeMillis(), position));
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/picker/events/PickerItemSelectEvent.java b/ReactAndroid/src/main/java/com/facebook/react/views/picker/events/PickerItemSelectEvent.java
new file mode 100644
index 000000000000..cabe53fdc41f
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/picker/events/PickerItemSelectEvent.java
@@ -0,0 +1,42 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.picker.events;
+
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.uimanager.events.Event;
+import com.facebook.react.uimanager.events.RCTEventEmitter;
+
+public class PickerItemSelectEvent extends Event<PickerItemSelectEvent> {
+  public static final String EVENT_NAME = "topSelect";
+
+  private final int mPosition;
+
+  public PickerItemSelectEvent(int id, long uptimeMillis, int position) {
+    super(id, uptimeMillis);
+    mPosition = position;
+  }
+
+  @Override
+  public String getEventName() {
+    return EVENT_NAME;
+  }
+
+  @Override
+  public void dispatch(RCTEventEmitter rctEventEmitter) {
+    rctEventEmitter.receiveEvent(getViewTag(), getEventName(), serializeEventData());
+  }
+
+  private WritableMap serializeEventData() {
+    WritableMap eventData = Arguments.createMap();
+    eventData.putInt("position", mPosition);
+    return eventData;
+  }
+}

From 1341f8bc8e54072a8a40d7b2774ae47cfe96e765 Mon Sep 17 00:00:00 2001
From: Tom Auty <tauty@moneylion.com>
Date: Fri, 15 Jan 2016 11:14:49 -0500
Subject: [PATCH 0751/1411] [Website] Add MoneyLion App

---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 09da35e12813..77cd42f955a5 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -332,6 +332,12 @@ var apps = [
     link: 'https://itunes.apple.com/cn/app/mockingbot/id1050565468?l=en&mt=8',
     author: 'YuanYi Zhang (@mockingbot)',
   },
+	{
+		name: 'MoneyLion',
+		icon: 'http://a5.mzstatic.com/us/r30/Purple69/v4/d7/9d/ad/d79daddc-8d67-8a6c-61e2-950425946dd2/icon350x350.jpeg',
+		link: 'https://itunes.apple.com/us/app/moneylion/id1064677082?mt=8',
+		author: 'MoneyLion LLC',
+	},
   {
     name: 'Mr. Dapper',
     icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple4/v4/e8/3f/7c/e83f7cb3-2602-f8e8-de9a-ce0a775a4a14/mzl.hmdjhfai.png',

From 2a02621e744d91f3af5416e667512e7548558746 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Fri, 15 Jan 2016 08:33:15 -0800
Subject: [PATCH 0752/1411] Fix incorrect size issue with inline image text

Reviewed By: andreicoman11

Differential Revision: D2834175

fb-gh-sync-id: 827d37e0128eb07f2e009479269b63c3a3549315
---
 .../com/facebook/react/views/text/ReactTextShadowNode.java    | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java
index 693e52b4d0bb..314df23ef3d5 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java
@@ -161,8 +161,8 @@ private static final void buildSpannedFromImageNode(
     int start = sb.length();
     // Create our own internal ImageSpan which will allow us to correctly layout the Image
     Resources resources = node.getThemedContext().getResources();
-    int height = (int) PixelUtil.toDIPFromPixel(node.getStyleHeight());
-    int width = (int) PixelUtil.toDIPFromPixel(node.getStyleWidth());
+    int height = (int) Math.ceil(node.getStyleHeight());
+    int width = (int) Math.ceil(node.getStyleWidth());
     TextInlineImageSpan imageSpan = new TextInlineImageSpan(
         resources,
         height,

From b68170a4894c172e78eba4388b0e10cbcca5b857 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Fri, 15 Jan 2016 16:47:45 +0000
Subject: [PATCH 0753/1411] Update Releases.md

---
 Releases.md | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/Releases.md b/Releases.md
index 6e19390f672a..053a2f321c12 100644
--- a/Releases.md
+++ b/Releases.md
@@ -6,10 +6,12 @@ Future releases:
 - **0.17 branch cut**, 0.17.0-rc - beginning of **week of Dec 7**
 - 0.17.0 - Dec 17
 - (Holiday break)
-- **0.18 branch cut**, 0.18.0-rc - beginning of **week of Jan 4**
-- 0.18.0 - Jan 14
-- **0.19 branch cut**, 0.19.0-rc - beginning of **week of Jan 18**
-- 0.19.0 - Jan 28
+- **0.18 branch cut**, 0.18.0-rc - **week of Jan 4**
+- 0.18.0 - Jan 18
+- **0.19 branch cut**, 0.19.0-rc - **week of Jan 18**
+- 0.19.0 - Feb 1
+- **0.20 branch cut**, 0.19.0-rc - **week of Feb 1**
+- 0.20.0 - Feb 15
 - ...
 
 ## Ideas for improvements

From 274a3e05858a51af3d0eb8bdea2f7975f7f61169 Mon Sep 17 00:00:00 2001
From: Horcrux <cyang@vip.deyi.com>
Date: Fri, 15 Jan 2016 09:30:47 -0800
Subject: [PATCH 0754/1411] add onLoading* prop for WebView

Summary:
add onLoadingStart,onLoadingError,onLoadingFinish prop for WebView
Closes https://github.com/facebook/react-native/pull/5335

Reviewed By: svcscm

Differential Revision: D2834003

Pulled By: nicklockwood

fb-gh-sync-id: bbe84297ebeb5a6c2bf1caaacee8c59e0bcef1db
---
 .../Components/WebView/WebView.android.js     | 12 ++++++++++
 Libraries/Components/WebView/WebView.ios.js   | 24 +++++++++++++++++++
 2 files changed, 36 insertions(+)

diff --git a/Libraries/Components/WebView/WebView.android.js b/Libraries/Components/WebView/WebView.android.js
index 19e1a4f1a1a6..f7b0a88ef763 100644
--- a/Libraries/Components/WebView/WebView.android.js
+++ b/Libraries/Components/WebView/WebView.android.js
@@ -40,6 +40,10 @@ var WebView = React.createClass({
     ...View.propTypes,
     renderError: PropTypes.func,
     renderLoading: PropTypes.func,
+    onLoad: PropTypes.func,
+    onLoadEnd: PropTypes.func,
+    onLoadStart: PropTypes.func,
+    onError: PropTypes.func,
     url: PropTypes.string,
     html: PropTypes.string,
     automaticallyAdjustContentInsets: PropTypes.bool,
@@ -189,11 +193,16 @@ var WebView = React.createClass({
   },
 
   onLoadingStart: function(event) {
+    var onLoadStart = this.props.onLoadStart;
+    onLoadStart && onLoadStart(event);
     this.updateNavigationState(event);
   },
 
   onLoadingError: function(event) {
     event.persist(); // persist this event because we need to store it
+    var {onError, onLoadEnd} = this.props;
+    onError && onError(event);
+    onLoadEnd && onLoadEnd(event);
     console.error('Encountered an error loading page', event.nativeEvent);
 
     this.setState({
@@ -203,6 +212,9 @@ var WebView = React.createClass({
   },
 
   onLoadingFinish: function(event) {
+    var {onLoad, onLoadEnd} = this.props;
+    onLoad && onLoad(event);
+    onLoadEnd && onLoadEnd(event);
     this.setState({
       viewState: WebViewState.IDLE,
     });
diff --git a/Libraries/Components/WebView/WebView.ios.js b/Libraries/Components/WebView/WebView.ios.js
index d97326667c6b..ea49044e10d4 100644
--- a/Libraries/Components/WebView/WebView.ios.js
+++ b/Libraries/Components/WebView/WebView.ios.js
@@ -97,6 +97,22 @@ var WebView = React.createClass({
      * Function that returns a loading indicator.
      */
     renderLoading: PropTypes.func,
+    /**
+     * Invoked when load finish
+     */
+    onLoad: PropTypes.func,
+    /**
+     * Invoked when load either succeeds or fails
+     */
+    onLoadEnd: PropTypes.func,
+    /**
+     * Invoked on load start
+     */
+    onLoadStart: PropTypes.func,
+    /**
+     * Invoked when load fails
+     */
+    onError: PropTypes.func,
     /**
      * @platform ios
      */
@@ -279,11 +295,16 @@ var WebView = React.createClass({
   },
 
   onLoadingStart: function(event: Event) {
+    var onLoadStart = this.props.onLoadStart;
+    onLoadStart && onLoadStart(event);
     this.updateNavigationState(event);
   },
 
   onLoadingError: function(event: Event) {
     event.persist(); // persist this event because we need to store it
+    var {onError, onLoadEnd} = this.props;
+    onError && onError(event);
+    onLoadEnd && onLoadEnd(event);
     console.warn('Encountered an error loading page', event.nativeEvent);
 
     this.setState({
@@ -293,6 +314,9 @@ var WebView = React.createClass({
   },
 
   onLoadingFinish: function(event: Event) {
+    var {onLoad, onLoadEnd} = this.props;
+    onLoad && onLoad(event);
+    onLoadEnd && onLoadEnd(event);
     this.setState({
       viewState: WebViewState.IDLE,
     });

From a10a510d968b3068dd2f8923b9abdaf012c62040 Mon Sep 17 00:00:00 2001
From: Felix Oghina <foghina@fb.com>
Date: Fri, 15 Jan 2016 09:46:34 -0800
Subject: [PATCH 0755/1411] support removeClippedSubviews in
 ReactHorizontalScrollView

Reviewed By: andreicoman11

Differential Revision: D2831013

fb-gh-sync-id: 2ac4eb8d748f2d66523992e8683c1b4d60198ba1
---
 .../scroll/ReactHorizontalScrollView.java     | 61 ++++++++++++++++++-
 .../ReactHorizontalScrollViewManager.java     |  7 +++
 2 files changed, 67 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java
index 298512c6d552..c8bdc978a8ed 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java
@@ -9,29 +9,54 @@
 
 package com.facebook.react.views.scroll;
 
+import javax.annotation.Nullable;
+
 import android.content.Context;
+import android.graphics.Rect;
 import android.view.MotionEvent;
+import android.view.View;
 import android.widget.HorizontalScrollView;
 
+import com.facebook.infer.annotation.Assertions;
 import com.facebook.react.uimanager.MeasureSpecAssertions;
 import com.facebook.react.uimanager.events.NativeGestureUtil;
+import com.facebook.react.views.view.ReactClippingViewGroup;
+import com.facebook.react.views.view.ReactClippingViewGroupHelper;
 
 /**
  * Similar to {@link ReactScrollView} but only supports horizontal scrolling.
  */
-public class ReactHorizontalScrollView extends HorizontalScrollView {
+public class ReactHorizontalScrollView extends HorizontalScrollView implements
+    ReactClippingViewGroup {
 
   private final OnScrollDispatchHelper mOnScrollDispatchHelper = new OnScrollDispatchHelper();
 
+  private boolean mRemoveClippedSubviews;
   private boolean mSendMomentumEvents;
   private boolean mDragging;
   private boolean mFlinging;
   private boolean mDoneFlinging;
 
+  private @Nullable Rect mClippingRect;
+
   public ReactHorizontalScrollView(Context context) {
     super(context);
   }
 
+  @Override
+  public void setRemoveClippedSubviews(boolean removeClippedSubviews) {
+    if (removeClippedSubviews && mClippingRect == null) {
+      mClippingRect = new Rect();
+    }
+    mRemoveClippedSubviews = removeClippedSubviews;
+    updateClippingRect();
+  }
+
+  @Override
+  public boolean getRemoveClippedSubviews() {
+    return mRemoveClippedSubviews;
+  }
+
   public void setSendMomentumEvents(boolean sendMomentumEvents) {
     mSendMomentumEvents = sendMomentumEvents;
   }
@@ -56,9 +81,14 @@ protected void onScrollChanged(int x, int y, int oldX, int oldY) {
     super.onScrollChanged(x, y, oldX, oldY);
 
     if (mOnScrollDispatchHelper.onScrollChanged(x, y)) {
+      if (mRemoveClippedSubviews) {
+        updateClippingRect();
+      }
+
       if (mFlinging) {
         mDoneFlinging = false;
       }
+
       ReactScrollViewHelper.emitScrollEvent(this);
     }
   }
@@ -106,4 +136,33 @@ public void run() {
       postOnAnimationDelayed(r, ReactScrollViewHelper.MOMENTUM_DELAY);
     }
   }
+
+
+  @Override
+  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+    super.onSizeChanged(w, h, oldw, oldh);
+    if (mRemoveClippedSubviews) {
+      updateClippingRect();
+    }
+  }
+
+  @Override
+  public void updateClippingRect() {
+    if (!mRemoveClippedSubviews) {
+      return;
+    }
+
+    Assertions.assertNotNull(mClippingRect);
+
+    ReactClippingViewGroupHelper.calculateClippingRect(this, mClippingRect);
+    View contentView = getChildAt(0);
+    if (contentView instanceof ReactClippingViewGroup) {
+      ((ReactClippingViewGroup) contentView).updateClippingRect();
+    }
+  }
+
+  @Override
+  public void getClippingRect(Rect outClippingRect) {
+    outClippingRect.set(Assertions.assertNotNull(mClippingRect));
+  }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java
index 972a88acd0b6..07a39d4a413f 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java
@@ -15,6 +15,7 @@
 import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.ViewGroupManager;
+import com.facebook.react.views.view.ReactClippingViewGroupHelper;
 
 /**
  * View manager for {@link ReactHorizontalScrollView} components.
@@ -38,6 +39,12 @@ public ReactHorizontalScrollView createViewInstance(ThemedReactContext context)
     return new ReactHorizontalScrollView(context);
   }
 
+  @ReactProp(name = ReactClippingViewGroupHelper.PROP_REMOVE_CLIPPED_SUBVIEWS)
+  public void setRemoveClippedSubviews(ReactHorizontalScrollView view, boolean removeClippedSubviews) {
+    view.setRemoveClippedSubviews(removeClippedSubviews);
+  }
+
+
   @ReactProp(name = "showsHorizontalScrollIndicator")
   public void setShowsHorizontalScrollIndicator(ReactHorizontalScrollView view, boolean value) {
     view.setHorizontalScrollBarEnabled(value);

From dd06596595a5797d33235ccb6f911db3417cf603 Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Fri, 15 Jan 2016 10:05:20 -0800
Subject: [PATCH 0756/1411] Don't extract dependencies from .json files

Reviewed By: davidaurelio

Differential Revision: D2832417

fb-gh-sync-id: 8bf3705bf620f3cc6d713ca08dde52464185797a
---
 packager/react-packager/src/DependencyResolver/Module.js | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/Module.js b/packager/react-packager/src/DependencyResolver/Module.js
index f6eb72beefc3..09fbe7939c0c 100644
--- a/packager/react-packager/src/DependencyResolver/Module.js
+++ b/packager/react-packager/src/DependencyResolver/Module.js
@@ -109,10 +109,11 @@ class Module {
           )[1];
         }
 
-        // Ignore requires in generated code. An example of this is prebuilt
-        // files like the SourceMap library.
-        if ('extern' in moduleDocBlock) {
+        // Ignore requires in JSON files or generated code. An example of this
+        // is prebuilt files like the SourceMap library.
+        if (this.isJSON() || 'extern' in moduleDocBlock) {
           data.dependencies = [];
+          data.asyncDependencies = [];
         } else {
           var dependencies = (this._extractor || extractRequires)(content).deps;
           data.dependencies = dependencies.sync;

From 38486dcbba25c04a2cb97f7e0d6f8e32d1991d46 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Fri, 15 Jan 2016 10:31:22 -0800
Subject: [PATCH 0757/1411] Throw if there's an error persisting the cache

Reviewed By: davidaurelio

Differential Revision: D2824116

fb-gh-sync-id: 46b3c51a11d22e2da750f9c5a4b431a88004cd81
---
 .../src/DependencyResolver/Cache/index.js     | 22 +++++++++++--------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/Cache/index.js b/packager/react-packager/src/DependencyResolver/Cache/index.js
index 3f601bd491e9..02384a202cf8 100644
--- a/packager/react-packager/src/DependencyResolver/Cache/index.js
+++ b/packager/react-packager/src/DependencyResolver/Cache/index.js
@@ -109,18 +109,18 @@ class Cache {
       return this._persisting;
     }
 
-    var data = this._data;
-    var cacheFilepath = this._cacheFilePath;
+    const data = this._data;
+    const cacheFilepath = this._cacheFilePath;
 
-    var allPromises = getObjectValues(data)
+    const allPromises = getObjectValues(data)
       .map(record => {
-        var fieldNames = Object.keys(record.data);
-        var fieldValues = getObjectValues(record.data);
+        const fieldNames = Object.keys(record.data);
+        const fieldValues = getObjectValues(record.data);
 
         return Promise
           .all(fieldValues)
           .then(ref => {
-            var ret = Object.create(null);
+            const ret = Object.create(null);
             ret.metadata = record.metadata;
             ret.data = Object.create(null);
             fieldNames.forEach((field, index) =>
@@ -134,18 +134,22 @@ class Cache {
 
     this._persisting = Promise.all(allPromises)
       .then(values => {
-        var json = Object.create(null);
+        const json = Object.create(null);
         Object.keys(data).forEach((key, i) => {
-          if (!values[i]) {
+          // make sure the key wasn't added nor removed after we started
+          // persisting the cache
+          const value = values[i];
+          if (!value) {
             return;
           }
 
           json[key] = Object.create(null);
           json[key].metadata = data[key].metadata;
-          json[key].data = values[i].data;
+          json[key].data = value.data;
         });
         return Promise.denodeify(fs.writeFile)(cacheFilepath, JSON.stringify(json));
       })
+      .catch(e => console.error('Error while persisting cache:', e.message))
       .then(() => {
         this._persisting = null;
         return true;

From c9f274c02d5100a48a92ad3408a1fcff891f4d87 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Fri, 15 Jan 2016 10:51:56 -0800
Subject: [PATCH 0758/1411] Send assets updates through HRM interface

Reviewed By: frantic

Differential Revision: D2832693

fb-gh-sync-id: 816a01fa2f1f7cc8ca218de86b3e2e847ee005c9
---
 local-cli/server/util/attachHMRServer.js     |  2 +-
 packager/react-packager/src/Bundler/index.js | 46 ++++++++++++++------
 2 files changed, 34 insertions(+), 14 deletions(-)

diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js
index 5de18b977787..25961ee4e5dd 100644
--- a/local-cli/server/util/attachHMRServer.js
+++ b/local-cli/server/util/attachHMRServer.js
@@ -139,7 +139,7 @@ function attachHMRServer({httpServer, path, packagerServer}) {
                     }
 
                     // build list of modules for which we'll send HMR updates
-                    const modulesToUpdate = [];
+                    const modulesToUpdate = [packagerServer.getModuleForPath(filename)];
                     Object.keys(dependenciesModulesCache).forEach(module => {
                       if (!client.dependenciesModulesCache[module]) {
                         modulesToUpdate.push(dependenciesModulesCache[module]);
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index 3380a3ce0283..ebac145ce929 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -291,11 +291,7 @@ class Bundler {
           modules.map(module => {
             return Promise.all([
               module.getName(),
-              this._transformer.loadFileAndTransform(
-                module.path,
-                // TODO(martinb): pass non null main (t9527509)
-                this._getTransformOptions({main: null}, {hot: true}),
-              ),
+              this._transformModuleForHMR(module, platform),
             ]).then(([moduleName, transformed]) => {
               return this._resolver.resolveRequires(response,
                 module,
@@ -317,6 +313,24 @@ class Bundler {
       .then(modules => modules.join('\n'));
   }
 
+  _transformModuleForHMR(module, platform) {
+    if (module.isAsset()) {
+      return this._generateAssetObjAndCode(module, platform).then(
+        ({asset, code}) => {
+          return {
+            code,
+          };
+        }
+      );
+    } else {
+      return this._transformer.loadFileAndTransform(
+        module.path,
+        // TODO(martinb): pass non null main (t9527509)
+        this._getTransformOptions({main: null}, {hot: true}),
+      );
+    }
+  }
+
   invalidateFile(filePath) {
     this._transformer.invalidateFile(filePath);
   }
@@ -371,9 +385,9 @@ class Bundler {
 
   _transformModule(bundle, response, module, platform = null, hot = false) {
     if (module.isAsset_DEPRECATED()) {
-      return this.generateAssetModule_DEPRECATED(bundle, module);
+      return this._generateAssetModule_DEPRECATED(bundle, module);
     } else if (module.isAsset()) {
-      return this.generateAssetModule(bundle, module, platform);
+      return this._generateAssetModule(bundle, module, platform);
     } else if (module.isJSON()) {
       return generateJSONModule(module);
     } else {
@@ -408,7 +422,7 @@ class Bundler {
     return this._resolver.getDebugInfo();
   }
 
-  generateAssetModule_DEPRECATED(bundle, module) {
+  _generateAssetModule_DEPRECATED(bundle, module) {
     return Promise.all([
       sizeOf(module.path),
       module.getName(),
@@ -435,7 +449,7 @@ class Bundler {
     });
   }
 
-  generateAssetModule(bundle, module, platform = null) {
+  _generateAssetObjAndCode(module, platform = null) {
     const relPath = getPathRelativeToRoot(this._projectRoots, module.path);
     var assetUrlPath = path.join('/assets', path.dirname(relPath));
 
@@ -450,7 +464,7 @@ class Bundler {
     ]).then(function(res) {
       const dimensions = res[0];
       const assetData = res[1];
-      const img = {
+      const asset = {
         __packager_asset: true,
         fileSystemLocation: path.dirname(module.path),
         httpServerLocation: assetUrlPath,
@@ -463,11 +477,17 @@ class Bundler {
         type: assetData.type,
       };
 
-      bundle.addAsset(img);
-
       const ASSET_TEMPLATE = 'module.exports = require("AssetRegistry").registerAsset(%json);';
-      const code = ASSET_TEMPLATE.replace('%json', JSON.stringify(img));
+      const code = ASSET_TEMPLATE.replace('%json', JSON.stringify(asset));
+
+      return {asset, code};
+    });
+  }
+
 
+  _generateAssetModule(bundle, module, platform = null) {
+    return this._generateAssetObjAndCode(module, platform).then(({asset, code}) => {
+      bundle.addAsset(asset);
       return new ModuleTransport({
         code: code,
         sourceCode: code,

From 5ac848cd7f90f55447d9022fec8d864cd032fc93 Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Sat, 16 Jan 2016 02:32:39 -0800
Subject: [PATCH 0759/1411] Allow setting elevation on any type of View

Summary:
Moved setElevation from ReactViewManager to BaseViewManager. This allows
setting elevation on any type of view such as Toolbar for exemple.
Closes https://github.com/facebook/react-native/pull/5292

Reviewed By: svcscm

Differential Revision: D2837415

Pulled By: androidtrunkagent

fb-gh-sync-id: a5aa7abd95b99303d312cd9c2414539335540925
---
 .../com/facebook/react/uimanager/BaseViewManager.java    | 9 +++++++++
 .../com/facebook/react/views/view/ReactViewManager.java  | 8 --------
 2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java
index 26e8adaad0b1..9a697ce3a541 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java
@@ -26,6 +26,7 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
   private static final String PROP_DECOMPOSED_MATRIX_TRANSLATE_X = "translateX";
   private static final String PROP_DECOMPOSED_MATRIX_TRANSLATE_Y = "translateY";
   private static final String PROP_OPACITY = "opacity";
+  private static final String PROP_ELEVATION = "elevation";
   private static final String PROP_RENDER_TO_HARDWARE_TEXTURE = "renderToHardwareTextureAndroid";
   private static final String PROP_ACCESSIBILITY_LABEL = "accessibilityLabel";
   private static final String PROP_ACCESSIBILITY_COMPONENT_TYPE = "accessibilityComponentType";
@@ -63,6 +64,14 @@ public void setDecomposedMatrix(T view, ReadableMap decomposedMatrix) {
   public void setOpacity(T view, float opacity) {
     view.setAlpha(opacity);
   }
+  
+  @ReactProp(name = PROP_ELEVATION)
+  public void setElevation(T view, float elevation) {
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+      view.setElevation(PixelUtil.toPixelFromDIP(elevation));
+    }
+    // Do nothing on API < 21
+  }
 
   @ReactProp(name = PROP_RENDER_TO_HARDWARE_TEXTURE)
   public void setRenderToHardwareTexture(T view, boolean useHWTexture) {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
index 0f3973bd2bb0..5e761b0f7a2e 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
@@ -61,14 +61,6 @@ public void setBorderStyle(ReactViewGroup view, @Nullable String borderStyle) {
     view.setBorderStyle(borderStyle);
   }
 
-  @ReactProp(name = "elevation")
-  public void setElevation(ReactViewGroup view, float elevation) {
-    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-      view.setElevation(PixelUtil.toPixelFromDIP(elevation));
-    }
-    // Do nothing on API < 21
-  }
-
   @ReactProp(name = "pointerEvents")
   public void setPointerEvents(ReactViewGroup view, @Nullable String pointerEventsStr) {
     if (pointerEventsStr != null) {

From 5ea4d397a952e336d6b62ea01d02a4d357cfedcf Mon Sep 17 00:00:00 2001
From: Aleksei Androsov <doochik@ya.ru>
Date: Sat, 16 Jan 2016 14:49:40 +0300
Subject: [PATCH 0760/1411] TextInput should call blur and focus methods of
 selectionState

DocumentSelectionState returns anchor and focus offsets only in focused state. So TextInput should set proper state to selectionState when blur and focus.
---
 Libraries/Components/TextInput/TextInput.js | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js
index b029db359b03..97b201280ec5 100644
--- a/Libraries/Components/TextInput/TextInput.js
+++ b/Libraries/Components/TextInput/TextInput.js
@@ -549,6 +549,10 @@ var TextInput = React.createClass({
     if (this.props.onFocus) {
       this.props.onFocus(event);
     }
+
+    if (this.props.selectionState) {
+      this.props.selectionState.focus();
+    }
   },
 
   _onPress: function(event: Event) {
@@ -589,6 +593,10 @@ var TextInput = React.createClass({
     if (this.props.onBlur) {
       this.props.onBlur(event);
     }
+
+    if (this.props.selectionState) {
+      this.props.selectionState.blur();
+    }
   },
 
   _onTextInput: function(event: Event) {

From 0c53c6f7ed90ceebeb9bc155358cdfee852a7713 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?H=C3=A5vard=20Fossli?= <hfossli@gmail.com>
Date: Wed, 13 Jan 2016 14:18:07 +0100
Subject: [PATCH 0761/1411] Notes about app transport security
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The error message wasn't very helpful. I didn't understand the problem
until I debugged the `RCTJavaScriptLoader`. So this might be to help for
others.

Squashed commits by @andrewsardone into @hfossli’s [original
commit][oc]:

[oc]: https://github.com/andrewsardone/react-native/commit/39fa5ca95b26014c17b3613de5166a587c8bf4c9

- Expand App Transport Security docs w/ localhost tip
- Tweak ATS error note in EmbeddedAppIOS docs
    - Per @satya164’s [recommendation][r], using the exact copy he
      recommended.

[r]: https://github.com/facebook/react-native/pull/5290#discussion_r49843876
---
 docs/EmbeddedAppIOS.md | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/docs/EmbeddedAppIOS.md b/docs/EmbeddedAppIOS.md
index 4c4b9995286e..cb9fd76ce5e8 100644
--- a/docs/EmbeddedAppIOS.md
+++ b/docs/EmbeddedAppIOS.md
@@ -161,6 +161,28 @@ In root directory, we need to start React Native development server.
 
 This command will start up a React Native development server within our CocoaPods dependency to build our bundled script. The `--root` option indicates the root of your React Native apps – this will be our `ReactComponents` directory containing the single `index.ios.js` file. This running server will package up the `index.ios.bundle` file accessible via `http://localhost:8081/index.ios.bundle`.
 
+## Update App Transport Security
+
+On iOS 9 and above the app won't be a able to connect over http to localhost unless specifically told so. See this thread for alternatives and instructions: http://stackoverflow.com/questions/31254725/transport-security-has-blocked-a-cleartext-http.
+
+It is recommended that you add an App Transport Security exception for `localhost` in your app's `Info.plist` file:
+
+```xml
+<key>NSAppTransportSecurity</key>
+<dict>
+    <key>NSExceptionDomains</key>
+    <dict>
+        <key>localhost</key>
+        <dict>
+            <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
+            <true/>
+        </dict>
+    </dict>
+</dict>
+```
+
+If you don't do this, you will see the error - `Could not connect to development server.` when connecting to your server over http.
+
 ## Compile And Run
 
 Now compile and run your app. You shall now see your React Native app running inside of the `ReactView`.

From d8825056fec5beb78b192850deaed89472a8951e Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Sat, 16 Jan 2016 21:56:26 +0000
Subject: [PATCH 0762/1411] Update breaking-changes.md

---
 breaking-changes.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/breaking-changes.md b/breaking-changes.md
index 0d8c5df65246..b7b040319fc4 100644
--- a/breaking-changes.md
+++ b/breaking-changes.md
@@ -1,6 +1,6 @@
 # Breaking Changes
 
-## 0.17
+Breaking changes are now tracked as part of [Release Notes](https://github.com/facebook/react-native/releases).
 
 ## 0.16
 

From 4f390e652fda0a5904a5f03a46a90ee3aa902f62 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Sat, 16 Jan 2016 21:56:57 +0000
Subject: [PATCH 0763/1411] Update breaking-changes.md

---
 breaking-changes.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/breaking-changes.md b/breaking-changes.md
index b7b040319fc4..91e2ce2a2896 100644
--- a/breaking-changes.md
+++ b/breaking-changes.md
@@ -1,6 +1,6 @@
 # Breaking Changes
 
-Breaking changes are now tracked as part of [Release Notes](https://github.com/facebook/react-native/releases).
+**Breaking changes are now tracked as part of [Release Notes](https://github.com/facebook/react-native/releases)**.
 
 ## 0.16
 

From 6411c0c9de89dc6e69cdbe9169f706bfb4dff462 Mon Sep 17 00:00:00 2001
From: Arjun Komath <arjunkomath@gmail.com>
Date: Sun, 17 Jan 2016 13:38:47 +0530
Subject: [PATCH 0764/1411] Add Honest Reviews Android App to Showcase

---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 77cd42f955a5..9215ea856e77 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -246,6 +246,12 @@ var apps = [
     link: 'https://play.google.com/store/apps/details?id=io.scrollback.neighborhoods',
     author: 'Scrollback',
   },
+  {
+    name: 'Honest Reviews',
+    icon: 'http://honestreviews.techulus.com/icon.png',
+    link: 'https://play.google.com/store/apps/details?id=com.techulus.honestreviews&hl=en',
+    author: 'Arjun Komath',
+  },
   {
     name: 'HSK Level 1 Chinese Flashcards',
     icon: 'http://is2.mzstatic.com/image/pf/us/r30/Purple1/v4/b2/4f/3a/b24f3ae3-2597-cc70-1040-731b425a5904/mzl.amxdcktl.jpg',

From 85bf2073f15d372eed15f1a18998fe21c13cdfcf Mon Sep 17 00:00:00 2001
From: Vipul A M <vipulnsward@gmail.com>
Date: Sun, 17 Jan 2016 23:16:51 +0530
Subject: [PATCH 0765/1411] Remove unused ApplicationContext fetch

---
 .../com/facebook/react/modules/clipboard/ClipboardModule.java    | 1 -
 1 file changed, 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java
index b3689f980d9b..412e8edaee9b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java
@@ -71,7 +71,6 @@ public void getString(Callback cb) {
   @SuppressLint("DeprecatedMethod")
   @ReactMethod
   public void setString(String text) {
-    ReactApplicationContext reactContext = getReactApplicationContext();
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
       ClipData clipdata = ClipData.newPlainText(null, text);
       ClipboardManager clipboard = getClipboardService();

From 182e97a62ca0677ae4940ac5f88199ec73ce6295 Mon Sep 17 00:00:00 2001
From: Maksim Ryzhikov <rv.maksim@gmail.com>
Date: Sun, 17 Jan 2016 18:15:38 -0800
Subject: [PATCH 0766/1411] chore: remove extra require

Summary:
We already have require fs [here](https://github.com/maksimr/react-native/blob/patch-cli/local-cli/cli.js#L34)
Closes https://github.com/facebook/react-native/pull/5352

Reviewed By: svcscm

Differential Revision: D2838334

Pulled By: martinbigio

fb-gh-sync-id: 96942b862fee925006687cfba3ad9185a2377a8a
---
 local-cli/cli.js | 1 -
 1 file changed, 1 deletion(-)

diff --git a/local-cli/cli.js b/local-cli/cli.js
index 767c642476d3..ace3251d764c 100644
--- a/local-cli/cli.js
+++ b/local-cli/cli.js
@@ -18,7 +18,6 @@ var childProcess = require('child_process');
 var Config = require('./util/Config');
 var defaultConfig = require('./default.config');
 var dependencies = require('./dependencies/dependencies');
-var fs = require('fs');
 var generate = require('./generate/generate');
 var library = require('./library/library');
 var link = require('./library/link');

From 4de8a4bc6df825e1942018d2620f0f66b8d1a97d Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Mon, 18 Jan 2016 13:20:29 +0000
Subject: [PATCH 0767/1411] Update Animations.md

Remove extra whitespace
---
 docs/Animations.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/Animations.md b/docs/Animations.md
index c4686814c3f7..af8d0031ca1f 100644
--- a/docs/Animations.md
+++ b/docs/Animations.md
@@ -213,13 +213,13 @@ respectively (`gestureState` is the second arg passed to the `PanResponder` hand
 ```javascript
 onScroll={Animated.event(
   // scrollX = e.nativeEvent.contentOffset.x
-  [{nativeEvent: {contentOffset: {x: scrollX}}}]   
+  [{nativeEvent: {contentOffset: {x: scrollX}}}]
 )}
 onPanResponderMove={Animated.event([
   null,                                          // ignore the native event
   // extract dx and dy from gestureState
   // like 'pan.x = gestureState.dx, pan.y = gestureState.dy'
-  {dx: pan.x, dy: pan.y}                         
+  {dx: pan.x, dy: pan.y}
 ]);
 ```
 

From a3706411ab5c8e0d49ab3c1930d223fa40d38a7e Mon Sep 17 00:00:00 2001
From: ahanriat <ahanriat@gmail.com>
Date: Mon, 18 Jan 2016 06:02:16 -0800
Subject: [PATCH 0768/1411] Fix jest preprocessor script

Summary:
Related to #3999

There is an issue with the `preprocessor` script when using node >=5 as it uses npm 3. ~~There are (at least) two solutions, (I'm submitting the first one):~~
- ~~specify min required node version to 5.x and modify [this the preprocessor script](https://github.com/facebook/react-native/blob/0.16-stable/jestSupport/preprocessor.js#L29) to match npm 3 requirements~~
- ~~specifify node version >= 4.x and < 5.x and let the preprocessor script as it is~~

**EDIT**:
Using `require.resolve` will do the trick !

--
Thank you guys for this amazing project by the way ;)
Closes https://github.com/facebook/react-native/pull/4903

Reviewed By: svcscm

Differential Revision: D2838759

Pulled By: androidtrunkagent

fb-gh-sync-id: ebb12f225a519ea23afc4f013bb063a920193719
---
 jestSupport/preprocessor.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/jestSupport/preprocessor.js b/jestSupport/preprocessor.js
index b2006b7d24ce..7d1376b27dde 100644
--- a/jestSupport/preprocessor.js
+++ b/jestSupport/preprocessor.js
@@ -26,6 +26,6 @@ module.exports = {
   getCacheKey: createCacheKeyFunction([
     __filename,
     path.join(__dirname, '../packager/transformer.js'),
-    path.join(__dirname, '../node_modules/babel-core/package.json'),
+    require.resolve('babel-core/package.json'),
   ]),
 };

From 1303e6d0392e8bc4da1198c98fc8cd7ad488b81c Mon Sep 17 00:00:00 2001
From: Alex Roman <Alex@romanink.net>
Date: Mon, 18 Jan 2016 07:47:04 -0800
Subject: [PATCH 0769/1411] Implement XHR timeout for Android and IOS natively.

Summary:
Opening this in a separate PR but the discussion can be viewed on #4832.

Basically, this is a native implementation and is a bit more elegant. The consensus on my previous PR was that it should be done natively rather than in JS.

There's now no maximum valid timeout value and a timeout of 0 will never time out.

ontimeout isn't implemented (yet) in this PR.

cc nicklockwood ide philikon
Closes https://github.com/facebook/react-native/pull/5038

Reviewed By: svcscm

Differential Revision: D2838743

Pulled By: nicklockwood

fb-gh-sync-id: 774f864ac35082bf522f7665f4311bd3affbe82c
---
 Libraries/Network/RCTNetworking.android.js    |  5 ++--
 Libraries/Network/RCTNetworking.m             |  2 +-
 Libraries/Network/XMLHttpRequest.android.js   |  6 ++---
 Libraries/Network/XMLHttpRequest.ios.js       |  3 ++-
 Libraries/Network/XMLHttpRequestBase.js       |  6 +++--
 .../modules/network/NetworkingModule.java     | 10 +++++++-
 .../modules/network/NetworkingModuleTest.java | 24 ++++++++++++-------
 7 files changed, 38 insertions(+), 18 deletions(-)

diff --git a/Libraries/Network/RCTNetworking.android.js b/Libraries/Network/RCTNetworking.android.js
index 351524eb991a..38f694d5452f 100644
--- a/Libraries/Network/RCTNetworking.android.js
+++ b/Libraries/Network/RCTNetworking.android.js
@@ -25,7 +25,7 @@ var generateRequestId = function() {
  */
 class RCTNetworking {
 
-  static sendRequest(method, url, headers, data, useIncrementalUpdates) {
+  static sendRequest(method, url, headers, data, useIncrementalUpdates, timeout) {
     var requestId = generateRequestId();
     RCTNetworkingNative.sendRequest(
       method,
@@ -33,7 +33,8 @@ class RCTNetworking {
       requestId,
       headers,
       data,
-      useIncrementalUpdates);
+      useIncrementalUpdates,
+      timeout);
     return requestId;
   }
 
diff --git a/Libraries/Network/RCTNetworking.m b/Libraries/Network/RCTNetworking.m
index 749541991002..5e30813430d0 100644
--- a/Libraries/Network/RCTNetworking.m
+++ b/Libraries/Network/RCTNetworking.m
@@ -210,7 +210,7 @@ - (RCTURLRequestCancellationBlock)buildRequest:(NSDictionary<NSString *, id> *)q
   NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
   request.HTTPMethod = [RCTConvert NSString:RCTNilIfNull(query[@"method"])].uppercaseString ?: @"GET";
   request.allHTTPHeaderFields = [RCTConvert NSDictionary:query[@"headers"]];
-
+  request.timeoutInterval = [RCTConvert NSTimeInterval:query[@"timeout"]];
   NSDictionary<NSString *, id> *data = [RCTConvert NSDictionary:RCTNilIfNull(query[@"data"])];
   return [self processDataForHTTPQuery:data callback:^(NSError *error, NSDictionary<NSString *, id> *result) {
     if (error) {
diff --git a/Libraries/Network/XMLHttpRequest.android.js b/Libraries/Network/XMLHttpRequest.android.js
index e0ebc77d0afd..165b6d316e29 100644
--- a/Libraries/Network/XMLHttpRequest.android.js
+++ b/Libraries/Network/XMLHttpRequest.android.js
@@ -26,7 +26,7 @@ function convertHeadersMapToArray(headers: Object): Array<Header> {
 }
 
 class XMLHttpRequest extends XMLHttpRequestBase {
-  sendImpl(method: ?string, url: ?string, headers: Object, data: any): void {
+  sendImpl(method: ?string, url: ?string, headers: Object, data: any, timeout: number): void {
     var body;
     if (typeof data === 'string') {
       body = {string: data};
@@ -40,14 +40,14 @@ class XMLHttpRequest extends XMLHttpRequestBase {
     } else {
       body = data;
     }
-
     var useIncrementalUpdates = this.onreadystatechange ? true : false;
     var requestId = RCTNetworking.sendRequest(
       method,
       url,
       convertHeadersMapToArray(headers),
       body,
-      useIncrementalUpdates
+      useIncrementalUpdates,
+      timeout
     );
     this.didCreateRequest(requestId);
   }
diff --git a/Libraries/Network/XMLHttpRequest.ios.js b/Libraries/Network/XMLHttpRequest.ios.js
index 21614ff36163..d79e38019f48 100644
--- a/Libraries/Network/XMLHttpRequest.ios.js
+++ b/Libraries/Network/XMLHttpRequest.ios.js
@@ -23,7 +23,7 @@ class XMLHttpRequest extends XMLHttpRequestBase {
     this.upload = {};
   }
 
-  sendImpl(method: ?string, url: ?string, headers: Object, data: any): void {
+  sendImpl(method: ?string, url: ?string, headers: Object, data: any, timeout: number): void {
     if (typeof data === 'string') {
       data = {string: data};
     } else if (data instanceof FormData) {
@@ -36,6 +36,7 @@ class XMLHttpRequest extends XMLHttpRequestBase {
         data,
         headers,
         incrementalUpdates: this.onreadystatechange ? true : false,
+        timeout
       },
       this.didCreateRequest.bind(this)
     );
diff --git a/Libraries/Network/XMLHttpRequestBase.js b/Libraries/Network/XMLHttpRequestBase.js
index f4c8bc5e246a..1fffb713f971 100644
--- a/Libraries/Network/XMLHttpRequestBase.js
+++ b/Libraries/Network/XMLHttpRequestBase.js
@@ -32,6 +32,7 @@ class XMLHttpRequestBase {
   responseHeaders: ?Object;
   responseText: ?string;
   status: number;
+  timeout: number;
   responseURL: ?string;
 
   upload: ?{
@@ -58,6 +59,7 @@ class XMLHttpRequestBase {
     this.onreadystatechange = null;
     this.onload = null;
     this.upload = undefined; /* Upload not supported yet */
+    this.timeout = 0;
 
     this._reset();
     this._method = null;
@@ -196,7 +198,7 @@ class XMLHttpRequestBase {
     this.setReadyState(this.OPENED);
   }
 
-  sendImpl(method: ?string, url: ?string, headers: Object, data: any): void {
+  sendImpl(method: ?string, url: ?string, headers: Object, data: any, timeout: number): void {
     throw new Error('Subclass must define sendImpl method');
   }
 
@@ -208,7 +210,7 @@ class XMLHttpRequestBase {
       throw new Error('Request has already been sent');
     }
     this._sent = true;
-    this.sendImpl(this._method, this._url, this._headers, data);
+    this.sendImpl(this._method, this._url, this._headers, data, this.timeout);
   }
 
   abort(): void {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
index d1f32616e6a4..9374683b9d8e 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
@@ -15,6 +15,8 @@
 import java.io.InputStream;
 import java.io.Reader;
 
+import java.util.concurrent.TimeUnit;
+
 import com.facebook.react.bridge.Arguments;
 import com.facebook.react.bridge.GuardedAsyncTask;
 import com.facebook.react.bridge.ReactApplicationContext;
@@ -113,19 +115,25 @@ public void onCatalystInstanceDestroy() {
   }
 
   @ReactMethod
+  /**
+  * @param timeout value of 0 results in no timeout
+  */
   public void sendRequest(
       String method,
       String url,
       final int requestId,
       ReadableArray headers,
       ReadableMap data,
-      final boolean useIncrementalUpdates) {
+      final boolean useIncrementalUpdates,
+      int timeout) {
     Request.Builder requestBuilder = new Request.Builder().url(url);
 
     if (requestId != 0) {
       requestBuilder.tag(requestId);
     }
 
+    mClient.setConnectTimeout(timeout, TimeUnit.MILLISECONDS);
+
     Headers requestHeaders = extractHeaders(headers, data);
     if (requestHeaders == null) {
       onRequestError(requestId, "Unrecognized headers format");
diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkingModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkingModuleTest.java
index 454a3cb986af..64884aabdb56 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkingModuleTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkingModuleTest.java
@@ -93,7 +93,8 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
         0,
         SimpleArray.of(),
         null,
-        true);
+        true,
+        0);
 
     ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
     verify(httpClient).newCall(argumentCaptor.capture());
@@ -122,7 +123,8 @@ public void testFailGetWithInvalidHeadersStruct() throws Exception {
         0,
         SimpleArray.from(invalidHeaders),
         null,
-        true);
+        true,
+        0);
 
     verifyErrorEmit(emitter, 0);
   }
@@ -147,7 +149,8 @@ public void testFailPostWithoutContentType() throws Exception {
         0,
         SimpleArray.of(),
         body,
-        true);
+        true,
+        0);
 
     verifyErrorEmit(emitter, 0);
   }
@@ -202,7 +205,8 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
         0,
         SimpleArray.of(SimpleArray.of("Content-Type", "text/plain")),
         body,
-        true);
+        true,
+        0);
 
     ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
     verify(httpClient).newCall(argumentCaptor.capture());
@@ -238,7 +242,8 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
         0,
         SimpleArray.from(headers),
         null,
-        true);
+        true,
+        0);
     ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
     verify(httpClient).newCall(argumentCaptor.capture());
     Headers requestHeaders = argumentCaptor.getValue().headers();
@@ -284,7 +289,8 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
         0,
         new SimpleArray(),
         body,
-        true);
+        true,
+        0);
 
     // verify url, method, headers
     ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
@@ -341,7 +347,8 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
         0,
         SimpleArray.from(headers),
         body,
-        true);
+        true,
+        0);
 
     // verify url, method, headers
     ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
@@ -435,7 +442,8 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
         0,
         SimpleArray.from(headers),
         body,
-        true);
+        true,
+        0);
 
     // verify RequestBodyPart for image
     PowerMockito.verifyStatic(times(1));

From 474b5e9b80a2471da7297cf36139a17a73bbe6a8 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Mon, 18 Jan 2016 16:19:56 +0000
Subject: [PATCH 0770/1411] Update Releases.md

---
 Releases.md | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Releases.md b/Releases.md
index 053a2f321c12..a5e3c02f4396 100644
--- a/Releases.md
+++ b/Releases.md
@@ -49,10 +49,10 @@ Make absolutely sure basic iOS and Android workflow works on master:
     - http://localhost:4873/ will show 0.18.0-rc
   - Test that everything works:
     - `cd /tmp`
-    - `react-native init Zero12rc`
-    - `cd Zero12rc`
+    - `react-native init AwesomeApp`
+    - `cd AwesomeApp`
     - Check that `package.json`, `android/app/build.gradle` have correct versions (`^0.18.0-rc`, `com.facebook.react:react-native:0.18.+`)
-    - `open ios/Zero12rc.xcodeproj`
+    - `open ios/AwesomeApp.xcodeproj`
     - Hit the Run button in Xcode.
     - Packager should open in a new window, you should see the Welcome to React Native screen, Reload JS, try Chrome debugging - put a breakpoint somewhere in `index.ios.js` and Reload JS, Chrome debugger should stop on the breakpoint (we don't have tests for Chrome debugging)
     - Close the packager window, close Xcode

From b8ff6212f84efebcf3ba2de3e1999d3e68e0c574 Mon Sep 17 00:00:00 2001
From: Connor McEwen <connor.mcewen@gmail.com>
Date: Mon, 18 Jan 2016 08:54:14 -0800
Subject: [PATCH 0771/1411] bind this in onreadystatechange call

Summary:
I ran into this problem that `this` is undefined in `onreadystatechange` function calls while using this github api library: https://github.com/michael/github/blob/master/github.js#L72

It seems that in the browser, the `onreadystatechange` function expects `this` to be bound. This example on the xhr spec website can be seen using `this` similarly: https://xhr.spec.whatwg.org/#the-getresponseheader()-method
Closes https://github.com/facebook/react-native/pull/5373

Reviewed By: svcscm

Differential Revision: D2838940

Pulled By: nicklockwood

fb-gh-sync-id: e42184887c7abb0af9c4358a5f33b8c97155624c
---
 Libraries/Network/XMLHttpRequestBase.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/Network/XMLHttpRequestBase.js b/Libraries/Network/XMLHttpRequestBase.js
index 1fffb713f971..29073b7d1ca2 100644
--- a/Libraries/Network/XMLHttpRequestBase.js
+++ b/Libraries/Network/XMLHttpRequestBase.js
@@ -247,7 +247,7 @@ class XMLHttpRequestBase {
     if (onreadystatechange) {
       // We should send an event to handler, but since we don't process that
       // event anywhere, let's leave it empty
-      onreadystatechange(null);
+      onreadystatechange.call(this, null);
     }
     if (newState === this.DONE && !this._aborted) {
       this._sendLoad();

From 58fc0f07bdb885dd21546636c467564b516ac3d7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Felix=20Oghin=C4=83?= <foghina@fb.com>
Date: Mon, 18 Jan 2016 10:03:45 -0800
Subject: [PATCH 0772/1411] add timeout param to remaining RCTNetworking
 implementations

Reviewed By: nicklockwood

Differential Revision: D2839041

fb-gh-sync-id: 374fca9ce0fdf5622f57a10456c99628ca7a1400
---
 .../com/facebook/react/testing/NetworkRecordingModuleMock.java | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/NetworkRecordingModuleMock.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/NetworkRecordingModuleMock.java
index b23ba1e738ce..43a5ebfcee90 100644
--- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/NetworkRecordingModuleMock.java
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/NetworkRecordingModuleMock.java
@@ -83,7 +83,8 @@ public final void sendRequest(
       int requestId,
       ReadableArray headers,
       ReadableMap data,
-      boolean incrementalUpdates) {
+      boolean incrementalUpdates,
+      int timeout) {
     mLastRequestId = requestId;
     mRequestCount++;
     mRequestMethod = method;

From bd9ac0df48555027521a3dff80050b8993f32ada Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Mon, 18 Jan 2016 20:26:07 +0000
Subject: [PATCH 0773/1411] Update Releases.md

---
 Releases.md | 65 ++++++++++++++++++-----------------------------------
 1 file changed, 22 insertions(+), 43 deletions(-)

diff --git a/Releases.md b/Releases.md
index a5e3c02f4396..c6166e09b37f 100644
--- a/Releases.md
+++ b/Releases.md
@@ -19,52 +19,27 @@ Future releases:
 - A lot of these steps could be done by a script
 - We could simplify the process quite a bit by publishing the Android binaries to npm. This will increase the size of the npm package by about 3.3MB. To do that: after `installArchives`, move the binaries to somewhere where `npm publish` will pick them up. Then, change the `build.gradle` file(s) of your generated app so that Gradle will pick up the binaries from `node_modules`. This will likely also **fix issues with incompatible versions of JS and Android binaries** (e.g. [#4488](https://github.com/facebook/react-native/issues/4488)).
 
+## One time setup
+
+Set up Sinopia: https://github.com/facebook/react-native/tree/master/react-native-cli
+
 ## Cut a release branch
 
-Note: Make sure you replace 0.18 in all the commands below with the version you're releasing :) For example, copy-paste all of this into an editor and replace 0.18.
+To cut a release branch and check that everything works, you'll need Mac OS with the [Android dev environment set up](https://github.com/facebook/react-native/blob/master/ReactAndroid/README.md).
+
+Run:
+
+    cd react-native
+    ./scripts/release.sh 0.19   # Replace 0.19 with the version you're cutting the branch for :)
 
 #### Check that everything works
 
-First, set up Sinopia (only need to do this once): https://github.com/facebook/react-native/tree/master/react-native-cli
-
-Make absolutely sure basic iOS and Android workflow works on master:
-  - `cd react-native`
-  - `git pull`
-  - `git checkout -b 0.18-stable`
-  - Edit `ReactAndroid/gradle.properties`, set `VERSION_NAME=0.18.0`
-  - Edit `ReactAndroid/release.gradle`, uncomment Javadoc generation (the line `// archives androidJavadocJar`)
-  - Make sure `java -version` prints 1.7.x, this is currently needed for Javadoc generation and Javadocs are required by Maven Central (we should make it work with Java 8)
-  - Run `./gradlew :ReactAndroid:installArchives`, it will print a lot of Javadoc warnings, that's OK.
-  - Check the artifacts were generated: `ls -al ~/.m2/repository/com/facebook/react/react-native/0.18.0/` should contain:
-    - `react-native-0.18.0-javadoc.jar`, `react-native-0.18.0-sources.jar`, `react-native-0.18.0.aar`, `react-native-0.18.0.pom`
-    - For each of the above also `.asc` file
-  - In `package.json`, set version to e.g. `0.18.0-rc`.
-  - In `React.podspec`, set version to e.g. `0.18.0-rc`.
-  - In `local-cli/generator-android/templates/src/app/build.gradle` update the dependency to e.g. `com.facebook.react:react-native:0.18.+`
-  - Publish to sinopia:
-    - `npm set registry http://localhost:4873/`, check that it worked: `npm config list` will show registry is set to localhost
-    - In a separate shell, start sinopia. Run `sinopia`. If started successfully it will print: http address - http://localhost:4873/.
-    - Make sure http://localhost:4873/ shows no old versions
-    - `npm publish`
-    - http://localhost:4873/ will show 0.18.0-rc
-  - Test that everything works:
-    - `cd /tmp`
-    - `react-native init AwesomeApp`
-    - `cd AwesomeApp`
-    - Check that `package.json`, `android/app/build.gradle` have correct versions (`^0.18.0-rc`, `com.facebook.react:react-native:0.18.+`)
-    - `open ios/AwesomeApp.xcodeproj`
-    - Hit the Run button in Xcode.
-    - Packager should open in a new window, you should see the Welcome to React Native screen, Reload JS, try Chrome debugging - put a breakpoint somewhere in `index.ios.js` and Reload JS, Chrome debugger should stop on the breakpoint (we don't have tests for Chrome debugging)
-    - Close the packager window, close Xcode
-    - Start an Android emulator (ideally Genymotion, it's faster and more reliable than Google emulators)
-    - `react-native run-android`
-    - Test is the same way as on iOS, including Chrome debugging
+Make absolutely sure basic iOS and Android workflow works on master, see the instructions printed by `release.sh`.
   
 #### Push to github
 
-  - Revert the Javadoc change in `ReactAndroid/release.gradle`
-  - `git commit -am "[0.18-rc] Bump version numbers"`
-  - `git push origin 0.18-stable`
+  - Check git history, the last commit should be "[0.19-rc] Bump version numbers" (with the correct version)
+  - `git push origin 0.version_you_are_releasing-stable`
 
 ## Do a release
 
@@ -74,7 +49,7 @@ Publish to Maven Central (Note: **We could get rid of this whole section by publ
   - Add all files: .aar, sources jar, javadoc jar, .asc for everything (including the POM file)
   - Wait a few hours until you see the version has propagated to [JCenter](https://bintray.com/bintray/jcenter/com.facebook.react%3Areact-native/view)
 
-To release 0.18-rc to npm:
+To release to npm:
 
 (You need to be a maintainer of the repo. For admins, here's the command to promote someone)
 
@@ -83,7 +58,7 @@ npm owner add <user> react-native
 ```
 
 ```
-git tag v0.18.0-rc 0.18-stable # don't forget the `v` at the beginning!
+git tag v0.version_you_are_releasing.0-rc 0.version_you_are_releasing-stable # don't forget the `v` at the beginning!
 git push --tags
 ```
 
@@ -92,9 +67,13 @@ git push --tags
 ```
 npm set registry https://registry.npmjs.org/
 npm publish
-# Only when doing a non-rc release:
-npm dist-tag add react-native@0.18.0 latest
+# *Only* when doing a non-rc release:
+# npm dist-tag add react-native@0.non_rc_version.0 latest
 ```
 - Upgrade tags to a release by going to https://github.com/facebook/react-native/tags
 - Click "Add Notes to release"
-- Click Publish
+- Click Publishd
+
+## Track bug reports from the community during the following two weeks and make sure they get fixed
+
+A good way to do this is to create a github issue and post about it so people can report bugs: https://github.com/facebook/react-native/issues/5201

From 2bc482257af819d12d5dbd27363341a49cebb36b Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Mon, 18 Jan 2016 20:26:57 +0000
Subject: [PATCH 0774/1411] Update Releases.md

---
 Releases.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Releases.md b/Releases.md
index c6166e09b37f..5e37bfd4f909 100644
--- a/Releases.md
+++ b/Releases.md
@@ -72,7 +72,7 @@ npm publish
 ```
 - Upgrade tags to a release by going to https://github.com/facebook/react-native/tags
 - Click "Add Notes to release"
-- Click Publishd
+- Click Publish
 
 ## Track bug reports from the community during the following two weeks and make sure they get fixed
 

From b6c1593d14f7daeae5fba5762c5fff4e560e5fe6 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Mon, 18 Jan 2016 20:37:55 +0000
Subject: [PATCH 0775/1411] [docs] Split release docs into two files

---
 Releases-publish.md | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
 create mode 100644 Releases-publish.md

diff --git a/Releases-publish.md b/Releases-publish.md
new file mode 100644
index 000000000000..7aad264e098a
--- /dev/null
+++ b/Releases-publish.md
@@ -0,0 +1,32 @@
+## Publish a release (same steps for an rc version, 0.x.0)
+
+Publish to Maven Central (Note: **We could get rid of this whole section by publishing binaries to npm instead**):
+  - Log into Sonatype and go to [Staging upload](https://oss.sonatype.org/#staging-upload). You'll need to get permissions for this by filing a ticket explaining you're a core contributor to React Native. [Example ticket](https://issues.sonatype.org/browse/OSSRH-11885).
+  - Select Artifact(s) with a POM (to publish to a local Maven repo for testing run `./gradlew :ReactAndroid:installArchives`)
+  - Add all files: .aar, sources jar, javadoc jar, .asc for everything (including the POM file)
+  - Wait a few hours until you see the version has propagated to [JCenter](https://bintray.com/bintray/jcenter/com.facebook.react%3Areact-native/view)
+
+To release to npm:
+
+(You need to be a maintainer of the repo. For admins, here's the command to promote someone)
+
+```
+npm owner add <user> react-native
+```
+
+```
+git tag v0.version_you_are_releasing.0-rc 0.version_you_are_releasing-stable # don't forget the `v` at the beginning!
+git push --tags
+```
+
+- Publish to npm
+
+```
+npm set registry https://registry.npmjs.org/
+npm publish
+# *Only* when doing a non-rc release:
+# npm dist-tag add react-native@0.non_rc_version.0 latest
+```
+- Upgrade tags to a release by going to https://github.com/facebook/react-native/tags
+- Click "Add Notes to release"
+- Click Publish
\ No newline at end of file

From 9fea48513807460bd4d2abdd8612f43480ddd2c2 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Mon, 18 Jan 2016 12:37:59 -0800
Subject: [PATCH 0776/1411] Build React Native with Buck

Reviewed By: bestander

Differential Revision: D2834002

fb-gh-sync-id: ebd5303a05fe9a01545365e4205d4cb8724a77a8
---
 .buckconfig                                         |   8 ++++++++
 ReactAndroid/build.gradle                           |   3 ++-
 .../java/com/facebook/soloader/ApkSoSource.java     |   0
 .../com/facebook/soloader/DirectorySoSource.java    |   0
 .../java/com/facebook/soloader/Elf32_Dyn.java       |   0
 .../java/com/facebook/soloader/Elf32_Ehdr.java      |   0
 .../java/com/facebook/soloader/Elf32_Phdr.java      |   0
 .../java/com/facebook/soloader/Elf32_Shdr.java      |   0
 .../java/com/facebook/soloader/Elf64_Dyn.java       |   0
 .../java/com/facebook/soloader/Elf64_Ehdr.java      |   0
 .../java/com/facebook/soloader/Elf64_Phdr.java      |   0
 .../java/com/facebook/soloader/Elf64_Shdr.java      |   0
 .../java/com/facebook/soloader/ExoSoSource.java     |   0
 .../java/com/facebook/soloader/FileLocker.java      |   0
 .../java/com/facebook/soloader/MinElf.java          |   0
 .../java/com/facebook/soloader/NativeLibrary.java   |   0
 .../java/com/facebook/soloader/NoopSoSource.java    |   0
 .../java/com/facebook/soloader/SoLoader.java        |   0
 .../java/com/facebook/soloader/SoSource.java        |   0
 .../java/com/facebook/soloader/SysUtil.java         |   0
 .../java/com/facebook/soloader/genstructs.sh        |   0
 .../java/com/facebook/soloader/soloader.pro         |   0
 .../infer-annotations}/infer-annotations-1.5.jar    | Bin
 23 files changed, 10 insertions(+), 1 deletion(-)
 create mode 100644 .buckconfig
 rename ReactAndroid/src/main/{ => libraries/soloader}/java/com/facebook/soloader/ApkSoSource.java (100%)
 rename ReactAndroid/src/main/{ => libraries/soloader}/java/com/facebook/soloader/DirectorySoSource.java (100%)
 rename ReactAndroid/src/main/{ => libraries/soloader}/java/com/facebook/soloader/Elf32_Dyn.java (100%)
 rename ReactAndroid/src/main/{ => libraries/soloader}/java/com/facebook/soloader/Elf32_Ehdr.java (100%)
 rename ReactAndroid/src/main/{ => libraries/soloader}/java/com/facebook/soloader/Elf32_Phdr.java (100%)
 rename ReactAndroid/src/main/{ => libraries/soloader}/java/com/facebook/soloader/Elf32_Shdr.java (100%)
 rename ReactAndroid/src/main/{ => libraries/soloader}/java/com/facebook/soloader/Elf64_Dyn.java (100%)
 rename ReactAndroid/src/main/{ => libraries/soloader}/java/com/facebook/soloader/Elf64_Ehdr.java (100%)
 rename ReactAndroid/src/main/{ => libraries/soloader}/java/com/facebook/soloader/Elf64_Phdr.java (100%)
 rename ReactAndroid/src/main/{ => libraries/soloader}/java/com/facebook/soloader/Elf64_Shdr.java (100%)
 rename ReactAndroid/src/main/{ => libraries/soloader}/java/com/facebook/soloader/ExoSoSource.java (100%)
 rename ReactAndroid/src/main/{ => libraries/soloader}/java/com/facebook/soloader/FileLocker.java (100%)
 rename ReactAndroid/src/main/{ => libraries/soloader}/java/com/facebook/soloader/MinElf.java (100%)
 rename ReactAndroid/src/main/{ => libraries/soloader}/java/com/facebook/soloader/NativeLibrary.java (100%)
 rename ReactAndroid/src/main/{ => libraries/soloader}/java/com/facebook/soloader/NoopSoSource.java (100%)
 rename ReactAndroid/src/main/{ => libraries/soloader}/java/com/facebook/soloader/SoLoader.java (100%)
 rename ReactAndroid/src/main/{ => libraries/soloader}/java/com/facebook/soloader/SoSource.java (100%)
 rename ReactAndroid/src/main/{ => libraries/soloader}/java/com/facebook/soloader/SysUtil.java (100%)
 rename ReactAndroid/src/main/{ => libraries/soloader}/java/com/facebook/soloader/genstructs.sh (100%)
 rename ReactAndroid/src/main/{ => libraries/soloader}/java/com/facebook/soloader/soloader.pro (100%)
 rename ReactAndroid/{libs => src/main/third-party/java/infer-annotations}/infer-annotations-1.5.jar (100%)

diff --git a/.buckconfig b/.buckconfig
new file mode 100644
index 000000000000..cc1b6556849d
--- /dev/null
+++ b/.buckconfig
@@ -0,0 +1,8 @@
+
+[android]
+  target = Google Inc.:Google APIs:23
+
+[maven_repositories]
+  central = https://repo1.maven.org/maven2
+
+
diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle
index 9721ee4dd6d4..d1dffee7bb32 100644
--- a/ReactAndroid/build.gradle
+++ b/ReactAndroid/build.gradle
@@ -228,6 +228,7 @@ android {
         jniLibs.srcDir "$buildDir/react-ndk/exported"
         res.srcDirs = ['src/main/res/devsupport', 'src/main/res/shell']
         java {
+          srcDirs = ['src/main/java', 'src/main/libraries/soloader']
           exclude 'com/facebook/react/processing'
         }
     }
@@ -244,7 +245,7 @@ android {
 }
 
 dependencies {
-    compile fileTree(dir: 'libs', include: ['*.jar'])
+    compile fileTree(dir: 'src/main/third-party/java/infer-annotations/', include: ['*.jar'])
     compile 'com.android.support:appcompat-v7:23.0.1'
     compile 'com.android.support:recyclerview-v7:23.0.1'
     compile 'com.facebook.fresco:fresco:0.8.1'
diff --git a/ReactAndroid/src/main/java/com/facebook/soloader/ApkSoSource.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/ApkSoSource.java
similarity index 100%
rename from ReactAndroid/src/main/java/com/facebook/soloader/ApkSoSource.java
rename to ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/ApkSoSource.java
diff --git a/ReactAndroid/src/main/java/com/facebook/soloader/DirectorySoSource.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/DirectorySoSource.java
similarity index 100%
rename from ReactAndroid/src/main/java/com/facebook/soloader/DirectorySoSource.java
rename to ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/DirectorySoSource.java
diff --git a/ReactAndroid/src/main/java/com/facebook/soloader/Elf32_Dyn.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Dyn.java
similarity index 100%
rename from ReactAndroid/src/main/java/com/facebook/soloader/Elf32_Dyn.java
rename to ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Dyn.java
diff --git a/ReactAndroid/src/main/java/com/facebook/soloader/Elf32_Ehdr.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Ehdr.java
similarity index 100%
rename from ReactAndroid/src/main/java/com/facebook/soloader/Elf32_Ehdr.java
rename to ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Ehdr.java
diff --git a/ReactAndroid/src/main/java/com/facebook/soloader/Elf32_Phdr.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Phdr.java
similarity index 100%
rename from ReactAndroid/src/main/java/com/facebook/soloader/Elf32_Phdr.java
rename to ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Phdr.java
diff --git a/ReactAndroid/src/main/java/com/facebook/soloader/Elf32_Shdr.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Shdr.java
similarity index 100%
rename from ReactAndroid/src/main/java/com/facebook/soloader/Elf32_Shdr.java
rename to ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Shdr.java
diff --git a/ReactAndroid/src/main/java/com/facebook/soloader/Elf64_Dyn.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Dyn.java
similarity index 100%
rename from ReactAndroid/src/main/java/com/facebook/soloader/Elf64_Dyn.java
rename to ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Dyn.java
diff --git a/ReactAndroid/src/main/java/com/facebook/soloader/Elf64_Ehdr.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Ehdr.java
similarity index 100%
rename from ReactAndroid/src/main/java/com/facebook/soloader/Elf64_Ehdr.java
rename to ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Ehdr.java
diff --git a/ReactAndroid/src/main/java/com/facebook/soloader/Elf64_Phdr.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Phdr.java
similarity index 100%
rename from ReactAndroid/src/main/java/com/facebook/soloader/Elf64_Phdr.java
rename to ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Phdr.java
diff --git a/ReactAndroid/src/main/java/com/facebook/soloader/Elf64_Shdr.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Shdr.java
similarity index 100%
rename from ReactAndroid/src/main/java/com/facebook/soloader/Elf64_Shdr.java
rename to ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Shdr.java
diff --git a/ReactAndroid/src/main/java/com/facebook/soloader/ExoSoSource.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/ExoSoSource.java
similarity index 100%
rename from ReactAndroid/src/main/java/com/facebook/soloader/ExoSoSource.java
rename to ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/ExoSoSource.java
diff --git a/ReactAndroid/src/main/java/com/facebook/soloader/FileLocker.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/FileLocker.java
similarity index 100%
rename from ReactAndroid/src/main/java/com/facebook/soloader/FileLocker.java
rename to ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/FileLocker.java
diff --git a/ReactAndroid/src/main/java/com/facebook/soloader/MinElf.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/MinElf.java
similarity index 100%
rename from ReactAndroid/src/main/java/com/facebook/soloader/MinElf.java
rename to ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/MinElf.java
diff --git a/ReactAndroid/src/main/java/com/facebook/soloader/NativeLibrary.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/NativeLibrary.java
similarity index 100%
rename from ReactAndroid/src/main/java/com/facebook/soloader/NativeLibrary.java
rename to ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/NativeLibrary.java
diff --git a/ReactAndroid/src/main/java/com/facebook/soloader/NoopSoSource.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/NoopSoSource.java
similarity index 100%
rename from ReactAndroid/src/main/java/com/facebook/soloader/NoopSoSource.java
rename to ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/NoopSoSource.java
diff --git a/ReactAndroid/src/main/java/com/facebook/soloader/SoLoader.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/SoLoader.java
similarity index 100%
rename from ReactAndroid/src/main/java/com/facebook/soloader/SoLoader.java
rename to ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/SoLoader.java
diff --git a/ReactAndroid/src/main/java/com/facebook/soloader/SoSource.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/SoSource.java
similarity index 100%
rename from ReactAndroid/src/main/java/com/facebook/soloader/SoSource.java
rename to ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/SoSource.java
diff --git a/ReactAndroid/src/main/java/com/facebook/soloader/SysUtil.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/SysUtil.java
similarity index 100%
rename from ReactAndroid/src/main/java/com/facebook/soloader/SysUtil.java
rename to ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/SysUtil.java
diff --git a/ReactAndroid/src/main/java/com/facebook/soloader/genstructs.sh b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/genstructs.sh
similarity index 100%
rename from ReactAndroid/src/main/java/com/facebook/soloader/genstructs.sh
rename to ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/genstructs.sh
diff --git a/ReactAndroid/src/main/java/com/facebook/soloader/soloader.pro b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/soloader.pro
similarity index 100%
rename from ReactAndroid/src/main/java/com/facebook/soloader/soloader.pro
rename to ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/soloader.pro
diff --git a/ReactAndroid/libs/infer-annotations-1.5.jar b/ReactAndroid/src/main/third-party/java/infer-annotations/infer-annotations-1.5.jar
similarity index 100%
rename from ReactAndroid/libs/infer-annotations-1.5.jar
rename to ReactAndroid/src/main/third-party/java/infer-annotations/infer-annotations-1.5.jar

From 2c6d9d8e142b34c37ccec797d43a24af43a5799d Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Mon, 18 Jan 2016 20:40:13 +0000
Subject: [PATCH 0777/1411] Update Releases.md

---
 Releases.md | 31 +------------------------------
 1 file changed, 1 insertion(+), 30 deletions(-)

diff --git a/Releases.md b/Releases.md
index 5e37bfd4f909..70b184ff0bcb 100644
--- a/Releases.md
+++ b/Releases.md
@@ -43,36 +43,7 @@ Make absolutely sure basic iOS and Android workflow works on master, see the ins
 
 ## Do a release
 
-Publish to Maven Central (Note: **We could get rid of this whole section by publishing binaries to npm instead**):
-  - Log into Sonatype and go to [Staging upload](https://oss.sonatype.org/#staging-upload). You'll need to get permissions for this by filing a ticket explaining you're a core contributor to React Native. [Example ticket](https://issues.sonatype.org/browse/OSSRH-11885).
-  - Select Artifact(s) with a POM (to publish to a local Maven repo for testing run `./gradlew :ReactAndroid:installArchives`)
-  - Add all files: .aar, sources jar, javadoc jar, .asc for everything (including the POM file)
-  - Wait a few hours until you see the version has propagated to [JCenter](https://bintray.com/bintray/jcenter/com.facebook.react%3Areact-native/view)
-
-To release to npm:
-
-(You need to be a maintainer of the repo. For admins, here's the command to promote someone)
-
-```
-npm owner add <user> react-native
-```
-
-```
-git tag v0.version_you_are_releasing.0-rc 0.version_you_are_releasing-stable # don't forget the `v` at the beginning!
-git push --tags
-```
-
-- Publish to npm
-
-```
-npm set registry https://registry.npmjs.org/
-npm publish
-# *Only* when doing a non-rc release:
-# npm dist-tag add react-native@0.non_rc_version.0 latest
-```
-- Upgrade tags to a release by going to https://github.com/facebook/react-native/tags
-- Click "Add Notes to release"
-- Click Publish
+Skip this for now, ping @mkonicek on messenger and he'll handle it. Docs [here](https://github.com/facebook/react-native/blob/master/Releases-publish.md).
 
 ## Track bug reports from the community during the following two weeks and make sure they get fixed
 

From daf0bd4cea724e7e1856da3d095fcfc767d236dc Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Mon, 18 Jan 2016 20:40:41 +0000
Subject: [PATCH 0778/1411] Update Releases.md

---
 Releases.md | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/Releases.md b/Releases.md
index 70b184ff0bcb..445e121de332 100644
--- a/Releases.md
+++ b/Releases.md
@@ -14,11 +14,6 @@ Future releases:
 - 0.20.0 - Feb 15
 - ...
 
-## Ideas for improvements
-
-- A lot of these steps could be done by a script
-- We could simplify the process quite a bit by publishing the Android binaries to npm. This will increase the size of the npm package by about 3.3MB. To do that: after `installArchives`, move the binaries to somewhere where `npm publish` will pick them up. Then, change the `build.gradle` file(s) of your generated app so that Gradle will pick up the binaries from `node_modules`. This will likely also **fix issues with incompatible versions of JS and Android binaries** (e.g. [#4488](https://github.com/facebook/react-native/issues/4488)).
-
 ## One time setup
 
 Set up Sinopia: https://github.com/facebook/react-native/tree/master/react-native-cli

From f471be7380c62a291b58b704a34a2fd48cd750d7 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Mon, 18 Jan 2016 20:41:11 +0000
Subject: [PATCH 0779/1411] Update Releases-publish.md

---
 Releases-publish.md | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/Releases-publish.md b/Releases-publish.md
index 7aad264e098a..07aec7a77eb7 100644
--- a/Releases-publish.md
+++ b/Releases-publish.md
@@ -1,3 +1,7 @@
+## Ideas for improvements
+
+We could simplify the process quite a bit by publishing the Android binaries to npm. This will increase the size of the npm package by about 3.3MB. To do that: after `installArchives`, move the binaries to somewhere where `npm publish` will pick them up. Then, change the `build.gradle` file(s) of your generated app so that Gradle will pick up the binaries from `node_modules`. This will likely also **fix issues with incompatible versions of JS and Android binaries** (e.g. [#4488](https://github.com/facebook/react-native/issues/4488)).
+
 ## Publish a release (same steps for an rc version, 0.x.0)
 
 Publish to Maven Central (Note: **We could get rid of this whole section by publishing binaries to npm instead**):
@@ -29,4 +33,4 @@ npm publish
 ```
 - Upgrade tags to a release by going to https://github.com/facebook/react-native/tags
 - Click "Add Notes to release"
-- Click Publish
\ No newline at end of file
+- Click Publish

From 3453a60bf8c23a1d329c8dc19dfd64d8c705421c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emil=20Sj=C3=B6lander?= <sjolander.emil@gmail.com>
Date: Mon, 18 Jan 2016 12:41:41 -0800
Subject: [PATCH 0780/1411] Escape directory path in packager.sh

Summary:
Previously could not handle directory paths with spaces.
Closes https://github.com/facebook/react-native/pull/5381

Reviewed By: svcscm

Differential Revision: D2839193

Pulled By: javache

fb-gh-sync-id: e95825a602c053761826255ac5254b97fadbe090
---
 packager/launchPackager.command | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packager/launchPackager.command b/packager/launchPackager.command
index 0d08a298a759..56683667df92 100755
--- a/packager/launchPackager.command
+++ b/packager/launchPackager.command
@@ -12,7 +12,7 @@ echo -en "\033]0;React Packager\a"
 clear
 
 THIS_DIR=$(dirname "$0")
-pushd $THIS_DIR
+pushd "$THIS_DIR"
 source packager.sh
 popd
 

From bd4bf8ca39c187c7aaadcaf5d27d411a68e60a6f Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Mon, 18 Jan 2016 13:56:19 -0800
Subject: [PATCH 0781/1411] Fix a crash in ViewPagerAndroid when passing a null
 child

Summary:
Fixes #5195
Closes https://github.com/facebook/react-native/pull/5236

Reviewed By: svcscm

Differential Revision: D2819197

Pulled By: androidtrunkagent

fb-gh-sync-id: cea451802c659512f64c1e90905647b8fbe4490b
---
 Libraries/Components/ViewPager/ViewPagerAndroid.android.js | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Libraries/Components/ViewPager/ViewPagerAndroid.android.js b/Libraries/Components/ViewPager/ViewPagerAndroid.android.js
index e5708d5ebaf0..360f847a84ae 100644
--- a/Libraries/Components/ViewPager/ViewPagerAndroid.android.js
+++ b/Libraries/Components/ViewPager/ViewPagerAndroid.android.js
@@ -112,6 +112,9 @@ var ViewPagerAndroid = React.createClass({
     // will handle positioning of elements, so it's not important to offset
     // them correctly.
     return React.Children.map(this.props.children, function(child) {
+      if (!child) {
+        return null;
+      }
       var newProps = {
         ...child.props,
         style: [child.props.style, {

From 88c2aa61b95a06acacf28b1f75505ae11691a496 Mon Sep 17 00:00:00 2001
From: Huang Yu <trave7er@users.noreply.github.com>
Date: Mon, 18 Jan 2016 14:27:51 -0800
Subject: [PATCH 0782/1411] fix lint warnings

Summary:
added two semi colons, separated from other lint commits to avoid potential conflicts
Closes https://github.com/facebook/react-native/pull/5217

Reviewed By: svcscm

Differential Revision: D2818391

Pulled By: mkonicek

fb-gh-sync-id: 94e3640a30fb7ab932b15bfd84a0ab346c82d5d7
---
 Libraries/Utilities/MessageQueue.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/Utilities/MessageQueue.js b/Libraries/Utilities/MessageQueue.js
index 1eb3c5c65795..f22094bbead0 100644
--- a/Libraries/Utilities/MessageQueue.js
+++ b/Libraries/Utilities/MessageQueue.js
@@ -110,7 +110,7 @@ class MessageQueue {
 
   processModuleConfig(config, moduleID) {
     const module = this._genModule(config, moduleID);
-    this._genLookup(config, moduleID, this._remoteModuleTable, this._remoteMethodTable)
+    this._genLookup(config, moduleID, this._remoteModuleTable, this._remoteMethodTable);
     return module;
   }
 

From e36de0a8588d183e7afab1209d40139f5fdc0331 Mon Sep 17 00:00:00 2001
From: "Dotan J. Nahum" <jondotan@gmail.com>
Date: Mon, 18 Jan 2016 14:58:37 -0800
Subject: [PATCH 0783/1411] small typo correction

Summary: Closes https://github.com/facebook/react-native/pull/5385

Reviewed By: svcscm

Differential Revision: D2839339

Pulled By: androidtrunkagent

fb-gh-sync-id: ff1c8663daf2c65dd387a51ef3b37f2118fc8da1
---
 .../main/java/com/facebook/react/uimanager/UIManagerModule.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
index b352f4d53e61..2a701d692983 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
@@ -40,7 +40,7 @@
  *
  * <p>
  * <h2>== Transactional Requirement ==</h2>
- * A requirement of this class is to make sure that transactional UI updates occur all at, meaning
+ * A requirement of this class is to make sure that transactional UI updates occur all at once, meaning
  * that no intermediate state is ever rendered to the screen. For example, if a JS application
  * update changes the background of View A to blue and the width of View B to 100, both need to
  * appear at once. Practically, this means that all UI update code related to a single transaction

From 05e8681cf4cb2123c130ec93cab4ab8b057d0148 Mon Sep 17 00:00:00 2001
From: Max Johnson <maxj@dropbox.com>
Date: Mon, 18 Jan 2016 16:21:18 -0800
Subject: [PATCH 0784/1411] Add Round to showcase

Summary:
Adding Round, a design-focused medication reminder and pill tracking app built almost entirely in React.
Closes https://github.com/facebook/react-native/pull/5389

Reviewed By: svcscm

Differential Revision: D2839411

Pulled By: androidtrunkagent

fb-gh-sync-id: dfa6eea72d24d4141610f97b33dc7203fb6d0cbf
---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 9215ea856e77..f1b58706d17a 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -428,6 +428,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/rota-worker-shifts-on-demand/id1042111289?mt=8',
     author: 'Rota',
   },
+  {
+    name: 'Round - A better way to remember your medicine',
+    icon: 'https://s3.mzstatic.com/us/r30/Purple69/v4/d3/ee/54/d3ee54cf-13b6-5f56-0edc-6c70ac90b2be/icon175x175.png',
+    link: 'https://itunes.apple.com/us/app/round-beautiful-medication/id1059591124?mt=8',
+    author: 'Circadian Design',
+  },
   {
     name: 'RWpodPlayer - audio player for RWpod podcast',
     icon: 'http://a1.mzstatic.com/us/r30/Purple69/v4/a8/c0/b1/a8c0b130-e44b-742d-6458-0c89fcc15b6b/icon175x175.png',

From 1b5b42f3cb594edbfef73e80763c826f2890885a Mon Sep 17 00:00:00 2001
From: James Ide <ide@jameside.com>
Date: Mon, 18 Jan 2016 17:36:28 -0800
Subject: [PATCH 0785/1411] Remove npm 2 recommendation

Summary:
npm 3 is working fine especially if you use shrinkwrap at the end. we've been using it for a month+ and the dependency deduping works well.
Closes https://github.com/facebook/react-native/pull/5391

Reviewed By: svcscm

Differential Revision: D2839472

Pulled By: androidtrunkagent

fb-gh-sync-id: 33e551185236694ee5979da701312f12e2582f3c
---
 docs/EmbeddedAppIOS.md | 1 -
 docs/GettingStarted.md | 1 -
 2 files changed, 2 deletions(-)

diff --git a/docs/EmbeddedAppIOS.md b/docs/EmbeddedAppIOS.md
index cb9fd76ce5e8..2082070ba16f 100644
--- a/docs/EmbeddedAppIOS.md
+++ b/docs/EmbeddedAppIOS.md
@@ -14,7 +14,6 @@ Since React makes no assumptions about the rest of your technology stack – it
 - [CocoaPods](http://cocoapods.org/) – `gem install cocoapods`
 - [Node.js](http://nodejs.org)
   - Install **nvm** with [its setup instructions here](https://github.com/creationix/nvm#installation). Then run `nvm install node && nvm alias default node`, which installs the latest version of Node.js and sets up your terminal so you can run it by typing `node`.  With nvm you can install multiple versions of Node.js and easily switch between them.
-  - If you are using Node 5.0 or newer, we recommend installing npm 2, which is much faster than npm 3. After installing Node, run `npm install -g npm@2`
 - Install the `react-native` package from npm by running the following command in the root directory of your project:
   - `npm install react-native`
 
diff --git a/docs/GettingStarted.md b/docs/GettingStarted.md
index 5c44b389d86d..cc83191d1140 100644
--- a/docs/GettingStarted.md
+++ b/docs/GettingStarted.md
@@ -13,7 +13,6 @@ next: android-setup
 2. [Homebrew](http://brew.sh/) is the recommended way to install Watchman and Flow.
 3. Install [Node.js](https://nodejs.org/) 4.0 or newer.
   - Install **nvm** with [its setup instructions here](https://github.com/creationix/nvm#installation). Then run `nvm install node && nvm alias default node`, which installs the latest version of Node.js and sets up your terminal so you can run it by typing `node`. With nvm you can install multiple versions of Node.js and easily switch between them.
-  - If you are using Node 5.0 or newer, we recommend installing npm 2, which is much faster than npm 3. After installing Node, run `npm install -g npm@2`.
   - New to [npm](https://docs.npmjs.com/)?
 4. `brew install watchman`. We recommend installing [watchman](https://facebook.github.io/watchman/docs/install.html), otherwise you might hit a node file watching bug.
 5. `brew install flow`, if you want to use [flow](http://www.flowtype.org).

From 1f501a9431a56a357987dcf42520c0626b713b50 Mon Sep 17 00:00:00 2001
From: Almouro <contact@almouro.com>
Date: Mon, 18 Jan 2016 19:30:43 -0800
Subject: [PATCH 0786/1411] Fix image orientation on Android for local uris

Summary:
In Android, when displaying an image with local uri, react-native seems to fail to rotate it according to Exif.
Images on iOS seem like they are being rotated, so this does not seem like a consistent behaviour.

For instance, when taking a picture on a Samsung Galaxy S6, and displaying it with code like below, image does not have a correct orientation.
```javascript
<Image source={{uri: "file:/storage/emulated/0/DCIM/Camera/20160106_171628.jpg"}} />
```
<img src="https://cloud.githubusercontent.com/assets/4534323/12403776/aa5075cc-be36-11e5-885a-7be8236a7fdd.jpg" width=200 />

As seen [here](http://frescolib.org/docs/resizing-rotating.html#auto-rotation), Fresco can do all the work for us (hence this very simple PR).
I tested it on Samsung Galaxy S6 (lollipop), Galaxy S4 (kitkat) and Moto X Style (marshmallow).

I have written an example that fetches images uri from the Java side and then display them in a list view.
[Here](https://github.com/Almouro/rn-camera-roll/tree/use-react-native-master
Closes https://github.com/facebook/react-native/pull/5386

Reviewed By: svcscm

Differential Revision: D2839551

Pulled By: androidtrunkagent

fb-gh-sync-id: 6f0f2f301f263fd142dfbeba6a53f8c482fb5cb0
---
 .../main/java/com/facebook/react/views/image/ReactImageView.java | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
index b0c8b74267e0..515c957d0aeb 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
@@ -279,6 +279,7 @@ public void maybeUpdateView() {
     ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(mUri)
         .setPostprocessor(postprocessor)
         .setResizeOptions(resizeOptions)
+        .setAutoRotateEnabled(true)
         .setProgressiveRenderingEnabled(mProgressiveRenderingEnabled)
         .build();
 

From c8355d377fc5a842a6b7c5be457015847808aa05 Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Tue, 19 Jan 2016 11:09:52 -0800
Subject: [PATCH 0787/1411] Don't register classes only found at runtime

Summary:
This caused issues for me when I tried to provide a native module on init that was also KVO'd (and dynamically subclassed)

On closer inspection, it also seems highly inconsistent to register these classes in DEBUG mode but have them fail silently in production. Reducing the difference between debug and release seems like a safer option.

public

Reviewed By: nicklockwood

Differential Revision: D2819838

fb-gh-sync-id: 79ab72b1152c89eae38c965ff7724aba59a00949
---
 React/Base/RCTBridge.m | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m
index c751fca96716..650d3c958d63 100644
--- a/React/Base/RCTBridge.m
+++ b/React/Base/RCTBridge.m
@@ -57,6 +57,9 @@ void RCTRegisterModule(Class moduleClass)
 
   // Register module
   [RCTModuleClasses addObject:moduleClass];
+
+  objc_setAssociatedObject(moduleClass, &RCTBridgeModuleClassIsRegistered,
+                           @NO, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
 }
 
 /**
@@ -118,10 +121,6 @@ + (void)initialize
           if (![RCTModuleClasses containsObject:cls]) {
             RCTLogWarn(@"Class %@ was not exported. Did you forget to use "
                        "RCT_EXPORT_MODULE()?", cls);
-
-            RCTRegisterModule(cls);
-            objc_setAssociatedObject(cls, &RCTBridgeModuleClassIsRegistered,
-                                     @NO, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
           }
           break;
         }

From a10b4d8c479b2c21dffb0a2bbc76435b7ebfa009 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Tue, 19 Jan 2016 12:09:01 -0800
Subject: [PATCH 0788/1411] Standardize Error objects for Promises

Summary:
public

Promises are coming.  And as part of it, we are standardizing the error objects that will be returned.  This puts the code in place on the Android side to always send the proper error format.

It will be an error object like this
`{
  code : "E_SOME_ERROR_CODE_DEFINED_BY_MODULE", // Meant to be machine parseable
  message : "Human readable message",
  nativeError : {} // Some representation of the underlying error (Exception or NSError) , still figuring out exactly, but hopefully something with stack info
}`

Reviewed By: davidaurelio

Differential Revision: D2839927

fb-gh-sync-id: 08f1ce79af24d70357b9957f14471a12627dcffa
---
 .../com/facebook/react/bridge/Promise.java    |  3 +++
 .../facebook/react/bridge/PromiseImpl.java    | 22 +++++++++++++++++--
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/Promise.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/Promise.java
index 92ce60699ce8..84b802b28aff 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/Promise.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/Promise.java
@@ -19,5 +19,8 @@
 public interface Promise {
   void resolve(Object value);
   void reject(Throwable reason);
+  @Deprecated
   void reject(String reason);
+  void reject(String code, Throwable extra);
+  void reject(String code, String reason, Throwable extra);
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/PromiseImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/PromiseImpl.java
index d6e25b694fb9..efbc4537592d 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/PromiseImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/PromiseImpl.java
@@ -15,6 +15,9 @@
 import javax.annotation.Nullable;
 
 public class PromiseImpl implements Promise {
+
+  private static final String DEFAULT_ERROR = "EUNSPECIFIED";
+
   private @Nullable Callback mResolve;
   private @Nullable Callback mReject;
 
@@ -32,18 +35,33 @@ public void resolve(Object value) {
 
   @Override
   public void reject(Throwable reason) {
-    reject(reason.getMessage());
+    reject(DEFAULT_ERROR, reason.getMessage(), reason);
   }
 
   @Override
+  @Deprecated
   public void reject(String reason) {
+    reject(DEFAULT_ERROR, reason, null);
+  }
+
+  @Override
+  public void reject(String code, Throwable extra) {
+    reject(code, extra.getMessage(), extra);
+  }
+
+  @Override
+  public void reject(String code, String reason, Throwable extra) {
     if (mReject != null) {
+      if (code == null) {
+        code = DEFAULT_ERROR;
+      }
       // The JavaScript side expects a map with at least the error message.
       // It is possible to expose all kind of information. It will be available on the JS
       // error instance.
-      // TODO(8850038): add more useful information, e.g. the native stack trace.
       WritableNativeMap errorInfo = new WritableNativeMap();
+      errorInfo.putString("code", code);
       errorInfo.putString("message", reason);
+      // TODO(8850038): add the stack trace info in, need to figure out way to serialize that
       mReject.invoke(errorInfo);
     }
   }

From 554292d3044c801a736d5eb333cb1e6610e39fa6 Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Tue, 19 Jan 2016 12:13:24 -0800
Subject: [PATCH 0789/1411] Improve the message shown when bundle download
 fails

Summary:
![screenshot_20160111-004544](https://cloud.githubusercontent.com/assets/1174278/12223410/cfc57586-b7fc-11e5-9f38-4d562c6e9f0a.png)
Closes https://github.com/facebook/react-native/pull/5235

Reviewed By: svcscm

Differential Revision: D2839867

Pulled By: foghina

fb-gh-sync-id: 36230e1a0d063146db11e9c1d38cea2022a89a12
---
 ReactAndroid/src/main/res/devsupport/values/strings.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/res/devsupport/values/strings.xml b/ReactAndroid/src/main/res/devsupport/values/strings.xml
index d56ca71d1cec..0107c3689cf3 100644
--- a/ReactAndroid/src/main/res/devsupport/values/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values/strings.xml
@@ -13,7 +13,7 @@
   <string name="catalyst_settings_title" project="catalyst" translatable="false">Catalyst Dev Settings</string>
   <string name="catalyst_jsload_title" project="catalyst" translatable="false">Please wait…</string>
   <string name="catalyst_jsload_message" project="catalyst" translatable="false">Fetching JS bundle</string>
-  <string name="catalyst_jsload_error" project="catalyst" translatable="false">Unable to download JS bundle. Did you forget to start the development server or connect your device?</string>
+  <string name="catalyst_jsload_error" project="catalyst" translatable="false">Unable to download JS bundle from the dev server.\n\nTry the following to fix the issue:\n• Ensure that the packager server is running\n• Ensure that your device/emulator is connected to your machine and has USB debugging enabled - run \'adb devices\' to see a list of connected devices\n• If you\'re on a physical device connected to the same machine, run \'adb reverse tcp:8081 tcp:8081\' to forward requests from your device\n• If your device is on the same Wi-Fi network, set \'Debug server host &amp; port for device\' in \'Dev settings\' to your machine\'s IP address and the port of the local dev server - e.g. 10.0.1.1:8081</string>
   <string name="catalyst_remotedbg_message" project="catalyst" translatable="false">Connecting to remote debugger</string>
   <string name="catalyst_remotedbg_error" project="catalyst" translatable="false">Unable to connect with remote debugger</string>
   <string name="catalyst_element_inspector" project="catalyst" translatable="false">Show Inspector</string>

From 0c5f279c9df869db2afb3e1d92a54e6d930551ad Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Tue, 19 Jan 2016 12:19:47 -0800
Subject: [PATCH 0790/1411] Standardize Error objects for Promises

Summary:
public

Promises are coming.  And as part of it, we are standardizing the error objects that will be returned.  This puts the code in place on the Android side to always send the proper error format.

It will be an error object like this
  {
    code : "E_SOME_ERROR_CODE_DEFINED_BY_MODULE", // Meant to be machine parseable
    message : "Human readable message",
    nativeError : {} // Some representation of the underlying error (Exception or NSError) , still figuring out exactly, but hopefully something with stack info
  }

Reviewed By: nicklockwood

Differential Revision: D2840128

fb-gh-sync-id: 174d620e2beb53e1fc14161a10fd0479218d98a6
---
 Libraries/RCTTest/RCTTestModule.m |  2 +-
 React/Base/RCTBridgeModule.h      |  2 +-
 React/Base/RCTModuleMethod.m      |  4 ++--
 React/Base/RCTUtils.h             |  4 ++++
 React/Base/RCTUtils.m             | 17 +++++++++++++----
 5 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/Libraries/RCTTest/RCTTestModule.m b/Libraries/RCTTest/RCTTestModule.m
index 0692543e755a..a889b8522a4e 100644
--- a/Libraries/RCTTest/RCTTestModule.m
+++ b/Libraries/RCTTest/RCTTestModule.m
@@ -62,7 +62,7 @@ - (dispatch_queue_t)methodQueue
 
 RCT_REMAP_METHOD(shouldReject, shouldReject_resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
 {
-  reject(nil);
+  reject(nil, nil, nil);
 }
 
 RCT_EXPORT_METHOD(markTestCompleted)
diff --git a/React/Base/RCTBridgeModule.h b/React/Base/RCTBridgeModule.h
index 39c7acad4aee..067ecb4927d1 100644
--- a/React/Base/RCTBridgeModule.h
+++ b/React/Base/RCTBridgeModule.h
@@ -37,7 +37,7 @@ typedef void (^RCTPromiseResolveBlock)(id result);
  * The error may be nil but it is preferable to pass an NSError object for more
  * precise error messages.
  */
-typedef void (^RCTPromiseRejectBlock)(NSError *error);
+typedef void (^RCTPromiseRejectBlock)(NSString *code, NSString *message, NSError *error);
 
 /**
  * This constant can be returned from +methodQueue to force module
diff --git a/React/Base/RCTModuleMethod.m b/React/Base/RCTModuleMethod.m
index 8f54f2d9e44a..0a6cd9390e6e 100644
--- a/React/Base/RCTModuleMethod.m
+++ b/React/Base/RCTModuleMethod.m
@@ -335,8 +335,8 @@ - (void)processMethodSignature
           return NO;
         }
 
-        RCT_BLOCK_ARGUMENT(^(NSError *error) {
-          NSDictionary *errorJSON = RCTJSErrorFromNSError(error);
+        RCT_BLOCK_ARGUMENT(^(NSString *code, NSString *message, NSError *error) {
+          NSDictionary *errorJSON = RCTJSErrorFromCodeMessageAndNSError(code, message, error);
           [bridge enqueueCallback:json args:@[errorJSON]];
         });
       )
diff --git a/React/Base/RCTUtils.h b/React/Base/RCTUtils.h
index 5e6815c4e03f..36383e8c61ab 100644
--- a/React/Base/RCTUtils.h
+++ b/React/Base/RCTUtils.h
@@ -52,6 +52,10 @@ RCT_EXTERN BOOL RCTClassOverridesInstanceMethod(Class cls, SEL selector);
 RCT_EXTERN NSDictionary<NSString *, id> *RCTMakeError(NSString *message, id toStringify, NSDictionary<NSString *, id> *extraData);
 RCT_EXTERN NSDictionary<NSString *, id> *RCTMakeAndLogError(NSString *message, id toStringify, NSDictionary<NSString *, id> *extraData);
 RCT_EXTERN NSDictionary<NSString *, id> *RCTJSErrorFromNSError(NSError *error);
+RCT_EXTERN NSDictionary<NSString *, id> *RCTJSErrorFromCodeMessageAndNSError(NSString *code, NSString *message, NSError *error);
+
+// The default error code that will be sent in the .code value of the Error object to js
+RCT_EXTERN NSString *const RCTErrorUnspecified;
 
 // Returns YES if React is running in a test environment
 RCT_EXTERN BOOL RCTRunningInTestEnvironment(void);
diff --git a/React/Base/RCTUtils.m b/React/Base/RCTUtils.m
index e6ebdb8061b3..cf0d8b8b00e4 100644
--- a/React/Base/RCTUtils.m
+++ b/React/Base/RCTUtils.m
@@ -21,6 +21,8 @@
 
 #import "RCTLog.h"
 
+NSString *const RCTErrorUnspecified = @"EUNSPECIFIED";
+
 NSString *RCTJSONStringify(id jsonObject, NSError **error)
 {
   static SEL JSONKitSelector = NULL;
@@ -313,27 +315,34 @@ BOOL RCTClassOverridesInstanceMethod(Class cls, SEL selector)
   return error;
 }
 
-// TODO: Can we just replace RCTMakeError with this function instead?
 NSDictionary<NSString *, id> *RCTJSErrorFromNSError(NSError *error)
+{
+  return RCTJSErrorFromCodeMessageAndNSError(RCTErrorUnspecified, nil, error);
+}
+
+// TODO: Can we just replace RCTMakeError with this function instead?
+NSDictionary<NSString *, id> *RCTJSErrorFromCodeMessageAndNSError(NSString *code, NSString *message, NSError *error)
 {
   NSString *errorMessage;
   NSArray<NSString *> *stackTrace = [NSThread callStackSymbols];
   NSMutableDictionary<NSString *, id> *errorInfo =
-    [NSMutableDictionary dictionaryWithObject:stackTrace forKey:@"nativeStackIOS"];
+  [NSMutableDictionary dictionaryWithObject:stackTrace forKey:@"nativeStackIOS"];
 
   if (error) {
     errorMessage = error.localizedDescription ?: @"Unknown error from a native module";
     errorInfo[@"domain"] = error.domain ?: RCTErrorDomain;
-    errorInfo[@"code"] = @(error.code);
   } else {
     errorMessage = @"Unknown error from a native module";
     errorInfo[@"domain"] = RCTErrorDomain;
-    errorInfo[@"code"] = @-1;
   }
+  errorInfo[@"code"] = code ?: RCTErrorUnspecified;
+  // Allow for explicit overriding of the error message
+  errorMessage = message ?: errorMessage;
 
   return RCTMakeError(errorMessage, nil, errorInfo);
 }
 
+
 BOOL RCTRunningInTestEnvironment(void)
 {
   static BOOL isTestEnvironment = NO;

From 58a448ece3faa1a60afb1d098ba7229c8f219b5b Mon Sep 17 00:00:00 2001
From: Jean-Richard Lai <jrichardlai@gmail.com>
Date: Tue, 19 Jan 2016 14:12:51 -0800
Subject: [PATCH 0791/1411] Update docs about MainActivity getPackages

Summary:
Didn't found someone that updated that, feel free to close if that is the case.
Closes https://github.com/facebook/react-native/pull/5415

Reviewed By: svcscm

Differential Revision: D2841576

Pulled By: androidtrunkagent

fb-gh-sync-id: 99b37fcb370453ce71fa83434f7c72b598375ef0
---
 docs/NativeModulesAndroid.md | 18 ++++++------------
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/docs/NativeModulesAndroid.md b/docs/NativeModulesAndroid.md
index 2bf46cc5cd53..4d8ea217fbc2 100644
--- a/docs/NativeModulesAndroid.md
+++ b/docs/NativeModulesAndroid.md
@@ -108,20 +108,14 @@ class AnExampleReactPackage implements ReactPackage {
   }
 ```
 
-The package needs to be provided to the **ReactInstanceManager** when it is built. To accomplish this you will need to insert an `.addPackage(new YourPackageName())` call to the `mReactInstanceManager = ReactInstanceManager.builder()` call chain.
-
-Refer to the code below and add the `addPackage` statement to your application's `MainActivity.java` file. This file exists under the android folder in your react-native application directory. The path to this file is: `android/app/src/main/java/com/your-app-name/MainActivity.java`.
-
+The package needs to be provided in the `getPackages` method of the `MainActivity.java` file. This file exists under the android folder in your react-native application directory. The path to this file is: `android/app/src/main/java/com/your-app-name/MainActivity.java`.
 
 ```java
-mReactInstanceManager = ReactInstanceManager.builder()
-  .setApplication(getApplication())
-  .setBundleAssetName("AnExampleApp.android.bundle")
-  .setJSMainModuleName("Examples/AnExampleApp/AnExampleApp.android")
-  .addPackage(new AnExampleReactPackage())  // <-- Add this line with your package name.
-  .setUseDeveloperSupport(true)
-  .setInitialLifecycleState(LifecycleState.RESUMED)
-  .build();
+protected List<ReactPackage> getPackages() {
+    return Arrays.<ReactPackage>asList(
+            new MainReactPackage(),
+            new AnExampleReactPackage()); // <-- Add this line with your package name.
+}
 ```
 
 To make it simpler to access your new functionality from JavaScript, it is common to wrap the native module in a JavaScript module. This is not necessary but saves the consumers of your library the need to pull it off of `NativeModules` each time. This JavaScript file also becomes a good location for you to add any JavaScript side functionality.

From 8ea9a1bc94a0d5635f6ab286331a8acba912f15f Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Tue, 19 Jan 2016 14:34:22 -0800
Subject: [PATCH 0792/1411] Invalidate JS executor when loading fails

Summary:
This solves https://github.com/facebook/react-native/issues/5090. Since https://github.com/facebook/react-native/commit/5b4e873c68be9a788ac8cc3f67199fbaacb58921 we had better reporting for when calls from native to JS fail. When trying to load an invalid bundle, this would now cause a stackoverflow, since RCTFatal would schedule a JS call to log, which would RCTFatal, which would ...

By invalidating the jsExecutor immediately after loading fails, we prevent any more attempts to log. We can't invalidate the whole bridge at this point since we still need the redbox module to actually display the error.

public

Reviewed By: majak

Differential Revision: D2834251

fb-gh-sync-id: a3e2ad425e40560beae4d3eacb93f66ace5341bf
---
 React/Base/RCTBatchedBridge.m | 1 +
 1 file changed, 1 insertion(+)

diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index e619c67d7494..50f6deb935fd 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -482,6 +482,7 @@ - (void)stopLoadingWithError:(NSError *)error
   }
 
   _loading = NO;
+  [_javaScriptExecutor invalidate];
 
   [[NSNotificationCenter defaultCenter]
    postNotificationName:RCTJavaScriptDidFailToLoadNotification

From 8638f6a735a8842486a44f9f5527faa14d2c2dec Mon Sep 17 00:00:00 2001
From: mangogogos <jacob.patenaude@teampages.com>
Date: Tue, 19 Jan 2016 14:37:32 -0800
Subject: [PATCH 0793/1411] Provide a method to easily provide initial props to
 a ReactAndroid application

Summary:
Adds back support for initial props in ReactAndroid while maintaining the abstraction benefits of having the details of ReactActivity abstracted from the end user's MainActivity. This does remove the need for ReactRootView's two paramater version of the overloaded startReactApplication as far as I can tell but I wasn't sure if anyone might be using that method internally.
Closes https://github.com/facebook/react-native/pull/5384

Reviewed By: svcscm

Differential Revision: D2841602

Pulled By: androidtrunkagent

fb-gh-sync-id: 07e0937bbbdb3ac1585aa252e2fd0f3736690898
---
 .../main/java/com/facebook/react/ReactActivity.java | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java b/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java
index 064c3b8b3fdb..c9679fafb96d 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java
@@ -60,6 +60,17 @@ protected String getJSMainModuleName() {
     return "index.android";
   }
 
+  /**
+   * Returns the launchOptions which will be passed to the {@link ReactInstanceManager}
+   * when the application is started. By default, this will return null and an empty
+   * object will be passed to your top level component as its initial props.
+   * If your React Native application requires props set outside of JS, override
+   * this method to return the Android.os.Bundle of your desired initial props.
+   */
+  protected @Nullable Bundle getLaunchOptions() {
+    return null;
+  }
+
   /**
    * Returns the name of the main component registered from JavaScript.
    * This is used to schedule rendering of the component.
@@ -128,7 +139,7 @@ protected void onCreate(Bundle savedInstanceState) {
 
     mReactInstanceManager = createReactInstanceManager();
     ReactRootView mReactRootView = createRootView();
-    mReactRootView.startReactApplication(mReactInstanceManager, getMainComponentName());
+    mReactRootView.startReactApplication(mReactInstanceManager, getMainComponentName(), getLaunchOptions());
     setContentView(mReactRootView);
   }
 

From 4f37fe6f68ee634d47f411171874b6e05b85b3e6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Tue, 19 Jan 2016 16:36:14 -0800
Subject: [PATCH 0794/1411] Improve error wording when packager dies and
 simulator was on debug mode

Reviewed By: jingc

Differential Revision: D2835719

fb-gh-sync-id: 694aac79cd9a76cfac32f7808c3f1bbb85d6bfb0
---
 Libraries/WebSocket/RCTWebSocketExecutor.m | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/WebSocket/RCTWebSocketExecutor.m b/Libraries/WebSocket/RCTWebSocketExecutor.m
index bc8d2b7fd88c..2ee409f33bfe 100644
--- a/Libraries/WebSocket/RCTWebSocketExecutor.m
+++ b/Libraries/WebSocket/RCTWebSocketExecutor.m
@@ -140,7 +140,7 @@ - (void)sendMessage:(NSDictionary<NSString *, id> *)message waitForReply:(RCTWSM
   dispatch_async(_jsQueue, ^{
     if (!self.valid) {
       NSError *error = [NSError errorWithDomain:@"WS" code:1 userInfo:@{
-        NSLocalizedDescriptionKey: @"socket closed"
+        NSLocalizedDescriptionKey: @"Runtime is not ready for debugging. Make sure Packager server is running."
       }];
       callback(error, nil);
       return;

From d4f6e447d2019ba784a83149a22bc6f392accee5 Mon Sep 17 00:00:00 2001
From: DengYun <tdzl2003>
Date: Tue, 19 Jan 2016 16:47:01 -0800
Subject: [PATCH 0795/1411] add host argument for packager.

Summary:
Now packager only listen to "::", which is IPv6 "Any address".
It failed to run in IPv4 Environment.

defaults to undefined or empty string will fix this.

And I think it's necessary to let user define host by cli argument.

It's also for security reason. When working on a public network, it's much safer to listen with localhost instead of ::, which may let everyone in same network be able to get your code from debugger-ui.

recommit for #1918, fixes #2441
Closes https://github.com/facebook/react-native/pull/5377

Reviewed By: svcscm

Differential Revision: D2842594

Pulled By: martinbigio

fb-gh-sync-id: 575944c5469dac80e99136a7903ea99f5339dba1
---
 local-cli/server/runServer.js | 2 +-
 local-cli/server/server.js    | 4 ++++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/local-cli/server/runServer.js b/local-cli/server/runServer.js
index c3a39a15a9d1..7d7463a06223 100644
--- a/local-cli/server/runServer.js
+++ b/local-cli/server/runServer.js
@@ -44,7 +44,7 @@ function runServer(args, config, readyCallback) {
 
   const serverInstance = http.createServer(app).listen(
     args.port,
-    '::',
+    args.host,
     function() {
       attachHMRServer({
         httpServer: serverInstance,
diff --git a/local-cli/server/server.js b/local-cli/server/server.js
index 3abffb5beef4..21d1d8e2cb06 100644
--- a/local-cli/server/server.js
+++ b/local-cli/server/server.js
@@ -30,6 +30,10 @@ function _server(argv, config, resolve, reject) {
     command: 'port',
     default: 8081,
     type: 'string',
+  }, {
+    command: 'host',
+    default: '',
+    type: 'string',
   }, {
     command: 'root',
     type: 'string',

From 4bbb0f4c16b494021e1c30cacfc11f2db2bbbdc1 Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Wed, 20 Jan 2016 07:16:33 +0530
Subject: [PATCH 0796/1411] Revert "Remove unused ApplicationContext fetch"

---
 .../com/facebook/react/modules/clipboard/ClipboardModule.java    | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java
index 412e8edaee9b..b3689f980d9b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java
@@ -71,6 +71,7 @@ public void getString(Callback cb) {
   @SuppressLint("DeprecatedMethod")
   @ReactMethod
   public void setString(String text) {
+    ReactApplicationContext reactContext = getReactApplicationContext();
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
       ClipData clipdata = ClipData.newPlainText(null, text);
       ClipboardManager clipboard = getClipboardService();

From c817764d6a652fe28efff5a827a070144f7a16e2 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Wed, 20 Jan 2016 05:04:08 -0800
Subject: [PATCH 0797/1411] Running OSS instrumentation tests with BUCK

Reviewed By: mkonicek

Differential Revision: D2839833

fb-gh-sync-id: ae9aa52962aba1b9057a93804c86b54cd161a8be
---
 .../src/androidTest/AndroidManifest.xml       | 19 ++++--
 ReactAndroid/src/androidTest/BUCK_temp        | 66 +++++++++++++++++++
 ReactAndroid/src/androidTest/buildBundle.sh   |  4 ++
 3 files changed, 84 insertions(+), 5 deletions(-)
 create mode 100644 ReactAndroid/src/androidTest/BUCK_temp
 create mode 100755 ReactAndroid/src/androidTest/buildBundle.sh

diff --git a/ReactAndroid/src/androidTest/AndroidManifest.xml b/ReactAndroid/src/androidTest/AndroidManifest.xml
index 2363aff11566..8d433458e0df 100644
--- a/ReactAndroid/src/androidTest/AndroidManifest.xml
+++ b/ReactAndroid/src/androidTest/AndroidManifest.xml
@@ -3,15 +3,24 @@
           package="com.facebook.react.tests"
           android:versionCode="1"
           android:versionName="1.0" >
-  <application>
-    <activity
-            android:name="com.facebook.react.testing.ReactAppTestActivity"
-            android:theme="@style/Theme.ReactNative.AppCompat.Light.NoActionBar.FullScreen"/>
-  </application>
   <uses-sdk android:targetSdkVersion="7" />
   <supports-screens android:anyDensity="true" />
   <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
   <!-- needed for screenshot tests -->
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+  <application>
+    <activity
+    android:name="com.facebook.react.testing.ReactAppTestActivity"/>
+    <!--<activity-->
+            <!--android:name="com.facebook.react.testing.ReactAppTestActivity"-->
+            <!--android:theme="@style/Theme.ReactNative.AppCompat.Light.NoActionBar.FullScreen"-->
+    <!--/>-->
+  </application>
+  <instrumentation
+          android:name="android.support.test.runner.AndroidJUnitRunner"
+          android:targetPackage="com.facebook.react.tests"
+          android:label="Integration tests for catalyst."/>
+
 </manifest>
diff --git a/ReactAndroid/src/androidTest/BUCK_temp b/ReactAndroid/src/androidTest/BUCK_temp
new file mode 100644
index 000000000000..d33209cedb57
--- /dev/null
+++ b/ReactAndroid/src/androidTest/BUCK_temp
@@ -0,0 +1,66 @@
+include_defs('//ReactAndroid/DEFS')
+
+
+CATALYST_PRIMERY_DEX_PATTERNS =  [
+  '/CatalystAppShell^',
+  '/CatalystApplicationImpl^',
+  '^com/facebook/buck/android/support/exopackage/',
+  '/FbInstrumentationTestRunner^',
+  '/PrimaryDexFactories^',
+  '/Screenshot^',
+  '/DexmakerMockMaker^',
+  '/AndroidJUnitRunner^',
+  '/InstrumentationRunListener^',
+  '/ExposedInstrumentationApi^',
+  '/TestApplication^',
+  '/ApplicationWithInjector^',
+  '/RunListener^',
+]
+
+JS_BUNDLE_DEPS = [
+  #':intern-schema',
+#   '//java/com/facebook/graphql:schema',
+#   '//java/com/facebook/graphql/graphql-data:locate_node'
+]
+
+
+# instrumentation tests that will run for tests located in GitHub open sourced folder
+android_binary (
+  name = 'react_oss',
+  manifest = 'AndroidManifest.xml',
+  keystore = '//keystores:debug',
+  use_split_dex = True,
+  linear_alloc_hard_limit = 10 * 1024 * 1024,
+  primary_dex_patterns = CATALYST_PRIMERY_DEX_PATTERNS,
+  deps = [
+#     ':integration_test_oss_bundle_js',
+    react_native_integration_tests_target('java/com/facebook/react/tests:tests'),
+  #     '//java/com/facebook/catalyst/js/react-native-github/ReactAndroid/src/main/res:shell',
+  ],
+)
+
+# Building this rule will produce a file named messenger_test.apk
+android_instrumentation_apk(
+  name = 'react_oss_test_apk',
+  manifest = 'AndroidManifest.xml',
+  apk = ':react_oss',
+  deps = [
+#     react_native_integration_tests_target('java/com/facebook/react/tests:tests'),
+    #     react_native_integration_tests_target('java/com/facebook/react/tests:tests'),
+    #     '//java/com/facebook/catalyst:integration_test_oss_bundle_js#dev',
+  ],
+)
+
+
+
+android_instrumentation_test(
+  name = 'react_oss_test',
+  apk = ':react_oss_test_apk',
+)
+
+sh_binary(
+  name = 'integration_test_oss_bundle_js',
+  main = 'buildBundle.sh',
+#     deps = [':InstallReactNativeNodeModules'],
+  visibility = ['PUBLIC'],
+)
diff --git a/ReactAndroid/src/androidTest/buildBundle.sh b/ReactAndroid/src/androidTest/buildBundle.sh
new file mode 100755
index 000000000000..6a61faa90ed2
--- /dev/null
+++ b/ReactAndroid/src/androidTest/buildBundle.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+# TODO put output to temp folder?
+node ./local-cli/cli.js bundle --entry-file ReactAndroid/src/androidTest/assets/TestBundle.js --dev --platform android --bundle-output ReactAndroid/src/androidTest/assets/ReactAndroidTestBundle.js

From 8d525b95dc0d7762838df9dc29fea25c5a9d1c0e Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Wed, 20 Jan 2016 06:21:38 -0800
Subject: [PATCH 0798/1411] Improve docs on Android Native Modules

Summary: Closes https://github.com/facebook/react-native/pull/5420

Reviewed By: svcscm

Differential Revision: D2844695

Pulled By: androidtrunkagent

fb-gh-sync-id: d23bd7ceb4ba34ec9f4368eda86730861560f0a8
---
 docs/NativeModulesAndroid.md | 121 ++++++++++++++++++++++++++++++++++-
 1 file changed, 120 insertions(+), 1 deletion(-)

diff --git a/docs/NativeModulesAndroid.md b/docs/NativeModulesAndroid.md
index 4d8ea217fbc2..bd86b8217f8c 100644
--- a/docs/NativeModulesAndroid.md
+++ b/docs/NativeModulesAndroid.md
@@ -221,7 +221,7 @@ public class UIManagerModule extends ReactContextBaseJavaModule {
 
       promise.resolve(map);
     } catch (IllegalViewOperationException e) {
-      promise.reject(e.getMessage());
+      promise.reject(e);
     }
   }
 
@@ -306,3 +306,122 @@ componentWillMount: function() {
 }
 ...
 ```
+
+### Getting activity result from `startActivityForResult`
+
+You'll need to listen to `onActivityResult` if you want to get results from an activity you started with `startActivityForResult`. To to do this, the module must implement `ActivityEventListener`. Then, you need to register a listener in the module's constructor,
+
+```java
+reactContext.addActivityEventListener(this);
+```
+
+Now you can listen to `onActivityResult` by implementing the following method:
+
+```java
+@Override
+public void onActivityResult(final int requestCode, final int resultCode, final Intent intent) {
+  // Your logic here
+}
+```
+
+We will implement a simple image picker to demonstrate this. The image picker will expose the method `pickImage` to JavaScript, which will return the path of the image when called.
+
+```java
+public class ImagePickerModule extends ReactContextBaseJavaModule implements ActivityEventListener {
+
+  private static final int IMAGE_PICKER_REQUEST = 467081;
+  private static final String E_ACTIVITY_DOES_NOT_EXIST = "E_ACTIVITY_DOES_NOT_EXIST";
+  private static final String E_PICKER_CANCELLED = "E_PICKER_CANCELLED";
+  private static final String E_FAILED_TO_SHOW_PICKER = "E_FAILED_TO_SHOW_PICKER";
+  private static final String E_NO_IMAGE_DATA_FOUND = "E_NO_IMAGE_DATA_FOUND";
+
+  private Promise mPickerPromise;
+
+  public ImagePickerModule(ReactApplicationContext reactContext) {
+    super(reactContext);
+
+    // Add the listener for `onActivityResult`
+    reactContext.addActivityEventListener(this);
+  }
+
+  @Override
+  public String getName() {
+    return "ImagePickerModule";
+  }
+
+  @ReactMethod
+  public void pickImage(final Promise promise) {
+    Activity currentActivity = getCurrentActivity();
+
+    if (currentActivity == null) {
+      promise.reject(E_ACTIVITY_DOES_NOT_EXIST, "Activity doesn't exist");
+      return;
+    }
+
+    // Store the promise to resolve/reject when picker returns data
+    mPickerPromise = promise;
+
+    try {
+      final Intent galleryIntent = new Intent(Intent.ACTION_PICK);
+
+      galleryIntent.setType("image/*");
+
+      final Intent chooserIntent = Intent.createChooser(galleryIntent, "Pick an image");
+
+      currentActivity.startActivityForResult(chooserIntent, PICK_IMAGE);
+    } catch (Exception e) {
+      mPickerPromise.reject(E_FAILED_TO_SHOW_PICKER, e);
+      mPickerPromise = null;
+    }
+  }
+
+  // You can get the result here
+  @Override
+  public void onActivityResult(final int requestCode, final int resultCode, final Intent intent) {
+    if (requestCode == IMAGE_PICKER_REQUEST) {
+      if (mPickerPromise != null) {
+        if (resultCode == Activity.RESULT_CANCELED) {
+          mPickerPromise.reject(E_PICKER_CANCELLED, "Image picker was cancelled");
+        } else if (resultCode == Activity.RESULT_OK) {
+          Uri uri = intent.getData();
+
+          if (uri == null) {
+            mPickerPromise.reject(E_NO_IMAGE_DATA_FOUND, "No image data found");
+          } else {
+            mPickerPromise.resolve(uri.toString());
+          }
+        }
+
+        mPickerPromise = null;
+      }
+    }
+  }
+}
+```
+
+### Listening to LifeCycle events
+
+Listening to the activity's LifeCycle events such as `onResume`, `onPause` etc. is very similar to how we implemented `ActivityEventListener`. The module must implement `ActivityEventListener`. Then, you need to register a listener in the module's constructor,
+
+```java
+reactContext.addLifecycleEventListener(this);
+```
+
+Now you can listen to the activity's LifeCycle events by implementing the following methods:
+
+```java
+@Override
+public void onHostResume() {
+    // Actvity `onResume`
+}
+
+@Override
+public void onHostPause() {
+    // Actvity `onPause`
+}
+
+@Override
+public void onHostDestroy() {
+    // Actvity `onDestroy`
+}
+```

From 4bd39500f82adecff5ecd3db5291d17bd1b518e3 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Wed, 20 Jan 2016 06:50:44 -0800
Subject: [PATCH 0799/1411] qucik fix for running CI tests with gradle

Reviewed By: mkonicek

Differential Revision: D2844709

fb-gh-sync-id: 9aaff6d0117501b91db519fbd640b8e1736a8cd6
---
 ReactAndroid/src/androidTest/AndroidManifest.xml | 13 +++----------
 1 file changed, 3 insertions(+), 10 deletions(-)

diff --git a/ReactAndroid/src/androidTest/AndroidManifest.xml b/ReactAndroid/src/androidTest/AndroidManifest.xml
index 8d433458e0df..4275a7ea6856 100644
--- a/ReactAndroid/src/androidTest/AndroidManifest.xml
+++ b/ReactAndroid/src/androidTest/AndroidManifest.xml
@@ -12,15 +12,8 @@
 
   <application>
     <activity
-    android:name="com.facebook.react.testing.ReactAppTestActivity"/>
-    <!--<activity-->
-            <!--android:name="com.facebook.react.testing.ReactAppTestActivity"-->
-            <!--android:theme="@style/Theme.ReactNative.AppCompat.Light.NoActionBar.FullScreen"-->
-    <!--/>-->
+            android:name="com.facebook.react.testing.ReactAppTestActivity"
+            android:theme="@style/Theme.ReactNative.AppCompat.Light.NoActionBar.FullScreen"
+    />
   </application>
-  <instrumentation
-          android:name="android.support.test.runner.AndroidJUnitRunner"
-          android:targetPackage="com.facebook.react.tests"
-          android:label="Integration tests for catalyst."/>
-
 </manifest>

From 67e5fe662b68a780e5e3dc6e1df62482e01202e9 Mon Sep 17 00:00:00 2001
From: Michael Abt <webwelten@users.noreply.github.com>
Date: Wed, 20 Jan 2016 16:00:08 +0100
Subject: [PATCH 0800/1411] Correct link to former react.rocks website

react.rocks has moved to js.coach and the packages at react.rocks aren't up to date anymore.
---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 7f36a8b69573..7f4b3a517964 100644
--- a/README.md
+++ b/README.md
@@ -71,7 +71,7 @@ Note that you'll need the Android NDK installed, see [prerequisites](https://git
 
 ## Extending React Native
 
-- Looking for a component? [react.parts](http://react.parts/)
+- Looking for a component? [JS.coach](https://js.coach)
 - Fellow developers write and publish React Native modules to npm and open source them on GitHub.
 - Making modules helps grow the React Native ecosystem and community. We recommend writing modules for your use cases and sharing them on npm.
 - Read the guides on Native Modules ([iOS](http://facebook.github.io/react-native/docs/native-modules-ios.html), [Android](http://facebook.github.io/react-native/docs/native-modules-android.html)) and Native UI Components ([iOS](http://facebook.github.io/react-native/docs/native-components-ios.html), [Android](http://facebook.github.io/react-native/docs/native-components-android.html)) if you are interested in extending native functionality.

From 4afeb4310b9004eff46466ad2c86cca4fc8df845 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Wed, 20 Jan 2016 07:13:26 -0800
Subject: [PATCH 0801/1411] Simplify HMR codepath

Reviewed By: davidaurelio

Differential Revision: D2839590

fb-gh-sync-id: 9bb14cafc69eec7d7a8712b60435e29f2ba48d3c
---
 local-cli/server/util/attachHMRServer.js      |  19 +-
 packager/react-packager/src/Bundler/Bundle.js | 124 ++---
 .../react-packager/src/Bundler/BundleBase.js  |  94 ++++
 .../react-packager/src/Bundler/HMRBundle.js   |  47 ++
 .../src/Bundler/__tests__/Bundle-test.js      | 463 ++++++++++--------
 .../src/Bundler/__tests__/Bundler-test.js     |  81 +--
 packager/react-packager/src/Bundler/index.js  | 143 +++---
 7 files changed, 529 insertions(+), 442 deletions(-)
 create mode 100644 packager/react-packager/src/Bundler/BundleBase.js
 create mode 100644 packager/react-packager/src/Bundler/HMRBundle.js

diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js
index 25961ee4e5dd..4a118d399ee0 100644
--- a/local-cli/server/util/attachHMRServer.js
+++ b/local-cli/server/util/attachHMRServer.js
@@ -168,18 +168,18 @@ function attachHMRServer({httpServer, path, packagerServer}) {
                   entryFile: client.bundleEntry,
                   platform: client.platform,
                   modules: modulesToUpdate,
-                });
+                })
               })
-              .then(update => {
-                if (!client) {
+              .then(bundle => {
+                if (!client || !bundle) {
                   return;
                 }
 
-                // check we actually want to send an HMR update
-                if (update) {
+                const hmrUpdate = bundle.getSource();
+                if (hmrUpdate) {
                   return JSON.stringify({
                     type: 'update',
-                    body: update,
+                    body: hmrUpdate,
                   });
                 }
               })
@@ -206,15 +206,12 @@ function attachHMRServer({httpServer, path, packagerServer}) {
 
                 return JSON.stringify({type: 'error', body});
               })
-              .then(bundle => {
+              .then(update => {
                 if (!client) {
                   return;
                 }
 
-                // check we actually want to send an HMR update
-                if (bundle) {
-                  client.ws.send(bundle);
-                }
+                client.ws.send(update);
               });
             },
             () => {
diff --git a/packager/react-packager/src/Bundler/Bundle.js b/packager/react-packager/src/Bundler/Bundle.js
index b5e591c8f0d4..04a2e1ae6a55 100644
--- a/packager/react-packager/src/Bundler/Bundle.js
+++ b/packager/react-packager/src/Bundler/Bundle.js
@@ -10,6 +10,7 @@
 
 const _ = require('underscore');
 const base64VLQ = require('./base64-vlq');
+const BundleBase = require('./BundleBase');
 const UglifyJS = require('uglify-js');
 const ModuleTransport = require('../lib/ModuleTransport');
 const Activity = require('../Activity');
@@ -24,11 +25,9 @@ const getNameAndCode = ({name, code}) => ({name, code});
 const getNameAndMinifiedCode =
   ({name, code}) => ({name, code: minifyCode(code)});
 
-class Bundle {
+class Bundle extends BundleBase {
   constructor(sourceMapUrl) {
-    this._finalized = false;
-    this._modules = [];
-    this._assets = [];
+    super();
     this._sourceMap = false;
     this._sourceMapUrl = sourceMapUrl;
     this._shouldCombineSourceMaps = false;
@@ -36,58 +35,49 @@ class Bundle {
     this._numRequireCalls = 0;
   }
 
-  setMainModuleId(moduleId) {
-    this._mainModuleId = moduleId;
-  }
-
-  addModule(module) {
-    if (!(module instanceof ModuleTransport)) {
-      throw new Error('Expeceted a ModuleTransport object');
-    }
-
-    // If we get a map from the transformer we'll switch to a mode
-    // were we're combining the source maps as opposed to
-    if (!this._shouldCombineSourceMaps && module.map != null) {
-      this._shouldCombineSourceMaps = true;
-    }
-
-    this._modules.push(module);
-  }
+  addModule(resolver, response, module, transformed) {
+    return resolver.wrapModule(
+      response,
+      module,
+      transformed.code
+    ).then(({code, name}) => {
+      const moduleTransport = new ModuleTransport({
+        code,
+        name,
+        map: transformed.map,
+        sourceCode: transformed.sourceCode,
+        sourcePath: transformed.sourcePath,
+        virtual: transformed.virtual,
+      });
 
-  getModules() {
-    return this._modules;
-  }
+      // If we get a map from the transformer we'll switch to a mode
+      // were we're combining the source maps as opposed to
+      if (!this._shouldCombineSourceMaps && moduleTransport.map != null) {
+        this._shouldCombineSourceMaps = true;
+      }
 
-  getMainModuleId() {
-    return this._mainModuleId;
+      super.addModule(moduleTransport);
+    });
   }
 
   setNumPrependedModules(n) {
     this._numPrependedModules = n;
   }
 
-  addAsset(asset) {
-    this._assets.push(asset);
-  }
-
   finalize(options) {
     options = options || {};
     if (options.runMainModule) {
       options.runBeforeMainModule.forEach(this._addRequireCall, this);
-      this._addRequireCall(this._mainModuleId);
+      this._addRequireCall(super.getMainModuleId());
     }
 
-    Object.freeze(this._modules);
-    Object.seal(this._modules);
-    Object.freeze(this._assets);
-    Object.seal(this._assets);
-    this._finalized = true;
+    super.finalize();
   }
 
   _addRequireCall(moduleId) {
     const code = ';require("' + moduleId + '");';
     const name = 'require-' + moduleId;
-    this.addModule(new ModuleTransport({
+    super.addModule(new ModuleTransport({
       name,
       code,
       virtual: true,
@@ -97,21 +87,6 @@ class Bundle {
     this._numRequireCalls += 1;
   }
 
-  _assertFinalized() {
-    if (!this._finalized) {
-      throw new Error('Bundle needs to be finalized before getting any source');
-    }
-  }
-
-  _getSource(dev) {
-    if (this._source) {
-      return this._source;
-    }
-
-    this._source = _.pluck(this._modules, 'code').join('\n');
-    return this._source;
-  }
-
   _getInlineSourceMap(dev) {
     if (this._inlineSourceMap == null) {
       const sourceMap = this.getSourceMap({excludeSource: true, dev});
@@ -123,7 +98,7 @@ class Bundle {
   }
 
   getSource(options) {
-    this._assertFinalized();
+    super.assertFinalized();
 
     options = options || {};
 
@@ -131,7 +106,7 @@ class Bundle {
       return this.getMinifiedSourceAndMap(options.dev).code;
     }
 
-    let source = this._getSource(options.dev);
+    let source = super.getSource();
 
     if (options.inlineSourceMap) {
       source += SOURCEMAPPING_URL + this._getInlineSourceMap(options.dev);
@@ -143,7 +118,7 @@ class Bundle {
   }
 
   getUnbundle({minify}) {
-    const allModules = this._modules.slice();
+    const allModules = super.getModules().slice();
     const prependedModules = this._numPrependedModules;
     const requireCalls = this._numRequireCalls;
 
@@ -163,13 +138,13 @@ class Bundle {
   }
 
   getMinifiedSourceAndMap(dev) {
-    this._assertFinalized();
+    super.assertFinalized();
 
     if (this._minifiedSourceAndMap) {
       return this._minifiedSourceAndMap;
     }
 
-    let source = this._getSource(dev);
+    let source = this.getSource();
     let map = this.getSourceMap();
 
     if (!dev) {
@@ -235,7 +210,7 @@ class Bundle {
     };
 
     let line = 0;
-    this._modules.forEach(function(module) {
+    super.getModules().forEach(function(module) {
       let map = module.map;
       if (module.virtual) {
         map = generateSourceMapForVirtualModule(module);
@@ -256,7 +231,7 @@ class Bundle {
   }
 
   getSourceMap(options) {
-    this._assertFinalized();
+    super.assertFinalized();
 
     options = options || {};
 
@@ -271,22 +246,18 @@ class Bundle {
     const mappings = this._getMappings();
     const map = {
       file: 'bundle.js',
-      sources: _.pluck(this._modules, 'sourcePath'),
+      sources: _.pluck(super.getModules(), 'sourcePath'),
       version: 3,
       names: [],
       mappings: mappings,
       sourcesContent: options.excludeSource
-    ? [] : _.pluck(this._modules, 'sourceCode')
+    ? [] : _.pluck(super.getModules(), 'sourceCode')
     };
     return map;
   }
 
-  getAssets() {
-    return this._assets;
-  }
-
   _getMappings() {
-    const modules = this._modules;
+    const modules = super.getModules();
 
     // The first line mapping in our package is basically the base64vlq code for
     // zeros (A).
@@ -333,7 +304,7 @@ class Bundle {
   }
 
   getJSModulePaths() {
-    return this._modules.filter(function(module) {
+    return super.getModules().filter(function(module) {
       // Filter out non-js files. Like images etc.
       return !module.virtual;
     }).map(function(module) {
@@ -343,7 +314,7 @@ class Bundle {
 
   getDebugInfo() {
     return [
-      '<div><h3>Main Module:</h3> ' + this._mainModuleId + '</div>',
+      '<div><h3>Main Module:</h3> ' + super.getMainModuleId() + '</div>',
       '<style>',
       'pre.collapsed {',
       '  height: 10px;',
@@ -355,7 +326,7 @@ class Bundle {
       '}',
       '</style>',
       '<h3> Module paths and transformed code: </h3>',
-      this._modules.map(function(m) {
+      super.getModules().map(function(m) {
         return '<div> <h4> Path: </h4>' + m.sourcePath + '<br/> <h4> Source: </h4>' +
                '<code><pre class="collapsed" onclick="this.classList.remove(\'collapsed\')">' +
                _.escape(m.code) + '</pre></code></div>';
@@ -369,10 +340,9 @@ class Bundle {
     }
 
     return {
-      modules: this._modules,
-      assets: this._assets,
+      ...super.toJSON(),
       sourceMapUrl: this._sourceMapUrl,
-      mainModuleId: this._mainModuleId,
+      mainModuleId: super.getMainModuleId(),
       numPrependedModules: this._numPrependedModules,
       numRequireCalls: this._numRequireCalls,
     };
@@ -380,18 +350,12 @@ class Bundle {
 
   static fromJSON(json) {
     const bundle = new Bundle(json.sourceMapUrl);
-    bundle._mainModuleId = json.mainModuleId;
-    bundle._assets = json.assets;
-    bundle._modules = json.modules;
+
     bundle._sourceMapUrl = json.sourceMapUrl;
     bundle._numPrependedModules = json.numPrependedModules;
     bundle._numRequireCalls = json.numRequireCalls;
 
-    Object.freeze(bundle._modules);
-    Object.seal(bundle._modules);
-    Object.freeze(bundle._assets);
-    Object.seal(bundle._assets);
-    bundle._finalized = true;
+    BundleBase.fromJSON(bundle, json);
 
     return bundle;
   }
diff --git a/packager/react-packager/src/Bundler/BundleBase.js b/packager/react-packager/src/Bundler/BundleBase.js
new file mode 100644
index 000000000000..635f87e733e7
--- /dev/null
+++ b/packager/react-packager/src/Bundler/BundleBase.js
@@ -0,0 +1,94 @@
+/**
+ * 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.
+ */
+'use strict';
+
+const _ = require('underscore');
+const ModuleTransport = require('../lib/ModuleTransport');
+
+class BundleBase {
+  constructor() {
+    this._finalized = false;
+    this._modules = [];
+    this._assets = [];
+  }
+
+  getMainModuleId() {
+    return this._mainModuleId;
+  }
+
+  setMainModuleId(moduleId) {
+    this._mainModuleId = moduleId;
+  }
+
+  addModule(module) {
+    if (!module instanceof ModuleTransport) {
+      throw new Error('Expeceted a ModuleTransport object');
+    }
+
+    this._modules.push(module);
+  }
+
+  getModules() {
+    return this._modules;
+  }
+
+  getAssets() {
+    return this._assets;
+  }
+
+  addAsset(asset) {
+    this._assets.push(asset);
+  }
+
+  finalize(options) {
+    Object.freeze(this._modules);
+    Object.seal(this._modules);
+    Object.freeze(this._assets);
+    Object.seal(this._assets);
+    this._finalized = true;
+  }
+
+  getSource(options) {
+    this.assertFinalized();
+
+    if (this._source) {
+      return this._source;
+    }
+
+    this._source = _.pluck(this._modules, 'code').join('\n');
+    return this._source;
+  }
+
+  assertFinalized() {
+    if (!this._finalized) {
+      throw new Error('Bundle needs to be finalized before getting any source');
+    }
+  }
+
+  toJSON() {
+    return {
+      modules: this._modules,
+      assets: this._assets,
+    };
+  }
+
+  static fromJSON(bundle, json) {
+    bundle._assets = json.assets;
+    bundle._modules = json.modules;
+    bundle._mainModuleId = json.mainModuleId;
+
+    Object.freeze(bundle._modules);
+    Object.seal(bundle._modules);
+    Object.freeze(bundle._assets);
+    Object.seal(bundle._assets);
+    bundle._finalized = true;
+  }
+}
+
+module.exports = BundleBase;
diff --git a/packager/react-packager/src/Bundler/HMRBundle.js b/packager/react-packager/src/Bundler/HMRBundle.js
new file mode 100644
index 000000000000..fa8c95db7656
--- /dev/null
+++ b/packager/react-packager/src/Bundler/HMRBundle.js
@@ -0,0 +1,47 @@
+/**
+ * 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.
+ */
+'use strict';
+
+const BundleBase = require('./BundleBase');
+const ModuleTransport = require('../lib/ModuleTransport');
+
+class HMRBundle extends BundleBase {
+  constructor() {
+    super();
+  }
+
+  addModule(resolver, response, module, transformed) {
+    return resolver.resolveRequires(response,
+      module,
+      transformed.code,
+    ).then(({name, code}) => {
+      code = `
+        __accept(
+          '${name}',
+          function(global, require, module, exports) {
+            ${code}
+          }
+        );
+      `;
+
+      const moduleTransport = new ModuleTransport({
+        code,
+        name,
+        map: transformed.map,
+        sourceCode: transformed.sourceCode,
+        sourcePath: transformed.sourcePath,
+        virtual: transformed.virtual,
+      });
+
+      super.addModule(moduleTransport);
+    });
+  }
+}
+
+module.exports = HMRBundle;
diff --git a/packager/react-packager/src/Bundler/__tests__/Bundle-test.js b/packager/react-packager/src/Bundler/__tests__/Bundle-test.js
index 6dd3d3b7c4c3..1180f0a2bb32 100644
--- a/packager/react-packager/src/Bundler/__tests__/Bundle-test.js
+++ b/packager/react-packager/src/Bundler/__tests__/Bundle-test.js
@@ -10,92 +10,106 @@
 
 jest.autoMockOff();
 
-var SourceMapGenerator = require('source-map').SourceMapGenerator;
+const Bundle = require('../Bundle');
+const ModuleTransport = require('../../lib/ModuleTransport');
+const Promise = require('Promise');
+const SourceMapGenerator = require('source-map').SourceMapGenerator;
+const UglifyJS = require('uglify-js');
 
-var Bundle = require('../Bundle');
-var ModuleTransport = require('../../lib/ModuleTransport');
-var UglifyJS = require('uglify-js');
-
-describe('Bundle', function() {
+describe('Bundle', () => {
   var bundle;
 
-  beforeEach(function() {
+  beforeEach(() => {
     bundle = new Bundle('test_url');
-    bundle.getSourceMap = jest.genMockFn().mockImpl(function() {
+    bundle.getSourceMap = jest.genMockFn().mockImpl(() => {
       return 'test-source-map';
     });
   });
 
-  describe('source bundle', function() {
-    it('should create a bundle and get the source', function() {
-      bundle.addModule(new ModuleTransport({
-        code: 'transformed foo;',
-        sourceCode: 'source foo',
-        sourcePath: 'foo path',
-      }));
-      bundle.addModule(new ModuleTransport({
-        code: 'transformed bar;',
-        sourceCode: 'source bar',
-        sourcePath: 'bar path',
-      }));
-
-      bundle.finalize({});
-      expect(bundle.getSource({dev: true})).toBe([
-        'transformed foo;',
-        'transformed bar;',
-        '\/\/# sourceMappingURL=test_url'
-      ].join('\n'));
+  describe('source bundle', () => {
+    pit('should create a bundle and get the source', () => {
+      return Promise.resolve().then(() => {
+        return addModule({
+          bundle,
+          code: 'transformed foo;',
+          sourceCode: 'source foo',
+          sourcePath: 'foo path',
+        });
+      }).then(() => {
+        return addModule({
+          bundle,
+          code: 'transformed bar;',
+          sourceCode: 'source bar',
+          sourcePath: 'bar path',
+        });
+      }).then(() => {
+        bundle.finalize({});
+        expect(bundle.getSource({dev: true})).toBe([
+          'transformed foo;',
+          'transformed bar;',
+          '\/\/# sourceMappingURL=test_url'
+        ].join('\n'));
+      });
     });
 
-    it('should be ok to leave out the source map url', function() {
-      var p = new Bundle();
-      p.addModule(new ModuleTransport({
-        code: 'transformed foo;',
-        sourceCode: 'source foo',
-        sourcePath: 'foo path',
-      }));
-      p.addModule(new ModuleTransport({
-        code: 'transformed bar;',
-        sourceCode: 'source bar',
-        sourcePath: 'bar path',
-      }));
-
-      p.finalize({});
-      expect(p.getSource({dev: true})).toBe([
-        'transformed foo;',
-        'transformed bar;',
-      ].join('\n'));
+    pit('should be ok to leave out the source map url', () => {
+      const otherBundle = new Bundle();
+      return Promise.resolve().then(() => {
+        return addModule({
+          bundle: otherBundle,
+          code: 'transformed foo;',
+          sourceCode: 'source foo',
+          sourcePath: 'foo path',
+        });
+      }).then(() => {
+        return addModule({
+          bundle: otherBundle,
+          code: 'transformed bar;',
+          sourceCode: 'source bar',
+          sourcePath: 'bar path',
+        });
+      }).then(() => {
+        otherBundle.finalize({});
+        expect(otherBundle.getSource({dev: true})).toBe([
+          'transformed foo;',
+          'transformed bar;',
+        ].join('\n'));
+      });
     });
 
-    it('should create a bundle and add run module code', function() {
-      bundle.addModule(new ModuleTransport({
-        code: 'transformed foo;',
-        sourceCode: 'source foo',
-        sourcePath: 'foo path'
-      }));
-
-      bundle.addModule(new ModuleTransport({
-        code: 'transformed bar;',
-        sourceCode: 'source bar',
-        sourcePath: 'bar path'
-      }));
-
-      bundle.setMainModuleId('foo');
-      bundle.finalize({
-        runBeforeMainModule: ['bar'],
-        runMainModule: true,
+    pit('should create a bundle and add run module code', () => {
+      return Promise.resolve().then(() => {
+        return addModule({
+          bundle,
+          code: 'transformed foo;',
+          sourceCode: 'source foo',
+          sourcePath: 'foo path',
+        });
+      }).then(() => {
+        return addModule({
+          bundle,
+          code: 'transformed bar;',
+          sourceCode: 'source bar',
+          sourcePath: 'bar path',
+        });
+      }).then(() => {
+        bundle.setMainModuleId('foo');
+        bundle.finalize({
+          runBeforeMainModule: ['bar'],
+          runMainModule: true,
+        });
+        expect(bundle.getSource({dev: true})).toBe([
+          'transformed foo;',
+          'transformed bar;',
+          ';require("bar");',
+          ';require("foo");',
+          '\/\/# sourceMappingURL=test_url',
+        ].join('\n'));
       });
-      expect(bundle.getSource({dev: true})).toBe([
-        'transformed foo;',
-        'transformed bar;',
-        ';require("bar");',
-        ';require("foo");',
-        '\/\/# sourceMappingURL=test_url',
-      ].join('\n'));
     });
 
-    it('should get minified source', function() {
-      var minified = {
+    pit('should get minified source', () => {
+      const minified = {
         code: 'minified',
         map: 'map',
       };
@@ -104,141 +118,156 @@ describe('Bundle', function() {
         return minified;
       };
 
-      bundle.addModule(new ModuleTransport({
-        code: 'transformed foo;',
-        sourceCode: 'source foo',
-        sourcePath: 'foo path'
-      }));
-      bundle.finalize();
-      expect(bundle.getMinifiedSourceAndMap({dev: true})).toBe(minified);
+      return Promise.resolve().then(() => {
+        return addModule({
+          bundle,
+          code: 'transformed foo;',
+          sourceCode: 'source foo',
+          sourcePath: 'foo path',
+        });
+      }).then(() => {
+        bundle.finalize();
+        expect(bundle.getMinifiedSourceAndMap({dev: true})).toBe(minified);
+      });
     });
   });
 
-  describe('sourcemap bundle', function() {
-    it('should create sourcemap', function() {
-      var p = new Bundle('test_url');
-      p.addModule(new ModuleTransport({
-        code: [
-          'transformed foo',
-          'transformed foo',
-          'transformed foo',
-        ].join('\n'),
-        sourceCode: [
-          'source foo',
-          'source foo',
-          'source foo',
-        ].join('\n'),
-        sourcePath: 'foo path',
-      }));
-      p.addModule(new ModuleTransport({
-        code: [
-          'transformed bar',
-          'transformed bar',
-          'transformed bar',
-        ].join('\n'),
-        sourceCode: [
-          'source bar',
-          'source bar',
-          'source bar',
-        ].join('\n'),
-        sourcePath: 'bar path',
-      }));
+  describe('sourcemap bundle', () => {
+    pit('should create sourcemap', () => {
+      const otherBundle = new Bundle('test_url');
 
-      p.setMainModuleId('foo');
-      p.finalize({
-        runBeforeMainModule: [],
-        runMainModule: true,
+      return Promise.resolve().then(() => {
+        return addModule({
+          bundle: otherBundle,
+          code: [
+            'transformed foo',
+            'transformed foo',
+            'transformed foo',
+          ].join('\n'),
+          sourceCode: [
+            'source foo',
+            'source foo',
+            'source foo',
+          ].join('\n'),
+          sourcePath: 'foo path',
+        });
+      }).then(() => {
+        return addModule({
+          bundle: otherBundle,
+          code: [
+            'transformed bar',
+            'transformed bar',
+            'transformed bar',
+          ].join('\n'),
+          sourceCode: [
+            'source bar',
+            'source bar',
+            'source bar',
+          ].join('\n'),
+          sourcePath: 'bar path',
+        });
+      }).then(() => {
+        otherBundle.setMainModuleId('foo');
+        otherBundle.finalize({
+          runBeforeMainModule: [],
+          runMainModule: true,
+        });
+        const sourceMap = otherBundle.getSourceMap({dev: true});
+        expect(sourceMap).toEqual(genSourceMap(otherBundle.getModules()));
       });
-      var s = p.getSourceMap({dev: true});
-      expect(s).toEqual(genSourceMap(p.getModules()));
     });
 
-    it('should combine sourcemaps', function() {
-      var p = new Bundle('test_url');
-
-      p.addModule(new ModuleTransport({
-        code: 'transformed foo;\n',
-        map: {name: 'sourcemap foo'},
-        sourceCode: 'source foo',
-        sourcePath: 'foo path'
-      }));
-
-      p.addModule(new ModuleTransport({
-        code: 'transformed foo;\n',
-        map: {name: 'sourcemap bar'},
-        sourceCode: 'source foo',
-        sourcePath: 'foo path'
-      }));
+    pit('should combine sourcemaps', () => {
+      const otherBundle = new Bundle('test_url');
 
-      p.addModule(new ModuleTransport({
-        code: 'image module;\nimage module;',
-        virtual: true,
-        sourceCode: 'image module;\nimage module;',
-        sourcePath: 'image.png',
-      }));
-
-      p.setMainModuleId('foo');
-      p.finalize({
-        runBeforeMainModule: ['InitializeJavaScriptAppEngine'],
-        runMainModule: true,
-      });
+      return Promise.resolve().then(() => {
+        return addModule({
+          bundle: otherBundle,
+          code: 'transformed foo;\n',
+          sourceCode: 'source foo',
+          map: {name: 'sourcemap foo'},
+          sourcePath: 'foo path',
+        });
+      }).then(() => {
+        return addModule({
+          bundle: otherBundle,
+          code: 'transformed bar;\n',
+          sourceCode: 'source bar',
+          map: {name: 'sourcemap bar'},
+          sourcePath: 'bar path',
+        });
+      }).then(() => {
+        return addModule({
+          bundle: otherBundle,
+          code: 'image module;\nimage module;',
+          virtual: true,
+          sourceCode: 'image module;\nimage module;',
+          sourcePath: 'image.png',
+        });
+      }).then(() => {
+        otherBundle.setMainModuleId('foo');
+        otherBundle.finalize({
+          runBeforeMainModule: ['InitializeJavaScriptAppEngine'],
+          runMainModule: true,
+        });
 
-      var s = p.getSourceMap({dev: true});
-      expect(s).toEqual({
-        file: 'bundle.js',
-        version: 3,
-        sections: [
-          { offset: { line: 0, column: 0 }, map: { name: 'sourcemap foo' } },
-          { offset: { line: 2, column: 0 }, map: { name: 'sourcemap bar' } },
-          {
-            offset: {
-              column: 0,
-              line: 4
+        const sourceMap = otherBundle.getSourceMap({dev: true});
+        expect(sourceMap).toEqual({
+          file: 'bundle.js',
+          version: 3,
+          sections: [
+            { offset: { line: 0, column: 0 }, map: { name: 'sourcemap foo' } },
+            { offset: { line: 2, column: 0 }, map: { name: 'sourcemap bar' } },
+            {
+              offset: {
+                column: 0,
+                line: 4
+              },
+              map: {
+                file: 'image.png',
+                mappings: 'AAAA;AACA;',
+                names: [],
+                sources: [ 'image.png' ],
+                sourcesContent: ['image module;\nimage module;'],
+                version: 3,
+              }
             },
-            map: {
-              file: 'image.png',
-              mappings: 'AAAA;AACA;',
-              names: [],
-              sources: [ 'image.png' ],
-              sourcesContent: ['image module;\nimage module;'],
-              version: 3,
-            }
-          },
-          {
-            offset: {
-              column: 0,
-              line: 6
+            {
+              offset: {
+                column: 0,
+                line: 6
+              },
+              map: {
+                file: 'require-InitializeJavaScriptAppEngine.js',
+                mappings: 'AAAA;',
+                names: [],
+                sources: [ 'require-InitializeJavaScriptAppEngine.js' ],
+                sourcesContent: [';require("InitializeJavaScriptAppEngine");'],
+                version: 3,
+              }
             },
-            map: {
-              file: 'require-InitializeJavaScriptAppEngine.js',
-              mappings: 'AAAA;',
-              names: [],
-              sources: [ 'require-InitializeJavaScriptAppEngine.js' ],
-              sourcesContent: [';require("InitializeJavaScriptAppEngine");'],
-              version: 3,
-            }
-          },
-          {
-            offset: {
-              column: 0,
-              line: 7
+            {
+              offset: {
+                column: 0,
+                line: 7
+              },
+              map: {
+                file: 'require-foo.js',
+                mappings: 'AAAA;',
+                names: [],
+                sources: [ 'require-foo.js' ],
+                sourcesContent: [';require("foo");'],
+                version: 3,
+              }
             },
-            map: {
-              file: 'require-foo.js',
-              mappings: 'AAAA;',
-              names: [],
-              sources: [ 'require-foo.js' ],
-              sourcesContent: [';require("foo");'],
-              version: 3,
-            }
-          },
-        ],
+          ],
+        });
       });
     });
   });
 
-  describe('getAssets()', function() {
-    it('should save and return asset objects', function() {
+  describe('getAssets()', () => {
+    it('should save and return asset objects', () => {
       var p = new Bundle('test_url');
       var asset1 = {};
       var asset2 = {};
@@ -249,22 +278,27 @@ describe('Bundle', function() {
     });
   });
 
-  describe('getJSModulePaths()', function() {
-    it('should return module paths', function() {
-      var p = new Bundle('test_url');
-      p.addModule(new ModuleTransport({
-        code: 'transformed foo;\n',
-        sourceCode: 'source foo',
-        sourcePath: 'foo path'
-      }));
-      p.addModule(new ModuleTransport({
-        code: 'image module;\nimage module;',
-        virtual: true,
-        sourceCode: 'image module;\nimage module;',
-        sourcePath: 'image.png',
-      }));
-
-      expect(p.getJSModulePaths()).toEqual(['foo path']);
+  describe('getJSModulePaths()', () => {
+    pit('should return module paths', () => {
+      var otherBundle = new Bundle('test_url');
+      return Promise.resolve().then(() => {
+        return addModule({
+          bundle: otherBundle,
+          code: 'transformed foo;\n',
+          sourceCode: 'source foo',
+          sourcePath: 'foo path',
+        });
+      }).then(() => {
+        return addModule({
+          bundle: otherBundle,
+          code: 'image module;\nimage module;',
+          virtual: true,
+          sourceCode: 'image module;\nimage module;',
+          sourcePath: 'image.png',
+        });
+      }).then(() => {
+        expect(otherBundle.getJSModulePaths()).toEqual(['foo path']);
+      });
     });
   });
 });
@@ -302,3 +336,20 @@ function genSourceMap(modules) {
   }
   return sourceMapGen.toJSON();
 }
+
+function resolverFor(code) {
+  return {
+    wrapModule: (response, module, sourceCode) => Promise.resolve(
+      {name: 'name', code}
+    ),
+  };
+}
+
+function addModule({bundle, code, sourceCode, sourcePath, map, virtual}) {
+  return bundle.addModule(
+    resolverFor(code),
+    null,
+    null,
+    {sourceCode, sourcePath, map, virtual}
+  );
+}
diff --git a/packager/react-packager/src/Bundler/__tests__/Bundler-test.js b/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
index ccdc84961d4c..467cf90d69ce 100644
--- a/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
+++ b/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
@@ -161,46 +161,29 @@ describe('Bundler', function() {
       runBeforeMainModule: [],
       runModule: true,
       sourceMapUrl: 'source_map_url',
-    }).then(function(p) {
-        expect(p.addModule.mock.calls[0][0]).toEqual({
-          name: 'foo',
-          code: 'lol transformed /root/foo.js lol',
-          map: 'sourcemap /root/foo.js',
-          sourceCode: 'source /root/foo.js',
-          sourcePath: '/root/foo.js',
-        });
+    }).then(bundle => {
+        const ithAddedModule = (i) => bundle.addModule.mock.calls[i][2].path;
 
-        expect(p.addModule.mock.calls[1][0]).toEqual({
-          name: 'bar',
-          code: 'lol transformed /root/bar.js lol',
-          map: 'sourcemap /root/bar.js',
-          sourceCode: 'source /root/bar.js',
-          sourcePath: '/root/bar.js'
-        });
+        expect(ithAddedModule(0)).toEqual('/root/foo.js');
+        expect(ithAddedModule(1)).toEqual('/root/bar.js');
+        expect(ithAddedModule(2)).toEqual('/root/img/img.png');
+        expect(ithAddedModule(3)).toEqual('/root/img/new_image.png');
+        expect(ithAddedModule(4)).toEqual('/root/file.json');
+
+        expect(bundle.finalize.mock.calls[0]).toEqual([
+          {runMainModule: true, runBeforeMainModule: []}
+        ]);
 
-        var imgModule_DEPRECATED = {
+        expect(bundle.addAsset.mock.calls).toContain([{
           __packager_asset: true,
           path: '/root/img/img.png',
           uri: 'img',
           width: 25,
           height: 50,
           deprecated: true,
-        };
+        }]);
 
-        expect(p.addModule.mock.calls[2][0]).toEqual({
-          name: 'image!img',
-          code: 'lol module.exports = ' +
-            JSON.stringify(imgModule_DEPRECATED) +
-            '; lol',
-          sourceCode: 'module.exports = ' +
-            JSON.stringify(imgModule_DEPRECATED) +
-            ';',
-          sourcePath: '/root/img/img.png',
-          virtual: true,
-          map: undefined,
-        });
-
-        var imgModule = {
+        expect(bundle.addAsset.mock.calls).toContain([{
           __packager_asset: true,
           fileSystemLocation: '/root/img',
           httpServerLocation: '/assets/img',
@@ -215,41 +198,7 @@ describe('Bundler', function() {
           hash: 'i am a hash',
           name: 'img',
           type: 'png',
-        };
-
-        expect(p.addModule.mock.calls[3][0]).toEqual({
-          name: 'new_image.png',
-          code: 'lol module.exports = require("AssetRegistry").registerAsset(' +
-            JSON.stringify(imgModule) +
-            '); lol',
-          sourceCode: 'module.exports = require("AssetRegistry").registerAsset(' +
-            JSON.stringify(imgModule) +
-            ');',
-          sourcePath: '/root/img/new_image.png',
-          virtual: true,
-          map: undefined,
-        });
-
-        expect(p.addModule.mock.calls[4][0]).toEqual({
-          name: 'package/file.json',
-          code: 'lol module.exports = {"json":true}; lol',
-          sourceCode: 'module.exports = {"json":true};',
-          sourcePath: '/root/file.json',
-          map: undefined,
-          virtual: true,
-        });
-
-        expect(p.finalize.mock.calls[0]).toEqual([
-          {runMainModule: true, runBeforeMainModule: []}
-        ]);
-
-        expect(p.addAsset.mock.calls).toContain([
-          imgModule_DEPRECATED
-        ]);
-
-        expect(p.addAsset.mock.calls).toContain([
-          imgModule
-        ]);
+        }]);
 
         // TODO(amasad) This fails with 0 != 5 in OSS
         //expect(ProgressBar.prototype.tick.mock.calls.length).toEqual(modules.length);
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index ebac145ce929..1cc28f23d805 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -18,6 +18,7 @@ const Cache = require('../DependencyResolver/Cache');
 const Transformer = require('../JSTransformer');
 const Resolver = require('../Resolver');
 const Bundle = require('./Bundle');
+const HMRBundle = require('./HMRBundle');
 const PrepackBundle = require('./PrepackBundle');
 const Activity = require('../Activity');
 const ModuleTransport = require('../lib/ModuleTransport');
@@ -155,31 +156,54 @@ class Bundler {
     return this._bundlesLayout.generateLayout(main, isDev);
   }
 
-  bundle({
+  bundle(options) {
+    return this._bundle({
+      bundle: new Bundle(options.sourceMapUrl),
+      includeSystemDependencies: true,
+      ...options,
+    });
+  }
+
+  bundleForHMR(options) {
+    return this._bundle({
+      bundle: new HMRBundle(),
+      hot: true,
+      ...options,
+    });
+  }
+
+  _bundle({
+    bundle,
+    modules,
     entryFile,
     runModule: runMainModule,
     runBeforeMainModule,
-    sourceMapUrl,
     dev: isDev,
+    includeSystemDependencies,
     platform,
     unbundle: isUnbundle,
     hot: hot,
   }) {
-    // Const cannot have the same name as the method (babel/babel#2834)
-    const bbundle = new Bundle(sourceMapUrl);
     const findEventId = Activity.startEvent('find dependencies');
     let transformEventId;
 
-    const moduleSystem = this._resolver.getModuleSystemDependencies(
-      { dev: isDev, platform, isUnbundle }
-    );
-
     return this.getDependencies(entryFile, isDev, platform).then((response) => {
       Activity.endEvent(findEventId);
+      bundle.setMainModuleId(response.mainModuleId);
       transformEventId = Activity.startEvent('transform');
 
-      // Prepend the module system polyfill to the top of dependencies
-      var dependencies = moduleSystem.concat(response.dependencies);
+      const moduleSystemDeps = includeSystemDependencies
+        ? this._resolver.getModuleSystemDependencies(
+          { dev: isDev, platform, isUnbundle }
+        )
+        : [];
+
+      const modulesToProcess = modules || response.dependencies;
+      const dependencies = moduleSystemDeps.concat(modulesToProcess);
+
+      bundle.setNumPrependedModules && bundle.setNumPrependedModules(
+        response.numPrependedDependencies + moduleSystemDeps.length
+      );
 
       let bar;
       if (process.stdout.isTTY) {
@@ -191,34 +215,41 @@ class Bundler {
         });
       }
 
-      bbundle.setMainModuleId(response.mainModuleId);
-      bbundle.setNumPrependedModules(
-        response.numPrependedDependencies + moduleSystem.length);
       return Promise.all(
         dependencies.map(
-          module => this._transformModule(
-            bbundle,
+          module => {
+            return this._transformModule(
+              bundle,
+              response,
+              module,
+              platform,
+              hot,
+            ).then(transformed => {
+              if (bar) {
+                bar.tick();
+              }
+
+              return {
+                module,
+                transformed,
+              };
+            });
+          }
+        )
+      ).then(transformedModules => Promise.all(
+        transformedModules.map(({module, transformed}) => {
+          return bundle.addModule(
+            this._resolver,
             response,
             module,
-            platform,
-            hot,
-          ).then(transformed => {
-            if (bar) {
-              bar.tick();
-            }
-            return this._wrapTransformedModule(response, module, transformed);
-          })
-        )
-      );
-    }).then((transformedModules) => {
+            transformed,
+          );
+        })
+      ));
+    }).then(() => {
       Activity.endEvent(transformEventId);
-
-      transformedModules.forEach(function(moduleTransport) {
-        bbundle.addModule(moduleTransport);
-      });
-
-      bbundle.finalize({runBeforeMainModule, runMainModule});
-      return bbundle;
+      bundle.finalize({runBeforeMainModule, runMainModule});
+      return bundle;
     });
   }
 
@@ -284,35 +315,6 @@ class Bundler {
     });
   }
 
-  bundleForHMR({entryFile, platform, modules}) {
-    return this.getDependencies(entryFile, /*isDev*/true, platform)
-      .then(response => {
-        return Promise.all(
-          modules.map(module => {
-            return Promise.all([
-              module.getName(),
-              this._transformModuleForHMR(module, platform),
-            ]).then(([moduleName, transformed]) => {
-              return this._resolver.resolveRequires(response,
-                module,
-                transformed.code,
-              ).then(({name, code}) => {
-                return (`
-                  __accept(
-                    '${moduleName}',
-                    function(global, require, module, exports) {
-                      ${code}
-                    }
-                  );
-                `);
-              });
-            });
-          })
-        );
-      })
-      .then(modules => modules.join('\n'));
-  }
-
   _transformModuleForHMR(module, platform) {
     if (module.isAsset()) {
       return this._generateAssetObjAndCode(module, platform).then(
@@ -401,23 +403,6 @@ class Bundler {
     }
   }
 
-  _wrapTransformedModule(response, module, transformed) {
-    return this._resolver.wrapModule(
-      response,
-      module,
-      transformed.code
-    ).then(
-      ({code, name}) => new ModuleTransport({
-        code,
-        name,
-        map: transformed.map,
-        sourceCode: transformed.sourceCode,
-        sourcePath: transformed.sourcePath,
-        virtual: transformed.virtual,
-      })
-    );
-  }
-
   getGraphDebugInfo() {
     return this._resolver.getDebugInfo();
   }

From cb45eaa0e8cab0f8a4b1c507494b0483e344b682 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Wed, 20 Jan 2016 08:26:46 -0800
Subject: [PATCH 0802/1411] Made Map & Set polyfills available globally

Summary:
public

Map and Set are a standard JavaScript features, but are only supported in a subset of JSC versions that we target (e.g. iOS 7's JSC doesn't support Set).

The consequence of this is that failing to require('Set') before using it won't error during testing on a modern OS, but will fail on older OS versions. This diff makes the Map and Set polyfills available globally to all RN apps to avoid that problem.

Reviewed By: davidaurelio

Differential Revision: D2833997

fb-gh-sync-id: 713d8b69f6a1bce2472a1b2e6b84f69d75f30289
---
 Libraries/AppStateIOS/AppStateIOS.ios.js                   | 1 -
 Libraries/CustomComponents/Navigator/Navigator.js          | 1 -
 .../Initialization/InitializeJavaScriptAppEngine.js        | 7 ++++++-
 Libraries/LinkingIOS/LinkingIOS.js                         | 1 -
 Libraries/PushNotificationIOS/PushNotificationIOS.js       | 1 -
 Libraries/ReactIOS/YellowBox.js                            | 1 -
 Libraries/Utilities/BackAndroid.android.js                 | 1 -
 7 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/Libraries/AppStateIOS/AppStateIOS.ios.js b/Libraries/AppStateIOS/AppStateIOS.ios.js
index f7dddcd5787c..d482b4e7d7b1 100644
--- a/Libraries/AppStateIOS/AppStateIOS.ios.js
+++ b/Libraries/AppStateIOS/AppStateIOS.ios.js
@@ -11,7 +11,6 @@
  */
 'use strict';
 
-var Map = require('Map');
 var NativeModules = require('NativeModules');
 var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
 var RCTAppState = NativeModules.AppState;
diff --git a/Libraries/CustomComponents/Navigator/Navigator.js b/Libraries/CustomComponents/Navigator/Navigator.js
index b87532e5867d..df6940f3a672 100644
--- a/Libraries/CustomComponents/Navigator/Navigator.js
+++ b/Libraries/CustomComponents/Navigator/Navigator.js
@@ -30,7 +30,6 @@
 var AnimationsDebugModule = require('NativeModules').AnimationsDebugModule;
 var Dimensions = require('Dimensions');
 var InteractionMixin = require('InteractionMixin');
-var Map = require('Map');
 var NavigationContext = require('NavigationContext');
 var NavigatorBreadcrumbNavigationBar = require('NavigatorBreadcrumbNavigationBar');
 var NavigatorNavigationBar = require('NavigatorNavigationBar');
diff --git a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
index 5f5f2e491be4..37f507c2e1ee 100644
--- a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
+++ b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
@@ -150,11 +150,15 @@ function setUpGeolocation() {
   polyfillGlobal('geolocation', require('Geolocation'), GLOBAL.navigator);
 }
 
+function setUpMapAndSet() {
+  polyfillGlobal('Map', require('Map'));
+  polyfillGlobal('Set', require('Set'));
+}
+
 function setUpProduct() {
   Object.defineProperty(GLOBAL.navigator, 'product', {value: 'ReactNative'});
 }
 
-
 function setUpWebSockets() {
   polyfillGlobal('WebSocket', require('WebSocket'));
 }
@@ -198,6 +202,7 @@ setUpPromise();
 setUpErrorHandler();
 setUpXHR();
 setUpGeolocation();
+setUpMapAndSet();
 setUpProduct();
 setUpWebSockets();
 setUpProfile();
diff --git a/Libraries/LinkingIOS/LinkingIOS.js b/Libraries/LinkingIOS/LinkingIOS.js
index 1d186ccbf21c..a4832f268304 100644
--- a/Libraries/LinkingIOS/LinkingIOS.js
+++ b/Libraries/LinkingIOS/LinkingIOS.js
@@ -13,7 +13,6 @@
 
 var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
 var RCTLinkingManager = require('NativeModules').LinkingManager;
-var Map = require('Map');
 var invariant = require('invariant');
 
 var _notifHandlers = new Map();
diff --git a/Libraries/PushNotificationIOS/PushNotificationIOS.js b/Libraries/PushNotificationIOS/PushNotificationIOS.js
index 4432f7ea1892..cab4ba362073 100644
--- a/Libraries/PushNotificationIOS/PushNotificationIOS.js
+++ b/Libraries/PushNotificationIOS/PushNotificationIOS.js
@@ -11,7 +11,6 @@
  */
 'use strict';
 
-var Map = require('Map');
 var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
 var RCTPushNotificationManager = require('NativeModules').PushNotificationManager;
 var invariant = require('invariant');
diff --git a/Libraries/ReactIOS/YellowBox.js b/Libraries/ReactIOS/YellowBox.js
index 762428ee2098..692cd4f6e6c2 100644
--- a/Libraries/ReactIOS/YellowBox.js
+++ b/Libraries/ReactIOS/YellowBox.js
@@ -14,7 +14,6 @@
 
 const EventEmitter = require('EventEmitter');
 import type EmitterSubscription from 'EmitterSubscription';
-const Map = require('Map');
 const Platform = require('Platform');
 const React = require('React');
 const StyleSheet = require('StyleSheet');
diff --git a/Libraries/Utilities/BackAndroid.android.js b/Libraries/Utilities/BackAndroid.android.js
index f828f2f7e8e9..ed920e22c927 100644
--- a/Libraries/Utilities/BackAndroid.android.js
+++ b/Libraries/Utilities/BackAndroid.android.js
@@ -11,7 +11,6 @@
 
 'use strict';
 
-var Set = require('Set');
 var DeviceEventManager = require('NativeModules').DeviceEventManager;
 var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
 

From eef56de3763258739977ec2b3148c9b364953869 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Wed, 20 Jan 2016 08:42:08 -0800
Subject: [PATCH 0803/1411] CameraRoll: remove comment about missing Android
 support

Reviewed By: bestander

Differential Revision: D2840793

fb-gh-sync-id: a8dca1044242b93283953ff342bf76cd844b5e14
---
 Libraries/CameraRoll/CameraRoll.js | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/Libraries/CameraRoll/CameraRoll.js b/Libraries/CameraRoll/CameraRoll.js
index 48c3132191bf..5ea9b94677af 100644
--- a/Libraries/CameraRoll/CameraRoll.js
+++ b/Libraries/CameraRoll/CameraRoll.js
@@ -35,7 +35,6 @@ var ASSET_TYPE_OPTIONS = [
   'Photos', // default
 ];
 
-
 // Flow treats Object and Array as disjoint types, currently.
 deepFreezeAndThrowOnMutationInDev((GROUP_TYPES_OPTIONS: any));
 deepFreezeAndThrowOnMutationInDev((ASSET_TYPE_OPTIONS: any));
@@ -119,8 +118,6 @@ class CameraRoll {
   /**
    * Saves the image to the camera roll / gallery.
    *
-   * The CameraRoll API is not yet implemented for Android.
-   *
    * @param {string} tag On Android, this is a local URI, such
    * as `"file:///sdcard/img.png"`.
    *

From ed0e6a2250789a226c64fb03fd77a5da32ce9e9b Mon Sep 17 00:00:00 2001
From: Michael Abt <webwelten@users.noreply.github.com>
Date: Wed, 20 Jan 2016 18:07:12 +0100
Subject: [PATCH 0804/1411] Make link more specific

Directly link to the react-native part the site
---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 7f4b3a517964..04dbd5e4b03b 100644
--- a/README.md
+++ b/README.md
@@ -71,7 +71,7 @@ Note that you'll need the Android NDK installed, see [prerequisites](https://git
 
 ## Extending React Native
 
-- Looking for a component? [JS.coach](https://js.coach)
+- Looking for a component? [JS.coach](https://js.coach/react-native)
 - Fellow developers write and publish React Native modules to npm and open source them on GitHub.
 - Making modules helps grow the React Native ecosystem and community. We recommend writing modules for your use cases and sharing them on npm.
 - Read the guides on Native Modules ([iOS](http://facebook.github.io/react-native/docs/native-modules-ios.html), [Android](http://facebook.github.io/react-native/docs/native-modules-android.html)) and Native UI Components ([iOS](http://facebook.github.io/react-native/docs/native-components-ios.html), [Android](http://facebook.github.io/react-native/docs/native-components-android.html)) if you are interested in extending native functionality.

From 97b8856d53f28d8129a8b1d07c176f978ded9793 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Wed, 20 Jan 2016 17:27:26 +0000
Subject: [PATCH 0805/1411] Update Releases.md

---
 Releases.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Releases.md b/Releases.md
index 445e121de332..efbd057b614f 100644
--- a/Releases.md
+++ b/Releases.md
@@ -29,7 +29,7 @@ Run:
 
 #### Check that everything works
 
-Make absolutely sure basic iOS and Android workflow works on master, see the instructions printed by `release.sh`.
+Make absolutely sure a basic iOS and Android workflow works on the release branch you've just created, see the instructions printed by `release.sh`.
   
 #### Push to github
 

From 52c2533b664672f957e918cea3b27350fd9b4628 Mon Sep 17 00:00:00 2001
From: Jan Kassens <jkassens@fb.com>
Date: Wed, 20 Jan 2016 10:25:23 -0800
Subject: [PATCH 0806/1411] add babelHelpers.toArray to polyfill

Reviewed By: yungsters, davidaurelio

Differential Revision: D2844203

fb-gh-sync-id: 6e76ed51265150108ef91ca64c5c5d930f14982e
---
 .../react-packager/src/Resolver/polyfills/babelHelpers.js   | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/packager/react-packager/src/Resolver/polyfills/babelHelpers.js b/packager/react-packager/src/Resolver/polyfills/babelHelpers.js
index e028a782000b..de54ebc2c11b 100644
--- a/packager/react-packager/src/Resolver/polyfills/babelHelpers.js
+++ b/packager/react-packager/src/Resolver/polyfills/babelHelpers.js
@@ -11,7 +11,7 @@
 /* eslint-disable strict */
 
 // Created by running:
-// require('babel-core').buildExternalHelpers('_extends classCallCheck createClass createRawReactElement defineProperty get inherits  interopRequireDefault interopRequireWildcard objectWithoutProperties possibleConstructorReturn slicedToArray taggedTemplateLiteral toConsumableArray '.split(' '))
+// require('babel-core').buildExternalHelpers('_extends classCallCheck createClass createRawReactElement defineProperty get inherits  interopRequireDefault interopRequireWildcard objectWithoutProperties possibleConstructorReturn slicedToArray taggedTemplateLiteral toArray toConsumableArray '.split(' '))
 // then replacing the `global` reference in the last line to also use `this`.
 //
 // actually, that's a lie, because babel6 omits _extends and createRawReactElement
@@ -216,6 +216,10 @@
     }));
   };
 
+  babelHelpers.toArray = function (arr) {
+    return Array.isArray(arr) ? arr : Array.from(arr);
+  };
+
   babelHelpers.toConsumableArray = function (arr) {
     if (Array.isArray(arr)) {
       for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];

From 1dffd056bffb0f1cbfa91d2150db839f2e9544f1 Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Wed, 20 Jan 2016 10:27:34 -0800
Subject: [PATCH 0807/1411] Fix default logger's loglevel, improve default
 error handler

Reviewed By: majak

Differential Revision: D2834267

fb-gh-sync-id: c89ce5160f03f57409497cc802690c8360d88a4d
---
 React/Base/RCTLog.m                                   |  2 +-
 .../src/Resolver/polyfills/error-guard.js             | 11 +++--------
 2 files changed, 4 insertions(+), 9 deletions(-)

diff --git a/React/Base/RCTLog.m b/React/Base/RCTLog.m
index 28562bde23d6..efcc12659b84 100644
--- a/React/Base/RCTLog.m
+++ b/React/Base/RCTLog.m
@@ -163,7 +163,7 @@ void RCTPerformBlockWithLogPrefix(void (^block)(void), NSString *prefix)
     [log appendString:[formatter stringFromDate:timestamp]];
   }
   if (level) {
-    [log appendFormat:@"[%s]", RCTLogLevels[level - 1]];
+    [log appendFormat:@"[%s]", RCTLogLevels[level]];
   }
 
   [log appendFormat:@"[tid:%@]", RCTCurrentThreadName()];
diff --git a/packager/react-packager/src/Resolver/polyfills/error-guard.js b/packager/react-packager/src/Resolver/polyfills/error-guard.js
index d4aa41225d84..ac99cadca578 100644
--- a/packager/react-packager/src/Resolver/polyfills/error-guard.js
+++ b/packager/react-packager/src/Resolver/polyfills/error-guard.js
@@ -72,17 +72,12 @@
 
   /**
    * This is the error handler that is called when we encounter an exception
-   * when loading a module.
+   * when loading a module. This will report any errors encountered before
+   * ExceptionsManager is configured.
    */
   function setupErrorGuard() {
     var onError = function(e) {
-      global.console.error(
-        'Error: ' +
-        '\n stack: ' + e.stack +
-        '\n line: ' + e.line +
-        '\n message: ' + e.message,
-        e
-      );
+      global.console.error('Error: ' + e.message + ', stack:\n' + e.stack);
     };
     global.ErrorUtils.setGlobalHandler(onError);
   }

From 15f806957f88baa7b530d8dfcf8f045c35f5ddec Mon Sep 17 00:00:00 2001
From: tantan <tan-tan.tan@schneider-electric.com>
Date: Wed, 20 Jan 2016 10:53:59 -0800
Subject: [PATCH 0808/1411] Return a Promise for `Clipboard.getString()`

Summary:
For clipboard, add error callback in Android. Code like
```javascript
Clipboard.getString((content)=>{
    //do something
},(error)=>{
   //do something for error
})
```
Closes https://github.com/facebook/react-native/pull/4792

Reviewed By: svcscm

Differential Revision: D2844937

Pulled By: nicklockwood

fb-gh-sync-id: 19953807ff07238e6a6ef5aedf1a3fcbca7e62a1
---
 Examples/UIExplorer/ClipboardExample.js       | 20 ++++++----
 Libraries/Components/Clipboard/Clipboard.js   | 37 ++++++++++++++++++-
 React/Modules/RCTClipboard.m                  | 10 +++--
 .../modules/clipboard/ClipboardModule.java    | 16 ++++----
 4 files changed, 61 insertions(+), 22 deletions(-)

diff --git a/Examples/UIExplorer/ClipboardExample.js b/Examples/UIExplorer/ClipboardExample.js
index bcc53dfbb6e4..0adfdd6f59da 100644
--- a/Examples/UIExplorer/ClipboardExample.js
+++ b/Examples/UIExplorer/ClipboardExample.js
@@ -23,23 +23,25 @@ var {
 } = React;
 
 var ClipboardExample = React.createClass({
-  getInitialState: function() {
+  getInitialState() {
     return {
       content: 'Content will appear here'
     };
   },
-  
-  _setContentToClipboard:function(){
+  async _setClipboardContent(){
     Clipboard.setString('Hello World');
-    Clipboard.getString(content => {
+    try {
+      var content = await Clipboard.getString();
       this.setState({content});
-    });
+    } catch (e) {
+      this.setState({content:e.message});
+    }
+
   },
-  
   render() {
     return (
       <View>
-        <Text onPress={this._setContentToClipboard} style={{color: 'blue'}}>
+        <Text onPress={this._setClipboardContent} style={{color: 'blue'}}>
           Tap to put "Hello World" in the clipboard
         </Text>
         <Text style={{color: 'red', marginTop: 20}}>
@@ -55,6 +57,8 @@ exports.description = 'Show Clipboard contents.';
 exports.examples = [
   {
     title: 'Clipboard.setString() and getString()',
-    render(): ReactElement { return <ClipboardExample />; }
+    render() {
+      return <ClipboardExample/>;
+    }
   }
 ];
diff --git a/Libraries/Components/Clipboard/Clipboard.js b/Libraries/Components/Clipboard/Clipboard.js
index fd8461ba4e86..0abc570109d3 100644
--- a/Libraries/Components/Clipboard/Clipboard.js
+++ b/Libraries/Components/Clipboard/Clipboard.js
@@ -10,4 +10,39 @@
  */
 'use strict';
 
-module.exports = require('NativeModules').Clipboard;
+var Clipboard = require('NativeModules').Clipboard;
+
+/**
+ * `Clipboard` gives you an interface for setting and getting content from Clipboard on both iOS and Android
+ */
+module.exports = {
+  /**
+   * Get content of string type, this method returns a `Promise`, so you can use following code to get clipboard content
+   * ```javascript
+   * async _getContent() {
+   *   var content = await Clipboard.getString();
+   * }
+   * ```
+   * @param this parameter is deprecated. callback is function with one argument of string type
+   */
+  getString(callback) {
+    if (callback) {
+        console.warn('Clipboard.getString(callback) is deprecated. Use the returned Promise instead');
+        Clipboard.getString().then(callback);
+        return;
+    }
+    return Clipboard.getString();
+  },
+  /**
+   * Set content of string type. You can use following code to set clipboard content
+   * ```javascript
+   * _setContent() {
+   *   Clipboard.setString('hello world');
+   * }
+   * ```
+   * @param this parameter is content that will be set into clipboard.
+   */
+  setString(content) {
+    Clipboard.setString(content);
+  }
+};
diff --git a/React/Modules/RCTClipboard.m b/React/Modules/RCTClipboard.m
index 0a62f3f888a8..0a0bf14816f8 100644
--- a/React/Modules/RCTClipboard.m
+++ b/React/Modules/RCTClipboard.m
@@ -22,16 +22,18 @@ - (dispatch_queue_t)methodQueue
   return dispatch_get_main_queue();
 }
 
-RCT_EXPORT_METHOD(getString:(RCTResponseSenderBlock)callback)
+
+RCT_EXPORT_METHOD(setString:(NSString *)content)
 {
   UIPasteboard *clipboard = [UIPasteboard generalPasteboard];
-  callback(@[RCTNullIfNil(clipboard.string)]);
+  clipboard.string = content;
 }
 
-RCT_EXPORT_METHOD(setString:(NSString *)content)
+RCT_EXPORT_METHOD(getString:(RCTPromiseResolveBlock)resolve
+                  rejecter:(__unused RCTPromiseRejectBlock)reject)
 {
   UIPasteboard *clipboard = [UIPasteboard generalPasteboard];
-  clipboard.string = content;
+  resolve(@[RCTNullIfNil(clipboard.string)]);
 }
 
 @end
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java
index b3689f980d9b..0ea6c90528c4 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java
@@ -21,6 +21,7 @@
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReactContextBaseJavaModule;
 import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.bridge.Promise;
 import com.facebook.react.common.ReactConstants;
 
 import java.util.ArrayList;
@@ -43,28 +44,25 @@ public String getName() {
   }
 
   private ClipboardManager getClipboardService() {
-    ReactApplicationContext reactContext = getReactApplicationContext(); 
-    return (ClipboardManager) reactContext.getSystemService(reactContext.CLIPBOARD_SERVICE);
+    return (ClipboardManager) getReactApplicationContext().getSystemService(getReactApplicationContext().CLIPBOARD_SERVICE);
   }
 
   @ReactMethod
-  public void getString(Callback cb) {
+  public void getString(Promise promise){
     try {
       ClipboardManager clipboard = getClipboardService();
       ClipData clipData = clipboard.getPrimaryClip();
       if (clipData == null) {
-        cb.invoke("");
-        return;
+        promise.resolve("");
       }
       if (clipData.getItemCount() >= 1) {
         ClipData.Item firstItem = clipboard.getPrimaryClip().getItemAt(0);
-        String text = "" + firstItem.getText();
-        cb.invoke(text);
+        promise.resolve("" + firstItem.getText());
       } else {
-        cb.invoke("");
+        promise.resolve("");
       }
     } catch(Exception e) {
-      FLog.w(ReactConstants.TAG, "Cannot get clipboard contents: " + e.getMessage());
+      promise.reject(e);
     }
   }
 

From 9b87e6c860a95fe3d55285314d3d56be06cb7833 Mon Sep 17 00:00:00 2001
From: Andy Prock <aprock@gmail.com>
Date: Wed, 20 Jan 2016 11:00:21 -0800
Subject: [PATCH 0809/1411] Added an optional options parameter for WebSockets

Summary:
This enables overriding origin, and other request headers. Similar to the https://github.com/websockets/ws api.
Closes https://github.com/facebook/react-native/pull/4629

Reviewed By: svcscm

Differential Revision: D2839951

Pulled By: mkonicek

fb-gh-sync-id: 3578af4343f90572b8851ff28342a05945498ef6
---
 Libraries/WebSocket/RCTSRWebSocket.h          |  4 ++-
 Libraries/WebSocket/RCTSRWebSocket.m          | 19 +++++++++-----
 Libraries/WebSocket/RCTWebSocketModule.m      |  4 +--
 Libraries/WebSocket/WebSocket.js              |  5 ++--
 Libraries/WebSocket/WebSocketBase.js          | 12 ++++++---
 .../modules/websocket/WebSocketModule.java    | 25 +++++++++++++++----
 6 files changed, 49 insertions(+), 20 deletions(-)

diff --git a/Libraries/WebSocket/RCTSRWebSocket.h b/Libraries/WebSocket/RCTSRWebSocket.h
index 0c209c21cebb..12753043470e 100644
--- a/Libraries/WebSocket/RCTSRWebSocket.h
+++ b/Libraries/WebSocket/RCTSRWebSocket.h
@@ -60,10 +60,12 @@ extern NSString *const RCTSRHTTPResponseErrorKey;
 @property (nonatomic, readonly, copy) NSString *protocol;
 
 // Protocols should be an array of strings that turn into Sec-WebSocket-Protocol.
-- (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray<NSString *> *)protocols NS_DESIGNATED_INITIALIZER;
+// options can contain a custom "origin" NSString
+- (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray<NSString *> *)protocols options:(NSDictionary<NSString *, NSString *> *)options NS_DESIGNATED_INITIALIZER;
 - (instancetype)initWithURLRequest:(NSURLRequest *)request;
 
 // Some helper constructors.
+- (instancetype)initWithURL:(NSURL *)url protocols:(NSArray<NSString *> *)protocols options:(NSDictionary<NSString *, NSString *> *)options;
 - (instancetype)initWithURL:(NSURL *)url protocols:(NSArray<NSString *> *)protocols;
 - (instancetype)initWithURL:(NSURL *)url;
 
diff --git a/Libraries/WebSocket/RCTSRWebSocket.m b/Libraries/WebSocket/RCTSRWebSocket.m
index 5f46bfd757ad..3d8782c87121 100644
--- a/Libraries/WebSocket/RCTSRWebSocket.m
+++ b/Libraries/WebSocket/RCTSRWebSocket.m
@@ -234,6 +234,7 @@ @implementation RCTSRWebSocket
   __strong RCTSRWebSocket *_selfRetain;
 
   NSArray<NSString *> *_requestedProtocols;
+  NSDictionary<NSString *, NSString *> *_requestedOptions;
   RCTSRIOConsumerPool *_consumerPool;
 }
 
@@ -244,7 +245,7 @@ + (void)initialize;
   CRLFCRLF = [[NSData alloc] initWithBytes:"\r\n\r\n" length:4];
 }
 
-- (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray<NSString *> *)protocols;
+- (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray<NSString *> *)protocols options:(NSDictionary<NSString *, NSString *> *)options
 {
   RCTAssertParam(request);
 
@@ -253,6 +254,7 @@ - (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray<NS
     _urlRequest = request;
 
     _requestedProtocols = [protocols copy];
+    _requestedOptions = [options copy];
 
     [self _RCTSR_commonInit];
   }
@@ -263,18 +265,23 @@ - (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray<NS
 
 - (instancetype)initWithURLRequest:(NSURLRequest *)request;
 {
-  return [self initWithURLRequest:request protocols:nil];
+  return [self initWithURLRequest:request protocols:nil options: nil];
 }
 
 - (instancetype)initWithURL:(NSURL *)URL;
 {
-  return [self initWithURL:URL protocols:nil];
+  return [self initWithURL:URL protocols:nil options:nil];
 }
 
 - (instancetype)initWithURL:(NSURL *)URL protocols:(NSArray<NSString *> *)protocols;
+{
+  return [self initWithURL:URL protocols:protocols options:nil];
+}
+
+- (instancetype)initWithURL:(NSURL *)URL protocols:(NSArray<NSString *> *)protocols options:(NSDictionary<NSString *, id> *)options
 {
   NSURLRequest *request = URL ? [NSURLRequest requestWithURL:URL] : nil;
-  return [self initWithURLRequest:request protocols:protocols];
+  return [self initWithURLRequest:request protocols:protocols options:options];
 }
 
 - (void)_RCTSR_commonInit;
@@ -465,12 +472,12 @@ - (void)didConnect
   CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Key"), (__bridge CFStringRef)_secKey);
   CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Version"), (__bridge CFStringRef)[NSString stringWithFormat:@"%ld", (long)_webSocketVersion]);
 
-  CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Origin"), (__bridge CFStringRef)_url.RCTSR_origin);
-
   if (_requestedProtocols) {
     CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Protocol"), (__bridge CFStringRef)[_requestedProtocols componentsJoinedByString:@", "]);
   }
 
+  CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Origin"), (__bridge CFStringRef)(_requestedOptions[@"origin"] ?: _url.RCTSR_origin));
+
   [_urlRequest.allHTTPHeaderFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
     CFHTTPMessageSetHeaderFieldValue(request, (__bridge CFStringRef)key, (__bridge CFStringRef)obj);
   }];
diff --git a/Libraries/WebSocket/RCTWebSocketModule.m b/Libraries/WebSocket/RCTWebSocketModule.m
index e16f3067c9d8..6e057f78b148 100644
--- a/Libraries/WebSocket/RCTWebSocketModule.m
+++ b/Libraries/WebSocket/RCTWebSocketModule.m
@@ -44,9 +44,9 @@ - (void)dealloc
   }
 }
 
-RCT_EXPORT_METHOD(connect:(NSURL *)URL socketID:(nonnull NSNumber *)socketID)
+RCT_EXPORT_METHOD(connect:(NSURL *)URL protocols:(NSArray *)protocols options:(NSDictionary *)options socketID:(nonnull NSNumber *)socketID)
 {
-  RCTSRWebSocket *webSocket = [[RCTSRWebSocket alloc] initWithURL:URL];
+  RCTSRWebSocket *webSocket = [[RCTSRWebSocket alloc] initWithURL:URL protocols:protocols options:options];
   webSocket.delegate = self;
   webSocket.reactTag = socketID;
   if (!_sockets) {
diff --git a/Libraries/WebSocket/WebSocket.js b/Libraries/WebSocket/WebSocket.js
index 515a6ad5cfda..b9eb255cc76a 100644
--- a/Libraries/WebSocket/WebSocket.js
+++ b/Libraries/WebSocket/WebSocket.js
@@ -26,15 +26,16 @@ var CLOSE_NORMAL = 1000;
  * Browser-compatible WebSockets implementation.
  *
  * See https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
+ * See https://github.com/websockets/ws
  */
 class WebSocket extends WebSocketBase {
   _socketId: number;
   _subs: any;
 
-  connectToSocketImpl(url: string): void {
+  connectToSocketImpl(url: string, protocols: ?Array<string>, options: ?{origin?: string}): void {
     this._socketId = WebSocketId++;
 
-    RCTWebSocketModule.connect(url, this._socketId);
+    RCTWebSocketModule.connect(url, protocols, options, this._socketId);
 
     this._registerEvents(this._socketId);
   }
diff --git a/Libraries/WebSocket/WebSocketBase.js b/Libraries/WebSocket/WebSocketBase.js
index ef52352d4122..931b297494c4 100644
--- a/Libraries/WebSocket/WebSocketBase.js
+++ b/Libraries/WebSocket/WebSocketBase.js
@@ -33,19 +33,23 @@ class WebSocketBase extends EventTarget {
   readyState: number;
   url: ?string;
 
-  constructor(url: string, protocols: ?any) {
+  constructor(url: string, protocols: ?string | ?Array<string>, options: ?{origin?: string}) {
     super();
     this.CONNECTING = 0;
     this.OPEN = 1;
     this.CLOSING = 2;
     this.CLOSED = 3;
 
-    if (!protocols) {
-      protocols = [];
+    if (typeof protocols === 'string') {
+      protocols = [protocols];
+    }
+
+    if (!Array.isArray(protocols)) {
+      protocols = null;
     }
 
     this.readyState = this.CONNECTING;
-    this.connectToSocketImpl(url);
+    this.connectToSocketImpl(url, protocols, options);
   }
 
   close(): void {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java
index dfa41638cf42..61e1057bf583 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java
@@ -10,6 +10,7 @@
 package com.facebook.react.modules.websocket;
 
 import java.io.IOException;
+import javax.annotation.Nullable;
 
 import com.facebook.common.logging.FLog;
 import com.facebook.react.bridge.Arguments;
@@ -17,6 +18,10 @@
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReactContextBaseJavaModule;
 import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.ReadableMapKeySetIterator;
+import com.facebook.react.bridge.ReadableType;
 import com.facebook.react.bridge.WritableMap;
 import com.facebook.react.common.ReactConstants;
 import com.facebook.react.modules.core.DeviceEventManagerModule;
@@ -57,7 +62,8 @@ public String getName() {
   }
 
   @ReactMethod
-  public void connect(final String url, final int id) {
+  public void connect(final String url, @Nullable final ReadableArray protocols, @Nullable final ReadableMap options, final int id) {
+    // ignoring protocols, since OKHttp overrides them.
     OkHttpClient client = new OkHttpClient();
 
     client.setConnectTimeout(10, TimeUnit.SECONDS);
@@ -65,12 +71,21 @@ public void connect(final String url, final int id) {
     // Disable timeouts for read
     client.setReadTimeout(0, TimeUnit.MINUTES);
 
-    Request request = new Request.Builder()
+    Request.Builder builder = new Request.Builder()
         .tag(id)
-        .url(url)
-        .build();
+        .url(url);
+
+    if (options != null && options.hasKey("origin")) {
+      if (ReadableType.String.equals(options.getType("origin"))) {
+        builder.addHeader("Origin", options.getString("origin"));
+      } else {
+        FLog.w(
+          ReactConstants.TAG,
+          "Ignoring: requested origin, value not a string");
+      }
+    }
 
-    WebSocketCall.create(client, request).enqueue(new WebSocketListener() {
+    WebSocketCall.create(client, builder.build()).enqueue(new WebSocketListener() {
 
       @Override
       public void onOpen(WebSocket webSocket, Response response) {

From 21fcbbc32cc822f6d2db3f099082cac6b225cb48 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Wed, 20 Jan 2016 11:03:22 -0800
Subject: [PATCH 0810/1411] Generalized image decoding and resizing logic

Summary:
public

Standardises the image decoding logic for all image sources, meaning we get the benefits of efficient downscaling of images from all sources, not just ALAssets.

Reviewed By: javache

Differential Revision: D2647083

fb-gh-sync-id: e41456f838e4c6ab709b1c1523f651a86ff6e623
---
 Examples/UIExplorer/ImageCapInsetsExample.js  |   1 +
 .../xcschemes/UIExplorer.xcscheme             |  10 +-
 .../RCTImageLoaderHelpers.h                   |   4 +-
 .../RCTImageLoaderHelpers.m                   |   4 +-
 .../UIExplorerUnitTests/RCTImageLoaderTests.m |  20 +--
 .../UIExplorerUnitTests/RCTImageUtilTests.m   |  28 +--
 .../CameraRoll/RCTAssetsLibraryImageLoader.m  | 168 ------------------
 ...der.h => RCTAssetsLibraryRequestHandler.h} |   7 +-
 .../RCTAssetsLibraryRequestHandler.m          | 114 ++++++++++++
 .../RCTCameraRoll.xcodeproj/project.pbxproj   |  12 +-
 Libraries/CameraRoll/RCTCameraRollManager.m   |   2 +-
 .../CameraRoll/RCTPhotoLibraryImageLoader.m   |   4 +-
 Libraries/Image/RCTGIFImageDecoder.m          |   2 +-
 .../Image/RCTImage.xcodeproj/project.pbxproj  |  12 +-
 Libraries/Image/RCTImageEditingManager.m      |  66 ++-----
 Libraries/Image/RCTImageLoader.h              |  19 +-
 Libraries/Image/RCTImageLoader.m              | 119 +++++++++++--
 Libraries/Image/RCTImageStoreManager.m        |   1 +
 Libraries/Image/RCTImageUtils.h               |  46 +++--
 Libraries/Image/RCTImageUtils.m               | 110 ++++++++----
 Libraries/Image/RCTImageView.h                |   1 +
 Libraries/Image/RCTImageView.m                |  53 +++---
 Libraries/Image/RCTImageViewManager.m         |   2 +-
 Libraries/Image/RCTResizeMode.h               |  22 +++
 Libraries/Image/RCTResizeMode.m               |  20 +++
 Libraries/Image/RCTShadowVirtualImage.m       |   2 +-
 Libraries/Image/RCTXCAssetImageLoader.m       |   2 +-
 React/Base/RCTUtils.h                         |   6 +-
 React/Base/RCTUtils.m                         |  28 +--
 React/Views/RCTComponentData.m                |   4 +
 30 files changed, 510 insertions(+), 379 deletions(-)
 delete mode 100644 Libraries/CameraRoll/RCTAssetsLibraryImageLoader.m
 rename Libraries/CameraRoll/{RCTAssetsLibraryImageLoader.h => RCTAssetsLibraryRequestHandler.h} (75%)
 create mode 100644 Libraries/CameraRoll/RCTAssetsLibraryRequestHandler.m
 create mode 100644 Libraries/Image/RCTResizeMode.h
 create mode 100644 Libraries/Image/RCTResizeMode.m

diff --git a/Examples/UIExplorer/ImageCapInsetsExample.js b/Examples/UIExplorer/ImageCapInsetsExample.js
index 8c6ab243e977..f75f7da98d30 100644
--- a/Examples/UIExplorer/ImageCapInsetsExample.js
+++ b/Examples/UIExplorer/ImageCapInsetsExample.js
@@ -46,6 +46,7 @@ var ImageCapInsetsExample = React.createClass({
           <Image
             source={require('image!story-background')}
             style={styles.storyBackground}
+            resizeMode={Image.resizeMode.stretch}
             capInsets={{left: 15, right: 15, bottom: 15, top: 15}}
           />
         </View>
diff --git a/Examples/UIExplorer/UIExplorer.xcodeproj/xcshareddata/xcschemes/UIExplorer.xcscheme b/Examples/UIExplorer/UIExplorer.xcodeproj/xcshareddata/xcschemes/UIExplorer.xcscheme
index e2f84182e74e..52560f0d6856 100644
--- a/Examples/UIExplorer/UIExplorer.xcodeproj/xcshareddata/xcschemes/UIExplorer.xcscheme
+++ b/Examples/UIExplorer/UIExplorer.xcodeproj/xcshareddata/xcschemes/UIExplorer.xcscheme
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
    LastUpgradeVersion = "0700"
-   version = "1.8">
+   version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"
       buildImplicitDependencies = "YES">
@@ -51,10 +51,10 @@
       </BuildActionEntries>
    </BuildAction>
    <TestAction
+      buildConfiguration = "Debug"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      buildConfiguration = "Debug">
+      shouldUseLaunchSchemeArgsEnv = "YES">
       <Testables>
          <TestableReference
             skipped = "NO">
@@ -90,11 +90,11 @@
       </AdditionalOptions>
    </TestAction>
    <LaunchAction
+      buildConfiguration = "Debug"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       launchStyle = "0"
       useCustomWorkingDirectory = "NO"
-      buildConfiguration = "Debug"
       ignoresPersistentStateOnLaunch = "NO"
       debugDocumentVersioning = "YES"
       debugServiceExtension = "internal"
@@ -113,10 +113,10 @@
       </AdditionalOptions>
    </LaunchAction>
    <ProfileAction
+      buildConfiguration = "Release"
       shouldUseLaunchSchemeArgsEnv = "YES"
       savedToolIdentifier = ""
       useCustomWorkingDirectory = "NO"
-      buildConfiguration = "Release"
       debugDocumentVersioning = "YES">
       <BuildableProductRunnable
          runnableDebuggingMode = "0">
diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderHelpers.h b/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderHelpers.h
index 6ee68b5c3803..fe68f0592a0b 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderHelpers.h
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderHelpers.h
@@ -15,7 +15,7 @@
 #import "RCTImageLoader.h"
 
 typedef BOOL (^RCTImageURLLoaderCanLoadImageURLHandler)(NSURL *requestURL);
-typedef RCTImageLoaderCancellationBlock (^RCTImageURLLoaderLoadImageURLHandler)(NSURL *imageURL, CGSize size, CGFloat scale, UIViewContentMode resizeMode, RCTImageLoaderProgressBlock progressHandler, RCTImageLoaderCompletionBlock completionHandler);
+typedef RCTImageLoaderCancellationBlock (^RCTImageURLLoaderLoadImageURLHandler)(NSURL *imageURL, CGSize size, CGFloat scale, RCTResizeMode resizeMode, RCTImageLoaderProgressBlock progressHandler, RCTImageLoaderCompletionBlock completionHandler);
 
 @interface RCTConcreteImageURLLoader : NSObject <RCTImageURLLoader>
 
@@ -26,7 +26,7 @@ typedef RCTImageLoaderCancellationBlock (^RCTImageURLLoaderLoadImageURLHandler)(
 @end
 
 typedef BOOL (^RCTImageDataDecoderCanDecodeImageDataHandler)(NSData *imageData);
-typedef RCTImageLoaderCancellationBlock (^RCTImageDataDecoderDecodeImageDataHandler)(NSData *imageData, CGSize size, CGFloat scale, UIViewContentMode resizeMode, RCTImageLoaderCompletionBlock completionHandler);
+typedef RCTImageLoaderCancellationBlock (^RCTImageDataDecoderDecodeImageDataHandler)(NSData *imageData, CGSize size, CGFloat scale, RCTResizeMode resizeMode, RCTImageLoaderCompletionBlock completionHandler);
 
 @interface RCTConcreteImageDecoder : NSObject <RCTImageDataDecoder>
 
diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderHelpers.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderHelpers.m
index e41b09f3d7f6..e3b4cb0861f8 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderHelpers.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderHelpers.m
@@ -47,7 +47,7 @@ - (BOOL)canLoadImageURL:(NSURL *)requestURL
   return _canLoadImageURLHandler(requestURL);
 }
 
-- (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL size:(CGSize)size scale:(CGFloat)scale resizeMode:(UIViewContentMode)resizeMode progressHandler:(RCTImageLoaderProgressBlock)progressHandler completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
+- (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL size:(CGSize)size scale:(CGFloat)scale resizeMode:(RCTResizeMode)resizeMode progressHandler:(RCTImageLoaderProgressBlock)progressHandler completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
 {
   return _loadImageURLHandler(imageURL, size, scale, resizeMode, progressHandler, completionHandler);
 }
@@ -92,7 +92,7 @@ - (BOOL)canDecodeImageData:(NSData *)imageData
   return _canDecodeImageDataHandler(imageData);
 }
 
-- (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)imageData size:(CGSize)size scale:(CGFloat)scale resizeMode:(UIViewContentMode)resizeMode completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
+- (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)imageData size:(CGSize)size scale:(CGFloat)scale resizeMode:(RCTResizeMode)resizeMode completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
 {
   return _decodeImageDataHandler(imageData, size, scale, resizeMode, completionHandler);
 }
diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderTests.m
index 04f367312a10..5713d03473a7 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderTests.m
@@ -41,7 +41,7 @@ - (void)testImageLoading
 
   id<RCTImageURLLoader> loader = [[RCTImageLoaderTestsURLLoader1 alloc] initWithPriority:1.0 canLoadImageURLHandler:^BOOL(__unused NSURL *requestURL) {
     return YES;
-  } loadImageURLHandler:^RCTImageLoaderCancellationBlock(__unused NSURL *imageURL, __unused CGSize size, __unused CGFloat scale, __unused UIViewContentMode resizeMode, RCTImageLoaderProgressBlock progressHandler, RCTImageLoaderCompletionBlock completionHandler) {
+  } loadImageURLHandler:^RCTImageLoaderCancellationBlock(__unused NSURL *imageURL, __unused CGSize size, __unused CGFloat scale, __unused RCTResizeMode resizeMode, RCTImageLoaderProgressBlock progressHandler, RCTImageLoaderCompletionBlock completionHandler) {
     progressHandler(1, 1);
     completionHandler(nil, image);
     return nil;
@@ -50,7 +50,7 @@ - (void)testImageLoading
   RCTImageLoader *imageLoader = [RCTImageLoader new];
   NS_VALID_UNTIL_END_OF_SCOPE RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil moduleProvider:^{ return @[loader, imageLoader]; } launchOptions:nil];
 
-  [imageLoader loadImageWithTag:@"http://facebook.github.io/react/img/logo_og.png" size:CGSizeMake(100, 100) scale:1.0 resizeMode:UIViewContentModeScaleAspectFit progressBlock:^(int64_t progress, int64_t total) {
+  [imageLoader loadImageWithTag:@"http://facebook.github.io/react/img/logo_og.png" size:CGSizeMake(100, 100) scale:1.0 resizeMode:RCTResizeModeContain progressBlock:^(int64_t progress, int64_t total) {
     XCTAssertEqual(progress, 1);
     XCTAssertEqual(total, 1);
   } completionBlock:^(NSError *loadError, id loadedImage) {
@@ -65,7 +65,7 @@ - (void)testImageLoaderUsesImageURLLoaderWithHighestPriority
 
   id<RCTImageURLLoader> loader1 = [[RCTImageLoaderTestsURLLoader1 alloc] initWithPriority:1.0 canLoadImageURLHandler:^BOOL(__unused NSURL *requestURL) {
     return YES;
-  } loadImageURLHandler:^RCTImageLoaderCancellationBlock(__unused NSURL *imageURL, __unused CGSize size, __unused CGFloat scale, __unused UIViewContentMode resizeMode, RCTImageLoaderProgressBlock progressHandler, RCTImageLoaderCompletionBlock completionHandler) {
+  } loadImageURLHandler:^RCTImageLoaderCancellationBlock(__unused NSURL *imageURL, __unused CGSize size, __unused CGFloat scale, __unused RCTResizeMode resizeMode, RCTImageLoaderProgressBlock progressHandler, RCTImageLoaderCompletionBlock completionHandler) {
     progressHandler(1, 1);
     completionHandler(nil, image);
     return nil;
@@ -73,7 +73,7 @@ - (void)testImageLoaderUsesImageURLLoaderWithHighestPriority
 
   id<RCTImageURLLoader> loader2 = [[RCTImageLoaderTestsURLLoader2 alloc] initWithPriority:0.5 canLoadImageURLHandler:^BOOL(__unused NSURL *requestURL) {
     return YES;
-  } loadImageURLHandler:^RCTImageLoaderCancellationBlock(__unused NSURL *imageURL, __unused CGSize size, __unused CGFloat scale, __unused UIViewContentMode resizeMode, __unused RCTImageLoaderProgressBlock progressHandler, __unused RCTImageLoaderCompletionBlock completionHandler) {
+  } loadImageURLHandler:^RCTImageLoaderCancellationBlock(__unused NSURL *imageURL, __unused CGSize size, __unused CGFloat scale, __unused RCTResizeMode resizeMode, __unused RCTImageLoaderProgressBlock progressHandler, __unused RCTImageLoaderCompletionBlock completionHandler) {
     XCTFail(@"Should not have used loader2");
     return nil;
   }];
@@ -81,7 +81,7 @@ - (void)testImageLoaderUsesImageURLLoaderWithHighestPriority
   RCTImageLoader *imageLoader = [RCTImageLoader new];
   NS_VALID_UNTIL_END_OF_SCOPE RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil moduleProvider:^{ return @[loader1, loader2, imageLoader]; } launchOptions:nil];
 
-  [imageLoader loadImageWithTag:@"http://facebook.github.io/react/img/logo_og.png" size:CGSizeMake(100, 100) scale:1.0 resizeMode:UIViewContentModeScaleAspectFit progressBlock:^(int64_t progress, int64_t total) {
+  [imageLoader loadImageWithTag:@"http://facebook.github.io/react/img/logo_og.png" size:CGSizeMake(100, 100) scale:1.0 resizeMode:RCTResizeModeContain progressBlock:^(int64_t progress, int64_t total) {
     XCTAssertEqual(progress, 1);
     XCTAssertEqual(total, 1);
   } completionBlock:^(NSError *loadError, id loadedImage) {
@@ -97,7 +97,7 @@ - (void)testImageDecoding
 
   id<RCTImageDataDecoder> decoder = [[RCTImageLoaderTestsDecoder1 alloc] initWithPriority:1.0 canDecodeImageDataHandler:^BOOL(__unused NSData *imageData) {
     return YES;
-  } decodeImageDataHandler:^RCTImageLoaderCancellationBlock(NSData *imageData, __unused CGSize size, __unused CGFloat scale, __unused UIViewContentMode resizeMode, RCTImageLoaderCompletionBlock completionHandler) {
+  } decodeImageDataHandler:^RCTImageLoaderCancellationBlock(NSData *imageData, __unused CGSize size, __unused CGFloat scale, __unused RCTResizeMode resizeMode, RCTImageLoaderCompletionBlock completionHandler) {
     XCTAssertEqualObjects(imageData, data);
     completionHandler(nil, image);
     return nil;
@@ -106,7 +106,7 @@ - (void)testImageDecoding
   RCTImageLoader *imageLoader = [RCTImageLoader new];
   NS_VALID_UNTIL_END_OF_SCOPE RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil moduleProvider:^{ return @[decoder, imageLoader]; } launchOptions:nil];
 
-  RCTImageLoaderCancellationBlock cancelBlock = [imageLoader decodeImageData:data size:CGSizeMake(1, 1) scale:1.0 resizeMode:UIViewContentModeScaleToFill completionBlock:^(NSError *decodeError, id decodedImage) {
+  RCTImageLoaderCancellationBlock cancelBlock = [imageLoader decodeImageData:data size:CGSizeMake(1, 1) scale:1.0 resizeMode:RCTResizeModeStretch completionBlock:^(NSError *decodeError, id decodedImage) {
     XCTAssertEqualObjects(decodedImage, image);
     XCTAssertNil(decodeError);
   }];
@@ -120,7 +120,7 @@ - (void)testImageLoaderUsesImageDecoderWithHighestPriority
 
   id<RCTImageDataDecoder> decoder1 = [[RCTImageLoaderTestsDecoder1 alloc] initWithPriority:1.0 canDecodeImageDataHandler:^BOOL(__unused NSData *imageData) {
     return YES;
-  } decodeImageDataHandler:^RCTImageLoaderCancellationBlock(NSData *imageData, __unused CGSize size, __unused CGFloat scale, __unused UIViewContentMode resizeMode, RCTImageLoaderCompletionBlock completionHandler) {
+  } decodeImageDataHandler:^RCTImageLoaderCancellationBlock(NSData *imageData, __unused CGSize size, __unused CGFloat scale, __unused RCTResizeMode resizeMode, RCTImageLoaderCompletionBlock completionHandler) {
     XCTAssertEqualObjects(imageData, data);
     completionHandler(nil, image);
     return nil;
@@ -128,7 +128,7 @@ - (void)testImageLoaderUsesImageDecoderWithHighestPriority
 
   id<RCTImageDataDecoder> decoder2 = [[RCTImageLoaderTestsDecoder2 alloc] initWithPriority:0.5 canDecodeImageDataHandler:^BOOL(__unused NSData *imageData) {
     return YES;
-  } decodeImageDataHandler:^RCTImageLoaderCancellationBlock(__unused NSData *imageData, __unused CGSize size, __unused CGFloat scale, __unused UIViewContentMode resizeMode, __unused RCTImageLoaderCompletionBlock completionHandler) {
+  } decodeImageDataHandler:^RCTImageLoaderCancellationBlock(__unused NSData *imageData, __unused CGSize size, __unused CGFloat scale, __unused RCTResizeMode resizeMode, __unused RCTImageLoaderCompletionBlock completionHandler) {
     XCTFail(@"Should not have used decoder2");
     return nil;
   }];
@@ -136,7 +136,7 @@ - (void)testImageLoaderUsesImageDecoderWithHighestPriority
   RCTImageLoader *imageLoader = [RCTImageLoader new];
   NS_VALID_UNTIL_END_OF_SCOPE RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil moduleProvider:^{ return @[decoder1, decoder2, imageLoader]; } launchOptions:nil];
 
-  RCTImageLoaderCancellationBlock cancelBlock = [imageLoader decodeImageData:data size:CGSizeMake(1, 1) scale:1.0 resizeMode:UIViewContentModeScaleToFill completionBlock:^(NSError *decodeError, id decodedImage) {
+  RCTImageLoaderCancellationBlock cancelBlock = [imageLoader decodeImageData:data size:CGSizeMake(1, 1) scale:1.0 resizeMode:RCTResizeModeStretch completionBlock:^(NSError *decodeError, id decodedImage) {
     XCTAssertEqualObjects(decodedImage, image);
     XCTAssertNil(decodeError);
   }];
diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTImageUtilTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTImageUtilTests.m
index f1effc8d64e1..19229d045cc0 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTImageUtilTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTImageUtilTests.m
@@ -46,19 +46,19 @@ - (void)testLandscapeSourceLandscapeTarget
 
   {
     CGRect expected = {CGPointZero, {100, 20}};
-    CGRect result = RCTTargetRect(content, target, 1, UIViewContentModeScaleToFill);
+    CGRect result = RCTTargetRect(content, target, 1, RCTResizeModeStretch);
     RCTAssertEqualRects(expected, result);
   }
 
   {
-    CGRect expected = {CGPointZero, {100, 10}};
-    CGRect result = RCTTargetRect(content, target, 1, UIViewContentModeScaleAspectFit);
+    CGRect expected = {{0, 5}, {100, 10}};
+    CGRect result = RCTTargetRect(content, target, 1, RCTResizeModeContain);
     RCTAssertEqualRects(expected, result);
   }
 
   {
     CGRect expected = {{-50, 0}, {200, 20}};
-    CGRect result = RCTTargetRect(content, target, 1, UIViewContentModeScaleAspectFill);
+    CGRect result = RCTTargetRect(content, target, 1, RCTResizeModeCover);
     RCTAssertEqualRects(expected, result);
   }
 }
@@ -70,19 +70,19 @@ - (void)testPortraitSourceLandscapeTarget
 
   {
     CGRect expected = {CGPointZero, {100, 20}};
-    CGRect result = RCTTargetRect(content, target, 1, UIViewContentModeScaleToFill);
+    CGRect result = RCTTargetRect(content, target, 1, RCTResizeModeStretch);
     RCTAssertEqualRects(expected, result);
   }
 
   {
-    CGRect expected = {CGPointZero, {2, 20}};
-    CGRect result = RCTTargetRect(content, target, 1, UIViewContentModeScaleAspectFit);
+    CGRect expected = {{49, 0}, {2, 20}};
+    CGRect result = RCTTargetRect(content, target, 1, RCTResizeModeContain);
     RCTAssertEqualRects(expected, result);
   }
 
   {
     CGRect expected = {{0, -490}, {100, 1000}};
-    CGRect result = RCTTargetRect(content, target, 1, UIViewContentModeScaleAspectFill);
+    CGRect result = RCTTargetRect(content, target, 1, RCTResizeModeCover);
     RCTAssertEqualRects(expected, result);
   }
 }
@@ -94,19 +94,19 @@ - (void)testPortraitSourcePortraitTarget
 
   {
     CGRect expected = {CGPointZero, {20, 50}};
-    CGRect result = RCTTargetRect(content, target, 1, UIViewContentModeScaleToFill);
+    CGRect result = RCTTargetRect(content, target, 1, RCTResizeModeStretch);
     RCTAssertEqualRects(expected, result);
   }
 
   {
-    CGRect expected = {CGPointZero, {5, 50}};
-    CGRect result = RCTTargetRect(content, target, 1, UIViewContentModeScaleAspectFit);
+    CGRect expected = {{7,0}, {5, 50}};
+    CGRect result = RCTTargetRect(content, target, 1, RCTResizeModeContain);
     RCTAssertEqualRects(expected, result);
   }
 
   {
     CGRect expected = {{0, -75}, {20, 200}};
-    CGRect result = RCTTargetRect(content, target, 2, UIViewContentModeScaleAspectFill);
+    CGRect result = RCTTargetRect(content, target, 2, RCTResizeModeCover);
     RCTAssertEqualRects(expected, result);
   }
 }
@@ -118,7 +118,7 @@ - (void)testRounding
 
   {
     CGRect expected = {{0, -75}, {20, 200}};
-    CGRect result = RCTTargetRect(content, target, 1, UIViewContentModeScaleAspectFill);
+    CGRect result = RCTTargetRect(content, target, 1, RCTResizeModeCover);
     RCTAssertEqualRects(expected, result);
   }
 }
@@ -129,7 +129,7 @@ - (void)testScaling
   CGSize target = {3, 3};
 
   CGRect expected = {CGPointZero, {3, 3}};
-  CGRect result = RCTTargetRect(content, target, 1, UIViewContentModeScaleToFill);
+  CGRect result = RCTTargetRect(content, target, 1, RCTResizeModeStretch);
   RCTAssertEqualRects(expected, result);
 }
 
diff --git a/Libraries/CameraRoll/RCTAssetsLibraryImageLoader.m b/Libraries/CameraRoll/RCTAssetsLibraryImageLoader.m
deleted file mode 100644
index f5cd3cb25cec..000000000000
--- a/Libraries/CameraRoll/RCTAssetsLibraryImageLoader.m
+++ /dev/null
@@ -1,168 +0,0 @@
-/**
- * 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.
- */
-
-#import "RCTAssetsLibraryImageLoader.h"
-
-#import <AssetsLibrary/AssetsLibrary.h>
-#import <ImageIO/ImageIO.h>
-#import <libkern/OSAtomic.h>
-#import <UIKit/UIKit.h>
-
-#import "RCTBridge.h"
-#import "RCTConvert.h"
-#import "RCTImageLoader.h"
-#import "RCTImageUtils.h"
-#import "RCTUtils.h"
-
-static dispatch_queue_t RCTAssetsLibraryImageLoaderQueue(void);
-
-@implementation RCTAssetsLibraryImageLoader
-{
-  ALAssetsLibrary *_assetsLibrary;
-}
-
-RCT_EXPORT_MODULE()
-
-@synthesize bridge = _bridge;
-
-- (ALAssetsLibrary *)assetsLibrary
-{
-  return _assetsLibrary ?: (_assetsLibrary = [ALAssetsLibrary new]);
-}
-
-#pragma mark - RCTImageLoader
-
-- (BOOL)canLoadImageURL:(NSURL *)requestURL
-{
-  return [requestURL.scheme caseInsensitiveCompare:@"assets-library"] == NSOrderedSame;
-}
-
-- (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL
-                                              size:(CGSize)size
-                                             scale:(CGFloat)scale
-                                        resizeMode:(UIViewContentMode)resizeMode
-                                   progressHandler:(RCTImageLoaderProgressBlock)progressHandler
-                                 completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
-{
-  __block volatile uint32_t cancelled = 0;
-
-  [[self assetsLibrary] assetForURL:imageURL resultBlock:^(ALAsset *asset) {
-    if (cancelled) {
-      return;
-    }
-
-    if (asset) {
-      // ALAssetLibrary API is async and will be multi-threaded. Loading a few full
-      // resolution images at once will spike the memory up to store the image data,
-      // and might trigger memory warnings and/or OOM crashes.
-      // To improve this, process the loaded asset in a serial queue.
-      dispatch_async(RCTAssetsLibraryImageLoaderQueue(), ^{
-        if (cancelled) {
-          return;
-        }
-
-        // Also make sure the image is released immediately after it's used so it
-        // doesn't spike the memory up during the process.
-        @autoreleasepool {
-          BOOL useMaximumSize = CGSizeEqualToSize(size, CGSizeZero);
-          ALAssetRepresentation *representation = [asset defaultRepresentation];
-
-#if RCT_DEV
-
-          CGSize sizeBeingLoaded = size;
-          if (useMaximumSize) {
-            CGSize pointSize = representation.dimensions;
-            sizeBeingLoaded = CGSizeMake(pointSize.width * representation.scale, pointSize.height * representation.scale);
-          }
-
-          CGSize screenSize;
-          if ([[[UIDevice currentDevice] systemVersion] compare:@"8.0" options:NSNumericSearch] == NSOrderedDescending) {
-            screenSize = [UIScreen mainScreen].nativeBounds.size;
-          } else {
-            CGSize mainScreenSize = [UIScreen mainScreen].bounds.size;
-            CGFloat mainScreenScale = [[UIScreen mainScreen] scale];
-            screenSize = CGSizeMake(mainScreenSize.width * mainScreenScale, mainScreenSize.height * mainScreenScale);
-          }
-          CGFloat maximumPixelDimension = fmax(screenSize.width, screenSize.height);
-
-          if (sizeBeingLoaded.width > maximumPixelDimension || sizeBeingLoaded.height > maximumPixelDimension) {
-            RCTLogInfo(@"[PERF ASSETS] Loading %@ at size %@, which is larger than screen size %@",
-                       representation.filename, NSStringFromCGSize(sizeBeingLoaded), NSStringFromCGSize(screenSize));
-          }
-
-#endif
-
-          UIImage *image = nil;
-          NSError *error = nil;
-          if (useMaximumSize) {
-
-            image = [UIImage imageWithCGImage:representation.fullResolutionImage
-                                        scale:scale
-                                  orientation:(UIImageOrientation)representation.orientation];
-          } else {
-
-            NSUInteger length = (NSUInteger)representation.size;
-            uint8_t *buffer = (uint8_t *)malloc((size_t)length);
-            if ([representation getBytes:buffer
-                                fromOffset:0
-                                    length:length
-                                      error:&error]) {
-
-              NSData *data = [[NSData alloc] initWithBytesNoCopy:buffer
-                                                          length:length
-                                                    freeWhenDone:YES];
-
-              image = RCTDecodeImageWithData(data, size, scale, resizeMode);
-            } else {
-              free(buffer);
-            }
-          }
-
-          completionHandler(error, image);
-        }
-      });
-    } else {
-      NSString *errorText = [NSString stringWithFormat:@"Failed to load asset at URL %@ with no error message.", imageURL];
-      completionHandler(RCTErrorWithMessage(errorText), nil);
-    }
-  } failureBlock:^(NSError *loadError) {
-    if (cancelled) {
-      return;
-    }
-
-    NSString *errorText = [NSString stringWithFormat:@"Failed to load asset at URL %@.\niOS Error: %@", imageURL, loadError];
-    completionHandler(RCTErrorWithMessage(errorText), nil);
-  }];
-
-  return ^{
-    OSAtomicOr32Barrier(1, &cancelled);
-  };
-}
-
-@end
-
-@implementation RCTBridge (RCTAssetsLibraryImageLoader)
-
-- (ALAssetsLibrary *)assetsLibrary
-{
-  return [[self moduleForClass:[RCTAssetsLibraryImageLoader class]] assetsLibrary];
-}
-
-@end
-
-static dispatch_queue_t RCTAssetsLibraryImageLoaderQueue(void)
-{
-  static dispatch_queue_t queue;
-  static dispatch_once_t onceToken;
-  dispatch_once(&onceToken, ^{
-    queue = dispatch_queue_create("com.facebook.RCTAssetsLibraryImageLoader", DISPATCH_QUEUE_SERIAL);
-  });
-
-  return queue;
-}
diff --git a/Libraries/CameraRoll/RCTAssetsLibraryImageLoader.h b/Libraries/CameraRoll/RCTAssetsLibraryRequestHandler.h
similarity index 75%
rename from Libraries/CameraRoll/RCTAssetsLibraryImageLoader.h
rename to Libraries/CameraRoll/RCTAssetsLibraryRequestHandler.h
index 0cc1c5353088..4ce68bc3b312 100644
--- a/Libraries/CameraRoll/RCTAssetsLibraryImageLoader.h
+++ b/Libraries/CameraRoll/RCTAssetsLibraryRequestHandler.h
@@ -7,9 +7,12 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  */
 
-#import "RCTImageLoader.h"
+#import "RCTBridge.h"
+#import "RCTURLRequestHandler.h"
 
-@interface RCTAssetsLibraryImageLoader : NSObject <RCTImageURLLoader>
+@class ALAssetsLibrary;
+
+@interface RCTAssetsLibraryRequestHandler : NSObject <RCTURLRequestHandler>
 
 @end
 
diff --git a/Libraries/CameraRoll/RCTAssetsLibraryRequestHandler.m b/Libraries/CameraRoll/RCTAssetsLibraryRequestHandler.m
new file mode 100644
index 000000000000..d818f336dbc3
--- /dev/null
+++ b/Libraries/CameraRoll/RCTAssetsLibraryRequestHandler.m
@@ -0,0 +1,114 @@
+/**
+ * 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.
+ */
+
+#import "RCTAssetsLibraryRequestHandler.h"
+
+#import <AssetsLibrary/AssetsLibrary.h>
+#import <libkern/OSAtomic.h>
+
+#import "RCTBridge.h"
+#import "RCTUtils.h"
+
+@implementation RCTAssetsLibraryRequestHandler
+{
+  ALAssetsLibrary *_assetsLibrary;
+}
+
+RCT_EXPORT_MODULE()
+
+@synthesize bridge = _bridge;
+
+- (ALAssetsLibrary *)assetsLibrary
+{
+  return _assetsLibrary ?: (_assetsLibrary = [ALAssetsLibrary new]);
+}
+
+#pragma mark - RCTURLRequestHandler
+
+- (BOOL)canHandleRequest:(NSURLRequest *)request
+{
+  return [request.URL.scheme caseInsensitiveCompare:@"assets-library"] == NSOrderedSame;
+}
+
+- (id)sendRequest:(NSURLRequest *)request
+     withDelegate:(id<RCTURLRequestDelegate>)delegate
+{
+  __block volatile uint32_t cancelled = 0;
+  void (^cancellationBlock)(void) = ^{
+    OSAtomicOr32Barrier(1, &cancelled);
+  };
+
+  [[self assetsLibrary] assetForURL:request.URL resultBlock:^(ALAsset *asset) {
+    if (cancelled) {
+      return;
+    }
+
+    if (asset) {
+
+      ALAssetRepresentation *representation = [asset defaultRepresentation];
+      NSInteger length = (NSInteger)representation.size;
+
+      NSURLResponse *response =
+      [[NSURLResponse alloc] initWithURL:request.URL
+                                MIMEType:representation.UTI
+                   expectedContentLength:length
+                        textEncodingName:nil];
+
+      [delegate URLRequest:cancellationBlock didReceiveResponse:response];
+
+      NSError *error = nil;
+      uint8_t *buffer = (uint8_t *)malloc((size_t)length);
+      if ([representation getBytes:buffer
+                        fromOffset:0
+                            length:length
+                             error:&error]) {
+
+        NSData *data = [[NSData alloc] initWithBytesNoCopy:buffer
+                                                    length:length
+                                              freeWhenDone:YES];
+
+        [delegate URLRequest:cancellationBlock didReceiveData:data];
+        [delegate URLRequest:cancellationBlock didCompleteWithError:nil];
+
+      } else {
+        free(buffer);
+        [delegate URLRequest:cancellationBlock didCompleteWithError:error];
+      }
+
+    } else {
+      NSString *errorMessage = [NSString stringWithFormat:@"Failed to load asset"
+                                " at URL %@ with no error message.", request.URL];
+      NSError *error = RCTErrorWithMessage(errorMessage);
+      [delegate URLRequest:cancellationBlock didCompleteWithError:error];
+    }
+  } failureBlock:^(NSError *loadError) {
+    if (cancelled) {
+      return;
+    }
+    [delegate URLRequest:cancellationBlock didCompleteWithError:loadError];
+  }];
+
+  return cancellationBlock;
+}
+
+- (void)cancelRequest:(id)requestToken
+{
+  ((void (^)(void))requestToken)();
+}
+
+@end
+
+@implementation RCTBridge (RCTAssetsLibraryImageLoader)
+
+- (ALAssetsLibrary *)assetsLibrary
+{
+  return [[self moduleForClass:[RCTAssetsLibraryRequestHandler class]] assetsLibrary];
+}
+
+@end
diff --git a/Libraries/CameraRoll/RCTCameraRoll.xcodeproj/project.pbxproj b/Libraries/CameraRoll/RCTCameraRoll.xcodeproj/project.pbxproj
index 56cced2147f1..a8bb79d92aa9 100644
--- a/Libraries/CameraRoll/RCTCameraRoll.xcodeproj/project.pbxproj
+++ b/Libraries/CameraRoll/RCTCameraRoll.xcodeproj/project.pbxproj
@@ -9,7 +9,7 @@
 /* Begin PBXBuildFile section */
 		137620351B31C53500677FF0 /* RCTImagePickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 137620341B31C53500677FF0 /* RCTImagePickerManager.m */; };
 		143879351AAD238D00F088A5 /* RCTCameraRollManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 143879341AAD238D00F088A5 /* RCTCameraRollManager.m */; };
-		8312EAEE1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 8312EAED1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.m */; };
+		8312EAEE1B85EB7C001867A2 /* RCTAssetsLibraryRequestHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 8312EAED1B85EB7C001867A2 /* RCTAssetsLibraryRequestHandler.m */; };
 		8312EAF11B85F071001867A2 /* RCTPhotoLibraryImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 8312EAF01B85F071001867A2 /* RCTPhotoLibraryImageLoader.m */; };
 /* End PBXBuildFile section */
 
@@ -31,8 +31,8 @@
 		143879331AAD238D00F088A5 /* RCTCameraRollManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTCameraRollManager.h; sourceTree = "<group>"; };
 		143879341AAD238D00F088A5 /* RCTCameraRollManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTCameraRollManager.m; sourceTree = "<group>"; };
 		58B5115D1A9E6B3D00147676 /* libRCTCameraRoll.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTCameraRoll.a; sourceTree = BUILT_PRODUCTS_DIR; };
-		8312EAEC1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAssetsLibraryImageLoader.h; sourceTree = "<group>"; };
-		8312EAED1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAssetsLibraryImageLoader.m; sourceTree = "<group>"; };
+		8312EAEC1B85EB7C001867A2 /* RCTAssetsLibraryRequestHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAssetsLibraryRequestHandler.h; sourceTree = "<group>"; };
+		8312EAED1B85EB7C001867A2 /* RCTAssetsLibraryRequestHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAssetsLibraryRequestHandler.m; sourceTree = "<group>"; };
 		8312EAEF1B85F071001867A2 /* RCTPhotoLibraryImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPhotoLibraryImageLoader.h; sourceTree = "<group>"; };
 		8312EAF01B85F071001867A2 /* RCTPhotoLibraryImageLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPhotoLibraryImageLoader.m; sourceTree = "<group>"; };
 /* End PBXFileReference section */
@@ -51,8 +51,8 @@
 		58B511541A9E6B3D00147676 = {
 			isa = PBXGroup;
 			children = (
-				8312EAEC1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.h */,
-				8312EAED1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.m */,
+				8312EAEC1B85EB7C001867A2 /* RCTAssetsLibraryRequestHandler.h */,
+				8312EAED1B85EB7C001867A2 /* RCTAssetsLibraryRequestHandler.m */,
 				143879331AAD238D00F088A5 /* RCTCameraRollManager.h */,
 				143879341AAD238D00F088A5 /* RCTCameraRollManager.m */,
 				137620331B31C53500677FF0 /* RCTImagePickerManager.h */,
@@ -129,7 +129,7 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				8312EAEE1B85EB7C001867A2 /* RCTAssetsLibraryImageLoader.m in Sources */,
+				8312EAEE1B85EB7C001867A2 /* RCTAssetsLibraryRequestHandler.m in Sources */,
 				8312EAF11B85F071001867A2 /* RCTPhotoLibraryImageLoader.m in Sources */,
 				137620351B31C53500677FF0 /* RCTImagePickerManager.m in Sources */,
 				143879351AAD238D00F088A5 /* RCTCameraRollManager.m in Sources */,
diff --git a/Libraries/CameraRoll/RCTCameraRollManager.m b/Libraries/CameraRoll/RCTCameraRollManager.m
index b1c285186b1e..ad4ad171371c 100644
--- a/Libraries/CameraRoll/RCTCameraRollManager.m
+++ b/Libraries/CameraRoll/RCTCameraRollManager.m
@@ -13,7 +13,7 @@
 #import <Foundation/Foundation.h>
 #import <UIKit/UIKit.h>
 
-#import "RCTAssetsLibraryImageLoader.h"
+#import "RCTAssetsLibraryRequestHandler.h"
 #import "RCTBridge.h"
 #import "RCTConvert.h"
 #import "RCTImageLoader.h"
diff --git a/Libraries/CameraRoll/RCTPhotoLibraryImageLoader.m b/Libraries/CameraRoll/RCTPhotoLibraryImageLoader.m
index 33a9cb31bebe..3cb4d1c3b4d5 100644
--- a/Libraries/CameraRoll/RCTPhotoLibraryImageLoader.m
+++ b/Libraries/CameraRoll/RCTPhotoLibraryImageLoader.m
@@ -30,7 +30,7 @@ - (BOOL)canLoadImageURL:(NSURL *)requestURL
 - (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL
                                               size:(CGSize)size
                                              scale:(CGFloat)scale
-                                        resizeMode:(UIViewContentMode)resizeMode
+                                        resizeMode:(RCTResizeMode)resizeMode
                                    progressHandler:(RCTImageLoaderProgressBlock)progressHandler
                                  completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
 {
@@ -71,7 +71,7 @@ - (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL
   }
 
   PHImageContentMode contentMode = PHImageContentModeAspectFill;
-  if (resizeMode == UIViewContentModeScaleAspectFit) {
+  if (resizeMode == RCTResizeModeContain) {
     contentMode = PHImageContentModeAspectFit;
   }
 
diff --git a/Libraries/Image/RCTGIFImageDecoder.m b/Libraries/Image/RCTGIFImageDecoder.m
index b90375856bf3..e578421a7e2f 100644
--- a/Libraries/Image/RCTGIFImageDecoder.m
+++ b/Libraries/Image/RCTGIFImageDecoder.m
@@ -30,7 +30,7 @@ - (BOOL)canDecodeImageData:(NSData *)imageData
 - (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)imageData
                                               size:(CGSize)size
                                              scale:(CGFloat)scale
-                                        resizeMode:(UIViewContentMode)resizeMode
+                                        resizeMode:(RCTResizeMode)resizeMode
                                  completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
 {
   CGImageSourceRef imageSource = CGImageSourceCreateWithData((CFDataRef)imageData, NULL);
diff --git a/Libraries/Image/RCTImage.xcodeproj/project.pbxproj b/Libraries/Image/RCTImage.xcodeproj/project.pbxproj
index 0c404f31c6a2..8c9c61861a31 100644
--- a/Libraries/Image/RCTImage.xcodeproj/project.pbxproj
+++ b/Libraries/Image/RCTImage.xcodeproj/project.pbxproj
@@ -11,9 +11,10 @@
 		1304D5AC1AA8C4A30002E2BE /* RCTImageViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1304D5AA1AA8C4A30002E2BE /* RCTImageViewManager.m */; };
 		1304D5B21AA8C50D0002E2BE /* RCTGIFImageDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 1304D5B11AA8C50D0002E2BE /* RCTGIFImageDecoder.m */; };
 		134B00A21B54232B00EC8DFB /* RCTImageUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 134B00A11B54232B00EC8DFB /* RCTImageUtils.m */; };
-		13EF7F0B1BC42D4E003F47DD /* RCTShadowVirtualImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 13EF7F081BC42D4E003F47DD /* RCTShadowVirtualImage.m */; settings = {ASSET_TAGS = (); }; };
-		13EF7F0C1BC42D4E003F47DD /* RCTVirtualImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13EF7F0A1BC42D4E003F47DD /* RCTVirtualImageManager.m */; settings = {ASSET_TAGS = (); }; };
-		13EF7F7F1BC825B1003F47DD /* RCTXCAssetImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 13EF7F7E1BC825B1003F47DD /* RCTXCAssetImageLoader.m */; settings = {ASSET_TAGS = (); }; };
+		139A38841C4D587C00862840 /* RCTResizeMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 139A38831C4D587C00862840 /* RCTResizeMode.m */; };
+		13EF7F0B1BC42D4E003F47DD /* RCTShadowVirtualImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 13EF7F081BC42D4E003F47DD /* RCTShadowVirtualImage.m */; };
+		13EF7F0C1BC42D4E003F47DD /* RCTVirtualImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13EF7F0A1BC42D4E003F47DD /* RCTVirtualImageManager.m */; };
+		13EF7F7F1BC825B1003F47DD /* RCTXCAssetImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 13EF7F7E1BC825B1003F47DD /* RCTXCAssetImageLoader.m */; };
 		143879381AAD32A300F088A5 /* RCTImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 143879371AAD32A300F088A5 /* RCTImageLoader.m */; };
 		35123E6B1B59C99D00EBAD80 /* RCTImageStoreManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 35123E6A1B59C99D00EBAD80 /* RCTImageStoreManager.m */; };
 		354631681B69857700AA0B86 /* RCTImageEditingManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 354631671B69857700AA0B86 /* RCTImageEditingManager.m */; };
@@ -40,6 +41,8 @@
 		1304D5B11AA8C50D0002E2BE /* RCTGIFImageDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTGIFImageDecoder.m; sourceTree = "<group>"; };
 		134B00A01B54232B00EC8DFB /* RCTImageUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImageUtils.h; sourceTree = "<group>"; };
 		134B00A11B54232B00EC8DFB /* RCTImageUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageUtils.m; sourceTree = "<group>"; };
+		139A38821C4D57AD00862840 /* RCTResizeMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTResizeMode.h; sourceTree = "<group>"; };
+		139A38831C4D587C00862840 /* RCTResizeMode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTResizeMode.m; sourceTree = "<group>"; };
 		13EF7F071BC42D4E003F47DD /* RCTShadowVirtualImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTShadowVirtualImage.h; sourceTree = "<group>"; };
 		13EF7F081BC42D4E003F47DD /* RCTShadowVirtualImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTShadowVirtualImage.m; sourceTree = "<group>"; };
 		13EF7F091BC42D4E003F47DD /* RCTVirtualImageManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVirtualImageManager.h; sourceTree = "<group>"; };
@@ -69,6 +72,8 @@
 		58B511541A9E6B3D00147676 = {
 			isa = PBXGroup;
 			children = (
+				139A38821C4D57AD00862840 /* RCTResizeMode.h */,
+				139A38831C4D587C00862840 /* RCTResizeMode.m */,
 				13EF7F7D1BC825B1003F47DD /* RCTXCAssetImageLoader.h */,
 				13EF7F7E1BC825B1003F47DD /* RCTXCAssetImageLoader.m */,
 				1304D5B01AA8C50D0002E2BE /* RCTGIFImageDecoder.h */,
@@ -165,6 +170,7 @@
 				1304D5B21AA8C50D0002E2BE /* RCTGIFImageDecoder.m in Sources */,
 				143879381AAD32A300F088A5 /* RCTImageLoader.m in Sources */,
 				354631681B69857700AA0B86 /* RCTImageEditingManager.m in Sources */,
+				139A38841C4D587C00862840 /* RCTResizeMode.m in Sources */,
 				1304D5AB1AA8C4A30002E2BE /* RCTImageView.m in Sources */,
 				13EF7F0B1BC42D4E003F47DD /* RCTShadowVirtualImage.m in Sources */,
 				13EF7F7F1BC825B1003F47DD /* RCTXCAssetImageLoader.m in Sources */,
diff --git a/Libraries/Image/RCTImageEditingManager.m b/Libraries/Image/RCTImageEditingManager.m
index 76fbc2703571..2a2ea967161b 100644
--- a/Libraries/Image/RCTImageEditingManager.m
+++ b/Libraries/Image/RCTImageEditingManager.m
@@ -14,6 +14,7 @@
 #import "RCTConvert.h"
 #import "RCTLog.h"
 #import "RCTUtils.h"
+#import "RCTImageUtils.h"
 
 #import "RCTImageStoreManager.h"
 #import "RCTImageLoader.h"
@@ -44,8 +45,6 @@ @implementation RCTImageEditingManager
     [RCTConvert CGSize:cropData[@"size"]]
   };
 
-  NSString *resizeMode = cropData[@"resizeMode"] ?: @"contain";
-
   [_bridge.imageLoader loadImageWithTag:imageTag callback:^(NSError *error, UIImage *image) {
     if (error) {
       errorCallback(error);
@@ -53,17 +52,21 @@ @implementation RCTImageEditingManager
     }
 
     // Crop image
-    CGRect rectToDrawIn = {{-rect.origin.x, -rect.origin.y}, image.size};
-    UIGraphicsBeginImageContextWithOptions(rect.size, !RCTImageHasAlpha(image.CGImage), image.scale);
-    [image drawInRect:rectToDrawIn];
-    UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext();
-    UIGraphicsEndImageContext();
+    CGSize targetSize = rect.size;
+    CGRect targetRect = {{-rect.origin.x, -rect.origin.y}, image.size};
+    CGAffineTransform transform = RCTTransformFromTargetRect(image.size, targetRect);
+    UIImage *croppedImage = RCTTransformImage(image, targetSize, image.scale, transform);
 
+    // Scale image
     if (cropData[@"displaySize"]) {
-      CGSize targetSize = [RCTConvert CGSize:cropData[@"displaySize"]];
-      croppedImage = [self scaleImage:croppedImage targetSize:targetSize resizeMode:resizeMode];
+      targetSize = [RCTConvert CGSize:cropData[@"displaySize"]]; // in pixels
+      RCTResizeMode resizeMode = [RCTConvert RCTResizeMode:cropData[@"resizeMode"] ?: @"contain"];
+      targetRect = RCTTargetRect(croppedImage.size, targetSize, 1, resizeMode);
+      transform = RCTTransformFromTargetRect(image.size, targetRect);
+      croppedImage = RCTTransformImage(image, targetSize, image.scale, transform);
     }
 
+    // Store image
     [_bridge.imageStoreManager storeImage:croppedImage withBlock:^(NSString *croppedImageTag) {
       if (!croppedImageTag) {
         NSString *errorMessage = @"Error storing cropped image in RCTImageStoreManager";
@@ -76,49 +79,4 @@ @implementation RCTImageEditingManager
   }];
 }
 
-- (UIImage *)scaleImage:(UIImage *)image targetSize:(CGSize)targetSize resizeMode:(NSString *)resizeMode
-{
-  if (CGSizeEqualToSize(image.size, targetSize)) {
-    return image;
-  }
-
-  CGFloat imageRatio = image.size.width / image.size.height;
-  CGFloat targetRatio = targetSize.width / targetSize.height;
-
-  CGFloat newWidth = targetSize.width;
-  CGFloat newHeight = targetSize.height;
-
-  // contain vs cover
-  // http://blog.vjeux.com/2013/image/css-container-and-cover.html
-  if ([resizeMode isEqualToString:@"contain"]) {
-    if (imageRatio <= targetRatio) {
-      newWidth = targetSize.height * imageRatio;
-      newHeight = targetSize.height;
-    } else {
-      newWidth = targetSize.width;
-      newHeight = targetSize.width / imageRatio;
-    }
-  } else if ([resizeMode isEqualToString:@"cover"]) {
-    if (imageRatio <= targetRatio) {
-      newWidth = targetSize.width;
-      newHeight = targetSize.width / imageRatio;
-    } else {
-      newWidth = targetSize.height * imageRatio;
-      newHeight = targetSize.height;
-    }
-  } // else assume we're stretching the image
-
-  // prevent upscaling
-  newWidth = MIN(newWidth, image.size.width);
-  newHeight = MIN(newHeight, image.size.height);
-
-  // perform the scaling @1x because targetSize is in actual pixel width/height
-  UIGraphicsBeginImageContextWithOptions(targetSize, NO, 1.0f);
-  [image drawInRect:CGRectMake(0.f, 0.f, newWidth, newHeight)];
-  UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
-  UIGraphicsEndImageContext();
-
-  return scaledImage;
-}
-
 @end
diff --git a/Libraries/Image/RCTImageLoader.h b/Libraries/Image/RCTImageLoader.h
index c9bea5437777..e7805b135cfa 100644
--- a/Libraries/Image/RCTImageLoader.h
+++ b/Libraries/Image/RCTImageLoader.h
@@ -11,6 +11,7 @@
 
 #import "RCTBridge.h"
 #import "RCTURLRequestHandler.h"
+#import "RCTResizeMode.h"
 
 @class ALAssetsLibrary;
 
@@ -40,10 +41,20 @@ typedef void (^RCTImageLoaderCancellationBlock)(void);
 - (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag
                                                size:(CGSize)size
                                               scale:(CGFloat)scale
-                                         resizeMode:(UIViewContentMode)resizeMode
+                                         resizeMode:(RCTResizeMode)resizeMode
                                       progressBlock:(RCTImageLoaderProgressBlock)progressBlock
                                     completionBlock:(RCTImageLoaderCompletionBlock)completionBlock;
 
+/**
+ * Loads an image without clipping the result to fit - used by RCTImageView.
+ */
+- (RCTImageLoaderCancellationBlock)loadImageWithoutClipping:(NSString *)imageTag
+                                                       size:(CGSize)size
+                                                      scale:(CGFloat)scale
+                                                 resizeMode:(RCTResizeMode)resizeMode
+                                              progressBlock:(RCTImageLoaderProgressBlock)progressBlock
+                                            completionBlock:(RCTImageLoaderCompletionBlock)completionBlock;
+
 /**
  * Finds an appropriate image decoder and passes the target size, scale and
  * resizeMode for optimal image decoding. Can be called from any thread,
@@ -52,7 +63,7 @@ typedef void (^RCTImageLoaderCancellationBlock)(void);
 - (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)imageData
                                               size:(CGSize)size
                                              scale:(CGFloat)scale
-                                        resizeMode:(UIViewContentMode)resizeMode
+                                        resizeMode:(RCTResizeMode)resizeMode
                                    completionBlock:(RCTImageLoaderCompletionBlock)completionBlock;
 
 /**
@@ -96,7 +107,7 @@ typedef void (^RCTImageLoaderCancellationBlock)(void);
 - (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL
                                               size:(CGSize)size
                                              scale:(CGFloat)scale
-                                        resizeMode:(UIViewContentMode)resizeMode
+                                        resizeMode:(RCTResizeMode)resizeMode
                                    progressHandler:(RCTImageLoaderProgressBlock)progressHandler
                                  completionHandler:(RCTImageLoaderCompletionBlock)completionHandler;
 
@@ -134,7 +145,7 @@ typedef void (^RCTImageLoaderCancellationBlock)(void);
 - (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)imageData
                                               size:(CGSize)size
                                              scale:(CGFloat)scale
-                                        resizeMode:(UIViewContentMode)resizeMode
+                                        resizeMode:(RCTResizeMode)resizeMode
                                  completionHandler:(RCTImageLoaderCompletionBlock)completionHandler;
 
 @optional
diff --git a/Libraries/Image/RCTImageLoader.m b/Libraries/Image/RCTImageLoader.m
index cd681b113114..0d7b06f5c1d5 100644
--- a/Libraries/Image/RCTImageLoader.m
+++ b/Libraries/Image/RCTImageLoader.m
@@ -173,13 +173,31 @@ - (void)setUp
   return nil;
 }
 
+static UIImage *RCTResizeImageIfNeeded(UIImage *image,
+                                       CGSize size,
+                                       CGFloat scale,
+                                       RCTResizeMode resizeMode)
+{
+  if (CGSizeEqualToSize(size, CGSizeZero) ||
+      CGSizeEqualToSize(image.size, CGSizeZero) ||
+      CGSizeEqualToSize(image.size, size)) {
+    return image;
+  }
+  CAKeyframeAnimation *animation = image.reactKeyframeAnimation;
+  CGRect targetSize = RCTTargetRect(image.size, size, scale, resizeMode);
+  CGAffineTransform transform = RCTTransformFromTargetRect(image.size, targetSize);
+  image = RCTTransformImage(image, size, scale, transform);
+  image.reactKeyframeAnimation = animation;
+  return image;
+}
+
 - (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag
                                            callback:(RCTImageLoaderCompletionBlock)callback
 {
   return [self loadImageWithTag:imageTag
                            size:CGSizeZero
                           scale:1
-                     resizeMode:UIViewContentModeScaleToFill
+                     resizeMode:RCTResizeModeStretch
                   progressBlock:nil
                 completionBlock:callback];
 }
@@ -192,7 +210,7 @@ - (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag
 - (RCTImageLoaderCancellationBlock)loadImageOrDataWithTag:(NSString *)imageTag
                                                      size:(CGSize)size
                                                     scale:(CGFloat)scale
-                                               resizeMode:(UIViewContentMode)resizeMode
+                                               resizeMode:(RCTResizeMode)resizeMode
                                             progressBlock:(RCTImageLoaderProgressBlock)progressHandler
                                           completionBlock:(void (^)(NSError *error, id imageOrData))completionBlock
 {
@@ -352,9 +370,26 @@ - (RCTImageLoaderCancellationBlock)loadImageOrDataWithTag:(NSString *)imageTag
 - (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag
                                                size:(CGSize)size
                                               scale:(CGFloat)scale
-                                         resizeMode:(UIViewContentMode)resizeMode
+                                         resizeMode:(RCTResizeMode)resizeMode
                                       progressBlock:(RCTImageLoaderProgressBlock)progressHandler
                                     completionBlock:(RCTImageLoaderCompletionBlock)completionBlock
+{
+  return [self loadImageWithoutClipping:imageTag
+                                   size:size
+                                  scale:scale
+                             resizeMode:resizeMode
+                          progressBlock:progressHandler
+                        completionBlock:^(NSError *error, UIImage *image) {
+                          completionBlock(error, RCTResizeImageIfNeeded(image, size, scale, resizeMode));
+                        }];
+}
+
+- (RCTImageLoaderCancellationBlock)loadImageWithoutClipping:(NSString *)imageTag
+                                                       size:(CGSize)size
+                                                      scale:(CGFloat)scale
+                                                 resizeMode:(RCTResizeMode)resizeMode
+                                              progressBlock:(RCTImageLoaderProgressBlock)progressHandler
+                                            completionBlock:(RCTImageLoaderCompletionBlock)completionBlock
 {
   __block volatile uint32_t cancelled = 0;
   __block void(^cancelLoad)(void) = nil;
@@ -365,11 +400,11 @@ - (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag
       if (!imageOrData || [imageOrData isKindOfClass:[UIImage class]]) {
         completionBlock(error, imageOrData);
       } else {
-        cancelLoad = [weakSelf decodeImageData:imageOrData
-                                          size:size
-                                         scale:scale
-                                    resizeMode:resizeMode
-                               completionBlock:completionBlock] ?: ^{};
+        cancelLoad = [weakSelf decodeImageDataWithoutClipping:imageOrData
+                                                         size:size
+                                                        scale:scale
+                                                   resizeMode:resizeMode
+                                              completionBlock:completionBlock] ?: ^{};
       }
     }
   };
@@ -391,17 +426,47 @@ - (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag
 - (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)data
                                               size:(CGSize)size
                                              scale:(CGFloat)scale
-                                        resizeMode:(UIViewContentMode)resizeMode
-                                   completionBlock:(RCTImageLoaderCompletionBlock)completionHandler
+                                        resizeMode:(RCTResizeMode)resizeMode
+                                   completionBlock:(RCTImageLoaderCompletionBlock)completionBlock
+{
+  return [self decodeImageDataWithoutClipping:data
+                                         size:size
+                                        scale:scale
+                                   resizeMode:resizeMode
+                              completionBlock:^(NSError *error, UIImage *image) {
+                                completionBlock(error, RCTResizeImageIfNeeded(image, size, scale, resizeMode));
+                              }];
+}
+
+- (RCTImageLoaderCancellationBlock)decodeImageDataWithoutClipping:(NSData *)data
+                                                             size:(CGSize)size
+                                                            scale:(CGFloat)scale
+                                                       resizeMode:(RCTResizeMode)resizeMode
+                                                  completionBlock:(RCTImageLoaderCompletionBlock)completionBlock
 {
   if (data.length == 0) {
-    completionHandler(RCTErrorWithMessage(@"No image data"), nil);
+    completionBlock(RCTErrorWithMessage(@"No image data"), nil);
     return ^{};
   }
 
+  __block volatile uint32_t cancelled = 0;
+  void (^completionHandler)(NSError *, UIImage *) = ^(NSError *error, UIImage *image) {
+    if ([NSThread isMainThread]) {
+
+      // Most loaders do not return on the main thread, so caller is probably not
+      // expecting it, and may do expensive post-processing in the callback
+      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+        if (!cancelled) {
+          completionBlock(error, image);
+        }
+      });
+    } else if (!cancelled) {
+      completionBlock(error, image);
+    }
+  };
+
   id<RCTImageDataDecoder> imageDecoder = [self imageDataDecoderForData:data];
   if (imageDecoder) {
-
     return [imageDecoder decodeImageData:data
                                     size:size
                                    scale:scale
@@ -409,12 +474,26 @@ - (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)data
                        completionHandler:completionHandler];
   } else {
 
-    __block volatile uint32_t cancelled = 0;
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       if (cancelled) {
         return;
       }
+
       UIImage *image = RCTDecodeImageWithData(data, size, scale, resizeMode);
+
+#if RCT_DEV
+
+      CGSize imagePixelSize = RCTSizeInPixels(image.size, image.scale);
+      CGSize screenPixelSize = RCTSizeInPixels(RCTScreenSize(), RCTScreenScale());
+      if (imagePixelSize.width * imagePixelSize.height >
+          screenPixelSize.width * screenPixelSize.height) {
+        RCTLogInfo(@"[PERF ASSETS] Loading image at size %@, which is larger "
+                   "than the screen size %@", NSStringFromCGSize(imagePixelSize),
+                   NSStringFromCGSize(screenPixelSize));
+      }
+
+#endif
+
       if (image) {
         completionHandler(nil, image);
       } else {
@@ -436,7 +515,7 @@ - (RCTImageLoaderCancellationBlock)getImageSize:(NSString *)imageTag
   return [self loadImageOrDataWithTag:imageTag
                                  size:CGSizeZero
                                 scale:1
-                           resizeMode:UIViewContentModeScaleToFill
+                           resizeMode:RCTResizeModeStretch
                         progressBlock:nil
                       completionBlock:^(NSError *error, id imageOrData) {
                         CGSize size;
@@ -461,7 +540,17 @@ - (RCTImageLoaderCancellationBlock)getImageSize:(NSString *)imageTag
 
 - (BOOL)canHandleRequest:(NSURLRequest *)request
 {
-  return [self imageURLLoaderForURL:request.URL] != nil;
+  NSURL *requestURL = request.URL;
+  for (id<RCTImageURLLoader> loader in _loaders) {
+    // Don't use RCTImageURLLoader protocol for modules that already conform to
+    // RCTURLRequestHandler as it's inefficient to decode an image and then
+    // convert it back into data
+    if (![loader conformsToProtocol:@protocol(RCTURLRequestHandler)] &&
+        [loader canLoadImageURL:requestURL]) {
+      return YES;
+    }
+  }
+  return NO;
 }
 
 - (id)sendRequest:(NSURLRequest *)request withDelegate:(id<RCTURLRequestDelegate>)delegate
diff --git a/Libraries/Image/RCTImageStoreManager.m b/Libraries/Image/RCTImageStoreManager.m
index 1827bd285a71..4c6441a64cda 100644
--- a/Libraries/Image/RCTImageStoreManager.m
+++ b/Libraries/Image/RCTImageStoreManager.m
@@ -217,6 +217,7 @@ - (void)getImageForTag:(NSString *)imageTag withBlock:(void (^)(UIImage *image))
   dispatch_async(_methodQueue, ^{
     NSData *imageData = _store[imageTag];
     dispatch_async(dispatch_get_main_queue(), ^{
+      // imageWithData: is not thread-safe, so we can't do this on methodQueue
       block([UIImage imageWithData:imageData]);
     });
   });
diff --git a/Libraries/Image/RCTImageUtils.h b/Libraries/Image/RCTImageUtils.h
index cb65449db973..f870bda675a2 100644
--- a/Libraries/Image/RCTImageUtils.h
+++ b/Libraries/Image/RCTImageUtils.h
@@ -11,28 +11,36 @@
 #import <UIKit/UIKit.h>
 
 #import "RCTDefines.h"
+#import "RCTResizeMode.h"
 
 NS_ASSUME_NONNULL_BEGIN
 
 /**
- * This function takes an input content size (typically from an image), a target
- * size and scale that it will be drawn at (typically in a CGContext) and then
+ * This function takes an source size (typically from an image), a target size
+ * and scale that it will be drawn at (typically in a CGContext) and then
  * calculates the rectangle to draw the image into so that it will be sized and
- * positioned correctly if drawn using the specified content mode.
+ * positioned correctly according to the specified resizeMode.
  */
 RCT_EXTERN CGRect RCTTargetRect(CGSize sourceSize, CGSize destSize,
-                                CGFloat destScale, UIViewContentMode resizeMode);
+                                CGFloat destScale, RCTResizeMode resizeMode);
+
+/**
+ * This function takes a source size (typically from an image), a target rect
+ * that it will be drawn into (typically relative to a CGContext), and works out
+ * the transform needed to draw the image at the correct scale and position.
+ */
+RCT_EXTERN CGAffineTransform RCTTransformFromTargetRect(CGSize sourceSize,
+                                                        CGRect targetRect);
 
 /**
  * This function takes an input content size & scale (typically from an image),
  * a target size & scale at which it will be displayed (typically in a
  * UIImageView) and then calculates the optimal size at which to redraw the
- * image so that it will be displayed correctly with the specified content mode.
+ * image so that it will be displayed correctly with the specified resizeMode.
  */
 RCT_EXTERN CGSize RCTTargetSize(CGSize sourceSize, CGFloat sourceScale,
                                 CGSize destSize, CGFloat destScale,
-                                UIViewContentMode resizeMode,
-                                BOOL allowUpscaling);
+                                RCTResizeMode resizeMode, BOOL allowUpscaling);
 
 /**
  * This function takes an input content size & scale (typically from an image),
@@ -41,12 +49,7 @@ RCT_EXTERN CGSize RCTTargetSize(CGSize sourceSize, CGFloat sourceScale,
  */
 RCT_EXTERN BOOL RCTUpscalingRequired(CGSize sourceSize, CGFloat sourceScale,
                                      CGSize destSize, CGFloat destScale,
-                                     UIViewContentMode resizeMode);
-/**
- * This function takes a source size and scale and returns the size in pixels.
- * Note that the pixel width/height is rounded up to the nearest integral size.
- */
-RCT_EXTERN CGSize RCTSizeInPixels(CGSize pointSize, CGFloat scale);
+                                     RCTResizeMode resizeMode);
 
 /**
  * This function takes the source data for an image and decodes it at the
@@ -58,7 +61,7 @@ RCT_EXTERN CGSize RCTSizeInPixels(CGSize pointSize, CGFloat scale);
 RCT_EXTERN UIImage *__nullable RCTDecodeImageWithData(NSData *data,
                                                       CGSize destSize,
                                                       CGFloat destScale,
-                                                      UIViewContentMode resizeMode);
+                                                      RCTResizeMode resizeMode);
 
 /**
  * This function takes the source data for an image and decodes just the
@@ -75,4 +78,19 @@ RCT_EXTERN NSDictionary<NSString *, id> *__nullable RCTGetImageMetadata(NSData *
  */
 RCT_EXTERN NSData *__nullable RCTGetImageData(CGImageRef image, float quality);
 
+/**
+ * This function transforms an image. `destSize` is the size of the final image,
+ * and `destScale` is its scale. The `transform` argument controls how the
+ * source image will be mapped to the destination image.
+ */
+RCT_EXTERN UIImage *__nullable RCTTransformImage(UIImage *image,
+                                                 CGSize destSize,
+                                                 CGFloat destScale,
+                                                 CGAffineTransform transform);
+
+/*
+ * Return YES if image has an alpha component
+ */
+RCT_EXTERN BOOL RCTImageHasAlpha(CGImageRef image);
+
 NS_ASSUME_NONNULL_END
diff --git a/Libraries/Image/RCTImageUtils.m b/Libraries/Image/RCTImageUtils.m
index 0b51eca7241d..d484ea238642 100644
--- a/Libraries/Image/RCTImageUtils.m
+++ b/Libraries/Image/RCTImageUtils.m
@@ -35,7 +35,7 @@ static CGSize RCTCeilSize(CGSize size, CGFloat scale)
 }
 
 CGRect RCTTargetRect(CGSize sourceSize, CGSize destSize,
-                     CGFloat destScale, UIViewContentMode resizeMode)
+                     CGFloat destScale, RCTResizeMode resizeMode)
 {
   if (CGSizeEqualToSize(destSize, CGSizeZero)) {
     // Assume we require the largest size available
@@ -58,16 +58,16 @@ CGRect RCTTargetRect(CGSize sourceSize, CGSize destSize,
   if (resizeMode != UIViewContentModeScaleToFill) {
     targetAspect = destSize.width / destSize.height;
     if (aspect == targetAspect) {
-      resizeMode = UIViewContentModeScaleToFill;
+      resizeMode = RCTResizeModeStretch;
     }
   }
 
   switch (resizeMode) {
-    case UIViewContentModeScaleToFill: // stretch
+    case RCTResizeModeStretch:
 
       return (CGRect){CGPointZero, RCTCeilSize(destSize, destScale)};
 
-    case UIViewContentModeScaleAspectFit: // contain
+    case RCTResizeModeContain:
 
       if (targetAspect <= aspect) { // target is taller than content
 
@@ -79,9 +79,15 @@ CGRect RCTTargetRect(CGSize sourceSize, CGSize destSize,
         sourceSize.height = destSize.height = destSize.height;
         sourceSize.width = sourceSize.height * aspect;
       }
-      return (CGRect){CGPointZero, RCTCeilSize(sourceSize, destScale)};
+      return (CGRect){
+        {
+          RCTFloorValue((destSize.width - sourceSize.width) / 2, destScale),
+          RCTFloorValue((destSize.height - sourceSize.height) / 2, destScale),
+        },
+        RCTCeilSize(sourceSize, destScale)
+      };
 
-    case UIViewContentModeScaleAspectFill: // cover
+    case RCTResizeModeCover:
 
       if (targetAspect <= aspect) { // target is taller than content
 
@@ -103,21 +109,28 @@ CGRect RCTTargetRect(CGSize sourceSize, CGSize destSize,
           RCTCeilSize(sourceSize, destScale)
         };
       }
-
-    default:
-
-      RCTLogError(@"A resizeMode value of %zd is not supported", resizeMode);
-      return (CGRect){CGPointZero, RCTCeilSize(destSize, destScale)};
   }
 }
 
+CGAffineTransform RCTTransformFromTargetRect(CGSize sourceSize, CGRect targetRect)
+{
+  CGAffineTransform transform = CGAffineTransformIdentity;
+  transform = CGAffineTransformTranslate(transform,
+                                         targetRect.origin.x,
+                                         targetRect.origin.y);
+  transform = CGAffineTransformScale(transform,
+                                     targetRect.size.width / sourceSize.width,
+                                     targetRect.size.height / sourceSize.height);
+  return transform;
+}
+
 CGSize RCTTargetSize(CGSize sourceSize, CGFloat sourceScale,
                      CGSize destSize, CGFloat destScale,
-                     UIViewContentMode resizeMode,
+                     RCTResizeMode resizeMode,
                      BOOL allowUpscaling)
 {
   switch (resizeMode) {
-    case UIViewContentModeScaleToFill: // stretch
+    case RCTResizeModeStretch:
 
       if (!allowUpscaling) {
         CGFloat scale = sourceScale / destScale;
@@ -143,7 +156,7 @@ CGSize RCTTargetSize(CGSize sourceSize, CGFloat sourceScale,
 
 BOOL RCTUpscalingRequired(CGSize sourceSize, CGFloat sourceScale,
                           CGSize destSize, CGFloat destScale,
-                          UIViewContentMode resizeMode)
+                          RCTResizeMode resizeMode)
 {
   if (CGSizeEqualToSize(destSize, CGSizeZero)) {
     // Assume we require the largest size available
@@ -161,16 +174,16 @@ BOOL RCTUpscalingRequired(CGSize sourceSize, CGFloat sourceScale,
     aspect = sourceSize.width / sourceSize.height;
     targetAspect = destSize.width / destSize.height;
     if (aspect == targetAspect) {
-      resizeMode = UIViewContentModeScaleToFill;
+      resizeMode = RCTResizeModeStretch;
     }
   }
 
   switch (resizeMode) {
-    case UIViewContentModeScaleToFill: // stretch
+    case RCTResizeModeStretch:
 
       return destSize.width > sourceSize.width || destSize.height > sourceSize.height;
 
-    case UIViewContentModeScaleAspectFit: // contain
+    case RCTResizeModeContain:
 
       if (targetAspect <= aspect) { // target is taller than content
 
@@ -181,7 +194,7 @@ BOOL RCTUpscalingRequired(CGSize sourceSize, CGFloat sourceScale,
         return destSize.height > sourceSize.height;
       }
 
-    case UIViewContentModeScaleAspectFill: // cover
+    case RCTResizeModeCover:
 
       if (targetAspect <= aspect) { // target is taller than content
 
@@ -191,33 +204,20 @@ BOOL RCTUpscalingRequired(CGSize sourceSize, CGFloat sourceScale,
 
         return destSize.width > sourceSize.width;
       }
-
-    default:
-
-      RCTLogError(@"A resizeMode value of %zd is not supported", resizeMode);
-      return NO;
   }
 }
 
-CGSize RCTSizeInPixels(CGSize pointSize, CGFloat scale)
-{
-  return (CGSize){
-    ceil(pointSize.width * scale),
-    ceil(pointSize.height * scale),
-  };
-}
-
 UIImage *__nullable RCTDecodeImageWithData(NSData *data,
                                            CGSize destSize,
                                            CGFloat destScale,
-                                           UIViewContentMode resizeMode)
+                                           RCTResizeMode resizeMode)
 {
   CGImageSourceRef sourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
   if (!sourceRef) {
     return nil;
   }
 
-  // get original image size
+  // Get original image size
   CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(sourceRef, 0, NULL);
   if (!imageProperties) {
     CFRelease(sourceRef);
@@ -237,8 +237,14 @@ CGSize RCTSizeInPixels(CGSize pointSize, CGFloat scale)
     destScale = RCTScreenScale();
   }
 
-  // calculate target size
-  CGSize targetSize = RCTTargetSize(sourceSize, 1, destSize, destScale, resizeMode, YES);
+  if (resizeMode == UIViewContentModeScaleToFill) {
+    // Decoder cannot change aspect ratio, so RCTResizeModeStretch is equivalent
+    // to RCTResizeModeCover for our purposes
+    resizeMode = RCTResizeModeCover;
+  }
+
+  // Calculate target size
+  CGSize targetSize = RCTTargetSize(sourceSize, 1, destSize, destScale, resizeMode, NO);
   CGSize targetPixelSize = RCTSizeInPixels(targetSize, destScale);
   CGFloat maxPixelSize = fmax(fmin(sourceSize.width, targetPixelSize.width),
                               fmin(sourceSize.height, targetPixelSize.height));
@@ -250,14 +256,14 @@ CGSize RCTSizeInPixels(CGSize pointSize, CGFloat scale)
     (id)kCGImageSourceThumbnailMaxPixelSize: @(maxPixelSize),
   };
 
-  // get thumbnail
+  // Get thumbnail
   CGImageRef imageRef = CGImageSourceCreateThumbnailAtIndex(sourceRef, 0, (__bridge CFDictionaryRef)options);
   CFRelease(sourceRef);
   if (!imageRef) {
     return nil;
   }
 
-  // return image
+  // Return image
   UIImage *image = [UIImage imageWithCGImage:imageRef
                                        scale:destScale
                                  orientation:UIImageOrientationUp];
@@ -298,3 +304,33 @@ CGSize RCTSizeInPixels(CGSize pointSize, CGFloat scale)
   CFRelease(destination);
   return (__bridge_transfer NSData *)imageData;
 }
+
+UIImage *__nullable RCTTransformImage(UIImage *image,
+                                      CGSize destSize,
+                                      CGFloat destScale,
+                                      CGAffineTransform transform)
+{
+  if (destSize.width <= 0 | destSize.height <= 0 || destScale <= 0) {
+    return nil;
+  }
+
+  UIGraphicsBeginImageContextWithOptions(destSize, NO, destScale);
+  CGContextRef currentContext = UIGraphicsGetCurrentContext();
+  CGContextConcatCTM(currentContext, transform);
+  [image drawAtPoint:CGPointZero];
+  UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
+  UIGraphicsGetCurrentContext();
+  return result;
+}
+
+BOOL RCTImageHasAlpha(CGImageRef image)
+{
+  switch (CGImageGetAlphaInfo(image)) {
+    case kCGImageAlphaNone:
+    case kCGImageAlphaNoneSkipLast:
+    case kCGImageAlphaNoneSkipFirst:
+      return NO;
+    default:
+      return YES;
+  }
+}
diff --git a/Libraries/Image/RCTImageView.h b/Libraries/Image/RCTImageView.h
index 8b5b993a731a..769f9c965d1e 100644
--- a/Libraries/Image/RCTImageView.h
+++ b/Libraries/Image/RCTImageView.h
@@ -9,6 +9,7 @@
 
 #import <UIKit/UIKit.h>
 #import "RCTImageComponent.h"
+#import "RCTResizeMode.h"
 
 @class RCTBridge;
 @class RCTImageSource;
diff --git a/Libraries/Image/RCTImageView.m b/Libraries/Image/RCTImageView.m
index 712f7e7a56db..36506d348d45 100644
--- a/Libraries/Image/RCTImageView.m
+++ b/Libraries/Image/RCTImageView.m
@@ -103,8 +103,15 @@ - (void)setImage:(UIImage *)image
 - (void)setCapInsets:(UIEdgeInsets)capInsets
 {
   if (!UIEdgeInsetsEqualToEdgeInsets(_capInsets, capInsets)) {
-    _capInsets = capInsets;
-    [self updateImage];
+    if (UIEdgeInsetsEqualToEdgeInsets(_capInsets, UIEdgeInsetsZero) ||
+        UIEdgeInsetsEqualToEdgeInsets(capInsets, UIEdgeInsetsZero)) {
+      _capInsets = capInsets;
+      // Need to reload image when enabling or disabling capInsets
+      [self reloadImage];
+    } else {
+      _capInsets = capInsets;
+      [self updateImage];
+    }
   }
 }
 
@@ -126,12 +133,8 @@ - (void)setSource:(RCTImageSource *)source
 
 - (BOOL)sourceNeedsReload
 {
-  NSString *scheme = _source.imageURL.scheme;
-  return
-    [scheme isEqualToString:@"http"] ||
-    [scheme isEqualToString:@"https"] ||
-    [scheme isEqualToString:@"assets-library"] ||
-    [scheme isEqualToString:@"ph"];
+  // If capInsets are set, image doesn't need reloading when resized
+  return UIEdgeInsetsEqualToEdgeInsets(_capInsets, UIEdgeInsetsZero);
 }
 
 - (void)setContentMode:(UIViewContentMode)contentMode
@@ -179,14 +182,22 @@ - (void)reloadImage
       };
     }
 
+    CGSize imageSize = self.bounds.size;
+    CGFloat imageScale = RCTScreenScale();
+    if (!UIEdgeInsetsEqualToEdgeInsets(_capInsets, UIEdgeInsetsZero)) {
+      // Don't resize images that use capInsets
+      imageSize = CGSizeZero;
+      imageScale = _source.scale;
+    }
+
     RCTImageSource *source = _source;
     __weak RCTImageView *weakSelf = self;
-    _reloadImageCancellationBlock = [_bridge.imageLoader loadImageWithTag:_source.imageURL.absoluteString
-                                                                     size:self.bounds.size
-                                                                    scale:RCTScreenScale()
-                                                               resizeMode:self.contentMode
-                                                            progressBlock:progressHandler
-                                                          completionBlock:^(NSError *error, UIImage *image) {
+    _reloadImageCancellationBlock = [_bridge.imageLoader loadImageWithoutClipping:_source.imageURL.absoluteString
+                                                                             size:imageSize
+                                                                            scale:imageScale
+                                                                       resizeMode:(RCTResizeMode)self.contentMode
+                                                                    progressBlock:progressHandler
+                                                                  completionBlock:^(NSError *error, UIImage *image) {
       dispatch_async(dispatch_get_main_queue(), ^{
         RCTImageView *strongSelf = weakSelf;
         if (![source isEqual:strongSelf.source]) {
@@ -227,14 +238,15 @@ - (void)reactSetFrame:(CGRect)frame
     [self reloadImage];
   } else if ([self sourceNeedsReload]) {
     CGSize imageSize = self.image.size;
-    CGSize idealSize = RCTTargetSize(imageSize, self.image.scale, frame.size, RCTScreenScale(), self.contentMode, YES);
+    CGSize idealSize = RCTTargetSize(imageSize, self.image.scale, frame.size,
+                                     RCTScreenScale(), (RCTResizeMode)self.contentMode, YES);
 
     if (RCTShouldReloadImageForSizeChange(imageSize, idealSize)) {
       if (RCTShouldReloadImageForSizeChange(_targetSize, idealSize)) {
         RCTLogInfo(@"[PERF IMAGEVIEW] Reloading image %@ as size %@", _source.imageURL, NSStringFromCGSize(idealSize));
 
-        // If the existing image or an image being loaded are not the right size, reload the asset in case there is a
-        // better size available.
+        // If the existing image or an image being loaded are not the right
+        // size, reload the asset in case there is a better size available.
         _targetSize = idealSize;
         [self reloadImage];
       }
@@ -251,8 +263,8 @@ - (void)didMoveToWindow
   [super didMoveToWindow];
 
   if (!self.window) {
-    // Don't keep self alive through the asynchronous dispatch, if the intention was to remove the view so it would
-    // deallocate.
+    // Don't keep self alive through the asynchronous dispatch, if the intention
+    // was to remove the view so it would deallocate.
     __weak typeof(self) weakSelf = self;
 
     dispatch_async(dispatch_get_main_queue(), ^{
@@ -261,7 +273,8 @@ - (void)didMoveToWindow
         return;
       }
 
-      // If we haven't been re-added to a window by this run loop iteration, clear out the image to save memory.
+      // If we haven't been re-added to a window by this run loop iteration,
+      // clear out the image to save memory.
       if (!strongSelf.window) {
         [strongSelf clearImage];
       }
diff --git a/Libraries/Image/RCTImageViewManager.m b/Libraries/Image/RCTImageViewManager.m
index 7ef593195aa4..65e18b5a2a9c 100644
--- a/Libraries/Image/RCTImageViewManager.m
+++ b/Libraries/Image/RCTImageViewManager.m
@@ -32,7 +32,7 @@ - (UIView *)view
 RCT_EXPORT_VIEW_PROPERTY(onError, RCTDirectEventBlock)
 RCT_EXPORT_VIEW_PROPERTY(onLoad, RCTDirectEventBlock)
 RCT_EXPORT_VIEW_PROPERTY(onLoadEnd, RCTDirectEventBlock)
-RCT_REMAP_VIEW_PROPERTY(resizeMode, contentMode, UIViewContentMode)
+RCT_REMAP_VIEW_PROPERTY(resizeMode, contentMode, RCTResizeMode)
 RCT_EXPORT_VIEW_PROPERTY(source, RCTImageSource)
 RCT_CUSTOM_VIEW_PROPERTY(tintColor, UIColor, RCTImageView)
 {
diff --git a/Libraries/Image/RCTResizeMode.h b/Libraries/Image/RCTResizeMode.h
new file mode 100644
index 000000000000..81e9d925fa9d
--- /dev/null
+++ b/Libraries/Image/RCTResizeMode.h
@@ -0,0 +1,22 @@
+/**
+ * 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.
+ */
+
+#import "RCTConvert.h"
+
+typedef NS_ENUM(NSInteger, RCTResizeMode) {
+  RCTResizeModeCover = UIViewContentModeScaleAspectFill,
+  RCTResizeModeContain = UIViewContentModeScaleAspectFit,
+  RCTResizeModeStretch = UIViewContentModeScaleToFill,
+};
+
+@interface RCTConvert(RCTResizeMode)
+
++ (RCTResizeMode)RCTResizeMode:(id)json;
+
+@end
diff --git a/Libraries/Image/RCTResizeMode.m b/Libraries/Image/RCTResizeMode.m
new file mode 100644
index 000000000000..b80839bb4426
--- /dev/null
+++ b/Libraries/Image/RCTResizeMode.m
@@ -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.
+ */
+
+#import "RCTResizeMode.h"
+
+@implementation RCTConvert(RCTResizeMode)
+
+RCT_ENUM_CONVERTER(RCTResizeMode, (@{
+  @"cover": @(RCTResizeModeCover),
+  @"contain": @(RCTResizeModeContain),
+  @"stretch": @(RCTResizeModeStretch),
+}), RCTResizeModeStretch, integerValue)
+
+@end
diff --git a/Libraries/Image/RCTShadowVirtualImage.m b/Libraries/Image/RCTShadowVirtualImage.m
index f3486f9a2f7a..d6b0153d11cc 100644
--- a/Libraries/Image/RCTShadowVirtualImage.m
+++ b/Libraries/Image/RCTShadowVirtualImage.m
@@ -46,7 +46,7 @@ - (void)setSource:(RCTImageSource *)source
     _cancellationBlock = [_bridge.imageLoader loadImageWithTag:source.imageURL.absoluteString
                                                           size:source.size
                                                          scale:source.scale
-                                                    resizeMode:UIViewContentModeScaleToFill
+                                                    resizeMode:RCTResizeModeStretch
                                                  progressBlock:nil
                                                completionBlock:^(NSError *error, UIImage *image) {
 
diff --git a/Libraries/Image/RCTXCAssetImageLoader.m b/Libraries/Image/RCTXCAssetImageLoader.m
index 799798a36629..750a1f848ed1 100644
--- a/Libraries/Image/RCTXCAssetImageLoader.m
+++ b/Libraries/Image/RCTXCAssetImageLoader.m
@@ -25,7 +25,7 @@ - (BOOL)canLoadImageURL:(NSURL *)requestURL
  - (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL
                                                size:(CGSize)size
                                               scale:(CGFloat)scale
-                                         resizeMode:(UIViewContentMode)resizeMode
+                                         resizeMode:(RCTResizeMode)resizeMode
                                     progressHandler:(RCTImageLoaderProgressBlock)progressHandler
                                   completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
 {
diff --git a/React/Base/RCTUtils.h b/React/Base/RCTUtils.h
index 36383e8c61ab..7c8aaa511138 100644
--- a/React/Base/RCTUtils.h
+++ b/React/Base/RCTUtils.h
@@ -40,6 +40,9 @@ RCT_EXTERN CGFloat RCTRoundPixelValue(CGFloat value);
 RCT_EXTERN CGFloat RCTCeilPixelValue(CGFloat value);
 RCT_EXTERN CGFloat RCTFloorPixelValue(CGFloat value);
 
+// Convert a size in points to pixels, rounded up to the nearest integral size
+RCT_EXTERN CGSize RCTSizeInPixels(CGSize pointSize, CGFloat scale);
+
 // Method swizzling
 RCT_EXTERN void RCTSwapClassMethods(Class cls, SEL original, SEL replacement);
 RCT_EXTERN void RCTSwapInstanceMethods(Class cls, SEL original, SEL replacement);
@@ -78,9 +81,6 @@ RCT_EXTERN UIAlertView *RCTAlertView(NSString *title,
                                      NSString *cancelButtonTitle,
                                      NSArray<NSString *> *otherButtonTitles);
 
-// Return YES if image has an alpha component
-RCT_EXTERN BOOL RCTImageHasAlpha(CGImageRef image);
-
 // Create an NSError in the RCTErrorDomain
 RCT_EXTERN NSError *RCTErrorWithMessage(NSString *message);
 
diff --git a/React/Base/RCTUtils.m b/React/Base/RCTUtils.m
index cf0d8b8b00e4..b13b3f951fdc 100644
--- a/React/Base/RCTUtils.m
+++ b/React/Base/RCTUtils.m
@@ -219,7 +219,13 @@ CGSize RCTScreenSize()
   static dispatch_once_t onceToken;
   dispatch_once(&onceToken, ^{
     RCTExecuteOnMainThread(^{
-      size = [UIScreen mainScreen].bounds.size;
+      if ([[[UIDevice currentDevice] systemVersion] compare:@"8.0" options:NSNumericSearch] == NSOrderedDescending) {
+        CGSize pixelSize = [UIScreen mainScreen].nativeBounds.size;
+        CGFloat scale = RCTScreenScale();
+        size = (CGSize){pixelSize.width / scale, pixelSize.height / scale};
+      } else {
+        size = [UIScreen mainScreen].bounds.size;
+      }
     }, YES);
   });
 
@@ -244,6 +250,14 @@ CGFloat RCTFloorPixelValue(CGFloat value)
   return floor(value * scale) / scale;
 }
 
+CGSize RCTSizeInPixels(CGSize pointSize, CGFloat scale)
+{
+  return (CGSize){
+    ceil(pointSize.width * scale),
+    ceil(pointSize.height * scale),
+  };
+}
+
 void RCTSwapClassMethods(Class cls, SEL original, SEL replacement)
 {
   Method originalMethod = class_getClassMethod(cls, original);
@@ -401,18 +415,6 @@ BOOL RCTRunningInAppExtension(void)
   return alertView;
 }
 
-BOOL RCTImageHasAlpha(CGImageRef image)
-{
-  switch (CGImageGetAlphaInfo(image)) {
-    case kCGImageAlphaNone:
-    case kCGImageAlphaNoneSkipLast:
-    case kCGImageAlphaNoneSkipFirst:
-      return NO;
-    default:
-      return YES;
-  }
-}
-
 NSError *RCTErrorWithMessage(NSString *message)
 {
   NSDictionary<NSString *, id> *errorInfo = @{NSLocalizedDescriptionKey: message};
diff --git a/React/Views/RCTComponentData.m b/React/Views/RCTComponentData.m
index 78952700603b..34f2742a6dd7 100644
--- a/React/Views/RCTComponentData.m
+++ b/React/Views/RCTComponentData.m
@@ -172,6 +172,10 @@ - (RCTPropBlock)propBlockForKey:(NSString *)name defaultView:(id)defaultView
 
         // Ordinary property handlers
         NSMethodSignature *typeSignature = [[RCTConvert class] methodSignatureForSelector:type];
+        if (!typeSignature) {
+          RCTLogError(@"No +[RCTConvert %@] function found.", NSStringFromSelector(type));
+          return ^(__unused id<RCTComponent> view, __unused id json){};
+        }
         switch (typeSignature.methodReturnType[0]) {
 
   #define RCT_CASE(_value, _type) \

From b9a8be97bc445edac024a35d644d5c86419a7f3a Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Wed, 20 Jan 2016 11:20:25 -0800
Subject: [PATCH 0811/1411] Build code depending on resources from the
 appcompat library with both Buck and Gradle

Reviewed By: sdwilsh

Differential Revision: D2844961

fb-gh-sync-id: 686a9f253eb370a9dc8cc33ca1c4e8453f89210a
---
 .../v7/appcompat/res-unpacker.py              | 20 +++++++++++++++++++
 1 file changed, 20 insertions(+)
 create mode 100644 ReactAndroid/src/main/third-party/android-support-for-standalone-apps/v7/appcompat/res-unpacker.py

diff --git a/ReactAndroid/src/main/third-party/android-support-for-standalone-apps/v7/appcompat/res-unpacker.py b/ReactAndroid/src/main/third-party/android-support-for-standalone-apps/v7/appcompat/res-unpacker.py
new file mode 100644
index 000000000000..145d09b02a73
--- /dev/null
+++ b/ReactAndroid/src/main/third-party/android-support-for-standalone-apps/v7/appcompat/res-unpacker.py
@@ -0,0 +1,20 @@
+import contextlib
+import os
+import shutil
+import sys
+import tempfile
+import zipfile
+
+# Helper that unpacks the contents of the res folder of an .aar file
+# into given destination.
+
+@contextlib.contextmanager
+def cleanup(path):
+    yield path
+    shutil.rmtree(path)
+
+if __name__ == '__main__':
+    with zipfile.ZipFile(sys.argv[1], 'r') as z:
+        with cleanup(tempfile.mkdtemp()) as temp_path:
+            z.extractall(temp_path, filter(lambda n: n.startswith('res/'), z.namelist()))
+            shutil.move(os.path.join(temp_path, 'res'), sys.argv[2])

From ab87033185b3bf9b08b69c8e0e3ed2cbc651376d Mon Sep 17 00:00:00 2001
From: Tim Yung <yungsters@fb.com>
Date: Wed, 20 Jan 2016 15:13:14 -0800
Subject: [PATCH 0812/1411] RN: Teach YellowBox to Count

Reviewed By: kassens

Differential Revision: D2846410

fb-gh-sync-id: 03127ff30cac54679ed0dbb225551efafb0cafa8
---
 Libraries/ReactIOS/YellowBox.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/ReactIOS/YellowBox.js b/Libraries/ReactIOS/YellowBox.js
index 692cd4f6e6c2..e1dddc14541e 100644
--- a/Libraries/ReactIOS/YellowBox.js
+++ b/Libraries/ReactIOS/YellowBox.js
@@ -83,7 +83,7 @@ function updateWarningMap(format, ...args): void {
   ].join(' ');
 
   const count = _warningMap.has(warning) ? _warningMap.get(warning) : 0;
-  _warningMap.set(warning, count + 2);
+  _warningMap.set(warning, count + 1);
   _warningEmitter.emit('warning', _warningMap);
 }
 

From a1cd6cf678c0fdd8415c46ec04a69aaa2f2763ba Mon Sep 17 00:00:00 2001
From: Takayuki Imai <bkhr.dat@gmail.com>
Date: Thu, 21 Jan 2016 11:47:21 +0900
Subject: [PATCH 0813/1411] Add utayomin to showcase

---
 website/src/react-native/showcase.js | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index f1b58706d17a..b3530354daa6 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -531,6 +531,13 @@ var apps = [
     icon: 'http://7xk1ez.com2.z0.glb.qiniucdn.com/logo-mobile-0114logo_welcom.png',
     link: 'https://itunes.apple.com/us/app/ni-zao-me/id1025294933?l=zh&ls=1&mt=8',
     author: 'Scott Chen(@NZAOM)'
+  },
+  {
+    name: 'うたよみん',
+    icon: 'http://a4.mzstatic.com/jp/r30/Purple69/v4/19/8f/fa/198ffafe-66a6-d682-c8d1-47faf2b0badb/icon175x175.jpeg',
+    linkAppStore: 'https://itunes.apple.com/jp/app/minnano-duan-ge-tou-gaokomyuniti/id675671254?mt=8',
+    linkPlayStore: 'https://play.google.com/store/apps/details?id=com.plasticaromantica.utayomin',
+    author: 'Takayuki IMAI'
   }
 ];
 

From 48117ce6c4350cd1336f0d37608d2f2829dd3c29 Mon Sep 17 00:00:00 2001
From: Jeff Berg <jeff@ministrycentered.com>
Date: Wed, 20 Jan 2016 20:35:18 -0800
Subject: [PATCH 0814/1411] Fix TouchNativeFeedback so that the ripple starts
 from where a person touches

Summary:
It needs the touch coordinates for with-in the element, not for on the page.
Closes https://github.com/facebook/react-native/pull/5400

Reviewed By: svcscm

Differential Revision: D2848834

Pulled By: androidtrunkagent

fb-gh-sync-id: 88cf0fd7bd2332eb3db835b26438064412c8358c
---
 Libraries/Components/Touchable/Touchable.js                   | 4 +++-
 .../Components/Touchable/TouchableNativeFeedback.android.js   | 2 +-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/Libraries/Components/Touchable/Touchable.js b/Libraries/Components/Touchable/Touchable.js
index c8d67ab3e176..f9d8e1e43346 100644
--- a/Libraries/Components/Touchable/Touchable.js
+++ b/Libraries/Components/Touchable/Touchable.js
@@ -623,7 +623,9 @@ var TouchableMixin = {
     var touch = TouchEventUtils.extractSingleTouch(e.nativeEvent);
     var pageX = touch && touch.pageX;
     var pageY = touch && touch.pageY;
-    this.pressInLocation = {pageX: pageX, pageY: pageY};
+    var locationX = touch && touch.locationX;
+    var locationY = touch && touch.locationY;
+    this.pressInLocation = {pageX, pageY, locationX, locationY};
   },
 
   _getDistanceBetweenPoints: function (aX, aY, bX, bY) {
diff --git a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js
index 240b2482a056..ec3850c6bf93 100644
--- a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js
+++ b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js
@@ -141,7 +141,7 @@ var TouchableNativeFeedback = React.createClass({
   touchableHandleActivePressIn: function() {
     this.props.onPressIn && this.props.onPressIn();
     this._dispatchPressedStateChange(true);
-    this._dispatchHotspotUpdate(this.pressInLocation.pageX, this.pressInLocation.pageY);
+    this._dispatchHotspotUpdate(this.pressInLocation.locationX, this.pressInLocation.locationY);
   },
 
   touchableHandleActivePressOut: function() {

From a9a7c7889991b1f43052a3c5260d79f07329d570 Mon Sep 17 00:00:00 2001
From: Marc Horowitz <mhorowitz@fb.com>
Date: Wed, 20 Jan 2016 22:31:48 -0800
Subject: [PATCH 0815/1411] Expose setGlobalVariable in CatalystInstance
 interface

Summary:
this helps with cleaning up some tests
public

Reviewed By: astreet

Differential Revision: D2816285

fb-gh-sync-id: 37c4da7bdb3c8b5439184316bb5a8939160b40a3
---
 .../com/facebook/react/bridge/CatalystInstance.java   |  4 ++++
 .../facebook/react/bridge/CatalystInstanceImpl.java   | 11 ++++++-----
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
index e9240eb88815..c0c98cf799cd 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
@@ -12,6 +12,7 @@
 import java.util.Collection;
 
 import com.facebook.react.bridge.queue.CatalystQueueConfiguration;
+import com.facebook.react.common.annotations.VisibleForTesting;
 import com.facebook.proguard.annotations.DoNotStrip;
 import com.facebook.react.common.annotations.VisibleForTesting;
 
@@ -66,4 +67,7 @@ public interface CatalystInstance {
   boolean supportsProfiling();
   void startProfiler(String title);
   void stopProfiler(String title, String filename);
+
+  @VisibleForTesting
+  void setGlobalVariable(String propName, String jsonValue);
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
index 70af8e3804f7..31fe7a528cc8 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
@@ -306,11 +306,6 @@ public CatalystQueueConfiguration getCatalystQueueConfiguration() {
     return mCatalystQueueConfiguration;
   }
 
-  @VisibleForTesting
-  public ReactBridge getBridge() {
-    return mBridge;
-  }
-
   @Override
   public <T extends JavaScriptModule> T getJSModule(Class<T> jsInterface) {
     return Assertions.assertNotNull(mJSModuleRegistry).getJavaScriptModule(jsInterface);
@@ -366,6 +361,12 @@ public void stopProfiler(String title, String filename) {
     mBridge.stopProfiler(title, filename);
   }
 
+  @VisibleForTesting
+  @Override
+  public void setGlobalVariable(String propName, String jsonValue) {
+    mBridge.setGlobalVariable(propName, jsonValue);
+  }
+
   private String buildModulesConfigJSONProperty(
       NativeModuleRegistry nativeModuleRegistry,
       JavaScriptModulesConfig jsModulesConfig) {

From 847220957aec7e094d66b1a6436cd3850e2c1291 Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeux@fb.com>
Date: Wed, 20 Jan 2016 23:46:25 -0800
Subject: [PATCH 0816/1411] Add "Edit on GitHub" link on normal docs pages

Summary:
<img width="938" alt="screen shot 2016-01-20 at 10 38 23 pm" src="https://cloud.githubusercontent.com/assets/197597/12473376/8f0ac970-bfc6-11e5-9e44-0481e9f250f1.png">
Closes https://github.com/facebook/react-native/pull/5454

Reviewed By: svcscm

Differential Revision: D2849235

Pulled By: vjeux

fb-gh-sync-id: 0103f3d5249b1dfc03aa77feb9ae3bb7bbe9c746
---
 website/layout/DocsLayout.js |  9 ++++++++-
 website/server/convert.js    | 10 +++++++---
 2 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/website/layout/DocsLayout.js b/website/layout/DocsLayout.js
index 12ba1ebf3a2e..b0cb690668fb 100644
--- a/website/layout/DocsLayout.js
+++ b/website/layout/DocsLayout.js
@@ -23,7 +23,14 @@ var DocsLayout = React.createClass({
           <DocsSidebar metadata={metadata} />
           <div className="inner-content">
             <a id="content" />
-            <h1>{metadata.title}</h1>
+            <h1>
+              {metadata.title}
+              <a
+                className="edit-github"
+                href={'https://github.com/facebook/react-native/blob/master/docs/' + metadata.filename}>
+                Edit on GitHub
+              </a>
+            </h1>
             <Marked>{content}</Marked>
             <div className="docs-prevnext">
               {metadata.previous && <a className="docs-prev" href={metadata.previous + '.html#content'}>&larr; Prev</a>}
diff --git a/website/server/convert.js b/website/server/convert.js
index e3b95f0ba1f5..62289e34cdde 100644
--- a/website/server/convert.js
+++ b/website/server/convert.js
@@ -52,7 +52,7 @@ function execute() {
     files: [],
   };
 
-  function handleMarkdown(content) {
+  function handleMarkdown(content, filename) {
     var metadata = {};
 
     // Extract markdown metadata header
@@ -78,6 +78,8 @@ function execute() {
       return;
     }
 
+    metadata.filename = filename;
+
     // Create a dummy .js version that just calls the associated layout
     var layout = metadata.layout[0].toUpperCase() + metadata.layout.substr(1) + 'Layout';
 
@@ -105,14 +107,16 @@ function execute() {
     fs.writeFileSync(targetFile, content);
   }
 
-  extractDocs().forEach(handleMarkdown);
+  extractDocs().forEach(function(content) {
+    handleMarkdown(content, null);
+  });
 
   var files = glob.sync(MD_DIR + '**/*.*');
   files.forEach(function(file) {
     var extension = path.extname(file);
     if (extension === '.md' || extension === '.markdown') {
       var content = fs.readFileSync(file, {encoding: 'utf8'});
-      handleMarkdown(content);
+      handleMarkdown(content, path.basename(file));
     }
 
     if (extension === '.json') {

From 342a7630f12ec78c2849802053e83afe4d95a117 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Thu, 21 Jan 2016 04:22:00 -0800
Subject: [PATCH 0817/1411] When using split builds, don't generate universal
 APK

Summary:
Closes https://github.com/facebook/react-native/issues/5452

public

Reviewed By: foghina

Differential Revision: D2849769

fb-gh-sync-id: 93a53b05dc39560529a916fbeeb74efa761a7d7e
---
 local-cli/generator-android/templates/src/app/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/local-cli/generator-android/templates/src/app/build.gradle b/local-cli/generator-android/templates/src/app/build.gradle
index 68f2f417ff04..943b871a27c1 100644
--- a/local-cli/generator-android/templates/src/app/build.gradle
+++ b/local-cli/generator-android/templates/src/app/build.gradle
@@ -92,7 +92,7 @@ android {
     splits {
         abi {
             enable enableSeparateBuildPerCPUArchitecture
-            universalApk true
+            universalApk false
             reset()
             include "armeabi-v7a", "x86"
         }

From d8b55391512a7c5da1f84b20dd390ee193f4787f Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Thu, 21 Jan 2016 04:30:52 -0800
Subject: [PATCH 0818/1411] Add a dummy .so file to make sure we don't export
 these to github

Reviewed By: bestander

Differential Revision: D2849772

fb-gh-sync-id: 514bb6245feb3652cbc6d1d5a029eed47dc068aa
---
 ReactAndroid/src/main/jni/prebuilt/lib/android-armv7/libdummy.so | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 ReactAndroid/src/main/jni/prebuilt/lib/android-armv7/libdummy.so

diff --git a/ReactAndroid/src/main/jni/prebuilt/lib/android-armv7/libdummy.so b/ReactAndroid/src/main/jni/prebuilt/lib/android-armv7/libdummy.so
new file mode 100644
index 000000000000..1f3fe3afa071
--- /dev/null
+++ b/ReactAndroid/src/main/jni/prebuilt/lib/android-armv7/libdummy.so
@@ -0,0 +1 @@
+Just a dummy file to double check it won't get exported to github.
\ No newline at end of file

From f97138f36f34d2aa046d48c5e0a32a8bb570c1ec Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Thu, 21 Jan 2016 05:23:39 -0800
Subject: [PATCH 0819/1411] Build first-party C++ deps of OSS React Native with
 Buck

Reviewed By: sdwilsh

Differential Revision: D2840290

fb-gh-sync-id: 3dd4f7ee83a520d5c01f7864f443a04aa73b35fa
---
 .../jni/fbjni/android/ReferenceChecking.cpp   | 37 +++++++++++++++++++
 1 file changed, 37 insertions(+)
 create mode 100644 ReactAndroid/src/main/jni/first-party/jni/fbjni/android/ReferenceChecking.cpp

diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/android/ReferenceChecking.cpp b/ReactAndroid/src/main/jni/first-party/jni/fbjni/android/ReferenceChecking.cpp
new file mode 100644
index 000000000000..e17eb2af5b8c
--- /dev/null
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/android/ReferenceChecking.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#ifndef __ANDROID__
+#error "This file should only be compiled for Android."
+#endif
+
+#include <jni/fbjni/References.h>
+#include <jni/fbjni/CoreClasses.h>
+
+namespace facebook {
+namespace jni {
+namespace internal {
+
+static int32_t getApiLevel() {
+  auto cls = findClassLocal("android/os/Build$VERSION");
+  auto fld = cls->getStaticField<int32_t>("SDK_INT");
+  if (fld) {
+    return cls->getStaticFieldValue(fld);
+  }
+  return 0;
+}
+
+bool doesGetObjectRefTypeWork() {
+  static auto level = getApiLevel();
+  return level >= 14;
+}
+
+}
+}
+}
\ No newline at end of file

From e10166a1a3394fb06dddec4e5b03880bf5a4094c Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Thu, 21 Jan 2016 15:03:25 +0000
Subject: [PATCH 0820/1411] Update Releases.md

---
 Releases.md | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/Releases.md b/Releases.md
index efbd057b614f..1032b1a5a84d 100644
--- a/Releases.md
+++ b/Releases.md
@@ -35,6 +35,13 @@ Make absolutely sure a basic iOS and Android workflow works on the release branc
 
   - Check git history, the last commit should be "[0.19-rc] Bump version numbers" (with the correct version)
   - `git push origin 0.version_you_are_releasing-stable`
+  
+## Make sure we have release notes
+
+Post that we're ready to release so voluteers can write release notes:
+https://github.com/facebook/react-native/releases
+
+To through all the commits that went into a release, one way is to use the github compare view: https://github.com/facebook/react-native/compare/0.18-stable...0.19-stable
 
 ## Do a release
 

From d806b755443a210a8f2a6eb511f89c79fa96e580 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Thu, 21 Jan 2016 15:04:30 +0000
Subject: [PATCH 0821/1411] Update Releases.md

---
 Releases.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Releases.md b/Releases.md
index 1032b1a5a84d..80a15f9a78dc 100644
--- a/Releases.md
+++ b/Releases.md
@@ -41,7 +41,7 @@ Make absolutely sure a basic iOS and Android workflow works on the release branc
 Post that we're ready to release so voluteers can write release notes:
 https://github.com/facebook/react-native/releases
 
-To through all the commits that went into a release, one way is to use the github compare view: https://github.com/facebook/react-native/compare/0.18-stable...0.19-stable
+To go through all the commits that went into a release, one way is to use the github compare view: https://github.com/facebook/react-native/compare/0.18-stable...0.19-stable
 
 ## Do a release
 

From d33b554f5d4bb7856cf2fc21175bab23d8225fe4 Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Thu, 21 Jan 2016 07:22:20 -0800
Subject: [PATCH 0822/1411] Make the packager work with babel strict mode
 transform

Summary:
At the moment we have to disable strict mode for the transform-es2015-modules-commonjs because strict mode leaks to the global scope and breaks the bridge. It was due to the way the polyfills were bundled in the package. To fix it, I wrapped the polyfill modules in an IIFE. Then when strict mode was enabled some polyfills were broken due to strict mode errors so that was fixed too. Also removed the IIFE from the polyfills that included one.

This diff doesn't enable the strict mode transform since some internal facebook modules depend on it not being enabled. When #5214 lands we could make the default babel config shipped with OSS react-native use strict mode modules and facebook could just modify the babel config to disable it if needed.

This will allow removing `"strict": false` from https://github.com/facebook/react-native/blob/master/packager/react-packager/.babelrc#L16

Fixes #5316
Closes https://github.com/facebook/react-native/pull/5422

Reviewed By: svcscm

Differential Revision: D2846422

Pulled By: davidaurelio

fb-gh-sync-id: a3e2f8909aa87dabab2b872c61b887e80220fb56
---
 .../InitializeJavaScriptAppEngine.js          |  27 +-
 .../JavaScriptAppEngine/polyfills/document.js |  56 +-
 Libraries/vendor/emitter/mixInEventEmitter.js |   3 +-
 .../src/Resolver/__tests__/Resolver-test.js   |  29 +
 packager/react-packager/src/Resolver/index.js |  12 +-
 .../Resolver/polyfills/Array.prototype.es6.js |  87 +-
 .../src/Resolver/polyfills/babelHelpers.js    | 347 ++++----
 .../src/Resolver/polyfills/console.js         | 799 +++++++++---------
 .../src/Resolver/polyfills/error-guard.js     | 132 ++-
 .../src/Resolver/polyfills/loadBundles.js     |  74 +-
 .../src/Resolver/polyfills/polyfills.js       |   2 +-
 .../src/Resolver/polyfills/prelude.js         |   7 +-
 .../src/Resolver/polyfills/prelude_dev.js     |   7 +-
 .../Resolver/polyfills/require-unbundle.js    | 109 ++-
 .../src/Resolver/polyfills/require.js         | 206 +++--
 .../__tests__/dead-module-elimination-test.js |  14 +-
 .../dead-module-elimination.js                |   9 +-
 17 files changed, 970 insertions(+), 950 deletions(-)

diff --git a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
index 37f507c2e1ee..dea05fa95226 100644
--- a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
+++ b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
@@ -25,11 +25,11 @@
 require('regenerator/runtime');
 
 if (typeof GLOBAL === 'undefined') {
-  GLOBAL = this;
+  global.GLOBAL = this;
 }
 
 if (typeof window === 'undefined') {
-  window = GLOBAL;
+  global.window = GLOBAL;
 }
 
 function setUpConsole() {
@@ -70,6 +70,15 @@ function polyfillGlobal(name, newValue, scope = GLOBAL) {
   Object.defineProperty(scope, name, {...descriptor, value: newValue});
 }
 
+/**
+ * Polyfill a module if it is not already defined in `scope`.
+ */
+function polyfillIfNeeded(name, polyfill, scope = GLOBAL, descriptor = {}) {
+  if (scope[name] === undefined) {
+    Object.defineProperty(scope, name, {...descriptor, value: polyfill});
+  }
+}
+
 function setUpErrorHandler() {
   if (global.__fbDisableExceptionsManager) {
     return;
@@ -78,7 +87,7 @@ function setUpErrorHandler() {
   function handleError(e, isFatal) {
     try {
       require('ExceptionsManager').handleException(e, isFatal);
-    } catch(ee) {
+    } catch (ee) {
       console.log('Failed to print error: ', ee.message);
     }
   }
@@ -146,7 +155,11 @@ function setUpXHR() {
 }
 
 function setUpGeolocation() {
-  GLOBAL.navigator = GLOBAL.navigator || {};
+  polyfillIfNeeded('navigator', {}, GLOBAL, {
+    writable: true,
+    enumerable: true,
+    configurable: true,
+  });
   polyfillGlobal('geolocation', require('Geolocation'), GLOBAL.navigator);
 }
 
@@ -179,9 +192,9 @@ function setUpProcessEnv() {
 }
 
 function setUpNumber() {
-  Number.EPSILON = Number.EPSILON || Math.pow(2, -52);
-  Number.MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || Math.pow(2, 53) - 1;
-  Number.MIN_SAFE_INTEGER = Number.MIN_SAFE_INTEGER || -(Math.pow(2, 53) - 1);
+  polyfillIfNeeded('EPSILON', Math.pow(2, -52), Number);
+  polyfillIfNeeded('MAX_SAFE_INTEGER', Math.pow(2, 53) - 1, Number);
+  polyfillIfNeeded('MIN_SAFE_INTEGER', -(Math.pow(2, 53) - 1), Number);
 }
 
 function setUpDevTools() {
diff --git a/Libraries/JavaScriptAppEngine/polyfills/document.js b/Libraries/JavaScriptAppEngine/polyfills/document.js
index 4e76db957259..bff669cce915 100644
--- a/Libraries/JavaScriptAppEngine/polyfills/document.js
+++ b/Libraries/JavaScriptAppEngine/polyfills/document.js
@@ -1,34 +1,30 @@
-/* eslint global-strict: 0 */
-(function(GLOBAL) {
-  /**
-   * The document must be shimmed before anything else that might define the
-   * `ExecutionEnvironment` module (which checks for `document.createElement`).
-   */
+/* eslint strict: 0 */
 
-  // The browser defines Text and Image globals by default. If you forget to
-  // require them, then the error message is very confusing.
-  function getInvalidGlobalUseError(name) {
-    return new Error(
-      'You are trying to render the global ' + name + ' variable as a ' +
-      'React element. You probably forgot to require ' + name + '.'
-    );
+// TODO: Remove document polyfill now that chrome debugging is in a web worker.
+
+// The browser defines Text and Image globals by default. If you forget to
+// require them, then the error message is very confusing.
+function getInvalidGlobalUseError(name) {
+  return new Error(
+    'You are trying to render the global ' + name + ' variable as a ' +
+    'React element. You probably forgot to require ' + name + '.'
+  );
+}
+global.Text = {
+  get defaultProps() {
+    throw getInvalidGlobalUseError('Text');
   }
-  GLOBAL.Text = {
-    get defaultProps() {
-      throw getInvalidGlobalUseError('Text');
-    }
-  };
-  GLOBAL.Image = {
-    get defaultProps() {
-      throw getInvalidGlobalUseError('Image');
-    }
-  };
-  // Force `ExecutionEnvironment.canUseDOM` to be false.
-  if (GLOBAL.document) {
-    GLOBAL.document.createElement = null;
+};
+global.Image = {
+  get defaultProps() {
+    throw getInvalidGlobalUseError('Image');
   }
+};
+// Force `ExecutionEnvironment.canUseDOM` to be false.
+if (global.document) {
+  global.document.createElement = null;
+}
 
-  // There is no DOM so MutationObserver doesn't make sense. It is used
-  // as feature detection in Bluebird Promise implementation
-  GLOBAL.MutationObserver = undefined;
-})(this);
+// There is no DOM so MutationObserver doesn't make sense. It is used
+// as feature detection in Bluebird Promise implementation
+global.MutationObserver = undefined;
diff --git a/Libraries/vendor/emitter/mixInEventEmitter.js b/Libraries/vendor/emitter/mixInEventEmitter.js
index cc62d04d4635..4dc938199d40 100644
--- a/Libraries/vendor/emitter/mixInEventEmitter.js
+++ b/Libraries/vendor/emitter/mixInEventEmitter.js
@@ -49,12 +49,13 @@ var TYPES_KEY = keyOf({__types: true});
  */
 function mixInEventEmitter(klass, types) {
   invariant(types, 'Must supply set of valid event types');
-  invariant(!this.__eventEmitter, 'An active emitter is already mixed in');
 
   // If this is a constructor, write to the prototype, otherwise write to the
   // singleton object.
   var target = klass.prototype || klass;
 
+  invariant(!target.__eventEmitter, 'An active emitter is already mixed in');
+
   var ctor = klass.constructor;
   if (ctor) {
     invariant(
diff --git a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
index 82184c61bb33..825399b4a023 100644
--- a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
+++ b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
@@ -58,6 +58,14 @@ describe('Resolver', function() {
     return module;
   }
 
+  function createPolyfill(id, dependencies) {
+    var polyfill = new Polyfill({});
+    polyfill.getName.mockImpl(() => Promise.resolve(id));
+    polyfill.getDependencies.mockImpl(() => Promise.resolve(dependencies));
+    polyfill.isPolyfill.mockReturnValue(true);
+    return polyfill;
+  }
+
   describe('getDependencies', function() {
     pit('should get dependencies with polyfills', function() {
       var module = createModule('index');
@@ -1020,5 +1028,26 @@ describe('Resolver', function() {
         ].join('\n'));
       });
     });
+
+    pit('should resolve polyfills', function () {
+      const depResolver = new Resolver({
+        projectRoot: '/root',
+      });
+      const polyfill = createPolyfill('test polyfill', []);
+      const code = [
+        'global.fetch = () => 1;',
+      ].join('');
+      return depResolver.wrapModule(
+        null,
+        polyfill,
+        code
+      ).then(processedCode => {
+        expect(processedCode.code).toEqual([
+          '(function(global) {',
+          'global.fetch = () => 1;',
+          "\n})(typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this);",
+        ].join(''));
+      });
+    });
   });
 });
diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index cf021e16f968..0166681f0b3e 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -214,7 +214,9 @@ class Resolver {
 
   wrapModule(resolutionResponse, module, code) {
     if (module.isPolyfill()) {
-      return Promise.resolve({code});
+      return Promise.resolve({
+        code: definePolyfillCode(code),
+      });
     }
 
     return this.resolveRequires(resolutionResponse, module, code).then(
@@ -239,4 +241,12 @@ function defineModuleCode(moduleName, code) {
   ].join('');
 }
 
+function definePolyfillCode(code) {
+  return [
+    '(function(global) {',
+    code,
+    `\n})(typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this);`,
+  ].join('');
+}
+
 module.exports = Resolver;
diff --git a/packager/react-packager/src/Resolver/polyfills/Array.prototype.es6.js b/packager/react-packager/src/Resolver/polyfills/Array.prototype.es6.js
index 80e62f05dee3..2752aab5e5d0 100644
--- a/packager/react-packager/src/Resolver/polyfills/Array.prototype.es6.js
+++ b/packager/react-packager/src/Resolver/polyfills/Array.prototype.es6.js
@@ -5,54 +5,51 @@
  * @polyfill
  */
 
-/*eslint-disable */
-/*jslint bitwise: true */
+/* eslint-disable */
 
-(function(undefined) {
-  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex
-  function findIndex(predicate, context) {
-    if (this == null) {
-      throw new TypeError(
-        'Array.prototype.findIndex called on null or undefined'
-      );
-    }
-    if (typeof predicate !== 'function') {
-      throw new TypeError('predicate must be a function');
-    }
-    var list = Object(this);
-    var length = list.length >>> 0;
-    for (var i = 0; i < length; i++) {
-      if (predicate.call(context, list[i], i, list)) {
-        return i;
-      }
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex
+function findIndex(predicate, context) {
+  if (this == null) {
+    throw new TypeError(
+      'Array.prototype.findIndex called on null or undefined'
+    );
+  }
+  if (typeof predicate !== 'function') {
+    throw new TypeError('predicate must be a function');
+  }
+  var list = Object(this);
+  var length = list.length >>> 0;
+  for (var i = 0; i < length; i++) {
+    if (predicate.call(context, list[i], i, list)) {
+      return i;
     }
-    return -1;
   }
+  return -1;
+}
 
-  if (!Array.prototype.findIndex) {
-    Object.defineProperty(Array.prototype, 'findIndex', {
-      enumerable: false,
-      writable: true,
-      configurable: true,
-      value: findIndex
-    });
-  }
+if (!Array.prototype.findIndex) {
+  Object.defineProperty(Array.prototype, 'findIndex', {
+    enumerable: false,
+    writable: true,
+    configurable: true,
+    value: findIndex
+  });
+}
 
-  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
-  if (!Array.prototype.find) {
-    Object.defineProperty(Array.prototype, 'find', {
-      enumerable: false,
-      writable: true,
-      configurable: true,
-      value: function(predicate, context) {
-        if (this == null) {
-          throw new TypeError(
-            'Array.prototype.find called on null or undefined'
-          );
-        }
-        var index = findIndex.call(this, predicate, context);
-        return index === -1 ? undefined : this[index];
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
+if (!Array.prototype.find) {
+  Object.defineProperty(Array.prototype, 'find', {
+    enumerable: false,
+    writable: true,
+    configurable: true,
+    value: function(predicate, context) {
+      if (this == null) {
+        throw new TypeError(
+          'Array.prototype.find called on null or undefined'
+        );
       }
-    });
-  }
-})();
+      var index = findIndex.call(this, predicate, context);
+      return index === -1 ? undefined : this[index];
+    }
+  });
+}
diff --git a/packager/react-packager/src/Resolver/polyfills/babelHelpers.js b/packager/react-packager/src/Resolver/polyfills/babelHelpers.js
index de54ebc2c11b..ff4422574089 100644
--- a/packager/react-packager/src/Resolver/polyfills/babelHelpers.js
+++ b/packager/react-packager/src/Resolver/polyfills/babelHelpers.js
@@ -7,8 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  */
 
-/* global self:true */
-/* eslint-disable strict */
+/* eslint-disable */
 
 // Created by running:
 // require('babel-core').buildExternalHelpers('_extends classCallCheck createClass createRawReactElement defineProperty get inherits  interopRequireDefault interopRequireWildcard objectWithoutProperties possibleConstructorReturn slicedToArray taggedTemplateLiteral toArray toConsumableArray '.split(' '))
@@ -16,217 +15,215 @@
 //
 // actually, that's a lie, because babel6 omits _extends and createRawReactElement
 
-(function (global) {
-  var babelHelpers = global.babelHelpers = {};
-
-  babelHelpers.createRawReactElement = (function () {
-    var REACT_ELEMENT_TYPE = typeof Symbol === "function" && Symbol.for && Symbol.for("react.element") || 0xeac7;
-    return function createRawReactElement(type, key, props) {
-      return {
-        $$typeof: REACT_ELEMENT_TYPE,
-        type: type,
-        key: key,
-        ref: null,
-        props: props,
-        _owner: null
-      };
+var babelHelpers = global.babelHelpers = {};
+
+babelHelpers.createRawReactElement = (function () {
+  var REACT_ELEMENT_TYPE = typeof Symbol === "function" && Symbol.for && Symbol.for("react.element") || 0xeac7;
+  return function createRawReactElement(type, key, props) {
+    return {
+      $$typeof: REACT_ELEMENT_TYPE,
+      type: type,
+      key: key,
+      ref: null,
+      props: props,
+      _owner: null
     };
-  })();
-
-  babelHelpers.classCallCheck = function (instance, Constructor) {
-    if (!(instance instanceof Constructor)) {
-      throw new TypeError("Cannot call a class as a function");
-    }
   };
-
-  babelHelpers.createClass = (function () {
-    function defineProperties(target, props) {
-      for (var i = 0; i < props.length; i++) {
-        var descriptor = props[i];
-        descriptor.enumerable = descriptor.enumerable || false;
-        descriptor.configurable = true;
-        if ("value" in descriptor) descriptor.writable = true;
-        Object.defineProperty(target, descriptor.key, descriptor);
-      }
+})();
+
+babelHelpers.classCallCheck = function (instance, Constructor) {
+  if (!(instance instanceof Constructor)) {
+    throw new TypeError("Cannot call a class as a function");
+  }
+};
+
+babelHelpers.createClass = (function () {
+  function defineProperties(target, props) {
+    for (var i = 0; i < props.length; i++) {
+      var descriptor = props[i];
+      descriptor.enumerable = descriptor.enumerable || false;
+      descriptor.configurable = true;
+      if ("value" in descriptor) descriptor.writable = true;
+      Object.defineProperty(target, descriptor.key, descriptor);
     }
+  }
 
-    return function (Constructor, protoProps, staticProps) {
-      if (protoProps) defineProperties(Constructor.prototype, protoProps);
-      if (staticProps) defineProperties(Constructor, staticProps);
-      return Constructor;
-    };
-  })();
-
-  babelHelpers.defineProperty = function (obj, key, value) {
-    if (key in obj) {
-      Object.defineProperty(obj, key, {
-        value: value,
-        enumerable: true,
-        configurable: true,
-        writable: true
-      });
-    } else {
-      obj[key] = value;
-    }
-
-    return obj;
+  return function (Constructor, protoProps, staticProps) {
+    if (protoProps) defineProperties(Constructor.prototype, protoProps);
+    if (staticProps) defineProperties(Constructor, staticProps);
+    return Constructor;
   };
+})();
+
+babelHelpers.defineProperty = function (obj, key, value) {
+  if (key in obj) {
+    Object.defineProperty(obj, key, {
+      value: value,
+      enumerable: true,
+      configurable: true,
+      writable: true
+    });
+  } else {
+    obj[key] = value;
+  }
+
+  return obj;
+};
 
-  babelHelpers._extends = babelHelpers.extends = Object.assign || function (target) {
-    for (var i = 1; i < arguments.length; i++) {
-      var source = arguments[i];
+babelHelpers._extends = babelHelpers.extends = Object.assign || function (target) {
+  for (var i = 1; i < arguments.length; i++) {
+    var source = arguments[i];
 
-      for (var key in source) {
-        if (Object.prototype.hasOwnProperty.call(source, key)) {
-          target[key] = source[key];
-        }
+    for (var key in source) {
+      if (Object.prototype.hasOwnProperty.call(source, key)) {
+        target[key] = source[key];
       }
     }
+  }
 
-    return target;
-  };
+  return target;
+};
 
-  babelHelpers.get = function get(object, property, receiver) {
-    if (object === null) object = Function.prototype;
-    var desc = Object.getOwnPropertyDescriptor(object, property);
+babelHelpers.get = function get(object, property, receiver) {
+  if (object === null) object = Function.prototype;
+  var desc = Object.getOwnPropertyDescriptor(object, property);
 
-    if (desc === undefined) {
-      var parent = Object.getPrototypeOf(object);
+  if (desc === undefined) {
+    var parent = Object.getPrototypeOf(object);
 
-      if (parent === null) {
-        return undefined;
-      } else {
-        return get(parent, property, receiver);
-      }
-    } else if ("value" in desc) {
-      return desc.value;
+    if (parent === null) {
+      return undefined;
     } else {
-      var getter = desc.get;
-
-      if (getter === undefined) {
-        return undefined;
-      }
-
-      return getter.call(receiver);
+      return get(parent, property, receiver);
     }
-  };
+  } else if ("value" in desc) {
+    return desc.value;
+  } else {
+    var getter = desc.get;
 
-  babelHelpers.inherits = function (subClass, superClass) {
-    if (typeof superClass !== "function" && superClass !== null) {
-      throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
+    if (getter === undefined) {
+      return undefined;
     }
 
-    subClass.prototype = Object.create(superClass && superClass.prototype, {
-      constructor: {
-        value: subClass,
-        enumerable: false,
-        writable: true,
-        configurable: true
-      }
-    });
-    if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
-  };
+    return getter.call(receiver);
+  }
+};
+
+babelHelpers.inherits = function (subClass, superClass) {
+  if (typeof superClass !== "function" && superClass !== null) {
+    throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
+  }
+
+  subClass.prototype = Object.create(superClass && superClass.prototype, {
+    constructor: {
+      value: subClass,
+      enumerable: false,
+      writable: true,
+      configurable: true
+    }
+  });
+  if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
+};
 
-  babelHelpers.interopRequireDefault = function (obj) {
-    return obj && obj.__esModule ? obj : {
-      default: obj
-    };
+babelHelpers.interopRequireDefault = function (obj) {
+  return obj && obj.__esModule ? obj : {
+    default: obj
   };
+};
 
-  babelHelpers.interopRequireWildcard = function (obj) {
-    if (obj && obj.__esModule) {
-      return obj;
-    } else {
-      var newObj = {};
+babelHelpers.interopRequireWildcard = function (obj) {
+  if (obj && obj.__esModule) {
+    return obj;
+  } else {
+    var newObj = {};
 
-      if (obj != null) {
-        for (var key in obj) {
-          if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key];
-        }
+    if (obj != null) {
+      for (var key in obj) {
+        if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key];
       }
-
-      newObj.default = obj;
-      return newObj;
     }
-  };
 
-  babelHelpers.objectWithoutProperties = function (obj, keys) {
-    var target = {};
+    newObj.default = obj;
+    return newObj;
+  }
+};
 
-    for (var i in obj) {
-      if (keys.indexOf(i) >= 0) continue;
-      if (!Object.prototype.hasOwnProperty.call(obj, i)) continue;
-      target[i] = obj[i];
-    }
+babelHelpers.objectWithoutProperties = function (obj, keys) {
+  var target = {};
 
-    return target;
-  };
+  for (var i in obj) {
+    if (keys.indexOf(i) >= 0) continue;
+    if (!Object.prototype.hasOwnProperty.call(obj, i)) continue;
+    target[i] = obj[i];
+  }
 
-  babelHelpers.possibleConstructorReturn = function (self, call) {
-    if (!self) {
-      throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
-    }
+  return target;
+};
 
-    return call && (typeof call === "object" || typeof call === "function") ? call : self;
-  };
+babelHelpers.possibleConstructorReturn = function (self, call) {
+  if (!self) {
+    throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+  }
 
-  babelHelpers.slicedToArray = (function () {
-    function sliceIterator(arr, i) {
-      var _arr = [];
-      var _n = true;
-      var _d = false;
-      var _e = undefined;
+  return call && (typeof call === "object" || typeof call === "function") ? call : self;
+};
 
-      try {
-        for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
-          _arr.push(_s.value);
-
-          if (i && _arr.length === i) break;
-        }
-      } catch (err) {
-        _d = true;
-        _e = err;
-      } finally {
-        try {
-          if (!_n && _i["return"]) _i["return"]();
-        } finally {
-          if (_d) throw _e;
-        }
-      }
+babelHelpers.slicedToArray = (function () {
+  function sliceIterator(arr, i) {
+    var _arr = [];
+    var _n = true;
+    var _d = false;
+    var _e = undefined;
 
-      return _arr;
-    }
+    try {
+      for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
+        _arr.push(_s.value);
 
-    return function (arr, i) {
-      if (Array.isArray(arr)) {
-        return arr;
-      } else if (Symbol.iterator in Object(arr)) {
-        return sliceIterator(arr, i);
-      } else {
-        throw new TypeError("Invalid attempt to destructure non-iterable instance");
+        if (i && _arr.length === i) break;
       }
-    };
-  })();
-  
-  babelHelpers.taggedTemplateLiteral = function (strings, raw) {
-    return Object.freeze(Object.defineProperties(strings, {
-      raw: {
-        value: Object.freeze(raw)
+    } catch (err) {
+      _d = true;
+      _e = err;
+    } finally {
+      try {
+        if (!_n && _i["return"]) _i["return"]();
+      } finally {
+        if (_d) throw _e;
       }
-    }));
-  };
+    }
 
-  babelHelpers.toArray = function (arr) {
-    return Array.isArray(arr) ? arr : Array.from(arr);
-  };
+    return _arr;
+  }
 
-  babelHelpers.toConsumableArray = function (arr) {
+  return function (arr, i) {
     if (Array.isArray(arr)) {
-      for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
-
-      return arr2;
+      return arr;
+    } else if (Symbol.iterator in Object(arr)) {
+      return sliceIterator(arr, i);
     } else {
-      return Array.from(arr);
+      throw new TypeError("Invalid attempt to destructure non-iterable instance");
     }
   };
-})(typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this);
+})();
+
+babelHelpers.taggedTemplateLiteral = function (strings, raw) {
+  return Object.freeze(Object.defineProperties(strings, {
+    raw: {
+      value: Object.freeze(raw)
+    }
+  }));
+};
+
+babelHelpers.toArray = function (arr) {
+  return Array.isArray(arr) ? arr : Array.from(arr);
+};
+
+babelHelpers.toConsumableArray = function (arr) {
+  if (Array.isArray(arr)) {
+    for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
+
+    return arr2;
+  } else {
+    return Array.from(arr);
+  }
+};
diff --git a/packager/react-packager/src/Resolver/polyfills/console.js b/packager/react-packager/src/Resolver/polyfills/console.js
index a8e5a72f41cf..5406db73e67e 100644
--- a/packager/react-packager/src/Resolver/polyfills/console.js
+++ b/packager/react-packager/src/Resolver/polyfills/console.js
@@ -14,495 +14,492 @@
  * @nolint
  */
 
-(function(global) {
-  'use strict';
-
-  var inspect = (function() {
-    // Copyright Joyent, Inc. and other Node contributors.
-    //
-    // 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.
-    //
-    // https://github.com/joyent/node/blob/master/lib/util.js
-
-    function inspect(obj, opts) {
-      var ctx = {
-        seen: [],
-        stylize: stylizeNoColor
-      };
-      return formatValue(ctx, obj, opts.depth);
-    }
-
-    function stylizeNoColor(str, styleType) {
-      return str;
-    }
-
-    function arrayToHash(array) {
-      var hash = {};
-
-      array.forEach(function(val, idx) {
-        hash[val] = true;
-      });
+/* eslint-disable */
+
+var inspect = (function() {
+  // Copyright Joyent, Inc. and other Node contributors.
+  //
+  // 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.
+  //
+  // https://github.com/joyent/node/blob/master/lib/util.js
+
+  function inspect(obj, opts) {
+    var ctx = {
+      seen: [],
+      stylize: stylizeNoColor
+    };
+    return formatValue(ctx, obj, opts.depth);
+  }
 
-      return hash;
-    }
+  function stylizeNoColor(str, styleType) {
+    return str;
+  }
 
+  function arrayToHash(array) {
+    var hash = {};
 
-    function formatValue(ctx, value, recurseTimes) {
-      // Primitive types cannot have properties
-      var primitive = formatPrimitive(ctx, value);
-      if (primitive) {
-        return primitive;
-      }
+    array.forEach(function(val, idx) {
+      hash[val] = true;
+    });
 
-      // Look up the keys of the object.
-      var keys = Object.keys(value);
-      var visibleKeys = arrayToHash(keys);
+    return hash;
+  }
 
-      // IE doesn't make error fields non-enumerable
-      // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
-      if (isError(value)
-          && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
-        return formatError(value);
-      }
 
-      // Some type of object without properties can be shortcutted.
-      if (keys.length === 0) {
-        if (isFunction(value)) {
-          var name = value.name ? ': ' + value.name : '';
-          return ctx.stylize('[Function' + name + ']', 'special');
-        }
-        if (isRegExp(value)) {
-          return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
-        }
-        if (isDate(value)) {
-          return ctx.stylize(Date.prototype.toString.call(value), 'date');
-        }
-        if (isError(value)) {
-          return formatError(value);
-        }
-      }
+  function formatValue(ctx, value, recurseTimes) {
+    // Primitive types cannot have properties
+    var primitive = formatPrimitive(ctx, value);
+    if (primitive) {
+      return primitive;
+    }
 
-      var base = '', array = false, braces = ['{', '}'];
+    // Look up the keys of the object.
+    var keys = Object.keys(value);
+    var visibleKeys = arrayToHash(keys);
 
-      // Make Array say that they are Array
-      if (isArray(value)) {
-        array = true;
-        braces = ['[', ']'];
-      }
+    // IE doesn't make error fields non-enumerable
+    // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
+    if (isError(value)
+        && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
+      return formatError(value);
+    }
 
-      // Make functions say that they are functions
+    // Some type of object without properties can be shortcutted.
+    if (keys.length === 0) {
       if (isFunction(value)) {
-        var n = value.name ? ': ' + value.name : '';
-        base = ' [Function' + n + ']';
+        var name = value.name ? ': ' + value.name : '';
+        return ctx.stylize('[Function' + name + ']', 'special');
       }
-
-      // Make RegExps say that they are RegExps
       if (isRegExp(value)) {
-        base = ' ' + RegExp.prototype.toString.call(value);
+        return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
       }
-
-      // Make dates with properties first say the date
       if (isDate(value)) {
-        base = ' ' + Date.prototype.toUTCString.call(value);
+        return ctx.stylize(Date.prototype.toString.call(value), 'date');
       }
-
-      // Make error with message first say the error
       if (isError(value)) {
-        base = ' ' + formatError(value);
+        return formatError(value);
       }
+    }
 
-      if (keys.length === 0 && (!array || value.length == 0)) {
-        return braces[0] + base + braces[1];
-      }
+    var base = '', array = false, braces = ['{', '}'];
 
-      if (recurseTimes < 0) {
-        if (isRegExp(value)) {
-          return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
-        } else {
-          return ctx.stylize('[Object]', 'special');
-        }
-      }
+    // Make Array say that they are Array
+    if (isArray(value)) {
+      array = true;
+      braces = ['[', ']'];
+    }
 
-      ctx.seen.push(value);
+    // Make functions say that they are functions
+    if (isFunction(value)) {
+      var n = value.name ? ': ' + value.name : '';
+      base = ' [Function' + n + ']';
+    }
 
-      var output;
-      if (array) {
-        output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
-      } else {
-        output = keys.map(function(key) {
-          return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
-        });
-      }
+    // Make RegExps say that they are RegExps
+    if (isRegExp(value)) {
+      base = ' ' + RegExp.prototype.toString.call(value);
+    }
 
-      ctx.seen.pop();
+    // Make dates with properties first say the date
+    if (isDate(value)) {
+      base = ' ' + Date.prototype.toUTCString.call(value);
+    }
 
-      return reduceToSingleString(output, base, braces);
+    // Make error with message first say the error
+    if (isError(value)) {
+      base = ' ' + formatError(value);
     }
 
+    if (keys.length === 0 && (!array || value.length == 0)) {
+      return braces[0] + base + braces[1];
+    }
 
-    function formatPrimitive(ctx, value) {
-      if (isUndefined(value))
-        return ctx.stylize('undefined', 'undefined');
-      if (isString(value)) {
-        var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
-                                                 .replace(/'/g, "\\'")
-                                                 .replace(/\\"/g, '"') + '\'';
-        return ctx.stylize(simple, 'string');
+    if (recurseTimes < 0) {
+      if (isRegExp(value)) {
+        return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
+      } else {
+        return ctx.stylize('[Object]', 'special');
       }
-      if (isNumber(value))
-        return ctx.stylize('' + value, 'number');
-      if (isBoolean(value))
-        return ctx.stylize('' + value, 'boolean');
-      // For some reason typeof null is "object", so special case here.
-      if (isNull(value))
-        return ctx.stylize('null', 'null');
     }
 
+    ctx.seen.push(value);
 
-    function formatError(value) {
-      return '[' + Error.prototype.toString.call(value) + ']';
+    var output;
+    if (array) {
+      output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
+    } else {
+      output = keys.map(function(key) {
+        return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
+      });
     }
 
+    ctx.seen.pop();
 
-    function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
-      var output = [];
-      for (var i = 0, l = value.length; i < l; ++i) {
-        if (hasOwnProperty(value, String(i))) {
-          output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
-              String(i), true));
-        } else {
-          output.push('');
-        }
+    return reduceToSingleString(output, base, braces);
+  }
+
+
+  function formatPrimitive(ctx, value) {
+    if (isUndefined(value))
+      return ctx.stylize('undefined', 'undefined');
+    if (isString(value)) {
+      var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
+                                               .replace(/'/g, "\\'")
+                                               .replace(/\\"/g, '"') + '\'';
+      return ctx.stylize(simple, 'string');
+    }
+    if (isNumber(value))
+      return ctx.stylize('' + value, 'number');
+    if (isBoolean(value))
+      return ctx.stylize('' + value, 'boolean');
+    // For some reason typeof null is "object", so special case here.
+    if (isNull(value))
+      return ctx.stylize('null', 'null');
+  }
+
+
+  function formatError(value) {
+    return '[' + Error.prototype.toString.call(value) + ']';
+  }
+
+
+  function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
+    var output = [];
+    for (var i = 0, l = value.length; i < l; ++i) {
+      if (hasOwnProperty(value, String(i))) {
+        output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
+            String(i), true));
+      } else {
+        output.push('');
       }
-      keys.forEach(function(key) {
-        if (!key.match(/^\d+$/)) {
-          output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
-              key, true));
-        }
-      });
-      return output;
     }
+    keys.forEach(function(key) {
+      if (!key.match(/^\d+$/)) {
+        output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
+            key, true));
+      }
+    });
+    return output;
+  }
 
 
-    function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
-      var name, str, desc;
-      desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
-      if (desc.get) {
-        if (desc.set) {
-          str = ctx.stylize('[Getter/Setter]', 'special');
-        } else {
-          str = ctx.stylize('[Getter]', 'special');
-        }
+  function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
+    var name, str, desc;
+    desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
+    if (desc.get) {
+      if (desc.set) {
+        str = ctx.stylize('[Getter/Setter]', 'special');
       } else {
-        if (desc.set) {
-          str = ctx.stylize('[Setter]', 'special');
-        }
+        str = ctx.stylize('[Getter]', 'special');
       }
-      if (!hasOwnProperty(visibleKeys, key)) {
-        name = '[' + key + ']';
+    } else {
+      if (desc.set) {
+        str = ctx.stylize('[Setter]', 'special');
       }
-      if (!str) {
-        if (ctx.seen.indexOf(desc.value) < 0) {
-          if (isNull(recurseTimes)) {
-            str = formatValue(ctx, desc.value, null);
+    }
+    if (!hasOwnProperty(visibleKeys, key)) {
+      name = '[' + key + ']';
+    }
+    if (!str) {
+      if (ctx.seen.indexOf(desc.value) < 0) {
+        if (isNull(recurseTimes)) {
+          str = formatValue(ctx, desc.value, null);
+        } else {
+          str = formatValue(ctx, desc.value, recurseTimes - 1);
+        }
+        if (str.indexOf('\n') > -1) {
+          if (array) {
+            str = str.split('\n').map(function(line) {
+              return '  ' + line;
+            }).join('\n').substr(2);
           } else {
-            str = formatValue(ctx, desc.value, recurseTimes - 1);
-          }
-          if (str.indexOf('\n') > -1) {
-            if (array) {
-              str = str.split('\n').map(function(line) {
-                return '  ' + line;
-              }).join('\n').substr(2);
-            } else {
-              str = '\n' + str.split('\n').map(function(line) {
-                return '   ' + line;
-              }).join('\n');
-            }
+            str = '\n' + str.split('\n').map(function(line) {
+              return '   ' + line;
+            }).join('\n');
           }
-        } else {
-          str = ctx.stylize('[Circular]', 'special');
         }
+      } else {
+        str = ctx.stylize('[Circular]', 'special');
       }
-      if (isUndefined(name)) {
-        if (array && key.match(/^\d+$/)) {
-          return str;
-        }
-        name = JSON.stringify('' + key);
-        if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
-          name = name.substr(1, name.length - 2);
-          name = ctx.stylize(name, 'name');
-        } else {
-          name = name.replace(/'/g, "\\'")
-                     .replace(/\\"/g, '"')
-                     .replace(/(^"|"$)/g, "'");
-          name = ctx.stylize(name, 'string');
-        }
+    }
+    if (isUndefined(name)) {
+      if (array && key.match(/^\d+$/)) {
+        return str;
+      }
+      name = JSON.stringify('' + key);
+      if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
+        name = name.substr(1, name.length - 2);
+        name = ctx.stylize(name, 'name');
+      } else {
+        name = name.replace(/'/g, "\\'")
+                   .replace(/\\"/g, '"')
+                   .replace(/(^"|"$)/g, "'");
+        name = ctx.stylize(name, 'string');
       }
-
-      return name + ': ' + str;
     }
 
+    return name + ': ' + str;
+  }
 
-    function reduceToSingleString(output, base, braces) {
-      var numLinesEst = 0;
-      var length = output.reduce(function(prev, cur) {
-        numLinesEst++;
-        if (cur.indexOf('\n') >= 0) numLinesEst++;
-        return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
-      }, 0);
-
-      if (length > 60) {
-        return braces[0] +
-               (base === '' ? '' : base + '\n ') +
-               ' ' +
-               output.join(',\n  ') +
-               ' ' +
-               braces[1];
-      }
 
-      return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
+  function reduceToSingleString(output, base, braces) {
+    var numLinesEst = 0;
+    var length = output.reduce(function(prev, cur) {
+      numLinesEst++;
+      if (cur.indexOf('\n') >= 0) numLinesEst++;
+      return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
+    }, 0);
+
+    if (length > 60) {
+      return braces[0] +
+             (base === '' ? '' : base + '\n ') +
+             ' ' +
+             output.join(',\n  ') +
+             ' ' +
+             braces[1];
     }
 
+    return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
+  }
 
-    // NOTE: These type checking functions intentionally don't use `instanceof`
-    // because it is fragile and can be easily faked with `Object.create()`.
-    function isArray(ar) {
-      return Array.isArray(ar);
-    }
 
-    function isBoolean(arg) {
-      return typeof arg === 'boolean';
-    }
+  // NOTE: These type checking functions intentionally don't use `instanceof`
+  // because it is fragile and can be easily faked with `Object.create()`.
+  function isArray(ar) {
+    return Array.isArray(ar);
+  }
 
-    function isNull(arg) {
-      return arg === null;
-    }
+  function isBoolean(arg) {
+    return typeof arg === 'boolean';
+  }
 
-    function isNullOrUndefined(arg) {
-      return arg == null;
-    }
+  function isNull(arg) {
+    return arg === null;
+  }
 
-    function isNumber(arg) {
-      return typeof arg === 'number';
-    }
+  function isNullOrUndefined(arg) {
+    return arg == null;
+  }
 
-    function isString(arg) {
-      return typeof arg === 'string';
-    }
+  function isNumber(arg) {
+    return typeof arg === 'number';
+  }
 
-    function isSymbol(arg) {
-      return typeof arg === 'symbol';
-    }
+  function isString(arg) {
+    return typeof arg === 'string';
+  }
 
-    function isUndefined(arg) {
-      return arg === void 0;
-    }
+  function isSymbol(arg) {
+    return typeof arg === 'symbol';
+  }
 
-    function isRegExp(re) {
-      return isObject(re) && objectToString(re) === '[object RegExp]';
-    }
+  function isUndefined(arg) {
+    return arg === void 0;
+  }
 
-    function isObject(arg) {
-      return typeof arg === 'object' && arg !== null;
-    }
+  function isRegExp(re) {
+    return isObject(re) && objectToString(re) === '[object RegExp]';
+  }
 
-    function isDate(d) {
-      return isObject(d) && objectToString(d) === '[object Date]';
-    }
+  function isObject(arg) {
+    return typeof arg === 'object' && arg !== null;
+  }
 
-    function isError(e) {
-      return isObject(e) &&
-          (objectToString(e) === '[object Error]' || e instanceof Error);
-    }
+  function isDate(d) {
+    return isObject(d) && objectToString(d) === '[object Date]';
+  }
 
-    function isFunction(arg) {
-      return typeof arg === 'function';
-    }
+  function isError(e) {
+    return isObject(e) &&
+        (objectToString(e) === '[object Error]' || e instanceof Error);
+  }
 
-    function isPrimitive(arg) {
-      return arg === null ||
-             typeof arg === 'boolean' ||
-             typeof arg === 'number' ||
-             typeof arg === 'string' ||
-             typeof arg === 'symbol' ||  // ES6 symbol
-             typeof arg === 'undefined';
-    }
+  function isFunction(arg) {
+    return typeof arg === 'function';
+  }
 
-    function objectToString(o) {
-      return Object.prototype.toString.call(o);
-    }
+  function isPrimitive(arg) {
+    return arg === null ||
+           typeof arg === 'boolean' ||
+           typeof arg === 'number' ||
+           typeof arg === 'string' ||
+           typeof arg === 'symbol' ||  // ES6 symbol
+           typeof arg === 'undefined';
+  }
 
-    function hasOwnProperty(obj, prop) {
-      return Object.prototype.hasOwnProperty.call(obj, prop);
-    }
+  function objectToString(o) {
+    return Object.prototype.toString.call(o);
+  }
 
-    return inspect;
-  })();
+  function hasOwnProperty(obj, prop) {
+    return Object.prototype.hasOwnProperty.call(obj, prop);
+  }
 
+  return inspect;
+})();
 
-  var OBJECT_COLUMN_NAME = '(index)';
-  var LOG_LEVELS = {
-    trace: 0,
-    info: 1,
-    warn: 2,
-    error: 3
-  };
 
-  function setupConsole(global) {
-    if (!global.nativeLoggingHook) {
-      return;
-    }
+var OBJECT_COLUMN_NAME = '(index)';
+var LOG_LEVELS = {
+  trace: 0,
+  info: 1,
+  warn: 2,
+  error: 3
+};
 
-    function getNativeLogFunction(level) {
-      return function() {
-        var str;
-        if (arguments.length === 1 && typeof arguments[0] === 'string') {
-          str = arguments[0];
-        } else {
-          str = Array.prototype.map.call(arguments, function(arg) {
-            return inspect(arg, {depth: 10});
-          }).join(', ');
-        }
+function setupConsole(global) {
+  if (!global.nativeLoggingHook) {
+    return;
+  }
 
-        var logLevel = level;
-        if (str.slice(0, 9) === 'Warning: ' && logLevel >= LOG_LEVELS.error) {
-          // React warnings use console.error so that a stack trace is shown,
-          // but we don't (currently) want these to show a redbox
-          // (Note: Logic duplicated in ExceptionsManager.js.)
-          logLevel = LOG_LEVELS.warn;
-        }
-        global.nativeLoggingHook(str, logLevel);
-      };
-    }
+  function getNativeLogFunction(level) {
+    return function() {
+      var str;
+      if (arguments.length === 1 && typeof arguments[0] === 'string') {
+        str = arguments[0];
+      } else {
+        str = Array.prototype.map.call(arguments, function(arg) {
+          return inspect(arg, {depth: 10});
+        }).join(', ');
+      }
 
-    var repeat = function(element, n) {
-      return Array.apply(null, Array(n)).map(function() { return element; });
+      var logLevel = level;
+      if (str.slice(0, 9) === 'Warning: ' && logLevel >= LOG_LEVELS.error) {
+        // React warnings use console.error so that a stack trace is shown,
+        // but we don't (currently) want these to show a redbox
+        // (Note: Logic duplicated in ExceptionsManager.js.)
+        logLevel = LOG_LEVELS.warn;
+      }
+      global.nativeLoggingHook(str, logLevel);
     };
+  }
 
-    function consoleTablePolyfill(rows) {
-      // convert object -> array
-      if (!Array.isArray(rows)) {
-        var data = rows;
-        rows = [];
-        for (var key in data) {
-          if (data.hasOwnProperty(key)) {
-            var row = data[key];
-            row[OBJECT_COLUMN_NAME] = key;
-            rows.push(row);
-          }
-        }
-      }
-      if (rows.length === 0) {
-        global.nativeLoggingHook('', LOG_LEVELS.info);
-        return;
-      }
+  var repeat = function(element, n) {
+    return Array.apply(null, Array(n)).map(function() { return element; });
+  };
 
-      var columns = Object.keys(rows[0]).sort();
-      var stringRows = [];
-      var columnWidths = [];
-
-      // Convert each cell to a string. Also
-      // figure out max cell width for each column
-      columns.forEach(function(k, i) {
-        columnWidths[i] = k.length;
-        for (var j = 0; j < rows.length; j++) {
-          var cellStr = rows[j][k].toString();
-          stringRows[j] = stringRows[j] || [];
-          stringRows[j][i] = cellStr;
-          columnWidths[i] = Math.max(columnWidths[i], cellStr.length);
+  function consoleTablePolyfill(rows) {
+    // convert object -> array
+    if (!Array.isArray(rows)) {
+      var data = rows;
+      rows = [];
+      for (var key in data) {
+        if (data.hasOwnProperty(key)) {
+          var row = data[key];
+          row[OBJECT_COLUMN_NAME] = key;
+          rows.push(row);
         }
-      });
-
-      // Join all elements in the row into a single string with | separators
-      // (appends extra spaces to each cell to make separators  | alligned)
-      var joinRow = function(row, space) {
-        var cells = row.map(function(cell, i) {
-          var extraSpaces = repeat(' ', columnWidths[i] - cell.length).join('');
-          return cell + extraSpaces;
-        });
-        space = space || ' ';
-        return cells.join(space + '|' + space);
-      };
-
-      var separators = columnWidths.map(function(columnWidth) {
-        return repeat('-', columnWidth).join('');
-      });
-      var separatorRow = joinRow(separators, '-');
-      var header = joinRow(columns);
-      var table = [header, separatorRow];
-
-      for (var i = 0; i < rows.length; i++) {
-        table.push(joinRow(stringRows[i]));
       }
-
-      // Notice extra empty line at the beginning.
-      // Native logging hook adds "RCTLog >" at the front of every
-      // logged string, which would shift the header and screw up
-      // the table
-      global.nativeLoggingHook('\n' + table.join('\n'), LOG_LEVELS.info);
     }
-
-    // Preserve the original `console` as `originalConsole`
-    var originalConsole = global.console;
-    var descriptor = Object.getOwnPropertyDescriptor(global, 'console');
-    if (descriptor) {
-      Object.defineProperty(global, 'originalConsole', descriptor);
+    if (rows.length === 0) {
+      global.nativeLoggingHook('', LOG_LEVELS.info);
+      return;
     }
 
-    var console = {
-      error: getNativeLogFunction(LOG_LEVELS.error),
-      info: getNativeLogFunction(LOG_LEVELS.info),
-      log: getNativeLogFunction(LOG_LEVELS.info),
-      warn: getNativeLogFunction(LOG_LEVELS.warn),
-      trace: getNativeLogFunction(LOG_LEVELS.trace),
-      table: consoleTablePolyfill
+    var columns = Object.keys(rows[0]).sort();
+    var stringRows = [];
+    var columnWidths = [];
+
+    // Convert each cell to a string. Also
+    // figure out max cell width for each column
+    columns.forEach(function(k, i) {
+      columnWidths[i] = k.length;
+      for (var j = 0; j < rows.length; j++) {
+        var cellStr = rows[j][k].toString();
+        stringRows[j] = stringRows[j] || [];
+        stringRows[j][i] = cellStr;
+        columnWidths[i] = Math.max(columnWidths[i], cellStr.length);
+      }
+    });
+
+    // Join all elements in the row into a single string with | separators
+    // (appends extra spaces to each cell to make separators  | alligned)
+    var joinRow = function(row, space) {
+      var cells = row.map(function(cell, i) {
+        var extraSpaces = repeat(' ', columnWidths[i] - cell.length).join('');
+        return cell + extraSpaces;
+      });
+      space = space || ' ';
+      return cells.join(space + '|' + space);
     };
 
-    // don't reassign to the original descriptor. breaks on ios7
-    Object.defineProperty(global, 'console', {
-      value: console,
-      configurable: descriptor ? descriptor.configurable : true,
-      enumerable: descriptor ? descriptor.enumerable : true,
-      writable: descriptor ? descriptor.writable : true,
+    var separators = columnWidths.map(function(columnWidth) {
+      return repeat('-', columnWidth).join('');
     });
+    var separatorRow = joinRow(separators, '-');
+    var header = joinRow(columns);
+    var table = [header, separatorRow];
 
-    // If available, also call the original `console` method since that is
-    // sometimes useful. Ex: on OS X, this will let you see rich output in
-    // the Safari Web Inspector console.
-    if (__DEV__ && originalConsole) {
-      Object.keys(console).forEach(methodName => {
-        var reactNativeMethod = console[methodName];
-        if (originalConsole[methodName]) {
-          console[methodName] = function() {
-            originalConsole[methodName](...arguments);
-            reactNativeMethod.apply(console, arguments);
-          };
-        }
-      });
+    for (var i = 0; i < rows.length; i++) {
+      table.push(joinRow(stringRows[i]));
     }
+
+    // Notice extra empty line at the beginning.
+    // Native logging hook adds "RCTLog >" at the front of every
+    // logged string, which would shift the header and screw up
+    // the table
+    global.nativeLoggingHook('\n' + table.join('\n'), LOG_LEVELS.info);
+  }
+
+  // Preserve the original `console` as `originalConsole`
+  var originalConsole = global.console;
+  var descriptor = Object.getOwnPropertyDescriptor(global, 'console');
+  if (descriptor) {
+    Object.defineProperty(global, 'originalConsole', descriptor);
   }
 
-  if (typeof module !== 'undefined') {
-    module.exports = setupConsole;
-  } else {
-    setupConsole(global);
+  var console = {
+    error: getNativeLogFunction(LOG_LEVELS.error),
+    info: getNativeLogFunction(LOG_LEVELS.info),
+    log: getNativeLogFunction(LOG_LEVELS.info),
+    warn: getNativeLogFunction(LOG_LEVELS.warn),
+    trace: getNativeLogFunction(LOG_LEVELS.trace),
+    table: consoleTablePolyfill
+  };
+
+  // don't reassign to the original descriptor. breaks on ios7
+  Object.defineProperty(global, 'console', {
+    value: console,
+    configurable: descriptor ? descriptor.configurable : true,
+    enumerable: descriptor ? descriptor.enumerable : true,
+    writable: descriptor ? descriptor.writable : true,
+  });
+
+  // If available, also call the original `console` method since that is
+  // sometimes useful. Ex: on OS X, this will let you see rich output in
+  // the Safari Web Inspector console.
+  if (__DEV__ && originalConsole) {
+    Object.keys(console).forEach(methodName => {
+      var reactNativeMethod = console[methodName];
+      if (originalConsole[methodName]) {
+        console[methodName] = function() {
+          originalConsole[methodName](...arguments);
+          reactNativeMethod.apply(console, arguments);
+        };
+      }
+    });
   }
+}
 
-})(this);
+if (typeof module !== 'undefined') {
+  module.exports = setupConsole;
+} else {
+  setupConsole(global);
+}
diff --git a/packager/react-packager/src/Resolver/polyfills/error-guard.js b/packager/react-packager/src/Resolver/polyfills/error-guard.js
index ac99cadca578..8810a4b12a77 100644
--- a/packager/react-packager/src/Resolver/polyfills/error-guard.js
+++ b/packager/react-packager/src/Resolver/polyfills/error-guard.js
@@ -13,74 +13,72 @@
  * before any of the modules, this ErrorUtils must be defined (and the handler
  * set) globally before requiring anything.
  */
-/* eslint global-strict:0 */
-(function(global) {
-  var ErrorUtils = {
-    _inGuard: 0,
-    _globalHandler: null,
-    setGlobalHandler: function(fun) {
-      ErrorUtils._globalHandler = fun;
-    },
-    reportError: function(error) {
-      ErrorUtils._globalHandler && ErrorUtils._globalHandler(error);
-    },
-    reportFatalError: function(error) {
-      ErrorUtils._globalHandler && ErrorUtils._globalHandler(error, true);
-    },
-    applyWithGuard: function(fun, context, args) {
-      try {
-        ErrorUtils._inGuard++;
-        return fun.apply(context, args);
-      } catch (e) {
-        ErrorUtils.reportError(e);
-      } finally {
-        ErrorUtils._inGuard--;
-      }
-    },
-    applyWithGuardIfNeeded: function(fun, context, args) {
-      if (ErrorUtils.inGuard()) {
-        return fun.apply(context, args);
-      } else {
-        ErrorUtils.applyWithGuard(fun, context, args);
-      }
-    },
-    inGuard: function() {
-      return ErrorUtils._inGuard;
-    },
-    guard: function(fun, name, context) {
-      if (typeof fun !== 'function') {
-        console.warn('A function must be passed to ErrorUtils.guard, got ', fun);
-        return null;
-      }
-      name = name || fun.name || '<generated guard>';
-      function guarded() {
-        return (
-          ErrorUtils.applyWithGuard(
-            fun,
-            context || this,
-            arguments,
-            null,
-            name
-          )
-        );
-      }
-
-      return guarded;
+/* eslint strict:0 */
+var ErrorUtils = {
+  _inGuard: 0,
+  _globalHandler: null,
+  setGlobalHandler: function(fun) {
+    ErrorUtils._globalHandler = fun;
+  },
+  reportError: function(error) {
+    ErrorUtils._globalHandler && ErrorUtils._globalHandler(error);
+  },
+  reportFatalError: function(error) {
+    ErrorUtils._globalHandler && ErrorUtils._globalHandler(error, true);
+  },
+  applyWithGuard: function(fun, context, args) {
+    try {
+      ErrorUtils._inGuard++;
+      return fun.apply(context, args);
+    } catch (e) {
+      ErrorUtils.reportError(e);
+    } finally {
+      ErrorUtils._inGuard--;
+    }
+  },
+  applyWithGuardIfNeeded: function(fun, context, args) {
+    if (ErrorUtils.inGuard()) {
+      return fun.apply(context, args);
+    } else {
+      ErrorUtils.applyWithGuard(fun, context, args);
+    }
+  },
+  inGuard: function() {
+    return ErrorUtils._inGuard;
+  },
+  guard: function(fun, name, context) {
+    if (typeof fun !== 'function') {
+      console.warn('A function must be passed to ErrorUtils.guard, got ', fun);
+      return null;
+    }
+    name = name || fun.name || '<generated guard>';
+    function guarded() {
+      return (
+        ErrorUtils.applyWithGuard(
+          fun,
+          context || this,
+          arguments,
+          null,
+          name
+        )
+      );
     }
-  };
-  global.ErrorUtils = ErrorUtils;
 
-  /**
-   * This is the error handler that is called when we encounter an exception
-   * when loading a module. This will report any errors encountered before
-   * ExceptionsManager is configured.
-   */
-  function setupErrorGuard() {
-    var onError = function(e) {
-      global.console.error('Error: ' + e.message + ', stack:\n' + e.stack);
-    };
-    global.ErrorUtils.setGlobalHandler(onError);
+    return guarded;
   }
+};
+global.ErrorUtils = ErrorUtils;
+
+/**
+ * This is the error handler that is called when we encounter an exception
+ * when loading a module. This will report any errors encountered before
+ * ExceptionsManager is configured.
+ */
+function setupErrorGuard() {
+  var onError = function(e) {
+    global.console.error('Error: ' + e.message + ', stack:\n' + e.stack);
+  };
+  global.ErrorUtils.setGlobalHandler(onError);
+}
 
-  setupErrorGuard();
-})(this);
+setupErrorGuard();
diff --git a/packager/react-packager/src/Resolver/polyfills/loadBundles.js b/packager/react-packager/src/Resolver/polyfills/loadBundles.js
index 4e893eda9cb2..7bb9be104a32 100644
--- a/packager/react-packager/src/Resolver/polyfills/loadBundles.js
+++ b/packager/react-packager/src/Resolver/polyfills/loadBundles.js
@@ -1,50 +1,34 @@
-/* eslint global-strict:0 */
-(global => {
-  let loadBundlesOnNative = (bundles) =>
-    new Promise((resolve) =>
-      require('NativeModules').RCTBundlesLoader.loadBundles(bundles, resolve));
+/* eslint strict:0 */
 
-  let requestedBundles = Object.create(null);
+let loadBundlesOnNative = (bundles) =>
+  new Promise((resolve) =>
+    require('NativeModules').RCTBundlesLoader.loadBundles(bundles, resolve));
 
-  /**
-   * Returns a promise that is fulfilled once all the indicated bundles are
-   * loaded into memory and injected into the JS engine.
-   * This invokation might need to go through the bridge
-   * and run native code to load some, if not all, the requested bundles.
-   * If all the bundles have already been loaded, the promise is resolved
-   * immediately. Otherwise, we'll determine which bundles still need to get
-   * loaded considering both, the ones already loaded, and the ones being
-   * currently asynchronously loaded by other invocations to `__loadBundles`,
-   * and return a promise that will get fulfilled once all these are finally
-   * loaded.
-   *
-   * Note this function should only be invoked by generated code.
-   */
-  global.__loadBundles = function(bundles) {
-    // split bundles by whether they've already been requested or not
-    const bundlesToRequest = bundles.filter(b => !requestedBundles[b]);
-    const bundlesAlreadyRequested = bundles.filter(b => !!requestedBundles[b]);
+let requestedBundles = Object.create(null);
 
-    // keep a reference to the promise loading each bundle
-    if (bundlesToRequest.length > 0) {
-      const nativePromise = loadBundlesOnNative(bundlesToRequest);
-      bundlesToRequest.forEach(b => requestedBundles[b] = nativePromise);
-    }
+/**
+ * Returns a promise that is fulfilled once all the indicated bundles are
+ * loaded into memory and injected into the JS engine.
+ * This invokation might need to go through the bridge
+ * and run native code to load some, if not all, the requested bundles.
+ * If all the bundles have already been loaded, the promise is resolved
+ * immediately. Otherwise, we'll determine which bundles still need to get
+ * loaded considering both, the ones already loaded, and the ones being
+ * currently asynchronously loaded by other invocations to `__loadBundles`,
+ * and return a promise that will get fulfilled once all these are finally
+ * loaded.
+ *
+ * Note this function should only be invoked by generated code.
+ */
+global.__loadBundles = function(bundles) {
+  // split bundles by whether they've already been requested or not
+  const bundlesToRequest = bundles.filter(b => !requestedBundles[b]);
 
-    return Promise.all(bundles.map(bundle => requestedBundles[bundle]));
-  };
-})(global);
+  // keep a reference to the promise loading each bundle
+  if (bundlesToRequest.length > 0) {
+    const nativePromise = loadBundlesOnNative(bundlesToRequest);
+    bundlesToRequest.forEach(b => requestedBundles[b] = nativePromise);
+  }
 
-
-// turns a callback async based function into a promised based one
-function promisify(fn) {
-  return function() {
-    var self = this;
-    var args = Array.prototype.slice.call(arguments);
-
-    return new Promise((resolve, reject) => {
-      args.push(resolve);
-      fn.apply(self, args);
-    });
-  };
-}
+  return Promise.all(bundles.map(bundle => requestedBundles[bundle]));
+};
diff --git a/packager/react-packager/src/Resolver/polyfills/polyfills.js b/packager/react-packager/src/Resolver/polyfills/polyfills.js
index 9698b4911dbd..5652334218a7 100644
--- a/packager/react-packager/src/Resolver/polyfills/polyfills.js
+++ b/packager/react-packager/src/Resolver/polyfills/polyfills.js
@@ -15,7 +15,7 @@
 
 // WARNING: This is an optimized version that fails on hasOwnProperty checks
 // and non objects. It's not spec-compliant. It's a perf optimization.
-/* eslint global-strict:0 */
+/* eslint strict:0 */
 Object.assign = function(target, sources) {
   if (__DEV__) {
     if (target == null) {
diff --git a/packager/react-packager/src/Resolver/polyfills/prelude.js b/packager/react-packager/src/Resolver/polyfills/prelude.js
index a1004b7d4cfd..02386ae1016a 100644
--- a/packager/react-packager/src/Resolver/polyfills/prelude.js
+++ b/packager/react-packager/src/Resolver/polyfills/prelude.js
@@ -1,5 +1,4 @@
-/* eslint global-strict:0 */
-__DEV__ = false;
+/* eslint strict:0 */
+global.__DEV__ = false;
 
-/* global __BUNDLE_START_TIME__:true */
-__BUNDLE_START_TIME__ = Date.now();
+global.__BUNDLE_START_TIME__ = Date.now();
diff --git a/packager/react-packager/src/Resolver/polyfills/prelude_dev.js b/packager/react-packager/src/Resolver/polyfills/prelude_dev.js
index 14b97faad6d5..99b9de2c1137 100644
--- a/packager/react-packager/src/Resolver/polyfills/prelude_dev.js
+++ b/packager/react-packager/src/Resolver/polyfills/prelude_dev.js
@@ -1,5 +1,4 @@
-/* eslint global-strict:0 */
-__DEV__ = true;
+/* eslint strict:0 */
+global.__DEV__ = true;
 
-/* global __BUNDLE_START_TIME__:true */
-__BUNDLE_START_TIME__ = Date.now();
+global.__BUNDLE_START_TIME__ = Date.now();
diff --git a/packager/react-packager/src/Resolver/polyfills/require-unbundle.js b/packager/react-packager/src/Resolver/polyfills/require-unbundle.js
index 1ea71705d401..c6c7cbc79c82 100644
--- a/packager/react-packager/src/Resolver/polyfills/require-unbundle.js
+++ b/packager/react-packager/src/Resolver/polyfills/require-unbundle.js
@@ -1,73 +1,70 @@
 'use strict';
 
-((global) => {
-  const {ErrorUtils, __nativeRequire} = global;
-  global.require = require;
-  global.__d = define;
+const {ErrorUtils, __nativeRequire} = global;
+global.require = require;
+global.__d = define;
 
-  const modules = Object.create(null);
+const modules = Object.create(null);
 
-  const loadModule = ErrorUtils ?
-    guardedLoadModule : loadModuleImplementation;
+const loadModule = ErrorUtils ?
+  guardedLoadModule : loadModuleImplementation;
 
-  function define(moduleId, factory) {
-    modules[moduleId] = {
-      factory,
-      hasError: false,
-      exports: undefined,
-    };
-  }
+function define(moduleId, factory) {
+  modules[moduleId] = {
+    factory,
+    hasError: false,
+    exports: undefined,
+  };
+}
 
-  function require(moduleId) {
-    const module = modules[moduleId];
-    return module && module.exports || loadModule(moduleId, module);
-  }
+function require(moduleId) {
+  const module = modules[moduleId];
+  return module && module.exports || loadModule(moduleId, module);
+}
 
-  function guardedLoadModule(moduleId, module) {
-    try {
-      return loadModuleImplementation(moduleId, module);
-    } catch (e) {
-      ErrorUtils.reportFatalError(e);
-    }
+function guardedLoadModule(moduleId, module) {
+  try {
+    return loadModuleImplementation(moduleId, module);
+  } catch (e) {
+    ErrorUtils.reportFatalError(e);
   }
+}
 
-  function loadModuleImplementation(moduleId, module) {
-    if (!module) {
-      __nativeRequire(moduleId);
-      module = modules[moduleId];
-    }
-
-    if (!module) {
-      throw unknownModuleError(moduleId);
-    }
+function loadModuleImplementation(moduleId, module) {
+  if (!module) {
+    __nativeRequire(moduleId);
+    module = modules[moduleId];
+  }
 
-    if (module.hasError) {
-      throw moduleThrewError(moduleId);
-    }
+  if (!module) {
+    throw unknownModuleError(moduleId);
+  }
 
-    const exports = module.exports = {};
-    const {factory} = module;
-    try {
-      const moduleObject = {exports};
-      factory(global, require, moduleObject, exports);
-      return (module.exports = moduleObject.exports);
-    } catch(e) {
-      module.hasError = true;
-      module.exports = undefined;
-    }
+  if (module.hasError) {
+    throw moduleThrewError(moduleId);
   }
 
-  function unknownModuleError(id) {
-    let message = 'Requiring unknown module "' + id + '".';
-    if (__DEV__) {
-      message +=
-        'If you are sure the module is there, try restarting the packager.';
-    }
-    return Error(message);
+  const exports = module.exports = {};
+  const {factory} = module;
+  try {
+    const moduleObject = {exports};
+    factory(global, require, moduleObject, exports);
+    return (module.exports = moduleObject.exports);
+  } catch (e) {
+    module.hasError = true;
+    module.exports = undefined;
   }
+}
 
-  function moduleThrewError(id) {
-    return Error('Requiring module "' + id + '", which threw an exception.');
+function unknownModuleError(id) {
+  let message = 'Requiring unknown module "' + id + '".';
+  if (__DEV__) {
+    message +=
+      'If you are sure the module is there, try restarting the packager.';
   }
+  return Error(message);
+}
 
-})(this);
+function moduleThrewError(id) {
+  return Error('Requiring module "' + id + '", which threw an exception.');
+}
diff --git a/packager/react-packager/src/Resolver/polyfills/require.js b/packager/react-packager/src/Resolver/polyfills/require.js
index 36c2b6b90d32..a5a7a55f01a5 100644
--- a/packager/react-packager/src/Resolver/polyfills/require.js
+++ b/packager/react-packager/src/Resolver/polyfills/require.js
@@ -1,130 +1,128 @@
 /* eslint strict:0 */
-(function(global) {
-  var modules = Object.create(null);
-  var inGuard = false;
-
-  function define(id, factory) {
-    modules[id] = {
-      factory,
-      module: {exports: {}},
-      isInitialized: false,
-      hasError: false,
-    };
-
-    if (__DEV__) { // HMR
-      Object.assign(modules[id].module, {
-        hot: {
-          acceptCallback: null,
-          accept: function(callback) {
-            modules[id].module.hot.acceptCallback = callback;
-          }
+var modules = Object.create(null);
+var inGuard = false;
+
+function define(id, factory) {
+  modules[id] = {
+    factory,
+    module: {exports: {}},
+    isInitialized: false,
+    hasError: false,
+  };
+
+  if (__DEV__) { // HMR
+    Object.assign(modules[id].module, {
+      hot: {
+        acceptCallback: null,
+        accept: function(callback) {
+          modules[id].module.hot.acceptCallback = callback;
         }
-      });
-    }
+      }
+    });
   }
+}
 
-  function require(id) {
-    var mod = modules[id];
-    if (mod && mod.isInitialized) {
-      return mod.module.exports;
-    }
-
-    return requireImpl(id);
+function require(id) {
+  var mod = modules[id];
+  if (mod && mod.isInitialized) {
+    return mod.module.exports;
   }
 
-  function requireImpl(id) {
-    if (global.ErrorUtils && !inGuard) {
-      inGuard = true;
-      var returnValue;
-      try {
-        returnValue = requireImpl.apply(this, arguments);
-      } catch (e) {
-        global.ErrorUtils.reportFatalError(e);
-      }
-      inGuard = false;
-      return returnValue;
-    }
+  return requireImpl(id);
+}
 
-    var mod = modules[id];
-    if (!mod) {
-      var msg = 'Requiring unknown module "' + id + '"';
-      if (__DEV__) {
-        msg += '. If you are sure the module is there, try restarting the packager.';
-      }
-      throw new Error(msg);
+function requireImpl(id) {
+  if (global.ErrorUtils && !inGuard) {
+    inGuard = true;
+    var returnValue;
+    try {
+      returnValue = requireImpl.apply(this, arguments);
+    } catch (e) {
+      global.ErrorUtils.reportFatalError(e);
     }
+    inGuard = false;
+    return returnValue;
+  }
 
-    if (mod.hasError) {
-      throw new Error(
-        'Requiring module "' + id + '" which threw an exception'
-      );
+  var mod = modules[id];
+  if (!mod) {
+    var msg = 'Requiring unknown module "' + id + '"';
+    if (__DEV__) {
+      msg += '. If you are sure the module is there, try restarting the packager.';
     }
+    throw new Error(msg);
+  }
 
-    try {
-      // We must optimistically mark mod as initialized before running the factory to keep any
-      // require cycles inside the factory from causing an infinite require loop.
-      mod.isInitialized = true;
+  if (mod.hasError) {
+    throw new Error(
+      'Requiring module "' + id + '" which threw an exception'
+    );
+  }
 
-      __DEV__ && Systrace().beginEvent('JS_require_' + id);
+  try {
+    // We must optimistically mark mod as initialized before running the factory to keep any
+    // require cycles inside the factory from causing an infinite require loop.
+    mod.isInitialized = true;
 
-      // keep args in sync with with defineModuleCode in
-      // packager/react-packager/src/Resolver/index.js
-      mod.factory.call(global, global, require, mod.module, mod.module.exports);
+    __DEV__ && Systrace().beginEvent('JS_require_' + id);
 
-      __DEV__ && Systrace().endEvent();
-    } catch (e) {
-      mod.hasError = true;
-      mod.isInitialized = false;
-      throw e;
-    }
+    // keep args in sync with with defineModuleCode in
+    // packager/react-packager/src/Resolver/index.js
+    mod.factory.call(global, global, require, mod.module, mod.module.exports);
 
-    return mod.module.exports;
+    __DEV__ && Systrace().endEvent();
+  } catch (e) {
+    mod.hasError = true;
+    mod.isInitialized = false;
+    throw e;
   }
 
-  const Systrace = __DEV__ && (() => {
-    var _Systrace;
-    try {
-      _Systrace = require('Systrace');
-    } catch(e) {}
+  return mod.module.exports;
+}
 
-    return _Systrace && _Systrace.beginEvent ?
-      _Systrace : { beginEvent: () => {}, endEvent: () => {} };
-  });
+const Systrace = __DEV__ && (() => {
+  var _Systrace;
+  try {
+    _Systrace = require('Systrace');
+  } catch (e) {}
 
-  global.__d = define;
-  global.require = require;
+  return _Systrace && _Systrace.beginEvent ?
+    _Systrace : { beginEvent: () => {}, endEvent: () => {} };
+});
 
-  if (__DEV__) { // HMR
-    function accept(id, factory) {
-      var mod = modules[id];
+global.__d = define;
+global.require = require;
 
-      if (!mod) {
-        define(id, factory);
-        return; // new modules don't need to be accepted
-      }
+if (__DEV__) { // HMR
+  function accept(id, factory) {
+    var mod = modules[id];
 
-      if (!mod.module.hot) {
-        console.warn(
-          'Cannot accept module because Hot Module Replacement ' +
-          'API was not installed.'
-        );
-        return;
-      }
+    if (!mod) {
+      define(id, factory);
+      return; // new modules don't need to be accepted
+    }
 
-      if (mod.module.hot.acceptCallback) {
-        mod.factory = factory;
-        mod.isInitialized = false;
-        require(id);
-
-        mod.module.hot.acceptCallback();
-      } else {
-        console.warn(
-          '[HMR] Module `' + id + '` can\'t be hot reloaded because it ' +
-          'doesn\'t provide accept callback hook. Reload the app to get the updates.'
-        );
-      }
+    if (!mod.module.hot) {
+      console.warn(
+        'Cannot accept module because Hot Module Replacement ' +
+        'API was not installed.'
+      );
+      return;
     }
 
-    global.__accept = accept;
+    if (mod.module.hot.acceptCallback) {
+      mod.factory = factory;
+      mod.isInitialized = false;
+      require(id);
+
+      mod.module.hot.acceptCallback();
+    } else {
+      console.warn(
+        '[HMR] Module `' + id + '` can\'t be hot reloaded because it ' +
+        'doesn\'t provide accept callback hook. Reload the app to get the updates.'
+      );
+    }
   }
-})(this);
+
+  global.__accept = accept;
+}
diff --git a/packager/react-packager/src/transforms/whole-program-optimisations/__tests__/dead-module-elimination-test.js b/packager/react-packager/src/transforms/whole-program-optimisations/__tests__/dead-module-elimination-test.js
index 7525fd0f0152..4d7d142c48a9 100644
--- a/packager/react-packager/src/transforms/whole-program-optimisations/__tests__/dead-module-elimination-test.js
+++ b/packager/react-packager/src/transforms/whole-program-optimisations/__tests__/dead-module-elimination-test.js
@@ -33,7 +33,7 @@ const trim = (str) =>
 describe('dead-module-elimination', () => {
   it('should inline __DEV__', () => {
     compare(
-      `__DEV__ = false;
+      `global.__DEV__ = false;
       var foo = __DEV__;`,
       `var foo = false;`
     );
@@ -41,7 +41,7 @@ describe('dead-module-elimination', () => {
 
   it('should accept unary operators with literals', () => {
     compare(
-      `__DEV__ = !1;
+      `global.__DEV__ = !1;
       var foo = __DEV__;`,
       `var foo = false;`
     );
@@ -49,7 +49,7 @@ describe('dead-module-elimination', () => {
 
   it('should kill dead branches', () => {
     compare(
-      `__DEV__ = false;
+      `global.__DEV__ = false;
       if (__DEV__) {
         doSomething();
       }`,
@@ -74,7 +74,7 @@ describe('dead-module-elimination', () => {
 
   it('should kill modules referenced only from dead branches', () => {
     compare(
-      `__DEV__ = false;
+      `global.__DEV__ = false;
       __d('bar', function() {});
       if (__DEV__) { require('bar'); }`,
       ``
@@ -83,7 +83,7 @@ describe('dead-module-elimination', () => {
 
   it('should replace logical expressions with the result', () => {
     compare(
-      `__DEV__ = false;
+      `global.__DEV__ = false;
       __d('bar', function() {});
       __DEV__ && require('bar');`,
       `false;`
@@ -92,7 +92,7 @@ describe('dead-module-elimination', () => {
 
   it('should keep if result branch', () => {
     compare(
-      `__DEV__ = false;
+      `global.__DEV__ = false;
       __d('bar', function() {});
       if (__DEV__) {
         killWithFire();
@@ -106,7 +106,7 @@ describe('dead-module-elimination', () => {
 
   it('should replace falsy ternaries with alternate expression', () => {
     compare(
-      `__DEV__ = false;
+      `global.__DEV__ = false;
       __DEV__ ? foo() : bar();
       `,
       `bar();`
diff --git a/packager/react-packager/src/transforms/whole-program-optimisations/dead-module-elimination.js b/packager/react-packager/src/transforms/whole-program-optimisations/dead-module-elimination.js
index 39eeb0a6c229..1d6c8f340f38 100644
--- a/packager/react-packager/src/transforms/whole-program-optimisations/dead-module-elimination.js
+++ b/packager/react-packager/src/transforms/whole-program-optimisations/dead-module-elimination.js
@@ -60,7 +60,12 @@ module.exports = function () {
     AssignmentExpression(path) {
       const { node } = path;
 
-      if (node.left.type === 'Identifier' && node.left.name === '__DEV__') {
+      if (
+        node.left.type === 'MemberExpression' &&
+        node.left.object.name === 'global' &&
+        node.left.property.type === 'Identifier' &&
+        node.left.property.name === '__DEV__'
+      ) {
         var value;
         if (node.right.type === 'BooleanLiteral') {
           value = node.right.value;
@@ -73,7 +78,7 @@ module.exports = function () {
         } else {
           return;
         }
-        globals[node.left.name] = value;
+        globals[node.left.property.name] = value;
 
         // workaround babel/source map bug - the minifier should strip it
         path.replaceWith(t.booleanLiteral(value));

From 34d5fa2695971ba9c9b2271578ade4b700061066 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 21 Jan 2016 07:49:45 -0800
Subject: [PATCH 0823/1411] RCTUtils Obj-C nullability annotations

Summary:
Add Objective-C nullability annotations to RCTUtils

public

Reviewed By: javache

Differential Revision: D2797331

fb-gh-sync-id: b918179625865760edc8c6fcc189ad78f819f3e3
---
 React/Base/RCTAssert.m |  6 ++--
 React/Base/RCTUtils.h  | 48 ++++++++++++++++--------------
 React/Base/RCTUtils.m  | 67 +++++++++++++++++++++++-------------------
 3 files changed, 66 insertions(+), 55 deletions(-)

diff --git a/React/Base/RCTAssert.m b/React/Base/RCTAssert.m
index 4742cb381d91..d0006e218f30 100644
--- a/React/Base/RCTAssert.m
+++ b/React/Base/RCTAssert.m
@@ -119,7 +119,7 @@ void _RCTAssertFormat(
 
 void RCTFatal(NSError *error)
 {
-  _RCTLogNativeInternal(RCTLogLevelFatal, NULL, 0, @"%@", [error localizedDescription]);
+  _RCTLogNativeInternal(RCTLogLevelFatal, NULL, 0, @"%@", error.localizedDescription);
 
   RCTFatalHandler fatalHandler = RCTGetFatalHandler();
   if (fatalHandler) {
@@ -128,8 +128,8 @@ void RCTFatal(NSError *error)
 #if DEBUG
     @try {
 #endif
-      NSString *name = [NSString stringWithFormat:@"%@: %@", RCTFatalExceptionName, [error localizedDescription]];
-      NSString *message = RCTFormatError([error localizedDescription], error.userInfo[RCTJSStackTraceKey], 75);
+      NSString *name = [NSString stringWithFormat:@"%@: %@", RCTFatalExceptionName, error.localizedDescription];
+      NSString *message = RCTFormatError(error.localizedDescription, error.userInfo[RCTJSStackTraceKey], 75);
       [NSException raise:name format:@"%@", message];
 #if DEBUG
     } @catch (NSException *e) {}
diff --git a/React/Base/RCTUtils.h b/React/Base/RCTUtils.h
index 7c8aaa511138..811c66d1ad67 100644
--- a/React/Base/RCTUtils.h
+++ b/React/Base/RCTUtils.h
@@ -16,10 +16,12 @@
 #import "RCTAssert.h"
 #import "RCTDefines.h"
 
+NS_ASSUME_NONNULL_BEGIN
+
 // JSON serialization/deserialization
-RCT_EXTERN NSString *RCTJSONStringify(id jsonObject, NSError **error);
-RCT_EXTERN id RCTJSONParse(NSString *jsonString, NSError **error);
-RCT_EXTERN id RCTJSONParseMutable(NSString *jsonString, NSError **error);
+RCT_EXTERN NSString *__nullable RCTJSONStringify(id __nullable jsonObject, NSError **error);
+RCT_EXTERN id __nullable RCTJSONParse(NSString *__nullable jsonString, NSError **error);
+RCT_EXTERN id __nullable RCTJSONParseMutable(NSString *__nullable jsonString, NSError **error);
 
 // Strip non JSON-safe values from an object graph
 RCT_EXTERN id RCTJSONClean(id object);
@@ -51,13 +53,13 @@ RCT_EXTERN void RCTSwapInstanceMethods(Class cls, SEL original, SEL replacement)
 RCT_EXTERN BOOL RCTClassOverridesClassMethod(Class cls, SEL selector);
 RCT_EXTERN BOOL RCTClassOverridesInstanceMethod(Class cls, SEL selector);
 
-// Creates a standardized error object
-RCT_EXTERN NSDictionary<NSString *, id> *RCTMakeError(NSString *message, id toStringify, NSDictionary<NSString *, id> *extraData);
-RCT_EXTERN NSDictionary<NSString *, id> *RCTMakeAndLogError(NSString *message, id toStringify, NSDictionary<NSString *, id> *extraData);
+// Creates a standardized error object to return in callbacks
+RCT_EXTERN NSDictionary<NSString *, id> *RCTMakeError(NSString *message, id __nullable toStringify, NSDictionary<NSString *, id> *__nullable extraData);
+RCT_EXTERN NSDictionary<NSString *, id> *RCTMakeAndLogError(NSString *message, id __nullable toStringify, NSDictionary<NSString *, id> *__nullable extraData);
 RCT_EXTERN NSDictionary<NSString *, id> *RCTJSErrorFromNSError(NSError *error);
-RCT_EXTERN NSDictionary<NSString *, id> *RCTJSErrorFromCodeMessageAndNSError(NSString *code, NSString *message, NSError *error);
+RCT_EXTERN NSDictionary<NSString *, id> *RCTJSErrorFromCodeMessageAndNSError(NSString *code, NSString *message, NSError *__nullable error);
 
-// The default error code that will be sent in the .code value of the Error object to js
+// The default error code to use as the `code` property for callback error objects
 RCT_EXTERN NSString *const RCTErrorUnspecified;
 
 // Returns YES if React is running in a test environment
@@ -67,26 +69,26 @@ RCT_EXTERN BOOL RCTRunningInTestEnvironment(void);
 RCT_EXTERN BOOL RCTRunningInAppExtension(void);
 
 // Returns the shared UIApplication instance, or nil if running in an App Extension
-RCT_EXTERN UIApplication *RCTSharedApplication(void);
+RCT_EXTERN UIApplication *__nullable RCTSharedApplication(void);
 
 // Returns the current main window, useful if you need to access the root view
 // or view controller, e.g. to present a modal view controller or alert.
-RCT_EXTERN UIWindow *RCTKeyWindow(void);
+RCT_EXTERN UIWindow *__nullable RCTKeyWindow(void);
 
 // Return a UIAlertView initialized with the given values
 // or nil if running in an app extension
-RCT_EXTERN UIAlertView *RCTAlertView(NSString *title,
-                                     NSString *message,
-                                     id delegate,
-                                     NSString *cancelButtonTitle,
-                                     NSArray<NSString *> *otherButtonTitles);
+RCT_EXTERN UIAlertView *__nullable RCTAlertView(NSString *title,
+                                                NSString *__nullable message,
+                                                id __nullable delegate,
+                                                NSString *__nullable cancelButtonTitle,
+                                                NSArray<NSString *> *__nullable otherButtonTitles);
 
 // Create an NSError in the RCTErrorDomain
 RCT_EXTERN NSError *RCTErrorWithMessage(NSString *message);
 
 // Convert nil values to NSNull, and vice-versa
-RCT_EXTERN id RCTNilIfNull(id value);
-RCT_EXTERN id RCTNullIfNil(id value);
+RCT_EXTERN id __nullable RCTNilIfNull(id __nullable value);
+RCT_EXTERN id RCTNullIfNil(id __nullable value);
 
 // Convert NaN or infinite values to zero, as these aren't JSON-safe
 RCT_EXTERN double RCTZeroIfNaN(double value);
@@ -95,14 +97,14 @@ RCT_EXTERN double RCTZeroIfNaN(double value);
 RCT_EXTERN NSURL *RCTDataURL(NSString *mimeType, NSData *data);
 
 // Gzip functionality - compression level in range 0 - 1 (-1 for default)
-RCT_EXTERN NSData *RCTGzipData(NSData *data, float level);
+RCT_EXTERN NSData *RCTGzipData(NSData *__nullable data, float level);
 
 // Returns the relative path within the main bundle for an absolute URL
 // (or nil, if the URL does not specify a path within the main bundle)
-RCT_EXTERN NSString *RCTBundlePathForURL(NSURL *URL);
+RCT_EXTERN NSString *__nullable RCTBundlePathForURL(NSURL *__nullable URL);
 
 // Determines if a given image URL actually refers to an XCAsset
-RCT_EXTERN BOOL RCTIsXCAssetURL(NSURL *imageURL);
+RCT_EXTERN BOOL RCTIsXCAssetURL(NSURL *__nullable imageURL);
 
 // Converts a CGColor to a hex string
 RCT_EXTERN NSString *RCTColorToHexString(CGColorRef color);
@@ -111,5 +113,7 @@ RCT_EXTERN NSString *RCTColorToHexString(CGColorRef color);
 RCT_EXTERN NSString *RCTUIKitLocalizedString(NSString *string);
 
 // URL manipulation
-RCT_EXTERN NSString *RCTGetURLQueryParam(NSURL *URL, NSString *param);
-RCT_EXTERN NSURL *RCTURLByReplacingQueryParam(NSURL *URL, NSString *param, NSString *value);
+RCT_EXTERN NSString *__nullable RCTGetURLQueryParam(NSURL *__nullable URL, NSString *param);
+RCT_EXTERN NSURL *__nullable RCTURLByReplacingQueryParam(NSURL *__nullable URL, NSString *param, NSString *__nullable value);
+
+NS_ASSUME_NONNULL_END
diff --git a/React/Base/RCTUtils.m b/React/Base/RCTUtils.m
index b13b3f951fdc..7040aa1fe0d3 100644
--- a/React/Base/RCTUtils.m
+++ b/React/Base/RCTUtils.m
@@ -23,7 +23,7 @@
 
 NSString *const RCTErrorUnspecified = @"EUNSPECIFIED";
 
-NSString *RCTJSONStringify(id jsonObject, NSError **error)
+NSString *__nullable RCTJSONStringify(id __nullable jsonObject, NSError **error)
 {
   static SEL JSONKitSelector = NULL;
   static NSSet<Class> *collectionTypes;
@@ -44,14 +44,14 @@
   }
 
   // Use Foundation JSON method
-  NSData *jsonData = [NSJSONSerialization
-                      dataWithJSONObject:jsonObject
-                      options:(NSJSONWritingOptions)NSJSONReadingAllowFragments
-                      error:error];
+  NSData *jsonData = jsonObject ? [NSJSONSerialization
+                                   dataWithJSONObject:jsonObject
+                                   options:(NSJSONWritingOptions)NSJSONReadingAllowFragments
+                                   error:error] : nil;
   return jsonData ? [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding] : nil;
 }
 
-static id _RCTJSONParse(NSString *jsonString, BOOL mutable, NSError **error)
+static id __nullable _RCTJSONParse(NSString *__nullable jsonString, BOOL mutable, NSError **error)
 {
   static SEL JSONKitSelector = NULL;
   static SEL JSONKitMutableSelector = NULL;
@@ -110,12 +110,12 @@ static id _RCTJSONParse(NSString *jsonString, BOOL mutable, NSError **error)
   return nil;
 }
 
-id RCTJSONParse(NSString *jsonString, NSError **error)
+id __nullable RCTJSONParse(NSString *__nullable jsonString, NSError **error)
 {
   return _RCTJSONParse(jsonString, NO, error);
 }
 
-id RCTJSONParseMutable(NSString *jsonString, NSError **error)
+id __nullable RCTJSONParseMutable(NSString *__nullable jsonString, NSError **error)
 {
   return _RCTJSONParse(jsonString, YES, error);
 }
@@ -311,18 +311,22 @@ BOOL RCTClassOverridesInstanceMethod(Class cls, SEL selector)
   return NO;
 }
 
-NSDictionary<NSString *, id> *RCTMakeError(NSString *message, id toStringify, NSDictionary<NSString *, id> *extraData)
+NSDictionary<NSString *, id> *RCTMakeError(NSString *message,
+                                           id __nullable toStringify,
+                                           NSDictionary<NSString *, id> *__nullable extraData)
 {
   if (toStringify) {
     message = [message stringByAppendingString:[toStringify description]];
   }
 
-  NSMutableDictionary<NSString *, id> *error = [NSMutableDictionary dictionaryWithDictionary:extraData];
+  NSMutableDictionary<NSString *, id> *error = [extraData mutableCopy] ?: [NSMutableDictionary new];
   error[@"message"] = message;
   return error;
 }
 
-NSDictionary<NSString *, id> *RCTMakeAndLogError(NSString *message, id toStringify, NSDictionary<NSString *, id> *extraData)
+NSDictionary<NSString *, id> *RCTMakeAndLogError(NSString *message,
+                                                 id __nullable toStringify,
+                                                 NSDictionary<NSString *, id> *__nullable extraData)
 {
   NSDictionary<NSString *, id> *error = RCTMakeError(message, toStringify, extraData);
   RCTLogError(@"\nError: %@", error);
@@ -331,11 +335,15 @@ BOOL RCTClassOverridesInstanceMethod(Class cls, SEL selector)
 
 NSDictionary<NSString *, id> *RCTJSErrorFromNSError(NSError *error)
 {
-  return RCTJSErrorFromCodeMessageAndNSError(RCTErrorUnspecified, nil, error);
+  return RCTJSErrorFromCodeMessageAndNSError(RCTErrorUnspecified,
+                                             error.localizedDescription,
+                                             error);
 }
 
 // TODO: Can we just replace RCTMakeError with this function instead?
-NSDictionary<NSString *, id> *RCTJSErrorFromCodeMessageAndNSError(NSString *code, NSString *message, NSError *error)
+NSDictionary<NSString *, id> *RCTJSErrorFromCodeMessageAndNSError(NSString *code,
+                                                                  NSString *message,
+                                                                  NSError *__nullable error)
 {
   NSString *errorMessage;
   NSArray<NSString *> *stackTrace = [NSThread callStackSymbols];
@@ -356,7 +364,6 @@ BOOL RCTClassOverridesInstanceMethod(Class cls, SEL selector)
   return RCTMakeError(errorMessage, nil, errorInfo);
 }
 
-
 BOOL RCTRunningInTestEnvironment(void)
 {
   static BOOL isTestEnvironment = NO;
@@ -372,7 +379,7 @@ BOOL RCTRunningInAppExtension(void)
   return [[[[NSBundle mainBundle] bundlePath] pathExtension] isEqualToString:@"appex"];
 }
 
-UIApplication *RCTSharedApplication(void)
+UIApplication *__nullable RCTSharedApplication(void)
 {
   if (RCTRunningInAppExtension()) {
     return nil;
@@ -380,7 +387,7 @@ BOOL RCTRunningInAppExtension(void)
   return [[UIApplication class] performSelector:@selector(sharedApplication)];
 }
 
-UIWindow *RCTKeyWindow(void)
+UIWindow *__nullable RCTKeyWindow(void)
 {
   if (RCTRunningInAppExtension()) {
     return nil;
@@ -390,11 +397,11 @@ BOOL RCTRunningInAppExtension(void)
   return RCTSharedApplication().keyWindow;
 }
 
-UIAlertView *RCTAlertView(NSString *title,
-                          NSString *message,
-                          id delegate,
-                          NSString *cancelButtonTitle,
-                          NSArray<NSString *> *otherButtonTitles)
+UIAlertView *__nullable RCTAlertView(NSString *title,
+                                     NSString *__nullable message,
+                                     id __nullable delegate,
+                                     NSString *__nullable cancelButtonTitle,
+                                     NSArray<NSString *> *__nullable otherButtonTitles)
 {
   if (RCTRunningInAppExtension()) {
     RCTLogError(@"RCTAlertView is unavailable when running in an app extension");
@@ -421,12 +428,12 @@ BOOL RCTRunningInAppExtension(void)
   return [[NSError alloc] initWithDomain:RCTErrorDomain code:0 userInfo:errorInfo];
 }
 
-id RCTNullIfNil(id value)
+id RCTNullIfNil(id __nullable value)
 {
   return value ?: (id)kCFNull;
 }
 
-id RCTNilIfNull(id value)
+id __nullable RCTNilIfNull(id __nullable value)
 {
   return value == (id)kCFNull ? nil : value;
 }
@@ -443,14 +450,14 @@ RCT_EXTERN double RCTZeroIfNaN(double value)
            [data base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)0]]];
 }
 
-BOOL RCTIsGzippedData(NSData *); // exposed for unit testing purposes
-BOOL RCTIsGzippedData(NSData *data)
+BOOL RCTIsGzippedData(NSData *__nullable); // exposed for unit testing purposes
+BOOL RCTIsGzippedData(NSData *__nullable data)
 {
   UInt8 *bytes = (UInt8 *)data.bytes;
   return (data.length >= 2 && bytes[0] == 0x1f && bytes[1] == 0x8b);
 }
 
-NSData *RCTGzipData(NSData *input, float level)
+NSData *RCTGzipData(NSData *__nullable input, float level)
 {
   if (input.length == 0 || RCTIsGzippedData(input)) {
     return input;
@@ -493,7 +500,7 @@ BOOL RCTIsGzippedData(NSData *data)
   return output;
 }
 
-NSString *RCTBundlePathForURL(NSURL *URL)
+NSString *__nullable  RCTBundlePathForURL(NSURL *__nullable URL)
 {
   if (!URL.fileURL) {
     // Not a file path
@@ -512,7 +519,7 @@ BOOL RCTIsGzippedData(NSData *data)
   return path;
 }
 
-BOOL RCTIsXCAssetURL(NSURL *imageURL)
+BOOL RCTIsXCAssetURL(NSURL *__nullable imageURL)
 {
   NSString *name = RCTBundlePathForURL(imageURL);
   if (name.pathComponents.count != 1) {
@@ -598,7 +605,7 @@ static void RCTGetRGBAColorComponents(CGColorRef color, CGFloat rgba[4])
   return UIKitBundle ? [UIKitBundle localizedStringForKey:string value:string table:nil] : string;
 }
 
-NSString *RCTGetURLQueryParam(NSURL *URL, NSString *param)
+NSString *__nullable RCTGetURLQueryParam(NSURL *__nullable URL, NSString *param)
 {
   RCTAssertParam(param);
   if (!URL) {
@@ -618,7 +625,7 @@ static void RCTGetRGBAColorComponents(CGColorRef color, CGFloat rgba[4])
   return nil;
 }
 
-NSURL *RCTURLByReplacingQueryParam(NSURL *URL, NSString *param, NSString *value)
+NSURL *__nullable RCTURLByReplacingQueryParam(NSURL *__nullable URL, NSString *param, NSString *__nullable value)
 {
   RCTAssertParam(param);
   if (!URL) {

From 9baff8f437eee49f8ab0e6f433bf86466ca16662 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Thu, 21 Jan 2016 08:07:01 -0800
Subject: [PATCH 0824/1411] Make CameraRoll work with Promises

Summary:
public
This is the first module moving to the new model of working with Promises.

We now warn on uses of callback version.  At some point we will remove that.

Reviewed By: davidaurelio

Differential Revision: D2849811

fb-gh-sync-id: 8a31924cc2b438efc58f3ad22d5f27c273563472
---
 Libraries/CameraRoll/CameraRoll.js            | 69 +++++++++----------
 Libraries/CameraRoll/RCTCameraRollManager.m   | 45 ++++++------
 Libraries/Utilities/MessageQueue.js           | 20 ++++--
 Libraries/Utilities/Platform.android.js       |  4 +-
 .../com/facebook/react/bridge/Promise.java    |  4 +-
 .../facebook/react/bridge/PromiseImpl.java    |  2 +-
 .../modules/camera/CameraRollManager.java     | 56 +++++++--------
 7 files changed, 105 insertions(+), 95 deletions(-)

diff --git a/Libraries/CameraRoll/CameraRoll.js b/Libraries/CameraRoll/CameraRoll.js
index 5ea9b94677af..3b4b0ed1a200 100644
--- a/Libraries/CameraRoll/CameraRoll.js
+++ b/Libraries/CameraRoll/CameraRoll.js
@@ -128,57 +128,56 @@ class CameraRoll {
    *   - a tag not matching any of the above, which means the image data will
    * be stored in memory (and consume memory as long as the process is alive)
    *
-   * @param successCallback Invoked with the value of `tag` on success.
-   * @param errorCallback Invoked with error message on error.
+   * Returns a Promise which when resolved will be passed the new uri
+   *
    */
-  static saveImageWithTag(tag, successCallback, errorCallback) {
+  static saveImageWithTag(tag) {
     invariant(
       typeof tag === 'string',
       'CameraRoll.saveImageWithTag tag must be a valid string.'
     );
-    RCTCameraRollManager.saveImageWithTag(
-      tag,
-      (imageTag) => {
-        successCallback && successCallback(imageTag);
-      },
-      (errorMessage) => {
-        errorCallback && errorCallback(errorMessage);
-      });
+    if (arguments.length > 1) {
+      console.warn("CameraRoll.saveImageWithTag(tag, success, error) is deprecated.  Use the returned Promise instead");
+      let successCallback = arguments[1];
+      let errorCallback = arguments[2] || ( () => {} );
+      RCTCameraRollManager.saveImageWithTag(tag).then(successCallback, errorCallback);
+      return;
+    }
+    return RCTCameraRollManager.saveImageWithTag(tag);
   }
 
   /**
-   *  Invokes `callback` with photo identifier objects from the local camera
+   *  Returns a Promise with photo identifier objects from the local camera
    *  roll of the device matching shape defined by `getPhotosReturnChecker`.
    *
    *  @param {object} params See `getPhotosParamChecker`.
-   *  @param {function} callback Invoked with arg of shape defined by
-   *  `getPhotosReturnChecker` on success.
-   *  @param {function} errorCallback Invoked with error message on error.
+   *
+   *  Returns a Promise which when resolved will be of shape `getPhotosReturnChecker`
+   *
    */
-  static getPhotos(params, callback, errorCallback) {
-    var metaCallback = callback;
+  static getPhotos(params) {
     if (__DEV__) {
       getPhotosParamChecker({params}, 'params', 'CameraRoll.getPhotos');
-      invariant(
-        typeof callback === 'function',
-        'CameraRoll.getPhotos callback must be a valid function.'
-      );
-      invariant(
-        typeof errorCallback === 'function',
-        'CameraRoll.getPhotos errorCallback must be a valid function.'
-      );
     }
-    if (__DEV__) {
-      metaCallback = (response) => {
-        getPhotosReturnChecker(
-          {response},
-          'response',
-          'CameraRoll.getPhotos callback'
-        );
-        callback(response);
-      };
+    if (arguments.length > 1) {
+      console.warn("CameraRoll.getPhotos(tag, success, error) is deprecated.  Use the returned Promise instead");
+      let successCallback = arguments[1];
+      if (__DEV__) {
+        let callback = arguments[1];
+        successCallback = (response) => {
+          getPhotosReturnChecker(
+            {response},
+            'response',
+            'CameraRoll.getPhotos callback'
+          );
+          callback(response);
+        };
+      }
+      let errorCallback = arguments[2] || ( () => {} );
+      RCTCameraRollManager.getPhotos(params).then(successCallback, errorCallback);
     }
-    RCTCameraRollManager.getPhotos(params, metaCallback, errorCallback);
+    // TODO: Add the __DEV__ check back in to verify the Promise result
+    return RCTCameraRollManager.getPhotos(params);
   }
 }
 
diff --git a/Libraries/CameraRoll/RCTCameraRollManager.m b/Libraries/CameraRoll/RCTCameraRollManager.m
index ad4ad171371c..fc97c9493b4a 100644
--- a/Libraries/CameraRoll/RCTCameraRollManager.m
+++ b/Libraries/CameraRoll/RCTCameraRollManager.m
@@ -79,13 +79,16 @@ @implementation RCTCameraRollManager
 
 @synthesize bridge = _bridge;
 
+NSString *const RCTErrorUnableToLoad = @"E_UNABLE_TO_LOAD";
+NSString *const RCTErrorUnableToSave = @"E_UNABLE_TO_SAVE";
+
 RCT_EXPORT_METHOD(saveImageWithTag:(NSString *)imageTag
-                  successCallback:(RCTResponseSenderBlock)successCallback
-                  errorCallback:(RCTResponseErrorBlock)errorCallback)
+                  resolve:(RCTPromiseResolveBlock)resolve
+                  reject:(RCTPromiseRejectBlock)reject)
 {
   [_bridge.imageLoader loadImageWithTag:imageTag callback:^(NSError *loadError, UIImage *loadedImage) {
     if (loadError) {
-      errorCallback(loadError);
+      reject(RCTErrorUnableToLoad, nil, loadError);
       return;
     }
     // It's unclear if writeImageToSavedPhotosAlbum is thread-safe
@@ -93,21 +96,21 @@ @implementation RCTCameraRollManager
       [_bridge.assetsLibrary writeImageToSavedPhotosAlbum:loadedImage.CGImage metadata:nil completionBlock:^(NSURL *assetURL, NSError *saveError) {
         if (saveError) {
           RCTLogWarn(@"Error saving cropped image: %@", saveError);
-          errorCallback(saveError);
+          reject(RCTErrorUnableToSave, nil, saveError);
         } else {
-          successCallback(@[assetURL.absoluteString]);
+          resolve(@[assetURL.absoluteString]);
         }
       }];
     });
   }];
 }
 
-static void RCTCallCallback(RCTResponseSenderBlock callback,
-                            NSArray<NSDictionary<NSString *, id> *> *assets,
-                            BOOL hasNextPage)
+static void RCTResolvePromise(RCTPromiseResolveBlock resolve,
+                              NSArray<NSDictionary<NSString *, id> *> *assets,
+                              BOOL hasNextPage)
 {
   if (!assets.count) {
-    callback(@[@{
+    resolve(@[@{
       @"edges": assets,
       @"page_info": @{
         @"has_next_page": @NO,
@@ -115,7 +118,7 @@ static void RCTCallCallback(RCTResponseSenderBlock callback,
     }]);
     return;
   }
-  callback(@[@{
+  resolve(@[@{
     @"edges": assets,
     @"page_info": @{
       @"start_cursor": assets[0][@"node"][@"image"][@"uri"],
@@ -126,8 +129,8 @@ static void RCTCallCallback(RCTResponseSenderBlock callback,
 }
 
 RCT_EXPORT_METHOD(getPhotos:(NSDictionary *)params
-                  successCallback:(RCTResponseSenderBlock)successCallback
-                  errorCallback:(RCTResponseErrorBlock)errorCallback)
+                  resolve:(RCTPromiseResolveBlock)resolve
+                  reject:(RCTPromiseRejectBlock)reject)
 {
   NSUInteger first = [RCTConvert NSInteger:params[@"first"]];
   NSString *afterCursor = [RCTConvert NSString:params[@"after"]];
@@ -137,7 +140,7 @@ static void RCTCallCallback(RCTResponseSenderBlock callback,
 
   BOOL __block foundAfter = NO;
   BOOL __block hasNextPage = NO;
-  BOOL __block calledCallback = NO;
+  BOOL __block resolvedPromise = NO;
   NSMutableArray<NSDictionary<NSString *, id> *> *assets = [NSMutableArray new];
 
   [_bridge.assetsLibrary enumerateGroupsWithTypes:groupTypes usingBlock:^(ALAssetsGroup *group, BOOL *stopGroups) {
@@ -157,9 +160,9 @@ static void RCTCallCallback(RCTResponseSenderBlock callback,
             *stopAssets = YES;
             *stopGroups = YES;
             hasNextPage = YES;
-            RCTAssert(calledCallback == NO, @"Called the callback before we finished processing the results.");
-            RCTCallCallback(successCallback, assets, hasNextPage);
-            calledCallback = YES;
+            RCTAssert(resolvedPromise == NO, @"Resolved the promise before we finished processing the results.");
+            RCTResolvePromise(resolve, assets, hasNextPage);
+            resolvedPromise = YES;
             return;
           }
           CGSize dimensions = [result defaultRepresentation].dimensions;
@@ -188,18 +191,18 @@ static void RCTCallCallback(RCTResponseSenderBlock callback,
         }
       }];
     } else {
-      // Sometimes the enumeration continues even if we set stop above, so we guard against calling the callback
+      // Sometimes the enumeration continues even if we set stop above, so we guard against resolving the promise
       // multiple times here.
-      if (!calledCallback) {
-        RCTCallCallback(successCallback, assets, hasNextPage);
-        calledCallback = YES;
+      if (!resolvedPromise) {
+        RCTResolvePromise(resolve, assets, hasNextPage);
+        resolvedPromise = YES;
       }
     }
   } failureBlock:^(NSError *error) {
     if (error.code != ALAssetsLibraryAccessUserDeniedError) {
       RCTLogError(@"Failure while iterating through asset groups %@", error);
     }
-    errorCallback(error);
+    reject(RCTErrorUnableToLoad, nil, error);
   }];
 }
 
diff --git a/Libraries/Utilities/MessageQueue.js b/Libraries/Utilities/MessageQueue.js
index f22094bbead0..8e58ee06e3c7 100644
--- a/Libraries/Utilities/MessageQueue.js
+++ b/Libraries/Utilities/MessageQueue.js
@@ -16,6 +16,7 @@
 let Systrace = require('Systrace');
 let ErrorUtils = require('ErrorUtils');
 let JSTimersExecution = require('JSTimersExecution');
+let Platform = require('Platform');
 
 let invariant = require('invariant');
 let keyMirror = require('keyMirror');
@@ -318,10 +319,21 @@ class MessageQueue {
     if (type === MethodTypes.remoteAsync) {
       fn = function(...args) {
         return new Promise((resolve, reject) => {
-          self.__nativeCall(module, method, args, resolve, (errorData) => {
-            var error = createErrorFromErrorData(errorData);
-            reject(error);
-          });
+          self.__nativeCall(
+            module,
+            method,
+            args,
+            (data) => {
+              // iOS always wraps the data in an Array regardless of what the
+              // shape of the data so we strip it out
+              // Android sends the data back properly
+              // TODO: Remove this once iOS has support for Promises natively (t9774697)
+              resolve(Platform.OS == 'ios' ? data[0] : data);
+            },
+            (errorData) => {
+              var error = createErrorFromErrorData(errorData);
+              reject(error);
+            });
         });
       };
     } else {
diff --git a/Libraries/Utilities/Platform.android.js b/Libraries/Utilities/Platform.android.js
index 2d061d4148d0..659d9c873a1c 100644
--- a/Libraries/Utilities/Platform.android.js
+++ b/Libraries/Utilities/Platform.android.js
@@ -12,11 +12,9 @@
 
 'use strict';
 
-var AndroidConstants = require('NativeModules').AndroidConstants;
-
 var Platform = {
   OS: 'android',
-  Version: AndroidConstants.Version,
+  get Version() { return require('NativeModules').AndroidConstants.Version; },
 };
 
 module.exports = Platform;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/Promise.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/Promise.java
index 84b802b28aff..5b107fd99a8d 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/Promise.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/Promise.java
@@ -9,6 +9,8 @@
 
 package com.facebook.react.bridge;
 
+import javax.annotation.Nullable;
+
 /**
  * Interface that represents a JavaScript Promise which can be passed to the native module as a
  * method parameter.
@@ -22,5 +24,5 @@ public interface Promise {
   @Deprecated
   void reject(String reason);
   void reject(String code, Throwable extra);
-  void reject(String code, String reason, Throwable extra);
+  void reject(String code, String reason, @Nullable Throwable extra);
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/PromiseImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/PromiseImpl.java
index efbc4537592d..0c1c85c9e6d6 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/PromiseImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/PromiseImpl.java
@@ -50,7 +50,7 @@ public void reject(String code, Throwable extra) {
   }
 
   @Override
-  public void reject(String code, String reason, Throwable extra) {
+  public void reject(String code, String reason, @Nullable Throwable extra) {
     if (mReject != null) {
       if (code == null) {
         code = DEFAULT_ERROR;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/CameraRollManager.java b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/CameraRollManager.java
index 289a045bfdba..357586aa13c6 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/CameraRollManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/CameraRollManager.java
@@ -36,8 +36,8 @@
 import android.text.TextUtils;
 
 import com.facebook.common.logging.FLog;
-import com.facebook.react.bridge.Callback;
 import com.facebook.react.bridge.GuardedAsyncTask;
+import com.facebook.react.bridge.Promise;
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReactContextBaseJavaModule;
@@ -60,6 +60,9 @@
 public class CameraRollManager extends ReactContextBaseJavaModule {
 
   private static final String TAG = "Catalyst/CameraRollManager";
+  private static final String ERROR_UNABLE_TO_LOAD = "E_UNABLE_TO_LOAD";
+  private static final String ERROR_UNABLE_TO_LOAD_PERMISSION = "E_UNABLE_TO_LOAD_PERMISSION";
+  private static final String ERROR_UNABLE_TO_SAVE = "E_UNABLE_TO_SAVE";
 
   public static final boolean IS_JELLY_BEAN_OR_LATER =
       Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
@@ -112,14 +115,11 @@ public Map<String, Object> getConstants() {
    * by the MediaScanner.
    *
    * @param uri the file:// URI of the image to save
-   * @param success callback to be invoked on successful save to gallery; the only argument passed
-   *        to this callback is the MediaStore content:// URI of the new image.
-   * @param error callback to be invoked on error (e.g. can't copy file, external storage not
-   *        available etc.)
+   * @param promise to be resolved or rejected
    */
   @ReactMethod
-  public void saveImageWithTag(String uri, final Callback success, final Callback error) {
-    new SaveImageTag(getReactApplicationContext(), Uri.parse(uri), success, error)
+  public void saveImageWithTag(String uri, Promise promise) {
+    new SaveImageTag(getReactApplicationContext(), Uri.parse(uri), promise)
         .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
   }
 
@@ -127,15 +127,13 @@ private static class SaveImageTag extends GuardedAsyncTask<Void, Void> {
 
     private final Context mContext;
     private final Uri mUri;
-    private final Callback mSuccess;
-    private final Callback mError;
+    private final Promise mPromise;
 
-    public SaveImageTag(ReactContext context, Uri uri, Callback success, Callback error) {
+    public SaveImageTag(ReactContext context, Uri uri, Promise promise) {
       super(context);
       mContext = context;
       mUri = uri;
-      mSuccess = success;
-      mError = error;
+      mPromise = promise;
     }
 
     @Override
@@ -147,7 +145,7 @@ protected void doInBackgroundGuarded(Void... params) {
             Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
         pictures.mkdirs();
         if (!pictures.isDirectory()) {
-          mError.invoke("External storage pictures directory not available");
+          mPromise.reject(ERROR_UNABLE_TO_LOAD, "External storage pictures directory not available", null);
           return;
         }
         File dest = new File(pictures, source.getName());
@@ -178,14 +176,14 @@ protected void doInBackgroundGuarded(Void... params) {
               @Override
               public void onScanCompleted(String path, Uri uri) {
                 if (uri != null) {
-                  mSuccess.invoke(uri.toString());
+                  mPromise.resolve(uri.toString());
                 } else {
-                  mError.invoke("Could not add image to gallery");
+                  mPromise.reject(ERROR_UNABLE_TO_SAVE, "Could not add image to gallery", null);
                 }
               }
             });
       } catch (IOException e) {
-        mError.invoke(e.getMessage());
+        mPromise.reject(e);
       } finally {
         if (input != null && input.isOpen()) {
           try {
@@ -221,12 +219,11 @@ public void onScanCompleted(String path, Uri uri) {
    *            image/jpeg)
    *          </li>
    *        </ul>
-   * @param success the callback to be called when the photos are loaded; for a format of the
+   * @param promise the Promise to be resolved when the photos are loaded; for a format of the
    *        parameters passed to this callback, see {@code getPhotosReturnChecker} in CameraRoll.js
-   * @param error the callback to be called on error
    */
   @ReactMethod
-  public void getPhotos(final ReadableMap params, final Callback success, Callback error) {
+  public void getPhotos(final ReadableMap params, final Promise promise) {
     int first = params.getInt("first");
     String after = params.hasKey("after") ? params.getString("after") : null;
     String groupName = params.hasKey("groupName") ? params.getString("groupName") : null;
@@ -243,8 +240,7 @@ public void getPhotos(final ReadableMap params, final Callback success, Callback
           after,
           groupName,
           mimeTypes,
-          success,
-          error)
+          promise)
           .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
   }
 
@@ -254,8 +250,7 @@ private static class GetPhotosTask extends GuardedAsyncTask<Void, Void> {
     private final @Nullable String mAfter;
     private final @Nullable String mGroupName;
     private final @Nullable ReadableArray mMimeTypes;
-    private final Callback mSuccess;
-    private final Callback mError;
+    private final Promise mPromise;
 
     private GetPhotosTask(
         ReactContext context,
@@ -263,16 +258,14 @@ private GetPhotosTask(
         @Nullable String after,
         @Nullable String groupName,
         @Nullable ReadableArray mimeTypes,
-        Callback success,
-        Callback error) {
+        Promise promise) {
       super(context);
       mContext = context;
       mFirst = first;
       mAfter = after;
       mGroupName = groupName;
       mMimeTypes = mimeTypes;
-      mSuccess = success;
-      mError = error;
+      mPromise = promise;
     }
 
     @Override
@@ -309,18 +302,21 @@ protected void doInBackgroundGuarded(Void... params) {
             Images.Media.DATE_TAKEN + " DESC, " + Images.Media.DATE_MODIFIED + " DESC LIMIT " +
                 (mFirst + 1)); // set LIMIT to first + 1 so that we know how to populate page_info
         if (photos == null) {
-          mError.invoke("Could not get photos");
+          mPromise.reject(ERROR_UNABLE_TO_LOAD, "Could not get photos", null);
         } else {
           try {
             putEdges(resolver, photos, response, mFirst);
             putPageInfo(photos, response, mFirst);
           } finally {
             photos.close();
-            mSuccess.invoke(response);
+            mPromise.resolve(response);
           }
         }
       } catch (SecurityException e) {
-        mError.invoke("Could not get photos: need READ_EXTERNAL_STORAGE permission");
+        mPromise.reject(
+            ERROR_UNABLE_TO_LOAD_PERMISSION,
+            "Could not get photos: need READ_EXTERNAL_STORAGE permission",
+            e);
       }
     }
   }

From 5d9163b87d288194fc910a9e0e8aeecc513717a3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Thu, 21 Jan 2016 08:15:19 -0800
Subject: [PATCH 0825/1411] Improve error message

Summary:
There's a long standing issue on open source (https://github.com/facebook/react-native/issues/4968). Until someone gets some free bandwidth to fix it lets at the very least improve the error message to guide users to the issue and suggest workarounds.

public

Reviewed By: mkonicek

Differential Revision: D2849051

fb-gh-sync-id: ef7913442ceabcab2076141bd13ab1ceeb529759
---
 .../DependencyGraph/ResolutionRequest.js                  | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
index 50a590256bb1..65742f1af91c 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
@@ -372,7 +372,13 @@ class ResolutionRequest {
         throw new UnableToResolveError(
           fromModule,
           toModule,
-          `Invalid directory ${potentialDirPath}`,
+`Invalid directory ${potentialDirPath}
+
+This might related to https://github.com/facebook/react-native/issues/4968
+To resolve try the following:
+  1. Clear watchman watches: \`watchman watch-del-all\`.
+  2. Delete the \`node_modules\` folder: \`rm -rf node_modules && npm install\`.
+  3. Reset packager cache: \`rm -fr $TMPDIR/react-*\` or \`npm start -- --reset-cache\`.`,
         );
       }
 

From edb523c6d76bbca1709e3a8fd78c0744cff5c750 Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Thu, 21 Jan 2016 08:22:44 -0800
Subject: [PATCH 0826/1411] adjust getSize so that its doc can be shown on the
 page

Summary: Closes https://github.com/facebook/react-native/pull/5426

Reviewed By: svcscm

Differential Revision: D2848229

Pulled By: nicklockwood

fb-gh-sync-id: d1cc28af889c3b1e26a098044e85e0b10032a776
---
 Libraries/Image/Image.ios.js | 44 ++++++++++++++++++------------------
 1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/Libraries/Image/Image.ios.js b/Libraries/Image/Image.ios.js
index e48b25baf7a8..970ef172cdd9 100644
--- a/Libraries/Image/Image.ios.js
+++ b/Libraries/Image/Image.ios.js
@@ -155,6 +155,28 @@ var Image = React.createClass({
 
   statics: {
     resizeMode: ImageResizeMode,
+    /**
+     * Retrieve the width and height (in pixels) of an image prior to displaying it.
+     * This method can fail if the image cannot be found, or fails to download.
+     *
+     * In order to retrieve the image dimensions, the image may first need to be
+     * loaded or downloaded, after which it will be cached. This means that in
+     * principle you could use this method to preload images, however it is not
+     * optimized for that purpose, and may in future be implemented in a way that
+     * does not fully load/download the image data. A proper, supported way to
+     * preload images will be provided as a separate API.
+     *
+     * @platform ios
+     */
+    getSize: function(
+      uri: string,
+      success: (width: number, height: number) => void,
+      failure: (error: any) => void,
+    ) {
+      ImageViewManager.getSize(uri, success, failure || function() {
+        console.warn('Failed to get size for image: ' + uri);
+      });
+    }
   },
 
   mixins: [NativeMethodsMixin],
@@ -214,27 +236,5 @@ var RCTImageView = requireNativeComponent('RCTImageView', Image);
 var RCTNetworkImageView = NetworkImageViewManager ? requireNativeComponent('RCTNetworkImageView', Image) : RCTImageView;
 var RCTVirtualImage = requireNativeComponent('RCTVirtualImage', Image);
 
-/**
- * Retrieve the width and height (in pixels) of an image prior to displaying it.
- * This method can fail if the image cannot be found, or fails to download.
- *
- * In order to retrieve the image dimensions, the image may first need to be
- * loaded or downloaded, after which it will be cached. This means that in
- * principle you could use this method to preload images, however it is not
- * optimized for that purpose, and may in future be implemented in a way that
- * does not fully load/download the image data. A proper, supported way to
- * preload images will be provided as a separate API.
- *
- * @platform ios
- */
-Image.getSize = function(
-  uri: string,
-  success: (width: number, height: number) => void,
-  failure: (error: any) => void,
-) {
-  ImageViewManager.getSize(uri, success, failure || function() {
-    console.warn('Failed to get size for image: ' + uri);
-  });
-};
 
 module.exports = Image;

From c888e6583f0bd64516c23945ff6a740615b10279 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Thu, 21 Jan 2016 09:09:52 -0800
Subject: [PATCH 0827/1411] Unit test `worker.js`

Summary:
public

We had a bug a few weeks ago which caused transform errors not to be shown properly. The problem was on this piece of code, so lets unit test it.

Reviewed By: davidaurelio

Differential Revision: D2849990

fb-gh-sync-id: 9f6bb8a8b7d59bbaa3577c29cee37fb23a50d66f
---
 .../JSTransformer/__tests__/worker-test.js    | 109 ++++++++++++++++++
 1 file changed, 109 insertions(+)
 create mode 100644 packager/react-packager/src/JSTransformer/__tests__/worker-test.js

diff --git a/packager/react-packager/src/JSTransformer/__tests__/worker-test.js b/packager/react-packager/src/JSTransformer/__tests__/worker-test.js
new file mode 100644
index 000000000000..fdb67d9d464d
--- /dev/null
+++ b/packager/react-packager/src/JSTransformer/__tests__/worker-test.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.
+ */
+'use strict';
+
+jest.autoMockOff();
+
+jest.mock('babel-core');
+
+const worker = require('../worker');
+const babel = require('babel-core');
+
+const code = 'code';
+
+describe('Resolver', function() {
+  beforeEach(() => {
+    babel.transform.mockImpl((source, options) => source);
+  });
+
+  describe('when no external transform is provided', () => {
+    it('should invoke internal transform if available', () => {
+      transform({
+        sourceCode: 'code',
+        filename: 'test',
+        options: options({opts: {}, internalTransformsEnabled: true}),
+      });
+      expect(babel.transform.mock.calls.length).toBe(1);
+    });
+
+    it('should not invoke internal transform if unavailable', () => {
+      transform({
+        sourceCode: 'code',
+        filename: 'test',
+        options: options({opts: {}, internalTransformsEnabled: false}),
+      });
+      expect(babel.transform.mock.calls.length).toBe(0);
+    });
+  });
+
+  describe('when external transform is provided', () => {
+    it('should invoke both transformers if internal is available', () => {
+      transform({
+        sourceCode: code,
+        filename: 'test',
+        options: options({
+          opts: {
+            externalTransformModulePath: require.resolve(
+              '../../../../transformer.js'
+            ),
+          },
+          internalTransformsEnabled: true,
+        }),
+      });
+      expect(babel.transform.mock.calls.length).toBe(2);
+    });
+
+    it('should invoke only external transformer if internal is not available', () => {
+      transform({
+        sourceCode: 'code',
+        filename: 'test',
+        options: options({
+          opts: {
+            externalTransformModulePath: require.resolve(
+              '../../../../transformer.js'
+            ),
+          },
+          internalTransformsEnabled: false,
+        }),
+      });
+      expect(babel.transform.mock.calls.length).toBe(1);
+    });
+
+    it('should pipe errors through transform pipeline', () => {
+      const error = new Error('transform error');
+      babel.transform.mockImpl((source, options) => {
+        throw error;
+      });
+
+      const callback = transform({
+        sourceCode: 'code',
+        filename: 'test',
+        options: options({
+          opts: {
+            externalTransformModulePath: require.resolve(
+              '../../../../transformer.js'
+            ),
+          },
+          internalTransformsEnabled: true,
+        }),
+      });
+      expect(callback.mock.calls[0][0]).toBe(error);
+    });
+  });
+});
+
+function transform(data) {
+  const callback = jest.genMockFunction();
+  worker(data, callback);
+  return callback;
+}
+
+function options({opts, internalTransformsEnabled}) {
+  return Object.assign(opts, {hot: internalTransformsEnabled});
+}

From 747be0bf5cd1f9953312c40e3099b5eb0a58de08 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Thu, 21 Jan 2016 09:48:47 -0800
Subject: [PATCH 0828/1411] Change the js signature to be Promise based and
 dynamically detect it used as a callback

Summary:
Making the default people see when they look at the module the Promise based version

public

Reviewed By: davidaurelio

Differential Revision: D2850048

fb-gh-sync-id: e0815983ed798c202047cb071e65ce63a52fd1af
---
 Examples/UIExplorer/ClipboardExample.js     | 3 ++-
 Libraries/Components/Clipboard/Clipboard.js | 6 +++---
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/Examples/UIExplorer/ClipboardExample.js b/Examples/UIExplorer/ClipboardExample.js
index 0adfdd6f59da..fa2814a2a7d8 100644
--- a/Examples/UIExplorer/ClipboardExample.js
+++ b/Examples/UIExplorer/ClipboardExample.js
@@ -28,6 +28,7 @@ var ClipboardExample = React.createClass({
       content: 'Content will appear here'
     };
   },
+
   async _setClipboardContent(){
     Clipboard.setString('Hello World');
     try {
@@ -36,8 +37,8 @@ var ClipboardExample = React.createClass({
     } catch (e) {
       this.setState({content:e.message});
     }
-
   },
+
   render() {
     return (
       <View>
diff --git a/Libraries/Components/Clipboard/Clipboard.js b/Libraries/Components/Clipboard/Clipboard.js
index 0abc570109d3..9b3ef5950735 100644
--- a/Libraries/Components/Clipboard/Clipboard.js
+++ b/Libraries/Components/Clipboard/Clipboard.js
@@ -23,10 +23,10 @@ module.exports = {
    *   var content = await Clipboard.getString();
    * }
    * ```
-   * @param this parameter is deprecated. callback is function with one argument of string type
    */
-  getString(callback) {
-    if (callback) {
+  getString() {
+    if (arguments.length > 0) {
+        let callback = arguments[0];
         console.warn('Clipboard.getString(callback) is deprecated. Use the returned Promise instead');
         Clipboard.getString().then(callback);
         return;

From 4362e98170147a4b4a347cf4a00f7d71d4d03d9e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Thu, 21 Jan 2016 09:51:18 -0800
Subject: [PATCH 0829/1411] Unit test reloading when hot loading is enabled

Reviewed By: sahrens

Differential Revision: D2824276

fb-gh-sync-id: a81acd20eb5b7d3da61becac00e4bdbea6b61a2f
---
 .../src/Server/__tests__/Server-test.js          | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/packager/react-packager/src/Server/__tests__/Server-test.js b/packager/react-packager/src/Server/__tests__/Server-test.js
index 107f275034f4..a21462cac7ba 100644
--- a/packager/react-packager/src/Server/__tests__/Server-test.js
+++ b/packager/react-packager/src/Server/__tests__/Server-test.js
@@ -165,6 +165,18 @@ describe('processRequest', () => {
     });
 
     it('rebuilds the bundles that contain a file when that file is changed', () => {
+      testChangingFileWith(() => new Server(options));
+    });
+
+    it('rebuilds the bundles that contain a file when that file is changed, even when hot loading is enabled', () => {
+      testChangingFileWith(() => {
+        const server = new Server(options);
+        server.setHMRFileChangeListener(() => Promise.resolve());
+        return server;
+      });
+    });
+
+    function testChangingFileWith(createServer) {
       const bundleFunc = jest.genMockFunction();
       bundleFunc
         .mockReturnValueOnce(
@@ -182,7 +194,7 @@ describe('processRequest', () => {
 
       Bundler.prototype.bundle = bundleFunc;
 
-      server = new Server(options);
+      server = createServer();
 
       requestHandler = server.processRequest.bind(server);
 
@@ -205,7 +217,7 @@ describe('processRequest', () => {
           expect(response).toEqual('this is the rebuilt source')
         );
       jest.runAllTicks();
-    });
+    }
   });
 
   describe('/onchange endpoint', () => {

From 2902701566b020c7269fa0bbea96cd6dd2287001 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Thu, 21 Jan 2016 10:25:29 -0800
Subject: [PATCH 0830/1411] Remove now unnecessary tweaking of global
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Summary:
public

When we were debugging in the main window JS context in Chrome, the global environment had to be tweaked so that DOM features wouldn’t be detected.

Since we switched to debugging within a web worker, we don’t need to do this tweaks any more.

Reviewed By: bestander

Differential Revision: D2850239

fb-gh-sync-id: 886f2f7ac5c579c3fd4a424d5341bc6bc0432c0d
---
 .../JavaScriptAppEngine/polyfills/document.js | 30 -------------------
 local-cli/server/runServer.js                 |  5 ----
 2 files changed, 35 deletions(-)
 delete mode 100644 Libraries/JavaScriptAppEngine/polyfills/document.js

diff --git a/Libraries/JavaScriptAppEngine/polyfills/document.js b/Libraries/JavaScriptAppEngine/polyfills/document.js
deleted file mode 100644
index bff669cce915..000000000000
--- a/Libraries/JavaScriptAppEngine/polyfills/document.js
+++ /dev/null
@@ -1,30 +0,0 @@
-/* eslint strict: 0 */
-
-// TODO: Remove document polyfill now that chrome debugging is in a web worker.
-
-// The browser defines Text and Image globals by default. If you forget to
-// require them, then the error message is very confusing.
-function getInvalidGlobalUseError(name) {
-  return new Error(
-    'You are trying to render the global ' + name + ' variable as a ' +
-    'React element. You probably forgot to require ' + name + '.'
-  );
-}
-global.Text = {
-  get defaultProps() {
-    throw getInvalidGlobalUseError('Text');
-  }
-};
-global.Image = {
-  get defaultProps() {
-    throw getInvalidGlobalUseError('Image');
-  }
-};
-// Force `ExecutionEnvironment.canUseDOM` to be false.
-if (global.document) {
-  global.document.createElement = null;
-}
-
-// There is no DOM so MutationObserver doesn't make sense. It is used
-// as feature detection in Bluebird Promise implementation
-global.MutationObserver = undefined;
diff --git a/local-cli/server/runServer.js b/local-cli/server/runServer.js
index 7d7463a06223..001b9c6878d2 100644
--- a/local-cli/server/runServer.js
+++ b/local-cli/server/runServer.js
@@ -79,11 +79,6 @@ function getPackagerServer(args, config) {
     assetRoots: args.assetRoots,
     assetExts: ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'webp'],
     resetCache: args.resetCache || args['reset-cache'],
-    polyfillModuleNames: [
-      require.resolve(
-        '../../Libraries/JavaScriptAppEngine/polyfills/document.js'
-      ),
-    ],
     verbose: args.verbose,
   });
 }

From cb4fca3590cf887e8d246bdbc1ceef196617f510 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Thu, 21 Jan 2016 10:36:50 -0800
Subject: [PATCH 0831/1411] Use numeric identifiers when building a bundle
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Summary:
public

Since the combination of node and haste modules (and modules that can be required as both node and haste module) can lead to situations where it’s impossible to decide an unambiguous module identifier, this diff switches all module ids to integers. Each integer maps to an absolute path to a JS file on disk.

We also had a problem, where haste modules outside and inside node_modules could end up with the same module identifier.

This problem has not manifested yet, because the last definition of a module wins. It becomes a problem when writing file-based unbundle modules to disk: the same file might be written to concurrently, leading to invalid code.

Using indexed modules will also help indexed file unbundles, as we can encode module IDs as integers rather than scanning string IDs.

Reviewed By: martinbigio

Differential Revision: D2842418

fb-gh-sync-id: 97addd28e964ac5f2b5081dcd3f36124d2864df8
---
 Libraries/Utilities/Systrace.js               |   7 +
 packager/react-packager/src/Bundler/Bundle.js |   6 +-
 .../src/Bundler/__tests__/Bundler-test.js     |  28 +-
 packager/react-packager/src/Bundler/index.js  |  50 +-
 .../BundlesLayoutIntegration-test.js          |   1 +
 .../src/DependencyResolver/AssetModule.js     |   8 +-
 .../DependencyGraph/ResolutionResponse.js     |   5 +
 .../__tests__/DependencyGraph-test.js         |  18 +-
 .../DependencyResolver/lib/replacePatterns.js |   8 +-
 .../src/Resolver/__tests__/Resolver-test.js   | 442 ++----------------
 packager/react-packager/src/Resolver/index.js |  35 +-
 .../src/Resolver/polyfills/require.js         |  27 +-
 12 files changed, 179 insertions(+), 456 deletions(-)

diff --git a/Libraries/Utilities/Systrace.js b/Libraries/Utilities/Systrace.js
index 0e11e8942bf6..a5d708dc3497 100644
--- a/Libraries/Utilities/Systrace.js
+++ b/Libraries/Utilities/Systrace.js
@@ -202,4 +202,11 @@ var Systrace = {
 
 Systrace.setEnabled(global.__RCTProfileIsProfiling || false);
 
+if (__DEV__) {
+  // This is needed, because require callis in polyfills are not processed as
+  // other files. Therefore, calls to `require('moduleId')` are not replaced
+  // with numeric IDs
+  // TODO(davidaurelio) Scan polyfills for dependencies, too (t9759686)
+  require.Systrace = Systrace;
+}
 module.exports = Systrace;
diff --git a/packager/react-packager/src/Bundler/Bundle.js b/packager/react-packager/src/Bundler/Bundle.js
index 04a2e1ae6a55..e457e203f21a 100644
--- a/packager/react-packager/src/Bundler/Bundle.js
+++ b/packager/react-packager/src/Bundler/Bundle.js
@@ -40,10 +40,10 @@ class Bundle extends BundleBase {
       response,
       module,
       transformed.code
-    ).then(({code, name}) => {
+    ).then(({code, id}) => {
       const moduleTransport = new ModuleTransport({
         code,
-        name,
+        name: id,
         map: transformed.map,
         sourceCode: transformed.sourceCode,
         sourcePath: transformed.sourcePath,
@@ -75,7 +75,7 @@ class Bundle extends BundleBase {
   }
 
   _addRequireCall(moduleId) {
-    const code = ';require("' + moduleId + '");';
+    const code = `;require(${JSON.stringify(moduleId)});`;
     const name = 'require-' + moduleId;
     super.addModule(new ModuleTransport({
       name,
diff --git a/packager/react-packager/src/Bundler/__tests__/Bundler-test.js b/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
index 467cf90d69ce..a85695be7492 100644
--- a/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
+++ b/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
@@ -10,16 +10,23 @@
 
 jest
   .setMock('worker-farm', () => () => undefined)
+  .dontMock('absolute-path')
   .dontMock('underscore')
   .dontMock('../../lib/ModuleTransport')
+  .dontMock('../../DependencyResolver/AssetModule')
+  .dontMock('../../DependencyResolver/Module')
+  .dontMock('../../DependencyResolver/lib/getAssetDataFromName')
   .setMock('uglify-js')
   .dontMock('../');
 
 jest.mock('fs');
 
+var AssetModule = require('../../DependencyResolver/AssetModule');
 var Bundler = require('../');
 var JSTransformer = require('../../JSTransformer');
+var Module = require('../../DependencyResolver/Module');
 var Resolver = require('../../Resolver');
+
 var sizeOf = require('image-size');
 var fs = require('fs');
 
@@ -34,6 +41,14 @@ describe('Bundler', function() {
     isJSON,
     resolution,
   }) {
+    if (isAsset) {
+      const module = new AssetModule({
+        file: path,
+        cache: {get: () => Promise.resolve(path)}
+      });
+      module.getName = () => Promise.resolve(id);
+      return module;
+    }
     return {
       path,
       resolution,
@@ -51,6 +66,8 @@ describe('Bundler', function() {
   var bundler;
   var assetServer;
   var modules;
+  const width = 50;
+  const height = 100;
 
   beforeEach(function() {
     getDependencies = jest.genMockFn();
@@ -108,10 +125,12 @@ describe('Bundler', function() {
       }),
     ];
 
+    const mainModule = new Module({file: '/root/foo'});
     getDependencies.mockImpl(function() {
       return Promise.resolve({
         mainModuleId: 'foo',
-        dependencies: modules
+        dependencies: modules,
+        getMainModule: () => mainModule,
       });
     });
 
@@ -132,12 +151,13 @@ describe('Bundler', function() {
     wrapModule.mockImpl(function(response, module, code) {
       return module.getName().then(name => ({
         name,
+        id: name,
         code: 'lol ' + code + ' lol'
       }));
     });
 
     sizeOf.mockImpl(function(path, cb) {
-      cb(null, { width: 50, height: 100 });
+      cb(null, { width, height });
     });
   });
 
@@ -187,8 +207,8 @@ describe('Bundler', function() {
           __packager_asset: true,
           fileSystemLocation: '/root/img',
           httpServerLocation: '/assets/img',
-          width: 25,
-          height: 50,
+          width,
+          height,
           scales: [1, 2, 3],
           files: [
             '/root/img/img.png',
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index 1cc28f23d805..9b7bb1fa30d2 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -102,6 +102,8 @@ class Bundler {
       mtime = '';
     }
 
+    this._getModuleId = createModuleIdGetter();
+
     this._cache = new Cache({
       resetCache: opts.resetCache,
       cacheKey: [
@@ -122,6 +124,7 @@ class Bundler {
       fileWatcher: opts.fileWatcher,
       assetExts: opts.assetExts,
       cache: this._cache,
+      getModuleId: this._getModuleId,
     });
 
     this._bundlesLayout = new BundlesLayout({
@@ -187,9 +190,19 @@ class Bundler {
     const findEventId = Activity.startEvent('find dependencies');
     let transformEventId;
 
+    if (isDev) {
+      // `require` calls int  the require polyfill itself are not analyzed and
+      // replaced so that they use numeric module IDs. Therefore, we include
+      // the Systrace module before any other module, and it will set itself
+      // as property on the require function.
+      // TODO(davidaurelio) Scan polyfills for dependencies, too (t9759686)
+      runBeforeMainModule = ['Systrace'].concat(runBeforeMainModule);
+    }
+
+    const modulesByName = Object.create(null);
     return this.getDependencies(entryFile, isDev, platform).then((response) => {
       Activity.endEvent(findEventId);
-      bundle.setMainModuleId(response.mainModuleId);
+      bundle.setMainModuleId(this._getModuleId(response.getMainModule()));
       transformEventId = Activity.startEvent('transform');
 
       const moduleSystemDeps = includeSystemDependencies
@@ -225,6 +238,11 @@ class Bundler {
               platform,
               hot,
             ).then(transformed => {
+              return module.getName().then(name => {
+                modulesByName[name] = module;
+                return transformed;
+              });
+            }).then(transformed => {
               if (bar) {
                 bar.tick();
               }
@@ -248,7 +266,11 @@ class Bundler {
       ));
     }).then(() => {
       Activity.endEvent(transformEventId);
-      bundle.finalize({runBeforeMainModule, runMainModule});
+      const runBeforeIds = runBeforeMainModule
+        .map(name => modulesByName[name])
+        .filter(Boolean)
+        .map(this._getModuleId, this);
+      bundle.finalize({runBeforeMainModule: runBeforeIds, runMainModule});
       return bundle;
     });
   }
@@ -462,8 +484,7 @@ class Bundler {
         type: assetData.type,
       };
 
-      const ASSET_TEMPLATE = 'module.exports = require("AssetRegistry").registerAsset(%json);';
-      const code = ASSET_TEMPLATE.replace('%json', JSON.stringify(asset));
+      const code = module.getCode(asset);
 
       return {asset, code};
     });
@@ -522,12 +543,21 @@ function verifyRootExists(root) {
   assert(fs.statSync(root).isDirectory(), 'Root has to be a valid directory');
 }
 
-class DummyCache {
-  get(filepath, field, loaderCb) {
-    return loaderCb();
-  }
 
-  end(){}
-  invalidate(filepath){}
+function createModuleIdGetter() {
+  const fileToIdMap = Object.create(null);
+  let nextId = 0;
+  return (
+    ({path}) => {
+      if (!(path in fileToIdMap)) {
+        // can't be a number for now, since we also replace in import / export
+        // we can change that when we eventually change to analyzing dependencies
+        // on transformed modules
+        fileToIdMap[path] = String(nextId++);
+      }
+      return fileToIdMap[path];
+    }
+  );
 }
+
 module.exports = Bundler;
diff --git a/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js b/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js
index fe4481a0955e..b18b424f54c2 100644
--- a/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js
+++ b/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js
@@ -55,6 +55,7 @@ describe('BundlesLayout', () => {
         cache: new Cache(),
         assetExts: ['js', 'png'],
         assetRoots: ['/root'],
+        getModuleId: () => {},
       });
 
       return new BundlesLayout({
diff --git a/packager/react-packager/src/DependencyResolver/AssetModule.js b/packager/react-packager/src/DependencyResolver/AssetModule.js
index f5555facd744..68a92ee24692 100644
--- a/packager/react-packager/src/DependencyResolver/AssetModule.js
+++ b/packager/react-packager/src/DependencyResolver/AssetModule.js
@@ -18,13 +18,19 @@ class AssetModule extends Module {
   }
 
   getDependencies() {
-    return Promise.resolve([]);
+    return Promise.resolve(['AssetRegistry']);
   }
 
   getAsyncDependencies() {
     return Promise.resolve([]);
   }
 
+  getCode(assetData) {
+    return `module.exports = require('AssetRegistry').registerAsset(${
+      JSON.stringify(assetData)
+    });`;
+  }
+
   read() {
     return Promise.resolve({});
   }
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js
index 7fbafde84982..3c1656c5a0ec 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js
@@ -39,6 +39,11 @@ class ResolutionResponse {
     });
   }
 
+  getMainModule() {
+    this._assertFinalized();
+    return this._mainModule;
+  }
+
   pushDependency(module) {
     this._assertNotFinalized();
     if (this.dependencies.length === 0) {
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
index b1126a4cc3e3..a858f1d2844f 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
@@ -374,7 +374,7 @@ describe('DependencyGraph', function() {
             {
               id: 'rootPackage/imgs/a.png',
               path: '/root/imgs/a.png',
-              dependencies: [],
+              dependencies: ['AssetRegistry'],
               isAsset: true,
               resolution: 1,
               isAsset_DEPRECATED: false,
@@ -434,7 +434,7 @@ describe('DependencyGraph', function() {
               id: 'rootPackage/imgs/a.png',
               path: '/root/imgs/a@1.5x.png',
               resolution: 1.5,
-              dependencies: [],
+              dependencies: ['AssetRegistry'],
               isAsset: true,
               isAsset_DEPRECATED: false,
               isJSON: false,
@@ -444,7 +444,7 @@ describe('DependencyGraph', function() {
               id: 'rootPackage/imgs/b.png',
               path: '/root/imgs/b@.7x.png',
               resolution: 0.7,
-              dependencies: [],
+              dependencies: ['AssetRegistry'],
               isAsset: true,
               isAsset_DEPRECATED: false,
               isJSON: false,
@@ -454,7 +454,7 @@ describe('DependencyGraph', function() {
               id: 'rootPackage/imgs/c.png',
               path: '/root/imgs/c.png',
               resolution: 1,
-              dependencies: [],
+              dependencies: ['AssetRegistry'],
               isAsset: true,
               isAsset_DEPRECATED: false,
               isJSON: false,
@@ -514,7 +514,7 @@ describe('DependencyGraph', function() {
               id: 'rootPackage/imgs/a.png',
               path: '/root/imgs/a@1.5x.ios.png',
               resolution: 1.5,
-              dependencies: [],
+              dependencies: ['AssetRegistry'],
               isAsset: true,
               isAsset_DEPRECATED: false,
               isJSON: false,
@@ -524,7 +524,7 @@ describe('DependencyGraph', function() {
               id: 'rootPackage/imgs/b.png',
               path: '/root/imgs/b@.7x.ios.png',
               resolution: 0.7,
-              dependencies: [],
+              dependencies: ['AssetRegistry'],
               isAsset: true,
               isAsset_DEPRECATED: false,
               isJSON: false,
@@ -534,7 +534,7 @@ describe('DependencyGraph', function() {
               id: 'rootPackage/imgs/c.png',
               path: '/root/imgs/c.ios.png',
               resolution: 1,
-              dependencies: [],
+              dependencies: ['AssetRegistry'],
               isAsset: true,
               isAsset_DEPRECATED: false,
               isJSON: false,
@@ -585,7 +585,7 @@ describe('DependencyGraph', function() {
             {
               id: 'rootPackage/imgs/a.png',
               path: '/root/imgs/a.png',
-              dependencies: [],
+              dependencies: ['AssetRegistry'],
               isAsset: true,
               resolution: 1,
               isAsset_DEPRECATED: false,
@@ -3367,7 +3367,7 @@ describe('DependencyGraph', function() {
               {
                 id: 'aPackage/foo.png',
                 path: '/root/foo.png',
-                dependencies: [],
+                dependencies: ['AssetRegistry'],
                 isAsset: true,
                 resolution: 1,
                 isAsset_DEPRECATED: false,
diff --git a/packager/react-packager/src/DependencyResolver/lib/replacePatterns.js b/packager/react-packager/src/DependencyResolver/lib/replacePatterns.js
index a4e563d2c67c..3bd6ef45b01e 100644
--- a/packager/react-packager/src/DependencyResolver/lib/replacePatterns.js
+++ b/packager/react-packager/src/DependencyResolver/lib/replacePatterns.js
@@ -9,7 +9,7 @@
 
 'use strict';
 
-exports.IMPORT_RE = /(\bimport\s+(?:[^'"]+\s+from\s+)??)(['"])([^'"]+)(\2)/g;
-exports.EXPORT_RE = /(\bexport\s+(?:[^'"]+\s+from\s+)??)(['"])([^'"]+)(\2)/g;
-exports.REQUIRE_RE = /(\brequire\s*?\(\s*?)(['"])([^'"]+)(\2\s*?\))/g;
-exports.SYSTEM_IMPORT_RE = /(\bSystem\.import\s*?\(\s*?)(['"])([^'"]+)(\2\s*?\))/g;
+exports.IMPORT_RE = /(\bimport\s*(?:[\s{][^'"]+[\s}]from\s*)??)(['"])([^'"]+)\2()/g;
+exports.EXPORT_RE = /(\bexport\s*(?:[\s{][^'"]+[\s}]from\s*)??)(['"])([^'"]+)\2()/g;
+exports.REQUIRE_RE = /(\brequire\s*?\(\s*?)(['"])([^'"]+)\2(\s*?\))/g;
+exports.SYSTEM_IMPORT_RE = /(\bSystem\.import\s*?\(\s*?)(['"])([^'"]+)\2(\s*?\))/g;
diff --git a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
index 825399b4a023..6093cf423092 100644
--- a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
+++ b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
@@ -35,6 +35,12 @@ describe('Resolver', function() {
     });
   });
 
+  const modulesWithIds = [];
+  function getModuleId(module) {
+    const index = modulesWithIds.indexOf(module);
+    return String(index !== -1 ? index + 1 : modulesWithIds.push(module));
+  }
+
   class ResolutionResponseMock {
     constructor({dependencies, mainModuleId, asyncDependencies}) {
       this.dependencies = dependencies;
@@ -73,6 +79,7 @@ describe('Resolver', function() {
 
       var depResolver = new Resolver({
         projectRoot: '/root',
+        getModuleId,
       });
 
       DependencyGraph.prototype.getDependencies.mockImpl(function() {
@@ -160,6 +167,7 @@ describe('Resolver', function() {
 
       var depResolver = new Resolver({
         projectRoot: '/root',
+        getModuleId,
       });
 
       DependencyGraph.prototype.getDependencies.mockImpl(function() {
@@ -187,6 +195,7 @@ describe('Resolver', function() {
       var depResolver = new Resolver({
         projectRoot: '/root',
         polyfillModuleNames: ['some module'],
+        getModuleId,
       });
 
       DependencyGraph.prototype.getDependencies.mockImpl(function() {
@@ -223,12 +232,13 @@ describe('Resolver', function() {
     pit('should resolve modules', function() {
       var depResolver = new Resolver({
         projectRoot: '/root',
+        getModuleId,
       });
 
-      var dependencies = ['x', 'y', 'z', 'a', 'b'];
+      const magicJoiner = '\n\n\n';
 
       /*eslint-disable */
-      var code = [
+      const testCases = [
         // single line import
         "import'x';",
         "import 'x';",
@@ -303,6 +313,7 @@ describe('Resolver', function() {
         'import * as All from "x";',
         'import { } from "x";',
         'import { Foo } from "x";',
+        'import{Foo}from"x";',
         'import { Foo, } from "x";',
         'import { Foo as Bar } from "x";',
         'import { Foo as Bar, } from "x";',
@@ -428,6 +439,7 @@ describe('Resolver', function() {
         "export { } from 'x';",
         "export {Foo} from 'x';",
         "export { Foo } from 'x';",
+        "export{Foo}from'x';",
         "export { Foo, } from 'x';",
         "export {Foo as Bar} from 'x';",
         "export { Foo as Bar } from 'x';",
@@ -613,8 +625,9 @@ describe('Resolver', function() {
         'require( \'z\' )',
         'require( "a")',
         'require("b" )',
-      ].join('\n');
+      ]
       /*eslint-disable */
+      const code = testCases.join(magicJoiner);
 
       const module = createModule('test module', ['x', 'y']);
 
@@ -624,11 +637,21 @@ describe('Resolver', function() {
         asyncDependencies: [],
       });
 
-      resolutionResponse.getResolvedDependencyPairs = (module) => {
-        return [
-          ['x', createModule('changed')],
-          ['y', createModule('Y')],
-        ];
+      const pairs = [
+        ['x', createModule('changed')],
+        ['y', createModule('Y')],
+      ];
+      resolutionResponse.getResolvedDependencyPairs = () => pairs;
+
+      function makeExpected(code) {
+        return pairs
+          .reduce((code, [id, module]) =>
+            code.replace(
+              RegExp(`(['"])${id}\\1`),
+              (_, quot) => `${quot}${getModuleId(module)}${quot} /* ${id} */`
+            ),
+            code
+          );
       }
 
       return depResolver.wrapModule(
@@ -637,395 +660,20 @@ describe('Resolver', function() {
         code
       ).then(processedCode => {
         expect(processedCode.name).toEqual('test module');
-        expect(processedCode.code).toEqual([
-          '__d(\'test module\',function(global, require,' +
-            ' module, exports) {  ' +
-            // single line import
-            "import'x';",
-          "import 'changed';",
-          "import 'changed' ;",
-          "import Default from 'changed';",
-          "import * as All from 'changed';",
-          "import {} from 'changed';",
-          "import { } from 'changed';",
-          "import {Foo} from 'changed';",
-          "import { Foo } from 'changed';",
-          "import { Foo, } from 'changed';",
-          "import {Foo as Bar} from 'changed';",
-          "import { Foo as Bar } from 'changed';",
-          "import { Foo as Bar, } from 'changed';",
-          "import { Foo, Bar } from 'changed';",
-          "import { Foo, Bar, } from 'changed';",
-          "import { Foo as Bar, Baz } from 'changed';",
-          "import { Foo as Bar, Baz, } from 'changed';",
-          "import { Foo, Bar as Baz } from 'changed';",
-          "import { Foo, Bar as Baz, } from 'changed';",
-          "import { Foo as Bar, Baz as Qux } from 'changed';",
-          "import { Foo as Bar, Baz as Qux, } from 'changed';",
-          "import { Foo, Bar, Baz } from 'changed';",
-          "import { Foo, Bar, Baz, } from 'changed';",
-          "import { Foo as Bar, Baz, Qux } from 'changed';",
-          "import { Foo as Bar, Baz, Qux, } from 'changed';",
-          "import { Foo, Bar as Baz, Qux } from 'changed';",
-          "import { Foo, Bar as Baz, Qux, } from 'changed';",
-          "import { Foo, Bar, Baz as Qux } from 'changed';",
-          "import { Foo, Bar, Baz as Qux, } from 'changed';",
-          "import { Foo as Bar, Baz as Qux, Norf } from 'changed';",
-          "import { Foo as Bar, Baz as Qux, Norf, } from 'changed';",
-          "import { Foo as Bar, Baz, Qux as Norf } from 'changed';",
-          "import { Foo as Bar, Baz, Qux as Norf, } from 'changed';",
-          "import { Foo, Bar as Baz, Qux as Norf } from 'changed';",
-          "import { Foo, Bar as Baz, Qux as Norf, } from 'changed';",
-          "import { Foo as Bar, Baz as Qux, Norf as Enuf } from 'changed';",
-          "import { Foo as Bar, Baz as Qux, Norf as Enuf, } from 'changed';",
-          "import Default, * as All from 'changed';",
-          "import Default, { } from 'changed';",
-          "import Default, { Foo } from 'changed';",
-          "import Default, { Foo, } from 'changed';",
-          "import Default, { Foo as Bar } from 'changed';",
-          "import Default, { Foo as Bar, } from 'changed';",
-          "import Default, { Foo, Bar } from 'changed';",
-          "import Default, { Foo, Bar, } from 'changed';",
-          "import Default, { Foo as Bar, Baz } from 'changed';",
-          "import Default, { Foo as Bar, Baz, } from 'changed';",
-          "import Default, { Foo, Bar as Baz } from 'changed';",
-          "import Default, { Foo, Bar as Baz, } from 'changed';",
-          "import Default, { Foo as Bar, Baz as Qux } from 'changed';",
-          "import Default, { Foo as Bar, Baz as Qux, } from 'changed';",
-          "import Default, { Foo, Bar, Baz } from 'changed';",
-          "import Default, { Foo, Bar, Baz, } from 'changed';",
-          "import Default, { Foo as Bar, Baz, Qux } from 'changed';",
-          "import Default, { Foo as Bar, Baz, Qux, } from 'changed';",
-          "import Default, { Foo, Bar as Baz, Qux } from 'changed';",
-          "import Default, { Foo, Bar as Baz, Qux, } from 'changed';",
-          "import Default, { Foo, Bar, Baz as Qux } from 'changed';",
-          "import Default, { Foo, Bar, Baz as Qux, } from 'changed';",
-          "import Default, { Foo as Bar, Baz as Qux, Norf } from 'changed';",
-          "import Default, { Foo as Bar, Baz as Qux, Norf, } from 'changed';",
-          "import Default, { Foo as Bar, Baz, Qux as Norf } from 'changed';",
-          "import Default, { Foo as Bar, Baz, Qux as Norf, } from 'changed';",
-          "import Default, { Foo, Bar as Baz, Qux as Norf } from 'changed';",
-          "import Default, { Foo, Bar as Baz, Qux as Norf, } from 'changed';",
-          "import Default, { Foo as Bar, Baz as Qux, Norf as NoMore } from 'changed';",
-          "import Default, { Foo as Bar, Baz as Qux, Norf as NoMore, } from 'changed';",
-          "import Default , { } from 'changed';",
-          'import "changed";',
-          'import Default from "changed";',
-          'import * as All from "changed";',
-          'import { } from "changed";',
-          'import { Foo } from "changed";',
-          'import { Foo, } from "changed";',
-          'import { Foo as Bar } from "changed";',
-          'import { Foo as Bar, } from "changed";',
-          'import { Foo, Bar } from "changed";',
-          'import { Foo, Bar, } from "changed";',
-          'import { Foo as Bar, Baz } from "changed";',
-          'import { Foo as Bar, Baz, } from "changed";',
-          'import { Foo, Bar as Baz } from "changed";',
-          'import { Foo, Bar as Baz, } from "changed";',
-          'import { Foo as Bar, Baz as Qux } from "changed";',
-          'import { Foo as Bar, Baz as Qux, } from "changed";',
-          'import { Foo, Bar, Baz } from "changed";',
-          'import { Foo, Bar, Baz, } from "changed";',
-          'import { Foo as Bar, Baz, Qux } from "changed";',
-          'import { Foo as Bar, Baz, Qux, } from "changed";',
-          'import { Foo, Bar as Baz, Qux } from "changed";',
-          'import { Foo, Bar as Baz, Qux, } from "changed";',
-          'import { Foo, Bar, Baz as Qux } from "changed";',
-          'import { Foo, Bar, Baz as Qux, } from "changed";',
-          'import { Foo as Bar, Baz as Qux, Norf } from "changed";',
-          'import { Foo as Bar, Baz as Qux, Norf, } from "changed";',
-          'import { Foo as Bar, Baz, Qux as Norf } from "changed";',
-          'import { Foo as Bar, Baz, Qux as Norf, } from "changed";',
-          'import { Foo, Bar as Baz, Qux as Norf } from "changed";',
-          'import { Foo, Bar as Baz, Qux as Norf, } from "changed";',
-          'import { Foo as Bar, Baz as Qux, Norf as NoMore } from "changed";',
-          'import { Foo as Bar, Baz as Qux, Norf as NoMore, } from "changed";',
-          'import Default, * as All from "changed";',
-          'import Default, { } from "changed";',
-          'import Default, { Foo } from "changed";',
-          'import Default, { Foo, } from "changed";',
-          'import Default, { Foo as Bar } from "changed";',
-          'import Default, { Foo as Bar, } from "changed";',
-          'import Default, { Foo, Bar } from "changed";',
-          'import Default, { Foo, Bar, } from "changed";',
-          'import Default, { Foo as Bar, Baz } from "changed";',
-          'import Default, { Foo as Bar, Baz, } from "changed";',
-          'import Default, { Foo, Bar as Baz } from "changed";',
-          'import Default, { Foo, Bar as Baz, } from "changed";',
-          'import Default, { Foo as Bar, Baz as Qux } from "changed";',
-          'import Default, { Foo as Bar, Baz as Qux, } from "changed";',
-          'import Default, { Foo, Bar, Baz } from "changed";',
-          'import Default, { Foo, Bar, Baz, } from "changed";',
-          'import Default, { Foo as Bar, Baz, Qux } from "changed";',
-          'import Default, { Foo as Bar, Baz, Qux, } from "changed";',
-          'import Default, { Foo, Bar as Baz, Qux } from "changed";',
-          'import Default, { Foo, Bar as Baz, Qux, } from "changed";',
-          'import Default, { Foo, Bar, Baz as Qux } from "changed";',
-          'import Default, { Foo, Bar, Baz as Qux, } from "changed";',
-          'import Default, { Foo as Bar, Baz as Qux, Norf } from "changed";',
-          'import Default, { Foo as Bar, Baz as Qux, Norf, } from "changed";',
-          'import Default, { Foo as Bar, Baz, Qux as Norf } from "changed";',
-          'import Default, { Foo as Bar, Baz, Qux as Norf, } from "changed";',
-          'import Default, { Foo, Bar as Baz, Qux as Norf } from "changed";',
-          'import Default, { Foo, Bar as Baz, Qux as Norf, } from "changed";',
-          'import Default, { Foo as Bar, Baz as Qux, Norf as Enuf } from "changed";',
-          'import Default, { Foo as Bar, Baz as Qux, Norf as Enuf, } from "changed";',
-          'import Default from "Y";',
-          'import * as All from \'z\';',
-          // import with support for new lines
-          "import { Foo,\n Bar }\n from 'changed';",
-          "import { \nFoo,\nBar,\n }\n from 'changed';",
-          "import { Foo as Bar,\n Baz\n }\n from 'changed';",
-          "import { \nFoo as Bar,\n Baz\n, }\n from 'changed';",
-          "import { Foo,\n Bar as Baz\n }\n from 'changed';",
-          "import { Foo,\n Bar as Baz,\n }\n from 'changed';",
-          "import { Foo as Bar,\n Baz as Qux\n }\n from 'changed';",
-          "import { Foo as Bar,\n Baz as Qux,\n }\n from 'changed';",
-          "import { Foo,\n Bar,\n Baz }\n from 'changed';",
-          "import { Foo,\n Bar,\n Baz,\n }\n from 'changed';",
-          "import { Foo as Bar,\n Baz,\n Qux\n }\n from 'changed';",
-          "import { Foo as Bar,\n Baz,\n Qux,\n }\n from 'changed';",
-          "import { Foo,\n Bar as Baz,\n Qux\n }\n from 'changed';",
-          "import { Foo,\n Bar as Baz,\n Qux,\n }\n from 'changed';",
-          "import { Foo,\n Bar,\n Baz as Qux\n }\n from 'changed';",
-          "import { Foo,\n Bar,\n Baz as Qux,\n }\n from 'changed';",
-          "import { Foo as Bar,\n Baz as Qux,\n Norf\n }\n from 'changed';",
-          "import { Foo as Bar,\n Baz as Qux,\n Norf,\n }\n from 'changed';",
-          "import { Foo as Bar,\n Baz,\n Qux as Norf\n }\n from 'changed';",
-          "import { Foo as Bar,\n Baz,\n Qux as Norf,\n }\n from 'changed';",
-          "import { Foo,\n Bar as Baz,\n Qux as Norf\n }\n from 'changed';",
-          "import { Foo,\n Bar as Baz,\n Qux as Norf,\n }\n from 'changed';",
-          "import { Foo as Bar,\n Baz as Qux,\n Norf as Enuf\n }\n from 'changed';",
-          "import { Foo as Bar,\n Baz as Qux,\n Norf as Enuf,\n }\n from 'changed';",
-          "import Default,\n * as All from 'changed';",
-          "import Default,\n { } from 'changed';",
-          "import Default,\n { Foo\n }\n from 'changed';",
-          "import Default,\n { Foo,\n }\n from 'changed';",
-          "import Default,\n { Foo as Bar\n }\n from 'changed';",
-          "import Default,\n { Foo as Bar,\n }\n from 'changed';",
-          "import Default,\n { Foo,\n Bar\n } from\n 'changed';",
-          "import Default,\n { Foo,\n Bar,\n } from\n 'changed';",
-          "import Default,\n { Foo as Bar,\n Baz\n }\n from 'changed';",
-          "import Default,\n { Foo as Bar,\n Baz,\n }\n from 'changed';",
-          "import Default,\n { Foo,\n Bar as Baz\n }\n from 'changed';",
-          "import Default,\n { Foo,\n Bar as Baz,\n }\n from 'changed';",
-          "import Default,\n { Foo as Bar,\n Baz as Qux\n }\n from 'changed';",
-          "import Default,\n { Foo as Bar,\n Baz as Qux,\n }\n from 'changed';",
-          "import Default,\n { Foo,\n Bar,\n Baz\n }\n from 'changed';",
-          "import Default,\n { Foo,\n Bar,\n Baz,\n }\n from 'changed';",
-          "import Default,\n { Foo as Bar,\n Baz,\n Qux\n }\n from 'changed';",
-          "import Default,\n { Foo as Bar,\n Baz,\n Qux,\n }\n from 'changed';",
-          "import Default,\n { Foo,\n Bar as Baz,\n Qux\n }\n from 'changed';",
-          "import Default,\n { Foo,\n Bar as Baz,\n Qux,\n }\n from 'changed';",
-          "import Default,\n { Foo,\n Bar,\n Baz as Qux\n }\n from 'changed';",
-          "import Default,\n { Foo,\n Bar,\n Baz as Qux,\n }\n from 'changed';",
-          "import Default,\n { Foo as Bar,\n Baz as Qux,\n Norf\n }\n from 'changed';",
-          "import Default,\n { Foo as Bar,\n Baz as Qux,\n Norf,\n }\n from 'changed';",
-          "import Default,\n { Foo as Bar,\n Baz,\n Qux as Norf }\n from 'changed';",
-          "import Default,\n { Foo as Bar,\n Baz,\n Qux as Norf, }\n from 'changed';",
-          "import Default,\n { Foo, Bar as Baz,\n Qux as Norf }\n from 'changed';",
-          "import Default,\n { Foo, Bar as Baz,\n Qux as Norf, }\n from 'changed';",
-          "import Default,\n { Foo as Bar,\n Baz as Qux,\n Norf as NoMore\n }\n from 'changed';",
-          "import Default,\n { Foo as Bar,\n Baz as Qux,\n Norf as NoMore,\n }\n from 'changed';",
-          "import Default\n , { } from 'changed';",
-          // single line export
-          "export'x';",
-          "export 'changed';",
-          "export 'changed' ;",
-          "export Default from 'changed';",
-          "export * as All from 'changed';",
-          "export {} from 'changed';",
-          "export { } from 'changed';",
-          "export {Foo} from 'changed';",
-          "export { Foo } from 'changed';",
-          "export { Foo, } from 'changed';",
-          "export {Foo as Bar} from 'changed';",
-          "export { Foo as Bar } from 'changed';",
-          "export { Foo as Bar, } from 'changed';",
-          "export { Foo, Bar } from 'changed';",
-          "export { Foo, Bar, } from 'changed';",
-          "export { Foo as Bar, Baz } from 'changed';",
-          "export { Foo as Bar, Baz, } from 'changed';",
-          "export { Foo, Bar as Baz } from 'changed';",
-          "export { Foo, Bar as Baz, } from 'changed';",
-          "export { Foo as Bar, Baz as Qux } from 'changed';",
-          "export { Foo as Bar, Baz as Qux, } from 'changed';",
-          "export { Foo, Bar, Baz } from 'changed';",
-          "export { Foo, Bar, Baz, } from 'changed';",
-          "export { Foo as Bar, Baz, Qux } from 'changed';",
-          "export { Foo as Bar, Baz, Qux, } from 'changed';",
-          "export { Foo, Bar as Baz, Qux } from 'changed';",
-          "export { Foo, Bar as Baz, Qux, } from 'changed';",
-          "export { Foo, Bar, Baz as Qux } from 'changed';",
-          "export { Foo, Bar, Baz as Qux, } from 'changed';",
-          "export { Foo as Bar, Baz as Qux, Norf } from 'changed';",
-          "export { Foo as Bar, Baz as Qux, Norf, } from 'changed';",
-          "export { Foo as Bar, Baz, Qux as Norf } from 'changed';",
-          "export { Foo as Bar, Baz, Qux as Norf, } from 'changed';",
-          "export { Foo, Bar as Baz, Qux as Norf } from 'changed';",
-          "export { Foo, Bar as Baz, Qux as Norf, } from 'changed';",
-          "export { Foo as Bar, Baz as Qux, Norf as Enuf } from 'changed';",
-          "export { Foo as Bar, Baz as Qux, Norf as Enuf, } from 'changed';",
-          "export Default, * as All from 'changed';",
-          "export Default, { } from 'changed';",
-          "export Default, { Foo } from 'changed';",
-          "export Default, { Foo, } from 'changed';",
-          "export Default, { Foo as Bar } from 'changed';",
-          "export Default, { Foo as Bar, } from 'changed';",
-          "export Default, { Foo, Bar } from 'changed';",
-          "export Default, { Foo, Bar, } from 'changed';",
-          "export Default, { Foo as Bar, Baz } from 'changed';",
-          "export Default, { Foo as Bar, Baz, } from 'changed';",
-          "export Default, { Foo, Bar as Baz } from 'changed';",
-          "export Default, { Foo, Bar as Baz, } from 'changed';",
-          "export Default, { Foo as Bar, Baz as Qux } from 'changed';",
-          "export Default, { Foo as Bar, Baz as Qux, } from 'changed';",
-          "export Default, { Foo, Bar, Baz } from 'changed';",
-          "export Default, { Foo, Bar, Baz, } from 'changed';",
-          "export Default, { Foo as Bar, Baz, Qux } from 'changed';",
-          "export Default, { Foo as Bar, Baz, Qux, } from 'changed';",
-          "export Default, { Foo, Bar as Baz, Qux } from 'changed';",
-          "export Default, { Foo, Bar as Baz, Qux, } from 'changed';",
-          "export Default, { Foo, Bar, Baz as Qux } from 'changed';",
-          "export Default, { Foo, Bar, Baz as Qux, } from 'changed';",
-          "export Default, { Foo as Bar, Baz as Qux, Norf } from 'changed';",
-          "export Default, { Foo as Bar, Baz as Qux, Norf, } from 'changed';",
-          "export Default, { Foo as Bar, Baz, Qux as Norf } from 'changed';",
-          "export Default, { Foo as Bar, Baz, Qux as Norf, } from 'changed';",
-          "export Default, { Foo, Bar as Baz, Qux as Norf } from 'changed';",
-          "export Default, { Foo, Bar as Baz, Qux as Norf, } from 'changed';",
-          "export Default, { Foo as Bar, Baz as Qux, Norf as NoMore } from 'changed';",
-          "export Default, { Foo as Bar, Baz as Qux, Norf as NoMore, } from 'changed';",
-          "export Default , { } from 'changed';",
-          'export "changed";',
-          'export Default from "changed";',
-          'export * as All from "changed";',
-          'export { } from "changed";',
-          'export { Foo } from "changed";',
-          'export { Foo, } from "changed";',
-          'export { Foo as Bar } from "changed";',
-          'export { Foo as Bar, } from "changed";',
-          'export { Foo, Bar } from "changed";',
-          'export { Foo, Bar, } from "changed";',
-          'export { Foo as Bar, Baz } from "changed";',
-          'export { Foo as Bar, Baz, } from "changed";',
-          'export { Foo, Bar as Baz } from "changed";',
-          'export { Foo, Bar as Baz, } from "changed";',
-          'export { Foo as Bar, Baz as Qux } from "changed";',
-          'export { Foo as Bar, Baz as Qux, } from "changed";',
-          'export { Foo, Bar, Baz } from "changed";',
-          'export { Foo, Bar, Baz, } from "changed";',
-          'export { Foo as Bar, Baz, Qux } from "changed";',
-          'export { Foo as Bar, Baz, Qux, } from "changed";',
-          'export { Foo, Bar as Baz, Qux } from "changed";',
-          'export { Foo, Bar as Baz, Qux, } from "changed";',
-          'export { Foo, Bar, Baz as Qux } from "changed";',
-          'export { Foo, Bar, Baz as Qux, } from "changed";',
-          'export { Foo as Bar, Baz as Qux, Norf } from "changed";',
-          'export { Foo as Bar, Baz as Qux, Norf, } from "changed";',
-          'export { Foo as Bar, Baz, Qux as Norf } from "changed";',
-          'export { Foo as Bar, Baz, Qux as Norf, } from "changed";',
-          'export { Foo, Bar as Baz, Qux as Norf } from "changed";',
-          'export { Foo, Bar as Baz, Qux as Norf, } from "changed";',
-          'export { Foo as Bar, Baz as Qux, Norf as NoMore } from "changed";',
-          'export { Foo as Bar, Baz as Qux, Norf as NoMore, } from "changed";',
-          'export Default, * as All from "changed";',
-          'export Default, { } from "changed";',
-          'export Default, { Foo } from "changed";',
-          'export Default, { Foo, } from "changed";',
-          'export Default, { Foo as Bar } from "changed";',
-          'export Default, { Foo as Bar, } from "changed";',
-          'export Default, { Foo, Bar } from "changed";',
-          'export Default, { Foo, Bar, } from "changed";',
-          'export Default, { Foo as Bar, Baz } from "changed";',
-          'export Default, { Foo as Bar, Baz, } from "changed";',
-          'export Default, { Foo, Bar as Baz } from "changed";',
-          'export Default, { Foo, Bar as Baz, } from "changed";',
-          'export Default, { Foo as Bar, Baz as Qux } from "changed";',
-          'export Default, { Foo as Bar, Baz as Qux, } from "changed";',
-          'export Default, { Foo, Bar, Baz } from "changed";',
-          'export Default, { Foo, Bar, Baz, } from "changed";',
-          'export Default, { Foo as Bar, Baz, Qux } from "changed";',
-          'export Default, { Foo as Bar, Baz, Qux, } from "changed";',
-          'export Default, { Foo, Bar as Baz, Qux } from "changed";',
-          'export Default, { Foo, Bar as Baz, Qux, } from "changed";',
-          'export Default, { Foo, Bar, Baz as Qux } from "changed";',
-          'export Default, { Foo, Bar, Baz as Qux, } from "changed";',
-          'export Default, { Foo as Bar, Baz as Qux, Norf } from "changed";',
-          'export Default, { Foo as Bar, Baz as Qux, Norf, } from "changed";',
-          'export Default, { Foo as Bar, Baz, Qux as Norf } from "changed";',
-          'export Default, { Foo as Bar, Baz, Qux as Norf, } from "changed";',
-          'export Default, { Foo, Bar as Baz, Qux as Norf } from "changed";',
-          'export Default, { Foo, Bar as Baz, Qux as Norf, } from "changed";',
-          'export Default, { Foo as Bar, Baz as Qux, Norf as Enuf } from "changed";',
-          'export Default, { Foo as Bar, Baz as Qux, Norf as Enuf, } from "changed";',
-          'export Default from "Y";',
-          'export * as All from \'z\';',
-          // export with support for new lines
-          "export { Foo,\n Bar }\n from 'changed';",
-          "export { \nFoo,\nBar,\n }\n from 'changed';",
-          "export { Foo as Bar,\n Baz\n }\n from 'changed';",
-          "export { \nFoo as Bar,\n Baz\n, }\n from 'changed';",
-          "export { Foo,\n Bar as Baz\n }\n from 'changed';",
-          "export { Foo,\n Bar as Baz,\n }\n from 'changed';",
-          "export { Foo as Bar,\n Baz as Qux\n }\n from 'changed';",
-          "export { Foo as Bar,\n Baz as Qux,\n }\n from 'changed';",
-          "export { Foo,\n Bar,\n Baz }\n from 'changed';",
-          "export { Foo,\n Bar,\n Baz,\n }\n from 'changed';",
-          "export { Foo as Bar,\n Baz,\n Qux\n }\n from 'changed';",
-          "export { Foo as Bar,\n Baz,\n Qux,\n }\n from 'changed';",
-          "export { Foo,\n Bar as Baz,\n Qux\n }\n from 'changed';",
-          "export { Foo,\n Bar as Baz,\n Qux,\n }\n from 'changed';",
-          "export { Foo,\n Bar,\n Baz as Qux\n }\n from 'changed';",
-          "export { Foo,\n Bar,\n Baz as Qux,\n }\n from 'changed';",
-          "export { Foo as Bar,\n Baz as Qux,\n Norf\n }\n from 'changed';",
-          "export { Foo as Bar,\n Baz as Qux,\n Norf,\n }\n from 'changed';",
-          "export { Foo as Bar,\n Baz,\n Qux as Norf\n }\n from 'changed';",
-          "export { Foo as Bar,\n Baz,\n Qux as Norf,\n }\n from 'changed';",
-          "export { Foo,\n Bar as Baz,\n Qux as Norf\n }\n from 'changed';",
-          "export { Foo,\n Bar as Baz,\n Qux as Norf,\n }\n from 'changed';",
-          "export { Foo as Bar,\n Baz as Qux,\n Norf as Enuf\n }\n from 'changed';",
-          "export { Foo as Bar,\n Baz as Qux,\n Norf as Enuf,\n }\n from 'changed';",
-          "export Default,\n * as All from 'changed';",
-          "export Default,\n { } from 'changed';",
-          "export Default,\n { Foo\n }\n from 'changed';",
-          "export Default,\n { Foo,\n }\n from 'changed';",
-          "export Default,\n { Foo as Bar\n }\n from 'changed';",
-          "export Default,\n { Foo as Bar,\n }\n from 'changed';",
-          "export Default,\n { Foo,\n Bar\n } from\n 'changed';",
-          "export Default,\n { Foo,\n Bar,\n } from\n 'changed';",
-          "export Default,\n { Foo as Bar,\n Baz\n }\n from 'changed';",
-          "export Default,\n { Foo as Bar,\n Baz,\n }\n from 'changed';",
-          "export Default,\n { Foo,\n Bar as Baz\n }\n from 'changed';",
-          "export Default,\n { Foo,\n Bar as Baz,\n }\n from 'changed';",
-          "export Default,\n { Foo as Bar,\n Baz as Qux\n }\n from 'changed';",
-          "export Default,\n { Foo as Bar,\n Baz as Qux,\n }\n from 'changed';",
-          "export Default,\n { Foo,\n Bar,\n Baz\n }\n from 'changed';",
-          "export Default,\n { Foo,\n Bar,\n Baz,\n }\n from 'changed';",
-          "export Default,\n { Foo as Bar,\n Baz,\n Qux\n }\n from 'changed';",
-          "export Default,\n { Foo as Bar,\n Baz,\n Qux,\n }\n from 'changed';",
-          "export Default,\n { Foo,\n Bar as Baz,\n Qux\n }\n from 'changed';",
-          "export Default,\n { Foo,\n Bar as Baz,\n Qux,\n }\n from 'changed';",
-          "export Default,\n { Foo,\n Bar,\n Baz as Qux\n }\n from 'changed';",
-          "export Default,\n { Foo,\n Bar,\n Baz as Qux,\n }\n from 'changed';",
-          "export Default,\n { Foo as Bar,\n Baz as Qux,\n Norf\n }\n from 'changed';",
-          "export Default,\n { Foo as Bar,\n Baz as Qux,\n Norf,\n }\n from 'changed';",
-          "export Default,\n { Foo as Bar,\n Baz,\n Qux as Norf }\n from 'changed';",
-          "export Default,\n { Foo as Bar,\n Baz,\n Qux as Norf, }\n from 'changed';",
-          "export Default,\n { Foo, Bar as Baz,\n Qux as Norf }\n from 'changed';",
-          "export Default,\n { Foo, Bar as Baz,\n Qux as Norf, }\n from 'changed';",
-          "export Default,\n { Foo as Bar,\n Baz as Qux,\n Norf as NoMore\n }\n from 'changed';",
-          "export Default,\n { Foo as Bar,\n Baz as Qux,\n Norf as NoMore,\n }\n from 'changed';",
-          "export Default\n , { } from 'changed';",
-          // require
-          'require("changed")',
-          'require("Y")',
-          'require( \'z\' )',
-          'require( "a")',
-          'require("b" )',
-          '});',
-        ].join('\n'));
+
+        // extract the converted code from the module wrapper
+        const cases =
+          processedCode.code
+            .match(/__d\(.*?\{\s*([\s\S]*)\}/)[1] // match code in wrapper
+            .replace(/\s+$/, '') // remove trailing whitespace
+            .split(magicJoiner); // extract every tested case
+
+        testCases.forEach((inputCode, i) => {
+          expect(cases[i]).toEqual(makeExpected(inputCode));
+          if(cases[i]!==makeExpected(inputCode)) {
+            console.log('FAIL %s: input(%s) expected(%s) actual(%s)', i, inputCode, makeExpected(inputCode), cases[i]);
+          }
+        });
       });
     });
 
diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index 0166681f0b3e..c657aae5905c 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -49,6 +49,10 @@ const validateOpts = declareOpts({
     type: 'object',
     required: true,
   },
+  getModuleId: {
+    type: 'function',
+    required: true,
+  }
 });
 
 const getDependenciesValidateOpts = declareOpts({
@@ -98,6 +102,7 @@ class Resolver {
       shouldThrowOnUnresolvedErrors: (_, platform) => platform === 'ios',
     });
 
+    this._getModuleId = options.getModuleId;
     this._polyfillModuleNames = opts.polyfillModuleNames || [];
   }
 
@@ -177,36 +182,32 @@ class Resolver {
       }
 
       const resolvedDeps = Object.create(null);
-      const resolvedDepsArr = [];
 
       return Promise.all(
         resolutionResponse.getResolvedDependencyPairs(module).map(
           ([depName, depModule]) => {
             if (depModule) {
-              return depModule.getName().then(name => {
-                resolvedDeps[depName] = name;
-                resolvedDepsArr.push(name);
-              });
+              resolvedDeps[depName] = this._getModuleId(depModule);
             }
           }
         )
       ).then(() => {
-        const relativizeCode = (codeMatch, pre, quot, depName, post) => {
-          const depId = resolvedDeps[depName];
-          if (depId) {
-            return pre + quot + depId + post;
+        const replaceModuleId = (codeMatch, pre, quot, depName, post = '') => {
+          if (depName in resolvedDeps) {
+            const replacement = `${quot}${resolvedDeps[depName]}${quot}`;
+            return `${pre}${replacement} /* ${depName} */${post}`;
           } else {
             return codeMatch;
           }
         };
 
         code = code
-          .replace(replacePatterns.IMPORT_RE, relativizeCode)
-          .replace(replacePatterns.EXPORT_RE, relativizeCode)
-          .replace(replacePatterns.REQUIRE_RE, relativizeCode);
+          .replace(replacePatterns.IMPORT_RE, replaceModuleId)
+          .replace(replacePatterns.EXPORT_RE, replaceModuleId)
+          .replace(replacePatterns.REQUIRE_RE, replaceModuleId);
 
         return module.getName().then(name => {
-          return {name, code};
+          return {name, code, id: this._getModuleId(module)};
         });
       });
     });
@@ -220,8 +221,8 @@ class Resolver {
     }
 
     return this.resolveRequires(resolutionResponse, module, code).then(
-      ({name, code}) => {
-        return {name, code: defineModuleCode(name, code)};
+      ({name, code, id}) => {
+        return {id, name, code: defineModuleCode(id, code, name)};
       });
   }
 
@@ -231,10 +232,10 @@ class Resolver {
 
 }
 
-function defineModuleCode(moduleName, code) {
+function defineModuleCode(moduleId, code, verboseName = '') {
   return [
     `__d(`,
-    `'${moduleName}',`,
+    `${JSON.stringify(moduleId)} /* ${verboseName} */ ,`,
     'function(global, require, module, exports) {',
     `  ${code}`,
     '\n});',
diff --git a/packager/react-packager/src/Resolver/polyfills/require.js b/packager/react-packager/src/Resolver/polyfills/require.js
index a5a7a55f01a5..bc14a6e8421b 100644
--- a/packager/react-packager/src/Resolver/polyfills/require.js
+++ b/packager/react-packager/src/Resolver/polyfills/require.js
@@ -59,18 +59,29 @@ function requireImpl(id) {
     );
   }
 
+
+  // `require` calls int  the require polyfill itself are not analyzed and
+  // replaced so that they use numeric module IDs.
+  // The systrace module will expose itself on the require function so that
+  // it can be used here.
+  // TODO(davidaurelio) Scan polyfills for dependencies, too (t9759686)
+  const {Systrace} = require;
   try {
     // We must optimistically mark mod as initialized before running the factory to keep any
     // require cycles inside the factory from causing an infinite require loop.
     mod.isInitialized = true;
 
-    __DEV__ && Systrace().beginEvent('JS_require_' + id);
+    if (__DEV__) {
+      Systrace.beginEvent('JS_require_' + id);
+    }
 
     // keep args in sync with with defineModuleCode in
     // packager/react-packager/src/Resolver/index.js
     mod.factory.call(global, global, require, mod.module, mod.module.exports);
 
-    __DEV__ && Systrace().endEvent();
+    if (__DEV__) {
+      Systrace.endEvent();
+    }
   } catch (e) {
     mod.hasError = true;
     mod.isInitialized = false;
@@ -80,15 +91,9 @@ function requireImpl(id) {
   return mod.module.exports;
 }
 
-const Systrace = __DEV__ && (() => {
-  var _Systrace;
-  try {
-    _Systrace = require('Systrace');
-  } catch (e) {}
-
-  return _Systrace && _Systrace.beginEvent ?
-    _Systrace : { beginEvent: () => {}, endEvent: () => {} };
-});
+if (__DEV__) {
+  require.Systrace = { beginEvent: () => {}, endEvent: () => {} };
+}
 
 global.__d = define;
 global.require = require;

From 7d457b09b44b1734c59ee152ec7f80c0847f4ea8 Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Thu, 21 Jan 2016 10:37:28 -0800
Subject: [PATCH 0832/1411] Turn to ES6

Summary: Closes https://github.com/facebook/react-native/pull/5460

Reviewed By: svcscm

Differential Revision: D2850417

Pulled By: androidtrunkagent

fb-gh-sync-id: 8ba8bf935de53676cb4930712fabfe832208213f
---
 docs/Tutorial.md | 98 ++++++++++++++++++++++++------------------------
 1 file changed, 50 insertions(+), 48 deletions(-)

diff --git a/docs/Tutorial.md b/docs/Tutorial.md
index c3b75cfb98cb..26696d3f5e2a 100644
--- a/docs/Tutorial.md
+++ b/docs/Tutorial.md
@@ -43,7 +43,7 @@ For this tutorial we'll be building a simple version of the Movies app that fetc
 
 ### Mocking data
 
-Before we write the code to fetch actual Rotten Tomatoes data let's mock some data so we can get our hands dirty with React Native. At Facebook we typically declare constants at the top of JS files, just below the requires, but feel free to add the following constant wherever you like. In `index.ios.js` or `index.android.js` :
+Before we write the code to fetch actual Rotten Tomatoes data let's mock some data so we can get our hands dirty with React Native. At Facebook we typically declare constants at the top of JS files, just below the imports, but feel free to add the following constant wherever you like. In `index.ios.js` or `index.android.js` :
 
 ```javascript
 var MOCKED_MOVIES_DATA = [
@@ -54,22 +54,22 @@ var MOCKED_MOVIES_DATA = [
 
 ### Render a movie
 
-We're going to render the title, year, and thumbnail for the movie. Since thumbnail is an Image component in React Native, add Image to the list of React requires below.
+We're going to render the title, year, and thumbnail for the movie. Since thumbnail is an Image component in React Native, add Image to the list of React imports below.
 
 ```javascript
-var {
+import React, {
   AppRegistry,
   Image,
   StyleSheet,
   Text,
   View,
-} = React;
+} from 'react-native';
 ```
 
 Now change the render function so that we're rendering the data mentioned above rather than hello world.
 
 ```javascript
-  render: function() {
+  render() {
     var movie = MOCKED_MOVIES_DATA[0];
     return (
       <View style={styles.container}>
@@ -196,7 +196,7 @@ Go ahead and press `⌘+R` / `Reload JS` and you'll see the updated view.
 
 Fetching data from Rotten Tomatoes's API isn't really relevant to learning React Native so feel free to breeze through this section.
 
-Add the following constants to the top of the file (typically below the requires) to create the REQUEST_URL used to request data with.
+Add the following constants to the top of the file (typically below the imports) to create the REQUEST_URL used to request data with.
 
 ```javascript
 /**
@@ -209,25 +209,26 @@ var REQUEST_URL = 'https://raw.githubusercontent.com/facebook/react-native/maste
 Add some initial state to our application so that we can check `this.state.movies === null` to determine whether the movies data has been loaded or not. We can set this data when the response comes back with `this.setState({movies: moviesData})`. Add this code just above the render function inside our React class.
 
 ```javascript
-  getInitialState: function() {
-    return {
+  constructor(props) {
+    super(props); 
+    this.state = {
       movies: null,
     };
-  },
+  }
 ```
 
 We want to send off the request after the component has finished loading. `componentDidMount` is a function of React components that React will call exactly once, just after the component has been loaded.
 
 ```javascript
-  componentDidMount: function() {
+  componentDidMount() {
     this.fetchData();
-  },
+  }
 ```
 
 Now add `fetchData` function used above to our main component. This method will be responsible for handling data fetching. All you need to do is call `this.setState({movies: data})` after resolving the promise chain because the way React works is that `setState` actually triggers a re-render and then the render function will notice that `this.state.movies` is no longer `null`.  Note that we call `done()` at the end of the promise chain - always make sure to call `done()` or any errors thrown will get swallowed.
 
 ```javascript
-  fetchData: function() {
+  fetchData() {
     fetch(REQUEST_URL)
       .then((response) => response.json())
       .then((responseData) => {
@@ -236,22 +237,22 @@ Now add `fetchData` function used above to our main component. This method will
         });
       })
       .done();
-  },
+  }
 ```
 
 Now modify the render function to render a loading view if we don't have any movies data, and to render the first movie otherwise.
 
 ```javascript
-  render: function() {
+  render() {
     if (!this.state.movies) {
       return this.renderLoadingView();
     }
 
     var movie = this.state.movies[0];
     return this.renderMovie(movie);
-  },
+  }
 
-  renderLoadingView: function() {
+  renderLoadingView() {
     return (
       <View style={styles.container}>
         <Text>
@@ -259,9 +260,9 @@ Now modify the render function to render a loading view if we don't have any mov
         </Text>
       </View>
     );
-  },
+  }
 
-  renderMovie: function(movie) {
+  renderMovie(movie) {
     return (
       <View style={styles.container}>
         <Image
@@ -274,7 +275,7 @@ Now modify the render function to render a loading view if we don't have any mov
         </View>
       </View>
     );
-  },
+  }
 ```
 
 Now press `⌘+R` / `Reload JS` and you should see "Loading movies..." until the response comes back, then it will render the first movie it fetched from Rotten Tomatoes.
@@ -290,23 +291,23 @@ Let's now modify this application to render all of this data in a `ListView` com
 
 Why is a `ListView` better than just rendering all of these elements or putting them in a `ScrollView`? Despite React being fast, rendering a possibly infinite list of elements could be slow. `ListView` schedules rendering of views so that you only display the ones on screen and those already rendered but off screen are removed from the native view hierarchy.
 
-First things first: add the `ListView` require to the top of the file.
+First things first: add the `ListView` import to the top of the file.
 
 ```javascript
-var {
+import React, {
   AppRegistry,
   Image,
   ListView,
   StyleSheet,
   Text,
   View,
-} = React;
+} from 'react-native';
 ```
 
 Now modify the render function so that once we have our data it renders a ListView of movies instead of a single movie.
 
 ```javascript
-  render: function() {
+  render() {
     if (!this.state.loaded) {
       return this.renderLoadingView();
     }
@@ -318,28 +319,29 @@ Now modify the render function so that once we have our data it renders a ListVi
         style={styles.listView}
       />
     );
-  },
+  }
 ```
 
 The `dataSource` is an interface that `ListView` is using to determine which rows have changed over the course of updates.
 
-You'll notice we used `dataSource` from `this.state`. The next step is to add an empty `dataSource` to the object returned by `getInitialState`. Also, now that we're storing the data in `dataSource`, we should no longer use `this.state.movies` to avoid storing data twice. We can use boolean property of the state (`this.state.loaded`) to tell whether data fetching has finished.
+You'll notice we used `dataSource` from `this.state`. The next step is to add an empty `dataSource` to the object returned by `constructor`. Also, now that we're storing the data in `dataSource`, we should no longer use `this.state.movies` to avoid storing data twice. We can use boolean property of the state (`this.state.loaded`) to tell whether data fetching has finished.
 
 ```javascript
-  getInitialState: function() {
-    return {
+  constructor(props) {
+    super(props);
+    this.state = {
       dataSource: new ListView.DataSource({
         rowHasChanged: (row1, row2) => row1 !== row2,
       }),
       loaded: false,
     };
-  },
+  }
 ```
 
 And here is the modified `fetchData` method that updates the state accordingly:
 
 ```javascript
-  fetchData: function() {
+  fetchData() {
     fetch(REQUEST_URL)
       .then((response) => response.json())
       .then((responseData) => {
@@ -349,7 +351,7 @@ And here is the modified `fetchData` method that updates the state accordingly:
         });
       })
       .done();
-  },
+  }
 ```
 
 Finally, we add styles for the `ListView` component to the `styles` JS object:
@@ -377,17 +379,16 @@ There's still some work to be done to make it a fully functional app such as: ad
  * Sample React Native App
  * https://github.com/facebook/react-native
  */
-'use strict';
 
-var React = require('react-native');
-var {
+import React, {
   AppRegistry,
+  Component,
   Image,
   ListView,
   StyleSheet,
   Text,
   View,
-} = React;
+} from 'react-native';
 
 var API_KEY = '7waqfqbprs7pajbz28mqf6vz';
 var API_URL = 'http://api.rottentomatoes.com/api/public/v1.0/lists/movies/in_theaters.json';
@@ -395,21 +396,22 @@ var PAGE_SIZE = 25;
 var PARAMS = '?apikey=' + API_KEY + '&page_limit=' + PAGE_SIZE;
 var REQUEST_URL = API_URL + PARAMS;
 
-var AwesomeProject = React.createClass({
-  getInitialState: function() {
-    return {
+class AwesomeProject extends Component {
+  constructor(props) {
+    super(props);
+    this.state = {
       dataSource: new ListView.DataSource({
         rowHasChanged: (row1, row2) => row1 !== row2,
       }),
       loaded: false,
     };
-  },
+  }
 
-  componentDidMount: function() {
+  componentDidMount() {
     this.fetchData();
-  },
+  }
 
-  fetchData: function() {
+  fetchData() {
     fetch(REQUEST_URL)
       .then((response) => response.json())
       .then((responseData) => {
@@ -419,9 +421,9 @@ var AwesomeProject = React.createClass({
         });
       })
       .done();
-  },
+  }
 
-  render: function() {
+  render() {
     if (!this.state.loaded) {
       return this.renderLoadingView();
     }
@@ -433,9 +435,9 @@ var AwesomeProject = React.createClass({
         style={styles.listView}
       />
     );
-  },
+  }
 
-  renderLoadingView: function() {
+  renderLoadingView() {
     return (
       <View style={styles.container}>
         <Text>
@@ -443,9 +445,9 @@ var AwesomeProject = React.createClass({
         </Text>
       </View>
     );
-  },
+  }
 
-  renderMovie: function(movie) {
+  renderMovie(movie) {
     return (
       <View style={styles.container}>
         <Image
@@ -458,7 +460,7 @@ var AwesomeProject = React.createClass({
         </View>
       </View>
     );
-  },
+  }
 });
 
 var styles = StyleSheet.create({

From ba4101dc4aa1054f0f1159d6bc5b5760d749c383 Mon Sep 17 00:00:00 2001
From: Kyle Corbitt <kyle@corbt.com>
Date: Thu, 21 Jan 2016 10:48:58 -0800
Subject: [PATCH 0833/1411] Simplified AlertIOS

Summary:
Ok, so this started as fixing #5273 but ended up getting a little more complicated. :smile:

Currently, AlertIOS has the following API:

* `alert(title, message, buttons, type)`
* `prompt(title, defaultValue, buttons, callback)`

I've changed the API to look like the following:

* `alert(title, message, callbackOrButtons)`
* `prompt(title, message, callbackOrButtons, type, defaultValue)`

I know that breaking changes are a big deal, but I find the current alert API to be fairly inconsistent and unnecessarily confusing. I'll try to justify my changes one by one:

1. Currently `type` is an optional parameter of `alert`. However, the only reason to change the alert type from the default is in order to create one of the input dialogs (text, password or username/password). So we're in a weird state where if you want a normal text input, you use `prompt`, but if you want a password input you use `alert` with the 'secure-text' type. I've moved `type` to `prompt` so all text input is now done with `pro
Closes https://github.com/facebook/react-native/pull/5286

Reviewed By: svcscm

Differential Revision: D2850400

Pulled By: androidtrunkagent

fb-gh-sync-id: 2986cfa2266225df7e4dcd703fce1e322c12b816
---
 Examples/UIExplorer/AlertExample.js    |   3 +-
 Examples/UIExplorer/AlertIOSExample.js |  96 +++--------
 Libraries/Utilities/Alert.js           |  14 +-
 Libraries/Utilities/AlertIOS.js        | 211 ++++++++++++++++---------
 React/Modules/RCTAlertManager.m        |   5 +
 5 files changed, 175 insertions(+), 154 deletions(-)

diff --git a/Examples/UIExplorer/AlertExample.js b/Examples/UIExplorer/AlertExample.js
index 702c49a6c921..37f47dd9b01d 100644
--- a/Examples/UIExplorer/AlertExample.js
+++ b/Examples/UIExplorer/AlertExample.js
@@ -18,7 +18,6 @@
 var React = require('react-native');
 var {
   Alert,
-  Platform,
   StyleSheet,
   Text,
   TouchableHighlight,
@@ -134,4 +133,4 @@ var styles = StyleSheet.create({
 module.exports = {
   AlertExample,
   SimpleAlertExampleBlock,
-}
+};
diff --git a/Examples/UIExplorer/AlertIOSExample.js b/Examples/UIExplorer/AlertIOSExample.js
index 015d68a18a95..a52c1ab79521 100644
--- a/Examples/UIExplorer/AlertIOSExample.js
+++ b/Examples/UIExplorer/AlertIOSExample.js
@@ -36,37 +36,19 @@ exports.examples = [{
   }
 },
 {
-  title: 'Alert Types',
+  title: 'Prompt Options',
+  render(): React.Component {
+    return <PromptOptions />;
+  }
+},
+{
+  title: 'Prompt Types',
   render() {
     return (
       <View>
         <TouchableHighlight
           style={styles.wrapper}
-          onPress={() => AlertIOS.alert(
-            'Hello World',
-            null,
-            [
-              {text: 'OK', onPress: (text) => console.log('OK pressed'), type: 'default'}
-            ]
-          )}>
-
-          <View style={styles.button}>
-            <Text>
-              {'default'}
-            </Text>
-          </View>
-
-        </TouchableHighlight>
-        <TouchableHighlight
-          style={styles.wrapper}
-          onPress={() => AlertIOS.alert(
-            'Plain Text Entry',
-            null,
-            [
-              {text: 'Submit', onPress: (text) => console.log('Text: ' + text), type: 'plain-text'},
-              {text: 'Cancel', onPress: () => console.log('Cancel'), style: 'cancel'}
-            ]
-          )}>
+          onPress={() => AlertIOS.prompt('Plain Text Entry')}>
 
           <View style={styles.button}>
             <Text>
@@ -77,14 +59,7 @@ exports.examples = [{
         </TouchableHighlight>
         <TouchableHighlight
           style={styles.wrapper}
-          onPress={() => AlertIOS.alert(
-            'Secure Text Entry',
-            null,
-            [
-              {text: 'Submit', onPress: (text) => console.log('Password: ' + text), type: 'secure-text'},
-              {text: 'Cancel', onPress: () => console.log('Cancel'), style: 'cancel'}
-            ]
-          )}>
+          onPress={() => AlertIOS.prompt('Secure Text', null, null, 'secure-text')}>
 
           <View style={styles.button}>
             <Text>
@@ -95,14 +70,7 @@ exports.examples = [{
         </TouchableHighlight>
         <TouchableHighlight
           style={styles.wrapper}
-          onPress={() => AlertIOS.alert(
-            'Login & Password',
-            null,
-            [
-              {text: 'Submit', onPress: (details) => console.log('Login: ' + details.login + '; Password: ' + details.password), type: 'login-password'},
-              {text: 'Cancel', onPress: () => console.log('Cancel'), style: 'cancel'}
-            ]
-          )}>
+          onPress={() => AlertIOS.prompt('Login & Password', null, null, 'login-password')}>
 
           <View style={styles.button}>
             <Text>
@@ -114,32 +82,25 @@ exports.examples = [{
       </View>
     );
   }
-},
-{
-  title: 'Prompt',
-  render(): React.Component {
-    return <PromptExample />;
-  }
 }];
 
-class PromptExample extends React.Component {
+class PromptOptions extends React.Component {
   constructor(props) {
     super(props);
 
-    this.promptResponse = this.promptResponse.bind(this);
-    this.state = {
-      promptValue: undefined,
-    };
+    this.saveResponse = this.saveResponse.bind(this);
 
-    this.title = 'Type a value';
-    this.defaultValue = 'Default value';
-    this.buttons = [{
+    this.customButtons = [{
       text: 'Custom OK',
-      onPress: this.promptResponse
+      onPress: this.saveResponse
     }, {
       text: 'Custom Cancel',
       style: 'cancel',
     }];
+
+    this.state = {
+      promptValue: undefined,
+    };
   }
 
   render() {
@@ -151,7 +112,7 @@ class PromptExample extends React.Component {
 
         <TouchableHighlight
           style={styles.wrapper}
-          onPress={this.prompt.bind(this, this.title, null, null, this.promptResponse)}>
+          onPress={() => AlertIOS.prompt('Type a value', null, this.saveResponse)}>
 
           <View style={styles.button}>
             <Text>
@@ -162,7 +123,7 @@ class PromptExample extends React.Component {
 
         <TouchableHighlight
           style={styles.wrapper}
-          onPress={this.prompt.bind(this, this.title, null, this.buttons, null)}>
+          onPress={() => AlertIOS.prompt('Type a value', null, this.customButtons)}>
 
           <View style={styles.button}>
             <Text>
@@ -173,22 +134,22 @@ class PromptExample extends React.Component {
 
         <TouchableHighlight
           style={styles.wrapper}
-          onPress={this.prompt.bind(this, this.title, this.defaultValue, null, this.promptResponse)}>
+          onPress={() => AlertIOS.prompt('Type a value', null, this.saveResponse, undefined, 'Default value')}>
 
           <View style={styles.button}>
             <Text>
-              prompt with title, default value & callback
+              prompt with title, callback & default value
             </Text>
           </View>
         </TouchableHighlight>
 
         <TouchableHighlight
           style={styles.wrapper}
-          onPress={this.prompt.bind(this, this.title, this.defaultValue, this.buttons, null)}>
+          onPress={() => AlertIOS.prompt('Type a value', null, this.customButtons, 'login-password', 'admin@site.com')}>
 
           <View style={styles.button}>
             <Text>
-              prompt with title, default value & custom buttons
+              prompt with title, custom buttons, login/password & default value
             </Text>
           </View>
         </TouchableHighlight>
@@ -196,13 +157,8 @@ class PromptExample extends React.Component {
     );
   }
 
-  prompt() {
-    // Flow's apply support is broken: #7035621
-    ((AlertIOS.prompt: any).apply: any)(AlertIOS, arguments);
-  }
-
-  promptResponse(promptValue) {
-    this.setState({ promptValue });
+  saveResponse(promptValue) {
+    this.setState({ promptValue: JSON.stringify(promptValue) });
   }
 }
 
diff --git a/Libraries/Utilities/Alert.js b/Libraries/Utilities/Alert.js
index 3768be64d9da..ee733d1ece63 100644
--- a/Libraries/Utilities/Alert.js
+++ b/Libraries/Utilities/Alert.js
@@ -37,11 +37,10 @@ type Buttons = Array<{
  * ## iOS
  *
  * On iOS you can specify any number of buttons. Each button can optionally
- * specify a style and you can also specify type of the alert. Refer to
- * `AlertIOS` for details.
+ * specify a style, which is one of 'default', 'cancel' or 'destructive'.
  *
  * ## Android
- * 
+ *
  * On Android at most three buttons can be specified. Android has a concept
  * of a neutral, negative and a positive button:
  *
@@ -68,10 +67,15 @@ class Alert {
     title: ?string,
     message?: ?string,
     buttons?: Buttons,
-    type?: AlertType
+    type?: AlertType,
   ): void {
     if (Platform.OS === 'ios') {
-      AlertIOS.alert(title, message, buttons, type);
+      if (typeof type !== 'undefined') {
+        console.warn('Alert.alert() with a 4th "type" parameter is deprecated and will be removed. Use AlertIOS.prompt() instead.');
+        AlertIOS.alert(title, message, buttons, type);
+        return;
+      }
+      AlertIOS.alert(title, message, buttons);
     } else if (Platform.OS === 'android') {
       AlertAndroid.alert(title, message, buttons);
     }
diff --git a/Libraries/Utilities/AlertIOS.js b/Libraries/Utilities/AlertIOS.js
index 2413f38d2ca4..ec8c926c6edb 100644
--- a/Libraries/Utilities/AlertIOS.js
+++ b/Libraries/Utilities/AlertIOS.js
@@ -12,7 +12,6 @@
 'use strict';
 
 var RCTAlertManager = require('NativeModules').AlertManager;
-var invariant = require('invariant');
 
 export type AlertType = $Enum<{
   'default': string;
@@ -27,61 +26,156 @@ export type AlertButtonStyle = $Enum<{
   'destructive': string;
 }>;
 
+type ButtonsArray = Array<{
+  text?: string;
+  onPress?: ?Function;
+  style?: AlertButtonStyle;
+}>;
+
 /**
- * Launches an alert dialog with the specified title and message.
- *
- * Optionally provide a list of buttons. Tapping any button will fire the
- * respective onPress callback and dismiss the alert. By default, the only
- * button will be an 'OK' button.
+ * The AlertsIOS utility provides two functions: `alert` and `prompt`. All
+ * functionality available through `AlertIOS.alert` is also available in the
+ * cross-platform `Alert.alert`, which we recommend you use if you don't need
+ * iOS-specific functionality.
  *
- * Use this API for iOS-specific features, such as prompting the user to enter
- * some information. In other cases, especially to show static alerts, use
- * the cross-platform `Alert` API.
+ * `AlertIOS.prompt` allows you to prompt the user for input inside of an
+ * alert popup.
  *
- * ```
- * AlertIOS.alert(
- *   'Enter password',
- *   null,
- *   [
- *     {text: 'Submit', onPress: (text) => console.log('Password: ' + text)},
- *   ],
- *   'secure-text'
- * )
- * ```
  */
 class AlertIOS {
+  /**
+   * Creates a popup to alert the user. See
+   * [Alert](/react-native/docs/alert.html).
+   *
+   *  - title: string -- The dialog's title.
+   *  - message: string -- An optional message that appears above the text input.
+   *  - callbackOrButtons -- This optional argument should be either a
+   *    single-argument function or an array of buttons. If passed a function,
+   *    it will be called when the user taps 'OK'.
+   *
+   *    If passed an array of button configurations, each button should include
+   *    a `text` key, as well as optional `onPress` and `style` keys.
+   *    `style` should be one of 'default', 'cancel' or 'destructive'.
+   *  - type -- *deprecated, do not use*
+   *
+   * Example:
+   *
+   * ```
+   * AlertIOS.alert(
+   *  'Sync Complete',
+   *  'All your data are belong to us.'
+   * );
+   * ```
+   */
   static alert(
     title: ?string,
     message?: ?string,
-    buttons?: Array<{
-      text?: string;
-      onPress?: ?Function;
-      style?: AlertButtonStyle;
-    }>,
-    type?: ?AlertType
+    callbackOrButtons?: ?(() => void) | ButtonsArray,
+    type?: AlertType,
   ): void {
+    if (typeof type !== 'undefined') {
+      console.warn('AlertIOS.alert() with a 4th "type" parameter is deprecated and will be removed. Use AlertIOS.prompt() instead.');
+      this.prompt(title, message, callbackOrButtons, type);
+      return;
+    }
+    this.prompt(title, message, callbackOrButtons, 'default');
+  }
+
+  /**
+   * Prompt the user to enter some text.
+   *
+   *  - title: string -- The dialog's title.
+   *  - message: string -- An optional message that appears above the text input.
+   *  - callbackOrButtons -- This optional argument should be either a
+   *    single-argument function or an array of buttons. If passed a function,
+   *    it will be called with the prompt's value when the user taps 'OK'.
+   *
+   *    If passed an array of button configurations, each button should include
+   *    a `text` key, as well as optional `onPress` and `style` keys (see example).
+   *    `style` should be one of 'default', 'cancel' or 'destructive'.
+   *  - type: string -- This configures the text input. One of 'plain-text',
+   *    'secure-text' or 'login-password'.
+   *  - defaultValue: string -- the default value for the text field.
+   *
+   * Example with custom buttons:
+   * ```
+   * AlertIOS.prompt(
+   *   'Enter password',
+   *   'Enter your password to claim your $1.5B in lottery winnings',
+   *   [
+   *     {text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
+   *     {text: 'OK', onPress: password => console.log('OK Pressed, password: ' + password)},
+   *   ],
+   *   'secure-text'
+   * );
+   * ```
+   *
+   * Example with the default button and a custom callback:
+   * ```
+   * AlertIOS.prompt(
+   *   'Update username',
+   *   null,
+   *   text => console.log("Your username is "+text),
+   *   null,
+   *   'default'
+   * )
+   * ```
+   */
+  static prompt(
+    title: ?string,
+    message?: ?string,
+    callbackOrButtons?: ?((text: string) => void) | ButtonsArray,
+    type?: ?AlertType = 'plain-text',
+    defaultValue?: string,
+  ): void {
+    if (typeof type === 'function') {
+      console.warn(
+        'You passed a callback function as the "type" argument to AlertIOS.prompt(). React Native is ' +
+        'assuming  you want to use the deprecated AlertIOS.prompt(title, defaultValue, buttons, callback) ' +
+        'signature. The current signature is AlertIOS.prompt(title, message, callbackOrButtons, type, defaultValue) ' +
+        'and the old syntax will be removed in a future version.');
+
+      var callback = type;
+      var defaultValue = message;
+      RCTAlertManager.alertWithArgs({
+        title: title || undefined,
+        type: 'plain-text',
+        defaultValue,
+      }, (id, value) => {
+        callback(value);
+      });
+      return;
+    }
+
     var callbacks = [];
-    var buttonsSpec = [];
+    var buttons = [];
     var cancelButtonKey;
     var destructiveButtonKey;
-    buttons && buttons.forEach((btn, index) => {
-      callbacks[index] = btn.onPress;
-      if (btn.style == 'cancel') {
-        cancelButtonKey = String(index);
-      } else if (btn.style == 'destructive') {
-        destructiveButtonKey = String(index);
-      }
-      if (btn.text || index < (buttons || []).length - 1) {
-        var btnDef = {};
-        btnDef[index] = btn.text || '';
-        buttonsSpec.push(btnDef);
-      }
-    });
+    if (typeof callbackOrButtons === 'function') {
+      callbacks = [callbackOrButtons];
+    }
+    else if (callbackOrButtons instanceof Array) {
+      callbackOrButtons.forEach((btn, index) => {
+        callbacks[index] = btn.onPress;
+        if (btn.style === 'cancel') {
+          cancelButtonKey = String(index);
+        } else if (btn.style === 'destructive') {
+          destructiveButtonKey = String(index);
+        }
+        if (btn.text || index < (callbackOrButtons || []).length - 1) {
+          var btnDef = {};
+          btnDef[index] = btn.text || '';
+          buttons.push(btnDef);
+        }
+      });
+    }
+
     RCTAlertManager.alertWithArgs({
       title: title || undefined,
       message: message || undefined,
-      buttons: buttonsSpec,
+      buttons,
       type: type || undefined,
+      defaultValue,
       cancelButtonKey,
       destructiveButtonKey,
     }, (id, value) => {
@@ -89,43 +183,6 @@ class AlertIOS {
       cb && cb(value);
     });
   }
-
-  /**
-   * Prompt the user to enter some text.
-   */
-  static prompt(
-    title: string,
-    value?: string,
-    buttons?: Array<{
-      text?: string;
-      onPress?: ?Function;
-      style?: AlertButtonStyle;
-    }>,
-    callback?: ?Function
-  ): void {
-    if (arguments.length === 2) {
-      if (typeof value === 'object') {
-        buttons = value;
-        value = undefined;
-      } else if (typeof value === 'function') {
-        callback = value;
-        value = undefined;
-      }
-    } else if (arguments.length === 3 && typeof buttons === 'function') {
-      callback = buttons;
-      buttons = undefined;
-    }
-
-    invariant(
-      !(callback && buttons) && (callback || buttons),
-      'Must provide either a button list or a callback, but not both'
-    );
-
-    if (!buttons) {
-      buttons = [{ onPress: callback }];
-    }
-    this.alert(title, value, buttons, 'plain-text');
-  }
 }
 
 module.exports = AlertIOS;
diff --git a/React/Modules/RCTAlertManager.m b/React/Modules/RCTAlertManager.m
index d735d54423a2..b2e7fe0a3ae0 100644
--- a/React/Modules/RCTAlertManager.m
+++ b/React/Modules/RCTAlertManager.m
@@ -75,6 +75,7 @@ - (void)invalidate
   NSString *message = [RCTConvert NSString:args[@"message"]];
   UIAlertViewStyle type = [RCTConvert UIAlertViewStyle:args[@"type"]];
   NSArray<NSDictionary *> *buttons = [RCTConvert NSDictionaryArray:args[@"buttons"]];
+  NSString *defaultValue = [RCTConvert NSString:args[@"defaultValue"]];
   NSString *cancelButtonKey = [RCTConvert NSString:args[@"cancelButtonKey"]];
   NSString *destructiveButtonKey = [RCTConvert NSString:args[@"destructiveButtonKey"]];
 
@@ -111,6 +112,10 @@ - (void)invalidate
     alertView.alertViewStyle = type;
     alertView.message = message;
 
+    if (type != UIAlertViewStyleDefault) {
+      [alertView textFieldAtIndex:0].text = defaultValue;
+    }
+
     NSMutableArray<NSString *> *buttonKeys =
       [[NSMutableArray alloc] initWithCapacity:buttons.count];
 

From dc9693568142f22147c7cefad4e62a6ae68ee504 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Thu, 21 Jan 2016 10:57:02 -0800
Subject: [PATCH 0834/1411] Fix a tiny typo in error message

Reviewed By: davidaurelio

Differential Revision: D2850195

fb-gh-sync-id: 8177ce2f8d7f799edc559b4f5a0da99d865874a7
---
 .../src/DependencyResolver/DependencyGraph/ResolutionRequest.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
index 65742f1af91c..2c18c95a34be 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
@@ -374,7 +374,7 @@ class ResolutionRequest {
           toModule,
 `Invalid directory ${potentialDirPath}
 
-This might related to https://github.com/facebook/react-native/issues/4968
+This might be related to https://github.com/facebook/react-native/issues/4968
 To resolve try the following:
   1. Clear watchman watches: \`watchman watch-del-all\`.
   2. Delete the \`node_modules\` folder: \`rm -rf node_modules && npm install\`.

From f453e14c8f91d00a8205e6bb06094c85281b38be Mon Sep 17 00:00:00 2001
From: Huang Yu <huang@bitgo.com>
Date: Thu, 21 Jan 2016 11:07:50 -0800
Subject: [PATCH 0835/1411] Fix StyleSheet 'textAlign' for AndroidTextInput.
 Closes #2702

Summary:
change `setTextAlign` and `setTextAlignVertical` to receive argument of type `String` (the same as in `StyleSheet`), so that native props and stylesheet props are calling the same ReactMethod

- add demo (may not be necessary)
Closes https://github.com/facebook/react-native/pull/4481

Reviewed By: svcscm

Differential Revision: D2823456

Pulled By: mkonicek

fb-gh-sync-id: 349d17549f419b5bdc001d70b583423ade06bfe8
---
 .../UIExplorer/TextInputExample.android.js    | 12 ++---
 Libraries/Components/TextInput/TextInput.js   | 24 ----------
 Libraries/Text/TextStylePropTypes.js          |  6 +++
 .../facebook/react/uimanager/ViewProps.java   |  1 +
 .../textinput/ReactTextInputManager.java      | 44 ++++++++++++-------
 5 files changed, 38 insertions(+), 49 deletions(-)

diff --git a/Examples/UIExplorer/TextInputExample.android.js b/Examples/UIExplorer/TextInputExample.android.js
index 9bccf5256a83..b3f5c6a4e263 100644
--- a/Examples/UIExplorer/TextInputExample.android.js
+++ b/Examples/UIExplorer/TextInputExample.android.js
@@ -348,25 +348,19 @@ exports.examples = [
             placeholder="multiline, aligned top-left"
             placeholderTextColor="red"
             multiline={true}
-            textAlign="start"
-            textAlignVertical="top"
-            style={styles.multiline}
+            style={[styles.multiline, {textAlign: "left", textAlignVertical: "top"}]}
           />
           <TextInput
             autoCorrect={true}
             placeholder="multiline, aligned center"
             placeholderTextColor="green"
             multiline={true}
-            textAlign="center"
-            textAlignVertical="center"
-            style={[styles.multiline]}
+            style={[styles.multiline, {textAlign: "center", textAlignVertical: "center"}]}
           />
           <TextInput
             autoCorrect={true}
             multiline={true}
-            textAlign="end"
-            textAlignVertical="bottom"
-            style={[styles.multiline, {color: 'blue'}]}>
+            style={[styles.multiline, {color: 'blue'}, {textAlign: "right", textAlignVertical: "bottom"}]}>
             <Text style={styles.multiline}>multiline with children, aligned bottom-right</Text>
           </TextInput>
         </View>
diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js
index b029db359b03..f9c03a175864 100644
--- a/Libraries/Components/TextInput/TextInput.js
+++ b/Libraries/Components/TextInput/TextInput.js
@@ -101,24 +101,6 @@ var TextInput = React.createClass({
      * The default value is false.
      */
     autoFocus: PropTypes.bool,
-    /**
-     * Set the position of the cursor from where editing will begin.
-     * @platform android
-     */
-    textAlign: PropTypes.oneOf([
-      'start',
-      'center',
-      'end',
-    ]),
-    /**
-     * Aligns text vertically within the TextInput.
-     * @platform android
-     */
-    textAlignVertical: PropTypes.oneOf([
-      'top',
-      'center',
-      'bottom',
-    ]),
     /**
      * If false, text is not editable. The default value is true.
      */
@@ -491,10 +473,6 @@ var TextInput = React.createClass({
 
     var autoCapitalize =
       UIManager.AndroidTextInput.Constants.AutoCapitalizationType[this.props.autoCapitalize];
-    var textAlign = UIManager.AndroidTextInput.Constants.TextAlign[this.props.textAlign];
-    var textAlignVertical =
-      UIManager.AndroidTextInput.Constants.TextAlignVertical[this.props.textAlignVertical];
-
     var children = this.props.children;
     var childCount = 0;
     ReactChildren.forEach(children, () => ++childCount);
@@ -512,8 +490,6 @@ var TextInput = React.createClass({
         style={[this.props.style]}
         autoCapitalize={autoCapitalize}
         autoCorrect={this.props.autoCorrect}
-        textAlign={textAlign}
-        textAlignVertical={textAlignVertical}
         keyboardType={this.props.keyboardType}
         mostRecentEventCount={0}
         multiline={this.props.multiline}
diff --git a/Libraries/Text/TextStylePropTypes.js b/Libraries/Text/TextStylePropTypes.js
index 3db900fd712a..9c4668174e4f 100644
--- a/Libraries/Text/TextStylePropTypes.js
+++ b/Libraries/Text/TextStylePropTypes.js
@@ -46,6 +46,12 @@ var TextStylePropTypes = Object.assign(Object.create(ViewStylePropTypes), {
   textAlign: ReactPropTypes.oneOf(
     ['auto' /*default*/, 'left', 'right', 'center', 'justify']
   ),
+  /**
+   * @platform android
+   */
+  textAlignVertical: ReactPropTypes.oneOf(
+    ['auto' /*default*/, 'top', 'bottom', 'center']
+  ),
   /**
    * @platform ios
    */
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java
index 7e87a8419d85..33e52fe95b21 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java
@@ -70,6 +70,7 @@ public class ViewProps {
   public static final String ON = "on";
   public static final String RESIZE_MODE = "resizeMode";
   public static final String TEXT_ALIGN = "textAlign";
+  public static final String TEXT_ALIGN_VERTICAL = "textAlignVertical";
 
   public static final String BORDER_WIDTH = "borderWidth";
   public static final String BORDER_LEFT_WIDTH = "borderLeftWidth";
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
index 8b6396ff2bd5..ed0d84935f8d 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
@@ -28,6 +28,8 @@
 import android.widget.TextView;
 
 import com.facebook.infer.annotation.Assertions;
+import com.facebook.react.bridge.JSApplicationCausedNativeException;
+import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.common.MapBuilder;
@@ -202,14 +204,34 @@ public void setUnderlineColor(ReactEditText view, @Nullable Integer underlineCol
     }
   }
 
-  @ReactProp(name = "textAlign")
-  public void setTextAlign(ReactEditText view, int gravity) {
-    view.setGravityHorizontal(gravity);
+  @ReactProp(name = ViewProps.TEXT_ALIGN)
+  public void setTextAlign(ReactEditText view, @Nullable String textAlign) {
+    if (textAlign == null || "auto".equals(textAlign)) {
+      view.setGravityHorizontal(Gravity.NO_GRAVITY);
+    } else if ("left".equals(textAlign)) {
+      view.setGravityHorizontal(Gravity.LEFT);
+    } else if ("right".equals(textAlign)) {
+      view.setGravityHorizontal(Gravity.RIGHT);
+    } else if ("center".equals(textAlign)) {
+      view.setGravityHorizontal(Gravity.CENTER_HORIZONTAL);
+    } else {
+      throw new JSApplicationIllegalArgumentException("Invalid textAlign: " + textAlign);
+    }
   }
 
-  @ReactProp(name = "textAlignVertical")
-  public void setTextAlignVertical(ReactEditText view, int gravity) {
-    view.setGravityVertical(gravity);
+  @ReactProp(name = ViewProps.TEXT_ALIGN_VERTICAL)
+  public void setTextAlignVertical(ReactEditText view, @Nullable String textAlignVertical) {
+    if (textAlignVertical == null || "auto".equals(textAlignVertical)) {
+      view.setGravityVertical(Gravity.NO_GRAVITY);
+    } else if ("top".equals(textAlignVertical)) {
+      view.setGravityVertical(Gravity.TOP);
+    } else if ("bottom".equals(textAlignVertical)) {
+      view.setGravityVertical(Gravity.BOTTOM);
+    } else if ("center".equals(textAlignVertical)) {
+      view.setGravityVertical(Gravity.CENTER_VERTICAL);
+    } else {
+      throw new JSApplicationIllegalArgumentException("Invalid textAlignVertical: " + textAlignVertical);
+    }
   }
 
   @ReactProp(name = "editable", defaultBoolean = true)
@@ -474,16 +496,6 @@ public void onSelectionChanged(int start, int end) {
   @Override
   public @Nullable Map getExportedViewConstants() {
     return MapBuilder.of(
-        "TextAlign",
-        MapBuilder.of(
-            "start", Gravity.START,
-            "center", Gravity.CENTER_HORIZONTAL,
-            "end", Gravity.END),
-        "TextAlignVertical",
-        MapBuilder.of(
-            "top", Gravity.TOP,
-            "center", Gravity.CENTER_VERTICAL,
-            "bottom", Gravity.BOTTOM),
         "AutoCapitalizationType",
         MapBuilder.of(
             "none",

From 2263cddd027601a4cf1a5aa4a9a96b349354c251 Mon Sep 17 00:00:00 2001
From: Hedger Wang <hedger@fb.com>
Date: Thu, 21 Jan 2016 11:18:18 -0800
Subject: [PATCH 0836/1411] Enable ES7 async functions in jest

Reviewed By: voideanvalue

Differential Revision: D2840780

fb-gh-sync-id: b86eed0078115d41e4400074f41244e4ae688762
---
 jestSupport/env.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/jestSupport/env.js b/jestSupport/env.js
index 0d3a757d9bd4..66cad00103b8 100644
--- a/jestSupport/env.js
+++ b/jestSupport/env.js
@@ -16,5 +16,6 @@ global.__fbBatchedBridgeConfig = {
 };
 
 global.Promise = require('promise');
+global.regeneratorRuntime = require.requireActual('regenerator/runtime');
 
 jest.setMock('ErrorUtils', require('ErrorUtils'));

From c2d75d7a65a2bdf6e1e24a9ce887f9492be477de Mon Sep 17 00:00:00 2001
From: Sokovikov <skv-headless@yandex.ru>
Date: Thu, 21 Jan 2016 11:43:51 -0800
Subject: [PATCH 0837/1411] Android AppState

Summary: Closes https://github.com/facebook/react-native/pull/5152

Reviewed By: svcscm

Differential Revision: D2850250

Pulled By: mkonicek

fb-gh-sync-id: 0b5063fa7121d4e304a70da8573c9ba1d05a757c
---
 Examples/UIExplorer/AppStateExample.js        |  80 ++++++++++
 Examples/UIExplorer/UIExplorerList.android.js |   1 +
 Examples/UIExplorer/UIExplorerList.ios.js     |   1 +
 Libraries/AppState/AppState.js                | 147 ++++++++++++++++++
 Libraries/react-native/react-native.js        |   1 +
 Libraries/react-native/react-native.js.flow   |   1 +
 .../modules/appstate/AppStateModule.java      |  76 +++++++++
 .../react/shell/MainReactPackage.java         |  14 +-
 website/server/extractDocs.js                 |   1 +
 9 files changed, 316 insertions(+), 6 deletions(-)
 create mode 100644 Examples/UIExplorer/AppStateExample.js
 create mode 100644 Libraries/AppState/AppState.js
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java

diff --git a/Examples/UIExplorer/AppStateExample.js b/Examples/UIExplorer/AppStateExample.js
new file mode 100644
index 000000000000..07d70be82de7
--- /dev/null
+++ b/Examples/UIExplorer/AppStateExample.js
@@ -0,0 +1,80 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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 AppStateExample
+ * @flow
+ */
+'use strict';
+
+var React = require('react-native');
+var {
+  AppState,
+  Text,
+  View
+} = React;
+
+var AppStateSubscription = React.createClass({
+  getInitialState() {
+    return {
+      appState: AppState.currentState,
+      previousAppStates: [],
+    };
+  },
+  componentDidMount: function() {
+    AppState.addEventListener('change', this._handleAppStateChange);
+  },
+  componentWillUnmount: function() {
+    AppState.removeEventListener('change', this._handleAppStateChange);
+  },
+  _handleAppStateChange: function(appState) {
+    var previousAppStates = this.state.previousAppStates.slice();
+    previousAppStates.push(this.state.appState);
+    this.setState({
+      appState,
+      previousAppStates,
+    });
+  },
+  render() {
+    if (this.props.showCurrentOnly) {
+      return (
+        <View>
+          <Text>{this.state.appState}</Text>
+        </View>
+      );
+    }
+    return (
+      <View>
+        <Text>{JSON.stringify(this.state.previousAppStates)}</Text>
+      </View>
+    );
+  }
+});
+
+exports.title = 'AppState';
+exports.description = 'app background status';
+exports.examples = [
+  {
+    title: 'AppState.currentState',
+    description: 'Can be null on app initialization',
+    render() { return <Text>{AppState.currentState}</Text>; }
+  },
+  {
+    title: 'Subscribed AppState:',
+    description: 'This changes according to the current state, so you can only ever see it rendered as "active"',
+    render(): ReactElement { return <AppStateSubscription showCurrentOnly={true} />; }
+  },
+  {
+    title: 'Previous states:',
+    render(): ReactElement { return <AppStateSubscription showCurrentOnly={false} />; }
+  },
+];
diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index 7d56b94f87df..01e8a331e62a 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -43,6 +43,7 @@ var COMPONENTS = [
 var APIS = [
   require('./AccessibilityAndroidExample.android'),
   require('./AlertExample').AlertExample,
+  require('./AppStateExample'),
   require('./BorderExample'),
   require('./CameraRollExample'),
   require('./ClipboardExample'),
diff --git a/Examples/UIExplorer/UIExplorerList.ios.js b/Examples/UIExplorer/UIExplorerList.ios.js
index 92f0f0bad1b8..f33d97c86134 100644
--- a/Examples/UIExplorer/UIExplorerList.ios.js
+++ b/Examples/UIExplorer/UIExplorerList.ios.js
@@ -64,6 +64,7 @@ var APIS = [
   require('./AnimatedExample'),
   require('./AnimatedGratuitousApp/AnExApp'),
   require('./AppStateIOSExample'),
+  require('./AppStateExample'),
   require('./AsyncStorageExample'),
   require('./BorderExample'),
   require('./BoxShadowExample'),
diff --git a/Libraries/AppState/AppState.js b/Libraries/AppState/AppState.js
new file mode 100644
index 000000000000..0bd7618fdb1b
--- /dev/null
+++ b/Libraries/AppState/AppState.js
@@ -0,0 +1,147 @@
+/**
+ * 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 AppState
+ * @flow
+ */
+'use strict';
+
+var Map = require('Map');
+var NativeModules = require('NativeModules');
+var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
+var RCTAppState = NativeModules.AppState;
+
+var logError = require('logError');
+var invariant = require('invariant');
+
+var _eventHandlers = {
+  change: new Map(),
+  memoryWarning: new Map(),
+};
+
+/**
+ * `AppState` can tell you if the app is in the foreground or background,
+ * and notify you when the state changes.
+ *
+ * AppState is frequently used to determine the intent and proper behavior when
+ * handling push notifications.
+ *
+ * ### App States
+ *
+ *  - `active` - The app is running in the foreground
+ *  - `background` - The app is running in the background. The user is either
+ *     in another app or on the home screen
+ *  - `inactive` - This is a transition state that currently never happens for
+ *     typical React Native apps.
+ *
+ * For more information, see
+ * [Apple's documentation](https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html)
+ *
+ * ### Basic Usage
+ *
+ * To see the current state, you can check `AppState.currentState`, which
+ * will be kept up-to-date. However, `currentState` will be null at launch
+ * while `AppState` retrieves it over the bridge.
+ *
+ * ```
+ * getInitialState: function() {
+ *   return {
+ *     currentAppState: AppState.currentState,
+ *   };
+ * },
+ * componentDidMount: function() {
+ *   AppState.addEventListener('change', this._handleAppStateChange);
+ * },
+ * componentWillUnmount: function() {
+ *   AppState.removeEventListener('change', this._handleAppStateChange);
+ * },
+ * _handleAppStateChange: function(currentAppState) {
+ *   this.setState({ currentAppState, });
+ * },
+ * render: function() {
+ *   return (
+ *     <Text>Current state is: {this.state.currentAppState}</Text>
+ *   );
+ * },
+ * ```
+ *
+ * This example will only ever appear to say "Current state is: active" because
+ * the app is only visible to the user when in the `active` state, and the null
+ * state will happen only momentarily.
+ */
+
+var AppState = {
+
+  /**
+   * Add a handler to AppState changes by listening to the `change` event type
+   * and providing the handler
+   */
+  addEventListener: function(
+    type: string,
+    handler: Function
+  ) {
+    invariant(
+      ['change', 'memoryWarning'].indexOf(type) !== -1,
+      'Trying to subscribe to unknown event: "%s"', type
+    );
+    if (type === 'change') {
+      _eventHandlers[type].set(handler, RCTDeviceEventEmitter.addListener(
+        'appStateDidChange',
+        (appStateData) => {
+          handler(appStateData.app_state);
+        }
+      ));
+    } else if (type === 'memoryWarning') {
+      _eventHandlers[type].set(handler, RCTDeviceEventEmitter.addListener(
+        'memoryWarning',
+        handler
+      ));
+    }
+  },
+
+  /**
+   * Remove a handler by passing the `change` event type and the handler
+   */
+  removeEventListener: function(
+    type: string,
+    handler: Function
+  ) {
+    invariant(
+      ['change', 'memoryWarning'].indexOf(type) !== -1,
+      'Trying to remove listener for unknown event: "%s"', type
+    );
+    if (!_eventHandlers[type].has(handler)) {
+      return;
+    }
+    _eventHandlers[type].get(handler).remove();
+    _eventHandlers[type].delete(handler);
+  },
+
+  // TODO: getCurrentAppState callback seems to be called at a really late stage
+  // after app launch. Trying to get currentState when mounting App component
+  // will likely to have the initial value here.
+  // Initialize to 'active' instead of null.
+  currentState: ('active' : ?string),
+
+};
+
+RCTDeviceEventEmitter.addListener(
+  'appStateDidChange',
+  (appStateData) => {
+    AppState.currentState = appStateData.app_state;
+  }
+);
+
+RCTAppState.getCurrentAppState(
+  (appStateData) => {
+    AppState.currentState = appStateData.app_state;
+  },
+  logError
+);
+
+module.exports = AppState;
diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js
index 16ca8ad82bcd..ade020c539de 100644
--- a/Libraries/react-native/react-native.js
+++ b/Libraries/react-native/react-native.js
@@ -60,6 +60,7 @@ var ReactNative = {
   get AlertIOS() { return require('AlertIOS'); },
   get Animated() { return require('Animated'); },
   get AppRegistry() { return require('AppRegistry'); },
+  get AppState() { return require('AppState'); },
   get AppStateIOS() { return require('AppStateIOS'); },
   get AsyncStorage() { return require('AsyncStorage'); },
   get BackAndroid() { return require('BackAndroid'); },
diff --git a/Libraries/react-native/react-native.js.flow b/Libraries/react-native/react-native.js.flow
index 2eb844c4d9b3..618eb2e05b1e 100644
--- a/Libraries/react-native/react-native.js.flow
+++ b/Libraries/react-native/react-native.js.flow
@@ -72,6 +72,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
   AlertIOS: require('AlertIOS'),
   Animated: require('Animated'),
   AppRegistry: require('AppRegistry'),
+  AppState: require('AppState'),
   AppStateIOS: require('AppStateIOS'),
   AsyncStorage: require('AsyncStorage'),
   BackAndroid: require('BackAndroid'),
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java
new file mode 100644
index 000000000000..a3daa95a78bc
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java
@@ -0,0 +1,76 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.modules.appstate;
+
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.Callback;
+import com.facebook.react.bridge.LifecycleEventListener;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter;
+
+public class AppStateModule extends ReactContextBaseJavaModule
+        implements LifecycleEventListener {
+
+  public static final String APP_STATE_ACTIVE = "active";
+  public static final String APP_STATE_BACKGROUND = "background";
+
+  private String mAppState = "uninitialized";
+
+  public AppStateModule(ReactApplicationContext reactContext) {
+    super(reactContext);
+  }
+
+  @Override
+  public String getName() {
+    return "AppState";
+  }
+
+  @Override
+  public void initialize() {
+    getReactApplicationContext().addLifecycleEventListener(this);
+  }
+
+  @ReactMethod
+  public void getCurrentAppState(Callback success, Callback error) {
+    success.invoke(createAppStateEventMap());
+  }
+
+  @Override
+  public void onHostResume() {
+    mAppState = APP_STATE_ACTIVE;
+    sendAppStateChangeEvent();
+  }
+
+  @Override
+  public void onHostPause() {
+    mAppState = APP_STATE_BACKGROUND;
+    sendAppStateChangeEvent();
+  }
+
+  @Override
+  public void onHostDestroy() {
+    // do not set state to destroyed, do not send an event. By the current implementation, the
+    // catalyst instance is going to be immediately dropped, and all JS calls with it.
+  }
+
+  private WritableMap createAppStateEventMap() {
+    WritableMap appState = Arguments.createMap();
+    appState.putString("app_state", mAppState);
+    return appState;
+  }
+
+  private void sendAppStateChangeEvent() {
+    getReactApplicationContext().getJSModule(RCTDeviceEventEmitter.class)
+            .emit("appStateDidChange", createAppStateEventMap());
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
index 5f0d2d4ead99..fa3e97e10b5e 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
@@ -26,6 +26,7 @@
 import com.facebook.react.modules.network.NetworkingModule;
 import com.facebook.react.modules.storage.AsyncStorageModule;
 import com.facebook.react.modules.toast.ToastModule;
+import com.facebook.react.modules.appstate.AppStateModule;
 import com.facebook.react.modules.websocket.WebSocketModule;
 import com.facebook.react.uimanager.ViewManager;
 import com.facebook.react.views.art.ARTRenderableViewManager;
@@ -59,6 +60,7 @@ public class MainReactPackage implements ReactPackage {
   @Override
   public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
     return Arrays.<NativeModule>asList(
+      new AppStateModule(reactContext),
       new AsyncStorageModule(reactContext),
       new CameraRollManager(reactContext),
       new ClipboardModule(reactContext),
@@ -68,8 +70,8 @@ public List<NativeModule> createNativeModules(ReactApplicationContext reactConte
       new LocationModule(reactContext),
       new NetworkingModule(reactContext),
       new NetInfoModule(reactContext),
-      new WebSocketModule(reactContext),
-      new ToastModule(reactContext));
+      new ToastModule(reactContext),
+      new WebSocketModule(reactContext));
   }
 
   @Override
@@ -91,17 +93,17 @@ public List<ViewManager> createViewManagers(ReactApplicationContext reactContext
       new ReactImageManager(),
       new ReactProgressBarViewManager(),
       new ReactRawTextManager(),
-      new RecyclerViewBackedScrollViewManager(),
       new ReactScrollViewManager(),
       new ReactSwitchManager(),
+      new ReactTextInlineImageViewManager(),
       new ReactTextInputManager(),
       new ReactTextViewManager(),
       new ReactToolbarManager(),
       new ReactViewManager(),
       new ReactViewPagerManager(),
-      new ReactTextInlineImageViewManager(),
       new ReactVirtualTextViewManager(),
-      new SwipeRefreshLayoutManager(),
-      new ReactWebViewManager());
+      new ReactWebViewManager(),
+      new RecyclerViewBackedScrollViewManager(),
+      new SwipeRefreshLayoutManager());
   }
 }
diff --git a/website/server/extractDocs.js b/website/server/extractDocs.js
index e9b25cd4e7ca..8b32daff2802 100644
--- a/website/server/extractDocs.js
+++ b/website/server/extractDocs.js
@@ -225,6 +225,7 @@ var apis = [
   '../Libraries/Animated/src/AnimatedImplementation.js',
   '../Libraries/AppRegistry/AppRegistry.js',
   '../Libraries/AppStateIOS/AppStateIOS.ios.js',
+  '../Libraries/AppState/AppState.js',
   '../Libraries/Storage/AsyncStorage.js',
   '../Libraries/Utilities/BackAndroid.android.js',
   '../Libraries/CameraRoll/CameraRoll.js',

From 29238eb3eba0c4d73e4a0e67f2d7de72bf0a1b83 Mon Sep 17 00:00:00 2001
From: Andrei Coman <andreic@fb.com>
Date: Thu, 21 Jan 2016 11:59:40 -0800
Subject: [PATCH 0838/1411] Remove timeouts from react instance loading

Reviewed By: lexs

Differential Revision: D2847813

fb-gh-sync-id: b4cb08633da8e637b0ec25a29bc21b963e337deb
---
 .../react/bridge/CatalystInstanceImpl.java    | 12 ++++------
 .../common/futures/SimpleSettableFuture.java  | 22 +++++++++----------
 2 files changed, 15 insertions(+), 19 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
index 31fe7a528cc8..01ceb8e8b4b0 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
@@ -16,18 +16,17 @@
 import java.util.Collection;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import com.facebook.common.logging.FLog;
+import com.facebook.infer.annotation.Assertions;
+import com.facebook.proguard.annotations.DoNotStrip;
 import com.facebook.react.bridge.queue.CatalystQueueConfiguration;
 import com.facebook.react.bridge.queue.CatalystQueueConfigurationImpl;
 import com.facebook.react.bridge.queue.CatalystQueueConfigurationSpec;
 import com.facebook.react.bridge.queue.QueueThreadExceptionHandler;
-import com.facebook.proguard.annotations.DoNotStrip;
 import com.facebook.react.common.ReactConstants;
 import com.facebook.react.common.annotations.VisibleForTesting;
-import com.facebook.infer.annotation.Assertions;
 import com.facebook.systrace.Systrace;
 import com.facebook.systrace.TraceListener;
 
@@ -41,9 +40,6 @@
 @DoNotStrip
 public class CatalystInstanceImpl implements CatalystInstance {
 
-  private static final int BRIDGE_SETUP_TIMEOUT_MS = 30000;
-  private static final int LOAD_JS_BUNDLE_TIMEOUT_MS = 30000;
-
   private static final AtomicInteger sNextInstanceIdForTrace = new AtomicInteger(1);
 
   // Access from any thread
@@ -96,7 +92,7 @@ public ReactBridge call() throws Exception {
                 Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
               }
             }
-          }).get(BRIDGE_SETUP_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+          }).get();
     } catch (Exception t) {
       throw new RuntimeException("Failed to initialize bridge", t);
     }
@@ -159,7 +155,7 @@ public Boolean call() throws Exception {
 
               return true;
             }
-          }).get(LOAD_JS_BUNDLE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+          }).get();
     } catch (Exception t) {
       throw new RuntimeException(t);
     }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java b/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java
index b2809ae37089..063279ad353e 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java
@@ -37,8 +37,8 @@ public void set(T result) {
   }
 
   /**
-   * Sets the eception. If another thread has called {@link #get}, they will immediately receive the
-   * exception. set or setException must only be called once.
+   * Sets the exception. If another thread has called {@link #get}, they will immediately receive
+   * the exception. set or setException must only be called once.
    */
   public void setException(Exception exception) {
     checkNotSet();
@@ -61,10 +61,14 @@ public boolean isDone() {
     return mReadyLatch.getCount() == 0;
   }
 
-  @Deprecated
   @Override
-  public T get() throws InterruptedException, ExecutionException {
-    throw new UnsupportedOperationException("Must use a timeout");
+  public @Nullable T get() throws InterruptedException, ExecutionException {
+    mReadyLatch.await();
+    if (mException != null) {
+      throw new ExecutionException(mException);
+    }
+
+    return mResult;
   }
 
   /**
@@ -77,12 +81,8 @@ public T get() throws InterruptedException, ExecutionException {
   @Override
   public @Nullable T get(long timeout, TimeUnit unit) throws
       InterruptedException, ExecutionException, TimeoutException {
-    try {
-      if (!mReadyLatch.await(timeout, unit)) {
-        throw new TimeoutException("Timed out waiting for result");
-      }
-    } catch (InterruptedException e) {
-      throw new RuntimeException(e);
+    if (!mReadyLatch.await(timeout, unit)) {
+      throw new TimeoutException("Timed out waiting for result");
     }
     if (mException != null) {
       throw new ExecutionException(mException);

From 528e30987aba8848f8c8815f00c42ecb2ce0919a Mon Sep 17 00:00:00 2001
From: "tfallon@mail.depaul.edu" <tfallon@mail.depaul.edu>
Date: Thu, 21 Jan 2016 12:59:41 -0800
Subject: [PATCH 0839/1411] Adding ETag handling to packager improves local
 development

Summary: Closes https://github.com/facebook/react-native/pull/2473

Reviewed By: svcscm

Differential Revision: D2669385

Pulled By: mkonicek

fb-gh-sync-id: bb9ee4a309a05e0da0ccc7663a373f4a53b9a0a2
---
 .../AssetServer/__tests__/AssetServer-test.js |  2 +-
 packager/react-packager/src/Bundler/Bundle.js |  6 ++
 .../src/Bundler/__tests__/Bundle-test.js      | 10 ++++
 .../src/Server/__tests__/Server-test.js       | 55 ++++++++++++++-----
 packager/react-packager/src/Server/index.js   |  8 ++-
 5 files changed, 66 insertions(+), 15 deletions(-)

diff --git a/packager/react-packager/src/AssetServer/__tests__/AssetServer-test.js b/packager/react-packager/src/AssetServer/__tests__/AssetServer-test.js
index 7a544a270e03..1cb90b334bcc 100644
--- a/packager/react-packager/src/AssetServer/__tests__/AssetServer-test.js
+++ b/packager/react-packager/src/AssetServer/__tests__/AssetServer-test.js
@@ -185,7 +185,7 @@ describe('AssetServer', () => {
     });
   });
 
-  describe('assetSerer.getAssetData', () => {
+  describe('assetServer.getAssetData', () => {
     pit('should get assetData', () => {
       const hash = {
         update: jest.genMockFn(),
diff --git a/packager/react-packager/src/Bundler/Bundle.js b/packager/react-packager/src/Bundler/Bundle.js
index e457e203f21a..4f54e3be3919 100644
--- a/packager/react-packager/src/Bundler/Bundle.js
+++ b/packager/react-packager/src/Bundler/Bundle.js
@@ -14,6 +14,7 @@ const BundleBase = require('./BundleBase');
 const UglifyJS = require('uglify-js');
 const ModuleTransport = require('../lib/ModuleTransport');
 const Activity = require('../Activity');
+const crypto = require('crypto');
 
 const SOURCEMAPPING_URL = '\n\/\/# sourceMappingURL=';
 
@@ -256,6 +257,11 @@ class Bundle extends BundleBase {
     return map;
   }
 
+  getEtag() {
+    var eTag = crypto.createHash('md5').update(this.getSource()).digest('hex');
+    return eTag;
+  }
+
   _getMappings() {
     const modules = super.getModules();
 
diff --git a/packager/react-packager/src/Bundler/__tests__/Bundle-test.js b/packager/react-packager/src/Bundler/__tests__/Bundle-test.js
index 1180f0a2bb32..b82f4a6c272a 100644
--- a/packager/react-packager/src/Bundler/__tests__/Bundle-test.js
+++ b/packager/react-packager/src/Bundler/__tests__/Bundle-test.js
@@ -15,6 +15,7 @@ const ModuleTransport = require('../../lib/ModuleTransport');
 const Promise = require('Promise');
 const SourceMapGenerator = require('source-map').SourceMapGenerator;
 const UglifyJS = require('uglify-js');
+const crypto = require('crypto');
 
 describe('Bundle', () => {
   var bundle;
@@ -301,6 +302,15 @@ describe('Bundle', () => {
       });
     });
   });
+
+  describe('getEtag()', function() {
+    it('should return an etag', function() {
+      var bundle = new Bundle('test_url');
+      bundle.finalize({});
+      var eTag = crypto.createHash('md5').update(bundle.getSource()).digest('hex');
+      expect(bundle.getEtag()).toEqual(eTag);
+    });
+  });
 });
 
 
diff --git a/packager/react-packager/src/Server/__tests__/Server-test.js b/packager/react-packager/src/Server/__tests__/Server-test.js
index a21462cac7ba..123134f84fe4 100644
--- a/packager/react-packager/src/Server/__tests__/Server-test.js
+++ b/packager/react-packager/src/Server/__tests__/Server-test.js
@@ -14,7 +14,8 @@ jest.setMock('worker-farm', function() { return () => {}; })
     .dontMock('url')
     .setMock('timers', { setImmediate: (fn) => setTimeout(fn, 0) })
     .setMock('uglify-js')
-    .dontMock('../');
+    .dontMock('../')
+    .setMock('crypto');
 
 const Promise = require('promise');
 
@@ -34,12 +35,17 @@ describe('processRequest', () => {
      polyfillModuleNames: null
   };
 
-  const makeRequest = (reqHandler, requrl) => new Promise(resolve =>
+  const makeRequest = (reqHandler, requrl, reqOptions) => new Promise(resolve =>
     reqHandler(
-      { url: requrl },
+      { url: requrl, headers:{}, ...reqOptions },
       {
-        setHeader: jest.genMockFunction(),
-        end: res => resolve(res),
+        headers: {},
+        getHeader(header) { return this.headers[header]; },
+        setHeader(header, value) { this.headers[header] = value; },
+        end(body) {
+          this.body = body;
+          resolve(this);
+        },
       },
       { next: () => {} },
     )
@@ -55,6 +61,7 @@ describe('processRequest', () => {
       Promise.resolve({
         getSource: () => 'this is the source',
         getSourceMap: () => 'this is the source map',
+        getEtag: () => 'this is an etag',
       })
     );
 
@@ -76,9 +83,10 @@ describe('processRequest', () => {
   pit('returns JS bundle source on request of *.bundle', () => {
     return makeRequest(
       requestHandler,
-      'mybundle.bundle?runModule=true'
+      'mybundle.bundle?runModule=true',
+      null
     ).then(response =>
-      expect(response).toEqual('this is the source')
+      expect(response.body).toEqual('this is the source')
     );
   });
 
@@ -87,16 +95,35 @@ describe('processRequest', () => {
       requestHandler,
       'mybundle.runModule.bundle'
     ).then(response =>
-      expect(response).toEqual('this is the source')
+      expect(response.body).toEqual('this is the source')
     );
   });
 
+  pit('returns ETag header on request of *.bundle', () => {
+    return makeRequest(
+      requestHandler,
+      'mybundle.bundle?runModule=true'
+    ).then(response => {
+      expect(response.getHeader('ETag')).toBeDefined()
+    });
+  });
+
+  pit('returns 304 on request of *.bundle when if-none-match equals the ETag', () => {
+    return makeRequest(
+      requestHandler,
+      'mybundle.bundle?runModule=true',
+      { headers : { 'if-none-match' : 'this is an etag' } }
+    ).then(response => {
+      expect(response.statusCode).toEqual(304)
+    });
+  });
+
   pit('returns sourcemap on request of *.map', () => {
     return makeRequest(
       requestHandler,
       'mybundle.map?runModule=true'
     ).then(response =>
-      expect(response).toEqual('this is the source map')
+      expect(response.body).toEqual('this is the source map')
     );
   });
 
@@ -105,7 +132,7 @@ describe('processRequest', () => {
       requestHandler,
       'index.ios.includeRequire.bundle'
     ).then(response => {
-      expect(response).toEqual('this is the source');
+      expect(response.body).toEqual('this is the source');
       expect(Bundler.prototype.bundle).toBeCalledWith({
         entryFile: 'index.ios.js',
         inlineSourceMap: false,
@@ -126,7 +153,7 @@ describe('processRequest', () => {
       requestHandler,
       'index.bundle?platform=ios'
     ).then(function(response) {
-      expect(response).toEqual('this is the source');
+      expect(response.body).toEqual('this is the source');
       expect(Bundler.prototype.bundle).toBeCalledWith({
         entryFile: 'index.js',
         inlineSourceMap: false,
@@ -183,12 +210,14 @@ describe('processRequest', () => {
           Promise.resolve({
             getSource: () => 'this is the first source',
             getSourceMap: () => {},
+            getEtag: () => () => 'this is an etag',
           })
         )
         .mockReturnValue(
           Promise.resolve({
             getSource: () => 'this is the rebuilt source',
             getSourceMap: () => {},
+            getEtag: () => () => 'this is an etag',
           })
         );
 
@@ -200,7 +229,7 @@ describe('processRequest', () => {
 
       makeRequest(requestHandler, 'mybundle.bundle?runModule=true')
         .done(response => {
-          expect(response).toEqual('this is the first source');
+          expect(response.body).toEqual('this is the first source');
           expect(bundleFunc.mock.calls.length).toBe(1);
         });
 
@@ -214,7 +243,7 @@ describe('processRequest', () => {
 
       makeRequest(requestHandler, 'mybundle.bundle?runModule=true')
         .done(response =>
-          expect(response).toEqual('this is the rebuilt source')
+          expect(response.body).toEqual('this is the rebuilt source')
         );
       jest.runAllTicks();
     }
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index 63432090570c..3bb8a9c0eafb 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -430,7 +430,13 @@ class Server {
             dev: options.dev,
           });
           res.setHeader('Content-Type', 'application/javascript');
-          res.end(bundleSource);
+          res.setHeader('ETag', p.getEtag());
+          if (req.headers['if-none-match'] === res.getHeader('ETag')){
+            res.statusCode = 304;
+            res.end();
+          } else {
+            res.end(bundleSource);
+          }
           Activity.endEvent(startReqEventId);
         } else if (requestType === 'map') {
           var sourceMap = p.getSourceMap({

From c14cc123d5be04f109ba2209a3393ee2ffa84149 Mon Sep 17 00:00:00 2001
From: Martin Kralik <kralik@fb.com>
Date: Thu, 21 Jan 2016 13:43:58 -0800
Subject: [PATCH 0840/1411] API for cancelling RCTTouchHandler

Reviewed By: spicyj

Differential Revision: D2846573

fb-gh-sync-id: 652864c773d03c24f0d68dd8335401eb052fc1bf
---
 React/Base/RCTRootView.h     | 19 +++++++++++++++++++
 React/Base/RCTRootView.m     | 11 +++++++++--
 React/Base/RCTTouchHandler.h |  1 +
 React/Base/RCTTouchHandler.m |  6 ++++++
 4 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/React/Base/RCTRootView.h b/React/Base/RCTRootView.h
index b11881de9559..ba1fe8712c53 100644
--- a/React/Base/RCTRootView.h
+++ b/React/Base/RCTRootView.h
@@ -123,6 +123,25 @@ extern NSString *const RCTContentDidAppearNotification;
  */
 @property (nonatomic, strong) UIView *loadingView;
 
+/**
+ * Calling this will result in emitting a "touches cancelled" event to js,
+ * which effectively cancels all js "gesture recognizers" such as as touchable
+ * (unless they explicitely ignore cancellation events, but noone should do that).
+ *
+ * This API is exposed for integration purposes where you embed RN rootView
+ * in a native view with a native gesture recognizer,
+ * whose activation should prevent any in-flight js "gesture recognizer" from activating.
+ *
+ * An example would be RN rootView embedded in an UIScrollView.
+ * When you touch down on a touchable component and drag your finger up,
+ * you don't want any touch to be registered as soon as the UIScrollView starts scrolling.
+ *
+ * Note that this doesn't help with tapping on a touchable element that is being scrolled,
+ * unless you can call cancelTouches exactly between "touches began" and "touches ended" events.
+ * This is a reason why this API may be soon removed in favor of a better solution.
+ */
+- (void)cancelTouches;
+
 /**
  * Timings for hiding the loading view after the content has loaded. Both of
  * these values default to 0.25 seconds.
diff --git a/React/Base/RCTRootView.m b/React/Base/RCTRootView.m
index f53c278b30b3..c0481e07638b 100644
--- a/React/Base/RCTRootView.m
+++ b/React/Base/RCTRootView.m
@@ -38,6 +38,8 @@ @interface RCTRootContentView : RCTView <RCTInvalidating>
 
 @property (nonatomic, readonly) BOOL contentHasAppeared;
 
+@property (nonatomic, readonly, strong) RCTTouchHandler *touchHandler;
+
 - (instancetype)initWithFrame:(CGRect)frame bridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
 
 @end
@@ -257,6 +259,11 @@ - (void)dealloc
   [_contentView invalidate];
 }
 
+- (void)cancelTouches
+{
+  [[_contentView touchHandler] cancel];
+}
+
 @end
 
 @implementation RCTUIManager (RCTRootView)
@@ -273,7 +280,6 @@ - (NSNumber *)allocateRootTag
 @implementation RCTRootContentView
 {
   __weak RCTBridge *_bridge;
-  RCTTouchHandler *_touchHandler;
   UIColor *_backgroundColor;
 }
 
@@ -335,7 +341,8 @@ - (void)setUp
    * the react tag is assigned every time we load new content.
    */
   self.reactTag = [_bridge.uiManager allocateRootTag];
-  [self addGestureRecognizer:[[RCTTouchHandler alloc] initWithBridge:_bridge]];
+  _touchHandler = [[RCTTouchHandler alloc] initWithBridge:_bridge];
+  [self addGestureRecognizer:_touchHandler];
   [_bridge.uiManager registerRootView:self];
 }
 
diff --git a/React/Base/RCTTouchHandler.h b/React/Base/RCTTouchHandler.h
index 9d3f1cbd4f92..5ea1919930d0 100644
--- a/React/Base/RCTTouchHandler.h
+++ b/React/Base/RCTTouchHandler.h
@@ -16,5 +16,6 @@
 @interface RCTTouchHandler : UIGestureRecognizer
 
 - (instancetype)initWithBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
+- (void)cancel;
 
 @end
diff --git a/React/Base/RCTTouchHandler.m b/React/Base/RCTTouchHandler.m
index 707830aab07f..f2490a7ad6e9 100644
--- a/React/Base/RCTTouchHandler.m
+++ b/React/Base/RCTTouchHandler.m
@@ -311,4 +311,10 @@ - (void)reset
   _dispatchedInitialTouches = NO;
 }
 
+- (void)cancel
+{
+  self.enabled = NO;
+  self.enabled = YES;
+}
+
 @end

From 0963192b18cb63f9da3b3f32da12b07e48e5d023 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Thu, 21 Jan 2016 13:56:23 -0800
Subject: [PATCH 0841/1411] Bump js/package.json version to clear cache

Reviewed By: sam-swarr

Differential Revision: D2851399

fb-gh-sync-id: 0fbeb7d4c6d669f981e3f5139387e506a3670931
---
 packager/package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packager/package.json b/packager/package.json
index c5d4832e65ec..117369a73bf1 100644
--- a/packager/package.json
+++ b/packager/package.json
@@ -1,5 +1,5 @@
 {
-  "version": "0.1.2",
+  "version": "0.1.3",
   "name": "react-native-packager",
   "description": "Build native apps with React!",
   "repository": {

From 17e1ceb5437049f794b74507feb6856e3450d2b2 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Thu, 21 Jan 2016 13:57:32 -0800
Subject: [PATCH 0842/1411] =?UTF-8?q?Add=20ability=20to=20load=20=E2=80=9C?=
 =?UTF-8?q?unbundles=E2=80=9D=20to=20android?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Summary:
public

This adds the ability to load “unbundles” in RN android apps. Unbundles are created by invoking the packager with the `unbundle` command rather than `bundle`.

The code detects usage of an “unbundle” by checking for the existence of a specific asset.

Reviewed By: astreet

Differential Revision: D2739596

fb-gh-sync-id: d0813c003fe0fa7b47798b970f56707079bfa5d7
---
 ReactAndroid/src/main/jni/react/Android.mk    |  1 +
 ReactAndroid/src/main/jni/react/Bridge.cpp    | 14 +++
 ReactAndroid/src/main/jni/react/Bridge.h      | 14 +++
 ReactAndroid/src/main/jni/react/Executor.h    |  9 ++
 .../src/main/jni/react/JSCExecutor.cpp        | 71 +++++++++++++-
 ReactAndroid/src/main/jni/react/JSCExecutor.h | 15 +++
 .../src/main/jni/react/JSCHelpers.cpp         | 11 ++-
 ReactAndroid/src/main/jni/react/JSCHelpers.h  |  2 -
 .../src/main/jni/react/JSModulesUnbundle.cpp  | 94 +++++++++++++++++++
 .../src/main/jni/react/JSModulesUnbundle.h    | 48 ++++++++++
 ReactAndroid/src/main/jni/react/Value.cpp     |  1 -
 .../src/main/jni/react/jni/JSLoader.cpp       | 11 +--
 .../src/main/jni/react/jni/JSLoader.h         |  3 +-
 .../src/main/jni/react/jni/OnLoad.cpp         | 30 +++++-
 .../src/main/jni/react/jni/ProxyExecutor.cpp  |  6 ++
 .../src/main/jni/react/jni/ProxyExecutor.h    |  4 +
 .../bundle/output/unbundle/as-indexed-file.js |  2 +-
 .../Resolver/polyfills/require-unbundle.js    |  4 +-
 18 files changed, 313 insertions(+), 27 deletions(-)
 create mode 100644 ReactAndroid/src/main/jni/react/JSModulesUnbundle.cpp
 create mode 100644 ReactAndroid/src/main/jni/react/JSModulesUnbundle.h

diff --git a/ReactAndroid/src/main/jni/react/Android.mk b/ReactAndroid/src/main/jni/react/Android.mk
index cf522d8df70a..78abe5bd15c8 100644
--- a/ReactAndroid/src/main/jni/react/Android.mk
+++ b/ReactAndroid/src/main/jni/react/Android.mk
@@ -9,6 +9,7 @@ LOCAL_SRC_FILES := \
   JSCExecutor.cpp \
   JSCHelpers.cpp \
   JSCWebWorker.cpp \
+  JSModulesUnbundle.cpp \
   MethodCall.cpp \
   Value.cpp \
 
diff --git a/ReactAndroid/src/main/jni/react/Bridge.cpp b/ReactAndroid/src/main/jni/react/Bridge.cpp
index b9b0580c4a34..a06871c1eea0 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.cpp
+++ b/ReactAndroid/src/main/jni/react/Bridge.cpp
@@ -27,6 +27,13 @@ class JSThreadState {
     m_jsExecutor->executeApplicationScript(script, sourceURL);
   }
 
+  void loadApplicationUnbundle(
+      JSModulesUnbundle&& unbundle,
+      const std::string& startupCode,
+      const std::string& sourceURL) {
+    m_jsExecutor->loadApplicationUnbundle(std::move(unbundle), startupCode, sourceURL);
+  }
+
   void flush() {
     auto returnedJSON = m_jsExecutor->flush();
     m_callback(parseMethodCalls(returnedJSON), true /* = isEndOfBatch */);
@@ -95,6 +102,13 @@ void Bridge::executeApplicationScript(const std::string& script, const std::stri
   m_threadState->executeApplicationScript(script, sourceURL);
 }
 
+void Bridge::loadApplicationUnbundle(
+    JSModulesUnbundle&& unbundle,
+    const std::string& startupCode,
+    const std::string& sourceURL) {
+  m_threadState->loadApplicationUnbundle(std::move(unbundle), startupCode, sourceURL);
+}
+
 void Bridge::flush() {
   if (*m_destroyed) {
     return;
diff --git a/ReactAndroid/src/main/jni/react/Bridge.h b/ReactAndroid/src/main/jni/react/Bridge.h
index 1d0f159458be..c8f0be4c4305 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.h
+++ b/ReactAndroid/src/main/jni/react/Bridge.h
@@ -11,6 +11,7 @@
 #include "Value.h"
 #include "Executor.h"
 #include "MethodCall.h"
+#include "JSModulesUnbundle.h"
 
 namespace folly {
 
@@ -45,7 +46,20 @@ class Bridge : public Countable {
    */
   void invokeCallback(const double callbackId, const folly::dynamic& args);
 
+  /**
+   * Starts the JS application from an "bundle", i.e. a JavaScript file that
+   * contains code for all modules and a runtime that resolves and
+   * executes modules.
+   */
   void executeApplicationScript(const std::string& script, const std::string& sourceURL);
+  /**
+   * Starts the JS application from an "unbundle", i.e. a backend that stores
+   * and injects each module as individual file.
+   */
+  void loadApplicationUnbundle(
+    JSModulesUnbundle&& unbundle,
+    const std::string& startupCode,
+    const std::string& sourceURL);
   void setGlobalVariable(const std::string& propName, const std::string& jsonValue);
   bool supportsProfiling();
   void startProfiler(const std::string& title);
diff --git a/ReactAndroid/src/main/jni/react/Executor.h b/ReactAndroid/src/main/jni/react/Executor.h
index dd09d59069bf..b4697d6d52ef 100644
--- a/ReactAndroid/src/main/jni/react/Executor.h
+++ b/ReactAndroid/src/main/jni/react/Executor.h
@@ -6,6 +6,7 @@
 #include <vector>
 #include <memory>
 #include <jni/Countable.h>
+#include "JSModulesUnbundle.h"
 
 namespace folly {
 
@@ -35,6 +36,14 @@ class JSExecutor {
     const std::string& script,
     const std::string& sourceURL) = 0;
 
+  /**
+   * Add an application "unbundle" file
+   */
+  virtual void loadApplicationUnbundle(
+    JSModulesUnbundle&& bundle,
+    const std::string& startupCode,
+    const std::string& sourceURL) = 0;
+
   /**
    * Executes BatchedBridge.flushedQueue in JS to get the next queue of changes.
    */
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index f13c085e2fe5..44d2354c2bc4 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -14,6 +14,7 @@
 #include "Value.h"
 #include "jni/JMessageQueueThread.h"
 #include "jni/OnLoad.h"
+#include <react/JSCHelpers.h>
 
 #ifdef WITH_JSC_EXTRA_TRACING
 #include <react/JSCTracing.h>
@@ -152,12 +153,24 @@ void JSCExecutor::executeApplicationScript(
   env->DeleteLocalRef(startStringMarker);
   env->DeleteLocalRef(endStringMarker);
 
-  String jsSourceURL(sourceURL.c_str());
   #ifdef WITH_FBSYSTRACE
   FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor::executeApplicationScript",
     "sourceURL", sourceURL);
   #endif
-  evaluateScript(m_context, jsScript, jsSourceURL);
+  evaluateScript(m_context, jsScript, String(sourceURL.c_str()));
+}
+
+void JSCExecutor::loadApplicationUnbundle(
+    JSModulesUnbundle&& unbundle,
+    const std::string& startupCode,
+    const std::string& sourceURL) {
+
+  m_unbundle = std::move(unbundle);
+  if (!m_isUnbundleInitialized) {
+    m_isUnbundleInitialized = true;
+    installGlobalFunction(m_context, "nativeRequire", nativeRequire);
+  }
+  executeApplicationScript(startupCode, sourceURL);
 }
 
 std::string JSCExecutor::flush() {
@@ -238,6 +251,13 @@ void JSCExecutor::flushQueueImmediate(std::string queueJSON) {
   m_flushImmediateCallback(queueJSON, false);
 }
 
+void JSCExecutor::loadModule(uint32_t moduleId) {
+  auto module = m_unbundle.getModule(moduleId);
+  auto sourceUrl = String::createExpectingAscii(module.name);
+  auto source = String::createExpectingAscii(module.code);
+  evaluateScript(m_context, source, sourceUrl);
+}
+
 // WebWorker impl
 
 JSGlobalContextRef JSCExecutor::getContext() {
@@ -287,12 +307,55 @@ void JSCExecutor::terminateWebWorker(int workerId) {
   m_webWorkerJSObjs.erase(workerId);
 }
 
+// Native JS hooks
+
+static JSValueRef makeInvalidModuleIdJSCException(
+    JSContextRef ctx,
+    const JSValueRef id,
+    JSValueRef *exception) {
+  std::string message = "Received invalid module ID: ";
+  message += String::adopt(JSValueToStringCopy(ctx, id, exception)).str();
+  return makeJSCException(ctx, message.c_str());
+}
+
+JSValueRef JSCExecutor::nativeRequire(
+  JSContextRef ctx,
+  JSObjectRef function,
+  JSObjectRef thisObject,
+  size_t argumentCount,
+  const JSValueRef arguments[],
+  JSValueRef *exception) {
+
+  if (argumentCount != 1) {
+    *exception = makeJSCException(ctx, "Got wrong number of args");
+    return JSValueMakeUndefined(ctx);
+  }
+
+  JSCExecutor *executor;
+  try {
+    executor = s_globalContextRefToJSCExecutor.at(JSContextGetGlobalContext(ctx));
+  } catch (std::out_of_range& e) {
+    *exception = makeJSCException(ctx, "Global JS context didn't map to a valid executor");
+    return JSValueMakeUndefined(ctx);
+  }
+
+  double moduleId = JSValueToNumber(ctx, arguments[0], exception);
+  if (moduleId <= (double) UINT32_MAX && moduleId >= 0.0) {
+    try {
+      executor->loadModule(moduleId);
+    } catch (JSModulesUnbundle::ModuleNotFound&) {
+      *exception = makeInvalidModuleIdJSCException(ctx, arguments[0], exception);
+    }
+  } else {
+    *exception = makeInvalidModuleIdJSCException(ctx, arguments[0], exception);
+  }
+  return JSValueMakeUndefined(ctx);
+}
+
 static JSValueRef createErrorString(JSContextRef ctx, const char *msg) {
   return JSValueMakeString(ctx, String(msg));
 }
 
-// Native JS hooks
-
 static JSValueRef nativeFlushQueueImmediate(
     JSContextRef ctx,
     JSObjectRef function,
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.h b/ReactAndroid/src/main/jni/react/JSCExecutor.h
index 3a9a6a0ea694..85d87c2a68a3 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.h
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.h
@@ -2,6 +2,7 @@
 
 #pragma once
 
+#include <cstdint>
 #include <memory>
 #include <unordered_map>
 #include <JavaScriptCore/JSContextRef.h>
@@ -30,6 +31,10 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
   virtual void executeApplicationScript(
     const std::string& script,
     const std::string& sourceURL) override;
+  virtual void loadApplicationUnbundle(
+    JSModulesUnbundle&& unbundle,
+    const std::string& startupCode,
+    const std::string& sourceURL) override;
   virtual std::string flush() override;
   virtual std::string callFunction(
     const double moduleId,
@@ -59,10 +64,13 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
   std::unordered_map<int, JSCWebWorker> m_webWorkers;
   std::unordered_map<int, Object> m_webWorkerJSObjs;
   std::shared_ptr<JMessageQueueThread> m_messageQueueThread;
+  JSModulesUnbundle m_unbundle;
+  bool m_isUnbundleInitialized = false;
 
   int addWebWorker(const std::string& script, JSValueRef workerRef);
   void postMessageToWebWorker(int worker, JSValueRef message, JSValueRef *exn);
   void terminateWebWorker(int worker);
+  void loadModule(uint32_t moduleId);
 
   static JSValueRef nativeStartWorker(
       JSContextRef ctx,
@@ -85,6 +93,13 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
       size_t argumentCount,
       const JSValueRef arguments[],
       JSValueRef *exception);
+  static JSValueRef nativeRequire(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[],
+    JSValueRef *exception);
 };
 
 } }
diff --git a/ReactAndroid/src/main/jni/react/JSCHelpers.cpp b/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
index 12702d03aaeb..4835781133f1 100644
--- a/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
@@ -41,13 +41,14 @@ JSValueRef evaluateScript(JSContextRef context, JSStringRef script, JSStringRef
     FBLOGE("Got JS Exception: %s", exceptionText.c_str());
     auto line = exception.asObject().getProperty("line");
 
-    std::ostringstream lineInfo;
+    std::ostringstream locationInfo;
+    std::string file = String::adopt(source).str();
+    locationInfo << "(" << (file.length() ? file : "<unknown file>");
     if (line != nullptr && line.isNumber()) {
-      lineInfo << " (line " << line.asInteger() << " in the generated bundle)";
-    } else {
-      lineInfo << " (no line info)";
+      locationInfo << ":" << line.asInteger();
     }
-    throwJSExecutionException("%s%s", exceptionText.c_str(), lineInfo.str().c_str());
+    locationInfo << ")";
+    throwJSExecutionException("%s %s", exceptionText.c_str(), locationInfo.str().c_str());
   }
   return result;
 }
diff --git a/ReactAndroid/src/main/jni/react/JSCHelpers.h b/ReactAndroid/src/main/jni/react/JSCHelpers.h
index 2d125f4af32f..fd19c48cc458 100644
--- a/ReactAndroid/src/main/jni/react/JSCHelpers.h
+++ b/ReactAndroid/src/main/jni/react/JSCHelpers.h
@@ -8,8 +8,6 @@
 
 #define throwJSExecutionException(...) jni::throwNewJavaException("com/facebook/react/bridge/JSExecutionException", __VA_ARGS__)
 
-#define throwJSExecutionException(...) jni::throwNewJavaException("com/facebook/react/bridge/JSExecutionException", __VA_ARGS__)
-
 namespace facebook {
 namespace react {
 
diff --git a/ReactAndroid/src/main/jni/react/JSModulesUnbundle.cpp b/ReactAndroid/src/main/jni/react/JSModulesUnbundle.cpp
new file mode 100644
index 000000000000..f1df636255f0
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/JSModulesUnbundle.cpp
@@ -0,0 +1,94 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#include "JSModulesUnbundle.h"
+
+#include <cstdint>
+#include <fb/assert.h>
+#include <libgen.h>
+#include <memory>
+#include <sstream>
+#include <sys/endian.h>
+#include <utility>
+
+using magic_number_t = uint32_t;
+const magic_number_t MAGIC_FILE_HEADER = 0xFB0BD1E5;
+const std::string MAGIC_FILE_NAME = "UNBUNDLE";
+
+namespace facebook {
+namespace react {
+
+using asset_ptr =
+  std::unique_ptr<AAsset, std::function<decltype(AAsset_close)>>;
+
+static std::string jsModulesDir(const std::string& entryFile) {
+  std::string dir = dirname(entryFile.c_str());
+
+  // android's asset manager does not work with paths that start with a dot
+  return dir == "." ? "js-modules/" : dir + "/js-modules/";
+}
+
+static asset_ptr openAsset(
+    AAssetManager *manager,
+    const std::string& fileName,
+    int mode = AASSET_MODE_STREAMING) {
+  return asset_ptr(
+    AAssetManager_open(manager, fileName.c_str(), mode),
+    AAsset_close);
+}
+
+JSModulesUnbundle::JSModulesUnbundle(AAssetManager *assetManager, const std::string& entryFile) :
+  m_assetManager(assetManager),
+  m_moduleDirectory(jsModulesDir(entryFile)) {}
+
+JSModulesUnbundle::JSModulesUnbundle(JSModulesUnbundle&& other) noexcept {
+  *this = std::move(other);
+}
+
+JSModulesUnbundle& JSModulesUnbundle::operator= (JSModulesUnbundle&& other) noexcept {
+  std::swap(m_assetManager, other.m_assetManager);
+  std::swap(m_moduleDirectory, other.m_moduleDirectory);
+
+  return *this;
+}
+
+bool JSModulesUnbundle::isUnbundle(
+    AAssetManager *assetManager,
+    const std::string& assetName) {
+  if (!assetManager) {
+    return false;
+  }
+
+  auto magicFileName = jsModulesDir(assetName) + MAGIC_FILE_NAME;
+  auto asset = openAsset(assetManager, magicFileName.c_str());
+  if (asset == nullptr) {
+    return false;
+  }
+
+  magic_number_t fileHeader = 0;
+  AAsset_read(asset.get(), &fileHeader, sizeof(fileHeader));
+  return fileHeader == htole32(MAGIC_FILE_HEADER);
+}
+
+JSModulesUnbundle::Module JSModulesUnbundle::getModule(uint32_t moduleId) const {
+  // can be nullptr for default constructor.
+  FBASSERTMSGF(m_assetManager != nullptr, "Unbundle has not been initialized with an asset manager");
+
+  std::ostringstream sourceUrlBuilder;
+  sourceUrlBuilder << moduleId << ".js";
+  auto sourceUrl = sourceUrlBuilder.str();
+
+  auto fileName = m_moduleDirectory + sourceUrl;
+  auto asset = openAsset(m_assetManager, fileName, AASSET_MODE_BUFFER);
+
+  const char *buffer = nullptr;
+  if (asset != nullptr) {
+    buffer = static_cast<const char *>(AAsset_getBuffer(asset.get()));
+  }
+  if (buffer == nullptr) {
+    throw ModuleNotFound("Module not found: " + sourceUrl);
+  }
+  return {sourceUrl, std::string(buffer, AAsset_getLength(asset.get()))};
+}
+
+}
+}
diff --git a/ReactAndroid/src/main/jni/react/JSModulesUnbundle.h b/ReactAndroid/src/main/jni/react/JSModulesUnbundle.h
new file mode 100644
index 000000000000..d2ca303b8671
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/JSModulesUnbundle.h
@@ -0,0 +1,48 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+#include <android/asset_manager.h>
+#include <cstdint>
+#include <fb/noncopyable.h>
+#include <string>
+#include <stdexcept>
+
+namespace facebook {
+namespace react {
+
+class JSModulesUnbundle : noncopyable {
+  /**
+   * Represents the set of JavaScript modules that the application consists of.
+   * The source code of each module can be retrieved by module ID.
+   * This implementation reads modules as single file from the assets of an apk.
+   *
+   * The class is non-copyable because copying instances might involve copying
+   * several megabytes of memory.
+   */
+public:
+  class ModuleNotFound : public std::out_of_range {
+    using std::out_of_range::out_of_range;
+  };
+  struct Module {
+    std::string name;
+    std::string code;
+  };
+
+  JSModulesUnbundle() = default;
+  JSModulesUnbundle(AAssetManager *assetManager, const std::string& entryFile);
+  JSModulesUnbundle(JSModulesUnbundle&& other) noexcept;
+  JSModulesUnbundle& operator= (JSModulesUnbundle&& other) noexcept;
+
+  static bool isUnbundle(
+    AAssetManager *assetManager,
+    const std::string& assetName);
+  Module getModule(uint32_t moduleId) const;
+
+private:
+  AAssetManager *m_assetManager = nullptr;
+  std::string m_moduleDirectory;
+};
+
+}
+}
diff --git a/ReactAndroid/src/main/jni/react/Value.cpp b/ReactAndroid/src/main/jni/react/Value.cpp
index ca292c0de2b5..d23490bbbc96 100644
--- a/ReactAndroid/src/main/jni/react/Value.cpp
+++ b/ReactAndroid/src/main/jni/react/Value.cpp
@@ -3,7 +3,6 @@
 #include "Value.h"
 
 #include <jni/fbjni.h>
-#include <fb/log.h>
 
 #include "JSCHelpers.h"
 
diff --git a/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp b/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp
index db8b4d980e63..24937d51b5f2 100644
--- a/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp
@@ -2,7 +2,6 @@
 
 #include "JSLoader.h"
 
-#include <android/asset_manager.h>
 #include <android/asset_manager_jni.h>
 #include <jni/Environment.h>
 #include <fstream>
@@ -10,7 +9,6 @@
 #include <streambuf>
 #include <string>
 #include <fb/log.h>
-
 #ifdef WITH_FBSYSTRACE
 #include <fbsystrace.h>
 using fbsystrace::FbSystraceSection;
@@ -29,19 +27,16 @@ std::string loadScriptFromAssets(std::string assetName) {
     gApplicationHolderClass,
     gGetApplicationMethod);
   jobject assetManager = env->CallObjectMethod(application, gGetAssetManagerMethod);
-  return loadScriptFromAssets(env, assetManager, assetName);
+  return loadScriptFromAssets(AAssetManager_fromJava(env, assetManager), assetName);
 }
 
 std::string loadScriptFromAssets(
-    JNIEnv *env,
-    jobject assetManager,
+    AAssetManager *manager,
     std::string assetName) {
   #ifdef WITH_FBSYSTRACE
   FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "reactbridge_jni_loadScriptFromAssets",
     "assetName", assetName);
   #endif
-
-  auto manager = AAssetManager_fromJava(env, assetManager);
   if (manager) {
     auto asset = AAssetManager_open(
       manager,
@@ -90,7 +85,7 @@ void registerJSLoaderNatives() {
   jclass applicationHolderClass = env->FindClass("com/facebook/react/common/ApplicationHolder");
   gApplicationHolderClass = (jclass)env->NewGlobalRef(applicationHolderClass);
   gGetApplicationMethod = env->GetStaticMethodID(applicationHolderClass, "getApplication", "()Landroid/app/Application;");
-  
+
   jclass appClass = env->FindClass("android/app/Application");
   gGetAssetManagerMethod = env->GetMethodID(appClass, "getAssets", "()Landroid/content/res/AssetManager;");
 }
diff --git a/ReactAndroid/src/main/jni/react/jni/JSLoader.h b/ReactAndroid/src/main/jni/react/jni/JSLoader.h
index 25dab510d7a2..91aa137c9295 100644
--- a/ReactAndroid/src/main/jni/react/jni/JSLoader.h
+++ b/ReactAndroid/src/main/jni/react/jni/JSLoader.h
@@ -2,6 +2,7 @@
 
 #pragma once
 
+#include <android/asset_manager.h>
 #include <string>
 #include <jni.h>
 
@@ -17,7 +18,7 @@ std::string loadScriptFromAssets(std::string assetName);
 /**
  * Helper method for loading JS script from android asset
  */
-std::string loadScriptFromAssets(JNIEnv *env, jobject assetManager, std::string assetName);
+std::string loadScriptFromAssets(AAssetManager *assetManager, std::string assetName);
 
 /**
  * Helper method for loading JS script from a file
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 7b66505c49e0..1acaa4175454 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -1,5 +1,6 @@
 // Copyright 2004-present Facebook. All Rights Reserved.
 
+#include <android/asset_manager_jni.h>
 #include <android/input.h>
 #include <fb/log.h>
 #include <folly/json.h>
@@ -13,6 +14,7 @@
 #include <react/Bridge.h>
 #include <react/Executor.h>
 #include <react/JSCExecutor.h>
+#include <react/JSModulesUnbundle.h>
 #include "JNativeRunnable.h"
 #include "JSLoader.h"
 #include "ReadableNativeArray.h"
@@ -643,15 +645,33 @@ static void executeApplicationScript(
   }
 }
 
+static void loadApplicationUnbundle(
+    const RefPtr<Bridge>& bridge,
+    AAssetManager *assetManager,
+    const std::string& startupCode,
+    const std::string& startupFileName) {
+
+  try {
+    // Load the application unbundle and collect/dispatch any native calls that might have occured
+    bridge->loadApplicationUnbundle(
+      JSModulesUnbundle(assetManager, startupFileName),
+      startupCode,
+      startupFileName);
+    bridge->flush();
+  } catch (...) {
+    translatePendingCppExceptionToJavaException();
+  }
+}
+
 static void loadScriptFromAssets(JNIEnv* env, jobject obj, jobject assetManager,
                                  jstring assetName) {
   jclass markerClass = env->FindClass("com/facebook/react/bridge/ReactMarker");
-
+  auto manager = AAssetManager_fromJava(env, assetManager);
   auto bridge = extractRefPtr<Bridge>(env, obj);
   auto assetNameStr = fromJString(env, assetName);
 
   env->CallStaticVoidMethod(markerClass, gLogMarkerMethod, env->NewStringUTF("loadScriptFromAssets_start"));
-  auto script = react::loadScriptFromAssets(env, assetManager, assetNameStr);
+  auto script = react::loadScriptFromAssets(manager, assetNameStr);
   #ifdef WITH_FBSYSTRACE
   FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "reactbridge_jni_"
     "executeApplicationScript",
@@ -659,7 +679,11 @@ static void loadScriptFromAssets(JNIEnv* env, jobject obj, jobject assetManager,
   #endif
 
   env->CallStaticVoidMethod(markerClass, gLogMarkerMethod, env->NewStringUTF("loadScriptFromAssets_read"));
-  executeApplicationScript(bridge, script, assetNameStr);
+  if (JSModulesUnbundle::isUnbundle(manager, assetNameStr)) {
+    loadApplicationUnbundle(bridge, manager, script, assetNameStr);
+  } else {
+    executeApplicationScript(bridge, script, assetNameStr);
+  }
   if (env->ExceptionCheck()) {
     return;
   }
diff --git a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
index ad4e245d188b..1c6cc188aa84 100644
--- a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
@@ -2,6 +2,7 @@
 
 #include "ProxyExecutor.h"
 
+#include <fb/assert.h>
 #include <jni/Environment.h>
 #include <jni/LocalReference.h>
 #include <jni/LocalString.h>
@@ -50,6 +51,11 @@ void ProxyExecutor::executeApplicationScript(
     jni::make_jstring(sourceURL).get());
 }
 
+void ProxyExecutor::loadApplicationUnbundle(JSModulesUnbundle&&, const std::string&, const std::string&) {
+  jni::throwNewJavaException(
+    "java/lang/UnsupportedOperationException",
+    "Loading application unbundles is not supported for proxy executors");
+}
 
 std::string ProxyExecutor::flush() {
   return executeJSCallWithProxy(m_executor.get(), "flushedQueue", std::vector<folly::dynamic>());
diff --git a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
index 2f5d21980d31..d88fc3d111c9 100644
--- a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
+++ b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
@@ -32,6 +32,10 @@ class ProxyExecutor : public JSExecutor {
   virtual void executeApplicationScript(
     const std::string& script,
     const std::string& sourceURL) override;
+  virtual void loadApplicationUnbundle(
+    JSModulesUnbundle&& bundle,
+    const std::string& startupCode,
+    const std::string& sourceURL) override;
   virtual std::string flush() override;
   virtual std::string callFunction(
     const double moduleId,
diff --git a/local-cli/bundle/output/unbundle/as-indexed-file.js b/local-cli/bundle/output/unbundle/as-indexed-file.js
index 7b27970816a4..f09b1f10d29a 100644
--- a/local-cli/bundle/output/unbundle/as-indexed-file.js
+++ b/local-cli/bundle/output/unbundle/as-indexed-file.js
@@ -76,7 +76,7 @@ function uInt32Buffer(n) {
 
 function buildModuleTable(buffers) {
   // table format:
-  //  - table_length: uint_32 length of all table entries in bytes
+  //  - table_length: uint_32 length of all table entries in bytes + the table length itself
   //  - entries: entry...
   //
   // entry:
diff --git a/packager/react-packager/src/Resolver/polyfills/require-unbundle.js b/packager/react-packager/src/Resolver/polyfills/require-unbundle.js
index c6c7cbc79c82..df75ae14da4b 100644
--- a/packager/react-packager/src/Resolver/polyfills/require-unbundle.js
+++ b/packager/react-packager/src/Resolver/polyfills/require-unbundle.js
@@ -1,6 +1,6 @@
 'use strict';
 
-const {ErrorUtils, __nativeRequire} = global;
+const {ErrorUtils, nativeRequire} = global;
 global.require = require;
 global.__d = define;
 
@@ -32,7 +32,7 @@ function guardedLoadModule(moduleId, module) {
 
 function loadModuleImplementation(moduleId, module) {
   if (!module) {
-    __nativeRequire(moduleId);
+    nativeRequire(moduleId);
     module = modules[moduleId];
   }
 

From c434893878e66f81df4d14b3789b97e92442853c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Thu, 21 Jan 2016 14:04:15 -0800
Subject: [PATCH 0843/1411] Hot Loading should be disabled by default

Summary:
public

Although the feature itself is gated, once the user is on the experiment we want to make sure hot loading starts disabled up until the feature is enabled through the dev menu.

Reviewed By: javache

Differential Revision: D2850070

fb-gh-sync-id: 66e69e152806d3bb01985afe20827e3b9cffeb41
---
 React/Modules/RCTDevMenu.m | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/React/Modules/RCTDevMenu.m b/React/Modules/RCTDevMenu.m
index a9e92e6cf30e..c3a47cb27497 100644
--- a/React/Modules/RCTDevMenu.m
+++ b/React/Modules/RCTDevMenu.m
@@ -267,7 +267,7 @@ - (void)updateSettings:(NSDictionary *)settings
   self.shakeToShow = [_settings[@"shakeToShow"] ?: @YES boolValue];
   self.profilingEnabled = [_settings[@"profilingEnabled"] ?: @NO boolValue];
   self.liveReloadEnabled = [_settings[@"liveReloadEnabled"] ?: @NO boolValue];
-  self.hotLoadingEnabled = [_settings[@"hotLoadingEnabled"] ?: @YES boolValue];
+  self.hotLoadingEnabled = [_settings[@"hotLoadingEnabled"] ?: @NO boolValue];
   self.showFPS = [_settings[@"showFPS"] ?: @NO boolValue];
   self.executorClass = NSClassFromString(_executorOverride ?: _settings[@"executorClass"]);
 }

From 89207a117113c678f15f9823486a8ec4f5d375a5 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Thu, 21 Jan 2016 14:10:49 -0800
Subject: [PATCH 0844/1411] `require` implementation for unbundles: Systrace
 and guard

Summary:
public

Adds two feature to the require implementation for unbundled code:
- Ports Systrace from `require.js`
- Prevents already loaded modules from being overwritten by repeated calls to `nativeRequire` with the same ID

Reviewed By: martinbigio

Differential Revision: D2850345

fb-gh-sync-id: 122e2d5d4a64b2e868d4cf6e5079810f59b1db18
---
 .../Resolver/polyfills/require-unbundle.js    | 24 +++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/packager/react-packager/src/Resolver/polyfills/require-unbundle.js b/packager/react-packager/src/Resolver/polyfills/require-unbundle.js
index df75ae14da4b..87e856013e1e 100644
--- a/packager/react-packager/src/Resolver/polyfills/require-unbundle.js
+++ b/packager/react-packager/src/Resolver/polyfills/require-unbundle.js
@@ -10,6 +10,11 @@ const loadModule = ErrorUtils ?
   guardedLoadModule : loadModuleImplementation;
 
 function define(moduleId, factory) {
+  if (moduleId in modules) {
+    // prevent repeated calls to `global.nativeRequire` to overwrite modules
+    // that are already loaded
+    return;
+  }
   modules[moduleId] = {
     factory,
     hasError: false,
@@ -44,11 +49,26 @@ function loadModuleImplementation(moduleId, module) {
     throw moduleThrewError(moduleId);
   }
 
+  // `require` calls int  the require polyfill itself are not analyzed and
+  // replaced so that they use numeric module IDs.
+  // The systrace module will expose itself on the require function so that
+  // it can be used here.
+  // TODO(davidaurelio) Scan polyfills for dependencies, too (t9759686)
+  const {Systrace} = require;
+
   const exports = module.exports = {};
   const {factory} = module;
   try {
+    if (__DEV__) {
+      Systrace.beginEvent('JS_require_' + moduleId);
+    }
+
     const moduleObject = {exports};
     factory(global, require, moduleObject, exports);
+
+    if (__DEV__) {
+      Systrace.endEvent();
+    }
     return (module.exports = moduleObject.exports);
   } catch (e) {
     module.hasError = true;
@@ -68,3 +88,7 @@ function unknownModuleError(id) {
 function moduleThrewError(id) {
   return Error('Requiring module "' + id + '", which threw an exception.');
 }
+
+if (__DEV__) {
+  require.Systrace = { beginEvent: () => {}, endEvent: () => {} };
+}

From 2a70c539477996e2dad6e4a4ddd6a794035c5697 Mon Sep 17 00:00:00 2001
From: Andrei Coman <andreic@fb.com>
Date: Thu, 21 Jan 2016 15:32:18 -0800
Subject: [PATCH 0845/1411] Don't NPE in reactTagForTouch

Summary:
This NPEs because the layout is null if the TextView has recently
changed. However, this also means that the TextView hasn't been laid out yet, so
the default TextView tag is correct.

public

Reviewed By: oli

Differential Revision: D2848412

fb-gh-sync-id: 5faf793d17f50283c153dc0d43fb717e8764cb7d
---
 .../java/com/facebook/react/views/text/ReactTextView.java    | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java
index faea8bad4a08..8c7e7f948d67 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java
@@ -39,6 +39,11 @@ public int reactTagForTouch(float touchX, float touchY) {
     int y = (int) touchY;
 
     Layout layout = getLayout();
+    if (layout == null) {
+      // If the layout is null, the view hasn't been properly laid out yet. Therefore, we can't find
+      // the exact text tag that has been touched, and the correct tag to return is the default one.
+      return target;
+    }
     int line = layout.getLineForVertical(y);
 
     int lineStartX = (int) layout.getLineLeft(line);

From 35e1fd8826644228272376bc7b196ad3618f4999 Mon Sep 17 00:00:00 2001
From: David Aurelio <dev@david-aurelio.com>
Date: Fri, 22 Jan 2016 03:23:51 -0800
Subject: [PATCH 0846/1411] Use `std::numeric_limits` in C++

Summary:
Instead of using `UINT32_MAX` in C++ code, use `std::numeric_limits<uint32_t>::max()`. The `UINT32_MAX` macro is not available in all compilation setups
Closes https://github.com/facebook/react-native/pull/5481

Reviewed By: svcscm

Differential Revision: D2854545

Pulled By: androidtrunkagent

fb-gh-sync-id: 00a70b429c78bcf120866bb59fae2ffe6330a910
---
 ReactAndroid/src/main/jni/react/JSCExecutor.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index 44d2354c2bc4..0aa59246f583 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -340,7 +340,7 @@ JSValueRef JSCExecutor::nativeRequire(
   }
 
   double moduleId = JSValueToNumber(ctx, arguments[0], exception);
-  if (moduleId <= (double) UINT32_MAX && moduleId >= 0.0) {
+  if (moduleId <= (double) std::numeric_limits<uint32_t>::max() && moduleId >= 0.0) {
     try {
       executor->loadModule(moduleId);
     } catch (JSModulesUnbundle::ModuleNotFound&) {

From f7cb7451955aa94dd4a6919ede23d063d2f45140 Mon Sep 17 00:00:00 2001
From: Moz Morris <moz@earthview.co.uk>
Date: Fri, 22 Jan 2016 06:53:50 -0800
Subject: [PATCH 0847/1411] Update Tutorial.md with missing Component import

Summary: Closes https://github.com/facebook/react-native/pull/5484

Reviewed By: svcscm

Differential Revision: D2854745

Pulled By: androidtrunkagent

fb-gh-sync-id: b89a8dbef33cc0d89d5e94fa7c5f35219d7c8147
---
 docs/Tutorial.md | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/docs/Tutorial.md b/docs/Tutorial.md
index 26696d3f5e2a..6a809b77c37a 100644
--- a/docs/Tutorial.md
+++ b/docs/Tutorial.md
@@ -59,6 +59,7 @@ We're going to render the title, year, and thumbnail for the movie. Since thumbn
 ```javascript
 import React, {
   AppRegistry,
+  Component,
   Image,
   StyleSheet,
   Text,
@@ -296,6 +297,7 @@ First things first: add the `ListView` import to the top of the file.
 ```javascript
 import React, {
   AppRegistry,
+  Component,
   Image,
   ListView,
   StyleSheet,

From c4b948f62ee4296dec01b14f55c48d207c687bd6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Fri, 22 Jan 2016 06:56:36 -0800
Subject: [PATCH 0848/1411] Make "Loading from pre-bundle" message more
 distinctive

Reviewed By: javache

Differential Revision: D2849126

fb-gh-sync-id: 28b42650de3716b43d228e83ede215aaa9098858
---
 React/Modules/RCTDevLoadingView.m | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/React/Modules/RCTDevLoadingView.m b/React/Modules/RCTDevLoadingView.m
index f522794ab316..e6d20261e9da 100644
--- a/React/Modules/RCTDevLoadingView.m
+++ b/React/Modules/RCTDevLoadingView.m
@@ -67,12 +67,10 @@ - (void)showWithURL:(NSURL *)URL
     if (!_window && !RCTRunningInTestEnvironment()) {
       CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
       _window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, screenWidth, 22)];
-      _window.backgroundColor = [UIColor blackColor];
       _window.windowLevel = UIWindowLevelStatusBar + 1;
 
       _label = [[UILabel alloc] initWithFrame:_window.bounds];
       _label.font = [UIFont systemFontOfSize:12.0];
-      _label.textColor = [UIColor grayColor];
       _label.textAlignment = NSTextAlignmentCenter;
 
       [_window addSubview:_label];
@@ -81,14 +79,17 @@ - (void)showWithURL:(NSURL *)URL
 
     NSString *source;
     if (URL.fileURL) {
+      _window.backgroundColor = [UIColor greenColor];
+      _label.textColor = [UIColor whiteColor];
       source = @"pre-bundled file";
     } else {
+      _window.backgroundColor = [UIColor blackColor];
+      _label.textColor = [UIColor grayColor];
       source = [NSString stringWithFormat:@"%@:%@", URL.host, URL.port];
     }
 
     _label.text = [NSString stringWithFormat:@"Loading from %@...", source];
     _window.hidden = NO;
-
   });
 }
 

From 36e0dd2d483ded2764af1a31abcceaaaf136cfa0 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Fri, 22 Jan 2016 08:18:15 -0800
Subject: [PATCH 0849/1411] Fixed screen size bug on iPhone6+

Summary:
public

This diff fixes a bug in RCTScreenScale() on iPhone6+. The issue was due to the fact that the iPhone6+'s virtual screen resolution of 414x736 points 3x resolution (1242x2208 pixels) does not match its actual screen resolution, which is 1080p (1080x1920 pixels).

I did not realize that `[UIScreen mainScreen].nativeBounds` reports the *actual* resolution, not the virtual resolution, and was dividing by the virtual scale (3.0) instead of the actual native scale factor (2.6).

This only affects iPhone6+, because for all other iOS devices, the virtual resolution matches the native resolution.

Reviewed By: milend

Differential Revision: D2854663

fb-gh-sync-id: bce8965a151e2f005a02a5f6b54f259d01b9ab12
---
 React/Base/RCTUtils.m | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/React/Base/RCTUtils.m b/React/Base/RCTUtils.m
index 7040aa1fe0d3..d2a0916b3490 100644
--- a/React/Base/RCTUtils.m
+++ b/React/Base/RCTUtils.m
@@ -219,13 +219,7 @@ CGSize RCTScreenSize()
   static dispatch_once_t onceToken;
   dispatch_once(&onceToken, ^{
     RCTExecuteOnMainThread(^{
-      if ([[[UIDevice currentDevice] systemVersion] compare:@"8.0" options:NSNumericSearch] == NSOrderedDescending) {
-        CGSize pixelSize = [UIScreen mainScreen].nativeBounds.size;
-        CGFloat scale = RCTScreenScale();
-        size = (CGSize){pixelSize.width / scale, pixelSize.height / scale};
-      } else {
-        size = [UIScreen mainScreen].bounds.size;
-      }
+      size = [UIScreen mainScreen].bounds.size;
     }, YES);
   });
 

From 581434ac04c6bd465f373e6fcc6aa0d1de7dea0b Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Fri, 22 Jan 2016 16:03:51 +0000
Subject: [PATCH 0850/1411] Add BUCK files

---
 ReactAndroid/DEFS                             | 53 +++++++++++++
 ReactAndroid/libs/BUCK                        | 22 ++++++
 .../java/com/facebook/react/testing/BUCK      | 30 ++++++++
 .../java/com/facebook/react/tests/BUCK        | 18 +++++
 .../src/main/java/com/facebook/csslayout/BUCK | 15 ++++
 .../src/main/java/com/facebook/jni/BUCK       | 17 +++++
 .../src/main/java/com/facebook/perftest/BUCK  | 11 +++
 .../com/facebook/proguard/annotations/BUCK    | 14 ++++
 .../src/main/java/com/facebook/quicklog/BUCK  | 16 ++++
 .../com/facebook/quicklog/identifiers/BUCK    | 11 +++
 .../src/main/java/com/facebook/react/BUCK     | 28 +++++++
 .../java/com/facebook/react/animation/BUCK    | 18 +++++
 .../main/java/com/facebook/react/bridge/BUCK  | 42 +++++++++++
 .../main/java/com/facebook/react/common/BUCK  | 32 ++++++++
 .../java/com/facebook/react/devsupport/BUCK   | 26 +++++++
 .../com/facebook/react/modules/appstate/BUCK  | 21 ++++++
 .../com/facebook/react/modules/camera/BUCK    | 20 +++++
 .../com/facebook/react/modules/clipboard/BUCK | 20 +++++
 .../com/facebook/react/modules/common/BUCK    | 20 +++++
 .../java/com/facebook/react/modules/core/BUCK | 22 ++++++
 .../com/facebook/react/modules/debug/BUCK     | 21 ++++++
 .../com/facebook/react/modules/dialog/BUCK    | 20 +++++
 .../com/facebook/react/modules/fresco/BUCK    | 29 ++++++++
 .../com/facebook/react/modules/intent/BUCK    | 19 +++++
 .../com/facebook/react/modules/location/BUCK  | 20 +++++
 .../com/facebook/react/modules/netinfo/BUCK   | 22 ++++++
 .../com/facebook/react/modules/network/BUCK   | 26 +++++++
 .../com/facebook/react/modules/storage/BUCK   | 21 ++++++
 .../facebook/react/modules/systeminfo/BUCK    | 19 +++++
 .../com/facebook/react/modules/toast/BUCK     | 19 +++++
 .../com/facebook/react/modules/websocket/BUCK | 24 ++++++
 .../java/com/facebook/react/processing/BUCK   | 22 ++++++
 .../main/java/com/facebook/react/shell/BUCK   | 54 ++++++++++++++
 .../main/java/com/facebook/react/touch/BUCK   | 17 +++++
 .../java/com/facebook/react/uimanager/BUCK    | 31 ++++++++
 .../facebook/react/uimanager/annotations/BUCK | 16 ++++
 .../java/com/facebook/react/views/art/BUCK    | 22 ++++++
 .../java/com/facebook/react/views/drawer/BUCK | 23 ++++++
 .../java/com/facebook/react/views/image/BUCK  | 26 +++++++
 .../java/com/facebook/react/views/picker/BUCK | 21 ++++++
 .../com/facebook/react/views/progressbar/BUCK | 22 ++++++
 .../facebook/react/views/recyclerview/BUCK    | 26 +++++++
 .../java/com/facebook/react/views/scroll/BUCK | 24 ++++++
 .../facebook/react/views/swiperefresh/BUCK    | 22 ++++++
 .../com/facebook/react/views/switchview/BUCK  | 22 ++++++
 .../java/com/facebook/react/views/text/BUCK   | 26 +++++++
 .../com/facebook/react/views/textinput/BUCK   | 24 ++++++
 .../com/facebook/react/views/toolbar/BUCK     | 27 +++++++
 .../java/com/facebook/react/views/view/BUCK   | 23 ++++++
 .../com/facebook/react/views/viewpager/BUCK   | 23 ++++++
 .../com/facebook/react/views/webview/BUCK     | 20 +++++
 .../src/main/java/com/facebook/systrace/BUCK  | 11 +++
 ReactAndroid/src/main/jni/first-party/fb/BUCK | 28 +++++++
 .../src/main/jni/first-party/jni/BUCK         | 50 +++++++++++++
 ReactAndroid/src/main/jni/react/BUCK          | 74 +++++++++++++++++++
 ReactAndroid/src/main/jni/react/jni/BUCK      | 64 ++++++++++++++++
 .../src/main/jni/react/perftests/BUCK         | 21 ++++++
 .../src/main/jni/third-party/android-ndk/BUCK | 24 ++++++
 .../src/main/jni/third-party/glibc/BUCK       | 52 +++++++++++++
 .../java/com/facebook/common/logging/BUCK     | 11 +++
 .../src/test/java/com/facebook/powermock/BUCK | 73 ++++++++++++++++++
 .../libraries/fresco/fresco-react-native/BUCK | 59 +++++++++++++++
 .../soloader/java/com/facebook/soloader/BUCK  | 20 +++++
 ReactAndroid/src/main/res/BUCK                | 19 +++++
 .../v7/appcompat/BUCK                         | 36 +++++++++
 .../android/support-annotations/BUCK          | 11 +++
 .../main/third-party/android/support/v4/BUCK  | 23 ++++++
 .../android/support/v7/recyclerview/BUCK      | 13 ++++
 .../src/main/third-party/java/fest/BUCK       | 11 +++
 .../third-party/java/infer-annotations/BUCK   |  5 ++
 .../src/main/third-party/java/jackson/BUCK    | 11 +++
 .../src/main/third-party/java/javapoet/BUCK   | 11 +++
 .../src/main/third-party/java/jsr-305/BUCK    | 11 +++
 .../src/main/third-party/java/junit/BUCK      | 11 +++
 .../src/main/third-party/java/mockito/BUCK    | 11 +++
 .../src/main/third-party/java/okhttp/BUCK     | 23 ++++++
 .../src/main/third-party/java/okio/BUCK       | 11 +++
 .../java/robolectric3/robolectric/BUCK        | 45 +++++++++++
 .../src/main/third-party/java/stetho/BUCK     | 23 ++++++
 .../test/java/com/facebook/react/bridge/BUCK  | 19 +++++
 .../test/java/com/facebook/react/modules/BUCK | 41 ++++++++++
 .../test/java/org/mockito/configuration/BUCK  | 16 ++++
 82 files changed, 2025 insertions(+)
 create mode 100644 ReactAndroid/DEFS
 create mode 100644 ReactAndroid/libs/BUCK
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/BUCK
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/tests/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/csslayout/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/jni/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/perftest/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/proguard/annotations/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/quicklog/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/quicklog/identifiers/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/animation/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/common/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/devsupport/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/appstate/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/camera/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/common/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/core/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/debug/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/dialog/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/fresco/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/intent/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/location/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/network/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/storage/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/toast/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/websocket/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/processing/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/shell/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/touch/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/annotations/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/art/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/drawer/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/image/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/picker/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/progressbar/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/scroll/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/textinput/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/view/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/viewpager/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/webview/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/systrace/BUCK
 create mode 100644 ReactAndroid/src/main/jni/first-party/fb/BUCK
 create mode 100644 ReactAndroid/src/main/jni/first-party/jni/BUCK
 create mode 100644 ReactAndroid/src/main/jni/react/BUCK
 create mode 100644 ReactAndroid/src/main/jni/react/jni/BUCK
 create mode 100644 ReactAndroid/src/main/jni/react/perftests/BUCK
 create mode 100644 ReactAndroid/src/main/jni/third-party/android-ndk/BUCK
 create mode 100644 ReactAndroid/src/main/jni/third-party/glibc/BUCK
 create mode 100644 ReactAndroid/src/main/libraries/fbcore/src/main/java/com/facebook/common/logging/BUCK
 create mode 100644 ReactAndroid/src/main/libraries/fbcore/src/test/java/com/facebook/powermock/BUCK
 create mode 100644 ReactAndroid/src/main/libraries/fresco/fresco-react-native/BUCK
 create mode 100644 ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/BUCK
 create mode 100644 ReactAndroid/src/main/res/BUCK
 create mode 100644 ReactAndroid/src/main/third-party/android-support-for-standalone-apps/v7/appcompat/BUCK
 create mode 100644 ReactAndroid/src/main/third-party/android/support-annotations/BUCK
 create mode 100644 ReactAndroid/src/main/third-party/android/support/v4/BUCK
 create mode 100644 ReactAndroid/src/main/third-party/android/support/v7/recyclerview/BUCK
 create mode 100644 ReactAndroid/src/main/third-party/java/fest/BUCK
 create mode 100644 ReactAndroid/src/main/third-party/java/infer-annotations/BUCK
 create mode 100644 ReactAndroid/src/main/third-party/java/jackson/BUCK
 create mode 100644 ReactAndroid/src/main/third-party/java/javapoet/BUCK
 create mode 100644 ReactAndroid/src/main/third-party/java/jsr-305/BUCK
 create mode 100644 ReactAndroid/src/main/third-party/java/junit/BUCK
 create mode 100644 ReactAndroid/src/main/third-party/java/mockito/BUCK
 create mode 100644 ReactAndroid/src/main/third-party/java/okhttp/BUCK
 create mode 100644 ReactAndroid/src/main/third-party/java/okio/BUCK
 create mode 100644 ReactAndroid/src/main/third-party/java/robolectric3/robolectric/BUCK
 create mode 100644 ReactAndroid/src/main/third-party/java/stetho/BUCK
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/bridge/BUCK
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/modules/BUCK
 create mode 100644 ReactAndroid/src/test/java/org/mockito/configuration/BUCK

diff --git a/ReactAndroid/DEFS b/ReactAndroid/DEFS
new file mode 100644
index 000000000000..87477552ff8a
--- /dev/null
+++ b/ReactAndroid/DEFS
@@ -0,0 +1,53 @@
+# Helpers for referring to React Native open source code.
+#
+# This lets us build React Native:
+# - At Facebook by running buck from the root of the fb repo
+# - Outside of Facebook by running buck in the root of the git repo
+
+# Example: react_native_target('java/com/facebook/react/common:common')
+def react_native_target(path):
+  return '//ReactAndroid/src/main/' + path
+
+# Example: react_native_tests_target('java/com/facebook/react/modules:modules')
+def react_native_tests_target(path):
+  return '//ReactAndroid/src/test/' + path
+
+# Example: react_native_integration_tests_target('java/com/facebook/react/testing:testing')
+def react_native_integration_tests_target(path):
+  return '//ReactAndroid/src/androidTest/' + path
+
+# Helper for referring to non-RN code from RN OSS code.
+# Example: react_native_dep('java/com/facebook/systrace:systrace')
+def react_native_dep(path):
+  return '//ReactAndroid/src/main/' + path
+
+INTERNAL_APP = 'PUBLIC'
+
+# React property preprocessor
+original_android_library=android_library
+def android_library(
+  name,
+  deps=[],
+  annotation_processors=[],
+  annotation_processor_deps=[],
+  *args,
+  **kwargs):
+
+  common_processors = [
+    'com.facebook.react.processing.ReactPropertyProcessor',
+  ]
+  common_processor_deps = [
+    react_native_target('java/com/facebook/react/processing:processing'),
+  ]
+
+  if react_native_target('java/com/facebook/react/uimanager/annotations:annotations') in deps and name != 'processing':
+      annotation_processors = list(set(annotation_processors + common_processors))
+      annotation_processor_deps = list(set(annotation_processor_deps + common_processor_deps))
+
+  original_android_library(
+    name=name,
+    deps=deps,
+    annotation_processors=annotation_processors,
+    annotation_processor_deps=annotation_processor_deps,
+    *args,
+    **kwargs)
diff --git a/ReactAndroid/libs/BUCK b/ReactAndroid/libs/BUCK
new file mode 100644
index 000000000000..8699bb3393c6
--- /dev/null
+++ b/ReactAndroid/libs/BUCK
@@ -0,0 +1,22 @@
+android_prebuilt_aar(
+    name = 'appcompat',
+    aar = ':appcompat-binary-aar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'appcompat-binary-aar',
+    url = 'mvn:com.android.support:appcompat-v7:aar:23.0.1',
+    sha1 = '7d659f671541394a8bc2b9f909950aa2a5ec87ff',
+)
+
+android_prebuilt_aar(
+  name = 'android-jsc',
+  aar = ':android-jsc-aar',
+)
+
+remote_file(
+  name = 'android-jsc-aar',
+  url = 'mvn:org.webkit:android-jsc:aar:r174650',
+  sha1 = '880cedd93f43e0fc841f01f2fa185a63d9230f85',
+)
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/BUCK b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/BUCK
new file mode 100644
index 000000000000..d3c6d72551dc
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/BUCK
@@ -0,0 +1,30 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'testing',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react:react'),
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/modules/core:core'),
+    react_native_target('java/com/facebook/react/modules/debug:debug'),
+    react_native_target('java/com/facebook/react/devsupport:devsupport'),
+    react_native_target('java/com/facebook/react/shell:shell'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_dep('libraries/soloader/java/com/facebook/soloader:soloader'),
+    react_native_dep('third-party/android/support/v4:lib-support-v4'),
+    react_native_dep('third-party/java/guava:guava'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+    react_native_dep('third-party/java/junit:junit'),
+    react_native_dep('third-party/java/testing-support-lib:testing-support-lib'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':testing',
+)
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/BUCK b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/BUCK
new file mode 100644
index 000000000000..78d23f13542f
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/BUCK
@@ -0,0 +1,18 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'tests',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_integration_tests_target('java/com/facebook/react/testing:testing'),
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':tests',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/csslayout/BUCK b/ReactAndroid/src/main/java/com/facebook/csslayout/BUCK
new file mode 100644
index 000000000000..da7888de9298
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/csslayout/BUCK
@@ -0,0 +1,15 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'csslayout',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = ['PUBLIC'],
+)
+
+project_config(
+  src_target = ':csslayout',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/jni/BUCK b/ReactAndroid/src/main/java/com/facebook/jni/BUCK
new file mode 100644
index 000000000000..220371dbaae6
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/jni/BUCK
@@ -0,0 +1,17 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'jni',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_dep('java/com/facebook/proguard/annotations:annotations'),
+    react_native_dep('libraries/soloader/java/com/facebook/soloader:soloader'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':jni',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/perftest/BUCK b/ReactAndroid/src/main/java/com/facebook/perftest/BUCK
new file mode 100644
index 000000000000..655817f6e11b
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/perftest/BUCK
@@ -0,0 +1,11 @@
+android_library(
+  name = 'perftest',
+  srcs = glob(['*.java']),
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':perftest',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/proguard/annotations/BUCK b/ReactAndroid/src/main/java/com/facebook/proguard/annotations/BUCK
new file mode 100644
index 000000000000..27de0b88a9c7
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/proguard/annotations/BUCK
@@ -0,0 +1,14 @@
+android_library(
+  name = 'annotations',
+  srcs = glob(['*.java']),
+  proguard_config = 'proguard_annotations.pro',
+  deps = [
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':annotations',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/quicklog/BUCK b/ReactAndroid/src/main/java/com/facebook/quicklog/BUCK
new file mode 100644
index 000000000000..8bd1a243fa96
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/quicklog/BUCK
@@ -0,0 +1,16 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'quicklog',
+  srcs = glob(['*.java']),
+  exported_deps = [
+    react_native_dep('java/com/facebook/quicklog/identifiers:identifiers'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':quicklog',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/quicklog/identifiers/BUCK b/ReactAndroid/src/main/java/com/facebook/quicklog/identifiers/BUCK
new file mode 100644
index 000000000000..38d3b1bfa8dc
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/quicklog/identifiers/BUCK
@@ -0,0 +1,11 @@
+android_library(
+  name = 'identifiers',
+  srcs = glob(['*.java']),
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':identifiers',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/BUCK b/ReactAndroid/src/main/java/com/facebook/react/BUCK
new file mode 100644
index 000000000000..0cc6b1e0d734
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/BUCK
@@ -0,0 +1,28 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'react',
+  srcs = glob(['*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/devsupport:devsupport'),
+    react_native_target('java/com/facebook/react/modules/core:core'),
+    react_native_target('java/com/facebook/react/modules/debug:debug'),
+    react_native_target('java/com/facebook/react/modules/systeminfo:systeminfo'),
+    react_native_target('java/com/facebook/react/modules/toast:toast'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_dep('java/com/facebook/systrace:systrace'),
+    react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'),
+    react_native_dep('libraries/soloader/java/com/facebook/soloader:soloader'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':react',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/animation/BUCK b/ReactAndroid/src/main/java/com/facebook/react/animation/BUCK
new file mode 100644
index 000000000000..6a3307d027a7
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/animation/BUCK
@@ -0,0 +1,18 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'animation',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC'
+  ],
+)
+
+project_config(
+  src_target = ':animation',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/BUCK b/ReactAndroid/src/main/java/com/facebook/react/bridge/BUCK
new file mode 100644
index 000000000000..43aaf9c5d40f
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/BUCK
@@ -0,0 +1,42 @@
+include_defs('//ReactAndroid/DEFS')
+
+# We package the JS files from the bundler and local directory into what we
+# pretend is an ordinary JAR file. By putting them under the assets/ directory
+# within the zip file and relying on Buck to merge its contents into the APK,
+# our JS bundles arrive in a place accessible by the AssetManager at runtime.
+
+python_binary(
+  name = 'package_js',
+  main = 'package_js.py',
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+android_library(
+  name = 'bridge',
+  srcs = glob(['**/*.java']),
+  exported_deps = [
+    react_native_dep('java/com/facebook/jni:jni'),
+    react_native_dep('java/com/facebook/proguard/annotations:annotations'),
+  ],
+  deps = [
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_dep('java/com/facebook/systrace:systrace'),
+    react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'),
+    react_native_dep('libraries/soloader/java/com/facebook/soloader:soloader'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jackson:core'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+    react_native_dep('third-party/java/okio:okio'),
+    react_native_dep('third-party/java/okhttp:okhttp'),
+    react_native_dep('third-party/java/okhttp:okhttp-ws'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':bridge',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/common/BUCK b/ReactAndroid/src/main/java/com/facebook/react/common/BUCK
new file mode 100644
index 000000000000..e98c528e86bc
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/common/BUCK
@@ -0,0 +1,32 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'common',
+  srcs = glob(['**/*.java']),
+  deps = [
+    ':build_config',
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  exported_deps = [
+    react_native_dep('java/com/facebook/proguard/annotations:annotations'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+android_build_config(
+  name = 'build_config',
+  package = 'com.facebook.react',
+  values = [
+   'boolean IS_INTERNAL_BUILD = true',
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':common',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/BUCK b/ReactAndroid/src/main/java/com/facebook/react/devsupport/BUCK
new file mode 100644
index 000000000000..5f81485ca5f7
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/BUCK
@@ -0,0 +1,26 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'devsupport',
+  manifest = 'AndroidManifest.xml',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('res:devsupport'),
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/modules/debug:debug'),
+    react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+    react_native_dep('third-party/java/okhttp:okhttp'),
+    react_native_dep('third-party/java/okio:okio'),
+
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':devsupport',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/BUCK
new file mode 100644
index 000000000000..27cc8a7cdb73
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/BUCK
@@ -0,0 +1,21 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'appstate',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/modules/core:core'),
+    react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':appstate',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/BUCK
new file mode 100644
index 000000000000..cede97b16073
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/BUCK
@@ -0,0 +1,20 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'camera',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':camera',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/BUCK
new file mode 100644
index 000000000000..262b92ef24dd
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/BUCK
@@ -0,0 +1,20 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'clipboard',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':clipboard',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/common/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/common/BUCK
new file mode 100644
index 000000000000..ed2454fac84d
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/common/BUCK
@@ -0,0 +1,20 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'common',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':common',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/core/BUCK
new file mode 100644
index 000000000000..2fff5f1efb6a
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/core/BUCK
@@ -0,0 +1,22 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'core',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/devsupport:devsupport'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':core',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/debug/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/debug/BUCK
new file mode 100644
index 000000000000..a43da0d29fb9
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/debug/BUCK
@@ -0,0 +1,21 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'debug',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':debug',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/BUCK
new file mode 100644
index 000000000000..45c6aeae97ab
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/BUCK
@@ -0,0 +1,20 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'dialog',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_dep('third-party/android/support/v4:lib-support-v4'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':dialog',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/BUCK
new file mode 100644
index 000000000000..18cae1994ea5
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/BUCK
@@ -0,0 +1,29 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'fresco',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/modules/common:common'),
+    react_native_target('java/com/facebook/react/modules/network:network'),
+    react_native_dep('java/com/facebook/systrace:systrace'),
+    react_native_dep('libraries/fresco/fresco-react-native:fresco-react-native'),
+    react_native_dep('libraries/fresco/fresco-react-native:imagepipeline'),
+    react_native_dep('libraries/fresco/fresco-react-native:imagepipeline-okhttp'),
+    react_native_dep('libraries/soloader/java/com/facebook/soloader:soloader'),
+    react_native_dep('third-party/android/support-annotations:android-support-annotations'),
+    react_native_dep('third-party/android/support/v4:lib-support-v4'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+    react_native_dep('third-party/java/okhttp:okhttp'),
+    react_native_dep('libraries/fresco/fresco-react-native:fbcore'),
+    react_native_dep('libraries/fresco/fresco-react-native:fresco-drawee'),
+],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':fresco',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/intent/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/intent/BUCK
new file mode 100644
index 000000000000..82c5b51b47b1
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/intent/BUCK
@@ -0,0 +1,19 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'intent',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':intent',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/location/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/location/BUCK
new file mode 100644
index 000000000000..4fb39039c503
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/location/BUCK
@@ -0,0 +1,20 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'location',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/modules/core:core'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':location',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/BUCK
new file mode 100644
index 000000000000..0a23937bae7e
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/BUCK
@@ -0,0 +1,22 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'netinfo',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/modules/core:core'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'),
+    react_native_dep('third-party/android/support/v4:lib-support-v4'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':netinfo',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/network/BUCK
new file mode 100644
index 000000000000..254326d6a7bb
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/BUCK
@@ -0,0 +1,26 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'network',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/modules/core:core'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'),
+    react_native_dep('third-party/android/support/v4:lib-support-v4'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+    react_native_dep('third-party/java/okhttp:okhttp'),
+    react_native_dep('third-party/java/okio:okio'),
+    react_native_dep('third-party/java/stetho:stetho'),
+    react_native_dep('third-party/java/stetho:stetho-okhttp'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':network',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/storage/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/storage/BUCK
new file mode 100644
index 000000000000..b9d5d418cbac
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/storage/BUCK
@@ -0,0 +1,21 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'storage',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/modules/common:common'),
+    react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':storage',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK
new file mode 100644
index 000000000000..a7be01fc4d7a
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK
@@ -0,0 +1,19 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'systeminfo',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':systeminfo',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/toast/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/toast/BUCK
new file mode 100644
index 000000000000..fdfec87eb25b
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/toast/BUCK
@@ -0,0 +1,19 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'toast',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':toast',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/BUCK
new file mode 100644
index 000000000000..6289e05986f1
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/BUCK
@@ -0,0 +1,24 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'websocket',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/modules/core:core'),
+    react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+    react_native_dep('third-party/java/okhttp:okhttp-ws'),
+    react_native_dep('third-party/java/okhttp:okhttp'),
+    react_native_dep('third-party/java/okio:okio'),
+],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':websocket',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/processing/BUCK b/ReactAndroid/src/main/java/com/facebook/react/processing/BUCK
new file mode 100644
index 000000000000..e057630de425
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/processing/BUCK
@@ -0,0 +1,22 @@
+include_defs('//ReactAndroid/DEFS')
+
+java_library(
+  name = 'processing',
+  srcs = glob(['*.java']),
+  source = '7',
+  target = '7',
+  deps = [
+    react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/javapoet:javapoet'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility=[
+    'PUBLIC'
+  ]
+)
+
+project_config(
+  src_target = ':processing',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK
new file mode 100644
index 000000000000..193749ddf23a
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK
@@ -0,0 +1,54 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'shell',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('res:shell'),
+    react_native_target('java/com/facebook/react:react'),
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/devsupport:devsupport'),
+    react_native_target('java/com/facebook/react/views/art:art'),
+    react_native_target('java/com/facebook/react/views/drawer:drawer'),
+    react_native_target('java/com/facebook/react/views/image:image'),
+    react_native_target('java/com/facebook/react/views/picker:picker'),
+    react_native_target('java/com/facebook/react/views/progressbar:progressbar'),
+    react_native_target('java/com/facebook/react/views/recyclerview:recyclerview'),
+    react_native_target('java/com/facebook/react/views/scroll:scroll'),
+    react_native_target('java/com/facebook/react/views/swiperefresh:swiperefresh'),
+    react_native_target('java/com/facebook/react/views/switchview:switchview'),
+    react_native_target('java/com/facebook/react/views/text:text'),
+    react_native_target('java/com/facebook/react/views/textinput:textinput'),
+    react_native_target('java/com/facebook/react/views/toolbar:toolbar'),
+    react_native_target('java/com/facebook/react/views/view:view'),
+    react_native_target('java/com/facebook/react/views/viewpager:viewpager'),
+    react_native_target('java/com/facebook/react/views/webview:webview'),
+    react_native_target('java/com/facebook/react/modules/appstate:appstate'),
+    react_native_target('java/com/facebook/react/modules/camera:camera'),
+    react_native_target('java/com/facebook/react/modules/clipboard:clipboard'),
+    react_native_target('java/com/facebook/react/modules/core:core'),
+    react_native_target('java/com/facebook/react/modules/debug:debug'),
+    react_native_target('java/com/facebook/react/modules/dialog:dialog'),
+    react_native_target('java/com/facebook/react/modules/fresco:fresco'),
+    react_native_target('java/com/facebook/react/modules/intent:intent'),
+    react_native_target('java/com/facebook/react/modules/location:location'),
+    react_native_target('java/com/facebook/react/modules/netinfo:netinfo'),
+    react_native_target('java/com/facebook/react/modules/network:network'),
+    react_native_target('java/com/facebook/react/modules/storage:storage'),
+    react_native_target('java/com/facebook/react/modules/toast:toast'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_target('java/com/facebook/react/modules/websocket:websocket'),
+    react_native_dep('libraries/soloader/java/com/facebook/soloader:soloader'),
+    react_native_dep('third-party/android/support/v4:lib-support-v4'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':shell',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/touch/BUCK b/ReactAndroid/src/main/java/com/facebook/react/touch/BUCK
new file mode 100644
index 000000000000..44cea8fdce54
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/touch/BUCK
@@ -0,0 +1,17 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'touch',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC'
+  ],
+)
+
+project_config(
+  src_target = ':touch',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK
new file mode 100644
index 000000000000..b39e66c9255c
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK
@@ -0,0 +1,31 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'uimanager',
+  srcs = glob([
+    '*.java',
+    'debug/*.java',
+    'events/*.java',
+    'layoutanimation/*.java'
+  ]),
+  deps = [
+    react_native_target('java/com/facebook/react/animation:animation'),
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
+    react_native_target('java/com/facebook/csslayout:csslayout'),
+    react_native_target('java/com/facebook/react/touch:touch'),
+    react_native_dep('java/com/facebook/systrace:systrace'),
+    react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+    react_native_dep('third-party/android/support/v4:lib-support-v4'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':uimanager',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/annotations/BUCK b/ReactAndroid/src/main/java/com/facebook/react/uimanager/annotations/BUCK
new file mode 100644
index 000000000000..6ec00fd33ec1
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/annotations/BUCK
@@ -0,0 +1,16 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'annotations',
+  srcs = glob(['*.java']),
+  deps = [
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':annotations',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/art/BUCK
new file mode 100644
index 000000000000..d7612a1e463b
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/BUCK
@@ -0,0 +1,22 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'art',
+  srcs = glob(['*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/csslayout:csslayout'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
+    react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':art',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/drawer/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/drawer/BUCK
new file mode 100644
index 000000000000..6698d3393e54
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/drawer/BUCK
@@ -0,0 +1,23 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'drawer',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/csslayout:csslayout'),
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
+    react_native_target('java/com/facebook/react/views/scroll:scroll'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+    react_native_dep('third-party/android/support/v4:lib-support-v4'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':drawer',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/image/BUCK
new file mode 100644
index 000000000000..abafb1b59eaa
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/BUCK
@@ -0,0 +1,26 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'image',
+  srcs = glob(['*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
+    react_native_dep('libraries/fresco/fresco-react-native:fbcore'),
+    react_native_dep('libraries/fresco/fresco-react-native:fresco-react-native'),
+    react_native_dep('libraries/fresco/fresco-react-native:fresco-drawee'),
+    react_native_dep('libraries/fresco/fresco-react-native:imagepipeline'),
+    react_native_dep('third-party/android/support/v4:lib-support-v4'),
+    react_native_dep('third-party/android/support-annotations:android-support-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':image',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/picker/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/picker/BUCK
new file mode 100644
index 000000000000..24ab25dbbadf
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/picker/BUCK
@@ -0,0 +1,21 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'picker',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':picker',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/BUCK
new file mode 100644
index 000000000000..fed1ed6a0503
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/progressbar/BUCK
@@ -0,0 +1,22 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'progressbar',
+  srcs = glob(['*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/csslayout:csslayout'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':progressbar',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/BUCK
new file mode 100644
index 000000000000..1457bc8e6ced
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/BUCK
@@ -0,0 +1,26 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'recyclerview',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/touch:touch'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
+    react_native_target('java/com/facebook/react/views/scroll:scroll'),
+    react_native_target('java/com/facebook/react/views/view:view'),
+    react_native_dep('third-party/android/support/v4:lib-support-v4'),
+    react_native_dep('third-party/android/support/v7/recyclerview:recyclerview'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':recyclerview',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/BUCK
new file mode 100644
index 000000000000..22caa2763be5
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/BUCK
@@ -0,0 +1,24 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'scroll',
+  srcs = glob(['*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/views/view:view'),
+    react_native_target('java/com/facebook/react/touch:touch'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+    react_native_dep('third-party/android/support/v4:lib-support-v4'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':scroll',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/BUCK
new file mode 100644
index 000000000000..214d47a55776
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/BUCK
@@ -0,0 +1,22 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'swiperefresh',
+  srcs = glob(['*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
+    react_native_target('java/com/facebook/react/views/scroll:scroll'),
+    react_native_dep('third-party/android/support/v4:lib-support-v4'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':swiperefresh',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK
new file mode 100644
index 000000000000..1ac7f3c79e6b
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK
@@ -0,0 +1,22 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'switchview',
+  srcs = glob(['*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/csslayout:csslayout'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
+    react_native_dep('third-party/android-support-for-standalone-apps/v7/appcompat:appcompat-23.1'),
+    react_native_dep('third-party/android-support-for-standalone-apps/v7/appcompat:res-for-react-native'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':switchview',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK
new file mode 100644
index 000000000000..df5bd7dee3c0
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK
@@ -0,0 +1,26 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'text',
+  srcs = glob(['*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/csslayout:csslayout'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
+    react_native_dep('libraries/fresco/fresco-react-native:fbcore'),
+    react_native_dep('libraries/fresco/fresco-react-native:fresco-react-native'),
+    react_native_dep('libraries/fresco/fresco-react-native:fresco-drawee'),
+    react_native_dep('libraries/fresco/fresco-react-native:imagepipeline'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':text',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/BUCK
new file mode 100644
index 000000000000..925dc15d3b0c
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/BUCK
@@ -0,0 +1,24 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'textinput',
+  srcs = glob(['*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/views/text:text'),
+    react_native_target('java/com/facebook/csslayout:csslayout'),
+    react_native_target('java/com/facebook/react/modules/core:core'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':textinput',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK
new file mode 100644
index 000000000000..253f3576a0f1
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK
@@ -0,0 +1,27 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'toolbar',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/csslayout:csslayout'),
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
+    react_native_dep('libraries/fresco/fresco-react-native:fresco-react-native'),
+    react_native_dep('libraries/fresco/fresco-react-native:fresco-drawee'),
+    react_native_dep('libraries/fresco/fresco-react-native:imagepipeline'),
+    react_native_dep('third-party/android-support-for-standalone-apps/v7/appcompat:appcompat-23.1'),
+    react_native_dep('third-party/android-support-for-standalone-apps/v7/appcompat:res-for-react-native'),
+    react_native_dep('third-party/android/support/v4:lib-support-v4'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':toolbar',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/view/BUCK
new file mode 100644
index 000000000000..dc06dec1873b
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/BUCK
@@ -0,0 +1,23 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'view',
+  srcs = glob(['*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/csslayout:csslayout'),
+    react_native_target('java/com/facebook/react/touch:touch'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':view',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/BUCK
new file mode 100644
index 000000000000..23bcd06f3f2f
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/BUCK
@@ -0,0 +1,23 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'viewpager',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
+    react_native_target('java/com/facebook/react/views/scroll:scroll'),
+    react_native_dep('third-party/android/support/v4:lib-support-v4'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':viewpager',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/webview/BUCK
new file mode 100644
index 000000000000..8da222d8dadd
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/BUCK
@@ -0,0 +1,20 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'webview',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':webview',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/systrace/BUCK b/ReactAndroid/src/main/java/com/facebook/systrace/BUCK
new file mode 100644
index 000000000000..6d222bb2a0f5
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/systrace/BUCK
@@ -0,0 +1,11 @@
+android_library(
+  name = 'systrace',
+  srcs = glob(['*.java']),
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':systrace',
+)
diff --git a/ReactAndroid/src/main/jni/first-party/fb/BUCK b/ReactAndroid/src/main/jni/first-party/fb/BUCK
new file mode 100644
index 000000000000..2890f37a14b6
--- /dev/null
+++ b/ReactAndroid/src/main/jni/first-party/fb/BUCK
@@ -0,0 +1,28 @@
+include_defs('//ReactAndroid/DEFS')
+
+cxx_library(
+  name = 'fb',
+  soname = 'libfb.so',
+  srcs = [
+    'assert.cpp',
+    'log.cpp',
+  ],
+  header_namespace='fb',
+  exported_headers=subdir_glob([
+    ('', '*.h'),
+    ('include/fb', '*.h'),
+  ]),
+  preprocessor_flags=[
+    '-DLOG_TAG="libfb"',
+  ],
+  # We want to use this library during bootstrap
+  can_be_asset = False,
+  deps = [
+    react_native_target('jni/third-party/android-ndk:android'),
+    react_native_target('jni/third-party/android-ndk:log'),
+    react_native_target('jni/third-party/glibc:dl'),
+  ],
+  visibility = [
+    'PUBLIC'
+  ],
+)
\ No newline at end of file
diff --git a/ReactAndroid/src/main/jni/first-party/jni/BUCK b/ReactAndroid/src/main/jni/first-party/jni/BUCK
new file mode 100644
index 000000000000..56d89123450a
--- /dev/null
+++ b/ReactAndroid/src/main/jni/first-party/jni/BUCK
@@ -0,0 +1,50 @@
+include_defs('//ReactAndroid/DEFS')
+
+cxx_library(
+  name = 'jni',
+  srcs = [
+    'Countable.cpp',
+    'Environment.cpp',
+    'fbjni.cpp',
+    'jni_helpers.cpp',
+    'LocalString.cpp',
+    'OnLoad.cpp',
+    'WeakReference.cpp',
+    'fbjni/Exceptions.cpp',
+    'fbjni/Hybrid.cpp',
+    'fbjni/References.cpp',
+  ],
+  platform_srcs = [
+    (r'.*\bandroid\b.*', [
+      'fbjni/android/ReferenceChecking.cpp',
+      ]),
+  ],
+  exported_headers = glob(['*.h', 'fbjni/*.h']),
+  header_namespace = 'jni',
+  soname = 'libfbjni.so',
+  preprocessor_flags = [
+    '-fexceptions',
+    '-DLOG_TAG="fbjni"',
+  ],
+  compiler_flags = [
+    '-fexceptions', 
+    '-frtti',
+  ],
+  # We want to use this library during bootstrap
+  can_be_asset = False,
+  exported_deps = [
+    react_native_target('jni/first-party/fb:fb'),
+    react_native_target('jni/third-party/android-ndk:log'),
+  ],
+  deps = [
+    # TODO Is this needed? Not used in the Gradle build.
+    # '//native/jni-hack:jni-hack',
+    # TODO should be react_native_target('java/com/facebook/jni:jni') but might not be needed as the bridge already depends on it.
+    # '//native/jni/java:java',
+  ],
+  visibility = ['PUBLIC'],
+)
+
+project_config(
+  src_target = ':jni',
+)
diff --git a/ReactAndroid/src/main/jni/react/BUCK b/ReactAndroid/src/main/jni/react/BUCK
new file mode 100644
index 000000000000..39e35cfe23df
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/BUCK
@@ -0,0 +1,74 @@
+include_defs('//ReactAndroid/DEFS')
+
+# We depend on JSC, support the same platforms
+SUPPORTED_PLATFORMS = '^android-(armv7|x86)$'
+
+DEPS = [
+  '//native/fb:fb',
+  '//native/jni:jni',
+  '//native/third-party/android-ndk:android',
+  '//xplat/fbsystrace:fbsystrace',
+  '//xplat/folly:molly',
+]
+
+PREPROCESSOR_FLAGS = [
+  '-DLOG_TAG="ReactNative"',
+  '-DWITH_JSC_EXTRA_TRACING=1',
+  '-DWITH_FBSYSTRACE=1',
+]
+
+def react_library(**kwargs):
+  cxx_library(
+    name = 'react',
+    visibility = [
+      react_native_target('jni/react/jni:jni'),
+    ],
+    deps = DEPS + [
+      '//native/third-party/jsc:jsc',
+      '//native/third-party/jsc:jsc_legacy_profiler',
+    ],
+    preprocessor_flags = PREPROCESSOR_FLAGS,
+    **kwargs
+  )
+
+react_library(
+  soname = 'libreactnative.so',
+  header_namespace = 'react',
+  supported_platforms_regex = SUPPORTED_PLATFORMS,
+  force_static = True,
+  srcs = [
+    'Bridge.cpp',
+    'JSModulesUnbundle.cpp',
+    'Value.cpp',
+    'MethodCall.cpp',
+    'JSCHelpers.cpp',
+    'JSCExecutor.cpp',
+    'JSCTracing.cpp',
+    'JSCMemory.cpp',
+    'JSCPerfLogging.cpp',
+    'JSCLegacyProfiler.cpp',
+    'JSCWebWorker.cpp',
+  ],
+  headers = [
+    'JSCTracing.h',
+    'JSCPerfLogging.h',
+    'JSCLegacyProfiler.h',
+    'JSCMemory.h'
+  ],
+  exported_headers = [
+    'Bridge.h',
+    'Executor.h',
+    'JSCExecutor.h',
+    'JSCHelpers.h',
+    'JSCWebWorker.h',
+    'MethodCall.h',
+    'JSModulesUnbundle.h',
+    'Value.h',
+  ],
+  compiler_flags = [
+    '-Wall',
+    '-std=c++11',
+    '-fexceptions',
+    '-fvisibility=hidden',
+  ],
+)
diff --git a/ReactAndroid/src/main/jni/react/jni/BUCK b/ReactAndroid/src/main/jni/react/jni/BUCK
new file mode 100644
index 000000000000..d29ea7dc604e
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/jni/BUCK
@@ -0,0 +1,64 @@
+include_defs('//ReactAndroid/DEFS')
+
+# We depend on JSC, support the same platforms
+SUPPORTED_PLATFORMS = '^android-(armv7|x86)$'
+
+DEPS = [
+  '//native/jni:jni',
+  '//xplat/folly:molly',
+]
+
+def jni_library(**kwargs):
+  cxx_library(
+    name='jni',
+    visibility = [
+      'PUBLIC',
+    ],
+    deps = DEPS + [
+      react_native_target('jni/react:react'),
+      '//native/third-party/jsc:jsc',
+      '//native/third-party/jsc:jsc_legacy_profiler',
+    ],
+    **kwargs
+  )
+
+jni_library(
+  soname = 'libreactnativejni.so',
+  header_namespace = 'react/jni',
+  supported_platforms_regex = SUPPORTED_PLATFORMS,
+  srcs = [
+    'JMessageQueueThread.cpp',
+    'JSLoader.cpp',
+    'NativeArray.cpp',
+    'OnLoad.cpp',
+    'ProxyExecutor.cpp',
+  ],
+  headers = [
+    'JSLoader.h',
+    'ProxyExecutor.h',
+  ],
+  exported_headers = [
+    'JMessageQueueThread.h',
+    'JNativeRunnable.h',
+    'NativeArray.h',
+    'ReadableNativeArray.h',
+    'WebWorkers.h',
+  ],
+  preprocessor_flags = [
+    '-DLOG_TAG="ReactNativeJNI"',
+    '-DWITH_FBSYSTRACE=1',
+    '-DWITH_FBJSCEXTENSIONS=1',
+  ],
+  compiler_flags = [
+    '-Wall',
+    '-Werror',
+    '-fexceptions',
+    '-std=c++11',
+    '-fvisibility=hidden',
+    '-frtti',
+  ],
+)
+
+project_config(
+  src_target = ':jni',
+)
diff --git a/ReactAndroid/src/main/jni/react/perftests/BUCK b/ReactAndroid/src/main/jni/react/perftests/BUCK
new file mode 100644
index 000000000000..2b0c46a7c134
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/perftests/BUCK
@@ -0,0 +1,21 @@
+include_defs('//ReactAndroid/DEFS')
+
+cxx_library(
+  name = 'perftests',
+  srcs = [ 'OnLoad.cpp' ],
+  soname = 'libreactnativetests.so',
+  preprocessor_flags = [
+    '-DLOG_TAG=\"ReactPerftests\"',
+  ],
+  deps = [
+    '//native:base',
+    '//native/jni:jni',
+  ],
+  visibility = [
+    '//instrumentation_tests/com/facebook/catalyst/...',
+  ],
+)
+
+project_config(
+  src_target = ':perftests',
+)
diff --git a/ReactAndroid/src/main/jni/third-party/android-ndk/BUCK b/ReactAndroid/src/main/jni/third-party/android-ndk/BUCK
new file mode 100644
index 000000000000..eb32890ccade
--- /dev/null
+++ b/ReactAndroid/src/main/jni/third-party/android-ndk/BUCK
@@ -0,0 +1,24 @@
+# NOTE(agallagher): The platform should really be responsible for providing
+# this type of implicit dependency.  As it is now, we need to setup a dummy
+# rules to model the Android NDK's built in libraries.
+
+LIBS = (
+  'android',
+  'EGL',
+  'GLESv2',
+  'jnigraphics',
+  'log',
+  'z',
+)
+
+for lib in LIBS:
+  prebuilt_cxx_library(
+    name = lib,
+    header_only = True,
+    exported_platform_linker_flags = [
+      ('android.*', ['-l' + lib]),
+    ],
+    visibility = [
+      'PUBLIC',
+    ],
+  )
\ No newline at end of file
diff --git a/ReactAndroid/src/main/jni/third-party/glibc/BUCK b/ReactAndroid/src/main/jni/third-party/glibc/BUCK
new file mode 100644
index 000000000000..847eed2711c5
--- /dev/null
+++ b/ReactAndroid/src/main/jni/third-party/glibc/BUCK
@@ -0,0 +1,52 @@
+# NOTE(agallagher): The platform really should be responsible for providing
+# this type of provided dependency.  As it is now, we need to setup dummy
+# rules to model glibc's libraries.
+
+# libpthread is implicitly included in the android runtime so, when building
+# on an android platform, we don't do anything.
+prebuilt_cxx_library(
+  name = 'pthread',
+  header_only = True,
+  exported_platform_linker_flags = [
+    ('android', []),
+    ('default', ['-lpthread']),
+    ('static', ['-lpthread']),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+prebuilt_cxx_library(
+  name = 'dl',
+  header_only = True,
+  exported_linker_flags = [
+    '-ldl',
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+prebuilt_cxx_library(
+  name = 'm',
+  header_only = True,
+  exported_linker_flags = [
+    '-lm',
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+prebuilt_cxx_library(
+  name = 'rt',
+  header_only = True,
+  exported_platform_linker_flags = [
+    ('android', []),  # Empty, since `-lc` is implicit
+    ('default', ['-lrt']),
+  ],
+  visibility = [
+      'PUBLIC',
+  ],
+)
\ No newline at end of file
diff --git a/ReactAndroid/src/main/libraries/fbcore/src/main/java/com/facebook/common/logging/BUCK b/ReactAndroid/src/main/libraries/fbcore/src/main/java/com/facebook/common/logging/BUCK
new file mode 100644
index 000000000000..cf221085156f
--- /dev/null
+++ b/ReactAndroid/src/main/libraries/fbcore/src/main/java/com/facebook/common/logging/BUCK
@@ -0,0 +1,11 @@
+android_prebuilt_aar(
+    name = 'logging',
+    aar = ':fbcore-binary-aar',
+    visibility = ['//ReactAndroid/...'],
+)
+
+remote_file(
+    name = 'fbcore-binary-aar',
+    url = 'mvn:com.facebook.fresco:fbcore:aar:0.8.1',
+    sha1 = 'cc46b3d564139bf63bb41534c7a723ee8119ae5f',
+)
diff --git a/ReactAndroid/src/main/libraries/fbcore/src/test/java/com/facebook/powermock/BUCK b/ReactAndroid/src/main/libraries/fbcore/src/test/java/com/facebook/powermock/BUCK
new file mode 100644
index 000000000000..7bb6f6802a4c
--- /dev/null
+++ b/ReactAndroid/src/main/libraries/fbcore/src/test/java/com/facebook/powermock/BUCK
@@ -0,0 +1,73 @@
+android_library(
+    name = 'powermock',
+    exported_deps = [
+        ':powermock-api-mockito',
+        ':powermock-api-support',
+        ':powermock-module-junit4-rule',
+        ':powermock-classloading-xstream',
+        ':powermock-core',
+    ],
+    visibility = ['//ReactAndroid/...',],
+)
+
+prebuilt_jar(
+    name = 'powermock-core',
+    binary_jar = ':download-powermock-core',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'download-powermock-core',
+    url = 'mvn:org.powermock:powermock-core:jar:1.6.2',
+    sha1 = 'ea04e79244e19dcf0c3ccf6863c5b028b4b58c9c',
+)
+
+prebuilt_jar(
+    name = 'powermock-api-mockito',
+    binary_jar = ':download-powermock-api-mockito',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'download-powermock-api-mockito',
+    url = 'mvn:org.powermock:powermock-api-mockito:jar:1.6.2',
+    sha1 = 'c213230ae20a7b422f3d622a261d0e3427d2464c',
+)
+
+prebuilt_jar(
+    name = 'powermock-api-support',
+    binary_jar = ':download-powermock-api-support',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'download-powermock-api-support',
+    url = 'mvn:org.powermock:powermock-api-support:jar:1.6.2',
+    sha1 = '93b21413b4ee99b7bc0dd34e1416fdca96866aaf',
+)
+
+prebuilt_jar(
+    name = 'powermock-module-junit4-rule',
+    binary_jar = ':download-powermock-module-junit4-rule',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'download-powermock-module-junit4-rule',
+    url = 'mvn:org.powermock:powermock-module-junit4-rule:jar:1.6.2',
+    sha1 = '4847638c5729b9f203e21144b0bdb5d34d888473',
+)
+
+prebuilt_jar(
+    name = 'powermock-classloading-xstream',
+    binary_jar = ':download-powermock-classloading-xstream',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'download-powermock-classloading-xstream',
+    url = 'mvn:org.powermock:powermock-classloading-xstream:jar:1.6.2',
+    sha1 = '3ced31cd7024fe365b9f3c8082d22c02434577da',
+)
+
+
diff --git a/ReactAndroid/src/main/libraries/fresco/fresco-react-native/BUCK b/ReactAndroid/src/main/libraries/fresco/fresco-react-native/BUCK
new file mode 100644
index 000000000000..9c618db04d71
--- /dev/null
+++ b/ReactAndroid/src/main/libraries/fresco/fresco-react-native/BUCK
@@ -0,0 +1,59 @@
+android_prebuilt_aar(
+    name = 'fresco-react-native',
+    aar = ':fresco-binary-aar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'fresco-binary-aar',
+    url = 'mvn:com.facebook.fresco:fresco:aar:0.8.1',
+    sha1 = 'f0a4f04318123e1597514b2abf56b7e66581f3f8',
+)
+
+android_prebuilt_aar(
+    name = 'fresco-drawee',
+    aar = ':drawee-binary-aar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'drawee-binary-aar',
+    url = 'mvn:com.facebook.fresco:drawee:aar:0.8.1',
+    sha1 = 'a944015ddf50fdad79302e42a85a351633c24472',
+)
+
+android_prebuilt_aar(
+    name = 'imagepipeline',
+    aar = ':imagepipeline-aar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'imagepipeline-aar',
+    url = 'mvn:com.facebook.fresco:imagepipeline:aar:0.8.1',
+    sha1 = '93fe3e629c03aea8f63dabd80a0e616b0caef65b',
+)
+
+android_prebuilt_aar(
+    name = 'fbcore',
+    aar = ':fbcore-aar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'fbcore-aar',
+    url = 'mvn:com.facebook.fresco:fbcore:aar:0.8.1',
+    sha1 = 'cc46b3d564139bf63bb41534c7a723ee8119ae5f',
+)
+
+android_prebuilt_aar(
+    name = 'imagepipeline-okhttp',
+    aar = ':imagepipeline-okhttp-binary-aar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'imagepipeline-okhttp-binary-aar',
+    url = 'mvn:com.facebook.fresco:imagepipeline-okhttp:aar:0.8.1',
+    sha1 = 'd6b16dbaab8b810620347355a425fb2982e33ef8',
+)
diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/BUCK b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/BUCK
new file mode 100644
index 000000000000..322ba2204e20
--- /dev/null
+++ b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/BUCK
@@ -0,0 +1,20 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'soloader',
+  srcs = glob(['*.java']),
+  proguard_config = 'soloader.pro',
+  deps = [
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+    # Be very careful adding new dependencies here, because this code
+    # has to run very early in the app startup process.
+    # Definitely do *not* depend on lib-base or guava.
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':soloader',
+)
diff --git a/ReactAndroid/src/main/res/BUCK b/ReactAndroid/src/main/res/BUCK
new file mode 100644
index 000000000000..90f796a13ee2
--- /dev/null
+++ b/ReactAndroid/src/main/res/BUCK
@@ -0,0 +1,19 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_resource(
+  name = 'devsupport',
+  res = 'devsupport',
+  package = 'com.facebook.react',
+  visibility = [
+    react_native_target('java/com/facebook/react/devsupport/...'),
+  ],
+)
+
+android_resource(
+  name = 'shell',
+  res = 'shell',
+  package = 'com.facebook.react',
+  visibility = [
+    'PUBLIC',
+  ],
+)
diff --git a/ReactAndroid/src/main/third-party/android-support-for-standalone-apps/v7/appcompat/BUCK b/ReactAndroid/src/main/third-party/android-support-for-standalone-apps/v7/appcompat/BUCK
new file mode 100644
index 000000000000..626b8dcdac7a
--- /dev/null
+++ b/ReactAndroid/src/main/third-party/android-support-for-standalone-apps/v7/appcompat/BUCK
@@ -0,0 +1,36 @@
+android_prebuilt_aar(
+    name = 'appcompat-23.1',
+    aar = ':appcompat-binary-aar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+# Unpack resources from the appcompat aar and merge their ids into the
+# generated com.facebook.react.R class.
+#
+# We do this for compatibility with Gradle: we build the open source
+# version React Native with both Buck and Gradle. See for example
+# ReactToolbarManager.java where we access the appcompat resources
+# via com.facebook.react.R.
+android_resource(
+    name = 'res-for-react-native',
+    res = ':res-unpacker-cmd',
+    package = 'com.facebook.react',
+    visibility = ['//ReactAndroid/...',],
+)
+
+genrule(
+    name = 'res-unpacker-cmd',
+    cmd = '$(exe :res-unpacker) $(location :appcompat-binary-aar) $OUT',
+    out = 'res',
+)
+
+python_binary(
+    name = 'res-unpacker',
+    main = 'res-unpacker.py',
+)
+
+remote_file(
+    name = 'appcompat-binary-aar',
+    url = 'mvn:com.android.support:appcompat-v7:aar:23.0.1',
+    sha1 = '7d659f671541394a8bc2b9f909950aa2a5ec87ff',
+)
diff --git a/ReactAndroid/src/main/third-party/android/support-annotations/BUCK b/ReactAndroid/src/main/third-party/android/support-annotations/BUCK
new file mode 100644
index 000000000000..0043bf0ce7b2
--- /dev/null
+++ b/ReactAndroid/src/main/third-party/android/support-annotations/BUCK
@@ -0,0 +1,11 @@
+prebuilt_jar(
+    name = 'android-support-annotations',
+    binary_jar = ':support-annotations-binary-aar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'support-annotations-binary-aar',
+    url = 'mvn:com.android.support:support-annotations:jar:22.2.0',
+    sha1 = '66b42a1f3eb7676070b7ef7f14b603483aecbee1',
+)
diff --git a/ReactAndroid/src/main/third-party/android/support/v4/BUCK b/ReactAndroid/src/main/third-party/android/support/v4/BUCK
new file mode 100644
index 000000000000..b0a85e26b286
--- /dev/null
+++ b/ReactAndroid/src/main/third-party/android/support/v4/BUCK
@@ -0,0 +1,23 @@
+android_prebuilt_aar(
+    name = 'lib-support-v4',
+    aar = ':lib-support-v4-binary-aar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'lib-support-v4-binary-aar',
+    url = 'mvn:com.android.support:support-v4:aar:23.0.1',
+    sha1 = '9e8da0e4ecf9f63258c7fbd273889252cba2d0c3',
+)
+
+prebuilt_jar(
+    name = 'lib-support-annotations',
+    binary_jar = ':lib-support-annotations-binary-aar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'lib-support-annotations-binary-aar',
+    url = 'mvn:com.android.support:support-annotations:jar:22.2.0',
+    sha1 = '66b42a1f3eb7676070b7ef7f14b603483aecbee1',
+)
diff --git a/ReactAndroid/src/main/third-party/android/support/v7/recyclerview/BUCK b/ReactAndroid/src/main/third-party/android/support/v7/recyclerview/BUCK
new file mode 100644
index 000000000000..80624867285f
--- /dev/null
+++ b/ReactAndroid/src/main/third-party/android/support/v7/recyclerview/BUCK
@@ -0,0 +1,13 @@
+android_prebuilt_aar(
+    name = 'recyclerview',
+    aar = ':recyclerview-binary-aar',
+    visibility = [
+        '//ReactAndroid/...',
+    ],
+)
+
+remote_file(
+    name = 'recyclerview-binary-aar',
+    url = 'mvn:com.android.support:recyclerview-v7:aar:23.0.1',
+    sha1 = '94d5f16be156521e135295e2ffa70d79ef8ad9d5',
+)
diff --git a/ReactAndroid/src/main/third-party/java/fest/BUCK b/ReactAndroid/src/main/third-party/java/fest/BUCK
new file mode 100644
index 000000000000..b802709c6dbb
--- /dev/null
+++ b/ReactAndroid/src/main/third-party/java/fest/BUCK
@@ -0,0 +1,11 @@
+prebuilt_jar(
+    name = 'fest',
+    binary_jar = ':fest-binary-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'fest-binary-jar',
+    url = 'mvn:org.easytesting:fest-assert-core:jar:2.0M10',
+    sha1 = 'cb7c91cf614901928ae405f19d9bcdedf82781db',
+)
diff --git a/ReactAndroid/src/main/third-party/java/infer-annotations/BUCK b/ReactAndroid/src/main/third-party/java/infer-annotations/BUCK
new file mode 100644
index 000000000000..2eabc6be2f0f
--- /dev/null
+++ b/ReactAndroid/src/main/third-party/java/infer-annotations/BUCK
@@ -0,0 +1,5 @@
+prebuilt_jar(
+    name = 'infer-annotations',
+    binary_jar = 'infer-annotations-1.5.jar',
+    visibility = ['//ReactAndroid/...'],
+)
diff --git a/ReactAndroid/src/main/third-party/java/jackson/BUCK b/ReactAndroid/src/main/third-party/java/jackson/BUCK
new file mode 100644
index 000000000000..818c52c8ae6f
--- /dev/null
+++ b/ReactAndroid/src/main/third-party/java/jackson/BUCK
@@ -0,0 +1,11 @@
+prebuilt_jar(
+    name = 'core',
+    binary_jar = ':jackson-core-binary-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'jackson-core-binary-jar',
+    url = 'mvn:com.fasterxml.jackson.core:jackson-core:jar:2.2.3',
+    sha1 = '1a0113da2cab5f4c216b4e5e7c1dbfaa67087e14',
+)
diff --git a/ReactAndroid/src/main/third-party/java/javapoet/BUCK b/ReactAndroid/src/main/third-party/java/javapoet/BUCK
new file mode 100644
index 000000000000..d16df03bf9fa
--- /dev/null
+++ b/ReactAndroid/src/main/third-party/java/javapoet/BUCK
@@ -0,0 +1,11 @@
+prebuilt_jar(
+    name = 'javapoet',
+    binary_jar = ':jsr305-binary-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'jsr305-binary-jar',
+    url = 'mvn:com.squareup:javapoet:jar:1.2.0',
+    sha1 = 'ad3ba65c1788f4d814a4da056323e2b84412fb3c',
+)
diff --git a/ReactAndroid/src/main/third-party/java/jsr-305/BUCK b/ReactAndroid/src/main/third-party/java/jsr-305/BUCK
new file mode 100644
index 000000000000..3b5bb0b0e0b8
--- /dev/null
+++ b/ReactAndroid/src/main/third-party/java/jsr-305/BUCK
@@ -0,0 +1,11 @@
+prebuilt_jar(
+    name = 'jsr-305',
+    binary_jar = ':jsr305-binary-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'jsr305-binary-jar',
+    url = 'mvn:com.google.code.findbugs:jsr305:jar:3.0.0',
+    sha1 = '5871fb60dc68d67da54a663c3fd636a10a532948',
+)
diff --git a/ReactAndroid/src/main/third-party/java/junit/BUCK b/ReactAndroid/src/main/third-party/java/junit/BUCK
new file mode 100644
index 000000000000..c5f67b01088d
--- /dev/null
+++ b/ReactAndroid/src/main/third-party/java/junit/BUCK
@@ -0,0 +1,11 @@
+prebuilt_jar(
+  name = 'junit',
+  binary_jar = ':download-junit',
+  visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+  name = 'download-junit',
+  url = 'mvn:junit:junit:jar:4.12',
+  sha1 = '2973d150c0dc1fefe998f834810d68f278ea58ec',
+)
diff --git a/ReactAndroid/src/main/third-party/java/mockito/BUCK b/ReactAndroid/src/main/third-party/java/mockito/BUCK
new file mode 100644
index 000000000000..ef93db4abb2b
--- /dev/null
+++ b/ReactAndroid/src/main/third-party/java/mockito/BUCK
@@ -0,0 +1,11 @@
+prebuilt_jar(
+    name = 'mockito',
+    binary_jar = ':mockito-binary-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'mockito-binary-jar',
+    url = 'mvn:org.mockito:mockito-core:jar:1.10.19',
+    sha1 = 'e8546f5bef4e061d8dd73895b4e8f40e3fe6effe',
+)
diff --git a/ReactAndroid/src/main/third-party/java/okhttp/BUCK b/ReactAndroid/src/main/third-party/java/okhttp/BUCK
new file mode 100644
index 000000000000..f4da3fa0b0a1
--- /dev/null
+++ b/ReactAndroid/src/main/third-party/java/okhttp/BUCK
@@ -0,0 +1,23 @@
+prebuilt_jar(
+    name = 'okhttp',
+    binary_jar = ':okhttp-binary-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'okhttp-binary-jar',
+    url = 'mvn:com.squareup.okhttp:okhttp:jar:2.5.0',
+    sha1 = '4de2b4ed3445c37ec1720a7d214712e845a24636'
+)
+
+prebuilt_jar(
+    name = 'okhttp-ws',
+    binary_jar = ':okhttp-ws-binary-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'okhttp-ws-binary-jar',
+    url = 'mvn:com.squareup.okhttp:okhttp-ws:jar:2.5.0',
+    sha1 = '0e9753b7dcae5deca92e871c5c759067070b07bc',
+)
diff --git a/ReactAndroid/src/main/third-party/java/okio/BUCK b/ReactAndroid/src/main/third-party/java/okio/BUCK
new file mode 100644
index 000000000000..61ad012c23cd
--- /dev/null
+++ b/ReactAndroid/src/main/third-party/java/okio/BUCK
@@ -0,0 +1,11 @@
+prebuilt_jar(
+    name = 'okio',
+    binary_jar = ':okio-binary-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'okio-binary-jar',
+    url = 'mvn:com.squareup.okio:okio:jar:1.6.0',
+    sha1 = '98476622f10715998eacf9240d6b479f12c66143',
+)
diff --git a/ReactAndroid/src/main/third-party/java/robolectric3/robolectric/BUCK b/ReactAndroid/src/main/third-party/java/robolectric3/robolectric/BUCK
new file mode 100644
index 000000000000..7e30d1c029ee
--- /dev/null
+++ b/ReactAndroid/src/main/third-party/java/robolectric3/robolectric/BUCK
@@ -0,0 +1,45 @@
+android_library(
+    name = 'robolectric',
+    exported_deps = [
+        ':robolectric-core',
+        ':robolectric-resources',
+        ':robolectric-annotations',
+    ],
+    visibility = ['//ReactAndroid/...',],
+)
+
+prebuilt_jar(
+    name = 'robolectric-core',
+    binary_jar = ':robolectric-binary-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'robolectric-binary-jar',
+    url = 'mvn:org.robolectric:robolectric:jar:3.0',
+    sha1 = 'f888cea3bc1a24110e315eb9827ab593610ea62f',
+)
+
+prebuilt_jar(
+    name = 'robolectric-resources',
+    binary_jar = ':robolectric-resources-binary-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'robolectric-resources-binary-jar',
+    url = 'mvn:org.robolectric:robolectric-resources:jar:3.0',
+    sha1 = '1ab609054aab67cd13a434567467f4b4774f2465',
+)
+
+prebuilt_jar(
+    name = 'robolectric-annotations',
+    binary_jar = ':robolectric-annotations-binary-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'robolectric-annotations-binary-jar',
+    url = 'mvn:org.robolectric:robolectric-annotations:jar:3.0',
+    sha1 = '2a6cfc072d7680694c1ff893c5dc8fec33163110',
+)
diff --git a/ReactAndroid/src/main/third-party/java/stetho/BUCK b/ReactAndroid/src/main/third-party/java/stetho/BUCK
new file mode 100644
index 000000000000..598e76ba87b0
--- /dev/null
+++ b/ReactAndroid/src/main/third-party/java/stetho/BUCK
@@ -0,0 +1,23 @@
+prebuilt_jar(
+    name = 'stetho',
+    binary_jar = ':stetho-binary-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'stetho-binary-jar',
+    url = 'mvn:com.facebook.stetho:stetho:jar:1.2.0',
+    sha1 = '1d6cdb8ce8185b8b23213fad48a83987fb6d2d67',
+)
+
+prebuilt_jar(
+    name = 'stetho-okhttp',
+    binary_jar = ':stetho-okhttp-binary-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'stetho-okhttp-binary-jar',
+    url = 'mvn:com.facebook.stetho:stetho-okhttp:jar:1.2.0',
+    sha1 = '6c5c9380e245c4ff5be2b2a49dcbb0200c39798e',
+)
diff --git a/ReactAndroid/src/test/java/com/facebook/react/bridge/BUCK b/ReactAndroid/src/test/java/com/facebook/react/bridge/BUCK
new file mode 100644
index 000000000000..22f7d5535c78
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/bridge/BUCK
@@ -0,0 +1,19 @@
+include_defs('//ReactAndroid/DEFS')
+
+STANDARD_TEST_SRCS = [
+  '**/*Test.java',
+]
+
+android_library(
+  name = 'testhelpers',
+  srcs = glob(['**/*.java'], excludes = STANDARD_TEST_SRCS),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_dep('third-party/java/mockito:mockito'),
+    react_native_dep('third-party/java/robolectric3/robolectric:robolectric'),
+  ],
+  visibility = [
+    'PUBLIC'
+  ],
+)
diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/BUCK b/ReactAndroid/src/test/java/com/facebook/react/modules/BUCK
new file mode 100644
index 000000000000..5e9df2b0b99d
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/modules/BUCK
@@ -0,0 +1,41 @@
+include_defs('//ReactAndroid/DEFS')
+
+robolectric3_test(
+  # Please change the contact to the oncall of your team
+  contacts = ['oncall+fbandroid_sheriff@xmail.facebook.com'],
+  name = 'modules',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/csslayout:csslayout'),
+    react_native_target('java/com/facebook/react:react'),
+    react_native_target('java/com/facebook/react/animation:animation'),
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/modules/clipboard:clipboard'),
+    react_native_target('java/com/facebook/react/modules/common:common'),
+    react_native_target('java/com/facebook/react/modules/core:core'),
+    react_native_target('java/com/facebook/react/modules/debug:debug'),
+    react_native_target('java/com/facebook/react/modules/dialog:dialog'),
+    react_native_target('java/com/facebook/react/modules/network:network'),
+    react_native_target('java/com/facebook/react/modules/storage:storage'),
+    react_native_target('java/com/facebook/react/modules/systeminfo:systeminfo'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_target('java/com/facebook/react/touch:touch'),
+
+    react_native_tests_target('java/com/facebook/react/bridge:testhelpers'),
+    react_native_dep('libraries/fbcore/src/test/java/com/facebook/powermock:powermock'),
+    react_native_dep('third-party/java/robolectric3/robolectric:robolectric'),
+    react_native_dep('third-party/java/fest:fest'),
+    react_native_dep('third-party/java/junit:junit'),
+    react_native_dep('third-party/java/okio:okio'),
+    react_native_dep('third-party/java/mockito:mockito'),
+    react_native_dep('third-party/java/okhttp:okhttp'),
+  ],
+  visibility = [
+    'PUBLIC'
+  ],
+)
+
+project_config(
+  test_target = ':modules',
+)
diff --git a/ReactAndroid/src/test/java/org/mockito/configuration/BUCK b/ReactAndroid/src/test/java/org/mockito/configuration/BUCK
new file mode 100644
index 000000000000..f4d1366df610
--- /dev/null
+++ b/ReactAndroid/src/test/java/org/mockito/configuration/BUCK
@@ -0,0 +1,16 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'configuration',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_dep('third-party/java/mockito:mockito'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':configuration',
+)

From cd2eed0d364bb47e59049f760ed56baccb77e03c Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Fri, 22 Jan 2016 08:39:44 -0800
Subject: [PATCH 0851/1411] RCTGzipData() acceps nil input, but was not marked
 as returning nullable output

Reviewed By: milend

Differential Revision: D2854721

fb-gh-sync-id: 336b3261f1694bcc173f267582561c0314c0cea0
---
 React/Base/RCTUtils.h | 2 +-
 React/Base/RCTUtils.m | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/React/Base/RCTUtils.h b/React/Base/RCTUtils.h
index 811c66d1ad67..30febd5a35d2 100644
--- a/React/Base/RCTUtils.h
+++ b/React/Base/RCTUtils.h
@@ -97,7 +97,7 @@ RCT_EXTERN double RCTZeroIfNaN(double value);
 RCT_EXTERN NSURL *RCTDataURL(NSString *mimeType, NSData *data);
 
 // Gzip functionality - compression level in range 0 - 1 (-1 for default)
-RCT_EXTERN NSData *RCTGzipData(NSData *__nullable data, float level);
+RCT_EXTERN NSData *__nullable RCTGzipData(NSData *__nullable data, float level);
 
 // Returns the relative path within the main bundle for an absolute URL
 // (or nil, if the URL does not specify a path within the main bundle)
diff --git a/React/Base/RCTUtils.m b/React/Base/RCTUtils.m
index d2a0916b3490..7b69da74b969 100644
--- a/React/Base/RCTUtils.m
+++ b/React/Base/RCTUtils.m
@@ -451,7 +451,7 @@ BOOL RCTIsGzippedData(NSData *__nullable data)
   return (data.length >= 2 && bytes[0] == 0x1f && bytes[1] == 0x8b);
 }
 
-NSData *RCTGzipData(NSData *__nullable input, float level)
+NSData *__nullable RCTGzipData(NSData *__nullable input, float level)
 {
   if (input.length == 0 || RCTIsGzippedData(input)) {
     return input;

From 798acac18e9daab543d7b2e947bc2ed760703d99 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Fri, 22 Jan 2016 10:37:44 -0800
Subject: [PATCH 0852/1411] Fix a crash in Image when passed an invalid uri

Summary:
public

Fix https://github.com/facebook/react-native/issues/5465

Instead of returning null when we fail to parse the Uri, just return an empty Uri which somewhat hides the problem but does prevent the crash

Reviewed By: mkonicek

Differential Revision: D2854902

fb-gh-sync-id: 71265d5e52302e174b898af5be25ac698abcf9ab
---
 .../java/com/facebook/react/views/image/ReactImageView.java   | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
index 515c957d0aeb..58ebb0c804e3 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
@@ -352,11 +352,11 @@ private static int getResourceDrawableId(Context context, @Nullable String name)
     return resId > 0 ? context.getResources().getDrawable(resId) : null;
   }
 
-  private static @Nullable Uri getResourceDrawableUri(Context context, @Nullable String name) {
+  private static Uri getResourceDrawableUri(Context context, @Nullable String name) {
     int resId = getResourceDrawableId(context, name);
     return resId > 0 ? new Uri.Builder()
         .scheme(UriUtil.LOCAL_RESOURCE_SCHEME)
         .path(String.valueOf(resId))
-        .build() : null;
+        .build() : Uri.EMPTY;
   }
 }

From 722bc73c0de2639ba07a08f1351d8f21e1b1b84d Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Fri, 22 Jan 2016 10:39:13 -0800
Subject: [PATCH 0853/1411] Distinguish between module ID and name

Reviewed By: martinbigio

Differential Revision: D2854975

fb-gh-sync-id: 8c75037d5d7f6155369d4ec581158ebabf445bac
---
 packager/react-packager/src/Bundler/Bundle.js |  5 +---
 .../react-packager/src/Bundler/BundleBase.js  | 18 ++++++++++---
 .../src/Bundler/__tests__/Bundle-test.js      | 25 +++++++++++++++++++
 3 files changed, 41 insertions(+), 7 deletions(-)

diff --git a/packager/react-packager/src/Bundler/Bundle.js b/packager/react-packager/src/Bundler/Bundle.js
index 4f54e3be3919..f02127f331b3 100644
--- a/packager/react-packager/src/Bundler/Bundle.js
+++ b/packager/react-packager/src/Bundler/Bundle.js
@@ -341,14 +341,11 @@ class Bundle extends BundleBase {
   }
 
   toJSON() {
-    if (!this._finalized) {
-      throw new Error('Cannot serialize bundle unless finalized');
-    }
+    this.assertFinalized('Cannot serialize bundle unless finalized');
 
     return {
       ...super.toJSON(),
       sourceMapUrl: this._sourceMapUrl,
-      mainModuleId: super.getMainModuleId(),
       numPrependedModules: this._numPrependedModules,
       numRequireCalls: this._numRequireCalls,
     };
diff --git a/packager/react-packager/src/Bundler/BundleBase.js b/packager/react-packager/src/Bundler/BundleBase.js
index 635f87e733e7..b9e1cbe36c84 100644
--- a/packager/react-packager/src/Bundler/BundleBase.js
+++ b/packager/react-packager/src/Bundler/BundleBase.js
@@ -16,6 +16,7 @@ class BundleBase {
     this._finalized = false;
     this._modules = [];
     this._assets = [];
+    this._mainModuleId = this._mainModuleName = undefined;
   }
 
   getMainModuleId() {
@@ -26,6 +27,14 @@ class BundleBase {
     this._mainModuleId = moduleId;
   }
 
+  getMainModuleName() {
+    return this._mainModuleName;
+  }
+
+  setMainModuleName(moduleName) {
+    this._mainModuleName = moduleName;
+  }
+
   addModule(module) {
     if (!module instanceof ModuleTransport) {
       throw new Error('Expeceted a ModuleTransport object');
@@ -65,9 +74,9 @@ class BundleBase {
     return this._source;
   }
 
-  assertFinalized() {
+  assertFinalized(message) {
     if (!this._finalized) {
-      throw new Error('Bundle needs to be finalized before getting any source');
+      throw new Error(message || 'Bundle needs to be finalized before getting any source');
     }
   }
 
@@ -75,13 +84,16 @@ class BundleBase {
     return {
       modules: this._modules,
       assets: this._assets,
+      mainModuleId: this.getMainModuleId(),
+      mainModuleName: this.getMainModuleName(),
     };
   }
 
   static fromJSON(bundle, json) {
     bundle._assets = json.assets;
     bundle._modules = json.modules;
-    bundle._mainModuleId = json.mainModuleId;
+    bundle.setMainModuleId(json.mainModuleId);
+    bundle.setMainModuleName(json.mainModuleName);
 
     Object.freeze(bundle._modules);
     Object.seal(bundle._modules);
diff --git a/packager/react-packager/src/Bundler/__tests__/Bundle-test.js b/packager/react-packager/src/Bundler/__tests__/Bundle-test.js
index b82f4a6c272a..5e5fca226cc4 100644
--- a/packager/react-packager/src/Bundler/__tests__/Bundle-test.js
+++ b/packager/react-packager/src/Bundler/__tests__/Bundle-test.js
@@ -311,6 +311,31 @@ describe('Bundle', () => {
       expect(bundle.getEtag()).toEqual(eTag);
     });
   });
+
+  describe('main module name and id:', function() {
+    it('keeps distinct module names and IDs', function() {
+      const id = 'arbitrary module ID';
+      const name = 'arbitrary module name';
+      bundle.setMainModuleId(id);
+      bundle.setMainModuleName(name);
+
+      expect(bundle.getMainModuleId()).toEqual(id);
+      expect(bundle.getMainModuleName()).toEqual(name);
+    });
+
+    it('can serialize and deserialize module ID and name', function() {
+      const id = 'arbitrary module ID';
+      const name = 'arbitrary module name';
+      bundle.setMainModuleId(id);
+      bundle.setMainModuleName(name);
+      bundle.finalize({});
+
+      const deserialized = Bundle.fromJSON(bundle.toJSON());
+
+      expect(deserialized.getMainModuleId()).toEqual(id);
+      expect(deserialized.getMainModuleName()).toEqual(name);
+    });
+  });
 });
 
 

From cb5314243e562852d8afbf1d242bb80a444911fd Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Fri, 22 Jan 2016 18:53:47 +0000
Subject: [PATCH 0854/1411] Update release.sh

---
 scripts/release.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/scripts/release.sh b/scripts/release.sh
index f2cb68e6ddc7..ce3b9dba9bd3 100755
--- a/scripts/release.sh
+++ b/scripts/release.sh
@@ -116,5 +116,5 @@ info "   - git tag v${RELEASE}.0-rc ${RELEASE}-stable"
 info "   - git push --tags"
 info "   - Once the change propagates to JCenter:"
 info "     - npm set registry https://registry.npmjs.org/"
-info "     - npm publish"
-info "     - Only when doing a non-rc release: npm dist-tag add react-native@${RELEASE}.0 latest"
+info "     - When doing a RC release: npm publish --tag next"
+info "     - When doing a non-RC release: npm publish  # Sets the latest tag automatically"

From f20453baee8c1cbe07e8f864a7c13be57537e865 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Fri, 22 Jan 2016 18:55:35 +0000
Subject: [PATCH 0855/1411] Update Releases.md

---
 Releases.md | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Releases.md b/Releases.md
index 80a15f9a78dc..324d9edd2259 100644
--- a/Releases.md
+++ b/Releases.md
@@ -47,6 +47,8 @@ To go through all the commits that went into a release, one way is to use the gi
 
 Skip this for now, ping @mkonicek on messenger and he'll handle it. Docs [here](https://github.com/facebook/react-native/blob/master/Releases-publish.md).
 
+IMPORTANT:  `npm publish` will automatically set the latest tag. **When doing an RC release**, run `npm publish --tag next` - this way people need to opt in to get the RC release.
+
 ## Track bug reports from the community during the following two weeks and make sure they get fixed
 
 A good way to do this is to create a github issue and post about it so people can report bugs: https://github.com/facebook/react-native/issues/5201

From 2cbc9127560c5f0f89ae5aa6ff863b1818f1c7c3 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Fri, 22 Jan 2016 11:31:40 -0800
Subject: [PATCH 0856/1411] Added support for width & height for text images

Summary:
public

Previously, `<Image>` elements embedded inside `<Text>` ignored all style attributes and props apart from `source`. Now, the `width`, `height` and `resizeMode` styles are observed. I've also added a transparent placeholder to be displayed while the image is loading, to prevent the layout from changing after the image has loaded.

Reviewed By: javache

Differential Revision: D2838659

fb-gh-sync-id: c27f9685b6976705ac2b24075922b2bf247e06ba
---
 Examples/UIExplorer/TextExample.ios.js        |  2 +-
 .../UIExplorerUnitTests/RCTImageUtilTests.m   | 48 +++++++++++++++
 Libraries/Image/Image.ios.js                  | 29 +++++----
 Libraries/Image/RCTImageUtils.h               |  7 +++
 Libraries/Image/RCTImageUtils.m               | 45 ++++++++++++++
 Libraries/Image/RCTShadowVirtualImage.h       |  2 +
 Libraries/Image/RCTShadowVirtualImage.m       | 61 +++++++++++--------
 Libraries/Image/RCTVirtualImageManager.m      |  1 +
 Libraries/Text/RCTShadowText.m                |  2 -
 9 files changed, 157 insertions(+), 40 deletions(-)

diff --git a/Examples/UIExplorer/TextExample.ios.js b/Examples/UIExplorer/TextExample.ios.js
index fbf434cdeccb..3de37c42349d 100644
--- a/Examples/UIExplorer/TextExample.ios.js
+++ b/Examples/UIExplorer/TextExample.ios.js
@@ -419,7 +419,7 @@ exports.examples = [
     return (
       <View>
         <Text>
-          This text contains an inline image <Image source={require('./flux.png')}/>. Neat, huh?
+          This text contains an inline image <Image source={require('./flux.png')} style={{width: 30, height: 11, resizeMode: 'cover'}}/>. Neat, huh?
         </Text>
       </View>
     );
diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTImageUtilTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTImageUtilTests.m
index 19229d045cc0..810e079ab211 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTImageUtilTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTImageUtilTests.m
@@ -133,4 +133,52 @@ - (void)testScaling
   RCTAssertEqualRects(expected, result);
 }
 
+- (void)testPlaceholderImage
+{
+  CGSize size = {45, 22};
+  CGFloat expectedScale = 1.0;
+  UIImage *image = RCTGetPlaceholderImage(size, nil);
+  RCTAssertEqualSizes(size, image.size);
+  XCTAssertEqual(expectedScale, image.scale);
+}
+
+- (void)testPlaceholderNonintegralSize
+{
+  CGSize size = {3.0/2, 7.0/3};
+  CGFloat expectedScale = 6;
+  CGSize pixelSize = {
+    round(size.width * expectedScale),
+    round(size.height * expectedScale)
+  };
+  UIImage *image = RCTGetPlaceholderImage(size, nil);
+  RCTAssertEqualSizes(size, image.size);
+  XCTAssertEqual(pixelSize.width, CGImageGetWidth(image.CGImage));
+  XCTAssertEqual(pixelSize.height, CGImageGetHeight(image.CGImage));
+  XCTAssertEqual(expectedScale, image.scale);
+}
+
+- (void)testPlaceholderSquareImage
+{
+  CGSize size = {333, 333};
+  CGFloat expectedScale = 1.0/333;
+  CGSize pixelSize = {1, 1};
+  UIImage *image = RCTGetPlaceholderImage(size, nil);
+  RCTAssertEqualSizes(size, image.size);
+  XCTAssertEqual(pixelSize.width, CGImageGetWidth(image.CGImage));
+  XCTAssertEqual(pixelSize.height, CGImageGetHeight(image.CGImage));
+  XCTAssertEqual(expectedScale, image.scale);
+}
+
+- (void)testPlaceholderNonsquareImage
+{
+  CGSize size = {640, 480};
+  CGFloat expectedScale = 1.0/160;
+  CGSize pixelSize = {4, 3};
+  UIImage *image = RCTGetPlaceholderImage(size, nil);
+  RCTAssertEqualSizes(size, image.size);
+  XCTAssertEqual(pixelSize.width, CGImageGetWidth(image.CGImage));
+  XCTAssertEqual(pixelSize.height, CGImageGetHeight(image.CGImage));
+  XCTAssertEqual(expectedScale, image.scale);
+}
+
 @end
diff --git a/Libraries/Image/Image.ios.js b/Libraries/Image/Image.ios.js
index 970ef172cdd9..4830a6dec336 100644
--- a/Libraries/Image/Image.ios.js
+++ b/Libraries/Image/Image.ios.js
@@ -196,10 +196,10 @@ var Image = React.createClass({
 
   render: function() {
     var source = resolveAssetSource(this.props.source) || {};
-    var {width, height} = source;
+    var {width, height, uri} = source;
     var style = flattenStyle([{width, height}, styles.base, this.props.style]) || {};
 
-    var isNetwork = source.uri && source.uri.match(/^https?:/);
+    var isNetwork = uri && uri.match(/^https?:/);
     var RawImage = isNetwork ? RCTNetworkImageView : RCTImageView;
     var resizeMode = this.props.resizeMode || (style || {}).resizeMode || 'cover'; // Workaround for flow bug t7737108
     var tintColor = (style || {}).tintColor; // Workaround for flow bug t7737108
@@ -211,18 +211,21 @@ var Image = React.createClass({
     }
 
     if (this.context.isInAParentText) {
-      return <RCTVirtualImage source={source}/>;
-    } else {
-      return (
-        <RawImage
-          {...this.props}
-          style={style}
-          resizeMode={resizeMode}
-          tintColor={tintColor}
-          source={source}
-        />
-      );
+      RawImage = RCTVirtualImage;
+      if (!width || !height) {
+        console.warn('You must specify a width and height for the image %s', uri); 
+      }
     }
+
+    return (
+      <RawImage
+        {...this.props}
+        style={style}
+        resizeMode={resizeMode}
+        tintColor={tintColor}
+        source={source}
+      />
+    );
   },
 });
 
diff --git a/Libraries/Image/RCTImageUtils.h b/Libraries/Image/RCTImageUtils.h
index f870bda675a2..0c855790e400 100644
--- a/Libraries/Image/RCTImageUtils.h
+++ b/Libraries/Image/RCTImageUtils.h
@@ -93,4 +93,11 @@ RCT_EXTERN UIImage *__nullable RCTTransformImage(UIImage *image,
  */
 RCT_EXTERN BOOL RCTImageHasAlpha(CGImageRef image);
 
+/**
+ * Create a solid placeholder image of the specified size and color to display
+ * while loading an image. If color is not specified, image will be transparent.
+ */
+RCT_EXTERN UIImage *__nullable RCTGetPlaceholderImage(CGSize size,
+                                                      UIColor *__nullable color);
+
 NS_ASSUME_NONNULL_END
diff --git a/Libraries/Image/RCTImageUtils.m b/Libraries/Image/RCTImageUtils.m
index d484ea238642..a89872508f74 100644
--- a/Libraries/Image/RCTImageUtils.m
+++ b/Libraries/Image/RCTImageUtils.m
@@ -16,6 +16,8 @@
 #import "RCTLog.h"
 #import "RCTUtils.h"
 
+static const CGFloat RCTThresholdValue = 0.0001;
+
 static CGFloat RCTCeilValue(CGFloat value, CGFloat scale)
 {
   return ceil(value * scale) / scale;
@@ -334,3 +336,46 @@ BOOL RCTImageHasAlpha(CGImageRef image)
       return YES;
   }
 }
+
+UIImage *__nullable RCTGetPlaceholderImage(CGSize size,
+                                           UIColor *__nullable color)
+{
+  if (size.width <= 0 || size.height <= 0) {
+    return nil;
+  }
+
+  // If dimensions are nonintegral, increase scale
+  CGFloat scale = 1;
+  if (size.width - floor(size.width) > RCTThresholdValue) {
+    scale *= round(1.0 / (size.width - floor(size.width)));
+  }
+  if (size.height - floor(size.height) > RCTThresholdValue) {
+    scale *= round(1.0 / (size.height - floor(size.height)));
+  }
+
+  // Use Euclid's algorithm to find the greatest common divisor
+  // between the specified placeholder width and height;
+  NSInteger a = size.width * scale;
+  NSInteger b = size.height * scale;
+  while (a != 0) {
+    NSInteger c = a;
+    a = b % a;
+    b = c;
+  }
+
+  // Divide the placeholder image scale by the GCD we found above. This allows
+  // us to save memory by creating the smallest possible placeholder image
+  // with the correct aspect ratio, then scaling it up at display time.
+  scale /= b;
+
+  // Fill image with specified color
+  CGFloat alpha = CGColorGetAlpha(color.CGColor);
+  UIGraphicsBeginImageContextWithOptions(size, ABS(1.0 - alpha) < RCTThresholdValue, scale);
+  if (alpha > 0) {
+    [color setFill];
+    UIRectFill((CGRect){CGPointZero, size});
+  }
+  UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
+  UIGraphicsEndImageContext();
+  return image;
+}
diff --git a/Libraries/Image/RCTShadowVirtualImage.h b/Libraries/Image/RCTShadowVirtualImage.h
index bd8bb51ae024..b9623f736f23 100644
--- a/Libraries/Image/RCTShadowVirtualImage.h
+++ b/Libraries/Image/RCTShadowVirtualImage.h
@@ -10,6 +10,7 @@
 #import "RCTShadowView.h"
 #import "RCTImageComponent.h"
 #import "RCTImageSource.h"
+#import "RCTResizeMode.h"
 
 @class RCTBridge;
 
@@ -22,5 +23,6 @@
 - (instancetype)initWithBridge:(RCTBridge *)bridge;
 
 @property (nonatomic, strong) RCTImageSource *source;
+@property (nonatomic, assign) RCTResizeMode resizeMode;
 
 @end
diff --git a/Libraries/Image/RCTShadowVirtualImage.m b/Libraries/Image/RCTShadowVirtualImage.m
index d6b0153d11cc..f950e63774a5 100644
--- a/Libraries/Image/RCTShadowVirtualImage.m
+++ b/Libraries/Image/RCTShadowVirtualImage.m
@@ -9,9 +9,11 @@
 
 #import "RCTShadowVirtualImage.h"
 #import "RCTImageLoader.h"
+#import "RCTImageUtils.h"
 #import "RCTBridge.h"
 #import "RCTConvert.h"
 #import "RCTUIManager.h"
+#import "RCTUtils.h"
 
 @implementation RCTShadowVirtualImage
 {
@@ -31,36 +33,47 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
 
 RCT_NOT_IMPLEMENTED(-(instancetype)init)
 
-- (void)setSource:(RCTImageSource *)source
+- (void)didSetProps:(NSArray<NSString *> *)changedProps
 {
-  if (![source isEqual:_source]) {
+  [super didSetProps:changedProps];
 
-    // Cancel previous request
-    if (_cancellationBlock) {
-      _cancellationBlock();
-    }
+  if (changedProps.count == 0) {
+    // No need to reload image
+    return;
+  }
 
-    _source = source;
+  // Cancel previous request
+  if (_cancellationBlock) {
+    _cancellationBlock();
+  }
 
-    __weak RCTShadowVirtualImage *weakSelf = self;
-    _cancellationBlock = [_bridge.imageLoader loadImageWithTag:source.imageURL.absoluteString
-                                                          size:source.size
-                                                         scale:source.scale
-                                                    resizeMode:RCTResizeModeStretch
-                                                 progressBlock:nil
-                                               completionBlock:^(NSError *error, UIImage *image) {
+  CGSize imageSize = {
+    RCTZeroIfNaN(self.width),
+    RCTZeroIfNaN(self.height),
+  };
 
-      dispatch_async(_bridge.uiManager.methodQueue, ^{
-        RCTShadowVirtualImage *strongSelf = weakSelf;
-        if (![source isEqual:strongSelf.source]) {
-          // Bail out if source has changed since we started loading
-          return;
-        }
-        strongSelf->_image = image;
-        [strongSelf dirtyText];
-      });
-    }];
+  if (!_image) {
+    _image = RCTGetPlaceholderImage(imageSize, nil);
   }
+
+  __weak RCTShadowVirtualImage *weakSelf = self;
+  _cancellationBlock = [_bridge.imageLoader loadImageWithTag:_source.imageURL.absoluteString
+                                                        size:imageSize
+                                                       scale:RCTScreenScale()
+                                                  resizeMode:_resizeMode
+                                               progressBlock:nil
+                                             completionBlock:^(NSError *error, UIImage *image) {
+
+    dispatch_async(_bridge.uiManager.methodQueue, ^{
+      RCTShadowVirtualImage *strongSelf = weakSelf;
+      if (![_source isEqual:strongSelf.source]) {
+        // Bail out if source has changed since we started loading
+        return;
+      }
+      strongSelf->_image = image;
+      [strongSelf dirtyText];
+    });
+  }];
 }
 
 - (void)dealloc
diff --git a/Libraries/Image/RCTVirtualImageManager.m b/Libraries/Image/RCTVirtualImageManager.m
index d497026ab740..6311010f4ce2 100644
--- a/Libraries/Image/RCTVirtualImageManager.m
+++ b/Libraries/Image/RCTVirtualImageManager.m
@@ -20,5 +20,6 @@ - (RCTShadowView *)shadowView
 }
 
 RCT_EXPORT_SHADOW_PROPERTY(source, RCTImageSource)
+RCT_EXPORT_SHADOW_PROPERTY(resizeMode, UIViewContentMode)
 
 @end
diff --git a/Libraries/Text/RCTShadowText.m b/Libraries/Text/RCTShadowText.m
index eebbc9c32b98..a3286a88b332 100644
--- a/Libraries/Text/RCTShadowText.m
+++ b/Libraries/Text/RCTShadowText.m
@@ -213,8 +213,6 @@ - (NSAttributedString *)_attributedStringWithFontFamily:(NSString *)fontFamily
         NSTextAttachment *imageAttachment = [NSTextAttachment new];
         imageAttachment.image = image;
         [attributedString appendAttributedString:[NSAttributedString attributedStringWithAttachment:imageAttachment]];
-      } else {
-        //TODO: add placeholder image?
       }
     } else {
       RCTLogError(@"<Text> can't have any children except <Text>, <Image> or raw strings");

From 717207a23f951ecc9080e6db0ad532daefc28f6c Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Fri, 22 Jan 2016 11:34:19 -0800
Subject: [PATCH 0857/1411] Hotfix jest startup time

Summary:
I talked about this a bunch before. node-haste2 will resolve this issue. Right now node-haste1 looks into eevery single node_module recursively even though we only need to look into a finite-set of them. Some node_modules are huge so it takes a long time. haste2 doesn't eagerly look into node_modules so it doesn't have this issue. This diff blacklists the modules from node-haste but since we use the `resolve` npm module as a fallback we'll still be able to require them.

public

Reviewed By: kassens

Differential Revision: D2852384

fb-gh-sync-id: 113f1bd9c66fcd712c2549a7110a3e752b0e4a69
---
 package.json | 1 +
 1 file changed, 1 insertion(+)

diff --git a/package.json b/package.json
index 88fdbc580c0b..bdd4d7d03897 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,7 @@
       "/node_modules/"
     ],
     "modulePathIgnorePatterns": [
+      "/node_modules/(?!react|fbjs|react-native|parse|react-transform-hmr|core-js|promise)/",
       "node_modules/react/lib/React.js",
       "node_modules/react/lib/ReactDOM.js",
 

From a0c5fb99a0160a57e40aae63ef029132fca45ff4 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Fri, 22 Jan 2016 11:38:51 -0800
Subject: [PATCH 0858/1411] Backout "Use numeric identifiers when building a
 bundle"
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Summary:
public

The reverted change doesn’t play nice with inline requires, let’s revert it for now.
I will bring it back after fixing it or adapting inline requires

Reviewed By: martinbigio

Differential Revision: D2854771

fb-gh-sync-id: 32fdbf8ad51240a9075b26502decb6328eed4b29
---
 Libraries/Utilities/Systrace.js               |   7 -
 packager/react-packager/src/Bundler/Bundle.js |   6 +-
 .../src/Bundler/__tests__/Bundler-test.js     |  28 +-
 packager/react-packager/src/Bundler/index.js  |  50 +-
 .../BundlesLayoutIntegration-test.js          |   1 -
 .../src/DependencyResolver/AssetModule.js     |   8 +-
 .../DependencyGraph/ResolutionResponse.js     |   5 -
 .../__tests__/DependencyGraph-test.js         |  18 +-
 .../DependencyResolver/lib/replacePatterns.js |   8 +-
 .../src/Resolver/__tests__/Resolver-test.js   | 442 ++++++++++++++++--
 packager/react-packager/src/Resolver/index.js |  35 +-
 .../src/Resolver/polyfills/require.js         |  27 +-
 12 files changed, 456 insertions(+), 179 deletions(-)

diff --git a/Libraries/Utilities/Systrace.js b/Libraries/Utilities/Systrace.js
index a5d708dc3497..0e11e8942bf6 100644
--- a/Libraries/Utilities/Systrace.js
+++ b/Libraries/Utilities/Systrace.js
@@ -202,11 +202,4 @@ var Systrace = {
 
 Systrace.setEnabled(global.__RCTProfileIsProfiling || false);
 
-if (__DEV__) {
-  // This is needed, because require callis in polyfills are not processed as
-  // other files. Therefore, calls to `require('moduleId')` are not replaced
-  // with numeric IDs
-  // TODO(davidaurelio) Scan polyfills for dependencies, too (t9759686)
-  require.Systrace = Systrace;
-}
 module.exports = Systrace;
diff --git a/packager/react-packager/src/Bundler/Bundle.js b/packager/react-packager/src/Bundler/Bundle.js
index f02127f331b3..2641550a047a 100644
--- a/packager/react-packager/src/Bundler/Bundle.js
+++ b/packager/react-packager/src/Bundler/Bundle.js
@@ -41,10 +41,10 @@ class Bundle extends BundleBase {
       response,
       module,
       transformed.code
-    ).then(({code, id}) => {
+    ).then(({code, name}) => {
       const moduleTransport = new ModuleTransport({
         code,
-        name: id,
+        name,
         map: transformed.map,
         sourceCode: transformed.sourceCode,
         sourcePath: transformed.sourcePath,
@@ -76,7 +76,7 @@ class Bundle extends BundleBase {
   }
 
   _addRequireCall(moduleId) {
-    const code = `;require(${JSON.stringify(moduleId)});`;
+    const code = ';require("' + moduleId + '");';
     const name = 'require-' + moduleId;
     super.addModule(new ModuleTransport({
       name,
diff --git a/packager/react-packager/src/Bundler/__tests__/Bundler-test.js b/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
index a85695be7492..467cf90d69ce 100644
--- a/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
+++ b/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
@@ -10,23 +10,16 @@
 
 jest
   .setMock('worker-farm', () => () => undefined)
-  .dontMock('absolute-path')
   .dontMock('underscore')
   .dontMock('../../lib/ModuleTransport')
-  .dontMock('../../DependencyResolver/AssetModule')
-  .dontMock('../../DependencyResolver/Module')
-  .dontMock('../../DependencyResolver/lib/getAssetDataFromName')
   .setMock('uglify-js')
   .dontMock('../');
 
 jest.mock('fs');
 
-var AssetModule = require('../../DependencyResolver/AssetModule');
 var Bundler = require('../');
 var JSTransformer = require('../../JSTransformer');
-var Module = require('../../DependencyResolver/Module');
 var Resolver = require('../../Resolver');
-
 var sizeOf = require('image-size');
 var fs = require('fs');
 
@@ -41,14 +34,6 @@ describe('Bundler', function() {
     isJSON,
     resolution,
   }) {
-    if (isAsset) {
-      const module = new AssetModule({
-        file: path,
-        cache: {get: () => Promise.resolve(path)}
-      });
-      module.getName = () => Promise.resolve(id);
-      return module;
-    }
     return {
       path,
       resolution,
@@ -66,8 +51,6 @@ describe('Bundler', function() {
   var bundler;
   var assetServer;
   var modules;
-  const width = 50;
-  const height = 100;
 
   beforeEach(function() {
     getDependencies = jest.genMockFn();
@@ -125,12 +108,10 @@ describe('Bundler', function() {
       }),
     ];
 
-    const mainModule = new Module({file: '/root/foo'});
     getDependencies.mockImpl(function() {
       return Promise.resolve({
         mainModuleId: 'foo',
-        dependencies: modules,
-        getMainModule: () => mainModule,
+        dependencies: modules
       });
     });
 
@@ -151,13 +132,12 @@ describe('Bundler', function() {
     wrapModule.mockImpl(function(response, module, code) {
       return module.getName().then(name => ({
         name,
-        id: name,
         code: 'lol ' + code + ' lol'
       }));
     });
 
     sizeOf.mockImpl(function(path, cb) {
-      cb(null, { width, height });
+      cb(null, { width: 50, height: 100 });
     });
   });
 
@@ -207,8 +187,8 @@ describe('Bundler', function() {
           __packager_asset: true,
           fileSystemLocation: '/root/img',
           httpServerLocation: '/assets/img',
-          width,
-          height,
+          width: 25,
+          height: 50,
           scales: [1, 2, 3],
           files: [
             '/root/img/img.png',
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index 9b7bb1fa30d2..1cc28f23d805 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -102,8 +102,6 @@ class Bundler {
       mtime = '';
     }
 
-    this._getModuleId = createModuleIdGetter();
-
     this._cache = new Cache({
       resetCache: opts.resetCache,
       cacheKey: [
@@ -124,7 +122,6 @@ class Bundler {
       fileWatcher: opts.fileWatcher,
       assetExts: opts.assetExts,
       cache: this._cache,
-      getModuleId: this._getModuleId,
     });
 
     this._bundlesLayout = new BundlesLayout({
@@ -190,19 +187,9 @@ class Bundler {
     const findEventId = Activity.startEvent('find dependencies');
     let transformEventId;
 
-    if (isDev) {
-      // `require` calls int  the require polyfill itself are not analyzed and
-      // replaced so that they use numeric module IDs. Therefore, we include
-      // the Systrace module before any other module, and it will set itself
-      // as property on the require function.
-      // TODO(davidaurelio) Scan polyfills for dependencies, too (t9759686)
-      runBeforeMainModule = ['Systrace'].concat(runBeforeMainModule);
-    }
-
-    const modulesByName = Object.create(null);
     return this.getDependencies(entryFile, isDev, platform).then((response) => {
       Activity.endEvent(findEventId);
-      bundle.setMainModuleId(this._getModuleId(response.getMainModule()));
+      bundle.setMainModuleId(response.mainModuleId);
       transformEventId = Activity.startEvent('transform');
 
       const moduleSystemDeps = includeSystemDependencies
@@ -238,11 +225,6 @@ class Bundler {
               platform,
               hot,
             ).then(transformed => {
-              return module.getName().then(name => {
-                modulesByName[name] = module;
-                return transformed;
-              });
-            }).then(transformed => {
               if (bar) {
                 bar.tick();
               }
@@ -266,11 +248,7 @@ class Bundler {
       ));
     }).then(() => {
       Activity.endEvent(transformEventId);
-      const runBeforeIds = runBeforeMainModule
-        .map(name => modulesByName[name])
-        .filter(Boolean)
-        .map(this._getModuleId, this);
-      bundle.finalize({runBeforeMainModule: runBeforeIds, runMainModule});
+      bundle.finalize({runBeforeMainModule, runMainModule});
       return bundle;
     });
   }
@@ -484,7 +462,8 @@ class Bundler {
         type: assetData.type,
       };
 
-      const code = module.getCode(asset);
+      const ASSET_TEMPLATE = 'module.exports = require("AssetRegistry").registerAsset(%json);';
+      const code = ASSET_TEMPLATE.replace('%json', JSON.stringify(asset));
 
       return {asset, code};
     });
@@ -543,21 +522,12 @@ function verifyRootExists(root) {
   assert(fs.statSync(root).isDirectory(), 'Root has to be a valid directory');
 }
 
+class DummyCache {
+  get(filepath, field, loaderCb) {
+    return loaderCb();
+  }
 
-function createModuleIdGetter() {
-  const fileToIdMap = Object.create(null);
-  let nextId = 0;
-  return (
-    ({path}) => {
-      if (!(path in fileToIdMap)) {
-        // can't be a number for now, since we also replace in import / export
-        // we can change that when we eventually change to analyzing dependencies
-        // on transformed modules
-        fileToIdMap[path] = String(nextId++);
-      }
-      return fileToIdMap[path];
-    }
-  );
+  end(){}
+  invalidate(filepath){}
 }
-
 module.exports = Bundler;
diff --git a/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js b/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js
index b18b424f54c2..fe4481a0955e 100644
--- a/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js
+++ b/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js
@@ -55,7 +55,6 @@ describe('BundlesLayout', () => {
         cache: new Cache(),
         assetExts: ['js', 'png'],
         assetRoots: ['/root'],
-        getModuleId: () => {},
       });
 
       return new BundlesLayout({
diff --git a/packager/react-packager/src/DependencyResolver/AssetModule.js b/packager/react-packager/src/DependencyResolver/AssetModule.js
index 68a92ee24692..f5555facd744 100644
--- a/packager/react-packager/src/DependencyResolver/AssetModule.js
+++ b/packager/react-packager/src/DependencyResolver/AssetModule.js
@@ -18,19 +18,13 @@ class AssetModule extends Module {
   }
 
   getDependencies() {
-    return Promise.resolve(['AssetRegistry']);
+    return Promise.resolve([]);
   }
 
   getAsyncDependencies() {
     return Promise.resolve([]);
   }
 
-  getCode(assetData) {
-    return `module.exports = require('AssetRegistry').registerAsset(${
-      JSON.stringify(assetData)
-    });`;
-  }
-
   read() {
     return Promise.resolve({});
   }
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js
index 3c1656c5a0ec..7fbafde84982 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js
@@ -39,11 +39,6 @@ class ResolutionResponse {
     });
   }
 
-  getMainModule() {
-    this._assertFinalized();
-    return this._mainModule;
-  }
-
   pushDependency(module) {
     this._assertNotFinalized();
     if (this.dependencies.length === 0) {
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
index a858f1d2844f..b1126a4cc3e3 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
@@ -374,7 +374,7 @@ describe('DependencyGraph', function() {
             {
               id: 'rootPackage/imgs/a.png',
               path: '/root/imgs/a.png',
-              dependencies: ['AssetRegistry'],
+              dependencies: [],
               isAsset: true,
               resolution: 1,
               isAsset_DEPRECATED: false,
@@ -434,7 +434,7 @@ describe('DependencyGraph', function() {
               id: 'rootPackage/imgs/a.png',
               path: '/root/imgs/a@1.5x.png',
               resolution: 1.5,
-              dependencies: ['AssetRegistry'],
+              dependencies: [],
               isAsset: true,
               isAsset_DEPRECATED: false,
               isJSON: false,
@@ -444,7 +444,7 @@ describe('DependencyGraph', function() {
               id: 'rootPackage/imgs/b.png',
               path: '/root/imgs/b@.7x.png',
               resolution: 0.7,
-              dependencies: ['AssetRegistry'],
+              dependencies: [],
               isAsset: true,
               isAsset_DEPRECATED: false,
               isJSON: false,
@@ -454,7 +454,7 @@ describe('DependencyGraph', function() {
               id: 'rootPackage/imgs/c.png',
               path: '/root/imgs/c.png',
               resolution: 1,
-              dependencies: ['AssetRegistry'],
+              dependencies: [],
               isAsset: true,
               isAsset_DEPRECATED: false,
               isJSON: false,
@@ -514,7 +514,7 @@ describe('DependencyGraph', function() {
               id: 'rootPackage/imgs/a.png',
               path: '/root/imgs/a@1.5x.ios.png',
               resolution: 1.5,
-              dependencies: ['AssetRegistry'],
+              dependencies: [],
               isAsset: true,
               isAsset_DEPRECATED: false,
               isJSON: false,
@@ -524,7 +524,7 @@ describe('DependencyGraph', function() {
               id: 'rootPackage/imgs/b.png',
               path: '/root/imgs/b@.7x.ios.png',
               resolution: 0.7,
-              dependencies: ['AssetRegistry'],
+              dependencies: [],
               isAsset: true,
               isAsset_DEPRECATED: false,
               isJSON: false,
@@ -534,7 +534,7 @@ describe('DependencyGraph', function() {
               id: 'rootPackage/imgs/c.png',
               path: '/root/imgs/c.ios.png',
               resolution: 1,
-              dependencies: ['AssetRegistry'],
+              dependencies: [],
               isAsset: true,
               isAsset_DEPRECATED: false,
               isJSON: false,
@@ -585,7 +585,7 @@ describe('DependencyGraph', function() {
             {
               id: 'rootPackage/imgs/a.png',
               path: '/root/imgs/a.png',
-              dependencies: ['AssetRegistry'],
+              dependencies: [],
               isAsset: true,
               resolution: 1,
               isAsset_DEPRECATED: false,
@@ -3367,7 +3367,7 @@ describe('DependencyGraph', function() {
               {
                 id: 'aPackage/foo.png',
                 path: '/root/foo.png',
-                dependencies: ['AssetRegistry'],
+                dependencies: [],
                 isAsset: true,
                 resolution: 1,
                 isAsset_DEPRECATED: false,
diff --git a/packager/react-packager/src/DependencyResolver/lib/replacePatterns.js b/packager/react-packager/src/DependencyResolver/lib/replacePatterns.js
index 3bd6ef45b01e..a4e563d2c67c 100644
--- a/packager/react-packager/src/DependencyResolver/lib/replacePatterns.js
+++ b/packager/react-packager/src/DependencyResolver/lib/replacePatterns.js
@@ -9,7 +9,7 @@
 
 'use strict';
 
-exports.IMPORT_RE = /(\bimport\s*(?:[\s{][^'"]+[\s}]from\s*)??)(['"])([^'"]+)\2()/g;
-exports.EXPORT_RE = /(\bexport\s*(?:[\s{][^'"]+[\s}]from\s*)??)(['"])([^'"]+)\2()/g;
-exports.REQUIRE_RE = /(\brequire\s*?\(\s*?)(['"])([^'"]+)\2(\s*?\))/g;
-exports.SYSTEM_IMPORT_RE = /(\bSystem\.import\s*?\(\s*?)(['"])([^'"]+)\2(\s*?\))/g;
+exports.IMPORT_RE = /(\bimport\s+(?:[^'"]+\s+from\s+)??)(['"])([^'"]+)(\2)/g;
+exports.EXPORT_RE = /(\bexport\s+(?:[^'"]+\s+from\s+)??)(['"])([^'"]+)(\2)/g;
+exports.REQUIRE_RE = /(\brequire\s*?\(\s*?)(['"])([^'"]+)(\2\s*?\))/g;
+exports.SYSTEM_IMPORT_RE = /(\bSystem\.import\s*?\(\s*?)(['"])([^'"]+)(\2\s*?\))/g;
diff --git a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
index 6093cf423092..825399b4a023 100644
--- a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
+++ b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
@@ -35,12 +35,6 @@ describe('Resolver', function() {
     });
   });
 
-  const modulesWithIds = [];
-  function getModuleId(module) {
-    const index = modulesWithIds.indexOf(module);
-    return String(index !== -1 ? index + 1 : modulesWithIds.push(module));
-  }
-
   class ResolutionResponseMock {
     constructor({dependencies, mainModuleId, asyncDependencies}) {
       this.dependencies = dependencies;
@@ -79,7 +73,6 @@ describe('Resolver', function() {
 
       var depResolver = new Resolver({
         projectRoot: '/root',
-        getModuleId,
       });
 
       DependencyGraph.prototype.getDependencies.mockImpl(function() {
@@ -167,7 +160,6 @@ describe('Resolver', function() {
 
       var depResolver = new Resolver({
         projectRoot: '/root',
-        getModuleId,
       });
 
       DependencyGraph.prototype.getDependencies.mockImpl(function() {
@@ -195,7 +187,6 @@ describe('Resolver', function() {
       var depResolver = new Resolver({
         projectRoot: '/root',
         polyfillModuleNames: ['some module'],
-        getModuleId,
       });
 
       DependencyGraph.prototype.getDependencies.mockImpl(function() {
@@ -232,13 +223,12 @@ describe('Resolver', function() {
     pit('should resolve modules', function() {
       var depResolver = new Resolver({
         projectRoot: '/root',
-        getModuleId,
       });
 
-      const magicJoiner = '\n\n\n';
+      var dependencies = ['x', 'y', 'z', 'a', 'b'];
 
       /*eslint-disable */
-      const testCases = [
+      var code = [
         // single line import
         "import'x';",
         "import 'x';",
@@ -313,7 +303,6 @@ describe('Resolver', function() {
         'import * as All from "x";',
         'import { } from "x";',
         'import { Foo } from "x";',
-        'import{Foo}from"x";',
         'import { Foo, } from "x";',
         'import { Foo as Bar } from "x";',
         'import { Foo as Bar, } from "x";',
@@ -439,7 +428,6 @@ describe('Resolver', function() {
         "export { } from 'x';",
         "export {Foo} from 'x';",
         "export { Foo } from 'x';",
-        "export{Foo}from'x';",
         "export { Foo, } from 'x';",
         "export {Foo as Bar} from 'x';",
         "export { Foo as Bar } from 'x';",
@@ -625,9 +613,8 @@ describe('Resolver', function() {
         'require( \'z\' )',
         'require( "a")',
         'require("b" )',
-      ]
+      ].join('\n');
       /*eslint-disable */
-      const code = testCases.join(magicJoiner);
 
       const module = createModule('test module', ['x', 'y']);
 
@@ -637,21 +624,11 @@ describe('Resolver', function() {
         asyncDependencies: [],
       });
 
-      const pairs = [
-        ['x', createModule('changed')],
-        ['y', createModule('Y')],
-      ];
-      resolutionResponse.getResolvedDependencyPairs = () => pairs;
-
-      function makeExpected(code) {
-        return pairs
-          .reduce((code, [id, module]) =>
-            code.replace(
-              RegExp(`(['"])${id}\\1`),
-              (_, quot) => `${quot}${getModuleId(module)}${quot} /* ${id} */`
-            ),
-            code
-          );
+      resolutionResponse.getResolvedDependencyPairs = (module) => {
+        return [
+          ['x', createModule('changed')],
+          ['y', createModule('Y')],
+        ];
       }
 
       return depResolver.wrapModule(
@@ -660,20 +637,395 @@ describe('Resolver', function() {
         code
       ).then(processedCode => {
         expect(processedCode.name).toEqual('test module');
-
-        // extract the converted code from the module wrapper
-        const cases =
-          processedCode.code
-            .match(/__d\(.*?\{\s*([\s\S]*)\}/)[1] // match code in wrapper
-            .replace(/\s+$/, '') // remove trailing whitespace
-            .split(magicJoiner); // extract every tested case
-
-        testCases.forEach((inputCode, i) => {
-          expect(cases[i]).toEqual(makeExpected(inputCode));
-          if(cases[i]!==makeExpected(inputCode)) {
-            console.log('FAIL %s: input(%s) expected(%s) actual(%s)', i, inputCode, makeExpected(inputCode), cases[i]);
-          }
-        });
+        expect(processedCode.code).toEqual([
+          '__d(\'test module\',function(global, require,' +
+            ' module, exports) {  ' +
+            // single line import
+            "import'x';",
+          "import 'changed';",
+          "import 'changed' ;",
+          "import Default from 'changed';",
+          "import * as All from 'changed';",
+          "import {} from 'changed';",
+          "import { } from 'changed';",
+          "import {Foo} from 'changed';",
+          "import { Foo } from 'changed';",
+          "import { Foo, } from 'changed';",
+          "import {Foo as Bar} from 'changed';",
+          "import { Foo as Bar } from 'changed';",
+          "import { Foo as Bar, } from 'changed';",
+          "import { Foo, Bar } from 'changed';",
+          "import { Foo, Bar, } from 'changed';",
+          "import { Foo as Bar, Baz } from 'changed';",
+          "import { Foo as Bar, Baz, } from 'changed';",
+          "import { Foo, Bar as Baz } from 'changed';",
+          "import { Foo, Bar as Baz, } from 'changed';",
+          "import { Foo as Bar, Baz as Qux } from 'changed';",
+          "import { Foo as Bar, Baz as Qux, } from 'changed';",
+          "import { Foo, Bar, Baz } from 'changed';",
+          "import { Foo, Bar, Baz, } from 'changed';",
+          "import { Foo as Bar, Baz, Qux } from 'changed';",
+          "import { Foo as Bar, Baz, Qux, } from 'changed';",
+          "import { Foo, Bar as Baz, Qux } from 'changed';",
+          "import { Foo, Bar as Baz, Qux, } from 'changed';",
+          "import { Foo, Bar, Baz as Qux } from 'changed';",
+          "import { Foo, Bar, Baz as Qux, } from 'changed';",
+          "import { Foo as Bar, Baz as Qux, Norf } from 'changed';",
+          "import { Foo as Bar, Baz as Qux, Norf, } from 'changed';",
+          "import { Foo as Bar, Baz, Qux as Norf } from 'changed';",
+          "import { Foo as Bar, Baz, Qux as Norf, } from 'changed';",
+          "import { Foo, Bar as Baz, Qux as Norf } from 'changed';",
+          "import { Foo, Bar as Baz, Qux as Norf, } from 'changed';",
+          "import { Foo as Bar, Baz as Qux, Norf as Enuf } from 'changed';",
+          "import { Foo as Bar, Baz as Qux, Norf as Enuf, } from 'changed';",
+          "import Default, * as All from 'changed';",
+          "import Default, { } from 'changed';",
+          "import Default, { Foo } from 'changed';",
+          "import Default, { Foo, } from 'changed';",
+          "import Default, { Foo as Bar } from 'changed';",
+          "import Default, { Foo as Bar, } from 'changed';",
+          "import Default, { Foo, Bar } from 'changed';",
+          "import Default, { Foo, Bar, } from 'changed';",
+          "import Default, { Foo as Bar, Baz } from 'changed';",
+          "import Default, { Foo as Bar, Baz, } from 'changed';",
+          "import Default, { Foo, Bar as Baz } from 'changed';",
+          "import Default, { Foo, Bar as Baz, } from 'changed';",
+          "import Default, { Foo as Bar, Baz as Qux } from 'changed';",
+          "import Default, { Foo as Bar, Baz as Qux, } from 'changed';",
+          "import Default, { Foo, Bar, Baz } from 'changed';",
+          "import Default, { Foo, Bar, Baz, } from 'changed';",
+          "import Default, { Foo as Bar, Baz, Qux } from 'changed';",
+          "import Default, { Foo as Bar, Baz, Qux, } from 'changed';",
+          "import Default, { Foo, Bar as Baz, Qux } from 'changed';",
+          "import Default, { Foo, Bar as Baz, Qux, } from 'changed';",
+          "import Default, { Foo, Bar, Baz as Qux } from 'changed';",
+          "import Default, { Foo, Bar, Baz as Qux, } from 'changed';",
+          "import Default, { Foo as Bar, Baz as Qux, Norf } from 'changed';",
+          "import Default, { Foo as Bar, Baz as Qux, Norf, } from 'changed';",
+          "import Default, { Foo as Bar, Baz, Qux as Norf } from 'changed';",
+          "import Default, { Foo as Bar, Baz, Qux as Norf, } from 'changed';",
+          "import Default, { Foo, Bar as Baz, Qux as Norf } from 'changed';",
+          "import Default, { Foo, Bar as Baz, Qux as Norf, } from 'changed';",
+          "import Default, { Foo as Bar, Baz as Qux, Norf as NoMore } from 'changed';",
+          "import Default, { Foo as Bar, Baz as Qux, Norf as NoMore, } from 'changed';",
+          "import Default , { } from 'changed';",
+          'import "changed";',
+          'import Default from "changed";',
+          'import * as All from "changed";',
+          'import { } from "changed";',
+          'import { Foo } from "changed";',
+          'import { Foo, } from "changed";',
+          'import { Foo as Bar } from "changed";',
+          'import { Foo as Bar, } from "changed";',
+          'import { Foo, Bar } from "changed";',
+          'import { Foo, Bar, } from "changed";',
+          'import { Foo as Bar, Baz } from "changed";',
+          'import { Foo as Bar, Baz, } from "changed";',
+          'import { Foo, Bar as Baz } from "changed";',
+          'import { Foo, Bar as Baz, } from "changed";',
+          'import { Foo as Bar, Baz as Qux } from "changed";',
+          'import { Foo as Bar, Baz as Qux, } from "changed";',
+          'import { Foo, Bar, Baz } from "changed";',
+          'import { Foo, Bar, Baz, } from "changed";',
+          'import { Foo as Bar, Baz, Qux } from "changed";',
+          'import { Foo as Bar, Baz, Qux, } from "changed";',
+          'import { Foo, Bar as Baz, Qux } from "changed";',
+          'import { Foo, Bar as Baz, Qux, } from "changed";',
+          'import { Foo, Bar, Baz as Qux } from "changed";',
+          'import { Foo, Bar, Baz as Qux, } from "changed";',
+          'import { Foo as Bar, Baz as Qux, Norf } from "changed";',
+          'import { Foo as Bar, Baz as Qux, Norf, } from "changed";',
+          'import { Foo as Bar, Baz, Qux as Norf } from "changed";',
+          'import { Foo as Bar, Baz, Qux as Norf, } from "changed";',
+          'import { Foo, Bar as Baz, Qux as Norf } from "changed";',
+          'import { Foo, Bar as Baz, Qux as Norf, } from "changed";',
+          'import { Foo as Bar, Baz as Qux, Norf as NoMore } from "changed";',
+          'import { Foo as Bar, Baz as Qux, Norf as NoMore, } from "changed";',
+          'import Default, * as All from "changed";',
+          'import Default, { } from "changed";',
+          'import Default, { Foo } from "changed";',
+          'import Default, { Foo, } from "changed";',
+          'import Default, { Foo as Bar } from "changed";',
+          'import Default, { Foo as Bar, } from "changed";',
+          'import Default, { Foo, Bar } from "changed";',
+          'import Default, { Foo, Bar, } from "changed";',
+          'import Default, { Foo as Bar, Baz } from "changed";',
+          'import Default, { Foo as Bar, Baz, } from "changed";',
+          'import Default, { Foo, Bar as Baz } from "changed";',
+          'import Default, { Foo, Bar as Baz, } from "changed";',
+          'import Default, { Foo as Bar, Baz as Qux } from "changed";',
+          'import Default, { Foo as Bar, Baz as Qux, } from "changed";',
+          'import Default, { Foo, Bar, Baz } from "changed";',
+          'import Default, { Foo, Bar, Baz, } from "changed";',
+          'import Default, { Foo as Bar, Baz, Qux } from "changed";',
+          'import Default, { Foo as Bar, Baz, Qux, } from "changed";',
+          'import Default, { Foo, Bar as Baz, Qux } from "changed";',
+          'import Default, { Foo, Bar as Baz, Qux, } from "changed";',
+          'import Default, { Foo, Bar, Baz as Qux } from "changed";',
+          'import Default, { Foo, Bar, Baz as Qux, } from "changed";',
+          'import Default, { Foo as Bar, Baz as Qux, Norf } from "changed";',
+          'import Default, { Foo as Bar, Baz as Qux, Norf, } from "changed";',
+          'import Default, { Foo as Bar, Baz, Qux as Norf } from "changed";',
+          'import Default, { Foo as Bar, Baz, Qux as Norf, } from "changed";',
+          'import Default, { Foo, Bar as Baz, Qux as Norf } from "changed";',
+          'import Default, { Foo, Bar as Baz, Qux as Norf, } from "changed";',
+          'import Default, { Foo as Bar, Baz as Qux, Norf as Enuf } from "changed";',
+          'import Default, { Foo as Bar, Baz as Qux, Norf as Enuf, } from "changed";',
+          'import Default from "Y";',
+          'import * as All from \'z\';',
+          // import with support for new lines
+          "import { Foo,\n Bar }\n from 'changed';",
+          "import { \nFoo,\nBar,\n }\n from 'changed';",
+          "import { Foo as Bar,\n Baz\n }\n from 'changed';",
+          "import { \nFoo as Bar,\n Baz\n, }\n from 'changed';",
+          "import { Foo,\n Bar as Baz\n }\n from 'changed';",
+          "import { Foo,\n Bar as Baz,\n }\n from 'changed';",
+          "import { Foo as Bar,\n Baz as Qux\n }\n from 'changed';",
+          "import { Foo as Bar,\n Baz as Qux,\n }\n from 'changed';",
+          "import { Foo,\n Bar,\n Baz }\n from 'changed';",
+          "import { Foo,\n Bar,\n Baz,\n }\n from 'changed';",
+          "import { Foo as Bar,\n Baz,\n Qux\n }\n from 'changed';",
+          "import { Foo as Bar,\n Baz,\n Qux,\n }\n from 'changed';",
+          "import { Foo,\n Bar as Baz,\n Qux\n }\n from 'changed';",
+          "import { Foo,\n Bar as Baz,\n Qux,\n }\n from 'changed';",
+          "import { Foo,\n Bar,\n Baz as Qux\n }\n from 'changed';",
+          "import { Foo,\n Bar,\n Baz as Qux,\n }\n from 'changed';",
+          "import { Foo as Bar,\n Baz as Qux,\n Norf\n }\n from 'changed';",
+          "import { Foo as Bar,\n Baz as Qux,\n Norf,\n }\n from 'changed';",
+          "import { Foo as Bar,\n Baz,\n Qux as Norf\n }\n from 'changed';",
+          "import { Foo as Bar,\n Baz,\n Qux as Norf,\n }\n from 'changed';",
+          "import { Foo,\n Bar as Baz,\n Qux as Norf\n }\n from 'changed';",
+          "import { Foo,\n Bar as Baz,\n Qux as Norf,\n }\n from 'changed';",
+          "import { Foo as Bar,\n Baz as Qux,\n Norf as Enuf\n }\n from 'changed';",
+          "import { Foo as Bar,\n Baz as Qux,\n Norf as Enuf,\n }\n from 'changed';",
+          "import Default,\n * as All from 'changed';",
+          "import Default,\n { } from 'changed';",
+          "import Default,\n { Foo\n }\n from 'changed';",
+          "import Default,\n { Foo,\n }\n from 'changed';",
+          "import Default,\n { Foo as Bar\n }\n from 'changed';",
+          "import Default,\n { Foo as Bar,\n }\n from 'changed';",
+          "import Default,\n { Foo,\n Bar\n } from\n 'changed';",
+          "import Default,\n { Foo,\n Bar,\n } from\n 'changed';",
+          "import Default,\n { Foo as Bar,\n Baz\n }\n from 'changed';",
+          "import Default,\n { Foo as Bar,\n Baz,\n }\n from 'changed';",
+          "import Default,\n { Foo,\n Bar as Baz\n }\n from 'changed';",
+          "import Default,\n { Foo,\n Bar as Baz,\n }\n from 'changed';",
+          "import Default,\n { Foo as Bar,\n Baz as Qux\n }\n from 'changed';",
+          "import Default,\n { Foo as Bar,\n Baz as Qux,\n }\n from 'changed';",
+          "import Default,\n { Foo,\n Bar,\n Baz\n }\n from 'changed';",
+          "import Default,\n { Foo,\n Bar,\n Baz,\n }\n from 'changed';",
+          "import Default,\n { Foo as Bar,\n Baz,\n Qux\n }\n from 'changed';",
+          "import Default,\n { Foo as Bar,\n Baz,\n Qux,\n }\n from 'changed';",
+          "import Default,\n { Foo,\n Bar as Baz,\n Qux\n }\n from 'changed';",
+          "import Default,\n { Foo,\n Bar as Baz,\n Qux,\n }\n from 'changed';",
+          "import Default,\n { Foo,\n Bar,\n Baz as Qux\n }\n from 'changed';",
+          "import Default,\n { Foo,\n Bar,\n Baz as Qux,\n }\n from 'changed';",
+          "import Default,\n { Foo as Bar,\n Baz as Qux,\n Norf\n }\n from 'changed';",
+          "import Default,\n { Foo as Bar,\n Baz as Qux,\n Norf,\n }\n from 'changed';",
+          "import Default,\n { Foo as Bar,\n Baz,\n Qux as Norf }\n from 'changed';",
+          "import Default,\n { Foo as Bar,\n Baz,\n Qux as Norf, }\n from 'changed';",
+          "import Default,\n { Foo, Bar as Baz,\n Qux as Norf }\n from 'changed';",
+          "import Default,\n { Foo, Bar as Baz,\n Qux as Norf, }\n from 'changed';",
+          "import Default,\n { Foo as Bar,\n Baz as Qux,\n Norf as NoMore\n }\n from 'changed';",
+          "import Default,\n { Foo as Bar,\n Baz as Qux,\n Norf as NoMore,\n }\n from 'changed';",
+          "import Default\n , { } from 'changed';",
+          // single line export
+          "export'x';",
+          "export 'changed';",
+          "export 'changed' ;",
+          "export Default from 'changed';",
+          "export * as All from 'changed';",
+          "export {} from 'changed';",
+          "export { } from 'changed';",
+          "export {Foo} from 'changed';",
+          "export { Foo } from 'changed';",
+          "export { Foo, } from 'changed';",
+          "export {Foo as Bar} from 'changed';",
+          "export { Foo as Bar } from 'changed';",
+          "export { Foo as Bar, } from 'changed';",
+          "export { Foo, Bar } from 'changed';",
+          "export { Foo, Bar, } from 'changed';",
+          "export { Foo as Bar, Baz } from 'changed';",
+          "export { Foo as Bar, Baz, } from 'changed';",
+          "export { Foo, Bar as Baz } from 'changed';",
+          "export { Foo, Bar as Baz, } from 'changed';",
+          "export { Foo as Bar, Baz as Qux } from 'changed';",
+          "export { Foo as Bar, Baz as Qux, } from 'changed';",
+          "export { Foo, Bar, Baz } from 'changed';",
+          "export { Foo, Bar, Baz, } from 'changed';",
+          "export { Foo as Bar, Baz, Qux } from 'changed';",
+          "export { Foo as Bar, Baz, Qux, } from 'changed';",
+          "export { Foo, Bar as Baz, Qux } from 'changed';",
+          "export { Foo, Bar as Baz, Qux, } from 'changed';",
+          "export { Foo, Bar, Baz as Qux } from 'changed';",
+          "export { Foo, Bar, Baz as Qux, } from 'changed';",
+          "export { Foo as Bar, Baz as Qux, Norf } from 'changed';",
+          "export { Foo as Bar, Baz as Qux, Norf, } from 'changed';",
+          "export { Foo as Bar, Baz, Qux as Norf } from 'changed';",
+          "export { Foo as Bar, Baz, Qux as Norf, } from 'changed';",
+          "export { Foo, Bar as Baz, Qux as Norf } from 'changed';",
+          "export { Foo, Bar as Baz, Qux as Norf, } from 'changed';",
+          "export { Foo as Bar, Baz as Qux, Norf as Enuf } from 'changed';",
+          "export { Foo as Bar, Baz as Qux, Norf as Enuf, } from 'changed';",
+          "export Default, * as All from 'changed';",
+          "export Default, { } from 'changed';",
+          "export Default, { Foo } from 'changed';",
+          "export Default, { Foo, } from 'changed';",
+          "export Default, { Foo as Bar } from 'changed';",
+          "export Default, { Foo as Bar, } from 'changed';",
+          "export Default, { Foo, Bar } from 'changed';",
+          "export Default, { Foo, Bar, } from 'changed';",
+          "export Default, { Foo as Bar, Baz } from 'changed';",
+          "export Default, { Foo as Bar, Baz, } from 'changed';",
+          "export Default, { Foo, Bar as Baz } from 'changed';",
+          "export Default, { Foo, Bar as Baz, } from 'changed';",
+          "export Default, { Foo as Bar, Baz as Qux } from 'changed';",
+          "export Default, { Foo as Bar, Baz as Qux, } from 'changed';",
+          "export Default, { Foo, Bar, Baz } from 'changed';",
+          "export Default, { Foo, Bar, Baz, } from 'changed';",
+          "export Default, { Foo as Bar, Baz, Qux } from 'changed';",
+          "export Default, { Foo as Bar, Baz, Qux, } from 'changed';",
+          "export Default, { Foo, Bar as Baz, Qux } from 'changed';",
+          "export Default, { Foo, Bar as Baz, Qux, } from 'changed';",
+          "export Default, { Foo, Bar, Baz as Qux } from 'changed';",
+          "export Default, { Foo, Bar, Baz as Qux, } from 'changed';",
+          "export Default, { Foo as Bar, Baz as Qux, Norf } from 'changed';",
+          "export Default, { Foo as Bar, Baz as Qux, Norf, } from 'changed';",
+          "export Default, { Foo as Bar, Baz, Qux as Norf } from 'changed';",
+          "export Default, { Foo as Bar, Baz, Qux as Norf, } from 'changed';",
+          "export Default, { Foo, Bar as Baz, Qux as Norf } from 'changed';",
+          "export Default, { Foo, Bar as Baz, Qux as Norf, } from 'changed';",
+          "export Default, { Foo as Bar, Baz as Qux, Norf as NoMore } from 'changed';",
+          "export Default, { Foo as Bar, Baz as Qux, Norf as NoMore, } from 'changed';",
+          "export Default , { } from 'changed';",
+          'export "changed";',
+          'export Default from "changed";',
+          'export * as All from "changed";',
+          'export { } from "changed";',
+          'export { Foo } from "changed";',
+          'export { Foo, } from "changed";',
+          'export { Foo as Bar } from "changed";',
+          'export { Foo as Bar, } from "changed";',
+          'export { Foo, Bar } from "changed";',
+          'export { Foo, Bar, } from "changed";',
+          'export { Foo as Bar, Baz } from "changed";',
+          'export { Foo as Bar, Baz, } from "changed";',
+          'export { Foo, Bar as Baz } from "changed";',
+          'export { Foo, Bar as Baz, } from "changed";',
+          'export { Foo as Bar, Baz as Qux } from "changed";',
+          'export { Foo as Bar, Baz as Qux, } from "changed";',
+          'export { Foo, Bar, Baz } from "changed";',
+          'export { Foo, Bar, Baz, } from "changed";',
+          'export { Foo as Bar, Baz, Qux } from "changed";',
+          'export { Foo as Bar, Baz, Qux, } from "changed";',
+          'export { Foo, Bar as Baz, Qux } from "changed";',
+          'export { Foo, Bar as Baz, Qux, } from "changed";',
+          'export { Foo, Bar, Baz as Qux } from "changed";',
+          'export { Foo, Bar, Baz as Qux, } from "changed";',
+          'export { Foo as Bar, Baz as Qux, Norf } from "changed";',
+          'export { Foo as Bar, Baz as Qux, Norf, } from "changed";',
+          'export { Foo as Bar, Baz, Qux as Norf } from "changed";',
+          'export { Foo as Bar, Baz, Qux as Norf, } from "changed";',
+          'export { Foo, Bar as Baz, Qux as Norf } from "changed";',
+          'export { Foo, Bar as Baz, Qux as Norf, } from "changed";',
+          'export { Foo as Bar, Baz as Qux, Norf as NoMore } from "changed";',
+          'export { Foo as Bar, Baz as Qux, Norf as NoMore, } from "changed";',
+          'export Default, * as All from "changed";',
+          'export Default, { } from "changed";',
+          'export Default, { Foo } from "changed";',
+          'export Default, { Foo, } from "changed";',
+          'export Default, { Foo as Bar } from "changed";',
+          'export Default, { Foo as Bar, } from "changed";',
+          'export Default, { Foo, Bar } from "changed";',
+          'export Default, { Foo, Bar, } from "changed";',
+          'export Default, { Foo as Bar, Baz } from "changed";',
+          'export Default, { Foo as Bar, Baz, } from "changed";',
+          'export Default, { Foo, Bar as Baz } from "changed";',
+          'export Default, { Foo, Bar as Baz, } from "changed";',
+          'export Default, { Foo as Bar, Baz as Qux } from "changed";',
+          'export Default, { Foo as Bar, Baz as Qux, } from "changed";',
+          'export Default, { Foo, Bar, Baz } from "changed";',
+          'export Default, { Foo, Bar, Baz, } from "changed";',
+          'export Default, { Foo as Bar, Baz, Qux } from "changed";',
+          'export Default, { Foo as Bar, Baz, Qux, } from "changed";',
+          'export Default, { Foo, Bar as Baz, Qux } from "changed";',
+          'export Default, { Foo, Bar as Baz, Qux, } from "changed";',
+          'export Default, { Foo, Bar, Baz as Qux } from "changed";',
+          'export Default, { Foo, Bar, Baz as Qux, } from "changed";',
+          'export Default, { Foo as Bar, Baz as Qux, Norf } from "changed";',
+          'export Default, { Foo as Bar, Baz as Qux, Norf, } from "changed";',
+          'export Default, { Foo as Bar, Baz, Qux as Norf } from "changed";',
+          'export Default, { Foo as Bar, Baz, Qux as Norf, } from "changed";',
+          'export Default, { Foo, Bar as Baz, Qux as Norf } from "changed";',
+          'export Default, { Foo, Bar as Baz, Qux as Norf, } from "changed";',
+          'export Default, { Foo as Bar, Baz as Qux, Norf as Enuf } from "changed";',
+          'export Default, { Foo as Bar, Baz as Qux, Norf as Enuf, } from "changed";',
+          'export Default from "Y";',
+          'export * as All from \'z\';',
+          // export with support for new lines
+          "export { Foo,\n Bar }\n from 'changed';",
+          "export { \nFoo,\nBar,\n }\n from 'changed';",
+          "export { Foo as Bar,\n Baz\n }\n from 'changed';",
+          "export { \nFoo as Bar,\n Baz\n, }\n from 'changed';",
+          "export { Foo,\n Bar as Baz\n }\n from 'changed';",
+          "export { Foo,\n Bar as Baz,\n }\n from 'changed';",
+          "export { Foo as Bar,\n Baz as Qux\n }\n from 'changed';",
+          "export { Foo as Bar,\n Baz as Qux,\n }\n from 'changed';",
+          "export { Foo,\n Bar,\n Baz }\n from 'changed';",
+          "export { Foo,\n Bar,\n Baz,\n }\n from 'changed';",
+          "export { Foo as Bar,\n Baz,\n Qux\n }\n from 'changed';",
+          "export { Foo as Bar,\n Baz,\n Qux,\n }\n from 'changed';",
+          "export { Foo,\n Bar as Baz,\n Qux\n }\n from 'changed';",
+          "export { Foo,\n Bar as Baz,\n Qux,\n }\n from 'changed';",
+          "export { Foo,\n Bar,\n Baz as Qux\n }\n from 'changed';",
+          "export { Foo,\n Bar,\n Baz as Qux,\n }\n from 'changed';",
+          "export { Foo as Bar,\n Baz as Qux,\n Norf\n }\n from 'changed';",
+          "export { Foo as Bar,\n Baz as Qux,\n Norf,\n }\n from 'changed';",
+          "export { Foo as Bar,\n Baz,\n Qux as Norf\n }\n from 'changed';",
+          "export { Foo as Bar,\n Baz,\n Qux as Norf,\n }\n from 'changed';",
+          "export { Foo,\n Bar as Baz,\n Qux as Norf\n }\n from 'changed';",
+          "export { Foo,\n Bar as Baz,\n Qux as Norf,\n }\n from 'changed';",
+          "export { Foo as Bar,\n Baz as Qux,\n Norf as Enuf\n }\n from 'changed';",
+          "export { Foo as Bar,\n Baz as Qux,\n Norf as Enuf,\n }\n from 'changed';",
+          "export Default,\n * as All from 'changed';",
+          "export Default,\n { } from 'changed';",
+          "export Default,\n { Foo\n }\n from 'changed';",
+          "export Default,\n { Foo,\n }\n from 'changed';",
+          "export Default,\n { Foo as Bar\n }\n from 'changed';",
+          "export Default,\n { Foo as Bar,\n }\n from 'changed';",
+          "export Default,\n { Foo,\n Bar\n } from\n 'changed';",
+          "export Default,\n { Foo,\n Bar,\n } from\n 'changed';",
+          "export Default,\n { Foo as Bar,\n Baz\n }\n from 'changed';",
+          "export Default,\n { Foo as Bar,\n Baz,\n }\n from 'changed';",
+          "export Default,\n { Foo,\n Bar as Baz\n }\n from 'changed';",
+          "export Default,\n { Foo,\n Bar as Baz,\n }\n from 'changed';",
+          "export Default,\n { Foo as Bar,\n Baz as Qux\n }\n from 'changed';",
+          "export Default,\n { Foo as Bar,\n Baz as Qux,\n }\n from 'changed';",
+          "export Default,\n { Foo,\n Bar,\n Baz\n }\n from 'changed';",
+          "export Default,\n { Foo,\n Bar,\n Baz,\n }\n from 'changed';",
+          "export Default,\n { Foo as Bar,\n Baz,\n Qux\n }\n from 'changed';",
+          "export Default,\n { Foo as Bar,\n Baz,\n Qux,\n }\n from 'changed';",
+          "export Default,\n { Foo,\n Bar as Baz,\n Qux\n }\n from 'changed';",
+          "export Default,\n { Foo,\n Bar as Baz,\n Qux,\n }\n from 'changed';",
+          "export Default,\n { Foo,\n Bar,\n Baz as Qux\n }\n from 'changed';",
+          "export Default,\n { Foo,\n Bar,\n Baz as Qux,\n }\n from 'changed';",
+          "export Default,\n { Foo as Bar,\n Baz as Qux,\n Norf\n }\n from 'changed';",
+          "export Default,\n { Foo as Bar,\n Baz as Qux,\n Norf,\n }\n from 'changed';",
+          "export Default,\n { Foo as Bar,\n Baz,\n Qux as Norf }\n from 'changed';",
+          "export Default,\n { Foo as Bar,\n Baz,\n Qux as Norf, }\n from 'changed';",
+          "export Default,\n { Foo, Bar as Baz,\n Qux as Norf }\n from 'changed';",
+          "export Default,\n { Foo, Bar as Baz,\n Qux as Norf, }\n from 'changed';",
+          "export Default,\n { Foo as Bar,\n Baz as Qux,\n Norf as NoMore\n }\n from 'changed';",
+          "export Default,\n { Foo as Bar,\n Baz as Qux,\n Norf as NoMore,\n }\n from 'changed';",
+          "export Default\n , { } from 'changed';",
+          // require
+          'require("changed")',
+          'require("Y")',
+          'require( \'z\' )',
+          'require( "a")',
+          'require("b" )',
+          '});',
+        ].join('\n'));
       });
     });
 
diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index c657aae5905c..0166681f0b3e 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -49,10 +49,6 @@ const validateOpts = declareOpts({
     type: 'object',
     required: true,
   },
-  getModuleId: {
-    type: 'function',
-    required: true,
-  }
 });
 
 const getDependenciesValidateOpts = declareOpts({
@@ -102,7 +98,6 @@ class Resolver {
       shouldThrowOnUnresolvedErrors: (_, platform) => platform === 'ios',
     });
 
-    this._getModuleId = options.getModuleId;
     this._polyfillModuleNames = opts.polyfillModuleNames || [];
   }
 
@@ -182,32 +177,36 @@ class Resolver {
       }
 
       const resolvedDeps = Object.create(null);
+      const resolvedDepsArr = [];
 
       return Promise.all(
         resolutionResponse.getResolvedDependencyPairs(module).map(
           ([depName, depModule]) => {
             if (depModule) {
-              resolvedDeps[depName] = this._getModuleId(depModule);
+              return depModule.getName().then(name => {
+                resolvedDeps[depName] = name;
+                resolvedDepsArr.push(name);
+              });
             }
           }
         )
       ).then(() => {
-        const replaceModuleId = (codeMatch, pre, quot, depName, post = '') => {
-          if (depName in resolvedDeps) {
-            const replacement = `${quot}${resolvedDeps[depName]}${quot}`;
-            return `${pre}${replacement} /* ${depName} */${post}`;
+        const relativizeCode = (codeMatch, pre, quot, depName, post) => {
+          const depId = resolvedDeps[depName];
+          if (depId) {
+            return pre + quot + depId + post;
           } else {
             return codeMatch;
           }
         };
 
         code = code
-          .replace(replacePatterns.IMPORT_RE, replaceModuleId)
-          .replace(replacePatterns.EXPORT_RE, replaceModuleId)
-          .replace(replacePatterns.REQUIRE_RE, replaceModuleId);
+          .replace(replacePatterns.IMPORT_RE, relativizeCode)
+          .replace(replacePatterns.EXPORT_RE, relativizeCode)
+          .replace(replacePatterns.REQUIRE_RE, relativizeCode);
 
         return module.getName().then(name => {
-          return {name, code, id: this._getModuleId(module)};
+          return {name, code};
         });
       });
     });
@@ -221,8 +220,8 @@ class Resolver {
     }
 
     return this.resolveRequires(resolutionResponse, module, code).then(
-      ({name, code, id}) => {
-        return {id, name, code: defineModuleCode(id, code, name)};
+      ({name, code}) => {
+        return {name, code: defineModuleCode(name, code)};
       });
   }
 
@@ -232,10 +231,10 @@ class Resolver {
 
 }
 
-function defineModuleCode(moduleId, code, verboseName = '') {
+function defineModuleCode(moduleName, code) {
   return [
     `__d(`,
-    `${JSON.stringify(moduleId)} /* ${verboseName} */ ,`,
+    `'${moduleName}',`,
     'function(global, require, module, exports) {',
     `  ${code}`,
     '\n});',
diff --git a/packager/react-packager/src/Resolver/polyfills/require.js b/packager/react-packager/src/Resolver/polyfills/require.js
index bc14a6e8421b..a5a7a55f01a5 100644
--- a/packager/react-packager/src/Resolver/polyfills/require.js
+++ b/packager/react-packager/src/Resolver/polyfills/require.js
@@ -59,29 +59,18 @@ function requireImpl(id) {
     );
   }
 
-
-  // `require` calls int  the require polyfill itself are not analyzed and
-  // replaced so that they use numeric module IDs.
-  // The systrace module will expose itself on the require function so that
-  // it can be used here.
-  // TODO(davidaurelio) Scan polyfills for dependencies, too (t9759686)
-  const {Systrace} = require;
   try {
     // We must optimistically mark mod as initialized before running the factory to keep any
     // require cycles inside the factory from causing an infinite require loop.
     mod.isInitialized = true;
 
-    if (__DEV__) {
-      Systrace.beginEvent('JS_require_' + id);
-    }
+    __DEV__ && Systrace().beginEvent('JS_require_' + id);
 
     // keep args in sync with with defineModuleCode in
     // packager/react-packager/src/Resolver/index.js
     mod.factory.call(global, global, require, mod.module, mod.module.exports);
 
-    if (__DEV__) {
-      Systrace.endEvent();
-    }
+    __DEV__ && Systrace().endEvent();
   } catch (e) {
     mod.hasError = true;
     mod.isInitialized = false;
@@ -91,9 +80,15 @@ function requireImpl(id) {
   return mod.module.exports;
 }
 
-if (__DEV__) {
-  require.Systrace = { beginEvent: () => {}, endEvent: () => {} };
-}
+const Systrace = __DEV__ && (() => {
+  var _Systrace;
+  try {
+    _Systrace = require('Systrace');
+  } catch (e) {}
+
+  return _Systrace && _Systrace.beginEvent ?
+    _Systrace : { beginEvent: () => {}, endEvent: () => {} };
+});
 
 global.__d = define;
 global.require = require;

From a23785ca2ef44a0b54e3514ff3a5c9fdcce3876c Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Fri, 22 Jan 2016 13:54:24 -0800
Subject: [PATCH 0859/1411] Pass on the bundle name rather than the ID when
 getting transform options

Summary:
public

This is needed to bring numerical module IDs back.

The numerical ID of the main module will always be `0` and is therefore of no use when used as conditional. We have to pass on the name, which will be preserved, when requesting transform options.

Reviewed By: martinbigio

Differential Revision: D2855106

fb-gh-sync-id: f9bc40e753b1b283ce0b00068e3c9964a541ad9b
---
 packager/react-packager/src/Bundler/index.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index 1cc28f23d805..fda21ace02fa 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -190,6 +190,7 @@ class Bundler {
     return this.getDependencies(entryFile, isDev, platform).then((response) => {
       Activity.endEvent(findEventId);
       bundle.setMainModuleId(response.mainModuleId);
+      bundle.setMainModuleName(response.mainModuleId);
       transformEventId = Activity.startEvent('transform');
 
       const moduleSystemDeps = includeSystemDependencies
@@ -396,7 +397,7 @@ class Bundler {
       return this._transformer.loadFileAndTransform(
         path.resolve(module.path),
         this._getTransformOptions(
-          {bundleEntry: bundle.getMainModuleId(), modulePath: module.path},
+          {bundleEntry: bundle.getMainModuleName(), modulePath: module.path},
           {hot: hot},
         ),
       );

From 969c5201268a68d063bf91cf7df4c17b22193071 Mon Sep 17 00:00:00 2001
From: Dale Jefferson <dale@dalejefferson.com>
Date: Fri, 22 Jan 2016 14:20:16 -0800
Subject: [PATCH 0860/1411] Use renderSeparator in List View Example

Summary: Closes https://github.com/facebook/react-native/pull/5443

Reviewed By: svcscm

Differential Revision: D2856259

Pulled By: androidtrunkagent

fb-gh-sync-id: 68b4f5d16c852bbf06cd65346c32b8c6d3f2d36c
---
 Examples/UIExplorer/ListViewExample.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Examples/UIExplorer/ListViewExample.js b/Examples/UIExplorer/ListViewExample.js
index 420ed6ef70a1..c4df7c7a969c 100644
--- a/Examples/UIExplorer/ListViewExample.js
+++ b/Examples/UIExplorer/ListViewExample.js
@@ -57,6 +57,7 @@ var ListViewSimpleExample = React.createClass({
           dataSource={this.state.dataSource}
           renderRow={this._renderRow}
           renderScrollComponent={props => <RecyclerViewBackedScrollView {...props} />}
+          renderSeparator={(sectionID, rowID) => <View key={`${sectionID}-${rowID}`} style={styles.separator} />}
         />
       </UIExplorerPage>
     );
@@ -74,7 +75,6 @@ var ListViewSimpleExample = React.createClass({
               {rowData + ' - ' + LOREM_IPSUM.substr(0, rowHash % 301 + 10)}
             </Text>
           </View>
-          <View style={styles.separator} />
         </View>
       </TouchableHighlight>
     );

From f644af34efaa660888533b5c2d74153e673a99b1 Mon Sep 17 00:00:00 2001
From: Elliot Hesp <elliot.hesp@gmail.com>
Date: Fri, 22 Jan 2016 14:44:17 -0800
Subject: [PATCH 0861/1411] Correctly bind Touchable.js setTimeout

Summary:
Fixes https://github.com/facebook/react-native/issues/5337

`this.setTimeout` is undefined and the scope wasn't being passed through causing a RedBox error.
Closes https://github.com/facebook/react-native/pull/5376

Reviewed By: svcscm

Differential Revision: D2838623

Pulled By: androidtrunkagent

fb-gh-sync-id: 513210298b6c39d812047a03d8f2edd5c11e46f6
---
 Libraries/Components/Touchable/Touchable.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/Components/Touchable/Touchable.js b/Libraries/Components/Touchable/Touchable.js
index f9d8e1e43346..e0ea8850b234 100644
--- a/Libraries/Components/Touchable/Touchable.js
+++ b/Libraries/Components/Touchable/Touchable.js
@@ -670,7 +670,7 @@ var TouchableMixin = {
       this.touchableHandleActivePressIn && this.touchableHandleActivePressIn(e);
     } else if (!newIsHighlight && curIsHighlight && this.touchableHandleActivePressOut) {
       if (this.touchableGetPressOutDelayMS && this.touchableGetPressOutDelayMS()) {
-        this.pressOutDelayTimeout = this.setTimeout(function() {
+        this.pressOutDelayTimeout = setTimeout(() => {
           this.touchableHandleActivePressOut(e);
         }, this.touchableGetPressOutDelayMS());
       } else {

From 5a5386414f534fd68a30f71d77065001b400c1de Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Fri, 22 Jan 2016 15:54:14 -0800
Subject: [PATCH 0862/1411] AndroidViewPager -> ViewPagerAndroid

Summary: Closes https://github.com/facebook/react-native/pull/5471

Reviewed By: svcscm

Differential Revision: D2854830

Pulled By: androidtrunkagent

fb-gh-sync-id: 59fc6db6cbb96c2a7b3b23295e470ffb251c39fa
---
 docs/KnownIssues.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/KnownIssues.md b/docs/KnownIssues.md
index cc9de7dd6d3b..5a93bc25e589 100644
--- a/docs/KnownIssues.md
+++ b/docs/KnownIssues.md
@@ -45,7 +45,7 @@ There are properties that work on one platform only, either because they can inh
 
 There are known cases where the APIs could be made more consistent across iOS and Android:
 
-- `<AndroidViewPager>` and `<ScrollView pagingEnabled={true}>` on iOS do a similar thing. We might want to unify them to `<ViewPager>`.
+- `<ViewPagerAndroid>` and `<ScrollView pagingEnabled={true}>` on iOS do a similar thing. We might want to unify them to `<ViewPager>`.
 - It might be possible to bring `LinkingIOS` and `IntentAndroid` closer together.
 - `ActivityIndicator` could render a native spinning indicator on both platforms (currently this is done using `ActivityIndicatorIOS` on iOS and `ProgressBarAndroid` on Android).
 - `ProgressBar` could render a horizontal progress bar on both platforms (on iOS this is `ProgressViewIOS`, on Android it's `ProgressBarAndroid`).

From cc30e2b57cf4f9ded1b0a178d4d28f4ef6fa8308 Mon Sep 17 00:00:00 2001
From: DougBanksPersonal <doug@zeemee.com>
Date: Fri, 22 Jan 2016 17:26:17 -0800
Subject: [PATCH 0863/1411] Update RCTNavigator.m

Summary:
I am using ReactNative in a hybrid App.

We have a setup like so:

Native Navigation Controller
  Native Tab Controller
    Native View Controller wrapping React
      React Navigation Controller
        React View Controller 1
          React View Controller 2
  Native View Controller 2.

When I pop Native View Controller 2 off the Navigation stack, I get a seg fault on this line:

NSUInteger indexOfFrom = [_currentViews indexOfObject:fromController.navItem];

I believe what's happening:
Your code is listening to Nav Controller transitions, assuming that they are all from React Native Nav Controllers.
You are catching this one instead, which is actually a Native Nav Controller transition.
You start trying to access the pushed/popped view controllers as if they were react native view controllers.

In this case, the view controllers are not react native -> no navItem field -> seg fault.

Solution: if we are catching this transition but it isn't from our react native nav controller, just
Closes https://github.com/facebook/react-native/pull/5495

Reviewed By: svcscm

Differential Revision: D2857473

Pulled By: nicklockwood

fb-gh-sync-id: cc7f0a16e2e0cea56ca9e49bcb87db4ebd3a0905
---
 React/Views/RCTNavigator.m | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/React/Views/RCTNavigator.m b/React/Views/RCTNavigator.m
index 460a5fc6ef17..10e415ab0ecf 100644
--- a/React/Views/RCTNavigator.m
+++ b/React/Views/RCTNavigator.m
@@ -361,6 +361,13 @@ - (void)navigationController:(UINavigationController *)navigationController
       (RCTWrapperViewController *)[context viewControllerForKey:UITransitionContextFromViewControllerKey];
     RCTWrapperViewController *toController =
       (RCTWrapperViewController *)[context viewControllerForKey:UITransitionContextToViewControllerKey];
+      
+    // This may be triggered by a navigation controller unrelated to me: if so, ignore.
+    if (fromController.navigationController != _navigationController ||
+        toController.navigationController != _navigationController) {
+      return;
+    }
+    
     NSUInteger indexOfFrom = [_currentViews indexOfObject:fromController.navItem];
     NSUInteger indexOfTo = [_currentViews indexOfObject:toController.navItem];
     CGFloat destination = indexOfFrom < indexOfTo ? 1.0 : -1.0;

From ae45d8bd4cc7b0fc810c3f21dcf2c7188ae3097d Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Sat, 23 Jan 2016 02:57:58 -0800
Subject: [PATCH 0864/1411] More fixes to BUCK and java builds of OSS React
 Native

Reviewed By: mkonicek

Differential Revision: D2849743

fb-gh-sync-id: 7d0ae9a2fcfda8c017b60af3e8fe7fa4029ab6ea
---
 ReactAndroid/DEFS                             |  36 ++++++
 .../java/com/facebook/react/testing/BUCK      |   1 -
 .../src/test/java/com/facebook/powermock/BUCK |  89 ++++++++++++++
 .../src/main/third-party/java/asm/BUCK        |  71 +++++++++++
 .../src/main/third-party/java/fest/BUCK       |  23 +++-
 .../src/main/third-party/java/junit/BUCK      |  25 +++-
 .../src/main/third-party/java/mockito/BUCK    |  23 +++-
 .../java/robolectric3/robolectric/BUCK        | 111 ++++++++++++++++++
 .../src/main/third-party/java/sqlite/BUCK     |  19 +++
 .../third-party/java/testing-support-lib/BUCK |  12 ++
 .../test/java/com/facebook/react/bridge/BUCK  |   3 +-
 11 files changed, 408 insertions(+), 5 deletions(-)
 create mode 100644 ReactAndroid/src/main/third-party/java/asm/BUCK
 create mode 100644 ReactAndroid/src/main/third-party/java/sqlite/BUCK
 create mode 100644 ReactAndroid/src/main/third-party/java/testing-support-lib/BUCK

diff --git a/ReactAndroid/DEFS b/ReactAndroid/DEFS
index 87477552ff8a..1ba010a93988 100644
--- a/ReactAndroid/DEFS
+++ b/ReactAndroid/DEFS
@@ -4,6 +4,9 @@
 # - At Facebook by running buck from the root of the fb repo
 # - Outside of Facebook by running buck in the root of the git repo
 
+import os
+
+
 # Example: react_native_target('java/com/facebook/react/common:common')
 def react_native_target(path):
   return '//ReactAndroid/src/main/' + path
@@ -51,3 +54,36 @@ def android_library(
     annotation_processor_deps=annotation_processor_deps,
     *args,
     **kwargs)
+
+
+def robolectric3_test(name, deps, vm_args=None, *args, **kwargs):
+
+  vm_args = vm_args or []
+
+  # We may need to create buck-out/gen/ if we're running after buck clean.
+  tmp = 'buck-out/gen/' + get_base_path() + '/__java_test_' + name + '_output__'
+  extra_vm_args = [
+    '-XX:+UseConcMarkSweepGC', # required by -XX:+CMSClassUnloadingEnabled
+    '-XX:+CMSClassUnloadingEnabled',
+    '-XX:ReservedCodeCacheSize=150M',
+    '-Drobolectric.dependency.dir=buck-out/gen/ReactAndroid/src/main/third-party/java/robolectric3/robolectric',
+    '-Dlibraries=buck-out/gen/ReactAndroid/src/main/third-party/java/robolectric3/robolectric/*.jar',
+    '-Drobolectric.logging.enabled=true',
+    '-XX:MaxPermSize=620m',
+    '-Drobolectric.offline=true',
+  ]
+  if os.path.isdir("/dev/shm"):
+      extra_vm_args.append('-Djava.io.tmpdir=/dev/shm')
+  else:
+      extra_vm_args.append(
+          '-Djava.io.tmpdir=%s' % os.path.join(os.path.abspath('.'),
+                                               'buck-out/bin'))
+
+  # defined in BUCK
+  robolectric_test(
+    name=name,
+    deps=deps,
+    vm_args=vm_args + extra_vm_args,
+    *args,
+    **kwargs
+  )
\ No newline at end of file
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/BUCK b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/BUCK
index d3c6d72551dc..2ec63965134a 100644
--- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/BUCK
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/BUCK
@@ -14,7 +14,6 @@ android_library(
     react_native_target('java/com/facebook/react/uimanager:uimanager'),
     react_native_dep('libraries/soloader/java/com/facebook/soloader:soloader'),
     react_native_dep('third-party/android/support/v4:lib-support-v4'),
-    react_native_dep('third-party/java/guava:guava'),
     react_native_dep('third-party/java/infer-annotations:infer-annotations'),
     react_native_dep('third-party/java/jsr-305:jsr-305'),
     react_native_dep('third-party/java/junit:junit'),
diff --git a/ReactAndroid/src/main/libraries/fbcore/src/test/java/com/facebook/powermock/BUCK b/ReactAndroid/src/main/libraries/fbcore/src/test/java/com/facebook/powermock/BUCK
index 7bb6f6802a4c..c5d9b9f497b6 100644
--- a/ReactAndroid/src/main/libraries/fbcore/src/test/java/com/facebook/powermock/BUCK
+++ b/ReactAndroid/src/main/libraries/fbcore/src/test/java/com/facebook/powermock/BUCK
@@ -2,10 +2,17 @@ android_library(
     name = 'powermock',
     exported_deps = [
         ':powermock-api-mockito',
+        ':mockito-all',
         ':powermock-api-support',
         ':powermock-module-junit4-rule',
+        ':powermock-classloading-base',
         ':powermock-classloading-xstream',
+        ':xstream',
         ':powermock-core',
+        ':powermock-reflect',
+        ':javassist',
+        ':xmlpull',
+        ':xpp3'
     ],
     visibility = ['//ReactAndroid/...',],
 )
@@ -70,4 +77,86 @@ remote_file(
     sha1 = '3ced31cd7024fe365b9f3c8082d22c02434577da',
 )
 
+prebuilt_jar(
+    name = 'powermock-classloading-base',
+    binary_jar = ':download-powermock-classloading-base',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'download-powermock-classloading-base',
+    url = 'mvn:org.powermock:powermock-classloading-base:jar:1.6.2',
+    sha1 = 'c8bfc10731a02d3b241892cf2c334a754d473ca7',
+)
+
+prebuilt_jar(
+    name = 'xstream',
+    binary_jar = ':download-xstream',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'download-xstream',
+    url = 'mvn:com.thoughtworks.xstream:xstream:jar:1.4.2',
+    sha1 = '97e5013f391487cce4de6b0eebcde21549e91872',
+)
+
+prebuilt_jar(
+    name = 'powermock-reflect',
+    binary_jar = ':download-powermock-reflect',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'download-powermock-reflect',
+    url = 'mvn:org.powermock:powermock-reflect:jar:1.6.2',
+    sha1 = '1af1bbd1207c3ecdcf64973e6f9d57dcd17cc145',
+)
+
+prebuilt_jar(
+    name = 'javassist',
+    binary_jar = ':download-javassist',
+    visibility = ['//ReactAndroid/...',],
+)
 
+remote_file(
+    name = 'download-javassist',
+    url = 'mvn:org.javassist:javassist:jar:3.20.0-GA',
+    sha1 = 'a9cbcdfb7e9f86fbc74d3afae65f2248bfbf82a0',
+)
+
+prebuilt_jar(
+    name = 'mockito-all',
+    binary_jar = ':download-mockito-all',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'download-mockito-all',
+    url = 'mvn:org.mockito:mockito-all:jar:1.10.19',
+    sha1 = '539df70269cc254a58cccc5d8e43286b4a73bf30',
+)
+
+prebuilt_jar(
+    name = 'xmlpull',
+    binary_jar = ':download-xmlpull',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'download-xmlpull',
+    url = 'mvn:xmlpull:xmlpull:jar:1.1.3.1',
+    sha1 = '2b8e230d2ab644e4ecaa94db7cdedbc40c805dfa',
+)
+
+prebuilt_jar(
+    name = 'xpp3',
+    binary_jar = ':download-xpp3',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'download-xpp3',
+    url = 'mvn:xpp3:xpp3_min:jar:1.1.4c',
+    sha1 = '19d4e90b43059058f6e056f794f0ea4030d60b86',
+)
diff --git a/ReactAndroid/src/main/third-party/java/asm/BUCK b/ReactAndroid/src/main/third-party/java/asm/BUCK
new file mode 100644
index 000000000000..08b3194c4785
--- /dev/null
+++ b/ReactAndroid/src/main/third-party/java/asm/BUCK
@@ -0,0 +1,71 @@
+android_library(
+  name = 'asm',
+  exported_deps = [
+      ':asm-core',
+      ':asm-commons',
+      ':asm-util',
+      ':asm-analysis',
+      ':asm-tree',
+  ],
+  visibility = ['//ReactAndroid/...',],
+)
+
+prebuilt_jar(
+  name = 'asm-core',
+  binary_jar = ':download-asm',
+  visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+  name = 'download-asm',
+  url = 'mvn:org.ow2.asm:asm:jar:5.0.1',
+  sha1 = '2fd56467a018aafe6ec6a73ccba520be4a7e1565',
+)
+
+prebuilt_jar(
+  name = 'asm-commons',
+  binary_jar = ':download-asm-commons',
+  visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+  name = 'download-asm-commons',
+  url = 'mvn:org.ow2.asm:asm-commons:jar:5.0.1',
+  sha1 = '7b7147a390a93a14d2edfdcf3f7b0e87a0939c3e',
+)
+
+prebuilt_jar(
+  name = 'asm-tree',
+  binary_jar = ':download-asm-tree',
+  visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+  name = 'download-asm-tree',
+  url = 'mvn:org.ow2.asm:asm-tree:jar:5.0.1',
+  sha1 = '1b1e6e9d869acd704056d0a4223071a511c619e6',
+)
+
+prebuilt_jar(
+  name = 'asm-util',
+  binary_jar = ':download-asm-util',
+  visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+  name = 'download-asm-util',
+  url = 'mvn:org.ow2.asm:asm-util:jar:5.0.1',
+  sha1 = '7c8caddfbd0b2d7b844f8fcc75175b9cb9cf4724',
+)
+
+prebuilt_jar(
+  name = 'asm-analysis',
+  binary_jar = ':download-asm-analysis',
+  visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+  name = 'download-asm-analysis',
+  url = 'mvn:org.ow2.asm:asm-analysis:jar:5.0.1',
+  sha1 = 'e286fbee48efacb4e7c175f7948d9d8b2ab52352',
+)
diff --git a/ReactAndroid/src/main/third-party/java/fest/BUCK b/ReactAndroid/src/main/third-party/java/fest/BUCK
index b802709c6dbb..9b9e10c86331 100644
--- a/ReactAndroid/src/main/third-party/java/fest/BUCK
+++ b/ReactAndroid/src/main/third-party/java/fest/BUCK
@@ -1,5 +1,14 @@
-prebuilt_jar(
+android_library(
     name = 'fest',
+    exported_deps = [
+        ':fest-core',
+        ':fest-util',
+    ],
+    visibility = ['//ReactAndroid/...',],
+)
+
+prebuilt_jar(
+    name = 'fest-core',
     binary_jar = ':fest-binary-jar',
     visibility = ['//ReactAndroid/...',],
 )
@@ -9,3 +18,15 @@ remote_file(
     url = 'mvn:org.easytesting:fest-assert-core:jar:2.0M10',
     sha1 = 'cb7c91cf614901928ae405f19d9bcdedf82781db',
 )
+
+prebuilt_jar(
+    name = 'fest-util',
+    binary_jar = ':fest-util-binary-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'fest-util-binary-jar',
+    url = 'mvn:org.easytesting:fest-util:jar:1.2.5',
+    sha1 = 'c4a8d7305b23b8d043be12c979813b096df11f44',
+)
diff --git a/ReactAndroid/src/main/third-party/java/junit/BUCK b/ReactAndroid/src/main/third-party/java/junit/BUCK
index c5f67b01088d..327e10078527 100644
--- a/ReactAndroid/src/main/third-party/java/junit/BUCK
+++ b/ReactAndroid/src/main/third-party/java/junit/BUCK
@@ -1,5 +1,16 @@
-prebuilt_jar(
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
   name = 'junit',
+  exported_deps = [
+    ':junit-core',
+    ':hamcrest',
+  ],
+  visibility = ['//ReactAndroid/...',],
+)
+
+prebuilt_jar(
+  name = 'junit-core',
   binary_jar = ':download-junit',
   visibility = ['//ReactAndroid/...',],
 )
@@ -9,3 +20,15 @@ remote_file(
   url = 'mvn:junit:junit:jar:4.12',
   sha1 = '2973d150c0dc1fefe998f834810d68f278ea58ec',
 )
+
+prebuilt_jar(
+  name = 'hamcrest',
+  binary_jar = ':download-hamcrest',
+  visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+  name = 'download-hamcrest',
+  url = 'mvn:org.hamcrest:hamcrest-all:jar:1.3',
+  sha1 = '63a21ebc981131004ad02e0434e799fd7f3a8d5a',
+)
diff --git a/ReactAndroid/src/main/third-party/java/mockito/BUCK b/ReactAndroid/src/main/third-party/java/mockito/BUCK
index ef93db4abb2b..35b50499a5a7 100644
--- a/ReactAndroid/src/main/third-party/java/mockito/BUCK
+++ b/ReactAndroid/src/main/third-party/java/mockito/BUCK
@@ -1,5 +1,14 @@
-prebuilt_jar(
+android_library(
     name = 'mockito',
+    exported_deps = [
+        ':mockito-core',
+        ':objenesis',
+    ],
+    visibility = ['//ReactAndroid/...',],
+)
+
+prebuilt_jar(
+    name = 'mockito-core',
     binary_jar = ':mockito-binary-jar',
     visibility = ['//ReactAndroid/...',],
 )
@@ -9,3 +18,15 @@ remote_file(
     url = 'mvn:org.mockito:mockito-core:jar:1.10.19',
     sha1 = 'e8546f5bef4e061d8dd73895b4e8f40e3fe6effe',
 )
+
+prebuilt_jar(
+    name = 'objenesis',
+    binary_jar = ':objenesis-binary-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'objenesis-binary-jar',
+    url = 'mvn:org.objenesis:objenesis:jar:2.1',
+    sha1 = '87c0ea803b69252868d09308b4618f766f135a96',
+)
diff --git a/ReactAndroid/src/main/third-party/java/robolectric3/robolectric/BUCK b/ReactAndroid/src/main/third-party/java/robolectric3/robolectric/BUCK
index 7e30d1c029ee..b035e0941063 100644
--- a/ReactAndroid/src/main/third-party/java/robolectric3/robolectric/BUCK
+++ b/ReactAndroid/src/main/third-party/java/robolectric3/robolectric/BUCK
@@ -1,9 +1,24 @@
+include_defs('//ReactAndroid/DEFS')
+
 android_library(
     name = 'robolectric',
     exported_deps = [
         ':robolectric-core',
         ':robolectric-resources',
         ':robolectric-annotations',
+        ':robolectric-utils',
+        ':bouncycastle',
+        ':vtd-xml',
+        ':icu',
+        ':android-all-4.1.2_r1-robolectric-0',
+        ':json-20080701',
+        ':tagsoup-1.2',
+        ':shadows-core-3.0-16',
+        react_native_dep('third-party/java/asm:asm'),
+        react_native_dep('third-party/java/sqlite:sqlite'),
+    ],
+    deps = [
+#         ':locate_android-all',
     ],
     visibility = ['//ReactAndroid/...',],
 )
@@ -43,3 +58,99 @@ remote_file(
     url = 'mvn:org.robolectric:robolectric-annotations:jar:3.0',
     sha1 = '2a6cfc072d7680694c1ff893c5dc8fec33163110',
 )
+
+prebuilt_jar(
+    name = 'robolectric-utils',
+    binary_jar = ':robolectric-utils-binary-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'robolectric-utils-binary-jar',
+    url = 'mvn:org.robolectric:robolectric-utils:jar:3.0',
+    sha1 = '4bcecd8115fe7296088bb1636e6cbd7ae8927392',
+)
+
+prebuilt_jar(
+    name = 'bouncycastle',
+    binary_jar = ':bouncycastle-binary-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'bouncycastle-binary-jar',
+    url = 'mvn:org.bouncycastle:bcprov-jdk16:jar:1.46',
+    sha1 = 'ce091790943599535cbb4de8ede84535b0c1260c',
+)
+
+prebuilt_jar(
+    name = 'vtd-xml',
+    binary_jar = ':vtd-xml-binary-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'vtd-xml-binary-jar',
+    url = 'mvn:com.ximpleware:vtd-xml:jar:2.11',
+    sha1 = 'ee5bcf62c1acf76434ee9f1c67a840bafef72a6d',
+)
+
+prebuilt_jar(
+    name = 'icu',
+    binary_jar = ':icu-binary-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'icu-binary-jar',
+    url = 'mvn:com.ibm.icu:icu4j:jar:53.1',
+    sha1 = '786d9055d4ca8c1aab4a7d4ac8283f973fd7e41f',
+)
+
+prebuilt_jar(
+    name = 'android-all-4.1.2_r1-robolectric-0', # name defines filename used by robolectric in runtime
+    binary_jar = ':robolectric-android-all-binary-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'robolectric-android-all-binary-jar',
+    url = 'mvn:org.robolectric:android-all:jar:4.1.2_r1-robolectric-0',
+    sha1 = 'aecc8ce5119a25fcea1cdf8285469c9d1261a352',
+)
+
+prebuilt_jar(
+    name = 'json-20080701', # name defines filename used by robolectric in runtime
+    binary_jar = ':json-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'json-jar',
+    url = 'mvn:org.json:json:jar:20080701',
+    sha1 = 'd652f102185530c93b66158b1859f35d45687258',
+)
+
+prebuilt_jar(
+    name = 'tagsoup-1.2', # name defines filename used by robolectric in runtime
+    binary_jar = ':tagsoup-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'tagsoup-jar',
+    url = 'mvn:org.ccil.cowan.tagsoup:tagsoup:jar:1.2',
+    sha1 = '639fd364750d7363c85797dc944b4a80f78fa684',
+)
+
+prebuilt_jar(
+    name = 'shadows-core-3.0-16', # name defines filename used by robolectric in runtime
+    binary_jar = ':robolectric-shadows-binary-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'robolectric-shadows-binary-jar',
+    url = 'https://repo1.maven.org/maven2/org/robolectric/shadows-core/3.0/shadows-core-3.0-16.jar',
+    sha1 = '39d7a856bf91640b1a6d044333336a2b3f3c198f',
+)
diff --git a/ReactAndroid/src/main/third-party/java/sqlite/BUCK b/ReactAndroid/src/main/third-party/java/sqlite/BUCK
new file mode 100644
index 000000000000..441701450543
--- /dev/null
+++ b/ReactAndroid/src/main/third-party/java/sqlite/BUCK
@@ -0,0 +1,19 @@
+android_library(
+  name = 'sqlite',
+  exported_deps = [
+      ':sqlite4java'
+  ],
+  visibility = ['//ReactAndroid/...',],
+)
+
+prebuilt_jar(
+  name = 'sqlite4java',
+  binary_jar = ':download-sqlite4java',
+  visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+  name = 'download-sqlite4java',
+  url = 'mvn:com.almworks.sqlite4java:sqlite4java:jar:0.282',
+  sha1 = '745a7e2f35fdbe6336922e0d492c979dbbfa74fb',
+)
diff --git a/ReactAndroid/src/main/third-party/java/testing-support-lib/BUCK b/ReactAndroid/src/main/third-party/java/testing-support-lib/BUCK
new file mode 100644
index 000000000000..f3b93922cc73
--- /dev/null
+++ b/ReactAndroid/src/main/third-party/java/testing-support-lib/BUCK
@@ -0,0 +1,12 @@
+android_prebuilt_aar(
+    name = 'testing-support-lib',
+    aar = ':testing-support-lib-download',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'testing-support-lib-download',
+    url = 'mvn:com.android.support.test:testing-support-lib:aar:0.1',
+    sha1 = '36e4f08b2a3389dd5a5093411df35091bdd68361',
+)
+
diff --git a/ReactAndroid/src/test/java/com/facebook/react/bridge/BUCK b/ReactAndroid/src/test/java/com/facebook/react/bridge/BUCK
index 22f7d5535c78..bb67c85be89d 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/bridge/BUCK
+++ b/ReactAndroid/src/test/java/com/facebook/react/bridge/BUCK
@@ -12,7 +12,8 @@ android_library(
     react_native_target('java/com/facebook/react/uimanager:uimanager'),
     react_native_dep('third-party/java/mockito:mockito'),
     react_native_dep('third-party/java/robolectric3/robolectric:robolectric'),
-  ],
+    react_native_tests_target('java/org/mockito/configuration:configuration'),
+],
   visibility = [
     'PUBLIC'
   ],

From 0331c02c8faed9e3a4bd0416d57b72f0c8a876e4 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Sat, 23 Jan 2016 10:49:33 -0800
Subject: [PATCH 0865/1411] added buck to circle.ci build infra

Summary: Closes https://github.com/facebook/react-native/pull/5333

Reviewed By: svcscm

Differential Revision: D2858779

Pulled By: androidtrunkagent

fb-gh-sync-id: 2458f6324384378ea9f6dd67dc170d42e418aa24
---
 circle.yml | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/circle.yml b/circle.yml
index c50783716fd6..eff3e340558a 100644
--- a/circle.yml
+++ b/circle.yml
@@ -13,12 +13,21 @@ machine:
 
 dependencies:
   pre:
+  # BUCK
+  - if [[ ! -e buck ]]; then git clone https://github.com/facebook/buck.git; fi
+  - cd buck && ant
+  - buck/bin/buck --version
+  - buck/bin/buck fetch ReactAndroid/src/test/java/com/facebook/react/modules
+  - buck/bin/buck fetch ReactAndroid/src/main/java/com/facebook/react
+  - buck/bin/buck fetch ReactAndroid/src/main/java/com/facebook/react/shell
+  - buck/bin/buck fetch ReactAndroid/src/androidTest/java/com/facebook/react/tests
   # using npm@3 because of problems with shrink-wrapped optional deps installs on linux
   - npm install -g npm@3.2
   - source scripts/circle-ci-android-setup.sh && getAndroidSDK
   - ./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog
   cache_directories:
   - "ReactAndroid/build/downloads"
+  - "buck-out"
 test:
   pre:
     # starting emulator in advance because it takes very long to boot
@@ -29,6 +38,13 @@ test:
             timeout: 360
     - source scripts/circle-ci-android-setup.sh && waitForAVD
   override:
+    # buck tests
+    - buck/bin/buck test ReactAndroid/src/test/java/com/facebook/react/modules
+    - buck/bin/buck build ReactAndroid/src/main/java/com/facebook/react
+    - buck/bin/buck build ReactAndroid/src/main/java/com/facebook/react/shell
+    # temp, we can't run instrumentation tests yet
+    - buck/bin/buck build ReactAndroid/src/androidTest/java/com/facebook/react/tests
+
     # unit tests
     - ./gradlew :ReactAndroid:testDebugUnitTest -PdisablePreDex
     # build JS bundle for instrumentation tests

From 2b309a426a3ba7156711af931099ba1bf1675195 Mon Sep 17 00:00:00 2001
From: Christopher Dro <hello@blick-labs.com>
Date: Sat, 23 Jan 2016 11:00:39 -0800
Subject: [PATCH 0866/1411] Updates to Text & IntentAndroid

Summary: Closes https://github.com/facebook/react-native/pull/5496

Reviewed By: svcscm

Differential Revision: D2858772

Pulled By: androidtrunkagent

fb-gh-sync-id: 5edf52af256efe6bb7ae1f8bcc2622d7e6a1298c
---
 .../Intent/IntentAndroid.android.js           | 23 +++++++++++++++++--
 Libraries/Text/Text.js                        |  1 +
 2 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/Libraries/Components/Intent/IntentAndroid.android.js b/Libraries/Components/Intent/IntentAndroid.android.js
index 9dad6327bbab..cebe69948209 100644
--- a/Libraries/Components/Intent/IntentAndroid.android.js
+++ b/Libraries/Components/Intent/IntentAndroid.android.js
@@ -33,8 +33,27 @@ var invariant = require('invariant');
  * }
  * ```
  *
- * NOTE: For instructions on how to add support for deep linking,
- * refer [Enabling Deep Links for App Content - Add Intent Filters for Your Deep Links](http://developer.android.com/training/app-indexing/deep-linking.html#adding-filters).
+ * Example to add support for deep linking inside your React Native app.
+ * More Info: [Enabling Deep Links for App Content - Add Intent Filters for Your Deep Links](http://developer.android.com/training/app-indexing/deep-linking.html#adding-filters).
+ *
+ * Edit in `android/app/src/main/AndroidManifest.xml`
+ *
+ * ```
+ *  <intent-filter>
+ *    <action android:name="android.intent.action.VIEW" />
+ *    <category android:name="android.intent.category.DEFAULT" />
+ *    <category android:name="android.intent.category.BROWSABLE" />
+ *
+ *    <!-- Accepts URIs that begin with "http://www.facebook.com/react -->
+ *    <data android:scheme="http"
+ *       android:host="www.facebook.com"
+ *       android:pathPrefix="/react" />
+ *    <!-- note that the leading "/" is required for pathPrefix-->
+ *
+ *    <!-- Accepts URIs that begin with "facebook://react -->
+ *    <!-- <data android:scheme="facebook" android:host="react" /> -->
+ *  </intent-filter>
+ * ```
  *
  * #### Opening external links
  *
diff --git a/Libraries/Text/Text.js b/Libraries/Text/Text.js
index e86f69fc195a..eeb88c2dd2d3 100644
--- a/Libraries/Text/Text.js
+++ b/Libraries/Text/Text.js
@@ -99,6 +99,7 @@ const Text = React.createClass({
     testID: React.PropTypes.string,
     /**
      * Specifies should fonts scale to respect Text Size accessibility setting on iOS.
+     * @platform ios
      */
     allowFontScaling: React.PropTypes.bool,
   },

From e3bb55335a21c1abdd4935389aac6164cf08b6f6 Mon Sep 17 00:00:00 2001
From: Arjun Komath <arjunkomath@gmail.com>
Date: Sun, 24 Jan 2016 02:17:26 +0530
Subject: [PATCH 0867/1411] Add 'Feline for Product Hunt' into Showcase Apps

---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index b3530354daa6..76c51c93be18 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -216,6 +216,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/fast-paper/id1001174614',
     author: 'Liubomyr Mykhalchenko (@liubko)',
   },
+  {
+    name: 'Feline for Product Hunt',
+    icon: 'https://lh3.googleusercontent.com/MCoiCCwUan0dxzqRR_Mrr7kO308roYdI2aTsIpUGYWzUmpJT1-R2_J04weQKFEd3Mg=w300-rw',
+    link: 'https://play.google.com/store/apps/details?id=com.arjunkomath.product_hunt&hl=en',
+    author: 'Arjun Komath',
+  },
   {
     name: 'Foodstand',
     icon: 'http://a3.mzstatic.com/us/r30/Purple69/v4/33/c1/3b/33c13b88-8ec2-23c1-56bb-712ad9938290/icon350x350.jpeg',

From f68281a0d8fc6026a5c27675c086090ace19a5eb Mon Sep 17 00:00:00 2001
From: Noam Bartov <bartov@gmail.com>
Date: Sun, 24 Jan 2016 13:59:36 -0800
Subject: [PATCH 0868/1411] added support for overlayColor property for image

Summary:
In Android, Fresco's default rounding corners support mode is BITMAP_ONLY which doesn't work in all cases (such as animated GIF's, some scale types, etc.).
Specifying the new "overlayColor" property on an Image will cause Fresco to switch to the other rounding corners mode, OVERLAY_COLOR, and will draw rounded corners by overlaying the solid color specified.

Fresco's behaviour is explained here: http://frescolib.org/docs/rounded-corners-and-circles.html
Closes https://github.com/facebook/react-native/pull/5366

Reviewed By: svcscm

Differential Revision: D2854696

Pulled By: mkonicek

fb-gh-sync-id: 251701ee8a64acbfc22694e9d4661c40eef75725
---
 .../View/ReactNativeStyleAttributes.js        |  1 +
 Libraries/Image/ImageStylePropTypes.js        | 25 +++++++++++++++++--
 .../react/views/image/ReactImageManager.java  |  9 +++++++
 .../react/views/image/ReactImageView.java     | 13 ++++++++++
 4 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/Libraries/Components/View/ReactNativeStyleAttributes.js b/Libraries/Components/View/ReactNativeStyleAttributes.js
index d26e01615f27..b9e909a17ecf 100644
--- a/Libraries/Components/View/ReactNativeStyleAttributes.js
+++ b/Libraries/Components/View/ReactNativeStyleAttributes.js
@@ -47,5 +47,6 @@ ReactNativeStyleAttributes.shadowColor = colorAttributes;
 ReactNativeStyleAttributes.textDecorationColor = colorAttributes;
 ReactNativeStyleAttributes.tintColor = colorAttributes;
 ReactNativeStyleAttributes.textShadowColor = colorAttributes;
+ReactNativeStyleAttributes.overlayColor = colorAttributes;
 
 module.exports = ReactNativeStyleAttributes;
diff --git a/Libraries/Image/ImageStylePropTypes.js b/Libraries/Image/ImageStylePropTypes.js
index 5e99a54b08c0..b1c5e12b1124 100644
--- a/Libraries/Image/ImageStylePropTypes.js
+++ b/Libraries/Image/ImageStylePropTypes.js
@@ -30,10 +30,31 @@ var ImageStylePropTypes = {
   borderRadius: ReactPropTypes.number,
   overflow: ReactPropTypes.oneOf(['visible', 'hidden']),
 
-  // iOS-Specific style to "tint" an image.
-  // It changes the color of all the non-transparent pixels to the tintColor
+  /** 
+   * iOS-Specific style to "tint" an image.
+   * Changes the color of all the non-transparent pixels to the tintColor.
+   * @platform ios
+   */
   tintColor: ColorPropType,
   opacity: ReactPropTypes.number,
+  /**
+   * When the image has rounded corners, specifying an overlayColor will
+   * cause the remaining space in the corners to be filled with a solid color.
+   * This is useful in cases which are not supported by the Android
+   * implementation of rounded corners:
+   *   - Certain resize modes, such as 'contain'
+   *   - Animated GIFs
+   * 
+   * A typical way to use this prop is with images displayed on a solid
+   * background and setting the `overlayColor` to the same color
+   * as the background.
+   *
+   * For details of how this works under the hood, see
+   * http://frescolib.org/docs/rounded-corners-and-circles.html
+   *
+   * @platform android
+  */
+  overlayColor: ReactPropTypes.string,
 };
 
 module.exports = ImageStylePropTypes;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
index 812fd4118fc6..8b3298647d0a 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
@@ -88,6 +88,15 @@ public void setBorderColor(ReactImageView view, @Nullable Integer borderColor) {
     }
   }
 
+  @ReactProp(name = "overlayColor")
+  public void setOverlayColor(ReactImageView view, @Nullable Integer overlayColor) {
+    if (overlayColor == null) {
+      view.setOverlayColor(Color.TRANSPARENT);
+    } else {
+      view.setOverlayColor(overlayColor);
+    }
+  }
+
   @ReactProp(name = "borderWidth")
   public void setBorderWidth(ReactImageView view, float borderWidth) {
     view.setBorderWidth(borderWidth);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
index 58ebb0c804e3..c627bdc6ebd3 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
@@ -16,6 +16,7 @@
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
+import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Rect;
@@ -108,6 +109,7 @@ public void process(Bitmap output, Bitmap source) {
   private @Nullable Uri mUri;
   private @Nullable Drawable mLoadingImageDrawable;
   private int mBorderColor;
+  private int mOverlayColor;
   private float mBorderWidth;
   private float mBorderRadius;
   private ScalingUtils.ScaleType mScaleType;
@@ -186,6 +188,11 @@ public void setBorderColor(int borderColor) {
     mIsDirty = true;
   }
 
+  public void setOverlayColor(int overlayColor) {
+    mOverlayColor = overlayColor;
+    mIsDirty = true;
+  }
+
   public void setBorderWidth(float borderWidth) {
     mBorderWidth = PixelUtil.toPixelFromDIP(borderWidth);
     mIsDirty = true;
@@ -266,6 +273,12 @@ public void maybeUpdateView() {
     RoundingParams roundingParams = hierarchy.getRoundingParams();
     roundingParams.setCornersRadius(hierarchyRadius);
     roundingParams.setBorder(mBorderColor, mBorderWidth);
+    if (mOverlayColor != Color.TRANSPARENT) {
+        roundingParams.setOverlayColor(mOverlayColor);
+    } else {
+        // make sure the default rounding method is used.
+        roundingParams.setRoundingMethod(RoundingParams.RoundingMethod.BITMAP_ONLY);
+    }
     hierarchy.setRoundingParams(roundingParams);
     hierarchy.setFadeDuration(
         mFadeDurationMs >= 0

From dde5e02c019ba75e7fd25a06ab449d4524f2f948 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=BC=A0=E4=BA=A6=E9=A9=B0?= <zhangyichi@meituan.com>
Date: Mon, 25 Jan 2016 01:30:37 -0800
Subject: [PATCH 0869/1411] fix the syntax error in doc tutorial

Summary:
maybe it is a bug when migrating from es5 to es6
Closes https://github.com/facebook/react-native/pull/5526

Reviewed By: svcscm

Differential Revision: D2860047

Pulled By: androidtrunkagent

fb-gh-sync-id: d8be261eea08ec659999fe8c714f33aca6fe3a60
---
 docs/Tutorial.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/Tutorial.md b/docs/Tutorial.md
index 6a809b77c37a..b5dc1d16c084 100644
--- a/docs/Tutorial.md
+++ b/docs/Tutorial.md
@@ -463,7 +463,7 @@ class AwesomeProject extends Component {
       </View>
     );
   }
-});
+}
 
 var styles = StyleSheet.create({
   container: {

From 0893d07db197b4f78752f982abbc568c6c0c7419 Mon Sep 17 00:00:00 2001
From: James Ide <ide@jameside.com>
Date: Mon, 25 Jan 2016 05:32:49 -0800
Subject: [PATCH 0870/1411] Revert "Enable JSX files extension"

Summary:
This reverts commit 888749220dac26382412f2c38ac5f9205cc842e5.

The original commit didn't handle cases like .(ios|android|native).js, and vjeux is in favor of standardizing on .js instead of custom extensions like .jsx or .es6 everywhere.

> Unfortunately this pull request doesn't implement with .ios.jsx. But, when/if it does, it raises more questions like what happens if you have both ios.js and ios.jsx?
>
> Sorry to chime in super late but I actually think that this is harmful to support .jsx extension. We now live in a world where we have many transforms for es6, flow, jsx... Why would we add .jsx but not .flow or .es6. Supporting more extensions is only going to fragment tools even more.

https://github.com/facebook/react-native/pull/5233#discussion_r49682279
Closes https://github.com/facebook/react-native/pull/5296

Reviewed By: svcscm

Differential Revision: D2830784

Pulled By: bestander

fb-gh-sync-id: 9a7a4745803acbcbc5dba176b971c629c904bacd
---
 .../src/DependencyResolver/DependencyGraph/ResolutionRequest.js | 2 --
 .../src/DependencyResolver/DependencyGraph/index.js             | 2 +-
 packager/react-packager/src/Server/index.js                     | 1 -
 3 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
index 2c18c95a34be..f67404393902 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
@@ -350,8 +350,6 @@ class ResolutionRequest {
         file = potentialModulePath + '.native.js';
       } else if (this._fastfs.fileExists(potentialModulePath + '.js')) {
         file = potentialModulePath + '.js';
-      } else if (this._fastfs.fileExists(potentialModulePath + '.jsx')) {
-        file = potentialModulePath + '.jsx';
       } else if (this._fastfs.fileExists(potentialModulePath + '.json')) {
         file = potentialModulePath + '.json';
       } else {
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
index 1278d2ce8544..1192159b308d 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
@@ -55,7 +55,7 @@ class DependencyGraph {
       platforms: platforms || [],
       preferNativePlatform: preferNativePlatform || false,
       cache,
-      extensions: extensions || ['js', 'jsx', 'json'],
+      extensions: extensions || ['js', 'json'],
       mocksPattern,
       extractRequires,
       shouldThrowOnUnresolvedErrors,
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index 3bb8a9c0eafb..99a3472d6483 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -151,7 +151,6 @@ class Server {
         dir: dir,
         globs: [
           '**/*.js',
-          '**/*.jsx',
           '**/*.json',
         ].concat(assetGlobs),
       };

From 481f560f64806ba3324cf722d6bf8c3f36ac74a5 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Mon, 25 Jan 2016 05:45:44 -0800
Subject: [PATCH 0871/1411] Added support for auto-resizing text fields

Summary:
public
This diff adds support for auto-resizing multiline text fields. This has been a long-requested feature, with several native solutions having been proposed (see https://github.com/facebook/react-native/pull/1229 and D2846915).

Rather than making this a feature of the native component, this diff simply exposes some extra information in the `onChange` event that makes it easy to implement this in pure JS code. I think this is preferable, since it's simpler, works cross-platform, and avoids any controversy about what the API should look like, or how the props should be named. It also makes it easier to implement custom min/max-height logic.

Reviewed By: sahrens

Differential Revision: D2849889

fb-gh-sync-id: d9ddf4ba4037d388dac0558aa467d958300aa691
---
 .../UIExplorer/TextInputExample.android.js    | 37 +++++++++++++++++++
 Examples/UIExplorer/TextInputExample.ios.js   | 37 +++++++++++++++++++
 Libraries/Text/RCTTextView.m                  | 36 +++++++++++++++---
 3 files changed, 105 insertions(+), 5 deletions(-)

diff --git a/Examples/UIExplorer/TextInputExample.android.js b/Examples/UIExplorer/TextInputExample.android.js
index b3f5c6a4e263..6e628f350ae5 100644
--- a/Examples/UIExplorer/TextInputExample.android.js
+++ b/Examples/UIExplorer/TextInputExample.android.js
@@ -72,6 +72,29 @@ var TextEventsExample = React.createClass({
   }
 });
 
+class AutoExpandingTextInput extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {text: '', height: 0};
+  }
+  render() {
+    return (
+      <TextInput
+        {...this.props}
+        multiline={true}
+        onChange={(event) => {
+          this.setState({
+            text: event.nativeEvent.text,
+            height: event.nativeEvent.contentSize.height,
+          });
+        }}
+        style={[styles.default, {height: Math.max(35, this.state.height)}]}
+        value={this.state.text}
+      />
+    );
+  }
+}
+
 class RewriteExample extends React.Component {
   constructor(props) {
     super(props);
@@ -385,6 +408,20 @@ exports.examples = [
       );
     }
   },
+  {
+    title: 'Auto-expanding',
+    render: function() {
+      return (
+        <View>
+          <AutoExpandingTextInput
+            placeholder="height increases with content"
+            enablesReturnKeyAutomatically={true}
+            returnKeyType="done"
+          />
+        </View>
+      );
+    }
+  },
   {
     title: 'Attributed text',
     render: function() {
diff --git a/Examples/UIExplorer/TextInputExample.ios.js b/Examples/UIExplorer/TextInputExample.ios.js
index 486cf411bfb1..49079ff8b917 100644
--- a/Examples/UIExplorer/TextInputExample.ios.js
+++ b/Examples/UIExplorer/TextInputExample.ios.js
@@ -96,6 +96,29 @@ var TextEventsExample = React.createClass({
   }
 });
 
+class AutoExpandingTextInput extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {text: '', height: 0};
+  }
+  render() {
+    return (
+      <TextInput
+        {...this.props}
+        multiline={true}
+        onChange={(event) => {
+          this.setState({
+            text: event.nativeEvent.text,
+            height: event.nativeEvent.contentSize.height,
+          });
+        }}
+        style={[styles.default, {height: Math.max(35, this.state.height)}]}
+        value={this.state.text}
+      />
+    );
+  }
+}
+
 class RewriteExample extends React.Component {
   constructor(props) {
     super(props);
@@ -630,6 +653,20 @@ exports.examples = [
       );
     }
   },
+  {
+    title: 'Auto-expanding',
+    render: function() {
+      return (
+        <View>
+          <AutoExpandingTextInput
+            placeholder="height increases with content"
+            enablesReturnKeyAutomatically={true}
+            returnKeyType="done"
+          />
+        </View>
+      );
+    }
+  },
   {
     title: 'Attributed text',
     render: function() {
diff --git a/Libraries/Text/RCTTextView.m b/Libraries/Text/RCTTextView.m
index ed1acffde4c9..b9c6a74b22d4 100644
--- a/Libraries/Text/RCTTextView.m
+++ b/Libraries/Text/RCTTextView.m
@@ -61,6 +61,8 @@ @implementation RCTTextView
   NSMutableArray<UIView *> *_subviews;
   BOOL _blockTextShouldChange;
   UITextRange *_previousSelectionRange;
+  NSUInteger _previousTextLength;
+  CGFloat _previousContentHeight;
   UIScrollView *_scrollView;
 }
 
@@ -437,12 +439,36 @@ - (void)textViewDidChange:(UITextView *)textView
   [self updateContentSize];
   [self _setPlaceholderVisibility];
   _nativeEventCount++;
-  [_eventDispatcher sendTextEventWithType:RCTTextEventTypeChange
-                                 reactTag:self.reactTag
-                                     text:textView.text
-                                      key:nil
-                               eventCount:_nativeEventCount];
 
+  if (!self.reactTag) {
+    return;
+  }
+
+  // When the context size increases, iOS updates the contentSize twice; once
+  // with a lower height, then again with the correct height. To prevent a
+  // spurious event from being sent, we track the previous, and only send the
+  // update event if it matches our expectation that greater text length
+  // should result in increased height. This assumption is, of course, not
+  // necessarily true because shorter text might include more linebreaks, but
+  // in practice this works well enough.
+  NSUInteger textLength = textView.text.length;
+  CGFloat contentHeight = textView.contentSize.height;
+  if (textLength >= _previousTextLength) {
+    contentHeight = MAX(contentHeight, _previousContentHeight);
+  }
+  _previousTextLength = textLength;
+  _previousContentHeight = contentHeight;
+
+  NSDictionary *event = @{
+    @"text": self.text,
+    @"contentSize": @{
+      @"height": @(contentHeight),
+      @"width": @(textView.contentSize.width)
+    },
+    @"target": self.reactTag,
+    @"eventCount": @(_nativeEventCount),
+  };
+  [_eventDispatcher sendInputEventWithName:@"change" body:event];
 }
 
 - (void)textViewDidEndEditing:(UITextView *)textView

From c95d74ac094ffc6dfce17e4c9bebf0af08e12cca Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Mon, 25 Jan 2016 05:55:06 -0800
Subject: [PATCH 0872/1411] Less Catalyst, more React

Summary:
Catalyst is the old project name. Rename a few files.

public

Reviewed By: bestander

Differential Revision: D2859553

fb-gh-sync-id: 65a87cc7bcc22f20326971becec02aa1c573e5b9
---
 .../react/testing/ReactTestHelper.java        |  4 +-
 .../react/ReactInstanceManagerImpl.java       |  4 +-
 .../react/bridge/CatalystInstance.java        |  6 +-
 .../react/bridge/CatalystInstanceImpl.java    | 56 +++++++++----------
 .../facebook/react/bridge/ReactContext.java   |  4 +-
 ...tion.java => ReactQueueConfiguration.java} |  2 +-
 ....java => ReactQueueConfigurationImpl.java} | 10 ++--
 ....java => ReactQueueConfigurationSpec.java} | 12 ++--
 .../processing/ReactPropertyProcessor.java    |  2 +-
 .../react/touch/JSResponderHandler.java       |  2 +-
 ...p.java => ReactInterceptingViewGroup.java} |  2 +-
 .../uimanager/NativeViewHierarchyManager.java |  4 +-
 .../NativeViewHierarchyOptimizer.java         |  8 +--
 .../react/uimanager/ReactShadowNode.java      |  2 +-
 ...esDiffMap.java => ReactStylesDiffMap.java} |  4 +-
 .../react/uimanager/UIImplementation.java     | 10 ++--
 .../react/uimanager/UIViewOperationQueue.java | 12 ++--
 .../facebook/react/uimanager/ViewManager.java |  8 +--
 .../uimanager/ViewManagerPropertyUpdater.java | 12 ++--
 .../uimanager/ViewManagersPropertyCache.java  | 24 ++++----
 .../views/art/ARTRenderableViewManager.java   |  2 +-
 .../react/views/art/ARTVirtualNode.java       |  2 +-
 .../facebook/react/views/art/PropHelper.java  |  2 +-
 .../react/views/text/ReactRawTextManager.java |  2 +-
 .../views/view/ReactClippingViewGroup.java    |  4 +-
 .../view/ReactClippingViewGroupHelper.java    |  2 +-
 .../view/ReactViewBackgroundDrawable.java     |  2 +-
 .../react/views/view/ReactViewGroup.java      |  4 +-
 .../react/bridge/ReactTestHelper.java         | 14 ++---
 website/src/react-native/index.js             |  2 +-
 30 files changed, 112 insertions(+), 112 deletions(-)
 rename ReactAndroid/src/main/java/com/facebook/react/bridge/queue/{CatalystQueueConfiguration.java => ReactQueueConfiguration.java} (95%)
 rename ReactAndroid/src/main/java/com/facebook/react/bridge/queue/{CatalystQueueConfigurationImpl.java => ReactQueueConfigurationImpl.java} (89%)
 rename ReactAndroid/src/main/java/com/facebook/react/bridge/queue/{CatalystQueueConfigurationSpec.java => ReactQueueConfigurationSpec.java} (87%)
 rename ReactAndroid/src/main/java/com/facebook/react/touch/{CatalystInterceptingViewGroup.java => ReactInterceptingViewGroup.java} (96%)
 rename ReactAndroid/src/main/java/com/facebook/react/uimanager/{CatalystStylesDiffMap.java => ReactStylesDiffMap.java} (97%)

diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java
index 5b9949ade916..ff23f1f2325a 100644
--- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java
@@ -18,7 +18,7 @@
 import com.facebook.react.bridge.NativeModule;
 import com.facebook.react.bridge.NativeModuleRegistry;
 import com.facebook.react.bridge.JavaScriptModulesConfig;
-import com.facebook.react.bridge.queue.CatalystQueueConfigurationSpec;
+import com.facebook.react.bridge.queue.ReactQueueConfigurationSpec;
 
 import com.android.internal.util.Predicate;
 
@@ -38,7 +38,7 @@ private ReactInstanceEasyBuilder(ReactIntegrationTestCase testCase) {
 
     public CatalystInstanceImpl build() {
       CatalystInstanceImpl instance = mTestCase.new ReactTestInstanceBuilder()
-          .setCatalystQueueConfigurationSpec(CatalystQueueConfigurationSpec.createDefault())
+          .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
           .setJSExecutor(new JSCJavaScriptExecutor())
           .setRegistry(mNativeModuleRegistryBuilder.build())
           .setJSModulesConfig(mJSModulesConfigBuilder.build())
diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index adb039d7ffee..be9c60688a8b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -46,7 +46,7 @@
 import com.facebook.react.bridge.UiThreadUtil;
 import com.facebook.react.bridge.WritableMap;
 import com.facebook.react.bridge.WritableNativeMap;
-import com.facebook.react.bridge.queue.CatalystQueueConfigurationSpec;
+import com.facebook.react.bridge.queue.ReactQueueConfigurationSpec;
 import com.facebook.react.common.ApplicationHolder;
 import com.facebook.react.common.ReactConstants;
 import com.facebook.react.common.annotations.VisibleForTesting;
@@ -711,7 +711,7 @@ private ReactApplicationContext createReactContext(
         ? mNativeModuleCallExceptionHandler
         : mDevSupportManager;
     CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
-        .setCatalystQueueConfigurationSpec(CatalystQueueConfigurationSpec.createDefault())
+        .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
         .setJSExecutor(jsExecutor)
         .setRegistry(nativeModuleRegistry)
         .setJSModulesConfig(javaScriptModulesConfig)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
index c0c98cf799cd..466f229d151d 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
@@ -11,7 +11,7 @@
 
 import java.util.Collection;
 
-import com.facebook.react.bridge.queue.CatalystQueueConfiguration;
+import com.facebook.react.bridge.queue.ReactQueueConfiguration;
 import com.facebook.react.common.annotations.VisibleForTesting;
 import com.facebook.proguard.annotations.DoNotStrip;
 import com.facebook.react.common.annotations.VisibleForTesting;
@@ -29,7 +29,7 @@ public interface CatalystInstance {
   @DoNotStrip
   void invokeCallback(final int callbackID, final NativeArray arguments);
   /**
-   * Destroys this catalyst instance, waiting for any other threads in CatalystQueueConfiguration
+   * Destroys this catalyst instance, waiting for any other threads in ReactQueueConfiguration
    * (besides the UI thread) to finish running. Must be called from the UI thread so that we can
    * fully shut down other threads.
    */
@@ -42,7 +42,7 @@ public interface CatalystInstance {
   @VisibleForTesting
   void initialize();
 
-  CatalystQueueConfiguration getCatalystQueueConfiguration();
+  ReactQueueConfiguration getReactQueueConfiguration();
 
   <T extends JavaScriptModule> T getJSModule(Class<T> jsInterface);
   <T extends NativeModule> T getNativeModule(Class<T> nativeModuleInterface);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
index 01ceb8e8b4b0..d3bcc1abd09a 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
@@ -21,9 +21,9 @@
 import com.facebook.common.logging.FLog;
 import com.facebook.infer.annotation.Assertions;
 import com.facebook.proguard.annotations.DoNotStrip;
-import com.facebook.react.bridge.queue.CatalystQueueConfiguration;
-import com.facebook.react.bridge.queue.CatalystQueueConfigurationImpl;
-import com.facebook.react.bridge.queue.CatalystQueueConfigurationSpec;
+import com.facebook.react.bridge.queue.ReactQueueConfiguration;
+import com.facebook.react.bridge.queue.ReactQueueConfigurationImpl;
+import com.facebook.react.bridge.queue.ReactQueueConfigurationSpec;
 import com.facebook.react.bridge.queue.QueueThreadExceptionHandler;
 import com.facebook.react.common.ReactConstants;
 import com.facebook.react.common.annotations.VisibleForTesting;
@@ -43,7 +43,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
   private static final AtomicInteger sNextInstanceIdForTrace = new AtomicInteger(1);
 
   // Access from any thread
-  private final CatalystQueueConfigurationImpl mCatalystQueueConfiguration;
+  private final ReactQueueConfigurationImpl mReactQueueConfiguration;
   private final CopyOnWriteArrayList<NotThreadSafeBridgeIdleDebugListener> mBridgeIdleListeners;
   private final AtomicInteger mPendingJSCalls = new AtomicInteger(0);
   private final String mJsPendingCallsTitleForTrace =
@@ -64,14 +64,14 @@ public class CatalystInstanceImpl implements CatalystInstance {
   private boolean mJSBundleHasLoaded;
 
   private CatalystInstanceImpl(
-      final CatalystQueueConfigurationSpec catalystQueueConfigurationSpec,
+      final ReactQueueConfigurationSpec ReactQueueConfigurationSpec,
       final JavaScriptExecutor jsExecutor,
       final NativeModuleRegistry registry,
       final JavaScriptModulesConfig jsModulesConfig,
       final JSBundleLoader jsBundleLoader,
       NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
-    mCatalystQueueConfiguration = CatalystQueueConfigurationImpl.create(
-        catalystQueueConfigurationSpec,
+    mReactQueueConfiguration = ReactQueueConfigurationImpl.create(
+        ReactQueueConfigurationSpec,
         new NativeExceptionHandler());
     mBridgeIdleListeners = new CopyOnWriteArrayList<>();
     mJavaRegistry = registry;
@@ -81,7 +81,7 @@ private CatalystInstanceImpl(
     mTraceListener = new JSProfilerTraceListener();
 
     try {
-      mBridge = mCatalystQueueConfiguration.getJSQueueThread().callOnQueue(
+      mBridge = mReactQueueConfiguration.getJSQueueThread().callOnQueue(
           new Callable<ReactBridge>() {
             @Override
             public ReactBridge call() throws Exception {
@@ -101,7 +101,7 @@ public ReactBridge call() throws Exception {
   private ReactBridge initializeBridge(
       JavaScriptExecutor jsExecutor,
       JavaScriptModulesConfig jsModulesConfig) {
-    mCatalystQueueConfiguration.getJSQueueThread().assertIsOnThread();
+    mReactQueueConfiguration.getJSQueueThread().assertIsOnThread();
     Assertions.assertCondition(mBridge == null, "initializeBridge should be called once");
 
     Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ReactBridgeCtor");
@@ -110,7 +110,7 @@ private ReactBridge initializeBridge(
       bridge = new ReactBridge(
           jsExecutor,
           new NativeModulesReactCallback(),
-          mCatalystQueueConfiguration.getNativeModulesQueueThread());
+          mReactQueueConfiguration.getNativeModulesQueueThread());
     } finally {
       Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
     }
@@ -133,7 +133,7 @@ private ReactBridge initializeBridge(
   @Override
   public void runJSBundle() {
     try {
-      mJSBundleHasLoaded = mCatalystQueueConfiguration.getJSQueueThread().callOnQueue(
+      mJSBundleHasLoaded = mReactQueueConfiguration.getJSQueueThread().callOnQueue(
           new Callable<Boolean>() {
             @Override
             public Boolean call() throws Exception {
@@ -179,11 +179,11 @@ public Boolean call() throws Exception {
         tracingName,
         traceID);
 
-    mCatalystQueueConfiguration.getJSQueueThread().runOnQueue(
+    mReactQueueConfiguration.getJSQueueThread().runOnQueue(
         new Runnable() {
           @Override
           public void run() {
-            mCatalystQueueConfiguration.getJSQueueThread().assertIsOnThread();
+            mReactQueueConfiguration.getJSQueueThread().assertIsOnThread();
 
             Systrace.endAsyncFlow(
                 Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
@@ -222,11 +222,11 @@ public void invokeCallback(final int callbackID, final NativeArray arguments) {
         "<callback>",
         traceID);
 
-    mCatalystQueueConfiguration.getJSQueueThread().runOnQueue(
+    mReactQueueConfiguration.getJSQueueThread().runOnQueue(
         new Runnable() {
           @Override
           public void run() {
-            mCatalystQueueConfiguration.getJSQueueThread().assertIsOnThread();
+            mReactQueueConfiguration.getJSQueueThread().assertIsOnThread();
 
             Systrace.endAsyncFlow(
                 Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
@@ -248,7 +248,7 @@ public void run() {
   }
 
   /**
-   * Destroys this catalyst instance, waiting for any other threads in CatalystQueueConfiguration
+   * Destroys this catalyst instance, waiting for any other threads in ReactQueueConfiguration
    * (besides the UI thread) to finish running. Must be called from the UI thread so that we can
    * fully shut down other threads.
    */
@@ -263,7 +263,7 @@ public void destroy() {
     // TODO: tell all APIs to shut down
     mDestroyed = true;
     mJavaRegistry.notifyCatalystInstanceDestroy();
-    mCatalystQueueConfiguration.destroy();
+    mReactQueueConfiguration.destroy();
     boolean wasIdle = (mPendingJSCalls.getAndSet(0) == 0);
     if (!wasIdle && !mBridgeIdleListeners.isEmpty()) {
       for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) {
@@ -274,7 +274,7 @@ public void destroy() {
     Systrace.unregisterListener(mTraceListener);
 
     // We can access the Bridge from any thread now because we know either we are on the JS thread
-    // or the JS thread has finished via CatalystQueueConfiguration#destroy()
+    // or the JS thread has finished via ReactQueueConfiguration#destroy()
     mBridge.dispose();
   }
 
@@ -298,8 +298,8 @@ public void initialize() {
   }
 
   @Override
-  public CatalystQueueConfiguration getCatalystQueueConfiguration() {
-    return mCatalystQueueConfiguration;
+  public ReactQueueConfiguration getReactQueueConfiguration() {
+    return mReactQueueConfiguration;
   }
 
   @Override
@@ -418,7 +418,7 @@ private class NativeModulesReactCallback implements ReactCallback {
 
     @Override
     public void call(int moduleId, int methodId, ReadableNativeArray parameters) {
-      mCatalystQueueConfiguration.getNativeModulesQueueThread().assertIsOnThread();
+      mReactQueueConfiguration.getNativeModulesQueueThread().assertIsOnThread();
 
       // Suppress any callbacks if destroyed - will only lead to sadness.
       if (mDestroyed) {
@@ -430,7 +430,7 @@ public void call(int moduleId, int methodId, ReadableNativeArray parameters) {
 
     @Override
     public void onBatchComplete() {
-      mCatalystQueueConfiguration.getNativeModulesQueueThread().assertIsOnThread();
+      mReactQueueConfiguration.getNativeModulesQueueThread().assertIsOnThread();
 
       // The bridge may have been destroyed due to an exception during the batch. In that case
       // native modules could be in a bad state so we don't want to call anything on them. We
@@ -457,7 +457,7 @@ public void handleException(Exception e) {
       // framework/native code, it was triggered by JS and theoretically since we were able
       // to set up the bridge, JS could change its logic, reload, and not trigger that crash.
       mNativeModuleCallExceptionHandler.handleException(e);
-      mCatalystQueueConfiguration.getUIQueueThread().runOnQueue(
+      mReactQueueConfiguration.getUIQueueThread().runOnQueue(
           new Runnable() {
             @Override
             public void run() {
@@ -481,16 +481,16 @@ public void onTraceStopped() {
 
   public static class Builder {
 
-    private @Nullable CatalystQueueConfigurationSpec mCatalystQueueConfigurationSpec;
+    private @Nullable ReactQueueConfigurationSpec mReactQueueConfigurationSpec;
     private @Nullable JSBundleLoader mJSBundleLoader;
     private @Nullable NativeModuleRegistry mRegistry;
     private @Nullable JavaScriptModulesConfig mJSModulesConfig;
     private @Nullable JavaScriptExecutor mJSExecutor;
     private @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
 
-    public Builder setCatalystQueueConfigurationSpec(
-        CatalystQueueConfigurationSpec catalystQueueConfigurationSpec) {
-      mCatalystQueueConfigurationSpec = catalystQueueConfigurationSpec;
+    public Builder setReactQueueConfigurationSpec(
+        ReactQueueConfigurationSpec ReactQueueConfigurationSpec) {
+      mReactQueueConfigurationSpec = ReactQueueConfigurationSpec;
       return this;
     }
 
@@ -522,7 +522,7 @@ public Builder setNativeModuleCallExceptionHandler(
 
     public CatalystInstanceImpl build() {
       return new CatalystInstanceImpl(
-          Assertions.assertNotNull(mCatalystQueueConfigurationSpec),
+          Assertions.assertNotNull(mReactQueueConfigurationSpec),
           Assertions.assertNotNull(mJSExecutor),
           Assertions.assertNotNull(mRegistry),
           Assertions.assertNotNull(mJSModulesConfig),
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java
index e1632401f460..084ed5c20150 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java
@@ -21,7 +21,7 @@
 import android.view.LayoutInflater;
 
 import com.facebook.infer.annotation.Assertions;
-import com.facebook.react.bridge.queue.CatalystQueueConfiguration;
+import com.facebook.react.bridge.queue.ReactQueueConfiguration;
 import com.facebook.react.bridge.queue.MessageQueueThread;
 
 /**
@@ -60,7 +60,7 @@ public void initializeWithInstance(CatalystInstance catalystInstance) {
 
     mCatalystInstance = catalystInstance;
 
-    CatalystQueueConfiguration queueConfig = catalystInstance.getCatalystQueueConfiguration();
+    ReactQueueConfiguration queueConfig = catalystInstance.getReactQueueConfiguration();
     mUiMessageQueueThread = queueConfig.getUIQueueThread();
     mNativeModulesMessageQueueThread = queueConfig.getNativeModulesQueueThread();
     mJSMessageQueueThread = queueConfig.getJSQueueThread();
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/CatalystQueueConfiguration.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/ReactQueueConfiguration.java
similarity index 95%
rename from ReactAndroid/src/main/java/com/facebook/react/bridge/queue/CatalystQueueConfiguration.java
rename to ReactAndroid/src/main/java/com/facebook/react/bridge/queue/ReactQueueConfiguration.java
index 99fec74857d3..6e40d4ba5c88 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/CatalystQueueConfiguration.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/ReactQueueConfiguration.java
@@ -18,7 +18,7 @@
  * Native Modules Queue Thread: The thread and Looper that native modules are invoked on.
  * JS Queue Thread: The thread and Looper that JS is executed on.
  */
-public interface CatalystQueueConfiguration {
+public interface ReactQueueConfiguration {
   MessageQueueThread getUIQueueThread();
   MessageQueueThread getNativeModulesQueueThread();
   MessageQueueThread getJSQueueThread();
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/CatalystQueueConfigurationImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/ReactQueueConfigurationImpl.java
similarity index 89%
rename from ReactAndroid/src/main/java/com/facebook/react/bridge/queue/CatalystQueueConfigurationImpl.java
rename to ReactAndroid/src/main/java/com/facebook/react/bridge/queue/ReactQueueConfigurationImpl.java
index c6b8be58b0ea..00af88372efc 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/CatalystQueueConfigurationImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/ReactQueueConfigurationImpl.java
@@ -15,13 +15,13 @@
 
 import com.facebook.react.common.MapBuilder;
 
-public class CatalystQueueConfigurationImpl implements CatalystQueueConfiguration {
+public class ReactQueueConfigurationImpl implements ReactQueueConfiguration {
 
   private final MessageQueueThreadImpl mUIQueueThread;
   private final MessageQueueThreadImpl mNativeModulesQueueThread;
   private final MessageQueueThreadImpl mJSQueueThread;
 
-  private CatalystQueueConfigurationImpl(
+  private ReactQueueConfigurationImpl(
       MessageQueueThreadImpl uiQueueThread,
       MessageQueueThreadImpl nativeModulesQueueThread,
       MessageQueueThreadImpl jsQueueThread) {
@@ -58,8 +58,8 @@ public void destroy() {
     }
   }
 
-  public static CatalystQueueConfigurationImpl create(
-      CatalystQueueConfigurationSpec spec,
+  public static ReactQueueConfigurationImpl create(
+      ReactQueueConfigurationSpec spec,
       QueueThreadExceptionHandler exceptionHandler) {
     Map<MessageQueueThreadSpec, MessageQueueThreadImpl> specsToThreads = MapBuilder.newHashMap();
 
@@ -80,6 +80,6 @@ public static CatalystQueueConfigurationImpl create(
           MessageQueueThreadImpl.create(spec.getNativeModulesQueueThreadSpec(), exceptionHandler);
     }
 
-    return new CatalystQueueConfigurationImpl(uiThread, nativeModulesThread, jsThread);
+    return new ReactQueueConfigurationImpl(uiThread, nativeModulesThread, jsThread);
   }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/CatalystQueueConfigurationSpec.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/ReactQueueConfigurationSpec.java
similarity index 87%
rename from ReactAndroid/src/main/java/com/facebook/react/bridge/queue/CatalystQueueConfigurationSpec.java
rename to ReactAndroid/src/main/java/com/facebook/react/bridge/queue/ReactQueueConfigurationSpec.java
index c5eb9ad68593..aceeba6aa9ca 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/CatalystQueueConfigurationSpec.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/ReactQueueConfigurationSpec.java
@@ -14,17 +14,17 @@
 import com.facebook.infer.annotation.Assertions;
 
 /**
- * Spec for creating a CatalystQueueConfiguration. This exists so that CatalystInstance is able to
+ * Spec for creating a ReactQueueConfiguration. This exists so that CatalystInstance is able to
  * set Exception handlers on the MessageQueueThreads it uses and it would not be super clean if the
  * threads were configured, then passed to CatalystInstance where they are configured more. These
  * specs allows the Threads to be created fully configured.
  */
-public class CatalystQueueConfigurationSpec {
+public class ReactQueueConfigurationSpec {
 
   private final MessageQueueThreadSpec mNativeModulesQueueThreadSpec;
   private final MessageQueueThreadSpec mJSQueueThreadSpec;
 
-  private CatalystQueueConfigurationSpec(
+  private ReactQueueConfigurationSpec(
       MessageQueueThreadSpec nativeModulesQueueThreadSpec,
       MessageQueueThreadSpec jsQueueThreadSpec) {
     mNativeModulesQueueThreadSpec = nativeModulesQueueThreadSpec;
@@ -43,7 +43,7 @@ public static Builder builder() {
     return new Builder();
   }
 
-  public static CatalystQueueConfigurationSpec createDefault() {
+  public static ReactQueueConfigurationSpec createDefault() {
     return builder()
         .setJSQueueThreadSpec(MessageQueueThreadSpec.newBackgroundThreadSpec("js"))
         .setNativeModulesQueueThreadSpec(
@@ -70,8 +70,8 @@ public Builder setJSQueueThreadSpec(MessageQueueThreadSpec spec) {
       return this;
     }
 
-    public CatalystQueueConfigurationSpec build() {
-      return new CatalystQueueConfigurationSpec(
+    public ReactQueueConfigurationSpec build() {
+      return new ReactQueueConfigurationSpec(
           Assertions.assertNotNull(mNativeModulesQueueSpec),
           Assertions.assertNotNull(mJSQueueSpec));
     }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/processing/ReactPropertyProcessor.java b/ReactAndroid/src/main/java/com/facebook/react/processing/ReactPropertyProcessor.java
index bffd3f5dffa5..bc18bf862fe4 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/processing/ReactPropertyProcessor.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/processing/ReactPropertyProcessor.java
@@ -64,7 +64,7 @@ public class ReactPropertyProcessor extends AbstractProcessor {
   private static final Set<TypeName> BOXED_PRIMITIVES;
 
   private static final TypeName PROPS_TYPE =
-      ClassName.get("com.facebook.react.uimanager", "CatalystStylesDiffMap");
+      ClassName.get("com.facebook.react.uimanager", "ReactStylesDiffMap");
   private static final TypeName STRING_TYPE = TypeName.get(String.class);
   private static final TypeName READABLE_MAP_TYPE = TypeName.get(ReadableMap.class);
   private static final TypeName READABLE_ARRAY_TYPE = TypeName.get(ReadableArray.class);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/touch/JSResponderHandler.java b/ReactAndroid/src/main/java/com/facebook/react/touch/JSResponderHandler.java
index 2e8ba61f2292..7140e2c303fe 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/touch/JSResponderHandler.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/touch/JSResponderHandler.java
@@ -18,7 +18,7 @@
 /**
  * This class coordinates JSResponder commands for {@link UIManagerModule}. It should be set as
  * OnInterceptTouchEventListener for all newly created native views that implements
- * {@link CatalystInterceptingViewGroup} and thanks to the information whether JSResponder is set
+ * {@link ReactInterceptingViewGroup} and thanks to the information whether JSResponder is set
  * and to which view it will correctly coordinate the return values of
  * {@link OnInterceptTouchEventListener} such that touch events will be dispatched to the view
  * selected by JS gesture recognizer.
diff --git a/ReactAndroid/src/main/java/com/facebook/react/touch/CatalystInterceptingViewGroup.java b/ReactAndroid/src/main/java/com/facebook/react/touch/ReactInterceptingViewGroup.java
similarity index 96%
rename from ReactAndroid/src/main/java/com/facebook/react/touch/CatalystInterceptingViewGroup.java
rename to ReactAndroid/src/main/java/com/facebook/react/touch/ReactInterceptingViewGroup.java
index 6bc10f034a3b..d7b919b7f18e 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/touch/CatalystInterceptingViewGroup.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/touch/ReactInterceptingViewGroup.java
@@ -16,7 +16,7 @@
  * which then is used to control touch event flow in cases in which they requested to be intercepted
  * by some parent view based on a JS gesture detector.
  */
-public interface CatalystInterceptingViewGroup {
+public interface ReactInterceptingViewGroup {
 
   /**
    * A {@link ViewGroup} instance that implement this interface is responsible for storing the
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
index e5e79eaf2a1e..aada76ee9143 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
@@ -106,7 +106,7 @@ public void setLayoutAnimationEnabled(boolean enabled) {
     mLayoutAnimationEnabled = enabled;
   }
 
-  public void updateProperties(int tag, CatalystStylesDiffMap props) {
+  public void updateProperties(int tag, ReactStylesDiffMap props) {
     UiThreadUtil.assertOnUiThread();
 
     ViewManager viewManager = resolveViewManager(tag);
@@ -190,7 +190,7 @@ public void createView(
       ThemedReactContext themedContext,
       int tag,
       String className,
-      @Nullable CatalystStylesDiffMap initialProps) {
+      @Nullable ReactStylesDiffMap initialProps) {
     UiThreadUtil.assertOnUiThread();
     SystraceMessage.beginSection(
         Systrace.TRACE_TAG_REACT_VIEW,
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java
index ef3c2c8484bb..1297cc7e37e9 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyOptimizer.java
@@ -70,7 +70,7 @@ public NativeViewHierarchyOptimizer(
   public void handleCreateView(
       ReactShadowNode node,
       ThemedReactContext themedContext,
-      @Nullable CatalystStylesDiffMap initialProps) {
+      @Nullable ReactStylesDiffMap initialProps) {
     if (!ENABLED) {
       int tag = node.getReactTag();
       mUIViewOperationQueue.enqueueCreateView(
@@ -109,7 +109,7 @@ public static void handleRemoveNode(ReactShadowNode node) {
   public void handleUpdateView(
       ReactShadowNode node,
       String className,
-      CatalystStylesDiffMap props) {
+      ReactStylesDiffMap props) {
     if (!ENABLED) {
       mUIViewOperationQueue.enqueueUpdateProperties(node.getReactTag(), className, props);
       return;
@@ -377,7 +377,7 @@ private void applyLayoutRecursive(ReactShadowNode toUpdate, int x, int y) {
 
   private void transitionLayoutOnlyViewToNativeView(
       ReactShadowNode node,
-      @Nullable CatalystStylesDiffMap props) {
+      @Nullable ReactStylesDiffMap props) {
     ReactShadowNode parent = node.getParent();
     if (parent == null) {
       node.setIsLayoutOnly(false);
@@ -419,7 +419,7 @@ private void transitionLayoutOnlyViewToNativeView(
     mTagsWithLayoutVisited.clear();
   }
 
-  private static boolean isLayoutOnlyAndCollapsable(@Nullable CatalystStylesDiffMap props) {
+  private static boolean isLayoutOnlyAndCollapsable(@Nullable ReactStylesDiffMap props) {
     if (props == null) {
       return true;
     }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java
index de9ca3cf65a3..eb287bef45a1 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java
@@ -168,7 +168,7 @@ private void updateNativeChildrenCountInParent(int delta) {
   public void onBeforeLayout() {
   }
 
-  public final void updateProperties(CatalystStylesDiffMap props) {
+  public final void updateProperties(ReactStylesDiffMap props) {
     ViewManagerPropertyUpdater.updateProps(this, props);
     onAfterUpdateTransaction();
   }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/CatalystStylesDiffMap.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactStylesDiffMap.java
similarity index 97%
rename from ReactAndroid/src/main/java/com/facebook/react/uimanager/CatalystStylesDiffMap.java
rename to ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactStylesDiffMap.java
index e2a01ea62782..2259abb3101d 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/CatalystStylesDiffMap.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactStylesDiffMap.java
@@ -34,11 +34,11 @@
  * property shouldn't be updated (whereas in all other cases it should be updated to the new value
  * or the property should be reset).
  */
-public class CatalystStylesDiffMap {
+public class ReactStylesDiffMap {
 
   /* package */ final ReadableMap mBackingMap;
 
-  public CatalystStylesDiffMap(ReadableMap props) {
+  public ReactStylesDiffMap(ReadableMap props) {
     mBackingMap = props;
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
index 5fb38cf9796a..95cd4756e2d9 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
@@ -141,9 +141,9 @@ public void createView(int tag, String className, int rootViewTag, ReadableMap p
 
     mShadowNodeRegistry.addNode(cssNode);
 
-    CatalystStylesDiffMap styles = null;
+    ReactStylesDiffMap styles = null;
     if (props != null) {
-      styles = new CatalystStylesDiffMap(props);
+      styles = new ReactStylesDiffMap(props);
       cssNode.updateProperties(styles);
     }
 
@@ -153,7 +153,7 @@ public void createView(int tag, String className, int rootViewTag, ReadableMap p
   protected void handleCreateView(
       ReactShadowNode cssNode,
       int rootViewTag,
-      @Nullable CatalystStylesDiffMap styles) {
+      @Nullable ReactStylesDiffMap styles) {
     if (!cssNode.isVirtual()) {
       mNativeViewHierarchyOptimizer.handleCreateView(cssNode, cssNode.getThemedContext(), styles);
     }
@@ -173,7 +173,7 @@ public void updateView(int tag, String className, ReadableMap props) {
     }
 
     if (props != null) {
-      CatalystStylesDiffMap styles = new CatalystStylesDiffMap(props);
+      ReactStylesDiffMap styles = new ReactStylesDiffMap(props);
       cssNode.updateProperties(styles);
       handleUpdateView(cssNode, className, styles);
     }
@@ -182,7 +182,7 @@ public void updateView(int tag, String className, ReadableMap props) {
   protected void handleUpdateView(
       ReactShadowNode cssNode,
       String className,
-      CatalystStylesDiffMap styles) {
+      ReactStylesDiffMap styles) {
     if (!cssNode.isVirtual()) {
       mNativeViewHierarchyOptimizer.handleUpdateView(cssNode, className, styles);
     }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
index ac2798333609..104e247b5e6c 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
@@ -78,9 +78,9 @@ public void execute() {
 
   private final class UpdatePropertiesOperation extends ViewOperation {
 
-    private final CatalystStylesDiffMap mProps;
+    private final ReactStylesDiffMap mProps;
 
-    private UpdatePropertiesOperation(int tag, CatalystStylesDiffMap props) {
+    private UpdatePropertiesOperation(int tag, ReactStylesDiffMap props) {
       super(tag);
       mProps = props;
     }
@@ -127,13 +127,13 @@ private final class CreateViewOperation extends ViewOperation {
 
     private final ThemedReactContext mThemedContext;
     private final String mClassName;
-    private final @Nullable CatalystStylesDiffMap mInitialProps;
+    private final @Nullable ReactStylesDiffMap mInitialProps;
 
     public CreateViewOperation(
         ThemedReactContext themedContext,
         int tag,
         String className,
-        @Nullable CatalystStylesDiffMap initialProps) {
+        @Nullable ReactStylesDiffMap initialProps) {
       super(tag);
       mThemedContext = themedContext;
       mClassName = className;
@@ -567,7 +567,7 @@ public void enqueueCreateView(
       ThemedReactContext themedContext,
       int viewReactTag,
       String viewClassName,
-      @Nullable CatalystStylesDiffMap initialProps) {
+      @Nullable ReactStylesDiffMap initialProps) {
     mOperations.add(
         new CreateViewOperation(
             themedContext,
@@ -576,7 +576,7 @@ public void enqueueCreateView(
             initialProps));
   }
 
-  public void enqueueUpdateProperties(int reactTag, String className, CatalystStylesDiffMap props) {
+  public void enqueueUpdateProperties(int reactTag, String className, ReactStylesDiffMap props) {
     mOperations.add(new UpdatePropertiesOperation(reactTag, props));
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java
index ca9fd66d3fe0..fdfaed32fdb3 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java
@@ -16,7 +16,7 @@
 import android.view.View;
 
 import com.facebook.react.bridge.ReadableArray;
-import com.facebook.react.touch.CatalystInterceptingViewGroup;
+import com.facebook.react.touch.ReactInterceptingViewGroup;
 import com.facebook.react.touch.JSResponderHandler;
 import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.annotations.ReactPropGroup;
@@ -30,7 +30,7 @@
 @ReactPropertyHolder
 public abstract class ViewManager<T extends View, C extends ReactShadowNode> {
 
-  public final void updateProperties(T viewToUpdate, CatalystStylesDiffMap props) {
+  public final void updateProperties(T viewToUpdate, ReactStylesDiffMap props) {
     ViewManagerPropertyUpdater.updateProps(this, viewToUpdate, props);
     onAfterUpdateTransaction(viewToUpdate);
   }
@@ -43,8 +43,8 @@ public final T createView(
       JSResponderHandler jsResponderHandler) {
     T view = createViewInstance(reactContext);
     addEventEmitters(reactContext, view);
-    if (view instanceof CatalystInterceptingViewGroup) {
-      ((CatalystInterceptingViewGroup) view).setOnInterceptTouchEventListener(jsResponderHandler);
+    if (view instanceof ReactInterceptingViewGroup) {
+      ((ReactInterceptingViewGroup) view).setOnInterceptTouchEventListener(jsResponderHandler);
     }
     return view;
   }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerPropertyUpdater.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerPropertyUpdater.java
index 9c8bdc5e5d3a..b88bc1828a30 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerPropertyUpdater.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerPropertyUpdater.java
@@ -17,11 +17,11 @@ public interface Settable {
   }
 
   public interface ViewManagerSetter<T extends ViewManager, V extends View> extends Settable {
-    void setProperty(T manager, V view, String name, CatalystStylesDiffMap props);
+    void setProperty(T manager, V view, String name, ReactStylesDiffMap props);
   }
 
   public interface ShadowNodeSetter<T extends ReactShadowNode> extends Settable {
-    void setProperty(T node, String name, CatalystStylesDiffMap props);
+    void setProperty(T node, String name, ReactStylesDiffMap props);
   }
 
   private static final String TAG = "ViewManagerPropertyUpdater";
@@ -33,7 +33,7 @@ public interface ShadowNodeSetter<T extends ReactShadowNode> extends Settable {
   public static <T extends ViewManager, V extends View> void updateProps(
       T manager,
       V v,
-      CatalystStylesDiffMap props) {
+      ReactStylesDiffMap props) {
     ViewManagerSetter<T, V> setter = findManagerSetter(manager.getClass());
     ReadableMap propMap = props.mBackingMap;
     ReadableMapKeySetIterator iterator = propMap.keySetIterator();
@@ -43,7 +43,7 @@ public static <T extends ViewManager, V extends View> void updateProps(
     }
   }
 
-  public static <T extends ReactShadowNode> void updateProps(T node, CatalystStylesDiffMap props) {
+  public static <T extends ReactShadowNode> void updateProps(T node, ReactStylesDiffMap props) {
     ShadowNodeSetter<T> setter = findNodeSetter(node.getClass());
     ReadableMap propMap = props.mBackingMap;
     ReadableMapKeySetIterator iterator = propMap.keySetIterator();
@@ -117,7 +117,7 @@ private FallbackViewManagerSetter(Class<? extends ViewManager> viewManagerClass)
     }
 
     @Override
-    public void setProperty(T manager, V v, String name, CatalystStylesDiffMap props) {
+    public void setProperty(T manager, V v, String name, ReactStylesDiffMap props) {
       ViewManagersPropertyCache.PropSetter setter = mPropSetters.get(name);
       if (setter != null) {
         setter.updateViewProp(manager, v, props);
@@ -144,7 +144,7 @@ private FallbackShadowNodeSetter(Class<? extends ReactShadowNode> shadowNodeClas
     }
 
     @Override
-    public void setProperty(ReactShadowNode node, String name, CatalystStylesDiffMap props) {
+    public void setProperty(ReactShadowNode node, String name, ReactStylesDiffMap props) {
       ViewManagersPropertyCache.PropSetter setter = mPropSetters.get(name);
       if (setter != null) {
         setter.updateShadowNodeProp(node, props);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagersPropertyCache.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagersPropertyCache.java
index ea1af2e550f4..063c999daedd 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagersPropertyCache.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagersPropertyCache.java
@@ -69,7 +69,7 @@ public String getPropType() {
     public void updateViewProp(
         ViewManager viewManager,
         View viewToUpdate,
-        CatalystStylesDiffMap props) {
+        ReactStylesDiffMap props) {
       try {
         if (mIndex == null) {
           VIEW_MGR_ARGS[0] = viewToUpdate;
@@ -92,7 +92,7 @@ public void updateViewProp(
 
     public void updateShadowNodeProp(
         ReactShadowNode nodeToUpdate,
-        CatalystStylesDiffMap props) {
+        ReactStylesDiffMap props) {
       try {
         if (mIndex == null) {
           SHADOW_ARGS[0] = extractProperty(props);
@@ -111,7 +111,7 @@ public void updateShadowNodeProp(
       }
     }
 
-    protected abstract @Nullable Object extractProperty(CatalystStylesDiffMap props);
+    protected abstract @Nullable Object extractProperty(ReactStylesDiffMap props);
   }
 
   private static class IntPropSetter extends PropSetter {
@@ -129,7 +129,7 @@ public IntPropSetter(ReactPropGroup prop, Method setter, int index, int defaultV
     }
 
     @Override
-    protected Object extractProperty(CatalystStylesDiffMap props) {
+    protected Object extractProperty(ReactStylesDiffMap props) {
       return props.getInt(mPropName, mDefaultValue);
     }
   }
@@ -149,7 +149,7 @@ public DoublePropSetter(ReactPropGroup prop, Method setter, int index, double de
     }
 
     @Override
-    protected Object extractProperty(CatalystStylesDiffMap props) {
+    protected Object extractProperty(ReactStylesDiffMap props) {
       return props.getDouble(mPropName, mDefaultValue);
     }
   }
@@ -164,7 +164,7 @@ public BooleanPropSetter(ReactProp prop, Method setter, boolean defaultValue) {
     }
 
     @Override
-    protected Object extractProperty(CatalystStylesDiffMap props) {
+    protected Object extractProperty(ReactStylesDiffMap props) {
       return props.getBoolean(mPropName, mDefaultValue) ? Boolean.TRUE : Boolean.FALSE;
     }
   }
@@ -184,7 +184,7 @@ public FloatPropSetter(ReactPropGroup prop, Method setter, int index, float defa
     }
 
     @Override
-    protected Object extractProperty(CatalystStylesDiffMap props) {
+    protected Object extractProperty(ReactStylesDiffMap props) {
       return props.getFloat(mPropName, mDefaultValue);
     }
   }
@@ -196,7 +196,7 @@ public ArrayPropSetter(ReactProp prop, Method setter) {
     }
 
     @Override
-    protected @Nullable Object extractProperty(CatalystStylesDiffMap props) {
+    protected @Nullable Object extractProperty(ReactStylesDiffMap props) {
       return props.getArray(mPropName);
     }
   }
@@ -208,7 +208,7 @@ public MapPropSetter(ReactProp prop, Method setter) {
     }
 
     @Override
-    protected @Nullable Object extractProperty(CatalystStylesDiffMap props) {
+    protected @Nullable Object extractProperty(ReactStylesDiffMap props) {
       return props.getMap(mPropName);
     }
   }
@@ -220,7 +220,7 @@ public StringPropSetter(ReactProp prop, Method setter) {
     }
 
     @Override
-    protected @Nullable Object extractProperty(CatalystStylesDiffMap props) {
+    protected @Nullable Object extractProperty(ReactStylesDiffMap props) {
       return props.getString(mPropName);
     }
   }
@@ -232,7 +232,7 @@ public BoxedBooleanPropSetter(ReactProp prop, Method setter) {
     }
 
     @Override
-    protected @Nullable Object extractProperty(CatalystStylesDiffMap props) {
+    protected @Nullable Object extractProperty(ReactStylesDiffMap props) {
       if (!props.isNull(mPropName)) {
         return props.getBoolean(mPropName, /* ignored */ false) ? Boolean.TRUE : Boolean.FALSE;
       }
@@ -251,7 +251,7 @@ public BoxedIntPropSetter(ReactPropGroup prop, Method setter, int index) {
     }
 
     @Override
-    protected @Nullable Object extractProperty(CatalystStylesDiffMap props) {
+    protected @Nullable Object extractProperty(ReactStylesDiffMap props) {
       if (!props.isNull(mPropName)) {
         return props.getInt(mPropName, /* ignored */ 0);
       }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTRenderableViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTRenderableViewManager.java
index bd6a7df907c8..44ba41ba6303 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTRenderableViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTRenderableViewManager.java
@@ -11,7 +11,7 @@
 
 import android.view.View;
 
-import com.facebook.react.uimanager.CatalystStylesDiffMap;
+import com.facebook.react.uimanager.ReactStylesDiffMap;
 import com.facebook.react.uimanager.ReactShadowNode;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.ViewManager;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTVirtualNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTVirtualNode.java
index 5027c5cbdbdd..289ad0b98515 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTVirtualNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTVirtualNode.java
@@ -17,7 +17,7 @@
 
 import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
 import com.facebook.react.bridge.ReadableArray;
-import com.facebook.react.uimanager.CatalystStylesDiffMap;
+import com.facebook.react.uimanager.ReactStylesDiffMap;
 import com.facebook.react.uimanager.DisplayMetricsHolder;
 import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.ReactShadowNode;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/PropHelper.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/PropHelper.java
index b8bc6246a12e..04497fc4d88d 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/art/PropHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/PropHelper.java
@@ -12,7 +12,7 @@
 import javax.annotation.Nullable;
 
 import com.facebook.react.bridge.ReadableArray;
-import com.facebook.react.uimanager.CatalystStylesDiffMap;
+import com.facebook.react.uimanager.ReactStylesDiffMap;
 
 /**
  * Contains static helper methods for accessing props.
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactRawTextManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactRawTextManager.java
index 9635adfcd8b6..aa71c74b9ff0 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactRawTextManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactRawTextManager.java
@@ -10,7 +10,7 @@
 package com.facebook.react.views.text;
 
 import com.facebook.react.common.annotations.VisibleForTesting;
-import com.facebook.react.uimanager.CatalystStylesDiffMap;
+import com.facebook.react.uimanager.ReactStylesDiffMap;
 import com.facebook.react.uimanager.ThemedReactContext;
 
 /**
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactClippingViewGroup.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactClippingViewGroup.java
index af73bda94c10..37482c2bce7f 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactClippingViewGroup.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactClippingViewGroup.java
@@ -12,7 +12,7 @@
 import android.graphics.Rect;
 import android.view.View;
 
-import com.facebook.react.uimanager.CatalystStylesDiffMap;
+import com.facebook.react.uimanager.ReactStylesDiffMap;
 
 /**
  * Interface that should be implemented by {@link View} subclasses that support
@@ -52,7 +52,7 @@ public interface ReactClippingViewGroup {
    *
    * Helper method {@link ReactClippingViewGroupHelper#applyRemoveClippedSubviewsProperty} may be
    * used by {@link ViewManager} subclass to apply this property based on property update map
-   * {@link CatalystStylesDiffMap}.
+   * {@link ReactStylesDiffMap}.
    */
   void setRemoveClippedSubviews(boolean removeClippedSubviews);
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactClippingViewGroupHelper.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactClippingViewGroupHelper.java
index 1345bdd89188..0751b9f7a19b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactClippingViewGroupHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactClippingViewGroupHelper.java
@@ -15,7 +15,7 @@
 import android.view.View;
 import android.view.ViewParent;
 
-import com.facebook.react.uimanager.CatalystStylesDiffMap;
+import com.facebook.react.uimanager.ReactStylesDiffMap;
 
 /**
  * Provides implementation of common tasks for view and it's view manager supporting property
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java
index 6ded1123d4b6..f36f70db7f46 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java
@@ -315,7 +315,7 @@ private int getBorderWidth(int position) {
   }
 
   private int getBorderColor(int position) {
-    // Check CatalystStylesDiffMap#getColorInt() to see why this is needed
+    // Check ReactStylesDiffMap#getColorInt() to see why this is needed
     return mBorderColor != null ? (int) (long) mBorderColor.get(position) : DEFAULT_BORDER_COLOR;
   }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
index 478208fab215..b52399c82f3a 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
@@ -23,7 +23,7 @@
 
 import com.facebook.infer.annotation.Assertions;
 import com.facebook.react.common.annotations.VisibleForTesting;
-import com.facebook.react.touch.CatalystInterceptingViewGroup;
+import com.facebook.react.touch.ReactInterceptingViewGroup;
 import com.facebook.react.touch.OnInterceptTouchEventListener;
 import com.facebook.react.uimanager.MeasureSpecAssertions;
 import com.facebook.react.uimanager.PointerEvents;
@@ -34,7 +34,7 @@
  * initializes most of the storage needed for them.
  */
 public class ReactViewGroup extends ViewGroup implements
-    CatalystInterceptingViewGroup, ReactClippingViewGroup, ReactPointerEventsView {
+    ReactInterceptingViewGroup, ReactClippingViewGroup, ReactPointerEventsView {
 
   private static final int ARRAY_CAPACITY_INCREMENT = 12;
   private static final int DEFAULT_BACKGROUND_COLOR = Color.TRANSPARENT;
diff --git a/ReactAndroid/src/test/java/com/facebook/react/bridge/ReactTestHelper.java b/ReactAndroid/src/test/java/com/facebook/react/bridge/ReactTestHelper.java
index 0aa236ddb9f6..1886a481b3dc 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/bridge/ReactTestHelper.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/bridge/ReactTestHelper.java
@@ -9,9 +9,9 @@
 
 package com.facebook.react.bridge;
 
-import com.facebook.react.bridge.queue.CatalystQueueConfiguration;
-import com.facebook.react.bridge.queue.CatalystQueueConfigurationImpl;
-import com.facebook.react.bridge.queue.CatalystQueueConfigurationSpec;
+import com.facebook.react.bridge.queue.ReactQueueConfiguration;
+import com.facebook.react.bridge.queue.ReactQueueConfigurationImpl;
+import com.facebook.react.bridge.queue.ReactQueueConfigurationSpec;
 import com.facebook.react.bridge.queue.MessageQueueThreadSpec;
 import com.facebook.react.bridge.queue.QueueThreadExceptionHandler;
 import com.facebook.react.uimanager.UIManagerModule;
@@ -38,14 +38,14 @@ public static ReactApplicationContext createCatalystContextForTest() {
   }
 
   /**
-   * @return a CatalystInstance mock that has a default working CatalystQueueConfiguration.
+   * @return a CatalystInstance mock that has a default working ReactQueueConfiguration.
    */
   public static CatalystInstance createMockCatalystInstance() {
-    CatalystQueueConfigurationSpec spec = CatalystQueueConfigurationSpec.builder()
+    ReactQueueConfigurationSpec spec = ReactQueueConfigurationSpec.builder()
         .setJSQueueThreadSpec(MessageQueueThreadSpec.mainThreadSpec())
         .setNativeModulesQueueThreadSpec(MessageQueueThreadSpec.mainThreadSpec())
         .build();
-    CatalystQueueConfiguration catalystQueueConfiguration = CatalystQueueConfigurationImpl.create(
+    ReactQueueConfiguration ReactQueueConfiguration = ReactQueueConfigurationImpl.create(
         spec,
         new QueueThreadExceptionHandler() {
           @Override
@@ -55,7 +55,7 @@ public void handleException(Exception e) {
         });
 
     CatalystInstance reactInstance = mock(CatalystInstance.class);
-    when(reactInstance.getCatalystQueueConfiguration()).thenReturn(catalystQueueConfiguration);
+    when(reactInstance.getReactQueueConfiguration()).thenReturn(ReactQueueConfiguration);
     when(reactInstance.getNativeModule(UIManagerModule.class))
         .thenReturn(mock(UIManagerModule.class));
 
diff --git a/website/src/react-native/index.js b/website/src/react-native/index.js
index 769a5f0866f8..919b799aeeb4 100644
--- a/website/src/react-native/index.js
+++ b/website/src/react-native/index.js
@@ -345,7 +345,7 @@ public class MyCustomViewManager extends SimpleViewManager<MyCustomView> {
   }
 
   @Override
-  public void updateView(MyCustomView view, CatalystStylesDiffMap props) {
+  public void updateView(MyCustomView view, ReactStylesDiffMap props) {
     super.updateView(view, props);
 
     if (props.hasKey(PROP_MY_CUSTOM_PROPERTY)) {

From dad462258fae332f276d9a256892cc5fe9fe0c14 Mon Sep 17 00:00:00 2001
From: asmockler <asmockler@gmail.com>
Date: Mon, 25 Jan 2016 06:00:26 -0800
Subject: [PATCH 0873/1411] Ensure perspective value is non-zero

Summary:
Setting `transform: {perspective: 0}` was causing app failure due to `NaN` produced by divide by zero in [MatrixMath.js](https://github.com/facebook/react-native/blob/96553cf553e26e48a87f83030e04aef788f2dfef/Libraries/Utilities/MatrixMath.js#L118).

See issue #2616
Closes https://github.com/facebook/react-native/pull/5457

Reviewed By: svcscm

Differential Revision: D2851748

Pulled By: bestander

fb-gh-sync-id: d2872fb73b4d95ba0b6e5ed2bee814158645cf73
---
 Libraries/StyleSheet/processTransform.js | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/Libraries/StyleSheet/processTransform.js b/Libraries/StyleSheet/processTransform.js
index 4666a3055291..4a523f909108 100644
--- a/Libraries/StyleSheet/processTransform.js
+++ b/Libraries/StyleSheet/processTransform.js
@@ -165,6 +165,20 @@ function _validateTransform(key, value, transformation) {
         stringifySafe(transformation),
       );
       break;
+    case 'perspective':
+      invariant(
+        typeof value === 'number',
+        'Transform with key of "%s" must be a number: %s',
+        key,
+        stringifySafe(transformation),
+      );
+      invariant(
+        value !== 0,
+        'Transform with key of "%s" cannot be zero: %s',
+        key,
+        stringifySafe(transformation),
+      );
+      break;
     default:
       invariant(
         typeof value === 'number',

From c49fc1ee6c51ac690733ea3f7e673f55e3579184 Mon Sep 17 00:00:00 2001
From: Alexander Kotliarskyi <alex.frantic@gmail.com>
Date: Mon, 25 Jan 2016 09:41:12 -0800
Subject: [PATCH 0874/1411] Update instructions for running on device

Summary:
We no longer need to manually build JS bundle, everything should be integrated into Xcode.
Closes https://github.com/facebook/react-native/pull/5521

Reviewed By: svcscm

Differential Revision: D2860511

Pulled By: martinbigio

fb-gh-sync-id: fdde6b39aabccd5a39c140d431acbbbe5af71ec4
---
 docs/RunningOnDeviceIOS.md | 21 ++++-----------------
 1 file changed, 4 insertions(+), 17 deletions(-)

diff --git a/docs/RunningOnDeviceIOS.md b/docs/RunningOnDeviceIOS.md
index 84d57c54175b..e36d90e8feaf 100644
--- a/docs/RunningOnDeviceIOS.md
+++ b/docs/RunningOnDeviceIOS.md
@@ -23,24 +23,11 @@ You can iterate quickly on device using development server. To do that, your lap
 
 ## Using offline bundle
 
-You can also pack all the JavaScript code within the app itself. This way you can test it without development server running and submit the app to the AppStore.
+When you run your app on device, we pack all the JavaScript code and the images used into the app's resources. This way you can test it without development server running and submit the app to the AppStore.
 
 1. Open `AwesomeApp/ios/AwesomeApp/AppDelegate.m`
-2. Follow the instructions for "OPTION 2":
-  * Uncomment `jsCodeLocation = [[NSBundle mainBundle] ...`
-  * Run the `react-native bundle --platform ios --dev false --entry-file index.ios.js --bundle-output iOS/main.jsbundle` command in terminal from the root directory of your app
-
-The bundle script supports a couple of flags:
-
-* `--dev` - a boolean with a default value of `true`. With the `--dev true` flag, the bundled JavaScript code turns on useful development warnings and limits performance optimizations. For production it is recommended to pass `--dev false`. Also for production, be sure to have your native build configuration set to `Release` (e.g., Xcode's Release configuration for iOS and gradle's `assembleRelease` task for Android) in order to disable things like the shake-to-show developer menu.
-* `--minify` - pipe the JS code through UglifyJS.
-
-Note that on 0.14 we'll change the API of `react-native bundle`. The major changes are: 
-
-* API is now `entry-file <path>` based instead of url based.
-* Need to specify which platform you're bundling for `--platform <ios|android>`.
-* Option `--out` has been renamed for `--bundle-output`.
-* Source maps are no longer automatically generated. Need to specify `--sourcemap-output <path>` 
+2. Uncomment `jsCodeLocation = [[NSBundle mainBundle] ...`
+3. The JS bundle will be built for dev or prod depending on your app's scheme (Debug = development build with warnings, Release = minified prod build with perf optimizations).
 
 ## Disabling in-app developer menu
 
@@ -50,4 +37,4 @@ When building your app for production, your app's scheme should be set to `Relea
 
 If `curl` command fails make sure the packager is running. Also try adding `--ipv4` flag to the end of it.
 
-If you started your project a while ago, `main.jsbundle` might not be included into Xcode project. To add it, right click on your project directory and click "Add Files to ..." - choose the `main.jsbundle` file that you generated.
+Note that since [v0.14](https://github.com/facebook/react-native/releases/tag/0.14.0) JS and images are automatically packaged into the iOS app using `Bundle React Native code and images` Xcode build phase.

From 193df8a4e06e08a17aa082feb5e411c9fd745fe8 Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeux@fb.com>
Date: Mon, 25 Jan 2016 09:52:51 -0800
Subject: [PATCH 0875/1411] Improve style prop display

Summary:
- Display the description when it exists
- Display the platform

<img width="667" alt="screen shot 2016-01-24 at 1 37 45 pm" src="https://cloud.githubusercontent.com/assets/197597/12539106/fb226d08-c29f-11e5-83ad-f85bb42ed693.png">
Closes https://github.com/facebook/react-native/pull/5520

Reviewed By: svcscm

Differential Revision: D2859743

Pulled By: vjeux

fb-gh-sync-id: 0ccfeca7bbdfa837501378c0bf701d589fea48d8
---
 website/layout/AutodocsLayout.js              | 88 ++++++++++++-------
 website/server/extractDocs.js                 |  6 +-
 website/src/react-native/css/react-native.css |  5 ++
 3 files changed, 66 insertions(+), 33 deletions(-)

diff --git a/website/layout/AutodocsLayout.js b/website/layout/AutodocsLayout.js
index 2b23a41daf3a..13be4808a6fa 100644
--- a/website/layout/AutodocsLayout.js
+++ b/website/layout/AutodocsLayout.js
@@ -65,6 +65,35 @@ function renderType(type) {
   return type.name;
 }
 
+function sortByPlatform(props, nameA, nameB) {
+  var a = props[nameA];
+  var b = props[nameB];
+
+  if (a.platforms && !b.platforms) {
+    return 1;
+  }
+  if (b.platforms && !a.platforms) {
+    return -1;
+  }
+
+  // Cheap hack: use < on arrays of strings to compare the two platforms
+  if (a.platforms < b.platforms) {
+    return -1;
+  }
+  if (a.platforms > b.platforms) {
+    return 1;
+  }
+
+  if (nameA < nameB) {
+    return -1;
+  }
+  if (nameA > nameB) {
+    return 1;
+  }
+
+  return 0;
+}
+
 var ComponentDoc = React.createClass({
   renderProp: function(name, prop) {
     return (
@@ -96,8 +125,28 @@ var ComponentDoc = React.createClass({
     );
   },
 
+  renderStylesheetProp: function(name, prop) {
+    return (
+      <div className="prop" key={name}>
+        <h6 className="propTitle">
+          {prop.platforms && prop.platforms.map(platform =>
+            <span className="platform">{platform}</span>
+          )}
+          {name}
+          {' '}
+          {prop.type && <span className="propType">
+            {renderType(prop.type)}
+          </span>}
+          {' '}
+          {prop.description && <Marked>{prop.description}</Marked>}
+        </h6>
+      </div>
+    );
+  },
+
   renderStylesheetProps: function(stylesheetName) {
     var style = this.props.content.styles[stylesheetName];
+    this.extractPlatformFromProps(style.props);
     return (
       <div className="compactProps">
         {(style.composes || []).map((name) => {
@@ -121,17 +170,10 @@ var ComponentDoc = React.createClass({
             </div>
           );
         })}
-        {Object.keys(style.props).map((name) =>
-          <div className="prop" key={name}>
-            <h6 className="propTitle">
-              {name}
-              {' '}
-              {style.props[name].type && <span className="propType">
-                {renderType(style.props[name].type)}
-              </span>}
-            </h6>
-          </div>
-        )}
+        {Object.keys(style.props)
+          .sort(sortByPlatform.bind(null, style.props))
+          .map((name) => this.renderStylesheetProp(name, style.props[name]))
+        }
       </div>
     );
   },
@@ -143,27 +185,9 @@ var ComponentDoc = React.createClass({
           this.renderCompose(name)
         )}
         {Object.keys(props)
-          .sort((nameA, nameB) => {
-            var a = props[nameA];
-            var b = props[nameB];
-
-            if (a.platforms && !b.platforms) {
-              return 1;
-            }
-            if (b.platforms && !a.platforms) {
-              return -1;
-            }
-            if (nameA < nameB) {
-              return -1;
-            }
-            if (nameA > nameB) {
-              return 1;
-            }
-            return 0;
-          })
-          .map((name) =>
-          this.renderProp(name, props[name])
-        )}
+          .sort(sortByPlatform.bind(null, props))
+          .map((name) => this.renderProp(name, props[name]))
+        }
       </div>
     );
   },
diff --git a/website/server/extractDocs.js b/website/server/extractDocs.js
index 8b32daff2802..151b6581458a 100644
--- a/website/server/extractDocs.js
+++ b/website/server/extractDocs.js
@@ -267,7 +267,11 @@ var styleDocs = styles.slice(2).reduce(function(docs, filepath) {
     docgen.parse(
       fs.readFileSync(filepath),
       docgenHelpers.findExportedObject,
-      [docgen.handlers.propTypeHandler, docgen.handlers.propTypeCompositionHandler]
+      [
+        docgen.handlers.propTypeHandler,
+        docgen.handlers.propTypeCompositionHandler,
+        docgen.handlers.propDocBlockHandler,
+      ]
     );
 
   return docs;
diff --git a/website/src/react-native/css/react-native.css b/website/src/react-native/css/react-native.css
index a08f351d6bde..05e541bb9d83 100644
--- a/website/src/react-native/css/react-native.css
+++ b/website/src/react-native/css/react-native.css
@@ -1041,6 +1041,11 @@ div[data-twttr-id] iframe {
   margin-top: 0;
 }
 
+.compactProps .propTitle div {
+  font-weight: normal;
+  margin-left: 20px;
+}
+
 .prop {
   padding: 5px 10px;
 }

From 191b692e051fac185c99aae70351c2b014f87fe9 Mon Sep 17 00:00:00 2001
From: Mark Vayngrib <mark@tradle.io>
Date: Mon, 25 Jan 2016 10:08:43 -0800
Subject: [PATCH 0876/1411] breaking test and fix for browser field mapping
 from package to file

Summary:
breaks on mappings like:

```json
"browser": {
  "node-package": "./dir/browser.js"
}
```
Closes https://github.com/facebook/react-native/pull/5505

Reviewed By: svcscm

Differential Revision: D2860579

Pulled By: androidtrunkagent

fb-gh-sync-id: 0d64c0999c47a6cbbf084cc8e0c8a6ea209b0880
---
 .../DependencyGraph/ResolutionRequest.js      | 31 +++++---
 .../__tests__/DependencyGraph-test.js         | 79 +++++++++++++++++++
 2 files changed, 101 insertions(+), 9 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
index f67404393902..87e00260cb85 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
@@ -264,20 +264,33 @@ class ResolutionRequest {
     });
   }
 
+  _resolveFileOrDir(fromModule, toModuleName) {
+    const potentialModulePath = isAbsolutePath(toModuleName) ?
+        toModuleName :
+        path.join(path.dirname(fromModule.path), toModuleName);
+
+    return this._redirectRequire(fromModule, potentialModulePath).then(
+      realModuleName => this._tryResolve(
+        () => this._loadAsFile(realModuleName, fromModule, toModuleName),
+        () => this._loadAsDir(realModuleName, fromModule, toModuleName)
+      )
+    );
+  }
+
   _resolveNodeDependency(fromModule, toModuleName) {
     if (toModuleName[0] === '.' || toModuleName[1] === '/') {
-      const potentialModulePath = isAbsolutePath(toModuleName) ?
-              toModuleName :
-              path.join(path.dirname(fromModule.path), toModuleName);
-      return this._redirectRequire(fromModule, potentialModulePath).then(
-        realModuleName => this._tryResolve(
-          () => this._loadAsFile(realModuleName, fromModule, toModuleName),
-          () => this._loadAsDir(realModuleName, fromModule, toModuleName)
-        )
-      );
+      return this._resolveFileOrDir(fromModule, toModuleName)
     } else {
       return this._redirectRequire(fromModule, toModuleName).then(
         realModuleName => {
+          if (realModuleName[0] === '.' || realModuleName[1] === '/') {
+            // derive absolute path /.../node_modules/fromModuleDir/realModuleName
+            let fromModuleParentIdx = fromModule.path.lastIndexOf('node_modules/') + 13
+            let fromModuleDir = fromModule.path.slice(0, fromModule.path.indexOf('/', fromModuleParentIdx))
+            let absPath = path.join(fromModuleDir, realModuleName)
+            return this._resolveFileOrDir(fromModule, absPath)
+          }
+
           const searchQueue = [];
           for (let currDir = path.dirname(fromModule.path);
                currDir !== path.parse(fromModule.path).root;
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
index b1126a4cc3e3..6c88acb63900 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
@@ -1774,6 +1774,85 @@ describe('DependencyGraph', function() {
         });
       });
 
+      pit('should support browser mapping of a package to a file ("' + fieldName + '")', function() {
+        var root = '/root';
+        fs.__setMockFilesystem({
+          'root': {
+            'index.js': [
+              '/**',
+              ' * @providesModule index',
+              ' */',
+              'require("aPackage")',
+            ].join('\n'),
+            'aPackage': {
+              'package.json': JSON.stringify(replaceBrowserField({
+                name: 'aPackage',
+                browser: {
+                  'node-package': './dir/browser.js',
+                },
+              }, fieldName)),
+              'index.js': 'require("./dir/ooga")',
+              'dir': {
+                'ooga.js': 'require("node-package")',
+                'browser.js': 'some browser code',
+              },
+              'node-package': {
+                'package.json': JSON.stringify({
+                  'name': 'node-package',
+                }),
+                'index.js': 'some node code',
+              },
+            },
+          },
+        });
+
+        const dgraph = new DependencyGraph({
+          ...defaults,
+          roots: [root],
+        });
+        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
+          expect(deps)
+            .toEqual([
+              { id: 'index',
+                path: '/root/index.js',
+                dependencies: ['aPackage'],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
+              },
+              { id: 'aPackage/index.js',
+                path: '/root/aPackage/index.js',
+                dependencies: ['./dir/ooga'],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
+              },
+              { id: 'aPackage/dir/ooga.js',
+                path: '/root/aPackage/dir/ooga.js',
+                dependencies: ['node-package'],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
+              },
+              { id: 'aPackage/dir/browser.js',
+                path: '/root/aPackage/dir/browser.js',
+                dependencies: [],
+                isAsset: false,
+                isAsset_DEPRECATED: false,
+                isJSON: false,
+                isPolyfill: false,
+                resolution: undefined,
+              },
+            ]);
+        });
+      });
+
       pit('should support browser mapping for packages ("' + fieldName + '")', function() {
         var root = '/root';
         fs.__setMockFilesystem({

From ea1aec3c230980b09b715c123c1a9c49a114ed3d Mon Sep 17 00:00:00 2001
From: Dan Caspi <danca@fb.com>
Date: Mon, 25 Jan 2016 11:40:29 -0800
Subject: [PATCH 0877/1411] JSC Pre-Parsing cache

Reviewed By: mikearmstrong001

Differential Revision: D2840411

fb-gh-sync-id: d238e10b9a859185e6011c4685229cedbcc57a3e
---
 .../src/main/jni/react/JSCExecutor.cpp        | 32 ++++++++++++++++++-
 ReactAndroid/src/main/jni/react/JSCExecutor.h |  1 +
 .../src/main/jni/react/JSCHelpers.cpp         | 20 ++++++++++--
 ReactAndroid/src/main/jni/react/JSCHelpers.h  |  2 +-
 4 files changed, 50 insertions(+), 5 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index 0aa59246f583..f62ec6e56dac 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -138,6 +138,29 @@ JSCExecutor::~JSCExecutor() {
   JSGlobalContextRelease(m_context);
 }
 
+std::string JSCExecutor::getDeviceCacheDir(){
+  // Get the Application Context object
+  auto getApplicationClass = findClassLocal(
+                              "com/facebook/react/common/ApplicationHolder");
+  auto getApplicationMethod = getApplicationClass->getStaticMethod<jobject()>(
+                              "getApplication",
+                              "()Landroid/app/Application;"
+                              );
+  auto application = getApplicationMethod(getApplicationClass);
+
+  // Get getCacheDir() from the context
+  auto getCacheDirMethod = findClassLocal("android/app/Application")
+                            ->getMethod<jobject()>("getCacheDir",
+                                                   "()Ljava/io/File;"
+                                                  );
+  auto cacheDirObj = getCacheDirMethod(application);
+
+  // Call getAbsolutePath() on the returned File object
+  auto getAbsolutePathMethod = findClassLocal("java/io/File")
+                                ->getMethod<jstring()>("getAbsolutePath");
+  return getAbsolutePathMethod(cacheDirObj)->toStdString();
+}
+
 void JSCExecutor::executeApplicationScript(
     const std::string& script,
     const std::string& sourceURL) {
@@ -153,11 +176,18 @@ void JSCExecutor::executeApplicationScript(
   env->DeleteLocalRef(startStringMarker);
   env->DeleteLocalRef(endStringMarker);
 
+  String jsSourceURL(sourceURL.c_str());
   #ifdef WITH_FBSYSTRACE
   FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor::executeApplicationScript",
     "sourceURL", sourceURL);
   #endif
-  evaluateScript(m_context, jsScript, String(sourceURL.c_str()));
+  if (!jsSourceURL) {
+    evaluateScript(m_context, jsScript, jsSourceURL);
+  } else {
+    // If we're evaluating a script, get the device's cache dir 
+    //  in which a cache file for that script will be stored.
+    evaluateScript(m_context, jsScript, jsSourceURL, getDeviceCacheDir().c_str());
+  }
 }
 
 void JSCExecutor::loadApplicationUnbundle(
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.h b/ReactAndroid/src/main/jni/react/JSCExecutor.h
index 85d87c2a68a3..9d66fdf99b58 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.h
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.h
@@ -71,6 +71,7 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
   void postMessageToWebWorker(int worker, JSValueRef message, JSValueRef *exn);
   void terminateWebWorker(int worker);
   void loadModule(uint32_t moduleId);
+  std::string getDeviceCacheDir();
 
   static JSValueRef nativeStartWorker(
       JSContextRef ctx,
diff --git a/ReactAndroid/src/main/jni/react/JSCHelpers.cpp b/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
index 4835781133f1..80b7966174d0 100644
--- a/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
@@ -8,6 +8,10 @@
 
 #include "Value.h"
 
+#if WITH_FBJSCEXTENSIONS
+#include <jsc_function_info_cache.h>
+#endif
+
 namespace facebook {
 namespace react {
 
@@ -32,9 +36,19 @@ JSValueRef makeJSCException(
   return JSValueToObject(ctx, exceptionString, NULL);
 }
 
-JSValueRef evaluateScript(JSContextRef context, JSStringRef script, JSStringRef source) {
-  JSValueRef exn;
-  auto result = JSEvaluateScript(context, script, NULL, source, 0, &exn);
+JSValueRef evaluateScript(JSContextRef context, JSStringRef script, JSStringRef source, const char *cachePath) {
+  JSValueRef exn, result;
+#if WITH_FBJSCEXTENSIONS
+  if (source){
+    // If evaluating an application script, send it through `JSEvaluateScriptWithCache()`
+    //  to add cache support.
+    result = JSEvaluateScriptWithCache(context, script, NULL, source, 0, &exn, cachePath);
+  } else {
+    result = JSEvaluateScript(context, script, NULL, source, 0, &exn);
+  }
+#else
+  result = JSEvaluateScript(context, script, NULL, source, 0, &exn);
+#endif
   if (result == nullptr) {
     Value exception = Value(context, exn);
     std::string exceptionText = exception.toString().str();
diff --git a/ReactAndroid/src/main/jni/react/JSCHelpers.h b/ReactAndroid/src/main/jni/react/JSCHelpers.h
index fd19c48cc458..7ac633075ce4 100644
--- a/ReactAndroid/src/main/jni/react/JSCHelpers.h
+++ b/ReactAndroid/src/main/jni/react/JSCHelpers.h
@@ -20,6 +20,6 @@ JSValueRef makeJSCException(
     JSContextRef ctx,
     const char* exception_text);
 
-JSValueRef evaluateScript(JSContextRef context, JSStringRef script, JSStringRef source);
+JSValueRef evaluateScript(JSContextRef context, JSStringRef script, JSStringRef source, const char *cachePath = nullptr);
 
 } }

From 0007bff9772e84d442523285882509bd141ef455 Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Mon, 25 Jan 2016 12:34:06 -0800
Subject: [PATCH 0878/1411] Use promises in 'SourceCodeModule'

Summary: Closes https://github.com/facebook/react-native/pull/5504

Reviewed By: svcscm

Differential Revision: D2861158

Pulled By: dmmiller

fb-gh-sync-id: 3e9c257288539183f6156b8d360b54dc570bc7ad
---
 .../Initialization/loadSourceMap.js                    |  2 +-
 React/Modules/RCTSourceCode.m                          | 10 ++++++----
 .../facebook/react/modules/debug/SourceCodeModule.java |  8 ++++----
 3 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/Libraries/JavaScriptAppEngine/Initialization/loadSourceMap.js b/Libraries/JavaScriptAppEngine/Initialization/loadSourceMap.js
index de96ad2be08d..852579c6067f 100644
--- a/Libraries/JavaScriptAppEngine/Initialization/loadSourceMap.js
+++ b/Libraries/JavaScriptAppEngine/Initialization/loadSourceMap.js
@@ -39,7 +39,7 @@ function fetchSourceMap(): Promise {
     return Promise.reject(new Error('RCTNetworking module is not available'));
   }
 
-  return new Promise(RCTSourceCode.getScriptText)
+  return RCTSourceCode.getScriptText()
     .then(extractSourceMapURL)
     .then((url) => {
       if (url === null) {
diff --git a/React/Modules/RCTSourceCode.m b/React/Modules/RCTSourceCode.m
index 281a304f93ea..e538fa5d0c96 100644
--- a/React/Modules/RCTSourceCode.m
+++ b/React/Modules/RCTSourceCode.m
@@ -24,15 +24,17 @@ @implementation RCTSourceCode
 - (void)setScriptText:(NSString *)scriptText {}
 #endif
 
-RCT_EXPORT_METHOD(getScriptText:(RCTResponseSenderBlock)successCallback
-                  failureCallback:(RCTResponseErrorBlock)failureCallback)
+NSString *const RCTErrorUnavailable = @"E_SOURCE_CODE_UNAVAILABLE";
+
+RCT_EXPORT_METHOD(getScriptText:(RCTPromiseResolveBlock)resolve
+                  reject:(RCTPromiseRejectBlock)reject)
 {
   if (RCT_DEV && self.scriptData && self.scriptURL) {
     NSString *scriptText = [[NSString alloc] initWithData:self.scriptData encoding:NSUTF8StringEncoding];
 
-    successCallback(@[@{@"text": scriptText, @"url": self.scriptURL.absoluteString}]);
+    resolve(@[@{@"text": scriptText, @"url": self.scriptURL.absoluteString}]);
   } else {
-    failureCallback(RCTErrorWithMessage(@"Source code is not available"));
+    reject(RCTErrorUnavailable, nil, RCTErrorWithMessage(@"Source code is not available"));
   }
 }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/debug/SourceCodeModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/debug/SourceCodeModule.java
index 07022a7e76c3..3417c81946af 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/debug/SourceCodeModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/debug/SourceCodeModule.java
@@ -14,7 +14,7 @@
 import java.util.HashMap;
 import java.util.Map;
 
-import com.facebook.react.bridge.Callback;
+import com.facebook.react.bridge.Promise;
 import com.facebook.react.bridge.BaseJavaModule;
 import com.facebook.react.bridge.ReactMethod;
 import com.facebook.react.bridge.WritableMap;
@@ -35,14 +35,14 @@ public SourceCodeModule(String sourceUrl, String sourceMapUrl) {
 
   @Override
   public String getName() {
-    return "RKSourceCode";
+    return "RCTSourceCode";
   }
 
   @ReactMethod
-  public void getScriptText(final Callback onSuccess, final Callback onError) {
+  public void getScriptText(final Promise promise) {
     WritableMap map = new WritableNativeMap();
     map.putString("fullSourceMappingURL", mSourceMapUrl);
-    onSuccess.invoke(map);
+    promise.resolve(map);
   }
 
   @Override

From d3e44143f6643662432960d156e93c3e1a49781d Mon Sep 17 00:00:00 2001
From: Alex Kotliarskyi <alex.frantic@gmail.com>
Date: Mon, 25 Jan 2016 12:35:48 -0800
Subject: [PATCH 0879/1411] Improve react-native-xcode.sh integration

Summary:
Inspired by conversation in https://github.com/facebook/react-native/pull/5374, this PR improves `react-native-xcode.sh`:

* No longer depends on global `react-native` binary
* Gracefully handles missing `node` dependency and adds a new way to configure the path to `node` in non-standard installation environments

This is how the error looks like:
![image](https://cloud.githubusercontent.com/assets/192222/12538882/3f9b5c3e-c29a-11e5-84fc-c7ccedf1c46a.png)
Closes https://github.com/facebook/react-native/pull/5518

Reviewed By: svcscm

Differential Revision: D2861116

Pulled By: frantic

fb-gh-sync-id: 9a80eda6c844d066e34369b1cda503955171485b
---
 .../templates/xcodeproj/project.pbxproj       |  2 +-
 packager/react-native-xcode.sh                | 27 ++++++++++++++-----
 2 files changed, 22 insertions(+), 7 deletions(-)

diff --git a/local-cli/generator-ios/templates/xcodeproj/project.pbxproj b/local-cli/generator-ios/templates/xcodeproj/project.pbxproj
index 33a28a480822..eab5cb0cbc56 100644
--- a/local-cli/generator-ios/templates/xcodeproj/project.pbxproj
+++ b/local-cli/generator-ios/templates/xcodeproj/project.pbxproj
@@ -525,7 +525,7 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "../node_modules/react-native/packager/react-native-xcode.sh";
+			shellScript = "export NODE_BINARY=node\n../node_modules/react-native/packager/react-native-xcode.sh";
 			showEnvVarsInLog = 1;
 		};
 /* End PBXShellScriptBuildPhase section */
diff --git a/packager/react-native-xcode.sh b/packager/react-native-xcode.sh
index 898862618acd..25533a853a03 100755
--- a/packager/react-native-xcode.sh
+++ b/packager/react-native-xcode.sh
@@ -23,12 +23,12 @@ case "$CONFIGURATION" in
     ;;
 esac
 
+# Path to react-native folder inside node_modules
+REACT_NATIVE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+
 # Xcode project file for React Native apps is located in ios/ subfolder
 cd ..
 
-set -x
-DEST=$CONFIGURATION_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH
-
 # Define NVM_DIR and source the nvm.sh setup script
 [ -z "$NVM_DIR" ] && export NVM_DIR="$HOME/.nvm"
 
@@ -43,10 +43,25 @@ if [[ -x "$HOME/.nodenv/bin/nodenv" ]]; then
   eval "$($HOME/.nodenv/bin/nodenv init -)"
 fi
 
-# npm global install path may be a non-standard location
-PATH="$(npm prefix -g)/bin:$PATH"
+[ -z "$NODE_BINARY" ] && export NODE_BINARY="node"
+
+nodejs_not_found()
+{
+  echo "error: Can't find '$NODE_BINARY' binary to build React Native bundle" >&2
+  echo "If you have non-standard nodejs installation, select your project in Xcode," >&2
+  echo "find 'Build Phases' - 'Bundle React Native code and images'" >&2
+  echo "and change NODE_BINARY to absolute path to your node executable" >&2
+  echo "(you can find it by invoking 'which node' in the terminal)" >&2
+  exit 2
+}
+
+type $NODE_BINARY >/dev/null 2>&1 || nodejs_not_found
+
+# Print commands before executing them (useful for troubleshooting)
+set -x
+DEST=$CONFIGURATION_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH
 
-react-native bundle \
+$NODE_BINARY $REACT_NATIVE_DIR/local-cli/cli.js bundle \
   --entry-file index.ios.js \
   --platform ios \
   --dev $DEV \

From ee989ce07fb96f7b99c5e4f4ce16fd8b09f0092e Mon Sep 17 00:00:00 2001
From: Yamill Vallecillo <yvallecillo@tracfone.com>
Date: Mon, 25 Jan 2016 17:09:57 -0500
Subject: [PATCH 0880/1411] App Icon Update

App Icon update for WPV v3
---
 website/src/react-native/showcase.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 76c51c93be18..d87d844e3f13 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -497,9 +497,9 @@ var apps = [
   },
   {
     name: 'WPV',
-    icon: 'http://a1.mzstatic.com/us/r30/Purple3/v4/f1/ae/51/f1ae516b-d8e9-1b6d-acfe-755623a88327/icon350x350.png',
+    icon: 'http://a2.mzstatic.com/us/r30/Purple49/v4/a8/26/d7/a826d7bf-337b-c6b8-488d-aca98027754d/icon350x350.png',
     link: 'https://itunes.apple.com/us/app/wpv/id725222647?mt=8',
-    author: 'Yamill Vallecillo (@yamill3)',
+    author: 'Yamill Vallecillo',
   },
   {
     name: 'Yoloci',

From 91fe9158c9df9ae838ba55d90d3388723a083a8c Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Mon, 25 Jan 2016 18:35:12 -0800
Subject: [PATCH 0881/1411] Remove JSThreadState from Bridge

Reviewed By: lexs

Differential Revision: D2857580

fb-gh-sync-id: f3172cecb8f4563c70564a50c2e9f42178af347a
---
 ReactAndroid/src/main/jni/react/Bridge.cpp | 101 ++++-----------------
 ReactAndroid/src/main/jni/react/Bridge.h   |   3 +-
 2 files changed, 20 insertions(+), 84 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/Bridge.cpp b/ReactAndroid/src/main/jni/react/Bridge.cpp
index a06871c1eea0..0e6982af5948 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.cpp
+++ b/ReactAndroid/src/main/jni/react/Bridge.cpp
@@ -13,107 +13,42 @@ using fbsystrace::FbSystraceSection;
 namespace facebook {
 namespace react {
 
-class JSThreadState {
-public:
-  JSThreadState(const RefPtr<JSExecutorFactory>& jsExecutorFactory, Bridge::Callback&& callback) :
-    m_callback(callback)
-  {
-    m_jsExecutor = jsExecutorFactory->createJSExecutor([this, callback] (std::string queueJSON, bool isEndOfBatch) {
-      m_callback(parseMethodCalls(queueJSON), false /* = isEndOfBatch */);
-    });
-  }
-
-  void executeApplicationScript(const std::string& script, const std::string& sourceURL) {
-    m_jsExecutor->executeApplicationScript(script, sourceURL);
-  }
-
-  void loadApplicationUnbundle(
-      JSModulesUnbundle&& unbundle,
-      const std::string& startupCode,
-      const std::string& sourceURL) {
-    m_jsExecutor->loadApplicationUnbundle(std::move(unbundle), startupCode, sourceURL);
-  }
-
-  void flush() {
-    auto returnedJSON = m_jsExecutor->flush();
-    m_callback(parseMethodCalls(returnedJSON), true /* = isEndOfBatch */);
-  }
-
-  void callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) {
-    auto returnedJSON = m_jsExecutor->callFunction(moduleId, methodId, arguments);
-    m_callback(parseMethodCalls(returnedJSON), true /* = isEndOfBatch */);
-  }
-
-  void invokeCallback(const double callbackId, const folly::dynamic& arguments) {
-    auto returnedJSON = m_jsExecutor->invokeCallback(callbackId, arguments);
-    m_callback(parseMethodCalls(returnedJSON), true /* = isEndOfBatch */);
-  }
-
-  void setGlobalVariable(const std::string& propName, const std::string& jsonValue) {
-    m_jsExecutor->setGlobalVariable(propName, jsonValue);
-  }
-
-  bool supportsProfiling() {
-    return m_jsExecutor->supportsProfiling();
-  }
-
-  void startProfiler(const std::string& title) {
-    m_jsExecutor->startProfiler(title);
-  }
-
-  void stopProfiler(const std::string& title, const std::string& filename) {
-    m_jsExecutor->stopProfiler(title, filename);
-  }
-
-  void handleMemoryPressureModerate() {
-    m_jsExecutor->handleMemoryPressureModerate();
-  }
-
-  void handleMemoryPressureCritical() {
-    m_jsExecutor->handleMemoryPressureCritical();
-  }
-
-private:
-  std::unique_ptr<JSExecutor> m_jsExecutor;
-  Bridge::Callback m_callback;
-};
-
 Bridge::Bridge(const RefPtr<JSExecutorFactory>& jsExecutorFactory, Callback callback) :
-  m_callback(callback),
+  m_callback(std::move(callback)),
   m_destroyed(std::shared_ptr<bool>(new bool(false)))
 {
   auto destroyed = m_destroyed;
-  auto proxyCallback = [this, destroyed] (std::vector<MethodCall> calls, bool isEndOfBatch) {
+  m_jsExecutor = jsExecutorFactory->createJSExecutor([this, destroyed] (std::string queueJSON, bool isEndOfBatch) {
     if (*destroyed) {
       return;
     }
-    m_callback(std::move(calls), isEndOfBatch);
-  };
-  m_threadState.reset(new JSThreadState(jsExecutorFactory, std::move(proxyCallback)));
+    m_callback(parseMethodCalls(queueJSON), isEndOfBatch);
+  });
 }
 
 // This must be called on the same thread on which the constructor was called.
 Bridge::~Bridge() {
   *m_destroyed = true;
-  m_threadState.reset();
+  m_jsExecutor.reset();
 }
 
 void Bridge::executeApplicationScript(const std::string& script, const std::string& sourceURL) {
-  m_threadState->executeApplicationScript(script, sourceURL);
+  m_jsExecutor->executeApplicationScript(script, sourceURL);
 }
 
 void Bridge::loadApplicationUnbundle(
     JSModulesUnbundle&& unbundle,
     const std::string& startupCode,
     const std::string& sourceURL) {
-  m_threadState->loadApplicationUnbundle(std::move(unbundle), startupCode, sourceURL);
+  m_jsExecutor->loadApplicationUnbundle(std::move(unbundle), startupCode, sourceURL);
 }
 
 void Bridge::flush() {
   if (*m_destroyed) {
     return;
   }
-  m_threadState->flush();
+  auto returnedJSON = m_jsExecutor->flush();
+  m_callback(parseMethodCalls(returnedJSON), true /* = isEndOfBatch */);
 }
 
 void Bridge::callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) {
@@ -123,7 +58,8 @@ void Bridge::callFunction(const double moduleId, const double methodId, const fo
   #ifdef WITH_FBSYSTRACE
   FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "Bridge.callFunction");
   #endif
-  m_threadState->callFunction(moduleId, methodId, arguments);
+  auto returnedJSON = m_jsExecutor->callFunction(moduleId, methodId, arguments);
+  m_callback(parseMethodCalls(returnedJSON), true /* = isEndOfBatch */);
 }
 
 void Bridge::invokeCallback(const double callbackId, const folly::dynamic& arguments) {
@@ -133,31 +69,32 @@ void Bridge::invokeCallback(const double callbackId, const folly::dynamic& argum
   #ifdef WITH_FBSYSTRACE
   FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "Bridge.invokeCallback");
   #endif
-  m_threadState->invokeCallback(callbackId, arguments);
+  auto returnedJSON = m_jsExecutor->invokeCallback(callbackId, arguments);
+  m_callback(parseMethodCalls(returnedJSON), true /* = isEndOfBatch */);
 }
 
 void Bridge::setGlobalVariable(const std::string& propName, const std::string& jsonValue) {
-  m_threadState->setGlobalVariable(propName, jsonValue);
+  m_jsExecutor->setGlobalVariable(propName, jsonValue);
 }
 
 bool Bridge::supportsProfiling() {
-  return m_threadState->supportsProfiling();
+  return m_jsExecutor->supportsProfiling();
 }
 
 void Bridge::startProfiler(const std::string& title) {
-  m_threadState->startProfiler(title);
+  m_jsExecutor->startProfiler(title);
 }
 
 void Bridge::stopProfiler(const std::string& title, const std::string& filename) {
-  m_threadState->stopProfiler(title, filename);
+  m_jsExecutor->stopProfiler(title, filename);
 }
 
 void Bridge::handleMemoryPressureModerate() {
-  m_threadState->handleMemoryPressureModerate();
+  m_jsExecutor->handleMemoryPressureModerate();
 }
 
 void Bridge::handleMemoryPressureCritical() {
-  m_threadState->handleMemoryPressureCritical();
+  m_jsExecutor->handleMemoryPressureCritical();
 }
 
 } }
diff --git a/ReactAndroid/src/main/jni/react/Bridge.h b/ReactAndroid/src/main/jni/react/Bridge.h
index c8f0be4c4305..33f7a4a99df3 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.h
+++ b/ReactAndroid/src/main/jni/react/Bridge.h
@@ -22,7 +22,6 @@ struct dynamic;
 namespace facebook {
 namespace react {
 
-class JSThreadState;
 class Bridge : public Countable {
 public:
   typedef std::function<void(std::vector<MethodCall>, bool isEndOfBatch)> Callback;
@@ -68,11 +67,11 @@ class Bridge : public Countable {
   void handleMemoryPressureCritical();
 private:
   Callback m_callback;
-  std::unique_ptr<JSThreadState> m_threadState;
   // This is used to avoid a race condition where a proxyCallback gets queued after ~Bridge(),
   // on the same thread. In that case, the callback will try to run the task on m_callback which
   // will have been destroyed within ~Bridge(), thus causing a SIGSEGV.
   std::shared_ptr<bool> m_destroyed;
+  std::unique_ptr<JSExecutor> m_jsExecutor;
 };
 
 } }

From c1aed7ba41246ff250e7aebac2c5ee2532c14868 Mon Sep 17 00:00:00 2001
From: Alex Kotliarskyi <frantic@fb.com>
Date: Mon, 25 Jan 2016 18:36:10 -0800
Subject: [PATCH 0882/1411] Fix warnings generated by Elements Inspector

Summary:
public

When using dev menu - elements inspector, a yellow box appears
with React warning regarding missing key prop in elements array.
This commit fixes this issue.

Reviewed By: martinbigio

Differential Revision: D2835332

fb-gh-sync-id: 3fcb37dfb6bdcff3788963b36416b7da190b9a84
---
 Libraries/Inspector/ElementProperties.js | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/Libraries/Inspector/ElementProperties.js b/Libraries/Inspector/ElementProperties.js
index 222da109fec8..1e808d0d1729 100644
--- a/Libraries/Inspector/ElementProperties.js
+++ b/Libraries/Inspector/ElementProperties.js
@@ -47,6 +47,7 @@ var ElementProperties = React.createClass({
               this.props.hierarchy,
               (item, i) => (
                 <TouchableHighlight
+                  key={'item-' + i}
                   style={[styles.breadItem, i === selection && styles.selected]}
                   onPress={() => this.props.setSelection(i)}>
                   <Text style={styles.breadItemText}>
@@ -54,7 +55,11 @@ var ElementProperties = React.createClass({
                   </Text>
                 </TouchableHighlight>
               ),
-              () => <Text style={styles.breadSep}>&#9656;</Text>
+              (i) => (
+                <Text key={'sep-' + i} style={styles.breadSep}>
+                  &#9656;
+                </Text>
+              )
             )}
           </View>
           <View style={styles.row}>

From 1edcf4c6ac44cdf7229d55d900d552dc6ebe2541 Mon Sep 17 00:00:00 2001
From: Hedger Wang <hedger@fb.com>
Date: Tue, 26 Jan 2016 01:27:14 -0800
Subject: [PATCH 0883/1411] Disable navigation bar right button when it's
 transparent.

Reviewed By: chaceliang

Differential Revision: D2863157

fb-gh-sync-id: ca73545303607333fe32cd8e2e8f040134ee1d24
---
 .../Navigator/NavigatorBreadcrumbNavigationBar.js      | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js b/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js
index b142b18fbbae..84a1e43cde1b 100644
--- a/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js
+++ b/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js
@@ -134,9 +134,13 @@ var NavigatorBreadcrumbNavigationBar = React.createClass({
       this._setPropsIfExists('title_' + index, TITLE_PROPS[index]);
     }
     var right = this.refs['right_' + index];
-    if (right &&
-        interpolate.RightItem(RIGHT_BUTTON_PROPS[index].style, amount)) {
-      right.setNativeProps(RIGHT_BUTTON_PROPS[index]);
+
+    const rightButtonStyle = RIGHT_BUTTON_PROPS[index].style;
+    if (right && interpolate.RightItem(rightButtonStyle, amount)) {
+      right.setNativeProps({
+        style: rightButtonStyle,
+        pointerEvents: rightButtonStyle.opacity === 0 ? 'none' : 'auto',
+      });
     }
   },
 

From 7419a82bd768a13ad662e51fbfd9fc1172acb935 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Tue, 26 Jan 2016 06:12:48 -0800
Subject: [PATCH 0884/1411] Handle bad JSON data without crashing

Summary:
public
NSJSONSerialization throws an exception when it encounters bad JSON data, including NaN values, which may not be a programming error.

This diff adds code to catch those exceptions and convert to an error. Also, if no error handling is in place, RCTJSONStringify will now display a redbox, and attempt to recover by sanitizing the JSON data and retrying.

Reviewed By: javache

Differential Revision: D2854778

fb-gh-sync-id: 18e6990af0d91083496d6a0b75c31a94ed9454a5
---
 .../UIExplorerUnitTests/RCTJSONTests.m        | 31 +++++++++
 React/Base/RCTUtils.h                         |  2 +-
 React/Base/RCTUtils.m                         | 63 ++++++++++++++++---
 React/Modules/RCTRedBox.m                     |  2 +-
 React/Profiler/RCTProfile.m                   |  2 +-
 5 files changed, 87 insertions(+), 13 deletions(-)

diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTJSONTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTJSONTests.m
index fd8343c08c84..acacc3a34c46 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTJSONTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTJSONTests.m
@@ -78,4 +78,35 @@ - (void)testLeadingWhitespace
   XCTAssertEqualObjects(obj, RCTJSONParse(json, NULL));
 }
 
+- (void)testNotJSONSerializable
+{
+  NSDictionary<NSString *, id> *obj = @{@"foo": [NSDate date]};
+  NSString *json = @"{\"foo\":null}";
+  XCTAssertEqualObjects(json, RCTJSONStringify(obj, NULL));
+}
+
+- (void)testNaN
+{
+  NSDictionary<NSString *, id> *obj = @{@"foo": @(NAN)};
+  NSString *json = @"{\"foo\":0}";
+  XCTAssertEqualObjects(json, RCTJSONStringify(obj, NULL));
+}
+
+- (void)testNotUTF8Convertible
+{
+  //see https://gist.github.com/0xced/56035d2f57254cf518b5
+  NSString *string = [[NSString alloc] initWithBytes:"\xd8\x00" length:2 encoding:NSUTF16StringEncoding];
+  NSDictionary<NSString *, id> *obj = @{@"foo": string};
+  NSString *json = @"{\"foo\":null}";
+  XCTAssertEqualObjects(json, RCTJSONStringify(obj, NULL));
+}
+
+- (void)testErrorPointer
+{
+  NSDictionary<NSString *, id> *obj = @{@"foo": [NSDate date]};
+  NSError *error;
+  XCTAssertNil(RCTJSONStringify(obj, &error));
+  XCTAssertNotNil(error);
+}
+
 @end
diff --git a/React/Base/RCTUtils.h b/React/Base/RCTUtils.h
index 30febd5a35d2..8f7a4858b737 100644
--- a/React/Base/RCTUtils.h
+++ b/React/Base/RCTUtils.h
@@ -23,7 +23,7 @@ RCT_EXTERN NSString *__nullable RCTJSONStringify(id __nullable jsonObject, NSErr
 RCT_EXTERN id __nullable RCTJSONParse(NSString *__nullable jsonString, NSError **error);
 RCT_EXTERN id __nullable RCTJSONParseMutable(NSString *__nullable jsonString, NSError **error);
 
-// Strip non JSON-safe values from an object graph
+// Santize a JSON string by stripping invalid objects and/or NaN values
 RCT_EXTERN id RCTJSONClean(id object);
 
 // Get MD5 hash of a string
diff --git a/React/Base/RCTUtils.m b/React/Base/RCTUtils.m
index 7b69da74b969..f49e117e202c 100644
--- a/React/Base/RCTUtils.m
+++ b/React/Base/RCTUtils.m
@@ -23,8 +23,12 @@
 
 NSString *const RCTErrorUnspecified = @"EUNSPECIFIED";
 
-NSString *__nullable RCTJSONStringify(id __nullable jsonObject, NSError **error)
+static NSString *__nullable _RCTJSONStringifyNoRetry(id __nullable jsonObject, NSError **error)
 {
+  if (!jsonObject) {
+    return nil;
+  }
+
   static SEL JSONKitSelector = NULL;
   static NSSet<Class> *collectionTypes;
   static dispatch_once_t onceToken;
@@ -38,17 +42,48 @@
     }
   });
 
-  // Use JSONKit if available and object is not a fragment
-  if (JSONKitSelector && [collectionTypes containsObject:[jsonObject classForCoder]]) {
-    return ((NSString *(*)(id, SEL, int, NSError **))objc_msgSend)(jsonObject, JSONKitSelector, 0, error);
+  @try {
+
+    // Use JSONKit if available and object is not a fragment
+    if (JSONKitSelector && [collectionTypes containsObject:[jsonObject classForCoder]]) {
+      return ((NSString *(*)(id, SEL, int, NSError **))objc_msgSend)(jsonObject, JSONKitSelector, 0, error);
+    }
+
+    // Use Foundation JSON method
+    NSData *jsonData = [NSJSONSerialization
+                        dataWithJSONObject:jsonObject options:(NSJSONWritingOptions)NSJSONReadingAllowFragments
+                        error:error];
+
+    return jsonData ? [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding] : nil;
   }
+  @catch (NSException *exception) {
 
-  // Use Foundation JSON method
-  NSData *jsonData = jsonObject ? [NSJSONSerialization
-                                   dataWithJSONObject:jsonObject
-                                   options:(NSJSONWritingOptions)NSJSONReadingAllowFragments
-                                   error:error] : nil;
-  return jsonData ? [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding] : nil;
+    // Convert exception to error
+    if (error) {
+      *error = [NSError errorWithDomain:RCTErrorDomain code:0 userInfo:@{
+        NSLocalizedDescriptionKey: exception.description ?: @""
+      }];
+    }
+    return nil;
+  }
+}
+
+NSString *__nullable RCTJSONStringify(id __nullable jsonObject, NSError **error)
+{
+  if (error) {
+    return _RCTJSONStringifyNoRetry(jsonObject, error);
+  } else {
+    NSError *localError;
+    NSString *json = _RCTJSONStringifyNoRetry(jsonObject, &localError);
+    if (localError) {
+      RCTLogError(@"RCTJSONStringify() encountered the following error: %@",
+                  localError.localizedDescription);
+      // Sanitize the data, then retry. This is slow, but it prevents uncaught
+      // data issues from crashing in production
+      return _RCTJSONStringifyNoRetry(RCTJSONClean(jsonObject), NULL);
+    }
+    return json;
+  }
 }
 
 static id __nullable _RCTJSONParse(NSString *__nullable jsonString, BOOL mutable, NSError **error)
@@ -134,6 +169,14 @@ id RCTJSONClean(id object)
   });
 
   if ([validLeafTypes containsObject:[object classForCoder]]) {
+    if ([object isKindOfClass:[NSNumber class]]) {
+      return @(RCTZeroIfNaN([object doubleValue]));
+    }
+    if ([object isKindOfClass:[NSString class]]) {
+      if ([object UTF8String] == NULL) {
+        return (id)kCFNull;
+      }
+    }
     return object;
   }
 
diff --git a/React/Modules/RCTRedBox.m b/React/Modules/RCTRedBox.m
index 6379c1164dbb..b8717b15096e 100644
--- a/React/Modules/RCTRedBox.m
+++ b/React/Modules/RCTRedBox.m
@@ -91,7 +91,7 @@ - (void)dealloc
 
 - (void)openStackFrameInEditor:(NSDictionary *)stackFrame
 {
-  NSData *stackFrameJSON = [RCTJSONStringify(stackFrame, nil) dataUsingEncoding:NSUTF8StringEncoding];
+  NSData *stackFrameJSON = [RCTJSONStringify(stackFrame, NULL) dataUsingEncoding:NSUTF8StringEncoding];
   NSString *postLength = [NSString stringWithFormat:@"%tu", stackFrameJSON.length];
   NSMutableURLRequest *request = [NSMutableURLRequest new];
   request.URL = [RCTConvert NSURL:@"http://localhost:8081/open-stack-frame"];
diff --git a/React/Profiler/RCTProfile.m b/React/Profiler/RCTProfile.m
index 8bcf2a56e3cf..42cf74c638b8 100644
--- a/React/Profiler/RCTProfile.m
+++ b/React/Profiler/RCTProfile.m
@@ -81,7 +81,7 @@
     systrace_args[i].key = keyc;
     systrace_args[i].key_len = (int)strlen(keyc);
 
-    const char *valuec = RCTJSONStringify(value, nil).UTF8String;
+    const char *valuec = RCTJSONStringify(value, NULL).UTF8String;
     systrace_args[i].value = valuec;
     systrace_args[i].value_len = (int)strlen(valuec);
     i++;

From 5f0ef12cb59f5bf619c3f5b38a7b400f5fbb9b8b Mon Sep 17 00:00:00 2001
From: Alex Kotliarskyi <alex.frantic@gmail.com>
Date: Tue, 26 Jan 2016 08:20:18 -0800
Subject: [PATCH 0885/1411] Skip bundling for Simulator

Summary:
Following up on the conversation in https://www.prod.facebook.com/groups/reactnativeoss/permalink/1516993445263951/ I currently don't see any good reason to create an offline bundle for simulator builds.
Closes https://github.com/facebook/react-native/pull/5519

Reviewed By: svcscm

Differential Revision: D2859751

Pulled By: mkonicek

fb-gh-sync-id: f70481e447e258f5531de773729fc31d9ebec6f7
---
 packager/react-native-xcode.sh | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/packager/react-native-xcode.sh b/packager/react-native-xcode.sh
index 25533a853a03..c0ed7282fbf5 100755
--- a/packager/react-native-xcode.sh
+++ b/packager/react-native-xcode.sh
@@ -10,6 +10,13 @@
 # This script is supposed to be invoked as part of Xcode build process
 # and relies on envoronment variables (including PWD) set by Xcode
 
+# There is no point in creating an offline package for simulator builds
+# because the packager is supposed to be running during development anyways
+if [[ "$PLATFORM_NAME" = "iphonesimulator" ]]; then
+  echo "Skipping bundling for Simulator platform"
+  exit 0;
+fi
+
 case "$CONFIGURATION" in
   Debug)
     DEV=true

From 9a0539d2c48c528d44ddb53d6ea8343890b0ddaa Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Tue, 26 Jan 2016 10:29:47 -0800
Subject: [PATCH 0886/1411] Open source Android date and time pickers

Reviewed By: bestander

Differential Revision: D2856486

fb-gh-sync-id: 0bb81136289e2f121387649765ba682103e4701b
---
 .../UIExplorer/DatePickerAndroidExample.js    | 117 ++++++++++++
 Examples/UIExplorer/ListViewExample.js        |   4 +-
 Examples/UIExplorer/PickerAndroidExample.js   |  18 +-
 Examples/UIExplorer/RefreshControlExample.js  |   4 +-
 .../UIExplorer/TimePickerAndroidExample.js    | 112 +++++++++++
 Examples/UIExplorer/UIExplorerList.android.js |   2 +
 Libraries/Components/Clipboard/Clipboard.js   |  10 +-
 .../DatePickerAndroid.android.js              |  84 +++++++++
 .../DatePickerAndroid.ios.js                  |  24 +++
 .../TimePickerAndroid.android.js              |  67 +++++++
 .../TimePickerAndroid.ios.js                  |  24 +++
 .../ToastAndroid/ToastAndroid.ios.js          |   2 +-
 Libraries/react-native/react-native.js        |   2 +
 Libraries/react-native/react-native.js.flow   |   2 +
 .../com/facebook/react/bridge/Promise.java    |  38 +++-
 .../facebook/react/bridge/PromiseImpl.java    |  21 ++-
 .../modules/camera/CameraRollManager.java     |   9 +-
 .../facebook/react/modules/datepicker/BUCK    |  20 ++
 .../datepicker/DatePickerDialogFragment.java  | 103 ++++++++++
 .../datepicker/DatePickerDialogModule.java    | 176 ++++++++++++++++++
 .../DismissableDatePickerDialog.java          |  57 ++++++
 .../SupportDatePickerDialogFragment.java      |  51 +++++
 .../facebook/react/modules/timepicker/BUCK    |  20 ++
 .../DismissableTimePickerDialog.java          |  58 ++++++
 .../SupportTimePickerDialogFragment.java      |  50 +++++
 .../timepicker/TimePickerDialogFragment.java  |  78 ++++++++
 .../timepicker/TimePickerDialogModule.java    | 153 +++++++++++++++
 .../main/java/com/facebook/react/shell/BUCK   |   2 +
 .../react/shell/MainReactPackage.java         |   8 +-
 29 files changed, 1275 insertions(+), 41 deletions(-)
 create mode 100644 Examples/UIExplorer/DatePickerAndroidExample.js
 create mode 100644 Examples/UIExplorer/TimePickerAndroidExample.js
 create mode 100644 Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js
 create mode 100644 Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js
 create mode 100644 Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js
 create mode 100644 Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/DatePickerDialogFragment.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/DatePickerDialogModule.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/DismissableDatePickerDialog.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/SupportDatePickerDialogFragment.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/DismissableTimePickerDialog.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/SupportTimePickerDialogFragment.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/TimePickerDialogFragment.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/TimePickerDialogModule.java

diff --git a/Examples/UIExplorer/DatePickerAndroidExample.js b/Examples/UIExplorer/DatePickerAndroidExample.js
new file mode 100644
index 000000000000..e59517d91329
--- /dev/null
+++ b/Examples/UIExplorer/DatePickerAndroidExample.js
@@ -0,0 +1,117 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ */
+'use strict';
+
+var React = require('react-native');
+var {
+  DatePickerAndroid,
+  StyleSheet,
+  Text,
+  TouchableWithoutFeedback,
+} = React;
+
+var UIExplorerBlock = require('./UIExplorerBlock');
+var UIExplorerPage = require('./UIExplorerPage');
+
+var DatePickerAndroidExample = React.createClass({
+
+  statics: {
+    title: 'DatePickerAndroid',
+    description: 'Standard Android date picker dialog',
+  },
+
+  getInitialState() {
+    return {
+      presetDate: new Date(2020, 4, 5),
+      allDate: new Date(2020, 4, 5),
+      simpleText: 'pick a date',
+      minText: 'pick a date, no earlier than today',
+      maxText: 'pick a date, no later than today',
+      presetText: 'pick a date, preset to 2020/5/5',
+      allText: 'pick a date between 2020/5/1 and 2020/5/10',
+    };
+  },
+
+  async showPicker(stateKey, options) {
+    try {
+      var newState = {};
+      const {action, year, month, day} = await DatePickerAndroid.open(options);      
+      if (action === DatePickerAndroid.dismissedAction) {
+        newState[stateKey + 'Text'] = 'dismissed';
+      } else {
+        var date = new Date(year, month, day);
+        newState[stateKey + 'Text'] = date.toLocaleDateString();
+        newState[stateKey + 'Date'] = date;
+      }
+      this.setState(newState);
+    } catch ({code, message}) {
+      console.warn(`Error in example '${stateKey}': `, message);
+    }
+  },
+
+  render() {
+    return (
+      <UIExplorerPage title="DatePickerAndroid">
+        <UIExplorerBlock title="Simple date picker">
+          <TouchableWithoutFeedback
+            onPress={this.showPicker.bind(this, 'simple', {date: this.state.simpleDate})}>
+            <Text style={styles.text}>{this.state.simpleText}</Text>
+          </TouchableWithoutFeedback>
+        </UIExplorerBlock>
+        <UIExplorerBlock title="Date picker with pre-set date">
+          <TouchableWithoutFeedback
+            onPress={this.showPicker.bind(this, 'preset', {date: this.state.presetDate})}>
+            <Text style={styles.text}>{this.state.presetText}</Text>
+          </TouchableWithoutFeedback>
+        </UIExplorerBlock>
+        <UIExplorerBlock title="Date picker with minDate">
+          <TouchableWithoutFeedback
+            onPress={this.showPicker.bind(this, 'min', {
+              date: this.state.minDate,
+              minDate: new Date(),
+            })}>
+            <Text style={styles.text}>{this.state.minText}</Text>
+          </TouchableWithoutFeedback>
+        </UIExplorerBlock>
+        <UIExplorerBlock title="Date picker with maxDate">
+          <TouchableWithoutFeedback
+            onPress={this.showPicker.bind(this, 'max', {
+              date: this.state.maxDate,
+              maxDate: new Date(),
+            })}>
+            <Text style={styles.text}>{this.state.maxText}</Text>
+          </TouchableWithoutFeedback>
+        </UIExplorerBlock>
+        <UIExplorerBlock title="Date picker with all options">
+          <TouchableWithoutFeedback
+            onPress={this.showPicker.bind(this, 'all', {
+              date: this.state.allDate,
+              minDate: new Date(2020, 4, 1),
+              maxDate: new Date(2020, 4, 10),
+            })}>
+            <Text style={styles.text}>{this.state.allText}</Text>
+          </TouchableWithoutFeedback>
+          </UIExplorerBlock>
+      </UIExplorerPage>
+    );
+  },
+});
+
+var styles = StyleSheet.create({
+  text: {
+    color: 'black',
+  },
+});
+
+module.exports = DatePickerAndroidExample;
diff --git a/Examples/UIExplorer/ListViewExample.js b/Examples/UIExplorer/ListViewExample.js
index c4df7c7a969c..ef16151ed221 100644
--- a/Examples/UIExplorer/ListViewExample.js
+++ b/Examples/UIExplorer/ListViewExample.js
@@ -30,7 +30,7 @@ var UIExplorerPage = require('./UIExplorerPage');
 
 var ListViewSimpleExample = React.createClass({
   statics: {
-    title: '<ListView> - Simple',
+    title: '<ListView>',
     description: 'Performant, scrollable list of data.'
   },
 
@@ -50,7 +50,7 @@ var ListViewSimpleExample = React.createClass({
   render: function() {
     return (
       <UIExplorerPage
-        title={this.props.navigator ? null : '<ListView> - Simple'}
+        title={this.props.navigator ? null : '<ListView>'}
         noSpacer={true}
         noScroll={true}>
         <ListView
diff --git a/Examples/UIExplorer/PickerAndroidExample.js b/Examples/UIExplorer/PickerAndroidExample.js
index 91a2bd5a405e..947a0129ea20 100644
--- a/Examples/UIExplorer/PickerAndroidExample.js
+++ b/Examples/UIExplorer/PickerAndroidExample.js
@@ -27,6 +27,12 @@ const {
 const Item = PickerAndroid.Item;
 
 const PickerAndroidExample = React.createClass({
+
+  statics: {
+    title: '<PickerAndroid>',
+    description: 'Provides multiple options to choose from, using either a dropdown menu or a dialog.',
+  },
+
   getInitialState: function() {
     return {
       selected1: 'key1',
@@ -124,19 +130,11 @@ const PickerAndroidExample = React.createClass({
     this.setState({mode: newMode});
   },
 
-  onSelect: function(key, value) {
+  onSelect: function(key: string, value: string) {
     const newState = {};
     newState[key] = value;
     this.setState(newState);
   },
 });
 
-exports.title = '<PickerAndroid>';
-exports.displayName = 'PickerAndroidExample';
-exports.description = 'The Android Picker component provides multiple options to choose from';
-exports.examples = [
-  {
-    title: 'PickerAndroidExample',
-    render(): ReactElement { return <PickerAndroidExample />; }
-  },
-];
+module.exports = PickerAndroidExample;
diff --git a/Examples/UIExplorer/RefreshControlExample.js b/Examples/UIExplorer/RefreshControlExample.js
index b8feefb661db..f56c9fed5188 100644
--- a/Examples/UIExplorer/RefreshControlExample.js
+++ b/Examples/UIExplorer/RefreshControlExample.js
@@ -69,7 +69,7 @@ const RefreshControlExample = React.createClass({
       isRefreshing: false,
       loaded: 0,
       rowData: Array.from(new Array(20)).map(
-        (val, i) => ({text: 'Initial row' + i, clicks: 0})),
+        (val, i) => ({text: 'Initial row ' + i, clicks: 0})),
     };
   },
 
@@ -108,7 +108,7 @@ const RefreshControlExample = React.createClass({
       // prepend 10 items
       const rowData = Array.from(new Array(10))
       .map((val, i) => ({
-        text: 'Loaded row' + (+this.state.loaded + i),
+        text: 'Loaded row ' + (+this.state.loaded + i),
         clicks: 0,
       }))
       .concat(this.state.rowData);
diff --git a/Examples/UIExplorer/TimePickerAndroidExample.js b/Examples/UIExplorer/TimePickerAndroidExample.js
new file mode 100644
index 000000000000..06733fc35c88
--- /dev/null
+++ b/Examples/UIExplorer/TimePickerAndroidExample.js
@@ -0,0 +1,112 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ */
+'use strict';
+
+var React = require('react-native');
+var {
+  TimePickerAndroid,
+  StyleSheet,
+  Text,
+  TouchableWithoutFeedback,
+} = React;
+
+var UIExplorerBlock = require('./UIExplorerBlock');
+var UIExplorerPage = require('./UIExplorerPage');
+
+var TimePickerAndroidExample = React.createClass({
+
+  statics: {
+    title: 'TimePickerAndroid',
+    description: 'Standard Android time picker dialog',
+  },
+
+  getInitialState() {
+    // *Text, *Hour and *Minute are set by successCallback -- this updates the text with the time
+    // picked by the user and makes it so the next time they open it the hour and minute they picked
+    // before is displayed.
+    return {
+      isoFormatText: 'pick a time (24-hour format)',
+      presetHour: 4,
+      presetMinute: 4,
+      presetText: 'pick a time, default: 4:04AM',
+      simpleText: 'pick a time',
+    };
+  },
+
+  async showPicker(stateKey, options) {
+    try {
+      const {action, minute, hour} = await TimePickerAndroid.open(options);
+      var newState = {};
+      if (action === TimePickerAndroid.timeSetAction) {
+        newState[stateKey + 'Text'] = _formatTime(hour, minute);
+        newState[stateKey + 'Hour'] = hour;
+        newState[stateKey + 'Minute'] = minute;
+      } else if (action === TimePickerAndroid.dismissedAction) {
+        newState[stateKey + 'Text'] = 'dismissed';
+      }
+      this.setState(newState);
+    } catch ({code, message}) {
+      console.warn(`Error in example '${stateKey}': `, message);
+    }
+  },
+
+  render() {
+    return (
+      <UIExplorerPage title="TimePickerAndroid">
+        <UIExplorerBlock title="Simple time picker">
+          <TouchableWithoutFeedback
+            onPress={this.showPicker.bind(this, 'simple')}>
+            <Text style={styles.text}>{this.state.simpleText}</Text>
+          </TouchableWithoutFeedback>
+        </UIExplorerBlock>
+        <UIExplorerBlock title="Time picker with pre-set time">
+          <TouchableWithoutFeedback
+            onPress={this.showPicker.bind(this, 'preset', {
+              hour: this.state.presetHour,
+              minute: this.state.presetMinute,
+            })}>
+            <Text style={styles.text}>{this.state.presetText}</Text>
+          </TouchableWithoutFeedback>
+        </UIExplorerBlock>
+
+        <UIExplorerBlock title="Time picker with 24-hour time format">
+          <TouchableWithoutFeedback
+            onPress={this.showPicker.bind(this, 'isoFormat', {
+              hour: this.state.isoFormatHour,
+              minute: this.state.isoFormatMinute,
+              is24Hour: true,
+            })}>
+            <Text style={styles.text}>{this.state.isoFormatText}</Text>
+          </TouchableWithoutFeedback>
+        </UIExplorerBlock>
+      </UIExplorerPage>
+    );
+  },
+});
+
+/**
+ * Returns e.g. '3:05'.
+ */
+function _formatTime(hour, minute) {
+  return hour + ':' + (minute < 10 ? '0' + minute : minute);
+}
+
+var styles = StyleSheet.create({
+  text: {
+    color: 'black',
+  },
+});
+
+module.exports = TimePickerAndroidExample;
+
diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index 01e8a331e62a..66caeef51b5f 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -47,6 +47,7 @@ var APIS = [
   require('./BorderExample'),
   require('./CameraRollExample'),
   require('./ClipboardExample'),
+  require('./DatePickerAndroidExample'),
   require('./GeolocationExample'),
   require('./IntentAndroidExample.android'),
   require('./LayoutEventsExample'),
@@ -54,6 +55,7 @@ var APIS = [
   require('./NetInfoExample'),
   require('./PanResponderExample'),
   require('./PointerEventsExample'),
+  require('./TimePickerAndroidExample'),
   require('./TimerExample'),
   require('./ToastAndroidExample.android'),
   require('./XHRExample'),
diff --git a/Libraries/Components/Clipboard/Clipboard.js b/Libraries/Components/Clipboard/Clipboard.js
index 9b3ef5950735..b09bc5b2f7b9 100644
--- a/Libraries/Components/Clipboard/Clipboard.js
+++ b/Libraries/Components/Clipboard/Clipboard.js
@@ -26,10 +26,10 @@ module.exports = {
    */
   getString() {
     if (arguments.length > 0) {
-        let callback = arguments[0];
-        console.warn('Clipboard.getString(callback) is deprecated. Use the returned Promise instead');
-        Clipboard.getString().then(callback);
-        return;
+      let callback = arguments[0];
+      console.warn('Clipboard.getString(callback) is deprecated. Use the returned Promise instead');
+      Clipboard.getString().then(callback);
+      return;
     }
     return Clipboard.getString();
   },
@@ -40,7 +40,7 @@ module.exports = {
    *   Clipboard.setString('hello world');
    * }
    * ```
-   * @param this parameter is content that will be set into clipboard.
+   * @param the content to be stored in the clipboard.
    */
   setString(content) {
     Clipboard.setString(content);
diff --git a/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js
new file mode 100644
index 000000000000..d446544c6aec
--- /dev/null
+++ b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js
@@ -0,0 +1,84 @@
+/**
+ * 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 DatePickerAndroid
+ * @flow
+ */
+'use strict';
+
+const DatePickerModule = require('NativeModules').DatePickerAndroid;
+
+/**
+ * Convert a Date to a timestamp.
+ */
+function _toMillis(options: Object, key: string) {
+  const dateVal = options[key];
+  // Is it a Date object?
+  if (typeof dateVal === 'object' && typeof dateVal.getMonth === 'function') {
+    options[key] = dateVal.getTime();
+  }
+}
+
+/**
+ * Opens the standard Android date picker dialog.
+ *
+ * ### Example
+ *
+ * ```
+ * try {
+ *   const {action, year, month, day} = await DatePickerAndroid.open({
+ *     // Use `new Date()` for current date.
+ *     // May 25 2020. Month 0 is January.
+ *     date: new Date(2020, 4, 25)
+ *   });
+ *   if (action !== DatePickerAndroid.dismissedAction) {
+ *     // Selected year, month (0-11), day
+ *   }
+ * } catch ({code, message}) {
+ *   console.warn('Cannot open date picker', message);
+ * }
+ * ```
+ */
+class DatePickerAndroid {
+  /**
+   * Opens the standard Android date picker dialog.
+   *
+   * The available keys for the `options` object are:
+   *   * `date` (`Date` object or timestamp in milliseconds) - date to show by default
+   *   * `minDate` (`Date` or timestamp in milliseconds) - minimum date that can be selected
+   *   * `maxDate` (`Date` object or timestamp in milliseconds) - minimum date that can be selected
+   * 
+   * Returns a Promise which will be invoked an object containing `action`, `year`, `month` (0-11),
+   * `day` if the user picked a date. If the user dismissed the dialog, the Promise will
+   * still be resolved with action being `DatePickerAndroid.dismissedAction` and all the other keys
+   * being undefined. **Always** check whether the `action` before reading the values.
+   *
+   * Note the native date picker dialog has some UI glitches on Android 4 and lower
+   * when using the `minDate` and `maxDate` options.
+   */
+  static async open(options: Object): Promise<Object> {
+    let optionsMs = options;
+    if (optionsMs) {
+      _toMillis(options, 'date');
+      _toMillis(options, 'minDate');
+      _toMillis(options, 'maxDate');
+    }
+    return DatePickerModule.open(options);
+  }
+
+  /**
+   * A date has been selected.
+   */
+  static get dateSetAction() { return 'dateSetAction'; }
+  /**
+   * The dialog has been dismissed.
+   */
+  static get dismissedAction() { return 'dismissedAction'; }
+}
+
+module.exports = DatePickerAndroid;
diff --git a/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js
new file mode 100644
index 000000000000..b0ab643fa23d
--- /dev/null
+++ b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js
@@ -0,0 +1,24 @@
+/**
+ * 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 DatePickerAndroid
+ * @flow
+ */
+'use strict';
+
+var warning = require('warning');
+
+const DatePickerAndroid = {
+  async open(options: Object): Promise<Object> {
+    return Promise.reject({
+      message: 'DatePickerAndroid is not supported on this platform.'
+    });
+  },
+}
+
+module.exports = DatePickerAndroid;
diff --git a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js
new file mode 100644
index 000000000000..98bf034a8e02
--- /dev/null
+++ b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js
@@ -0,0 +1,67 @@
+/**
+ * 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 TimePickerAndroid
+ * @flow
+ */
+'use strict';
+
+const TimePickerModule = require('NativeModules').TimePickerAndroid;
+
+/**
+ * Opens the standard Android time picker dialog.
+ *
+ * ### Example
+ *
+ * ```
+ * try {
+ *   const {action, hour, minute} = await TimePickerAndroid.open({
+ *     hour: 14,
+ *     minute: 0,
+ *     is24Hour: false, // Will display '2 PM'
+ *   });
+ *   if (action !== DatePickerAndroid.dismissedAction) {
+ *     // Selected hour (0-23), minute (0-59)
+ *   }
+ * } catch ({code, message}) {
+ *   console.warn('Cannot open time picker', message);
+ * }
+ * ```
+ */
+class TimePickerAndroid {
+
+  /**
+   * Opens the standard Android time picker dialog.
+   *
+   * The available keys for the `options` object are:
+   *   * `hour` (0-23) - the hour to show, defaults to the current time
+   *   * `minute` (0-59) - the minute to show, defaults to the current time
+   *   * `is24Hour` (boolean) - If `true`, the picker uses the 24-hour format. If `false`,
+   *     the picker shows an AM/PM chooser. If undefined, the default for the current locale
+   *     is used.
+   *
+   * Returns a Promise which will be invoked an object containing `action`, `hour` (0-23),
+   * `minute` (0-59) if the user picked a time. If the user dismissed the dialog, the Promise will
+   * still be resolved with action being `TimePickerAndroid.dismissedAction` and all the other keys
+   * being undefined. **Always** check whether the `action` before reading the values.
+   */
+  static async open(options: Object): Promise<Object> {
+    return TimePickerModule.open(options);
+  }
+
+  /**
+   * A time has been selected.
+   */
+  static get timeSetAction() { return 'timeSetAction'; }
+  /**
+   * The dialog has been dismissed.
+   */
+  static get dismissedAction() { return 'dismissedAction'; }
+};
+
+module.exports = TimePickerAndroid;
diff --git a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js
new file mode 100644
index 000000000000..df993ba92275
--- /dev/null
+++ b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js
@@ -0,0 +1,24 @@
+/**
+ * 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 TimePickerAndroid
+ * @flow
+ */
+'use strict';
+
+var warning = require('warning');
+
+const TimePickerAndroid = {
+  async open(options: Object): Promise<Object> {
+    return Promise.reject({
+      message: 'TimePickerAndroid is not supported on this platform.'
+    });
+  },
+}
+
+module.exports = TimePickerAndroid;
diff --git a/Libraries/Components/ToastAndroid/ToastAndroid.ios.js b/Libraries/Components/ToastAndroid/ToastAndroid.ios.js
index 087786e08937..8eb79dfb0dff 100644
--- a/Libraries/Components/ToastAndroid/ToastAndroid.ios.js
+++ b/Libraries/Components/ToastAndroid/ToastAndroid.ios.js
@@ -19,7 +19,7 @@ var ToastAndroid = {
     message: string,
     duration: number
   ): void {
-    warning(false, 'Cannot use ToastAndroid on iOS.');
+    warning(false, 'ToastAndroid is not supported on this platform.');
   },
 
 };
diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js
index ade020c539de..865ee0cabe16 100644
--- a/Libraries/react-native/react-native.js
+++ b/Libraries/react-native/react-native.js
@@ -66,6 +66,7 @@ var ReactNative = {
   get BackAndroid() { return require('BackAndroid'); },
   get CameraRoll() { return require('CameraRoll'); },
   get Clipboard() { return require('Clipboard'); },
+  get DatePickerAndroid() { return require('DatePickerAndroid'); },
   get Dimensions() { return require('Dimensions'); },
   get Easing() { return require('Easing'); },
   get ImagePickerIOS() { return require('ImagePickerIOS'); },
@@ -80,6 +81,7 @@ var ReactNative = {
   get Settings() { return require('Settings'); },
   get StatusBarIOS() { return require('StatusBarIOS'); },
   get StyleSheet() { return require('StyleSheet'); },
+  get TimePickerAndroid() { return require('TimePickerAndroid'); },
   get UIManager() { return require('UIManager'); },
   get VibrationIOS() { return require('VibrationIOS'); },
 
diff --git a/Libraries/react-native/react-native.js.flow b/Libraries/react-native/react-native.js.flow
index 618eb2e05b1e..17d46a0af2e8 100644
--- a/Libraries/react-native/react-native.js.flow
+++ b/Libraries/react-native/react-native.js.flow
@@ -78,6 +78,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
   BackAndroid: require('BackAndroid'),
   CameraRoll: require('CameraRoll'),
   Clipboard: require('Clipboard'),
+  DatePickerAndroid: require('DatePickerAndroid'),
   Dimensions: require('Dimensions'),
   Easing: require('Easing'),
   ImagePickerIOS: require('ImagePickerIOS'),
@@ -92,6 +93,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
   Settings: require('Settings'),
   StatusBarIOS: require('StatusBarIOS'),
   StyleSheet: require('StyleSheet'),
+  TimePickerAndroid: require('TimePickerAndroid'),
   UIManager: require('UIManager'),
   VibrationIOS: require('VibrationIOS'),
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/Promise.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/Promise.java
index 5b107fd99a8d..87a9b4b53511 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/Promise.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/Promise.java
@@ -9,8 +9,6 @@
 
 package com.facebook.react.bridge;
 
-import javax.annotation.Nullable;
-
 /**
  * Interface that represents a JavaScript Promise which can be passed to the native module as a
  * method parameter.
@@ -19,10 +17,38 @@
  * will be marked as "remoteAsync" and will return a promise when invoked from JavaScript.
  */
 public interface Promise {
+
+  /**
+   * Successfully resolve the Promise.
+   */
   void resolve(Object value);
-  void reject(Throwable reason);
+
+  /**
+   * Report an error which wasn't caused by an exception.
+   */
+  void reject(String code, String message);
+
+  /**
+   * Report an exception.
+   */
+  void reject(String code, Throwable e);
+
+  /**
+   * Report an exception with a custom error message.
+   */
+  void reject(String code, String message, Throwable e);
+
+  /**
+   * Report an error which wasn't caused by an exception.
+   * @deprecated Prefer passing a module-specific error code to JS.
+   *             Using this method will pass the error code "EUNSPECIFIED".
+   */
   @Deprecated
-  void reject(String reason);
-  void reject(String code, Throwable extra);
-  void reject(String code, String reason, @Nullable Throwable extra);
+  void reject(String message);
+
+  /**
+   * Report an exception, with default error code.
+   * Useful in catch-all scenarios where it's unclear why the error occurred.
+   */
+  void reject(Throwable reason);
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/PromiseImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/PromiseImpl.java
index 0c1c85c9e6d6..519448f6d9ed 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/PromiseImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/PromiseImpl.java
@@ -34,23 +34,28 @@ public void resolve(Object value) {
   }
 
   @Override
-  public void reject(Throwable reason) {
-    reject(DEFAULT_ERROR, reason.getMessage(), reason);
+  public void reject(String code, String message) {
+    reject(code, message, /*Throwable*/null);
   }
 
   @Override
   @Deprecated
-  public void reject(String reason) {
-    reject(DEFAULT_ERROR, reason, null);
+  public void reject(String message) {
+    reject(DEFAULT_ERROR, message, /*Throwable*/null);
   }
 
   @Override
-  public void reject(String code, Throwable extra) {
-    reject(code, extra.getMessage(), extra);
+  public void reject(String code, Throwable e) {
+    reject(code, e.getMessage(), e);
   }
 
   @Override
-  public void reject(String code, String reason, @Nullable Throwable extra) {
+  public void reject(Throwable e) {
+    reject(DEFAULT_ERROR, e.getMessage(), e);
+  }
+
+  @Override
+  public void reject(String code, String message, @Nullable Throwable e) {
     if (mReject != null) {
       if (code == null) {
         code = DEFAULT_ERROR;
@@ -60,7 +65,7 @@ public void reject(String code, String reason, @Nullable Throwable extra) {
       // error instance.
       WritableNativeMap errorInfo = new WritableNativeMap();
       errorInfo.putString("code", code);
-      errorInfo.putString("message", reason);
+      errorInfo.putString("message", message);
       // TODO(8850038): add the stack trace info in, need to figure out way to serialize that
       mReject.invoke(errorInfo);
     }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/CameraRollManager.java b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/CameraRollManager.java
index 357586aa13c6..e5302355c7e4 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/CameraRollManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/CameraRollManager.java
@@ -59,7 +59,6 @@
  */
 public class CameraRollManager extends ReactContextBaseJavaModule {
 
-  private static final String TAG = "Catalyst/CameraRollManager";
   private static final String ERROR_UNABLE_TO_LOAD = "E_UNABLE_TO_LOAD";
   private static final String ERROR_UNABLE_TO_LOAD_PERMISSION = "E_UNABLE_TO_LOAD_PERMISSION";
   private static final String ERROR_UNABLE_TO_SAVE = "E_UNABLE_TO_SAVE";
@@ -145,7 +144,7 @@ protected void doInBackgroundGuarded(Void... params) {
             Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
         pictures.mkdirs();
         if (!pictures.isDirectory()) {
-          mPromise.reject(ERROR_UNABLE_TO_LOAD, "External storage pictures directory not available", null);
+          mPromise.reject(ERROR_UNABLE_TO_LOAD, "External storage pictures directory not available");
           return;
         }
         File dest = new File(pictures, source.getName());
@@ -178,7 +177,7 @@ public void onScanCompleted(String path, Uri uri) {
                 if (uri != null) {
                   mPromise.resolve(uri.toString());
                 } else {
-                  mPromise.reject(ERROR_UNABLE_TO_SAVE, "Could not add image to gallery", null);
+                  mPromise.reject(ERROR_UNABLE_TO_SAVE, "Could not add image to gallery");
                 }
               }
             });
@@ -302,7 +301,7 @@ protected void doInBackgroundGuarded(Void... params) {
             Images.Media.DATE_TAKEN + " DESC, " + Images.Media.DATE_MODIFIED + " DESC LIMIT " +
                 (mFirst + 1)); // set LIMIT to first + 1 so that we know how to populate page_info
         if (photos == null) {
-          mPromise.reject(ERROR_UNABLE_TO_LOAD, "Could not get photos", null);
+          mPromise.reject(ERROR_UNABLE_TO_LOAD, "Could not get photos");
         } else {
           try {
             putEdges(resolver, photos, response, mFirst);
@@ -412,7 +411,7 @@ private static boolean putImageInfo(
         width = options.outWidth;
         height = options.outHeight;
       } catch (IOException e) {
-        FLog.e(TAG, "Could not get width/height for " + photoUri.toString(), e);
+        FLog.e(ReactConstants.TAG, "Could not get width/height for " + photoUri.toString(), e);
         return false;
       }
     }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/BUCK
new file mode 100644
index 000000000000..d53004753df3
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/BUCK
@@ -0,0 +1,20 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'datepicker',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_dep('third-party/android/support/v4:lib-support-v4'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':datepicker',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/DatePickerDialogFragment.java b/ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/DatePickerDialogFragment.java
new file mode 100644
index 000000000000..6568f35041d9
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/DatePickerDialogFragment.java
@@ -0,0 +1,103 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.modules.datepicker;
+
+import javax.annotation.Nullable;
+
+import java.util.Calendar;
+
+import android.annotation.SuppressLint;
+import android.app.DatePickerDialog;
+import android.app.DatePickerDialog.OnDateSetListener;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnDismissListener;
+import android.os.Bundle;
+import android.widget.DatePicker;
+
+@SuppressLint("ValidFragment")
+public class DatePickerDialogFragment extends DialogFragment {
+
+  /**
+   * Minimum date supported by {@link DatePicker}, 01 Jan 1900
+   */
+  private static final long DEFAULT_MIN_DATE = -2208988800001l;
+
+  @Nullable
+  private OnDateSetListener mOnDateSetListener;
+  @Nullable
+  private OnDismissListener mOnDismissListener;
+
+  @Override
+  public Dialog onCreateDialog(Bundle savedInstanceState) {
+    Bundle args = getArguments();
+    return createDialog(args, getActivity(), mOnDateSetListener);
+  }
+
+  /*package*/ static Dialog createDialog(
+      Bundle args, Context activityContext, @Nullable OnDateSetListener onDateSetListener) {
+    final Calendar c = Calendar.getInstance();
+    if (args != null && args.containsKey(DatePickerDialogModule.ARG_DATE)) {
+      c.setTimeInMillis(args.getLong(DatePickerDialogModule.ARG_DATE));
+    }
+    final int year = c.get(Calendar.YEAR);
+    final int month = c.get(Calendar.MONTH);
+    final int day = c.get(Calendar.DAY_OF_MONTH);
+
+    final DatePickerDialog dialog =
+        new DismissableDatePickerDialog(activityContext, onDateSetListener, year, month, day);
+    final DatePicker datePicker = dialog.getDatePicker();
+
+    if (args != null && args.containsKey(DatePickerDialogModule.ARG_MINDATE)) {
+      // Set minDate to the beginning of the day. We need this because of clowniness in datepicker
+      // that causes it to throw an exception if minDate is greater than the internal timestamp
+      // that it generates from the y/m/d passed in the constructor.
+      c.setTimeInMillis(args.getLong(DatePickerDialogModule.ARG_MINDATE));
+      c.set(Calendar.HOUR_OF_DAY, 0);
+      c.set(Calendar.MINUTE, 0);
+      c.set(Calendar.SECOND, 0);
+      c.set(Calendar.MILLISECOND, 0);
+      datePicker.setMinDate(c.getTimeInMillis());
+    } else {
+      // This is to work around a bug in DatePickerDialog where it doesn't display a title showing
+      // the date under certain conditions.
+      datePicker.setMinDate(DEFAULT_MIN_DATE);
+    }
+    if (args != null && args.containsKey(DatePickerDialogModule.ARG_MAXDATE)) {
+      // Set maxDate to the end of the day, same reason as for minDate.
+      c.setTimeInMillis(args.getLong(DatePickerDialogModule.ARG_MAXDATE));
+      c.set(Calendar.HOUR_OF_DAY, 23);
+      c.set(Calendar.MINUTE, 59);
+      c.set(Calendar.SECOND, 59);
+      c.set(Calendar.MILLISECOND, 999);
+      datePicker.setMaxDate(c.getTimeInMillis());
+    }
+
+    return dialog;
+  }
+
+  @Override
+  public void onDismiss(DialogInterface dialog) {
+    super.onDismiss(dialog);
+    if (mOnDismissListener != null) {
+      mOnDismissListener.onDismiss(dialog);
+    }
+  }
+
+  /*package*/ void setOnDateSetListener(@Nullable OnDateSetListener onDateSetListener) {
+    mOnDateSetListener = onDateSetListener;
+  }
+
+  /*package*/ void setOnDismissListener(@Nullable OnDismissListener onDismissListener) {
+    mOnDismissListener = onDismissListener;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/DatePickerDialogModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/DatePickerDialogModule.java
new file mode 100644
index 000000000000..6f76ea7e4098
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/DatePickerDialogModule.java
@@ -0,0 +1,176 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.modules.datepicker;
+
+import javax.annotation.Nullable;
+
+import java.util.Map;
+
+import android.app.Activity;
+import android.app.DatePickerDialog.OnDateSetListener;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnDismissListener;
+import android.os.Bundle;
+import android.widget.DatePicker;
+
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.Promise;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.bridge.WritableNativeMap;
+import com.facebook.react.common.annotations.VisibleForTesting;
+
+/**
+ * {@link NativeModule} that allows JS to show a native date picker dialog and get called back when
+ * the user selects a date.
+ */
+public class DatePickerDialogModule extends ReactContextBaseJavaModule {
+
+  @VisibleForTesting
+  public static final String FRAGMENT_TAG = "DatePickerAndroid";
+
+  private static final String ERROR_NO_ACTIVITY = "E_NO_ACTIVITY";
+
+  /* package */ static final String ARG_DATE = "date";
+  /* package */ static final String ARG_MINDATE = "minDate";
+  /* package */ static final String ARG_MAXDATE = "maxDate";
+
+  /* package */ static final String ACTION_DATE_SET = "dateSetAction";
+  /* package */ static final String ACTION_DISMISSED = "dismissedAction";
+
+  public DatePickerDialogModule(ReactApplicationContext reactContext) {
+    super(reactContext);
+  }
+
+  @Override
+  public String getName() {
+    return "DatePickerAndroid";
+  }
+
+  private class DatePickerDialogListener implements OnDateSetListener, OnDismissListener {
+
+    private final Promise mPromise;
+    private boolean mPromiseResolved = false;
+
+    public DatePickerDialogListener(final Promise promise) {
+      mPromise = promise;
+    }
+
+    @Override
+    public void onDateSet(DatePicker view, int year, int month, int day) {
+      if (!mPromiseResolved && getReactApplicationContext().hasActiveCatalystInstance()) {
+        WritableMap result = new WritableNativeMap();
+        result.putString("action", ACTION_DATE_SET);
+        result.putInt("year", year);
+        result.putInt("month", month);
+        result.putInt("day", day);
+        mPromise.resolve(result);
+        mPromiseResolved = true;
+      }
+    }
+
+    @Override
+    public void onDismiss(DialogInterface dialog) {
+      if (!mPromiseResolved && getReactApplicationContext().hasActiveCatalystInstance()) {
+        WritableMap result = new WritableNativeMap();
+        result.putString("action", ACTION_DISMISSED);
+        mPromise.resolve(result);
+        mPromiseResolved = true;
+      }
+    }
+  }
+
+  /**
+   * Show a date picker dialog.
+   *
+   * @param options a map containing options. Available keys are:
+   *
+   * <ul>
+   *   <li>{@code date} (timestamp in milliseconds) the date to show by default</li>
+   *   <li>
+   *     {@code minDate} (timestamp in milliseconds) the minimum date the user should be allowed
+   *     to select
+   *   </li>
+   *   <li>
+   *     {@code maxDate} (timestamp in milliseconds) the maximum date the user should be allowed
+   *     to select
+   *    </li>
+   * </ul>
+   *
+   * @param promise This will be invoked with parameters action, year,
+   *                month (0-11), day, where action is {@code dateSetAction} or
+   *                {@code dismissedAction}, depending on what the user did. If the action is
+   *                dismiss, year, month and date are undefined.
+   */
+  @ReactMethod
+  public void open(@Nullable final ReadableMap options, Promise promise) {
+    Activity activity = getCurrentActivity();
+    if (activity == null) {
+      promise.reject(
+          ERROR_NO_ACTIVITY,
+          "Tried to open a DatePicker dialog while not attached to an Activity");
+      return;
+    }
+    // We want to support both android.app.Activity and the pre-Honeycomb FragmentActivity
+    // (for apps that use it for legacy reasons). This unfortunately leads to some code duplication.
+    if (activity instanceof android.support.v4.app.FragmentActivity) {
+      android.support.v4.app.FragmentManager fragmentManager =
+          ((android.support.v4.app.FragmentActivity) activity).getSupportFragmentManager();
+      android.support.v4.app.DialogFragment oldFragment =
+          (android.support.v4.app.DialogFragment)fragmentManager.findFragmentByTag(FRAGMENT_TAG);
+      if (oldFragment != null) {
+        oldFragment.dismiss();
+      }
+      SupportDatePickerDialogFragment fragment = new SupportDatePickerDialogFragment();
+      if (options != null) {
+        final Bundle args = createFragmentArguments(options);
+        fragment.setArguments(args);
+      }
+      final DatePickerDialogListener listener = new DatePickerDialogListener(promise);
+      fragment.setOnDismissListener(listener);
+      fragment.setOnDateSetListener(listener);
+      fragment.show(fragmentManager, FRAGMENT_TAG);
+    } else {
+      FragmentManager fragmentManager = activity.getFragmentManager();
+      DialogFragment oldFragment = (DialogFragment)fragmentManager.findFragmentByTag(FRAGMENT_TAG);
+      if (oldFragment != null) {
+        oldFragment.dismiss();
+      }
+      DatePickerDialogFragment fragment = new DatePickerDialogFragment();
+      if (options != null) {
+        final Bundle args = createFragmentArguments(options);
+        fragment.setArguments(args);
+      }
+      final DatePickerDialogListener listener = new DatePickerDialogListener(promise);
+      fragment.setOnDismissListener(listener);
+      fragment.setOnDateSetListener(listener);
+      fragment.show(fragmentManager, FRAGMENT_TAG);
+    }
+  }
+
+  private Bundle createFragmentArguments(ReadableMap options) {
+    final Bundle args = new Bundle();
+    if (options.hasKey(ARG_DATE) && !options.isNull(ARG_DATE)) {
+      args.putLong(ARG_DATE, (long) options.getDouble(ARG_DATE));
+    }
+    if (options.hasKey(ARG_MINDATE) && !options.isNull(ARG_MINDATE)) {
+      args.putLong(ARG_MINDATE, (long) options.getDouble(ARG_MINDATE));
+    }
+    if (options.hasKey(ARG_MAXDATE) && !options.isNull(ARG_MAXDATE)) {
+      args.putLong(ARG_MAXDATE, (long) options.getDouble(ARG_MAXDATE));
+    }
+    return args;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/DismissableDatePickerDialog.java b/ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/DismissableDatePickerDialog.java
new file mode 100644
index 000000000000..57791948ea80
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/DismissableDatePickerDialog.java
@@ -0,0 +1,57 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.modules.datepicker;
+
+import javax.annotation.Nullable;
+
+import android.app.DatePickerDialog;
+import android.content.Context;
+import android.os.Build;
+
+/**
+ * <p>
+ *   Certain versions of Android (Jellybean-KitKat) have a bug where when dismissed, the
+ *   {@link DatePickerDialog} still calls the OnDateSetListener. This class works around that issue.
+ * </p>
+ *
+ * <p>
+ *   See: <a href="https://code.google.com/p/android/issues/detail?id=34833">Issue 34833</a>
+ * </p>
+ */
+public class DismissableDatePickerDialog extends DatePickerDialog {
+
+  public DismissableDatePickerDialog(
+      Context context,
+      @Nullable OnDateSetListener callback,
+      int year,
+      int monthOfYear,
+      int dayOfMonth) {
+    super(context, callback, year, monthOfYear, dayOfMonth);
+  }
+
+  public DismissableDatePickerDialog(
+      Context context,
+      int theme,
+      @Nullable OnDateSetListener callback,
+      int year,
+      int monthOfYear,
+      int dayOfMonth) {
+    super(context, theme, callback, year, monthOfYear, dayOfMonth);
+  }
+
+  @Override
+  protected void onStop() {
+    // do *not* call super.onStop() on KitKat on lower, as that would erroneously call the
+    // OnDateSetListener when the dialog is dismissed, or call it twice when "OK" is pressed.
+    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
+      super.onStop();
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/SupportDatePickerDialogFragment.java b/ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/SupportDatePickerDialogFragment.java
new file mode 100644
index 000000000000..d935d58d84d5
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/SupportDatePickerDialogFragment.java
@@ -0,0 +1,51 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.modules.datepicker;
+
+import javax.annotation.Nullable;
+
+import android.annotation.SuppressLint;
+import android.app.DatePickerDialog.OnDateSetListener;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnDismissListener;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+
+@SuppressLint("ValidFragment")
+public class SupportDatePickerDialogFragment extends DialogFragment {
+
+  @Nullable
+  private OnDateSetListener mOnDateSetListener;
+  @Nullable
+  private OnDismissListener mOnDismissListener;
+
+  @Override
+  public Dialog onCreateDialog(Bundle savedInstanceState) {
+    final Bundle args = getArguments();
+    return DatePickerDialogFragment.createDialog(args, getActivity(), mOnDateSetListener);
+  }
+
+  @Override
+  public void onDismiss(DialogInterface dialog) {
+    super.onDismiss(dialog);
+    if (mOnDismissListener != null) {
+      mOnDismissListener.onDismiss(dialog);
+    }
+  }
+
+  /*package*/ void setOnDateSetListener(@Nullable OnDateSetListener onDateSetListener) {
+    mOnDateSetListener = onDateSetListener;
+  }
+
+  /*package*/ void setOnDismissListener(@Nullable OnDismissListener onDismissListener) {
+    mOnDismissListener = onDismissListener;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/BUCK
new file mode 100644
index 000000000000..1b7d3eac350c
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/BUCK
@@ -0,0 +1,20 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'timepicker',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_dep('third-party/android/support/v4:lib-support-v4'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':timepicker',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/DismissableTimePickerDialog.java b/ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/DismissableTimePickerDialog.java
new file mode 100644
index 000000000000..3baf4c924166
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/DismissableTimePickerDialog.java
@@ -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.
+ */
+
+package com.facebook.react.modules.timepicker;
+
+import javax.annotation.Nullable;
+
+import android.app.TimePickerDialog;
+import android.content.Context;
+import android.os.Build;
+
+/**
+ * <p>
+ *   Certain versions of Android (Jellybean-KitKat) have a bug where when dismissed, the
+ *   {@link TimePickerDialog} still calls the OnTimeSetListener. This class works around that issue
+ *   by *not* calling super.onStop on KitKat on lower, as that would erroneously call the
+ *   OnTimeSetListener when the dialog is dismissed, or call it twice when "OK" is pressed.
+ * </p>
+ *
+ * <p>
+ *   See: <a href="https://code.google.com/p/android/issues/detail?id=34833">Issue 34833</a>
+ * </p>
+ */
+public class DismissableTimePickerDialog extends TimePickerDialog {
+
+  public DismissableTimePickerDialog(
+      Context context,
+      @Nullable OnTimeSetListener callback,
+      int hourOfDay,
+      int minute,
+      boolean is24HourView) {
+    super(context, callback, hourOfDay, minute, is24HourView);
+  }
+
+  public DismissableTimePickerDialog(
+      Context context,
+      int theme,
+      @Nullable OnTimeSetListener callback,
+      int hourOfDay,
+      int minute,
+      boolean is24HourView) {
+    super(context, theme, callback, hourOfDay, minute, is24HourView);
+  }
+
+  @Override
+  protected void onStop() {
+    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
+      super.onStop();
+    }
+  }
+
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/SupportTimePickerDialogFragment.java b/ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/SupportTimePickerDialogFragment.java
new file mode 100644
index 000000000000..d745984a1d42
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/SupportTimePickerDialogFragment.java
@@ -0,0 +1,50 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.modules.timepicker;
+
+import javax.annotation.Nullable;
+
+import android.app.Dialog;
+import android.app.TimePickerDialog.OnTimeSetListener;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnDismissListener;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+
+@SuppressWarnings("ValidFragment")
+public class SupportTimePickerDialogFragment extends DialogFragment {
+
+  @Nullable
+  private OnTimeSetListener mOnTimeSetListener;
+  @Nullable
+  private OnDismissListener mOnDismissListener;
+
+  @Override
+  public Dialog onCreateDialog(Bundle savedInstanceState) {
+    final Bundle args = getArguments();
+    return TimePickerDialogFragment.createDialog(args, getActivity(), mOnTimeSetListener);
+  }
+
+  @Override
+  public void onDismiss(DialogInterface dialog) {
+    super.onDismiss(dialog);
+    if (mOnDismissListener != null) {
+      mOnDismissListener.onDismiss(dialog);
+    }
+  }
+
+  public void setOnDismissListener(@Nullable OnDismissListener onDismissListener) {
+    mOnDismissListener = onDismissListener;
+  }
+
+  public void setOnTimeSetListener(@Nullable OnTimeSetListener onTimeSetListener) {
+    mOnTimeSetListener = onTimeSetListener;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/TimePickerDialogFragment.java b/ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/TimePickerDialogFragment.java
new file mode 100644
index 000000000000..64005ae1a845
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/TimePickerDialogFragment.java
@@ -0,0 +1,78 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.modules.timepicker;
+
+import javax.annotation.Nullable;
+
+import java.util.Calendar;
+
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.TimePickerDialog.OnTimeSetListener;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnDismissListener;
+import android.os.Bundle;
+import android.text.format.DateFormat;
+
+@SuppressWarnings("ValidFragment")
+public class TimePickerDialogFragment extends DialogFragment {
+
+  @Nullable
+  private OnTimeSetListener mOnTimeSetListener;
+  @Nullable
+  private OnDismissListener mOnDismissListener;
+
+  @Override
+  public Dialog onCreateDialog(Bundle savedInstanceState) {
+    final Bundle args = getArguments();
+    return createDialog(args, getActivity(), mOnTimeSetListener);
+  }
+
+  /*package*/ static Dialog createDialog(
+      Bundle args, Context activityContext, @Nullable OnTimeSetListener onTimeSetListener
+  ) {
+    final Calendar now = Calendar.getInstance();
+    int hour = now.get(Calendar.HOUR_OF_DAY);
+    int minute = now.get(Calendar.MINUTE);
+    boolean is24hour = DateFormat.is24HourFormat(activityContext);
+
+    if (args != null) {
+      hour = args.getInt(TimePickerDialogModule.ARG_HOUR, now.get(Calendar.HOUR_OF_DAY));
+      minute = args.getInt(TimePickerDialogModule.ARG_MINUTE, now.get(Calendar.MINUTE));
+      is24hour = args.getBoolean(
+          TimePickerDialogModule.ARG_IS24HOUR,
+          DateFormat.is24HourFormat(activityContext));
+    }
+
+    return new DismissableTimePickerDialog(
+        activityContext,
+        onTimeSetListener,
+        hour,
+        minute,
+        is24hour);
+  }
+
+  @Override
+  public void onDismiss(DialogInterface dialog) {
+    super.onDismiss(dialog);
+    if (mOnDismissListener != null) {
+      mOnDismissListener.onDismiss(dialog);
+    }
+  }
+
+  public void setOnDismissListener(@Nullable OnDismissListener onDismissListener) {
+    mOnDismissListener = onDismissListener;
+  }
+
+  public void setOnTimeSetListener(@Nullable OnTimeSetListener onTimeSetListener) {
+    mOnTimeSetListener = onTimeSetListener;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/TimePickerDialogModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/TimePickerDialogModule.java
new file mode 100644
index 000000000000..7d627b5833a5
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/timepicker/TimePickerDialogModule.java
@@ -0,0 +1,153 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.modules.timepicker;
+
+import javax.annotation.Nullable;
+
+import java.util.Map;
+
+import android.app.Activity;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
+import android.app.TimePickerDialog.OnTimeSetListener;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnDismissListener;
+import android.os.Bundle;
+import android.widget.TimePicker;
+
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.Promise;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.bridge.WritableNativeMap;
+import com.facebook.react.common.annotations.VisibleForTesting;
+
+/**
+ * {@link NativeModule} that allows JS to show a native time picker dialog and get called back when
+ * the user selects a time.
+ */
+public class TimePickerDialogModule extends ReactContextBaseJavaModule {
+
+  @VisibleForTesting
+  public static final String FRAGMENT_TAG = "TimePickerAndroid";
+
+  private static final String ERROR_NO_ACTIVITY = "E_NO_ACTIVITY";
+
+  /* package */ static final String ARG_HOUR = "hour";
+  /* package */ static final String ARG_MINUTE = "minute";
+  /* package */ static final String ARG_IS24HOUR = "is24Hour";
+  /* package */ static final String ACTION_TIME_SET = "timeSetAction";
+  /* package */ static final String ACTION_DISMISSED = "dismissedAction";
+
+  public TimePickerDialogModule(ReactApplicationContext reactContext) {
+    super(reactContext);
+  }
+
+  @Override
+  public String getName() {
+    return "TimePickerAndroid";
+  }
+
+  private class TimePickerDialogListener implements OnTimeSetListener, OnDismissListener {
+
+    private final Promise mPromise;
+    private boolean mPromiseResolved = false;
+
+    public TimePickerDialogListener(Promise promise) {
+      mPromise = promise;
+    }
+
+    @Override
+    public void onTimeSet(TimePicker view, int hour, int minute) {
+      if (!mPromiseResolved && getReactApplicationContext().hasActiveCatalystInstance()) {
+        WritableMap result = new WritableNativeMap();
+        result.putString("action", ACTION_TIME_SET);
+        result.putInt("hour", hour);
+        result.putInt("minute", minute);
+        mPromise.resolve(result);
+        mPromiseResolved = true;
+      }
+    }
+
+    @Override
+    public void onDismiss(DialogInterface dialog) {
+      if (!mPromiseResolved && getReactApplicationContext().hasActiveCatalystInstance()) {
+        WritableMap result = new WritableNativeMap();
+        result.putString("action", ACTION_DISMISSED);
+        mPromise.resolve(result);
+        mPromiseResolved = true;
+      }
+    }
+  }
+
+  @ReactMethod
+  public void open(@Nullable final ReadableMap options, Promise promise) {
+
+    Activity activity = getCurrentActivity();
+    if (activity == null) {
+      promise.reject(
+          ERROR_NO_ACTIVITY,
+          "Tried to open a TimePicker dialog while not attached to an Activity");
+      return;
+    }
+    // We want to support both android.app.Activity and the pre-Honeycomb FragmentActivity
+    // (for apps that use it for legacy reasons). This unfortunately leads to some code duplication.
+    if (activity instanceof android.support.v4.app.FragmentActivity) {
+      android.support.v4.app.FragmentManager fragmentManager =
+          ((android.support.v4.app.FragmentActivity) activity).getSupportFragmentManager();
+      android.support.v4.app.DialogFragment oldFragment =
+          (android.support.v4.app.DialogFragment)fragmentManager.findFragmentByTag(FRAGMENT_TAG);
+      if (oldFragment != null) {
+        oldFragment.dismiss();
+      }
+      SupportTimePickerDialogFragment fragment = new SupportTimePickerDialogFragment();
+      if (options != null) {
+        Bundle args = createFragmentArguments(options);
+        fragment.setArguments(args);
+      }
+      TimePickerDialogListener listener = new TimePickerDialogListener(promise);
+      fragment.setOnDismissListener(listener);
+      fragment.setOnTimeSetListener(listener);
+      fragment.show(fragmentManager, FRAGMENT_TAG);
+    } else {
+      FragmentManager fragmentManager = activity.getFragmentManager();
+      DialogFragment oldFragment = (DialogFragment) fragmentManager.findFragmentByTag(FRAGMENT_TAG);
+      if (oldFragment != null) {
+        oldFragment.dismiss();
+      }
+      TimePickerDialogFragment fragment = new TimePickerDialogFragment();
+      if (options != null) {
+        final Bundle args = createFragmentArguments(options);
+        fragment.setArguments(args);
+      }
+      TimePickerDialogListener listener = new TimePickerDialogListener(promise);
+      fragment.setOnDismissListener(listener);
+      fragment.setOnTimeSetListener(listener);
+      fragment.show(fragmentManager, FRAGMENT_TAG);
+    }
+  }
+
+  private Bundle createFragmentArguments(ReadableMap options) {
+    final Bundle args = new Bundle();
+    if (options.hasKey(ARG_HOUR) && !options.isNull(ARG_HOUR)) {
+      args.putInt(ARG_HOUR, options.getInt(ARG_HOUR));
+    }
+    if (options.hasKey(ARG_MINUTE) && !options.isNull(ARG_MINUTE)) {
+      args.putInt(ARG_MINUTE, options.getInt(ARG_MINUTE));
+    }
+    if (options.hasKey(ARG_IS24HOUR) && !options.isNull(ARG_IS24HOUR)) {
+      args.putBoolean(ARG_IS24HOUR, options.getBoolean(ARG_IS24HOUR));
+    }
+    return args;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK
index 193749ddf23a..8af3f1421e67 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK
+++ b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK
@@ -28,6 +28,7 @@ android_library(
     react_native_target('java/com/facebook/react/modules/camera:camera'),
     react_native_target('java/com/facebook/react/modules/clipboard:clipboard'),
     react_native_target('java/com/facebook/react/modules/core:core'),
+    react_native_target('java/com/facebook/react/modules/datepicker:datepicker'),
     react_native_target('java/com/facebook/react/modules/debug:debug'),
     react_native_target('java/com/facebook/react/modules/dialog:dialog'),
     react_native_target('java/com/facebook/react/modules/fresco:fresco'),
@@ -36,6 +37,7 @@ android_library(
     react_native_target('java/com/facebook/react/modules/netinfo:netinfo'),
     react_native_target('java/com/facebook/react/modules/network:network'),
     react_native_target('java/com/facebook/react/modules/storage:storage'),
+    react_native_target('java/com/facebook/react/modules/timepicker:timepicker'),
     react_native_target('java/com/facebook/react/modules/toast:toast'),
     react_native_target('java/com/facebook/react/uimanager:uimanager'),
     react_native_target('java/com/facebook/react/modules/websocket:websocket'),
diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
index fa3e97e10b5e..b817f55ac6e4 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
@@ -17,16 +17,19 @@
 import com.facebook.react.bridge.JavaScriptModule;
 import com.facebook.react.bridge.NativeModule;
 import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.modules.appstate.AppStateModule;
 import com.facebook.react.modules.camera.CameraRollManager;
+import com.facebook.react.modules.clipboard.ClipboardModule;
 import com.facebook.react.modules.dialog.DialogModule;
+import com.facebook.react.modules.datepicker.DatePickerDialogModule;
 import com.facebook.react.modules.fresco.FrescoModule;
 import com.facebook.react.modules.intent.IntentModule;
 import com.facebook.react.modules.location.LocationModule;
 import com.facebook.react.modules.netinfo.NetInfoModule;
 import com.facebook.react.modules.network.NetworkingModule;
 import com.facebook.react.modules.storage.AsyncStorageModule;
+import com.facebook.react.modules.timepicker.TimePickerDialogModule;
 import com.facebook.react.modules.toast.ToastModule;
-import com.facebook.react.modules.appstate.AppStateModule;
 import com.facebook.react.modules.websocket.WebSocketModule;
 import com.facebook.react.uimanager.ViewManager;
 import com.facebook.react.views.art.ARTRenderableViewManager;
@@ -50,7 +53,6 @@
 import com.facebook.react.views.viewpager.ReactViewPagerManager;
 import com.facebook.react.views.swiperefresh.SwipeRefreshLayoutManager;
 import com.facebook.react.views.webview.ReactWebViewManager;
-import com.facebook.react.modules.clipboard.ClipboardModule;
 
 /**
  * Package defining basic modules and view managers.
@@ -64,12 +66,14 @@ public List<NativeModule> createNativeModules(ReactApplicationContext reactConte
       new AsyncStorageModule(reactContext),
       new CameraRollManager(reactContext),
       new ClipboardModule(reactContext),
+      new DatePickerDialogModule(reactContext),
       new DialogModule(reactContext),
       new FrescoModule(reactContext),
       new IntentModule(reactContext),
       new LocationModule(reactContext),
       new NetworkingModule(reactContext),
       new NetInfoModule(reactContext),
+      new TimePickerDialogModule(reactContext),
       new ToastModule(reactContext),
       new WebSocketModule(reactContext));
   }

From 6b75d7f4977b421f44dd33d2015c4ba1c3ef1072 Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Tue, 26 Jan 2016 10:50:19 -0800
Subject: [PATCH 0887/1411] Expose `has` method on Cache.

Reviewed By: davidaurelio

Differential Revision: D2862315

fb-gh-sync-id: 03728a2593b477aef3bbfe01d42382893a05ea50
---
 .../Cache/__tests__/Cache-test.js             | 28 +++++++++++++++++++
 .../src/DependencyResolver/Cache/index.js     |  6 ++--
 2 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/Cache/__tests__/Cache-test.js b/packager/react-packager/src/DependencyResolver/Cache/__tests__/Cache-test.js
index f4c0f4309563..22d6825e9231 100644
--- a/packager/react-packager/src/DependencyResolver/Cache/__tests__/Cache-test.js
+++ b/packager/react-packager/src/DependencyResolver/Cache/__tests__/Cache-test.js
@@ -275,4 +275,32 @@ describe('Cache', () => {
       expect(fs.writeFile).toBeCalled();
     });
   });
+
+  describe('check for cache presence', () => {
+    it('synchronously resolves cache presence', () => {
+      fs.stat.mockImpl((file, callback) =>
+        callback(null, {
+          mtime: {
+            getTime: () => {},
+          },
+        })
+      );
+
+      var cache = new Cache({
+        cacheKey: 'cache',
+      });
+      var loaderCb = jest.genMockFn().mockImpl(() =>
+        Promise.resolve('banana')
+      );
+      var file = '/rootDir/someFile';
+
+      return cache
+        .get(file, 'field', loaderCb)
+        .then(() => {
+          expect(cache.has(file)).toBe(true);
+          expect(cache.has(file, 'field')).toBe(true);
+          expect(cache.has(file, 'foo')).toBe(false);
+        });
+    });
+  });
 });
diff --git a/packager/react-packager/src/DependencyResolver/Cache/index.js b/packager/react-packager/src/DependencyResolver/Cache/index.js
index 02384a202cf8..40f16c77baa3 100644
--- a/packager/react-packager/src/DependencyResolver/Cache/index.js
+++ b/packager/react-packager/src/DependencyResolver/Cache/index.js
@@ -51,7 +51,7 @@ class Cache {
       throw new Error('Use absolute paths');
     }
 
-    var recordP = this._has(filepath, field)
+    var recordP = this.has(filepath, field)
       ? this._data[filepath].data[field]
       : this._set(filepath, field, loaderCb(filepath));
 
@@ -59,7 +59,7 @@ class Cache {
   }
 
   invalidate(filepath) {
-    if (this._has(filepath)) {
+    if (this.has(filepath)) {
       delete this._data[filepath];
     }
   }
@@ -68,7 +68,7 @@ class Cache {
     return this._persistCache();
   }
 
-  _has(filepath, field) {
+  has(filepath, field) {
     return Object.prototype.hasOwnProperty.call(this._data, filepath) &&
       (!field || Object.prototype.hasOwnProperty.call(this._data[filepath].data, field));
   }

From 7e64ad8fc4defb68deabf10c4bf1d8582e3cbf95 Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Tue, 26 Jan 2016 11:15:55 -0800
Subject: [PATCH 0888/1411] Fix some lint nits

Reviewed By: voideanvalue

Differential Revision: D2862332

fb-gh-sync-id: 19ab5e8a580137ffe6276b21a9018f7b322dd0cb
---
 .../DependencyGraph/ResolutionRequest.js               | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
index 87e00260cb85..ebe7c39a9fe8 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
@@ -279,16 +279,16 @@ class ResolutionRequest {
 
   _resolveNodeDependency(fromModule, toModuleName) {
     if (toModuleName[0] === '.' || toModuleName[1] === '/') {
-      return this._resolveFileOrDir(fromModule, toModuleName)
+      return this._resolveFileOrDir(fromModule, toModuleName);
     } else {
       return this._redirectRequire(fromModule, toModuleName).then(
         realModuleName => {
           if (realModuleName[0] === '.' || realModuleName[1] === '/') {
             // derive absolute path /.../node_modules/fromModuleDir/realModuleName
-            let fromModuleParentIdx = fromModule.path.lastIndexOf('node_modules/') + 13
-            let fromModuleDir = fromModule.path.slice(0, fromModule.path.indexOf('/', fromModuleParentIdx))
-            let absPath = path.join(fromModuleDir, realModuleName)
-            return this._resolveFileOrDir(fromModule, absPath)
+            const fromModuleParentIdx = fromModule.path.lastIndexOf('node_modules/') + 13;
+            const fromModuleDir = fromModule.path.slice(0, fromModule.path.indexOf('/', fromModuleParentIdx));
+            const absPath = path.join(fromModuleDir, realModuleName);
+            return this._resolveFileOrDir(fromModule, absPath);
           }
 
           const searchQueue = [];

From affd6230fed22e48a679cfc76d995a2ebc4af75f Mon Sep 17 00:00:00 2001
From: Jed Lau <jedlau@samsara.com>
Date: Tue, 26 Jan 2016 14:22:29 -0800
Subject: [PATCH 0889/1411] self -> this in ScrollResponder

Summary:
I *think* this is causing a crash for me in a release build (curiously, not a debug build):
```
ReferenceError: Can't find variable: self
```

I saw this in 0.18.1, which I assume was renamed to v0.19.0-rc.
Closes https://github.com/facebook/react-native/pull/5562

Reviewed By: svcscm

Differential Revision: D2866491

Pulled By: androidtrunkagent

fb-gh-sync-id: 196f718bf807c5eef676f66f1e15d7bde9475d5b
---
 Libraries/Components/ScrollResponder.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/Components/ScrollResponder.js b/Libraries/Components/ScrollResponder.js
index eb1475ce8770..baa3336a06b5 100644
--- a/Libraries/Components/ScrollResponder.js
+++ b/Libraries/Components/ScrollResponder.js
@@ -372,7 +372,7 @@ var ScrollResponderMixin = {
    */
   scrollResponderScrollWithoutAnimationTo: function(offsetX: number, offsetY: number) {
     console.warn('`scrollResponderScrollWithoutAnimationTo` is deprecated. Use `scrollResponderScrollTo` instead');
-    self.scrollResponderScrollTo(offsetX, offsetY, false);
+    this.scrollResponderScrollTo(offsetX, offsetY, false);
   },
 
   /**

From e33e6ab1f0999b3d972344a8ff33f7ee6fd1bb64 Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Tue, 26 Jan 2016 14:34:00 -0800
Subject: [PATCH 0890/1411] Add cross-platform Linking module

Summary:
A promise based API for handling Link for Android and iOS. Refer #4971

The iOS part doesn't handle errors. Will need someone with iOS knowledge to do that.

cc skevy ide brentvatne mkonicek vjeux nicklockwood
Closes https://github.com/facebook/react-native/pull/5336

Reviewed By: svcscm

Differential Revision: D2866664

Pulled By: androidtrunkagent

fb-gh-sync-id: 67e68a827e6b85886bfa84e79b897f079e78b1b5
---
 .../Intent/IntentAndroid.android.js           |  33 ++-
 Libraries/Linking/Linking.js                  | 211 ++++++++++++++++++
 Libraries/LinkingIOS/LinkingIOS.js            |  58 ++---
 Libraries/LinkingIOS/RCTLinkingManager.m      |  14 +-
 Libraries/react-native/react-native.js        |   1 +
 Libraries/react-native/react-native.js.flow   |   1 +
 .../react/modules/intent/IntentModule.java    |  36 +--
 7 files changed, 281 insertions(+), 73 deletions(-)
 create mode 100644 Libraries/Linking/Linking.js

diff --git a/Libraries/Components/Intent/IntentAndroid.android.js b/Libraries/Components/Intent/IntentAndroid.android.js
index cebe69948209..48877dd6b1ee 100644
--- a/Libraries/Components/Intent/IntentAndroid.android.js
+++ b/Libraries/Components/Intent/IntentAndroid.android.js
@@ -7,13 +7,16 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule IntentAndroid
+ * @flow
  */
 'use strict';
 
-var IntentAndroidModule = require('NativeModules').IntentAndroid;
+var Linking = require('Linking');
 var invariant = require('invariant');
 
 /**
+ * NOTE: `IntentAndroid` is being deprecated. Use `Linking` instead.
+ *
  * `IntentAndroid` gives you a general interface to handle external links.
  *
  * ### Basic Usage
@@ -89,10 +92,12 @@ class IntentAndroid {
    * If you're passing in a non-http(s) URL, it's best to check {@code canOpenURL} first.
    *
    * NOTE: For web URLs, the protocol ("http://", "https://") must be set accordingly!
+   *
+   * @deprecated
    */
   static openURL(url: string) {
-    this._validateURL(url);
-    IntentAndroidModule.openURL(url);
+    console.warn('"IntentAndroid.openURL" is deprecated. Use the promise based "Linking.openURL" instead.');
+    Linking.openURL(url);
   }
 
   /**
@@ -104,14 +109,16 @@ class IntentAndroid {
    * NOTE: For web URLs, the protocol ("http://", "https://") must be set accordingly!
    *
    * @param URL the URL to open
+   *
+   * @deprecated
    */
   static canOpenURL(url: string, callback: Function) {
-    this._validateURL(url);
+    console.warn('"IntentAndroid.canOpenURL" is deprecated. Use the promise based "Linking.canOpenURL" instead.');
     invariant(
       typeof callback === 'function',
       'A valid callback function is required'
     );
-    IntentAndroidModule.canOpenURL(url, callback);
+    Linking.canOpenURL(url).then(callback);
   }
 
   /**
@@ -119,24 +126,16 @@ class IntentAndroid {
    * it will give the link url, otherwise it will give `null`
    *
    * Refer http://developer.android.com/training/app-indexing/deep-linking.html#handling-intents
+   *
+   * @deprecated
    */
   static getInitialURL(callback: Function) {
+    console.warn('"IntentAndroid.getInitialURL" is deprecated. Use the promise based "Linking.getInitialURL" instead.');
     invariant(
       typeof callback === 'function',
       'A valid callback function is required'
     );
-    IntentAndroidModule.getInitialURL(callback);
-  }
-
-  static _validateURL(url: string) {
-    invariant(
-      typeof url === 'string',
-      'Invalid URL: should be a string. Was: ' + url
-    );
-    invariant(
-      url,
-      'Invalid URL: cannot be empty'
-    );
+    Linking.getInitialURL().then(callback);
   }
 }
 
diff --git a/Libraries/Linking/Linking.js b/Libraries/Linking/Linking.js
new file mode 100644
index 000000000000..97282ab66391
--- /dev/null
+++ b/Libraries/Linking/Linking.js
@@ -0,0 +1,211 @@
+/**
+ * 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 Linking
+ * @flow
+ */
+'use strict';
+
+const Platform = require('Platform');
+const RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
+const {
+  IntentAndroid,
+  LinkingManager: LinkingManagerIOS
+} = require('NativeModules');
+const LinkingManager = Platform.OS === 'android' ? IntentAndroid : LinkingManagerIOS;
+const invariant = require('invariant');
+const Map = require('Map');
+
+const _notifHandlers = new Map();
+
+const DEVICE_NOTIF_EVENT = 'openURL';
+
+/**
+ * `Linking` gives you a general interface to interact with both incoming
+ * and outgoing app links.
+ *
+ * ### Basic Usage
+ *
+ * #### Handling deep links
+ *
+ * If your app was launched from an external url registered to your app you can
+ * access and handle it from any component you want with
+ *
+ * ```
+ * componentDidMount() {
+ *   var url = Linking.getInitialURL().then(url) => {
+ *     if (url) {
+ *       console.log('Initial url is: ' + url);
+ *     }
+ *   }).catch(err => console.error('An error occurred', err));
+ * }
+ * ```
+ *
+ * NOTE: For instructions on how to add support for deep linking on Android,
+ * refer [Enabling Deep Links for App Content - Add Intent Filters for Your Deep Links](http://developer.android.com/training/app-indexing/deep-linking.html#adding-filters).
+ *
+ * NOTE: For iOS, in case you also want to listen to incoming app links during your app's
+ * execution you'll need to add the following lines to you `*AppDelegate.m`:
+ *
+ * ```
+ * - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
+ *   sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
+ * {
+ *   return [LinkingManager application:application openURL:url
+ *                       sourceApplication:sourceApplication annotation:annotation];
+ * }
+ *
+ * // Only if your app is using [Universal Links](https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/AppSearch/UniversalLinks.html).
+ * - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity
+ *  restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
+ * {
+ *  return [LinkingManager application:application
+ *                   continueUserActivity:userActivity
+ *                     restorationHandler:restorationHandler];
+ * }
+ *
+ * ```
+ *
+ * And then on your React component you'll be able to listen to the events on
+ * `Linking` as follows
+ *
+ * ```
+ * componentDidMount() {
+ *   Linking.addEventListener('url', this._handleOpenURL);
+ * },
+ * componentWillUnmount() {
+ *   Linking.removeEventListener('url', this._handleOpenURL);
+ * },
+ * _handleOpenURL(event) {
+ *   console.log(event.url);
+ * }
+ * ```
+ * Note that this is only supported on iOS.
+ *
+ * #### Opening external links
+ *
+ * To start the corresponding activity for a link (web URL, email, contact etc.), call
+ *
+ * ```
+ * Linking.openURL(url).catch(err => console.error('An error occurred', err));
+ * ```
+ *
+ * If you want to check if any installed app can handle a given URL beforehand you can call
+ * ```
+ * Linking.canOpenURL(url).then(supported => {
+ *   if (!supported) {
+ *     console.log('Can\'t handle url: ' + url);
+ *   } else {
+ *     return Linking.openURL(url);
+ *   }
+ * }).catch(err => console.error('An error occurred', err));
+ * ```
+ */
+class Linking {
+  /**
+   * Add a handler to Linking changes by listening to the `url` event type
+   * and providing the handler
+   *
+   * @platform ios
+   */
+  static addEventListener(type: string, handler: Function) {
+    if (Platform.OS === 'android') {
+        console.warn('Linking.addEventListener is not supported on Android');
+    } else {
+      invariant(
+        type === 'url',
+        'Linking only supports `url` events'
+      );
+      var listener = RCTDeviceEventEmitter.addListener(
+        DEVICE_NOTIF_EVENT,
+        handler
+      );
+      _notifHandlers.set(handler, listener);
+    }
+  }
+
+  /**
+   * Remove a handler by passing the `url` event type and the handler
+   *
+   * @platform ios
+   */
+  static removeEventListener(type: string, handler: Function ) {
+    if (Platform.OS === 'android') {
+        console.warn('Linking.removeEventListener is not supported on Android');
+    } else {
+      invariant(
+        type === 'url',
+        'Linking only supports `url` events'
+      );
+      var listener = _notifHandlers.get(handler);
+      if (!listener) {
+        return;
+      }
+      listener.remove();
+      _notifHandlers.delete(handler);
+    }
+  }
+
+  /**
+   * Try to open the given `url` with any of the installed apps.
+   *
+   * You can use other URLs, like a location (e.g. "geo:37.484847,-122.148386"), a contact,
+   * or any other URL that can be opened with the installed apps.
+   *
+   * NOTE: This method will fail if the system doesn't know how to open the specified URL.
+   * If you're passing in a non-http(s) URL, it's best to check {@code canOpenURL} first.
+   *
+   * NOTE: For web URLs, the protocol ("http://", "https://") must be set accordingly!
+   */
+  static openURL(url: string): Promise<boolean> {
+    this._validateURL(url);
+    return LinkingManager.openURL(url);
+  }
+
+  /**
+   * Determine whether or not an installed app can handle a given URL.
+   *
+   * NOTE: For web URLs, the protocol ("http://", "https://") must be set accordingly!
+   *
+   * NOTE: As of iOS 9, your app needs to provide the `LSApplicationQueriesSchemes` key
+   * inside `Info.plist`.
+   *
+   * @param URL the URL to open
+   */
+  static canOpenURL(url: string): Promise<boolean> {
+    this._validateURL(url);
+    return LinkingManager.canOpenURL(url);
+  }
+
+  /**
+   * If the app launch was triggered by an app link with,
+   * it will give the link url, otherwise it will give `null`
+   *
+   * NOTE: To support deep linking on Android, refer http://developer.android.com/training/app-indexing/deep-linking.html#handling-intents
+   */
+  static getInitialURL(): Promise<?string> {
+    if (Platform.OS === 'android') {
+      return IntentAndroid.getInitialURL();
+    } else {
+      return Promise.resolve(LinkingManagerIOS.initialURL);
+    }
+  }
+
+  static _validateURL(url: string) {
+    invariant(
+      typeof url === 'string',
+      'Invalid URL: should be a string. Was: ' + url
+    );
+    invariant(
+      url,
+      'Invalid URL: cannot be empty'
+    );
+  }
+}
+
+module.exports = Linking;
diff --git a/Libraries/LinkingIOS/LinkingIOS.js b/Libraries/LinkingIOS/LinkingIOS.js
index a4832f268304..d223b0d8b729 100644
--- a/Libraries/LinkingIOS/LinkingIOS.js
+++ b/Libraries/LinkingIOS/LinkingIOS.js
@@ -11,17 +11,15 @@
  */
 'use strict';
 
-var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
+var Linking = require('Linking');
 var RCTLinkingManager = require('NativeModules').LinkingManager;
 var invariant = require('invariant');
 
-var _notifHandlers = new Map();
-var _initialURL = RCTLinkingManager &&
-  RCTLinkingManager.initialURL;
-
-var DEVICE_NOTIF_EVENT = 'openURL';
+var _initialURL = RCTLinkingManager.initialURL;
 
 /**
+ * NOTE: `LinkingIOS` is being deprecated. Use `Linking` instead.
+ *
  * `LinkingIOS` gives you a general interface to interact with both incoming
  * and outgoing app links.
  *
@@ -98,44 +96,32 @@ class LinkingIOS {
   /**
    * Add a handler to LinkingIOS changes by listening to the `url` event type
    * and providing the handler
+   *
+   * @deprecated
    */
   static addEventListener(type: string, handler: Function) {
-    invariant(
-      type === 'url',
-      'LinkingIOS only supports `url` events'
-    );
-    var listener = RCTDeviceEventEmitter.addListener(
-      DEVICE_NOTIF_EVENT,
-      handler
-    );
-    _notifHandlers.set(handler, listener);
+    console.warn('"LinkingIOS.addEventListener" is deprecated. Use "Linking.addEventListener" instead.');
+    Linking.addEventListener(type, handler);
   }
 
   /**
    * Remove a handler by passing the `url` event type and the handler
+   *
+   * @deprecated
    */
   static removeEventListener(type: string, handler: Function ) {
-    invariant(
-      type === 'url',
-      'LinkingIOS only supports `url` events'
-    );
-    var listener = _notifHandlers.get(handler);
-    if (!listener) {
-      return;
-    }
-    listener.remove();
-    _notifHandlers.delete(handler);
+    console.warn('"LinkingIOS.removeEventListener" is deprecated. Use "Linking.removeEventListener" instead.');
+    Linking.removeEventListener(type, handler);
   }
 
   /**
    * Try to open the given `url` with any of the installed apps.
+   *
+   * @deprecated
    */
   static openURL(url: string) {
-    invariant(
-      typeof url === 'string',
-      'Invalid url: should be a string'
-    );
-    RCTLinkingManager.openURL(url);
+    console.warn('"LinkingIOS.openURL" is deprecated. Use the promise based "Linking.openURL" instead.');
+    Linking.openURL(url);
   }
 
   /**
@@ -144,24 +130,26 @@ class LinkingIOS {
    *
    * NOTE: As of iOS 9, your app needs to provide the `LSApplicationQueriesSchemes` key
    * inside `Info.plist`.
+   *
+   * @deprecated
    */
   static canOpenURL(url: string, callback: Function) {
-    invariant(
-      typeof url === 'string',
-      'Invalid url: should be a string'
-    );
+    console.warn('"LinkingIOS.canOpenURL" is deprecated. Use the promise based "Linking.canOpenURL" instead.');
     invariant(
       typeof callback === 'function',
       'A valid callback function is required'
     );
-    RCTLinkingManager.canOpenURL(url, callback);
+    Linking.canOpenURL(url).then(callback);
   }
 
   /**
    * If the app launch was triggered by an app link, it will pop the link url,
    * otherwise it will return `null`
+   *
+   * @deprecated
    */
   static popInitialURL(): ?string {
+    console.warn('"LinkingIOS.popInitialURL" is deprecated. Use the promise based "Linking.getInitialURL" instead.');
     var initialURL = _initialURL;
     _initialURL = null;
     return initialURL;
diff --git a/Libraries/LinkingIOS/RCTLinkingManager.m b/Libraries/LinkingIOS/RCTLinkingManager.m
index 749d2c27ad30..d720631674c9 100644
--- a/Libraries/LinkingIOS/RCTLinkingManager.m
+++ b/Libraries/LinkingIOS/RCTLinkingManager.m
@@ -73,26 +73,30 @@ - (void)handleOpenURLNotification:(NSNotification *)notification
                                               body:notification.userInfo];
 }
 
-RCT_EXPORT_METHOD(openURL:(NSURL *)URL)
+RCT_EXPORT_METHOD(openURL:(NSURL *)URL
+                  resolve:(RCTPromiseResolveBlock)resolve
+                  reject:(__unused RCTPromiseRejectBlock)reject)
 {
-  // TODO: we should really return success/failure via a callback here
+  // TODO: we should really report success/failure via the promise here
   // Doesn't really matter what thread we call this on since it exits the app
   [RCTSharedApplication() openURL:URL];
+  resolve(@[@YES]);
 }
 
 RCT_EXPORT_METHOD(canOpenURL:(NSURL *)URL
-                  callback:(RCTResponseSenderBlock)callback)
+                  resolve:(RCTPromiseResolveBlock)resolve
+                  reject:(__unused RCTPromiseRejectBlock)reject)
 {
   if (RCTRunningInAppExtension()) {
     // Technically Today widgets can open urls, but supporting that would require
     // a reference to the NSExtensionContext
-    callback(@[@NO]);
+    resolve(@[@NO]);
     return;
   }
 
   // This can be expensive, so we deliberately don't call on main thread
   BOOL canOpen = [RCTSharedApplication() canOpenURL:URL];
-  callback(@[@(canOpen)]);
+  resolve(@[@(canOpen)]);
 }
 
 @end
diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js
index 865ee0cabe16..da90b75c0fa0 100644
--- a/Libraries/react-native/react-native.js
+++ b/Libraries/react-native/react-native.js
@@ -73,6 +73,7 @@ var ReactNative = {
   get IntentAndroid() { return require('IntentAndroid'); },
   get InteractionManager() { return require('InteractionManager'); },
   get LayoutAnimation() { return require('LayoutAnimation'); },
+  get Linking() { return require('Linking'); },
   get LinkingIOS() { return require('LinkingIOS'); },
   get NetInfo() { return require('NetInfo'); },
   get PanResponder() { return require('PanResponder'); },
diff --git a/Libraries/react-native/react-native.js.flow b/Libraries/react-native/react-native.js.flow
index 17d46a0af2e8..52d7eeddb496 100644
--- a/Libraries/react-native/react-native.js.flow
+++ b/Libraries/react-native/react-native.js.flow
@@ -85,6 +85,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
   IntentAndroid: require('IntentAndroid'),
   InteractionManager: require('InteractionManager'),
   LayoutAnimation: require('LayoutAnimation'),
+  Linking: require('Linking'),
   LinkingIOS: require('LinkingIOS'),
   NetInfo: require('NetInfo'),
   PanResponder: require('PanResponder'),
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java
index ce4681264193..8f57f570ea73 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java
@@ -13,8 +13,8 @@
 import android.content.Intent;
 import android.net.Uri;
 
-import com.facebook.react.bridge.Callback;
 import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
+import com.facebook.react.bridge.Promise;
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.ReactContextBaseJavaModule;
 import com.facebook.react.bridge.ReactMethod;
@@ -36,10 +36,10 @@ public String getName() {
   /**
    * Return the URL the activity was started with
    *
-   * @param callback a callback which is called with the initial URL
+   * @param promise a promise which is resolved with the initial URL
    */
   @ReactMethod
-  public void getInitialURL(Callback callback) {
+  public void getInitialURL(Promise promise) {
     try {
       Activity currentActivity = getCurrentActivity();
       String initialURL = null;
@@ -54,10 +54,10 @@ public void getInitialURL(Callback callback) {
         }
       }
 
-      callback.invoke(initialURL);
+      promise.resolve(initialURL);
     } catch (Exception e) {
-      throw new JSApplicationIllegalArgumentException(
-          "Could not get the initial URL : " + e.getMessage());
+      promise.reject(new JSApplicationIllegalArgumentException(
+          "Could not get the initial URL : " + e.getMessage()));
     }
   }
 
@@ -70,9 +70,10 @@ public void getInitialURL(Callback callback) {
    * @param url the URL to open
    */
   @ReactMethod
-  public void openURL(String url) {
+  public void openURL(String url, Promise promise) {
     if (url == null || url.isEmpty()) {
-      throw new JSApplicationIllegalArgumentException("Invalid URL: " + url);
+      promise.reject(new JSApplicationIllegalArgumentException("Invalid URL: " + url));
+      return;
     }
 
     try {
@@ -85,9 +86,11 @@ public void openURL(String url) {
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         getReactApplicationContext().startActivity(intent);
       }
+
+      promise.resolve(true);
     } catch (Exception e) {
-      throw new JSApplicationIllegalArgumentException(
-          "Could not open URL '" + url + "': " + e.getMessage());
+      promise.reject(new JSApplicationIllegalArgumentException(
+          "Could not open URL '" + url + "': " + e.getMessage()));
     }
   }
 
@@ -95,12 +98,13 @@ public void openURL(String url) {
    * Determine whether or not an installed app can handle a given URL.
    *
    * @param url the URL to open
-   * @param callback a callback that is always called with a boolean argument
+   * @param promise a promise that is always resolved with a boolean argument
    */
   @ReactMethod
-  public void canOpenURL(String url, Callback callback) {
+  public void canOpenURL(String url, Promise promise) {
     if (url == null || url.isEmpty()) {
-      throw new JSApplicationIllegalArgumentException("Invalid URL: " + url);
+      promise.reject(new JSApplicationIllegalArgumentException("Invalid URL: " + url));
+      return;
     }
 
     try {
@@ -110,10 +114,10 @@ public void canOpenURL(String url, Callback callback) {
       intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
       boolean canOpen =
           intent.resolveActivity(getReactApplicationContext().getPackageManager()) != null;
-      callback.invoke(canOpen);
+      promise.resolve(canOpen);
     } catch (Exception e) {
-      throw new JSApplicationIllegalArgumentException(
-          "Could not check if URL '" + url + "' can be opened: " + e.getMessage());
+      promise.reject(new JSApplicationIllegalArgumentException(
+          "Could not check if URL '" + url + "' can be opened: " + e.getMessage()));
     }
   }
 }

From bccdef00d4a411c5d659220aa66b0cc67b53c938 Mon Sep 17 00:00:00 2001
From: SangYeob Bono Yu <deminoth@gmail.com>
Date: Wed, 27 Jan 2016 18:14:41 +0900
Subject: [PATCH 0891/1411] added ShareHows app android link in showcase

---
 website/src/react-native/showcase.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index d87d844e3f13..71eca1e46ef3 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -455,7 +455,8 @@ var apps = [
   {
     name: 'ShareHows',
     icon: 'http://a4.mzstatic.com/us/r30/Purple5/v4/78/1c/83/781c8325-a1e1-4afc-f106-a629bcf3c6ef/icon175x175.png',
-    link: 'https://itunes.apple.com/kr/app/sweeohauseu-sesang-ui-modeun/id1060914858?mt=8',
+    linkAppStore: 'https://itunes.apple.com/kr/app/sweeohauseu-sesang-ui-modeun/id1060914858?mt=8',
+    linkPlayStore: 'https://play.google.com/store/apps/details?id=kr.dobbit.sharehows',
     author: 'Dobbit Co., Ltd.'
   },
   {

From 3f97c5a3408a67dfc2de6134da7b3f29fa59a34e Mon Sep 17 00:00:00 2001
From: tuyou <yoututouch@gmail.com>
Date: Wed, 27 Jan 2016 02:49:12 -0800
Subject: [PATCH 0892/1411] assign webView's delegate to nil
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Summary:
assign webView’s delegate to nil when the delegate release
Closes https://github.com/facebook/react-native/pull/5574

Reviewed By: svcscm

Differential Revision: D2869485

Pulled By: nicklockwood

fb-gh-sync-id: c72ac64e6c8757a2095d4e5d7baa3a0b6bded6ce
---
 React/Views/RCTWebView.m | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/React/Views/RCTWebView.m b/React/Views/RCTWebView.m
index 46a263d0e620..1b1ef646a36e 100644
--- a/React/Views/RCTWebView.m
+++ b/React/Views/RCTWebView.m
@@ -35,6 +35,11 @@ @implementation RCTWebView
   NSString *_injectedJavaScript;
 }
 
+- (void)dealloc
+{
+  _webView.delegate = nil;
+}
+
 - (instancetype)initWithFrame:(CGRect)frame
 {
   if ((self = [super initWithFrame:frame])) {

From fff5dc39436cfe705ec40c0518926a450b5ef98c Mon Sep 17 00:00:00 2001
From: Matt Apperson <matt@appersonlabs.com>
Date: Wed, 27 Jan 2016 07:13:14 -0800
Subject: [PATCH 0893/1411] Add 3dTouch props to touch events

Summary:
This adds the first of the three 3dTouch API types, that found on the touch event.

It adds the `force` prop to touch events when running on iOS 9 devices:
Closes https://github.com/facebook/react-native/pull/3055

Reviewed By: svcscm

Differential Revision: D2860540

Pulled By: nicklockwood

fb-gh-sync-id: 95a3eb433837c844f755b3ed4a3dfcb28452c284
---
 React/Base/RCTTouchHandler.m | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/React/Base/RCTTouchHandler.m b/React/Base/RCTTouchHandler.m
index f2490a7ad6e9..c0f6b6f4260a 100644
--- a/React/Base/RCTTouchHandler.m
+++ b/React/Base/RCTTouchHandler.m
@@ -108,7 +108,7 @@ - (void)_recordNewTouches:(NSSet<UITouch *> *)touches
     }
 
     // Create touch
-    NSMutableDictionary *reactTouch = [[NSMutableDictionary alloc] initWithCapacity:9];
+    NSMutableDictionary *reactTouch = [[NSMutableDictionary alloc] initWithCapacity:11];
     reactTouch[@"target"] = reactTag;
     reactTouch[@"identifier"] = @(touchID);
     reactTouch[@"touches"] = (id)kCFNull;        // We hijack this touchObj to serve both as an event
@@ -150,6 +150,12 @@ - (void)_updateReactTouchAtIndex:(NSInteger)touchIndex
   reactTouch[@"locationX"] = @(touchViewLocation.x);
   reactTouch[@"locationY"] = @(touchViewLocation.y);
   reactTouch[@"timestamp"] =  @(nativeTouch.timestamp * 1000); // in ms, for JS
+
+  if ([nativeTouch.view respondsToSelector:@selector(traitCollection)] &&
+      [nativeTouch.view.traitCollection respondsToSelector:@selector(forceTouchCapability)]) {
+
+    reactTouch[@"force"] = @(RCTZeroIfNaN(nativeTouch.force/nativeTouch.maximumPossibleForce));
+  }
 }
 
 /**

From 83fd314e375b182551f33ca5c9f7b7125ae1e86b Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Wed, 27 Jan 2016 07:26:55 -0800
Subject: [PATCH 0894/1411] Moving more unit tests to open source

Reviewed By: foghina, mkonicek

Differential Revision: D2865561

fb-gh-sync-id: 7aab67d205b94d657a6ec7bf81a4ecee644eabc2
---
 .../java/robolectric3/robolectric/BUCK        |   3 -
 .../java/com/facebook/react/uimanager/BUCK    |  37 +
 .../LayoutPropertyApplicatorTest.java         | 449 ++++++++++
 .../ReactPropAnnotationSetterSpecTest.java    | 143 +++
 .../ReactPropAnnotationSetterTest.java        | 493 +++++++++++
 .../uimanager/ReactPropConstantsTest.java     | 188 ++++
 .../ReactPropForShadowNodeSetterTest.java     | 133 +++
 .../ReactPropForShadowNodeSpecTest.java       | 123 +++
 .../uimanager/SimpleViewPropertyTest.java     | 105 +++
 .../UIManagerModuleConstantsTest.java         | 198 +++++
 .../react/uimanager/UIManagerModuleTest.java  | 827 ++++++++++++++++++
 circle.yml                                    |  12 +-
 12 files changed, 2702 insertions(+), 9 deletions(-)
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/uimanager/BUCK
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/uimanager/LayoutPropertyApplicatorTest.java
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropAnnotationSetterSpecTest.java
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropAnnotationSetterTest.java
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropConstantsTest.java
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropForShadowNodeSetterTest.java
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropForShadowNodeSpecTest.java
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/uimanager/SimpleViewPropertyTest.java
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleConstantsTest.java
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java

diff --git a/ReactAndroid/src/main/third-party/java/robolectric3/robolectric/BUCK b/ReactAndroid/src/main/third-party/java/robolectric3/robolectric/BUCK
index b035e0941063..1f5d94f7670a 100644
--- a/ReactAndroid/src/main/third-party/java/robolectric3/robolectric/BUCK
+++ b/ReactAndroid/src/main/third-party/java/robolectric3/robolectric/BUCK
@@ -17,9 +17,6 @@ android_library(
         react_native_dep('third-party/java/asm:asm'),
         react_native_dep('third-party/java/sqlite:sqlite'),
     ],
-    deps = [
-#         ':locate_android-all',
-    ],
     visibility = ['//ReactAndroid/...',],
 )
 
diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/BUCK b/ReactAndroid/src/test/java/com/facebook/react/uimanager/BUCK
new file mode 100644
index 000000000000..9fe1b6977714
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/BUCK
@@ -0,0 +1,37 @@
+include_defs('//ReactAndroid/DEFS')
+
+robolectric3_test(
+  name = 'uimanager',
+  # Please change the contact to the oncall of your team
+  contacts = ['oncall+fbandroid_sheriff@xmail.facebook.com'],
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/csslayout:csslayout'),
+    react_native_target('java/com/facebook/react:react'),
+    react_native_target('java/com/facebook/react/animation:animation'),
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/touch:touch'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
+    react_native_target('java/com/facebook/react/views/text:text'),
+    react_native_target('java/com/facebook/react/views/view:view'),
+
+    react_native_tests_target('java/com/facebook/react/bridge:testhelpers'),
+    react_native_dep('libraries/fbcore/src/test/java/com/facebook/powermock:powermock'),
+    react_native_dep('third-party/java/robolectric3/robolectric:robolectric'),
+    react_native_dep('third-party/java/fest:fest'),
+    react_native_dep('third-party/java/junit:junit'),
+    react_native_dep('third-party/java/okio:okio'),
+    react_native_dep('third-party/java/mockito:mockito'),
+    react_native_dep('third-party/java/okhttp:okhttp'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC'
+  ],
+)
+
+project_config(
+  test_target = ':uimanager',
+)
diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/LayoutPropertyApplicatorTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/LayoutPropertyApplicatorTest.java
new file mode 100644
index 000000000000..155af711f7a2
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/LayoutPropertyApplicatorTest.java
@@ -0,0 +1,449 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.uimanager;
+
+import android.util.DisplayMetrics;
+
+import com.facebook.csslayout.CSSAlign;
+import com.facebook.csslayout.CSSConstants;
+import com.facebook.csslayout.CSSFlexDirection;
+import com.facebook.csslayout.CSSJustify;
+import com.facebook.csslayout.CSSPositionType;
+import com.facebook.csslayout.Spacing;
+import com.facebook.react.bridge.SimpleMap;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.modules.junit4.rule.PowerMockRule;
+import org.robolectric.RobolectricTestRunner;
+
+import static junit.framework.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyFloat;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.powermock.api.mockito.PowerMockito.mockStatic;
+
+@PrepareForTest({PixelUtil.class})
+@RunWith(RobolectricTestRunner.class)
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+public class LayoutPropertyApplicatorTest {
+
+  @Rule
+  public PowerMockRule rule = new PowerMockRule();
+
+  @Before
+  public void setup() {
+    DisplayMetricsHolder.setDisplayMetrics(new DisplayMetrics());
+  }
+
+  @After
+  public void teardown() {
+    DisplayMetricsHolder.setDisplayMetrics(null);
+  }
+
+  public ReactStylesDiffMap buildStyles(Object... keysAndValues) {
+    return new ReactStylesDiffMap(SimpleMap.of(keysAndValues));
+  }
+
+  @Test
+  public void testDimensions() {
+    LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode());
+    ReactStylesDiffMap map = spy(
+        buildStyles(
+            "width", 10.0,
+            "height", 10.0,
+            "left", 10.0,
+            "top", 10.0));
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode).setStyleWidth(anyFloat());
+    verify(map).getFloat(eq("width"), anyFloat());
+    verify(reactShadowNode).setStyleHeight(anyFloat());
+    verify(map).getFloat(eq("height"), anyFloat());
+    verify(reactShadowNode).setPositionLeft(anyFloat());
+    verify(map).getFloat(eq("left"), anyFloat());
+    verify(reactShadowNode).setPositionTop(anyFloat());
+    verify(map).getFloat(eq("top"), anyFloat());
+
+    reactShadowNode = spy(new LayoutShadowNode());
+    map = spy(buildStyles());
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode, never()).setStyleWidth(anyFloat());
+    verify(map, never()).getFloat(eq("width"), anyFloat());
+    verify(reactShadowNode, never()).setStyleHeight(anyFloat());
+    verify(map, never()).getFloat(eq("height"), anyFloat());
+    verify(reactShadowNode, never()).setPositionLeft(anyFloat());
+    verify(map, never()).getFloat(eq("left"), anyFloat());
+    verify(reactShadowNode, never()).setPositionTop(anyFloat());
+    verify(map, never()).getFloat(eq("top"), anyFloat());
+  }
+
+  @Test
+  public void testFlex() {
+    LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode());
+    ReactStylesDiffMap map = spy(buildStyles("flex", 10.0));
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode).setFlex(anyFloat());
+    verify(map).getFloat("flex", 0.f);
+
+    reactShadowNode = spy(new LayoutShadowNode());
+    map = spy(buildStyles());
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode, never()).setFlex(anyFloat());
+    verify(map, never()).getFloat("flex", 0.f);
+  }
+
+  @Test
+  public void testPosition() {
+    LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode());
+    ReactStylesDiffMap map = spy(buildStyles(
+            "position", "absolute",
+            "bottom", 10.0,
+            "right", 5.0));
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode).setPositionBottom(anyFloat());
+    verify(reactShadowNode).setPositionRight(anyFloat());
+    verify(reactShadowNode).setPositionType(any(CSSPositionType.class));
+    verify(map).getFloat("bottom", Float.NaN);
+    verify(map).getFloat("right", Float.NaN);
+
+    reactShadowNode = spy(new LayoutShadowNode());
+    map = spy(buildStyles());
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode, never()).setPositionBottom(anyFloat());
+    verify(reactShadowNode, never()).setPositionRight(anyFloat());
+    verify(reactShadowNode, never()).setPositionType(any(CSSPositionType.class));
+    verify(map, never()).getFloat("bottom", Float.NaN);
+    verify(map, never()).getFloat("right", Float.NaN);
+  }
+
+  @Test
+  public void testMargin() {
+    // margin
+    LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode());
+    ReactStylesDiffMap map = spy(buildStyles("margin", 10.0));
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode).setMargin(eq(Spacing.ALL), anyFloat());
+    verify(map).getFloat("margin", CSSConstants.UNDEFINED);
+
+    // marginVertical
+    reactShadowNode = spy(new LayoutShadowNode());
+    map = spy(buildStyles("marginVertical", 10.0));
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode).setMargin(eq(Spacing.VERTICAL), anyFloat());
+    verify(map).getFloat("marginVertical", CSSConstants.UNDEFINED);
+
+    // marginHorizontal
+    reactShadowNode = spy(new LayoutShadowNode());
+    map = spy(buildStyles("marginHorizontal", 10.0));
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode).setMargin(eq(Spacing.HORIZONTAL), anyFloat());
+    verify(map).getFloat("marginHorizontal", CSSConstants.UNDEFINED);
+
+    // marginTop
+    reactShadowNode = spy(new LayoutShadowNode());
+    map = spy(buildStyles("marginTop", 10.0));
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode).setMargin(eq(Spacing.TOP), anyFloat());
+    verify(map).getFloat("marginTop", CSSConstants.UNDEFINED);
+
+    // marginBottom
+    reactShadowNode = spy(new LayoutShadowNode());
+    map = spy(buildStyles("marginBottom", 10.0));
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode).setMargin(eq(Spacing.BOTTOM), anyFloat());
+    verify(map).getFloat("marginBottom", CSSConstants.UNDEFINED);
+
+    // marginLeft
+    reactShadowNode = spy(new LayoutShadowNode());
+    map = spy(buildStyles("marginLeft", 10.0));
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode).setMargin(eq(Spacing.LEFT), anyFloat());
+    verify(map).getFloat("marginLeft", CSSConstants.UNDEFINED);
+
+    // marginRight
+    reactShadowNode = spy(new LayoutShadowNode());
+    map = spy(buildStyles("marginRight", 10.0));
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode).setMargin(eq(Spacing.RIGHT), anyFloat());
+    verify(map).getFloat("marginRight", CSSConstants.UNDEFINED);
+
+    // no margin
+    reactShadowNode = spy(new LayoutShadowNode());
+    map = spy(buildStyles());
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode, never()).setMargin(anyInt(), anyFloat());
+    verify(map, never()).getFloat("margin", CSSConstants.UNDEFINED);
+  }
+
+  @Test
+  public void testPadding() {
+    // padding
+    LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode());
+    ReactStylesDiffMap map = spy(buildStyles("padding", 10.0));
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode).setPadding(eq(Spacing.ALL), anyFloat());
+    verify(map).getFloat("padding", CSSConstants.UNDEFINED);
+
+    // paddingVertical
+    reactShadowNode = spy(new LayoutShadowNode());
+    map = spy(buildStyles("paddingVertical", 10.0));
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode).setPadding(eq(Spacing.VERTICAL), anyFloat());
+    verify(map).getFloat("paddingVertical", CSSConstants.UNDEFINED);
+
+    // paddingHorizontal
+    reactShadowNode = spy(new LayoutShadowNode());
+    map = spy(buildStyles("paddingHorizontal", 10.0));
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode).setPadding(eq(Spacing.HORIZONTAL), anyFloat());
+    verify(map).getFloat("paddingHorizontal", CSSConstants.UNDEFINED);
+
+    // paddingTop
+    reactShadowNode = spy(new LayoutShadowNode());
+    map = spy(buildStyles("paddingTop", 10.0));
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode).setPadding(eq(Spacing.TOP), anyFloat());
+    verify(map).getFloat("paddingTop", CSSConstants.UNDEFINED);
+
+    // paddingBottom
+    reactShadowNode = spy(new LayoutShadowNode());
+    map = spy(buildStyles("paddingBottom", 10.0));
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode).setPadding(eq(Spacing.BOTTOM), anyFloat());
+    verify(map).getFloat("paddingBottom", CSSConstants.UNDEFINED);
+
+    // paddingLeft
+    reactShadowNode = spy(new LayoutShadowNode());
+    map = spy(buildStyles("paddingLeft", 10.0));
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode).setPadding(eq(Spacing.LEFT), anyFloat());
+    verify(map).getFloat("paddingLeft", CSSConstants.UNDEFINED);
+
+    // paddingRight
+    reactShadowNode = spy(new LayoutShadowNode());
+    map = spy(buildStyles("paddingRight", 10.0));
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode).setPadding(eq(Spacing.RIGHT), anyFloat());
+    verify(map).getFloat("paddingRight", CSSConstants.UNDEFINED);
+
+    // no padding
+    reactShadowNode = spy(new LayoutShadowNode());
+    map = spy(buildStyles());
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode, never()).setPadding(anyInt(), anyFloat());
+    verify(map, never()).getFloat("padding", CSSConstants.UNDEFINED);
+  }
+
+  @Test
+  public void testEnumerations() {
+    LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode());
+    ReactStylesDiffMap map = buildStyles(
+        "flexDirection", "column",
+        "alignSelf", "stretch",
+        "alignItems", "center",
+        "justifyContent", "space_between",
+        "position", "relative");
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode).setFlexDirection(CSSFlexDirection.COLUMN);
+    verify(reactShadowNode).setAlignSelf(CSSAlign.STRETCH);
+    verify(reactShadowNode).setAlignItems(CSSAlign.CENTER);
+    verify(reactShadowNode).setJustifyContent(CSSJustify.SPACE_BETWEEN);
+    verify(reactShadowNode).setPositionType(CSSPositionType.RELATIVE);
+
+    reactShadowNode = spy(new LayoutShadowNode());
+    map = buildStyles();
+    reactShadowNode.updateProperties(map);
+
+    verify(reactShadowNode, never()).setFlexDirection(any(CSSFlexDirection.class));
+    verify(reactShadowNode, never()).setAlignSelf(any(CSSAlign.class));
+    verify(reactShadowNode, never()).setAlignItems(any(CSSAlign.class));
+    verify(reactShadowNode, never()).setJustifyContent(any(CSSJustify.class));
+    verify(reactShadowNode, never()).setPositionType(any(CSSPositionType.class));
+  }
+
+  @Test
+  public void testPropertiesResetToDefault() {
+    DisplayMetrics displayMetrics = new DisplayMetrics();
+    displayMetrics.density = 1.0f;
+    DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
+
+    LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode());
+    ReactStylesDiffMap map = buildStyles(
+        "width", 10.0,
+        "height", 10.0,
+        "left", 10.0,
+        "top", 10.0,
+        "flex", 1.0,
+        "padding", 10.0,
+        "marginLeft", 10.0,
+        "borderTopWidth", 10.0,
+        "flexDirection", "row",
+        "alignSelf", "stretch",
+        "alignItems", "center",
+        "justifyContent", "space_between",
+        "position", "absolute");
+
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode).setStyleWidth(10.f);
+    verify(reactShadowNode).setStyleHeight(10.f);
+    verify(reactShadowNode).setPositionLeft(10.f);
+    verify(reactShadowNode).setPositionTop(10.f);
+    verify(reactShadowNode).setFlex(1.0f);
+    verify(reactShadowNode).setPadding(Spacing.ALL, 10.f);
+    verify(reactShadowNode).setMargin(Spacing.LEFT, 10.f);
+    verify(reactShadowNode).setBorder(Spacing.TOP, 10.f);
+    verify(reactShadowNode).setFlexDirection(CSSFlexDirection.ROW);
+    verify(reactShadowNode).setAlignSelf(CSSAlign.STRETCH);
+    verify(reactShadowNode).setAlignItems(CSSAlign.CENTER);
+    verify(reactShadowNode).setJustifyContent(CSSJustify.SPACE_BETWEEN);
+    verify(reactShadowNode).setPositionType(CSSPositionType.ABSOLUTE);
+
+    map = buildStyles(
+        "width", null,
+        "height", null,
+        "left", null,
+        "top", null,
+        "flex", null,
+        "padding", null,
+        "marginLeft", null,
+        "borderTopWidth", null,
+        "flexDirection", null,
+        "alignSelf", null,
+        "alignItems", null,
+        "justifyContent", null,
+        "position", null);
+
+    reset(reactShadowNode);
+    reactShadowNode.updateProperties(map);
+    verify(reactShadowNode).setStyleWidth(CSSConstants.UNDEFINED);
+    verify(reactShadowNode).setStyleHeight(CSSConstants.UNDEFINED);
+    verify(reactShadowNode).setPositionLeft(CSSConstants.UNDEFINED);
+    verify(reactShadowNode).setPositionTop(CSSConstants.UNDEFINED);
+    verify(reactShadowNode).setFlex(0.f);
+    verify(reactShadowNode).setPadding(Spacing.ALL, CSSConstants.UNDEFINED);
+    verify(reactShadowNode).setMargin(Spacing.LEFT, CSSConstants.UNDEFINED);
+    verify(reactShadowNode).setBorder(Spacing.TOP, CSSConstants.UNDEFINED);
+    verify(reactShadowNode).setFlexDirection(CSSFlexDirection.COLUMN);
+    verify(reactShadowNode).setAlignSelf(CSSAlign.AUTO);
+    verify(reactShadowNode).setAlignItems(CSSAlign.STRETCH);
+    verify(reactShadowNode).setJustifyContent(CSSJustify.FLEX_START);
+    verify(reactShadowNode).setPositionType(CSSPositionType.RELATIVE);
+  }
+
+  @Test
+  public void testSettingDefaultStyleValues() {
+    mockStatic(PixelUtil.class);
+    when(PixelUtil.toPixelFromDIP(anyFloat())).thenAnswer(
+        new Answer() {
+          @Override
+          public Float answer(InvocationOnMock invocation) throws Throwable {
+            Object[] args = invocation.getArguments();
+            return (Float) args[0];
+          }
+        });
+
+    LayoutShadowNode[] nodes = new LayoutShadowNode[7];
+    for (int idx = 0; idx < nodes.length; idx++) {
+      nodes[idx] = new LayoutShadowNode();
+      nodes[idx].setDefaultPadding(Spacing.LEFT, 15);
+      nodes[idx].setDefaultPadding(Spacing.TOP, 25);
+      nodes[idx].setDefaultPadding(Spacing.RIGHT, 35);
+      nodes[idx].setDefaultPadding(Spacing.BOTTOM, 45);
+    }
+
+    ReactStylesDiffMap[] mapNodes = new ReactStylesDiffMap[7];
+    mapNodes[0] = buildStyles("paddingLeft", 10.0, "paddingHorizontal", 5.0);
+    mapNodes[1] = buildStyles("padding", 10.0, "paddingTop", 5.0);
+    mapNodes[2] = buildStyles("paddingLeft", 10.0, "paddingVertical", 5.0);
+    mapNodes[3] = buildStyles("paddingBottom", 10.0, "paddingHorizontal", 5.0);
+    mapNodes[4] = buildStyles("padding", null, "paddingTop", 5.0);
+    mapNodes[5] = buildStyles(
+        "paddingRight", 10.0,
+        "paddingHorizontal", null,
+        "paddingVertical", 7.0);
+    mapNodes[6] = buildStyles("margin", 5.0);
+
+    for (int idx = 0; idx < nodes.length; idx++) {
+      nodes[idx].updateProperties(mapNodes[idx]);
+    }
+
+    assertEquals(10.0, nodes[0].getPadding().get(Spacing.LEFT), .0001);
+    assertEquals(25.0, nodes[0].getPadding().get(Spacing.TOP), .0001);
+    assertEquals(5.0, nodes[0].getPadding().get(Spacing.RIGHT), .0001);
+    assertEquals(45.0, nodes[0].getPadding().get(Spacing.BOTTOM), .0001);
+
+    assertEquals(10.0, nodes[1].getPadding().get(Spacing.LEFT), .0001);
+    assertEquals(5.0, nodes[1].getPadding().get(Spacing.TOP), .0001);
+    assertEquals(10.0, nodes[1].getPadding().get(Spacing.RIGHT), .0001);
+    assertEquals(10.0, nodes[1].getPadding().get(Spacing.BOTTOM), .0001);
+
+    assertEquals(10.0, nodes[2].getPadding().get(Spacing.LEFT), .0001);
+    assertEquals(5.0, nodes[2].getPadding().get(Spacing.TOP), .0001);
+    assertEquals(35.0, nodes[2].getPadding().get(Spacing.RIGHT), .0001);
+    assertEquals(5.0, nodes[2].getPadding().get(Spacing.BOTTOM), .0001);
+
+    assertEquals(5.0, nodes[3].getPadding().get(Spacing.LEFT), .0001);
+    assertEquals(25.0, nodes[3].getPadding().get(Spacing.TOP), .0001);
+    assertEquals(5.0, nodes[3].getPadding().get(Spacing.RIGHT), .0001);
+    assertEquals(10.0, nodes[3].getPadding().get(Spacing.BOTTOM), .0001);
+
+    assertEquals(15.0, nodes[4].getPadding().get(Spacing.LEFT), .0001);
+    assertEquals(5.0, nodes[4].getPadding().get(Spacing.TOP), .0001);
+    assertEquals(35.0, nodes[4].getPadding().get(Spacing.RIGHT), .0001);
+    assertEquals(45.0, nodes[4].getPadding().get(Spacing.BOTTOM), .0001);
+
+    assertEquals(15.0, nodes[5].getPadding().get(Spacing.LEFT), .0001);
+    assertEquals(7.0, nodes[5].getPadding().get(Spacing.TOP), .0001);
+    assertEquals(10.0, nodes[5].getPadding().get(Spacing.RIGHT), .0001);
+    assertEquals(7.0, nodes[5].getPadding().get(Spacing.BOTTOM), .0001);
+
+    assertEquals(15.0, nodes[6].getPadding().get(Spacing.LEFT), .0001);
+    assertEquals(25.0, nodes[6].getPadding().get(Spacing.TOP), .0001);
+    assertEquals(35.0, nodes[6].getPadding().get(Spacing.RIGHT), .0001);
+    assertEquals(45.0, nodes[6].getPadding().get(Spacing.BOTTOM), .0001);
+  }
+}
diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropAnnotationSetterSpecTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropAnnotationSetterSpecTest.java
new file mode 100644
index 000000000000..8df49c6f6e69
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropAnnotationSetterSpecTest.java
@@ -0,0 +1,143 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.uimanager;
+
+import java.util.Date;
+
+import android.view.View;
+
+import com.facebook.react.uimanager.annotations.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactPropGroup;
+
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.modules.junit4.rule.PowerMockRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+/**
+ * Test that verifies that spec of methods annotated with @ReactProp is correct
+ */
+@RunWith(RobolectricTestRunner.class)
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+public class ReactPropAnnotationSetterSpecTest {
+
+  @Rule
+  public PowerMockRule rule = new PowerMockRule();
+
+  private abstract class BaseViewManager extends ViewManager<View, ReactShadowNode> {
+
+    @Override
+    public String getName() {
+      return "IgnoredName";
+    }
+
+    @Override
+    public ReactShadowNode createShadowNodeInstance() {
+      return null;
+    }
+
+    @Override
+    public Class<? extends ReactShadowNode> getShadowNodeClass() {
+      return ReactShadowNode.class;
+    }
+
+    @Override
+    protected View createViewInstance(ThemedReactContext reactContext) {
+      return null;
+    }
+
+    @Override
+    public void updateExtraData(View root, Object extraData) {
+    }
+  }
+
+  @Test(expected = RuntimeException.class)
+  public void testMethodWithWongNumberOfParams() {
+    new BaseViewManager() {
+      @ReactProp(name = "prop")
+      public void setterWithIncorrectNumberOfArgs(View v, boolean value, boolean otherValue) {
+      }
+    }.getNativeProps();
+  }
+
+  @Test(expected = RuntimeException.class)
+  public void testMethodWithTooFewParams() {
+    new BaseViewManager() {
+      @ReactProp(name = "prop")
+      public void setterWithTooFewParams(View v) {
+      }
+    }.getNativeProps();
+  }
+
+  @Test(expected = RuntimeException.class)
+  public void testUnsupportedPropValueType() {
+    new BaseViewManager() {
+      @ReactProp(name = "prop")
+      public void setterWithUnsupportedValueType(View v, Date value) {
+      }
+    }.getNativeProps();
+  }
+
+  @Test(expected = RuntimeException.class)
+  public void testSetterWIthNonViewParam() {
+    new BaseViewManager() {
+      @ReactProp(name = "prop")
+      public void setterWithNonViewParam(Object v, boolean value) {
+      }
+    }.getNativeProps();
+  }
+
+  @Test(expected = RuntimeException.class)
+  public void testGroupInvalidNumberOfParams() {
+    new BaseViewManager() {
+      @ReactPropGroup(names = {"prop1", "prop2"})
+      public void setterWIthInvalidNumberOfParams(View v, int index, float value, float other) {
+      }
+    }.getNativeProps();
+  }
+
+  @Test(expected = RuntimeException.class)
+  public void testGroupTooFewParams() {
+    new BaseViewManager() {
+      @ReactPropGroup(names = {"prop1", "prop2"})
+      public void setterWIthTooFewParams(View v, int index) {
+      }
+    }.getNativeProps();
+  }
+
+  @Test(expected = RuntimeException.class)
+  public void testGroupNoIndexParam() {
+    new BaseViewManager() {
+      @ReactPropGroup(names = {"prop1", "prop2"})
+      public void setterWithoutIndexParam(View v, float value, float sth) {
+      }
+    }.getNativeProps();
+  }
+
+  @Test(expected = RuntimeException.class)
+  public void testGroupNoViewParam() {
+    new BaseViewManager() {
+      @ReactPropGroup(names = {"prop1", "prop2"})
+      public void setterWithoutViewParam(Object v, int index, float value) {
+      }
+    }.getNativeProps();
+  }
+
+  @Test(expected = RuntimeException.class)
+  public void testGroupUnsupportedPropType() {
+    new BaseViewManager() {
+      @ReactPropGroup(names = {"prop1", "prop2"})
+      public void setterWithUnsupportedPropType(View v, int index, long value) {
+      }
+    }.getNativeProps();
+  }
+}
diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropAnnotationSetterTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropAnnotationSetterTest.java
new file mode 100644
index 000000000000..88cbbf7d3f26
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropAnnotationSetterTest.java
@@ -0,0 +1,493 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.uimanager;
+
+import android.view.View;
+
+import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.SimpleArray;
+import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.uimanager.annotations.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactPropGroup;
+
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.junit.Rule;
+import org.junit.Test;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.modules.junit4.rule.PowerMockRule;
+import org.robolectric.RobolectricTestRunner;
+
+import static org.fest.assertions.api.Assertions.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+/**
+ * Test updating view through {@link ViewManager} with {@link ReactProp} and {@link ReactPropGroup}
+ * annotations.
+ */
+@RunWith(RobolectricTestRunner.class)
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+public class ReactPropAnnotationSetterTest {
+
+  @Rule
+  public PowerMockRule rule = new PowerMockRule();
+
+  public interface ViewManagerUpdatesReceiver {
+    void onBooleanSetterCalled(boolean value);
+    void onIntSetterCalled(int value);
+    void onDoubleSetterCalled(double value);
+    void onFloatSetterCalled(float value);
+    void onStringSetterCalled(String value);
+    void onBoxedBooleanSetterCalled(Boolean value);
+    void onBoxedIntSetterCalled(Integer value);
+    void onArraySetterCalled(ReadableArray value);
+    void onMapSetterCalled(ReadableMap value);
+    void onFloatGroupPropSetterCalled(int index, float value);
+    void onIntGroupPropSetterCalled(int index, int value);
+    void onBoxedIntGroupPropSetterCalled(int index, Integer value);
+  }
+
+  private class ViewManagerUnderTest extends ViewManager<View, ReactShadowNode> {
+
+    final ViewManagerUpdatesReceiver mViewManagerUpdatesReceiver;
+
+    private ViewManagerUnderTest(ViewManagerUpdatesReceiver viewManagerUpdatesReceiver) {
+      mViewManagerUpdatesReceiver = viewManagerUpdatesReceiver;
+    }
+
+    @Override
+    public String getName() {
+      return "RedpandasLivestreamVideoView";
+    }
+
+    @Override
+    public ReactShadowNode createShadowNodeInstance() {
+      fail("This method should not be executed as a part of this test");
+      return null;
+    }
+
+    @Override
+    public Class<? extends ReactShadowNode> getShadowNodeClass() {
+      return ReactShadowNode.class;
+    }
+
+    @Override
+    protected View createViewInstance(ThemedReactContext reactContext) {
+      fail("This method should not be executed as a part of this test");
+      return null;
+    }
+
+    @Override
+    public void updateExtraData(View root, Object extraData) {
+      fail("This method should not be executed as a part of this test");
+    }
+
+    @ReactProp(name = "boolProp")
+    public void setBoolProp(View v, boolean value) {
+      mViewManagerUpdatesReceiver.onBooleanSetterCalled(value);
+    }
+
+    @ReactProp(name = "boolPropWithDefault", defaultBoolean = true)
+    public void setBoolPropWithDefault(View v, boolean value) {
+      mViewManagerUpdatesReceiver.onBooleanSetterCalled(value);
+    }
+
+    @ReactProp(name = "intProp")
+    public void setIntProp(View v, int value) {
+      mViewManagerUpdatesReceiver.onIntSetterCalled(value);
+    }
+
+    @ReactProp(name = "intPropWithDefault", defaultInt = 7168)
+    public void setIntPropWithDefault(View v, int value) {
+      mViewManagerUpdatesReceiver.onIntSetterCalled(value);
+    }
+
+    @ReactProp(name = "floatProp")
+    public void setFloatProp(View v, float value) {
+      mViewManagerUpdatesReceiver.onFloatSetterCalled(value);
+    }
+
+    @ReactProp(name = "floatPropWithDefault", defaultFloat = 14.0f)
+    public void setFloatPropWithDefault(View v, float value) {
+      mViewManagerUpdatesReceiver.onFloatSetterCalled(value);
+    }
+
+    @ReactProp(name = "doubleProp")
+    public void setDoubleProp(View v, double value) {
+      mViewManagerUpdatesReceiver.onDoubleSetterCalled(value);
+    }
+
+    @ReactProp(name = "doublePropWithDefault", defaultDouble = -88.0)
+    public void setDoublePropWithDefault(View v, double value) {
+      mViewManagerUpdatesReceiver.onDoubleSetterCalled(value);
+    }
+
+    @ReactProp(name = "stringProp")
+    public void setStringProp(View v, String value) {
+      mViewManagerUpdatesReceiver.onStringSetterCalled(value);
+    }
+
+    @ReactProp(name = "boxedBoolProp")
+    public void setBoxedBoolProp(View v, Boolean value) {
+      mViewManagerUpdatesReceiver.onBoxedBooleanSetterCalled(value);
+    }
+
+    @ReactProp(name = "boxedIntProp")
+    public void setBoxedIntProp(View v, Integer value) {
+      mViewManagerUpdatesReceiver.onBoxedIntSetterCalled(value);
+    }
+
+    @ReactProp(name = "arrayProp")
+    public void setArrayProp(View v, ReadableArray value) {
+      mViewManagerUpdatesReceiver.onArraySetterCalled(value);
+    }
+
+    @ReactProp(name = "mapProp")
+    public void setMapProp(View v, ReadableMap value) {
+      mViewManagerUpdatesReceiver.onMapSetterCalled(value);
+    }
+
+    @ReactPropGroup(names = {
+        "floatGroupPropFirst",
+        "floatGroupPropSecond",
+    })
+    public void setFloatGroupProp(View v, int index, float value) {
+      mViewManagerUpdatesReceiver.onFloatGroupPropSetterCalled(index, value);
+    }
+
+    @ReactPropGroup(names = {
+        "floatGroupPropWithDefaultFirst",
+        "floatGroupPropWithDefaultSecond",
+    }, defaultFloat = -100.0f)
+    public void setFloatGroupPropWithDefault(View v, int index, float value) {
+      mViewManagerUpdatesReceiver.onFloatGroupPropSetterCalled(index, value);
+    }
+
+    @ReactPropGroup(names = {
+        "intGroupPropFirst",
+        "intGroupPropSecond"
+    })
+    public void setIntGroupProp(View v, int index, int value) {
+      mViewManagerUpdatesReceiver.onIntGroupPropSetterCalled(index, value);
+    }
+
+    @ReactPropGroup(names = {
+        "intGroupPropWithDefaultFirst",
+        "intGroupPropWithDefaultSecond"
+    }, defaultInt = 555)
+    public void setIntGroupPropWithDefault(View v, int index, int value) {
+      mViewManagerUpdatesReceiver.onIntGroupPropSetterCalled(index, value);
+    }
+
+    @ReactPropGroup(names = {
+        "boxedIntGroupPropFirst",
+        "boxedIntGroupPropSecond",
+    })
+    public void setBoxedIntGroupProp(View v, int index, Integer value) {
+      mViewManagerUpdatesReceiver.onBoxedIntGroupPropSetterCalled(index, value);
+    }
+  }
+
+  public static ReactStylesDiffMap buildStyles(Object... keysAndValues) {
+    return new ReactStylesDiffMap(SimpleMap.of(keysAndValues));
+  }
+
+  private ViewManagerUnderTest mViewManager;
+  private ViewManagerUpdatesReceiver mUpdatesReceiverMock;
+
+  @Before
+  public void setup() {
+    mUpdatesReceiverMock = mock(ViewManagerUpdatesReceiver.class);
+    mViewManager = new ViewManagerUnderTest(mUpdatesReceiverMock);
+  }
+
+  @Test
+  public void testBooleanSetter() {
+    mViewManager.updateProperties(null, buildStyles("boolProp", true));
+    verify(mUpdatesReceiverMock).onBooleanSetterCalled(true);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("boolProp", false));
+    verify(mUpdatesReceiverMock).onBooleanSetterCalled(false);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("boolProp", null));
+    verify(mUpdatesReceiverMock).onBooleanSetterCalled(false);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("boolPropWithDefault", false));
+    verify(mUpdatesReceiverMock).onBooleanSetterCalled(false);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("boolPropWithDefault", null));
+    verify(mUpdatesReceiverMock).onBooleanSetterCalled(true);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+  }
+
+  @Test
+  public void testIntSetter() {
+    mViewManager.updateProperties(null, buildStyles("intProp", 13));
+    verify(mUpdatesReceiverMock).onIntSetterCalled(13);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("intProp", null));
+    verify(mUpdatesReceiverMock).onIntSetterCalled(0);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("intPropWithDefault", -1));
+    verify(mUpdatesReceiverMock).onIntSetterCalled(-1);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("intPropWithDefault", null));
+    verify(mUpdatesReceiverMock).onIntSetterCalled(7168);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+  }
+
+  @Test
+  public void testDoubleSetter() {
+    mViewManager.updateProperties(null, buildStyles("doubleProp", 13.0));
+    verify(mUpdatesReceiverMock).onDoubleSetterCalled(13.0);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("doubleProp", null));
+    verify(mUpdatesReceiverMock).onDoubleSetterCalled(0.0);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("doublePropWithDefault", -1.0));
+    verify(mUpdatesReceiverMock).onDoubleSetterCalled(-1.0);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("doublePropWithDefault", null));
+    verify(mUpdatesReceiverMock).onDoubleSetterCalled(-88.0);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+  }
+
+  @Test
+  public void testFloatSetter() {
+    mViewManager.updateProperties(null, buildStyles("floatProp", 13.0));
+    verify(mUpdatesReceiverMock).onFloatSetterCalled(13.0f);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("floatProp", null));
+    verify(mUpdatesReceiverMock).onFloatSetterCalled(0.0f);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("floatPropWithDefault", -1.0));
+    verify(mUpdatesReceiverMock).onFloatSetterCalled(-1.0f);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("floatPropWithDefault", null));
+    verify(mUpdatesReceiverMock).onFloatSetterCalled(14.0f);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+  }
+
+  @Test
+  public void testStringSetter() {
+    mViewManager.updateProperties(null, buildStyles("stringProp", "someRandomString"));
+    verify(mUpdatesReceiverMock).onStringSetterCalled("someRandomString");
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("stringProp", null));
+    verify(mUpdatesReceiverMock).onStringSetterCalled(null);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+  }
+
+  @Test
+  public void testBoxedBooleanSetter() {
+    mViewManager.updateProperties(null, buildStyles("boxedBoolProp", true));
+    verify(mUpdatesReceiverMock).onBoxedBooleanSetterCalled(Boolean.TRUE);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("boxedBoolProp", false));
+    verify(mUpdatesReceiverMock).onBoxedBooleanSetterCalled(Boolean.FALSE);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("boxedBoolProp", null));
+    verify(mUpdatesReceiverMock).onBoxedBooleanSetterCalled(null);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+  }
+
+  @Test
+  public void testBoxedIntSetter() {
+    mViewManager.updateProperties(null, buildStyles("boxedIntProp", 55));
+    verify(mUpdatesReceiverMock).onBoxedIntSetterCalled(Integer.valueOf(55));
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("boxedIntProp", null));
+    verify(mUpdatesReceiverMock).onBoxedIntSetterCalled(null);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+  }
+
+  @Test
+  public void testArraySetter() {
+    ReadableArray array = new SimpleArray();
+    mViewManager.updateProperties(null, buildStyles("arrayProp", array));
+    verify(mUpdatesReceiverMock).onArraySetterCalled(array);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("arrayProp", null));
+    verify(mUpdatesReceiverMock).onArraySetterCalled(null);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+  }
+
+  @Test
+  public void testMapSetter() {
+    ReadableMap map = new SimpleMap();
+    mViewManager.updateProperties(null, buildStyles("mapProp", map));
+    verify(mUpdatesReceiverMock).onMapSetterCalled(map);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("mapProp", null));
+    verify(mUpdatesReceiverMock).onMapSetterCalled(null);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+  }
+
+  @Test
+  public void testFloatGroupSetter() {
+    mViewManager.updateProperties(null, buildStyles("floatGroupPropFirst", 11.0));
+    verify(mUpdatesReceiverMock).onFloatGroupPropSetterCalled(0, 11.0f);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("floatGroupPropSecond", -111.0));
+    verify(mUpdatesReceiverMock).onFloatGroupPropSetterCalled(1, -111.0f);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("floatGroupPropSecond", null));
+    verify(mUpdatesReceiverMock).onFloatGroupPropSetterCalled(1, 0.0f);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("floatGroupPropWithDefaultFirst", null));
+    verify(mUpdatesReceiverMock).onFloatGroupPropSetterCalled(0, -100.0f);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+  }
+
+  @Test
+  public void testIntGroupSetter() {
+    mViewManager.updateProperties(null, buildStyles("intGroupPropFirst", -7));
+    verify(mUpdatesReceiverMock).onIntGroupPropSetterCalled(0, -7);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("intGroupPropSecond", -77));
+    verify(mUpdatesReceiverMock).onIntGroupPropSetterCalled(1, -77);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("intGroupPropSecond", null));
+    verify(mUpdatesReceiverMock).onIntGroupPropSetterCalled(1, 0);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("intGroupPropWithDefaultFirst", 5));
+    verify(mUpdatesReceiverMock).onIntGroupPropSetterCalled(0, 5);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("intGroupPropWithDefaultFirst", null));
+    verify(mUpdatesReceiverMock).onIntGroupPropSetterCalled(0, 555);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("intGroupPropWithDefaultSecond", null));
+    verify(mUpdatesReceiverMock).onIntGroupPropSetterCalled(1, 555);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+  }
+
+  @Test
+  public void testStringGroupSetter() {
+    mViewManager.updateProperties(null, buildStyles("boxedIntGroupPropFirst", -7));
+    verify(mUpdatesReceiverMock).onBoxedIntGroupPropSetterCalled(0, -7);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("boxedIntGroupPropSecond", 12345));
+    verify(mUpdatesReceiverMock).onBoxedIntGroupPropSetterCalled(1, 12345);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mViewManager.updateProperties(null, buildStyles("boxedIntGroupPropSecond", null));
+    verify(mUpdatesReceiverMock).onBoxedIntGroupPropSetterCalled(1, null);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+  }
+
+  @Test(expected = JSApplicationIllegalArgumentException.class)
+  public void testFailToUpdateBoolPropWithMap() {
+    mViewManager.updateProperties(null, buildStyles("boolProp", new SimpleMap()));
+  }
+
+  @Test(expected = JSApplicationIllegalArgumentException.class)
+  public void testFailToUpdateStringPropWithDouble() {
+    mViewManager.updateProperties(null, buildStyles("stringProp", 14.5));
+  }
+
+  @Test(expected = JSApplicationIllegalArgumentException.class)
+  public void testFailToUpdateDoublePropWithString() {
+    mViewManager.updateProperties(null, buildStyles("doubleProp", "hello"));
+  }
+
+  @Test(expected = JSApplicationIllegalArgumentException.class)
+  public void testFailToUpdateIntPropWithDouble() {
+    mViewManager.updateProperties(null, buildStyles("intProp", -7.4));
+  }
+
+  @Test(expected = JSApplicationIllegalArgumentException.class)
+  public void testFailToUpdateArrayPropWithBool() {
+    mViewManager.updateProperties(null, buildStyles("arrayProp", false));
+  }
+
+  @Test(expected = JSApplicationIllegalArgumentException.class)
+  public void testFailToUpdateMapPropWithArray() {
+    mViewManager.updateProperties(null, buildStyles("mapProp", new SimpleArray()));
+  }
+
+  @Test(expected = JSApplicationIllegalArgumentException.class)
+  public void testFailToUpdateBoxedIntPropWithBoxedDouble() {
+    mViewManager.updateProperties(null, buildStyles("boxedIntProp", Double.valueOf(1)));
+  }
+}
diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropConstantsTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropConstantsTest.java
new file mode 100644
index 000000000000..2f6eea4b7451
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropConstantsTest.java
@@ -0,0 +1,188 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.uimanager;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import android.view.View;
+
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.common.MapBuilder;
+import com.facebook.react.uimanager.annotations.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactPropGroup;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.modules.junit4.rule.PowerMockRule;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+import static org.fest.assertions.api.Assertions.fail;
+
+/**
+ * Verifies that prop constants are generated properly based on {@code ReactProp} annotation.
+ */
+@RunWith(RobolectricTestRunner.class)
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+public class ReactPropConstantsTest {
+
+  @Rule
+  public PowerMockRule rule = new PowerMockRule();
+
+  private class ViewManagerUnderTest extends ViewManager<View, ReactShadowNode> {
+
+    @Override
+    public String getName() {
+      return "SomeView";
+    }
+
+    @Override
+    public ReactShadowNode createShadowNodeInstance() {
+      fail("This method should not be executed as a part of this test");
+      return null;
+    }
+
+    @Override
+    protected View createViewInstance(ThemedReactContext reactContext) {
+      fail("This method should not be executed as a part of this test");
+      return null;
+    }
+
+    @Override
+    public Class<? extends ReactShadowNode> getShadowNodeClass() {
+      return ReactShadowNode.class;
+    }
+
+    @Override
+    public void updateExtraData(View root, Object extraData) {
+      fail("This method should not be executed as a part of this test");
+    }
+
+    @ReactProp(name = "boolProp")
+    public void setBoolProp(View v, boolean value) {
+    }
+
+    @ReactProp(name = "intProp")
+    public void setIntProp(View v, int value) {
+    }
+
+    @ReactProp(name = "floatProp")
+    public void setFloatProp(View v, float value) {
+    }
+
+    @ReactProp(name = "doubleProp")
+    public void setDoubleProp(View v, double value) {
+    }
+
+    @ReactProp(name = "stringProp")
+    public void setStringProp(View v, String value) {
+    }
+
+    @ReactProp(name = "boxedBoolProp")
+    public void setBoxedBoolProp(View v, Boolean value) {
+    }
+
+    @ReactProp(name = "boxedIntProp")
+    public void setBoxedIntProp(View v, Integer value) {
+    }
+
+    @ReactProp(name = "arrayProp")
+    public void setArrayProp(View v, ReadableArray value) {
+    }
+
+    @ReactProp(name = "mapProp")
+    public void setMapProp(View v, ReadableMap value) {
+    }
+
+    @ReactPropGroup(names = {
+        "floatGroupPropFirst",
+        "floatGroupPropSecond",
+    })
+    public void setFloatGroupProp(View v, int index, float value) {
+    }
+
+    @ReactPropGroup(names = {
+        "intGroupPropFirst",
+        "intGroupPropSecond"
+    })
+    public void setIntGroupProp(View v, int index, int value) {
+    }
+
+    @ReactPropGroup(names = {
+        "boxedIntGroupPropFirst",
+        "boxedIntGroupPropSecond",
+    })
+    public void setBoxedIntGroupProp(View v, int index, Integer value) {
+    }
+
+    @ReactProp(name = "customIntProp", customType = "date")
+    public void customIntProp(View v, int value) {
+    }
+
+    @ReactPropGroup(names = {
+        "customBoxedIntGroupPropFirst",
+        "customBoxedIntGroupPropSecond"
+    }, customType = "color")
+    public void customIntGroupProp(View v, int index, Integer value) {
+    }
+  }
+
+  @Test
+  public void testNativePropsIncludeCorrectTypes() {
+    List<ViewManager> viewManagers = Arrays.<ViewManager>asList(new ViewManagerUnderTest());
+    ReactApplicationContext reactContext = new ReactApplicationContext(RuntimeEnvironment.application);
+    UIManagerModule uiManagerModule = new UIManagerModule(
+        reactContext,
+        viewManagers,
+        new UIImplementation(reactContext, viewManagers));
+    Map<String, String> constants =
+        (Map) valueAtPath(uiManagerModule.getConstants(), "SomeView", "NativeProps");
+    assertThat(constants).isEqualTo(
+        MapBuilder.<String, String>builder()
+            .put("boolProp", "boolean")
+            .put("intProp", "number")
+            .put("doubleProp", "number")
+            .put("floatProp", "number")
+            .put("stringProp", "String")
+            .put("boxedBoolProp", "boolean")
+            .put("boxedIntProp", "number")
+            .put("arrayProp", "Array")
+            .put("mapProp", "Map")
+            .put("floatGroupPropFirst", "number")
+            .put("floatGroupPropSecond", "number")
+            .put("intGroupPropFirst", "number")
+            .put("intGroupPropSecond", "number")
+            .put("boxedIntGroupPropFirst", "number")
+            .put("boxedIntGroupPropSecond", "number")
+            .put("customIntProp", "date")
+            .put("customBoxedIntGroupPropFirst", "color")
+            .put("customBoxedIntGroupPropSecond", "color")
+            .build());
+  }
+
+  private static Object valueAtPath(Map nestedMap, String... keyPath) {
+    assertThat(keyPath).isNotEmpty();
+    Object value = nestedMap;
+    for (String key : keyPath) {
+      assertThat(value).isInstanceOf(Map.class);
+      nestedMap = (Map) value;
+      assertThat(nestedMap).containsKey(key);
+      value = nestedMap.get(key);
+    }
+    return value;
+  }
+}
diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropForShadowNodeSetterTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropForShadowNodeSetterTest.java
new file mode 100644
index 000000000000..59710b7efcfc
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropForShadowNodeSetterTest.java
@@ -0,0 +1,133 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.uimanager;
+
+import javax.annotation.Nullable;
+
+import com.facebook.react.uimanager.annotations.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactPropGroup;
+
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.junit.Rule;
+import org.junit.Test;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.modules.junit4.rule.PowerMockRule;
+import org.robolectric.RobolectricTestRunner;
+
+import static com.facebook.react.uimanager.ReactPropAnnotationSetterTest.ViewManagerUpdatesReceiver;
+import static com.facebook.react.uimanager.ReactPropAnnotationSetterTest.buildStyles;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+/**
+ * Test {@link ReactProp} annotation for {@link ReactShadowNode}. More comprahensive test of this
+ * annotation can be found in {@link ReactPropAnnotationSetterTest} where we test all possible types
+ * of properties to be updated.
+ */
+@RunWith(RobolectricTestRunner.class)
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+public class ReactPropForShadowNodeSetterTest {
+
+  @Rule
+  public PowerMockRule rule = new PowerMockRule();
+
+  private class ShadowViewUnderTest extends ReactShadowNode {
+
+    private ViewManagerUpdatesReceiver mViewManagerUpdatesReceiver;
+
+    private ShadowViewUnderTest(ViewManagerUpdatesReceiver viewManagerUpdatesReceiver) {
+      mViewManagerUpdatesReceiver = viewManagerUpdatesReceiver;
+    }
+
+    @ReactProp(name = "boolProp")
+    public void setBoolProp(boolean value) {
+      mViewManagerUpdatesReceiver.onBooleanSetterCalled(value);
+    }
+
+    @ReactProp(name = "stringProp")
+    public void setStringProp(@Nullable String value) {
+      mViewManagerUpdatesReceiver.onStringSetterCalled(value);
+    }
+
+    @ReactProp(name = "boxedIntProp")
+    public void setBoxedIntProp(@Nullable Integer value) {
+      mViewManagerUpdatesReceiver.onBoxedIntSetterCalled(value);
+    }
+
+    @ReactPropGroup(names = {
+        "floatGroupPropFirst",
+        "floatGroupPropSecond",
+    })
+    public void setFloatGroupProp(int index, float value) {
+      mViewManagerUpdatesReceiver.onFloatGroupPropSetterCalled(index, value);
+    }
+  }
+
+  private ViewManagerUpdatesReceiver mUpdatesReceiverMock;
+  private ShadowViewUnderTest mShadowView;
+
+  @Before
+  public void setup() {
+    mUpdatesReceiverMock = mock(ViewManagerUpdatesReceiver.class);
+    mShadowView = new ShadowViewUnderTest(mUpdatesReceiverMock);
+  }
+
+  @Test
+  public void testBooleanSetter() {
+    mShadowView.updateProperties(buildStyles("boolProp", true));
+    verify(mUpdatesReceiverMock).onBooleanSetterCalled(true);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mShadowView.updateProperties(buildStyles("boolProp", false));
+    verify(mUpdatesReceiverMock).onBooleanSetterCalled(false);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mShadowView.updateProperties(buildStyles("boolProp", null));
+    verify(mUpdatesReceiverMock).onBooleanSetterCalled(false);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+  }
+
+  @Test
+  public void testStringSetter() {
+    mShadowView.updateProperties(buildStyles("stringProp", "someRandomString"));
+    verify(mUpdatesReceiverMock).onStringSetterCalled("someRandomString");
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mShadowView.updateProperties(buildStyles("stringProp", null));
+    verify(mUpdatesReceiverMock).onStringSetterCalled(null);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+  }
+
+  @Test
+  public void testFloatGroupSetter() {
+    mShadowView.updateProperties(buildStyles("floatGroupPropFirst", 11.0));
+    verify(mUpdatesReceiverMock).onFloatGroupPropSetterCalled(0, 11.0f);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mShadowView.updateProperties(buildStyles("floatGroupPropSecond", -111.0));
+    verify(mUpdatesReceiverMock).onFloatGroupPropSetterCalled(1, -111.0f);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+
+    mShadowView.updateProperties(buildStyles("floatGroupPropSecond", null));
+    verify(mUpdatesReceiverMock).onFloatGroupPropSetterCalled(1, 0.0f);
+    verifyNoMoreInteractions(mUpdatesReceiverMock);
+    reset(mUpdatesReceiverMock);
+  }
+}
diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropForShadowNodeSpecTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropForShadowNodeSpecTest.java
new file mode 100644
index 000000000000..1ddcdf047c23
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropForShadowNodeSpecTest.java
@@ -0,0 +1,123 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.uimanager;
+
+import java.util.Map;
+
+import android.view.View;
+
+import com.facebook.react.uimanager.annotations.ReactProp;
+import com.facebook.react.uimanager.annotations.ReactPropGroup;
+
+import org.junit.Test;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.modules.junit4.rule.PowerMockRule;
+import org.robolectric.RobolectricTestRunner;
+
+/**
+ * Test that verifies that spec of methods annotated with @ReactProp in {@link ReactShadowNode} is
+ * correct
+ */
+@RunWith(RobolectricTestRunner.class)
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+public class ReactPropForShadowNodeSpecTest {
+
+  @Rule
+  public PowerMockRule rule = new PowerMockRule();
+
+  private static class BaseViewManager extends ViewManager {
+
+    private final Class<? extends ReactShadowNode> mShadowNodeClass;
+
+    private BaseViewManager(Class<? extends ReactShadowNode> shadowNodeClass) {
+      mShadowNodeClass = shadowNodeClass;
+    }
+
+    @Override
+    public String getName() {
+      return "IgnoredName";
+    }
+
+    @Override
+    public ReactShadowNode createShadowNodeInstance() {
+      return null;
+    }
+
+    @Override
+    public Class getShadowNodeClass() {
+      return mShadowNodeClass;
+    }
+
+    @Override
+    protected View createViewInstance(ThemedReactContext reactContext) {
+      return null;
+    }
+
+    @Override
+    public void updateExtraData(View root, Object extraData) {
+    }
+  }
+
+  @Test(expected = RuntimeException.class)
+  public void testMethodWithWrongNumberOfParams() {
+    new BaseViewManager(new ReactShadowNode() {
+      @ReactProp(name = "prop")
+      public void setterWithIncorrectNumberOfArgs(boolean value, int anotherValue) {
+      }
+    }.getClass()).getNativeProps();
+  }
+
+  @Test(expected = RuntimeException.class)
+  public void testMethodWithTooFewParams() {
+    new BaseViewManager(new ReactShadowNode() {
+      @ReactProp(name = "prop")
+      public void setterWithNoArgs() {
+      }
+    }.getClass()).getNativeProps();
+  }
+
+  @Test(expected = RuntimeException.class)
+  public void testUnsupportedValueType() {
+    new BaseViewManager(new ReactShadowNode() {
+      @ReactProp(name = "prop")
+      public void setterWithMap(Map value) {
+      }
+    }.getClass()).getNativeProps();
+  }
+
+  @Test(expected = RuntimeException.class)
+  public void testGroupInvalidNumberOfParams() {
+    new BaseViewManager(new ReactShadowNode() {
+      @ReactPropGroup(names = {"prop1", "prop2"})
+      public void setterWithTooManyParams(int index, float value, boolean bool) {
+      }
+    }.getClass()).getNativeProps();
+  }
+
+  @Test(expected = RuntimeException.class)
+  public void testGroupTooFewParams() {
+    new BaseViewManager(new ReactShadowNode() {
+      @ReactPropGroup(names = {"prop1", "prop2"})
+      public void setterWithTooManyParams(int index) {
+      }
+    }.getClass()).getNativeProps();
+  }
+
+  @Test(expected = RuntimeException.class)
+  public void testGroupNoIndexParam() {
+    new BaseViewManager(new ReactShadowNode() {
+      @ReactPropGroup(names = {"prop1", "prop2"})
+      public void setterWithTooManyParams(float value, boolean bool) {
+      }
+    }.getClass()).getNativeProps();
+  }
+}
diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/SimpleViewPropertyTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/SimpleViewPropertyTest.java
new file mode 100644
index 000000000000..76f2b2e21839
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/SimpleViewPropertyTest.java
@@ -0,0 +1,105 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.uimanager;
+
+import java.util.Map;
+
+import android.view.View;
+
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.touch.JSResponderHandler;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactTestHelper;
+import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.bridge.CatalystInstance;
+import com.facebook.react.uimanager.annotations.ReactProp;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.RobolectricTestRunner;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.modules.junit4.rule.PowerMockRule;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+import static org.fest.assertions.api.Assertions.offset;
+
+/**
+ * Verify {@link View} view property being applied properly by {@link SimpleViewManager}
+ */
+@RunWith(RobolectricTestRunner.class)
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+public class SimpleViewPropertyTest {
+
+  @Rule
+  public PowerMockRule rule = new PowerMockRule();
+
+  private static class ConcreteViewManager extends SimpleViewManager<View> {
+
+    @ReactProp(name = "foo")
+    public void setFoo(View view, boolean foo) {
+    }
+
+    @ReactProp(name = "bar")
+    public void setBar(View view, ReadableMap bar) {
+    }
+
+    @Override
+    protected View createViewInstance(ThemedReactContext reactContext) {
+      return new View(reactContext);
+    }
+
+    @Override
+    public String getName() {
+      return "View";
+    }
+  }
+
+  private ReactApplicationContext mContext;
+  private CatalystInstance mCatalystInstanceMock;
+  private ThemedReactContext mThemedContext;
+  private ConcreteViewManager mManager;
+
+  @Before
+  public void setup() {
+    mContext = new ReactApplicationContext(RuntimeEnvironment.application);
+    mCatalystInstanceMock = ReactTestHelper.createMockCatalystInstance();
+    mContext.initializeWithInstance(mCatalystInstanceMock);
+    mThemedContext = new ThemedReactContext(mContext, mContext);
+    mManager = new ConcreteViewManager();
+  }
+
+  public ReactStylesDiffMap buildStyles(Object... keysAndValues) {
+    return new ReactStylesDiffMap(SimpleMap.of(keysAndValues));
+  }
+
+  @Test
+  public void testOpacity() {
+    View view = mManager.createView(mThemedContext, new JSResponderHandler());
+
+    mManager.updateProperties(view, buildStyles());
+    assertThat(view.getAlpha()).isEqualTo(1.0f);
+
+    mManager.updateProperties(view, buildStyles("opacity", 0.31));
+    assertThat(view.getAlpha()).isEqualTo(0.31f, offset(1e-5f));
+
+    mManager.updateProperties(view, buildStyles("opacity", null));
+    assertThat(view.getAlpha()).isEqualTo(1.0f);
+  }
+
+  @Test
+  public void testGetNativeProps() {
+    Map<String, String> nativeProps = mManager.getNativeProps();
+    assertThat(nativeProps.get("foo")).isEqualTo("boolean");
+    assertThat(nativeProps.get("bar")).isEqualTo("Map");
+  }
+}
diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleConstantsTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleConstantsTest.java
new file mode 100644
index 000000000000..5d757eb2ffdc
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleConstantsTest.java
@@ -0,0 +1,198 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.uimanager;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.common.MapBuilder;
+
+import org.fest.assertions.data.MapEntry;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.modules.junit4.rule.PowerMockRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith(RobolectricTestRunner.class)
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+public class UIManagerModuleConstantsTest {
+
+  @Rule
+  public PowerMockRule rule = new PowerMockRule();
+
+  private static final String CUSTOM_BUBBLING_EVENT_TYPES = "customBubblingEventTypes";
+  private static final String CUSTOM_DIRECT_EVENT_TYPES = "customDirectEventTypes";
+
+  private static final Map TWIRL_BUBBLING_EVENT_MAP = MapBuilder.of(
+      "phasedRegistrationNames",
+      MapBuilder.of(
+          "bubbled",
+          "onTwirl",
+          "captured",
+          "onTwirlCaptured"));
+  private static final Map TWIRL_DIRECT_EVENT_MAP = MapBuilder.of("registrationName", "onTwirl");
+
+  private ReactApplicationContext mReactContext;
+  private UIImplementation mUIImplementation;
+
+  @Before
+  public void setUp() {
+    mReactContext = new ReactApplicationContext(RuntimeEnvironment.application);
+    mUIImplementation = mock(UIImplementation.class);
+  }
+
+  @Test
+  public void testNoCustomConstants() {
+    List<ViewManager> viewManagers = Arrays.asList(mock(ViewManager.class));
+    UIManagerModule uiManagerModule = new UIManagerModule(
+        mReactContext,
+        viewManagers,
+        mUIImplementation);
+    Map<String, Object> constants = uiManagerModule.getConstants();
+    assertThat(constants)
+        .containsKey(CUSTOM_BUBBLING_EVENT_TYPES)
+        .containsKey(CUSTOM_DIRECT_EVENT_TYPES)
+        .containsKey("Dimensions");
+  }
+
+  @Test
+  public void testCustomBubblingEvents() {
+    ViewManager mockViewManager = mock(ViewManager.class);
+    List<ViewManager> viewManagers = Arrays.asList(mockViewManager);
+    when(mockViewManager.getExportedCustomBubblingEventTypeConstants())
+        .thenReturn(MapBuilder.of("onTwirl", TWIRL_BUBBLING_EVENT_MAP));
+    UIManagerModule uiManagerModule = new UIManagerModule(
+        mReactContext,
+        viewManagers,
+        mUIImplementation);
+    Map<String, Object> constants = uiManagerModule.getConstants();
+    assertThat((Map) constants.get(CUSTOM_BUBBLING_EVENT_TYPES))
+        .contains(MapEntry.entry("onTwirl", TWIRL_BUBBLING_EVENT_MAP))
+        .containsKey("topChange");
+  }
+
+  @Test
+  public void testCustomDirectEvents() {
+    ViewManager mockViewManager = mock(ViewManager.class);
+    List<ViewManager> viewManagers = Arrays.asList(mockViewManager);
+    when(mockViewManager.getExportedCustomDirectEventTypeConstants())
+        .thenReturn(MapBuilder.of("onTwirl", TWIRL_DIRECT_EVENT_MAP));
+    UIManagerModule uiManagerModule = new UIManagerModule(
+        mReactContext,
+        viewManagers,
+        mUIImplementation);
+    Map<String, Object> constants = uiManagerModule.getConstants();
+    assertThat((Map) constants.get(CUSTOM_DIRECT_EVENT_TYPES))
+        .contains(MapEntry.entry("onTwirl", TWIRL_DIRECT_EVENT_MAP))
+        .containsKey("topLoadingStart");
+  }
+
+  @Test
+  public void testCustomViewConstants() {
+    ViewManager mockViewManager = mock(ViewManager.class);
+    List<ViewManager> viewManagers = Arrays.asList(mockViewManager);
+    when(mockViewManager.getName()).thenReturn("RedPandaPhotoOfTheDayView");
+    when(mockViewManager.getExportedViewConstants())
+        .thenReturn(MapBuilder.of("PhotoSizeType", MapBuilder.of("Small", 1, "Large", 2)));
+    UIManagerModule uiManagerModule = new UIManagerModule(
+        mReactContext,
+        viewManagers,
+        mUIImplementation);
+    Map<String, Object> constants = uiManagerModule.getConstants();
+    assertThat(constants).containsKey("RedPandaPhotoOfTheDayView");
+    assertThat((Map) constants.get("RedPandaPhotoOfTheDayView")).containsKey("Constants");
+    assertThat((Map) valueAtPath(constants, "RedPandaPhotoOfTheDayView", "Constants"))
+        .containsKey("PhotoSizeType");
+  }
+
+  @Test
+  public void testNativeProps() {
+    ViewManager mockViewManager = mock(ViewManager.class);
+    List<ViewManager> viewManagers = Arrays.asList(mockViewManager);
+    when(mockViewManager.getName()).thenReturn("SomeView");
+    when(mockViewManager.getNativeProps())
+        .thenReturn(MapBuilder.of("fooProp", "number"));
+    UIManagerModule uiManagerModule = new UIManagerModule(
+        mReactContext,
+        viewManagers,
+        mUIImplementation);
+    Map<String, Object> constants = uiManagerModule.getConstants();
+    assertThat((String) valueAtPath(constants, "SomeView", "NativeProps", "fooProp"))
+        .isEqualTo("number");
+  }
+
+  @Test
+  public void testMergeConstants() {
+    ViewManager managerX = mock(ViewManager.class);
+    when(managerX.getExportedCustomDirectEventTypeConstants()).thenReturn(MapBuilder.of(
+        "onTwirl",
+        MapBuilder.of(
+            "registrationName",
+            "onTwirl",
+            "keyToOverride",
+            "valueX",
+            "mapToMerge",
+            MapBuilder.of("keyToOverride", "innerValueX", "anotherKey", "valueX"))));
+
+    ViewManager managerY = mock(ViewManager.class);
+    when(managerY.getExportedCustomDirectEventTypeConstants()).thenReturn(MapBuilder.of(
+        "onTwirl",
+        MapBuilder.of(
+            "extraKey",
+            "extraValue",
+            "keyToOverride",
+            "valueY",
+            "mapToMerge",
+            MapBuilder.of("keyToOverride", "innerValueY", "extraKey", "valueY"))));
+
+    List<ViewManager> viewManagers = Arrays.asList(managerX, managerY);
+    UIManagerModule uiManagerModule = new UIManagerModule(
+        mReactContext,
+        viewManagers,
+        mUIImplementation);
+    Map<String, Object> constants = uiManagerModule.getConstants();
+    assertThat((Map) constants.get(CUSTOM_DIRECT_EVENT_TYPES)).containsKey("onTwirl");
+
+    Map twirlMap = (Map) valueAtPath(constants, CUSTOM_DIRECT_EVENT_TYPES, "onTwirl");
+    assertThat(twirlMap)
+        .contains(MapEntry.entry("registrationName", "onTwirl"))
+        .contains(MapEntry.entry("keyToOverride", "valueY"))
+        .contains(MapEntry.entry("extraKey", "extraValue"))
+        .containsKey("mapToMerge");
+
+    Map mapToMerge = (Map) valueAtPath(twirlMap, "mapToMerge");
+    assertThat(mapToMerge)
+        .contains(MapEntry.entry("keyToOverride", "innerValueY"))
+        .contains(MapEntry.entry("anotherKey", "valueX"))
+        .contains(MapEntry.entry("extraKey", "valueY"));
+  }
+
+  private static Object valueAtPath(Map nestedMap, String... keyPath) {
+    assertThat(keyPath).isNotEmpty();
+    Object value = nestedMap;
+    for (String key : keyPath) {
+      assertThat(value).isInstanceOf(Map.class);
+      nestedMap = (Map) value;
+      assertThat(nestedMap).containsKey(key);
+      value = nestedMap.get(key);
+    }
+    return value;
+  }
+}
diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java
new file mode 100644
index 000000000000..26db0858723c
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java
@@ -0,0 +1,827 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.uimanager;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import android.graphics.Color;
+import android.view.Choreographer;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.facebook.react.ReactRootView;
+import com.facebook.react.animation.Animation;
+import com.facebook.react.animation.AnimationPropertyUpdater;
+import com.facebook.react.bridge.Callback;
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.CatalystInstance;
+import com.facebook.react.bridge.SimpleArray;
+import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.views.text.ReactRawTextManager;
+import com.facebook.react.views.text.ReactTextShadowNode;
+import com.facebook.react.views.text.ReactTextViewManager;
+import com.facebook.react.views.view.ReactViewGroup;
+import com.facebook.react.views.view.ReactViewManager;
+import com.facebook.react.bridge.ReactTestHelper;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.modules.junit4.rule.PowerMockRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for {@link UIManagerModule}.
+ */
+@PrepareForTest({Arguments.class, ReactChoreographer.class})
+@RunWith(RobolectricTestRunner.class)
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+public class UIManagerModuleTest {
+
+  @Rule
+  public PowerMockRule rule = new PowerMockRule();
+
+  private ReactApplicationContext mReactContext;
+  private CatalystInstance mCatalystInstanceMock;
+  private ArrayList<Choreographer.FrameCallback> mPendingChoreographerCallbacks;
+
+  @Before
+  public void setUp() {
+    PowerMockito.mockStatic(Arguments.class, ReactChoreographer.class);
+
+    ReactChoreographer choreographerMock = mock(ReactChoreographer.class);
+    PowerMockito.when(Arguments.createArray()).thenAnswer(new Answer<Object>() {
+      @Override
+      public Object answer(InvocationOnMock invocation) throws Throwable {
+        return new SimpleArray();
+      }
+    });
+    PowerMockito.when(Arguments.createMap()).thenAnswer(new Answer<Object>() {
+      @Override
+      public Object answer(InvocationOnMock invocation) throws Throwable {
+        return new SimpleMap();
+      }
+    });
+    PowerMockito.when(ReactChoreographer.getInstance()).thenReturn(choreographerMock);
+
+    mPendingChoreographerCallbacks = new ArrayList<>();
+    doAnswer(new Answer() {
+      @Override
+      public Object answer(InvocationOnMock invocation) throws Throwable {
+        mPendingChoreographerCallbacks
+            .add((Choreographer.FrameCallback) invocation.getArguments()[1]);
+        return null;
+      }
+    }).when(choreographerMock).postFrameCallback(
+        any(ReactChoreographer.CallbackType.class),
+        any(Choreographer.FrameCallback.class));
+
+    mCatalystInstanceMock = ReactTestHelper.createMockCatalystInstance();
+    mReactContext = new ReactApplicationContext(RuntimeEnvironment.application);
+    mReactContext.initializeWithInstance(mCatalystInstanceMock);
+
+    UIManagerModule uiManagerModuleMock = mock(UIManagerModule.class);
+    when(mCatalystInstanceMock.getNativeModule(UIManagerModule.class))
+        .thenReturn(uiManagerModuleMock);
+  }
+
+  @Test
+  public void testCreateSimpleHierarchy() {
+    UIManagerModule uiManager = getUIManagerModule();
+
+    ViewGroup rootView = createSimpleTextHierarchy(uiManager, "Some text");
+
+    assertThat(rootView.getChildCount()).isEqualTo(1);
+
+    View firstChild = rootView.getChildAt(0);
+    assertThat(firstChild).isInstanceOf(TextView.class);
+    assertThat(((TextView) firstChild).getText().toString()).isEqualTo("Some text");
+  }
+
+  @Test
+  public void testUpdateSimpleHierarchy() {
+    UIManagerModule uiManager = getUIManagerModule();
+
+    ViewGroup rootView = createSimpleTextHierarchy(uiManager, "Some text");
+    TextView textView = (TextView) rootView.getChildAt(0);
+
+    int rawTextTag = 3;
+    uiManager.updateView(
+        rawTextTag,
+        ReactRawTextManager.REACT_CLASS,
+        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "New text"));
+
+    uiManager.onBatchComplete();
+    executePendingChoreographerCallbacks();
+
+    assertThat(textView.getText().toString()).isEqualTo("New text");
+  }
+
+  @Test
+  public void testHierarchyWithView() {
+    UIManagerModule uiManager = getUIManagerModule();
+
+    ReactRootView rootView =
+        new ReactRootView(RuntimeEnvironment.application.getApplicationContext());
+    int rootTag = uiManager.addMeasuredRootView(rootView);
+    int viewTag = rootTag + 1;
+    int subViewTag = viewTag + 1;
+
+    uiManager.createView(
+        viewTag,
+        ReactViewManager.REACT_CLASS,
+        rootTag,
+        SimpleMap.of("collapsable", false));
+    uiManager.createView(
+        subViewTag,
+        ReactViewManager.REACT_CLASS,
+        rootTag,
+        SimpleMap.of("collapsable", false));
+
+    uiManager.manageChildren(
+        viewTag,
+        null,
+        null,
+        SimpleArray.of(subViewTag),
+        SimpleArray.of(0),
+        null);
+
+    uiManager.manageChildren(
+        rootTag,
+        null,
+        null,
+        SimpleArray.of(viewTag),
+        SimpleArray.of(0),
+        null);
+
+    uiManager.onBatchComplete();
+    executePendingChoreographerCallbacks();
+
+    assertThat(rootView.getChildCount()).isEqualTo(1);
+
+    ViewGroup child = (ViewGroup) rootView.getChildAt(0);
+    assertThat(child.getChildCount()).isEqualTo(1);
+
+    ViewGroup grandchild = (ViewGroup) child.getChildAt(0);
+    assertThat(grandchild).isInstanceOf(ViewGroup.class);
+    assertThat(grandchild.getChildCount()).isEqualTo(0);
+  }
+
+  @Test
+  public void testMoveViews() {
+    UIManagerModule uiManager = getUIManagerModule();
+    TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
+
+    View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(1);
+    View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(2);
+    View expectedViewAt2 = hierarchy.nativeRootView.getChildAt(0);
+    View expectedViewAt3 = hierarchy.nativeRootView.getChildAt(3);
+
+    uiManager.manageChildren(
+        hierarchy.rootView,
+        SimpleArray.of(1, 0, 2),
+        SimpleArray.of(0, 2, 1),
+        null,
+        null,
+        null);
+
+    uiManager.onBatchComplete();
+    executePendingChoreographerCallbacks();
+
+    assertChildrenAreExactly(
+        hierarchy.nativeRootView,
+        expectedViewAt0,
+        expectedViewAt1,
+        expectedViewAt2,
+        expectedViewAt3);
+  }
+
+  @Test
+  public void testDeleteViews() {
+    UIManagerModule uiManager = getUIManagerModule();
+    TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
+
+    View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(1);
+    View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(2);
+
+    uiManager.manageChildren(
+        hierarchy.rootView,
+        null,
+        null,
+        null,
+        null,
+        SimpleArray.of(0, 3));
+
+    uiManager.onBatchComplete();
+    executePendingChoreographerCallbacks();
+
+    assertChildrenAreExactly(
+        hierarchy.nativeRootView,
+        expectedViewAt0,
+        expectedViewAt1);
+  }
+
+  @Test
+  public void testMoveAndDeleteViews() {
+    UIManagerModule uiManager = getUIManagerModule();
+    TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
+
+    View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(0);
+    View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(3);
+    View expectedViewAt2 = hierarchy.nativeRootView.getChildAt(2);
+
+    uiManager.manageChildren(
+        hierarchy.rootView,
+        SimpleArray.of(3),
+        SimpleArray.of(1),
+        null,
+        null,
+        SimpleArray.of(1));
+
+    uiManager.onBatchComplete();
+    executePendingChoreographerCallbacks();
+
+    assertChildrenAreExactly(
+        hierarchy.nativeRootView,
+        expectedViewAt0,
+        expectedViewAt1,
+        expectedViewAt2);
+  }
+
+  @Test(expected = IllegalViewOperationException.class)
+  public void testMoveAndDeleteRemoveViewsDuplicateRemove() {
+    UIManagerModule uiManager = getUIManagerModule();
+    TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
+
+    uiManager.manageChildren(
+        hierarchy.rootView,
+        SimpleArray.of(3),
+        SimpleArray.of(1),
+        null,
+        null,
+        SimpleArray.of(3));
+
+    uiManager.onBatchComplete();
+    executePendingChoreographerCallbacks();
+  }
+
+  @Test(expected = IllegalViewOperationException.class)
+  public void testDuplicateRemove() {
+    UIManagerModule uiManager = getUIManagerModule();
+    TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
+
+    uiManager.manageChildren(
+        hierarchy.rootView,
+        null,
+        null,
+        null,
+        null,
+        SimpleArray.of(3, 3));
+
+    uiManager.onBatchComplete();
+    executePendingChoreographerCallbacks();
+  }
+
+  @Test
+  public void testMoveAndAddViews() {
+    UIManagerModule uiManager = getUIManagerModule();
+    TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
+
+    int textViewTag = 1000;
+    uiManager.createView(
+        textViewTag,
+        ReactTextViewManager.REACT_CLASS,
+        hierarchy.rootView,
+        SimpleMap.of("collapsable", false));
+
+    View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(0);
+    View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(3);
+    View expectedViewAt3 = hierarchy.nativeRootView.getChildAt(1);
+    View expectedViewAt4 = hierarchy.nativeRootView.getChildAt(2);
+
+    uiManager.manageChildren(
+        hierarchy.rootView,
+        SimpleArray.of(1, 2, 3),
+        SimpleArray.of(3, 4, 1),
+        SimpleArray.of(textViewTag),
+        SimpleArray.of(2),
+        null);
+
+    uiManager.onBatchComplete();
+    executePendingChoreographerCallbacks();
+
+    assertThat(hierarchy.nativeRootView.getChildCount()).isEqualTo(5);
+    assertThat(hierarchy.nativeRootView.getChildAt(0)).isEqualTo(expectedViewAt0);
+    assertThat(hierarchy.nativeRootView.getChildAt(1)).isEqualTo(expectedViewAt1);
+    assertThat(hierarchy.nativeRootView.getChildAt(3)).isEqualTo(expectedViewAt3);
+    assertThat(hierarchy.nativeRootView.getChildAt(4)).isEqualTo(expectedViewAt4);
+  }
+
+  @Test
+  public void testMoveViewsWithChildren() {
+    UIManagerModule uiManager = getUIManagerModule();
+    TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
+
+    View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(0);
+    View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(2);
+    View expectedViewAt2 = hierarchy.nativeRootView.getChildAt(1);
+    View expectedViewAt3 = hierarchy.nativeRootView.getChildAt(3);
+
+    uiManager.manageChildren(
+        hierarchy.rootView,
+        SimpleArray.of(1, 2),
+        SimpleArray.of(2, 1),
+        null,
+        null,
+        null);
+
+    uiManager.onBatchComplete();
+    executePendingChoreographerCallbacks();
+
+    assertChildrenAreExactly(
+        hierarchy.nativeRootView,
+        expectedViewAt0,
+        expectedViewAt1,
+        expectedViewAt2,
+        expectedViewAt3);
+    assertThat(((ViewGroup) hierarchy.nativeRootView.getChildAt(2)).getChildCount()).isEqualTo(2);
+  }
+
+  @Test
+  public void testDeleteViewsWithChildren() {
+    UIManagerModule uiManager = getUIManagerModule();
+    TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
+
+    View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(0);
+    View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(2);
+    View expectedViewAt2 = hierarchy.nativeRootView.getChildAt(3);
+
+    uiManager.manageChildren(
+        hierarchy.rootView,
+        null,
+        null,
+        null,
+        null,
+        SimpleArray.of(1));
+
+    uiManager.onBatchComplete();
+    executePendingChoreographerCallbacks();
+
+    assertChildrenAreExactly(
+        hierarchy.nativeRootView,
+        expectedViewAt0,
+        expectedViewAt1,
+        expectedViewAt2);
+  }
+
+  @Test
+  public void testLayoutAppliedToNodes() throws Exception {
+    UIManagerModule uiManager = getUIManagerModule();
+
+    TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
+
+    int newViewTag = 10000;
+    uiManager.createView(
+        newViewTag,
+        ReactViewManager.REACT_CLASS,
+        hierarchy.rootView,
+        SimpleMap
+            .of("left", 10.0, "top", 20.0, "width", 30.0, "height", 40.0, "collapsable", false));
+
+    uiManager.manageChildren(
+        hierarchy.rootView,
+        null,
+        null,
+        SimpleArray.of(newViewTag),
+        SimpleArray.of(4),
+        null);
+
+    uiManager.onBatchComplete();
+    executePendingChoreographerCallbacks();
+
+    View newView = hierarchy.nativeRootView.getChildAt(4);
+    assertThat(newView.getLeft()).isEqualTo(10);
+    assertThat(newView.getTop()).isEqualTo(20);
+
+    assertThat(newView.getWidth()).isEqualTo(30);
+    assertThat(newView.getHeight()).isEqualTo(40);
+  }
+
+  /**
+   * This is to make sure we execute enqueued operations in the order given by JS.
+   */
+  @Test
+  public void testAddUpdateRemoveInSingleBatch() {
+    UIManagerModule uiManager = getUIManagerModule();
+
+    TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
+
+    int newViewTag = 10000;
+    uiManager.createView(
+        newViewTag,
+        ReactViewManager.REACT_CLASS,
+        hierarchy.rootView,
+        SimpleMap.of("collapsable", false));
+
+    uiManager.manageChildren(
+        hierarchy.rootView,
+        null,
+        null,
+        SimpleArray.of(newViewTag),
+        SimpleArray.of(4),
+        null);
+
+    uiManager.updateView(
+        newViewTag,
+        ReactViewManager.REACT_CLASS,
+        SimpleMap.of("backgroundColor", Color.RED));
+
+    uiManager.manageChildren(
+        hierarchy.rootView,
+        null,
+        null,
+        null,
+        null,
+        SimpleArray.of(4));
+
+    uiManager.onBatchComplete();
+    executePendingChoreographerCallbacks();
+
+    assertThat(hierarchy.nativeRootView.getChildCount()).isEqualTo(4);
+  }
+
+  @Test
+  public void testTagsAssignment() {
+    UIManagerModule uiManager = getUIManagerModule();
+    TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
+
+    View view0 = hierarchy.nativeRootView.getChildAt(0);
+    assertThat(view0.getId()).isEqualTo(hierarchy.view0);
+
+    View viewWithChildren1 = hierarchy.nativeRootView.getChildAt(1);
+    assertThat(viewWithChildren1.getId()).isEqualTo(hierarchy.viewWithChildren1);
+
+    View childView0 = ((ViewGroup) viewWithChildren1).getChildAt(0);
+    assertThat(childView0.getId()).isEqualTo(hierarchy.childView0);
+
+    View childView1 = ((ViewGroup) viewWithChildren1).getChildAt(1);
+    assertThat(childView1.getId()).isEqualTo(hierarchy.childView1);
+
+    View view2 = hierarchy.nativeRootView.getChildAt(2);
+    assertThat(view2.getId()).isEqualTo(hierarchy.view2);
+
+    View view3 = hierarchy.nativeRootView.getChildAt(3);
+    assertThat(view3.getId()).isEqualTo(hierarchy.view3);
+  }
+
+  @Test
+  public void testLayoutPropertyUpdatingOnlyOnLayoutChange() {
+    UIManagerModule uiManager = getUIManagerModule();
+
+    TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
+
+    // Update layout to some values, this way we can verify it hasn't been updated, because the
+    // update process would normally reset it back to some non-negative value
+    View view0 = hierarchy.nativeRootView.getChildAt(0);
+    view0.layout(1, 2, 3, 4);
+
+    // verify that X get updated when we update layout properties
+    uiManager.updateView(
+        hierarchy.view0,
+        ReactViewManager.REACT_CLASS,
+        SimpleMap.of("left", 10.0, "top", 20.0, "width", 30.0, "height", 40.0));
+    uiManager.onBatchComplete();
+    executePendingChoreographerCallbacks();
+    assertThat(view0.getLeft()).isGreaterThan(2);
+
+    // verify that the layout doesn't get updated when we update style property not affecting the
+    // position (e.g., background-color)
+    view0.layout(1, 2, 3, 4);
+    uiManager.updateView(
+        hierarchy.view0,
+        ReactViewManager.REACT_CLASS,
+        SimpleMap.of("backgroundColor", Color.RED));
+    uiManager.onBatchComplete();
+    executePendingChoreographerCallbacks();
+    assertThat(view0.getLeft()).isEqualTo(1);
+  }
+
+  private static class AnimationStub extends Animation {
+
+    public AnimationStub(int animationID, AnimationPropertyUpdater propertyUpdater) {
+      super(animationID, propertyUpdater);
+    }
+
+    @Override
+    public void run() {
+    }
+  }
+
+  @Test
+  public void testAddAndRemoveAnimation() {
+    UIManagerModule uiManagerModule = getUIManagerModule();
+    TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManagerModule);
+
+    AnimationPropertyUpdater mockPropertyUpdater = mock(AnimationPropertyUpdater.class);
+    Animation mockAnimation = spy(new AnimationStub(1000, mockPropertyUpdater));
+    Callback callbackMock = mock(Callback.class);
+
+    int rootTag = hierarchy.rootView;
+    uiManagerModule.createView(
+        hierarchy.rootView,
+        ReactViewManager.REACT_CLASS,
+        rootTag,
+        SimpleMap.of("collapsable", false));
+
+    uiManagerModule.registerAnimation(mockAnimation);
+    uiManagerModule.addAnimation(hierarchy.rootView, 1000, callbackMock);
+    uiManagerModule.removeAnimation(hierarchy.rootView, 1000);
+
+    uiManagerModule.onBatchComplete();
+    executePendingChoreographerCallbacks();
+
+    verify(callbackMock, times(1)).invoke(false);
+    verify(mockAnimation).run();
+    verify(mockAnimation).cancel();
+  }
+
+  /**
+   * Makes sure replaceExistingNonRootView by replacing a view with a new view that has a background
+   * color set.
+   */
+  @Test
+  public void testReplaceExistingNonRootView() {
+    UIManagerModule uiManager = getUIManagerModule();
+    TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager);
+
+    int newViewTag = 1234;
+    uiManager.createView(
+        newViewTag,
+        ReactViewManager.REACT_CLASS,
+        hierarchy.rootView,
+        SimpleMap.of("backgroundColor", Color.RED));
+
+    uiManager.replaceExistingNonRootView(hierarchy.view2, newViewTag);
+
+    uiManager.onBatchComplete();
+    executePendingChoreographerCallbacks();
+
+    assertThat(hierarchy.nativeRootView.getChildCount()).isEqualTo(4);
+    assertThat(hierarchy.nativeRootView.getChildAt(2)).isInstanceOf(ReactViewGroup.class);
+    ReactViewGroup view = (ReactViewGroup) hierarchy.nativeRootView.getChildAt(2);
+    assertThat(view.getBackgroundColor()).isEqualTo(Color.RED);
+  }
+
+  /**
+   * Verifies removeSubviewsFromContainerWithID works by adding subviews, removing them, and
+   * checking that the final number of children is correct.
+   */
+  @Test
+  public void testRemoveSubviewsFromContainerWithID() {
+    UIManagerModule uiManager = getUIManagerModule();
+    ReactRootView rootView =
+        new ReactRootView(RuntimeEnvironment.application.getApplicationContext());
+    int rootTag = uiManager.addMeasuredRootView(rootView);
+
+    final int containerTag = rootTag + 1;
+    final int containerSiblingTag = containerTag + 1;
+
+    uiManager.createView(
+        containerTag,
+        ReactViewManager.REACT_CLASS,
+        rootTag,
+        SimpleMap.of("collapsable", false));
+    uiManager.createView(
+        containerSiblingTag,
+        ReactViewManager.REACT_CLASS,
+        rootTag,
+        SimpleMap.of("collapsable", false));
+    addChild(uiManager, rootTag, containerTag, 0);
+    addChild(uiManager, rootTag, containerSiblingTag, 1);
+
+    uiManager.createView(
+        containerTag + 2,
+        ReactTextViewManager.REACT_CLASS,
+        rootTag,
+        SimpleMap.of("collapsable", false));
+    uiManager.createView(
+        containerTag + 3,
+        ReactTextViewManager.REACT_CLASS,
+        rootTag,
+        SimpleMap.of("collapsable", false));
+    addChild(uiManager, containerTag, containerTag + 2, 0);
+    addChild(uiManager, containerTag, containerTag + 3, 1);
+
+    uiManager.onBatchComplete();
+    executePendingChoreographerCallbacks();
+
+    assertThat(rootView.getChildCount()).isEqualTo(2);
+    assertThat(((ViewGroup)rootView.getChildAt(0)).getChildCount()).isEqualTo(2);
+
+    uiManager.removeSubviewsFromContainerWithID(containerTag);
+
+    uiManager.onBatchComplete();
+    executePendingChoreographerCallbacks();
+
+    assertThat(rootView.getChildCount()).isEqualTo(2);
+    assertThat(((ViewGroup)rootView.getChildAt(0)).getChildCount()).isEqualTo(0);
+  }
+
+  /**
+   * Assuming no other views have been created, the root view will have tag 1, Text tag 2, and
+   * RawText tag 3.
+   */
+  private ViewGroup createSimpleTextHierarchy(UIManagerModule uiManager, String text) {
+    ReactRootView rootView =
+        new ReactRootView(RuntimeEnvironment.application.getApplicationContext());
+    int rootTag = uiManager.addMeasuredRootView(rootView);
+    int textTag = rootTag + 1;
+    int rawTextTag = textTag + 1;
+
+    uiManager.createView(
+        textTag,
+        ReactTextViewManager.REACT_CLASS,
+        rootTag,
+        SimpleMap.of("collapsable", false));
+    uiManager.createView(
+        rawTextTag,
+        ReactRawTextManager.REACT_CLASS,
+        rootTag,
+        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, text, "collapsable", false));
+
+    uiManager.manageChildren(
+        textTag,
+        null,
+        null,
+        SimpleArray.of(rawTextTag),
+        SimpleArray.of(0),
+        null);
+
+    uiManager.manageChildren(
+        rootTag,
+        null,
+        null,
+        SimpleArray.of(textTag),
+        SimpleArray.of(0),
+        null);
+
+    uiManager.onBatchComplete();
+    executePendingChoreographerCallbacks();
+
+    return rootView;
+  }
+
+  private TestMoveDeleteHierarchy createMoveDeleteHierarchy(UIManagerModule uiManager) {
+    ReactRootView rootView = new ReactRootView(mReactContext);
+    int rootTag = uiManager.addMeasuredRootView(rootView);
+
+    TestMoveDeleteHierarchy hierarchy = new TestMoveDeleteHierarchy(rootView, rootTag);
+
+    uiManager.createView(
+        hierarchy.view0,
+        ReactViewManager.REACT_CLASS,
+        rootTag,
+        SimpleMap.of("collapsable", false));
+    uiManager.createView(
+        hierarchy.viewWithChildren1,
+        ReactViewManager.REACT_CLASS,
+        rootTag,
+        SimpleMap.of("collapsable", false));
+    uiManager.createView(
+        hierarchy.view2,
+        ReactViewManager.REACT_CLASS,
+        rootTag,
+        SimpleMap.of("collapsable", false));
+    uiManager.createView(
+        hierarchy.view3,
+        ReactViewManager.REACT_CLASS,
+        rootTag,
+        SimpleMap.of("collapsable", false));
+    uiManager.createView(
+        hierarchy.childView0,
+        ReactViewManager.REACT_CLASS,
+        rootTag,
+        SimpleMap.of("collapsable", false));
+    uiManager.createView(
+        hierarchy.childView1,
+        ReactViewManager.REACT_CLASS,
+        rootTag,
+        SimpleMap.of("collapsable", false));
+
+    addChild(uiManager, rootTag, hierarchy.view0, 0);
+    addChild(uiManager, rootTag, hierarchy.viewWithChildren1, 1);
+    addChild(uiManager, rootTag, hierarchy.view2, 2);
+    addChild(uiManager, rootTag, hierarchy.view3, 3);
+
+    addChild(uiManager, hierarchy.viewWithChildren1, hierarchy.childView0, 0);
+    addChild(uiManager, hierarchy.viewWithChildren1, hierarchy.childView1, 1);
+
+    uiManager.onBatchComplete();
+    executePendingChoreographerCallbacks();
+
+    return hierarchy;
+  }
+
+  private void addChild(UIManagerModule uiManager, int parentTag, int childTag, int index) {
+    uiManager.manageChildren(
+        parentTag,
+        null,
+        null,
+        SimpleArray.of(childTag),
+        SimpleArray.of(index),
+        null);
+  }
+
+  private void assertChildrenAreExactly(ViewGroup parent, View... views) {
+    assertThat(parent.getChildCount()).isEqualTo(views.length);
+    for (int i = 0; i < views.length; i++) {
+      assertThat(parent.getChildAt(i))
+          .describedAs("View at " + i)
+          .isEqualTo(views[i]);
+    }
+  }
+
+  /**
+   * Holder for the tags that represent that represent views in the following hierarchy:
+   *  - View rootView
+   *    - View view0
+   *    - View viewWithChildren1
+   *      - View childView0
+   *      - View childView1
+   *    - View view2
+   *    - View view3
+   *
+   * This hierarchy is used to test move/delete functionality in manageChildren.
+   */
+  private static class TestMoveDeleteHierarchy {
+
+    public ReactRootView nativeRootView;
+    public int rootView;
+    public int view0;
+    public int viewWithChildren1;
+    public int view2;
+    public int view3;
+    public int childView0;
+    public int childView1;
+
+    public TestMoveDeleteHierarchy(ReactRootView nativeRootView, int rootViewTag) {
+      this.nativeRootView = nativeRootView;
+      rootView = rootViewTag;
+      view0 = rootView + 1;
+      viewWithChildren1 = rootView + 2;
+      view2 = rootView + 3;
+      view3 = rootView + 4;
+      childView0 = rootView + 5;
+      childView1 = rootView + 6;
+    }
+  }
+
+  private void executePendingChoreographerCallbacks() {
+    ArrayList<Choreographer.FrameCallback> callbacks =
+        new ArrayList<>(mPendingChoreographerCallbacks);
+    mPendingChoreographerCallbacks.clear();
+    for (Choreographer.FrameCallback frameCallback : callbacks) {
+      frameCallback.doFrame(0);
+    }
+  }
+
+  private UIManagerModule getUIManagerModule() {
+    List<ViewManager> viewManagers = Arrays.<ViewManager>asList(
+        new ReactViewManager(),
+        new ReactTextViewManager(),
+        new ReactRawTextManager());
+    UIManagerModule uiManagerModule =  new UIManagerModule(
+        mReactContext,
+        viewManagers,
+        new UIImplementation(mReactContext, viewManagers));
+    uiManagerModule.onHostResume();
+    return uiManagerModule;
+  }
+}
diff --git a/circle.yml b/circle.yml
index eff3e340558a..841ebcb5a674 100644
--- a/circle.yml
+++ b/circle.yml
@@ -17,17 +17,17 @@ dependencies:
   - if [[ ! -e buck ]]; then git clone https://github.com/facebook/buck.git; fi
   - cd buck && ant
   - buck/bin/buck --version
-  - buck/bin/buck fetch ReactAndroid/src/test/java/com/facebook/react/modules
-  - buck/bin/buck fetch ReactAndroid/src/main/java/com/facebook/react
-  - buck/bin/buck fetch ReactAndroid/src/main/java/com/facebook/react/shell
-  - buck/bin/buck fetch ReactAndroid/src/androidTest/java/com/facebook/react/tests
+  - buck/bin/buck fetch ReactAndroid/src/main/...
+  - buck/bin/buck fetch ReactAndroid/src/test/...
+  - buck/bin/buck fetch ReactAndroid/src/androidTest/...
   # using npm@3 because of problems with shrink-wrapped optional deps installs on linux
   - npm install -g npm@3.2
   - source scripts/circle-ci-android-setup.sh && getAndroidSDK
   - ./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog
   cache_directories:
   - "ReactAndroid/build/downloads"
-  - "buck-out"
+  - "buck"
+  - "buck-out/bin"
 test:
   pre:
     # starting emulator in advance because it takes very long to boot
@@ -39,7 +39,7 @@ test:
     - source scripts/circle-ci-android-setup.sh && waitForAVD
   override:
     # buck tests
-    - buck/bin/buck test ReactAndroid/src/test/java/com/facebook/react/modules
+    - buck/bin/buck test ReactAndroid/src/test/...
     - buck/bin/buck build ReactAndroid/src/main/java/com/facebook/react
     - buck/bin/buck build ReactAndroid/src/main/java/com/facebook/react/shell
     # temp, we can't run instrumentation tests yet

From 825ba6cf4821a1bf9c8e395ec882803e70a06a3d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Wed, 27 Jan 2016 07:40:55 -0800
Subject: [PATCH 0895/1411] Inline Require every module but the preloaded ones

Reviewed By: javache

Differential Revision: D2858983

fb-gh-sync-id: b73de54163d7b75891cb00be96ffb4556d3311a3
---
 packager/react-packager/src/Bundler/index.js | 67 ++++++++++++++------
 1 file changed, 47 insertions(+), 20 deletions(-)

diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index fda21ace02fa..b6ff9133343a 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -143,7 +143,9 @@ class Bundler {
     this._assetServer = opts.assetServer;
 
     if (opts.getTransformOptionsModulePath) {
-      this._getTransformOptionsModule = require(opts.getTransformOptionsModulePath);
+      this._transformOptionsModule = require(
+        opts.getTransformOptionsModulePath
+      );
     }
   }
 
@@ -224,6 +226,7 @@ class Bundler {
               response,
               module,
               platform,
+              isDev,
               hot,
             ).then(transformed => {
               if (bar) {
@@ -289,7 +292,8 @@ class Bundler {
             bundle,
             response,
             module,
-            platform
+            platform,
+            isDev,
           ).then(transformed => {
             if (bar) {
               bar.tick();
@@ -326,15 +330,22 @@ class Bundler {
         }
       );
     } else {
-      return this._transformer.loadFileAndTransform(
-        module.path,
-        // TODO(martinb): pass non null main (t9527509)
-        this._getTransformOptions({main: null}, {hot: true}),
-      );
+      // TODO(martinb): pass non null main (t9527509)
+      return this._getTransformOptions(
+        {main: null, dev: true, platform: 'ios'}, // TODO(martinb): avoid hard-coding platform
+        {hot: true},
+      ).then(options => {
+        return this._transformer.loadFileAndTransform(module.path, options);
+      });
     }
   }
 
   invalidateFile(filePath) {
+    if (this._transformOptionsModule) {
+      this._transformOptionsModule.onFileChange &&
+        this._transformOptionsModule.onFileChange();
+    }
+
     this._transformer.invalidateFile(filePath);
   }
 
@@ -386,7 +397,7 @@ class Bundler {
     );
   }
 
-  _transformModule(bundle, response, module, platform = null, hot = false) {
+  _transformModule(bundle, response, module, platform = null, dev = true, hot = false) {
     if (module.isAsset_DEPRECATED()) {
       return this._generateAssetModule_DEPRECATED(bundle, module);
     } else if (module.isAsset()) {
@@ -394,13 +405,20 @@ class Bundler {
     } else if (module.isJSON()) {
       return generateJSONModule(module);
     } else {
-      return this._transformer.loadFileAndTransform(
-        path.resolve(module.path),
-        this._getTransformOptions(
-          {bundleEntry: bundle.getMainModuleName(), modulePath: module.path},
-          {hot: hot},
-        ),
-      );
+      return this._getTransformOptions(
+        {
+          bundleEntry: bundle.getMainModuleName(),
+          platform: platform,
+          dev: dev,
+          modulePath: module.path,
+        },
+        {hot: hot},
+      ).then(options => {
+        return this._transformer.loadFileAndTransform(
+          path.resolve(module.path),
+          options,
+        );
+      });
     }
   }
 
@@ -484,11 +502,20 @@ class Bundler {
   }
 
   _getTransformOptions(config, options) {
-    const transformerOptions = this._getTransformOptionsModule
-      ? this._getTransformOptionsModule(config)
-      : null;
-
-    return {...options, ...transformerOptions};
+    const transformerOptions = this._transformOptionsModule
+      ? this._transformOptionsModule.get(Object.assign(
+          {
+            bundler: this,
+            platform: options.platform,
+            dev: options.dev,
+          },
+          config,
+        ))
+      : Promise.resolve(null);
+
+    return transformerOptions.then(overrides => {
+      return {...options, ...overrides};
+    });
   }
 }
 

From 21a4c6e853b0e2391f6862f565985051988bb103 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Wed, 27 Jan 2016 08:51:54 -0800
Subject: [PATCH 0896/1411] quick fix circle buck builds

Summary: Closes https://github.com/facebook/react-native/pull/5582

Reviewed By: svcscm

Differential Revision: D2869861

Pulled By: androidtrunkagent

fb-gh-sync-id: 5b004521e11d0e55c237183e69f8251732c6bd14
---
 circle.yml | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/circle.yml b/circle.yml
index 841ebcb5a674..ee9901bbf112 100644
--- a/circle.yml
+++ b/circle.yml
@@ -17,7 +17,9 @@ dependencies:
   - if [[ ! -e buck ]]; then git clone https://github.com/facebook/buck.git; fi
   - cd buck && ant
   - buck/bin/buck --version
-  - buck/bin/buck fetch ReactAndroid/src/main/...
+  - buck/bin/buck fetch ReactAndroid/src/test/java/com/facebook/react/modules
+  - buck/bin/buck fetch ReactAndroid/src/main/java/com/facebook/react		 
+  - buck/bin/buck fetch ReactAndroid/src/main/java/com/facebook/react/shell
   - buck/bin/buck fetch ReactAndroid/src/test/...
   - buck/bin/buck fetch ReactAndroid/src/androidTest/...
   # using npm@3 because of problems with shrink-wrapped optional deps installs on linux

From f685878938b59f858dc65b8e5e873045a25ccf79 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Wed, 27 Jan 2016 09:04:14 -0800
Subject: [PATCH 0897/1411] Improved 3D touch implementation, and added example

Summary:
public
This diff improves the implementation of 3D touch by adding a `forceTouchAvailable` constant to View that can be used to check if the feature is supported.

I've also added an example of how you can use the `force` property of the touch event to measure touch pressure in React Native.

Reviewed By: vjeux

Differential Revision: D2864926

fb-gh-sync-id: 754c54989212ce4e4863716ceaba59673f0bb29d
---
 Examples/UIExplorer/TouchableExample.js     | 104 +++++++++++++++-----
 Libraries/Components/Touchable/Touchable.js |  10 +-
 Libraries/Components/View/View.js           |  54 ++++++----
 React/Base/RCTTouchHandler.m                |  13 ++-
 React/Base/RCTUtils.h                       |   3 +
 React/Base/RCTUtils.m                       |  15 ++-
 React/Views/RCTViewManager.m                |   5 +
 7 files changed, 144 insertions(+), 60 deletions(-)

diff --git a/Examples/UIExplorer/TouchableExample.js b/Examples/UIExplorer/TouchableExample.js
index 7b0bf2c0b333..dd3b2c9c89f7 100644
--- a/Examples/UIExplorer/TouchableExample.js
+++ b/Examples/UIExplorer/TouchableExample.js
@@ -23,6 +23,7 @@ var {
   Text,
   TouchableHighlight,
   TouchableOpacity,
+  UIManager,
   View,
 } = React;
 
@@ -85,6 +86,13 @@ exports.examples = [
   render: function(): ReactElement {
     return <TouchableDelayEvents />;
   },
+}, {
+  title: '3D Touch / Force Touch',
+  description: 'iPhone 6s and 6s plus support 3D touch, which adds a force property to touches',
+  render: function(): ReactElement {
+    return <ForceTouchExample />;
+  },
+  platform: 'ios',
 }];
 
 var TextOnPressBox = React.createClass({
@@ -133,18 +141,18 @@ var TouchableFeedbackEvents = React.createClass({
     return (
       <View testID="touchable_feedback_events">
         <View style={[styles.row, {justifyContent: 'center'}]}>
-        <TouchableOpacity
-          style={styles.wrapper}
-          testID="touchable_feedback_events_button"
-          onPress={() => this._appendEvent('press')}
-          onPressIn={() => this._appendEvent('pressIn')}
-          onPressOut={() => this._appendEvent('pressOut')}
-          onLongPress={() => this._appendEvent('longPress')}>
-          <Text style={styles.button}>
-            Press Me
-          </Text>
-        </TouchableOpacity>
-      </View>
+          <TouchableOpacity
+            style={styles.wrapper}
+            testID="touchable_feedback_events_button"
+            onPress={() => this._appendEvent('press')}
+            onPressIn={() => this._appendEvent('pressIn')}
+            onPressOut={() => this._appendEvent('pressOut')}
+            onLongPress={() => this._appendEvent('longPress')}>
+            <Text style={styles.button}>
+              Press Me
+            </Text>
+          </TouchableOpacity>
+        </View>
         <View testID="touchable_feedback_events_console" style={styles.eventLogBox}>
           {this.state.eventLog.map((e, ii) => <Text key={ii}>{e}</Text>)}
         </View>
@@ -169,21 +177,21 @@ var TouchableDelayEvents = React.createClass({
     return (
       <View testID="touchable_delay_events">
         <View style={[styles.row, {justifyContent: 'center'}]}>
-        <TouchableOpacity
-          style={styles.wrapper}
-          testID="touchable_delay_events_button"
-          onPress={() => this._appendEvent('press')}
-          delayPressIn={400}
-          onPressIn={() => this._appendEvent('pressIn - 400ms delay')}
-          delayPressOut={1000}
-          onPressOut={() => this._appendEvent('pressOut - 1000ms delay')}
-          delayLongPress={800}
-          onLongPress={() => this._appendEvent('longPress - 800ms delay')}>
-          <Text style={styles.button}>
-            Press Me
-          </Text>
-        </TouchableOpacity>
-      </View>
+          <TouchableOpacity
+            style={styles.wrapper}
+            testID="touchable_delay_events_button"
+            onPress={() => this._appendEvent('press')}
+            delayPressIn={400}
+            onPressIn={() => this._appendEvent('pressIn - 400ms delay')}
+            delayPressOut={1000}
+            onPressOut={() => this._appendEvent('pressOut - 1000ms delay')}
+            delayLongPress={800}
+            onLongPress={() => this._appendEvent('longPress - 800ms delay')}>
+            <Text style={styles.button}>
+              Press Me
+            </Text>
+          </TouchableOpacity>
+        </View>
         <View style={styles.eventLogBox} testID="touchable_delay_events_console">
           {this.state.eventLog.map((e, ii) => <Text key={ii}>{e}</Text>)}
         </View>
@@ -198,6 +206,40 @@ var TouchableDelayEvents = React.createClass({
   },
 });
 
+var ForceTouchExample = React.createClass({
+  getInitialState: function() {
+    return {
+      force: 0,
+    };
+  },
+  _renderConsoleText: function() {
+    return View.forceTouchAvailable ?
+      'Force: ' + this.state.force.toFixed(3) :
+      '3D Touch is not available on this device';
+  },
+  render: function() {
+    return (
+      <View testID="touchable_3dtouch_event">
+        <View style={styles.forceTouchBox} testID="touchable_3dtouch_output">
+          <Text>{this._renderConsoleText()}</Text>
+        </View>
+        <View style={[styles.row, {justifyContent: 'center'}]}>
+          <View
+            style={styles.wrapper}
+            testID="touchable_3dtouch_button"
+            onStartShouldSetResponder={() => true}
+            onResponderMove={(event) => this.setState({force: event.nativeEvent.force})}
+            onResponderRelease={(event) => this.setState({force: 0})}>
+            <Text style={styles.button}>
+              Press Me
+            </Text>
+          </View>
+        </View>
+      </View>
+    );
+  },
+});
+
 var heartImage = {uri: 'https://pbs.twimg.com/media/BlXBfT3CQAA6cVZ.png:small'};
 
 var styles = StyleSheet.create({
@@ -241,6 +283,14 @@ var styles = StyleSheet.create({
     borderColor: '#f0f0f0',
     backgroundColor: '#f9f9f9',
   },
+  forceTouchBox: {
+    padding: 10,
+    margin: 10,
+    borderWidth: StyleSheet.hairlineWidth,
+    borderColor: '#f0f0f0',
+    backgroundColor: '#f9f9f9',
+    alignItems: 'center',
+  },
   textBlock: {
     fontWeight: '500',
     color: 'blue',
diff --git a/Libraries/Components/Touchable/Touchable.js b/Libraries/Components/Touchable/Touchable.js
index e0ea8850b234..9f457c5c043a 100644
--- a/Libraries/Components/Touchable/Touchable.js
+++ b/Libraries/Components/Touchable/Touchable.js
@@ -49,24 +49,24 @@ var queryLayoutByID = require('queryLayoutByID');
  *
  * - Choose the rendered component who's touches should start the interactive
  *   sequence. On that rendered node, forward all `Touchable` responder
- *   handlers. You can choose any rendered node you like. Choose a node who's
+ *   handlers. You can choose any rendered node you like. Choose a node whose
  *   hit target you'd like to instigate the interaction sequence:
  *
  *   // In render function:
  *   return (
- *     <div
+ *     <View
  *       onStartShouldSetResponder={this.touchableHandleStartShouldSetResponder}
  *       onResponderTerminationRequest={this.touchableHandleResponderTerminationRequest}
  *       onResponderGrant={this.touchableHandleResponderGrant}
  *       onResponderMove={this.touchableHandleResponderMove}
  *       onResponderRelease={this.touchableHandleResponderRelease}
  *       onResponderTerminate={this.touchableHandleResponderTerminate}>
- *       <div>
+ *       <View>
  *         Even though the hit detection/interactions are triggered by the
  *         wrapping (typically larger) node, we usually end up implementing
  *         custom logic that highlights this inner one.
- *       </div>
- *     </div>
+ *       </View>
+ *     </View>
  *   );
  *
  * - You may set up your own handlers for each of these events, so long as you
diff --git a/Libraries/Components/View/View.js b/Libraries/Components/View/View.js
index beaffb75c09a..a7f31f9a0ac8 100644
--- a/Libraries/Components/View/View.js
+++ b/Libraries/Components/View/View.js
@@ -11,20 +11,20 @@
  */
 'use strict';
 
-var NativeMethodsMixin = require('NativeMethodsMixin');
-var PropTypes = require('ReactPropTypes');
-var React = require('React');
-var ReactNativeStyleAttributes = require('ReactNativeStyleAttributes');
-var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
-var StyleSheetPropType = require('StyleSheetPropType');
-var UIManager = require('UIManager');
-var ViewStylePropTypes = require('ViewStylePropTypes');
+const NativeMethodsMixin = require('NativeMethodsMixin');
+const PropTypes = require('ReactPropTypes');
+const React = require('React');
+const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes');
+const ReactNativeViewAttributes = require('ReactNativeViewAttributes');
+const StyleSheetPropType = require('StyleSheetPropType');
+const UIManager = require('UIManager');
+const ViewStylePropTypes = require('ViewStylePropTypes');
 
-var requireNativeComponent = require('requireNativeComponent');
+const requireNativeComponent = require('requireNativeComponent');
 
-var stylePropType = StyleSheetPropType(ViewStylePropTypes);
+const stylePropType = StyleSheetPropType(ViewStylePropTypes);
 
-var AccessibilityTraits = [
+const AccessibilityTraits = [
   'none',
   'button',
   'link',
@@ -44,13 +44,26 @@ var AccessibilityTraits = [
   'pageTurn',
 ];
 
-var AccessibilityComponentType = [
+const AccessibilityComponentType = [
   'none',
   'button',
   'radiobutton_checked',
   'radiobutton_unchecked',
 ];
 
+const forceTouchAvailable = (UIManager.RCTView.Constants &&
+  UIManager.RCTView.Constants.forceTouchAvailable) || false;
+  
+const statics = {
+  AccessibilityTraits,
+  AccessibilityComponentType,
+  /**
+   * Is 3D Touch / Force Touch available (i.e. will touch events include `force`)
+   * @platform ios
+   */
+  forceTouchAvailable,
+};
+
 /**
  * The most fundamental component for building UI, `View` is a
  * container that supports layout with flexbox, style, some touch handling, and
@@ -71,7 +84,7 @@ var AccessibilityComponentType = [
  * `View`s are designed to be used with `StyleSheet`s for clarity and
  * performance, although inline styles are also supported.
  */
-var View = React.createClass({
+const View = React.createClass({
   mixins: [NativeMethodsMixin],
 
   /**
@@ -84,8 +97,7 @@ var View = React.createClass({
   },
 
   statics: {
-    AccessibilityTraits,
-    AccessibilityComponentType,
+    ...statics,
   },
 
   propTypes: {
@@ -320,16 +332,16 @@ var View = React.createClass({
   },
 });
 
-var RCTView = requireNativeComponent('RCTView', View, {
+const RCTView = requireNativeComponent('RCTView', View, {
   nativeOnly: {
     nativeBackgroundAndroid: true,
   }
 });
 
 if (__DEV__) {
-  var viewConfig = UIManager.viewConfigs && UIManager.viewConfigs.RCTView || {};
-  for (var prop in viewConfig.nativeProps) {
-    var viewAny: any = View; // Appease flow
+  const viewConfig = UIManager.viewConfigs && UIManager.viewConfigs.RCTView || {};
+  for (const prop in viewConfig.nativeProps) {
+    const viewAny: any = View; // Appease flow
     if (!viewAny.propTypes[prop] && !ReactNativeStyleAttributes[prop]) {
       throw new Error(
         'View is missing propType for native prop `' + prop + '`'
@@ -338,9 +350,11 @@ if (__DEV__) {
   }
 }
 
-var ViewToExport = RCTView;
+let ViewToExport = RCTView;
 if (__DEV__) {
   ViewToExport = View;
+} else {
+  Object.assign(RCTView, statics);
 }
 
 module.exports = ViewToExport;
diff --git a/React/Base/RCTTouchHandler.m b/React/Base/RCTTouchHandler.m
index c0f6b6f4260a..f3050cfe9068 100644
--- a/React/Base/RCTTouchHandler.m
+++ b/React/Base/RCTTouchHandler.m
@@ -108,11 +108,9 @@ - (void)_recordNewTouches:(NSSet<UITouch *> *)touches
     }
 
     // Create touch
-    NSMutableDictionary *reactTouch = [[NSMutableDictionary alloc] initWithCapacity:11];
+    NSMutableDictionary *reactTouch = [[NSMutableDictionary alloc] initWithCapacity:RCTMaxTouches];
     reactTouch[@"target"] = reactTag;
     reactTouch[@"identifier"] = @(touchID);
-    reactTouch[@"touches"] = (id)kCFNull;        // We hijack this touchObj to serve both as an event
-    reactTouch[@"changedTouches"] = (id)kCFNull; // and as a Touch object, so making this JIT friendly.
 
     // Add to arrays
     [_touchViews addObject:targetView];
@@ -151,10 +149,11 @@ - (void)_updateReactTouchAtIndex:(NSInteger)touchIndex
   reactTouch[@"locationY"] = @(touchViewLocation.y);
   reactTouch[@"timestamp"] =  @(nativeTouch.timestamp * 1000); // in ms, for JS
 
-  if ([nativeTouch.view respondsToSelector:@selector(traitCollection)] &&
-      [nativeTouch.view.traitCollection respondsToSelector:@selector(forceTouchCapability)]) {
-
-    reactTouch[@"force"] = @(RCTZeroIfNaN(nativeTouch.force/nativeTouch.maximumPossibleForce));
+  // TODO: force for a 'normal' touch is usually 1.0;
+  // should we expose a `normalTouchForce` constant somewhere (which would
+  // have a value of `1.0 / nativeTouch.maximumPossibleForce`)?
+  if (RCTForceTouchAvailable()) {
+    reactTouch[@"force"] = @(RCTZeroIfNaN(nativeTouch.force / nativeTouch.maximumPossibleForce));
   }
 }
 
diff --git a/React/Base/RCTUtils.h b/React/Base/RCTUtils.h
index 8f7a4858b737..c751dabbd25b 100644
--- a/React/Base/RCTUtils.h
+++ b/React/Base/RCTUtils.h
@@ -75,6 +75,9 @@ RCT_EXTERN UIApplication *__nullable RCTSharedApplication(void);
 // or view controller, e.g. to present a modal view controller or alert.
 RCT_EXTERN UIWindow *__nullable RCTKeyWindow(void);
 
+// Does this device support force touch (aka 3D Touch)?
+RCT_EXTERN BOOL RCTForceTouchAvailable(void);
+
 // Return a UIAlertView initialized with the given values
 // or nil if running in an app extension
 RCT_EXTERN UIAlertView *__nullable RCTAlertView(NSString *title,
diff --git a/React/Base/RCTUtils.m b/React/Base/RCTUtils.m
index f49e117e202c..68e3a15e520f 100644
--- a/React/Base/RCTUtils.m
+++ b/React/Base/RCTUtils.m
@@ -434,6 +434,19 @@ BOOL RCTRunningInAppExtension(void)
   return RCTSharedApplication().keyWindow;
 }
 
+BOOL RCTForceTouchAvailable(void)
+{
+  static BOOL forceSupported;
+  static dispatch_once_t onceToken;
+  dispatch_once(&onceToken, ^{
+    forceSupported = [UITraitCollection class] &&
+    [UITraitCollection instancesRespondToSelector:@selector(forceTouchCapability)];
+  });
+
+  return forceSupported &&
+    (RCTKeyWindow() ?: [UIView new]).traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable;
+}
+
 UIAlertView *__nullable RCTAlertView(NSString *title,
                                      NSString *__nullable message,
                                      id __nullable delegate,
@@ -475,7 +488,7 @@ id __nullable RCTNilIfNull(id __nullable value)
   return value == (id)kCFNull ? nil : value;
 }
 
-RCT_EXTERN double RCTZeroIfNaN(double value)
+double RCTZeroIfNaN(double value)
 {
   return isnan(value) || isinf(value) ? 0 : value;
 }
diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m
index bbbca7da1061..68980e0bf6d3 100644
--- a/React/Views/RCTViewManager.m
+++ b/React/Views/RCTViewManager.m
@@ -91,6 +91,11 @@ - (RCTShadowView *)shadowView
   return @[];
 }
 
+- (NSDictionary<NSString *, id> *)constantsToExport
+{
+  return @{@"forceTouchAvailable": @(RCTForceTouchAvailable())};
+}
+
 - (RCTViewManagerUIBlock)uiBlockToAmendWithShadowView:(__unused RCTShadowView *)shadowView
 {
   return nil;

From b84f5fb6c9db79f378eed26c19e299d87c4852bf Mon Sep 17 00:00:00 2001
From: Jean Regisser <jean.regisser@gmail.com>
Date: Wed, 27 Jan 2016 10:16:10 -0800
Subject: [PATCH 0898/1411] Added iOS indicatorStyle prop to ScrollView

Summary:
Hi,

The doc wording was adapted from https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIScrollView_Class/#//apple_ref/doc/c_ref/UIScrollViewIndicatorStyle

Note that the iOS doc is misleading, and `UIScrollViewIndicatorStyleDefault` is the same as `UIScrollViewIndicatorStyleBlack` (since iOS 7 I think).

Let me know what you think.
Closes https://github.com/facebook/react-native/pull/5583

Reviewed By: svcscm

Differential Revision: D2870011

Pulled By: nicklockwood

fb-gh-sync-id: d28a96e1a2d4610cbeaee0ae70108ab9d9f05fdb
---
 Libraries/Components/ScrollView/ScrollView.js | 13 +++++++++++++
 React/Views/RCTScrollView.m                   |  1 +
 React/Views/RCTScrollViewManager.m            |  7 +++++++
 3 files changed, 21 insertions(+)

diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js
index 7556e9c71edb..fb8d1452c320 100644
--- a/Libraries/Components/ScrollView/ScrollView.js
+++ b/Libraries/Components/ScrollView/ScrollView.js
@@ -141,6 +141,18 @@ var ScrollView = React.createClass({
      * instead of vertically in a column. The default value is false.
      */
     horizontal: PropTypes.bool,
+    /**
+     * The style of the scroll indicators.
+     *   - `default` (the default), same as `black`.
+     *   - `black`, scroll indicator is black. This style is good against a white content background.
+     *   - `white`, scroll indicator is white. This style is good against a black content background.
+     * @platform ios
+     */
+    indicatorStyle: PropTypes.oneOf([
+      'default', // default
+      'black',
+      'white',
+    ]),
     /**
      * When true, the ScrollView will try to lock to only vertical or horizontal
      * scrolling while dragging.  The default value is false.
@@ -524,6 +536,7 @@ var validAttributes = {
   contentOffset: {diff: pointsDiffer},
   decelerationRate: true,
   horizontal: true,
+  indicatorStyle: true,
   keyboardDismissMode: true,
   keyboardShouldPersistTaps: true,
   maximumZoomScale: true,
diff --git a/React/Views/RCTScrollView.m b/React/Views/RCTScrollView.m
index de9bcb273d53..c69aabb19a2d 100644
--- a/React/Views/RCTScrollView.m
+++ b/React/Views/RCTScrollView.m
@@ -838,6 +838,7 @@ - (void)setter:(type)value                           \
 RCT_SET_AND_PRESERVE_OFFSET(setCanCancelContentTouches, BOOL)
 RCT_SET_AND_PRESERVE_OFFSET(setDecelerationRate, CGFloat)
 RCT_SET_AND_PRESERVE_OFFSET(setDirectionalLockEnabled, BOOL)
+RCT_SET_AND_PRESERVE_OFFSET(setIndicatorStyle, UIScrollViewIndicatorStyle)
 RCT_SET_AND_PRESERVE_OFFSET(setKeyboardDismissMode, UIScrollViewKeyboardDismissMode)
 RCT_SET_AND_PRESERVE_OFFSET(setMaximumZoomScale, CGFloat)
 RCT_SET_AND_PRESERVE_OFFSET(setMinimumZoomScale, CGFloat)
diff --git a/React/Views/RCTScrollViewManager.m b/React/Views/RCTScrollViewManager.m
index 549bc1fac824..2d48c0cb67a0 100644
--- a/React/Views/RCTScrollViewManager.m
+++ b/React/Views/RCTScrollViewManager.m
@@ -29,6 +29,12 @@ @implementation RCTConvert (UIScrollView)
   @"onDrag": @(UIScrollViewKeyboardDismissModeOnDrag),
 }), UIScrollViewKeyboardDismissModeNone, integerValue)
 
+RCT_ENUM_CONVERTER(UIScrollViewIndicatorStyle, (@{
+  @"default": @(UIScrollViewIndicatorStyleDefault),
+  @"black": @(UIScrollViewIndicatorStyleBlack),
+  @"white": @(UIScrollViewIndicatorStyleWhite),
+}), UIScrollViewIndicatorStyleDefault, integerValue)
+
 @end
 
 @implementation RCTScrollViewManager
@@ -49,6 +55,7 @@ - (UIView *)view
 RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets, BOOL)
 RCT_EXPORT_VIEW_PROPERTY(decelerationRate, CGFloat)
 RCT_EXPORT_VIEW_PROPERTY(directionalLockEnabled, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(indicatorStyle, UIScrollViewIndicatorStyle)
 RCT_EXPORT_VIEW_PROPERTY(keyboardDismissMode, UIScrollViewKeyboardDismissMode)
 RCT_EXPORT_VIEW_PROPERTY(maximumZoomScale, CGFloat)
 RCT_EXPORT_VIEW_PROPERTY(minimumZoomScale, CGFloat)

From 1d819e9503e69737733c3a0890ae272597527083 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Wed, 27 Jan 2016 10:49:31 -0800
Subject: [PATCH 0899/1411] Open sourced <ImageEditor>, <ImageStore> for
 Android

Reviewed By: mkonicek

Differential Revision: D2869751

fb-gh-sync-id: 862c266601dd83ca3bf9c9bcbf107f7b17b8bdfd
---
 Examples/UIExplorer/ImageEditingExample.js    |  33 +-
 Examples/UIExplorer/UIExplorerList.android.js |   7 +-
 Examples/UIExplorer/UIExplorerList.ios.js     |   2 +-
 Libraries/Image/ImageStore.js                 |   3 +-
 .../modules/camera/ImageEditingManager.java   | 440 ++++++++++++++++++
 .../modules/camera/ImageStoreManager.java     | 107 +++++
 .../react/shell/MainReactPackage.java         |   4 +
 7 files changed, 575 insertions(+), 21 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageEditingManager.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageStoreManager.java

diff --git a/Examples/UIExplorer/ImageEditingExample.js b/Examples/UIExplorer/ImageEditingExample.js
index 29b2dfd84166..8f4e4e7f657b 100644
--- a/Examples/UIExplorer/ImageEditingExample.js
+++ b/Examples/UIExplorer/ImageEditingExample.js
@@ -67,22 +67,21 @@ class SquareImageCropper extends React.Component {
     this._fetchRandomPhoto();
   }
 
-  _fetchRandomPhoto() {
-    CameraRoll.getPhotos(
-      {first: PAGE_SIZE},
-      (data) => {
-        if (!this._isMounted) {
-          return;
-        }
-        var edges = data.edges;
-        var edge = edges[Math.floor(Math.random() * edges.length)];
-        var randomPhoto = edge && edge.node && edge.node.image;
-        if (randomPhoto) {
-          this.setState({randomPhoto});
-        }
-      },
-      (error) => undefined
-    );
+  async _fetchRandomPhoto() {
+    try {
+      const data = await CameraRoll.getPhotos({first: PAGE_SIZE});
+      if (!this._isMounted) {
+        return;
+      }
+      var edges = data.edges;
+      var edge = edges[Math.floor(Math.random() * edges.length)];
+      var randomPhoto = edge && edge.node && edge.node.image;
+      if (randomPhoto) {
+        this.setState({randomPhoto});
+      }
+    } catch (error) {
+      console.warn("Can't get a photo from camera roll", error);
+    }
   }
 
   componentWillUnmount() {
@@ -209,6 +208,8 @@ class ImageCropper extends React.Component {
         height: this.props.size.height,
       };
     }
+    // a quick hack for android because Android ScrollView does not have zoom feature
+    this._scaledImageSize.width = 2 * this._scaledImageSize.width;
     this._contentOffset = {
       x: (this._scaledImageSize.width - this.props.size.width) / 2,
       y: (this._scaledImageSize.height - this.props.size.height) / 2,
diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index 66caeef51b5f..367b256de49f 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -25,12 +25,12 @@ var UIExplorerListBase = require('./UIExplorerListBase');
 var COMPONENTS = [
   require('./ImageExample'),
   require('./ListViewExample'),
+  require('./PickerAndroidExample'),
   require('./ProgressBarAndroidExample'),
+  require('./PullToRefreshViewAndroidExample.android'),
+  require('./RefreshControlExample'),
   require('./ScrollViewSimpleExample'),
   require('./SwitchExample'),
-  require('./RefreshControlExample'),
-  require('./PickerAndroidExample'),
-  require('./PullToRefreshViewAndroidExample.android'),
   require('./TextExample.android'),
   require('./TextInputExample.android'),
   require('./ToolbarAndroidExample'),
@@ -49,6 +49,7 @@ var APIS = [
   require('./ClipboardExample'),
   require('./DatePickerAndroidExample'),
   require('./GeolocationExample'),
+  require('./ImageEditingExample'),
   require('./IntentAndroidExample.android'),
   require('./LayoutEventsExample'),
   require('./LayoutExample'),
diff --git a/Examples/UIExplorer/UIExplorerList.ios.js b/Examples/UIExplorer/UIExplorerList.ios.js
index f33d97c86134..3fa57d818bfb 100644
--- a/Examples/UIExplorer/UIExplorerList.ios.js
+++ b/Examples/UIExplorer/UIExplorerList.ios.js
@@ -71,6 +71,7 @@ var APIS = [
   require('./CameraRollExample'),
   require('./ClipboardExample'),
   require('./GeolocationExample'),
+  require('./ImageEditingExample'),
   require('./LayoutExample'),
   require('./NetInfoExample'),
   require('./PanResponderExample'),
@@ -82,7 +83,6 @@ var APIS = [
   require('./TransformExample'),
   require('./VibrationIOSExample'),
   require('./XHRExample.ios'),
-  require('./ImageEditingExample'),
 ];
 
 type Props = {
diff --git a/Libraries/Image/ImageStore.js b/Libraries/Image/ImageStore.js
index e4006a73d9b9..f03262d6d08f 100644
--- a/Libraries/Image/ImageStore.js
+++ b/Libraries/Image/ImageStore.js
@@ -51,6 +51,7 @@ class ImageStore {
    * Note that it is very inefficient to transfer large quantities of binary
    * data between JS and native code, so you should avoid calling this more
    * than necessary.
+   * @platform ios
    */
   static addImageFromBase64(
     base64ImageData: string,
@@ -80,4 +81,4 @@ class ImageStore {
   }
 }
 
-module.exports = ImageStore;
\ No newline at end of file
+module.exports = ImageStore;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageEditingManager.java b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageEditingManager.java
new file mode 100644
index 000000000000..cbcfbb596e00
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageEditingManager.java
@@ -0,0 +1,440 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.modules.camera;
+
+import javax.annotation.Nullable;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Matrix;
+import android.net.Uri;
+import android.os.AsyncTask;
+
+import com.facebook.react.bridge.Callback;
+import com.facebook.react.bridge.GuardedAsyncTask;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.infer.annotation.Assertions;
+
+/**
+ * Native module that provides image cropping functionality.
+ */
+public class ImageEditingManager extends ReactContextBaseJavaModule {
+
+  private static final List<String> LOCAL_URI_PREFIXES = Arrays.asList(
+      "file://", "content://");
+
+  private static final String TEMP_FILE_PREFIX = "ReactNative_cropped_image_";
+
+  /** Compress quality of the output file. */
+  private static final int COMPRESS_QUALITY = 90;
+
+  public ImageEditingManager(ReactApplicationContext reactContext) {
+    super(reactContext);
+    new CleanTask(getReactApplicationContext()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+  }
+
+  @Override
+  public String getName() {
+    return "RKImageEditingManager";
+  }
+
+  @Override
+  public Map<String, Object> getConstants() {
+    return Collections.emptyMap();
+  }
+
+  @Override
+  public void onCatalystInstanceDestroy() {
+    new CleanTask(getReactApplicationContext()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+  }
+
+  /**
+   * Asynchronous task that cleans up cache dirs (internal and, if available, external) of cropped
+   * image files. This is run when the catalyst instance is being destroyed (i.e. app is shutting
+   * down) and when the module is instantiated, to handle the case where the app crashed.
+   */
+  private static class CleanTask extends GuardedAsyncTask<Void, Void> {
+    private final Context mContext;
+
+    private CleanTask(ReactContext context) {
+      super(context);
+      mContext = context;
+    }
+
+    @Override
+    protected void doInBackgroundGuarded(Void... params) {
+      cleanDirectory(mContext.getCacheDir());
+      File externalCacheDir = mContext.getExternalCacheDir();
+      if (externalCacheDir != null) {
+        cleanDirectory(externalCacheDir);
+      }
+    }
+
+    private void cleanDirectory(File directory) {
+      File[] toDelete = directory.listFiles(
+          new FilenameFilter() {
+            @Override
+            public boolean accept(File dir, String filename) {
+              return filename.startsWith(TEMP_FILE_PREFIX);
+            }
+          });
+      if (toDelete != null) {
+        for (File file: toDelete) {
+          file.delete();
+        }
+      }
+    }
+  }
+
+  /**
+   * Crop an image. If all goes well, the success callback will be called with the file:// URI of
+   * the new image as the only argument. This is a temporary file - consider using
+   * CameraRollManager.saveImageWithTag to save it in the gallery.
+   *
+   * @param uri the MediaStore URI of the image to crop
+   * @param options crop parameters specified as {@code {offset: {x, y}, size: {width, height}}}.
+   *        Optionally this also contains  {@code {targetSize: {width, height}}}. If this is
+   *        specified, the cropped image will be resized to that size.
+   *        All units are in pixels (not DPs).
+   * @param success callback to be invoked when the image has been cropped; the only argument that
+   *        is passed to this callback is the file:// URI of the new image
+   * @param error callback to be invoked when an error occurs (e.g. can't create file etc.)
+   */
+  @ReactMethod
+  public void cropImage(
+      String uri,
+      ReadableMap options,
+      final Callback success,
+      final Callback error) {
+    ReadableMap offset = options.hasKey("offset") ? options.getMap("offset") : null;
+    ReadableMap size = options.hasKey("size") ? options.getMap("size") : null;
+    if (offset == null || size == null ||
+        !offset.hasKey("x") || !offset.hasKey("y") ||
+        !size.hasKey("width") || !size.hasKey("height")) {
+      throw new JSApplicationIllegalArgumentException("Please specify offset and size");
+    }
+    if (uri == null || uri.isEmpty()) {
+      throw new JSApplicationIllegalArgumentException("Please specify a URI");
+    }
+
+    CropTask cropTask = new CropTask(
+        getReactApplicationContext(),
+        uri,
+        (int) offset.getDouble("x"),
+        (int) offset.getDouble("y"),
+        (int) size.getDouble("width"),
+        (int) size.getDouble("height"),
+        success,
+        error);
+    if (options.hasKey("displaySize")) {
+      ReadableMap targetSize = options.getMap("displaySize");
+      cropTask.setTargetSize(targetSize.getInt("width"), targetSize.getInt("height"));
+    }
+    cropTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+  }
+
+  private static class CropTask extends GuardedAsyncTask<Void, Void> {
+    final Context mContext;
+    final String mUri;
+    final int mX;
+    final int mY;
+    final int mWidth;
+    final int mHeight;
+    int mTargetWidth = 0;
+    int mTargetHeight = 0;
+    final Callback mSuccess;
+    final Callback mError;
+
+    private CropTask(
+        ReactContext context,
+        String uri,
+        int x,
+        int y,
+        int width,
+        int height,
+        Callback success,
+        Callback error) {
+      super(context);
+      if (x < 0 || y < 0 || width <= 0 || height <= 0) {
+        throw new JSApplicationIllegalArgumentException(String.format(
+            "Invalid crop rectangle: [%d, %d, %d, %d]", x, y, width, height));
+      }
+      mContext = context;
+      mUri = uri;
+      mX = x;
+      mY = y;
+      mWidth = width;
+      mHeight = height;
+      mSuccess = success;
+      mError = error;
+    }
+
+    public void setTargetSize(int width, int height) {
+      if (width <= 0 || height <= 0) {
+        throw new JSApplicationIllegalArgumentException(String.format(
+            "Invalid target size: [%d, %d]", width, height));
+      }
+      mTargetWidth = width;
+      mTargetHeight = height;
+    }
+
+    private InputStream openBitmapInputStream() throws IOException {
+      InputStream stream;
+      if (isLocalUri(mUri)) {
+        stream = mContext.getContentResolver().openInputStream(Uri.parse(mUri));
+      } else {
+        URLConnection connection = new URL(mUri).openConnection();
+        stream = connection.getInputStream();
+      }
+      if (stream == null) {
+        throw new IOException("Cannot open bitmap: " + mUri);
+      }
+      return stream;
+    }
+
+    @Override
+    protected void doInBackgroundGuarded(Void... params) {
+      try {
+        BitmapFactory.Options outOptions = new BitmapFactory.Options();
+
+        // If we're downscaling, we can decode the bitmap more efficiently, using less memory
+        boolean hasTargetSize = (mTargetWidth > 0) && (mTargetHeight > 0);
+
+        Bitmap cropped;
+        if (hasTargetSize) {
+          cropped = cropAndResize(mTargetWidth, mTargetHeight, outOptions);
+        } else {
+          cropped = crop(outOptions);
+        }
+
+        String mimeType = outOptions.outMimeType;
+        if (mimeType == null || mimeType.isEmpty()) {
+          throw new IOException("Could not determine MIME type");
+        }
+
+        File tempFile = createTempFile(mContext, mimeType);
+        writeCompressedBitmapToFile(cropped, mimeType, tempFile);
+
+        mSuccess.invoke(Uri.fromFile(tempFile).toString());
+
+      } catch (Exception e) {
+        mError.invoke(e.getMessage());
+      }
+    }
+
+    /**
+     * Reads and crops the bitmap.
+     * @param outOptions Bitmap options, useful to determine {@code outMimeType}.
+     */
+    private Bitmap crop(BitmapFactory.Options outOptions) throws IOException {
+      InputStream inputStream = openBitmapInputStream();
+      try {
+        // This can use a lot of memory
+        Bitmap fullResolutionBitmap = BitmapFactory.decodeStream(inputStream, null, outOptions);
+        if (fullResolutionBitmap == null) {
+          throw new IOException("Cannot decode bitmap: " + mUri);
+        }
+        return Bitmap.createBitmap(fullResolutionBitmap, mX, mY, mWidth, mHeight);
+      } finally {
+        if (inputStream != null) {
+          inputStream.close();
+        }
+      }
+    }
+
+    /**
+     * Crop the rectangle given by {@code mX, mY, mWidth, mHeight} within the source bitmap
+     * and scale the result to {@code targetWidth, targetHeight}.
+     * @param outOptions Bitmap options, useful to determine {@code outMimeType}.
+     */
+    private Bitmap cropAndResize(
+        int targetWidth,
+        int targetHeight,
+        BitmapFactory.Options outOptions)
+        throws IOException {
+      Assertions.assertNotNull(outOptions);
+
+      // Loading large bitmaps efficiently:
+      // http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
+
+      // Just decode the dimensions
+      BitmapFactory.Options options = new BitmapFactory.Options();
+      options.inJustDecodeBounds = true;
+      InputStream inputStream = openBitmapInputStream();
+      try {
+        BitmapFactory.decodeStream(inputStream, null, options);
+      } finally {
+        if (inputStream != null) {
+          inputStream.close();
+        }
+      }
+
+      // This uses scaling mode COVER
+
+      // Where would the crop rect end up within the scaled bitmap?
+      float newWidth, newHeight, newX, newY, scale;
+      float cropRectRatio = mWidth / (float) mHeight;
+      float targetRatio = targetWidth / (float) targetHeight;
+      if (cropRectRatio > targetRatio) {
+        // e.g. source is landscape, target is portrait
+        newWidth = mHeight * targetRatio;
+        newHeight = mHeight;
+        newX = mX + (mWidth - newWidth) / 2;
+        newY = mY;
+        scale = targetHeight / (float) mHeight;
+      } else {
+        // e.g. source is landscape, target is portrait
+        newWidth = mWidth;
+        newHeight = mWidth / targetRatio;
+        newX = mX;
+        newY = mY + (mHeight - newHeight) / 2;
+        scale = targetWidth / (float) mWidth;
+      }
+
+      // Decode the bitmap. We have to open the stream again, like in the example linked above.
+      // Is there a way to just continue reading from the stream?
+      outOptions.inSampleSize = getDecodeSampleSize(mWidth, mHeight, targetWidth, targetHeight);
+      options.inJustDecodeBounds = false;
+      inputStream = openBitmapInputStream();
+
+      Bitmap bitmap;
+      try {
+        // This can use significantly less memory than decoding the full-resolution bitmap
+        bitmap = BitmapFactory.decodeStream(inputStream, null, outOptions);
+        if (bitmap == null) {
+          throw new IOException("Cannot decode bitmap: " + mUri);
+        }
+      } finally {
+        if (inputStream != null) {
+          inputStream.close();
+        }
+      }
+
+      int cropX = (int) Math.floor(newX / (float) outOptions.inSampleSize);
+      int cropY = (int) Math.floor(newY / (float) outOptions.inSampleSize);
+      int cropWidth = (int) Math.floor(newWidth / (float) outOptions.inSampleSize);
+      int cropHeight = (int) Math.floor(newHeight / (float) outOptions.inSampleSize);
+      float cropScale = scale * outOptions.inSampleSize;
+
+      Matrix scaleMatrix = new Matrix();
+      scaleMatrix.setScale(cropScale, cropScale);
+      boolean filter = true;
+
+      return Bitmap.createBitmap(bitmap, cropX, cropY, cropWidth, cropHeight, scaleMatrix, filter);
+    }
+  }
+
+  // Utils
+
+  private static boolean isLocalUri(String uri) {
+    for (String localPrefix : LOCAL_URI_PREFIXES) {
+      if (uri.startsWith(localPrefix)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  private static String getFileExtensionForType(@Nullable String mimeType) {
+    if ("image/png".equals(mimeType)) {
+      return ".png";
+    }
+    if ("image/webp".equals(mimeType)) {
+      return ".webp";
+    }
+    return ".jpg";
+  }
+
+  private static Bitmap.CompressFormat getCompressFormatForType(String type) {
+    if ("image/png".equals(type)) {
+      return Bitmap.CompressFormat.PNG;
+    }
+    if ("image/webp".equals(type)) {
+      return Bitmap.CompressFormat.WEBP;
+    }
+    return Bitmap.CompressFormat.JPEG;
+  }
+
+  private static void writeCompressedBitmapToFile(Bitmap cropped, String mimeType, File tempFile)
+      throws IOException {
+    OutputStream out = new FileOutputStream(tempFile);
+    try {
+      cropped.compress(getCompressFormatForType(mimeType), COMPRESS_QUALITY, out);
+    } finally {
+      if (out != null) {
+        out.close();
+      }
+    }
+  }
+
+  /**
+   * Create a temporary file in the cache directory on either internal or external storage,
+   * whichever is available and has more free space.
+   *
+   * @param mimeType the MIME type of the file to create (image/*)
+   */
+  private static File createTempFile(Context context, @Nullable String mimeType)
+      throws IOException {
+    File externalCacheDir = context.getExternalCacheDir();
+    File internalCacheDir = context.getCacheDir();
+    File cacheDir;
+    if (externalCacheDir == null && externalCacheDir == null) {
+      throw new IOException("No cache directory available");
+    }
+    if (externalCacheDir == null) {
+      cacheDir = internalCacheDir;
+    }
+    else if (internalCacheDir == null) {
+      cacheDir = externalCacheDir;
+    } else {
+      cacheDir = externalCacheDir.getFreeSpace() > internalCacheDir.getFreeSpace() ?
+          externalCacheDir : internalCacheDir;
+    }
+    return File.createTempFile(TEMP_FILE_PREFIX, getFileExtensionForType(mimeType), cacheDir);
+  }
+
+  /**
+   * When scaling down the bitmap, decode only every n-th pixel in each dimension.
+   * Calculate the largest {@code inSampleSize} value that is a power of 2 and keeps both
+   * {@code width, height} larger or equal to {@code targetWidth, targetHeight}.
+   * This can significantly reduce memory usage.
+   */
+  private static int getDecodeSampleSize(int width, int height, int targetWidth, int targetHeight) {
+    int inSampleSize = 1;
+    if (height > targetWidth || width > targetHeight) {
+      int halfHeight = height / 2;
+      int halfWidth = width / 2;
+      while ((halfWidth / inSampleSize) >= targetWidth
+          && (halfHeight / inSampleSize) >= targetHeight) {
+        inSampleSize *= 2;
+      }
+    }
+    return inSampleSize;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageStoreManager.java b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageStoreManager.java
new file mode 100644
index 000000000000..68329f42a105
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageStoreManager.java
@@ -0,0 +1,107 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.modules.camera;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+
+import android.content.ContentResolver;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.util.Base64;
+import android.util.Base64OutputStream;
+
+import com.facebook.react.bridge.Callback;
+import com.facebook.react.bridge.GuardedAsyncTask;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+
+public class ImageStoreManager extends ReactContextBaseJavaModule {
+
+  private static final int BUFFER_SIZE = 8192;
+
+  public ImageStoreManager(ReactApplicationContext reactContext) {
+    super(reactContext);
+  }
+
+  @Override
+  public String getName() {
+    return "ImageStoreManager";
+  }
+
+  /**
+   * Calculate the base64 representation for an image. The "tag" comes from iOS naming.
+   *
+   * @param uri the URI of the image, file:// or content://
+   * @param success callback to be invoked with the base64 string as the only argument
+   * @param error callback to be invoked on error (e.g. file not found, not readable etc.)
+   */
+  @ReactMethod
+  public void getBase64ForTag(String uri, Callback success, Callback error) {
+    new GetBase64Task(getReactApplicationContext(), uri, success, error)
+        .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+  }
+
+  private class GetBase64Task extends GuardedAsyncTask<Void, Void> {
+    private final String mUri;
+    private final Callback mSuccess;
+    private final Callback mError;
+
+    private GetBase64Task(
+        ReactContext reactContext,
+        String uri,
+        Callback success,
+        Callback error) {
+      super(reactContext);
+      mUri = uri;
+      mSuccess = success;
+      mError = error;
+    }
+
+    @Override
+    protected void doInBackgroundGuarded(Void... params) {
+      try {
+        ContentResolver contentResolver = getReactApplicationContext().getContentResolver();
+        Uri uri = Uri.parse(mUri);
+        InputStream is = contentResolver.openInputStream(uri);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        Base64OutputStream b64os = new Base64OutputStream(baos, Base64.DEFAULT);
+        byte[] buffer = new byte[BUFFER_SIZE];
+        int bytesRead;
+        try {
+          while ((bytesRead = is.read(buffer)) > -1) {
+            b64os.write(buffer, 0, bytesRead);
+          }
+          mSuccess.invoke(baos.toString());
+        } catch (IOException e) {
+          mError.invoke(e.getMessage());
+        } finally {
+          closeQuietly(is);
+          closeQuietly(b64os); // this also closes baos
+        }
+      } catch (FileNotFoundException e) {
+        mError.invoke(e.getMessage());
+      }
+    }
+  }
+
+  private static void closeQuietly(Closeable closeable) {
+    try {
+      closeable.close();
+    } catch (IOException e) {
+      // shhh
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
index b817f55ac6e4..9933b41d517c 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
@@ -19,6 +19,8 @@
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.modules.appstate.AppStateModule;
 import com.facebook.react.modules.camera.CameraRollManager;
+import com.facebook.react.modules.camera.ImageEditingManager;
+import com.facebook.react.modules.camera.ImageStoreManager;
 import com.facebook.react.modules.clipboard.ClipboardModule;
 import com.facebook.react.modules.dialog.DialogModule;
 import com.facebook.react.modules.datepicker.DatePickerDialogModule;
@@ -69,6 +71,8 @@ public List<NativeModule> createNativeModules(ReactApplicationContext reactConte
       new DatePickerDialogModule(reactContext),
       new DialogModule(reactContext),
       new FrescoModule(reactContext),
+      new ImageEditingManager(reactContext),
+      new ImageStoreManager(reactContext),
       new IntentModule(reactContext),
       new LocationModule(reactContext),
       new NetworkingModule(reactContext),

From 04d14e5a2eac29fbecaf0d6e3973ff3fe2177a42 Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Wed, 27 Jan 2016 11:31:22 -0800
Subject: [PATCH 0900/1411] Fix colors in RCTDevLoadingView

Reviewed By: martinbigio

Differential Revision: D2862821

fb-gh-sync-id: d763985cc499fc49d7ed1b25341d19b80e1be55d
---
 React/Modules/RCTDevLoadingView.m | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/React/Modules/RCTDevLoadingView.m b/React/Modules/RCTDevLoadingView.m
index e6d20261e9da..b652f7ce937d 100644
--- a/React/Modules/RCTDevLoadingView.m
+++ b/React/Modules/RCTDevLoadingView.m
@@ -79,12 +79,12 @@ - (void)showWithURL:(NSURL *)URL
 
     NSString *source;
     if (URL.fileURL) {
-      _window.backgroundColor = [UIColor greenColor];
-      _label.textColor = [UIColor whiteColor];
-      source = @"pre-bundled file";
-    } else {
       _window.backgroundColor = [UIColor blackColor];
       _label.textColor = [UIColor grayColor];
+      source = @"pre-bundled file";
+    } else {
+      _window.backgroundColor = [UIColor colorWithHue:1./3 saturation:1 brightness:.35 alpha:1];
+      _label.textColor = [UIColor whiteColor];
       source = [NSString stringWithFormat:@"%@:%@", URL.host, URL.port];
     }
 

From b85a52a46181b096faf665d3382aa7a10fc65f76 Mon Sep 17 00:00:00 2001
From: Andreas Drivenes <andreas.drivenes@gmail.com>
Date: Wed, 27 Jan 2016 13:21:42 -0800
Subject: [PATCH 0901/1411] Update Image docs and examples to the new asset
 system

Summary:
After the release of 0.14, static images should be placed in the source code tree and then required as explained in the [Images guide] (https://facebook.github.io/react-native/docs/images.html). This pull request updates the image documentation and examples to the new asset system. UIExplorer tested on iOS and Android.
Closes https://github.com/facebook/react-native/pull/4987

Reviewed By: svcscm

Differential Revision: D2796276

Pulled By: bestander

fb-gh-sync-id: 732ffa2f136391bb8a3e40a54b5b1ff5022c97f2
---
 Examples/UIExplorer/ImageExample.js           |  20 ++++++++---------
 Examples/UIExplorer/MapViewExample.js         |   2 +-
 .../Contents.json                             |  21 ------------------
 .../uie_comment_normal.imageset/Contents.json |  21 ------------------
 .../uie_thumb_normal.imageset/Contents.json   |  21 ------------------
 .../uie_thumb_selected.imageset/Contents.json |  21 ------------------
 .../res/drawable/uie_comment_highlighted.png  | Bin 403 -> 0 bytes
 .../main/res/drawable/uie_comment_normal.png  | Bin 420 -> 0 bytes
 .../main/res/drawable/uie_thumb_normal.png    | Bin 850 -> 0 bytes
 .../main/res/drawable/uie_thumb_selected.png  | Bin 1110 -> 0 bytes
 .../uie_comment_highlighted@2x.png            | Bin
 .../uie_comment_normal@2x.png                 | Bin
 .../uie_thumb_normal@2x.png                   | Bin
 .../uie_thumb_selected@2x.png                 | Bin
 Libraries/Image/Image.android.js              |   6 ++---
 15 files changed, 14 insertions(+), 98 deletions(-)
 delete mode 100644 Examples/UIExplorer/UIExplorer/Images.xcassets/uie_comment_highlighted.imageset/Contents.json
 delete mode 100644 Examples/UIExplorer/UIExplorer/Images.xcassets/uie_comment_normal.imageset/Contents.json
 delete mode 100644 Examples/UIExplorer/UIExplorer/Images.xcassets/uie_thumb_normal.imageset/Contents.json
 delete mode 100644 Examples/UIExplorer/UIExplorer/Images.xcassets/uie_thumb_selected.imageset/Contents.json
 delete mode 100644 Examples/UIExplorer/android/app/src/main/res/drawable/uie_comment_highlighted.png
 delete mode 100644 Examples/UIExplorer/android/app/src/main/res/drawable/uie_comment_normal.png
 delete mode 100644 Examples/UIExplorer/android/app/src/main/res/drawable/uie_thumb_normal.png
 delete mode 100644 Examples/UIExplorer/android/app/src/main/res/drawable/uie_thumb_selected.png
 rename Examples/UIExplorer/{UIExplorer/Images.xcassets/uie_comment_highlighted.imageset => }/uie_comment_highlighted@2x.png (100%)
 rename Examples/UIExplorer/{UIExplorer/Images.xcassets/uie_comment_normal.imageset => }/uie_comment_normal@2x.png (100%)
 rename Examples/UIExplorer/{UIExplorer/Images.xcassets/uie_thumb_normal.imageset => }/uie_thumb_normal@2x.png (100%)
 rename Examples/UIExplorer/{UIExplorer/Images.xcassets/uie_thumb_selected.imageset => }/uie_thumb_selected@2x.png (100%)

diff --git a/Examples/UIExplorer/ImageExample.js b/Examples/UIExplorer/ImageExample.js
index 60fc38dabe2e..eb13b16b012c 100644
--- a/Examples/UIExplorer/ImageExample.js
+++ b/Examples/UIExplorer/ImageExample.js
@@ -148,15 +148,15 @@ exports.examples = [
   },
   {
     title: 'Plain Static Image',
-    description: 'Static assets should be required by prefixing with `image!` ' +
-      'and are located in the app bundle.',
+    description: 'Static assets should be placed in the source code tree, and ' +
+    'required in the same way as JavaScript modules.',
     render: function() {
       return (
         <View style={styles.horizontal}>
-          <Image source={require('image!uie_thumb_normal')} style={styles.icon} />
-          <Image source={require('image!uie_thumb_selected')} style={styles.icon} />
-          <Image source={require('image!uie_comment_normal')} style={styles.icon} />
-          <Image source={require('image!uie_comment_highlighted')} style={styles.icon} />
+          <Image source={require('./uie_thumb_normal.png')} style={styles.icon} />
+          <Image source={require('./uie_thumb_selected.png')} style={styles.icon} />
+          <Image source={require('./uie_comment_normal.png')} style={styles.icon} />
+          <Image source={require('./uie_comment_highlighted.png')} style={styles.icon} />
         </View>
       );
     },
@@ -320,19 +320,19 @@ exports.examples = [
         <View>
           <View style={styles.horizontal}>
             <Image
-              source={require('image!uie_thumb_normal')}
+              source={require('./uie_thumb_normal.png')}
               style={[styles.icon, {borderRadius: 5, tintColor: '#5ac8fa' }]}
             />
             <Image
-              source={require('image!uie_thumb_normal')}
+              source={require('./uie_thumb_normal.png')}
               style={[styles.icon, styles.leftMargin, {borderRadius: 5, tintColor: '#4cd964' }]}
             />
             <Image
-              source={require('image!uie_thumb_normal')}
+              source={require('./uie_thumb_normal.png')}
               style={[styles.icon, styles.leftMargin, {borderRadius: 5, tintColor: '#ff2d55' }]}
             />
             <Image
-              source={require('image!uie_thumb_normal')}
+              source={require('./uie_thumb_normal.png')}
               style={[styles.icon, styles.leftMargin, {borderRadius: 5, tintColor: '#8e8e93' }]}
             />
           </View>
diff --git a/Examples/UIExplorer/MapViewExample.js b/Examples/UIExplorer/MapViewExample.js
index bd1173a83fea..b10620b04a60 100644
--- a/Examples/UIExplorer/MapViewExample.js
+++ b/Examples/UIExplorer/MapViewExample.js
@@ -313,7 +313,7 @@ exports.examples = [
             }}>
             <Image
               style={{width:30, height:30}}
-              source={require('image!uie_thumb_selected')}
+              source={require('./uie_thumb_selected.png')}
             />
           </TouchableOpacity>
         ),
diff --git a/Examples/UIExplorer/UIExplorer/Images.xcassets/uie_comment_highlighted.imageset/Contents.json b/Examples/UIExplorer/UIExplorer/Images.xcassets/uie_comment_highlighted.imageset/Contents.json
deleted file mode 100644
index e1ccff627e54..000000000000
--- a/Examples/UIExplorer/UIExplorer/Images.xcassets/uie_comment_highlighted.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "scale" : "1x"
-    },
-    {
-      "idiom" : "universal",
-      "scale" : "2x",
-      "filename" : "uie_comment_highlighted@2x.png"
-    },
-    {
-      "idiom" : "universal",
-      "scale" : "3x"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  }
-}
\ No newline at end of file
diff --git a/Examples/UIExplorer/UIExplorer/Images.xcassets/uie_comment_normal.imageset/Contents.json b/Examples/UIExplorer/UIExplorer/Images.xcassets/uie_comment_normal.imageset/Contents.json
deleted file mode 100644
index 6f75231d5e6a..000000000000
--- a/Examples/UIExplorer/UIExplorer/Images.xcassets/uie_comment_normal.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "scale" : "1x"
-    },
-    {
-      "idiom" : "universal",
-      "scale" : "2x",
-      "filename" : "uie_comment_normal@2x.png"
-    },
-    {
-      "idiom" : "universal",
-      "scale" : "3x"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  }
-}
\ No newline at end of file
diff --git a/Examples/UIExplorer/UIExplorer/Images.xcassets/uie_thumb_normal.imageset/Contents.json b/Examples/UIExplorer/UIExplorer/Images.xcassets/uie_thumb_normal.imageset/Contents.json
deleted file mode 100644
index 06a7acabf522..000000000000
--- a/Examples/UIExplorer/UIExplorer/Images.xcassets/uie_thumb_normal.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "scale" : "1x"
-    },
-    {
-      "idiom" : "universal",
-      "scale" : "2x",
-      "filename" : "uie_thumb_normal@2x.png"
-    },
-    {
-      "idiom" : "universal",
-      "scale" : "3x"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  }
-}
\ No newline at end of file
diff --git a/Examples/UIExplorer/UIExplorer/Images.xcassets/uie_thumb_selected.imageset/Contents.json b/Examples/UIExplorer/UIExplorer/Images.xcassets/uie_thumb_selected.imageset/Contents.json
deleted file mode 100644
index a00a3dc54d03..000000000000
--- a/Examples/UIExplorer/UIExplorer/Images.xcassets/uie_thumb_selected.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "scale" : "1x"
-    },
-    {
-      "idiom" : "universal",
-      "scale" : "2x",
-      "filename" : "uie_thumb_selected@2x.png"
-    },
-    {
-      "idiom" : "universal",
-      "scale" : "3x"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  }
-}
\ No newline at end of file
diff --git a/Examples/UIExplorer/android/app/src/main/res/drawable/uie_comment_highlighted.png b/Examples/UIExplorer/android/app/src/main/res/drawable/uie_comment_highlighted.png
deleted file mode 100644
index b33726757ed46498e7da512385e6708961b815e6..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/Examples/UIExplorer/android/app/src/main/res/drawable/uie_comment_normal.png b/Examples/UIExplorer/android/app/src/main/res/drawable/uie_comment_normal.png
deleted file mode 100644
index 6491689fbbc88bfd4289d4ffee2e4262097ddaae..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/Examples/UIExplorer/android/app/src/main/res/drawable/uie_thumb_normal.png b/Examples/UIExplorer/android/app/src/main/res/drawable/uie_thumb_normal.png
deleted file mode 100644
index 72683dfac123c8724b2fa6b5705524ad64b58247..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/Examples/UIExplorer/android/app/src/main/res/drawable/uie_thumb_selected.png b/Examples/UIExplorer/android/app/src/main/res/drawable/uie_thumb_selected.png
deleted file mode 100644
index 79eb69cf92b3638954dd11b045006803abe6d904..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/Examples/UIExplorer/UIExplorer/Images.xcassets/uie_comment_highlighted.imageset/uie_comment_highlighted@2x.png b/Examples/UIExplorer/uie_comment_highlighted@2x.png
similarity index 100%
rename from Examples/UIExplorer/UIExplorer/Images.xcassets/uie_comment_highlighted.imageset/uie_comment_highlighted@2x.png
rename to Examples/UIExplorer/uie_comment_highlighted@2x.png
diff --git a/Examples/UIExplorer/UIExplorer/Images.xcassets/uie_comment_normal.imageset/uie_comment_normal@2x.png b/Examples/UIExplorer/uie_comment_normal@2x.png
similarity index 100%
rename from Examples/UIExplorer/UIExplorer/Images.xcassets/uie_comment_normal.imageset/uie_comment_normal@2x.png
rename to Examples/UIExplorer/uie_comment_normal@2x.png
diff --git a/Examples/UIExplorer/UIExplorer/Images.xcassets/uie_thumb_normal.imageset/uie_thumb_normal@2x.png b/Examples/UIExplorer/uie_thumb_normal@2x.png
similarity index 100%
rename from Examples/UIExplorer/UIExplorer/Images.xcassets/uie_thumb_normal.imageset/uie_thumb_normal@2x.png
rename to Examples/UIExplorer/uie_thumb_normal@2x.png
diff --git a/Examples/UIExplorer/UIExplorer/Images.xcassets/uie_thumb_selected.imageset/uie_thumb_selected@2x.png b/Examples/UIExplorer/uie_thumb_selected@2x.png
similarity index 100%
rename from Examples/UIExplorer/UIExplorer/Images.xcassets/uie_thumb_selected.imageset/uie_thumb_selected@2x.png
rename to Examples/UIExplorer/uie_thumb_selected@2x.png
diff --git a/Libraries/Image/Image.android.js b/Libraries/Image/Image.android.js
index 3cf5ae1f66eb..4c920dcf2aa5 100644
--- a/Libraries/Image/Image.android.js
+++ b/Libraries/Image/Image.android.js
@@ -38,7 +38,7 @@ var resolveAssetSource = require('resolveAssetSource');
  *       <View>
  *         <Image
  *           style={styles.icon}
- *           source={require('image!myIcon')}
+ *           source={require('./myIcon.png')}
  *         />
  *         <Image
  *           style={styles.logo}
@@ -66,8 +66,8 @@ var Image = React.createClass({
     style: StyleSheetPropType(ImageStylePropTypes), 
    /**
      * `uri` is a string representing the resource identifier for the image, which
-     * could be an http address, a local file path, or the name of a static image
-     * resource (which should be wrapped in the `require('image!name')` function).
+     * could be an http address, a local file path, or a static image
+     * resource (which should be wrapped in the `require('./path/to/image.png')` function).
      */
     source: PropTypes.oneOfType([
       PropTypes.shape({

From f2438b440d410ca1aa3ca7d0544d6e000e29e774 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Wed, 27 Jan 2016 14:55:02 -0800
Subject: [PATCH 0902/1411] Hot Loading Sourcemaps

Summary:
public

To make sourcemaps work on Hot Loading work, we'll need to be able to serve them for each module that is dynamically replaced. To do so we introduced a new parameter to the bundler, namely `entryModuleOnly` to decide whether or not to process the full dependency tree or just the module associated to the entry file. Also we need to add `//sourceMappingURL` to the HMR updates so that in case of an error the runtime retrieves the sourcemaps for the file on which an error occurred from the server.

Finally, we need to refactor a bit how we load the HMR updates into JSC. Unfortunately, if the code is eval'ed when an error is thrown, the line and column number are missing. This is a bug/missing feature in JSC. To walkaround the issue we need to eval the code on native. This adds a bit of complexity to HMR as for both platforms we'll have to have a thin module to inject code but I don't see any other alternative. when debugging this is not needed as Chrome supports sourceMappingURLs on eval'ed code

Reviewed By: javache

Differential Revision: D2841788

fb-gh-sync-id: ad9370d26894527a151cea722463e694c670227e
---
 .../Initialization/ExceptionsManager.js       | 42 +++++-----
 .../Initialization/SourceMapsCache.js         | 44 ++++++++++
 .../Initialization/SourceMapsUtils.js         | 76 +++++++++++++++++
 .../Initialization/loadSourceMap.js           | 66 ---------------
 .../Initialization/parseErrorStack.js         | 21 ++++-
 .../Initialization/source-map-url.js          |  2 +-
 Libraries/Utilities/HMRClient.js              | 28 ++++++-
 React/Executors/RCTJSCExecutor.m              | 18 ++++
 React/Modules/RCTRedBox.m                     |  2 +-
 local-cli/server/util/attachHMRServer.js      | 19 +++--
 packager/react-packager/src/Bundler/Bundle.js | 10 ++-
 .../react-packager/src/Bundler/BundleBase.js  |  4 +
 .../react-packager/src/Bundler/HMRBundle.js   | 31 +++++--
 .../src/Bundler/__tests__/Bundle-test.js      |  4 +-
 packager/react-packager/src/Bundler/index.js  | 83 ++++++++++++++++---
 .../src/Server/__tests__/Server-test.js       |  4 +
 packager/react-packager/src/Server/index.js   |  9 ++
 17 files changed, 333 insertions(+), 130 deletions(-)
 create mode 100644 Libraries/JavaScriptAppEngine/Initialization/SourceMapsCache.js
 create mode 100644 Libraries/JavaScriptAppEngine/Initialization/SourceMapsUtils.js
 delete mode 100644 Libraries/JavaScriptAppEngine/Initialization/loadSourceMap.js

diff --git a/Libraries/JavaScriptAppEngine/Initialization/ExceptionsManager.js b/Libraries/JavaScriptAppEngine/Initialization/ExceptionsManager.js
index f7537669fde9..a75b166e29d8 100644
--- a/Libraries/JavaScriptAppEngine/Initialization/ExceptionsManager.js
+++ b/Libraries/JavaScriptAppEngine/Initialization/ExceptionsManager.js
@@ -11,37 +11,37 @@
  */
 'use strict';
 
-var sourceMapPromise;
-
-var exceptionID = 0;
+let exceptionID = 0;
 
 /**
  * Handles the developer-visible aspect of errors and exceptions
  */
 function reportException(e: Error, isFatal: bool) {
-  var loadSourceMap = require('loadSourceMap');
-  var parseErrorStack = require('parseErrorStack');
-  var RCTExceptionsManager = require('NativeModules').ExceptionsManager;
+  const parseErrorStack = require('parseErrorStack');
+  const RCTExceptionsManager = require('NativeModules').ExceptionsManager;
 
-  var currentExceptionID = ++exceptionID;
+  const currentExceptionID = ++exceptionID;
   if (RCTExceptionsManager) {
-    var stack = parseErrorStack(e);
+    const stack = parseErrorStack(e);
     if (isFatal) {
       RCTExceptionsManager.reportFatalException(e.message, stack, currentExceptionID);
     } else {
       RCTExceptionsManager.reportSoftException(e.message, stack, currentExceptionID);
     }
     if (__DEV__) {
-      (sourceMapPromise = sourceMapPromise || loadSourceMap())
-        .then(map => {
-          var prettyStack = parseErrorStack(e, map);
-          RCTExceptionsManager.updateExceptionMessage(e.message, prettyStack, currentExceptionID);
-        })
-        .catch(error => {
-          // This can happen in a variety of normal situations, such as
-          // Network module not being available, or when running locally
-          console.warn('Unable to load source map: ' + error.message);
-        });
+      require('SourceMapsCache').getSourceMaps().then(sourceMaps => {
+        const prettyStack = parseErrorStack(e, sourceMaps);
+        RCTExceptionsManager.updateExceptionMessage(
+          e.message,
+          prettyStack,
+          currentExceptionID,
+        );
+      })
+      .catch(error => {
+        // This can happen in a variety of normal situations, such as
+        // Network module not being available, or when running locally
+        console.warn('Unable to load source map: ' + error.message);
+      });
     }
   }
 }
@@ -81,15 +81,15 @@ function installConsoleErrorReporter() {
     if (arguments[0] && arguments[0].stack) {
       reportException(arguments[0], /* isFatal */ false);
     } else {
-      var stringifySafe = require('stringifySafe');
-      var str = Array.prototype.map.call(arguments, stringifySafe).join(', ');
+      const stringifySafe = require('stringifySafe');
+      const str = Array.prototype.map.call(arguments, stringifySafe).join(', ');
       if (str.slice(0, 10) === '"Warning: ') {
         // React warnings use console.error so that a stack trace is shown, but
         // we don't (currently) want these to show a redbox
         // (Note: Logic duplicated in polyfills/console.js.)
         return;
       }
-      var error : any = new Error('console.error: ' + str);
+      const error : any = new Error('console.error: ' + str);
       error.framesToPop = 1;
       reportException(error, /* isFatal */ false);
     }
diff --git a/Libraries/JavaScriptAppEngine/Initialization/SourceMapsCache.js b/Libraries/JavaScriptAppEngine/Initialization/SourceMapsCache.js
new file mode 100644
index 000000000000..63ab9c642c11
--- /dev/null
+++ b/Libraries/JavaScriptAppEngine/Initialization/SourceMapsCache.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 SourceMapsCache
+ */
+'use strict';
+
+const getObjectValues = require('getObjectValues');
+const SourceMapsUtils = require('SourceMapsUtils');
+
+const sourceMapsCache = {};
+
+const SourceMapsCache = {
+  mainSourceMapID: 'main',
+
+  fetch({text, url, fullSourceMappingURL}) {
+    const sourceMappingURL = fullSourceMappingURL
+      ? fullSourceMappingURL
+      : SourceMapsUtils.extractSourceMapURL({text, url});
+
+    sourceMapsCache[sourceMappingURL] = SourceMapsUtils.fetchSourceMap(
+      sourceMappingURL
+    );
+  },
+
+  getSourceMaps() {
+    fetchMainSourceMap();
+    return Promise.all(getObjectValues(sourceMapsCache));
+  },
+};
+
+function fetchMainSourceMap() {
+  if (!sourceMapsCache[SourceMapsCache.mainSourceMapID]) {
+    sourceMapsCache[SourceMapsCache.mainSourceMapID] =
+      SourceMapsUtils.fetchMainSourceMap();
+  }
+}
+
+module.exports = SourceMapsCache;
diff --git a/Libraries/JavaScriptAppEngine/Initialization/SourceMapsUtils.js b/Libraries/JavaScriptAppEngine/Initialization/SourceMapsUtils.js
new file mode 100644
index 000000000000..f49a107c1d2f
--- /dev/null
+++ b/Libraries/JavaScriptAppEngine/Initialization/SourceMapsUtils.js
@@ -0,0 +1,76 @@
+/**
+ * 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 SourceMapsUtils
+ * @flow
+ */
+
+'use strict';
+
+var HMRClient = require('../../Utilities/HMRClient');
+var Promise = require('Promise');
+var NativeModules = require('NativeModules');
+var SourceMapConsumer = require('SourceMap').SourceMapConsumer;
+var SourceMapURL = require('./source-map-url');
+
+var RCTSourceCode = NativeModules.SourceCode;
+var RCTNetworking = NativeModules.Networking;
+
+var SourceMapsUtils = {
+  fetchMainSourceMap(): Promise {
+    return SourceMapsUtils._getMainSourceMapURL().then(url =>
+      SourceMapsUtils.fetchSourceMap(url)
+    );
+  },
+
+  fetchSourceMap(sourceMappingURL: string): Promise {
+    return fetch(sourceMappingURL)
+      .then(response => response.text())
+      .then(map => new SourceMapConsumer(map));
+  },
+
+  extractSourceMapURL(data: ({url:string, text:string})): ?string {
+    const url = data.url;
+    const text = data.text;
+    var mapURL = SourceMapURL.getFrom(text);
+    if (!mapURL) {
+      return null;
+    }
+    var baseURLs = url.match(/(.+:\/\/.*?)\//);
+    if (!baseURLs || baseURLs.length < 2) {
+      return null;
+    }
+    return baseURLs[1] + mapURL;
+  },
+
+  _getMainSourceMapURL(): Promise {
+    if (global.RAW_SOURCE_MAP) {
+      return Promise.resolve(global.RAW_SOURCE_MAP);
+    }
+
+    if (!RCTSourceCode) {
+      return Promise.reject(new Error('RCTSourceCode module is not available'));
+    }
+
+    if (!RCTNetworking) {
+      // Used internally by fetch
+      return Promise.reject(new Error('RCTNetworking module is not available'));
+    }
+
+    return RCTSourceCode.getScriptText()
+      .then(SourceMapsUtils.extractSourceMapURL)
+      .then((url) => {
+        if (url === null) {
+          return Promise.reject(new Error('No source map URL found. May be running from bundled file.'));
+        }
+        return Promise.resolve(url);
+      });
+  },
+};
+
+module.exports = SourceMapsUtils;
diff --git a/Libraries/JavaScriptAppEngine/Initialization/loadSourceMap.js b/Libraries/JavaScriptAppEngine/Initialization/loadSourceMap.js
deleted file mode 100644
index 852579c6067f..000000000000
--- a/Libraries/JavaScriptAppEngine/Initialization/loadSourceMap.js
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * 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 loadSourceMap
- * @flow
- */
-
-'use strict';
-
-var Promise = require('Promise');
-var NativeModules = require('NativeModules');
-var SourceMapConsumer = require('SourceMap').SourceMapConsumer;
-var SourceMapURL = require('./source-map-url');
-
-var RCTSourceCode = NativeModules.SourceCode;
-var RCTNetworking = NativeModules.Networking;
-
-function loadSourceMap(): Promise {
-  return fetchSourceMap()
-    .then(map => new SourceMapConsumer(map));
-}
-
-function fetchSourceMap(): Promise {
-  if (global.RAW_SOURCE_MAP) {
-    return Promise.resolve(global.RAW_SOURCE_MAP);
-  }
-
-  if (!RCTSourceCode) {
-    return Promise.reject(new Error('RCTSourceCode module is not available'));
-  }
-
-  if (!RCTNetworking) {
-    // Used internally by fetch
-    return Promise.reject(new Error('RCTNetworking module is not available'));
-  }
-
-  return RCTSourceCode.getScriptText()
-    .then(extractSourceMapURL)
-    .then((url) => {
-      if (url === null) {
-        return Promise.reject(new Error('No source map URL found. May be running from bundled file.'));
-      }
-      return Promise.resolve(url);
-    })
-    .then(fetch)
-    .then(response => response.text());
-}
-
-function extractSourceMapURL({url, text, fullSourceMappingURL}): ?string {
-  if (fullSourceMappingURL) {
-    return fullSourceMappingURL;
-  }
-  var mapURL = SourceMapURL.getFrom(text);
-  if (!mapURL) {
-    return null;
-  }
-  var baseURL = url.match(/(.+:\/\/.*?)\//)[1];
-  return baseURL + mapURL;
-}
-
-module.exports = loadSourceMap;
diff --git a/Libraries/JavaScriptAppEngine/Initialization/parseErrorStack.js b/Libraries/JavaScriptAppEngine/Initialization/parseErrorStack.js
index 63076c7b8413..5fec943152b4 100644
--- a/Libraries/JavaScriptAppEngine/Initialization/parseErrorStack.js
+++ b/Libraries/JavaScriptAppEngine/Initialization/parseErrorStack.js
@@ -19,7 +19,11 @@ function resolveSourceMaps(sourceMapInstance, stackFrame) {
       column: stackFrame.column,
     });
     if (orig) {
-      stackFrame.file = orig.source;
+      // remove query string if any
+      const queryStringStartIndex = orig.source.indexOf('?');
+      stackFrame.file = queryStringStartIndex === -1
+        ? orig.source
+        : orig.source.substring(0, queryStringStartIndex);
       stackFrame.lineNumber = orig.line;
       stackFrame.column = orig.column;
     }
@@ -27,7 +31,7 @@ function resolveSourceMaps(sourceMapInstance, stackFrame) {
   }
 }
 
-function parseErrorStack(e, sourceMapInstance) {
+function parseErrorStack(e, sourceMaps) {
   if (!e || !e.stack) {
     return [];
   }
@@ -39,8 +43,17 @@ function parseErrorStack(e, sourceMapInstance) {
     stack.shift();
   }
 
-  if (sourceMapInstance) {
-    stack.forEach(resolveSourceMaps.bind(null, sourceMapInstance));
+  if (sourceMaps) {
+    sourceMaps.forEach((sourceMap, index) => {
+      stack.forEach(frame => {
+        if (frame.file.indexOf(sourceMap.file) !== -1 ||
+            frame.file.replace('.map', '.bundle').indexOf(
+              sourceMap.file
+            ) !== -1) {
+          resolveSourceMaps(sourceMap, frame);
+        }
+      });
+    });
   }
 
   return stack;
diff --git a/Libraries/JavaScriptAppEngine/Initialization/source-map-url.js b/Libraries/JavaScriptAppEngine/Initialization/source-map-url.js
index 8342a5a90ccf..f44740031842 100644
--- a/Libraries/JavaScriptAppEngine/Initialization/source-map-url.js
+++ b/Libraries/JavaScriptAppEngine/Initialization/source-map-url.js
@@ -29,7 +29,7 @@ void (function(root, factory) {
   }
 }(this, function() {
 
-  var innerRegex = /[#@] sourceMappingURL=([^\s'"]*)/
+  var innerRegex = /[#@] source(?:Mapping)?URL=([^\s'"]*)/
 
   var regex = RegExp(
     "(?:" +
diff --git a/Libraries/Utilities/HMRClient.js b/Libraries/Utilities/HMRClient.js
index f500748d5139..79be2be45805 100644
--- a/Libraries/Utilities/HMRClient.js
+++ b/Libraries/Utilities/HMRClient.js
@@ -25,7 +25,7 @@ const HMRClient = {
     const host = 'localhost';
     const port = '8081';
 
-    // need to require WebSocket inside of `enable` function because the
+    // need to require WebSocket inside of `enable` function because
     // this module is defined as a `polyfillGlobal`.
     // See `InitializeJavascriptAppEngine.js`
     const WebSocket = require('WebSocket');
@@ -51,7 +51,31 @@ Error: ${e.message}`
     activeWS.onmessage = ({data}) => {
       data = JSON.parse(data);
       if (data.type === 'update') {
-        eval(data.body); // eslint-disable-line no-eval
+        const modules = data.body.modules;
+        const sourceMappingURLs = data.body.sourceMappingURLs;
+        const sourceURLs = data.body.sourceURLs;
+
+        const RCTRedBox = require('NativeModules').RedBox;
+        RCTRedBox && RCTRedBox.dismiss && RCTRedBox.dismiss();
+
+        modules.forEach((code, i) => {
+          code = code + '\n\n' + sourceMappingURLs[i];
+
+          require('SourceMapsCache').fetch({
+            text: code,
+            url: sourceURLs[i],
+            sourceMappingURL: sourceMappingURLs[i],
+          });
+
+          // on JSC we need to inject from native for sourcemaps to work
+          // (Safari doesn't support `sourceMappingURL` nor any variant when
+          // evaluating code) but on Chrome we can simply use eval
+          const injectFunction = typeof __injectHMRUpdate === 'function'
+            ? __injectHMRUpdate
+            : eval;
+
+          injectFunction(code, sourceURLs[i]);
+        })
         return;
       }
 
diff --git a/React/Executors/RCTJSCExecutor.m b/React/Executors/RCTJSCExecutor.m
index 6e5736a9f9f1..9e4c6201ecbc 100644
--- a/React/Executors/RCTJSCExecutor.m
+++ b/React/Executors/RCTJSCExecutor.m
@@ -23,6 +23,8 @@
 #import "RCTPerformanceLogger.h"
 #import "RCTUtils.h"
 #import "RCTJSCProfiler.h"
+#import "RCTRedBox.h"
+#import "RCTSourceCode.h"
 
 static NSString *const RCTJSCProfilerEnabledDefaultsKey = @"RCTJSCProfilerEnabled";
 
@@ -493,6 +495,22 @@ - (void)executeApplicationScript:(NSData *)script
   RCTAssertParam(sourceURL);
 
   __weak RCTJSCExecutor *weakSelf = self;
+#if RCT_DEV
+  _context.context[@"__injectHMRUpdate"] = ^(NSString *sourceCode, NSString *sourceCodeURL) {
+    RCTJSCExecutor *strongSelf = weakSelf;
+
+    if (!strongSelf) {
+      return;
+    }
+
+    JSStringRef execJSString = JSStringCreateWithUTF8CString(sourceCode.UTF8String);
+    JSStringRef jsURL = JSStringCreateWithUTF8CString(sourceCodeURL.UTF8String);
+    JSEvaluateScript(strongSelf->_context.ctx, execJSString, NULL, jsURL, 0, NULL);
+    JSStringRelease(jsURL);
+    JSStringRelease(execJSString);
+  };
+#endif
+
   [self executeBlockOnJavaScriptQueue:RCTProfileBlock((^{
     RCTJSCExecutor *strongSelf = weakSelf;
     if (!strongSelf || !strongSelf.isValid) {
diff --git a/React/Modules/RCTRedBox.m b/React/Modules/RCTRedBox.m
index b8717b15096e..ec0cfb850533 100644
--- a/React/Modules/RCTRedBox.m
+++ b/React/Modules/RCTRedBox.m
@@ -309,7 +309,7 @@ - (void)showErrorMessage:(NSString *)message withStack:(NSArray<NSDictionary *>
   });
 }
 
-- (void)dismiss
+RCT_EXPORT_METHOD(dismiss)
 {
   dispatch_async(dispatch_get_main_queue(), ^{
     [_window dismiss];
diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js
index 4a118d399ee0..c3ea086ed978 100644
--- a/local-cli/server/util/attachHMRServer.js
+++ b/local-cli/server/util/attachHMRServer.js
@@ -171,17 +171,18 @@ function attachHMRServer({httpServer, path, packagerServer}) {
                 })
               })
               .then(bundle => {
-                if (!client || !bundle) {
+                if (!client || !bundle || bundle.isEmpty()) {
                   return;
                 }
 
-                const hmrUpdate = bundle.getSource();
-                if (hmrUpdate) {
-                  return JSON.stringify({
-                    type: 'update',
-                    body: hmrUpdate,
-                  });
-                }
+                return JSON.stringify({
+                  type: 'update',
+                  body: {
+                    modules: bundle.getModulesCode(),
+                    sourceURLs: bundle.getSourceURLs(),
+                    sourceMappingURLs: bundle.getSourceMappingURLs(),
+                  },
+                });
               })
               .catch(error => {
                 // send errors to the client instead of killing packager server
@@ -207,7 +208,7 @@ function attachHMRServer({httpServer, path, packagerServer}) {
                 return JSON.stringify({type: 'error', body});
               })
               .then(update => {
-                if (!client) {
+                if (!client || !update) {
                   return;
                 }
 
diff --git a/packager/react-packager/src/Bundler/Bundle.js b/packager/react-packager/src/Bundler/Bundle.js
index 2641550a047a..9700af088631 100644
--- a/packager/react-packager/src/Bundler/Bundle.js
+++ b/packager/react-packager/src/Bundler/Bundle.js
@@ -206,7 +206,7 @@ class Bundle extends BundleBase {
   _getCombinedSourceMaps(options) {
     const result = {
       version: 3,
-      file: 'bundle.js',
+      file: this._getSourceMapFile(),
       sections: [],
     };
 
@@ -246,7 +246,7 @@ class Bundle extends BundleBase {
 
     const mappings = this._getMappings();
     const map = {
-      file: 'bundle.js',
+      file: this._getSourceMapFile(),
       sources: _.pluck(super.getModules(), 'sourcePath'),
       version: 3,
       names: [],
@@ -262,6 +262,12 @@ class Bundle extends BundleBase {
     return eTag;
   }
 
+  _getSourceMapFile() {
+    return this._sourceMapUrl
+      ? this._sourceMapUrl.replace('.map', '.bundle')
+      : 'bundle.js';
+  }
+
   _getMappings() {
     const modules = super.getModules();
 
diff --git a/packager/react-packager/src/Bundler/BundleBase.js b/packager/react-packager/src/Bundler/BundleBase.js
index b9e1cbe36c84..79cbfefc37b0 100644
--- a/packager/react-packager/src/Bundler/BundleBase.js
+++ b/packager/react-packager/src/Bundler/BundleBase.js
@@ -19,6 +19,10 @@ class BundleBase {
     this._mainModuleId = this._mainModuleName = undefined;
   }
 
+  isEmpty() {
+    return this._modules.length === 0 && this._assets.length === 0;
+  }
+
   getMainModuleId() {
     return this._mainModuleId;
   }
diff --git a/packager/react-packager/src/Bundler/HMRBundle.js b/packager/react-packager/src/Bundler/HMRBundle.js
index fa8c95db7656..49a21dfd8bc7 100644
--- a/packager/react-packager/src/Bundler/HMRBundle.js
+++ b/packager/react-packager/src/Bundler/HMRBundle.js
@@ -8,12 +8,17 @@
  */
 'use strict';
 
+const _ = require('underscore');
 const BundleBase = require('./BundleBase');
 const ModuleTransport = require('../lib/ModuleTransport');
 
 class HMRBundle extends BundleBase {
-  constructor() {
+  constructor({sourceURLFn, sourceMappingURLFn}) {
     super();
+    this._sourceURLFn = sourceURLFn
+    this._sourceMappingURLFn = sourceMappingURLFn;
+    this._sourceURLs = [];
+    this._sourceMappingURLs = [];
   }
 
   addModule(resolver, response, module, transformed) {
@@ -21,14 +26,8 @@ class HMRBundle extends BundleBase {
       module,
       transformed.code,
     ).then(({name, code}) => {
-      code = `
-        __accept(
-          '${name}',
-          function(global, require, module, exports) {
-            ${code}
-          }
-        );
-      `;
+      // need to be in single line so that lines match on sourcemaps
+      code = `__accept(${JSON.stringify(name)}, function(global, require, module, exports) { ${code} });`;
 
       const moduleTransport = new ModuleTransport({
         code,
@@ -40,8 +39,22 @@ class HMRBundle extends BundleBase {
       });
 
       super.addModule(moduleTransport);
+      this._sourceMappingURLs.push(this._sourceMappingURLFn(moduleTransport.sourcePath));
+      this._sourceURLs.push(this._sourceURLFn(moduleTransport.sourcePath));
     });
   }
+
+  getModulesCode() {
+    return this._modules.map(module => module.code);
+  }
+
+  getSourceURLs() {
+    return this._sourceURLs;
+  }
+
+  getSourceMappingURLs() {
+    return this._sourceMappingURLs;
+  }
 }
 
 module.exports = HMRBundle;
diff --git a/packager/react-packager/src/Bundler/__tests__/Bundle-test.js b/packager/react-packager/src/Bundler/__tests__/Bundle-test.js
index 5e5fca226cc4..b4152a7b2a3e 100644
--- a/packager/react-packager/src/Bundler/__tests__/Bundle-test.js
+++ b/packager/react-packager/src/Bundler/__tests__/Bundle-test.js
@@ -214,7 +214,7 @@ describe('Bundle', () => {
 
         const sourceMap = otherBundle.getSourceMap({dev: true});
         expect(sourceMap).toEqual({
-          file: 'bundle.js',
+          file: 'test_url',
           version: 3,
           sections: [
             { offset: { line: 0, column: 0 }, map: { name: 'sourcemap foo' } },
@@ -340,7 +340,7 @@ describe('Bundle', () => {
 
 
 function genSourceMap(modules) {
-  var sourceMapGen = new SourceMapGenerator({file: 'bundle.js', version: 3});
+  var sourceMapGen = new SourceMapGenerator({file: 'test_url', version: 3});
   var bundleLineNo = 0;
   for (var i = 0; i < modules.length; i++) {
     var module = modules[i];
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index b6ff9133343a..d2852d447cce 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -166,9 +166,58 @@ class Bundler {
     });
   }
 
+  _sourceHMRURL(platform, path) {
+    return this._hmrURL(
+      'http://localhost:8081', // TODO: (martinb) avoid hardcoding
+      platform,
+      'bundle',
+      path,
+    );
+  }
+
+  _sourceMappingHMRURL(platform, path) {
+    // Chrome expects `sourceURL` when eval'ing code
+    return this._hmrURL(
+      '\/\/# sourceURL=',
+      platform,
+      'map',
+      path,
+    );
+  }
+
+  _hmrURL(prefix, platform, extensionOverride, path) {
+    const matchingRoot = this._projectRoots.find(root => path.startsWith(root));
+
+    if (!matchingRoot) {
+      throw new Error('No matching project root for ', path);
+    }
+
+    const extensionStart = path.lastIndexOf('.');
+    let resource = path.substring(
+      matchingRoot.length,
+      extensionStart !== -1 ? extensionStart : undefined,
+    );
+
+    const extension = extensionStart !== -1
+      ? path.substring(extensionStart + 1)
+      : null;
+
+    return (
+      prefix + resource +
+      '.' + extensionOverride + '?' +
+      'platform=' + platform + '&runModule=false&entryModuleOnly=true&hot=true'
+    );
+  }
+
   bundleForHMR(options) {
     return this._bundle({
-      bundle: new HMRBundle(),
+      bundle: new HMRBundle({
+        sourceURLFn: this._sourceHMRURL.bind(this, options.platform),
+        sourceMappingURLFn: this._sourceMappingHMRURL.bind(
+          this,
+          options.platform,
+        ),
+      }),
       hot: true,
       ...options,
     });
@@ -185,6 +234,7 @@ class Bundler {
     platform,
     unbundle: isUnbundle,
     hot: hot,
+    entryModuleOnly,
   }) {
     const findEventId = Activity.startEvent('find dependencies');
     let transformEventId;
@@ -195,18 +245,25 @@ class Bundler {
       bundle.setMainModuleName(response.mainModuleId);
       transformEventId = Activity.startEvent('transform');
 
-      const moduleSystemDeps = includeSystemDependencies
-        ? this._resolver.getModuleSystemDependencies(
-          { dev: isDev, platform, isUnbundle }
-        )
-        : [];
-
-      const modulesToProcess = modules || response.dependencies;
-      const dependencies = moduleSystemDeps.concat(modulesToProcess);
-
-      bundle.setNumPrependedModules && bundle.setNumPrependedModules(
-        response.numPrependedDependencies + moduleSystemDeps.length
-      );
+      let dependencies;
+      if (entryModuleOnly) {
+        dependencies = response.dependencies.filter(module =>
+          module.path.endsWith(entryFile)
+        );
+      } else {
+        const moduleSystemDeps = includeSystemDependencies
+          ? this._resolver.getModuleSystemDependencies(
+            { dev: isDev, platform, isUnbundle }
+          )
+          : [];
+
+        const modulesToProcess = modules || response.dependencies;
+        const dependencies = moduleSystemDeps.concat(modulesToProcess);
+
+        bundle.setNumPrependedModules && bundle.setNumPrependedModules(
+          response.numPrependedDependencies + moduleSystemDeps.length
+        );
+      }
 
       let bar;
       if (process.stdout.isTTY) {
diff --git a/packager/react-packager/src/Server/__tests__/Server-test.js b/packager/react-packager/src/Server/__tests__/Server-test.js
index 123134f84fe4..668e162f0685 100644
--- a/packager/react-packager/src/Server/__tests__/Server-test.js
+++ b/packager/react-packager/src/Server/__tests__/Server-test.js
@@ -144,6 +144,7 @@ describe('processRequest', () => {
         platform: undefined,
         runBeforeMainModule: ['InitializeJavaScriptAppEngine'],
         unbundle: false,
+        entryModuleOnly: false,
       });
     });
   });
@@ -165,6 +166,7 @@ describe('processRequest', () => {
         platform: 'ios',
         runBeforeMainModule: ['InitializeJavaScriptAppEngine'],
         unbundle: false,
+        entryModuleOnly: false,
       });
     });
   });
@@ -321,6 +323,7 @@ describe('processRequest', () => {
           platform: undefined,
           runBeforeMainModule: ['InitializeJavaScriptAppEngine'],
           unbundle: false,
+          entryModuleOnly: false,
         })
       );
     });
@@ -341,6 +344,7 @@ describe('processRequest', () => {
             platform: undefined,
             runBeforeMainModule: ['InitializeJavaScriptAppEngine'],
             unbundle: false,
+            entryModuleOnly: false,
           })
         );
     });
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index 99a3472d6483..559fb3022f4e 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -118,6 +118,10 @@ const bundleOpts = declareOpts({
     type: 'boolean',
     default: false,
   },
+  entryModuleOnly: {
+    type: 'boolean',
+    default: false,
+  },
 });
 
 const dependencyOpts = declareOpts({
@@ -527,6 +531,11 @@ class Server {
         false
       ),
       platform: platform,
+      entryModuleOnly: this._getBoolOptionFromQuery(
+        urlObj.query,
+        'entryModuleOnly',
+        false,
+      ),
     };
   }
 

From c56f280af2c61f203d173ddcc9a537b3f01de459 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Wed, 27 Jan 2016 15:32:17 -0800
Subject: [PATCH 0903/1411] Disable Flow on Packager

Reviewed By: frantic

Differential Revision: D2870105

fb-gh-sync-id: c95db83e40b3558c53614b08240a5361c14e0e6c
---
 .../InitializeJavaScriptAppEngine.js          |   8 -
 .../Initialization/checkFlowAtRuntime.js      |  59 -------
 .../middleware/getFlowTypeCheckMiddleware.js  | 150 ------------------
 local-cli/server/runServer.js                 |   2 -
 4 files changed, 219 deletions(-)
 delete mode 100644 Libraries/JavaScriptAppEngine/Initialization/checkFlowAtRuntime.js
 delete mode 100644 local-cli/server/middleware/getFlowTypeCheckMiddleware.js

diff --git a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
index dea05fa95226..3a5fd5234300 100644
--- a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
+++ b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
@@ -96,13 +96,6 @@ function setUpErrorHandler() {
   ErrorUtils.setGlobalHandler(handleError);
 }
 
-function setUpFlowChecker() {
-  if (__DEV__) {
-    var checkFlowAtRuntime = require('checkFlowAtRuntime');
-    checkFlowAtRuntime();
-  }
-}
-
 /**
  * Sets up a set of window environment wrappers that ensure that the
  * BatchedBridge is flushed after each tick. In both the case of the
@@ -219,7 +212,6 @@ setUpMapAndSet();
 setUpProduct();
 setUpWebSockets();
 setUpProfile();
-setUpFlowChecker();
 setUpNumber();
 setUpDevTools();
 
diff --git a/Libraries/JavaScriptAppEngine/Initialization/checkFlowAtRuntime.js b/Libraries/JavaScriptAppEngine/Initialization/checkFlowAtRuntime.js
deleted file mode 100644
index 8165ae6673d7..000000000000
--- a/Libraries/JavaScriptAppEngine/Initialization/checkFlowAtRuntime.js
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * 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 checkFlowAtRuntime
- *
- */
-'use strict';
-
-function checkFlowAtRuntime() {
-  var url = getPackagerURL();
-  if (!url) {
-    return;
-  }
-  fetch(url + 'flow/')
-    .then(response => response.json())
-    .then(response => {
-      if (response.silentError) {
-        return;
-      }
-      throw {
-        message: response.message,
-        stack: response.errors.map(err => {
-          return {
-            ...err,
-            methodName: err.description,
-            file: err.filename,
-          };
-        }),
-      };
-    },
-    () => {
-    //if fetch fails, silently give up
-    })
-    .done();
-}
-
-function getPackagerURL() {
-  var NativeModules = require('NativeModules');
-  var scriptURL = (NativeModules
-    && NativeModules.SourceCode
-    && NativeModules.SourceCode.scriptURL)
-    || '';
-
-  // extract the url of the packager from the whole scriptURL
-  // we match until the first / after http(s)://
-  // i.e. http://www.mypackger.com/debug/my/bundle -> http://www.mypackger.com/
-  return getFirstOrNull(scriptURL.match(/^https?:\/\/[^/]+\//));
-}
-
-function getFirstOrNull(ar) {
-  return ar ? ar[0] : null;
-}
-
-module.exports = checkFlowAtRuntime;
diff --git a/local-cli/server/middleware/getFlowTypeCheckMiddleware.js b/local-cli/server/middleware/getFlowTypeCheckMiddleware.js
deleted file mode 100644
index 3d90507dd4fe..000000000000
--- a/local-cli/server/middleware/getFlowTypeCheckMiddleware.js
+++ /dev/null
@@ -1,150 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-var chalk = require('chalk');
-var exec = require('child_process').exec;
-var url = require('url');
-var Activity = require('../../../packager/react-packager').Activity;
-
-var hasWarned = {};
-
-function getFlowTypeCheckMiddleware(options) {
-  return function(req, res, next) {
-    var reqObj = url.parse(req.url);
-    var isFlowCheck =  (reqObj.path.match(/^\/flow\//));
-
-    if (!isFlowCheck) {
-      return next();
-    }
-    if (options.skipflow) {
-      _endSkipFlow(res);
-      return;
-    }
-    if (options.flowroot || options.projectRoots.length === 1) {
-      var flowroot = options.flowroot || options.projectRoots[0];
-    } else {
-      if (!hasWarned.noRoot) {
-        hasWarned.noRoot = true;
-        console.warn('flow: No suitable root');
-      }
-      _endFlowBad(res);
-      return;
-    }
-    exec('command -v flow >/dev/null 2>&1', function(error, stdout) {
-      if (error) {
-        if (!hasWarned.noFlow) {
-          hasWarned.noFlow = true;
-          console.warn(chalk.yellow('flow: Skipping because not installed.  Install with ' +
-            '`brew install flow`.'));
-        }
-        _endFlowBad(res);
-        return;
-      } else {
-        return doFlowTypecheck(res, flowroot, next);
-      }
-    });
-  };
-}
-
-function doFlowTypecheck(res, flowroot, next) {
-  var flowCmd = 'cd "' + flowroot + '" && flow --json --timeout 20';
-  var eventId = Activity.startEvent('flow static typechecks');
-  exec(flowCmd, function(flowError, stdout, stderr) {
-    Activity.endEvent(eventId);
-    if (!flowError) {
-      _endFlowOk(res);
-      return;
-    } else {
-      try {
-        var flowResponse = JSON.parse(stdout);
-        var errors = [];
-        var errorNum = 1;
-        flowResponse.errors.forEach(function(err) {
-          // flow errors are paired across callsites, so we indent and prefix to
-          // group them
-          var indent = '';
-          err.message.forEach(function(msg) {
-            errors.push({
-              description: indent + 'E' + errorNum + ': ' + msg.descr,
-              filename: msg.path,
-              lineNumber: msg.line,
-              column: msg.start,
-            });
-            indent = '  ';
-          });
-          errorNum++;
-        });
-        var error = {
-          status: 200,
-          message: 'Flow found type errors.  If you think these are wrong, ' +
-            'make sure your flow bin and .flowconfig are up to date, or ' +
-            'disable with --skipflow.',
-          type: 'FlowError',
-          errors: errors,
-        };
-        res.writeHead(error.status, {
-          'Content-Type': 'application/json; charset=UTF-8',
-        });
-        res.end(JSON.stringify(error));
-      } catch (e) {
-        if (stderr.match(/Could not find a \.flowconfig/)) {
-          if (!hasWarned.noConfig) {
-            hasWarned.noConfig = true;
-            console.warn(chalk.yellow('flow: ' + stderr));
-          }
-          _endFlowBad(res);
-        } else if (flowError.code === 3) {
-          if (!hasWarned.timeout) {
-            hasWarned.timeout = true;
-            console.warn(chalk.yellow('flow: ' + stdout));
-          }
-          _endSkipFlow(res);
-        } else {
-          if (!hasWarned.brokenFlow) {
-            hasWarned.brokenFlow = true;
-            console.warn(chalk.yellow(
-              'Flow failed to provide parseable output:\n\n`' + stdout +
-              '`.\n' + 'stderr: `' + stderr + '`'
-            ));
-          }
-          _endFlowBad(res);
-        }
-        return;
-      }
-    }
-  });
-}
-
-function _endRes(res, message, code, silentError) {
-  res.writeHead(code, {
-    'Content-Type': 'application/json; charset=UTF-8',
-  });
-  res.end(JSON.stringify({
-    message: message,
-    errors: [],
-    silentError: silentError,
-  }));
-}
-
-function _endFlowOk(res) {
-  _endRes(res, 'No Flow Error', '200', true);
-}
-
-function _endFlowBad(res) {
-  // we want to show that flow failed
-  // status 200 is need for the fetch to not be rejected
-  _endRes(res, 'Flow failed to run! Please look at the console for more details.', '200', false);
-}
-
-function _endSkipFlow(res) {
-  _endRes(res, 'Flow was skipped, check the server options', '200', true);
-}
-
-module.exports = getFlowTypeCheckMiddleware;
diff --git a/local-cli/server/runServer.js b/local-cli/server/runServer.js
index 001b9c6878d2..e8d181a278e7 100644
--- a/local-cli/server/runServer.js
+++ b/local-cli/server/runServer.js
@@ -33,8 +33,6 @@ function runServer(args, config, readyCallback) {
     .use(statusPageMiddleware)
     .use(systraceProfileMiddleware)
     .use(cpuProfilerMiddleware)
-    // Temporarily disable flow check until it's more stable
-    //.use(getFlowTypeCheckMiddleware(args))
     .use(packagerServer.processRequest.bind(packagerServer));
 
   args.projectRoots.forEach(root => app.use(connect.static(root)));

From af2f40754a3b50609e8337830da1b50294b1f8a8 Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Wed, 27 Jan 2016 15:54:47 -0800
Subject: [PATCH 0904/1411] Add global flow types to eslint globals

Summary:
Added a subset of the global flow types from the fbjs eslint config to remove the no-undef errors for flow types as well as a few missing browser globals that were used in the codebase.

I also added a .eslintrc file to Examples to allow using alert there without warnings.
Closes https://github.com/facebook/react-native/pull/5585

Reviewed By: svcscm

Differential Revision: D2872016

Pulled By: vjeux

fb-gh-sync-id: f9b1b511289425393074b7237049dec38ea407b6
---
 .eslintrc          | 28 +++++++++++++++++++++++++++-
 Examples/.eslintrc |  5 +++++
 2 files changed, 32 insertions(+), 1 deletion(-)
 create mode 100644 Examples/.eslintrc

diff --git a/.eslintrc b/.eslintrc
index 5a7692b800d2..612fdaf405c7 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -19,6 +19,7 @@
     "__DEV__": true,
     "__dirname": false,
     "__fbBatchedBridgeConfig": false,
+    "alert": false,
     "cancelAnimationFrame": false,
     "clearImmediate": true,
     "clearInterval": false,
@@ -26,8 +27,11 @@
     "console": false,
     "document": false,
     "escape": false,
+    "Event": false,
+    "EventTarget": false,
     "exports": false,
     "fetch": false,
+    "FormData": false,
     "global": false,
     "jest": false,
     "Map": true,
@@ -43,7 +47,29 @@
     "setTimeout": false,
     "window": false,
     "XMLHttpRequest": false,
-    "pit": false
+    "pit": false,
+
+    // Flow global types.
+    "ReactComponent": false,
+    "ReactClass": false,
+    "ReactElement": false,
+    "ReactPropsCheckType": false,
+    "ReactPropsChainableTypeChecker": false,
+    "ReactPropTypes": false,
+    "SyntheticEvent": false,
+    "$Either": false,
+    "$All": false,
+    "$Tuple": false,
+    "$Supertype": false,
+    "$Subtype": false,
+    "$Shape": false,
+    "$Diff": false,
+    "$Keys": false,
+    "$Enum": false,
+    "$Exports": false,
+    "$FlowIssue": false,
+    "$FlowFixMe": false,
+    "$FixMe": false
   },
 
   "rules": {
diff --git a/Examples/.eslintrc b/Examples/.eslintrc
new file mode 100644
index 000000000000..8dc9d22c11ec
--- /dev/null
+++ b/Examples/.eslintrc
@@ -0,0 +1,5 @@
+{
+  "rules": {
+    "no-alert": 0
+  }
+}

From 2529179769ff7f24f9b91acc5417e19983958ff6 Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeuxx@gmail.com>
Date: Wed, 27 Jan 2016 17:05:33 -0800
Subject: [PATCH 0905/1411] Remove min/max Width/Height in the docs

Summary:
An initial implementation was done on css-layout but isn't working correctly on many cases. The binding from React Native has been removed a long time ago. Let's not confuse people and remove it from the docs :)
Closes https://github.com/facebook/react-native/pull/5522

Reviewed By: svcscm

Differential Revision: D2859665

Pulled By: vjeux

fb-gh-sync-id: 4aa008dd93a6cea6b79a7bce444c94148791eee4
---
 Libraries/StyleSheet/LayoutPropTypes.js | 4 ----
 React/Views/RCTShadowView.h             | 4 ----
 React/Views/RCTShadowView.m             | 4 ----
 React/Views/RCTViewManager.m            | 4 ----
 4 files changed, 16 deletions(-)

diff --git a/Libraries/StyleSheet/LayoutPropTypes.js b/Libraries/StyleSheet/LayoutPropTypes.js
index 825db546cafb..95414b339291 100644
--- a/Libraries/StyleSheet/LayoutPropTypes.js
+++ b/Libraries/StyleSheet/LayoutPropTypes.js
@@ -27,11 +27,7 @@ var ReactPropTypes = require('ReactPropTypes');
  */
 var LayoutPropTypes = {
   width: ReactPropTypes.number,
-  maxWidth: ReactPropTypes.number,
-  minWidth: ReactPropTypes.number,
   height: ReactPropTypes.number,
-  maxHeight: ReactPropTypes.number,
-  minHeight: ReactPropTypes.number,
   top: ReactPropTypes.number,
   left: ReactPropTypes.number,
   right: ReactPropTypes.number,
diff --git a/React/Views/RCTShadowView.h b/React/Views/RCTShadowView.h
index d77bb3aea04e..40917304d483 100644
--- a/React/Views/RCTShadowView.h
+++ b/React/Views/RCTShadowView.h
@@ -63,10 +63,6 @@ typedef void (^RCTApplierBlock)(NSDictionary<NSNumber *, UIView *> *viewRegistry
 
 @property (nonatomic, assign) CGFloat width;
 @property (nonatomic, assign) CGFloat height;
-@property (nonatomic, assign) CGFloat minWidth;
-@property (nonatomic, assign) CGFloat minHeight;
-@property (nonatomic, assign) CGFloat maxWidth;
-@property (nonatomic, assign) CGFloat maxHeight;
 @property (nonatomic, assign) CGRect frame;
 
 - (void)setTopLeft:(CGPoint)topLeft;
diff --git a/React/Views/RCTShadowView.m b/React/Views/RCTShadowView.m
index dd1720cd6995..42a2f1b8847f 100644
--- a/React/Views/RCTShadowView.m
+++ b/React/Views/RCTShadowView.m
@@ -507,10 +507,6 @@ - (CGFloat)getProp                                                     \
 
 RCT_DIMENSIONS_PROPERTY(Width, width, WIDTH, dimensions)
 RCT_DIMENSIONS_PROPERTY(Height, height, HEIGHT, dimensions)
-RCT_DIMENSIONS_PROPERTY(MinWidth, minWidth, WIDTH, minDimensions)
-RCT_DIMENSIONS_PROPERTY(MinHeight, minHeight, HEIGHT, minDimensions)
-RCT_DIMENSIONS_PROPERTY(MaxWidth, maxWidth, WIDTH, maxDimensions)
-RCT_DIMENSIONS_PROPERTY(MaxHeight, maxHeight, HEIGHT, maxDimensions)
 
 // Position
 
diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m
index 68980e0bf6d3..5c5cb8f7c2d4 100644
--- a/React/Views/RCTViewManager.m
+++ b/React/Views/RCTViewManager.m
@@ -239,10 +239,6 @@ - (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(__unused NSDictio
 
 RCT_EXPORT_SHADOW_PROPERTY(width, CGFloat)
 RCT_EXPORT_SHADOW_PROPERTY(height, CGFloat)
-RCT_EXPORT_SHADOW_PROPERTY(minWidth, CGFloat)
-RCT_EXPORT_SHADOW_PROPERTY(minHeight, CGFloat)
-RCT_EXPORT_SHADOW_PROPERTY(maxWidth, CGFloat)
-RCT_EXPORT_SHADOW_PROPERTY(maxHeight, CGFloat)
 
 RCT_EXPORT_SHADOW_PROPERTY(borderTopWidth, CGFloat)
 RCT_EXPORT_SHADOW_PROPERTY(borderRightWidth, CGFloat)

From 47f863c4daa897b511b7529bb558073410a50ebc Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeux@fb.com>
Date: Wed, 27 Jan 2016 17:08:11 -0800
Subject: [PATCH 0906/1411] Single quotes in enum values

Summary:
This was driving me crazy :p Turns out that if the value is `'auto' /* default */`, then the docparser will not only trim the comment but also normalize the quote to double quote.

This is not pretty but does the job.
Closes https://github.com/facebook/react-native/pull/5509

Reviewed By: svcscm

Differential Revision: D2872482

Pulled By: vjeux

fb-gh-sync-id: 8ba5dad695f747f82b7680ee26bdc0792e21ea8f
---
 website/layout/AutodocsLayout.js | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/website/layout/AutodocsLayout.js b/website/layout/AutodocsLayout.js
index 13be4808a6fa..d3b2234492e0 100644
--- a/website/layout/AutodocsLayout.js
+++ b/website/layout/AutodocsLayout.js
@@ -20,12 +20,20 @@ var slugify = require('slugify');
 
 var styleReferencePattern = /^[^.]+\.propTypes\.style$/;
 
+function renderEnumValue(value) {
+  // Use single quote strings even when we are given double quotes
+  if (value.match(/^"(.+)"$/)) {
+    return "'" + value.slice(1, -1) + "'";
+  }
+  return value;
+}
+
 function renderType(type) {
   if (type.name === 'enum') {
     if (typeof type.value === 'string') {
       return type.value;
     }
-    return 'enum(' + type.value.map((v) => v.value).join(', ') + ')';
+    return 'enum(' + type.value.map((v) => renderEnumValue(v.value)).join(', ') + ')';
   }
 
   if (type.name === 'shape') {

From 23f772061d6b83b4796c081d47a432a0fffe8bd4 Mon Sep 17 00:00:00 2001
From: Tim Yung <yungsters@fb.com>
Date: Wed, 27 Jan 2016 18:14:12 -0800
Subject: [PATCH 0907/1411] RN: Update / Fix PixelRatio Manual Mock

Reviewed By: cpojer

Differential Revision: D2872990

fb-gh-sync-id: 34c644ec79b424954a14e049b996c658f6b69610
---
 Libraries/Utilities/__mocks__/PixelRatio.js | 28 ++++++++++++---------
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/Libraries/Utilities/__mocks__/PixelRatio.js b/Libraries/Utilities/__mocks__/PixelRatio.js
index bcf04d7fe48a..6e16eddf171f 100644
--- a/Libraries/Utilities/__mocks__/PixelRatio.js
+++ b/Libraries/Utilities/__mocks__/PixelRatio.js
@@ -1,20 +1,24 @@
 /**
  * Copyright 2004-present Facebook. All Rights Reserved.
  */
-'use strict';
-
-var PixelRatio = {
-  startDetecting: function () {
-    // noop for our implementation
-  },
 
-  get: function() {
-    return 2;
-  },
+'use strict';
 
-  getPixelSizeForLayoutSize: function (layoutSize) {
-    return Math.round(layoutSize * PixelRatio.get());
-  }
+const PixelRatio = {
+  get: jest.genMockFunction().mockReturnValue(2),
+  getFontScale: jest.genMockFunction().mockImplementation(
+    () => PixelRatio.get()
+  ),
+  getPixelSizeForLayoutSize: jest.genMockFunction().mockImplementation(
+    layoutSize => Math.round(layoutSize * PixelRatio.get())
+  ),
+  roundToNearestPixel: jest.genMockFunction().mockImplementation(
+    layoutSize => {
+      const ratio = PixelRatio.get();
+      return Math.round(layoutSize * ratio) / ratio;
+    }
+  ),
+  startDetecting: jest.genMockFunction(),
 };
 
 module.exports = PixelRatio;

From 3117a334b1627121333ff9941e02d3c328addff4 Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Wed, 27 Jan 2016 18:46:23 -0800
Subject: [PATCH 0908/1411] Limit mocks shared with a resolution response

Reviewed By: davidaurelio

Differential Revision: D2872340

fb-gh-sync-id: a76b580ff670115cd4bd0098e7b9f31110239369
---
 .../DependencyGraph/ResolutionRequest.js      | 19 ++++++++++---------
 .../__tests__/DependencyGraph-test.js         |  5 +++--
 2 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
index ebe7c39a9fe8..58dcc7d1c36e 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
@@ -104,10 +104,9 @@ class ResolutionRequest {
   }
 
   getOrderedDependencies(response, mocksPattern) {
-    return this._getAllMocks(mocksPattern).then(mocks => {
-      response.setMocks(mocks);
-
+    return this._getAllMocks(mocksPattern).then(allMocks => {
       const entry = this._moduleCache.getModule(this._entryPath);
+      const mocks = Object.create(null);
       const visited = Object.create(null);
       visited[entry.hash()] = true;
 
@@ -118,13 +117,14 @@ class ResolutionRequest {
             depNames.map(name => this.resolveDependency(mod, name))
           ).then((dependencies) => [depNames, dependencies])
         ).then(([depNames, dependencies]) => {
-          if (mocks) {
+          if (allMocks) {
             return mod.getName().then(name => {
-              if (mocks[name]) {
+              if (allMocks[name]) {
                 const mockModule =
-                  this._moduleCache.getModule(mocks[name]);
+                  this._moduleCache.getModule(allMocks[name]);
                 depNames.push(name);
                 dependencies.push(mockModule);
+                mocks[name] = allMocks[name];
               }
               return [depNames, dependencies];
             });
@@ -141,8 +141,9 @@ class ResolutionRequest {
               // module backing them. If a dependency cannot be found but there
               // exists a mock with the desired ID, resolve it and add it as
               // a dependency.
-              if (mocks && mocks[name]) {
-                const mockModule = this._moduleCache.getModule(mocks[name]);
+              if (allMocks && allMocks[name]) {
+                const mockModule = this._moduleCache.getModule(allMocks[name]);
+                mocks[name] = allMocks[name];
                 return filteredPairs.push([name, mockModule]);
               }
 
@@ -172,7 +173,7 @@ class ResolutionRequest {
         });
       };
 
-      return collect(entry);
+      return collect(entry).then(() => response.setMocks(mocks));
     });
   }
 
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
index 6c88acb63900..464985f692f8 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
@@ -4117,11 +4117,11 @@ describe('DependencyGraph', function() {
       return dgraph.getDependencies('/root/index.js')
         .then(response => response.finalize())
         .then(response => {
-          expect(response.mocks).toBe(null);
+          expect(response.mocks).toEqual({});
         });
     });
 
-    pit('retrieves a list of all mocks in the system', () => {
+    pit('retrieves a list of all required mocks', () => {
       var root = '/root';
       fs.__setMockFilesystem({
         'root': {
@@ -4133,6 +4133,7 @@ describe('DependencyGraph', function() {
             '/**',
             ' * @providesModule b',
             ' */',
+            'require("A");',
           ].join('\n'),
         },
       });

From f7c48ee0cef0bd8cb5fe94ce2e7d1e028c553a83 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Wed, 27 Jan 2016 18:59:56 -0800
Subject: [PATCH 0909/1411] Fix per connection timeouts for XHR

Summary:
public

When initially implemented, the timeout for a request was actually set for all requests that the OKHttpClient handled, not just that request.
The fix is to clone the client, set the timeout for the client which will be used for that request.

Reviewed By: andreicoman11

Differential Revision: D2873220

fb-gh-sync-id: c8c102a6eb9dd0ac57d5a7f53c3ba3b7d6db5ef9
---
 .../react/modules/network/NetworkingModule.java      | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
index 9374683b9d8e..50cd58a08da0 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
@@ -132,7 +132,15 @@ public void sendRequest(
       requestBuilder.tag(requestId);
     }
 
-    mClient.setConnectTimeout(timeout, TimeUnit.MILLISECONDS);
+    OkHttpClient client = mClient;
+    // If the current timeout does not equal the passed in timeout, we need to clone the existing
+    // client and set the timeout explicitly on the clone.  This is cheap as everything else is
+    // shared under the hood.
+    // See https://github.com/square/okhttp/wiki/Recipes#per-call-configuration for more information
+    if (timeout != mClient.getConnectTimeout()) {
+      client = mClient.clone();
+      client.setReadTimeout(timeout, TimeUnit.MILLISECONDS);
+    }
 
     Headers requestHeaders = extractHeaders(headers, data);
     if (requestHeaders == null) {
@@ -193,7 +201,7 @@ public void sendRequest(
       requestBuilder.method(method, null);
     }
 
-    mClient.newCall(requestBuilder.build()).enqueue(
+    client.newCall(requestBuilder.build()).enqueue(
         new Callback() {
           @Override
           public void onFailure(Request request, IOException e) {

From 96a3a8e9b93d9931a6b133649bfab4048682a62a Mon Sep 17 00:00:00 2001
From: Daniel Colascione <dancol@fb.com>
Date: Wed, 27 Jan 2016 21:55:24 -0800
Subject: [PATCH 0910/1411] Codemod realtime to CLOCK_MONOTONIC where it makes
 sense

Reviewed By: rickbrew

Differential Revision: D2860798

fb-gh-sync-id: 35cd188091f6f790809afed81529531850f82d85
---
 .../react/testing/ReactIdleDetectionUtil.java      | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIdleDetectionUtil.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIdleDetectionUtil.java
index bd09d2133530..340dec8347f6 100644
--- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIdleDetectionUtil.java
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIdleDetectionUtil.java
@@ -36,16 +36,16 @@ public static void waitForBridgeAndUIIdle(
       long timeoutMs) {
     UiThreadUtil.assertNotOnUiThread();
 
-    long startTime = SystemClock.elapsedRealtime();
+    long startTime = SystemClock.uptimeMillis();
     waitInner(idleSignaler, timeoutMs);
 
-    long timeToWait = Math.max(1, timeoutMs - (SystemClock.elapsedRealtime() - startTime));
+    long timeToWait = Math.max(1, timeoutMs - (SystemClock.uptimeMillis() - startTime));
     waitForChoreographer(timeToWait);
     waitForJSIdle(reactContext);
 
-    timeToWait = Math.max(1, timeoutMs - (SystemClock.elapsedRealtime() - startTime));
+    timeToWait = Math.max(1, timeoutMs - (SystemClock.uptimeMillis() - startTime));
     waitInner(idleSignaler, timeToWait);
-    timeToWait = Math.max(1, timeoutMs - (SystemClock.elapsedRealtime() - startTime));
+    timeToWait = Math.max(1, timeoutMs - (SystemClock.uptimeMillis() - startTime));
     waitForChoreographer(timeToWait);
   }
 
@@ -108,15 +108,15 @@ public void run() {
   private static void waitInner(ReactBridgeIdleSignaler idleSignaler, long timeToWait) {
     // TODO gets broken in gradle, do we need it?
     Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
-    long startTime = SystemClock.elapsedRealtime();
+    long startTime = SystemClock.uptimeMillis();
     boolean bridgeWasIdle = false;
-    while (SystemClock.elapsedRealtime() - startTime < timeToWait) {
+    while (SystemClock.uptimeMillis() - startTime < timeToWait) {
       boolean bridgeIsIdle = idleSignaler.isBridgeIdle();
       if (bridgeIsIdle && bridgeWasIdle) {
         return;
       }
       bridgeWasIdle = bridgeIsIdle;
-      long newTimeToWait = Math.max(1, timeToWait - (SystemClock.elapsedRealtime() - startTime));
+      long newTimeToWait = Math.max(1, timeToWait - (SystemClock.uptimeMillis() - startTime));
       idleSignaler.waitForIdle(newTimeToWait);
       instrumentation.waitForIdleSync();
     }

From 4511993ffaf503b902fb9741c396eaa090a5662e Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 28 Jan 2016 04:06:27 -0800
Subject: [PATCH 0911/1411] Fix duplicate platform labels in UIExplorer
 examples

Summary:
public
This fixes a bug in UIExplorer, where platform labels on examples like (ios only) or (android only) would be re-appended to the title each time the example was viewed.

Reviewed By: javache

Differential Revision: D2869690

fb-gh-sync-id: 07f3f14007f75eea23a5328b7850f3f620691ac2
---
 Examples/UIExplorer/createExamplePage.js | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/Examples/UIExplorer/createExamplePage.js b/Examples/UIExplorer/createExamplePage.js
index 41068816096d..55ebd159961d 100644
--- a/Examples/UIExplorer/createExamplePage.js
+++ b/Examples/UIExplorer/createExamplePage.js
@@ -39,11 +39,13 @@ var createExamplePage = function(title: ?string, exampleModule: ExampleModule)
     },
 
     getBlock: function(example: Example, i) {
-      if (example.platform) {
-        if (Platform.OS !== example.platform) {
-          return;
+      // Filter platform-specific examples
+      var {title, description, platform} = example;
+      if (platform) {
+        if (Platform.OS !== platform) {
+          return null;
         }
-        example.title += ' (' + example.platform + ' only)';
+        title += ' (' + platform + ' only)';
       }
       // Hack warning: This is a hack because the www UI explorer requires
       // renderComponent to be called.
@@ -74,8 +76,8 @@ var createExamplePage = function(title: ?string, exampleModule: ExampleModule)
       return (
         <UIExplorerBlock
           key={i}
-          title={example.title}
-          description={example.description}>
+          title={title}
+          description={description}>
           {renderedComponent}
         </UIExplorerBlock>
       );

From 0f7477f9f9fc13e437e311a188253366529bdeb2 Mon Sep 17 00:00:00 2001
From: August Flanagan <august.flanagan@gmail.com>
Date: Thu, 28 Jan 2016 05:35:14 -0800
Subject: [PATCH 0912/1411] add flag to enable momentum scrolling on iOS

Summary:
Expose a `decelerationNormalEnabled` flag on WebView, which, when enabled, will WebView's ScrollView's `decelerationRate` to `UIScrollViewDecelerationRateNormal`. This gives the WebView the same "momentum" style scrolling as other iOS views.

This was discussed with ide in #5447. Please let me know if there's anything I'm missing, or anything else you'd like to see in this pull request.
Closes https://github.com/facebook/react-native/pull/5527

Reviewed By: svcscm

Differential Revision: D2870312

Pulled By: nicklockwood

fb-gh-sync-id: 7dbfd06a349e3365a5df40c3bacf25a4fdb306cf
---
 Examples/UIExplorer/ImageEditingExample.js    |  9 +-----
 Examples/UIExplorer/WebViewExample.js         |  1 +
 Libraries/Components/ScrollView/ScrollView.js | 17 +++++++++--
 .../ScrollView/processDecelerationRate.js     | 29 +++++++++++++++++++
 Libraries/Components/WebView/WebView.ios.js   | 16 ++++++++++
 React/Views/RCTWebViewManager.m               |  1 +
 6 files changed, 62 insertions(+), 11 deletions(-)
 create mode 100644 Libraries/Components/ScrollView/processDecelerationRate.js

diff --git a/Examples/UIExplorer/ImageEditingExample.js b/Examples/UIExplorer/ImageEditingExample.js
index 8f4e4e7f657b..86b4f53435ee 100644
--- a/Examples/UIExplorer/ImageEditingExample.js
+++ b/Examples/UIExplorer/ImageEditingExample.js
@@ -30,8 +30,6 @@ var {
   View,
 } = React;
 
-var RCTScrollViewConsts = UIManager.RCTScrollView.Constants;
-
 var PAGE_SIZE = 20;
 
 type ImageOffset = {
@@ -249,17 +247,12 @@ class ImageCropper extends React.Component {
   }
 
   render() {
-    var decelerationRate =
-      RCTScrollViewConsts && RCTScrollViewConsts.DecelerationRate ?
-        RCTScrollViewConsts.DecelerationRate.Fast :
-        0;
-
     return (
       <ScrollView
         alwaysBounceVertical={true}
         automaticallyAdjustContentInsets={false}
         contentOffset={this._contentOffset}
-        decelerationRate={decelerationRate}
+        decelerationRate="fast"
         horizontal={true}
         maximumZoomScale={3.0}
         onMomentumScrollEnd={this._onScroll.bind(this)}
diff --git a/Examples/UIExplorer/WebViewExample.js b/Examples/UIExplorer/WebViewExample.js
index 96f60b13110a..e760ebdf5b62 100644
--- a/Examples/UIExplorer/WebViewExample.js
+++ b/Examples/UIExplorer/WebViewExample.js
@@ -96,6 +96,7 @@ var WebViewExample = React.createClass({
           url={this.state.url}
           javaScriptEnabled={true}
           domStorageEnabled={true}
+          decelerationRate="normal"
           onNavigationStateChange={this.onNavigationStateChange}
           onShouldStartLoadWithRequest={this.onShouldStartLoadWithRequest}
           startInLoadingState={true}
diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js
index fb8d1452c320..6d80b6751716 100644
--- a/Libraries/Components/ScrollView/ScrollView.js
+++ b/Libraries/Components/ScrollView/ScrollView.js
@@ -32,7 +32,7 @@ var invariant = require('invariant');
 var pointsDiffer = require('pointsDiffer');
 var requireNativeComponent = require('requireNativeComponent');
 var processColor = require('processColor');
-
+var processDecelerationRate = require('processDecelerationRate');
 var PropTypes = React.PropTypes;
 
 var SCROLLVIEW = 'ScrollView';
@@ -130,12 +130,18 @@ var ScrollView = React.createClass({
     contentContainerStyle: StyleSheetPropType(ViewStylePropTypes),
     /**
      * A floating-point number that determines how quickly the scroll view
-     * decelerates after the user lifts their finger. Reasonable choices include
+     * decelerates after the user lifts their finger. You may also use string
+     * shortcuts `"normal"` and `"fast"` which match the underlying iOS settings
+     * for `UIScrollViewDecelerationRateNormal` and
+     * `UIScrollViewDecelerationRateFast` respectively.
      *   - Normal: 0.998 (the default)
      *   - Fast: 0.9
      * @platform ios
      */
-    decelerationRate: PropTypes.number,
+    decelerationRate: PropTypes.oneOfType([
+      PropTypes.oneOf(['fast', 'normal']),
+      PropTypes.number,
+    ]),
     /**
      * When true, the scroll view's children are arranged horizontally in a row
      * instead of vertically in a column. The default value is false.
@@ -465,6 +471,11 @@ var ScrollView = React.createClass({
         function() { onRefreshStart && onRefreshStart(this.endRefreshing); }.bind(this);
     }
 
+    var { decelerationRate } = this.props;
+    if (decelerationRate) {
+      props.decelerationRate = processDecelerationRate(decelerationRate);
+    }
+
     var ScrollViewClass;
     if (Platform.OS === 'ios') {
       ScrollViewClass = RCTScrollView;
diff --git a/Libraries/Components/ScrollView/processDecelerationRate.js b/Libraries/Components/ScrollView/processDecelerationRate.js
new file mode 100644
index 000000000000..82be66cef4a6
--- /dev/null
+++ b/Libraries/Components/ScrollView/processDecelerationRate.js
@@ -0,0 +1,29 @@
+/**
+ * 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 processDecelerationRate
+ */
+'use strict';
+
+var ScrollViewConsts = require('UIManager').RCTScrollView.Constants;
+
+function processDecelerationRate(decelerationRate) {
+  var ScrollViewDecelerationRateNormal = ScrollViewConsts && ScrollViewConsts.DecelerationRate.normal;
+  var ScrollViewDecelerationRateFast = ScrollViewConsts && ScrollViewConsts.DecelerationRate.fast;
+
+  if (typeof decelerationRate === 'string') {
+    if (decelerationRate === 'fast') {
+      return ScrollViewDecelerationRateFast;
+    } else if (decelerationRate === 'normal') {
+      return ScrollViewDecelerationRateNormal;
+    }
+  }
+  return decelerationRate;
+}
+
+module.exports = processDecelerationRate;
diff --git a/Libraries/Components/WebView/WebView.ios.js b/Libraries/Components/WebView/WebView.ios.js
index ea49044e10d4..1b561d225d9b 100644
--- a/Libraries/Components/WebView/WebView.ios.js
+++ b/Libraries/Components/WebView/WebView.ios.js
@@ -18,7 +18,9 @@ var StyleSheet = require('StyleSheet');
 var Text = require('Text');
 var UIManager = require('UIManager');
 var View = require('View');
+var ScrollView = require('ScrollView')
 
+var processDecelerationRate = require('processDecelerationRate');
 var invariant = require('invariant');
 var keyMirror = require('keyMirror');
 var requireNativeComponent = require('requireNativeComponent');
@@ -117,6 +119,17 @@ var WebView = React.createClass({
      * @platform ios
      */
     bounces: PropTypes.bool,
+    /**
+     * A floating-point number that determines how quickly the scroll view
+     * decelerates after the user lifts their finger. You may also use string
+     * shortcuts `"normal"` and `"fast"` which match the underlying iOS settings
+     * for `UIScrollViewDecelerationRateNormal` and
+     * `UIScrollViewDecelerationRateFast` respectively.
+     *   - Normal: 0.998
+     *   - Fast: 0.9 (the default for iOS WebView)
+     * @platform ios
+     */
+    decelerationRate: ScrollView.propTypes.decelerationRate,
     /**
      * @platform ios
      */
@@ -228,6 +241,8 @@ var WebView = React.createClass({
       domStorageEnabled = this.props.domStorageEnabledAndroid;
     }
 
+    var decelerationRate = processDecelerationRate(this.props.decelerationRate);
+
     var webView =
       <RCTWebView
         ref={RCT_WEBVIEW_REF}
@@ -238,6 +253,7 @@ var WebView = React.createClass({
         injectedJavaScript={this.props.injectedJavaScript}
         bounces={this.props.bounces}
         scrollEnabled={this.props.scrollEnabled}
+        decelerationRate={decelerationRate}
         contentInset={this.props.contentInset}
         automaticallyAdjustContentInsets={this.props.automaticallyAdjustContentInsets}
         onLoadingStart={this.onLoadingStart}
diff --git a/React/Views/RCTWebViewManager.m b/React/Views/RCTWebViewManager.m
index 58d663cad6da..5e5aff190738 100644
--- a/React/Views/RCTWebViewManager.m
+++ b/React/Views/RCTWebViewManager.m
@@ -38,6 +38,7 @@ - (UIView *)view
 RCT_REMAP_VIEW_PROPERTY(bounces, _webView.scrollView.bounces, BOOL)
 RCT_REMAP_VIEW_PROPERTY(scrollEnabled, _webView.scrollView.scrollEnabled, BOOL)
 RCT_REMAP_VIEW_PROPERTY(scalesPageToFit, _webView.scalesPageToFit, BOOL)
+RCT_REMAP_VIEW_PROPERTY(decelerationRate, _webView.scrollView.decelerationRate, CGFloat)
 RCT_EXPORT_VIEW_PROPERTY(injectedJavaScript, NSString)
 RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets)
 RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets, BOOL)

From a322ab61fba58fda655093006e0b96e5e3a9a7ab Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 28 Jan 2016 09:42:28 -0800
Subject: [PATCH 0913/1411] Fix ImageEditor example

Summary:
public

A fix added to make the ImageEditor example usable on Android inadvertantly broke the cropping logic on iOS, so that zoomed images were cropped incorrectly.

This diff fixes that, and also sets the min/max zoom scale correctly based on the image scale, instead of using a hard-coded value.

Reviewed By: bestander

Differential Revision: D2874576

fb-gh-sync-id: 02c62940c24f4d4266655de6ddbf4fe3bc9c13ce
---
 Examples/UIExplorer/ImageEditingExample.js | 40 ++++++++++++++++------
 1 file changed, 30 insertions(+), 10 deletions(-)

diff --git a/Examples/UIExplorer/ImageEditingExample.js b/Examples/UIExplorer/ImageEditingExample.js
index 86b4f53435ee..1a8c931221d5 100644
--- a/Examples/UIExplorer/ImageEditingExample.js
+++ b/Examples/UIExplorer/ImageEditingExample.js
@@ -22,6 +22,7 @@ var {
   Image,
   ImageEditor,
   NativeModules,
+  Platform,
   ScrollView,
   StyleSheet,
   Text,
@@ -187,31 +188,49 @@ class SquareImageCropper extends React.Component {
 }
 
 class ImageCropper extends React.Component {
-  _scaledImageSize: ImageSize;
   _contentOffset: ImageOffset;
+  _maximumZoomScale: number;
+  _minimumZoomScale: number;
+  _scaledImageSize: ImageSize;
+  _horizontal: boolean;
 
   componentWillMount() {
     // Scale an image to the minimum size that is large enough to completely
     // fill the crop box.
     var widthRatio = this.props.image.width / this.props.size.width;
     var heightRatio = this.props.image.height / this.props.size.height;
-    if (widthRatio < heightRatio) {
+    this._horizontal = widthRatio > heightRatio;
+    if (this._horizontal) {
       this._scaledImageSize = {
-        width: this.props.size.width,
-        height: this.props.image.height / widthRatio,
+        width: this.props.image.width / heightRatio,
+        height: this.props.size.height,
       };
     } else {
       this._scaledImageSize = {
-        width: this.props.image.width / heightRatio,
-        height: this.props.size.height,
+        width: this.props.size.width,
+        height: this.props.image.height / widthRatio,
       };
+      if (Platform.OS === 'android') {
+        // hack to work around Android ScrollView a) not supporting zoom, and
+        // b) not supporting vertical scrolling when nested inside another
+        // vertical ScrollView (which it is, when displayed inside UIExplorer)
+        this._scaledImageSize.width *= 2;
+        this._scaledImageSize.height *= 2;
+        this._horizontal = true;
+      }
     }
-    // a quick hack for android because Android ScrollView does not have zoom feature
-    this._scaledImageSize.width = 2 * this._scaledImageSize.width;
     this._contentOffset = {
       x: (this._scaledImageSize.width - this.props.size.width) / 2,
       y: (this._scaledImageSize.height - this.props.size.height) / 2,
     };
+    this._maximumZoomScale = Math.min(
+      this.props.image.width / this._scaledImageSize.width,
+      this.props.image.height / this._scaledImageSize.height
+    );
+    this._minimumZoomScale = Math.max(
+      this.props.size.width / this._scaledImageSize.width,
+      this.props.size.height / this._scaledImageSize.height 
+    );
     this._updateTransformData(
       this._contentOffset,
       this._scaledImageSize,
@@ -253,8 +272,9 @@ class ImageCropper extends React.Component {
         automaticallyAdjustContentInsets={false}
         contentOffset={this._contentOffset}
         decelerationRate="fast"
-        horizontal={true}
-        maximumZoomScale={3.0}
+        horizontal={this._horizontal}
+        maximumZoomScale={this._maximumZoomScale}
+        minimumZoomScale={this._minimumZoomScale}
         onMomentumScrollEnd={this._onScroll.bind(this)}
         onScrollEndDrag={this._onScroll.bind(this)}
         showsHorizontalScrollIndicator={false}

From 4a226fc1af835db125cd7cf5a40c765096761753 Mon Sep 17 00:00:00 2001
From: Jan Kassens <jkassens@fb.com>
Date: Thu, 28 Jan 2016 12:07:38 -0800
Subject: [PATCH 0914/1411] Add guard to ErrorUtils mock

Summary:
This method is defined in the implementation but is missing from the mock.

public

Reviewed By: cpojer

Differential Revision: D2875173

fb-gh-sync-id: 6544c34a3d707ff9cecacc0608ab8320b950bfb7
---
 Libraries/Utilities/__mocks__/ErrorUtils.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Libraries/Utilities/__mocks__/ErrorUtils.js b/Libraries/Utilities/__mocks__/ErrorUtils.js
index 59fbbafbc904..832d27e60072 100644
--- a/Libraries/Utilities/__mocks__/ErrorUtils.js
+++ b/Libraries/Utilities/__mocks__/ErrorUtils.js
@@ -15,6 +15,7 @@ function reportError(error) {
 var ErrorUtils = {
   apply: jest.genMockFunction().mockImplementation(execute),
   applyWithGuard: jest.genMockFunction().mockImplementation(execute),
+  guard: jest.genMockFunction().mockImplementation(callback => callback),
   inGuard: jest.genMockFunction().mockReturnValue(true),
   reportError: jest.genMockFunction().mockImplementation(reportError),
   setGlobalHandler: jest.genMockFunction(),

From b55dcbe0af36b7cdb262cd046d09359243811ef6 Mon Sep 17 00:00:00 2001
From: Wenjing Wang <wenjingw@fb.com>
Date: Thu, 28 Jan 2016 14:24:01 -0800
Subject: [PATCH 0915/1411] Fix CPU spike: should use UIGraphicsEndImageContext
 rather than UIGraphicsGetCurrentContext

Summary:
should use UIGraphicsEndImageContext rather than UIGraphicsGetCurrentContext

public

Reviewed By: nicklockwood, chaceliang

Differential Revision: D2875657

fb-gh-sync-id: 0fa059e2da3d0bb1ffe5fe50a1bdaeddafc2bbfa
---
 Libraries/Image/RCTImageUtils.m | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/Image/RCTImageUtils.m b/Libraries/Image/RCTImageUtils.m
index a89872508f74..edc1cb926c16 100644
--- a/Libraries/Image/RCTImageUtils.m
+++ b/Libraries/Image/RCTImageUtils.m
@@ -321,7 +321,7 @@ BOOL RCTUpscalingRequired(CGSize sourceSize, CGFloat sourceScale,
   CGContextConcatCTM(currentContext, transform);
   [image drawAtPoint:CGPointZero];
   UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
-  UIGraphicsGetCurrentContext();
+  UIGraphicsEndImageContext();
   return result;
 }
 

From e9f95c1a7d08d34640625e4db362f73e29385cb3 Mon Sep 17 00:00:00 2001
From: Brent Vatne <brentvatne@gmail.com>
Date: Thu, 28 Jan 2016 15:10:59 -0800
Subject: [PATCH 0916/1411] Check for contentView before emitting scroll event

Summary:
I've found that when switching between tabs that each have ScrollViews, sometimes `emitScrollEvent` fires without a `contentView`, which causes the following crash:

```
`D/AndroidRuntime(24496): Shutting down VM
E/AndroidRuntime(24496): FATAL EXCEPTION: main
E/AndroidRuntime(24496): Process: com.listexp, PID: 24496
E/AndroidRuntime(24496): java.lang.NullPointerException: Attempt to invoke virtual method 'int android.view.View.getWidth()' on a null object reference
E/AndroidRuntime(24496):        at com.facebook.react.views.scroll.ReactScrollViewHelper.emitScrollEvent(ReactScrollViewHelper.java:59)
E/AndroidRuntime(24496):        at com.facebook.react.views.scroll.ReactScrollViewHelper.emitScrollMomentumEndEvent(ReactScrollViewHelper.java:46)
E/AndroidRuntime(24496):        at com.facebook.react.views.scroll.ReactScrollView$1.run(ReactScrollView.java:159)
E/AndroidRuntime(24496):        at android.os.Handler.handleCallback(Handler.java:739)
E/AndroidRuntime(24496):        at android.os.Handler.disp
Closes https://github.com/facebook/react-native/pull/5561

Reviewed By: svcscm

Differential Revision: D2876385

Pulled By: androidtrunkagent

fb-gh-sync-id: 33406eaa96352d5adae857088da09fb446b68440
---
 .../facebook/react/views/scroll/ReactScrollViewHelper.java   | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java
index 1b9c3eb7d901..3ee46350dbe1 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java
@@ -48,6 +48,11 @@ public static void emitScrollMomentumEndEvent(ViewGroup scrollView) {
 
   private static void emitScrollEvent(ViewGroup scrollView, ScrollEventType scrollEventType) {
     View contentView = scrollView.getChildAt(0);
+
+    if (contentView == null) {
+      return;
+    }
+
     ReactContext reactContext = (ReactContext) scrollView.getContext();
     reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(
         ScrollEvent.obtain(

From b7b27bdf2543e145c9624ecdb4ecaca81eea3d0f Mon Sep 17 00:00:00 2001
From: Adam Miskiewicz <adam@sk3vy.com>
Date: Thu, 28 Jan 2016 15:18:04 -0800
Subject: [PATCH 0917/1411] Fixing typo in Bundler

Summary:
With an upgraded Babel dependency, failing tests correctly found this typo.

It does not currently cause a test failure in the current version of master, however,
which is concerning. I found it when testing #5214.

cc martinbigio just because it was your code :)
Closes https://github.com/facebook/react-native/pull/5601

Reviewed By: svcscm

Differential Revision: D2876386

Pulled By: androidtrunkagent

fb-gh-sync-id: 378da39be79ac1b9a950ea9a7442ac24c0c3a87d
---
 packager/react-packager/src/Bundler/index.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index d2852d447cce..b0ccc235ef59 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -258,7 +258,7 @@ class Bundler {
           : [];
 
         const modulesToProcess = modules || response.dependencies;
-        const dependencies = moduleSystemDeps.concat(modulesToProcess);
+        dependencies = moduleSystemDeps.concat(modulesToProcess);
 
         bundle.setNumPrependedModules && bundle.setNumPrependedModules(
           response.numPrependedDependencies + moduleSystemDeps.length

From ca8792d2ccb16baefde7837b5a1a97d864575528 Mon Sep 17 00:00:00 2001
From: Nathan Spaun <nspaun@fb.com>
Date: Thu, 28 Jan 2016 15:50:45 -0800
Subject: [PATCH 0918/1411] Add check to broadcast receiver to prevent
 exception

Reviewed By: andreicoman11

Differential Revision: D2876479

fb-gh-sync-id: 55b7e31a91cf8a05849a0876bf912ac931233638
---
 .../react/modules/netinfo/NetInfoModule.java    | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java
index bff80bf26b22..463ad17c4d59 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java
@@ -106,10 +106,14 @@ private void registerReceiver() {
     IntentFilter filter = new IntentFilter();
     filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
     getReactApplicationContext().registerReceiver(mConnectivityBroadcastReceiver, filter);
+    mConnectivityBroadcastReceiver.setRegistered(true);
   }
 
   private void unregisterReceiver() {
-    getReactApplicationContext().unregisterReceiver(mConnectivityBroadcastReceiver);
+    if (mConnectivityBroadcastReceiver.isRegistered()) {
+      getReactApplicationContext().unregisterReceiver(mConnectivityBroadcastReceiver);
+      mConnectivityBroadcastReceiver.setRegistered(false);
+    }
   }
 
   private void updateAndSendConnectionType() {
@@ -155,6 +159,17 @@ private WritableMap createConnectivityEventMap() {
    */
   private class ConnectivityBroadcastReceiver extends BroadcastReceiver {
 
+    //TODO: Remove registered check when source of crash is found. t9846865
+    private boolean isRegistered = false;
+
+    public void setRegistered(boolean registered) {
+      isRegistered = registered;
+    }
+
+    public boolean isRegistered() {
+      return isRegistered;
+    }
+
     @Override
     public void onReceive(Context context, Intent intent) {
       if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {

From a61ab8795af508669a986e7a60d3f82acf367166 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Thu, 28 Jan 2016 16:28:37 -0800
Subject: [PATCH 0919/1411] Add transform option to module / module cache

Summary:
public

This adds an option to `Module` (and its callers) that allows to transform code before extracting dependencies. The transform function has to return a promise that resolves to an object with `code`, and optionally `dependencies` and/or `asyncDependencies` properties, if standard dependency extraction cannot be applied

Reviewed By: cpojer

Differential Revision: D2870437

fb-gh-sync-id: 806d24ba16b1693d838a3fa747d82be9dc6ccf00
---
 .../DependencyGraph/index.js                  |  18 +-
 .../src/DependencyResolver/Module.js          |  34 ++-
 .../src/DependencyResolver/ModuleCache.js     |  11 +-
 .../__tests__/Module-test.js                  | 230 ++++++++++++------
 4 files changed, 199 insertions(+), 94 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
index 1192159b308d..023fca506ec8 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
@@ -42,6 +42,7 @@ class DependencyGraph {
     extensions,
     mocksPattern,
     extractRequires,
+    transformCode,
     shouldThrowOnUnresolvedErrors = () => true,
   }) {
     this._opts = {
@@ -54,13 +55,13 @@ class DependencyGraph {
       providesModuleNodeModules,
       platforms: platforms || [],
       preferNativePlatform: preferNativePlatform || false,
-      cache,
       extensions: extensions || ['js', 'json'],
       mocksPattern,
       extractRequires,
       shouldThrowOnUnresolvedErrors,
+      transformCode
     };
-    this._cache = this._opts.cache;
+    this._cache = cache;
     this._helpers = new DependencyGraphHelpers(this._opts);
     this.load().catch((err) => {
       // This only happens at initialization. Live errors are easier to recover from.
@@ -98,12 +99,13 @@ class DependencyGraph {
 
     this._fastfs.on('change', this._processFileChange.bind(this));
 
-    this._moduleCache = new ModuleCache(
-      this._fastfs,
-      this._cache,
-      this._opts.extractRequires,
-      this._helpers
-    );
+    this._moduleCache = new ModuleCache({
+      fastfs: this._fastfs,
+      cache: this._cache,
+      extractRequires: this._opts.extractRequires,
+      transformCode: this._opts.transformCode,
+      depGraphHelpers: this._helpers,
+    });
 
     this._hasteMap = new HasteMap({
       fastfs: this._fastfs,
diff --git a/packager/react-packager/src/DependencyResolver/Module.js b/packager/react-packager/src/DependencyResolver/Module.js
index 09fbe7939c0c..df6ed710726b 100644
--- a/packager/react-packager/src/DependencyResolver/Module.js
+++ b/packager/react-packager/src/DependencyResolver/Module.js
@@ -15,7 +15,15 @@ const extractRequires = require('./lib/extractRequires');
 
 class Module {
 
-  constructor({ file, fastfs, moduleCache, cache, extractor, depGraphHelpers }) {
+  constructor({
+    file,
+    fastfs,
+    moduleCache,
+    cache,
+    extractor = extractRequires,
+    transformCode,
+    depGraphHelpers,
+  }) {
     if (!isAbsolutePath(file)) {
       throw new Error('Expected file to be absolute path but got ' + file);
     }
@@ -27,6 +35,7 @@ class Module {
     this._moduleCache = moduleCache;
     this._cache = cache;
     this._extractor = extractor;
+    this._transformCode = transformCode;
     this._depGraphHelpers = depGraphHelpers;
   }
 
@@ -38,6 +47,10 @@ class Module {
     );
   }
 
+  getCode() {
+    return this.read().then(({code}) => code);
+  }
+
   getName() {
     return this._cache.get(
       this.path,
@@ -114,13 +127,22 @@ class Module {
         if (this.isJSON() || 'extern' in moduleDocBlock) {
           data.dependencies = [];
           data.asyncDependencies = [];
+          data.code = content;
+          return data;
         } else {
-          var dependencies = (this._extractor || extractRequires)(content).deps;
-          data.dependencies = dependencies.sync;
-          data.asyncDependencies = dependencies.async;
+          const transformCode = this._transformCode;
+          const codePromise = transformCode
+              ? transformCode(this, content)
+              : Promise.resolve({code: content});
+
+          return codePromise.then(({code, dependencies, asyncDependencies}) => {
+            const {deps} = this._extractor(code);
+            data.dependencies = dependencies || deps.sync;
+            data.asyncDependencies = asyncDependencies || deps.async;
+            data.code = code;
+            return data;
+          });
         }
-
-        return data;
       });
     }
 
diff --git a/packager/react-packager/src/DependencyResolver/ModuleCache.js b/packager/react-packager/src/DependencyResolver/ModuleCache.js
index a4836d0afb81..fac1820b817e 100644
--- a/packager/react-packager/src/DependencyResolver/ModuleCache.js
+++ b/packager/react-packager/src/DependencyResolver/ModuleCache.js
@@ -7,13 +7,21 @@ const path = require('path');
 
 class ModuleCache {
 
-  constructor(fastfs, cache, extractRequires, depGraphHelpers) {
+  constructor({
+    fastfs,
+    cache,
+    extractRequires,
+    transformCode,
+    depGraphHelpers,
+  }) {
     this._moduleCache = Object.create(null);
     this._packageCache = Object.create(null);
     this._fastfs = fastfs;
     this._cache = cache;
     this._extractRequires = extractRequires;
+    this._transformCode = transformCode;
     this._depGraphHelpers = depGraphHelpers;
+
     fastfs.on('change', this._processFileChange.bind(this));
   }
 
@@ -26,6 +34,7 @@ class ModuleCache {
         moduleCache: this,
         cache: this._cache,
         extractor: this._extractRequires,
+        transformCode: this._transformCode,
         depGraphHelpers: this._depGraphHelpers,
       });
     }
diff --git a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js b/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
index f0c9cbd2358f..947fa0b1c7f1 100644
--- a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
+++ b/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
@@ -26,74 +26,74 @@ const DependencyGraphHelpers = require('../DependencyGraph/DependencyGraphHelper
 const Promise = require('promise');
 const fs = require('graceful-fs');
 
+function mockIndexFile(indexJs) {
+  fs.__setMockFilesystem({'root': {'index.js': indexJs}});
+}
+
 describe('Module', () => {
   const fileWatcher = {
     on: () =>  this,
     isWatchman: () => Promise.resolve(false),
   };
+  const fileName = '/root/index.js';
+
+  let cache, fastfs;
+
+  const createCache = () => ({
+    get: jest.genMockFn().mockImplementation(
+      (filepath, field, cb) => cb(filepath)
+    ),
+    invalidate: jest.genMockFn(),
+    end: jest.genMockFn(),
+  });
+
+  const createModule = (options) =>
+    new Module({
+      cache,
+      fastfs,
+      file: fileName,
+      depGraphHelpers: new DependencyGraphHelpers(),
+      moduleCache: new ModuleCache({fastfs, cache}),
+      ...options,
+    });
 
-  const Cache = jest.genMockFn();
-  Cache.prototype.get = jest.genMockFn().mockImplementation(
-    (filepath, field, cb) => cb(filepath)
-  );
-  Cache.prototype.invalidate = jest.genMockFn();
-  Cache.prototype.end = jest.genMockFn();
+  beforeEach(function(done) {
+    cache = createCache();
+    fastfs = new Fastfs(
+      'test',
+      ['/root'],
+      fileWatcher,
+      {crawling: Promise.resolve([fileName]), ignore: []},
+    );
 
+    fastfs.build().then(done);
+  });
 
   describe('Async Dependencies', () => {
     function expectAsyncDependenciesToEqual(expected) {
-      const fastfs = new Fastfs(
-        'test',
-        ['/root'],
-        fileWatcher,
-        {crawling: Promise.resolve(['/root/index.js']), ignore: []},
+      const module = createModule();
+      return module.getAsyncDependencies().then(actual =>
+        expect(actual).toEqual(expected)
       );
-      const cache = new Cache();
-
-      return fastfs.build().then(() => {
-        const module = new Module({
-          file: '/root/index.js',
-          fastfs,
-          moduleCache: new ModuleCache(fastfs, cache),
-          cache: cache,
-          depGraphHelpers: new DependencyGraphHelpers(),
-        });
-
-        return module.getAsyncDependencies().then(actual =>
-          expect(actual).toEqual(expected)
-        );
-      });
     }
 
     pit('should recognize single dependency', () => {
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': 'System.' + 'import("dep1")',
-        },
-      });
+      mockIndexFile('System.' + 'import("dep1")');
 
       return expectAsyncDependenciesToEqual([['dep1']]);
     });
 
     pit('should parse single quoted dependencies', () => {
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': 'System.' + 'import(\'dep1\')',
-        },
-      });
+      mockIndexFile('System.' + 'import(\'dep1\')');
 
       return expectAsyncDependenciesToEqual([['dep1']]);
     });
 
     pit('should parse multiple async dependencies on the same module', () => {
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            'System.' + 'import("dep1")',
-            'System.' + 'import("dep2")',
-          ].join('\n'),
-        },
-      });
+      mockIndexFile([
+        'System.' + 'import("dep1")',
+        'System.' + 'import("dep2")',
+      ].join('\n'));
 
       return expectAsyncDependenciesToEqual([
         ['dep1'],
@@ -102,53 +102,125 @@ describe('Module', () => {
     });
 
     pit('parse fine new lines', () => {
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': 'System.' + 'import(\n"dep1"\n)',
-        },
-      });
+      mockIndexFile('System.' + 'import(\n"dep1"\n)');
 
       return expectAsyncDependenciesToEqual([['dep1']]);
     });
   });
 
+  describe('Code', () => {
+    const fileContents = 'arbitrary(code)';
+    beforeEach(function() {
+      mockIndexFile(fileContents);
+    });
+
+    pit('exposes file contents as `code` property on the data exposed by `read()`', () =>
+      createModule().read().then(({code}) =>
+        expect(code).toBe(fileContents))
+    );
+
+    pit('exposes file contes via the `getCode()` method', () =>
+      createModule().getCode().then(code =>
+        expect(code).toBe(fileContents))
+    );
+
+    pit('does not save the code in the cache', () =>
+      createModule().getCode().then(() =>
+        expect(cache.get).not.toBeCalled()
+      )
+    );
+  });
+
   describe('Extrators', () => {
 
-    function createModuleWithExtractor(extractor) {
-      const fastfs = new Fastfs(
-        'test',
-        ['/root'],
-        fileWatcher,
-        {crawling: Promise.resolve(['/root/index.js']), ignore: []},
-      );
-      const cache = new Cache();
-
-      return fastfs.build().then(() => {
-        return new Module({
-          file: '/root/index.js',
-          fastfs,
-          moduleCache: new ModuleCache(fastfs, cache),
-          cache,
-          extractor,
-          depGraphHelpers: new DependencyGraphHelpers(),
+    pit('uses custom require extractors if specified', () => {
+      mockIndexFile('');
+      const module = createModule({
+        extractor: code => ({deps: {sync: ['foo', 'bar']}}),
+      });
+
+      return module.getDependencies().then(actual =>
+        expect(actual).toEqual(['foo', 'bar']));
+    });
+  });
+
+  describe('Custom Code Transform', () => {
+    let transformCode;
+    const fileContents = 'arbitrary(code);';
+    const exampleCode = `
+      require('a');
+      System.import('b');
+      require('c');`;
+
+    beforeEach(function() {
+      transformCode = jest.genMockFn();
+      mockIndexFile(fileContents);
+      transformCode.mockReturnValue(Promise.resolve({code: ''}));
+    });
+
+    pit('passes the module and file contents to the transform function when reading', () => {
+      const module = createModule({transformCode});
+      return module.read()
+        .then(() => {
+          expect(transformCode).toBeCalledWith(module, fileContents);
         });
+    });
+
+    pit('uses the code that `transformCode` resolves to to extract dependencies', () => {
+      transformCode.mockReturnValue(Promise.resolve({code: exampleCode}));
+      const module = createModule({transformCode});
+
+      return Promise.all([
+        module.getDependencies(),
+        module.getAsyncDependencies(),
+      ]).then(([dependencies, asyncDependencies]) => {
+        expect(dependencies).toEqual(['a', 'c']);
+        expect(asyncDependencies).toEqual([['b']]);
       });
-    }
+    });
 
-    pit('uses custom require extractors if specified', () => {
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': '',
-        },
+    pit('uses dependencies that `transformCode` resolves to, instead of extracting them', () => {
+      const mockedDependencies = ['foo', 'bar'];
+      transformCode.mockReturnValue(Promise.resolve({
+        code: exampleCode,
+        dependencies: mockedDependencies,
+      }));
+      const module = createModule({transformCode});
+
+      return Promise.all([
+        module.getDependencies(),
+        module.getAsyncDependencies(),
+      ]).then(([dependencies, asyncDependencies]) => {
+        expect(dependencies).toEqual(mockedDependencies);
+        expect(asyncDependencies).toEqual([['b']]);
       });
+    });
 
-      return createModuleWithExtractor(
-        code => ({deps: {sync: ['foo', 'bar']}})
-      ).then(module =>
-        module.getDependencies().then(actual =>
-          expect(actual).toEqual(['foo', 'bar'])
-        )
-      );
+    pit('uses async dependencies that `transformCode` resolves to, instead of extracting them', () => {
+      const mockedAsyncDependencies = [['foo', 'bar'], ['baz']];
+      transformCode.mockReturnValue(Promise.resolve({
+        code: exampleCode,
+        asyncDependencies: mockedAsyncDependencies,
+      }));
+      const module = createModule({transformCode});
+
+      return Promise.all([
+        module.getDependencies(),
+        module.getAsyncDependencies(),
+      ]).then(([dependencies, asyncDependencies]) => {
+        expect(dependencies).toEqual(['a', 'c']);
+        expect(asyncDependencies).toEqual(mockedAsyncDependencies);
+      });
+    });
+
+    pit('exposes the transformed code rather than the raw file contents', () => {
+      transformCode.mockReturnValue(Promise.resolve({code: exampleCode}));
+      const module = createModule({transformCode});
+      return Promise.all([module.read(), module.getCode()])
+        .then(([data, code]) => {
+          expect(data.code).toBe(exampleCode);
+          expect(code).toBe(exampleCode);
+        });
     });
   });
 });

From 0b39c72bfa9ae5fe6ce9b3bb35a0eec4c7030bc8 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Thu, 28 Jan 2016 16:35:56 -0800
Subject: [PATCH 0920/1411] Fix bundler to not do as many passes in
 optimization

Reviewed By: davidaurelio

Differential Revision: D2876894

fb-gh-sync-id: b652ff77dd442a82c16f3b446c931fb985a2efcd
---
 .../whole-program-optimisations/dead-module-elimination.js    | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/packager/react-packager/src/transforms/whole-program-optimisations/dead-module-elimination.js b/packager/react-packager/src/transforms/whole-program-optimisations/dead-module-elimination.js
index 1d6c8f340f38..b5f33b4e09be 100644
--- a/packager/react-packager/src/transforms/whole-program-optimisations/dead-module-elimination.js
+++ b/packager/react-packager/src/transforms/whole-program-optimisations/dead-module-elimination.js
@@ -135,10 +135,12 @@ module.exports = function () {
     visitor: {
       Program(path) {
         path.traverse(firstPass);
-        while (hasDeadModules(requires)) {
+        var counter = 0;
+        while (hasDeadModules(requires) && counter < 3) {
           _requires = requires;
           requires = {};
           path.traverse(secondPass);
+          counter++;
         }
       }
     }

From 0c0bd533f5ec063dbfe964c5a3795d1035ff32f5 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Fri, 29 Jan 2016 01:48:48 +0100
Subject: [PATCH 0921/1411] Remove dummy .so file

---
 ReactAndroid/src/main/jni/prebuilt/lib/android-armv7/libdummy.so | 1 -
 1 file changed, 1 deletion(-)
 delete mode 100644 ReactAndroid/src/main/jni/prebuilt/lib/android-armv7/libdummy.so

diff --git a/ReactAndroid/src/main/jni/prebuilt/lib/android-armv7/libdummy.so b/ReactAndroid/src/main/jni/prebuilt/lib/android-armv7/libdummy.so
deleted file mode 100644
index 1f3fe3afa071..000000000000
--- a/ReactAndroid/src/main/jni/prebuilt/lib/android-armv7/libdummy.so
+++ /dev/null
@@ -1 +0,0 @@
-Just a dummy file to double check it won't get exported to github.
\ No newline at end of file

From 181896e4d95982aaf22d4c67fe0ef3158d2ecf37 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Thu, 28 Jan 2016 17:02:02 -0800
Subject: [PATCH 0922/1411] Move HMR to external transformer

Summary:
public

`babel-plugin-react-transform` doesn't support to run on transformed code (it doesn't detect some react components). The reason why HMR was originally on the internal transform was so that it worked with non JS code (TypeScript, Coffeescript, etc), but looks like this is not very popupar in the community, maybe because the JS ecosystem is getting better everyday.

So long story short, for now lets move HMR to the external transformer. This should also give us a perf boost.

Reviewed By: davidaurelio

Differential Revision: D2870973

fb-gh-sync-id: 68ca8d0540b88b9516b9fef10643f93fc9b530d2
---
 .../JSTransformer/__tests__/worker-test.js    |  6 +++---
 .../react-packager/src/transforms/index.js    | 21 +------------------
 packager/transformer.js                       | 12 +++++++++++
 3 files changed, 16 insertions(+), 23 deletions(-)

diff --git a/packager/react-packager/src/JSTransformer/__tests__/worker-test.js b/packager/react-packager/src/JSTransformer/__tests__/worker-test.js
index fdb67d9d464d..f81907c2c8e0 100644
--- a/packager/react-packager/src/JSTransformer/__tests__/worker-test.js
+++ b/packager/react-packager/src/JSTransformer/__tests__/worker-test.js
@@ -23,7 +23,7 @@ describe('Resolver', function() {
   });
 
   describe('when no external transform is provided', () => {
-    it('should invoke internal transform if available', () => {
+    xit('should invoke internal transform if available', () => {
       transform({
         sourceCode: 'code',
         filename: 'test',
@@ -43,7 +43,7 @@ describe('Resolver', function() {
   });
 
   describe('when external transform is provided', () => {
-    it('should invoke both transformers if internal is available', () => {
+    xit('should invoke both transformers if internal is available', () => {
       transform({
         sourceCode: code,
         filename: 'test',
@@ -75,7 +75,7 @@ describe('Resolver', function() {
       expect(babel.transform.mock.calls.length).toBe(1);
     });
 
-    it('should pipe errors through transform pipeline', () => {
+    xit('should pipe errors through transform pipeline', () => {
       const error = new Error('transform error');
       babel.transform.mockImpl((source, options) => {
         throw error;
diff --git a/packager/react-packager/src/transforms/index.js b/packager/react-packager/src/transforms/index.js
index 33cb24622d1d..37f17ccd1a9e 100644
--- a/packager/react-packager/src/transforms/index.js
+++ b/packager/react-packager/src/transforms/index.js
@@ -9,25 +9,6 @@
 'use strict';
 
 exports.getAll = function(options) {
-  var plugins = [];
-  if (options.hot) {
-    plugins = plugins.concat([
-      [
-        'react-transform',
-        {
-          transforms: [{
-            transform: 'react-transform-hmr/lib/index.js',
-            imports: ['React'],
-            locals: ['module'],
-          }]
-        },
-      ],
-      'transform-es2015-block-scoping',
-      'transform-es2015-constants',
-      ['transform-es2015-modules-commonjs', {strict: false, allowTopLevelThis: true}],
-    ]);
-  }
-
-  return plugins;
+  return [];
 };
 
diff --git a/packager/transformer.js b/packager/transformer.js
index df6009bd7f81..a38fdb0db5d9 100644
--- a/packager/transformer.js
+++ b/packager/transformer.js
@@ -33,6 +33,18 @@ function transform(src, filename, options) {
   };
 
   const config = Object.assign({}, babelRC, extraConfig);
+  if (options.hot) {
+    extraPlugins.push([
+      'react-transform',
+      {
+        transforms: [{
+          transform: 'react-transform-hmr/lib/index.js',
+          imports: ['React'],
+          locals: ['module'],
+        }]
+      },
+    ]);
+  }
 
   if (options.inlineRequires) {
     extraPlugins.push(inlineRequires);

From 203fdcaa40e34458683eb214bce104260a6b8819 Mon Sep 17 00:00:00 2001
From: Ahmed El-Helw <ahmedre@fb.com>
Date: Thu, 28 Jan 2016 17:06:17 -0800
Subject: [PATCH 0923/1411] Support fade for remote images in React with nodes.

Reviewed By: dkoroskin

Differential Revision: D2804997

fb-gh-sync-id: e143fc16c07856e56182cba6d0eb2884a95c7318
---
 .../java/com/facebook/react/views/image/ReactImageView.java | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
index c627bdc6ebd3..be57d799d337 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
@@ -23,20 +23,20 @@
 import android.graphics.RectF;
 import android.graphics.Shader;
 import android.graphics.drawable.Animatable;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.SystemClock;
 
 import com.facebook.common.util.UriUtil;
 import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
-import com.facebook.drawee.drawable.AutoRotateDrawable;
 import com.facebook.drawee.controller.BaseControllerListener;
 import com.facebook.drawee.controller.ControllerListener;
 import com.facebook.drawee.controller.ForwardingControllerListener;
+import com.facebook.drawee.drawable.AutoRotateDrawable;
 import com.facebook.drawee.drawable.ScalingUtils;
 import com.facebook.drawee.generic.GenericDraweeHierarchy;
 import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
 import com.facebook.drawee.generic.RoundingParams;
-import com.facebook.drawee.interfaces.DraweeController;
 import com.facebook.drawee.view.GenericDraweeView;
 import com.facebook.imagepipeline.common.ResizeOptions;
 import com.facebook.imagepipeline.image.ImageInfo;
@@ -55,7 +55,7 @@
  */
 public class ReactImageView extends GenericDraweeView {
 
-  private static final int REMOTE_IMAGE_FADE_DURATION_MS = 300;
+  public static final int REMOTE_IMAGE_FADE_DURATION_MS = 300;
 
   /*
    * Implementation note re rounded corners:

From 598df0bc201e4a177d51bd3d29a4249b997987df Mon Sep 17 00:00:00 2001
From: Dmitry Soshnikov <dmitrys@fb.com>
Date: Thu, 28 Jan 2016 17:20:39 -0800
Subject: [PATCH 0924/1411] Add Object.entries and Object.values polyfill

Reviewed By: martinbigio

Differential Revision: D2876430

fb-gh-sync-id: 25c7680a71c9187beb937f6faf030a83c9c81fc5
---
 packager/react-packager/src/Resolver/index.js |   1 +
 .../src/Resolver/polyfills/Object.es7.js      |  56 ++++++++
 .../polyfills/__tests__/Object.es7-test.js    | 120 ++++++++++++++++++
 3 files changed, 177 insertions(+)
 create mode 100644 packager/react-packager/src/Resolver/polyfills/Object.es7.js
 create mode 100644 packager/react-packager/src/Resolver/polyfills/__tests__/Object.es7-test.js

diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index 0166681f0b3e..4cb4707f1283 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -157,6 +157,7 @@ class Resolver {
       path.join(__dirname, 'polyfills/String.prototype.es6.js'),
       path.join(__dirname, 'polyfills/Array.prototype.es6.js'),
       path.join(__dirname, 'polyfills/Array.es6.js'),
+      path.join(__dirname, 'polyfills/Object.es7.js'),
       path.join(__dirname, 'polyfills/babelHelpers.js'),
     ].concat(this._polyfillModuleNames);
 
diff --git a/packager/react-packager/src/Resolver/polyfills/Object.es7.js b/packager/react-packager/src/Resolver/polyfills/Object.es7.js
new file mode 100644
index 000000000000..597c49e7fc22
--- /dev/null
+++ b/packager/react-packager/src/Resolver/polyfills/Object.es7.js
@@ -0,0 +1,56 @@
+/**
+ * Copyright 2004-present Facebook. All Rights Reserved.
+ *
+ * @provides Object.es7
+ * @polyfill
+ */
+
+(function() {
+
+  const hasOwnProperty = Object.prototype.hasOwnProperty;
+
+  /**
+   * Returns an array of the given object's own enumerable entries.
+   * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries
+   *
+   */
+  if (typeof Object.entries !== 'function') {
+    Object.entries = function(object) {
+      // `null` and `undefined` values are not allowed.
+      if (object == null) {
+        throw new TypeError('Object.entries called on non-object');
+      }
+
+      let entries = [];
+      for (let key in object) {
+        if (hasOwnProperty.call(object, key)) {
+          entries.push([key, object[key]]);
+        }
+      }
+      return entries;
+    };
+  }
+
+  /**
+   * Returns an array of the given object's own enumerable entries.
+   * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values
+   *
+   */
+  if (typeof Object.values !== 'function') {
+    Object.values = function(object) {
+      // `null` and `undefined` values are not allowed.
+      if (object == null) {
+        throw new TypeError('Object.values called on non-object');
+      }
+
+      let values = [];
+      for (let key in object) {
+        if (hasOwnProperty.call(object, key)) {
+          values.push(object[key]);
+        }
+      }
+      return values;
+    };
+  }
+
+})();
\ No newline at end of file
diff --git a/packager/react-packager/src/Resolver/polyfills/__tests__/Object.es7-test.js b/packager/react-packager/src/Resolver/polyfills/__tests__/Object.es7-test.js
new file mode 100644
index 000000000000..ee7782eb781a
--- /dev/null
+++ b/packager/react-packager/src/Resolver/polyfills/__tests__/Object.es7-test.js
@@ -0,0 +1,120 @@
+/**
+ * Copyright 2004-present Facebook. All Rights Reserved.
+ *
+ * @emails oncall+jsinfra
+ */
+
+ /* eslint-disable fb-www/object-create-only-one-param */
+
+jest.autoMockOff();
+
+describe('Object (ES7)', () => {
+  beforeEach(() => {
+    delete Object.entries;
+    delete Object.values;
+    jest.resetModuleRegistry();
+    require('../Object.es7');
+  });
+
+  describe('Object.entries', () => {
+    it('should have a length of 1', () => {
+      expect(Object.entries.length).toBe(1);
+    });
+
+    it('should check for type', () => {
+      expect(Object.entries.bind(null, null)).toThrow(TypeError(
+        'Object.entries called on non-object'
+      ));
+      expect(Object.entries.bind(null, undefined)).toThrow(TypeError(
+        'Object.entries called on non-object'
+      ));
+      expect(Object.entries.bind(null, [])).not.toThrow();
+      expect(Object.entries.bind(null, () => {})).not.toThrow();
+      expect(Object.entries.bind(null, {})).not.toThrow();
+      expect(Object.entries.bind(null, 'abc')).not.toThrow();
+    });
+
+    it('should return enumerable entries', () => {
+      let foo = Object.defineProperties({}, {
+        x: {value: 10, enumerable: true},
+        y: {value: 20},
+      });
+
+      expect(Object.entries(foo)).toEqual([['x', 10]]);
+
+      let bar = {x: 10, y: 20};
+      expect(Object.entries(bar)).toEqual([['x', 10], ['y', 20]]);
+    });
+
+    it('should work with proto-less objects', () => {
+      let foo = Object.create(null, {
+        x: {value: 10, enumerable: true},
+        y: {value: 20},
+      });
+
+      expect(Object.entries(foo)).toEqual([['x', 10]]);
+    });
+
+    it('should return only own entries', () => {
+      let foo = Object.create({z: 30}, {
+        x: {value: 10, enumerable: true},
+        y: {value: 20},
+      });
+
+      expect(Object.entries(foo)).toEqual([['x', 10]]);
+    });
+
+    it('should convert to object primitive string', () => {
+      expect(Object.entries('ab')).toEqual([['0', 'a'], ['1', 'b']]);
+    });
+  });
+
+  describe('Object.values', () => {
+    it('should have a length of 1', () => {
+      expect(Object.values.length).toBe(1);
+    });
+
+    it('should check for type', () => {
+      expect(Object.values.bind(null, null)).toThrow(TypeError(
+        'Object.values called on non-object'
+      ));
+      expect(Object.values.bind(null, [])).not.toThrow();
+      expect(Object.values.bind(null, () => {})).not.toThrow();
+      expect(Object.values.bind(null, {})).not.toThrow();
+    });
+
+    it('should return enumerable values', () => {
+      let foo = Object.defineProperties({}, {
+        x: {value: 10, enumerable: true},
+        y: {value: 20},
+      });
+
+      expect(Object.values(foo)).toEqual([10]);
+
+      let bar = {x: 10, y: 20};
+      expect(Object.values(bar)).toEqual([10, 20]);
+    });
+
+    it('should work with proto-less objects', () => {
+      let foo = Object.create(null, {
+        x: {value: 10, enumerable: true},
+        y: {value: 20},
+      });
+
+      expect(Object.values(foo)).toEqual([10]);
+    });
+
+    it('should return only own values', () => {
+      let foo = Object.create({z: 30}, {
+        x: {value: 10, enumerable: true},
+        y: {value: 20},
+      });
+
+      expect(Object.values(foo)).toEqual([10]);
+    });
+
+    it('should convert to object primitive string', () => {
+      expect(Object.values('ab')).toEqual(['a', 'b']);
+    });
+  });
+});
\ No newline at end of file

From 7e5247c041cbf6a302f9392f87f1897aa83c31dd Mon Sep 17 00:00:00 2001
From: Andrei Coman <andreic@fb.com>
Date: Thu, 28 Jan 2016 18:55:02 -0800
Subject: [PATCH 0925/1411] Fix timing initialization bug

Reviewed By: AaaChiuuu

Differential Revision: D2875476

fb-gh-sync-id: a0d5b97524da3a37fc7bd30e8d2e58b9a0a9ba9e
---
 .../main/java/com/facebook/react/modules/core/Timing.java | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java b/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java
index a29b2632b479..36954a125f86 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java
@@ -18,16 +18,15 @@
 import android.util.SparseArray;
 import android.view.Choreographer;
 
+import com.facebook.infer.annotation.Assertions;
 import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.LifecycleEventListener;
 import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReactContextBaseJavaModule;
 import com.facebook.react.bridge.ReactMethod;
-import com.facebook.react.bridge.LifecycleEventListener;
 import com.facebook.react.bridge.WritableArray;
-import com.facebook.react.uimanager.ReactChoreographer;
 import com.facebook.react.common.SystemClock;
-import com.facebook.infer.annotation.Assertions;
+import com.facebook.react.uimanager.ReactChoreographer;
 
 /**
  * Native module for JS timer execution. Timers fire on frame boundaries.
@@ -124,7 +123,6 @@ public void initialize() {
     mJSTimersModule = getReactApplicationContext().getCatalystInstance()
         .getJSModule(JSTimersExecution.class);
     getReactApplicationContext().addLifecycleEventListener(this);
-    setChoreographerCallback();
   }
 
   @Override

From 1154f2a371e9489ccc1e6a5ec24a1de2b79a9b73 Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeux@fb.com>
Date: Thu, 28 Jan 2016 19:36:54 -0800
Subject: [PATCH 0926/1411] Document colors

Summary:
<img width="601" alt="screen shot 2016-01-27 at 3 37 22 pm" src="https://cloud.githubusercontent.com/assets/197597/12632329/12084e98-c50c-11e5-96c4-4f56e8219b3b.png">

<img width="303" alt="screen shot 2016-01-27 at 3 37 16 pm" src="https://cloud.githubusercontent.com/assets/197597/12632328/12075e70-c50c-11e5-95a3-5f483b4dcb47.png">

<img width="135" alt="screen shot 2016-01-27 at 3 37 38 pm" src="https://cloud.githubusercontent.com/assets/197597/12632327/12067668-c50c-11e5-92f9-ee0c719302b5.png">
Closes https://github.com/facebook/react-native/pull/5587

Reviewed By: svcscm

Differential Revision: D2878110

Pulled By: vjeux

fb-gh-sync-id: 00330e2857b07aac2e3d3c24f1003cdd9a2516c6
---
 docs/Colors.md                                | 171 ++++++++++++++++++
 docs/Timers.md                                |   1 +
 website/core/Marked.js                        |   7 +
 website/layout/AutodocsLayout.js              |   3 +
 website/src/react-native/css/react-native.css |  20 ++
 5 files changed, 202 insertions(+)
 create mode 100644 docs/Colors.md

diff --git a/docs/Colors.md b/docs/Colors.md
new file mode 100644
index 000000000000..d1036c65bb1e
--- /dev/null
+++ b/docs/Colors.md
@@ -0,0 +1,171 @@
+---
+id: colors
+title: Colors
+layout: docs
+category: Polyfills
+permalink: docs/colors.html
+---
+
+The following formats are supported:
+
+ - `#f0f` (#rgb)
+ - `#f0fc` (#rgba)
+ - `#ff00ff` (#rrggbb)
+ - `#ff00ff00` (#rrggbbaa)
+ - `rgb(255, 255, 255)`
+ - `rgba(255, 255, 255, 1.0)`
+ - `hsl(360, 100%, 100%)`
+ - `hsla(360, 100%, 100%, 1.0)`
+ - `transparent`
+ - `red`
+
+For the named colors, React Native follows the [CSS3 specification](http://www.w3.org/TR/css3-color/#svg-color):
+
+- <color aliceblue /> aliceblue (#f0f8ff)
+- <color antiquewhite /> antiquewhite (#faebd7)
+- <color aqua /> aqua (#00ffff)
+- <color aquamarine /> aquamarine (#7fffd4)
+- <color azure /> azure (#f0ffff)
+- <color beige /> beige (#f5f5dc)
+- <color bisque /> bisque (#ffe4c4)
+- <color black /> black (#000000)
+- <color blanchedalmond /> blanchedalmond (#ffebcd)
+- <color blue /> blue (#0000ff)
+- <color blueviolet /> blueviolet (#8a2be2)
+- <color brown /> brown (#a52a2a)
+- <color burlywood /> burlywood (#deb887)
+- <color cadetblue /> cadetblue (#5f9ea0)
+- <color chartreuse /> chartreuse (#7fff00)
+- <color chocolate /> chocolate (#d2691e)
+- <color coral /> coral (#ff7f50)
+- <color cornflowerblue /> cornflowerblue (#6495ed)
+- <color cornsilk /> cornsilk (#fff8dc)
+- <color crimson /> crimson (#dc143c)
+- <color cyan /> cyan (#00ffff)
+- <color darkblue /> darkblue (#00008b)
+- <color darkcyan /> darkcyan (#008b8b)
+- <color darkgoldenrod /> darkgoldenrod (#b8860b)
+- <color darkgray /> darkgray (#a9a9a9)
+- <color darkgreen /> darkgreen (#006400)
+- <color darkgrey /> darkgrey (#a9a9a9)
+- <color darkkhaki /> darkkhaki (#bdb76b)
+- <color darkmagenta /> darkmagenta (#8b008b)
+- <color darkolivegreen /> darkolivegreen (#556b2f)
+- <color darkorange /> darkorange (#ff8c00)
+- <color darkorchid /> darkorchid (#9932cc)
+- <color darkred /> darkred (#8b0000)
+- <color darksalmon /> darksalmon (#e9967a)
+- <color darkseagreen /> darkseagreen (#8fbc8f)
+- <color darkslateblue /> darkslateblue (#483d8b)
+- <color darkslategray /> darkslategray (#2f4f4f)
+- <color darkslategrey /> darkslategrey (#2f4f4f)
+- <color darkturquoise /> darkturquoise (#00ced1)
+- <color darkviolet /> darkviolet (#9400d3)
+- <color deeppink /> deeppink (#ff1493)
+- <color deepskyblue /> deepskyblue (#00bfff)
+- <color dimgray /> dimgray (#696969)
+- <color dimgrey /> dimgrey (#696969)
+- <color dodgerblue /> dodgerblue (#1e90ff)
+- <color firebrick /> firebrick (#b22222)
+- <color floralwhite /> floralwhite (#fffaf0)
+- <color forestgreen /> forestgreen (#228b22)
+- <color fuchsia /> fuchsia (#ff00ff)
+- <color gainsboro /> gainsboro (#dcdcdc)
+- <color ghostwhite /> ghostwhite (#f8f8ff)
+- <color gold /> gold (#ffd700)
+- <color goldenrod /> goldenrod (#daa520)
+- <color gray /> gray (#808080)
+- <color green /> green (#008000)
+- <color greenyellow /> greenyellow (#adff2f)
+- <color grey /> grey (#808080)
+- <color honeydew /> honeydew (#f0fff0)
+- <color hotpink /> hotpink (#ff69b4)
+- <color indianred /> indianred (#cd5c5c)
+- <color indigo /> indigo (#4b0082)
+- <color ivory /> ivory (#fffff0)
+- <color khaki /> khaki (#f0e68c)
+- <color lavender /> lavender (#e6e6fa)
+- <color lavenderblush /> lavenderblush (#fff0f5)
+- <color lawngreen /> lawngreen (#7cfc00)
+- <color lemonchiffon /> lemonchiffon (#fffacd)
+- <color lightblue /> lightblue (#add8e6)
+- <color lightcoral /> lightcoral (#f08080)
+- <color lightcyan /> lightcyan (#e0ffff)
+- <color lightgoldenrodyellow /> lightgoldenrodyellow (#fafad2)
+- <color lightgray /> lightgray (#d3d3d3)
+- <color lightgreen /> lightgreen (#90ee90)
+- <color lightgrey /> lightgrey (#d3d3d3)
+- <color lightpink /> lightpink (#ffb6c1)
+- <color lightsalmon /> lightsalmon (#ffa07a)
+- <color lightseagreen /> lightseagreen (#20b2aa)
+- <color lightskyblue /> lightskyblue (#87cefa)
+- <color lightslategray /> lightslategray (#778899)
+- <color lightslategrey /> lightslategrey (#778899)
+- <color lightsteelblue /> lightsteelblue (#b0c4de)
+- <color lightyellow /> lightyellow (#ffffe0)
+- <color lime /> lime (#00ff00)
+- <color limegreen /> limegreen (#32cd32)
+- <color linen /> linen (#faf0e6)
+- <color magenta /> magenta (#ff00ff)
+- <color maroon /> maroon (#800000)
+- <color mediumaquamarine /> mediumaquamarine (#66cdaa)
+- <color mediumblue /> mediumblue (#0000cd)
+- <color mediumorchid /> mediumorchid (#ba55d3)
+- <color mediumpurple /> mediumpurple (#9370db)
+- <color mediumseagreen /> mediumseagreen (#3cb371)
+- <color mediumslateblue /> mediumslateblue (#7b68ee)
+- <color mediumspringgreen /> mediumspringgreen (#00fa9a)
+- <color mediumturquoise /> mediumturquoise (#48d1cc)
+- <color mediumvioletred /> mediumvioletred (#c71585)
+- <color midnightblue /> midnightblue (#191970)
+- <color mintcream /> mintcream (#f5fffa)
+- <color mistyrose /> mistyrose (#ffe4e1)
+- <color moccasin /> moccasin (#ffe4b5)
+- <color navajowhite /> navajowhite (#ffdead)
+- <color navy /> navy (#000080)
+- <color oldlace /> oldlace (#fdf5e6)
+- <color olive /> olive (#808000)
+- <color olivedrab /> olivedrab (#6b8e23)
+- <color orange /> orange (#ffa500)
+- <color orangered /> orangered (#ff4500)
+- <color orchid /> orchid (#da70d6)
+- <color palegoldenrod /> palegoldenrod (#eee8aa)
+- <color palegreen /> palegreen (#98fb98)
+- <color paleturquoise /> paleturquoise (#afeeee)
+- <color palevioletred /> palevioletred (#db7093)
+- <color papayawhip /> papayawhip (#ffefd5)
+- <color peachpuff /> peachpuff (#ffdab9)
+- <color peru /> peru (#cd853f)
+- <color pink /> pink (#ffc0cb)
+- <color plum /> plum (#dda0dd)
+- <color powderblue /> powderblue (#b0e0e6)
+- <color purple /> purple (#800080)
+- <color rebeccapurple /> rebeccapurple (#663399)
+- <color red /> red (#ff0000)
+- <color rosybrown /> rosybrown (#bc8f8f)
+- <color royalblue /> royalblue (#4169e1)
+- <color saddlebrown /> saddlebrown (#8b4513)
+- <color salmon /> salmon (#fa8072)
+- <color sandybrown /> sandybrown (#f4a460)
+- <color seagreen /> seagreen (#2e8b57)
+- <color seashell /> seashell (#fff5ee)
+- <color sienna /> sienna (#a0522d)
+- <color silver /> silver (#c0c0c0)
+- <color skyblue /> skyblue (#87ceeb)
+- <color slateblue /> slateblue (#6a5acd)
+- <color slategray /> slategray (#708090)
+- <color slategrey /> slategrey (#708090)
+- <color snow /> snow (#fffafa)
+- <color springgreen /> springgreen (#00ff7f)
+- <color steelblue /> steelblue (#4682b4)
+- <color tan /> tan (#d2b48c)
+- <color teal /> teal (#008080)
+- <color thistle /> thistle (#d8bfd8)
+- <color tomato /> tomato (#ff6347)
+- <color turquoise /> turquoise (#40e0d0)
+- <color violet /> violet (#ee82ee)
+- <color wheat /> wheat (#f5deb3)
+- <color white /> white (#ffffff)
+- <color whitesmoke /> whitesmoke (#f5f5f5)
+- <color yellow /> yellow (#ffff00)
+- <color yellowgreen /> yellowgreen (#9acd32)
diff --git a/docs/Timers.md b/docs/Timers.md
index 9f8e2ace0001..d4a9396decee 100644
--- a/docs/Timers.md
+++ b/docs/Timers.md
@@ -4,6 +4,7 @@ title: Timers
 layout: docs
 category: Polyfills
 permalink: docs/timers.html
+next: colors
 ---
 
 Timers are an important part of an application and React Native implements the [browser timers](https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Timers).
diff --git a/website/core/Marked.js b/website/core/Marked.js
index e8608e995200..7d3fa4626449 100644
--- a/website/core/Marked.js
+++ b/website/core/Marked.js
@@ -595,6 +595,13 @@ InlineLexer.prototype.output = function(src) {
     // tag
     if (cap = this.rules.tag.exec(src)) {
       src = src.substring(cap[0].length);
+
+      var color = cap[0].match('<color ([^ ]+) />');
+      if (color) {
+        out.push(React.DOM.span({className: 'color', style: {backgroundColor: color[1]}}));
+        continue;
+      }
+
       // TODO(alpert): Don't escape if sanitize is false
       out.push(cap[0]);
       continue;
diff --git a/website/layout/AutodocsLayout.js b/website/layout/AutodocsLayout.js
index d3b2234492e0..c3715522a831 100644
--- a/website/layout/AutodocsLayout.js
+++ b/website/layout/AutodocsLayout.js
@@ -57,6 +57,9 @@ function renderType(type) {
       var name = type.raw.substring(0, type.raw.indexOf('.'));
       return <a href={slugify(name) + '.html#style'}>{name}#style</a>
     }
+    if (type.raw === 'ColorPropType') {
+      return <a href={'colors.html'}>color</a>
+    }
     if (type.raw === 'EdgeInsetsPropType') {
       return '{top: number, left: number, bottom: number, right: number}';
     }
diff --git a/website/src/react-native/css/react-native.css b/website/src/react-native/css/react-native.css
index 05e541bb9d83..41b347369046 100644
--- a/website/src/react-native/css/react-native.css
+++ b/website/src/react-native/css/react-native.css
@@ -1076,6 +1076,26 @@ div[data-twttr-id] iframe {
   -ms-user-select: none;
 }
 
+.color {
+  display: inline-block;
+  width: 20px;
+  height: 20px;
+  margin-right: 5px;
+  position: relative;
+  top: 5px;
+}
+
+.color::before {
+  content: '';
+  display: block;
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  border: 1px solid rgba(0, 0, 0, 0.2);
+}
+
 .edit-github {
   font-size: 15px;
   font-weight: normal;

From 54e50332211c7495bee169dff27c74a4b43d5904 Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeuxx@gmail.com>
Date: Thu, 28 Jan 2016 20:13:32 -0800
Subject: [PATCH 0927/1411] More helpful description for native-js prop
 mismatch

Summary:
A lot of people see this error and end up posting in our support group. The root cause is that their js and native versions are out of sync. Adding a helpful description here will unblock them on their own.
Closes https://github.com/facebook/react-native/pull/5605

Reviewed By: svcscm

Differential Revision: D2878376

Pulled By: martinbigio

fb-gh-sync-id: 10dedbdbb4bee3fce5119367223ebb42a3c1b6a4
---
 Libraries/ReactIOS/verifyPropTypes.js | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Libraries/ReactIOS/verifyPropTypes.js b/Libraries/ReactIOS/verifyPropTypes.js
index 1974716ba260..07432eacb58b 100644
--- a/Libraries/ReactIOS/verifyPropTypes.js
+++ b/Libraries/ReactIOS/verifyPropTypes.js
@@ -50,6 +50,9 @@ function verifyPropTypes(
         viewConfig.uiViewClassName + '.' + prop + '` of native type `' +
         nativeProps[prop] + '`';
       };
+      message += '\nIf you haven\'t changed this prop yourself, this usually means that ' +
+        'your versions of the native code and JavaScript code are out of sync. Updating both ' +
+        'should make this error go away.';
       throw new Error(message);
     }
   }

From 2d9876dedfb24a27d9eb0dafd8463beefcbb3aaf Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Thu, 28 Jan 2016 21:18:10 -0800
Subject: [PATCH 0928/1411] Add partial reading of files to fastfs

Summary:
public

Adds the ability to read files partially with `readWhile` to `Fastfs`
This feature will be used by for building the haste map, where we only need to read the doc block (if present) to extract the provided module name.

Reviewed By: martinbigio

Differential Revision: D2878093

fb-gh-sync-id: 219cf6d5962b89eeb42c728e176bf9fcf6a67e9c
---
 .../DependencyResolver/__tests__/fastfs-data  | 39 +++++++++
 .../__tests__/fastfs-integrated-test.js       | 86 +++++++++++++++++++
 .../src/DependencyResolver/fastfs.js          | 47 ++++++++++
 3 files changed, 172 insertions(+)
 create mode 100644 packager/react-packager/src/DependencyResolver/__tests__/fastfs-data
 create mode 100644 packager/react-packager/src/DependencyResolver/__tests__/fastfs-integrated-test.js

diff --git a/packager/react-packager/src/DependencyResolver/__tests__/fastfs-data b/packager/react-packager/src/DependencyResolver/__tests__/fastfs-data
new file mode 100644
index 000000000000..fe2c6388532b
--- /dev/null
+++ b/packager/react-packager/src/DependencyResolver/__tests__/fastfs-data
@@ -0,0 +1,39 @@
+/**
+ * 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.
+ * An arbitrary module header
+ * @providesModule
+ */
+
+ const some: string = 'arbitrary code';
+ const containing: string = 'ūñïčødę';
+
+/**
+ * An arbitrary class that extends some thing
+ * It exposes a random number, which may be reset at the callers discretion
+ */
+class Arbitrary extends Something {
+  constructor() {
+    this.reset();
+  }
+
+  /**
+   * Returns the random number
+   * @returns number
+   */
+  get random(): number {
+    return this._random;
+  }
+
+  /**
+   * Re-creates the internal random number
+   * @returns void
+   */
+  reset(): void {
+    this._random = Math.random();
+  }
+}
diff --git a/packager/react-packager/src/DependencyResolver/__tests__/fastfs-integrated-test.js b/packager/react-packager/src/DependencyResolver/__tests__/fastfs-integrated-test.js
new file mode 100644
index 000000000000..f7fb3558820c
--- /dev/null
+++ b/packager/react-packager/src/DependencyResolver/__tests__/fastfs-integrated-test.js
@@ -0,0 +1,86 @@
+/**
+ * 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.
+ */
+'use strict';
+
+jest.autoMockOff();
+
+const Fastfs = require('../fastfs');
+
+const {EventEmitter} = require('events');
+const fs = require('fs');
+const path = require('path');
+
+const fileName = path.resolve(__dirname, 'fastfs-data');
+const contents = fs.readFileSync(fileName, 'utf-8');
+
+describe('fastfs:', function() {
+  let fastfs;
+  const crawling = Promise.resolve([fileName]);
+  const roots = [__dirname];
+  const watcher = new EventEmitter();
+
+  beforeEach(function(done) {
+    fastfs = new Fastfs('arbitrary', roots, watcher, {crawling});
+    fastfs.build().then(done);
+  });
+
+  describe('partial reading', () => {
+    // these are integrated tests that read real files from disk
+
+    pit('reads a file while a predicate returns true', function() {
+      return fastfs.readWhile(fileName, () => true).then(readContent =>
+        expect(readContent).toEqual(contents)
+      );
+    });
+
+    pit('invokes the predicate with the new chunk, the invocation index, and the result collected so far', () => {
+      const predicate = jest.genMockFn().mockReturnValue(true);
+      return fastfs.readWhile(fileName, predicate).then(() => {
+        let aggregated = '';
+        const {calls} = predicate.mock;
+        expect(calls).not.toEqual([]);
+
+        calls.forEach((call, i) => {
+          const [chunk] = call;
+          aggregated += chunk;
+          expect(chunk).not.toBe('');
+          expect(call).toEqual([chunk, i, aggregated]);
+        });
+
+        expect(aggregated).toEqual(contents);
+      });
+    });
+
+    pit('stops reading when the predicate returns false', () => {
+      const predicate = jest.genMockFn().mockImpl((_, i) => i !== 0);
+      return fastfs.readWhile(fileName, predicate).then((readContent) => {
+        const {calls} = predicate.mock;
+        expect(calls.length).toBe(1);
+        expect(readContent).toBe(calls[0][2]);
+      });
+    });
+
+    pit('after reading the whole file with `readWhile`, `read()` still works', () => {
+      // this test allows to reuse the results of `readWhile` for `readFile`
+      return fastfs.readWhile(fileName, () => true).then(() => {
+        fastfs.readFile(fileName).then(readContent =>
+          expect(readContent).toEqual(contents)
+        );
+      });
+    });
+
+    pit('after reading parts of the file with `readWhile`, `read()` still works', () => {
+      return fastfs.readWhile(fileName, () => false).then(() => {
+        fastfs.readFile(fileName).then(readContent =>
+          expect(readContent).toEqual(contents)
+        );
+      });
+    });
+  });
+});
diff --git a/packager/react-packager/src/DependencyResolver/fastfs.js b/packager/react-packager/src/DependencyResolver/fastfs.js
index ca01b86c8964..f33b9927851e 100644
--- a/packager/react-packager/src/DependencyResolver/fastfs.js
+++ b/packager/react-packager/src/DependencyResolver/fastfs.js
@@ -14,6 +14,7 @@ const {EventEmitter} = require('events');
 const fs = require('graceful-fs');
 const path = require('path');
 
+const open = Promise.denodeify(fs.open);
 const readFile = Promise.denodeify(fs.readFile);
 const stat = Promise.denodeify(fs.stat);
 
@@ -114,6 +115,14 @@ class Fastfs extends EventEmitter {
     return file.read();
   }
 
+  readWhile(filePath, predicate) {
+    const file = this._getFile(filePath);
+    if (!file) {
+      throw new Error(`Unable to find file with path: ${filePath}`);
+    }
+    return file.readWhile(predicate);
+  }
+
   closest(filePath, name) {
     for (let file = this._getFile(filePath).parent;
          file;
@@ -241,6 +250,44 @@ class File {
     return this._read;
   }
 
+  readWhile(predicate) {
+    const CHUNK_SIZE = 512;
+    let result = '';
+
+    return open(this.path, 'r').then(fd => {
+      /* global Buffer: true */
+      const buffer = new Buffer(CHUNK_SIZE);
+      const p = new Promise((resolve, reject) => {
+        let counter = 0;
+        const callback = (error, bytesRead) => {
+          if (error) {
+            reject();
+            return;
+          }
+
+          const chunk = buffer.toString('utf8', 0, bytesRead);
+          result += chunk;
+          if (bytesRead > 0 && predicate(chunk, counter++, result)) {
+            readChunk(fd, buffer, callback);
+          } else {
+            if (bytesRead === 0 && !this._read) { // reached EOF
+              this._read = Promise.resolve(result);
+            }
+            resolve(result);
+          }
+        };
+        readChunk(fd, buffer, callback);
+      });
+
+      p.catch(() => fs.close(fd));
+      return p;
+    });
+
+    function readChunk(fd, buffer, callback) {
+      fs.read(fd, buffer, 0, CHUNK_SIZE, null, callback);
+    }
+  }
+
   stat() {
     if (!this._stat) {
       this._stat = stat(this.path);

From b9ceecb31fcafcc59870fd8bc92bf42d0cdaf7b9 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Thu, 28 Jan 2016 22:01:34 -0800
Subject: [PATCH 0929/1411] Adapt tests to new Object/es7 polyfill

Summary:
public

Adds the new polyfill to the relevant tests (Resolver/BundlesLayout)

Reviewed By: martinbigio

Differential Revision: D2878697

fb-gh-sync-id: 9681f16dd19a0b337aac63101450c703bf387346
---
 .../__tests__/BundlesLayoutIntegration-test.js     |  1 +
 .../src/Resolver/__tests__/Resolver-test.js        | 14 ++++++++++++++
 2 files changed, 15 insertions(+)

diff --git a/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js b/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js
index fe4481a0955e..00868b22908d 100644
--- a/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js
+++ b/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js
@@ -36,6 +36,7 @@ describe('BundlesLayout', () => {
     'polyfills/String.prototype.es6.js',
     'polyfills/Array.prototype.es6.js',
     'polyfills/Array.es6.js',
+    'polyfills/Object.es7.js',
     'polyfills/babelHelpers.js',
   ];
   const baseFs = getBaseFs();
diff --git a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
index 825399b4a023..b542d43b1d33 100644
--- a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
+++ b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
@@ -138,6 +138,18 @@ describe('Resolver', function() {
                 'polyfills/Array.prototype.es6.js',
               ],
             },
+            { id: 'polyfills/Object.es7.js',
+              isPolyfill: true,
+              path: 'polyfills/Object.es7.js',
+              dependencies: [
+                'polyfills/polyfills.js',
+                'polyfills/console.js',
+                'polyfills/error-guard.js',
+                'polyfills/String.prototype.es6.js',
+                'polyfills/Array.prototype.es6.js',
+                'polyfills/Array.es6.js',
+              ],
+            },
             { id: 'polyfills/babelHelpers.js',
               isPolyfill: true,
               path: 'polyfills/babelHelpers.js',
@@ -148,6 +160,7 @@ describe('Resolver', function() {
                 'polyfills/String.prototype.es6.js',
                 'polyfills/Array.prototype.es6.js',
                 'polyfills/Array.es6.js',
+                'polyfills/Object.es7.js',
               ],
             },
           ]);
@@ -211,6 +224,7 @@ describe('Resolver', function() {
                 'polyfills/String.prototype.es6.js',
                 'polyfills/Array.prototype.es6.js',
                 'polyfills/Array.es6.js',
+                'polyfills/Object.es7.js',
                 'polyfills/babelHelpers.js',
               ]
             },

From 5e82094fcbddd8927e90567db6ef685215cd78f8 Mon Sep 17 00:00:00 2001
From: Marc Horowitz <mhorowitz@fb.com>
Date: Fri, 29 Jan 2016 00:56:51 -0800
Subject: [PATCH 0930/1411] Move bridge dependencies into a single
 ReactTestFactory

Reviewed By: cjhopman

Differential Revision: D2816291

fb-gh-sync-id: 0eb654541cac7816922d948cc38a26fab44fad70
---
 .../react/testing/ReactAppTestActivity.java   |   3 +-
 .../testing/ReactIntegrationTestCase.java     |  38 ++----
 .../react/testing/ReactTestFactory.java       |  27 ++++
 .../react/testing/ReactTestHelper.java        | 119 +++++++++++++-----
 4 files changed, 128 insertions(+), 59 deletions(-)
 create mode 100644 ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestFactory.java

diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java
index d63110551603..9297f59a2460 100644
--- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java
@@ -132,7 +132,8 @@ public void loadApp(
     final CountDownLatch currentLayoutEvent = mLayoutEvent = new CountDownLatch(1);
     mBridgeIdleSignaler = new ReactBridgeIdleSignaler();
 
-    ReactInstanceManager.Builder builder = ReactInstanceManager.builder()
+    ReactInstanceManager.Builder builder =
+      ReactTestHelper.getReactTestFactory().getReactInstanceManagerBuilder()
         .setApplication(getApplication())
         .setBundleAssetName(bundleName)
         // By not setting a JS module name, we force the bundle to be always loaded from
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java
index 58173647f0ad..3b8f1aba6146 100644
--- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java
@@ -24,7 +24,7 @@
 import com.facebook.react.bridge.BaseJavaModule;
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.CatalystInstanceImpl;
+import com.facebook.react.bridge.CatalystInstance;
 import com.facebook.react.bridge.LifecycleEventListener;
 import com.facebook.react.bridge.SoftAssertions;
 import com.facebook.react.bridge.UiThreadUtil;
@@ -41,17 +41,16 @@
  *
  * In order to write catalyst integration:
  *  1) Make {@link ReactIntegrationTestCase} a base class of your test case
- *  2) Use {@link ReactIntegrationTestCase.ReactTestInstanceBuilder}
+ *  2) Use {@link ReactTestHelper#catalystInstanceBuilder()}
  *  instead of {@link com.facebook.react.bridge.CatalystInstanceImpl.Builder} to build catalyst
  *  instance for testing purposes
  *
  */
 public abstract class ReactIntegrationTestCase extends AndroidTestCase {
 
-  private static final long SETUP_TIMEOUT_MS = 5000;
   private static final long IDLE_TIMEOUT_MS = 15000;
 
-  private @Nullable CatalystInstanceImpl mInstance;
+  private @Nullable CatalystInstance mInstance;
   private @Nullable ReactBridgeIdleSignaler mBridgeIdleSignaler;
   private @Nullable ReactApplicationContext mReactContext;
 
@@ -143,31 +142,12 @@ public void run() {
     }
   }
 
-  public class ReactTestInstanceBuilder extends CatalystInstanceImpl.Builder {
-
-    @Override
-    public CatalystInstanceImpl build() {
-      // Call build in separate looper and wait for it to finish before returning
-      final Event setupEvent = new Event();
-      UiThreadUtil.runOnUiThread(
-          new Runnable() {
-            @Override
-            public void run() {
-              mInstance = ReactTestInstanceBuilder.super.build();
-              mBridgeIdleSignaler = new ReactBridgeIdleSignaler();
-              mInstance.addBridgeIdleDebugListener(mBridgeIdleSignaler);
-              getContext().initializeWithInstance(mInstance);
-              ApplicationHolder.setApplication((Application) getContext().getApplicationContext());
-              setupEvent.occur();
-            }
-          });
-
-      if (!setupEvent.await(SETUP_TIMEOUT_MS)) {
-        throw new RuntimeException(
-            "Instance setup should take less than " + SETUP_TIMEOUT_MS + "ms");
-      }
-      return mInstance;
-    }
+  public void initializeWithInstance(CatalystInstance instance) {
+    mInstance = instance;
+    mBridgeIdleSignaler = new ReactBridgeIdleSignaler();
+    mInstance.addBridgeIdleDebugListener(mBridgeIdleSignaler);
+    getContext().initializeWithInstance(mInstance);
+    ApplicationHolder.setApplication((Application) getContext().getApplicationContext());
   }
 
   public boolean waitForBridgeIdle(long millis) {
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestFactory.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestFactory.java
new file mode 100644
index 000000000000..42877cdd8969
--- /dev/null
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestFactory.java
@@ -0,0 +1,27 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.testing;
+
+import android.content.Context;
+
+import com.facebook.react.ReactInstanceManager;
+import com.facebook.react.bridge.CatalystInstance;
+import com.facebook.react.bridge.NativeModule;
+
+public interface ReactTestFactory {
+  public static interface ReactInstanceEasyBuilder {
+    ReactInstanceEasyBuilder setContext(Context context);
+    ReactInstanceEasyBuilder addNativeModule(NativeModule module);
+    ReactInstanceEasyBuilder addJSModule(Class moduleInterfaceClass);
+    CatalystInstance build();
+  }
+
+  ReactInstanceEasyBuilder getCatalystInstanceBuilder();
+  ReactInstanceManager.Builder getReactInstanceManagerBuilder();
+}
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java
index ff23f1f2325a..fbe1c0db2395 100644
--- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java
@@ -8,70 +8,131 @@
 
 package com.facebook.react.testing;
 
+import javax.annotation.Nullable;
+
+import android.app.Instrumentation;
+import android.content.Context;
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.facebook.react.ReactInstanceManager;
+import com.facebook.react.bridge.CatalystInstance;
 import com.facebook.react.bridge.CatalystInstanceImpl;
 import com.facebook.react.bridge.JSBundleLoader;
-import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
 import com.facebook.react.bridge.JSCJavaScriptExecutor;
+import com.facebook.react.bridge.JavaScriptModulesConfig;
 import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
 import com.facebook.react.bridge.NativeModuleRegistry;
-import com.facebook.react.bridge.JavaScriptModulesConfig;
 import com.facebook.react.bridge.queue.ReactQueueConfigurationSpec;
 
+import android.support.test.InstrumentationRegistry;
 import com.android.internal.util.Predicate;
 
 public class ReactTestHelper {
+  private static class DefaultReactTestFactory implements ReactTestFactory {
+    private static class ReactInstanceEasyBuilderImpl implements ReactInstanceEasyBuilder {
+      private @Nullable Context mContext;
+      private final NativeModuleRegistry.Builder mNativeModuleRegistryBuilder =
+        new NativeModuleRegistry.Builder();
+      private final JavaScriptModulesConfig.Builder mJSModulesConfigBuilder =
+        new JavaScriptModulesConfig.Builder();
 
-  public static class ReactInstanceEasyBuilder {
+      @Override
+      public ReactInstanceEasyBuilder setContext(Context context) {
+        mContext = context;
+        return this;
+      }
 
-    private final ReactIntegrationTestCase mTestCase;
-    private final NativeModuleRegistry.Builder mNativeModuleRegistryBuilder;
-    private final JavaScriptModulesConfig.Builder mJSModulesConfigBuilder;
+      @Override
+      public ReactInstanceEasyBuilder addNativeModule(NativeModule module) {
+        mNativeModuleRegistryBuilder.add(module);
+        return this;
+      }
 
-    private ReactInstanceEasyBuilder(ReactIntegrationTestCase testCase) {
-      mTestCase = testCase;
-      mNativeModuleRegistryBuilder = new NativeModuleRegistry.Builder();
-      mJSModulesConfigBuilder = new JavaScriptModulesConfig.Builder();
-    }
+      @Override
+      public ReactInstanceEasyBuilder addJSModule(Class moduleInterfaceClass) {
+        mJSModulesConfigBuilder.add(moduleInterfaceClass);
+        return this;
+      }
 
-    public CatalystInstanceImpl build() {
-      CatalystInstanceImpl instance = mTestCase.new ReactTestInstanceBuilder()
+      @Override
+      public CatalystInstance build() {
+        return new CatalystInstanceImpl.Builder()
           .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
           .setJSExecutor(new JSCJavaScriptExecutor())
           .setRegistry(mNativeModuleRegistryBuilder.build())
           .setJSModulesConfig(mJSModulesConfigBuilder.build())
           .setJSBundleLoader(JSBundleLoader.createFileLoader(
-                  mTestCase.getContext(),
-                  "assets://AndroidTestBundle.js"))
+                               mContext,
+                               "assets://AndroidTestBundle.js"))
           .setNativeModuleCallExceptionHandler(
-              new NativeModuleCallExceptionHandler() {
+            new NativeModuleCallExceptionHandler() {
                 @Override
                 public void handleException(Exception e) {
                   throw new RuntimeException(e);
                 }
-              })
+            })
           .build();
-      instance.runJSBundle();
-      mTestCase.waitForBridgeAndUIIdle();
-      return instance;
+      }
     }
 
-    public ReactInstanceEasyBuilder addNativeModule(NativeModule module) {
-      mNativeModuleRegistryBuilder.add(module);
-      return this;
+    @Override
+    public ReactInstanceEasyBuilder getCatalystInstanceBuilder() {
+      return new ReactInstanceEasyBuilderImpl();
     }
 
-    public ReactInstanceEasyBuilder addJSModule(Class moduleInterfaceClass) {
-      mJSModulesConfigBuilder.add(moduleInterfaceClass);
-      return this;
+    @Override
+    public ReactInstanceManager.Builder getReactInstanceManagerBuilder() {
+      return ReactInstanceManager.builder();
     }
   }
 
-  public static ReactInstanceEasyBuilder catalystInstanceBuilder(
-      ReactIntegrationTestCase testCase) {
-    return new ReactInstanceEasyBuilder(testCase);
+  public static ReactTestFactory getReactTestFactory() {
+    Instrumentation inst = InstrumentationRegistry.getInstrumentation();
+    if (!(inst instanceof ReactTestFactory)) {
+      return new DefaultReactTestFactory();
+    }
+
+    return (ReactTestFactory) inst;
+  }
+
+  public static ReactTestFactory.ReactInstanceEasyBuilder catalystInstanceBuilder(
+      final ReactIntegrationTestCase testCase) {
+    final ReactTestFactory.ReactInstanceEasyBuilder builder =
+      getReactTestFactory().getCatalystInstanceBuilder();
+    ReactTestFactory.ReactInstanceEasyBuilder postBuilder =
+      new ReactTestFactory.ReactInstanceEasyBuilder() {
+        @Override
+        public ReactTestFactory.ReactInstanceEasyBuilder setContext(Context context) {
+          builder.setContext(context);
+          return this;
+        }
+
+        @Override
+        public ReactTestFactory.ReactInstanceEasyBuilder addNativeModule(NativeModule module) {
+          builder.addNativeModule(module);
+          return this;
+        }
+
+        @Override
+        public ReactTestFactory.ReactInstanceEasyBuilder addJSModule(Class moduleInterfaceClass) {
+          builder.addJSModule(moduleInterfaceClass);
+          return this;
+        }
+
+        @Override
+        public CatalystInstance build() {
+          CatalystInstance instance = builder.build();
+          testCase.initializeWithInstance(instance);
+          instance.runJSBundle();
+          testCase.waitForBridgeAndUIIdle();
+          return instance;
+        }
+      };
+
+    postBuilder.setContext(testCase.getContext());
+    return postBuilder;
   }
 
   /**

From 8de86a0d65dce976bdf4d56486ce8f78a7ed68f2 Mon Sep 17 00:00:00 2001
From: Kudo Chien <ckchien@gmail.com>
Date: Fri, 29 Jan 2016 01:16:40 -0800
Subject: [PATCH 0931/1411] Add onPageScrollStateChanged for ViewPagerAndroid

Summary:
I have an issue when combining `PullToRefreshViewAndroid` and `ViewPagerAndroid`.
`ViewPagerAndroid` will not able to scroll that gesture handler is being taken by `PullToRefreshViewAndroid`
One solution is to disable `PullToRefreshViewAndroid` if `ViewPagerAndroid` is scrolling (i.e. not idle).
[Reference solution here](http://stackoverflow.com/a/29946734/2590265)

So here need to expose the `onPageScrollStateChanged` event.
Some code referenced from  DrawerLayoutAndroid, especially the `VIEWPAGER_PAGE_SCROLL_STATES` array.
Please feel free give me comments.
Thanks.
Closes https://github.com/facebook/react-native/pull/5026

Reviewed By: svcscm

Differential Revision: D2830623

Pulled By: andreicoman11

fb-gh-sync-id: c2a6920c6f4c7daab0115f13864db83b93b31abf
---
 .../ViewPagerAndroidExample.android.js        | 11 +++++
 .../ViewPager/ViewPagerAndroid.android.js     | 25 ++++++++++
 .../PageScrollStateChangedEvent.java          | 49 +++++++++++++++++++
 .../react/views/viewpager/ReactViewPager.java | 17 ++++++-
 .../viewpager/ReactViewPagerManager.java      |  1 +
 5 files changed, 102 insertions(+), 1 deletion(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/viewpager/PageScrollStateChangedEvent.java

diff --git a/Examples/UIExplorer/ViewPagerAndroidExample.android.js b/Examples/UIExplorer/ViewPagerAndroidExample.android.js
index e4f33458e95b..0e672ee8cf99 100644
--- a/Examples/UIExplorer/ViewPagerAndroidExample.android.js
+++ b/Examples/UIExplorer/ViewPagerAndroidExample.android.js
@@ -25,6 +25,8 @@ var {
   ViewPagerAndroid,
 } = React;
 
+import type { ViewPagerScrollState } from 'ViewPagerAndroid';
+
 var PAGES = 5;
 var BGCOLOR = ['#fdc08e', '#fff6b9', '#99d1b7', '#dde5fe', '#f79273'];
 var IMAGE_URIS = [
@@ -114,6 +116,10 @@ var ViewPagerAndroidExample = React.createClass({
     this.setState({progress: e.nativeEvent});
   },
 
+  onPageScrollStateChanged: function(state : ViewPagerScrollState) {
+    this.setState({scrollState: state});
+  },
+
   move: function(delta) {
     var page = this.state.page + delta;
     this.go(page);
@@ -155,6 +161,7 @@ var ViewPagerAndroidExample = React.createClass({
           initialPage={0}
           onPageScroll={this.onPageScroll}
           onPageSelected={this.onPageSelected}
+          onPageScrollStateChanged={this.onPageScrollStateChanged}
           ref={viewPager => { this.viewPager = viewPager; }}>
           {pages}
         </ViewPagerAndroid>
@@ -170,6 +177,7 @@ var ViewPagerAndroidExample = React.createClass({
               enabled={true}
               onPress={() => this.setState({animationsAreEnabled: true})}
             /> }
+          <Text style={styles.scrollStateText}>ScrollState[ {this.state.scrollState} ]</Text>
         </View>
         <View style={styles.buttons}>
           <Button text="Start" enabled={page > 0} onPress={() => this.go(0)}/>
@@ -207,6 +215,9 @@ var styles = StyleSheet.create({
   buttonText: {
     color: 'white',
   },
+  scrollStateText: {
+    color: '#99d1b7',
+  },
   container: {
     flex: 1,
     backgroundColor: 'white',
diff --git a/Libraries/Components/ViewPager/ViewPagerAndroid.android.js b/Libraries/Components/ViewPager/ViewPagerAndroid.android.js
index 360f847a84ae..a8af449746c9 100644
--- a/Libraries/Components/ViewPager/ViewPagerAndroid.android.js
+++ b/Libraries/Components/ViewPager/ViewPagerAndroid.android.js
@@ -19,6 +19,14 @@ var requireNativeComponent = require('requireNativeComponent');
 
 var VIEWPAGER_REF = 'viewPager';
 
+type Event = Object;
+
+export type ViewPagerScrollState = $Enum<{
+  idle: string;
+  dragging: string;
+  settling: string;
+}>;
+
 /**
  * Container that allows to flip left and right between child views. Each
  * child view of the `ViewPagerAndroid` will be treated as a separate page
@@ -78,6 +86,16 @@ var ViewPagerAndroid = React.createClass({
      */
     onPageScroll: ReactPropTypes.func,
 
+    /**
+     * Function called when the page scrolling state has changed.
+     * The page scrolling state can be in 3 states:
+     * - idle, meaning there is no interaction with the page scroller happening at the time
+     * - dragging, meaning there is currently an interaction with the page scroller
+     * - settling, meaning that there was an interaction with the page scroller, and the
+     *   page scroller is now finishing it's closing or opening animation
+     */
+    onPageScrollStateChanged: ReactPropTypes.func,
+
     /**
      * This callback will be called once ViewPager finish navigating to selected page
      * (when user swipes between pages). The `event.nativeEvent` object passed to this
@@ -147,6 +165,12 @@ var ViewPagerAndroid = React.createClass({
     }
   },
 
+  _onPageScrollStateChanged: function(e: Event) {
+    if (this.props.onPageScrollStateChanged) {
+      this.props.onPageScrollStateChanged(e.nativeEvent.pageScrollState);
+    }
+  },
+
   _onPageSelected: function(e: Event) {
     if (this.props.onPageSelected) {
       this.props.onPageSelected(e);
@@ -183,6 +207,7 @@ var ViewPagerAndroid = React.createClass({
         ref={VIEWPAGER_REF}
         style={this.props.style}
         onPageScroll={this._onPageScroll}
+        onPageScrollStateChanged={this._onPageScrollStateChanged}
         onPageSelected={this._onPageSelected}
         children={this._childrenWithOverridenStyle()}
       />
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/PageScrollStateChangedEvent.java b/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/PageScrollStateChangedEvent.java
new file mode 100644
index 000000000000..668c0337ef69
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/PageScrollStateChangedEvent.java
@@ -0,0 +1,49 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.viewpager;
+
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.uimanager.events.Event;
+import com.facebook.react.uimanager.events.RCTEventEmitter;
+
+/**
+ * Event emitted by {@link ReactViewPager} when user scrolling state changed.
+ *
+ * Additional data provided by this event:
+ *  - pageScrollState - {Idle,Dragging,Settling}
+ */
+class PageScrollStateChangedEvent extends Event<PageScrollStateChangedEvent> {
+
+  public static final String EVENT_NAME = "topPageScrollStateChanged";
+
+  private final String mPageScrollState;
+
+  protected PageScrollStateChangedEvent(int viewTag, long timestampMs, String pageScrollState) {
+    super(viewTag, timestampMs);
+    mPageScrollState = pageScrollState;
+  }
+
+  @Override
+  public String getEventName() {
+    return EVENT_NAME;
+  }
+
+  @Override
+  public void dispatch(RCTEventEmitter rctEventEmitter) {
+    rctEventEmitter.receiveEvent(getViewTag(), getEventName(), serializeEventData());
+  }
+
+  private WritableMap serializeEventData() {
+    WritableMap eventData = Arguments.createMap();
+    eventData.putString("pageScrollState", mPageScrollState);
+    return eventData;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/ReactViewPager.java b/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/ReactViewPager.java
index e2a4b0fcd42c..3ad5c55e0cd5 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/ReactViewPager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/ReactViewPager.java
@@ -104,7 +104,22 @@ public void onPageSelected(int position) {
 
     @Override
     public void onPageScrollStateChanged(int state) {
-      // don't send events
+      String pageScrollState;
+      switch (state) {
+        case SCROLL_STATE_IDLE:
+          pageScrollState = "idle";
+          break;
+        case SCROLL_STATE_DRAGGING:
+          pageScrollState = "dragging";
+          break;
+        case SCROLL_STATE_SETTLING:
+          pageScrollState = "settling";
+          break;
+        default:
+          throw new IllegalStateException("Unsupported pageScrollState");
+      }
+      mEventDispatcher.dispatchEvent(
+        new PageScrollStateChangedEvent(getId(), SystemClock.uptimeMillis(), pageScrollState));
     }
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/ReactViewPagerManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/ReactViewPagerManager.java
index 10b131d9924e..0ae266e38020 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/ReactViewPagerManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/ReactViewPagerManager.java
@@ -50,6 +50,7 @@ public boolean needsCustomLayoutForChildren() {
   public Map getExportedCustomDirectEventTypeConstants() {
     return MapBuilder.of(
         PageScrollEvent.EVENT_NAME, MapBuilder.of("registrationName", "onPageScroll"),
+        PageScrollStateChangedEvent.EVENT_NAME, MapBuilder.of("registrationName", "onPageScrollStateChanged"),
         PageSelectedEvent.EVENT_NAME, MapBuilder.of("registrationName", "onPageSelected")
     );
   }

From 1c6e837504d08214726d0a9b2fb54b77d7beb09c Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Fri, 29 Jan 2016 02:04:44 -0800
Subject: [PATCH 0932/1411] Add a deprecatedPropType module to show deprecation
 warnings

Summary:
To allow smoother API changes for users we often deprecate props and keep them around for a while before removing them. Right now it is all done manually, this adds a consistent way to show a warning when using a deprecated prop.

This also adds a deprecation warning of the website generated from the deprecatedPropType.

<img width="643" alt="screen shot 2016-01-26 at 7 43 08 pm" src="https://cloud.githubusercontent.com/assets/2677334/12600172/7af28fb0-c465-11e5-85e5-3786852bf522.png">

It also changes places where we added the warnings manually to use deprecatedPropType instead.
Closes https://github.com/facebook/react-native/pull/5566

Reviewed By: svcscm

Differential Revision: D2874629

Pulled By: nicklockwood

fb-gh-sync-id: c3c63bae7bbec26cc146029abd9aa5efbe73f795
---
 Libraries/Components/MapView/MapView.js       | 41 ++++++++++---------
 Libraries/Components/ScrollView/ScrollView.js |  8 ++--
 .../CustomComponents/Navigator/Navigator.js   | 17 ++++----
 Libraries/StyleSheet/TransformPropTypes.js    | 11 ++---
 Libraries/Utilities/deprecatedPropType.js     | 33 +++++++++++++++
 website/layout/AutodocsLayout.js              |  9 ++++
 website/server/docgenHelpers.js               | 39 ++++++++++++++++++
 website/server/extractDocs.js                 |  5 ++-
 website/src/react-native/css/react-native.css | 22 ++++++++++
 website/src/react-native/img/Warning.png      |  0
 10 files changed, 148 insertions(+), 37 deletions(-)
 create mode 100644 Libraries/Utilities/deprecatedPropType.js
 create mode 100644 website/src/react-native/img/Warning.png

diff --git a/Libraries/Components/MapView/MapView.js b/Libraries/Components/MapView/MapView.js
index ec25733039be..5dbbf2d9f83c 100644
--- a/Libraries/Components/MapView/MapView.js
+++ b/Libraries/Components/MapView/MapView.js
@@ -22,6 +22,7 @@ const React = require('React');
 const StyleSheet = require('StyleSheet');
 const View = require('View');
 
+const deprecatedPropType = require('deprecatedPropType');
 const processColor = require('processColor');
 const resolveAssetSource = require('resolveAssetSource');
 const requireNativeComponent = require('requireNativeComponent');
@@ -64,7 +65,7 @@ const MapView = React.createClass({
      * @platform ios
      */
     followUserLocation: React.PropTypes.bool,
-    
+
     /**
      * If `false` points of interest won't be displayed on the map.
      * Default value is `true`.
@@ -160,7 +161,7 @@ const MapView = React.createClass({
        * Whether the pin drop should be animated or not
        */
       animateDrop: React.PropTypes.bool,
-      
+
       /**
        * Whether the pin should be draggable or not
        */
@@ -168,7 +169,7 @@ const MapView = React.createClass({
 
       /**
        * Event that fires when the annotation drag state changes.
-       */  
+       */
       onDragStateChange: React.PropTypes.func,
 
       /**
@@ -213,11 +214,22 @@ const MapView = React.createClass({
       /**
        * Deprecated. Use the left/right/detailsCalloutView props instead.
        */
-      hasLeftCallout: React.PropTypes.bool,
-      hasRightCallout: React.PropTypes.bool,
-      onLeftCalloutPress: React.PropTypes.func,
-      onRightCalloutPress: React.PropTypes.func,
-
+      hasLeftCallout: deprecatedPropType(
+        React.PropTypes.bool,
+        'Use `leftCalloutView` instead.'
+      ),
+      hasRightCallout: deprecatedPropType(
+        React.PropTypes.bool,
+        'Use `rightCalloutView` instead.'
+      ),
+      onLeftCalloutPress: deprecatedPropType(
+        React.PropTypes.func,
+        'Use `leftCalloutView` instead.'
+      ),
+      onRightCalloutPress: deprecatedPropType(
+        React.PropTypes.func,
+        'Use `rightCalloutView` instead.'
+      ),
     })),
 
     /**
@@ -335,18 +347,7 @@ const MapView = React.createClass({
           style: [styles.calloutView, detailCalloutView.props.style || {}]
         }));
       }
-      if (__DEV__) {
-        ['hasLeftCallout', 'onLeftCalloutPress'].forEach(key => {
-          if (annotation[key]) {
-            console.warn('`' + key + '` is deprecated. Use leftCalloutView instead.');
-          }
-        });
-        ['hasRightCallout', 'onRightCalloutPress'].forEach(key => {
-          if (annotation[key]) {
-            console.warn('`' + key + '` is deprecated. Use rightCalloutView instead.');
-          }
-        });
-      }
+
       let result = {
         ...annotation,
         tintColor: tintColor && processColor(tintColor),
diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js
index 6d80b6751716..89cc17921044 100644
--- a/Libraries/Components/ScrollView/ScrollView.js
+++ b/Libraries/Components/ScrollView/ScrollView.js
@@ -25,6 +25,7 @@ var View = require('View');
 var ViewStylePropTypes = require('ViewStylePropTypes');
 
 var deepDiffer = require('deepDiffer');
+var deprecatedPropType = require('deprecatedPropType');
 var dismissKeyboard = require('dismissKeyboard');
 var flattenStyle = require('flattenStyle');
 var insetsDiffer = require('insetsDiffer');
@@ -321,10 +322,12 @@ var ScrollView = React.createClass({
     refreshControl: PropTypes.element,
 
     /**
-     * Deprecated - use `refreshControl` property instead.
      * @platform ios
      */
-    onRefreshStart: PropTypes.func,
+    onRefreshStart: deprecatedPropType(
+      PropTypes.func,
+      'Use the `refreshControl` prop instead.'
+    ),
   },
 
   mixins: [ScrollResponder.Mixin],
@@ -464,7 +467,6 @@ var ScrollView = React.createClass({
 
     var onRefreshStart = this.props.onRefreshStart;
     if (onRefreshStart) {
-      console.warn('onRefreshStart is deprecated. Use the refreshControl prop instead.');
       // this is necessary because if we set it on props, even when empty,
       // it'll trigger the default pull-to-refresh behavior on native.
       props.onRefreshStart =
diff --git a/Libraries/CustomComponents/Navigator/Navigator.js b/Libraries/CustomComponents/Navigator/Navigator.js
index df6940f3a672..af1ceb2a4c08 100644
--- a/Libraries/CustomComponents/Navigator/Navigator.js
+++ b/Libraries/CustomComponents/Navigator/Navigator.js
@@ -42,6 +42,7 @@ var TimerMixin = require('react-timer-mixin');
 var View = require('View');
 
 var clamp = require('clamp');
+var deprecatedPropType = require('deprecatedPropType');
 var flattenStyle = require('flattenStyle');
 var invariant = require('invariant');
 var rebound = require('rebound');
@@ -224,21 +225,21 @@ var Navigator = React.createClass({
     initialRouteStack: PropTypes.arrayOf(PropTypes.object),
 
     /**
-     * @deprecated
-     * Use `navigationContext.addListener('willfocus', callback)` instead.
-     *
      * Will emit the target route upon mounting and before each nav transition
      */
-    onWillFocus: PropTypes.func,
+    onWillFocus: deprecatedPropType(
+      PropTypes.func,
+      "Use `navigationContext.addListener('willfocus', callback)` instead."
+    ),
 
     /**
-     * @deprecated
-     * Use `navigationContext.addListener('didfocus', callback)` instead.
-     *
      * Will be called with the new route of each scene after the transition is
      * complete or after the initial mounting
      */
-    onDidFocus: PropTypes.func,
+    onDidFocus: deprecatedPropType(
+      PropTypes.func,
+      "Use `navigationContext.addListener('didfocus', callback)` instead."
+    ),
 
     /**
      * Optionally provide a navigation bar that persists across scene
diff --git a/Libraries/StyleSheet/TransformPropTypes.js b/Libraries/StyleSheet/TransformPropTypes.js
index e91382caef9b..9988b8216ea2 100644
--- a/Libraries/StyleSheet/TransformPropTypes.js
+++ b/Libraries/StyleSheet/TransformPropTypes.js
@@ -12,6 +12,7 @@
 'use strict';
 
 var ReactPropTypes = require('ReactPropTypes');
+var deprecatedPropType = require('deprecatedPropType');
 
 var ArrayOfNumberPropType = ReactPropTypes.arrayOf(ReactPropTypes.number);
 
@@ -49,11 +50,11 @@ var TransformPropTypes = {
   transformMatrix: TransformMatrixPropType,
 
   /* Deprecated transform props used on Android only */
-  scaleX: ReactPropTypes.number,
-  scaleY: ReactPropTypes.number,
-  rotation: ReactPropTypes.number,
-  translateX: ReactPropTypes.number,
-  translateY: ReactPropTypes.number,
+  scaleX: deprecatedPropType(ReactPropTypes.number, 'Use the transform prop instead.'),
+  scaleY: deprecatedPropType(ReactPropTypes.number, 'Use the transform prop instead.'),
+  rotation: deprecatedPropType(ReactPropTypes.number, 'Use the transform prop instead.'),
+  translateX: deprecatedPropType(ReactPropTypes.number, 'Use the transform prop instead.'),
+  translateY: deprecatedPropType(ReactPropTypes.number, 'Use the transform prop instead.'),
 };
 
 module.exports = TransformPropTypes;
diff --git a/Libraries/Utilities/deprecatedPropType.js b/Libraries/Utilities/deprecatedPropType.js
new file mode 100644
index 000000000000..63bc61020b4a
--- /dev/null
+++ b/Libraries/Utilities/deprecatedPropType.js
@@ -0,0 +1,33 @@
+/**
+ * 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 deprecatedPropType
+ * @flow
+ */
+'use strict';
+
+const UIManager = require('UIManager');
+
+/**
+ * Adds a deprecation warning when the prop is used.
+ */
+function deprecatedPropType(
+  propType: ReactPropsCheckType,
+  explanation: string
+): ReactPropsCheckType {
+  return function validate(props, propName, componentName) {
+    // Don't warn for native components.
+    if (!UIManager[componentName] && props[propName] !== undefined) {
+      console.warn(`\`${propName}\` supplied to \`${componentName}\` has been deprecated. ${explanation}`);
+    }
+
+    return propType(props, propName, componentName);
+  };
+}
+
+module.exports = deprecatedPropType;
diff --git a/website/layout/AutodocsLayout.js b/website/layout/AutodocsLayout.js
index c3715522a831..c5dbb5445c4e 100644
--- a/website/layout/AutodocsLayout.js
+++ b/website/layout/AutodocsLayout.js
@@ -119,6 +119,15 @@ var ComponentDoc = React.createClass({
             {renderType(prop.type)}
           </span>}
         </Header>
+        {prop.deprecationMessage && <div className="deprecated">
+          <div className="deprecatedTitle">
+            <img className="deprecatedIcon" src="/react-native/img/Warning.png" />
+            <span>Deprecated</span>
+          </div>
+          <div className="deprecatedMessage">
+            <Marked>{prop.deprecationMessage}</Marked>
+          </div>
+        </div>}
         {prop.type && prop.type.name === 'stylesheet' &&
           this.renderStylesheetProps(prop.type.value)}
         {prop.description && <Marked>{prop.description}</Marked>}
diff --git a/website/server/docgenHelpers.js b/website/server/docgenHelpers.js
index 89762e0cf073..36873fdee75c 100644
--- a/website/server/docgenHelpers.js
+++ b/website/server/docgenHelpers.js
@@ -6,6 +6,7 @@ function stylePropTypeHandler(documentation, path) {
   if (!propTypesPath) {
     return;
   }
+
   propTypesPath = docgen.utils.resolveToValue(propTypesPath);
   if (!propTypesPath || propTypesPath.node.type !== 'ObjectExpression') {
     return;
@@ -34,6 +35,43 @@ function stylePropTypeHandler(documentation, path) {
   });
 }
 
+function deprecatedPropTypeHandler(documentation, path) {
+  var propTypesPath = docgen.utils.getMemberValuePath(path, 'propTypes');
+  if (!propTypesPath) {
+    return;
+  }
+
+  propTypesPath = docgen.utils.resolveToValue(propTypesPath);
+  if (!propTypesPath || propTypesPath.node.type !== 'ObjectExpression') {
+    return;
+  }
+
+  // Checks for deprecatedPropType function and add deprecation info.
+  propTypesPath.get('properties').each(function(propertyPath) {
+    var valuePath = docgen.utils.resolveToValue(propertyPath.get('value'));
+    // If it's a call to deprecatedPropType, do stuff
+    if (valuePath.node.type !== 'CallExpression' ||
+        valuePath.node.callee.name !== 'deprecatedPropType') {
+      return;
+    }
+    var propDescriptor = documentation.getPropDescriptor(
+      docgen.utils.getPropertyName(propertyPath)
+    );
+    // The 2nd argument of deprecatedPropType is the deprecation message.
+    // Used printValue to get the string otherwise there was issues with template
+    // strings.
+    propDescriptor.deprecationMessage = docgen.utils
+      .printValue(valuePath.get('arguments', 1))
+      // Remove the quotes printValue adds.
+      .slice(1, -1);
+
+    // Get the actual prop type.
+    propDescriptor.type = docgen.utils.getPropType(
+      valuePath.get('arguments', 0)
+    );
+  });
+}
+
 function findExportedOrFirst(node, recast) {
   return docgen.resolver.findExportedComponentDefinition(node, recast) ||
     docgen.resolver.findAllComponentDefinitions(node, recast)[0];
@@ -86,5 +124,6 @@ function findExportedObject(ast, recast) {
 }
 
 exports.stylePropTypeHandler = stylePropTypeHandler;
+exports.deprecatedPropTypeHandler = deprecatedPropTypeHandler;
 exports.findExportedOrFirst = findExportedOrFirst;
 exports.findExportedObject = findExportedObject;
diff --git a/website/server/extractDocs.js b/website/server/extractDocs.js
index 151b6581458a..766fc336311a 100644
--- a/website/server/extractDocs.js
+++ b/website/server/extractDocs.js
@@ -149,7 +149,10 @@ function renderComponent(filepath) {
   var json = docgen.parse(
     fs.readFileSync(filepath),
     docgenHelpers.findExportedOrFirst,
-    docgen.defaultHandlers.concat(docgenHelpers.stylePropTypeHandler)
+    docgen.defaultHandlers.concat([
+      docgenHelpers.stylePropTypeHandler,
+      docgenHelpers.deprecatedPropTypeHandler,
+    ])
   );
 
   return componentsToMarkdown('component', json, filepath, n++, styleDocs);
diff --git a/website/src/react-native/css/react-native.css b/website/src/react-native/css/react-native.css
index 41b347369046..1331e880f534 100644
--- a/website/src/react-native/css/react-native.css
+++ b/website/src/react-native/css/react-native.css
@@ -1096,6 +1096,28 @@ div[data-twttr-id] iframe {
   border: 1px solid rgba(0, 0, 0, 0.2);
 }
 
+.deprecated {
+  margin-bottom: 24px;
+}
+
+.deprecatedTitle {
+  margin-bottom: 6px;
+  line-height: 18px;
+  font-weight: bold;
+  color: #ffa500;
+}
+
+.deprecatedIcon {
+  width: 18px;
+  height: 18px;
+  margin-right: 8px;
+  vertical-align: top;
+}
+
+.deprecatedMessage {
+  margin-left: 26px;
+}
+
 .edit-github {
   font-size: 15px;
   font-weight: normal;
diff --git a/website/src/react-native/img/Warning.png b/website/src/react-native/img/Warning.png
new file mode 100644
index 000000000000..e69de29bb2d1

From c33e8524c1a1b17b47a696269624042bb0720e87 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Fri, 29 Jan 2016 12:09:15 +0100
Subject: [PATCH 0933/1411] [website] Fix warning.png file

Added in PR #5566. Importing binary files doesn't work correctly
yet but it's being worked on.
---
 website/src/react-native/img/Warning.png | Bin 0 -> 758 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)

diff --git a/website/src/react-native/img/Warning.png b/website/src/react-native/img/Warning.png
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ceeb6edf2c6612fe4246a2b14e254384ad7edbd1 100644
GIT binary patch

From 1dd5ba7021c13f3475097db5652f8f4e5e2469f1 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Fri, 29 Jan 2016 03:58:35 -0800
Subject: [PATCH 0934/1411] Add a cross-platform Picker

Summary:
The basic API is consistent with iOS; there are several platform-specific props.

Also fixed the flickering when a value is selected.

public

Reviewed By: bestander

Differential Revision: D2871092

fb-gh-sync-id: f5cdf6858cb7344b28ee46954cb6b0a3b144b646
---
 Examples/UIExplorer/PickerAndroidExample.js   | 128 +++++------
 Libraries/Components/Picker/Picker.js         | 152 +++++++++++++
 .../Picker/PickerAndroid.android.js           | 141 ++++++++++++
 .../Components/Picker/PickerAndroid.ios.js    |  13 ++
 .../Components/PickerAndroid/PickerAndroid.js | 213 ------------------
 Libraries/react-native/react-native.js        |   2 +-
 Libraries/react-native/react-native.js.flow   |   2 +-
 .../views/picker/ReactPickerManager.java      |   2 +-
 8 files changed, 373 insertions(+), 280 deletions(-)
 create mode 100644 Libraries/Components/Picker/Picker.js
 create mode 100644 Libraries/Components/Picker/PickerAndroid.android.js
 create mode 100644 Libraries/Components/Picker/PickerAndroid.ios.js
 delete mode 100644 Libraries/Components/PickerAndroid/PickerAndroid.js

diff --git a/Examples/UIExplorer/PickerAndroidExample.js b/Examples/UIExplorer/PickerAndroidExample.js
index 947a0129ea20..0f76f6e8480a 100644
--- a/Examples/UIExplorer/PickerAndroidExample.js
+++ b/Examples/UIExplorer/PickerAndroidExample.js
@@ -16,20 +16,21 @@
 'use strict';
 
 const React = require('react-native');
+const StyleSheet = require('StyleSheet');
 const UIExplorerBlock = require('UIExplorerBlock');
 const UIExplorerPage = require('UIExplorerPage');
 
 const {
-  PickerAndroid,
+  Picker,
   Text,
   TouchableWithoutFeedback,
 } = React;
-const Item = PickerAndroid.Item;
+const Item = Picker.Item;
 
-const PickerAndroidExample = React.createClass({
+const PickerExample = React.createClass({
 
   statics: {
-    title: '<PickerAndroid>',
+    title: '<Picker>',
     description: 'Provides multiple options to choose from, using either a dropdown menu or a dialog.',
   },
 
@@ -38,9 +39,8 @@ const PickerAndroidExample = React.createClass({
       selected1: 'key1',
       selected2: 'key1',
       selected3: 'key1',
-      selected4: 'key1',
       color: 'red',
-      mode: PickerAndroid.MODE_DIALOG,
+      mode: Picker.MODE_DIALOG,
     };
   },
 
@@ -48,93 +48,93 @@ const PickerAndroidExample = React.createClass({
 
   render: function() {
     return (
-      <UIExplorerPage title="<PickerAndroid>">
+      <UIExplorerPage title="<Picker>">
         <UIExplorerBlock title="Basic Picker">
-          <PickerAndroid
-            style={{width: 100, height: 56}}
-            onSelect={this.onSelect.bind(this, 'selected1')}>
-            <Item text="hello" value="key0" selected={this.state.selected1 === 'key0'} />
-            <Item text="world" value="key1" selected={this.state.selected1 === 'key1'} />
-          </PickerAndroid>
+          <Picker
+            style={styles.picker}
+            selectedValue={this.state.selected1}
+            onValueChange={this.onValueChange.bind(this, 'selected1')}>
+            <Item label="hello" value="key0" />
+            <Item label="world" value="key1" />
+          </Picker>
         </UIExplorerBlock>
         <UIExplorerBlock title="Disabled picker">
-          <PickerAndroid style={{width: 100, height: 56}} enabled={false}>
-            <Item text="hello" value="key0" selected={this.state.selected1 === 'key0'} />
-            <Item text="world" value="key1" selected={this.state.selected1 === 'key1'} />
-          </PickerAndroid>
+          <Picker style={styles.picker} enabled={false} selectedValue={this.state.selected1}>
+            <Item label="hello" value="key0" />
+            <Item label="world" value="key1" />
+          </Picker>
         </UIExplorerBlock>
         <UIExplorerBlock title="Dropdown Picker">
-          <PickerAndroid
-            style={{width: 100, height: 56}}
-            onSelect={this.onSelect.bind(this, 'selected2')}
+          <Picker
+            style={styles.picker}
+            selectedValue={this.state.selected2}
+            onValueChange={this.onValueChange.bind(this, 'selected2')}
             mode="dropdown">
-            <Item text="hello" value="key0" selected={this.state.selected2 === 'key0'} />
-            <Item text="world" value="key1" selected={this.state.selected2 === 'key1'} />
-          </PickerAndroid>
-        </UIExplorerBlock>
-        <UIExplorerBlock title="Alternating Picker">
-          <PickerAndroid
-            style={{width: 100, height: 56}}
-            onSelect={this.onSelect.bind(this, 'selected3')}
-            mode={this.state.mode}>
-            <Item text="hello" value="key0" selected={this.state.selected3 === 'key0'} />
-            <Item text="world" value="key1" selected={this.state.selected3 === 'key1'} />
-          </PickerAndroid>
-          <TouchableWithoutFeedback onPress={this.changeMode}>
-            <Text>Tap here to switch between dialog/dropdown.</Text>
-          </TouchableWithoutFeedback>
+            <Item label="hello" value="key0" />
+            <Item label="world" value="key1" />
+          </Picker>
         </UIExplorerBlock>
         <UIExplorerBlock title="Picker with prompt message">
-          <PickerAndroid
-            style={{width: 100, height: 56}}
-            onSelect={this.onSelect.bind(this, 'selected4')}
+          <Picker
+            style={styles.picker}
+            selectedValue={this.state.selected3}
+            onValueChange={this.onValueChange.bind(this, 'selected3')}
             prompt="Pick one, just one">
-            <Item text="hello" value="key0" selected={this.state.selected4 === 'key0'} />
-            <Item text="world" value="key1" selected={this.state.selected4 === 'key1'} />
-          </PickerAndroid>
+            <Item label="hello" value="key0" />
+            <Item label="world" value="key1" />
+          </Picker>
         </UIExplorerBlock>
         <UIExplorerBlock title="Picker with no listener">
-          <PickerAndroid style={{width: 100, height: 56}}>
-            <Item text="hello" value="key0" />
-            <Item text="world" value="key1" />
-          </PickerAndroid>
+          <Picker style={styles.picker}>
+            <Item label="hello" value="key0" />
+            <Item label="world" value="key1" />
+          </Picker>
           <Text>
-            You can not change the value of this picker because it doesn't set a selected prop on
-            its items.
+            Cannot change the value of this picker because it doesn't update selectedValue.
           </Text>
         </UIExplorerBlock>
         <UIExplorerBlock title="Colorful pickers">
-          <PickerAndroid style={{width: 100, height: 56, color: 'black'}}
-            onSelect={this.onSelect.bind(this, 'color')}
+          <Picker
+            style={[styles.picker, {color: 'white', backgroundColor: '#333'}]}
+            selectedValue={this.state.color}
+            onValueChange={this.onValueChange.bind(this, 'color')}
             mode="dropdown">
-            <Item text="red" color="red" value="red" selected={this.state.color === 'red'}/>
-            <Item text="green" color="green" value="green" selected={this.state.color === 'green'}/>
-            <Item text="blue" color="blue" value="blue" selected={this.state.color === 'blue'}/>
-          </PickerAndroid>
-          <PickerAndroid style={{width: 100, height: 56}}
-            onSelect={this.onSelect.bind(this, 'color')}
+            <Item label="red" color="red" value="red" />
+            <Item label="green" color="green" value="green" />
+            <Item label="blue" color="blue" value="blue" />
+          </Picker>
+          <Picker
+            style={styles.picker}
+            selectedValue={this.state.color}
+            onValueChange={this.onValueChange.bind(this, 'color')}
             mode="dialog">
-            <Item text="red" color="red" value="red" selected={this.state.color === 'red'}/>
-            <Item text="green" color="green" value="green" selected={this.state.color === 'green'}/>
-            <Item text="blue" color="blue" value="blue" selected={this.state.color === 'blue'} />
-          </PickerAndroid>
+            <Item label="red" color="red" value="red" />
+            <Item label="green" color="green" value="green" />
+            <Item label="blue" color="blue" value="blue" />
+          </Picker>
         </UIExplorerBlock>
       </UIExplorerPage>
     );
   },
 
   changeMode: function() {
-    const newMode = this.state.mode === PickerAndroid.MODE_DIALOG
-        ? PickerAndroid.MODE_DROPDOWN
-        : PickerAndroid.MODE_DIALOG;
+    const newMode = this.state.mode === Picker.MODE_DIALOG
+        ? Picker.MODE_DROPDOWN
+        : Picker.MODE_DIALOG;
     this.setState({mode: newMode});
   },
 
-  onSelect: function(key: string, value: string) {
+  onValueChange: function(key: string, value: string) {
     const newState = {};
     newState[key] = value;
     this.setState(newState);
   },
 });
 
-module.exports = PickerAndroidExample;
+var styles = StyleSheet.create({
+  picker: {
+    width: 100,
+  },
+});
+
+module.exports = PickerExample;
diff --git a/Libraries/Components/Picker/Picker.js b/Libraries/Components/Picker/Picker.js
new file mode 100644
index 000000000000..9db560fb9c82
--- /dev/null
+++ b/Libraries/Components/Picker/Picker.js
@@ -0,0 +1,152 @@
+/**
+ * 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 Picker
+ * @flow
+ */
+
+'use strict';
+
+var ColorPropType = require('ColorPropType');
+var PickerIOS = require('PickerIOS');
+var PickerAndroid = require('PickerAndroid');
+var Platform = require('Platform');
+var React = require('React');
+var StyleSheet = require('StyleSheet');
+var StyleSheetPropType = require('StyleSheetPropType');
+var TextStylePropTypes = require('TextStylePropTypes');
+var UnimplementedView = require('UnimplementedView');
+var View = require('View');
+var ViewStylePropTypes = require('ViewStylePropTypes');
+
+var itemStylePropType = StyleSheetPropType(TextStylePropTypes);
+
+var pickerStyleType = StyleSheetPropType({
+  ...ViewStylePropTypes,
+  color: ColorPropType,
+});
+
+var MODE_DIALOG = 'dialog';
+var MODE_DROPDOWN = 'dropdown';
+
+/**
+ * Renders the native picker component on iOS and Android. Example:
+ *
+ *     <Picker
+ *       selectedValue={this.state.language}
+ *       onValueChange={(lang) => this.setState({language: lang})}>
+ *       <Picker.Item label="Java" value="java" />
+ *       <Picker.Item label="JavaScript" value="js" />
+ *     </Picker>
+ */
+var Picker = React.createClass({
+
+  statics: {
+    /**
+     * On Android, display the options in a dialog.
+     */
+    MODE_DIALOG: MODE_DIALOG,
+    /**
+     * On Android, display the options in a dropdown (this is the default).
+     */
+    MODE_DROPDOWN: MODE_DROPDOWN,
+  },
+
+  getDefaultProps: function() {
+    return {
+      mode: MODE_DIALOG,
+    };
+  },
+
+  propTypes: {
+    ...View.propTypes,
+    style: pickerStyleType,
+    /**
+     * Value matching value of one of the items. Can be a string or an integer.
+     */
+    selectedValue: React.PropTypes.any,
+    /**
+     * Callback for when an item is selected. This is called with the following parameters:
+     *   - `itemValue`: the `value` prop of the item that was selected
+     *   - `itemPosition`: the index of the selected item in this picker
+     */
+    onValueChange: React.PropTypes.func,
+    /**
+     * If set to false, the picker will be disabled, i.e. the user will not be able to make a
+     * selection.
+     * @platform android
+     */
+    enabled: React.PropTypes.bool,
+    /**
+     * On Android, specifies how to display the selection items when the user taps on the picker:
+     *   - 'dialog': Show a modal dialog. This is the default.
+     *   - 'dropdown': Shows a dropdown anchored to the picker view
+     *
+     * @platform android
+     */
+    mode: React.PropTypes.oneOf([MODE_DIALOG, MODE_DROPDOWN]),
+    /**
+     * Style to apply to each of the item labels.
+     * @platform ios
+     */
+    itemStyle: itemStylePropType,
+    /**
+     * Prompt string for this picker, used on Android in dialog mode as the title of the dialog.
+     * @platform android
+     */
+    prompt: React.PropTypes.string,
+    /**
+     * Used to locate this view in end-to-end tests.
+     */
+    testID: React.PropTypes.string,
+  },
+
+  render: function() {
+      if (Platform.OS === 'ios') {
+        return <PickerIOS {...this.props}>{this.props.children}</PickerIOS>;
+      } else if (Platform.OS === 'android') {
+        return <PickerAndroid {...this.props}>{this.props.children}</PickerAndroid>;
+      } else {
+        return <UnimplementedView />;
+      }
+  },
+});
+
+/**
+ * Individual selectable item in a Picker.
+ */
+Picker.Item = React.createClass({
+
+  propTypes: {
+    /**
+     * Text to display for this item.
+     */
+    label: React.PropTypes.string.isRequired,
+    /**
+     * The value to be passed to picker's `onValueChange` callback when
+     * this item is selected. Can be a string or an integer.
+     */
+    value: React.PropTypes.any,
+    /**
+     * Color of this item's text.
+     * @platform android
+     */
+    color: ColorPropType,
+    /**
+     * Used to locate the item in end-to-end tests.
+     */
+    testID: React.PropTypes.string,
+  },
+
+  render: function() {
+    // The items are not rendered directly
+    throw null;
+  },
+});
+
+module.exports = Picker;
diff --git a/Libraries/Components/Picker/PickerAndroid.android.js b/Libraries/Components/Picker/PickerAndroid.android.js
new file mode 100644
index 000000000000..2e95b32f1a6a
--- /dev/null
+++ b/Libraries/Components/Picker/PickerAndroid.android.js
@@ -0,0 +1,141 @@
+/**
+ * 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 PickerAndroid
+ * @flow
+ */
+
+'use strict';
+
+var ColorPropType = require('ColorPropType');
+var React = require('React');
+var ReactChildren = require('ReactChildren');
+var ReactPropTypes = require('ReactPropTypes');
+var StyleSheet = require('StyleSheet');
+var StyleSheetPropType = require('StyleSheetPropType');
+var View = require('View');
+var ViewStylePropTypes = require('ViewStylePropTypes');
+
+var processColor = require('processColor');
+var requireNativeComponent = require('requireNativeComponent');
+
+var REF_PICKER = 'picker';
+var MODE_DIALOG = 'dialog';
+var MODE_DROPDOWN = 'dropdown';
+
+var pickerStyleType = StyleSheetPropType({
+  ...ViewStylePropTypes,
+  color: ColorPropType,
+});
+
+type Event = Object;
+
+/**
+ * Not exposed as a public API - use <Picker> instead.
+ */
+var PickerAndroid = React.createClass({
+
+  propTypes: {
+    ...View.propTypes,
+    style: pickerStyleType,
+    selectedValue: React.PropTypes.any,
+    enabled: ReactPropTypes.bool,
+    mode: ReactPropTypes.oneOf(['dialog', 'dropdown']),
+    onValueChange: ReactPropTypes.func,
+    prompt: ReactPropTypes.string,
+    testID: ReactPropTypes.string,
+  },
+
+  getInitialState: function() {
+    return this._stateFromProps(this.props);
+  },
+
+  componentWillReceiveProps: function(nextProps) {
+    this.setState(this._stateFromProps(nextProps));
+  },
+
+  // Translate prop and children into stuff that the native picker understands.
+  _stateFromProps: function(props) {
+    var selectedIndex = 0;
+    let items = ReactChildren.map(props.children, (child, index) => {
+      if (child.props.value === props.selectedValue) {
+        selectedIndex = index;
+      }
+      let childProps = {
+        value: child.props.value,
+        label: child.props.label,
+      };
+      if (child.props.color) {
+        childProps.color = processColor(child.props.color);
+      }
+      return childProps;
+    });
+    return {selectedIndex, items};
+  },
+
+  render: function() {
+    var Picker = this.props.mode === MODE_DROPDOWN ? DropdownPicker : DialogPicker;
+
+    var nativeProps = {
+      enabled: this.props.enabled,
+      items: this.state.items,
+      mode: this.props.mode,
+      onSelect: this._onChange,
+      prompt: this.props.prompt,
+      selected: this.state.selectedIndex,
+      testID: this.props.testID,
+      style: [styles.pickerAndroid, this.props.style],
+    };
+
+    return <Picker ref={REF_PICKER} {...nativeProps} />;
+  },
+
+  _onChange: function(event: Event) {
+    if (this.props.onValueChange) {
+      var position = event.nativeEvent.position;
+      if (position >= 0) {
+        var value = this.props.children[position].props.value;
+        this.props.onValueChange(value);
+      } else {
+        this.props.onValueChange(null);
+      }
+    }
+
+    // The picker is a controlled component. This means we expect the
+    // on*Change handlers to be in charge of updating our
+    // `selectedValue` prop. That way they can also
+    // disallow/undo/mutate the selection of certain values. In other
+    // words, the embedder of this component should be the source of
+    // truth, not the native component.
+    if (this.refs[REF_PICKER] && this.state.selectedIndex !== event.nativeEvent.position) {
+      this.refs[REF_PICKER].setNativeProps({selected: this.state.selectedIndex});
+    }
+  },
+});
+
+var styles = StyleSheet.create({
+  pickerAndroid: {
+    // The picker will conform to whatever width is given, but we do
+    // have to set the component's height explicitly on the
+    // surrounding view to ensure it gets rendered.
+    // TODO would be better to export a native constant for this,
+    // like in iOS the RCTDatePickerManager.m
+    height: 50,
+  },
+});
+
+var cfg = {
+  nativeOnly: {
+    items: true,
+    selected: true,
+  }
+}
+var DropdownPicker = requireNativeComponent('AndroidDropdownPicker', PickerAndroid, cfg);
+var DialogPicker = requireNativeComponent('AndroidDialogPicker', PickerAndroid, cfg);
+
+module.exports = PickerAndroid;
diff --git a/Libraries/Components/Picker/PickerAndroid.ios.js b/Libraries/Components/Picker/PickerAndroid.ios.js
new file mode 100644
index 000000000000..fc589882864a
--- /dev/null
+++ b/Libraries/Components/Picker/PickerAndroid.ios.js
@@ -0,0 +1,13 @@
+/**
+ * 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 PickerAndroid
+ */
+'use strict';
+
+module.exports = require('UnimplementedView');
diff --git a/Libraries/Components/PickerAndroid/PickerAndroid.js b/Libraries/Components/PickerAndroid/PickerAndroid.js
deleted file mode 100644
index 1ec105ca45e1..000000000000
--- a/Libraries/Components/PickerAndroid/PickerAndroid.js
+++ /dev/null
@@ -1,213 +0,0 @@
-/**
- * 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 PickerAndroid
- * @flow
- */
-
-'use strict';
-
-var ColorPropType = require('ColorPropType');
-var React = require('React');
-var ReactChildren = require('ReactChildren');
-var ReactPropTypes = require('ReactPropTypes');
-var StyleSheetPropType = require('StyleSheetPropType');
-var View = require('View');
-var ViewStylePropTypes = require('ViewStylePropTypes');
-
-var processColor = require('processColor');
-var requireNativeComponent = require('requireNativeComponent');
-
-var MODE_DIALOG = 'dialog';
-var MODE_DROPDOWN = 'dropdown';
-var REF_PICKER = 'picker';
-
-var pickerStyleType = StyleSheetPropType({
-  ...ViewStylePropTypes,
-  color: ColorPropType,
-});
-
-type Items = {
-  selected: number;
-  items: any[];
-};
-
-type Event = Object;
-
-/**
- * Individual selectable item in a Picker.
- */
-var Item = React.createClass({
-
-  propTypes: {
-    /**
-     * Color of this item's text.
-     */
-    color: ColorPropType,
-    /**
-     * Text to display for this item.
-     */
-    text: ReactPropTypes.string.isRequired,
-    /**
-     * The value to be passed to picker's `onSelect` callback when this item is selected.
-     */
-    value: ReactPropTypes.string,
-    /**
-     * If `true`, this item is selected and shown in the picker.
-     * Usually this is set based on state.
-     */
-    selected: ReactPropTypes.bool,
-    /**
-     * Used to locate this view in end-to-end tests.
-     */
-    testID: ReactPropTypes.string,
-  },
-
-  render: function() {
-    throw new Error('Picker items should never be rendered');
-  },
-
-});
-
-/**
- * <PickerAndroid> - A React component that renders the native Picker widget on Android. The items
- * that can be selected are specified as children views of type Item. Example usage:
- *
- *     <PickerAndroid>
- *       <PickerAndroid.Item text="Java" value="js" />
- *       <PickerAndroid.Item text="JavaScript" value="java" selected={true} />
- *     </PickerAndroid>
- */
-var PickerAndroid = React.createClass({
-
-  propTypes: {
-    ...View.propTypes,
-    style: pickerStyleType,
-    /**
-     * If set to false, the picker will be disabled, i.e. the user will not be able to make a
-     * selection.
-     */
-    enabled: ReactPropTypes.bool,
-    /**
-     * Specifies how to display the selection items when the user taps on the picker:
-     *
-     * - dialog: Show a modal dialog
-     * - dropdown: Shows a dropdown anchored to the picker view
-     */
-    mode: ReactPropTypes.oneOf([MODE_DIALOG, MODE_DROPDOWN]),
-    /**
-     * Callback for when an item is selected. This is called with the following parameters:
-     *
-     * - `itemValue`: the `value` prop of the item that was selected
-     * - `itemPosition`: the index of the selected item in this picker
-     */
-    onSelect: ReactPropTypes.func,
-    /**
-     * Prompt string for this picker, currently only used in `dialog` mode as the title of the
-     * dialog.
-     */
-    prompt: ReactPropTypes.string,
-    /**
-     * Used to locate this view in end-to-end tests.
-     */
-    testID: ReactPropTypes.string,
-  },
-
-  statics: {
-    Item: Item,
-    MODE_DIALOG: MODE_DIALOG,
-    MODE_DROPDOWN: MODE_DROPDOWN,
-  },
-
-  getDefaultProps: function() {
-    return {
-      mode: MODE_DIALOG,
-    };
-  },
-
-  render: function() {
-    var Picker = this.props.mode === MODE_DROPDOWN ? DropdownPicker : DialogPicker;
-
-    var { selected, items } = this._getItems();
-
-    var nativeProps = {
-      enabled: this.props.enabled,
-      items: items,
-      mode: this.props.mode,
-      onSelect: this._onSelect,
-      prompt: this.props.prompt,
-      selected: selected,
-      style: this.props.style,
-      testID: this.props.testID,
-    };
-
-    return <Picker ref={REF_PICKER} {...nativeProps} />;
-  },
-
-  /**
-   * Transform this view's children into an array of items to be passed to the native component.
-   * Since we're traversing the children, also determine the selected position.
-   *
-   * @returns an object with two keys:
-   *
-   * - `selected` (number) - the index of the selected item
-   * - `items` (array) - the items of this picker, as an array of strings
-   */
-  _getItems: function(): Items {
-    var items = [];
-    var selected = 0;
-    ReactChildren.forEach(this.props.children, function(child, index) {
-      var childProps = Object.assign({}, child.props);
-      if (childProps.color) {
-        childProps.color = processColor(childProps.color);
-      }
-      items.push(childProps);
-      if (childProps.selected) {
-        selected = index;
-      }
-    });
-    return {
-      selected: selected,
-      items: items,
-    };
-  },
-
-  _onSelect: function(event: Event) {
-    if (this.props.onSelect) {
-      var position = event.nativeEvent.position;
-      if (position >= 0) {
-        var value = this.props.children[position].props.value;
-        this.props.onSelect(value, position);
-      } else {
-        this.props.onSelect(null, position);
-      }
-    }
-
-    // The native Picker has changed, but the props haven't (yet). If
-    // the handler decides to not accept the new value or do something
-    // else with it we might end up in a bad state, so we reset the
-    // selection on the native component.
-    // tl;dr: PickerAndroid is a controlled component.
-    var { selected } = this._getItems();
-    if (this.refs[REF_PICKER]) {
-      this.refs[REF_PICKER].setNativeProps({selected: selected});
-    }
-  },
-
-});
-
-var cfg = {
-  nativeOnly: {
-    items: true,
-    selected: true,
-  }
-}
-var DropdownPicker = requireNativeComponent('AndroidDropdownPicker', PickerAndroid, cfg);
-var DialogPicker = requireNativeComponent('AndroidDialogPicker', PickerAndroid, cfg);
-
-module.exports = PickerAndroid;
diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js
index da90b75c0fa0..6efc9af3c74d 100644
--- a/Libraries/react-native/react-native.js
+++ b/Libraries/react-native/react-native.js
@@ -25,7 +25,7 @@ var ReactNative = {
   get Modal() { return require('Modal'); },
   get Navigator() { return require('Navigator'); },
   get NavigatorIOS() { return require('NavigatorIOS'); },
-  get PickerAndroid() { return require('PickerAndroid'); },
+  get Picker() { return require('Picker'); },
   get PickerIOS() { return require('PickerIOS'); },
   get ProgressBarAndroid() { return require('ProgressBarAndroid'); },
   get ProgressViewIOS() { return require('ProgressViewIOS'); },
diff --git a/Libraries/react-native/react-native.js.flow b/Libraries/react-native/react-native.js.flow
index 52d7eeddb496..a0c20f5e0677 100644
--- a/Libraries/react-native/react-native.js.flow
+++ b/Libraries/react-native/react-native.js.flow
@@ -37,7 +37,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
   Modal: require('Modal'),
   Navigator: require('Navigator'),
   NavigatorIOS: require('NavigatorIOS'),
-  PickerAndroid: require('PickerAndroid'),
+  Picker: require('Picker'),
   PickerIOS: require('PickerIOS'),
   ProgressBarAndroid: require('ProgressBarAndroid'),
   ProgressViewIOS: require('ProgressViewIOS'),
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactPickerManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactPickerManager.java
index fe2f23cd020c..2c8c24038907 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactPickerManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactPickerManager.java
@@ -128,7 +128,7 @@ private View getView(int position, View convertView, ViewGroup parent, boolean i
       }
 
       TextView textView = (TextView) convertView;
-      textView.setText(item.getString("text"));
+      textView.setText(item.getString("label"));
       if (!isDropdown && mPrimaryTextColor != null) {
         textView.setTextColor(mPrimaryTextColor);
       } else if (item.hasKey("color") && !item.isNull("color")) {

From 53100ecccb9fc6e478153b37271a407e11a98870 Mon Sep 17 00:00:00 2001
From: Ognjen Dragoljevic <plamenko@fb.com>
Date: Fri, 29 Jan 2016 04:25:16 -0800
Subject: [PATCH 0935/1411] Add support for custom scale types

Summary:
public
This diff adds support for providing custom scaletypes to Drawee. The implementation for the preexisting scale types is preserved.
Breaking changes should be minimal. In fact, only direct usages of `ScalingUtils.getTransform(..., scaleType)` should be converted to `scaleType.getTransform(...)`.

Reviewed By: kirwan

Differential Revision: D2862911

fb-gh-sync-id: ab0355fd13544dc08ce4481eda87287404ea7adb
---
 .../react/views/image/ReactImageView.java     | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
index be57d799d337..36fa511c0282 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
@@ -74,16 +74,15 @@ public class ReactImageView extends GenericDraweeView {
   private class RoundedCornerPostprocessor extends BasePostprocessor {
 
     float getRadius(Bitmap source) {
-        ScalingUtils.getTransform(
-            sMatrix,
-            new Rect(0, 0, source.getWidth(), source.getHeight()),
-            source.getWidth(),
-            source.getHeight(),
-            0.0f,
-            0.0f,
-            mScaleType);
-        sMatrix.invert(sInverse);
-        return sInverse.mapRadius(mBorderRadius);
+      mScaleType.getTransform(
+          sMatrix,
+          new Rect(0, 0, source.getWidth(), source.getHeight()),
+          source.getWidth(),
+          source.getHeight(),
+          0.0f,
+          0.0f);
+      sMatrix.invert(sInverse);
+      return sInverse.mapRadius(mBorderRadius);
     }
 
     @Override

From cb874a55aafa97395730964639e3b711ea774d64 Mon Sep 17 00:00:00 2001
From: Christoph Jerolimov <jerolimov+git+2015@gmail.com>
Date: Fri, 29 Jan 2016 06:25:35 -0800
Subject: [PATCH 0936/1411] Add MapView annotation callback when it gets / lost
 the focus

Summary:
For my project it was required to receive a notification when the MapView annotation was deselected.

So I renamed `onAnnotationPress` to `onAnnotationSelected` and added a new method `onAnnotationDeselected`, this names was "inspired" by the underlaying iOS API. The old API was still called and marked as deprecated.

But maybe you have an idea for a better naming (onAnnotationFocus/-Blur?) -- or should a deselected call the press method again without an annotation (undefined)?
Closes https://github.com/facebook/react-native/pull/5167

Reviewed By: svcscm

Differential Revision: D2869695

Pulled By: nicklockwood

fb-gh-sync-id: 91795ac3f1e4533b250af8901534d8870729d9db
---
 Examples/UIExplorer/MapViewExample.js   | 14 ++++
 Libraries/Components/MapView/MapView.js | 94 ++++++++++++++++---------
 React/Views/RCTMap.h                    |  2 +
 React/Views/RCTMapManager.m             | 24 +++++++
 4 files changed, 100 insertions(+), 34 deletions(-)

diff --git a/Examples/UIExplorer/MapViewExample.js b/Examples/UIExplorer/MapViewExample.js
index b10620b04a60..d11d3006ac47 100644
--- a/Examples/UIExplorer/MapViewExample.js
+++ b/Examples/UIExplorer/MapViewExample.js
@@ -320,6 +320,20 @@ exports.examples = [
       }}/>;
     }
   },
+  {
+    title: 'Annotation focus example',
+    render() {
+      return <AnnotationExample style={styles.map} annotation={{
+        title: 'More Info...',
+        onFocus: () => {
+          alert('Annotation gets focus');
+        },
+        onBlur: () => {
+          alert('Annotation lost focus');
+        }
+      }}/>;
+    }
+  },
   {
     title: 'Draggable pin',
     render() {
diff --git a/Libraries/Components/MapView/MapView.js b/Libraries/Components/MapView/MapView.js
index 5dbbf2d9f83c..13ee06ee8618 100644
--- a/Libraries/Components/MapView/MapView.js
+++ b/Libraries/Components/MapView/MapView.js
@@ -172,6 +172,18 @@ const MapView = React.createClass({
        */
       onDragStateChange: React.PropTypes.func,
 
+      /**
+       * Event that fires when the annotation gets was tapped by the user
+       * and the callout view was displayed.
+       */
+      onFocus: React.PropTypes.func,
+
+      /**
+       * Event that fires when another annotation or the mapview itself
+       * was tapped and a previously shown annotation will be closed.
+       */
+      onBlur: React.PropTypes.func,
+
       /**
        * Annotation title/subtile.
        */
@@ -288,7 +300,7 @@ const MapView = React.createClass({
     onRegionChangeComplete: React.PropTypes.func,
 
     /**
-     * Callback that is called once, when the user taps an annotation.
+     * Deprecated. Use annotation onFocus and onBlur instead.
      */
     onAnnotationPress: React.PropTypes.func,
 
@@ -376,51 +388,61 @@ const MapView = React.createClass({
       return result;
     });
 
+    const findByAnnotationId = (annotationId: string) => {
+      if (!annotations) {
+        return null;
+      }
+      for (let i = 0, l = annotations.length; i < l; i++) {
+        if (annotations[i].id === annotationId) {
+          return annotations[i];
+        }
+      }
+      return null;
+    };
+
     // TODO: these should be separate events, to reduce bridge traffic
+    let onPress, onAnnotationDragStateChange, onAnnotationFocus, onAnnotationBlur;
     if (annotations) {
-      var onPress = (event: Event) => {
-        if (!annotations) {
-          return;
-        }
+      onPress = (event: Event) => {
         if (event.nativeEvent.action === 'annotation-click') {
+          // TODO: Remove deprecated onAnnotationPress API call later.
           this.props.onAnnotationPress &&
             this.props.onAnnotationPress(event.nativeEvent.annotation);
         } else if (event.nativeEvent.action === 'callout-click') {
-          // Find the annotation with the id that was pressed
-          for (let i = 0, l = annotations.length; i < l; i++) {
-            let annotation = annotations[i];
-            if (annotation.id === event.nativeEvent.annotationId) {
-              // Pass the right function
-              if (event.nativeEvent.side === 'left') {
-                annotation.onLeftCalloutPress &&
-                  annotation.onLeftCalloutPress(event.nativeEvent);
-              } else if (event.nativeEvent.side === 'right') {
-                annotation.onRightCalloutPress &&
-                  annotation.onRightCalloutPress(event.nativeEvent);
-              }
-              break;
+          const annotation = findByAnnotationId(event.nativeEvent.annotationId);
+          if (annotation) {
+            // Pass the right function
+            if (event.nativeEvent.side === 'left' && annotation.onLeftCalloutPress) {
+              annotation.onLeftCalloutPress(event.nativeEvent);
+            } else if (event.nativeEvent.side === 'right' && annotation.onRightCalloutPress) {
+              annotation.onRightCalloutPress(event.nativeEvent);
             }
           }
         }
       };
-      var onAnnotationDragStateChange = (event: Event) => {
-        if (!annotations) {
-          return;
+      onAnnotationDragStateChange = (event: Event) => {
+        const annotation = findByAnnotationId(event.nativeEvent.annotationId);
+        if (annotation) {
+          // Update location
+          annotation.latitude = event.nativeEvent.latitude;
+          annotation.longitude = event.nativeEvent.longitude;
+          // Call callback
+          annotation.onDragStateChange &&
+            annotation.onDragStateChange(event.nativeEvent);
         }
-        // Find the annotation with the id that was pressed
-        for (let i = 0, l = annotations.length; i < l; i++) {
-          let annotation = annotations[i];
-          if (annotation.id === event.nativeEvent.annotationId) {
-            // Update location
-            annotation.latitude = event.nativeEvent.latitude;
-            annotation.longitude = event.nativeEvent.longitude;
-            // Call callback
-            annotation.onDragStateChange &&
-              annotation.onDragStateChange(event.nativeEvent);
-            break;
-          }
+      };
+      onAnnotationFocus = (event: Event) => {
+        const annotation = findByAnnotationId(event.nativeEvent.annotationId);
+        if (annotation && annotation.onFocus) {
+          annotation.onFocus(event.nativeEvent);
         }
-      }
+      };
+      onAnnotationBlur = (event: Event) => {
+        const annotation = findByAnnotationId(event.nativeEvent.annotationId);
+        if (annotation && annotation.onBlur) {
+          annotation.onBlur(event.nativeEvent);
+        }
+      };
     }
 
     // TODO: these should be separate events, to reduce bridge traffic
@@ -451,6 +473,8 @@ const MapView = React.createClass({
         onPress={onPress}
         onChange={onChange}
         onAnnotationDragStateChange={onAnnotationDragStateChange}
+        onAnnotationFocus={onAnnotationFocus}
+        onAnnotationBlur={onAnnotationBlur}
       />
     );
   },
@@ -484,6 +508,8 @@ MapView.PinColors = PinColors && {
 const RCTMap = requireNativeComponent('RCTMap', MapView, {
   nativeOnly: {
     onAnnotationDragStateChange: true,
+    onAnnotationFocus: true,
+    onAnnotationBlur: true,
     onChange: true,
     onPress: true
   }
diff --git a/React/Views/RCTMap.h b/React/Views/RCTMap.h
index e7a0768107a1..e6c5cabf0b80 100644
--- a/React/Views/RCTMap.h
+++ b/React/Views/RCTMap.h
@@ -31,6 +31,8 @@ RCT_EXTERN const CGFloat RCTMapZoomBoundBuffer;
 @property (nonatomic, copy) RCTBubblingEventBlock onChange;
 @property (nonatomic, copy) RCTBubblingEventBlock onPress;
 @property (nonatomic, copy) RCTBubblingEventBlock onAnnotationDragStateChange;
+@property (nonatomic, copy) RCTBubblingEventBlock onAnnotationFocus;
+@property (nonatomic, copy) RCTBubblingEventBlock onAnnotationBlur;
 
 - (void)setAnnotations:(NSArray<RCTMapAnnotation *> *)annotations;
 - (void)setOverlays:(NSArray<RCTMapOverlay *> *)overlays;
diff --git a/React/Views/RCTMapManager.m b/React/Views/RCTMapManager.m
index 74517b4c40db..ec4595a5a3a5 100644
--- a/React/Views/RCTMapManager.m
+++ b/React/Views/RCTMapManager.m
@@ -97,6 +97,8 @@ - (UIView *)view
 RCT_EXPORT_VIEW_PROPERTY(annotations, NSArray<RCTMapAnnotation *>)
 RCT_EXPORT_VIEW_PROPERTY(overlays, NSArray<RCTMapOverlay *>)
 RCT_EXPORT_VIEW_PROPERTY(onAnnotationDragStateChange, RCTBubblingEventBlock)
+RCT_EXPORT_VIEW_PROPERTY(onAnnotationFocus, RCTBubblingEventBlock)
+RCT_EXPORT_VIEW_PROPERTY(onAnnotationBlur, RCTBubblingEventBlock)
 RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock)
 RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
 RCT_CUSTOM_VIEW_PROPERTY(region, MKCoordinateRegion, RCTMap)
@@ -137,6 +139,7 @@ - (UIView *)view
 
 - (void)mapView:(RCTMap *)mapView didSelectAnnotationView:(MKAnnotationView *)view
 {
+  // TODO: Remove deprecated onAnnotationPress API call later.
   if (mapView.onPress && [view.annotation isKindOfClass:[RCTMapAnnotation class]]) {
     RCTMapAnnotation *annotation = (RCTMapAnnotation *)view.annotation;
     mapView.onPress(@{
@@ -150,6 +153,27 @@ - (void)mapView:(RCTMap *)mapView didSelectAnnotationView:(MKAnnotationView *)vi
       }
     });
   }
+
+  if ([view.annotation isKindOfClass:[RCTMapAnnotation class]]) {
+    RCTMapAnnotation *annotation = (RCTMapAnnotation *)view.annotation;
+    if (mapView.onAnnotationFocus) {
+      mapView.onAnnotationFocus(@{
+        @"annotationId": annotation.identifier
+      });
+    }
+  }
+}
+
+- (void)mapView:(RCTMap *)mapView didDeselectAnnotationView:(MKAnnotationView *)view
+{
+  if ([view.annotation isKindOfClass:[RCTMapAnnotation class]]) {
+    RCTMapAnnotation *annotation = (RCTMapAnnotation *)view.annotation;
+    if (mapView.onAnnotationBlur) {
+      mapView.onAnnotationBlur(@{
+        @"annotationId": annotation.identifier
+      });
+    }
+  }
 }
 
 - (void)mapView:(RCTMap *)mapView annotationView:(MKAnnotationView *)view

From 715081c4da4fab4bb82693c6fb0672fbac826b56 Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Fri, 29 Jan 2016 17:22:36 +0100
Subject: [PATCH 0937/1411] Update Releases.md

---
 Releases.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Releases.md b/Releases.md
index 324d9edd2259..11c61502146d 100644
--- a/Releases.md
+++ b/Releases.md
@@ -10,7 +10,7 @@ Future releases:
 - 0.18.0 - Jan 18
 - **0.19 branch cut**, 0.19.0-rc - **week of Jan 18**
 - 0.19.0 - Feb 1
-- **0.20 branch cut**, 0.19.0-rc - **week of Feb 1**
+- **0.20 branch cut**, 0.20.0-rc - **week of Feb 1**
 - 0.20.0 - Feb 15
 - ...
 

From c8a0a3eff6e18b21feb89cfdd3a375adab6a68e2 Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeux@fb.com>
Date: Fri, 29 Jan 2016 09:11:53 -0800
Subject: [PATCH 0938/1411] Reimplement color processing

Summary:
**Problem:**

As I was trying to document what color formats we supported, I realized that our current implementation based on the open source project tinycolor supported some crazy things. A few examples that were all valid:

```
tinycolor('abc')
tinycolor(' #abc ')
tinycolor('##abc')
tinycolor('rgb 255 0 0')
tinycolor('RGBA(0, 1, 2)')
tinycolor('rgb (0, 1, 2)')
tinycolor('hsv(0, 1, 2)')
tinycolor({r: 10, g: 10, b: 10})
tinycolor('hsl(1%, 2, 3)')
tinycolor('rgb(1.0, 2.0, 3.0)')
tinycolor('rgb(1%, 2%, 3%)')
```

The integrations of tinycolor were also really bad. processColor added "support" for pure numbers and an array of colors!?? ColorPropTypes did some crazy trim().toString() and repeated a bad error message twice.

**Solution:**

While iteratively cleaning the file, I eventually ended up reimplementing it entierly. Major changes are:
- The API is now dead simple: returns null if it doesn't parse or returns the int32 representation of the color
- Stricter parsing of at
Closes https://github.com/facebook/react-native/pull/5529

Reviewed By: svcscm

Differential Revision: D2872015

Pulled By: nicklockwood

fb-gh-sync-id: df78244eefce6cf8e8ed2ea51f58d6b232de16f9
---
 Libraries/Animated/src/Interpolation.js       |  23 +-
 .../src/__tests__/Interpolation-test.js       |  14 +-
 Libraries/ReactIOS/requireNativeComponent.js  |   8 +-
 Libraries/StyleSheet/ColorPropType.js         |  40 +-
 .../__tests__/normalizeColor-test.js          | 112 ++++
 .../StyleSheet/__tests__/processColor-test.js |  24 -
 Libraries/StyleSheet/normalizeColor.js        | 347 ++++++++++++
 Libraries/StyleSheet/processColor.js          |  38 +-
 Libraries/vendor/tinycolor/tinycolor.js       | 503 ------------------
 9 files changed, 529 insertions(+), 580 deletions(-)
 create mode 100644 Libraries/StyleSheet/__tests__/normalizeColor-test.js
 create mode 100755 Libraries/StyleSheet/normalizeColor.js
 delete mode 100755 Libraries/vendor/tinycolor/tinycolor.js

diff --git a/Libraries/Animated/src/Interpolation.js b/Libraries/Animated/src/Interpolation.js
index da9671316064..c4e739e5ef87 100644
--- a/Libraries/Animated/src/Interpolation.js
+++ b/Libraries/Animated/src/Interpolation.js
@@ -9,9 +9,10 @@
  * @providesModule Interpolation
  * @flow
  */
+/* eslint no-bitwise: 0 */
 'use strict';
 
-var tinycolor = require('tinycolor');
+var normalizeColor = require('normalizeColor');
 
 // TODO(#7644673): fix this hack once github jest actually checks invariants
 var invariant = function(condition, message) {
@@ -164,16 +165,20 @@ function interpolate(
   return result;
 }
 
-function colorToRgba(
-  input: string
-): string {
-  var color = tinycolor(input);
-  if (color.isValid()) {
-    var {r, g, b, a} = color.toRgb();
-    return `rgba(${r}, ${g}, ${b}, ${a === undefined ? 1 : a})`;
-  } else {
+function colorToRgba(input: string): string {
+  var int32Color = normalizeColor(input);
+  if (int32Color === null) {
     return input;
   }
+
+  int32Color = int32Color || 0; // $FlowIssue
+
+  var a = ((int32Color & 0xff000000) >>> 24) / 255;
+  var r = (int32Color & 0x00ff0000) >>> 16;
+  var g = (int32Color & 0x0000ff00) >>> 8;
+  var b = int32Color & 0x000000ff;
+
+  return `rgba(${r}, ${g}, ${b}, ${a})`;
 }
 
 var stringShapeRegex = /[0-9\.-]+/g;
diff --git a/Libraries/Animated/src/__tests__/Interpolation-test.js b/Libraries/Animated/src/__tests__/Interpolation-test.js
index d6625f25074c..afea659ed956 100644
--- a/Libraries/Animated/src/__tests__/Interpolation-test.js
+++ b/Libraries/Animated/src/__tests__/Interpolation-test.js
@@ -11,7 +11,7 @@
 jest
   .dontMock('Interpolation')
   .dontMock('Easing')
-  .dontMock('tinycolor');
+  .dontMock('normalizeColor');
 
 var Interpolation = require('Interpolation');
 var Easing = require('Easing');
@@ -216,12 +216,12 @@ describe('Interpolation', () => {
   it('should work with output ranges as string', () => {
     var interpolation = Interpolation.create({
       inputRange: [0, 1],
-      outputRange: ['rgba(0, 100, 200, 0)', 'rgba(50, 150, 250, 0.5)'],
+      outputRange: ['rgba(0, 100, 200, 0)', 'rgba(50, 150, 250, 0.4)'],
     });
 
     expect(interpolation(0)).toBe('rgba(0, 100, 200, 0)');
-    expect(interpolation(0.5)).toBe('rgba(25, 125, 225, 0.25)');
-    expect(interpolation(1)).toBe('rgba(50, 150, 250, 0.5)');
+    expect(interpolation(0.5)).toBe('rgba(25, 125, 225, 0.2)');
+    expect(interpolation(1)).toBe('rgba(50, 150, 250, 0.4)');
   });
 
   it('should work with output ranges as short hex string', () => {
@@ -249,11 +249,11 @@ describe('Interpolation', () => {
   it('should work with output ranges with mixed hex and rgba strings', () => {
     var interpolation = Interpolation.create({
       inputRange: [0, 1],
-      outputRange: ['rgba(100, 120, 140, .5)', '#87FC70'],
+      outputRange: ['rgba(100, 120, 140, .4)', '#87FC70'],
     });
 
-    expect(interpolation(0)).toBe('rgba(100, 120, 140, 0.5)');
-    expect(interpolation(0.5)).toBe('rgba(117.5, 186, 126, 0.75)');
+    expect(interpolation(0)).toBe('rgba(100, 120, 140, 0.4)');
+    expect(interpolation(0.5)).toBe('rgba(117.5, 186, 126, 0.7)');
     expect(interpolation(1)).toBe('rgba(135, 252, 112, 1)');
   });
 
diff --git a/Libraries/ReactIOS/requireNativeComponent.js b/Libraries/ReactIOS/requireNativeComponent.js
index 84789e6cf61d..cb190912401d 100644
--- a/Libraries/ReactIOS/requireNativeComponent.js
+++ b/Libraries/ReactIOS/requireNativeComponent.js
@@ -106,12 +106,16 @@ var TypeToDifferMap = {
   // (not yet implemented)
 };
 
+function processColorArray(colors: []): [] {
+  return colors && colors.map(processColor);
+}
+
 var TypeToProcessorMap = {
   // iOS Types
   CGColor: processColor,
-  CGColorArray: processColor,
+  CGColorArray: processColorArray,
   UIColor: processColor,
-  UIColorArray: processColor,
+  UIColorArray: processColorArray,
   CGImage: resolveAssetSource,
   UIImage: resolveAssetSource,
   RCTImageSource: resolveAssetSource,
diff --git a/Libraries/StyleSheet/ColorPropType.js b/Libraries/StyleSheet/ColorPropType.js
index 753b65c2d320..564ab92e0844 100644
--- a/Libraries/StyleSheet/ColorPropType.js
+++ b/Libraries/StyleSheet/ColorPropType.js
@@ -9,26 +9,38 @@
   * @providesModule ColorPropType
   */
 'use strict';
+
 var ReactPropTypes = require('ReactPropTypes');
-var tinycolor = require('tinycolor');
 
-var colorValidator = function (props, propName) {
-  var selectedColor = props[propName];
-  if (selectedColor === null || selectedColor === undefined || selectedColor.toString().trim() === '') {
-    return new Error(
-      `Invalid argument supplied to ${propName}.Expected a string like #123ADF or 'red'.`
-    );
+var normalizeColor = require('normalizeColor');
+
+var ColorPropType = function(props, propName) {
+  var color = props[propName];
+  if (color === undefined || color === null) {
+    return;
   }
 
-  if (tinycolor(selectedColor.toString().trim()).isValid()) {
-    return null;
+  if (typeof color === 'number') {
+    // Developers should not use a number, but we are using the prop type
+    // both for user provided colors and for transformed ones. This isn't ideal
+    // and should be fixed but will do for now...
+    return;
   }
 
-  return new Error(
-    `Invalid argument supplied to ${propName}.Expected a string like #123ADF or 'red'.`
-  );
+  if (normalizeColor(color) === null) {
+    return new Error(
+`Invalid color supplied to ${propName}: ${color}. Valid color formats are
+  - #f0f (#rgb)
+  - #f0fc (#rgba)
+  - #ff00ff (#rrggbb)
+  - #ff00ff00 (#rrggbbaa)
+  - rgb(255, 255, 255)
+  - rgba(255, 255, 255, 1.0)
+  - hsl(360, 100%, 100%)
+  - hsla(360, 100%, 100%, 1.0)
+  - transparent
+  - red`);
+  }
 };
 
-var ColorPropType = ReactPropTypes.oneOfType([colorValidator, ReactPropTypes.number]);
-
 module.exports = ColorPropType;
diff --git a/Libraries/StyleSheet/__tests__/normalizeColor-test.js b/Libraries/StyleSheet/__tests__/normalizeColor-test.js
new file mode 100644
index 000000000000..6f333fba00a5
--- /dev/null
+++ b/Libraries/StyleSheet/__tests__/normalizeColor-test.js
@@ -0,0 +1,112 @@
+/**
+ * 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.
+ */
+'use strict';
+
+jest.dontMock('normalizeColor');
+
+var normalizeColor = require('normalizeColor');
+
+describe('normalizeColor', function() {
+  it('should accept only spec compliant colors', function() {
+    expect(normalizeColor('#abc')).not.toBe(null);
+    expect(normalizeColor('#abcd')).not.toBe(null);
+    expect(normalizeColor('#abcdef')).not.toBe(null);
+    expect(normalizeColor('#abcdef01')).not.toBe(null);
+    expect(normalizeColor('rgb(1,2,3)')).not.toBe(null);
+    expect(normalizeColor('rgb(1, 2, 3)')).not.toBe(null);
+    expect(normalizeColor('rgb(   1   , 2   , 3   )')).not.toBe(null);
+    expect(normalizeColor('rgb(-1, -2, -3)')).not.toBe(null);
+    expect(normalizeColor('rgba(0, 0, 0, 1)')).not.toBe(null);
+  });
+
+  it('should refuse non spec compliant colors', function() {
+    expect(normalizeColor('#00gg00')).toBe(null);
+    expect(normalizeColor('rgb(1, 2, 3,)')).toBe(null);
+    expect(normalizeColor('rgb(1, 2, 3')).toBe(null);
+
+    // Used to be accepted by normalizeColor
+    expect(normalizeColor('abc')).toBe(null);
+    expect(normalizeColor(' #abc ')).toBe(null);
+    expect(normalizeColor('##abc')).toBe(null);
+    expect(normalizeColor('rgb 255 0 0')).toBe(null);
+    expect(normalizeColor('RGBA(0, 1, 2)')).toBe(null);
+    expect(normalizeColor('rgb (0, 1, 2)')).toBe(null);
+    expect(normalizeColor('hsv(0, 1, 2)')).toBe(null);
+    expect(normalizeColor({r: 10, g: 10, b: 10})).toBe(null);
+    expect(normalizeColor('hsl(1%, 2, 3)')).toBe(null);
+    expect(normalizeColor('rgb(1.0, 2.0, 3.0)')).toBe(null);
+    expect(normalizeColor('rgb(1%, 2%, 3%)')).toBe(null);
+  });
+
+  it('should handle hex6 properly', function() {
+    expect(normalizeColor('#000000')).toBe(0xff000000);
+    expect(normalizeColor('#ffffff')).toBe(0xffffffff);
+    expect(normalizeColor('#ff00ff')).toBe(0xffff00ff);
+    expect(normalizeColor('#abcdef')).toBe(0xffabcdef);
+    expect(normalizeColor('#012345')).toBe(0xff012345);
+  });
+
+  it('should handle hex3 properly', function() {
+    expect(normalizeColor('#000')).toBe(0xff000000);
+    expect(normalizeColor('#fff')).toBe(0xffffffff);
+    expect(normalizeColor('#f0f')).toBe(0xffff00ff);
+  });
+
+  it('should handle hex8 properly', function() {
+    expect(normalizeColor('#00000000')).toBe(0x00000000);
+    expect(normalizeColor('#ffffffff')).toBe(0xffffffff);
+    expect(normalizeColor('#ffff00ff')).toBe(0xffffff00);
+    expect(normalizeColor('#abcdef01')).toBe(0x01abcdef);
+    expect(normalizeColor('#01234567')).toBe(0x67012345);
+  });
+
+  it('should handle rgb properly', function() {
+    expect(normalizeColor('rgb(0, 0, 0)')).toBe(0xff000000);
+    expect(normalizeColor('rgb(-1, -2, -3)')).toBe(0xff000000);
+    expect(normalizeColor('rgb(0, 0, 255)')).toBe(0xff0000ff);
+    expect(normalizeColor('rgb(100, 15, 69)')).toBe(0xff640f45);
+    expect(normalizeColor('rgb(255, 255, 255)')).toBe(0xffffffff);
+    expect(normalizeColor('rgb(256, 256, 256)')).toBe(0xffffffff);
+  });
+
+  it('should handle rgba properly', function() {
+    expect(normalizeColor('rgba(0, 0, 0, 0.0)')).toBe(0x00000000);
+    expect(normalizeColor('rgba(0, 0, 0, 0)')).toBe(0x00000000);
+    expect(normalizeColor('rgba(0, 0, 0, -0.5)')).toBe(0x00000000);
+    expect(normalizeColor('rgba(0, 0, 0, 1.0)')).toBe(0xff000000);
+    expect(normalizeColor('rgba(0, 0, 0, 1)')).toBe(0xff000000);
+    expect(normalizeColor('rgba(0, 0, 0, 1.5)')).toBe(0xff000000);
+    expect(normalizeColor('rgba(100, 15, 69, 0.5)')).toBe(0x80640f45);
+  });
+
+  it('should handle hsl properly', function() {
+    expect(normalizeColor('hsl(0, 0%, 0%)')).toBe(0xff000000);
+    expect(normalizeColor('hsl(360, 100%, 100%)')).toBe(0xffffffff);
+    expect(normalizeColor('hsl(180, 50%, 50%)')).toBe(0xff40bfbf);
+    expect(normalizeColor('hsl(540, 50%, 50%)')).toBe(0xff40bfbf);
+    expect(normalizeColor('hsl(70, 25%, 75%)')).toBe(0xffcacfaf);
+    expect(normalizeColor('hsl(70, 100%, 75%)')).toBe(0xffeaff80);
+    expect(normalizeColor('hsl(70, 110%, 75%)')).toBe(0xffeaff80);
+    expect(normalizeColor('hsl(70, 0%, 75%)')).toBe(0xffbfbfbf);
+    expect(normalizeColor('hsl(70, -10%, 75%)')).toBe(0xffbfbfbf);
+  });
+
+  it('should handle hsla properly', function() {
+    expect(normalizeColor('hsla(0, 0%, 0%, 0)')).toBe(0x00000000);
+    expect(normalizeColor('hsla(360, 100%, 100%, 1)')).toBe(0xffffffff);
+    expect(normalizeColor('hsla(360, 100%, 100%, 0)')).toBe(0x00ffffff);
+    expect(normalizeColor('hsla(180, 50%, 50%, 0.2)')).toBe(0x3340bfbf);
+  });
+
+  it('should handle named colors properly', function() {
+    expect(normalizeColor('red')).toBe(0xffff0000);
+    expect(normalizeColor('transparent')).toBe(0x00000000);
+    expect(normalizeColor('peachpuff')).toBe(0xffffdab9);
+  });
+});
diff --git a/Libraries/StyleSheet/__tests__/processColor-test.js b/Libraries/StyleSheet/__tests__/processColor-test.js
index 9416353b79b6..79682bbacc51 100644
--- a/Libraries/StyleSheet/__tests__/processColor-test.js
+++ b/Libraries/StyleSheet/__tests__/processColor-test.js
@@ -49,12 +49,6 @@ describe('processColor', () => {
       expect(colorFromString).toEqual(expectedInt);
     });
 
-    it('should convert rgb x, y, z', () => {
-      var colorFromString = processColor('rgb 10, 20, 30');
-      var expectedInt = 0xFF0A141E;
-      expect(colorFromString).toEqual(expectedInt);
-    });
-
   });
 
   describe('RGBA strings', () => {
@@ -65,12 +59,6 @@ describe('processColor', () => {
       expect(colorFromString).toEqual(expectedInt);
     });
 
-    it('should convert rgba x, y, z, a', () => {
-      var colorFromString = processColor('rgba 10, 20, 30, 0.4');
-      var expectedInt = 0x660A141E;
-      expect(colorFromString).toEqual(expectedInt);
-    });
-
   });
 
   describe('HSL strings', () => {
@@ -81,12 +69,6 @@ describe('processColor', () => {
       expect(colorFromString).toEqual(expectedInt);
     });
 
-    it('should convert hsl x, y%, z%', () => {
-      var colorFromString = processColor('hsl 318, 69%, 55%');
-      var expectedInt = 0xFFDB3DAC;
-      expect(colorFromString).toEqual(expectedInt);
-    });
-
   });
 
   describe('HSL strings', () => {
@@ -97,12 +79,6 @@ describe('processColor', () => {
       expect(colorFromString).toEqual(expectedInt);
     });
 
-    it('should convert hsla x, y%, z%, a', () => {
-      var colorFromString = processColor('hsla 318, 69%, 55%, 0.25');
-      var expectedInt = 0x40DB3DAC;
-      expect(colorFromString).toEqual(expectedInt);
-    });
-
   });
 
   describe('hex strings', () => {
diff --git a/Libraries/StyleSheet/normalizeColor.js b/Libraries/StyleSheet/normalizeColor.js
new file mode 100755
index 000000000000..417fc5d3d0d1
--- /dev/null
+++ b/Libraries/StyleSheet/normalizeColor.js
@@ -0,0 +1,347 @@
+/**
+ * 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 normalizeColor
+ * @flow
+ */
+/* eslint no-bitwise: 0 */
+'use strict';
+
+function normalizeColor(color: string): ?number {
+  var match;
+
+  // Ordered based on occurrences on Facebook codebase
+  if ((match = matchers.hex6.exec(color))) {
+    return 0xff000000 + parseInt(match[1], 16);
+  }
+
+  if (names.hasOwnProperty(color)) {
+    return names[color];
+  }
+
+  if ((match = matchers.rgb.exec(color))) {
+    return (
+      0xff000000 + // a
+      parse255(match[1]) * (1 << 16) + // r
+      parse255(match[2]) * (1 << 8) + // g
+      parse255(match[3]) // b
+    );
+  }
+
+  if ((match = matchers.rgba.exec(color))) {
+    return (
+      parse1(match[4]) * (1 << 24) + // a
+      parse255(match[1]) * (1 << 16) + // r
+      parse255(match[2]) * (1 << 8) + // g
+      parse255(match[3]) // b
+    );
+  }
+
+  if ((match = matchers.hex3.exec(color))) {
+    return (
+      parseInt(
+        'ff' + // a
+        match[1] + match[1] + // r
+        match[2] + match[2] + // g
+        match[3] + match[3], // b
+        16
+      )
+    );
+  }
+
+  // https://drafts.csswg.org/css-color-4/#hex-notation
+  if ((match = matchers.hex8.exec(color))) {
+    var number = parseInt(match[1], 16);
+    // Convert 0xrrggbbaa into 0xaarrggbb
+    return (number << 24 | number >>> 8) >>> 0;
+  }
+
+  if ((match = matchers.hex4.exec(color))) {
+    return (
+      parseInt(
+        match[4] + match[4] + // a
+        match[1] + match[1] + // r
+        match[2] + match[2] + // g
+        match[3] + match[3], // b
+        16
+      )
+    );
+  }
+
+  if ((match = matchers.hsl.exec(color))) {
+    return (
+      0xff000000 + // a
+      hslToRgb(
+        parse360(match[1]), // h
+        parsePercentage(match[2]), // s
+        parsePercentage(match[3]) // l
+      )
+    );
+  }
+
+  if ((match = matchers.hsla.exec(color))) {
+    return (
+      parse1(match[4]) * (1 << 24) + // a
+      hslToRgb(
+        parse360(match[1]), // h
+        parsePercentage(match[2]), // s
+        parsePercentage(match[3]) // l
+      )
+    );
+  }
+
+  return null;
+}
+
+function hue2rgb(p: number, q: number, t: number): number {
+  if (t < 0) {
+    t += 1;
+  }
+  if (t > 1) {
+    t -= 1;
+  }
+  if (t < 1 / 6) {
+    return p + (q - p) * 6 * t;
+  }
+  if (t < 1 / 2) {
+    return q;
+  }
+  if (t < 2 / 3) {
+    return p + (q - p) * (2 / 3 - t) * 6;
+  }
+  return p;
+}
+
+function hslToRgb(h: number, s: number, l: number): number {
+  var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
+  var p = 2 * l - q;
+  var r = hue2rgb(p, q, h + 1 / 3);
+  var g = hue2rgb(p, q, h);
+  var b = hue2rgb(p, q, h - 1 / 3);
+
+  return (
+    Math.round(r * 255) * (1 << 16) +
+    Math.round(g * 255) * (1 << 8) +
+    Math.round(b * 255)
+  );
+}
+
+var INTEGER = '[-+]?\\d+';
+var NUMBER = '[-+]?\\d*\\.?\\d+';
+var PERCENTAGE = NUMBER + '%';
+
+function call(...args) {
+  return '\\(\\s*(' + args.join(')\\s*,\\s*(') + ')\\s*\\)';
+}
+
+var matchers = {
+  rgb: new RegExp('rgb' + call(INTEGER, INTEGER, INTEGER)),
+  rgba: new RegExp('rgba' + call(INTEGER, INTEGER, INTEGER, NUMBER)),
+  hsl: new RegExp('hsl' + call(NUMBER, PERCENTAGE, PERCENTAGE)),
+  hsla: new RegExp('hsla' + call(NUMBER, PERCENTAGE, PERCENTAGE, NUMBER)),
+  hex3: /^#([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
+  hex4: /^#([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
+  hex6: /^#([0-9a-fA-F]{6})$/,
+  hex8: /^#([0-9a-fA-F]{8})$/,
+};
+
+function parse255(str: string): number {
+  var int = parseInt(str, 10);
+  if (int < 0) {
+    return 0;
+  }
+  if (int > 255) {
+    return 255;
+  }
+  return int;
+}
+
+function parse360(str: string): number {
+  var int = parseFloat(str);
+  return (((int % 360) + 360) % 360) / 360;
+}
+
+function parse1(str: string): number {
+  var num = parseFloat(str);
+  if (num < 0) {
+    return 0;
+  }
+  if (num > 1) {
+    return 255;
+  }
+  return Math.round(num * 255);
+}
+
+function parsePercentage(str: string): number {
+  // parseFloat conveniently ignores the final %
+  var int = parseFloat(str, 10);
+  if (int < 0) {
+    return 0;
+  }
+  if (int > 100) {
+    return 1;
+  }
+  return int / 100;
+}
+
+var names = {
+  transparent: 0x00000000,
+
+  // http://www.w3.org/TR/css3-color/#svg-color
+  aliceblue: 0xfff0f8ff,
+  antiquewhite: 0xfffaebd7,
+  aqua: 0xff00ffff,
+  aquamarine: 0xff7fffd4,
+  azure: 0xfff0ffff,
+  beige: 0xfff5f5dc,
+  bisque: 0xffffe4c4,
+  black: 0xff000000,
+  blanchedalmond: 0xffffebcd,
+  blue: 0xff0000ff,
+  blueviolet: 0xff8a2be2,
+  brown: 0xffa52a2a,
+  burlywood: 0xffdeb887,
+  burntsienna: 0xffea7e5d,
+  cadetblue: 0xff5f9ea0,
+  chartreuse: 0xff7fff00,
+  chocolate: 0xffd2691e,
+  coral: 0xffff7f50,
+  cornflowerblue: 0xff6495ed,
+  cornsilk: 0xfffff8dc,
+  crimson: 0xffdc143c,
+  cyan: 0xff00ffff,
+  darkblue: 0xff00008b,
+  darkcyan: 0xff008b8b,
+  darkgoldenrod: 0xffb8860b,
+  darkgray: 0xffa9a9a9,
+  darkgreen: 0xff006400,
+  darkgrey: 0xffa9a9a9,
+  darkkhaki: 0xffbdb76b,
+  darkmagenta: 0xff8b008b,
+  darkolivegreen: 0xff556b2f,
+  darkorange: 0xffff8c00,
+  darkorchid: 0xff9932cc,
+  darkred: 0xff8b0000,
+  darksalmon: 0xffe9967a,
+  darkseagreen: 0xff8fbc8f,
+  darkslateblue: 0xff483d8b,
+  darkslategray: 0xff2f4f4f,
+  darkslategrey: 0xff2f4f4f,
+  darkturquoise: 0xff00ced1,
+  darkviolet: 0xff9400d3,
+  deeppink: 0xffff1493,
+  deepskyblue: 0xff00bfff,
+  dimgray: 0xff696969,
+  dimgrey: 0xff696969,
+  dodgerblue: 0xff1e90ff,
+  firebrick: 0xffb22222,
+  floralwhite: 0xfffffaf0,
+  forestgreen: 0xff228b22,
+  fuchsia: 0xffff00ff,
+  gainsboro: 0xffdcdcdc,
+  ghostwhite: 0xfff8f8ff,
+  gold: 0xffffd700,
+  goldenrod: 0xffdaa520,
+  gray: 0xff808080,
+  green: 0xff008000,
+  greenyellow: 0xffadff2f,
+  grey: 0xff808080,
+  honeydew: 0xfff0fff0,
+  hotpink: 0xffff69b4,
+  indianred: 0xffcd5c5c,
+  indigo: 0xff4b0082,
+  ivory: 0xfffffff0,
+  khaki: 0xfff0e68c,
+  lavender: 0xffe6e6fa,
+  lavenderblush: 0xfffff0f5,
+  lawngreen: 0xff7cfc00,
+  lemonchiffon: 0xfffffacd,
+  lightblue: 0xffadd8e6,
+  lightcoral: 0xfff08080,
+  lightcyan: 0xffe0ffff,
+  lightgoldenrodyellow: 0xfffafad2,
+  lightgray: 0xffd3d3d3,
+  lightgreen: 0xff90ee90,
+  lightgrey: 0xffd3d3d3,
+  lightpink: 0xffffb6c1,
+  lightsalmon: 0xffffa07a,
+  lightseagreen: 0xff20b2aa,
+  lightskyblue: 0xff87cefa,
+  lightslategray: 0xff778899,
+  lightslategrey: 0xff778899,
+  lightsteelblue: 0xffb0c4de,
+  lightyellow: 0xffffffe0,
+  lime: 0xff00ff00,
+  limegreen: 0xff32cd32,
+  linen: 0xfffaf0e6,
+  magenta: 0xffff00ff,
+  maroon: 0xff800000,
+  mediumaquamarine: 0xff66cdaa,
+  mediumblue: 0xff0000cd,
+  mediumorchid: 0xffba55d3,
+  mediumpurple: 0xff9370db,
+  mediumseagreen: 0xff3cb371,
+  mediumslateblue: 0xff7b68ee,
+  mediumspringgreen: 0xff00fa9a,
+  mediumturquoise: 0xff48d1cc,
+  mediumvioletred: 0xffc71585,
+  midnightblue: 0xff191970,
+  mintcream: 0xfff5fffa,
+  mistyrose: 0xffffe4e1,
+  moccasin: 0xffffe4b5,
+  navajowhite: 0xffffdead,
+  navy: 0xff000080,
+  oldlace: 0xfffdf5e6,
+  olive: 0xff808000,
+  olivedrab: 0xff6b8e23,
+  orange: 0xffffa500,
+  orangered: 0xffff4500,
+  orchid: 0xffda70d6,
+  palegoldenrod: 0xffeee8aa,
+  palegreen: 0xff98fb98,
+  paleturquoise: 0xffafeeee,
+  palevioletred: 0xffdb7093,
+  papayawhip: 0xffffefd5,
+  peachpuff: 0xffffdab9,
+  peru: 0xffcd853f,
+  pink: 0xffffc0cb,
+  plum: 0xffdda0dd,
+  powderblue: 0xffb0e0e6,
+  purple: 0xff800080,
+  rebeccapurple: 0xff663399,
+  red: 0xffff0000,
+  rosybrown: 0xffbc8f8f,
+  royalblue: 0xff4169e1,
+  saddlebrown: 0xff8b4513,
+  salmon: 0xfffa8072,
+  sandybrown: 0xfff4a460,
+  seagreen: 0xff2e8b57,
+  seashell: 0xfffff5ee,
+  sienna: 0xffa0522d,
+  silver: 0xffc0c0c0,
+  skyblue: 0xff87ceeb,
+  slateblue: 0xff6a5acd,
+  slategray: 0xff708090,
+  slategrey: 0xff708090,
+  snow: 0xfffffafa,
+  springgreen: 0xff00ff7f,
+  steelblue: 0xff4682b4,
+  tan: 0xffd2b48c,
+  teal: 0xff008080,
+  thistle: 0xffd8bfd8,
+  tomato: 0xffff6347,
+  turquoise: 0xff40e0d0,
+  violet: 0xffee82ee,
+  wheat: 0xfff5deb3,
+  white: 0xffffffff,
+  whitesmoke: 0xfff5f5f5,
+  yellow: 0xffffff00,
+  yellowgreen: 0xff9acd32,
+};
+
+module.exports = normalizeColor;
diff --git a/Libraries/StyleSheet/processColor.js b/Libraries/StyleSheet/processColor.js
index 09ea0369733c..9e93ae88fb4f 100644
--- a/Libraries/StyleSheet/processColor.js
+++ b/Libraries/StyleSheet/processColor.js
@@ -10,33 +10,29 @@
  */
 'use strict';
 
-var tinycolor = require('tinycolor');
 var Platform = require('Platform');
 
+var normalizeColor = require('normalizeColor');
+
 /* eslint no-bitwise: 0 */
 function processColor(color) {
-  if (!color || typeof color === 'number') {
+  if (color === undefined || color === null) {
     return color;
-  } else if (color instanceof Array) {
-    return color.map(processColor);
-  } else {
-    var color = tinycolor(color);
-    if (color.isValid()) {
-      var rgb = color.toRgb();
-      // All bitwise operations happen on 32-bit numbers, so we shift the 1 first
-      // then multiply it with the actual value.
-      var colorInt = Math.round(rgb.a * 255) * (1 << 24) + rgb.r * (1 << 16) + rgb.g * (1 << 8) + rgb.b;
-      if (Platform.OS === 'android') {
-        // Android use 32 bit *signed* integer to represent the color
-        // We utilize the fact that bitwise operations in JS also operates on
-        // signed 32 bit integers, so that we can use those to convert from
-        // *unsigned* to *signed* 32bit int that way.
-        colorInt = colorInt | 0x0;
-      }
-      return colorInt;
-    }
-    return 0;
   }
+
+  var int32Color = normalizeColor(color);
+  if (int32Color === null) {
+    return undefined;
+  }
+
+  if (Platform.OS === 'android') {
+    // Android use 32 bit *signed* integer to represent the color
+    // We utilize the fact that bitwise operations in JS also operates on
+    // signed 32 bit integers, so that we can use those to convert from
+    // *unsigned* to *signed* 32bit int that way.
+    int32Color = int32Color | 0x0;
+  }
+  return int32Color;
 }
 
 module.exports = processColor;
diff --git a/Libraries/vendor/tinycolor/tinycolor.js b/Libraries/vendor/tinycolor/tinycolor.js
deleted file mode 100755
index 7035bc166fba..000000000000
--- a/Libraries/vendor/tinycolor/tinycolor.js
+++ /dev/null
@@ -1,503 +0,0 @@
-/**
- * @providesModule tinycolor
- * @nolint
- */
-'use strict';
-
-// TinyColor v1.2.1
-// https://github.com/bgrins/TinyColor
-// Brian Grinstead, MIT License
-
-var trimLeft = /^[\s,#]+/,
-    trimRight = /\s+$/,
-    tinyCounter = 0,
-    mathRound = Math.round,
-    mathMin = Math.min,
-    mathMax = Math.max;
-
-function tinycolor (color, opts) {
-    // If we are called as a function, call using new instead
-    if (!(this instanceof tinycolor)) {
-        return new tinycolor(color, opts);
-    }
-
-    color = (color) ? color : '';
-    opts = opts || { };
-
-    var rgb = inputToRGB(color);
-    this._r = rgb.r,
-    this._g = rgb.g,
-    this._b = rgb.b,
-    this._a = rgb.a,
-
-    this._ok = rgb.ok;
-}
-
-tinycolor.prototype = {
-    toRgb: function() {
-        return { r: mathRound(this._r), g: mathRound(this._g), b: mathRound(this._b), a: this._a };
-    },
-    isValid: function() {
-        return this._ok;
-    },
-};
-
-// Given a string or object, convert that input to RGB
-// Possible string inputs:
-//
-//     "red"
-//     "#f00" or "f00"
-//     "#f00f" or "f00f"
-//     "#ff0000" or "ff0000"
-//     "#ff0000ff" or "ff0000ff"
-//     "rgb 255 0 0" or "rgb (255, 0, 0)"
-//     "rgb 1.0 0 0" or "rgb (1, 0, 0)"
-//     "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1"
-//     "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1"
-//     "hsl(0, 100%, 50%)" or "hsl 0 100% 50%"
-//     "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1"
-//     "hsv(0, 100%, 100%)" or "hsv 0 100% 100%"
-//
-function inputToRGB(color) {
-    var rgb = { r: 0, g: 0, b: 0 };
-    var a = 1;
-    var ok = false;
-    var format = false;
-
-    if (typeof color == "string") {
-        color = stringInputToObject(color);
-    }
-
-    if (typeof color == "object") {
-        if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) {
-            rgb = rgbToRgb(color.r, color.g, color.b);
-            ok = true;
-        }
-        else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) {
-            color.s = convertToPercentage(color.s);
-            color.v = convertToPercentage(color.v);
-            rgb = hsvToRgb(color.h, color.s, color.v);
-            ok = true;
-        }
-        else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) {
-            color.s = convertToPercentage(color.s);
-            color.l = convertToPercentage(color.l);
-            rgb = hslToRgb(color.h, color.s, color.l);
-            ok = true;
-        }
-
-        if (color.hasOwnProperty("a")) {
-            a = color.a;
-        }
-    }
-
-    a = boundAlpha(a);
-
-    return {
-        ok: ok,
-        r: mathMin(255, mathMax(rgb.r, 0)),
-        g: mathMin(255, mathMax(rgb.g, 0)),
-        b: mathMin(255, mathMax(rgb.b, 0)),
-        a: a
-    };
-}
-
-
-// Conversion Functions
-// --------------------
-
-// `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from:
-// <http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript>
-
-// `rgbToRgb`
-// Handle bounds / percentage checking to conform to CSS color spec
-// <http://www.w3.org/TR/css3-color/>
-// *Assumes:* r, g, b in [0, 255] or [0, 1]
-// *Returns:* { r, g, b } in [0, 255]
-function rgbToRgb(r, g, b){
-    return {
-        r: bound01(r, 255) * 255,
-        g: bound01(g, 255) * 255,
-        b: bound01(b, 255) * 255
-    };
-}
-
-// `hslToRgb`
-// Converts an HSL color value to RGB.
-// *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100]
-// *Returns:* { r, g, b } in the set [0, 255]
-function hslToRgb(h, s, l) {
-    var r, g, b;
-
-    h = bound01(h, 360);
-    s = bound01(s, 100);
-    l = bound01(l, 100);
-
-    function hue2rgb(p, q, t) {
-        if(t < 0) t += 1;
-        if(t > 1) t -= 1;
-        if(t < 1/6) return p + (q - p) * 6 * t;
-        if(t < 1/2) return q;
-        if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
-        return p;
-    }
-
-    if(s === 0) {
-        r = g = b = l; // achromatic
-    }
-    else {
-        var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
-        var p = 2 * l - q;
-        r = hue2rgb(p, q, h + 1/3);
-        g = hue2rgb(p, q, h);
-        b = hue2rgb(p, q, h - 1/3);
-    }
-
-    return { r: r * 255, g: g * 255, b: b * 255 };
-}
-
-// `hsvToRgb`
-// Converts an HSV color value to RGB.
-// *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100]
-// *Returns:* { r, g, b } in the set [0, 255]
- function hsvToRgb(h, s, v) {
-    h = bound01(h, 360) * 6;
-    s = bound01(s, 100);
-    v = bound01(v, 100);
-
-    var i = math.floor(h),
-        f = h - i,
-        p = v * (1 - s),
-        q = v * (1 - f * s),
-        t = v * (1 - (1 - f) * s),
-        mod = i % 6,
-        r = [v, q, p, p, t, v][mod],
-        g = [t, v, v, q, p, p][mod],
-        b = [p, p, t, v, v, q][mod];
-
-    return { r: r * 255, g: g * 255, b: b * 255 };
-}
-
-// Big List of Colors
-// ------------------
-// <http://www.w3.org/TR/css3-color/#svg-color>
-var names = tinycolor.names = {
-    aliceblue: "f0f8ff",
-    antiquewhite: "faebd7",
-    aqua: "0ff",
-    aquamarine: "7fffd4",
-    azure: "f0ffff",
-    beige: "f5f5dc",
-    bisque: "ffe4c4",
-    black: "000",
-    blanchedalmond: "ffebcd",
-    blue: "00f",
-    blueviolet: "8a2be2",
-    brown: "a52a2a",
-    burlywood: "deb887",
-    burntsienna: "ea7e5d",
-    cadetblue: "5f9ea0",
-    chartreuse: "7fff00",
-    chocolate: "d2691e",
-    coral: "ff7f50",
-    cornflowerblue: "6495ed",
-    cornsilk: "fff8dc",
-    crimson: "dc143c",
-    cyan: "0ff",
-    darkblue: "00008b",
-    darkcyan: "008b8b",
-    darkgoldenrod: "b8860b",
-    darkgray: "a9a9a9",
-    darkgreen: "006400",
-    darkgrey: "a9a9a9",
-    darkkhaki: "bdb76b",
-    darkmagenta: "8b008b",
-    darkolivegreen: "556b2f",
-    darkorange: "ff8c00",
-    darkorchid: "9932cc",
-    darkred: "8b0000",
-    darksalmon: "e9967a",
-    darkseagreen: "8fbc8f",
-    darkslateblue: "483d8b",
-    darkslategray: "2f4f4f",
-    darkslategrey: "2f4f4f",
-    darkturquoise: "00ced1",
-    darkviolet: "9400d3",
-    deeppink: "ff1493",
-    deepskyblue: "00bfff",
-    dimgray: "696969",
-    dimgrey: "696969",
-    dodgerblue: "1e90ff",
-    firebrick: "b22222",
-    floralwhite: "fffaf0",
-    forestgreen: "228b22",
-    fuchsia: "f0f",
-    gainsboro: "dcdcdc",
-    ghostwhite: "f8f8ff",
-    gold: "ffd700",
-    goldenrod: "daa520",
-    gray: "808080",
-    green: "008000",
-    greenyellow: "adff2f",
-    grey: "808080",
-    honeydew: "f0fff0",
-    hotpink: "ff69b4",
-    indianred: "cd5c5c",
-    indigo: "4b0082",
-    ivory: "fffff0",
-    khaki: "f0e68c",
-    lavender: "e6e6fa",
-    lavenderblush: "fff0f5",
-    lawngreen: "7cfc00",
-    lemonchiffon: "fffacd",
-    lightblue: "add8e6",
-    lightcoral: "f08080",
-    lightcyan: "e0ffff",
-    lightgoldenrodyellow: "fafad2",
-    lightgray: "d3d3d3",
-    lightgreen: "90ee90",
-    lightgrey: "d3d3d3",
-    lightpink: "ffb6c1",
-    lightsalmon: "ffa07a",
-    lightseagreen: "20b2aa",
-    lightskyblue: "87cefa",
-    lightslategray: "789",
-    lightslategrey: "789",
-    lightsteelblue: "b0c4de",
-    lightyellow: "ffffe0",
-    lime: "0f0",
-    limegreen: "32cd32",
-    linen: "faf0e6",
-    magenta: "f0f",
-    maroon: "800000",
-    mediumaquamarine: "66cdaa",
-    mediumblue: "0000cd",
-    mediumorchid: "ba55d3",
-    mediumpurple: "9370db",
-    mediumseagreen: "3cb371",
-    mediumslateblue: "7b68ee",
-    mediumspringgreen: "00fa9a",
-    mediumturquoise: "48d1cc",
-    mediumvioletred: "c71585",
-    midnightblue: "191970",
-    mintcream: "f5fffa",
-    mistyrose: "ffe4e1",
-    moccasin: "ffe4b5",
-    navajowhite: "ffdead",
-    navy: "000080",
-    oldlace: "fdf5e6",
-    olive: "808000",
-    olivedrab: "6b8e23",
-    orange: "ffa500",
-    orangered: "ff4500",
-    orchid: "da70d6",
-    palegoldenrod: "eee8aa",
-    palegreen: "98fb98",
-    paleturquoise: "afeeee",
-    palevioletred: "db7093",
-    papayawhip: "ffefd5",
-    peachpuff: "ffdab9",
-    peru: "cd853f",
-    pink: "ffc0cb",
-    plum: "dda0dd",
-    powderblue: "b0e0e6",
-    purple: "800080",
-    rebeccapurple: "663399",
-    red: "f00",
-    rosybrown: "bc8f8f",
-    royalblue: "4169e1",
-    saddlebrown: "8b4513",
-    salmon: "fa8072",
-    sandybrown: "f4a460",
-    seagreen: "2e8b57",
-    seashell: "fff5ee",
-    sienna: "a0522d",
-    silver: "c0c0c0",
-    skyblue: "87ceeb",
-    slateblue: "6a5acd",
-    slategray: "708090",
-    slategrey: "708090",
-    snow: "fffafa",
-    springgreen: "00ff7f",
-    steelblue: "4682b4",
-    tan: "d2b48c",
-    teal: "008080",
-    thistle: "d8bfd8",
-    tomato: "ff6347",
-    turquoise: "40e0d0",
-    violet: "ee82ee",
-    wheat: "f5deb3",
-    white: "fff",
-    whitesmoke: "f5f5f5",
-    yellow: "ff0",
-    yellowgreen: "9acd32"
-};
-
-// Return a valid alpha value [0,1] with all invalid values being set to 1
-function boundAlpha(a) {
-    a = parseFloat(a);
-
-    if (isNaN(a) || a < 0 || a > 1) {
-        a = 1;
-    }
-
-    return a;
-}
-
-// Take input from [0, n] and return it as [0, 1]
-function bound01(n, max) {
-    if (isOnePointZero(n)) { n = "100%"; }
-
-    var processPercent = isPercentage(n);
-    n = mathMin(max, mathMax(0, parseFloat(n)));
-
-    // Automatically convert percentage into number
-    if (processPercent) {
-        n = parseInt(n * max, 10) / 100;
-    }
-
-    // Handle floating point rounding errors
-    if ((Math.abs(n - max) < 0.000001)) {
-        return 1;
-    }
-
-    // Convert into [0, 1] range if it isn't already
-    return (n % max) / parseFloat(max);
-}
-
-// Parse a base-16 hex value into a base-10 integer
-function parseIntFromHex(val) {
-    return parseInt(val, 16);
-}
-
-// Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1
-// <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0>
-function isOnePointZero(n) {
-    return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1;
-}
-
-// Check to see if string passed in is a percentage
-function isPercentage(n) {
-    return typeof n === "string" && n.indexOf('%') != -1;
-}
-
-// Replace a decimal with it's percentage value
-function convertToPercentage(n) {
-    if (n <= 1) {
-        n = (n * 100) + "%";
-    }
-
-    return n;
-}
-
-// Converts a hex value to a decimal
-function convertHexToDecimal(h) {
-    return (parseIntFromHex(h) / 255);
-}
-
-var matchers = (function() {
-    // <http://www.w3.org/TR/css3-values/#integers>
-    var CSS_INTEGER = "[-\\+]?\\d+%?";
-
-    // <http://www.w3.org/TR/css3-values/#number-value>
-    var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?";
-
-    // Allow positive/negative integer/number.  Don't capture the either/or, just the entire outcome.
-    var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")";
-
-    // Actual matching.
-    // Parentheses and commas are optional, but not required.
-    // Whitespace can take the place of commas or opening paren
-    var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
-    var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
-
-    return {
-        rgb: new RegExp("rgb" + PERMISSIVE_MATCH3),
-        rgba: new RegExp("rgba" + PERMISSIVE_MATCH4),
-        hsl: new RegExp("hsl" + PERMISSIVE_MATCH3),
-        hsla: new RegExp("hsla" + PERMISSIVE_MATCH4),
-        hsv: new RegExp("hsv" + PERMISSIVE_MATCH3),
-        hsva: new RegExp("hsva" + PERMISSIVE_MATCH4),
-        hex3: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
-        hex4: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
-        hex6: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
-        hex8: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
-    };
-})();
-
-// `stringInputToObject`
-// Permissive string parsing.  Take in a number of formats, and output an object
-// based on detected format.  Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}`
-function stringInputToObject(color) {
-    color = color.replace(trimLeft,'').replace(trimRight, '').toLowerCase();
-    var named = false;
-    if (names[color]) {
-        color = names[color];
-        named = true;
-    }
-    else if (color == 'transparent') {
-        return { r: 0, g: 0, b: 0, a: 0, format: "name" };
-    }
-
-    // Try to match string input using regular expressions.
-    // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360]
-    // Just return an object and let the conversion functions handle that.
-    // This way the result will be the same whether the tinycolor is initialized with string or object.
-    var match;
-    if ((match = matchers.rgb.exec(color))) {
-        return { r: match[1], g: match[2], b: match[3] };
-    }
-    if ((match = matchers.rgba.exec(color))) {
-        return { r: match[1], g: match[2], b: match[3], a: match[4] };
-    }
-    if ((match = matchers.hsl.exec(color))) {
-        return { h: match[1], s: match[2], l: match[3] };
-    }
-    if ((match = matchers.hsla.exec(color))) {
-        return { h: match[1], s: match[2], l: match[3], a: match[4] };
-    }
-    if ((match = matchers.hsv.exec(color))) {
-        return { h: match[1], s: match[2], v: match[3] };
-    }
-    if ((match = matchers.hsva.exec(color))) {
-        return { h: match[1], s: match[2], v: match[3], a: match[4] };
-    }
-    if ((match = matchers.hex8.exec(color))) {
-        return {
-            r: parseIntFromHex(match[1]),
-            g: parseIntFromHex(match[2]),
-            b: parseIntFromHex(match[3]),
-            a: convertHexToDecimal(match[4]),
-            format: named ? "name" : "hex"
-        };
-    }
-    if ((match = matchers.hex6.exec(color))) {
-        return {
-            r: parseIntFromHex(match[1]),
-            g: parseIntFromHex(match[2]),
-            b: parseIntFromHex(match[3]),
-            format: named ? "name" : "hex"
-        };
-    }
-    if ((match = matchers.hex4.exec(color))) {
-        return {
-            r: parseIntFromHex(match[1] + '' + match[1]),
-            g: parseIntFromHex(match[2] + '' + match[2]),
-            b: parseIntFromHex(match[3] + '' + match[3]),
-            a: convertHexToDecimal(match[4] + '' + match[4]),
-            format: named ? "name" : "hex"
-        };
-    }
-    if ((match = matchers.hex3.exec(color))) {
-        return {
-            r: parseIntFromHex(match[1] + '' + match[1]),
-            g: parseIntFromHex(match[2] + '' + match[2]),
-            b: parseIntFromHex(match[3] + '' + match[3]),
-            format: named ? "name" : "hex"
-        };
-    }
-
-    return false;
-}
-
-module.exports = tinycolor;

From 65b8ff17f324facf2739eb120261cb768bfe5153 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Fri, 29 Jan 2016 10:14:37 -0800
Subject: [PATCH 0939/1411] Make HMR faster

Summary:
public

At the moment, when the user changes a file we end up pulling the dependencies of the entry point to build the bundle. This could take a long time if the bundle is big. To avoid it, lets introduce a new parameter to `getDependencies` to be able to avoid processing the modules recursively and reuse the resolution responseto build the bundle.

Reviewed By: davidaurelio

Differential Revision: D2862850

fb-gh-sync-id: b8ae2b811a8ae9aec5612f9655d1c762671ce730
---
 local-cli/server/util/attachHMRServer.js      | 30 +++++++--
 .../src/Bundler/__tests__/Bundler-test.js     | 11 ++--
 packager/react-packager/src/Bundler/index.js  | 63 ++++++++++++++-----
 .../DependencyGraph/ResolutionRequest.js      |  6 +-
 .../DependencyGraph/index.js                  |  8 ++-
 .../src/Resolver/__tests__/Resolver-test.js   |  3 +-
 packager/react-packager/src/Resolver/index.js | 22 ++++---
 packager/react-packager/src/Server/index.js   |  5 ++
 8 files changed, 112 insertions(+), 36 deletions(-)

diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js
index c3ea086ed978..ef2e3be55d79 100644
--- a/local-cli/server/util/attachHMRServer.js
+++ b/local-cli/server/util/attachHMRServer.js
@@ -74,6 +74,7 @@ function attachHMRServer({httpServer, path, packagerServer}) {
             dependenciesCache,
             dependenciesModulesCache,
             shallowDependencies,
+            resolutionResponse: response,
           };
         });
       });
@@ -123,7 +124,23 @@ function attachHMRServer({httpServer, path, packagerServer}) {
                 // to the client may have changed
                 const oldDependencies = client.shallowDependencies[filename];
                 if (arrayEquals(deps, oldDependencies)) {
-                  return [packagerServer.getModuleForPath(filename)];
+                  // Need to create a resolution response to pass to the bundler
+                  // to process requires after transform. By providing a
+                  // specific response we can compute a non recursive one which
+                  // is the least we need and improve performance.
+                  return packagerServer.getDependencies({
+                    platform: client.platform,
+                    dev: true,
+                    entryFile: filename,
+                    recursive: true,
+                  }).then(response => {
+                    const module = packagerServer.getModuleForPath(filename);
+
+                    return {
+                      modulesToUpdate: [module],
+                      resolutionResponse: response,
+                    };
+                  });
                 }
 
                 // if there're new dependencies compare the full list of
@@ -133,9 +150,10 @@ function attachHMRServer({httpServer, path, packagerServer}) {
                     dependenciesCache,
                     dependenciesModulesCache,
                     shallowDependencies,
+                    resolutionResponse,
                   }) => {
                     if (!client) {
-                      return [];
+                      return {};
                     }
 
                     // build list of modules for which we'll send HMR updates
@@ -151,10 +169,13 @@ function attachHMRServer({httpServer, path, packagerServer}) {
                     client.dependenciesModulesCache = dependenciesModulesCache;
                     client.shallowDependencies = shallowDependencies;
 
-                    return modulesToUpdate;
+                    return {
+                      modulesToUpdate,
+                      resolutionResponse,
+                    };
                   });
               })
-              .then(modulesToUpdate => {
+              .then(({modulesToUpdate, resolutionResponse}) => {
                 if (!client) {
                   return;
                 }
@@ -168,6 +189,7 @@ function attachHMRServer({httpServer, path, packagerServer}) {
                   entryFile: client.bundleEntry,
                   platform: client.platform,
                   modules: modulesToUpdate,
+                  resolutionResponse,
                 })
               })
               .then(bundle => {
diff --git a/packager/react-packager/src/Bundler/__tests__/Bundler-test.js b/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
index 467cf90d69ce..5ed7d65877d8 100644
--- a/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
+++ b/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
@@ -206,11 +206,12 @@ describe('Bundler', function() {
   });
 
   pit('gets the list of dependencies from the resolver', function() {
-    return bundler.getDependencies('/root/foo.js', true)
-      .then(
-        () => expect(getDependencies)
-                .toBeCalledWith('/root/foo.js', { dev: true })
-      );
+    return bundler.getDependencies('/root/foo.js', true).then(() =>
+      expect(getDependencies).toBeCalledWith(
+        '/root/foo.js',
+        { dev: true, recursive: true },
+      )
+    );
   });
 
   describe('getOrderedDependencyPaths', () => {
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index b0ccc235ef59..d03fdb89a28e 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -235,14 +235,48 @@ class Bundler {
     unbundle: isUnbundle,
     hot: hot,
     entryModuleOnly,
+    resolutionResponse,
   }) {
-    const findEventId = Activity.startEvent('find dependencies');
     let transformEventId;
+    const moduleSystemDeps = includeSystemDependencies
+      ? this._resolver.getModuleSystemDependencies(
+        { dev: isDev, platform, isUnbundle }
+      )
+      : [];
+
+    const findModules = () => {
+      const findEventId = Activity.startEvent('find dependencies');
+      return this.getDependencies(entryFile, isDev, platform).then(response => {
+        Activity.endEvent(findEventId);
+        bundle.setMainModuleId(response.mainModuleId);
+        bundle.setMainModuleName(response.mainModuleId);
+        if (!entryModuleOnly && bundle.setNumPrependedModules) {
+          bundle.setNumPrependedModules(
+            response.numPrependedDependencies + moduleSystemDeps.length
+          );
+        }
+
+        return {
+          response,
+          modulesToProcess: response.dependencies,
+        };
+      });
+    };
+
+    const useProvidedModules = () => {
+      const moduleId = this._resolver.getModuleForPath(entryFile);
+      bundle.setMainModuleId(moduleId);
+      bundle.setMainModuleName(moduleId);
+      return Promise.resolve({
+        response: resolutionResponse,
+        modulesToProcess: modules
+      });
+    };
+
+    return (
+      modules ? useProvidedModules() : findModules()
+    ).then(({response, modulesToProcess}) => {
 
-    return this.getDependencies(entryFile, isDev, platform).then((response) => {
-      Activity.endEvent(findEventId);
-      bundle.setMainModuleId(response.mainModuleId);
-      bundle.setMainModuleName(response.mainModuleId);
       transformEventId = Activity.startEvent('transform');
 
       let dependencies;
@@ -259,10 +293,6 @@ class Bundler {
 
         const modulesToProcess = modules || response.dependencies;
         dependencies = moduleSystemDeps.concat(modulesToProcess);
-
-        bundle.setNumPrependedModules && bundle.setNumPrependedModules(
-          response.numPrependedDependencies + moduleSystemDeps.length
-        );
       }
 
       let bar;
@@ -280,7 +310,6 @@ class Bundler {
           module => {
             return this._transformModule(
               bundle,
-              response,
               module,
               platform,
               isDev,
@@ -347,7 +376,6 @@ class Bundler {
         response.dependencies.map(
           module => this._transformModule(
             bundle,
-            response,
             module,
             platform,
             isDev,
@@ -418,8 +446,15 @@ class Bundler {
     return this._resolver.getModuleForPath(entryFile);
   }
 
-  getDependencies(main, isDev, platform) {
-    return this._resolver.getDependencies(main, { dev: isDev, platform });
+  getDependencies(main, isDev, platform, recursive = true) {
+    return this._resolver.getDependencies(
+      main,
+      {
+        dev: isDev,
+        platform,
+        recursive,
+      },
+    );
   }
 
   getOrderedDependencyPaths({ entryFile, dev, platform }) {
@@ -454,7 +489,7 @@ class Bundler {
     );
   }
 
-  _transformModule(bundle, response, module, platform = null, dev = true, hot = false) {
+  _transformModule(bundle, module, platform = null, dev = true, hot = false) {
     if (module.isAsset_DEPRECATED()) {
       return this._generateAssetModule_DEPRECATED(bundle, module);
     } else if (module.isAsset()) {
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
index 58dcc7d1c36e..149cab010b3f 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
@@ -103,7 +103,7 @@ class ResolutionRequest {
       );
   }
 
-  getOrderedDependencies(response, mocksPattern) {
+  getOrderedDependencies(response, mocksPattern, recursive = true) {
     return this._getAllMocks(mocksPattern).then(allMocks => {
       const entry = this._moduleCache.getModule(this._entryPath);
       const mocks = Object.create(null);
@@ -163,7 +163,9 @@ class ResolutionRequest {
             p = p.then(() => {
               if (!visited[modDep.hash()]) {
                 visited[modDep.hash()] = true;
-                return collect(modDep);
+                if (recursive) {
+                  return collect(modDep);
+                }
               }
               return null;
             });
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
index 023fca506ec8..273b9b587689 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
@@ -158,7 +158,7 @@ class DependencyGraph {
     return this._moduleCache.getModule(entryFile);
   }
 
-  getDependencies(entryPath, platform) {
+  getDependencies(entryPath, platform, recursive = true) {
     return this.load().then(() => {
       platform = this._getRequestPlatform(entryPath, platform);
       const absPath = this._getAbsolutePath(entryPath);
@@ -177,7 +177,11 @@ class DependencyGraph {
       const response = new ResolutionResponse();
 
       return Promise.all([
-        req.getOrderedDependencies(response, this._opts.mocksPattern),
+        req.getOrderedDependencies(
+          response,
+          this._opts.mocksPattern,
+          recursive,
+        ),
         req.getAsyncDependencies(response),
       ]).then(() => response);
     });
diff --git a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
index b542d43b1d33..962bba9681d0 100644
--- a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
+++ b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
@@ -186,7 +186,8 @@ describe('Resolver', function() {
       return depResolver.getDependencies('/root/index.js', { dev: true })
         .then(function(result) {
           expect(result.mainModuleId).toEqual('index');
-          expect(DependencyGraph.mock.instances[0].getDependencies).toBeCalledWith('/root/index.js', undefined);
+          expect(DependencyGraph.mock.instances[0].getDependencies)
+              .toBeCalledWith('/root/index.js', undefined, true);
           expect(result.dependencies[0]).toBe(Polyfill.mock.instances[0]);
           expect(result.dependencies[result.dependencies.length - 1])
               .toBe(module);
diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index 4cb4707f1283..4f3444ecd515 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -64,6 +64,10 @@ const getDependenciesValidateOpts = declareOpts({
     type: 'boolean',
     default: false
   },
+  recursive: {
+    type: 'boolean',
+    default: true,
+  },
 });
 
 class Resolver {
@@ -116,15 +120,17 @@ class Resolver {
   getDependencies(main, options) {
     const opts = getDependenciesValidateOpts(options);
 
-    return this._depGraph.getDependencies(main, opts.platform).then(
-      resolutionResponse => {
-        this._getPolyfillDependencies().reverse().forEach(
-          polyfill => resolutionResponse.prependDependency(polyfill)
-        );
+    return this._depGraph.getDependencies(
+      main,
+      opts.platform,
+      opts.recursive,
+    ).then(resolutionResponse => {
+      this._getPolyfillDependencies().reverse().forEach(
+        polyfill => resolutionResponse.prependDependency(polyfill)
+      );
 
-        return resolutionResponse.finalize();
-      }
-    );
+      return resolutionResponse.finalize();
+    });
   }
 
   getModuleSystemDependencies(options) {
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index 559fb3022f4e..defbf5a5b633 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -137,6 +137,10 @@ const dependencyOpts = declareOpts({
     type: 'string',
     required: true,
   },
+  recursive: {
+    type: 'boolean',
+    default: true,
+  },
 });
 
 class Server {
@@ -269,6 +273,7 @@ class Server {
         opts.entryFile,
         opts.dev,
         opts.platform,
+        opts.recursive,
       );
     });
   }

From 68f71dab4c353d662c91e5951b406f46717517c4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Fri, 29 Jan 2016 10:14:43 -0800
Subject: [PATCH 0940/1411] Make HMR faster (2)

Summary:
public

The HMR listener needs to be invoked on the non debounced callback to avoid loosing updates if 2 files are updated within the debounce configured time.

Also, improve the time it takes to send HMR updates by avoiding rebuilding the bundle when the listener is defined. Instead just invalidate the bundles cache so that if the user reloads or disables Hot Loading the packager rebuilds the requested bundle.

Reviewed By: davidaurelio

Differential Revision: D2863141

fb-gh-sync-id: 3ab500eacbd4a2e4b63619755e5eabf8afdd1db9
---
 local-cli/server/util/attachHMRServer.js      |  4 +-
 .../src/Server/__tests__/Server-test.js       | 64 +++++++++++++++----
 packager/react-packager/src/Server/index.js   | 34 +++++-----
 3 files changed, 69 insertions(+), 33 deletions(-)

diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js
index ef2e3be55d79..9eb62b5516a0 100644
--- a/local-cli/server/util/attachHMRServer.js
+++ b/local-cli/server/util/attachHMRServer.js
@@ -109,10 +109,10 @@ function attachHMRServer({httpServer, path, packagerServer}) {
 
         packagerServer.setHMRFileChangeListener((filename, stat) => {
           if (!client) {
-            return Promise.resolve();
+            return;
           }
 
-          return stat.then(() => {
+          stat.then(() => {
             return packagerServer.getShallowDependencies(filename)
               .then(deps => {
                 if (!client) {
diff --git a/packager/react-packager/src/Server/__tests__/Server-test.js b/packager/react-packager/src/Server/__tests__/Server-test.js
index 668e162f0685..b731a026526e 100644
--- a/packager/react-packager/src/Server/__tests__/Server-test.js
+++ b/packager/react-packager/src/Server/__tests__/Server-test.js
@@ -194,18 +194,6 @@ describe('processRequest', () => {
     });
 
     it('rebuilds the bundles that contain a file when that file is changed', () => {
-      testChangingFileWith(() => new Server(options));
-    });
-
-    it('rebuilds the bundles that contain a file when that file is changed, even when hot loading is enabled', () => {
-      testChangingFileWith(() => {
-        const server = new Server(options);
-        server.setHMRFileChangeListener(() => Promise.resolve());
-        return server;
-      });
-    });
-
-    function testChangingFileWith(createServer) {
       const bundleFunc = jest.genMockFunction();
       bundleFunc
         .mockReturnValueOnce(
@@ -225,7 +213,7 @@ describe('processRequest', () => {
 
       Bundler.prototype.bundle = bundleFunc;
 
-      server = createServer();
+      server = new Server(options);
 
       requestHandler = server.processRequest.bind(server);
 
@@ -248,7 +236,55 @@ describe('processRequest', () => {
           expect(response.body).toEqual('this is the rebuilt source')
         );
       jest.runAllTicks();
-    }
+    });
+
+    it('rebuilds the bundles that contain a file when that file is changed, even when hot loading is enabled', () => {
+      const bundleFunc = jest.genMockFunction();
+      bundleFunc
+        .mockReturnValueOnce(
+          Promise.resolve({
+            getSource: () => 'this is the first source',
+            getSourceMap: () => {},
+            getEtag: () => () => 'this is an etag',
+          })
+        )
+        .mockReturnValue(
+          Promise.resolve({
+            getSource: () => 'this is the rebuilt source',
+            getSourceMap: () => {},
+            getEtag: () => () => 'this is an etag',
+          })
+        );
+
+      Bundler.prototype.bundle = bundleFunc;
+
+      const server = new Server(options);
+      server.setHMRFileChangeListener(() => {});
+
+      requestHandler = server.processRequest.bind(server);
+
+      makeRequest(requestHandler, 'mybundle.bundle?runModule=true')
+        .done(response => {
+          expect(response.body).toEqual('this is the first source');
+          expect(bundleFunc.mock.calls.length).toBe(1);
+        });
+
+      jest.runAllTicks();
+
+      triggerFileChange('all','path/file.js', options.projectRoots[0]);
+      jest.runAllTimers();
+      jest.runAllTicks();
+
+      expect(bundleFunc.mock.calls.length).toBe(1);
+      server.setHMRFileChangeListener(null);
+
+      makeRequest(requestHandler, 'mybundle.bundle?runModule=true')
+        .done(response => {
+          expect(response.body).toEqual('this is the rebuilt source');
+          expect(bundleFunc.mock.calls.length).toBe(2);
+        });
+      jest.runAllTicks();
+    });
   });
 
   describe('/onchange endpoint', () => {
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index defbf5a5b633..da8653f845b3 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -192,23 +192,8 @@ class Server {
     this._fileWatcher.on('all', this._onFileChange.bind(this));
 
     this._debouncedFileChangeHandler = _.debounce(filePath => {
-      const onFileChange = () => {
-        this._rebuildBundles(filePath);
-        this._informChangeWatchers();
-      };
-
-      // if Hot Loading is enabled avoid rebuilding bundles and sending live
-      // updates. Instead, send the HMR updates right away and once that
-      // finishes, invoke any other file change listener.
-      if (this._hmrFileChangeListener) {
-        this._hmrFileChangeListener(
-          filePath,
-          this._bundler.stat(filePath),
-        ).then(onFileChange).done();
-        return;
-      }
-
-      onFileChange();
+      this._rebuildBundles(filePath);
+      this._informChangeWatchers();
     }, 50);
   }
 
@@ -288,11 +273,26 @@ class Server {
   _onFileChange(type, filepath, root) {
     const absPath = path.join(root, filepath);
     this._bundler.invalidateFile(absPath);
+
+    // If Hot Loading is enabled avoid rebuilding bundles and sending live
+    // updates. Instead, send the HMR updates right away and clear the bundles
+    // cache so that if the user reloads we send them a fresh bundle
+    if (this._hmrFileChangeListener) {
+      // Clear cached bundles in case user reloads
+      this._clearBundles();
+      this._hmrFileChangeListener(absPath, this._bundler.stat(absPath));
+      return;
+    }
+
     // Make sure the file watcher event runs through the system before
     // we rebuild the bundles.
     this._debouncedFileChangeHandler(absPath);
   }
 
+  _clearBundles() {
+    this._bundles = Object.create(null);
+  }
+
   _rebuildBundles() {
     const buildBundle = this.buildBundle.bind(this);
     const bundles = this._bundles;

From 063e8b9ae5514cc5a0e401159a1320c31a4f5546 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Fri, 29 Jan 2016 12:20:23 -0800
Subject: [PATCH 0941/1411] revert D2862911: this broke ReactNative

Reviewed By: balazsbalazs

Differential Revision: D2879926

fb-gh-sync-id: 9f833c209128eaa00b111387ee57dbbc6b74fcb7
---
 .../react/views/image/ReactImageView.java     | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
index 36fa511c0282..be57d799d337 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
@@ -74,15 +74,16 @@ public class ReactImageView extends GenericDraweeView {
   private class RoundedCornerPostprocessor extends BasePostprocessor {
 
     float getRadius(Bitmap source) {
-      mScaleType.getTransform(
-          sMatrix,
-          new Rect(0, 0, source.getWidth(), source.getHeight()),
-          source.getWidth(),
-          source.getHeight(),
-          0.0f,
-          0.0f);
-      sMatrix.invert(sInverse);
-      return sInverse.mapRadius(mBorderRadius);
+        ScalingUtils.getTransform(
+            sMatrix,
+            new Rect(0, 0, source.getWidth(), source.getHeight()),
+            source.getWidth(),
+            source.getHeight(),
+            0.0f,
+            0.0f,
+            mScaleType);
+        sMatrix.invert(sInverse);
+        return sInverse.mapRadius(mBorderRadius);
     }
 
     @Override

From 041fb591460fd3a59b2ab37b059ddba54c6ee028 Mon Sep 17 00:00:00 2001
From: Krzysztof Magiera <krzys.magiera@gmail.com>
Date: Fri, 29 Jan 2016 13:25:43 -0800
Subject: [PATCH 0942/1411] Fix bug with calculating Y offset in
 RecyclerViewBackedScrollView.

Summary:
This change fixes a bug in getTopOffsetForItem method of RecyclerViewBackedScrollView that was causing Y offset of onScroll events to be invalid when user would scroll up. I'm also adding some comments to this method which may help to understand its complexity.
Closes https://github.com/facebook/react-native/pull/5610

Reviewed By: svcscm

Differential Revision: D2880743

Pulled By: androidtrunkagent

fb-gh-sync-id: 7183e3d6760fab5683afc49d454864239260fb91
---
 .../RecyclerViewBackedScrollView.java         | 46 ++++++++++++++++---
 1 file changed, 39 insertions(+), 7 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollView.java
index 919764f8481b..f1729c55ca32 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollView.java
@@ -114,25 +114,57 @@ public void onHeightChange(int index, int oldHeight, int newHeight) {
     }
 
     public int getTopOffsetForItem(int index) {
+      // This method is frequently called from the "onScroll" handler of the "RecyclerView" with an
+      // index of first visible item of the view. Implementation of this method takes advantage of
+      // that fact by caching the value for the last index that this method has been called with.
+      //
+      // There are a 2 cases that we optimize for:
+      // 1) The visible item doesn't change between subsequent "onScroll" calls, in that case we
+      //    don't need to calculate anything, just return the cached value
+      // 2) The next visible item will be the one that is adjacent to the item that we store the
+      //    cached value for: index + 1 when scrolling down or index - 1 when scrolling up. Then it
+      //    is sufficient to add/subtract height of item at the "last index"
+      //
+      // The implementation accounts for the cases when next index is not necessarily a subsequent
+      // number of the cached one. In which case we try to minimize the number of rows we will loop
+      // through.
       if (mLastRequestedPosition != index) {
-        int sum = 0;
-        int startIndex = 0;
-
-        if (mLastRequestedPosition != -1) {
-          sum = mOffsetForLastPosition;
-          startIndex = mLastRequestedPosition;
-        }
+        int sum;
 
         if (mLastRequestedPosition < index) {
+          // This can either happen when we're scrolling down or if the cached value has never been
+          // calculated
+          int startIndex;
+
+          if (mLastRequestedPosition != -1) {
+            // We already have the value cached, let's use it and only add heights of the items
+            // starting at the index we have the cached value for
+            sum = mOffsetForLastPosition;
+            startIndex = mLastRequestedPosition;
+          } else {
+            sum = 0;
+            startIndex = 0;
+          }
+
           for (int i = startIndex; i < index; i++) {
             sum += mReactListAdapter.mViews.get(i).getMeasuredHeight();
           }
         } else {
+          // We are scrolling up, we can either use cached value and subtract heights of rows
+          // between mLastRequestPosition and index, or we can calculate the height starting from 0
+          // (this can be quite a frequent case as well, when the list implements "jump to the top"
+          // action). We just go for the option that require less calculations
           if (index < (mLastRequestedPosition - index)) {
+            // index is relatively small, it's faster to calculate the sum starting from 0
+            sum = 0;
             for (int i = 0; i < index; i++) {
               sum += mReactListAdapter.mViews.get(i).getMeasuredHeight();
             }
           } else {
+            // index is "closer" to the last cached index than it is to 0. We can reuse cached sum
+            // and calculate the new sum by subtracting heights of the elements between
+            // "mLastRequestPosition" and "index"
+            sum = mOffsetForLastPosition;
             for (int i = mLastRequestedPosition - 1; i >= index; i--) {
               sum -= mReactListAdapter.mViews.get(i).getMeasuredHeight();
             }

From 8a10fc629a5f6a43cbed167cc993ee03e1f557dc Mon Sep 17 00:00:00 2001
From: Andrei Coman <andreic@fb.com>
Date: Fri, 29 Jan 2016 14:11:36 -0800
Subject: [PATCH 0943/1411] Remove timeout from MessageQueueThreadImpl creation

Reviewed By: oli

Differential Revision: D2880630

fb-gh-sync-id: bd31395abc69750f16a6ab32d11c55af3ec985a4
---
 .../react/bridge/queue/MessageQueueThreadImpl.java   |  7 +++----
 .../react/common/futures/SimpleSettableFuture.java   | 12 ++++++++++++
 2 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java
index 62184512652d..f4377f4fe420 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java
@@ -11,7 +11,6 @@
 
 import java.util.concurrent.Callable;
 import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
 
 import android.os.Looper;
 
@@ -158,7 +157,7 @@ public void run() {
               registrationFuture.set(null);
             }
           });
-      registrationFuture.getOrThrow(5000, TimeUnit.MILLISECONDS);
+      registrationFuture.getOrThrow();
     }
     return mqt;
   }
@@ -180,14 +179,14 @@ public void run() {
             Looper.prepare();
 
             looperFuture.set(Looper.myLooper());
-            MessageQueueThreadRegistry.register(mqtFuture.getOrThrow(5000, TimeUnit.MILLISECONDS));
+            MessageQueueThreadRegistry.register(mqtFuture.getOrThrow());
 
             Looper.loop();
           }
         }, "mqt_" + name);
     bgThread.start();
 
-    Looper myLooper = looperFuture.getOrThrow(5000, TimeUnit.MILLISECONDS);
+    Looper myLooper = looperFuture.getOrThrow();
     MessageQueueThreadImpl mqt = new MessageQueueThreadImpl(name, myLooper, exceptionHandler);
     mqtFuture.set(mqt);
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java b/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java
index 063279ad353e..55fc9eb089e2 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java
@@ -91,6 +91,18 @@ public boolean isDone() {
     return mResult;
   }
 
+  /**
+   * Convenience wrapper for {@link #get()} that re-throws get()'s Exceptions as
+   * RuntimeExceptions.
+   */
+  public @Nullable T getOrThrow() {
+    try {
+      return get();
+    } catch (InterruptedException | ExecutionException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
   /**
    * Convenience wrapper for {@link #get(long, TimeUnit)} that re-throws get()'s Exceptions as
    * RuntimeExceptions.

From 8b7671a31a50aa9fd94d9cec2631421a8bda16b5 Mon Sep 17 00:00:00 2001
From: Harry Moreno <morenoh149@gmail.com>
Date: Fri, 29 Jan 2016 14:26:44 -0800
Subject: [PATCH 0944/1411] Improve ios offline build instructions

Summary: Closes https://github.com/facebook/react-native/pull/5626

Reviewed By: svcscm

Differential Revision: D2881020

Pulled By: androidtrunkagent

fb-gh-sync-id: 7f472d554a334f39c4b85ccfa4db81b7c3f41d38
---
 docs/RunningOnDeviceIOS.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/RunningOnDeviceIOS.md b/docs/RunningOnDeviceIOS.md
index e36d90e8feaf..c90f3b04ed88 100644
--- a/docs/RunningOnDeviceIOS.md
+++ b/docs/RunningOnDeviceIOS.md
@@ -27,7 +27,7 @@ When you run your app on device, we pack all the JavaScript code and the images
 
 1. Open `AwesomeApp/ios/AwesomeApp/AppDelegate.m`
 2. Uncomment `jsCodeLocation = [[NSBundle mainBundle] ...`
-3. The JS bundle will be built for dev or prod depending on your app's scheme (Debug = development build with warnings, Release = minified prod build with perf optimizations).
+3. The JS bundle will be built for dev or prod depending on your app's scheme (Debug = development build with warnings, Release = minified prod build with perf optimizations). To change the scheme navigate to `Product > Scheme > Edit Scheme...` in xcode and change `Build Configuration` between `Debug` and `Release`.
 
 ## Disabling in-app developer menu
 

From 1bc03871f391d4df958dd8af97c6002cdef5f943 Mon Sep 17 00:00:00 2001
From: Jan Kassens <jkassens@fb.com>
Date: Fri, 29 Jan 2016 18:17:16 -0800
Subject: [PATCH 0945/1411] remove ReactDOM from Jest blacklist

Reviewed By: yungsters, spicyj

Differential Revision: D2875010

fb-gh-sync-id: d316d5befd0d978bded99f70b814dc133c85b40f
---
 packager/blacklist.js | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/packager/blacklist.js b/packager/blacklist.js
index f3c652034014..0a705b9c8096 100644
--- a/packager/blacklist.js
+++ b/packager/blacklist.js
@@ -70,6 +70,9 @@ var sharedBlacklist = [
   'downstream/core/toArray.js',
 
   /website\/node_modules\/.*/,
+
+  // TODO(jkassens, #9876132): Remove this rule when it's no longer needed.
+  'downstream/relay/tools/relayUnstableBatchedUpdates.js',
 ];
 
 var platformBlacklists = {

From 9d0242fdc3e9728f6afef5d49c712d24a9c8f49f Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Sat, 30 Jan 2016 07:35:36 -0800
Subject: [PATCH 0946/1411] Replace direct access of NativeModules.UIManager
 with require('UIManager')

Summary:
public
Due to the cross-platform polyfills we have added (and will add in future) to `UIManager.js`, accessing UIManager directly via NativeModules instead of importing the wrapper is discouraged.

This diff fixes a few places where we were doing this inside our own modules.

Note: As a general policy, we should avoid accessing modules via NativeModules anyway. Using wrapper classes allows us to provide static declarations for all the native methods and properties, which can be checked at build time by flow. If we access the modules directly, those interfaces are only known at runtime.

Reviewed By: vjeux

Differential Revision: D2881300

fb-gh-sync-id: 6737358ea8ea6d722cc1941a4b9fa0123a87fc29
---
 Libraries/Components/DatePicker/DatePickerIOS.ios.js | 2 +-
 Libraries/Components/ScrollResponder.js              | 3 ++-
 Libraries/RCTTest/SnapshotViewIOS.ios.js             | 3 ++-
 docs/NativeComponentsIOS.md                          | 2 +-
 4 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/Libraries/Components/DatePicker/DatePickerIOS.ios.js b/Libraries/Components/DatePicker/DatePickerIOS.ios.js
index 3516ae35d003..c436abbbb362 100644
--- a/Libraries/Components/DatePicker/DatePickerIOS.ios.js
+++ b/Libraries/Components/DatePicker/DatePickerIOS.ios.js
@@ -16,7 +16,7 @@
 var NativeMethodsMixin = require('NativeMethodsMixin');
 var PropTypes = require('ReactPropTypes');
 var React = require('React');
-var RCTDatePickerIOSConsts = require('NativeModules').UIManager.RCTDatePicker.Constants;
+var RCTDatePickerIOSConsts = require('UIManager').RCTDatePicker.Constants;
 var StyleSheet = require('StyleSheet');
 var View = require('View');
 
diff --git a/Libraries/Components/ScrollResponder.js b/Libraries/Components/ScrollResponder.js
index baa3336a06b5..b385b87b8ad3 100644
--- a/Libraries/Components/ScrollResponder.js
+++ b/Libraries/Components/ScrollResponder.js
@@ -17,8 +17,9 @@ var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
 var React = require('React');
 var Subscribable = require('Subscribable');
 var TextInputState = require('TextInputState');
+var UIManager = require('UIManager');
 
-var { UIManager, ScrollViewManager } = require('NativeModules');
+var { ScrollViewManager } = require('NativeModules');
 
 var invariant = require('invariant');
 var warning = require('warning');
diff --git a/Libraries/RCTTest/SnapshotViewIOS.ios.js b/Libraries/RCTTest/SnapshotViewIOS.ios.js
index 3ecefdc3dea1..3cd8bf04ae33 100644
--- a/Libraries/RCTTest/SnapshotViewIOS.ios.js
+++ b/Libraries/RCTTest/SnapshotViewIOS.ios.js
@@ -13,7 +13,8 @@
 
 var React = require('React');
 var StyleSheet = require('StyleSheet');
-var { TestModule, UIManager } = require('NativeModules');
+var { TestModule } = require('NativeModules');
+var UIManager = require('UIManager');
 var View = require('View');
 
 var requireNativeComponent = require('requireNativeComponent');
diff --git a/docs/NativeComponentsIOS.md b/docs/NativeComponentsIOS.md
index ebdbc2f71f80..fffb06ecadcf 100644
--- a/docs/NativeComponentsIOS.md
+++ b/docs/NativeComponentsIOS.md
@@ -302,7 +302,7 @@ Since all our native react views are subclasses of `UIView`, most style attribut
 ```javascript
 // DatePickerIOS.ios.js
 
-var RCTDatePickerIOSConsts = require('react-native').NativeModules.UIManager.RCTDatePicker.Constants;
+var RCTDatePickerIOSConsts = require('react-native').UIManager.RCTDatePicker.Constants;
 ...
   render: function() {
     return (

From 99e56d6e943803b4521181dd694756a6363f46a5 Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Sat, 30 Jan 2016 16:02:32 -0500
Subject: [PATCH 0947/1411] Add buck build folders to gitignore

---
 .gitignore | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/.gitignore b/.gitignore
index 74ab1dc77337..fe61f843f91d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,6 +26,10 @@ project.xcworkspace
 /Examples/**/android/app/build/
 /ReactAndroid/build/
 
+# Buck
+.buckd
+buck-out
+
 # Android
 .idea
 .gradle

From 679beb2a3af4b77b22f3923e3937f5e293909d12 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Sat, 30 Jan 2016 17:10:14 -0800
Subject: [PATCH 0948/1411] Tweak docs before releasing 0.19

Reviewed By: mkonicek

Differential Revision:D2883844
Ninja: Only docs and React Native website, doesn't affect any fb apps

fb-gh-sync-id: 4bf56dc695224f172832ca5381cebceab9e5fe4f
---
 Libraries/AppState/AppState.js        |  5 -----
 Libraries/CameraRoll/CameraRoll.js    | 15 ++++++---------
 Libraries/Components/Picker/Picker.js |  3 ++-
 website/server/extractDocs.js         |  1 +
 4 files changed, 9 insertions(+), 15 deletions(-)

diff --git a/Libraries/AppState/AppState.js b/Libraries/AppState/AppState.js
index 0bd7618fdb1b..ed06c9203b32 100644
--- a/Libraries/AppState/AppState.js
+++ b/Libraries/AppState/AppState.js
@@ -122,12 +122,7 @@ var AppState = {
     _eventHandlers[type].delete(handler);
   },
 
-  // TODO: getCurrentAppState callback seems to be called at a really late stage
-  // after app launch. Trying to get currentState when mounting App component
-  // will likely to have the initial value here.
-  // Initialize to 'active' instead of null.
   currentState: ('active' : ?string),
-
 };
 
 RCTDeviceEventEmitter.addListener(
diff --git a/Libraries/CameraRoll/CameraRoll.js b/Libraries/CameraRoll/CameraRoll.js
index 3b4b0ed1a200..985fc2c74cba 100644
--- a/Libraries/CameraRoll/CameraRoll.js
+++ b/Libraries/CameraRoll/CameraRoll.js
@@ -118,8 +118,7 @@ class CameraRoll {
   /**
    * Saves the image to the camera roll / gallery.
    *
-   * @param {string} tag On Android, this is a local URI, such
-   * as `"file:///sdcard/img.png"`.
+   * On Android, the tag is a local URI, such as `"file:///sdcard/img.png"`.
    *
    * On iOS, the tag can be one of the following:
    *
@@ -128,8 +127,7 @@ class CameraRoll {
    *   - a tag not matching any of the above, which means the image data will
    * be stored in memory (and consume memory as long as the process is alive)
    *
-   * Returns a Promise which when resolved will be passed the new uri
-   *
+   * Returns a Promise which when resolved will be passed the new URI.
    */
   static saveImageWithTag(tag) {
     invariant(
@@ -147,13 +145,12 @@ class CameraRoll {
   }
 
   /**
-   *  Returns a Promise with photo identifier objects from the local camera
-   *  roll of the device matching shape defined by `getPhotosReturnChecker`.
-   *
-   *  @param {object} params See `getPhotosParamChecker`.
+   * Returns a Promise with photo identifier objects from the local camera
+   * roll of the device matching shape defined by `getPhotosReturnChecker`.
    *
-   *  Returns a Promise which when resolved will be of shape `getPhotosReturnChecker`
+   * @param {object} params See `getPhotosParamChecker`.
    *
+   * Returns a Promise which when resolved will be of shape `getPhotosReturnChecker`.
    */
   static getPhotos(params) {
     if (__DEV__) {
diff --git a/Libraries/Components/Picker/Picker.js b/Libraries/Components/Picker/Picker.js
index 9db560fb9c82..5fa3ba7e185e 100644
--- a/Libraries/Components/Picker/Picker.js
+++ b/Libraries/Components/Picker/Picker.js
@@ -84,12 +84,13 @@ var Picker = React.createClass({
     enabled: React.PropTypes.bool,
     /**
      * On Android, specifies how to display the selection items when the user taps on the picker:
+     *
      *   - 'dialog': Show a modal dialog. This is the default.
      *   - 'dropdown': Shows a dropdown anchored to the picker view
      *
      * @platform android
      */
-    mode: React.PropTypes.oneOf([MODE_DIALOG, MODE_DROPDOWN]),
+    mode: React.PropTypes.oneOf(['dialog', 'dropdown']),
     /**
      * Style to apply to each of the item labels.
      * @platform ios
diff --git a/website/server/extractDocs.js b/website/server/extractDocs.js
index 766fc336311a..939e78018da2 100644
--- a/website/server/extractDocs.js
+++ b/website/server/extractDocs.js
@@ -199,6 +199,7 @@ var components = [
   '../Libraries/CustomComponents/Navigator/Navigator.js',
   '../Libraries/Components/Navigation/NavigatorIOS.ios.js',
   '../Libraries/Picker/PickerIOS.ios.js',
+  '../Libraries/Components/Picker/Picker.js',
   '../Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js',
   '../Libraries/Components/ProgressViewIOS/ProgressViewIOS.ios.js',
   '../Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js',

From 3fbd46c6d956f92fd236345ace082c0a2602a9d1 Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeux@fb.com>
Date: Sat, 30 Jan 2016 23:01:14 -0800
Subject: [PATCH 0949/1411] Cleanup Edit with GitHub

Summary:
- Now using a table layout. While having the link inside of the header worked well in the browser, the search API would put "Edit in GitHub" as part of the title -_-
- Instead of putting the link inside of every section like Props, put it on the page header. This makes it less repetetitive and also works on API pages where the link was absent before
- Remove "Run this example" link as there's a giant Run this example sidebar already.
Closes https://github.com/facebook/react-native/pull/5643

Reviewed By: svcscm

Differential Revision: D2883989

Pulled By: vjeux

fb-gh-sync-id: e810e1677d5130692997dd301d6d59cfe04b948f
---
 website/core/HeaderWithGithub.js              |  40 +++++++
 website/layout/AutodocsLayout.js              | 112 +++++++-----------
 website/layout/DocsLayout.js                  |  19 ++-
 website/server/extractDocs.js                 |   1 +
 website/src/react-native/css/react-native.css |  12 --
 5 files changed, 92 insertions(+), 92 deletions(-)
 create mode 100644 website/core/HeaderWithGithub.js

diff --git a/website/core/HeaderWithGithub.js b/website/core/HeaderWithGithub.js
new file mode 100644
index 000000000000..7304caad40b7
--- /dev/null
+++ b/website/core/HeaderWithGithub.js
@@ -0,0 +1,40 @@
+/**
+ * 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 HeaderWithGithub
+ */
+
+var H = require('Header');
+var React = require('React');
+
+var HeaderWithGithub = React.createClass({
+  render: function() {
+    return (
+      <table width="100%">
+        <tbody>
+          <tr>
+            <td>
+              <H level={this.props.level || 3} toSlug={this.props.title}>
+                {this.props.title}
+              </H>
+            </td>
+            <td style={{textAlign: 'right'}}>
+              <a
+                target="_blank"
+                href={'https://github.com/facebook/react-native/blob/master/' + this.props.path}>
+                Edit on GitHub
+              </a>
+            </td>
+          </tr>
+        </tbody>
+      </table>
+    );
+  }
+});
+
+module.exports = HeaderWithGithub;
diff --git a/website/layout/AutodocsLayout.js b/website/layout/AutodocsLayout.js
index c5dbb5445c4e..e0b493ae192e 100644
--- a/website/layout/AutodocsLayout.js
+++ b/website/layout/AutodocsLayout.js
@@ -12,6 +12,7 @@
 var DocsSidebar = require('DocsSidebar');
 var H = require('Header');
 var Header = require('Header');
+var HeaderWithGithub = require('HeaderWithGithub');
 var Marked = require('Marked');
 var Prism = require('Prism');
 var React = require('React');
@@ -233,10 +234,7 @@ var ComponentDoc = React.createClass({
         <Marked>
           {content.description}
         </Marked>
-        <HeaderWithGithub
-          title="Props"
-          path={content.filepath}
-        />
+        <H level={3}>Props</H>
         {this.renderProps(content.props, content.composes)}
       </div>
     );
@@ -406,32 +404,45 @@ var APIDoc = React.createClass({
   }
 });
 
-var HeaderWithGithub = React.createClass({
-
-  renderRunnableLink: function() {
-    if (this.props.metadata && this.props.metadata.runnable) {
-      return (
-        <a
-          className="run-example"
-          target="_blank"
-          href={'https://rnplay.org/apps/l3Zi2g?route='+this.props.metadata.title+'&file=' + this.props.metadata.title+ "Example.js"}>
-          Run this example
-        </a>
-      );
+var EmbeddedSimulator = React.createClass({
+  render: function() {
+    if (!this.props.shouldRender) {
+      return null;
     }
-  },
 
+    var metadata = this.props.metadata;
+
+    return (
+      <div className="column-left">
+        <p><a className="modal-button-open"><strong>Run this example</strong></a></p>
+        <div className="modal-button-open modal-button-open-img">
+          <img alt="Run example in simulator" width="170" height="358" src="/react-native/img/alertIOS.png" />
+        </div>
+        <Modal />
+      </div>
+    );
+  }
+});
+
+var Modal = React.createClass({
   render: function() {
+    var appParams = {route: 'AlertIOS'};
+    var encodedParams = encodeURIComponent(JSON.stringify(appParams));
+    var url = `https://appetize.io/embed/bypdk4jnjra5uwyj2kzd2aenv4?device=iphone5s&scale=70&autoplay=false&orientation=portrait&deviceColor=white&params=${encodedParams}`;
+
     return (
-      <H level={3} toSlug={this.props.title}>
-        <a
-          className="edit-github"
-          href={'https://github.com/facebook/react-native/blob/master/' + this.props.path}>
-          Edit on GitHub
-        </a>
-        {this.renderRunnableLink()}
-        {this.props.title}
-      </H>
+      <div>
+        <div className="modal">
+          <div className="modal-content">
+            <button className="modal-button-close">&times;</button>
+            <div className="center">
+              <iframe className="simulator" src={url} width="256" height="550" frameborder="0" scrolling="no"></iframe>
+              <p>Powered by <a target="_blank" href="https://appetize.io">appetize.io</a></p>
+            </div>
+          </div>
+        </div>
+        <div className="modal-backdrop" />
+      </div>
     );
   }
 });
@@ -486,7 +497,11 @@ var Autodocs = React.createClass({
           <DocsSidebar metadata={metadata} />
           <div className="inner-content">
             <a id="content" />
-            <h1>{metadata.title}</h1>
+            <HeaderWithGithub
+              title={metadata.title}
+              level={1}
+              path={metadata.path}
+            />
             {content}
             {this.renderFullDescription(docs)}
             {this.renderExample(docs, metadata)}
@@ -504,47 +519,4 @@ var Autodocs = React.createClass({
   }
 });
 
-var EmbeddedSimulator = React.createClass({
-  render: function() {
-    if (!this.props.shouldRender) {
-      return null;
-    }
-
-    var metadata = this.props.metadata;
-
-    return (
-      <div className="column-left">
-        <p><a className="modal-button-open"><strong>Run this example</strong></a></p>
-        <div className="modal-button-open modal-button-open-img">
-          <img alt="Run example in simulator" width="170" height="358" src="/react-native/img/alertIOS.png" />
-        </div>
-        <Modal />
-      </div>
-    );
-  }
-});
-
-var Modal = React.createClass({
-  render: function() {
-    var appParams = {route: 'AlertIOS'};
-    var encodedParams = encodeURIComponent(JSON.stringify(appParams));
-    var url = `https://appetize.io/embed/bypdk4jnjra5uwyj2kzd2aenv4?device=iphone5s&scale=70&autoplay=false&orientation=portrait&deviceColor=white&params=${encodedParams}`;
-
-    return (
-      <div>
-        <div className="modal">
-          <div className="modal-content">
-            <button className="modal-button-close">&times;</button>
-            <div className="center">
-              <iframe className="simulator" src={url} width="256" height="550" frameborder="0" scrolling="no"></iframe>
-              <p>Powered by <a target="_blank" href="https://appetize.io">appetize.io</a></p>
-            </div>
-          </div>
-        </div>
-        <div className="modal-backdrop" />
-      </div>
-    );
-  }
-});
-
 module.exports = Autodocs;
diff --git a/website/layout/DocsLayout.js b/website/layout/DocsLayout.js
index b0cb690668fb..673496938b65 100644
--- a/website/layout/DocsLayout.js
+++ b/website/layout/DocsLayout.js
@@ -9,10 +9,12 @@
  * @providesModule DocsLayout
  */
 
+var DocsSidebar = require('DocsSidebar');
+var HeaderWithGithub = require('HeaderWithGithub');
+var Marked = require('Marked');
 var React = require('React');
 var Site = require('Site');
-var Marked = require('Marked');
-var DocsSidebar = require('DocsSidebar');
+
 var DocsLayout = React.createClass({
   render: function() {
     var metadata = this.props.metadata;
@@ -23,14 +25,11 @@ var DocsLayout = React.createClass({
           <DocsSidebar metadata={metadata} />
           <div className="inner-content">
             <a id="content" />
-            <h1>
-              {metadata.title}
-              <a
-                className="edit-github"
-                href={'https://github.com/facebook/react-native/blob/master/docs/' + metadata.filename}>
-                Edit on GitHub
-              </a>
-            </h1>
+            <HeaderWithGithub
+              title={metadata.title}
+              level={1}
+              path={'docs/' + metadata.filename}
+            />
             <Marked>{content}</Marked>
             <div className="docs-prevnext">
               {metadata.previous && <a className="docs-prev" href={metadata.previous + '.html#content'}>&larr; Prev</a>}
diff --git a/website/server/extractDocs.js b/website/server/extractDocs.js
index 939e78018da2..2f88d9bfe8c8 100644
--- a/website/server/extractDocs.js
+++ b/website/server/extractDocs.js
@@ -137,6 +137,7 @@ function componentsToMarkdown(type, json, filepath, i, styles) {
     'next: ' + next,
     'sidebar: ' + shouldDisplayInSidebar(componentName),
     'runnable:' + isRunnable(componentName),
+    'path:' + json.filepath,
     '---',
     JSON.stringify(json, null, 2),
   ].filter(function(line) { return line; }).join('\n');
diff --git a/website/src/react-native/css/react-native.css b/website/src/react-native/css/react-native.css
index 1331e880f534..83cf44113d98 100644
--- a/website/src/react-native/css/react-native.css
+++ b/website/src/react-native/css/react-native.css
@@ -1118,18 +1118,6 @@ div[data-twttr-id] iframe {
   margin-left: 26px;
 }
 
-.edit-github {
-  font-size: 15px;
-  font-weight: normal;
-  float: right;
-}
-
-.run-example {
-  font-size: 15px;
-  float: right;
-  margin-right: 20px;
-}
-
 #content {
   display: none;
 }

From 670f9afaa1561dc0adb3d02a15de04ab794aa4c8 Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeux@fb.com>
Date: Sun, 31 Jan 2016 00:53:01 -0800
Subject: [PATCH 0950/1411] Document Linking

Summary:
Both LinkingIOS and IntentAndroid are deprecated in favor of Linking but it was not in the website documentation.
Closes https://github.com/facebook/react-native/pull/5642

Reviewed By: svcscm

Differential Revision: D2883999

Pulled By: androidtrunkagent

fb-gh-sync-id: cd2ce6192f84fffef7ab7d4e56f87eb55fb30901
---
 website/server/extractDocs.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/website/server/extractDocs.js b/website/server/extractDocs.js
index 2f88d9bfe8c8..29d6a9878bfc 100644
--- a/website/server/extractDocs.js
+++ b/website/server/extractDocs.js
@@ -238,6 +238,7 @@ var apis = [
   '../Libraries/Components/Intent/IntentAndroid.android.js',
   '../Libraries/Interaction/InteractionManager.js',
   '../Libraries/LayoutAnimation/LayoutAnimation.js',
+  '../Libraries/Linking/Linking.js',
   '../Libraries/LinkingIOS/LinkingIOS.js',
   '../Libraries/ReactIOS/NativeMethodsMixin.js',
   '../Libraries/Network/NetInfo.js',

From d3a1d27aaa0a686b692499a88b03475f9823446e Mon Sep 17 00:00:00 2001
From: Austin Kuo <auszon3@gmail.com>
Date: Sun, 31 Jan 2016 06:44:10 -0800
Subject: [PATCH 0951/1411] Improve the error message when the packager can't
 find a module

Summary: Closes https://github.com/facebook/react-native/pull/5647

Reviewed By: svcscm

Differential Revision: D2884241

Pulled By: androidtrunkagent

fb-gh-sync-id: 115491270c8f84d45f67a1a477543d9ace76f447
---
 .../src/DependencyResolver/DependencyGraph/ResolutionRequest.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
index 149cab010b3f..2651561799ad 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
@@ -386,7 +386,7 @@ class ResolutionRequest {
         throw new UnableToResolveError(
           fromModule,
           toModule,
-`Invalid directory ${potentialDirPath}
+`Unable to find this module in its module map or any of the node_modules directories under ${potentialDirPath} and its parent directories
 
 This might be related to https://github.com/facebook/react-native/issues/4968
 To resolve try the following:

From 5712e0c3eb7a84be15edac4c352ba5d7f895216a Mon Sep 17 00:00:00 2001
From: "Dotan J. Nahum" <jondotan@gmail.com>
Date: Sun, 31 Jan 2016 08:40:21 -0800
Subject: [PATCH 0952/1411] Typo: Change WebWiew to WebView

Summary: Closes https://github.com/facebook/react-native/pull/5648

Reviewed By: svcscm

Differential Revision: D2884296

Pulled By: androidtrunkagent

fb-gh-sync-id: 50340c0fc06926fbb3dc41c3078aa985ff48ccd3
---
 Libraries/Components/WebView/WebView.android.js | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/Libraries/Components/WebView/WebView.android.js b/Libraries/Components/WebView/WebView.android.js
index f7b0a88ef763..e2bbad6e5ba1 100644
--- a/Libraries/Components/WebView/WebView.android.js
+++ b/Libraries/Components/WebView/WebView.android.js
@@ -156,7 +156,7 @@ var WebView = React.createClass({
 
   goForward: function() {
     UIManager.dispatchViewManagerCommand(
-      this.getWebWiewHandle(),
+      this.getWebViewHandle(),
       UIManager.RCTWebView.Commands.goForward,
       null
     );
@@ -164,7 +164,7 @@ var WebView = React.createClass({
 
   goBack: function() {
     UIManager.dispatchViewManagerCommand(
-      this.getWebWiewHandle(),
+      this.getWebViewHandle(),
       UIManager.RCTWebView.Commands.goBack,
       null
     );
@@ -172,7 +172,7 @@ var WebView = React.createClass({
 
   reload: function() {
     UIManager.dispatchViewManagerCommand(
-      this.getWebWiewHandle(),
+      this.getWebViewHandle(),
       UIManager.RCTWebView.Commands.reload,
       null
     );
@@ -188,7 +188,7 @@ var WebView = React.createClass({
     }
   },
 
-  getWebWiewHandle: function() {
+  getWebViewHandle: function() {
     return React.findNodeHandle(this.refs[RCT_WEBVIEW_REF]);
   },
 

From 23412459b201cb89366c4c0e3dc31e38adde01b6 Mon Sep 17 00:00:00 2001
From: Sam Neubardt <samneubardt@gmail.com>
Date: Sun, 31 Jan 2016 15:50:58 -0800
Subject: [PATCH 0953/1411] Handle spaces in $REACT_NATIVE_DIR

Summary:
`react-native-xcode.sh` can fail to execute if `$REACT_NATIVE_DIR` contains spaces.

E.g. if `$REACT_NATIVE_DIR` was `/Users/samn/src/Xcode Projects/AwesomeReact` then `react-native-xcode.sh` would fail with the following error:

```
node /Users/samn/src/Xcode Projects/ReactNativeBeaconTest/node_modules/react-native/local-cli/cli.js bundle .... (elided)

module.js:341
    throw err;
    ^

Error: Cannot find module '/Users/samn/src/Xcode'
    at Function.Module._resolveFilename (module.js:339:15)
    at Function.Module._load (module.js:290:25)
    at Function.Module.runMain (module.js:447:10)
    at startup (node.js:139:18)
    at node.js:999:3
Command /bin/sh failed with exit code 1
```

This change properly handles paths with spaces in them by quoting `$REACT_NATIVE_DIR`
Closes https://github.com/facebook/react-native/pull/5651

Reviewed By: svcscm

Differential Revision: D2884600

Pulled By: androidtrunkagent

fb-gh-sync-id: 3784d8f4e16c0c2cadac738c5f085a5023b5ecf7
---
 packager/react-native-xcode.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packager/react-native-xcode.sh b/packager/react-native-xcode.sh
index c0ed7282fbf5..87251051f12e 100755
--- a/packager/react-native-xcode.sh
+++ b/packager/react-native-xcode.sh
@@ -68,7 +68,7 @@ type $NODE_BINARY >/dev/null 2>&1 || nodejs_not_found
 set -x
 DEST=$CONFIGURATION_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH
 
-$NODE_BINARY $REACT_NATIVE_DIR/local-cli/cli.js bundle \
+$NODE_BINARY "$REACT_NATIVE_DIR/local-cli/cli.js" bundle \
   --entry-file index.ios.js \
   --platform ios \
   --dev $DEV \

From 5afb74027fb0b36c8859a847de51215f7ac123ad Mon Sep 17 00:00:00 2001
From: Ahmed Abbas <ahmed1490@gmail.com>
Date: Sun, 31 Jan 2016 16:37:40 -0800
Subject: [PATCH 0954/1411] Update 3rd-party modules website to Js.coach

Summary:
This section was outdated with older website : https://facebook.github.io/react-native/docs/known-issues.html#using-3rd-party-native-modules
Closes https://github.com/facebook/react-native/pull/5650

Reviewed By: svcscm

Differential Revision: D2884630

Pulled By: androidtrunkagent

fb-gh-sync-id: afe35817421e055e343233a1db863954d6f75f01
---
 docs/KnownIssues.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/KnownIssues.md b/docs/KnownIssues.md
index 5a93bc25e589..cfc9bd00aba6 100644
--- a/docs/KnownIssues.md
+++ b/docs/KnownIssues.md
@@ -52,7 +52,7 @@ There are known cases where the APIs could be made more consistent across iOS an
 
 ### Using 3rd-party native modules
 
-There are many awesome 3rd-party modules: https://react.parts/native
+There are many awesome 3rd-party modules: [JS.coach](https://js.coach/react-native)
 
 Adding these to your apps should be made simpler. Here's [an example](https://github.com/apptailor/react-native-google-signin) how this is done currently.
 

From bee6988f94888acdc9a4539c780e664a32ecf63f Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeux@fb.com>
Date: Sun, 31 Jan 2016 22:45:30 -0800
Subject: [PATCH 0955/1411] Temporarily allow decimals on rgb() and rgba()

Summary:
Animating colors using Animated is currently interpolating rgb and rgba and doesn't round the intermediate values. We need to fix it there but it's not a straightforward change so reverting to the lax version here until we fix it inside of Animated (which is needed to work on web anyway).
Closes https://github.com/facebook/react-native/pull/5654

Reviewed By: svcscm

Differential Revision: D2885051

Pulled By: vjeux

fb-gh-sync-id: dab69b1da11131c9fab2fd08c434c73ec93d59d2
---
 Libraries/StyleSheet/__tests__/normalizeColor-test.js | 6 +++++-
 Libraries/StyleSheet/normalizeColor.js                | 6 +++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/Libraries/StyleSheet/__tests__/normalizeColor-test.js b/Libraries/StyleSheet/__tests__/normalizeColor-test.js
index 6f333fba00a5..8365465f7caa 100644
--- a/Libraries/StyleSheet/__tests__/normalizeColor-test.js
+++ b/Libraries/StyleSheet/__tests__/normalizeColor-test.js
@@ -25,6 +25,11 @@ describe('normalizeColor', function() {
     expect(normalizeColor('rgba(0, 0, 0, 1)')).not.toBe(null);
   });
 
+  it('should temporarly accept floating point values for rgb', function() {
+    expect(normalizeColor('rgb(1.1, 2.1, 3.1)')).toBe(0xff010203);
+    expect(normalizeColor('rgba(1.1, 2.1, 3.1, 1.0)')).toBe(0xff010203);
+  });
+
   it('should refuse non spec compliant colors', function() {
     expect(normalizeColor('#00gg00')).toBe(null);
     expect(normalizeColor('rgb(1, 2, 3,)')).toBe(null);
@@ -40,7 +45,6 @@ describe('normalizeColor', function() {
     expect(normalizeColor('hsv(0, 1, 2)')).toBe(null);
     expect(normalizeColor({r: 10, g: 10, b: 10})).toBe(null);
     expect(normalizeColor('hsl(1%, 2, 3)')).toBe(null);
-    expect(normalizeColor('rgb(1.0, 2.0, 3.0)')).toBe(null);
     expect(normalizeColor('rgb(1%, 2%, 3%)')).toBe(null);
   });
 
diff --git a/Libraries/StyleSheet/normalizeColor.js b/Libraries/StyleSheet/normalizeColor.js
index 417fc5d3d0d1..70d9bcad500a 100755
--- a/Libraries/StyleSheet/normalizeColor.js
+++ b/Libraries/StyleSheet/normalizeColor.js
@@ -131,7 +131,7 @@ function hslToRgb(h: number, s: number, l: number): number {
   );
 }
 
-var INTEGER = '[-+]?\\d+';
+// var INTEGER = '[-+]?\\d+';
 var NUMBER = '[-+]?\\d*\\.?\\d+';
 var PERCENTAGE = NUMBER + '%';
 
@@ -140,8 +140,8 @@ function call(...args) {
 }
 
 var matchers = {
-  rgb: new RegExp('rgb' + call(INTEGER, INTEGER, INTEGER)),
-  rgba: new RegExp('rgba' + call(INTEGER, INTEGER, INTEGER, NUMBER)),
+  rgb: new RegExp('rgb' + call(NUMBER, NUMBER, NUMBER)),
+  rgba: new RegExp('rgba' + call(NUMBER, NUMBER, NUMBER, NUMBER)),
   hsl: new RegExp('hsl' + call(NUMBER, PERCENTAGE, PERCENTAGE)),
   hsla: new RegExp('hsla' + call(NUMBER, PERCENTAGE, PERCENTAGE, NUMBER)),
   hex3: /^#([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,

From 9308f89c1c4e9effebcb9f26b12cb90a4fa73961 Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Sun, 31 Jan 2016 23:24:39 -0800
Subject: [PATCH 0956/1411] Add per-field cache invalidation

Summary:
Jest needs this for efficient caching of resolution responses.

public

Reviewed By: voideanvalue

Differential Revision: D2873291

fb-gh-sync-id: fee27d2ffdfe64bd68fdb4d9e4259e721b33631f
---
 .../Cache/__tests__/Cache-test.js             | 29 +++++++++++++++++++
 .../src/DependencyResolver/Cache/index.js     | 12 +++++---
 .../DependencyGraph/index.js                  |  2 +-
 3 files changed, 38 insertions(+), 5 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/Cache/__tests__/Cache-test.js b/packager/react-packager/src/DependencyResolver/Cache/__tests__/Cache-test.js
index 22d6825e9231..2de2318e454c 100644
--- a/packager/react-packager/src/DependencyResolver/Cache/__tests__/Cache-test.js
+++ b/packager/react-packager/src/DependencyResolver/Cache/__tests__/Cache-test.js
@@ -303,4 +303,33 @@ describe('Cache', () => {
         });
     });
   });
+
+  describe('invalidate', () => {
+    it('invalidates the cache per file or per-field', () => {
+      fs.stat.mockImpl((file, callback) =>
+        callback(null, {
+          mtime: {
+            getTime: () => {},
+          },
+        })
+      );
+
+      var cache = new Cache({
+        cacheKey: 'cache',
+      });
+      var loaderCb = jest.genMockFn().mockImpl(() =>
+        Promise.resolve('banana')
+      );
+      var file = '/rootDir/someFile';
+
+      return cache.get(file, 'field', loaderCb).then(() => {
+        expect(cache.has(file)).toBe(true);
+        cache.invalidate(file, 'field');
+        expect(cache.has(file)).toBe(true);
+        expect(cache.has(file, 'field')).toBe(false);
+        cache.invalidate(file);
+        expect(cache.has(file)).toBe(false);
+      });
+    });
+  });
 });
diff --git a/packager/react-packager/src/DependencyResolver/Cache/index.js b/packager/react-packager/src/DependencyResolver/Cache/index.js
index 40f16c77baa3..06d346d6254e 100644
--- a/packager/react-packager/src/DependencyResolver/Cache/index.js
+++ b/packager/react-packager/src/DependencyResolver/Cache/index.js
@@ -58,9 +58,13 @@ class Cache {
     return recordP.then(record => record);
   }
 
-  invalidate(filepath) {
-    if (this.has(filepath)) {
-      delete this._data[filepath];
+  invalidate(filepath, field) {
+    if (this.has(filepath, field)) {
+      if (field == null) {
+        delete this._data[filepath];
+      } else {
+        delete this._data[filepath].data[field];
+      }
     }
   }
 
@@ -70,7 +74,7 @@ class Cache {
 
   has(filepath, field) {
     return Object.prototype.hasOwnProperty.call(this._data, filepath) &&
-      (!field || Object.prototype.hasOwnProperty.call(this._data[filepath].data, field));
+      (field == null || Object.prototype.hasOwnProperty.call(this._data[filepath].data, field));
   }
 
   _set(filepath, field, loaderPromise) {
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
index 273b9b587689..6fda8d93b75b 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
@@ -59,7 +59,7 @@ class DependencyGraph {
       mocksPattern,
       extractRequires,
       shouldThrowOnUnresolvedErrors,
-      transformCode
+      transformCode,
     };
     this._cache = cache;
     this._helpers = new DependencyGraphHelpers(this._opts);

From ee30433b7616a9807f38abd8c822c3f54c27dc39 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Mon, 1 Feb 2016 04:03:55 -0800
Subject: [PATCH 0957/1411] Update Android's ScrollView.scrollTo API to match
 JS/iOS

Summary:
public
We recently updated the `ScrollResponder.scrollResponderScrollTo` method to accept an `animated` argument, and deprecated the `scrollResponderScrollWithoutAnimationTo` method. This change was reflected in the native iOS implementation, but not on Android.

This diff updates the Android ScrollViewManager implementation to match the JS API, and removes the platform-specific fork in the JS code.

Reviewed By: dmmiller

Differential Revision: D2883515

fb-gh-sync-id: e5a0e1cf470e21af837b2311cf1048162ac3aff5
---
 Libraries/Components/ScrollResponder.js       | 18 +++++-------------
 .../RecyclerViewBackedScrollViewManager.java  | 11 ++---------
 .../ReactHorizontalScrollViewManager.java     | 13 +++++--------
 .../scroll/ReactScrollViewCommandHelper.java  | 19 ++++++-------------
 .../views/scroll/ReactScrollViewManager.java  | 13 +++++--------
 5 files changed, 23 insertions(+), 51 deletions(-)

diff --git a/Libraries/Components/ScrollResponder.js b/Libraries/Components/ScrollResponder.js
index b385b87b8ad3..e6ef4c554a51 100644
--- a/Libraries/Components/ScrollResponder.js
+++ b/Libraries/Components/ScrollResponder.js
@@ -353,19 +353,11 @@ var ScrollResponderMixin = {
    * can also be used to quickly scroll to any element we want to focus
    */
   scrollResponderScrollTo: function(offsetX: number, offsetY: number, animated: boolean = true) {
-    if (Platform.OS === 'android') {
-      UIManager.dispatchViewManagerCommand(
-        React.findNodeHandle(this),
-        UIManager.RCTScrollView.Commands[animated ? 'scrollTo' : 'scrollWithoutAnimationTo'],
-        [Math.round(offsetX), Math.round(offsetY)],
-      );
-    } else {
-      ScrollViewManager.scrollTo(
-        React.findNodeHandle(this),
-        { x: offsetX, y: offsetY },
-        animated
-      );
-    }
+    UIManager.dispatchViewManagerCommand(
+      React.findNodeHandle(this),
+      UIManager.RCTScrollView.Commands.scrollTo,
+      [offsetX, offsetY, animated],
+    );
   },
 
   /**
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollViewManager.java
index cafd71de8824..dfac0da4e105 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollViewManager.java
@@ -75,16 +75,9 @@ public void receiveCommand(
 
   @Override
   public void scrollTo(
-      RecyclerViewBackedScrollView view,
-      ReactScrollViewCommandHelper.ScrollToCommandData data) {
-    view.scrollTo(data.mDestX, data.mDestY, true);
-  }
-
-  @Override
-  public void scrollWithoutAnimationTo(
-      RecyclerViewBackedScrollView view,
+      RecyclerViewBackedScrollView scrollView,
       ReactScrollViewCommandHelper.ScrollToCommandData data) {
-    view.scrollTo(data.mDestX, data.mDestY, false);
+    scrollView.scrollTo(data.mDestX, data.mDestY, data.mAnimated);
   }
 
   @Override
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java
index 07a39d4a413f..923d35e77ce2 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java
@@ -75,13 +75,10 @@ public void receiveCommand(
   public void scrollTo(
       ReactHorizontalScrollView scrollView,
       ReactScrollViewCommandHelper.ScrollToCommandData data) {
-    scrollView.smoothScrollTo(data.mDestX, data.mDestY);
-  }
-
-  @Override
-  public void scrollWithoutAnimationTo(
-      ReactHorizontalScrollView scrollView,
-      ReactScrollViewCommandHelper.ScrollToCommandData data) {
-    scrollView.scrollTo(data.mDestX, data.mDestY);
+    if (data.mAnimated) {
+      scrollView.smoothScrollTo(data.mDestX, data.mDestY);
+    } else {
+      scrollView.scrollTo(data.mDestX, data.mDestY);
+    }
   }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewCommandHelper.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewCommandHelper.java
index a5eb1421c089..aa9560df071a 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewCommandHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewCommandHelper.java
@@ -25,29 +25,27 @@
 public class ReactScrollViewCommandHelper {
 
   public static final int COMMAND_SCROLL_TO = 1;
-  public static final int COMMAND_SCROLL_WITHOUT_ANIMATION_TO = 2;
 
   public interface ScrollCommandHandler<T> {
     void scrollTo(T scrollView, ScrollToCommandData data);
-    void scrollWithoutAnimationTo(T scrollView, ScrollToCommandData data);
   }
 
   public static class ScrollToCommandData {
 
     public final int mDestX, mDestY;
+    public final boolean mAnimated;
 
-    ScrollToCommandData(int destX, int destY) {
+    ScrollToCommandData(int destX, int destY, boolean animated) {
       mDestX = destX;
       mDestY = destY;
+      mAnimated = animated;
     }
   }
 
   public static Map<String,Integer> getCommandsMap() {
     return MapBuilder.of(
         "scrollTo",
-        COMMAND_SCROLL_TO,
-        "scrollWithoutAnimationTo",
-        COMMAND_SCROLL_WITHOUT_ANIMATION_TO);
+        COMMAND_SCROLL_TO);
   }
 
   public static <T> void receiveCommand(
@@ -62,13 +60,8 @@ public static <T> void receiveCommand(
       case COMMAND_SCROLL_TO: {
         int destX = Math.round(PixelUtil.toPixelFromDIP(args.getDouble(0)));
         int destY = Math.round(PixelUtil.toPixelFromDIP(args.getDouble(1)));
-        viewManager.scrollTo(scrollView, new ScrollToCommandData(destX, destY));
-        return;
-      }
-      case COMMAND_SCROLL_WITHOUT_ANIMATION_TO: {
-        int destX = Math.round(PixelUtil.toPixelFromDIP(args.getDouble(0)));
-        int destY = Math.round(PixelUtil.toPixelFromDIP(args.getDouble(1)));
-        viewManager.scrollWithoutAnimationTo(scrollView, new ScrollToCommandData(destX, destY));
+        boolean animated = args.getBoolean(2);
+        viewManager.scrollTo(scrollView, new ScrollToCommandData(destX, destY, animated));
         return;
       }
       default:
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java
index 6289ce22dc79..ff71d30ab872 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java
@@ -82,14 +82,11 @@ public void receiveCommand(
   public void scrollTo(
       ReactScrollView scrollView,
       ReactScrollViewCommandHelper.ScrollToCommandData data) {
-    scrollView.smoothScrollTo(data.mDestX, data.mDestY);
-  }
-
-  @Override
-  public void scrollWithoutAnimationTo(
-      ReactScrollView scrollView,
-      ReactScrollViewCommandHelper.ScrollToCommandData data) {
-    scrollView.scrollTo(data.mDestX, data.mDestY);
+    if (data.mAnimated) {
+      scrollView.smoothScrollTo(data.mDestX, data.mDestY);
+    } else {
+      scrollView.scrollTo(data.mDestX, data.mDestY);
+    }
   }
 
   @Override

From 33e8a03adae4c11329b8dacb5a7bb01e8056c263 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Mon, 1 Feb 2016 05:32:31 -0800
Subject: [PATCH 0958/1411] Open sourced view tests

Reviewed By: mkonicek

Differential Revision: D2881830

fb-gh-sync-id: fef9176964892c5aa40633c177f1d5d8e3aed499
---
 .../libraries/fresco/fresco-react-native/BUCK |  24 +-
 .../src/main/third-party/java/jackson/BUCK    |  35 ++
 .../src/test/java/com/facebook/react/BUCK     |  34 ++
 .../react/CompositeReactPackageTest.java      | 218 ++++++++++
 .../java/com/facebook/react/RootViewTest.java | 192 +++++++++
 .../test/java/com/facebook/react/bridge/BUCK  |  33 +-
 .../bridge/JavaScriptModuleConfigTest.java    |  98 +++++
 .../bridge/NativeModuleRegistryTest.java      | 296 ++++++++++++++
 .../test/java/com/facebook/react/views/BUCK   |  39 ++
 .../views/image/ImageResizeModeTest.java      |  49 +++
 .../views/image/ReactImagePropertyTest.java   | 134 ++++++
 .../react/views/text/ReactTextTest.java       | 386 ++++++++++++++++++
 .../textinput/ReactTextInputPropertyTest.java | 314 ++++++++++++++
 .../react/views/textinput/TextInputTest.java  | 191 +++++++++
 .../react/views/view/ColorUtilTest.java       |  53 +++
 15 files changed, 2093 insertions(+), 3 deletions(-)
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/BUCK
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/CompositeReactPackageTest.java
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/bridge/JavaScriptModuleConfigTest.java
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/bridge/NativeModuleRegistryTest.java
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/views/BUCK
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/views/image/ImageResizeModeTest.java
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/views/image/ReactImagePropertyTest.java
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.java
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/views/view/ColorUtilTest.java

diff --git a/ReactAndroid/src/main/libraries/fresco/fresco-react-native/BUCK b/ReactAndroid/src/main/libraries/fresco/fresco-react-native/BUCK
index 9c618db04d71..7b410d076afe 100644
--- a/ReactAndroid/src/main/libraries/fresco/fresco-react-native/BUCK
+++ b/ReactAndroid/src/main/libraries/fresco/fresco-react-native/BUCK
@@ -22,8 +22,18 @@ remote_file(
     sha1 = 'a944015ddf50fdad79302e42a85a351633c24472',
 )
 
+android_library(
+  name = 'imagepipeline',
+  exported_deps = [
+      ':imagepipeline-core',
+      ':bolts',
+  ],
+  visibility = ['//ReactAndroid/...',],
+)
+
+
 android_prebuilt_aar(
-    name = 'imagepipeline',
+    name = 'imagepipeline-core',
     aar = ':imagepipeline-aar',
     visibility = ['//ReactAndroid/...',],
 )
@@ -34,6 +44,18 @@ remote_file(
     sha1 = '93fe3e629c03aea8f63dabd80a0e616b0caef65b',
 )
 
+prebuilt_jar(
+  name = 'bolts',
+  binary_jar = ':download-bolts',
+  visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+  name = 'download-bolts',
+  url = 'mvn:com.parse.bolts:bolts-tasks:jar:1.4.0',
+  sha1 = 'd85884acf6810a3bbbecb587f239005cbc846dc4',
+)
+
 android_prebuilt_aar(
     name = 'fbcore',
     aar = ':fbcore-aar',
diff --git a/ReactAndroid/src/main/third-party/java/jackson/BUCK b/ReactAndroid/src/main/third-party/java/jackson/BUCK
index 818c52c8ae6f..e6377adf4ed5 100644
--- a/ReactAndroid/src/main/third-party/java/jackson/BUCK
+++ b/ReactAndroid/src/main/third-party/java/jackson/BUCK
@@ -1,3 +1,14 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'jackson',
+  exported_deps = [
+    ':databind',
+    ':annotations',
+  ],
+  visibility = ['//ReactAndroid/...',],
+)
+
 prebuilt_jar(
     name = 'core',
     binary_jar = ':jackson-core-binary-jar',
@@ -9,3 +20,27 @@ remote_file(
     url = 'mvn:com.fasterxml.jackson.core:jackson-core:jar:2.2.3',
     sha1 = '1a0113da2cab5f4c216b4e5e7c1dbfaa67087e14',
 )
+
+prebuilt_jar(
+    name = 'databind',
+    binary_jar = ':jackson-databind-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'jackson-databind-jar',
+    url = 'mvn:com.fasterxml.jackson.core:jackson-databind:jar:2.2.3',
+    sha1 = '03ae380888029daefb91d3ecdca3a37d8cb92bc9',
+)
+
+prebuilt_jar(
+    name = 'annotations',
+    binary_jar = ':jackson-annotations-jar',
+    visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+    name = 'jackson-annotations-jar',
+    url = 'mvn:com.fasterxml.jackson.core:jackson-annotations:jar:2.2.3',
+    sha1 = '0527fece4f23a457070a36c371a26d6c0208e1c3',
+)
diff --git a/ReactAndroid/src/test/java/com/facebook/react/BUCK b/ReactAndroid/src/test/java/com/facebook/react/BUCK
new file mode 100644
index 000000000000..0396f42ae08a
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/BUCK
@@ -0,0 +1,34 @@
+include_defs('//ReactAndroid/DEFS')
+
+robolectric3_test(
+  name = 'react',
+  # Please change the contact to the oncall of your team
+  contacts = ['oncall+fbandroid_sheriff@xmail.facebook.com'],
+  srcs = glob(['*.java']),
+  deps = [
+    react_native_target('java/com/facebook/csslayout:csslayout'),
+    react_native_target('java/com/facebook/react:react'),
+    react_native_target('java/com/facebook/react/animation:animation'),
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/touch:touch'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_target('java/com/facebook/react/views/text:text'),
+    react_native_target('java/com/facebook/react/views/view:view'),
+    react_native_tests_target('java/com/facebook/react/bridge:testhelpers'),
+
+    react_native_dep('third-party/java/robolectric3/robolectric:robolectric'),
+    react_native_dep('third-party/java/fest:fest'),
+    react_native_dep('third-party/java/junit:junit'),
+    react_native_dep('third-party/java/okio:okio'),
+    react_native_dep('third-party/java/mockito:mockito'),
+    react_native_dep('third-party/java/okhttp:okhttp'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+    react_native_dep('libraries/fbcore/src/test/java/com/facebook/powermock:powermock'),
+  ],
+)
+
+project_config(
+  test_target = ':react',
+)
+
diff --git a/ReactAndroid/src/test/java/com/facebook/react/CompositeReactPackageTest.java b/ReactAndroid/src/test/java/com/facebook/react/CompositeReactPackageTest.java
new file mode 100644
index 000000000000..38e2dce4864c
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/CompositeReactPackageTest.java
@@ -0,0 +1,218 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react;
+
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import com.facebook.react.bridge.JavaScriptModule;
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.uimanager.ViewManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.Rule;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.modules.junit4.rule.PowerMockRule;
+import org.robolectric.RobolectricTestRunner;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(RobolectricTestRunner.class)
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+public class CompositeReactPackageTest {
+
+  @Rule
+  public PowerMockRule rule = new PowerMockRule();
+
+  @Mock ReactPackage packageNo1;
+  @Mock ReactPackage packageNo2;
+  @Mock ReactPackage packageNo3;
+
+  @Mock ReactApplicationContext reactContext;
+
+  @Before
+  public void initMocks() {
+    MockitoAnnotations.initMocks(this);
+  }
+
+  @Test
+  public void testThatCreateNativeModulesIsCalledOnAllPackages() {
+    // Given
+    CompositeReactPackage composite = new CompositeReactPackage(packageNo1, packageNo2, packageNo3);
+
+    // When
+    composite.createNativeModules(reactContext);
+
+    // Then
+    verify(packageNo1).createNativeModules(reactContext);
+    verify(packageNo2).createNativeModules(reactContext);
+    verify(packageNo3).createNativeModules(reactContext);
+  }
+
+  @Test
+  public void testThatCreateJSModulesIsCalledOnAllPackages() {
+    // Given
+    CompositeReactPackage composite = new CompositeReactPackage(packageNo1, packageNo2, packageNo3);
+
+    // When
+    composite.createJSModules();
+
+    // Then
+    verify(packageNo1).createJSModules();
+    verify(packageNo2).createJSModules();
+    verify(packageNo3).createJSModules();
+  }
+
+  @Test
+  public void testThatCreateViewManagersIsCalledOnAllPackages() {
+    // Given
+    CompositeReactPackage composite = new CompositeReactPackage(packageNo1, packageNo2, packageNo3);
+
+    // When
+    composite.createViewManagers(reactContext);
+
+    // Then
+    verify(packageNo1).createViewManagers(reactContext);
+    verify(packageNo2).createViewManagers(reactContext);
+    verify(packageNo3).createViewManagers(reactContext);
+  }
+
+  @Test
+  public void testThatCompositeReturnsASumOfNativeModules() {
+    // Given
+    CompositeReactPackage composite = new CompositeReactPackage(packageNo1, packageNo2);
+
+    NativeModule moduleNo1 = mock(NativeModule.class);
+    when(moduleNo1.getName()).thenReturn("ModuleNo1");
+
+    // module2 and module3 will share same name, composite should return only the latter one
+    final String sameModuleName = "SameModuleName";
+
+    NativeModule moduleNo2 = mock(NativeModule.class);
+    when(moduleNo2.getName()).thenReturn(sameModuleName);
+
+    NativeModule moduleNo3 = mock(NativeModule.class);
+    when(moduleNo3.getName()).thenReturn(sameModuleName);
+
+    NativeModule moduleNo4 = mock(NativeModule.class);
+    when(moduleNo4.getName()).thenReturn("ModuleNo4");
+
+    when(packageNo1.createNativeModules(reactContext)).thenReturn(
+        Arrays.asList(new NativeModule[]{moduleNo1, moduleNo2}));
+
+    when(packageNo2.createNativeModules(reactContext)).thenReturn(
+        Arrays.asList(new NativeModule[]{moduleNo3, moduleNo4}));
+
+    // When
+    List<NativeModule> compositeModules = composite.createNativeModules(reactContext);
+
+    // Then
+
+    // Wrapping lists into sets to be order-independent.
+    // Note that there should be no module2 returned.
+    Set<NativeModule> expected = new HashSet<>(
+        Arrays.asList(new NativeModule[]{moduleNo1, moduleNo3, moduleNo4}));
+    Set<NativeModule> actual = new HashSet<>(compositeModules);
+
+    assertEquals(expected, actual);
+  }
+
+  @Test
+  public void testThatCompositeReturnsASumOfViewManagers() {
+    // Given
+    CompositeReactPackage composite = new CompositeReactPackage(packageNo1, packageNo2);
+
+    ViewManager managerNo1 = mock(ViewManager.class);
+    when(managerNo1.getName()).thenReturn("ManagerNo1");
+
+    // managerNo2 and managerNo3 will share same name, composite should return only the latter one
+    final String sameModuleName = "SameModuleName";
+
+    ViewManager managerNo2 = mock(ViewManager.class);
+    when(managerNo2.getName()).thenReturn(sameModuleName);
+
+    ViewManager managerNo3 = mock(ViewManager.class);
+    when(managerNo3.getName()).thenReturn(sameModuleName);
+
+    ViewManager managerNo4 = mock(ViewManager.class);
+    when(managerNo4.getName()).thenReturn("ManagerNo4");
+
+    when(packageNo1.createViewManagers(reactContext)).thenReturn(
+        Arrays.asList(new ViewManager[]{managerNo1, managerNo2}));
+
+    when(packageNo2.createViewManagers(reactContext)).thenReturn(
+        Arrays.asList(new ViewManager[]{managerNo3, managerNo4}));
+
+    // When
+    List<ViewManager> compositeModules = composite.createViewManagers(reactContext);
+
+    // Then
+
+    // Wrapping lists into sets to be order-independent.
+    // Note that there should be no managerNo2 returned.
+    Set<ViewManager> expected = new HashSet<>(
+        Arrays.asList(new ViewManager[]{managerNo1, managerNo3, managerNo4})
+    );
+    Set<ViewManager> actual = new HashSet<>(compositeModules);
+
+    assertEquals(expected, actual);
+  }
+
+  // public access level is required by Mockito
+  public static class JavaScriptModuleNo1 implements JavaScriptModule {};
+  public static class JavaScriptModuleNo2 implements JavaScriptModule {};
+  public static class JavaScriptModuleNo3 implements JavaScriptModule {};
+
+  @Test
+  public void testThatCompositeReturnsASumOfJSModules() {
+    // Given
+    CompositeReactPackage composite = new CompositeReactPackage(packageNo1, packageNo2);
+
+    Class<? extends JavaScriptModule> moduleNo1 = mock(JavaScriptModuleNo1.class).getClass();
+    Class<? extends JavaScriptModule> moduleNo2 = mock(JavaScriptModuleNo2.class).getClass();
+    Class<? extends JavaScriptModule> moduleNo3 = mock(JavaScriptModuleNo3.class).getClass();
+
+    List<Class<? extends JavaScriptModule>> l1 = new ArrayList<>();
+    l1.add(moduleNo1);
+    when(packageNo1.createJSModules()).thenReturn(l1);
+
+    List<Class<? extends JavaScriptModule>> l2 = new ArrayList<>();
+    l2.add(moduleNo2);
+    l2.add(moduleNo3);
+    when(packageNo2.createJSModules()).thenReturn(l2);
+
+    // When
+    List<Class<? extends JavaScriptModule>> compositeModules = composite.createJSModules();
+
+    // Then
+
+    // wrapping lists into sets to be order-independent
+    List<Class<? extends JavaScriptModule>> l3 = new ArrayList<>();
+    l3.add(moduleNo1);
+    l3.add(moduleNo2);
+    l3.add(moduleNo3);
+    Set<Class<? extends JavaScriptModule>> expected = new HashSet<>(l3);
+    Set<Class<? extends JavaScriptModule>> actual = new HashSet<>(compositeModules);
+
+    assertEquals(expected, actual);
+  }
+}
diff --git a/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java b/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java
new file mode 100644
index 000000000000..388d5064d532
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java
@@ -0,0 +1,192 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react;
+
+import java.util.Date;
+
+import android.util.DisplayMetrics;
+import android.view.MotionEvent;
+
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.CatalystInstance;
+import com.facebook.react.bridge.ReactTestHelper;
+import com.facebook.react.bridge.SimpleArray;
+import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.bridge.WritableArray;
+import com.facebook.react.uimanager.UIManagerModule;
+import com.facebook.react.uimanager.DisplayMetricsHolder;
+import com.facebook.react.uimanager.events.Event;
+import com.facebook.react.uimanager.events.EventDispatcher;
+import com.facebook.react.uimanager.events.RCTEventEmitter;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.Rule;
+import org.mockito.ArgumentCaptor;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.modules.junit4.rule.PowerMockRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@PrepareForTest(Arguments.class)
+@RunWith(RobolectricTestRunner.class)
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+public class RootViewTest {
+
+  @Rule
+  public PowerMockRule rule = new PowerMockRule();
+
+  private ReactContext mReactContext;
+  private CatalystInstance mCatalystInstanceMock;
+
+  @Before
+  public void setUp() {
+    PowerMockito.mockStatic(Arguments.class);
+    PowerMockito.when(Arguments.createArray()).thenAnswer(new Answer<Object>() {
+      @Override
+      public Object answer(InvocationOnMock invocation) throws Throwable {
+        return new SimpleArray();
+      }
+    });
+    PowerMockito.when(Arguments.createMap()).thenAnswer(new Answer<Object>() {
+      @Override
+      public Object answer(InvocationOnMock invocation) throws Throwable {
+        return new SimpleMap();
+      }
+    });
+
+    mCatalystInstanceMock = ReactTestHelper.createMockCatalystInstance();
+    mReactContext = new ReactApplicationContext(RuntimeEnvironment.application);
+    mReactContext.initializeWithInstance(mCatalystInstanceMock);
+    DisplayMetrics displayMetrics = mReactContext.getResources().getDisplayMetrics();
+    DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
+
+    UIManagerModule uiManagerModuleMock = mock(UIManagerModule.class);
+    when(mCatalystInstanceMock.getNativeModule(UIManagerModule.class))
+        .thenReturn(uiManagerModuleMock);
+  }
+
+  @Test
+  public void testTouchEmitter() {
+    ReactInstanceManager instanceManager = mock(ReactInstanceManager.class);
+    when(instanceManager.getCurrentReactContext()).thenReturn(mReactContext);
+
+    UIManagerModule uiManager = mock(UIManagerModule.class);
+    EventDispatcher eventDispatcher = mock(EventDispatcher.class);
+    RCTEventEmitter eventEmitterModuleMock = mock(RCTEventEmitter.class);
+    when(mCatalystInstanceMock.getNativeModule(UIManagerModule.class))
+        .thenReturn(uiManager);
+    when(uiManager.getEventDispatcher()).thenReturn(eventDispatcher);
+
+    int rootViewId = 7;
+
+    ReactRootView rootView = new ReactRootView(mReactContext);
+    rootView.setId(rootViewId);
+    rootView.startReactApplication(instanceManager, "");
+    rootView.simulateAttachForTesting();
+
+    long ts = new Date().getTime();
+
+    // Test ACTION_DOWN event
+    rootView.onTouchEvent(
+        MotionEvent.obtain(100, ts, MotionEvent.ACTION_DOWN, 0, 0, 0));
+
+    ArgumentCaptor<Event> downEventCaptor = ArgumentCaptor.forClass(Event.class);
+    verify(eventDispatcher).dispatchEvent(downEventCaptor.capture());
+    verifyNoMoreInteractions(eventDispatcher);
+
+    downEventCaptor.getValue().dispatch(eventEmitterModuleMock);
+
+    ArgumentCaptor<SimpleArray> downActionTouchesArgCaptor =
+        ArgumentCaptor.forClass(SimpleArray.class);
+    verify(eventEmitterModuleMock).receiveTouches(
+        eq("topTouchStart"),
+        downActionTouchesArgCaptor.capture(),
+        any(SimpleArray.class));
+    verifyNoMoreInteractions(eventEmitterModuleMock);
+
+    assertThat(downActionTouchesArgCaptor.getValue().size()).isEqualTo(1);
+    assertThat(downActionTouchesArgCaptor.getValue().getMap(0)).isEqualTo(
+        SimpleMap.of(
+            "pageX",
+            0.,
+            "pageY",
+            0.,
+            "locationX",
+            0.,
+            "locationY",
+            0.,
+            "target",
+            rootViewId,
+            "timeStamp",
+            (double) ts,
+            "identifier",
+            0.));
+
+    // Test ACTION_UP event
+    reset(eventEmitterModuleMock, eventDispatcher);
+
+    ArgumentCaptor<Event> upEventCaptor = ArgumentCaptor.forClass(Event.class);
+    ArgumentCaptor<SimpleArray> upActionTouchesArgCaptor =
+        ArgumentCaptor.forClass(SimpleArray.class);
+
+    rootView.onTouchEvent(
+        MotionEvent.obtain(50, ts, MotionEvent.ACTION_UP, 0, 0, 0));
+    verify(eventDispatcher).dispatchEvent(upEventCaptor.capture());
+    verifyNoMoreInteractions(eventDispatcher);
+
+    upEventCaptor.getValue().dispatch(eventEmitterModuleMock);
+    verify(eventEmitterModuleMock).receiveTouches(
+        eq("topTouchEnd"),
+        upActionTouchesArgCaptor.capture(),
+        any(WritableArray.class));
+    verifyNoMoreInteractions(eventEmitterModuleMock);
+
+    assertThat(upActionTouchesArgCaptor.getValue().size()).isEqualTo(1);
+    assertThat(upActionTouchesArgCaptor.getValue().getMap(0)).isEqualTo(
+        SimpleMap.of(
+            "pageX",
+            0.,
+            "pageY",
+            0.,
+            "locationX",
+            0.,
+            "locationY",
+            0.,
+            "target",
+            rootViewId,
+            "timeStamp",
+            (double) ts,
+            "identifier",
+            0.));
+
+    // Test other action
+    reset(eventDispatcher);
+    rootView.onTouchEvent(
+        MotionEvent.obtain(50, new Date().getTime(), MotionEvent.ACTION_HOVER_MOVE, 0, 0, 0));
+    verifyNoMoreInteractions(eventDispatcher);
+  }
+}
diff --git a/ReactAndroid/src/test/java/com/facebook/react/bridge/BUCK b/ReactAndroid/src/test/java/com/facebook/react/bridge/BUCK
index bb67c85be89d..9e0251c7878a 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/bridge/BUCK
+++ b/ReactAndroid/src/test/java/com/facebook/react/bridge/BUCK
@@ -1,12 +1,12 @@
 include_defs('//ReactAndroid/DEFS')
 
 STANDARD_TEST_SRCS = [
-  '**/*Test.java',
+  '*Test.java',
 ]
 
 android_library(
   name = 'testhelpers',
-  srcs = glob(['**/*.java'], excludes = STANDARD_TEST_SRCS),
+  srcs = glob(['*.java'], excludes = STANDARD_TEST_SRCS),
   deps = [
     react_native_target('java/com/facebook/react/bridge:bridge'),
     react_native_target('java/com/facebook/react/uimanager:uimanager'),
@@ -18,3 +18,32 @@ android_library(
     'PUBLIC'
   ],
 )
+
+robolectric3_test(
+  name = 'bridge',
+  # Please change the contact to the oncall of your team
+  contacts = ['oncall+fbandroid_sheriff@xmail.facebook.com'],
+  srcs = glob(STANDARD_TEST_SRCS),
+  deps = [
+    ':testhelpers',
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+
+    react_native_dep('third-party/java/robolectric3/robolectric:robolectric'),
+    react_native_dep('third-party/java/fest:fest'),
+    react_native_dep('third-party/java/junit:junit'),
+    react_native_dep('third-party/java/mockito:mockito'),
+    react_native_dep('third-party/java/jackson:core'),
+    react_native_dep('third-party/java/jackson:jackson'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+    react_native_dep('libraries/fbcore/src/test/java/com/facebook/powermock:powermock'),
+  ],
+  visibility = [
+    'PUBLIC'
+  ],
+)
+
+project_config(
+  test_target = ':bridge',
+)
diff --git a/ReactAndroid/src/test/java/com/facebook/react/bridge/JavaScriptModuleConfigTest.java b/ReactAndroid/src/test/java/com/facebook/react/bridge/JavaScriptModuleConfigTest.java
new file mode 100644
index 000000000000..6b2b9ea7bb9d
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/bridge/JavaScriptModuleConfigTest.java
@@ -0,0 +1,98 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.bridge;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.Test;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+
+public class JavaScriptModuleConfigTest {
+
+  private static interface SomeModule extends JavaScriptModule {
+    public void stringMethod(String arg);
+    public void intMethod(int arg);
+  }
+
+  private static interface OtherModule extends JavaScriptModule {
+    public void method(String arg1, int arg2);
+  }
+
+  @Test
+  public void testModuleWithMethods() throws Exception {
+    JavaScriptModulesConfig jsModulesConfig = new JavaScriptModulesConfig.Builder()
+        .add(SomeModule.class)
+        .build();
+
+    String json = getModuleDescriptions(jsModulesConfig);
+    JsonNode node = parse(json);
+    assertThat(node).hasSize(1);
+
+    JsonNode module = node.fields().next().getValue();
+    assertThat(module).isNotNull();
+
+    JsonNode methods = module.get("methods");
+    assertThat(methods)
+        .isNotNull()
+        .hasSize(2);
+
+    JsonNode intMethodNode = methods.get("intMethod");
+    assertThat(intMethodNode).isNotNull();
+    assertThat(intMethodNode.get("methodID").asInt()).isEqualTo(0);
+
+    JsonNode stringMethod = methods.get("stringMethod");
+    assertThat(stringMethod).isNotNull();
+    assertThat(stringMethod.get("methodID").asInt()).isEqualTo(1);
+  }
+
+  @Test
+  public void testMultipleModules() throws Exception {
+    JavaScriptModulesConfig jsModulesConfig = new JavaScriptModulesConfig.Builder()
+        .add(OtherModule.class)
+        .add(SomeModule.class)
+        .build();
+
+    String json = getModuleDescriptions(jsModulesConfig);
+    JsonNode node = parse(json);
+    assertThat(node).hasSize(2);
+
+    JsonNode someModuleNode = node.get("SomeModule");
+    assertThat(someModuleNode).isNotNull();
+    int someModuleID = someModuleNode.get("moduleID").asInt();
+
+    JsonNode otherModuleNode = node.get("OtherModule");
+    assertThat(otherModuleNode).isNotNull();
+    int otherModuleID = otherModuleNode.get("moduleID").asInt();
+    assertThat(otherModuleID)
+        .isNotEqualTo(someModuleID);
+  }
+
+  private static String getModuleDescriptions(JavaScriptModulesConfig jsModulesConfig)
+      throws IOException {
+    JsonFactory jsonFactory = new JsonFactory();
+    StringWriter writer = new StringWriter();
+    JsonGenerator jg = jsonFactory.createGenerator(writer);
+    jsModulesConfig.writeModuleDescriptions(jg);
+    jg.close();
+    return writer.getBuffer().toString();
+  }
+
+  private JsonNode parse(String json) throws Exception {
+    ObjectMapper mapper = new ObjectMapper();
+    return mapper.readTree(json);
+  }
+
+}
diff --git a/ReactAndroid/src/test/java/com/facebook/react/bridge/NativeModuleRegistryTest.java b/ReactAndroid/src/test/java/com/facebook/react/bridge/NativeModuleRegistryTest.java
new file mode 100644
index 000000000000..813120c21763
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/bridge/NativeModuleRegistryTest.java
@@ -0,0 +1,296 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.bridge;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import com.facebook.react.common.MapBuilder;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.TextNode;
+import org.junit.Test;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+import org.powermock.modules.junit4.rule.PowerMockRule;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.robolectric.RobolectricTestRunner;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link NativeModuleRegistry}.
+ */
+@RunWith(RobolectricTestRunner.class)
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+public class NativeModuleRegistryTest {
+
+  @Rule
+  public PowerMockRule rule = new PowerMockRule();
+
+  @Test
+  public void testModuleWithMethods() throws Exception {
+    NativeModuleRegistry registry = new NativeModuleRegistry.Builder()
+        .add(new MethodsModule())
+        .build();
+
+    String json = getModuleDescriptions(registry);
+    JsonNode node = parse(json);
+
+    JsonNode module = node.fields().next().getValue();
+    assertThat(module).isNotNull();
+
+    JsonNode methods = module.get("methods");
+    assertThat(methods).isNotNull();
+
+    ArrayList<String> expected = new ArrayList<String>();
+    expected.add("doSomething");
+    expected.add("saveData");
+
+    assertMethodsContainExactly(methods, expected);
+  }
+
+  @Test
+  public void testAsyncMethod() throws Exception {
+    NativeModuleRegistry registry = new NativeModuleRegistry.Builder()
+        .add(new MethodsModule())
+        .build();
+
+    String json = getModuleDescriptions(registry);
+    JsonNode node = parse(json);
+
+    JsonNode asyncMethodData = node.get("TestModule").get("methods").get("saveData");
+    assertThat(asyncMethodData.get("type")).isEqualTo(new TextNode("remoteAsync"));
+
+    JsonNode regularMethodData = node.get("TestModule").get("methods").get("doSomething");
+    assertThat(regularMethodData.get("type")).isNotEqualTo(new TextNode("remoteAsync"));
+  }
+
+  @Test
+  public void testModuleWithConstants() throws Exception {
+    ConstantsModule constantsModule = new ConstantsModule();
+    NativeModuleRegistry registry = new NativeModuleRegistry.Builder()
+        .add(constantsModule)
+        .build();
+
+    String json = getModuleDescriptions(registry);
+    JsonNode node = parse(json);
+
+    JsonNode module = node.fields().next().getValue();
+    assertThat(module).isNotNull();
+
+    JsonNode methods = module.get("methods");
+    assertThat(methods).isNotNull();
+
+    ArrayList<String> expected = new ArrayList<String>();
+    expected.add("runDMC");
+
+    assertMethodsContainExactly(methods, expected);
+
+    JsonNode constants = module.get("constants");
+    assertThat(constants.get("testInt").asInt()).isEqualTo(3);
+    assertThat(constants.get("testDouble").asDouble()).isEqualTo(3.14);
+    assertThat(constants.get("testString").asText()).isEqualTo("red panda");
+
+    JsonNode stringMap = constants.get("testStringMap");
+    assertThat(stringMap.get("war_room").asText()).isEqualTo("17.1");
+    assertThat(stringMap.get("android_corex").asText()).isEqualTo("16.1");
+
+    JsonNode intMap = constants.get("testIntMap");
+    assertThat(intMap.get("42").asInt()).isEqualTo(1);
+    assertThat(intMap.get("84").asInt()).isEqualTo(2);
+
+    JsonNode stringList = constants.get("testStringList");
+    assertThat(stringList.get(0).asText()).isEqualTo("vulpes vulpes");
+    assertThat(stringList.get(4).asText()).isEqualTo("vulpes velox");
+
+    JsonNode intList = constants.get("testIntList");
+    assertThat(intList.get(0).asInt()).isEqualTo(3);
+    assertThat(intList.get(4).asInt()).isEqualTo(5);
+  }
+
+  @Test
+  public void testModuleWithOnlyConstants() throws Exception {
+    OnlyConstantsModule onlyConstantsModule = new OnlyConstantsModule();
+    NativeModuleRegistry registry = new NativeModuleRegistry.Builder()
+        .add(onlyConstantsModule)
+        .build();
+
+    String json = getModuleDescriptions(registry);
+    JsonNode node = parse(json);
+
+    JsonNode module = node.fields().next().getValue();
+    assertThat(module).isNotNull();
+
+    JsonNode constants = module.get("constants");
+    assertThat(constants.get("testInt").asInt()).isEqualTo(4);
+  }
+
+  @Test
+  public void testModuleWithNestedMapConstants() throws Exception {
+    NestedMapConstantsModule nestedMapConstantsModule = new NestedMapConstantsModule();
+    NativeModuleRegistry registry = new NativeModuleRegistry.Builder()
+        .add(nestedMapConstantsModule)
+        .build();
+
+    String json = getModuleDescriptions(registry);
+    JsonNode node = parse(json);
+
+    JsonNode module = node.fields().next().getValue();
+    assertThat(module).isNotNull();
+
+    JsonNode constants = module.get("constants");
+    assertThat(constants).isNotNull();
+
+    JsonNode nestedMapConstant = constants.get("nestedMap");
+    assertThat(nestedMapConstant).isNotNull();
+
+    JsonNode firstLevel = nestedMapConstant.get("weNeedToGoDeeper");
+    assertThat(firstLevel).isNotNull();
+
+    JsonNode secondLevel = firstLevel.get("evenDeeper");
+    assertThat(secondLevel).isNotNull();
+
+    assertThat(secondLevel.get("inception").asBoolean()).isTrue();
+  }
+
+  private JsonNode parse(String json) throws Exception {
+    ObjectMapper mapper = new ObjectMapper();
+    return mapper.readTree(json);
+  }
+
+  private void assertMethodsContainExactly(JsonNode methodsObject, List<String> methodNames) {
+    ArrayList<String> actual = new ArrayList();
+    Iterator<Map.Entry<String,JsonNode>> fields = methodsObject.fields();
+    while (fields.hasNext()) {
+      String name = fields.next().getKey();
+      actual.add(name);
+    }
+    assertThat(actual)
+        .hasSize(methodNames.size())
+        .containsAll(methodNames);
+  }
+
+  private static String getModuleDescriptions(NativeModuleRegistry registry)
+      throws IOException {
+    JsonFactory jsonFactory = new JsonFactory();
+    StringWriter writer = new StringWriter();
+    JsonGenerator jg = jsonFactory.createGenerator(writer);
+    registry.writeModuleDescriptions(jg);
+    jg.close();
+    return writer.getBuffer().toString();
+  }
+
+  private static class MethodsModule extends BaseJavaModule {
+
+    @Override
+    public String getName() {
+      return "TestModule";
+    }
+
+    public void notACatalystMethod() {
+    }
+
+    @ReactMethod
+    public void doSomething() {
+    }
+
+    @ReactMethod
+    public void saveData(Promise promise) {
+    }
+  }
+
+  private static class ConstantsModule extends BaseJavaModule {
+
+    @Override
+    public String getName() {
+      return "ConstantsModule";
+    }
+
+    @Override
+    public Map<String, Object> getConstants() {
+      HashMap<String, Object> constants = new HashMap<String, Object>();
+      constants.put("testInt", 3);
+      constants.put("testDouble", 3.14);
+      constants.put("testString", "red panda");
+      constants.put(
+          "testStringMap",
+          MapBuilder.of(
+              "war_room",
+              "17.1",
+              "android_corex",
+              "16.1"));
+      constants.put(
+          "testIntMap",
+          MapBuilder.of(
+              42,
+              1,
+              84,
+              2));
+      constants.put(
+          "testStringList",
+          Arrays.asList(
+              new String[]{
+                  "vulpes vulpes",
+                  "vulpes cana",
+                  "vulpes chama",
+                  "vulpes fulfa",
+                  "vulpes velox"}));
+      constants.put("testIntList", Arrays.asList(3, 1, 4, 1, 5));
+      return constants;
+    }
+
+    @ReactMethod
+    public void runDMC() {
+    }
+  }
+
+  private static class OnlyConstantsModule extends BaseJavaModule {
+
+    @Override
+    public String getName() {
+      return "OnlyConstantsModule";
+    }
+
+    @Override
+    public Map<String, Object> getConstants() {
+      return MapBuilder.<String, Object>of("testInt", 4);
+    }
+  }
+
+  private static class NestedMapConstantsModule extends BaseJavaModule {
+
+    @Override
+    public String getName() {
+      return "NestedMapConstantsModule";
+    }
+
+    @Override
+    public Map<String, Object> getConstants() {
+      return MapBuilder.<String, Object>of(
+          "nestedMap",
+          MapBuilder.of(
+              "weNeedToGoDeeper",
+              MapBuilder.of(
+                  "evenDeeper",
+                  MapBuilder.of("inception", true))));
+    }
+  }
+
+}
diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/BUCK b/ReactAndroid/src/test/java/com/facebook/react/views/BUCK
new file mode 100644
index 000000000000..5834b9374d1b
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/views/BUCK
@@ -0,0 +1,39 @@
+include_defs('//ReactAndroid/DEFS')
+
+robolectric3_test(
+  name = 'views',
+  # Please change the contact to the oncall of your team
+  contacts = ['oncall+fbandroid_sheriff@xmail.facebook.com'],
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/csslayout:csslayout'),
+    react_native_target('java/com/facebook/react:react'),
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/touch:touch'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
+    react_native_target('java/com/facebook/react/views/image:image'),
+    react_native_target('java/com/facebook/react/views/text:text'),
+    react_native_target('java/com/facebook/react/views/textinput:textinput'),
+    react_native_target('java/com/facebook/react/views/view:view'),
+
+    react_native_tests_target('java/com/facebook/react/bridge:testhelpers'),
+    react_native_dep('third-party/java/robolectric3/robolectric:robolectric'),
+    react_native_dep('third-party/java/fest:fest'),
+    react_native_dep('third-party/java/junit:junit'),
+    react_native_dep('third-party/java/okio:okio'),
+    react_native_dep('third-party/java/mockito:mockito'),
+    react_native_dep('third-party/java/okhttp:okhttp'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+
+    react_native_dep('libraries/fbcore/src/test/java/com/facebook/powermock:powermock'),
+    react_native_dep('libraries/fresco/fresco-react-native:fresco-react-native'),
+    react_native_dep('libraries/fresco/fresco-react-native:imagepipeline'),
+    react_native_dep('libraries/fresco/fresco-react-native:fresco-drawee'),
+  ],
+)
+
+project_config(
+  test_target = ':views',
+)
diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/image/ImageResizeModeTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/image/ImageResizeModeTest.java
new file mode 100644
index 000000000000..f74b4528e7ec
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/views/image/ImageResizeModeTest.java
@@ -0,0 +1,49 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.image;
+
+import com.facebook.drawee.drawable.ScalingUtils;
+
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.modules.junit4.rule.PowerMockRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+
+@RunWith(RobolectricTestRunner.class)
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+public class ImageResizeModeTest {
+
+  @Rule
+  public PowerMockRule rule = new PowerMockRule();
+
+  @Test
+  public void testImageResizeMode() {
+    assertThat(ImageResizeMode.toScaleType(null))
+        .isEqualTo(ScalingUtils.ScaleType.CENTER_CROP);
+
+    assertThat(ImageResizeMode.toScaleType("contain"))
+        .isEqualTo(ScalingUtils.ScaleType.CENTER_INSIDE);
+
+    assertThat(ImageResizeMode.toScaleType("cover"))
+        .isEqualTo(ScalingUtils.ScaleType.CENTER_CROP);
+
+    assertThat(ImageResizeMode.toScaleType("stretch"))
+        .isEqualTo(ScalingUtils.ScaleType.FIT_XY);
+
+    // No resizeMode set
+    assertThat(ImageResizeMode.defaultValue())
+        .isEqualTo(ScalingUtils.ScaleType.CENTER_CROP);
+  }
+}
diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/image/ReactImagePropertyTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/image/ReactImagePropertyTest.java
new file mode 100644
index 000000000000..030ce793e075
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/views/image/ReactImagePropertyTest.java
@@ -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.
+ */
+
+package com.facebook.react.views.image;
+
+import android.graphics.Color;
+import android.util.DisplayMetrics;
+
+import com.facebook.drawee.backends.pipeline.Fresco;
+import com.facebook.react.bridge.CatalystInstance;
+import com.facebook.react.bridge.ReactTestHelper;
+import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.uimanager.ReactStylesDiffMap;
+import com.facebook.react.uimanager.DisplayMetricsHolder;
+import com.facebook.react.uimanager.ThemedReactContext;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+import org.powermock.modules.junit4.rule.PowerMockRule;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.Robolectric;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Verify that {@link ScalingUtils} properties are being applied correctly
+ * by {@link ReactImageManager}.
+ */
+@RunWith(RobolectricTestRunner.class)
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+public class ReactImagePropertyTest {
+
+  @Rule
+  public PowerMockRule rule = new PowerMockRule();
+
+  private ReactApplicationContext mContext;
+  private CatalystInstance mCatalystInstanceMock;
+  private ThemedReactContext mThemeContext;
+
+  @Before
+  public void setup() {
+    mContext = new ReactApplicationContext(RuntimeEnvironment.application);
+    mCatalystInstanceMock = ReactTestHelper.createMockCatalystInstance();
+    mContext.initializeWithInstance(mCatalystInstanceMock);
+    mThemeContext = new ThemedReactContext(mContext, mContext);
+    Fresco.initialize(mContext);
+    DisplayMetricsHolder.setDisplayMetrics(new DisplayMetrics());
+  }
+
+  @After
+  public void teardown() {
+    DisplayMetricsHolder.setDisplayMetrics(null);
+  }
+
+  public ReactStylesDiffMap buildStyles(Object... keysAndValues) {
+    return new ReactStylesDiffMap(SimpleMap.of(keysAndValues));
+  }
+
+  @Test(expected=JSApplicationIllegalArgumentException.class)
+  public void testImageInvalidResizeMode() {
+    ReactImageManager viewManager = new ReactImageManager();
+    ReactImageView view = viewManager.createViewInstance(mThemeContext);
+    viewManager.updateProperties(view, buildStyles("resizeMode", "pancakes"));
+  }
+
+  @Test
+  public void testBorderColor() {
+    ReactImageManager viewManager = new ReactImageManager();
+    ReactImageView view = viewManager.createViewInstance(mThemeContext);
+    viewManager.updateProperties(view, buildStyles("src", "http://mysite.com/mypic.jpg"));
+
+    viewManager.updateProperties(view, buildStyles("borderColor", Color.argb(0, 0, 255, 255)));
+    int borderColor = view.getHierarchy().getRoundingParams().getBorderColor();
+    assertEquals(0, Color.alpha(borderColor));
+    assertEquals(0, Color.red(borderColor));
+    assertEquals(255, Color.green(borderColor));
+    assertEquals(255, Color.blue(borderColor));
+
+    viewManager.updateProperties(view, buildStyles("borderColor", Color.argb(0, 255, 50, 128)));
+    borderColor = view.getHierarchy().getRoundingParams().getBorderColor();
+    assertEquals(0, Color.alpha(borderColor));
+    assertEquals(255, Color.red(borderColor));
+    assertEquals(50, Color.green(borderColor));
+    assertEquals(128, Color.blue(borderColor));
+
+    viewManager.updateProperties(view, buildStyles("borderColor", null));
+    borderColor = view.getHierarchy().getRoundingParams().getBorderColor();
+    assertEquals(0, Color.alpha(borderColor));
+    assertEquals(0, Color.red(borderColor));
+    assertEquals(0, Color.green(borderColor));
+    assertEquals(0, Color.blue(borderColor));
+  }
+
+  @Test
+  public void testRoundedCorners() {
+    ReactImageManager viewManager = new ReactImageManager();
+    ReactImageView view = viewManager.createViewInstance(mThemeContext);
+    viewManager.updateProperties(view, buildStyles("src", "http://mysite.com/mypic.jpg"));
+
+    // We can't easily verify if rounded corner was honored or not, this tests simply verifies
+    // we're not crashing..
+    viewManager.updateProperties(view, buildStyles("borderRadius", (double) 10));
+    viewManager.updateProperties(view, buildStyles("borderRadius", (double) 0));
+    viewManager.updateProperties(view, buildStyles("borderRadius", null));
+  }
+
+  @Test
+  public void testTintColor() {
+    ReactImageManager viewManager = new ReactImageManager();
+    ReactImageView view = viewManager.createViewInstance(mThemeContext);
+    assertNull(view.getColorFilter());
+    viewManager.updateProperties(view, buildStyles("tintColor", Color.argb(50, 0, 0, 255)));
+            // Can't actually assert the specific color so this is the next best thing.
+            // Does the color filter now exist?
+            assertNotNull(view.getColorFilter());
+    viewManager.updateProperties(view, buildStyles("tintColor", null));
+    assertNull(view.getColorFilter());
+  }
+}
diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java
new file mode 100644
index 000000000000..890d0c0beee4
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java
@@ -0,0 +1,386 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.text;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import android.annotation.TargetApi;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.text.Spanned;
+import android.text.TextUtils;
+import android.text.style.AbsoluteSizeSpan;
+import android.view.Choreographer;
+import android.widget.TextView;
+
+import com.facebook.react.ReactRootView;
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.ReactTestHelper;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.SimpleArray;
+import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.uimanager.ReactChoreographer;
+import com.facebook.react.uimanager.UIImplementation;
+import com.facebook.react.uimanager.UIManagerModule;
+import com.facebook.react.uimanager.ViewManager;
+import com.facebook.react.uimanager.ViewProps;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.rule.PowerMockRule;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Tests for {@link UIManagerModule} specifically for React Text/RawText.
+ */
+@PrepareForTest({Arguments.class, ReactChoreographer.class})
+@RunWith(RobolectricTestRunner.class)
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+public class ReactTextTest {
+
+  @Rule
+  public PowerMockRule rule = new PowerMockRule();
+
+  private ArrayList<Choreographer.FrameCallback> mPendingChoreographerCallbacks;
+
+  @Before
+  public void setUp() {
+    PowerMockito.mockStatic(Arguments.class, ReactChoreographer.class);
+
+    ReactChoreographer choreographerMock = mock(ReactChoreographer.class);
+    PowerMockito.when(Arguments.createMap()).thenAnswer(new Answer<Object>() {
+      @Override
+      public Object answer(InvocationOnMock invocation) throws Throwable {
+        return new SimpleMap();
+      }
+    });
+    PowerMockito.when(ReactChoreographer.getInstance()).thenReturn(choreographerMock);
+
+    mPendingChoreographerCallbacks = new ArrayList<>();
+    doAnswer(new Answer() {
+      @Override
+      public Object answer(InvocationOnMock invocation) throws Throwable {
+        mPendingChoreographerCallbacks
+            .add((Choreographer.FrameCallback) invocation.getArguments()[1]);
+        return null;
+      }
+    }).when(choreographerMock).postFrameCallback(
+        any(ReactChoreographer.CallbackType.class),
+        any(Choreographer.FrameCallback.class));
+  }
+
+  @Test
+  public void testFontSizeApplied() {
+    UIManagerModule uiManager = getUIManagerModule();
+
+    ReactRootView rootView = createText(
+        uiManager,
+        SimpleMap.of(ViewProps.FONT_SIZE, 21.0),
+        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+
+    AbsoluteSizeSpan sizeSpan = getSingleSpan(
+        (TextView) rootView.getChildAt(0), AbsoluteSizeSpan.class);
+    assertThat(sizeSpan.getSize()).isEqualTo(21);
+  }
+
+  @Test
+  public void testBoldFontApplied() {
+    UIManagerModule uiManager = getUIManagerModule();
+
+    ReactRootView rootView = createText(
+        uiManager,
+        SimpleMap.of(ViewProps.FONT_WEIGHT, "bold"),
+        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+
+    CustomStyleSpan customStyleSpan =
+        getSingleSpan((TextView)rootView.getChildAt(0), CustomStyleSpan.class);
+    assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isNotZero();
+    assertThat(customStyleSpan.getStyle() & Typeface.ITALIC).isZero();
+  }
+
+  @Test
+  public void testNumericBoldFontApplied() {
+    UIManagerModule uiManager = getUIManagerModule();
+
+    ReactRootView rootView = createText(
+        uiManager,
+        SimpleMap.of(ViewProps.FONT_WEIGHT, "500"),
+        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+
+    CustomStyleSpan customStyleSpan =
+        getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
+    assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isNotZero();
+    assertThat(customStyleSpan.getStyle() & Typeface.ITALIC).isZero();
+  }
+
+  @Test
+  public void testItalicFontApplied() {
+    UIManagerModule uiManager = getUIManagerModule();
+
+    ReactRootView rootView = createText(
+        uiManager,
+        SimpleMap.of(ViewProps.FONT_STYLE, "italic"),
+        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+
+    CustomStyleSpan customStyleSpan =
+        getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
+    assertThat(customStyleSpan.getStyle() & Typeface.ITALIC).isNotZero();
+    assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isZero();
+  }
+
+  @Test
+  public void testBoldItalicFontApplied() {
+    UIManagerModule uiManager = getUIManagerModule();
+
+    ReactRootView rootView = createText(
+        uiManager,
+        SimpleMap.of(ViewProps.FONT_WEIGHT, "bold", ViewProps.FONT_STYLE, "italic"),
+        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+
+    CustomStyleSpan customStyleSpan =
+        getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
+    assertThat(customStyleSpan.getStyle() & Typeface.ITALIC).isNotZero();
+    assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isNotZero();
+  }
+
+  @Test
+  public void testNormalFontWeightApplied() {
+    UIManagerModule uiManager = getUIManagerModule();
+
+    ReactRootView rootView = createText(
+        uiManager,
+        SimpleMap.of(ViewProps.FONT_WEIGHT, "normal"),
+        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+
+    CustomStyleSpan customStyleSpan =
+        getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
+    assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isZero();
+  }
+
+  @Test
+  public void testNumericNormalFontWeightApplied() {
+    UIManagerModule uiManager = getUIManagerModule();
+
+    ReactRootView rootView = createText(
+        uiManager,
+        SimpleMap.of(ViewProps.FONT_WEIGHT, "200"),
+        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+
+    CustomStyleSpan customStyleSpan =
+        getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
+    assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isZero();
+  }
+
+  @Test
+  public void testNormalFontStyleApplied() {
+    UIManagerModule uiManager = getUIManagerModule();
+
+    ReactRootView rootView = createText(
+        uiManager,
+        SimpleMap.of(ViewProps.FONT_STYLE, "normal"),
+        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+
+    CustomStyleSpan customStyleSpan =
+        getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
+    assertThat(customStyleSpan.getStyle() & Typeface.ITALIC).isZero();
+  }
+
+  @Test
+  public void testFontFamilyStyleApplied() {
+    UIManagerModule uiManager = getUIManagerModule();
+
+    ReactRootView rootView = createText(
+        uiManager,
+        SimpleMap.of(ViewProps.FONT_FAMILY, "sans-serif"),
+        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+
+    CustomStyleSpan customStyleSpan =
+        getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
+    assertThat(customStyleSpan.getFontFamily()).isEqualTo("sans-serif");
+    assertThat(customStyleSpan.getStyle() & Typeface.ITALIC).isZero();
+    assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isZero();
+  }
+
+  @Test
+  public void testFontFamilyBoldStyleApplied() {
+    UIManagerModule uiManager = getUIManagerModule();
+
+    ReactRootView rootView = createText(
+        uiManager,
+        SimpleMap.of(ViewProps.FONT_FAMILY, "sans-serif", ViewProps.FONT_WEIGHT, "bold"),
+        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+
+    CustomStyleSpan customStyleSpan =
+        getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
+    assertThat(customStyleSpan.getFontFamily()).isEqualTo("sans-serif");
+    assertThat(customStyleSpan.getStyle() & Typeface.ITALIC).isZero();
+    assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isNotZero();
+  }
+
+  @Test
+  public void testFontFamilyItalicStyleApplied() {
+    UIManagerModule uiManager = getUIManagerModule();
+
+    ReactRootView rootView = createText(
+        uiManager,
+        SimpleMap.of(ViewProps.FONT_FAMILY, "sans-serif", ViewProps.FONT_STYLE, "italic"),
+        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+
+    CustomStyleSpan customStyleSpan =
+        getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
+    assertThat(customStyleSpan.getFontFamily()).isEqualTo("sans-serif");
+    assertThat(customStyleSpan.getStyle() & Typeface.ITALIC).isNotZero();
+    assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isZero();
+  }
+
+  @Test
+  public void testFontFamilyBoldItalicStyleApplied() {
+    UIManagerModule uiManager = getUIManagerModule();
+
+    ReactRootView rootView = createText(
+        uiManager,
+        SimpleMap.of(
+            ViewProps.FONT_FAMILY, "sans-serif",
+            ViewProps.FONT_WEIGHT, "500",
+            ViewProps.FONT_STYLE, "italic"),
+        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+
+    CustomStyleSpan customStyleSpan =
+        getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
+    assertThat(customStyleSpan.getFontFamily()).isEqualTo("sans-serif");
+    assertThat(customStyleSpan.getStyle() & Typeface.ITALIC).isNotZero();
+    assertThat(customStyleSpan.getWeight() & Typeface.BOLD).isNotZero();
+  }
+
+  @Test
+  public void testBackgroundColorStyleApplied() {
+    UIManagerModule uiManager = getUIManagerModule();
+
+    ReactRootView rootView = createText(
+        uiManager,
+        SimpleMap.of(ViewProps.BACKGROUND_COLOR, Color.BLUE),
+        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+
+    Drawable backgroundDrawable = ((TextView) rootView.getChildAt(0)).getBackground();
+    assertThat(((ColorDrawable) backgroundDrawable).getColor()).isEqualTo(Color.BLUE);
+  }
+
+  // JELLY_BEAN is needed for TextView#getMaxLines(), which is OK, because in the actual code we
+  // only use TextView#setMaxLines() which exists since API Level 1.
+  @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
+  @Test
+  public void testMaxLinesApplied() {
+    UIManagerModule uiManager = getUIManagerModule();
+
+    ReactRootView rootView = createText(
+        uiManager,
+        SimpleMap.of(ViewProps.NUMBER_OF_LINES, 2),
+        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+
+    TextView textView = (TextView) rootView.getChildAt(0);
+    assertThat(textView.getText().toString()).isEqualTo("test text");
+    assertThat(textView.getMaxLines()).isEqualTo(2);
+    assertThat(textView.getEllipsize()).isEqualTo(TextUtils.TruncateAt.END);
+  }
+
+  /**
+   * Make sure TextView has exactly one span and that span has given type.
+   */
+  private static <TSPAN> TSPAN getSingleSpan(TextView textView, Class<TSPAN> spanClass) {
+    Spanned text = (Spanned) textView.getText();
+    TSPAN[] spans = text.getSpans(0, text.length(), spanClass);
+    assertThat(spans).hasSize(1);
+    return spans[0];
+  }
+
+  private ReactRootView createText(
+      UIManagerModule uiManager,
+      SimpleMap textProps,
+      SimpleMap rawTextProps) {
+    ReactRootView rootView = new ReactRootView(RuntimeEnvironment.application);
+    int rootTag = uiManager.addMeasuredRootView(rootView);
+    int textTag = rootTag + 1;
+    int rawTextTag = textTag + 1;
+
+    uiManager.createView(
+        textTag,
+        ReactTextViewManager.REACT_CLASS,
+        rootTag,
+        textProps);
+    uiManager.createView(
+        rawTextTag,
+        ReactRawTextManager.REACT_CLASS,
+        rootTag,
+        rawTextProps);
+
+    uiManager.manageChildren(
+        textTag,
+        null,
+        null,
+        SimpleArray.of(rawTextTag),
+        SimpleArray.of(0),
+        null);
+
+    uiManager.manageChildren(
+        rootTag,
+        null,
+        null,
+        SimpleArray.of(textTag),
+        SimpleArray.of(0),
+        null);
+
+    uiManager.onBatchComplete();
+    executePendingChoreographerCallbacks();
+    return rootView;
+  }
+
+  private void executePendingChoreographerCallbacks() {
+    ArrayList<Choreographer.FrameCallback> callbacks =
+        new ArrayList<>(mPendingChoreographerCallbacks);
+    mPendingChoreographerCallbacks.clear();
+    for (Choreographer.FrameCallback frameCallback : callbacks) {
+      frameCallback.doFrame(0);
+    }
+  }
+
+  public UIManagerModule getUIManagerModule() {
+    ReactApplicationContext reactContext = ReactTestHelper.createCatalystContextForTest();
+    List<ViewManager> viewManagers = Arrays.asList(
+        new ViewManager[] {
+            new ReactTextViewManager(),
+            new ReactRawTextManager(),
+        });
+    UIManagerModule uiManagerModule = new UIManagerModule(
+        reactContext,
+        viewManagers,
+        new UIImplementation(reactContext, viewManagers));
+    uiManagerModule.onHostResume();
+    return uiManagerModule;
+  }
+}
diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.java
new file mode 100644
index 000000000000..a423801991f5
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.java
@@ -0,0 +1,314 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.textinput;
+
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.text.InputType;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.widget.EditText;
+
+import com.facebook.react.bridge.CatalystInstance;
+import com.facebook.react.bridge.ReactTestHelper;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.JSApplicationCausedNativeException;
+import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.uimanager.ReactStylesDiffMap;
+import com.facebook.react.uimanager.DisplayMetricsHolder;
+import com.facebook.react.views.text.DefaultStyleValuesUtil;
+import com.facebook.react.uimanager.ThemedReactContext;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.powermock.modules.junit4.rule.PowerMockRule;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+
+/**
+ * Verify {@link EditText} view property being applied properly by {@link ReactTextInputManager}
+ */
+@RunWith(RobolectricTestRunner.class)
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+public class ReactTextInputPropertyTest {
+
+  @Rule
+  public PowerMockRule rule = new PowerMockRule();
+
+  private ReactApplicationContext mContext;
+  private CatalystInstance mCatalystInstanceMock;
+  private ThemedReactContext mThemedContext;
+  private ReactTextInputManager mManager;
+
+  @Before
+  public void setup() {
+    mContext = new ReactApplicationContext(RuntimeEnvironment.application);
+    mCatalystInstanceMock = ReactTestHelper.createMockCatalystInstance();
+    mContext.initializeWithInstance(mCatalystInstanceMock);
+    mThemedContext = new ThemedReactContext(mContext, mContext);
+    mManager = new ReactTextInputManager();
+    DisplayMetricsHolder.setDisplayMetrics(new DisplayMetrics());
+  }
+
+  public ReactStylesDiffMap buildStyles(Object... keysAndValues) {
+    return new ReactStylesDiffMap(SimpleMap.of(keysAndValues));
+  }
+
+  @Test
+  public void testAutoCorrect() {
+    ReactEditText view = mManager.createViewInstance(mThemedContext);
+
+    mManager.updateProperties(view, buildStyles());
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT).isZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS).isZero();
+
+    mManager.updateProperties(view, buildStyles("autoCorrect", true));
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT).isNotZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS).isZero();
+
+    mManager.updateProperties(view, buildStyles("autoCorrect", false));
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT).isZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS).isNotZero();
+
+    mManager.updateProperties(view, buildStyles("autoCorrect", null));
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT).isZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS).isZero();
+  }
+
+  @Test
+  public void testAutoCapitalize() {
+    ReactEditText view = mManager.createViewInstance(mThemedContext);
+
+    mManager.updateProperties(view, buildStyles());
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_SENTENCES).isZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_WORDS).isZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS).isZero();
+
+    mManager.updateProperties(
+        view,
+        buildStyles("autoCapitalize", InputType.TYPE_TEXT_FLAG_CAP_SENTENCES));
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_SENTENCES).isNotZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_WORDS).isZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS).isZero();
+
+    mManager.updateProperties(
+        view,
+        buildStyles("autoCapitalize", InputType.TYPE_TEXT_FLAG_CAP_WORDS));
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_SENTENCES).isZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_WORDS).isNotZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS).isZero();
+
+    mManager.updateProperties(
+        view,
+        buildStyles("autoCapitalize", InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS));
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_SENTENCES).isZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_WORDS).isZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS).isNotZero();
+
+    mManager.updateProperties(
+        view,
+        buildStyles("autoCapitalize", InputType.TYPE_CLASS_TEXT));
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_SENTENCES).isZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_WORDS).isZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS).isZero();
+  }
+
+  @Test
+  public void testPlaceholder() {
+    ReactEditText view = mManager.createViewInstance(mThemedContext);
+    mManager.updateProperties(view, buildStyles());
+    assertThat(view.getHint()).isNull();
+
+    mManager.updateProperties(view, buildStyles("placeholder", "sometext"));
+    assertThat(view.getHint()).isEqualTo("sometext");
+
+    mManager.updateProperties(view, buildStyles("placeholder", null));
+    assertThat(view.getHint()).isNull();
+  }
+
+  @Test
+  public void testEditable() {
+    ReactEditText view = mManager.createViewInstance(mThemedContext);
+
+    mManager.updateProperties(view, buildStyles());
+    assertThat(view.isEnabled()).isTrue();
+
+    mManager.updateProperties(view, buildStyles("editable", false));
+    assertThat(view.isEnabled()).isFalse();
+
+    mManager.updateProperties(view, buildStyles("editable", null));
+    assertThat(view.isEnabled()).isTrue();
+
+    mManager.updateProperties(view, buildStyles("editable", false));
+    assertThat(view.isEnabled()).isFalse();
+
+    mManager.updateProperties(view, buildStyles("editable", true));
+    assertThat(view.isEnabled()).isTrue();
+  }
+
+  @Test
+  public void testPlaceholderTextColor() {
+    ReactEditText view = mManager.createViewInstance(mThemedContext);
+
+    final ColorStateList defaultPlaceholderColorStateList =
+        DefaultStyleValuesUtil.getDefaultTextColorHint(
+            view.getContext());
+
+    ColorStateList colors = view.getHintTextColors();
+    assertThat(colors).isEqualTo(defaultPlaceholderColorStateList);
+
+    mManager.updateProperties(view, buildStyles("placeholderTextColor", null));
+    colors = view.getHintTextColors();
+    assertThat(colors).isEqualTo(defaultPlaceholderColorStateList);
+
+    mManager.updateProperties(view, buildStyles("placeholderTextColor", Color.RED));
+    colors = view.getHintTextColors();
+    assertThat(colors.getDefaultColor()).isEqualTo(Color.RED);
+
+    mManager.updateProperties(view, buildStyles("placeholderTextColor", null));
+    colors = view.getHintTextColors();
+    assertThat(colors).isEqualTo(defaultPlaceholderColorStateList);
+  }
+
+  @Test
+  public void testMultiline() {
+    ReactEditText view = mManager.createViewInstance(mThemedContext);
+
+    mManager.updateProperties(view, buildStyles());
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_MULTI_LINE).isZero();
+
+    mManager.updateProperties(view, buildStyles("multiline", false));
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_MULTI_LINE).isZero();
+
+    mManager.updateProperties(view, buildStyles("multiline", true));
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_MULTI_LINE).isNotZero();
+
+    mManager.updateProperties(view, buildStyles("multiline", null));
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_MULTI_LINE).isZero();
+  }
+
+  @Test
+  public void testNumLines() {
+    ReactEditText view = mManager.createViewInstance(mThemedContext);
+
+    mManager.updateProperties(view, buildStyles());
+    assertThat(view.getMinLines()).isEqualTo(1);
+
+    mManager.updateProperties(view, buildStyles("numberOfLines", 5));
+    assertThat(view.getMinLines()).isEqualTo(5);
+
+    mManager.updateProperties(view, buildStyles("numberOfLines", 4));
+    assertThat(view.getMinLines()).isEqualTo(4);
+  }
+
+  @Test
+  public void testKeyboardType() {
+    ReactEditText view = mManager.createViewInstance(mThemedContext);
+
+    mManager.updateProperties(view, buildStyles());
+    assertThat(view.getInputType() & InputType.TYPE_CLASS_NUMBER).isZero();
+
+    mManager.updateProperties(view, buildStyles("keyboardType", "text"));
+    assertThat(view.getInputType() & InputType.TYPE_CLASS_NUMBER).isZero();
+
+    mManager.updateProperties(view, buildStyles("keyboardType", "numeric"));
+    assertThat(view.getInputType() & InputType.TYPE_CLASS_NUMBER).isNotZero();
+
+    mManager.updateProperties(view, buildStyles("keyboardType", "email-address"));
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS).isNotZero();
+
+    mManager.updateProperties(view, buildStyles("keyboardType", null));
+    assertThat(view.getInputType() & InputType.TYPE_CLASS_NUMBER).isZero();
+  }
+
+  @Test
+  public void testPasswordInput() {
+    ReactEditText view = mManager.createViewInstance(mThemedContext);
+
+    mManager.updateProperties(view, buildStyles());
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_VARIATION_PASSWORD).isZero();
+
+    mManager.updateProperties(view, buildStyles("password", false));
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_VARIATION_PASSWORD).isZero();
+
+    mManager.updateProperties(view, buildStyles("password", true));
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_VARIATION_PASSWORD).isNotZero();
+
+    mManager.updateProperties(view, buildStyles("password", null));
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_VARIATION_PASSWORD).isZero();
+  }
+
+  @Test
+  public void testIncrementalInputTypeUpdates() {
+    ReactEditText view = mManager.createViewInstance(mThemedContext);
+
+    mManager.updateProperties(view, buildStyles());
+    assertThat(view.getInputType() & InputType.TYPE_CLASS_NUMBER).isZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_MULTI_LINE).isZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT).isZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS).isZero();
+
+    mManager.updateProperties(view, buildStyles("multiline", true));
+    assertThat(view.getInputType() & InputType.TYPE_CLASS_NUMBER).isZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_MULTI_LINE).isNotZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT).isZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS).isZero();
+
+    mManager.updateProperties(view, buildStyles("autoCorrect", false));
+    assertThat(view.getInputType() & InputType.TYPE_CLASS_NUMBER).isZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_MULTI_LINE).isNotZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT).isZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS).isNotZero();
+
+    mManager.updateProperties(view, buildStyles("keyboardType", "NUMERIC"));
+    assertThat(view.getInputType() & InputType.TYPE_CLASS_NUMBER).isNotZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_MULTI_LINE).isNotZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT).isZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS).isNotZero();
+
+    mManager.updateProperties(view, buildStyles("multiline", null));
+    assertThat(view.getInputType() & InputType.TYPE_CLASS_NUMBER).isNotZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_MULTI_LINE).isZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT).isZero();
+    assertThat(view.getInputType() & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS).isNotZero();
+  }
+
+  @Test
+  public void testTextAlign() {
+    ReactEditText view = mManager.createViewInstance(mThemedContext);
+    int gravity = view.getGravity();
+    assertThat(view.getGravity() & Gravity.BOTTOM).isNotEqualTo(Gravity.BOTTOM);
+
+    mManager.updateProperties(view, buildStyles("textAlignVertical", "bottom"));
+    assertThat(view.getGravity() & Gravity.BOTTOM).isEqualTo(Gravity.BOTTOM);
+
+    mManager.updateProperties(
+        view,
+        buildStyles("textAlign", "right", "textAlignVertical", "top"));
+    assertThat(view.getGravity() & Gravity.BOTTOM).isNotEqualTo(Gravity.BOTTOM);
+    assertThat(view.getGravity() & (Gravity.RIGHT | Gravity.TOP))
+        .isEqualTo(Gravity.RIGHT | Gravity.TOP);
+
+    mManager.updateProperties(
+        view,
+        buildStyles("textAlignVertical", null));
+    assertThat(view.getGravity() & Gravity.RIGHT).isEqualTo(Gravity.RIGHT);
+    assertThat(view.getGravity() & Gravity.TOP).isNotEqualTo(Gravity.TOP);
+
+    mManager.updateProperties(view, buildStyles("textAlign", null));
+    assertThat(view.getGravity()).isEqualTo(gravity);
+  }
+}
diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java
new file mode 100644
index 000000000000..56d79f8bfae8
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java
@@ -0,0 +1,191 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.textinput;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import android.view.Choreographer;
+import android.widget.EditText;
+
+import com.facebook.react.ReactRootView;
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.ReactTestHelper;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.SimpleArray;
+import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.uimanager.ReactChoreographer;
+import com.facebook.react.uimanager.UIImplementation;
+import com.facebook.react.uimanager.UIManagerModule;
+import com.facebook.react.uimanager.ViewManager;
+import com.facebook.react.uimanager.ViewProps;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.rule.PowerMockRule;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Tests for TextInput.
+ */
+@PrepareForTest({Arguments.class, ReactChoreographer.class})
+@RunWith(RobolectricTestRunner.class)
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+public class TextInputTest {
+
+  @Rule
+  public PowerMockRule rule = new PowerMockRule();
+
+  private ArrayList<Choreographer.FrameCallback> mPendingChoreographerCallbacks;
+
+  @Before
+  public void setUp() {
+    PowerMockito.mockStatic(Arguments.class, ReactChoreographer.class);
+
+    ReactChoreographer choreographerMock = mock(ReactChoreographer.class);
+    PowerMockito.when(Arguments.createMap()).thenAnswer(new Answer<Object>() {
+      @Override
+      public Object answer(InvocationOnMock invocation) throws Throwable {
+        return new SimpleMap();
+      }
+    });
+    PowerMockito.when(ReactChoreographer.getInstance()).thenReturn(choreographerMock);
+
+    mPendingChoreographerCallbacks = new ArrayList<>();
+    doAnswer(new Answer() {
+      @Override
+      public Object answer(InvocationOnMock invocation) throws Throwable {
+        mPendingChoreographerCallbacks
+            .add((Choreographer.FrameCallback) invocation.getArguments()[1]);
+        return null;
+      }
+    }).when(choreographerMock).postFrameCallback(
+        any(ReactChoreographer.CallbackType.class),
+        any(Choreographer.FrameCallback.class));
+  }
+
+  @Test
+  public void testPropsApplied() {
+    UIManagerModule uiManager = getUIManagerModule();
+
+    ReactRootView rootView = new ReactRootView(RuntimeEnvironment.application);
+    int rootTag = uiManager.addMeasuredRootView(rootView);
+    int textInputTag = rootTag + 1;
+    final String hintStr = "placeholder text";
+
+    uiManager.createView(
+        textInputTag,
+        ReactTextInputManager.REACT_CLASS,
+        rootTag,
+        SimpleMap.of(
+            ViewProps.FONT_SIZE, 13.37, ViewProps.HEIGHT, 20.0, "placeholder", hintStr));
+
+    uiManager.manageChildren(
+        rootTag,
+        null,
+        null,
+        SimpleArray.of(textInputTag),
+        SimpleArray.of(0),
+        null);
+
+    uiManager.onBatchComplete();
+    executePendingChoreographerCallbacks();
+
+    EditText editText = (EditText) rootView.getChildAt(0);
+    assertThat(editText.getHint()).isEqualTo(hintStr);
+    assertThat(editText.getTextSize()).isEqualTo((float) Math.ceil(13.37));
+    assertThat(editText.getHeight()).isEqualTo(20);
+  }
+
+  @Test
+  public void testPropsUpdate() {
+    UIManagerModule uiManager = getUIManagerModule();
+
+    ReactRootView rootView = new ReactRootView(RuntimeEnvironment.application);
+    int rootTag = uiManager.addMeasuredRootView(rootView);
+    int textInputTag = rootTag + 1;
+    final String hintStr = "placeholder text";
+
+    uiManager.createView(
+        textInputTag,
+        ReactTextInputManager.REACT_CLASS,
+        rootTag,
+        SimpleMap.of(
+            ViewProps.FONT_SIZE, 13.37, ViewProps.HEIGHT, 20.0, "placeholder", hintStr));
+
+    uiManager.manageChildren(
+        rootTag,
+        null,
+        null,
+        SimpleArray.of(textInputTag),
+        SimpleArray.of(0),
+        null);
+    uiManager.onBatchComplete();
+    executePendingChoreographerCallbacks();
+
+    EditText editText = (EditText) rootView.getChildAt(0);
+    assertThat(editText.getHint()).isEqualTo(hintStr);
+    assertThat(editText.getTextSize()).isEqualTo((float) Math.ceil(13.37));
+    assertThat(editText.getHeight()).isEqualTo(20);
+
+    final String hintStr2 = "such hint";
+    uiManager.updateView(
+        textInputTag,
+        ReactTextInputManager.REACT_CLASS,
+        SimpleMap.of(
+            ViewProps.FONT_SIZE, 26.74, ViewProps.HEIGHT, 40.0, "placeholder", hintStr2));
+
+    uiManager.onBatchComplete();
+    executePendingChoreographerCallbacks();
+
+    EditText updatedEditText = (EditText) rootView.getChildAt(0);
+    assertThat(updatedEditText.getHint()).isEqualTo(hintStr2);
+    assertThat(updatedEditText.getTextSize()).isEqualTo((float) Math.ceil(26.74f));
+    assertThat(updatedEditText.getHeight()).isEqualTo(40);
+  }
+
+  private void executePendingChoreographerCallbacks() {
+    ArrayList<Choreographer.FrameCallback> callbacks =
+        new ArrayList<>(mPendingChoreographerCallbacks);
+    mPendingChoreographerCallbacks.clear();
+    for (Choreographer.FrameCallback frameCallback : callbacks) {
+      frameCallback.doFrame(0);
+    }
+  }
+
+  public UIManagerModule getUIManagerModule() {
+    ReactApplicationContext reactContext = ReactTestHelper.createCatalystContextForTest();
+    List<ViewManager> viewManagers = Arrays.asList(
+        new ViewManager[] {
+            new ReactTextInputManager(),
+        });
+    UIManagerModule uiManagerModule = new UIManagerModule(
+        reactContext,
+        viewManagers,
+        new UIImplementation(reactContext, viewManagers));
+    uiManagerModule.onHostResume();
+    return uiManagerModule;
+  }
+}
diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/view/ColorUtilTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/view/ColorUtilTest.java
new file mode 100644
index 000000000000..9b79b2594f0a
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/views/view/ColorUtilTest.java
@@ -0,0 +1,53 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.view;
+
+import android.graphics.PixelFormat;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.modules.junit4.rule.PowerMockRule;
+import org.robolectric.RobolectricTestRunner;
+
+import static org.junit.Assert.*;
+
+/**
+ * Based on Fresco's DrawableUtilsTest (https://github.com/facebook/fresco).
+ */
+@RunWith(RobolectricTestRunner.class)
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+public class ColorUtilTest {
+
+  @Rule
+  public PowerMockRule rule = new PowerMockRule();
+
+  @Test
+  public void testMultiplyColorAlpha() {
+    assertEquals(0x00123456, ColorUtil.multiplyColorAlpha(0xC0123456, 0));
+    assertEquals(0x07123456, ColorUtil.multiplyColorAlpha(0xC0123456, 10));
+    assertEquals(0x96123456, ColorUtil.multiplyColorAlpha(0xC0123456, 200));
+    assertEquals(0xC0123456, ColorUtil.multiplyColorAlpha(0xC0123456, 255));
+  }
+
+  @Test
+  public void testGetOpacityFromColor() {
+    assertEquals(PixelFormat.TRANSPARENT, ColorUtil.getOpacityFromColor(0x00000000));
+    assertEquals(PixelFormat.TRANSPARENT, ColorUtil.getOpacityFromColor(0x00123456));
+    assertEquals(PixelFormat.TRANSPARENT, ColorUtil.getOpacityFromColor(0x00FFFFFF));
+    assertEquals(PixelFormat.TRANSLUCENT, ColorUtil.getOpacityFromColor(0xC0000000));
+    assertEquals(PixelFormat.TRANSLUCENT, ColorUtil.getOpacityFromColor(0xC0123456));
+    assertEquals(PixelFormat.TRANSLUCENT, ColorUtil.getOpacityFromColor(0xC0FFFFFF));
+    assertEquals(PixelFormat.OPAQUE, ColorUtil.getOpacityFromColor(0xFF000000));
+    assertEquals(PixelFormat.OPAQUE, ColorUtil.getOpacityFromColor(0xFF123456));
+    assertEquals(PixelFormat.OPAQUE, ColorUtil.getOpacityFromColor(0xFFFFFFFF));
+  }
+}

From 97723e4d7e3c6b5475eb94d3f8c9f8cef53fd2e4 Mon Sep 17 00:00:00 2001
From: Shane Rogers <srogers@quickleft.com>
Date: Mon, 1 Feb 2016 07:42:33 -0800
Subject: [PATCH 0959/1411] Typo

Summary:
Tiny typo :)

:bee: :beers:
Closes https://github.com/facebook/react-native/pull/5665

Reviewed By: svcscm

Differential Revision: D2885581

Pulled By: androidtrunkagent

fb-gh-sync-id: 4f442a95ea05e2f58c47c664644210c99e256943
---
 packager/react-native-xcode.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packager/react-native-xcode.sh b/packager/react-native-xcode.sh
index 87251051f12e..66ecea85464c 100755
--- a/packager/react-native-xcode.sh
+++ b/packager/react-native-xcode.sh
@@ -8,7 +8,7 @@
 
 # Bundle React Native app's code and image assets.
 # This script is supposed to be invoked as part of Xcode build process
-# and relies on envoronment variables (including PWD) set by Xcode
+# and relies on environment variables (including PWD) set by Xcode
 
 # There is no point in creating an offline package for simulator builds
 # because the packager is supposed to be running during development anyways

From bb5a6be9dd996febaed5b55fb59d095f0dc4c4d3 Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Mon, 1 Feb 2016 07:50:50 -0800
Subject: [PATCH 0960/1411] Only execute update block once

Summary:
We were executing all the updateBlocks for every frame that was updated in the UI flush. This would quickly give you an explosive number of block calls when loading complex views.

This update block is only really used by text to propagate padding, even though the actual insets are mostly just 0.

public

Reviewed By: nicklockwood

Differential Revision: D2848968

fb-gh-sync-id: e43c529c2bb9729e2b779bf4abefeed58775cc2e
---
 React/Modules/RCTUIManager.m | 60 +++++++++++++++++++++---------------
 1 file changed, 35 insertions(+), 25 deletions(-)

diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m
index 9d0ea2502437..d98cf73363df 100644
--- a/React/Modules/RCTUIManager.m
+++ b/React/Modules/RCTUIManager.m
@@ -483,6 +483,8 @@ - (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTShadowView *)roo
     [NSMutableArray arrayWithCapacity:viewsWithNewFrames.count];
   NSMutableArray<NSNumber *> *parentsAreNew =
     [NSMutableArray arrayWithCapacity:viewsWithNewFrames.count];
+  NSMutableDictionary<NSNumber *, RCTViewManagerUIBlock> *updateBlocks =
+    [NSMutableDictionary new];
 
   for (RCTShadowView *shadowView in viewsWithNewFrames) {
     [frameReactTags addObject:shadowView.reactTag];
@@ -500,10 +502,13 @@ - (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTShadowView *)roo
   // reactSetFrame: has been called. Note that if reactSetFrame: is not called,
   // these won't be called either, so this is not a suitable place to update
   // properties that aren't related to layout.
-  NSMutableArray<RCTViewManagerUIBlock> *updateBlocks = [NSMutableArray new];
   for (RCTShadowView *shadowView in viewsWithNewFrames) {
     RCTViewManager *manager = [_componentDataByName[shadowView.viewName] manager];
     RCTViewManagerUIBlock block = [manager uiBlockToAmendWithShadowView:shadowView];
+    if (block) {
+      updateBlocks[shadowView.reactTag] = block;
+    }
+
     if (shadowView.onLayout) {
       CGRect frame = shadowView.frame;
       shadowView.onLayout(@{
@@ -525,14 +530,9 @@ - (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTShadowView *)roo
         RCTAssert(view != nil, @"view (for ID %@) not found", reactTag);
 
         RCTRootView *rootView = (RCTRootView *)[view superview];
-
         rootView.intrinsicSize = contentSize;
       });
     }
-
-    if (block) {
-      [updateBlocks addObject:block];
-    }
   }
 
   // Perform layout (possibly animated)
@@ -561,24 +561,10 @@ - (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTShadowView *)roo
         }
       };
 
-      // Animate view update
-      if (updateAnimation) {
-        [updateAnimation performAnimations:^{
-          [view reactSetFrame:frame];
-          for (RCTViewManagerUIBlock block in updateBlocks) {
-            block(self, _viewRegistry);
-          }
-        } withCompletionBlock:completion];
-      } else {
-        [view reactSetFrame:frame];
-        for (RCTViewManagerUIBlock block in updateBlocks) {
-          block(self, _viewRegistry);
-        }
-        completion(YES);
-      }
-
       // Animate view creation
       if (createAnimation) {
+        [view reactSetFrame:frame];
+
         CATransform3D finalTransform = view.layer.transform;
         CGFloat finalOpacity = view.layer.opacity;
         if ([createAnimation.property isEqualToString:@"scaleXY"]) {
@@ -586,6 +572,7 @@ - (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTShadowView *)roo
         } else if ([createAnimation.property isEqualToString:@"opacity"]) {
           view.layer.opacity = 0.0;
         }
+
         [createAnimation performAnimations:^{
           if ([createAnimation.property isEqual:@"scaleXY"]) {
             view.layer.transform = finalTransform;
@@ -595,10 +582,33 @@ - (RCTViewManagerUIBlock)uiBlockWithLayoutUpdateForRootView:(RCTShadowView *)roo
             RCTLogError(@"Unsupported layout animation createConfig property %@",
                         createAnimation.property);
           }
-          for (RCTViewManagerUIBlock block in updateBlocks) {
-            block(self, _viewRegistry);
+
+          RCTViewManagerUIBlock updateBlock = updateBlocks[reactTag];
+          if (updateBlock) {
+            updateBlock(self, _viewRegistry);
+          }
+        } withCompletionBlock:completion];
+
+      // Animate view update
+      } else if (updateAnimation) {
+        [updateAnimation performAnimations:^{
+          [view reactSetFrame:frame];
+
+          RCTViewManagerUIBlock updateBlock = updateBlocks[reactTag];
+          if (updateBlock) {
+            updateBlock(self, _viewRegistry);
           }
-        } withCompletionBlock:nil];
+        } withCompletionBlock:completion];
+
+      // Update without animation
+      } else {
+        [view reactSetFrame:frame];
+
+        RCTViewManagerUIBlock updateBlock = updateBlocks[reactTag];
+        if (updateBlock) {
+          updateBlock(self, _viewRegistry);
+        }
+        completion(YES);
       }
     }
   };

From 8e603940e3fca4ed2fe420c02a66d860b53f3076 Mon Sep 17 00:00:00 2001
From: Jack Hsu <jack.hsu@gmail.com>
Date: Mon, 1 Feb 2016 09:08:56 -0800
Subject: [PATCH 0961/1411] Use `getRealMetrics` for display metrics. Closes
 #4934

Summary:
Fixes https://github.com/facebook/react-native/issues/4934.

Since API level 17, there has a `Display.getRealMetrics` method. This allows us to get the actual sizes of the screen (including soft menu bar and other system decor elements).

See: http://developer.android.com/reference/android/view/Display.html#getRealMetrics(android.util.DisplayMetrics)

I'm not sure if there is a good way to write unit or integration tests for this. Please let me know if there are any suggestions or concerns.
Closes https://github.com/facebook/react-native/pull/4935

Reviewed By: svcscm

Differential Revision: D2811091

Pulled By: bestander

fb-gh-sync-id: fed4e357db7eb36d638eebabd8ced4bdffd766a4
---
 .../react/uimanager/UIManagerModule.java      | 45 ++++++++++++++++++-
 1 file changed, 44 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
index 2a701d692983..725c874c3923 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
@@ -11,11 +11,17 @@
 
 import javax.annotation.Nullable;
 
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 
+import android.content.Context;
+import android.os.Build;
 import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.WindowManager;
 
 import com.facebook.csslayout.CSSLayoutContext;
 import com.facebook.infer.annotation.Assertions;
@@ -84,7 +90,9 @@ public UIManagerModule(
       UIImplementation uiImplementation) {
     super(reactContext);
     mEventDispatcher = new EventDispatcher(reactContext);
-    DisplayMetrics displayMetrics = reactContext.getResources().getDisplayMetrics();
+
+    DisplayMetrics displayMetrics = getDisplayMetrics();
+
     DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
     mModuleConstants = createConstants(displayMetrics, viewManagerList);
     mUIImplementation = uiImplementation;
@@ -452,4 +460,39 @@ public EventDispatcher getEventDispatcher() {
   public void sendAccessibilityEvent(int tag, int eventType) {
     mUIImplementation.sendAccessibilityEvent(tag, eventType);
   }
+
+  private DisplayMetrics getDisplayMetrics() {
+    Context context = getReactApplicationContext();
+
+    DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+    WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+    Display display = wm.getDefaultDisplay();
+
+    // Get the real display metrics if we are using API level 17 or higher.
+    // The real metrics include system decor elements (e.g. soft menu bar).
+    //
+    // See: http://developer.android.com/reference/android/view/Display.html#getRealMetrics(android.util.DisplayMetrics)
+    if (Build.VERSION.SDK_INT >= 17){
+      display.getRealMetrics(displayMetrics);
+
+    } else {
+      // For 14 <= API level <= 16, we need to invoke getRawHeight and getRawWidth to get the real dimensions.
+      // Since react-native only supports API level 16+ we don't have to worry about other cases.
+      //
+      // Reflection exceptions are rethrown at runtime.
+      //
+      // See: http://stackoverflow.com/questions/14341041/how-to-get-real-screen-height-and-width/23861333#23861333
+      try {
+        Method mGetRawH = Display.class.getMethod("getRawHeight");
+        Method mGetRawW = Display.class.getMethod("getRawWidth");
+        displayMetrics.widthPixels = (Integer) mGetRawW.invoke(display);
+        displayMetrics.heightPixels = (Integer) mGetRawH.invoke(display);
+      } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
+        throw new RuntimeException("Error getting real dimensions for API level < 17", e);
+      }
+    }
+
+    return displayMetrics;
+  }
+
 }

From f6187565acf6bef204420abf68f9ecfe80888dc2 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Mon, 1 Feb 2016 09:42:03 -0800
Subject: [PATCH 0962/1411] fixed gradle deps

Summary: Closes https://github.com/facebook/react-native/pull/5670

Reviewed By: svcscm

Differential Revision: D2885815

Pulled By: androidtrunkagent

fb-gh-sync-id: 670f731b0b12ca2f1b31f0a982f109ce4f736836
---
 ReactAndroid/build.gradle | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle
index d1dffee7bb32..93768246fe07 100644
--- a/ReactAndroid/build.gradle
+++ b/ReactAndroid/build.gradle
@@ -252,7 +252,8 @@ dependencies {
     compile 'com.facebook.fresco:imagepipeline-okhttp:0.8.1'
     compile 'com.facebook.stetho:stetho:1.2.0'
     compile 'com.facebook.stetho:stetho-okhttp:1.2.0'
-    compile 'com.fasterxml.jackson.core:jackson-core:2.2.3'
+    compile 'com.fasterxml.jackson.core:jackson-annotations:2.2.3'
+    compile 'com.fasterxml.jackson.core:jackson-databind:2.2.3'
     compile 'com.google.code.findbugs:jsr305:3.0.0'
     compile 'com.squareup.okhttp:okhttp:2.5.0'
     compile 'com.squareup.okhttp:okhttp-ws:2.5.0'

From f04882f8e4b5755cc63b0b9a87672627e00ece51 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Mon, 1 Feb 2016 09:59:37 -0800
Subject: [PATCH 0963/1411] Fix problems with graceful-fs bug
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Summary:
public
This fixes the problem that graceful-fs exposes an unpatched `close()` method, that will never trigger retries.
This behavior deadlocks the packager when trying to use graceful-fs’s `open()`/`read()`/`close()` methods.

See: isaacs/node-graceful-fs#56

Reviewed By: cpojer

Differential Revision: D2885512

fb-gh-sync-id: 71112d2488929bf1775fe9f8566fa03fd66b6bea
---
 .../src/DependencyResolver/fastfs.js          | 96 ++++++++++++-------
 1 file changed, 61 insertions(+), 35 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/fastfs.js b/packager/react-packager/src/DependencyResolver/fastfs.js
index f33b9927851e..325604ffe08f 100644
--- a/packager/react-packager/src/DependencyResolver/fastfs.js
+++ b/packager/react-packager/src/DependencyResolver/fastfs.js
@@ -14,7 +14,10 @@ const {EventEmitter} = require('events');
 const fs = require('graceful-fs');
 const path = require('path');
 
-const open = Promise.denodeify(fs.open);
+// workaround for https://github.com/isaacs/node-graceful-fs/issues/56
+// fs.close is patched, whereas graceful-fs.close is not.
+const fsClose = require('fs').close;
+
 const readFile = Promise.denodeify(fs.readFile);
 const stat = Promise.denodeify(fs.stat);
 
@@ -251,41 +254,12 @@ class File {
   }
 
   readWhile(predicate) {
-    const CHUNK_SIZE = 512;
-    let result = '';
-
-    return open(this.path, 'r').then(fd => {
-      /* global Buffer: true */
-      const buffer = new Buffer(CHUNK_SIZE);
-      const p = new Promise((resolve, reject) => {
-        let counter = 0;
-        const callback = (error, bytesRead) => {
-          if (error) {
-            reject();
-            return;
-          }
-
-          const chunk = buffer.toString('utf8', 0, bytesRead);
-          result += chunk;
-          if (bytesRead > 0 && predicate(chunk, counter++, result)) {
-            readChunk(fd, buffer, callback);
-          } else {
-            if (bytesRead === 0 && !this._read) { // reached EOF
-              this._read = Promise.resolve(result);
-            }
-            resolve(result);
-          }
-        };
-        readChunk(fd, buffer, callback);
-      });
-
-      p.catch(() => fs.close(fd));
-      return p;
+    return readWhile(this.path, predicate).then(({result, completed}) => {
+      if (completed && !this._read) {
+        this._read = Promise.resolve(result);
+      }
+      return result;
     });
-
-    function readChunk(fd, buffer, callback) {
-      fs.read(fd, buffer, 0, CHUNK_SIZE, null, callback);
-    }
   }
 
   stat() {
@@ -365,6 +339,58 @@ class File {
   }
 }
 
+function readWhile(filePath, predicate) {
+  return new Promise((resolve, reject) => {
+    fs.open(filePath, 'r', (openError, fd) => {
+      if (openError) {
+        reject(openError);
+        return;
+      }
+
+      read(
+        fd,
+        /*global Buffer: true*/
+        new Buffer(512),
+        makeReadCallback(fd, predicate, (readError, result, completed) => {
+          if (readError) {
+            reject(readError);
+          } else {
+            resolve({result, completed});
+          }
+        })
+      );
+    });
+  });
+}
+
+function read(fd, buffer, callback) {
+  fs.read(fd, buffer, 0, buffer.length, -1, callback);
+}
+
+function close(fd, error, result, complete, callback) {
+  fsClose(fd, closeError => callback(error || closeError, result, complete));
+}
+
+function makeReadCallback(fd, predicate, callback) {
+  let result = '';
+  let index = 0;
+  return function readCallback(error, bytesRead, buffer) {
+    if (error) {
+      close(fd, error, undefined, false, callback);
+      return;
+    }
+
+    const completed = bytesRead === 0;
+    const chunk = completed ? '' : buffer.toString('utf8', 0, bytesRead);
+    result += chunk;
+    if (completed || !predicate(chunk, index++, result)) {
+      close(fd, null, result, completed, callback);
+    } else {
+      read(fd, buffer, readCallback);
+    }
+  };
+}
+
 function isDescendant(root, child) {
   return path.relative(root, child).indexOf('..') !== 0;
 }

From 80a2f5d50fc61b8ba48169d8dcca0247f4b484f2 Mon Sep 17 00:00:00 2001
From: Michael Tostenson <mtostenson@mail.csuchico.edu>
Date: Mon, 1 Feb 2016 10:05:26 -0800
Subject: [PATCH 0964/1411] Add headers prop to Android WebViews

Summary:
Related to [issue #5418](https://github.com/facebook/react-native/issues/5418)

This is a follow-up to [this previous pull request.](https://github.com/facebook/react-native/pull/5419)

~~Adds a new ReactProp 'urlWithHeaders' to Android WebViews that takes an object with a 'url' string and a 'headers' map.~~

[Update] Adds a new prop 'source' to Android WebViews
```
{
   html: string,
   url: string,
   headers: map<string, string>,
}
```

Update: resolves TODO 8495359
Closes https://github.com/facebook/react-native/pull/5494

Reviewed By: svcscm

Differential Revision: D2881313

Pulled By: nicklockwood

fb-gh-sync-id: 7cad8490d4932d0a7ef559165f3ec279d873c537
---
 .../Components/WebView/WebView.android.js     | 30 ++++++++--
 .../views/webview/ReactWebViewManager.java    | 58 +++++++++----------
 2 files changed, 55 insertions(+), 33 deletions(-)

diff --git a/Libraries/Components/WebView/WebView.android.js b/Libraries/Components/WebView/WebView.android.js
index e2bbad6e5ba1..1f6fdd98044d 100644
--- a/Libraries/Components/WebView/WebView.android.js
+++ b/Libraries/Components/WebView/WebView.android.js
@@ -17,6 +17,7 @@ var StyleSheet = require('StyleSheet');
 var UIManager = require('UIManager');
 var View = require('View');
 
+var deprecatedPropType = require('deprecatedPropType');
 var keyMirror = require('keyMirror');
 var merge = require('merge');
 var requireNativeComponent = require('requireNativeComponent');
@@ -44,14 +45,29 @@ var WebView = React.createClass({
     onLoadEnd: PropTypes.func,
     onLoadStart: PropTypes.func,
     onError: PropTypes.func,
-    url: PropTypes.string,
-    html: PropTypes.string,
     automaticallyAdjustContentInsets: PropTypes.bool,
     contentInset: EdgeInsetsPropType,
     onNavigationStateChange: PropTypes.func,
     startInLoadingState: PropTypes.bool, // force WebView to show loadingView on first load
     style: View.propTypes.style,
 
+    html: deprecatedPropType(
+      PropTypes.string,
+      'Use the `source` prop instead.'
+    ),
+
+    url: deprecatedPropType(
+      PropTypes.string,
+      'Use the `source` prop instead.'
+    ),
+
+    /**
+     * Used on Android only, provides html or url with optional headers to the WebView.
+     * `{ html: string, uri: string, headers: map<string, string> }`
+     * @platform android
+     */
+    source: PropTypes.object,
+
     /**
      * Used on Android only, JS is enabled by default for WebView on iOS
      * @platform android
@@ -127,13 +143,19 @@ var WebView = React.createClass({
       domStorageEnabled = this.props.domStorageEnabledAndroid;
     }
 
+    var source = this.props.source || {};
+    if (this.props.html) {
+      source.html = this.props.html;
+    } else if (this.props.url) {
+      source.uri = this.props.url;
+    }
+
     var webView =
       <RCTWebView
         ref={RCT_WEBVIEW_REF}
         key="webViewKey"
         style={webViewStyles}
-        url={this.props.url}
-        html={this.props.html}
+        source={source}
         injectedJavaScript={this.props.injectedJavaScript}
         userAgent={this.props.userAgent}
         javaScriptEnabled={javaScriptEnabled}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
index 7e756c782b14..41ab1b4149b1 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
@@ -9,10 +9,6 @@
 
 package com.facebook.react.views.webview;
 
-import javax.annotation.Nullable;
-
-import java.util.Map;
-
 import android.graphics.Bitmap;
 import android.os.Build;
 import android.os.SystemClock;
@@ -27,16 +23,23 @@
 import com.facebook.react.bridge.LifecycleEventListener;
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.ReadableMapKeySetIterator;
 import com.facebook.react.bridge.WritableMap;
 import com.facebook.react.common.MapBuilder;
 import com.facebook.react.common.build.ReactBuildConfig;
-import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.SimpleViewManager;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.UIManagerModule;
+import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.events.Event;
 import com.facebook.react.uimanager.events.EventDispatcher;
 
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
 /**
  * Manages instances of {@link WebView}
  *
@@ -271,31 +274,28 @@ public void setInjectedJavaScript(WebView view, @Nullable String injectedJavaScr
     ((ReactWebView) view).setInjectedJavaScript(injectedJavaScript);
   }
 
-  @ReactProp(name = "html")
-  public void setHtml(WebView view, @Nullable String html) {
-    if (html != null) {
-      view.loadData(html, HTML_MIME_TYPE, HTML_ENCODING);
-    } else {
-      view.loadUrl(BLANK_URL);
-    }
-  }
-
-  @ReactProp(name = "url")
-  public void setUrl(WebView view, @Nullable String url) {
-    // TODO(8495359): url and html are coupled as they both call loadUrl, therefore in case when
-    // property url is removed in favor of property html being added in single transaction we may
-    // end up in a state when blank url is loaded as it depends on the order of update operations!
-
-    String currentUrl = view.getUrl();
-    if (currentUrl != null && currentUrl.equals(url)) {
-      // We are already loading it so no need to stomp over it and start again
-      return;
-    }
-    if (url != null) {
-      view.loadUrl(url);
-    } else {
-      view.loadUrl(BLANK_URL);
+  @ReactProp(name = "source")
+  public void setSource(WebView view, @Nullable ReadableMap source) {
+    if (source != null) {
+      if (source.hasKey("html")) {
+        view.loadData(source.getString("html"), HTML_MIME_TYPE, HTML_ENCODING);
+        return;
+      }
+      if (source.hasKey("uri")) {
+        HashMap<String, String> headerMap = new HashMap<>();
+        if (source.hasKey("headers")) {
+          ReadableMap headers = source.getMap("headers");
+          ReadableMapKeySetIterator iter = headers.keySetIterator();
+          while (iter.hasNextKey()) {
+            String key = iter.nextKey();
+            headerMap.put(key, headers.getString(key));
+          }
+        }
+        view.loadUrl(source.getString("uri"), headerMap);
+        return;
+      }
     }
+    view.loadUrl(BLANK_URL);
   }
 
   @Override

From cb2eeb484d52c24853471025a49c136159429afa Mon Sep 17 00:00:00 2001
From: Brent Vatne <brentvatne@gmail.com>
Date: Mon, 1 Feb 2016 10:19:56 -0800
Subject: [PATCH 0965/1411] Add defaultSource example

Summary: Closes https://github.com/facebook/react-native/pull/5074

Reviewed By: svcscm

Differential Revision: D2798023

Pulled By: nicklockwood

fb-gh-sync-id: d8aa87bf8dcbecf53b341d5914bbe3354cc753aa
---
 Examples/UIExplorer/ImageExample.js | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/Examples/UIExplorer/ImageExample.js b/Examples/UIExplorer/ImageExample.js
index eb13b16b012c..1a9af6c877cd 100644
--- a/Examples/UIExplorer/ImageExample.js
+++ b/Examples/UIExplorer/ImageExample.js
@@ -187,6 +187,20 @@ exports.examples = [
     },
     platform: 'ios',
   },
+  {
+    title: 'defaultSource',
+    description: 'Show a placeholder image when a network image is loading',
+    render: function() {
+      return (
+        <Image
+          defaultSource={require('./bunny.png')}
+          source={{uri: 'http://facebook.github.io/origami/public/images/birds.jpg'}}
+          style={styles.base}
+        />
+      );
+    },
+    platform: 'ios',
+  },
   {
     title: 'Border Color',
     render: function() {

From 3e0631af7fb5c91efa151d70667f2111958ba163 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Mon, 1 Feb 2016 10:48:51 -0800
Subject: [PATCH 0966/1411] limiting BUCK's memory for CI

Summary: Closes https://github.com/facebook/react-native/pull/5666

Reviewed By: svcscm

Differential Revision: D2885968

Pulled By: androidtrunkagent

fb-gh-sync-id: 59614f89c18f8db96210e5c93f599055575330fa
---
 .buckconfig   | 2 --
 .buckjavaargs | 1 +
 circle.yml    | 3 ++-
 3 files changed, 3 insertions(+), 3 deletions(-)
 create mode 100644 .buckjavaargs

diff --git a/.buckconfig b/.buckconfig
index cc1b6556849d..934256cb29d4 100644
--- a/.buckconfig
+++ b/.buckconfig
@@ -4,5 +4,3 @@
 
 [maven_repositories]
   central = https://repo1.maven.org/maven2
-
-
diff --git a/.buckjavaargs b/.buckjavaargs
new file mode 100644
index 000000000000..11452478196f
--- /dev/null
+++ b/.buckjavaargs
@@ -0,0 +1 @@
+-Xmx512m -XX:+HeapDumpOnOutOfMemoryError
diff --git a/circle.yml b/circle.yml
index ee9901bbf112..b0ea6e9902b3 100644
--- a/circle.yml
+++ b/circle.yml
@@ -41,7 +41,7 @@ test:
     - source scripts/circle-ci-android-setup.sh && waitForAVD
   override:
     # buck tests
-    - buck/bin/buck test ReactAndroid/src/test/...
+    - buck/bin/buck test ReactAndroid/src/test/... --config build.threads=1
     - buck/bin/buck build ReactAndroid/src/main/java/com/facebook/react
     - buck/bin/buck build ReactAndroid/src/main/java/com/facebook/react/shell
     # temp, we can't run instrumentation tests yet
@@ -49,6 +49,7 @@ test:
 
     # unit tests
     - ./gradlew :ReactAndroid:testDebugUnitTest -PdisablePreDex
+
     # build JS bundle for instrumentation tests
     - node local-cli/cli.js bundle --platform android --dev true --entry-file ReactAndroid/src/androidTest/assets/TestBundle.js --bundle-output ReactAndroid/src/androidTest/assets/AndroidTestBundle.js
     # run tests on the emulator

From 180ead05e988de74b33dc75f92c29b8cc3c8deeb Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Mon, 1 Feb 2016 11:04:43 -0800
Subject: [PATCH 0967/1411] Fixed ScrollView.scrollTo() on iOS

Summary:
public
My refactor to unify the scrollTo() apis on iOS + Android broke iOS. Oops.

Reviewed By: jingc

Differential Revision: D2886305

fb-gh-sync-id: de287cba8df7cf14c8049d91621cd7f86aa4e92c
---
 React/Views/RCTScrollViewManager.m | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/React/Views/RCTScrollViewManager.m b/React/Views/RCTScrollViewManager.m
index 2d48c0cb67a0..9ab7ca806bc4 100644
--- a/React/Views/RCTScrollViewManager.m
+++ b/React/Views/RCTScrollViewManager.m
@@ -139,14 +139,15 @@ - (UIView *)view
 }
 
 RCT_EXPORT_METHOD(scrollTo:(nonnull NSNumber *)reactTag
-                  withOffset:(CGPoint)offset
+                  offsetX:(CGFloat)x
+                  offsetY:(CGFloat)y
                   animated:(BOOL)animated)
 {
   [self.bridge.uiManager addUIBlock:
    ^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry){
     UIView *view = viewRegistry[reactTag];
     if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) {
-      [(id<RCTScrollableProtocol>)view scrollToOffset:offset animated:animated];
+      [(id<RCTScrollableProtocol>)view scrollToOffset:(CGPoint){x, y} animated:animated];
     } else {
       RCTLogError(@"tried to scrollTo: on non-RCTScrollableProtocol view %@ "
                   "with tag #%@", view, reactTag);

From 36efbc341d8bda87a083251409456643a28cdd78 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Mon, 1 Feb 2016 12:41:04 -0800
Subject: [PATCH 0968/1411] Hot Loading Indicators

Summary:
public

Introduce a header bar similar to the one shown when loading the bundle to indicate that the packager server is processing an HMR update. Hook into HMR events to show this bar when appropriate.

Reviewed By: javache

Differential Revision: D2873521

fb-gh-sync-id: a77cbb2368b75b045aa8c6ababce2f731baf514b
---
 Libraries/Utilities/HMRClient.js         | 74 +++++++++++++++---------
 React/Modules/RCTDevLoadingView.m        | 42 ++++++++------
 local-cli/server/util/attachHMRServer.js |  5 +-
 3 files changed, 77 insertions(+), 44 deletions(-)

diff --git a/Libraries/Utilities/HMRClient.js b/Libraries/Utilities/HMRClient.js
index 79be2be45805..ed55ee6b912c 100644
--- a/Libraries/Utilities/HMRClient.js
+++ b/Libraries/Utilities/HMRClient.js
@@ -11,6 +11,7 @@
 'use strict';
 
 const invariant = require('invariant');
+const processColor = require('processColor');
 
 /**
  * HMR Client that receives from the server HMR updates and propagates them
@@ -49,39 +50,60 @@ Error: ${e.message}`
       );
     };
     activeWS.onmessage = ({data}) => {
+      const DevLoadingView = require('NativeModules').DevLoadingView;
       data = JSON.parse(data);
-      if (data.type === 'update') {
-        const modules = data.body.modules;
-        const sourceMappingURLs = data.body.sourceMappingURLs;
-        const sourceURLs = data.body.sourceURLs;
 
-        const RCTRedBox = require('NativeModules').RedBox;
-        RCTRedBox && RCTRedBox.dismiss && RCTRedBox.dismiss();
+      switch(data.type) {
+        case 'update-start': {
+          DevLoadingView.showMessage(
+            'Hot Loading...',
+            processColor('#000000'),
+            processColor('#aaaaaa'),
+          );
+          break;
+        }
+        case 'update': {
+          const modules = data.body.modules;
+          const sourceMappingURLs = data.body.sourceMappingURLs;
+          const sourceURLs = data.body.sourceURLs;
 
-        modules.forEach((code, i) => {
-          code = code + '\n\n' + sourceMappingURLs[i];
+          const RCTRedBox = require('NativeModules').RedBox;
+          RCTRedBox && RCTRedBox.dismiss && RCTRedBox.dismiss();
 
-          require('SourceMapsCache').fetch({
-            text: code,
-            url: sourceURLs[i],
-            sourceMappingURL: sourceMappingURLs[i],
-          });
+          modules.forEach((code, i) => {
+            code = code + '\n\n' + sourceMappingURLs[i];
 
-          // on JSC we need to inject from native for sourcemaps to work
-          // (Safari doesn't support `sourceMappingURL` nor any variant when
-          // evaluating code) but on Chrome we can simply use eval
-          const injectFunction = typeof __injectHMRUpdate === 'function'
-            ? __injectHMRUpdate
-            : eval;
+            require('SourceMapsCache').fetch({
+              text: code,
+              url: sourceURLs[i],
+              sourceMappingURL: sourceMappingURLs[i],
+            });
 
-          injectFunction(code, sourceURLs[i]);
-        })
-        return;
-      }
+            // on JSC we need to inject from native for sourcemaps to work
+            // (Safari doesn't support `sourceMappingURL` nor any variant when
+            // evaluating code) but on Chrome we can simply use eval
+            const injectFunction = typeof __injectHMRUpdate === 'function'
+              ? __injectHMRUpdate
+              : eval;
 
-      // TODO: add support for opening filename by clicking on the stacktrace
-      const error = data.body;
-      throw new Error(error.type + ' ' + error.description);
+            injectFunction(code, sourceURLs[i]);
+          });
+
+          DevLoadingView.hide();
+          break;
+        }
+        case 'update-done': {
+          DevLoadingView.hide();
+          break;
+        }
+        case 'error': {
+          DevLoadingView.hide();
+          throw new Error(data.body.type + ' ' + data.body.description);
+        }
+        default: {
+          throw new Error(`Unexpected message: ${data}`);
+        }
+      }
     };
   },
 };
diff --git a/React/Modules/RCTDevLoadingView.m b/React/Modules/RCTDevLoadingView.m
index b652f7ce937d..5c799791cf2a 100644
--- a/React/Modules/RCTDevLoadingView.m
+++ b/React/Modules/RCTDevLoadingView.m
@@ -55,14 +55,13 @@ - (void)setBridge:(RCTBridge *)bridge
   [self showWithURL:bridge.bundleURL];
 }
 
-- (void)showWithURL:(NSURL *)URL
+RCT_EXPORT_METHOD(showMessage:(NSString *)message color:(UIColor *)color backgroundColor:(UIColor *)backgroundColor)
 {
   if (!isEnabled) {
     return;
   }
 
   dispatch_async(dispatch_get_main_queue(), ^{
-
     _showDate = [NSDate date];
     if (!_window && !RCTRunningInTestEnvironment()) {
       CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
@@ -77,34 +76,23 @@ - (void)showWithURL:(NSURL *)URL
       [_window makeKeyAndVisible];
     }
 
-    NSString *source;
-    if (URL.fileURL) {
-      _window.backgroundColor = [UIColor blackColor];
-      _label.textColor = [UIColor grayColor];
-      source = @"pre-bundled file";
-    } else {
-      _window.backgroundColor = [UIColor colorWithHue:1./3 saturation:1 brightness:.35 alpha:1];
-      _label.textColor = [UIColor whiteColor];
-      source = [NSString stringWithFormat:@"%@:%@", URL.host, URL.port];
-    }
-
-    _label.text = [NSString stringWithFormat:@"Loading from %@...", source];
+    _label.text = message;
+    _label.textColor = color;
+    _window.backgroundColor = backgroundColor;
     _window.hidden = NO;
   });
 }
 
-- (void)hide
+RCT_EXPORT_METHOD(hide)
 {
   if (!isEnabled) {
     return;
   }
 
   dispatch_async(dispatch_get_main_queue(), ^{
-
     const NSTimeInterval MIN_PRESENTED_TIME = 0.6;
     NSTimeInterval presentedTime = [[NSDate date] timeIntervalSinceDate:_showDate];
     NSTimeInterval delay = MAX(0, MIN_PRESENTED_TIME - presentedTime);
-
     CGRect windowFrame = _window.frame;
     [UIView animateWithDuration:0.25
                           delay:delay
@@ -119,6 +107,26 @@ - (void)hide
   });
 }
 
+- (void)showWithURL:(NSURL *)URL
+{
+  UIColor *color;
+  UIColor *backgroundColor;
+  NSString *source;
+  if (URL.fileURL) {
+    color = [UIColor grayColor];
+    backgroundColor = [UIColor blackColor];
+    source = @"pre-bundled file";
+  } else {
+    color = [UIColor whiteColor];
+    backgroundColor = [UIColor colorWithHue:1./3 saturation:1 brightness:.35 alpha:1];
+    source = [NSString stringWithFormat:@"%@:%@", URL.host, URL.port];
+  }
+
+  [self showMessage:[NSString stringWithFormat:@"Loading from %@...", source]
+              color:color
+    backgroundColor:backgroundColor];
+}
+
 @end
 
 #else
diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js
index 9eb62b5516a0..3fc85e98c83f 100644
--- a/local-cli/server/util/attachHMRServer.js
+++ b/local-cli/server/util/attachHMRServer.js
@@ -112,6 +112,7 @@ function attachHMRServer({httpServer, path, packagerServer}) {
             return;
           }
 
+          client.ws.send(JSON.stringify({type: 'update-start'}));
           stat.then(() => {
             return packagerServer.getShallowDependencies(filename)
               .then(deps => {
@@ -240,7 +241,9 @@ function attachHMRServer({httpServer, path, packagerServer}) {
             () => {
               // do nothing, file was removed
             },
-          );
+          ).finally(() => {
+            client.ws.send(JSON.stringify({type: 'update-done'}));
+          });
         });
 
         client.ws.on('error', e => {

From 1491668b350d6268f5167a05f774f8ca1d93bfbd Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeux@fb.com>
Date: Mon, 1 Feb 2016 12:46:50 -0800
Subject: [PATCH 0969/1411] ColorPropTypes support for isRequired and more
 precise description

Summary:
The previous implementation of ColorPropType was very hacky as it used `ReactPropTypes.oneOfType([colorValidator, ReactPropTypes.number])`. It turns out that oneOfType also accepts arbitrary functions instead of a type, but doesn't display any of the error message.

In this diff I properly implement isRequired (sadly we don't export `createChainableTypeChecker` in ReactPropTypes) and provide a lot more context that we have. I copy and pasted the way we displayed this context from the existing checkers.

**Test Plan**

When doing .isRequired and do not provide the value:

![simulator screen shot feb 1 2016 9 56 00 am](https://cloud.githubusercontent.com/assets/197597/12726239/61243f88-c8cb-11e5-889b-6594ffd85973.png)

When providing a bad value:

![simulator screen shot feb 1 2016 10 01 25 am](https://cloud.githubusercontent.com/assets/197597/12726244/6e80aa36-c8cb-11e5-9bd3-a8637de75496.png)
Closes https://github.com/facebook/react-native/pull/5671

Reviewed By: svcscm

Differential Revision: D2886760

Pulled By: vjeux

fb-gh-sync-id: d6be42b5768fca5463fe80fe4b144506d21b0832
---
 Libraries/StyleSheet/ColorPropType.js | 21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/Libraries/StyleSheet/ColorPropType.js b/Libraries/StyleSheet/ColorPropType.js
index 564ab92e0844..9e956e4c4e7b 100644
--- a/Libraries/StyleSheet/ColorPropType.js
+++ b/Libraries/StyleSheet/ColorPropType.js
@@ -11,12 +11,20 @@
 'use strict';
 
 var ReactPropTypes = require('ReactPropTypes');
+var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames');
 
 var normalizeColor = require('normalizeColor');
 
-var ColorPropType = function(props, propName) {
+var colorPropType = function(isRequired, props, propName, componentName, location, propFullName) {
   var color = props[propName];
   if (color === undefined || color === null) {
+    if (isRequired) {
+      var locationName = ReactPropTypeLocationNames[location];
+      return new Error(
+        'Required ' + locationName + ' `' + (propFullName || propName) +
+        '` was not specified in `' + componentName + '`.'
+      );
+    }
     return;
   }
 
@@ -28,8 +36,11 @@ var ColorPropType = function(props, propName) {
   }
 
   if (normalizeColor(color) === null) {
+    var locationName = ReactPropTypeLocationNames[location];
     return new Error(
-`Invalid color supplied to ${propName}: ${color}. Valid color formats are
+      'Invalid ' + locationName + ' `' + (propFullName || propName) +
+      '` supplied to `' + componentName + '`: ' + color + '\n' +
+`Valid color formats are
   - #f0f (#rgb)
   - #f0fc (#rgba)
   - #ff00ff (#rrggbb)
@@ -39,8 +50,12 @@ var ColorPropType = function(props, propName) {
   - hsl(360, 100%, 100%)
   - hsla(360, 100%, 100%, 1.0)
   - transparent
-  - red`);
+  - red
+`);
   }
 };
 
+var ColorPropType = colorPropType.bind(null, false /* isRequired */);
+ColorPropType.isRequired = colorPropType.bind(null, true /* isRequired */);
+
 module.exports = ColorPropType;

From dd759aa78d69674750f54de99eb77504ccbf6fce Mon Sep 17 00:00:00 2001
From: Ilana Sufrin <pair+ilana.sufrin@refinery29.com>
Date: Mon, 1 Feb 2016 15:55:56 -0500
Subject: [PATCH 0970/1411] adds thisam to showcase

---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 71eca1e46ef3..eaa4b6eadaaf 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -477,6 +477,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/thai-tone/id1064086189?mt=8',
     author: 'Alexey Ledak',
   },
+  {
+    name: 'This AM',
+    icon: 'http://s3.r29static.com//bin/public/efe/x/1542038/image.png',
+    link: 'https://itunes.apple.com/us/app/refinery29-this-am-top-breaking/id988472315?mt=8',
+    author: 'Refinery29',
+  },
   {
     name: 'Tong Xing Wang',
     icon: 'http://a3.mzstatic.com/us/r30/Purple1/v4/7d/52/a7/7d52a71f-9532-82a5-b92f-87076624fdb2/icon175x175.jpeg',

From 6ecfb611474e89e1193aabb8aa08b3a19a8c20ef Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Mon, 1 Feb 2016 13:23:05 -0800
Subject: [PATCH 0971/1411] fixes gradle dependencies for compile and test

Summary: Closes https://github.com/facebook/react-native/pull/5676

Reviewed By: svcscm

Differential Revision: D2886944

Pulled By: androidtrunkagent

fb-gh-sync-id: 9cb68883cd38c31e588222bc746b5e296962c845
---
 ReactAndroid/build.gradle | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle
index 93768246fe07..913dcbb73347 100644
--- a/ReactAndroid/build.gradle
+++ b/ReactAndroid/build.gradle
@@ -252,8 +252,7 @@ dependencies {
     compile 'com.facebook.fresco:imagepipeline-okhttp:0.8.1'
     compile 'com.facebook.stetho:stetho:1.2.0'
     compile 'com.facebook.stetho:stetho-okhttp:1.2.0'
-    compile 'com.fasterxml.jackson.core:jackson-annotations:2.2.3'
-    compile 'com.fasterxml.jackson.core:jackson-databind:2.2.3'
+    compile 'com.fasterxml.jackson.core:jackson-core:2.2.3'
     compile 'com.google.code.findbugs:jsr305:3.0.0'
     compile 'com.squareup.okhttp:okhttp:2.5.0'
     compile 'com.squareup.okhttp:okhttp-ws:2.5.0'
@@ -262,6 +261,7 @@ dependencies {
 
     testCompile "junit:junit:${JUNIT_VERSION}"
     testCompile "org.powermock:powermock-api-mockito:${POWERMOCK_VERSION}"
+    testCompile 'com.fasterxml.jackson.core:jackson-databind:2.2.3'
     testCompile "org.powermock:powermock-module-junit4-rule:${POWERMOCK_VERSION}"
     testCompile "org.powermock:powermock-classloading-xstream:${POWERMOCK_VERSION}"
     testCompile "org.mockito:mockito-core:${MOCKITO_CORE_VERSION}"

From debcac59d06d527c3a6a07ef9561fe4041022ff4 Mon Sep 17 00:00:00 2001
From: Jelle van den Hooff <jelle@samsara.com>
Date: Mon, 1 Feb 2016 14:18:26 -0800
Subject: [PATCH 0972/1411] iOS websocket: include cookies with request

Summary:
This PR modifies the Websocket implementation on iOS to pass cookies to the server. Sending cookies is useful for clients that wish to access protected Websocket endpoints without creating a new authentication protocol.
Closes https://github.com/facebook/react-native/pull/5630

Reviewed By: svcscm

Differential Revision: D2881815

Pulled By: martinbigio

fb-gh-sync-id: 31c1640626cd15447bdb4f2058ae4e34dfa52f88
---
 Libraries/WebSocket/RCTSRWebSocket.m | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/Libraries/WebSocket/RCTSRWebSocket.m b/Libraries/WebSocket/RCTSRWebSocket.m
index 3d8782c87121..bf67c3b14e37 100644
--- a/Libraries/WebSocket/RCTSRWebSocket.m
+++ b/Libraries/WebSocket/RCTSRWebSocket.m
@@ -280,7 +280,23 @@ - (instancetype)initWithURL:(NSURL *)URL protocols:(NSArray<NSString *> *)protoc
 
 - (instancetype)initWithURL:(NSURL *)URL protocols:(NSArray<NSString *> *)protocols options:(NSDictionary<NSString *, id> *)options
 {
-  NSURLRequest *request = URL ? [NSURLRequest requestWithURL:URL] : nil;
+  NSMutableURLRequest *request;
+  if (URL) {
+    // Build a mutable request so we can fill the cookie header.
+    request = [NSMutableURLRequest requestWithURL:URL];
+
+    // We load cookies from sharedHTTPCookieStorage (shared with XHR and
+    // fetch). To get HTTPS-only cookies for wss URLs, replace wss with https
+    // in the URL.
+    NSURLComponents *components = [NSURLComponents componentsWithURL:URL resolvingAgainstBaseURL:true];
+    if ([components.scheme isEqualToString:@"wss"]) {
+      components.scheme = @"https";
+    }
+
+    // Load and set the cookie header.
+    NSArray<NSHTTPCookie *> *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:components.URL];
+    [request setAllHTTPHeaderFields:[NSHTTPCookie requestHeaderFieldsWithCookies:cookies]];
+  }
   return [self initWithURLRequest:request protocols:protocols options:options];
 }
 

From 9506e5afc7844a45d3029c209ae5809c5f4c5e44 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= <renaudeau.gaetan@gmail.com>
Date: Mon, 1 Feb 2016 14:52:33 -0800
Subject: [PATCH 0973/1411] add animated param in ListView#scrollTo

Summary:
Since scrollTo(x,y,**animated**) params has been introduced, it was not backported to ListView scrollTo method.
Closes https://github.com/facebook/react-native/pull/5661

Reviewed By: svcscm

Differential Revision: D2886049

Pulled By: nicklockwood

fb-gh-sync-id: 016e92beadc7f397be77b8c58dc572119f873556
---
 Libraries/CustomComponents/ListView/ListView.js | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js
index fb1210304467..e395ee8175d9 100644
--- a/Libraries/CustomComponents/ListView/ListView.js
+++ b/Libraries/CustomComponents/ListView/ListView.js
@@ -236,8 +236,8 @@ var ListView = React.createClass({
       this.refs[SCROLLVIEW_REF].getScrollResponder();
   },
 
-  scrollTo: function(destY, destX) {
-    this.getScrollResponder().scrollResponderScrollTo(destX || 0, destY || 0);
+  scrollTo: function(destY, destX, animated = true) {
+    this.getScrollResponder().scrollResponderScrollTo(destX || 0, destY || 0, animated);
   },
 
   setNativeProps: function(props) {
@@ -472,7 +472,7 @@ var ListView = React.createClass({
       this.scrollProperties.visibleLength = visibleLength;
       this._updateVisibleRows();
       this._renderMoreRowsIfNeeded();
-    } 
+    }
     this.props.onLayout && this.props.onLayout(event);
   },
 
@@ -495,7 +495,7 @@ var ListView = React.createClass({
       this._maybeCallOnEndReached();
       return;
     }
- 
+
     var distanceFromEnd = this._getDistanceFromEnd(this.scrollProperties);
     if (distanceFromEnd < this.props.scrollRenderAheadDistance) {
       this._pageInNewRows();

From 700b848826e7ec5fb836b1e69e872ee52b0913c1 Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Mon, 1 Feb 2016 16:59:28 -0800
Subject: [PATCH 0974/1411] Expose fastfs on the DepencenyGraph instance.

Summary:
The FS as seen by an instance of a dependency graph is useful for clients of node-haste. This provides an accessor to fastfs so that the partial view of the filesystem can be queried. I was thinking of splitting out the fastfs creation to outside the constructor but the necessary refactoring doesn't seem worth it. The fastfs is intrinsically tied to the dependency graph and the `DependencyGraph` instance is meant to be a base-class for clients anyway. Both in react-packager and jest we are wrapping it with higher-level client specific containers, Resolver and HasteResolver respectively.

public

Reviewed By: davidaurelio

Differential Revision: D2885217

fb-gh-sync-id: 47a408b2682516bee9d6a4e6c61b9063817aaf22
---
 .../src/DependencyResolver/DependencyGraph/index.js           | 4 ++--
 packager/react-packager/src/Resolver/index.js                 | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
index 6fda8d93b75b..ed09f91adaab 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
@@ -147,8 +147,8 @@ class DependencyGraph {
     return this._moduleCache.getModule(entryPath).getDependencies();
   }
 
-  stat(filePath) {
-    return this._fastfs.stat(filePath);
+  getFS() {
+    return this._fastfs;
   }
 
   /**
diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index 4f3444ecd515..1822eb9943ff 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -110,7 +110,7 @@ class Resolver {
   }
 
   stat(filePath) {
-    return this._depGraph.stat(filePath);
+    return this._depGraph.getFS().stat(filePath);
   }
 
   getModuleForPath(entryFile) {

From 5ec1d354c2ebbe0b168c84dd0486459266e29708 Mon Sep 17 00:00:00 2001
From: "glevi@fb.com" <glevi@fb.com>
Date: Mon, 1 Feb 2016 17:13:08 -0800
Subject: [PATCH 0975/1411] Deploy v0.21.0

Reviewed By: jeffmo

Differential Revision: D2888689

fb-gh-sync-id: fe94e50c7872b9a1344a054acccab365d385f6ed
---
 .flowconfig                                         | 6 +++---
 Examples/UIExplorer/ExampleTypes.js                 | 1 -
 Libraries/Animated/src/AnimatedImplementation.js    | 6 +++---
 Libraries/Components/Navigation/NavigatorIOS.ios.js | 4 ++--
 4 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/.flowconfig b/.flowconfig
index 53bfd25208fb..fd4925d5b1b8 100644
--- a/.flowconfig
+++ b/.flowconfig
@@ -57,9 +57,9 @@ suppress_type=$FlowIssue
 suppress_type=$FlowFixMe
 suppress_type=$FixMe
 
-suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-0]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
-suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-0]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
+suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-1]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
+suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-1]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
 suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
 
 [version]
-0.20.1
+0.21.0
diff --git a/Examples/UIExplorer/ExampleTypes.js b/Examples/UIExplorer/ExampleTypes.js
index 4513f19e228b..ac9deaadfaf7 100644
--- a/Examples/UIExplorer/ExampleTypes.js
+++ b/Examples/UIExplorer/ExampleTypes.js
@@ -18,7 +18,6 @@
 
 export type Example = {
   title: string,
-  /* $FlowFixMe(>=0.16.0) */
   render: () => ?ReactElement<any, any, any>,
   description?: string,
   platform?: string;
diff --git a/Libraries/Animated/src/AnimatedImplementation.js b/Libraries/Animated/src/AnimatedImplementation.js
index 87602fc778f3..3d70feef8b38 100644
--- a/Libraries/Animated/src/AnimatedImplementation.js
+++ b/Libraries/Animated/src/AnimatedImplementation.js
@@ -165,9 +165,9 @@ class TimingAnimation extends Animation {
   ) {
     super();
     this._toValue = config.toValue;
-    this._easing = config.easing || easeInOut;
+    this._easing = config.easing !== undefined ? config.easing : easeInOut;
     this._duration = config.duration !== undefined ? config.duration : 500;
-    this._delay = config.delay || 0;
+    this._delay = config.delay !== undefined ? config.delay : 0;
     this.__isInteraction = config.isInteraction !== undefined ? config.isInteraction : true;
   }
 
@@ -252,7 +252,7 @@ class DecayAnimation extends Animation {
     config: DecayAnimationConfigSingle,
   ) {
     super();
-    this._deceleration = config.deceleration || 0.998;
+    this._deceleration = config.deceleration !== undefined ? config.deceleration : 0.998;
     this._velocity = config.velocity;
     this.__isInteraction = config.isInteraction !== undefined ? config.isInteraction : true;
   }
diff --git a/Libraries/Components/Navigation/NavigatorIOS.ios.js b/Libraries/Components/Navigation/NavigatorIOS.ios.js
index 6635a25bb8a9..ea5b395a3cf1 100644
--- a/Libraries/Components/Navigation/NavigatorIOS.ios.js
+++ b/Libraries/Components/Navigation/NavigatorIOS.ios.js
@@ -635,8 +635,8 @@ var NavigatorIOS = React.createClass({
     this._handleNavigatorStackChanged(e);
   },
 
-  _routeToStackItem: function(route: Route, i: number) {
-    var {component, wrapperStyle, passProps, ...route} = route;
+  _routeToStackItem: function(routeArg: Route, i: number) {
+    var {component, wrapperStyle, passProps, ...route} = routeArg;
     var {itemWrapperStyle, ...props} = this.props;
     var shouldUpdateChild =
       this.state.updatingAllIndicesAtOrBeyond != null &&

From 46106f756ad230ed381ecaf06e6fcd87c318b148 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Mon, 1 Feb 2016 18:00:18 -0800
Subject: [PATCH 0976/1411] Ported `source` prop over to iOS WebView

Summary:
public
https://github.com/facebook/react-native/pull/5494 added a new `source` property to WebView on Android that provides a better API, as well as allowing for request headers to be set.

This diff ports that functionality over to iOS, so we can have a consistent API cross-platform.

I've also extended the API to include `method` (GET or POST) and `body` when setting the WebView content with a URI, and `baseUrl` when setting static HTML.

Reviewed By: javache

Differential Revision: D2884643

fb-gh-sync-id: 83f24494bdbb4e1408aa8f3b7428fee33888ae3a
---
 Examples/UIExplorer/WebViewExample.js         | 29 +++++++-
 .../Components/WebView/WebView.android.js     | 46 +++++++++++--
 Libraries/Components/WebView/WebView.ios.js   | 67 +++++++++++++++++--
 React/Base/RCTConvert.m                       | 27 +++++++-
 React/Views/RCTWebView.h                      |  2 +-
 React/Views/RCTWebView.m                      | 48 +++++++------
 React/Views/RCTWebViewManager.m               |  3 +-
 .../views/webview/ReactWebViewManager.java    | 47 ++++++++++---
 8 files changed, 220 insertions(+), 49 deletions(-)

diff --git a/Examples/UIExplorer/WebViewExample.js b/Examples/UIExplorer/WebViewExample.js
index e760ebdf5b62..817b16e3f2c4 100644
--- a/Examples/UIExplorer/WebViewExample.js
+++ b/Examples/UIExplorer/WebViewExample.js
@@ -49,7 +49,11 @@ var WebViewExample = React.createClass({
   inputText: '',
 
   handleTextInputChange: function(event) {
-    this.inputText = event.nativeEvent.text;
+    var url = event.nativeEvent.text;
+    if (!/^[a-zA-Z-_]:/.test(url)) {
+      url = 'http://' + url;
+    }
+    this.inputText = url;
   },
 
   render: function() {
@@ -93,7 +97,7 @@ var WebViewExample = React.createClass({
           ref={WEBVIEW_REF}
           automaticallyAdjustContentInsets={false}
           style={styles.webView}
-          url={this.state.url}
+          source={{uri: this.state.url}}
           javaScriptEnabled={true}
           domStorageEnabled={true}
           decelerationRate="normal"
@@ -232,7 +236,26 @@ exports.title = '<WebView>';
 exports.description = 'Base component to display web content';
 exports.examples = [
   {
-    title: 'WebView',
+    title: 'Simple Browser',
     render(): ReactElement { return <WebViewExample />; }
+  },
+  {
+    title: 'POST Test',
+    render(): ReactElement {
+      return (
+        <WebView
+          style={{
+            backgroundColor: BGWASH,
+            height: 100,
+          }}
+          source={{
+            uri: 'http://www.posttestserver.com/post.php',
+            method: 'POST',
+            body: 'foo=bar&bar=foo'
+          }}
+          scalesPageToFit={false}
+        />
+      );
+    }
   }
 ];
diff --git a/Libraries/Components/WebView/WebView.android.js b/Libraries/Components/WebView/WebView.android.js
index 1f6fdd98044d..23dc5f02fb43 100644
--- a/Libraries/Components/WebView/WebView.android.js
+++ b/Libraries/Components/WebView/WebView.android.js
@@ -62,11 +62,43 @@ var WebView = React.createClass({
     ),
 
     /**
-     * Used on Android only, provides html or url with optional headers to the WebView.
-     * `{ html: string, uri: string, headers: map<string, string> }`
-     * @platform android
+     * Loads static html or a uri (with optional headers) in the WebView.
      */
-    source: PropTypes.object,
+    source: PropTypes.oneOfType([
+      PropTypes.shape({
+        /*
+         * The URI to load in the WebView. Can be a local or remote file.
+         */
+        uri: PropTypes.string,
+        /*
+         * The HTTP Method to use. Defaults to GET if not specified.
+         * NOTE: On Android, only GET and POST are supported.
+         */
+        method: PropTypes.oneOf(['GET', 'POST']),
+        /*
+         * Additional HTTP headers to send with the request.
+         * NOTE: On Android, this can only be used with GET requests.
+         */
+        headers: PropTypes.object,
+        /*
+         * The HTTP body to send with the request. This must be a valid
+         * UTF-8 string, and will be sent exactly as specified, with no
+         * additional encoding (e.g. URL-escaping or base64) applied.
+         * NOTE: On Android, this can only be used with POST requests.
+         */
+        body: PropTypes.string,
+      }),
+      PropTypes.shape({
+        /*
+         * A static HTML page to display in the WebView.
+         */
+        html: PropTypes.string,
+        /*
+         * The base URL to be used for any relative links in the HTML.
+         */
+        baseUrl: PropTypes.string,
+      }),
+    ]),
 
     /**
      * Used on Android only, JS is enabled by default for WebView on iOS
@@ -149,6 +181,12 @@ var WebView = React.createClass({
     } else if (this.props.url) {
       source.uri = this.props.url;
     }
+    
+    if (source.method === 'POST' && source.headers) {
+      console.warn('WebView: `source.headers` is not supported when using POST.');
+    } else if (source.method === 'GET' && source.body) {
+      console.warn('WebView: `source.body` is not supported when using GET.');
+    }
 
     var webView =
       <RCTWebView
diff --git a/Libraries/Components/WebView/WebView.ios.js b/Libraries/Components/WebView/WebView.ios.js
index 1b561d225d9b..6ea171331b9a 100644
--- a/Libraries/Components/WebView/WebView.ios.js
+++ b/Libraries/Components/WebView/WebView.ios.js
@@ -7,7 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule WebView
- * @flow
+ * @noflow
  */
 'use strict';
 
@@ -20,9 +20,10 @@ var UIManager = require('UIManager');
 var View = require('View');
 var ScrollView = require('ScrollView')
 
-var processDecelerationRate = require('processDecelerationRate');
+var deprecatedPropType = require('deprecatedPropType');
 var invariant = require('invariant');
 var keyMirror = require('keyMirror');
+var processDecelerationRate = require('processDecelerationRate');
 var requireNativeComponent = require('requireNativeComponent');
 
 var PropTypes = React.PropTypes;
@@ -89,8 +90,56 @@ var WebView = React.createClass({
 
   propTypes: {
     ...View.propTypes,
-    url: PropTypes.string,
-    html: PropTypes.string,
+
+    html: deprecatedPropType(
+      PropTypes.string,
+      'Use the `source` prop instead.'
+    ),
+
+    url: deprecatedPropType(
+      PropTypes.string,
+      'Use the `source` prop instead.'
+    ),
+
+    /**
+     * Loads static html or a uri (with optional headers) in the WebView.
+     */
+    source: PropTypes.oneOfType([
+      PropTypes.shape({
+        /*
+         * The URI to load in the WebView. Can be a local or remote file.
+         */
+        uri: PropTypes.string,
+        /*
+         * The HTTP Method to use. Defaults to GET if not specified.
+         * NOTE: On Android, only GET and POST are supported.
+         */
+        method: PropTypes.string,
+        /*
+         * Additional HTTP headers to send with the request.
+         * NOTE: On Android, this can only be used with GET requests.
+         */
+        headers: PropTypes.object,
+        /*
+         * The HTTP body to send with the request. This must be a valid
+         * UTF-8 string, and will be sent exactly as specified, with no
+         * additional encoding (e.g. URL-escaping or base64) applied.
+         * NOTE: On Android, this can only be used with POST requests.
+         */
+        body: PropTypes.string,
+      }),
+      PropTypes.shape({
+        /*
+         * A static HTML page to display in the WebView.
+         */
+        html: PropTypes.string,
+        /*
+         * The base URL to be used for any relative links in the HTML.
+         */
+        baseUrl: PropTypes.string,
+      }),
+    ]),
+
     /**
      * Function that returns a view to show if there's an error.
      */
@@ -243,13 +292,19 @@ var WebView = React.createClass({
 
     var decelerationRate = processDecelerationRate(this.props.decelerationRate);
 
+    var source = this.props.source || {};
+    if (this.props.html) {
+      source.html = this.props.html;
+    } else if (this.props.url) {
+      source.uri = this.props.url;
+    }
+
     var webView =
       <RCTWebView
         ref={RCT_WEBVIEW_REF}
         key="webViewKey"
         style={webViewStyles}
-        url={this.props.url}
-        html={this.props.html}
+        source={source}
         injectedJavaScript={this.props.injectedJavaScript}
         bounces={this.props.bounces}
         scrollEnabled={this.props.scrollEnabled}
diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m
index fdd8ccc43237..ebdbee02a584 100644
--- a/React/Base/RCTConvert.m
+++ b/React/Base/RCTConvert.m
@@ -118,8 +118,31 @@ + (NSURL *)NSURL:(id)json
 
 + (NSURLRequest *)NSURLRequest:(id)json
 {
-  NSURL *URL = [self NSURL:json];
-  return URL ? [NSURLRequest requestWithURL:URL] : nil;
+  if ([json isKindOfClass:[NSString class]]) {
+    NSURL *URL = [self NSURL:json];
+    return URL ? [NSURLRequest requestWithURL:URL] : nil;
+  }
+  if ([json isKindOfClass:[NSDictionary class]]) {
+    NSURL *URL = [self NSURL:json[@"uri"] ?: json[@"url"]];
+    if (!URL) {
+      return nil;
+    }
+    NSData *body = [self NSData:json[@"body"]];
+    NSString *method = [self NSString:json[@"method"]].uppercaseString ?: @"GET";
+    NSDictionary *headers = [self NSDictionary:json[@"headers"]];
+    if ([method isEqualToString:@"GET"] && headers == nil && body == nil) {
+      return [NSURLRequest requestWithURL:URL];
+    }
+    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
+    request.HTTPBody = body;
+    request.HTTPMethod = method;
+    request.allHTTPHeaderFields = headers;
+    return [request copy];
+  }
+  if (json) {
+    RCTLogConvertError(json, @"a valid URLRequest");
+  }
+  return nil;
 }
 
 + (RCTFileURL *)RCTFileURL:(id)json
diff --git a/React/Views/RCTWebView.h b/React/Views/RCTWebView.h
index d806cd987507..386ce8990cef 100644
--- a/React/Views/RCTWebView.h
+++ b/React/Views/RCTWebView.h
@@ -31,7 +31,7 @@ shouldStartLoadForRequest:(NSMutableDictionary<NSString *, id> *)request
 
 @property (nonatomic, weak) id<RCTWebViewDelegate> delegate;
 
-@property (nonatomic, strong) NSURL *URL;
+@property (nonatomic, copy) NSDictionary *source;
 @property (nonatomic, assign) UIEdgeInsets contentInset;
 @property (nonatomic, assign) BOOL automaticallyAdjustContentInsets;
 @property (nonatomic, copy) NSString *injectedJavaScript;
diff --git a/React/Views/RCTWebView.m b/React/Views/RCTWebView.m
index 1b1ef646a36e..cddd9ede1784 100644
--- a/React/Views/RCTWebView.m
+++ b/React/Views/RCTWebView.m
@@ -12,6 +12,7 @@
 #import <UIKit/UIKit.h>
 
 #import "RCTAutoInsetsProtocol.h"
+#import "RCTConvert.h"
 #import "RCTEventDispatcher.h"
 #import "RCTLog.h"
 #import "RCTUtils.h"
@@ -70,31 +71,34 @@ - (void)reload
   [_webView reload];
 }
 
-- (NSURL *)URL
+- (void)setSource:(NSDictionary *)source
 {
-  return _webView.request.URL;
-}
+  if (![_source isEqualToDictionary:source]) {
+    _source = [source copy];
 
-- (void)setURL:(NSURL *)URL
-{
-  // Because of the way React works, as pages redirect, we actually end up
-  // passing the redirect urls back here, so we ignore them if trying to load
-  // the same url. We'll expose a call to 'reload' to allow a user to load
-  // the existing page.
-  if ([URL isEqual:_webView.request.URL]) {
-    return;
-  }
-  if (!URL) {
-    // Clear the webview
-    [_webView loadHTMLString:@"" baseURL:nil];
-    return;
-  }
-  [_webView loadRequest:[NSURLRequest requestWithURL:URL]];
-}
+    // Check for a static html source first
+    NSString *html = [RCTConvert NSString:source[@"html"]];
+    if (html) {
+      NSURL *baseURL = [RCTConvert NSURL:source[@"baseUrl"]];
+      [_webView loadHTMLString:html baseURL:baseURL];
+      return;
+    }
 
-- (void)setHTML:(NSString *)HTML
-{
-  [_webView loadHTMLString:HTML baseURL:nil];
+    NSURLRequest *request = [RCTConvert NSURLRequest:source];
+    // Because of the way React works, as pages redirect, we actually end up
+    // passing the redirect urls back here, so we ignore them if trying to load
+    // the same url. We'll expose a call to 'reload' to allow a user to load
+    // the existing page.
+    if ([request.URL isEqual:_webView.request.URL]) {
+      return;
+    }
+    if (!request.URL) {
+      // Clear the webview
+      [_webView loadHTMLString:@"" baseURL:nil];
+      return;
+    }
+    [_webView loadRequest:request];
+  }
 }
 
 - (void)layoutSubviews
diff --git a/React/Views/RCTWebViewManager.m b/React/Views/RCTWebViewManager.m
index 5e5aff190738..33a5d77937fb 100644
--- a/React/Views/RCTWebViewManager.m
+++ b/React/Views/RCTWebViewManager.m
@@ -33,8 +33,7 @@ - (UIView *)view
   return webView;
 }
 
-RCT_REMAP_VIEW_PROPERTY(url, URL, NSURL)
-RCT_REMAP_VIEW_PROPERTY(html, HTML, NSString)
+RCT_EXPORT_VIEW_PROPERTY(source, NSDictionary)
 RCT_REMAP_VIEW_PROPERTY(bounces, _webView.scrollView.bounces, BOOL)
 RCT_REMAP_VIEW_PROPERTY(scrollEnabled, _webView.scrollView.scrollEnabled, BOOL)
 RCT_REMAP_VIEW_PROPERTY(scalesPageToFit, _webView.scalesPageToFit, BOOL)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
index 41ab1b4149b1..aac2460c5929 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
@@ -35,6 +35,8 @@
 import com.facebook.react.uimanager.events.Event;
 import com.facebook.react.uimanager.events.EventDispatcher;
 
+import java.io.UnsupportedEncodingException;
+
 import java.util.HashMap;
 import java.util.Map;
 
@@ -68,6 +70,8 @@ public class ReactWebViewManager extends SimpleViewManager<WebView> {
   private static final String HTML_ENCODING = "UTF-8";
   private static final String HTML_MIME_TYPE = "text/html; charset=utf-8";
 
+  private static final String HTTP_METHOD_POST = "POST";
+
   public static final int COMMAND_GO_BACK = 1;
   public static final int COMMAND_GO_FORWARD = 2;
   public static final int COMMAND_RELOAD = 3;
@@ -135,9 +139,9 @@ public void doUpdateVisitedHistory(WebView webView, String url, boolean isReload
       dispatchEvent(
           webView,
           new TopLoadingStartEvent(
-            webView.getId(),
-            SystemClock.uptimeMillis(),
-            createWebViewEvent(webView, url)));
+              webView.getId(),
+              SystemClock.uptimeMillis(),
+              createWebViewEvent(webView, url)));
     }
 
     private void emitFinishEvent(WebView webView, String url) {
@@ -208,10 +212,9 @@ public void setInjectedJavaScript(@Nullable String js) {
     }
 
     public void callInjectedJavaScript() {
-      if (
-          getSettings().getJavaScriptEnabled() &&
-              injectedJS != null &&
-              !TextUtils.isEmpty(injectedJS)) {
+      if (getSettings().getJavaScriptEnabled() &&
+          injectedJS != null &&
+          !TextUtils.isEmpty(injectedJS)) {
         loadUrl("javascript:(function() {\n" + injectedJS + ";\n})();");
       }
     }
@@ -278,10 +281,36 @@ public void setInjectedJavaScript(WebView view, @Nullable String injectedJavaScr
   public void setSource(WebView view, @Nullable ReadableMap source) {
     if (source != null) {
       if (source.hasKey("html")) {
-        view.loadData(source.getString("html"), HTML_MIME_TYPE, HTML_ENCODING);
+        String html = source.getString("html");
+        if (source.hasKey("baseUrl")) {
+          view.loadDataWithBaseURL(
+              source.getString("baseUrl"), html, HTML_MIME_TYPE, HTML_ENCODING, null);
+        } else {
+          view.loadData(html, HTML_MIME_TYPE, HTML_ENCODING);
+        }
         return;
       }
       if (source.hasKey("uri")) {
+        String url = source.getString("uri");
+        if (source.hasKey("method")) {
+          String method = source.getString("method");
+          if (method.equals(HTTP_METHOD_POST)) {
+            byte[] postData = null;
+            if (source.hasKey("body")) {
+              String body = source.getString("body");
+              try {
+                postData = body.getBytes("UTF-8");
+              } catch (UnsupportedEncodingException e) {
+                postData = body.getBytes();
+              }
+            }
+            if (postData == null) {
+              postData = new byte[0];
+            }
+            view.postUrl(url, postData);
+            return;
+          }
+        }
         HashMap<String, String> headerMap = new HashMap<>();
         if (source.hasKey("headers")) {
           ReadableMap headers = source.getMap("headers");
@@ -291,7 +320,7 @@ public void setSource(WebView view, @Nullable ReadableMap source) {
             headerMap.put(key, headers.getString(key));
           }
         }
-        view.loadUrl(source.getString("uri"), headerMap);
+        view.loadUrl(url, headerMap);
         return;
       }
     }

From db275dd49f2031a6d5d3db36fafb386645349b5e Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Mon, 1 Feb 2016 18:26:30 -0800
Subject: [PATCH 0977/1411] Updates from GitHub

Summary:
This syncs a couple of changes from GitHub that are necessary for jest:

* Expose `set` on Cache
* Add a function to `getAllModules` from the graph
* Explicitly dontMock `graceful-fs` in the fastfs test. node-haste2 has this manual mock which is still used in automocked tests (ugh!).

public

Reviewed By: davidaurelio

Differential Revision: D2885112

fb-gh-sync-id: b2060d5474ebee5aa13e6ba2bdf5879b46f3fd5f
---
 packager/react-packager/src/DependencyResolver/Cache/index.js | 4 ++--
 .../src/DependencyResolver/DependencyGraph/index.js           | 4 ++++
 packager/react-packager/src/DependencyResolver/ModuleCache.js | 4 ++++
 .../DependencyResolver/__tests__/fastfs-integrated-test.js    | 3 ++-
 4 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/Cache/index.js b/packager/react-packager/src/DependencyResolver/Cache/index.js
index 06d346d6254e..4e1698cb3fda 100644
--- a/packager/react-packager/src/DependencyResolver/Cache/index.js
+++ b/packager/react-packager/src/DependencyResolver/Cache/index.js
@@ -53,7 +53,7 @@ class Cache {
 
     var recordP = this.has(filepath, field)
       ? this._data[filepath].data[field]
-      : this._set(filepath, field, loaderCb(filepath));
+      : this.set(filepath, field, loaderCb(filepath));
 
     return recordP.then(record => record);
   }
@@ -77,7 +77,7 @@ class Cache {
       (field == null || Object.prototype.hasOwnProperty.call(this._data[filepath].data, field));
   }
 
-  _set(filepath, field, loaderPromise) {
+  set(filepath, field, loaderPromise) {
     let record = this._data[filepath];
     if (!record) {
       record = Object.create(null);
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
index ed09f91adaab..bc5d85d7864d 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
@@ -158,6 +158,10 @@ class DependencyGraph {
     return this._moduleCache.getModule(entryFile);
   }
 
+  getAllModules() {
+    return this.load().then(() => this._moduleCache.getAllModules());
+  }
+
   getDependencies(entryPath, platform, recursive = true) {
     return this.load().then(() => {
       platform = this._getRequestPlatform(entryPath, platform);
diff --git a/packager/react-packager/src/DependencyResolver/ModuleCache.js b/packager/react-packager/src/DependencyResolver/ModuleCache.js
index fac1820b817e..3fcfb173ad97 100644
--- a/packager/react-packager/src/DependencyResolver/ModuleCache.js
+++ b/packager/react-packager/src/DependencyResolver/ModuleCache.js
@@ -41,6 +41,10 @@ class ModuleCache {
     return this._moduleCache[filePath];
   }
 
+  getAllModules() {
+    return this._moduleCache;
+  }
+
   getAssetModule(filePath) {
     filePath = path.resolve(filePath);
     if (!this._moduleCache[filePath]) {
diff --git a/packager/react-packager/src/DependencyResolver/__tests__/fastfs-integrated-test.js b/packager/react-packager/src/DependencyResolver/__tests__/fastfs-integrated-test.js
index f7fb3558820c..cbff314af1a0 100644
--- a/packager/react-packager/src/DependencyResolver/__tests__/fastfs-integrated-test.js
+++ b/packager/react-packager/src/DependencyResolver/__tests__/fastfs-integrated-test.js
@@ -8,7 +8,8 @@
  */
 'use strict';
 
-jest.autoMockOff();
+jest.autoMockOff()
+  .dontMock('graceful-fs');
 
 const Fastfs = require('../fastfs');
 

From 361f3f30d3ae2b48429a1738d309a2693c4a1038 Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Mon, 1 Feb 2016 19:08:09 -0800
Subject: [PATCH 0978/1411] Fix shallow dependency resolution

Summary:
The feature added in D2862850 only adds the module that requests shallow dependency resolution to the dependencies of a module. The reason why this is happens is because `collect` calls `response.addDependency` but if `recursive` is set to `false`, dependencies don't call `collect` and therefore don't get added to the resolution response. This fixes it by adding dependencies outside of the `collect` call.

public

Reviewed By: davidaurelio

Differential Revision: D2885152

fb-gh-sync-id: 8ab3b6c6b7cd45d59615a99ac87984a41b5d7025
---
 .../DependencyGraph/ResolutionRequest.js      |  3 +-
 .../__tests__/DependencyGraph-test.js         | 76 ++++++++++++++++++-
 2 files changed, 76 insertions(+), 3 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
index 2651561799ad..e95237e64a60 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
@@ -110,8 +110,8 @@ class ResolutionRequest {
       const visited = Object.create(null);
       visited[entry.hash()] = true;
 
+      response.pushDependency(entry);
       const collect = (mod) => {
-        response.pushDependency(mod);
         return mod.getDependencies().then(
           depNames => Promise.all(
             depNames.map(name => this.resolveDependency(mod, name))
@@ -163,6 +163,7 @@ class ResolutionRequest {
             p = p.then(() => {
               if (!visited[modDep.hash()]) {
                 visited[modDep.hash()] = true;
+                response.pushDependency(modDep);
                 if (recursive) {
                   return collect(modDep);
                 }
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
index 464985f692f8..66d02729a400 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
@@ -21,8 +21,8 @@ const mocksPattern = /(?:[\\/]|^)__mocks__[\\/]([^\/]+)\.js$/;
 describe('DependencyGraph', function() {
   let defaults;
 
-  function getOrderedDependenciesAsJSON(dgraph, entry, platform) {
-    return dgraph.getDependencies(entry, platform)
+  function getOrderedDependenciesAsJSON(dgraph, entry, platform, recursive = true) {
+    return dgraph.getDependencies(entry, platform, recursive)
       .then(response => response.finalize())
       .then(({ dependencies }) => Promise.all(dependencies.map(dep => Promise.all([
         dep.getName(),
@@ -89,6 +89,12 @@ describe('DependencyGraph', function() {
             '/**',
             ' * @providesModule a',
             ' */',
+            'require("b")',
+          ].join('\n'),
+          'b.js': [
+            '/**',
+            ' * @providesModule b',
+            ' */',
           ].join('\n'),
         },
       });
@@ -114,6 +120,17 @@ describe('DependencyGraph', function() {
             {
               id: 'a',
               path: '/root/a.js',
+              dependencies: ['b'],
+              isAsset: false,
+              isAsset_DEPRECATED: false,
+              isJSON: false,
+              isPolyfill: false,
+              resolution: undefined,
+              resolveDependency: undefined,
+            },
+            {
+              id: 'b',
+              path: '/root/b.js',
               dependencies: [],
               isAsset: false,
               isAsset_DEPRECATED: false,
@@ -126,6 +143,61 @@ describe('DependencyGraph', function() {
       });
     });
 
+    pit('should get shallow dependencies', function() {
+      var root = '/root';
+      fs.__setMockFilesystem({
+        'root': {
+          'index.js': [
+            '/**',
+            ' * @providesModule index',
+            ' */',
+            'require("a")',
+          ].join('\n'),
+          'a.js': [
+            '/**',
+            ' * @providesModule a',
+            ' */',
+            'require("b")',
+          ].join('\n'),
+          'b.js': [
+            '/**',
+            ' * @providesModule b',
+            ' */',
+          ].join('\n'),
+        },
+      });
+
+      var dgraph = new DependencyGraph({
+        ...defaults,
+        roots: [root],
+      });
+      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js', null, false).then(function(deps) {
+        expect(deps)
+          .toEqual([
+            {
+              id: 'index',
+              path: '/root/index.js',
+              dependencies: ['a'],
+              isAsset: false,
+              isAsset_DEPRECATED: false,
+              isJSON: false,
+              isPolyfill: false,
+              resolution: undefined,
+            },
+            {
+              id: 'a',
+              path: '/root/a.js',
+              dependencies: ['b'],
+              isAsset: false,
+              isAsset_DEPRECATED: false,
+              isJSON: false,
+              isPolyfill: false,
+              resolution: undefined,
+            },
+          ]);
+      });
+    });
+
     pit('should get dependencies with the correct extensions', function() {
       var root = '/root';
       fs.__setMockFilesystem({

From 80e1ca870be5f70f923a9d3b1700d9ec45107966 Mon Sep 17 00:00:00 2001
From: Jan Kassens <jkassens@fb.com>
Date: Mon, 1 Feb 2016 20:10:12 -0800
Subject: [PATCH 0979/1411] move Relay sources to unsigned directory

Reviewed By: yungsters

Differential Revision: D2887448

fb-gh-sync-id: 53e71be7fa875b3495991f2bf941c5eeb6ae1534
---
 packager/blacklist.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packager/blacklist.js b/packager/blacklist.js
index 0a705b9c8096..ee369e1af726 100644
--- a/packager/blacklist.js
+++ b/packager/blacklist.js
@@ -72,7 +72,7 @@ var sharedBlacklist = [
   /website\/node_modules\/.*/,
 
   // TODO(jkassens, #9876132): Remove this rule when it's no longer needed.
-  'downstream/relay/tools/relayUnstableBatchedUpdates.js',
+  'Libraries/Relay/relay/tools/relayUnstableBatchedUpdates.js',
 ];
 
 var platformBlacklists = {

From fa4a5afe35af4e93059b089c3107af916a5b21ab Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Tue, 2 Feb 2016 00:01:42 -0800
Subject: [PATCH 0980/1411] Fix Keyboard handling to allow all characters on
 Soft Input Panel and hardware keyboard

Summary:
public
This diff fixes two issues:
1) Makes it so that when a keyboard is displayed, all keys in that keyboard actually can be set as text.  Previously you could display a Numeric keyboard and it would only allow entering numbers despite the keyboard having other keys like comma, plus, space, etc.
 a) This also allows any key entered on a physical keyboard to go through to the view even if not present on the Soft Input keyboard
2) Makes more robust our Filter setting in setMaxLength so that we only affect the InputFilter.LengthFilter if present instead of all.

This works by creating a new KeyListener which will respond to getInputType as the KeyListener it is replacing (like a DigitsKeyListener for a numeric keyboard) but allow all characters when actually entering text.

Reviewed By: andreicoman11

Differential Revision: D2880851

fb-gh-sync-id: fa5eb549a849d8f30c592d7eac48054ca6a75544
---
 .../react/views/textinput/ReactEditText.java  | 66 +++++++++++++++++++
 .../textinput/ReactTextInputManager.java      | 39 +++++++++--
 2 files changed, 101 insertions(+), 4 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
index de7178d76a0e..52a18a40ce33 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
@@ -21,11 +21,14 @@
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
 import android.text.TextWatcher;
+import android.text.method.KeyListener;
+import android.text.method.QwertyKeyListener;
 import android.text.style.AbsoluteSizeSpan;
 import android.text.style.BackgroundColorSpan;
 import android.text.style.ForegroundColorSpan;
 import android.view.Gravity;
 import android.view.KeyEvent;
+import android.view.View;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.EditText;
 
@@ -65,6 +68,9 @@ public class ReactEditText extends EditText {
   private int mStagedInputType;
   private boolean mContainsImages;
   private @Nullable SelectionWatcher mSelectionWatcher;
+  private final InternalKeyListener mKeyListener;
+
+  private static KeyListener sKeyListener = QwertyKeyListener.getInstanceForFullKeyboard();
 
   public ReactEditText(Context context) {
     super(context);
@@ -81,6 +87,7 @@ public ReactEditText(Context context) {
     mListeners = null;
     mTextWatcherDelegator = null;
     mStagedInputType = getInputType();
+    mKeyListener = new InternalKeyListener();
   }
 
   // After the text changes inside an EditText, TextView checks if a layout() has been requested.
@@ -190,6 +197,12 @@ public void setSelectionWatcher(SelectionWatcher selectionWatcher) {
   public void setInputType(int type) {
     super.setInputType(type);
     mStagedInputType = type;
+
+    // We override the KeyListener so that all keys on the soft input keyboard as well as hardware
+    // keyboards work. Some KeyListeners like DigitsKeyListener will display the keyboard but not
+    // accept all input from it
+    mKeyListener.setInputType(type);
+    setKeyListener(mKeyListener);
   }
 
   // VisibleForTesting from {@link TextInputEventsTestCase}.
@@ -419,4 +432,57 @@ public void afterTextChanged(Editable s) {
       }
     }
   }
+
+  /*
+   * This class is set as the KeyListener for the underlying TextView
+   * It does two things
+   *  1) Provides the same answer to getInputType() as the real KeyListener would have which allows
+   *     the proper keyboard to pop up on screen
+   *  2) Permits all keyboard input through
+   */
+  private static class InternalKeyListener implements KeyListener {
+
+    private int mInputType = 0;
+
+    public InternalKeyListener() {
+    }
+
+    public void setInputType(int inputType) {
+      mInputType = inputType;
+    }
+
+    /*
+     * getInputType will return whatever value is passed in.  This will allow the proper keyboard
+     * to be shown on screen but without the actual filtering done by other KeyListeners
+     */
+    @Override
+    public int getInputType() {
+      return mInputType;
+    }
+
+    /*
+     * All overrides of key handling defer to the underlying KeyListener which is shared by all
+     * ReactEditText instances.  It will basically allow any/all keyboard input whether from
+     * physical keyboard or from soft input.
+     */
+    @Override
+    public boolean onKeyDown(View view, Editable text, int keyCode, KeyEvent event) {
+      return sKeyListener.onKeyDown(view, text, keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyUp(View view, Editable text, int keyCode, KeyEvent event) {
+      return sKeyListener.onKeyUp(view, text, keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyOther(View view, Editable text, KeyEvent event) {
+      return sKeyListener.onKeyOther(view, text, event);
+    }
+
+    @Override
+    public void clearMetaKeyState(View view, Editable content, int states) {
+      sKeyListener.clearMetaKeyState(view, content, states);
+    }
+  }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
index ed0d84935f8d..a9b071c72b98 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
@@ -11,6 +11,7 @@
 
 import javax.annotation.Nullable;
 
+import java.util.LinkedList;
 import java.util.Map;
 
 import android.graphics.PorterDuff;
@@ -246,13 +247,43 @@ public void setNumLines(ReactEditText view, int numLines) {
 
   @ReactProp(name = "maxLength")
   public void setMaxLength(ReactEditText view, @Nullable Integer maxLength) {
+    InputFilter [] currentFilters = view.getFilters();
+    InputFilter[] newFilters = EMPTY_FILTERS;
+
     if (maxLength == null) {
-      view.setFilters(EMPTY_FILTERS);
+      if (currentFilters.length > 0) {
+        LinkedList<InputFilter> list = new LinkedList<>();
+        for (int i = 0; i < currentFilters.length; i++) {
+          if (!(currentFilters[i] instanceof InputFilter.LengthFilter)) {
+            list.add(currentFilters[i]);
+          }
+        }
+        if (list.size() > 0) {
+          newFilters = (InputFilter[])list.toArray();
+        }
+      }
     } else {
-      InputFilter[] filterArray = new InputFilter[1];
-      filterArray[0] = new InputFilter.LengthFilter(maxLength);
-      view.setFilters(filterArray);
+      if (currentFilters.length > 0) {
+        newFilters = currentFilters;
+        boolean replaced = false;
+        for (int i = 0; i < currentFilters.length; i++) {
+          if (currentFilters[i] instanceof InputFilter.LengthFilter) {
+            currentFilters[i] = new InputFilter.LengthFilter(maxLength);
+            replaced = true;
+          }
+        }
+        if (!replaced) {
+          newFilters = new InputFilter[currentFilters.length + 1];
+          System.arraycopy(currentFilters, 0, newFilters, 0, currentFilters.length);
+          currentFilters[currentFilters.length] = new InputFilter.LengthFilter(maxLength);
+        }
+      } else {
+        newFilters = new InputFilter[1];
+        newFilters[0] = new InputFilter.LengthFilter(maxLength);
+      }
     }
+
+    view.setFilters(newFilters);
   }
 
   @ReactProp(name = "autoCorrect")

From 729c04b58b8c54476a13e139996cbc41be03ee5c Mon Sep 17 00:00:00 2001
From: Andrei-Ovidiu Coman <andreicoman11@gmail.com>
Date: Tue, 2 Feb 2016 13:19:58 +0000
Subject: [PATCH 0981/1411] Revert "TextInput should call blur and focus
 methods of selectionState"

---
 Libraries/Components/TextInput/TextInput.js | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js
index 1f1aebf8be96..f9c03a175864 100644
--- a/Libraries/Components/TextInput/TextInput.js
+++ b/Libraries/Components/TextInput/TextInput.js
@@ -525,10 +525,6 @@ var TextInput = React.createClass({
     if (this.props.onFocus) {
       this.props.onFocus(event);
     }
-
-    if (this.props.selectionState) {
-      this.props.selectionState.focus();
-    }
   },
 
   _onPress: function(event: Event) {
@@ -569,10 +565,6 @@ var TextInput = React.createClass({
     if (this.props.onBlur) {
       this.props.onBlur(event);
     }
-
-    if (this.props.selectionState) {
-      this.props.selectionState.blur();
-    }
   },
 
   _onTextInput: function(event: Event) {

From 65b09132100732756db7a7acbd392971c644cfec Mon Sep 17 00:00:00 2001
From: Aleksei Androsov <doochik@ya.ru>
Date: Tue, 2 Feb 2016 04:40:40 -0800
Subject: [PATCH 0982/1411] TextInput should call blur and focus methods of
 selectionState

Summary:
DocumentSelectionState returns anchor and focus offsets only in focused state. So TextInput should set proper state to selectionState when blur and focus.
Closes https://github.com/facebook/react-native/pull/5354

Reviewed By: svcscm

Differential Revision: D2890277

Pulled By: andreicoman11

fb-gh-sync-id: 84f96504e218cf7c70d7e24865ab074d882f3bea
---
 Libraries/Components/TextInput/TextInput.js | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js
index f9c03a175864..1f1aebf8be96 100644
--- a/Libraries/Components/TextInput/TextInput.js
+++ b/Libraries/Components/TextInput/TextInput.js
@@ -525,6 +525,10 @@ var TextInput = React.createClass({
     if (this.props.onFocus) {
       this.props.onFocus(event);
     }
+
+    if (this.props.selectionState) {
+      this.props.selectionState.focus();
+    }
   },
 
   _onPress: function(event: Event) {
@@ -565,6 +569,10 @@ var TextInput = React.createClass({
     if (this.props.onBlur) {
       this.props.onBlur(event);
     }
+
+    if (this.props.selectionState) {
+      this.props.selectionState.blur();
+    }
   },
 
   _onTextInput: function(event: Event) {

From a0bed63f1322d64c1d0b3828efbc65c91d0aa127 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Tue, 2 Feb 2016 05:18:02 -0800
Subject: [PATCH 0983/1411] Migrating RN unit tests to robolectric 3 for
 opensourcing

Reviewed By: foghina

Differential Revision: D2887376

fb-gh-sync-id: 719942bb18a5aba27eeb9d30766084d636b3d2b5
---
 .../test/java/com/facebook/react/bridge/BUCK  |  1 +
 .../react/bridge/BaseJavaModuleTest.java      | 86 +++++++++++++++++++
 2 files changed, 87 insertions(+)
 create mode 100644 ReactAndroid/src/test/java/com/facebook/react/bridge/BaseJavaModuleTest.java

diff --git a/ReactAndroid/src/test/java/com/facebook/react/bridge/BUCK b/ReactAndroid/src/test/java/com/facebook/react/bridge/BUCK
index 9e0251c7878a..83b2c81f8296 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/bridge/BUCK
+++ b/ReactAndroid/src/test/java/com/facebook/react/bridge/BUCK
@@ -38,6 +38,7 @@ robolectric3_test(
     react_native_dep('third-party/java/jackson:jackson'),
     react_native_dep('third-party/java/jsr-305:jsr-305'),
     react_native_dep('libraries/fbcore/src/test/java/com/facebook/powermock:powermock'),
+    react_native_dep('libraries/soloader/java/com/facebook/soloader:soloader'),
   ],
   visibility = [
     'PUBLIC'
diff --git a/ReactAndroid/src/test/java/com/facebook/react/bridge/BaseJavaModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/bridge/BaseJavaModuleTest.java
new file mode 100644
index 000000000000..8a681ccb51bf
--- /dev/null
+++ b/ReactAndroid/src/test/java/com/facebook/react/bridge/BaseJavaModuleTest.java
@@ -0,0 +1,86 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.bridge;
+
+import java.util.Map;
+
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.ReadableNativeArray;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.rule.PowerMockRule;
+import org.robolectric.RobolectricTestRunner;
+
+import com.facebook.soloader.SoLoader;
+
+/**
+ * Tests for {@link BaseJavaModule}
+ */
+@PrepareForTest({ReadableNativeArray.class, SoLoader.class})
+@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
+@RunWith(RobolectricTestRunner.class)
+public class BaseJavaModuleTest {
+
+  @Rule
+  public PowerMockRule rule = new PowerMockRule();
+
+  private Map<String, NativeModule.NativeMethod> mMethods;
+  private ReadableNativeArray mArguments;
+
+  @Before
+  public void setup() {
+    mMethods = new MethodsModule().getMethods();
+    PowerMockito.mockStatic(SoLoader.class);
+    mArguments = PowerMockito.mock(ReadableNativeArray.class);
+  }
+
+  @Test(expected = NativeArgumentsParseException.class)
+  public void testCallMethodWithoutEnoughArgs() throws Exception {
+    BaseJavaModule.NativeMethod regularMethod = mMethods.get("regularMethod");
+    Mockito.stub(mArguments.size()).toReturn(1);
+    regularMethod.invoke(null, mArguments);
+  }
+
+  @Test(expected = NativeArgumentsParseException.class)
+  public void testCallAsyncMethodWithoutEnoughArgs() throws Exception {
+    BaseJavaModule.NativeMethod asyncMethod = mMethods.get("asyncMethod");
+    Mockito.stub(mArguments.size()).toReturn(2);
+    asyncMethod.invoke(null, mArguments);
+  }
+
+  @Test()
+  public void testCallAsyncMethodWithEnoughArgs() throws Exception {
+    BaseJavaModule.NativeMethod asyncMethod = mMethods.get("asyncMethod");
+    Mockito.stub(mArguments.size()).toReturn(3);
+    asyncMethod.invoke(null, mArguments);
+  }
+
+  private static class MethodsModule extends BaseJavaModule {
+    @Override
+    public String getName() {
+      return "Methods";
+    }
+
+    @ReactMethod
+    public void regularMethod(String a, int b) {
+    }
+
+    @ReactMethod
+    public void asyncMethod(int a, Promise p) {
+    }
+  }
+}

From 6d65a90017718ce763cc818a553e32856c5084d3 Mon Sep 17 00:00:00 2001
From: Kudo Chien <ckchien@gmail.com>
Date: Tue, 2 Feb 2016 07:11:41 -0800
Subject: [PATCH 0984/1411] Allow customized refreshControl in ScrollView for
 Android

Summary:
Original Android's refreshControl in ScrollView is tightly coupled with AndroidSwipeRefreshLayout. If someone use `ref=` for RefreshControl in ScrollView, it does nothing since RefreshControl in Android return null.

This change allows customized  RefreshControl especially for `ref=` as well as making ScrollView's code clearer.
Closes https://github.com/facebook/react-native/pull/5623

Reviewed By: svcscm

Differential Revision: D2890072

Pulled By: nicklockwood

fb-gh-sync-id: a8fc7746bcc050a6e46fedf3583979f4cb9021b6
---
 .../RefreshControl/RefreshControl.js           | 17 ++++++++---------
 Libraries/Components/ScrollView/ScrollView.js  | 18 ++++++------------
 .../PullToRefreshViewAndroid.android.js        |  3 +--
 Libraries/ReactIOS/requireNativeComponent.js   |  1 +
 .../SwipeRefreshLayoutManager.java             |  2 +-
 5 files changed, 17 insertions(+), 24 deletions(-)

diff --git a/Libraries/Components/RefreshControl/RefreshControl.js b/Libraries/Components/RefreshControl/RefreshControl.js
index 319f054c38eb..1ae8119a1e2e 100644
--- a/Libraries/Components/RefreshControl/RefreshControl.js
+++ b/Libraries/Components/RefreshControl/RefreshControl.js
@@ -13,6 +13,7 @@
 const React = require('React');
 const Platform = require('Platform');
 const ColorPropType = require('ColorPropType');
+const View = require('View');
 
 const requireNativeComponent = require('requireNativeComponent');
 
@@ -33,6 +34,7 @@ const RefreshControl = React.createClass({
   },
 
   propTypes: {
+    ...View.propTypes,
     /**
      * Called when the view starts refreshing.
      */
@@ -74,15 +76,7 @@ const RefreshControl = React.createClass({
   },
 
   render() {
-    if (Platform.OS === 'ios') {
-      return <NativeRefreshControl {...this.props}/>;
-    } else {
-      // On Android the ScrollView is wrapped so this component doesn't render
-      // anything and only acts as a way to configure the wrapper view.
-      // ScrollView will wrap itself in a AndroidSwipeRefreshLayout using props
-      // from this.
-      return null;
-    }
+    return <NativeRefreshControl {...this.props} />;
   },
 });
 
@@ -91,6 +85,11 @@ if (Platform.OS === 'ios') {
     'RCTRefreshControl',
     RefreshControl
   );
+} else if (Platform.OS === 'android') {
+  var NativeRefreshControl = requireNativeComponent(
+    'AndroidSwipeRefreshLayout',
+    RefreshControl
+  );
 }
 
 module.exports = RefreshControl;
diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js
index 89cc17921044..623951b5ed08 100644
--- a/Libraries/Components/ScrollView/ScrollView.js
+++ b/Libraries/Components/ScrollView/ScrollView.js
@@ -32,7 +32,6 @@ var insetsDiffer = require('insetsDiffer');
 var invariant = require('invariant');
 var pointsDiffer = require('pointsDiffer');
 var requireNativeComponent = require('requireNativeComponent');
-var processColor = require('processColor');
 var processDecelerationRate = require('processDecelerationRate');
 var PropTypes = React.PropTypes;
 
@@ -507,16 +506,12 @@ var ScrollView = React.createClass({
         // On Android wrap the ScrollView with a AndroidSwipeRefreshLayout.
         // Since the ScrollView is wrapped add the style props to the
         // AndroidSwipeRefreshLayout and use flex: 1 for the ScrollView.
-        var refreshProps = refreshControl.props;
-        return (
-          <AndroidSwipeRefreshLayout
-            {...refreshProps}
-            colors={refreshProps.colors && refreshProps.colors.map(processColor)}
-            style={props.style}>
-            <ScrollViewClass {...props} style={styles.base} ref={SCROLLVIEW}>
-              {contentContainer}
-            </ScrollViewClass>
-          </AndroidSwipeRefreshLayout>
+        return React.cloneElement(
+          refreshControl,
+          {style: this.props.style},
+          <ScrollViewClass {...props} style={styles.base} ref={SCROLLVIEW}>
+            {contentContainer}
+          </ScrollViewClass>
         );
       }
     }
@@ -574,7 +569,6 @@ if (Platform.OS === 'android') {
     'AndroidHorizontalScrollView',
     ScrollView
   );
-  var AndroidSwipeRefreshLayout = requireNativeComponent('AndroidSwipeRefreshLayout');
 } else if (Platform.OS === 'ios') {
   var RCTScrollView = requireNativeComponent('RCTScrollView', ScrollView);
 }
diff --git a/Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js b/Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js
index 1c37d2ec9058..c0f498ba2532 100644
--- a/Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js
+++ b/Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js
@@ -16,7 +16,6 @@ var RefreshLayoutConsts = require('UIManager').AndroidSwipeRefreshLayout.Constan
 var View = require('View');
 
 var onlyChild = require('onlyChild');
-var processColor = require('processColor');
 var requireNativeComponent = require('requireNativeComponent');
 
 var NATIVE_REF = 'native_swiperefreshlayout';
@@ -68,7 +67,7 @@ var PullToRefreshViewAndroid = React.createClass({
   render: function() {
     return (
       <NativePullToRefresh
-        colors={this.props.colors && this.props.colors.map(processColor)}
+        colors={this.props.colors}
         enabled={this.props.enabled}
         onRefresh={this._onRefresh}
         progressBackgroundColor={this.props.progressBackgroundColor}
diff --git a/Libraries/ReactIOS/requireNativeComponent.js b/Libraries/ReactIOS/requireNativeComponent.js
index cb190912401d..4f8ddaf2e4f4 100644
--- a/Libraries/ReactIOS/requireNativeComponent.js
+++ b/Libraries/ReactIOS/requireNativeComponent.js
@@ -121,6 +121,7 @@ var TypeToProcessorMap = {
   RCTImageSource: resolveAssetSource,
   // Android Types
   Color: processColor,
+  ColorArray: processColorArray,
 };
 
 module.exports = requireNativeComponent;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/SwipeRefreshLayoutManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/SwipeRefreshLayoutManager.java
index d6b3a36629e3..3dccc4c48bab 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/SwipeRefreshLayoutManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/SwipeRefreshLayoutManager.java
@@ -47,7 +47,7 @@ public void setEnabled(ReactSwipeRefreshLayout view, boolean enabled) {
     view.setEnabled(enabled);
   }
 
-  @ReactProp(name = "colors")
+  @ReactProp(name = "colors", customType = "ColorArray")
   public void setColors(ReactSwipeRefreshLayout view, @Nullable ReadableArray colors) {
     if (colors != null) {
       int[] colorValues = new int[colors.size()];

From 2633f10588d3d71d9d1a675e19e48a148ac0c6a3 Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Tue, 2 Feb 2016 08:29:54 -0800
Subject: [PATCH 0985/1411] Fix a crash when logging a JS exception that has no
 source file

Summary:
This error occurs primarily when starting the app and the packager is not running.

`source` can be null when the evaluated code does not come from a source file so it just crashes with a SIGSEGV when passing it to `String::adopt`. This restores the beloved 'Can't find variable __fbBatchedBridge' redbox error :)

Seems to be introduced in 17e1ceb5437049f794b74507feb6856e3450d2b2.

cc davidaurelio
Closes https://github.com/facebook/react-native/pull/5689

Reviewed By: svcscm

Differential Revision: D2890634

Pulled By: astreet

fb-gh-sync-id: b96bbe8e26c9ac580b1aa17222d2f59376832560
---
 ReactAndroid/src/main/jni/react/JSCHelpers.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/jni/react/JSCHelpers.cpp b/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
index 80b7966174d0..7e6b8db3c999 100644
--- a/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
@@ -56,7 +56,7 @@ JSValueRef evaluateScript(JSContextRef context, JSStringRef script, JSStringRef
     auto line = exception.asObject().getProperty("line");
 
     std::ostringstream locationInfo;
-    std::string file = String::adopt(source).str();
+    std::string file = source != nullptr ? String::adopt(source).str() : "";
     locationInfo << "(" << (file.length() ? file : "<unknown file>");
     if (line != nullptr && line.isNumber()) {
       locationInfo << ":" << line.asInteger();

From 804b23811b6243bf4d8405c36720b0819edd27c9 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Tue, 2 Feb 2016 08:43:52 -0800
Subject: [PATCH 0986/1411] Fix lint for D2880851

Reviewed By: andreicoman11

Differential Revision: D2890474

fb-gh-sync-id: 2d6b2a9a5caa1964646706ba75a5fae8350d0ee5
---
 .../com/facebook/react/views/textinput/ReactEditText.java     | 2 +-
 .../facebook/react/views/textinput/ReactTextInputManager.java | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
index 52a18a40ce33..58e3e5a560a0 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
@@ -70,7 +70,7 @@ public class ReactEditText extends EditText {
   private @Nullable SelectionWatcher mSelectionWatcher;
   private final InternalKeyListener mKeyListener;
 
-  private static KeyListener sKeyListener = QwertyKeyListener.getInstanceForFullKeyboard();
+  private static final KeyListener sKeyListener = QwertyKeyListener.getInstanceForFullKeyboard();
 
   public ReactEditText(Context context) {
     super(context);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
index a9b071c72b98..043a3683370a 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
@@ -258,8 +258,8 @@ public void setMaxLength(ReactEditText view, @Nullable Integer maxLength) {
             list.add(currentFilters[i]);
           }
         }
-        if (list.size() > 0) {
-          newFilters = (InputFilter[])list.toArray();
+        if (!list.isEmpty()) {
+          newFilters = (InputFilter[]) list.toArray();
         }
       }
     } else {

From fb29a95e011921ac043993a852223a27d1224464 Mon Sep 17 00:00:00 2001
From: Adam Miskiewicz <adam@sk3vy.com>
Date: Tue, 2 Feb 2016 09:24:30 -0800
Subject: [PATCH 0987/1411] Fix import of LinkingIOS on Android

Summary:
We need to check the existence of RCTLinkingManager (which doesn't exist on Android) because this code is called on require.
Closes https://github.com/facebook/react-native/pull/5680

Reviewed By: svcscm

Differential Revision: D2887260

Pulled By: androidtrunkagent

fb-gh-sync-id: 4a5843ea6a5898d0f2810ad9ddb5b2078054e9f1
---
 Libraries/LinkingIOS/LinkingIOS.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/LinkingIOS/LinkingIOS.js b/Libraries/LinkingIOS/LinkingIOS.js
index d223b0d8b729..aa252c7d62aa 100644
--- a/Libraries/LinkingIOS/LinkingIOS.js
+++ b/Libraries/LinkingIOS/LinkingIOS.js
@@ -15,7 +15,7 @@ var Linking = require('Linking');
 var RCTLinkingManager = require('NativeModules').LinkingManager;
 var invariant = require('invariant');
 
-var _initialURL = RCTLinkingManager.initialURL;
+var _initialURL = RCTLinkingManager && RCTLinkingManager.initialURL;
 
 /**
  * NOTE: `LinkingIOS` is being deprecated. Use `Linking` instead.

From 5c705264aa2dcd40ee674c76181e44aeeef16a15 Mon Sep 17 00:00:00 2001
From: Richard Lai <it.rclai@gmail.com>
Date: Tue, 2 Feb 2016 10:20:11 -0800
Subject: [PATCH 0988/1411] Remove AppState from Known Issues page

Summary:
Closes https://github.com/facebook/react-native/issues/5682.
Closes https://github.com/facebook/react-native/pull/5704

Reviewed By: svcscm

Differential Revision: D2890937

Pulled By: androidtrunkagent

fb-gh-sync-id: 75760220640a836947ea91e8dc554734dff790b8
---
 docs/KnownIssues.md | 1 -
 1 file changed, 1 deletion(-)

diff --git a/docs/KnownIssues.md b/docs/KnownIssues.md
index cfc9bd00aba6..3a4870f4ab79 100644
--- a/docs/KnownIssues.md
+++ b/docs/KnownIssues.md
@@ -31,7 +31,6 @@ Slider (known as SeekBar)
 #### Modules
 
 ```
-App State
 Camera Roll
 Media
 PushNotificationIOS

From ba89d9bb7e50d023957046029f4eac0601210547 Mon Sep 17 00:00:00 2001
From: AnishKumar Dubey <anish.p@caratlane.com>
Date: Wed, 3 Feb 2016 00:35:33 +0530
Subject: [PATCH 0989/1411] Adding CaratLane app to react-native showcase

---
 website/src/react-native/showcase.js | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index eaa4b6eadaaf..d2644b64eb46 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -149,8 +149,14 @@ var apps = [
     author: 'CANDDi LTD.',
   },
   {
-    name: 'CBS Sports Franchise Football',
+    name: 'CaratLane',
     icon: 'http://a2.mzstatic.com/us/r30/Purple69/v4/7b/0c/a0/7b0ca007-885a-7cfc-9fa2-2ec4394c2ecc/icon175x175.png',
+    link: 'https://play.google.com/store/apps/details?id=com.caratlane.android&hl=en',
+    author: 'CaratLane',
+  },
+  {
+    name: 'CBS Sports Franchise Football',
+    icon: 'https://lh3.googleusercontent.com/wEN-Vvpbnw_n89dbXPxWkNnXB7sALKBKvpX_hbzrWbuC4tFi5tVkWHq8k5TAvdbf5UQ=w300-rw',
     link: 'https://play.google.com/store/apps/details?id=com.cbssports.fantasy.franchisefootball2015',
     author: 'CBS Sports',
   },

From cc231cde73cd25e88bfd30bf264a7e738f491792 Mon Sep 17 00:00:00 2001
From: AnishKumar Dubey <anish.p@caratlane.com>
Date: Wed, 3 Feb 2016 00:51:10 +0530
Subject: [PATCH 0990/1411] Adding CaratLane app to react-native showcase

---
 website/src/react-native/showcase.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index d2644b64eb46..54433bcc4274 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -150,13 +150,13 @@ var apps = [
   },
   {
     name: 'CaratLane',
-    icon: 'http://a2.mzstatic.com/us/r30/Purple69/v4/7b/0c/a0/7b0ca007-885a-7cfc-9fa2-2ec4394c2ecc/icon175x175.png',
+    icon: 'https://lh3.googleusercontent.com/wEN-Vvpbnw_n89dbXPxWkNnXB7sALKBKvpX_hbzrWbuC4tFi5tVkWHq8k5TAvdbf5UQ=w300-rw',
     link: 'https://play.google.com/store/apps/details?id=com.caratlane.android&hl=en',
     author: 'CaratLane',
   },
   {
     name: 'CBS Sports Franchise Football',
-    icon: 'https://lh3.googleusercontent.com/wEN-Vvpbnw_n89dbXPxWkNnXB7sALKBKvpX_hbzrWbuC4tFi5tVkWHq8k5TAvdbf5UQ=w300-rw',
+    icon: 'http://a2.mzstatic.com/us/r30/Purple69/v4/7b/0c/a0/7b0ca007-885a-7cfc-9fa2-2ec4394c2ecc/icon175x175.png',
     link: 'https://play.google.com/store/apps/details?id=com.cbssports.fantasy.franchisefootball2015',
     author: 'CBS Sports',
   },

From d1e9fc0737fc0987436807d3b9992869f51ce078 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Tue, 2 Feb 2016 12:20:36 -0800
Subject: [PATCH 0991/1411] Fix SourceMap loading on Android

Reviewed By: martinbigio

Differential Revision: D2891405

fb-gh-sync-id: 8fa38e530952c6e7fda48557ea6386b4b456efb0
---
 .../Initialization/SourceMapsUtils.js                    | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/Libraries/JavaScriptAppEngine/Initialization/SourceMapsUtils.js b/Libraries/JavaScriptAppEngine/Initialization/SourceMapsUtils.js
index f49a107c1d2f..ecd6d8272597 100644
--- a/Libraries/JavaScriptAppEngine/Initialization/SourceMapsUtils.js
+++ b/Libraries/JavaScriptAppEngine/Initialization/SourceMapsUtils.js
@@ -34,13 +34,20 @@ var SourceMapsUtils = {
       .then(map => new SourceMapConsumer(map));
   },
 
-  extractSourceMapURL(data: ({url:string, text:string})): ?string {
+  extractSourceMapURL(data: ({url?:string, text?:string, fullSourceMappingURL?:string})): ?string {
     const url = data.url;
     const text = data.text;
+    const fullSourceMappingURL = data.fullSourceMappingURL;
+    if (fullSourceMappingURL) {
+      return fullSourceMappingURL;
+    }
     var mapURL = SourceMapURL.getFrom(text);
     if (!mapURL) {
       return null;
     }
+    if (!url) {
+      return null;
+    }
     var baseURLs = url.match(/(.+:\/\/.*?)\//);
     if (!baseURLs || baseURLs.length < 2) {
       return null;

From 422bb263b6d37c13e6827b9955186c05b4816f3e Mon Sep 17 00:00:00 2001
From: Thomas Goldenberg <thomasagoldenberg@gmail.com>
Date: Tue, 2 Feb 2016 16:36:22 -0500
Subject: [PATCH 0992/1411] Update showcase.js

---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 54433bcc4274..6c98ec02e744 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -557,6 +557,12 @@ var apps = [
     linkAppStore: 'https://itunes.apple.com/jp/app/minnano-duan-ge-tou-gaokomyuniti/id675671254?mt=8',
     linkPlayStore: 'https://play.google.com/store/apps/details?id=com.plasticaromantica.utayomin',
     author: 'Takayuki IMAI'
+  },
+  {
+    name: 'Bhagavad Gita Lite',
+    icon: 'https://s3-us-west-2.amazonaws.com/bhagavadgitaapp/gita-free.png',
+    link: 'https://itunes.apple.com/us/app/bhagavad-gita-lite/id1071711190?ls=1&mt=8',
+    author: 'Tom Goldenberg & Nick Brown'
   }
 ];
 

From c7d0a9b54f38fa28e2b69557dbb797b2d730adc5 Mon Sep 17 00:00:00 2001
From: Thomas Goldenberg <thomasagoldenberg@gmail.com>
Date: Tue, 2 Feb 2016 17:36:09 -0500
Subject: [PATCH 0993/1411] Update showcase.js

---
 website/src/react-native/showcase.js | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 6c98ec02e744..c183012e0398 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -135,6 +135,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/beetroot/id1016159001?ls=1&mt=8',
     author: 'Alex Duckmanton',
   },
+  {
+    name: 'Bhagavad Gita Lite',
+    icon: 'https://s3-us-west-2.amazonaws.com/bhagavadgitaapp/gita-free.png',
+    link: 'https://itunes.apple.com/us/app/bhagavad-gita-lite/id1071711190?ls=1&mt=8',
+    author: 'Tom Goldenberg & Nick Brown'
+  },
   {
     name: 'Bionic eStore',
     icon: 'http://a5.mzstatic.com/us/r30/Purple7/v4/c1/9a/3f/c19a3f82-ecc3-d60b-f983-04acc203705f/icon175x175.jpeg',
@@ -558,12 +564,6 @@ var apps = [
     linkPlayStore: 'https://play.google.com/store/apps/details?id=com.plasticaromantica.utayomin',
     author: 'Takayuki IMAI'
   },
-  {
-    name: 'Bhagavad Gita Lite',
-    icon: 'https://s3-us-west-2.amazonaws.com/bhagavadgitaapp/gita-free.png',
-    link: 'https://itunes.apple.com/us/app/bhagavad-gita-lite/id1071711190?ls=1&mt=8',
-    author: 'Tom Goldenberg & Nick Brown'
-  }
 ];
 
 var AppList = React.createClass({

From 8c62ed7c95ce86efecbb0fd540b1770ef5ca72dd Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Tue, 2 Feb 2016 15:48:01 -0800
Subject: [PATCH 0994/1411] Use `fastfs.readWhile` to parse module docblocks
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Summary:
Uses `fastfs.readWhile` to build the haste map

- cuts the time needed to build the haste map in half
- we don’t need to allocate memory for all JS files in the tree
- we only read in as much as necessary during startup
- we only read files completely that are part of the bundle
- we will be able to move the transform before dependency extraction

public

Reviewed By: martinbigio

Differential Revision: D2890933

fb-gh-sync-id: 5fef6b53458e8bc95d0251d0bcf16821581a3362
---
 .../src/DependencyResolver/Module.js          | 122 ++++++++++++------
 .../__tests__/Module-test.js                  |  98 ++++++++++++++
 packager/react-packager/src/__mocks__/fs.js   |  50 +++++++
 3 files changed, 227 insertions(+), 43 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/Module.js b/packager/react-packager/src/DependencyResolver/Module.js
index df6ed710726b..f9142611fed3 100644
--- a/packager/react-packager/src/DependencyResolver/Module.js
+++ b/packager/react-packager/src/DependencyResolver/Module.js
@@ -43,7 +43,7 @@ class Module {
     return this._cache.get(
       this.path,
       'isHaste',
-      () => this.read().then(data => !!data.id)
+      () => this._readDocBlock().then(data => !!data.id)
     );
   }
 
@@ -55,9 +55,9 @@ class Module {
     return this._cache.get(
       this.path,
       'name',
-      () => this.read().then(data => {
-        if (data.id) {
-          return data.id;
+      () => this._readDocBlock().then(({id}) => {
+        if (id) {
+          return id;
         }
 
         const p = this.getPackage();
@@ -103,49 +103,70 @@ class Module {
     this._cache.invalidate(this.path);
   }
 
-  read() {
-    if (!this._reading) {
-      this._reading = this._fastfs.readFile(this.path).then(content => {
-        const data = {};
-
-        // Set an id on the module if it's using @providesModule syntax
-        // and if it's NOT in node_modules (and not a whitelisted node_module).
-        // This handles the case where a project may have a dep that has @providesModule
-        // docblock comments, but doesn't want it to conflict with whitelisted @providesModule
-        // modules, such as react-haste, fbjs-haste, or react-native or with non-dependency,
-        // project-specific code that is using @providesModule.
-        const moduleDocBlock = docblock.parseAsObject(content);
-        if (!this._depGraphHelpers.isNodeModulesDir(this.path) &&
-            (moduleDocBlock.providesModule || moduleDocBlock.provides)) {
-          data.id = /^(\S*)/.exec(
-            moduleDocBlock.providesModule || moduleDocBlock.provides
-          )[1];
-        }
+  _parseDocBlock(docBlock) {
+    // Extract an id for the module if it's using @providesModule syntax
+    // and if it's NOT in node_modules (and not a whitelisted node_module).
+    // This handles the case where a project may have a dep that has @providesModule
+    // docblock comments, but doesn't want it to conflict with whitelisted @providesModule
+    // modules, such as react-haste, fbjs-haste, or react-native or with non-dependency,
+    // project-specific code that is using @providesModule.
+    const moduleDocBlock = docblock.parseAsObject(docBlock);
+    const provides = moduleDocBlock.providesModule || moduleDocBlock.provides;
+
+    const id = provides && !this._depGraphHelpers.isNodeModulesDir(this.path)
+        ? /^\S+/.exec(provides)[0]
+        : undefined;
+    return [id, moduleDocBlock];
+  }
 
-        // Ignore requires in JSON files or generated code. An example of this
-        // is prebuilt files like the SourceMap library.
-        if (this.isJSON() || 'extern' in moduleDocBlock) {
-          data.dependencies = [];
-          data.asyncDependencies = [];
-          data.code = content;
-          return data;
-        } else {
-          const transformCode = this._transformCode;
-          const codePromise = transformCode
-              ? transformCode(this, content)
-              : Promise.resolve({code: content});
-
-          return codePromise.then(({code, dependencies, asyncDependencies}) => {
-            const {deps} = this._extractor(code);
-            data.dependencies = dependencies || deps.sync;
-            data.asyncDependencies = asyncDependencies || deps.async;
-            data.code = code;
-            return data;
-          });
-        }
+  _readDocBlock() {
+    const reading = this._reading || this._docBlock;
+    if (reading) {
+      return reading;
+    }
+    this._docBlock = this._fastfs.readWhile(this.path, whileInDocBlock)
+      .then(docBlock => {
+        const [id] = this._parseDocBlock(docBlock);
+        return {id};
       });
+    return this._docBlock;
+  }
+
+  read() {
+    if (this._reading) {
+      return this._reading;
     }
 
+    this._reading = this._fastfs.readFile(this.path).then(content => {
+      const [id, moduleDocBlock] = this._parseDocBlock(content);
+
+      // Ignore requires in JSON files or generated code. An example of this
+      // is prebuilt files like the SourceMap library.
+      if (this.isJSON() || 'extern' in moduleDocBlock) {
+        return {
+          id,
+          dependencies: [],
+          asyncDependencies: [],
+          code: content,
+        };
+      } else {
+        const transformCode = this._transformCode;
+        const codePromise = transformCode
+            ? transformCode(this, content)
+            : Promise.resolve({code: content});
+
+        return codePromise.then(({code, dependencies, asyncDependencies}) => {
+          const {deps} = this._extractor(code);
+          return {
+            id,
+            code,
+            dependencies: dependencies || deps.sync,
+            asyncDependencies: asyncDependencies || deps.async,
+          };
+        });
+      }
+    });
+
     return this._reading;
   }
 
@@ -181,4 +202,19 @@ class Module {
   }
 }
 
+function whileInDocBlock(chunk, i, result) {
+  // consume leading whitespace
+  if (!/\S/.test(result)) {
+    return true;
+  }
+
+  // check for start of doc block
+  if (!/^\s*\/(\*{2}|\*?$)/.test(result)) {
+    return false;
+  }
+
+  // check for end of doc block
+  return !/\*\//.test(result);
+}
+
 module.exports = Module;
diff --git a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js b/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
index 947fa0b1c7f1..4ed5868b1860 100644
--- a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
+++ b/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
@@ -69,6 +69,104 @@ describe('Module', () => {
     fastfs.build().then(done);
   });
 
+  describe('Module ID', () => {
+    const moduleId = 'arbitraryModule';
+    const source =
+    `/**
+       * @providesModule ${moduleId}
+       */
+    `;
+
+    let module;
+    beforeEach(() => {
+      module = createModule();
+    });
+
+    describe('@providesModule annotations', () => {
+      beforeEach(() => {
+        mockIndexFile(source);
+      });
+
+      pit('extracts the module name from the header', () =>
+        module.getName().then(name => expect(name).toEqual(moduleId))
+      );
+
+      pit('identifies the module as haste module', () =>
+        module.isHaste().then(isHaste => expect(isHaste).toBe(true))
+      );
+
+      pit('does not transform the file in order to access the name', () => {
+        const transformCode =
+          jest.genMockFn().mockReturnValue(Promise.resolve());
+        return createModule({transformCode}).getName()
+          .then(() => expect(transformCode).not.toBeCalled());
+      });
+
+      pit('does not transform the file in order to access the haste status', () => {
+        const transformCode =
+          jest.genMockFn().mockReturnValue(Promise.resolve());
+        return createModule({transformCode}).isHaste()
+          .then(() => expect(transformCode).not.toBeCalled());
+      });
+    });
+
+    describe('@provides annotations', () => {
+      beforeEach(() => {
+        mockIndexFile(source.replace(/@providesModule/, '@provides'));
+      });
+
+      pit('extracts the module name from the header if it has a @provides annotation', () =>
+        module.getName().then(name => expect(name).toEqual(moduleId))
+      );
+
+      pit('identifies the module as haste module', () =>
+        module.isHaste().then(isHaste => expect(isHaste).toBe(true))
+      );
+
+      pit('does not transform the file in order to access the name', () => {
+        const transformCode =
+          jest.genMockFn().mockReturnValue(Promise.resolve());
+        return createModule({transformCode}).getName()
+          .then(() => expect(transformCode).not.toBeCalled());
+      });
+
+      pit('does not transform the file in order to access the haste status', () => {
+        const transformCode =
+          jest.genMockFn().mockReturnValue(Promise.resolve());
+        return createModule({transformCode}).isHaste()
+          .then(() => expect(transformCode).not.toBeCalled());
+      });
+    });
+
+    describe('no annotation', () => {
+      beforeEach(() => {
+        mockIndexFile('arbitrary(code);');
+      });
+
+      pit('uses the file name as module name', () =>
+        module.getName().then(name => expect(name).toEqual(fileName))
+      );
+
+      pit('does not identify the module as haste module', () =>
+        module.isHaste().then(isHaste => expect(isHaste).toBe(false))
+      );
+
+      pit('does not transform the file in order to access the name', () => {
+        const transformCode =
+          jest.genMockFn().mockReturnValue(Promise.resolve());
+        return createModule({transformCode}).getName()
+          .then(() => expect(transformCode).not.toBeCalled());
+      });
+
+      pit('does not transform the file in order to access the haste status', () => {
+        const transformCode =
+          jest.genMockFn().mockReturnValue(Promise.resolve());
+        return createModule({transformCode}).isHaste()
+          .then(() => expect(transformCode).not.toBeCalled());
+      });
+    });
+  });
+
   describe('Async Dependencies', () => {
     function expectAsyncDependenciesToEqual(expected) {
       const module = createModule();
diff --git a/packager/react-packager/src/__mocks__/fs.js b/packager/react-packager/src/__mocks__/fs.js
index 1aca92500ae0..64b0c9b1896c 100644
--- a/packager/react-packager/src/__mocks__/fs.js
+++ b/packager/react-packager/src/__mocks__/fs.js
@@ -112,6 +112,56 @@ fs.stat.mockImpl(function(filepath, callback) {
   }
 });
 
+const noop = () => {};
+fs.open.mockImpl(function(path) {
+  const callback = arguments[arguments.length - 1] || noop;
+  let data, error, fd;
+  try {
+    data = getToNode(path);
+  } catch (e) {
+    error = e;
+  }
+
+  if (error || data == null) {
+    error = Error(`ENOENT: no such file or directory, open ${path}`);
+  }
+  if (data != null) {
+    /* global Buffer: true */
+    fd = {
+      buffer: new Buffer(data, 'utf8'),
+      position: 0,
+    };
+  }
+
+  callback(error, fd);
+});
+
+fs.read.mockImpl((fd, buffer, writeOffset, length, position, callback = noop) => {
+  let bytesWritten;
+  try {
+    if (position == null || position < 0) {
+      ({position} = fd);
+    }
+    bytesWritten =
+      fd.buffer.copy(buffer, writeOffset, position, position + length);
+    fd.position = position + bytesWritten;
+  } catch (e) {
+    callback(Error('invalid argument'));
+    return;
+  }
+  callback(null, bytesWritten, buffer);
+});
+
+fs.close.mockImpl((fd, callback = noop) => {
+  try {
+    fd.buffer = fs.position = undefined;
+  } catch (e) {
+    callback(Error('invalid argument'));
+    return;
+  }
+  callback(null);
+});
+
 var filesystem;
 
 fs.__setMockFilesystem = function(object) {

From 5ca519de299e6f0d34f795d314d2aa6fc6199ac4 Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Tue, 2 Feb 2016 17:49:50 -0800
Subject: [PATCH 0995/1411] Add mocks for packages to resolution responses

Summary:
Right now, a mock called `debug.js` shadows a node module called `debug`. When I made mocking more strict I didn't realize that it didn't include those mocks any more because requiring `debug` would result in a module like `debug/node.js` which doesn't have a mock associated with it. This diff changes it so it looks at the associated `package.json` to match the name up to mocks. This is the least invasive non-breaking change I can make right now. Yes, mocking strategies are basically fucked but I don't want the haste2 integration to have even more breaking changes right now. Consider this code to be temporary, I'll fix this and make the mocking system more sane mid-term.

public

Reviewed By: davidaurelio

Differential Revision: D2889198

fb-gh-sync-id: 58db852ed9acad830538245f7dc347365fe4de38
---
 .../DependencyGraph/ResolutionRequest.js      | 25 ++++++++++++-------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
index e95237e64a60..879c53efa59f 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
@@ -118,14 +118,21 @@ class ResolutionRequest {
           ).then((dependencies) => [depNames, dependencies])
         ).then(([depNames, dependencies]) => {
           if (allMocks) {
-            return mod.getName().then(name => {
-              if (allMocks[name]) {
-                const mockModule =
-                  this._moduleCache.getModule(allMocks[name]);
-                depNames.push(name);
-                dependencies.push(mockModule);
-                mocks[name] = allMocks[name];
-              }
+            const list = [mod.getName()];
+            const pkg = mod.getPackage();
+            if (pkg) {
+              list.push(pkg.getName());
+            }
+            return Promise.all(list).then(names => {
+              names.forEach(name => {
+                if (allMocks[name] && !mocks[name]) {
+                  const mockModule =
+                    this._moduleCache.getModule(allMocks[name]);
+                  depNames.push(name);
+                  dependencies.push(mockModule);
+                  mocks[name] = allMocks[name];
+                }
+              });
               return [depNames, dependencies];
             });
           }
@@ -141,7 +148,7 @@ class ResolutionRequest {
               // module backing them. If a dependency cannot be found but there
               // exists a mock with the desired ID, resolve it and add it as
               // a dependency.
-              if (allMocks && allMocks[name]) {
+              if (allMocks && allMocks[name] && !mocks[name]) {
                 const mockModule = this._moduleCache.getModule(allMocks[name]);
                 mocks[name] = allMocks[name];
                 return filteredPairs.push([name, mockModule]);

From 55f4e55109768d377e38a66542bbbaefb243331b Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Tue, 2 Feb 2016 18:09:45 -0800
Subject: [PATCH 0996/1411] Move process.exit outside of DependencyResolver
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Summary:
node-haste shouldn't ever call process.exit and should leave it up to clients to shut down properly. This change just moves it out into the `Resolver` class – I'll leave it up to David and Martin to improve error handling for the rn packager :)

public

Reviewed By: davidaurelio

Differential Revision: D2889908

fb-gh-sync-id: 6f03162c44d89e268891ef71c8db784a6f2e081d
---
 .../__tests__/DependencyGraph-test.js           | 14 +++-----------
 .../DependencyResolver/DependencyGraph/index.js | 17 +++++++++++------
 .../src/Resolver/__tests__/Resolver-test.js     |  3 ++-
 packager/react-packager/src/Resolver/index.js   |  5 +++++
 4 files changed, 21 insertions(+), 18 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
index 66d02729a400..09a4454373e2 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
@@ -1189,22 +1189,14 @@ describe('DependencyGraph', function() {
         },
       });
 
-      const _exit = process.exit;
-      const _error = console.error;
-
-      process.exit = jest.genMockFn();
-      console.error = jest.genMockFn();
-
       var dgraph = new DependencyGraph({
         ...defaults,
         roots: [root],
       });
 
-      return dgraph.load().catch(() => {
-        expect(process.exit).toBeCalledWith(1);
-        expect(console.error).toBeCalled();
-        process.exit = _exit;
-        console.error = _error;
+      return dgraph.load().catch(err => {
+        expect(err.message).toEqual('Failed to build DependencyGraph: Naming collision detected: /root/b.js collides with /root/index.js');
+        expect(err.type).toEqual('DependencyGraphError');
       });
     });
 
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
index bc5d85d7864d..3c5ade661eb5 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
@@ -22,6 +22,8 @@ const ResolutionResponse = require('./ResolutionResponse');
 const HasteMap = require('./HasteMap');
 const DeprecatedAssetMap = require('./DeprecatedAssetMap');
 
+const ERROR_BUILDING_DEP_GRAPH = 'DependencyGraphError';
+
 const defaultActivity = {
   startEvent: () => {},
   endEvent: () => {},
@@ -63,11 +65,7 @@ class DependencyGraph {
     };
     this._cache = cache;
     this._helpers = new DependencyGraphHelpers(this._opts);
-    this.load().catch((err) => {
-      // This only happens at initialization. Live errors are easier to recover from.
-      console.error('Error building DependencyGraph:\n', err.stack);
-      process.exit(1);
-    });
+    this.load();
   }
 
   load() {
@@ -134,7 +132,14 @@ class DependencyGraph {
       this._deprecatedAssetMap.build(),
     ]).then(() =>
       activity.endEvent(depGraphActivity)
-    );
+    ).catch(err => {
+      const error = new Error(
+        `Failed to build DependencyGraph: ${err.message}`
+      );
+      error.type = ERROR_BUILDING_DEP_GRAPH;
+      error.stack = err.stack;
+      throw error;
+    });
 
     return this._loading;
   }
diff --git a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
index 962bba9681d0..7ef335d9b3d2 100644
--- a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
+++ b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
@@ -10,7 +10,6 @@
 
 jest.dontMock('../')
   .dontMock('underscore')
-  .dontMock('PixelRatio')
   .dontMock('../../DependencyResolver/lib/extractRequires')
   .dontMock('../../DependencyResolver/lib/replacePatterns');
 
@@ -33,6 +32,8 @@ describe('Resolver', function() {
     path.join.mockImpl(function(a, b) {
       return b;
     });
+
+    DependencyGraph.prototype.load.mockImpl(() => Promise.resolve());
   });
 
   class ResolutionResponseMock {
diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index 1822eb9943ff..4c6e3efbd295 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -103,6 +103,11 @@ class Resolver {
     });
 
     this._polyfillModuleNames = opts.polyfillModuleNames || [];
+
+    this._depGraph.load().catch(err => {
+      console.error(err.message + '\n' + err.stack);
+      process.exit(1);
+    });
   }
 
   getShallowDependencies(entryFile) {

From c2233ef7e6cb24d673d494a37085c67ddb79c944 Mon Sep 17 00:00:00 2001
From: joranz <jordanmranz@gmail.com>
Date: Wed, 3 Feb 2016 00:21:30 -0800
Subject: [PATCH 0997/1411] Add iOS tintColor prop to TextInput

Summary:
In response to https://github.com/facebook/react-native/issues/5595

Adds tintColor property to TextInput component for iOS:

<img width="375" alt="screen shot 2016-01-28 at 1 39 35 pm" src="https://cloud.githubusercontent.com/assets/3868826/12730689/eae58a36-c8e1-11e5-9453-70716617bfab.png">

Usage:

<img width="454" alt="screen shot 2016-01-28 at 1 42 37 pm" src="https://cloud.githubusercontent.com/assets/3868826/12730711/fedeed8e-c8e1-11e5-87d0-1621d19a0418.png">
Closes https://github.com/facebook/react-native/pull/5678

Reviewed By: svcscm

Differential Revision: D2895115

Pulled By: nicklockwood

fb-gh-sync-id: bfb52b992d5e02754fe47f409f6e8df426514718
---
 Examples/UIExplorer/TextInputExample.ios.js | 19 +++++++++++++++++++
 Libraries/Components/TextInput/TextInput.js |  5 +++++
 Libraries/Text/RCTTextFieldManager.m        |  1 +
 Libraries/Text/RCTTextViewManager.m         |  1 +
 4 files changed, 26 insertions(+)

diff --git a/Examples/UIExplorer/TextInputExample.ios.js b/Examples/UIExplorer/TextInputExample.ios.js
index 49079ff8b917..905328f602b4 100644
--- a/Examples/UIExplorer/TextInputExample.ios.js
+++ b/Examples/UIExplorer/TextInputExample.ios.js
@@ -536,6 +536,25 @@ exports.examples = [
       );
     }
   },
+  {
+    title: 'Colored highlight/cursor for text input',
+    render: function() {
+      return (
+        <View>
+          <TextInput
+            style={styles.default}
+            tintColor={"green"}
+            defaultValue="Highlight me"
+          />
+          <TextInput
+            style={styles.default}
+            tintColor={"rgba(86, 76, 205, 1)"}
+            defaultValue="Highlight me"
+          />
+        </View>
+      );
+    }
+  },
   {
     title: 'Clear button mode',
     render: function () {
diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js
index 1f1aebf8be96..128f7aaa8513 100644
--- a/Libraries/Components/TextInput/TextInput.js
+++ b/Libraries/Components/TextInput/TextInput.js
@@ -226,6 +226,11 @@ var TextInput = React.createClass({
      * The text color of the placeholder string
      */
     placeholderTextColor: PropTypes.string,
+    /**
+    * The highlight and cursor color of the text input
+    * @platform ios
+    */
+    tintColor: PropTypes.string,
     /**
      * If true, the text input obscures the text entered so that sensitive text
      * like passwords stay secure. The default value is false.
diff --git a/Libraries/Text/RCTTextFieldManager.m b/Libraries/Text/RCTTextFieldManager.m
index f2ccf07f4616..b2dd5d77c1b3 100644
--- a/Libraries/Text/RCTTextFieldManager.m
+++ b/Libraries/Text/RCTTextFieldManager.m
@@ -78,6 +78,7 @@ - (BOOL)textFieldShouldEndEditing:(RCTTextField *)textField
 RCT_REMAP_VIEW_PROPERTY(editable, enabled, BOOL)
 RCT_EXPORT_VIEW_PROPERTY(placeholder, NSString)
 RCT_EXPORT_VIEW_PROPERTY(placeholderTextColor, UIColor)
+RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
 RCT_EXPORT_VIEW_PROPERTY(text, NSString)
 RCT_EXPORT_VIEW_PROPERTY(maxLength, NSNumber)
 RCT_EXPORT_VIEW_PROPERTY(clearButtonMode, UITextFieldViewMode)
diff --git a/Libraries/Text/RCTTextViewManager.m b/Libraries/Text/RCTTextViewManager.m
index f32369c4a3ce..8c0247d13ad0 100644
--- a/Libraries/Text/RCTTextViewManager.m
+++ b/Libraries/Text/RCTTextViewManager.m
@@ -28,6 +28,7 @@ - (UIView *)view
 RCT_EXPORT_VIEW_PROPERTY(blurOnSubmit, BOOL)
 RCT_EXPORT_VIEW_PROPERTY(clearTextOnFocus, BOOL)
 RCT_REMAP_VIEW_PROPERTY(color, textView.textColor, UIColor)
+RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
 RCT_REMAP_VIEW_PROPERTY(editable, textView.editable, BOOL)
 RCT_REMAP_VIEW_PROPERTY(enablesReturnKeyAutomatically, textView.enablesReturnKeyAutomatically, BOOL)
 RCT_REMAP_VIEW_PROPERTY(keyboardType, textView.keyboardType, UIKeyboardType)

From 5f4390bf0364a79804747270733f8bab33b7a5c3 Mon Sep 17 00:00:00 2001
From: Krzysztof Magiera <krzys.magiera@gmail.com>
Date: Wed, 3 Feb 2016 03:30:23 -0800
Subject: [PATCH 0998/1411] Fix bug related to removeClippedSubviews and view
 collapsing.

Summary:
The bug occurs for the cases when there is a nested view structure of at least two views with removeClippedSubvews enabled and with a "collapsable" view in between them that migrates from the collapsed state to non-collapsed state.

What happens in that case is that the "inner" view with "removeClippsedSubviews" gets reattached to a new parent, but we never update it's clipping rect because the update is currently only triggered for the size change (and for scroll change in case of scrollview). In the case when the view was doing some "clipping" when attached to its previous parent it needs to update its "clipping" status because the parent has change and clipping rect is calculated based on the parent clipping rect (see `ReactClippingViewGroupHelper#calculateClippingRect`).

This change triggers `updateClippingRect` when the view is attached to the window, which covers the case when it's reattached from one parent to the other.
Closes https://github.com/facebook/react-native/pull/5692

Reviewed By: svcscm

Differential Revision: D2893304

Pulled By: foghina

fb-gh-sync-id: a94ab3674adf9e496fc86dca5a430a91117f2c83
---
 .../views/scroll/ReactHorizontalScrollView.java      |  8 ++++++++
 .../facebook/react/views/scroll/ReactScrollView.java |  8 ++++++++
 .../facebook/react/views/view/ReactViewGroup.java    | 12 +++++++++++-
 3 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java
index c8bdc978a8ed..61735c0ea9b8 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java
@@ -146,6 +146,14 @@ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
     }
   }
 
+  @Override
+  protected void onAttachedToWindow() {
+    super.onAttachedToWindow();
+    if (mRemoveClippedSubviews) {
+      updateClippingRect();
+    }
+  }
+
   @Override
   public void updateClippingRect() {
     if (!mRemoveClippedSubviews) {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java
index a6a813db9f95..64559d1a35b5 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java
@@ -72,6 +72,14 @@ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
     }
   }
 
+  @Override
+  protected void onAttachedToWindow() {
+    super.onAttachedToWindow();
+    if (mRemoveClippedSubviews) {
+      updateClippingRect();
+    }
+  }
+
   @Override
   protected void onScrollChanged(int x, int y, int oldX, int oldY) {
     super.onScrollChanged(x, y, oldX, oldY);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
index b52399c82f3a..88ac93397859 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
@@ -353,7 +353,17 @@ private void updateSubviewClipStatus(View subview) {
   @Override
   protected void onSizeChanged(int w, int h, int oldw, int oldh) {
     super.onSizeChanged(w, h, oldw, oldh);
-    updateClippingRect();
+    if (mRemoveClippedSubviews) {
+      updateClippingRect();
+    }
+  }
+
+  @Override
+  protected void onAttachedToWindow() {
+    super.onAttachedToWindow();
+    if (mRemoveClippedSubviews) {
+      updateClippingRect();
+    }
   }
 
   @Override

From 6941c4e027abb582d7cef0e7c3b9b7ebf51bc070 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Wed, 3 Feb 2016 03:59:20 -0800
Subject: [PATCH 0999/1411] Replace `ScrollView.scrollTo()` API with something
 less ambiguous.

Summary:
public
The current `ScrollView.scrollTo()` API is confusing due to the `(y, x)` parameter order, and the boolean `animated` argument. E.g.

    ScrollView.scrollTo(5, 0, true) // what do these arguments mean?

This diff replaces the API with a configuration object, so the arguments are all explicit:

    ScrollView.scrollTo({x: 0, y: 5, animated: true}) // much better

The `scrollTo()` method checks the argument types, and provides backwards compatibility with the old argument format for now. Using the old API will generate a warning, and this will eventually be upgraded to an error.

Reviewed By: davidaurelio

Differential Revision: D2892287

fb-gh-sync-id: cec4d504242391267c6e863816b6180ced7a7d5e
---
 Examples/UIExplorer/ScrollViewExample.js      | 46 +++++++++++++------
 Libraries/Components/ScrollResponder.js       | 42 +++++++++++++----
 Libraries/Components/ScrollView/ScrollView.js | 27 +++++++++--
 3 files changed, 89 insertions(+), 26 deletions(-)

diff --git a/Examples/UIExplorer/ScrollViewExample.js b/Examples/UIExplorer/ScrollViewExample.js
index 53d19148b67f..469c9a63c113 100644
--- a/Examples/UIExplorer/ScrollViewExample.js
+++ b/Examples/UIExplorer/ScrollViewExample.js
@@ -19,6 +19,8 @@ var React = require('react-native');
 var {
   ScrollView,
   StyleSheet,
+  Text,
+  TouchableOpacity,
   View,
   Image
 } = React;
@@ -31,27 +33,45 @@ exports.examples = [
   title: '<ScrollView>',
   description: 'To make content scrollable, wrap it within a <ScrollView> component',
   render: function() {
+    var _scrollView: ScrollView;
     return (
-      <ScrollView
-        automaticallyAdjustContentInsets={false}
-        onScroll={() => { console.log('onScroll!'); }}
-        scrollEventThrottle={200}
-        style={styles.scrollView}>
-        {THUMBS.map(createThumbRow)}
-      </ScrollView>
+      <View>
+        <ScrollView
+          ref={(scrollView) => { _scrollView = scrollView; }}
+          automaticallyAdjustContentInsets={false}
+          onScroll={() => { console.log('onScroll!'); }}
+          scrollEventThrottle={200}
+          style={styles.scrollView}>
+          {THUMBS.map(createThumbRow)}
+        </ScrollView>
+        <TouchableOpacity
+          style={styles.button}
+          onPress={() => { _scrollView.scrollTo({y: 0}); }}>
+          <Text>Scroll to top</Text>
+        </TouchableOpacity>
+      </View>
     );
   }
 }, {
   title: '<ScrollView> (horizontal = true)',
   description: 'You can display <ScrollView>\'s child components horizontally rather than vertically',
   render: function() {
+    var _scrollView: ScrollView;
     return (
-      <ScrollView
-        automaticallyAdjustContentInsets={false}
-        horizontal={true}
-        style={[styles.scrollView, styles.horizontalScrollView]}>
-        {THUMBS.map(createThumbRow)}
-      </ScrollView>
+      <View>
+        <ScrollView
+          ref={(scrollView) => { _scrollView = scrollView; }}
+          automaticallyAdjustContentInsets={false}
+          horizontal={true}
+          style={[styles.scrollView, styles.horizontalScrollView]}>
+          {THUMBS.map(createThumbRow)}
+        </ScrollView>
+        <TouchableOpacity
+          style={styles.button}
+          onPress={() => { _scrollView.scrollTo({x: 0}); }}>
+          <Text>Scroll to start</Text>
+        </TouchableOpacity>
+      </View>
     );
   }
 }];
diff --git a/Libraries/Components/ScrollResponder.js b/Libraries/Components/ScrollResponder.js
index e6ef4c554a51..65531aa2fe63 100644
--- a/Libraries/Components/ScrollResponder.js
+++ b/Libraries/Components/ScrollResponder.js
@@ -349,14 +349,29 @@ var ScrollResponderMixin = {
 
   /**
    * A helper function to scroll to a specific point  in the scrollview.
-   * This is currently used to help focus on child textviews, but this
-   * can also be used to quickly scroll to any element we want to focus
+   * This is currently used to help focus on child textviews, but can also
+   * be used to quickly scroll to any element we want to focus. Syntax:
+   *
+   * scrollResponderScrollTo(options: {x: number = 0; y: number = 0; animated: boolean = true})
+   *
+   * Note: The weird argument signature is due to the fact that, for historical reasons,
+   * the function also accepts separate arguments as as alternative to the options object.
+   * This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED.
    */
-  scrollResponderScrollTo: function(offsetX: number, offsetY: number, animated: boolean = true) {
+  scrollResponderScrollTo: function(
+    x?: number | { x?: number; y?: number; animated?: boolean },
+    y?: number,
+    animated?: boolean
+  ) {
+    if (typeof x === 'number') {
+      console.warn('`scrollResponderScrollTo(x, y, animated)` is deprecated. Use `scrollResponderScrollTo({x: 5, y: 5, animated: true})` instead.');
+    } else {
+      ({x, y, animated} = x || {});
+    }
     UIManager.dispatchViewManagerCommand(
       React.findNodeHandle(this),
       UIManager.RCTScrollView.Commands.scrollTo,
-      [offsetX, offsetY, animated],
+      [x || 0, y || 0, animated !== false],
     );
   },
 
@@ -369,15 +384,24 @@ var ScrollResponderMixin = {
   },
 
   /**
-   * A helper function to zoom to a specific rect in the scrollview.
-   * @param {object} rect Should have shape {x, y, width, height}
-   * @param {bool} animated Specify whether zoom is instant or animated
+   * A helper function to zoom to a specific rect in the scrollview. The argument has the shape
+   * {x: number; y: number; width: number; height: number; animated: boolean = true}
+   *
+   * @platform ios
    */
-  scrollResponderZoomTo: function(rect: { x: number; y: number; width: number; height: number; }, animated: boolean = true) {
+  scrollResponderZoomTo: function(
+    rect: { x: number; y: number; width: number; height: number; animated?: boolean },
+    animated?: boolean // deprecated, put this inside the rect argument instead
+  ) {
     if (Platform.OS === 'android') {
       invariant('zoomToRect is not implemented');
     } else {
-      ScrollViewManager.zoomToRect(React.findNodeHandle(this), rect, animated);
+      if ('animated' in rect) {
+        var { animated, ...rect } = rect;
+      } else if (typeof animated !== 'undefined') {
+        console.warn('`scrollResponderZoomTo` `animated` argument is deprecated. Use `options.animated` instead');
+      }
+      ScrollViewManager.zoomToRect(React.findNodeHandle(this), rect, animated !== false);
     }
   },
 
diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js
index 623951b5ed08..279712808b28 100644
--- a/Libraries/Components/ScrollView/ScrollView.js
+++ b/Libraries/Components/ScrollView/ScrollView.js
@@ -359,17 +359,36 @@ var ScrollView = React.createClass({
     return React.findNodeHandle(this.refs[INNERVIEW]);
   },
 
-  scrollTo: function(destY: number = 0, destX: number = 0, animated: boolean = true) {
+  /**
+   * Scrolls to a given x, y offset, either immediately or with a smooth animation.
+   * Syntax:
+   *
+   * scrollTo(options: {x: number = 0; y: number = 0; animated: boolean = true})
+   *
+   * Note: The weird argument signature is due to the fact that, for historical reasons,
+   * the function also accepts separate arguments as as alternative to the options object.
+   * This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED.
+   */
+  scrollTo: function(
+    y?: number | { x?: number, y?: number, animated?: boolean },
+    x?: number,
+    animated?: boolean
+  ) {
+    if (typeof y === 'number') {
+      console.warn('`scrollTo(y, x, animated)` is deprecated. Use `scrollTo({x: 5, y: 5, animated: true})` instead.');
+    } else {
+      ({x, y, animated} = y || {});
+    }
     // $FlowFixMe - Don't know how to pass Mixin correctly. Postpone for now
-    this.getScrollResponder().scrollResponderScrollTo(destX, destY, animated);
+    this.getScrollResponder().scrollResponderScrollTo({x: x || 0, y: y || 0, animated: animated !== false});
   },
 
   /**
    * Deprecated, do not use.
    */
-  scrollWithoutAnimationTo: function(destY: number = 0, destX: number = 0) {
+  scrollWithoutAnimationTo: function(y: number = 0, x: number = 0) {
     console.warn('`scrollWithoutAnimationTo` is deprecated. Use `scrollTo` instead');
-    this.scrollTo(destX, destY, false);
+    this.scrollTo({x, y, animated: false});
   },
 
   handleScroll: function(e: Object) {

From ee533037f63fb378d029e58dc62c5f1d5260655f Mon Sep 17 00:00:00 2001
From: Martin Kralik <kralik@fb.com>
Date: Wed, 3 Feb 2016 05:22:11 -0800
Subject: [PATCH 1000/1411] removed unused RCTBaseEvent (1/7)

Summary:
`RCTBaseEvent` was never used. This diff removes it.

public
___
//This diff is part of a larger stack. For high level overview what's going on jump to D2884593.//

Reviewed By: javache

Differential Revision: D2884585

fb-gh-sync-id: 66a6afcda3b5baec7f768682da215570f6d33bb1
---
 .../RCTEventDispatcherTests.m                 | 26 ++++++++---
 React/Base/RCTEventDispatcher.h               |  7 ---
 React/Base/RCTEventDispatcher.m               | 46 -------------------
 3 files changed, 20 insertions(+), 59 deletions(-)

diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m
index e0406d49727f..d75f264455f2 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m
@@ -18,22 +18,36 @@
 #import <OCMock/OCMock.h>
 #import "RCTEventDispatcher.h"
 
-@interface RCTTestEvent : RCTBaseEvent
-
-@property (nonatomic, assign) BOOL canCoalesce;
-
+@interface RCTTestEvent : NSObject  <RCTEvent>
+@property (atomic, assign, readwrite) BOOL canCoalesce;
 @end
 
 @implementation RCTTestEvent
+{
+  NSDictionary<NSString *, id> *_body;
+}
+
+@synthesize viewTag = _viewTag;
+@synthesize eventName = _eventName;
+@synthesize body = _body;
+@synthesize coalescingKey = _coalescingKey;
 
 - (instancetype)initWithViewTag:(NSNumber *)viewTag eventName:(NSString *)eventName body:(NSDictionary<NSString *, id> *)body
 {
-  if (self = [super initWithViewTag:viewTag eventName:eventName body:body]) {
-    self.canCoalesce = YES;
+  if (self = [super init]) {
+    _viewTag = viewTag;
+    _eventName = eventName;
+    _body = body;
+    _canCoalesce = YES;
   }
   return self;
 }
 
+- (id<RCTEvent>)coalesceWithEvent:(id<RCTEvent>)newEvent
+{
+  return newEvent;
+}
+
 + (NSString *)moduleDotMethod
 {
   return @"RCTDeviceEventEmitter.emit";
diff --git a/React/Base/RCTEventDispatcher.h b/React/Base/RCTEventDispatcher.h
index 4cbd84fa2920..6f7e7ac07b1a 100644
--- a/React/Base/RCTEventDispatcher.h
+++ b/React/Base/RCTEventDispatcher.h
@@ -58,13 +58,6 @@ RCT_EXTERN NSString *RCTNormalizeInputEventName(NSString *eventName);
 
 @end
 
-@interface RCTBaseEvent : NSObject <RCTEvent>
-
-- (instancetype)initWithViewTag:(NSNumber *)viewTag
-                      eventName:(NSString *)eventName
-                           body:(NSDictionary *)body NS_DESIGNATED_INITIALIZER;
-
-@end
 
 /**
  * This class wraps the -[RCTBridge enqueueJSCall:args:] method, and
diff --git a/React/Base/RCTEventDispatcher.m b/React/Base/RCTEventDispatcher.m
index b0d2be661d2a..4b2df3e9c688 100644
--- a/React/Base/RCTEventDispatcher.m
+++ b/React/Base/RCTEventDispatcher.m
@@ -35,52 +35,6 @@
   );
 }
 
-@implementation RCTBaseEvent
-
-@synthesize viewTag = _viewTag;
-@synthesize eventName = _eventName;
-@synthesize body = _body;
-
-- (instancetype)initWithViewTag:(NSNumber *)viewTag
-                      eventName:(NSString *)eventName
-                           body:(NSDictionary *)body
-{
-  if (RCT_DEBUG) {
-    RCTAssertParam(eventName);
-  }
-
-  if ((self = [super init])) {
-    _viewTag = viewTag;
-    _eventName = eventName;
-    _body = body;
-  }
-  return self;
-}
-
-RCT_NOT_IMPLEMENTED(- (instancetype)init)
-
-- (uint16_t)coalescingKey
-{
-  return 0;
-}
-
-- (BOOL)canCoalesce
-{
-  return YES;
-}
-
-- (id<RCTEvent>)coalesceWithEvent:(id<RCTEvent>)newEvent
-{
-  return newEvent;
-}
-
-+ (NSString *)moduleDotMethod
-{
-  return nil;
-}
-
-@end
-
 @interface RCTEventDispatcher() <RCTFrameUpdateObserver>
 
 @end

From 3e89c3ea3b706c8d8b9dac3787c242ceaaf732e3 Mon Sep 17 00:00:00 2001
From: Martin Kralik <kralik@fb.com>
Date: Wed, 3 Feb 2016 05:22:12 -0800
Subject: [PATCH 1001/1411] removed `coalescingKey` from events (2/7)

Summary:
This property was never used, so I'm removing it.

public
___
//This diff is part of a larger stack. For high level overview what's going on jump to D2884593.//

Reviewed By: javache

Differential Revision: D2884587

fb-gh-sync-id: acd5e576cd13a02e77225f3b308232f8331d3b61
---
 .../UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m | 1 -
 React/Base/RCTEventDispatcher.h                              | 1 -
 React/Base/RCTEventDispatcher.m                              | 4 +---
 React/Views/RCTScrollView.m                                  | 5 -----
 4 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m
index d75f264455f2..4cf5c2cd760f 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m
@@ -30,7 +30,6 @@ @implementation RCTTestEvent
 @synthesize viewTag = _viewTag;
 @synthesize eventName = _eventName;
 @synthesize body = _body;
-@synthesize coalescingKey = _coalescingKey;
 
 - (instancetype)initWithViewTag:(NSNumber *)viewTag eventName:(NSString *)eventName body:(NSDictionary<NSString *, id> *)body
 {
diff --git a/React/Base/RCTEventDispatcher.h b/React/Base/RCTEventDispatcher.h
index 6f7e7ac07b1a..a6d0bd0ae780 100644
--- a/React/Base/RCTEventDispatcher.h
+++ b/React/Base/RCTEventDispatcher.h
@@ -49,7 +49,6 @@ RCT_EXTERN NSString *RCTNormalizeInputEventName(NSString *eventName);
 @property (nonatomic, strong, readonly) NSNumber *viewTag;
 @property (nonatomic, copy, readonly) NSString *eventName;
 @property (nonatomic, copy, readonly) NSDictionary *body;
-@property (nonatomic, assign, readonly) uint16_t coalescingKey;
 
 - (BOOL)canCoalesce;
 - (id<RCTEvent>)coalesceWithEvent:(id<RCTEvent>)newEvent;
diff --git a/React/Base/RCTEventDispatcher.m b/React/Base/RCTEventDispatcher.m
index 4b2df3e9c688..5681c3fed96f 100644
--- a/React/Base/RCTEventDispatcher.m
+++ b/React/Base/RCTEventDispatcher.m
@@ -30,9 +30,7 @@
 {
   return @(
     event.viewTag.intValue |
-    (((uint64_t)event.eventName.hash & 0xFFFF) << 32)  |
-    (((uint64_t)event.coalescingKey) << 48)
-  );
+    (((uint64_t)event.eventName.hash & 0xFFFF) << 32));
 }
 
 @interface RCTEventDispatcher() <RCTFrameUpdateObserver>
diff --git a/React/Views/RCTScrollView.m b/React/Views/RCTScrollView.m
index c69aabb19a2d..97ede2145aa6 100644
--- a/React/Views/RCTScrollView.m
+++ b/React/Views/RCTScrollView.m
@@ -59,11 +59,6 @@ - (instancetype)initWithType:(RCTScrollEventType)type
 
 RCT_NOT_IMPLEMENTED(- (instancetype)init)
 
-- (uint16_t)coalescingKey
-{
-  return 0;
-}
-
 - (NSDictionary *)body
 {
   NSDictionary *body = @{

From 7f2b72528eedd144e949e5a8c744ebc5c05ebbac Mon Sep 17 00:00:00 2001
From: Martin Kralik <kralik@fb.com>
Date: Wed, 3 Feb 2016 05:22:14 -0800
Subject: [PATCH 1002/1411] RCTEvent protocol changes (3/7)

Summary:
I want to use the `RCTEvent` protocol for touch events as well. That's why I'm removing not very well defined `body` property and replacing it with `arguments` method, which will return an array that will be passed directly to the js call.
I think this makes sense because there is no unified arguments format for all events and and the called  js method (`moduleDotMethod`) is already event specific.
This way touch events and scroll events can result in calling a completely different js function with a completely different arguments (what they indeed currently do).

public
___
//This diff is part of a larger stack. For high level overview what's going on jump to D2884593.//

Reviewed By: nicklockwood

Differential Revision: D2884590

fb-gh-sync-id: 2c1885c3414e255d8572c0fbbbfe62a23d94dd06
---
 .../RCTEventDispatcherTests.m                  | 18 +++++++++++-------
 React/Base/RCTEventDispatcher.h                |  4 +++-
 React/Base/RCTEventDispatcher.m                | 14 +-------------
 React/Views/RCTScrollView.m                    |  5 +++++
 4 files changed, 20 insertions(+), 21 deletions(-)

diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m
index 4cf5c2cd760f..a8ec446bfaa1 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m
@@ -29,7 +29,6 @@ @implementation RCTTestEvent
 
 @synthesize viewTag = _viewTag;
 @synthesize eventName = _eventName;
-@synthesize body = _body;
 
 - (instancetype)initWithViewTag:(NSNumber *)viewTag eventName:(NSString *)eventName body:(NSDictionary<NSString *, id> *)body
 {
@@ -52,6 +51,11 @@ + (NSString *)moduleDotMethod
   return @"RCTDeviceEventEmitter.emit";
 }
 
+- (NSArray *)arguments
+{
+  return @[_eventName, _body];
+}
+
 @end
 
 @interface RCTEventDispatcherTests : XCTestCase
@@ -89,7 +93,7 @@ - (void)setUp
 - (void)testLegacyEventsAreImmediatelyDispatched
 {
   [[_bridge expect] enqueueJSCall:_JSMethod
-                             args:@[_eventName, _body]];
+                             args:[_testEvent arguments]];
 
   [_eventDispatcher sendDeviceEventWithName:_eventName body:_body];
 
@@ -100,7 +104,7 @@ - (void)testNonCoalescingEventsAreImmediatelyDispatched
 {
   _testEvent.canCoalesce = NO;
   [[_bridge expect] enqueueJSCall:_JSMethod
-                             args:@[_eventName, _body]];
+                             args:[_testEvent arguments]];
 
   [_eventDispatcher sendEvent:_testEvent];
 
@@ -112,7 +116,7 @@ - (void)testCoalescedEventShouldBeDispatchedOnFrameUpdate
   [_eventDispatcher sendEvent:_testEvent];
 
   [[_bridge expect] enqueueJSCall:@"RCTDeviceEventEmitter.emit"
-                             args:@[_eventName, _body]];
+                             args:[_testEvent arguments]];
 
   [(id<RCTFrameUpdateObserver>)_eventDispatcher didUpdateFrame:nil];
 
@@ -129,7 +133,7 @@ - (void)testBasicCoalescingReturnsLastEvent
   [_eventDispatcher sendEvent:_testEvent];
 
   [[_bridge expect] enqueueJSCall:@"RCTDeviceEventEmitter.emit"
-                             args:@[_eventName, _body]];
+                             args:[_testEvent arguments]];
 
   [(id<RCTFrameUpdateObserver>)_eventDispatcher didUpdateFrame:nil];
 
@@ -147,10 +151,10 @@ - (void)testDifferentEventTypesDontCoalesce
   [_eventDispatcher sendEvent:_testEvent];
 
   [[_bridge expect] enqueueJSCall:@"RCTDeviceEventEmitter.emit"
-                             args:@[firstEventName, _body]];
+                             args:[firstEvent arguments]];
 
   [[_bridge expect] enqueueJSCall:@"RCTDeviceEventEmitter.emit"
-                             args:@[_eventName, _body]];
+                             args:[_testEvent arguments]];
 
   [(id<RCTFrameUpdateObserver>)_eventDispatcher didUpdateFrame:nil];
 
diff --git a/React/Base/RCTEventDispatcher.h b/React/Base/RCTEventDispatcher.h
index a6d0bd0ae780..4e4bc67e877c 100644
--- a/React/Base/RCTEventDispatcher.h
+++ b/React/Base/RCTEventDispatcher.h
@@ -48,12 +48,14 @@ RCT_EXTERN NSString *RCTNormalizeInputEventName(NSString *eventName);
 
 @property (nonatomic, strong, readonly) NSNumber *viewTag;
 @property (nonatomic, copy, readonly) NSString *eventName;
-@property (nonatomic, copy, readonly) NSDictionary *body;
 
 - (BOOL)canCoalesce;
 - (id<RCTEvent>)coalesceWithEvent:(id<RCTEvent>)newEvent;
 
+// used directly for doing a JS call
 + (NSString *)moduleDotMethod;
+// must contain only JSON compatible values
+- (NSArray *)arguments;
 
 @end
 
diff --git a/React/Base/RCTEventDispatcher.m b/React/Base/RCTEventDispatcher.m
index 5681c3fed96f..96f55e432639 100644
--- a/React/Base/RCTEventDispatcher.m
+++ b/React/Base/RCTEventDispatcher.m
@@ -159,19 +159,7 @@ - (void)sendEvent:(id<RCTEvent>)event
 
 - (void)dispatchEvent:(id<RCTEvent>)event
 {
-  NSMutableArray<id /* any JSON value */> *arguments = [NSMutableArray new];
-
-  if (event.viewTag) {
-    [arguments addObject:event.viewTag];
-  }
-
-  [arguments addObject:RCTNormalizeInputEventName(event.eventName)];
-
-  if (event.body) {
-    [arguments addObject:event.body];
-  }
-
-  [_bridge enqueueJSCall:[[event class] moduleDotMethod] args:arguments];
+  [_bridge enqueueJSCall:[[event class] moduleDotMethod] args:[event arguments]];
 }
 
 - (dispatch_queue_t)methodQueue
diff --git a/React/Views/RCTScrollView.m b/React/Views/RCTScrollView.m
index 97ede2145aa6..09c606176231 100644
--- a/React/Views/RCTScrollView.m
+++ b/React/Views/RCTScrollView.m
@@ -129,6 +129,11 @@ + (NSString *)moduleDotMethod
   return @"RCTEventEmitter.receiveEvent";
 }
 
+- (NSArray *)arguments
+{
+  return @[self.viewTag, RCTNormalizeInputEventName(self.eventName), [self body]];
+}
+
 @end
 
 /**

From 91e582941957c636f732d5aa2a12a6e7ec3334e4 Mon Sep 17 00:00:00 2001
From: Martin Kralik <kralik@fb.com>
Date: Wed, 3 Feb 2016 05:22:15 -0800
Subject: [PATCH 1003/1411] flush events queue when an event cannot be
 coalesced (4/7)

Summary:
Currently only scroll events are send through `sendEvent`, and all of them are can be coalesced. In future (further in the stack) touch events will go through there as well, but they won't support coalescing.
In order to ensure js processes touch and scroll events in the same order as they were created, we will flush the coalesced events when we encounter one that cannot be coalesced.

public
___
//This diff is part of a larger stack. For high level overview what's going on jump to D2884593.//

Reviewed By: nicklockwood

Differential Revision: D2884591

fb-gh-sync-id: a3d0e916843265ec57f16aad2f016a79764dcce8
---
 .../RCTEventDispatcherTests.m                 | 19 ++++++++++++++++++-
 React/Base/RCTEventDispatcher.h               |  8 ++++++++
 React/Base/RCTEventDispatcher.m               |  8 +++++++-
 3 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m
index a8ec446bfaa1..e34d9f29c2aa 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTEventDispatcherTests.m
@@ -114,7 +114,7 @@ - (void)testNonCoalescingEventsAreImmediatelyDispatched
 - (void)testCoalescedEventShouldBeDispatchedOnFrameUpdate
 {
   [_eventDispatcher sendEvent:_testEvent];
-
+  [_bridge verify];
   [[_bridge expect] enqueueJSCall:@"RCTDeviceEventEmitter.emit"
                              args:[_testEvent arguments]];
 
@@ -123,6 +123,23 @@ - (void)testCoalescedEventShouldBeDispatchedOnFrameUpdate
   [_bridge verify];
 }
 
+- (void)testNonCoalescingEventForcesColescedEventsToBeImmediatelyDispatched
+{
+  RCTTestEvent *nonCoalescingEvent = [[RCTTestEvent alloc] initWithViewTag:nil
+                                                                 eventName:_eventName
+                                                                      body:@{}];
+  nonCoalescingEvent.canCoalesce = NO;
+  [_eventDispatcher sendEvent:_testEvent];
+
+  [[_bridge expect] enqueueJSCall:[[_testEvent class] moduleDotMethod]
+                             args:[_testEvent arguments]];
+  [[_bridge expect] enqueueJSCall:[[nonCoalescingEvent class] moduleDotMethod]
+                             args:[nonCoalescingEvent arguments]];
+
+  [_eventDispatcher sendEvent:nonCoalescingEvent];
+  [_bridge verify];
+}
+
 - (void)testBasicCoalescingReturnsLastEvent
 {
   RCTTestEvent *ignoredEvent = [[RCTTestEvent alloc] initWithViewTag:nil
diff --git a/React/Base/RCTEventDispatcher.h b/React/Base/RCTEventDispatcher.h
index 4e4bc67e877c..4b424b2241d7 100644
--- a/React/Base/RCTEventDispatcher.h
+++ b/React/Base/RCTEventDispatcher.h
@@ -95,6 +95,14 @@ RCT_EXTERN NSString *RCTNormalizeInputEventName(NSString *eventName);
 
 /**
  * Send a pre-prepared event object.
+ * 
+ * If the event can be coalesced it is added to a pool of events that are sent at the beginning of the next js frame.
+ * Otherwise if the event cannot be coalesced we first flush the pool of coalesced events and the new event after that.
+ *
+ * Why it works this way?
+ * Making sure js gets events in the right order is crucial for correctly interpreting gestures.
+ * Unfortunately we cannot emit all events as they come. If we would do that we would have to emit scroll and touch moved event on every frame,
+ * which is too much data to transfer and process on older devices. This is especially bad when js starts lagging behind main thread.
  */
 - (void)sendEvent:(id<RCTEvent>)event;
 
diff --git a/React/Base/RCTEventDispatcher.m b/React/Base/RCTEventDispatcher.m
index 96f55e432639..2e8040e4606d 100644
--- a/React/Base/RCTEventDispatcher.m
+++ b/React/Base/RCTEventDispatcher.m
@@ -138,6 +138,7 @@ - (void)sendTextEventWithType:(RCTTextEventType)type
 - (void)sendEvent:(id<RCTEvent>)event
 {
   if (!event.canCoalesce) {
+    [self flushEventsQueue];
     [self dispatchEvent:event];
     return;
   }
@@ -168,9 +169,14 @@ - (dispatch_queue_t)methodQueue
 }
 
 - (void)didUpdateFrame:(__unused RCTFrameUpdate *)update
+{
+  [self flushEventsQueue];
+}
+
+- (void)flushEventsQueue
 {
   [_eventQueueLock lock];
-   NSDictionary *eventQueue = _eventQueue;
+  NSDictionary *eventQueue = _eventQueue;
   _eventQueue = [NSMutableDictionary new];
   self.paused = YES;
   [_eventQueueLock unlock];

From 4d83cfbc50fde20f6af2a7ea7edcc218e6a0159c Mon Sep 17 00:00:00 2001
From: Martin Kralik <kralik@fb.com>
Date: Wed, 3 Feb 2016 05:22:16 -0800
Subject: [PATCH 1004/1411] added RCTTouchEvent (5/7)

Summary:
This diff adds an implementation of `RCTEvent` protocol which represents touch events.
It's basically a copy of this code: https://github.com/facebook/react-native/blob/c14cc123d5be04f109ba2209a3393ee2ffa84149/React/Base/RCTTouchHandler.m#L194-L196
which is replaced using `RCTTouchEvent` in the next diff (D2884593).

public
___
//This diff is part of a larger stack. For high level overview what's going on jump to D2884593.//

Reviewed By: nicklockwood

Differential Revision: D2884592

fb-gh-sync-id: e35addcf15a7012f89644200a08f5856c7f57299
---
 React/Base/RCTTouchEvent.h | 23 +++++++++++++++
 React/Base/RCTTouchEvent.m | 57 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 80 insertions(+)
 create mode 100644 React/Base/RCTTouchEvent.h
 create mode 100644 React/Base/RCTTouchEvent.m

diff --git a/React/Base/RCTTouchEvent.h b/React/Base/RCTTouchEvent.h
new file mode 100644
index 000000000000..5fe3951dca7b
--- /dev/null
+++ b/React/Base/RCTTouchEvent.h
@@ -0,0 +1,23 @@
+/**
+ * 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "RCTEventDispatcher.h"
+
+/**
+ * Represents a touch event, which may be composed of several touches (one for every finger).
+ * For more information on contents of passed data structures see RCTTouchHandler.
+ */
+@interface RCTTouchEvent : NSObject <RCTEvent>
+
+- (instancetype)initWithEventName:(NSString *)eventName
+                     reactTouches:(NSArray<NSDictionary *> *)reactTouches
+                   changedIndexes:(NSArray<NSNumber *> *)changedIndexes NS_DESIGNATED_INITIALIZER;
+@end
diff --git a/React/Base/RCTTouchEvent.m b/React/Base/RCTTouchEvent.m
new file mode 100644
index 000000000000..780a7bec01ee
--- /dev/null
+++ b/React/Base/RCTTouchEvent.m
@@ -0,0 +1,57 @@
+/**
+ * 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.
+ */
+
+#import "RCTTouchEvent.h"
+
+@implementation RCTTouchEvent
+{
+  NSArray<NSDictionary *> *_reactTouches;
+  NSArray<NSNumber *> *_changedIndexes;
+}
+
+@synthesize eventName = _eventName;
+@synthesize viewTag = _viewTag;
+
+- (instancetype)initWithEventName:(NSString *)eventName
+                     reactTouches:(NSArray<NSDictionary *> *)reactTouches
+                   changedIndexes:(NSArray<NSNumber *> *)changedIndexes
+{
+  if (self = [super init]) {
+    _eventName = eventName;
+    _reactTouches = reactTouches;
+    _changedIndexes = changedIndexes;
+  }
+  return self;
+}
+
+RCT_NOT_IMPLEMENTED(- (instancetype)init)
+
+#pragma mark - RCTEvent
+
+- (BOOL)canCoalesce
+{
+  return NO;
+}
+
+- (id<RCTEvent>)coalesceWithEvent:(id<RCTEvent>)newEvent
+{
+  return newEvent;
+}
+
++ (NSString *)moduleDotMethod
+{
+  return @"RCTEventEmitter.receiveTouches";
+}
+
+- (NSArray *)arguments
+{
+  return @[RCTNormalizeInputEventName(_eventName), _reactTouches, _changedIndexes];
+}
+
+@end

From 4aaa35a22e382d79ebf6d6acb3c7d103a6613bb3 Mon Sep 17 00:00:00 2001
From: Martin Kralik <kralik@fb.com>
Date: Wed, 3 Feb 2016 05:22:17 -0800
Subject: [PATCH 1005/1411] use RCTEventDispatcher for touch events (6/7)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Summary:
This diff finally makes touch events to be emitted to js from the same object as scroll events. Thanks to changes in previous diffs this means the js will now process them in the right order.

This diff on its own would cause us to send events to js on every frame while dragging a finger on the screen. This is something we tried to avoid with event coalescing in the past, and gets fixed in the following diff D2884595.

public
___
**This diff is part of a larger stack. This is a high level overview about what’s going on here.**

This stack of diffs fixes an issue where scroll events and touch events wouldn’t be processed in the correct order on js side.
Current state of world:
* touch events are send to js immediately when they happen (this makes js respond to touches as soon as possible)
* scroll events are buffered, coalesced and send at the beginning of each js frame (coalescing helps in a case where js is busy processing for several native frames and would get all scroll event for that period afterwards)

How did I change this?
1. I’ve made touch events go through the same class every other event (scroll events included) go, RCTEventDispatcher. This gives us a single place to handle all events.
2. I’ve changed RCTEventDispatcher to flush all buffered events every time it gets a touch event before dispatching the touch. This fixes the original ordering issue.
3. I’ve made “touchMove” behave the same way as scroll events do - they are buffered and coalesced. Since “touchMove” events are fired as often as scroll events (while you drag your finger around), doing only 2. would bring back the issue buffering was fixing.
All of this together effectively still keeps the order of events right, avoids overloading js in the important case we care about. The only downside is an increased latency for “touchMove” events, since they are to longer send to js immediately.

(Even better solution would be changing the native->js event passing system to be pull based instead of push based. That way js would always request touches that has happened since the last time it has asked, which would make it get them as soon as it’s possible to process them and native could do coalescing at that point.
However this change has a much bigger scope, so I’m going with this stack of diffs for now.)

Reviewed By: nicklockwood

Differential Revision: D2884593

fb-gh-sync-id: 749a4dc6256f93fde0d8733687394b080ddd4484
---
 React/Base/RCTTouchHandler.m | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/React/Base/RCTTouchHandler.m b/React/Base/RCTTouchHandler.m
index f3050cfe9068..1727709e7610 100644
--- a/React/Base/RCTTouchHandler.m
+++ b/React/Base/RCTTouchHandler.m
@@ -15,6 +15,7 @@
 #import "RCTBridge.h"
 #import "RCTEventDispatcher.h"
 #import "RCTLog.h"
+#import "RCTTouchEvent.h"
 #import "RCTUIManager.h"
 #import "RCTUtils.h"
 #import "UIView+React.h"
@@ -23,7 +24,7 @@
 // module if we were to assume that modules and RootViews had a 1:1 relationship
 @implementation RCTTouchHandler
 {
-  __weak RCTBridge *_bridge;
+  __weak RCTEventDispatcher *_eventDispatcher;
 
   /**
    * Arrays managed in parallel tracking native touch object along with the
@@ -46,7 +47,7 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
 
   if ((self = [super initWithTarget:self action:@selector(handleGestureUpdate:)])) {
 
-    _bridge = bridge;
+    _eventDispatcher = [bridge moduleForClass:[RCTEventDispatcher class]];
     _dispatchedInitialTouches = NO;
     _nativeTouches = [NSMutableOrderedSet new];
     _reactTouches = [NSMutableArray new];
@@ -196,9 +197,10 @@ - (void)_updateAndDispatchTouches:(NSSet<UITouch *> *)touches
     [reactTouches addObject:[touch copy]];
   }
 
-  eventName = RCTNormalizeInputEventName(eventName);
-  [_bridge enqueueJSCall:@"RCTEventEmitter.receiveTouches"
-                    args:@[eventName, reactTouches, changedIndexes]];
+  RCTTouchEvent *event = [[RCTTouchEvent alloc] initWithEventName:eventName
+                                                     reactTouches:reactTouches
+                                                   changedIndexes:changedIndexes];
+  [_eventDispatcher sendEvent:event];
 }
 
 #pragma mark - Gesture Recognizer Delegate Callbacks

From 2e8eb652e10ba5d5419f277a98294faff4e46f56 Mon Sep 17 00:00:00 2001
From: Martin Kralik <kralik@fb.com>
Date: Wed, 3 Feb 2016 05:22:18 -0800
Subject: [PATCH 1006/1411] coalesce "touchMove" events (7/7)

Summary:
This is a final diff in the stack, which makes us not send a bazillion events to js after it's been busy while an user dragged his finger on a screen (resulting in ~two events per frame).
I made "touchMove" event to be coalescable, which makes us not send anything while dragging (since this makes both scroll events and touch move events coalesced and not being  send until either next js frame or the next different touch event occurs).

This change is far from perfect. The event name is a hard coded string and the coalescing works with some (reasonable) assumptions on internal structure of these touch events. Which may or may not be really true. It would be great if someone could comment on these.
I'm thinking about making the touches more strongly typed. Any thoughts on this?

public
___
//This diff is part of a larger stack. For high level overview what's going on jump to D2884593.//

Reviewed By: nicklockwood

Differential Revision: D2884595

fb-gh-sync-id: f3c2f13430679e2bf52e0c7a3689650b3acae42f
---
 React/Base/RCTTouchEvent.m | 24 ++++++++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/React/Base/RCTTouchEvent.m b/React/Base/RCTTouchEvent.m
index 780a7bec01ee..a6a97c037094 100644
--- a/React/Base/RCTTouchEvent.m
+++ b/React/Base/RCTTouchEvent.m
@@ -8,6 +8,7 @@
  */
 
 #import "RCTTouchEvent.h"
+#import "RCTAssert.h"
 
 @implementation RCTTouchEvent
 {
@@ -36,12 +37,31 @@ - (instancetype)initWithEventName:(NSString *)eventName
 
 - (BOOL)canCoalesce
 {
-  return NO;
+  return [_eventName isEqual:@"touchMove"];
 }
 
+// We coalesce only move events, while holding some assumptions that seem reasonable but there are no explicit guarantees about them.
 - (id<RCTEvent>)coalesceWithEvent:(id<RCTEvent>)newEvent
 {
-  return newEvent;
+  RCTAssert([newEvent isKindOfClass:[RCTTouchEvent class]], @"Touch event cannot be coalesced with any other type of event, such as provided %@", newEvent);
+  RCTTouchEvent *newTouchEvent = (RCTTouchEvent *)newEvent;
+  RCTAssert([_reactTouches count] == [newTouchEvent->_reactTouches count], @"Touch events have different number of touches. %@ %@", self, newEvent);
+
+  BOOL newEventIsMoreRecent = NO;
+  BOOL oldEventIsMoreRecent = NO;
+  NSInteger count = _reactTouches.count;
+  for (int i = 0; i<count; i++) {
+    NSDictionary *touch = _reactTouches[i];
+    NSDictionary *newTouch = newTouchEvent->_reactTouches[i];
+    RCTAssert([touch[@"identifier"] isEqual:newTouch[@"identifier"]], @"Touch events doesn't have touches in the same order. %@ %@", touch, newTouch);
+    if ([touch[@"timestamp"] doubleValue] > [newTouch[@"timestamp"] doubleValue]) {
+      oldEventIsMoreRecent = YES;
+    } else {
+      newEventIsMoreRecent = YES;
+    }
+  }
+  RCTAssert(!(oldEventIsMoreRecent && newEventIsMoreRecent), @"Neither touch event is exclusively more recent than the other one. %@ %@", _reactTouches, newTouchEvent->_reactTouches);
+  return newEventIsMoreRecent ? newEvent : self;
 }
 
 + (NSString *)moduleDotMethod

From 0c91931adf15fb456e72d08dca872f632661b655 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Wed, 3 Feb 2016 05:48:31 -0800
Subject: [PATCH 1007/1411] Add support for selectionColor on Android TextInput

Summary:
public
This adds support to set the highlight color on TextInput on Android.  See https://github.com/facebook/react-native/pull/5678 for the iOS implementation.

Note : We will merge these two properties with one name 'selectionColor' in a follow on diff, and may move it to a style.

Reviewed By: nicklockwood

Differential Revision: D2895253

fb-gh-sync-id: 6f2c08c812ff0028973185356a8af285f7dd7969
---
 .../UIExplorer/TextInputExample.android.js    |  5 ++++
 Examples/UIExplorer/TextInputExample.ios.js   |  4 +--
 Libraries/Components/TextInput/TextInput.js   | 10 +++----
 Libraries/Text/RCTTextFieldManager.m          |  2 +-
 Libraries/Text/RCTTextViewManager.m           |  2 +-
 .../views/text/DefaultStyleValuesUtil.java    | 28 +++++++++++--------
 .../textinput/ReactTextInputManager.java      |  9 ++++++
 7 files changed, 39 insertions(+), 21 deletions(-)

diff --git a/Examples/UIExplorer/TextInputExample.android.js b/Examples/UIExplorer/TextInputExample.android.js
index 6e628f350ae5..f3691f14ba86 100644
--- a/Examples/UIExplorer/TextInputExample.android.js
+++ b/Examples/UIExplorer/TextInputExample.android.js
@@ -322,6 +322,11 @@ exports.examples = [
               Darker backgroundColor
             </Text>
           </TextInput>
+          <TextInput
+            defaultValue="Highlight Color is red"
+            selectionColor={'red'}
+            style={styles.singleLine}>
+          </TextInput>
         </View>
       );
     }
diff --git a/Examples/UIExplorer/TextInputExample.ios.js b/Examples/UIExplorer/TextInputExample.ios.js
index 905328f602b4..49e28ffced8a 100644
--- a/Examples/UIExplorer/TextInputExample.ios.js
+++ b/Examples/UIExplorer/TextInputExample.ios.js
@@ -543,12 +543,12 @@ exports.examples = [
         <View>
           <TextInput
             style={styles.default}
-            tintColor={"green"}
+            selectionColor={"green"}
             defaultValue="Highlight me"
           />
           <TextInput
             style={styles.default}
-            tintColor={"rgba(86, 76, 205, 1)"}
+            selectionColor={"rgba(86, 76, 205, 1)"}
             defaultValue="Highlight me"
           />
         </View>
diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js
index 128f7aaa8513..e72c98cdfa93 100644
--- a/Libraries/Components/TextInput/TextInput.js
+++ b/Libraries/Components/TextInput/TextInput.js
@@ -226,16 +226,15 @@ var TextInput = React.createClass({
      * The text color of the placeholder string
      */
     placeholderTextColor: PropTypes.string,
-    /**
-    * The highlight and cursor color of the text input
-    * @platform ios
-    */
-    tintColor: PropTypes.string,
     /**
      * If true, the text input obscures the text entered so that sensitive text
      * like passwords stay secure. The default value is false.
      */
     secureTextEntry: PropTypes.bool,
+    /**
+    * The highlight (and cursor on ios) color of the text input
+    */
+    selectionColor: PropTypes.string,
     /**
      * See DocumentSelectionState.js, some state that is responsible for
      * maintaining selection information for a document
@@ -511,6 +510,7 @@ var TextInput = React.createClass({
         password={this.props.password || this.props.secureTextEntry}
         placeholder={this.props.placeholder}
         placeholderTextColor={this.props.placeholderTextColor}
+        selectionColor={this.props.selectionColor}
         text={this._getText()}
         underlineColorAndroid={this.props.underlineColorAndroid}
         children={children}
diff --git a/Libraries/Text/RCTTextFieldManager.m b/Libraries/Text/RCTTextFieldManager.m
index b2dd5d77c1b3..652639a0409f 100644
--- a/Libraries/Text/RCTTextFieldManager.m
+++ b/Libraries/Text/RCTTextFieldManager.m
@@ -78,7 +78,6 @@ - (BOOL)textFieldShouldEndEditing:(RCTTextField *)textField
 RCT_REMAP_VIEW_PROPERTY(editable, enabled, BOOL)
 RCT_EXPORT_VIEW_PROPERTY(placeholder, NSString)
 RCT_EXPORT_VIEW_PROPERTY(placeholderTextColor, UIColor)
-RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
 RCT_EXPORT_VIEW_PROPERTY(text, NSString)
 RCT_EXPORT_VIEW_PROPERTY(maxLength, NSNumber)
 RCT_EXPORT_VIEW_PROPERTY(clearButtonMode, UITextFieldViewMode)
@@ -95,6 +94,7 @@ - (BOOL)textFieldShouldEndEditing:(RCTTextField *)textField
 RCT_REMAP_VIEW_PROPERTY(color, textColor, UIColor)
 RCT_REMAP_VIEW_PROPERTY(autoCapitalize, autocapitalizationType, UITextAutocapitalizationType)
 RCT_REMAP_VIEW_PROPERTY(textAlign, textAlignment, NSTextAlignment)
+RCT_REMAP_VIEW_PROPERTY(selectionColor, tintColor, UIColor)
 RCT_CUSTOM_VIEW_PROPERTY(fontSize, CGFloat, RCTTextField)
 {
   view.font = [RCTConvert UIFont:view.font withSize:json ?: @(defaultView.font.pointSize)];
diff --git a/Libraries/Text/RCTTextViewManager.m b/Libraries/Text/RCTTextViewManager.m
index 8c0247d13ad0..791e5f89447d 100644
--- a/Libraries/Text/RCTTextViewManager.m
+++ b/Libraries/Text/RCTTextViewManager.m
@@ -28,7 +28,6 @@ - (UIView *)view
 RCT_EXPORT_VIEW_PROPERTY(blurOnSubmit, BOOL)
 RCT_EXPORT_VIEW_PROPERTY(clearTextOnFocus, BOOL)
 RCT_REMAP_VIEW_PROPERTY(color, textView.textColor, UIColor)
-RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
 RCT_REMAP_VIEW_PROPERTY(editable, textView.editable, BOOL)
 RCT_REMAP_VIEW_PROPERTY(enablesReturnKeyAutomatically, textView.enablesReturnKeyAutomatically, BOOL)
 RCT_REMAP_VIEW_PROPERTY(keyboardType, textView.keyboardType, UIKeyboardType)
@@ -39,6 +38,7 @@ - (UIView *)view
 RCT_EXPORT_VIEW_PROPERTY(placeholderTextColor, UIColor)
 RCT_REMAP_VIEW_PROPERTY(returnKeyType, textView.returnKeyType, UIReturnKeyType)
 RCT_REMAP_VIEW_PROPERTY(secureTextEntry, textView.secureTextEntry, BOOL)
+RCT_REMAP_VIEW_PROPERTY(selectionColor, tintColor, UIColor)
 RCT_EXPORT_VIEW_PROPERTY(selectTextOnFocus, BOOL)
 RCT_EXPORT_VIEW_PROPERTY(text, NSString)
 RCT_CUSTOM_VIEW_PROPERTY(fontSize, CGFloat, RCTTextView)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/DefaultStyleValuesUtil.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/DefaultStyleValuesUtil.java
index 78aa65a3d1e9..51edb5a32c87 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/DefaultStyleValuesUtil.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/DefaultStyleValuesUtil.java
@@ -30,17 +30,7 @@ private DefaultStyleValuesUtil() {
    * @return The ColorStateList for the hint text as defined in the style
    */
   public static ColorStateList getDefaultTextColorHint(Context context) {
-    Resources.Theme theme = context.getTheme();
-    TypedArray textAppearances = null;
-    try {
-      textAppearances = theme.obtainStyledAttributes(new int[]{android.R.attr.textColorHint});
-      ColorStateList textColorHint = textAppearances.getColorStateList(0);
-      return textColorHint;
-    } finally {
-      if (textAppearances != null) {
-        textAppearances.recycle();
-      }
-    }
+    return getDefaultTextAttribute(context, android.R.attr.textColorHint);
   }
 
   /**
@@ -50,10 +40,24 @@ public static ColorStateList getDefaultTextColorHint(Context context) {
    * @return The ColorStateList for the text as defined in the style
    */
   public static ColorStateList getDefaultTextColor(Context context) {
+    return getDefaultTextAttribute(context, android.R.attr.textColor);
+  }
+
+  /**
+   * Utility method that returns the default text highlight color as define by the theme
+   *
+   * @param context The Context
+   * @return The int for the highlight color as defined in the style
+   */
+  public static int getDefaultTextColorHighlight(Context context) {
+    return getDefaultTextAttribute(context, android.R.attr.textColorHighlight).getDefaultColor();
+  }
+
+  private static ColorStateList getDefaultTextAttribute(Context context, int attribute) {
     Resources.Theme theme = context.getTheme();
     TypedArray textAppearances = null;
     try {
-      textAppearances = theme.obtainStyledAttributes(new int[]{android.R.attr.textColor});
+      textAppearances = theme.obtainStyledAttributes(new int[]{attribute});
       ColorStateList textColor = textAppearances.getColorStateList(0);
       return textColor;
     } finally {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
index 043a3683370a..f3473a05f678 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
@@ -196,6 +196,15 @@ public void setPlaceholderTextColor(ReactEditText view, @Nullable Integer color)
     }
   }
 
+  @ReactProp(name = "selectionColor", customType = "Color")
+  public void setSelectionColor(ReactEditText view, @Nullable Integer color) {
+    if (color == null) {
+      view.setHighlightColor(DefaultStyleValuesUtil.getDefaultTextColorHighlight(view.getContext()));
+    } else {
+      view.setHighlightColor(color);
+    }
+  }
+
   @ReactProp(name = "underlineColorAndroid", customType = "Color")
   public void setUnderlineColor(ReactEditText view, @Nullable Integer underlineColor) {
     if (underlineColor == null) {

From b979128c54ea8f1eba2f2d570e374a1f50c5abfc Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Wed, 3 Feb 2016 06:40:39 -0800
Subject: [PATCH 1008/1411] Cross platform status bar API

Summary:
I started working on improving the `StatusBar` API and make it work on Android. I added support for `setColor`, `setTranslucent` (the status bar is still visible but the app can draw under) and `setHidden` on Android. Looking for feedback on how to improve the API before I put more time on this :).

Right now I went for a cross platform API and functions that don't exist on a platform are just a no-op but I'm not sure it is the best choice since at the moment what is supported is very different between both platforms. I was wondering what you guys think and if it would be better off as 2 different modules.

It is also possible to port some of the features I added for Android to iOS even if there is no 'standard' way to do it. Like `setColor` could be implemented by drawing a colored view under the status bar and translucent by adding/removing some padding.
Closes https://github.com/facebook/react-native/pull/5360

Reviewed By: svcscm

Differential Revision: D2840417

Pulled By: nicklockwood

fb-gh-sync-id: 5c8d988bccf8035341f0efe27e54dd8402c18d24
---
 Examples/UIExplorer/StatusBarExample.js       | 206 ++++++++++++++++++
 Examples/UIExplorer/UIExplorerApp.android.js  |   4 +
 Examples/UIExplorer/UIExplorerApp.ios.js      |  34 +--
 Examples/UIExplorer/UIExplorerList.android.js |   1 +
 Examples/UIExplorer/UIExplorerList.ios.js     |   1 +
 Libraries/Components/StatusBar/StatusBar.js   | 194 +++++++++++++++++
 Libraries/react-native/react-native.js        |   1 +
 Libraries/react-native/react-native.js.flow   |   1 +
 .../com/facebook/react/bridge/Promise.java    |   4 +-
 .../com/facebook/react/modules/statusbar/BUCK |  20 ++
 .../modules/statusbar/StatusBarModule.java    | 132 +++++++++++
 .../main/java/com/facebook/react/shell/BUCK   |   1 +
 .../react/shell/MainReactPackage.java         |   5 +-
 website/server/extractDocs.js                 |   1 +
 14 files changed, 588 insertions(+), 17 deletions(-)
 create mode 100644 Examples/UIExplorer/StatusBarExample.js
 create mode 100644 Libraries/Components/StatusBar/StatusBar.js
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.java

diff --git a/Examples/UIExplorer/StatusBarExample.js b/Examples/UIExplorer/StatusBarExample.js
new file mode 100644
index 000000000000..094148c4d71d
--- /dev/null
+++ b/Examples/UIExplorer/StatusBarExample.js
@@ -0,0 +1,206 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ *
+ * @flow
+ */
+'use strict';
+
+const React = require('react-native');
+const {
+  StyleSheet,
+  View,
+  Text,
+  TouchableHighlight,
+  StatusBar,
+} = React;
+
+type BarStyle = 'default' | 'light-content';
+type ShowHideTransition = 'fade' | 'slide';
+
+type State = {
+  animated: boolean,
+  backgroundColor: string,
+  hidden?: boolean,
+  showHideTransition: ShowHideTransition,
+  translucent?: boolean,
+  barStyle?: BarStyle,
+  networkActivityIndicatorVisible?: boolean
+};
+
+exports.framework = 'React';
+exports.title = '<StatusBar>';
+exports.description = 'Component for controlling the status bar';
+
+const colors = [
+  '#ff0000',
+  '#00ff00',
+  '#0000ff',
+];
+
+const barStyles = [
+  'default',
+  'light-content',
+];
+
+const showHideTransitions = [
+  'fade',
+  'slide',
+];
+
+const StatusBarExample = React.createClass({
+  getInitialState(): State {
+    return {
+      animated: true,
+      backgroundColor: this._getValue(colors, 0),
+      showHideTransition: this._getValue(showHideTransitions, 0),
+    };
+  },
+
+  _colorIndex: 0,
+  _barStyleIndex: 0,
+  _showHideTransitionIndex: 0,
+
+  _getValue(values: Array<any>, index: number): any {
+    return values[index % values.length];
+  },
+
+  render() {
+    return (
+      <View>
+        <StatusBar
+          backgroundColor={this.state.backgroundColor}
+          translucent={this.state.translucent}
+          hidden={this.state.hidden}
+          showHideTransition={this.state.showHideTransition}
+          animated={this.state.animated}
+          barStyle={this.state.barStyle}
+          networkActivityIndicatorVisible={this.state.networkActivityIndicatorVisible}
+        />
+        <View>
+          <TouchableHighlight
+            style={styles.wrapper}
+            onPress={() => this.setState({animated: !this.state.animated})}>
+            <View style={styles.button}>
+              <Text>animated: {this.state.animated ? 'true' : 'false'}</Text>
+            </View>
+          </TouchableHighlight>
+        </View>
+        <View>
+          <TouchableHighlight
+            style={styles.wrapper}
+            onPress={() => this.setState({hidden: !this.state.hidden})}>
+            <View style={styles.button}>
+              <Text>hidden: {this.state.hidden ? 'true' : 'false'}</Text>
+            </View>
+          </TouchableHighlight>
+        </View>
+        <Text style={styles.title}>iOS</Text>
+        <View>
+          <TouchableHighlight
+            style={styles.wrapper}
+            onPress={() => {
+              this._barStyleIndex++;
+              this.setState({barStyle: this._getValue(barStyles, this._barStyleIndex)});
+            }}>
+            <View style={styles.button}>
+              <Text>style: '{this._getValue(barStyles, this._barStyleIndex)}'</Text>
+            </View>
+          </TouchableHighlight>
+        </View>
+        <View>
+          <TouchableHighlight
+            style={styles.wrapper}
+            onPress={() => this.setState({
+              networkActivityIndicatorVisible: !this.state.networkActivityIndicatorVisible,
+            })}>
+            <View style={styles.button}>
+              <Text>
+                networkActivityIndicatorVisible:
+                {this.state.networkActivityIndicatorVisible ? 'true' : 'false'}
+              </Text>
+            </View>
+          </TouchableHighlight>
+        </View>
+        <View>
+          <TouchableHighlight
+            style={styles.wrapper}
+            onPress={() => {
+              this._showHideTransitionIndex++;
+              this.setState({
+                showHideTransition:
+                this._getValue(showHideTransitions, this._showHideTransitionIndex),
+              });
+            }}>
+            <View style={styles.button}>
+              <Text>
+                showHideTransition:
+                '{this._getValue(showHideTransitions, this._showHideTransitionIndex)}'
+              </Text>
+            </View>
+          </TouchableHighlight>
+        </View>
+        <Text style={styles.title}>Android</Text>
+        <View>
+          <TouchableHighlight
+            style={styles.wrapper}
+            onPress={() => {
+              this._colorIndex++;
+              this.setState({backgroundColor: this._getValue(colors, this._colorIndex)});
+            }}>
+            <View style={styles.button}>
+              <Text>backgroundColor: '{this._getValue(colors, this._colorIndex)}'</Text>
+            </View>
+          </TouchableHighlight>
+        </View>
+        <View>
+          <TouchableHighlight
+            style={styles.wrapper}
+            onPress={() => {
+              this.setState({
+                translucent: !this.state.translucent,
+                backgroundColor: !this.state.translucent ? 'rgba(0, 0, 0, 0.4)' : 'black',
+              });
+            }}>
+            <View style={styles.button}>
+              <Text>translucent: {this.state.translucent ? 'true' : 'false'}</Text>
+            </View>
+          </TouchableHighlight>
+        </View>
+      </View>
+    );
+  },
+});
+
+exports.examples = [{
+  title: 'Status Bar',
+  render() {
+    return <StatusBarExample />;
+  },
+}];
+
+var styles = StyleSheet.create({
+  wrapper: {
+    borderRadius: 5,
+    marginBottom: 5,
+  },
+  button: {
+    borderRadius: 5,
+    backgroundColor: '#eeeeee',
+    padding: 10,
+  },
+  title: {
+    marginTop: 16,
+    marginBottom: 8,
+    fontWeight: 'bold',
+  }
+});
diff --git a/Examples/UIExplorer/UIExplorerApp.android.js b/Examples/UIExplorer/UIExplorerApp.android.js
index c9bd2418fe44..25a4745bf115 100644
--- a/Examples/UIExplorer/UIExplorerApp.android.js
+++ b/Examples/UIExplorer/UIExplorerApp.android.js
@@ -25,6 +25,7 @@ var {
   StyleSheet,
   ToolbarAndroid,
   View,
+  StatusBar,
 } = React;
 var UIExplorerList = require('./UIExplorerList.android');
 
@@ -98,6 +99,9 @@ var UIExplorerApp = React.createClass({
     var Component = this.state.example.component;
     return (
       <View style={styles.container}>
+        <StatusBar
+          backgroundColor="#589c90"
+        />
         <ToolbarAndroid
           logo={require('image!launcher_icon')}
           navIcon={require('image!ic_menu_black_24dp')}
diff --git a/Examples/UIExplorer/UIExplorerApp.ios.js b/Examples/UIExplorer/UIExplorerApp.ios.js
index c8c4a834f1fc..f93cc2a66a64 100644
--- a/Examples/UIExplorer/UIExplorerApp.ios.js
+++ b/Examples/UIExplorer/UIExplorerApp.ios.js
@@ -24,7 +24,8 @@ var {
   StyleSheet,
   Text,
   TouchableHighlight,
-  View
+  View,
+  StatusBar,
 } = React;
 
 var UIExplorerApp = React.createClass({
@@ -48,20 +49,23 @@ var UIExplorerApp = React.createClass({
     }
 
     return (
-      <NavigatorIOS
-        style={styles.container}
-        initialRoute={{
-          title: 'UIExplorer',
-          component: UIExplorerList,
-          passProps: {
-            onExternalExampleRequested: (example) => {
-              this.setState({ openExternalExample: example, });
-            },
-          }
-        }}
-        itemWrapperStyle={styles.itemWrapper}
-        tintColor="#008888"
-      />
+      <View style={{flex: 1}}>
+        <StatusBar barStyle="default" />
+        <NavigatorIOS
+          style={styles.container}
+          initialRoute={{
+            title: 'UIExplorer',
+            component: UIExplorerList,
+            passProps: {
+              onExternalExampleRequested: (example) => {
+                this.setState({ openExternalExample: example, });
+              },
+            }
+          }}
+          itemWrapperStyle={styles.itemWrapper}
+          tintColor="#008888"
+        />
+      </View>
     );
   }
 });
diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index 367b256de49f..ed84e62aad11 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -30,6 +30,7 @@ var COMPONENTS = [
   require('./PullToRefreshViewAndroidExample.android'),
   require('./RefreshControlExample'),
   require('./ScrollViewSimpleExample'),
+  require('./StatusBarExample'),
   require('./SwitchExample'),
   require('./TextExample.android'),
   require('./TextInputExample.android'),
diff --git a/Examples/UIExplorer/UIExplorerList.ios.js b/Examples/UIExplorer/UIExplorerList.ios.js
index 3fa57d818bfb..1cd0eaaaf0b5 100644
--- a/Examples/UIExplorer/UIExplorerList.ios.js
+++ b/Examples/UIExplorer/UIExplorerList.ios.js
@@ -46,6 +46,7 @@ var COMPONENTS = [
   require('./ScrollViewExample'),
   require('./SegmentedControlIOSExample'),
   require('./SliderIOSExample'),
+  require('./StatusBarExample'),
   require('./SwitchExample'),
   require('./TabBarIOSExample'),
   require('./TextExample.ios'),
diff --git a/Libraries/Components/StatusBar/StatusBar.js b/Libraries/Components/StatusBar/StatusBar.js
new file mode 100644
index 000000000000..b6571146af68
--- /dev/null
+++ b/Libraries/Components/StatusBar/StatusBar.js
@@ -0,0 +1,194 @@
+/**
+ * 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 StatusBar
+ * @flow
+ */
+'use strict';
+
+const React = require('React');
+const ColorPropType = require('ColorPropType');
+const Platform = require('Platform');
+
+const processColor = require('processColor');
+
+const StatusBarManager = require('NativeModules').StatusBarManager;
+
+type DefaultProps = {
+  animated: boolean;
+};
+
+/**
+ * Merges the prop stack with the default values.
+ */
+function mergePropsStack(propsStack: Array<Object>): Object {
+  return propsStack.reduce((prev, cur) => {
+    return Object.assign(prev, cur);
+  }, {
+    backgroundColor: 'black',
+    barStyle: 'default',
+    translucent: false,
+    hidden: false,
+    networkActivityIndicatorVisible: false,
+  });
+}
+
+/**
+ * Component to control the app status bar.
+ *
+ * ### Usage with Navigator
+ *
+ * It is possible to have multiple `StatusBar` components mounted at the same
+ * time. The props will be merged in the order the `StatusBar` components were
+ * mounted. One use case is to specify status bar styles per route using `Navigator`.
+ *
+ * ```
+ *  <View>
+ *    <StatusBar
+ *      backgroundColor="blue"
+ *      barStyle="light-content"
+ *    />
+ *    <Navigator
+ *      initialRoute={{statusBarHidden: true}}
+ *      renderScene={(route, navigator) =>
+ *        <View>
+ *          <StatusBar hidden={route.statusBarHidden} />
+ *          ...
+ *        </View>
+ *      }
+ *    />
+ *  </View>
+ * ```
+ */
+const StatusBar = React.createClass({
+  statics: {
+    _propsStack: [],
+  },
+
+  propTypes: {
+    /**
+     * If the status bar is hidden.
+     */
+    hidden: React.PropTypes.bool,
+    /**
+     * If the transition between status bar property changes should be animated.
+     * Supported for backgroundColor, barStyle and hidden.
+     */
+    animated: React.PropTypes.bool,
+    /**
+     * The background color of the status bar.
+     * @platform android
+     */
+    backgroundColor: ColorPropType,
+    /**
+     * If the status bar is translucent.
+     * When translucent is set to true, the app will draw under the status bar.
+     * This is useful when using a semi transparent status bar color.
+     *
+     * @platform android
+     */
+    translucent: React.PropTypes.bool,
+    /**
+     * Sets the color of the status bar text.
+     *
+     * @platform ios
+     */
+    barStyle: React.PropTypes.oneOf([
+      'default',
+      'light-content',
+    ]),
+    /**
+     * If the network activity indicator should be visible.
+     *
+     * @platform ios
+     */
+    networkActivityIndicatorVisible: React.PropTypes.bool,
+    /**
+     * The transition effect when showing and hiding the status bar using the `hidden`
+     * prop. Defaults to 'fade'.
+     *
+     * @platform ios
+     */
+    showHideTransition: React.PropTypes.oneOf([
+      'fade',
+      'slide',
+    ]),
+  },
+
+  getDefaultProps(): DefaultProps {
+    return {
+      animated: false,
+      showHideTransition: 'fade',
+    };
+  },
+
+  componentDidMount() {
+    // Every time a StatusBar component is mounted, we push it's prop to a stack
+    // and always update the native status bar with the props from the top of then
+    // stack. This allows having multiple StatusBar components and the one that is
+    // added last or is deeper in the view hierachy will have priority.
+    StatusBar._propsStack.push(this.props);
+    this._updatePropsStack();
+  },
+
+  componentWillUnmount() {
+    // When a StatusBar is unmounted, remove itself from the stack and update
+    // the native bar with the next props.
+    const index = StatusBar._propsStack.indexOf(this.props);
+    StatusBar._propsStack.splice(index, 1);
+
+    this._updatePropsStack();
+  },
+
+  componentDidUpdate(oldProps: Object) {
+    const index = StatusBar._propsStack.indexOf(oldProps);
+    StatusBar._propsStack[index] = this.props;
+
+    this._updatePropsStack();
+  },
+
+  /**
+   * Updates the native status bar with the props from the stack.
+   */
+  _updatePropsStack() {
+    const mergedProps = mergePropsStack(StatusBar._propsStack);
+
+    if (Platform.OS === 'ios') {
+      if (mergedProps.barStyle !== undefined) {
+        StatusBarManager.setStyle(mergedProps.barStyle, this.props.animated);
+      }
+      if (mergedProps.hidden !== undefined) {
+        StatusBarManager.setHidden(
+          mergedProps.hidden,
+          this.props.animated ? this.props.showHideTransition : 'none'
+        );
+      }
+      if (mergedProps.networkActivityIndicatorVisible !== undefined) {
+        StatusBarManager.setNetworkActivityIndicatorVisible(
+          mergedProps.networkActivityIndicatorVisible
+        );
+      }
+    } else if (Platform.OS === 'android') {
+      if (mergedProps.backgroundColor !== undefined) {
+        StatusBarManager.setColor(processColor(mergedProps.backgroundColor), this.props.animated);
+      }
+      if (mergedProps.hidden !== undefined) {
+        StatusBarManager.setHidden(mergedProps.hidden);
+      }
+      if (mergedProps.translucent !== undefined) {
+        StatusBarManager.setTranslucent(mergedProps.translucent);
+      }
+    }
+  },
+
+  render(): ?ReactElement {
+    return null;
+  },
+});
+
+module.exports = StatusBar;
diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js
index 6efc9af3c74d..79a4ec0d5a8a 100644
--- a/Libraries/react-native/react-native.js
+++ b/Libraries/react-native/react-native.js
@@ -37,6 +37,7 @@ var ReactNative = {
   get PullToRefreshViewAndroid() { return require('PullToRefreshViewAndroid'); },
   get RecyclerViewBackedScrollView() { return require('RecyclerViewBackedScrollView'); },
   get RefreshControl() { return require('RefreshControl'); },
+  get StatusBar() { return require('StatusBar'); },
   get SwitchAndroid() { return require('SwitchAndroid'); },
   get SwitchIOS() { return require('SwitchIOS'); },
   get TabBarIOS() { return require('TabBarIOS'); },
diff --git a/Libraries/react-native/react-native.js.flow b/Libraries/react-native/react-native.js.flow
index a0c20f5e0677..6b4f333c03d2 100644
--- a/Libraries/react-native/react-native.js.flow
+++ b/Libraries/react-native/react-native.js.flow
@@ -45,6 +45,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
   SegmentedControlIOS: require('SegmentedControlIOS'),
   SliderIOS: require('SliderIOS'),
   SnapshotViewIOS: require('SnapshotViewIOS'),
+  StatusBar: require('StatusBar'),
   Switch: require('Switch'),
   PullToRefreshViewAndroid: require('PullToRefreshViewAndroid'),
   RecyclerViewBackedScrollView: require('RecyclerViewBackedScrollView'),
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/Promise.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/Promise.java
index 87a9b4b53511..db192da980fa 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/Promise.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/Promise.java
@@ -9,6 +9,8 @@
 
 package com.facebook.react.bridge;
 
+import javax.annotation.Nullable;
+
 /**
  * Interface that represents a JavaScript Promise which can be passed to the native module as a
  * method parameter.
@@ -21,7 +23,7 @@ public interface Promise {
   /**
    * Successfully resolve the Promise.
    */
-  void resolve(Object value);
+  void resolve(@Nullable Object value);
 
   /**
    * Report an error which wasn't caused by an exception.
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/BUCK
new file mode 100644
index 000000000000..3cedd2172b69
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/BUCK
@@ -0,0 +1,20 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'statusbar',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_dep('third-party/android/support/v4:lib-support-v4'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':statusbar',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.java
new file mode 100644
index 000000000000..ed905797a539
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.java
@@ -0,0 +1,132 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ * All rights reserved.
+ * <p/>
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+
+package com.facebook.react.modules.statusbar;
+
+import android.animation.ArgbEvaluator;
+import android.animation.ValueAnimator;
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.os.Build;
+import android.support.v4.view.ViewCompat;
+import android.view.View;
+
+import com.facebook.react.bridge.Promise;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.bridge.UiThreadUtil;
+
+public class StatusBarModule extends ReactContextBaseJavaModule {
+
+  private static final String ERROR_NO_ACTIVITY =
+    "Tried to change the status bar while not attached to an Activity";
+
+  private int mWindowFlags = 0;
+
+  public StatusBarModule(ReactApplicationContext reactContext) {
+    super(reactContext);
+  }
+
+  @Override
+  public String getName() {
+    return "StatusBarManager";
+  }
+
+  @ReactMethod
+  public void setColor(final int color, final boolean animated, final Promise res) {
+    final Activity activity = getCurrentActivity();
+    if (activity == null) {
+      res.reject(ERROR_NO_ACTIVITY);
+      return;
+    }
+
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+      UiThreadUtil.runOnUiThread(
+        new Runnable() {
+          @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+          @Override
+          public void run() {
+            if (animated) {
+              int curColor = activity.getWindow().getStatusBarColor();
+              ValueAnimator colorAnimation = ValueAnimator.ofObject(
+                new ArgbEvaluator(), curColor, color);
+
+              colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator animator) {
+                  activity.getWindow().setStatusBarColor((Integer) animator.getAnimatedValue());
+                }
+              });
+              colorAnimation
+                .setDuration(300)
+                .setStartDelay(0);
+              colorAnimation.start();
+            } else {
+              activity.getWindow().setStatusBarColor(color);
+            }
+            res.resolve(null);
+          }
+        }
+      );
+    } else {
+      res.resolve(null);
+    }
+  }
+
+  @ReactMethod
+  public void setTranslucent(final boolean translucent, final Promise res) {
+    final Activity activity = getCurrentActivity();
+    if (activity == null) {
+      res.reject(ERROR_NO_ACTIVITY);
+      return;
+    }
+    UiThreadUtil.runOnUiThread(
+      new Runnable() {
+        @Override
+        public void run() {
+          if (translucent) {
+            mWindowFlags |=
+              View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+          } else {
+            mWindowFlags &=
+              ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
+          }
+          activity.getWindow().getDecorView().setSystemUiVisibility(mWindowFlags);
+          ViewCompat.requestApplyInsets(activity.getWindow().getDecorView());
+          res.resolve(null);
+        }
+      }
+    );
+  }
+
+  @ReactMethod
+  public void setHidden(final boolean hidden, final Promise res) {
+    final Activity activity = getCurrentActivity();
+    if (activity == null) {
+      res.reject(ERROR_NO_ACTIVITY);
+      return;
+    }
+    UiThreadUtil.runOnUiThread(
+      new Runnable() {
+        @Override
+        public void run() {
+          if (hidden) {
+            mWindowFlags |= View.SYSTEM_UI_FLAG_FULLSCREEN;
+          } else {
+            mWindowFlags &= ~View.SYSTEM_UI_FLAG_FULLSCREEN;
+          }
+          activity.getWindow().getDecorView().setSystemUiVisibility(mWindowFlags);
+          res.resolve(null);
+        }
+      }
+    );
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK
index 8af3f1421e67..88b94ebdaae3 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK
+++ b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK
@@ -36,6 +36,7 @@ android_library(
     react_native_target('java/com/facebook/react/modules/location:location'),
     react_native_target('java/com/facebook/react/modules/netinfo:netinfo'),
     react_native_target('java/com/facebook/react/modules/network:network'),
+    react_native_target('java/com/facebook/react/modules/statusbar:statusbar'),
     react_native_target('java/com/facebook/react/modules/storage:storage'),
     react_native_target('java/com/facebook/react/modules/timepicker:timepicker'),
     react_native_target('java/com/facebook/react/modules/toast:toast'),
diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
index 9933b41d517c..d3ec2880ff71 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
@@ -29,6 +29,7 @@
 import com.facebook.react.modules.location.LocationModule;
 import com.facebook.react.modules.netinfo.NetInfoModule;
 import com.facebook.react.modules.network.NetworkingModule;
+import com.facebook.react.modules.statusbar.StatusBarModule;
 import com.facebook.react.modules.storage.AsyncStorageModule;
 import com.facebook.react.modules.timepicker.TimePickerDialogModule;
 import com.facebook.react.modules.toast.ToastModule;
@@ -77,9 +78,11 @@ public List<NativeModule> createNativeModules(ReactApplicationContext reactConte
       new LocationModule(reactContext),
       new NetworkingModule(reactContext),
       new NetInfoModule(reactContext),
+      new StatusBarModule(reactContext),
       new TimePickerDialogModule(reactContext),
       new ToastModule(reactContext),
-      new WebSocketModule(reactContext));
+      new WebSocketModule(reactContext)
+    );
   }
 
   @Override
diff --git a/website/server/extractDocs.js b/website/server/extractDocs.js
index 29d6a9878bfc..8d8abba0be96 100644
--- a/website/server/extractDocs.js
+++ b/website/server/extractDocs.js
@@ -208,6 +208,7 @@ var components = [
   '../Libraries/Components/ScrollView/ScrollView.js',
   '../Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js',
   '../Libraries/Components/SliderIOS/SliderIOS.ios.js',
+  '../Libraries/Components/StatusBar/StatusBar.js',
   '../Libraries/Components/Switch/Switch.js',
   '../Libraries/Components/TabBarIOS/TabBarIOS.ios.js',
   '../Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js',

From fff46884230b95a14f84893725df091d6ea09662 Mon Sep 17 00:00:00 2001
From: Martin Kralik <kralik@fb.com>
Date: Wed, 3 Feb 2016 07:09:55 -0800
Subject: [PATCH 1009/1411] fix UIExplorer project

Summary:
I forgot to add new files manually to `React.xcodeproj` (it's not managed by buck).

public

Reviewed By: javache

Differential Revision: D2895546

fb-gh-sync-id: ed58e3505c269f5ed9433e94994471485adb2378
---
 React/React.xcodeproj/project.pbxproj | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj
index 3a9f0334a55b..40147b76de6f 100644
--- a/React/React.xcodeproj/project.pbxproj
+++ b/React/React.xcodeproj/project.pbxproj
@@ -72,6 +72,7 @@
 		14F7A0F01BDA714B003C6C10 /* RCTFPSGraph.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F7A0EF1BDA714B003C6C10 /* RCTFPSGraph.m */; };
 		191E3EBE1C29D9AF00C180A6 /* RCTRefreshControlManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 191E3EBD1C29D9AF00C180A6 /* RCTRefreshControlManager.m */; };
 		191E3EC11C29DC3800C180A6 /* RCTRefreshControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 191E3EC01C29DC3800C180A6 /* RCTRefreshControl.m */; };
+		391E86A41C623EC800009732 /* RCTTouchEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 391E86A21C623EC800009732 /* RCTTouchEvent.m */; };
 		58114A161AAE854800E7D092 /* RCTPicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A131AAE854800E7D092 /* RCTPicker.m */; };
 		58114A171AAE854800E7D092 /* RCTPickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A151AAE854800E7D092 /* RCTPickerManager.m */; };
 		58114A501AAE93D500E7D092 /* RCTAsyncLocalStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 58114A4E1AAE93D500E7D092 /* RCTAsyncLocalStorage.m */; };
@@ -248,6 +249,8 @@
 		191E3EBD1C29D9AF00C180A6 /* RCTRefreshControlManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRefreshControlManager.m; sourceTree = "<group>"; };
 		191E3EBF1C29DC3800C180A6 /* RCTRefreshControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRefreshControl.h; sourceTree = "<group>"; };
 		191E3EC01C29DC3800C180A6 /* RCTRefreshControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRefreshControl.m; sourceTree = "<group>"; };
+		391E86A21C623EC800009732 /* RCTTouchEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTouchEvent.m; sourceTree = "<group>"; };
+		391E86A31C623EC800009732 /* RCTTouchEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTouchEvent.h; sourceTree = "<group>"; };
 		58114A121AAE854800E7D092 /* RCTPicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPicker.h; sourceTree = "<group>"; };
 		58114A131AAE854800E7D092 /* RCTPicker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPicker.m; sourceTree = "<group>"; };
 		58114A141AAE854800E7D092 /* RCTPickerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPickerManager.h; sourceTree = "<group>"; };
@@ -546,6 +549,8 @@
 				830A229C1A66C68A008503DA /* RCTRootView.h */,
 				830A229D1A66C68A008503DA /* RCTRootView.m */,
 				13AFBCA21C07287B00BBAEAA /* RCTRootViewDelegate.h */,
+				391E86A31C623EC800009732 /* RCTTouchEvent.h */,
+				391E86A21C623EC800009732 /* RCTTouchEvent.m */,
 				83CBBA961A6020BB00E9B192 /* RCTTouchHandler.h */,
 				83CBBA971A6020BB00E9B192 /* RCTTouchHandler.m */,
 				1345A83A1B265A0E00583190 /* RCTURLRequestDelegate.h */,
@@ -728,6 +733,7 @@
 				83CBBA691A601EF300E9B192 /* RCTEventDispatcher.m in Sources */,
 				83A1FE8F1B62643A00BE0E65 /* RCTModalHostViewManager.m in Sources */,
 				13E0674A1A70F434002CDEE1 /* RCTUIManager.m in Sources */,
+				391E86A41C623EC800009732 /* RCTTouchEvent.m in Sources */,
 				1450FF861BCFF28A00208362 /* RCTProfile.m in Sources */,
 				13AB90C11B6FA36700713B4F /* RCTComponentData.m in Sources */,
 				13B0801B1A69489C00A75B9A /* RCTNavigatorManager.m in Sources */,

From 41f5a21b56a19c8059595850e0f7782b2ba70fc8 Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Wed, 3 Feb 2016 07:10:52 -0800
Subject: [PATCH 1010/1411] Improve systrace markers

Reviewed By: jspahrsummers

Differential Revision: D2851737

fb-gh-sync-id: 4aa0872e7d56d59de2fa42b87a795b2d64e0faa0
---
 React/Base/RCTBatchedBridge.m    | 12 +++++++-----
 React/Base/RCTRootView.m         | 10 ++++++++--
 React/Executors/RCTJSCExecutor.m | 13 +++++++------
 React/Profiler/RCTProfile.h      | 15 ++++++++-------
 React/Profiler/RCTProfile.m      |  7 +++----
 5 files changed, 33 insertions(+), 24 deletions(-)

diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index 50f6deb935fd..87e1fb8f774e 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -189,7 +189,7 @@ - (void)loadSource:(RCTSourceLoadBlock)_onSourceLoad
   (void)cookie;
 
   RCTSourceLoadBlock onSourceLoad = ^(NSError *error, NSData *source) {
-    RCTProfileEndAsyncEvent(0, @"init,download", cookie, @"JavaScript download", nil);
+    RCTProfileEndAsyncEvent(0, @"native", cookie, @"JavaScript download", @"JS async", nil);
     RCTPerformanceLoggerEnd(RCTPLScriptDownload);
 
     _onSourceLoad(error, source);
@@ -629,6 +629,8 @@ - (void)enqueueJSCall:(NSString *)moduleDotMethod args:(NSArray *)args
    * AnyThread
    */
 
+  RCT_PROFILE_BEGIN_EVENT(0, @"-[RCTBatchedBridge enqueueJSCall:]", nil);
+
   NSArray<NSString *> *ids = [moduleDotMethod componentsSeparatedByString:@"."];
 
   NSString *module = ids[0];
@@ -654,6 +656,8 @@ - (void)enqueueJSCall:(NSString *)moduleDotMethod args:(NSArray *)args
       [strongSelf _actuallyInvokeAndProcessModule:module method:method arguments:args ?: @[]];
     }
   }];
+
+  RCT_PROFILE_END_EVENT(0, @"", nil);
 }
 
 /**
@@ -843,8 +847,7 @@ - (void)handleBuffer:(NSArray *)buffer
 
     dispatch_block_t block = ^{
       RCTProfileEndFlowEvent();
-
-      RCT_PROFILE_BEGIN_EVENT(0, RCTCurrentThreadName(), nil);
+      RCT_PROFILE_BEGIN_EVENT(0, @"-[RCTBatchedBridge handleBuffer:]", nil);
 
       NSOrderedSet *calls = [buckets objectForKey:queue];
       @autoreleasepool {
@@ -940,14 +943,13 @@ - (BOOL)_handleRequestNumber:(NSUInteger)i
 - (void)_jsThreadUpdate:(CADisplayLink *)displayLink
 {
   RCTAssertJSThread();
-  RCT_PROFILE_BEGIN_EVENT(0, @"DispatchFrameUpdate", nil);
+  RCT_PROFILE_BEGIN_EVENT(0, @"-[RCTBatchedBridge _jsThreadUpdate:]", nil);
 
   RCTFrameUpdate *frameUpdate = [[RCTFrameUpdate alloc] initWithDisplayLink:displayLink];
   for (RCTModuleData *moduleData in _frameUpdateObservers) {
     id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)moduleData.instance;
     if (!observer.paused) {
       RCTProfileBeginFlowEvent();
-
       [self dispatchBlock:^{
         RCTProfileEndFlowEvent();
         [observer didUpdateFrame:frameUpdate];
diff --git a/React/Base/RCTRootView.m b/React/Base/RCTRootView.m
index c0481e07638b..d5726a2bcfa3 100644
--- a/React/Base/RCTRootView.m
+++ b/React/Base/RCTRootView.m
@@ -25,6 +25,7 @@
 #import "RCTUtils.h"
 #import "RCTView.h"
 #import "UIView+React.h"
+#import "RCTProfile.h"
 
 NSString *const RCTContentDidAppearNotification = @"RCTContentDidAppearNotification";
 
@@ -60,6 +61,8 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
   RCTAssert(bridge, @"A bridge instance is required to create an RCTRootView");
   RCTAssert(moduleName, @"A moduleName is required to create an RCTRootView");
 
+  RCT_PROFILE_BEGIN_EVENT(0, @"-[RCTRootView init]", nil);
+
   if ((self = [super initWithFrame:CGRectZero])) {
 
     self.backgroundColor = [UIColor whiteColor];
@@ -86,6 +89,9 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
 
     [self showLoadingView];
   }
+
+  RCT_PROFILE_END_EVENT(0, @"", nil);
+
   return self;
 }
 
@@ -174,10 +180,10 @@ - (void)bundleFinishedLoading:(RCTBridge *)bridge
 
   [_contentView removeFromSuperview];
   _contentView = [[RCTRootContentView alloc] initWithFrame:self.bounds bridge:bridge];
+  [self runApplication:bridge];
+
   _contentView.backgroundColor = self.backgroundColor;
   [self insertSubview:_contentView atIndex:0];
-
-  [self runApplication:bridge];
 }
 
 - (void)runApplication:(RCTBridge *)bridge
diff --git a/React/Executors/RCTJSCExecutor.m b/React/Executors/RCTJSCExecutor.m
index 9e4c6201ecbc..a1489d35e03b 100644
--- a/React/Executors/RCTJSCExecutor.m
+++ b/React/Executors/RCTJSCExecutor.m
@@ -261,12 +261,11 @@ - (void)setUp
       return nil;
     }
 
+    RCT_PROFILE_BEGIN_EVENT(0, @"nativeRequireModuleConfig", nil);
     NSArray *config = [strongSelf->_bridge configForModuleName:moduleName];
-    if (config) {
-      return RCTJSONStringify(config, NULL);
-    }
-
-    return nil;
+    NSString *result = config ? RCTJSONStringify(config, NULL) : nil;
+    RCT_PROFILE_END_EVENT(0, @"js_call,config", @{ @"moduleName": moduleName });
+    return result;
   }];
 
   [self addSynchronousHookWithName:@"nativeFlushQueueImmediate" usingBlock:^(NSArray<NSArray *> *calls){
@@ -275,7 +274,9 @@ - (void)setUp
       return;
     }
 
+    RCT_PROFILE_BEGIN_EVENT(0, @"nativeFlushQueueImmediate", nil);
     [strongSelf->_bridge handleBuffer:calls batchEnded:NO];
+    RCT_PROFILE_END_EVENT(0, @"js_call", nil);
   }];
 
   [self addSynchronousHookWithName:@"nativePerformanceNow" usingBlock:^{
@@ -296,7 +297,7 @@ - (void)setUp
 
   [self addSynchronousHookWithName:@"nativeTraceEndAsyncSection" usingBlock:^(uint64_t tag, NSString *name, NSUInteger cookie) {
     NSUInteger newCookie = (NSUInteger)CFDictionaryGetValue(cookieMap, (const void *)cookie);
-    RCTProfileEndAsyncEvent(tag, @"js,async", newCookie, name, nil);
+    RCTProfileEndAsyncEvent(tag, @"js,async", newCookie, name, @"JS async", nil);
     CFDictionaryRemoveValue(cookieMap, (const void *)cookie);
   }];
 
diff --git a/React/Profiler/RCTProfile.h b/React/Profiler/RCTProfile.h
index 1cd721ab7cd2..17b3bf27d2ab 100644
--- a/React/Profiler/RCTProfile.h
+++ b/React/Profiler/RCTProfile.h
@@ -69,10 +69,10 @@ RCT_EXTERN void _RCTProfileBeginEvent(NSThread *calleeThread,
 #define RCT_PROFILE_BEGIN_EVENT(...) \
   do { \
     if (RCTProfileIsProfiling()) { \
-      NSThread *calleeThread = [NSThread currentThread]; \
-      NSTimeInterval time = CACurrentMediaTime(); \
+      NSThread *__calleeThread = [NSThread currentThread]; \
+      NSTimeInterval __time = CACurrentMediaTime(); \
       dispatch_async(RCTProfileGetQueue(), ^{ \
-        _RCTProfileBeginEvent(calleeThread, time, __VA_ARGS__); \
+        _RCTProfileBeginEvent(__calleeThread, __time, __VA_ARGS__); \
       }); \
     } \
   } while(0)
@@ -92,11 +92,11 @@ RCT_EXTERN void _RCTProfileEndEvent(NSThread *calleeThread,
 #define RCT_PROFILE_END_EVENT(...) \
   do { \
     if (RCTProfileIsProfiling()) { \
-      NSThread *calleeThread = [NSThread currentThread]; \
-      NSString *threadName = RCTCurrentThreadName(); \
-      NSTimeInterval time = CACurrentMediaTime(); \
+      NSThread *__calleeThread = [NSThread currentThread]; \
+      NSString *__threadName = RCTCurrentThreadName(); \
+      NSTimeInterval __time = CACurrentMediaTime(); \
       dispatch_async(RCTProfileGetQueue(), ^{ \
-        _RCTProfileEndEvent(calleeThread, threadName, time, __VA_ARGS__); \
+        _RCTProfileEndEvent(__calleeThread, __threadName, __time, __VA_ARGS__); \
       }); \
     } \
   } while(0)
@@ -117,6 +117,7 @@ RCT_EXTERN void RCTProfileEndAsyncEvent(uint64_t tag,
                                         NSString *category,
                                         NSUInteger cookie,
                                         NSString *name,
+                                        NSString *threadName,
                                         NSDictionary *args);
 
 /**
diff --git a/React/Profiler/RCTProfile.m b/React/Profiler/RCTProfile.m
index 42cf74c638b8..32f63e91658c 100644
--- a/React/Profiler/RCTProfile.m
+++ b/React/Profiler/RCTProfile.m
@@ -472,7 +472,6 @@ void _RCTProfileBeginEvent(
   NSMutableArray *events = RCTProfileGetThreadEvents(calleeThread);
   [events addObject:@[
     RCTProfileTimestamp(time),
-    @(tag),
     name,
     RCTNullIfNil(args),
   ]];
@@ -507,12 +506,12 @@ void _RCTProfileEndEvent(
 
   RCTProfileAddEvent(RCTProfileTraceEvents,
     @"tid": threadName,
-    @"name": event[2],
+    @"name": event[1],
     @"cat": category,
     @"ph": @"X",
     @"ts": start,
     @"dur": @(RCTProfileTimestamp(time).doubleValue - start.doubleValue),
-    @"args": RCTProfileMergeArgs(event[3], args),
+    @"args": RCTProfileMergeArgs(event[2], args),
   );
 }
 
@@ -548,6 +547,7 @@ void RCTProfileEndAsyncEvent(
   NSString *category,
   NSUInteger cookie,
   NSString *name,
+  NSString *threadName,
   NSDictionary *args
 ) {
   CHECK();
@@ -558,7 +558,6 @@ void RCTProfileEndAsyncEvent(
   }
 
   NSTimeInterval time = CACurrentMediaTime();
-  NSString *threadName = RCTCurrentThreadName();
 
   dispatch_async(RCTProfileGetQueue(), ^{
     NSArray *event = RCTProfileOngoingEvents[@(cookie)];

From 4a3900bf5dc9a47fe041be34d3623d4de51f5d64 Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Wed, 3 Feb 2016 07:26:50 -0800
Subject: [PATCH 1011/1411] LinkingIOS and IntentAndroid now unified

Summary: Closes https://github.com/facebook/react-native/pull/5733

Reviewed By: svcscm

Differential Revision: D2895570

Pulled By: androidtrunkagent

fb-gh-sync-id: b4e5d4de96b4453c620e82858627f08023e0a265
---
 docs/KnownIssues.md | 1 -
 1 file changed, 1 deletion(-)

diff --git a/docs/KnownIssues.md b/docs/KnownIssues.md
index 3a4870f4ab79..a3deb7319783 100644
--- a/docs/KnownIssues.md
+++ b/docs/KnownIssues.md
@@ -45,7 +45,6 @@ There are properties that work on one platform only, either because they can inh
 There are known cases where the APIs could be made more consistent across iOS and Android:
 
 - `<ViewPagerAndroid>` and `<ScrollView pagingEnabled={true}>` on iOS do a similar thing. We might want to unify them to `<ViewPager>`.
-- It might be possible to bring `LinkingIOS` and `IntentAndroid` closer together.
 - `ActivityIndicator` could render a native spinning indicator on both platforms (currently this is done using `ActivityIndicatorIOS` on iOS and `ProgressBarAndroid` on Android).
 - `ProgressBar` could render a horizontal progress bar on both platforms (on iOS this is `ProgressViewIOS`, on Android it's `ProgressBarAndroid`).
 

From 34389c529dc5a1dff86164b6087228ca021fdde7 Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Wed, 3 Feb 2016 07:59:28 -0800
Subject: [PATCH 1012/1411] Fix sticky headers position when scrolling while
 RefreshControl is refreshing

Summary:
When scrolling while RefreshControl is refreshing the sticky headers are offset by the height of the UIRefreshControl. This simply removes the height of the UIRefreshControl while it is refreshing and fixes the problem.

You can repro the bug using this example in UIExplorer by doing a pull to refresh and scrolling the ListView immediately after.
https://gist.github.com/janicduplessis/26b4f2758e90b2aa1620

Fixes #5405
Closes https://github.com/facebook/react-native/pull/5517

Reviewed By: svcscm

Differential Revision: D2895623

Pulled By: nicklockwood

fb-gh-sync-id: 81df36cccfc3e7b973c2be78565f8b8408c9fc12
---
 React/Views/RCTScrollView.m | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/React/Views/RCTScrollView.m b/React/Views/RCTScrollView.m
index 09c606176231..10f2e5ec9c53 100644
--- a/React/Views/RCTScrollView.m
+++ b/React/Views/RCTScrollView.m
@@ -275,6 +275,11 @@ - (void)dockClosestSectionHeader
 {
   UIView *contentView = [self contentView];
   CGFloat scrollTop = self.bounds.origin.y + self.contentInset.top;
+  // If the RefreshControl is refreshing, remove it's height so sticky headers are
+  // positioned properly when scrolling down while refreshing.
+  if (self.refreshControl != nil && self.refreshControl.refreshing) {
+    scrollTop -= self.refreshControl.frame.size.height;
+  }
 
   // Find the section headers that need to be docked
   __block UIView *previousHeader = nil;

From e6cb02d61af82832016bafb259a1b0d3039a357e Mon Sep 17 00:00:00 2001
From: Adam Miskiewicz <adam@sk3vy.com>
Date: Wed, 3 Feb 2016 08:14:38 -0800
Subject: [PATCH 1013/1411] Use "babel-preset-react-native"

Summary:
Rather than specifying Babel plugins in the `.babelrc` packaged with react-native, leverage a Babel preset to define the plugins (https://github.com/exponentjs/babel-preset-react-native).

This allows for a much better user experience for those who want (or need) to override options in their project's `.babelrc`.

Prior to this PR, if a user wanted to use a custom babel-plugin (or a custom set of babel plugins), they'd have either 1) manually override the `.babelrc` in the react-packager directory (or fork RN), or 2) specify a custom transformer to use when running the packager that loaded their own `.babelrc`. Note - the custom transformer was necessary because without it, RN's `.babelrc` options would supersede the options defined in the project's `.babelrc`...potentially causing issues with plugin ordering.

This PR makes the transformer check for the existence of a project-level `.babelrc`, and if it it's there, it _doesn't_ use the react-native `.babelrc`. This prevents any oddities with Babel plug
Closes https://github.com/facebook/react-native/pull/5214

Reviewed By: davidaurelio

Differential Revision: D2881814

Pulled By: martinbigio

fb-gh-sync-id: 4168144b7a365fae62bbeed094d8a03a48b4798c
---
 .../assets/ScrollViewTestModule.js            |    1 -
 babel-preset/README.md                        |   31 +
 babel-preset/configs/hmr.js                   |   28 +
 babel-preset/configs/internal.js              |   16 +
 babel-preset/configs/main.js                  |   42 +
 .../src/transforms => babel-preset}/index.js  |    5 +-
 .../lib}/resolvePlugins.js                    |    0
 babel-preset/package.json                     |   45 +
 babel-preset/plugins.js                       |   35 +
 npm-shrinkwrap.json                           | 6568 +++++------------
 package.json                                  |   42 +-
 packager/babelRegisterOnly.js                 |    4 +-
 packager/react-packager/.babelrc              |   30 -
 packager/react-packager/index.js              |    2 -
 packager/react-packager/rn-babelrc.json       |    4 +
 .../react-packager/src/JSTransformer/index.js |    2 +
 .../src/JSTransformer/worker.js               |   17 +-
 packager/react-packager/src/Resolver/index.js |    1 -
 packager/transformer.js                       |  100 +-
 19 files changed, 2123 insertions(+), 4850 deletions(-)
 create mode 100644 babel-preset/README.md
 create mode 100644 babel-preset/configs/hmr.js
 create mode 100644 babel-preset/configs/internal.js
 create mode 100644 babel-preset/configs/main.js
 rename {packager/react-packager/src/transforms => babel-preset}/index.js (85%)
 rename {packager/react-packager/src/JSTransformer => babel-preset/lib}/resolvePlugins.js (100%)
 create mode 100644 babel-preset/package.json
 create mode 100644 babel-preset/plugins.js
 delete mode 100644 packager/react-packager/.babelrc
 create mode 100644 packager/react-packager/rn-babelrc.json

diff --git a/ReactAndroid/src/androidTest/assets/ScrollViewTestModule.js b/ReactAndroid/src/androidTest/assets/ScrollViewTestModule.js
index 0a2f5143a148..e7dac8c7e1fa 100644
--- a/ReactAndroid/src/androidTest/assets/ScrollViewTestModule.js
+++ b/ReactAndroid/src/androidTest/assets/ScrollViewTestModule.js
@@ -1,6 +1,5 @@
 /**
  * @providesModule ScrollViewTestModule
- * @jsx React.DOM
  */
 
 'use strict';
diff --git a/babel-preset/README.md b/babel-preset/README.md
new file mode 100644
index 000000000000..eaab8477ea6d
--- /dev/null
+++ b/babel-preset/README.md
@@ -0,0 +1,31 @@
+# babel-preset-react-native
+
+Babel presets for React Native applications. React Native itself uses this Babel preset by default when transforming your app's source code.
+
+If you wish to use a custom Babel configuration by writing a `.babelrc` file in your project's root directory, you must specify all the plugins necessary to transform your code. React Native does not apply its default Babel configuration in this case. So, to make your life easier, you can use this preset to get the default configuration and then specify more plugins that run before it.
+
+## Usage
+
+As mentioned above, you only need to use this preset if you are writing a custom `.babelrc` file.
+
+### Installation
+
+Install `babel-preset-react-native` in your app:
+```sh
+npm i babel-preset-react-native --save-dev
+```
+
+### Configuring Babel
+
+Then, create a file called `.babelrc` in your project's root directory. The existence of this `.babelrc` file will tell React Native to use your custom Babel configuration instead of its own. Then load this preset:
+```
+{
+  "presets": ["react-native"]
+}
+```
+
+You can further customize your Babel configuration by specifying plugins and other options. See [Babel's `.babelrc` documentation](https://babeljs.io/docs/usage/babelrc/) to learn more.
+
+## Help and Support
+
+If you get stuck configuring Babel, please ask a question on Stack Overflow or find a consultant for help. If you discover a bug, please open up an issue.
diff --git a/babel-preset/configs/hmr.js b/babel-preset/configs/hmr.js
new file mode 100644
index 000000000000..2a4bb9a93703
--- /dev/null
+++ b/babel-preset/configs/hmr.js
@@ -0,0 +1,28 @@
+/**
+ * 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.
+ */
+'use strict';
+
+var resolvePlugins = require('../lib/resolvePlugins');
+
+module.exports = function(options) {
+  return {
+    plugins: resolvePlugins([
+      [
+        'react-transform',
+        {
+          transforms: [{
+            transform: 'react-transform-hmr/lib/index.js',
+            imports: ['React'],
+            locals: ['module'],
+          }]
+        },
+      ]
+    ])
+  };
+}
diff --git a/babel-preset/configs/internal.js b/babel-preset/configs/internal.js
new file mode 100644
index 000000000000..53830b0d6fd2
--- /dev/null
+++ b/babel-preset/configs/internal.js
@@ -0,0 +1,16 @@
+/**
+ * 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.
+ */
+'use strict';
+
+var resolvePlugins = require('../lib/resolvePlugins');
+
+module.exports = function(options) {
+  // For future internal pipeline usage
+  return null;
+}
diff --git a/babel-preset/configs/main.js b/babel-preset/configs/main.js
new file mode 100644
index 000000000000..204028fbb130
--- /dev/null
+++ b/babel-preset/configs/main.js
@@ -0,0 +1,42 @@
+/**
+ * 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.
+ */
+'use strict';
+
+var resolvePlugins = require('../lib/resolvePlugins');
+
+module.exports = {
+  comments: false,
+  compact: true,
+  plugins: resolvePlugins([
+    'syntax-async-functions',
+    'syntax-class-properties',
+    'syntax-trailing-function-commas',
+    'transform-class-properties',
+    'transform-es2015-arrow-functions',
+    'transform-es2015-block-scoping',
+    'transform-es2015-classes',
+    'transform-es2015-computed-properties',
+    'transform-es2015-constants',
+    'transform-es2015-destructuring',
+    ['transform-es2015-modules-commonjs', { strict: false, allowTopLevelThis: true }],
+    'transform-es2015-parameters',
+    'transform-es2015-shorthand-properties',
+    'transform-es2015-spread',
+    'transform-es2015-template-literals',
+    'transform-flow-strip-types',
+    'transform-object-assign',
+    'transform-object-rest-spread',
+    'transform-react-display-name',
+    'transform-react-jsx',
+    'transform-regenerator',
+    ['transform-es2015-for-of', { loose: true }],
+  ]),
+  retainLines: true,
+  sourceMaps: false,
+};
diff --git a/packager/react-packager/src/transforms/index.js b/babel-preset/index.js
similarity index 85%
rename from packager/react-packager/src/transforms/index.js
rename to babel-preset/index.js
index 37f17ccd1a9e..a1e2956ed563 100644
--- a/packager/react-packager/src/transforms/index.js
+++ b/babel-preset/index.js
@@ -8,7 +8,4 @@
  */
 'use strict';
 
-exports.getAll = function(options) {
-  return [];
-};
-
+module.exports = require('./configs/main');
diff --git a/packager/react-packager/src/JSTransformer/resolvePlugins.js b/babel-preset/lib/resolvePlugins.js
similarity index 100%
rename from packager/react-packager/src/JSTransformer/resolvePlugins.js
rename to babel-preset/lib/resolvePlugins.js
diff --git a/babel-preset/package.json b/babel-preset/package.json
new file mode 100644
index 000000000000..01cef395297f
--- /dev/null
+++ b/babel-preset/package.json
@@ -0,0 +1,45 @@
+{
+  "name": "babel-preset-react-native",
+  "version": "1.2.3",
+  "description": "Babel preset for React Native applications",
+  "main": "index.js",
+  "repository": "https://github.com/facebook/react-native/tree/master/babel-preset",
+  "keywords": [
+    "babel",
+    "preset",
+    "react-native"
+  ],
+  "license" : "BSD-3-Clause",
+  "bugs": {
+    "url": "https://github.com/facebook/react-native/issues"
+  },
+  "homepage": "https://github.com/facebook/react-native/tree/master/babel-preset/README.md",
+  "dependencies": {
+    "babel-plugin-react-transform": "2.0.0-beta1",
+    "babel-plugin-syntax-async-functions": "^6.3.13",
+    "babel-plugin-syntax-class-properties": "^6.3.13",
+    "babel-plugin-syntax-flow": "^6.3.13",
+    "babel-plugin-syntax-jsx": "^6.3.13",
+    "babel-plugin-syntax-trailing-function-commas": "^6.3.13",
+    "babel-plugin-transform-class-properties": "^6.4.0",
+    "babel-plugin-transform-es2015-arrow-functions": "^6.4.0",
+    "babel-plugin-transform-es2015-block-scoping": "^6.4.0",
+    "babel-plugin-transform-es2015-classes": "^6.4.0",
+    "babel-plugin-transform-es2015-computed-properties": "^6.4.0",
+    "babel-plugin-transform-es2015-constants": "^6.1.4",
+    "babel-plugin-transform-es2015-destructuring": "^6.4.0",
+    "babel-plugin-transform-es2015-for-of": "^6.3.13",
+    "babel-plugin-transform-es2015-modules-commonjs": "^6.4.0",
+    "babel-plugin-transform-es2015-parameters": "^6.4.2",
+    "babel-plugin-transform-es2015-shorthand-properties": "^6.3.13",
+    "babel-plugin-transform-es2015-spread": "^6.4.0",
+    "babel-plugin-transform-es2015-template-literals": "^6.3.13",
+    "babel-plugin-transform-flow-strip-types": "^6.4.0",
+    "babel-plugin-transform-object-assign": "^6.3.13",
+    "babel-plugin-transform-object-rest-spread": "^6.3.13",
+    "babel-plugin-transform-react-display-name": "^6.4.0",
+    "babel-plugin-transform-react-jsx": "^6.4.0",
+    "babel-plugin-transform-regenerator": "^6.3.26",
+    "react-transform-hmr": "^1.0.2"
+  }
+}
diff --git a/babel-preset/plugins.js b/babel-preset/plugins.js
new file mode 100644
index 000000000000..b24a31a3b081
--- /dev/null
+++ b/babel-preset/plugins.js
@@ -0,0 +1,35 @@
+/**
+ * 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.
+ */
+'use strict';
+
+module.exports = {
+  'babel-plugin-react-transform': require('babel-plugin-react-transform'),
+  'babel-plugin-syntax-async-functions': require('babel-plugin-syntax-async-functions'),
+  'babel-plugin-syntax-class-properties': require('babel-plugin-syntax-class-properties'),
+  'babel-plugin-syntax-trailing-function-commas': require('babel-plugin-syntax-trailing-function-commas'),
+  'babel-plugin-transform-class-properties': require('babel-plugin-transform-class-properties'),
+  'babel-plugin-transform-es2015-arrow-functions': require('babel-plugin-transform-es2015-arrow-functions'),
+  'babel-plugin-transform-es2015-block-scoping': require('babel-plugin-transform-es2015-block-scoping'),
+  'babel-plugin-transform-es2015-classes': require('babel-plugin-transform-es2015-classes'),
+  'babel-plugin-transform-es2015-computed-properties': require('babel-plugin-transform-es2015-computed-properties'),
+  'babel-plugin-transform-es2015-constants': require('babel-plugin-transform-es2015-constants'),
+  'babel-plugin-transform-es2015-destructuring': require('babel-plugin-transform-es2015-destructuring'),
+  'babel-plugin-transform-es2015-modules-commonjs': require('babel-plugin-transform-es2015-modules-commonjs'),
+  'babel-plugin-transform-es2015-parameters': require('babel-plugin-transform-es2015-parameters'),
+  'babel-plugin-transform-es2015-shorthand-properties': require('babel-plugin-transform-es2015-shorthand-properties'),
+  'babel-plugin-transform-es2015-spread': require('babel-plugin-transform-es2015-spread'),
+  'babel-plugin-transform-es2015-template-literals': require('babel-plugin-transform-es2015-template-literals'),
+  'babel-plugin-transform-flow-strip-types': require('babel-plugin-transform-flow-strip-types'),
+  'babel-plugin-transform-object-assign': require('babel-plugin-transform-object-assign'),
+  'babel-plugin-transform-object-rest-spread': require('babel-plugin-transform-object-rest-spread'),
+  'babel-plugin-transform-react-display-name': require('babel-plugin-transform-react-display-name'),
+  'babel-plugin-transform-react-jsx': require('babel-plugin-transform-react-jsx'),
+  'babel-plugin-transform-regenerator': require('babel-plugin-transform-regenerator'),
+  'babel-plugin-transform-es2015-for-of': require('babel-plugin-transform-es2015-for-of'),
+};
diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index 0fc1c377b728..dc7c0be87142 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -4,1186 +4,1493 @@
   "dependencies": {
     "absolute-path": {
       "version": "0.0.0",
-      "from": "absolute-path@0.0.0",
+      "from": "https://registry.npmjs.org/absolute-path/-/absolute-path-0.0.0.tgz",
       "resolved": "https://registry.npmjs.org/absolute-path/-/absolute-path-0.0.0.tgz"
     },
     "acorn": {
       "version": "1.2.2",
-      "from": "acorn@>=1.0.3 <2.0.0",
+      "from": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz",
       "resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz"
     },
     "acorn-to-esprima": {
       "version": "1.0.5",
-      "from": "acorn-to-esprima@>=1.0.5 <2.0.0",
+      "from": "https://registry.npmjs.org/acorn-to-esprima/-/acorn-to-esprima-1.0.5.tgz",
       "resolved": "https://registry.npmjs.org/acorn-to-esprima/-/acorn-to-esprima-1.0.5.tgz"
     },
     "align-text": {
       "version": "0.1.3",
-      "from": "align-text@>=0.1.0 <0.2.0",
+      "from": "https://registry.npmjs.org/align-text/-/align-text-0.1.3.tgz",
       "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.3.tgz"
     },
     "alter": {
       "version": "0.2.0",
-      "from": "alter@>=0.2.0 <0.3.0",
+      "from": "https://registry.npmjs.org/alter/-/alter-0.2.0.tgz",
       "resolved": "https://registry.npmjs.org/alter/-/alter-0.2.0.tgz"
     },
     "amdefine": {
       "version": "1.0.0",
-      "from": "amdefine@>=0.0.4",
+      "from": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz"
     },
     "ansi-green": {
       "version": "0.1.1",
-      "from": "ansi-green@>=0.1.1 <0.2.0",
+      "from": "https://registry.npmjs.org/ansi-green/-/ansi-green-0.1.1.tgz",
       "resolved": "https://registry.npmjs.org/ansi-green/-/ansi-green-0.1.1.tgz"
     },
     "ansi-regex": {
       "version": "2.0.0",
-      "from": "ansi-regex@>=2.0.0 <3.0.0",
+      "from": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz",
       "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
     },
     "ansi-styles": {
       "version": "2.1.0",
-      "from": "ansi-styles@>=2.1.0 <3.0.0",
+      "from": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz",
       "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz"
     },
     "ansi-wrap": {
       "version": "0.1.0",
-      "from": "ansi-wrap@0.1.0",
+      "from": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz",
       "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz"
     },
     "anymatch": {
       "version": "1.3.0",
-      "from": "anymatch@>=1.1.0 <2.0.0",
+      "from": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz",
       "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz"
     },
     "arr-diff": {
       "version": "1.1.0",
-      "from": "arr-diff@>=1.0.1 <2.0.0",
+      "from": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz",
       "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz"
     },
     "arr-flatten": {
       "version": "1.0.1",
-      "from": "arr-flatten@>=1.0.1 <2.0.0",
+      "from": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.0.1.tgz"
     },
     "array-differ": {
       "version": "1.0.0",
-      "from": "array-differ@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz"
     },
     "array-slice": {
       "version": "0.2.3",
-      "from": "array-slice@>=0.2.3 <0.3.0",
+      "from": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz",
       "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz"
     },
     "array-uniq": {
       "version": "1.0.2",
-      "from": "array-uniq@>=1.0.2 <2.0.0",
+      "from": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.2.tgz",
       "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.2.tgz"
     },
     "array-unique": {
       "version": "0.2.1",
-      "from": "array-unique@>=0.2.1 <0.3.0",
+      "from": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
       "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz"
     },
     "arrify": {
       "version": "1.0.0",
-      "from": "arrify@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/arrify/-/arrify-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.0.tgz"
     },
     "art": {
       "version": "0.10.0",
-      "from": "art@0.10.0",
+      "from": "https://registry.npmjs.org/art/-/art-0.10.0.tgz",
       "resolved": "https://registry.npmjs.org/art/-/art-0.10.0.tgz"
     },
     "ast-traverse": {
       "version": "0.1.1",
-      "from": "ast-traverse@>=0.1.1 <0.2.0",
+      "from": "https://registry.npmjs.org/ast-traverse/-/ast-traverse-0.1.1.tgz",
       "resolved": "https://registry.npmjs.org/ast-traverse/-/ast-traverse-0.1.1.tgz"
     },
-    "ast-types": {
-      "version": "0.8.5",
-      "from": "ast-types@0.8.5",
-      "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.5.tgz"
-    },
     "async-each": {
       "version": "0.1.6",
-      "from": "async-each@>=0.1.5 <0.2.0",
+      "from": "https://registry.npmjs.org/async-each/-/async-each-0.1.6.tgz",
       "resolved": "https://registry.npmjs.org/async-each/-/async-each-0.1.6.tgz"
     },
     "babel": {
       "version": "5.8.29",
-      "from": "babel@>=5.4.7 <6.0.0",
+      "from": "https://registry.npmjs.org/babel/-/babel-5.8.29.tgz",
       "resolved": "https://registry.npmjs.org/babel/-/babel-5.8.29.tgz",
       "dependencies": {
         "babel-core": {
           "version": "5.8.33",
-          "from": "babel-core@>=5.6.21 <6.0.0",
+          "from": "https://registry.npmjs.org/babel-core/-/babel-core-5.8.33.tgz",
           "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-5.8.33.tgz"
         },
         "source-map": {
           "version": "0.5.3",
-          "from": "source-map@>=0.5.0 <0.6.0",
+          "from": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz"
         },
         "ast-types": {
           "version": "0.8.12",
-          "from": "ast-types@0.8.12",
+          "from": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz",
           "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz"
         },
         "babylon": {
           "version": "5.8.29",
-          "from": "babylon@>=5.8.29 <6.0.0",
+          "from": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz",
           "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz"
         },
-        "chalk": {
-          "version": "1.1.1",
-          "from": "chalk@>=1.0.0 <2.0.0"
-        },
-        "debug": {
-          "version": "2.2.0",
-          "from": "debug@>=2.1.1 <3.0.0"
+        "globals": {
+          "version": "6.4.1",
+          "from": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz",
+          "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
         },
         "js-tokens": {
           "version": "1.0.1",
-          "from": "js-tokens@1.0.1",
+          "from": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz",
           "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
         },
-        "globals": {
-          "version": "6.4.1",
-          "from": "globals@>=6.4.0 <7.0.0",
-          "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
-        },
         "recast": {
           "version": "0.10.33",
-          "from": "recast@0.10.33",
+          "from": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz",
           "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
         },
         "regenerator": {
           "version": "0.8.40",
-          "from": "regenerator@0.8.40",
+          "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
           "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
         }
       }
     },
-    "babel-code-frame": {
-      "version": "6.0.15",
-      "from": "babel-code-frame@>=6.0.15 <7.0.0",
-      "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.0.15.tgz",
-      "dependencies": {
-        "chalk": {
-          "version": "1.1.1",
-          "from": "chalk@>=1.1.0 <2.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz"
-        }
-      }
-    },
     "babel-core": {
-      "version": "6.1.20",
-      "from": "babel-core@6.1.20",
-      "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.1.20.tgz",
+      "version": "6.4.5",
+      "from": "https://registry.npmjs.org/babel-core/-/babel-core-6.4.5.tgz",
+      "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.4.5.tgz",
       "dependencies": {
         "babel-code-frame": {
-          "version": "6.1.18",
-          "from": "babel-code-frame@>=6.1.18 <7.0.0",
-          "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.1.18.tgz"
+          "version": "6.3.13",
+          "from": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.3.13.tgz",
+          "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.3.13.tgz"
         },
-        "babel-messages": {
-          "version": "6.1.18",
-          "from": "babel-messages@>=6.1.18 <7.0.0",
-          "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.1.18.tgz"
+        "babel-generator": {
+          "version": "6.4.5",
+          "from": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.4.5.tgz",
+          "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.4.5.tgz"
         },
-        "babel-template": {
-          "version": "6.1.18",
-          "from": "babel-template@>=6.1.18 <7.0.0",
-          "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.1.18.tgz"
+        "babel-helpers": {
+          "version": "6.4.5",
+          "from": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.4.5.tgz",
+          "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.4.5.tgz"
         },
-        "babel-traverse": {
-          "version": "6.1.20",
-          "from": "babel-traverse@>=6.1.20 <7.0.0",
-          "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.1.20.tgz"
+        "babel-messages": {
+          "version": "6.3.18",
+          "from": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.3.18.tgz",
+          "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.3.18.tgz"
         },
-        "babel-types": {
-          "version": "6.1.18",
-          "from": "babel-types@>=6.1.18 <7.0.0",
-          "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.1.18.tgz"
+        "babel-template": {
+          "version": "6.3.13",
+          "from": "https://registry.npmjs.org/babel-template/-/babel-template-6.3.13.tgz",
+          "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.3.13.tgz"
         },
-        "babylon": {
-          "version": "6.1.21",
-          "from": "babylon@>=6.1.20 <7.0.0",
-          "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.1.21.tgz"
+        "babel-runtime": {
+          "version": "5.8.35",
+          "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
         },
-        "regenerator": {
-          "version": "0.8.35",
-          "from": "regenerator@0.8.35",
-          "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.35.tgz"
+        "babel-traverse": {
+          "version": "6.4.5",
+          "from": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.4.5.tgz",
+          "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.4.5.tgz",
+          "dependencies": {
+            "globals": {
+              "version": "8.18.0",
+              "from": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz",
+              "resolved": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz"
+            },
+            "invariant": {
+              "version": "2.2.0",
+              "from": "https://registry.npmjs.org/invariant/-/invariant-2.2.0.tgz",
+              "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.0.tgz"
+            }
+          }
         },
         "source-map": {
           "version": "0.5.3",
-          "from": "source-map@>=0.5.0 <0.6.0",
+          "from": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz"
-        },
-        "esprima-fb": {
-          "version": "15001.1.0-dev-harmony-fb",
-          "from": "esprima-fb@>=15001.1.0-dev-harmony-fb <15001.2.0",
-          "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1.0-dev-harmony-fb.tgz"
-        },
-        "recast": {
-          "version": "0.10.24",
-          "from": "recast@0.10.24",
-          "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.24.tgz",
-          "dependencies": {
-            "source-map": {
-              "version": "0.4.4",
-              "from": "source-map@>=0.4.1 <0.5.0",
-              "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz"
-            }
-          }
         }
       }
     },
     "babel-eslint": {
       "version": "4.1.4",
-      "from": "babel-eslint@*",
+      "from": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-4.1.4.tgz",
       "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-4.1.4.tgz",
       "dependencies": {
         "babel-core": {
           "version": "5.8.33",
-          "from": "babel-core@>=5.8.33 <6.0.0",
-          "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-5.8.33.tgz",
-          "dependencies": {
-            "chalk": {
-              "version": "1.1.1",
-              "from": "chalk@>=1.0.0 <2.0.0"
-            },
-            "debug": {
-              "version": "2.2.0",
-              "from": "debug@>=2.1.1 <3.0.0"
-            }
-          }
-        },
-        "babylon": {
-          "version": "5.8.29",
-          "from": "babylon@>=5.8.29 <6.0.0",
-          "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz"
+          "from": "https://registry.npmjs.org/babel-core/-/babel-core-5.8.33.tgz",
+          "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-5.8.33.tgz"
         },
         "ast-types": {
           "version": "0.8.12",
-          "from": "ast-types@0.8.12",
+          "from": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz",
           "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz"
         },
-        "esprima-fb": {
-          "version": "15001.1001.0-dev-harmony-fb",
-          "from": "esprima-fb@>=15001.1001.0-dev-harmony-fb <15001.1002.0",
-          "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz"
+        "babylon": {
+          "version": "5.8.29",
+          "from": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz",
+          "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz"
         },
         "globals": {
           "version": "6.4.1",
-          "from": "globals@>=6.4.0 <7.0.0",
+          "from": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz",
           "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
         },
         "js-tokens": {
           "version": "1.0.1",
-          "from": "js-tokens@1.0.1",
+          "from": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz",
           "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
         },
         "recast": {
           "version": "0.10.33",
-          "from": "recast@0.10.33",
+          "from": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz",
           "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
         },
         "regenerator": {
           "version": "0.8.40",
-          "from": "regenerator@0.8.40",
+          "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
           "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
         },
         "source-map": {
           "version": "0.5.3",
-          "from": "source-map@>=0.5.0 <0.6.0",
+          "from": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz"
         }
       }
     },
-    "babel-generator": {
-      "version": "6.1.20",
-      "from": "babel-generator@>=6.1.20 <7.0.0",
-      "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.1.20.tgz",
-      "dependencies": {
-        "babel-messages": {
-          "version": "6.1.18",
-          "from": "babel-messages@>=6.1.18 <7.0.0"
-        },
-        "babel-types": {
-          "version": "6.1.18",
-          "from": "babel-types@>=6.1.18 <7.0.0"
-        },
-        "source-map": {
-          "version": "0.5.3",
-          "from": "source-map@>=0.5.0 <0.6.0"
-        },
-        "babel-code-frame": {
-          "version": "6.1.18",
-          "from": "babel-code-frame@>=6.1.18 <7.0.0"
-        },
-        "babel-traverse": {
-          "version": "6.1.20",
-          "from": "babel-traverse@>=6.1.18 <7.0.0"
-        },
-        "babylon": {
-          "version": "6.1.21",
-          "from": "babylon@>=6.1.20 <7.0.0"
-        }
-      }
-    },
-    "babel-helper-builder-react-jsx": {
-      "version": "6.0.15",
-      "from": "babel-helper-builder-react-jsx@>=6.0.14 <7.0.0",
-      "resolved": "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.0.15.tgz"
-    },
-    "babel-helper-call-delegate": {
-      "version": "6.0.15",
-      "from": "babel-helper-call-delegate@>=6.0.14 <7.0.0",
-      "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.0.15.tgz"
-    },
-    "babel-helper-define-map": {
-      "version": "6.0.15",
-      "from": "babel-helper-define-map@>=6.0.15 <7.0.0",
-      "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.0.15.tgz"
-    },
-    "babel-helper-function-name": {
-      "version": "6.0.15",
-      "from": "babel-helper-function-name@>=6.0.15 <7.0.0",
-      "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.0.15.tgz"
-    },
-    "babel-helper-get-function-arity": {
-      "version": "6.0.15",
-      "from": "babel-helper-get-function-arity@>=6.0.15 <7.0.0",
-      "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.0.15.tgz"
-    },
-    "babel-helper-hoist-variables": {
-      "version": "6.0.15",
-      "from": "babel-helper-hoist-variables@>=6.0.15 <7.0.0",
-      "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.0.15.tgz"
-    },
-    "babel-helper-optimise-call-expression": {
-      "version": "6.0.15",
-      "from": "babel-helper-optimise-call-expression@>=6.0.15 <7.0.0",
-      "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.0.15.tgz"
-    },
-    "babel-helper-replace-supers": {
-      "version": "6.0.18",
-      "from": "babel-helper-replace-supers@>=6.0.15 <7.0.0",
-      "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.0.18.tgz"
-    },
-    "babel-helpers": {
-      "version": "6.1.20",
-      "from": "babel-helpers@>=6.1.20 <7.0.0",
-      "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.1.20.tgz",
-      "dependencies": {
-        "babel-template": {
-          "version": "6.1.18",
-          "from": "babel-template@>=6.1.18 <7.0.0"
-        },
-        "babel-code-frame": {
-          "version": "6.1.18",
-          "from": "babel-code-frame@>=6.1.18 <7.0.0"
-        },
-        "babel-messages": {
-          "version": "6.1.18",
-          "from": "babel-messages@>=6.1.18 <7.0.0"
-        },
-        "babel-traverse": {
-          "version": "6.1.20",
-          "from": "babel-traverse@>=6.1.18 <7.0.0"
-        },
-        "babel-types": {
-          "version": "6.1.18",
-          "from": "babel-types@>=6.1.18 <7.0.0"
-        },
-        "babylon": {
-          "version": "6.1.21",
-          "from": "babylon@>=6.1.18 <7.0.0"
-        }
-      }
-    },
-    "babel-messages": {
-      "version": "6.0.15",
-      "from": "babel-messages@>=6.0.15 <7.0.0",
-      "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.0.15.tgz"
-    },
     "babel-plugin-constant-folding": {
       "version": "1.0.1",
-      "from": "babel-plugin-constant-folding@>=1.0.1 <2.0.0",
+      "from": "https://registry.npmjs.org/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz"
     },
     "babel-plugin-dead-code-elimination": {
       "version": "1.0.2",
-      "from": "babel-plugin-dead-code-elimination@>=1.0.2 <2.0.0",
+      "from": "https://registry.npmjs.org/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz",
       "resolved": "https://registry.npmjs.org/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz"
     },
     "babel-plugin-eval": {
       "version": "1.0.1",
-      "from": "babel-plugin-eval@>=1.0.1 <2.0.0",
+      "from": "https://registry.npmjs.org/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz"
     },
-    "babel-plugin-external-helpers-2": {
-      "version": "6.1.4",
-      "from": "babel-plugin-external-helpers-2@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-external-helpers-2/-/babel-plugin-external-helpers-2-6.1.4.tgz"
+    "babel-plugin-external-helpers": {
+      "version": "6.4.0",
+      "from": "https://registry.npmjs.org/babel-plugin-external-helpers/-/babel-plugin-external-helpers-6.4.0.tgz",
+      "resolved": "https://registry.npmjs.org/babel-plugin-external-helpers/-/babel-plugin-external-helpers-6.4.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "5.8.35",
+          "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+        }
+      }
     },
     "babel-plugin-inline-environment-variables": {
       "version": "1.0.1",
-      "from": "babel-plugin-inline-environment-variables@>=1.0.1 <2.0.0",
+      "from": "https://registry.npmjs.org/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz"
     },
     "babel-plugin-jscript": {
       "version": "1.0.4",
-      "from": "babel-plugin-jscript@>=1.0.4 <2.0.0",
+      "from": "https://registry.npmjs.org/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz",
       "resolved": "https://registry.npmjs.org/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz"
     },
     "babel-plugin-member-expression-literals": {
       "version": "1.0.1",
-      "from": "babel-plugin-member-expression-literals@>=1.0.1 <2.0.0",
+      "from": "https://registry.npmjs.org/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz"
     },
     "babel-plugin-property-literals": {
       "version": "1.0.1",
-      "from": "babel-plugin-property-literals@>=1.0.1 <2.0.0",
+      "from": "https://registry.npmjs.org/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz"
     },
     "babel-plugin-proto-to-assign": {
       "version": "1.0.4",
-      "from": "babel-plugin-proto-to-assign@>=1.0.3 <2.0.0",
+      "from": "https://registry.npmjs.org/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz",
       "resolved": "https://registry.npmjs.org/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz"
     },
     "babel-plugin-react-constant-elements": {
       "version": "1.0.3",
-      "from": "babel-plugin-react-constant-elements@>=1.0.3 <2.0.0",
+      "from": "https://registry.npmjs.org/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz",
       "resolved": "https://registry.npmjs.org/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz"
     },
     "babel-plugin-react-display-name": {
       "version": "1.0.3",
-      "from": "babel-plugin-react-display-name@>=1.0.3 <2.0.0",
+      "from": "https://registry.npmjs.org/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz",
       "resolved": "https://registry.npmjs.org/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz"
     },
-    "babel-plugin-react-transform": {
-      "version": "2.0.0-beta1",
-      "from": "babel-plugin-react-transform@2.0.0-beta1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-react-transform/-/babel-plugin-react-transform-2.0.0-beta1.tgz",
-      "dependencies": {
-        "array-find": {
-          "version": "1.0.0",
-          "from": "array-find@>=1.0.0 <2.0.0",
-          "resolved": "https://registry.npmjs.org/array-find/-/array-find-1.0.0.tgz"
-        }
-      }
-    },
     "babel-plugin-remove-console": {
       "version": "1.0.1",
-      "from": "babel-plugin-remove-console@>=1.0.1 <2.0.0",
+      "from": "https://registry.npmjs.org/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz"
     },
     "babel-plugin-remove-debugger": {
       "version": "1.0.1",
-      "from": "babel-plugin-remove-debugger@>=1.0.1 <2.0.0",
+      "from": "https://registry.npmjs.org/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz"
     },
     "babel-plugin-runtime": {
       "version": "1.0.7",
-      "from": "babel-plugin-runtime@>=1.0.7 <2.0.0",
+      "from": "https://registry.npmjs.org/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz",
       "resolved": "https://registry.npmjs.org/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz"
     },
-    "babel-plugin-syntax-async-functions": {
-      "version": "6.0.14",
-      "from": "babel-plugin-syntax-async-functions@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.0.14.tgz"
-    },
-    "babel-plugin-syntax-class-properties": {
-      "version": "6.0.14",
-      "from": "babel-plugin-syntax-class-properties@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.0.14.tgz"
-    },
-    "babel-plugin-syntax-flow": {
-      "version": "6.0.14",
-      "from": "babel-plugin-syntax-flow@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.0.14.tgz"
-    },
-    "babel-plugin-syntax-jsx": {
-      "version": "6.0.14",
-      "from": "babel-plugin-syntax-jsx@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.0.14.tgz"
-    },
-    "babel-plugin-syntax-object-rest-spread": {
-      "version": "6.0.14",
-      "from": "babel-plugin-syntax-object-rest-spread@>=6.0.14 <7.0.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.0.14.tgz"
-    },
-    "babel-plugin-syntax-trailing-function-commas": {
-      "version": "6.0.14",
-      "from": "babel-plugin-syntax-trailing-function-commas@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.0.14.tgz"
-    },
-    "babel-plugin-transform-class-properties": {
-      "version": "6.0.14",
-      "from": "babel-plugin-transform-class-properties@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.0.14.tgz"
-    },
-    "babel-plugin-transform-es2015-arrow-functions": {
-      "version": "6.0.14",
-      "from": "babel-plugin-transform-es2015-arrow-functions@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.0.14.tgz"
-    },
-    "babel-plugin-transform-es2015-block-scoping": {
-      "version": "6.0.18",
-      "from": "babel-plugin-transform-es2015-block-scoping@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.0.18.tgz"
-    },
-    "babel-plugin-transform-es2015-classes": {
-      "version": "6.1.2",
-      "from": "babel-plugin-transform-es2015-classes@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.1.2.tgz"
-    },
-    "babel-plugin-transform-es2015-computed-properties": {
-      "version": "6.0.14",
-      "from": "babel-plugin-transform-es2015-computed-properties@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.0.14.tgz"
-    },
-    "babel-plugin-transform-es2015-constants": {
-      "version": "6.0.15",
-      "from": "babel-plugin-transform-es2015-constants@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-constants/-/babel-plugin-transform-es2015-constants-6.0.15.tgz"
-    },
-    "babel-plugin-transform-es2015-destructuring": {
-      "version": "6.0.18",
-      "from": "babel-plugin-transform-es2015-destructuring@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.0.18.tgz"
-    },
-    "babel-plugin-transform-es2015-for-of": {
-      "version": "6.0.14",
-      "from": "babel-plugin-transform-es2015-for-of@>=6.0.14 <7.0.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.0.14.tgz"
-    },
-    "babel-plugin-transform-es2015-modules-commonjs": {
-      "version": "6.1.3",
-      "from": "babel-plugin-transform-es2015-modules-commonjs@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.1.3.tgz"
-    },
-    "babel-plugin-transform-es2015-parameters": {
-      "version": "6.0.18",
-      "from": "babel-plugin-transform-es2015-parameters@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.0.18.tgz"
-    },
-    "babel-plugin-transform-es2015-shorthand-properties": {
-      "version": "6.0.14",
-      "from": "babel-plugin-transform-es2015-shorthand-properties@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.0.14.tgz"
-    },
-    "babel-plugin-transform-es2015-spread": {
-      "version": "6.0.14",
-      "from": "babel-plugin-transform-es2015-spread@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.0.14.tgz"
-    },
-    "babel-plugin-transform-es2015-template-literals": {
-      "version": "6.0.14",
-      "from": "babel-plugin-transform-es2015-template-literals@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.0.14.tgz"
-    },
-    "babel-plugin-transform-flow-strip-types": {
-      "version": "6.0.14",
-      "from": "babel-plugin-transform-flow-strip-types@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.0.14.tgz"
-    },
-    "babel-plugin-transform-object-assign": {
-      "version": "6.0.14",
-      "from": "babel-plugin-transform-object-assign@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-assign/-/babel-plugin-transform-object-assign-6.0.14.tgz"
-    },
-    "babel-plugin-transform-object-rest-spread": {
-      "version": "6.0.14",
-      "from": "babel-plugin-transform-object-rest-spread@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.0.14.tgz"
-    },
-    "babel-plugin-transform-react-display-name": {
-      "version": "6.0.14",
-      "from": "babel-plugin-transform-react-display-name@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.0.14.tgz"
-    },
-    "babel-plugin-transform-react-jsx": {
-      "version": "6.0.18",
-      "from": "babel-plugin-transform-react-jsx@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.0.18.tgz"
-    },
-    "babel-plugin-transform-regenerator": {
-      "version": "6.0.18",
-      "from": "babel-plugin-transform-regenerator@*",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.0.18.tgz"
-    },
-    "babel-plugin-transform-strict-mode": {
-      "version": "6.1.2",
-      "from": "babel-plugin-transform-strict-mode@>=6.0.15 <7.0.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.1.2.tgz"
-    },
     "babel-plugin-undeclared-variables-check": {
       "version": "1.0.2",
-      "from": "babel-plugin-undeclared-variables-check@>=1.0.2 <2.0.0",
+      "from": "https://registry.npmjs.org/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz",
       "resolved": "https://registry.npmjs.org/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz"
     },
     "babel-plugin-undefined-to-void": {
       "version": "1.1.6",
-      "from": "babel-plugin-undefined-to-void@>=1.1.6 <2.0.0",
+      "from": "https://registry.npmjs.org/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz",
       "resolved": "https://registry.npmjs.org/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz"
     },
     "babel-polyfill": {
-      "version": "6.0.16",
-      "from": "babel-polyfill@*",
-      "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.0.16.tgz"
+      "version": "6.3.14",
+      "from": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.3.14.tgz",
+      "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.3.14.tgz",
+      "dependencies": {
+        "babel-regenerator-runtime": {
+          "version": "6.3.13",
+          "from": "https://registry.npmjs.org/babel-regenerator-runtime/-/babel-regenerator-runtime-6.3.13.tgz",
+          "resolved": "https://registry.npmjs.org/babel-regenerator-runtime/-/babel-regenerator-runtime-6.3.13.tgz"
+        },
+        "babel-runtime": {
+          "version": "5.8.35",
+          "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+        }
+      }
+    },
+    "babel-preset-react-native": {
+      "version": "1.2.4",
+      "from": "https://registry.npmjs.org/babel-preset-react-native/-/babel-preset-react-native-1.2.4.tgz",
+      "resolved": "https://registry.npmjs.org/babel-preset-react-native/-/babel-preset-react-native-1.2.4.tgz",
+      "dependencies": {
+        "babel-plugin-react-transform": {
+          "version": "2.0.0-beta1",
+          "from": "https://registry.npmjs.org/babel-plugin-react-transform/-/babel-plugin-react-transform-2.0.0-beta1.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-react-transform/-/babel-plugin-react-transform-2.0.0-beta1.tgz",
+          "dependencies": {
+            "array-find": {
+              "version": "1.0.0",
+              "from": "https://registry.npmjs.org/array-find/-/array-find-1.0.0.tgz",
+              "resolved": "https://registry.npmjs.org/array-find/-/array-find-1.0.0.tgz"
+            }
+          }
+        },
+        "babel-plugin-syntax-async-functions": {
+          "version": "6.3.13",
+          "from": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.3.13.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.3.13.tgz",
+          "dependencies": {
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            }
+          }
+        },
+        "babel-plugin-syntax-class-properties": {
+          "version": "6.3.13",
+          "from": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.3.13.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.3.13.tgz",
+          "dependencies": {
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            }
+          }
+        },
+        "babel-plugin-syntax-flow": {
+          "version": "6.3.13",
+          "from": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.3.13.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.3.13.tgz",
+          "dependencies": {
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            }
+          }
+        },
+        "babel-plugin-syntax-jsx": {
+          "version": "6.3.13",
+          "from": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.3.13.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.3.13.tgz",
+          "dependencies": {
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            }
+          }
+        },
+        "babel-plugin-syntax-trailing-function-commas": {
+          "version": "6.3.13",
+          "from": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.3.13.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.3.13.tgz",
+          "dependencies": {
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            }
+          }
+        },
+        "babel-plugin-transform-class-properties": {
+          "version": "6.4.0",
+          "from": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.4.0.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.4.0.tgz",
+          "dependencies": {
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            }
+          }
+        },
+        "babel-plugin-transform-es2015-arrow-functions": {
+          "version": "6.4.0",
+          "from": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.4.0.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.4.0.tgz",
+          "dependencies": {
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            }
+          }
+        },
+        "babel-plugin-transform-es2015-block-scoping": {
+          "version": "6.4.0",
+          "from": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.4.0.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.4.0.tgz",
+          "dependencies": {
+            "babel-traverse": {
+              "version": "6.4.5",
+              "from": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.4.5.tgz",
+              "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.4.5.tgz",
+              "dependencies": {
+                "babel-code-frame": {
+                  "version": "6.3.13",
+                  "from": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.3.13.tgz",
+                  "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.3.13.tgz"
+                },
+                "babel-messages": {
+                  "version": "6.3.18",
+                  "from": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.3.18.tgz",
+                  "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.3.18.tgz"
+                },
+                "globals": {
+                  "version": "8.18.0",
+                  "from": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz",
+                  "resolved": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz"
+                },
+                "invariant": {
+                  "version": "2.2.0",
+                  "from": "https://registry.npmjs.org/invariant/-/invariant-2.2.0.tgz",
+                  "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.0.tgz"
+                }
+              }
+            },
+            "babel-template": {
+              "version": "6.3.13",
+              "from": "https://registry.npmjs.org/babel-template/-/babel-template-6.3.13.tgz",
+              "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.3.13.tgz"
+            },
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            }
+          }
+        },
+        "babel-plugin-transform-es2015-classes": {
+          "version": "6.4.5",
+          "from": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.4.5.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.4.5.tgz",
+          "dependencies": {
+            "babel-helper-optimise-call-expression": {
+              "version": "6.3.13",
+              "from": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.3.13.tgz",
+              "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.3.13.tgz"
+            },
+            "babel-helper-function-name": {
+              "version": "6.4.0",
+              "from": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.4.0.tgz",
+              "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.4.0.tgz",
+              "dependencies": {
+                "babel-helper-get-function-arity": {
+                  "version": "6.3.13",
+                  "from": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.3.13.tgz",
+                  "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.3.13.tgz"
+                }
+              }
+            },
+            "babel-helper-replace-supers": {
+              "version": "6.3.13",
+              "from": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.3.13.tgz",
+              "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.3.13.tgz"
+            },
+            "babel-template": {
+              "version": "6.3.13",
+              "from": "https://registry.npmjs.org/babel-template/-/babel-template-6.3.13.tgz",
+              "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.3.13.tgz"
+            },
+            "babel-traverse": {
+              "version": "6.4.5",
+              "from": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.4.5.tgz",
+              "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.4.5.tgz",
+              "dependencies": {
+                "babel-code-frame": {
+                  "version": "6.3.13",
+                  "from": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.3.13.tgz",
+                  "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.3.13.tgz"
+                },
+                "globals": {
+                  "version": "8.18.0",
+                  "from": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz",
+                  "resolved": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz"
+                },
+                "invariant": {
+                  "version": "2.2.0",
+                  "from": "https://registry.npmjs.org/invariant/-/invariant-2.2.0.tgz",
+                  "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.0.tgz"
+                }
+              }
+            },
+            "babel-helper-define-map": {
+              "version": "6.4.5",
+              "from": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.4.5.tgz",
+              "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.4.5.tgz"
+            },
+            "babel-messages": {
+              "version": "6.3.18",
+              "from": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.3.18.tgz",
+              "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.3.18.tgz"
+            },
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            }
+          }
+        },
+        "babel-plugin-transform-es2015-computed-properties": {
+          "version": "6.4.0",
+          "from": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.4.0.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.4.0.tgz",
+          "dependencies": {
+            "babel-helper-define-map": {
+              "version": "6.4.5",
+              "from": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.4.5.tgz",
+              "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.4.5.tgz",
+              "dependencies": {
+                "babel-helper-function-name": {
+                  "version": "6.4.0",
+                  "from": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.4.0.tgz",
+                  "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.4.0.tgz",
+                  "dependencies": {
+                    "babel-traverse": {
+                      "version": "6.4.5",
+                      "from": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.4.5.tgz",
+                      "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.4.5.tgz",
+                      "dependencies": {
+                        "babel-code-frame": {
+                          "version": "6.3.13",
+                          "from": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.3.13.tgz",
+                          "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.3.13.tgz"
+                        },
+                        "babel-messages": {
+                          "version": "6.3.18",
+                          "from": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.3.18.tgz",
+                          "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.3.18.tgz"
+                        },
+                        "globals": {
+                          "version": "8.18.0",
+                          "from": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz",
+                          "resolved": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz"
+                        },
+                        "invariant": {
+                          "version": "2.2.0",
+                          "from": "https://registry.npmjs.org/invariant/-/invariant-2.2.0.tgz",
+                          "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.0.tgz"
+                        }
+                      }
+                    },
+                    "babel-helper-get-function-arity": {
+                      "version": "6.3.13",
+                      "from": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.3.13.tgz",
+                      "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.3.13.tgz"
+                    }
+                  }
+                }
+              }
+            },
+            "babel-template": {
+              "version": "6.3.13",
+              "from": "https://registry.npmjs.org/babel-template/-/babel-template-6.3.13.tgz",
+              "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.3.13.tgz",
+              "dependencies": {
+                "babel-traverse": {
+                  "version": "6.4.5",
+                  "from": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.4.5.tgz",
+                  "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.4.5.tgz",
+                  "dependencies": {
+                    "babel-code-frame": {
+                      "version": "6.3.13",
+                      "from": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.3.13.tgz",
+                      "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.3.13.tgz"
+                    },
+                    "babel-messages": {
+                      "version": "6.3.18",
+                      "from": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.3.18.tgz",
+                      "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.3.18.tgz"
+                    },
+                    "globals": {
+                      "version": "8.18.0",
+                      "from": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz",
+                      "resolved": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz"
+                    },
+                    "invariant": {
+                      "version": "2.2.0",
+                      "from": "https://registry.npmjs.org/invariant/-/invariant-2.2.0.tgz",
+                      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.0.tgz"
+                    }
+                  }
+                }
+              }
+            },
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            }
+          }
+        },
+        "babel-plugin-transform-es2015-constants": {
+          "version": "6.1.4",
+          "from": "https://registry.npmjs.org/babel-plugin-transform-es2015-constants/-/babel-plugin-transform-es2015-constants-6.1.4.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-constants/-/babel-plugin-transform-es2015-constants-6.1.4.tgz",
+          "dependencies": {
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            }
+          }
+        },
+        "babel-plugin-transform-es2015-destructuring": {
+          "version": "6.4.0",
+          "from": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.4.0.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.4.0.tgz",
+          "dependencies": {
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            }
+          }
+        },
+        "babel-plugin-transform-es2015-for-of": {
+          "version": "6.3.13",
+          "from": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.3.13.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.3.13.tgz",
+          "dependencies": {
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            }
+          }
+        },
+        "babel-plugin-transform-es2015-modules-commonjs": {
+          "version": "6.4.5",
+          "from": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.4.5.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.4.5.tgz",
+          "dependencies": {
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            },
+            "babel-template": {
+              "version": "6.3.13",
+              "from": "https://registry.npmjs.org/babel-template/-/babel-template-6.3.13.tgz",
+              "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.3.13.tgz",
+              "dependencies": {
+                "babel-traverse": {
+                  "version": "6.4.5",
+                  "from": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.4.5.tgz",
+                  "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.4.5.tgz",
+                  "dependencies": {
+                    "babel-code-frame": {
+                      "version": "6.3.13",
+                      "from": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.3.13.tgz",
+                      "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.3.13.tgz"
+                    },
+                    "babel-messages": {
+                      "version": "6.3.18",
+                      "from": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.3.18.tgz",
+                      "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.3.18.tgz"
+                    },
+                    "globals": {
+                      "version": "8.18.0",
+                      "from": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz",
+                      "resolved": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz"
+                    },
+                    "invariant": {
+                      "version": "2.2.0",
+                      "from": "https://registry.npmjs.org/invariant/-/invariant-2.2.0.tgz",
+                      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.0.tgz"
+                    }
+                  }
+                }
+              }
+            },
+            "babel-plugin-transform-strict-mode": {
+              "version": "6.3.13",
+              "from": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.3.13.tgz",
+              "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.3.13.tgz"
+            }
+          }
+        },
+        "babel-plugin-transform-es2015-parameters": {
+          "version": "6.4.5",
+          "from": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.4.5.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.4.5.tgz",
+          "dependencies": {
+            "babel-traverse": {
+              "version": "6.4.5",
+              "from": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.4.5.tgz",
+              "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.4.5.tgz",
+              "dependencies": {
+                "babel-code-frame": {
+                  "version": "6.3.13",
+                  "from": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.3.13.tgz",
+                  "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.3.13.tgz"
+                },
+                "babel-messages": {
+                  "version": "6.3.18",
+                  "from": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.3.18.tgz",
+                  "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.3.18.tgz"
+                },
+                "globals": {
+                  "version": "8.18.0",
+                  "from": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz",
+                  "resolved": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz"
+                },
+                "invariant": {
+                  "version": "2.2.0",
+                  "from": "https://registry.npmjs.org/invariant/-/invariant-2.2.0.tgz",
+                  "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.0.tgz"
+                }
+              }
+            },
+            "babel-helper-call-delegate": {
+              "version": "6.3.13",
+              "from": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.3.13.tgz",
+              "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.3.13.tgz",
+              "dependencies": {
+                "babel-helper-hoist-variables": {
+                  "version": "6.3.13",
+                  "from": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.3.13.tgz",
+                  "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.3.13.tgz"
+                }
+              }
+            },
+            "babel-helper-get-function-arity": {
+              "version": "6.3.13",
+              "from": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.3.13.tgz",
+              "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.3.13.tgz"
+            },
+            "babel-template": {
+              "version": "6.3.13",
+              "from": "https://registry.npmjs.org/babel-template/-/babel-template-6.3.13.tgz",
+              "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.3.13.tgz"
+            },
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            }
+          }
+        },
+        "babel-plugin-transform-es2015-shorthand-properties": {
+          "version": "6.3.13",
+          "from": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.3.13.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.3.13.tgz",
+          "dependencies": {
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            }
+          }
+        },
+        "babel-plugin-transform-es2015-spread": {
+          "version": "6.4.0",
+          "from": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.4.0.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.4.0.tgz",
+          "dependencies": {
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            }
+          }
+        },
+        "babel-plugin-transform-es2015-template-literals": {
+          "version": "6.3.13",
+          "from": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.3.13.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.3.13.tgz",
+          "dependencies": {
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            }
+          }
+        },
+        "babel-plugin-transform-flow-strip-types": {
+          "version": "6.4.0",
+          "from": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.4.0.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.4.0.tgz",
+          "dependencies": {
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            }
+          }
+        },
+        "babel-plugin-transform-object-assign": {
+          "version": "6.3.13",
+          "from": "https://registry.npmjs.org/babel-plugin-transform-object-assign/-/babel-plugin-transform-object-assign-6.3.13.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-assign/-/babel-plugin-transform-object-assign-6.3.13.tgz",
+          "dependencies": {
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            }
+          }
+        },
+        "babel-plugin-transform-object-rest-spread": {
+          "version": "6.3.13",
+          "from": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.3.13.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.3.13.tgz",
+          "dependencies": {
+            "babel-plugin-syntax-object-rest-spread": {
+              "version": "6.3.13",
+              "from": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.3.13.tgz",
+              "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.3.13.tgz"
+            },
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            }
+          }
+        },
+        "babel-plugin-transform-react-display-name": {
+          "version": "6.4.0",
+          "from": "https://registry.npmjs.org/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.4.0.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.4.0.tgz",
+          "dependencies": {
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            }
+          }
+        },
+        "babel-plugin-transform-react-jsx": {
+          "version": "6.4.0",
+          "from": "https://registry.npmjs.org/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.4.0.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.4.0.tgz",
+          "dependencies": {
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            },
+            "babel-helper-builder-react-jsx": {
+              "version": "6.3.13",
+              "from": "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.3.13.tgz",
+              "resolved": "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.3.13.tgz"
+            }
+          }
+        },
+        "babel-plugin-transform-regenerator": {
+          "version": "6.4.4",
+          "from": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.4.4.tgz",
+          "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.4.4.tgz",
+          "dependencies": {
+            "babel-runtime": {
+              "version": "5.8.35",
+              "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+              "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+            },
+            "babel-traverse": {
+              "version": "6.4.5",
+              "from": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.4.5.tgz",
+              "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.4.5.tgz",
+              "dependencies": {
+                "babel-code-frame": {
+                  "version": "6.3.13",
+                  "from": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.3.13.tgz",
+                  "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.3.13.tgz"
+                },
+                "babel-messages": {
+                  "version": "6.3.18",
+                  "from": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.3.18.tgz",
+                  "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.3.18.tgz"
+                },
+                "globals": {
+                  "version": "8.18.0",
+                  "from": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz",
+                  "resolved": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz"
+                },
+                "invariant": {
+                  "version": "2.2.0",
+                  "from": "https://registry.npmjs.org/invariant/-/invariant-2.2.0.tgz",
+                  "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.0.tgz"
+                }
+              }
+            }
+          }
+        }
+      }
     },
     "babel-register": {
-      "version": "6.1.18",
-      "from": "babel-register@>=6.1.18 <7.0.0",
-      "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.1.18.tgz"
-    },
-    "babel-runtime": {
-      "version": "5.8.29",
-      "from": "babel-runtime@>=5.0.0 <6.0.0",
-      "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.29.tgz"
-    },
-    "babel-template": {
-      "version": "6.0.16",
-      "from": "babel-template@>=6.0.16 <7.0.0",
-      "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.0.16.tgz"
-    },
-    "babel-traverse": {
-      "version": "6.1.2",
-      "from": "babel-traverse@>=6.1.2 <7.0.0",
-      "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.1.2.tgz"
+      "version": "6.4.3",
+      "from": "https://registry.npmjs.org/babel-register/-/babel-register-6.4.3.tgz",
+      "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.4.3.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "5.8.35",
+          "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+        }
+      }
     },
     "babel-types": {
-      "version": "6.1.2",
-      "from": "babel-types@*",
-      "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.1.2.tgz"
+      "version": "6.4.5",
+      "from": "https://registry.npmjs.org/babel-types/-/babel-types-6.4.5.tgz",
+      "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.4.5.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "5.8.35",
+          "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+        },
+        "babel-traverse": {
+          "version": "6.4.5",
+          "from": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.4.5.tgz",
+          "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.4.5.tgz",
+          "dependencies": {
+            "babel-code-frame": {
+              "version": "6.3.13",
+              "from": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.3.13.tgz",
+              "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.3.13.tgz"
+            },
+            "babel-messages": {
+              "version": "6.3.18",
+              "from": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.3.18.tgz",
+              "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.3.18.tgz"
+            },
+            "globals": {
+              "version": "8.18.0",
+              "from": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz",
+              "resolved": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz"
+            },
+            "invariant": {
+              "version": "2.2.0",
+              "from": "https://registry.npmjs.org/invariant/-/invariant-2.2.0.tgz",
+              "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.0.tgz"
+            }
+          }
+        }
+      }
     },
     "babylon": {
-      "version": "6.1.2",
-      "from": "babylon@*",
-      "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.1.2.tgz"
+      "version": "6.4.5",
+      "from": "https://registry.npmjs.org/babylon/-/babylon-6.4.5.tgz",
+      "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.4.5.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "5.8.35",
+          "from": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.35.tgz"
+        }
+      }
     },
     "balanced-match": {
       "version": "0.2.1",
-      "from": "balanced-match@>=0.2.0 <0.3.0",
+      "from": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.1.tgz",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.1.tgz"
     },
     "base64-js": {
       "version": "0.0.8",
-      "from": "base64-js@0.0.8",
+      "from": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz",
       "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz"
     },
     "beeper": {
       "version": "1.1.0",
-      "from": "beeper@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/beeper/-/beeper-1.1.0.tgz",
       "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.0.tgz"
     },
     "binary-extensions": {
       "version": "1.3.1",
-      "from": "binary-extensions@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.3.1.tgz",
       "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.3.1.tgz"
     },
     "bluebird": {
       "version": "2.10.2",
-      "from": "bluebird@>=2.9.33 <3.0.0",
+      "from": "https://registry.npmjs.org/bluebird/-/bluebird-2.10.2.tgz",
       "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.10.2.tgz"
     },
     "brace-expansion": {
       "version": "1.1.1",
-      "from": "brace-expansion@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz"
     },
     "braces": {
       "version": "1.8.2",
-      "from": "braces@>=1.8.0 <2.0.0",
+      "from": "https://registry.npmjs.org/braces/-/braces-1.8.2.tgz",
       "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.2.tgz"
     },
     "breakable": {
       "version": "1.0.0",
-      "from": "breakable@>=1.0.0 <1.1.0",
+      "from": "https://registry.npmjs.org/breakable/-/breakable-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/breakable/-/breakable-1.0.0.tgz"
     },
     "bser": {
       "version": "1.0.2",
-      "from": "bser@1.0.2",
+      "from": "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz",
       "resolved": "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz",
       "dependencies": {
         "node-int64": {
           "version": "0.4.0",
-          "from": "node-int64@>=0.4.0 <0.5.0",
+          "from": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
           "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz"
         }
       }
     },
     "builtin-modules": {
       "version": "1.1.0",
-      "from": "builtin-modules@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.0.tgz",
       "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.0.tgz"
     },
     "camelcase": {
       "version": "1.2.1",
-      "from": "camelcase@>=1.2.1 <2.0.0",
+      "from": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
       "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz"
     },
     "camelcase-keys": {
       "version": "1.0.0",
-      "from": "camelcase-keys@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-1.0.0.tgz"
     },
     "center-align": {
       "version": "0.1.2",
-      "from": "center-align@>=0.1.1 <0.2.0",
+      "from": "https://registry.npmjs.org/center-align/-/center-align-0.1.2.tgz",
       "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.2.tgz"
     },
     "chalk": {
       "version": "1.1.1",
-      "from": "chalk@>=1.1.1 <2.0.0",
+      "from": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz",
       "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz"
     },
     "chokidar": {
       "version": "1.2.0",
-      "from": "chokidar@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/chokidar/-/chokidar-1.2.0.tgz",
       "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.2.0.tgz"
     },
     "cliui": {
       "version": "2.1.0",
-      "from": "cliui@>=2.1.0 <3.0.0",
+      "from": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
       "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
       "dependencies": {
         "wordwrap": {
           "version": "0.0.2",
-          "from": "wordwrap@0.0.2",
+          "from": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
           "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz"
         }
       }
     },
     "clone": {
       "version": "1.0.2",
-      "from": "clone@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz",
       "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz"
     },
     "clone-stats": {
       "version": "0.0.1",
-      "from": "clone-stats@>=0.0.1 <0.0.2",
+      "from": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz",
       "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz"
     },
     "commander": {
       "version": "2.9.0",
-      "from": "commander@>=2.5.0 <3.0.0",
+      "from": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
       "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz"
     },
     "commoner": {
       "version": "0.10.4",
-      "from": "commoner@>=0.10.3 <0.11.0",
-      "dependencies": {
-        "graceful-fs": {
-          "version": "4.1.2",
-          "from": "graceful-fs@>=4.1.2 <5.0.0"
-        }
-      }
+      "from": "commoner@0.10.4",
+      "resolved": "https://registry.npmjs.org/commoner/-/commoner-0.10.4.tgz"
     },
     "concat-map": {
       "version": "0.0.1",
-      "from": "concat-map@0.0.1",
+      "from": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
     },
     "connect": {
       "version": "2.8.3",
-      "from": "connect@2.8.3",
+      "from": "https://registry.npmjs.org/connect/-/connect-2.8.3.tgz",
       "resolved": "https://registry.npmjs.org/connect/-/connect-2.8.3.tgz",
       "dependencies": {
         "qs": {
           "version": "0.6.5",
-          "from": "qs@0.6.5",
+          "from": "https://registry.npmjs.org/qs/-/qs-0.6.5.tgz",
           "resolved": "https://registry.npmjs.org/qs/-/qs-0.6.5.tgz"
         },
         "formidable": {
           "version": "1.0.14",
-          "from": "formidable@1.0.14",
+          "from": "https://registry.npmjs.org/formidable/-/formidable-1.0.14.tgz",
           "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.0.14.tgz"
         },
         "cookie-signature": {
           "version": "1.0.1",
-          "from": "cookie-signature@1.0.1",
+          "from": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.1.tgz",
           "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.1.tgz"
         },
         "buffer-crc32": {
           "version": "0.2.1",
-          "from": "buffer-crc32@0.2.1",
+          "from": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.1.tgz",
           "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.1.tgz"
         },
         "cookie": {
           "version": "0.1.0",
-          "from": "cookie@0.1.0",
+          "from": "https://registry.npmjs.org/cookie/-/cookie-0.1.0.tgz",
           "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.0.tgz"
         },
         "send": {
           "version": "0.1.2",
-          "from": "send@0.1.2",
+          "from": "https://registry.npmjs.org/send/-/send-0.1.2.tgz",
           "resolved": "https://registry.npmjs.org/send/-/send-0.1.2.tgz",
           "dependencies": {
             "mime": {
               "version": "1.2.11",
-              "from": "mime@>=1.2.9 <1.3.0",
+              "from": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz",
               "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz"
             },
             "range-parser": {
               "version": "0.0.4",
-              "from": "range-parser@0.0.4",
+              "from": "https://registry.npmjs.org/range-parser/-/range-parser-0.0.4.tgz",
               "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-0.0.4.tgz"
             }
           }
         },
         "bytes": {
           "version": "0.2.0",
-          "from": "bytes@0.2.0",
+          "from": "https://registry.npmjs.org/bytes/-/bytes-0.2.0.tgz",
           "resolved": "https://registry.npmjs.org/bytes/-/bytes-0.2.0.tgz"
         },
         "fresh": {
           "version": "0.1.0",
-          "from": "fresh@0.1.0",
+          "from": "https://registry.npmjs.org/fresh/-/fresh-0.1.0.tgz",
           "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.1.0.tgz"
         },
         "pause": {
           "version": "0.0.1",
-          "from": "pause@0.0.1",
+          "from": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
           "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz"
         },
         "uid2": {
           "version": "0.0.2",
-          "from": "uid2@0.0.2",
+          "from": "https://registry.npmjs.org/uid2/-/uid2-0.0.2.tgz",
           "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.2.tgz"
         },
-        "debug": {
-          "version": "2.2.0",
-          "from": "debug@*"
-        },
         "methods": {
           "version": "0.0.1",
-          "from": "methods@0.0.1",
+          "from": "https://registry.npmjs.org/methods/-/methods-0.0.1.tgz",
           "resolved": "https://registry.npmjs.org/methods/-/methods-0.0.1.tgz"
         }
       }
     },
     "convert-source-map": {
       "version": "1.1.1",
-      "from": "convert-source-map@>=1.1.0 <2.0.0",
+      "from": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.1.tgz",
       "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.1.tgz"
     },
     "core-js": {
       "version": "1.2.6",
-      "from": "core-js@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/core-js/-/core-js-1.2.6.tgz",
       "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.6.tgz"
     },
     "core-util-is": {
       "version": "1.0.1",
-      "from": "core-util-is@>=1.0.0 <1.1.0",
+      "from": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
     },
     "dateformat": {
       "version": "1.0.11",
-      "from": "dateformat@>=1.0.11 <2.0.0",
+      "from": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.11.tgz",
       "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.11.tgz"
     },
     "debug": {
       "version": "2.2.0",
-      "from": "debug@>=2.2.0 <3.0.0",
+      "from": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
       "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz"
     },
     "decamelize": {
       "version": "1.1.1",
-      "from": "decamelize@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/decamelize/-/decamelize-1.1.1.tgz",
       "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.1.1.tgz"
     },
     "defined": {
       "version": "1.0.0",
-      "from": "defined@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz"
     },
     "defs": {
       "version": "1.1.1",
-      "from": "defs@>=1.1.0 <1.2.0",
+      "from": "https://registry.npmjs.org/defs/-/defs-1.1.1.tgz",
       "resolved": "https://registry.npmjs.org/defs/-/defs-1.1.1.tgz",
       "dependencies": {
         "yargs": {
           "version": "3.27.0",
-          "from": "yargs@>=3.27.0 <3.28.0",
+          "from": "https://registry.npmjs.org/yargs/-/yargs-3.27.0.tgz",
           "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.27.0.tgz"
         }
       }
     },
     "detect-indent": {
       "version": "3.0.1",
-      "from": "detect-indent@>=3.0.1 <4.0.0",
+      "from": "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz",
       "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz"
     },
     "detective": {
       "version": "4.3.1",
-      "from": "detective@>=4.3.1 <5.0.0",
+      "from": "https://registry.npmjs.org/detective/-/detective-4.3.1.tgz",
       "resolved": "https://registry.npmjs.org/detective/-/detective-4.3.1.tgz"
     },
     "duplexer2": {
       "version": "0.0.2",
-      "from": "duplexer2@0.0.2",
+      "from": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz",
       "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz",
       "dependencies": {
         "readable-stream": {
           "version": "1.1.13",
-          "from": "readable-stream@>=1.1.9 <1.2.0",
+          "from": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz",
           "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz"
         }
       }
     },
     "error-ex": {
       "version": "1.3.0",
-      "from": "error-ex@>=1.2.0 <2.0.0",
+      "from": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.0.tgz",
       "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.0.tgz"
     },
     "escape-string-regexp": {
       "version": "1.0.3",
-      "from": "escape-string-regexp@>=1.0.2 <2.0.0",
+      "from": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz",
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz"
     },
     "eslint": {
       "version": "1.3.1",
-      "from": "eslint@1.3.1",
+      "from": "https://registry.npmjs.org/eslint/-/eslint-1.3.1.tgz",
       "resolved": "https://registry.npmjs.org/eslint/-/eslint-1.3.1.tgz",
       "dependencies": {
-        "chalk": {
-          "version": "1.1.1",
-          "from": "chalk@>=1.0.0 <2.0.0"
-        },
         "concat-stream": {
           "version": "1.5.0",
-          "from": "concat-stream@>=1.4.6 <2.0.0",
+          "from": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz",
           "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz",
           "dependencies": {
-            "inherits": {
-              "version": "2.0.1",
-              "from": "inherits@>=2.0.1 <2.1.0",
-              "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-            },
             "typedarray": {
               "version": "0.0.6",
-              "from": "typedarray@>=0.0.5 <0.1.0",
+              "from": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
               "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
             },
             "readable-stream": {
               "version": "2.0.2",
-              "from": "readable-stream@>=2.0.0 <2.1.0",
+              "from": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz",
               "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz",
               "dependencies": {
-                "core-util-is": {
-                  "version": "1.0.1",
-                  "from": "core-util-is@>=1.0.0 <1.1.0",
-                  "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-                },
-                "isarray": {
-                  "version": "0.0.1",
-                  "from": "isarray@0.0.1",
-                  "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
-                },
                 "process-nextick-args": {
                   "version": "1.0.2",
-                  "from": "process-nextick-args@>=1.0.0 <1.1.0",
+                  "from": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.2.tgz",
                   "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.2.tgz"
                 },
-                "string_decoder": {
-                  "version": "0.10.31",
-                  "from": "string_decoder@>=0.10.0 <0.11.0",
-                  "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
-                },
                 "util-deprecate": {
                   "version": "1.0.1",
-                  "from": "util-deprecate@>=1.0.1 <1.1.0",
+                  "from": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.1.tgz",
                   "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.1.tgz"
                 }
               }
             }
           }
         },
-        "debug": {
-          "version": "2.2.0",
-          "from": "debug@>=2.1.1 <3.0.0"
-        },
         "doctrine": {
           "version": "0.6.4",
-          "from": "doctrine@>=0.6.2 <0.7.0",
+          "from": "https://registry.npmjs.org/doctrine/-/doctrine-0.6.4.tgz",
           "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-0.6.4.tgz",
           "dependencies": {
             "esutils": {
               "version": "1.1.6",
-              "from": "esutils@>=1.1.6 <2.0.0",
+              "from": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz",
               "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz"
-            },
-            "isarray": {
-              "version": "0.0.1",
-              "from": "isarray@0.0.1",
-              "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
             }
           }
         },
-        "escape-string-regexp": {
-          "version": "1.0.3",
-          "from": "escape-string-regexp@>=1.0.2 <2.0.0",
-          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz"
-        },
         "escope": {
           "version": "3.2.0",
-          "from": "escope@>=3.2.0 <4.0.0",
+          "from": "https://registry.npmjs.org/escope/-/escope-3.2.0.tgz",
           "resolved": "https://registry.npmjs.org/escope/-/escope-3.2.0.tgz",
           "dependencies": {
             "es6-map": {
               "version": "0.1.1",
-              "from": "es6-map@>=0.1.1 <0.2.0",
+              "from": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.1.tgz",
               "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.1.tgz",
               "dependencies": {
                 "d": {
                   "version": "0.1.1",
-                  "from": "d@>=0.1.1 <0.2.0",
+                  "from": "https://registry.npmjs.org/d/-/d-0.1.1.tgz",
                   "resolved": "https://registry.npmjs.org/d/-/d-0.1.1.tgz"
                 },
                 "es5-ext": {
                   "version": "0.10.7",
-                  "from": "es5-ext@>=0.10.4 <0.11.0",
+                  "from": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.7.tgz",
                   "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.7.tgz",
                   "dependencies": {
                     "es6-symbol": {
                       "version": "2.0.1",
-                      "from": "es6-symbol@>=2.0.1 <2.1.0",
+                      "from": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-2.0.1.tgz",
                       "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-2.0.1.tgz"
                     }
                   }
                 },
                 "es6-iterator": {
                   "version": "0.1.3",
-                  "from": "es6-iterator@>=0.1.1 <0.2.0",
+                  "from": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-0.1.3.tgz",
                   "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-0.1.3.tgz",
                   "dependencies": {
                     "es6-symbol": {
                       "version": "2.0.1",
-                      "from": "es6-symbol@>=2.0.1 <2.1.0",
+                      "from": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-2.0.1.tgz",
                       "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-2.0.1.tgz"
                     }
                   }
                 },
                 "es6-set": {
                   "version": "0.1.1",
-                  "from": "es6-set@>=0.1.1 <0.2.0",
+                  "from": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.1.tgz",
                   "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.1.tgz"
                 },
                 "es6-symbol": {
                   "version": "0.1.1",
-                  "from": "es6-symbol@>=0.1.1 <0.2.0",
+                  "from": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-0.1.1.tgz",
                   "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-0.1.1.tgz"
                 },
                 "event-emitter": {
                   "version": "0.3.3",
-                  "from": "event-emitter@>=0.3.1 <0.4.0",
+                  "from": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.3.tgz",
                   "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.3.tgz"
                 }
               }
             },
             "es6-weak-map": {
               "version": "0.1.4",
-              "from": "es6-weak-map@>=0.1.2 <0.2.0",
+              "from": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-0.1.4.tgz",
               "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-0.1.4.tgz",
               "dependencies": {
                 "d": {
                   "version": "0.1.1",
-                  "from": "d@>=0.1.1 <0.2.0",
+                  "from": "https://registry.npmjs.org/d/-/d-0.1.1.tgz",
                   "resolved": "https://registry.npmjs.org/d/-/d-0.1.1.tgz"
                 },
                 "es5-ext": {
                   "version": "0.10.7",
-                  "from": "es5-ext@>=0.10.6 <0.11.0",
+                  "from": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.7.tgz",
                   "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.7.tgz"
                 },
                 "es6-iterator": {
                   "version": "0.1.3",
-                  "from": "es6-iterator@>=0.1.3 <0.2.0",
+                  "from": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-0.1.3.tgz",
                   "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-0.1.3.tgz"
                 },
                 "es6-symbol": {
                   "version": "2.0.1",
-                  "from": "es6-symbol@>=2.0.1 <2.1.0",
+                  "from": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-2.0.1.tgz",
                   "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-2.0.1.tgz"
                 }
               }
             },
             "esrecurse": {
               "version": "3.1.1",
-              "from": "esrecurse@>=3.1.1 <4.0.0",
+              "from": "https://registry.npmjs.org/esrecurse/-/esrecurse-3.1.1.tgz",
               "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-3.1.1.tgz"
             },
             "estraverse": {
               "version": "3.1.0",
-              "from": "estraverse@>=3.1.0 <4.0.0",
+              "from": "https://registry.npmjs.org/estraverse/-/estraverse-3.1.0.tgz",
               "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-3.1.0.tgz"
             }
           }
         },
         "espree": {
           "version": "2.2.4",
-          "from": "espree@>=2.2.4 <3.0.0",
+          "from": "https://registry.npmjs.org/espree/-/espree-2.2.4.tgz",
           "resolved": "https://registry.npmjs.org/espree/-/espree-2.2.4.tgz"
         },
         "estraverse": {
           "version": "4.1.0",
-          "from": "estraverse@>=4.1.0 <5.0.0",
+          "from": "https://registry.npmjs.org/estraverse/-/estraverse-4.1.0.tgz",
           "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.1.0.tgz"
         },
         "estraverse-fb": {
           "version": "1.3.1",
-          "from": "estraverse-fb@>=1.3.1 <2.0.0",
+          "from": "https://registry.npmjs.org/estraverse-fb/-/estraverse-fb-1.3.1.tgz",
           "resolved": "https://registry.npmjs.org/estraverse-fb/-/estraverse-fb-1.3.1.tgz"
         },
         "globals": {
           "version": "8.7.0",
-          "from": "globals@>=8.5.0 <9.0.0",
+          "from": "https://registry.npmjs.org/globals/-/globals-8.7.0.tgz",
           "resolved": "https://registry.npmjs.org/globals/-/globals-8.7.0.tgz"
         },
         "handlebars": {
           "version": "3.0.3",
-          "from": "handlebars@>=3.0.3 <4.0.0",
+          "from": "https://registry.npmjs.org/handlebars/-/handlebars-3.0.3.tgz",
           "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-3.0.3.tgz",
           "dependencies": {
             "source-map": {
               "version": "0.1.43",
-              "from": "source-map@>=0.1.40 <0.2.0",
-              "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz",
-              "dependencies": {
-                "amdefine": {
-                  "version": "1.0.0",
-                  "from": "amdefine@>=0.0.4",
-                  "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz"
-                }
-              }
+              "from": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz",
+              "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz"
             },
             "uglify-js": {
               "version": "2.3.6",
-              "from": "uglify-js@>=2.3.0 <2.4.0",
+              "from": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.3.6.tgz",
               "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.3.6.tgz",
               "dependencies": {
                 "async": {
                   "version": "0.2.10",
-                  "from": "async@>=0.2.6 <0.3.0",
+                  "from": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
                   "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz"
                 },
                 "optimist": {
                   "version": "0.3.7",
-                  "from": "optimist@>=0.3.5 <0.4.0",
+                  "from": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz",
                   "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz",
                   "dependencies": {
                     "wordwrap": {
                       "version": "0.0.3",
-                      "from": "wordwrap@>=0.0.2 <0.1.0",
+                      "from": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
                       "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
                     }
                   }
@@ -1194,47 +1501,37 @@
         },
         "inquirer": {
           "version": "0.9.0",
-          "from": "inquirer@>=0.9.0 <0.10.0",
+          "from": "https://registry.npmjs.org/inquirer/-/inquirer-0.9.0.tgz",
           "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.9.0.tgz",
           "dependencies": {
-            "ansi-regex": {
-              "version": "2.0.0",
-              "from": "ansi-regex@>=2.0.0 <3.0.0",
-              "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
-            },
             "cli-width": {
               "version": "1.0.1",
-              "from": "cli-width@>=1.0.1 <2.0.0",
+              "from": "https://registry.npmjs.org/cli-width/-/cli-width-1.0.1.tgz",
               "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-1.0.1.tgz"
             },
             "figures": {
               "version": "1.3.5",
-              "from": "figures@>=1.3.5 <2.0.0",
+              "from": "https://registry.npmjs.org/figures/-/figures-1.3.5.tgz",
               "resolved": "https://registry.npmjs.org/figures/-/figures-1.3.5.tgz"
             },
-            "lodash": {
-              "version": "3.10.1",
-              "from": "lodash@>=3.3.1 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz"
-            },
             "readline2": {
               "version": "0.1.1",
-              "from": "readline2@>=0.1.1 <0.2.0",
+              "from": "https://registry.npmjs.org/readline2/-/readline2-0.1.1.tgz",
               "resolved": "https://registry.npmjs.org/readline2/-/readline2-0.1.1.tgz",
               "dependencies": {
                 "mute-stream": {
                   "version": "0.0.4",
-                  "from": "mute-stream@0.0.4",
+                  "from": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.4.tgz",
                   "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.4.tgz"
                 },
                 "strip-ansi": {
                   "version": "2.0.1",
-                  "from": "strip-ansi@>=2.0.1 <3.0.0",
+                  "from": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz",
                   "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz",
                   "dependencies": {
                     "ansi-regex": {
                       "version": "1.1.1",
-                      "from": "ansi-regex@>=1.0.0 <2.0.0",
+                      "from": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz",
                       "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz"
                     }
                   }
@@ -1243,602 +1540,342 @@
             },
             "run-async": {
               "version": "0.1.0",
-              "from": "run-async@>=0.1.0 <0.2.0",
-              "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz",
-              "dependencies": {
-                "once": {
-                  "version": "1.3.2",
-                  "from": "once@>=1.3.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz",
-                  "dependencies": {
-                    "wrappy": {
-                      "version": "1.0.1",
-                      "from": "wrappy@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
-                    }
-                  }
-                }
-              }
+              "from": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz",
+              "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz"
             },
             "rx-lite": {
               "version": "2.5.2",
-              "from": "rx-lite@>=2.5.2 <3.0.0",
+              "from": "https://registry.npmjs.org/rx-lite/-/rx-lite-2.5.2.tgz",
               "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-2.5.2.tgz"
-            },
-            "strip-ansi": {
-              "version": "3.0.0",
-              "from": "strip-ansi@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz"
-            },
-            "through": {
-              "version": "2.3.8",
-              "from": "through@>=2.3.6 <3.0.0",
-              "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
             }
           }
         },
         "is-my-json-valid": {
           "version": "2.12.2",
-          "from": "is-my-json-valid@>=2.10.0 <3.0.0",
+          "from": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.2.tgz",
           "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.2.tgz",
           "dependencies": {
             "generate-function": {
               "version": "2.0.0",
-              "from": "generate-function@>=2.0.0 <3.0.0",
+              "from": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz",
               "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz"
             },
             "generate-object-property": {
               "version": "1.2.0",
-              "from": "generate-object-property@>=1.1.0 <2.0.0",
+              "from": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
               "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
               "dependencies": {
                 "is-property": {
                   "version": "1.0.2",
-                  "from": "is-property@>=1.0.0 <2.0.0",
+                  "from": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
                   "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz"
                 }
               }
             },
             "jsonpointer": {
               "version": "2.0.0",
-              "from": "jsonpointer@2.0.0",
+              "from": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz",
               "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
             },
             "xtend": {
               "version": "4.0.0",
-              "from": "xtend@>=4.0.0 <5.0.0",
+              "from": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz",
               "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz"
             }
           }
         },
         "is-resolvable": {
           "version": "1.0.0",
-          "from": "is-resolvable@>=1.0.0 <2.0.0",
+          "from": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz",
           "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz",
           "dependencies": {
             "tryit": {
               "version": "1.0.1",
-              "from": "tryit@>=1.0.1 <2.0.0",
+              "from": "https://registry.npmjs.org/tryit/-/tryit-1.0.1.tgz",
               "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.1.tgz"
             }
           }
         },
         "js-yaml": {
           "version": "3.4.0",
-          "from": "js-yaml@>=3.0.0 <4.0.0",
+          "from": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.4.0.tgz",
           "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.4.0.tgz",
           "dependencies": {
             "argparse": {
               "version": "1.0.2",
-              "from": "argparse@>=1.0.2 <1.1.0",
+              "from": "https://registry.npmjs.org/argparse/-/argparse-1.0.2.tgz",
               "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.2.tgz",
               "dependencies": {
-                "lodash": {
-                  "version": "3.10.1",
-                  "from": "lodash@>=3.2.0 <4.0.0",
-                  "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz"
-                },
                 "sprintf-js": {
                   "version": "1.0.3",
-                  "from": "sprintf-js@>=1.0.2 <1.1.0",
+                  "from": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
                   "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz"
                 }
               }
             },
             "esprima": {
               "version": "2.2.0",
-              "from": "esprima@>=2.2.0 <2.3.0",
+              "from": "https://registry.npmjs.org/esprima/-/esprima-2.2.0.tgz",
               "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.2.0.tgz"
             }
           }
         },
         "lodash.clonedeep": {
           "version": "3.0.2",
-          "from": "lodash.clonedeep@>=3.0.1 <4.0.0",
+          "from": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-3.0.2.tgz",
           "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-3.0.2.tgz",
           "dependencies": {
             "lodash._baseclone": {
               "version": "3.3.0",
-              "from": "lodash._baseclone@>=3.0.0 <4.0.0",
+              "from": "https://registry.npmjs.org/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz",
               "resolved": "https://registry.npmjs.org/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz",
               "dependencies": {
                 "lodash._arraycopy": {
                   "version": "3.0.0",
-                  "from": "lodash._arraycopy@>=3.0.0 <4.0.0",
+                  "from": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz"
                 },
                 "lodash._arrayeach": {
                   "version": "3.0.0",
-                  "from": "lodash._arrayeach@>=3.0.0 <4.0.0",
+                  "from": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz"
-                },
-                "lodash._baseassign": {
-                  "version": "3.2.0",
-                  "from": "lodash._baseassign@>=3.0.0 <4.0.0",
-                  "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz",
-                  "dependencies": {
-                    "lodash._basecopy": {
-                      "version": "3.0.1",
-                      "from": "lodash._basecopy@>=3.0.0 <4.0.0",
-                      "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz"
-                    }
-                  }
-                },
-                "lodash._basefor": {
-                  "version": "3.0.2",
-                  "from": "lodash._basefor@>=3.0.0 <4.0.0",
-                  "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.2.tgz"
-                },
-                "lodash.isarray": {
-                  "version": "3.0.4",
-                  "from": "lodash.isarray@>=3.0.0 <4.0.0",
-                  "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz"
-                },
-                "lodash.keys": {
-                  "version": "3.1.2",
-                  "from": "lodash.keys@>=3.0.0 <4.0.0",
-                  "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",
-                  "dependencies": {
-                    "lodash._getnative": {
-                      "version": "3.9.1",
-                      "from": "lodash._getnative@>=3.0.0 <4.0.0",
-                      "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz"
-                    },
-                    "lodash.isarguments": {
-                      "version": "3.0.4",
-                      "from": "lodash.isarguments@>=3.0.0 <4.0.0",
-                      "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.4.tgz"
-                    }
-                  }
                 }
               }
-            },
-            "lodash._bindcallback": {
-              "version": "3.0.1",
-              "from": "lodash._bindcallback@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz"
             }
           }
         },
         "lodash.merge": {
           "version": "3.3.2",
-          "from": "lodash.merge@>=3.3.2 <4.0.0",
+          "from": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-3.3.2.tgz",
           "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-3.3.2.tgz",
           "dependencies": {
             "lodash._arraycopy": {
               "version": "3.0.0",
-              "from": "lodash._arraycopy@>=3.0.0 <4.0.0",
+              "from": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz",
               "resolved": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz"
             },
             "lodash._arrayeach": {
               "version": "3.0.0",
-              "from": "lodash._arrayeach@>=3.0.0 <4.0.0",
+              "from": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz",
               "resolved": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz"
             },
-            "lodash._createassigner": {
-              "version": "3.1.1",
-              "from": "lodash._createassigner@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz",
-              "dependencies": {
-                "lodash._bindcallback": {
-                  "version": "3.0.1",
-                  "from": "lodash._bindcallback@>=3.0.0 <4.0.0",
-                  "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz"
-                },
-                "lodash._isiterateecall": {
-                  "version": "3.0.9",
-                  "from": "lodash._isiterateecall@>=3.0.0 <4.0.0",
-                  "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz"
-                },
-                "lodash.restparam": {
-                  "version": "3.6.1",
-                  "from": "lodash.restparam@>=3.0.0 <4.0.0",
-                  "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz"
-                }
-              }
-            },
-            "lodash._getnative": {
-              "version": "3.9.1",
-              "from": "lodash._getnative@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz"
-            },
-            "lodash.isarguments": {
-              "version": "3.0.4",
-              "from": "lodash.isarguments@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.4.tgz"
-            },
-            "lodash.isarray": {
-              "version": "3.0.4",
-              "from": "lodash.isarray@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz"
-            },
             "lodash.isplainobject": {
               "version": "3.2.0",
-              "from": "lodash.isplainobject@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz",
-              "dependencies": {
-                "lodash._basefor": {
-                  "version": "3.0.2",
-                  "from": "lodash._basefor@>=3.0.0 <4.0.0",
-                  "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.2.tgz"
-                }
-              }
+              "from": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz",
+              "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz"
             },
             "lodash.istypedarray": {
               "version": "3.0.2",
-              "from": "lodash.istypedarray@>=3.0.0 <4.0.0",
+              "from": "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.2.tgz",
               "resolved": "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.2.tgz"
             },
-            "lodash.keys": {
-              "version": "3.1.2",
-              "from": "lodash.keys@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz"
-            },
-            "lodash.keysin": {
-              "version": "3.0.8",
-              "from": "lodash.keysin@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz"
-            },
             "lodash.toplainobject": {
               "version": "3.0.0",
-              "from": "lodash.toplainobject@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz",
-              "dependencies": {
-                "lodash._basecopy": {
-                  "version": "3.0.1",
-                  "from": "lodash._basecopy@>=3.0.0 <4.0.0",
-                  "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz"
-                }
-              }
+              "from": "https://registry.npmjs.org/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz",
+              "resolved": "https://registry.npmjs.org/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz"
             }
           }
         },
         "lodash.omit": {
           "version": "3.1.0",
-          "from": "lodash.omit@>=3.1.0 <4.0.0",
+          "from": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-3.1.0.tgz",
           "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-3.1.0.tgz",
           "dependencies": {
             "lodash._arraymap": {
               "version": "3.0.0",
-              "from": "lodash._arraymap@>=3.0.0 <4.0.0",
+              "from": "https://registry.npmjs.org/lodash._arraymap/-/lodash._arraymap-3.0.0.tgz",
               "resolved": "https://registry.npmjs.org/lodash._arraymap/-/lodash._arraymap-3.0.0.tgz"
             },
             "lodash._basedifference": {
               "version": "3.0.3",
-              "from": "lodash._basedifference@>=3.0.0 <4.0.0",
+              "from": "https://registry.npmjs.org/lodash._basedifference/-/lodash._basedifference-3.0.3.tgz",
               "resolved": "https://registry.npmjs.org/lodash._basedifference/-/lodash._basedifference-3.0.3.tgz",
               "dependencies": {
                 "lodash._baseindexof": {
                   "version": "3.1.0",
-                  "from": "lodash._baseindexof@>=3.0.0 <4.0.0",
+                  "from": "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz",
                   "resolved": "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz"
                 },
                 "lodash._cacheindexof": {
                   "version": "3.0.2",
-                  "from": "lodash._cacheindexof@>=3.0.0 <4.0.0",
+                  "from": "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz",
                   "resolved": "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz"
                 },
                 "lodash._createcache": {
                   "version": "3.1.2",
-                  "from": "lodash._createcache@>=3.0.0 <4.0.0",
-                  "resolved": "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz",
-                  "dependencies": {
-                    "lodash._getnative": {
-                      "version": "3.9.1",
-                      "from": "lodash._getnative@>=3.0.0 <4.0.0",
-                      "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz"
-                    }
-                  }
-                }
-              }
-            },
-            "lodash._baseflatten": {
-              "version": "3.1.4",
-              "from": "lodash._baseflatten@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz",
-              "dependencies": {
-                "lodash.isarguments": {
-                  "version": "3.0.4",
-                  "from": "lodash.isarguments@>=3.0.0 <4.0.0",
-                  "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.4.tgz"
-                },
-                "lodash.isarray": {
-                  "version": "3.0.4",
-                  "from": "lodash.isarray@>=3.0.0 <4.0.0",
-                  "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz"
-                }
-              }
-            },
-            "lodash._bindcallback": {
-              "version": "3.0.1",
-              "from": "lodash._bindcallback@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz"
-            },
-            "lodash._pickbyarray": {
-              "version": "3.0.2",
-              "from": "lodash._pickbyarray@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash._pickbyarray/-/lodash._pickbyarray-3.0.2.tgz"
-            },
-            "lodash._pickbycallback": {
-              "version": "3.0.0",
-              "from": "lodash._pickbycallback@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash._pickbycallback/-/lodash._pickbycallback-3.0.0.tgz",
-              "dependencies": {
-                "lodash._basefor": {
-                  "version": "3.0.2",
-                  "from": "lodash._basefor@>=3.0.0 <4.0.0",
-                  "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.2.tgz"
-                }
-              }
-            },
-            "lodash.keysin": {
-              "version": "3.0.8",
-              "from": "lodash.keysin@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz",
-              "dependencies": {
-                "lodash.isarguments": {
-                  "version": "3.0.4",
-                  "from": "lodash.isarguments@>=3.0.0 <4.0.0",
-                  "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.4.tgz"
-                },
-                "lodash.isarray": {
-                  "version": "3.0.4",
-                  "from": "lodash.isarray@>=3.0.0 <4.0.0",
-                  "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz"
-                }
-              }
-            },
-            "lodash.restparam": {
-              "version": "3.6.1",
-              "from": "lodash.restparam@>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz"
-            }
-          }
-        },
-        "minimatch": {
-          "version": "2.0.10",
-          "from": "minimatch@>=2.0.1 <3.0.0",
-          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz",
-          "dependencies": {
-            "brace-expansion": {
-              "version": "1.1.0",
-              "from": "brace-expansion@>=1.0.0 <2.0.0",
-              "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.0.tgz",
-              "dependencies": {
-                "balanced-match": {
-                  "version": "0.2.0",
-                  "from": "balanced-match@>=0.2.0 <0.3.0",
-                  "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.0.tgz"
-                },
-                "concat-map": {
-                  "version": "0.0.1",
-                  "from": "concat-map@0.0.1",
-                  "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
+                  "from": "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz",
+                  "resolved": "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz"
                 }
               }
             }
           }
         },
-        "mkdirp": {
-          "version": "0.5.1",
-          "from": "mkdirp@>=0.5.0 <0.6.0",
-          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
-          "dependencies": {
-            "minimist": {
-              "version": "0.0.8",
-              "from": "minimist@0.0.8",
-              "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
-            }
-          }
-        },
         "object-assign": {
           "version": "2.1.1",
-          "from": "object-assign@>=2.0.0 <3.0.0",
+          "from": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz",
           "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz"
         },
         "optionator": {
           "version": "0.5.0",
-          "from": "optionator@>=0.5.0 <0.6.0",
+          "from": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz",
           "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz",
           "dependencies": {
             "prelude-ls": {
               "version": "1.1.2",
-              "from": "prelude-ls@>=1.1.1 <1.2.0",
+              "from": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
               "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz"
             },
             "deep-is": {
               "version": "0.1.3",
-              "from": "deep-is@>=0.1.2 <0.2.0",
+              "from": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
               "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz"
             },
             "wordwrap": {
               "version": "0.0.3",
-              "from": "wordwrap@>=0.0.2 <0.1.0",
+              "from": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
               "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
             },
             "type-check": {
               "version": "0.3.1",
-              "from": "type-check@>=0.3.1 <0.4.0",
+              "from": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz",
               "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz"
             },
             "levn": {
               "version": "0.2.5",
-              "from": "levn@>=0.2.5 <0.3.0",
+              "from": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz",
               "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz"
             },
             "fast-levenshtein": {
               "version": "1.0.7",
-              "from": "fast-levenshtein@>=1.0.0 <1.1.0",
+              "from": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz",
               "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz"
             }
           }
         },
-        "path-is-absolute": {
-          "version": "1.0.0",
-          "from": "path-is-absolute@>=1.0.0 <2.0.0",
-          "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz"
-        },
         "path-is-inside": {
           "version": "1.0.1",
-          "from": "path-is-inside@>=1.0.1 <2.0.0",
+          "from": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.1.tgz",
           "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.1.tgz"
         },
         "strip-json-comments": {
           "version": "1.0.4",
-          "from": "strip-json-comments@>=1.0.1 <1.1.0",
+          "from": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz",
           "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz"
         },
         "text-table": {
           "version": "0.2.0",
-          "from": "text-table@>=0.2.0 <0.3.0",
+          "from": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
           "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz"
         },
-        "user-home": {
-          "version": "1.1.1",
-          "from": "user-home@>=1.0.0 <2.0.0",
-          "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz"
-        },
         "xml-escape": {
           "version": "1.0.0",
-          "from": "xml-escape@>=1.0.0 <1.1.0",
+          "from": "https://registry.npmjs.org/xml-escape/-/xml-escape-1.0.0.tgz",
           "resolved": "https://registry.npmjs.org/xml-escape/-/xml-escape-1.0.0.tgz"
         }
       }
     },
     "eslint-plugin-react": {
       "version": "3.3.1",
-      "from": "eslint-plugin-react@3.3.1",
+      "from": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-3.3.1.tgz",
       "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-3.3.1.tgz"
     },
     "esprima-fb": {
       "version": "15001.1001.0-dev-harmony-fb",
-      "from": "esprima-fb@>=15001.1001.0-dev-harmony-fb <15001.1002.0",
+      "from": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz",
       "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz"
     },
     "esutils": {
       "version": "2.0.2",
-      "from": "esutils@>=2.0.0 <3.0.0",
+      "from": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
       "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz"
     },
     "event-target-shim": {
       "version": "1.0.5",
-      "from": "event-target-shim@*",
+      "from": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-1.0.5.tgz",
       "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-1.0.5.tgz"
     },
     "expand-brackets": {
       "version": "0.1.4",
-      "from": "expand-brackets@>=0.1.1 <0.2.0",
+      "from": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.4.tgz",
       "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.4.tgz"
     },
     "expand-range": {
       "version": "1.8.1",
-      "from": "expand-range@>=1.8.1 <2.0.0",
+      "from": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.1.tgz",
       "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.1.tgz"
     },
     "extglob": {
       "version": "0.3.1",
-      "from": "extglob@>=0.3.0 <0.4.0",
+      "from": "https://registry.npmjs.org/extglob/-/extglob-0.3.1.tgz",
       "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.1.tgz"
     },
     "fancy-log": {
       "version": "1.1.0",
-      "from": "fancy-log@>=1.1.0 <2.0.0",
-      "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.1.0.tgz",
-      "dependencies": {
-        "chalk": {
-          "version": "1.1.1",
-          "from": "chalk@>=1.1.1 <2.0.0"
-        }
-      }
+      "from": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.1.0.tgz",
+      "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.1.0.tgz"
     },
     "fbjs": {
       "version": "0.6.0",
-      "from": "fbjs@>=0.6.0 <0.7.0",
+      "from": "https://registry.npmjs.org/fbjs/-/fbjs-0.6.0.tgz",
       "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.6.0.tgz",
       "dependencies": {
         "ua-parser-js": {
           "version": "0.7.10",
-          "from": "ua-parser-js@>=0.7.9 <0.8.0",
+          "from": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.10.tgz",
           "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.10.tgz"
         },
         "whatwg-fetch": {
           "version": "0.9.0",
-          "from": "whatwg-fetch@>=0.9.0 <0.10.0",
+          "from": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz",
           "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz"
         }
       }
     },
     "fbjs-scripts": {
       "version": "0.4.0",
-      "from": "fbjs-scripts@>=0.4.0 <0.5.0",
-      "dependencies": {
-        "semver": {
-          "version": "5.0.3",
-          "from": "semver@>=5.0.1 <6.0.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
-        }
-      }
+      "from": "fbjs-scripts@0.4.0",
+      "resolved": "https://registry.npmjs.org/fbjs-scripts/-/fbjs-scripts-0.4.0.tgz"
     },
     "filename-regex": {
       "version": "2.0.0",
-      "from": "filename-regex@>=2.0.0 <3.0.0",
+      "from": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.0.tgz",
       "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.0.tgz"
     },
     "fill-range": {
       "version": "2.2.2",
-      "from": "fill-range@>=2.1.0 <3.0.0",
+      "from": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.2.tgz",
       "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.2.tgz"
     },
     "find-up": {
       "version": "1.0.0",
-      "from": "find-up@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/find-up/-/find-up-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.0.0.tgz",
       "dependencies": {
         "path-exists": {
           "version": "2.0.0",
-          "from": "path-exists@>=2.0.0 <3.0.0",
+          "from": "https://registry.npmjs.org/path-exists/-/path-exists-2.0.0.tgz",
           "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.0.0.tgz"
         }
       }
     },
     "for-in": {
       "version": "0.1.4",
-      "from": "for-in@>=0.1.4 <0.2.0",
+      "from": "https://registry.npmjs.org/for-in/-/for-in-0.1.4.tgz",
       "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.4.tgz"
     },
     "for-own": {
       "version": "0.1.3",
-      "from": "for-own@>=0.1.3 <0.2.0",
+      "from": "https://registry.npmjs.org/for-own/-/for-own-0.1.3.tgz",
       "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.3.tgz"
     },
     "fs-readdir-recursive": {
       "version": "0.1.2",
-      "from": "fs-readdir-recursive@>=0.1.0 <0.2.0",
+      "from": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz",
       "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz"
     },
     "fsevents": {
       "version": "1.0.5",
-      "from": "fsevents@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/fsevents/-/fsevents-1.0.5.tgz",
       "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.0.5.tgz",
       "dependencies": {
         "node-pre-gyp": {
@@ -1918,16 +1955,16 @@
           "from": "brace-expansion@>=1.0.0 <2.0.0",
           "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz"
         },
-        "caseless": {
-          "version": "0.11.0",
-          "from": "caseless@~0.11.0",
-          "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
-        },
         "chalk": {
           "version": "1.1.1",
           "from": "chalk@^1.1.1",
           "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz"
         },
+        "caseless": {
+          "version": "0.11.0",
+          "from": "caseless@~0.11.0",
+          "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
+        },
         "combined-stream": {
           "version": "1.0.5",
           "from": "combined-stream@~1.0.5",
@@ -2028,16 +2065,16 @@
           "from": "graceful-readlink@>= 1.0.0",
           "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
         },
-        "har-validator": {
-          "version": "2.0.2",
-          "from": "har-validator@~2.0.2",
-          "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.2.tgz"
-        },
         "has-ansi": {
           "version": "2.0.0",
           "from": "has-ansi@^2.0.0",
           "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
         },
+        "har-validator": {
+          "version": "2.0.2",
+          "from": "har-validator@~2.0.2",
+          "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.2.tgz"
+        },
         "has-unicode": {
           "version": "1.0.1",
           "from": "has-unicode@^1.0.0",
@@ -2198,16 +2235,16 @@
           "from": "request@2.x",
           "resolved": "https://registry.npmjs.org/request/-/request-2.65.0.tgz"
         },
-        "semver": {
-          "version": "5.0.3",
-          "from": "semver@~5.0.1",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
-        },
         "sntp": {
           "version": "1.0.9",
           "from": "sntp@1.x.x",
           "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
         },
+        "semver": {
+          "version": "5.0.3",
+          "from": "semver@~5.0.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
+        },
         "string_decoder": {
           "version": "0.10.31",
           "from": "string_decoder@~0.10.x",
@@ -2238,16 +2275,16 @@
           "from": "tar@~2.2.0",
           "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz"
         },
-        "tunnel-agent": {
-          "version": "0.4.1",
-          "from": "tunnel-agent@~0.4.1",
-          "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz"
-        },
         "tough-cookie": {
           "version": "2.2.0",
           "from": "tough-cookie@~2.2.0",
           "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.0.tgz"
         },
+        "tunnel-agent": {
+          "version": "0.4.1",
+          "from": "tunnel-agent@~0.4.1",
+          "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz"
+        },
         "uid-number": {
           "version": "0.0.3",
           "from": "uid-number@0.0.3",
@@ -2406,372 +2443,359 @@
     },
     "get-stdin": {
       "version": "4.0.1",
-      "from": "get-stdin@>=4.0.1 <5.0.0",
+      "from": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
       "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz"
     },
     "glob": {
       "version": "5.0.15",
-      "from": "glob@>=5.0.15 <6.0.0",
+      "from": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
       "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz"
     },
     "glob-base": {
       "version": "0.3.0",
-      "from": "glob-base@>=0.3.0 <0.4.0",
+      "from": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
       "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz"
     },
     "glob-parent": {
       "version": "2.0.0",
-      "from": "glob-parent@>=2.0.0 <3.0.0",
+      "from": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
       "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz"
     },
-    "globals": {
-      "version": "8.11.0",
-      "from": "globals@>=8.3.0 <9.0.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-8.11.0.tgz"
-    },
     "glogg": {
       "version": "1.0.0",
-      "from": "glogg@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/glogg/-/glogg-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.0.tgz"
     },
     "graceful-fs": {
       "version": "4.1.2",
-      "from": "graceful-fs@>=4.1.2 <5.0.0",
+      "from": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.2.tgz",
       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.2.tgz"
     },
     "graceful-readlink": {
       "version": "1.0.1",
-      "from": "graceful-readlink@>=1.0.0",
+      "from": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
     },
     "gulp-util": {
       "version": "3.0.7",
-      "from": "gulp-util@>=3.0.4 <4.0.0",
+      "from": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.7.tgz",
       "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.7.tgz",
       "dependencies": {
-        "chalk": {
-          "version": "1.1.1",
-          "from": "chalk@>=1.0.0 <2.0.0"
-        },
         "object-assign": {
           "version": "3.0.0",
-          "from": "object-assign@>=3.0.0 <4.0.0",
+          "from": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
           "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz"
         }
       }
     },
     "gulplog": {
       "version": "1.0.0",
-      "from": "gulplog@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz"
     },
     "has-ansi": {
       "version": "2.0.0",
-      "from": "has-ansi@>=2.0.0 <3.0.0",
+      "from": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
       "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
     },
     "has-gulplog": {
       "version": "0.1.0",
-      "from": "has-gulplog@>=0.1.0 <0.2.0",
+      "from": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz",
       "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz"
     },
     "home-or-tmp": {
       "version": "1.0.0",
-      "from": "home-or-tmp@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-1.0.0.tgz"
     },
     "hosted-git-info": {
       "version": "2.1.4",
-      "from": "hosted-git-info@>=2.1.4 <3.0.0",
+      "from": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.4.tgz",
       "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.4.tgz"
     },
     "iconv-lite": {
       "version": "0.4.13",
-      "from": "iconv-lite@>=0.4.5 <0.5.0",
+      "from": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz",
       "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz"
     },
     "image-size": {
       "version": "0.3.5",
-      "from": "image-size@0.3.5",
+      "from": "https://registry.npmjs.org/image-size/-/image-size-0.3.5.tgz",
       "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.3.5.tgz"
     },
     "immutable": {
       "version": "3.7.5",
-      "from": "immutable@>=3.7.4 <4.0.0",
+      "from": "https://registry.npmjs.org/immutable/-/immutable-3.7.5.tgz",
       "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.5.tgz"
     },
     "indent-string": {
       "version": "2.1.0",
-      "from": "indent-string@>=2.1.0 <3.0.0",
+      "from": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
       "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
       "dependencies": {
         "repeating": {
           "version": "2.0.0",
-          "from": "repeating@>=2.0.0 <3.0.0",
+          "from": "https://registry.npmjs.org/repeating/-/repeating-2.0.0.tgz",
           "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.0.tgz"
         }
       }
     },
     "inflight": {
       "version": "1.0.4",
-      "from": "inflight@>=1.0.4 <2.0.0",
+      "from": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz",
       "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz"
     },
     "inherits": {
       "version": "2.0.1",
-      "from": "inherits@>=2.0.0 <3.0.0",
+      "from": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
     },
-    "invariant": {
-      "version": "2.1.2",
-      "from": "invariant@>=2.1.0 <3.0.0",
-      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.1.2.tgz"
-    },
     "invert-kv": {
       "version": "1.0.0",
-      "from": "invert-kv@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz"
     },
     "is-arrayish": {
       "version": "0.2.1",
-      "from": "is-arrayish@>=0.2.1 <0.3.0",
+      "from": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
       "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz"
     },
     "is-binary-path": {
       "version": "1.0.1",
-      "from": "is-binary-path@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz"
     },
     "is-buffer": {
       "version": "1.1.0",
-      "from": "is-buffer@>=1.0.2 <2.0.0",
+      "from": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.0.tgz",
       "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.0.tgz"
     },
     "is-builtin-module": {
       "version": "1.0.0",
-      "from": "is-builtin-module@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz"
     },
     "is-dotfile": {
       "version": "1.0.2",
-      "from": "is-dotfile@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.2.tgz",
       "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.2.tgz"
     },
     "is-equal-shallow": {
       "version": "0.1.3",
-      "from": "is-equal-shallow@>=0.1.1 <0.2.0",
+      "from": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
       "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz"
     },
     "is-extendable": {
       "version": "0.1.1",
-      "from": "is-extendable@>=0.1.1 <0.2.0",
+      "from": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
       "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz"
     },
     "is-extglob": {
       "version": "1.0.0",
-      "from": "is-extglob@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz"
     },
     "is-finite": {
       "version": "1.0.1",
-      "from": "is-finite@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.1.tgz"
     },
     "is-glob": {
       "version": "2.0.1",
-      "from": "is-glob@>=2.0.0 <3.0.0",
+      "from": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
       "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz"
     },
     "is-integer": {
       "version": "1.0.6",
-      "from": "is-integer@>=1.0.4 <2.0.0",
+      "from": "https://registry.npmjs.org/is-integer/-/is-integer-1.0.6.tgz",
       "resolved": "https://registry.npmjs.org/is-integer/-/is-integer-1.0.6.tgz"
     },
     "is-number": {
       "version": "1.1.2",
-      "from": "is-number@>=1.1.2 <2.0.0",
+      "from": "https://registry.npmjs.org/is-number/-/is-number-1.1.2.tgz",
       "resolved": "https://registry.npmjs.org/is-number/-/is-number-1.1.2.tgz"
     },
     "is-primitive": {
       "version": "2.0.0",
-      "from": "is-primitive@>=2.0.0 <3.0.0",
+      "from": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
       "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz"
     },
     "is-utf8": {
       "version": "0.2.0",
-      "from": "is-utf8@>=0.2.0 <0.3.0",
+      "from": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.0.tgz",
       "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.0.tgz"
     },
     "isarray": {
       "version": "0.0.1",
-      "from": "isarray@0.0.1",
+      "from": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
       "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
     },
     "isobject": {
       "version": "1.0.2",
-      "from": "isobject@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/isobject/-/isobject-1.0.2.tgz",
       "resolved": "https://registry.npmjs.org/isobject/-/isobject-1.0.2.tgz"
     },
     "jest-cli": {
       "version": "0.8.2",
       "from": "jest-cli@0.8.2",
+      "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-0.8.2.tgz",
       "dependencies": {
         "cover": {
           "version": "0.2.9",
-          "from": "cover@>=0.2.9 <0.3.0",
+          "from": "https://registry.npmjs.org/cover/-/cover-0.2.9.tgz",
           "resolved": "https://registry.npmjs.org/cover/-/cover-0.2.9.tgz",
           "dependencies": {
             "cli-table": {
               "version": "0.0.2",
-              "from": "cli-table@>=0.0.0 <0.1.0",
+              "from": "https://registry.npmjs.org/cli-table/-/cli-table-0.0.2.tgz",
               "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.0.2.tgz",
               "dependencies": {
                 "colors": {
                   "version": "0.3.0",
-                  "from": "colors@0.3.0",
+                  "from": "https://registry.npmjs.org/colors/-/colors-0.3.0.tgz",
                   "resolved": "https://registry.npmjs.org/colors/-/colors-0.3.0.tgz"
                 }
               }
             },
             "underscore": {
               "version": "1.2.4",
-              "from": "underscore@>=1.2.0 <1.3.0",
+              "from": "https://registry.npmjs.org/underscore/-/underscore-1.2.4.tgz",
               "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.2.4.tgz"
             },
             "underscore.string": {
               "version": "2.0.0",
-              "from": "underscore.string@>=2.0.0 <2.1.0",
+              "from": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.0.0.tgz",
               "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.0.0.tgz"
             },
             "which": {
               "version": "1.0.9",
-              "from": "which@>=1.0.0 <1.1.0",
+              "from": "https://registry.npmjs.org/which/-/which-1.0.9.tgz",
               "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz"
             }
           }
         },
         "diff": {
           "version": "2.2.1",
-          "from": "diff@>=2.1.1 <3.0.0",
+          "from": "https://registry.npmjs.org/diff/-/diff-2.2.1.tgz",
           "resolved": "https://registry.npmjs.org/diff/-/diff-2.2.1.tgz"
         },
         "istanbul": {
           "version": "0.3.22",
-          "from": "istanbul@>=0.3.19 <0.4.0",
+          "from": "https://registry.npmjs.org/istanbul/-/istanbul-0.3.22.tgz",
           "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.3.22.tgz",
           "dependencies": {
             "abbrev": {
               "version": "1.0.7",
-              "from": "abbrev@>=1.0.0 <1.1.0",
+              "from": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz",
               "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz"
             },
             "async": {
               "version": "1.5.0",
-              "from": "async@>=1.0.0 <2.0.0",
+              "from": "https://registry.npmjs.org/async/-/async-1.5.0.tgz",
               "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz"
             },
             "escodegen": {
               "version": "1.7.1",
-              "from": "escodegen@>=1.7.0 <1.8.0",
+              "from": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.1.tgz",
               "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.1.tgz",
               "dependencies": {
                 "estraverse": {
                   "version": "1.9.3",
-                  "from": "estraverse@>=1.9.1 <2.0.0",
+                  "from": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz",
                   "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz"
                 },
                 "esprima": {
                   "version": "1.2.5",
-                  "from": "esprima@>=1.2.2 <2.0.0",
+                  "from": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz",
                   "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz"
                 },
                 "optionator": {
                   "version": "0.5.0",
-                  "from": "optionator@>=0.5.0 <0.6.0",
+                  "from": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz",
                   "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz",
                   "dependencies": {
                     "prelude-ls": {
                       "version": "1.1.2",
-                      "from": "prelude-ls@>=1.1.1 <1.2.0",
+                      "from": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
                       "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz"
                     },
                     "deep-is": {
                       "version": "0.1.3",
-                      "from": "deep-is@>=0.1.2 <0.2.0",
+                      "from": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
                       "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz"
                     },
                     "wordwrap": {
                       "version": "0.0.3",
-                      "from": "wordwrap@>=0.0.2 <0.1.0",
+                      "from": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
                       "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
                     },
                     "type-check": {
                       "version": "0.3.1",
-                      "from": "type-check@>=0.3.1 <0.4.0",
+                      "from": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz",
                       "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz"
                     },
                     "levn": {
                       "version": "0.2.5",
-                      "from": "levn@>=0.2.5 <0.3.0",
+                      "from": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz",
                       "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz"
                     },
                     "fast-levenshtein": {
                       "version": "1.0.7",
-                      "from": "fast-levenshtein@>=1.0.0 <1.1.0",
+                      "from": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz",
                       "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz"
                     }
                   }
                 },
                 "source-map": {
                   "version": "0.2.0",
-                  "from": "source-map@>=0.2.0 <0.3.0",
+                  "from": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz",
                   "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz"
                 }
               }
             },
             "esprima": {
               "version": "2.5.0",
-              "from": "esprima@>=2.5.0 <2.6.0",
+              "from": "https://registry.npmjs.org/esprima/-/esprima-2.5.0.tgz",
               "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.5.0.tgz"
             },
             "fileset": {
               "version": "0.2.1",
-              "from": "fileset@>=0.2.0 <0.3.0",
+              "from": "https://registry.npmjs.org/fileset/-/fileset-0.2.1.tgz",
               "resolved": "https://registry.npmjs.org/fileset/-/fileset-0.2.1.tgz"
             },
             "handlebars": {
               "version": "4.0.5",
-              "from": "handlebars@>=4.0.1 <5.0.0",
+              "from": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.5.tgz",
               "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.5.tgz",
               "dependencies": {
                 "uglify-js": {
                   "version": "2.6.1",
-                  "from": "uglify-js@>=2.6.0 <3.0.0",
+                  "from": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.1.tgz",
                   "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.1.tgz",
                   "dependencies": {
                     "async": {
                       "version": "0.2.10",
-                      "from": "async@>=0.2.6 <0.3.0",
+                      "from": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
                       "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz"
                     },
                     "source-map": {
                       "version": "0.5.3",
-                      "from": "source-map@>=0.5.1 <0.6.0",
+                      "from": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz",
                       "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz"
                     },
                     "uglify-to-browserify": {
                       "version": "1.0.2",
-                      "from": "uglify-to-browserify@>=1.0.0 <1.1.0",
+                      "from": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
                       "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz"
                     },
                     "yargs": {
                       "version": "3.10.0",
-                      "from": "yargs@>=3.10.0 <3.11.0",
+                      "from": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
                       "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
                       "dependencies": {
                         "window-size": {
                           "version": "0.1.0",
-                          "from": "window-size@0.1.0",
+                          "from": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
                           "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz"
                         }
                       }
@@ -2782,46 +2806,46 @@
             },
             "js-yaml": {
               "version": "3.4.6",
-              "from": "js-yaml@>=3.0.0 <4.0.0",
+              "from": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.4.6.tgz",
               "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.4.6.tgz",
               "dependencies": {
                 "argparse": {
                   "version": "1.0.3",
-                  "from": "argparse@>=1.0.2 <2.0.0",
+                  "from": "https://registry.npmjs.org/argparse/-/argparse-1.0.3.tgz",
                   "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.3.tgz",
                   "dependencies": {
                     "sprintf-js": {
                       "version": "1.0.3",
-                      "from": "sprintf-js@>=1.0.2 <1.1.0",
+                      "from": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
                       "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz"
                     }
                   }
                 },
                 "esprima": {
                   "version": "2.7.1",
-                  "from": "esprima@>=2.6.0 <3.0.0",
+                  "from": "https://registry.npmjs.org/esprima/-/esprima-2.7.1.tgz",
                   "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.1.tgz"
                 },
                 "inherit": {
                   "version": "2.2.2",
-                  "from": "inherit@>=2.2.2 <3.0.0",
+                  "from": "https://registry.npmjs.org/inherit/-/inherit-2.2.2.tgz",
                   "resolved": "https://registry.npmjs.org/inherit/-/inherit-2.2.2.tgz"
                 }
               }
             },
             "nopt": {
               "version": "3.0.6",
-              "from": "nopt@>=3.0.0 <4.0.0",
+              "from": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
               "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz"
             },
             "supports-color": {
               "version": "3.1.2",
-              "from": "supports-color@>=3.1.0 <4.0.0",
+              "from": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz",
               "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz",
               "dependencies": {
                 "has-flag": {
                   "version": "1.0.0",
-                  "from": "has-flag@>=1.0.0 <2.0.0",
+                  "from": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz"
                 }
               }
@@ -2830,249 +2854,249 @@
         },
         "jsdom": {
           "version": "7.2.1",
-          "from": "jsdom@>=7.2.0 <8.0.0",
+          "from": "https://registry.npmjs.org/jsdom/-/jsdom-7.2.1.tgz",
           "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-7.2.1.tgz",
           "dependencies": {
             "abab": {
               "version": "1.0.1",
-              "from": "abab@>=1.0.0 <2.0.0",
+              "from": "https://registry.npmjs.org/abab/-/abab-1.0.1.tgz",
               "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.1.tgz"
             },
             "acorn": {
               "version": "2.6.4",
-              "from": "acorn@>=2.4.0 <3.0.0",
+              "from": "https://registry.npmjs.org/acorn/-/acorn-2.6.4.tgz",
               "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.6.4.tgz"
             },
             "acorn-globals": {
               "version": "1.0.9",
-              "from": "acorn-globals@>=1.0.4 <2.0.0",
+              "from": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz",
               "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz"
             },
             "cssom": {
               "version": "0.3.0",
-              "from": "cssom@>=0.3.0 <0.4.0",
+              "from": "https://registry.npmjs.org/cssom/-/cssom-0.3.0.tgz",
               "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.0.tgz"
             },
             "cssstyle": {
               "version": "0.2.30",
-              "from": "cssstyle@>=0.2.29 <0.3.0",
+              "from": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.30.tgz",
               "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.30.tgz"
             },
             "escodegen": {
               "version": "1.7.1",
-              "from": "escodegen@>=1.6.1 <2.0.0",
+              "from": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.1.tgz",
               "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.1.tgz",
               "dependencies": {
                 "estraverse": {
                   "version": "1.9.3",
-                  "from": "estraverse@>=1.9.1 <2.0.0",
+                  "from": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz",
                   "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz"
                 },
                 "esprima": {
                   "version": "1.2.5",
-                  "from": "esprima@>=1.2.2 <2.0.0",
+                  "from": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz",
                   "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz"
                 },
                 "optionator": {
                   "version": "0.5.0",
-                  "from": "optionator@>=0.5.0 <0.6.0",
+                  "from": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz",
                   "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz",
                   "dependencies": {
                     "prelude-ls": {
                       "version": "1.1.2",
-                      "from": "prelude-ls@>=1.1.1 <1.2.0",
+                      "from": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
                       "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz"
                     },
                     "deep-is": {
                       "version": "0.1.3",
-                      "from": "deep-is@>=0.1.2 <0.2.0",
+                      "from": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
                       "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz"
                     },
                     "wordwrap": {
                       "version": "0.0.3",
-                      "from": "wordwrap@>=0.0.2 <0.1.0",
+                      "from": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
                       "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
                     },
                     "type-check": {
                       "version": "0.3.1",
-                      "from": "type-check@>=0.3.1 <0.4.0",
+                      "from": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz",
                       "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz"
                     },
                     "levn": {
                       "version": "0.2.5",
-                      "from": "levn@>=0.2.5 <0.3.0",
+                      "from": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz",
                       "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz"
                     },
                     "fast-levenshtein": {
                       "version": "1.0.7",
-                      "from": "fast-levenshtein@>=1.0.0 <1.1.0",
+                      "from": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz",
                       "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz"
                     }
                   }
                 },
                 "source-map": {
                   "version": "0.2.0",
-                  "from": "source-map@>=0.2.0 <0.3.0",
+                  "from": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz",
                   "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz"
                 }
               }
             },
             "nwmatcher": {
               "version": "1.3.7",
-              "from": "nwmatcher@>=1.3.7 <2.0.0",
+              "from": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.3.7.tgz",
               "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.3.7.tgz"
             },
             "parse5": {
               "version": "1.5.1",
-              "from": "parse5@>=1.5.1 <2.0.0",
+              "from": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz",
               "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz"
             },
             "request": {
               "version": "2.67.0",
-              "from": "request@>=2.55.0 <3.0.0",
+              "from": "https://registry.npmjs.org/request/-/request-2.67.0.tgz",
               "resolved": "https://registry.npmjs.org/request/-/request-2.67.0.tgz",
               "dependencies": {
                 "bl": {
                   "version": "1.0.0",
-                  "from": "bl@>=1.0.0 <1.1.0",
+                  "from": "https://registry.npmjs.org/bl/-/bl-1.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/bl/-/bl-1.0.0.tgz"
                 },
                 "caseless": {
                   "version": "0.11.0",
-                  "from": "caseless@>=0.11.0 <0.12.0",
+                  "from": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz",
                   "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
                 },
                 "extend": {
                   "version": "3.0.0",
-                  "from": "extend@>=3.0.0 <3.1.0",
+                  "from": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz"
                 },
                 "forever-agent": {
                   "version": "0.6.1",
-                  "from": "forever-agent@>=0.6.1 <0.7.0",
+                  "from": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
                   "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz"
                 },
                 "form-data": {
                   "version": "1.0.0-rc3",
-                  "from": "form-data@>=1.0.0-rc3 <1.1.0",
+                  "from": "https://registry.npmjs.org/form-data/-/form-data-1.0.0-rc3.tgz",
                   "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.0-rc3.tgz",
                   "dependencies": {
                     "async": {
                       "version": "1.5.0",
-                      "from": "async@>=1.4.0 <2.0.0",
+                      "from": "https://registry.npmjs.org/async/-/async-1.5.0.tgz",
                       "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz"
                     }
                   }
                 },
                 "json-stringify-safe": {
                   "version": "5.0.1",
-                  "from": "json-stringify-safe@>=5.0.1 <5.1.0",
+                  "from": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
                   "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
                 },
                 "mime-types": {
                   "version": "2.1.8",
-                  "from": "mime-types@>=2.1.7 <2.2.0",
+                  "from": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.8.tgz",
                   "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.8.tgz",
                   "dependencies": {
                     "mime-db": {
                       "version": "1.20.0",
-                      "from": "mime-db@>=1.20.0 <1.21.0",
+                      "from": "https://registry.npmjs.org/mime-db/-/mime-db-1.20.0.tgz",
                       "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.20.0.tgz"
                     }
                   }
                 },
                 "node-uuid": {
                   "version": "1.4.7",
-                  "from": "node-uuid@>=1.4.7 <1.5.0",
+                  "from": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz",
                   "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz"
                 },
                 "qs": {
                   "version": "5.2.0",
-                  "from": "qs@>=5.2.0 <5.3.0",
+                  "from": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz",
                   "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz"
                 },
                 "tunnel-agent": {
                   "version": "0.4.2",
-                  "from": "tunnel-agent@>=0.4.1 <0.5.0",
+                  "from": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.2.tgz",
                   "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.2.tgz"
                 },
                 "http-signature": {
                   "version": "1.1.0",
-                  "from": "http-signature@>=1.1.0 <1.2.0",
+                  "from": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.0.tgz",
                   "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.0.tgz",
                   "dependencies": {
                     "assert-plus": {
                       "version": "0.1.5",
-                      "from": "assert-plus@>=0.1.5 <0.2.0",
+                      "from": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz",
                       "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
                     },
                     "jsprim": {
                       "version": "1.2.2",
-                      "from": "jsprim@>=1.2.2 <2.0.0",
+                      "from": "https://registry.npmjs.org/jsprim/-/jsprim-1.2.2.tgz",
                       "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.2.2.tgz",
                       "dependencies": {
                         "extsprintf": {
                           "version": "1.0.2",
-                          "from": "extsprintf@1.0.2",
+                          "from": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz",
                           "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz"
                         },
                         "json-schema": {
                           "version": "0.2.2",
-                          "from": "json-schema@0.2.2",
+                          "from": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.2.tgz",
                           "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.2.tgz"
                         },
                         "verror": {
                           "version": "1.3.6",
-                          "from": "verror@1.3.6",
+                          "from": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz",
                           "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz"
                         }
                       }
                     },
                     "sshpk": {
                       "version": "1.7.1",
-                      "from": "sshpk@>=1.7.0 <2.0.0",
+                      "from": "https://registry.npmjs.org/sshpk/-/sshpk-1.7.1.tgz",
                       "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.7.1.tgz",
                       "dependencies": {
                         "asn1": {
                           "version": "0.2.3",
-                          "from": "asn1@>=0.2.3 <0.3.0",
+                          "from": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
                           "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz"
                         },
                         "assert-plus": {
                           "version": "0.2.0",
-                          "from": "assert-plus@>=0.2.0 <0.3.0",
+                          "from": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz",
                           "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz"
                         },
                         "dashdash": {
                           "version": "1.10.1",
-                          "from": "dashdash@>=1.10.1 <2.0.0",
+                          "from": "https://registry.npmjs.org/dashdash/-/dashdash-1.10.1.tgz",
                           "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.10.1.tgz",
                           "dependencies": {
                             "assert-plus": {
                               "version": "0.1.5",
-                              "from": "assert-plus@>=0.1.0 <0.2.0",
+                              "from": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz",
                               "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
                             }
                           }
                         },
                         "jsbn": {
                           "version": "0.1.0",
-                          "from": "jsbn@>=0.1.0 <0.2.0",
+                          "from": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz",
                           "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz"
                         },
                         "tweetnacl": {
                           "version": "0.13.2",
-                          "from": "tweetnacl@>=0.13.0 <1.0.0",
+                          "from": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.13.2.tgz",
                           "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.13.2.tgz"
                         },
                         "jodid25519": {
                           "version": "1.0.2",
-                          "from": "jodid25519@>=1.0.0 <2.0.0",
+                          "from": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz",
                           "resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz"
                         },
                         "ecc-jsbn": {
                           "version": "0.1.1",
-                          "from": "ecc-jsbn@>=0.0.1 <1.0.0",
+                          "from": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
                           "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz"
                         }
                       }
@@ -3081,110 +3105,110 @@
                 },
                 "oauth-sign": {
                   "version": "0.8.0",
-                  "from": "oauth-sign@>=0.8.0 <0.9.0",
+                  "from": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.0.tgz",
                   "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.0.tgz"
                 },
                 "hawk": {
                   "version": "3.1.2",
-                  "from": "hawk@>=3.1.0 <3.2.0",
+                  "from": "https://registry.npmjs.org/hawk/-/hawk-3.1.2.tgz",
                   "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.2.tgz",
                   "dependencies": {
                     "hoek": {
                       "version": "2.16.3",
-                      "from": "hoek@>=2.0.0 <3.0.0",
+                      "from": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
                       "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz"
                     },
                     "boom": {
                       "version": "2.10.1",
-                      "from": "boom@>=2.0.0 <3.0.0",
+                      "from": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
                       "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz"
                     },
                     "cryptiles": {
                       "version": "2.0.5",
-                      "from": "cryptiles@>=2.0.0 <3.0.0",
+                      "from": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
                       "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz"
                     },
                     "sntp": {
                       "version": "1.0.9",
-                      "from": "sntp@>=1.0.0 <2.0.0",
+                      "from": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
                       "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
                     }
                   }
                 },
                 "aws-sign2": {
                   "version": "0.6.0",
-                  "from": "aws-sign2@>=0.6.0 <0.7.0",
+                  "from": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz",
                   "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
                 },
                 "stringstream": {
                   "version": "0.0.5",
-                  "from": "stringstream@>=0.0.4 <0.1.0",
+                  "from": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
                   "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
                 },
                 "combined-stream": {
                   "version": "1.0.5",
-                  "from": "combined-stream@>=1.0.5 <1.1.0",
+                  "from": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
                   "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
                   "dependencies": {
                     "delayed-stream": {
                       "version": "1.0.0",
-                      "from": "delayed-stream@>=1.0.0 <1.1.0",
+                      "from": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
                       "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
                     }
                   }
                 },
                 "isstream": {
                   "version": "0.1.2",
-                  "from": "isstream@>=0.1.2 <0.2.0",
+                  "from": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
                   "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
                 },
                 "is-typedarray": {
                   "version": "1.0.0",
-                  "from": "is-typedarray@>=1.0.0 <1.1.0",
+                  "from": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz"
                 },
                 "har-validator": {
                   "version": "2.0.3",
-                  "from": "har-validator@>=2.0.2 <2.1.0",
+                  "from": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.3.tgz",
                   "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.3.tgz",
                   "dependencies": {
                     "is-my-json-valid": {
                       "version": "2.12.3",
-                      "from": "is-my-json-valid@>=2.12.3 <3.0.0",
+                      "from": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.3.tgz",
                       "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.3.tgz",
                       "dependencies": {
                         "generate-function": {
                           "version": "2.0.0",
-                          "from": "generate-function@>=2.0.0 <3.0.0",
+                          "from": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz",
                           "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz"
                         },
                         "generate-object-property": {
                           "version": "1.2.0",
-                          "from": "generate-object-property@>=1.1.0 <2.0.0",
+                          "from": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
                           "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
                           "dependencies": {
                             "is-property": {
                               "version": "1.0.2",
-                              "from": "is-property@>=1.0.0 <2.0.0",
+                              "from": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
                               "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz"
                             }
                           }
                         },
                         "jsonpointer": {
                           "version": "2.0.0",
-                          "from": "jsonpointer@2.0.0",
+                          "from": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz",
                           "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
                         }
                       }
                     },
                     "pinkie-promise": {
                       "version": "2.0.0",
-                      "from": "pinkie-promise@>=2.0.0 <3.0.0",
+                      "from": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.0.tgz",
                       "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.0.tgz",
                       "dependencies": {
                         "pinkie": {
                           "version": "2.0.1",
-                          "from": "pinkie@>=2.0.0 <3.0.0",
+                          "from": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.1.tgz",
                           "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.1.tgz"
                         }
                       }
@@ -3195,80 +3219,80 @@
             },
             "sax": {
               "version": "1.1.4",
-              "from": "sax@>=1.1.4 <2.0.0",
+              "from": "https://registry.npmjs.org/sax/-/sax-1.1.4.tgz",
               "resolved": "https://registry.npmjs.org/sax/-/sax-1.1.4.tgz"
             },
             "symbol-tree": {
               "version": "3.1.4",
-              "from": "symbol-tree@>=3.1.0 <4.0.0",
+              "from": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.1.4.tgz",
               "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.1.4.tgz"
             },
             "tough-cookie": {
               "version": "2.2.1",
-              "from": "tough-cookie@>=2.2.0 <3.0.0",
+              "from": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.1.tgz",
               "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.1.tgz"
             },
             "webidl-conversions": {
               "version": "2.0.1",
-              "from": "webidl-conversions@>=2.0.0 <3.0.0",
+              "from": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-2.0.1.tgz",
               "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-2.0.1.tgz"
             },
             "whatwg-url-compat": {
               "version": "0.6.5",
-              "from": "whatwg-url-compat@>=0.6.5 <0.7.0",
+              "from": "https://registry.npmjs.org/whatwg-url-compat/-/whatwg-url-compat-0.6.5.tgz",
               "resolved": "https://registry.npmjs.org/whatwg-url-compat/-/whatwg-url-compat-0.6.5.tgz",
               "dependencies": {
                 "tr46": {
                   "version": "0.0.2",
-                  "from": "tr46@>=0.0.1 <0.1.0",
+                  "from": "https://registry.npmjs.org/tr46/-/tr46-0.0.2.tgz",
                   "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.2.tgz"
                 }
               }
             },
             "xml-name-validator": {
               "version": "2.0.1",
-              "from": "xml-name-validator@>=2.0.1 <3.0.0",
+              "from": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz",
               "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz"
             }
           }
         },
         "json-stable-stringify": {
           "version": "1.0.0",
-          "from": "json-stable-stringify@>=1.0.0 <2.0.0",
+          "from": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.0.tgz",
           "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.0.tgz",
           "dependencies": {
             "jsonify": {
               "version": "0.0.0",
-              "from": "jsonify@>=0.0.0 <0.1.0",
+              "from": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
               "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz"
             }
           }
         },
         "node-haste": {
           "version": "1.2.8",
-          "from": "node-haste@>=1.2.8 <2.0.0",
+          "from": "https://registry.npmjs.org/node-haste/-/node-haste-1.2.8.tgz",
           "resolved": "https://registry.npmjs.org/node-haste/-/node-haste-1.2.8.tgz",
           "dependencies": {
             "esprima-fb": {
               "version": "4001.1001.0-dev-harmony-fb",
-              "from": "esprima-fb@4001.1001.0-dev-harmony-fb",
+              "from": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-4001.1001.0-dev-harmony-fb.tgz",
               "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-4001.1001.0-dev-harmony-fb.tgz"
             }
           }
         },
         "which": {
           "version": "1.2.0",
-          "from": "which@>=1.1.1 <2.0.0",
+          "from": "https://registry.npmjs.org/which/-/which-1.2.0.tgz",
           "resolved": "https://registry.npmjs.org/which/-/which-1.2.0.tgz",
           "dependencies": {
             "is-absolute": {
               "version": "0.1.7",
-              "from": "is-absolute@>=0.1.7 <0.2.0",
+              "from": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz",
               "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz",
               "dependencies": {
                 "is-relative": {
                   "version": "0.1.3",
-                  "from": "is-relative@>=0.1.0 <0.2.0",
+                  "from": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz",
                   "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz"
                 }
               }
@@ -3279,630 +3303,503 @@
     },
     "joi": {
       "version": "6.6.1",
-      "from": "joi@6.6.1",
+      "from": "https://registry.npmjs.org/joi/-/joi-6.6.1.tgz",
       "resolved": "https://registry.npmjs.org/joi/-/joi-6.6.1.tgz",
       "dependencies": {
         "hoek": {
           "version": "2.14.0",
-          "from": "hoek@>=2.2.0 <3.0.0",
+          "from": "https://registry.npmjs.org/hoek/-/hoek-2.14.0.tgz",
           "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.14.0.tgz"
         },
         "topo": {
           "version": "1.0.3",
-          "from": "topo@>=1.0.0 <2.0.0",
+          "from": "https://registry.npmjs.org/topo/-/topo-1.0.3.tgz",
           "resolved": "https://registry.npmjs.org/topo/-/topo-1.0.3.tgz"
         },
         "isemail": {
           "version": "1.1.1",
-          "from": "isemail@>=1.0.0 <2.0.0",
+          "from": "https://registry.npmjs.org/isemail/-/isemail-1.1.1.tgz",
           "resolved": "https://registry.npmjs.org/isemail/-/isemail-1.1.1.tgz"
         },
         "moment": {
           "version": "2.10.6",
-          "from": "moment@>=2.0.0 <3.0.0",
+          "from": "https://registry.npmjs.org/moment/-/moment-2.10.6.tgz",
           "resolved": "https://registry.npmjs.org/moment/-/moment-2.10.6.tgz"
         }
       }
     },
     "js-tokens": {
       "version": "1.0.2",
-      "from": "js-tokens@>=1.0.1 <2.0.0",
+      "from": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.2.tgz",
       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.2.tgz"
     },
     "jsesc": {
       "version": "0.5.0",
-      "from": "jsesc@>=0.5.0 <0.6.0",
+      "from": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
       "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz"
     },
     "json5": {
       "version": "0.4.0",
-      "from": "json5@*",
+      "from": "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz",
       "resolved": "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz"
     },
     "jstransform": {
       "version": "11.0.3",
-      "from": "jstransform@11.0.3",
+      "from": "https://registry.npmjs.org/jstransform/-/jstransform-11.0.3.tgz",
       "resolved": "https://registry.npmjs.org/jstransform/-/jstransform-11.0.3.tgz",
       "dependencies": {
         "base62": {
           "version": "1.1.0",
-          "from": "base62@>=1.1.0 <2.0.0",
+          "from": "https://registry.npmjs.org/base62/-/base62-1.1.0.tgz",
           "resolved": "https://registry.npmjs.org/base62/-/base62-1.1.0.tgz"
         },
         "commoner": {
           "version": "0.10.3",
-          "from": "commoner@>=0.10.1 <0.11.0",
+          "from": "https://registry.npmjs.org/commoner/-/commoner-0.10.3.tgz",
           "resolved": "https://registry.npmjs.org/commoner/-/commoner-0.10.3.tgz",
           "dependencies": {
             "q": {
               "version": "1.1.2",
-              "from": "q@>=1.1.2 <1.2.0",
+              "from": "https://registry.npmjs.org/q/-/q-1.1.2.tgz",
               "resolved": "https://registry.npmjs.org/q/-/q-1.1.2.tgz"
             },
             "recast": {
               "version": "0.10.32",
-              "from": "recast@>=0.10.0 <0.11.0",
+              "from": "https://registry.npmjs.org/recast/-/recast-0.10.32.tgz",
               "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.32.tgz",
               "dependencies": {
                 "esprima-fb": {
                   "version": "15001.1001.0-dev-harmony-fb",
-                  "from": "esprima-fb@>=15001.1001.0-dev-harmony-fb <15001.1002.0",
+                  "from": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz",
                   "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz"
                 },
                 "ast-types": {
                   "version": "0.8.11",
-                  "from": "ast-types@0.8.11",
+                  "from": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.11.tgz",
                   "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.11.tgz"
                 }
               }
             },
             "commander": {
               "version": "2.5.1",
-              "from": "commander@>=2.5.0 <2.6.0",
+              "from": "https://registry.npmjs.org/commander/-/commander-2.5.1.tgz",
               "resolved": "https://registry.npmjs.org/commander/-/commander-2.5.1.tgz"
-            },
-            "graceful-fs": {
-              "version": "3.0.8",
-              "from": "graceful-fs@>=3.0.4 <3.1.0",
-              "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.8.tgz"
-            },
-            "glob": {
-              "version": "4.2.2",
-              "from": "glob@>=4.2.1 <4.3.0",
-              "resolved": "https://registry.npmjs.org/glob/-/glob-4.2.2.tgz",
-              "dependencies": {
-                "inflight": {
-                  "version": "1.0.4",
-                  "from": "inflight@>=1.0.4 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz",
-                  "dependencies": {
-                    "wrappy": {
-                      "version": "1.0.1",
-                      "from": "wrappy@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
-                    }
-                  }
-                },
-                "inherits": {
-                  "version": "2.0.1",
-                  "from": "inherits@>=2.0.0 <3.0.0",
-                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                },
+            },
+            "graceful-fs": {
+              "version": "3.0.8",
+              "from": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.8.tgz",
+              "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.8.tgz"
+            },
+            "glob": {
+              "version": "4.2.2",
+              "from": "https://registry.npmjs.org/glob/-/glob-4.2.2.tgz",
+              "resolved": "https://registry.npmjs.org/glob/-/glob-4.2.2.tgz",
+              "dependencies": {
                 "minimatch": {
                   "version": "1.0.0",
-                  "from": "minimatch@>=1.0.0 <2.0.0",
+                  "from": "https://registry.npmjs.org/minimatch/-/minimatch-1.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-1.0.0.tgz",
                   "dependencies": {
                     "lru-cache": {
                       "version": "2.6.5",
-                      "from": "lru-cache@>=2.0.0 <3.0.0",
+                      "from": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.6.5.tgz",
                       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.6.5.tgz"
                     },
                     "sigmund": {
                       "version": "1.0.1",
-                      "from": "sigmund@>=1.0.0 <1.1.0",
+                      "from": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
                       "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz"
                     }
                   }
-                },
-                "once": {
-                  "version": "1.3.2",
-                  "from": "once@>=1.3.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz",
-                  "dependencies": {
-                    "wrappy": {
-                      "version": "1.0.1",
-                      "from": "wrappy@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
-                    }
-                  }
-                }
-              }
-            },
-            "mkdirp": {
-              "version": "0.5.1",
-              "from": "mkdirp@>=0.5.0 <0.6.0",
-              "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
-              "dependencies": {
-                "minimist": {
-                  "version": "0.0.8",
-                  "from": "minimist@0.0.8",
-                  "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
                 }
               }
             },
-            "private": {
-              "version": "0.1.6",
-              "from": "private@>=0.1.6 <0.2.0",
-              "resolved": "https://registry.npmjs.org/private/-/private-0.1.6.tgz"
-            },
             "install": {
               "version": "0.1.8",
-              "from": "install@>=0.1.7 <0.2.0",
+              "from": "https://registry.npmjs.org/install/-/install-0.1.8.tgz",
               "resolved": "https://registry.npmjs.org/install/-/install-0.1.8.tgz"
             },
             "iconv-lite": {
               "version": "0.4.11",
-              "from": "iconv-lite@>=0.4.5 <0.5.0",
+              "from": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.11.tgz",
               "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.11.tgz"
             }
           }
         },
         "esprima-fb": {
           "version": "15001.1.0-dev-harmony-fb",
-          "from": "esprima-fb@>=15001.1.0-dev-harmony-fb <15002.0.0",
+          "from": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1.0-dev-harmony-fb.tgz",
           "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1.0-dev-harmony-fb.tgz"
         },
         "object-assign": {
           "version": "2.1.1",
-          "from": "object-assign@>=2.0.0 <3.0.0",
+          "from": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz",
           "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz"
-        },
-        "source-map": {
-          "version": "0.4.4",
-          "from": "source-map@>=0.4.2 <0.5.0"
         }
       }
     },
     "kind-of": {
       "version": "2.0.1",
-      "from": "kind-of@>=2.0.0 <3.0.0",
+      "from": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz",
       "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz"
     },
     "lazy-cache": {
       "version": "0.2.4",
-      "from": "lazy-cache@>=0.2.4 <0.3.0",
+      "from": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.4.tgz",
       "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.4.tgz"
     },
     "lcid": {
       "version": "1.0.0",
-      "from": "lcid@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz"
     },
     "left-pad": {
       "version": "0.0.3",
-      "from": "left-pad@0.0.3",
+      "from": "https://registry.npmjs.org/left-pad/-/left-pad-0.0.3.tgz",
       "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-0.0.3.tgz"
     },
     "leven": {
       "version": "1.0.2",
-      "from": "leven@>=1.0.2 <2.0.0",
+      "from": "https://registry.npmjs.org/leven/-/leven-1.0.2.tgz",
       "resolved": "https://registry.npmjs.org/leven/-/leven-1.0.2.tgz"
     },
     "line-numbers": {
       "version": "0.2.0",
-      "from": "line-numbers@>=0.2.0 <0.3.0",
+      "from": "https://registry.npmjs.org/line-numbers/-/line-numbers-0.2.0.tgz",
       "resolved": "https://registry.npmjs.org/line-numbers/-/line-numbers-0.2.0.tgz"
     },
     "load-json-file": {
       "version": "1.0.1",
-      "from": "load-json-file@>=1.0.0 <2.0.0",
-      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.0.1.tgz",
-      "dependencies": {
-        "graceful-fs": {
-          "version": "4.1.2",
-          "from": "graceful-fs@>=4.1.2 <5.0.0"
-        }
-      }
+      "from": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.0.1.tgz",
+      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.0.1.tgz"
     },
     "lodash": {
       "version": "3.10.1",
-      "from": "lodash@>=3.10.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz"
     },
     "lodash._baseassign": {
       "version": "3.2.0",
-      "from": "lodash._baseassign@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz",
       "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz"
     },
     "lodash._basecopy": {
       "version": "3.0.1",
-      "from": "lodash._basecopy@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz",
       "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz"
     },
     "lodash._baseflatten": {
       "version": "3.1.4",
-      "from": "lodash._baseflatten@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz",
       "resolved": "https://registry.npmjs.org/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz"
     },
     "lodash._basefor": {
       "version": "3.0.2",
-      "from": "lodash._basefor@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.2.tgz",
       "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.2.tgz"
     },
     "lodash._basetostring": {
       "version": "3.0.1",
-      "from": "lodash._basetostring@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz",
       "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz"
     },
     "lodash._basevalues": {
       "version": "3.0.0",
-      "from": "lodash._basevalues@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz",
       "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz"
     },
     "lodash._bindcallback": {
       "version": "3.0.1",
-      "from": "lodash._bindcallback@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz",
       "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz"
     },
     "lodash._createassigner": {
       "version": "3.1.1",
-      "from": "lodash._createassigner@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz",
       "resolved": "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz"
     },
     "lodash._getnative": {
       "version": "3.9.1",
-      "from": "lodash._getnative@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",
       "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz"
     },
     "lodash._isiterateecall": {
       "version": "3.0.9",
-      "from": "lodash._isiterateecall@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz",
       "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz"
     },
     "lodash._pickbyarray": {
       "version": "3.0.2",
-      "from": "lodash._pickbyarray@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash._pickbyarray/-/lodash._pickbyarray-3.0.2.tgz",
       "resolved": "https://registry.npmjs.org/lodash._pickbyarray/-/lodash._pickbyarray-3.0.2.tgz"
     },
     "lodash._pickbycallback": {
       "version": "3.0.0",
-      "from": "lodash._pickbycallback@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash._pickbycallback/-/lodash._pickbycallback-3.0.0.tgz",
       "resolved": "https://registry.npmjs.org/lodash._pickbycallback/-/lodash._pickbycallback-3.0.0.tgz"
     },
     "lodash._reescape": {
       "version": "3.0.0",
-      "from": "lodash._reescape@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz",
       "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz"
     },
     "lodash._reevaluate": {
       "version": "3.0.0",
-      "from": "lodash._reevaluate@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz",
       "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz"
     },
     "lodash._reinterpolate": {
       "version": "3.0.0",
-      "from": "lodash._reinterpolate@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
       "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz"
     },
     "lodash.assign": {
       "version": "3.2.0",
-      "from": "lodash.assign@>=3.2.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz",
       "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz"
     },
     "lodash.escape": {
       "version": "3.0.0",
-      "from": "lodash.escape@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.0.0.tgz",
       "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.0.0.tgz"
     },
     "lodash.flatten": {
       "version": "3.0.2",
-      "from": "lodash.flatten@>=3.0.2 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-3.0.2.tgz",
       "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-3.0.2.tgz"
     },
     "lodash.isarguments": {
       "version": "3.0.4",
-      "from": "lodash.isarguments@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.4.tgz",
       "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.4.tgz"
     },
     "lodash.isarray": {
       "version": "3.0.4",
-      "from": "lodash.isarray@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
       "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz"
     },
     "lodash.keys": {
       "version": "3.1.2",
-      "from": "lodash.keys@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",
       "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz"
     },
     "lodash.keysin": {
       "version": "3.0.8",
-      "from": "lodash.keysin@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz",
       "resolved": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz"
     },
     "lodash.pick": {
       "version": "3.1.0",
-      "from": "lodash.pick@>=3.1.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-3.1.0.tgz",
       "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-3.1.0.tgz"
     },
     "lodash.restparam": {
       "version": "3.6.1",
-      "from": "lodash.restparam@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz",
       "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz"
     },
     "lodash.template": {
       "version": "3.6.2",
-      "from": "lodash.template@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz",
       "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz"
     },
     "lodash.templatesettings": {
       "version": "3.1.0",
-      "from": "lodash.templatesettings@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.0.tgz",
       "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.0.tgz"
     },
     "longest": {
       "version": "1.0.1",
-      "from": "longest@>=1.0.1 <2.0.0",
+      "from": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz"
     },
     "loose-envify": {
       "version": "1.1.0",
-      "from": "loose-envify@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.1.0.tgz",
       "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.1.0.tgz"
     },
     "loud-rejection": {
       "version": "1.0.0",
-      "from": "loud-rejection@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.0.0.tgz"
     },
     "map-obj": {
       "version": "1.0.1",
-      "from": "map-obj@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz"
     },
     "meow": {
       "version": "3.5.0",
-      "from": "meow@*",
+      "from": "https://registry.npmjs.org/meow/-/meow-3.5.0.tgz",
       "resolved": "https://registry.npmjs.org/meow/-/meow-3.5.0.tgz"
     },
     "micromatch": {
       "version": "2.3.0",
-      "from": "micromatch@>=2.1.5 <3.0.0",
+      "from": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.0.tgz",
       "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.0.tgz"
     },
     "minimatch": {
       "version": "2.0.10",
-      "from": "minimatch@>=2.0.3 <3.0.0",
+      "from": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz"
     },
     "minimist": {
       "version": "1.2.0",
-      "from": "minimist@>=1.1.0 <2.0.0",
+      "from": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
       "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
     },
     "mkdirp": {
       "version": "0.5.1",
-      "from": "mkdirp@>=0.5.0 <0.6.0",
+      "from": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
       "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
       "dependencies": {
         "minimist": {
           "version": "0.0.8",
-          "from": "minimist@0.0.8",
+          "from": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
           "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
         }
       }
     },
     "module-deps": {
       "version": "3.9.1",
-      "from": "module-deps@3.9.1",
+      "from": "https://registry.npmjs.org/module-deps/-/module-deps-3.9.1.tgz",
       "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-3.9.1.tgz",
       "dependencies": {
         "JSONStream": {
           "version": "1.0.4",
-          "from": "JSONStream@>=1.0.3 <2.0.0",
+          "from": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.0.4.tgz",
           "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.0.4.tgz",
           "dependencies": {
             "jsonparse": {
               "version": "1.0.0",
-              "from": "jsonparse@>=1.0.0 <1.1.0",
+              "from": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.0.0.tgz",
               "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.0.0.tgz"
-            },
-            "through": {
-              "version": "2.3.8",
-              "from": "through@>=2.2.7 <3.0.0",
-              "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
             }
           }
         },
         "browser-resolve": {
           "version": "1.9.1",
-          "from": "browser-resolve@>=1.7.0 <2.0.0",
+          "from": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.9.1.tgz",
           "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.9.1.tgz"
         },
         "concat-stream": {
           "version": "1.4.10",
-          "from": "concat-stream@>=1.4.5 <1.5.0",
+          "from": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.4.10.tgz",
           "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.4.10.tgz",
           "dependencies": {
             "typedarray": {
               "version": "0.0.6",
-              "from": "typedarray@>=0.0.5 <0.1.0",
+              "from": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
               "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
             }
           }
         },
-        "defined": {
-          "version": "1.0.0",
-          "from": "defined@>=1.0.0 <2.0.0",
-          "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz"
-        },
         "detective": {
           "version": "4.2.0",
-          "from": "detective@>=4.0.0 <5.0.0",
+          "from": "https://registry.npmjs.org/detective/-/detective-4.2.0.tgz",
           "resolved": "https://registry.npmjs.org/detective/-/detective-4.2.0.tgz",
           "dependencies": {
-            "acorn": {
-              "version": "1.2.2",
-              "from": "acorn@>=1.0.3 <2.0.0",
-              "resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz"
-            },
             "escodegen": {
               "version": "1.6.1",
-              "from": "escodegen@>=1.4.1 <2.0.0",
+              "from": "https://registry.npmjs.org/escodegen/-/escodegen-1.6.1.tgz",
               "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.6.1.tgz",
               "dependencies": {
                 "estraverse": {
                   "version": "1.9.3",
-                  "from": "estraverse@>=1.9.1 <2.0.0",
+                  "from": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz",
                   "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz"
                 },
                 "esutils": {
                   "version": "1.1.6",
-                  "from": "esutils@>=1.1.6 <2.0.0",
+                  "from": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz",
                   "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz"
                 },
                 "esprima": {
                   "version": "1.2.5",
-                  "from": "esprima@>=1.2.2 <2.0.0",
+                  "from": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz",
                   "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz"
                 },
                 "optionator": {
                   "version": "0.5.0",
-                  "from": "optionator@>=0.5.0 <0.6.0",
+                  "from": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz",
                   "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz",
                   "dependencies": {
                     "prelude-ls": {
                       "version": "1.1.2",
-                      "from": "prelude-ls@>=1.1.1 <1.2.0",
+                      "from": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
                       "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz"
                     },
                     "deep-is": {
                       "version": "0.1.3",
-                      "from": "deep-is@>=0.1.2 <0.2.0",
+                      "from": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
                       "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz"
                     },
                     "wordwrap": {
                       "version": "0.0.3",
-                      "from": "wordwrap@>=0.0.2 <0.1.0",
+                      "from": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
                       "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
                     },
                     "type-check": {
                       "version": "0.3.1",
-                      "from": "type-check@>=0.3.1 <0.4.0",
+                      "from": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz",
                       "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz"
                     },
                     "levn": {
                       "version": "0.2.5",
-                      "from": "levn@>=0.2.5 <0.3.0",
+                      "from": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz",
                       "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz"
                     },
                     "fast-levenshtein": {
                       "version": "1.0.7",
-                      "from": "fast-levenshtein@>=1.0.0 <1.1.0",
+                      "from": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz",
                       "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz"
                     }
                   }
                 },
                 "source-map": {
                   "version": "0.1.43",
-                  "from": "source-map@>=0.1.40 <0.2.0",
-                  "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz",
-                  "dependencies": {
-                    "amdefine": {
-                      "version": "1.0.0",
-                      "from": "amdefine@>=0.0.4",
-                      "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz"
-                    }
-                  }
+                  "from": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz",
+                  "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz"
                 }
               }
             }
           }
         },
-        "duplexer2": {
-          "version": "0.0.2",
-          "from": "duplexer2@0.0.2",
-          "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz"
-        },
-        "inherits": {
-          "version": "2.0.1",
-          "from": "inherits@>=2.0.1 <3.0.0",
-          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-        },
         "parents": {
           "version": "1.0.1",
-          "from": "parents@>=1.0.0 <2.0.0",
+          "from": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz",
           "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz",
           "dependencies": {
             "path-platform": {
               "version": "0.11.15",
-              "from": "path-platform@>=0.11.15 <0.12.0",
+              "from": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz",
               "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz"
             }
           }
         },
         "readable-stream": {
           "version": "1.1.13",
-          "from": "readable-stream@>=1.1.13 <2.0.0",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz",
-          "dependencies": {
-            "core-util-is": {
-              "version": "1.0.1",
-              "from": "core-util-is@>=1.0.0 <1.1.0",
-              "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-            },
-            "isarray": {
-              "version": "0.0.1",
-              "from": "isarray@0.0.1",
-              "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
-            },
-            "string_decoder": {
-              "version": "0.10.31",
-              "from": "string_decoder@>=0.10.0 <0.11.0",
-              "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
-            }
-          }
-        },
-        "resolve": {
-          "version": "1.1.6",
-          "from": "resolve@>=1.1.3 <2.0.0",
-          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.6.tgz"
+          "from": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz"
         },
         "stream-combiner2": {
           "version": "1.0.2",
-          "from": "stream-combiner2@>=1.0.0 <1.1.0",
+          "from": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.0.2.tgz",
           "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.0.2.tgz",
           "dependencies": {
             "through2": {
               "version": "0.5.1",
-              "from": "through2@>=0.5.1 <0.6.0",
+              "from": "https://registry.npmjs.org/through2/-/through2-0.5.1.tgz",
               "resolved": "https://registry.npmjs.org/through2/-/through2-0.5.1.tgz",
               "dependencies": {
                 "readable-stream": {
                   "version": "1.0.33",
-                  "from": "readable-stream@>=1.0.17 <1.1.0",
-                  "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz",
-                  "dependencies": {
-                    "core-util-is": {
-                      "version": "1.0.1",
-                      "from": "core-util-is@>=1.0.0 <1.1.0",
-                      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-                    },
-                    "isarray": {
-                      "version": "0.0.1",
-                      "from": "isarray@0.0.1",
-                      "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
-                    },
-                    "string_decoder": {
-                      "version": "0.10.31",
-                      "from": "string_decoder@>=0.10.0 <0.11.0",
-                      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
-                    }
-                  }
+                  "from": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz",
+                  "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz"
                 },
                 "xtend": {
                   "version": "3.0.0",
-                  "from": "xtend@>=3.0.0 <3.1.0",
+                  "from": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz"
                 }
               }
@@ -3911,230 +3808,192 @@
         },
         "subarg": {
           "version": "1.0.0",
-          "from": "subarg@>=1.0.0 <2.0.0",
-          "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz",
-          "dependencies": {
-            "minimist": {
-              "version": "1.2.0",
-              "from": "minimist@>=1.1.0 <2.0.0",
-              "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
-            }
-          }
+          "from": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz",
+          "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz"
         },
         "through2": {
           "version": "1.1.1",
-          "from": "through2@>=1.0.0 <2.0.0",
+          "from": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz",
           "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz"
         },
         "xtend": {
           "version": "4.0.0",
-          "from": "xtend@>=4.0.0 <5.0.0",
+          "from": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz",
           "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz"
         }
       }
     },
     "ms": {
       "version": "0.7.1",
-      "from": "ms@0.7.1",
+      "from": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
       "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz"
     },
     "multipipe": {
       "version": "0.1.2",
-      "from": "multipipe@>=0.1.2 <0.2.0",
+      "from": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz",
       "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz"
     },
     "nan": {
       "version": "2.1.0",
-      "from": "nan@>=2.0.2 <3.0.0",
+      "from": "https://registry.npmjs.org/nan/-/nan-2.1.0.tgz",
       "resolved": "https://registry.npmjs.org/nan/-/nan-2.1.0.tgz"
     },
     "node-fetch": {
       "version": "1.3.3",
-      "from": "node-fetch@1.3.3",
+      "from": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.3.3.tgz",
       "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.3.3.tgz",
       "dependencies": {
         "encoding": {
           "version": "0.1.11",
-          "from": "encoding@>=0.1.11 <0.2.0",
-          "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.11.tgz",
-          "dependencies": {
-            "iconv-lite": {
-              "version": "0.4.13",
-              "from": "iconv-lite@>=0.4.4 <0.5.0",
-              "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz"
-            }
-          }
+          "from": "https://registry.npmjs.org/encoding/-/encoding-0.1.11.tgz",
+          "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.11.tgz"
         }
       }
     },
     "normalize-package-data": {
       "version": "2.3.5",
-      "from": "normalize-package-data@>=2.3.4 <3.0.0",
-      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.5.tgz",
-      "dependencies": {
-        "semver": {
-          "version": "5.0.3",
-          "from": "semver@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0||>=4.0.0 <5.0.0||>=5.0.0 <6.0.0"
-        }
-      }
+      "from": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.5.tgz",
+      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.5.tgz"
     },
     "normalize-path": {
       "version": "2.0.0",
-      "from": "normalize-path@>=2.0.0 <3.0.0",
+      "from": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.0.0.tgz",
       "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.0.0.tgz"
     },
     "number-is-nan": {
       "version": "1.0.0",
-      "from": "number-is-nan@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz"
     },
     "object-assign": {
       "version": "4.0.1",
-      "from": "object-assign@>=4.0.1 <5.0.0",
+      "from": "https://registry.npmjs.org/object-assign/-/object-assign-4.0.1.tgz",
       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.0.1.tgz"
     },
     "object.omit": {
       "version": "2.0.0",
-      "from": "object.omit@>=2.0.0 <3.0.0",
+      "from": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.0.tgz",
       "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.0.tgz"
     },
     "once": {
       "version": "1.3.2",
-      "from": "once@>=1.3.0 <2.0.0",
+      "from": "https://registry.npmjs.org/once/-/once-1.3.2.tgz",
       "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz"
     },
     "opn": {
       "version": "3.0.2",
-      "from": "opn@*",
+      "from": "https://registry.npmjs.org/opn/-/opn-3.0.2.tgz",
       "resolved": "https://registry.npmjs.org/opn/-/opn-3.0.2.tgz",
       "dependencies": {
         "object-assign": {
           "version": "3.0.0",
-          "from": "object-assign@>=3.0.0 <4.0.0",
+          "from": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
           "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz"
         }
       }
     },
     "optimist": {
       "version": "0.6.1",
-      "from": "optimist@0.6.1",
+      "from": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
       "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
       "dependencies": {
         "wordwrap": {
           "version": "0.0.3",
-          "from": "wordwrap@>=0.0.2 <0.1.0",
+          "from": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
           "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
         },
         "minimist": {
           "version": "0.0.10",
-          "from": "minimist@>=0.0.1 <0.1.0",
+          "from": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
           "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz"
         }
       }
     },
     "os-locale": {
       "version": "1.4.0",
-      "from": "os-locale@>=1.4.0 <2.0.0",
+      "from": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
       "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz"
     },
     "os-tmpdir": {
       "version": "1.0.1",
-      "from": "os-tmpdir@>=1.0.1 <2.0.0",
+      "from": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.1.tgz"
     },
     "output-file-sync": {
       "version": "1.1.1",
-      "from": "output-file-sync@>=1.1.0 <2.0.0",
+      "from": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.1.tgz",
       "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.1.tgz"
     },
     "parse-glob": {
       "version": "3.0.4",
-      "from": "parse-glob@>=3.0.1 <4.0.0",
+      "from": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
       "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz"
     },
     "parse-json": {
       "version": "2.2.0",
-      "from": "parse-json@>=2.2.0 <3.0.0",
+      "from": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
       "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz"
     },
     "path-exists": {
       "version": "1.0.0",
-      "from": "path-exists@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz"
     },
     "path-is-absolute": {
       "version": "1.0.0",
-      "from": "path-is-absolute@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz"
     },
     "path-type": {
       "version": "1.0.0",
-      "from": "path-type@>=1.0.0 <2.0.0",
-      "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.0.0.tgz",
-      "dependencies": {
-        "graceful-fs": {
-          "version": "4.1.2",
-          "from": "graceful-fs@>=4.1.2 <5.0.0"
-        }
-      }
+      "from": "https://registry.npmjs.org/path-type/-/path-type-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.0.0.tgz"
     },
     "pify": {
       "version": "2.3.0",
-      "from": "pify@>=2.0.0 <3.0.0",
+      "from": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
       "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz"
     },
     "pinkie": {
       "version": "1.0.0",
-      "from": "pinkie@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
     },
     "pinkie-promise": {
       "version": "1.0.0",
-      "from": "pinkie-promise@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz"
     },
     "portfinder": {
       "version": "0.4.0",
-      "from": "portfinder@0.4.0",
+      "from": "https://registry.npmjs.org/portfinder/-/portfinder-0.4.0.tgz",
       "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-0.4.0.tgz",
       "dependencies": {
         "async": {
           "version": "0.9.0",
-          "from": "async@0.9.0",
+          "from": "https://registry.npmjs.org/async/-/async-0.9.0.tgz",
           "resolved": "https://registry.npmjs.org/async/-/async-0.9.0.tgz"
-        },
-        "mkdirp": {
-          "version": "0.5.1",
-          "from": "mkdirp@>=0.5.0 <0.6.0",
-          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
-          "dependencies": {
-            "minimist": {
-              "version": "0.0.8",
-              "from": "minimist@0.0.8",
-              "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
-            }
-          }
         }
       }
     },
     "preserve": {
       "version": "0.2.0",
-      "from": "preserve@>=0.2.0 <0.3.0",
+      "from": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
       "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz"
     },
     "private": {
       "version": "0.1.6",
-      "from": "private@>=0.1.6 <0.2.0",
+      "from": "https://registry.npmjs.org/private/-/private-0.1.6.tgz",
       "resolved": "https://registry.npmjs.org/private/-/private-0.1.6.tgz"
     },
     "process-nextick-args": {
       "version": "1.0.3",
-      "from": "process-nextick-args@>=1.0.0 <1.1.0",
+      "from": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.3.tgz",
       "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.3.tgz"
     },
     "progress": {
       "version": "1.1.8",
-      "from": "progress@>=1.1.8 <2.0.0",
+      "from": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz",
       "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz"
     },
     "promise": {
@@ -4144,56 +4003,56 @@
       "dependencies": {
         "asap": {
           "version": "2.0.3",
-          "from": "asap@>=2.0.3 <2.1.0",
+          "from": "https://registry.npmjs.org/asap/-/asap-2.0.3.tgz",
           "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.3.tgz"
         }
       }
     },
     "q": {
       "version": "1.4.1",
-      "from": "q@>=1.1.2 <2.0.0",
+      "from": "https://registry.npmjs.org/q/-/q-1.4.1.tgz",
       "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz"
     },
     "randomatic": {
       "version": "1.1.0",
-      "from": "randomatic@>=1.1.0 <2.0.0",
+      "from": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.0.tgz",
       "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.0.tgz",
       "dependencies": {
         "kind-of": {
           "version": "1.1.0",
-          "from": "kind-of@>=1.0.0 <2.0.0",
+          "from": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz",
           "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz"
         }
       }
     },
     "react": {
       "version": "0.14.5",
-      "from": "react@>=0.14.5 <0.15.0",
+      "from": "https://registry.npmjs.org/react/-/react-0.14.5.tgz",
       "resolved": "https://registry.npmjs.org/react/-/react-0.14.5.tgz",
       "dependencies": {
         "envify": {
           "version": "3.4.0",
-          "from": "envify@>=3.0.0 <4.0.0",
+          "from": "https://registry.npmjs.org/envify/-/envify-3.4.0.tgz",
           "resolved": "https://registry.npmjs.org/envify/-/envify-3.4.0.tgz",
           "dependencies": {
             "jstransform": {
               "version": "10.1.0",
-              "from": "jstransform@>=10.0.1 <11.0.0",
+              "from": "https://registry.npmjs.org/jstransform/-/jstransform-10.1.0.tgz",
               "resolved": "https://registry.npmjs.org/jstransform/-/jstransform-10.1.0.tgz",
               "dependencies": {
                 "base62": {
                   "version": "0.1.1",
-                  "from": "base62@0.1.1",
+                  "from": "https://registry.npmjs.org/base62/-/base62-0.1.1.tgz",
                   "resolved": "https://registry.npmjs.org/base62/-/base62-0.1.1.tgz"
                 },
                 "esprima-fb": {
                   "version": "13001.1001.0-dev-harmony-fb",
-                  "from": "esprima-fb@13001.1001.0-dev-harmony-fb",
+                  "from": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-13001.1001.0-dev-harmony-fb.tgz",
                   "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-13001.1001.0-dev-harmony-fb.tgz"
                 },
                 "source-map": {
                   "version": "0.1.31",
-                  "from": "source-map@0.1.31",
+                  "from": "https://registry.npmjs.org/source-map/-/source-map-0.1.31.tgz",
                   "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.31.tgz"
                 }
               }
@@ -4204,46 +4063,46 @@
     },
     "react-timer-mixin": {
       "version": "0.13.2",
-      "from": "react-timer-mixin@>=0.13.1 <0.14.0",
+      "from": "https://registry.npmjs.org/react-timer-mixin/-/react-timer-mixin-0.13.2.tgz",
       "resolved": "https://registry.npmjs.org/react-timer-mixin/-/react-timer-mixin-0.13.2.tgz"
     },
     "react-transform-hmr": {
-      "version": "1.0.1",
-      "from": "https://registry.npmjs.org/react-transform-hmr/-/react-transform-hmr-1.0.1.tgz",
-      "resolved": "https://registry.npmjs.org/react-transform-hmr/-/react-transform-hmr-1.0.1.tgz",
+      "version": "1.0.2",
+      "from": "https://registry.npmjs.org/react-transform-hmr/-/react-transform-hmr-1.0.2.tgz",
+      "resolved": "https://registry.npmjs.org/react-transform-hmr/-/react-transform-hmr-1.0.2.tgz",
       "dependencies": {
         "global": {
           "version": "4.3.0",
-          "from": "global@>=4.3.0 <5.0.0",
+          "from": "https://registry.npmjs.org/global/-/global-4.3.0.tgz",
           "resolved": "https://registry.npmjs.org/global/-/global-4.3.0.tgz",
           "dependencies": {
             "min-document": {
-              "version": "2.17.0",
-              "from": "min-document@>=2.6.1 <3.0.0",
-              "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.17.0.tgz",
+              "version": "2.18.0",
+              "from": "https://registry.npmjs.org/min-document/-/min-document-2.18.0.tgz",
+              "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.18.0.tgz",
               "dependencies": {
                 "dom-walk": {
                   "version": "0.1.1",
-                  "from": "dom-walk@>=0.1.0 <0.2.0",
+                  "from": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz",
                   "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz"
                 }
               }
             },
             "process": {
               "version": "0.5.2",
-              "from": "process@>=0.5.1 <0.6.0",
+              "from": "https://registry.npmjs.org/process/-/process-0.5.2.tgz",
               "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz"
             }
           }
         },
         "react-proxy": {
           "version": "1.1.2",
-          "from": "react-proxy@>=1.1.1 <2.0.0",
+          "from": "https://registry.npmjs.org/react-proxy/-/react-proxy-1.1.2.tgz",
           "resolved": "https://registry.npmjs.org/react-proxy/-/react-proxy-1.1.2.tgz",
           "dependencies": {
             "react-deep-force-update": {
               "version": "1.0.1",
-              "from": "react-deep-force-update@>=1.0.0 <2.0.0",
+              "from": "https://registry.npmjs.org/react-deep-force-update/-/react-deep-force-update-1.0.1.tgz",
               "resolved": "https://registry.npmjs.org/react-deep-force-update/-/react-deep-force-update-1.0.1.tgz"
             }
           }
@@ -4252,375 +4111,262 @@
     },
     "read-pkg": {
       "version": "1.1.0",
-      "from": "read-pkg@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
       "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz"
     },
     "read-pkg-up": {
       "version": "1.0.1",
-      "from": "read-pkg-up@>=1.0.1 <2.0.0",
+      "from": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz"
     },
     "readable-stream": {
       "version": "2.0.4",
-      "from": "readable-stream@>=2.0.2 <3.0.0",
+      "from": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.4.tgz",
       "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.4.tgz"
     },
     "readdirp": {
       "version": "2.0.0",
-      "from": "readdirp@>=2.0.0 <3.0.0",
-      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.0.0.tgz",
-      "dependencies": {
-        "graceful-fs": {
-          "version": "4.1.2",
-          "from": "graceful-fs@>=4.1.2 <5.0.0"
-        }
-      }
+      "from": "https://registry.npmjs.org/readdirp/-/readdirp-2.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.0.0.tgz"
     },
     "rebound": {
       "version": "0.0.13",
-      "from": "rebound@>=0.0.13 <0.0.14",
+      "from": "https://registry.npmjs.org/rebound/-/rebound-0.0.13.tgz",
       "resolved": "https://registry.npmjs.org/rebound/-/rebound-0.0.13.tgz"
     },
     "recast": {
       "version": "0.10.37",
-      "from": "recast@>=0.10.0 <0.11.0",
+      "from": "https://registry.npmjs.org/recast/-/recast-0.10.37.tgz",
       "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.37.tgz",
       "dependencies": {
-        "ast-types": {
-          "version": "0.8.12",
-          "from": "ast-types@0.8.12",
-          "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz"
-        },
         "source-map": {
           "version": "0.5.3",
-          "from": "source-map@>=0.5.0 <0.6.0",
+          "from": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz"
+        },
+        "ast-types": {
+          "version": "0.8.12",
+          "from": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz",
+          "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz"
         }
       }
     },
     "redent": {
       "version": "1.0.0",
-      "from": "redent@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz"
     },
     "regenerate": {
       "version": "1.2.1",
-      "from": "regenerate@>=1.2.1 <2.0.0",
+      "from": "https://registry.npmjs.org/regenerate/-/regenerate-1.2.1.tgz",
       "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.2.1.tgz"
     },
     "regenerator": {
       "version": "0.8.36",
-      "from": "regenerator@0.8.36",
+      "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.36.tgz",
       "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.36.tgz",
       "dependencies": {
         "commoner": {
           "version": "0.10.3",
-          "from": "commoner@>=0.10.0 <0.11.0",
+          "from": "https://registry.npmjs.org/commoner/-/commoner-0.10.3.tgz",
           "resolved": "https://registry.npmjs.org/commoner/-/commoner-0.10.3.tgz",
           "dependencies": {
             "q": {
               "version": "1.1.2",
-              "from": "q@>=1.1.2 <1.2.0",
+              "from": "https://registry.npmjs.org/q/-/q-1.1.2.tgz",
               "resolved": "https://registry.npmjs.org/q/-/q-1.1.2.tgz"
             },
             "commander": {
               "version": "2.5.1",
-              "from": "commander@>=2.5.0 <2.6.0",
+              "from": "https://registry.npmjs.org/commander/-/commander-2.5.1.tgz",
               "resolved": "https://registry.npmjs.org/commander/-/commander-2.5.1.tgz"
             },
             "graceful-fs": {
               "version": "3.0.8",
-              "from": "graceful-fs@>=3.0.4 <3.1.0",
+              "from": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.8.tgz",
               "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.8.tgz"
             },
             "glob": {
               "version": "4.2.2",
-              "from": "glob@>=4.2.1 <4.3.0",
+              "from": "https://registry.npmjs.org/glob/-/glob-4.2.2.tgz",
               "resolved": "https://registry.npmjs.org/glob/-/glob-4.2.2.tgz",
               "dependencies": {
-                "inflight": {
-                  "version": "1.0.4",
-                  "from": "inflight@>=1.0.4 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz",
-                  "dependencies": {
-                    "wrappy": {
-                      "version": "1.0.1",
-                      "from": "wrappy@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
-                    }
-                  }
-                },
-                "inherits": {
-                  "version": "2.0.1",
-                  "from": "inherits@>=2.0.0 <3.0.0",
-                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                },
                 "minimatch": {
                   "version": "1.0.0",
-                  "from": "minimatch@>=1.0.0 <2.0.0",
+                  "from": "https://registry.npmjs.org/minimatch/-/minimatch-1.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-1.0.0.tgz",
                   "dependencies": {
                     "lru-cache": {
                       "version": "2.6.5",
-                      "from": "lru-cache@>=2.0.0 <3.0.0",
+                      "from": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.6.5.tgz",
                       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.6.5.tgz"
                     },
                     "sigmund": {
                       "version": "1.0.1",
-                      "from": "sigmund@>=1.0.0 <1.1.0",
+                      "from": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
                       "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz"
                     }
                   }
-                },
-                "once": {
-                  "version": "1.3.2",
-                  "from": "once@>=1.3.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz",
-                  "dependencies": {
-                    "wrappy": {
-                      "version": "1.0.1",
-                      "from": "wrappy@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
-                    }
-                  }
-                }
-              }
-            },
-            "mkdirp": {
-              "version": "0.5.1",
-              "from": "mkdirp@>=0.5.0 <0.6.0",
-              "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
-              "dependencies": {
-                "minimist": {
-                  "version": "0.0.8",
-                  "from": "minimist@0.0.8",
-                  "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
                 }
               }
             },
             "install": {
               "version": "0.1.8",
-              "from": "install@>=0.1.7 <0.2.0",
+              "from": "https://registry.npmjs.org/install/-/install-0.1.8.tgz",
               "resolved": "https://registry.npmjs.org/install/-/install-0.1.8.tgz"
             },
             "iconv-lite": {
               "version": "0.4.11",
-              "from": "iconv-lite@>=0.4.5 <0.5.0",
+              "from": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.11.tgz",
               "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.11.tgz"
             }
           }
         },
         "defs": {
           "version": "1.1.0",
-          "from": "defs@>=1.1.0 <1.2.0",
+          "from": "https://registry.npmjs.org/defs/-/defs-1.1.0.tgz",
           "resolved": "https://registry.npmjs.org/defs/-/defs-1.1.0.tgz",
           "dependencies": {
-            "alter": {
-              "version": "0.2.0",
-              "from": "alter@>=0.2.0 <0.3.0",
-              "resolved": "https://registry.npmjs.org/alter/-/alter-0.2.0.tgz",
-              "dependencies": {
-                "stable": {
-                  "version": "0.1.5",
-                  "from": "stable@>=0.1.3 <0.2.0",
-                  "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.5.tgz"
-                }
-              }
-            },
-            "ast-traverse": {
-              "version": "0.1.1",
-              "from": "ast-traverse@>=0.1.1 <0.2.0",
-              "resolved": "https://registry.npmjs.org/ast-traverse/-/ast-traverse-0.1.1.tgz"
-            },
-            "breakable": {
-              "version": "1.0.0",
-              "from": "breakable@>=1.0.0 <1.1.0",
-              "resolved": "https://registry.npmjs.org/breakable/-/breakable-1.0.0.tgz"
-            },
             "esprima-fb": {
               "version": "8001.1001.0-dev-harmony-fb",
-              "from": "esprima-fb@>=8001.1001.0-dev-harmony-fb <8001.1002.0",
+              "from": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-8001.1001.0-dev-harmony-fb.tgz",
               "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-8001.1001.0-dev-harmony-fb.tgz"
             },
-            "simple-fmt": {
-              "version": "0.1.0",
-              "from": "simple-fmt@>=0.1.0 <0.2.0",
-              "resolved": "https://registry.npmjs.org/simple-fmt/-/simple-fmt-0.1.0.tgz"
-            },
-            "simple-is": {
-              "version": "0.2.0",
-              "from": "simple-is@>=0.2.0 <0.3.0",
-              "resolved": "https://registry.npmjs.org/simple-is/-/simple-is-0.2.0.tgz"
-            },
-            "stringmap": {
-              "version": "0.2.2",
-              "from": "stringmap@>=0.2.2 <0.3.0",
-              "resolved": "https://registry.npmjs.org/stringmap/-/stringmap-0.2.2.tgz"
-            },
-            "stringset": {
-              "version": "0.2.1",
-              "from": "stringset@>=0.2.1 <0.3.0",
-              "resolved": "https://registry.npmjs.org/stringset/-/stringset-0.2.1.tgz"
-            },
-            "tryor": {
-              "version": "0.1.2",
-              "from": "tryor@>=0.1.2 <0.2.0",
-              "resolved": "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz"
-            },
             "yargs": {
               "version": "1.3.3",
-              "from": "yargs@>=1.3.2 <1.4.0",
+              "from": "https://registry.npmjs.org/yargs/-/yargs-1.3.3.tgz",
               "resolved": "https://registry.npmjs.org/yargs/-/yargs-1.3.3.tgz"
             }
           }
         },
         "esprima-fb": {
           "version": "15001.1.0-dev-harmony-fb",
-          "from": "esprima-fb@>=15001.1.0-dev-harmony-fb <15001.2.0",
+          "from": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1.0-dev-harmony-fb.tgz",
           "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1.0-dev-harmony-fb.tgz"
         },
-        "private": {
-          "version": "0.1.6",
-          "from": "private@>=0.1.5 <0.2.0",
-          "resolved": "https://registry.npmjs.org/private/-/private-0.1.6.tgz"
-        },
         "recast": {
           "version": "0.10.25",
-          "from": "recast@0.10.25",
+          "from": "https://registry.npmjs.org/recast/-/recast-0.10.25.tgz",
           "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.25.tgz",
           "dependencies": {
-            "source-map": {
-              "version": "0.4.4",
-              "from": "source-map@>=0.4.1 <0.5.0"
-            },
             "ast-types": {
               "version": "0.8.5",
-              "from": "ast-types@0.8.5",
+              "from": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.5.tgz",
               "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.5.tgz"
             }
           }
-        },
-        "through": {
-          "version": "2.3.8",
-          "from": "through@>=2.3.6 <2.4.0",
-          "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
         }
       }
     },
     "regex-cache": {
       "version": "0.4.2",
-      "from": "regex-cache@>=0.4.2 <0.5.0",
+      "from": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.2.tgz",
       "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.2.tgz"
     },
     "regexpu": {
       "version": "1.3.0",
-      "from": "regexpu@>=1.3.0 <2.0.0",
+      "from": "https://registry.npmjs.org/regexpu/-/regexpu-1.3.0.tgz",
       "resolved": "https://registry.npmjs.org/regexpu/-/regexpu-1.3.0.tgz",
       "dependencies": {
         "esprima": {
           "version": "2.7.0",
-          "from": "esprima@>=2.6.0 <3.0.0",
+          "from": "https://registry.npmjs.org/esprima/-/esprima-2.7.0.tgz",
           "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.0.tgz"
         }
       }
     },
     "regjsgen": {
       "version": "0.2.0",
-      "from": "regjsgen@>=0.2.0 <0.3.0",
+      "from": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz",
       "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz"
     },
     "regjsparser": {
       "version": "0.1.5",
-      "from": "regjsparser@>=0.1.4 <0.2.0",
+      "from": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz",
       "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz"
     },
     "repeat-element": {
       "version": "1.1.2",
-      "from": "repeat-element@>=1.1.2 <2.0.0",
+      "from": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
       "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz"
     },
     "repeat-string": {
       "version": "1.5.2",
-      "from": "repeat-string@>=1.5.2 <2.0.0",
+      "from": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.2.tgz",
       "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.2.tgz"
     },
     "repeating": {
       "version": "1.1.3",
-      "from": "repeating@>=1.1.3 <2.0.0",
+      "from": "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz",
       "resolved": "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz"
     },
     "replace-ext": {
       "version": "0.0.1",
-      "from": "replace-ext@0.0.1",
+      "from": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz",
       "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz"
     },
     "resolve": {
       "version": "1.1.6",
-      "from": "resolve@>=1.1.6 <2.0.0",
+      "from": "https://registry.npmjs.org/resolve/-/resolve-1.1.6.tgz",
       "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.6.tgz"
     },
     "right-align": {
       "version": "0.1.3",
-      "from": "right-align@>=0.1.1 <0.2.0",
+      "from": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
       "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz"
     },
     "sane": {
       "version": "1.2.0",
-      "from": "sane@>=1.2.0 <1.3.0",
+      "from": "https://registry.npmjs.org/sane/-/sane-1.2.0.tgz",
       "resolved": "https://registry.npmjs.org/sane/-/sane-1.2.0.tgz",
       "dependencies": {
         "exec-sh": {
           "version": "0.2.0",
-          "from": "exec-sh@>=0.2.0 <0.3.0",
+          "from": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.0.tgz",
           "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.0.tgz",
           "dependencies": {
             "merge": {
               "version": "1.2.0",
-              "from": "merge@>=1.1.3 <2.0.0",
+              "from": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz",
               "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz"
             }
           }
         },
         "fb-watchman": {
           "version": "1.6.0",
-          "from": "fb-watchman@>=1.5.0 <2.0.0",
+          "from": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.6.0.tgz",
           "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.6.0.tgz"
         },
         "minimatch": {
           "version": "0.2.14",
-          "from": "minimatch@>=0.2.14 <0.3.0",
+          "from": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz",
           "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz",
           "dependencies": {
             "lru-cache": {
               "version": "2.6.5",
-              "from": "lru-cache@>=2.0.0 <3.0.0",
+              "from": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.6.5.tgz",
               "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.6.5.tgz"
             },
             "sigmund": {
               "version": "1.0.1",
-              "from": "sigmund@>=1.0.0 <1.1.0",
+              "from": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
               "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz"
             }
           }
         },
-        "minimist": {
-          "version": "1.2.0",
-          "from": "minimist@>=1.1.1 <2.0.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
-        },
         "walker": {
           "version": "1.0.7",
-          "from": "walker@>=1.0.5 <1.1.0",
+          "from": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz",
           "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz",
           "dependencies": {
             "makeerror": {
               "version": "1.0.11",
-              "from": "makeerror@>=1.0.0 <1.1.0",
+              "from": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz",
               "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz",
               "dependencies": {
                 "tmpl": {
                   "version": "1.0.4",
-                  "from": "tmpl@>=1.0.0 <1.1.0",
+                  "from": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz",
                   "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz"
                 }
               }
@@ -4629,230 +4375,213 @@
         },
         "watch": {
           "version": "0.10.0",
-          "from": "watch@>=0.10.0 <0.11.0",
+          "from": "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz",
           "resolved": "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz"
         }
       }
     },
     "semver": {
       "version": "5.0.3",
-      "from": "semver@>=5.0.1 <6.0.0",
+      "from": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz",
       "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
     },
     "shebang-regex": {
       "version": "1.0.0",
-      "from": "shebang-regex@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz"
     },
     "simple-fmt": {
       "version": "0.1.0",
-      "from": "simple-fmt@>=0.1.0 <0.2.0",
+      "from": "https://registry.npmjs.org/simple-fmt/-/simple-fmt-0.1.0.tgz",
       "resolved": "https://registry.npmjs.org/simple-fmt/-/simple-fmt-0.1.0.tgz"
     },
     "simple-is": {
       "version": "0.2.0",
-      "from": "simple-is@>=0.2.0 <0.3.0",
+      "from": "https://registry.npmjs.org/simple-is/-/simple-is-0.2.0.tgz",
       "resolved": "https://registry.npmjs.org/simple-is/-/simple-is-0.2.0.tgz"
     },
     "slash": {
       "version": "1.0.0",
-      "from": "slash@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz"
     },
     "source-map": {
       "version": "0.4.4",
-      "from": "source-map@>=0.4.4 <0.5.0",
+      "from": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
       "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz"
     },
     "source-map-support": {
       "version": "0.2.10",
-      "from": "source-map-support@>=0.2.10 <0.3.0",
+      "from": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.2.10.tgz",
       "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.2.10.tgz",
       "dependencies": {
         "source-map": {
           "version": "0.1.32",
-          "from": "source-map@0.1.32",
+          "from": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz"
         }
       }
     },
     "sparkles": {
       "version": "1.0.0",
-      "from": "sparkles@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.0.tgz"
     },
     "spdx-correct": {
       "version": "1.0.2",
-      "from": "spdx-correct@>=1.0.0 <1.1.0",
+      "from": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz",
       "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz"
     },
     "spdx-exceptions": {
       "version": "1.0.4",
-      "from": "spdx-exceptions@>=1.0.4 <2.0.0",
+      "from": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-1.0.4.tgz",
       "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-1.0.4.tgz"
     },
     "spdx-expression-parse": {
       "version": "1.0.1",
-      "from": "spdx-expression-parse@>=1.0.0 <1.1.0",
+      "from": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.1.tgz"
     },
     "spdx-license-ids": {
       "version": "1.1.0",
-      "from": "spdx-license-ids@>=1.0.2 <2.0.0",
+      "from": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.1.0.tgz",
       "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.1.0.tgz"
     },
     "stable": {
       "version": "0.1.5",
-      "from": "stable@>=0.1.3 <0.2.0",
+      "from": "https://registry.npmjs.org/stable/-/stable-0.1.5.tgz",
       "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.5.tgz"
     },
     "stacktrace-parser": {
       "version": "0.1.3",
-      "from": "stacktrace-parser@0.1.3",
+      "from": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.3.tgz",
       "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.3.tgz"
     },
     "string_decoder": {
       "version": "0.10.31",
-      "from": "string_decoder@>=0.10.0 <0.11.0",
+      "from": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
       "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
     },
     "stringmap": {
       "version": "0.2.2",
-      "from": "stringmap@>=0.2.2 <0.3.0",
+      "from": "https://registry.npmjs.org/stringmap/-/stringmap-0.2.2.tgz",
       "resolved": "https://registry.npmjs.org/stringmap/-/stringmap-0.2.2.tgz"
     },
     "stringset": {
       "version": "0.2.1",
-      "from": "stringset@>=0.2.1 <0.3.0",
+      "from": "https://registry.npmjs.org/stringset/-/stringset-0.2.1.tgz",
       "resolved": "https://registry.npmjs.org/stringset/-/stringset-0.2.1.tgz"
     },
     "strip-ansi": {
       "version": "3.0.0",
-      "from": "strip-ansi@>=3.0.0 <4.0.0",
+      "from": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz",
       "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz"
     },
     "strip-bom": {
       "version": "2.0.0",
-      "from": "strip-bom@>=2.0.0 <3.0.0",
+      "from": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
       "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz"
     },
     "strip-indent": {
       "version": "1.0.1",
-      "from": "strip-indent@>=1.0.1 <2.0.0",
+      "from": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz"
     },
     "success-symbol": {
       "version": "0.1.0",
-      "from": "success-symbol@>=0.1.0 <0.2.0",
+      "from": "https://registry.npmjs.org/success-symbol/-/success-symbol-0.1.0.tgz",
       "resolved": "https://registry.npmjs.org/success-symbol/-/success-symbol-0.1.0.tgz"
     },
     "supports-color": {
       "version": "2.0.0",
-      "from": "supports-color@>=2.0.0 <3.0.0",
+      "from": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
     },
     "temp": {
       "version": "0.8.3",
-      "from": "temp@0.8.3",
+      "from": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz",
       "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz",
       "dependencies": {
-        "os-tmpdir": {
-          "version": "1.0.1",
-          "from": "os-tmpdir@>=1.0.0 <2.0.0",
-          "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.1.tgz"
-        },
         "rimraf": {
           "version": "2.2.8",
-          "from": "rimraf@>=2.2.6 <2.3.0",
+          "from": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz",
           "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz"
         }
       }
     },
     "through": {
       "version": "2.3.8",
-      "from": "through@>=2.3.6 <2.4.0",
+      "from": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
       "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
     },
     "through2": {
       "version": "2.0.0",
-      "from": "through2@>=2.0.0 <3.0.0",
+      "from": "https://registry.npmjs.org/through2/-/through2-2.0.0.tgz",
       "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.0.tgz"
     },
     "to-fast-properties": {
       "version": "1.0.1",
-      "from": "to-fast-properties@>=1.0.1 <2.0.0",
+      "from": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.1.tgz"
     },
     "trim-newlines": {
       "version": "1.0.0",
-      "from": "trim-newlines@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz"
     },
     "trim-right": {
       "version": "1.0.1",
-      "from": "trim-right@>=1.0.1 <2.0.0",
+      "from": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz"
     },
     "try-resolve": {
       "version": "1.0.1",
-      "from": "try-resolve@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/try-resolve/-/try-resolve-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/try-resolve/-/try-resolve-1.0.1.tgz"
     },
     "tryor": {
       "version": "0.1.2",
-      "from": "tryor@>=0.1.2 <0.2.0",
+      "from": "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz",
       "resolved": "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz"
     },
     "uglify-js": {
       "version": "2.4.24",
-      "from": "uglify-js@2.4.24",
+      "from": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.4.24.tgz",
       "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.4.24.tgz",
       "dependencies": {
         "async": {
           "version": "0.2.10",
-          "from": "async@>=0.2.6 <0.3.0",
+          "from": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
           "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz"
         },
         "source-map": {
           "version": "0.1.34",
-          "from": "source-map@0.1.34",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.34.tgz",
-          "dependencies": {
-            "amdefine": {
-              "version": "1.0.0",
-              "from": "amdefine@>=0.0.4",
-              "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz"
-            }
-          }
+          "from": "https://registry.npmjs.org/source-map/-/source-map-0.1.34.tgz",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.34.tgz"
         },
         "uglify-to-browserify": {
           "version": "1.0.2",
-          "from": "uglify-to-browserify@>=1.0.0 <1.1.0",
+          "from": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
           "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz"
         },
         "yargs": {
           "version": "3.5.4",
-          "from": "yargs@>=3.5.4 <3.6.0",
+          "from": "https://registry.npmjs.org/yargs/-/yargs-3.5.4.tgz",
           "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.5.4.tgz",
           "dependencies": {
-            "camelcase": {
-              "version": "1.2.1",
-              "from": "camelcase@>=1.0.2 <2.0.0",
-              "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz"
-            },
             "decamelize": {
               "version": "1.0.0",
-              "from": "decamelize@>=1.0.0 <2.0.0",
+              "from": "https://registry.npmjs.org/decamelize/-/decamelize-1.0.0.tgz",
               "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.0.0.tgz"
             },
             "window-size": {
               "version": "0.1.0",
-              "from": "window-size@0.1.0",
+              "from": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
               "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz"
             },
             "wordwrap": {
               "version": "0.0.2",
-              "from": "wordwrap@0.0.2",
+              "from": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
               "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz"
             }
           }
@@ -4861,113 +4590,113 @@
     },
     "underscore": {
       "version": "1.8.3",
-      "from": "underscore@1.8.3",
+      "from": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
       "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz"
     },
     "user-home": {
       "version": "1.1.1",
-      "from": "user-home@>=1.1.1 <2.0.0",
+      "from": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz",
       "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz"
     },
     "util-deprecate": {
       "version": "1.0.2",
-      "from": "util-deprecate@>=1.0.1 <1.1.0",
+      "from": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
     },
     "validate-npm-package-license": {
       "version": "3.0.1",
-      "from": "validate-npm-package-license@>=3.0.1 <4.0.0",
+      "from": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz",
       "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz"
     },
     "vinyl": {
       "version": "0.5.3",
-      "from": "vinyl@>=0.5.0 <0.6.0",
+      "from": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz",
       "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz"
     },
     "window-size": {
       "version": "0.1.2",
-      "from": "window-size@>=0.1.2 <0.2.0",
+      "from": "https://registry.npmjs.org/window-size/-/window-size-0.1.2.tgz",
       "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.2.tgz"
     },
     "wordwrap": {
       "version": "1.0.0",
-      "from": "wordwrap@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz"
     },
     "worker-farm": {
       "version": "1.3.1",
-      "from": "worker-farm@>=1.3.1 <2.0.0",
+      "from": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.3.1.tgz",
       "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.3.1.tgz",
       "dependencies": {
         "errno": {
           "version": "0.1.4",
-          "from": "errno@>=0.1.1 <0.2.0-0",
+          "from": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz",
           "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz",
           "dependencies": {
             "prr": {
               "version": "0.0.0",
-              "from": "prr@>=0.0.0 <0.1.0",
+              "from": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz",
               "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz"
             }
           }
         },
         "xtend": {
           "version": "4.0.0",
-          "from": "xtend@>=4.0.0 <4.1.0-0",
+          "from": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz",
           "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz"
         }
       }
     },
     "wrappy": {
       "version": "1.0.1",
-      "from": "wrappy@>=1.0.0 <2.0.0",
+      "from": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
     },
     "ws": {
       "version": "0.8.0",
-      "from": "ws@0.8.0",
+      "from": "https://registry.npmjs.org/ws/-/ws-0.8.0.tgz",
       "resolved": "https://registry.npmjs.org/ws/-/ws-0.8.0.tgz",
       "dependencies": {
         "options": {
           "version": "0.0.6",
-          "from": "options@>=0.0.5",
+          "from": "https://registry.npmjs.org/options/-/options-0.0.6.tgz",
           "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz"
         },
         "ultron": {
           "version": "1.0.2",
-          "from": "ultron@>=1.0.0 <1.1.0",
+          "from": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz",
           "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz"
         },
         "bufferutil": {
           "version": "1.2.1",
-          "from": "bufferutil@>=1.2.0 <1.3.0",
+          "from": "https://registry.npmjs.org/bufferutil/-/bufferutil-1.2.1.tgz",
           "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-1.2.1.tgz",
           "dependencies": {
             "bindings": {
               "version": "1.2.1",
-              "from": "bindings@>=1.2.0 <1.3.0",
+              "from": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz",
               "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz"
             },
             "nan": {
               "version": "2.0.8",
-              "from": "nan@>=2.0.5 <3.0.0",
+              "from": "https://registry.npmjs.org/nan/-/nan-2.0.8.tgz",
               "resolved": "https://registry.npmjs.org/nan/-/nan-2.0.8.tgz"
             }
           }
         },
         "utf-8-validate": {
           "version": "1.2.1",
-          "from": "utf-8-validate@>=1.2.0 <1.3.0",
+          "from": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-1.2.1.tgz",
           "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-1.2.1.tgz",
           "dependencies": {
             "bindings": {
               "version": "1.2.1",
-              "from": "bindings@>=1.2.0 <1.3.0",
+              "from": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz",
               "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz"
             },
             "nan": {
               "version": "2.0.8",
-              "from": "nan@>=2.0.5 <3.0.0",
+              "from": "https://registry.npmjs.org/nan/-/nan-2.0.8.tgz",
               "resolved": "https://registry.npmjs.org/nan/-/nan-2.0.8.tgz"
             }
           }
@@ -4976,452 +4705,194 @@
     },
     "xtend": {
       "version": "4.0.1",
-      "from": "xtend@>=4.0.0 <5.0.0",
+      "from": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
       "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz"
     },
     "y18n": {
       "version": "3.2.0",
-      "from": "y18n@>=3.2.0 <4.0.0",
+      "from": "https://registry.npmjs.org/y18n/-/y18n-3.2.0.tgz",
       "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.0.tgz"
     },
     "yargs": {
       "version": "3.24.0",
-      "from": "yargs@3.24.0",
+      "from": "https://registry.npmjs.org/yargs/-/yargs-3.24.0.tgz",
       "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.24.0.tgz",
       "dependencies": {
-        "camelcase": {
-          "version": "1.2.1",
-          "from": "camelcase@>=1.2.1 <2.0.0",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz"
-        },
-        "cliui": {
-          "version": "2.1.0",
-          "from": "cliui@>=2.1.0 <3.0.0",
-          "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
-          "dependencies": {
-            "center-align": {
-              "version": "0.1.1",
-              "from": "center-align@>=0.1.1 <0.2.0",
-              "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.1.tgz",
-              "dependencies": {
-                "align-text": {
-                  "version": "0.1.3",
-                  "from": "align-text@>=0.1.1 <0.2.0",
-                  "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.3.tgz",
-                  "dependencies": {
-                    "kind-of": {
-                      "version": "2.0.1",
-                      "from": "kind-of@>=2.0.0 <3.0.0",
-                      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz",
-                      "dependencies": {
-                        "is-buffer": {
-                          "version": "1.0.2",
-                          "from": "is-buffer@>=1.0.2 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.0.2.tgz"
-                        }
-                      }
-                    },
-                    "longest": {
-                      "version": "1.0.1",
-                      "from": "longest@>=1.0.1 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz"
-                    },
-                    "repeat-string": {
-                      "version": "1.5.2",
-                      "from": "repeat-string@>=1.5.2 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.2.tgz"
-                    }
-                  }
-                }
-              }
-            },
-            "right-align": {
-              "version": "0.1.3",
-              "from": "right-align@>=0.1.1 <0.2.0",
-              "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
-              "dependencies": {
-                "align-text": {
-                  "version": "0.1.3",
-                  "from": "align-text@>=0.1.1 <0.2.0",
-                  "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.3.tgz",
-                  "dependencies": {
-                    "kind-of": {
-                      "version": "2.0.1",
-                      "from": "kind-of@>=2.0.0 <3.0.0",
-                      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz",
-                      "dependencies": {
-                        "is-buffer": {
-                          "version": "1.0.2",
-                          "from": "is-buffer@>=1.0.2 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.0.2.tgz"
-                        }
-                      }
-                    },
-                    "longest": {
-                      "version": "1.0.1",
-                      "from": "longest@>=1.0.1 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz"
-                    },
-                    "repeat-string": {
-                      "version": "1.5.2",
-                      "from": "repeat-string@>=1.5.2 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.2.tgz"
-                    }
-                  }
-                }
-              }
-            },
-            "wordwrap": {
-              "version": "0.0.2",
-              "from": "wordwrap@0.0.2",
-              "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz"
-            }
-          }
-        },
         "decamelize": {
           "version": "1.0.0",
-          "from": "decamelize@>=1.0.0 <2.0.0",
+          "from": "https://registry.npmjs.org/decamelize/-/decamelize-1.0.0.tgz",
           "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.0.0.tgz"
         },
         "os-locale": {
           "version": "1.3.1",
-          "from": "os-locale@>=1.3.1 <2.0.0",
-          "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.3.1.tgz",
-          "dependencies": {
-            "lcid": {
-              "version": "1.0.0",
-              "from": "lcid@>=1.0.0 <2.0.0",
-              "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
-              "dependencies": {
-                "invert-kv": {
-                  "version": "1.0.0",
-                  "from": "invert-kv@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz"
-                }
-              }
-            }
-          }
-        },
-        "window-size": {
-          "version": "0.1.2",
-          "from": "window-size@>=0.1.2 <0.2.0",
-          "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.2.tgz"
+          "from": "https://registry.npmjs.org/os-locale/-/os-locale-1.3.1.tgz",
+          "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.3.1.tgz"
         },
         "y18n": {
           "version": "3.1.0",
-          "from": "y18n@>=3.1.0 <4.0.0",
+          "from": "https://registry.npmjs.org/y18n/-/y18n-3.1.0.tgz",
           "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.1.0.tgz"
         }
       }
     },
     "yeoman-environment": {
       "version": "1.2.7",
-      "from": "yeoman-environment@>=1.2.7 <2.0.0",
+      "from": "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-1.2.7.tgz",
       "resolved": "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-1.2.7.tgz",
       "dependencies": {
-        "chalk": {
-          "version": "1.1.1",
-          "from": "chalk@>=1.0.0 <2.0.0"
-        },
-        "debug": {
-          "version": "2.2.0",
-          "from": "debug@>=2.0.0 <3.0.0"
-        },
         "diff": {
           "version": "1.4.0",
-          "from": "diff@>=1.0.4 <2.0.0",
+          "from": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz",
           "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz"
         },
-        "escape-string-regexp": {
-          "version": "1.0.3",
-          "from": "escape-string-regexp@>=1.0.2 <2.0.0",
-          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz"
-        },
         "globby": {
           "version": "2.1.0",
-          "from": "globby@>=2.0.0 <3.0.0",
+          "from": "https://registry.npmjs.org/globby/-/globby-2.1.0.tgz",
           "resolved": "https://registry.npmjs.org/globby/-/globby-2.1.0.tgz",
           "dependencies": {
-            "array-union": {
-              "version": "1.0.1",
-              "from": "array-union@>=1.0.1 <2.0.0",
-              "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.1.tgz",
-              "dependencies": {
-                "array-uniq": {
-                  "version": "1.0.2",
-                  "from": "array-uniq@>=1.0.1 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.2.tgz"
-                }
-              }
-            },
-            "async": {
-              "version": "1.4.2",
-              "from": "async@>=1.4.2 <2.0.0",
-              "resolved": "https://registry.npmjs.org/async/-/async-1.4.2.tgz"
-            },
-            "glob": {
-              "version": "5.0.14",
-              "from": "glob@>=5.0.3 <6.0.0",
-              "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.14.tgz",
-              "dependencies": {
-                "inflight": {
-                  "version": "1.0.4",
-                  "from": "inflight@>=1.0.4 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz",
-                  "dependencies": {
-                    "wrappy": {
-                      "version": "1.0.1",
-                      "from": "wrappy@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
-                    }
-                  }
-                },
-                "inherits": {
-                  "version": "2.0.1",
-                  "from": "inherits@>=2.0.0 <3.0.0",
-                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                },
-                "minimatch": {
-                  "version": "2.0.10",
-                  "from": "minimatch@>=2.0.1 <3.0.0",
-                  "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz",
-                  "dependencies": {
-                    "brace-expansion": {
-                      "version": "1.1.0",
-                      "from": "brace-expansion@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.0.tgz",
-                      "dependencies": {
-                        "balanced-match": {
-                          "version": "0.2.0",
-                          "from": "balanced-match@>=0.2.0 <0.3.0",
-                          "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.0.tgz"
-                        },
-                        "concat-map": {
-                          "version": "0.0.1",
-                          "from": "concat-map@0.0.1",
-                          "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
-                        }
-                      }
-                    }
-                  }
-                },
-                "once": {
-                  "version": "1.3.2",
-                  "from": "once@>=1.3.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz",
-                  "dependencies": {
-                    "wrappy": {
-                      "version": "1.0.1",
-                      "from": "wrappy@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
-                    }
-                  }
-                },
-                "path-is-absolute": {
-                  "version": "1.0.0",
-                  "from": "path-is-absolute@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz"
-                }
-              }
+            "array-union": {
+              "version": "1.0.1",
+              "from": "https://registry.npmjs.org/array-union/-/array-union-1.0.1.tgz",
+              "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.1.tgz"
+            },
+            "async": {
+              "version": "1.4.2",
+              "from": "https://registry.npmjs.org/async/-/async-1.4.2.tgz",
+              "resolved": "https://registry.npmjs.org/async/-/async-1.4.2.tgz"
+            },
+            "glob": {
+              "version": "5.0.14",
+              "from": "https://registry.npmjs.org/glob/-/glob-5.0.14.tgz",
+              "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.14.tgz"
             },
             "object-assign": {
               "version": "3.0.0",
-              "from": "object-assign@>=3.0.0 <4.0.0",
+              "from": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
               "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz"
             }
           }
         },
         "grouped-queue": {
           "version": "0.3.0",
-          "from": "grouped-queue@>=0.3.0 <0.4.0",
+          "from": "https://registry.npmjs.org/grouped-queue/-/grouped-queue-0.3.0.tgz",
           "resolved": "https://registry.npmjs.org/grouped-queue/-/grouped-queue-0.3.0.tgz",
           "dependencies": {
             "lodash": {
               "version": "2.4.2",
-              "from": "lodash@>=2.4.1 <2.5.0",
+              "from": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz",
               "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz"
             },
             "setimmediate": {
               "version": "1.0.2",
-              "from": "setimmediate@>=1.0.1 <1.1.0",
+              "from": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.2.tgz",
               "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.2.tgz"
             }
           }
         },
         "inquirer": {
           "version": "0.8.5",
-          "from": "inquirer@>=0.8.0 <0.9.0",
+          "from": "https://registry.npmjs.org/inquirer/-/inquirer-0.8.5.tgz",
           "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.8.5.tgz",
           "dependencies": {
             "ansi-regex": {
               "version": "1.1.1",
-              "from": "ansi-regex@>=1.1.1 <2.0.0",
+              "from": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz",
               "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz"
             },
             "cli-width": {
               "version": "1.0.1",
-              "from": "cli-width@>=1.0.1 <2.0.0",
+              "from": "https://registry.npmjs.org/cli-width/-/cli-width-1.0.1.tgz",
               "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-1.0.1.tgz"
             },
             "figures": {
               "version": "1.3.5",
-              "from": "figures@>=1.3.5 <2.0.0",
+              "from": "https://registry.npmjs.org/figures/-/figures-1.3.5.tgz",
               "resolved": "https://registry.npmjs.org/figures/-/figures-1.3.5.tgz"
             },
             "readline2": {
               "version": "0.1.1",
-              "from": "readline2@>=0.1.1 <0.2.0",
+              "from": "https://registry.npmjs.org/readline2/-/readline2-0.1.1.tgz",
               "resolved": "https://registry.npmjs.org/readline2/-/readline2-0.1.1.tgz",
               "dependencies": {
                 "mute-stream": {
                   "version": "0.0.4",
-                  "from": "mute-stream@0.0.4",
+                  "from": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.4.tgz",
                   "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.4.tgz"
                 },
                 "strip-ansi": {
                   "version": "2.0.1",
-                  "from": "strip-ansi@>=2.0.1 <3.0.0",
+                  "from": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz",
                   "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz"
                 }
               }
             },
             "rx": {
               "version": "2.5.3",
-              "from": "rx@>=2.4.3 <3.0.0",
+              "from": "https://registry.npmjs.org/rx/-/rx-2.5.3.tgz",
               "resolved": "https://registry.npmjs.org/rx/-/rx-2.5.3.tgz"
-            },
-            "through": {
-              "version": "2.3.8",
-              "from": "through@>=2.3.6 <3.0.0",
-              "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
             }
           }
         },
-        "lodash": {
-          "version": "3.10.1",
-          "from": "lodash@>=3.1.0 <4.0.0",
-          "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz"
-        },
         "log-symbols": {
           "version": "1.0.2",
-          "from": "log-symbols@>=1.0.1 <2.0.0",
+          "from": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz",
           "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz"
         },
         "mem-fs": {
           "version": "1.1.0",
-          "from": "mem-fs@>=1.1.0 <2.0.0",
+          "from": "https://registry.npmjs.org/mem-fs/-/mem-fs-1.1.0.tgz",
           "resolved": "https://registry.npmjs.org/mem-fs/-/mem-fs-1.1.0.tgz",
           "dependencies": {
             "through2": {
               "version": "0.6.5",
-              "from": "through2@>=0.6.3 <0.7.0",
+              "from": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
               "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
               "dependencies": {
                 "readable-stream": {
                   "version": "1.0.33",
-                  "from": "readable-stream@>=1.0.33-1 <1.1.0-0",
-                  "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz",
-                  "dependencies": {
-                    "core-util-is": {
-                      "version": "1.0.1",
-                      "from": "core-util-is@>=1.0.0 <1.1.0",
-                      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-                    },
-                    "isarray": {
-                      "version": "0.0.1",
-                      "from": "isarray@0.0.1",
-                      "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
-                    },
-                    "string_decoder": {
-                      "version": "0.10.31",
-                      "from": "string_decoder@>=0.10.0 <0.11.0",
-                      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
-                    },
-                    "inherits": {
-                      "version": "2.0.1",
-                      "from": "inherits@>=2.0.1 <2.1.0",
-                      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                    }
-                  }
+                  "from": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz",
+                  "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz"
                 },
                 "xtend": {
                   "version": "4.0.0",
-                  "from": "xtend@>=4.0.0 <4.1.0-0",
+                  "from": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz"
                 }
               }
             },
             "vinyl": {
               "version": "0.4.6",
-              "from": "vinyl@>=0.4.3 <0.5.0",
+              "from": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz",
               "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz",
               "dependencies": {
                 "clone": {
                   "version": "0.2.0",
-                  "from": "clone@>=0.2.0 <0.3.0",
+                  "from": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz",
                   "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz"
-                },
-                "clone-stats": {
-                  "version": "0.0.1",
-                  "from": "clone-stats@>=0.0.1 <0.0.2",
-                  "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz"
                 }
               }
             },
             "vinyl-file": {
               "version": "1.2.1",
-              "from": "vinyl-file@>=1.1.0 <2.0.0",
+              "from": "https://registry.npmjs.org/vinyl-file/-/vinyl-file-1.2.1.tgz",
               "resolved": "https://registry.npmjs.org/vinyl-file/-/vinyl-file-1.2.1.tgz",
               "dependencies": {
-                "graceful-fs": {
-                  "version": "4.1.2",
-                  "from": "graceful-fs@>=4.1.2 <5.0.0"
-                },
-                "strip-bom": {
-                  "version": "2.0.0",
-                  "from": "strip-bom@>=2.0.0 <3.0.0",
-                  "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
-                  "dependencies": {
-                    "is-utf8": {
-                      "version": "0.2.0",
-                      "from": "is-utf8@>=0.2.0 <0.3.0",
-                      "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.0.tgz"
-                    }
-                  }
-                },
                 "strip-bom-stream": {
                   "version": "1.0.0",
-                  "from": "strip-bom-stream@>=1.0.0 <2.0.0",
+                  "from": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz",
                   "dependencies": {
                     "first-chunk-stream": {
                       "version": "1.0.0",
-                      "from": "first-chunk-stream@>=1.0.0 <2.0.0",
+                      "from": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz",
                       "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz"
                     }
                   }
                 },
                 "vinyl": {
                   "version": "0.5.3",
-                  "from": "vinyl@>=0.5.0 <0.6.0",
-                  "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz",
-                  "dependencies": {
-                    "clone": {
-                      "version": "1.0.2",
-                      "from": "clone@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz"
-                    },
-                    "clone-stats": {
-                      "version": "0.0.1",
-                      "from": "clone-stats@>=0.0.1 <0.0.2",
-                      "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz"
-                    },
-                    "replace-ext": {
-                      "version": "0.0.1",
-                      "from": "replace-ext@0.0.1",
-                      "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz"
-                    }
-                  }
+                  "from": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz",
+                  "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz"
                 }
               }
             }
@@ -5429,17 +4900,17 @@
         },
         "text-table": {
           "version": "0.2.0",
-          "from": "text-table@>=0.2.0 <0.3.0",
+          "from": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
           "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz"
         },
         "untildify": {
           "version": "2.1.0",
-          "from": "untildify@>=2.0.0 <3.0.0",
+          "from": "https://registry.npmjs.org/untildify/-/untildify-2.1.0.tgz",
           "resolved": "https://registry.npmjs.org/untildify/-/untildify-2.1.0.tgz",
           "dependencies": {
             "os-homedir": {
               "version": "1.0.1",
-              "from": "os-homedir@>=1.0.0 <2.0.0",
+              "from": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.1.tgz",
               "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.1.tgz"
             }
           }
@@ -5448,70 +4919,66 @@
     },
     "yeoman-generator": {
       "version": "0.20.3",
-      "from": "yeoman-generator@0.20.3",
+      "from": "https://registry.npmjs.org/yeoman-generator/-/yeoman-generator-0.20.3.tgz",
       "resolved": "https://registry.npmjs.org/yeoman-generator/-/yeoman-generator-0.20.3.tgz",
       "dependencies": {
         "async": {
           "version": "1.4.2",
-          "from": "async@>=1.4.2 <2.0.0",
+          "from": "https://registry.npmjs.org/async/-/async-1.4.2.tgz",
           "resolved": "https://registry.npmjs.org/async/-/async-1.4.2.tgz"
         },
-        "chalk": {
-          "version": "1.1.1",
-          "from": "chalk@>=1.0.0 <2.0.0"
-        },
         "class-extend": {
           "version": "0.1.2",
-          "from": "class-extend@>=0.1.0 <0.2.0",
+          "from": "https://registry.npmjs.org/class-extend/-/class-extend-0.1.2.tgz",
           "resolved": "https://registry.npmjs.org/class-extend/-/class-extend-0.1.2.tgz",
           "dependencies": {
             "object-assign": {
               "version": "2.1.1",
-              "from": "object-assign@>=2.0.0 <3.0.0",
+              "from": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz",
               "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz"
             }
           }
         },
         "cli-table": {
           "version": "0.3.1",
-          "from": "cli-table@>=0.3.1 <0.4.0",
+          "from": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz",
           "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz",
           "dependencies": {
             "colors": {
               "version": "1.0.3",
-              "from": "colors@1.0.3",
+              "from": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
               "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz"
             }
           }
         },
         "cross-spawn": {
           "version": "2.0.0",
-          "from": "cross-spawn@>=2.0.0 <3.0.0",
+          "from": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-2.0.0.tgz",
           "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-2.0.0.tgz",
           "dependencies": {
             "cross-spawn-async": {
               "version": "2.0.0",
-              "from": "cross-spawn-async@>=2.0.0 <3.0.0",
+              "from": "https://registry.npmjs.org/cross-spawn-async/-/cross-spawn-async-2.0.0.tgz",
               "resolved": "https://registry.npmjs.org/cross-spawn-async/-/cross-spawn-async-2.0.0.tgz",
               "dependencies": {
                 "lru-cache": {
                   "version": "2.7.0",
-                  "from": "lru-cache@>=2.6.5 <3.0.0",
+                  "from": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.0.tgz",
                   "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.0.tgz"
                 },
                 "which": {
                   "version": "1.2.0",
-                  "from": "which@>=1.1.1 <2.0.0",
+                  "from": "https://registry.npmjs.org/which/-/which-1.2.0.tgz",
                   "resolved": "https://registry.npmjs.org/which/-/which-1.2.0.tgz",
                   "dependencies": {
                     "is-absolute": {
                       "version": "0.1.7",
-                      "from": "is-absolute@>=0.1.7 <0.2.0",
+                      "from": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz",
                       "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz",
                       "dependencies": {
                         "is-relative": {
                           "version": "0.1.3",
-                          "from": "is-relative@>=0.1.0 <0.2.0",
+                          "from": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz",
                           "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz"
                         }
                       }
@@ -5522,61 +4989,29 @@
             },
             "spawn-sync": {
               "version": "1.0.13",
-              "from": "spawn-sync@>=1.0.13 <2.0.0",
+              "from": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.13.tgz",
               "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.13.tgz",
               "dependencies": {
                 "concat-stream": {
                   "version": "1.5.0",
-                  "from": "concat-stream@>=1.4.7 <2.0.0",
+                  "from": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz",
                   "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz",
                   "dependencies": {
-                    "inherits": {
-                      "version": "2.0.1",
-                      "from": "inherits@>=2.0.1 <2.1.0",
-                      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                    },
                     "typedarray": {
                       "version": "0.0.6",
-                      "from": "typedarray@>=0.0.5 <0.1.0",
+                      "from": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
                       "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
                     },
                     "readable-stream": {
                       "version": "2.0.2",
-                      "from": "readable-stream@>=2.0.0 <2.1.0",
-                      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz",
-                      "dependencies": {
-                        "core-util-is": {
-                          "version": "1.0.1",
-                          "from": "core-util-is@>=1.0.0 <1.1.0",
-                          "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-                        },
-                        "isarray": {
-                          "version": "0.0.1",
-                          "from": "isarray@0.0.1",
-                          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
-                        },
-                        "process-nextick-args": {
-                          "version": "1.0.3",
-                          "from": "process-nextick-args@>=1.0.0 <1.1.0",
-                          "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.3.tgz"
-                        },
-                        "string_decoder": {
-                          "version": "0.10.31",
-                          "from": "string_decoder@>=0.10.0 <0.11.0",
-                          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
-                        },
-                        "util-deprecate": {
-                          "version": "1.0.2",
-                          "from": "util-deprecate@>=1.0.1 <1.1.0",
-                          "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
-                        }
-                      }
+                      "from": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz",
+                      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz"
                     }
                   }
                 },
                 "os-shim": {
                   "version": "0.1.3",
-                  "from": "os-shim@>=0.1.2 <0.2.0",
+                  "from": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz",
                   "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz"
                 }
               }
@@ -5585,351 +5020,57 @@
         },
         "dargs": {
           "version": "4.0.1",
-          "from": "dargs@>=4.0.0 <5.0.0",
-          "resolved": "https://registry.npmjs.org/dargs/-/dargs-4.0.1.tgz",
-          "dependencies": {
-            "number-is-nan": {
-              "version": "1.0.0",
-              "from": "number-is-nan@>=1.0.0 <2.0.0",
-              "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz"
-            }
-          }
-        },
-        "dateformat": {
-          "version": "1.0.11",
-          "from": "dateformat@>=1.0.11 <2.0.0",
-          "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.11.tgz",
-          "dependencies": {
-            "get-stdin": {
-              "version": "5.0.0",
-              "from": "get-stdin@*",
-              "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.0.tgz"
-            },
-            "meow": {
-              "version": "3.4.2",
-              "from": "meow@*",
-              "resolved": "https://registry.npmjs.org/meow/-/meow-3.4.2.tgz",
-              "dependencies": {
-                "camelcase-keys": {
-                  "version": "1.0.0",
-                  "from": "camelcase-keys@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-1.0.0.tgz",
-                  "dependencies": {
-                    "camelcase": {
-                      "version": "1.2.1",
-                      "from": "camelcase@>=1.0.1 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz"
-                    },
-                    "map-obj": {
-                      "version": "1.0.1",
-                      "from": "map-obj@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz"
-                    }
-                  }
-                },
-                "loud-rejection": {
-                  "version": "1.0.0",
-                  "from": "loud-rejection@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.0.0.tgz"
-                },
-                "minimist": {
-                  "version": "1.2.0",
-                  "from": "minimist@>=1.1.3 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
-                },
-                "normalize-package-data": {
-                  "version": "2.3.4",
-                  "from": "normalize-package-data@>=2.3.4 <3.0.0",
-                  "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.4.tgz",
-                  "dependencies": {
-                    "hosted-git-info": {
-                      "version": "2.1.4",
-                      "from": "hosted-git-info@>=2.0.2 <3.0.0",
-                      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.4.tgz"
-                    },
-                    "is-builtin-module": {
-                      "version": "1.0.0",
-                      "from": "is-builtin-module@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
-                      "dependencies": {
-                        "builtin-modules": {
-                          "version": "1.1.0",
-                          "from": "builtin-modules@>=1.0.0 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.0.tgz"
-                        }
-                      }
-                    },
-                    "semver": {
-                      "version": "5.0.3",
-                      "from": "semver@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0||>=4.0.0 <5.0.0||>=5.0.0 <6.0.0"
-                    },
-                    "validate-npm-package-license": {
-                      "version": "3.0.1",
-                      "from": "validate-npm-package-license@>=3.0.1 <4.0.0",
-                      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz",
-                      "dependencies": {
-                        "spdx-correct": {
-                          "version": "1.0.1",
-                          "from": "spdx-correct@>=1.0.0 <1.1.0",
-                          "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.1.tgz",
-                          "dependencies": {
-                            "spdx-license-ids": {
-                              "version": "1.0.2",
-                              "from": "spdx-license-ids@>=1.0.2 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.0.2.tgz"
-                            }
-                          }
-                        },
-                        "spdx-expression-parse": {
-                          "version": "1.0.0",
-                          "from": "spdx-expression-parse@>=1.0.0 <1.1.0",
-                          "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.0.tgz",
-                          "dependencies": {
-                            "spdx-exceptions": {
-                              "version": "1.0.3",
-                              "from": "spdx-exceptions@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-1.0.3.tgz"
-                            },
-                            "spdx-license-ids": {
-                              "version": "1.0.2",
-                              "from": "spdx-license-ids@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.0.2.tgz"
-                            }
-                          }
-                        }
-                      }
-                    }
-                  }
-                },
-                "object-assign": {
-                  "version": "4.0.1",
-                  "from": "object-assign@>=4.0.1 <5.0.0",
-                  "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.0.1.tgz"
-                },
-                "read-pkg-up": {
-                  "version": "1.0.1",
-                  "from": "read-pkg-up@>=1.0.1 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
-                  "dependencies": {
-                    "find-up": {
-                      "version": "1.0.0",
-                      "from": "find-up@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.0.0.tgz",
-                      "dependencies": {
-                        "path-exists": {
-                          "version": "2.0.0",
-                          "from": "path-exists@>=2.0.0 <3.0.0",
-                          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.0.0.tgz"
-                        },
-                        "pinkie-promise": {
-                          "version": "1.0.0",
-                          "from": "pinkie-promise@>=1.0.0 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz",
-                          "dependencies": {
-                            "pinkie": {
-                              "version": "1.0.0",
-                              "from": "pinkie@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
-                            }
-                          }
-                        }
-                      }
-                    },
-                    "read-pkg": {
-                      "version": "1.1.0",
-                      "from": "read-pkg@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
-                      "dependencies": {
-                        "load-json-file": {
-                          "version": "1.0.1",
-                          "from": "load-json-file@>=1.0.0 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.0.1.tgz",
-                          "dependencies": {
-                            "graceful-fs": {
-                              "version": "4.1.2",
-                              "from": "graceful-fs@>=4.1.2 <5.0.0"
-                            },
-                            "parse-json": {
-                              "version": "2.2.0",
-                              "from": "parse-json@>=2.2.0 <3.0.0",
-                              "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
-                              "dependencies": {
-                                "error-ex": {
-                                  "version": "1.2.0",
-                                  "from": "error-ex@>=1.2.0 <2.0.0",
-                                  "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.2.0.tgz"
-                                }
-                              }
-                            },
-                            "pify": {
-                              "version": "2.2.0",
-                              "from": "pify@>=2.0.0 <3.0.0",
-                              "resolved": "https://registry.npmjs.org/pify/-/pify-2.2.0.tgz"
-                            },
-                            "pinkie-promise": {
-                              "version": "1.0.0",
-                              "from": "pinkie-promise@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz",
-                              "dependencies": {
-                                "pinkie": {
-                                  "version": "1.0.0",
-                                  "from": "pinkie@>=1.0.0 <2.0.0",
-                                  "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
-                                }
-                              }
-                            },
-                            "strip-bom": {
-                              "version": "2.0.0",
-                              "from": "strip-bom@>=2.0.0 <3.0.0",
-                              "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
-                              "dependencies": {
-                                "is-utf8": {
-                                  "version": "0.2.0",
-                                  "from": "is-utf8@>=0.2.0 <0.3.0",
-                                  "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.0.tgz"
-                                }
-                              }
-                            }
-                          }
-                        },
-                        "path-type": {
-                          "version": "1.0.0",
-                          "from": "path-type@>=1.0.0 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.0.0.tgz",
-                          "dependencies": {
-                            "graceful-fs": {
-                              "version": "4.1.2",
-                              "from": "graceful-fs@>=4.1.2 <5.0.0"
-                            },
-                            "pify": {
-                              "version": "2.2.0",
-                              "from": "pify@>=2.0.0 <3.0.0",
-                              "resolved": "https://registry.npmjs.org/pify/-/pify-2.2.0.tgz"
-                            },
-                            "pinkie-promise": {
-                              "version": "1.0.0",
-                              "from": "pinkie-promise@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz",
-                              "dependencies": {
-                                "pinkie": {
-                                  "version": "1.0.0",
-                                  "from": "pinkie@>=1.0.0 <2.0.0",
-                                  "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
-                                }
-                              }
-                            }
-                          }
-                        }
-                      }
-                    }
-                  }
-                },
-                "redent": {
-                  "version": "1.0.0",
-                  "from": "redent@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
-                  "dependencies": {
-                    "indent-string": {
-                      "version": "2.1.0",
-                      "from": "indent-string@>=2.1.0 <3.0.0",
-                      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
-                      "dependencies": {
-                        "repeating": {
-                          "version": "2.0.0",
-                          "from": "repeating@>=2.0.0 <3.0.0",
-                          "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.0.tgz",
-                          "dependencies": {
-                            "is-finite": {
-                              "version": "1.0.1",
-                              "from": "is-finite@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.1.tgz",
-                              "dependencies": {
-                                "number-is-nan": {
-                                  "version": "1.0.0",
-                                  "from": "number-is-nan@>=1.0.0 <2.0.0",
-                                  "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz"
-                                }
-                              }
-                            }
-                          }
-                        }
-                      }
-                    },
-                    "strip-indent": {
-                      "version": "1.0.1",
-                      "from": "strip-indent@>=1.0.1 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
-                      "dependencies": {
-                        "get-stdin": {
-                          "version": "4.0.1",
-                          "from": "get-stdin@>=4.0.1 <5.0.0",
-                          "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz"
-                        }
-                      }
-                    }
-                  }
-                },
-                "trim-newlines": {
-                  "version": "1.0.0",
-                  "from": "trim-newlines@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz"
-                }
-              }
-            }
-          }
-        },
-        "debug": {
-          "version": "2.2.0",
-          "from": "debug@>=2.1.0 <3.0.0"
+          "from": "https://registry.npmjs.org/dargs/-/dargs-4.0.1.tgz",
+          "resolved": "https://registry.npmjs.org/dargs/-/dargs-4.0.1.tgz"
         },
         "detect-conflict": {
           "version": "1.0.0",
-          "from": "detect-conflict@>=1.0.0 <2.0.0",
+          "from": "https://registry.npmjs.org/detect-conflict/-/detect-conflict-1.0.0.tgz",
           "resolved": "https://registry.npmjs.org/detect-conflict/-/detect-conflict-1.0.0.tgz"
         },
         "diff": {
           "version": "2.1.3",
-          "from": "diff@>=2.0.2 <3.0.0",
+          "from": "https://registry.npmjs.org/diff/-/diff-2.1.3.tgz",
           "resolved": "https://registry.npmjs.org/diff/-/diff-2.1.3.tgz"
         },
         "download": {
           "version": "4.2.1",
-          "from": "download@>=4.1.2 <5.0.0",
+          "from": "https://registry.npmjs.org/download/-/download-4.2.1.tgz",
           "resolved": "https://registry.npmjs.org/download/-/download-4.2.1.tgz",
           "dependencies": {
             "caw": {
               "version": "1.1.0",
-              "from": "caw@>=1.0.1 <2.0.0",
+              "from": "https://registry.npmjs.org/caw/-/caw-1.1.0.tgz",
               "resolved": "https://registry.npmjs.org/caw/-/caw-1.1.0.tgz",
               "dependencies": {
                 "get-proxy": {
                   "version": "1.0.1",
-                  "from": "get-proxy@>=1.0.1 <2.0.0",
+                  "from": "https://registry.npmjs.org/get-proxy/-/get-proxy-1.0.1.tgz",
                   "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-1.0.1.tgz",
                   "dependencies": {
                     "rc": {
                       "version": "0.5.5",
-                      "from": "rc@>=0.5.5 <0.6.0",
+                      "from": "https://registry.npmjs.org/rc/-/rc-0.5.5.tgz",
                       "resolved": "https://registry.npmjs.org/rc/-/rc-0.5.5.tgz",
                       "dependencies": {
                         "minimist": {
                           "version": "0.0.10",
-                          "from": "minimist@>=0.0.7 <0.1.0",
+                          "from": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
                           "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz"
                         },
                         "deep-extend": {
                           "version": "0.2.11",
-                          "from": "deep-extend@>=0.2.5 <0.3.0",
+                          "from": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.2.11.tgz",
                           "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.2.11.tgz"
                         },
                         "strip-json-comments": {
                           "version": "0.1.3",
-                          "from": "strip-json-comments@>=0.1.0 <0.2.0",
+                          "from": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz",
                           "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
                         },
                         "ini": {
                           "version": "1.3.4",
-                          "from": "ini@>=1.3.0 <1.4.0",
+                          "from": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz",
                           "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz"
                         }
                       }
@@ -5938,506 +5079,182 @@
                 },
                 "is-obj": {
                   "version": "1.0.0",
-                  "from": "is-obj@>=1.0.0 <2.0.0",
+                  "from": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.0.tgz"
                 },
                 "object-assign": {
                   "version": "3.0.0",
-                  "from": "object-assign@>=3.0.0 <4.0.0",
+                  "from": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz"
                 },
                 "tunnel-agent": {
                   "version": "0.4.1",
-                  "from": "tunnel-agent@>=0.4.0 <0.5.0",
+                  "from": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz",
                   "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz"
                 }
               }
             },
             "concat-stream": {
               "version": "1.5.0",
-              "from": "concat-stream@>=1.4.7 <2.0.0",
+              "from": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz",
               "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz",
               "dependencies": {
-                "inherits": {
-                  "version": "2.0.1",
-                  "from": "inherits@>=2.0.1 <2.1.0",
-                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                },
                 "typedarray": {
                   "version": "0.0.6",
-                  "from": "typedarray@>=0.0.5 <0.1.0",
+                  "from": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
                   "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
                 },
                 "readable-stream": {
                   "version": "2.0.4",
-                  "from": "readable-stream@>=2.0.0 <2.1.0"
+                  "from": "readable-stream@2.0.4",
+                  "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.4.tgz"
                 }
               }
             },
             "each-async": {
               "version": "1.1.1",
-              "from": "each-async@>=1.0.0 <2.0.0",
+              "from": "https://registry.npmjs.org/each-async/-/each-async-1.1.1.tgz",
               "resolved": "https://registry.npmjs.org/each-async/-/each-async-1.1.1.tgz",
               "dependencies": {
                 "onetime": {
                   "version": "1.0.0",
-                  "from": "onetime@>=1.0.0 <2.0.0",
+                  "from": "https://registry.npmjs.org/onetime/-/onetime-1.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.0.0.tgz"
                 },
                 "set-immediate-shim": {
                   "version": "1.0.1",
-                  "from": "set-immediate-shim@>=1.0.0 <2.0.0",
+                  "from": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
                   "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz"
                 }
               }
             },
             "filenamify": {
               "version": "1.2.0",
-              "from": "filenamify@>=1.0.1 <2.0.0",
+              "from": "https://registry.npmjs.org/filenamify/-/filenamify-1.2.0.tgz",
               "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-1.2.0.tgz",
               "dependencies": {
                 "filename-reserved-regex": {
                   "version": "1.0.0",
-                  "from": "filename-reserved-regex@>=1.0.0 <2.0.0",
+                  "from": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-1.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-1.0.0.tgz"
                 },
                 "strip-outer": {
                   "version": "1.0.0",
-                  "from": "strip-outer@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.0.tgz",
-                  "dependencies": {
-                    "escape-string-regexp": {
-                      "version": "1.0.3",
-                      "from": "escape-string-regexp@>=1.0.2 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz"
-                    }
-                  }
+                  "from": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.0.tgz",
+                  "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.0.tgz"
                 },
                 "trim-repeated": {
                   "version": "1.0.0",
-                  "from": "trim-repeated@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
-                  "dependencies": {
-                    "escape-string-regexp": {
-                      "version": "1.0.3",
-                      "from": "escape-string-regexp@>=1.0.2 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz"
-                    }
-                  }
+                  "from": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
+                  "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz"
                 }
               }
             },
             "got": {
               "version": "4.2.0",
-              "from": "got@>=4.2.0 <5.0.0",
+              "from": "https://registry.npmjs.org/got/-/got-4.2.0.tgz",
               "resolved": "https://registry.npmjs.org/got/-/got-4.2.0.tgz",
               "dependencies": {
                 "create-error-class": {
                   "version": "2.0.1",
-                  "from": "create-error-class@>=2.0.0 <3.0.0",
+                  "from": "https://registry.npmjs.org/create-error-class/-/create-error-class-2.0.1.tgz",
                   "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-2.0.1.tgz",
                   "dependencies": {
                     "capture-stack-trace": {
                       "version": "1.0.0",
-                      "from": "capture-stack-trace@>=1.0.0 <2.0.0",
+                      "from": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz",
                       "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz"
-                    },
-                    "inherits": {
-                      "version": "2.0.1",
-                      "from": "inherits@>=2.0.1 <3.0.0",
-                      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
                     }
                   }
                 },
                 "duplexify": {
                   "version": "3.4.2",
-                  "from": "duplexify@>=3.2.0 <4.0.0",
+                  "from": "https://registry.npmjs.org/duplexify/-/duplexify-3.4.2.tgz",
                   "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.4.2.tgz",
                   "dependencies": {
                     "end-of-stream": {
                       "version": "1.0.0",
-                      "from": "end-of-stream@1.0.0",
-                      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz",
-                      "dependencies": {
-                        "once": {
-                          "version": "1.3.2",
-                          "from": "once@>=1.3.0 <1.4.0",
-                          "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz",
-                          "dependencies": {
-                            "wrappy": {
-                              "version": "1.0.1",
-                              "from": "wrappy@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
-                            }
-                          }
-                        }
-                      }
+                      "from": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz",
+                      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz"
                     },
                     "readable-stream": {
                       "version": "2.0.4",
-                      "from": "readable-stream@>=2.0.0 <3.0.0"
+                      "from": "readable-stream@2.0.4",
+                      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.4.tgz"
                     }
                   }
                 },
                 "is-plain-obj": {
                   "version": "1.0.0",
-                  "from": "is-plain-obj@>=1.0.0 <2.0.0",
+                  "from": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.0.0.tgz"
                 },
                 "is-redirect": {
                   "version": "1.0.0",
-                  "from": "is-redirect@>=1.0.0 <2.0.0",
+                  "from": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz"
                 },
                 "is-stream": {
                   "version": "1.0.1",
-                  "from": "is-stream@>=1.0.0 <2.0.0",
+                  "from": "https://registry.npmjs.org/is-stream/-/is-stream-1.0.1.tgz",
                   "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.0.1.tgz"
                 },
                 "lowercase-keys": {
                   "version": "1.0.0",
-                  "from": "lowercase-keys@>=1.0.0 <2.0.0",
+                  "from": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz"
                 },
                 "node-status-codes": {
                   "version": "1.0.0",
-                  "from": "node-status-codes@>=1.0.0 <2.0.0",
+                  "from": "https://registry.npmjs.org/node-status-codes/-/node-status-codes-1.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/node-status-codes/-/node-status-codes-1.0.0.tgz"
                 },
                 "object-assign": {
                   "version": "3.0.0",
-                  "from": "object-assign@>=3.0.0 <4.0.0",
+                  "from": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz"
                 },
-                "parse-json": {
-                  "version": "2.2.0",
-                  "from": "parse-json@>=2.1.0 <3.0.0",
-                  "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
-                  "dependencies": {
-                    "error-ex": {
-                      "version": "1.2.0",
-                      "from": "error-ex@>=1.2.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.2.0.tgz"
-                    }
-                  }
-                },
-                "pinkie-promise": {
-                  "version": "1.0.0",
-                  "from": "pinkie-promise@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz",
-                  "dependencies": {
-                    "pinkie": {
-                      "version": "1.0.0",
-                      "from": "pinkie@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
-                    }
-                  }
-                },
                 "prepend-http": {
                   "version": "1.0.3",
-                  "from": "prepend-http@>=1.0.0 <2.0.0",
+                  "from": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.3.tgz",
                   "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.3.tgz"
                 },
-                "read-all-stream": {
-                  "version": "3.0.1",
-                  "from": "read-all-stream@>=3.0.0 <4.0.0",
-                  "resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.0.1.tgz"
-                },
                 "timed-out": {
                   "version": "2.0.0",
-                  "from": "timed-out@>=2.0.0 <3.0.0",
+                  "from": "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz"
                 },
                 "unzip-response": {
                   "version": "1.0.0",
-                  "from": "unzip-response@>=1.0.0 <2.0.0",
+                  "from": "https://registry.npmjs.org/unzip-response/-/unzip-response-1.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-1.0.0.tgz"
                 }
               }
             },
             "gulp-decompress": {
               "version": "1.1.0",
-              "from": "gulp-decompress@>=1.0.2 <2.0.0",
+              "from": "https://registry.npmjs.org/gulp-decompress/-/gulp-decompress-1.1.0.tgz",
               "resolved": "https://registry.npmjs.org/gulp-decompress/-/gulp-decompress-1.1.0.tgz",
               "dependencies": {
                 "archive-type": {
                   "version": "3.0.1",
-                  "from": "archive-type@>=3.0.0 <4.0.0",
+                  "from": "https://registry.npmjs.org/archive-type/-/archive-type-3.0.1.tgz",
                   "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-3.0.1.tgz",
                   "dependencies": {
                     "file-type": {
                       "version": "2.12.0",
-                      "from": "file-type@>=2.0.1 <3.0.0",
+                      "from": "https://registry.npmjs.org/file-type/-/file-type-2.12.0.tgz",
                       "resolved": "https://registry.npmjs.org/file-type/-/file-type-2.12.0.tgz",
                       "dependencies": {
                         "meow": {
                           "version": "3.4.2",
-                          "from": "meow@>=3.3.0 <4.0.0",
+                          "from": "https://registry.npmjs.org/meow/-/meow-3.4.2.tgz",
                           "resolved": "https://registry.npmjs.org/meow/-/meow-3.4.2.tgz",
                           "dependencies": {
-                            "camelcase-keys": {
-                              "version": "1.0.0",
-                              "from": "camelcase-keys@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-1.0.0.tgz",
-                              "dependencies": {
-                                "camelcase": {
-                                  "version": "1.2.1",
-                                  "from": "camelcase@>=1.0.1 <2.0.0",
-                                  "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz"
-                                },
-                                "map-obj": {
-                                  "version": "1.0.1",
-                                  "from": "map-obj@>=1.0.0 <2.0.0",
-                                  "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz"
-                                }
-                              }
-                            },
-                            "loud-rejection": {
-                              "version": "1.0.0",
-                              "from": "loud-rejection@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.0.0.tgz"
-                            },
-                            "minimist": {
-                              "version": "1.2.0",
-                              "from": "minimist@>=1.1.3 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
-                            },
                             "normalize-package-data": {
                               "version": "2.3.4",
-                              "from": "normalize-package-data@>=2.3.4 <3.0.0",
-                              "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.4.tgz",
-                              "dependencies": {
-                                "hosted-git-info": {
-                                  "version": "2.1.4",
-                                  "from": "hosted-git-info@>=2.0.2 <3.0.0",
-                                  "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.4.tgz"
-                                },
-                                "is-builtin-module": {
-                                  "version": "1.0.0",
-                                  "from": "is-builtin-module@>=1.0.0 <2.0.0",
-                                  "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
-                                  "dependencies": {
-                                    "builtin-modules": {
-                                      "version": "1.1.0",
-                                      "from": "builtin-modules@>=1.0.0 <2.0.0",
-                                      "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.0.tgz"
-                                    }
-                                  }
-                                },
-                                "semver": {
-                                  "version": "5.0.3",
-                                  "from": "semver@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0||>=4.0.0 <5.0.0||>=5.0.0 <6.0.0"
-                                },
-                                "validate-npm-package-license": {
-                                  "version": "3.0.1",
-                                  "from": "validate-npm-package-license@>=3.0.1 <4.0.0",
-                                  "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz",
-                                  "dependencies": {
-                                    "spdx-correct": {
-                                      "version": "1.0.1",
-                                      "from": "spdx-correct@>=1.0.0 <1.1.0",
-                                      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.1.tgz",
-                                      "dependencies": {
-                                        "spdx-license-ids": {
-                                          "version": "1.0.2",
-                                          "from": "spdx-license-ids@>=1.0.2 <2.0.0",
-                                          "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.0.2.tgz"
-                                        }
-                                      }
-                                    },
-                                    "spdx-expression-parse": {
-                                      "version": "1.0.0",
-                                      "from": "spdx-expression-parse@>=1.0.0 <1.1.0",
-                                      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.0.tgz",
-                                      "dependencies": {
-                                        "spdx-exceptions": {
-                                          "version": "1.0.3",
-                                          "from": "spdx-exceptions@>=1.0.0 <2.0.0",
-                                          "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-1.0.3.tgz"
-                                        },
-                                        "spdx-license-ids": {
-                                          "version": "1.0.2",
-                                          "from": "spdx-license-ids@>=1.0.0 <2.0.0",
-                                          "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.0.2.tgz"
-                                        }
-                                      }
-                                    }
-                                  }
-                                }
-                              }
-                            },
-                            "object-assign": {
-                              "version": "4.0.1",
-                              "from": "object-assign@>=4.0.1 <5.0.0",
-                              "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.0.1.tgz"
-                            },
-                            "read-pkg-up": {
-                              "version": "1.0.1",
-                              "from": "read-pkg-up@>=1.0.1 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
-                              "dependencies": {
-                                "find-up": {
-                                  "version": "1.0.0",
-                                  "from": "find-up@>=1.0.0 <2.0.0",
-                                  "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.0.0.tgz",
-                                  "dependencies": {
-                                    "path-exists": {
-                                      "version": "2.0.0",
-                                      "from": "path-exists@>=2.0.0 <3.0.0",
-                                      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.0.0.tgz"
-                                    },
-                                    "pinkie-promise": {
-                                      "version": "1.0.0",
-                                      "from": "pinkie-promise@>=1.0.0 <2.0.0",
-                                      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz",
-                                      "dependencies": {
-                                        "pinkie": {
-                                          "version": "1.0.0",
-                                          "from": "pinkie@>=1.0.0 <2.0.0",
-                                          "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
-                                        }
-                                      }
-                                    }
-                                  }
-                                },
-                                "read-pkg": {
-                                  "version": "1.1.0",
-                                  "from": "read-pkg@>=1.0.0 <2.0.0",
-                                  "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
-                                  "dependencies": {
-                                    "load-json-file": {
-                                      "version": "1.0.1",
-                                      "from": "load-json-file@>=1.0.0 <2.0.0",
-                                      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.0.1.tgz",
-                                      "dependencies": {
-                                        "graceful-fs": {
-                                          "version": "4.1.2",
-                                          "from": "graceful-fs@>=4.1.2 <5.0.0"
-                                        },
-                                        "parse-json": {
-                                          "version": "2.2.0",
-                                          "from": "parse-json@>=2.2.0 <3.0.0",
-                                          "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
-                                          "dependencies": {
-                                            "error-ex": {
-                                              "version": "1.2.0",
-                                              "from": "error-ex@>=1.2.0 <2.0.0",
-                                              "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.2.0.tgz"
-                                            }
-                                          }
-                                        },
-                                        "pify": {
-                                          "version": "2.2.0",
-                                          "from": "pify@>=2.0.0 <3.0.0",
-                                          "resolved": "https://registry.npmjs.org/pify/-/pify-2.2.0.tgz"
-                                        },
-                                        "pinkie-promise": {
-                                          "version": "1.0.0",
-                                          "from": "pinkie-promise@>=1.0.0 <2.0.0",
-                                          "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz",
-                                          "dependencies": {
-                                            "pinkie": {
-                                              "version": "1.0.0",
-                                              "from": "pinkie@>=1.0.0 <2.0.0",
-                                              "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
-                                            }
-                                          }
-                                        },
-                                        "strip-bom": {
-                                          "version": "2.0.0",
-                                          "from": "strip-bom@>=2.0.0 <3.0.0",
-                                          "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
-                                          "dependencies": {
-                                            "is-utf8": {
-                                              "version": "0.2.0",
-                                              "from": "is-utf8@>=0.2.0 <0.3.0",
-                                              "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.0.tgz"
-                                            }
-                                          }
-                                        }
-                                      }
-                                    },
-                                    "path-type": {
-                                      "version": "1.0.0",
-                                      "from": "path-type@>=1.0.0 <2.0.0",
-                                      "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.0.0.tgz",
-                                      "dependencies": {
-                                        "graceful-fs": {
-                                          "version": "4.1.2",
-                                          "from": "graceful-fs@>=4.1.2 <5.0.0"
-                                        },
-                                        "pify": {
-                                          "version": "2.2.0",
-                                          "from": "pify@>=2.0.0 <3.0.0",
-                                          "resolved": "https://registry.npmjs.org/pify/-/pify-2.2.0.tgz"
-                                        },
-                                        "pinkie-promise": {
-                                          "version": "1.0.0",
-                                          "from": "pinkie-promise@>=1.0.0 <2.0.0",
-                                          "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz",
-                                          "dependencies": {
-                                            "pinkie": {
-                                              "version": "1.0.0",
-                                              "from": "pinkie@>=1.0.0 <2.0.0",
-                                              "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
-                                            }
-                                          }
-                                        }
-                                      }
-                                    }
-                                  }
-                                }
-                              }
-                            },
-                            "redent": {
-                              "version": "1.0.0",
-                              "from": "redent@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
-                              "dependencies": {
-                                "indent-string": {
-                                  "version": "2.1.0",
-                                  "from": "indent-string@>=2.1.0 <3.0.0",
-                                  "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
-                                  "dependencies": {
-                                    "repeating": {
-                                      "version": "2.0.0",
-                                      "from": "repeating@>=2.0.0 <3.0.0",
-                                      "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.0.tgz",
-                                      "dependencies": {
-                                        "is-finite": {
-                                          "version": "1.0.1",
-                                          "from": "is-finite@>=1.0.0 <2.0.0",
-                                          "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.1.tgz",
-                                          "dependencies": {
-                                            "number-is-nan": {
-                                              "version": "1.0.0",
-                                              "from": "number-is-nan@>=1.0.0 <2.0.0",
-                                              "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz"
-                                            }
-                                          }
-                                        }
-                                      }
-                                    }
-                                  }
-                                },
-                                "strip-indent": {
-                                  "version": "1.0.1",
-                                  "from": "strip-indent@>=1.0.1 <2.0.0",
-                                  "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
-                                  "dependencies": {
-                                    "get-stdin": {
-                                      "version": "4.0.1",
-                                      "from": "get-stdin@>=4.0.1 <5.0.0",
-                                      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz"
-                                    }
-                                  }
-                                }
-                              }
-                            },
-                            "trim-newlines": {
-                              "version": "1.0.0",
-                              "from": "trim-newlines@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz"
+                              "from": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.4.tgz",
+                              "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.4.tgz"
                             }
                           }
                         }
@@ -6447,177 +5264,128 @@
                 },
                 "decompress": {
                   "version": "2.3.0",
-                  "from": "decompress@>=2.1.1 <3.0.0",
+                  "from": "https://registry.npmjs.org/decompress/-/decompress-2.3.0.tgz",
                   "resolved": "https://registry.npmjs.org/decompress/-/decompress-2.3.0.tgz",
                   "dependencies": {
                     "buffer-to-vinyl": {
                       "version": "1.0.1",
-                      "from": "buffer-to-vinyl@>=1.0.0 <2.0.0",
+                      "from": "https://registry.npmjs.org/buffer-to-vinyl/-/buffer-to-vinyl-1.0.1.tgz",
                       "resolved": "https://registry.npmjs.org/buffer-to-vinyl/-/buffer-to-vinyl-1.0.1.tgz",
                       "dependencies": {
                         "file-type": {
                           "version": "2.12.0",
-                          "from": "file-type@>=2.2.0 <3.0.0",
+                          "from": "https://registry.npmjs.org/file-type/-/file-type-2.12.0.tgz",
                           "resolved": "https://registry.npmjs.org/file-type/-/file-type-2.12.0.tgz"
                         },
                         "readable-stream": {
                           "version": "2.0.4",
-                          "from": "readable-stream@>=2.0.2 <3.0.0"
+                          "from": "readable-stream@2.0.4",
+                          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.4.tgz"
                         },
                         "uuid": {
                           "version": "2.0.1",
-                          "from": "uuid@>=2.0.1 <3.0.0",
+                          "from": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz",
                           "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz"
-                        },
-                        "vinyl": {
-                          "version": "0.5.3",
-                          "from": "vinyl@>=0.5.1 <0.6.0",
-                          "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz"
                         }
                       }
                     },
                     "decompress-tar": {
                       "version": "3.1.0",
-                      "from": "decompress-tar@>=3.0.0 <4.0.0",
+                      "from": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-3.1.0.tgz",
                       "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-3.1.0.tgz",
                       "dependencies": {
                         "is-tar": {
                           "version": "1.0.0",
-                          "from": "is-tar@>=1.0.0 <2.0.0",
+                          "from": "https://registry.npmjs.org/is-tar/-/is-tar-1.0.0.tgz",
                           "resolved": "https://registry.npmjs.org/is-tar/-/is-tar-1.0.0.tgz"
                         },
                         "object-assign": {
                           "version": "2.1.1",
-                          "from": "object-assign@>=2.0.0 <3.0.0",
+                          "from": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz",
                           "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz"
                         },
                         "strip-dirs": {
                           "version": "1.1.1",
-                          "from": "strip-dirs@>=1.0.0 <2.0.0",
+                          "from": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-1.1.1.tgz",
                           "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-1.1.1.tgz",
                           "dependencies": {
                             "is-absolute": {
                               "version": "0.1.7",
-                              "from": "is-absolute@>=0.1.5 <0.2.0",
+                              "from": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz",
                               "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz",
                               "dependencies": {
                                 "is-relative": {
                                   "version": "0.1.3",
-                                  "from": "is-relative@>=0.1.0 <0.2.0",
+                                  "from": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz",
                                   "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz"
                                 }
                               }
                             },
                             "is-natural-number": {
                               "version": "2.0.0",
-                              "from": "is-natural-number@>=2.0.0 <3.0.0",
+                              "from": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-2.0.0.tgz",
                               "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-2.0.0.tgz"
                             },
-                            "minimist": {
-                              "version": "1.2.0",
-                              "from": "minimist@>=1.1.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
-                            },
                             "sum-up": {
                               "version": "1.0.2",
-                              "from": "sum-up@>=1.0.1 <2.0.0",
+                              "from": "https://registry.npmjs.org/sum-up/-/sum-up-1.0.2.tgz",
                               "resolved": "https://registry.npmjs.org/sum-up/-/sum-up-1.0.2.tgz"
                             }
                           }
                         },
                         "tar-stream": {
                           "version": "1.2.1",
-                          "from": "tar-stream@>=1.1.1 <2.0.0",
+                          "from": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.2.1.tgz",
                           "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.2.1.tgz",
                           "dependencies": {
                             "bl": {
                               "version": "1.0.0",
-                              "from": "bl@>=1.0.0 <2.0.0",
+                              "from": "https://registry.npmjs.org/bl/-/bl-1.0.0.tgz",
                               "resolved": "https://registry.npmjs.org/bl/-/bl-1.0.0.tgz"
                             },
                             "end-of-stream": {
-                              "version": "1.1.0",
-                              "from": "end-of-stream@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.1.0.tgz",
-                              "dependencies": {
-                                "once": {
-                                  "version": "1.3.2",
-                                  "from": "once@>=1.3.0 <1.4.0",
-                                  "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz",
-                                  "dependencies": {
-                                    "wrappy": {
-                                      "version": "1.0.1",
-                                      "from": "wrappy@>=1.0.0 <2.0.0",
-                                      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
-                                    }
-                                  }
-                                }
-                              }
+                              "version": "1.1.0",
+                              "from": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.1.0.tgz",
+                              "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.1.0.tgz"
                             },
                             "readable-stream": {
                               "version": "2.0.4",
-                              "from": "readable-stream@>=2.0.0 <3.0.0"
+                              "from": "readable-stream@2.0.4",
+                              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.4.tgz"
                             },
                             "xtend": {
                               "version": "4.0.0",
-                              "from": "xtend@>=4.0.0 <5.0.0",
+                              "from": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz",
                               "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz"
                             }
                           }
                         },
                         "through2": {
                           "version": "0.6.5",
-                          "from": "through2@>=0.6.1 <0.7.0",
+                          "from": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
                           "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
                           "dependencies": {
                             "readable-stream": {
                               "version": "1.0.33",
-                              "from": "readable-stream@>=1.0.33-1 <1.1.0-0",
-                              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz",
-                              "dependencies": {
-                                "core-util-is": {
-                                  "version": "1.0.1",
-                                  "from": "core-util-is@>=1.0.0 <1.1.0",
-                                  "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-                                },
-                                "isarray": {
-                                  "version": "0.0.1",
-                                  "from": "isarray@0.0.1",
-                                  "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
-                                },
-                                "string_decoder": {
-                                  "version": "0.10.31",
-                                  "from": "string_decoder@>=0.10.0 <0.11.0",
-                                  "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
-                                },
-                                "inherits": {
-                                  "version": "2.0.1",
-                                  "from": "inherits@>=2.0.1 <2.1.0",
-                                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                                }
-                              }
+                              "from": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz",
+                              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz"
                             },
                             "xtend": {
                               "version": "4.0.0",
-                              "from": "xtend@>=4.0.0 <4.1.0-0",
+                              "from": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz",
                               "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz"
                             }
                           }
                         },
                         "vinyl": {
                           "version": "0.4.6",
-                          "from": "vinyl@>=0.4.3 <0.5.0",
+                          "from": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz",
                           "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz",
                           "dependencies": {
                             "clone": {
                               "version": "0.2.0",
-                              "from": "clone@>=0.2.0 <0.3.0",
+                              "from": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz",
                               "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz"
-                            },
-                            "clone-stats": {
-                              "version": "0.0.1",
-                              "from": "clone-stats@>=0.0.1 <0.0.2",
-                              "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz"
                             }
                           }
                         }
@@ -6625,165 +5393,113 @@
                     },
                     "decompress-tarbz2": {
                       "version": "3.1.0",
-                      "from": "decompress-tarbz2@>=3.0.0 <4.0.0",
+                      "from": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-3.1.0.tgz",
                       "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-3.1.0.tgz",
                       "dependencies": {
                         "is-bzip2": {
                           "version": "1.0.0",
-                          "from": "is-bzip2@>=1.0.0 <2.0.0",
+                          "from": "https://registry.npmjs.org/is-bzip2/-/is-bzip2-1.0.0.tgz",
                           "resolved": "https://registry.npmjs.org/is-bzip2/-/is-bzip2-1.0.0.tgz"
                         },
                         "object-assign": {
                           "version": "2.1.1",
-                          "from": "object-assign@>=2.0.0 <3.0.0",
+                          "from": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz",
                           "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz"
                         },
                         "seek-bzip": {
                           "version": "1.0.5",
-                          "from": "seek-bzip@>=1.0.3 <2.0.0",
+                          "from": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz",
                           "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz",
                           "dependencies": {
                             "commander": {
                               "version": "2.8.1",
-                              "from": "commander@>=2.8.1 <2.9.0",
-                              "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
-                              "dependencies": {
-                                "graceful-readlink": {
-                                  "version": "1.0.1",
-                                  "from": "graceful-readlink@>=1.0.0",
-                                  "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
-                                }
-                              }
+                              "from": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
+                              "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz"
                             }
                           }
                         },
                         "strip-dirs": {
                           "version": "1.1.1",
-                          "from": "strip-dirs@>=1.0.0 <2.0.0",
+                          "from": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-1.1.1.tgz",
                           "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-1.1.1.tgz",
                           "dependencies": {
                             "is-absolute": {
                               "version": "0.1.7",
-                              "from": "is-absolute@>=0.1.5 <0.2.0",
+                              "from": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz",
                               "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz",
                               "dependencies": {
                                 "is-relative": {
                                   "version": "0.1.3",
-                                  "from": "is-relative@>=0.1.0 <0.2.0",
+                                  "from": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz",
                                   "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz"
                                 }
                               }
                             },
                             "is-natural-number": {
                               "version": "2.0.0",
-                              "from": "is-natural-number@>=2.0.0 <3.0.0",
+                              "from": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-2.0.0.tgz",
                               "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-2.0.0.tgz"
                             },
-                            "minimist": {
-                              "version": "1.2.0",
-                              "from": "minimist@>=1.1.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
-                            },
                             "sum-up": {
                               "version": "1.0.2",
-                              "from": "sum-up@>=1.0.1 <2.0.0",
+                              "from": "https://registry.npmjs.org/sum-up/-/sum-up-1.0.2.tgz",
                               "resolved": "https://registry.npmjs.org/sum-up/-/sum-up-1.0.2.tgz"
                             }
                           }
                         },
                         "tar-stream": {
                           "version": "1.2.1",
-                          "from": "tar-stream@>=1.1.1 <2.0.0",
+                          "from": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.2.1.tgz",
                           "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.2.1.tgz",
                           "dependencies": {
                             "bl": {
                               "version": "1.0.0",
-                              "from": "bl@>=1.0.0 <2.0.0",
+                              "from": "https://registry.npmjs.org/bl/-/bl-1.0.0.tgz",
                               "resolved": "https://registry.npmjs.org/bl/-/bl-1.0.0.tgz"
                             },
                             "end-of-stream": {
                               "version": "1.1.0",
-                              "from": "end-of-stream@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.1.0.tgz",
-                              "dependencies": {
-                                "once": {
-                                  "version": "1.3.2",
-                                  "from": "once@>=1.3.0 <1.4.0",
-                                  "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz",
-                                  "dependencies": {
-                                    "wrappy": {
-                                      "version": "1.0.1",
-                                      "from": "wrappy@>=1.0.0 <2.0.0",
-                                      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
-                                    }
-                                  }
-                                }
-                              }
+                              "from": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.1.0.tgz",
+                              "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.1.0.tgz"
                             },
                             "readable-stream": {
                               "version": "2.0.4",
-                              "from": "readable-stream@>=2.0.0 <3.0.0"
+                              "from": "readable-stream@2.0.4",
+                              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.4.tgz"
                             },
                             "xtend": {
                               "version": "4.0.0",
-                              "from": "xtend@>=4.0.0 <5.0.0",
+                              "from": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz",
                               "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz"
                             }
                           }
                         },
                         "through2": {
                           "version": "0.6.5",
-                          "from": "through2@>=0.6.1 <0.7.0",
+                          "from": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
                           "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
                           "dependencies": {
                             "readable-stream": {
                               "version": "1.0.33",
-                              "from": "readable-stream@>=1.0.33-1 <1.1.0-0",
-                              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz",
-                              "dependencies": {
-                                "core-util-is": {
-                                  "version": "1.0.1",
-                                  "from": "core-util-is@>=1.0.0 <1.1.0",
-                                  "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-                                },
-                                "isarray": {
-                                  "version": "0.0.1",
-                                  "from": "isarray@0.0.1",
-                                  "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
-                                },
-                                "string_decoder": {
-                                  "version": "0.10.31",
-                                  "from": "string_decoder@>=0.10.0 <0.11.0",
-                                  "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
-                                },
-                                "inherits": {
-                                  "version": "2.0.1",
-                                  "from": "inherits@>=2.0.1 <2.1.0",
-                                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                                }
-                              }
+                              "from": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz",
+                              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz"
                             },
                             "xtend": {
                               "version": "4.0.0",
-                              "from": "xtend@>=4.0.0 <4.1.0-0",
+                              "from": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz",
                               "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz"
                             }
                           }
                         },
                         "vinyl": {
                           "version": "0.4.6",
-                          "from": "vinyl@>=0.4.3 <0.5.0",
+                          "from": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz",
                           "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz",
                           "dependencies": {
                             "clone": {
                               "version": "0.2.0",
-                              "from": "clone@>=0.2.0 <0.3.0",
+                              "from": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz",
                               "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz"
-                            },
-                            "clone-stats": {
-                              "version": "0.0.1",
-                              "from": "clone-stats@>=0.0.1 <0.0.2",
-                              "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz"
                             }
                           }
                         }
@@ -6791,146 +5507,101 @@
                     },
                     "decompress-targz": {
                       "version": "3.1.0",
-                      "from": "decompress-targz@>=3.0.0 <4.0.0",
+                      "from": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-3.1.0.tgz",
                       "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-3.1.0.tgz",
                       "dependencies": {
                         "is-gzip": {
                           "version": "1.0.0",
-                          "from": "is-gzip@>=1.0.0 <2.0.0",
+                          "from": "https://registry.npmjs.org/is-gzip/-/is-gzip-1.0.0.tgz",
                           "resolved": "https://registry.npmjs.org/is-gzip/-/is-gzip-1.0.0.tgz"
                         },
                         "object-assign": {
                           "version": "2.1.1",
-                          "from": "object-assign@>=2.0.0 <3.0.0",
+                          "from": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz",
                           "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz"
                         },
                         "strip-dirs": {
                           "version": "1.1.1",
-                          "from": "strip-dirs@>=1.0.0 <2.0.0",
+                          "from": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-1.1.1.tgz",
                           "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-1.1.1.tgz",
                           "dependencies": {
                             "is-absolute": {
                               "version": "0.1.7",
-                              "from": "is-absolute@>=0.1.5 <0.2.0",
+                              "from": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz",
                               "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz",
                               "dependencies": {
                                 "is-relative": {
                                   "version": "0.1.3",
-                                  "from": "is-relative@>=0.1.0 <0.2.0",
+                                  "from": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz",
                                   "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz"
                                 }
                               }
                             },
                             "is-natural-number": {
                               "version": "2.0.0",
-                              "from": "is-natural-number@>=2.0.0 <3.0.0",
+                              "from": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-2.0.0.tgz",
                               "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-2.0.0.tgz"
                             },
-                            "minimist": {
-                              "version": "1.2.0",
-                              "from": "minimist@>=1.1.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
-                            },
                             "sum-up": {
                               "version": "1.0.2",
-                              "from": "sum-up@>=1.0.1 <2.0.0",
+                              "from": "https://registry.npmjs.org/sum-up/-/sum-up-1.0.2.tgz",
                               "resolved": "https://registry.npmjs.org/sum-up/-/sum-up-1.0.2.tgz"
                             }
                           }
                         },
                         "tar-stream": {
                           "version": "1.2.1",
-                          "from": "tar-stream@>=1.1.1 <2.0.0",
+                          "from": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.2.1.tgz",
                           "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.2.1.tgz",
                           "dependencies": {
                             "bl": {
                               "version": "1.0.0",
-                              "from": "bl@>=1.0.0 <2.0.0",
+                              "from": "https://registry.npmjs.org/bl/-/bl-1.0.0.tgz",
                               "resolved": "https://registry.npmjs.org/bl/-/bl-1.0.0.tgz"
                             },
                             "end-of-stream": {
                               "version": "1.1.0",
-                              "from": "end-of-stream@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.1.0.tgz",
-                              "dependencies": {
-                                "once": {
-                                  "version": "1.3.2",
-                                  "from": "once@>=1.3.0 <1.4.0",
-                                  "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz",
-                                  "dependencies": {
-                                    "wrappy": {
-                                      "version": "1.0.1",
-                                      "from": "wrappy@>=1.0.0 <2.0.0",
-                                      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
-                                    }
-                                  }
-                                }
-                              }
+                              "from": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.1.0.tgz",
+                              "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.1.0.tgz"
                             },
                             "readable-stream": {
                               "version": "2.0.4",
-                              "from": "readable-stream@>=2.0.0 <3.0.0"
+                              "from": "readable-stream@2.0.4",
+                              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.4.tgz"
                             },
                             "xtend": {
                               "version": "4.0.0",
-                              "from": "xtend@>=4.0.0 <5.0.0",
+                              "from": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz",
                               "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz"
                             }
                           }
                         },
                         "through2": {
                           "version": "0.6.5",
-                          "from": "through2@>=0.6.1 <0.7.0",
+                          "from": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
                           "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
                           "dependencies": {
                             "readable-stream": {
                               "version": "1.0.33",
-                              "from": "readable-stream@>=1.0.33-1 <1.1.0-0",
-                              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz",
-                              "dependencies": {
-                                "core-util-is": {
-                                  "version": "1.0.1",
-                                  "from": "core-util-is@>=1.0.0 <1.1.0",
-                                  "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-                                },
-                                "isarray": {
-                                  "version": "0.0.1",
-                                  "from": "isarray@0.0.1",
-                                  "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
-                                },
-                                "string_decoder": {
-                                  "version": "0.10.31",
-                                  "from": "string_decoder@>=0.10.0 <0.11.0",
-                                  "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
-                                },
-                                "inherits": {
-                                  "version": "2.0.1",
-                                  "from": "inherits@>=2.0.1 <2.1.0",
-                                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                                }
-                              }
+                              "from": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz",
+                              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz"
                             },
                             "xtend": {
                               "version": "4.0.0",
-                              "from": "xtend@>=4.0.0 <4.1.0-0",
+                              "from": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz",
                               "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz"
                             }
                           }
                         },
                         "vinyl": {
                           "version": "0.4.6",
-                          "from": "vinyl@>=0.4.3 <0.5.0",
+                          "from": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz",
                           "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz",
                           "dependencies": {
                             "clone": {
                               "version": "0.2.0",
-                              "from": "clone@>=0.2.0 <0.3.0",
+                              "from": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz",
                               "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz"
-                            },
-                            "clone-stats": {
-                              "version": "0.0.1",
-                              "from": "clone-stats@>=0.0.1 <0.0.2",
-                              "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz"
                             }
                           }
                         }
@@ -6938,356 +5609,88 @@
                     },
                     "decompress-unzip": {
                       "version": "3.3.0",
-                      "from": "decompress-unzip@>=3.0.0 <4.0.0",
+                      "from": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-3.3.0.tgz",
                       "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-3.3.0.tgz",
                       "dependencies": {
                         "is-zip": {
                           "version": "1.0.0",
-                          "from": "is-zip@>=1.0.0 <2.0.0",
+                          "from": "https://registry.npmjs.org/is-zip/-/is-zip-1.0.0.tgz",
                           "resolved": "https://registry.npmjs.org/is-zip/-/is-zip-1.0.0.tgz"
                         },
                         "stat-mode": {
                           "version": "0.2.1",
-                          "from": "stat-mode@>=0.2.0 <0.3.0",
+                          "from": "https://registry.npmjs.org/stat-mode/-/stat-mode-0.2.1.tgz",
                           "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-0.2.1.tgz"
                         },
                         "strip-dirs": {
                           "version": "1.1.1",
-                          "from": "strip-dirs@>=1.0.0 <2.0.0",
+                          "from": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-1.1.1.tgz",
                           "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-1.1.1.tgz",
                           "dependencies": {
                             "is-absolute": {
                               "version": "0.1.7",
-                              "from": "is-absolute@>=0.1.5 <0.2.0",
+                              "from": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz",
                               "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz",
                               "dependencies": {
                                 "is-relative": {
                                   "version": "0.1.3",
-                                  "from": "is-relative@>=0.1.0 <0.2.0",
+                                  "from": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz",
                                   "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz"
                                 }
                               }
                             },
                             "is-natural-number": {
                               "version": "2.0.0",
-                              "from": "is-natural-number@>=2.0.0 <3.0.0",
+                              "from": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-2.0.0.tgz",
                               "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-2.0.0.tgz"
                             },
-                            "minimist": {
-                              "version": "1.2.0",
-                              "from": "minimist@>=1.1.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
-                            },
                             "sum-up": {
                               "version": "1.0.2",
-                              "from": "sum-up@>=1.0.1 <2.0.0",
+                              "from": "https://registry.npmjs.org/sum-up/-/sum-up-1.0.2.tgz",
                               "resolved": "https://registry.npmjs.org/sum-up/-/sum-up-1.0.2.tgz"
                             }
                           }
                         },
-                        "vinyl": {
-                          "version": "0.5.3",
-                          "from": "vinyl@>=0.5.0 <0.6.0"
-                        },
                         "yauzl": {
                           "version": "2.3.1",
-                          "from": "yauzl@>=2.2.1 <3.0.0",
+                          "from": "https://registry.npmjs.org/yauzl/-/yauzl-2.3.1.tgz",
                           "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.3.1.tgz",
                           "dependencies": {
                             "fd-slicer": {
                               "version": "1.0.1",
-                              "from": "fd-slicer@>=1.0.1 <1.1.0",
+                              "from": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz",
                               "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz"
                             },
                             "pend": {
                               "version": "1.2.0",
-                              "from": "pend@>=1.2.0 <1.3.0",
+                              "from": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
                               "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz"
                             }
                           }
                         }
                       }
                     },
-                    "get-stdin": {
-                      "version": "4.0.1",
-                      "from": "get-stdin@>=4.0.1 <5.0.0",
-                      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz"
-                    },
                     "meow": {
                       "version": "3.4.2",
-                      "from": "meow@>=3.0.0 <4.0.0",
+                      "from": "https://registry.npmjs.org/meow/-/meow-3.4.2.tgz",
                       "resolved": "https://registry.npmjs.org/meow/-/meow-3.4.2.tgz",
                       "dependencies": {
-                        "camelcase-keys": {
-                          "version": "1.0.0",
-                          "from": "camelcase-keys@>=1.0.0 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-1.0.0.tgz",
-                          "dependencies": {
-                            "camelcase": {
-                              "version": "1.2.1",
-                              "from": "camelcase@>=1.0.1 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz"
-                            },
-                            "map-obj": {
-                              "version": "1.0.1",
-                              "from": "map-obj@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz"
-                            }
-                          }
-                        },
-                        "loud-rejection": {
-                          "version": "1.0.0",
-                          "from": "loud-rejection@>=1.0.0 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.0.0.tgz"
-                        },
-                        "minimist": {
-                          "version": "1.2.0",
-                          "from": "minimist@>=1.1.3 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
-                        },
                         "normalize-package-data": {
                           "version": "2.3.4",
-                          "from": "normalize-package-data@>=2.3.4 <3.0.0",
-                          "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.4.tgz",
-                          "dependencies": {
-                            "hosted-git-info": {
-                              "version": "2.1.4",
-                              "from": "hosted-git-info@>=2.0.2 <3.0.0",
-                              "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.4.tgz"
-                            },
-                            "is-builtin-module": {
-                              "version": "1.0.0",
-                              "from": "is-builtin-module@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
-                              "dependencies": {
-                                "builtin-modules": {
-                                  "version": "1.1.0",
-                                  "from": "builtin-modules@>=1.0.0 <2.0.0",
-                                  "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.0.tgz"
-                                }
-                              }
-                            },
-                            "semver": {
-                              "version": "5.0.3",
-                              "from": "semver@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0||>=4.0.0 <5.0.0||>=5.0.0 <6.0.0"
-                            },
-                            "validate-npm-package-license": {
-                              "version": "3.0.1",
-                              "from": "validate-npm-package-license@>=3.0.1 <4.0.0",
-                              "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz",
-                              "dependencies": {
-                                "spdx-correct": {
-                                  "version": "1.0.1",
-                                  "from": "spdx-correct@>=1.0.0 <1.1.0",
-                                  "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.1.tgz",
-                                  "dependencies": {
-                                    "spdx-license-ids": {
-                                      "version": "1.0.2",
-                                      "from": "spdx-license-ids@>=1.0.2 <2.0.0",
-                                      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.0.2.tgz"
-                                    }
-                                  }
-                                },
-                                "spdx-expression-parse": {
-                                  "version": "1.0.0",
-                                  "from": "spdx-expression-parse@>=1.0.0 <1.1.0",
-                                  "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.0.tgz",
-                                  "dependencies": {
-                                    "spdx-exceptions": {
-                                      "version": "1.0.3",
-                                      "from": "spdx-exceptions@>=1.0.0 <2.0.0",
-                                      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-1.0.3.tgz"
-                                    },
-                                    "spdx-license-ids": {
-                                      "version": "1.0.2",
-                                      "from": "spdx-license-ids@>=1.0.0 <2.0.0",
-                                      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.0.2.tgz"
-                                    }
-                                  }
-                                }
-                              }
-                            }
-                          }
-                        },
-                        "object-assign": {
-                          "version": "4.0.1",
-                          "from": "object-assign@>=4.0.1 <5.0.0"
-                        },
-                        "read-pkg-up": {
-                          "version": "1.0.1",
-                          "from": "read-pkg-up@>=1.0.1 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
-                          "dependencies": {
-                            "find-up": {
-                              "version": "1.0.0",
-                              "from": "find-up@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.0.0.tgz",
-                              "dependencies": {
-                                "path-exists": {
-                                  "version": "2.0.0",
-                                  "from": "path-exists@>=2.0.0 <3.0.0",
-                                  "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.0.0.tgz"
-                                },
-                                "pinkie-promise": {
-                                  "version": "1.0.0",
-                                  "from": "pinkie-promise@>=1.0.0 <2.0.0",
-                                  "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz",
-                                  "dependencies": {
-                                    "pinkie": {
-                                      "version": "1.0.0",
-                                      "from": "pinkie@>=1.0.0 <2.0.0",
-                                      "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
-                                    }
-                                  }
-                                }
-                              }
-                            },
-                            "read-pkg": {
-                              "version": "1.1.0",
-                              "from": "read-pkg@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
-                              "dependencies": {
-                                "load-json-file": {
-                                  "version": "1.0.1",
-                                  "from": "load-json-file@>=1.0.0 <2.0.0",
-                                  "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.0.1.tgz",
-                                  "dependencies": {
-                                    "graceful-fs": {
-                                      "version": "4.1.2",
-                                      "from": "graceful-fs@>=4.1.2 <5.0.0"
-                                    },
-                                    "parse-json": {
-                                      "version": "2.2.0",
-                                      "from": "parse-json@>=2.2.0 <3.0.0",
-                                      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
-                                      "dependencies": {
-                                        "error-ex": {
-                                          "version": "1.2.0",
-                                          "from": "error-ex@>=1.2.0 <2.0.0",
-                                          "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.2.0.tgz"
-                                        }
-                                      }
-                                    },
-                                    "pify": {
-                                      "version": "2.2.0",
-                                      "from": "pify@>=2.0.0 <3.0.0",
-                                      "resolved": "https://registry.npmjs.org/pify/-/pify-2.2.0.tgz"
-                                    },
-                                    "pinkie-promise": {
-                                      "version": "1.0.0",
-                                      "from": "pinkie-promise@>=1.0.0 <2.0.0",
-                                      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz",
-                                      "dependencies": {
-                                        "pinkie": {
-                                          "version": "1.0.0",
-                                          "from": "pinkie@>=1.0.0 <2.0.0",
-                                          "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
-                                        }
-                                      }
-                                    },
-                                    "strip-bom": {
-                                      "version": "2.0.0",
-                                      "from": "strip-bom@>=2.0.0 <3.0.0",
-                                      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
-                                      "dependencies": {
-                                        "is-utf8": {
-                                          "version": "0.2.0",
-                                          "from": "is-utf8@>=0.2.0 <0.3.0",
-                                          "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.0.tgz"
-                                        }
-                                      }
-                                    }
-                                  }
-                                },
-                                "path-type": {
-                                  "version": "1.0.0",
-                                  "from": "path-type@>=1.0.0 <2.0.0",
-                                  "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.0.0.tgz",
-                                  "dependencies": {
-                                    "graceful-fs": {
-                                      "version": "4.1.2",
-                                      "from": "graceful-fs@>=4.1.2 <5.0.0"
-                                    },
-                                    "pify": {
-                                      "version": "2.2.0",
-                                      "from": "pify@>=2.0.0 <3.0.0",
-                                      "resolved": "https://registry.npmjs.org/pify/-/pify-2.2.0.tgz"
-                                    },
-                                    "pinkie-promise": {
-                                      "version": "1.0.0",
-                                      "from": "pinkie-promise@>=1.0.0 <2.0.0",
-                                      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz",
-                                      "dependencies": {
-                                        "pinkie": {
-                                          "version": "1.0.0",
-                                          "from": "pinkie@>=1.0.0 <2.0.0",
-                                          "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
-                                        }
-                                      }
-                                    }
-                                  }
-                                }
-                              }
-                            }
-                          }
-                        },
-                        "redent": {
-                          "version": "1.0.0",
-                          "from": "redent@>=1.0.0 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
-                          "dependencies": {
-                            "indent-string": {
-                              "version": "2.1.0",
-                              "from": "indent-string@>=2.1.0 <3.0.0",
-                              "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
-                              "dependencies": {
-                                "repeating": {
-                                  "version": "2.0.0",
-                                  "from": "repeating@>=2.0.0 <3.0.0",
-                                  "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.0.tgz",
-                                  "dependencies": {
-                                    "is-finite": {
-                                      "version": "1.0.1",
-                                      "from": "is-finite@>=1.0.0 <2.0.0",
-                                      "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.1.tgz",
-                                      "dependencies": {
-                                        "number-is-nan": {
-                                          "version": "1.0.0",
-                                          "from": "number-is-nan@>=1.0.0 <2.0.0",
-                                          "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz"
-                                        }
-                                      }
-                                    }
-                                  }
-                                }
-                              }
-                            },
-                            "strip-indent": {
-                              "version": "1.0.1",
-                              "from": "strip-indent@>=1.0.1 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz"
-                            }
-                          }
-                        },
-                        "trim-newlines": {
-                          "version": "1.0.0",
-                          "from": "trim-newlines@>=1.0.0 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz"
+                          "from": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.4.tgz",
+                          "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.4.tgz"
                         }
                       }
                     },
                     "vinyl-assign": {
                       "version": "1.2.1",
-                      "from": "vinyl-assign@>=1.0.1 <2.0.0",
+                      "from": "https://registry.npmjs.org/vinyl-assign/-/vinyl-assign-1.2.1.tgz",
                       "resolved": "https://registry.npmjs.org/vinyl-assign/-/vinyl-assign-1.2.1.tgz",
                       "dependencies": {
-                        "object-assign": {
-                          "version": "4.0.1",
-                          "from": "object-assign@>=4.0.1 <5.0.0"
-                        },
                         "readable-stream": {
                           "version": "2.0.4",
-                          "from": "readable-stream@>=2.0.0 <3.0.0"
+                          "from": "readable-stream@2.0.4",
+                          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.4.tgz"
                         }
                       }
                     }
@@ -7295,162 +5698,13 @@
                 },
                 "gulp-util": {
                   "version": "3.0.6",
-                  "from": "gulp-util@>=3.0.1 <4.0.0",
+                  "from": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.6.tgz",
                   "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.6.tgz",
                   "dependencies": {
-                    "array-differ": {
-                      "version": "1.0.0",
-                      "from": "array-differ@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz"
-                    },
-                    "array-uniq": {
-                      "version": "1.0.2",
-                      "from": "array-uniq@>=1.0.2 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.2.tgz"
-                    },
-                    "beeper": {
-                      "version": "1.1.0",
-                      "from": "beeper@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.0.tgz"
-                    },
-                    "lodash._reescape": {
-                      "version": "3.0.0",
-                      "from": "lodash._reescape@>=3.0.0 <4.0.0",
-                      "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz"
-                    },
-                    "lodash._reevaluate": {
-                      "version": "3.0.0",
-                      "from": "lodash._reevaluate@>=3.0.0 <4.0.0",
-                      "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz"
-                    },
-                    "lodash._reinterpolate": {
-                      "version": "3.0.0",
-                      "from": "lodash._reinterpolate@>=3.0.0 <4.0.0",
-                      "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz"
-                    },
-                    "lodash.template": {
-                      "version": "3.6.2",
-                      "from": "lodash.template@>=3.0.0 <4.0.0",
-                      "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz",
-                      "dependencies": {
-                        "lodash._basecopy": {
-                          "version": "3.0.1",
-                          "from": "lodash._basecopy@>=3.0.0 <4.0.0",
-                          "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz"
-                        },
-                        "lodash._basetostring": {
-                          "version": "3.0.1",
-                          "from": "lodash._basetostring@>=3.0.0 <4.0.0",
-                          "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz"
-                        },
-                        "lodash._basevalues": {
-                          "version": "3.0.0",
-                          "from": "lodash._basevalues@>=3.0.0 <4.0.0",
-                          "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz"
-                        },
-                        "lodash._isiterateecall": {
-                          "version": "3.0.9",
-                          "from": "lodash._isiterateecall@>=3.0.0 <4.0.0",
-                          "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz"
-                        },
-                        "lodash.escape": {
-                          "version": "3.0.0",
-                          "from": "lodash.escape@>=3.0.0 <4.0.0",
-                          "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.0.0.tgz"
-                        },
-                        "lodash.keys": {
-                          "version": "3.1.2",
-                          "from": "lodash.keys@>=3.0.0 <4.0.0",
-                          "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",
-                          "dependencies": {
-                            "lodash._getnative": {
-                              "version": "3.9.1",
-                              "from": "lodash._getnative@>=3.0.0 <4.0.0",
-                              "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz"
-                            },
-                            "lodash.isarguments": {
-                              "version": "3.0.4",
-                              "from": "lodash.isarguments@>=3.0.0 <4.0.0",
-                              "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.4.tgz"
-                            },
-                            "lodash.isarray": {
-                              "version": "3.0.4",
-                              "from": "lodash.isarray@>=3.0.0 <4.0.0",
-                              "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz"
-                            }
-                          }
-                        },
-                        "lodash.restparam": {
-                          "version": "3.6.1",
-                          "from": "lodash.restparam@>=3.0.0 <4.0.0",
-                          "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz"
-                        },
-                        "lodash.templatesettings": {
-                          "version": "3.1.0",
-                          "from": "lodash.templatesettings@>=3.0.0 <4.0.0",
-                          "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.0.tgz"
-                        }
-                      }
-                    },
-                    "minimist": {
-                      "version": "1.2.0",
-                      "from": "minimist@>=1.1.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
-                    },
-                    "multipipe": {
-                      "version": "0.1.2",
-                      "from": "multipipe@>=0.1.2 <0.2.0",
-                      "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz",
-                      "dependencies": {
-                        "duplexer2": {
-                          "version": "0.0.2",
-                          "from": "duplexer2@0.0.2",
-                          "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz",
-                          "dependencies": {
-                            "readable-stream": {
-                              "version": "1.1.13",
-                              "from": "readable-stream@>=1.1.9 <1.2.0",
-                              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz",
-                              "dependencies": {
-                                "core-util-is": {
-                                  "version": "1.0.1",
-                                  "from": "core-util-is@>=1.0.0 <1.1.0",
-                                  "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-                                },
-                                "isarray": {
-                                  "version": "0.0.1",
-                                  "from": "isarray@0.0.1",
-                                  "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
-                                },
-                                "string_decoder": {
-                                  "version": "0.10.31",
-                                  "from": "string_decoder@>=0.10.0 <0.11.0",
-                                  "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
-                                },
-                                "inherits": {
-                                  "version": "2.0.1",
-                                  "from": "inherits@>=2.0.1 <2.1.0",
-                                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                                }
-                              }
-                            }
-                          }
-                        }
-                      }
-                    },
                     "object-assign": {
                       "version": "3.0.0",
-                      "from": "object-assign@>=3.0.0 <4.0.0",
+                      "from": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
                       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz"
-                    },
-                    "replace-ext": {
-                      "version": "0.0.1",
-                      "from": "replace-ext@0.0.1",
-                      "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz"
-                    },
-                    "vinyl": {
-                      "version": "0.5.3",
-                      "from": "vinyl@>=0.5.0 <0.6.0"
                     }
                   }
                 }
@@ -7458,322 +5712,129 @@
             },
             "gulp-rename": {
               "version": "1.2.2",
-              "from": "gulp-rename@>=1.2.0 <2.0.0",
+              "from": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-1.2.2.tgz",
               "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-1.2.2.tgz"
             },
             "is-url": {
               "version": "1.2.1",
-              "from": "is-url@>=1.2.0 <2.0.0",
+              "from": "https://registry.npmjs.org/is-url/-/is-url-1.2.1.tgz",
               "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.1.tgz"
             },
-            "object-assign": {
-              "version": "4.0.1",
-              "from": "object-assign@>=4.0.1 <5.0.0",
-              "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.0.1.tgz"
-            },
             "read-all-stream": {
               "version": "3.0.1",
-              "from": "read-all-stream@>=3.0.0 <4.0.0",
+              "from": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.0.1.tgz",
               "resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.0.1.tgz",
               "dependencies": {
-                "pinkie-promise": {
-                  "version": "1.0.0",
-                  "from": "pinkie-promise@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz",
-                  "dependencies": {
-                    "pinkie": {
-                      "version": "1.0.0",
-                      "from": "pinkie@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
-                    }
-                  }
-                },
                 "readable-stream": {
                   "version": "2.0.4",
-                  "from": "readable-stream@>=2.0.0 <3.0.0"
+                  "from": "readable-stream@2.0.4",
+                  "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.4.tgz"
                 }
               }
             },
             "readable-stream": {
               "version": "2.0.2",
-              "from": "readable-stream@>=2.0.2 <3.0.0",
-              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz",
-              "dependencies": {
-                "core-util-is": {
-                  "version": "1.0.1",
-                  "from": "core-util-is@>=1.0.0 <1.1.0",
-                  "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-                },
-                "inherits": {
-                  "version": "2.0.1",
-                  "from": "inherits@>=2.0.1 <2.1.0",
-                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                },
-                "isarray": {
-                  "version": "0.0.1",
-                  "from": "isarray@0.0.1",
-                  "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
-                },
-                "process-nextick-args": {
-                  "version": "1.0.3",
-                  "from": "process-nextick-args@>=1.0.0 <1.1.0",
-                  "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.3.tgz"
-                },
-                "string_decoder": {
-                  "version": "0.10.31",
-                  "from": "string_decoder@>=0.10.0 <0.11.0",
-                  "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
-                },
-                "util-deprecate": {
-                  "version": "1.0.2",
-                  "from": "util-deprecate@>=1.0.1 <1.1.0",
-                  "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
-                }
-              }
+              "from": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz",
+              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz"
             },
             "stream-combiner2": {
               "version": "1.0.2",
-              "from": "stream-combiner2@>=1.0.2 <2.0.0",
+              "from": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.0.2.tgz",
               "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.0.2.tgz",
               "dependencies": {
-                "duplexer2": {
-                  "version": "0.0.2",
-                  "from": "duplexer2@>=0.0.2 <0.1.0",
-                  "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz",
-                  "dependencies": {
-                    "readable-stream": {
-                      "version": "1.1.13",
-                      "from": "readable-stream@>=1.1.9 <1.2.0",
-                      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz",
-                      "dependencies": {
-                        "core-util-is": {
-                          "version": "1.0.1",
-                          "from": "core-util-is@>=1.0.0 <1.1.0",
-                          "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-                        },
-                        "isarray": {
-                          "version": "0.0.1",
-                          "from": "isarray@0.0.1",
-                          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
-                        },
-                        "string_decoder": {
-                          "version": "0.10.31",
-                          "from": "string_decoder@>=0.10.0 <0.11.0",
-                          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
-                        },
-                        "inherits": {
-                          "version": "2.0.1",
-                          "from": "inherits@>=2.0.1 <2.1.0",
-                          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                        }
-                      }
-                    }
-                  }
-                },
                 "through2": {
                   "version": "0.5.1",
-                  "from": "through2@>=0.5.1 <0.6.0",
+                  "from": "https://registry.npmjs.org/through2/-/through2-0.5.1.tgz",
                   "resolved": "https://registry.npmjs.org/through2/-/through2-0.5.1.tgz",
                   "dependencies": {
                     "readable-stream": {
                       "version": "1.0.33",
-                      "from": "readable-stream@>=1.0.17 <1.1.0",
-                      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz",
-                      "dependencies": {
-                        "core-util-is": {
-                          "version": "1.0.1",
-                          "from": "core-util-is@>=1.0.0 <1.1.0",
-                          "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-                        },
-                        "isarray": {
-                          "version": "0.0.1",
-                          "from": "isarray@0.0.1",
-                          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
-                        },
-                        "string_decoder": {
-                          "version": "0.10.31",
-                          "from": "string_decoder@>=0.10.0 <0.11.0",
-                          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
-                        },
-                        "inherits": {
-                          "version": "2.0.1",
-                          "from": "inherits@>=2.0.1 <2.1.0",
-                          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                        }
-                      }
+                      "from": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz",
+                      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz"
                     },
                     "xtend": {
                       "version": "3.0.0",
-                      "from": "xtend@>=3.0.0 <3.1.0",
+                      "from": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz",
                       "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz"
                     }
                   }
                 }
               }
             },
-            "vinyl": {
-              "version": "0.5.3",
-              "from": "vinyl@>=0.5.3 <0.6.0",
-              "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz",
-              "dependencies": {
-                "clone": {
-                  "version": "1.0.2",
-                  "from": "clone@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz"
-                },
-                "clone-stats": {
-                  "version": "0.0.1",
-                  "from": "clone-stats@>=0.0.1 <0.0.2",
-                  "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz"
-                },
-                "replace-ext": {
-                  "version": "0.0.1",
-                  "from": "replace-ext@0.0.1",
-                  "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz"
-                }
-              }
-            },
             "vinyl-fs": {
               "version": "1.0.0",
-              "from": "vinyl-fs@>=1.0.0 <2.0.0",
+              "from": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-1.0.0.tgz",
               "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-1.0.0.tgz",
               "dependencies": {
                 "duplexify": {
                   "version": "3.4.2",
-                  "from": "duplexify@>=3.2.0 <4.0.0",
+                  "from": "https://registry.npmjs.org/duplexify/-/duplexify-3.4.2.tgz",
                   "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.4.2.tgz",
                   "dependencies": {
-                    "end-of-stream": {
-                      "version": "1.0.0",
-                      "from": "end-of-stream@1.0.0",
-                      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz",
-                      "dependencies": {
-                        "once": {
-                          "version": "1.3.2",
-                          "from": "once@>=1.3.0 <1.4.0",
-                          "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz",
-                          "dependencies": {
-                            "wrappy": {
-                              "version": "1.0.1",
-                              "from": "wrappy@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
-                            }
-                          }
-                        }
-                      }
-                    },
-                    "readable-stream": {
-                      "version": "2.0.4",
-                      "from": "readable-stream@>=2.0.0 <3.0.0"
-                    }
-                  }
-                },
-                "glob-stream": {
-                  "version": "4.1.1",
-                  "from": "glob-stream@>=4.0.1 <5.0.0",
-                  "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-4.1.1.tgz",
-                  "dependencies": {
-                    "glob": {
-                      "version": "4.5.3",
-                      "from": "glob@>=4.3.1 <5.0.0",
-                      "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz",
-                      "dependencies": {
-                        "inflight": {
-                          "version": "1.0.4",
-                          "from": "inflight@>=1.0.4 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz",
-                          "dependencies": {
-                            "wrappy": {
-                              "version": "1.0.1",
-                              "from": "wrappy@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
-                            }
-                          }
-                        },
-                        "inherits": {
-                          "version": "2.0.1",
-                          "from": "inherits@>=2.0.0 <3.0.0",
-                          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                        },
-                        "once": {
-                          "version": "1.3.2",
-                          "from": "once@>=1.3.0 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz",
-                          "dependencies": {
-                            "wrappy": {
-                              "version": "1.0.1",
-                              "from": "wrappy@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
-                            }
-                          }
-                        }
-                      }
+                    "end-of-stream": {
+                      "version": "1.0.0",
+                      "from": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz",
+                      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz"
                     },
-                    "minimatch": {
-                      "version": "2.0.10",
-                      "from": "minimatch@>=2.0.1 <3.0.0",
-                      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz",
-                      "dependencies": {
-                        "brace-expansion": {
-                          "version": "1.1.1",
-                          "from": "brace-expansion@>=1.0.0 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz",
-                          "dependencies": {
-                            "balanced-match": {
-                              "version": "0.2.0",
-                              "from": "balanced-match@>=0.2.0 <0.3.0",
-                              "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.0.tgz"
-                            },
-                            "concat-map": {
-                              "version": "0.0.1",
-                              "from": "concat-map@0.0.1",
-                              "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
-                            }
-                          }
-                        }
-                      }
+                    "readable-stream": {
+                      "version": "2.0.4",
+                      "from": "readable-stream@2.0.4",
+                      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.4.tgz"
+                    }
+                  }
+                },
+                "glob-stream": {
+                  "version": "4.1.1",
+                  "from": "https://registry.npmjs.org/glob-stream/-/glob-stream-4.1.1.tgz",
+                  "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-4.1.1.tgz",
+                  "dependencies": {
+                    "glob": {
+                      "version": "4.5.3",
+                      "from": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz",
+                      "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz"
                     },
                     "ordered-read-streams": {
                       "version": "0.1.0",
-                      "from": "ordered-read-streams@>=0.1.0 <0.2.0",
+                      "from": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz",
                       "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz"
                     },
                     "glob2base": {
                       "version": "0.0.12",
-                      "from": "glob2base@>=0.0.12 <0.0.13",
+                      "from": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz",
                       "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz",
                       "dependencies": {
                         "find-index": {
                           "version": "0.1.1",
-                          "from": "find-index@>=0.1.1 <0.2.0",
+                          "from": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz",
                           "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz"
                         }
                       }
                     },
                     "unique-stream": {
                       "version": "2.2.0",
-                      "from": "unique-stream@>=2.0.2 <3.0.0",
+                      "from": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.2.0.tgz",
                       "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.2.0.tgz",
                       "dependencies": {
                         "through2-filter": {
                           "version": "2.0.0",
-                          "from": "through2-filter@>=2.0.0 <3.0.0",
+                          "from": "https://registry.npmjs.org/through2-filter/-/through2-filter-2.0.0.tgz",
                           "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-2.0.0.tgz",
                           "dependencies": {
                             "through2": {
                               "version": "2.0.0",
-                              "from": "through2@>=2.0.0 <2.1.0",
+                              "from": "https://registry.npmjs.org/through2/-/through2-2.0.0.tgz",
                               "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.0.tgz",
                               "dependencies": {
                                 "readable-stream": {
                                   "version": "2.0.4",
-                                  "from": "readable-stream@>=2.0.0 <2.1.0"
+                                  "from": "readable-stream@2.0.4",
+                                  "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.4.tgz"
                                 }
                               }
                             },
                             "xtend": {
                               "version": "4.0.0",
-                              "from": "xtend@>=4.0.0 <4.1.0",
+                              "from": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz",
                               "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz"
                             }
                           }
@@ -7784,54 +5845,54 @@
                 },
                 "glob-watcher": {
                   "version": "0.0.8",
-                  "from": "glob-watcher@>=0.0.8 <0.0.9",
+                  "from": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-0.0.8.tgz",
                   "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-0.0.8.tgz",
                   "dependencies": {
                     "gaze": {
                       "version": "0.5.2",
-                      "from": "gaze@>=0.5.1 <0.6.0",
+                      "from": "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz",
                       "resolved": "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz",
                       "dependencies": {
                         "globule": {
                           "version": "0.1.0",
-                          "from": "globule@>=0.1.0 <0.2.0",
+                          "from": "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz",
                           "resolved": "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz",
                           "dependencies": {
                             "lodash": {
                               "version": "1.0.2",
-                              "from": "lodash@>=1.0.1 <1.1.0",
+                              "from": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz",
                               "resolved": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz"
                             },
                             "glob": {
                               "version": "3.1.21",
-                              "from": "glob@>=3.1.21 <3.2.0",
+                              "from": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz",
                               "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz",
                               "dependencies": {
                                 "graceful-fs": {
                                   "version": "1.2.3",
-                                  "from": "graceful-fs@>=1.2.0 <1.3.0",
+                                  "from": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz",
                                   "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz"
                                 },
                                 "inherits": {
                                   "version": "1.0.2",
-                                  "from": "inherits@>=1.0.0 <2.0.0",
+                                  "from": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz",
                                   "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz"
                                 }
                               }
                             },
                             "minimatch": {
                               "version": "0.2.14",
-                              "from": "minimatch@>=0.2.11 <0.3.0",
+                              "from": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz",
                               "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz",
                               "dependencies": {
                                 "lru-cache": {
                                   "version": "2.7.0",
-                                  "from": "lru-cache@>=2.0.0 <3.0.0",
+                                  "from": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.0.tgz",
                                   "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.0.tgz"
                                 },
                                 "sigmund": {
                                   "version": "1.0.1",
-                                  "from": "sigmund@>=1.0.0 <1.1.0",
+                                  "from": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
                                   "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz"
                                 }
                               }
@@ -7844,89 +5905,57 @@
                 },
                 "graceful-fs": {
                   "version": "3.0.8",
-                  "from": "graceful-fs@>=3.0.0 <4.0.0",
+                  "from": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.8.tgz",
                   "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.8.tgz"
                 },
                 "merge-stream": {
                   "version": "0.1.8",
-                  "from": "merge-stream@>=0.1.7 <0.2.0",
+                  "from": "https://registry.npmjs.org/merge-stream/-/merge-stream-0.1.8.tgz",
                   "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-0.1.8.tgz"
                 },
                 "object-assign": {
                   "version": "2.1.1",
-                  "from": "object-assign@>=2.0.0 <3.0.0",
+                  "from": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz",
                   "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz"
                 },
                 "strip-bom": {
                   "version": "1.0.0",
-                  "from": "strip-bom@>=1.0.0 <2.0.0",
+                  "from": "https://registry.npmjs.org/strip-bom/-/strip-bom-1.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-1.0.0.tgz",
                   "dependencies": {
                     "first-chunk-stream": {
                       "version": "1.0.0",
-                      "from": "first-chunk-stream@>=1.0.0 <2.0.0",
+                      "from": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz",
                       "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz"
-                    },
-                    "is-utf8": {
-                      "version": "0.2.0",
-                      "from": "is-utf8@>=0.2.0 <0.3.0",
-                      "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.0.tgz"
                     }
                   }
                 },
                 "through2": {
                   "version": "0.6.5",
-                  "from": "through2@>=0.6.1 <0.7.0",
+                  "from": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
                   "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
                   "dependencies": {
                     "readable-stream": {
                       "version": "1.0.33",
-                      "from": "readable-stream@>=1.0.33-1 <1.1.0-0",
-                      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz",
-                      "dependencies": {
-                        "core-util-is": {
-                          "version": "1.0.1",
-                          "from": "core-util-is@>=1.0.0 <1.1.0",
-                          "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-                        },
-                        "isarray": {
-                          "version": "0.0.1",
-                          "from": "isarray@0.0.1",
-                          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
-                        },
-                        "string_decoder": {
-                          "version": "0.10.31",
-                          "from": "string_decoder@>=0.10.0 <0.11.0",
-                          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
-                        },
-                        "inherits": {
-                          "version": "2.0.1",
-                          "from": "inherits@>=2.0.1 <2.1.0",
-                          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                        }
-                      }
+                      "from": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz",
+                      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz"
                     },
                     "xtend": {
                       "version": "4.0.0",
-                      "from": "xtend@>=4.0.0 <4.1.0-0",
+                      "from": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz",
                       "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz"
                     }
                   }
                 },
                 "vinyl": {
                   "version": "0.4.6",
-                  "from": "vinyl@>=0.4.0 <0.5.0",
+                  "from": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz",
                   "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz",
                   "dependencies": {
                     "clone": {
                       "version": "0.2.0",
-                      "from": "clone@>=0.2.0 <0.3.0",
+                      "from": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz",
                       "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz"
-                    },
-                    "clone-stats": {
-                      "version": "0.0.1",
-                      "from": "clone-stats@>=0.0.1 <0.0.2",
-                      "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz"
                     }
                   }
                 }
@@ -7934,17 +5963,17 @@
             },
             "ware": {
               "version": "1.3.0",
-              "from": "ware@>=1.2.0 <2.0.0",
+              "from": "https://registry.npmjs.org/ware/-/ware-1.3.0.tgz",
               "resolved": "https://registry.npmjs.org/ware/-/ware-1.3.0.tgz",
               "dependencies": {
                 "wrap-fn": {
                   "version": "0.1.4",
-                  "from": "wrap-fn@>=0.1.0 <0.2.0",
+                  "from": "https://registry.npmjs.org/wrap-fn/-/wrap-fn-0.1.4.tgz",
                   "resolved": "https://registry.npmjs.org/wrap-fn/-/wrap-fn-0.1.4.tgz",
                   "dependencies": {
                     "co": {
                       "version": "3.1.0",
-                      "from": "co@3.1.0",
+                      "from": "https://registry.npmjs.org/co/-/co-3.1.0.tgz",
                       "resolved": "https://registry.npmjs.org/co/-/co-3.1.0.tgz"
                     }
                   }
@@ -7955,589 +5984,118 @@
         },
         "findup-sync": {
           "version": "0.2.1",
-          "from": "findup-sync@>=0.2.1 <0.3.0",
+          "from": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.2.1.tgz",
           "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.2.1.tgz",
           "dependencies": {
             "glob": {
               "version": "4.3.5",
-              "from": "glob@>=4.3.0 <4.4.0",
-              "resolved": "https://registry.npmjs.org/glob/-/glob-4.3.5.tgz",
-              "dependencies": {
-                "inflight": {
-                  "version": "1.0.4",
-                  "from": "inflight@>=1.0.4 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz",
-                  "dependencies": {
-                    "wrappy": {
-                      "version": "1.0.1",
-                      "from": "wrappy@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
-                    }
-                  }
-                },
-                "inherits": {
-                  "version": "2.0.1",
-                  "from": "inherits@>=2.0.0 <3.0.0",
-                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                },
-                "minimatch": {
-                  "version": "2.0.10",
-                  "from": "minimatch@>=2.0.1 <3.0.0",
-                  "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz",
-                  "dependencies": {
-                    "brace-expansion": {
-                      "version": "1.1.1",
-                      "from": "brace-expansion@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz",
-                      "dependencies": {
-                        "balanced-match": {
-                          "version": "0.2.0",
-                          "from": "balanced-match@>=0.2.0 <0.3.0",
-                          "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.0.tgz"
-                        },
-                        "concat-map": {
-                          "version": "0.0.1",
-                          "from": "concat-map@0.0.1",
-                          "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
-                        }
-                      }
-                    }
-                  }
-                },
-                "once": {
-                  "version": "1.3.2",
-                  "from": "once@>=1.3.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz",
-                  "dependencies": {
-                    "wrappy": {
-                      "version": "1.0.1",
-                      "from": "wrappy@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
-                    }
-                  }
-                }
-              }
+              "from": "https://registry.npmjs.org/glob/-/glob-4.3.5.tgz",
+              "resolved": "https://registry.npmjs.org/glob/-/glob-4.3.5.tgz"
             }
           }
         },
         "github-username": {
           "version": "2.0.0",
-          "from": "github-username@>=2.0.0 <3.0.0",
+          "from": "https://registry.npmjs.org/github-username/-/github-username-2.0.0.tgz",
           "resolved": "https://registry.npmjs.org/github-username/-/github-username-2.0.0.tgz",
           "dependencies": {
             "gh-got": {
               "version": "1.1.0",
-              "from": "gh-got@>=1.0.3 <2.0.0",
+              "from": "https://registry.npmjs.org/gh-got/-/gh-got-1.1.0.tgz",
               "resolved": "https://registry.npmjs.org/gh-got/-/gh-got-1.1.0.tgz",
               "dependencies": {
                 "got": {
                   "version": "3.3.1",
-                  "from": "got@>=3.2.0 <4.0.0",
+                  "from": "https://registry.npmjs.org/got/-/got-3.3.1.tgz",
                   "resolved": "https://registry.npmjs.org/got/-/got-3.3.1.tgz",
                   "dependencies": {
                     "duplexify": {
                       "version": "3.4.2",
-                      "from": "duplexify@>=3.2.0 <4.0.0",
+                      "from": "https://registry.npmjs.org/duplexify/-/duplexify-3.4.2.tgz",
                       "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.4.2.tgz",
                       "dependencies": {
                         "end-of-stream": {
                           "version": "1.0.0",
-                          "from": "end-of-stream@1.0.0",
-                          "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz",
-                          "dependencies": {
-                            "once": {
-                              "version": "1.3.2",
-                              "from": "once@>=1.3.0 <1.4.0",
-                              "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz",
-                              "dependencies": {
-                                "wrappy": {
-                                  "version": "1.0.1",
-                                  "from": "wrappy@>=1.0.0 <2.0.0",
-                                  "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
-                                }
-                              }
-                            }
-                          }
+                          "from": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz",
+                          "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz"
                         },
                         "readable-stream": {
                           "version": "2.0.2",
-                          "from": "readable-stream@>=2.0.0 <3.0.0",
-                          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz",
-                          "dependencies": {
-                            "core-util-is": {
-                              "version": "1.0.1",
-                              "from": "core-util-is@>=1.0.0 <1.1.0",
-                              "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-                            },
-                            "inherits": {
-                              "version": "2.0.1",
-                              "from": "inherits@>=2.0.1 <2.1.0",
-                              "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                            },
-                            "isarray": {
-                              "version": "0.0.1",
-                              "from": "isarray@0.0.1",
-                              "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
-                            },
-                            "process-nextick-args": {
-                              "version": "1.0.3",
-                              "from": "process-nextick-args@>=1.0.0 <1.1.0",
-                              "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.3.tgz"
-                            },
-                            "string_decoder": {
-                              "version": "0.10.31",
-                              "from": "string_decoder@>=0.10.0 <0.11.0",
-                              "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
-                            },
-                            "util-deprecate": {
-                              "version": "1.0.2",
-                              "from": "util-deprecate@>=1.0.1 <1.1.0",
-                              "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
-                            }
-                          }
+                          "from": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz",
+                          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz"
                         }
                       }
                     },
                     "infinity-agent": {
                       "version": "2.0.3",
-                      "from": "infinity-agent@>=2.0.0 <3.0.0",
+                      "from": "https://registry.npmjs.org/infinity-agent/-/infinity-agent-2.0.3.tgz",
                       "resolved": "https://registry.npmjs.org/infinity-agent/-/infinity-agent-2.0.3.tgz"
                     },
                     "is-redirect": {
                       "version": "1.0.0",
-                      "from": "is-redirect@>=1.0.0 <2.0.0",
+                      "from": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz",
                       "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz"
                     },
                     "is-stream": {
                       "version": "1.0.1",
-                      "from": "is-stream@>=1.0.0 <2.0.0",
+                      "from": "https://registry.npmjs.org/is-stream/-/is-stream-1.0.1.tgz",
                       "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.0.1.tgz"
                     },
                     "lowercase-keys": {
                       "version": "1.0.0",
-                      "from": "lowercase-keys@>=1.0.0 <2.0.0",
+                      "from": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz",
                       "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz"
                     },
                     "nested-error-stacks": {
                       "version": "1.0.1",
-                      "from": "nested-error-stacks@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-1.0.1.tgz",
-                      "dependencies": {
-                        "inherits": {
-                          "version": "2.0.1",
-                          "from": "inherits@>=2.0.1 <2.1.0",
-                          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                        }
-                      }
+                      "from": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-1.0.1.tgz",
+                      "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-1.0.1.tgz"
                     },
                     "object-assign": {
                       "version": "3.0.0",
-                      "from": "object-assign@>=3.0.0 <4.0.0",
+                      "from": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
                       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz"
                     },
                     "prepend-http": {
                       "version": "1.0.3",
-                      "from": "prepend-http@>=1.0.0 <2.0.0",
+                      "from": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.3.tgz",
                       "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.3.tgz"
                     },
-                    "read-all-stream": {
-                      "version": "3.0.1",
-                      "from": "read-all-stream@>=3.0.0 <4.0.0",
-                      "resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.0.1.tgz",
-                      "dependencies": {
-                        "pinkie-promise": {
-                          "version": "1.0.0",
-                          "from": "pinkie-promise@>=1.0.0 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz",
-                          "dependencies": {
-                            "pinkie": {
-                              "version": "1.0.0",
-                              "from": "pinkie@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
-                            }
-                          }
-                        },
-                        "readable-stream": {
-                          "version": "2.0.2",
-                          "from": "readable-stream@>=2.0.0 <3.0.0",
-                          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz",
-                          "dependencies": {
-                            "core-util-is": {
-                              "version": "1.0.1",
-                              "from": "core-util-is@>=1.0.0 <1.1.0",
-                              "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-                            },
-                            "inherits": {
-                              "version": "2.0.1",
-                              "from": "inherits@>=2.0.1 <2.1.0",
-                              "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                            },
-                            "isarray": {
-                              "version": "0.0.1",
-                              "from": "isarray@0.0.1",
-                              "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
-                            },
-                            "process-nextick-args": {
-                              "version": "1.0.3",
-                              "from": "process-nextick-args@>=1.0.0 <1.1.0",
-                              "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.3.tgz"
-                            },
-                            "string_decoder": {
-                              "version": "0.10.31",
-                              "from": "string_decoder@>=0.10.0 <0.11.0",
-                              "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
-                            },
-                            "util-deprecate": {
-                              "version": "1.0.2",
-                              "from": "util-deprecate@>=1.0.1 <1.1.0",
-                              "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
-                            }
-                          }
-                        }
-                      }
-                    },
-                    "timed-out": {
-                      "version": "2.0.0",
-                      "from": "timed-out@>=2.0.0 <3.0.0",
-                      "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz"
-                    }
-                  }
-                },
-                "object-assign": {
-                  "version": "2.1.1",
-                  "from": "object-assign@>=2.0.0 <3.0.0",
-                  "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz"
-                }
-              }
-            },
-            "meow": {
-              "version": "3.4.2",
-              "from": "meow@>=3.1.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/meow/-/meow-3.4.2.tgz",
-              "dependencies": {
-                "camelcase-keys": {
-                  "version": "1.0.0",
-                  "from": "camelcase-keys@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-1.0.0.tgz",
-                  "dependencies": {
-                    "camelcase": {
-                      "version": "1.2.1",
-                      "from": "camelcase@>=1.0.1 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz"
-                    },
-                    "map-obj": {
-                      "version": "1.0.1",
-                      "from": "map-obj@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz"
-                    }
-                  }
-                },
-                "loud-rejection": {
-                  "version": "1.0.0",
-                  "from": "loud-rejection@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.0.0.tgz"
-                },
-                "minimist": {
-                  "version": "1.2.0",
-                  "from": "minimist@>=1.1.3 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
-                },
-                "normalize-package-data": {
-                  "version": "2.3.4",
-                  "from": "normalize-package-data@>=2.3.4 <3.0.0",
-                  "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.4.tgz",
-                  "dependencies": {
-                    "hosted-git-info": {
-                      "version": "2.1.4",
-                      "from": "hosted-git-info@>=2.0.2 <3.0.0",
-                      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.4.tgz"
-                    },
-                    "is-builtin-module": {
-                      "version": "1.0.0",
-                      "from": "is-builtin-module@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
-                      "dependencies": {
-                        "builtin-modules": {
-                          "version": "1.1.0",
-                          "from": "builtin-modules@>=1.0.0 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.0.tgz"
-                        }
-                      }
-                    },
-                    "semver": {
-                      "version": "5.0.3",
-                      "from": "semver@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0||>=4.0.0 <5.0.0||>=5.0.0 <6.0.0"
-                    },
-                    "validate-npm-package-license": {
-                      "version": "3.0.1",
-                      "from": "validate-npm-package-license@>=3.0.1 <4.0.0",
-                      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz",
-                      "dependencies": {
-                        "spdx-correct": {
-                          "version": "1.0.1",
-                          "from": "spdx-correct@>=1.0.0 <1.1.0",
-                          "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.1.tgz",
-                          "dependencies": {
-                            "spdx-license-ids": {
-                              "version": "1.0.2",
-                              "from": "spdx-license-ids@>=1.0.2 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.0.2.tgz"
-                            }
-                          }
-                        },
-                        "spdx-expression-parse": {
-                          "version": "1.0.0",
-                          "from": "spdx-expression-parse@>=1.0.0 <1.1.0",
-                          "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.0.tgz",
-                          "dependencies": {
-                            "spdx-exceptions": {
-                              "version": "1.0.3",
-                              "from": "spdx-exceptions@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-1.0.3.tgz"
-                            },
-                            "spdx-license-ids": {
-                              "version": "1.0.2",
-                              "from": "spdx-license-ids@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.0.2.tgz"
-                            }
-                          }
-                        }
-                      }
-                    }
-                  }
-                },
-                "object-assign": {
-                  "version": "4.0.1",
-                  "from": "object-assign@>=4.0.1 <5.0.0",
-                  "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.0.1.tgz"
-                },
-                "read-pkg-up": {
-                  "version": "1.0.1",
-                  "from": "read-pkg-up@>=1.0.1 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
-                  "dependencies": {
-                    "find-up": {
-                      "version": "1.0.0",
-                      "from": "find-up@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.0.0.tgz",
-                      "dependencies": {
-                        "path-exists": {
-                          "version": "2.0.0",
-                          "from": "path-exists@>=2.0.0 <3.0.0",
-                          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.0.0.tgz"
-                        },
-                        "pinkie-promise": {
-                          "version": "1.0.0",
-                          "from": "pinkie-promise@>=1.0.0 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz",
-                          "dependencies": {
-                            "pinkie": {
-                              "version": "1.0.0",
-                              "from": "pinkie@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
-                            }
-                          }
-                        }
-                      }
-                    },
-                    "read-pkg": {
-                      "version": "1.1.0",
-                      "from": "read-pkg@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
-                      "dependencies": {
-                        "load-json-file": {
-                          "version": "1.0.1",
-                          "from": "load-json-file@>=1.0.0 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.0.1.tgz",
-                          "dependencies": {
-                            "graceful-fs": {
-                              "version": "4.1.2",
-                              "from": "graceful-fs@>=4.1.2 <5.0.0"
-                            },
-                            "parse-json": {
-                              "version": "2.2.0",
-                              "from": "parse-json@>=2.2.0 <3.0.0",
-                              "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
-                              "dependencies": {
-                                "error-ex": {
-                                  "version": "1.2.0",
-                                  "from": "error-ex@>=1.2.0 <2.0.0",
-                                  "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.2.0.tgz"
-                                }
-                              }
-                            },
-                            "pify": {
-                              "version": "2.2.0",
-                              "from": "pify@>=2.0.0 <3.0.0",
-                              "resolved": "https://registry.npmjs.org/pify/-/pify-2.2.0.tgz"
-                            },
-                            "pinkie-promise": {
-                              "version": "1.0.0",
-                              "from": "pinkie-promise@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz",
-                              "dependencies": {
-                                "pinkie": {
-                                  "version": "1.0.0",
-                                  "from": "pinkie@>=1.0.0 <2.0.0",
-                                  "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
-                                }
-                              }
-                            },
-                            "strip-bom": {
-                              "version": "2.0.0",
-                              "from": "strip-bom@>=2.0.0 <3.0.0",
-                              "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
-                              "dependencies": {
-                                "is-utf8": {
-                                  "version": "0.2.0",
-                                  "from": "is-utf8@>=0.2.0 <0.3.0",
-                                  "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.0.tgz"
-                                }
-                              }
-                            }
-                          }
-                        },
-                        "path-type": {
-                          "version": "1.0.0",
-                          "from": "path-type@>=1.0.0 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.0.0.tgz",
-                          "dependencies": {
-                            "graceful-fs": {
-                              "version": "4.1.2",
-                              "from": "graceful-fs@>=4.1.2 <5.0.0"
-                            },
-                            "pify": {
-                              "version": "2.2.0",
-                              "from": "pify@>=2.0.0 <3.0.0",
-                              "resolved": "https://registry.npmjs.org/pify/-/pify-2.2.0.tgz"
-                            },
-                            "pinkie-promise": {
-                              "version": "1.0.0",
-                              "from": "pinkie-promise@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz",
-                              "dependencies": {
-                                "pinkie": {
-                                  "version": "1.0.0",
-                                  "from": "pinkie@>=1.0.0 <2.0.0",
-                                  "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
-                                }
-                              }
-                            }
-                          }
-                        }
-                      }
-                    }
-                  }
-                },
-                "redent": {
-                  "version": "1.0.0",
-                  "from": "redent@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
-                  "dependencies": {
-                    "indent-string": {
-                      "version": "2.1.0",
-                      "from": "indent-string@>=2.1.0 <3.0.0",
-                      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
-                      "dependencies": {
-                        "repeating": {
-                          "version": "2.0.0",
-                          "from": "repeating@>=2.0.0 <3.0.0",
-                          "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.0.tgz",
-                          "dependencies": {
-                            "is-finite": {
-                              "version": "1.0.1",
-                              "from": "is-finite@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.1.tgz",
-                              "dependencies": {
-                                "number-is-nan": {
-                                  "version": "1.0.0",
-                                  "from": "number-is-nan@>=1.0.0 <2.0.0",
-                                  "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz"
-                                }
-                              }
-                            }
-                          }
-                        }
-                      }
-                    },
-                    "strip-indent": {
-                      "version": "1.0.1",
-                      "from": "strip-indent@>=1.0.1 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
-                      "dependencies": {
-                        "get-stdin": {
-                          "version": "4.0.1",
-                          "from": "get-stdin@>=4.0.1 <5.0.0",
-                          "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz"
-                        }
-                      }
-                    }
-                  }
-                },
-                "trim-newlines": {
-                  "version": "1.0.0",
-                  "from": "trim-newlines@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz"
-                }
-              }
-            }
-          }
-        },
-        "glob": {
-          "version": "5.0.15",
-          "from": "glob@>=5.0.3 <6.0.0",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
-          "dependencies": {
-            "inflight": {
-              "version": "1.0.4",
-              "from": "inflight@>=1.0.4 <2.0.0",
-              "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz",
-              "dependencies": {
-                "wrappy": {
-                  "version": "1.0.1",
-                  "from": "wrappy@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
-                }
-              }
-            },
-            "inherits": {
-              "version": "2.0.1",
-              "from": "inherits@>=2.0.0 <3.0.0",
-              "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-            },
-            "minimatch": {
-              "version": "3.0.0",
-              "from": "minimatch@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.0.tgz",
-              "dependencies": {
-                "brace-expansion": {
-                  "version": "1.1.1",
-                  "from": "brace-expansion@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz",
-                  "dependencies": {
-                    "balanced-match": {
-                      "version": "0.2.0",
-                      "from": "balanced-match@>=0.2.0 <0.3.0",
-                      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.0.tgz"
-                    },
-                    "concat-map": {
-                      "version": "0.0.1",
-                      "from": "concat-map@0.0.1",
-                      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
+                    "read-all-stream": {
+                      "version": "3.0.1",
+                      "from": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.0.1.tgz",
+                      "resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.0.1.tgz",
+                      "dependencies": {
+                        "readable-stream": {
+                          "version": "2.0.2",
+                          "from": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz",
+                          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz"
+                        }
+                      }
+                    },
+                    "timed-out": {
+                      "version": "2.0.0",
+                      "from": "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz",
+                      "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz"
                     }
                   }
+                },
+                "object-assign": {
+                  "version": "2.1.1",
+                  "from": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz",
+                  "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz"
                 }
               }
             },
-            "once": {
-              "version": "1.3.2",
-              "from": "once@>=1.3.0 <2.0.0",
-              "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz",
+            "meow": {
+              "version": "3.4.2",
+              "from": "https://registry.npmjs.org/meow/-/meow-3.4.2.tgz",
+              "resolved": "https://registry.npmjs.org/meow/-/meow-3.4.2.tgz",
               "dependencies": {
-                "wrappy": {
-                  "version": "1.0.1",
-                  "from": "wrappy@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
+                "normalize-package-data": {
+                  "version": "2.3.4",
+                  "from": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.4.tgz",
+                  "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.4.tgz"
                 }
               }
             }
@@ -8545,93 +6103,81 @@
         },
         "gruntfile-editor": {
           "version": "1.0.0",
-          "from": "gruntfile-editor@>=1.0.0 <2.0.0",
+          "from": "https://registry.npmjs.org/gruntfile-editor/-/gruntfile-editor-1.0.0.tgz",
           "resolved": "https://registry.npmjs.org/gruntfile-editor/-/gruntfile-editor-1.0.0.tgz",
           "dependencies": {
             "ast-query": {
               "version": "1.0.1",
-              "from": "ast-query@>=1.0.1 <2.0.0",
+              "from": "https://registry.npmjs.org/ast-query/-/ast-query-1.0.1.tgz",
               "resolved": "https://registry.npmjs.org/ast-query/-/ast-query-1.0.1.tgz",
               "dependencies": {
                 "escodegen": {
                   "version": "1.7.0",
-                  "from": "escodegen@>=1.6.0 <2.0.0",
+                  "from": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.0.tgz",
                   "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.0.tgz",
                   "dependencies": {
                     "estraverse": {
                       "version": "1.9.3",
-                      "from": "estraverse@>=1.9.1 <2.0.0",
+                      "from": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz",
                       "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz"
                     },
-                    "esutils": {
-                      "version": "2.0.2",
-                      "from": "esutils@>=2.0.2 <3.0.0",
-                      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz"
-                    },
                     "esprima": {
                       "version": "1.2.5",
-                      "from": "esprima@>=1.2.2 <2.0.0",
+                      "from": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz",
                       "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz"
                     },
                     "optionator": {
                       "version": "0.5.0",
-                      "from": "optionator@>=0.5.0 <0.6.0",
+                      "from": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz",
                       "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz",
                       "dependencies": {
                         "prelude-ls": {
                           "version": "1.1.2",
-                          "from": "prelude-ls@>=1.1.1 <1.2.0",
+                          "from": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
                           "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz"
                         },
                         "deep-is": {
                           "version": "0.1.3",
-                          "from": "deep-is@>=0.1.2 <0.2.0",
+                          "from": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
                           "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz"
                         },
                         "wordwrap": {
                           "version": "0.0.3",
-                          "from": "wordwrap@>=0.0.2 <0.1.0",
+                          "from": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
                           "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
                         },
                         "type-check": {
                           "version": "0.3.1",
-                          "from": "type-check@>=0.3.1 <0.4.0",
+                          "from": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz",
                           "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz"
                         },
                         "levn": {
                           "version": "0.2.5",
-                          "from": "levn@>=0.2.5 <0.3.0",
+                          "from": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz",
                           "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz"
                         },
                         "fast-levenshtein": {
                           "version": "1.0.7",
-                          "from": "fast-levenshtein@>=1.0.0 <1.1.0",
+                          "from": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz",
                           "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz"
                         }
                       }
                     },
                     "source-map": {
                       "version": "0.2.0",
-                      "from": "source-map@>=0.2.0 <0.3.0",
-                      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz",
-                      "dependencies": {
-                        "amdefine": {
-                          "version": "1.0.0",
-                          "from": "amdefine@>=0.0.4",
-                          "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz"
-                        }
-                      }
+                      "from": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz",
+                      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz"
                     }
                   }
                 },
                 "esprima": {
                   "version": "2.6.0",
-                  "from": "esprima@>=2.0.0 <3.0.0",
+                  "from": "https://registry.npmjs.org/esprima/-/esprima-2.6.0.tgz",
                   "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.6.0.tgz"
                 },
                 "traverse": {
                   "version": "0.6.6",
-                  "from": "traverse@>=0.6.6 <0.7.0",
+                  "from": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz",
                   "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz"
                 }
               }
@@ -8640,115 +6186,93 @@
         },
         "html-wiring": {
           "version": "1.2.0",
-          "from": "html-wiring@>=1.0.0 <2.0.0",
+          "from": "https://registry.npmjs.org/html-wiring/-/html-wiring-1.2.0.tgz",
           "resolved": "https://registry.npmjs.org/html-wiring/-/html-wiring-1.2.0.tgz",
           "dependencies": {
             "cheerio": {
               "version": "0.19.0",
-              "from": "cheerio@>=0.19.0 <0.20.0",
+              "from": "https://registry.npmjs.org/cheerio/-/cheerio-0.19.0.tgz",
               "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.19.0.tgz",
               "dependencies": {
                 "css-select": {
                   "version": "1.0.0",
-                  "from": "css-select@>=1.0.0 <1.1.0",
+                  "from": "https://registry.npmjs.org/css-select/-/css-select-1.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.0.0.tgz",
                   "dependencies": {
                     "css-what": {
                       "version": "1.0.0",
-                      "from": "css-what@>=1.0.0 <1.1.0",
+                      "from": "https://registry.npmjs.org/css-what/-/css-what-1.0.0.tgz",
                       "resolved": "https://registry.npmjs.org/css-what/-/css-what-1.0.0.tgz"
                     },
                     "domutils": {
                       "version": "1.4.3",
-                      "from": "domutils@>=1.4.0 <1.5.0",
+                      "from": "https://registry.npmjs.org/domutils/-/domutils-1.4.3.tgz",
                       "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.4.3.tgz",
                       "dependencies": {
                         "domelementtype": {
                           "version": "1.3.0",
-                          "from": "domelementtype@>=1.0.0 <2.0.0",
+                          "from": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz",
                           "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz"
                         }
                       }
                     },
                     "boolbase": {
                       "version": "1.0.0",
-                      "from": "boolbase@>=1.0.0 <1.1.0",
+                      "from": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
                       "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz"
                     },
                     "nth-check": {
                       "version": "1.0.1",
-                      "from": "nth-check@>=1.0.0 <1.1.0",
+                      "from": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz",
                       "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz"
                     }
                   }
                 },
                 "entities": {
                   "version": "1.1.1",
-                  "from": "entities@>=1.1.1 <1.2.0",
+                  "from": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz",
                   "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz"
                 },
                 "htmlparser2": {
                   "version": "3.8.3",
-                  "from": "htmlparser2@>=3.8.1 <3.9.0",
+                  "from": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz",
                   "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz",
                   "dependencies": {
                     "domhandler": {
                       "version": "2.3.0",
-                      "from": "domhandler@>=2.3.0 <2.4.0",
+                      "from": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz",
                       "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz"
                     },
                     "domutils": {
                       "version": "1.5.1",
-                      "from": "domutils@>=1.5.0 <1.6.0",
+                      "from": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
                       "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz"
                     },
                     "domelementtype": {
                       "version": "1.3.0",
-                      "from": "domelementtype@>=1.0.0 <2.0.0",
+                      "from": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz",
                       "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz"
                     },
                     "readable-stream": {
                       "version": "1.1.13",
-                      "from": "readable-stream@>=1.1.0 <1.2.0",
-                      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz",
-                      "dependencies": {
-                        "core-util-is": {
-                          "version": "1.0.1",
-                          "from": "core-util-is@>=1.0.0 <1.1.0",
-                          "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-                        },
-                        "isarray": {
-                          "version": "0.0.1",
-                          "from": "isarray@0.0.1",
-                          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
-                        },
-                        "string_decoder": {
-                          "version": "0.10.31",
-                          "from": "string_decoder@>=0.10.0 <0.11.0",
-                          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
-                        },
-                        "inherits": {
-                          "version": "2.0.1",
-                          "from": "inherits@>=2.0.1 <2.1.0",
-                          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                        }
-                      }
+                      "from": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz",
+                      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz"
                     },
                     "entities": {
                       "version": "1.0.0",
-                      "from": "entities@>=1.0.0 <1.1.0",
+                      "from": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz",
                       "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz"
                     }
                   }
                 },
                 "dom-serializer": {
                   "version": "0.1.0",
-                  "from": "dom-serializer@>=0.1.0 <0.2.0",
+                  "from": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
                   "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
                   "dependencies": {
                     "domelementtype": {
                       "version": "1.1.3",
-                      "from": "domelementtype@>=1.1.1 <1.2.0",
+                      "from": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz",
                       "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz"
                     }
                   }
@@ -8757,200 +6281,113 @@
             },
             "detect-newline": {
               "version": "1.0.3",
-              "from": "detect-newline@>=1.0.3 <2.0.0",
-              "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-1.0.3.tgz",
-              "dependencies": {
-                "get-stdin": {
-                  "version": "4.0.1",
-                  "from": "get-stdin@>=4.0.1 <5.0.0",
-                  "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz"
-                },
-                "minimist": {
-                  "version": "1.2.0",
-                  "from": "minimist@>=1.1.3 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
-                }
-              }
+              "from": "https://registry.npmjs.org/detect-newline/-/detect-newline-1.0.3.tgz",
+              "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-1.0.3.tgz"
             }
           }
         },
         "inquirer": {
           "version": "0.8.5",
-          "from": "inquirer@>=0.8.0 <0.9.0",
+          "from": "https://registry.npmjs.org/inquirer/-/inquirer-0.8.5.tgz",
           "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.8.5.tgz",
           "dependencies": {
             "ansi-regex": {
               "version": "1.1.1",
-              "from": "ansi-regex@>=1.1.1 <2.0.0",
+              "from": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz",
               "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz"
             },
             "cli-width": {
               "version": "1.0.1",
-              "from": "cli-width@>=1.0.1 <2.0.0",
+              "from": "https://registry.npmjs.org/cli-width/-/cli-width-1.0.1.tgz",
               "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-1.0.1.tgz"
             },
             "figures": {
               "version": "1.4.0",
-              "from": "figures@>=1.3.5 <2.0.0",
+              "from": "https://registry.npmjs.org/figures/-/figures-1.4.0.tgz",
               "resolved": "https://registry.npmjs.org/figures/-/figures-1.4.0.tgz"
             },
             "readline2": {
               "version": "0.1.1",
-              "from": "readline2@>=0.1.1 <0.2.0",
+              "from": "https://registry.npmjs.org/readline2/-/readline2-0.1.1.tgz",
               "resolved": "https://registry.npmjs.org/readline2/-/readline2-0.1.1.tgz",
               "dependencies": {
                 "mute-stream": {
                   "version": "0.0.4",
-                  "from": "mute-stream@0.0.4",
+                  "from": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.4.tgz",
                   "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.4.tgz"
                 },
                 "strip-ansi": {
                   "version": "2.0.1",
-                  "from": "strip-ansi@>=2.0.1 <3.0.0",
+                  "from": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz",
                   "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz"
                 }
               }
             },
             "rx": {
               "version": "2.5.3",
-              "from": "rx@>=2.4.3 <3.0.0",
+              "from": "https://registry.npmjs.org/rx/-/rx-2.5.3.tgz",
               "resolved": "https://registry.npmjs.org/rx/-/rx-2.5.3.tgz"
-            },
-            "through": {
-              "version": "2.3.8",
-              "from": "through@>=2.3.6 <3.0.0",
-              "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
             }
           }
         },
         "istextorbinary": {
           "version": "1.0.2",
-          "from": "istextorbinary@>=1.0.2 <2.0.0",
+          "from": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-1.0.2.tgz",
           "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-1.0.2.tgz",
           "dependencies": {
             "textextensions": {
               "version": "1.0.1",
-              "from": "textextensions@>=1.0.0 <1.1.0",
+              "from": "https://registry.npmjs.org/textextensions/-/textextensions-1.0.1.tgz",
               "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-1.0.1.tgz"
             },
             "binaryextensions": {
               "version": "1.0.0",
-              "from": "binaryextensions@>=1.0.0 <1.1.0",
+              "from": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-1.0.0.tgz",
               "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-1.0.0.tgz"
             }
           }
         },
-        "lodash": {
-          "version": "3.10.1",
-          "from": "lodash@>=3.5.0 <4.0.0",
-          "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz"
-        },
         "mem-fs-editor": {
           "version": "2.0.4",
-          "from": "mem-fs-editor@>=2.0.0 <3.0.0",
+          "from": "https://registry.npmjs.org/mem-fs-editor/-/mem-fs-editor-2.0.4.tgz",
           "resolved": "https://registry.npmjs.org/mem-fs-editor/-/mem-fs-editor-2.0.4.tgz",
           "dependencies": {
             "commondir": {
               "version": "1.0.1",
-              "from": "commondir@>=1.0.1 <2.0.0",
+              "from": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
               "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz"
             },
             "ejs": {
               "version": "2.3.4",
-              "from": "ejs@>=2.3.1 <3.0.0",
+              "from": "https://registry.npmjs.org/ejs/-/ejs-2.3.4.tgz",
               "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.3.4.tgz"
             },
             "globby": {
               "version": "2.1.0",
-              "from": "globby@>=2.0.0 <3.0.0",
+              "from": "https://registry.npmjs.org/globby/-/globby-2.1.0.tgz",
               "resolved": "https://registry.npmjs.org/globby/-/globby-2.1.0.tgz",
               "dependencies": {
                 "array-union": {
                   "version": "1.0.1",
-                  "from": "array-union@>=1.0.1 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.1.tgz",
-                  "dependencies": {
-                    "array-uniq": {
-                      "version": "1.0.2",
-                      "from": "array-uniq@>=1.0.1 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.2.tgz"
-                    }
-                  }
+                  "from": "https://registry.npmjs.org/array-union/-/array-union-1.0.1.tgz",
+                  "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.1.tgz"
                 },
                 "object-assign": {
                   "version": "3.0.0",
-                  "from": "object-assign@>=3.0.0 <4.0.0",
+                  "from": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
                   "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz"
                 }
               }
             },
             "multimatch": {
               "version": "2.0.0",
-              "from": "multimatch@>=2.0.0 <3.0.0",
+              "from": "https://registry.npmjs.org/multimatch/-/multimatch-2.0.0.tgz",
               "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.0.0.tgz",
               "dependencies": {
-                "array-differ": {
-                  "version": "1.0.0",
-                  "from": "array-differ@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz"
-                },
                 "array-union": {
                   "version": "1.0.1",
-                  "from": "array-union@>=1.0.1 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.1.tgz",
-                  "dependencies": {
-                    "array-uniq": {
-                      "version": "1.0.2",
-                      "from": "array-uniq@>=1.0.1 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.2.tgz"
-                    }
-                  }
-                },
-                "minimatch": {
-                  "version": "2.0.10",
-                  "from": "minimatch@>=2.0.1 <3.0.0",
-                  "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz",
-                  "dependencies": {
-                    "brace-expansion": {
-                      "version": "1.1.1",
-                      "from": "brace-expansion@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz",
-                      "dependencies": {
-                        "balanced-match": {
-                          "version": "0.2.0",
-                          "from": "balanced-match@>=0.2.0 <0.3.0",
-                          "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.0.tgz"
-                        },
-                        "concat-map": {
-                          "version": "0.0.1",
-                          "from": "concat-map@0.0.1",
-                          "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
-                        }
-                      }
-                    }
-                  }
-                }
-              }
-            },
-            "vinyl": {
-              "version": "0.5.3",
-              "from": "vinyl@>=0.5.0 <0.6.0",
-              "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz",
-              "dependencies": {
-                "clone": {
-                  "version": "1.0.2",
-                  "from": "clone@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz"
-                },
-                "clone-stats": {
-                  "version": "0.0.1",
-                  "from": "clone-stats@>=0.0.1 <0.0.2",
-                  "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz"
-                },
-                "replace-ext": {
-                  "version": "0.0.1",
-                  "from": "replace-ext@0.0.1",
-                  "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz"
+                  "from": "https://registry.npmjs.org/array-union/-/array-union-1.0.1.tgz",
+                  "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.1.tgz"
                 }
               }
             }
@@ -8958,476 +6395,129 @@
         },
         "mime": {
           "version": "1.3.4",
-          "from": "mime@>=1.2.9 <2.0.0",
+          "from": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz",
           "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz"
         },
-        "mkdirp": {
-          "version": "0.5.1",
-          "from": "mkdirp@>=0.5.0 <0.6.0",
-          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
-          "dependencies": {
-            "minimist": {
-              "version": "0.0.8",
-              "from": "minimist@0.0.8",
-              "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
-            }
-          }
-        },
         "nopt": {
           "version": "3.0.4",
-          "from": "nopt@>=3.0.0 <4.0.0",
+          "from": "https://registry.npmjs.org/nopt/-/nopt-3.0.4.tgz",
           "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.4.tgz",
           "dependencies": {
             "abbrev": {
               "version": "1.0.7",
-              "from": "abbrev@>=1.0.0 <2.0.0",
+              "from": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz",
               "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz"
             }
           }
         },
-        "path-exists": {
-          "version": "1.0.0",
-          "from": "path-exists@>=1.0.0 <2.0.0",
-          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz"
-        },
-        "path-is-absolute": {
-          "version": "1.0.0",
-          "from": "path-is-absolute@>=1.0.0 <2.0.0",
-          "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz"
-        },
         "pretty-bytes": {
           "version": "2.0.1",
-          "from": "pretty-bytes@>=2.0.1 <3.0.0",
+          "from": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-2.0.1.tgz",
           "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-2.0.1.tgz",
           "dependencies": {
-            "get-stdin": {
-              "version": "4.0.1",
-              "from": "get-stdin@>=4.0.1 <5.0.0",
-              "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz"
-            },
             "meow": {
               "version": "3.4.2",
-              "from": "meow@>=3.1.0 <4.0.0",
+              "from": "https://registry.npmjs.org/meow/-/meow-3.4.2.tgz",
               "resolved": "https://registry.npmjs.org/meow/-/meow-3.4.2.tgz",
               "dependencies": {
-                "camelcase-keys": {
-                  "version": "1.0.0",
-                  "from": "camelcase-keys@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-1.0.0.tgz",
-                  "dependencies": {
-                    "camelcase": {
-                      "version": "1.2.1",
-                      "from": "camelcase@>=1.0.1 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz"
-                    },
-                    "map-obj": {
-                      "version": "1.0.1",
-                      "from": "map-obj@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz"
-                    }
-                  }
-                },
-                "loud-rejection": {
-                  "version": "1.0.0",
-                  "from": "loud-rejection@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.0.0.tgz"
-                },
-                "minimist": {
-                  "version": "1.2.0",
-                  "from": "minimist@>=1.1.3 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
-                },
                 "normalize-package-data": {
                   "version": "2.3.4",
-                  "from": "normalize-package-data@>=2.3.4 <3.0.0",
-                  "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.4.tgz",
-                  "dependencies": {
-                    "hosted-git-info": {
-                      "version": "2.1.4",
-                      "from": "hosted-git-info@>=2.0.2 <3.0.0",
-                      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.4.tgz"
-                    },
-                    "is-builtin-module": {
-                      "version": "1.0.0",
-                      "from": "is-builtin-module@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
-                      "dependencies": {
-                        "builtin-modules": {
-                          "version": "1.1.0",
-                          "from": "builtin-modules@>=1.0.0 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.0.tgz"
-                        }
-                      }
-                    },
-                    "semver": {
-                      "version": "5.0.3",
-                      "from": "semver@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0||>=4.0.0 <5.0.0||>=5.0.0 <6.0.0"
-                    },
-                    "validate-npm-package-license": {
-                      "version": "3.0.1",
-                      "from": "validate-npm-package-license@>=3.0.1 <4.0.0",
-                      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz",
-                      "dependencies": {
-                        "spdx-correct": {
-                          "version": "1.0.1",
-                          "from": "spdx-correct@>=1.0.0 <1.1.0",
-                          "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.1.tgz",
-                          "dependencies": {
-                            "spdx-license-ids": {
-                              "version": "1.0.2",
-                              "from": "spdx-license-ids@>=1.0.2 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.0.2.tgz"
-                            }
-                          }
-                        },
-                        "spdx-expression-parse": {
-                          "version": "1.0.0",
-                          "from": "spdx-expression-parse@>=1.0.0 <1.1.0",
-                          "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.0.tgz",
-                          "dependencies": {
-                            "spdx-exceptions": {
-                              "version": "1.0.3",
-                              "from": "spdx-exceptions@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-1.0.3.tgz"
-                            },
-                            "spdx-license-ids": {
-                              "version": "1.0.2",
-                              "from": "spdx-license-ids@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.0.2.tgz"
-                            }
-                          }
-                        }
-                      }
-                    }
-                  }
-                },
-                "object-assign": {
-                  "version": "4.0.1",
-                  "from": "object-assign@>=4.0.1 <5.0.0",
-                  "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.0.1.tgz"
-                },
-                "read-pkg-up": {
-                  "version": "1.0.1",
-                  "from": "read-pkg-up@>=1.0.1 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
-                  "dependencies": {
-                    "find-up": {
-                      "version": "1.0.0",
-                      "from": "find-up@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.0.0.tgz",
-                      "dependencies": {
-                        "path-exists": {
-                          "version": "2.0.0",
-                          "from": "path-exists@>=2.0.0 <3.0.0",
-                          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.0.0.tgz"
-                        },
-                        "pinkie-promise": {
-                          "version": "1.0.0",
-                          "from": "pinkie-promise@>=1.0.0 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz",
-                          "dependencies": {
-                            "pinkie": {
-                              "version": "1.0.0",
-                              "from": "pinkie@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
-                            }
-                          }
-                        }
-                      }
-                    },
-                    "read-pkg": {
-                      "version": "1.1.0",
-                      "from": "read-pkg@>=1.0.0 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
-                      "dependencies": {
-                        "load-json-file": {
-                          "version": "1.0.1",
-                          "from": "load-json-file@>=1.0.0 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.0.1.tgz",
-                          "dependencies": {
-                            "graceful-fs": {
-                              "version": "4.1.2",
-                              "from": "graceful-fs@>=4.1.2 <5.0.0"
-                            },
-                            "parse-json": {
-                              "version": "2.2.0",
-                              "from": "parse-json@>=2.2.0 <3.0.0",
-                              "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
-                              "dependencies": {
-                                "error-ex": {
-                                  "version": "1.2.0",
-                                  "from": "error-ex@>=1.2.0 <2.0.0",
-                                  "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.2.0.tgz"
-                                }
-                              }
-                            },
-                            "pify": {
-                              "version": "2.2.0",
-                              "from": "pify@>=2.0.0 <3.0.0",
-                              "resolved": "https://registry.npmjs.org/pify/-/pify-2.2.0.tgz"
-                            },
-                            "pinkie-promise": {
-                              "version": "1.0.0",
-                              "from": "pinkie-promise@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz",
-                              "dependencies": {
-                                "pinkie": {
-                                  "version": "1.0.0",
-                                  "from": "pinkie@>=1.0.0 <2.0.0",
-                                  "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
-                                }
-                              }
-                            },
-                            "strip-bom": {
-                              "version": "2.0.0",
-                              "from": "strip-bom@>=2.0.0 <3.0.0",
-                              "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
-                              "dependencies": {
-                                "is-utf8": {
-                                  "version": "0.2.0",
-                                  "from": "is-utf8@>=0.2.0 <0.3.0",
-                                  "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.0.tgz"
-                                }
-                              }
-                            }
-                          }
-                        },
-                        "path-type": {
-                          "version": "1.0.0",
-                          "from": "path-type@>=1.0.0 <2.0.0",
-                          "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.0.0.tgz",
-                          "dependencies": {
-                            "graceful-fs": {
-                              "version": "4.1.2",
-                              "from": "graceful-fs@>=4.1.2 <5.0.0"
-                            },
-                            "pify": {
-                              "version": "2.2.0",
-                              "from": "pify@>=2.0.0 <3.0.0",
-                              "resolved": "https://registry.npmjs.org/pify/-/pify-2.2.0.tgz"
-                            },
-                            "pinkie-promise": {
-                              "version": "1.0.0",
-                              "from": "pinkie-promise@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz",
-                              "dependencies": {
-                                "pinkie": {
-                                  "version": "1.0.0",
-                                  "from": "pinkie@>=1.0.0 <2.0.0",
-                                  "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
-                                }
-                              }
-                            }
-                          }
-                        }
-                      }
-                    }
-                  }
-                },
-                "redent": {
-                  "version": "1.0.0",
-                  "from": "redent@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
-                  "dependencies": {
-                    "indent-string": {
-                      "version": "2.1.0",
-                      "from": "indent-string@>=2.1.0 <3.0.0",
-                      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
-                      "dependencies": {
-                        "repeating": {
-                          "version": "2.0.0",
-                          "from": "repeating@>=2.0.0 <3.0.0",
-                          "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.0.tgz",
-                          "dependencies": {
-                            "is-finite": {
-                              "version": "1.0.1",
-                              "from": "is-finite@>=1.0.0 <2.0.0",
-                              "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.1.tgz"
-                            }
-                          }
-                        }
-                      }
-                    },
-                    "strip-indent": {
-                      "version": "1.0.1",
-                      "from": "strip-indent@>=1.0.1 <2.0.0",
-                      "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz"
-                    }
-                  }
-                },
-                "trim-newlines": {
-                  "version": "1.0.0",
-                  "from": "trim-newlines@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz"
+                  "from": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.4.tgz",
+                  "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.4.tgz"
                 }
               }
-            },
-            "number-is-nan": {
-              "version": "1.0.0",
-              "from": "number-is-nan@>=1.0.0 <2.0.0",
-              "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz"
             }
           }
         },
         "read-chunk": {
           "version": "1.0.1",
-          "from": "read-chunk@>=1.0.1 <2.0.0",
+          "from": "https://registry.npmjs.org/read-chunk/-/read-chunk-1.0.1.tgz",
           "resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-1.0.1.tgz"
         },
         "rimraf": {
           "version": "2.4.3",
-          "from": "rimraf@>=2.2.0 <3.0.0",
+          "from": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.3.tgz",
           "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.3.tgz"
         },
         "run-async": {
           "version": "0.1.0",
-          "from": "run-async@>=0.1.0 <0.2.0",
-          "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz",
-          "dependencies": {
-            "once": {
-              "version": "1.3.2",
-              "from": "once@>=1.3.0 <2.0.0",
-              "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz",
-              "dependencies": {
-                "wrappy": {
-                  "version": "1.0.1",
-                  "from": "wrappy@>=1.0.0 <2.0.0",
-                  "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
-                }
-              }
-            }
-          }
+          "from": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz",
+          "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz"
         },
         "shelljs": {
           "version": "0.5.3",
-          "from": "shelljs@>=0.5.0 <0.6.0",
+          "from": "https://registry.npmjs.org/shelljs/-/shelljs-0.5.3.tgz",
           "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.5.3.tgz"
         },
         "sinon": {
           "version": "1.17.1",
-          "from": "sinon@>=1.9.1 <2.0.0",
+          "from": "https://registry.npmjs.org/sinon/-/sinon-1.17.1.tgz",
           "resolved": "https://registry.npmjs.org/sinon/-/sinon-1.17.1.tgz",
           "dependencies": {
             "formatio": {
               "version": "1.1.1",
-              "from": "formatio@1.1.1",
+              "from": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz",
               "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz"
             },
             "util": {
               "version": "0.10.3",
-              "from": "util@>=0.10.3 <1.0.0",
-              "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
-              "dependencies": {
-                "inherits": {
-                  "version": "2.0.1",
-                  "from": "inherits@2.0.1",
-                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                }
-              }
+              "from": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
+              "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz"
             },
             "lolex": {
               "version": "1.3.2",
-              "from": "lolex@1.3.2",
+              "from": "https://registry.npmjs.org/lolex/-/lolex-1.3.2.tgz",
               "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.3.2.tgz"
             },
             "samsam": {
               "version": "1.1.2",
-              "from": "samsam@1.1.2",
+              "from": "https://registry.npmjs.org/samsam/-/samsam-1.1.2.tgz",
               "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.2.tgz"
             }
           }
         },
         "text-table": {
           "version": "0.2.0",
-          "from": "text-table@>=0.2.0 <0.3.0",
+          "from": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
           "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz"
         },
-        "through2": {
-          "version": "2.0.0",
-          "from": "through2@>=2.0.0 <3.0.0",
-          "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.0.tgz",
-          "dependencies": {
-            "readable-stream": {
-              "version": "2.0.2",
-              "from": "readable-stream@>=2.0.2 <3.0.0",
-              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz",
-              "dependencies": {
-                "core-util-is": {
-                  "version": "1.0.1",
-                  "from": "core-util-is@>=1.0.0 <1.1.0",
-                  "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-                },
-                "inherits": {
-                  "version": "2.0.1",
-                  "from": "inherits@>=2.0.1 <2.1.0",
-                  "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-                },
-                "isarray": {
-                  "version": "0.0.1",
-                  "from": "isarray@0.0.1",
-                  "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
-                },
-                "process-nextick-args": {
-                  "version": "1.0.3",
-                  "from": "process-nextick-args@>=1.0.0 <1.1.0",
-                  "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.3.tgz"
-                },
-                "string_decoder": {
-                  "version": "0.10.31",
-                  "from": "string_decoder@>=0.10.0 <0.11.0",
-                  "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
-                },
-                "util-deprecate": {
-                  "version": "1.0.2",
-                  "from": "util-deprecate@>=1.0.1 <1.1.0",
-                  "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
-                }
-              }
-            },
-            "xtend": {
-              "version": "4.0.0",
-              "from": "xtend@>=4.0.0 <4.1.0",
-              "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz"
-            }
-          }
-        },
         "underscore.string": {
           "version": "3.2.2",
-          "from": "underscore.string@>=3.0.3 <4.0.0",
+          "from": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.2.2.tgz",
           "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.2.2.tgz"
         },
         "user-home": {
           "version": "2.0.0",
-          "from": "user-home@>=2.0.0 <3.0.0",
+          "from": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz",
           "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz",
           "dependencies": {
             "os-homedir": {
               "version": "1.0.1",
-              "from": "os-homedir@>=1.0.0 <2.0.0",
+              "from": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.1.tgz",
               "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.1.tgz"
             }
           }
         },
         "xdg-basedir": {
           "version": "2.0.0",
-          "from": "xdg-basedir@>=2.0.0 <3.0.0",
+          "from": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-2.0.0.tgz",
           "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-2.0.0.tgz",
           "dependencies": {
             "os-homedir": {
               "version": "1.0.1",
-              "from": "os-homedir@>=1.0.0 <2.0.0",
+              "from": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.1.tgz",
               "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.1.tgz"
             }
           }
         },
         "yeoman-assert": {
           "version": "2.1.0",
-          "from": "yeoman-assert@>=2.0.0 <3.0.0",
+          "from": "https://registry.npmjs.org/yeoman-assert/-/yeoman-assert-2.1.0.tgz",
           "resolved": "https://registry.npmjs.org/yeoman-assert/-/yeoman-assert-2.1.0.tgz"
         },
         "yeoman-welcome": {
           "version": "1.0.1",
-          "from": "yeoman-welcome@>=1.0.0 <2.0.0",
+          "from": "https://registry.npmjs.org/yeoman-welcome/-/yeoman-welcome-1.0.1.tgz",
           "resolved": "https://registry.npmjs.org/yeoman-welcome/-/yeoman-welcome-1.0.1.tgz"
         }
       }
diff --git a/package.json b/package.json
index bdd4d7d03897..e7040699e370 100644
--- a/package.json
+++ b/package.json
@@ -25,7 +25,6 @@
       "/node_modules/(?!react|fbjs|react-native|parse|react-transform-hmr|core-js|promise)/",
       "node_modules/react/lib/React.js",
       "node_modules/react/lib/ReactDOM.js",
-
       "node_modules/fbjs/lib/Map.js",
       "node_modules/fbjs/lib/Promise.js",
       "node_modules/fbjs/lib/fetch.js",
@@ -49,7 +48,6 @@
       "node_modules/fbjs/lib/someObject.js",
       "node_modules/fbjs/lib/sprintf.js",
       "node_modules/fbjs/lib/xhrSimpleDataSerializer.js",
-
       "downstream/core/CSSCore.js",
       "downstream/core/TouchEventUtils.js",
       "downstream/core/camelize.js",
@@ -69,7 +67,6 @@
       "downstream/core/invariant.js",
       "downstream/core/nativeRequestAnimationFrame.js",
       "downstream/core/toArray.js",
-
       "node_modules/jest-cli",
       "node_modules/react/dist"
     ],
@@ -108,35 +105,13 @@
   "dependencies": {
     "absolute-path": "^0.0.0",
     "art": "^0.10.0",
-    "babel-core": "^6.1.20",
-    "babel-plugin-external-helpers-2": "^6.1.4",
-    "babel-plugin-syntax-async-functions": "^6.0.14",
-    "babel-plugin-syntax-class-properties": "^6.0.14",
-    "babel-plugin-syntax-flow": "^6.0.14",
-    "babel-plugin-syntax-jsx": "^6.0.14",
-    "babel-plugin-syntax-trailing-function-commas": "^6.0.14",
-    "babel-plugin-transform-class-properties": "^6.0.14",
-    "babel-plugin-transform-es2015-arrow-functions": "^6.0.14",
-    "babel-plugin-transform-es2015-block-scoping": "^6.0.18",
-    "babel-plugin-transform-es2015-classes": "^6.1.2",
-    "babel-plugin-transform-es2015-computed-properties": "^6.0.14",
-    "babel-plugin-transform-es2015-constants": "^6.0.15",
-    "babel-plugin-transform-es2015-destructuring": "^6.0.18",
-    "babel-plugin-transform-es2015-for-of": "^6.0.14",
-    "babel-plugin-transform-es2015-modules-commonjs": "^6.1.3",
-    "babel-plugin-transform-es2015-parameters": "^6.0.18",
-    "babel-plugin-transform-es2015-shorthand-properties": "^6.0.14",
-    "babel-plugin-transform-es2015-spread": "^6.0.14",
-    "babel-plugin-transform-es2015-template-literals": "^6.0.14",
-    "babel-plugin-transform-flow-strip-types": "^6.0.14",
-    "babel-plugin-transform-object-assign": "^6.0.14",
-    "babel-plugin-transform-object-rest-spread": "^6.0.14",
-    "babel-plugin-transform-react-display-name": "^6.0.14",
-    "babel-plugin-transform-react-jsx": "^6.0.18",
-    "babel-plugin-transform-regenerator": "^6.0.18",
-    "babel-polyfill": "^6.0.16",
-    "babel-types": "^6.1.2",
-    "babylon": "^6.1.2",
+    "babel-core": "~6.4.5",
+    "babel-plugin-external-helpers": "~6.4.0",
+    "babel-polyfill": "~6.3.14",
+    "babel-preset-react-native": "^1.2.4",
+    "babel-register": "~6.4.3",
+    "babel-types": "~6.4.5",
+    "babylon": "~6.4.5",
     "base64-js": "^0.0.8",
     "bser": "^1.0.2",
     "chalk": "^1.1.1",
@@ -160,8 +135,7 @@
     "promise": "^7.1.1",
     "react": "^0.14.5",
     "react-timer-mixin": "^0.13.2",
-    "react-transform-hmr": "^1.0.1",
-    "babel-plugin-react-transform": "2.0.0-beta1",
+    "react-transform-hmr": "^1.0.2",
     "rebound": "^0.0.13",
     "regenerator": "^0.8.36",
     "sane": "^1.2.0",
diff --git a/packager/babelRegisterOnly.js b/packager/babelRegisterOnly.js
index bf32861055ef..f862bb757e23 100644
--- a/packager/babelRegisterOnly.js
+++ b/packager/babelRegisterOnly.js
@@ -16,7 +16,7 @@ var path = require('path');
 var _only = [];
 
 function readBabelRC() {
-  var rcpath = path.join(__dirname, 'react-packager', '.babelrc');
+  var rcpath = path.join(__dirname, 'react-packager', 'rn-babelrc.json');
   var source = fs.readFileSync(rcpath).toString();
   return JSON.parse(source);
 }
@@ -25,5 +25,5 @@ module.exports = function(onlyList) {
   _only = _only.concat(onlyList);
   var config = readBabelRC();
   config.only = _only;
-  require('babel-core/register')(config);
+  require('babel-register')(config);
 };
diff --git a/packager/react-packager/.babelrc b/packager/react-packager/.babelrc
deleted file mode 100644
index e1c61b11f7df..000000000000
--- a/packager/react-packager/.babelrc
+++ /dev/null
@@ -1,30 +0,0 @@
-{
-  "retainLines": true,
-  "compact": true,
-  "comments": false,
-  "plugins": [
-    "syntax-async-functions",
-    "syntax-class-properties",
-    "syntax-trailing-function-commas",
-    "transform-class-properties",
-    "transform-es2015-arrow-functions",
-    "transform-es2015-block-scoping",
-    "transform-es2015-classes",
-    "transform-es2015-computed-properties",
-    "transform-es2015-constants",
-    "transform-es2015-destructuring",
-    ["transform-es2015-modules-commonjs", {"strict": false, "allowTopLevelThis": true}],
-    "transform-es2015-parameters",
-    "transform-es2015-shorthand-properties",
-    "transform-es2015-spread",
-    "transform-es2015-template-literals",
-    "transform-flow-strip-types",
-    "transform-object-assign",
-    "transform-object-rest-spread",
-    "transform-react-display-name",
-    "transform-react-jsx",
-    "transform-regenerator",
-    "transform-es2015-for-of"
-  ],
-  "sourceMaps": false
-}
diff --git a/packager/react-packager/index.js b/packager/react-packager/index.js
index 367f23f3df8e..5b28e7741a2b 100644
--- a/packager/react-packager/index.js
+++ b/packager/react-packager/index.js
@@ -15,7 +15,6 @@ useGracefulFs();
 var debug = require('debug');
 var omit = require('underscore').omit;
 var Activity = require('./src/Activity');
-var Transforms = require('./src/transforms');
 
 exports.createServer = createServer;
 exports.middleware = function(options) {
@@ -24,7 +23,6 @@ exports.middleware = function(options) {
 };
 
 exports.Activity = Activity;
-exports.getTransforms = Transforms.getAll;
 
 // Renamed "package" to "bundle". But maintain backwards
 // compat.
diff --git a/packager/react-packager/rn-babelrc.json b/packager/react-packager/rn-babelrc.json
new file mode 100644
index 000000000000..bbc20ea981db
--- /dev/null
+++ b/packager/react-packager/rn-babelrc.json
@@ -0,0 +1,4 @@
+{
+  "presets": [ "react-native" ],
+  "plugins": []
+}
diff --git a/packager/react-packager/src/JSTransformer/index.js b/packager/react-packager/src/JSTransformer/index.js
index 14886d062438..9767985926b5 100644
--- a/packager/react-packager/src/JSTransformer/index.js
+++ b/packager/react-packager/src/JSTransformer/index.js
@@ -66,6 +66,7 @@ class Transformer {
 
     this._cache = opts.cache;
     this._transformModulePath = opts.transformModulePath;
+    this._projectRoots = opts.projectRoots;
 
     if (opts.transformModulePath != null) {
       let transformer;
@@ -129,6 +130,7 @@ class Transformer {
             filename: filePath,
             options: {
               ...options,
+              projectRoots: this._projectRoots,
               externalTransformModulePath: this._transformModulePath,
             },
           }).then(res => {
diff --git a/packager/react-packager/src/JSTransformer/worker.js b/packager/react-packager/src/JSTransformer/worker.js
index b33b4ae51869..c8d388a41e27 100644
--- a/packager/react-packager/src/JSTransformer/worker.js
+++ b/packager/react-packager/src/JSTransformer/worker.js
@@ -9,30 +9,25 @@
 'use strict';
 
 var babel = require('babel-core');
-var resolvePlugins = require('./resolvePlugins');
-var Transforms = require('../transforms');
+var makeInternalConfig = require('babel-preset-react-native/configs/internal');
 
 // Runs internal transforms on the given sourceCode. Note that internal
 // transforms should be run after the external ones to ensure that they run on
 // Javascript code
 function internalTransforms(sourceCode, filename, options) {
-  var plugins = resolvePlugins(Transforms.getAll(options));
-  if (plugins.length === 0) {
+  var internalBabelConfig = makeInternalConfig(options);
+
+  if (!internalBabelConfig) {
     return {
       code: sourceCode,
       filename: filename,
     };
   }
 
-  var result = babel.transform(sourceCode, {
-    retainLines: true,
-    compact: true,
-    comments: false,
+  var result = babel.transform(sourceCode, Object.assign({
     filename: filename,
     sourceFileName: filename,
-    sourceMaps: false,
-    plugins: plugins,
-  });
+  }, internalBabelConfig));
 
   return {
     code: result.code,
diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index 4c6e3efbd295..a677c2199da8 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -93,7 +93,6 @@ class Resolver {
         // should work after this release and we can
         // remove it from here.
         'parse',
-        'react-transform-hmr',
       ],
       platforms: ['ios', 'android'],
       preferNativePlatform: true,
diff --git a/packager/transformer.js b/packager/transformer.js
index a38fdb0db5d9..071f4007fab1 100644
--- a/packager/transformer.js
+++ b/packager/transformer.js
@@ -11,47 +11,95 @@
 'use strict';
 
 const babel = require('babel-core');
+const externalHelpersPlugin = require('babel-plugin-external-helpers');
 const fs = require('fs');
-const inlineRequires = require('fbjs-scripts/babel-6/inline-requires');
+const makeHMRConfig = require('babel-preset-react-native/configs/hmr');
+const resolvePlugins = require('babel-preset-react-native/lib/resolvePlugins');
+const inlineRequiresPlugin = require('fbjs-scripts/babel-6/inline-requires');
 const json5 = require('json5');
 const path = require('path');
-const ReactPackager = require('./react-packager');
-const resolvePlugins = require('./react-packager/src/JSTransformer/resolvePlugins');
 
-const babelRC =
-  json5.parse(
-    fs.readFileSync(
-      path.resolve(__dirname, 'react-packager', '.babelrc')));
+/**
+ * Return a memoized function that checks for the existence of a
+ * project level .babelrc file, and if it doesn't exist, reads the
+ * default RN babelrc file and uses that.
+ */
+const getBabelRC = (function() {
+  let babelRC = null;
 
-function transform(src, filename, options) {
-  options = options || {};
+  return function _getBabelRC(projectRoots) {
+    if (babelRC !== null) {
+      return babelRC;
+    }
+
+    babelRC = { plugins: [] }; // empty babelrc
+
+    // Let's look for the .babelrc in the first project root.
+    // In the future let's look into adding a command line option to specify
+    // this location.
+    //
+    // NOTE: we're not reading the project's .babelrc here. We leave it up to
+    // Babel to do that automatically and apply the transforms accordingly
+    // (which works because we pass in `filename` and `sourceFilename` to
+    // Babel when we transform).
+    let projectBabelRCPath;
+    if (projectRoots && projectRoots.length > 0) {
+      projectBabelRCPath = path.resolve(projectRoots[0], '.babelrc');
+    }
+
+    // If a .babelrc file doesn't exist in the project,
+    // use the Babel config provided with react-native.
+    if (!projectBabelRCPath || !fs.existsSync(projectBabelRCPath)) {
+      babelRC = json5.parse(
+        fs.readFileSync(
+          path.resolve(__dirname, 'react-packager', 'rn-babelrc.json'))
+        );
+
+      // Require the babel-preset's listed in the default babel config
+      babelRC.presets = babelRC.presets.map((preset) => require('babel-preset-' + preset));
+      babelRC.plugins = resolvePlugins(babelRC.plugins);
+    }
+
+    return babelRC;
+  }
+})();
+
+/**
+ * Given a filename and options, build a Babel
+ * config object with the appropriate plugins.
+ */
+function buildBabelConfig(filename, options) {
+  const babelRC = getBabelRC(options.projectRoots);
 
-  const extraPlugins = ['external-helpers-2'];
   const extraConfig = {
     filename,
     sourceFileName: filename,
   };
 
-  const config = Object.assign({}, babelRC, extraConfig);
-  if (options.hot) {
-    extraPlugins.push([
-      'react-transform',
-      {
-        transforms: [{
-          transform: 'react-transform-hmr/lib/index.js',
-          imports: ['React'],
-          locals: ['module'],
-        }]
-      },
-    ]);
-  }
+  let config = Object.assign({}, babelRC, extraConfig);
+
+  // Add extra plugins
+  const extraPlugins = [externalHelpersPlugin];
 
   if (options.inlineRequires) {
-    extraPlugins.push(inlineRequires);
+    extraPlugins.push(inlineRequiresPlugin);
+  }
+
+  config.plugins = extraPlugins.concat(config.plugins);
+
+  if (options.hot) {
+    const hmrConfig = makeHMRConfig(options);
+    config = Object.assign({}, config, hmrConfig);
   }
-  config.plugins = resolvePlugins(extraPlugins.concat(config.plugins));
 
-  const result = babel.transform(src, Object.assign({}, babelRC, config));
+  return Object.assign({}, babelRC, config);
+}
+
+function transform(src, filename, options) {
+  options = options || {};
+
+  const babelConfig = buildBabelConfig(filename, options);
+  const result = babel.transform(src, babelConfig);
 
   return {
     code: result.code,

From e9f64b2f3f3ff1e71e8592e4522ba1cf25c3c5b0 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Wed, 3 Feb 2016 09:16:15 -0800
Subject: [PATCH 1014/1411] Updated ListView.scrollTo() API to match ScrollView

Reviewed By: davidaurelio

Differential Revision: D2895460

fb-gh-sync-id: 0520df3f2ed6614a08e3fc20a2417c7a8e2ace68
---
 Libraries/CustomComponents/ListView/ListView.js | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js
index e395ee8175d9..f0140f8e4ae9 100644
--- a/Libraries/CustomComponents/ListView/ListView.js
+++ b/Libraries/CustomComponents/ListView/ListView.js
@@ -227,17 +227,14 @@ var ListView = React.createClass({
   },
 
   /**
-   * Provides a handle to the underlying scroll responder to support operations
-   * such as scrollTo.
+   * Provides a handle to the underlying scroll responder.
    */
   getScrollResponder: function() {
-    return this.refs[SCROLLVIEW_REF] &&
-      this.refs[SCROLLVIEW_REF].getScrollResponder &&
-      this.refs[SCROLLVIEW_REF].getScrollResponder();
+    return this.refs[SCROLLVIEW_REF].getScrollResponder();
   },
 
-  scrollTo: function(destY, destX, animated = true) {
-    this.getScrollResponder().scrollResponderScrollTo(destX || 0, destY || 0, animated);
+  scrollTo: function(...args) {
+    this.refs[SCROLLVIEW_REF].scrollTo(...args);
   },
 
   setNativeProps: function(props) {

From 0fa54d5a226f3899e6d241ae197351687b6131cb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Wed, 3 Feb 2016 11:08:07 -0800
Subject: [PATCH 1015/1411] Bump preset to 1.2.4

Reviewed By: javache

Differential Revision: D2896094

fb-gh-sync-id: 6423ccb7f258bd166a0b04e0a3f41963dc0f8c8c
---
 babel-preset/package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/babel-preset/package.json b/babel-preset/package.json
index 01cef395297f..b442ab23cc85 100644
--- a/babel-preset/package.json
+++ b/babel-preset/package.json
@@ -1,6 +1,6 @@
 {
   "name": "babel-preset-react-native",
-  "version": "1.2.3",
+  "version": "1.2.4",
   "description": "Babel preset for React Native applications",
   "main": "index.js",
   "repository": "https://github.com/facebook/react-native/tree/master/babel-preset",

From db74e713fe68b8509777baf34db8a7bb496091e0 Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Wed, 3 Feb 2016 11:12:58 -0800
Subject: [PATCH 1016/1411] Fix scrollTo when using RefreshControl on Android

Summary:
The issue is that the ScrollResponder mixin assumes that the native scrollable node is the top level element and gets it using `React.findNodeHandle(this)` but since Android wraps the native `ScrollView` component with the `RefreshControl`, it finds the native `RefreshControl` node instead and the scroll command gets ignored because it doesn't exists.

This adds a hook to ScrollResponder mixin to allow specifying what is the native scrollable node.

The bug can be reproduced using this https://gist.github.com/janicduplessis/871c0b6d3ad0acaacba9 in UIExplorer.

Fixes #5725
Closes https://github.com/facebook/react-native/pull/5736

Reviewed By: svcscm

Differential Revision: D2896125

Pulled By: nicklockwood

fb-gh-sync-id: 0a00a20551421982c5bc519c542774877ba15c9b
---
 Libraries/Components/ScrollResponder.js       | 15 +++++++++++++--
 Libraries/Components/ScrollView/ScrollView.js |  4 ++++
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/Libraries/Components/ScrollResponder.js b/Libraries/Components/ScrollResponder.js
index 65531aa2fe63..52c6c946b862 100644
--- a/Libraries/Components/ScrollResponder.js
+++ b/Libraries/Components/ScrollResponder.js
@@ -347,6 +347,17 @@ var ScrollResponderMixin = {
     return isAnimating;
   },
 
+  /**
+   * Returns the node that represents native view that can be scrolled.
+   * Components can pass what node to use by defining a `getScrollableNode`
+   * function otherwise `this` is used.
+   */
+  scrollResponderGetScrollableNode: function(): any {
+    return this.getScrollableNode ?
+      this.getScrollableNode() :
+      React.findNodeHandle(this);
+  },
+
   /**
    * A helper function to scroll to a specific point  in the scrollview.
    * This is currently used to help focus on child textviews, but can also
@@ -369,7 +380,7 @@ var ScrollResponderMixin = {
       ({x, y, animated} = x || {});
     }
     UIManager.dispatchViewManagerCommand(
-      React.findNodeHandle(this),
+      this.scrollResponderGetScrollableNode(),
       UIManager.RCTScrollView.Commands.scrollTo,
       [x || 0, y || 0, animated !== false],
     );
@@ -401,7 +412,7 @@ var ScrollResponderMixin = {
       } else if (typeof animated !== 'undefined') {
         console.warn('`scrollResponderZoomTo` `animated` argument is deprecated. Use `options.animated` instead');
       }
-      ScrollViewManager.zoomToRect(React.findNodeHandle(this), rect, animated !== false);
+      ScrollViewManager.zoomToRect(this.scrollResponderGetScrollableNode(), rect, animated !== false);
     }
   },
 
diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js
index 279712808b28..d9d7102460fd 100644
--- a/Libraries/Components/ScrollView/ScrollView.js
+++ b/Libraries/Components/ScrollView/ScrollView.js
@@ -355,6 +355,10 @@ var ScrollView = React.createClass({
     return this;
   },
 
+  getScrollableNode: function(): any {
+    return React.findNodeHandle(this.refs[SCROLLVIEW]);
+  },
+
   getInnerViewNode: function(): any {
     return React.findNodeHandle(this.refs[INNERVIEW]);
   },

From 98373ac6e3656f539e4cd3156465692e2aa44e77 Mon Sep 17 00:00:00 2001
From: Ian Cervantez <TigerC10@users.noreply.github.com>
Date: Wed, 3 Feb 2016 11:35:53 -0800
Subject: [PATCH 1017/1411] Conditionally allowing showCompass view property

Summary:
Only allow the showsCompass view property when iOS 9+ is used.  Fixes #5706.
Closes https://github.com/facebook/react-native/pull/5708

Reviewed By: svcscm

Differential Revision: D2896322

Pulled By: nicklockwood

fb-gh-sync-id: 16b789d3516ad1ff7189d6ceab4300039ce2a76b
---
 React/Views/RCTMap.m | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/React/Views/RCTMap.m b/React/Views/RCTMap.m
index 0d8e56c806fa..1b3472530155 100644
--- a/React/Views/RCTMap.m
+++ b/React/Views/RCTMap.m
@@ -209,4 +209,17 @@ - (void)setOverlays:(NSArray<RCTMapOverlay *> *)overlays
   self.overlayIDs = newOverlayIDs;
 }
 
+- (BOOL)showsCompass {
+  if ([MKMapView instancesRespondToSelector:@selector(showsCompass)]) {
+    return super. showsCompass;
+  }
+  return NO;
+}
+
+- (void)setShowsCompass:(BOOL)showsCompass {
+  if ([MKMapView instancesRespondToSelector:@selector(setShowsCompass:)]) {
+    super.showsCompass = showsCompass;
+  }
+}
+
 @end

From 82b0df9d2a6163879647691235f01b3067c471b8 Mon Sep 17 00:00:00 2001
From: Brent Vatne <brentvatne@gmail.com>
Date: Wed, 3 Feb 2016 13:38:17 -0800
Subject: [PATCH 1018/1411] Add scrollEnabled prop to Android ScrollView

Summary:
Perhaps there is a better way to do this, curious to hear it!

- If momentum scroll is active when `scrollEnabled` is toggled, the momentum scroll continues and the onMomentumScrollEnd event fires, which is the same as on iOS.
Closes https://github.com/facebook/react-native/pull/5656

Reviewed By: svcscm

Differential Revision: D2889897

Pulled By: dmmiller

fb-gh-sync-id: b2f44d2bcb48373f9945f6afd966447a118df717
---
 Libraries/Components/ScrollView/ScrollView.js |  1 -
 .../scroll/ReactHorizontalScrollView.java     | 22 ++++++++++++++-----
 .../ReactHorizontalScrollViewManager.java     | 12 ++++++----
 .../react/views/scroll/ReactScrollView.java   | 19 +++++++++++++---
 .../views/scroll/ReactScrollViewManager.java  |  5 +++++
 5 files changed, 46 insertions(+), 13 deletions(-)

diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js
index d9d7102460fd..bd3f9b99e570 100644
--- a/Libraries/Components/ScrollView/ScrollView.js
+++ b/Libraries/Components/ScrollView/ScrollView.js
@@ -227,7 +227,6 @@ var ScrollView = React.createClass({
     /**
      * When false, the content does not scroll.
      * The default value is true.
-     * @platform ios
      */
     scrollEnabled: PropTypes.bool,
     /**
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java
index 61735c0ea9b8..e35dd064755b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java
@@ -31,13 +31,13 @@ public class ReactHorizontalScrollView extends HorizontalScrollView implements
 
   private final OnScrollDispatchHelper mOnScrollDispatchHelper = new OnScrollDispatchHelper();
 
-  private boolean mRemoveClippedSubviews;
-  private boolean mSendMomentumEvents;
+  private @Nullable Rect mClippingRect;
+  private boolean mDoneFlinging;
   private boolean mDragging;
   private boolean mFlinging;
-  private boolean mDoneFlinging;
-
-  private @Nullable Rect mClippingRect;
+  private boolean mRemoveClippedSubviews;
+  private boolean mScrollEnabled = true;
+  private boolean mSendMomentumEvents;
 
   public ReactHorizontalScrollView(Context context) {
     super(context);
@@ -61,6 +61,10 @@ public void setSendMomentumEvents(boolean sendMomentumEvents) {
     mSendMomentumEvents = sendMomentumEvents;
   }
 
+  public void setScrollEnabled(boolean scrollEnabled) {
+    mScrollEnabled = scrollEnabled;
+  }
+
   @Override
   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
     MeasureSpecAssertions.assertExplicitMeasureSpec(widthMeasureSpec, heightMeasureSpec);
@@ -95,6 +99,10 @@ protected void onScrollChanged(int x, int y, int oldX, int oldY) {
 
   @Override
   public boolean onInterceptTouchEvent(MotionEvent ev) {
+    if (!mScrollEnabled) {
+      return false;
+    }
+
     if (super.onInterceptTouchEvent(ev)) {
       NativeGestureUtil.notifyNativeGestureStarted(this, ev);
       ReactScrollViewHelper.emitScrollBeginDragEvent(this);
@@ -107,6 +115,10 @@ public boolean onInterceptTouchEvent(MotionEvent ev) {
 
   @Override
   public boolean onTouchEvent(MotionEvent ev) {
+    if (!mScrollEnabled) {
+      return false;
+    }
+
     int action = ev.getAction() & MotionEvent.ACTION_MASK;
     if (action == MotionEvent.ACTION_UP && mDragging) {
       ReactScrollViewHelper.emitScrollEndDragEvent(this);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java
index 923d35e77ce2..69185fef89cf 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java
@@ -39,17 +39,21 @@ public ReactHorizontalScrollView createViewInstance(ThemedReactContext context)
     return new ReactHorizontalScrollView(context);
   }
 
-  @ReactProp(name = ReactClippingViewGroupHelper.PROP_REMOVE_CLIPPED_SUBVIEWS)
-  public void setRemoveClippedSubviews(ReactHorizontalScrollView view, boolean removeClippedSubviews) {
-    view.setRemoveClippedSubviews(removeClippedSubviews);
+  @ReactProp(name = "scrollEnabled", defaultBoolean = true)
+  public void setScrollEnabled(ReactHorizontalScrollView view, boolean value) {
+    view.setScrollEnabled(value);
   }
 
-
   @ReactProp(name = "showsHorizontalScrollIndicator")
   public void setShowsHorizontalScrollIndicator(ReactHorizontalScrollView view, boolean value) {
     view.setHorizontalScrollBarEnabled(value);
   }
 
+  @ReactProp(name = ReactClippingViewGroupHelper.PROP_REMOVE_CLIPPED_SUBVIEWS)
+  public void setRemoveClippedSubviews(ReactHorizontalScrollView view, boolean removeClippedSubviews) {
+    view.setRemoveClippedSubviews(removeClippedSubviews);
+  }
+
   /**
    * Computing momentum events is potentially expensive since we post a runnable on the UI thread
    * to see when it is done.  We only do that if {@param sendMomentumEvents} is set to true.  This
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java
index 64559d1a35b5..5e87db3bf5d8 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java
@@ -34,12 +34,13 @@ public class ReactScrollView extends ScrollView implements ReactClippingViewGrou
 
   private final OnScrollDispatchHelper mOnScrollDispatchHelper = new OnScrollDispatchHelper();
 
-  private boolean mRemoveClippedSubviews;
   private @Nullable Rect mClippingRect;
-  private boolean mSendMomentumEvents;
+  private boolean mDoneFlinging;
   private boolean mDragging;
   private boolean mFlinging;
-  private boolean mDoneFlinging;
+  private boolean mRemoveClippedSubviews;
+  private boolean mScrollEnabled = true;
+  private boolean mSendMomentumEvents;
 
   public ReactScrollView(Context context) {
     super(context);
@@ -49,6 +50,10 @@ public void setSendMomentumEvents(boolean sendMomentumEvents) {
     mSendMomentumEvents = sendMomentumEvents;
   }
 
+  public void setScrollEnabled(boolean scrollEnabled) {
+    mScrollEnabled = scrollEnabled;
+  }
+
   @Override
   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
     MeasureSpecAssertions.assertExplicitMeasureSpec(widthMeasureSpec, heightMeasureSpec);
@@ -99,6 +104,10 @@ protected void onScrollChanged(int x, int y, int oldX, int oldY) {
 
   @Override
   public boolean onInterceptTouchEvent(MotionEvent ev) {
+    if (!mScrollEnabled) {
+      return false;
+    }
+
     if (super.onInterceptTouchEvent(ev)) {
       NativeGestureUtil.notifyNativeGestureStarted(this, ev);
       ReactScrollViewHelper.emitScrollBeginDragEvent(this);
@@ -111,6 +120,10 @@ public boolean onInterceptTouchEvent(MotionEvent ev) {
 
   @Override
   public boolean onTouchEvent(MotionEvent ev) {
+    if (!mScrollEnabled) {
+      return false;
+    }
+
     int action = ev.getAction() & MotionEvent.ACTION_MASK;
     if (action == MotionEvent.ACTION_UP && mDragging) {
       ReactScrollViewHelper.emitScrollEndDragEvent(this);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java
index ff71d30ab872..be023a76a2e3 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java
@@ -42,6 +42,11 @@ public ReactScrollView createViewInstance(ThemedReactContext context) {
     return new ReactScrollView(context);
   }
 
+  @ReactProp(name = "scrollEnabled", defaultBoolean = true)
+  public void setScrollEnabled(ReactScrollView view, boolean value) {
+    view.setScrollEnabled(value);
+  }
+
   @ReactProp(name = "showsVerticalScrollIndicator")
   public void setShowsVerticalScrollIndicator(ReactScrollView view, boolean value) {
     view.setVerticalScrollBarEnabled(value);

From e59efc1f023e4c78c3973dcd2ed77385c6cc4261 Mon Sep 17 00:00:00 2001
From: Ben Manes <ben.manes@gmail.com>
Date: Wed, 3 Feb 2016 17:01:11 -0800
Subject: [PATCH 1019/1411] Add LoadDocs android app to showcase

---
 website/src/react-native/showcase.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index c183012e0398..d7cf18585a72 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -310,7 +310,8 @@ var apps = [
   {
     name: 'LoadDocs',
     icon: 'http://a2.mzstatic.com/us/r30/Purple3/v4/b5/ca/78/b5ca78ca-392d-6874-48bf-762293482d42/icon350x350.jpeg',
-    link: 'https://itunes.apple.com/us/app/loaddocs/id1041596066',
+    linkAppStore: 'https://itunes.apple.com/us/app/loaddocs/id1041596066',
+    linkPlayStore: 'https://play.google.com/store/apps/details?id=com.convoy.loaddoc&hl=en',
     author: 'LoadDocs',
   },
   {

From 81fb985335a8ee3657905177abe32380b6b5fdc0 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Wed, 3 Feb 2016 17:30:01 -0800
Subject: [PATCH 1020/1411] Support non-image assets in packager

Summary:
public
The packager currently assumes that all assets that are not JSON or JS files must be images. Although it is possible to add other extension types, they crash the packager if you try to require them, because it attempts to get their dimensions, assuming that they are an image.

This is a crude workaround for that problem, which skips the image-specific processing for non-image assets, but really it would be better if the packager was properly aware of different asset types and treated them differently (e.g. for sounds it could include the duration, for HTML pages it could parse and include linked CSS files, etc).

I've also added an example of using `require('...')` to load a packager-managed HTML page in the UIExplorer WebView example. In future I anticipate that all static asset types (sounds, fonts, etc.) could be handled in this way, which allows them to be edited or added/removed on the fly instead of needing to restart the app.

Reviewed By: martinbigio

Differential Revision: D2895619

fb-gh-sync-id: cd93794ca66bad838621cd7df3ff3c62b5645e85
---
 .flowconfig                                   |  2 +-
 Examples/UIExplorer/WebViewExample.js         | 60 ++++++++++++++++++-
 Examples/UIExplorer/helloworld.html           | 25 ++++++++
 .../Components/WebView/WebView.android.js     |  7 ++-
 Libraries/Components/WebView/WebView.ios.js   |  8 ++-
 local-cli/server/runServer.js                 |  7 ++-
 packager/react-packager/src/Bundler/index.js  | 12 +++-
 packager/react-packager/src/Server/index.js   |  7 ++-
 8 files changed, 119 insertions(+), 9 deletions(-)
 create mode 100644 Examples/UIExplorer/helloworld.html

diff --git a/.flowconfig b/.flowconfig
index fd4925d5b1b8..78c0582045e1 100644
--- a/.flowconfig
+++ b/.flowconfig
@@ -51,7 +51,7 @@ module.system=haste
 munge_underscores=true
 
 module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub'
-module.name_mapper='^[./a-zA-Z0-9$_-]+\.png$' -> 'RelativeImageStub'
+module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\)$' -> 'RelativeImageStub'
 
 suppress_type=$FlowIssue
 suppress_type=$FlowFixMe
diff --git a/Examples/UIExplorer/WebViewExample.js b/Examples/UIExplorer/WebViewExample.js
index 817b16e3f2c4..f7346149395c 100644
--- a/Examples/UIExplorer/WebViewExample.js
+++ b/Examples/UIExplorer/WebViewExample.js
@@ -50,7 +50,7 @@ var WebViewExample = React.createClass({
 
   handleTextInputChange: function(event) {
     var url = event.nativeEvent.text;
-    if (!/^[a-zA-Z-_]:/.test(url)) {
+    if (!/^[a-zA-Z-_]+:/.test(url)) {
       url = 'http://' + url;
     }
     this.inputText = url;
@@ -231,6 +231,34 @@ var styles = StyleSheet.create({
   },
 });
 
+const HTML = `
+<!DOCTYPE html>\n
+<html>
+  <head>
+    <title>Hello Static World</title>
+    <meta http-equiv="content-type" content="text/html; charset=utf-8">
+    <meta name="viewport" content="width=320, user-scalable=no">
+    <style type="text/css">
+      body {
+        margin: 0;
+        padding: 0;
+        font: 62.5% arial, sans-serif;
+        background: #ccc;
+      }
+      h1 {
+        padding: 45px;
+        margin: 0;
+        text-align: center;
+        color: #33f;
+      }
+    </style>
+  </head>
+  <body>
+    <h1>Hello Static World</h1>
+  </body>
+</html>
+`;
+
 exports.displayName = (undefined: ?string);
 exports.title = '<WebView>';
 exports.description = 'Base component to display web content';
@@ -239,6 +267,36 @@ exports.examples = [
     title: 'Simple Browser',
     render(): ReactElement { return <WebViewExample />; }
   },
+  {
+    title: 'Bundled HTML',
+    render(): ReactElement {
+      return (
+        <WebView
+          style={{
+            backgroundColor: BGWASH,
+            height: 100,
+          }}
+          source={require('./helloworld.html')}
+          scalesPageToFit={true}
+        />
+      );
+    }
+  },
+  {
+    title: 'Static HTML',
+    render(): ReactElement {
+      return (
+        <WebView
+          style={{
+            backgroundColor: BGWASH,
+            height: 100,
+          }}
+          source={{html: HTML}}
+          scalesPageToFit={true}
+        />
+      );
+    }
+  },
   {
     title: 'POST Test',
     render(): ReactElement {
diff --git a/Examples/UIExplorer/helloworld.html b/Examples/UIExplorer/helloworld.html
new file mode 100644
index 000000000000..7289b0f87944
--- /dev/null
+++ b/Examples/UIExplorer/helloworld.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Hello Bundled World</title>
+    <meta http-equiv="content-type" content="text/html; charset=utf-8">
+    <meta name="viewport" content="width=320, user-scalable=no">
+    <style type="text/css">
+      body {
+        margin: 0;
+        padding: 0;
+        font: 62.5% arial, sans-serif;
+        background: #ccc;
+      }
+      h1 {
+        padding: 45px;
+        margin: 0;
+        text-align: center;
+        color: #f33;
+      }
+    </style>
+  </head>
+  <body>
+    <h1>Hello Bundled World</h1>
+  </body>
+</html>
diff --git a/Libraries/Components/WebView/WebView.android.js b/Libraries/Components/WebView/WebView.android.js
index 23dc5f02fb43..44ad8a925721 100644
--- a/Libraries/Components/WebView/WebView.android.js
+++ b/Libraries/Components/WebView/WebView.android.js
@@ -21,6 +21,7 @@ var deprecatedPropType = require('deprecatedPropType');
 var keyMirror = require('keyMirror');
 var merge = require('merge');
 var requireNativeComponent = require('requireNativeComponent');
+var resolveAssetSource = require('resolveAssetSource');
 
 var PropTypes = React.PropTypes;
 
@@ -98,6 +99,10 @@ var WebView = React.createClass({
          */
         baseUrl: PropTypes.string,
       }),
+      /*
+       * Used internally by packager.
+       */
+      PropTypes.number,
     ]),
 
     /**
@@ -193,7 +198,7 @@ var WebView = React.createClass({
         ref={RCT_WEBVIEW_REF}
         key="webViewKey"
         style={webViewStyles}
-        source={source}
+        source={resolveAssetSource(source)}
         injectedJavaScript={this.props.injectedJavaScript}
         userAgent={this.props.userAgent}
         javaScriptEnabled={javaScriptEnabled}
diff --git a/Libraries/Components/WebView/WebView.ios.js b/Libraries/Components/WebView/WebView.ios.js
index 6ea171331b9a..7714d383df87 100644
--- a/Libraries/Components/WebView/WebView.ios.js
+++ b/Libraries/Components/WebView/WebView.ios.js
@@ -25,6 +25,7 @@ var invariant = require('invariant');
 var keyMirror = require('keyMirror');
 var processDecelerationRate = require('processDecelerationRate');
 var requireNativeComponent = require('requireNativeComponent');
+var resolveAssetSource = require('resolveAssetSource');
 
 var PropTypes = React.PropTypes;
 var RCTWebViewManager = require('NativeModules').WebViewManager;
@@ -138,6 +139,10 @@ var WebView = React.createClass({
          */
         baseUrl: PropTypes.string,
       }),
+      /*
+       * Used internally by packager.
+       */
+      PropTypes.number,
     ]),
 
     /**
@@ -304,7 +309,7 @@ var WebView = React.createClass({
         ref={RCT_WEBVIEW_REF}
         key="webViewKey"
         style={webViewStyles}
-        source={source}
+        source={resolveAssetSource(source)}
         injectedJavaScript={this.props.injectedJavaScript}
         bounces={this.props.bounces}
         scrollEnabled={this.props.scrollEnabled}
@@ -432,6 +437,7 @@ var styles = StyleSheet.create({
     flex: 1,
     justifyContent: 'center',
     alignItems: 'center',
+    height: 100,
   },
   webView: {
     backgroundColor: '#ffffff',
diff --git a/local-cli/server/runServer.js b/local-cli/server/runServer.js
index e8d181a278e7..3f5f33aeeddf 100644
--- a/local-cli/server/runServer.js
+++ b/local-cli/server/runServer.js
@@ -75,7 +75,12 @@ function getPackagerServer(args, config) {
     getTransformOptionsModulePath: config.getTransformOptionsModulePath,
     transformModulePath: transformerPath,
     assetRoots: args.assetRoots,
-    assetExts: ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'webp'],
+    assetExts: [
+      'bmp', 'gif', 'jpg', 'jpeg', 'png', 'psd', 'svg', 'webp', // Image formats
+      'm4v', 'mov', 'mp4', 'mpeg', 'mpg', 'webm', // Video formats
+      'aac', 'aiff', 'caf', 'm4a', 'mp3', 'wav', // Audio formats
+      'html', // Document formats
+    ],
     resetCache: args.resetCache || args['reset-cache'],
     verbose: args.verbose,
   });
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index d03fdb89a28e..fc7be66d0357 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -554,8 +554,14 @@ class Bundler {
       assetUrlPath = assetUrlPath.replace(/\\/g, '/');
     }
 
+    // Test extension against all types supported by image-size module.
+    // If it's not one of these, we won't treat it as an image.
+    let isImage = [
+      'png', 'jpg', 'jpeg', 'bmp', 'gif', 'webp', 'psd', 'svg', 'tiff'
+    ].indexOf(path.extname(module.path).slice(1)) !== -1;
+
     return Promise.all([
-      sizeOf(module.path),
+      isImage ? sizeOf(module.path) : null,
       this._assetServer.getAssetData(relPath, platform),
     ]).then(function(res) {
       const dimensions = res[0];
@@ -564,8 +570,8 @@ class Bundler {
         __packager_asset: true,
         fileSystemLocation: path.dirname(module.path),
         httpServerLocation: assetUrlPath,
-        width: dimensions.width / module.resolution,
-        height: dimensions.height / module.resolution,
+        width: dimensions ? dimensions.width / module.resolution : undefined,
+        height: dimensions ? dimensions.height / module.resolution : undefined,
         scales: assetData.scales,
         files: assetData.files,
         hash: assetData.hash,
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index da8653f845b3..f8c252a3fd23 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -58,7 +58,12 @@ const validateOpts = declareOpts({
   },
   assetExts: {
     type: 'array',
-    default: ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'webp'],
+    default: [
+      'bmp', 'gif', 'jpg', 'jpeg', 'png', 'psd', 'svg', 'webp', // Image formats
+      'm4v', 'mov', 'mp4', 'mpeg', 'mpg', 'webm', // Video formats
+      'aac', 'aiff', 'caf', 'm4a', 'mp3', 'wav', // Audio formats
+      'html', // Document formats
+    ],
   },
   transformTimeoutInterval: {
     type: 'number',

From 33d8db599ef8eb85dc27150e04c71719be6ffd26 Mon Sep 17 00:00:00 2001
From: fangmobile <fangjian@gmail.com>
Date: Thu, 4 Feb 2016 05:12:36 -0800
Subject: [PATCH 1021/1411] added accessibility props for touchables

Summary:
accessibilityLabels are missing in these touchable*.js files.
for #5322
ide This is not tested yet. I will update with test.
Closes https://github.com/facebook/react-native/pull/5346

Reviewed By: svcscm

Differential Revision: D2882061

Pulled By: gkassabli

fb-gh-sync-id: dff0ef373e5f5895027cb1cc08c8887a6ace8eee
---
 Examples/UIExplorer/TextInputExample.android.js        |  8 +++++++-
 Examples/UIExplorer/TextInputExample.ios.js            |  8 +++++++-
 Examples/UIExplorer/TouchableExample.js                |  3 +++
 Libraries/Components/TextInput/TextInput.js            | 10 ++++++----
 Libraries/Components/Touchable/TouchableBounce.js      |  3 +++
 Libraries/Components/Touchable/TouchableHighlight.js   |  1 +
 .../Touchable/TouchableNativeFeedback.android.js       |  1 +
 Libraries/Components/Touchable/TouchableOpacity.js     |  1 +
 .../Components/Touchable/TouchableWithoutFeedback.js   |  1 +
 9 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/Examples/UIExplorer/TextInputExample.android.js b/Examples/UIExplorer/TextInputExample.android.js
index f3691f14ba86..3652b974c8fc 100644
--- a/Examples/UIExplorer/TextInputExample.android.js
+++ b/Examples/UIExplorer/TextInputExample.android.js
@@ -208,7 +208,13 @@ exports.examples = [
   {
     title: 'Auto-focus',
     render: function() {
-      return <TextInput autoFocus={true} style={styles.singleLine} />;
+      return (
+        <TextInput
+          autoFocus={true}
+          style={styles.singleLine}
+          accessibilityLabel="I am the accessibility label for text input"
+        />
+      );
     }
   },
   {
diff --git a/Examples/UIExplorer/TextInputExample.ios.js b/Examples/UIExplorer/TextInputExample.ios.js
index 49e28ffced8a..eac262d77061 100644
--- a/Examples/UIExplorer/TextInputExample.ios.js
+++ b/Examples/UIExplorer/TextInputExample.ios.js
@@ -348,7 +348,13 @@ exports.examples = [
   {
     title: 'Auto-focus',
     render: function() {
-      return <TextInput autoFocus={true} style={styles.default} />;
+      return (
+        <TextInput
+          autoFocus={true}
+          style={styles.default}
+          accessibilityLabel="I am the accessibility label for text input"
+        />
+      );
     }
   },
   {
diff --git a/Examples/UIExplorer/TouchableExample.js b/Examples/UIExplorer/TouchableExample.js
index dd3b2c9c89f7..515a0c2b858c 100644
--- a/Examples/UIExplorer/TouchableExample.js
+++ b/Examples/UIExplorer/TouchableExample.js
@@ -144,6 +144,9 @@ var TouchableFeedbackEvents = React.createClass({
           <TouchableOpacity
             style={styles.wrapper}
             testID="touchable_feedback_events_button"
+            accessibilityLabel="touchable feedback events"
+            accessibilityTraits="button"
+            accessibilityComponentType="button"
             onPress={() => this._appendEvent('press')}
             onPressIn={() => this._appendEvent('pressIn')}
             onPressOut={() => this._appendEvent('pressOut')}
diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js
index e72c98cdfa93..7a902576c7ef 100644
--- a/Libraries/Components/TextInput/TextInput.js
+++ b/Libraries/Components/TextInput/TextInput.js
@@ -290,10 +290,6 @@ var TextInput = React.createClass({
      * Styles
      */
     style: Text.propTypes.style,
-    /**
-     * Used to locate this view in end-to-end tests
-     */
-    testID: PropTypes.string,
     /**
      * The color of the textInput underline.
      * @platform android
@@ -457,6 +453,9 @@ var TextInput = React.createClass({
       <TouchableWithoutFeedback
         onPress={this._onPress}
         rejectResponderTermination={true}
+        accessible={props.accessible}
+        accessibilityLabel={props.accessibilityLabel}
+        accessibilityTraits={props.accessibilityTraits}
         testID={props.testID}>
         {textContainer}
       </TouchableWithoutFeedback>
@@ -520,6 +519,9 @@ var TextInput = React.createClass({
     return (
       <TouchableWithoutFeedback
         onPress={this._onPress}
+        accessible={this.props.accessible}
+        accessibilityLabel={this.props.accessibilityLabel}
+        accessibilityComponentType={this.props.accessibilityComponentType}
         testID={this.props.testID}>
         {textContainer}
       </TouchableWithoutFeedback>
diff --git a/Libraries/Components/Touchable/TouchableBounce.js b/Libraries/Components/Touchable/TouchableBounce.js
index d3c1696769e8..1d7abcc71e83 100644
--- a/Libraries/Components/Touchable/TouchableBounce.js
+++ b/Libraries/Components/Touchable/TouchableBounce.js
@@ -117,6 +117,9 @@ var TouchableBounce = React.createClass({
       <Animated.View
         style={[{transform: [{scale: this.state.scale}]}, this.props.style]}
         accessible={true}
+        accessibilityLabel={this.props.accessibilityLabel}
+        accessibilityComponentType={this.props.accessibilityComponentType}
+        accessibilityTraits={this.props.accessibilityTraits}
         testID={this.props.testID}
         onStartShouldSetResponder={this.touchableHandleStartShouldSetResponder}
         onResponderTerminationRequest={this.touchableHandleResponderTerminationRequest}
diff --git a/Libraries/Components/Touchable/TouchableHighlight.js b/Libraries/Components/Touchable/TouchableHighlight.js
index 929c43dfcbfb..4c7324d6f6e7 100644
--- a/Libraries/Components/Touchable/TouchableHighlight.js
+++ b/Libraries/Components/Touchable/TouchableHighlight.js
@@ -215,6 +215,7 @@ var TouchableHighlight = React.createClass({
     return (
       <View
         accessible={true}
+        accessibilityLabel={this.props.accessibilityLabel}
         accessibilityComponentType={this.props.accessibilityComponentType}
         accessibilityTraits={this.props.accessibilityTraits}
         ref={UNDERLAY_REF}
diff --git a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js
index ec3850c6bf93..19439d4e5ff0 100644
--- a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js
+++ b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js
@@ -200,6 +200,7 @@ var TouchableNativeFeedback = React.createClass({
       ...onlyChild(this.props.children).props,
       nativeBackgroundAndroid: this.props.background,
       accessible: this.props.accessible !== false,
+      accessibilityLabel: this.props.accessibilityLabel,
       accessibilityComponentType: this.props.accessibilityComponentType,
       accessibilityTraits: this.props.accessibilityTraits,
       testID: this.props.testID,
diff --git a/Libraries/Components/Touchable/TouchableOpacity.js b/Libraries/Components/Touchable/TouchableOpacity.js
index 627dd1205bd6..2cd0abefb470 100644
--- a/Libraries/Components/Touchable/TouchableOpacity.js
+++ b/Libraries/Components/Touchable/TouchableOpacity.js
@@ -154,6 +154,7 @@ var TouchableOpacity = React.createClass({
     return (
       <Animated.View
         accessible={true}
+        accessibilityLabel={this.props.accessibilityLabel}
         accessibilityComponentType={this.props.accessibilityComponentType}
         accessibilityTraits={this.props.accessibilityTraits}
         style={[this.props.style, {opacity: this.state.anim}]}
diff --git a/Libraries/Components/Touchable/TouchableWithoutFeedback.js b/Libraries/Components/Touchable/TouchableWithoutFeedback.js
index 96bcb6bf9ed8..5a578a205a7c 100755
--- a/Libraries/Components/Touchable/TouchableWithoutFeedback.js
+++ b/Libraries/Components/Touchable/TouchableWithoutFeedback.js
@@ -135,6 +135,7 @@ var TouchableWithoutFeedback = React.createClass({
     // Note(avik): remove dynamic typecast once Flow has been upgraded
     return (React: any).cloneElement(onlyChild(this.props.children), {
       accessible: this.props.accessible !== false,
+      accessibilityLabel: this.props.accessibilityLabel,
       accessibilityComponentType: this.props.accessibilityComponentType,
       accessibilityTraits: this.props.accessibilityTraits,
       testID: this.props.testID,

From a0eddff5de5f71e5f9fdb7402f0cc0c920c5cb1e Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Thu, 4 Feb 2016 08:38:17 -0800
Subject: [PATCH 1022/1411] Force stack alignment on x86 devices

Summary:
public

JSC enforces a stack-alignment that wasn't always being provided on x86 builds. See D2886997.

Reviewed By: foghina

Differential Revision: D2900982

fb-gh-sync-id: 3f8dffcc1c528a4c21d7ed0b17e49d87761b1df7
---
 ReactAndroid/src/main/jni/react/JSCHelpers.h | 21 +++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/jni/react/JSCHelpers.h b/ReactAndroid/src/main/jni/react/JSCHelpers.h
index 7ac633075ce4..de3bfbacbf15 100644
--- a/ReactAndroid/src/main/jni/react/JSCHelpers.h
+++ b/ReactAndroid/src/main/jni/react/JSCHelpers.h
@@ -20,6 +20,25 @@ JSValueRef makeJSCException(
     JSContextRef ctx,
     const char* exception_text);
 
-JSValueRef evaluateScript(JSContextRef context, JSStringRef script, JSStringRef source, const char *cachePath = nullptr);
+#ifdef __i386__
+// The Android x86 ABI states that the NDK toolchain assumes 16 byte stack
+// alignment: http://developer.android.com/ndk/guides/x86.html JSC checks for
+// stack alignment, and fails with SIGTRAP if it is not.  Empirically, the
+// google android x86 emulator does not provide this alignment, and so JSC
+// calls may crash.  All checked calls go through here, so the attribute here
+// is added to force alignment and prevent crashes.
+
+JSValueRef evaluateScript(
+    JSContextRef ctx,
+    JSStringRef script,
+    JSStringRef sourceURL,
+    const char* cachePath = nullptr) __attribute__((force_align_arg_pointer));
+#else
+JSValueRef evaluateScript(
+    JSContextRef ctx,
+    JSStringRef script,
+    JSStringRef sourceURL,
+    const char* cachePath = nullptr);
+#endif
 
 } }

From aea67c88901be99f22db72148498ae09bb347ec9 Mon Sep 17 00:00:00 2001
From: Eric Sauter <esauter5@gmail.com>
Date: Thu, 4 Feb 2016 09:49:19 -0800
Subject: [PATCH 1023/1411] Update DropBot Showcase information

Summary:
We recently renamed DropBot to Fixt, so I updated the info including the app icon and a link for our now released Android app.

Also, added whitespace to the right side of the dash between iOS and Android app links. Super minor, but it looks nicer :smiley:
Closes https://github.com/facebook/react-native/pull/5759

Reviewed By: svcscm

Differential Revision: D2901143

Pulled By: androidtrunkagent

fb-gh-sync-id: 29df3d2804387b6dcf1973efd53b616e84bbd922
---
 website/src/react-native/showcase.js | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index d7cf18585a72..9b3b8722de38 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -198,10 +198,11 @@ var apps = [
     author: 'Genki Takiuchi (s21g Inc.)',
   },
   {
-    name: 'DropBot',
-    icon: 'http://a2.mzstatic.com/us/r30/Purple69/v4/fb/df/73/fbdf73e0-22d2-c936-3115-1defa195acba/icon175x175.png',
-    link:  'https://itunes.apple.com/us/app/dropbot-phone-replacement/id1000855694?mt=8',
-    author: 'Peach Labs',
+    name: 'Fixt',
+    icon: 'http://a5.mzstatic.com/us/r30/Purple69/v4/46/bc/66/46bc66a2-7775-4d24-235d-e1fe28d55d7f/icon175x175.png',
+    linkAppStore:  'https://itunes.apple.com/us/app/dropbot-phone-replacement/id1000855694?mt=8',
+    linkPlayStore:  'https://play.google.com/store/apps/details?id=co.fixt',
+    author: 'Fixt',
   },
   {
     name: 'Due',
@@ -628,7 +629,8 @@ var AppList = React.createClass({
   _renderLinks: function(app) {
     return (
       <p>
-        <a href={app.linkAppStore} target="blank">iOS</a> -
+        <a href={app.linkAppStore} target="blank">iOS</a>
+        {" - "}
         <a href={app.linkPlayStore} target="blank">Android</a>
       </p>
     );

From e1f04bf2e328de9d232ef0fe600709b151da09ec Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeux@fb.com>
Date: Thu, 4 Feb 2016 15:22:12 -0800
Subject: [PATCH 1024/1411] Quit early if node < 4

Summary:
Before we would display this warning at the top and have the packager throw thousands of lines of errors because of es6 syntax.

Before:

<img width="602" alt="screen shot 2016-02-04 at 1 49 27 pm" src="https://cloud.githubusercontent.com/assets/197597/12831357/a72bdc0a-cb48-11e5-9b81-dde895eaf113.png">

After:

<img width="1440" alt="screen shot 2016-02-04 at 2 04 50 pm" src="https://cloud.githubusercontent.com/assets/197597/12831364/af1c16a0-cb48-11e5-949c-c470938f8b49.png">
Closes https://github.com/facebook/react-native/pull/5767

Reviewed By: svcscm

Differential Revision: D2902978

Pulled By: androidtrunkagent

fb-gh-sync-id: c0193c3b1e36778d61aa9013f0c294f8c3475442
---
 local-cli/server/checkNodeVersion.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/local-cli/server/checkNodeVersion.js b/local-cli/server/checkNodeVersion.js
index 5d73f9e463d9..406c08cf8257 100644
--- a/local-cli/server/checkNodeVersion.js
+++ b/local-cli/server/checkNodeVersion.js
@@ -36,5 +36,6 @@ module.exports = function() {
       marginRight: 1,
       paddingBottom: 1,
     }));
+    process.exit(1);
   }
 };

From 58738483abdee8091fdf94072f40fb65cc187990 Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeuxx@gmail.com>
Date: Thu, 4 Feb 2016 15:32:22 -0800
Subject: [PATCH 1025/1411] Stop spamming the logs

Summary:
We should have 0 logs at startup. In theory it could be useful to know if the profiler is enabled, but in practice 99% of the time you don't care and it ends up spamming you for no good reason. Then more people add logs and not only do the logs are not useful, they prevent people from actually using them when debugging.
Closes https://github.com/facebook/react-native/pull/5766

Reviewed By: svcscm

Differential Revision: D2902987

Pulled By: androidtrunkagent

fb-gh-sync-id: d47f8e58edf5f2c8e2a7a4373fd7d9036d2309a0
---
 React/Profiler/RCTJSCProfiler.m | 2 --
 1 file changed, 2 deletions(-)

diff --git a/React/Profiler/RCTJSCProfiler.m b/React/Profiler/RCTJSCProfiler.m
index f808c1c5f432..8ad34b62682e 100644
--- a/React/Profiler/RCTJSCProfiler.m
+++ b/React/Profiler/RCTJSCProfiler.m
@@ -56,11 +56,9 @@ static void RCTJSCProfilerStateInit()
 
     if (RCTNativeProfilerStart && RCTNativeProfilerEnd && enableBytecode) {
       enableBytecode();
-      RCTLogInfo(@"JSC profiler is available.");
     } else {
       RCTNativeProfilerStart = NULL;
       RCTNativeProfilerEnd = NULL;
-      RCTLogInfo(@"JSC profiler is not supported.");
     }
   });
 }

From 184c708b14e110e1856a381c00e8c8a487b04efc Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeux@fb.com>
Date: Thu, 4 Feb 2016 15:36:28 -0800
Subject: [PATCH 1026/1411] Remove React dev tools upsell

Summary:
React dev tools have been broken since we moved to web worker but we had a gigantic upsell for them. This must be a very frustrating experience for people just starting to use react native to be told to use something and see that it doesn't work.

Removing that upsell until it works again

<img width="1090" alt="screen shot 2016-02-04 at 2 00 37 pm" src="https://cloud.githubusercontent.com/assets/197597/12831501/8eba3f4e-cb49-11e5-8bdc-84f902053321.png">
Closes https://github.com/facebook/react-native/pull/5768

Reviewed By: svcscm

Differential Revision: D2903017

Pulled By: vjeux

fb-gh-sync-id: 731c5fefbef1a5249d632fc62ca36813533f2639
---
 local-cli/server/util/debugger.html | 40 -----------------------------
 1 file changed, 40 deletions(-)

diff --git a/local-cli/server/util/debugger.html b/local-cli/server/util/debugger.html
index 289b1f53b304..3d1c5947e219 100644
--- a/local-cli/server/util/debugger.html
+++ b/local-cli/server/util/debugger.html
@@ -27,12 +27,6 @@
   }
 };
 
-window.addEventListener('load', function () {
-  if (typeof window.__REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') {
-    document.getElementById('devtools-banner').style.display = 'block';
-  }
-});
-
 // Alias native implementations needed by the debugger before platform-specific
 // implementations are loaded into the global namespace
 var debuggerSetTimeout = window.setTimeout;
@@ -123,46 +117,12 @@
     border-radius: 4px;
     letter-spacing: 3px;
   }
-  #devtools-banner {
-    display: none;
-    background-color: #FDFDD5;
-    padding: 10px;
-  }
-  #devtools-banner h3 {
-    margin: 0;
-    font-weight: normal;
-  }
-  #devtools-banner a {
-    display: none;
-    padding: 10px 20px 10px 20px;
-    margin-bottom: 10px;
-    color: white;
-    text-decoration: none;
-    font-size: 11px;
-    text-shadow: 0 1px 1px rgba(0,0,0,0.1);
-    text-transform: uppercase;
-    font-weight: bold;
-    background-color: #4d7bd6;
-    border-radius: 2px;
-    border: 1px solid #2d53af;
-    display: inline-block;
-  }
   .content {
     padding: 10px;
   }
 </style>
 </head>
 <body>
-  <div id="devtools-banner">
-    <h3>Install React DevTools</h3>
-    <p>
-       React Developer Tools is an extension that allows you to inspect the
-       React component hierarchies in the Chrome Developer Tools.
-    </p>
-    <a href="https://fb.me/react-devtools" target="_blank">
-      Install
-    </a>
-  </div>
   <div class="content">
     <p>
       React Native JS code runs inside this Chrome tab.

From 4326b01181559a908740cda0a4c8459c9bdb919d Mon Sep 17 00:00:00 2001
From: Olivier Notteghem <oli@fb.com>
Date: Thu, 4 Feb 2016 15:45:25 -0800
Subject: [PATCH 1027/1411] safety fixes

Reviewed By: nspaun

Differential Revision: D2902378

fb-gh-sync-id: da35b6d61e6248e5920eab6f5e53a7ce8deb8e01
---
 Libraries/CustomComponents/ListView/ListView.js | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js
index f0140f8e4ae9..2ebbf24e6343 100644
--- a/Libraries/CustomComponents/ListView/ListView.js
+++ b/Libraries/CustomComponents/ListView/ListView.js
@@ -230,15 +230,18 @@ var ListView = React.createClass({
    * Provides a handle to the underlying scroll responder.
    */
   getScrollResponder: function() {
-    return this.refs[SCROLLVIEW_REF].getScrollResponder();
+    return this.refs[SCROLLVIEW_REF] && 
+      this.refs[SCROLLVIEW_REF].getScrollResponder();
   },
 
   scrollTo: function(...args) {
-    this.refs[SCROLLVIEW_REF].scrollTo(...args);
+    this.refs[SCROLLVIEW_REF] && 
+      this.refs[SCROLLVIEW_REF].scrollTo(...args);
   },
 
   setNativeProps: function(props) {
-    this.refs[SCROLLVIEW_REF].setNativeProps(props);
+    this.refs[SCROLLVIEW_REF] && 
+      this.refs[SCROLLVIEW_REF].setNativeProps(props);
   },
 
   /**

From 736e90053243a03c48c00f072a2f3bbbdcb07567 Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeux@fb.com>
Date: Thu, 4 Feb 2016 15:45:34 -0800
Subject: [PATCH 1028/1411] Support for ShadowPropTypesIOS

Summary:
Fixes https://github.com/facebook/react-native/issues/5748

<img width="1179" alt="screen shot 2016-02-04 at 12 08 07 pm" src="https://cloud.githubusercontent.com/assets/197597/12828197/340f7d5e-cb38-11e5-84b5-8dde48014100.png">
Closes https://github.com/facebook/react-native/pull/5763

Reviewed By: svcscm

Differential Revision: D2902270

Pulled By: vjeux

fb-gh-sync-id: bde9beaa869f9fe6d610e7bdf8f16bc3f4a08c7a
---
 website/server/extractDocs.js | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/website/server/extractDocs.js b/website/server/extractDocs.js
index 8d8abba0be96..26c4eb7525c1 100644
--- a/website/server/extractDocs.js
+++ b/website/server/extractDocs.js
@@ -252,9 +252,13 @@ var apis = [
   '../Libraries/Vibration/VibrationIOS.ios.js',
 ];
 
-var styles = [
+var stylesWithPermalink = [
   '../Libraries/StyleSheet/LayoutPropTypes.js',
   '../Libraries/StyleSheet/TransformPropTypes.js',
+  '../Libraries/Components/View/ShadowPropTypesIOS.js',
+];
+
+var stylesForEmbed = [
   '../Libraries/Components/View/ViewStylePropTypes.js',
   '../Libraries/Text/TextStylePropTypes.js',
   '../Libraries/Image/ImageStylePropTypes.js',
@@ -266,10 +270,10 @@ var polyfills = [
 
 var all = components
   .concat(apis)
-  .concat(styles.slice(0, 2))
+  .concat(stylesWithPermalink)
   .concat(polyfills);
 
-var styleDocs = styles.slice(2).reduce(function(docs, filepath) {
+var styleDocs = stylesForEmbed.reduce(function(docs, filepath) {
   docs[path.basename(filepath).replace(path.extname(filepath), '')] =
     docgen.parse(
       fs.readFileSync(filepath),
@@ -289,7 +293,7 @@ module.exports = function() {
   return [].concat(
     components.map(renderComponent),
     apis.map(renderAPI('api')),
-    styles.slice(0, 2).map(renderStyle),
+    stylesWithPermalink.map(renderStyle),
     polyfills.map(renderAPI('Polyfill'))
   );
 };

From 10c0758906fa071142e3ea309b2bfcbe64d7b5e0 Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Fri, 5 Feb 2016 05:19:52 -0800
Subject: [PATCH 1029/1411] Fix proguard template for ReactProp and
 ReactPropGroup

Summary:
ReactProp and ReactPropGroup were moved in the annotations package but the proguard file was not updated accordingly. This caused apps to crash when built in release using proguard.

Fixes #5655
Closes https://github.com/facebook/react-native/pull/5717

Reviewed By: svcscm

Differential Revision: D2905573

Pulled By: lexs

fb-gh-sync-id: 29ab14bacda7254d9896ff3991bf17d7fdfd6ea9
---
 .../generator-android/templates/src/app/proguard-rules.pro    | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/local-cli/generator-android/templates/src/app/proguard-rules.pro b/local-cli/generator-android/templates/src/app/proguard-rules.pro
index 35840261d7cc..7d72e46927a9 100644
--- a/local-cli/generator-android/templates/src/app/proguard-rules.pro
+++ b/local-cli/generator-android/templates/src/app/proguard-rules.pro
@@ -42,8 +42,8 @@
 -keep class * extends com.facebook.react.bridge.NativeModule { *; }
 -keepclassmembers,includedescriptorclasses class * { native <methods>; }
 -keepclassmembers class *  { @com.facebook.react.uimanager.UIProp <fields>; }
--keepclassmembers class *  { @com.facebook.react.uimanager.ReactProp <methods>; }
--keepclassmembers class *  { @com.facebook.react.uimanager.ReactPropGroup <methods>; }
+-keepclassmembers class *  { @com.facebook.react.uimanager.annotations.ReactProp <methods>; }
+-keepclassmembers class *  { @com.facebook.react.uimanager.annotations.ReactPropGroup <methods>; }
 
 -dontwarn com.facebook.react.**
 

From fef4196c8b5ab725cf3b8331ca1bdf189e7067d1 Mon Sep 17 00:00:00 2001
From: Andrei Coman <andreic@fb.com>
Date: Fri, 5 Feb 2016 05:34:26 -0800
Subject: [PATCH 1030/1411] Cache image resource ids

Reviewed By: AaaChiuuu

Differential Revision: D2895691

fb-gh-sync-id: 40824c6fdf5bdd8f0b724a7c81645d3ea911bccf
---
 .../react/views/image/ReactImageManager.java  |  7 ++-
 .../react/views/image/ReactImageView.java     | 36 +++---------
 .../views/image/ResourceDrawableIdHelper.java | 55 +++++++++++++++++++
 3 files changed, 68 insertions(+), 30 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/image/ResourceDrawableIdHelper.java

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
index 8b3298647d0a..4231d207d9aa 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
@@ -32,6 +32,7 @@ public String getName() {
     return REACT_CLASS;
   }
 
+  private ResourceDrawableIdHelper mResourceDrawableIdHelper;
   private @Nullable AbstractDraweeControllerBuilder mDraweeControllerBuilder;
   private final @Nullable Object mCallerContext;
 
@@ -40,12 +41,14 @@ public ReactImageManager(
       Object callerContext) {
     mDraweeControllerBuilder = draweeControllerBuilder;
     mCallerContext = callerContext;
+    mResourceDrawableIdHelper = new ResourceDrawableIdHelper();
   }
 
   public ReactImageManager() {
     // Lazily initialize as FrescoModule have not been initialized yet
     mDraweeControllerBuilder = null;
     mCallerContext = null;
+    mResourceDrawableIdHelper = new ResourceDrawableIdHelper();
   }
 
   public AbstractDraweeControllerBuilder getDraweeControllerBuilder() {
@@ -70,13 +73,13 @@ public ReactImageView createViewInstance(ThemedReactContext context) {
   // In JS this is Image.props.source.uri
   @ReactProp(name = "src")
   public void setSource(ReactImageView view, @Nullable String source) {
-    view.setSource(source);
+    view.setSource(source, mResourceDrawableIdHelper);
   }
 
   // In JS this is Image.props.loadingIndicatorSource.uri
   @ReactProp(name = "loadingIndicatorSrc")
   public void setLoadingIndicatorSource(ReactImageView view, @Nullable String source) {
-    view.setLoadingIndicatorSource(source);
+    view.setLoadingIndicatorSource(source, mResourceDrawableIdHelper);
   }
 
   @ReactProp(name = "borderColor", customType = "Color")
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
index be57d799d337..1c020acdcc8a 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
@@ -15,7 +15,6 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
 import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Paint;
@@ -208,7 +207,9 @@ public void setScaleType(ScalingUtils.ScaleType scaleType) {
     mIsDirty = true;
   }
 
-  public void setSource(@Nullable String source) {
+  public void setSource(
+      @Nullable String source,
+      ResourceDrawableIdHelper resourceDrawableIdHelper) {
     mUri = null;
     if (source != null) {
       try {
@@ -221,7 +222,7 @@ public void setSource(@Nullable String source) {
         // ignore malformed uri, then attempt to extract resource ID.
       }
       if (mUri == null) {
-        mUri = getResourceDrawableUri(getContext(), source);
+        mUri = resourceDrawableIdHelper.getResourceDrawableUri(getContext(), source);
         mIsLocalImage = true;
       } else {
         mIsLocalImage = false;
@@ -230,8 +231,10 @@ public void setSource(@Nullable String source) {
     mIsDirty = true;
   }
 
-  public void setLoadingIndicatorSource(@Nullable String name) {
-    Drawable drawable = getResourceDrawable(getContext(), name);
+  public void setLoadingIndicatorSource(
+      @Nullable String name,
+      ResourceDrawableIdHelper resourceDrawableIdHelper) {
+    Drawable drawable = resourceDrawableIdHelper.getResourceDrawable(getContext(), name);
     mLoadingImageDrawable =
         drawable != null ? (Drawable) new AutoRotateDrawable(drawable, 1000) : null;
     mIsDirty = true;
@@ -349,27 +352,4 @@ private static boolean shouldResize(@Nullable Uri uri) {
     // has no control over the original size
     return uri != null && (UriUtil.isLocalContentUri(uri) || UriUtil.isLocalFileUri(uri));
   }
-
-  private static int getResourceDrawableId(Context context, @Nullable String name) {
-    if (name == null || name.isEmpty()) {
-      return 0;
-    }
-    return context.getResources().getIdentifier(
-        name.toLowerCase().replace("-", "_"),
-        "drawable",
-        context.getPackageName());
-  }
-
-  private static @Nullable Drawable getResourceDrawable(Context context, @Nullable String name) {
-    int resId = getResourceDrawableId(context, name);
-    return resId > 0 ? context.getResources().getDrawable(resId) : null;
-  }
-
-  private static Uri getResourceDrawableUri(Context context, @Nullable String name) {
-    int resId = getResourceDrawableId(context, name);
-    return resId > 0 ? new Uri.Builder()
-        .scheme(UriUtil.LOCAL_RESOURCE_SCHEME)
-        .path(String.valueOf(resId))
-        .build() : Uri.EMPTY;
-  }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ResourceDrawableIdHelper.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ResourceDrawableIdHelper.java
new file mode 100644
index 000000000000..17d930601b64
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ResourceDrawableIdHelper.java
@@ -0,0 +1,55 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.views.image;
+
+import javax.annotation.Nullable;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+
+import com.facebook.common.util.UriUtil;
+
+/**
+ * Helper class for obtaining information about local images.
+ */
+/* package */ class ResourceDrawableIdHelper {
+
+  private Map<String, Integer> mResourceDrawableIdMap;
+
+  public ResourceDrawableIdHelper() {
+    mResourceDrawableIdMap = new HashMap<String, Integer>();
+  }
+
+  public int getResourceDrawableId(Context context, @Nullable String name) {
+    if (name == null || name.isEmpty()) {
+      return 0;
+    }
+    name = name.toLowerCase().replace("-", "_");
+    if (mResourceDrawableIdMap.containsKey(name)) {
+      return mResourceDrawableIdMap.get(name);
+    }
+    int id = context.getResources().getIdentifier(
+        name,
+        "drawable",
+        context.getPackageName());
+    mResourceDrawableIdMap.put(name, id);
+    return id;
+  }
+
+  public @Nullable Drawable getResourceDrawable(Context context, @Nullable String name) {
+    int resId = getResourceDrawableId(context, name);
+    return resId > 0 ? context.getResources().getDrawable(resId) : null;
+  }
+
+  public Uri getResourceDrawableUri(Context context, @Nullable String name) {
+    int resId = getResourceDrawableId(context, name);
+    return resId > 0 ? new Uri.Builder()
+        .scheme(UriUtil.LOCAL_RESOURCE_SCHEME)
+        .path(String.valueOf(resId))
+        .build() : Uri.EMPTY;
+  }
+}

From 6ac007b2ba50d5d909f09f5b4632558d1192a570 Mon Sep 17 00:00:00 2001
From: Adam Miskiewicz <adam@sk3vy.com>
Date: Fri, 5 Feb 2016 06:28:20 -0800
Subject: [PATCH 1031/1411] Use new DisplayMetrics object in
 `getDisplayMetrics` as to not overwrite Android global state

Summary:
The change in https://github.com/facebook/react-native/commit/8e603940e3fca4ed2fe420c02a66d860b53f3076 actually causes a super bad bug when `context.getResources().getDisplayMetrics()` is accessed in other parts of the application.

It turns out that when you dive into the impl of `getRealMetrics`, it mutates whatever `DisplayMetrics` object is passed to it. In this case, `getDisplayMetrics` ends up mutating the `DisplayMetrics` object that sits on the application context's `Resources` instance.

This PR makes that not so.

/cc jesseruder ide jaysoo bestander astreet
Closes https://github.com/facebook/react-native/pull/5764

Reviewed By: svcscm

Differential Revision: D2902386

Pulled By: androidtrunkagent

fb-gh-sync-id: 3f24b68bc7e6b4ca83808c03ef3637e1ac9a673e
---
 .../java/com/facebook/react/uimanager/UIManagerModule.java     | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
index 725c874c3923..4aab528e5539 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
@@ -464,7 +464,8 @@ public void sendAccessibilityEvent(int tag, int eventType) {
   private DisplayMetrics getDisplayMetrics() {
     Context context = getReactApplicationContext();
 
-    DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+    DisplayMetrics displayMetrics = new DisplayMetrics();
+    displayMetrics.setTo(context.getResources().getDisplayMetrics());
     WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
     Display display = wm.getDefaultDisplay();
 

From 77ad9459f5ab6eae88f6e0e0e9bf69de7a9be48a Mon Sep 17 00:00:00 2001
From: Andrei Coman <andreic@fb.com>
Date: Fri, 5 Feb 2016 06:53:25 -0800
Subject: [PATCH 1032/1411] Kill bridge initialization in onDestroy

Reviewed By: AaaChiuuu

Differential Revision: D2877999

fb-gh-sync-id: c986a921c8456213b03d6b7fd339da11713d040b
---
 .../react/ReactInstanceManagerImpl.java       | 28 ++++++++++++++-----
 1 file changed, 21 insertions(+), 7 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index be9c60688a8b..cfeb91fad3af 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -86,8 +86,8 @@
   /* should only be accessed from main thread (UI thread) */
   private final List<ReactRootView> mAttachedRootViews = new ArrayList<>();
   private LifecycleState mLifecycleState;
-  private boolean mIsContextInitAsyncTaskRunning;
   private @Nullable ReactContextInitParams mPendingReactContextInitParams;
+  private @Nullable ReactContextInitAsyncTask mReactContextInitAsyncTask;
 
   /* accessed from any thread */
   private @Nullable String mJSBundleFile; /* path to JS bundle on file system */
@@ -188,7 +188,7 @@ protected void onPostExecute(Result<ReactApplicationContext> result) {
       } catch (Exception e) {
         mDevSupportManager.handleException(e);
       } finally {
-        mIsContextInitAsyncTaskRunning = false;
+        mReactContextInitAsyncTask = null;
       }
 
       // Handle enqueued request to re-initialize react context.
@@ -199,6 +199,17 @@ protected void onPostExecute(Result<ReactApplicationContext> result) {
         mPendingReactContextInitParams = null;
       }
     }
+
+    @Override
+    protected void onCancelled(Result<ReactApplicationContext> reactApplicationContextResult) {
+      try {
+        mMemoryPressureRouter.destroy(reactApplicationContextResult.get());
+      } catch (Exception e) {
+        FLog.w(ReactConstants.TAG, "Caught exception after cancelling react context init", e);
+      } finally {
+        mReactContextInitAsyncTask = null;
+      }
+    }
   }
 
   private static class Result<T> {
@@ -453,6 +464,10 @@ public void onResume(Activity activity, DefaultHardwareBackBtnHandler defaultBac
   public void onDestroy() {
     UiThreadUtil.assertOnUiThread();
 
+    if (mReactContextInitAsyncTask != null) {
+      mReactContextInitAsyncTask.cancel(true);
+    }
+
     mMemoryPressureRouter.destroy(mApplicationContext);
     if (mUseDeveloperSupport) {
       mDevSupportManager.setDevSupportEnabled(false);
@@ -502,7 +517,7 @@ public void attachMeasuredRootView(ReactRootView rootView) {
 
     // If react context is being created in the background, JS application will be started
     // automatically when creation completes, as root view is part of the attached root view list.
-    if (!mIsContextInitAsyncTaskRunning && mCurrentReactContext != null) {
+    if (mReactContextInitAsyncTask == null && mCurrentReactContext != null) {
       attachMeasuredRootViewToInstance(rootView, mCurrentReactContext.getCatalystInstance());
     }
   }
@@ -574,11 +589,10 @@ private void recreateReactContextInBackground(
 
     ReactContextInitParams initParams =
         new ReactContextInitParams(jsExecutorFactory, jsBundleLoader);
-    if (!mIsContextInitAsyncTaskRunning) {
+    if (mReactContextInitAsyncTask == null) {
       // No background task to create react context is currently running, create and execute one.
-      ReactContextInitAsyncTask initTask = new ReactContextInitAsyncTask();
-      initTask.execute(initParams);
-      mIsContextInitAsyncTaskRunning = true;
+      mReactContextInitAsyncTask = new ReactContextInitAsyncTask();
+      mReactContextInitAsyncTask.execute(initParams);
     } else {
       // Background task is currently running, queue up most recent init params to recreate context
       // once task completes.

From fa2b53166e5db685e6c2db86346365aaaa76185a Mon Sep 17 00:00:00 2001
From: Andrei Coman <andreic@fb.com>
Date: Fri, 5 Feb 2016 07:09:50 -0800
Subject: [PATCH 1033/1411] More perf markers

Reviewed By: javache

Differential Revision: D2895501

fb-gh-sync-id: bc06e2dc45a6f9201c25271ae4467cc93eb44545
---
 .../react/ReactInstanceManagerImpl.java       | 16 +++++++++++--
 .../react/bridge/ReactMarkerConstants.java    | 24 +++++++++++++++++++
 2 files changed, 38 insertions(+), 2 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/ReactMarkerConstants.java

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index cfeb91fad3af..3c570a0616e2 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -64,6 +64,8 @@
 import com.facebook.soloader.SoLoader;
 import com.facebook.systrace.Systrace;
 
+import static com.facebook.react.bridge.ReactMarkerConstants.*;
+
 /**
  * This class is managing instances of {@link CatalystInstance}. It expose a way to configure
  * catalyst instance using {@link ReactPackage} and keeps track of the lifecycle of that
@@ -672,7 +674,7 @@ private ReactApplicationContext createReactContext(
       JavaScriptExecutor jsExecutor,
       JSBundleLoader jsBundleLoader) {
     FLog.i(ReactConstants.TAG, "Creating react context.");
-    ReactMarker.logMarker("CREATE_REACT_CONTEXT_START");
+    ReactMarker.logMarker(CREATE_REACT_CONTEXT_START);
     mSourceUrl = jsBundleLoader.getSourceUrl();
     NativeModuleRegistry.Builder nativeRegistryBuilder = new NativeModuleRegistry.Builder();
     JavaScriptModulesConfig.Builder jsModulesBuilder = new JavaScriptModulesConfig.Builder();
@@ -682,6 +684,7 @@ private ReactApplicationContext createReactContext(
       reactContext.setNativeModuleCallExceptionHandler(mDevSupportManager);
     }
 
+    ReactMarker.logMarker(PROCESS_PACKAGES_START);
     Systrace.beginSection(
         Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
         "createAndProcessCoreModulesPackage");
@@ -704,21 +707,26 @@ private ReactApplicationContext createReactContext(
         Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
       }
     }
+    ReactMarker.logMarker(PROCESS_PACKAGES_END);
 
+    ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_START);
     Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "buildNativeModuleRegistry");
     NativeModuleRegistry nativeModuleRegistry;
     try {
        nativeModuleRegistry = nativeRegistryBuilder.build();
     } finally {
       Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+      ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_END);
     }
 
+    ReactMarker.logMarker(BUILD_JS_MODULE_CONFIG_START);
     Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "buildJSModuleConfig");
     JavaScriptModulesConfig javaScriptModulesConfig;
     try {
       javaScriptModulesConfig = jsModulesBuilder.build();
     } finally {
       Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+      ReactMarker.logMarker(BUILD_JS_MODULE_CONFIG_END);
     }
 
     NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null
@@ -732,12 +740,14 @@ private ReactApplicationContext createReactContext(
         .setJSBundleLoader(jsBundleLoader)
         .setNativeModuleCallExceptionHandler(exceptionHandler);
 
+    ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_START);
     Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstance");
     CatalystInstance catalystInstance;
     try {
       catalystInstance = catalystInstanceBuilder.build();
     } finally {
       Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+      ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_END);
     }
 
     if (mBridgeIdleDebugListener != null) {
@@ -746,14 +756,16 @@ private ReactApplicationContext createReactContext(
 
     reactContext.initializeWithInstance(catalystInstance);
 
+    ReactMarker.logMarker(RUN_JS_BUNDLE_START);
     Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "runJSBundle");
     try {
       catalystInstance.runJSBundle();
     } finally {
       Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+      ReactMarker.logMarker(RUN_JS_BUNDLE_END);
     }
 
-    ReactMarker.logMarker("CREATE_REACT_CONTEXT_END");
+    ReactMarker.logMarker(CREATE_REACT_CONTEXT_END);
     return reactContext;
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactMarkerConstants.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactMarkerConstants.java
new file mode 100644
index 000000000000..fb920b9ac0fa
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactMarkerConstants.java
@@ -0,0 +1,24 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.bridge;
+
+/**
+ * Constants used by ReactMarker.
+ */
+public class ReactMarkerConstants {
+
+  public static final String CREATE_REACT_CONTEXT_START = "CREATE_REACT_CONTEXT_START";
+  public static final String CREATE_REACT_CONTEXT_END = "CREATE_REACT_CONTEXT_END";
+  public static final String PROCESS_PACKAGES_START = "PROCESS_PACKAGES_START";
+  public static final String PROCESS_PACKAGES_END = "PROCESS_PACKAGES_END";
+  public static final String BUILD_NATIVE_MODULE_REGISTRY_START =
+      "BUILD_NATIVE_MODULE_REGISTRY_START";
+  public static final String BUILD_NATIVE_MODULE_REGISTRY_END =
+      "BUILD_NATIVE_MODULE_REGISTRY_END";
+  public static final String BUILD_JS_MODULE_CONFIG_START = "BUILD_JS_MODULE_CONFIG_START";
+  public static final String BUILD_JS_MODULE_CONFIG_END = "BUILD_JS_MODULE_CONFIG_END";
+  public static final String CREATE_CATALYST_INSTANCE_START = "CREATE_CATALYST_INSTANCE_START";
+  public static final String CREATE_CATALYST_INSTANCE_END = "CREATE_CATALYST_INSTANCE_END";
+  public static final String RUN_JS_BUNDLE_START = "RUN_JS_BUNDLE_START";
+  public static final String RUN_JS_BUNDLE_END = "RUN_JS_BUNDLE_END";
+}

From d2ab6cabd46804a52d4e116d29767ca6a4061976 Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Fri, 5 Feb 2016 11:08:59 -0800
Subject: [PATCH 1034/1411] Don't automatically render more rows when
 dataSource updates

Reviewed By: sahrens

Differential Revision: D2875678

fb-gh-sync-id: c10e2c65c133d01245ac134170b25cb93377f97b
---
 .../CustomComponents/ListView/ListView.js     | 21 +++++++------------
 1 file changed, 7 insertions(+), 14 deletions(-)

diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js
index 2ebbf24e6343..1a9bef47b3fb 100644
--- a/Libraries/CustomComponents/ListView/ListView.js
+++ b/Libraries/CustomComponents/ListView/ListView.js
@@ -35,7 +35,6 @@ var StaticRenderer = require('StaticRenderer');
 var TimerMixin = require('react-timer-mixin');
 
 var isEmpty = require('isEmpty');
-var logError = require('logError');
 var merge = require('merge');
 
 var PropTypes = React.PropTypes;
@@ -292,26 +291,20 @@ var ListView = React.createClass({
   },
 
   componentWillReceiveProps: function(nextProps) {
-    if (this.props.dataSource !== nextProps.dataSource) {
+    if (this.props.dataSource !== nextProps.dataSource ||
+        this.props.initialListSize !== nextProps.initialListSize) {
       this.setState((state, props) => {
         this._prevRenderedRowsCount = 0;
         return {
           curRenderedRowsCount: Math.min(
-            state.curRenderedRowsCount + props.pageSize,
+            Math.max(
+              state.curRenderedRowsCount,
+              props.initialListSize
+            ),
             props.dataSource.getRowCount()
           ),
         };
-      });
-    }
-    if (this.props.initialListSize !== nextProps.initialListSize) {
-      this.setState((state, props) => {
-        return {
-          curRenderedRowsCount: Math.max(
-            state.curRenderedRowsCount,
-            props.initialListSize
-          ),
-        };
-      });
+      }, () => this._renderMoreRowsIfNeeded());
     }
   },
 

From 2f73ad0241453fac379925a8c48426c5125ed2eb Mon Sep 17 00:00:00 2001
From: Corentin Smith <corentin.smith@gmail.com>
Date: Fri, 5 Feb 2016 12:08:49 -0800
Subject: [PATCH 1035/1411] Add String.prototype.includes polyfill

Summary:
Add a polyfill for `String.prototype.includes` taken from MDN (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/includes)
See https://github.com/facebook/react-native/issues/5727
Closes https://github.com/facebook/react-native/pull/5735

Reviewed By: svcscm

Differential Revision: D2906667

Pulled By: vjeux

fb-gh-sync-id: e02f605bf57171062b29a98b98ba9fc898cedfc2
---
 .../Resolver/polyfills/String.prototype.es6.js    | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/packager/react-packager/src/Resolver/polyfills/String.prototype.es6.js b/packager/react-packager/src/Resolver/polyfills/String.prototype.es6.js
index afc68d76ab53..c455ef1ee586 100644
--- a/packager/react-packager/src/Resolver/polyfills/String.prototype.es6.js
+++ b/packager/react-packager/src/Resolver/polyfills/String.prototype.es6.js
@@ -83,3 +83,18 @@ if (!String.prototype.repeat) {
     return result;
   };
 }
+
+if (!String.prototype.includes) {
+  String.prototype.includes = function(search, start) {
+    'use strict';
+    if (typeof start !== 'number') {
+      start = 0;
+    }
+    
+    if (start + search.length > this.length) {
+      return false;
+    } else {
+      return this.indexOf(search, start) !== -1;
+    }
+  };
+}

From a3085464f6ea36fc6b53cd0c711c048ffb1516f9 Mon Sep 17 00:00:00 2001
From: Eric Vicenti <evv@fb.com>
Date: Fri, 5 Feb 2016 14:25:17 -0800
Subject: [PATCH 1036/1411] NavigationExperimental

Summary:
A new API to unify internal navigation. Also addresses a highly-rated community 'pain': https://productpains.com/post/react-native/better-navigator-api-and-docs/

Offers the following improvements:

- Redux-style navigation logic is easy to reason about
- Navigation state can be easily saved and restored through refreshes
- Declarative navigation views can be implemented in native or JS
- Animations and gestures are isolated and now use the Animated library

public

Reviewed By: hedgerwang

Differential Revision: D2798048

fb-gh-sync-id: 88027ef9ead8a80afa38354252bc377455cc6dbb
---
 .../NavigationAnimatedExample.js              | 105 +++++++
 .../NavigationBasicExample.js                 |  82 ++++++
 .../NavigationCompositionExample.js           | 264 ++++++++++++++++++
 .../NavigationExampleRow.js                   |  65 +++++
 .../NavigationExampleTabBar.js                |  81 ++++++
 .../NavigationExperimentalExample.js          | 129 +++++++++
 .../NavigationTabsExample.js                  | 104 +++++++
 Examples/UIExplorer/UIExplorerList.ios.js     |   1 +
 .../NavigationExperimental/NavigationCard.js  | 160 +++++++++++
 .../NavigationHeader.js                       | 149 ++++++++++
 .../NavigationExperimental/back_chevron.png   | Bin 0 -> 575 bytes
 .../NavigationAnimatedView.js                 | 225 +++++++++++++++
 .../NavigationContainer.js                    |  51 ++++
 .../NavigationExperimental.js                 |  41 +++
 .../NavigationRootContainer.js                |  86 ++++++
 .../NavigationExperimental/NavigationState.js | 196 +++++++++++++
 .../NavigationExperimental/NavigationView.js  |  63 +++++
 .../Reducer/NavigationFindReducer.js          |  38 +++
 .../Reducer/NavigationReducer.js              |  24 ++
 .../Reducer/NavigationStackReducer.js         | 141 ++++++++++
 .../Reducer/NavigationTabsReducer.js          | 143 ++++++++++
 .../__tests__/NavigationFindReducer-test.js   |  46 +++
 .../__tests__/NavigationStackReducer-test.js  | 197 +++++++++++++
 .../__tests__/NavigationTabsReducer-test.js   |  55 ++++
 .../__tests__/NavigationState-test.js         |  57 ++++
 Libraries/react-native/react-native.js        |   1 +
 26 files changed, 2504 insertions(+)
 create mode 100644 Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
 create mode 100644 Examples/UIExplorer/NavigationExperimental/NavigationBasicExample.js
 create mode 100644 Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js
 create mode 100644 Examples/UIExplorer/NavigationExperimental/NavigationExampleRow.js
 create mode 100644 Examples/UIExplorer/NavigationExperimental/NavigationExampleTabBar.js
 create mode 100644 Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js
 create mode 100644 Examples/UIExplorer/NavigationExperimental/NavigationTabsExample.js
 create mode 100644 Libraries/CustomComponents/NavigationExperimental/NavigationCard.js
 create mode 100644 Libraries/CustomComponents/NavigationExperimental/NavigationHeader.js
 create mode 100644 Libraries/CustomComponents/NavigationExperimental/back_chevron.png
 create mode 100644 Libraries/NavigationExperimental/NavigationAnimatedView.js
 create mode 100644 Libraries/NavigationExperimental/NavigationContainer.js
 create mode 100644 Libraries/NavigationExperimental/NavigationExperimental.js
 create mode 100644 Libraries/NavigationExperimental/NavigationRootContainer.js
 create mode 100644 Libraries/NavigationExperimental/NavigationState.js
 create mode 100644 Libraries/NavigationExperimental/NavigationView.js
 create mode 100644 Libraries/NavigationExperimental/Reducer/NavigationFindReducer.js
 create mode 100644 Libraries/NavigationExperimental/Reducer/NavigationReducer.js
 create mode 100644 Libraries/NavigationExperimental/Reducer/NavigationStackReducer.js
 create mode 100644 Libraries/NavigationExperimental/Reducer/NavigationTabsReducer.js
 create mode 100644 Libraries/NavigationExperimental/Reducer/__tests__/NavigationFindReducer-test.js
 create mode 100644 Libraries/NavigationExperimental/Reducer/__tests__/NavigationStackReducer-test.js
 create mode 100644 Libraries/NavigationExperimental/Reducer/__tests__/NavigationTabsReducer-test.js
 create mode 100644 Libraries/NavigationExperimental/__tests__/NavigationState-test.js

diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
new file mode 100644
index 000000000000..2139397908a5
--- /dev/null
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
@@ -0,0 +1,105 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+*/
+'use strict';
+
+var React = require('react-native');
+var {
+  NavigationExperimental,
+  StyleSheet,
+  ScrollView,
+} = React;
+var NavigationExampleRow = require('./NavigationExampleRow');
+var {
+  AnimatedView: NavigationAnimatedView,
+  Card: NavigationCard,
+  RootContainer: NavigationRootContainer,
+  Reducer: NavigationReducer,
+  Header: NavigationHeader,
+} = NavigationExperimental;
+
+const NavigationBasicReducer = NavigationReducer.StackReducer({
+  initialStates: [
+    {key: 'First Route'}
+  ],
+  matchAction: action => true,
+  actionStateMap: actionString => ({key: actionString}),
+});
+
+class NavigationAnimatedExample extends React.Component {
+  componentWillMount() {
+    this._renderNavigated = this._renderNavigated.bind(this);
+  }
+  render() {
+    return (
+      <NavigationRootContainer
+        reducer={NavigationBasicReducer}
+        persistenceKey="NavigationAnimatedExampleState"
+        renderNavigation={this._renderNavigated}
+      />
+    );
+  }
+  _renderNavigated(navigationState, onNavigate) {
+    if (!navigationState) {
+      return null;
+    }
+    return (
+      <NavigationAnimatedView
+        navigationState={navigationState}
+        style={styles.animatedView}
+        renderOverlay={(position, layout) => (
+          <NavigationHeader
+            navigationState={navigationState}
+            position={position}
+            getTitle={state => state.key}
+          />
+        )}
+        renderScene={(state, index, position, layout) => (
+          <NavigationCard
+            key={state.key}
+            index={index}
+            navigationState={navigationState}
+            position={position}
+            layout={layout}>
+            <ScrollView style={styles.scrollView}>
+              <NavigationExampleRow
+                text={navigationState.children[navigationState.index].key}
+              />
+              <NavigationExampleRow
+                text="Push!"
+                onPress={() => {
+                  onNavigate('Route #' + navigationState.children.length);
+                }}
+              />
+              <NavigationExampleRow
+                text="Exit Animated Nav Example"
+                onPress={this.props.onExampleExit}
+              />
+            </ScrollView>
+          </NavigationCard>
+        )}
+      />
+    );
+  }
+}
+
+const styles = StyleSheet.create({
+  animatedView: {
+    flex: 1,
+  },
+  scrollView: {
+    marginTop: 64
+  },
+});
+
+module.exports = NavigationAnimatedExample;
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationBasicExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationBasicExample.js
new file mode 100644
index 000000000000..21f03eb63889
--- /dev/null
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationBasicExample.js
@@ -0,0 +1,82 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+*/
+'use strict';
+
+const React = require('react-native');
+const {
+  NavigationExperimental,
+  ScrollView,
+  StyleSheet,
+} = React;
+const NavigationExampleRow = require('./NavigationExampleRow');
+const {
+  RootContainer: NavigationRootContainer,
+  Reducer: NavigationReducer,
+} = NavigationExperimental;
+const StackReducer = NavigationReducer.StackReducer;
+
+const NavigationBasicReducer = StackReducer({
+  initialStates: [
+    {key: 'first_page'}
+  ],
+  matchAction: action => true,
+  actionStateMap: action => ({key: action}),
+});
+
+const NavigationBasicExample = React.createClass({
+  render: function() {
+    return (
+      <NavigationRootContainer
+        reducer={NavigationBasicReducer}
+        persistenceKey="NavigationBasicExampleState"
+        renderNavigation={(navState, onNavigate) => {
+          if (!navState) { return null; }
+          return (
+            <ScrollView style={styles.topView}>
+              <NavigationExampleRow
+                text={`Current page: ${navState.children[navState.index].key}`}
+              />
+              <NavigationExampleRow
+                text={`Push page #${navState.children.length}`}
+                onPress={() => {
+                  onNavigate('page #' + navState.children.length);
+                }}
+              />
+              <NavigationExampleRow
+                text="pop"
+                onPress={() => {
+                  onNavigate(StackReducer.PopAction());
+                }}
+              />
+              <NavigationExampleRow
+                text="Exit Basic Nav Example"
+                onPress={this.props.onExampleExit}
+              />
+            </ScrollView>
+          );
+        }}
+      />
+    );
+  },
+});
+
+const styles = StyleSheet.create({
+  topView: {
+    backgroundColor: '#E9E9EF',
+    flex: 1,
+    paddingTop: 30,
+  },
+});
+
+module.exports = NavigationBasicExample;
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js
new file mode 100644
index 000000000000..1af4c63bbeb4
--- /dev/null
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js
@@ -0,0 +1,264 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+*/
+'use strict';
+
+const React = require('react-native');
+const {
+  NavigationExperimental,
+  ScrollView,
+  StyleSheet,
+  View,
+} = React;
+const {
+  AnimatedView: NavigationAnimatedView,
+  Card: NavigationCard,
+  Container: NavigationContainer,
+  RootContainer: NavigationRootContainer,
+  Header: NavigationHeader,
+  Reducer: NavigationReducer,
+  View: NavigationView,
+} = NavigationExperimental;
+const NavigationExampleRow = require('./NavigationExampleRow');
+const NavigationExampleTabBar = require('./NavigationExampleTabBar');
+
+const ExampleExitAction = () => ({
+  isExitAction: true,
+});
+ExampleExitAction.match = (action) => (
+  action && action.isExitAction === true
+);
+
+const ExamplePageAction = (type) => ({
+  type,
+  isPageAction: true,
+});
+ExamplePageAction.match = (action) => (
+  action && action.isPageAction === true
+);
+
+const ExampleSettingsPageAction = (type) => ({
+  ...ExamplePageAction(type),
+  isSettingsPageAction: true,
+});
+ExampleSettingsPageAction.match = (action) => (
+  action && action.isSettingsPageAction === true
+);
+
+const ExampleInfoAction = () => ExamplePageAction('InfoPage');
+
+const ExampleNotifSettingsAction = () => ExampleSettingsPageAction('NotifSettingsPage');
+
+const _jsInstanceUniqueId = '' + Date.now();
+let _uniqueIdCount = 0;
+function pageStateActionMap(action) {
+  return {
+    key: 'page-' + _jsInstanceUniqueId + '-' + (_uniqueIdCount++),
+    type: action.type,
+  };
+}
+
+function getTabActionMatcher(key) {
+  return function (action) {
+    if (!ExamplePageAction.match(action)) {
+      return false;
+    }
+    if (ExampleSettingsPageAction.match(action)) {
+      return key === 'settings';
+    }
+    return true;
+  };
+}
+
+var ExampleTabs = [
+  {
+    label: 'Account',
+    reducer: NavigationReducer.StackReducer({
+      initialStates: [
+        {type: 'AccountPage', key: 'base'}
+      ],
+      key: 'account',
+      matchAction: getTabActionMatcher('account'),
+      actionStateMap: pageStateActionMap,
+    }),
+  },
+  {
+    label: 'Notifications',
+    reducer: NavigationReducer.StackReducer({
+      initialStates: [
+        {type: 'NotifsPage', key: 'base'}
+      ],
+      key: 'notifs',
+      matchAction: getTabActionMatcher('notifs'),
+      actionStateMap: pageStateActionMap,
+    }),
+  },
+  {
+    label: 'Settings',
+    reducer: NavigationReducer.StackReducer({
+      initialStates: [
+        {type: 'SettingsPage', key: 'base'}
+      ],
+      key: 'settings',
+      matchAction: getTabActionMatcher('settings'),
+      actionStateMap: pageStateActionMap,
+    }),
+  },
+];
+
+const ExampleAppReducer = NavigationReducer.TabsReducer({
+  tabReducers: ExampleTabs.map(tab => tab.reducer),
+});
+
+function stateTypeTitleMap(pageState) {
+  switch (pageState.type) {
+    case 'AccountPage':
+      return 'Account Page';
+    case 'NotifsPage':
+      return 'Notifications';
+    case 'SettingsPage':
+      return 'Settings';
+    case 'InfoPage':
+      return 'Info Page';
+    case 'NotifSettingsPage':
+      return 'Notification Settings';
+  }
+}
+
+let ExampleTabScreen = React.createClass({
+  render: function() {
+    return (
+      <NavigationAnimatedView
+        style={styles.tabContent}
+        navigationState={this.props.navigationState}
+        renderOverlay={this._renderHeader}
+        renderScene={this._renderScene}
+      />
+    );
+  },
+  _renderHeader: function(position, layout) {
+    return (
+      <NavigationHeader
+        navigationState={this.props.navigationState}
+        position={position}
+        layout={layout}
+        getTitle={state => stateTypeTitleMap(state)}
+      />
+    );
+  },
+  _renderScene: function(child, index, position, layout) {
+    return (
+      <NavigationCard
+        key={child.key}
+        index={index}
+        childState={child}
+        navigationState={this.props.navigationState}
+        position={position}
+        layout={layout}>
+        <ScrollView style={styles.scrollView}>
+          <NavigationExampleRow
+            text="Open page"
+            onPress={() => {
+              this.props.onNavigate(ExampleInfoAction());
+            }}
+          />
+          <NavigationExampleRow
+            text="Open notifs settings in settings tab"
+            onPress={() => {
+              this.props.onNavigate(ExampleNotifSettingsAction());
+            }}
+          />
+          <NavigationExampleRow
+            text="Exit Composition Example"
+            onPress={() => {
+              this.props.onNavigate(ExampleExitAction());
+            }}
+          />
+        </ScrollView>
+      </NavigationCard>
+    );
+  },
+});
+ExampleTabScreen = NavigationContainer.create(ExampleTabScreen);
+
+const NavigationCompositionExample = React.createClass({
+  render: function() {
+    return (
+      <NavigationRootContainer
+        reducer={ExampleAppReducer}
+        persistenceKey="NavigationCompositionExampleState"
+        renderNavigation={this.renderApp}
+      />
+    );
+  },
+  renderApp: function(navigationState, onNavigate) {
+    if (!navigationState) {
+      return null;
+    }
+    return (
+      <View style={styles.topView}>
+        <ExampleMainView
+          navigationState={navigationState}
+          onExampleExit={this.props.onExampleExit}
+        />
+        <NavigationExampleTabBar
+          tabs={navigationState.children}
+          index={navigationState.index}
+        />
+      </View>
+    );
+  },
+});
+
+let ExampleMainView = React.createClass({
+  render: function() {
+    return (
+      <NavigationView
+        navigationState={this.props.navigationState}
+        style={styles.tabsContent}
+        renderScene={(tabState, index) => (
+          <ExampleTabScreen
+            key={tabState.key}
+            navigationState={tabState}
+            onNavigate={this._handleNavigation.bind(null, tabState.key)}
+          />
+        )}
+      />
+    );
+  },
+  _handleNavigation: function(tabKey, action) {
+    if (ExampleExitAction.match(action)) {
+      this.props.onExampleExit();
+      return;
+    }
+    this.props.onNavigate(action);
+  },
+});
+ExampleMainView = NavigationContainer.create(ExampleMainView);
+
+const styles = StyleSheet.create({
+  topView: {
+    flex: 1,
+  },
+  tabsContent: {
+    flex: 1,
+  },
+  scrollView: {
+    marginTop: 64
+  },
+  tabContent: {
+    flex: 1,
+  },
+});
+
+module.exports = NavigationCompositionExample;
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationExampleRow.js b/Examples/UIExplorer/NavigationExperimental/NavigationExampleRow.js
new file mode 100644
index 000000000000..4e431e30a722
--- /dev/null
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationExampleRow.js
@@ -0,0 +1,65 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+*/
+'use strict';
+
+var React = require('react-native');
+var {
+  Text,
+  PixelRatio,
+  StyleSheet,
+  View,
+  TouchableHighlight,
+} = React;
+
+var NavigationExampleRow = React.createClass({
+  render: function() {
+    if (this.props.onPress) {
+      return (
+        <TouchableHighlight
+          style={styles.row}
+          underlayColor="#D0D0D0"
+          onPress={this.props.onPress}>
+          <Text style={styles.buttonText}>
+            {this.props.text}
+          </Text>
+        </TouchableHighlight>
+      );
+    }
+    return (
+      <View style={styles.row}>
+        <Text style={styles.rowText}>
+          {this.props.text}
+        </Text>
+      </View>
+    );
+  },
+});
+
+const styles = StyleSheet.create({
+  row: {
+    padding: 15,
+    backgroundColor: 'white',
+    borderBottomWidth: 1 / PixelRatio.get(),
+    borderBottomColor: '#CDCDCD',
+  },
+  rowText: {
+    fontSize: 17,
+  },
+  buttonText: {
+    fontSize: 17,
+    fontWeight: '500',
+  },
+});
+
+module.exports = NavigationExampleRow;
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationExampleTabBar.js b/Examples/UIExplorer/NavigationExperimental/NavigationExampleTabBar.js
new file mode 100644
index 000000000000..6dbaab095b9b
--- /dev/null
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationExampleTabBar.js
@@ -0,0 +1,81 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+*/
+'use strict';
+
+var React = require('react-native');
+var {
+  NavigationExperimental,
+  StyleSheet,
+  Text,
+  TouchableOpacity,
+  View,
+} = React;
+const {
+  Container: NavigationContainer,
+  Reducer: NavigationReducer,
+} = NavigationExperimental;
+const {
+  JumpToAction,
+} = NavigationReducer.TabsReducer;
+
+var NavigationExampleTabBar = React.createClass({
+  render: function() {
+    return (
+      <View style={styles.tabBar}>
+        {this.props.tabs.map(this._renderTab)}
+      </View>
+    );
+  },
+  _renderTab: function(tab, index) {
+    var textStyle = [styles.tabButtonText];
+    if (this.props.index === index) {
+      textStyle.push(styles.selectedTabButtonText);
+    }
+    return (
+      <TouchableOpacity
+        style={styles.tabButton}
+        key={tab.key}
+        onPress={() => {
+          this.props.onNavigate(JumpToAction(index));
+        }}>
+        <Text style={textStyle}>
+          {tab.key}
+        </Text>
+      </TouchableOpacity>
+    );
+  },
+});
+
+NavigationExampleTabBar = NavigationContainer.create(NavigationExampleTabBar);
+
+const styles = StyleSheet.create({
+  tabBar: {
+    height: 50,
+    flexDirection: 'row',
+  },
+  tabButton: {
+    flex: 1,
+  },
+  tabButtonText: {
+    paddingTop: 20,
+    textAlign: 'center',
+    fontSize: 17,
+    fontWeight: '500',
+  },
+  selectedTabButtonText: {
+    color: 'blue',
+  },
+});
+
+module.exports = NavigationExampleTabBar;
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js
new file mode 100644
index 000000000000..0d11a8e649fc
--- /dev/null
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js
@@ -0,0 +1,129 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+*/
+'use strict';
+
+var React = require('react-native');
+var {
+  AsyncStorage,
+  ScrollView,
+  StyleSheet,
+  View,
+} = React;
+var NavigationExampleRow = require('./NavigationExampleRow');
+
+/*
+ * Heads up! This file is not the real navigation example- only a utility to switch between them.
+ *
+ * To learn how to use the Navigation API, take a look at the following exmample files:
+ */
+var EXAMPLES = {
+  'Tabs': require('./NavigationTabsExample'),
+  'Basic': require('./NavigationBasicExample'),
+  'Animated Card Stack': require('./NavigationAnimatedExample'),
+  'Composition': require('./NavigationCompositionExample'),
+};
+
+var EXAMPLE_STORAGE_KEY = 'NavigationExampleExample';
+
+var NavigationExperimentalExample = React.createClass({
+  statics: {
+    title: 'Navigation (Experimental)',
+    description: 'Upcoming navigation APIs and animated navigation views',
+    external: true,
+  },
+
+  getInitialState: function() {
+    return {
+      exampe: null,
+    };
+  },
+
+  componentDidMount() {
+    AsyncStorage.getItem(EXAMPLE_STORAGE_KEY, (err, example) => {
+      if (err || !example) {
+        this.setState({
+          example: 'menu',
+        });
+        return;
+      }
+      this.setState({
+        example,
+      });
+    });
+  },
+
+  setExample: function(example) {
+    this.setState({
+      example,
+    });
+    AsyncStorage.setItem(EXAMPLE_STORAGE_KEY, example);
+  },
+
+  _renderMenu: function() {
+    var exitRow = null;
+    if (this.props.onExampleExit) {
+      exitRow = (
+        <NavigationExampleRow
+          text="Exit Navigation Examples"
+          onPress={this.props.onExampleExit}
+        />
+      );
+    }
+    return (
+      <View style={styles.menu}>
+        <ScrollView>
+          {this._renderExampleList()}
+          {exitRow}
+        </ScrollView>
+      </View>
+    );
+  },
+
+  _renderExampleList: function() {
+    return Object.keys(EXAMPLES).map(exampleName => (
+      <NavigationExampleRow
+        key={exampleName}
+        text={exampleName}
+        onPress={() => {
+          this.setExample(exampleName);
+        }}
+      />
+    ));
+  },
+
+  _exitInnerExample: function() {
+    this.setExample('menu');
+  },
+
+  render: function() {
+    if (this.state.example === 'menu') {
+      return this._renderMenu();
+    }
+    if (EXAMPLES[this.state.example]) {
+      var Component = EXAMPLES[this.state.example];
+      return <Component onExampleExit={this._exitInnerExample} />;
+    }
+    return null;
+  },
+});
+
+const styles = StyleSheet.create({
+  menu: {
+    backgroundColor: '#E9E9EF',
+    flex: 1,
+    marginTop: 20,
+  },
+});
+
+module.exports = NavigationExperimentalExample;
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationTabsExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationTabsExample.js
new file mode 100644
index 000000000000..beb3a6e35af3
--- /dev/null
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationTabsExample.js
@@ -0,0 +1,104 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+*/
+'use strict';
+
+const React = require('react-native');
+const {
+  NavigationExperimental,
+  ScrollView,
+  StyleSheet,
+  View,
+} = React;
+const {
+  Container: NavigationContainer,
+  RootContainer: NavigationRootContainer,
+  Reducer: NavigationReducer,
+} = NavigationExperimental;
+
+const NavigationExampleRow = require('./NavigationExampleRow');
+const NavigationExampleTabBar = require('./NavigationExampleTabBar');
+
+class ExmpleTabPage extends React.Component {
+  render() {
+    const currentTabRoute = this.props.tabs[this.props.index];
+    return (
+      <ScrollView style={styles.tabPage}>
+        <NavigationExampleRow
+          text={`Current Tab is: ${currentTabRoute.key}`}
+        />
+        {this.props.tabs.map((tab, index) => (
+          <NavigationExampleRow
+            key={tab.key}
+            text={`Go to ${tab.key}`}
+            onPress={() => {
+              this.props.onNavigate(NavigationReducer.TabsReducer.JumpToAction(index));
+            }}
+          />
+        ))}
+        <NavigationExampleRow
+          text="Exit Tabs Example"
+          onPress={this.props.onExampleExit}
+        />
+      </ScrollView>
+    );
+  }
+}
+ExmpleTabPage = NavigationContainer.create(ExmpleTabPage);
+
+const ExampleTabsReducer = NavigationReducer.TabsReducer({
+  tabReducers: [
+    (lastRoute) => lastRoute || {key: 'one'},
+    (lastRoute) => lastRoute || {key: 'two'},
+    (lastRoute) => lastRoute || {key: 'three'},
+  ],
+});
+
+const NavigationTabsExample = React.createClass({
+  render: function() {
+    return (
+      <NavigationRootContainer
+        reducer={ExampleTabsReducer}
+        persistenceKey="NAV_EXAMPLE_STATE_TABS"
+        renderNavigation={(navigationState) => {
+          if (!navigationState) { return null; }
+          return (
+            <View style={styles.topView}>
+              <ExmpleTabPage
+                tabs={navigationState.children}
+                index={navigationState.index}
+                onExampleExit={this.props.onExampleExit}
+              />
+              <NavigationExampleTabBar
+                tabs={navigationState.children}
+                index={navigationState.index}
+              />
+            </View>
+          );
+        }}
+      />
+    );
+  },
+});
+
+const styles = StyleSheet.create({
+  topView: {
+    flex: 1,
+    paddingTop: 30,
+  },
+  tabPage: {
+    backgroundColor: '#E9E9EF',
+  },
+});
+
+module.exports = NavigationTabsExample;
diff --git a/Examples/UIExplorer/UIExplorerList.ios.js b/Examples/UIExplorer/UIExplorerList.ios.js
index 1cd0eaaaf0b5..5c33d7f645e5 100644
--- a/Examples/UIExplorer/UIExplorerList.ios.js
+++ b/Examples/UIExplorer/UIExplorerList.ios.js
@@ -74,6 +74,7 @@ var APIS = [
   require('./GeolocationExample'),
   require('./ImageEditingExample'),
   require('./LayoutExample'),
+  require('./NavigationExperimental/NavigationExperimentalExample'),
   require('./NetInfoExample'),
   require('./PanResponderExample'),
   require('./PointerEventsExample'),
diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationCard.js b/Libraries/CustomComponents/NavigationExperimental/NavigationCard.js
new file mode 100644
index 000000000000..d25c45aefdec
--- /dev/null
+++ b/Libraries/CustomComponents/NavigationExperimental/NavigationCard.js
@@ -0,0 +1,160 @@
+/**
+ * Copyright (c) 2015, Facebook, Inc.  All rights reserved.
+ *
+ * Facebook, Inc. ("Facebook") owns all right, title and interest, including
+ * all intellectual property and other proprietary rights, in and to the React
+ * Native CustomComponents software (the "Software").  Subject to your
+ * compliance with these terms, you are hereby granted a non-exclusive,
+ * worldwide, royalty-free copyright license to (1) use and copy the Software;
+ * and (2) reproduce and distribute the Software as part of your own software
+ * ("Your Software").  Facebook reserves all rights not expressly granted to
+ * you in this license agreement.
+ *
+ * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "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 FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
+ * EMPLOYEES 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 THE SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @providesModule NavigationCard
+ * @flow
+ */
+'use strict';
+
+const Animated = require('Animated');
+const NavigationReducer = require('NavigationReducer');
+const NavigationContainer = require('NavigationContainer');
+const PanResponder = require('PanResponder');
+const React = require('React');
+const StyleSheet = require('StyleSheet');
+const View = require('View');
+
+import type {
+  NavigationParentState
+} from 'NavigationState';
+
+type Layout = {
+  initWidth: number,
+  initHeight: number,
+  width: Animated.Value;
+  height: Animated.Value;
+};
+
+type Props = {
+  navigationState: NavigationParentState;
+  index: number;
+  position: Animated.Value;
+  layout: Layout;
+  onNavigate: Function;
+  children: Object;
+};
+
+class NavigationCard extends React.Component {
+  _responder: ?Object;
+  _lastHeight: number;
+  _lastWidth: number;
+  _widthListener: string;
+  _heightListener: string;
+  props: Props;
+  componentWillMount(props) {
+    this._responder = PanResponder.create({
+      onMoveShouldSetPanResponder: (e, {dx, dy, moveX, moveY, x0, y0}) => {
+        if (this.props.navigationState.index === 0) {
+          return false;
+        }
+        if (moveX > 30) {
+          return false;
+        }
+        if (dx > 5 && Math.abs(dy) < 4) {
+          return true;
+        }
+        return false;
+      },
+      onPanResponderGrant: (e, {dx, dy, moveX, moveY, x0, y0}) => {
+      },
+      onPanResponderMove: (e, {dx}) => {
+        const a = (-dx / this._lastWidth) + this.props.navigationState.index;
+        this.props.position.setValue(a);
+      },
+      onPanResponderRelease: (e, {vx, dx}) => {
+        const xRatio = dx / this._lastWidth;
+        const doesPop = (xRatio + vx) > 0.45;
+        if (doesPop) {
+          // todo: add an action which accepts velocity of the pop action/gesture, which is caught and used by NavigationAnimatedView
+          this.props.onNavigate(NavigationReducer.StackReducer.PopAction());
+          return;
+        }
+        Animated.spring(this.props.position, {
+          toValue: this.props.navigationState.index,
+        }).start();
+      },
+      onPanResponderTerminate: (e, {vx, dx}) => {
+        Animated.spring(this.props.position, {
+          toValue: this.props.navigationState.index,
+        }).start();
+      },
+    });
+  }
+  componentDidMount() {
+    this._lastHeight = this.props.layout.initHeight;
+    this._lastWidth = this.props.layout.initWidth;
+    this._widthListener = this.props.layout.width.addListener(({value}) => {
+      this._lastWidth = value;
+    });
+    this._heightListener = this.props.layout.height.addListener(({value}) => {
+      this._lastHeight = value;
+    });
+    // todo: fix listener and last layout dimentsions when props change. potential bugs here
+  }
+  componentWillUnmount() {
+    this.props.layout.width.removeListener(this._widthListener);
+    this.props.layout.height.removeListener(this._heightListener);
+  }
+  render() {
+    const cardPosition = Animated.add(this.props.position, new Animated.Value(-this.props.index));
+    const gestureValue = Animated.multiply(cardPosition, this.props.layout.width);
+    return (
+      <Animated.View
+        {...this._responder.panHandlers}
+        style={[
+          styles.card,
+          {
+            right: gestureValue,
+            left: gestureValue.interpolate({
+              inputRange: [0, 1],
+              outputRange: [0, -1],
+            }),
+            opacity: cardPosition.interpolate({
+              inputRange: [-1,0,1],
+              outputRange: [0,1,1],
+            }),
+          }
+        ]}>
+        {this.props.children}
+      </Animated.View>
+    );
+  }
+}
+
+NavigationCard = NavigationContainer.create(NavigationCard);
+
+const styles = StyleSheet.create({
+  card: {
+    backgroundColor: '#E9E9EF',
+    shadowColor: 'black',
+    shadowOpacity: 0.4,
+    shadowOffset: {width: 0, height: 0},
+    shadowRadius: 10,
+    top: 0,
+    bottom: 0,
+    position: 'absolute',
+  },
+});
+
+module.exports = NavigationCard;
diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationHeader.js b/Libraries/CustomComponents/NavigationExperimental/NavigationHeader.js
new file mode 100644
index 000000000000..98a4c5e9140c
--- /dev/null
+++ b/Libraries/CustomComponents/NavigationExperimental/NavigationHeader.js
@@ -0,0 +1,149 @@
+/**
+ * Copyright (c) 2015, Facebook, Inc.  All rights reserved.
+ *
+ * Facebook, Inc. ("Facebook") owns all right, title and interest, including
+ * all intellectual property and other proprietary rights, in and to the React
+ * Native CustomComponents software (the "Software").  Subject to your
+ * compliance with these terms, you are hereby granted a non-exclusive,
+ * worldwide, royalty-free copyright license to (1) use and copy the Software;
+ * and (2) reproduce and distribute the Software as part of your own software
+ * ("Your Software").  Facebook reserves all rights not expressly granted to
+ * you in this license agreement.
+ *
+ * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "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 FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
+ * EMPLOYEES 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 THE SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @providesModule NavigationHeader
+ * @flow
+ */
+'use strict';
+
+const Animated = require('Animated');
+const Image = require('Image');
+const NavigationContainer = require('NavigationContainer');
+const NavigationReducer = require('NavigationReducer');
+const React = require('react-native');
+const StyleSheet = require('StyleSheet');
+const Text = require('Text');
+const TouchableOpacity = require('TouchableOpacity');
+const View = require('View');
+
+import type {
+  NavigationState,
+  NavigationParentState
+} from 'NavigationState';
+
+type Props = {
+  navigationState: NavigationParentState,
+  onNavigate: Function,
+  position: Animated.Value,
+  getTitle: (navState: NavigationState) => string,
+};
+
+class NavigationHeader extends React.Component {
+  _handleBackPress: Function;
+  props: Props;
+  componentWillMount() {
+    this._handleBackPress = this._handleBackPress.bind(this);
+  }
+  render() {
+    var state = this.props.navigationState;
+    return (
+      <Animated.View
+        style={[
+          styles.header,
+        ]}>
+        {state.children.map(this._renderTitle, this)}
+        {this._renderBackButton()}
+      </Animated.View>
+    );
+  }
+  _renderBackButton() {
+    if (this.props.navigationState.index === 0) {
+      return null;
+    }
+    return (
+      <TouchableOpacity style={styles.backButton} onPress={this._handleBackPress}>
+        <Image source={require('./back_chevron.png')} style={styles.backButtonImage} />
+      </TouchableOpacity>
+    );
+  }
+  _renderTitle(childState, index) {
+    return (
+      <Animated.Text
+        key={childState.key}
+        style={[
+          styles.title,
+          {
+            opacity: this.props.position.interpolate({
+              inputRange: [index - 1, index, index + 1],
+              outputRange: [0, 1, 0],
+            }),
+            left: this.props.position.interpolate({
+              inputRange: [index - 1, index + 1],
+              outputRange: [200, -200],
+            }),
+            right: this.props.position.interpolate({
+              inputRange: [index - 1, index + 1],
+              outputRange: [-200, 200],
+            }),
+          },
+        ]}>
+        {this.props.getTitle(childState)}
+      </Animated.Text>
+    );
+  }
+  _handleBackPress() {
+    this.props.onNavigate(NavigationReducer.StackReducer.PopAction());
+  }
+}
+
+NavigationHeader = NavigationContainer.create(NavigationHeader);
+
+const styles = StyleSheet.create({
+  title: {
+    textAlign: 'center',
+    marginTop: 10,
+    fontSize: 18,
+    fontWeight: '500',
+    color: '#0A0A0A',
+    position: 'absolute',
+    top: 20,
+    left: 0,
+    right: 0,
+  },
+  header: {
+    backgroundColor: '#EFEFF2',
+    paddingTop: 20,
+    top: 0,
+    height: 64,
+    right: 0,
+    left: 0,
+    borderBottomWidth: 0.5,
+    borderBottomColor: '#828287',
+    position: 'absolute',
+  },
+  backButton: {
+    width: 29,
+    height: 37,
+    position: 'absolute',
+    bottom: 4,
+    left: 2,
+    padding: 8,
+  },
+  backButtonImage: {
+    width: 13,
+    height: 21,
+  },
+});
+
+module.exports = NavigationHeader;
diff --git a/Libraries/CustomComponents/NavigationExperimental/back_chevron.png b/Libraries/CustomComponents/NavigationExperimental/back_chevron.png
new file mode 100644
index 0000000000000000000000000000000000000000..af21cf9d5718b71d1d2be0c445fa7f6012813609
GIT binary patch
diff --git a/Libraries/NavigationExperimental/NavigationAnimatedView.js b/Libraries/NavigationExperimental/NavigationAnimatedView.js
new file mode 100644
index 000000000000..8e6dce680452
--- /dev/null
+++ b/Libraries/NavigationExperimental/NavigationAnimatedView.js
@@ -0,0 +1,225 @@
+/**
+ * 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 NavigationAnimatedView
+ * @flow
+ */
+'use strict';
+
+var Animated = require('Animated');
+var Map = require('Map');
+var NavigationStateUtils = require('NavigationState');
+var NavigationContainer = require('NavigationContainer');
+var React = require('react-native');
+var View = require('View');
+
+import type {
+  NavigationState,
+  NavigationParentState,
+} from 'NavigationState';
+
+type NavigationScene = {
+  index: number,
+  state: NavigationState,
+  isStale: boolean,
+};
+
+/**
+ * Helper function to compare route keys (e.g. "9", "11").
+ */
+function compareKey(one: string, two: string): number {
+  var delta = one.length - two.length;
+  if (delta > 0) {
+    return 1;
+  }
+  if (delta < 0) {
+    return -1;
+  }
+  return one > two ? 1 : -1;
+}
+
+/**
+ * Helper function to sort scenes based on their index and view key.
+ */
+function compareScenes(
+  one: NavigationScene,
+  two: NavigationScene
+): number {
+  if (one.index > two.index) {
+    return 1;
+  }
+  if (one.index < two.index) {
+    return -1;
+  }
+
+  return compareKey(
+    one.state.key,
+    two.state.key
+  );
+}
+
+type Layout = {
+  initWidth: number,
+  initHeight: number,
+  width: Animated.Value;
+  height: Animated.Value;
+};
+
+type OverlayRenderer = (
+  position: Animated.Value,
+  layout: Layout
+) => ReactElement;
+
+type SceneRenderer = (
+  state: NavigationState,
+  index: number,
+  position: Animated.Value,
+  layout: Layout
+) => ReactElement
+
+type Props = {
+  navigationState: NavigationParentState;
+  renderScene: SceneRenderer;
+  renderOverlay: ?OverlayRenderer;
+  style: any;
+};
+
+class NavigationAnimatedView extends React.Component {
+  _animatedHeight: Animated.Value;
+  _animatedWidth: Animated.Value;
+  _lastHeight: number;
+  _lastWidth: number;
+  props: Props;
+  constructor(props) {
+    super(props);
+    this._animatedHeight = new Animated.Value(0);
+    this._animatedWidth = new Animated.Value(0);
+    this.state = {
+      position: new Animated.Value(this.props.navigationState.index),
+      scenes: new Map(),
+    };
+  }
+  componentWillMount() {
+    this.setState({
+      scenes: this._reduceScenes(this.state.scenes, this.props.navigationState),
+    });
+  }
+  componentDidMount() {
+    this.postionListener = this.state.position.addListener(this._onProgressChange.bind(this));
+  }
+  componentWillReceiveProps(nextProps) {
+    if (nextProps.navigationState !== this.props.navigationState) {
+      this.setState({
+        scenes: this._reduceScenes(this.state.scenes, nextProps.navigationState, this.props.navigationState),
+      });
+    }
+  }
+  componentDidUpdate(lastProps) {
+    if (lastProps.navigationState.index !== this.props.navigationState.index) {
+      Animated.spring(
+        this.state.position,
+        {toValue: this.props.navigationState.index}
+      ).start();
+    }
+  }
+  componentWillUnmount() {
+    if (this.postionListener) {
+      this.state.position.removeListener(this.postionListener);
+      this.postionListener = null;
+    }
+  }
+  _onProgressChange(data: Object): void {
+    if (Math.abs(data.value - this.props.navigationState.index) > Number.EPSILON) {
+      return;
+    }
+    this.state.scenes.forEach((scene, index) => {
+      if (scene.isStale) {
+        const scenes = this.state.scenes.slice();
+        scenes.splice(index, 1);
+        this.setState({ scenes, });
+      }
+    });
+  }
+  _reduceScenes(
+    scenes: Array<NavigationScene>,
+    nextState: NavigationParentState,
+    lastState: ?NavigationParentState
+  ): Array<NavigationScene> {
+    let nextScenes = nextState.children.map((child, index) => {
+      return {
+        index,
+        state: child,
+        isStale: false,
+      };
+    });
+
+    if (lastState) {
+      lastState.children.forEach((child, index) => {
+        if (!NavigationStateUtils.get(nextState, child.key)) {
+          nextScenes.push({
+            index,
+            state: child,
+            isStale: true,
+          });
+        }
+      });
+    }
+
+    nextScenes = nextScenes.sort(compareScenes);
+
+    return nextScenes;
+  }
+  render() {
+    return (
+      <View
+        onLayout={(e) => {
+          const {height, width} = e.nativeEvent.layout;
+          this._animatedHeight &&
+            this._animatedHeight.setValue(height);
+          this._animatedWidth &&
+            this._animatedWidth.setValue(width);
+          this._lastHeight = height;
+          this._lastWidth = width;
+        }}
+        style={this.props.style}>
+        {this.state.scenes.map(this._renderScene, this)}
+        {this._renderOverlay(this._renderOverlay, this)}
+      </View>
+    );
+  }
+  _getLayout() {
+    return {
+      height: this._animatedHeight,
+      width: this._animatedWidth,
+      initWidth: this._lastWidth,
+      initHeight: this._lastHeight,
+    };
+  }
+  _renderScene(scene: NavigationScene) {
+    return this.props.renderScene(
+      scene.state,
+      scene.index,
+      this.state.position,
+      this._getLayout()
+    );
+  }
+  _renderOverlay() {
+    const {renderOverlay} = this.props;
+    if (renderOverlay) {
+      return renderOverlay(
+        this.state.position,
+        this._getLayout()
+      );
+    }
+    return null;
+  }
+}
+
+NavigationAnimatedView = NavigationContainer.create(NavigationAnimatedView);
+
+module.exports = NavigationAnimatedView;
diff --git a/Libraries/NavigationExperimental/NavigationContainer.js b/Libraries/NavigationExperimental/NavigationContainer.js
new file mode 100644
index 000000000000..8e178f1c6faa
--- /dev/null
+++ b/Libraries/NavigationExperimental/NavigationContainer.js
@@ -0,0 +1,51 @@
+/**
+ * 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 NavigationContainer
+ * @flow
+ */
+'use strict';
+
+var React = require('react-native');
+var NavigationRootContainer = require('NavigationRootContainer');
+
+function createNavigationContainer(Component: React.Component): React.Component {
+  class NavigationComponent extends React.Component {
+    render() {
+      return (
+        <Component
+          onNavigate={this.getNavigationHandler()}
+          {...this.props}
+        />
+      );
+    }
+    getNavigationHandler() {
+      return this.props.onNavigate || this.context.onNavigate;
+    }
+    getChildContext() {
+      return {
+        onNavigate: this.getNavigationHandler(),
+      };
+    }
+  }
+  NavigationComponent.contextTypes = {
+    onNavigate: React.PropTypes.func,
+  };
+  NavigationComponent.childContextTypes = {
+    onNavigate: React.PropTypes.func,
+  };
+  return NavigationComponent;
+}
+
+var NavigationContainer = {
+  create: createNavigationContainer,
+  RootContainer: NavigationRootContainer,
+};
+
+
+module.exports = NavigationContainer;
diff --git a/Libraries/NavigationExperimental/NavigationExperimental.js b/Libraries/NavigationExperimental/NavigationExperimental.js
new file mode 100644
index 000000000000..9d37015f6a17
--- /dev/null
+++ b/Libraries/NavigationExperimental/NavigationExperimental.js
@@ -0,0 +1,41 @@
+/**
+ * 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 NavigationExperimental
+ * @flow
+ */
+'use strict';
+
+const NavigationAnimatedView = require('NavigationAnimatedView');
+const NavigationCard = require('NavigationCard');
+const NavigationContainer = require('NavigationContainer');
+const NavigationHeader = require('NavigationHeader');
+const NavigationRootContainer = require('NavigationRootContainer');
+const NavigationReducer = require('NavigationReducer');
+const NavigationState = require('NavigationState');
+const NavigationView = require('NavigationView');
+
+const NavigationExperimental = {
+  // Core
+  State: NavigationState,
+  Reducer: NavigationReducer,
+
+  // Containers
+  Container: NavigationContainer,
+  RootContainer: NavigationRootContainer,
+
+  // Views
+  View: NavigationView,
+  AnimatedView: NavigationAnimatedView,
+
+  // CustomComponents:
+  Header: NavigationHeader,
+  Card: NavigationCard,
+};
+
+module.exports = NavigationExperimental;
diff --git a/Libraries/NavigationExperimental/NavigationRootContainer.js b/Libraries/NavigationExperimental/NavigationRootContainer.js
new file mode 100644
index 000000000000..a9beeba62741
--- /dev/null
+++ b/Libraries/NavigationExperimental/NavigationRootContainer.js
@@ -0,0 +1,86 @@
+/**
+ * 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 NavigationRootContainer
+ * @flow
+ */
+'use strict';
+
+var AsyncStorage = require('AsyncStorage');
+var React = require('React');
+
+import type {
+  NavigationState,
+  NavigationReducer
+} from 'NavigationState';
+
+type NavigationRenderer = (
+  navigationState: NavigationState,
+  onNavigate: Function
+) => ReactElement;
+
+type Props = {
+  renderNavigation: NavigationRenderer;
+  reducer: NavigationReducer;
+  persistenceKey: ?string;
+};
+
+class NavigationRootContainer extends React.Component {
+  props: Props;
+  constructor(props: Props) {
+    super(props);
+    this.handleNavigation = this.handleNavigation.bind(this);
+    let navState = null;
+    if (!this.props.persistenceKey) {
+      navState = this.props.reducer(null, null);
+    }
+    this.state = { navState };
+  }
+  componentDidMount() {
+    if (this.props.persistenceKey) {
+      AsyncStorage.getItem(this.props.persistenceKey, (err, storedString) => {
+        if (err || !storedString) {
+          this.setState({
+            navState: this.props.reducer(null, null),
+          });
+          return;
+        }
+        this.setState({
+          navState: JSON.parse(storedString),
+        });
+      });
+    }
+  }
+  getChildContext(): Object {
+    return {
+      onNavigate: this.handleNavigation,
+    };
+  }
+  handleNavigation(action: Object) {
+    const navState = this.props.reducer(this.state.navState, action);
+    this.setState({
+      navState,
+    });
+    if (this.props.persistenceKey) {
+      AsyncStorage.setItem(this.props.persistenceKey, JSON.stringify(navState));
+    }
+  }
+  render(): ReactElement {
+    var navigation = this.props.renderNavigation(
+      this.state.navState,
+      this.handleNavigation
+    );
+    return navigation;
+  }
+}
+
+NavigationRootContainer.childContextTypes = {
+  onNavigate: React.PropTypes.func,
+};
+
+module.exports = NavigationRootContainer;
diff --git a/Libraries/NavigationExperimental/NavigationState.js b/Libraries/NavigationExperimental/NavigationState.js
new file mode 100644
index 000000000000..8ef085fd9b2a
--- /dev/null
+++ b/Libraries/NavigationExperimental/NavigationState.js
@@ -0,0 +1,196 @@
+/**
+ * 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 NavigationState
+ * @flow
+ */
+'use strict';
+
+const invariant = require('invariant');
+
+export type NavigationState = {
+  key: string;
+};
+
+export type NavigationParentState = {
+  key: string;
+  index: number;
+  children: Array<NavigationState>;
+};
+
+export type NavigationReducer = (
+  state: ?NavigationState,
+  action: ?any
+) => ?NavigationState;
+
+export type NavigationReducerWithDefault = (
+  state: ?NavigationState,
+  action: ?any
+) => NavigationState;
+
+export function getParent(state: NavigationState): ?NavigationParentState {
+  if (
+    (state instanceof Object) &&
+    (state.children instanceof Array) &&
+    (state.children[0] !== undefined) &&
+    (typeof state.index === 'number') &&
+    (state.children[state.index] !== undefined)
+  ) {
+    return state;
+  }
+  return null;
+}
+
+export function get(state: NavigationState, key: string): ?NavigationState {
+  const parentState = getParent(state);
+  if (!parentState) {
+    return null;
+  }
+  const childState = parentState.children.find(child => child.key === key);
+  return childState || null;
+}
+
+export function indexOf(state: NavigationState, key: string): ?number {
+  const parentState = getParent(state);
+  if (!parentState) {
+    return null;
+  }
+  const index = parentState.children.map(child => child.key).indexOf(key);
+  if (index === -1) {
+    return null;
+  }
+  return index;
+}
+
+export function push(state: NavigationState, newChildState: NavigationState): NavigationState {
+  const parentState = getParent(state);
+  if (!parentState) {
+    return state;
+  }
+  var lastChildren: Array<NavigationState> = parentState.children;
+  return {
+    ...parentState,
+    children: [
+      ...lastChildren,
+      newChildState,
+    ],
+    index: lastChildren.length,
+  };
+}
+
+export function pop(state: NavigationState): NavigationState {
+  const parentState = getParent(state);
+  if (!parentState) {
+    return state;
+  }
+  const lastChildren = parentState.children;
+  return {
+    ...parentState,
+    children: lastChildren.slice(0, lastChildren.length - 1),
+    index: lastChildren.length - 2,
+  };
+}
+
+export function reset(state: NavigationState, nextChildren: ?Array<NavigationState>, nextIndex: ?number): NavigationState {
+  const parentState = getParent(state);
+  if (!parentState) {
+    return state;
+  }
+  const children = nextChildren || parentState.children;
+  const index = nextIndex == null ? parentState.index : nextIndex;
+  if (children === parentState.children && index === parentState.index) {
+    return state;
+  }
+  return {
+    ...parentState,
+    children,
+    index,
+  };
+}
+
+export function set(state: ?NavigationState, key: string, nextChildren: Array<NavigationState>, nextIndex: number): NavigationState {
+  if (!state) {
+    return {
+      children: nextChildren,
+      index: nextIndex,
+      key,
+    };
+  }
+  const parentState = getParent(state);
+  if (!parentState) {
+    return {
+      children: nextChildren,
+      index: nextIndex,
+      key,
+    };
+  }
+  if (nextChildren === parentState.children && nextIndex === parentState.index && key === parentState.key) {
+    return parentState;
+  }
+  return {
+    ...parentState,
+    children: nextChildren,
+    index: nextIndex,
+    key,
+  };
+}
+
+export function jumpToIndex(state: NavigationState, index: number): NavigationState {
+  const parentState = getParent(state);
+  return {
+    ...parentState,
+    index,
+  };
+}
+
+export function jumpTo(state: NavigationState, key: string): NavigationState {
+  const parentState = getParent(state);
+  if (!parentState) {
+    return state;
+  }
+  const index = parentState.children.indexOf(parentState.children.find(child => child.key === key));
+  invariant(
+    index !== -1,
+    'Cannot find child with matching key in this NavigationState'
+  );
+  return {
+    ...parentState,
+    index,
+  };
+}
+
+export function replaceAt(state: NavigationState, key: string, newState: NavigationState): NavigationState {
+  const parentState = getParent(state);
+  if (!parentState) {
+    return state;
+  }
+  const children = [...parentState.children];
+  const index = parentState.children.indexOf(parentState.children.find(child => child.key === key));
+  invariant(
+    index !== -1,
+    'Cannot find child with matching key in this NavigationState'
+  );
+  children[index] = newState;
+  return {
+    ...parentState,
+    children,
+  };
+}
+
+export function replaceAtIndex(state: NavigationState, index: number, newState: NavigationState): NavigationState {
+  const parentState = getParent(state);
+  if (!parentState) {
+    return state;
+  }
+  const children = [...parentState.children];
+  children[index] = newState;
+  return {
+    ...parentState,
+    children,
+  };
+}
diff --git a/Libraries/NavigationExperimental/NavigationView.js b/Libraries/NavigationExperimental/NavigationView.js
new file mode 100644
index 000000000000..5e0fc8b28f71
--- /dev/null
+++ b/Libraries/NavigationExperimental/NavigationView.js
@@ -0,0 +1,63 @@
+/**
+ * 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 NavigationView
+ * @flow
+ */
+'use strict';
+
+var React = require('react-native');
+var NavigationContainer = require('NavigationContainer');
+var {
+  StyleSheet,
+  View,
+} = React;
+
+var NavigationView = React.createClass({
+  propTypes: {
+    // todo, figure out a propType for getK
+    navigationState: React.PropTypes.object.isRequired,
+    renderScene: React.PropTypes.func.isRequired,
+  },
+  render: function() {
+    return (
+      <View
+        style={this.props.style}>
+        {this.props.navigationState.children.map(this._renderScene)}
+      </View>
+    );
+  },
+  _renderScene: function(route, index) {
+    var isSelected = index === this.props.navigationState.index;
+    return (
+      <View
+        key={route.key}
+        pointerEvents={isSelected ? 'auto' : 'none'}
+        style={[
+          styles.navView,
+          {opacity: isSelected ? 1 : 0},
+        ]}>
+        {this.props.renderScene(route, index)}
+      </View>
+    );
+  },
+});
+
+NavigationView = NavigationContainer.create(NavigationView);
+
+var styles = StyleSheet.create({
+  navView: {
+    position: 'absolute',
+    left: 0,
+    right: 0,
+    top: 0,
+    bottom: 0,
+  },
+});
+
+module.exports = NavigationView;
diff --git a/Libraries/NavigationExperimental/Reducer/NavigationFindReducer.js b/Libraries/NavigationExperimental/Reducer/NavigationFindReducer.js
new file mode 100644
index 000000000000..db8bb8f40071
--- /dev/null
+++ b/Libraries/NavigationExperimental/Reducer/NavigationFindReducer.js
@@ -0,0 +1,38 @@
+/**
+ * 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 NavigationFindReducer
+ * @flow
+ */
+'use strict';
+
+/*
+ * NavigationFindReducer takes an array of reducers, and returns a reducer that
+ * iterates through all of the reducers and the result of the first reducer
+ * that modifies the input
+ */
+
+import type {
+  NavigationState,
+  NavigationReducer
+} from 'NavigationState';
+
+function NavigationFindReducer(reducers: Array<NavigationReducer>): ?NavigationReducer {
+  return function(lastState: ?NavigationState, action: ?any): ?NavigationState {
+    for (let i = 0; i < reducers.length; i++) {
+      let reducer = reducers[i];
+      let newState = reducer(lastState, action);
+      if (newState !== lastState) {
+        return newState;
+      }
+    }
+    return lastState;
+  };
+}
+
+module.exports = NavigationFindReducer;
diff --git a/Libraries/NavigationExperimental/Reducer/NavigationReducer.js b/Libraries/NavigationExperimental/Reducer/NavigationReducer.js
new file mode 100644
index 000000000000..4fb52297daaa
--- /dev/null
+++ b/Libraries/NavigationExperimental/Reducer/NavigationReducer.js
@@ -0,0 +1,24 @@
+/**
+ * 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 NavigationReducer
+ * @flow
+ */
+'use strict';
+
+var NavigationFindReducer = require('NavigationFindReducer');
+var NavigationStackReducer = require('NavigationStackReducer');
+var NavigationTabsReducer = require('NavigationTabsReducer');
+
+const NavigationReducer = {
+  FindReducer: NavigationFindReducer,
+  StackReducer: NavigationStackReducer,
+  TabsReducer: NavigationTabsReducer,
+};
+
+module.exports = NavigationReducer;
diff --git a/Libraries/NavigationExperimental/Reducer/NavigationStackReducer.js b/Libraries/NavigationExperimental/Reducer/NavigationStackReducer.js
new file mode 100644
index 000000000000..7aec5f4ee4cd
--- /dev/null
+++ b/Libraries/NavigationExperimental/Reducer/NavigationStackReducer.js
@@ -0,0 +1,141 @@
+/**
+ * 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 NavigationStackReducer
+ * @flow
+ */
+'use strict';
+
+var NavigationStateUtils = require('NavigationState');
+
+import type {
+  NavigationState,
+  NavigationReducer,
+} from 'NavigationState';
+
+export type NavigationStackReducerAction = {
+  type: string,
+};
+
+const ActionTypes = {
+  PUSH: 'react-native/NavigationExperimental/stack-push',
+  POP: 'react-native/NavigationExperimental/stack-pop',
+  JUMP_TO: 'react-native/NavigationExperimental/stack-jumpTo',
+  JUMP_TO_INDEX: 'react-native/NavigationExperimental/stack-jumpToIndex',
+  RESET: 'react-native/NavigationExperimental/stack-reset',
+};
+
+const DEFAULT_KEY = 'NAV_STACK_DEFAULT_KEY';
+
+function NavigationStackPushAction(state: NavigationState): NavigationStackReducerAction {
+  return {
+    type: ActionTypes.PUSH,
+    state,
+  };
+}
+
+function NavigationStackPopAction(): NavigationStackReducerAction {
+  return {
+    type: ActionTypes.POP,
+  };
+}
+
+function NavigationStackJumpToAction(key: string): NavigationStackReducerAction {
+  return {
+    type: ActionTypes.JUMP_TO,
+    key,
+  };
+}
+
+function NavigationStackJumpToIndexAction(index: number): NavigationStackReducerAction {
+  return {
+    type: ActionTypes.JUMP_TO_INDEX,
+    index,
+  };
+}
+
+function NavigationStackResetAction(children: Array<NavigationState>, index: number): NavigationStackReducerAction {
+  return {
+    type: ActionTypes.RESET,
+    index,
+    children,
+  };
+}
+
+type StackReducerConfig = {
+  initialStates: Array<NavigationState>;
+  initialIndex: ?number;
+  key: ?string;
+  matchAction: (action: any) => boolean;
+  actionStateMap: (action: any) => NavigationState;
+};
+
+function NavigationStackReducer({initialStates, initialIndex, key, matchAction, actionStateMap}: StackReducerConfig): NavigationReducer {
+  return function (lastState: ?NavigationState, action: any): NavigationState {
+    if (key == null) {
+      key = DEFAULT_KEY;
+    }
+    if (initialIndex == null) {
+      initialIndex = initialStates.length - 1;
+    }
+    if (!lastState) {
+      lastState = {
+        index: initialIndex,
+        children: initialStates,
+        key,
+      };
+    }
+    const lastParentState = NavigationStateUtils.getParent(lastState);
+    if (!action || !lastParentState) {
+      return lastState;
+    }
+    switch (action.type) {
+      case ActionTypes.PUSH:
+        return NavigationStateUtils.push(
+          lastParentState,
+          action.state
+        );
+      case ActionTypes.POP:
+        if (lastParentState.index === 0 || lastParentState.children.length === 1) {
+          return lastParentState;
+        }
+        return NavigationStateUtils.pop(lastParentState);
+      case ActionTypes.JUMP_TO:
+        return NavigationStateUtils.jumpTo(
+          lastParentState,
+          action.key
+        );
+      case ActionTypes.JUMP_TO_INDEX:
+        return NavigationStateUtils.jumpToIndex(
+          lastParentState,
+          action.index
+        );
+      case ActionTypes.RESET:
+        return {
+          ...lastParentState,
+          index: action.index,
+          children: action.children,
+        };
+    }
+    if (matchAction(action)) {
+      return NavigationStateUtils.push(
+        lastParentState,
+        actionStateMap(action)
+      );
+    }
+    return lastParentState;
+  };
+}
+
+NavigationStackReducer.PushAction = NavigationStackPushAction;
+NavigationStackReducer.PopAction = NavigationStackPopAction;
+NavigationStackReducer.JumpToAction = NavigationStackJumpToAction;
+NavigationStackReducer.JumpToIndexAction = NavigationStackJumpToIndexAction;
+NavigationStackReducer.ResetAction = NavigationStackResetAction;
+
+module.exports = NavigationStackReducer;
diff --git a/Libraries/NavigationExperimental/Reducer/NavigationTabsReducer.js b/Libraries/NavigationExperimental/Reducer/NavigationTabsReducer.js
new file mode 100644
index 000000000000..6d31164f0cac
--- /dev/null
+++ b/Libraries/NavigationExperimental/Reducer/NavigationTabsReducer.js
@@ -0,0 +1,143 @@
+/**
+ * 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 NavigationTabsReducer
+ * @flow
+ */
+'use strict';
+
+const NavigationFindReducer = require('NavigationFindReducer');
+const NavigationStateUtils = require('NavigationState');
+
+import type {
+  NavigationReducer,
+  NavigationReducerWithDefault,
+  NavigationState
+} from 'NavigationState';
+
+const ActionTypes = {
+  JUMP_TO: 'react-native/NavigationExperimental/tabs-jumpTo',
+  ON_TAB_ACTION: 'react-native/NavigationExperimental/tabs-onTabAction',
+};
+
+const DEFAULT_KEY = 'TABS_STATE_DEFAULT_KEY';
+
+export type JumpToAction = {
+  type: typeof ActionTypes.JUMP_TO,
+  index: number,
+};
+function NavigationTabsJumpToAction(index: number): JumpToAction {
+  return {
+    type: ActionTypes.JUMP_TO,
+    index,
+  };
+}
+
+export type OnTabAction = {
+  type: string,
+  index: number,
+  action: any,
+};
+function NavigationTabsOnTabAction(index: number, action: any): OnTabAction {
+  return {
+    type: ActionTypes.ON_TAB_ACTION,
+    index,
+    action,
+  };
+}
+
+type TabsReducerConfig = {
+  key: string;
+  initialIndex: ?number;
+  tabReducers: Array<NavigationReducerWithDefault>;
+};
+
+function NavigationTabsReducer({key, initialIndex, tabReducers}: TabsReducerConfig): NavigationReducer {
+  if (initialIndex == null) {
+    initialIndex = 0;
+  }
+  if (key == null) {
+    key = DEFAULT_KEY;
+  }
+  return function(lastNavState: ?NavigationState, action: ?any): ?NavigationState {
+    if (!lastNavState) {
+      lastNavState = {
+        children: tabReducers.map(reducer => reducer(null, null)),
+        index: initialIndex,
+        key,
+      };
+    }
+    const lastParentNavState = NavigationStateUtils.getParent(lastNavState);
+    if (!action || !lastParentNavState) {
+      return lastNavState;
+    }
+    if (
+      action.type === ActionTypes.JUMP_TO &&
+      action.index !== lastParentNavState.index
+    ) {
+      return NavigationStateUtils.jumpToIndex(
+        lastParentNavState,
+        action.index,
+      );
+    }
+    if (action.type === ActionTypes.ON_TAB_ACTION) {
+      const onTabAction: OnTabAction = action;
+      const lastTabRoute = lastParentNavState.children[onTabAction.index];
+      const tabReducer = tabReducers[onTabAction.index];
+      if (tabReducer) {
+        const newTabRoute = tabReducer(lastTabRoute, action.action);
+        if (newTabRoute && newTabRoute !== lastTabRoute) {
+          let navState = NavigationStateUtils.replaceAtIndex(
+            lastParentNavState,
+            onTabAction.index,
+            newTabRoute
+          );
+          navState = NavigationStateUtils.jumpToIndex(
+            navState,
+            onTabAction.index
+          );
+          return navState;
+        }
+      }
+    }
+    const subReducers = tabReducers.map((tabReducer, tabIndex) => {
+      return function reduceTab(lastTabState: ?NavigationState, tabAction: ?any): ?NavigationState {
+        if (!lastTabState) {
+          return tabReducer(lastTabState, tabAction);
+        }
+        if (!lastParentNavState) {
+          return lastTabState;
+        }
+        const lastSubTabState = lastParentNavState.children[tabIndex];
+        const nextSubTabState = tabReducer(lastSubTabState, tabAction);
+        if (nextSubTabState && lastSubTabState !== nextSubTabState) {
+          const tabs = lastParentNavState.children;
+          tabs[tabIndex] = nextSubTabState;
+          return {
+            ...lastParentNavState,
+            tabs,
+            index: tabIndex,
+          };
+        }
+        return lastParentNavState;
+      };
+    });
+    let selectedTabReducer = subReducers.splice(lastParentNavState.index, 1)[0];
+    subReducers.unshift(selectedTabReducer);
+    const findReducer = NavigationFindReducer(subReducers);
+    if (findReducer) {
+      return findReducer(lastParentNavState, action);
+    }
+    return lastParentNavState;
+  };
+}
+
+NavigationTabsReducer.JumpToAction = NavigationTabsJumpToAction;
+NavigationTabsReducer.OnTabAction = NavigationTabsOnTabAction;
+
+module.exports = NavigationTabsReducer;
diff --git a/Libraries/NavigationExperimental/Reducer/__tests__/NavigationFindReducer-test.js b/Libraries/NavigationExperimental/Reducer/__tests__/NavigationFindReducer-test.js
new file mode 100644
index 000000000000..e67e64f2e481
--- /dev/null
+++ b/Libraries/NavigationExperimental/Reducer/__tests__/NavigationFindReducer-test.js
@@ -0,0 +1,46 @@
+/**
+ * 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-broken
+ */
+'use strict';
+
+jest
+ .autoMockOff()
+ .mock('ErrorUtils');
+
+const NavigationFindReducer = require('NavigationFindReducer');
+
+describe('NavigationFindReducer', () => {
+
+  it('handles basic find reducing with strings', () => {
+    let reducer = NavigationFindReducer([
+      s => s,
+      s => s + '_yes',
+      s => 'nope',
+    ]);
+    let route = reducer('input');
+    expect(route).toBe('input_yes');
+
+    reducer = NavigationFindReducer([
+      (s, action) => s,
+      (s, action) => 'origRoute',
+      (s, action) => 'firstChangedState',
+    ]);
+    route = reducer('origRoute', 'action1');
+    expect(route).toBe('firstChangedState');
+
+    reducer = NavigationFindReducer([
+      (s, action) => s,
+      (s, action) => action,
+    ]);
+    route = reducer('inputState', 'action2');
+    expect(route).toBe('action2');
+  });
+
+});
diff --git a/Libraries/NavigationExperimental/Reducer/__tests__/NavigationStackReducer-test.js b/Libraries/NavigationExperimental/Reducer/__tests__/NavigationStackReducer-test.js
new file mode 100644
index 000000000000..4d497346cfeb
--- /dev/null
+++ b/Libraries/NavigationExperimental/Reducer/__tests__/NavigationStackReducer-test.js
@@ -0,0 +1,197 @@
+/**
+ * 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-broken
+ */
+'use strict';
+
+jest
+ .autoMockOff()
+ .mock('ErrorUtils');
+
+const NavigationStackReducer = require('NavigationStackReducer');
+
+const {
+  JumpToAction,
+  JumpToIndexAction,
+  PopAction,
+  PushAction,
+  ResetAction,
+} = NavigationStackReducer;
+
+describe('NavigationStackReducer', () => {
+
+  it('handles PushAction', () => {
+    const initialStates = [
+      {key: 'route0'},
+      {key: 'route1'},
+    ];
+    let reducer = NavigationStackReducer({
+      initialStates,
+      matchAction: () => true,
+      actionStateMap: (action) => action,
+    });
+
+    let state = reducer();
+    expect(state.children).toBe(initialStates);
+    expect(state.index).toBe(1);
+    expect(state.key).toBe('NAV_STACK_DEFAULT_KEY');
+
+    state = reducer(state, PushAction({key: 'route2'}));
+    expect(state.children[0].key).toBe('route0');
+    expect(state.children[1].key).toBe('route1');
+    expect(state.children[2].key).toBe('route2');
+    expect(state.index).toBe(2);
+  });
+
+  it('handles PopAction', () => {
+    let reducer = NavigationStackReducer({
+      initialStates: [
+        {key: 'a'},
+        {key: 'b'},
+      ],
+      initialIndex: 1,
+      key: 'myStack',
+      matchAction: () => true,
+      actionStateMap: (action) => action,
+    });
+
+    let state = reducer();
+    expect(state.children[0].key).toBe('a');
+    expect(state.children[1].key).toBe('b');
+    expect(state.children.length).toBe(2);
+    expect(state.index).toBe(1);
+    expect(state.key).toBe('myStack');
+
+    state = reducer(state, PopAction());
+    expect(state.children[0].key).toBe('a');
+    expect(state.children.length).toBe(1);
+    expect(state.index).toBe(0);
+    expect(state.key).toBe('myStack');
+
+    // make sure Pop on an single-route state is a no-op
+    state = reducer(state, PopAction());
+    expect(state.children[0].key).toBe('a');
+    expect(state.children.length).toBe(1);
+    expect(state.index).toBe(0);
+    expect(state.key).toBe('myStack');
+  });
+
+  it('handles JumpToAction', () => {
+    let reducer = NavigationStackReducer({
+      initialStates: [
+        {key: 'a'},
+        {key: 'b'},
+        {key: 'c'},
+      ],
+      initialIndex: 0,
+      key: 'myStack',
+      matchAction: () => true,
+      actionStateMap: (action) => action,
+    });
+
+    let state = reducer();
+    expect(state.children[0].key).toBe('a');
+    expect(state.children[1].key).toBe('b');
+    expect(state.children[2].key).toBe('c');
+    expect(state.children.length).toBe(3);
+    expect(state.index).toBe(0);
+
+    state = reducer(state, JumpToAction('b'));
+    expect(state.children[0].key).toBe('a');
+    expect(state.children[1].key).toBe('b');
+    expect(state.children[2].key).toBe('c');
+    expect(state.children.length).toBe(3);
+    expect(state.index).toBe(1);
+
+    state = reducer(state, JumpToAction('c'));
+    expect(state.children[0].key).toBe('a');
+    expect(state.children[1].key).toBe('b');
+    expect(state.children[2].key).toBe('c');
+    expect(state.children.length).toBe(3);
+    expect(state.index).toBe(2);
+
+    state = reducer(state, JumpToAction('c'));
+    expect(state.children[0].key).toBe('a');
+    expect(state.children[1].key).toBe('b');
+    expect(state.children[2].key).toBe('c');
+    expect(state.children.length).toBe(3);
+    expect(state.index).toBe(2);
+    expect(state.key).toBe('myStack');
+  });
+
+  it('handles JumpToIndexAction', () => {
+    let reducer = NavigationStackReducer({
+      initialStates: [
+        {key: 'a'},
+        {key: 'b'},
+        {key: 'c'},
+      ],
+      initialIndex: 2,
+      key: 'myStack',
+      matchAction: () => true,
+      actionStateMap: (action) => action,
+    });
+
+    let state = reducer();
+    expect(state.children.length).toBe(3);
+    expect(state.index).toBe(2);
+
+    state = reducer(state, JumpToIndexAction(0));
+    expect(state.children.length).toBe(3);
+    expect(state.index).toBe(0);
+
+    state = reducer(state, JumpToIndexAction(1));
+    expect(state.children[0].key).toBe('a');
+    expect(state.children[1].key).toBe('b');
+    expect(state.children[2].key).toBe('c');
+    expect(state.children.length).toBe(3);
+    expect(state.index).toBe(1);
+    expect(state.key).toBe('myStack');
+  });
+
+  it('handles ResetAction', () => {
+    let reducer = NavigationStackReducer({
+      initialStates: [
+        {key: 'a'},
+        {key: 'b'},
+      ],
+      initialIndex: 1,
+      key: 'myStack',
+      matchAction: () => true,
+      actionStateMap: (action) => action,
+    });
+
+    let state = reducer();
+    expect(state.children[0].key).toBe('a');
+    expect(state.children[1].key).toBe('b');
+    expect(state.children.length).toBe(2);
+    expect(state.index).toBe(1);
+
+    state = reducer(state, ResetAction([{key: 'c'}, {key: 'd'}], 0));
+    expect(state.children[0].key).toBe('c');
+    expect(state.children[1].key).toBe('d');
+    expect(state.children.length).toBe(2);
+    expect(state.index).toBe(0);
+
+    const newStates = [
+      {key: 'e'},
+      {key: 'f'},
+      {key: 'g'},
+    ];
+
+    state = reducer(state, ResetAction(newStates, 1));
+    expect(state.children[0].key).toBe('e');
+    expect(state.children[1].key).toBe('f');
+    expect(state.children[2].key).toBe('g');
+    expect(state.children.length).toBe(3);
+    expect(state.index).toBe(1);
+    expect(state.key).toBe('myStack');
+  });
+
+});
diff --git a/Libraries/NavigationExperimental/Reducer/__tests__/NavigationTabsReducer-test.js b/Libraries/NavigationExperimental/Reducer/__tests__/NavigationTabsReducer-test.js
new file mode 100644
index 000000000000..a39aa76bfd23
--- /dev/null
+++ b/Libraries/NavigationExperimental/Reducer/__tests__/NavigationTabsReducer-test.js
@@ -0,0 +1,55 @@
+/**
+ * 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-broken
+ */
+'use strict';
+
+jest
+ .autoMockOff()
+ .mock('ErrorUtils');
+
+const NavigationTabsReducer = require('NavigationTabsReducer');
+
+const {
+  JumpToAction,
+} = NavigationTabsReducer;
+
+describe('NavigationTabsReducer', () => {
+
+  it('handles JumpTo with index', () => {
+    let reducer = NavigationTabsReducer({
+      tabReducers: [
+        (tabState, action) => tabState || 'a',
+        (tabState, action) => tabState || 'b',
+        (tabState, action) => tabState || 'c',
+      ],
+      initialIndex: 1,
+    });
+
+    let navState = reducer();
+
+    expect(navState.children[0]).toBe('a');
+    expect(navState.children[1]).toBe('b');
+    expect(navState.children[2]).toBe('c');
+    expect(navState.children.length).toBe(3);
+    expect(navState.index).toBe(1);
+
+    navState = reducer(
+      navState,
+      JumpToAction(2)
+    );
+
+    expect(navState.children[0]).toEqual('a');
+    expect(navState.children[1]).toEqual('b');
+    expect(navState.children[2]).toEqual('c');
+    expect(navState.children.length).toBe(3);
+    expect(navState.index).toBe(2);
+  });
+
+});
diff --git a/Libraries/NavigationExperimental/__tests__/NavigationState-test.js b/Libraries/NavigationExperimental/__tests__/NavigationState-test.js
new file mode 100644
index 000000000000..b28aaaca20dc
--- /dev/null
+++ b/Libraries/NavigationExperimental/__tests__/NavigationState-test.js
@@ -0,0 +1,57 @@
+/**
+ * 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-broken
+ */
+'use strict';
+
+jest
+ .autoMockOff()
+ .mock('ErrorUtils');
+
+var NavigationState = require('NavigationState');
+
+var VALID_PARENT_STATES = [
+  {children: ['a','b'], index: 0},
+  {children: [{key: 'a'},{key: 'b', foo: 123}], index: 1},
+  {children: [{key: 'a'},{key: 'b'}], index: 0},
+  {children: [{key: 'a'},{key: 'b'}], index: 2},
+];
+var INVALID_PARENT_STATES = [
+  'foo',
+  {},
+  {children: [{key: 'a'}], index: 4},
+  {children: [{key: 'a'}], index: -1},
+  {children: [{key: 'a'}]},
+  {children: {key: 'foo'}},
+  12,
+  null,
+  undefined,
+  [],
+];
+
+describe('NavigationState', () => {
+
+  it('identifies parents correctly with getParent', () => {
+    for (var i = 0; i <= VALID_PARENT_STATES.length; i++) {
+      var navState = VALID_PARENT_STATES[0];
+      expect(NavigationState.getParent(navState)).toBe(navState);
+    }
+    for (var i = 0; i <= INVALID_PARENT_STATES.length; i++) {
+      var navState = INVALID_PARENT_STATES[0];
+      expect(NavigationState.getParent(navState)).toBe(null);
+    }
+  });
+
+  it('can get children', () => {
+    var fooState = {key: 'foo'};
+    var navState = {children: [{key: 'foobar'}, fooState], index: 0};
+    expect(NavigationState.get(navState, 'foo')).toBe(fooState);
+    expect(NavigationState.get(navState, 'missing')).toBe(null);
+  });
+});
diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js
index 79a4ec0d5a8a..e8eca3c72a5a 100644
--- a/Libraries/react-native/react-native.js
+++ b/Libraries/react-native/react-native.js
@@ -76,6 +76,7 @@ var ReactNative = {
   get LayoutAnimation() { return require('LayoutAnimation'); },
   get Linking() { return require('Linking'); },
   get LinkingIOS() { return require('LinkingIOS'); },
+  get NavigationExperimental() { return require('NavigationExperimental'); },
   get NetInfo() { return require('NetInfo'); },
   get PanResponder() { return require('PanResponder'); },
   get PixelRatio() { return require('PixelRatio'); },

From 995b66db8244a14fea4fedb88a2feaa1d3cf23e4 Mon Sep 17 00:00:00 2001
From: Lasse Bang Mikkelsen <lbm@lbm.dk>
Date: Fri, 5 Feb 2016 15:07:31 -0800
Subject: [PATCH 1037/1411] Fix XMLHttpRequest.abort() not functional due to
 incorrect lazy loading in RCTNetworking ObjC module

Summary:
Introduced in a major lazy loading refactoring: 060664fd3d9331f062696e68179bac9cd4544a06.

This is especially an issue when aborting a long-lived HTTP connection used as a notification channel, as it will use 1 of the maximum 4 connections per host (default limit defined by iOS' NSURLSession).
Closes https://github.com/facebook/react-native/pull/5782

Reviewed By: svcscm

Differential Revision: D2907600

Pulled By: nicklockwood

fb-gh-sync-id: 8406a045904a7ddb61fe1539a0474ec27b5e9e37
---
 Libraries/Network/RCTNetworking.m | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/Network/RCTNetworking.m b/Libraries/Network/RCTNetworking.m
index 5e30813430d0..47cbc74d222a 100644
--- a/Libraries/Network/RCTNetworking.m
+++ b/Libraries/Network/RCTNetworking.m
@@ -411,7 +411,7 @@ - (void)sendRequest:(NSURLRequest *)request
   task.uploadProgressBlock = uploadProgressBlock;
 
   if (task.requestID) {
-    if (_tasksByRequestID) {
+    if (!_tasksByRequestID) {
       _tasksByRequestID = [NSMutableDictionary new];
     }
     _tasksByRequestID[task.requestID] = task;

From 4fd115ffa262ff51f429892500c5afecb425db3b Mon Sep 17 00:00:00 2001
From: Oleg Lokhvitsky <olegbl@fb.com>
Date: Fri, 5 Feb 2016 15:13:32 -0800
Subject: [PATCH 1038/1411] Added .setItems() integration for Android
 AlertDialog

Reviewed By: dmmiller

Differential Revision: D2892199

fb-gh-sync-id: d052313a488d9dfa0ab23f76ea0a96a77260d6c2
---
 .../facebook/react/modules/dialog/AlertFragment.java | 12 ++++++++++--
 .../facebook/react/modules/dialog/DialogModule.java  | 10 ++++++++++
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/AlertFragment.java b/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/AlertFragment.java
index 04d6d421a973..98dd9cc0abda 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/AlertFragment.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/AlertFragment.java
@@ -28,6 +28,7 @@
   /* package */ static final String ARG_BUTTON_POSITIVE = "button_positive";
   /* package */ static final String ARG_BUTTON_NEGATIVE = "button_negative";
   /* package */ static final String ARG_BUTTON_NEUTRAL = "button_neutral";
+  /* package */ static final String ARG_ITEMS = "items";
 
   private final @Nullable DialogModule.AlertFragmentListener mListener;
 
@@ -39,8 +40,7 @@ public AlertFragment(@Nullable DialogModule.AlertFragmentListener listener, Bund
   public static Dialog createDialog(
       Context activityContext, Bundle arguments, DialogInterface.OnClickListener fragment) {
     AlertDialog.Builder builder = new AlertDialog.Builder(activityContext)
-        .setTitle(arguments.getString(ARG_TITLE))
-        .setMessage(arguments.getString(ARG_MESSAGE));
+        .setTitle(arguments.getString(ARG_TITLE));
 
     if (arguments.containsKey(ARG_BUTTON_POSITIVE)) {
       builder.setPositiveButton(arguments.getString(ARG_BUTTON_POSITIVE), fragment);
@@ -51,6 +51,14 @@ public static Dialog createDialog(
     if (arguments.containsKey(ARG_BUTTON_NEUTRAL)) {
       builder.setNeutralButton(arguments.getString(ARG_BUTTON_NEUTRAL), fragment);
     }
+    // if both message and items are set, Android will only show the message
+    // and ignore the items argument entirely
+    if (arguments.containsKey(ARG_MESSAGE)) {
+      builder.setMessage(arguments.getString(ARG_MESSAGE));
+    }
+    if (arguments.containsKey(ARG_ITEMS)) {
+      builder.setItems(arguments.getCharSequenceArray(ARG_ITEMS), fragment);
+    }
 
     return builder.create();
   }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/DialogModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/DialogModule.java
index 10dfbc8d4760..30bcedb226ac 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/DialogModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/dialog/DialogModule.java
@@ -26,6 +26,7 @@
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.ReactContextBaseJavaModule;
 import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.bridge.ReadableMap;
 import com.facebook.react.common.MapBuilder;
 
@@ -43,6 +44,7 @@ public class DialogModule extends ReactContextBaseJavaModule implements Lifecycl
   /* package */ static final String KEY_BUTTON_POSITIVE = "buttonPositive";
   /* package */ static final String KEY_BUTTON_NEGATIVE = "buttonNegative";
   /* package */ static final String KEY_BUTTON_NEUTRAL = "buttonNeutral";
+  /* package */ static final String KEY_ITEMS = "items";
 
   /* package */ static final Map<String, Object> CONSTANTS = MapBuilder.<String, Object>of(
       ACTION_BUTTON_CLICKED, ACTION_BUTTON_CLICKED,
@@ -230,6 +232,14 @@ public void showAlert(
     if (options.hasKey(KEY_BUTTON_NEUTRAL)) {
       args.putString(AlertFragment.ARG_BUTTON_NEUTRAL, options.getString(KEY_BUTTON_NEUTRAL));
     }
+    if (options.hasKey(KEY_ITEMS)) {
+      ReadableArray items = options.getArray(KEY_ITEMS);
+      CharSequence[] itemsArray = new CharSequence[items.size()];
+      for (int i = 0; i < items.size(); i ++) {
+        itemsArray[i] = items.getString(i);
+      }
+      args.putCharSequenceArray(AlertFragment.ARG_ITEMS, itemsArray);
+    }
 
     fragmentManagerHelper.showNewAlert(mIsInForeground, args, actionCallback);
   }

From 64d56f34b779de94f251f4b443463cbfe790912d Mon Sep 17 00:00:00 2001
From: Alex Kotliarskyi <alex.frantic@gmail.com>
Date: Fri, 5 Feb 2016 15:16:16 -0800
Subject: [PATCH 1039/1411] Improve Chrome debugger

Summary:
`debugger.html` contained a ton of hacky code that was needed to ensure we have a clean JS runtime every time a client RN app connects. That was needed because we used the page's global environment as runtime. Some time ago WebWorker support was added and now we run RN code inside an isolated WebWorker instance, and we can safely get rid of all these hacks.

This has a bunch of nice side-effects: debug reload works faster, `console.log`s are preserved, `debuggerWorker.js` selection doesn't change.

Made sure the debugging (breakpoints, etc.) still works as before.

Small demo
![](http://g.recordit.co/FPdVHLHPUW.gif)
Closes https://github.com/facebook/react-native/pull/5715

Reviewed By: svcscm

Differential Revision: D2906602

Pulled By: frantic

fb-gh-sync-id: 1a6ab9a5655d7c32ddd23619564e59c377b53a35
---
 Libraries/WebSocket/RCTWebSocketExecutor.m    |   2 +-
 .../react/devsupport/DevServerHelper.java     |   2 +-
 local-cli/server/util/debugger.html           | 103 +++++++++---------
 local-cli/server/util/webSocketProxy.js       |  80 +++++++-------
 4 files changed, 95 insertions(+), 92 deletions(-)

diff --git a/Libraries/WebSocket/RCTWebSocketExecutor.m b/Libraries/WebSocket/RCTWebSocketExecutor.m
index 2ee409f33bfe..de26e8a91857 100644
--- a/Libraries/WebSocket/RCTWebSocketExecutor.m
+++ b/Libraries/WebSocket/RCTWebSocketExecutor.m
@@ -51,7 +51,7 @@ - (void)setUp
   if (!_url) {
     NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
     NSInteger port = [standardDefaults integerForKey:@"websocket-executor-port"] ?: 8081;
-    NSString *URLString = [NSString stringWithFormat:@"http://localhost:%zd/debugger-proxy", port];
+    NSString *URLString = [NSString stringWithFormat:@"http://localhost:%zd/debugger-proxy?role=client", port];
     _url = [RCTConvert NSURL:URLString];
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java
index 515cab3a517b..79a71b242da4 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java
@@ -62,7 +62,7 @@ public class DevServerHelper {
       "http://%s/launch-chrome-devtools";
   private static final String ONCHANGE_ENDPOINT_URL_FORMAT =
       "http://%s/onchange";
-  private static final String WEBSOCKET_PROXY_URL_FORMAT = "ws://%s/debugger-proxy";
+  private static final String WEBSOCKET_PROXY_URL_FORMAT = "ws://%s/debugger-proxy?role=client";
   private static final String PACKAGER_STATUS_URL_FORMAT = "http://%s/status";
 
   private static final String PACKAGER_OK_STATUS = "packager-status:running";
diff --git a/local-cli/server/util/debugger.html b/local-cli/server/util/debugger.html
index 3d1c5947e219..878574260cc4 100644
--- a/local-cli/server/util/debugger.html
+++ b/local-cli/server/util/debugger.html
@@ -17,83 +17,82 @@
 <script>
 (function() {
 
-var sessionID = window.localStorage.getItem('sessionID');
-window.localStorage.removeItem('sessionID');
-
-window.onbeforeunload = function() {
-  if (sessionID) {
-    return 'If you reload this page, it is going to break the debugging session. ' +
-      'You should press ⌘R in simulator to reload.';
-  }
-};
-
-// Alias native implementations needed by the debugger before platform-specific
-// implementations are loaded into the global namespace
-var debuggerSetTimeout = window.setTimeout;
-var DebuggerWebSocket = window.WebSocket;
-
 function setStatus(status) {
   document.getElementById('status').innerHTML = status;
 }
 
-// This worker will run the application javascript code,
-// making sure that it's run in an environment without a global
-// document, to make it consistent with the JSC executor environment.
-var worker = new Worker('debuggerWorker.js');
+var INITIAL_MESSAGE = 'Waiting, press <span class="shortcut">⌘R</span> in simulator to reload and connect.';
 
-var messageHandlers = {
-  // This method is a bit hacky. Catalyst asks for a new clean JS runtime.
-  // The easiest way to do this is to reload this page. That also means that
-  // web socket connection will be lost. To send reply back we need to remember
-  // message id.
-  // This message also needs to be handled outside of the worker, since the worker
-  // doesn't have access to local storage.
-  'prepareJSRuntime': function(message) {
-    window.onbeforeunload = undefined;
-    window.localStorage.setItem('sessionID', message.id);
-    window.location.reload();
+function connectToDebuggerProxy() {
+  var worker;
+  var ws = new WebSocket('ws://' + window.location.host + '/debugger-proxy?role=debugger&name=Chrome');
+
+  function createJSRuntime() {
+    // This worker will run the application javascript code,
+    // making sure that it's run in an environment without a global
+    // document, to make it consistent with the JSC executor environment.
+    worker = new Worker('debuggerWorker.js');
+    worker.onmessage = function(message) {
+      ws.send(JSON.stringify(message.data));
+    };
+    window.onbeforeunload = function() {
+      return 'If you reload this page, it is going to break the debugging session. ' +
+        'You should press ⌘R in simulator to reload.';
+    };
   }
-};
 
-function connectToDebuggerProxy() {
-  var ws = new DebuggerWebSocket('ws://' + window.location.host + '/debugger-proxy');
+  function shutdownJSRuntime() {
+    if (worker) {
+      worker.terminate();
+      worker = null;
+      window.onbeforeunload = null;
+    }
+  }
 
   ws.onopen = function() {
-    if (sessionID) {
-      setStatus('Debugger session #' + sessionID + ' active.');
-      ws.send(JSON.stringify({replyID: parseInt(sessionID, 10)}));
-    } else {
-      setStatus('Waiting, press <span class="shortcut">⌘R</span> in simulator to reload and connect.');
-    }
+    setStatus(INITIAL_MESSAGE);
   };
 
   ws.onmessage = function(message) {
+    if (!message.data) {
+      return;
+    }
     var object = JSON.parse(message.data);
+
+    if (object.$event === 'client-disconnected') {
+      shutdownJSRuntime();
+      setStatus('Waiting, press <span class="shortcut">⌘R</span> in simulator to reload and connect.');
+      return;
+    }
+
     if (!object.method) {
       return;
     }
 
-    var handler = messageHandlers[object.method];
-    if (handler) {
-      // If we have a local handler, use it.
-      handler(object);
+    // Special message that asks for a new JS runtime
+    if (object.method === 'prepareJSRuntime') {
+      shutdownJSRuntime();
+      createJSRuntime();
+      ws.send(JSON.stringify({replyID: object.id}));
+      setStatus('Debugger session #' + object.id + ' active.');
+    } else if (object.method === '$disconnected') {
+      shutdownJSRuntime();
+      setStatus(INITIAL_MESSAGE);
     } else {
       // Otherwise, pass through to the worker.
       worker.postMessage(object);
     }
   };
 
-  ws.onclose = function() {
+  ws.onclose = function(e) {
+    shutdownJSRuntime();
     setStatus('Disconnected from proxy. Attempting reconnection. Is node server running?');
-
-    sessionID = null;
-    window.localStorage.removeItem('sessionID');
-    debuggerSetTimeout(connectToDebuggerProxy, 100);
+    if (e.reason) {
+      setStatus(e.reason);
+      console.warn(e.reason);
+    }
+    setTimeout(connectToDebuggerProxy, 500);
   };
-
-  worker.onmessage = function(message) {
-    ws.send(JSON.stringify(message.data));
-  }
 }
 
 connectToDebuggerProxy();
diff --git a/local-cli/server/util/webSocketProxy.js b/local-cli/server/util/webSocketProxy.js
index 66eaefb15f16..74c01f8ef179 100644
--- a/local-cli/server/util/webSocketProxy.js
+++ b/local-cli/server/util/webSocketProxy.js
@@ -15,55 +15,59 @@ function attachToServer(server, path) {
     server: server,
     path: path
   });
-  var clients = [];
+  var debuggerSocket, clientSocket;
 
-  function sendSpecial(message) {
-    clients.forEach(function (cn) {
-      try {
-        cn.send(JSON.stringify(message));
-      } catch(e) {
-        // Sometimes this call throws 'not opened'
-      }
-    });
+  function send(dest, message) {
+    if (!dest) {
+      return;
+    }
+
+    try {
+      dest.send(message);
+    } catch(e) {
+      console.warn(e);
+      // Sometimes this call throws 'not opened'
+    }
   }
 
   wss.on('connection', function(ws) {
-    var id = Math.random().toString(15).slice(10, 20);
-    sendSpecial({$open: id});
-    clients.push(ws);
-
-    var allClientsExcept = function(ws) {
-      return clients.filter(function(cn) { return cn !== ws; });
-    };
+    const {url} = ws.upgradeReq;
 
-    ws.onerror = function() {
-      clients = allClientsExcept(ws);
-      sendSpecial({$error: id});
-    };
-
-    ws.onclose = function() {
-      clients = allClientsExcept(ws);
-      sendSpecial({$close: id});
-    };
-
-    ws.on('message', function(message) {
-      allClientsExcept(ws).forEach(function(cn) {
-        try {
-          cn.send(message);
-        } catch(e) {
-          // Sometimes this call throws 'not opened'
+    if (url.indexOf('role=debugger') > -1) {
+      if (debuggerSocket) {
+        ws.close(1011, 'Another debugger is already connected');
+        return;
+      }
+      debuggerSocket = ws;
+      debuggerSocket.onerror =
+      debuggerSocket.onclose = () => {
+        debuggerSocket = null;
+        if (clientSocket) {
+          clientSocket.close(1011, 'Debugger was disconnected');
         }
-      });
-    });
+      };
+      debuggerSocket.onmessage = ({data}) => send(clientSocket, data);
+    } else if (url.indexOf('role=client') > -1) {
+      if (clientSocket) {
+        clientSocket.onerror = clientSocket.onclose = clientSocket.onmessage = null;
+        clientSocket.close(1011, 'Another client connected');
+      }
+      clientSocket = ws;
+      clientSocket.onerror =
+      clientSocket.onclose = () => {
+        clientSocket = null;
+        send(debuggerSocket, JSON.stringify({method: '$disconnected'}));
+      };
+      clientSocket.onmessage = ({data}) => send(debuggerSocket, data);
+    } else {
+      ws.close(1011, 'Missing role param');
+    }
   });
 
   return {
     server: wss,
     isChromeConnected: function() {
-      return clients
-        .map(function(ws) { return ws.upgradeReq.headers['user-agent']; })
-        .filter(Boolean)
-        .some(function(userAgent) { return userAgent.includes('Chrome'); });
+      return !!debuggerSocket;
     }
   };
 }

From 98797177abd93d01a206fe3f4c5f31143fdebf08 Mon Sep 17 00:00:00 2001
From: Keith Norman <keithnorm@gmail.com>
Date: Fri, 5 Feb 2016 16:24:48 -0800
Subject: [PATCH 1040/1411] fix issue that breaks scroll views w/
 RefreshControl on Android

Summary:
Fixes the issue I mentioned here https://github.com/facebook/react-native/pull/5623#issuecomment-180583142
Closes https://github.com/facebook/react-native/pull/5784

Reviewed By: svcscm

Differential Revision: D2908112

Pulled By: nicklockwood

fb-gh-sync-id: 8a2f053de3f7dc19807ee21dd969c53a57b71345
---
 Libraries/Components/ScrollView/ScrollView.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js
index bd3f9b99e570..7c769a05f0be 100644
--- a/Libraries/Components/ScrollView/ScrollView.js
+++ b/Libraries/Components/ScrollView/ScrollView.js
@@ -530,7 +530,7 @@ var ScrollView = React.createClass({
         // AndroidSwipeRefreshLayout and use flex: 1 for the ScrollView.
         return React.cloneElement(
           refreshControl,
-          {style: this.props.style},
+          {style: props.style},
           <ScrollViewClass {...props} style={styles.base} ref={SCROLLVIEW}>
             {contentContainer}
           </ScrollViewClass>

From 97b8a57bdbbf462aaef807991eea22665f0662c9 Mon Sep 17 00:00:00 2001
From: wusuopu <admin@longchangjin.cn>
Date: Fri, 5 Feb 2016 16:29:17 -0800
Subject: [PATCH 1041/1411] Fix inspector for displaying styles' value

Summary:
StyleInspector will occur a error if a style's value is an object, such as transform. Now it converts the value to string before display.

fix issue #5774 .

Now it can display okay.

![simulator screen shot feb 6 2016 12 32 24 am](https://cloud.githubusercontent.com/assets/1478284/12852296/36736966-cc69-11e5-8f28-9e4681585bcb.png)
Closes https://github.com/facebook/react-native/pull/5777

Reviewed By: svcscm

Differential Revision: D2908135

Pulled By: nicklockwood

fb-gh-sync-id: 5914f9e9538f90ae9a38ef7d8dc85b2df84ec43e
---
 Libraries/Inspector/StyleInspector.js | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/Libraries/Inspector/StyleInspector.js b/Libraries/Inspector/StyleInspector.js
index 702d01e1da35..96d13ad6a74e 100644
--- a/Libraries/Inspector/StyleInspector.js
+++ b/Libraries/Inspector/StyleInspector.js
@@ -27,8 +27,12 @@ class StyleInspector extends React.Component {
         <View>
           {names.map(name => <Text style={styles.attr}>{name}:</Text>)}
         </View>
+
         <View>
-          {names.map(name => <Text style={styles.value}>{this.props.style[name]}</Text>)}
+          {names.map(name => {
+            var value = typeof this.props.style[name] === 'object' ? JSON.stringify(this.props.style[name]) : this.props.style[name];
+            return <Text style={styles.value}>{value}</Text>;
+          } ) }
         </View>
       </View>
     );

From 375abc3f06093852928ee9f9e8b8fa754ca45dc3 Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeuxx@gmail.com>
Date: Fri, 5 Feb 2016 16:33:29 -0800
Subject: [PATCH 1042/1411] More helpful description for native-js prop
 mismatch

Summary:
Similar as https://github.com/facebook/react-native/pull/5605
Closes https://github.com/facebook/react-native/pull/5673

Reviewed By: svcscm

Differential Revision: D2908218

Pulled By: nicklockwood

fb-gh-sync-id: da5e42ea660df2c0bb60165c7429d480414a0a20
---
 React/Base/RCTModuleMethod.m | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/React/Base/RCTModuleMethod.m b/React/Base/RCTModuleMethod.m
index 0a6cd9390e6e..0e7dd72f246a 100644
--- a/React/Base/RCTModuleMethod.m
+++ b/React/Base/RCTModuleMethod.m
@@ -448,7 +448,10 @@ - (void)invokeWithBridge:(RCTBridge *)bridge
         expectedCount -= 2;
       }
 
-      RCTLogError(@"%@.%@ was called with %zd arguments, but expects %zd",
+      RCTLogError(@"%@.%@ was called with %zd arguments, but expects %zd. \
+                  If you haven\'t changed this method yourself, this usually means that \
+                  your versions of the native code and JavaScript code are out of sync. \
+                  Updating both should make this error go away.",
                   RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName,
                   actualCount, expectedCount);
       return;

From 52755fdde278404540a17117098151db5f2a86e3 Mon Sep 17 00:00:00 2001
From: Mark Vayngrib <mark@tradle.io>
Date: Fri, 5 Feb 2016 16:44:44 -0800
Subject: [PATCH 1043/1411] multiGet breaking test and fix

Summary:
the flush + optimized multiGet result in an obscure bug that results when two multiGet requests with overlapping key sets get issued. The result array for both requests ends up bigger than the key array (because it has duplicates)
Closes https://github.com/facebook/react-native/pull/5514

Reviewed By: svcscm

Differential Revision: D2908264

Pulled By: nicklockwood

fb-gh-sync-id: 60be1bce4acfc47083e4ae28bb8b63f9dfa56039
---
 IntegrationTests/AsyncStorageTest.js | 18 ++++++++++++++++++
 Libraries/Storage/AsyncStorage.js    | 18 +++++++++++++-----
 2 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/IntegrationTests/AsyncStorageTest.js b/IntegrationTests/AsyncStorageTest.js
index 3bd313a7fd0e..06ea818e4511 100644
--- a/IntegrationTests/AsyncStorageTest.js
+++ b/IntegrationTests/AsyncStorageTest.js
@@ -142,12 +142,30 @@ function testMerge() {
         expectAsyncNoError('testMerge/setItem', err3);
         expectEqual(JSON.parse(result), VAL_MERGE_EXPECT, 'testMerge');
         updateMessage('objects deeply merged\nDone!');
+        runTestCase('multi set and get', testOptimizedMultiGet);
+      });
+    });
+  });
+}
+
+function testOptimizedMultiGet() {
+  let batch = [[KEY_1, VAL_1], [KEY_2, VAL_2]];
+  let keys = batch.map(([key, value]) => key);
+  AsyncStorage.multiSet(batch, (err1) => {
+    // yes, twice on purpose
+    ;[1, 2].forEach((i) => {
+      expectAsyncNoError(`${i} testOptimizedMultiGet/multiSet`, err1);
+      AsyncStorage.multiGet(keys, (err2, result) => {
+        expectAsyncNoError(`${i} testOptimizedMultiGet/multiGet`, err2);
+        expectEqual(result, batch, `${i} testOptimizedMultiGet multiGet`);
+        updateMessage('multiGet([key_1, key_2]) correctly returned ' + JSON.stringify(result));
         done();
       });
     });
   });
 }
 
+
 var AsyncStorageTest = React.createClass({
   getInitialState() {
     return {
diff --git a/Libraries/Storage/AsyncStorage.js b/Libraries/Storage/AsyncStorage.js
index eb41c8a736f5..f1ed35c3c1c5 100644
--- a/Libraries/Storage/AsyncStorage.js
+++ b/Libraries/Storage/AsyncStorage.js
@@ -180,14 +180,16 @@ var AsyncStorage = {
       // Even though the runtime complexity of this is theoretically worse vs if we used a map,
       // it's much, much faster in practice for the data sets we deal with (we avoid
       // allocating result pair arrays). This was heavily benchmarked.
+      //
+      // Is there a way to avoid using the map but fix the bug in this breaking test?
+      // https://github.com/facebook/react-native/commit/8dd8ad76579d7feef34c014d387bf02065692264
+      let map = {};
+      result.forEach(([key, value]) => map[key] = value);
       const reqLength = getRequests.length;
       for (let i = 0; i < reqLength; i++) {
         const request = getRequests[i];
         const requestKeys = request.keys;
-        var requestResult = result.filter(function(resultPair) {
-          return requestKeys.indexOf(resultPair[0]) !== -1;
-        });
-
+        let requestResult = requestKeys.map(key => [key, map[key]]);
         request.callback && request.callback(null, requestResult);
         request.resolve && request.resolve(requestResult);
       }
@@ -214,6 +216,7 @@ var AsyncStorage = {
     var getRequest = {
       keys: keys,
       callback: callback,
+      // do we need this?
       keyIndex: this._getKeys.length,
       resolve: null,
       reject: null,
@@ -225,7 +228,12 @@ var AsyncStorage = {
     });
 
     this._getRequests.push(getRequest);
-    this._getKeys.push.apply(this._getKeys, keys);
+    // avoid fetching duplicates
+    keys.forEach(key => {
+      if (this._getKeys.indexOf(key) === -1) {
+        this._getKeys.push(key);
+      }
+    });
 
     return promiseResult;
   },

From 109036b4c4b530c04c394c48e43319ca91ca2d53 Mon Sep 17 00:00:00 2001
From: Christopher Dro <hello@blick-labs.com>
Date: Fri, 5 Feb 2016 16:54:14 -0800
Subject: [PATCH 1044/1411] Expose option for distance filtering on location
 updates.

Summary:
My original implementation involved creating a `RCT_ENUM_CONVERTER` with `CLLocationAccuracy` on iOS and a Hashmap on Android that would convert `string` values to `doubles` for distance filtering.

I got this to work just fine but realized that I made things more complicated than they needed to be and simplified everything by just have the option be a decimal value (in meters) that works both for iOS and Android.

The only thing i'm not sure about is if we can set arbitrary values for CLLocationManager's distance filter.
nicklockwood  Any idea?
Closes https://github.com/facebook/react-native/pull/5563

Reviewed By: svcscm

Differential Revision: D2908250

Pulled By: nicklockwood

fb-gh-sync-id: d83c12b3ce7c343f413749a2cd614b3bf04d6750
---
 Libraries/Geolocation/Geolocation.js                  |  3 ++-
 Libraries/Geolocation/RCTLocationObserver.m           | 10 ++++++++--
 .../react/modules/location/LocationModule.java        | 11 ++++++++---
 3 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/Libraries/Geolocation/Geolocation.js b/Libraries/Geolocation/Geolocation.js
index 82bc1c9a059c..42d7378eb102 100644
--- a/Libraries/Geolocation/Geolocation.js
+++ b/Libraries/Geolocation/Geolocation.js
@@ -26,6 +26,7 @@ type GeoOptions = {
   timeout: number;
   maximumAge: number;
   enableHighAccuracy: bool;
+  distanceFilter: number;
 }
 
 /**
@@ -68,7 +69,7 @@ var Geolocation = {
 
   /*
    * Invokes the success callback whenever the location changes.  Supported
-   * options: timeout (ms), maximumAge (ms), enableHighAccuracy (bool)
+   * options: timeout (ms), maximumAge (ms), enableHighAccuracy (bool), distanceFilter(m)
    */
   watchPosition: function(success: Function, error?: Function, options?: GeoOptions): number {
     if (!updatesEnabled) {
diff --git a/Libraries/Geolocation/RCTLocationObserver.m b/Libraries/Geolocation/RCTLocationObserver.m
index 63ceb7c9d95d..7320fae8980c 100644
--- a/Libraries/Geolocation/RCTLocationObserver.m
+++ b/Libraries/Geolocation/RCTLocationObserver.m
@@ -31,6 +31,7 @@ typedef NS_ENUM(NSInteger, RCTPositionErrorCode) {
   double timeout;
   double maximumAge;
   double accuracy;
+  double distanceFilter;
 } RCTLocationOptions;
 
 @implementation RCTConvert (RCTLocationOptions)
@@ -38,10 +39,15 @@ @implementation RCTConvert (RCTLocationOptions)
 + (RCTLocationOptions)RCTLocationOptions:(id)json
 {
   NSDictionary<NSString *, id> *options = [RCTConvert NSDictionary:json];
+
+  double distanceFilter = options[@"distanceFilter"] == NULL ? RCT_DEFAULT_LOCATION_ACCURACY
+    : [RCTConvert double:options[@"distanceFilter"]] ?: kCLDistanceFilterNone;
+
   return (RCTLocationOptions){
     .timeout = [RCTConvert NSTimeInterval:options[@"timeout"]] ?: INFINITY,
     .maximumAge = [RCTConvert NSTimeInterval:options[@"maximumAge"]] ?: INFINITY,
-    .accuracy = [RCTConvert BOOL:options[@"enableHighAccuracy"]] ? kCLLocationAccuracyBest : RCT_DEFAULT_LOCATION_ACCURACY
+    .accuracy = [RCTConvert BOOL:options[@"enableHighAccuracy"]] ? kCLLocationAccuracyBest : RCT_DEFAULT_LOCATION_ACCURACY,
+    .distanceFilter = distanceFilter
   };
 }
 
@@ -128,7 +134,7 @@ - (void)beginLocationUpdates
 {
   if (!_locationManager) {
     _locationManager = [CLLocationManager new];
-    _locationManager.distanceFilter = RCT_DEFAULT_LOCATION_ACCURACY;
+    _locationManager.distanceFilter = _observerOptions.distanceFilter;
     _locationManager.delegate = self;
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/location/LocationModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/location/LocationModule.java
index 9973563fc120..86dec164b26a 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/location/LocationModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/location/LocationModule.java
@@ -36,6 +36,7 @@
 public class LocationModule extends ReactContextBaseJavaModule {
 
   private @Nullable String mWatchedProvider;
+  private static final float RCT_DEFAULT_LOCATION_ACCURACY = 100;
 
   private final LocationListener mLocationListener = new LocationListener() {
     @Override
@@ -73,11 +74,13 @@ private static class LocationOptions {
     private final long timeout;
     private final double maximumAge;
     private final boolean highAccuracy;
+    private final float distanceFilter;
 
-    private LocationOptions(long timeout, double maximumAge, boolean highAccuracy) {
+    private LocationOptions(long timeout, double maximumAge, boolean highAccuracy, float distanceFilter) {
       this.timeout = timeout;
       this.maximumAge = maximumAge;
       this.highAccuracy = highAccuracy;
+      this.distanceFilter = distanceFilter;
     }
 
     private static LocationOptions fromReactMap(ReadableMap map) {
@@ -88,8 +91,10 @@ private static LocationOptions fromReactMap(ReadableMap map) {
           map.hasKey("maximumAge") ? map.getDouble("maximumAge") : Double.POSITIVE_INFINITY;
       boolean highAccuracy =
           map.hasKey("enableHighAccuracy") && map.getBoolean("enableHighAccuracy");
+      float distanceFilter =
+          map.hasKey("distanceFilter") ? (float) map.getDouble("distanceFilter") : RCT_DEFAULT_LOCATION_ACCURACY;
 
-      return new LocationOptions(timeout, maximumAge, highAccuracy);
+      return new LocationOptions(timeout, maximumAge, highAccuracy, distanceFilter);
     }
   }
 
@@ -151,7 +156,7 @@ public void startObserving(ReadableMap options) {
       }
       if (!provider.equals(mWatchedProvider)) {
         locationManager.removeUpdates(mLocationListener);
-        locationManager.requestLocationUpdates(provider, 1000, 0, mLocationListener);
+        locationManager.requestLocationUpdates(provider, 1000, locationOptions.distanceFilter, mLocationListener);
       }
       mWatchedProvider = provider;
     } catch (SecurityException e) {

From 7cbad9f53048ab5d19a8004df30ae621f1bfbd09 Mon Sep 17 00:00:00 2001
From: Arjun Balaji <arjunblj@gmail.com>
Date: Fri, 5 Feb 2016 16:56:54 -0800
Subject: [PATCH 1045/1411] Add Children.toArray to ReactNative

Summary:
To fix #5769. I believe `ReactNative.Children.toArray` should be accessible now.
Closes https://github.com/facebook/react-native/pull/5780

Reviewed By: svcscm

Differential Revision: D2907876

Pulled By: spicyj

fb-gh-sync-id: 649908843f535a89909425bcdcbc58461854779b
---
 Libraries/ReactNative/ReactNative.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Libraries/ReactNative/ReactNative.js b/Libraries/ReactNative/ReactNative.js
index 1b02747532af..e2314ba581f9 100644
--- a/Libraries/ReactNative/ReactNative.js
+++ b/Libraries/ReactNative/ReactNative.js
@@ -84,6 +84,7 @@ var ReactNative = {
     map: ReactChildren.map,
     forEach: ReactChildren.forEach,
     count: ReactChildren.count,
+    toArray: ReactChildren.toArray,
     only: onlyChild
   },
   Component: ReactComponent,

From 294185ac328b1c9ae2da6331575d48fc1bb818ff Mon Sep 17 00:00:00 2001
From: Chris Hopman <cjhopman@fb.com>
Date: Fri, 5 Feb 2016 18:09:18 -0800
Subject: [PATCH 1046/1411] Fix race in catalyst tests

Summary:
Native code accesses the Java Application through the ApplicationHolder. The application should be set on the holder as soon as possible. This change fixes a race in WebWorkersTest.

public

Reviewed By: astreet

Differential Revision: D2905157

fb-gh-sync-id: 7e488f4eecefedb8482276776b3a66e14a843f90
---
 .../facebook/react/testing/ReactIntegrationTestCase.java   | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java
index 3b8f1aba6146..5161a4aaab60 100644
--- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java
@@ -147,7 +147,6 @@ public void initializeWithInstance(CatalystInstance instance) {
     mBridgeIdleSignaler = new ReactBridgeIdleSignaler();
     mInstance.addBridgeIdleDebugListener(mBridgeIdleSignaler);
     getContext().initializeWithInstance(mInstance);
-    ApplicationHolder.setApplication((Application) getContext().getApplicationContext());
   }
 
   public boolean waitForBridgeIdle(long millis) {
@@ -165,6 +164,12 @@ public void waitForBridgeAndUIIdle() {
         IDLE_TIMEOUT_MS);
   }
 
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+    ApplicationHolder.setApplication((Application) getContext().getApplicationContext());
+  }
+
   @Override
   protected void tearDown() throws Exception {
     super.tearDown();

From fc94f1e6d0ac61e250c13d293ff76c9c5a5dbbf5 Mon Sep 17 00:00:00 2001
From: Chris Hopman <cjhopman@fb.com>
Date: Fri, 5 Feb 2016 18:09:21 -0800
Subject: [PATCH 1047/1411] Update ReactAndroid/main/jni/react to use glog for
 logging

Summary:
Updates uses of FBLOG* and FBASSERT* to their glog equivalents.

public

Reviewed By: astreet

Differential Revision: D2905159

fb-gh-sync-id: 1f916283aa3de68d8469c8d4ca7fa0874cec28ef
---
 ReactAndroid/src/main/jni/react/BUCK          |  1 +
 .../src/main/jni/react/JSCHelpers.cpp         |  4 ++--
 .../src/main/jni/react/JSCWebWorker.cpp       | 20 +++++++++----------
 .../src/main/jni/react/JSCWebWorker.h         |  2 --
 4 files changed, 13 insertions(+), 14 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/BUCK b/ReactAndroid/src/main/jni/react/BUCK
index 39e35cfe23df..10b22bdcd140 100644
--- a/ReactAndroid/src/main/jni/react/BUCK
+++ b/ReactAndroid/src/main/jni/react/BUCK
@@ -9,6 +9,7 @@ DEPS = [
   '//native/third-party/android-ndk:android',
   '//xplat/fbsystrace:fbsystrace',
   '//xplat/folly:molly',
+  '//xplat/third-party/glog:glog',
 ]
 
 PREPROCESSOR_FLAGS = [
diff --git a/ReactAndroid/src/main/jni/react/JSCHelpers.cpp b/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
index 7e6b8db3c999..b24651bd36b5 100644
--- a/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
@@ -3,7 +3,7 @@
 #include "JSCHelpers.h"
 
 #include <JavaScriptCore/JSStringRef.h>
-#include <fb/log.h>
+#include <glog/logging.h>
 #include <jni/fbjni/Exceptions.h>
 
 #include "Value.h"
@@ -52,7 +52,7 @@ JSValueRef evaluateScript(JSContextRef context, JSStringRef script, JSStringRef
   if (result == nullptr) {
     Value exception = Value(context, exn);
     std::string exceptionText = exception.toString().str();
-    FBLOGE("Got JS Exception: %s", exceptionText.c_str());
+    LOG(ERROR) << "Got JS Exception: " << exceptionText;
     auto line = exception.asObject().getProperty("line");
 
     std::ostringstream locationInfo;
diff --git a/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp b/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
index c0313c4eba21..961ac8269c4a 100644
--- a/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
@@ -1,17 +1,17 @@
 // Copyright 2004-present Facebook. All Rights Reserved.
 
+#include "JSCWebWorker.h"
+
 #include <unistd.h>
 #include <condition_variable>
 #include <mutex>
 #include <unordered_map>
 
-#include <fb/assert.h>
-#include <fb/log.h>
+#include <glog/logging.h>
 #include <folly/Memory.h>
 #include <jni/fbjni/Exceptions.h>
 #include <jni/LocalReference.h>
 
-#include "JSCWebWorker.h"
 #include "JSCHelpers.h"
 #include "jni/JMessageQueueThread.h"
 #include "jni/JSLoader.h"
@@ -33,9 +33,9 @@ JSCWebWorker::JSCWebWorker(int id, JSCWebWorkerOwner *owner, std::string scriptS
     scriptName_(std::move(scriptSrc)),
     owner_(owner) {
   ownerMessageQueueThread_ = owner->getMessageQueueThread();
-  FBASSERTMSGF(ownerMessageQueueThread_, "Owner MessageQueueThread must not be null");
+  CHECK(ownerMessageQueueThread_) << "Owner MessageQueue must not be null";
   workerMessageQueueThread_ = WebWorkers::createWebWorkerThread(id, ownerMessageQueueThread_.get());
-  FBASSERTMSGF(workerMessageQueueThread_, "Failed to create worker thread");
+  CHECK(workerMessageQueueThread_) << "Failed to create worker thread";
 
   workerMessageQueueThread_->runOnQueue([this] () {
     initJSVMAndLoadScript();
@@ -43,7 +43,7 @@ JSCWebWorker::JSCWebWorker(int id, JSCWebWorkerOwner *owner, std::string scriptS
 }
 
 JSCWebWorker::~JSCWebWorker() {
-  FBASSERTMSGF(isTerminated(), "Didn't terminate the web worker before releasing it!");
+  CHECK(isTerminated()) << "Didn't terminate the web worker before releasing it!";;
 }
 
 void JSCWebWorker::postMessage(JSValueRef msg) {
@@ -99,15 +99,15 @@ bool JSCWebWorker::isTerminated() {
 }
 
 void JSCWebWorker::initJSVMAndLoadScript() {
-  FBASSERTMSGF(!isTerminated(), "Worker was already finished!");
-  FBASSERTMSGF(!context_, "Worker JS VM was already created!");
+  CHECK(!isTerminated()) << "Worker was already finished!";
+  CHECK(!context_) << "Worker JS VM was already created!";
 
   context_ = JSGlobalContextCreateInGroup(
       NULL, // use default JS 'global' object
       NULL // create new group (i.e. new VM)
-  ); 
+  );
   s_globalContextRefToJSCWebWorker[context_] = this;
-  
+
   // TODO(9604438): Protect against script does not exist
   std::string script = loadScriptFromAssets(scriptName_);
   evaluateScript(context_, String(script.c_str()), String(scriptName_.c_str()));
diff --git a/ReactAndroid/src/main/jni/react/JSCWebWorker.h b/ReactAndroid/src/main/jni/react/JSCWebWorker.h
index e8bda56f11f9..4f0374e030e3 100644
--- a/ReactAndroid/src/main/jni/react/JSCWebWorker.h
+++ b/ReactAndroid/src/main/jni/react/JSCWebWorker.h
@@ -11,8 +11,6 @@
 
 #include "Value.h"
 
-using namespace facebook::jni;
-
 namespace facebook {
 namespace react {
 

From 2c8802f3169980d648204862cde98f6dbbd37fba Mon Sep 17 00:00:00 2001
From: Chris Hopman <cjhopman@fb.com>
Date: Fri, 5 Feb 2016 18:09:22 -0800
Subject: [PATCH 1048/1411] Make JSExecutorFactory not derive from
 fbjni::Countable

Summary:
This adds a CountableJSExecutorFactory that derives from Countable. And uses that. Basically it allows code that doesn't need to know about jni or Countable not depend on it.
public

Reviewed By: astreet

Differential Revision: D2905163

fb-gh-sync-id: f2bfd5589a3185bb175ad51660b17be08ba62424
---
 ReactAndroid/src/main/jni/react/Bridge.cpp          |  2 +-
 ReactAndroid/src/main/jni/react/Bridge.h            |  5 ++++-
 ReactAndroid/src/main/jni/react/Executor.h          |  3 +--
 ReactAndroid/src/main/jni/react/jni/OnLoad.cpp      | 10 ++++++++--
 ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h |  3 ++-
 5 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/Bridge.cpp b/ReactAndroid/src/main/jni/react/Bridge.cpp
index 0e6982af5948..e4645f37e247 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.cpp
+++ b/ReactAndroid/src/main/jni/react/Bridge.cpp
@@ -13,7 +13,7 @@ using fbsystrace::FbSystraceSection;
 namespace facebook {
 namespace react {
 
-Bridge::Bridge(const RefPtr<JSExecutorFactory>& jsExecutorFactory, Callback callback) :
+Bridge::Bridge(const RefPtr<CountableJSExecutorFactory>& jsExecutorFactory, Callback callback) :
   m_callback(std::move(callback)),
   m_destroyed(std::shared_ptr<bool>(new bool(false)))
 {
diff --git a/ReactAndroid/src/main/jni/react/Bridge.h b/ReactAndroid/src/main/jni/react/Bridge.h
index 33f7a4a99df3..eab3ee89a4a8 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.h
+++ b/ReactAndroid/src/main/jni/react/Bridge.h
@@ -22,11 +22,14 @@ struct dynamic;
 namespace facebook {
 namespace react {
 
+class CountableJSExecutorFactory : public JSExecutorFactory, public Countable {
+};
+
 class Bridge : public Countable {
 public:
   typedef std::function<void(std::vector<MethodCall>, bool isEndOfBatch)> Callback;
 
-  Bridge(const RefPtr<JSExecutorFactory>& jsExecutorFactory, Callback callback);
+  Bridge(const RefPtr<CountableJSExecutorFactory>& jsExecutorFactory, Callback callback);
   virtual ~Bridge();
 
   /**
diff --git a/ReactAndroid/src/main/jni/react/Executor.h b/ReactAndroid/src/main/jni/react/Executor.h
index b4697d6d52ef..2cd891ac1c14 100644
--- a/ReactAndroid/src/main/jni/react/Executor.h
+++ b/ReactAndroid/src/main/jni/react/Executor.h
@@ -5,7 +5,6 @@
 #include <string>
 #include <vector>
 #include <memory>
-#include <jni/Countable.h>
 #include "JSModulesUnbundle.h"
 
 namespace folly {
@@ -21,7 +20,7 @@ class JSExecutor;
 
 typedef std::function<void(std::string, bool)> FlushImmediateCallback;
 
-class JSExecutorFactory : public Countable {
+class JSExecutorFactory {
 public:
   virtual std::unique_ptr<JSExecutor> createJSExecutor(FlushImmediateCallback cb) = 0;
   virtual ~JSExecutorFactory() {};
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 1acaa4175454..4abc78f20762 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -627,7 +627,7 @@ static void create(JNIEnv* env, jobject obj, jobject executor, jobject callback,
   auto bridgeCallback = [weakCallback, weakCallbackQueueThread] (std::vector<MethodCall> calls, bool isEndOfBatch) {
     dispatchCallbacksToJava(weakCallback, weakCallbackQueueThread, std::move(calls), isEndOfBatch);
   };
-  auto nativeExecutorFactory = extractRefPtr<JSExecutorFactory>(env, executor);
+  auto nativeExecutorFactory = extractRefPtr<CountableJSExecutorFactory>(env, executor);
   auto bridge = createNew<Bridge>(nativeExecutorFactory, bridgeCallback);
   setCountableForJava(env, obj, std::move(bridge));
 }
@@ -774,8 +774,14 @@ static void handleMemoryPressureCritical(JNIEnv* env, jobject obj) {
 
 namespace executors {
 
+struct CountableJSCExecutorFactory : CountableJSExecutorFactory  {
+  virtual std::unique_ptr<JSExecutor> createJSExecutor(FlushImmediateCallback cb) override {
+    return JSCExecutorFactory().createJSExecutor(cb);
+  }
+};
+
 static void createJSCExecutor(JNIEnv *env, jobject obj) {
-  auto executor = createNew<JSCExecutorFactory>();
+  auto executor = createNew<CountableJSCExecutorFactory>();
   setCountableForJava(env, obj, std::move(executor));
 }
 
diff --git a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
index d88fc3d111c9..5e168db836f9 100644
--- a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
+++ b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
@@ -2,6 +2,7 @@
 
 #pragma once
 
+#include <react/Bridge.h>
 #include <react/Executor.h>
 #include <jni/fbjni.h>
 #include <jni.h>
@@ -14,7 +15,7 @@ namespace react {
  * This executor factory can only create a single executor instance because it moves
  * executorInstance global reference to the executor instance it creates.
  */
-class ProxyExecutorOneTimeFactory : public JSExecutorFactory {
+class ProxyExecutorOneTimeFactory : public CountableJSExecutorFactory {
 public:
   ProxyExecutorOneTimeFactory(jni::global_ref<jobject>&& executorInstance) :
     m_executor(std::move(executorInstance)) {}

From 75ca46e332269da3da3380d54bad2637bd7f0806 Mon Sep 17 00:00:00 2001
From: Chris Hopman <cjhopman@fb.com>
Date: Fri, 5 Feb 2016 18:09:24 -0800
Subject: [PATCH 1049/1411] Inject some behavior from react/jni/ to react/

Summary:
So, this makes it so a set of behaviors that require accessing java can be injected from the jni/ folder. The behaviors are logging, perf logging, log markers and loading script from assets.

I'd argue that these should all actually be encapsulated by interfaces that are passed to the JSCExecutor/others (and I'd say that's regardless of whether they are injected from jni/ or not), but I wanted to stick to the least disruptive pattern for these changes.

public

Reviewed By: astreet

Differential Revision: D2905168

fb-gh-sync-id: 7c8c16cb77b8fc3d42750dacc6574259ad512ac2
---
 ReactAndroid/src/main/jni/react/BUCK          |  6 +--
 .../src/main/jni/react/JSCExecutor.cpp        | 51 +++----------------
 .../src/main/jni/react/JSCWebWorker.cpp       |  3 +-
 ReactAndroid/src/main/jni/react/Platform.cpp  | 24 +++++++++
 ReactAndroid/src/main/jni/react/Platform.h    | 39 ++++++++++++++
 ReactAndroid/src/main/jni/react/jni/BUCK      |  5 ++
 .../jni/react/{ => jni}/JSCPerfLogging.cpp    |  4 +-
 .../main/jni/react/{ => jni}/JSCPerfLogging.h |  0
 .../src/main/jni/react/jni/JSLoader.cpp       |  6 +--
 .../src/main/jni/react/jni/JSLoader.h         |  6 +--
 .../src/main/jni/react/jni/JSLogging.cpp      | 36 +++++++++++++
 .../src/main/jni/react/jni/JSLogging.h        | 15 ++++++
 .../src/main/jni/react/jni/OnLoad.cpp         | 21 ++++++++
 13 files changed, 160 insertions(+), 56 deletions(-)
 create mode 100644 ReactAndroid/src/main/jni/react/Platform.cpp
 create mode 100644 ReactAndroid/src/main/jni/react/Platform.h
 rename ReactAndroid/src/main/jni/react/{ => jni}/JSCPerfLogging.cpp (99%)
 rename ReactAndroid/src/main/jni/react/{ => jni}/JSCPerfLogging.h (100%)
 create mode 100644 ReactAndroid/src/main/jni/react/jni/JSLogging.cpp
 create mode 100644 ReactAndroid/src/main/jni/react/jni/JSLogging.h

diff --git a/ReactAndroid/src/main/jni/react/BUCK b/ReactAndroid/src/main/jni/react/BUCK
index 10b22bdcd140..aebe0af685cd 100644
--- a/ReactAndroid/src/main/jni/react/BUCK
+++ b/ReactAndroid/src/main/jni/react/BUCK
@@ -46,15 +46,14 @@ react_library(
     'JSCExecutor.cpp',
     'JSCTracing.cpp',
     'JSCMemory.cpp',
-    'JSCPerfLogging.cpp',
     'JSCLegacyProfiler.cpp',
     'JSCWebWorker.cpp',
+    'Platform.cpp',
   ],
   headers = [
     'JSCTracing.h',
-    'JSCPerfLogging.h',
     'JSCLegacyProfiler.h',
-    'JSCMemory.h'
+    'JSCMemory.h',
   ],
   exported_headers = [
     'Bridge.h',
@@ -65,6 +64,7 @@ react_library(
     'MethodCall.h',
     'JSModulesUnbundle.h',
     'Value.h',
+    'Platform.h',
   ],
   compiler_flags = [
     '-Wall',
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index f62ec6e56dac..ae1aa7a4ff0f 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -15,6 +15,7 @@
 #include "jni/JMessageQueueThread.h"
 #include "jni/OnLoad.h"
 #include <react/JSCHelpers.h>
+#include "Platform.h"
 
 #ifdef WITH_JSC_EXTRA_TRACING
 #include <react/JSCTracing.h>
@@ -31,9 +32,6 @@
 using fbsystrace::FbSystraceSection;
 #endif
 
-// Add native performance markers support
-#include <react/JSCPerfLogging.h>
-
 #ifdef WITH_FB_MEMORY_PROFILING
 #include <react/JSCMemory.h>
 #endif
@@ -59,13 +57,6 @@ static JSValueRef nativeFlushQueueImmediate(
     size_t argumentCount,
     const JSValueRef arguments[],
     JSValueRef *exception);
-static JSValueRef nativeLoggingHook(
-    JSContextRef ctx,
-    JSObjectRef function,
-    JSObjectRef thisObject,
-    size_t argumentCount,
-    const JSValueRef arguments[],
-    JSValueRef *exception);
 static JSValueRef nativePerformanceNow(
     JSContextRef ctx,
     JSObjectRef function,
@@ -103,12 +94,13 @@ JSCExecutor::JSCExecutor(FlushImmediateCallback cb) :
   m_messageQueueThread = JMessageQueueThread::currentMessageQueueThread();
   s_globalContextRefToJSCExecutor[m_context] = this;
   installGlobalFunction(m_context, "nativeFlushQueueImmediate", nativeFlushQueueImmediate);
-  installGlobalFunction(m_context, "nativeLoggingHook", nativeLoggingHook);
   installGlobalFunction(m_context, "nativePerformanceNow", nativePerformanceNow);
   installGlobalFunction(m_context, "nativeStartWorker", nativeStartWorker);
   installGlobalFunction(m_context, "nativePostMessageToWorker", nativePostMessageToWorker);
   installGlobalFunction(m_context, "nativeTerminateWorker", nativeTerminateWorker);
 
+  installGlobalFunction(m_context, "nativeLoggingHook", JSLogging::nativeHook);
+
   #ifdef WITH_FB_JSC_TUNING
   configureJSCForAndroid();
   #endif
@@ -116,7 +108,7 @@ JSCExecutor::JSCExecutor(FlushImmediateCallback cb) :
   #ifdef WITH_JSC_EXTRA_TRACING
   addNativeTracingHooks(m_context);
   addNativeProfilingHooks(m_context);
-  addNativePerfLoggingHooks(m_context);
+  PerfLogging::installNativeHooks(m_context);
   #endif
 
   #ifdef WITH_FB_MEMORY_PROFILING
@@ -164,17 +156,9 @@ std::string JSCExecutor::getDeviceCacheDir(){
 void JSCExecutor::executeApplicationScript(
     const std::string& script,
     const std::string& sourceURL) {
-  JNIEnv* env = Environment::current();
-  jclass markerClass = env->FindClass("com/facebook/react/bridge/ReactMarker");
-  jmethodID logMarkerMethod = facebook::react::getLogMarkerMethod();
-  jstring startStringMarker = env->NewStringUTF("executeApplicationScript_startStringConvert");
-  jstring endStringMarker = env->NewStringUTF("executeApplicationScript_endStringConvert");
-
-  env->CallStaticVoidMethod(markerClass, logMarkerMethod, startStringMarker);
+  ReactMarker::logMarker("executeApplicationScript_startStringConvert");
   String jsScript = String::createExpectingAscii(script);
-  env->CallStaticVoidMethod(markerClass, logMarkerMethod, endStringMarker);
-  env->DeleteLocalRef(startStringMarker);
-  env->DeleteLocalRef(endStringMarker);
+  ReactMarker::logMarker("executeApplicationScript_endStringConvert");
 
   String jsSourceURL(sourceURL.c_str());
   #ifdef WITH_FBSYSTRACE
@@ -504,29 +488,6 @@ JSValueRef JSCExecutor::nativeTerminateWorker(
   return JSValueMakeUndefined(ctx);
 }
 
-static JSValueRef nativeLoggingHook(
-    JSContextRef ctx,
-    JSObjectRef function,
-    JSObjectRef thisObject,
-    size_t argumentCount,
-    const JSValueRef arguments[], JSValueRef *exception) {
-  android_LogPriority logLevel = ANDROID_LOG_DEBUG;
-  if (argumentCount > 1) {
-    int level = (int) JSValueToNumber(ctx, arguments[1], NULL);
-    // The lowest log level we get from JS is 0. We shift and cap it to be
-    // in the range the Android logging method expects.
-    logLevel = std::min(
-        static_cast<android_LogPriority>(level + ANDROID_LOG_DEBUG),
-        ANDROID_LOG_FATAL);
-  }
-  if (argumentCount > 0) {
-    JSStringRef jsString = JSValueToStringCopy(ctx, arguments[0], NULL);
-    String message = String::adopt(jsString);
-    FBLOG_PRI(logLevel, "ReactNativeJS", "%s", message.str().c_str());
-  }
-  return JSValueMakeUndefined(ctx);
-}
-
 static JSValueRef nativePerformanceNow(
     JSContextRef ctx,
     JSObjectRef function,
diff --git a/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp b/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
index 961ac8269c4a..27ba10114447 100644
--- a/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
@@ -16,6 +16,7 @@
 #include "jni/JMessageQueueThread.h"
 #include "jni/JSLoader.h"
 #include "jni/WebWorkers.h"
+#include "Platform.h"
 #include "Value.h"
 
 #include <JavaScriptCore/JSValueRef.h>
@@ -109,7 +110,7 @@ void JSCWebWorker::initJSVMAndLoadScript() {
   s_globalContextRefToJSCWebWorker[context_] = this;
 
   // TODO(9604438): Protect against script does not exist
-  std::string script = loadScriptFromAssets(scriptName_);
+  std::string script = WebWorkerUtil::loadScriptFromAssets(scriptName_);
   evaluateScript(context_, String(script.c_str()), String(scriptName_.c_str()));
 
   installGlobalFunction(context_, "postMessage", nativePostMessage);
diff --git a/ReactAndroid/src/main/jni/react/Platform.cpp b/ReactAndroid/src/main/jni/react/Platform.cpp
new file mode 100644
index 000000000000..be5caf546402
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/Platform.cpp
@@ -0,0 +1,24 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#include "Platform.h"
+
+namespace facebook {
+namespace react {
+
+namespace ReactMarker {
+LogMarker logMarker;
+};
+
+namespace WebWorkerUtil {
+LoadScriptFromAssets loadScriptFromAssets;
+};
+
+namespace PerfLogging {
+InstallNativeHooks installNativeHooks;
+}
+
+namespace JSLogging {
+JSCNativeHook nativeHook = nullptr;
+}
+
+} }
diff --git a/ReactAndroid/src/main/jni/react/Platform.h b/ReactAndroid/src/main/jni/react/Platform.h
new file mode 100644
index 000000000000..3de8b4b6b3ab
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/Platform.h
@@ -0,0 +1,39 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <string>
+
+#include <JavaScriptCore/JSContextRef.h>
+
+namespace facebook {
+namespace react {
+
+namespace ReactMarker {
+using LogMarker = std::function<void(const std::string&)>;
+extern LogMarker logMarker;
+};
+
+namespace WebWorkerUtil {
+using LoadScriptFromAssets = std::function<std::string(const std::string& assetName)>;
+extern LoadScriptFromAssets loadScriptFromAssets;
+};
+
+namespace PerfLogging {
+using InstallNativeHooks = std::function<void(JSGlobalContextRef)>;
+extern InstallNativeHooks installNativeHooks;
+}
+
+namespace JSLogging {
+  using JSCNativeHook = JSValueRef (*) (
+      JSContextRef ctx,
+      JSObjectRef function,
+      JSObjectRef thisObject,
+      size_t argumentCount,
+      const JSValueRef arguments[], JSValueRef *exception);
+  extern JSCNativeHook nativeHook;
+}
+
+} }
diff --git a/ReactAndroid/src/main/jni/react/jni/BUCK b/ReactAndroid/src/main/jni/react/jni/BUCK
index d29ea7dc604e..32d3f3f90a3a 100644
--- a/ReactAndroid/src/main/jni/react/jni/BUCK
+++ b/ReactAndroid/src/main/jni/react/jni/BUCK
@@ -5,6 +5,7 @@ SUPPORTED_PLATFORMS = '^android-(armv7|x86)$'
 
 DEPS = [
   '//native/jni:jni',
+  '//native/third-party/android-ndk:android',
   '//xplat/folly:molly',
 ]
 
@@ -28,14 +29,18 @@ jni_library(
   supported_platforms_regex = SUPPORTED_PLATFORMS,
   srcs = [
     'JMessageQueueThread.cpp',
+    'JSCPerfLogging.cpp',
     'JSLoader.cpp',
     'NativeArray.cpp',
     'OnLoad.cpp',
     'ProxyExecutor.cpp',
+    'JSLogging.cpp',
   ],
   headers = [
     'JSLoader.h',
     'ProxyExecutor.h',
+    'JSCPerfLogging.h',
+    'JSLogging.h',
   ],
   exported_headers = [
     'JMessageQueueThread.h',
diff --git a/ReactAndroid/src/main/jni/react/JSCPerfLogging.cpp b/ReactAndroid/src/main/jni/react/jni/JSCPerfLogging.cpp
similarity index 99%
rename from ReactAndroid/src/main/jni/react/JSCPerfLogging.cpp
rename to ReactAndroid/src/main/jni/react/jni/JSCPerfLogging.cpp
index 3700b14c050f..d480a8833ae9 100644
--- a/ReactAndroid/src/main/jni/react/JSCPerfLogging.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/JSCPerfLogging.cpp
@@ -1,8 +1,10 @@
 // Copyright 2004-present Facebook. All Rights Reserved.
 
-#include "JSCHelpers.h"
+#include "JSCPerfLogging.h"
+
 #include <fb/log.h>
 #include <jni/fbjni.h>
+#include <react/JSCHelpers.h>
 
 using namespace facebook::jni;
 
diff --git a/ReactAndroid/src/main/jni/react/JSCPerfLogging.h b/ReactAndroid/src/main/jni/react/jni/JSCPerfLogging.h
similarity index 100%
rename from ReactAndroid/src/main/jni/react/JSCPerfLogging.h
rename to ReactAndroid/src/main/jni/react/jni/JSCPerfLogging.h
diff --git a/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp b/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp
index 24937d51b5f2..a96d0c3ded6c 100644
--- a/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp
@@ -21,7 +21,7 @@ static jclass gApplicationHolderClass;
 static jmethodID gGetApplicationMethod;
 static jmethodID gGetAssetManagerMethod;
 
-std::string loadScriptFromAssets(std::string assetName) {
+std::string loadScriptFromAssets(const std::string& assetName) {
   JNIEnv *env = jni::Environment::current();
   jobject application = env->CallStaticObjectMethod(
     gApplicationHolderClass,
@@ -32,7 +32,7 @@ std::string loadScriptFromAssets(std::string assetName) {
 
 std::string loadScriptFromAssets(
     AAssetManager *manager,
-    std::string assetName) {
+    const std::string& assetName) {
   #ifdef WITH_FBSYSTRACE
   FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "reactbridge_jni_loadScriptFromAssets",
     "assetName", assetName);
@@ -59,7 +59,7 @@ std::string loadScriptFromAssets(
   return "";
 }
 
-std::string loadScriptFromFile(std::string fileName) {
+std::string loadScriptFromFile(const std::string& fileName) {
   #ifdef WITH_FBSYSTRACE
   FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "reactbridge_jni_loadScriptFromFile",
     "fileName", fileName);
diff --git a/ReactAndroid/src/main/jni/react/jni/JSLoader.h b/ReactAndroid/src/main/jni/react/jni/JSLoader.h
index 91aa137c9295..8b716beef17d 100644
--- a/ReactAndroid/src/main/jni/react/jni/JSLoader.h
+++ b/ReactAndroid/src/main/jni/react/jni/JSLoader.h
@@ -13,17 +13,17 @@ namespace react {
  * Helper method for loading a JS script from Android assets without
  * a reference to an AssetManager.
  */
-std::string loadScriptFromAssets(std::string assetName);
+std::string loadScriptFromAssets(const std::string& assetName);
 
 /**
  * Helper method for loading JS script from android asset
  */
-std::string loadScriptFromAssets(AAssetManager *assetManager, std::string assetName);
+std::string loadScriptFromAssets(AAssetManager *assetManager, const std::string& assetName);
 
 /**
  * Helper method for loading JS script from a file
  */
-std::string loadScriptFromFile(std::string fileName);
+std::string loadScriptFromFile(const std::string& fileName);
 
 void registerJSLoaderNatives();
 
diff --git a/ReactAndroid/src/main/jni/react/jni/JSLogging.cpp b/ReactAndroid/src/main/jni/react/jni/JSLogging.cpp
new file mode 100644
index 000000000000..7690a5656ebd
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/jni/JSLogging.cpp
@@ -0,0 +1,36 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#include "JSLogging.h"
+
+#include <android/log.h>
+#include <algorithm>
+#include <react/Value.h>
+#include <fb/log.h>
+
+namespace facebook {
+namespace react {
+
+JSValueRef nativeLoggingHook(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[], JSValueRef *exception) {
+  android_LogPriority logLevel = ANDROID_LOG_DEBUG;
+  if (argumentCount > 1) {
+    int level = (int) JSValueToNumber(ctx, arguments[1], NULL);
+    // The lowest log level we get from JS is 0. We shift and cap it to be
+    // in the range the Android logging method expects.
+    logLevel = std::min(
+        static_cast<android_LogPriority>(level + ANDROID_LOG_DEBUG),
+        ANDROID_LOG_FATAL);
+  }
+  if (argumentCount > 0) {
+    JSStringRef jsString = JSValueToStringCopy(ctx, arguments[0], NULL);
+    String message = String::adopt(jsString);
+    FBLOG_PRI(logLevel, "ReactNativeJS", "%s", message.str().c_str());
+  }
+  return JSValueMakeUndefined(ctx);
+}
+
+}};
diff --git a/ReactAndroid/src/main/jni/react/jni/JSLogging.h b/ReactAndroid/src/main/jni/react/jni/JSLogging.h
new file mode 100644
index 000000000000..27756b665076
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/jni/JSLogging.h
@@ -0,0 +1,15 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+#include <JavaScriptCore/JSContextRef.h>
+
+namespace facebook {
+namespace react {
+JSValueRef nativeLoggingHook(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[], JSValueRef *exception);
+}}
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 4abc78f20762..41a4044f61b6 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -15,11 +15,14 @@
 #include <react/Executor.h>
 #include <react/JSCExecutor.h>
 #include <react/JSModulesUnbundle.h>
+#include <react/Platform.h>
 #include "JNativeRunnable.h"
 #include "JSLoader.h"
 #include "ReadableNativeArray.h"
 #include "ProxyExecutor.h"
 #include "OnLoad.h"
+#include "JSLogging.h"
+#include "JSCPerfLogging.h"
 #include <algorithm>
 
 #ifdef WITH_FBSYSTRACE
@@ -561,6 +564,15 @@ static jmethodID gCallbackMethod;
 static jmethodID gOnBatchCompleteMethod;
 static jmethodID gLogMarkerMethod;
 
+static void logMarker(const std::string& marker) {
+  JNIEnv* env = Environment::current();
+  jclass markerClass = env->FindClass("com/facebook/react/bridge/ReactMarker");
+  jstring jmarker = env->NewStringUTF(marker.c_str());
+  env->CallStaticVoidMethod(markerClass, gLogMarkerMethod, jmarker);
+  env->DeleteLocalRef(markerClass);
+  env->DeleteLocalRef(jmarker);
+}
+
 static void makeJavaCall(JNIEnv* env, jobject callback, MethodCall&& call) {
   if (call.arguments.isNull()) {
     return;
@@ -801,6 +813,15 @@ jmethodID getLogMarkerMethod() {
 
 extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
   return initialize(vm, [] {
+    // Inject some behavior into react/
+    ReactMarker::logMarker = bridge::logMarker;
+    WebWorkerUtil::loadScriptFromAssets =
+      [] (const std::string& assetName) {
+        return loadScriptFromAssets(assetName);
+      };
+    PerfLogging::installNativeHooks = addNativePerfLoggingHooks;
+    JSLogging::nativeHook = nativeLoggingHook;
+
     // get the current env
     JNIEnv* env = Environment::current();
 

From 2997c8feed357121806e46aca2c413d3fd122743 Mon Sep 17 00:00:00 2001
From: Chris Hopman <cjhopman@fb.com>
Date: Fri, 5 Feb 2016 18:09:25 -0800
Subject: [PATCH 1050/1411] Move getting the cache dir into react/jni

Summary:
This just moves the jni code that actual figures out the cache dir into OnLoad.cpp and then passes it down to the JSCEXecutorFactory.

public

Reviewed By: astreet

Differential Revision: D2905176

fb-gh-sync-id: bedf52fbeaab6beabac25c87aad00a98ddf182f7
---
 .../src/main/jni/react/JSCExecutor.cpp        | 31 +++----------------
 ReactAndroid/src/main/jni/react/JSCExecutor.h |  7 +++--
 .../src/main/jni/react/jni/OnLoad.cpp         | 25 ++++++++++++++-
 3 files changed, 33 insertions(+), 30 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index ae1aa7a4ff0f..81165a0806ee 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -85,11 +85,11 @@ static std::string executeJSCallWithJSC(
 }
 
 std::unique_ptr<JSExecutor> JSCExecutorFactory::createJSExecutor(FlushImmediateCallback cb) {
-  return std::unique_ptr<JSExecutor>(new JSCExecutor(cb));
+  return std::unique_ptr<JSExecutor>(new JSCExecutor(cb, cacheDir_));
 }
 
-JSCExecutor::JSCExecutor(FlushImmediateCallback cb) :
-    m_flushImmediateCallback(cb) {
+JSCExecutor::JSCExecutor(FlushImmediateCallback cb, const std::string& cacheDir) :
+    m_flushImmediateCallback(cb), m_deviceCacheDir(cacheDir) {
   m_context = JSGlobalContextCreateInGroup(nullptr, nullptr);
   m_messageQueueThread = JMessageQueueThread::currentMessageQueueThread();
   s_globalContextRefToJSCExecutor[m_context] = this;
@@ -130,29 +130,6 @@ JSCExecutor::~JSCExecutor() {
   JSGlobalContextRelease(m_context);
 }
 
-std::string JSCExecutor::getDeviceCacheDir(){
-  // Get the Application Context object
-  auto getApplicationClass = findClassLocal(
-                              "com/facebook/react/common/ApplicationHolder");
-  auto getApplicationMethod = getApplicationClass->getStaticMethod<jobject()>(
-                              "getApplication",
-                              "()Landroid/app/Application;"
-                              );
-  auto application = getApplicationMethod(getApplicationClass);
-
-  // Get getCacheDir() from the context
-  auto getCacheDirMethod = findClassLocal("android/app/Application")
-                            ->getMethod<jobject()>("getCacheDir",
-                                                   "()Ljava/io/File;"
-                                                  );
-  auto cacheDirObj = getCacheDirMethod(application);
-
-  // Call getAbsolutePath() on the returned File object
-  auto getAbsolutePathMethod = findClassLocal("java/io/File")
-                                ->getMethod<jstring()>("getAbsolutePath");
-  return getAbsolutePathMethod(cacheDirObj)->toStdString();
-}
-
 void JSCExecutor::executeApplicationScript(
     const std::string& script,
     const std::string& sourceURL) {
@@ -170,7 +147,7 @@ void JSCExecutor::executeApplicationScript(
   } else {
     // If we're evaluating a script, get the device's cache dir 
     //  in which a cache file for that script will be stored.
-    evaluateScript(m_context, jsScript, jsSourceURL, getDeviceCacheDir().c_str());
+    evaluateScript(m_context, jsScript, jsSourceURL, m_deviceCacheDir.c_str());
   }
 }
 
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.h b/ReactAndroid/src/main/jni/react/JSCExecutor.h
index 9d66fdf99b58..8ddecb100a44 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.h
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.h
@@ -17,7 +17,10 @@ class JMessageQueueThread;
 
 class JSCExecutorFactory : public JSExecutorFactory {
 public:
+  JSCExecutorFactory(const std::string& cacheDir) : cacheDir_(cacheDir) {}
   virtual std::unique_ptr<JSExecutor> createJSExecutor(FlushImmediateCallback cb) override;
+private:
+  std::string cacheDir_;
 };
 
 class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
@@ -25,7 +28,7 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
   /**
    * Should be invoked from the JS thread.
    */
-  explicit JSCExecutor(FlushImmediateCallback flushImmediateCallback);
+  explicit JSCExecutor(FlushImmediateCallback flushImmediateCallback, const std::string& cacheDir);
   ~JSCExecutor() override;
 
   virtual void executeApplicationScript(
@@ -66,12 +69,12 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
   std::shared_ptr<JMessageQueueThread> m_messageQueueThread;
   JSModulesUnbundle m_unbundle;
   bool m_isUnbundleInitialized = false;
+  std::string m_deviceCacheDir;
 
   int addWebWorker(const std::string& script, JSValueRef workerRef);
   void postMessageToWebWorker(int worker, JSValueRef message, JSValueRef *exn);
   void terminateWebWorker(int worker);
   void loadModule(uint32_t moduleId);
-  std::string getDeviceCacheDir();
 
   static JSValueRef nativeStartWorker(
       JSContextRef ctx,
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 41a4044f61b6..49fd32ae3895 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -786,9 +786,32 @@ static void handleMemoryPressureCritical(JNIEnv* env, jobject obj) {
 
 namespace executors {
 
+std::string getDeviceCacheDir() {
+  // Get the Application Context object
+  auto getApplicationClass = findClassLocal(
+                              "com/facebook/react/common/ApplicationHolder");
+  auto getApplicationMethod = getApplicationClass->getStaticMethod<jobject()>(
+                              "getApplication",
+                              "()Landroid/app/Application;"
+                              );
+  auto application = getApplicationMethod(getApplicationClass);
+
+  // Get getCacheDir() from the context
+  auto getCacheDirMethod = findClassLocal("android/app/Application")
+                            ->getMethod<jobject()>("getCacheDir",
+                                                   "()Ljava/io/File;"
+                                                  );
+  auto cacheDirObj = getCacheDirMethod(application);
+
+  // Call getAbsolutePath() on the returned File object
+  auto getAbsolutePathMethod = findClassLocal("java/io/File")
+                                ->getMethod<jstring()>("getAbsolutePath");
+  return getAbsolutePathMethod(cacheDirObj)->toStdString();
+}
+
 struct CountableJSCExecutorFactory : CountableJSExecutorFactory  {
   virtual std::unique_ptr<JSExecutor> createJSExecutor(FlushImmediateCallback cb) override {
-    return JSCExecutorFactory().createJSExecutor(cb);
+    return JSCExecutorFactory(getDeviceCacheDir()).createJSExecutor(cb);
   }
 };
 

From f4b826d6a0172929ab22b3d6a8e3befb999184f5 Mon Sep 17 00:00:00 2001
From: Chris Hopman <cjhopman@fb.com>
Date: Fri, 5 Feb 2016 18:09:26 -0800
Subject: [PATCH 1051/1411] Add MessageQueueThread interface to react/

Summary:
Everything below the bridge interacts with just a MessageQueueThread. The implementation (JMessageQueueThread) is injected from react/jni.

public

Reviewed By: astreet

Differential Revision: D2905178

fb-gh-sync-id: 8b138e746d5a96dd70837bb2149cd4e188fcdacc
---
 ReactAndroid/src/main/jni/react/BUCK          |  1 +
 .../src/main/jni/react/JSCExecutor.cpp        |  5 ++---
 ReactAndroid/src/main/jni/react/JSCExecutor.h |  6 +++---
 .../src/main/jni/react/JSCWebWorker.cpp       |  2 +-
 .../src/main/jni/react/JSCWebWorker.h         |  8 ++++----
 .../src/main/jni/react/MessageQueueThread.h   | 19 +++++++++++++++++++
 ReactAndroid/src/main/jni/react/Platform.cpp  |  4 ++++
 ReactAndroid/src/main/jni/react/Platform.h    |  7 +++++++
 ReactAndroid/src/main/jni/react/jni/BUCK      |  4 ++--
 .../jni/react/jni/JMessageQueueThread.cpp     | 10 +++++-----
 .../main/jni/react/jni/JMessageQueueThread.h  | 18 ++++++++++--------
 .../src/main/jni/react/jni/OnLoad.cpp         |  6 ++++++
 .../src/main/jni/react/jni/WebWorkers.h       |  6 +++---
 13 files changed, 67 insertions(+), 29 deletions(-)
 create mode 100644 ReactAndroid/src/main/jni/react/MessageQueueThread.h

diff --git a/ReactAndroid/src/main/jni/react/BUCK b/ReactAndroid/src/main/jni/react/BUCK
index aebe0af685cd..3ef6b24bf633 100644
--- a/ReactAndroid/src/main/jni/react/BUCK
+++ b/ReactAndroid/src/main/jni/react/BUCK
@@ -61,6 +61,7 @@ react_library(
     'JSCExecutor.h',
     'JSCHelpers.h',
     'JSCWebWorker.h',
+    'MessageQueueThread.h',
     'MethodCall.h',
     'JSModulesUnbundle.h',
     'Value.h',
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index 81165a0806ee..e06a0bef5884 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -12,7 +12,6 @@
 #include <jni/fbjni/Exceptions.h>
 #include <sys/time.h>
 #include "Value.h"
-#include "jni/JMessageQueueThread.h"
 #include "jni/OnLoad.h"
 #include <react/JSCHelpers.h>
 #include "Platform.h"
@@ -91,7 +90,7 @@ std::unique_ptr<JSExecutor> JSCExecutorFactory::createJSExecutor(FlushImmediateC
 JSCExecutor::JSCExecutor(FlushImmediateCallback cb, const std::string& cacheDir) :
     m_flushImmediateCallback(cb), m_deviceCacheDir(cacheDir) {
   m_context = JSGlobalContextCreateInGroup(nullptr, nullptr);
-  m_messageQueueThread = JMessageQueueThread::currentMessageQueueThread();
+  m_messageQueueThread = MessageQueues::getCurrentMessageQueueThread();
   s_globalContextRefToJSCExecutor[m_context] = this;
   installGlobalFunction(m_context, "nativeFlushQueueImmediate", nativeFlushQueueImmediate);
   installGlobalFunction(m_context, "nativePerformanceNow", nativePerformanceNow);
@@ -255,7 +254,7 @@ JSGlobalContextRef JSCExecutor::getContext() {
   return m_context;
 }
 
-std::shared_ptr<JMessageQueueThread> JSCExecutor::getMessageQueueThread() {
+std::shared_ptr<MessageQueueThread> JSCExecutor::getMessageQueueThread() {
   return m_messageQueueThread;
 }
 
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.h b/ReactAndroid/src/main/jni/react/JSCExecutor.h
index 8ddecb100a44..f0f3b490677a 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.h
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.h
@@ -13,7 +13,7 @@
 namespace facebook {
 namespace react {
 
-class JMessageQueueThread;
+class MessageQueueThread;
 
 class JSCExecutorFactory : public JSExecutorFactory {
 public:
@@ -59,16 +59,16 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
   void installNativeHook(const char *name, JSObjectCallAsFunctionCallback callback);
   virtual void onMessageReceived(int workerId, const std::string& message) override;
   virtual JSGlobalContextRef getContext() override;
-  virtual std::shared_ptr<JMessageQueueThread> getMessageQueueThread() override;
+  virtual std::shared_ptr<MessageQueueThread> getMessageQueueThread() override;
 
 private:
   JSGlobalContextRef m_context;
   FlushImmediateCallback m_flushImmediateCallback;
   std::unordered_map<int, JSCWebWorker> m_webWorkers;
   std::unordered_map<int, Object> m_webWorkerJSObjs;
-  std::shared_ptr<JMessageQueueThread> m_messageQueueThread;
   JSModulesUnbundle m_unbundle;
   bool m_isUnbundleInitialized = false;
+  std::shared_ptr<MessageQueueThread> m_messageQueueThread;
   std::string m_deviceCacheDir;
 
   int addWebWorker(const std::string& script, JSValueRef workerRef);
diff --git a/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp b/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
index 27ba10114447..91895b800ec2 100644
--- a/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
@@ -13,9 +13,9 @@
 #include <jni/LocalReference.h>
 
 #include "JSCHelpers.h"
-#include "jni/JMessageQueueThread.h"
 #include "jni/JSLoader.h"
 #include "jni/WebWorkers.h"
+#include "MessageQueueThread.h"
 #include "Platform.h"
 #include "Value.h"
 
diff --git a/ReactAndroid/src/main/jni/react/JSCWebWorker.h b/ReactAndroid/src/main/jni/react/JSCWebWorker.h
index 4f0374e030e3..73d983cdfe7b 100644
--- a/ReactAndroid/src/main/jni/react/JSCWebWorker.h
+++ b/ReactAndroid/src/main/jni/react/JSCWebWorker.h
@@ -14,7 +14,7 @@
 namespace facebook {
 namespace react {
 
-class JMessageQueueThread;
+class MessageQueueThread;
 
 /**
  * A class that can own the lifecycle, receive messages from, and dispatch messages
@@ -32,7 +32,7 @@ class JSCWebWorkerOwner {
    * Should return the owner's MessageQueueThread. Calls to onMessageReceived will be enqueued
    * on this thread.
    */
-  virtual std::shared_ptr<JMessageQueueThread> getMessageQueueThread() = 0;
+  virtual std::shared_ptr<MessageQueueThread> getMessageQueueThread() = 0;
 };
 
 /**
@@ -77,8 +77,8 @@ class JSCWebWorker {
   std::atomic_bool isTerminated_ = ATOMIC_VAR_INIT(false);
   std::string scriptName_;
   JSCWebWorkerOwner *owner_ = nullptr;
-  std::shared_ptr<JMessageQueueThread> ownerMessageQueueThread_;
-  std::unique_ptr<JMessageQueueThread> workerMessageQueueThread_;
+  std::shared_ptr<MessageQueueThread> ownerMessageQueueThread_;
+  std::unique_ptr<MessageQueueThread> workerMessageQueueThread_;
   JSGlobalContextRef context_ = nullptr;
 
   static JSValueRef nativePostMessage(
diff --git a/ReactAndroid/src/main/jni/react/MessageQueueThread.h b/ReactAndroid/src/main/jni/react/MessageQueueThread.h
new file mode 100644
index 000000000000..544b91142be9
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/MessageQueueThread.h
@@ -0,0 +1,19 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+#include <functional>
+
+namespace facebook {
+namespace react {
+
+class MessageQueueThread {
+ public:
+  virtual ~MessageQueueThread() {}
+  virtual void runOnQueue(std::function<void()>&&) = 0;
+  virtual bool isOnThread() = 0;
+  // quitSynchronous() should synchronously ensure that no further tasks will run on the queue.
+  virtual void quitSynchronous() = 0;
+};
+
+}}
diff --git a/ReactAndroid/src/main/jni/react/Platform.cpp b/ReactAndroid/src/main/jni/react/Platform.cpp
index be5caf546402..d91cfcaebe28 100644
--- a/ReactAndroid/src/main/jni/react/Platform.cpp
+++ b/ReactAndroid/src/main/jni/react/Platform.cpp
@@ -9,6 +9,10 @@ namespace ReactMarker {
 LogMarker logMarker;
 };
 
+namespace MessageQueues {
+GetCurrentMessageQueueThread getCurrentMessageQueueThread;
+};
+
 namespace WebWorkerUtil {
 LoadScriptFromAssets loadScriptFromAssets;
 };
diff --git a/ReactAndroid/src/main/jni/react/Platform.h b/ReactAndroid/src/main/jni/react/Platform.h
index 3de8b4b6b3ab..4fa42591ae72 100644
--- a/ReactAndroid/src/main/jni/react/Platform.h
+++ b/ReactAndroid/src/main/jni/react/Platform.h
@@ -6,6 +6,8 @@
 #include <memory>
 #include <string>
 
+#include "MessageQueueThread.h"
+
 #include <JavaScriptCore/JSContextRef.h>
 
 namespace facebook {
@@ -16,6 +18,11 @@ using LogMarker = std::function<void(const std::string&)>;
 extern LogMarker logMarker;
 };
 
+namespace MessageQueues {
+using GetCurrentMessageQueueThread = std::function<std::unique_ptr<MessageQueueThread>()>;
+extern GetCurrentMessageQueueThread getCurrentMessageQueueThread;
+};
+
 namespace WebWorkerUtil {
 using LoadScriptFromAssets = std::function<std::string(const std::string& assetName)>;
 extern LoadScriptFromAssets loadScriptFromAssets;
diff --git a/ReactAndroid/src/main/jni/react/jni/BUCK b/ReactAndroid/src/main/jni/react/jni/BUCK
index 32d3f3f90a3a..da77b5275ce1 100644
--- a/ReactAndroid/src/main/jni/react/jni/BUCK
+++ b/ReactAndroid/src/main/jni/react/jni/BUCK
@@ -39,12 +39,12 @@ jni_library(
   headers = [
     'JSLoader.h',
     'ProxyExecutor.h',
+    'JMessageQueueThread.h',
+    'JNativeRunnable.h',
     'JSCPerfLogging.h',
     'JSLogging.h',
   ],
   exported_headers = [
-    'JMessageQueueThread.h',
-    'JNativeRunnable.h',
     'NativeArray.h',
     'ReadableNativeArray.h',
     'WebWorkers.h',
diff --git a/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.cpp b/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.cpp
index 8499f7b1c615..0c068ab19de4 100644
--- a/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.cpp
@@ -11,24 +11,24 @@
 namespace facebook {
 namespace react {
 
-JMessageQueueThread::JMessageQueueThread(alias_ref<MessageQueueThread::javaobject> jobj) :
+JMessageQueueThread::JMessageQueueThread(alias_ref<JavaMessageQueueThread::javaobject> jobj) :
     m_jobj(make_global(jobj)) {
 }
 
 void JMessageQueueThread::runOnQueue(std::function<void()>&& runnable) {
-  static auto method = MessageQueueThread::javaClassStatic()->
+  static auto method = JavaMessageQueueThread::javaClassStatic()->
     getMethod<void(Runnable::javaobject)>("runOnQueue");
   method(m_jobj, JNativeRunnable::newObjectCxxArgs(runnable).get());
 }
 
 bool JMessageQueueThread::isOnThread() {
-  static auto method = MessageQueueThread::javaClassStatic()->
+  static auto method = JavaMessageQueueThread::javaClassStatic()->
     getMethod<jboolean()>("isOnThread");
   return method(m_jobj);
 }
 
 void JMessageQueueThread::quitSynchronous() {
-  static auto method = MessageQueueThread::javaClassStatic()->
+  static auto method = JavaMessageQueueThread::javaClassStatic()->
     getMethod<void()>("quitSynchronous");
   method(m_jobj);
 }
@@ -36,7 +36,7 @@ void JMessageQueueThread::quitSynchronous() {
 /* static */
 std::unique_ptr<JMessageQueueThread> JMessageQueueThread::currentMessageQueueThread() {
   static auto method = MessageQueueThreadRegistry::javaClassStatic()->
-      getStaticMethod<MessageQueueThread::javaobject()>("myMessageQueueThread");
+      getStaticMethod<JavaMessageQueueThread::javaobject()>("myMessageQueueThread");
   return folly::make_unique<JMessageQueueThread>(method(MessageQueueThreadRegistry::javaClassStatic()));
 }
 
diff --git a/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.h b/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.h
index 1a75f819af7e..e81d5dead294 100644
--- a/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.h
+++ b/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.h
@@ -4,6 +4,8 @@
 
 #include <functional>
 
+#include <react/MessageQueueThread.h>
+
 #include <jni/fbjni.h>
 
 using namespace facebook::jni;
@@ -11,32 +13,32 @@ using namespace facebook::jni;
 namespace facebook {
 namespace react {
 
-class MessageQueueThread : public jni::JavaClass<MessageQueueThread> {
+class JavaMessageQueueThread : public jni::JavaClass<JavaMessageQueueThread> {
 public:
   static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/queue/MessageQueueThread;";
 };
 
-class JMessageQueueThread {
+class JMessageQueueThread : public MessageQueueThread {
 public:
-  JMessageQueueThread(alias_ref<MessageQueueThread::javaobject> jobj);
+  JMessageQueueThread(alias_ref<JavaMessageQueueThread::javaobject> jobj);
 
   /**
    * Enqueues the given function to run on this MessageQueueThread.
    */
-  void runOnQueue(std::function<void()>&& runnable);
+  void runOnQueue(std::function<void()>&& runnable) override;
 
   /**
    * Returns whether the currently executing thread is this MessageQueueThread.
    */
-  bool isOnThread();
+  bool isOnThread() override;
 
   /**
    * Synchronously quits the current MessageQueueThread. Can be called from any thread, but will
    * block if not called on this MessageQueueThread.
    */
-  void quitSynchronous();
+  void quitSynchronous() override;
 
-  MessageQueueThread::javaobject jobj() {
+  JavaMessageQueueThread::javaobject jobj() {
     return m_jobj.get();
   }
 
@@ -45,7 +47,7 @@ class JMessageQueueThread {
    */
   static std::unique_ptr<JMessageQueueThread> currentMessageQueueThread();
 private:
-  global_ref<MessageQueueThread::javaobject> m_jobj;
+  global_ref<JavaMessageQueueThread::javaobject> m_jobj;
 };
 
 class MessageQueueThreadRegistry : public jni::JavaClass<MessageQueueThreadRegistry> {
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 49fd32ae3895..10f1399f2490 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -21,6 +21,7 @@
 #include "ReadableNativeArray.h"
 #include "ProxyExecutor.h"
 #include "OnLoad.h"
+#include "JMessageQueueThread.h"
 #include "JSLogging.h"
 #include "JSCPerfLogging.h"
 #include <algorithm>
@@ -842,6 +843,11 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
       [] (const std::string& assetName) {
         return loadScriptFromAssets(assetName);
       };
+    MessageQueues::getCurrentMessageQueueThread =
+      [] {
+        return std::unique_ptr<MessageQueueThread>(
+            JMessageQueueThread::currentMessageQueueThread().release());
+      };
     PerfLogging::installNativeHooks = addNativePerfLoggingHooks;
     JSLogging::nativeHook = nativeLoggingHook;
 
diff --git a/ReactAndroid/src/main/jni/react/jni/WebWorkers.h b/ReactAndroid/src/main/jni/react/jni/WebWorkers.h
index 2a506280a629..e243fa8bfb32 100644
--- a/ReactAndroid/src/main/jni/react/jni/WebWorkers.h
+++ b/ReactAndroid/src/main/jni/react/jni/WebWorkers.h
@@ -18,10 +18,10 @@ class WebWorkers : public JavaClass<WebWorkers> {
 public:
   static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/webworkers/WebWorkers;";
 
-  static std::unique_ptr<JMessageQueueThread> createWebWorkerThread(int id, JMessageQueueThread *ownerMessageQueueThread) {
+  static std::unique_ptr<JMessageQueueThread> createWebWorkerThread(int id, MessageQueueThread *ownerMessageQueueThread) {
     static auto method = WebWorkers::javaClassStatic()->
-        getStaticMethod<MessageQueueThread::javaobject(jint, MessageQueueThread::javaobject)>("createWebWorkerThread");
-    auto res = method(WebWorkers::javaClassStatic(), id, ownerMessageQueueThread->jobj());
+        getStaticMethod<JavaMessageQueueThread::javaobject(jint, JavaMessageQueueThread::javaobject)>("createWebWorkerThread");
+    auto res = method(WebWorkers::javaClassStatic(), id, static_cast<JMessageQueueThread*>(ownerMessageQueueThread)->jobj());
     return folly::make_unique<JMessageQueueThread>(res);
   }
 };

From 52fcfc31cd2cf8a1ca96c3cb79e5bda4f77892fc Mon Sep 17 00:00:00 2001
From: Chris Hopman <cjhopman@fb.com>
Date: Fri, 5 Feb 2016 18:09:27 -0800
Subject: [PATCH 1052/1411] Move creation of web worker threads into react/jni

Summary:
Injects implementation into react/

public

Reviewed By: astreet

Differential Revision: D2905183

fb-gh-sync-id: 3ea6aaf50aabc1faae4e7a93fe92e02b033407e8
---
 ReactAndroid/src/main/jni/react/JSCWebWorker.cpp | 2 +-
 ReactAndroid/src/main/jni/react/Platform.cpp     | 1 +
 ReactAndroid/src/main/jni/react/Platform.h       | 3 +++
 ReactAndroid/src/main/jni/react/jni/OnLoad.cpp   | 2 ++
 4 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp b/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
index 91895b800ec2..62902fcf0adf 100644
--- a/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
@@ -35,7 +35,7 @@ JSCWebWorker::JSCWebWorker(int id, JSCWebWorkerOwner *owner, std::string scriptS
     owner_(owner) {
   ownerMessageQueueThread_ = owner->getMessageQueueThread();
   CHECK(ownerMessageQueueThread_) << "Owner MessageQueue must not be null";
-  workerMessageQueueThread_ = WebWorkers::createWebWorkerThread(id, ownerMessageQueueThread_.get());
+  workerMessageQueueThread_ = WebWorkerUtil::createWebWorkerThread(id, ownerMessageQueueThread_.get());
   CHECK(workerMessageQueueThread_) << "Failed to create worker thread";
 
   workerMessageQueueThread_->runOnQueue([this] () {
diff --git a/ReactAndroid/src/main/jni/react/Platform.cpp b/ReactAndroid/src/main/jni/react/Platform.cpp
index d91cfcaebe28..03edca72c635 100644
--- a/ReactAndroid/src/main/jni/react/Platform.cpp
+++ b/ReactAndroid/src/main/jni/react/Platform.cpp
@@ -14,6 +14,7 @@ GetCurrentMessageQueueThread getCurrentMessageQueueThread;
 };
 
 namespace WebWorkerUtil {
+WebWorkerQueueFactory createWebWorkerThread;
 LoadScriptFromAssets loadScriptFromAssets;
 };
 
diff --git a/ReactAndroid/src/main/jni/react/Platform.h b/ReactAndroid/src/main/jni/react/Platform.h
index 4fa42591ae72..c5c1c5043b04 100644
--- a/ReactAndroid/src/main/jni/react/Platform.h
+++ b/ReactAndroid/src/main/jni/react/Platform.h
@@ -24,6 +24,9 @@ extern GetCurrentMessageQueueThread getCurrentMessageQueueThread;
 };
 
 namespace WebWorkerUtil {
+using WebWorkerQueueFactory = std::function<std::unique_ptr<MessageQueueThread>(int id, MessageQueueThread* ownerMessageQueue)>;
+extern WebWorkerQueueFactory createWebWorkerThread;
+
 using LoadScriptFromAssets = std::function<std::string(const std::string& assetName)>;
 extern LoadScriptFromAssets loadScriptFromAssets;
 };
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 10f1399f2490..2617fae7cd2e 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -24,6 +24,7 @@
 #include "JMessageQueueThread.h"
 #include "JSLogging.h"
 #include "JSCPerfLogging.h"
+#include "WebWorkers.h"
 #include <algorithm>
 
 #ifdef WITH_FBSYSTRACE
@@ -839,6 +840,7 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
   return initialize(vm, [] {
     // Inject some behavior into react/
     ReactMarker::logMarker = bridge::logMarker;
+    WebWorkerUtil::createWebWorkerThread = WebWorkers::createWebWorkerThread;
     WebWorkerUtil::loadScriptFromAssets =
       [] (const std::string& assetName) {
         return loadScriptFromAssets(assetName);

From cc926211b61d305b0cc61faa55fc4329bb456898 Mon Sep 17 00:00:00 2001
From: Chris Hopman <cjhopman@fb.com>
Date: Fri, 5 Feb 2016 18:09:28 -0800
Subject: [PATCH 1053/1411] Move implementation of extracting bundles from
 assets to react/jni

Summary:
Splits JSModulesUnbundle into interface+implementation.

public

Reviewed By: astreet

Differential Revision: D2905186

fb-gh-sync-id: 3e621f7a7239d3f1e730334da2fe7cbeb17a1de4
---
 ReactAndroid/src/main/jni/react/BUCK          |  1 -
 ReactAndroid/src/main/jni/react/Bridge.cpp    |  2 +-
 ReactAndroid/src/main/jni/react/Bridge.h      |  2 +-
 ReactAndroid/src/main/jni/react/Executor.h    |  2 +-
 .../src/main/jni/react/JSCExecutor.cpp        | 10 +++---
 ReactAndroid/src/main/jni/react/JSCExecutor.h |  5 ++-
 .../src/main/jni/react/JSModulesUnbundle.h    | 18 ++---------
 ReactAndroid/src/main/jni/react/jni/BUCK      |  2 ++
 .../JniJSModulesUnbundle.cpp}                 | 19 +++---------
 .../main/jni/react/jni/JniJSModulesUnbundle.h | 31 +++++++++++++++++++
 .../src/main/jni/react/jni/OnLoad.cpp         |  6 ++--
 .../src/main/jni/react/jni/ProxyExecutor.cpp  |  2 +-
 .../src/main/jni/react/jni/ProxyExecutor.h    |  2 +-
 13 files changed, 54 insertions(+), 48 deletions(-)
 rename ReactAndroid/src/main/jni/react/{JSModulesUnbundle.cpp => jni/JniJSModulesUnbundle.cpp} (79%)
 create mode 100644 ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.h

diff --git a/ReactAndroid/src/main/jni/react/BUCK b/ReactAndroid/src/main/jni/react/BUCK
index 3ef6b24bf633..2835903f46ca 100644
--- a/ReactAndroid/src/main/jni/react/BUCK
+++ b/ReactAndroid/src/main/jni/react/BUCK
@@ -39,7 +39,6 @@ react_library(
   force_static = True,
   srcs = [
     'Bridge.cpp',
-    'JSModulesUnbundle.cpp',
     'Value.cpp',
     'MethodCall.cpp',
     'JSCHelpers.cpp',
diff --git a/ReactAndroid/src/main/jni/react/Bridge.cpp b/ReactAndroid/src/main/jni/react/Bridge.cpp
index e4645f37e247..93ba78e5a812 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.cpp
+++ b/ReactAndroid/src/main/jni/react/Bridge.cpp
@@ -37,7 +37,7 @@ void Bridge::executeApplicationScript(const std::string& script, const std::stri
 }
 
 void Bridge::loadApplicationUnbundle(
-    JSModulesUnbundle&& unbundle,
+    std::unique_ptr<JSModulesUnbundle> unbundle,
     const std::string& startupCode,
     const std::string& sourceURL) {
   m_jsExecutor->loadApplicationUnbundle(std::move(unbundle), startupCode, sourceURL);
diff --git a/ReactAndroid/src/main/jni/react/Bridge.h b/ReactAndroid/src/main/jni/react/Bridge.h
index eab3ee89a4a8..cbc6c7a982c8 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.h
+++ b/ReactAndroid/src/main/jni/react/Bridge.h
@@ -59,7 +59,7 @@ class Bridge : public Countable {
    * and injects each module as individual file.
    */
   void loadApplicationUnbundle(
-    JSModulesUnbundle&& unbundle,
+    std::unique_ptr<JSModulesUnbundle> unbundle,
     const std::string& startupCode,
     const std::string& sourceURL);
   void setGlobalVariable(const std::string& propName, const std::string& jsonValue);
diff --git a/ReactAndroid/src/main/jni/react/Executor.h b/ReactAndroid/src/main/jni/react/Executor.h
index 2cd891ac1c14..fb740d9f9d41 100644
--- a/ReactAndroid/src/main/jni/react/Executor.h
+++ b/ReactAndroid/src/main/jni/react/Executor.h
@@ -39,7 +39,7 @@ class JSExecutor {
    * Add an application "unbundle" file
    */
   virtual void loadApplicationUnbundle(
-    JSModulesUnbundle&& bundle,
+    std::unique_ptr<JSModulesUnbundle> bundle,
     const std::string& startupCode,
     const std::string& sourceURL) = 0;
 
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index e06a0bef5884..8655ee5dc69a 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -151,15 +151,13 @@ void JSCExecutor::executeApplicationScript(
 }
 
 void JSCExecutor::loadApplicationUnbundle(
-    JSModulesUnbundle&& unbundle,
+    std::unique_ptr<JSModulesUnbundle> unbundle,
     const std::string& startupCode,
     const std::string& sourceURL) {
-
-  m_unbundle = std::move(unbundle);
-  if (!m_isUnbundleInitialized) {
-    m_isUnbundleInitialized = true;
+  if (!m_unbundle) {
     installGlobalFunction(m_context, "nativeRequire", nativeRequire);
   }
+  m_unbundle = std::move(unbundle);
   executeApplicationScript(startupCode, sourceURL);
 }
 
@@ -242,7 +240,7 @@ void JSCExecutor::flushQueueImmediate(std::string queueJSON) {
 }
 
 void JSCExecutor::loadModule(uint32_t moduleId) {
-  auto module = m_unbundle.getModule(moduleId);
+  auto module = m_unbundle->getModule(moduleId);
   auto sourceUrl = String::createExpectingAscii(module.name);
   auto source = String::createExpectingAscii(module.code);
   evaluateScript(m_context, source, sourceUrl);
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.h b/ReactAndroid/src/main/jni/react/JSCExecutor.h
index f0f3b490677a..d06071a2a7a8 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.h
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.h
@@ -35,7 +35,7 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
     const std::string& script,
     const std::string& sourceURL) override;
   virtual void loadApplicationUnbundle(
-    JSModulesUnbundle&& unbundle,
+    std::unique_ptr<JSModulesUnbundle> unbundle,
     const std::string& startupCode,
     const std::string& sourceURL) override;
   virtual std::string flush() override;
@@ -66,10 +66,9 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
   FlushImmediateCallback m_flushImmediateCallback;
   std::unordered_map<int, JSCWebWorker> m_webWorkers;
   std::unordered_map<int, Object> m_webWorkerJSObjs;
-  JSModulesUnbundle m_unbundle;
-  bool m_isUnbundleInitialized = false;
   std::shared_ptr<MessageQueueThread> m_messageQueueThread;
   std::string m_deviceCacheDir;
+  std::unique_ptr<JSModulesUnbundle> m_unbundle;
 
   int addWebWorker(const std::string& script, JSValueRef workerRef);
   void postMessageToWebWorker(int worker, JSValueRef message, JSValueRef *exn);
diff --git a/ReactAndroid/src/main/jni/react/JSModulesUnbundle.h b/ReactAndroid/src/main/jni/react/JSModulesUnbundle.h
index d2ca303b8671..cc5c3e429014 100644
--- a/ReactAndroid/src/main/jni/react/JSModulesUnbundle.h
+++ b/ReactAndroid/src/main/jni/react/JSModulesUnbundle.h
@@ -2,7 +2,6 @@
 
 #pragma once
 
-#include <android/asset_manager.h>
 #include <cstdint>
 #include <fb/noncopyable.h>
 #include <string>
@@ -15,7 +14,6 @@ class JSModulesUnbundle : noncopyable {
   /**
    * Represents the set of JavaScript modules that the application consists of.
    * The source code of each module can be retrieved by module ID.
-   * This implementation reads modules as single file from the assets of an apk.
    *
    * The class is non-copyable because copying instances might involve copying
    * several megabytes of memory.
@@ -28,20 +26,8 @@ class JSModulesUnbundle : noncopyable {
     std::string name;
     std::string code;
   };
-
-  JSModulesUnbundle() = default;
-  JSModulesUnbundle(AAssetManager *assetManager, const std::string& entryFile);
-  JSModulesUnbundle(JSModulesUnbundle&& other) noexcept;
-  JSModulesUnbundle& operator= (JSModulesUnbundle&& other) noexcept;
-
-  static bool isUnbundle(
-    AAssetManager *assetManager,
-    const std::string& assetName);
-  Module getModule(uint32_t moduleId) const;
-
-private:
-  AAssetManager *m_assetManager = nullptr;
-  std::string m_moduleDirectory;
+  virtual ~JSModulesUnbundle() {}
+  virtual Module getModule(uint32_t moduleId) const = 0;
 };
 
 }
diff --git a/ReactAndroid/src/main/jni/react/jni/BUCK b/ReactAndroid/src/main/jni/react/jni/BUCK
index da77b5275ce1..69f13e78eaa5 100644
--- a/ReactAndroid/src/main/jni/react/jni/BUCK
+++ b/ReactAndroid/src/main/jni/react/jni/BUCK
@@ -31,6 +31,7 @@ jni_library(
     'JMessageQueueThread.cpp',
     'JSCPerfLogging.cpp',
     'JSLoader.cpp',
+    'JniJSModulesUnbundle.cpp',
     'NativeArray.cpp',
     'OnLoad.cpp',
     'ProxyExecutor.cpp',
@@ -41,6 +42,7 @@ jni_library(
     'ProxyExecutor.h',
     'JMessageQueueThread.h',
     'JNativeRunnable.h',
+    'JniJSModulesUnbundle.h',
     'JSCPerfLogging.h',
     'JSLogging.h',
   ],
diff --git a/ReactAndroid/src/main/jni/react/JSModulesUnbundle.cpp b/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.cpp
similarity index 79%
rename from ReactAndroid/src/main/jni/react/JSModulesUnbundle.cpp
rename to ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.cpp
index f1df636255f0..20c71bc8c11a 100644
--- a/ReactAndroid/src/main/jni/react/JSModulesUnbundle.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.cpp
@@ -1,6 +1,6 @@
 // Copyright 2004-present Facebook. All Rights Reserved.
 
-#include "JSModulesUnbundle.h"
+#include "JniJSModulesUnbundle.h"
 
 #include <cstdint>
 #include <fb/assert.h>
@@ -36,22 +36,11 @@ static asset_ptr openAsset(
     AAsset_close);
 }
 
-JSModulesUnbundle::JSModulesUnbundle(AAssetManager *assetManager, const std::string& entryFile) :
+JniJSModulesUnbundle::JniJSModulesUnbundle(AAssetManager *assetManager, const std::string& entryFile) :
   m_assetManager(assetManager),
   m_moduleDirectory(jsModulesDir(entryFile)) {}
 
-JSModulesUnbundle::JSModulesUnbundle(JSModulesUnbundle&& other) noexcept {
-  *this = std::move(other);
-}
-
-JSModulesUnbundle& JSModulesUnbundle::operator= (JSModulesUnbundle&& other) noexcept {
-  std::swap(m_assetManager, other.m_assetManager);
-  std::swap(m_moduleDirectory, other.m_moduleDirectory);
-
-  return *this;
-}
-
-bool JSModulesUnbundle::isUnbundle(
+bool JniJSModulesUnbundle::isUnbundle(
     AAssetManager *assetManager,
     const std::string& assetName) {
   if (!assetManager) {
@@ -69,7 +58,7 @@ bool JSModulesUnbundle::isUnbundle(
   return fileHeader == htole32(MAGIC_FILE_HEADER);
 }
 
-JSModulesUnbundle::Module JSModulesUnbundle::getModule(uint32_t moduleId) const {
+JSModulesUnbundle::Module JniJSModulesUnbundle::getModule(uint32_t moduleId) const {
   // can be nullptr for default constructor.
   FBASSERTMSGF(m_assetManager != nullptr, "Unbundle has not been initialized with an asset manager");
 
diff --git a/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.h b/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.h
new file mode 100644
index 000000000000..9f75175e47dc
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.h
@@ -0,0 +1,31 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+#include <android/asset_manager.h>
+#include <react/JSModulesUnbundle.h>
+
+namespace facebook {
+namespace react {
+
+class JniJSModulesUnbundle : public JSModulesUnbundle {
+  /**
+   * This implementation reads modules as single file from the assets of an apk.
+   */
+public:
+  JniJSModulesUnbundle() = default;
+  JniJSModulesUnbundle(AAssetManager *assetManager, const std::string& entryFile);
+  JniJSModulesUnbundle(JniJSModulesUnbundle&& other) = delete;
+  JniJSModulesUnbundle& operator= (JSModulesUnbundle&& other) = delete;
+
+  static bool isUnbundle(
+    AAssetManager *assetManager,
+    const std::string& assetName);
+  virtual Module getModule(uint32_t moduleId) const override;
+private:
+  AAssetManager *m_assetManager = nullptr;
+  std::string m_moduleDirectory;
+};
+
+}
+}
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 2617fae7cd2e..2492fe858bbc 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -22,6 +22,7 @@
 #include "ProxyExecutor.h"
 #include "OnLoad.h"
 #include "JMessageQueueThread.h"
+#include "JniJSModulesUnbundle.h"
 #include "JSLogging.h"
 #include "JSCPerfLogging.h"
 #include "WebWorkers.h"
@@ -668,7 +669,8 @@ static void loadApplicationUnbundle(
   try {
     // Load the application unbundle and collect/dispatch any native calls that might have occured
     bridge->loadApplicationUnbundle(
-      JSModulesUnbundle(assetManager, startupFileName),
+      std::unique_ptr<JSModulesUnbundle>(
+        new JniJSModulesUnbundle(assetManager, startupFileName)),
       startupCode,
       startupFileName);
     bridge->flush();
@@ -693,7 +695,7 @@ static void loadScriptFromAssets(JNIEnv* env, jobject obj, jobject assetManager,
   #endif
 
   env->CallStaticVoidMethod(markerClass, gLogMarkerMethod, env->NewStringUTF("loadScriptFromAssets_read"));
-  if (JSModulesUnbundle::isUnbundle(manager, assetNameStr)) {
+  if (JniJSModulesUnbundle::isUnbundle(manager, assetNameStr)) {
     loadApplicationUnbundle(bridge, manager, script, assetNameStr);
   } else {
     executeApplicationScript(bridge, script, assetNameStr);
diff --git a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
index 1c6cc188aa84..e1025b06bba5 100644
--- a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
@@ -51,7 +51,7 @@ void ProxyExecutor::executeApplicationScript(
     jni::make_jstring(sourceURL).get());
 }
 
-void ProxyExecutor::loadApplicationUnbundle(JSModulesUnbundle&&, const std::string&, const std::string&) {
+void ProxyExecutor::loadApplicationUnbundle(std::unique_ptr<JSModulesUnbundle>, const std::string&, const std::string&) {
   jni::throwNewJavaException(
     "java/lang/UnsupportedOperationException",
     "Loading application unbundles is not supported for proxy executors");
diff --git a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
index 5e168db836f9..5b2842592eae 100644
--- a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
+++ b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
@@ -34,7 +34,7 @@ class ProxyExecutor : public JSExecutor {
     const std::string& script,
     const std::string& sourceURL) override;
   virtual void loadApplicationUnbundle(
-    JSModulesUnbundle&& bundle,
+    std::unique_ptr<JSModulesUnbundle> bundle,
     const std::string& startupCode,
     const std::string& sourceURL) override;
   virtual std::string flush() override;

From 8f6e074bd619fda1ee36de8024f74cc1249f1775 Mon Sep 17 00:00:00 2001
From: Spencer Ahrens <sahrens@fb.com>
Date: Fri, 5 Feb 2016 20:34:48 -0800
Subject: [PATCH 1054/1411] Return objects with remove methods when subscribing
 to back or host state

Reviewed By: fkgozali

Differential Revision: D2907942

fb-gh-sync-id: 11666f2f8cd2432c42cc90bbf48ead02a75f8bc4
---
 Libraries/Utilities/BackAndroid.android.js | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Libraries/Utilities/BackAndroid.android.js b/Libraries/Utilities/BackAndroid.android.js
index ed920e22c927..66baa59c4ea8 100644
--- a/Libraries/Utilities/BackAndroid.android.js
+++ b/Libraries/Utilities/BackAndroid.android.js
@@ -59,8 +59,11 @@ var BackAndroid = {
   addEventListener: function (
     eventName: BackPressEventName,
     handler: Function
-  ): void {
+  ): {remove: () => void} {
     _backPressSubscriptions.add(handler);
+    return {
+      remove: () => BackAndroid.removeEventListener(eventName, handler),
+    };
   },
 
   removeEventListener: function(

From 087eeda6161b2fd666e4371b46caba07fef8671d Mon Sep 17 00:00:00 2001
From: Tim Yung <yungsters@fb.com>
Date: Sat, 6 Feb 2016 00:39:32 -0800
Subject: [PATCH 1055/1411] RN: Allow `X == null` in ESLint

Reviewed By: voideanvalue

Differential Revision: D2908714

fb-gh-sync-id: a5f382fb3a71517fdab4c809311e78323e284fd9
---
 .eslintrc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.eslintrc b/.eslintrc
index 612fdaf405c7..8c33d4d3842d 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -107,7 +107,7 @@
     "curly": 1,                      // specify curly brace conventions for all control statements
     "default-case": 0,               // require default case in switch statements (off by default)
     "dot-notation": 1,               // encourages use of dot notation whenever possible
-    "eqeqeq": 1,                     // require the use of === and !==
+    "eqeqeq": [1, "allow-null"],     // require the use of === and !==
     "guard-for-in": 0,               // make sure for-in loops have an if statement (off by default)
     "no-alert": 1,                   // disallow the use of alert, confirm, and prompt
     "no-caller": 1,                  // disallow use of arguments.caller or arguments.callee

From 8c4f6443852153985077f478235273d354a6c419 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Sat, 6 Feb 2016 11:44:40 -0800
Subject: [PATCH 1056/1411] Change ulimit to 2048 for non root Mac users

Reviewed By: vjeux

Differential Revision: D2905603

fb-gh-sync-id: 929e1ff562f6a4903bce55a5255c61c407fa8ad9
---
 local-cli/setup_env.sh | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/local-cli/setup_env.sh b/local-cli/setup_env.sh
index 9bf18b5b4597..983cc8d6f084 100755
--- a/local-cli/setup_env.sh
+++ b/local-cli/setup_env.sh
@@ -5,4 +5,5 @@
 # LICENSE file in the root directory of this source tree. An additional grant
 # of patent rights can be found in the PATENTS file in the same directory.
 
-ulimit -n 4096
+# 2048 is the max for non root users on Mac
+ulimit -n 2048

From 62440b86b04839583bbab0199be997ce1e868a73 Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Sat, 6 Feb 2016 14:02:54 -0800
Subject: [PATCH 1057/1411] Fix jni build with gradle

Summary:
fc94f1e6d0ac61e250c13d293ff76c9c5a5dbbf5 and the following commits introduced some changes to the jni build but only changed the BUCK build files and not the gradle ones. This ports the changes to the gradle build files to fix the build.
Closes https://github.com/facebook/react-native/pull/5791

Reviewed By: svcscm

Differential Revision: D2910012

Pulled By: vjeux

fb-gh-sync-id: b6c7edfed6873d501e46e80a0c9f128d9df04ca4
---
 ReactAndroid/src/main/jni/react/Android.mk     | 5 +++--
 ReactAndroid/src/main/jni/react/jni/Android.mk | 3 +++
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/Android.mk b/ReactAndroid/src/main/jni/react/Android.mk
index 78abe5bd15c8..3e3fbe247f98 100644
--- a/ReactAndroid/src/main/jni/react/Android.mk
+++ b/ReactAndroid/src/main/jni/react/Android.mk
@@ -9,8 +9,8 @@ LOCAL_SRC_FILES := \
   JSCExecutor.cpp \
   JSCHelpers.cpp \
   JSCWebWorker.cpp \
-  JSModulesUnbundle.cpp \
   MethodCall.cpp \
+  Platform.cpp \
   Value.cpp \
 
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/..
@@ -24,7 +24,7 @@ CXX11_FLAGS := -std=c++11
 LOCAL_CFLAGS += $(CXX11_FLAGS)
 LOCAL_EXPORT_CPPFLAGS := $(CXX11_FLAGS)
 
-LOCAL_SHARED_LIBRARIES := libfb libfbjni libfolly_json libjsc
+LOCAL_SHARED_LIBRARIES := libfb libfbjni libfolly_json libjsc libglog
 
 include $(BUILD_STATIC_LIBRARY)
 
@@ -32,3 +32,4 @@ $(call import-module,fb)
 $(call import-module,jni)
 $(call import-module,folly)
 $(call import-module,jsc)
+$(call import-module,glog)
diff --git a/ReactAndroid/src/main/jni/react/jni/Android.mk b/ReactAndroid/src/main/jni/react/jni/Android.mk
index bb051ddafa99..9d4d9b2b5fff 100644
--- a/ReactAndroid/src/main/jni/react/jni/Android.mk
+++ b/ReactAndroid/src/main/jni/react/jni/Android.mk
@@ -6,7 +6,10 @@ LOCAL_MODULE := reactnativejni
 
 LOCAL_SRC_FILES := \
   JMessageQueueThread.cpp \
+  JSCPerfLogging.cpp \
   JSLoader.cpp \
+  JSLogging.cpp \
+  JniJSModulesUnbundle.cpp \
   NativeArray.cpp \
   OnLoad.cpp \
   ProxyExecutor.cpp \

From 1e58a4287c065a6cd19b731dadf1868ab3ff0a57 Mon Sep 17 00:00:00 2001
From: Austin Kuo <auszon3@gmail.com>
Date: Sun, 7 Feb 2016 07:12:42 -0800
Subject: [PATCH 1058/1411] Emend the comment

Summary:
Emend the comment error
Closes https://github.com/facebook/react-native/pull/5795

Reviewed By: svcscm

Differential Revision: D2910532

Pulled By: vjeux

fb-gh-sync-id: 9f8fe026e57e049db5a0f6d4e3ee4a752457c4a5
---
 Libraries/Components/ScrollView/ScrollView.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js
index 7c769a05f0be..cb07b740918d 100644
--- a/Libraries/Components/ScrollView/ScrollView.js
+++ b/Libraries/Components/ScrollView/ScrollView.js
@@ -287,7 +287,7 @@ var ScrollView = React.createClass({
     snapToInterval: PropTypes.number,
     /**
      * When `snapToInterval` is set, `snapToAlignment` will define the relationship
-     * of the the snapping to the scroll view.
+     * of the snapping to the scroll view.
      *   - `start` (the default) will align the snap at the left (horizontal) or top (vertical)
      *   - `center` will align the snap in the center
      *   - `end` will align the snap at the right (horizontal) or bottom (vertical)

From 4ac49a5c37234ec5cba3d0fa485d8f727acc39f0 Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeuxx@gmail.com>
Date: Sun, 7 Feb 2016 09:45:25 -0800
Subject: [PATCH 1059/1411] Beef up JavaScript environment doc

Summary:
Put the transform list up to date and add a polyfill section
Closes https://github.com/facebook/react-native/pull/5793

Reviewed By: svcscm

Differential Revision: D2910585

Pulled By: vjeux

fb-gh-sync-id: c67852654241def4a826d6d694ad6fc9cb849264
---
 docs/JavaScriptEnvironment.md | 34 +++++++++++++++++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/docs/JavaScriptEnvironment.md b/docs/JavaScriptEnvironment.md
index dcd866156c15..cf6b3d409fd4 100644
--- a/docs/JavaScriptEnvironment.md
+++ b/docs/JavaScriptEnvironment.md
@@ -22,7 +22,7 @@ Syntax transformers make writing code more enjoyable by allowing you to use new
 
 As of version 0.5.0, React Native ships with the [Babel JavaScript compiler](https://babeljs.io). Check [Babel documentation](http://babeljs.io/docs/advanced/transformers/) on its supported transformations for more details.
 
-Here's a full list of React Native's [enabled transformations](https://github.com/facebook/react-native/blob/master/packager/transformer.js#L21).
+Here's a full list of React Native's [enabled transformations](https://github.com/facebook/react-native/blob/master/babel-preset/configs/main.js#L16).
 
 ES5
 
@@ -36,6 +36,7 @@ ES6
 * [Classes](http://babeljs.io/docs/learn-es2015/#classes): `class C extends React.Component { render() { return <View />; } }`
 * [Constants](https://babeljs.io/docs/learn-es2015/#let-const): `const answer = 42;`
 * [Destructuring](http://babeljs.io/docs/learn-es2015/#destructuring): `var {isActive, style} = this.props;`
+* [for...of](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of): `for (var num of [1, 2, 3]) {}`
 * [Modules](http://babeljs.io/docs/learn-es2015/#modules): `import React, { Component } from 'react-native';`
 * [Computed Properties](http://babeljs.io/docs/learn-es2015/#enhanced-object-literals): `var key = 'abc'; var obj = {[key]: 10};`
 * Object Consise Method: `var obj = { method() { return 10; } };`
@@ -48,3 +49,34 @@ ES7
 * [Object Spread](https://github.com/sebmarkbage/ecmascript-rest-spread): `var extended = { ...obj, a: 10 };`
 * [Function Trailing Comma](https://github.com/jeffmo/es-trailing-function-commas): `function f(a, b, c,) { }`
 * [Async Functions](https://github.com/tc39/ecmascript-asyncawait): `async function doStuffAsync() { const foo = await doOtherStuffAsync(); }`;
+
+Specific
+
+- [JSX](https://facebook.github.io/react/docs/jsx-in-depth.html): `<View style={{color: 'red'}} />`
+- [Flow](http://flowtype.org/): `function foo(x: ?number): string {}`
+
+
+## Polyfills
+
+Many standards functions are also available on all the supported JavaScript runtimes.
+
+Browser
+
+* [console.{log, warn, error, info, trace, table}](https://developer.chrome.com/devtools/docs/console-api)
+* [CommonJS require](https://nodejs.org/docs/latest/api/modules.html)
+* [XMLHttpRequest, fetch](/react-native/docs/network.html#content)
+* [{set, clear}{Timeout, Interval, Immediate}, {request, cancel}AnimationFrame](/react-native/docs/timers.html#content)
+* [navigator.geolocation](/react-native/docs/geolocation.html#content)
+ 
+ES6
+* [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
+* String.prototype.{[startsWith](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith), [endsWith](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith), [repeat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeats), [includes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes)}
+* [Array.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from)
+* Array.prototype.{[find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find), [findIndex](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex)}
+* 
+
+ES7
+* Object.{[entries](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries), [values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values)}
+
+Specific
+* `__DEV__`

From e2873cf85f53592dc1ab7ec76306c55179b25508 Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeux@fb.com>
Date: Sun, 7 Feb 2016 10:13:35 -0800
Subject: [PATCH 1060/1411] Change internal format from 0xaarrggbb to
 0xrrggbbaa

Summary:
The hex8 specified version is #rrggbbaa so it would be great to have the internal representation be 0xrrggbbaa to prevent confusion.

This pull request changes the internals of normalizeColor. It changes a lot of lines but there isn't any big changes.

Small changes:
- Use | instead of + for number operations
- Use x << 24 instead of x * (1 << 24)
- Have hslToRgb return pre shifted number

processColor is still sending colors the 0xaarrggbb format to native and tests still pass without changes.
Closes https://github.com/facebook/react-native/pull/5792

Reviewed By: svcscm

Differential Revision: D2910589

Pulled By: vjeux

fb-gh-sync-id: 6dd353f2edd5127f1762e7a57a65379d2a58e0c1
---
 .../__tests__/normalizeColor-test.js          |  62 +--
 .../StyleSheet/__tests__/processColor-test.js |   2 +-
 Libraries/StyleSheet/normalizeColor.js        | 372 +++++++++---------
 Libraries/StyleSheet/processColor.js          |   3 +
 4 files changed, 218 insertions(+), 221 deletions(-)

diff --git a/Libraries/StyleSheet/__tests__/normalizeColor-test.js b/Libraries/StyleSheet/__tests__/normalizeColor-test.js
index 8365465f7caa..e57fc0b7c364 100644
--- a/Libraries/StyleSheet/__tests__/normalizeColor-test.js
+++ b/Libraries/StyleSheet/__tests__/normalizeColor-test.js
@@ -26,8 +26,8 @@ describe('normalizeColor', function() {
   });
 
   it('should temporarly accept floating point values for rgb', function() {
-    expect(normalizeColor('rgb(1.1, 2.1, 3.1)')).toBe(0xff010203);
-    expect(normalizeColor('rgba(1.1, 2.1, 3.1, 1.0)')).toBe(0xff010203);
+    expect(normalizeColor('rgb(1.1, 2.1, 3.1)')).toBe(0x010203ff);
+    expect(normalizeColor('rgba(1.1, 2.1, 3.1, 1.0)')).toBe(0x010203ff);
   });
 
   it('should refuse non spec compliant colors', function() {
@@ -49,32 +49,32 @@ describe('normalizeColor', function() {
   });
 
   it('should handle hex6 properly', function() {
-    expect(normalizeColor('#000000')).toBe(0xff000000);
+    expect(normalizeColor('#000000')).toBe(0x000000ff);
     expect(normalizeColor('#ffffff')).toBe(0xffffffff);
-    expect(normalizeColor('#ff00ff')).toBe(0xffff00ff);
-    expect(normalizeColor('#abcdef')).toBe(0xffabcdef);
-    expect(normalizeColor('#012345')).toBe(0xff012345);
+    expect(normalizeColor('#ff00ff')).toBe(0xff00ffff);
+    expect(normalizeColor('#abcdef')).toBe(0xabcdefff);
+    expect(normalizeColor('#012345')).toBe(0x012345ff);
   });
 
   it('should handle hex3 properly', function() {
-    expect(normalizeColor('#000')).toBe(0xff000000);
+    expect(normalizeColor('#000')).toBe(0x000000ff);
     expect(normalizeColor('#fff')).toBe(0xffffffff);
-    expect(normalizeColor('#f0f')).toBe(0xffff00ff);
+    expect(normalizeColor('#f0f')).toBe(0xff00ffff);
   });
 
   it('should handle hex8 properly', function() {
     expect(normalizeColor('#00000000')).toBe(0x00000000);
     expect(normalizeColor('#ffffffff')).toBe(0xffffffff);
-    expect(normalizeColor('#ffff00ff')).toBe(0xffffff00);
-    expect(normalizeColor('#abcdef01')).toBe(0x01abcdef);
-    expect(normalizeColor('#01234567')).toBe(0x67012345);
+    expect(normalizeColor('#ffff00ff')).toBe(0xffff00ff);
+    expect(normalizeColor('#abcdef01')).toBe(0xabcdef01);
+    expect(normalizeColor('#01234567')).toBe(0x01234567);
   });
 
   it('should handle rgb properly', function() {
-    expect(normalizeColor('rgb(0, 0, 0)')).toBe(0xff000000);
-    expect(normalizeColor('rgb(-1, -2, -3)')).toBe(0xff000000);
-    expect(normalizeColor('rgb(0, 0, 255)')).toBe(0xff0000ff);
-    expect(normalizeColor('rgb(100, 15, 69)')).toBe(0xff640f45);
+    expect(normalizeColor('rgb(0, 0, 0)')).toBe(0x000000ff);
+    expect(normalizeColor('rgb(-1, -2, -3)')).toBe(0x000000ff);
+    expect(normalizeColor('rgb(0, 0, 255)')).toBe(0x0000ffff);
+    expect(normalizeColor('rgb(100, 15, 69)')).toBe(0x640f45ff);
     expect(normalizeColor('rgb(255, 255, 255)')).toBe(0xffffffff);
     expect(normalizeColor('rgb(256, 256, 256)')).toBe(0xffffffff);
   });
@@ -83,34 +83,34 @@ describe('normalizeColor', function() {
     expect(normalizeColor('rgba(0, 0, 0, 0.0)')).toBe(0x00000000);
     expect(normalizeColor('rgba(0, 0, 0, 0)')).toBe(0x00000000);
     expect(normalizeColor('rgba(0, 0, 0, -0.5)')).toBe(0x00000000);
-    expect(normalizeColor('rgba(0, 0, 0, 1.0)')).toBe(0xff000000);
-    expect(normalizeColor('rgba(0, 0, 0, 1)')).toBe(0xff000000);
-    expect(normalizeColor('rgba(0, 0, 0, 1.5)')).toBe(0xff000000);
-    expect(normalizeColor('rgba(100, 15, 69, 0.5)')).toBe(0x80640f45);
+    expect(normalizeColor('rgba(0, 0, 0, 1.0)')).toBe(0x000000ff);
+    expect(normalizeColor('rgba(0, 0, 0, 1)')).toBe(0x000000ff);
+    expect(normalizeColor('rgba(0, 0, 0, 1.5)')).toBe(0x000000ff);
+    expect(normalizeColor('rgba(100, 15, 69, 0.5)')).toBe(0x640f4580);
   });
 
   it('should handle hsl properly', function() {
-    expect(normalizeColor('hsl(0, 0%, 0%)')).toBe(0xff000000);
+    expect(normalizeColor('hsl(0, 0%, 0%)')).toBe(0x000000ff);
     expect(normalizeColor('hsl(360, 100%, 100%)')).toBe(0xffffffff);
-    expect(normalizeColor('hsl(180, 50%, 50%)')).toBe(0xff40bfbf);
-    expect(normalizeColor('hsl(540, 50%, 50%)')).toBe(0xff40bfbf);
-    expect(normalizeColor('hsl(70, 25%, 75%)')).toBe(0xffcacfaf);
-    expect(normalizeColor('hsl(70, 100%, 75%)')).toBe(0xffeaff80);
-    expect(normalizeColor('hsl(70, 110%, 75%)')).toBe(0xffeaff80);
-    expect(normalizeColor('hsl(70, 0%, 75%)')).toBe(0xffbfbfbf);
-    expect(normalizeColor('hsl(70, -10%, 75%)')).toBe(0xffbfbfbf);
+    expect(normalizeColor('hsl(180, 50%, 50%)')).toBe(0x40bfbfff);
+    expect(normalizeColor('hsl(540, 50%, 50%)')).toBe(0x40bfbfff);
+    expect(normalizeColor('hsl(70, 25%, 75%)')).toBe(0xcacfafff);
+    expect(normalizeColor('hsl(70, 100%, 75%)')).toBe(0xeaff80ff);
+    expect(normalizeColor('hsl(70, 110%, 75%)')).toBe(0xeaff80ff);
+    expect(normalizeColor('hsl(70, 0%, 75%)')).toBe(0xbfbfbfff);
+    expect(normalizeColor('hsl(70, -10%, 75%)')).toBe(0xbfbfbfff);
   });
 
   it('should handle hsla properly', function() {
     expect(normalizeColor('hsla(0, 0%, 0%, 0)')).toBe(0x00000000);
     expect(normalizeColor('hsla(360, 100%, 100%, 1)')).toBe(0xffffffff);
-    expect(normalizeColor('hsla(360, 100%, 100%, 0)')).toBe(0x00ffffff);
-    expect(normalizeColor('hsla(180, 50%, 50%, 0.2)')).toBe(0x3340bfbf);
+    expect(normalizeColor('hsla(360, 100%, 100%, 0)')).toBe(0xffffff00);
+    expect(normalizeColor('hsla(180, 50%, 50%, 0.2)')).toBe(0x40bfbf33);
   });
 
   it('should handle named colors properly', function() {
-    expect(normalizeColor('red')).toBe(0xffff0000);
+    expect(normalizeColor('red')).toBe(0xff0000ff);
     expect(normalizeColor('transparent')).toBe(0x00000000);
-    expect(normalizeColor('peachpuff')).toBe(0xffffdab9);
+    expect(normalizeColor('peachpuff')).toBe(0xffdab9ff);
   });
 });
diff --git a/Libraries/StyleSheet/__tests__/processColor-test.js b/Libraries/StyleSheet/__tests__/processColor-test.js
index 79682bbacc51..aaf45d5e23e3 100644
--- a/Libraries/StyleSheet/__tests__/processColor-test.js
+++ b/Libraries/StyleSheet/__tests__/processColor-test.js
@@ -71,7 +71,7 @@ describe('processColor', () => {
 
   });
 
-  describe('HSL strings', () => {
+  describe('HSLA strings', () => {
 
     it('should convert hsla(x, y%, z%, a)', () => {
       var colorFromString = processColor('hsla(318, 69%, 55%, 0.25)');
diff --git a/Libraries/StyleSheet/normalizeColor.js b/Libraries/StyleSheet/normalizeColor.js
index 70d9bcad500a..ae8d62f3011a 100755
--- a/Libraries/StyleSheet/normalizeColor.js
+++ b/Libraries/StyleSheet/normalizeColor.js
@@ -17,7 +17,7 @@ function normalizeColor(color: string): ?number {
 
   // Ordered based on occurrences on Facebook codebase
   if ((match = matchers.hex6.exec(color))) {
-    return 0xff000000 + parseInt(match[1], 16);
+    return (parseInt(match[1], 16) << 8 | 0x000000ff) >>> 0;
   }
 
   if (names.hasOwnProperty(color)) {
@@ -26,73 +26,67 @@ function normalizeColor(color: string): ?number {
 
   if ((match = matchers.rgb.exec(color))) {
     return (
-      0xff000000 + // a
-      parse255(match[1]) * (1 << 16) + // r
-      parse255(match[2]) * (1 << 8) + // g
-      parse255(match[3]) // b
-    );
+      parse255(match[1]) << 24 | // r
+      parse255(match[2]) << 16 | // g
+      parse255(match[3]) << 8 | // b
+      0x000000ff // a
+    ) >>> 0;
   }
 
   if ((match = matchers.rgba.exec(color))) {
     return (
-      parse1(match[4]) * (1 << 24) + // a
-      parse255(match[1]) * (1 << 16) + // r
-      parse255(match[2]) * (1 << 8) + // g
-      parse255(match[3]) // b
-    );
+      parse255(match[1]) << 24 | // r
+      parse255(match[2]) << 16 | // g
+      parse255(match[3]) << 8 | // b
+      parse1(match[4]) // a
+    ) >>> 0;
   }
 
   if ((match = matchers.hex3.exec(color))) {
-    return (
-      parseInt(
-        'ff' + // a
-        match[1] + match[1] + // r
-        match[2] + match[2] + // g
-        match[3] + match[3], // b
-        16
-      )
-    );
+    return parseInt(
+      match[1] + match[1] + // r
+      match[2] + match[2] + // g
+      match[3] + match[3] + // b
+      'ff', // a
+      16
+    ) >>> 0;
   }
 
   // https://drafts.csswg.org/css-color-4/#hex-notation
   if ((match = matchers.hex8.exec(color))) {
-    var number = parseInt(match[1], 16);
-    // Convert 0xrrggbbaa into 0xaarrggbb
-    return (number << 24 | number >>> 8) >>> 0;
+    return parseInt(match[1], 16) >>> 0;
   }
 
   if ((match = matchers.hex4.exec(color))) {
-    return (
-      parseInt(
-        match[4] + match[4] + // a
-        match[1] + match[1] + // r
-        match[2] + match[2] + // g
-        match[3] + match[3], // b
-        16
-      )
-    );
+    return parseInt(
+      match[1] + match[1] + // r
+      match[2] + match[2] + // g
+      match[3] + match[3] + // b
+      match[4] + match[4], // a
+      16
+    ) >>> 0;
   }
 
   if ((match = matchers.hsl.exec(color))) {
     return (
-      0xff000000 + // a
       hslToRgb(
         parse360(match[1]), // h
         parsePercentage(match[2]), // s
         parsePercentage(match[3]) // l
-      )
-    );
+      ) |
+      0x000000ff // a
+    ) >>> 0;
   }
 
   if ((match = matchers.hsla.exec(color))) {
     return (
-      parse1(match[4]) * (1 << 24) + // a
       hslToRgb(
         parse360(match[1]), // h
         parsePercentage(match[2]), // s
         parsePercentage(match[3]) // l
-      )
-    );
+      ) |
+      parse1(match[4]) // a
+    ) >>> 0;
   }
 
   return null;
@@ -125,9 +119,9 @@ function hslToRgb(h: number, s: number, l: number): number {
   var b = hue2rgb(p, q, h - 1 / 3);
 
   return (
-    Math.round(r * 255) * (1 << 16) +
-    Math.round(g * 255) * (1 << 8) +
-    Math.round(b * 255)
+    Math.round(r * 255) << 24 |
+    Math.round(g * 255) << 16 |
+    Math.round(b * 255) << 8
   );
 }
 
@@ -193,155 +187,155 @@ var names = {
   transparent: 0x00000000,
 
   // http://www.w3.org/TR/css3-color/#svg-color
-  aliceblue: 0xfff0f8ff,
-  antiquewhite: 0xfffaebd7,
-  aqua: 0xff00ffff,
-  aquamarine: 0xff7fffd4,
-  azure: 0xfff0ffff,
-  beige: 0xfff5f5dc,
-  bisque: 0xffffe4c4,
-  black: 0xff000000,
-  blanchedalmond: 0xffffebcd,
-  blue: 0xff0000ff,
-  blueviolet: 0xff8a2be2,
-  brown: 0xffa52a2a,
-  burlywood: 0xffdeb887,
-  burntsienna: 0xffea7e5d,
-  cadetblue: 0xff5f9ea0,
-  chartreuse: 0xff7fff00,
-  chocolate: 0xffd2691e,
-  coral: 0xffff7f50,
-  cornflowerblue: 0xff6495ed,
-  cornsilk: 0xfffff8dc,
-  crimson: 0xffdc143c,
-  cyan: 0xff00ffff,
-  darkblue: 0xff00008b,
-  darkcyan: 0xff008b8b,
-  darkgoldenrod: 0xffb8860b,
-  darkgray: 0xffa9a9a9,
-  darkgreen: 0xff006400,
-  darkgrey: 0xffa9a9a9,
-  darkkhaki: 0xffbdb76b,
-  darkmagenta: 0xff8b008b,
-  darkolivegreen: 0xff556b2f,
-  darkorange: 0xffff8c00,
-  darkorchid: 0xff9932cc,
-  darkred: 0xff8b0000,
-  darksalmon: 0xffe9967a,
-  darkseagreen: 0xff8fbc8f,
-  darkslateblue: 0xff483d8b,
-  darkslategray: 0xff2f4f4f,
-  darkslategrey: 0xff2f4f4f,
-  darkturquoise: 0xff00ced1,
-  darkviolet: 0xff9400d3,
-  deeppink: 0xffff1493,
-  deepskyblue: 0xff00bfff,
-  dimgray: 0xff696969,
-  dimgrey: 0xff696969,
-  dodgerblue: 0xff1e90ff,
-  firebrick: 0xffb22222,
-  floralwhite: 0xfffffaf0,
-  forestgreen: 0xff228b22,
-  fuchsia: 0xffff00ff,
-  gainsboro: 0xffdcdcdc,
-  ghostwhite: 0xfff8f8ff,
-  gold: 0xffffd700,
-  goldenrod: 0xffdaa520,
-  gray: 0xff808080,
-  green: 0xff008000,
-  greenyellow: 0xffadff2f,
-  grey: 0xff808080,
-  honeydew: 0xfff0fff0,
-  hotpink: 0xffff69b4,
-  indianred: 0xffcd5c5c,
-  indigo: 0xff4b0082,
-  ivory: 0xfffffff0,
-  khaki: 0xfff0e68c,
-  lavender: 0xffe6e6fa,
-  lavenderblush: 0xfffff0f5,
-  lawngreen: 0xff7cfc00,
-  lemonchiffon: 0xfffffacd,
-  lightblue: 0xffadd8e6,
-  lightcoral: 0xfff08080,
-  lightcyan: 0xffe0ffff,
-  lightgoldenrodyellow: 0xfffafad2,
-  lightgray: 0xffd3d3d3,
-  lightgreen: 0xff90ee90,
-  lightgrey: 0xffd3d3d3,
-  lightpink: 0xffffb6c1,
-  lightsalmon: 0xffffa07a,
-  lightseagreen: 0xff20b2aa,
-  lightskyblue: 0xff87cefa,
-  lightslategray: 0xff778899,
-  lightslategrey: 0xff778899,
-  lightsteelblue: 0xffb0c4de,
-  lightyellow: 0xffffffe0,
-  lime: 0xff00ff00,
-  limegreen: 0xff32cd32,
-  linen: 0xfffaf0e6,
-  magenta: 0xffff00ff,
-  maroon: 0xff800000,
-  mediumaquamarine: 0xff66cdaa,
-  mediumblue: 0xff0000cd,
-  mediumorchid: 0xffba55d3,
-  mediumpurple: 0xff9370db,
-  mediumseagreen: 0xff3cb371,
-  mediumslateblue: 0xff7b68ee,
-  mediumspringgreen: 0xff00fa9a,
-  mediumturquoise: 0xff48d1cc,
-  mediumvioletred: 0xffc71585,
-  midnightblue: 0xff191970,
-  mintcream: 0xfff5fffa,
-  mistyrose: 0xffffe4e1,
-  moccasin: 0xffffe4b5,
-  navajowhite: 0xffffdead,
-  navy: 0xff000080,
-  oldlace: 0xfffdf5e6,
-  olive: 0xff808000,
-  olivedrab: 0xff6b8e23,
-  orange: 0xffffa500,
-  orangered: 0xffff4500,
-  orchid: 0xffda70d6,
-  palegoldenrod: 0xffeee8aa,
-  palegreen: 0xff98fb98,
-  paleturquoise: 0xffafeeee,
-  palevioletred: 0xffdb7093,
-  papayawhip: 0xffffefd5,
-  peachpuff: 0xffffdab9,
-  peru: 0xffcd853f,
-  pink: 0xffffc0cb,
-  plum: 0xffdda0dd,
-  powderblue: 0xffb0e0e6,
-  purple: 0xff800080,
-  rebeccapurple: 0xff663399,
-  red: 0xffff0000,
-  rosybrown: 0xffbc8f8f,
-  royalblue: 0xff4169e1,
-  saddlebrown: 0xff8b4513,
-  salmon: 0xfffa8072,
-  sandybrown: 0xfff4a460,
-  seagreen: 0xff2e8b57,
-  seashell: 0xfffff5ee,
-  sienna: 0xffa0522d,
-  silver: 0xffc0c0c0,
-  skyblue: 0xff87ceeb,
-  slateblue: 0xff6a5acd,
-  slategray: 0xff708090,
-  slategrey: 0xff708090,
-  snow: 0xfffffafa,
-  springgreen: 0xff00ff7f,
-  steelblue: 0xff4682b4,
-  tan: 0xffd2b48c,
-  teal: 0xff008080,
-  thistle: 0xffd8bfd8,
-  tomato: 0xffff6347,
-  turquoise: 0xff40e0d0,
-  violet: 0xffee82ee,
-  wheat: 0xfff5deb3,
+  aliceblue: 0xf0f8ffff,
+  antiquewhite: 0xfaebd7ff,
+  aqua: 0x00ffffff,
+  aquamarine: 0x7fffd4ff,
+  azure: 0xf0ffffff,
+  beige: 0xf5f5dcff,
+  bisque: 0xffe4c4ff,
+  black: 0x000000ff,
+  blanchedalmond: 0xffebcdff,
+  blue: 0x0000ffff,
+  blueviolet: 0x8a2be2ff,
+  brown: 0xa52a2aff,
+  burlywood: 0xdeb887ff,
+  burntsienna: 0xea7e5dff,
+  cadetblue: 0x5f9ea0ff,
+  chartreuse: 0x7fff00ff,
+  chocolate: 0xd2691eff,
+  coral: 0xff7f50ff,
+  cornflowerblue: 0x6495edff,
+  cornsilk: 0xfff8dcff,
+  crimson: 0xdc143cff,
+  cyan: 0x00ffffff,
+  darkblue: 0x00008bff,
+  darkcyan: 0x008b8bff,
+  darkgoldenrod: 0xb8860bff,
+  darkgray: 0xa9a9a9ff,
+  darkgreen: 0x006400ff,
+  darkgrey: 0xa9a9a9ff,
+  darkkhaki: 0xbdb76bff,
+  darkmagenta: 0x8b008bff,
+  darkolivegreen: 0x556b2fff,
+  darkorange: 0xff8c00ff,
+  darkorchid: 0x9932ccff,
+  darkred: 0x8b0000ff,
+  darksalmon: 0xe9967aff,
+  darkseagreen: 0x8fbc8fff,
+  darkslateblue: 0x483d8bff,
+  darkslategray: 0x2f4f4fff,
+  darkslategrey: 0x2f4f4fff,
+  darkturquoise: 0x00ced1ff,
+  darkviolet: 0x9400d3ff,
+  deeppink: 0xff1493ff,
+  deepskyblue: 0x00bfffff,
+  dimgray: 0x696969ff,
+  dimgrey: 0x696969ff,
+  dodgerblue: 0x1e90ffff,
+  firebrick: 0xb22222ff,
+  floralwhite: 0xfffaf0ff,
+  forestgreen: 0x228b22ff,
+  fuchsia: 0xff00ffff,
+  gainsboro: 0xdcdcdcff,
+  ghostwhite: 0xf8f8ffff,
+  gold: 0xffd700ff,
+  goldenrod: 0xdaa520ff,
+  gray: 0x808080ff,
+  green: 0x008000ff,
+  greenyellow: 0xadff2fff,
+  grey: 0x808080ff,
+  honeydew: 0xf0fff0ff,
+  hotpink: 0xff69b4ff,
+  indianred: 0xcd5c5cff,
+  indigo: 0x4b0082ff,
+  ivory: 0xfffff0ff,
+  khaki: 0xf0e68cff,
+  lavender: 0xe6e6faff,
+  lavenderblush: 0xfff0f5ff,
+  lawngreen: 0x7cfc00ff,
+  lemonchiffon: 0xfffacdff,
+  lightblue: 0xadd8e6ff,
+  lightcoral: 0xf08080ff,
+  lightcyan: 0xe0ffffff,
+  lightgoldenrodyellow: 0xfafad2ff,
+  lightgray: 0xd3d3d3ff,
+  lightgreen: 0x90ee90ff,
+  lightgrey: 0xd3d3d3ff,
+  lightpink: 0xffb6c1ff,
+  lightsalmon: 0xffa07aff,
+  lightseagreen: 0x20b2aaff,
+  lightskyblue: 0x87cefaff,
+  lightslategray: 0x778899ff,
+  lightslategrey: 0x778899ff,
+  lightsteelblue: 0xb0c4deff,
+  lightyellow: 0xffffe0ff,
+  lime: 0x00ff00ff,
+  limegreen: 0x32cd32ff,
+  linen: 0xfaf0e6ff,
+  magenta: 0xff00ffff,
+  maroon: 0x800000ff,
+  mediumaquamarine: 0x66cdaaff,
+  mediumblue: 0x0000cdff,
+  mediumorchid: 0xba55d3ff,
+  mediumpurple: 0x9370dbff,
+  mediumseagreen: 0x3cb371ff,
+  mediumslateblue: 0x7b68eeff,
+  mediumspringgreen: 0x00fa9aff,
+  mediumturquoise: 0x48d1ccff,
+  mediumvioletred: 0xc71585ff,
+  midnightblue: 0x191970ff,
+  mintcream: 0xf5fffaff,
+  mistyrose: 0xffe4e1ff,
+  moccasin: 0xffe4b5ff,
+  navajowhite: 0xffdeadff,
+  navy: 0x000080ff,
+  oldlace: 0xfdf5e6ff,
+  olive: 0x808000ff,
+  olivedrab: 0x6b8e23ff,
+  orange: 0xffa500ff,
+  orangered: 0xff4500ff,
+  orchid: 0xda70d6ff,
+  palegoldenrod: 0xeee8aaff,
+  palegreen: 0x98fb98ff,
+  paleturquoise: 0xafeeeeff,
+  palevioletred: 0xdb7093ff,
+  papayawhip: 0xffefd5ff,
+  peachpuff: 0xffdab9ff,
+  peru: 0xcd853fff,
+  pink: 0xffc0cbff,
+  plum: 0xdda0ddff,
+  powderblue: 0xb0e0e6ff,
+  purple: 0x800080ff,
+  rebeccapurple: 0x663399ff,
+  red: 0xff0000ff,
+  rosybrown: 0xbc8f8fff,
+  royalblue: 0x4169e1ff,
+  saddlebrown: 0x8b4513ff,
+  salmon: 0xfa8072ff,
+  sandybrown: 0xf4a460ff,
+  seagreen: 0x2e8b57ff,
+  seashell: 0xfff5eeff,
+  sienna: 0xa0522dff,
+  silver: 0xc0c0c0ff,
+  skyblue: 0x87ceebff,
+  slateblue: 0x6a5acdff,
+  slategray: 0x708090ff,
+  slategrey: 0x708090ff,
+  snow: 0xfffafaff,
+  springgreen: 0x00ff7fff,
+  steelblue: 0x4682b4ff,
+  tan: 0xd2b48cff,
+  teal: 0x008080ff,
+  thistle: 0xd8bfd8ff,
+  tomato: 0xff6347ff,
+  turquoise: 0x40e0d0ff,
+  violet: 0xee82eeff,
+  wheat: 0xf5deb3ff,
   white: 0xffffffff,
-  whitesmoke: 0xfff5f5f5,
-  yellow: 0xffffff00,
-  yellowgreen: 0xff9acd32,
+  whitesmoke: 0xf5f5f5ff,
+  yellow: 0xffff00ff,
+  yellowgreen: 0x9acd32ff,
 };
 
 module.exports = normalizeColor;
diff --git a/Libraries/StyleSheet/processColor.js b/Libraries/StyleSheet/processColor.js
index 9e93ae88fb4f..4cb9b2e5e60d 100644
--- a/Libraries/StyleSheet/processColor.js
+++ b/Libraries/StyleSheet/processColor.js
@@ -25,6 +25,9 @@ function processColor(color) {
     return undefined;
   }
 
+  // Converts 0xrrggbbaa into 0xaarrggbb
+  int32Color = (int32Color << 24 | int32Color >>> 8) >>> 0;
+
   if (Platform.OS === 'android') {
     // Android use 32 bit *signed* integer to represent the color
     // We utilize the fact that bitwise operations in JS also operates on

From 7b22606f49c63d07642f419b95ca15654f1aa6ec Mon Sep 17 00:00:00 2001
From: Dan Brewster <dnbrwstr@gmail.com>
Date: Sun, 7 Feb 2016 12:37:17 -0800
Subject: [PATCH 1061/1411] Add support for `textAlign` on iOS multiline text
 input

Summary:
Fixes https://github.com/facebook/react-native/issues/2641
Closes https://github.com/facebook/react-native/pull/5801

Reviewed By: svcscm

Differential Revision: D2910644

Pulled By: nicklockwood

fb-gh-sync-id: 8f97daac09fd2bd4120344e28c239262dd013f85
---
 Libraries/Text/RCTTextViewManager.m | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Libraries/Text/RCTTextViewManager.m b/Libraries/Text/RCTTextViewManager.m
index 791e5f89447d..f447c905c54a 100644
--- a/Libraries/Text/RCTTextViewManager.m
+++ b/Libraries/Text/RCTTextViewManager.m
@@ -28,6 +28,7 @@ - (UIView *)view
 RCT_EXPORT_VIEW_PROPERTY(blurOnSubmit, BOOL)
 RCT_EXPORT_VIEW_PROPERTY(clearTextOnFocus, BOOL)
 RCT_REMAP_VIEW_PROPERTY(color, textView.textColor, UIColor)
+RCT_REMAP_VIEW_PROPERTY(textAlign, textView.textAlignment, NSTextAlignment)
 RCT_REMAP_VIEW_PROPERTY(editable, textView.editable, BOOL)
 RCT_REMAP_VIEW_PROPERTY(enablesReturnKeyAutomatically, textView.enablesReturnKeyAutomatically, BOOL)
 RCT_REMAP_VIEW_PROPERTY(keyboardType, textView.keyboardType, UIKeyboardType)

From 3e1f1ea7bbb0461e8ad5a40cb29e94c46cddc04d Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Sun, 7 Feb 2016 13:39:17 -0800
Subject: [PATCH 1062/1411] Allows RefreshControl to be mounted with refreshing
 = true

Summary:
RefreshControl did not start refreshing when refreshing was set to true initially. It also did not start refreshing on iOS when setting the prop from false to true without doing a pull to refresh gesture.

This was a pain in the ass to make work on iOS because UIRefreshControl seems super sensitive to when beginRefreshing can be called, for the initial render I need to call it in layoutSubviews. I also have to manually adjust the scrollview content offset when calling beginRefreshing. The code is a bit hacky but it was the only solution I found that was actually working.

Fixes #5716
Closes https://github.com/facebook/react-native/pull/5745

Reviewed By: svcscm

Differential Revision: D2910716

Pulled By: nicklockwood

fb-gh-sync-id: d60e73bcfe8d86bb01249ba5f17e6a23c5a5aff6
---
 React/Views/RCTRefreshControl.m               | 53 +++++++++++++++++--
 .../SwipeRefreshLayoutManager.java            | 11 +++-
 2 files changed, 59 insertions(+), 5 deletions(-)

diff --git a/React/Views/RCTRefreshControl.m b/React/Views/RCTRefreshControl.m
index d3fc0e7f9bf6..b066f1b632af 100644
--- a/React/Views/RCTRefreshControl.m
+++ b/React/Views/RCTRefreshControl.m
@@ -11,18 +11,59 @@
 
 #import "RCTUtils.h"
 
-@implementation RCTRefreshControl
+@implementation RCTRefreshControl {
+  BOOL _initialRefreshingState;
+  BOOL _isInitialRender;
+}
 
 - (instancetype)init
 {
   if ((self = [super init])) {
     [self addTarget:self action:@selector(refreshControlValueChanged) forControlEvents:UIControlEventValueChanged];
+    _isInitialRender = true;
   }
   return self;
 }
 
 RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
 
+- (void)layoutSubviews
+{
+  [super layoutSubviews];
+  
+  // If the control is refreshing when mounted we need to call
+  // beginRefreshing in layoutSubview or it doesn't work.
+  if (_isInitialRender && _initialRefreshingState) {
+    [self beginRefreshing];
+  }
+  _isInitialRender = false;
+}
+
+- (void)beginRefreshing
+{
+  // When using begin refreshing we need to adjust the ScrollView content offset manually.
+  UIScrollView *scrollView = (UIScrollView *)self.superview;
+  CGPoint offset = {scrollView.contentOffset.x, scrollView.contentOffset.y - self.frame.size.height};
+  // Don't animate when the prop is set initialy.
+  if (_isInitialRender) {
+    // Must use `[scrollView setContentOffset:offset animated:NO]` instead of just setting
+    // `scrollview.contentOffset` or it doesn't work, don't ask me why!
+    [scrollView setContentOffset:offset animated:NO];
+    [super beginRefreshing];
+  } else {
+    // `beginRefreshing` must be called after the animation is done. This is why it is impossible
+    // to use `setContentOffset` with `animated:YES`.
+    [UIView animateWithDuration:0.25
+                          delay:0
+                        options:UIViewAnimationOptionBeginFromCurrentState
+                     animations:^(void) {
+                       [scrollView setContentOffset:offset];
+                     } completion:^(__unused BOOL finished) {
+                       [super beginRefreshing];
+                     }];
+  }
+}
+
 - (NSString *)title
 {
   return self.attributedTitle.string;
@@ -35,9 +76,15 @@ - (void)setTitle:(NSString *)title
 
 - (void)setRefreshing:(BOOL)refreshing
 {
-  if (super.refreshing != refreshing) {
+  if (self.refreshing != refreshing) {
     if (refreshing) {
-      [self beginRefreshing];
+      // If it is the initial render, beginRefreshing will get called
+      // in layoutSubviews.
+      if (_isInitialRender) {
+        _initialRefreshingState = refreshing;
+      } else {
+        [self beginRefreshing];
+      }
     } else {
       [self endRefreshing];
     }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/SwipeRefreshLayoutManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/SwipeRefreshLayoutManager.java
index 3dccc4c48bab..07a42e049455 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/SwipeRefreshLayoutManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/SwipeRefreshLayoutManager.java
@@ -71,8 +71,15 @@ public void setSize(ReactSwipeRefreshLayout view, int size) {
   }
 
   @ReactProp(name = "refreshing")
-  public void setRefreshing(ReactSwipeRefreshLayout view, boolean refreshing) {
-    view.setRefreshing(refreshing);
+  public void setRefreshing(final ReactSwipeRefreshLayout view, final boolean refreshing) {
+    // Use `post` otherwise the control won't start refreshing if refreshing is true when
+    // the component gets mounted.
+    view.post(new Runnable() {
+      @Override
+      public void run() {
+        view.setRefreshing(refreshing);
+      }
+    });
   }
 
   @Override

From 577206fe51cf94d53cd69123ac64bf70cd2cc0ba Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeuxx@gmail.com>
Date: Sun, 7 Feb 2016 16:41:54 -0800
Subject: [PATCH 1063/1411] Remove String.prototype.contains polyfill

Summary:
Now that String.prototype.includes is there, we should remove the .contains one which has not been standardized.

For fb reviewers, this needs to land after D2910339 which updates internal callsites.
Closes https://github.com/facebook/react-native/pull/5794

Reviewed By: svcscm

Differential Revision: D2910855

Pulled By: vjeux

fb-gh-sync-id: 8fd216222385f038995d1ed10e8a2c4c34c7e928
---
 .../src/Resolver/polyfills/String.prototype.es6.js  | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/packager/react-packager/src/Resolver/polyfills/String.prototype.es6.js b/packager/react-packager/src/Resolver/polyfills/String.prototype.es6.js
index c455ef1ee586..59e5351d3d6b 100644
--- a/packager/react-packager/src/Resolver/polyfills/String.prototype.es6.js
+++ b/packager/react-packager/src/Resolver/polyfills/String.prototype.es6.js
@@ -44,19 +44,6 @@ if (!String.prototype.endsWith) {
   };
 }
 
-if (!String.prototype.contains) {
-  String.prototype.contains = function(search) {
-    'use strict';
-    if (this == null) {
-      throw TypeError();
-    }
-    var string = String(this);
-    var pos = arguments.length > 1 ?
-      (Number(arguments[1]) || 0) : 0;
-    return string.indexOf(String(search), pos) !== -1;
-  };
-}
-
 if (!String.prototype.repeat) {
   String.prototype.repeat = function(count) {
     'use strict';

From 81dc884b2adba94d7c1223c939f70b181f61b97e Mon Sep 17 00:00:00 2001
From: Charles Dick <cwdick@fb.com>
Date: Mon, 8 Feb 2016 03:17:10 -0800
Subject: [PATCH 1064/1411] cwdick: add better error messages on js bundle
 downloads

Reviewed By: foghina

Differential Revision: D2845168

fb-gh-sync-id: 4566eeff0181d5ae6045e7aeaf00b91579a01feb
---
 .../devsupport/DebugServerException.java      | 16 ++++-----------
 .../react/devsupport/DevServerHelper.java     | 20 ++++++++++++++++---
 .../devsupport/DevSupportManagerImpl.java     |  2 +-
 .../main/res/devsupport/values/strings.xml    |  2 +-
 4 files changed, 23 insertions(+), 17 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DebugServerException.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DebugServerException.java
index 59f80aba467b..1cf1ff387f15 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DebugServerException.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DebugServerException.java
@@ -22,24 +22,16 @@
 import org.json.JSONObject;
 
 /**
+ * Tracks errors connecting to or received from the debug derver.
  * The debug server returns errors as json objects. This exception represents that error.
  */
 public class DebugServerException extends IOException {
-
-  public final String description;
-  public final String fileName;
-  public final int lineNumber;
-  public final int column;
-
   private DebugServerException(String description, String fileName, int lineNumber, int column) {
-    this.description = description;
-    this.fileName = fileName;
-    this.lineNumber = lineNumber;
-    this.column = column;
+    super(description + "\n  at " + fileName + ":" + lineNumber + ":" + column);
   }
 
-  public String toReadableMessage() {
-    return description + "\n  at " + fileName + ":" + lineNumber + ":" + column;
+  public DebugServerException(String description) {
+    super(description);
   }
 
   /**
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java
index 79a71b242da4..d8d802320837 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java
@@ -13,6 +13,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.net.URL;
 import java.util.Locale;
 import java.util.concurrent.TimeUnit;
 
@@ -177,7 +178,7 @@ public void downloadBundleFromURL(
       final String jsModulePath,
       final File outputFile) {
     final String bundleURL = createBundleURL(getDebugServerHost(), jsModulePath, getDevMode(), getHMR());
-    Request request = new Request.Builder()
+    final Request request = new Request.Builder()
         .url(bundleURL)
         .build();
     mDownloadBundleFromURLCall = Assertions.assertNotNull(mClient.newCall(request));
@@ -191,7 +192,15 @@ public void onFailure(Request request, IOException e) {
         }
         mDownloadBundleFromURLCall = null;
 
-        callback.onFailure(e);
+        StringBuilder sb = new StringBuilder();
+        sb.append("Could not connect to development server.\n\n")
+          .append("URL: ").append(request.urlString()).append("\n\n")
+          .append("Try the following to fix the issue:\n")
+          .append("\u2022 Ensure that the packager server is running\n")
+          .append("\u2022 Ensure that your device/emulator is connected to your machine and has USB debugging enabled - run 'adb devices' to see a list of connected devices\n")
+          .append("\u2022 If you're on a physical device connected to the same machine, run 'adb reverse tcp:8081 tcp:8081' to forward requests from your device\n")
+          .append("\u2022 If your device is on the same Wi-Fi network, set 'Debug server host & port for device' in 'Dev settings' to your machine's IP address and the port of the local dev server - e.g. 10.0.1.1:8081");
+        callback.onFailure(new DebugServerException(sb.toString()));
       }
 
       @Override
@@ -210,7 +219,12 @@ public void onResponse(Response response) throws IOException {
           if (debugServerException != null) {
             callback.onFailure(debugServerException);
           } else {
-            callback.onFailure(new IOException("Unexpected response code: " + response.code()));
+            StringBuilder sb = new StringBuilder();
+            sb.append("The development server returned response error code: ").append(response.code()).append("\n\n")
+              .append("URL: ").append(request.urlString()).append("\n\n")
+              .append("Body:\n")
+              .append(body);
+            callback.onFailure(new DebugServerException(sb.toString()));
           }
           return;
         }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java
index 7bdeea2d7ce5..120443eca3d1 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java
@@ -633,7 +633,7 @@ public void onFailure(final Exception cause) {
                   public void run() {
                     if (cause instanceof DebugServerException) {
                       DebugServerException debugServerException = (DebugServerException) cause;
-                      showNewJavaError(debugServerException.description, cause);
+                      showNewJavaError(debugServerException.getMessage(), cause);
                     } else {
                       showNewJavaError(
                           mApplicationContext.getString(R.string.catalyst_jsload_error),
diff --git a/ReactAndroid/src/main/res/devsupport/values/strings.xml b/ReactAndroid/src/main/res/devsupport/values/strings.xml
index 0107c3689cf3..d56ca71d1cec 100644
--- a/ReactAndroid/src/main/res/devsupport/values/strings.xml
+++ b/ReactAndroid/src/main/res/devsupport/values/strings.xml
@@ -13,7 +13,7 @@
   <string name="catalyst_settings_title" project="catalyst" translatable="false">Catalyst Dev Settings</string>
   <string name="catalyst_jsload_title" project="catalyst" translatable="false">Please wait…</string>
   <string name="catalyst_jsload_message" project="catalyst" translatable="false">Fetching JS bundle</string>
-  <string name="catalyst_jsload_error" project="catalyst" translatable="false">Unable to download JS bundle from the dev server.\n\nTry the following to fix the issue:\n• Ensure that the packager server is running\n• Ensure that your device/emulator is connected to your machine and has USB debugging enabled - run \'adb devices\' to see a list of connected devices\n• If you\'re on a physical device connected to the same machine, run \'adb reverse tcp:8081 tcp:8081\' to forward requests from your device\n• If your device is on the same Wi-Fi network, set \'Debug server host &amp; port for device\' in \'Dev settings\' to your machine\'s IP address and the port of the local dev server - e.g. 10.0.1.1:8081</string>
+  <string name="catalyst_jsload_error" project="catalyst" translatable="false">Unable to download JS bundle. Did you forget to start the development server or connect your device?</string>
   <string name="catalyst_remotedbg_message" project="catalyst" translatable="false">Connecting to remote debugger</string>
   <string name="catalyst_remotedbg_error" project="catalyst" translatable="false">Unable to connect with remote debugger</string>
   <string name="catalyst_element_inspector" project="catalyst" translatable="false">Show Inspector</string>

From 90403154a21c654e4f0bc7258a3655ce9c1ae3c5 Mon Sep 17 00:00:00 2001
From: Fabian Eichinger <fabian.eichinger@gmail.com>
Date: Mon, 8 Feb 2016 03:22:47 -0800
Subject: [PATCH 1065/1411] Snapshot the Set of listeners when dispatching a
 BackAndroid event
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Summary:
…while an event is dispatched

While it is guarded, a copy of the Set is created before listeners are added or removed. The event dispatch loop continues with the old Set of listeners.

This PR modifies `BackAndroid` to match the proposal at the end of #5781.
Closes https://github.com/facebook/react-native/pull/5783

Reviewed By: svcscm

Differential Revision: D2911282

Pulled By: foghina

fb-gh-sync-id: 34964ec3414af85eb9574bbcef081238fc67ffaf
---
 Libraries/Utilities/BackAndroid.android.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/Libraries/Utilities/BackAndroid.android.js b/Libraries/Utilities/BackAndroid.android.js
index 66baa59c4ea8..795380448d2f 100644
--- a/Libraries/Utilities/BackAndroid.android.js
+++ b/Libraries/Utilities/BackAndroid.android.js
@@ -23,8 +23,9 @@ type BackPressEventName = $Enum<{
 var _backPressSubscriptions = new Set();
 
 RCTDeviceEventEmitter.addListener(DEVICE_BACK_EVENT, function() {
+  var backPressSubscriptions = new Set(_backPressSubscriptions);
   var invokeDefault = true;
-  _backPressSubscriptions.forEach((subscription) => {
+  backPressSubscriptions.forEach((subscription) => {
     if (subscription()) {
       invokeDefault = false;
     }

From 1c112762e33aac6241ea7e31a1fb5c969250d16b Mon Sep 17 00:00:00 2001
From: Christopher Chedeau <vjeux@fb.com>
Date: Mon, 8 Feb 2016 04:04:01 -0800
Subject: [PATCH 1066/1411] Add support for number as colors

Summary: Closes https://github.com/facebook/react-native/pull/5805

Reviewed By: svcscm

Differential Revision: D2911330

Pulled By: javache

fb-gh-sync-id: b07c00a9271a161e3c88755434f6ffa34f4d519d
---
 Libraries/StyleSheet/ColorPropType.js         | 21 +++++++++---------
 .../__tests__/normalizeColor-test.js          | 10 +++++++++
 Libraries/StyleSheet/normalizeColor.js        | 11 ++++++++--
 docs/Colors.md                                | 22 ++++++++++---------
 4 files changed, 42 insertions(+), 22 deletions(-)

diff --git a/Libraries/StyleSheet/ColorPropType.js b/Libraries/StyleSheet/ColorPropType.js
index 9e956e4c4e7b..ab6cf45243d0 100644
--- a/Libraries/StyleSheet/ColorPropType.js
+++ b/Libraries/StyleSheet/ColorPropType.js
@@ -41,16 +41,17 @@ var colorPropType = function(isRequired, props, propName, componentName, locatio
       'Invalid ' + locationName + ' `' + (propFullName || propName) +
       '` supplied to `' + componentName + '`: ' + color + '\n' +
 `Valid color formats are
-  - #f0f (#rgb)
-  - #f0fc (#rgba)
-  - #ff00ff (#rrggbb)
-  - #ff00ff00 (#rrggbbaa)
-  - rgb(255, 255, 255)
-  - rgba(255, 255, 255, 1.0)
-  - hsl(360, 100%, 100%)
-  - hsla(360, 100%, 100%, 1.0)
-  - transparent
-  - red
+  - '#f0f' (#rgb)
+  - '#f0fc' (#rgba)
+  - '#ff00ff' (#rrggbb)
+  - '#ff00ff00' (#rrggbbaa)
+  - 'rgb(255, 255, 255)'
+  - 'rgba(255, 255, 255, 1.0)'
+  - 'hsl(360, 100%, 100%)'
+  - 'hsla(360, 100%, 100%, 1.0)'
+  - 'transparent'
+  - 'red'
+  - 0xff00ff00 (0xrrggbbaa)
 `);
   }
 };
diff --git a/Libraries/StyleSheet/__tests__/normalizeColor-test.js b/Libraries/StyleSheet/__tests__/normalizeColor-test.js
index e57fc0b7c364..dc12de12ff4f 100644
--- a/Libraries/StyleSheet/__tests__/normalizeColor-test.js
+++ b/Libraries/StyleSheet/__tests__/normalizeColor-test.js
@@ -23,6 +23,9 @@ describe('normalizeColor', function() {
     expect(normalizeColor('rgb(   1   , 2   , 3   )')).not.toBe(null);
     expect(normalizeColor('rgb(-1, -2, -3)')).not.toBe(null);
     expect(normalizeColor('rgba(0, 0, 0, 1)')).not.toBe(null);
+    expect(normalizeColor(0x01234567 + 0.5)).toBe(null);
+    expect(normalizeColor(-1)).toBe(null);
+    expect(normalizeColor(0xffffffff + 1)).toBe(null);
   });
 
   it('should temporarly accept floating point values for rgb', function() {
@@ -113,4 +116,11 @@ describe('normalizeColor', function() {
     expect(normalizeColor('transparent')).toBe(0x00000000);
     expect(normalizeColor('peachpuff')).toBe(0xffdab9ff);
   });
+
+  it('should handle number colors properly', function() {
+    expect(normalizeColor(0x00000000)).toBe(0x00000000);
+    expect(normalizeColor(0xff0000ff)).toBe(0xff0000ff);
+    expect(normalizeColor(0xffffffff)).toBe(0xffffffff);
+    expect(normalizeColor(0x01234567)).toBe(0x01234567);
+  });
 });
diff --git a/Libraries/StyleSheet/normalizeColor.js b/Libraries/StyleSheet/normalizeColor.js
index ae8d62f3011a..f32a09631682 100755
--- a/Libraries/StyleSheet/normalizeColor.js
+++ b/Libraries/StyleSheet/normalizeColor.js
@@ -12,12 +12,19 @@
 /* eslint no-bitwise: 0 */
 'use strict';
 
-function normalizeColor(color: string): ?number {
+function normalizeColor(color: string | number): ?number {
   var match;
 
+  if (typeof color === 'number') {
+    if (color >>> 0 === color && color >= 0 && color <= 0xffffffff) {
+      return color;
+    }
+    return null;
+  }
+
   // Ordered based on occurrences on Facebook codebase
   if ((match = matchers.hex6.exec(color))) {
-    return (parseInt(match[1], 16) << 8 | 0x000000ff) >>> 0;
+    return parseInt(match[1] + 'ff', 16) >>> 0;
   }
 
   if (names.hasOwnProperty(color)) {
diff --git a/docs/Colors.md b/docs/Colors.md
index d1036c65bb1e..aba269085a2b 100644
--- a/docs/Colors.md
+++ b/docs/Colors.md
@@ -8,16 +8,18 @@ permalink: docs/colors.html
 
 The following formats are supported:
 
- - `#f0f` (#rgb)
- - `#f0fc` (#rgba)
- - `#ff00ff` (#rrggbb)
- - `#ff00ff00` (#rrggbbaa)
- - `rgb(255, 255, 255)`
- - `rgba(255, 255, 255, 1.0)`
- - `hsl(360, 100%, 100%)`
- - `hsla(360, 100%, 100%, 1.0)`
- - `transparent`
- - `red`
+ - `'#f0f'` (#rgb)
+ - `'#f0fc'` (#rgba)
+ - `'#ff00ff'` (#rrggbb)
+ - `'#ff00ff00'` (#rrggbbaa)
+ - `'rgb(255, 255, 255)'`
+ - `'rgba(255, 255, 255, 1.0)'`
+ - `'hsl(360, 100%, 100%)'`
+ - `'hsla(360, 100%, 100%, 1.0)'`
+ - `'transparent'`
+ - `'red'`
+ - `0xff00ff00` (0xrrggbbaa)
+
 
 For the named colors, React Native follows the [CSS3 specification](http://www.w3.org/TR/css3-color/#svg-color):
 

From 042862a010da0ceda4af507d5c8ca1b3ac764681 Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Mon, 8 Feb 2016 04:48:29 -0800
Subject: [PATCH 1067/1411] Update Interpolation to use new color format

Reviewed By: bestander

Differential Revision: D2911363

fb-gh-sync-id: eddfc1f1e33ee6c74f3a492a69f6d93de018e4ae
---
 Libraries/Animated/src/Interpolation.js | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/Libraries/Animated/src/Interpolation.js b/Libraries/Animated/src/Interpolation.js
index c4e739e5ef87..b97d063b949a 100644
--- a/Libraries/Animated/src/Interpolation.js
+++ b/Libraries/Animated/src/Interpolation.js
@@ -173,10 +173,10 @@ function colorToRgba(input: string): string {
 
   int32Color = int32Color || 0; // $FlowIssue
 
-  var a = ((int32Color & 0xff000000) >>> 24) / 255;
-  var r = (int32Color & 0x00ff0000) >>> 16;
-  var g = (int32Color & 0x0000ff00) >>> 8;
-  var b = int32Color & 0x000000ff;
+  var r = (int32Color & 0xff000000) >>> 24;
+  var g = (int32Color & 0x00ff0000) >>> 16;
+  var b = (int32Color & 0x0000ff00) >>> 8;
+  var a = (int32Color & 0x000000ff) / 255;
 
   return `rgba(${r}, ${g}, ${b}, ${a})`;
 }

From c00049ce4f42ca342973fb6cdb50c5e6cec4c442 Mon Sep 17 00:00:00 2001
From: Tadeu Zagallo <tadeuzagallo@fb.com>
Date: Mon, 8 Feb 2016 07:06:52 -0800
Subject: [PATCH 1068/1411] Expose flow events to JS + add JS -> Native flows

Summary:
public

Expose JS hooks to create flow events in systrace (the nice arrows to show async work flow) +
add support to the showing all the work enqueued from the JS thread as added in D2743733

Depends on D2743733

Reviewed By: jspahrsummers

Differential Revision: D2815293

fb-gh-sync-id: 4278f61a67a6e78cf2704bacce34b1389328c6df
---
 React/Base/RCTBatchedBridge.m    | 29 +++++++++++++++++++++++++----
 React/Base/RCTBridge+Private.h   |  4 ++++
 React/Executors/RCTJSCExecutor.m | 15 +++++++++++++++
 React/Profiler/RCTProfile.h      |  2 +-
 4 files changed, 45 insertions(+), 5 deletions(-)

diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index 87e1fb8f774e..6ca0fad9cdee 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -35,7 +35,8 @@
 typedef NS_ENUM(NSUInteger, RCTBridgeFields) {
   RCTBridgeFieldRequestModuleIDs = 0,
   RCTBridgeFieldMethodIDs,
-  RCTBridgeFieldParamss,
+  RCTBridgeFieldParams,
+  RCTBridgeFieldCallID,
 };
 
 RCT_EXTERN NSArray<Class> *RCTGetModuleClasses(void);
@@ -65,6 +66,9 @@ @implementation RCTBatchedBridge
   NSUInteger _asyncInitializedModules;
 }
 
+@synthesize flowID = _flowID;
+@synthesize flowIDMap = _flowIDMap;
+
 - (instancetype)initWithParentBridge:(RCTBridge *)bridge
 {
   RCTAssertMainThread();
@@ -606,6 +610,9 @@ - (void)invalidate
       _frameUpdateObservers = nil;
       _pendingCalls = nil;
 
+      if (_flowIDMap != NULL) {
+        CFRelease(_flowIDMap);
+      }
     }];
   });
 }
@@ -812,15 +819,22 @@ - (void)handleBuffer:(id)buffer batchEnded:(BOOL)batchEnded
 - (void)handleBuffer:(NSArray *)buffer
 {
   NSArray *requestsArray = [RCTConvert NSArray:buffer];
-  if (RCT_DEBUG && requestsArray.count <= RCTBridgeFieldParamss) {
+
+  if (RCT_DEBUG && requestsArray.count <= RCTBridgeFieldParams) {
     RCTLogError(@"Buffer should contain at least %tu sub-arrays. Only found %tu",
-              RCTBridgeFieldParamss + 1, requestsArray.count);
+                RCTBridgeFieldParams + 1, requestsArray.count);
     return;
   }
 
   NSArray<NSNumber *> *moduleIDs = [RCTConvert NSNumberArray:requestsArray[RCTBridgeFieldRequestModuleIDs]];
   NSArray<NSNumber *> *methodIDs = [RCTConvert NSNumberArray:requestsArray[RCTBridgeFieldMethodIDs]];
-  NSArray<NSArray *> *paramsArrays = [RCTConvert NSArrayArray:requestsArray[RCTBridgeFieldParamss]];
+  NSArray<NSArray *> *paramsArrays = [RCTConvert NSArrayArray:requestsArray[RCTBridgeFieldParams]];
+
+  int64_t callID = -1;
+
+  if (requestsArray.count > 3) {
+    callID = [requestsArray[RCTBridgeFieldCallID] longLongValue];
+  }
 
   if (RCT_DEBUG && (moduleIDs.count != methodIDs.count || moduleIDs.count != paramsArrays.count)) {
     RCTLogError(@"Invalid data message - all must be length: %zd", moduleIDs.count);
@@ -853,6 +867,11 @@ - (void)handleBuffer:(NSArray *)buffer
       @autoreleasepool {
         for (NSNumber *indexObj in calls) {
           NSUInteger index = indexObj.unsignedIntegerValue;
+          if (callID != -1 && _flowIDMap != NULL) {
+            int64_t newFlowID = (int64_t)CFDictionaryGetValue(_flowIDMap, (const void *)(_flowID + index));
+            _RCTProfileEndFlowEvent(@(newFlowID));
+            CFDictionaryRemoveValue(_flowIDMap, (const void *)(_flowID + index));
+          }
           [self _handleRequestNumber:index
                             moduleID:[moduleIDs[index] integerValue]
                             methodID:[methodIDs[index] integerValue]
@@ -871,6 +890,8 @@ - (void)handleBuffer:(NSArray *)buffer
       dispatch_async(queue, block);
     }
   }
+
+  _flowID = callID;
 }
 
 - (void)partialBatchDidFlush
diff --git a/React/Base/RCTBridge+Private.h b/React/Base/RCTBridge+Private.h
index 8e673a6b05ec..eedda8cd8b77 100644
--- a/React/Base/RCTBridge+Private.h
+++ b/React/Base/RCTBridge+Private.h
@@ -13,6 +13,10 @@
 
 @interface RCTBridge ()
 
+// Used for the profiler flow events between JS and native
+@property (nonatomic, assign) int64_t flowID;
+@property (nonatomic, assign) CFMutableDictionaryRef flowIDMap;
+
 + (instancetype)currentBridge;
 + (void)setCurrentBridge:(RCTBridge *)bridge;
 
diff --git a/React/Executors/RCTJSCExecutor.m b/React/Executors/RCTJSCExecutor.m
index a1489d35e03b..f96d2992a9c3 100644
--- a/React/Executors/RCTJSCExecutor.m
+++ b/React/Executors/RCTJSCExecutor.m
@@ -314,6 +314,21 @@ - (void)setUp
     RCT_PROFILE_END_EVENT(tag.longLongValue, @"console", nil);
   }];
 
+  __weak RCTBridge *weakBridge = _bridge;
+#ifndef __clang_analyzer__
+  weakBridge.flowIDMap = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
+#endif
+  [self addSynchronousHookWithName:@"nativeTraceBeginAsyncFlow" usingBlock:^(__unused uint64_t tag, __unused NSString *name, int64_t cookie) {
+    int64_t newCookie = [_RCTProfileBeginFlowEvent() longLongValue];
+    CFDictionarySetValue(weakBridge.flowIDMap, (const void *)cookie, (const void *)newCookie);
+  }];
+
+  [self addSynchronousHookWithName:@"nativeTraceEndAsyncFlow" usingBlock:^(__unused uint64_t tag, __unused NSString *name, int64_t cookie) {
+    int64_t newCookie = (int64_t)CFDictionaryGetValue(weakBridge.flowIDMap, (const void *)cookie);
+    _RCTProfileEndFlowEvent(@(newCookie));
+    CFDictionaryRemoveValue(weakBridge.flowIDMap, (const void *)cookie);
+  }];
+
   [self executeBlockOnJavaScriptQueue:^{
     RCTInstallJSCProfiler(_bridge, self.context.ctx);
   }];
diff --git a/React/Profiler/RCTProfile.h b/React/Profiler/RCTProfile.h
index 17b3bf27d2ab..2212e2cb1f19 100644
--- a/React/Profiler/RCTProfile.h
+++ b/React/Profiler/RCTProfile.h
@@ -191,7 +191,7 @@ RCT_EXTERN void RCTProfileRegisterCallbacks(RCTProfileCallbacks *);
 #define _RCTProfileBeginFlowEvent() @0
 
 #define RCTProfileEndFlowEvent()
-#define _RCTProfileEndFlowEvent()
+#define _RCTProfileEndFlowEvent(...)
 
 #define RCTProfileIsProfiling(...) NO
 #define RCTProfileInit(...)

From 3c74a2595abf572c38d7eeb5887c4baff47aca7c Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@gmail.com>
Date: Mon, 8 Feb 2016 08:14:56 -0800
Subject: [PATCH 1069/1411] Disable proguard

Summary:
until we have an automated test in CI
Closes https://github.com/facebook/react-native/pull/5775

Reviewed By: svcscm

Differential Revision: D2911639

Pulled By: mkonicek

fb-gh-sync-id: 26d8194dd5a6fd7210f4b014787e6847217dd7f1
---
 local-cli/generator-android/templates/src/app/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/local-cli/generator-android/templates/src/app/build.gradle b/local-cli/generator-android/templates/src/app/build.gradle
index 943b871a27c1..05682ee30845 100644
--- a/local-cli/generator-android/templates/src/app/build.gradle
+++ b/local-cli/generator-android/templates/src/app/build.gradle
@@ -73,7 +73,7 @@ def enableSeparateBuildPerCPUArchitecture = false
 /**
  * Run Proguard to shrink the Java bytecode in release builds.
  */
-def enableProguardInReleaseBuilds = true
+def enableProguardInReleaseBuilds = false
 
 android {
     compileSdkVersion 23

From fca18652d0dbc147325660fe6b5aa99d2e4a3c3d Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Mon, 8 Feb 2016 08:55:11 -0800
Subject: [PATCH 1070/1411] fix markdown format problem

Summary: Closes https://github.com/facebook/react-native/pull/5819

Reviewed By: svcscm

Differential Revision: D2911774

Pulled By: vjeux

fb-gh-sync-id: 07737648216c775889742c81b82ec9b08e003a8f
---
 docs/JavaScriptEnvironment.md | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/docs/JavaScriptEnvironment.md b/docs/JavaScriptEnvironment.md
index cf6b3d409fd4..8bda774986da 100644
--- a/docs/JavaScriptEnvironment.md
+++ b/docs/JavaScriptEnvironment.md
@@ -52,8 +52,8 @@ ES7
 
 Specific
 
-- [JSX](https://facebook.github.io/react/docs/jsx-in-depth.html): `<View style={{color: 'red'}} />`
-- [Flow](http://flowtype.org/): `function foo(x: ?number): string {}`
+* [JSX](https://facebook.github.io/react/docs/jsx-in-depth.html): `<View style={{color: 'red'}} />`
+* [Flow](http://flowtype.org/): `function foo(x: ?number): string {}`
 
 
 ## Polyfills
@@ -69,14 +69,16 @@ Browser
 * [navigator.geolocation](/react-native/docs/geolocation.html#content)
  
 ES6
+
 * [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
 * String.prototype.{[startsWith](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith), [endsWith](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith), [repeat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeats), [includes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes)}
 * [Array.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from)
 * Array.prototype.{[find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find), [findIndex](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex)}
-* 
 
 ES7
+
 * Object.{[entries](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries), [values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values)}
 
 Specific
+
 * `__DEV__`

From 1cf605dda36cae1fc783f219abef9f8e770c1dd8 Mon Sep 17 00:00:00 2001
From: Jagdeep Nagpal <jagdeepnagpal@gmail.com>
Date: Mon, 8 Feb 2016 09:04:27 -0800
Subject: [PATCH 1071/1411] Fix Product Flavour builds

Summary:
- Capitalise productFlavorName for target path
- Capitalise buildType in sourceName when flavour exists
- Fix the path the assets are added.
- Backward compatibility with bundleIn(buildTypeName) when flavours are added
Closes https://github.com/facebook/react-native/pull/5580

Reviewed By: svcscm

Differential Revision: D2911735

Pulled By: mkonicek

fb-gh-sync-id: 6fb391a12ee27ee2a503961d8779a85d31cf5367
---
 .../templates/src/app/build.gradle            |  4 +++-
 .../templates/src/app/react.gradle            | 19 ++++++++++---------
 2 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/local-cli/generator-android/templates/src/app/build.gradle b/local-cli/generator-android/templates/src/app/build.gradle
index 05682ee30845..ee7028cf4f25 100644
--- a/local-cli/generator-android/templates/src/app/build.gradle
+++ b/local-cli/generator-android/templates/src/app/build.gradle
@@ -26,7 +26,9 @@ import com.android.build.OutputFile
  *
  *   // whether to bundle JS and assets in another build variant (if configured).
  *   // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
- *   // The configuration property is in the format 'bundleIn${productFlavor}${buildType}'
+ *   // The configuration property can be in the following formats
+ *   //         'bundleIn${productFlavor}${buildType}'
+ *   //         'bundleIn${buildType}'
  *   // bundleInFreeDebug: true,
  *   // bundleInPaidRelease: true,
  *   // bundleInBeta: true,
diff --git a/local-cli/generator-android/templates/src/app/react.gradle b/local-cli/generator-android/templates/src/app/react.gradle
index 4b43bf910cc8..11a4f8b871de 100644
--- a/local-cli/generator-android/templates/src/app/react.gradle
+++ b/local-cli/generator-android/templates/src/app/react.gradle
@@ -30,21 +30,20 @@ gradle.projectsEvaluated {
 
     productFlavors.each { productFlavorName ->
         buildTypes.each { buildTypeName ->
-            // Create variant and source names
-            def sourceName = "${buildTypeName}"
-            def targetName = "${sourceName.capitalize()}"
-            if (productFlavorName) {
-                sourceName = "${productFlavorName}${targetName}"
-            }
+            // Create variant and target names
+            def targetName = "${productFlavorName.capitalize()}${buildTypeName.capitalize()}"
+            def targetPath = productFlavorName ?
+                    "${productFlavorName}/${buildTypeName}" :
+                    "${buildTypeName}"
 
             // React js bundle directories
             def jsBundleDirConfigName = "jsBundleDir${targetName}"
             def jsBundleDir = elvisFile(config."$jsBundleDirConfigName") ?:
-                    file("$buildDir/intermediates/assets/${sourceName}")
+                    file("$buildDir/intermediates/assets/${targetPath}")
 
             def resourcesDirConfigName = "jsBundleDir${targetName}"
             def resourcesDir = elvisFile(config."${resourcesDirConfigName}") ?:
-                    file("$buildDir/intermediates/res/merged/${sourceName}")
+                    file("$buildDir/intermediates/res/merged/${targetPath}")
             def jsBundleFile = file("$jsBundleDir/$bundleAssetName")
 
             // Bundle task name for variant
@@ -80,7 +79,9 @@ gradle.projectsEvaluated {
                             "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir
                 }
 
-                enabled config."bundleIn${targetName}" ?: targetName.toLowerCase().contains("release")
+                enabled config."bundleIn${targetName}" ||
+                    config."bundleIn${buildTypeName.capitalize()}" ?:
+                            targetName.toLowerCase().contains("release")
             }
 
             // Hook bundle${productFlavor}${buildType}JsAndAssets into the android build process

From 6b63afb0979af5ada733fc0608438de5b8ed30c9 Mon Sep 17 00:00:00 2001
From: Andrei Coman <andreic@fb.com>
Date: Mon, 8 Feb 2016 09:16:24 -0800
Subject: [PATCH 1072/1411] Add invariant for null root ids

Reviewed By: astreet

Differential Revision: D2911414

fb-gh-sync-id: 7d7a4144765e093de18b442f7304693556fdfc2f
---
 Libraries/ReactNative/ReactNativeBaseComponent.js | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/Libraries/ReactNative/ReactNativeBaseComponent.js b/Libraries/ReactNative/ReactNativeBaseComponent.js
index 8b60d8682497..0beef933454f 100644
--- a/Libraries/ReactNative/ReactNativeBaseComponent.js
+++ b/Libraries/ReactNative/ReactNativeBaseComponent.js
@@ -19,6 +19,7 @@ var ReactMultiChild = require('ReactMultiChild');
 var UIManager = require('UIManager');
 
 var deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
+var invariant = require('invariant');
 var warning = require('warning');
 
 var registrationNames = ReactNativeEventEmitter.registrationNames;
@@ -79,7 +80,7 @@ ReactNativeBaseComponent.Mixin = {
     // 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 = [];
@@ -189,10 +190,16 @@ ReactNativeBaseComponent.Mixin = {
     );
 
     var nativeTopRootID = ReactNativeTagHandles.getNativeTopRootIDFromNodeID(rootID);
+    if (nativeTopRootID == null) {
+      invariant(
+        false,
+        'nativeTopRootID not found for tag ' + tag + ' view type ' +
+          this.viewConfig.uiViewClassName + ' with rootID ' + rootID);
+    }
     UIManager.createView(
       tag,
       this.viewConfig.uiViewClassName,
-      nativeTopRootID ? ReactNativeTagHandles.rootNodeIDToTag[nativeTopRootID] : null,
+      ReactNativeTagHandles.rootNodeIDToTag[nativeTopRootID],
       updatePayload
     );
 

From 0a6604fa96098baf47f71bc624ab3e08bc34f697 Mon Sep 17 00:00:00 2001
From: Csaba Palfi <csaba@palfi.me>
Date: Mon, 8 Feb 2016 10:06:22 -0800
Subject: [PATCH 1073/1411] Fix Movies example deprecation warning

Summary: Closes https://github.com/facebook/react-native/pull/5802

Reviewed By: svcscm

Differential Revision: D2911814

Pulled By: androidtrunkagent

fb-gh-sync-id: b623827442fdde53a64e17b7d7842e3a268cf016
---
 Examples/Movies/SearchScreen.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Examples/Movies/SearchScreen.js b/Examples/Movies/SearchScreen.js
index 1bc6bb906cea..ad1f9b72bfdd 100644
--- a/Examples/Movies/SearchScreen.js
+++ b/Examples/Movies/SearchScreen.js
@@ -316,7 +316,7 @@ var SearchScreen = React.createClass({
           onSearchChange={this.onSearchChange}
           isLoading={this.state.isLoading}
           onFocus={() =>
-            this.refs.listview && this.refs.listview.getScrollResponder().scrollTo(0, 0)}
+            this.refs.listview && this.refs.listview.getScrollResponder().scrollTo({ x: 0, y: 0 })}
         />
         <View style={styles.separator} />
         {content}

From 17fcc9440f9f6f6bbed9c746cb035dd3c4716355 Mon Sep 17 00:00:00 2001
From: sospartan <sospartan@gmail.com>
Date: Mon, 8 Feb 2016 10:09:15 -0800
Subject: [PATCH 1074/1411] allow use external typeface in native code

Summary:
Expose method to implement changing font family cache.  Like ide suggested in #4420 , this will helpful for using remote font file (use `Typeface#createFromFile` to load downloaded font file).
iOS's CoreText  already allow this in native code.
Closes https://github.com/facebook/react-native/pull/4696

Reviewed By: bestander

Differential Revision: D2911762

Pulled By: andreicoman11

fb-gh-sync-id: a931e2e711dd94fa0df6fdd066827756d862a4ba
---
 .../react/views/text/ReactFontManager.java    | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactFontManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactFontManager.java
index 10e2a4d7b9ff..1e63a2094923 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactFontManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactFontManager.java
@@ -72,6 +72,25 @@ public static ReactFontManager getInstance() {
     return typeface;
   }
 
+  /**
+   * Add additional font family, or replace the exist one in the font memory cache.
+   * @param style
+   * @see {@link Typeface#DEFAULT}
+   * @see {@link Typeface#BOLD}
+   * @see {@link Typeface#ITALIC}
+   * @see {@link Typeface#BOLD_ITALIC}
+   */
+  public void setTypeface(String fontFamilyName, int style, Typeface typeface) {
+    if (typeface != null) {
+      FontFamily fontFamily = mFontCache.get(fontFamilyName);
+      if (fontFamily == null) {
+        fontFamily = new FontFamily();
+        mFontCache.put(fontFamilyName, fontFamily);
+      }
+      fontFamily.setTypeface(style, typeface);
+    }
+  }
+
   private static
   @Nullable Typeface createTypeface(
       String fontFamilyName,

From 4937a4c5cd2494a875019bfeb691026b0abfe58e Mon Sep 17 00:00:00 2001
From: mattds <matthewstephanou@Matthews-iMac.local>
Date: Mon, 8 Feb 2016 10:42:31 -0800
Subject: [PATCH 1075/1411] Added support for corner radii in Android

Summary:
This is a cut down version of a previous pull request with just the 4 corners catered for.
Closes https://github.com/facebook/react-native/pull/4252

Reviewed By: svcscm

Differential Revision: D2911959

Pulled By: androidtrunkagent

fb-gh-sync-id: 7ddcd684d90d4d92ccefed906c0126e92818dcde
---
 Examples/UIExplorer/BorderExample.js          | 29 +++++++
 .../facebook/react/uimanager/ViewProps.java   |  5 ++
 .../view/ReactViewBackgroundDrawable.java     | 78 ++++++++++++++++---
 .../react/views/view/ReactViewGroup.java      |  4 +
 .../react/views/view/ReactViewManager.java    | 20 ++++-
 5 files changed, 124 insertions(+), 12 deletions(-)

diff --git a/Examples/UIExplorer/BorderExample.js b/Examples/UIExplorer/BorderExample.js
index c6c22f5531f0..1c547ea6ea21 100644
--- a/Examples/UIExplorer/BorderExample.js
+++ b/Examples/UIExplorer/BorderExample.js
@@ -98,6 +98,20 @@ var styles = StyleSheet.create({
     marginRight: 10,
     backgroundColor: 'lightgrey',
   },
+  border9: {
+    borderWidth: 10,
+    borderTopLeftRadius: 10,
+    borderBottomRightRadius: 20,
+    borderColor: 'black',
+  },
+  border10: {
+    borderWidth: 10,
+    backgroundColor: 'white',
+    borderTopLeftRadius: 10,
+    borderBottomRightRadius: 20,
+    borderColor: 'black',
+    elevation: 10
+  }
 });
 
 exports.title = 'Border';
@@ -180,4 +194,19 @@ exports.examples = [
       );
     }
   },
+  {
+    title: 'Corner Radii',
+    description: 'borderTopLeftRadius & borderBottomRightRadius',
+    render() {
+      return <View style={[styles.box, styles.border9]} />;
+    }
+  },
+  {
+    title: 'Corner Radii / Elevation',
+    description: 'borderTopLeftRadius & borderBottomRightRadius & elevation',
+    platform: 'android',
+    render() {
+      return <View style={[styles.box, styles.border10]} />;
+    }
+  },
 ];
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java
index 33e52fe95b21..3cef8895ac77 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java
@@ -77,6 +77,11 @@ public class ViewProps {
   public static final String BORDER_TOP_WIDTH = "borderTopWidth";
   public static final String BORDER_RIGHT_WIDTH = "borderRightWidth";
   public static final String BORDER_BOTTOM_WIDTH = "borderBottomWidth";
+  public static final String BORDER_RADIUS = "borderRadius";
+  public static final String BORDER_TOP_LEFT_RADIUS = "borderTopLeftRadius";
+  public static final String BORDER_TOP_RIGHT_RADIUS = "borderTopRightRadius";
+  public static final String BORDER_BOTTOM_LEFT_RADIUS = "borderBottomLeftRadius";
+  public static final String BORDER_BOTTOM_RIGHT_RADIUS = "borderBottomRightRadius";
   public static final int[] BORDER_SPACING_TYPES = {
       Spacing.ALL, Spacing.LEFT, Spacing.RIGHT, Spacing.TOP, Spacing.BOTTOM
   };
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java
index f36f70db7f46..742adbd84b1b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java
@@ -11,6 +11,7 @@
 
 import javax.annotation.Nullable;
 
+import java.util.Arrays;
 import java.util.Locale;
 
 import android.graphics.Canvas;
@@ -78,7 +79,9 @@ private static enum BorderStyle {
   /* Used for rounded border and rounded background */
   private @Nullable PathEffect mPathEffectForBorderStyle;
   private @Nullable Path mPathForBorderRadius;
+  private @Nullable Path mPathForBorderRadiusOutline;
   private @Nullable RectF mTempRectForBorderRadius;
+  private @Nullable RectF mTempRectForBorderRadiusOutline;
   private boolean mNeedUpdatePathForBorderRadius = false;
   private float mBorderRadius = CSSConstants.UNDEFINED;
 
@@ -87,9 +90,11 @@ private static enum BorderStyle {
   private int mColor = Color.TRANSPARENT;
   private int mAlpha = 255;
 
+  private @Nullable float[] mBorderCornerRadii;
+
   @Override
   public void draw(Canvas canvas) {
-    if (!CSSConstants.isUndefined(mBorderRadius) && mBorderRadius > 0) {
+    if ((!CSSConstants.isUndefined(mBorderRadius) && mBorderRadius > 0) || mBorderCornerRadii != null) {
       drawRoundedBackgroundWithBorders(canvas);
     } else {
       drawRectangularBackgroundWithBorders(canvas);
@@ -132,11 +137,10 @@ public void getOutline(Outline outline) {
       super.getOutline(outline);
       return;
     }
-    if(!CSSConstants.isUndefined(mBorderRadius) && mBorderRadius > 0) {
-      float extraRadiusFromBorderWidth = (mBorderWidth != null)
-              ? mBorderWidth.get(Spacing.ALL) / 2f
-              : 0;
-      outline.setRoundRect(getBounds(), mBorderRadius + extraRadiusFromBorderWidth);
+    if((!CSSConstants.isUndefined(mBorderRadius) && mBorderRadius > 0) || mBorderCornerRadii != null) {
+      updatePath();
+
+      outline.setConvexPath(mPathForBorderRadiusOutline);
     } else {
       outline.setRect(getBounds());
     }
@@ -181,8 +185,22 @@ public void setBorderStyle(@Nullable String style) {
   }
 
   public void setRadius(float radius) {
-    if (mBorderRadius != radius) {
+    if (!FloatUtil.floatsEqual(mBorderRadius,radius)) {
       mBorderRadius = radius;
+      mNeedUpdatePathForBorderRadius = true;
+      invalidateSelf();
+    }
+  }
+
+  public void setRadius(float radius, int position) {
+    if (mBorderCornerRadii == null) {
+      mBorderCornerRadii = new float[4];
+      Arrays.fill(mBorderCornerRadii, CSSConstants.UNDEFINED);
+    }
+
+    if (!FloatUtil.floatsEqual(mBorderCornerRadii[position], radius)) {
+      mBorderCornerRadii[position] = radius;
+      mNeedUpdatePathForBorderRadius = true;
       invalidateSelf();
     }
   }
@@ -225,19 +243,61 @@ private void updatePath() {
     if (mPathForBorderRadius == null) {
       mPathForBorderRadius = new Path();
       mTempRectForBorderRadius = new RectF();
+      mPathForBorderRadiusOutline = new Path();
+      mTempRectForBorderRadiusOutline = new RectF();
     }
+
     mPathForBorderRadius.reset();
+    mPathForBorderRadiusOutline.reset();
+
     mTempRectForBorderRadius.set(getBounds());
+    mTempRectForBorderRadiusOutline.set(getBounds());
     float fullBorderWidth = getFullBorderWidth();
     if (fullBorderWidth > 0) {
       mTempRectForBorderRadius.inset(fullBorderWidth * 0.5f, fullBorderWidth * 0.5f);
     }
+
+    float defaultBorderRadius = !CSSConstants.isUndefined(mBorderRadius) ? mBorderRadius : 0;
+    float topLeftRadius = mBorderCornerRadii != null && !CSSConstants.isUndefined(mBorderCornerRadii[0]) ? mBorderCornerRadii[0] : defaultBorderRadius;
+    float topRightRadius = mBorderCornerRadii != null && !CSSConstants.isUndefined(mBorderCornerRadii[1]) ? mBorderCornerRadii[1] : defaultBorderRadius;
+    float bottomRightRadius = mBorderCornerRadii != null && !CSSConstants.isUndefined(mBorderCornerRadii[2]) ? mBorderCornerRadii[2] : defaultBorderRadius;
+    float bottomLeftRadius = mBorderCornerRadii != null && !CSSConstants.isUndefined(mBorderCornerRadii[3]) ? mBorderCornerRadii[3] : defaultBorderRadius;
+
+
     mPathForBorderRadius.addRoundRect(
         mTempRectForBorderRadius,
-        mBorderRadius,
-        mBorderRadius,
+        new float[] {
+          topLeftRadius,
+          topLeftRadius,
+          topRightRadius,
+          topRightRadius,
+          bottomRightRadius,
+          bottomRightRadius,
+          bottomLeftRadius,
+          bottomLeftRadius
+        },
         Path.Direction.CW);
 
+    float extraRadiusForOutline = 0;
+
+    if (mBorderWidth != null) {
+      extraRadiusForOutline = mBorderWidth.get(Spacing.ALL) / 2f;
+    }
+
+    mPathForBorderRadiusOutline.addRoundRect(
+      mTempRectForBorderRadiusOutline,
+      new float[] {
+        topLeftRadius + extraRadiusForOutline,
+        topLeftRadius + extraRadiusForOutline,
+        topRightRadius + extraRadiusForOutline,
+        topRightRadius + extraRadiusForOutline,
+        bottomRightRadius + extraRadiusForOutline,
+        bottomRightRadius + extraRadiusForOutline,
+        bottomLeftRadius + extraRadiusForOutline,
+        bottomLeftRadius + extraRadiusForOutline
+      },
+      Path.Direction.CW);
+
     mPathEffectForBorderStyle = mBorderStyle != null
         ? mBorderStyle.getPathEffect(getFullBorderWidth())
         : null;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
index 88ac93397859..bf57e47a6554 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
@@ -207,6 +207,10 @@ public void setBorderRadius(float borderRadius) {
     getOrCreateReactViewBackground().setRadius(borderRadius);
   }
 
+  public void setBorderRadius(float borderRadius, int position) {
+    getOrCreateReactViewBackground().setRadius(borderRadius, position);
+  }
+
   public void setBorderStyle(@Nullable String style) {
     getOrCreateReactViewBackground().setBorderStyle(style);
   }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
index 5e761b0f7a2e..789b294e1f94 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
@@ -51,9 +51,23 @@ public void setAccessible(ReactViewGroup view, boolean accessible) {
     view.setFocusable(accessible);
   }
 
-  @ReactProp(name = "borderRadius")
-  public void setBorderRadius(ReactViewGroup view, float borderRadius) {
-    view.setBorderRadius(PixelUtil.toPixelFromDIP(borderRadius));
+  @ReactPropGroup(names = {
+      ViewProps.BORDER_RADIUS,
+      ViewProps.BORDER_TOP_LEFT_RADIUS,
+      ViewProps.BORDER_TOP_RIGHT_RADIUS,
+      ViewProps.BORDER_BOTTOM_RIGHT_RADIUS,
+      ViewProps.BORDER_BOTTOM_LEFT_RADIUS
+  }, defaultFloat = CSSConstants.UNDEFINED)
+  public void setBorderRadius(ReactViewGroup view, int index, float borderRadius) {
+    if (!CSSConstants.isUndefined(borderRadius)) {
+      borderRadius = PixelUtil.toPixelFromDIP(borderRadius);
+    }
+
+    if (index == 0) {
+      view.setBorderRadius(borderRadius);
+    } else {
+      view.setBorderRadius(borderRadius, index - 1);
+    }
   }
 
   @ReactProp(name = "borderStyle")

From 6b74535e97a1320ca0a9f2b356e2b1826f78335e Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Mon, 8 Feb 2016 11:18:25 -0800
Subject: [PATCH 1076/1411] Clean up Bundler

Summary:
The bundler class had duplicated code and parts that were hard to follow, because functions accepted heterogenous arguments, leading to a lot of conditionals.

This commit tries to remove duplication between build steps of different type of bundles, and by accepting less different types of arguments. These differences are now handled further up the call stack.

public

Reviewed By: sebmarkbage

Differential Revision: D2905807

fb-gh-sync-id: ef85ea0d461a9a06a4a64480e014a5324c4ef532
---
 local-cli/server/util/attachHMRServer.js      |  17 +-
 .../react-packager/src/Bundler/BundleBase.js  |  12 +-
 .../src/Bundler/__tests__/Bundle-test.js      |  13 +-
 packager/react-packager/src/Bundler/index.js  | 289 ++++++++----------
 .../DependencyGraph/ResolutionResponse.js     |  15 +
 packager/react-packager/src/Server/index.js   |   2 +-
 6 files changed, 145 insertions(+), 203 deletions(-)

diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js
index 3fc85e98c83f..54f510fd71ee 100644
--- a/local-cli/server/util/attachHMRServer.js
+++ b/local-cli/server/util/attachHMRServer.js
@@ -137,10 +137,7 @@ function attachHMRServer({httpServer, path, packagerServer}) {
                   }).then(response => {
                     const module = packagerServer.getModuleForPath(filename);
 
-                    return {
-                      modulesToUpdate: [module],
-                      resolutionResponse: response,
-                    };
+                    return response.copy({dependencies: [module]});
                   });
                 }
 
@@ -170,13 +167,12 @@ function attachHMRServer({httpServer, path, packagerServer}) {
                     client.dependenciesModulesCache = dependenciesModulesCache;
                     client.shallowDependencies = shallowDependencies;
 
-                    return {
-                      modulesToUpdate,
-                      resolutionResponse,
-                    };
+                    return resolutionResponse.copy({
+                      dependencies: modulesToUpdate
+                    });
                   });
               })
-              .then(({modulesToUpdate, resolutionResponse}) => {
+              .then((resolutionResponse) => {
                 if (!client) {
                   return;
                 }
@@ -189,9 +185,8 @@ function attachHMRServer({httpServer, path, packagerServer}) {
                 return packagerServer.buildBundleForHMR({
                   entryFile: client.bundleEntry,
                   platform: client.platform,
-                  modules: modulesToUpdate,
                   resolutionResponse,
-                })
+                });
               })
               .then(bundle => {
                 if (!client || !bundle || bundle.isEmpty()) {
diff --git a/packager/react-packager/src/Bundler/BundleBase.js b/packager/react-packager/src/Bundler/BundleBase.js
index 79cbfefc37b0..d3794a433c2f 100644
--- a/packager/react-packager/src/Bundler/BundleBase.js
+++ b/packager/react-packager/src/Bundler/BundleBase.js
@@ -16,7 +16,7 @@ class BundleBase {
     this._finalized = false;
     this._modules = [];
     this._assets = [];
-    this._mainModuleId = this._mainModuleName = undefined;
+    this._mainModuleId = undefined;
   }
 
   isEmpty() {
@@ -31,14 +31,6 @@ class BundleBase {
     this._mainModuleId = moduleId;
   }
 
-  getMainModuleName() {
-    return this._mainModuleName;
-  }
-
-  setMainModuleName(moduleName) {
-    this._mainModuleName = moduleName;
-  }
-
   addModule(module) {
     if (!module instanceof ModuleTransport) {
       throw new Error('Expeceted a ModuleTransport object');
@@ -89,7 +81,6 @@ class BundleBase {
       modules: this._modules,
       assets: this._assets,
       mainModuleId: this.getMainModuleId(),
-      mainModuleName: this.getMainModuleName(),
     };
   }
 
@@ -97,7 +88,6 @@ class BundleBase {
     bundle._assets = json.assets;
     bundle._modules = json.modules;
     bundle.setMainModuleId(json.mainModuleId);
-    bundle.setMainModuleName(json.mainModuleName);
 
     Object.freeze(bundle._modules);
     Object.seal(bundle._modules);
diff --git a/packager/react-packager/src/Bundler/__tests__/Bundle-test.js b/packager/react-packager/src/Bundler/__tests__/Bundle-test.js
index b4152a7b2a3e..23fe5762dda7 100644
--- a/packager/react-packager/src/Bundler/__tests__/Bundle-test.js
+++ b/packager/react-packager/src/Bundler/__tests__/Bundle-test.js
@@ -312,28 +312,21 @@ describe('Bundle', () => {
     });
   });
 
-  describe('main module name and id:', function() {
-    it('keeps distinct module names and IDs', function() {
+  describe('main module id:', function() {
+    it('can save a main module ID', function() {
       const id = 'arbitrary module ID';
-      const name = 'arbitrary module name';
       bundle.setMainModuleId(id);
-      bundle.setMainModuleName(name);
-
       expect(bundle.getMainModuleId()).toEqual(id);
-      expect(bundle.getMainModuleName()).toEqual(name);
     });
 
-    it('can serialize and deserialize module ID and name', function() {
+    it('can serialize and deserialize the module ID', function() {
       const id = 'arbitrary module ID';
-      const name = 'arbitrary module name';
       bundle.setMainModuleId(id);
-      bundle.setMainModuleName(name);
       bundle.finalize({});
 
       const deserialized = Bundle.fromJSON(bundle.toJSON());
 
       expect(deserialized.getMainModuleId()).toEqual(id);
-      expect(deserialized.getMainModuleName()).toEqual(name);
     });
   });
 });
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index fc7be66d0357..a07d73f7ac5f 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -29,6 +29,8 @@ const version = require('../../../../package.json').version;
 const sizeOf = Promise.denodeify(imageSize);
 const readFile = Promise.denodeify(fs.readFile);
 
+const noop = () => {};
+
 const validateOpts = declareOpts({
   projectRoots: {
     type: 'array',
@@ -159,9 +161,12 @@ class Bundler {
   }
 
   bundle(options) {
+    const {dev, isUnbundle, platform} = options;
+    const moduleSystemDeps =
+      this._resolver.getModuleSystemDependencies({dev, isUnbundle, platform});
     return this._bundle({
       bundle: new Bundle(options.sourceMapUrl),
-      includeSystemDependencies: true,
+      moduleSystemDeps,
       ...options,
     });
   }
@@ -209,7 +214,7 @@ class Bundler {
     );
   }
 
-  bundleForHMR(options) {
+  hmrBundle(options) {
     return this._bundle({
       bundle: new HMRBundle({
         sourceURLFn: this._sourceHMRURL.bind(this, options.platform),
@@ -225,121 +230,50 @@ class Bundler {
 
   _bundle({
     bundle,
-    modules,
     entryFile,
     runModule: runMainModule,
     runBeforeMainModule,
     dev: isDev,
-    includeSystemDependencies,
     platform,
-    unbundle: isUnbundle,
-    hot: hot,
+    moduleSystemDeps = [],
+    hot,
     entryModuleOnly,
-    resolutionResponse,
+    resolutionResponse
   }) {
-    let transformEventId;
-    const moduleSystemDeps = includeSystemDependencies
-      ? this._resolver.getModuleSystemDependencies(
-        { dev: isDev, platform, isUnbundle }
-      )
-      : [];
-
-    const findModules = () => {
-      const findEventId = Activity.startEvent('find dependencies');
-      return this.getDependencies(entryFile, isDev, platform).then(response => {
-        Activity.endEvent(findEventId);
-        bundle.setMainModuleId(response.mainModuleId);
-        bundle.setMainModuleName(response.mainModuleId);
-        if (!entryModuleOnly && bundle.setNumPrependedModules) {
-          bundle.setNumPrependedModules(
-            response.numPrependedDependencies + moduleSystemDeps.length
-          );
-        }
-
-        return {
-          response,
-          modulesToProcess: response.dependencies,
-        };
-      });
-    };
-
-    const useProvidedModules = () => {
-      const moduleId = this._resolver.getModuleForPath(entryFile);
-      bundle.setMainModuleId(moduleId);
-      bundle.setMainModuleName(moduleId);
-      return Promise.resolve({
-        response: resolutionResponse,
-        modulesToProcess: modules
-      });
-    };
-
-    return (
-      modules ? useProvidedModules() : findModules()
-    ).then(({response, modulesToProcess}) => {
-
-      transformEventId = Activity.startEvent('transform');
-
-      let dependencies;
+    const onResolutionResponse = response => {
+      bundle.setMainModuleId(response.mainModuleId);
+      if (bundle.setNumPrependedModules) {
+        bundle.setNumPrependedModules(
+          response.numPrependedDependencies + moduleSystemDeps.length
+        );
+      }
       if (entryModuleOnly) {
-        dependencies = response.dependencies.filter(module =>
+        response.dependencies = response.dependencies.filter(module =>
           module.path.endsWith(entryFile)
         );
       } else {
-        const moduleSystemDeps = includeSystemDependencies
-          ? this._resolver.getModuleSystemDependencies(
-            { dev: isDev, platform, isUnbundle }
-          )
-          : [];
-
-        const modulesToProcess = modules || response.dependencies;
-        dependencies = moduleSystemDeps.concat(modulesToProcess);
-      }
-
-      let bar;
-      if (process.stdout.isTTY) {
-        bar = new ProgressBar('transforming [:bar] :percent :current/:total', {
-          complete: '=',
-          incomplete: ' ',
-          width: 40,
-          total: dependencies.length,
-        });
+        response.dependencies = moduleSystemDeps.concat(response.dependencies);
       }
-
-      return Promise.all(
-        dependencies.map(
-          module => {
-            return this._transformModule(
-              bundle,
-              module,
-              platform,
-              isDev,
-              hot,
-            ).then(transformed => {
-              if (bar) {
-                bar.tick();
-              }
-
-              return {
-                module,
-                transformed,
-              };
-            });
-          }
+    };
+    const finalizeBundle = ({bundle, transformedModules, response}) =>
+      Promise.all(
+        transformedModules.map(({module, transformed}) =>
+          bundle.addModule(this._resolver, response, module, transformed)
         )
-      ).then(transformedModules => Promise.all(
-        transformedModules.map(({module, transformed}) => {
-          return bundle.addModule(
-            this._resolver,
-            response,
-            module,
-            transformed,
-          );
-        })
-      ));
-    }).then(() => {
-      Activity.endEvent(transformEventId);
-      bundle.finalize({runBeforeMainModule, runMainModule});
-      return bundle;
+      ).then(() => {
+        bundle.finalize({runBeforeMainModule, runMainModule});
+        return bundle;
+      });
+
+    return this._buildBundle({
+      entryFile,
+      isDev,
+      platform,
+      bundle,
+      hot,
+      resolutionResponse,
+      onResolutionResponse,
+      finalizeBundle,
     });
   }
 
@@ -351,78 +285,86 @@ class Bundler {
     dev: isDev,
     platform,
   }) {
-    const bundle = new PrepackBundle(sourceMapUrl);
-    const findEventId = Activity.startEvent('find dependencies');
-    let transformEventId;
-    let mainModuleId;
-
-    return this.getDependencies(entryFile, isDev, platform).then((response) => {
-      Activity.endEvent(findEventId);
-      transformEventId = Activity.startEvent('transform');
-
-      let bar;
-      if (process.stdout.isTTY) {
-        bar = new ProgressBar('transforming [:bar] :percent :current/:total', {
-          complete: '=',
-          incomplete: ' ',
-          width: 40,
-          total: response.dependencies.length,
+    const onModuleTransformed = ({module, transformed, response, bundle}) => {
+      const deps = Object.create(null);
+      const pairs = response.getResolvedDependencyPairs(module);
+      if (pairs) {
+        pairs.forEach(pair => {
+          deps[pair[0]] = pair[1].path;
         });
       }
 
-      mainModuleId = response.mainModuleId;
+      return module.getName().then(name => {
+        bundle.addModule(name, transformed, deps, module.isPolyfill());
+      });
+    };
+    const finalizeBundle = ({bundle, response}) => {
+      const {mainModuleId} = response;
+      bundle.finalize({runBeforeMainModule, runMainModule, mainModuleId});
+      return bundle;
+    };
+
+    return this._buildBundle({
+      entryFile,
+      isDev,
+      platform,
+      onModuleTransformed,
+      finalizeBundle,
+      bundle: new PrepackBundle(sourceMapUrl),
+    });
+  }
 
-      return Promise.all(
-        response.dependencies.map(
-          module => this._transformModule(
+  _buildBundle({
+    entryFile,
+    isDev,
+    platform,
+    bundle,
+    hot,
+    resolutionResponse,
+    onResolutionResponse = noop,
+    onModuleTransformed = noop,
+    finalizeBundle = noop,
+  }) {
+    const findEventId = Activity.startEvent('find dependencies');
+    if (!resolutionResponse) {
+      resolutionResponse = this.getDependencies(entryFile, isDev, platform);
+    }
+
+    return Promise.resolve(resolutionResponse).then(response => {
+      Activity.endEvent(findEventId);
+      onResolutionResponse(response);
+
+      const transformEventId = Activity.startEvent('transform');
+      const bar = process.stdout.isTTY
+          ? new ProgressBar('transforming [:bar] :percent :current/:total', {
+              complete: '=',
+              incomplete: ' ',
+              width: 40,
+              total: response.dependencies.length,
+            })
+          : {tick() {}};
+      const transformPromises =
+        response.dependencies.map(module =>
+          this._transformModule({
+            mainModuleName: response.mainModuleId,
             bundle,
             module,
             platform,
-            isDev,
-          ).then(transformed => {
-            if (bar) {
-              bar.tick();
-            }
-
-            var deps = Object.create(null);
-            var pairs = response.getResolvedDependencyPairs(module);
-            if (pairs) {
-              pairs.forEach(pair => {
-                deps[pair[0]] = pair[1].path;
-              });
-            }
-
-            return module.getName().then(name => {
-              bundle.addModule(name, transformed, deps, module.isPolyfill());
-            });
+            dev: isDev,
+            hot
+          }).then(transformed => {
+            bar.tick();
+            onModuleTransformed({module, transformed, response, bundle});
+            return {module, transformed};
           })
-        )
-      );
-    }).then(() => {
-      Activity.endEvent(transformEventId);
-      bundle.finalize({runBeforeMainModule, runMainModule, mainModuleId });
-      return bundle;
-    });
-  }
-
-  _transformModuleForHMR(module, platform) {
-    if (module.isAsset()) {
-      return this._generateAssetObjAndCode(module, platform).then(
-        ({asset, code}) => {
-          return {
-            code,
-          };
-        }
-      );
-    } else {
-      // TODO(martinb): pass non null main (t9527509)
-      return this._getTransformOptions(
-        {main: null, dev: true, platform: 'ios'}, // TODO(martinb): avoid hard-coding platform
-        {hot: true},
-      ).then(options => {
-        return this._transformer.loadFileAndTransform(module.path, options);
+        );
+      return Promise.all(transformPromises).then(transformedModules => {
+        Activity.endEvent(transformEventId);
+        return Promise
+          .resolve(finalizeBundle({bundle, transformedModules, response}))
+          .then(() => bundle);
       });
-    }
+    });
   }
 
   invalidateFile(filePath) {
@@ -489,7 +431,14 @@ class Bundler {
     );
   }
 
-  _transformModule(bundle, module, platform = null, dev = true, hot = false) {
+  _transformModule({
+    bundle,
+    module,
+    mainModuleName,
+    platform = null,
+    dev = true,
+    hot = false,
+  }) {
     if (module.isAsset_DEPRECATED()) {
       return this._generateAssetModule_DEPRECATED(bundle, module);
     } else if (module.isAsset()) {
@@ -499,12 +448,12 @@ class Bundler {
     } else {
       return this._getTransformOptions(
         {
-          bundleEntry: bundle.getMainModuleName(),
+          bundleEntry: mainModuleName,
           platform: platform,
           dev: dev,
           modulePath: module.path,
         },
-        {hot: hot},
+        {hot},
       ).then(options => {
         return this._transformer.loadFileAndTransform(
           path.resolve(module.path),
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js
index 7fbafde84982..c13895fbe1e9 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js
@@ -19,6 +19,21 @@ class ResolutionResponse {
     this._finalized = false;
   }
 
+  copy(properties) {
+    const {
+      dependencies = this.dependencies,
+      asyncDependencies = this.asyncDependencies,
+      mainModuleId = this.mainModuleId,
+      mocks = this.mocks,
+    } = properties;
+    return Object.assign(new this.constructor(), this, {
+      dependencies,
+      asyncDependencies,
+      mainModuleId,
+      mocks,
+    });
+  }
+
   _assertNotFinalized() {
     if (this._finalized) {
       throw new Error('Attempted to mutate finalized response.');
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index f8c252a3fd23..0146e7d6695e 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -241,7 +241,7 @@ class Server {
   }
 
   buildBundleForHMR(modules) {
-    return this._bundler.bundleForHMR(modules);
+    return this._bundler.hmrBundle(modules);
   }
 
   getShallowDependencies(entryFile) {

From 4254e8a0a9a9b2cfbaed6037de360420e6c268e4 Mon Sep 17 00:00:00 2001
From: Andrei Coman <andreic@fb.com>
Date: Mon, 8 Feb 2016 11:45:30 -0800
Subject: [PATCH 1077/1411] Fix DisplayMetrics KeyboardListener dependency

Summary:
public
KeyboardListener needs DisplayMetrics to be initialized when it is attached. At
the moment, this breaks easily whenever we change these components, since DisplayMetrics are intialized
in a module and KeyboardListener is created eagerly in ReactRootView, whereas
ReactRootView can exist without the instance.
This changes to create DisplayMetrics as soon as possible, when the react
instance is built. The KeyboardListener is created and attached after the ReactRootView is
attached to an existing instance, point at which DisplayMetrics have to be
initialized.

Reviewed By: dmmiller

Differential Revision: D2911351

fb-gh-sync-id: 64d1805c5d5b2f6876adb694b565a2df059b381d
---
 .../react/ReactInstanceManagerImpl.java       | 40 ++++++++++++
 .../com/facebook/react/ReactRootView.java     | 23 +++++--
 .../react/uimanager/UIManagerModule.java      | 63 +------------------
 .../uimanager/UIManagerModuleConstants.java   |  4 +-
 .../UIManagerModuleConstantsHelper.java       |  9 +--
 .../textinput/ReactTextInputManager.java      |  3 +-
 .../uimanager/ReactPropConstantsTest.java     |  3 +
 .../UIManagerModuleConstantsTest.java         |  5 ++
 .../react/uimanager/UIManagerModuleTest.java  |  5 ++
 .../react/views/text/ReactTextTest.java       |  4 ++
 .../react/views/textinput/TextInputTest.java  |  4 ++
 11 files changed, 86 insertions(+), 77 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index 3c570a0616e2..a92b151e1d17 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -11,6 +11,8 @@
 
 import javax.annotation.Nullable;
 
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
@@ -21,8 +23,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.AsyncTask;
+import android.os.Build;
 import android.os.Bundle;
+import android.util.DisplayMetrics;
+import android.view.Display;
 import android.view.View;
+import android.view.WindowManager;
 
 import com.facebook.common.logging.FLog;
 import com.facebook.infer.annotation.Assertions;
@@ -58,6 +64,7 @@
 import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
 import com.facebook.react.modules.core.DeviceEventManagerModule;
 import com.facebook.react.uimanager.AppRegistry;
+import com.facebook.react.uimanager.DisplayMetricsHolder;
 import com.facebook.react.uimanager.UIImplementationProvider;
 import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.ViewManager;
@@ -261,6 +268,7 @@ public T get() throws Exception {
 
     // TODO(9577825): remove this
     ApplicationHolder.setApplication((Application) applicationContext.getApplicationContext());
+    setDisplayMetrics(applicationContext);
 
     mApplicationContext = applicationContext;
     mJSBundleFile = jsBundleFile;
@@ -299,6 +307,38 @@ private static void initializeSoLoaderIfNecessary(Context applicationContext) {
     SoLoader.init(applicationContext, /* native exopackage */ false);
   }
 
+  private static void setDisplayMetrics(Context context) {
+    DisplayMetrics displayMetrics = new DisplayMetrics();
+    displayMetrics.setTo(context.getResources().getDisplayMetrics());
+    WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+    Display display = wm.getDefaultDisplay();
+
+    // Get the real display metrics if we are using API level 17 or higher.
+    // The real metrics include system decor elements (e.g. soft menu bar).
+    //
+    // See: http://developer.android.com/reference/android/view/Display.html#getRealMetrics(android.util.DisplayMetrics)
+    if (Build.VERSION.SDK_INT >= 17){
+      display.getRealMetrics(displayMetrics);
+
+    } else {
+      // For 14 <= API level <= 16, we need to invoke getRawHeight and getRawWidth to get the real dimensions.
+      // Since react-native only supports API level 16+ we don't have to worry about other cases.
+      //
+      // Reflection exceptions are rethrown at runtime.
+      //
+      // See: http://stackoverflow.com/questions/14341041/how-to-get-real-screen-height-and-width/23861333#23861333
+      try {
+        Method mGetRawH = Display.class.getMethod("getRawHeight");
+        Method mGetRawW = Display.class.getMethod("getRawWidth");
+        displayMetrics.widthPixels = (Integer) mGetRawW.invoke(display);
+        displayMetrics.heightPixels = (Integer) mGetRawH.invoke(display);
+      } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
+        throw new RuntimeException("Error getting real dimensions for API level < 17", e);
+      }
+    }
+    DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
+  }
+
   /**
    * Trigger react context initialization asynchronously in a background async task. This enables
    * applications to pre-load the application JS, and execute global code before
diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
index 3450f883aa55..e6d356876096 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
@@ -55,11 +55,10 @@
  */
 public class ReactRootView extends SizeMonitoringFrameLayout implements RootView {
 
-  private final KeyboardListener mKeyboardListener = new KeyboardListener();
-
   private @Nullable ReactInstanceManager mReactInstanceManager;
   private @Nullable String mJSModuleName;
   private @Nullable Bundle mLaunchOptions;
+  private @Nullable KeyboardListener mKeyboardListener;
   private int mTargetTag = -1;
   private final float[] mTargetCoordinates = new float[2];
   private boolean mChildIsHandlingNativeGesture = false;
@@ -107,7 +106,7 @@ public void run() {
           Assertions.assertNotNull(mReactInstanceManager)
               .attachMeasuredRootView(ReactRootView.this);
           mIsAttachedToInstance = true;
-          getViewTreeObserver().addOnGlobalLayoutListener(mKeyboardListener);
+          getViewTreeObserver().addOnGlobalLayoutListener(getKeyboardListener());
         }
       });
     }
@@ -298,7 +297,7 @@ protected void onDetachedFromWindow() {
     if (mReactInstanceManager != null && !mAttachScheduled) {
       mReactInstanceManager.detachRootView(this);
       mIsAttachedToInstance = false;
-      getViewTreeObserver().removeOnGlobalLayoutListener(mKeyboardListener);
+      getViewTreeObserver().removeOnGlobalLayoutListener(getKeyboardListener());
     }
   }
 
@@ -356,7 +355,7 @@ public void startReactApplication(
     if (mWasMeasured && mIsAttachedToWindow) {
       mReactInstanceManager.attachMeasuredRootView(this);
       mIsAttachedToInstance = true;
-      getViewTreeObserver().addOnGlobalLayoutListener(mKeyboardListener);
+      getViewTreeObserver().addOnGlobalLayoutListener(getKeyboardListener());
     } else {
       mAttachScheduled = true;
     }
@@ -381,9 +380,21 @@ public void startReactApplication(
     mWasMeasured = true;
   }
 
+  private KeyboardListener getKeyboardListener() {
+    if (mKeyboardListener == null) {
+      mKeyboardListener = new KeyboardListener();
+    }
+    return mKeyboardListener;
+  }
+
   private class KeyboardListener implements ViewTreeObserver.OnGlobalLayoutListener {
+    private final Rect mVisibleViewArea;
+
     private int mKeyboardHeight = 0;
-    private final Rect mVisibleViewArea = new Rect();
+
+    /* package */ KeyboardListener() {
+      mVisibleViewArea = new Rect();
+    }
 
     @Override
     public void onGlobalLayout() {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
index 4aab528e5539..9742fc041c27 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
@@ -11,22 +11,10 @@
 
 import javax.annotation.Nullable;
 
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 
-import android.content.Context;
-import android.os.Build;
-import android.util.DisplayMetrics;
-import android.view.Display;
-import android.view.WindowManager;
-
-import com.facebook.csslayout.CSSLayoutContext;
-import com.facebook.infer.annotation.Assertions;
 import com.facebook.react.animation.Animation;
-import com.facebook.react.bridge.Arguments;
 import com.facebook.react.bridge.Callback;
 import com.facebook.react.bridge.LifecycleEventListener;
 import com.facebook.react.bridge.OnBatchCompleteListener;
@@ -35,7 +23,6 @@
 import com.facebook.react.bridge.ReactMethod;
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.bridge.ReadableMap;
-import com.facebook.react.bridge.WritableArray;
 import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
 import com.facebook.react.uimanager.events.EventDispatcher;
 import com.facebook.systrace.Systrace;
@@ -90,11 +77,7 @@ public UIManagerModule(
       UIImplementation uiImplementation) {
     super(reactContext);
     mEventDispatcher = new EventDispatcher(reactContext);
-
-    DisplayMetrics displayMetrics = getDisplayMetrics();
-
-    DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
-    mModuleConstants = createConstants(displayMetrics, viewManagerList);
+    mModuleConstants = createConstants(viewManagerList);
     mUIImplementation = uiImplementation;
 
     reactContext.addLifecycleEventListener(this);
@@ -131,14 +114,10 @@ public void onCatalystInstanceDestroy() {
     mEventDispatcher.onCatalystInstanceDestroyed();
   }
 
-  private static Map<String, Object> createConstants(
-      DisplayMetrics displayMetrics,
-      List<ViewManager> viewManagerList) {
+  private static Map<String, Object> createConstants(List<ViewManager> viewManagerList) {
     Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "CreateUIManagerConstants");
     try {
-      return UIManagerModuleConstantsHelper.createConstants(
-          displayMetrics,
-          viewManagerList);
+      return UIManagerModuleConstantsHelper.createConstants(viewManagerList);
     } finally {
       Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
     }
@@ -460,40 +439,4 @@ public EventDispatcher getEventDispatcher() {
   public void sendAccessibilityEvent(int tag, int eventType) {
     mUIImplementation.sendAccessibilityEvent(tag, eventType);
   }
-
-  private DisplayMetrics getDisplayMetrics() {
-    Context context = getReactApplicationContext();
-
-    DisplayMetrics displayMetrics = new DisplayMetrics();
-    displayMetrics.setTo(context.getResources().getDisplayMetrics());
-    WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-    Display display = wm.getDefaultDisplay();
-
-    // Get the real display metrics if we are using API level 17 or higher.
-    // The real metrics include system decor elements (e.g. soft menu bar).
-    //
-    // See: http://developer.android.com/reference/android/view/Display.html#getRealMetrics(android.util.DisplayMetrics)
-    if (Build.VERSION.SDK_INT >= 17){
-      display.getRealMetrics(displayMetrics);
-
-    } else {
-      // For 14 <= API level <= 16, we need to invoke getRawHeight and getRawWidth to get the real dimensions.
-      // Since react-native only supports API level 16+ we don't have to worry about other cases.
-      //
-      // Reflection exceptions are rethrown at runtime.
-      //
-      // See: http://stackoverflow.com/questions/14341041/how-to-get-real-screen-height-and-width/23861333#23861333
-      try {
-        Method mGetRawH = Display.class.getMethod("getRawHeight");
-        Method mGetRawW = Display.class.getMethod("getRawWidth");
-        displayMetrics.widthPixels = (Integer) mGetRawW.invoke(display);
-        displayMetrics.heightPixels = (Integer) mGetRawH.invoke(display);
-      } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
-        throw new RuntimeException("Error getting real dimensions for API level < 17", e);
-      }
-    }
-
-    return displayMetrics;
-  }
-
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java
index 476a2673bf21..8981d4354d2a 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java
@@ -12,7 +12,6 @@
 import java.util.HashMap;
 import java.util.Map;
 
-import android.text.InputType;
 import android.util.DisplayMetrics;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.ImageView;
@@ -80,7 +79,7 @@
         .build();
   }
 
-  public static Map<String, Object> getConstants(DisplayMetrics displayMetrics) {
+  public static Map<String, Object> getConstants() {
     HashMap<String, Object> constants = new HashMap<String, Object>();
     constants.put(
         "UIView",
@@ -92,6 +91,7 @@ public static Map<String, Object> getConstants(DisplayMetrics displayMetrics) {
                 "ScaleAspectFill",
                 ImageView.ScaleType.CENTER_CROP.ordinal())));
 
+    DisplayMetrics displayMetrics = DisplayMetricsHolder.getDisplayMetrics();
     constants.put(
         "Dimensions",
         MapBuilder.of(
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java
index bce7c37361b2..ffee1cea45d2 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java
@@ -9,12 +9,9 @@
 
 package com.facebook.react.uimanager;
 
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import android.util.DisplayMetrics;
-
 import com.facebook.react.common.MapBuilder;
 
 /**
@@ -39,10 +36,8 @@
    * {@link UIManagerModuleConstants}.
    * TODO(6845124): Create a test for this
    */
-  /* package */ static Map<String, Object> createConstants(
-      DisplayMetrics displayMetrics,
-      List<ViewManager> viewManagers) {
-    Map<String, Object> constants = UIManagerModuleConstants.getConstants(displayMetrics);
+  /* package */ static Map<String, Object> createConstants(List<ViewManager> viewManagers) {
+    Map<String, Object> constants = UIManagerModuleConstants.getConstants();
     Map bubblingEventTypesConstants = UIManagerModuleConstants.getBubblingEventTypeConstants();
     Map directEventTypesConstants = UIManagerModuleConstants.getDirectEventTypeConstants();
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
index f3473a05f678..6cbb5894e1c2 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
@@ -29,18 +29,17 @@
 import android.widget.TextView;
 
 import com.facebook.infer.annotation.Assertions;
-import com.facebook.react.bridge.JSApplicationCausedNativeException;
 import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.common.MapBuilder;
 import com.facebook.react.uimanager.BaseViewManager;
 import com.facebook.react.uimanager.PixelUtil;
-import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.ViewDefaults;
 import com.facebook.react.uimanager.ViewProps;
+import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.events.EventDispatcher;
 import com.facebook.react.views.text.DefaultStyleValuesUtil;
 import com.facebook.react.views.text.ReactTextUpdate;
diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropConstantsTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropConstantsTest.java
index 2f6eea4b7451..641e299920cb 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropConstantsTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropConstantsTest.java
@@ -13,6 +13,7 @@
 import java.util.List;
 import java.util.Map;
 
+import android.util.DisplayMetrics;
 import android.view.View;
 
 import com.facebook.react.bridge.ReactApplicationContext;
@@ -145,6 +146,8 @@ public void customIntGroupProp(View v, int index, Integer value) {
   public void testNativePropsIncludeCorrectTypes() {
     List<ViewManager> viewManagers = Arrays.<ViewManager>asList(new ViewManagerUnderTest());
     ReactApplicationContext reactContext = new ReactApplicationContext(RuntimeEnvironment.application);
+    DisplayMetrics displayMetrics = reactContext.getResources().getDisplayMetrics();
+    DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
     UIManagerModule uiManagerModule = new UIManagerModule(
         reactContext,
         viewManagers,
diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleConstantsTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleConstantsTest.java
index 5d757eb2ffdc..2652422e9834 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleConstantsTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleConstantsTest.java
@@ -13,6 +13,8 @@
 import java.util.List;
 import java.util.Map;
 
+import android.util.DisplayMetrics;
+
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.common.MapBuilder;
 
@@ -56,6 +58,9 @@ public class UIManagerModuleConstantsTest {
   public void setUp() {
     mReactContext = new ReactApplicationContext(RuntimeEnvironment.application);
     mUIImplementation = mock(UIImplementation.class);
+
+    DisplayMetrics displayMetrics = mReactContext.getResources().getDisplayMetrics();
+    DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
   }
 
   @Test
diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java
index 26db0858723c..6752ba062908 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java
@@ -14,6 +14,7 @@
 import java.util.List;
 
 import android.graphics.Color;
+import android.util.DisplayMetrics;
 import android.view.Choreographer;
 import android.view.View;
 import android.view.ViewGroup;
@@ -107,9 +108,13 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
     mReactContext = new ReactApplicationContext(RuntimeEnvironment.application);
     mReactContext.initializeWithInstance(mCatalystInstanceMock);
 
+    DisplayMetrics displayMetrics = mReactContext.getResources().getDisplayMetrics();
+    DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
+
     UIManagerModule uiManagerModuleMock = mock(UIManagerModule.class);
     when(mCatalystInstanceMock.getNativeModule(UIManagerModule.class))
         .thenReturn(uiManagerModuleMock);
+
   }
 
   @Test
diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java
index 890d0c0beee4..d710ffbd8718 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java
@@ -21,6 +21,7 @@
 import android.os.Build;
 import android.text.Spanned;
 import android.text.TextUtils;
+import android.util.DisplayMetrics;
 import android.text.style.AbsoluteSizeSpan;
 import android.view.Choreographer;
 import android.widget.TextView;
@@ -31,6 +32,7 @@
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.SimpleArray;
 import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.uimanager.DisplayMetricsHolder;
 import com.facebook.react.uimanager.ReactChoreographer;
 import com.facebook.react.uimanager.UIImplementation;
 import com.facebook.react.uimanager.UIManagerModule;
@@ -371,6 +373,8 @@ private void executePendingChoreographerCallbacks() {
 
   public UIManagerModule getUIManagerModule() {
     ReactApplicationContext reactContext = ReactTestHelper.createCatalystContextForTest();
+    DisplayMetrics displayMetrics = reactContext.getResources().getDisplayMetrics();
+    DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
     List<ViewManager> viewManagers = Arrays.asList(
         new ViewManager[] {
             new ReactTextViewManager(),
diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java
index 56d79f8bfae8..59871f217a12 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java
@@ -13,6 +13,7 @@
 import java.util.Arrays;
 import java.util.List;
 
+import android.util.DisplayMetrics;
 import android.view.Choreographer;
 import android.widget.EditText;
 
@@ -22,6 +23,7 @@
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.SimpleArray;
 import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.uimanager.DisplayMetricsHolder;
 import com.facebook.react.uimanager.ReactChoreographer;
 import com.facebook.react.uimanager.UIImplementation;
 import com.facebook.react.uimanager.UIManagerModule;
@@ -181,6 +183,8 @@ public UIManagerModule getUIManagerModule() {
         new ViewManager[] {
             new ReactTextInputManager(),
         });
+    DisplayMetrics displayMetrics = reactContext.getResources().getDisplayMetrics();
+    DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
     UIManagerModule uiManagerModule = new UIManagerModule(
         reactContext,
         viewManagers,

From 5a109ae43bec251abca49a91fbd41c37e166ebbd Mon Sep 17 00:00:00 2001
From: Andrei Coman <andreic@fb.com>
Date: Mon, 8 Feb 2016 11:45:32 -0800
Subject: [PATCH 1078/1411] Make keyboard detection more robust

Reviewed By: nspaun

Differential Revision: D2905647

fb-gh-sync-id: 0bd5405f32a5e63c9f85178b4d1f777fe032f8d5
---
 .../main/java/com/facebook/react/ReactRootView.java    | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
index e6d356876096..2271b20fd46a 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
@@ -389,11 +389,13 @@ private KeyboardListener getKeyboardListener() {
 
   private class KeyboardListener implements ViewTreeObserver.OnGlobalLayoutListener {
     private final Rect mVisibleViewArea;
-
+    private final int mMinKeyboardHeightDetected;
+    
     private int mKeyboardHeight = 0;
 
     /* package */ KeyboardListener() {
       mVisibleViewArea = new Rect();
+      mMinKeyboardHeightDetected = (int) PixelUtil.toPixelFromDIP(60);
     }
 
     @Override
@@ -409,7 +411,7 @@ public void onGlobalLayout() {
       getRootView().getWindowVisibleDisplayFrame(mVisibleViewArea);
       final int heightDiff =
           DisplayMetricsHolder.getDisplayMetrics().heightPixels - mVisibleViewArea.bottom;
-      if (mKeyboardHeight != heightDiff && heightDiff > 0) {
+      if (mKeyboardHeight != heightDiff && heightDiff > mMinKeyboardHeightDetected) {
         // keyboard is now showing, or the keyboard height has changed
         mKeyboardHeight = heightDiff;
         WritableMap params = Arguments.createMap();
@@ -420,9 +422,9 @@ public void onGlobalLayout() {
         coordinates.putDouble("height", PixelUtil.toDIPFromPixel(mKeyboardHeight));
         params.putMap("endCoordinates", coordinates);
         sendEvent("keyboardDidShow", params);
-      } else if (mKeyboardHeight != 0 && heightDiff == 0) {
+      } else if (mKeyboardHeight != 0 && heightDiff <= mMinKeyboardHeightDetected) {
         // keyboard is now hidden
-        mKeyboardHeight = heightDiff;
+        mKeyboardHeight = 0;
         sendEvent("keyboardDidHide", null);
       }
     }

From 194092e7290c2a2e50e0263bac67686df418b915 Mon Sep 17 00:00:00 2001
From: Adam Miskiewicz <adam@sk3vy.com>
Date: Mon, 8 Feb 2016 15:00:42 -0800
Subject: [PATCH 1079/1411] Adding 'transform-symbol-member' transform to
 preset.

Summary:
Turns out, even after discussion that was had in https://github.com/facebook/react-native/pull/5294#issuecomment-174397103, we really do need this transform.

I've just included it in the preset...let me know if you all would rather publish to npm.

The actual reason why this is necessary is because in the latest sync from FB, fbjs was updated to use the `Symbol.iterator` express in it's isEmpty function: https://github.com/facebook/fbjs/commit/064a484e18b03f988f9eb540255ef8d742301c8d

We use this in RN in the ListView...and this change (once #5084 is merged) will cause ListView to break on older JSC context's.

This resolves that, and is probably something we should have had all along.
Closes https://github.com/facebook/react-native/pull/5824

Reviewed By: svcscm

Differential Revision: D2913315

Pulled By: vjeux

fb-gh-sync-id: abaf484a9431b3111e8118d01db8d2c0d2dd73ca
shipit-source-id: abaf484a9431b3111e8118d01db8d2c0d2dd73ca
---
 babel-preset/configs/main.js                  |  1 +
 babel-preset/package.json                     |  2 +-
 .../transforms/transform-symbol-member.js     | 61 +++++++++++++++++++
 3 files changed, 63 insertions(+), 1 deletion(-)
 create mode 100644 babel-preset/transforms/transform-symbol-member.js

diff --git a/babel-preset/configs/main.js b/babel-preset/configs/main.js
index 204028fbb130..3322812bd07c 100644
--- a/babel-preset/configs/main.js
+++ b/babel-preset/configs/main.js
@@ -36,6 +36,7 @@ module.exports = {
     'transform-react-jsx',
     'transform-regenerator',
     ['transform-es2015-for-of', { loose: true }],
+    require('../transforms/transform-symbol-member'),
   ]),
   retainLines: true,
   sourceMaps: false,
diff --git a/babel-preset/package.json b/babel-preset/package.json
index b442ab23cc85..0ab0579b1532 100644
--- a/babel-preset/package.json
+++ b/babel-preset/package.json
@@ -1,6 +1,6 @@
 {
   "name": "babel-preset-react-native",
-  "version": "1.2.4",
+  "version": "1.4.0",
   "description": "Babel preset for React Native applications",
   "main": "index.js",
   "repository": "https://github.com/facebook/react-native/tree/master/babel-preset",
diff --git a/babel-preset/transforms/transform-symbol-member.js b/babel-preset/transforms/transform-symbol-member.js
new file mode 100644
index 000000000000..305eb3c2dbce
--- /dev/null
+++ b/babel-preset/transforms/transform-symbol-member.js
@@ -0,0 +1,61 @@
+/**
+ * Copyright 2004-present Facebook. All Rights Reserved.
+ */
+
+'use strict';
+
+/*eslint consistent-return: 0*/
+
+/**
+ * Transforms function properties of the `Symbol` into
+ * the presence check, and fallback string "@@<name>".
+ *
+ * Example:
+ *
+ *   Symbol.iterator;
+ *
+ * Transformed to:
+ *
+ *   typeof Symbol.iterator === 'function' ? Symbol.iterator : '@@iterator';
+ */
+module.exports = function symbolMember(babel) {
+  const t = babel.types;
+
+  return {
+    visitor: {
+      MemberExpression(path) {
+        let node = path.node;
+
+        if (!isAppropriateMember(node)) {
+          return;
+        }
+
+        path.replaceWith(
+          t.conditionalExpression(
+            t.binaryExpression(
+              '===',
+              t.unaryExpression(
+                'typeof',
+                t.identifier('Symbol'),
+                true
+              ),
+              t.stringLiteral('function')
+            ),
+            node,
+            t.stringLiteral(`@@${node.property.name}`)
+          )
+        );
+
+        // We should stop to avoid infinite recursion, since Babel
+        // traverses replaced path, and again would hit our transform.
+        path.stop();
+      },
+    },
+  };
+};
+
+function isAppropriateMember(node) {
+  return node.object.type === 'Identifier' &&
+    node.object.name === 'Symbol' &&
+    node.property.type === 'Identifier';
+}

From 843b5567698327525015326e87bcaaa5cfbe807f Mon Sep 17 00:00:00 2001
From: Renyu Liu <lry@fb.com>
Date: Mon, 8 Feb 2016 15:05:41 -0800
Subject: [PATCH 1080/1411] Fix the perspective projection

Reviewed By: kukulski

Differential Revision: D2907261

fb-gh-sync-id: 3954b015ece9c4339a674c4fcc2c2c7187b6da41
shipit-source-id: 3954b015ece9c4339a674c4fcc2c2c7187b6da41
---
 Libraries/Utilities/MatrixMath.js | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/Libraries/Utilities/MatrixMath.js b/Libraries/Utilities/MatrixMath.js
index addc8660ef47..32f3cd32f4de 100755
--- a/Libraries/Utilities/MatrixMath.js
+++ b/Libraries/Utilities/MatrixMath.js
@@ -67,8 +67,14 @@ var MatrixMath = {
     ];
   },
 
+  /**
+   * This create a perspective projection towards negative z
+   * Clipping the z range of [-near, -far]
+   *
+   * @param fovInRadians - field of view in randians
+   */
   createPerspective: function(fovInRadians, aspect, near, far) {
-    var h = 1 / Math.tan(fovInRadians);
+    var h = 1 / Math.tan(fovInRadians / 2);
     var r_depth  = 1 / (near - far);
     var C = (far + near) * r_depth;
     var D = 2 * (far * near * r_depth);

From abdca047b0d3a1f9627a485c15fad0b99c5c241e Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Mon, 8 Feb 2016 15:24:23 -0800
Subject: [PATCH 1081/1411] Add a note about Android Studio to docs, fix
 formatting

Summary:
We should use 4 spaces of indentation in the MainActivity template as this
is the most common setting outside fb.

public

Reviewed By: bestander

Differential Revision: D2911952

fb-gh-sync-id: 3b5285945f0033d7342348b7a7cbafa32809f7dc
shipit-source-id: 3b5285945f0033d7342348b7a7cbafa32809f7dc
---
 docs/DevelopmentSetupAndroid.md                    |  8 ++++++--
 .../templates/package/MainActivity.java            | 14 +++++++-------
 2 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/docs/DevelopmentSetupAndroid.md b/docs/DevelopmentSetupAndroid.md
index 4b0b8fe93ad6..eab90e85a875 100644
--- a/docs/DevelopmentSetupAndroid.md
+++ b/docs/DevelopmentSetupAndroid.md
@@ -7,7 +7,7 @@ permalink: docs/android-setup.html
 next: linux-windows-support
 ---
 
-This guide describes basic steps of the Android development environment setup that are required to run React Native android apps on an android emulator. We don't discuss developer tool configuration such as IDEs here.
+This guide describes basic steps of the Android development environment setup that are required to run React Native android apps on an android emulator.
 
 ### Install Git
 
@@ -19,7 +19,7 @@ This guide describes basic steps of the Android development environment setup th
 
   - **On Windows**, download and install [Git for Windows](https://git-for-windows.github.io/). During the setup process, choose "Run Git from Windows Command Prompt", which will add Git to your `PATH` environment variable.
 
-### Install the Android SDK (unless you have it)
+### Install the Android SDK (unless you already have it)
 
 1. [Install the latest JDK](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
 2. Install the Android SDK:
@@ -95,3 +95,7 @@ To use it with react-native you just have to add a key and value to your registr
 You will also need to run the command `adb reverse tcp:8081 tcp:8081` with this emulator.
 
 Then restart the emulator and when it runs you can just do `react-native run-android` as usual.
+
+### Editing your app's Java code in Android Studio
+
+You can use any editor to edit JavaScript. If you want to use Android Studio to work on native code, from the Welcome screen of Android Studio choose "Import project" and select the `android` folder of your app.
diff --git a/local-cli/generator-android/templates/package/MainActivity.java b/local-cli/generator-android/templates/package/MainActivity.java
index 6d5cb73f3021..552a4d2a59de 100644
--- a/local-cli/generator-android/templates/package/MainActivity.java
+++ b/local-cli/generator-android/templates/package/MainActivity.java
@@ -27,14 +27,14 @@ protected boolean getUseDeveloperSupport() {
         return BuildConfig.DEBUG;
     }
 
-   /**
-   * A list of packages used by the app. If the app uses additional views
-   * or modules besides the default ones, add more packages here.
-   */
+    /**
+    * A list of packages used by the app. If the app uses additional views
+    * or modules besides the default ones, add more packages here.
+    */
     @Override
     protected List<ReactPackage> getPackages() {
-      return Arrays.<ReactPackage>asList(
-        new MainReactPackage()
-      );
+        return Arrays.<ReactPackage>asList(
+            new MainReactPackage()
+        );
     }
 }

From 05e4236b806ffd2fec96c24c94f006b445a39db3 Mon Sep 17 00:00:00 2001
From: chirag04 <jain_chirag04@yahoo.com>
Date: Mon, 8 Feb 2016 15:40:54 -0800
Subject: [PATCH 1082/1411] document date and timer picker android

Summary: Closes https://github.com/facebook/react-native/pull/5826

Reviewed By: svcscm

Differential Revision: D2913829

Pulled By: vjeux

fb-gh-sync-id: a4adeb6ba402bbd0ff3cea00429e79c140b965dd
shipit-source-id: a4adeb6ba402bbd0ff3cea00429e79c140b965dd
---
 website/server/extractDocs.js | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/website/server/extractDocs.js b/website/server/extractDocs.js
index 26c4eb7525c1..48e4dfb6b8db 100644
--- a/website/server/extractDocs.js
+++ b/website/server/extractDocs.js
@@ -250,6 +250,8 @@ var apis = [
   '../Libraries/StyleSheet/StyleSheet.js',
   '../Libraries/Components/ToastAndroid/ToastAndroid.android.js',
   '../Libraries/Vibration/VibrationIOS.ios.js',
+  '../Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js',
+  '../Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js',
 ];
 
 var stylesWithPermalink = [

From 7b57b5c84aba58abb48526b581ee1d6d40a5f4be Mon Sep 17 00:00:00 2001
From: Hedger Wang <hedger@fb.com>
Date: Mon, 8 Feb 2016 19:51:06 -0800
Subject: [PATCH 1083/1411] re-render the whole navigation bar while calling
 immediatelyResetRouteStack

Summary:
public

Navigator expects that the navigation bar implements the method to refresh itself.
NavigatorNavigationBar already has this method but not for NavigatorBreadcrumbNavigationBar.

Fix diff fixes this with the same fix as D2751922 did.

Reviewed By: wenjingw

Differential Revision: D2914475

fb-gh-sync-id: a2960bad5df3b403bdd2ab1dc4d349d7251b86c8
shipit-source-id: a2960bad5df3b403bdd2ab1dc4d349d7251b86c8
---
 .../NavigatorBreadcrumbNavigationBar.js       | 25 ++++++++++++++-----
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js b/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js
index 84a1e43cde1b..e224253c21be 100644
--- a/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js
+++ b/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js
@@ -36,6 +36,7 @@ var View = require('View');
 
 var { Map } = require('immutable');
 
+var guid = require('guid');
 var invariant = require('invariant');
 
 var Interpolators = NavigatorBreadcrumbNavigationBarStyles.Interpolators;
@@ -179,11 +180,7 @@ var NavigatorBreadcrumbNavigationBar = React.createClass({
   },
 
   componentWillMount: function() {
-    this._descriptors = {
-      crumb: new Map(),
-      title: new Map(),
-      right: new Map(),
-    };
+    this._reset();
   },
 
   render: function() {
@@ -192,7 +189,9 @@ var NavigatorBreadcrumbNavigationBar = React.createClass({
     var titles = navState.routeStack.map(this._getTitle);
     var buttons = navState.routeStack.map(this._getRightButton);
     return (
-      <View style={[styles.breadCrumbContainer, this.props.style]}>
+      <View
+        key={this._key}
+        style={[styles.breadCrumbContainer, this.props.style]}>
         {titles}
         {icons}
         {buttons}
@@ -200,6 +199,20 @@ var NavigatorBreadcrumbNavigationBar = React.createClass({
     );
   },
 
+  immediatelyRefresh: function() {
+    this._reset();
+    this.forceUpdate();
+  },
+
+  _reset() {
+    this._key = guid();
+    this._descriptors = {
+      crumb: new Map(),
+      title: new Map(),
+      right: new Map(),
+    };
+  },
+
   _getBreadcrumb: function(route, index) {
     if (this._descriptors.crumb.has(route)) {
       return this._descriptors.crumb.get(route);

From 7b2b0c3c1c7a541782e730b8c237ae2f2101e226 Mon Sep 17 00:00:00 2001
From: Eric Vicenti <evv@fb.com>
Date: Mon, 8 Feb 2016 20:02:45 -0800
Subject: [PATCH 1084/1411] Navigation Back support and examples for Android

Summary:
public
- Intro new back action
- Add support in the two main reducers
- Use it in examples to support Android back button
- Disable NavigationCard gestures on Android

Reviewed By: hedgerwang

Differential Revision: D2914154

fb-gh-sync-id: d4dce6538e19613a2ffca21e2e3b2ecaded3d5dc
shipit-source-id: d4dce6538e19613a2ffca21e2e3b2ecaded3d5dc
---
 .../NavigationAnimatedExample.js              |  7 +++
 .../NavigationBasicExample.js                 |  9 +++
 .../NavigationCompositionExample.js           | 55 +++++++++++--------
 .../NavigationExperimentalExample.js          | 25 ++++++++-
 .../NavigationTabsExample.js                  | 15 +++--
 Examples/UIExplorer/UIExplorerApp.android.js  | 11 +++-
 Examples/UIExplorer/UIExplorerList.android.js |  1 +
 .../NavigationExperimental/NavigationCard.js  | 13 ++++-
 .../NavigationRootContainer.js                | 26 +++++++--
 .../NavigationExperimental/NavigationState.js |  9 ++-
 .../Reducer/NavigationFindReducer.js          |  2 +-
 .../Reducer/NavigationStackReducer.js         |  7 ++-
 .../Reducer/NavigationTabsReducer.js          | 31 ++++++-----
 13 files changed, 157 insertions(+), 54 deletions(-)

diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
index 2139397908a5..e9f85ed1cb68 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
@@ -44,11 +44,18 @@ class NavigationAnimatedExample extends React.Component {
     return (
       <NavigationRootContainer
         reducer={NavigationBasicReducer}
+        ref={navRootContainer => { this.navRootContainer = navRootContainer; }}
         persistenceKey="NavigationAnimatedExampleState"
         renderNavigation={this._renderNavigated}
       />
     );
   }
+  handleBackAction() {
+    return (
+      this.navRootContainer &&
+      this.navRootContainer.handleNavigation(NavigationRootContainer.getBackAction())
+    );
+  }
   _renderNavigated(navigationState, onNavigate) {
     if (!navigationState) {
       return null;
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationBasicExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationBasicExample.js
index 21f03eb63889..8f8669fb4c23 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationBasicExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationBasicExample.js
@@ -40,6 +40,7 @@ const NavigationBasicExample = React.createClass({
       <NavigationRootContainer
         reducer={NavigationBasicReducer}
         persistenceKey="NavigationBasicExampleState"
+        ref={navRootContainer => { this.navRootContainer = navRootContainer; }}
         renderNavigation={(navState, onNavigate) => {
           if (!navState) { return null; }
           return (
@@ -69,6 +70,14 @@ const NavigationBasicExample = React.createClass({
       />
     );
   },
+
+  handleBackAction: function() {
+    return (
+      this.navRootContainer &&
+      this.navRootContainer.handleNavigation(NavigationRootContainer.getBackAction())
+    );
+  },
+
 });
 
 const styles = StyleSheet.create({
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js
index 1af4c63bbeb4..ee8472242c4a 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js
@@ -135,18 +135,18 @@ function stateTypeTitleMap(pageState) {
   }
 }
 
-let ExampleTabScreen = React.createClass({
-  render: function() {
+class ExampleTabScreen extends React.Component {
+  render() {
     return (
       <NavigationAnimatedView
         style={styles.tabContent}
         navigationState={this.props.navigationState}
-        renderOverlay={this._renderHeader}
-        renderScene={this._renderScene}
+        renderOverlay={this._renderHeader.bind(this)}
+        renderScene={this._renderScene.bind(this)}
       />
     );
-  },
-  _renderHeader: function(position, layout) {
+  }
+  _renderHeader(position, layout) {
     return (
       <NavigationHeader
         navigationState={this.props.navigationState}
@@ -155,8 +155,8 @@ let ExampleTabScreen = React.createClass({
         getTitle={state => stateTypeTitleMap(state)}
       />
     );
-  },
-  _renderScene: function(child, index, position, layout) {
+  }
+  _renderScene(child, index, position, layout) {
     return (
       <NavigationCard
         key={child.key}
@@ -187,21 +187,28 @@ let ExampleTabScreen = React.createClass({
         </ScrollView>
       </NavigationCard>
     );
-  },
-});
+  }
+}
 ExampleTabScreen = NavigationContainer.create(ExampleTabScreen);
 
-const NavigationCompositionExample = React.createClass({
-  render: function() {
+class NavigationCompositionExample extends React.Component {
+  render() {
     return (
       <NavigationRootContainer
         reducer={ExampleAppReducer}
         persistenceKey="NavigationCompositionExampleState"
-        renderNavigation={this.renderApp}
+        ref={navRootContainer => { this.navRootContainer = navRootContainer; }}
+        renderNavigation={this.renderApp.bind(this)}
       />
     );
-  },
-  renderApp: function(navigationState, onNavigate) {
+  }
+  handleBackAction() {
+    return (
+      this.navRootContainer &&
+      this.navRootContainer.handleNavigation(NavigationRootContainer.getBackAction())
+    );
+  }
+  renderApp(navigationState, onNavigate) {
     if (!navigationState) {
       return null;
     }
@@ -217,11 +224,11 @@ const NavigationCompositionExample = React.createClass({
         />
       </View>
     );
-  },
-});
+  }
+}
 
-let ExampleMainView = React.createClass({
-  render: function() {
+class ExampleMainView extends React.Component {
+  render() {
     return (
       <NavigationView
         navigationState={this.props.navigationState}
@@ -230,20 +237,20 @@ let ExampleMainView = React.createClass({
           <ExampleTabScreen
             key={tabState.key}
             navigationState={tabState}
-            onNavigate={this._handleNavigation.bind(null, tabState.key)}
+            onNavigate={this._handleNavigation.bind(this, tabState.key)}
           />
         )}
       />
     );
-  },
-  _handleNavigation: function(tabKey, action) {
+  }
+  _handleNavigation(tabKey, action) {
     if (ExampleExitAction.match(action)) {
       this.props.onExampleExit();
       return;
     }
     this.props.onNavigate(action);
-  },
-});
+  }
+}
 ExampleMainView = NavigationContainer.create(ExampleMainView);
 
 const styles = StyleSheet.create({
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js
index 0d11a8e649fc..4aade5303c17 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js
@@ -25,7 +25,7 @@ var NavigationExampleRow = require('./NavigationExampleRow');
 /*
  * Heads up! This file is not the real navigation example- only a utility to switch between them.
  *
- * To learn how to use the Navigation API, take a look at the following exmample files:
+ * To learn how to use the Navigation API, take a look at the following example files:
  */
 var EXAMPLES = {
   'Tabs': require('./NavigationTabsExample'),
@@ -106,13 +106,34 @@ var NavigationExperimentalExample = React.createClass({
     this.setExample('menu');
   },
 
+  handleBackAction: function() {
+    const wasHandledByExample = (
+      this.exampleRef &&
+      this.exampleRef.handleBackAction &&
+      this.exampleRef.handleBackAction()
+    );
+    if (wasHandledByExample) {
+      return true;
+    }
+    if (this.state.example && this.state.example !== 'menu') {
+      this._exitInnerExample();
+      return true;
+    }
+    return false;
+  },
+
   render: function() {
     if (this.state.example === 'menu') {
       return this._renderMenu();
     }
     if (EXAMPLES[this.state.example]) {
       var Component = EXAMPLES[this.state.example];
-      return <Component onExampleExit={this._exitInnerExample} />;
+      return (
+        <Component
+          onExampleExit={this._exitInnerExample}
+          ref={exampleRef => { this.exampleRef = exampleRef; }}
+        />
+      );
     }
     return null;
   },
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationTabsExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationTabsExample.js
index beb3a6e35af3..ae4de59a6da8 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationTabsExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationTabsExample.js
@@ -64,12 +64,13 @@ const ExampleTabsReducer = NavigationReducer.TabsReducer({
   ],
 });
 
-const NavigationTabsExample = React.createClass({
-  render: function() {
+class NavigationTabsExample extends React.Component {
+  render() {
     return (
       <NavigationRootContainer
         reducer={ExampleTabsReducer}
         persistenceKey="NAV_EXAMPLE_STATE_TABS"
+        ref={navRootContainer => { this.navRootContainer = navRootContainer; }}
         renderNavigation={(navigationState) => {
           if (!navigationState) { return null; }
           return (
@@ -88,8 +89,14 @@ const NavigationTabsExample = React.createClass({
         }}
       />
     );
-  },
-});
+  }
+  handleBackAction() {
+    return (
+      this.navRootContainer &&
+      this.navRootContainer.handleNavigation(NavigationRootContainer.getBackAction())
+    );
+  }
+}
 
 const styles = StyleSheet.create({
   topView: {
diff --git a/Examples/UIExplorer/UIExplorerApp.android.js b/Examples/UIExplorer/UIExplorerApp.android.js
index 25a4745bf115..cdf92c6848de 100644
--- a/Examples/UIExplorer/UIExplorerApp.android.js
+++ b/Examples/UIExplorer/UIExplorerApp.android.js
@@ -109,12 +109,21 @@ var UIExplorerApp = React.createClass({
           style={styles.toolbar}
           title={this.state.example.title}
         />
-        <Component />
+        <Component
+          ref={(example) => { this._exampleRef = example; }}
+        />
       </View>
     );
   },
 
   _handleBackButtonPress: function() {
+    if (
+      this._exampleRef &&
+      this._exampleRef.handleBackAction &&
+      this._exampleRef.handleBackAction()
+    ) {
+      return true;
+    }
     if (this.state.example.title !== this._getUIExplorerHome().title) {
       this.onSelectExample(this._getUIExplorerHome());
       return true;
diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index ed84e62aad11..8959a0919f9a 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -54,6 +54,7 @@ var APIS = [
   require('./IntentAndroidExample.android'),
   require('./LayoutEventsExample'),
   require('./LayoutExample'),
+  require('./NavigationExperimental/NavigationExperimentalExample'),
   require('./NetInfoExample'),
   require('./PanResponderExample'),
   require('./PointerEventsExample'),
diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationCard.js b/Libraries/CustomComponents/NavigationExperimental/NavigationCard.js
index d25c45aefdec..096e99d1c3ea 100644
--- a/Libraries/CustomComponents/NavigationExperimental/NavigationCard.js
+++ b/Libraries/CustomComponents/NavigationExperimental/NavigationCard.js
@@ -31,10 +31,13 @@ const Animated = require('Animated');
 const NavigationReducer = require('NavigationReducer');
 const NavigationContainer = require('NavigationContainer');
 const PanResponder = require('PanResponder');
+const Platform = require('Platform');
 const React = require('React');
 const StyleSheet = require('StyleSheet');
 const View = require('View');
 
+const ENABLE_GESTURES = Platform.OS !== 'android';
+
 import type {
   NavigationParentState
 } from 'NavigationState';
@@ -62,7 +65,12 @@ class NavigationCard extends React.Component {
   _widthListener: string;
   _heightListener: string;
   props: Props;
-  componentWillMount(props) {
+  componentWillMount() {
+    if (ENABLE_GESTURES) {
+      this._enableGestures();
+    }
+  }
+  _enableGestures() {
     this._responder = PanResponder.create({
       onMoveShouldSetPanResponder: (e, {dx, dy, moveX, moveY, x0, y0}) => {
         if (this.props.navigationState.index === 0) {
@@ -119,9 +127,10 @@ class NavigationCard extends React.Component {
   render() {
     const cardPosition = Animated.add(this.props.position, new Animated.Value(-this.props.index));
     const gestureValue = Animated.multiply(cardPosition, this.props.layout.width);
+    const touchResponderHandlers = this._responder ? this._responder.panHandlers : null;
     return (
       <Animated.View
-        {...this._responder.panHandlers}
+        {...touchResponderHandlers}
         style={[
           styles.card,
           {
diff --git a/Libraries/NavigationExperimental/NavigationRootContainer.js b/Libraries/NavigationExperimental/NavigationRootContainer.js
index a9beeba62741..b40c3114fdd3 100644
--- a/Libraries/NavigationExperimental/NavigationRootContainer.js
+++ b/Libraries/NavigationExperimental/NavigationRootContainer.js
@@ -11,19 +11,29 @@
  */
 'use strict';
 
-var AsyncStorage = require('AsyncStorage');
-var React = require('React');
+const AsyncStorage = require('AsyncStorage');
+const React = require('React');
+const BackAndroid = require('BackAndroid');
+const Platform = require('Platform');
 
 import type {
   NavigationState,
   NavigationReducer
 } from 'NavigationState';
 
-type NavigationRenderer = (
+export type NavigationRenderer = (
   navigationState: NavigationState,
   onNavigate: Function
 ) => ReactElement;
 
+export type BackAction = {
+  type: 'BackAction';
+};
+
+function getBackAction(): BackAction {
+  return { type: 'BackAction' };
+}
+
 type Props = {
   renderNavigation: NavigationRenderer;
   reducer: NavigationReducer;
@@ -61,17 +71,21 @@ class NavigationRootContainer extends React.Component {
       onNavigate: this.handleNavigation,
     };
   }
-  handleNavigation(action: Object) {
+  handleNavigation(action: Object): boolean {
     const navState = this.props.reducer(this.state.navState, action);
+    if (navState === this.state.navState) {
+      return false;
+    }
     this.setState({
       navState,
     });
     if (this.props.persistenceKey) {
       AsyncStorage.setItem(this.props.persistenceKey, JSON.stringify(navState));
     }
+    return true;
   }
   render(): ReactElement {
-    var navigation = this.props.renderNavigation(
+    const navigation = this.props.renderNavigation(
       this.state.navState,
       this.handleNavigation
     );
@@ -83,4 +97,6 @@ NavigationRootContainer.childContextTypes = {
   onNavigate: React.PropTypes.func,
 };
 
+NavigationRootContainer.getBackAction = getBackAction;
+
 module.exports = NavigationRootContainer;
diff --git a/Libraries/NavigationExperimental/NavigationState.js b/Libraries/NavigationExperimental/NavigationState.js
index 8ef085fd9b2a..d78d3559177c 100644
--- a/Libraries/NavigationExperimental/NavigationState.js
+++ b/Libraries/NavigationExperimental/NavigationState.js
@@ -23,9 +23,13 @@ export type NavigationParentState = {
   children: Array<NavigationState>;
 };
 
+export type NavigationAction = {
+  type: string;
+};
+
 export type NavigationReducer = (
   state: ?NavigationState,
-  action: ?any
+  action: ?NavigationAction
 ) => ?NavigationState;
 
 export type NavigationReducerWithDefault = (
@@ -142,6 +146,9 @@ export function set(state: ?NavigationState, key: string, nextChildren: Array<Na
 
 export function jumpToIndex(state: NavigationState, index: number): NavigationState {
   const parentState = getParent(state);
+  if (parentState && parentState.index === index) {
+    return parentState;
+  }
   return {
     ...parentState,
     index,
diff --git a/Libraries/NavigationExperimental/Reducer/NavigationFindReducer.js b/Libraries/NavigationExperimental/Reducer/NavigationFindReducer.js
index db8bb8f40071..f0947fd56645 100644
--- a/Libraries/NavigationExperimental/Reducer/NavigationFindReducer.js
+++ b/Libraries/NavigationExperimental/Reducer/NavigationFindReducer.js
@@ -22,7 +22,7 @@ import type {
   NavigationReducer
 } from 'NavigationState';
 
-function NavigationFindReducer(reducers: Array<NavigationReducer>): ?NavigationReducer {
+function NavigationFindReducer(reducers: Array<NavigationReducer>): NavigationReducer {
   return function(lastState: ?NavigationState, action: ?any): ?NavigationState {
     for (let i = 0; i < reducers.length; i++) {
       let reducer = reducers[i];
diff --git a/Libraries/NavigationExperimental/Reducer/NavigationStackReducer.js b/Libraries/NavigationExperimental/Reducer/NavigationStackReducer.js
index 7aec5f4ee4cd..5dcf34966daf 100644
--- a/Libraries/NavigationExperimental/Reducer/NavigationStackReducer.js
+++ b/Libraries/NavigationExperimental/Reducer/NavigationStackReducer.js
@@ -18,7 +18,11 @@ import type {
   NavigationReducer,
 } from 'NavigationState';
 
-export type NavigationStackReducerAction = {
+import type {
+  BackAction,
+} from 'NavigationRootContainer';
+
+export type NavigationStackReducerAction = BackAction | {
   type: string,
 };
 
@@ -101,6 +105,7 @@ function NavigationStackReducer({initialStates, initialIndex, key, matchAction,
           action.state
         );
       case ActionTypes.POP:
+      case 'BackAction':
         if (lastParentState.index === 0 || lastParentState.children.length === 1) {
           return lastParentState;
         }
diff --git a/Libraries/NavigationExperimental/Reducer/NavigationTabsReducer.js b/Libraries/NavigationExperimental/Reducer/NavigationTabsReducer.js
index 6d31164f0cac..9d6d76a4ff22 100644
--- a/Libraries/NavigationExperimental/Reducer/NavigationTabsReducer.js
+++ b/Libraries/NavigationExperimental/Reducer/NavigationTabsReducer.js
@@ -17,7 +17,8 @@ const NavigationStateUtils = require('NavigationState');
 import type {
   NavigationReducer,
   NavigationReducerWithDefault,
-  NavigationState
+  NavigationState,
+  NavigationParentState
 } from 'NavigationState';
 
 const ActionTypes = {
@@ -106,17 +107,15 @@ function NavigationTabsReducer({key, initialIndex, tabReducers}: TabsReducerConf
       }
     }
     const subReducers = tabReducers.map((tabReducer, tabIndex) => {
-      return function reduceTab(lastTabState: ?NavigationState, tabAction: ?any): ?NavigationState {
-        if (!lastTabState) {
-          return tabReducer(lastTabState, tabAction);
+      return function reduceTab(lastNavState: ?NavigationState, tabAction: ?any): ?NavigationState {
+        if (!tabReducer || !lastNavState) {
+          return lastNavState;
         }
-        if (!lastParentNavState) {
-          return lastTabState;
-        }
-        const lastSubTabState = lastParentNavState.children[tabIndex];
+        const lastParentNavState = NavigationStateUtils.getParent(lastNavState);
+        const lastSubTabState = lastParentNavState && lastParentNavState.children[tabIndex];
         const nextSubTabState = tabReducer(lastSubTabState, tabAction);
         if (nextSubTabState && lastSubTabState !== nextSubTabState) {
-          const tabs = lastParentNavState.children;
+          const tabs = lastParentNavState && lastParentNavState.children || [];
           tabs[tabIndex] = nextSubTabState;
           return {
             ...lastParentNavState,
@@ -129,11 +128,17 @@ function NavigationTabsReducer({key, initialIndex, tabReducers}: TabsReducerConf
     });
     let selectedTabReducer = subReducers.splice(lastParentNavState.index, 1)[0];
     subReducers.unshift(selectedTabReducer);
+    subReducers.push((lastParentNavState: ?NavigationState, action: ?any) => {
+      if (lastParentNavState && action && action.type === 'BackAction') {
+        return NavigationStateUtils.jumpToIndex(
+          lastParentNavState,
+          0
+        );
+      }
+      return lastParentNavState;
+    });
     const findReducer = NavigationFindReducer(subReducers);
-    if (findReducer) {
-      return findReducer(lastParentNavState, action);
-    }
-    return lastParentNavState;
+    return findReducer(lastParentNavState, action);
   };
 }
 

From 855d411321119e79f899c7420a5a435506fb6cbf Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Tue, 9 Feb 2016 03:29:18 -0800
Subject: [PATCH 1085/1411] Moved constants export to bridge init

Summary:
public
Lazy export of module constants required a sync dispatch to the main thread, which was deadlocking in some of our projects.

This moves the constants export to the initial bridge init, which may slightly increase initial startup time, but avoids the deadlock.

Reviewed By: javache

Differential Revision: D2911295

fb-gh-sync-id: 0d14a629ac4fc7ee21acd293c09595c18232659b
shipit-source-id: 0d14a629ac4fc7ee21acd293c09595c18232659b
---
 React/Base/RCTBatchedBridge.m |  7 ++++---
 React/Base/RCTModuleData.m    | 15 ++++++++-------
 2 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index 6ca0fad9cdee..debc00d9a026 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -282,10 +282,11 @@ - (void)initModules
     id module = preregisteredModules[moduleName];
     if (!module) {
       // Check if the module class, or any of its superclasses override init
-      // or setBridge:. If they do, we assume that they are expecting to be
-      // initialized when the bridge first loads.
+      // or setBridge:, or has exported constants. If they do, we assume that
+      // they are expecting to be initialized when the bridge first loads.
       if ([moduleClass instanceMethodForSelector:@selector(init)] != objectInitMethod ||
-          [moduleClass instancesRespondToSelector:setBridgeSelector]) {
+          [moduleClass instancesRespondToSelector:setBridgeSelector] ||
+          RCTClassOverridesInstanceMethod(moduleClass, @selector(constantsToExport))) {
         module = [moduleClass new];
         if (!module) {
           module = (id)kCFNull;
diff --git a/React/Base/RCTModuleData.m b/React/Base/RCTModuleData.m
index 9d4b57539250..78ef8471e6f6 100644
--- a/React/Base/RCTModuleData.m
+++ b/React/Base/RCTModuleData.m
@@ -17,6 +17,7 @@
 
 @implementation RCTModuleData
 {
+  NSDictionary<NSString *, id> *_constantsToExport;
   NSString *_queueName;
   __weak RCTBridge *_bridge;
   NSLock *_instanceLock;
@@ -79,6 +80,11 @@ - (void)finishSetupForInstance
     [[NSNotificationCenter defaultCenter] postNotificationName:RCTDidInitializeModuleNotification
                                                         object:_bridge
                                                       userInfo:@{@"module": _instance}];
+
+    if (RCTClassOverridesInstanceMethod(_moduleClass, @selector(constantsToExport))) {
+      RCTAssertMainThread();
+      _constantsToExport = [_instance constantsToExport];
+    }
   }
 }
 
@@ -181,13 +187,8 @@ - (NSString *)name
 
 - (NSArray *)config
 {
-  __block NSDictionary<NSString *, id> *constants;
-  if (RCTClassOverridesInstanceMethod(_moduleClass, @selector(constantsToExport))) {
-    [self instance];
-    RCTExecuteOnMainThread(^{
-      constants = [_instance constantsToExport];
-    }, YES);
-  }
+  __block NSDictionary<NSString *, id> *constants = _constantsToExport;
+  _constantsToExport = nil; // Not needed any more
 
   if (constants.count == 0 && self.methods.count == 0) {
     return (id)kCFNull; // Nothing to export

From c6366e4dd8110a05046894968dc8548aed7c26db Mon Sep 17 00:00:00 2001
From: Ryan Linton <ryanl@clearsightstudio.com>
Date: Tue, 9 Feb 2016 04:44:43 -0800
Subject: [PATCH 1086/1411] Use media url instead of reference url when picking
 movie types in image picker

Summary:
I ran into an issue trying to upload videos selected with ImagePickerIOS to S3. The file would upload just fine but would be reduced in size and have no duration. It appears to be just a thumbnail of the video. Using the media url resolves this.
Closes https://github.com/facebook/react-native/pull/5771

Reviewed By: svcscm

Differential Revision: D2905720

Pulled By: nicklockwood

fb-gh-sync-id: 4b0200652c3b6a62cdb65deb582fbc5829c577a6
shipit-source-id: 4b0200652c3b6a62cdb65deb582fbc5829c577a6
---
 Libraries/CameraRoll/RCTImagePickerManager.m | 36 +++++++++-----------
 1 file changed, 17 insertions(+), 19 deletions(-)

diff --git a/Libraries/CameraRoll/RCTImagePickerManager.m b/Libraries/CameraRoll/RCTImagePickerManager.m
index 0f97099ad851..e772ce0816db 100644
--- a/Libraries/CameraRoll/RCTImagePickerManager.m
+++ b/Libraries/CameraRoll/RCTImagePickerManager.m
@@ -104,26 +104,24 @@ - (dispatch_queue_t)methodQueue
 - (void)imagePickerController:(UIImagePickerController *)picker
 didFinishPickingMediaWithInfo:(NSDictionary<NSString *, id> *)info
 {
-  // Image from PhotoLibrary
-  NSString *imageUri = [info[UIImagePickerControllerReferenceURL] absoluteString];
-  if (imageUri) {
-    [self _dismissPicker:picker args:@[imageUri]];
-
-  } else {
-    // Image from CameraRoll hasn't uri.
-    // We need to save it to the store first.
-    UIImage *originalImage = info[UIImagePickerControllerOriginalImage];
-
-    // WARNING: Using imageStoreManager causes memory leak
-    // because image isn't removed from store once we're done using it
-    [_bridge.imageStoreManager storeImage:originalImage withBlock:^(NSString *tempImageTag) {
-      if (!tempImageTag) {
-        [self _dismissPicker:picker args:nil];
-        return;
-      }
-      [self _dismissPicker:picker args:@[tempImageTag]];
-    }];
+  NSString *mediaType = info[UIImagePickerControllerMediaType];
+  BOOL isMovie = [mediaType isEqualToString:(NSString *)kUTTypeMovie];
+  NSString *key = isMovie ? UIImagePickerControllerMediaURL : UIImagePickerControllerReferenceURL;
+  NSURL *imageURL = info[key];
+  if (imageURL) {
+    [self _dismissPicker:picker args:@[imageURL.absoluteString]];
+    return;
   }
+
+  // This is a newly taken image, and doesn't have a URL yet.
+  // We need to save it to the image store first.
+  UIImage *originalImage = info[UIImagePickerControllerOriginalImage];
+
+  // WARNING: Using ImageStoreManager may cause a memory leak because the
+  // image isn't automatically removed from store once we're done using it.
+  [_bridge.imageStoreManager storeImage:originalImage withBlock:^(NSString *tempImageTag) {
+    [self _dismissPicker:picker args:tempImageTag ? @[tempImageTag] : nil];
+  }];
 }
 
 - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker

From 758d9e83042d80731dcc3e33e68a9db838b79fd1 Mon Sep 17 00:00:00 2001
From: slycoder <jonathan.chang@zipongo.com>
Date: Tue, 9 Feb 2016 05:45:23 -0800
Subject: [PATCH 1087/1411] Add observers for local notifications

Summary:
This commit adds the delegate hooks so that local notifications get
passed onto the JS and adds a new event listener type for local
notifications.

Also add functions to clear local notifications
Closes https://github.com/facebook/react-native/pull/2084

Reviewed By: svcscm

Differential Revision: D2908096

Pulled By: nicklockwood

fb-gh-sync-id: 759d299ea35abea177e72934076297d666d3ea20
shipit-source-id: 759d299ea35abea177e72934076297d666d3ea20
---
 .../PushNotificationIOS.js                    | 35 +++++++--
 .../RCTPushNotificationManager.h              |  1 +
 .../RCTPushNotificationManager.m              | 78 ++++++++++++++-----
 React/Base/RCTUtils.h                         |  2 +-
 4 files changed, 89 insertions(+), 27 deletions(-)

diff --git a/Libraries/PushNotificationIOS/PushNotificationIOS.js b/Libraries/PushNotificationIOS/PushNotificationIOS.js
index cab4ba362073..189bc7ead83a 100644
--- a/Libraries/PushNotificationIOS/PushNotificationIOS.js
+++ b/Libraries/PushNotificationIOS/PushNotificationIOS.js
@@ -21,6 +21,7 @@ var _initialNotification = RCTPushNotificationManager &&
 
 var DEVICE_NOTIF_EVENT = 'remoteNotificationReceived';
 var NOTIF_REGISTER_EVENT = 'remoteNotificationsRegistered';
+var DEVICE_LOCAL_NOTIF_EVENT = 'localNotificationReceived';
 
 /**
  * Handle push notifications for your app, including permission handling and
@@ -59,6 +60,11 @@ var NOTIF_REGISTER_EVENT = 'remoteNotificationsRegistered';
  *    {
  *     [RCTPushNotificationManager didReceiveRemoteNotification:notification];
  *    }
+ *    // Required for the localNotification event.
+ *    - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
+ *    {
+ *     [RCTPushNotificationManager didReceiveLocalNotification:notification];
+ *    }
  *   ```
  */
 class PushNotificationIOS {
@@ -74,7 +80,6 @@ class PushNotificationIOS {
    *
    * - `alertBody` : The message displayed in the notification alert.
    * - `soundName` : The sound played when the notification is fired (optional).
-   *
    */
   static presentLocalNotification(details: Object) {
     RCTPushNotificationManager.presentLocalNotification(details);
@@ -88,7 +93,7 @@ class PushNotificationIOS {
    * - `fireDate` : The date and time when the system should deliver the notification.
    * - `alertBody` : The message displayed in the notification alert.
    * - `soundName` : The sound played when the notification is fired (optional).
-   *
+   * - `userInfo` : An optional object containing additional notification data.
    */
   static scheduleLocalNotification(details: Object) {
     RCTPushNotificationManager.scheduleLocalNotification(details);
@@ -115,6 +120,17 @@ class PushNotificationIOS {
     RCTPushNotificationManager.getApplicationIconBadgeNumber(callback);
   }
 
+  /**
+   * Cancel local notifications.
+   *
+   * Optionally restricts the set of canceled notifications to those
+   * notifications whose `userInfo` fields match the corresponding fields
+   * in the `userInfo` argument.
+   */
+  static cancelLocalNotifications(userInfo: Object) {
+    RCTPushNotificationManager.cancelLocalNotifications(userInfo);
+  }
+
   /**
    * Attaches a listener to remote notification events while the app is running
    * in the foreground or the background.
@@ -128,8 +144,8 @@ class PushNotificationIOS {
    */
   static addEventListener(type: string, handler: Function) {
     invariant(
-      type === 'notification' || type === 'register',
-      'PushNotificationIOS only supports `notification` and `register` events'
+      type === 'notification' || type === 'register' || type === 'localNotification',
+      'PushNotificationIOS only supports `notification`, `register` and `localNotification` events'
     );
     var listener;
     if (type === 'notification') {
@@ -139,6 +155,13 @@ class PushNotificationIOS {
           handler(new PushNotificationIOS(notifData));
         }
       );
+    } else if (type === 'localNotification') {
+      listener = RCTDeviceEventEmitter.addListener(
+        DEVICE_LOCAL_NOTIF_EVENT,
+        (notifData) => {
+          handler(new PushNotificationIOS(notifData));
+        }
+      );
     } else if (type === 'register') {
       listener = RCTDeviceEventEmitter.addListener(
         NOTIF_REGISTER_EVENT,
@@ -220,8 +243,8 @@ class PushNotificationIOS {
    */
   static removeEventListener(type: string, handler: Function) {
     invariant(
-      type === 'notification' || type === 'register',
-      'PushNotificationIOS only supports `notification` and `register` events'
+      type === 'notification' || type === 'register' || type === 'localNotification',
+      'PushNotificationIOS only supports `notification`, `register` and `localNotification` events'
     );
     var listener = _notifHandlers.get(handler);
     if (!listener) {
diff --git a/Libraries/PushNotificationIOS/RCTPushNotificationManager.h b/Libraries/PushNotificationIOS/RCTPushNotificationManager.h
index dd18b95183e4..b7ab540151b5 100644
--- a/Libraries/PushNotificationIOS/RCTPushNotificationManager.h
+++ b/Libraries/PushNotificationIOS/RCTPushNotificationManager.h
@@ -16,5 +16,6 @@
 + (void)didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings;
 + (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
 + (void)didReceiveRemoteNotification:(NSDictionary *)notification;
++ (void)didReceiveLocalNotification:(UILocalNotification *)notification;
 
 @end
diff --git a/Libraries/PushNotificationIOS/RCTPushNotificationManager.m b/Libraries/PushNotificationIOS/RCTPushNotificationManager.m
index 33de7ba627ff..e9c68a5ec6f0 100644
--- a/Libraries/PushNotificationIOS/RCTPushNotificationManager.m
+++ b/Libraries/PushNotificationIOS/RCTPushNotificationManager.m
@@ -24,6 +24,7 @@
 
 #endif
 
+NSString *const RCTLocalNotificationReceived = @"LocalNotificationReceived";
 NSString *const RCTRemoteNotificationReceived = @"RemoteNotificationReceived";
 NSString *const RCTRemoteNotificationsRegistered = @"RemoteNotificationsRegistered";
 
@@ -36,6 +37,7 @@ + (UILocalNotification *)UILocalNotification:(id)json
   notification.fireDate = [RCTConvert NSDate:details[@"fireDate"]] ?: [NSDate date];
   notification.alertBody = [RCTConvert NSString:details[@"alertBody"]];
   notification.soundName = [RCTConvert NSString:details[@"soundName"]] ?: UILocalNotificationDefaultSoundName;
+  notification.userInfo = [RCTConvert NSDictionary:details[@"userInfo"]];
   return notification;
 }
 
@@ -56,6 +58,10 @@ - (void)setBridge:(RCTBridge *)bridge
 {
   _bridge = bridge;
 
+  [[NSNotificationCenter defaultCenter] addObserver:self
+                                           selector:@selector(handleLocalNotificationReceived:)
+                                               name:RCTLocalNotificationReceived
+                                             object:nil];
   [[NSNotificationCenter defaultCenter] addObserver:self
                                            selector:@selector(handleRemoteNotificationReceived:)
                                                name:RCTRemoteNotificationReceived
@@ -68,7 +74,8 @@ - (void)setBridge:(RCTBridge *)bridge
 
 - (NSDictionary<NSString *, id> *)constantsToExport
 {
-  NSDictionary<NSString *, id> *initialNotification = [_bridge.launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey] copy];
+  NSDictionary<NSString *, id> *initialNotification =
+    [_bridge.launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey] copy];
   return @{@"initialNotification": RCTNullIfNil(initialNotification)};
 }
 
@@ -87,12 +94,9 @@ + (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
   for (NSUInteger i = 0; i < deviceTokenLength; i++) {
     [hexString appendFormat:@"%02x", bytes[i]];
   }
-  NSDictionary<NSString *, id> *userInfo = @{
-    @"deviceToken" : [hexString copy]
-  };
   [[NSNotificationCenter defaultCenter] postNotificationName:RCTRemoteNotificationsRegistered
                                                       object:self
-                                                    userInfo:userInfo];
+                                                    userInfo:@{@"deviceToken" : [hexString copy]}];
 }
 
 + (void)didReceiveRemoteNotification:(NSDictionary *)notification
@@ -102,6 +106,26 @@ + (void)didReceiveRemoteNotification:(NSDictionary *)notification
                                                     userInfo:notification];
 }
 
++ (void)didReceiveLocalNotification:(UILocalNotification *)notification
+{
+  NSMutableDictionary *details = [NSMutableDictionary new];
+  if (notification.alertBody) {
+    details[@"alertBody"] = notification.alertBody;
+  }
+  if (notification.userInfo) {
+    details[@"userInfo"] = RCTJSONClean(notification.userInfo);
+  }
+  [[NSNotificationCenter defaultCenter] postNotificationName:RCTLocalNotificationReceived
+                                                      object:self
+                                                    userInfo:details];
+}
+
+- (void)handleLocalNotificationReceived:(NSNotification *)notification
+{
+  [_bridge.eventDispatcher sendDeviceEventWithName:@"localNotificationReceived"
+                                              body:notification.userInfo];
+}
+
 - (void)handleRemoteNotificationReceived:(NSNotification *)notification
 {
   [_bridge.eventDispatcher sendDeviceEventWithName:@"remoteNotificationReceived"
@@ -127,9 +151,7 @@ - (void)handleRemoteNotificationsRegistered:(NSNotification *)notification
  */
 RCT_EXPORT_METHOD(getApplicationIconBadgeNumber:(RCTResponseSenderBlock)callback)
 {
-  callback(@[
-    @(RCTSharedApplication().applicationIconBadgeNumber)
-  ]);
+  callback(@[@(RCTSharedApplication().applicationIconBadgeNumber)]);
 }
 
 RCT_EXPORT_METHOD(requestPermissions:(NSDictionary *)permissions)
@@ -140,13 +162,13 @@ - (void)handleRemoteNotificationsRegistered:(NSNotification *)notification
 
   UIUserNotificationType types = UIUserNotificationTypeNone;
   if (permissions) {
-    if ([permissions[@"alert"] boolValue]) {
+    if ([RCTConvert BOOL:permissions[@"alert"]]) {
       types |= UIUserNotificationTypeAlert;
     }
-    if ([permissions[@"badge"] boolValue]) {
+    if ([RCTConvert BOOL:permissions[@"badge"]]) {
       types |= UIUserNotificationTypeBadge;
     }
-    if ([permissions[@"sound"] boolValue]) {
+    if ([RCTConvert BOOL:permissions[@"sound"]]) {
       types |= UIUserNotificationTypeSound;
     }
   } else {
@@ -155,7 +177,8 @@ - (void)handleRemoteNotificationsRegistered:(NSNotification *)notification
 
   UIApplication *app = RCTSharedApplication();
   if ([app respondsToSelector:@selector(registerUserNotificationSettings:)]) {
-    UIUserNotificationSettings *notificationSettings = [UIUserNotificationSettings settingsForTypes:(NSUInteger)types categories:nil];
+    UIUserNotificationSettings *notificationSettings =
+      [UIUserNotificationSettings settingsForTypes:(NSUInteger)types categories:nil];
     [app registerUserNotificationSettings:notificationSettings];
     [app registerForRemoteNotifications];
   } else {
@@ -171,8 +194,7 @@ - (void)handleRemoteNotificationsRegistered:(NSNotification *)notification
 RCT_EXPORT_METHOD(checkPermissions:(RCTResponseSenderBlock)callback)
 {
   if (RCTRunningInAppExtension()) {
-    NSDictionary<NSString *, NSNumber *> *permissions = @{@"alert": @NO, @"badge": @NO, @"sound": @NO};
-    callback(@[permissions]);
+    callback(@[@{@"alert": @NO, @"badge": @NO, @"sound": @NO}]);
     return;
   }
 
@@ -189,12 +211,11 @@ - (void)handleRemoteNotificationsRegistered:(NSNotification *)notification
 
   }
 
-  NSMutableDictionary<NSString *, NSNumber *> *permissions = [NSMutableDictionary new];
-  permissions[@"alert"] = @((types & UIUserNotificationTypeAlert) > 0);
-  permissions[@"badge"] = @((types & UIUserNotificationTypeBadge) > 0);
-  permissions[@"sound"] = @((types & UIUserNotificationTypeSound) > 0);
-
-  callback(@[permissions]);
+  callback(@[@{
+    @"alert": @((types & UIUserNotificationTypeAlert) > 0),
+    @"badge": @((types & UIUserNotificationTypeBadge) > 0),
+    @"sound": @((types & UIUserNotificationTypeSound) > 0),
+  }]);
 }
 
 RCT_EXPORT_METHOD(presentLocalNotification:(UILocalNotification *)notification)
@@ -212,4 +233,21 @@ - (void)handleRemoteNotificationsRegistered:(NSNotification *)notification
   [RCTSharedApplication() cancelAllLocalNotifications];
 }
 
+RCT_EXPORT_METHOD(cancelLocalNotifications:(NSDictionary *)userInfo)
+{
+  for (UILocalNotification *notification in [UIApplication sharedApplication].scheduledLocalNotifications) {
+    __block BOOL matchesAll = YES;
+    NSDictionary *notificationInfo = notification.userInfo;
+    [userInfo enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
+      if (![notificationInfo[key] isEqual:obj]) {
+        matchesAll = NO;
+        *stop = YES;
+      }
+    }];
+    if (matchesAll) {
+      [[UIApplication sharedApplication] cancelLocalNotification:notification];
+    }
+  }
+}
+
 @end
diff --git a/React/Base/RCTUtils.h b/React/Base/RCTUtils.h
index c751dabbd25b..9d63bdbf3379 100644
--- a/React/Base/RCTUtils.h
+++ b/React/Base/RCTUtils.h
@@ -23,7 +23,7 @@ RCT_EXTERN NSString *__nullable RCTJSONStringify(id __nullable jsonObject, NSErr
 RCT_EXTERN id __nullable RCTJSONParse(NSString *__nullable jsonString, NSError **error);
 RCT_EXTERN id __nullable RCTJSONParseMutable(NSString *__nullable jsonString, NSError **error);
 
-// Santize a JSON string by stripping invalid objects and/or NaN values
+// Sanitize a JSON object by stripping invalid types and/or NaN values
 RCT_EXTERN id RCTJSONClean(id object);
 
 // Get MD5 hash of a string

From 702f999b050d50286d7a222587772bf4d2f7c557 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Tue, 9 Feb 2016 06:36:30 -0800
Subject: [PATCH 1088/1411] Consume Android artifacts from npm

Summary:
This lets us say goodbye to Maven Central. This will greatly simplify
and speed up the release process as releasing Android artifacts to
Maven Central adds a lot of [complexity](https://github.com/facebook/react-native/blob/master/Releases-publish.md)
and delays the whole release by several hours when we have to wait
for the artifacts to propagate.

This diff assumes there's a local Maven repo at
`node_modules/react-native/android`.

The second part once this lands is to change our `release.sh` script to
output the artifacts under `react-native/android` before publishing to
npm.

This adds 3.7MB to the size of `node_modules` of any app. However,
we just download eagerly what we'd normally download later via Gradle.

**Test plan**

Released RN including a local Maven repo into Sinopia:

    $ cd react-native
    # Updated version in gradle.properties to 0.21.0
    $ ./gradlew ReactAndroid:installArchives
    # Moved everything in .m2/repository/com/facebook/react to react-native/android
    $ ls react-native/android
    com/facebook/react/react-native/0.21.0/react-native-0.21.0.aar
    com/facebook/react/react-native/0.21.0/react-native-0.21.0.pom
    com/facebook/react/react-native/maven-metadata.xml
    ...

    # Set version in package.json to 0.21.0
    $ npm set registry http://localhost:4873/
    $ npm publish

Created and ran an app:

   $ cd /tmp
   $ react-native init AndroidNpm
   $ cd AndroidNpm
   $ react-native run-android

It worked.

Checked that we're using the artifacts from node_modules/react-native/android:

    $ cd android
    $ ./gradlew app:dependencies
    compile - Classpath for compiling the main sources.
    +--- com.android.support:appcompat-v7:23.0.1
    |    \--- com.android.support:support-v4:23.0.1
    |         \--- com.android.support:support-annotations:23.0.1
    \--- com.facebook.react:react-native:+ -> 0.21.0
         +--- com.google.code.findbugs:jsr305:3.0.0
         +--- com.facebook.stetho:stetho-okhttp:1.2.0
    ...

Checked that Android Studio can find the source jars (you can navigate to RN sources in Android Studio). Opened the new project as described in the [docs](https://facebook.github.io/react-native/docs/android-setup.html#editing-your-app-s-java-code-in-android-studio).

public

Reviewed By: bestander

Differential Revision: D2912557

fb-gh-sync-id: 251c180518a3fb9bb8e80963b236e982d65533be
shipit-source-id: 251c180518a3fb9bb8e80963b236e982d65533be
---
 .../generator-android/templates/src/app/build.gradle     | 9 ++++-----
 local-cli/generator-android/templates/src/build.gradle   | 4 ++++
 package.json                                             | 2 +-
 3 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/local-cli/generator-android/templates/src/app/build.gradle b/local-cli/generator-android/templates/src/app/build.gradle
index ee7028cf4f25..428bb043dd75 100644
--- a/local-cli/generator-android/templates/src/app/build.gradle
+++ b/local-cli/generator-android/templates/src/app/build.gradle
@@ -62,8 +62,7 @@ import com.android.build.OutputFile
 apply from: "react.gradle"
 
 /**
- * Set this to true to create three separate APKs instead of one:
- *   - A universal APK that works on all devices
+ * Set this to true to create two separate APKs instead of one:
  *   - An APK that only works on ARM devices
  *   - An APK that only works on x86 devices
  * The advantage is the size of the APK is reduced by about 4MB.
@@ -93,9 +92,9 @@ android {
     }
     splits {
         abi {
-            enable enableSeparateBuildPerCPUArchitecture
-            universalApk false
             reset()
+            enable enableSeparateBuildPerCPUArchitecture
+            universalApk false  // If true, also generate a universal APK
             include "armeabi-v7a", "x86"
         }
     }
@@ -123,5 +122,5 @@ android {
 dependencies {
     compile fileTree(dir: "libs", include: ["*.jar"])
     compile "com.android.support:appcompat-v7:23.0.1"
-    compile "com.facebook.react:react-native:0.13.0"
+    compile "com.facebook.react:react-native:+"  // From node_modules
 }
diff --git a/local-cli/generator-android/templates/src/build.gradle b/local-cli/generator-android/templates/src/build.gradle
index ccdfc4e3dca8..403a007564d9 100644
--- a/local-cli/generator-android/templates/src/build.gradle
+++ b/local-cli/generator-android/templates/src/build.gradle
@@ -16,5 +16,9 @@ allprojects {
     repositories {
         mavenLocal()
         jcenter()
+        maven {
+            // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
+            url "$projectDir/../../node_modules/react-native/android"
+        }
     }
 }
diff --git a/package.json b/package.json
index e7040699e370..c77553f3767b 100644
--- a/package.json
+++ b/package.json
@@ -82,7 +82,7 @@
   "files": [
     "React",
     "React.podspec",
-    "ReactAndroid",
+    "android",
     "Libraries",
     "packager",
     "cli.js",

From f7468ec3568257e1cf4461c7b030bd8d6d09c0bd Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Tue, 9 Feb 2016 16:00:49 +0000
Subject: [PATCH 1089/1411] Update Releases.md

---
 Releases.md | 15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/Releases.md b/Releases.md
index 11c61502146d..06933c78924e 100644
--- a/Releases.md
+++ b/Releases.md
@@ -3,15 +3,14 @@ https://github.com/facebook/react-native/releases
 
 Future releases:
 
-- **0.17 branch cut**, 0.17.0-rc - beginning of **week of Dec 7**
-- 0.17.0 - Dec 17
-- (Holiday break)
-- **0.18 branch cut**, 0.18.0-rc - **week of Jan 4**
-- 0.18.0 - Jan 18
-- **0.19 branch cut**, 0.19.0-rc - **week of Jan 18**
-- 0.19.0 - Feb 1
 - **0.20 branch cut**, 0.20.0-rc - **week of Feb 1**
 - 0.20.0 - Feb 15
+- **0.21 branch cut**, 0.21.0-rc - **week of Feb 15**
+- 0.21.0 - Feb 29
+- **0.22 branch cut**, 0.22.0-rc - **week of Feb 29**
+- 0.22.0 - Mar 7
+- **0.23 branch cut**, 0.23.0-rc - **week of Mar 7**
+- 0.23.0 - Mar 21
 - ...
 
 ## One time setup
@@ -45,8 +44,6 @@ To go through all the commits that went into a release, one way is to use the gi
 
 ## Do a release
 
-Skip this for now, ping @mkonicek on messenger and he'll handle it. Docs [here](https://github.com/facebook/react-native/blob/master/Releases-publish.md).
-
 IMPORTANT:  `npm publish` will automatically set the latest tag. **When doing an RC release**, run `npm publish --tag next` - this way people need to opt in to get the RC release.
 
 ## Track bug reports from the community during the following two weeks and make sure they get fixed

From 8a9996c5c76d4624324d68a96781b0366c8c99ab Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Tue, 9 Feb 2016 16:01:36 +0000
Subject: [PATCH 1090/1411] New release process: Update release script and docs

---
 Releases-publish.md | 36 ------------------------------------
 scripts/release.sh  | 13 ++++---------
 2 files changed, 4 insertions(+), 45 deletions(-)
 delete mode 100644 Releases-publish.md

diff --git a/Releases-publish.md b/Releases-publish.md
deleted file mode 100644
index 07aec7a77eb7..000000000000
--- a/Releases-publish.md
+++ /dev/null
@@ -1,36 +0,0 @@
-## Ideas for improvements
-
-We could simplify the process quite a bit by publishing the Android binaries to npm. This will increase the size of the npm package by about 3.3MB. To do that: after `installArchives`, move the binaries to somewhere where `npm publish` will pick them up. Then, change the `build.gradle` file(s) of your generated app so that Gradle will pick up the binaries from `node_modules`. This will likely also **fix issues with incompatible versions of JS and Android binaries** (e.g. [#4488](https://github.com/facebook/react-native/issues/4488)).
-
-## Publish a release (same steps for an rc version, 0.x.0)
-
-Publish to Maven Central (Note: **We could get rid of this whole section by publishing binaries to npm instead**):
-  - Log into Sonatype and go to [Staging upload](https://oss.sonatype.org/#staging-upload). You'll need to get permissions for this by filing a ticket explaining you're a core contributor to React Native. [Example ticket](https://issues.sonatype.org/browse/OSSRH-11885).
-  - Select Artifact(s) with a POM (to publish to a local Maven repo for testing run `./gradlew :ReactAndroid:installArchives`)
-  - Add all files: .aar, sources jar, javadoc jar, .asc for everything (including the POM file)
-  - Wait a few hours until you see the version has propagated to [JCenter](https://bintray.com/bintray/jcenter/com.facebook.react%3Areact-native/view)
-
-To release to npm:
-
-(You need to be a maintainer of the repo. For admins, here's the command to promote someone)
-
-```
-npm owner add <user> react-native
-```
-
-```
-git tag v0.version_you_are_releasing.0-rc 0.version_you_are_releasing-stable # don't forget the `v` at the beginning!
-git push --tags
-```
-
-- Publish to npm
-
-```
-npm set registry https://registry.npmjs.org/
-npm publish
-# *Only* when doing a non-rc release:
-# npm dist-tag add react-native@0.non_rc_version.0 latest
-```
-- Upgrade tags to a release by going to https://github.com/facebook/react-native/tags
-- Click "Add Notes to release"
-- Click Publish
diff --git a/scripts/release.sh b/scripts/release.sh
index ce3b9dba9bd3..79e6d24a785e 100755
--- a/scripts/release.sh
+++ b/scripts/release.sh
@@ -45,16 +45,13 @@ artifacts_dir=~/.m2/repository/com/facebook/react/react-native/${RELEASE}.0
 
 for i in "${artifacts_list[@]}"; do
    artifact_file="${artifacts_dir}/react-native-${RELEASE}.0${i}"
-
    [ -e "${artifact_file}" ] || error "Couldn't find file: ${artifact_file}"
-   [ -e "${artifact_file}.asc" ] || error "Couldn't find file: ${artifact_file}.asc"
 done
 
 success "Generated artifacts for Maven"
 
 sed -i.bak -E "s/(\"version\":[[:space:]]*\").+(\")/\"version\": \"${RELEASE}.0-rc\"/g" "package.json" || error "Couldn't update version for npm"
 sed -i.bak -E "s/(s.version[[:space:]]{13}=[[:space:]].+)/s.version             = \"${RELEASE}.0-rc\"/g" "React.podspec" || error "Couldn't update version for CocoaPods"
-sed -i.bak -E "s/\"com\.facebook\.react:react-native:.+\"/\"com.facebook.react:react-native:${RELEASE}.+\"/g" "local-cli/generator-android/templates/src/app/build.gradle" || error "Couldn't update version in Android template's build.gradle"
 
 success "Updated version numbers"
 
@@ -82,7 +79,7 @@ react-native init "$project_name"
 
 info "Double checking the versions in package.json and build.gradle are correct:"
 grep "\"react-native\": \"\^${RELEASE}.0-rc\"" "/tmp/${project_name}/package.json" || error "Incorrect version number in /tmp/${project_name}/package.json"
-grep "com.facebook.react:react-native:${RELEASE}.+" "${project_name}/android/app/build.gradle" || error "Incorrect version number in /tmp/${project_name}/android/app/build.gradle"
+grep -E "com.facebook.react:react-native:\\+" "${project_name}/android/app/build.gradle" || error "Dependency in /tmp/${project_name}/android/app/build.gradle must be com.facebook.react:react-native:+"
 
 success "New sample project generated at /tmp/${project_name}"
 
@@ -110,11 +107,9 @@ git commit -am "[${RELEASE}.0-rc] Bump version numbers"
 find . -path "*.bak" | xargs rm
 
 info "Next steps:"
-info "   - Release to Maven Central: https://github.com/facebook/react-native/blob/master/Releases.md#do-a-release"
 info "   - git push origin ${RELEASE}-stable"
 info "   - git tag v${RELEASE}.0-rc ${RELEASE}-stable"
 info "   - git push --tags"
-info "   - Once the change propagates to JCenter:"
-info "     - npm set registry https://registry.npmjs.org/"
-info "     - When doing a RC release: npm publish --tag next"
-info "     - When doing a non-RC release: npm publish  # Sets the latest tag automatically"
+info "   - npm set registry https://registry.npmjs.org/"
+info "   - When doing a RC release: npm publish --tag next"
+info "   - When doing a non-RC release: npm publish  # Sets the latest tag automatically"

From 47dac4ff5008b7e87857f9b7951775ef8e913681 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Tue, 9 Feb 2016 16:13:33 +0000
Subject: [PATCH 1091/1411] New release process: Fix path in release.sh

---
 scripts/release.sh | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/scripts/release.sh b/scripts/release.sh
index 79e6d24a785e..04776a5a3d14 100755
--- a/scripts/release.sh
+++ b/scripts/release.sh
@@ -41,7 +41,8 @@ sed -i.bak s:\/\/\ archives\ androidJavadocJar:archives\ androidJavadocJar:g "Re
 sed -i.bak s:archives\ androidJavadocJar:\/\/\ archives\ androidJavadocJar:g "ReactAndroid/release.gradle" || error "Couldn't enable Javadoc generation"
 
 artifacts_list=( -javadoc.jar -sources.jar .aar .pom )
-artifacts_dir=~/.m2/repository/com/facebook/react/react-native/${RELEASE}.0
+# ./gradlew :ReactAndroid:installArchives put the artifacts in react-native/android, ready to be published to npm
+artifacts_dir="${repo_root}/android/com/facebook/react/react-native/${RELEASE}.0"
 
 for i in "${artifacts_list[@]}"; do
    artifact_file="${artifacts_dir}/react-native-${RELEASE}.0${i}"

From 788e25894ed0f9331c44170ef63b5ceb5c1631ad Mon Sep 17 00:00:00 2001
From: Krzysztof Magiera <krzys.magiera@gmail.com>
Date: Tue, 9 Feb 2016 08:16:26 -0800
Subject: [PATCH 1092/1411] Move SimpleArray and SimpleMap from test to src.

Summary:
As a part of this change I'm also renaming SimpleArray to JavaOnlyArray and SimpleMap to JavaOnlyMap. The main reason for the change is to support use-cases such as driving animations form the native code. In the case of native "animated" I'd like to be able to use the same interface as JS is using for updating the View properties. As view setters can take ReadableMap and ReadableArray as an argument in some cases it is necessary to create and pass those types to the setter. Using WritableNativeArray and WritableNativeMap for this purpose seems to me like a misuse and IMO will be less performant (vs java-only map/array) as those implementations of ReadableMap and ReadableArray proxies all their methods through JNI.

I'm also adding some additional class-level comments for the moved classes to avoid confusion and hopefuly prevent people from using those classess accidentally while writing native modules or methods that calls to JS.
Closes https://github.com/facebook/react-native/pull/5816

Reviewed By: svcscm

Differential Revision: D2911339

Pulled By: foghina

fb-gh-sync-id: 5b9a98d64f48d8bba34c15e3eecba2151da3577a
shipit-source-id: 5b9a98d64f48d8bba34c15e3eecba2151da3577a
---
 .../facebook/react/bridge/JavaOnlyArray.java} |  36 +++---
 .../facebook/react/bridge/JavaOnlyMap.java}   |  31 +++--
 .../java/com/facebook/react/RootViewTest.java |  22 ++--
 .../modules/dialog/DialogModuleTest.java      |  12 +-
 .../modules/network/NetworkingModuleTest.java |  86 ++++++-------
 .../storage/AsyncStorageModuleTest.java       |  56 ++++-----
 .../modules/timing/TimingModuleTest.java      |  16 +--
 .../LayoutPropertyApplicatorTest.java         |   4 +-
 .../ReactPropAnnotationSetterTest.java        |  14 +--
 .../uimanager/SimpleViewPropertyTest.java     |   4 +-
 .../react/uimanager/UIManagerModuleTest.java  | 118 +++++++++---------
 .../views/image/ReactImagePropertyTest.java   |   4 +-
 .../react/views/text/ReactTextTest.java       |  81 ++++++------
 .../textinput/ReactTextInputPropertyTest.java |   4 +-
 .../react/views/textinput/TextInputTest.java  |  25 ++--
 15 files changed, 263 insertions(+), 250 deletions(-)
 rename ReactAndroid/src/{test/java/com/facebook/react/bridge/SimpleArray.java => main/java/com/facebook/react/bridge/JavaOnlyArray.java} (66%)
 rename ReactAndroid/src/{test/java/com/facebook/react/bridge/SimpleMap.java => main/java/com/facebook/react/bridge/JavaOnlyMap.java} (74%)

diff --git a/ReactAndroid/src/test/java/com/facebook/react/bridge/SimpleArray.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaOnlyArray.java
similarity index 66%
rename from ReactAndroid/src/test/java/com/facebook/react/bridge/SimpleArray.java
rename to ReactAndroid/src/main/java/com/facebook/react/bridge/JavaOnlyArray.java
index 15656bde422e..4ac476a31b5f 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/bridge/SimpleArray.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaOnlyArray.java
@@ -14,29 +14,37 @@
 import java.util.List;
 
 /**
- * A simple read/write array that can be used in tests in place of {@link WritableNativeArray}.
+ * Java {@link ArrayList} backed impementation of {@link ReadableArray} and {@link WritableArray}
+ * Instances of this class SHOULD NOT be used for communication between java and JS, use instances
+ * of {@link WritableNativeArray} created via {@link Arguments#createArray} or just
+ * {@link ReadableArray} interface if you want your "native" module method to take an array from JS
+ * as an argument.
+ *
+ * Main purpose for this class is to be used in java-only unit tests, but could also be used outside
+ * of tests in the code that operates only in java and needs to communicate with RN modules via
+ * their JS-exposed API.
  */
-public class SimpleArray implements ReadableArray, WritableArray {
+public class JavaOnlyArray implements ReadableArray, WritableArray {
 
   private final List mBackingList;
 
-  public static SimpleArray from(List list) {
-    return new SimpleArray(list);
+  public static JavaOnlyArray from(List list) {
+    return new JavaOnlyArray(list);
   }
 
-  public static SimpleArray of(Object... values) {
-    return new SimpleArray(values);
+  public static JavaOnlyArray of(Object... values) {
+    return new JavaOnlyArray(values);
   }
 
-  private SimpleArray(Object... values) {
+  private JavaOnlyArray(Object... values) {
     mBackingList = Arrays.asList(values);
   }
 
-  private SimpleArray(List list) {
+  private JavaOnlyArray(List list) {
     mBackingList = new ArrayList(list);
   }
 
-  public SimpleArray() {
+  public JavaOnlyArray() {
     mBackingList = new ArrayList();
   }
 
@@ -66,8 +74,8 @@ public String getString(int index) {
   }
 
   @Override
-  public SimpleArray getArray(int index) {
-    return (SimpleArray) mBackingList.get(index);
+  public JavaOnlyArray getArray(int index) {
+    return (JavaOnlyArray) mBackingList.get(index);
   }
 
   @Override
@@ -76,8 +84,8 @@ public boolean getBoolean(int index) {
   }
 
   @Override
-  public SimpleMap getMap(int index) {
-    return (SimpleMap) mBackingList.get(index);
+  public JavaOnlyMap getMap(int index) {
+    return (JavaOnlyMap) mBackingList.get(index);
   }
 
   @Override
@@ -130,7 +138,7 @@ public boolean equals(Object o) {
     if (this == o) return true;
     if (o == null || getClass() != o.getClass()) return false;
 
-    SimpleArray that = (SimpleArray) o;
+    JavaOnlyArray that = (JavaOnlyArray) o;
 
     if (mBackingList != null ? !mBackingList.equals(that.mBackingList) : that.mBackingList != null)
       return false;
diff --git a/ReactAndroid/src/test/java/com/facebook/react/bridge/SimpleMap.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaOnlyMap.java
similarity index 74%
rename from ReactAndroid/src/test/java/com/facebook/react/bridge/SimpleMap.java
rename to ReactAndroid/src/main/java/com/facebook/react/bridge/JavaOnlyMap.java
index f86f04e8cc62..607d686e2c6f 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/bridge/SimpleMap.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaOnlyMap.java
@@ -14,20 +14,27 @@
 import java.util.Map;
 
 /**
- * A simple read/write map that can be used in tests in place of {@link WritableNativeMap}.
+ * Java {@link HashMap} backed impementation of {@link ReadableMap} and {@link WritableMap}
+ * Instances of this class SHOULD NOT be used for communication between java and JS, use instances
+ * of {@link WritableNativeMap} created via {@link Arguments#createMap} or just {@link ReadableMap}
+ * interface if you want your "native" module method to take a map from JS as an argument.
+ *
+ * Main purpose for this class is to be used in java-only unit tests, but could also be used outside
+ * of tests in the code that operates only in java and needs to communicate with RN modules via
+ * their JS-exposed API.
  */
-public class SimpleMap implements ReadableMap, WritableMap {
+public class JavaOnlyMap implements ReadableMap, WritableMap {
 
   private final Map mBackingMap;
 
-  public static SimpleMap of(Object... keysAndValues) {
-    return new SimpleMap(keysAndValues);
+  public static JavaOnlyMap of(Object... keysAndValues) {
+    return new JavaOnlyMap(keysAndValues);
   }
 
   /**
    * @param keysAndValues keys and values, interleaved
    */
-  private SimpleMap(Object... keysAndValues) {
+  private JavaOnlyMap(Object... keysAndValues) {
     if (keysAndValues.length % 2 != 0) {
       throw new IllegalArgumentException("You must provide the same number of keys and values");
     }
@@ -37,7 +44,7 @@ private SimpleMap(Object... keysAndValues) {
     }
   }
 
-  public SimpleMap() {
+  public JavaOnlyMap() {
     mBackingMap = new HashMap();
   }
 
@@ -72,13 +79,13 @@ public String getString(String name) {
   }
 
   @Override
-  public SimpleMap getMap(String name) {
-    return (SimpleMap) mBackingMap.get(name);
+  public JavaOnlyMap getMap(String name) {
+    return (JavaOnlyMap) mBackingMap.get(name);
   }
 
   @Override
-  public SimpleArray getArray(String name) {
-    return (SimpleArray) mBackingMap.get(name);
+  public JavaOnlyArray getArray(String name) {
+    return (JavaOnlyArray) mBackingMap.get(name);
   }
 
   @Override
@@ -135,7 +142,7 @@ public void putMap(String key, WritableMap value) {
 
   @Override
   public void merge(ReadableMap source) {
-    mBackingMap.putAll(((SimpleMap) source).mBackingMap);
+    mBackingMap.putAll(((JavaOnlyMap) source).mBackingMap);
   }
 
   @Override
@@ -153,7 +160,7 @@ public boolean equals(Object o) {
     if (this == o) return true;
     if (o == null || getClass() != o.getClass()) return false;
 
-    SimpleMap that = (SimpleMap) o;
+    JavaOnlyMap that = (JavaOnlyMap) o;
 
     if (mBackingMap != null ? !mBackingMap.equals(that.mBackingMap) : that.mBackingMap != null)
       return false;
diff --git a/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java b/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java
index 388d5064d532..7f3d96f30b1a 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java
@@ -19,8 +19,8 @@
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.CatalystInstance;
 import com.facebook.react.bridge.ReactTestHelper;
-import com.facebook.react.bridge.SimpleArray;
-import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.bridge.JavaOnlyArray;
+import com.facebook.react.bridge.JavaOnlyMap;
 import com.facebook.react.bridge.WritableArray;
 import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.DisplayMetricsHolder;
@@ -68,13 +68,13 @@ public void setUp() {
     PowerMockito.when(Arguments.createArray()).thenAnswer(new Answer<Object>() {
       @Override
       public Object answer(InvocationOnMock invocation) throws Throwable {
-        return new SimpleArray();
+        return new JavaOnlyArray();
       }
     });
     PowerMockito.when(Arguments.createMap()).thenAnswer(new Answer<Object>() {
       @Override
       public Object answer(InvocationOnMock invocation) throws Throwable {
-        return new SimpleMap();
+        return new JavaOnlyMap();
       }
     });
 
@@ -120,17 +120,17 @@ public void testTouchEmitter() {
 
     downEventCaptor.getValue().dispatch(eventEmitterModuleMock);
 
-    ArgumentCaptor<SimpleArray> downActionTouchesArgCaptor =
-        ArgumentCaptor.forClass(SimpleArray.class);
+    ArgumentCaptor<JavaOnlyArray> downActionTouchesArgCaptor =
+        ArgumentCaptor.forClass(JavaOnlyArray.class);
     verify(eventEmitterModuleMock).receiveTouches(
         eq("topTouchStart"),
         downActionTouchesArgCaptor.capture(),
-        any(SimpleArray.class));
+        any(JavaOnlyArray.class));
     verifyNoMoreInteractions(eventEmitterModuleMock);
 
     assertThat(downActionTouchesArgCaptor.getValue().size()).isEqualTo(1);
     assertThat(downActionTouchesArgCaptor.getValue().getMap(0)).isEqualTo(
-        SimpleMap.of(
+        JavaOnlyMap.of(
             "pageX",
             0.,
             "pageY",
@@ -150,8 +150,8 @@ public void testTouchEmitter() {
     reset(eventEmitterModuleMock, eventDispatcher);
 
     ArgumentCaptor<Event> upEventCaptor = ArgumentCaptor.forClass(Event.class);
-    ArgumentCaptor<SimpleArray> upActionTouchesArgCaptor =
-        ArgumentCaptor.forClass(SimpleArray.class);
+    ArgumentCaptor<JavaOnlyArray> upActionTouchesArgCaptor =
+        ArgumentCaptor.forClass(JavaOnlyArray.class);
 
     rootView.onTouchEvent(
         MotionEvent.obtain(50, ts, MotionEvent.ACTION_UP, 0, 0, 0));
@@ -167,7 +167,7 @@ public void testTouchEmitter() {
 
     assertThat(upActionTouchesArgCaptor.getValue().size()).isEqualTo(1);
     assertThat(upActionTouchesArgCaptor.getValue().getMap(0)).isEqualTo(
-        SimpleMap.of(
+        JavaOnlyMap.of(
             "pageX",
             0.,
             "pageY",
diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/dialog/DialogModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/dialog/DialogModuleTest.java
index f0ae5dc3acfd..3925adb26f09 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/modules/dialog/DialogModuleTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/modules/dialog/DialogModuleTest.java
@@ -15,7 +15,7 @@
 
 import com.facebook.react.bridge.Callback;
 import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.bridge.JavaOnlyMap;
 
 import org.junit.After;
 import org.junit.Before;
@@ -84,7 +84,7 @@ public void tearDown() {
 
   @Test
   public void testAllOptions() {
-    final SimpleMap options = new SimpleMap();
+    final JavaOnlyMap options = new JavaOnlyMap();
     options.putString("title", "Title");
     options.putString("message", "Message");
     options.putString("buttonPositive", "OK");
@@ -104,7 +104,7 @@ public void testAllOptions() {
 
   @Test
   public void testCallbackPositive() {
-    final SimpleMap options = new SimpleMap();
+    final JavaOnlyMap options = new JavaOnlyMap();
     options.putString("buttonPositive", "OK");
 
     final SimpleCallback actionCallback = new SimpleCallback();
@@ -120,7 +120,7 @@ public void testCallbackPositive() {
 
   @Test
   public void testCallbackNegative() {
-    final SimpleMap options = new SimpleMap();
+    final JavaOnlyMap options = new JavaOnlyMap();
     options.putString("buttonNegative", "Cancel");
 
     final SimpleCallback actionCallback = new SimpleCallback();
@@ -136,7 +136,7 @@ public void testCallbackNegative() {
 
   @Test
   public void testCallbackNeutral() {
-    final SimpleMap options = new SimpleMap();
+    final JavaOnlyMap options = new JavaOnlyMap();
     options.putString("buttonNeutral", "Later");
 
     final SimpleCallback actionCallback = new SimpleCallback();
@@ -152,7 +152,7 @@ public void testCallbackNeutral() {
 
   @Test
   public void testCallbackDismiss() {
-    final SimpleMap options = new SimpleMap();
+    final JavaOnlyMap options = new JavaOnlyMap();
 
     final SimpleCallback actionCallback = new SimpleCallback();
     mDialogModule.showAlert(options, null, actionCallback);
diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkingModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkingModuleTest.java
index 64884aabdb56..63707bae0ebf 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkingModuleTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkingModuleTest.java
@@ -16,8 +16,8 @@
 import com.facebook.react.bridge.Arguments;
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.ReactContext;
-import com.facebook.react.bridge.SimpleArray;
-import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.bridge.JavaOnlyArray;
+import com.facebook.react.bridge.JavaOnlyMap;
 import com.facebook.react.bridge.WritableArray;
 import com.facebook.react.bridge.WritableMap;
 import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter;
@@ -91,7 +91,7 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
         "GET",
         "http://somedomain/foo",
         0,
-        SimpleArray.of(),
+        JavaOnlyArray.of(),
         null,
         true,
         0);
@@ -113,7 +113,7 @@ public void testFailGetWithInvalidHeadersStruct() throws Exception {
     OkHttpClient httpClient = mock(OkHttpClient.class);
     NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient);
 
-    List<SimpleArray> invalidHeaders = Arrays.asList(SimpleArray.of("foo"));
+    List<JavaOnlyArray> invalidHeaders = Arrays.asList(JavaOnlyArray.of("foo"));
 
     mockEvents();
 
@@ -121,7 +121,7 @@ public void testFailGetWithInvalidHeadersStruct() throws Exception {
         "GET",
         "http://somedoman/foo",
         0,
-        SimpleArray.from(invalidHeaders),
+        JavaOnlyArray.from(invalidHeaders),
         null,
         true,
         0);
@@ -138,7 +138,7 @@ public void testFailPostWithoutContentType() throws Exception {
     OkHttpClient httpClient = mock(OkHttpClient.class);
     NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient);
 
-    SimpleMap body = new SimpleMap();
+    JavaOnlyMap body = new JavaOnlyMap();
     body.putString("string", "This is request body");
 
     mockEvents();
@@ -147,7 +147,7 @@ public void testFailPostWithoutContentType() throws Exception {
         "POST",
         "http://somedomain/bar",
         0,
-        SimpleArray.of(),
+        JavaOnlyArray.of(),
         body,
         true,
         0);
@@ -170,7 +170,7 @@ private static void mockEvents() {
         new Answer<WritableArray>() {
           @Override
           public WritableArray answer(InvocationOnMock invocation) throws Throwable {
-            return new SimpleArray();
+            return new JavaOnlyArray();
           }
         });
 
@@ -178,7 +178,7 @@ public WritableArray answer(InvocationOnMock invocation) throws Throwable {
         new Answer<WritableMap>() {
           @Override
           public WritableMap answer(InvocationOnMock invocation) throws Throwable {
-            return new SimpleMap();
+            return new JavaOnlyMap();
           }
         });
   }
@@ -196,14 +196,14 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
 
     NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient);
 
-    SimpleMap body = new SimpleMap();
+    JavaOnlyMap body = new JavaOnlyMap();
     body.putString("string", "This is request body");
 
     networkingModule.sendRequest(
         "POST",
         "http://somedomain/bar",
         0,
-        SimpleArray.of(SimpleArray.of("Content-Type", "text/plain")),
+        JavaOnlyArray.of(JavaOnlyArray.of("Content-Type", "text/plain")),
         body,
         true,
         0);
@@ -232,15 +232,15 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
     });
     NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient);
 
-    List<SimpleArray> headers = Arrays.asList(
-        SimpleArray.of("Accept", "text/plain"),
-        SimpleArray.of("User-Agent", "React test agent/1.0"));
+    List<JavaOnlyArray> headers = Arrays.asList(
+        JavaOnlyArray.of("Accept", "text/plain"),
+        JavaOnlyArray.of("User-Agent", "React test agent/1.0"));
 
     networkingModule.sendRequest(
         "GET",
         "http://someurl/baz",
         0,
-        SimpleArray.from(headers),
+        JavaOnlyArray.from(headers),
         null,
         true,
         0);
@@ -260,15 +260,15 @@ public void testMultipartPostRequestSimple() throws Exception {
     when(RequestBodyUtil.create(any(MediaType.class), any(InputStream.class)))
         .thenReturn(mock(RequestBody.class));
 
-    SimpleMap body = new SimpleMap();
-    SimpleArray formData = new SimpleArray();
-    SimpleMap bodyPart = new SimpleMap();
+    JavaOnlyMap body = new JavaOnlyMap();
+    JavaOnlyArray formData = new JavaOnlyArray();
+    JavaOnlyMap bodyPart = new JavaOnlyMap();
     bodyPart.putString("string", "value");
     bodyPart.putArray(
         "headers",
-        SimpleArray.from(
+        JavaOnlyArray.from(
             Arrays.asList(
-                SimpleArray.of("content-disposition", "name"))));
+                JavaOnlyArray.of("content-disposition", "name"))));
     formData.pushMap(bodyPart);
     body.putArray("formData", formData);
 
@@ -287,7 +287,7 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
         "POST",
         "http://someurl/uploadFoo",
         0,
-        new SimpleArray(),
+        new JavaOnlyArray(),
         body,
         true,
         0);
@@ -313,20 +313,20 @@ public void testMultipartPostRequestHeaders() throws Exception {
     when(RequestBodyUtil.create(any(MediaType.class), any(InputStream.class)))
         .thenReturn(mock(RequestBody.class));
 
-    List<SimpleArray> headers = Arrays.asList(
-            SimpleArray.of("Accept", "text/plain"),
-            SimpleArray.of("User-Agent", "React test agent/1.0"),
-            SimpleArray.of("content-type", "multipart/form-data"));
+    List<JavaOnlyArray> headers = Arrays.asList(
+            JavaOnlyArray.of("Accept", "text/plain"),
+            JavaOnlyArray.of("User-Agent", "React test agent/1.0"),
+            JavaOnlyArray.of("content-type", "multipart/form-data"));
 
-    SimpleMap body = new SimpleMap();
-    SimpleArray formData = new SimpleArray();
-    SimpleMap bodyPart = new SimpleMap();
+    JavaOnlyMap body = new JavaOnlyMap();
+    JavaOnlyArray formData = new JavaOnlyArray();
+    JavaOnlyMap bodyPart = new JavaOnlyMap();
     bodyPart.putString("string", "value");
     bodyPart.putArray(
         "headers",
-        SimpleArray.from(
+        JavaOnlyArray.from(
             Arrays.asList(
-                SimpleArray.of("content-disposition", "name"))));
+                JavaOnlyArray.of("content-disposition", "name"))));
     formData.pushMap(bodyPart);
     body.putArray("formData", formData);
 
@@ -345,7 +345,7 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
         "POST",
         "http://someurl/uploadFoo",
         0,
-        SimpleArray.from(headers),
+        JavaOnlyArray.from(headers),
         body,
         true,
         0);
@@ -399,30 +399,30 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
           }
         });
 
-    List<SimpleArray> headers = Arrays.asList(
-            SimpleArray.of("content-type", "multipart/form-data"));
+    List<JavaOnlyArray> headers = Arrays.asList(
+            JavaOnlyArray.of("content-type", "multipart/form-data"));
 
-    SimpleMap body = new SimpleMap();
-    SimpleArray formData = new SimpleArray();
+    JavaOnlyMap body = new JavaOnlyMap();
+    JavaOnlyArray formData = new JavaOnlyArray();
     body.putArray("formData", formData);
 
-    SimpleMap bodyPart = new SimpleMap();
+    JavaOnlyMap bodyPart = new JavaOnlyMap();
     bodyPart.putString("string", "locale");
     bodyPart.putArray(
         "headers",
-        SimpleArray.from(
+        JavaOnlyArray.from(
             Arrays.asList(
-                          SimpleArray.of("content-disposition", "user"))));
+                          JavaOnlyArray.of("content-disposition", "user"))));
     formData.pushMap(bodyPart);
 
-    SimpleMap imageBodyPart = new SimpleMap();
+    JavaOnlyMap imageBodyPart = new JavaOnlyMap();
     imageBodyPart.putString("uri", "imageUri");
     imageBodyPart.putArray(
         "headers",
-        SimpleArray.from(
+        JavaOnlyArray.from(
             Arrays.asList(
-                SimpleArray.of("content-type", "image/jpg"),
-                SimpleArray.of("content-disposition", "filename=photo.jpg"))));
+                JavaOnlyArray.of("content-type", "image/jpg"),
+                JavaOnlyArray.of("content-disposition", "filename=photo.jpg"))));
     formData.pushMap(imageBodyPart);
 
     OkHttpClient httpClient = mock(OkHttpClient.class);
@@ -440,7 +440,7 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
         "POST",
         "http://someurl/uploadFoo",
         0,
-        SimpleArray.from(headers),
+        JavaOnlyArray.from(headers),
         body,
         true,
         0);
diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/storage/AsyncStorageModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/storage/AsyncStorageModuleTest.java
index 819aececc8f7..291e1604819d 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/modules/storage/AsyncStorageModuleTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/modules/storage/AsyncStorageModuleTest.java
@@ -21,8 +21,8 @@
 import com.facebook.react.bridge.Callback;
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.ReactTestHelper;
-import com.facebook.react.bridge.SimpleArray;
-import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.bridge.JavaOnlyArray;
+import com.facebook.react.bridge.JavaOnlyMap;
 import com.facebook.react.modules.storage.AsyncStorageModule;
 import com.facebook.react.modules.storage.ReactDatabaseSupplier;
 
@@ -58,7 +58,7 @@
 public class AsyncStorageModuleTest {
 
   private AsyncStorageModule mStorage;
-  private SimpleArray mEmptyArray;
+  private JavaOnlyArray mEmptyArray;
 
   @Rule
   public PowerMockRule rule = new PowerMockRule();
@@ -70,7 +70,7 @@ public void prepareModules() {
         new Answer<Object>() {
      @Override
      public Object answer(InvocationOnMock invocation) throws Throwable {
-       return new SimpleArray();
+       return new JavaOnlyArray();
      }
    });
 
@@ -78,13 +78,13 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
         new Answer<Object>() {
        @Override
        public Object answer(InvocationOnMock invocation) throws Throwable {
-         return new SimpleMap();
+         return new JavaOnlyMap();
        }
      });
 
     // don't use Robolectric before initializing mocks
     mStorage = new AsyncStorageModule(ReactTestHelper.createCatalystContextForTest());
-    mEmptyArray = new SimpleArray();
+    mEmptyArray = new JavaOnlyArray();
   }
 
   @After
@@ -100,7 +100,7 @@ public void testMultiSetMultiGet() {
     final String fakeKey = "fakeKey";
     final String value1 = "bar1";
     final String value2 = "bar2";
-    SimpleArray keyValues = new SimpleArray();
+    JavaOnlyArray keyValues = new JavaOnlyArray();
     keyValues.pushArray(getArray(key1, value1));
     keyValues.pushArray(getArray(key2, value2));
 
@@ -108,7 +108,7 @@ public void testMultiSetMultiGet() {
     mStorage.multiSet(keyValues, setCallback);
     Mockito.verify(setCallback, Mockito.times(1)).invoke();
 
-    SimpleArray keys = new SimpleArray();
+    JavaOnlyArray keys = new JavaOnlyArray();
     keys.pushString(key1);
     keys.pushString(key2);
 
@@ -117,7 +117,7 @@ public void testMultiSetMultiGet() {
     Mockito.verify(getCallback, Mockito.times(1)).invoke(null, keyValues);
 
     keys.pushString(fakeKey);
-    SimpleArray row3 = new SimpleArray();
+    JavaOnlyArray row3 = new JavaOnlyArray();
     row3.pushString(fakeKey);
     row3.pushString(null);
     keyValues.pushArray(row3);
@@ -134,12 +134,12 @@ public void testMultiRemove() {
     final String value1 = "bar1";
     final String value2 = "bar2";
 
-    SimpleArray keyValues = new SimpleArray();
+    JavaOnlyArray keyValues = new JavaOnlyArray();
     keyValues.pushArray(getArray(key1, value1));
     keyValues.pushArray(getArray(key2, value2));
     mStorage.multiSet(keyValues, mock(Callback.class));
 
-    SimpleArray keys = new SimpleArray();
+    JavaOnlyArray keys = new JavaOnlyArray();
     keys.pushString(key1);
     keys.pushString(key2);
 
@@ -173,12 +173,12 @@ public void testMultiMerge() throws Exception {
     value.put("foo3", 1001);
     value.put("foo4", createJSONObject("key1", "randomValueThatWillNeverBeUsed"));
 
-    mStorage.multiSet(SimpleArray.of(getArray(mergeKey, value.toString())), mock(Callback.class));
+    mStorage.multiSet(JavaOnlyArray.of(getArray(mergeKey, value.toString())), mock(Callback.class));
     {
       Callback callback = mock(Callback.class);
       mStorage.multiGet(getArray(mergeKey), callback);
       Mockito.verify(callback, Mockito.times(1))
-          .invoke(null, SimpleArray.of(getArray(mergeKey, value.toString())));
+          .invoke(null, JavaOnlyArray.of(getArray(mergeKey, value.toString())));
     }
 
     value.put("foo1", 1001);
@@ -193,29 +193,29 @@ public void testMultiMerge() throws Exception {
     newValue2.put("foo2", createJSONObject("key1", "val3"));
 
     mStorage.multiMerge(
-        SimpleArray.of(
-            SimpleArray.of(mergeKey, value.toString()),
-            SimpleArray.of(mergeKey, newValue.toString()),
-            SimpleArray.of(mergeKey, newValue2.toString())),
+        JavaOnlyArray.of(
+            JavaOnlyArray.of(mergeKey, value.toString()),
+            JavaOnlyArray.of(mergeKey, newValue.toString()),
+            JavaOnlyArray.of(mergeKey, newValue2.toString())),
         mock(Callback.class));
 
     value.put("foo2", createJSONObject("key1", "val3", "key2", "val2"));
     Callback callback = mock(Callback.class);
     mStorage.multiGet(getArray(mergeKey), callback);
     Mockito.verify(callback, Mockito.times(1))
-        .invoke(null, SimpleArray.of(getArray(mergeKey, value.toString())));
+        .invoke(null, JavaOnlyArray.of(getArray(mergeKey, value.toString())));
   }
 
   @Test
   public void testGetAllKeys() {
     final String[] keys = {"foo", "foo2"};
     final String[] values = {"bar", "bar2"};
-    SimpleArray keyValues = new SimpleArray();
+    JavaOnlyArray keyValues = new JavaOnlyArray();
     keyValues.pushArray(getArray(keys[0], values[0]));
     keyValues.pushArray(getArray(keys[1], values[1]));
     mStorage.multiSet(keyValues, mock(Callback.class));
 
-    SimpleArray storedKeys = new SimpleArray();
+    JavaOnlyArray storedKeys = new JavaOnlyArray();
     storedKeys.pushString(keys[0]);
     storedKeys.pushString(keys[1]);
 
@@ -237,7 +237,7 @@ public void testGetAllKeys() {
 
   @Test
   public void testClear() {
-    SimpleArray keyValues = new SimpleArray();
+    JavaOnlyArray keyValues = new JavaOnlyArray();
     keyValues.pushArray(getArray("foo", "foo2"));
     keyValues.pushArray(getArray("bar", "bar2"));
     mStorage.multiSet(keyValues, mock(Callback.class));
@@ -259,14 +259,14 @@ public void testHugeMultiGetMultiGet() {
     // and returns null for missing keys
     final int magicalNumber = 343;
 
-    SimpleArray keyValues = new SimpleArray();
+    JavaOnlyArray keyValues = new JavaOnlyArray();
     for (int i = 0; i < keyCount; i++) {
       if (i % magicalNumber > 0) {
         keyValues.pushArray(getArray("key" + i, "value" + i));
       }
     }
     mStorage.multiSet(keyValues, mock(Callback.class));
-    SimpleArray keys = new SimpleArray();
+    JavaOnlyArray keys = new JavaOnlyArray();
     for (int i = 0; i < keyCount; i++) {
       keys.pushString("key" + i);
     }
@@ -275,7 +275,7 @@ keys, new Callback() {
           @Override
           public void invoke(Object... args) {
             assertThat(args.length).isEqualTo(2);
-            SimpleArray resultArray = (SimpleArray) args[1];
+            JavaOnlyArray resultArray = (JavaOnlyArray) args[1];
 
             assertThat(resultArray.size()).isEqualTo(keyCount);
             boolean keyReceived[] = new boolean[keyCount];
@@ -297,7 +297,7 @@ public void invoke(Object... args) {
 
     // Test removal in same test, since it's costly to set up the test again.
     // Remove only odd keys
-    SimpleArray keyRemoves = new SimpleArray();
+    JavaOnlyArray keyRemoves = new JavaOnlyArray();
     for (int i = 0; i < keyCount; i++) {
       if (i % 2 > 0) {
         keyRemoves.pushString("key" + i);
@@ -308,7 +308,7 @@ public void invoke(Object... args) {
         new Callback() {
           @Override
           public void invoke(Object... args) {
-            SimpleArray resultArray = (SimpleArray) args[1];
+            JavaOnlyArray resultArray = (JavaOnlyArray) args[1];
             assertThat(resultArray.size()).isEqualTo(499);
             for (int i = 0; i < resultArray.size(); i++) {
               String key = resultArray.getString(i).substring(3);
@@ -334,8 +334,8 @@ private static JSONObject createJSONObject(Object... keysAndValues) {
     return new JSONObject(map);
   }
 
-  private SimpleArray getArray(String... values) {
-    SimpleArray array = new SimpleArray();
+  private JavaOnlyArray getArray(String... values) {
+    JavaOnlyArray array = new JavaOnlyArray();
     for (String value : values) {
       array.pushString(value);
     }
diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java
index 219bccf13b35..423480cda275 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java
@@ -14,7 +14,7 @@
 import com.facebook.react.bridge.Arguments;
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.CatalystInstance;
-import com.facebook.react.bridge.SimpleArray;
+import com.facebook.react.bridge.JavaOnlyArray;
 import com.facebook.react.uimanager.ReactChoreographer;
 import com.facebook.react.common.SystemClock;
 import com.facebook.react.modules.core.JSTimersExecution;
@@ -65,7 +65,7 @@ public void prepareModules() {
         new Answer<Object>() {
           @Override
           public Object answer(InvocationOnMock invocation) throws Throwable {
-            return new SimpleArray();
+            return new JavaOnlyArray();
           }
         });
 
@@ -109,7 +109,7 @@ public void testSimpleTimer() {
     mTiming.onHostResume();
     mTiming.createTimer(1, 0, 0, false);
     stepChoreographerFrame();
-    verify(mJSTimersMock).callTimers(SimpleArray.of(1));
+    verify(mJSTimersMock).callTimers(JavaOnlyArray.of(1));
     reset(mJSTimersMock);
     stepChoreographerFrame();
     verifyNoMoreInteractions(mJSTimersMock);
@@ -120,11 +120,11 @@ public void testSimpleRecurringTimer() {
     mTiming.createTimer(100, 0, 0, true);
     mTiming.onHostResume();
     stepChoreographerFrame();
-    verify(mJSTimersMock).callTimers(SimpleArray.of(100));
+    verify(mJSTimersMock).callTimers(JavaOnlyArray.of(100));
 
     reset(mJSTimersMock);
     stepChoreographerFrame();
-    verify(mJSTimersMock).callTimers(SimpleArray.of(100));
+    verify(mJSTimersMock).callTimers(JavaOnlyArray.of(100));
   }
 
   @Test
@@ -133,7 +133,7 @@ public void testCancelRecurringTimer() {
     mTiming.createTimer(105, 0, 0, true);
 
     stepChoreographerFrame();
-    verify(mJSTimersMock).callTimers(SimpleArray.of(105));
+    verify(mJSTimersMock).callTimers(JavaOnlyArray.of(105));
 
     reset(mJSTimersMock);
     mTiming.deleteTimer(105);
@@ -147,7 +147,7 @@ public void testPausingAndResuming() {
     mTiming.createTimer(41, 0, 0, true);
 
     stepChoreographerFrame();
-    verify(mJSTimersMock).callTimers(SimpleArray.of(41));
+    verify(mJSTimersMock).callTimers(JavaOnlyArray.of(41));
 
     reset(mJSTimersMock);
     mTiming.onHostPause();
@@ -157,7 +157,7 @@ public void testPausingAndResuming() {
     reset(mJSTimersMock);
     mTiming.onHostResume();
     stepChoreographerFrame();
-    verify(mJSTimersMock).callTimers(SimpleArray.of(41));
+    verify(mJSTimersMock).callTimers(JavaOnlyArray.of(41));
   }
 
   private static class PostFrameCallbackHandler implements Answer<Void> {
diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/LayoutPropertyApplicatorTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/LayoutPropertyApplicatorTest.java
index 155af711f7a2..5da10ac938e7 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/uimanager/LayoutPropertyApplicatorTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/LayoutPropertyApplicatorTest.java
@@ -17,7 +17,7 @@
 import com.facebook.csslayout.CSSJustify;
 import com.facebook.csslayout.CSSPositionType;
 import com.facebook.csslayout.Spacing;
-import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.bridge.JavaOnlyMap;
 
 import org.junit.After;
 import org.junit.Before;
@@ -63,7 +63,7 @@ public void teardown() {
   }
 
   public ReactStylesDiffMap buildStyles(Object... keysAndValues) {
-    return new ReactStylesDiffMap(SimpleMap.of(keysAndValues));
+    return new ReactStylesDiffMap(JavaOnlyMap.of(keysAndValues));
   }
 
   @Test
diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropAnnotationSetterTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropAnnotationSetterTest.java
index 88cbbf7d3f26..33e0b8892e8f 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropAnnotationSetterTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropAnnotationSetterTest.java
@@ -14,8 +14,8 @@
 import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.bridge.ReadableMap;
-import com.facebook.react.bridge.SimpleArray;
-import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.bridge.JavaOnlyArray;
+import com.facebook.react.bridge.JavaOnlyMap;
 import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.annotations.ReactPropGroup;
 
@@ -201,7 +201,7 @@ public void setBoxedIntGroupProp(View v, int index, Integer value) {
   }
 
   public static ReactStylesDiffMap buildStyles(Object... keysAndValues) {
-    return new ReactStylesDiffMap(SimpleMap.of(keysAndValues));
+    return new ReactStylesDiffMap(JavaOnlyMap.of(keysAndValues));
   }
 
   private ViewManagerUnderTest mViewManager;
@@ -356,7 +356,7 @@ public void testBoxedIntSetter() {
 
   @Test
   public void testArraySetter() {
-    ReadableArray array = new SimpleArray();
+    ReadableArray array = new JavaOnlyArray();
     mViewManager.updateProperties(null, buildStyles("arrayProp", array));
     verify(mUpdatesReceiverMock).onArraySetterCalled(array);
     verifyNoMoreInteractions(mUpdatesReceiverMock);
@@ -370,7 +370,7 @@ public void testArraySetter() {
 
   @Test
   public void testMapSetter() {
-    ReadableMap map = new SimpleMap();
+    ReadableMap map = new JavaOnlyMap();
     mViewManager.updateProperties(null, buildStyles("mapProp", map));
     verify(mUpdatesReceiverMock).onMapSetterCalled(map);
     verifyNoMoreInteractions(mUpdatesReceiverMock);
@@ -458,7 +458,7 @@ public void testStringGroupSetter() {
 
   @Test(expected = JSApplicationIllegalArgumentException.class)
   public void testFailToUpdateBoolPropWithMap() {
-    mViewManager.updateProperties(null, buildStyles("boolProp", new SimpleMap()));
+    mViewManager.updateProperties(null, buildStyles("boolProp", new JavaOnlyMap()));
   }
 
   @Test(expected = JSApplicationIllegalArgumentException.class)
@@ -483,7 +483,7 @@ public void testFailToUpdateArrayPropWithBool() {
 
   @Test(expected = JSApplicationIllegalArgumentException.class)
   public void testFailToUpdateMapPropWithArray() {
-    mViewManager.updateProperties(null, buildStyles("mapProp", new SimpleArray()));
+    mViewManager.updateProperties(null, buildStyles("mapProp", new JavaOnlyArray()));
   }
 
   @Test(expected = JSApplicationIllegalArgumentException.class)
diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/SimpleViewPropertyTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/SimpleViewPropertyTest.java
index 76f2b2e21839..b97941d93f3e 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/uimanager/SimpleViewPropertyTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/SimpleViewPropertyTest.java
@@ -17,7 +17,7 @@
 import com.facebook.react.touch.JSResponderHandler;
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.ReactTestHelper;
-import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.bridge.JavaOnlyMap;
 import com.facebook.react.bridge.CatalystInstance;
 import com.facebook.react.uimanager.annotations.ReactProp;
 
@@ -79,7 +79,7 @@ public void setup() {
   }
 
   public ReactStylesDiffMap buildStyles(Object... keysAndValues) {
-    return new ReactStylesDiffMap(SimpleMap.of(keysAndValues));
+    return new ReactStylesDiffMap(JavaOnlyMap.of(keysAndValues));
   }
 
   @Test
diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java
index 6752ba062908..d409752caf8a 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java
@@ -27,8 +27,8 @@
 import com.facebook.react.bridge.Arguments;
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.CatalystInstance;
-import com.facebook.react.bridge.SimpleArray;
-import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.bridge.JavaOnlyArray;
+import com.facebook.react.bridge.JavaOnlyMap;
 import com.facebook.react.views.text.ReactRawTextManager;
 import com.facebook.react.views.text.ReactTextShadowNode;
 import com.facebook.react.views.text.ReactTextViewManager;
@@ -81,13 +81,13 @@ public void setUp() {
     PowerMockito.when(Arguments.createArray()).thenAnswer(new Answer<Object>() {
       @Override
       public Object answer(InvocationOnMock invocation) throws Throwable {
-        return new SimpleArray();
+        return new JavaOnlyArray();
       }
     });
     PowerMockito.when(Arguments.createMap()).thenAnswer(new Answer<Object>() {
       @Override
       public Object answer(InvocationOnMock invocation) throws Throwable {
-        return new SimpleMap();
+        return new JavaOnlyMap();
       }
     });
     PowerMockito.when(ReactChoreographer.getInstance()).thenReturn(choreographerMock);
@@ -141,7 +141,7 @@ public void testUpdateSimpleHierarchy() {
     uiManager.updateView(
         rawTextTag,
         ReactRawTextManager.REACT_CLASS,
-        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "New text"));
+        JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "New text"));
 
     uiManager.onBatchComplete();
     executePendingChoreographerCallbacks();
@@ -163,27 +163,27 @@ public void testHierarchyWithView() {
         viewTag,
         ReactViewManager.REACT_CLASS,
         rootTag,
-        SimpleMap.of("collapsable", false));
+        JavaOnlyMap.of("collapsable", false));
     uiManager.createView(
         subViewTag,
         ReactViewManager.REACT_CLASS,
         rootTag,
-        SimpleMap.of("collapsable", false));
+        JavaOnlyMap.of("collapsable", false));
 
     uiManager.manageChildren(
         viewTag,
         null,
         null,
-        SimpleArray.of(subViewTag),
-        SimpleArray.of(0),
+        JavaOnlyArray.of(subViewTag),
+        JavaOnlyArray.of(0),
         null);
 
     uiManager.manageChildren(
         rootTag,
         null,
         null,
-        SimpleArray.of(viewTag),
-        SimpleArray.of(0),
+        JavaOnlyArray.of(viewTag),
+        JavaOnlyArray.of(0),
         null);
 
     uiManager.onBatchComplete();
@@ -211,8 +211,8 @@ public void testMoveViews() {
 
     uiManager.manageChildren(
         hierarchy.rootView,
-        SimpleArray.of(1, 0, 2),
-        SimpleArray.of(0, 2, 1),
+        JavaOnlyArray.of(1, 0, 2),
+        JavaOnlyArray.of(0, 2, 1),
         null,
         null,
         null);
@@ -242,7 +242,7 @@ public void testDeleteViews() {
         null,
         null,
         null,
-        SimpleArray.of(0, 3));
+        JavaOnlyArray.of(0, 3));
 
     uiManager.onBatchComplete();
     executePendingChoreographerCallbacks();
@@ -264,11 +264,11 @@ public void testMoveAndDeleteViews() {
 
     uiManager.manageChildren(
         hierarchy.rootView,
-        SimpleArray.of(3),
-        SimpleArray.of(1),
+        JavaOnlyArray.of(3),
+        JavaOnlyArray.of(1),
         null,
         null,
-        SimpleArray.of(1));
+        JavaOnlyArray.of(1));
 
     uiManager.onBatchComplete();
     executePendingChoreographerCallbacks();
@@ -287,11 +287,11 @@ public void testMoveAndDeleteRemoveViewsDuplicateRemove() {
 
     uiManager.manageChildren(
         hierarchy.rootView,
-        SimpleArray.of(3),
-        SimpleArray.of(1),
+        JavaOnlyArray.of(3),
+        JavaOnlyArray.of(1),
         null,
         null,
-        SimpleArray.of(3));
+        JavaOnlyArray.of(3));
 
     uiManager.onBatchComplete();
     executePendingChoreographerCallbacks();
@@ -308,7 +308,7 @@ public void testDuplicateRemove() {
         null,
         null,
         null,
-        SimpleArray.of(3, 3));
+        JavaOnlyArray.of(3, 3));
 
     uiManager.onBatchComplete();
     executePendingChoreographerCallbacks();
@@ -324,7 +324,7 @@ public void testMoveAndAddViews() {
         textViewTag,
         ReactTextViewManager.REACT_CLASS,
         hierarchy.rootView,
-        SimpleMap.of("collapsable", false));
+        JavaOnlyMap.of("collapsable", false));
 
     View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(0);
     View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(3);
@@ -333,10 +333,10 @@ public void testMoveAndAddViews() {
 
     uiManager.manageChildren(
         hierarchy.rootView,
-        SimpleArray.of(1, 2, 3),
-        SimpleArray.of(3, 4, 1),
-        SimpleArray.of(textViewTag),
-        SimpleArray.of(2),
+        JavaOnlyArray.of(1, 2, 3),
+        JavaOnlyArray.of(3, 4, 1),
+        JavaOnlyArray.of(textViewTag),
+        JavaOnlyArray.of(2),
         null);
 
     uiManager.onBatchComplete();
@@ -361,8 +361,8 @@ public void testMoveViewsWithChildren() {
 
     uiManager.manageChildren(
         hierarchy.rootView,
-        SimpleArray.of(1, 2),
-        SimpleArray.of(2, 1),
+        JavaOnlyArray.of(1, 2),
+        JavaOnlyArray.of(2, 1),
         null,
         null,
         null);
@@ -394,7 +394,7 @@ public void testDeleteViewsWithChildren() {
         null,
         null,
         null,
-        SimpleArray.of(1));
+        JavaOnlyArray.of(1));
 
     uiManager.onBatchComplete();
     executePendingChoreographerCallbacks();
@@ -417,15 +417,15 @@ public void testLayoutAppliedToNodes() throws Exception {
         newViewTag,
         ReactViewManager.REACT_CLASS,
         hierarchy.rootView,
-        SimpleMap
+        JavaOnlyMap
             .of("left", 10.0, "top", 20.0, "width", 30.0, "height", 40.0, "collapsable", false));
 
     uiManager.manageChildren(
         hierarchy.rootView,
         null,
         null,
-        SimpleArray.of(newViewTag),
-        SimpleArray.of(4),
+        JavaOnlyArray.of(newViewTag),
+        JavaOnlyArray.of(4),
         null);
 
     uiManager.onBatchComplete();
@@ -453,20 +453,20 @@ public void testAddUpdateRemoveInSingleBatch() {
         newViewTag,
         ReactViewManager.REACT_CLASS,
         hierarchy.rootView,
-        SimpleMap.of("collapsable", false));
+        JavaOnlyMap.of("collapsable", false));
 
     uiManager.manageChildren(
         hierarchy.rootView,
         null,
         null,
-        SimpleArray.of(newViewTag),
-        SimpleArray.of(4),
+        JavaOnlyArray.of(newViewTag),
+        JavaOnlyArray.of(4),
         null);
 
     uiManager.updateView(
         newViewTag,
         ReactViewManager.REACT_CLASS,
-        SimpleMap.of("backgroundColor", Color.RED));
+        JavaOnlyMap.of("backgroundColor", Color.RED));
 
     uiManager.manageChildren(
         hierarchy.rootView,
@@ -474,7 +474,7 @@ public void testAddUpdateRemoveInSingleBatch() {
         null,
         null,
         null,
-        SimpleArray.of(4));
+        JavaOnlyArray.of(4));
 
     uiManager.onBatchComplete();
     executePendingChoreographerCallbacks();
@@ -521,7 +521,7 @@ public void testLayoutPropertyUpdatingOnlyOnLayoutChange() {
     uiManager.updateView(
         hierarchy.view0,
         ReactViewManager.REACT_CLASS,
-        SimpleMap.of("left", 10.0, "top", 20.0, "width", 30.0, "height", 40.0));
+        JavaOnlyMap.of("left", 10.0, "top", 20.0, "width", 30.0, "height", 40.0));
     uiManager.onBatchComplete();
     executePendingChoreographerCallbacks();
     assertThat(view0.getLeft()).isGreaterThan(2);
@@ -532,7 +532,7 @@ public void testLayoutPropertyUpdatingOnlyOnLayoutChange() {
     uiManager.updateView(
         hierarchy.view0,
         ReactViewManager.REACT_CLASS,
-        SimpleMap.of("backgroundColor", Color.RED));
+        JavaOnlyMap.of("backgroundColor", Color.RED));
     uiManager.onBatchComplete();
     executePendingChoreographerCallbacks();
     assertThat(view0.getLeft()).isEqualTo(1);
@@ -563,7 +563,7 @@ public void testAddAndRemoveAnimation() {
         hierarchy.rootView,
         ReactViewManager.REACT_CLASS,
         rootTag,
-        SimpleMap.of("collapsable", false));
+        JavaOnlyMap.of("collapsable", false));
 
     uiManagerModule.registerAnimation(mockAnimation);
     uiManagerModule.addAnimation(hierarchy.rootView, 1000, callbackMock);
@@ -591,7 +591,7 @@ public void testReplaceExistingNonRootView() {
         newViewTag,
         ReactViewManager.REACT_CLASS,
         hierarchy.rootView,
-        SimpleMap.of("backgroundColor", Color.RED));
+        JavaOnlyMap.of("backgroundColor", Color.RED));
 
     uiManager.replaceExistingNonRootView(hierarchy.view2, newViewTag);
 
@@ -622,12 +622,12 @@ public void testRemoveSubviewsFromContainerWithID() {
         containerTag,
         ReactViewManager.REACT_CLASS,
         rootTag,
-        SimpleMap.of("collapsable", false));
+        JavaOnlyMap.of("collapsable", false));
     uiManager.createView(
         containerSiblingTag,
         ReactViewManager.REACT_CLASS,
         rootTag,
-        SimpleMap.of("collapsable", false));
+        JavaOnlyMap.of("collapsable", false));
     addChild(uiManager, rootTag, containerTag, 0);
     addChild(uiManager, rootTag, containerSiblingTag, 1);
 
@@ -635,12 +635,12 @@ public void testRemoveSubviewsFromContainerWithID() {
         containerTag + 2,
         ReactTextViewManager.REACT_CLASS,
         rootTag,
-        SimpleMap.of("collapsable", false));
+        JavaOnlyMap.of("collapsable", false));
     uiManager.createView(
         containerTag + 3,
         ReactTextViewManager.REACT_CLASS,
         rootTag,
-        SimpleMap.of("collapsable", false));
+        JavaOnlyMap.of("collapsable", false));
     addChild(uiManager, containerTag, containerTag + 2, 0);
     addChild(uiManager, containerTag, containerTag + 3, 1);
 
@@ -674,27 +674,27 @@ private ViewGroup createSimpleTextHierarchy(UIManagerModule uiManager, String te
         textTag,
         ReactTextViewManager.REACT_CLASS,
         rootTag,
-        SimpleMap.of("collapsable", false));
+        JavaOnlyMap.of("collapsable", false));
     uiManager.createView(
         rawTextTag,
         ReactRawTextManager.REACT_CLASS,
         rootTag,
-        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, text, "collapsable", false));
+        JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, text, "collapsable", false));
 
     uiManager.manageChildren(
         textTag,
         null,
         null,
-        SimpleArray.of(rawTextTag),
-        SimpleArray.of(0),
+        JavaOnlyArray.of(rawTextTag),
+        JavaOnlyArray.of(0),
         null);
 
     uiManager.manageChildren(
         rootTag,
         null,
         null,
-        SimpleArray.of(textTag),
-        SimpleArray.of(0),
+        JavaOnlyArray.of(textTag),
+        JavaOnlyArray.of(0),
         null);
 
     uiManager.onBatchComplete();
@@ -713,32 +713,32 @@ private TestMoveDeleteHierarchy createMoveDeleteHierarchy(UIManagerModule uiMana
         hierarchy.view0,
         ReactViewManager.REACT_CLASS,
         rootTag,
-        SimpleMap.of("collapsable", false));
+        JavaOnlyMap.of("collapsable", false));
     uiManager.createView(
         hierarchy.viewWithChildren1,
         ReactViewManager.REACT_CLASS,
         rootTag,
-        SimpleMap.of("collapsable", false));
+        JavaOnlyMap.of("collapsable", false));
     uiManager.createView(
         hierarchy.view2,
         ReactViewManager.REACT_CLASS,
         rootTag,
-        SimpleMap.of("collapsable", false));
+        JavaOnlyMap.of("collapsable", false));
     uiManager.createView(
         hierarchy.view3,
         ReactViewManager.REACT_CLASS,
         rootTag,
-        SimpleMap.of("collapsable", false));
+        JavaOnlyMap.of("collapsable", false));
     uiManager.createView(
         hierarchy.childView0,
         ReactViewManager.REACT_CLASS,
         rootTag,
-        SimpleMap.of("collapsable", false));
+        JavaOnlyMap.of("collapsable", false));
     uiManager.createView(
         hierarchy.childView1,
         ReactViewManager.REACT_CLASS,
         rootTag,
-        SimpleMap.of("collapsable", false));
+        JavaOnlyMap.of("collapsable", false));
 
     addChild(uiManager, rootTag, hierarchy.view0, 0);
     addChild(uiManager, rootTag, hierarchy.viewWithChildren1, 1);
@@ -759,8 +759,8 @@ private void addChild(UIManagerModule uiManager, int parentTag, int childTag, in
         parentTag,
         null,
         null,
-        SimpleArray.of(childTag),
-        SimpleArray.of(index),
+        JavaOnlyArray.of(childTag),
+        JavaOnlyArray.of(index),
         null);
   }
 
diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/image/ReactImagePropertyTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/image/ReactImagePropertyTest.java
index 030ce793e075..c029d4653e32 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/views/image/ReactImagePropertyTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/views/image/ReactImagePropertyTest.java
@@ -17,7 +17,7 @@
 import com.facebook.react.bridge.ReactTestHelper;
 import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
 import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.bridge.JavaOnlyMap;
 import com.facebook.react.uimanager.ReactStylesDiffMap;
 import com.facebook.react.uimanager.DisplayMetricsHolder;
 import com.facebook.react.uimanager.ThemedReactContext;
@@ -68,7 +68,7 @@ public void teardown() {
   }
 
   public ReactStylesDiffMap buildStyles(Object... keysAndValues) {
-    return new ReactStylesDiffMap(SimpleMap.of(keysAndValues));
+    return new ReactStylesDiffMap(JavaOnlyMap.of(keysAndValues));
   }
 
   @Test(expected=JSApplicationIllegalArgumentException.class)
diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java
index d710ffbd8718..f23128ab3dd5 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java
@@ -21,17 +21,17 @@
 import android.os.Build;
 import android.text.Spanned;
 import android.text.TextUtils;
-import android.util.DisplayMetrics;
 import android.text.style.AbsoluteSizeSpan;
+import android.util.DisplayMetrics;
 import android.view.Choreographer;
 import android.widget.TextView;
 
 import com.facebook.react.ReactRootView;
 import com.facebook.react.bridge.Arguments;
-import com.facebook.react.bridge.ReactTestHelper;
+import com.facebook.react.bridge.JavaOnlyArray;
+import com.facebook.react.bridge.JavaOnlyMap;
 import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.SimpleArray;
-import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.bridge.ReactTestHelper;
 import com.facebook.react.uimanager.DisplayMetricsHolder;
 import com.facebook.react.uimanager.ReactChoreographer;
 import com.facebook.react.uimanager.UIImplementation;
@@ -40,8 +40,8 @@
 import com.facebook.react.uimanager.ViewProps;
 
 import org.junit.Before;
-import org.junit.Test;
 import org.junit.Rule;
+import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
@@ -49,7 +49,6 @@
 import org.powermock.core.classloader.annotations.PowerMockIgnore;
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.rule.PowerMockRule;
-import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
@@ -79,7 +78,7 @@ public void setUp() {
     PowerMockito.when(Arguments.createMap()).thenAnswer(new Answer<Object>() {
       @Override
       public Object answer(InvocationOnMock invocation) throws Throwable {
-        return new SimpleMap();
+        return new JavaOnlyMap();
       }
     });
     PowerMockito.when(ReactChoreographer.getInstance()).thenReturn(choreographerMock);
@@ -103,8 +102,8 @@ public void testFontSizeApplied() {
 
     ReactRootView rootView = createText(
         uiManager,
-        SimpleMap.of(ViewProps.FONT_SIZE, 21.0),
-        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+        JavaOnlyMap.of(ViewProps.FONT_SIZE, 21.0),
+        JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
 
     AbsoluteSizeSpan sizeSpan = getSingleSpan(
         (TextView) rootView.getChildAt(0), AbsoluteSizeSpan.class);
@@ -117,8 +116,8 @@ public void testBoldFontApplied() {
 
     ReactRootView rootView = createText(
         uiManager,
-        SimpleMap.of(ViewProps.FONT_WEIGHT, "bold"),
-        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+        JavaOnlyMap.of(ViewProps.FONT_WEIGHT, "bold"),
+        JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
 
     CustomStyleSpan customStyleSpan =
         getSingleSpan((TextView)rootView.getChildAt(0), CustomStyleSpan.class);
@@ -132,8 +131,8 @@ public void testNumericBoldFontApplied() {
 
     ReactRootView rootView = createText(
         uiManager,
-        SimpleMap.of(ViewProps.FONT_WEIGHT, "500"),
-        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+        JavaOnlyMap.of(ViewProps.FONT_WEIGHT, "500"),
+        JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
 
     CustomStyleSpan customStyleSpan =
         getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
@@ -147,8 +146,8 @@ public void testItalicFontApplied() {
 
     ReactRootView rootView = createText(
         uiManager,
-        SimpleMap.of(ViewProps.FONT_STYLE, "italic"),
-        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+        JavaOnlyMap.of(ViewProps.FONT_STYLE, "italic"),
+        JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
 
     CustomStyleSpan customStyleSpan =
         getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
@@ -162,8 +161,8 @@ public void testBoldItalicFontApplied() {
 
     ReactRootView rootView = createText(
         uiManager,
-        SimpleMap.of(ViewProps.FONT_WEIGHT, "bold", ViewProps.FONT_STYLE, "italic"),
-        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+        JavaOnlyMap.of(ViewProps.FONT_WEIGHT, "bold", ViewProps.FONT_STYLE, "italic"),
+        JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
 
     CustomStyleSpan customStyleSpan =
         getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
@@ -177,8 +176,8 @@ public void testNormalFontWeightApplied() {
 
     ReactRootView rootView = createText(
         uiManager,
-        SimpleMap.of(ViewProps.FONT_WEIGHT, "normal"),
-        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+        JavaOnlyMap.of(ViewProps.FONT_WEIGHT, "normal"),
+        JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
 
     CustomStyleSpan customStyleSpan =
         getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
@@ -191,8 +190,8 @@ public void testNumericNormalFontWeightApplied() {
 
     ReactRootView rootView = createText(
         uiManager,
-        SimpleMap.of(ViewProps.FONT_WEIGHT, "200"),
-        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+        JavaOnlyMap.of(ViewProps.FONT_WEIGHT, "200"),
+        JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
 
     CustomStyleSpan customStyleSpan =
         getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
@@ -205,8 +204,8 @@ public void testNormalFontStyleApplied() {
 
     ReactRootView rootView = createText(
         uiManager,
-        SimpleMap.of(ViewProps.FONT_STYLE, "normal"),
-        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+        JavaOnlyMap.of(ViewProps.FONT_STYLE, "normal"),
+        JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
 
     CustomStyleSpan customStyleSpan =
         getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
@@ -219,8 +218,8 @@ public void testFontFamilyStyleApplied() {
 
     ReactRootView rootView = createText(
         uiManager,
-        SimpleMap.of(ViewProps.FONT_FAMILY, "sans-serif"),
-        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+        JavaOnlyMap.of(ViewProps.FONT_FAMILY, "sans-serif"),
+        JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
 
     CustomStyleSpan customStyleSpan =
         getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
@@ -235,8 +234,8 @@ public void testFontFamilyBoldStyleApplied() {
 
     ReactRootView rootView = createText(
         uiManager,
-        SimpleMap.of(ViewProps.FONT_FAMILY, "sans-serif", ViewProps.FONT_WEIGHT, "bold"),
-        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+        JavaOnlyMap.of(ViewProps.FONT_FAMILY, "sans-serif", ViewProps.FONT_WEIGHT, "bold"),
+        JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
 
     CustomStyleSpan customStyleSpan =
         getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
@@ -251,8 +250,8 @@ public void testFontFamilyItalicStyleApplied() {
 
     ReactRootView rootView = createText(
         uiManager,
-        SimpleMap.of(ViewProps.FONT_FAMILY, "sans-serif", ViewProps.FONT_STYLE, "italic"),
-        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+        JavaOnlyMap.of(ViewProps.FONT_FAMILY, "sans-serif", ViewProps.FONT_STYLE, "italic"),
+        JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
 
     CustomStyleSpan customStyleSpan =
         getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
@@ -267,11 +266,11 @@ public void testFontFamilyBoldItalicStyleApplied() {
 
     ReactRootView rootView = createText(
         uiManager,
-        SimpleMap.of(
+        JavaOnlyMap.of(
             ViewProps.FONT_FAMILY, "sans-serif",
             ViewProps.FONT_WEIGHT, "500",
             ViewProps.FONT_STYLE, "italic"),
-        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+        JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
 
     CustomStyleSpan customStyleSpan =
         getSingleSpan((TextView) rootView.getChildAt(0), CustomStyleSpan.class);
@@ -286,8 +285,8 @@ public void testBackgroundColorStyleApplied() {
 
     ReactRootView rootView = createText(
         uiManager,
-        SimpleMap.of(ViewProps.BACKGROUND_COLOR, Color.BLUE),
-        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+        JavaOnlyMap.of(ViewProps.BACKGROUND_COLOR, Color.BLUE),
+        JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
 
     Drawable backgroundDrawable = ((TextView) rootView.getChildAt(0)).getBackground();
     assertThat(((ColorDrawable) backgroundDrawable).getColor()).isEqualTo(Color.BLUE);
@@ -302,8 +301,8 @@ public void testMaxLinesApplied() {
 
     ReactRootView rootView = createText(
         uiManager,
-        SimpleMap.of(ViewProps.NUMBER_OF_LINES, 2),
-        SimpleMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
+        JavaOnlyMap.of(ViewProps.NUMBER_OF_LINES, 2),
+        JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "test text"));
 
     TextView textView = (TextView) rootView.getChildAt(0);
     assertThat(textView.getText().toString()).isEqualTo("test text");
@@ -323,8 +322,8 @@ private static <TSPAN> TSPAN getSingleSpan(TextView textView, Class<TSPAN> spanC
 
   private ReactRootView createText(
       UIManagerModule uiManager,
-      SimpleMap textProps,
-      SimpleMap rawTextProps) {
+      JavaOnlyMap textProps,
+      JavaOnlyMap rawTextProps) {
     ReactRootView rootView = new ReactRootView(RuntimeEnvironment.application);
     int rootTag = uiManager.addMeasuredRootView(rootView);
     int textTag = rootTag + 1;
@@ -345,16 +344,16 @@ private ReactRootView createText(
         textTag,
         null,
         null,
-        SimpleArray.of(rawTextTag),
-        SimpleArray.of(0),
+        JavaOnlyArray.of(rawTextTag),
+        JavaOnlyArray.of(0),
         null);
 
     uiManager.manageChildren(
         rootTag,
         null,
         null,
-        SimpleArray.of(textTag),
-        SimpleArray.of(0),
+        JavaOnlyArray.of(textTag),
+        JavaOnlyArray.of(0),
         null);
 
     uiManager.onBatchComplete();
diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.java
index a423801991f5..08489bbc0257 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.java
@@ -20,7 +20,7 @@
 import com.facebook.react.bridge.ReactTestHelper;
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.JSApplicationCausedNativeException;
-import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.bridge.JavaOnlyMap;
 import com.facebook.react.uimanager.ReactStylesDiffMap;
 import com.facebook.react.uimanager.DisplayMetricsHolder;
 import com.facebook.react.views.text.DefaultStyleValuesUtil;
@@ -64,7 +64,7 @@ public void setup() {
   }
 
   public ReactStylesDiffMap buildStyles(Object... keysAndValues) {
-    return new ReactStylesDiffMap(SimpleMap.of(keysAndValues));
+    return new ReactStylesDiffMap(JavaOnlyMap.of(keysAndValues));
   }
 
   @Test
diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java
index 59871f217a12..ef89b7df0029 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java
@@ -19,10 +19,10 @@
 
 import com.facebook.react.ReactRootView;
 import com.facebook.react.bridge.Arguments;
-import com.facebook.react.bridge.ReactTestHelper;
+import com.facebook.react.bridge.JavaOnlyArray;
+import com.facebook.react.bridge.JavaOnlyMap;
 import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.SimpleArray;
-import com.facebook.react.bridge.SimpleMap;
+import com.facebook.react.bridge.ReactTestHelper;
 import com.facebook.react.uimanager.DisplayMetricsHolder;
 import com.facebook.react.uimanager.ReactChoreographer;
 import com.facebook.react.uimanager.UIImplementation;
@@ -31,8 +31,8 @@
 import com.facebook.react.uimanager.ViewProps;
 
 import org.junit.Before;
-import org.junit.Test;
 import org.junit.Rule;
+import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
@@ -40,7 +40,6 @@
 import org.powermock.core.classloader.annotations.PowerMockIgnore;
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.rule.PowerMockRule;
-import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
@@ -70,7 +69,7 @@ public void setUp() {
     PowerMockito.when(Arguments.createMap()).thenAnswer(new Answer<Object>() {
       @Override
       public Object answer(InvocationOnMock invocation) throws Throwable {
-        return new SimpleMap();
+        return new JavaOnlyMap();
       }
     });
     PowerMockito.when(ReactChoreographer.getInstance()).thenReturn(choreographerMock);
@@ -101,15 +100,15 @@ public void testPropsApplied() {
         textInputTag,
         ReactTextInputManager.REACT_CLASS,
         rootTag,
-        SimpleMap.of(
+        JavaOnlyMap.of(
             ViewProps.FONT_SIZE, 13.37, ViewProps.HEIGHT, 20.0, "placeholder", hintStr));
 
     uiManager.manageChildren(
         rootTag,
         null,
         null,
-        SimpleArray.of(textInputTag),
-        SimpleArray.of(0),
+        JavaOnlyArray.of(textInputTag),
+        JavaOnlyArray.of(0),
         null);
 
     uiManager.onBatchComplete();
@@ -134,15 +133,15 @@ public void testPropsUpdate() {
         textInputTag,
         ReactTextInputManager.REACT_CLASS,
         rootTag,
-        SimpleMap.of(
+        JavaOnlyMap.of(
             ViewProps.FONT_SIZE, 13.37, ViewProps.HEIGHT, 20.0, "placeholder", hintStr));
 
     uiManager.manageChildren(
         rootTag,
         null,
         null,
-        SimpleArray.of(textInputTag),
-        SimpleArray.of(0),
+        JavaOnlyArray.of(textInputTag),
+        JavaOnlyArray.of(0),
         null);
     uiManager.onBatchComplete();
     executePendingChoreographerCallbacks();
@@ -156,7 +155,7 @@ public void testPropsUpdate() {
     uiManager.updateView(
         textInputTag,
         ReactTextInputManager.REACT_CLASS,
-        SimpleMap.of(
+        JavaOnlyMap.of(
             ViewProps.FONT_SIZE, 26.74, ViewProps.HEIGHT, 40.0, "placeholder", hintStr2));
 
     uiManager.onBatchComplete();

From e0f0bd28320149598d6132d146d86f8f1082b17d Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Tue, 9 Feb 2016 08:32:49 -0800
Subject: [PATCH 1093/1411] New release process: simplify installArchives

Summary:
Output the Android artifacts in the new location so we can simply
do `./gradlew :ReactAndroid:installArchives` and `npm publish`.

**Test Plan**

Same as test plan of https://github.com/facebook/react-native/commit/702f999b050d50286d7a222587772bf4d2f7c557 without having to manually move the artifacts.

public

Reviewed By: bestander

Differential Revision: D2916664

fb-gh-sync-id: 27dcc711b3055a5a6c554ed1e69cf4a64add849c
shipit-source-id: 27dcc711b3055a5a6c554ed1e69cf4a64add849c
---
 ReactAndroid/release.gradle | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/ReactAndroid/release.gradle b/ReactAndroid/release.gradle
index 9b8cd35a8b0f..d57754dbeabb 100644
--- a/ReactAndroid/release.gradle
+++ b/ReactAndroid/release.gradle
@@ -117,12 +117,8 @@ afterEvaluate { project ->
     task installArchives(type: Upload) {
         configuration = configurations.archives
         repositories.mavenDeployer {
-            beforeDeployment {
-                MavenDeployment deployment -> signing.signPom(deployment)
-            }
-
-            repository url: "file://${System.properties['user.home']}/.m2/repository"
-            configureReactNativePom pom
+            // Deploy to react-native/android, ready to publish to npm
+            repository url: "file://${projectDir}/../android"
         }
     }
 }

From 54da3926d9bac84a9880b062510ab5892bb2b2be Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Tue, 9 Feb 2016 09:15:36 -0800
Subject: [PATCH 1094/1411] Make the docs of time and date picker in order

Summary: Closes https://github.com/facebook/react-native/pull/5841

Reviewed By: svcscm

Differential Revision: D2916710

Pulled By: androidtrunkagent

fb-gh-sync-id: b698cefc29ded291952b35feaad86cff023c8c6e
shipit-source-id: b698cefc29ded291952b35feaad86cff023c8c6e
---
 website/server/extractDocs.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/website/server/extractDocs.js b/website/server/extractDocs.js
index 48e4dfb6b8db..6cbbc489f315 100644
--- a/website/server/extractDocs.js
+++ b/website/server/extractDocs.js
@@ -235,6 +235,7 @@ var apis = [
   '../Libraries/Storage/AsyncStorage.js',
   '../Libraries/Utilities/BackAndroid.android.js',
   '../Libraries/CameraRoll/CameraRoll.js',
+  '../Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js',
   '../Libraries/Utilities/Dimensions.js',
   '../Libraries/Components/Intent/IntentAndroid.android.js',
   '../Libraries/Interaction/InteractionManager.js',
@@ -248,10 +249,9 @@ var apis = [
   '../Libraries/PushNotificationIOS/PushNotificationIOS.js',
   '../Libraries/Components/StatusBar/StatusBarIOS.ios.js',
   '../Libraries/StyleSheet/StyleSheet.js',
+  '../Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js',
   '../Libraries/Components/ToastAndroid/ToastAndroid.android.js',
   '../Libraries/Vibration/VibrationIOS.ios.js',
-  '../Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js',
-  '../Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js',
 ];
 
 var stylesWithPermalink = [

From 157b5274b75ffb4a338d35272ba2ae49e7054558 Mon Sep 17 00:00:00 2001
From: Corentin Smith <corentin.smith@gmail.com>
Date: Tue, 9 Feb 2016 10:22:27 -0800
Subject: [PATCH 1095/1411] Update debugging docs with YellowBox/RedBox

Summary:
See https://github.com/facebook/react-native/issues/5271
Closes https://github.com/facebook/react-native/pull/5737

Reviewed By: svcscm

Differential Revision: D2917002

Pulled By: mkonicek

fb-gh-sync-id: 9c7cb62b3141d8af1b0213c795cf7c3f334eecd6
shipit-source-id: 9c7cb62b3141d8af1b0213c795cf7c3f334eecd6
---
 docs/Debugging.md | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/docs/Debugging.md b/docs/Debugging.md
index 6391d516a35e..3e7793aabdb3 100644
--- a/docs/Debugging.md
+++ b/docs/Debugging.md
@@ -20,9 +20,19 @@ To access the in-app developer menu:
 > 1. For iOS open your project in Xcode and select `Product` → `Scheme` → `Edit Scheme...` (or press `⌘ + <`). Next, select `Run` from the menu on the left and change the Build Configuration to `Release`.
 > 2. For Android, by default, developer menu will be disabled in release builds done by gradle (e.g with gradle `assembleRelease` task). Although this behavior can be customized by passing proper value to `ReactInstanceManager#setUseDeveloperSupport`.
 
+### Android logging
+Run `adb logcat *:S ReactNative:V ReactNativeJS:V` in a terminal to see your Android app's logs.
+
 ### Reload
 Selecting `Reload` (or pressing `⌘ + r` in the iOS simulator) will reload the JavaScript that powers your application. If you have added new resources (such as an image to `Images.xcassets` on iOS or to `res/drawable` folder on Android) or modified any native code (Objective-C/Swift code on iOS or Java/C++ code on Android), you will need to re-build the app for the changes to take effect.
 
+### YellowBox/RedBox
+Using `console.warn` will display an on-screen log on a yellow background. Click on this warning to show more information about it full screen and/or dismiss the warning.
+
+You can use `console.error` to display a full screen error on a red background.
+
+These boxes only appear when you're running your app in dev mode.
+
 ### Chrome Developer Tools
 To debug the JavaScript code in Chrome, select `Debug in Chrome` from the developer menu. This will open a new tab at [http://localhost:8081/debugger-ui](http://localhost:8081/debugger-ui).
 

From 1d561fd604800164134c9c95d10c3b596898a2f5 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Tue, 9 Feb 2016 10:29:33 -0800
Subject: [PATCH 1096/1411] New release process: Fix installArchives

Reviewed By: mkonicek

Differential Revision:D2917191
Ninja: Only related to open source React Native, does not affect any fb apps

fb-gh-sync-id: c4fc80ebdd520942e75161a4a30ea4d18030bec4
shipit-source-id: c4fc80ebdd520942e75161a4a30ea4d18030bec4
---
 ReactAndroid/release.gradle | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/ReactAndroid/release.gradle b/ReactAndroid/release.gradle
index d57754dbeabb..e5b34d73cc79 100644
--- a/ReactAndroid/release.gradle
+++ b/ReactAndroid/release.gradle
@@ -119,6 +119,8 @@ afterEvaluate { project ->
         repositories.mavenDeployer {
             // Deploy to react-native/android, ready to publish to npm
             repository url: "file://${projectDir}/../android"
+            
+            configureReactNativePom pom
         }
     }
 }

From 229c8c35c940318102daaa6d1a654f773ecffd2f Mon Sep 17 00:00:00 2001
From: Chris Hopman <cjhopman@fb.com>
Date: Tue, 9 Feb 2016 12:59:33 -0800
Subject: [PATCH 1097/1411] Remove jni dependencies from Bridge.h/cpp

Reviewed By: astreet

Differential Revision: D2905191

fb-gh-sync-id: 7510ef1d1b87ff50f35195d5ca8c0dd98f81526f
shipit-source-id: 7510ef1d1b87ff50f35195d5ca8c0dd98f81526f
---
 ReactAndroid/src/main/jni/react/Android.mk    |  2 +-
 ReactAndroid/src/main/jni/react/BUCK          |  1 +
 ReactAndroid/src/main/jni/react/Bridge.cpp    |  5 +---
 ReactAndroid/src/main/jni/react/Bridge.h      | 10 ++-----
 .../src/main/jni/react/jni/OnLoad.cpp         | 30 +++++++++++--------
 ReactAndroid/src/main/jni/react/jni/OnLoad.h  |  6 ++++
 .../src/main/jni/react/jni/ProxyExecutor.h    |  2 +-
 7 files changed, 29 insertions(+), 27 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/Android.mk b/ReactAndroid/src/main/jni/react/Android.mk
index 3e3fbe247f98..073d091577cc 100644
--- a/ReactAndroid/src/main/jni/react/Android.mk
+++ b/ReactAndroid/src/main/jni/react/Android.mk
@@ -19,7 +19,7 @@ LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
 LOCAL_CFLAGS := \
   -DLOG_TAG=\"ReactNative\"
 
-LOCAL_CFLAGS += -Wall -Werror -fexceptions
+LOCAL_CFLAGS += -Wall -Werror -fexceptions -frtti
 CXX11_FLAGS := -std=c++11
 LOCAL_CFLAGS += $(CXX11_FLAGS)
 LOCAL_EXPORT_CPPFLAGS := $(CXX11_FLAGS)
diff --git a/ReactAndroid/src/main/jni/react/BUCK b/ReactAndroid/src/main/jni/react/BUCK
index 2835903f46ca..8bafe44d28aa 100644
--- a/ReactAndroid/src/main/jni/react/BUCK
+++ b/ReactAndroid/src/main/jni/react/BUCK
@@ -71,5 +71,6 @@ react_library(
     '-std=c++11',
     '-fexceptions',
     '-fvisibility=hidden',
+    '-frtti',
   ],
 )
diff --git a/ReactAndroid/src/main/jni/react/Bridge.cpp b/ReactAndroid/src/main/jni/react/Bridge.cpp
index 93ba78e5a812..a4bb6887eb2a 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.cpp
+++ b/ReactAndroid/src/main/jni/react/Bridge.cpp
@@ -2,9 +2,6 @@
 
 #include "Bridge.h"
 
-#include "Executor.h"
-#include "MethodCall.h"
-
 #ifdef WITH_FBSYSTRACE
 #include <fbsystrace.h>
 using fbsystrace::FbSystraceSection;
@@ -13,7 +10,7 @@ using fbsystrace::FbSystraceSection;
 namespace facebook {
 namespace react {
 
-Bridge::Bridge(const RefPtr<CountableJSExecutorFactory>& jsExecutorFactory, Callback callback) :
+Bridge::Bridge(JSExecutorFactory* jsExecutorFactory, Callback callback) :
   m_callback(std::move(callback)),
   m_destroyed(std::shared_ptr<bool>(new bool(false)))
 {
diff --git a/ReactAndroid/src/main/jni/react/Bridge.h b/ReactAndroid/src/main/jni/react/Bridge.h
index cbc6c7a982c8..26b1aa8ef9f6 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.h
+++ b/ReactAndroid/src/main/jni/react/Bridge.h
@@ -5,9 +5,6 @@
 #include <functional>
 #include <map>
 #include <vector>
-#include <jni.h>
-#include <fb/Countable.h>
-#include <fb/RefPtr.h>
 #include "Value.h"
 #include "Executor.h"
 #include "MethodCall.h"
@@ -22,14 +19,11 @@ struct dynamic;
 namespace facebook {
 namespace react {
 
-class CountableJSExecutorFactory : public JSExecutorFactory, public Countable {
-};
-
-class Bridge : public Countable {
+class Bridge {
 public:
   typedef std::function<void(std::vector<MethodCall>, bool isEndOfBatch)> Callback;
 
-  Bridge(const RefPtr<CountableJSExecutorFactory>& jsExecutorFactory, Callback callback);
+  Bridge(JSExecutorFactory* jsExecutorFactory, Callback callback);
   virtual ~Bridge();
 
   /**
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 2492fe858bbc..128ef8338954 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -567,6 +567,10 @@ static jmethodID gCallbackMethod;
 static jmethodID gOnBatchCompleteMethod;
 static jmethodID gLogMarkerMethod;
 
+struct CountableBridge : Bridge, Countable {
+  using Bridge::Bridge;
+};
+
 static void logMarker(const std::string& marker) {
   JNIEnv* env = Environment::current();
   jclass markerClass = env->FindClass("com/facebook/react/bridge/ReactMarker");
@@ -643,12 +647,12 @@ static void create(JNIEnv* env, jobject obj, jobject executor, jobject callback,
     dispatchCallbacksToJava(weakCallback, weakCallbackQueueThread, std::move(calls), isEndOfBatch);
   };
   auto nativeExecutorFactory = extractRefPtr<CountableJSExecutorFactory>(env, executor);
-  auto bridge = createNew<Bridge>(nativeExecutorFactory, bridgeCallback);
+  auto bridge = createNew<CountableBridge>(nativeExecutorFactory.get(), bridgeCallback);
   setCountableForJava(env, obj, std::move(bridge));
 }
 
 static void executeApplicationScript(
-    const RefPtr<Bridge>& bridge,
+    const RefPtr<CountableBridge>& bridge,
     const std::string& script,
     const std::string& sourceUri) {
   try {
@@ -661,7 +665,7 @@ static void executeApplicationScript(
 }
 
 static void loadApplicationUnbundle(
-    const RefPtr<Bridge>& bridge,
+    const RefPtr<CountableBridge>& bridge,
     AAssetManager *assetManager,
     const std::string& startupCode,
     const std::string& startupFileName) {
@@ -683,7 +687,7 @@ static void loadScriptFromAssets(JNIEnv* env, jobject obj, jobject assetManager,
                                  jstring assetName) {
   jclass markerClass = env->FindClass("com/facebook/react/bridge/ReactMarker");
   auto manager = AAssetManager_fromJava(env, assetManager);
-  auto bridge = extractRefPtr<Bridge>(env, obj);
+  auto bridge = extractRefPtr<CountableBridge>(env, obj);
   auto assetNameStr = fromJString(env, assetName);
 
   env->CallStaticVoidMethod(markerClass, gLogMarkerMethod, env->NewStringUTF("loadScriptFromAssets_start"));
@@ -709,7 +713,7 @@ static void loadScriptFromAssets(JNIEnv* env, jobject obj, jobject assetManager,
 static void loadScriptFromFile(JNIEnv* env, jobject obj, jstring fileName, jstring sourceURL) {
   jclass markerClass = env->FindClass("com/facebook/react/bridge/ReactMarker");
 
-  auto bridge = jni::extractRefPtr<Bridge>(env, obj);
+  auto bridge = jni::extractRefPtr<CountableBridge>(env, obj);
   auto fileNameStr = fileName == NULL ? "" : fromJString(env, fileName);
   env->CallStaticVoidMethod(markerClass, gLogMarkerMethod, env->NewStringUTF("loadScriptFromFile_start"));
   auto script = fileName == NULL ? "" : react::loadScriptFromFile(fileNameStr);
@@ -729,7 +733,7 @@ static void loadScriptFromFile(JNIEnv* env, jobject obj, jstring fileName, jstri
 
 static void callFunction(JNIEnv* env, jobject obj, jint moduleId, jint methodId,
                          NativeArray::jhybridobject args) {
-  auto bridge = extractRefPtr<Bridge>(env, obj);
+  auto bridge = extractRefPtr<CountableBridge>(env, obj);
   auto arguments = cthis(wrap_alias(args));
   try {
     bridge->callFunction(
@@ -744,7 +748,7 @@ static void callFunction(JNIEnv* env, jobject obj, jint moduleId, jint methodId,
 
 static void invokeCallback(JNIEnv* env, jobject obj, jint callbackId,
                            NativeArray::jhybridobject args) {
-  auto bridge = extractRefPtr<Bridge>(env, obj);
+  auto bridge = extractRefPtr<CountableBridge>(env, obj);
   auto arguments = cthis(wrap_alias(args));
   try {
     bridge->invokeCallback(
@@ -757,32 +761,32 @@ static void invokeCallback(JNIEnv* env, jobject obj, jint callbackId,
 }
 
 static void setGlobalVariable(JNIEnv* env, jobject obj, jstring propName, jstring jsonValue) {
-  auto bridge = extractRefPtr<Bridge>(env, obj);
+  auto bridge = extractRefPtr<CountableBridge>(env, obj);
   bridge->setGlobalVariable(fromJString(env, propName), fromJString(env, jsonValue));
 }
 
 static jboolean supportsProfiling(JNIEnv* env, jobject obj) {
-  auto bridge = extractRefPtr<Bridge>(env, obj);
+  auto bridge = extractRefPtr<CountableBridge>(env, obj);
   return bridge->supportsProfiling() ? JNI_TRUE : JNI_FALSE;
 }
 
 static void startProfiler(JNIEnv* env, jobject obj, jstring title) {
-  auto bridge = extractRefPtr<Bridge>(env, obj);
+  auto bridge = extractRefPtr<CountableBridge>(env, obj);
   bridge->startProfiler(fromJString(env, title));
 }
 
 static void stopProfiler(JNIEnv* env, jobject obj, jstring title, jstring filename) {
-  auto bridge = extractRefPtr<Bridge>(env, obj);
+  auto bridge = extractRefPtr<CountableBridge>(env, obj);
   bridge->stopProfiler(fromJString(env, title), fromJString(env, filename));
 }
 
 static void handleMemoryPressureModerate(JNIEnv* env, jobject obj) {
-  auto bridge = extractRefPtr<Bridge>(env, obj);
+  auto bridge = extractRefPtr<CountableBridge>(env, obj);
   bridge->handleMemoryPressureModerate();
 }
 
 static void handleMemoryPressureCritical(JNIEnv* env, jobject obj) {
-  auto bridge = extractRefPtr<Bridge>(env, obj);
+  auto bridge = extractRefPtr<CountableBridge>(env, obj);
   bridge->handleMemoryPressureCritical();
 }
 
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.h b/ReactAndroid/src/main/jni/react/jni/OnLoad.h
index 9da83c447b96..e7a7d04a46fb 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.h
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.h
@@ -3,11 +3,17 @@
 #pragma once
 
 #include <jni.h>
+#include <jni/Countable.h>
+#include <react/Executor.h>
 
 namespace facebook {
 namespace react {
 
 jmethodID getLogMarkerMethod();
 
+struct CountableJSExecutorFactory : JSExecutorFactory, Countable {
+  using JSExecutorFactory::JSExecutorFactory;
+};
+
 } // namespace react
 } // namespace facebook
diff --git a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
index 5b2842592eae..09e7778b097e 100644
--- a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
+++ b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
@@ -2,11 +2,11 @@
 
 #pragma once
 
-#include <react/Bridge.h>
 #include <react/Executor.h>
 #include <jni/fbjni.h>
 #include <jni.h>
 #include <jni/GlobalReference.h>
+#include "OnLoad.h"
 
 namespace facebook {
 namespace react {

From 7cda49d516c7868341daf12564864cfca8c2d520 Mon Sep 17 00:00:00 2001
From: Chris Hopman <cjhopman@fb.com>
Date: Tue, 9 Feb 2016 12:59:36 -0800
Subject: [PATCH 1098/1411] Use c++ exceptions in react/

Reviewed By: astreet

Differential Revision: D2905193

fb-gh-sync-id: ddb4c615ede606e99c92a09a96a15141b912ef72
shipit-source-id: ddb4c615ede606e99c92a09a96a15141b912ef72
---
 .../src/main/jni/react/JSCExecutor.cpp        |  3 ---
 .../src/main/jni/react/JSCHelpers.cpp         |  1 -
 ReactAndroid/src/main/jni/react/JSCHelpers.h  | 20 ++++++++++++++-
 .../src/main/jni/react/JSCWebWorker.cpp       |  3 +--
 .../src/main/jni/react/MethodCall.cpp         | 25 ++++++++-----------
 5 files changed, 31 insertions(+), 21 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index 8655ee5dc69a..c9b1c1966238 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -9,7 +9,6 @@
 #include <fb/log.h>
 #include <folly/json.h>
 #include <folly/String.h>
-#include <jni/fbjni/Exceptions.h>
 #include <sys/time.h>
 #include "Value.h"
 #include "jni/OnLoad.h"
@@ -42,8 +41,6 @@ using fbsystrace::FbSystraceSection;
 static const int64_t NANOSECONDS_IN_SECOND = 1000000000LL;
 static const int64_t NANOSECONDS_IN_MILLISECOND = 1000000LL;
 
-using namespace facebook::jni;
-
 namespace facebook {
 namespace react {
 
diff --git a/ReactAndroid/src/main/jni/react/JSCHelpers.cpp b/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
index b24651bd36b5..0711c273f140 100644
--- a/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
@@ -4,7 +4,6 @@
 
 #include <JavaScriptCore/JSStringRef.h>
 #include <glog/logging.h>
-#include <jni/fbjni/Exceptions.h>
 
 #include "Value.h"
 
diff --git a/ReactAndroid/src/main/jni/react/JSCHelpers.h b/ReactAndroid/src/main/jni/react/JSCHelpers.h
index de3bfbacbf15..c765421c4ca5 100644
--- a/ReactAndroid/src/main/jni/react/JSCHelpers.h
+++ b/ReactAndroid/src/main/jni/react/JSCHelpers.h
@@ -6,11 +6,29 @@
 #include <JavaScriptCore/JSObjectRef.h>
 #include <JavaScriptCore/JSValueRef.h>
 
-#define throwJSExecutionException(...) jni::throwNewJavaException("com/facebook/react/bridge/JSExecutionException", __VA_ARGS__)
+#include <stdexcept>
+#include <algorithm>
 
 namespace facebook {
 namespace react {
 
+struct JsException : std::runtime_error {
+  using std::runtime_error::runtime_error;
+};
+
+inline void throwJSExecutionException(const char* msg) {
+  throw JsException(msg);
+}
+
+template <typename... Args>
+inline void throwJSExecutionException(const char* fmt, Args... args) {
+  int msgSize = snprintf(nullptr, 0, fmt, args...);
+  msgSize = std::min(512, msgSize + 1);
+  char *msg = (char*) alloca(msgSize);
+  snprintf(msg, msgSize, fmt, args...);
+  throw JsException(msg);
+}
+
 void installGlobalFunction(
     JSGlobalContextRef ctx,
     const char* name,
diff --git a/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp b/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
index 62902fcf0adf..2c91d17fe326 100644
--- a/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
@@ -9,8 +9,6 @@
 
 #include <glog/logging.h>
 #include <folly/Memory.h>
-#include <jni/fbjni/Exceptions.h>
-#include <jni/LocalReference.h>
 
 #include "JSCHelpers.h"
 #include "jni/JSLoader.h"
@@ -43,6 +41,7 @@ JSCWebWorker::JSCWebWorker(int id, JSCWebWorkerOwner *owner, std::string scriptS
   });
 }
 
+
 JSCWebWorker::~JSCWebWorker() {
   CHECK(isTerminated()) << "Didn't terminate the web worker before releasing it!";;
 }
diff --git a/ReactAndroid/src/main/jni/react/MethodCall.cpp b/ReactAndroid/src/main/jni/react/MethodCall.cpp
index ac9b13edd57f..2782e05b6f9f 100644
--- a/ReactAndroid/src/main/jni/react/MethodCall.cpp
+++ b/ReactAndroid/src/main/jni/react/MethodCall.cpp
@@ -2,9 +2,8 @@
 
 #include "MethodCall.h"
 
-#include <jni/fbjni.h>
-
 #include <folly/json.h>
+#include <stdexcept>
 
 namespace facebook {
 namespace react {
@@ -22,13 +21,13 @@ std::vector<MethodCall> parseMethodCalls(const std::string& json) {
   }
 
   if (!jsonData.isArray()) {
-    jni::throwNewJavaException(jni::gJavaLangIllegalArgumentException,
-                               "Did not get valid calls back from JS: %s", jsonData.typeName());
+    throw std::invalid_argument(
+        folly::to<std::string>("Did not get valid calls back from JS: ", jsonData.typeName()));
   }
 
   if (jsonData.size() < REQUEST_PARAMSS + 1) {
-    jni::throwNewJavaException(jni::gJavaLangIllegalArgumentException,
-                               "Did not get valid calls back from JS: size == %d", jsonData.size());
+    throw std::invalid_argument(
+          folly::to<std::string>("Did not get valid calls back from JS: size == ", jsonData.size()));
   }
 
   auto moduleIds = jsonData[REQUEST_MODULE_IDS];
@@ -37,16 +36,14 @@ std::vector<MethodCall> parseMethodCalls(const std::string& json) {
   int  callId = -1;
 
   if (!moduleIds.isArray() || !methodIds.isArray() || !params.isArray()) {
-    jni::throwNewJavaException(jni::gJavaLangIllegalArgumentException,
-                               "Did not get valid calls back from JS: %s",
-                               json.c_str());
+    throw std::invalid_argument(
+          folly::to<std::string>("Did not get valid calls back from JS: ", json.c_str()));
   }
 
   if (jsonData.size() > REQUEST_CALLID) {
     if (!jsonData[REQUEST_CALLID].isInt()) {
-      jni::throwNewJavaException(jni::gJavaLangIllegalArgumentException,
-                               "Did not get valid calls back from JS: %s",
-                               json.c_str());
+      throw std::invalid_argument(
+          folly::to<std::string>("Did not get valid calls back from JS: %s", json.c_str()));
     } else {
       callId = jsonData[REQUEST_CALLID].getInt();
     }
@@ -56,8 +53,8 @@ std::vector<MethodCall> parseMethodCalls(const std::string& json) {
   for (size_t i = 0; i < moduleIds.size(); i++) {
     auto paramsValue = params[i];
     if (!paramsValue.isArray()) {
-      jni::throwNewJavaException(jni::gJavaLangIllegalArgumentException,
-                                 "Call argument isn't an array");
+      throw std::invalid_argument(
+          folly::to<std::string>("Call argument isn't an array"));
     }
 
     methodCalls.emplace_back(

From 48f82e4e2b2de806311bd61c75c4845ab189c001 Mon Sep 17 00:00:00 2001
From: Chris Hopman <cjhopman@fb.com>
Date: Tue, 9 Feb 2016 12:59:37 -0800
Subject: [PATCH 1099/1411] Use our own noncopyable in react/

Reviewed By: astreet

Differential Revision: D2905195

fb-gh-sync-id: feede5288ef2d5de9dbd9802280e51f8782070ec
shipit-source-id: feede5288ef2d5de9dbd9802280e51f8782070ec
---
 ReactAndroid/src/main/jni/react/BUCK                |  1 +
 ReactAndroid/src/main/jni/react/JSModulesUnbundle.h |  3 ++-
 ReactAndroid/src/main/jni/react/Value.h             |  4 +++-
 ReactAndroid/src/main/jni/react/noncopyable.h       | 12 ++++++++++++
 4 files changed, 18 insertions(+), 2 deletions(-)
 create mode 100644 ReactAndroid/src/main/jni/react/noncopyable.h

diff --git a/ReactAndroid/src/main/jni/react/BUCK b/ReactAndroid/src/main/jni/react/BUCK
index 8bafe44d28aa..42796146a3cf 100644
--- a/ReactAndroid/src/main/jni/react/BUCK
+++ b/ReactAndroid/src/main/jni/react/BUCK
@@ -65,6 +65,7 @@ react_library(
     'JSModulesUnbundle.h',
     'Value.h',
     'Platform.h',
+    'noncopyable.h',
   ],
   compiler_flags = [
     '-Wall',
diff --git a/ReactAndroid/src/main/jni/react/JSModulesUnbundle.h b/ReactAndroid/src/main/jni/react/JSModulesUnbundle.h
index cc5c3e429014..d1c2f12547f1 100644
--- a/ReactAndroid/src/main/jni/react/JSModulesUnbundle.h
+++ b/ReactAndroid/src/main/jni/react/JSModulesUnbundle.h
@@ -3,10 +3,11 @@
 #pragma once
 
 #include <cstdint>
-#include <fb/noncopyable.h>
 #include <string>
 #include <stdexcept>
 
+#include "noncopyable.h"
+
 namespace facebook {
 namespace react {
 
diff --git a/ReactAndroid/src/main/jni/react/Value.h b/ReactAndroid/src/main/jni/react/Value.h
index fb02fe50ab8f..1cee8cc9fd15 100644
--- a/ReactAndroid/src/main/jni/react/Value.h
+++ b/ReactAndroid/src/main/jni/react/Value.h
@@ -8,7 +8,9 @@
 #include <JavaScriptCore/JSRetainPtr.h>
 #include <JavaScriptCore/JSStringRef.h>
 #include <JavaScriptCore/JSValueRef.h>
-#include <fb/noncopyable.h>
+
+#include "noncopyable.h"
+
 #if WITH_FBJSCEXTENSIONS
 #include <jsc_stringref.h>
 #endif
diff --git a/ReactAndroid/src/main/jni/react/noncopyable.h b/ReactAndroid/src/main/jni/react/noncopyable.h
new file mode 100644
index 000000000000..96b32d44b835
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/noncopyable.h
@@ -0,0 +1,12 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+namespace facebook {
+namespace react {
+struct noncopyable {
+  noncopyable(const noncopyable&) = delete;
+  noncopyable& operator=(const noncopyable&) = delete;
+ protected:
+  noncopyable() = default;
+};
+}}

From d80ee0a8ac5afd3f24ffad6f64f3f50e0d6b1ceb Mon Sep 17 00:00:00 2001
From: Chris Hopman <cjhopman@fb.com>
Date: Tue, 9 Feb 2016 12:59:38 -0800
Subject: [PATCH 1100/1411] Clean up some includes/dependencies

Reviewed By: astreet

Differential Revision: D2905196

fb-gh-sync-id: d92f0e0296f4877b589cac674e388a5dbabc7d71
shipit-source-id: d92f0e0296f4877b589cac674e388a5dbabc7d71
---
 ReactAndroid/src/main/jni/react/BUCK             |  3 ---
 ReactAndroid/src/main/jni/react/JSCExecutor.cpp  | 11 +++++------
 ReactAndroid/src/main/jni/react/JSCWebWorker.cpp |  4 ----
 ReactAndroid/src/main/jni/react/Value.cpp        |  2 --
 ReactAndroid/src/main/jni/react/jni/BUCK         |  2 +-
 5 files changed, 6 insertions(+), 16 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/BUCK b/ReactAndroid/src/main/jni/react/BUCK
index 42796146a3cf..ffa06d775025 100644
--- a/ReactAndroid/src/main/jni/react/BUCK
+++ b/ReactAndroid/src/main/jni/react/BUCK
@@ -4,9 +4,6 @@ include_defs('//ReactAndroid/DEFS')
 SUPPORTED_PLATFORMS = '^android-(armv7|x86)$'
 
 DEPS = [
-  '//native/fb:fb',
-  '//native/jni:jni',
-  '//native/third-party/android-ndk:android',
   '//xplat/fbsystrace:fbsystrace',
   '//xplat/folly:molly',
   '//xplat/third-party/glog:glog',
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index c9b1c1966238..a951c5d8f4df 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -6,18 +6,17 @@
 #include <atomic>
 #include <sstream>
 #include <string>
-#include <fb/log.h>
 #include <folly/json.h>
 #include <folly/String.h>
 #include <sys/time.h>
+
+#include "JSCHelpers.h"
 #include "Value.h"
-#include "jni/OnLoad.h"
-#include <react/JSCHelpers.h>
 #include "Platform.h"
 
 #ifdef WITH_JSC_EXTRA_TRACING
-#include <react/JSCTracing.h>
-#include <react/JSCLegacyProfiler.h>
+#include "JSCTracing.h"
+#include "JSCLegacyProfiler.h"
 #include <JavaScriptCore/API/JSProfilerPrivate.h>
 #endif
 
@@ -31,7 +30,7 @@ using fbsystrace::FbSystraceSection;
 #endif
 
 #ifdef WITH_FB_MEMORY_PROFILING
-#include <react/JSCMemory.h>
+#include "JSCMemory.h"
 #endif
 
 #ifdef WITH_FB_JSC_TUNING
diff --git a/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp b/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
index 2c91d17fe326..e8e710bdf393 100644
--- a/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
@@ -11,16 +11,12 @@
 #include <folly/Memory.h>
 
 #include "JSCHelpers.h"
-#include "jni/JSLoader.h"
-#include "jni/WebWorkers.h"
 #include "MessageQueueThread.h"
 #include "Platform.h"
 #include "Value.h"
 
 #include <JavaScriptCore/JSValueRef.h>
 
-using namespace facebook::jni;
-
 namespace facebook {
 namespace react {
 
diff --git a/ReactAndroid/src/main/jni/react/Value.cpp b/ReactAndroid/src/main/jni/react/Value.cpp
index d23490bbbc96..ac07c486fd5c 100644
--- a/ReactAndroid/src/main/jni/react/Value.cpp
+++ b/ReactAndroid/src/main/jni/react/Value.cpp
@@ -2,8 +2,6 @@
 
 #include "Value.h"
 
-#include <jni/fbjni.h>
-
 #include "JSCHelpers.h"
 
 namespace facebook {
diff --git a/ReactAndroid/src/main/jni/react/jni/BUCK b/ReactAndroid/src/main/jni/react/jni/BUCK
index 69f13e78eaa5..bebdf54ce2a3 100644
--- a/ReactAndroid/src/main/jni/react/jni/BUCK
+++ b/ReactAndroid/src/main/jni/react/jni/BUCK
@@ -45,11 +45,11 @@ jni_library(
     'JniJSModulesUnbundle.h',
     'JSCPerfLogging.h',
     'JSLogging.h',
+    'WebWorkers.h',
   ],
   exported_headers = [
     'NativeArray.h',
     'ReadableNativeArray.h',
-    'WebWorkers.h',
   ],
   preprocessor_flags = [
     '-DLOG_TAG="ReactNativeJNI"',

From d97223bc3b207545ac1bb9d97868685481a25f07 Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Tue, 9 Feb 2016 14:57:58 -0800
Subject: [PATCH 1101/1411] Replace usages of hexToRgb with
 setNormalizedColorAlpha

Reviewed By: vjeux

Differential Revision: D2906507

fb-gh-sync-id: 671ec5b9f5a701891c3601a8f78968b99476a2b5
shipit-source-id: 671ec5b9f5a701891c3601a8f78968b99476a2b5
---
 .../__tests__/normalizeColor-test.js          |  5 +++
 .../__tests__/setNormalizedColorAlpha-test.js | 36 +++++++++++++++++++
 .../StyleSheet/setNormalizedColorAlpha.js     | 31 ++++++++++++++++
 3 files changed, 72 insertions(+)
 create mode 100644 Libraries/StyleSheet/__tests__/setNormalizedColorAlpha-test.js
 create mode 100644 Libraries/StyleSheet/setNormalizedColorAlpha.js

diff --git a/Libraries/StyleSheet/__tests__/normalizeColor-test.js b/Libraries/StyleSheet/__tests__/normalizeColor-test.js
index dc12de12ff4f..fd8d7d147460 100644
--- a/Libraries/StyleSheet/__tests__/normalizeColor-test.js
+++ b/Libraries/StyleSheet/__tests__/normalizeColor-test.js
@@ -123,4 +123,9 @@ describe('normalizeColor', function() {
     expect(normalizeColor(0xffffffff)).toBe(0xffffffff);
     expect(normalizeColor(0x01234567)).toBe(0x01234567);
   });
+
+  it('should return the same color when it\'s already normalized', function() {
+    const normalizedColor = normalizeColor('red') || 0;
+    expect(normalizeColor(normalizedColor)).toBe(normalizedColor);
+  });
 });
diff --git a/Libraries/StyleSheet/__tests__/setNormalizedColorAlpha-test.js b/Libraries/StyleSheet/__tests__/setNormalizedColorAlpha-test.js
new file mode 100644
index 000000000000..598652dbba7b
--- /dev/null
+++ b/Libraries/StyleSheet/__tests__/setNormalizedColorAlpha-test.js
@@ -0,0 +1,36 @@
+/**
+ * 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.
+ */
+'use strict';
+
+jest.dontMock('setNormalizedColorAlpha');
+jest.dontMock('normalizeColor');
+
+var setNormalizedColorAlpha = require('setNormalizedColorAlpha');
+var normalizeColor = require('normalizeColor');
+
+describe('setNormalizedColorAlpha', function() {
+  it('should adjust the alpha of the color passed in', function() {
+    expect(setNormalizedColorAlpha(0xffffffff, 0.4)).toBe(0xffffff66);
+    expect(setNormalizedColorAlpha(0x204080ff, 0.6)).toBe(0x20408099);
+  });
+
+  it('should clamp invalid input', function() {
+    expect(setNormalizedColorAlpha(0xffffffff, 1.5)).toBe(0xffffffff);
+    expect(setNormalizedColorAlpha(0xffffffff, -1)).toBe(0xffffff00);
+  });
+
+  it('should ignore the color\'s original alpha', function() {
+    expect(setNormalizedColorAlpha(0x204080aa, 0.8)).toBe(0x204080cc);
+  });
+
+  it('should return the original color when alpha is unchanged', function() {
+    var originalColor = normalizeColor('blue');
+    expect(setNormalizedColorAlpha(originalColor, 1)).toBe(originalColor);
+  });
+});
diff --git a/Libraries/StyleSheet/setNormalizedColorAlpha.js b/Libraries/StyleSheet/setNormalizedColorAlpha.js
new file mode 100644
index 000000000000..cd943309922c
--- /dev/null
+++ b/Libraries/StyleSheet/setNormalizedColorAlpha.js
@@ -0,0 +1,31 @@
+/**
+ * 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 setNormalizedColorAlpha
+ * @flow
+ */
+/* eslint no-bitwise: 0 */
+'use strict';
+
+/**
+ * number should be a color processed by `normalizeColor`
+ * alpha should be number between 0 and 1
+ */
+function setNormalizedColorAlpha(input: number, alpha: number): number {
+  if (alpha < 0) {
+    alpha = 0;
+  } else if (alpha > 1) {
+    alpha = 1;
+  }
+
+  alpha = Math.round(alpha * 255);
+  // magic bitshift guarantees we return an unsigned int
+  return ((input & 0xffffff00) | alpha) >>> 0;
+}
+
+module.exports = setNormalizedColorAlpha;

From 9f01f9677096117da8be721913a09db870505c2f Mon Sep 17 00:00:00 2001
From: Adam Miskiewicz <adam@sk3vy.com>
Date: Tue, 9 Feb 2016 15:37:28 -0800
Subject: [PATCH 1102/1411] Move `react` to peerDependencies

Summary:
This PR moves `react` from dependencies to peerDependencies.

In general, this would have only been important for those people using packages that depend on `react` and were using npm@2...npm@3 would automatically de-dupe.

However, when #5812 gets merged, dependencies will be scoped to react-native (on both npm@2 & npm@3), thus breaking projects that are using a package like `react-redux` for example, which depends on `react`. There would be two copies of React installed, and due to the use of haste modules in `react`, this would break the packager and cause naming collisions.

This PR does three things -

1. Moves the dependency from dependencies to peerDependencies
2. Updates the local-cli to run `npm install react --save` when a new project is initialized.
3. Updates `react-native upgrade` to warn if `react` is not listed in the package.json's dependencies.

**Note: This will require a shrinkwrap update.**
Closes https://github.com/facebook/react-native/pull/5813

Reviewed By: svcscm

Differential Revision: D2918380

Pulled By: androidtrunkagent

fb-gh-sync-id: 6e4234a45284be2fdf6fedf29e70b2d2d0262486
shipit-source-id: 6e4234a45284be2fdf6fedf29e70b2d2d0262486
---
 local-cli/generator/index.js |  8 ++++++++
 local-cli/upgrade/upgrade.js | 13 +++++++++++++
 package.json                 |  4 +++-
 3 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/local-cli/generator/index.js b/local-cli/generator/index.js
index dadbd7a17c43..90f08912a1df 100644
--- a/local-cli/generator/index.js
+++ b/local-cli/generator/index.js
@@ -82,5 +82,13 @@ module.exports = yeoman.generators.NamedBase.extend({
         {name: this.name}
       );
     }
+  },
+
+  install: function() {
+    if (this.options.upgrade) {
+      return;
+    }
+
+    this.npmInstall('react', { '--save': true });
   }
 });
diff --git a/local-cli/upgrade/upgrade.js b/local-cli/upgrade/upgrade.js
index 4038bc6aaee4..4ce704984532 100644
--- a/local-cli/upgrade/upgrade.js
+++ b/local-cli/upgrade/upgrade.js
@@ -44,6 +44,19 @@ module.exports = function upgrade(args, config) {
               'https://github.com/facebook/react-native/releases/tag/v' + semver.major(v) + '.' + semver.minor(v) + '.0'
             )
           );
+
+          // >= v0.21.0, we require react to be a peer depdendency
+          if (semver.gte(v, '0.21.0') && !pak.dependencies['react']) {
+            console.log(
+              chalk.yellow(
+                '\nYour \'package.json\' file doesn\'t seem to have \'react\' as a dependency.\n' +
+                '\'react\' was changed from a dependency to a peer dependency in react-native v0.21.0.\n' +
+                'Therefore, it\'s necessary to include \'react\' in your project\'s dependencies.\n' +
+                'Just run \'npm install --save react\', then re-run \'react-native upgrade\'.\n'
+              )
+            );
+            return Promise.resolve();
+          }
         } else {
           console.log(
             chalk.yellow(
diff --git a/package.json b/package.json
index c77553f3767b..8e606d2fc6b5 100644
--- a/package.json
+++ b/package.json
@@ -102,6 +102,9 @@
   "bin": {
     "react-native": "local-cli/wrong-react-native.js"
   },
+  "peerDependencies": {
+    "react": "^0.14.5"
+  },
   "dependencies": {
     "absolute-path": "^0.0.0",
     "art": "^0.10.0",
@@ -133,7 +136,6 @@
     "optimist": "^0.6.1",
     "progress": "^1.1.8",
     "promise": "^7.1.1",
-    "react": "^0.14.5",
     "react-timer-mixin": "^0.13.2",
     "react-transform-hmr": "^1.0.2",
     "rebound": "^0.0.13",

From de3b942b4d9fbf7f575c5e16bc3f2a1ea4b13009 Mon Sep 17 00:00:00 2001
From: Sam <sam@lalop.co>
Date: Tue, 9 Feb 2016 16:21:52 -0800
Subject: [PATCH 1103/1411] make copyright render the current year

Summary:
As discussed here https://github.com/facebook/react-native/pull/5835 now the copyright is computed from `Date`
Closes https://github.com/facebook/react-native/pull/5847

Reviewed By: svcscm

Differential Revision: D2918854

Pulled By: androidtrunkagent

fb-gh-sync-id: bd5a56111aec1282857ffd469b91f7476b67221d
shipit-source-id: bd5a56111aec1282857ffd469b91f7476b67221d
---
 website/core/Site.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/website/core/Site.js b/website/core/Site.js
index eface427c5bb..c1cdc5a129e4 100644
--- a/website/core/Site.js
+++ b/website/core/Site.js
@@ -15,6 +15,7 @@ var HeaderLinks = require('HeaderLinks');
 var Site = React.createClass({
   render: function() {
     var title = this.props.title ? this.props.title + ' – ' : '';
+    var currentYear = (new Date()).getFullYear();
     title += 'React Native | A framework for building native apps using React';
     return (
       <html>
@@ -53,7 +54,7 @@ var Site = React.createClass({
             {this.props.children}
 
             <footer className="wrap">
-              <div className="center">© 2015 Facebook Inc.</div>
+              <div className="center">© {currentYear} Facebook Inc.</div>
             </footer>
           </div>
 

From 7c03b16a1bc0f8415eaad68362ce06faddfa8f6b Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Tue, 9 Feb 2016 17:15:22 -0800
Subject: [PATCH 1104/1411] / [node-haste] Remove support for asynchronous
 dependencies (`System.import`)

Summary:
public
Remove the unused feature for async dependencies / bundle layouts. We can bring it back later, if needed.

Reviewed By: cpojer

Differential Revision: D2916543

fb-gh-sync-id: 3a3890f10d7d275a4cb9371a6e9cace601a82b2c
shipit-source-id: 3a3890f10d7d275a4cb9371a6e9cace601a82b2c
---
 packager/react-packager/src/Bundler/index.js  |  12 -
 .../__tests__/BundlesLayout-test.js           | 320 ----------
 .../BundlesLayoutIntegration-test.js          | 599 ------------------
 .../react-packager/src/BundlesLayout/index.js | 219 -------
 .../src/DependencyResolver/AssetModule.js     |   4 -
 .../AssetModule_DEPRECATED.js                 |   4 -
 .../DependencyGraph/ResolutionRequest.js      |  17 -
 .../DependencyGraph/ResolutionResponse.js     |   8 -
 .../__tests__/DependencyGraph-test.js         |  34 -
 .../DependencyGraph/index.js                  |  13 +-
 .../src/DependencyResolver/Module.js          |  12 +-
 .../__tests__/Module-test.js                  |  70 +-
 .../DependencyResolver/lib/extractRequires.js |  10 -
 .../DependencyResolver/lib/replacePatterns.js |   1 -
 .../src/Resolver/__tests__/Resolver-test.js   |   7 +-
 .../polyfills/__tests__/loadBundles-test.js   |  63 --
 .../src/Resolver/polyfills/loadBundles.js     |  34 -
 .../babel-plugin-system-import-test.js        |  71 ---
 .../babel-plugin-system-import/index.js       |  63 --
 19 files changed, 10 insertions(+), 1551 deletions(-)
 delete mode 100644 packager/react-packager/src/BundlesLayout/__tests__/BundlesLayout-test.js
 delete mode 100644 packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js
 delete mode 100644 packager/react-packager/src/BundlesLayout/index.js
 delete mode 100644 packager/react-packager/src/Resolver/polyfills/__tests__/loadBundles-test.js
 delete mode 100644 packager/react-packager/src/Resolver/polyfills/loadBundles.js
 delete mode 100644 packager/react-packager/src/transforms/babel-plugin-system-import/__tests__/babel-plugin-system-import-test.js
 delete mode 100644 packager/react-packager/src/transforms/babel-plugin-system-import/index.js

diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index a07d73f7ac5f..99923e657620 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -13,7 +13,6 @@ const fs = require('fs');
 const path = require('path');
 const Promise = require('promise');
 const ProgressBar = require('progress');
-const BundlesLayout = require('../BundlesLayout');
 const Cache = require('../DependencyResolver/Cache');
 const Transformer = require('../JSTransformer');
 const Resolver = require('../Resolver');
@@ -126,13 +125,6 @@ class Bundler {
       cache: this._cache,
     });
 
-    this._bundlesLayout = new BundlesLayout({
-      dependencyResolver: this._resolver,
-      resetCache: opts.resetCache,
-      cacheVersion: opts.cacheVersion,
-      projectRoots: opts.projectRoots,
-    });
-
     this._transformer = new Transformer({
       projectRoots: opts.projectRoots,
       blacklistRE: opts.blacklistRE,
@@ -156,10 +148,6 @@ class Bundler {
     return this._cache.end();
   }
 
-  getLayout(main, isDev) {
-    return this._bundlesLayout.generateLayout(main, isDev);
-  }
-
   bundle(options) {
     const {dev, isUnbundle, platform} = options;
     const moduleSystemDeps =
diff --git a/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayout-test.js b/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayout-test.js
deleted file mode 100644
index dafdb3680ae1..000000000000
--- a/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayout-test.js
+++ /dev/null
@@ -1,320 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-jest.dontMock('../index')
-    .mock('fs');
-
-var Promise = require('promise');
-var BundlesLayout = require('../index');
-var Resolver = require('../../Resolver');
-var loadCacheSync = require('../../DependencyResolver/Cache/lib/loadCacheSync');
-
-describe('BundlesLayout', () => {
-  function newBundlesLayout(options) {
-    return new BundlesLayout(Object.assign({
-      projectRoots: ['/root'],
-      dependencyResolver: new Resolver(),
-    }, options));
-  }
-
-  describe('layout', () => {
-    function isPolyfill() {
-      return false;
-    }
-
-    describe('getLayout', () => {
-      function dep(path) {
-        return {
-          path: path,
-          isPolyfill: isPolyfill,
-        };
-      }
-
-      pit('should bundle sync dependencies', () => {
-        Resolver.prototype.getDependencies.mockImpl((path) => {
-          switch (path) {
-            case '/root/index.js':
-              return Promise.resolve({
-                dependencies: [dep('/root/index.js'), dep('/root/a.js')],
-                asyncDependencies: [],
-              });
-            case '/root/a.js':
-              return Promise.resolve({
-                dependencies: [dep('/root/a.js')],
-                asyncDependencies: [],
-              });
-            default:
-              throw 'Undefined path: ' + path;
-          }
-        });
-
-        return newBundlesLayout({resetCache: true})
-          .getLayout('/root/index.js')
-          .then(bundles =>
-            expect(bundles).toEqual({
-              id: 'bundle.0',
-              modules: ['/root/index.js', '/root/a.js'],
-              children: [],
-            })
-          );
-      });
-
-      pit('should separate async dependencies into different bundle', () => {
-        Resolver.prototype.getDependencies.mockImpl((path) => {
-          switch (path) {
-            case '/root/index.js':
-              return Promise.resolve({
-                dependencies: [dep('/root/index.js')],
-                asyncDependencies: [['/root/a.js']],
-              });
-            case '/root/a.js':
-              return Promise.resolve({
-                dependencies: [dep('/root/a.js')],
-                asyncDependencies: [],
-              });
-            default:
-              throw 'Undefined path: ' + path;
-          }
-        });
-
-        return newBundlesLayout({resetCache: true})
-          .getLayout('/root/index.js')
-          .then(bundles =>
-            expect(bundles).toEqual({
-              id: 'bundle.0',
-              modules: ['/root/index.js'],
-              children: [{
-                id:'bundle.0.1',
-                modules: ['/root/a.js'],
-                children: [],
-              }],
-            })
-          );
-      });
-
-      pit('separate async dependencies of async dependencies', () => {
-        Resolver.prototype.getDependencies.mockImpl((path) => {
-          switch (path) {
-            case '/root/index.js':
-              return Promise.resolve({
-                dependencies: [dep('/root/index.js')],
-                asyncDependencies: [['/root/a.js']],
-              });
-            case '/root/a.js':
-              return Promise.resolve({
-                dependencies: [dep('/root/a.js')],
-                asyncDependencies: [['/root/b.js']],
-              });
-            case '/root/b.js':
-              return Promise.resolve({
-                dependencies: [dep('/root/b.js')],
-                asyncDependencies: [],
-              });
-            default:
-              throw 'Undefined path: ' + path;
-          }
-        });
-
-        return newBundlesLayout({resetCache: true})
-          .getLayout('/root/index.js')
-          .then(bundles =>
-            expect(bundles).toEqual({
-              id: 'bundle.0',
-              modules: ['/root/index.js'],
-              children: [{
-                id: 'bundle.0.1',
-                modules: ['/root/a.js'],
-                  children: [{
-                    id: 'bundle.0.1.2',
-                    modules: ['/root/b.js'],
-                    children: [],
-                  }],
-              }],
-            })
-          );
-      });
-
-      pit('separate bundle sync dependencies of async ones on same bundle', () => {
-        Resolver.prototype.getDependencies.mockImpl((path) => {
-          switch (path) {
-            case '/root/index.js':
-              return Promise.resolve({
-                dependencies: [dep('/root/index.js')],
-                asyncDependencies: [['/root/a.js']],
-              });
-            case '/root/a.js':
-              return Promise.resolve({
-                dependencies: [dep('/root/a.js'), dep('/root/b.js')],
-                asyncDependencies: [],
-              });
-            case '/root/b.js':
-              return Promise.resolve({
-                dependencies: [dep('/root/b.js')],
-                asyncDependencies: [],
-              });
-            default:
-              throw 'Undefined path: ' + path;
-          }
-        });
-
-        return newBundlesLayout({resetCache: true})
-          .getLayout('/root/index.js')
-          .then(bundles =>
-            expect(bundles).toEqual({
-              id: 'bundle.0',
-              modules: ['/root/index.js'],
-              children: [{
-                id: 'bundle.0.1',
-                modules: ['/root/a.js', '/root/b.js'],
-                children: [],
-              }],
-            })
-          );
-      });
-
-      pit('separate cache in which bundle is each dependency', () => {
-        Resolver.prototype.getDependencies.mockImpl((path) => {
-          switch (path) {
-            case '/root/index.js':
-              return Promise.resolve({
-                dependencies: [dep('/root/index.js'), dep('/root/a.js')],
-                asyncDependencies: [],
-              });
-            case '/root/a.js':
-              return Promise.resolve({
-                dependencies: [dep('/root/a.js')],
-                asyncDependencies: [['/root/b.js']],
-              });
-            case '/root/b.js':
-              return Promise.resolve({
-                dependencies: [dep('/root/b.js')],
-                asyncDependencies: [],
-              });
-            default:
-              throw 'Undefined path: ' + path;
-          }
-        });
-
-        return newBundlesLayout({resetCache: true})
-          .getLayout('/root/index.js')
-          .then(bundles =>
-            expect(bundles).toEqual({
-              id: 'bundle.0',
-              modules: ['/root/index.js', '/root/a.js'],
-              children: [{
-                id: 'bundle.0.1',
-                modules: ['/root/b.js'],
-                children: [],
-              }],
-            })
-          );
-      });
-
-      pit('separate cache in which bundle is each dependency', () => {
-        Resolver.prototype.getDependencies.mockImpl((path) => {
-          switch (path) {
-            case '/root/index.js':
-              return Promise.resolve({
-                dependencies: [dep('/root/index.js'), dep('/root/a.js')],
-                asyncDependencies: [['/root/b.js'], ['/root/c.js']],
-              });
-            case '/root/a.js':
-              return Promise.resolve({
-                dependencies: [dep('/root/a.js')],
-                asyncDependencies: [],
-              });
-            case '/root/b.js':
-              return Promise.resolve({
-                dependencies: [dep('/root/b.js')],
-                asyncDependencies: [['/root/d.js']],
-              });
-            case '/root/c.js':
-              return Promise.resolve({
-                dependencies: [dep('/root/c.js')],
-                asyncDependencies: [],
-              });
-            case '/root/d.js':
-              return Promise.resolve({
-                dependencies: [dep('/root/d.js')],
-                asyncDependencies: [],
-              });
-            default:
-              throw 'Undefined path: ' + path;
-          }
-        });
-
-        var layout = newBundlesLayout({resetCache: true});
-        return layout.getLayout('/root/index.js').then(() => {
-          expect(layout.getBundleIDForModule('/root/index.js')).toBe('bundle.0');
-          expect(layout.getBundleIDForModule('/root/a.js')).toBe('bundle.0');
-          expect(layout.getBundleIDForModule('/root/b.js')).toBe('bundle.0.1');
-          expect(layout.getBundleIDForModule('/root/c.js')).toBe('bundle.0.2');
-          expect(layout.getBundleIDForModule('/root/d.js')).toBe('bundle.0.1.3');
-        });
-      });
-    });
-  });
-
-  describe('cache', () => {
-    beforeEach(() => {
-      loadCacheSync.mockReturnValue({
-        '/root/index.js': {
-          id: 'bundle.0',
-          modules: ['/root/index.js'],
-          children: [{
-            id: 'bundle.0.1',
-            modules: ['/root/a.js'],
-            children: [],
-          }],
-        },
-        '/root/b.js': {
-          id: 'bundle.2',
-          modules: ['/root/b.js'],
-          children: [],
-        },
-      });
-    });
-
-    pit('should load layouts', () => {
-      const layout = newBundlesLayout({ resetCache: false });
-
-      return Promise
-        .all([
-          layout.getLayout('/root/index.js'),
-          layout.getLayout('/root/b.js'),
-        ])
-        .then(([layoutIndex, layoutB]) => {
-          expect(layoutIndex).toEqual({
-            id: 'bundle.0',
-            modules: ['/root/index.js'],
-            children: [{
-              id: 'bundle.0.1',
-              modules: ['/root/a.js'],
-              children: [],
-            }],
-          });
-
-          expect(layoutB).toEqual({
-            id: 'bundle.2',
-            modules: ['/root/b.js'],
-            children: [],
-          });
-        });
-    });
-
-    it('should load moduleToBundle map', () => {
-      const layout = newBundlesLayout({ resetCache: false });
-
-      expect(layout.getBundleIDForModule('/root/index.js')).toBe('bundle.0');
-      expect(layout.getBundleIDForModule('/root/a.js')).toBe('bundle.0.1');
-      expect(layout.getBundleIDForModule('/root/b.js')).toBe('bundle.2');
-    });
-  });
-});
diff --git a/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js b/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js
deleted file mode 100644
index 00868b22908d..000000000000
--- a/packager/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js
+++ /dev/null
@@ -1,599 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-jest
-  .autoMockOff()
-  .mock('../../DependencyResolver/Cache')
-  .mock('../../Activity');
-
-const Promise = require('promise');
-const path = require('path');
-
-jest.mock('fs');
-
-var BundlesLayout = require('../index');
-var Cache = require('../../DependencyResolver/Cache');
-var Resolver = require('../../Resolver');
-var fs = require('fs');
-
-describe('BundlesLayout', () => {
-  var fileWatcher;
-
-  const polyfills = [
-    'polyfills/prelude_dev.js',
-    'polyfills/prelude.js',
-    'polyfills/require.js',
-    'polyfills/polyfills.js',
-    'polyfills/console.js',
-    'polyfills/error-guard.js',
-    'polyfills/String.prototype.es6.js',
-    'polyfills/Array.prototype.es6.js',
-    'polyfills/Array.es6.js',
-    'polyfills/Object.es7.js',
-    'polyfills/babelHelpers.js',
-  ];
-  const baseFs = getBaseFs();
-
-  beforeEach(() => {
-    fileWatcher = {
-      on: () => this,
-      isWatchman: () => Promise.resolve(false)
-    };
-  });
-
-  describe('generate', () => {
-    function newBundlesLayout() {
-      const resolver = new Resolver({
-        projectRoots: ['/root', '/' + __dirname.split('/')[1]],
-        fileWatcher: fileWatcher,
-        cache: new Cache(),
-        assetExts: ['js', 'png'],
-        assetRoots: ['/root'],
-      });
-
-      return new BundlesLayout({
-        dependencyResolver: resolver,
-        resetCache: true,
-        projectRoots: ['/root', '/' + __dirname.split('/')[1]],
-      });
-    }
-
-    function stripPolyfills(bundle) {
-      return Promise
-        .all(bundle.children.map(childModule => stripPolyfills(childModule)))
-        .then(children => {
-          const modules = bundle.modules
-            .filter(moduleName => { // filter polyfills
-              for (let p of polyfills) {
-                if (moduleName.indexOf(p) !== -1) {
-                  return false;
-                }
-              }
-              return true;
-            });
-
-          return {
-            id: bundle.id,
-            modules: modules,
-            children: children,
-          };
-        });
-    }
-
-    function setMockFilesystem(mockFs) {
-      fs.__setMockFilesystem(Object.assign(mockFs, baseFs));
-    }
-
-    pit('should bundle single-module app', () => {
-      setMockFilesystem({
-        'root': {
-          'index.js': `
-            /**
-             * @providesModule xindex
-             */`,
-        }
-      });
-
-      return newBundlesLayout().getLayout('/root/index.js').then(bundles =>
-        stripPolyfills(bundles).then(resolvedBundles =>
-          expect(resolvedBundles).toEqual({
-            id: 'bundle.0',
-            modules: ['/root/index.js'],
-            children: [],
-          })
-        )
-      );
-    });
-
-    pit('should bundle dependant modules', () => {
-      setMockFilesystem({
-        'root': {
-          'index.js': `
-            /**
-             * @providesModule xindex
-             */
-            require("xa");`,
-          'a.js': `
-            /**
-             * @providesModule xa
-             */`,
-        }
-      });
-
-      return newBundlesLayout().getLayout('/root/index.js').then(bundles =>
-        stripPolyfills(bundles).then(resolvedBundles =>
-          expect(resolvedBundles).toEqual({
-            id: 'bundle.0',
-            modules: ['/root/index.js', '/root/a.js'],
-            children: [],
-          })
-        )
-      );
-    });
-
-    pit('should split bundles for async dependencies', () => {
-      setMockFilesystem({
-        'root': {
-          'index.js': `
-            /**
-             * @providesModule xindex
-             */
-            ${'System.import'}("xa");`,
-          'a.js': `
-            /**,
-             * @providesModule xa
-             */`,
-        }
-      });
-
-      return newBundlesLayout().getLayout('/root/index.js').then(bundles =>
-        stripPolyfills(bundles).then(resolvedBundles =>
-          expect(resolvedBundles).toEqual({
-            id: 'bundle.0',
-            modules: ['/root/index.js'],
-            children: [{
-              id: 'bundle.0.1',
-              modules: ['/root/a.js'],
-              children: [],
-            }],
-          })
-        )
-      );
-    });
-
-    pit('should split into multiple bundles separate async dependencies', () => {
-      setMockFilesystem({
-        'root': {
-          'index.js': `
-            /**
-             * @providesModule xindex
-             */
-            ${'System.import'}("xa");
-            ${'System.import'}("xb");`,
-          'a.js': `
-            /**,
-             * @providesModule xa
-             */`,
-          'b.js': `
-            /**
-             * @providesModule xb
-             */`,
-        }
-      });
-
-      return newBundlesLayout().getLayout('/root/index.js').then(bundles =>
-        stripPolyfills(bundles).then(resolvedBundles =>
-          expect(resolvedBundles).toEqual({
-            id: 'bundle.0',
-            modules: ['/root/index.js'],
-            children: [
-              {
-                id: 'bundle.0.1',
-                modules: ['/root/a.js'],
-                children: [],
-              }, {
-                id: 'bundle.0.2',
-                modules: ['/root/b.js'],
-                children: [],
-              },
-            ],
-          })
-        )
-      );
-    });
-
-    pit('should fully traverse sync dependencies', () => {
-      setMockFilesystem({
-        'root': {
-          'index.js': `
-            /**
-             * @providesModule xindex
-             */
-            require("xa");
-            ${'System.import'}("xb");`,
-          'a.js': `
-            /**,
-             * @providesModule xa
-             */`,
-          'b.js': `
-            /**
-             * @providesModule xb
-             */`,
-        }
-      });
-
-      return newBundlesLayout().getLayout('/root/index.js').then(bundles =>
-        stripPolyfills(bundles).then(resolvedBundles =>
-          expect(resolvedBundles).toEqual({
-            id: 'bundle.0',
-            modules: ['/root/index.js', '/root/a.js'],
-            children: [{
-              id: 'bundle.0.1',
-              modules: ['/root/b.js'],
-              children: [],
-            }],
-          })
-        )
-      );
-    });
-
-    pit('should include sync dependencies async dependencies might have', () => {
-      setMockFilesystem({
-        'root': {
-          'index.js': `
-            /**
-             * @providesModule xindex
-             */
-            ${'System.import'}("xa");`,
-          'a.js': `
-            /**,
-             * @providesModule xa
-             */,
-            require("xb");`,
-          'b.js': `
-            /**
-             * @providesModule xb
-             */
-            require("xc");`,
-          'c.js': `
-            /**
-             * @providesModule xc
-             */`,
-        }
-      });
-
-      return newBundlesLayout().getLayout('/root/index.js').then(bundles =>
-        stripPolyfills(bundles).then(resolvedBundles =>
-          expect(resolvedBundles).toEqual({
-            id: 'bundle.0',
-            modules: ['/root/index.js'],
-            children: [{
-              id: 'bundle.0.1',
-              modules: ['/root/a.js', '/root/b.js', '/root/c.js'],
-              children: [],
-            }],
-          })
-        )
-      );
-    });
-
-    pit('should allow duplicated dependencies across bundles', () => {
-      setMockFilesystem({
-        'root': {
-          'index.js': `
-            /**
-             * @providesModule xindex
-             */
-            ${'System.import'}("xa");
-            ${'System.import'}("xb");`,
-          'a.js': `
-            /**,
-             * @providesModule xa
-             */,
-            require("xc");`,
-          'b.js': `
-            /**
-             * @providesModule xb
-             */
-            require("xc");`,
-          'c.js': `
-            /**
-             * @providesModule xc
-             */`,
-        }
-      });
-
-      return newBundlesLayout().getLayout('/root/index.js').then(bundles =>
-        stripPolyfills(bundles).then(resolvedBundles =>
-          expect(resolvedBundles).toEqual({
-            id: 'bundle.0',
-            modules: ['/root/index.js'],
-            children: [
-              {
-                id: 'bundle.0.1',
-                modules: ['/root/a.js', '/root/c.js'],
-                children: [],
-              },
-              {
-                id: 'bundle.0.2',
-                modules: ['/root/b.js', '/root/c.js'],
-                children: [],
-              },
-            ],
-          })
-        )
-      );
-    });
-
-    pit('should put in separate bundles async dependencies of async dependencies', () => {
-      setMockFilesystem({
-        'root': {
-          'index.js': `
-            /**
-             * @providesModule xindex
-             */
-            ${'System.import'}("xa");`,
-          'a.js': `
-            /**,
-             * @providesModule xa
-             */,
-            ${'System.import'}("xb");`,
-          'b.js': `
-            /**
-             * @providesModule xb
-             */
-            require("xc");`,
-          'c.js': `
-            /**
-             * @providesModule xc
-             */`,
-        }
-      });
-
-      return newBundlesLayout().getLayout('/root/index.js').then(bundles =>
-        stripPolyfills(bundles).then(resolvedBundles =>
-          expect(resolvedBundles).toEqual({
-            id: 'bundle.0',
-            modules: ['/root/index.js'],
-            children: [
-              {
-                id: 'bundle.0.1',
-                modules: ['/root/a.js'],
-                children: [{
-                  id: 'bundle.0.1.2',
-                  modules: ['/root/b.js', '/root/c.js'],
-                  children: [],
-                }],
-              },
-            ],
-          })
-        )
-      );
-    });
-
-    pit('should put image dependencies into separate bundles', () => {
-      setMockFilesystem({
-        'root': {
-          'index.js': `
-            /**
-             * @providesModule xindex
-             */
-            ${'System.import'}("xa");`,
-          'a.js':`
-            /**,
-             * @providesModule xa
-             */,
-            require("./img.png");`,
-          'img.png': '',
-        }
-      });
-
-      return newBundlesLayout().getLayout('/root/index.js').then(bundles =>
-        stripPolyfills(bundles).then(resolvedBundles =>
-          expect(resolvedBundles).toEqual({
-            id: 'bundle.0',
-            modules: ['/root/index.js'],
-            children: [{
-              id: 'bundle.0.1',
-              modules: ['/root/a.js', '/root/img.png'],
-              children: [],
-            }],
-          })
-        )
-      );
-    });
-
-    pit('should put image dependencies across bundles', () => {
-      setMockFilesystem({
-        'root': {
-          'index.js': `
-            /**
-             * @providesModule xindex
-             */
-            ${'System.import'}("xa");
-            ${'System.import'}("xb");`,
-          'a.js':`
-            /**,
-             * @providesModule xa
-             */,
-            require("./img.png");`,
-          'b.js':`
-            /**,
-             * @providesModule xb
-             */,
-            require("./img.png");`,
-          'img.png': '',
-        }
-      });
-
-      return newBundlesLayout().getLayout('/root/index.js').then(bundles =>
-        stripPolyfills(bundles).then(resolvedBundles =>
-          expect(resolvedBundles).toEqual({
-            id: 'bundle.0',
-            modules: ['/root/index.js'],
-            children: [
-              {
-                id: 'bundle.0.1',
-                modules: ['/root/a.js', '/root/img.png'],
-                children: [],
-              },
-              {
-                id: 'bundle.0.2',
-                modules: ['/root/b.js', '/root/img.png'],
-                children: [],
-              },
-            ],
-          })
-        )
-      );
-    });
-
-    pit('could async require asset', () => {
-      setMockFilesystem({
-        'root': {
-          'index.js': `
-            /**
-             * @providesModule xindex
-             */
-            ${'System.import'}("./img.png");`,
-          'img.png': '',
-        }
-      });
-
-      return newBundlesLayout().getLayout('/root/index.js').then(bundles =>
-        stripPolyfills(bundles).then(resolvedBundles =>
-          expect(resolvedBundles).toEqual({
-            id: 'bundle.0',
-            modules: ['/root/index.js'],
-            children: [{
-              id: 'bundle.0.1',
-              modules: ['/root/img.png'],
-              children: [],
-            }],
-          })
-        )
-      );
-    });
-
-    pit('should include deprecated assets into separate bundles', () => {
-      setMockFilesystem({
-        'root': {
-          'index.js': `
-            /**
-             * @providesModule xindex
-             */
-            ${'System.import'}("xa");`,
-          'a.js':`
-            /**,
-             * @providesModule xa
-             */,
-            require("image!img");`,
-          'img.png': '',
-        }
-      });
-
-      return newBundlesLayout().getLayout('/root/index.js').then(bundles =>
-        stripPolyfills(bundles).then(resolvedBundles =>
-          expect(resolvedBundles).toEqual({
-            id: 'bundle.0',
-            modules: ['/root/index.js'],
-            children: [{
-              id: 'bundle.0.1',
-              modules: ['/root/a.js', '/root/img.png'],
-              children: [],
-            }],
-          })
-        )
-      );
-    });
-
-    pit('could async require deprecated asset', () => {
-      setMockFilesystem({
-        'root': {
-          'index.js': `
-            /**
-             * @providesModule xindex
-             */
-            ${'System.import'}("image!img");`,
-          'img.png': '',
-        }
-      });
-
-      return newBundlesLayout().getLayout('/root/index.js').then(bundles =>
-        stripPolyfills(bundles).then(resolvedBundles =>
-          expect(resolvedBundles).toEqual({
-            id: 'bundle.0',
-            modules: ['/root/index.js'],
-            children: [{
-              id: 'bundle.0.1',
-              modules: ['/root/img.png'],
-              children: [],
-            }],
-          })
-        )
-      );
-    });
-
-    pit('should put packages into bundles', () => {
-      setMockFilesystem({
-        'root': {
-          'index.js': `
-            /**
-             * @providesModule xindex
-             */
-            ${'System.import'}("aPackage");`,
-          'aPackage': {
-            'package.json': JSON.stringify({
-              name: 'aPackage',
-              main: './main.js',
-              browser: {
-                './main.js': './client.js',
-              },
-            }),
-            'main.js': 'some other code',
-            'client.js': 'some code',
-          },
-        }
-      });
-
-      return newBundlesLayout().getLayout('/root/index.js').then(bundles =>
-        stripPolyfills(bundles).then(resolvedBundles =>
-          expect(resolvedBundles).toEqual({
-            id: 'bundle.0',
-            modules: ['/root/index.js'],
-            children: [{
-              id: 'bundle.0.1',
-              modules: ['/root/aPackage/client.js'],
-              children: [],
-            }],
-          })
-        )
-      );
-    });
-  });
-
-  function getBaseFs() {
-    const p = path.join(__dirname, '../../../Resolver/polyfills').substring(1);
-    const root = {};
-    let currentPath = root;
-
-    p.split('/').forEach(part => {
-      const child = {};
-      currentPath[part] = child;
-      currentPath = child;
-    });
-
-    polyfills.forEach(polyfill =>
-      currentPath[polyfill.split('/')[1]] = ''
-    );
-
-    return root;
-  }
-});
diff --git a/packager/react-packager/src/BundlesLayout/index.js b/packager/react-packager/src/BundlesLayout/index.js
deleted file mode 100644
index 2fd906232af5..000000000000
--- a/packager/react-packager/src/BundlesLayout/index.js
+++ /dev/null
@@ -1,219 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-const Activity = require('../Activity');
-
-const _ = require('underscore');
-const declareOpts = require('../lib/declareOpts');
-const fs = require('fs');
-const getCacheFilePath = require('../DependencyResolver/Cache/lib/getCacheFilePath');
-const loadCacheSync = require('../DependencyResolver/Cache/lib/loadCacheSync');
-const version = require('../../../../package.json').version;
-const path = require('path');
-const tmpdir = require('os').tmpDir();
-
-const validateOpts = declareOpts({
-  dependencyResolver: {
-    type: 'object',
-    required: true,
-  },
-  resetCache: {
-    type: 'boolean',
-    default: false,
-  },
-  cacheVersion: {
-    type: 'string',
-    default: '1.0',
-  },
-  projectRoots: {
-    type: 'array',
-    required: true,
-  },
-});
-
-const BUNDLE_PREFIX = 'bundle';
-
-/**
- * Class that takes care of separating the graph of dependencies into
- * separate bundles
- */
-class BundlesLayout {
-  constructor(options) {
-    const opts = validateOpts(options);
-    this._resolver = opts.dependencyResolver;
-
-    // Cache in which bundle is each module.
-    this._moduleToBundle = Object.create(null);
-
-    // Cache the bundles layouts for each entry point. This entries
-    // are not evicted unless the user explicitly specifies so as
-    // computing them is pretty expensive
-    this._layouts = Object.create(null);
-
-    // TODO: watch for file creations and removals to update this caches
-
-    this._cacheFilePath = this._getCacheFilePath(opts);
-    if (!opts.resetCache) {
-      this._loadCacheSync(this._cacheFilePath);
-    } else {
-      this._persistCacheEventually();
-    }
-  }
-
-  getLayout(entryPath, isDev) {
-    if (this._layouts[entryPath]) {
-      return this._layouts[entryPath];
-    }
-    var currentBundleID =  0;
-    const rootBundle = {
-      id: BUNDLE_PREFIX + '.' + currentBundleID++,
-      modules: [],
-      children: [],
-    };
-    var pending = [{paths: [entryPath], bundle: rootBundle}];
-
-    this._layouts[entryPath] = promiseWhile(
-      () => pending.length > 0,
-      () => rootBundle,
-      () => {
-        const {paths, bundle} = pending.shift();
-
-        // pending sync dependencies we still need to explore for the current
-        // pending dependency
-        const pendingSyncDeps = paths;
-
-        // accum variable for sync dependencies of the current pending
-        // dependency we're processing
-        const syncDependencies = Object.create(null);
-
-        return promiseWhile(
-          () => pendingSyncDeps.length > 0,
-          () => {
-            const dependencies = Object.keys(syncDependencies);
-            if (dependencies.length > 0) {
-              bundle.modules = dependencies;
-            }
-
-            // persist changes to layouts
-            this._persistCacheEventually();
-          },
-          index => {
-            const pendingSyncDep = pendingSyncDeps.shift();
-            return this._resolver
-              .getDependencies(pendingSyncDep, {dev: isDev})
-              .then(deps => {
-                deps.dependencies.forEach(dep => {
-                  if (dep.path !== pendingSyncDep && !dep.isPolyfill()) {
-                    pendingSyncDeps.push(dep.path);
-                  }
-                  syncDependencies[dep.path] = true;
-                  this._moduleToBundle[dep.path] = bundle.id;
-                });
-                deps.asyncDependencies.forEach(asyncDeps => {
-                  const childBundle = {
-                    id: bundle.id + '.' + currentBundleID++,
-                    modules: [],
-                    children: [],
-                  };
-
-                  bundle.children.push(childBundle);
-                  pending.push({paths: asyncDeps, bundle: childBundle});
-                });
-              });
-          },
-        );
-      },
-    );
-
-    return this._layouts[entryPath];
-  }
-
-  getBundleIDForModule(path) {
-    return this._moduleToBundle[path];
-  }
-
-  _loadCacheSync(cachePath) {
-    const loadCacheId = Activity.startEvent('Loading bundles layout');
-    const cacheOnDisk = loadCacheSync(cachePath);
-
-    // TODO: create single-module bundles for unexistent modules
-    // TODO: remove modules that no longer exist
-    Object.keys(cacheOnDisk).forEach(entryPath => {
-      this._layouts[entryPath] = Promise.resolve(cacheOnDisk[entryPath]);
-      this._fillModuleToBundleMap(cacheOnDisk[entryPath]);
-    });
-
-    Activity.endEvent(loadCacheId);
-  }
-
-  _fillModuleToBundleMap(bundle) {
-    bundle.modules.forEach(module => this._moduleToBundle[module] = bundle.id);
-    bundle.children.forEach(child => this._fillModuleToBundleMap(child));
-  }
-
-  _persistCacheEventually() {
-    _.debounce(
-      this._persistCache.bind(this),
-      2000,
-    );
-  }
-
-  _persistCache() {
-    if (this._persisting !== null) {
-      return this._persisting;
-    }
-
-    this._persisting = Promise
-      .all(_.values(this._layouts))
-      .then(bundlesLayout => {
-        var json = Object.create(null);
-        Object.keys(this._layouts).forEach((p, i) =>
-          json[p] = bundlesLayout[i]
-        );
-
-        return Promise.denodeify(fs.writeFile)(
-          this._cacheFilepath,
-          JSON.stringify(json),
-        );
-      })
-      .then(() => this._persisting = null);
-
-    return this._persisting;
-  }
-
-  _getCacheFilePath(options) {
-    return getCacheFilePath(
-      tmpdir,
-      'react-packager-bundles-cache-',
-      version,
-      options.projectRoots.join(',').split(path.sep).join('-'),
-      options.cacheVersion || '0',
-    );
-  }
-}
-
-// Runs the body Promise meanwhile the condition callback is satisfied.
-// Once it's not satisfied anymore, it returns what the results callback
-// indicates
-function promiseWhile(condition, result, body) {
-  return _promiseWhile(condition, result, body, 0);
-}
-
-function _promiseWhile(condition, result, body, index) {
-  if (!condition()) {
-    return Promise.resolve(result());
-  }
-
-  return body(index).then(() =>
-    _promiseWhile(condition, result, body, index + 1)
-  );
-}
-
-module.exports = BundlesLayout;
diff --git a/packager/react-packager/src/DependencyResolver/AssetModule.js b/packager/react-packager/src/DependencyResolver/AssetModule.js
index f5555facd744..c2f51fbb2b44 100644
--- a/packager/react-packager/src/DependencyResolver/AssetModule.js
+++ b/packager/react-packager/src/DependencyResolver/AssetModule.js
@@ -21,10 +21,6 @@ class AssetModule extends Module {
     return Promise.resolve([]);
   }
 
-  getAsyncDependencies() {
-    return Promise.resolve([]);
-  }
-
   read() {
     return Promise.resolve({});
   }
diff --git a/packager/react-packager/src/DependencyResolver/AssetModule_DEPRECATED.js b/packager/react-packager/src/DependencyResolver/AssetModule_DEPRECATED.js
index a77d0aef5e93..3c4659462aa8 100644
--- a/packager/react-packager/src/DependencyResolver/AssetModule_DEPRECATED.js
+++ b/packager/react-packager/src/DependencyResolver/AssetModule_DEPRECATED.js
@@ -24,10 +24,6 @@ class AssetModule_DEPRECATED extends Module {
     return Promise.resolve([]);
   }
 
-  getAsyncDependencies() {
-    return Promise.resolve([]);
-  }
-
   hash() {
     return `AssetModule_DEPRECATED : ${this.path}`;
   }
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
index 879c53efa59f..c4004ed75183 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
@@ -187,23 +187,6 @@ class ResolutionRequest {
     });
   }
 
-  getAsyncDependencies(response) {
-    return Promise.resolve().then(() => {
-      const mod = this._moduleCache.getModule(this._entryPath);
-      return mod.getAsyncDependencies().then(bundles =>
-        Promise
-          .all(bundles.map(bundle =>
-            Promise.all(bundle.map(
-              dep => this.resolveDependency(mod, dep)
-            ))
-          ))
-          .then(bs => bs.map(bundle => bundle.map(dep => dep.path)))
-      );
-    }).then(asyncDependencies => asyncDependencies.forEach(
-      (dependency) => response.pushAsyncDependency(dependency)
-    ));
-  }
-
   _getAllMocks(pattern) {
     // Take all mocks in all the roots into account. This is necessary
     // because currently mocks are global: any module can be mocked by
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js
index c13895fbe1e9..56e1ed7a104b 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js
@@ -11,7 +11,6 @@
 class ResolutionResponse {
   constructor() {
     this.dependencies = [];
-    this.asyncDependencies = [];
     this.mainModuleId = null;
     this.mocks = null;
     this.numPrependedDependencies = 0;
@@ -22,13 +21,11 @@ class ResolutionResponse {
   copy(properties) {
     const {
       dependencies = this.dependencies,
-      asyncDependencies = this.asyncDependencies,
       mainModuleId = this.mainModuleId,
       mocks = this.mocks,
     } = properties;
     return Object.assign(new this.constructor(), this, {
       dependencies,
-      asyncDependencies,
       mainModuleId,
       mocks,
     });
@@ -69,11 +66,6 @@ class ResolutionResponse {
     this.numPrependedDependencies += 1;
   }
 
-  pushAsyncDependency(dependency) {
-    this._assertNotFinalized();
-    this.asyncDependencies.push(dependency);
-  }
-
   setResolvedDependencyPairs(module, pairs) {
     this._assertNotFinalized();
     const hash = module.hash();
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
index 09a4454373e2..990e234f82ad 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
@@ -4068,40 +4068,6 @@ describe('DependencyGraph', function() {
     });
   });
 
-  describe('getAsyncDependencies', () => {
-    pit('should get dependencies', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'System.' + 'import("a")',
-          ].join('\n'),
-          'a.js': [
-            '/**',
-            ' * @providesModule a',
-            ' */',
-          ].join('\n'),
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-
-      return dgraph.getDependencies('/root/index.js')
-        .then(response => response.finalize())
-        .then(({ asyncDependencies }) => {
-          expect(asyncDependencies).toEqual([
-            ['/root/a.js'],
-          ]);
-        });
-    });
-  });
-
   describe('Extensions', () => {
     pit('supports custom file extensions', () => {
       var root = '/root';
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
index 3c5ade661eb5..9241b18a119a 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
@@ -185,14 +185,11 @@ class DependencyGraph {
 
       const response = new ResolutionResponse();
 
-      return Promise.all([
-        req.getOrderedDependencies(
-          response,
-          this._opts.mocksPattern,
-          recursive,
-        ),
-        req.getAsyncDependencies(response),
-      ]).then(() => response);
+      return req.getOrderedDependencies(
+        response,
+        this._opts.mocksPattern,
+        recursive,
+      ).then(() => response);
     });
   }
 
diff --git a/packager/react-packager/src/DependencyResolver/Module.js b/packager/react-packager/src/DependencyResolver/Module.js
index f9142611fed3..116a52e093ce 100644
--- a/packager/react-packager/src/DependencyResolver/Module.js
+++ b/packager/react-packager/src/DependencyResolver/Module.js
@@ -91,14 +91,6 @@ class Module {
     );
   }
 
-  getAsyncDependencies() {
-    return this._cache.get(
-      this.path,
-      'asyncDependencies',
-      () => this.read().then(data => data.asyncDependencies)
-    );
-  }
-
   invalidate() {
     this._cache.invalidate(this.path);
   }
@@ -146,7 +138,6 @@ class Module {
         return {
           id,
           dependencies: [],
-          asyncDependencies: [],
           code: content,
         };
       } else {
@@ -155,13 +146,12 @@ class Module {
             ? transformCode(this, content)
             : Promise.resolve({code: content});
 
-        return codePromise.then(({code, dependencies, asyncDependencies}) => {
+        return codePromise.then(({code, dependencies}) => {
           const {deps} = this._extractor(code);
           return {
             id,
             code,
             dependencies: dependencies || deps.sync,
-            asyncDependencies: asyncDependencies || deps.async,
           };
         });
       }
diff --git a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js b/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
index 4ed5868b1860..71bc552278a2 100644
--- a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
+++ b/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
@@ -167,45 +167,6 @@ describe('Module', () => {
     });
   });
 
-  describe('Async Dependencies', () => {
-    function expectAsyncDependenciesToEqual(expected) {
-      const module = createModule();
-      return module.getAsyncDependencies().then(actual =>
-        expect(actual).toEqual(expected)
-      );
-    }
-
-    pit('should recognize single dependency', () => {
-      mockIndexFile('System.' + 'import("dep1")');
-
-      return expectAsyncDependenciesToEqual([['dep1']]);
-    });
-
-    pit('should parse single quoted dependencies', () => {
-      mockIndexFile('System.' + 'import(\'dep1\')');
-
-      return expectAsyncDependenciesToEqual([['dep1']]);
-    });
-
-    pit('should parse multiple async dependencies on the same module', () => {
-      mockIndexFile([
-        'System.' + 'import("dep1")',
-        'System.' + 'import("dep2")',
-      ].join('\n'));
-
-      return expectAsyncDependenciesToEqual([
-        ['dep1'],
-        ['dep2'],
-      ]);
-    });
-
-    pit('parse fine new lines', () => {
-      mockIndexFile('System.' + 'import(\n"dep1"\n)');
-
-      return expectAsyncDependenciesToEqual([['dep1']]);
-    });
-  });
-
   describe('Code', () => {
     const fileContents = 'arbitrary(code)';
     beforeEach(function() {
@@ -247,7 +208,7 @@ describe('Module', () => {
     const fileContents = 'arbitrary(code);';
     const exampleCode = `
       require('a');
-      System.import('b');
+      arbitrary.code('b');
       require('c');`;
 
     beforeEach(function() {
@@ -268,12 +229,8 @@ describe('Module', () => {
       transformCode.mockReturnValue(Promise.resolve({code: exampleCode}));
       const module = createModule({transformCode});
 
-      return Promise.all([
-        module.getDependencies(),
-        module.getAsyncDependencies(),
-      ]).then(([dependencies, asyncDependencies]) => {
+      return module.getDependencies().then(dependencies => {
         expect(dependencies).toEqual(['a', 'c']);
-        expect(asyncDependencies).toEqual([['b']]);
       });
     });
 
@@ -285,29 +242,8 @@ describe('Module', () => {
       }));
       const module = createModule({transformCode});
 
-      return Promise.all([
-        module.getDependencies(),
-        module.getAsyncDependencies(),
-      ]).then(([dependencies, asyncDependencies]) => {
+      return module.getDependencies().then(dependencies => {
         expect(dependencies).toEqual(mockedDependencies);
-        expect(asyncDependencies).toEqual([['b']]);
-      });
-    });
-
-    pit('uses async dependencies that `transformCode` resolves to, instead of extracting them', () => {
-      const mockedAsyncDependencies = [['foo', 'bar'], ['baz']];
-      transformCode.mockReturnValue(Promise.resolve({
-        code: exampleCode,
-        asyncDependencies: mockedAsyncDependencies,
-      }));
-      const module = createModule({transformCode});
-
-      return Promise.all([
-        module.getDependencies(),
-        module.getAsyncDependencies(),
-      ]).then(([dependencies, asyncDependencies]) => {
-        expect(dependencies).toEqual(['a', 'c']);
-        expect(asyncDependencies).toEqual(mockedAsyncDependencies);
       });
     });
 
diff --git a/packager/react-packager/src/DependencyResolver/lib/extractRequires.js b/packager/react-packager/src/DependencyResolver/lib/extractRequires.js
index 107cc6ba9e36..5dbf63cc6b4b 100644
--- a/packager/react-packager/src/DependencyResolver/lib/extractRequires.js
+++ b/packager/react-packager/src/DependencyResolver/lib/extractRequires.js
@@ -18,7 +18,6 @@ const lineCommentRe = /\/\/.+(\n|$)/g;
 function extractRequires(code) {
   var deps = {
     sync: [],
-    async: [],
   };
 
   code = code
@@ -41,15 +40,6 @@ function extractRequires(code) {
       deps.sync.push(dep);
       return match;
     })
-    // Parse async dependencies this module has. As opposed to what happens
-    // with sync dependencies, when the module is required, it's async
-    // dependencies won't be loaded into memory. This is deferred till the
-    // code path gets to the import statement:
-    //   System.import('dep1')
-    .replace(replacePatterns.SYSTEM_IMPORT_RE, (match, pre, quot, dep, post) => {
-      deps.async.push([dep]);
-      return match;
-    });
 
   return {code, deps};
 }
diff --git a/packager/react-packager/src/DependencyResolver/lib/replacePatterns.js b/packager/react-packager/src/DependencyResolver/lib/replacePatterns.js
index a4e563d2c67c..8c10710ec459 100644
--- a/packager/react-packager/src/DependencyResolver/lib/replacePatterns.js
+++ b/packager/react-packager/src/DependencyResolver/lib/replacePatterns.js
@@ -12,4 +12,3 @@
 exports.IMPORT_RE = /(\bimport\s+(?:[^'"]+\s+from\s+)??)(['"])([^'"]+)(\2)/g;
 exports.EXPORT_RE = /(\bexport\s+(?:[^'"]+\s+from\s+)??)(['"])([^'"]+)(\2)/g;
 exports.REQUIRE_RE = /(\brequire\s*?\(\s*?)(['"])([^'"]+)(\2\s*?\))/g;
-exports.SYSTEM_IMPORT_RE = /(\bSystem\.import\s*?\(\s*?)(['"])([^'"]+)(\2\s*?\))/g;
diff --git a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
index 7ef335d9b3d2..2f1f65dea676 100644
--- a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
+++ b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
@@ -37,10 +37,9 @@ describe('Resolver', function() {
   });
 
   class ResolutionResponseMock {
-    constructor({dependencies, mainModuleId, asyncDependencies}) {
+    constructor({dependencies, mainModuleId}) {
       this.dependencies = dependencies;
       this.mainModuleId = mainModuleId;
-      this.asyncDependencies = asyncDependencies;
     }
 
     prependDependency(dependency) {
@@ -80,7 +79,6 @@ describe('Resolver', function() {
         return Promise.resolve(new ResolutionResponseMock({
           dependencies: deps,
           mainModuleId: 'index',
-          asyncDependencies: [],
         }));
       });
 
@@ -180,7 +178,6 @@ describe('Resolver', function() {
         return Promise.resolve(new ResolutionResponseMock({
           dependencies: deps,
           mainModuleId: 'index',
-          asyncDependencies: [],
         }));
       });
 
@@ -208,7 +205,6 @@ describe('Resolver', function() {
         return Promise.resolve(new ResolutionResponseMock({
           dependencies: deps,
           mainModuleId: 'index',
-          asyncDependencies: [],
         }));
       });
 
@@ -637,7 +633,6 @@ describe('Resolver', function() {
       const resolutionResponse = new ResolutionResponseMock({
         dependencies: [module],
         mainModuleId: 'test module',
-        asyncDependencies: [],
       });
 
       resolutionResponse.getResolvedDependencyPairs = (module) => {
diff --git a/packager/react-packager/src/Resolver/polyfills/__tests__/loadBundles-test.js b/packager/react-packager/src/Resolver/polyfills/__tests__/loadBundles-test.js
deleted file mode 100644
index 39d687881885..000000000000
--- a/packager/react-packager/src/Resolver/polyfills/__tests__/loadBundles-test.js
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-jest.dontMock('../loadBundles');
-jest.mock('NativeModules');
-
-let loadBundles;
-let loadBundlesCalls;
-
-describe('loadBundles', () => {
-  beforeEach(() => {
-    loadBundles = jest.genMockFunction();
-    loadBundlesCalls = loadBundles.mock.calls;
-    require('NativeModules').RCTBundlesLoader = {loadBundles};
-
-    require('../loadBundles');
-  });
-
-  it('should set `global.__loadBundles` function when polyfill is initialized', () => {
-    expect(typeof global.__loadBundles).toBe('function');
-  });
-
-  it('should return a promise', () => {
-    loadBundles.mockImpl((bundles, callback) => callback());
-    expect(global.__loadBundles(['bundle.0']) instanceof Promise).toBeTruthy();
-  });
-
-  pit('shouldn\'t request already loaded bundles', () => {
-    loadBundles.mockImpl((bundles, callback) => callback());
-    return global.__loadBundles(['bundle.0'])
-      .then(() => global.__loadBundles(['bundle.0']))
-      .then(() => expect(loadBundlesCalls.length).toBe(1));
-  });
-
-  pit('shouldn\'n request inflight bundles', () => {
-    loadBundles.mockImpl((bundles, callback) => {
-      if (bundles.length === 1 && bundles[0] === 'bundle.0') {
-        setTimeout(callback, 1000);
-      } else if (bundles.length === 1 && bundles[0] === 'bundle.1') {
-        setTimeout(callback, 500);
-      }
-    });
-
-    const promises = Promise.all([
-      global.__loadBundles(['bundle.0']),
-      global.__loadBundles(['bundle.0', 'bundle.1']),
-    ]).then(() => {
-      expect(loadBundlesCalls.length).toBe(2);
-      expect(loadBundlesCalls[0][0][0]).toBe('bundle.0');
-      expect(loadBundlesCalls[1][0][0]).toBe('bundle.1');
-    });
-
-    jest.runAllTimers();
-    return promises;
-  });
-});
diff --git a/packager/react-packager/src/Resolver/polyfills/loadBundles.js b/packager/react-packager/src/Resolver/polyfills/loadBundles.js
deleted file mode 100644
index 7bb9be104a32..000000000000
--- a/packager/react-packager/src/Resolver/polyfills/loadBundles.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/* eslint strict:0 */
-
-let loadBundlesOnNative = (bundles) =>
-  new Promise((resolve) =>
-    require('NativeModules').RCTBundlesLoader.loadBundles(bundles, resolve));
-
-let requestedBundles = Object.create(null);
-
-/**
- * Returns a promise that is fulfilled once all the indicated bundles are
- * loaded into memory and injected into the JS engine.
- * This invokation might need to go through the bridge
- * and run native code to load some, if not all, the requested bundles.
- * If all the bundles have already been loaded, the promise is resolved
- * immediately. Otherwise, we'll determine which bundles still need to get
- * loaded considering both, the ones already loaded, and the ones being
- * currently asynchronously loaded by other invocations to `__loadBundles`,
- * and return a promise that will get fulfilled once all these are finally
- * loaded.
- *
- * Note this function should only be invoked by generated code.
- */
-global.__loadBundles = function(bundles) {
-  // split bundles by whether they've already been requested or not
-  const bundlesToRequest = bundles.filter(b => !requestedBundles[b]);
-
-  // keep a reference to the promise loading each bundle
-  if (bundlesToRequest.length > 0) {
-    const nativePromise = loadBundlesOnNative(bundlesToRequest);
-    bundlesToRequest.forEach(b => requestedBundles[b] = nativePromise);
-  }
-
-  return Promise.all(bundles.map(bundle => requestedBundles[bundle]));
-};
diff --git a/packager/react-packager/src/transforms/babel-plugin-system-import/__tests__/babel-plugin-system-import-test.js b/packager/react-packager/src/transforms/babel-plugin-system-import/__tests__/babel-plugin-system-import-test.js
deleted file mode 100644
index b29f1bd55be6..000000000000
--- a/packager/react-packager/src/transforms/babel-plugin-system-import/__tests__/babel-plugin-system-import-test.js
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * Copyright 2004-present Facebook. All Rights Reserved.
- *
- * @emails oncall+jsinfra
- */
-
-'use strict';
-
-jest.autoMockOff();
-jest.mock('../../../BundlesLayout');
-
-const babel = require('babel-core');
-const BundlesLayout = require('../../../BundlesLayout');
-
-const testData = {
-  isolated: {
-    input:  'System.' + 'import("moduleA");',
-    output: 'loadBundles(["bundle.0"]);'
-  },
-  single: {
-    input:  'System.' + 'import("moduleA").then(function (bundleA) {});',
-    output: 'loadBundles(["bundle.0"]).then(function (bundleA) {});'
-  },
-  multiple: {
-    input: [
-      'Promise.all([',
-        'System.' + 'import("moduleA"), System.' + 'import("moduleB"),',
-      ']).then(function (bundlesA, bundlesB) {});',
-    ].join('\n'),
-    output: [
-      'Promise.all([',
-        'loadBundles(["bundle.0"]), loadBundles(["bundle.1"])',
-      ']).then(function (bundlesA, bundlesB) {});',
-    ].join(''),
-  },
-};
-
-describe('System.import', () => {
-  let layout = new BundlesLayout();
-  BundlesLayout.prototype.getBundleIDForModule.mockImpl(module => {
-    switch (module) {
-      case 'moduleA': return 'bundle.0';
-      case 'moduleB': return 'bundle.1';
-    }
-  });
-
-  function transform(source) {
-    return babel.transform(source, {
-      plugins: [
-        [require('../'), { bundlesLayout: layout }]
-      ],
-    }).code;
-  }
-
-  function test(data) {
-    // transform and remove new lines
-    expect(transform(data.input).replace(/(\r\n|\n|\r)/gm,'')).toEqual(data.output);
-  }
-
-  it('should transform isolated `System.import`', () => {
-    test(testData.isolated);
-  });
-
-  it('should transform single `System.import`', () => {
-    test(testData.single);
-  });
-
-  it('should transform multiple `System.import`s', () => {
-    test(testData.multiple);
-  });
-});
diff --git a/packager/react-packager/src/transforms/babel-plugin-system-import/index.js b/packager/react-packager/src/transforms/babel-plugin-system-import/index.js
deleted file mode 100644
index 7cf0f0a08524..000000000000
--- a/packager/react-packager/src/transforms/babel-plugin-system-import/index.js
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
- * 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.
- *
- */
-/*jslint node: true */
-'use strict';
-
-const t = require('babel-types');
-
-/**
-* Transforms asynchronous module importing into a function call
-* that includes which bundle needs to be loaded
-*
-* Transforms:
-*
-*  System.import('moduleA')
-*
-* to:
-*
-*  loadBundles('bundleA')
-*/
-module.exports = function() {
- return {
-   visitor: {
-     CallExpression: function (path, state) {
-       if (!isAppropriateSystemImportCall(path.node)) {
-         return;
-       }
-
-       var bundlesLayout = state.opts.bundlesLayout;
-       var bundleID = bundlesLayout.getBundleIDForModule(
-         path.node.arguments[0].value
-       );
-
-       var bundles = bundleID.split('.');
-       bundles.splice(0, 1);
-       bundles = bundles.map(function(id) {
-         return t.stringLiteral('bundle.' + id);
-       });
-
-       path.replaceWith(t.callExpression(
-         t.identifier('loadBundles'),
-         [t.arrayExpression(bundles)]
-       ));
-     },
-   },
- };
-};
-
-function isAppropriateSystemImportCall(node) {
- return (
-   node.callee.type === 'MemberExpression' &&
-   node.callee.object.name === 'System' &&
-   node.callee.property.name === 'import' &&
-   node.arguments.length === 1 &&
-   node.arguments[0].type === 'StringLiteral'
- );
-}

From 272096ce7c0d3dfb0302079cefbb6f72e43a9870 Mon Sep 17 00:00:00 2001
From: Henry Kirkness <henry@kirkness.com>
Date: Tue, 9 Feb 2016 18:46:42 -0800
Subject: [PATCH 1105/1411] Added Choke to showcase

Summary: Closes https://github.com/facebook/react-native/pull/5848

Reviewed By: svcscm

Differential Revision: D2920042

Pulled By: androidtrunkagent

fb-gh-sync-id: e45d4789200e1825e319eaf7bb70d3ff52c12325
shipit-source-id: e45d4789200e1825e319eaf7bb70d3ff52c12325
---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 9b3b8722de38..83ebcb88eac9 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -166,6 +166,12 @@ var apps = [
     link: 'https://play.google.com/store/apps/details?id=com.cbssports.fantasy.franchisefootball2015',
     author: 'CBS Sports',
   },
+  {
+    name: 'Choke - Rap Battle With Friends',
+    icon: 'http://a3.mzstatic.com/us/r30/Purple49/v4/3e/83/85/3e8385d8-140f-da38-a100-1393cef3e816/icon175x175.png',
+    link: 'https://itunes.apple.com/us/app/choke-rap-battle-with-friends/id1077937445?ls=1&mt=8',
+    author: 'Henry Kirkness',
+  },
   {
     name: 'Codementor - Live 1:1 Expert Developer Help',
     icon: 'http://a1.mzstatic.com/us/r30/Purple3/v4/db/cf/35/dbcf3523-bac7-0f54-c6a8-a80bf4f43c38/icon175x175.jpeg',

From a11f980a3425149bed7f560a3162315cc8c0e82f Mon Sep 17 00:00:00 2001
From: Christopher Dro <hello@blick-labs.com>
Date: Tue, 9 Feb 2016 19:15:52 -0800
Subject: [PATCH 1106/1411] Remove isRequired on source prop for Android

Summary:
Makes source required across both platforms.
Closes https://github.com/facebook/react-native/pull/5845

Reviewed By: svcscm

Differential Revision: D2920250

Pulled By: vjeux

fb-gh-sync-id: 21845b601df32dc2e12a95544afa3db4c0414746
shipit-source-id: 21845b601df32dc2e12a95544afa3db4c0414746
---
 Libraries/Image/Image.android.js | 4 ++--
 Libraries/Image/Image.ios.js     | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Libraries/Image/Image.android.js b/Libraries/Image/Image.android.js
index 4c920dcf2aa5..fdc8c2f64cec 100644
--- a/Libraries/Image/Image.android.js
+++ b/Libraries/Image/Image.android.js
@@ -63,7 +63,7 @@ var ImageViewAttributes = merge(ReactNativeViewAttributes.UIView, {
 var Image = React.createClass({
   propTypes: {
     ...View.propTypes,
-    style: StyleSheetPropType(ImageStylePropTypes), 
+    style: StyleSheetPropType(ImageStylePropTypes),
    /**
      * `uri` is a string representing the resource identifier for the image, which
      * could be an http address, a local file path, or a static image
@@ -75,7 +75,7 @@ var Image = React.createClass({
       }),
       // Opaque type returned by require('./image.jpg')
       PropTypes.number,
-    ]).isRequired,
+    ]),
     /**
      * similarly to `source`, this property represents the resource used to render
      * the loading indicator for the image, displayed until image is ready to be
diff --git a/Libraries/Image/Image.ios.js b/Libraries/Image/Image.ios.js
index 4830a6dec336..625dc8d50eca 100644
--- a/Libraries/Image/Image.ios.js
+++ b/Libraries/Image/Image.ios.js
@@ -213,7 +213,7 @@ var Image = React.createClass({
     if (this.context.isInAParentText) {
       RawImage = RCTVirtualImage;
       if (!width || !height) {
-        console.warn('You must specify a width and height for the image %s', uri); 
+        console.warn('You must specify a width and height for the image %s', uri);
       }
     }
 

From 142f8c92de22a27bcbf09d8a0626a562c67a6aff Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andreas=20Stu=CC=88tz?= <andreas.stuetz@runtastic.com>
Date: Wed, 10 Feb 2016 05:00:32 -0800
Subject: [PATCH 1107/1411] Fixed icon handling

Summary:
[This commit](https://github.com/facebook/react-native/commit/e730a9fdd08e63eabf75963ed9cdc17564cf0bfb) (_Load assets from same folder as JSbundle (Android)_) causes React Native to look for assets inside the same folder the JSBundle was loaded from and generates asset URIs containing the absolute path to the asset (e.g. _/sdcard/bundle/drawable-xxhdpi/ic_back.png_).

While this is fine for a normal `ImageView`, `ToolbarAndroid`/`ReactToolbar` currently crashes if the icons are located on the file system. This happens because when setting an icon on `ReactToolbar`, Fresco is only used if the icon URI contains `http:// `or `https://`. For all other cases (like in this case where it starts with `file://`), the view tries to load the Drawable from the Android App Resources by it's name (which in this case is an absolute file-URI) and therefore causes it to crash (`getDrawableResourceByName` returns 0 if the Drawable was not found, then `getResources().getDrawable(DrawableRes int id)` throws an Exception if th
Closes https://github.com/facebook/react-native/pull/5753

Reviewed By: svcscm

Differential Revision: D2921418

Pulled By: foghina

fb-gh-sync-id: 7a3f81b530a8c1530e98e7b592ee7e44c8f19df1
shipit-source-id: 7a3f81b530a8c1530e98e7b592ee7e44c8f19df1
---
 .../react/views/toolbar/ReactToolbar.java     | 278 ++++++++++--------
 1 file changed, 157 insertions(+), 121 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbar.java b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbar.java
index 5fe30921a695..aae498379410 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbar.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbar.java
@@ -2,8 +2,6 @@
 
 package com.facebook.react.views.toolbar;
 
-import javax.annotation.Nullable;
-
 import android.content.Context;
 import android.graphics.drawable.Animatable;
 import android.graphics.drawable.Drawable;
@@ -14,7 +12,6 @@
 
 import com.facebook.drawee.backends.pipeline.Fresco;
 import com.facebook.drawee.controller.BaseControllerListener;
-import com.facebook.drawee.controller.ControllerListener;
 import com.facebook.drawee.drawable.ScalingUtils;
 import com.facebook.drawee.generic.GenericDraweeHierarchy;
 import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
@@ -22,88 +19,110 @@
 import com.facebook.drawee.view.DraweeHolder;
 import com.facebook.drawee.view.MultiDraweeHolder;
 import com.facebook.imagepipeline.image.ImageInfo;
+import com.facebook.imagepipeline.image.QualityInfo;
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.uimanager.PixelUtil;
+
+import javax.annotation.Nullable;
 
 /**
  * Custom implementation of the {@link Toolbar} widget that adds support for remote images in logo
  * and navigationIcon using fresco.
  */
 public class ReactToolbar extends Toolbar {
+
   private static final String PROP_ACTION_ICON = "icon";
   private static final String PROP_ACTION_SHOW = "show";
   private static final String PROP_ACTION_SHOW_WITH_TEXT = "showWithText";
   private static final String PROP_ACTION_TITLE = "title";
 
+  private static final String PROP_ICON_URI = "uri";
+  private static final String PROP_ICON_WIDTH = "width";
+  private static final String PROP_ICON_HEIGHT = "height";
+
   private final DraweeHolder mLogoHolder;
   private final DraweeHolder mNavIconHolder;
   private final DraweeHolder mOverflowIconHolder;
   private final MultiDraweeHolder<GenericDraweeHierarchy> mActionsHolder =
-      new MultiDraweeHolder<>();
-
-  private final ControllerListener<ImageInfo> mLogoControllerListener =
-      new BaseControllerListener<ImageInfo>() {
-        @Override
-        public void onFinalImageSet(
-            String id,
-            @Nullable final ImageInfo imageInfo,
-            @Nullable Animatable animatable) {
-          if (imageInfo != null) {
-            final DrawableWithIntrinsicSize logoDrawable =
-                new DrawableWithIntrinsicSize(mLogoHolder.getTopLevelDrawable(), imageInfo);
-            setLogo(logoDrawable);
-          }
-        }
-      };
-
-  private final ControllerListener<ImageInfo> mNavIconControllerListener =
-      new BaseControllerListener<ImageInfo>() {
-        @Override
-        public void onFinalImageSet(
-            String id,
-            @Nullable final ImageInfo imageInfo,
-            @Nullable Animatable animatable) {
-          if (imageInfo != null) {
-            final DrawableWithIntrinsicSize navIconDrawable =
-                new DrawableWithIntrinsicSize(mNavIconHolder.getTopLevelDrawable(), imageInfo);
-            setNavigationIcon(navIconDrawable);
-          }
-        }
-      };
-
-  private final ControllerListener<ImageInfo> mOverflowIconControllerListener =
-      new BaseControllerListener<ImageInfo>() {
-        @Override
-        public void onFinalImageSet(
-            String id,
-            @Nullable final ImageInfo imageInfo,
-            @Nullable Animatable animatable) {
-          if (imageInfo != null) {
-            final DrawableWithIntrinsicSize overflowIconDrawable =
-                new DrawableWithIntrinsicSize(mOverflowIconHolder.getTopLevelDrawable(), imageInfo);
-            setOverflowIcon(overflowIconDrawable);
-          }
-        }
-      };
+          new MultiDraweeHolder<>();
+
+  private IconControllerListener mLogoControllerListener;
+  private IconControllerListener mNavIconControllerListener;
+  private IconControllerListener mOverflowIconControllerListener;
+
+  /**
+   * Attaches specific icon width & height to a BaseControllerListener which will be used to
+   * create the Drawable
+   */
+  private abstract class IconControllerListener extends BaseControllerListener<ImageInfo> {
 
-  private static class ActionIconControllerListener extends BaseControllerListener<ImageInfo> {
-    private final MenuItem mItem;
     private final DraweeHolder mHolder;
 
+    private IconImageInfo mIconImageInfo;
+
+    public IconControllerListener(DraweeHolder holder) {
+      mHolder = holder;
+    }
+
+    public void setIconImageInfo(IconImageInfo iconImageInfo) {
+      mIconImageInfo = iconImageInfo;
+    }
+
+    @Override
+    public void onFinalImageSet(String id, @Nullable ImageInfo imageInfo, @Nullable Animatable animatable) {
+      super.onFinalImageSet(id, imageInfo, animatable);
+
+      final ImageInfo info = mIconImageInfo != null ? mIconImageInfo : imageInfo;
+      setDrawable(new DrawableWithIntrinsicSize(mHolder.getTopLevelDrawable(), info));
+    }
+
+    protected abstract void setDrawable(Drawable d);
+
+  }
+
+  private class ActionIconControllerListener extends IconControllerListener {
+    private final MenuItem mItem;
+
     ActionIconControllerListener(MenuItem item, DraweeHolder holder) {
+      super(holder);
       mItem = item;
-      mHolder = holder;
     }
 
     @Override
-    public void onFinalImageSet(
-        String id,
-        @Nullable ImageInfo imageInfo,
-        @Nullable Animatable animatable) {
-      if (imageInfo != null) {
-        mItem.setIcon(new DrawableWithIntrinsicSize(mHolder.getTopLevelDrawable(), imageInfo));
-      }
+    protected void setDrawable(Drawable d) {
+      mItem.setIcon(d);
+    }
+  }
+
+  /**
+   * Simple implementation of ImageInfo, only providing width & height
+   */
+  private static class IconImageInfo implements ImageInfo {
+
+    private int mWidth;
+    private int mHeight;
+
+    public IconImageInfo(int width, int height) {
+      mWidth = width;
+      mHeight = height;
+    }
+
+    @Override
+    public int getWidth() {
+      return mWidth;
+    }
+
+    @Override
+    public int getHeight() {
+      return mHeight;
+    }
+
+    @Override
+    public QualityInfo getQualityInfo() {
+      return null;
     }
+
   }
 
   public ReactToolbar(Context context) {
@@ -112,6 +131,28 @@ public ReactToolbar(Context context) {
     mLogoHolder = DraweeHolder.create(createDraweeHierarchy(), context);
     mNavIconHolder = DraweeHolder.create(createDraweeHierarchy(), context);
     mOverflowIconHolder = DraweeHolder.create(createDraweeHierarchy(), context);
+
+    mLogoControllerListener = new IconControllerListener(mLogoHolder) {
+      @Override
+      protected void setDrawable(Drawable d) {
+        setLogo(d);
+      }
+    };
+
+    mNavIconControllerListener = new IconControllerListener(mNavIconHolder) {
+      @Override
+      protected void setDrawable(Drawable d) {
+        setNavigationIcon(d);
+      }
+    };
+
+    mOverflowIconControllerListener = new IconControllerListener(mOverflowIconHolder) {
+      @Override
+      protected void setDrawable(Drawable d) {
+        setOverflowIcon(d);
+      }
+    };
+
   }
 
   private final Runnable mLayoutRunnable = new Runnable() {
@@ -172,51 +213,15 @@ private void attachDraweeHolders() {
   }
 
   /* package */ void setLogoSource(@Nullable ReadableMap source) {
-    String uri = source != null ? source.getString("uri") : null;
-    if (uri == null) {
-      setLogo(null);
-    } else if (uri.startsWith("http://") || uri.startsWith("https://")) {
-      DraweeController controller = Fresco.newDraweeControllerBuilder()
-          .setUri(Uri.parse(uri))
-          .setControllerListener(mLogoControllerListener)
-          .setOldController(mLogoHolder.getController())
-          .build();
-      mLogoHolder.setController(controller);
-    } else {
-      setLogo(getDrawableResourceByName(uri));
-    }
+    setIconSource(source, mLogoControllerListener, mLogoHolder);
   }
 
   /* package */ void setNavIconSource(@Nullable ReadableMap source) {
-    String uri = source != null ? source.getString("uri") : null;
-    if (uri == null) {
-      setNavigationIcon(null);
-    } else if (uri.startsWith("http://") || uri.startsWith("https://")) {
-      DraweeController controller = Fresco.newDraweeControllerBuilder()
-          .setUri(Uri.parse(uri))
-          .setControllerListener(mNavIconControllerListener)
-          .setOldController(mNavIconHolder.getController())
-          .build();
-      mNavIconHolder.setController(controller);
-    } else {
-      setNavigationIcon(getDrawableResourceByName(uri));
-    }
+    setIconSource(source, mNavIconControllerListener, mNavIconHolder);
   }
 
   /* package */ void setOverflowIconSource(@Nullable ReadableMap source) {
-    String uri = source != null ? source.getString("uri") : null;
-    if (uri == null) {
-      setOverflowIcon(null);
-    } else if (uri.startsWith("http://") || uri.startsWith("https://")) {
-      DraweeController controller = Fresco.newDraweeControllerBuilder()
-          .setUri(Uri.parse(uri))
-          .setControllerListener(mOverflowIconControllerListener)
-          .setOldController(mOverflowIconHolder.getController())
-          .build();
-      mOverflowIconHolder.setController(controller);
-    } else {
-      setOverflowIcon(getDrawableByName(uri));
-    }
+    setIconSource(source, mOverflowIconControllerListener, mOverflowIconHolder);
   }
 
   /* package */ void setActions(@Nullable ReadableArray actions) {
@@ -226,16 +231,13 @@ private void attachDraweeHolders() {
     if (actions != null) {
       for (int i = 0; i < actions.size(); i++) {
         ReadableMap action = actions.getMap(i);
+
         MenuItem item = menu.add(Menu.NONE, Menu.NONE, i, action.getString(PROP_ACTION_TITLE));
-        ReadableMap icon = action.hasKey(PROP_ACTION_ICON) ? action.getMap(PROP_ACTION_ICON) : null;
-        if (icon != null) {
-          String iconSource = icon.getString("uri");
-          if (iconSource.startsWith("http://") || iconSource.startsWith("https://")) {
-            setMenuItemIcon(item, icon);
-          } else {
-            item.setIcon(getDrawableResourceByName(iconSource));
-          }
+
+        if (action.hasKey(PROP_ACTION_ICON)) {
+          setMenuItemIcon(item, action.getMap(PROP_ACTION_ICON));
         }
+
         int showAsAction = action.hasKey(PROP_ACTION_SHOW)
             ? action.getInt(PROP_ACTION_SHOW)
             : MenuItem.SHOW_AS_ACTION_NEVER;
@@ -248,24 +250,43 @@ private void attachDraweeHolders() {
     }
   }
 
-  /**
-   * This is only used when the icon is remote (http/s). Creates & adds a new {@link DraweeHolder}
-   * to {@link #mActionsHolder} and attaches a {@link ActionIconControllerListener} that just sets
-   * the top level drawable when it's loaded.
-   */
-  private void setMenuItemIcon(MenuItem item, ReadableMap icon) {
-    String iconSource = icon.getString("uri");
+  private void setMenuItemIcon(final MenuItem item, ReadableMap iconSource) {
 
     DraweeHolder<GenericDraweeHierarchy> holder =
-        DraweeHolder.create(createDraweeHierarchy(), getContext());
-    DraweeController controller = Fresco.newDraweeControllerBuilder()
-        .setUri(Uri.parse(iconSource))
-        .setControllerListener(new ActionIconControllerListener(item, holder))
-        .setOldController(holder.getController())
-        .build();
-    holder.setController(controller);
+            DraweeHolder.create(createDraweeHierarchy(), getContext());
+    ActionIconControllerListener controllerListener = new ActionIconControllerListener(item, holder);
+    controllerListener.setIconImageInfo(getIconImageInfo(iconSource));
+
+    setIconSource(iconSource, controllerListener, holder);
 
     mActionsHolder.add(holder);
+
+  }
+
+  /**
+   * Sets an icon for a specific icon source. If the uri indicates an icon
+   * to be somewhere remote (http/https) or on the local filesystem, it uses fresco to load it.
+   * Otherwise it loads the Drawable from the Resources and directly returns it via a callback
+   */
+  private void setIconSource(ReadableMap source, IconControllerListener controllerListener, DraweeHolder holder) {
+
+    String uri = source != null ? source.getString(PROP_ICON_URI) : null;
+
+    if (uri == null) {
+      controllerListener.setIconImageInfo(null);
+      controllerListener.setDrawable(null);
+    } else if (uri.startsWith("http://") || uri.startsWith("https://") || uri.startsWith("file://")) {
+      controllerListener.setIconImageInfo(getIconImageInfo(source));
+      DraweeController controller = Fresco.newDraweeControllerBuilder()
+              .setUri(Uri.parse(uri))
+              .setControllerListener(controllerListener)
+              .setOldController(holder.getController())
+              .build();
+      holder.setController(controller);
+    } else {
+      controllerListener.setDrawable(getDrawableByName(uri));
+    }
+
   }
 
   private GenericDraweeHierarchy createDraweeHierarchy() {
@@ -283,7 +304,22 @@ private int getDrawableResourceByName(String name) {
   }
 
   private Drawable getDrawableByName(String name) {
-    return getResources().getDrawable(getDrawableResourceByName(name));
+    int drawableResId = getDrawableResourceByName(name);
+    if (drawableResId != 0) {
+      return getResources().getDrawable(getDrawableResourceByName(name));
+    } else {
+      return null;
+    }
+  }
+
+  private IconImageInfo getIconImageInfo(ReadableMap source) {
+    if (source.hasKey(PROP_ICON_WIDTH) && source.hasKey(PROP_ICON_HEIGHT)) {
+      final int width = Math.round(PixelUtil.toPixelFromDIP(source.getInt(PROP_ICON_WIDTH)));
+      final int height = Math.round(PixelUtil.toPixelFromDIP(source.getInt(PROP_ICON_HEIGHT)));
+      return new IconImageInfo(width, height);
+    } else {
+      return null;
+    }
   }
 
 }

From 152f1ee58cd3b6f65292c38a7cbe9e280ab914c1 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Wed, 10 Feb 2016 14:21:06 +0000
Subject: [PATCH 1108/1411] removed temporarilty .travis.yml

It will be synced from fbsource in an hour
---
 .travis.yml | 87 -----------------------------------------------------
 1 file changed, 87 deletions(-)
 delete mode 100644 .travis.yml

diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 67ac1cc42ecd..000000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,87 +0,0 @@
-language: objective-c
-
-osx_image: xcode7.2
-
-cache:
-    directories:
-        - node_modules
-        - .nvm
-
-install:
-  - brew reinstall nvm
-  - mkdir -p .nvm
-  - export NVM_DIR="$PWD/.nvm"
-  - source $(brew --prefix nvm)/nvm.sh
-  - nvm install 5
-  - rm -Rf "${TMPDIR}/jest_preprocess_cache"
-  - npm config set spin=false
-  - npm install -g flow-bin@`node -p "require('fs').readFileSync('.flowconfig', 'utf8').split('[version]')[1].trim()"`
-  - npm install
-
-script:
-- |
-  if [ "$TEST_TYPE" = objc ]
-  then
-
-    ./scripts/objc-test.sh
-
-  elif [ "$TEST_TYPE" = js ]
-  then
-
-    npm install github@0.2.4
-    cat <(echo eslint; npm run lint --silent -- --format=json; echo flow; flow --json) | GITHUB_TOKEN="af6ef0d15709bc91d""06a6217a5a826a226fb57b7" node bots/code-analysis-bot.js
-    flow check && npm test -- '\/Libraries\/'
-
-  elif [ "$TEST_TYPE" = packager ]
-  then
-
-    npm test -- '\/packager\/'
-
-  elif [ "$TEST_TYPE" = cli ]
-  then
-
-    npm test -- '\/(local|private|react-native)-cli\/'
-
-  elif [ "$TEST_TYPE" = build_website ]
-  then
-
-    cd website
-    $(which npm) install
-    ./setup.sh
-    if [ "$TRAVIS_PULL_REQUEST" = false ] && [ "$TRAVIS_BRANCH" = master ]; then
-      # Automatically publish the website
-      echo "machine github.com login reactjs-bot password $GITHUB_TOKEN" >~/.netrc
-      ./publish.sh
-    else
-      # Make sure the website builds without error
-      node server/generate.js
-    fi
-
-  elif [ "$TEST_TYPE" = e2e ]
-  then
-    ./scripts/e2e-test.sh
-  else
-    echo "Unknown test type: $TEST_TYPE"
-    exit 1
-  fi
-
-env:
-  matrix:
-    - TEST_TYPE=objc
-    - TEST_TYPE=js
-    - TEST_TYPE=packager
-    - TEST_TYPE=cli
-    - TEST_TYPE=build_website
-    - TEST_TYPE=e2e
-  global:
-    # $GITHUB_TOKEN
-    - secure: "HlmG8M2DmBUSBh6KH1yVIe/8gR4iibg4WfcHq1x/xYQxGbvleq7NOo04V6eFHnl9cvZCu+PKH0841WLnGR7c4BBf47GVu/o16nXzggPumHKy++lDzxFPlJ1faMDfjg/5vjbAxRUe7D3y98hQSeGHH4tedc8LvTaFLVu7iiGqvjU="
-    # $APPETIZE_TOKEN
-    - secure: "egsvVSpszTzrNd6bN62DsVAzMiSZI/OHgdizfPryqvqWBf655ztE6XFQSEFNpuIAzSKDDF25ioT8iPfVsbC1iK6HDWHfmqYxML0L+OoU0gi+hV2oKUBFZDZ1fwSnFoWuBdNdMDpLlUxvJp6N1WyfNOB2dxuZUt8eTt48Hi3+Hpc="
-    # $S3_TOKEN
-    - secure: "lY8JZPA0A7zT7L5KF9BBg34XYWIeR/RJiEvE7l7oVr88KnEPtyd//79eHhhVKnUnav7zsk5QJwkcX0MxKTp/dp4G0Am+zOX+sfA8kQrJ+2/+FzFW7AEsW/kHByfaIEIly9DQvUFt4I4oMm8nQZysJLahDgNWglyI3RTuJp//hcY="
-
-branches:
-  only:
-    - master
-    - /^.*-stable$/

From d7f787665c52949600f806b7f8655bb1db7bae6f Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Wed, 10 Feb 2016 07:04:48 -0800
Subject: [PATCH 1109/1411] Added .travis.yml to fbsource to support github PR
 with it

Reviewed By: mkonicek

Differential Revision: D2921590

fb-gh-sync-id: 714813270268e5b83e7068f3fe12ee442cd2eb69
shipit-source-id: 714813270268e5b83e7068f3fe12ee442cd2eb69
---
 .travis.yml | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 88 insertions(+)
 create mode 100644 .travis.yml

diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 000000000000..9b10d721b5b2
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,88 @@
+language: objective-c
+
+osx_image: xcode7.2
+
+cache:
+    directories:
+        - node_modules
+        - .nvm
+
+install:
+  - brew reinstall nvm
+  - mkdir -p .nvm
+  - export NVM_DIR="$PWD/.nvm"
+  - source $(brew --prefix nvm)/nvm.sh
+  - nvm install 5
+  - rm -Rf "${TMPDIR}/jest_preprocess_cache"
+  - npm config set spin=false
+  - npm install -g flow-bin@`node -p "require('fs').readFileSync('.flowconfig', 'utf8').split('[version]')[1].trim()"`
+  - npm install
+
+script:
+- |
+  if [ "$TEST_TYPE" = objc ]
+  then
+
+    ./scripts/objc-test.sh
+
+  elif [ "$TEST_TYPE" = js ]
+  then
+
+    npm install github@0.2.4
+    cat <(echo eslint; npm run lint --silent -- --format=json; echo flow; flow --json) | GITHUB_TOKEN="af6ef0d15709bc91d""06a6217a5a826a226fb57b7" node bots/code-analysis-bot.js
+    flow check && npm test -- '\/Libraries\/'
+
+  elif [ "$TEST_TYPE" = packager ]
+  then
+
+    npm test -- '\/packager\/'
+
+  elif [ "$TEST_TYPE" = cli ]
+  then
+
+    npm test -- '\/(local|private|react-native)-cli\/'
+
+  elif [ "$TEST_TYPE" = build_website ]
+  then
+
+    cd website
+    $(which npm) install
+    ./setup.sh
+    if [ "$TRAVIS_PULL_REQUEST" = false ] && [ "$TRAVIS_BRANCH" = master ]; then
+      # Automatically publish the website
+      echo "machine github.com login reactjs-bot password $GITHUB_TOKEN" >~/.netrc
+      ./publish.sh
+    else
+      # Make sure the website builds without error
+      node server/generate.js
+    fi
+
+  elif [ "$TEST_TYPE" = e2e ]
+  then
+    ./scripts/e2e-test.sh
+  else
+    echo "Unknown test type: $TEST_TYPE"
+    exit 1
+  fi
+
+env:
+  matrix:
+    - TEST_TYPE=objc
+    - TEST_TYPE=js
+    - TEST_TYPE=packager
+    - TEST_TYPE=cli
+    - TEST_TYPE=build_website
+    - TEST_TYPE=e2e
+  global:
+    # $GITHUB_TOKEN
+    - secure: "HlmG8M2DmBUSBh6KH1yVIe/8gR4iibg4WfcHq1x/xYQxGbvleq7NOo04V6eFHnl9cvZCu+PKH0841WLnGR7c4BBf47GVu/o16nXzggPumHKy++lDzxFPlJ1faMDfjg/5vjbAxRUe7D3y98hQSeGHH4tedc8LvTaFLVu7iiGqvjU="
+    # $APPETIZE_TOKEN
+    - secure: "egsvVSpszTzrNd6bN62DsVAzMiSZI/OHgdizfPryqvqWBf655ztE6XFQSEFNpuIAzSKDDF25ioT8iPfVsbC1iK6HDWHfmqYxML0L+OoU0gi+hV2oKUBFZDZ1fwSnFoWuBdNdMDpLlUxvJp6N1WyfNOB2dxuZUt8eTt48Hi3+Hpc="
+    # $S3_TOKEN
+    - secure: "lY8JZPA0A7zT7L5KF9BBg34XYWIeR/RJiEvE7l7oVr88KnEPtyd//79eHhhVKnUnav7zsk5QJwkcX0MxKTp/dp4G0Am+zOX+sfA8kQrJ+2/+FzFW7AEsW/kHByfaIEIly9DQvUFt4I4oMm8nQZysJLahDgNWglyI3RTuJp//hcY="
+
+branches:
+  only:
+    - master
+    - /^.*-stable$/
+    
\ No newline at end of file

From c9a1956c4fd9cfb6bf883c835b501d097181e1a4 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Wed, 10 Feb 2016 07:24:38 -0800
Subject: [PATCH 1110/1411] Fix promises on iOS to no longer wrap values in
 Arrays

Summary:
public
In https://github.com/facebook/react-native/commit/9baff8f437eee49f8ab0e6f433bf86466ca16662#diff-8d9841e5b53fd6c9cf3a7f431827e319R331, I incorrectly assumed that iOS was wrapping promises in an extra Array.  What was really happening is that all the callers were doing this.  I removed the wrapping in the callers and the special case handling MessageQueue.

Now one can pass whatever object one wants to resolve and it will show properly in the resolve call on the js side.  This fixes issue https://github.com/facebook/react-native/issues/5851

Reviewed By: nicklockwood

Differential Revision: D2921565

fb-gh-sync-id: 9f81e2a87f6a48e9197413b843e452db345a7ff9
shipit-source-id: 9f81e2a87f6a48e9197413b843e452db345a7ff9
---
 Libraries/CameraRoll/RCTCameraRollManager.m | 10 +++++-----
 Libraries/LinkingIOS/RCTLinkingManager.m    |  6 +++---
 Libraries/Utilities/MessageQueue.js         |  6 +-----
 React/Modules/RCTClipboard.m                |  2 +-
 React/Modules/RCTSourceCode.m               |  2 +-
 5 files changed, 11 insertions(+), 15 deletions(-)

diff --git a/Libraries/CameraRoll/RCTCameraRollManager.m b/Libraries/CameraRoll/RCTCameraRollManager.m
index fc97c9493b4a..d060224ccc7a 100644
--- a/Libraries/CameraRoll/RCTCameraRollManager.m
+++ b/Libraries/CameraRoll/RCTCameraRollManager.m
@@ -98,7 +98,7 @@ @implementation RCTCameraRollManager
           RCTLogWarn(@"Error saving cropped image: %@", saveError);
           reject(RCTErrorUnableToSave, nil, saveError);
         } else {
-          resolve(@[assetURL.absoluteString]);
+          resolve(assetURL.absoluteString);
         }
       }];
     });
@@ -110,22 +110,22 @@ static void RCTResolvePromise(RCTPromiseResolveBlock resolve,
                               BOOL hasNextPage)
 {
   if (!assets.count) {
-    resolve(@[@{
+    resolve(@{
       @"edges": assets,
       @"page_info": @{
         @"has_next_page": @NO,
       }
-    }]);
+    });
     return;
   }
-  resolve(@[@{
+  resolve(@{
     @"edges": assets,
     @"page_info": @{
       @"start_cursor": assets[0][@"node"][@"image"][@"uri"],
       @"end_cursor": assets[assets.count - 1][@"node"][@"image"][@"uri"],
       @"has_next_page": @(hasNextPage),
     }
-  }]);
+  });
 }
 
 RCT_EXPORT_METHOD(getPhotos:(NSDictionary *)params
diff --git a/Libraries/LinkingIOS/RCTLinkingManager.m b/Libraries/LinkingIOS/RCTLinkingManager.m
index d720631674c9..b8bc364bd8bf 100644
--- a/Libraries/LinkingIOS/RCTLinkingManager.m
+++ b/Libraries/LinkingIOS/RCTLinkingManager.m
@@ -80,7 +80,7 @@ - (void)handleOpenURLNotification:(NSNotification *)notification
   // TODO: we should really report success/failure via the promise here
   // Doesn't really matter what thread we call this on since it exits the app
   [RCTSharedApplication() openURL:URL];
-  resolve(@[@YES]);
+  resolve(@YES);
 }
 
 RCT_EXPORT_METHOD(canOpenURL:(NSURL *)URL
@@ -90,13 +90,13 @@ - (void)handleOpenURLNotification:(NSNotification *)notification
   if (RCTRunningInAppExtension()) {
     // Technically Today widgets can open urls, but supporting that would require
     // a reference to the NSExtensionContext
-    resolve(@[@NO]);
+    resolve(@NO);
     return;
   }
 
   // This can be expensive, so we deliberately don't call on main thread
   BOOL canOpen = [RCTSharedApplication() canOpenURL:URL];
-  resolve(@[@(canOpen)]);
+  resolve(@(canOpen));
 }
 
 @end
diff --git a/Libraries/Utilities/MessageQueue.js b/Libraries/Utilities/MessageQueue.js
index 8e58ee06e3c7..7b31c114914a 100644
--- a/Libraries/Utilities/MessageQueue.js
+++ b/Libraries/Utilities/MessageQueue.js
@@ -324,11 +324,7 @@ class MessageQueue {
             method,
             args,
             (data) => {
-              // iOS always wraps the data in an Array regardless of what the
-              // shape of the data so we strip it out
-              // Android sends the data back properly
-              // TODO: Remove this once iOS has support for Promises natively (t9774697)
-              resolve(Platform.OS == 'ios' ? data[0] : data);
+              resolve(data);
             },
             (errorData) => {
               var error = createErrorFromErrorData(errorData);
diff --git a/React/Modules/RCTClipboard.m b/React/Modules/RCTClipboard.m
index 0a0bf14816f8..cad23d58b4e6 100644
--- a/React/Modules/RCTClipboard.m
+++ b/React/Modules/RCTClipboard.m
@@ -33,7 +33,7 @@ - (dispatch_queue_t)methodQueue
                   rejecter:(__unused RCTPromiseRejectBlock)reject)
 {
   UIPasteboard *clipboard = [UIPasteboard generalPasteboard];
-  resolve(@[RCTNullIfNil(clipboard.string)]);
+  resolve(RCTNullIfNil(clipboard.string));
 }
 
 @end
diff --git a/React/Modules/RCTSourceCode.m b/React/Modules/RCTSourceCode.m
index e538fa5d0c96..f8d96fac68e8 100644
--- a/React/Modules/RCTSourceCode.m
+++ b/React/Modules/RCTSourceCode.m
@@ -32,7 +32,7 @@ - (void)setScriptText:(NSString *)scriptText {}
   if (RCT_DEV && self.scriptData && self.scriptURL) {
     NSString *scriptText = [[NSString alloc] initWithData:self.scriptData encoding:NSUTF8StringEncoding];
 
-    resolve(@[@{@"text": scriptText, @"url": self.scriptURL.absoluteString}]);
+    resolve(@{@"text": scriptText, @"url": self.scriptURL.absoluteString});
   } else {
     reject(RCTErrorUnavailable, nil, RCTErrorWithMessage(@"Source code is not available"));
   }

From e6b6aedd86cc20ef153b10c53025118b9ca8b296 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Wed, 10 Feb 2016 15:50:52 +0000
Subject: [PATCH 1111/1411] new way to update stable website

---
 Releases.md | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/Releases.md b/Releases.md
index 06933c78924e..b41c73c82d08 100644
--- a/Releases.md
+++ b/Releases.md
@@ -34,7 +34,19 @@ Make absolutely sure a basic iOS and Android workflow works on the release branc
 
   - Check git history, the last commit should be "[0.19-rc] Bump version numbers" (with the correct version)
   - `git push origin 0.version_you_are_releasing-stable`
-  
+
+#### Update https://facebook.github.io/react-native
+
+Move `latest` tag when doing a release and pushing to `0.x-stable` branch, CI will build and deploy the
+latest docs to the website.
+
+```
+git tag -d latest
+git push origin :latest
+git tag latest
+git push origin version_you_are_releasing-stable --tags
+```
+
 ## Make sure we have release notes
 
 Post that we're ready to release so voluteers can write release notes:

From bab48182d94a36f1eb98d475315077f0ee8aeba1 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Wed, 10 Feb 2016 08:13:26 -0800
Subject: [PATCH 1112/1411] Add Object.getPropertyNames() and Object.toJSONMap
 APIs

Summary:
Adds APIs to get all the enumerable property names of an object and to get an object as a map of property names to JSON values.

public

Reviewed By: lexs

Differential Revision: D2916238

fb-gh-sync-id: 0d9ee1eb4886d58fba8241537f6a0dad6024bd0e
shipit-source-id: 0d9ee1eb4886d58fba8241537f6a0dad6024bd0e
---
 ReactAndroid/src/main/jni/react/Value.cpp | 34 +++++++++++++++++++++++
 ReactAndroid/src/main/jni/react/Value.h   |  6 ++++
 2 files changed, 40 insertions(+)

diff --git a/ReactAndroid/src/main/jni/react/Value.cpp b/ReactAndroid/src/main/jni/react/Value.cpp
index ac07c486fd5c..6c1c393ded78 100644
--- a/ReactAndroid/src/main/jni/react/Value.cpp
+++ b/ReactAndroid/src/main/jni/react/Value.cpp
@@ -79,6 +79,16 @@ Value Object::getProperty(const String& propName) const {
   return Value(m_context, property);
 }
 
+Value Object::getPropertyAtIndex(unsigned index) const {
+  JSValueRef exn;
+  JSValueRef property = JSObjectGetPropertyAtIndex(m_context, m_obj, index, &exn);
+  if (!property) {
+    std::string exceptionText = Value(m_context, exn).toString().str();
+    throwJSExecutionException("Failed to get property at index %u: %s", index, exceptionText.c_str());
+  }
+  return Value(m_context, property);
+}
+
 Value Object::getProperty(const char *propName) const {
   return getProperty(String(propName));
 }
@@ -96,6 +106,30 @@ void Object::setProperty(const char *propName, const Value& value) const {
   setProperty(String(propName), value);
 }
 
+std::vector<std::string> Object::getPropertyNames() const {
+  std::vector<std::string> names;
+  auto namesRef = JSObjectCopyPropertyNames(m_context, m_obj);
+  size_t count = JSPropertyNameArrayGetCount(namesRef);
+  for (size_t i = 0; i < count; i++) {
+    auto string = String::ref(JSPropertyNameArrayGetNameAtIndex(namesRef, i));
+    names.emplace_back(string.str());
+  }
+  JSPropertyNameArrayRelease(namesRef);
+  return names;
+}
+
+std::unordered_map<std::string, std::string> Object::toJSONMap() const {
+  std::unordered_map<std::string, std::string> map;
+  auto namesRef = JSObjectCopyPropertyNames(m_context, m_obj);
+  size_t count = JSPropertyNameArrayGetCount(namesRef);
+  for (size_t i = 0; i < count; i++) {
+    auto key = String::ref(JSPropertyNameArrayGetNameAtIndex(namesRef, i));
+    map.emplace(key.str(), getProperty(key).toJSONString());
+  }
+  JSPropertyNameArrayRelease(namesRef);
+  return map;
+}
+
 /* static */
 Object Object::create(JSContextRef ctx) {
   JSObjectRef newObj = JSObjectMake(
diff --git a/ReactAndroid/src/main/jni/react/Value.h b/ReactAndroid/src/main/jni/react/Value.h
index 1cee8cc9fd15..8549c7f1bc4d 100644
--- a/ReactAndroid/src/main/jni/react/Value.h
+++ b/ReactAndroid/src/main/jni/react/Value.h
@@ -4,6 +4,9 @@
 
 #include <memory>
 #include <sstream>
+#include <unordered_map>
+#include <vector>
+
 #include <JavaScriptCore/JSObjectRef.h>
 #include <JavaScriptCore/JSRetainPtr.h>
 #include <JavaScriptCore/JSStringRef.h>
@@ -123,8 +126,11 @@ class Object : public noncopyable {
 
   Value getProperty(const String& propName) const;
   Value getProperty(const char *propName) const;
+  Value getPropertyAtIndex(unsigned index) const;
   void setProperty(const String& propName, const Value& value) const;
   void setProperty(const char *propName, const Value& value) const;
+  std::vector<std::string> getPropertyNames() const;
+  std::unordered_map<std::string, std::string> toJSONMap() const;
 
   void makeProtected() {
     if (!m_isProtected && m_obj) {

From e7005f7f5429422b6f2e9c2aa29c9d57bda7b77a Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Wed, 10 Feb 2016 08:36:15 -0800
Subject: [PATCH 1113/1411] Fixed missing rows on UIExplorer <ListView> - Grid
 Layout example

Summary:
public
I was looking into the missing panels at the bottom of the <ListView> - Grid Layout example, and found that it was caused by several problems, some in the example and some in ListView itself.

The first problem seemed to be a bug in the `_getDistanceFromEnd()` method, which calculates whether the ListView needs to load more content based on the distance of the visible content from the bottom of the scrollview. This was previously using the function

    Math.max(scrollProperties.contentLength, scrollProperties.visibleLength) - scrollProperties.visibleLength - scrollProperties.offset

to calculate the amount the user could scroll before they run out of content. This sort-of works in most cases because `scrollProperties.contentLength` is usually longer than `scrollProperties.visibleLength`, so this would generally evaluate to

    scrollProperties.contentLength - scrollProperties.visibleLength - scrollProperties.offset

which meant that it would be positive as long as there was content still to be displayed offscreen, and negative when you reached the end of the content. This logic breaks down if `contentLength` is less than `visibleLength`, however. For example, if you have 300pts of content loaded, and your scrollView is 500pts tall, and your scroll position is zero, this evaluates to

    Math.max(300, 500) - 500 - 0 = 0

In other words, the algorithm is saying that you have zero pts of scroll content remaining before you need to reload. But actually, the bottom 200pts of the screen are empty, so you're really 200pts in debt, and need to load extra rows to fill that space. The correct algorithm is simply to get rid of the `Math.max` and just use

    scrollProperties.contentLength - scrollProperties.visibleLength - scrollProperties.offset

I originally thought that this was the cause of the gap, but it isn't, because ListView has `DEFAULT_SCROLL_RENDER_AHEAD = 1000`, which means that it tries to load at least 1000pts more content than is currently visible, to avoid gaps. This masked the bug, so in practice it wasn't causing an issue.

The next problem I found was that there is an implict assumption in ListView that the first page of content you load is sufficient to cover the screen, or rather, that the first _ second page is sufficient. The constants `DEFAULT_INITIAL_ROWS = 10` and `DEFAULT_PAGE_SIZE = 1`, mean that when the ListView first loads, the following happens:

    1. It loads 10 rows of content.
    2. It checks if `_getDistanceFromEnd() < DEFAULT_SCROLL_RENDER_AHEAD` (1000).
    3. If it is, it loads another `DEFAULT_PAGE_SIZE` rows of content, then stops.

In the case of the ListView Grid Layout example, this meant that it first loaded 10 cells, then loaded another 1, for a total of 11. The problem was that going from 10 to 11 cells isn't sufficient to fill the visible scroll area, and it doesn't change the `contentSize` (since the cells wrap onto the same line), and since ListView doesn't try to load any more until the `contentSize` or `scrollOffset ` changes, it stops loading new rows at that point.

I tried fixing this by calling `_renderMoreRowsIfNeeded()` after `_pageInNewRows()` so that it will continue to fetch new rows until the `_getDistanceFromEnd()` is less than the threshold, rather than stopping after the first page and waiting until the `contentSize` or `scrollOffset` change, but although this solves the problem for the Grid Layout example, it leads to over-fetching in the more common case of a standard row-based ListView.

In the end, I just increased the `pageSize` to 3 for the Grid Layout example, which makes more sense anyway since loading a page that is not a multiple of the number of cells per row confuses the `_renderMoreRowsIfNeeded` algorithm, and leads to gaps at the bottom of the view.

This solved the problem, however there was still a "pop-in" effect, where the additional rows were paged in after the ListView appeared. This was simply a misconfiguration in the example itself: The default of 10 rows was insufficient to fill the screen, so I changed the `initialListSize` prop to `20`.

Reviewed By: javache

Differential Revision: D2911690

fb-gh-sync-id: 8d6bd78843335fb091e7e24f7c2e6a416b0321d3
shipit-source-id: 8d6bd78843335fb091e7e24f7c2e6a416b0321d3
---
 Examples/UIExplorer/ListViewGridLayoutExample.js |  3 +++
 Examples/UIExplorer/ListViewPagingExample.js     |  5 ++---
 Libraries/CustomComponents/ListView/ListView.js  | 14 +++++++-------
 3 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/Examples/UIExplorer/ListViewGridLayoutExample.js b/Examples/UIExplorer/ListViewGridLayoutExample.js
index ac7d56b86112..4d8017335d56 100644
--- a/Examples/UIExplorer/ListViewGridLayoutExample.js
+++ b/Examples/UIExplorer/ListViewGridLayoutExample.js
@@ -67,6 +67,9 @@ var ListViewGridLayoutExample = React.createClass({
       <ListView
         contentContainerStyle={styles.list}
         dataSource={this.state.dataSource}
+        initialListSize={21}
+        pageSize={3} // should be a multiple of the no. of visible cells per row
+        scrollRenderAheadDistance={500}
         renderRow={this._renderRow}
       />
     );
diff --git a/Examples/UIExplorer/ListViewPagingExample.js b/Examples/UIExplorer/ListViewPagingExample.js
index f6cdcae62aa4..a1406c52ff95 100644
--- a/Examples/UIExplorer/ListViewPagingExample.js
+++ b/Examples/UIExplorer/ListViewPagingExample.js
@@ -32,7 +32,6 @@ var {
   UIManager,
 } = NativeModules;
 
-var PAGE_SIZE = 4;
 var THUMB_URLS = [
   require('./Thumbnails/like.png'),
   require('./Thumbnails/dislike.png'),
@@ -182,8 +181,8 @@ var ListViewPagingExample = React.createClass({
         renderSectionHeader={this.renderSectionHeader}
         renderRow={this.renderRow}
         initialListSize={10}
-        pageSize={PAGE_SIZE}
-        scrollRenderAheadDistance={2000}
+        pageSize={4}
+        scrollRenderAheadDistance={500}
       />
     );
   },
diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js
index 1a9bef47b3fb..c10717b5a782 100644
--- a/Libraries/CustomComponents/ListView/ListView.js
+++ b/Libraries/CustomComponents/ListView/ListView.js
@@ -147,11 +147,15 @@ var ListView = React.createClass({
      */
     onEndReached: PropTypes.func,
     /**
-     * Threshold in pixels for onEndReached.
+     * Threshold in pixels (virtual, not physical) for calling onEndReached.
      */
     onEndReachedThreshold: PropTypes.number,
     /**
-     * Number of rows to render per event loop.
+     * Number of rows to render per event loop. Note: if your 'rows' are actually
+     * cells, i.e. they don't span the full width of your view (as in the
+     * ListViewGridLayoutExample), you should set the pageSize to be a multiple
+     * of the number of cells per row, otherwise you're likely to see gaps at
+     * the edge of the ListView as new pages are loaded.
      */
     pageSize: PropTypes.number,
     /**
@@ -512,11 +516,7 @@ var ListView = React.createClass({
   },
 
   _getDistanceFromEnd: function(scrollProperties) {
-    var maxLength = Math.max(
-      scrollProperties.contentLength,
-      scrollProperties.visibleLength
-    );
-    return maxLength - scrollProperties.visibleLength - scrollProperties.offset;
+    return scrollProperties.contentLength - scrollProperties.visibleLength - scrollProperties.offset;
   },
 
   _updateVisibleRows: function(updatedFrames) {

From 197880518b30d6f2b72ff4c86f92ea2982ed8524 Mon Sep 17 00:00:00 2001
From: Michael Anderson <normanganderson@gmail.com>
Date: Wed, 10 Feb 2016 08:37:58 -0800
Subject: [PATCH 1114/1411] Updating the native code to make it match reality.

Summary:
In the native code, you must use RCTLinkingManager instead of LinkingManager and you have to import it as well.
Closes https://github.com/facebook/react-native/pull/5830

Reviewed By: svcscm

Differential Revision: D2921718

Pulled By: androidtrunkagent

fb-gh-sync-id: a95ec358c69e8830b7f0fb2ec60baefc06139758
shipit-source-id: a95ec358c69e8830b7f0fb2ec60baefc06139758
---
 Libraries/Linking/Linking.js | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/Libraries/Linking/Linking.js b/Libraries/Linking/Linking.js
index 97282ab66391..a27e454647b6 100644
--- a/Libraries/Linking/Linking.js
+++ b/Libraries/Linking/Linking.js
@@ -53,10 +53,12 @@ const DEVICE_NOTIF_EVENT = 'openURL';
  * execution you'll need to add the following lines to you `*AppDelegate.m`:
  *
  * ```
+ *#import "RCTLinkingManager.h" 
+ *
  * - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
  *   sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
  * {
- *   return [LinkingManager application:application openURL:url
+ *   return [RCTLinkingManager application:application openURL:url
  *                       sourceApplication:sourceApplication annotation:annotation];
  * }
  *
@@ -64,7 +66,7 @@ const DEVICE_NOTIF_EVENT = 'openURL';
  * - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity
  *  restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
  * {
- *  return [LinkingManager application:application
+ *  return [RCTLinkingManager application:application
  *                   continueUserActivity:userActivity
  *                     restorationHandler:restorationHandler];
  * }

From 97741af8b99ea8e443d41b80c4d9a8fd843a96ab Mon Sep 17 00:00:00 2001
From: wusuopu <admin@longchangjin.cn>
Date: Wed, 10 Feb 2016 08:40:01 -0800
Subject: [PATCH 1115/1411] Fix warnings of StyleInspector

Summary:
Fix issue #5831
Closes https://github.com/facebook/react-native/pull/5832

Reviewed By: svcscm

Differential Revision: D2917760

Pulled By: vjeux

fb-gh-sync-id: 3808d14075b259dd21056a7111205edae1e3eb48
shipit-source-id: 3808d14075b259dd21056a7111205edae1e3eb48
---
 Libraries/Inspector/StyleInspector.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Libraries/Inspector/StyleInspector.js b/Libraries/Inspector/StyleInspector.js
index 96d13ad6a74e..96db90e8a076 100644
--- a/Libraries/Inspector/StyleInspector.js
+++ b/Libraries/Inspector/StyleInspector.js
@@ -25,13 +25,13 @@ class StyleInspector extends React.Component {
     return (
       <View style={styles.container}>
         <View>
-          {names.map(name => <Text style={styles.attr}>{name}:</Text>)}
+          {names.map(name => <Text key={name} style={styles.attr}>{name}:</Text>)}
         </View>
 
         <View>
           {names.map(name => {
             var value = typeof this.props.style[name] === 'object' ? JSON.stringify(this.props.style[name]) : this.props.style[name];
-            return <Text style={styles.value}>{value}</Text>;
+            return <Text key={name} style={styles.value}>{value}</Text>;
           } ) }
         </View>
       </View>

From 189ef95bb609cf60537320dbd523e821fc978b2f Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Wed, 10 Feb 2016 17:13:51 +0000
Subject: [PATCH 1116/1411] [website] Update 404.js

---
 website/src/react-native/404.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/website/src/react-native/404.js b/website/src/react-native/404.js
index 4b1e116ae418..fb6bc8d0c542 100755
--- a/website/src/react-native/404.js
+++ b/website/src/react-native/404.js
@@ -22,4 +22,4 @@ var fourOhFour = React.createClass({
   }
 });
 
-module.exports = fourOhFour;
+module.exports = fourOhFour;
\ No newline at end of file

From ab09ff53d4ceaf1d2ceb11ab99814bca5cfbeceb Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Wed, 10 Feb 2016 17:20:53 +0000
Subject: [PATCH 1117/1411] [website] Make 404.js line ending match internal

---
 website/src/react-native/404.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/website/src/react-native/404.js b/website/src/react-native/404.js
index fb6bc8d0c542..4b1e116ae418 100755
--- a/website/src/react-native/404.js
+++ b/website/src/react-native/404.js
@@ -22,4 +22,4 @@ var fourOhFour = React.createClass({
   }
 });
 
-module.exports = fourOhFour;
\ No newline at end of file
+module.exports = fourOhFour;

From d96a4ba94de5171a53150ee55e277abdd9c5b968 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Wed, 10 Feb 2016 09:25:30 -0800
Subject: [PATCH 1118/1411] Minor fixes to clipboard and Linking to remove
 TODOs

Reviewed By: nicklockwood

Differential Revision: D2921782

fb-gh-sync-id: e387b720421ed6ed03a50633d71e08791f87c761
shipit-source-id: e387b720421ed6ed03a50633d71e08791f87c761
---
 Libraries/LinkingIOS/RCTLinkingManager.m | 6 ++----
 React/Modules/RCTClipboard.m             | 4 ++--
 2 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/Libraries/LinkingIOS/RCTLinkingManager.m b/Libraries/LinkingIOS/RCTLinkingManager.m
index b8bc364bd8bf..1a30422175b1 100644
--- a/Libraries/LinkingIOS/RCTLinkingManager.m
+++ b/Libraries/LinkingIOS/RCTLinkingManager.m
@@ -77,10 +77,8 @@ - (void)handleOpenURLNotification:(NSNotification *)notification
                   resolve:(RCTPromiseResolveBlock)resolve
                   reject:(__unused RCTPromiseRejectBlock)reject)
 {
-  // TODO: we should really report success/failure via the promise here
-  // Doesn't really matter what thread we call this on since it exits the app
-  [RCTSharedApplication() openURL:URL];
-  resolve(@YES);
+  BOOL opened = [RCTSharedApplication() openURL:URL];
+  resolve(@(opened));
 }
 
 RCT_EXPORT_METHOD(canOpenURL:(NSURL *)URL
diff --git a/React/Modules/RCTClipboard.m b/React/Modules/RCTClipboard.m
index cad23d58b4e6..8d059c4a3745 100644
--- a/React/Modules/RCTClipboard.m
+++ b/React/Modules/RCTClipboard.m
@@ -26,14 +26,14 @@ - (dispatch_queue_t)methodQueue
 RCT_EXPORT_METHOD(setString:(NSString *)content)
 {
   UIPasteboard *clipboard = [UIPasteboard generalPasteboard];
-  clipboard.string = content;
+  clipboard.string = (content ? : @"");
 }
 
 RCT_EXPORT_METHOD(getString:(RCTPromiseResolveBlock)resolve
                   rejecter:(__unused RCTPromiseRejectBlock)reject)
 {
   UIPasteboard *clipboard = [UIPasteboard generalPasteboard];
-  resolve(RCTNullIfNil(clipboard.string));
+  resolve((clipboard.string ? : @""));
 }
 
 @end

From f2a60a202fd3dd737a968820c7941686ed1d9ddb Mon Sep 17 00:00:00 2001
From: Adam Miskiewicz <adam@sk3vy.com>
Date: Wed, 10 Feb 2016 10:40:42 -0800
Subject: [PATCH 1119/1411] Add 'file://' prefix to sourceURL when loading a
 script from a file.

Reviewed By: svcscm

Differential Revision: D2922108

Pulled By: androidtrunkagent

fb-gh-sync-id: d9c98af31e844e3fed2f57a3a4250a6ef5e735a8
shipit-source-id: d9c98af31e844e3fed2f57a3a4250a6ef5e735a8
---
 .../main/java/com/facebook/react/bridge/JSBundleLoader.java   | 2 +-
 ReactAndroid/src/main/jni/react/jni/OnLoad.cpp                | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java
index db9fb05df8eb..799863b087c4 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java
@@ -31,7 +31,7 @@ public void loadScript(ReactBridge bridge) {
         if (fileName.startsWith("assets://")) {
           bridge.loadScriptFromAssets(context.getAssets(), fileName.replaceFirst("assets://", ""));
         } else {
-          bridge.loadScriptFromFile(fileName, fileName);
+          bridge.loadScriptFromFile(fileName, "file://" + fileName);
         }
       }
 
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 128ef8338954..783b45dd91d6 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -700,9 +700,9 @@ static void loadScriptFromAssets(JNIEnv* env, jobject obj, jobject assetManager,
 
   env->CallStaticVoidMethod(markerClass, gLogMarkerMethod, env->NewStringUTF("loadScriptFromAssets_read"));
   if (JniJSModulesUnbundle::isUnbundle(manager, assetNameStr)) {
-    loadApplicationUnbundle(bridge, manager, script, assetNameStr);
+    loadApplicationUnbundle(bridge, manager, script, "file://" + assetNameStr);
   } else {
-    executeApplicationScript(bridge, script, assetNameStr);
+    executeApplicationScript(bridge, script, "file://" + assetNameStr);
   }
   if (env->ExceptionCheck()) {
     return;

From b051d07b819be7ff01ac54106ca7f0f0289d1bd0 Mon Sep 17 00:00:00 2001
From: James Ide <ide+github@jameside.com>
Date: Wed, 10 Feb 2016 12:46:26 -0800
Subject: [PATCH 1120/1411] Update CONTRIBUTING.md

---
 CONTRIBUTING.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3171208c89d3..b5d0c744d117 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -17,7 +17,7 @@ The core team will be monitoring for pull requests. When we get one, we'll run s
 *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!
+2. **Describe your test plan in your commit.** If you've added code that should be tested, add tests!
 3. If you've changed APIs, update the documentation.
 4. Add the copyright notice to the top of any new files you've added.
 5. Ensure tests pass on Travis and Circle CI.

From 915e5826efba758c42aefeeab69499ddcdd9cf50 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Wed, 10 Feb 2016 12:48:41 -0800
Subject: [PATCH 1121/1411] Restricted image decoding to 2 simultaneous threads

Reviewed By: zjj010104

Differential Revision: D2922292

fb-gh-sync-id: eddd47d02fc721acc1da69e7483c6570997320b5
shipit-source-id: eddd47d02fc721acc1da69e7483c6570997320b5
---
 Libraries/Image/RCTImageLoader.m | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/Libraries/Image/RCTImageLoader.m b/Libraries/Image/RCTImageLoader.m
index 0d7b06f5c1d5..22bffa4a3d26 100644
--- a/Libraries/Image/RCTImageLoader.m
+++ b/Libraries/Image/RCTImageLoader.m
@@ -38,6 +38,7 @@ @implementation RCTImageLoader
 {
   NSArray<id<RCTImageURLLoader>> *_loaders;
   NSArray<id<RCTImageDataDecoder>> *_decoders;
+  NSOperationQueue *_imageDecodeQueue;
   dispatch_queue_t _URLCacheQueue;
   NSURLCache *_URLCache;
 }
@@ -474,7 +475,13 @@ - (RCTImageLoaderCancellationBlock)decodeImageDataWithoutClipping:(NSData *)data
                        completionHandler:completionHandler];
   } else {
 
-    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+    // Serialize decoding to prevent excessive memory usage
+    if (!_imageDecodeQueue) {
+      _imageDecodeQueue = [NSOperationQueue new];
+      _imageDecodeQueue.name = @"com.facebook.react.ImageDecoderQueue";
+      _imageDecodeQueue.maxConcurrentOperationCount = 2;
+    }
+    [_imageDecodeQueue addOperationWithBlock:^{
       if (cancelled) {
         return;
       }
@@ -501,7 +508,7 @@ - (RCTImageLoaderCancellationBlock)decodeImageDataWithoutClipping:(NSData *)data
         NSError *finalError = RCTErrorWithMessage(errorMessage);
         completionHandler(finalError, nil);
       }
-    });
+    }];
 
     return ^{
       OSAtomicOr32Barrier(1, &cancelled);

From eab211b1ecc68c26d227b07800b1c0b328c2fcec Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Wed, 10 Feb 2016 12:50:16 -0800
Subject: [PATCH 1122/1411] Fix comment in open source MainActivity

Reviewed By: mkonicek

Differential Revision:D2923275
Ninja: ninja

fb-gh-sync-id: 1a6700853a1b292c3ae3dd17f2b3e8ce4a2755cf
shipit-source-id: 1a6700853a1b292c3ae3dd17f2b3e8ce4a2755cf
---
 .../generator-android/templates/package/MainActivity.java   | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/local-cli/generator-android/templates/package/MainActivity.java b/local-cli/generator-android/templates/package/MainActivity.java
index 552a4d2a59de..283dffc92e17 100644
--- a/local-cli/generator-android/templates/package/MainActivity.java
+++ b/local-cli/generator-android/templates/package/MainActivity.java
@@ -28,9 +28,9 @@ protected boolean getUseDeveloperSupport() {
     }
 
     /**
-    * A list of packages used by the app. If the app uses additional views
-    * or modules besides the default ones, add more packages here.
-    */
+     * A list of packages used by the app. If the app uses additional views
+     * or modules besides the default ones, add more packages here.
+     */
     @Override
     protected List<ReactPackage> getPackages() {
         return Arrays.<ReactPackage>asList(

From bf21002f2a7f4541091e04758cd32c97da53c893 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Wed, 10 Feb 2016 13:51:33 -0800
Subject: [PATCH 1123/1411] =?UTF-8?q?Circle=20CI=20stopped=20working=20wit?=
 =?UTF-8?q?h=20Gradle=20properly=20https://circleci.com/g=E2=80=A6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Summary:
…h/facebook/react-native/2393, this is a fix
Closes https://github.com/facebook/react-native/pull/5857

Reviewed By: svcscm

Differential Revision: D2923274

Pulled By: androidtrunkagent

fb-gh-sync-id: 0f76958fde4639eca0b3f59b85a1443adf8c48d1
shipit-source-id: 0f76958fde4639eca0b3f59b85a1443adf8c48d1
---
 circle.yml | 34 ++++++++++++++++++----------------
 1 file changed, 18 insertions(+), 16 deletions(-)

diff --git a/circle.yml b/circle.yml
index b0ea6e9902b3..7ea22ee0edad 100644
--- a/circle.yml
+++ b/circle.yml
@@ -13,23 +13,25 @@ machine:
 
 dependencies:
   pre:
-  # BUCK
-  - if [[ ! -e buck ]]; then git clone https://github.com/facebook/buck.git; fi
-  - cd buck && ant
-  - buck/bin/buck --version
-  - buck/bin/buck fetch ReactAndroid/src/test/java/com/facebook/react/modules
-  - buck/bin/buck fetch ReactAndroid/src/main/java/com/facebook/react		 
-  - buck/bin/buck fetch ReactAndroid/src/main/java/com/facebook/react/shell
-  - buck/bin/buck fetch ReactAndroid/src/test/...
-  - buck/bin/buck fetch ReactAndroid/src/androidTest/...
-  # using npm@3 because of problems with shrink-wrapped optional deps installs on linux
-  - npm install -g npm@3.2
-  - source scripts/circle-ci-android-setup.sh && getAndroidSDK
-  - ./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog
+    # BUCK
+    - if [[ ! -e buck ]]; then git clone https://github.com/facebook/buck.git; fi
+    - cd buck && ant
+    - buck/bin/buck --version
+    - buck/bin/buck fetch ReactAndroid/src/test/java/com/facebook/react/modules
+    - buck/bin/buck fetch ReactAndroid/src/main/java/com/facebook/react
+    - buck/bin/buck fetch ReactAndroid/src/main/java/com/facebook/react/shell
+    - buck/bin/buck fetch ReactAndroid/src/test/...
+    - buck/bin/buck fetch ReactAndroid/src/androidTest/...
+    # using npm@3 because of problems with shrink-wrapped optional deps installs on linux
+    - npm install -g npm@3.2
+    - source scripts/circle-ci-android-setup.sh && getAndroidSDK
+    - ./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog
   cache_directories:
-  - "ReactAndroid/build/downloads"
-  - "buck"
-  - "buck-out/bin"
+    - "ReactAndroid/build/downloads"
+    - "buck"
+    - "buck-out/bin"
+  override:
+    - npm install
 test:
   pre:
     # starting emulator in advance because it takes very long to boot

From 98e5e2b4275871b86c1e2c30a3400a331d6b422f Mon Sep 17 00:00:00 2001
From: Adam Miskiewicz <adam@sk3vy.com>
Date: Thu, 11 Feb 2016 02:20:59 -0800
Subject: [PATCH 1124/1411] Remove knowledge of fbjs from the packager

Summary:
As spicyj mentioned in commit 6a838a4, the ideal state of affairs when it comes to consuming `react` and `fbjs` from NPM is for the packager not to have knowledge of either package. This PR addresses the `fbjs` part of that, and relies on https://github.com/facebook/fbjs/pull/95. **DO NOT MERGE** until #95 (or a variation) is in `fbjs` and is released to npm.

This PR does several things:

1. Adds stub modules within RN that expose `fbjs` modules to be required using Haste. After discussing a few ideas with spicyj, this seemed like a good option to keep internal FB devs happy (and not make them change the way they write JS), but allow for removing packager complexity and fit in better with the NPM ecosystem. Note -- it skips stubbing `fetch`, `ExecutionEnvironment`, and `ErrorUtils`, due to the fact that these need to have Native specific implementations, and there's no reason for those implementations to exist in `fbjs`.
2. Removes the modules that were previously being used in lieu of their `fbjs` eq
Closes https://github.com/facebook/react-native/pull/5084

Reviewed By: bestander

Differential Revision: D2803288

Pulled By: davidaurelio

fb-gh-sync-id: fd257958ee2f8696eebe9048c1e7628c168bf4a2
shipit-source-id: fd257958ee2f8696eebe9048c1e7628c168bf4a2
---
 .flowconfig                                   |   4 -
 .../__tests__/InteractionManager-test.js      |   1 +
 Libraries/Promise.js                          |  36 +-
 Libraries/vendor/core/Map.js                  | 626 ------------------
 Libraries/vendor/core/isEmpty.js              |  34 -
 Libraries/vendor/crypto/crc32.js              |  92 ---
 Libraries/vendor/fbjs/CSSCore.js              |  14 +
 Libraries/vendor/fbjs/Deferred.js             |  14 +
 Libraries/vendor/fbjs/EventListener.js        |  14 +
 Libraries/vendor/fbjs/Map.js                  |  14 +
 Libraries/vendor/fbjs/PromiseMap.js           |  14 +
 Libraries/vendor/fbjs/TouchEventUtils.js      |  14 +
 Libraries/vendor/fbjs/URI.js                  |  14 +
 Libraries/vendor/fbjs/UserAgent.js            |  14 +
 Libraries/vendor/fbjs/UserAgentData.js        |  14 +
 Libraries/vendor/fbjs/VersionRange.js         |  14 +
 Libraries/vendor/fbjs/areEqual.js             |  14 +
 Libraries/vendor/fbjs/base62.js               |  14 +
 Libraries/vendor/fbjs/camelize.js             |  14 +
 Libraries/vendor/fbjs/camelizeStyleName.js    |  14 +
 Libraries/vendor/fbjs/containsNode.js         |  14 +
 Libraries/vendor/fbjs/crc32.js                |  14 +
 Libraries/vendor/fbjs/createArrayFromMixed.js |  14 +
 .../vendor/fbjs/createNodesFromMarkup.js      |  14 +
 Libraries/vendor/fbjs/emptyFunction.js        |  14 +
 Libraries/vendor/fbjs/emptyObject.js          |  14 +
 Libraries/vendor/fbjs/everyObject.js          |  14 +
 Libraries/vendor/fbjs/fetchWithRetries.js     |  14 +
 Libraries/vendor/fbjs/filterObject.js         |  14 +
 Libraries/vendor/fbjs/flattenArray.js         |  14 +
 Libraries/vendor/fbjs/focusNode.js            |  14 +
 Libraries/vendor/fbjs/forEachObject.js        |  14 +
 Libraries/vendor/fbjs/getActiveElement.js     |  14 +
 Libraries/vendor/fbjs/getMarkupWrap.js        |  14 +
 .../vendor/fbjs/getUnboundedScrollPosition.js |  14 +
 Libraries/vendor/fbjs/hyphenate.js            |  14 +
 Libraries/vendor/fbjs/hyphenateStyleName.js   |  14 +
 Libraries/vendor/fbjs/invariant.js            |  14 +
 Libraries/vendor/fbjs/isEmpty.js              |  14 +
 Libraries/vendor/fbjs/isNode.js               |  14 +
 Libraries/vendor/fbjs/isTextNode.js           |  14 +
 Libraries/vendor/fbjs/joinClasses.js          |  14 +
 Libraries/vendor/fbjs/keyMirror.js            |  14 +
 Libraries/vendor/fbjs/keyOf.js                |  14 +
 Libraries/vendor/fbjs/mapObject.js            |  14 +
 Libraries/vendor/fbjs/memoizeStringOnly.js    |  14 +
 Libraries/vendor/fbjs/monitorCodeUse.js       |  14 +
 .../fbjs/nativeRequestAnimationFrame.js       |  14 +
 Libraries/vendor/fbjs/nullthrows.js           |  14 +
 Libraries/vendor/fbjs/performance.js          |  14 +
 Libraries/vendor/fbjs/performanceNow.js       |  14 +
 Libraries/vendor/fbjs/removeFromArray.js      |  14 +
 .../vendor/fbjs/requestAnimationFrame.js      |  14 +
 Libraries/vendor/fbjs/resolveImmediate.js     |  14 +
 Libraries/vendor/fbjs/shallowEqual.js         |  14 +
 Libraries/vendor/fbjs/someObject.js           |  14 +
 Libraries/vendor/fbjs/sprintf.js              |  14 +
 Libraries/vendor/fbjs/warning.js              |  14 +
 .../vendor/fbjs/xhrSimpleDataSerializer.js    |  14 +
 npm-shrinkwrap.json                           | 169 ++---
 package.json                                  |   5 +-
 packager/blacklist.js                         |  30 -
 packager/react-packager/src/Resolver/index.js |   1 -
 63 files changed, 848 insertions(+), 892 deletions(-)
 delete mode 100644 Libraries/vendor/core/Map.js
 delete mode 100644 Libraries/vendor/core/isEmpty.js
 delete mode 100644 Libraries/vendor/crypto/crc32.js
 create mode 100644 Libraries/vendor/fbjs/CSSCore.js
 create mode 100644 Libraries/vendor/fbjs/Deferred.js
 create mode 100644 Libraries/vendor/fbjs/EventListener.js
 create mode 100644 Libraries/vendor/fbjs/Map.js
 create mode 100644 Libraries/vendor/fbjs/PromiseMap.js
 create mode 100644 Libraries/vendor/fbjs/TouchEventUtils.js
 create mode 100644 Libraries/vendor/fbjs/URI.js
 create mode 100644 Libraries/vendor/fbjs/UserAgent.js
 create mode 100644 Libraries/vendor/fbjs/UserAgentData.js
 create mode 100644 Libraries/vendor/fbjs/VersionRange.js
 create mode 100644 Libraries/vendor/fbjs/areEqual.js
 create mode 100644 Libraries/vendor/fbjs/base62.js
 create mode 100644 Libraries/vendor/fbjs/camelize.js
 create mode 100644 Libraries/vendor/fbjs/camelizeStyleName.js
 create mode 100644 Libraries/vendor/fbjs/containsNode.js
 create mode 100644 Libraries/vendor/fbjs/crc32.js
 create mode 100644 Libraries/vendor/fbjs/createArrayFromMixed.js
 create mode 100644 Libraries/vendor/fbjs/createNodesFromMarkup.js
 create mode 100644 Libraries/vendor/fbjs/emptyFunction.js
 create mode 100644 Libraries/vendor/fbjs/emptyObject.js
 create mode 100644 Libraries/vendor/fbjs/everyObject.js
 create mode 100644 Libraries/vendor/fbjs/fetchWithRetries.js
 create mode 100644 Libraries/vendor/fbjs/filterObject.js
 create mode 100644 Libraries/vendor/fbjs/flattenArray.js
 create mode 100644 Libraries/vendor/fbjs/focusNode.js
 create mode 100644 Libraries/vendor/fbjs/forEachObject.js
 create mode 100644 Libraries/vendor/fbjs/getActiveElement.js
 create mode 100644 Libraries/vendor/fbjs/getMarkupWrap.js
 create mode 100644 Libraries/vendor/fbjs/getUnboundedScrollPosition.js
 create mode 100644 Libraries/vendor/fbjs/hyphenate.js
 create mode 100644 Libraries/vendor/fbjs/hyphenateStyleName.js
 create mode 100644 Libraries/vendor/fbjs/invariant.js
 create mode 100644 Libraries/vendor/fbjs/isEmpty.js
 create mode 100644 Libraries/vendor/fbjs/isNode.js
 create mode 100644 Libraries/vendor/fbjs/isTextNode.js
 create mode 100644 Libraries/vendor/fbjs/joinClasses.js
 create mode 100644 Libraries/vendor/fbjs/keyMirror.js
 create mode 100644 Libraries/vendor/fbjs/keyOf.js
 create mode 100644 Libraries/vendor/fbjs/mapObject.js
 create mode 100644 Libraries/vendor/fbjs/memoizeStringOnly.js
 create mode 100644 Libraries/vendor/fbjs/monitorCodeUse.js
 create mode 100644 Libraries/vendor/fbjs/nativeRequestAnimationFrame.js
 create mode 100644 Libraries/vendor/fbjs/nullthrows.js
 create mode 100644 Libraries/vendor/fbjs/performance.js
 create mode 100644 Libraries/vendor/fbjs/performanceNow.js
 create mode 100644 Libraries/vendor/fbjs/removeFromArray.js
 create mode 100644 Libraries/vendor/fbjs/requestAnimationFrame.js
 create mode 100644 Libraries/vendor/fbjs/resolveImmediate.js
 create mode 100644 Libraries/vendor/fbjs/shallowEqual.js
 create mode 100644 Libraries/vendor/fbjs/someObject.js
 create mode 100644 Libraries/vendor/fbjs/sprintf.js
 create mode 100644 Libraries/vendor/fbjs/warning.js
 create mode 100644 Libraries/vendor/fbjs/xhrSimpleDataSerializer.js

diff --git a/.flowconfig b/.flowconfig
index 78c0582045e1..026deca0e9c9 100644
--- a/.flowconfig
+++ b/.flowconfig
@@ -14,12 +14,8 @@
 
 # Ignore react and fbjs where there are overlaps, but don't ignore
 # anything that react-native relies on
-.*/node_modules/fbjs/lib/Map.js
-.*/node_modules/fbjs/lib/Promise.js
 .*/node_modules/fbjs/lib/fetch.js
 .*/node_modules/fbjs/lib/ExecutionEnvironment.js
-.*/node_modules/fbjs/lib/isEmpty.js
-.*/node_modules/fbjs/lib/crc32.js
 .*/node_modules/fbjs/lib/ErrorUtils.js
 
 # Flow has a built-in definition for the 'react' module which we prefer to use
diff --git a/Libraries/Interaction/__tests__/InteractionManager-test.js b/Libraries/Interaction/__tests__/InteractionManager-test.js
index 736fc93c585f..032acf255546 100644
--- a/Libraries/Interaction/__tests__/InteractionManager-test.js
+++ b/Libraries/Interaction/__tests__/InteractionManager-test.js
@@ -6,6 +6,7 @@
 
 jest
   .autoMockOff()
+  .mock('ErrorUtils')
   .mock('BatchedBridge');
 
 function expectToBeCalledOnce(fn) {
diff --git a/Libraries/Promise.js b/Libraries/Promise.js
index 004741948e4d..6484dd176807 100644
--- a/Libraries/Promise.js
+++ b/Libraries/Promise.js
@@ -1,30 +1,18 @@
 /**
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
  *
- * Copyright 2013-2014 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.
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule Promise
- *
- * This module wraps and augments the minimally ES6-compliant Promise
- * implementation provided by the promise npm package.
+ * @flow
  */
-
 'use strict';
 
-global.setImmediate = require('setImmediate');
-var Promise = require('promise/setimmediate/es6-extensions');
-require('promise/setimmediate/done');
+const Promise = require('fbjs/lib/Promise'); // this will require Promise.native.js
+
 if (__DEV__) {
   require('promise/setimmediate/rejection-tracking').enable({
     allRejections: true,
@@ -46,12 +34,4 @@ if (__DEV__) {
   });
 }
 
-/**
- * Handle either fulfillment or rejection with the same callback.
- */
-Promise.prototype.finally = function(onSettled) {
-  return this.then(onSettled, onSettled);
-};
-
-
 module.exports = Promise;
diff --git a/Libraries/vendor/core/Map.js b/Libraries/vendor/core/Map.js
deleted file mode 100644
index 114add77b308..000000000000
--- a/Libraries/vendor/core/Map.js
+++ /dev/null
@@ -1,626 +0,0 @@
-/**
- * @generated SignedSource<<375749f44ce7c0f681fc1297943eaf74>>
- *
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !! This file is a check-in of a static_upstream project!      !!
- * !!                                                            !!
- * !! You should not modify this file directly. Instead:         !!
- * !! 1) Use `fjs use-upstream` to temporarily replace this with !!
- * !!    the latest version from upstream.                       !!
- * !! 2) Make your changes, test them, etc.                      !!
- * !! 3) Use `fjs push-upstream` to copy your changes back to    !!
- * !!    static_upstream.                                        !!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- *
- * Copyright 2013-2014 Facebook, Inc.
- * @providesModule Map
- * @preventMunge
- * @typechecks
- */
-
-var guid = require('guid');
-var isNode = require('isNode');
-var toIterator = require('toIterator');
-var _shouldPolyfillES6Collection = require('_shouldPolyfillES6Collection');
-
-module.exports = (function(global, undefined) {
-  // Since our implementation is spec-compliant for the most part we can safely
-  // delegate to a built-in version if exists and is implemented correctly.
-  // Firefox had gotten a few implementation details wrong across different
-  // versions so we guard against that.
-  if (!_shouldPolyfillES6Collection('Map')) {
-    return global.Map;
-  }
-
-  /**
-   * == ES6 Map Collection ==
-   *
-   * This module is meant to implement a Map collection as described in chapter
-   * 23.1 of the ES6 specification.
-   *
-   * Map objects are collections of key/value pairs where both the keys and
-   * values may be arbitrary ECMAScript language values. A distinct key value
-   * may only occur in one key/value pair within the Map's collection.
-   *
-   * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-map-objects
-   *
-   * There only two -- rather small -- diviations from the spec:
-   *
-   * 1. The use of frozen objects as keys.
-   *    We decided not to allow and simply throw an error. The reason being is
-   *    we store a "hash" on the object for fast access to it's place in the
-   *    internal map entries.
-   *    If this turns out to be a popular use case it's possible to implement by
-   *    overiding `Object.freeze` to store a "hash" property on the object
-   *    for later use with the map.
-   *
-   * 2. The `size` property on a map object is a regular property and not a
-   *    computed property on the prototype as described by the spec.
-   *    The reason being is that we simply want to support ES3 environments
-   *    which doesn't implement computed properties.
-   *
-   * == Usage ==
-   *
-   * var map = new Map(iterable);
-   *
-   * map.set(key, value);
-   * map.get(key); // value
-   * map.has(key); // true
-   * map.delete(key); // true
-   *
-   * var iterator = map.keys();
-   * iterator.next(); // {value: key, done: false}
-   *
-   * var iterator = map.values();
-   * iterator.next(); // {value: value, done: false}
-   *
-   * var iterator = map.entries();
-   * iterator.next(); // {value: [key, value], done: false}
-   *
-   * map.forEach(function(value, key){ this === thisArg }, thisArg);
-   *
-   * map.clear(); // resets map.
-   */
-
-  /**
-   * Constants
-   */
-
-  // Kinds of map iterations 23.1.5.3
-  var KIND_KEY = 'key';
-  var KIND_VALUE = 'value';
-  var KIND_KEY_VALUE = 'key+value';
-
-  // In older browsers we can't create a null-prototype object so we have to
-  // defend against key collisions with built-in methods.
-  var KEY_PREFIX = '$map_';
-
-  // This property will be used as the internal size variable to disallow
-  // writing and to issue warnings for writings in development.
-  var SECRET_SIZE_PROP;
-  if (__DEV__) {
-    SECRET_SIZE_PROP = '$size' + guid();
-  }
-
-  // In oldIE we use the DOM Node `uniqueID` property to get create the hash.
-  var OLD_IE_HASH_PREFIX = 'IE_HASH_';
-
-  class Map {
-
-    /**
-     * 23.1.1.1
-     * Takes an `iterable` which is basically any object that implements a
-     * Symbol.iterator (@@iterator) method. The iterable is expected to be a
-     * collection of pairs. Each pair is a key/value pair that will be used
-     * to instantiate the map.
-     *
-     * @param {*} iterable
-     */
-    constructor(iterable) {
-      if (!isObject(this)) {
-        throw new TypeError('Wrong map object type.');
-      }
-
-      initMap(this);
-
-      if (iterable != null) {
-        var it = toIterator(iterable);
-        var next;
-        while (!(next = it.next()).done) {
-          if (!isObject(next.value)) {
-            throw new TypeError('Expected iterable items to be pair objects.');
-          }
-          this.set(next.value[0], next.value[1]);
-        }
-      }
-    }
-
-    /**
-     * 23.1.3.1
-     * Clears the map from all keys and values.
-     */
-    clear() {
-      initMap(this);
-    }
-
-    /**
-     * 23.1.3.7
-     * Check if a key exists in the collection.
-     *
-     * @param {*} key
-     * @return {boolean}
-     */
-    has(key) {
-      var index = getIndex(this, key);
-      return !!(index != null && this._mapData[index]);
-    }
-
-    /**
-     * 23.1.3.9
-     * Adds a key/value pair to the collection.
-     *
-     * @param {*} key
-     * @param {*} value
-     * @return {map}
-     */
-    set(key, value) {
-      var index = getIndex(this, key);
-
-      if (index != null && this._mapData[index]) {
-        this._mapData[index][1] = value;
-      } else {
-        index = this._mapData.push([
-          key,
-          value
-        ]) - 1;
-        setIndex(this, key, index);
-        if (__DEV__) {
-          this[SECRET_SIZE_PROP] += 1;
-        } else {
-          this.size += 1;
-        }
-      }
-
-      return this;
-    }
-
-    /**
-     * 23.1.3.6
-     * Gets a value associated with a key in the collection.
-     *
-     * @param {*} key
-     * @return {*}
-     */
-    get(key) {
-      var index = getIndex(this, key);
-      if (index == null) {
-        return undefined;
-      } else {
-        return this._mapData[index][1];
-      }
-    }
-
-
-    /**
-     * 23.1.3.3
-     * Delete a key/value from the collection.
-     *
-     * @param {*} key
-     * @return {boolean} Whether the key was found and deleted.
-     */
-    delete(key) {
-      var index = getIndex(this, key);
-      if (index != null && this._mapData[index]) {
-        setIndex(this, key, undefined);
-        this._mapData[index] = undefined;
-        if (__DEV__) {
-          this[SECRET_SIZE_PROP] -= 1;
-        } else {
-          this.size -= 1;
-        }
-        return true;
-      } else {
-        return false;
-      }
-    }
-
-    /**
-     * 23.1.3.4
-     * Returns an iterator over the key/value pairs (in the form of an Array) in
-     * the collection.
-     *
-     * @return {MapIterator}
-     */
-    entries() {
-      return new MapIterator(this, KIND_KEY_VALUE);
-    }
-
-    /**
-     * 23.1.3.8
-     * Returns an iterator over the keys in the collection.
-     *
-     * @return {MapIterator}
-     */
-    keys() {
-      return new MapIterator(this, KIND_KEY);
-    }
-
-    /**
-     * 23.1.3.11
-     * Returns an iterator over the values pairs in the collection.
-     *
-     * @return {MapIterator}
-     */
-    values() {
-      return new MapIterator(this, KIND_VALUE);
-    }
-
-    /**
-     * 23.1.3.5
-     * Iterates over the key/value pairs in the collection calling `callback`
-     * with [value, key, map]. An optional `thisArg` can be passed to set the
-     * context when `callback` is called.
-     *
-     * @param {function} callback
-     * @param {?object} thisArg
-     */
-    forEach(callback, thisArg) {
-      if (typeof callback !== 'function') {
-        throw new TypeError('Callback must be callable.');
-      }
-
-      var boundCallback = callback.bind(thisArg || undefined);
-      var mapData = this._mapData;
-
-      // Note that `mapData.length` should be computed on each iteration to
-      // support iterating over new items in the map that were added after the
-      // start of the iteration.
-      for (var i = 0; i < mapData.length; i++) {
-        var entry = mapData[i];
-        if (entry != null) {
-          boundCallback(entry[1], entry[0], this);
-        }
-      }
-    }
-  }
-
-  // 23.1.3.12
-  Map.prototype[toIterator.ITERATOR_SYMBOL] = Map.prototype.entries;
-
-  class MapIterator {
-
-    /**
-     * 23.1.5.1
-     * Create a `MapIterator` for a given `map`. While this class is private it
-     * will create objects that will be passed around publicily.
-     *
-     * @param {map} map
-     * @param {string} kind
-     */
-    constructor(map, kind) {
-      if (!(isObject(map) && map['_mapData'])) {
-        throw new TypeError('Object is not a map.');
-      }
-
-      if ([KIND_KEY, KIND_KEY_VALUE, KIND_VALUE].indexOf(kind) === -1) {
-        throw new Error('Invalid iteration kind.');
-      }
-
-      this._map = map;
-      this._nextIndex = 0;
-      this._kind = kind;
-    }
-
-    /**
-     * 23.1.5.2.1
-     * Get the next iteration.
-     *
-     * @return {object}
-     */
-    next() {
-      if (!this instanceof Map) {
-        throw new TypeError('Expected to be called on a MapIterator.');
-      }
-
-      var map = this._map;
-      var index = this._nextIndex;
-      var kind = this._kind;
-
-      if (map == null) {
-        return createIterResultObject(undefined, true);
-      }
-
-      var entries = map['_mapData'];
-
-      while (index < entries.length) {
-        var record = entries[index];
-
-        index += 1;
-        this._nextIndex = index;
-
-        if (record) {
-          if (kind === KIND_KEY) {
-            return createIterResultObject(record[0], false);
-          } else if (kind === KIND_VALUE) {
-            return createIterResultObject(record[1], false);
-          } else if (kind) {
-            return createIterResultObject(record, false);
-          }
-        }
-      }
-
-      this._map = undefined;
-
-      return createIterResultObject(undefined, true);
-    }
-  }
-
-  // We can put this in the class definition once we have computed props
-  // transform.
-  // 23.1.5.2.2
-  MapIterator.prototype[toIterator.ITERATOR_SYMBOL] = function() {
-    return this;
-  }
-
-  /**
-   * Helper Functions.
-   */
-
-  /**
-   * Return an index to map.[[MapData]] array for a given Key.
-   *
-   * @param {map} map
-   * @param {*} key
-   * @return {?number}
-   */
-  function getIndex(map, key) {
-    if (isObject(key)) {
-      var hash = getHash(key);
-      return map._objectIndex[hash];
-    } else {
-      var prefixedKey = KEY_PREFIX + key;
-      if (typeof key === 'string') {
-        return map._stringIndex[prefixedKey];
-      } else {
-        return map._otherIndex[prefixedKey];
-      }
-    }
-  }
-
-  /**
-   * Setup an index that refer to the key's location in map.[[MapData]].
-   *
-   * @param {map} map
-   * @param {*} key
-   */
-  function setIndex(map, key, index) {
-    var shouldDelete = index == null;
-
-    if (isObject(key)) {
-      var hash = getHash(key);
-      if (shouldDelete) {
-        delete map._objectIndex[hash];
-      } else {
-        map._objectIndex[hash] = index;
-      }
-    } else {
-      var prefixedKey = KEY_PREFIX + key;
-      if (typeof key === 'string') {
-        if (shouldDelete) {
-          delete map._stringIndex[prefixedKey];
-        } else {
-          map._stringIndex[prefixedKey] = index;
-        }
-      } else {
-        if (shouldDelete) {
-          delete map._otherIndex[prefixedKey];
-        } else {
-          map._otherIndex[prefixedKey] = index;
-        }
-      }
-    }
-  }
-
-  /**
-   * Instantiate a map with internal slots.
-   *
-   * @param {map} map
-   */
-  function initMap(map) {
-    // Data structure design inspired by Traceur's Map implementation.
-    // We maintain an internal array for all the entries. The array is needed
-    // to remember order. However, to have a reasonable HashMap performance
-    // i.e. O(1) for insertion, deletion, and retrieval. We maintain indices
-    // in objects for fast look ups. Indices are split up according to data
-    // types to avoid collisions.
-    map._mapData = [];
-
-    // Object index maps from an object "hash" to index. The hash being a unique
-    // property of our choosing that we associate with the object. Association
-    // is done by ways of keeping a non-enumerable property on the object.
-    // Ideally these would be `Object.create(null)` objects but since we're
-    // trying to support ES3 we'll have to gaurd against collisions using
-    // prefixes on the keys rather than rely on null prototype objects.
-    map._objectIndex = {};
-
-    // String index maps from strings to index.
-    map._stringIndex = {};
-
-    // Numbers, booleans, undefined, and null.
-    map._otherIndex = {};
-
-    // Unfortunately we have to support ES3 and cannot have `Map.prototype.size`
-    // be a getter method but just a regular method. The biggest problem with
-    // this is safety. Clients can change the size property easily and possibly
-    // without noticing (e.g. `if (map.size = 1) {..}` kind of typo). What we
-    // can do to mitigate use getters and setters in development to disallow
-    // and issue a warning for changing the `size` property.
-    if (__DEV__) {
-      if (isES5) {
-        // If the `SECRET_SIZE_PROP` property is already defined then we're not
-        // in the first call to `initMap` (e.g. coming from `map.clear()`) so
-        // all we need to do is reset the size without defining the properties.
-        if (map.hasOwnProperty(SECRET_SIZE_PROP)) {
-          map[SECRET_SIZE_PROP] = 0;
-        } else {
-          Object.defineProperty(map, SECRET_SIZE_PROP, {
-            value: 0,
-            writable: true
-          });
-          Object.defineProperty(map, 'size', {
-            set: (v) => {
-              console.error(
-                'PLEASE FIX ME: You are changing the map size property which ' +
-                'should not be writable and will break in production.'
-              );
-              throw new Error('The map size property is not writable.');
-            },
-            get: () => map[SECRET_SIZE_PROP]
-          });
-        }
-
-        // NOTE: Early return to implement immutable `.size` in DEV.
-        return;
-      }
-    }
-
-    // This is a diviation from the spec. `size` should be a getter on
-    // `Map.prototype`. However, we have to support IE8.
-    map.size = 0;
-  }
-
-  /**
-   * Check if something is an object.
-   *
-   * @param {*} o
-   * @return {boolean}
-   */
-  function isObject(o) {
-    return o != null && (typeof o === 'object' || typeof o === 'function');
-  }
-
-  /**
-   * Create an iteration object.
-   *
-   * @param {*} value
-   * @param {boolean} done
-   * @return {object}
-   */
-  function createIterResultObject(value, done) {
-    return {value, done};
-  }
-
-  // Are we in a legit ES5 environment. Spoiler alert: that doesn't include IE8.
-  var isES5 = (function() {
-    try {
-      Object.defineProperty({}, 'x', {});
-      return true;
-    } catch(e) {
-      return false;
-    }
-  })();
-
-  /**
-   * Check if an object can be extended.
-   *
-   * @param {object|array|function|regexp} o
-   * @return {boolean}
-   */
-  function isExtensible(o) {
-    if (!isES5) {
-      return true;
-    } else {
-      return Object.isExtensible(o);
-    }
-  }
-
-  /**
-   * IE has a `uniqueID` set on every DOM node. So we construct the hash from
-   * this uniqueID to avoid memory leaks and the IE cloneNode bug where it
-   * clones properties in addition to the attributes.
-   *
-   * @param {object} node
-   * @return {?string}
-   */
-  function getIENodeHash(node) {
-    var uniqueID;
-    switch (node.nodeType) {
-      case 1: // Element
-        uniqueID = node.uniqueID;
-        break;
-      case 9: // Document
-        uniqueID = node.documentElement.uniqueID;
-        break;
-      default:
-        return null;
-    }
-
-    if (uniqueID) {
-      return  OLD_IE_HASH_PREFIX + uniqueID;
-    } else {
-      return null;
-    }
-  }
-
-  var getHash = (function() {
-    var propIsEnumerable = Object.prototype.propertyIsEnumerable;
-    var hashProperty = guid();
-    var hashCounter = 0;
-
-    /**
-     * Get the "hash" associated with an object.
-     *
-     * @param {object|array|function|regexp} o
-     * @return {number}
-     */
-    return function getHash(o) {
-      if (o[hashProperty]) {
-        return o[hashProperty];
-      } else if (!isES5 &&
-                  o.propertyIsEnumerable &&
-                  o.propertyIsEnumerable[hashProperty]) {
-        return o.propertyIsEnumerable[hashProperty];
-      } else if (!isES5 &&
-                  isNode(o) &&
-                  getIENodeHash(o)) {
-        return getIENodeHash(o);
-      } else if (!isES5 && o[hashProperty]) {
-        return o[hashProperty];
-      }
-
-      if (isExtensible(o)) {
-        hashCounter += 1;
-        if (isES5) {
-          Object.defineProperty(o, hashProperty, {
-            enumerable: false,
-            writable: false,
-            configurable: false,
-            value: hashCounter
-          });
-        } else if (o.propertyIsEnumerable) {
-          // Since we can't define a non-enumerable property on the object
-          // we'll hijack one of the less-used non-enumerable properties to
-          // save our hash on it. Addiotionally, since this is a function it
-          // will not show up in `JSON.stringify` which is what we want.
-          o.propertyIsEnumerable = function() {
-            return propIsEnumerable.apply(this, arguments);
-          };
-          o.propertyIsEnumerable[hashProperty] = hashCounter;
-        } else if (isNode(o)) {
-          // At this point we couldn't get the IE `uniqueID` to use as a hash
-          // and we couldn't use a non-enumerable property to exploit the
-          // dontEnum bug so we simply add the `hashProperty` on the node
-          // itself.
-          o[hashProperty] = hashCounter;
-        } else {
-          throw new Error('Unable to set a non-enumerable property on object.');
-        }
-        return hashCounter;
-      } else {
-        throw new Error('Non-extensible objects are not allowed as keys.');
-      }
-    };
-  })();
-
-  return Map;
-})(/* jslint evil: true */ Function('return this')());
diff --git a/Libraries/vendor/core/isEmpty.js b/Libraries/vendor/core/isEmpty.js
deleted file mode 100644
index 27f4c0069a06..000000000000
--- a/Libraries/vendor/core/isEmpty.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * @generated SignedSource<<97ffcebc9ae390e734026a4f3964bff6>>
- *
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !! This file is a check-in of a static_upstream project!      !!
- * !!                                                            !!
- * !! You should not modify this file directly. Instead:         !!
- * !! 1) Use `fjs use-upstream` to temporarily replace this with !!
- * !!    the latest version from upstream.                       !!
- * !! 2) Make your changes, test them, etc.                      !!
- * !! 3) Use `fjs push-upstream` to copy your changes back to    !!
- * !!    static_upstream.                                        !!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- *
- * @providesModule isEmpty
- */
-
-/**
- * Mimics empty from PHP.
- */
-function isEmpty(obj) {
-  if (Array.isArray(obj)) {
-    return obj.length === 0;
-  } else if (typeof obj === 'object') {
-    for (var i in obj) {
-      return false;
-    }
-    return true;
-  } else {
-    return !obj;
-  }
-}
-
-module.exports = isEmpty;
diff --git a/Libraries/vendor/crypto/crc32.js b/Libraries/vendor/crypto/crc32.js
deleted file mode 100644
index 540d60aa832b..000000000000
--- a/Libraries/vendor/crypto/crc32.js
+++ /dev/null
@@ -1,92 +0,0 @@
-/**
- * @generated SignedSource<<77bdeb858138636c96c405d64b6be55c>>
- *
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !! This file is a check-in of a static_upstream project!      !!
- * !!                                                            !!
- * !! You should not modify this file directly. Instead:         !!
- * !! 1) Use `fjs use-upstream` to temporarily replace this with !!
- * !!    the latest version from upstream.                       !!
- * !! 2) Make your changes, test them, etc.                      !!
- * !! 3) Use `fjs push-upstream` to copy your changes back to    !!
- * !!    static_upstream.                                        !!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- *
- * Copyright 2004-present Facebook. All Rights Reserved.
- *
- * @providesModule crc32
- */
-
-/* jslint bitwise: true */
-
-/**
- * Modified from the original for performance improvements.
- *
- * @see http://create.stephan-brumme.com/crc32/
- * @see http://stackoverflow.com/questions/18638900/
- * @copyright 2006 Andrea Ercolino
- * @license MIT
- */
-
-var table = [
-  0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
-  0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
-  0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
-  0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
-  0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
-  0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
-  0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
-  0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
-  0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
-  0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
-  0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
-  0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
-  0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
-  0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
-  0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
-  0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
-  0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
-  0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
-  0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
-  0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
-  0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
-  0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
-  0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
-  0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
-  0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
-  0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
-  0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
-  0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
-  0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
-  0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
-  0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
-  0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
-  0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
-  0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
-  0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
-  0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
-  0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
-  0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
-  0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
-  0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
-  0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
-  0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
-  0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
-];
-
-if (global.Int32Array !== undefined) {
-  table = new Int32Array(table);
-}
-
-/**
- * @returns Number
- */
-function crc32(str) {
-  var crc = -1;
-  for (var i = 0, len = str.length; i < len; i++) {
-    crc = (crc >>> 8) ^ table[(crc ^ str.charCodeAt(i)) & 0xFF];
-  }
-  return ~crc;
-}
-
-module.exports = crc32;
diff --git a/Libraries/vendor/fbjs/CSSCore.js b/Libraries/vendor/fbjs/CSSCore.js
new file mode 100644
index 000000000000..70f72f7677a6
--- /dev/null
+++ b/Libraries/vendor/fbjs/CSSCore.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 CSSCore
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/CSSCore');
diff --git a/Libraries/vendor/fbjs/Deferred.js b/Libraries/vendor/fbjs/Deferred.js
new file mode 100644
index 000000000000..88704b83901a
--- /dev/null
+++ b/Libraries/vendor/fbjs/Deferred.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 Deferred
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/Deferred');
diff --git a/Libraries/vendor/fbjs/EventListener.js b/Libraries/vendor/fbjs/EventListener.js
new file mode 100644
index 000000000000..ec6041de37df
--- /dev/null
+++ b/Libraries/vendor/fbjs/EventListener.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 EventListener
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/EventListener');
diff --git a/Libraries/vendor/fbjs/Map.js b/Libraries/vendor/fbjs/Map.js
new file mode 100644
index 000000000000..4fd97503ba8b
--- /dev/null
+++ b/Libraries/vendor/fbjs/Map.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 Map
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/Map');
diff --git a/Libraries/vendor/fbjs/PromiseMap.js b/Libraries/vendor/fbjs/PromiseMap.js
new file mode 100644
index 000000000000..30891f521c75
--- /dev/null
+++ b/Libraries/vendor/fbjs/PromiseMap.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 PromiseMap
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/PromiseMap');
diff --git a/Libraries/vendor/fbjs/TouchEventUtils.js b/Libraries/vendor/fbjs/TouchEventUtils.js
new file mode 100644
index 000000000000..f75be6944164
--- /dev/null
+++ b/Libraries/vendor/fbjs/TouchEventUtils.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 TouchEventUtils
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/TouchEventUtils');
diff --git a/Libraries/vendor/fbjs/URI.js b/Libraries/vendor/fbjs/URI.js
new file mode 100644
index 000000000000..72c5650012cf
--- /dev/null
+++ b/Libraries/vendor/fbjs/URI.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 URI
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/URI');
diff --git a/Libraries/vendor/fbjs/UserAgent.js b/Libraries/vendor/fbjs/UserAgent.js
new file mode 100644
index 000000000000..85c2669b8c1a
--- /dev/null
+++ b/Libraries/vendor/fbjs/UserAgent.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 UserAgent
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/UserAgent');
diff --git a/Libraries/vendor/fbjs/UserAgentData.js b/Libraries/vendor/fbjs/UserAgentData.js
new file mode 100644
index 000000000000..13ff6a335caf
--- /dev/null
+++ b/Libraries/vendor/fbjs/UserAgentData.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 UserAgentData
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/UserAgentData');
diff --git a/Libraries/vendor/fbjs/VersionRange.js b/Libraries/vendor/fbjs/VersionRange.js
new file mode 100644
index 000000000000..de55fe18928d
--- /dev/null
+++ b/Libraries/vendor/fbjs/VersionRange.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 VersionRange
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/VersionRange');
diff --git a/Libraries/vendor/fbjs/areEqual.js b/Libraries/vendor/fbjs/areEqual.js
new file mode 100644
index 000000000000..8c020878a20a
--- /dev/null
+++ b/Libraries/vendor/fbjs/areEqual.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 areEqual
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/areEqual');
diff --git a/Libraries/vendor/fbjs/base62.js b/Libraries/vendor/fbjs/base62.js
new file mode 100644
index 000000000000..596b871dcbf6
--- /dev/null
+++ b/Libraries/vendor/fbjs/base62.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 base62
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/base62');
diff --git a/Libraries/vendor/fbjs/camelize.js b/Libraries/vendor/fbjs/camelize.js
new file mode 100644
index 000000000000..356cfefaad1c
--- /dev/null
+++ b/Libraries/vendor/fbjs/camelize.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 camelize
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/camelize');
diff --git a/Libraries/vendor/fbjs/camelizeStyleName.js b/Libraries/vendor/fbjs/camelizeStyleName.js
new file mode 100644
index 000000000000..a92ed2c104d9
--- /dev/null
+++ b/Libraries/vendor/fbjs/camelizeStyleName.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 camelizeStyleName
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/camelizeStyleName');
diff --git a/Libraries/vendor/fbjs/containsNode.js b/Libraries/vendor/fbjs/containsNode.js
new file mode 100644
index 000000000000..67d65e4f4a74
--- /dev/null
+++ b/Libraries/vendor/fbjs/containsNode.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 containsNode
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/containsNode');
diff --git a/Libraries/vendor/fbjs/crc32.js b/Libraries/vendor/fbjs/crc32.js
new file mode 100644
index 000000000000..cb4fba1a2012
--- /dev/null
+++ b/Libraries/vendor/fbjs/crc32.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 crc32
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/crc32');
diff --git a/Libraries/vendor/fbjs/createArrayFromMixed.js b/Libraries/vendor/fbjs/createArrayFromMixed.js
new file mode 100644
index 000000000000..6489c47746cd
--- /dev/null
+++ b/Libraries/vendor/fbjs/createArrayFromMixed.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 createArrayFromMixed
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/createArrayFromMixed');
diff --git a/Libraries/vendor/fbjs/createNodesFromMarkup.js b/Libraries/vendor/fbjs/createNodesFromMarkup.js
new file mode 100644
index 000000000000..fb5899c0ff3d
--- /dev/null
+++ b/Libraries/vendor/fbjs/createNodesFromMarkup.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 createNodesFromMarkup
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/createNodesFromMarkup');
diff --git a/Libraries/vendor/fbjs/emptyFunction.js b/Libraries/vendor/fbjs/emptyFunction.js
new file mode 100644
index 000000000000..ac55c276a163
--- /dev/null
+++ b/Libraries/vendor/fbjs/emptyFunction.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 emptyFunction
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/emptyFunction');
diff --git a/Libraries/vendor/fbjs/emptyObject.js b/Libraries/vendor/fbjs/emptyObject.js
new file mode 100644
index 000000000000..f738081cc0d0
--- /dev/null
+++ b/Libraries/vendor/fbjs/emptyObject.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 emptyObject
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/emptyObject');
diff --git a/Libraries/vendor/fbjs/everyObject.js b/Libraries/vendor/fbjs/everyObject.js
new file mode 100644
index 000000000000..4fe49e035ad7
--- /dev/null
+++ b/Libraries/vendor/fbjs/everyObject.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 everyObject
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/everyObject');
diff --git a/Libraries/vendor/fbjs/fetchWithRetries.js b/Libraries/vendor/fbjs/fetchWithRetries.js
new file mode 100644
index 000000000000..16d1e1aa98eb
--- /dev/null
+++ b/Libraries/vendor/fbjs/fetchWithRetries.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 fetchWithRetries
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/fetchWithRetries');
diff --git a/Libraries/vendor/fbjs/filterObject.js b/Libraries/vendor/fbjs/filterObject.js
new file mode 100644
index 000000000000..819e188e4bf5
--- /dev/null
+++ b/Libraries/vendor/fbjs/filterObject.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 filterObject
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/filterObject');
diff --git a/Libraries/vendor/fbjs/flattenArray.js b/Libraries/vendor/fbjs/flattenArray.js
new file mode 100644
index 000000000000..14f12d6a41ff
--- /dev/null
+++ b/Libraries/vendor/fbjs/flattenArray.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 flattenArray
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/flattenArray');
diff --git a/Libraries/vendor/fbjs/focusNode.js b/Libraries/vendor/fbjs/focusNode.js
new file mode 100644
index 000000000000..91df968db9e0
--- /dev/null
+++ b/Libraries/vendor/fbjs/focusNode.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 focusNode
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/focusNode');
diff --git a/Libraries/vendor/fbjs/forEachObject.js b/Libraries/vendor/fbjs/forEachObject.js
new file mode 100644
index 000000000000..1e5b39f29f29
--- /dev/null
+++ b/Libraries/vendor/fbjs/forEachObject.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 forEachObject
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/forEachObject');
diff --git a/Libraries/vendor/fbjs/getActiveElement.js b/Libraries/vendor/fbjs/getActiveElement.js
new file mode 100644
index 000000000000..cb597c5a2783
--- /dev/null
+++ b/Libraries/vendor/fbjs/getActiveElement.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 getActiveElement
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/getActiveElement');
diff --git a/Libraries/vendor/fbjs/getMarkupWrap.js b/Libraries/vendor/fbjs/getMarkupWrap.js
new file mode 100644
index 000000000000..8673d4630225
--- /dev/null
+++ b/Libraries/vendor/fbjs/getMarkupWrap.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 getMarkupWrap
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/getMarkupWrap');
diff --git a/Libraries/vendor/fbjs/getUnboundedScrollPosition.js b/Libraries/vendor/fbjs/getUnboundedScrollPosition.js
new file mode 100644
index 000000000000..a72586ef4063
--- /dev/null
+++ b/Libraries/vendor/fbjs/getUnboundedScrollPosition.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 getUnboundedScrollPosition
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/getUnboundedScrollPosition');
diff --git a/Libraries/vendor/fbjs/hyphenate.js b/Libraries/vendor/fbjs/hyphenate.js
new file mode 100644
index 000000000000..00cec2c76b63
--- /dev/null
+++ b/Libraries/vendor/fbjs/hyphenate.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 hyphenate
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/hyphenate');
diff --git a/Libraries/vendor/fbjs/hyphenateStyleName.js b/Libraries/vendor/fbjs/hyphenateStyleName.js
new file mode 100644
index 000000000000..b1349ea097d1
--- /dev/null
+++ b/Libraries/vendor/fbjs/hyphenateStyleName.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 hyphenateStyleName
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/hyphenateStyleName');
diff --git a/Libraries/vendor/fbjs/invariant.js b/Libraries/vendor/fbjs/invariant.js
new file mode 100644
index 000000000000..1a19702441d8
--- /dev/null
+++ b/Libraries/vendor/fbjs/invariant.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 invariant
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/invariant');
diff --git a/Libraries/vendor/fbjs/isEmpty.js b/Libraries/vendor/fbjs/isEmpty.js
new file mode 100644
index 000000000000..3d9ae58e99ec
--- /dev/null
+++ b/Libraries/vendor/fbjs/isEmpty.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 isEmpty
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/isEmpty');
diff --git a/Libraries/vendor/fbjs/isNode.js b/Libraries/vendor/fbjs/isNode.js
new file mode 100644
index 000000000000..d99b32dad507
--- /dev/null
+++ b/Libraries/vendor/fbjs/isNode.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 isNode
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/isNode');
diff --git a/Libraries/vendor/fbjs/isTextNode.js b/Libraries/vendor/fbjs/isTextNode.js
new file mode 100644
index 000000000000..7b39b169863c
--- /dev/null
+++ b/Libraries/vendor/fbjs/isTextNode.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 isTextNode
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/isTextNode');
diff --git a/Libraries/vendor/fbjs/joinClasses.js b/Libraries/vendor/fbjs/joinClasses.js
new file mode 100644
index 000000000000..8e7908a9d0d1
--- /dev/null
+++ b/Libraries/vendor/fbjs/joinClasses.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 joinClasses
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/joinClasses');
diff --git a/Libraries/vendor/fbjs/keyMirror.js b/Libraries/vendor/fbjs/keyMirror.js
new file mode 100644
index 000000000000..021b3405206c
--- /dev/null
+++ b/Libraries/vendor/fbjs/keyMirror.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 keyMirror
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/keyMirror');
diff --git a/Libraries/vendor/fbjs/keyOf.js b/Libraries/vendor/fbjs/keyOf.js
new file mode 100644
index 000000000000..646040a57186
--- /dev/null
+++ b/Libraries/vendor/fbjs/keyOf.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 keyOf
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/keyOf');
diff --git a/Libraries/vendor/fbjs/mapObject.js b/Libraries/vendor/fbjs/mapObject.js
new file mode 100644
index 000000000000..a74e35737cc1
--- /dev/null
+++ b/Libraries/vendor/fbjs/mapObject.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 mapObject
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/mapObject');
diff --git a/Libraries/vendor/fbjs/memoizeStringOnly.js b/Libraries/vendor/fbjs/memoizeStringOnly.js
new file mode 100644
index 000000000000..36d4d31458f9
--- /dev/null
+++ b/Libraries/vendor/fbjs/memoizeStringOnly.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 memoizeStringOnly
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/memoizeStringOnly');
diff --git a/Libraries/vendor/fbjs/monitorCodeUse.js b/Libraries/vendor/fbjs/monitorCodeUse.js
new file mode 100644
index 000000000000..c06614c17d2b
--- /dev/null
+++ b/Libraries/vendor/fbjs/monitorCodeUse.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 monitorCodeUse
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/monitorCodeUse');
diff --git a/Libraries/vendor/fbjs/nativeRequestAnimationFrame.js b/Libraries/vendor/fbjs/nativeRequestAnimationFrame.js
new file mode 100644
index 000000000000..5ff2ba2a85be
--- /dev/null
+++ b/Libraries/vendor/fbjs/nativeRequestAnimationFrame.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 nativeRequestAnimationFrame
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/nativeRequestAnimationFrame');
diff --git a/Libraries/vendor/fbjs/nullthrows.js b/Libraries/vendor/fbjs/nullthrows.js
new file mode 100644
index 000000000000..5de73280dbf0
--- /dev/null
+++ b/Libraries/vendor/fbjs/nullthrows.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 nullthrows
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/nullthrows');
diff --git a/Libraries/vendor/fbjs/performance.js b/Libraries/vendor/fbjs/performance.js
new file mode 100644
index 000000000000..eab35d18d69e
--- /dev/null
+++ b/Libraries/vendor/fbjs/performance.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 performance
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/performance');
diff --git a/Libraries/vendor/fbjs/performanceNow.js b/Libraries/vendor/fbjs/performanceNow.js
new file mode 100644
index 000000000000..fa0c50535c11
--- /dev/null
+++ b/Libraries/vendor/fbjs/performanceNow.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 performanceNow
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/performanceNow');
diff --git a/Libraries/vendor/fbjs/removeFromArray.js b/Libraries/vendor/fbjs/removeFromArray.js
new file mode 100644
index 000000000000..0af09ec36792
--- /dev/null
+++ b/Libraries/vendor/fbjs/removeFromArray.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 removeFromArray
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/removeFromArray');
diff --git a/Libraries/vendor/fbjs/requestAnimationFrame.js b/Libraries/vendor/fbjs/requestAnimationFrame.js
new file mode 100644
index 000000000000..1671e27ef1f2
--- /dev/null
+++ b/Libraries/vendor/fbjs/requestAnimationFrame.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 requestAnimationFrame
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/requestAnimationFrame');
diff --git a/Libraries/vendor/fbjs/resolveImmediate.js b/Libraries/vendor/fbjs/resolveImmediate.js
new file mode 100644
index 000000000000..e587c24dada3
--- /dev/null
+++ b/Libraries/vendor/fbjs/resolveImmediate.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 resolveImmediate
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/resolveImmediate');
diff --git a/Libraries/vendor/fbjs/shallowEqual.js b/Libraries/vendor/fbjs/shallowEqual.js
new file mode 100644
index 000000000000..065a3e682002
--- /dev/null
+++ b/Libraries/vendor/fbjs/shallowEqual.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 shallowEqual
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/shallowEqual');
diff --git a/Libraries/vendor/fbjs/someObject.js b/Libraries/vendor/fbjs/someObject.js
new file mode 100644
index 000000000000..edd2cdd7b1d7
--- /dev/null
+++ b/Libraries/vendor/fbjs/someObject.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 someObject
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/someObject');
diff --git a/Libraries/vendor/fbjs/sprintf.js b/Libraries/vendor/fbjs/sprintf.js
new file mode 100644
index 000000000000..f4140fc06400
--- /dev/null
+++ b/Libraries/vendor/fbjs/sprintf.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 sprintf
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/sprintf');
diff --git a/Libraries/vendor/fbjs/warning.js b/Libraries/vendor/fbjs/warning.js
new file mode 100644
index 000000000000..7ae0cdf81b8e
--- /dev/null
+++ b/Libraries/vendor/fbjs/warning.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 warning
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/warning');
diff --git a/Libraries/vendor/fbjs/xhrSimpleDataSerializer.js b/Libraries/vendor/fbjs/xhrSimpleDataSerializer.js
new file mode 100644
index 000000000000..d0d9b2c60c52
--- /dev/null
+++ b/Libraries/vendor/fbjs/xhrSimpleDataSerializer.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) 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 xhrSimpleDataSerializer
+ * @flow
+ */
+'use strict';
+
+module.exports = require('fbjs/lib/xhrSimpleDataSerializer');
diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index dc7c0be87142..9826948e1dca 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -142,15 +142,15 @@
           "from": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz",
           "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
         },
-        "recast": {
-          "version": "0.10.33",
-          "from": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz",
-          "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
-        },
         "regenerator": {
           "version": "0.8.40",
           "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
           "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
+        },
+        "recast": {
+          "version": "0.10.33",
+          "from": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz",
+          "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
         }
       }
     },
@@ -1815,19 +1815,21 @@
       "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.1.0.tgz"
     },
     "fbjs": {
-      "version": "0.6.0",
-      "from": "https://registry.npmjs.org/fbjs/-/fbjs-0.6.0.tgz",
-      "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.6.0.tgz",
+      "version": "0.7.2",
+      "from": "fbjs@0.7.2",
+      "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.7.2.tgz",
       "dependencies": {
-        "ua-parser-js": {
-          "version": "0.7.10",
-          "from": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.10.tgz",
-          "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.10.tgz"
-        },
-        "whatwg-fetch": {
-          "version": "0.9.0",
-          "from": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz",
-          "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz"
+        "isomorphic-fetch": {
+          "version": "2.2.1",
+          "from": "isomorphic-fetch@>=2.1.1 <3.0.0",
+          "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
+          "dependencies": {
+            "whatwg-fetch": {
+              "version": "0.11.0",
+              "from": "whatwg-fetch@>=0.10.0",
+              "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.11.0.tgz"
+            }
+          }
         }
       }
     },
@@ -1915,16 +1917,16 @@
           "from": "are-we-there-yet@~1.0.0",
           "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.4.tgz"
         },
-        "asn1": {
-          "version": "0.1.11",
-          "from": "asn1@0.1.11",
-          "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
-        },
         "assert-plus": {
           "version": "0.1.5",
           "from": "assert-plus@^0.1.5",
           "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
         },
+        "asn1": {
+          "version": "0.1.11",
+          "from": "asn1@0.1.11",
+          "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
+        },
         "async": {
           "version": "1.5.0",
           "from": "async@^1.4.0",
@@ -1950,6 +1952,11 @@
           "from": "boom@^2.8.x",
           "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz"
         },
+        "caseless": {
+          "version": "0.11.0",
+          "from": "caseless@~0.11.0",
+          "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
+        },
         "brace-expansion": {
           "version": "1.1.1",
           "from": "brace-expansion@>=1.0.0 <2.0.0",
@@ -1960,11 +1967,6 @@
           "from": "chalk@^1.1.1",
           "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz"
         },
-        "caseless": {
-          "version": "0.11.0",
-          "from": "caseless@~0.11.0",
-          "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
-        },
         "combined-stream": {
           "version": "1.0.5",
           "from": "combined-stream@~1.0.5",
@@ -2065,36 +2067,36 @@
           "from": "graceful-readlink@>= 1.0.0",
           "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
         },
-        "has-ansi": {
-          "version": "2.0.0",
-          "from": "has-ansi@^2.0.0",
-          "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
-        },
         "har-validator": {
           "version": "2.0.2",
           "from": "har-validator@~2.0.2",
           "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.2.tgz"
         },
-        "has-unicode": {
-          "version": "1.0.1",
-          "from": "has-unicode@^1.0.0",
-          "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-1.0.1.tgz"
+        "has-ansi": {
+          "version": "2.0.0",
+          "from": "has-ansi@^2.0.0",
+          "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
         },
         "hawk": {
           "version": "3.1.0",
           "from": "hawk@~3.1.0",
           "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.0.tgz"
         },
-        "hoek": {
-          "version": "2.16.3",
-          "from": "hoek@2.x.x",
-          "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz"
+        "has-unicode": {
+          "version": "1.0.1",
+          "from": "has-unicode@^1.0.0",
+          "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-1.0.1.tgz"
         },
         "http-signature": {
           "version": "0.11.0",
           "from": "http-signature@~0.11.0",
           "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.11.0.tgz"
         },
+        "hoek": {
+          "version": "2.16.3",
+          "from": "hoek@2.x.x",
+          "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz"
+        },
         "inherits": {
           "version": "2.0.1",
           "from": "inherits@*",
@@ -2120,31 +2122,31 @@
           "from": "isarray@0.0.1",
           "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
         },
-        "isstream": {
-          "version": "0.1.2",
-          "from": "isstream@~0.1.2",
-          "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
-        },
         "json-stringify-safe": {
           "version": "5.0.1",
           "from": "json-stringify-safe@~5.0.1",
           "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
         },
+        "isstream": {
+          "version": "0.1.2",
+          "from": "isstream@~0.1.2",
+          "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
+        },
         "jsonpointer": {
           "version": "2.0.0",
           "from": "jsonpointer@2.0.0",
           "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
         },
-        "lodash._basetostring": {
-          "version": "3.0.1",
-          "from": "lodash._basetostring@^3.0.0",
-          "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz"
-        },
         "lodash._createpadding": {
           "version": "3.6.1",
           "from": "lodash._createpadding@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash._createpadding/-/lodash._createpadding-3.6.1.tgz"
         },
+        "lodash._basetostring": {
+          "version": "3.0.1",
+          "from": "lodash._basetostring@^3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz"
+        },
         "lodash.pad": {
           "version": "3.1.1",
           "from": "lodash.pad@^3.0.0",
@@ -2210,16 +2212,16 @@
           "from": "path-is-absolute@>=1.0.0 <2.0.0",
           "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz"
         },
-        "pinkie": {
-          "version": "1.0.0",
-          "from": "pinkie@^1.0.0",
-          "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
-        },
         "pinkie-promise": {
           "version": "1.0.0",
           "from": "pinkie-promise@^1.0.0",
           "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz"
         },
+        "pinkie": {
+          "version": "1.0.0",
+          "from": "pinkie@^1.0.0",
+          "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
+        },
         "qs": {
           "version": "5.2.0",
           "from": "qs@~5.2.0",
@@ -2235,16 +2237,16 @@
           "from": "request@2.x",
           "resolved": "https://registry.npmjs.org/request/-/request-2.65.0.tgz"
         },
-        "sntp": {
-          "version": "1.0.9",
-          "from": "sntp@1.x.x",
-          "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
-        },
         "semver": {
           "version": "5.0.3",
           "from": "semver@~5.0.1",
           "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
         },
+        "sntp": {
+          "version": "1.0.9",
+          "from": "sntp@1.x.x",
+          "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
+        },
         "string_decoder": {
           "version": "0.10.31",
           "from": "string_decoder@~0.10.x",
@@ -2255,21 +2257,16 @@
           "from": "stringstream@~0.0.4",
           "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
         },
-        "strip-ansi": {
-          "version": "3.0.0",
-          "from": "strip-ansi@^3.0.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz"
-        },
-        "supports-color": {
-          "version": "2.0.0",
-          "from": "supports-color@^2.0.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
-        },
         "strip-json-comments": {
           "version": "0.1.3",
           "from": "strip-json-comments@0.1.x",
           "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
         },
+        "strip-ansi": {
+          "version": "3.0.0",
+          "from": "strip-ansi@^3.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz"
+        },
         "tar": {
           "version": "2.2.1",
           "from": "tar@~2.2.0",
@@ -2280,6 +2277,11 @@
           "from": "tough-cookie@~2.2.0",
           "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.0.tgz"
         },
+        "supports-color": {
+          "version": "2.0.0",
+          "from": "supports-color@^2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
+        },
         "tunnel-agent": {
           "version": "0.4.1",
           "from": "tunnel-agent@~0.4.1",
@@ -2344,15 +2346,15 @@
               "from": "glob@>=5.0.14 <6.0.0",
               "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz"
             },
-            "minimatch": {
-              "version": "3.0.0",
-              "from": "minimatch@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0",
-              "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.0.tgz"
-            },
             "once": {
               "version": "1.3.2",
               "from": "once@>=1.3.0 <2.0.0",
               "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz"
+            },
+            "minimatch": {
+              "version": "3.0.0",
+              "from": "minimatch@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0",
+              "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.0.tgz"
             }
           }
         },
@@ -4058,6 +4060,18 @@
               }
             }
           }
+        },
+        "fbjs": {
+          "version": "0.6.1",
+          "from": "fbjs@>=0.6.0 <0.7.0",
+          "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.6.1.tgz",
+          "dependencies": {
+            "whatwg-fetch": {
+              "version": "0.9.0",
+              "from": "whatwg-fetch@>=0.9.0 <0.10.0",
+              "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz"
+            }
+          }
         }
       }
     },
@@ -4544,6 +4558,11 @@
       "from": "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz",
       "resolved": "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz"
     },
+    "ua-parser-js": {
+      "version": "0.7.10",
+      "from": "ua-parser-js@>=0.7.9 <0.8.0",
+      "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.10.tgz"
+    },
     "uglify-js": {
       "version": "2.4.24",
       "from": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.4.24.tgz",
diff --git a/package.json b/package.json
index 8e606d2fc6b5..eb0789b0164e 100644
--- a/package.json
+++ b/package.json
@@ -75,7 +75,8 @@
     ],
     "unmockedModulePathPatterns": [
       "promise",
-      "source-map"
+      "source-map",
+      "fbjs"
     ]
   },
   "main": "Libraries/react-native/react-native.js",
@@ -121,7 +122,7 @@
     "connect": "^2.8.3",
     "debug": "^2.2.0",
     "event-target-shim": "^1.0.5",
-    "fbjs": "^0.6.0",
+    "fbjs": "^0.7.2",
     "fbjs-scripts": "^0.4.0",
     "graceful-fs": "^4.1.2",
     "image-size": "^0.3.5",
diff --git a/packager/blacklist.js b/packager/blacklist.js
index ee369e1af726..318e09e88ee8 100644
--- a/packager/blacklist.js
+++ b/packager/blacklist.js
@@ -17,36 +17,6 @@ var sharedBlacklist = [
   'node_modules/react/lib/React.js',
   'node_modules/react/lib/ReactDOM.js',
 
-  // For each of these fbjs files (especially the non-forks/stubs), we should
-  // consider deleting the conflicting copy and just using the fbjs version.
-  //
-  // fbjs forks:
-  'node_modules/fbjs/lib/Map.js',
-  'node_modules/fbjs/lib/Promise.js',
-  'node_modules/fbjs/lib/fetch.js',
-  // fbjs stubs:
-  'node_modules/fbjs/lib/ErrorUtils.js',
-  'node_modules/fbjs/lib/URI.js',
-  // fbjs modules:
-  'node_modules/fbjs/lib/Deferred.js',
-  'node_modules/fbjs/lib/PromiseMap.js',
-  'node_modules/fbjs/lib/UserAgent.js',
-  'node_modules/fbjs/lib/areEqual.js',
-  'node_modules/fbjs/lib/base62.js',
-  'node_modules/fbjs/lib/crc32.js',
-  'node_modules/fbjs/lib/everyObject.js',
-  'node_modules/fbjs/lib/fetchWithRetries.js',
-  'node_modules/fbjs/lib/filterObject.js',
-  'node_modules/fbjs/lib/flattenArray.js',
-  'node_modules/fbjs/lib/forEachObject.js',
-  'node_modules/fbjs/lib/isEmpty.js',
-  'node_modules/fbjs/lib/nullthrows.js',
-  'node_modules/fbjs/lib/removeFromArray.js',
-  'node_modules/fbjs/lib/resolveImmediate.js',
-  'node_modules/fbjs/lib/someObject.js',
-  'node_modules/fbjs/lib/sprintf.js',
-  'node_modules/fbjs/lib/xhrSimpleDataSerializer.js',
-
   // Those conflicts with the ones in fbjs/. We need to blacklist the
   // internal version otherwise they won't work in open source.
   'downstream/core/CSSCore.js',
diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index a677c2199da8..10e138c8b961 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -85,7 +85,6 @@ class Resolver {
           (opts.blacklistRE && opts.blacklistRE.test(filepath));
       },
       providesModuleNodeModules: [
-        'fbjs',
         'react',
         'react-native',
         // Parse requires AsyncStorage. They will

From 28116ec3dbfc410d74d6a01c76068d9b62582d7a Mon Sep 17 00:00:00 2001
From: Adam Miskiewicz <adam@sk3vy.com>
Date: Thu, 11 Feb 2016 02:44:24 -0800
Subject: [PATCH 1125/1411] Reverted commit D2803288

Summary:
As spicyj mentioned in commit 6a838a4, the ideal state of affairs when it comes to consuming `react` and `fbjs` from NPM is for the packager not to have knowledge of either package. This PR addresses the `fbjs` part of that, and relies on https://github.com/facebook/fbjs/pull/95. **DO NOT MERGE** until #95 (or a variation) is in `fbjs` and is released to npm.

This PR does several things:

1. Adds stub modules within RN that expose `fbjs` modules to be required using Haste. After discussing a few ideas with spicyj, this seemed like a good option to keep internal FB devs happy (and not make them change the way they write JS), but allow for removing packager complexity and fit in better with the NPM ecosystem. Note -- it skips stubbing `fetch`, `ExecutionEnvironment`, and `ErrorUtils`, due to the fact that these need to have Native specific implementations, and there's no reason for those implementations to exist in `fbjs`.
2. Removes the modules that were previously being used in lieu of their `fbjs` eq
Closes https://github.com/facebook/react-native/pull/5084

Reviewed By: bestander

Differential Revision: D2803288

Pulled By: javache

fb-gh-sync-id: 121ae811ce4cc30e6ea79246f85a1e4f65648ce1
shipit-source-id: 121ae811ce4cc30e6ea79246f85a1e4f65648ce1
---
 .flowconfig                                   |   4 +
 .../__tests__/InteractionManager-test.js      |   1 -
 Libraries/Promise.js                          |  36 +-
 Libraries/vendor/core/Map.js                  | 626 ++++++++++++++++++
 Libraries/vendor/core/isEmpty.js              |  34 +
 Libraries/vendor/crypto/crc32.js              |  92 +++
 Libraries/vendor/fbjs/CSSCore.js              |  14 -
 Libraries/vendor/fbjs/Deferred.js             |  14 -
 Libraries/vendor/fbjs/EventListener.js        |  14 -
 Libraries/vendor/fbjs/Map.js                  |  14 -
 Libraries/vendor/fbjs/PromiseMap.js           |  14 -
 Libraries/vendor/fbjs/TouchEventUtils.js      |  14 -
 Libraries/vendor/fbjs/URI.js                  |  14 -
 Libraries/vendor/fbjs/UserAgent.js            |  14 -
 Libraries/vendor/fbjs/UserAgentData.js        |  14 -
 Libraries/vendor/fbjs/VersionRange.js         |  14 -
 Libraries/vendor/fbjs/areEqual.js             |  14 -
 Libraries/vendor/fbjs/base62.js               |  14 -
 Libraries/vendor/fbjs/camelize.js             |  14 -
 Libraries/vendor/fbjs/camelizeStyleName.js    |  14 -
 Libraries/vendor/fbjs/containsNode.js         |  14 -
 Libraries/vendor/fbjs/crc32.js                |  14 -
 Libraries/vendor/fbjs/createArrayFromMixed.js |  14 -
 .../vendor/fbjs/createNodesFromMarkup.js      |  14 -
 Libraries/vendor/fbjs/emptyFunction.js        |  14 -
 Libraries/vendor/fbjs/emptyObject.js          |  14 -
 Libraries/vendor/fbjs/everyObject.js          |  14 -
 Libraries/vendor/fbjs/fetchWithRetries.js     |  14 -
 Libraries/vendor/fbjs/filterObject.js         |  14 -
 Libraries/vendor/fbjs/flattenArray.js         |  14 -
 Libraries/vendor/fbjs/focusNode.js            |  14 -
 Libraries/vendor/fbjs/forEachObject.js        |  14 -
 Libraries/vendor/fbjs/getActiveElement.js     |  14 -
 Libraries/vendor/fbjs/getMarkupWrap.js        |  14 -
 .../vendor/fbjs/getUnboundedScrollPosition.js |  14 -
 Libraries/vendor/fbjs/hyphenate.js            |  14 -
 Libraries/vendor/fbjs/hyphenateStyleName.js   |  14 -
 Libraries/vendor/fbjs/invariant.js            |  14 -
 Libraries/vendor/fbjs/isEmpty.js              |  14 -
 Libraries/vendor/fbjs/isNode.js               |  14 -
 Libraries/vendor/fbjs/isTextNode.js           |  14 -
 Libraries/vendor/fbjs/joinClasses.js          |  14 -
 Libraries/vendor/fbjs/keyMirror.js            |  14 -
 Libraries/vendor/fbjs/keyOf.js                |  14 -
 Libraries/vendor/fbjs/mapObject.js            |  14 -
 Libraries/vendor/fbjs/memoizeStringOnly.js    |  14 -
 Libraries/vendor/fbjs/monitorCodeUse.js       |  14 -
 .../fbjs/nativeRequestAnimationFrame.js       |  14 -
 Libraries/vendor/fbjs/nullthrows.js           |  14 -
 Libraries/vendor/fbjs/performance.js          |  14 -
 Libraries/vendor/fbjs/performanceNow.js       |  14 -
 Libraries/vendor/fbjs/removeFromArray.js      |  14 -
 .../vendor/fbjs/requestAnimationFrame.js      |  14 -
 Libraries/vendor/fbjs/resolveImmediate.js     |  14 -
 Libraries/vendor/fbjs/shallowEqual.js         |  14 -
 Libraries/vendor/fbjs/someObject.js           |  14 -
 Libraries/vendor/fbjs/sprintf.js              |  14 -
 Libraries/vendor/fbjs/warning.js              |  14 -
 .../vendor/fbjs/xhrSimpleDataSerializer.js    |  14 -
 npm-shrinkwrap.json                           | 169 +++--
 package.json                                  |   5 +-
 packager/blacklist.js                         |  30 +
 packager/react-packager/src/Resolver/index.js |   1 +
 63 files changed, 892 insertions(+), 848 deletions(-)
 create mode 100644 Libraries/vendor/core/Map.js
 create mode 100644 Libraries/vendor/core/isEmpty.js
 create mode 100644 Libraries/vendor/crypto/crc32.js
 delete mode 100644 Libraries/vendor/fbjs/CSSCore.js
 delete mode 100644 Libraries/vendor/fbjs/Deferred.js
 delete mode 100644 Libraries/vendor/fbjs/EventListener.js
 delete mode 100644 Libraries/vendor/fbjs/Map.js
 delete mode 100644 Libraries/vendor/fbjs/PromiseMap.js
 delete mode 100644 Libraries/vendor/fbjs/TouchEventUtils.js
 delete mode 100644 Libraries/vendor/fbjs/URI.js
 delete mode 100644 Libraries/vendor/fbjs/UserAgent.js
 delete mode 100644 Libraries/vendor/fbjs/UserAgentData.js
 delete mode 100644 Libraries/vendor/fbjs/VersionRange.js
 delete mode 100644 Libraries/vendor/fbjs/areEqual.js
 delete mode 100644 Libraries/vendor/fbjs/base62.js
 delete mode 100644 Libraries/vendor/fbjs/camelize.js
 delete mode 100644 Libraries/vendor/fbjs/camelizeStyleName.js
 delete mode 100644 Libraries/vendor/fbjs/containsNode.js
 delete mode 100644 Libraries/vendor/fbjs/crc32.js
 delete mode 100644 Libraries/vendor/fbjs/createArrayFromMixed.js
 delete mode 100644 Libraries/vendor/fbjs/createNodesFromMarkup.js
 delete mode 100644 Libraries/vendor/fbjs/emptyFunction.js
 delete mode 100644 Libraries/vendor/fbjs/emptyObject.js
 delete mode 100644 Libraries/vendor/fbjs/everyObject.js
 delete mode 100644 Libraries/vendor/fbjs/fetchWithRetries.js
 delete mode 100644 Libraries/vendor/fbjs/filterObject.js
 delete mode 100644 Libraries/vendor/fbjs/flattenArray.js
 delete mode 100644 Libraries/vendor/fbjs/focusNode.js
 delete mode 100644 Libraries/vendor/fbjs/forEachObject.js
 delete mode 100644 Libraries/vendor/fbjs/getActiveElement.js
 delete mode 100644 Libraries/vendor/fbjs/getMarkupWrap.js
 delete mode 100644 Libraries/vendor/fbjs/getUnboundedScrollPosition.js
 delete mode 100644 Libraries/vendor/fbjs/hyphenate.js
 delete mode 100644 Libraries/vendor/fbjs/hyphenateStyleName.js
 delete mode 100644 Libraries/vendor/fbjs/invariant.js
 delete mode 100644 Libraries/vendor/fbjs/isEmpty.js
 delete mode 100644 Libraries/vendor/fbjs/isNode.js
 delete mode 100644 Libraries/vendor/fbjs/isTextNode.js
 delete mode 100644 Libraries/vendor/fbjs/joinClasses.js
 delete mode 100644 Libraries/vendor/fbjs/keyMirror.js
 delete mode 100644 Libraries/vendor/fbjs/keyOf.js
 delete mode 100644 Libraries/vendor/fbjs/mapObject.js
 delete mode 100644 Libraries/vendor/fbjs/memoizeStringOnly.js
 delete mode 100644 Libraries/vendor/fbjs/monitorCodeUse.js
 delete mode 100644 Libraries/vendor/fbjs/nativeRequestAnimationFrame.js
 delete mode 100644 Libraries/vendor/fbjs/nullthrows.js
 delete mode 100644 Libraries/vendor/fbjs/performance.js
 delete mode 100644 Libraries/vendor/fbjs/performanceNow.js
 delete mode 100644 Libraries/vendor/fbjs/removeFromArray.js
 delete mode 100644 Libraries/vendor/fbjs/requestAnimationFrame.js
 delete mode 100644 Libraries/vendor/fbjs/resolveImmediate.js
 delete mode 100644 Libraries/vendor/fbjs/shallowEqual.js
 delete mode 100644 Libraries/vendor/fbjs/someObject.js
 delete mode 100644 Libraries/vendor/fbjs/sprintf.js
 delete mode 100644 Libraries/vendor/fbjs/warning.js
 delete mode 100644 Libraries/vendor/fbjs/xhrSimpleDataSerializer.js

diff --git a/.flowconfig b/.flowconfig
index 026deca0e9c9..78c0582045e1 100644
--- a/.flowconfig
+++ b/.flowconfig
@@ -14,8 +14,12 @@
 
 # Ignore react and fbjs where there are overlaps, but don't ignore
 # anything that react-native relies on
+.*/node_modules/fbjs/lib/Map.js
+.*/node_modules/fbjs/lib/Promise.js
 .*/node_modules/fbjs/lib/fetch.js
 .*/node_modules/fbjs/lib/ExecutionEnvironment.js
+.*/node_modules/fbjs/lib/isEmpty.js
+.*/node_modules/fbjs/lib/crc32.js
 .*/node_modules/fbjs/lib/ErrorUtils.js
 
 # Flow has a built-in definition for the 'react' module which we prefer to use
diff --git a/Libraries/Interaction/__tests__/InteractionManager-test.js b/Libraries/Interaction/__tests__/InteractionManager-test.js
index 032acf255546..736fc93c585f 100644
--- a/Libraries/Interaction/__tests__/InteractionManager-test.js
+++ b/Libraries/Interaction/__tests__/InteractionManager-test.js
@@ -6,7 +6,6 @@
 
 jest
   .autoMockOff()
-  .mock('ErrorUtils')
   .mock('BatchedBridge');
 
 function expectToBeCalledOnce(fn) {
diff --git a/Libraries/Promise.js b/Libraries/Promise.js
index 6484dd176807..004741948e4d 100644
--- a/Libraries/Promise.js
+++ b/Libraries/Promise.js
@@ -1,18 +1,30 @@
 /**
- * Copyright (c) 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.
+ * Copyright 2013-2014 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 Promise
- * @flow
+ *
+ * This module wraps and augments the minimally ES6-compliant Promise
+ * implementation provided by the promise npm package.
  */
-'use strict';
 
-const Promise = require('fbjs/lib/Promise'); // this will require Promise.native.js
+'use strict';
 
+global.setImmediate = require('setImmediate');
+var Promise = require('promise/setimmediate/es6-extensions');
+require('promise/setimmediate/done');
 if (__DEV__) {
   require('promise/setimmediate/rejection-tracking').enable({
     allRejections: true,
@@ -34,4 +46,12 @@ if (__DEV__) {
   });
 }
 
+/**
+ * Handle either fulfillment or rejection with the same callback.
+ */
+Promise.prototype.finally = function(onSettled) {
+  return this.then(onSettled, onSettled);
+};
+
+
 module.exports = Promise;
diff --git a/Libraries/vendor/core/Map.js b/Libraries/vendor/core/Map.js
new file mode 100644
index 000000000000..114add77b308
--- /dev/null
+++ b/Libraries/vendor/core/Map.js
@@ -0,0 +1,626 @@
+/**
+ * @generated SignedSource<<375749f44ce7c0f681fc1297943eaf74>>
+ *
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * !! This file is a check-in of a static_upstream project!      !!
+ * !!                                                            !!
+ * !! You should not modify this file directly. Instead:         !!
+ * !! 1) Use `fjs use-upstream` to temporarily replace this with !!
+ * !!    the latest version from upstream.                       !!
+ * !! 2) Make your changes, test them, etc.                      !!
+ * !! 3) Use `fjs push-upstream` to copy your changes back to    !!
+ * !!    static_upstream.                                        !!
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ *
+ * Copyright 2013-2014 Facebook, Inc.
+ * @providesModule Map
+ * @preventMunge
+ * @typechecks
+ */
+
+var guid = require('guid');
+var isNode = require('isNode');
+var toIterator = require('toIterator');
+var _shouldPolyfillES6Collection = require('_shouldPolyfillES6Collection');
+
+module.exports = (function(global, undefined) {
+  // Since our implementation is spec-compliant for the most part we can safely
+  // delegate to a built-in version if exists and is implemented correctly.
+  // Firefox had gotten a few implementation details wrong across different
+  // versions so we guard against that.
+  if (!_shouldPolyfillES6Collection('Map')) {
+    return global.Map;
+  }
+
+  /**
+   * == ES6 Map Collection ==
+   *
+   * This module is meant to implement a Map collection as described in chapter
+   * 23.1 of the ES6 specification.
+   *
+   * Map objects are collections of key/value pairs where both the keys and
+   * values may be arbitrary ECMAScript language values. A distinct key value
+   * may only occur in one key/value pair within the Map's collection.
+   *
+   * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-map-objects
+   *
+   * There only two -- rather small -- diviations from the spec:
+   *
+   * 1. The use of frozen objects as keys.
+   *    We decided not to allow and simply throw an error. The reason being is
+   *    we store a "hash" on the object for fast access to it's place in the
+   *    internal map entries.
+   *    If this turns out to be a popular use case it's possible to implement by
+   *    overiding `Object.freeze` to store a "hash" property on the object
+   *    for later use with the map.
+   *
+   * 2. The `size` property on a map object is a regular property and not a
+   *    computed property on the prototype as described by the spec.
+   *    The reason being is that we simply want to support ES3 environments
+   *    which doesn't implement computed properties.
+   *
+   * == Usage ==
+   *
+   * var map = new Map(iterable);
+   *
+   * map.set(key, value);
+   * map.get(key); // value
+   * map.has(key); // true
+   * map.delete(key); // true
+   *
+   * var iterator = map.keys();
+   * iterator.next(); // {value: key, done: false}
+   *
+   * var iterator = map.values();
+   * iterator.next(); // {value: value, done: false}
+   *
+   * var iterator = map.entries();
+   * iterator.next(); // {value: [key, value], done: false}
+   *
+   * map.forEach(function(value, key){ this === thisArg }, thisArg);
+   *
+   * map.clear(); // resets map.
+   */
+
+  /**
+   * Constants
+   */
+
+  // Kinds of map iterations 23.1.5.3
+  var KIND_KEY = 'key';
+  var KIND_VALUE = 'value';
+  var KIND_KEY_VALUE = 'key+value';
+
+  // In older browsers we can't create a null-prototype object so we have to
+  // defend against key collisions with built-in methods.
+  var KEY_PREFIX = '$map_';
+
+  // This property will be used as the internal size variable to disallow
+  // writing and to issue warnings for writings in development.
+  var SECRET_SIZE_PROP;
+  if (__DEV__) {
+    SECRET_SIZE_PROP = '$size' + guid();
+  }
+
+  // In oldIE we use the DOM Node `uniqueID` property to get create the hash.
+  var OLD_IE_HASH_PREFIX = 'IE_HASH_';
+
+  class Map {
+
+    /**
+     * 23.1.1.1
+     * Takes an `iterable` which is basically any object that implements a
+     * Symbol.iterator (@@iterator) method. The iterable is expected to be a
+     * collection of pairs. Each pair is a key/value pair that will be used
+     * to instantiate the map.
+     *
+     * @param {*} iterable
+     */
+    constructor(iterable) {
+      if (!isObject(this)) {
+        throw new TypeError('Wrong map object type.');
+      }
+
+      initMap(this);
+
+      if (iterable != null) {
+        var it = toIterator(iterable);
+        var next;
+        while (!(next = it.next()).done) {
+          if (!isObject(next.value)) {
+            throw new TypeError('Expected iterable items to be pair objects.');
+          }
+          this.set(next.value[0], next.value[1]);
+        }
+      }
+    }
+
+    /**
+     * 23.1.3.1
+     * Clears the map from all keys and values.
+     */
+    clear() {
+      initMap(this);
+    }
+
+    /**
+     * 23.1.3.7
+     * Check if a key exists in the collection.
+     *
+     * @param {*} key
+     * @return {boolean}
+     */
+    has(key) {
+      var index = getIndex(this, key);
+      return !!(index != null && this._mapData[index]);
+    }
+
+    /**
+     * 23.1.3.9
+     * Adds a key/value pair to the collection.
+     *
+     * @param {*} key
+     * @param {*} value
+     * @return {map}
+     */
+    set(key, value) {
+      var index = getIndex(this, key);
+
+      if (index != null && this._mapData[index]) {
+        this._mapData[index][1] = value;
+      } else {
+        index = this._mapData.push([
+          key,
+          value
+        ]) - 1;
+        setIndex(this, key, index);
+        if (__DEV__) {
+          this[SECRET_SIZE_PROP] += 1;
+        } else {
+          this.size += 1;
+        }
+      }
+
+      return this;
+    }
+
+    /**
+     * 23.1.3.6
+     * Gets a value associated with a key in the collection.
+     *
+     * @param {*} key
+     * @return {*}
+     */
+    get(key) {
+      var index = getIndex(this, key);
+      if (index == null) {
+        return undefined;
+      } else {
+        return this._mapData[index][1];
+      }
+    }
+
+
+    /**
+     * 23.1.3.3
+     * Delete a key/value from the collection.
+     *
+     * @param {*} key
+     * @return {boolean} Whether the key was found and deleted.
+     */
+    delete(key) {
+      var index = getIndex(this, key);
+      if (index != null && this._mapData[index]) {
+        setIndex(this, key, undefined);
+        this._mapData[index] = undefined;
+        if (__DEV__) {
+          this[SECRET_SIZE_PROP] -= 1;
+        } else {
+          this.size -= 1;
+        }
+        return true;
+      } else {
+        return false;
+      }
+    }
+
+    /**
+     * 23.1.3.4
+     * Returns an iterator over the key/value pairs (in the form of an Array) in
+     * the collection.
+     *
+     * @return {MapIterator}
+     */
+    entries() {
+      return new MapIterator(this, KIND_KEY_VALUE);
+    }
+
+    /**
+     * 23.1.3.8
+     * Returns an iterator over the keys in the collection.
+     *
+     * @return {MapIterator}
+     */
+    keys() {
+      return new MapIterator(this, KIND_KEY);
+    }
+
+    /**
+     * 23.1.3.11
+     * Returns an iterator over the values pairs in the collection.
+     *
+     * @return {MapIterator}
+     */
+    values() {
+      return new MapIterator(this, KIND_VALUE);
+    }
+
+    /**
+     * 23.1.3.5
+     * Iterates over the key/value pairs in the collection calling `callback`
+     * with [value, key, map]. An optional `thisArg` can be passed to set the
+     * context when `callback` is called.
+     *
+     * @param {function} callback
+     * @param {?object} thisArg
+     */
+    forEach(callback, thisArg) {
+      if (typeof callback !== 'function') {
+        throw new TypeError('Callback must be callable.');
+      }
+
+      var boundCallback = callback.bind(thisArg || undefined);
+      var mapData = this._mapData;
+
+      // Note that `mapData.length` should be computed on each iteration to
+      // support iterating over new items in the map that were added after the
+      // start of the iteration.
+      for (var i = 0; i < mapData.length; i++) {
+        var entry = mapData[i];
+        if (entry != null) {
+          boundCallback(entry[1], entry[0], this);
+        }
+      }
+    }
+  }
+
+  // 23.1.3.12
+  Map.prototype[toIterator.ITERATOR_SYMBOL] = Map.prototype.entries;
+
+  class MapIterator {
+
+    /**
+     * 23.1.5.1
+     * Create a `MapIterator` for a given `map`. While this class is private it
+     * will create objects that will be passed around publicily.
+     *
+     * @param {map} map
+     * @param {string} kind
+     */
+    constructor(map, kind) {
+      if (!(isObject(map) && map['_mapData'])) {
+        throw new TypeError('Object is not a map.');
+      }
+
+      if ([KIND_KEY, KIND_KEY_VALUE, KIND_VALUE].indexOf(kind) === -1) {
+        throw new Error('Invalid iteration kind.');
+      }
+
+      this._map = map;
+      this._nextIndex = 0;
+      this._kind = kind;
+    }
+
+    /**
+     * 23.1.5.2.1
+     * Get the next iteration.
+     *
+     * @return {object}
+     */
+    next() {
+      if (!this instanceof Map) {
+        throw new TypeError('Expected to be called on a MapIterator.');
+      }
+
+      var map = this._map;
+      var index = this._nextIndex;
+      var kind = this._kind;
+
+      if (map == null) {
+        return createIterResultObject(undefined, true);
+      }
+
+      var entries = map['_mapData'];
+
+      while (index < entries.length) {
+        var record = entries[index];
+
+        index += 1;
+        this._nextIndex = index;
+
+        if (record) {
+          if (kind === KIND_KEY) {
+            return createIterResultObject(record[0], false);
+          } else if (kind === KIND_VALUE) {
+            return createIterResultObject(record[1], false);
+          } else if (kind) {
+            return createIterResultObject(record, false);
+          }
+        }
+      }
+
+      this._map = undefined;
+
+      return createIterResultObject(undefined, true);
+    }
+  }
+
+  // We can put this in the class definition once we have computed props
+  // transform.
+  // 23.1.5.2.2
+  MapIterator.prototype[toIterator.ITERATOR_SYMBOL] = function() {
+    return this;
+  }
+
+  /**
+   * Helper Functions.
+   */
+
+  /**
+   * Return an index to map.[[MapData]] array for a given Key.
+   *
+   * @param {map} map
+   * @param {*} key
+   * @return {?number}
+   */
+  function getIndex(map, key) {
+    if (isObject(key)) {
+      var hash = getHash(key);
+      return map._objectIndex[hash];
+    } else {
+      var prefixedKey = KEY_PREFIX + key;
+      if (typeof key === 'string') {
+        return map._stringIndex[prefixedKey];
+      } else {
+        return map._otherIndex[prefixedKey];
+      }
+    }
+  }
+
+  /**
+   * Setup an index that refer to the key's location in map.[[MapData]].
+   *
+   * @param {map} map
+   * @param {*} key
+   */
+  function setIndex(map, key, index) {
+    var shouldDelete = index == null;
+
+    if (isObject(key)) {
+      var hash = getHash(key);
+      if (shouldDelete) {
+        delete map._objectIndex[hash];
+      } else {
+        map._objectIndex[hash] = index;
+      }
+    } else {
+      var prefixedKey = KEY_PREFIX + key;
+      if (typeof key === 'string') {
+        if (shouldDelete) {
+          delete map._stringIndex[prefixedKey];
+        } else {
+          map._stringIndex[prefixedKey] = index;
+        }
+      } else {
+        if (shouldDelete) {
+          delete map._otherIndex[prefixedKey];
+        } else {
+          map._otherIndex[prefixedKey] = index;
+        }
+      }
+    }
+  }
+
+  /**
+   * Instantiate a map with internal slots.
+   *
+   * @param {map} map
+   */
+  function initMap(map) {
+    // Data structure design inspired by Traceur's Map implementation.
+    // We maintain an internal array for all the entries. The array is needed
+    // to remember order. However, to have a reasonable HashMap performance
+    // i.e. O(1) for insertion, deletion, and retrieval. We maintain indices
+    // in objects for fast look ups. Indices are split up according to data
+    // types to avoid collisions.
+    map._mapData = [];
+
+    // Object index maps from an object "hash" to index. The hash being a unique
+    // property of our choosing that we associate with the object. Association
+    // is done by ways of keeping a non-enumerable property on the object.
+    // Ideally these would be `Object.create(null)` objects but since we're
+    // trying to support ES3 we'll have to gaurd against collisions using
+    // prefixes on the keys rather than rely on null prototype objects.
+    map._objectIndex = {};
+
+    // String index maps from strings to index.
+    map._stringIndex = {};
+
+    // Numbers, booleans, undefined, and null.
+    map._otherIndex = {};
+
+    // Unfortunately we have to support ES3 and cannot have `Map.prototype.size`
+    // be a getter method but just a regular method. The biggest problem with
+    // this is safety. Clients can change the size property easily and possibly
+    // without noticing (e.g. `if (map.size = 1) {..}` kind of typo). What we
+    // can do to mitigate use getters and setters in development to disallow
+    // and issue a warning for changing the `size` property.
+    if (__DEV__) {
+      if (isES5) {
+        // If the `SECRET_SIZE_PROP` property is already defined then we're not
+        // in the first call to `initMap` (e.g. coming from `map.clear()`) so
+        // all we need to do is reset the size without defining the properties.
+        if (map.hasOwnProperty(SECRET_SIZE_PROP)) {
+          map[SECRET_SIZE_PROP] = 0;
+        } else {
+          Object.defineProperty(map, SECRET_SIZE_PROP, {
+            value: 0,
+            writable: true
+          });
+          Object.defineProperty(map, 'size', {
+            set: (v) => {
+              console.error(
+                'PLEASE FIX ME: You are changing the map size property which ' +
+                'should not be writable and will break in production.'
+              );
+              throw new Error('The map size property is not writable.');
+            },
+            get: () => map[SECRET_SIZE_PROP]
+          });
+        }
+
+        // NOTE: Early return to implement immutable `.size` in DEV.
+        return;
+      }
+    }
+
+    // This is a diviation from the spec. `size` should be a getter on
+    // `Map.prototype`. However, we have to support IE8.
+    map.size = 0;
+  }
+
+  /**
+   * Check if something is an object.
+   *
+   * @param {*} o
+   * @return {boolean}
+   */
+  function isObject(o) {
+    return o != null && (typeof o === 'object' || typeof o === 'function');
+  }
+
+  /**
+   * Create an iteration object.
+   *
+   * @param {*} value
+   * @param {boolean} done
+   * @return {object}
+   */
+  function createIterResultObject(value, done) {
+    return {value, done};
+  }
+
+  // Are we in a legit ES5 environment. Spoiler alert: that doesn't include IE8.
+  var isES5 = (function() {
+    try {
+      Object.defineProperty({}, 'x', {});
+      return true;
+    } catch(e) {
+      return false;
+    }
+  })();
+
+  /**
+   * Check if an object can be extended.
+   *
+   * @param {object|array|function|regexp} o
+   * @return {boolean}
+   */
+  function isExtensible(o) {
+    if (!isES5) {
+      return true;
+    } else {
+      return Object.isExtensible(o);
+    }
+  }
+
+  /**
+   * IE has a `uniqueID` set on every DOM node. So we construct the hash from
+   * this uniqueID to avoid memory leaks and the IE cloneNode bug where it
+   * clones properties in addition to the attributes.
+   *
+   * @param {object} node
+   * @return {?string}
+   */
+  function getIENodeHash(node) {
+    var uniqueID;
+    switch (node.nodeType) {
+      case 1: // Element
+        uniqueID = node.uniqueID;
+        break;
+      case 9: // Document
+        uniqueID = node.documentElement.uniqueID;
+        break;
+      default:
+        return null;
+    }
+
+    if (uniqueID) {
+      return  OLD_IE_HASH_PREFIX + uniqueID;
+    } else {
+      return null;
+    }
+  }
+
+  var getHash = (function() {
+    var propIsEnumerable = Object.prototype.propertyIsEnumerable;
+    var hashProperty = guid();
+    var hashCounter = 0;
+
+    /**
+     * Get the "hash" associated with an object.
+     *
+     * @param {object|array|function|regexp} o
+     * @return {number}
+     */
+    return function getHash(o) {
+      if (o[hashProperty]) {
+        return o[hashProperty];
+      } else if (!isES5 &&
+                  o.propertyIsEnumerable &&
+                  o.propertyIsEnumerable[hashProperty]) {
+        return o.propertyIsEnumerable[hashProperty];
+      } else if (!isES5 &&
+                  isNode(o) &&
+                  getIENodeHash(o)) {
+        return getIENodeHash(o);
+      } else if (!isES5 && o[hashProperty]) {
+        return o[hashProperty];
+      }
+
+      if (isExtensible(o)) {
+        hashCounter += 1;
+        if (isES5) {
+          Object.defineProperty(o, hashProperty, {
+            enumerable: false,
+            writable: false,
+            configurable: false,
+            value: hashCounter
+          });
+        } else if (o.propertyIsEnumerable) {
+          // Since we can't define a non-enumerable property on the object
+          // we'll hijack one of the less-used non-enumerable properties to
+          // save our hash on it. Addiotionally, since this is a function it
+          // will not show up in `JSON.stringify` which is what we want.
+          o.propertyIsEnumerable = function() {
+            return propIsEnumerable.apply(this, arguments);
+          };
+          o.propertyIsEnumerable[hashProperty] = hashCounter;
+        } else if (isNode(o)) {
+          // At this point we couldn't get the IE `uniqueID` to use as a hash
+          // and we couldn't use a non-enumerable property to exploit the
+          // dontEnum bug so we simply add the `hashProperty` on the node
+          // itself.
+          o[hashProperty] = hashCounter;
+        } else {
+          throw new Error('Unable to set a non-enumerable property on object.');
+        }
+        return hashCounter;
+      } else {
+        throw new Error('Non-extensible objects are not allowed as keys.');
+      }
+    };
+  })();
+
+  return Map;
+})(/* jslint evil: true */ Function('return this')());
diff --git a/Libraries/vendor/core/isEmpty.js b/Libraries/vendor/core/isEmpty.js
new file mode 100644
index 000000000000..27f4c0069a06
--- /dev/null
+++ b/Libraries/vendor/core/isEmpty.js
@@ -0,0 +1,34 @@
+/**
+ * @generated SignedSource<<97ffcebc9ae390e734026a4f3964bff6>>
+ *
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * !! This file is a check-in of a static_upstream project!      !!
+ * !!                                                            !!
+ * !! You should not modify this file directly. Instead:         !!
+ * !! 1) Use `fjs use-upstream` to temporarily replace this with !!
+ * !!    the latest version from upstream.                       !!
+ * !! 2) Make your changes, test them, etc.                      !!
+ * !! 3) Use `fjs push-upstream` to copy your changes back to    !!
+ * !!    static_upstream.                                        !!
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ *
+ * @providesModule isEmpty
+ */
+
+/**
+ * Mimics empty from PHP.
+ */
+function isEmpty(obj) {
+  if (Array.isArray(obj)) {
+    return obj.length === 0;
+  } else if (typeof obj === 'object') {
+    for (var i in obj) {
+      return false;
+    }
+    return true;
+  } else {
+    return !obj;
+  }
+}
+
+module.exports = isEmpty;
diff --git a/Libraries/vendor/crypto/crc32.js b/Libraries/vendor/crypto/crc32.js
new file mode 100644
index 000000000000..540d60aa832b
--- /dev/null
+++ b/Libraries/vendor/crypto/crc32.js
@@ -0,0 +1,92 @@
+/**
+ * @generated SignedSource<<77bdeb858138636c96c405d64b6be55c>>
+ *
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * !! This file is a check-in of a static_upstream project!      !!
+ * !!                                                            !!
+ * !! You should not modify this file directly. Instead:         !!
+ * !! 1) Use `fjs use-upstream` to temporarily replace this with !!
+ * !!    the latest version from upstream.                       !!
+ * !! 2) Make your changes, test them, etc.                      !!
+ * !! 3) Use `fjs push-upstream` to copy your changes back to    !!
+ * !!    static_upstream.                                        !!
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ *
+ * Copyright 2004-present Facebook. All Rights Reserved.
+ *
+ * @providesModule crc32
+ */
+
+/* jslint bitwise: true */
+
+/**
+ * Modified from the original for performance improvements.
+ *
+ * @see http://create.stephan-brumme.com/crc32/
+ * @see http://stackoverflow.com/questions/18638900/
+ * @copyright 2006 Andrea Ercolino
+ * @license MIT
+ */
+
+var table = [
+  0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
+  0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
+  0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
+  0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+  0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
+  0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
+  0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
+  0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+  0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
+  0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
+  0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
+  0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+  0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
+  0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
+  0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
+  0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+  0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
+  0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
+  0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
+  0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+  0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
+  0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
+  0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
+  0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+  0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
+  0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
+  0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
+  0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+  0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
+  0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
+  0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
+  0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+  0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
+  0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
+  0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
+  0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+  0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
+  0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
+  0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
+  0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+  0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
+  0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
+  0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+];
+
+if (global.Int32Array !== undefined) {
+  table = new Int32Array(table);
+}
+
+/**
+ * @returns Number
+ */
+function crc32(str) {
+  var crc = -1;
+  for (var i = 0, len = str.length; i < len; i++) {
+    crc = (crc >>> 8) ^ table[(crc ^ str.charCodeAt(i)) & 0xFF];
+  }
+  return ~crc;
+}
+
+module.exports = crc32;
diff --git a/Libraries/vendor/fbjs/CSSCore.js b/Libraries/vendor/fbjs/CSSCore.js
deleted file mode 100644
index 70f72f7677a6..000000000000
--- a/Libraries/vendor/fbjs/CSSCore.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 CSSCore
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/CSSCore');
diff --git a/Libraries/vendor/fbjs/Deferred.js b/Libraries/vendor/fbjs/Deferred.js
deleted file mode 100644
index 88704b83901a..000000000000
--- a/Libraries/vendor/fbjs/Deferred.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 Deferred
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/Deferred');
diff --git a/Libraries/vendor/fbjs/EventListener.js b/Libraries/vendor/fbjs/EventListener.js
deleted file mode 100644
index ec6041de37df..000000000000
--- a/Libraries/vendor/fbjs/EventListener.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 EventListener
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/EventListener');
diff --git a/Libraries/vendor/fbjs/Map.js b/Libraries/vendor/fbjs/Map.js
deleted file mode 100644
index 4fd97503ba8b..000000000000
--- a/Libraries/vendor/fbjs/Map.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 Map
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/Map');
diff --git a/Libraries/vendor/fbjs/PromiseMap.js b/Libraries/vendor/fbjs/PromiseMap.js
deleted file mode 100644
index 30891f521c75..000000000000
--- a/Libraries/vendor/fbjs/PromiseMap.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 PromiseMap
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/PromiseMap');
diff --git a/Libraries/vendor/fbjs/TouchEventUtils.js b/Libraries/vendor/fbjs/TouchEventUtils.js
deleted file mode 100644
index f75be6944164..000000000000
--- a/Libraries/vendor/fbjs/TouchEventUtils.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 TouchEventUtils
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/TouchEventUtils');
diff --git a/Libraries/vendor/fbjs/URI.js b/Libraries/vendor/fbjs/URI.js
deleted file mode 100644
index 72c5650012cf..000000000000
--- a/Libraries/vendor/fbjs/URI.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 URI
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/URI');
diff --git a/Libraries/vendor/fbjs/UserAgent.js b/Libraries/vendor/fbjs/UserAgent.js
deleted file mode 100644
index 85c2669b8c1a..000000000000
--- a/Libraries/vendor/fbjs/UserAgent.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 UserAgent
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/UserAgent');
diff --git a/Libraries/vendor/fbjs/UserAgentData.js b/Libraries/vendor/fbjs/UserAgentData.js
deleted file mode 100644
index 13ff6a335caf..000000000000
--- a/Libraries/vendor/fbjs/UserAgentData.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 UserAgentData
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/UserAgentData');
diff --git a/Libraries/vendor/fbjs/VersionRange.js b/Libraries/vendor/fbjs/VersionRange.js
deleted file mode 100644
index de55fe18928d..000000000000
--- a/Libraries/vendor/fbjs/VersionRange.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 VersionRange
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/VersionRange');
diff --git a/Libraries/vendor/fbjs/areEqual.js b/Libraries/vendor/fbjs/areEqual.js
deleted file mode 100644
index 8c020878a20a..000000000000
--- a/Libraries/vendor/fbjs/areEqual.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 areEqual
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/areEqual');
diff --git a/Libraries/vendor/fbjs/base62.js b/Libraries/vendor/fbjs/base62.js
deleted file mode 100644
index 596b871dcbf6..000000000000
--- a/Libraries/vendor/fbjs/base62.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 base62
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/base62');
diff --git a/Libraries/vendor/fbjs/camelize.js b/Libraries/vendor/fbjs/camelize.js
deleted file mode 100644
index 356cfefaad1c..000000000000
--- a/Libraries/vendor/fbjs/camelize.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 camelize
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/camelize');
diff --git a/Libraries/vendor/fbjs/camelizeStyleName.js b/Libraries/vendor/fbjs/camelizeStyleName.js
deleted file mode 100644
index a92ed2c104d9..000000000000
--- a/Libraries/vendor/fbjs/camelizeStyleName.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 camelizeStyleName
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/camelizeStyleName');
diff --git a/Libraries/vendor/fbjs/containsNode.js b/Libraries/vendor/fbjs/containsNode.js
deleted file mode 100644
index 67d65e4f4a74..000000000000
--- a/Libraries/vendor/fbjs/containsNode.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 containsNode
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/containsNode');
diff --git a/Libraries/vendor/fbjs/crc32.js b/Libraries/vendor/fbjs/crc32.js
deleted file mode 100644
index cb4fba1a2012..000000000000
--- a/Libraries/vendor/fbjs/crc32.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 crc32
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/crc32');
diff --git a/Libraries/vendor/fbjs/createArrayFromMixed.js b/Libraries/vendor/fbjs/createArrayFromMixed.js
deleted file mode 100644
index 6489c47746cd..000000000000
--- a/Libraries/vendor/fbjs/createArrayFromMixed.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 createArrayFromMixed
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/createArrayFromMixed');
diff --git a/Libraries/vendor/fbjs/createNodesFromMarkup.js b/Libraries/vendor/fbjs/createNodesFromMarkup.js
deleted file mode 100644
index fb5899c0ff3d..000000000000
--- a/Libraries/vendor/fbjs/createNodesFromMarkup.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 createNodesFromMarkup
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/createNodesFromMarkup');
diff --git a/Libraries/vendor/fbjs/emptyFunction.js b/Libraries/vendor/fbjs/emptyFunction.js
deleted file mode 100644
index ac55c276a163..000000000000
--- a/Libraries/vendor/fbjs/emptyFunction.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 emptyFunction
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/emptyFunction');
diff --git a/Libraries/vendor/fbjs/emptyObject.js b/Libraries/vendor/fbjs/emptyObject.js
deleted file mode 100644
index f738081cc0d0..000000000000
--- a/Libraries/vendor/fbjs/emptyObject.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 emptyObject
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/emptyObject');
diff --git a/Libraries/vendor/fbjs/everyObject.js b/Libraries/vendor/fbjs/everyObject.js
deleted file mode 100644
index 4fe49e035ad7..000000000000
--- a/Libraries/vendor/fbjs/everyObject.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 everyObject
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/everyObject');
diff --git a/Libraries/vendor/fbjs/fetchWithRetries.js b/Libraries/vendor/fbjs/fetchWithRetries.js
deleted file mode 100644
index 16d1e1aa98eb..000000000000
--- a/Libraries/vendor/fbjs/fetchWithRetries.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 fetchWithRetries
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/fetchWithRetries');
diff --git a/Libraries/vendor/fbjs/filterObject.js b/Libraries/vendor/fbjs/filterObject.js
deleted file mode 100644
index 819e188e4bf5..000000000000
--- a/Libraries/vendor/fbjs/filterObject.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 filterObject
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/filterObject');
diff --git a/Libraries/vendor/fbjs/flattenArray.js b/Libraries/vendor/fbjs/flattenArray.js
deleted file mode 100644
index 14f12d6a41ff..000000000000
--- a/Libraries/vendor/fbjs/flattenArray.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 flattenArray
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/flattenArray');
diff --git a/Libraries/vendor/fbjs/focusNode.js b/Libraries/vendor/fbjs/focusNode.js
deleted file mode 100644
index 91df968db9e0..000000000000
--- a/Libraries/vendor/fbjs/focusNode.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 focusNode
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/focusNode');
diff --git a/Libraries/vendor/fbjs/forEachObject.js b/Libraries/vendor/fbjs/forEachObject.js
deleted file mode 100644
index 1e5b39f29f29..000000000000
--- a/Libraries/vendor/fbjs/forEachObject.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 forEachObject
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/forEachObject');
diff --git a/Libraries/vendor/fbjs/getActiveElement.js b/Libraries/vendor/fbjs/getActiveElement.js
deleted file mode 100644
index cb597c5a2783..000000000000
--- a/Libraries/vendor/fbjs/getActiveElement.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 getActiveElement
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/getActiveElement');
diff --git a/Libraries/vendor/fbjs/getMarkupWrap.js b/Libraries/vendor/fbjs/getMarkupWrap.js
deleted file mode 100644
index 8673d4630225..000000000000
--- a/Libraries/vendor/fbjs/getMarkupWrap.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 getMarkupWrap
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/getMarkupWrap');
diff --git a/Libraries/vendor/fbjs/getUnboundedScrollPosition.js b/Libraries/vendor/fbjs/getUnboundedScrollPosition.js
deleted file mode 100644
index a72586ef4063..000000000000
--- a/Libraries/vendor/fbjs/getUnboundedScrollPosition.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 getUnboundedScrollPosition
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/getUnboundedScrollPosition');
diff --git a/Libraries/vendor/fbjs/hyphenate.js b/Libraries/vendor/fbjs/hyphenate.js
deleted file mode 100644
index 00cec2c76b63..000000000000
--- a/Libraries/vendor/fbjs/hyphenate.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 hyphenate
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/hyphenate');
diff --git a/Libraries/vendor/fbjs/hyphenateStyleName.js b/Libraries/vendor/fbjs/hyphenateStyleName.js
deleted file mode 100644
index b1349ea097d1..000000000000
--- a/Libraries/vendor/fbjs/hyphenateStyleName.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 hyphenateStyleName
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/hyphenateStyleName');
diff --git a/Libraries/vendor/fbjs/invariant.js b/Libraries/vendor/fbjs/invariant.js
deleted file mode 100644
index 1a19702441d8..000000000000
--- a/Libraries/vendor/fbjs/invariant.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 invariant
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/invariant');
diff --git a/Libraries/vendor/fbjs/isEmpty.js b/Libraries/vendor/fbjs/isEmpty.js
deleted file mode 100644
index 3d9ae58e99ec..000000000000
--- a/Libraries/vendor/fbjs/isEmpty.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 isEmpty
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/isEmpty');
diff --git a/Libraries/vendor/fbjs/isNode.js b/Libraries/vendor/fbjs/isNode.js
deleted file mode 100644
index d99b32dad507..000000000000
--- a/Libraries/vendor/fbjs/isNode.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 isNode
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/isNode');
diff --git a/Libraries/vendor/fbjs/isTextNode.js b/Libraries/vendor/fbjs/isTextNode.js
deleted file mode 100644
index 7b39b169863c..000000000000
--- a/Libraries/vendor/fbjs/isTextNode.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 isTextNode
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/isTextNode');
diff --git a/Libraries/vendor/fbjs/joinClasses.js b/Libraries/vendor/fbjs/joinClasses.js
deleted file mode 100644
index 8e7908a9d0d1..000000000000
--- a/Libraries/vendor/fbjs/joinClasses.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 joinClasses
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/joinClasses');
diff --git a/Libraries/vendor/fbjs/keyMirror.js b/Libraries/vendor/fbjs/keyMirror.js
deleted file mode 100644
index 021b3405206c..000000000000
--- a/Libraries/vendor/fbjs/keyMirror.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 keyMirror
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/keyMirror');
diff --git a/Libraries/vendor/fbjs/keyOf.js b/Libraries/vendor/fbjs/keyOf.js
deleted file mode 100644
index 646040a57186..000000000000
--- a/Libraries/vendor/fbjs/keyOf.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 keyOf
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/keyOf');
diff --git a/Libraries/vendor/fbjs/mapObject.js b/Libraries/vendor/fbjs/mapObject.js
deleted file mode 100644
index a74e35737cc1..000000000000
--- a/Libraries/vendor/fbjs/mapObject.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 mapObject
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/mapObject');
diff --git a/Libraries/vendor/fbjs/memoizeStringOnly.js b/Libraries/vendor/fbjs/memoizeStringOnly.js
deleted file mode 100644
index 36d4d31458f9..000000000000
--- a/Libraries/vendor/fbjs/memoizeStringOnly.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 memoizeStringOnly
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/memoizeStringOnly');
diff --git a/Libraries/vendor/fbjs/monitorCodeUse.js b/Libraries/vendor/fbjs/monitorCodeUse.js
deleted file mode 100644
index c06614c17d2b..000000000000
--- a/Libraries/vendor/fbjs/monitorCodeUse.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 monitorCodeUse
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/monitorCodeUse');
diff --git a/Libraries/vendor/fbjs/nativeRequestAnimationFrame.js b/Libraries/vendor/fbjs/nativeRequestAnimationFrame.js
deleted file mode 100644
index 5ff2ba2a85be..000000000000
--- a/Libraries/vendor/fbjs/nativeRequestAnimationFrame.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 nativeRequestAnimationFrame
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/nativeRequestAnimationFrame');
diff --git a/Libraries/vendor/fbjs/nullthrows.js b/Libraries/vendor/fbjs/nullthrows.js
deleted file mode 100644
index 5de73280dbf0..000000000000
--- a/Libraries/vendor/fbjs/nullthrows.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 nullthrows
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/nullthrows');
diff --git a/Libraries/vendor/fbjs/performance.js b/Libraries/vendor/fbjs/performance.js
deleted file mode 100644
index eab35d18d69e..000000000000
--- a/Libraries/vendor/fbjs/performance.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 performance
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/performance');
diff --git a/Libraries/vendor/fbjs/performanceNow.js b/Libraries/vendor/fbjs/performanceNow.js
deleted file mode 100644
index fa0c50535c11..000000000000
--- a/Libraries/vendor/fbjs/performanceNow.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 performanceNow
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/performanceNow');
diff --git a/Libraries/vendor/fbjs/removeFromArray.js b/Libraries/vendor/fbjs/removeFromArray.js
deleted file mode 100644
index 0af09ec36792..000000000000
--- a/Libraries/vendor/fbjs/removeFromArray.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 removeFromArray
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/removeFromArray');
diff --git a/Libraries/vendor/fbjs/requestAnimationFrame.js b/Libraries/vendor/fbjs/requestAnimationFrame.js
deleted file mode 100644
index 1671e27ef1f2..000000000000
--- a/Libraries/vendor/fbjs/requestAnimationFrame.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 requestAnimationFrame
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/requestAnimationFrame');
diff --git a/Libraries/vendor/fbjs/resolveImmediate.js b/Libraries/vendor/fbjs/resolveImmediate.js
deleted file mode 100644
index e587c24dada3..000000000000
--- a/Libraries/vendor/fbjs/resolveImmediate.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 resolveImmediate
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/resolveImmediate');
diff --git a/Libraries/vendor/fbjs/shallowEqual.js b/Libraries/vendor/fbjs/shallowEqual.js
deleted file mode 100644
index 065a3e682002..000000000000
--- a/Libraries/vendor/fbjs/shallowEqual.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 shallowEqual
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/shallowEqual');
diff --git a/Libraries/vendor/fbjs/someObject.js b/Libraries/vendor/fbjs/someObject.js
deleted file mode 100644
index edd2cdd7b1d7..000000000000
--- a/Libraries/vendor/fbjs/someObject.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 someObject
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/someObject');
diff --git a/Libraries/vendor/fbjs/sprintf.js b/Libraries/vendor/fbjs/sprintf.js
deleted file mode 100644
index f4140fc06400..000000000000
--- a/Libraries/vendor/fbjs/sprintf.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 sprintf
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/sprintf');
diff --git a/Libraries/vendor/fbjs/warning.js b/Libraries/vendor/fbjs/warning.js
deleted file mode 100644
index 7ae0cdf81b8e..000000000000
--- a/Libraries/vendor/fbjs/warning.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 warning
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/warning');
diff --git a/Libraries/vendor/fbjs/xhrSimpleDataSerializer.js b/Libraries/vendor/fbjs/xhrSimpleDataSerializer.js
deleted file mode 100644
index d0d9b2c60c52..000000000000
--- a/Libraries/vendor/fbjs/xhrSimpleDataSerializer.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 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 xhrSimpleDataSerializer
- * @flow
- */
-'use strict';
-
-module.exports = require('fbjs/lib/xhrSimpleDataSerializer');
diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index 9826948e1dca..dc7c0be87142 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -142,15 +142,15 @@
           "from": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz",
           "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
         },
-        "regenerator": {
-          "version": "0.8.40",
-          "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
-          "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
-        },
         "recast": {
           "version": "0.10.33",
           "from": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz",
           "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
+        },
+        "regenerator": {
+          "version": "0.8.40",
+          "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
+          "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
         }
       }
     },
@@ -1815,21 +1815,19 @@
       "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.1.0.tgz"
     },
     "fbjs": {
-      "version": "0.7.2",
-      "from": "fbjs@0.7.2",
-      "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.7.2.tgz",
+      "version": "0.6.0",
+      "from": "https://registry.npmjs.org/fbjs/-/fbjs-0.6.0.tgz",
+      "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.6.0.tgz",
       "dependencies": {
-        "isomorphic-fetch": {
-          "version": "2.2.1",
-          "from": "isomorphic-fetch@>=2.1.1 <3.0.0",
-          "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
-          "dependencies": {
-            "whatwg-fetch": {
-              "version": "0.11.0",
-              "from": "whatwg-fetch@>=0.10.0",
-              "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.11.0.tgz"
-            }
-          }
+        "ua-parser-js": {
+          "version": "0.7.10",
+          "from": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.10.tgz",
+          "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.10.tgz"
+        },
+        "whatwg-fetch": {
+          "version": "0.9.0",
+          "from": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz",
+          "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz"
         }
       }
     },
@@ -1917,16 +1915,16 @@
           "from": "are-we-there-yet@~1.0.0",
           "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.4.tgz"
         },
-        "assert-plus": {
-          "version": "0.1.5",
-          "from": "assert-plus@^0.1.5",
-          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
-        },
         "asn1": {
           "version": "0.1.11",
           "from": "asn1@0.1.11",
           "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
         },
+        "assert-plus": {
+          "version": "0.1.5",
+          "from": "assert-plus@^0.1.5",
+          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
+        },
         "async": {
           "version": "1.5.0",
           "from": "async@^1.4.0",
@@ -1952,11 +1950,6 @@
           "from": "boom@^2.8.x",
           "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz"
         },
-        "caseless": {
-          "version": "0.11.0",
-          "from": "caseless@~0.11.0",
-          "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
-        },
         "brace-expansion": {
           "version": "1.1.1",
           "from": "brace-expansion@>=1.0.0 <2.0.0",
@@ -1967,6 +1960,11 @@
           "from": "chalk@^1.1.1",
           "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz"
         },
+        "caseless": {
+          "version": "0.11.0",
+          "from": "caseless@~0.11.0",
+          "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
+        },
         "combined-stream": {
           "version": "1.0.5",
           "from": "combined-stream@~1.0.5",
@@ -2067,36 +2065,36 @@
           "from": "graceful-readlink@>= 1.0.0",
           "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
         },
-        "har-validator": {
-          "version": "2.0.2",
-          "from": "har-validator@~2.0.2",
-          "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.2.tgz"
-        },
         "has-ansi": {
           "version": "2.0.0",
           "from": "has-ansi@^2.0.0",
           "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
         },
-        "hawk": {
-          "version": "3.1.0",
-          "from": "hawk@~3.1.0",
-          "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.0.tgz"
+        "har-validator": {
+          "version": "2.0.2",
+          "from": "har-validator@~2.0.2",
+          "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.2.tgz"
         },
         "has-unicode": {
           "version": "1.0.1",
           "from": "has-unicode@^1.0.0",
           "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-1.0.1.tgz"
         },
-        "http-signature": {
-          "version": "0.11.0",
-          "from": "http-signature@~0.11.0",
-          "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.11.0.tgz"
+        "hawk": {
+          "version": "3.1.0",
+          "from": "hawk@~3.1.0",
+          "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.0.tgz"
         },
         "hoek": {
           "version": "2.16.3",
           "from": "hoek@2.x.x",
           "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz"
         },
+        "http-signature": {
+          "version": "0.11.0",
+          "from": "http-signature@~0.11.0",
+          "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.11.0.tgz"
+        },
         "inherits": {
           "version": "2.0.1",
           "from": "inherits@*",
@@ -2122,31 +2120,31 @@
           "from": "isarray@0.0.1",
           "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
         },
-        "json-stringify-safe": {
-          "version": "5.0.1",
-          "from": "json-stringify-safe@~5.0.1",
-          "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
-        },
         "isstream": {
           "version": "0.1.2",
           "from": "isstream@~0.1.2",
           "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
         },
+        "json-stringify-safe": {
+          "version": "5.0.1",
+          "from": "json-stringify-safe@~5.0.1",
+          "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
+        },
         "jsonpointer": {
           "version": "2.0.0",
           "from": "jsonpointer@2.0.0",
           "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
         },
-        "lodash._createpadding": {
-          "version": "3.6.1",
-          "from": "lodash._createpadding@^3.0.0",
-          "resolved": "https://registry.npmjs.org/lodash._createpadding/-/lodash._createpadding-3.6.1.tgz"
-        },
         "lodash._basetostring": {
           "version": "3.0.1",
           "from": "lodash._basetostring@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz"
         },
+        "lodash._createpadding": {
+          "version": "3.6.1",
+          "from": "lodash._createpadding@^3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash._createpadding/-/lodash._createpadding-3.6.1.tgz"
+        },
         "lodash.pad": {
           "version": "3.1.1",
           "from": "lodash.pad@^3.0.0",
@@ -2212,16 +2210,16 @@
           "from": "path-is-absolute@>=1.0.0 <2.0.0",
           "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz"
         },
-        "pinkie-promise": {
-          "version": "1.0.0",
-          "from": "pinkie-promise@^1.0.0",
-          "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz"
-        },
         "pinkie": {
           "version": "1.0.0",
           "from": "pinkie@^1.0.0",
           "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
         },
+        "pinkie-promise": {
+          "version": "1.0.0",
+          "from": "pinkie-promise@^1.0.0",
+          "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz"
+        },
         "qs": {
           "version": "5.2.0",
           "from": "qs@~5.2.0",
@@ -2237,16 +2235,16 @@
           "from": "request@2.x",
           "resolved": "https://registry.npmjs.org/request/-/request-2.65.0.tgz"
         },
-        "semver": {
-          "version": "5.0.3",
-          "from": "semver@~5.0.1",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
-        },
         "sntp": {
           "version": "1.0.9",
           "from": "sntp@1.x.x",
           "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
         },
+        "semver": {
+          "version": "5.0.3",
+          "from": "semver@~5.0.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
+        },
         "string_decoder": {
           "version": "0.10.31",
           "from": "string_decoder@~0.10.x",
@@ -2257,16 +2255,21 @@
           "from": "stringstream@~0.0.4",
           "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
         },
-        "strip-json-comments": {
-          "version": "0.1.3",
-          "from": "strip-json-comments@0.1.x",
-          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
-        },
         "strip-ansi": {
           "version": "3.0.0",
           "from": "strip-ansi@^3.0.0",
           "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz"
         },
+        "supports-color": {
+          "version": "2.0.0",
+          "from": "supports-color@^2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
+        },
+        "strip-json-comments": {
+          "version": "0.1.3",
+          "from": "strip-json-comments@0.1.x",
+          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
+        },
         "tar": {
           "version": "2.2.1",
           "from": "tar@~2.2.0",
@@ -2277,11 +2280,6 @@
           "from": "tough-cookie@~2.2.0",
           "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.0.tgz"
         },
-        "supports-color": {
-          "version": "2.0.0",
-          "from": "supports-color@^2.0.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
-        },
         "tunnel-agent": {
           "version": "0.4.1",
           "from": "tunnel-agent@~0.4.1",
@@ -2346,15 +2344,15 @@
               "from": "glob@>=5.0.14 <6.0.0",
               "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz"
             },
-            "once": {
-              "version": "1.3.2",
-              "from": "once@>=1.3.0 <2.0.0",
-              "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz"
-            },
             "minimatch": {
               "version": "3.0.0",
               "from": "minimatch@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0",
               "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.0.tgz"
+            },
+            "once": {
+              "version": "1.3.2",
+              "from": "once@>=1.3.0 <2.0.0",
+              "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz"
             }
           }
         },
@@ -4060,18 +4058,6 @@
               }
             }
           }
-        },
-        "fbjs": {
-          "version": "0.6.1",
-          "from": "fbjs@>=0.6.0 <0.7.0",
-          "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.6.1.tgz",
-          "dependencies": {
-            "whatwg-fetch": {
-              "version": "0.9.0",
-              "from": "whatwg-fetch@>=0.9.0 <0.10.0",
-              "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz"
-            }
-          }
         }
       }
     },
@@ -4558,11 +4544,6 @@
       "from": "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz",
       "resolved": "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz"
     },
-    "ua-parser-js": {
-      "version": "0.7.10",
-      "from": "ua-parser-js@>=0.7.9 <0.8.0",
-      "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.10.tgz"
-    },
     "uglify-js": {
       "version": "2.4.24",
       "from": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.4.24.tgz",
diff --git a/package.json b/package.json
index eb0789b0164e..8e606d2fc6b5 100644
--- a/package.json
+++ b/package.json
@@ -75,8 +75,7 @@
     ],
     "unmockedModulePathPatterns": [
       "promise",
-      "source-map",
-      "fbjs"
+      "source-map"
     ]
   },
   "main": "Libraries/react-native/react-native.js",
@@ -122,7 +121,7 @@
     "connect": "^2.8.3",
     "debug": "^2.2.0",
     "event-target-shim": "^1.0.5",
-    "fbjs": "^0.7.2",
+    "fbjs": "^0.6.0",
     "fbjs-scripts": "^0.4.0",
     "graceful-fs": "^4.1.2",
     "image-size": "^0.3.5",
diff --git a/packager/blacklist.js b/packager/blacklist.js
index 318e09e88ee8..ee369e1af726 100644
--- a/packager/blacklist.js
+++ b/packager/blacklist.js
@@ -17,6 +17,36 @@ var sharedBlacklist = [
   'node_modules/react/lib/React.js',
   'node_modules/react/lib/ReactDOM.js',
 
+  // For each of these fbjs files (especially the non-forks/stubs), we should
+  // consider deleting the conflicting copy and just using the fbjs version.
+  //
+  // fbjs forks:
+  'node_modules/fbjs/lib/Map.js',
+  'node_modules/fbjs/lib/Promise.js',
+  'node_modules/fbjs/lib/fetch.js',
+  // fbjs stubs:
+  'node_modules/fbjs/lib/ErrorUtils.js',
+  'node_modules/fbjs/lib/URI.js',
+  // fbjs modules:
+  'node_modules/fbjs/lib/Deferred.js',
+  'node_modules/fbjs/lib/PromiseMap.js',
+  'node_modules/fbjs/lib/UserAgent.js',
+  'node_modules/fbjs/lib/areEqual.js',
+  'node_modules/fbjs/lib/base62.js',
+  'node_modules/fbjs/lib/crc32.js',
+  'node_modules/fbjs/lib/everyObject.js',
+  'node_modules/fbjs/lib/fetchWithRetries.js',
+  'node_modules/fbjs/lib/filterObject.js',
+  'node_modules/fbjs/lib/flattenArray.js',
+  'node_modules/fbjs/lib/forEachObject.js',
+  'node_modules/fbjs/lib/isEmpty.js',
+  'node_modules/fbjs/lib/nullthrows.js',
+  'node_modules/fbjs/lib/removeFromArray.js',
+  'node_modules/fbjs/lib/resolveImmediate.js',
+  'node_modules/fbjs/lib/someObject.js',
+  'node_modules/fbjs/lib/sprintf.js',
+  'node_modules/fbjs/lib/xhrSimpleDataSerializer.js',
+
   // Those conflicts with the ones in fbjs/. We need to blacklist the
   // internal version otherwise they won't work in open source.
   'downstream/core/CSSCore.js',
diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index 10e138c8b961..a677c2199da8 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -85,6 +85,7 @@ class Resolver {
           (opts.blacklistRE && opts.blacklistRE.test(filepath));
       },
       providesModuleNodeModules: [
+        'fbjs',
         'react',
         'react-native',
         // Parse requires AsyncStorage. They will

From 0b89b18b1bd85307110ae073ae0a291d9a534e0c Mon Sep 17 00:00:00 2001
From: Felix Oghina <foghina@fb.com>
Date: Thu, 11 Feb 2016 04:36:16 -0800
Subject: [PATCH 1126/1411] format exceptions correctly when crashing

Reviewed By: ivank

Differential Revision: D2921881

fb-gh-sync-id: bd35ada33c752877dd3f6274ed8d4b4b7c851b9a
shipit-source-id: bd35ada33c752877dd3f6274ed8d4b4b7c851b9a
---
 .../modules/core/ExceptionsManagerModule.java | 22 ++++++++++---------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/ExceptionsManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/core/ExceptionsManagerModule.java
index 876a2fca2c5d..ca12dd6c57d7 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/core/ExceptionsManagerModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/core/ExceptionsManagerModule.java
@@ -16,6 +16,7 @@
 import com.facebook.react.bridge.ReactMethod;
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.ReadableType;
 import com.facebook.react.devsupport.DevSupportManager;
 import com.facebook.react.common.ReactConstants;
 
@@ -32,16 +33,17 @@ public String getName() {
     return "RKExceptionsManager";
   }
 
-  private String stackTraceToString(ReadableArray stack) {
-    StringBuilder stringBuilder = new StringBuilder();
+  private String stackTraceToString(String message, ReadableArray stack) {
+    StringBuilder stringBuilder = new StringBuilder(message).append(", stack:\n");
     for (int i = 0; i < stack.size(); i++) {
       ReadableMap frame = stack.getMap(i);
-      stringBuilder.append(frame.getString("methodName"));
-      stringBuilder.append("\n    ");
-      stringBuilder.append(new File(frame.getString("file")).getName());
-      stringBuilder.append(":");
-      stringBuilder.append(frame.getInt("lineNumber"));
-      if (frame.hasKey("column") && !frame.isNull("column")) {
+      stringBuilder
+          .append(frame.getString("methodName"))
+          .append("@")
+          .append(frame.getInt("lineNumber"));
+      if (frame.hasKey("column") &&
+          !frame.isNull("column") &&
+          frame.getType("column") == ReadableType.Number) {
         stringBuilder
             .append(":")
             .append(frame.getInt("column"));
@@ -58,14 +60,14 @@ public void reportFatalException(String title, ReadableArray details, int except
 
   @ReactMethod
   public void reportSoftException(String title, ReadableArray details, int exceptionId) {
-    FLog.e(ReactConstants.TAG, title + "\n" + stackTraceToString(details));
+    FLog.e(ReactConstants.TAG, stackTraceToString(title, details));
   }
 
   private void showOrThrowError(String title, ReadableArray details, int exceptionId) {
     if (mDevSupportManager.getDevSupportEnabled()) {
       mDevSupportManager.showNewJSError(title, details, exceptionId);
     } else {
-      throw new JavascriptException(stackTraceToString(details));
+      throw new JavascriptException(stackTraceToString(title, details));
     }
   }
 

From 6f1417c84982e0705912b57bf9d1aaaf1476d7d9 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Thu, 11 Feb 2016 06:16:34 -0800
Subject: [PATCH 1127/1411] CI now builds docs website and deploys it to
 /%version% path

Summary:
Copy of #5760 reverted merge.

We need to preserve history of docs changes on the webserver.
The goal is to allow users to browse outdated versions of docs.
To make things simple all websites will be released to https://facebook.github.io/react-native/releases/version/XX folder when there is a branch cut.

I switched from Travis CI to Cirle CI because it works faster and I am more familiar with it.

How it works:

1. If code is pushed to `master` branch then CI will build a fresh version of docs and put it in https://github.com/facebook/react-native/tree/gh-pages/releases/next folder.
Github will serve this website from https://facebook.github.io/react-native/releases/version/next URL.
All relative URLs will work within that website

2. If code is pushed to `0.20-stable` branch then CI will build a fresh version of docs and put it in https://github.com/facebook/react-native/tree/gh-pages/releases/0.20 folder.
Github will serve this website from https://facebook.github.io/react-native/releases/v
Closes https://github.com/facebook/react-native/pull/5873

Reviewed By: svcscm

Differential Revision: D2926901

Pulled By: androidtrunkagent

fb-gh-sync-id: 16aea430bac815933d9c603f03921cc6353906f1
shipit-source-id: 16aea430bac815933d9c603f03921cc6353906f1
---
 .travis.yml                                   | 20 +---
 .../Animated/src/AnimatedImplementation.js    |  2 +-
 Libraries/Components/ScrollView/ScrollView.js |  2 +-
 .../PushNotificationIOS.js                    |  2 +-
 Libraries/ReactIOS/NativeMethodsMixin.js      |  6 +-
 Libraries/Utilities/AlertIOS.js               |  2 +-
 .../browser/eventPlugins/PanResponder.js      |  2 +-
 circle.yml                                    | 16 +++
 docs/AndroidUIPerformance.md                  | 24 ++---
 docs/Animations.md                            | 18 ++--
 docs/CommunicationIOS.md                      | 12 +--
 docs/DevelopmentSetupAndroid.md               |  4 +-
 docs/DirectManipulation.md                    |  2 +-
 docs/EmbeddedAppAndroid.md                    |  2 +-
 docs/EmbeddedAppIOS.md                        |  4 +-
 docs/GestureResponderSystem.md                |  2 +-
 docs/GettingStarted.md                        |  8 +-
 docs/Images.md                                |  2 +-
 docs/KnownIssues.md                           |  4 +-
 docs/LinkingLibraries.md                      |  6 +-
 docs/NavigatorComparison.md                   |  4 +-
 docs/Performance.md                           |  2 +-
 docs/RunningOnDeviceIOS.md                    |  2 +-
 docs/SignedAPKAndroid.md                      |  2 +-
 docs/Style.md                                 | 12 +--
 docs/Troubleshooting.md                       |  2 +-
 docs/Tutorial.md                              | 18 ++--
 docs/Upgrading.md                             |  2 +-
 website/.gitignore                            |  1 +
 website/README.md                             | 10 +-
 website/core/DocsSidebar.js                   |  2 +-
 website/core/HeaderLinks.js                   |  6 +-
 website/core/Site.js                          | 15 ++-
 website/layout/AutodocsLayout.js              |  4 +-
 website/package.json                          |  6 +-
 website/publish-android.sh                    | 36 -------
 website/publish-gh-pages.js                   | 99 +++++++++++++++++++
 website/publish.sh                            | 33 -------
 website/server/convert.js                     | 11 +++
 website/server/extractDocs.js                 |  2 +-
 website/server/generate.js                    |  3 +-
 website/src/react-native/circle.yml           |  4 +
 website/src/react-native/css/react-native.css |  2 +-
 website/src/react-native/index.js             |  2 +-
 44 files changed, 234 insertions(+), 186 deletions(-)
 delete mode 100755 website/publish-android.sh
 create mode 100644 website/publish-gh-pages.js
 delete mode 100755 website/publish.sh
 create mode 100644 website/src/react-native/circle.yml

diff --git a/.travis.yml b/.travis.yml
index 9b10d721b5b2..c1d47f6c00f6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -42,24 +42,11 @@ script:
 
     npm test -- '\/(local|private|react-native)-cli\/'
 
-  elif [ "$TEST_TYPE" = build_website ]
-  then
-
-    cd website
-    $(which npm) install
-    ./setup.sh
-    if [ "$TRAVIS_PULL_REQUEST" = false ] && [ "$TRAVIS_BRANCH" = master ]; then
-      # Automatically publish the website
-      echo "machine github.com login reactjs-bot password $GITHUB_TOKEN" >~/.netrc
-      ./publish.sh
-    else
-      # Make sure the website builds without error
-      node server/generate.js
-    fi
-
   elif [ "$TEST_TYPE" = e2e ]
   then
+
     ./scripts/e2e-test.sh
+
   else
     echo "Unknown test type: $TEST_TYPE"
     exit 1
@@ -71,11 +58,8 @@ env:
     - TEST_TYPE=js
     - TEST_TYPE=packager
     - TEST_TYPE=cli
-    - TEST_TYPE=build_website
     - TEST_TYPE=e2e
   global:
-    # $GITHUB_TOKEN
-    - secure: "HlmG8M2DmBUSBh6KH1yVIe/8gR4iibg4WfcHq1x/xYQxGbvleq7NOo04V6eFHnl9cvZCu+PKH0841WLnGR7c4BBf47GVu/o16nXzggPumHKy++lDzxFPlJ1faMDfjg/5vjbAxRUe7D3y98hQSeGHH4tedc8LvTaFLVu7iiGqvjU="
     # $APPETIZE_TOKEN
     - secure: "egsvVSpszTzrNd6bN62DsVAzMiSZI/OHgdizfPryqvqWBf655ztE6XFQSEFNpuIAzSKDDF25ioT8iPfVsbC1iK6HDWHfmqYxML0L+OoU0gi+hV2oKUBFZDZ1fwSnFoWuBdNdMDpLlUxvJp6N1WyfNOB2dxuZUt8eTt48Hi3+Hpc="
     # $S3_TOKEN
diff --git a/Libraries/Animated/src/AnimatedImplementation.js b/Libraries/Animated/src/AnimatedImplementation.js
index 3d70feef8b38..01b701a77706 100644
--- a/Libraries/Animated/src/AnimatedImplementation.js
+++ b/Libraries/Animated/src/AnimatedImplementation.js
@@ -1556,7 +1556,7 @@ var event = function(
  * interaction patterns, like drag-and-drop.
  *
  * You can see more example usage in `AnimationExample.js`, the Gratuitous
- * Animation App, and [Animations documentation guide](http://facebook.github.io/react-native/docs/animations.html).
+ * Animation App, and [Animations documentation guide](docs/animations.html).
  *
  * Note that `Animated` is designed to be fully serializable so that animations
  * can be run in a high performance way, independent of the normal JavaScript
diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js
index cb07b740918d..bdc8978e5166 100644
--- a/Libraries/Components/ScrollView/ScrollView.js
+++ b/Libraries/Components/ScrollView/ScrollView.js
@@ -315,7 +315,7 @@ var ScrollView = React.createClass({
      * A RefreshControl component, used to provide pull-to-refresh
      * functionality for the ScrollView.
      *
-     * See [RefreshControl](http://facebook.github.io/react-native/docs/refreshcontrol.html).
+     * See [RefreshControl](docs/refreshcontrol.html).
      */
     refreshControl: PropTypes.element,
 
diff --git a/Libraries/PushNotificationIOS/PushNotificationIOS.js b/Libraries/PushNotificationIOS/PushNotificationIOS.js
index 189bc7ead83a..a4adace18ac8 100644
--- a/Libraries/PushNotificationIOS/PushNotificationIOS.js
+++ b/Libraries/PushNotificationIOS/PushNotificationIOS.js
@@ -30,7 +30,7 @@ var DEVICE_LOCAL_NOTIF_EVENT = 'localNotificationReceived';
  * To get up and running, [configure your notifications with Apple](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/AddingCapabilities/AddingCapabilities.html#//apple_ref/doc/uid/TP40012582-CH26-SW6)
  * and your server-side system. To get an idea, [this is the Parse guide](https://parse.com/tutorials/ios-push-notifications).
  *
- * [Manually link](https://facebook.github.io/react-native/docs/linking-libraries-ios.html#manual-linking) the PushNotificationIOS library
+ * [Manually link](docs/linking-libraries-ios.html#manual-linking) the PushNotificationIOS library
  *
  * - Be sure to add the following to your `Header Search Paths`:
  * `$(SRCROOT)/../node_modules/react-native/Libraries/PushNotificationIOS`
diff --git a/Libraries/ReactIOS/NativeMethodsMixin.js b/Libraries/ReactIOS/NativeMethodsMixin.js
index 33b99994a72d..c288ea8a01b0 100644
--- a/Libraries/ReactIOS/NativeMethodsMixin.js
+++ b/Libraries/ReactIOS/NativeMethodsMixin.js
@@ -56,7 +56,7 @@ function warnForStyleProps(props, validAttributes) {
  * 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](/react-native/docs/direct-manipulation.html).
+ * Manipulation](docs/direct-manipulation.html).
  */
 var NativeMethodsMixin = {
   /**
@@ -74,7 +74,7 @@ var NativeMethodsMixin = {
    * 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](/react-native/docs/view.html#onlayout) instead.
+   * prop](docs/view.html#onlayout) instead.
    */
   measure: function(callback: MeasureOnSuccessCallback) {
     UIManager.measure(
@@ -108,7 +108,7 @@ var NativeMethodsMixin = {
    * 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](/react-native/docs/direct-manipulation.html)).
+   * Manipulation](docs/direct-manipulation.html)).
    */
   setNativeProps: function(nativeProps: Object) {
     if (__DEV__) {
diff --git a/Libraries/Utilities/AlertIOS.js b/Libraries/Utilities/AlertIOS.js
index ec8c926c6edb..1da237b0c23e 100644
--- a/Libraries/Utilities/AlertIOS.js
+++ b/Libraries/Utilities/AlertIOS.js
@@ -45,7 +45,7 @@ type ButtonsArray = Array<{
 class AlertIOS {
   /**
    * Creates a popup to alert the user. See
-   * [Alert](/react-native/docs/alert.html).
+   * [Alert](docs/alert.html).
    *
    *  - title: string -- The dialog's title.
    *  - message: string -- An optional message that appears above the text input.
diff --git a/Libraries/vendor/react/browser/eventPlugins/PanResponder.js b/Libraries/vendor/react/browser/eventPlugins/PanResponder.js
index 36490a843026..c633dd724be7 100644
--- a/Libraries/vendor/react/browser/eventPlugins/PanResponder.js
+++ b/Libraries/vendor/react/browser/eventPlugins/PanResponder.js
@@ -23,7 +23,7 @@ var currentCentroidY = TouchHistoryMath.currentCentroidY;
  * recognize simple multi-touch gestures.
  *
  * It provides a predictable wrapper of the responder handlers provided by the
- * [gesture responder system](/react-native/docs/gesture-responder-system.html).
+ * [gesture responder system](docs/gesture-responder-system.html).
  * For each handler, it provides a new `gestureState` object alongside the
  * native event object:
  *
diff --git a/circle.yml b/circle.yml
index 7ea22ee0edad..7d396cc43eef 100644
--- a/circle.yml
+++ b/circle.yml
@@ -26,12 +26,15 @@ dependencies:
     - npm install -g npm@3.2
     - source scripts/circle-ci-android-setup.sh && getAndroidSDK
     - ./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog
+    - cd website && npm install
   cache_directories:
     - "ReactAndroid/build/downloads"
     - "buck"
     - "buck-out/bin"
+    - "website/node_modules"
   override:
     - npm install
+
 test:
   pre:
     # starting emulator in advance because it takes very long to boot
@@ -41,6 +44,7 @@ test:
     - ./gradlew :ReactAndroid:assembleDebug -PdisablePreDex -Pjobs=1:
             timeout: 360
     - source scripts/circle-ci-android-setup.sh && waitForAVD
+
   override:
     # buck tests
     - buck/bin/buck test ReactAndroid/src/test/... --config build.threads=1
@@ -57,9 +61,21 @@ test:
     # run tests on the emulator
     - ./gradlew :ReactAndroid:connectedAndroidTest -PdisablePreDex --stacktrace --info:
         timeout: 360
+
+    # testing docs generation is not broken
+    - cd website && node ./server/generate.js
   post:
     # copy test report for Circle CI to display
     - mkdir -p $CIRCLE_TEST_REPORTS/junit/
     - find . -type f -regex ".*/build/test-results/debug/.*xml" -exec cp {} $CIRCLE_TEST_REPORTS/junit/ \;
     - find . -type f -regex ".*/outputs/androidTest-results/connected/.*xml" -exec cp {} $CIRCLE_TEST_REPORTS/junit/ \;
 
+deployment:
+  website:
+    branch: [/.*-stable/, /master/]
+    commands:
+      # generate docs website
+      - git config --global user.email "bestnader@fb.com"
+      - git config --global user.name "Website Deployment Script"
+      - echo "machine github.com login reactjs-bot password $GITHUB_TOKEN" > ~/.netrc
+      - cd website && GIT_USER=bestander npm run gh-pages
diff --git a/docs/AndroidUIPerformance.md b/docs/AndroidUIPerformance.md
index 321bb0c46bfe..3dc51532dc38 100644
--- a/docs/AndroidUIPerformance.md
+++ b/docs/AndroidUIPerformance.md
@@ -43,7 +43,7 @@ Once the trace starts collecting, perform the animation or interaction you care
 
 After opening the trace in your browser (preferably Chrome), you should see something like this:
 
-![Example](/react-native/img/SystraceExample.png)
+![Example](img/SystraceExample.png)
 
 **HINT**: Use the WASD keys to strafe and zoom
 
@@ -51,7 +51,7 @@ After opening the trace in your browser (preferably Chrome), you should see some
 
 The first thing you should do is highlight the 16ms frame boundaries if you haven't already done that. Check this checkbox at the top right of the screen:
 
-![Enable VSync Highlighting](/react-native/img/SystraceHighlightVSync.png)
+![Enable VSync Highlighting](img/SystraceHighlightVSync.png)
 
 You should see zebra stripes as in the screenshot above. If you don't, try profiling on a different device: Samsung has been known to have issues displaying vsyncs while the Nexus series is generally pretty reliable.
 
@@ -65,43 +65,43 @@ On the left side, you'll see a set of threads which correspond to the timeline r
 
 This is where standard android measure/layout/draw happens. The thread name on the right will be your package name (in my case book.adsmanager) or UI Thread. The events that you see on this thread should look something like this and have to do with `Choreographer`, `traversals`, and `DispatchUI`:
 
-![UI Thread Example](/react-native/img/SystraceUIThreadExample.png)
+![UI Thread Example](img/SystraceUIThreadExample.png)
 
 ### JS Thread
 
 This is where JS is executed. The thread name will be either `mqt_js` or `<...>` depending on how cooperative the kernel on your device is being. To identify it if it doesn't have a name, look for things like `JSCall`, `Bridge.executeJSCall`, etc:
 
-![JS Thread Example](/react-native/img/SystraceJSThreadExample.png)
+![JS Thread Example](img/SystraceJSThreadExample.png)
 
 ### Native Modules Thread
 
 This is where native module calls (e.g. the `UIManager`) are executed. The thread name will be either `mqt_native_modules` or `<...>`. To identify it in the latter case, look for things like `NativeCall`, `callJavaModuleMethod`, and `onBatchComplete`:
 
-![Native Modules Thread Example](/react-native/img/SystraceNativeModulesThreadExample.png)
+![Native Modules Thread Example](img/SystraceNativeModulesThreadExample.png)
 
 ### Bonus: Render Thread
 
 If you're using Android L (5.0) and up, you will also have a render thread in your application. This thread generates the actual OpenGL commands used to draw your UI. The thread name will be either `RenderThread` or `<...>`. To identify it in the latter case, look for things like `DrawFrame` and `queueBuffer`:
 
-![Render Thread Example](/react-native/img/SystraceRenderThreadExample.png)
+![Render Thread Example](img/SystraceRenderThreadExample.png)
 
 ## Identifying a culprit
 
 A smooth animation should look something like the following:
 
-![Smooth Animation](/react-native/img/SystraceWellBehaved.png)
+![Smooth Animation](img/SystraceWellBehaved.png)
 
 Each change in color is a frame -- remember that in order to display a frame, all our UI work needs to be done by the end of that 16ms period. Notice that no thread is working close to the frame boundary. An application rendering like this is rendering at 60FPS.
 
 If you noticed chop, however, you might see something like this:
 
-![Choppy Animation from JS](/react-native/img/SystraceBadJS.png)
+![Choppy Animation from JS](img/SystraceBadJS.png)
 
 Notice that the JS thread is executing basically all the time, and across frame boundaries! This app is not rendering at 60FPS. In this case, **the problem lies in JS**.
 
 You might also see something like this:
 
-![Choppy Animation from UI](/react-native/img/SystraceBadUI.png)
+![Choppy Animation from UI](img/SystraceBadUI.png)
 
 In this case, the UI and render threads are the ones that have work crossing frame boundaries. The UI that we're trying to render on each frame is requiring too much work to be done. In this case, **the problem lies in the native views being rendered**.
 
@@ -111,7 +111,7 @@ At this point, you'll have some very helpful information to inform your next ste
 
 If you identified a JS problem, look for clues in the specific JS that you're executing. In the scenario above, we see `RCTEventEmitter` being called multiple times per frame. Here's a zoom-in of the JS thread from the trace above:
 
-![Too much JS](/react-native/img/SystraceBadJS2.png)
+![Too much JS](img/SystraceBadJS2.png)
 
 This doesn't seem right. Why is it being called so often? Are they actually different events? The answers to these questions will probably depend on your product code. And many times, you'll want to look into [shouldComponentUpdate](https://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate).
 
@@ -128,7 +128,7 @@ If you identified a native UI problem, there are usually two scenarios:
 
 In the first scenario, you'll see a trace that has the UI thread and/or Render Thread looking like this:
 
-![Overloaded GPU](/react-native/img/SystraceBadUI.png)
+![Overloaded GPU](img/SystraceBadUI.png)
 
 Notice the long amount of time spent in `DrawFrame` that crosses frame boundaries. This is time spent waiting for the GPU to drain its command buffer from the previous frame.
 
@@ -143,7 +143,7 @@ If these don't help and you want to dig deeper into what the GPU is actually doi
 
 In the second scenario, you'll see something more like this:
 
-![Creating Views](/react-native/img/SystraceBadCreateUI.png)
+![Creating Views](img/SystraceBadCreateUI.png)
 
 Notice that first the JS thread thinks for a bit, then you see some work done on the native modules thread, followed by an expensive traversal on the UI thread.
 
diff --git a/docs/Animations.md b/docs/Animations.md
index af8d0031ca1f..15dac519b865 100644
--- a/docs/Animations.md
+++ b/docs/Animations.md
@@ -267,7 +267,7 @@ it provides much less control than `Animated` and other animation libraries, so
 you may need to use another approach if you can't get `LayoutAnimation` to do
 what you want.
 
-![](/react-native/img/LayoutAnimationExample.gif)
+![](img/LayoutAnimationExample.gif)
 
 ```javascript
 var App = React.createClass({
@@ -376,7 +376,7 @@ var App = React.createClass({
 ```
 [Run this example](https://rnplay.org/apps/4FUQ-A)
 
-![](/react-native/img/TweenState.gif)
+![](img/TweenState.gif)
 
 Here we animated the opacity, but as you might guess, we can animate any
 numeric value. Read more about react-tween-state in its
@@ -395,7 +395,7 @@ value and end value.  Rebound [is used
 internally](https://github.com/facebook/react-native/search?utf8=%E2%9C%93&q=rebound)
 by React Native on `Navigator` and `WarningBox`.
 
-![](/react-native/img/ReboundImage.gif)
+![](img/ReboundImage.gif)
 
 Notice that Rebound animations can be interrupted - if you release in
 the middle of a press, it will animate back from the current state to
@@ -440,7 +440,7 @@ var App = React.createClass({
       transform: [{scaleX: this.state.scale}, {scaleY: this.state.scale}],
     };
 
-    var imageUri = "https://facebook.github.io/react-native/img/ReboundExample.png";
+    var imageUri = "img/ReboundExample.png";
 
     return (
       <View style={styles.container}>
@@ -461,13 +461,13 @@ oscillate around the end value. In the above example, we would add
 See the below gif for an example of where in your interface you might
 use this.
 
-![](/react-native/img/Rebound.gif) Screenshot from
+![](img/Rebound.gif) Screenshot from
 [react-native-scrollable-tab-view](https://github.com/brentvatne/react-native-scrollable-tab-view).
 You can run a similar example [here](https://rnplay.org/apps/qHU_5w).
 
 #### A sidenote about setNativeProps
 
-As mentioned [in the Direction Manipulation section](/react-native/docs/direct-manipulation.html),
+As mentioned [in the Direction Manipulation section](docs/direct-manipulation.html),
 `setNativeProps` allows us to modify properties of native-backed
 components (components that are actually backed by native views, unlike
 composite components) directly, without having to `setState` and
@@ -497,7 +497,7 @@ render: function() {
     <View style={styles.container}>
       <TouchableWithoutFeedback onPressIn={this._onPressIn} onPressOut={this._onPressOut}>
         <Image ref={component => this._photo = component}
-               source={{uri: "https://facebook.github.io/react-native/img/ReboundExample.png"}}
+               source={{uri: "img/ReboundExample.png"}}
                style={{width: 250, height: 200}} />
       </TouchableWithoutFeedback>
     </View>
@@ -516,14 +516,14 @@ frames per second), look into using `setNativeProps` or
 `shouldComponentUpdate` to optimize them. You may also want to defer any
 computationally intensive work until after animations are complete,
 using the
-[InteractionManager](/react-native/docs/interactionmanager.html). You
+[InteractionManager](docs/interactionmanager.html). You
 can monitor the frame rate by using the In-App Developer Menu "FPS
 Monitor" tool.
 
 ### Navigator Scene Transitions
 
 As mentioned in the [Navigator
-Comparison](https://facebook.github.io/react-native/docs/navigator-comparison.html#content),
+Comparison](docs/navigator-comparison.html#content),
 `Navigator` is implemented in JavaScript and `NavigatorIOS` is a wrapper
 around native functionality provided by `UINavigationController`, so
 these scene transitions apply only to `Navigator`. In order to re-create
diff --git a/docs/CommunicationIOS.md b/docs/CommunicationIOS.md
index 3e430636f05b..dae65bc2737e 100644
--- a/docs/CommunicationIOS.md
+++ b/docs/CommunicationIOS.md
@@ -7,7 +7,7 @@ permalink: docs/communication-ios.html
 next: native-modules-android
 ---
 
-In [Integrating with Existing Apps guide](http://facebook.github.io/react-native/docs/embedded-app-ios.html) and [Native UI Components guide](https://facebook.github.io/react-native/docs/native-components-ios.html) we learn how to embed React Native in a native component and vice versa. When we mix native and React Native components, we'll eventually find a need to communicate between these two worlds. Some ways to achieve that have been already mentioned in other guides. This article summarizes available techniques.
+In [Integrating with Existing Apps guide](docs/embedded-app-ios.html) and [Native UI Components guide](docs/native-components-ios.html) we learn how to embed React Native in a native component and vice versa. When we mix native and React Native components, we'll eventually find a need to communicate between these two worlds. Some ways to achieve that have been already mentioned in other guides. This article summarizes available techniques.
 
 ## Introduction
 
@@ -80,13 +80,13 @@ There is no way to update only a few properties at a time. We suggest that you b
 > Currently, JS functions `componentWillReceiveProps` and `componentWillUpdateProps` of the top level RN component will not be called after a prop update. However, you can access the new props in `componentWillMount` function.
 
 ### Passing properties from React Native to native
-The problem exposing properties of native components is covered in detail in [this article](https://facebook.github.io/react-native/docs/native-components-ios.html#properties). In short, export properties with `RCT_CUSTOM_VIEW_PROPERTY` macro in your custom native component, then just use them in React Native as if the component was an ordinary React Native component.
+The problem exposing properties of native components is covered in detail in [this article](docs/native-components-ios.html#properties). In short, export properties with `RCT_CUSTOM_VIEW_PROPERTY` macro in your custom native component, then just use them in React Native as if the component was an ordinary React Native component.
 
 ### Limits of properties
 
 The main drawback of cross-language properties is that they do not support callbacks, which would allow us to handle bottom-up data bindings. Imagine you have a small RN view that you want to be removed from the native parent view as a result of a JS action. There is no way to do that with props, as the information would need to go bottom-up.
 
-Although we have a flavor of cross-language callbacks ([described here](https://facebook.github.io/react-native/docs/native-modules-ios.html#callbacks)), these callbacks are not always the thing we need. The main problem is that they are not intended to be passed as properties. Rather, this mechanism allows us to trigger a native action from JS, and handle the result of that action in JS.
+Although we have a flavor of cross-language callbacks ([described here](docs/native-modules-ios.html#callbacks)), these callbacks are not always the thing we need. The main problem is that they are not intended to be passed as properties. Rather, this mechanism allows us to trigger a native action from JS, and handle the result of that action in JS.
 
 ## Other ways of cross-language interaction (events and native modules)
 
@@ -96,7 +96,7 @@ React Native enables you to perform cross-language function calls. You can execu
 
 ### Calling React Native functions from native (events)
 
-Events are described in detail in [this article](http://facebook.github.io/react-native/docs/native-components-ios.html#events). Note that using events gives us no guarantees about execution time, as the event is handled on a separate thread.
+Events are described in detail in [this article](docs/native-components-ios.html#events). Note that using events gives us no guarantees about execution time, as the event is handled on a separate thread.
 
 Events are powerful, because they allow us to change React Native components without needing a reference to them. However, there are some pitfalls that you can fall into while using them:
 
@@ -108,7 +108,7 @@ The common pattern we use when embedding native in React Native is to make the n
 
 ### Calling native functions from React Native (native modules)
 
-Native modules are Objective-C classes that are available in JS. Typically one instance of each module is created per JS bridge. They can export arbitrary functions and constants to React Native. They have been covered in detail in [this article](https://facebook.github.io/react-native/docs/native-modules-ios.html#content).
+Native modules are Objective-C classes that are available in JS. Typically one instance of each module is created per JS bridge. They can export arbitrary functions and constants to React Native. They have been covered in detail in [this article](docs/native-modules-ios.html#content).
 
 The fact that native modules are singletons limits the mechanism in context of embedding. Let's say we have a React Native component embedded in a native view and we want to update the native, parent view. Using the native module mechanism, we would export a function that not only takes expected arguments, but also an identifier of the parent native view. The identifier would be used to retrieve a reference to the parent view to update. That said, we would need to keep a mapping from identifiers to native views in the module.
 
@@ -125,7 +125,7 @@ When integrating native and React Native, we also need a way to consolidate two
 
 ### Layout of a native component embedded in React Native
 
-This case is covered in [this article](https://facebook.github.io/react-native/docs/native-components-ios.html#styles). Basically, as all our native react views are subclasses of `UIView`, most style and size attributes will work like you would expect out of the box.
+This case is covered in [this article](docs/native-components-ios.html#styles). Basically, as all our native react views are subclasses of `UIView`, most style and size attributes will work like you would expect out of the box.
 
 ### Layout of a React Native component embedded in native
 
diff --git a/docs/DevelopmentSetupAndroid.md b/docs/DevelopmentSetupAndroid.md
index eab90e85a875..9eee76088519 100644
--- a/docs/DevelopmentSetupAndroid.md
+++ b/docs/DevelopmentSetupAndroid.md
@@ -55,7 +55,7 @@ React Native Android use [gradle](https://docs.gradle.org) as a build system. We
   * Android Support Repository
 2. Click "Install Packages"
 
-![SDK Manager window](/react-native/img/AndroidSDK1.png) ![SDK Manager window](/react-native/img/AndroidSDK2.png)
+![SDK Manager window](img/AndroidSDK1.png) ![SDK Manager window](img/AndroidSDK2.png)
 
 ### Install Genymotion
 
@@ -75,7 +75,7 @@ Genymotion is much easier to set up than stock Google emulators. However, it's o
 3. [Configure hardware acceleration (HAXM)](http://developer.android.com/tools/devices/emulator.html#vm-mac), otherwise the emulator is going to be slow.
 4. Create an Android Virtual Device (AVD):
   1. Run `android avd` and click on **Create...**
-  ![Create AVD dialog](/react-native/img/CreateAVD.png)
+  ![Create AVD dialog](img/CreateAVD.png)
   2. With the new AVD selected, click `Start...`
 5. To bring up the developer menu press F2 (or install [Frappé](http://getfrappe.com))
 
diff --git a/docs/DirectManipulation.md b/docs/DirectManipulation.md
index a47a39fe2cbd..3c6fd46ed930 100644
--- a/docs/DirectManipulation.md
+++ b/docs/DirectManipulation.md
@@ -156,7 +156,7 @@ view using `{...this.props}`. The reason for this is that
 `TouchableOpacity` is actually a composite component, and so in addition
 to depending on `setNativeProps` on its child, it also requires that the
 child perform touch handling. To do this, it passes on [various
-props](https://facebook.github.io/react-native/docs/view.html#onmoveshouldsetresponder)
+props](docs/view.html#onmoveshouldsetresponder)
 that call back to the `TouchableOpacity` component.
 `TouchableHighlight`, in contrast, is backed by a native view and only
 requires that we implement `setNativeProps`.
diff --git a/docs/EmbeddedAppAndroid.md b/docs/EmbeddedAppAndroid.md
index 88122d52ac86..eb8cc6fb4a45 100644
--- a/docs/EmbeddedAppAndroid.md
+++ b/docs/EmbeddedAppAndroid.md
@@ -166,7 +166,7 @@ To run your app, you need to first start the development server. To do this, sim
 
 Now build and run your Android app as normal (e.g. `./gradlew installDebug`). Once you reach your React-powered activity inside the app, it should load the JavaScript code from the development server and display:
 
-![Screenshot](/react-native/img/EmbeddedAppAndroid.png)
+![Screenshot](img/EmbeddedAppAndroid.png)
 
 ## Sharing a ReactInstance across multiple Activities / Fragments in your app
 
diff --git a/docs/EmbeddedAppIOS.md b/docs/EmbeddedAppIOS.md
index 2082070ba16f..294d4b7fe30a 100644
--- a/docs/EmbeddedAppIOS.md
+++ b/docs/EmbeddedAppIOS.md
@@ -98,7 +98,7 @@ React.AppRegistry.registerComponent('SimpleApp', () => SimpleApp);
 
 You should now add a container view for the React Native component. It can be any `UIView` in your app.
 
-![Container view example](/react-native/img/EmbeddedAppContainerViewExample.png)
+![Container view example](img/EmbeddedAppContainerViewExample.png)
 
 However, let's subclass `UIView` for the sake of clean code. Let's name it `ReactView`. Open up `Yourproject.xcworkspace` and create a new class `ReactView` (You can name it whatever you like :)).
 
@@ -186,7 +186,7 @@ If you don't do this, you will see the error - `Could not connect to development
 
 Now compile and run your app. You shall now see your React Native app running inside of the `ReactView`.
 
-![Example](/react-native/img/EmbeddedAppExample.png)
+![Example](img/EmbeddedAppExample.png)
 
 Live reload and all of the debugging tools will work from the simulator (make sure that DEBUG=1 is set under Build Settings -> Preprocessor Macros).  You've got a simple React component totally encapsulated behind an Objective-C `UIView` subclass.
 
diff --git a/docs/GestureResponderSystem.md b/docs/GestureResponderSystem.md
index 2c83274350c7..b7c8dbc40e19 100644
--- a/docs/GestureResponderSystem.md
+++ b/docs/GestureResponderSystem.md
@@ -68,4 +68,4 @@ However, sometimes a parent will want to make sure that it becomes responder. Th
 
 ### PanResponder
 
-For higher-level gesture interpretation, check out [PanResponder](/react-native/docs/panresponder.html).
+For higher-level gesture interpretation, check out [PanResponder](docs/panresponder.html).
diff --git a/docs/GettingStarted.md b/docs/GettingStarted.md
index cc83191d1140..dcee2490ad53 100644
--- a/docs/GettingStarted.md
+++ b/docs/GettingStarted.md
@@ -27,7 +27,7 @@ We recommend periodically running `brew update && brew upgrade` to keep your pro
 
 To write React Native apps for Android, you will need to install the Android SDK (and an Android emulator if you want to work on your app without having to use a physical device). See [Android setup guide](android-setup.html) for instructions on how to set up your Android environment.
 
-_NOTE:_ There is experimental [Windows and Linux support](/react-native/docs/linux-windows-support.html) for Android development.
+_NOTE:_ There is experimental [Windows and Linux support](docs/linux-windows-support.html) for Android development.
 
 ## Quick start
 
@@ -41,7 +41,7 @@ _NOTE:_ There is experimental [Windows and Linux support](/react-native/docs/lin
 - Open `index.ios.js` in your text editor of choice and edit some lines.
 - Hit ⌘-R in your iOS simulator to reload the app and see your change!
 
-_Note: If you are using an iOS device, see the [Running on iOS Device page](http://facebook.github.io/react-native/docs/running-on-device-ios.html#content)._
+_Note: If you are using an iOS device, see the [Running on iOS Device page](docs/running-on-device-ios.html#content)._
 
 **To run the Android app:**
 
@@ -51,11 +51,11 @@ _Note: If you are using an iOS device, see the [Running on iOS Device page](http
 - Press the menu button (F2 by default, or ⌘-M in Genymotion) and select *Reload JS* to see your change!
 - Run `adb logcat *:S ReactNative:V ReactNativeJS:V` in a terminal to see your app's logs
 
-_Note: If you are using an Android device, see the [Running on Android Device page](http://facebook.github.io/react-native/docs/running-on-device-android.html#content)._
+_Note: If you are using an Android device, see the [Running on Android Device page](docs/running-on-device-android.html#content)._
 
 Congratulations! You've successfully run and modified your first React Native app.
 
-_If you run into any issues getting started, see the [troubleshooting page](/react-native/docs/troubleshooting.html#content)._
+_If you run into any issues getting started, see the [troubleshooting page](docs/troubleshooting.html#content)._
 
 ## Adding Android to an existing React Native project
 
diff --git a/docs/Images.md b/docs/Images.md
index 12ab24fe2fdf..7685626eb37b 100644
--- a/docs/Images.md
+++ b/docs/Images.md
@@ -90,7 +90,7 @@ Many of the images you will display in your app will not be available at compile
 
 ## Local Filesystem Images
 
-See [CameraRoll](/react-native/docs/cameraroll.html) for an example of
+See [CameraRoll](docs/cameraroll.html) for an example of
 using local resources that are outside of `Images.xcassets`.
 
 ### Best Camera Roll Image
diff --git a/docs/KnownIssues.md b/docs/KnownIssues.md
index a3deb7319783..8a2616c023ff 100644
--- a/docs/KnownIssues.md
+++ b/docs/KnownIssues.md
@@ -38,7 +38,7 @@ PushNotificationIOS
 
 ### Some props are only supported on one platform
 
-There are properties that work on one platform only, either because they can inherently only be supported on that platform or because they haven't been implemented on the other platforms yet. All of these are annotated with `@platform` in JS docs and have a small badge next to them on the website. See e.g. [Image](https://facebook.github.io/react-native/docs/image.html).
+There are properties that work on one platform only, either because they can inherently only be supported on that platform or because they haven't been implemented on the other platforms yet. All of these are annotated with `@platform` in JS docs and have a small badge next to them on the website. See e.g. [Image](docs/image.html).
 
 ### Platform parity
 
@@ -62,7 +62,7 @@ Another issue with `overflow: 'hidden'` on Android: a view is not clipped by the
 
 ### View shadows
 
-The `shadow*` [view styles](/react-native/docs/view.html#style) apply on iOS, and the `elevation` view prop is available on Android. Setting `elevation` on Android is equivalent to using the [native elevation API](https://developer.android.com/training/material/shadows-clipping.html#Elevation), and has the same limitations (most significantly, it only works on Android 5.0+). Setting `elevation` on Android also affects the z-order for overlapping views.
+The `shadow*` [view styles](docs/view.html#style) apply on iOS, and the `elevation` view prop is available on Android. Setting `elevation` on Android is equivalent to using the [native elevation API](https://developer.android.com/training/material/shadows-clipping.html#Elevation), and has the same limitations (most significantly, it only works on Android 5.0+). Setting `elevation` on Android also affects the z-order for overlapping views.
 
 ### Android M permissions
 
diff --git a/docs/LinkingLibraries.md b/docs/LinkingLibraries.md
index 8fc6fe6e582b..0ce0849531a4 100644
--- a/docs/LinkingLibraries.md
+++ b/docs/LinkingLibraries.md
@@ -65,7 +65,7 @@ folder.
 Drag this file to your project on Xcode (usually under the `Libraries` group
 on Xcode);
 
-![](/react-native/img/AddToLibraries.png)
+![](img/AddToLibraries.png)
 
 #### Step 2
 
@@ -73,7 +73,7 @@ Click on your main project file (the one that represents the `.xcodeproj`)
 select `Build Phases` and drag the static library from the `Products` folder
 inside the Library you are importing to `Link Binary With Libraries`
 
-![](/react-native/img/AddToBuildPhases.png)
+![](img/AddToBuildPhases.png)
 
 #### Step 3
 
@@ -97,4 +97,4 @@ Paths`. There you should include the path to your library (if it has relevant
 files on subdirectories remember to make it `recursive`, like `React` on the
 example).
 
-![](/react-native/img/AddToSearchPaths.png)
+![](img/AddToSearchPaths.png)
diff --git a/docs/NavigatorComparison.md b/docs/NavigatorComparison.md
index cc6c5c6c8bbd..80262d1a358d 100644
--- a/docs/NavigatorComparison.md
+++ b/docs/NavigatorComparison.md
@@ -7,8 +7,8 @@ permalink: docs/navigator-comparison.html
 next: known-issues
 ---
 
-The differences between [Navigator](/react-native/docs/navigator.html)
-and [NavigatorIOS](/react-native/docs/navigatorios.html) are a common
+The differences between [Navigator](docs/navigator.html)
+and [NavigatorIOS](docs/navigatorios.html) are a common
 source of confusion for newcomers.
 
 Both `Navigator` and `NavigatorIOS` are components that allow you to
diff --git a/docs/Performance.md b/docs/Performance.md
index 1dfbb544445c..efded189650c 100644
--- a/docs/Performance.md
+++ b/docs/Performance.md
@@ -72,7 +72,7 @@ out of the box than `Navigator`. The reason for this is that the
 animations for the transitions are done entirely on the main thread, and
 so they are not interrupted by frame drops on the JavaScript thread.
 ([Read about why you should probably use Navigator
-anyways.](/react-native/docs/navigator-comparison.html))
+anyways.](docs/navigator-comparison.html))
 
 Similarly, you can happily scroll up and down through a ScrollView when
 the JavaScript thread is locked up because the ScrollView lives on the
diff --git a/docs/RunningOnDeviceIOS.md b/docs/RunningOnDeviceIOS.md
index c90f3b04ed88..619b048fcea2 100644
--- a/docs/RunningOnDeviceIOS.md
+++ b/docs/RunningOnDeviceIOS.md
@@ -31,7 +31,7 @@ When you run your app on device, we pack all the JavaScript code and the images
 
 ## Disabling in-app developer menu
 
-When building your app for production, your app's scheme should be set to `Release` as detailed in [the debugging documentation](/react-native/docs/debugging.html#debugging-react-native-apps) in order to disable the in-app developer menu.
+When building your app for production, your app's scheme should be set to `Release` as detailed in [the debugging documentation](docs/debugging.html#debugging-react-native-apps) in order to disable the in-app developer menu.
 
 ## Troubleshooting
 
diff --git a/docs/SignedAPKAndroid.md b/docs/SignedAPKAndroid.md
index d35e95d82d9d..b32defa06eaf 100644
--- a/docs/SignedAPKAndroid.md
+++ b/docs/SignedAPKAndroid.md
@@ -78,7 +78,7 @@ If you need to change the way the JavaScript bundle and/or drawable resources ar
 
 #### If you *don't* have a `react.gradle` file:
 
-You can [upgrade](/react-native/docs/upgrading.html) to the latest version of React Native to get this file. Alternatively, you can bundle the JavaScript package and drawable resources manually by doing the following in a terminal:
+You can [upgrade](docs/upgrading.html) to the latest version of React Native to get this file. Alternatively, you can bundle the JavaScript package and drawable resources manually by doing the following in a terminal:
 
 ```sh
 $ mkdir -p android/app/src/main/assets
diff --git a/docs/Style.md b/docs/Style.md
index 9f7229c94e2e..fb6cb7a6dc07 100644
--- a/docs/Style.md
+++ b/docs/Style.md
@@ -33,7 +33,7 @@ var styles = StyleSheet.create({
 
 `StyleSheet.create` construct is optional but provides some key advantages. It ensures that the values are **immutable** and **opaque** by transforming them into plain numbers that reference an internal table. By putting it at the end of the file, you also ensure that they are only created once for the application and not on every render.
 
-All the attribute names and values are a subset of what works on the web. For layout, React Native implements [Flexbox](/react-native/docs/flexbox.html).
+All the attribute names and values are a subset of what works on the web. For layout, React Native implements [Flexbox](docs/flexbox.html).
 
 ## Using Styles
 
@@ -95,8 +95,8 @@ var List = React.createClass({
 
 You can checkout latest support of CSS Properties in following Links.
 
-- [View Properties](/react-native/docs/view.html#style)
-- [Image Properties](/react-native/docs/image.html#style)
-- [Text Properties](/react-native/docs/text.html#style)
-- [Flex Properties](/react-native/docs/flexbox.html#content)
-- [Transform Properties](/react-native/docs/transforms.html#content)
+- [View Properties](docs/view.html#style)
+- [Image Properties](docs/image.html#style)
+- [Text Properties](docs/text.html#style)
+- [Flex Properties](docs/flexbox.html#content)
+- [Transform Properties](docs/transforms.html#content)
diff --git a/docs/Troubleshooting.md b/docs/Troubleshooting.md
index 6db929a2c278..b0063ae19cf2 100644
--- a/docs/Troubleshooting.md
+++ b/docs/Troubleshooting.md
@@ -78,7 +78,7 @@ pod 'React', :path => '../node_modules/react-native', :subspecs => [
 ```
 Next, make sure you have run `pod install` and that a `Pods/` directory has been created in your project with React installed. CocoaPods will instruct you to use the generated `.xcworkspace` file henceforth to be able to use these installed dependencies.
 
-If you are adding React manually, make sure you have included all the relevant dependencies, like `RCTText.xcodeproj`, `RCTImage.xcodeproj` depending on the ones you are using. Next, the binaries built by these dependencies have to be linked to your app binary. Use the `Linked Frameworks and Binaries` section in the Xcode project settings. More detailed steps are here: [Linking Libraries](https://facebook.github.io/react-native/docs/linking-libraries-ios.html#content).
+If you are adding React manually, make sure you have included all the relevant dependencies, like `RCTText.xcodeproj`, `RCTImage.xcodeproj` depending on the ones you are using. Next, the binaries built by these dependencies have to be linked to your app binary. Use the `Linked Frameworks and Binaries` section in the Xcode project settings. More detailed steps are here: [Linking Libraries](docs/linking-libraries-ios.html#content).
 
 ##### Argument list too long: recursive header expansion failed
 
diff --git a/docs/Tutorial.md b/docs/Tutorial.md
index b5dc1d16c084..1e0be8a205e6 100644
--- a/docs/Tutorial.md
+++ b/docs/Tutorial.md
@@ -16,7 +16,7 @@ We assume you have experience writing applications with React. If not, you can l
 
 ## Setup
 
-React Native requires the basic setup explained at [React Native Getting Started](https://facebook.github.io/react-native/docs/getting-started.html#content).
+React Native requires the basic setup explained at [React Native Getting Started](docs/getting-started.html#content).
 
 After installing these dependencies there are two simple commands to get a React Native project all set up for development.
 
@@ -111,8 +111,8 @@ And lastly we need to apply this style to the Image component:
 Press `⌘+R` / `Reload JS` and the image should now render.
 
 <div class="tutorial-mock">
-  <img src="/react-native/img/TutorialMock.png" />
-  <img src="/react-native/img/TutorialMock2.png" />
+  <img src="img/TutorialMock.png" />
+  <img src="img/TutorialMock2.png" />
 </div>
 
 
@@ -189,8 +189,8 @@ Styling the text is pretty straightforward:
 Go ahead and press `⌘+R` / `Reload JS` and you'll see the updated view.
 
 <div class="tutorial-mock">
-  <img src="/react-native/img/TutorialStyledMock.png" />
-  <img src="/react-native/img/TutorialStyledMock2.png" />
+  <img src="img/TutorialStyledMock.png" />
+  <img src="img/TutorialStyledMock2.png" />
 </div>
 
 ### Fetching real data
@@ -282,8 +282,8 @@ Now modify the render function to render a loading view if we don't have any mov
 Now press `⌘+R` / `Reload JS` and you should see "Loading movies..." until the response comes back, then it will render the first movie it fetched from Rotten Tomatoes.
 
 <div class="tutorial-mock">
-  <img src="/react-native/img/TutorialSingleFetched.png" />
-  <img src="/react-native/img/TutorialSingleFetched2.png" />
+  <img src="img/TutorialSingleFetched.png" />
+  <img src="img/TutorialSingleFetched2.png" />
 </div>
 
 ## ListView
@@ -367,8 +367,8 @@ Finally, we add styles for the `ListView` component to the `styles` JS object:
 And here's the final result:
 
 <div class="tutorial-mock">
-  <img src="/react-native/img/TutorialFinal.png" />
-  <img src="/react-native/img/TutorialFinal2.png" />
+  <img src="img/TutorialFinal.png" />
+  <img src="img/TutorialFinal2.png" />
 </div>
 
 There's still some work to be done to make it a fully functional app such as: adding navigation, search, infinite scroll loading, etc. Check the [Movies Example](https://github.com/facebook/react-native/tree/master/Examples/Movies) to see it all working.
diff --git a/docs/Upgrading.md b/docs/Upgrading.md
index 51b46bfe737e..4034b4f731cf 100644
--- a/docs/Upgrading.md
+++ b/docs/Upgrading.md
@@ -50,7 +50,7 @@ Xcode project format is pretty complex and sometimes it's tricky to upgrade and
 
 ### From 0.13 to 0.14
 
-The major change in this version happened to the CLI ([see changelog](https://github.com/facebook/react-native/releases/tag/v0.14.0-rc)) and static images ([see docs](http://facebook.github.io/react-native/docs/images.html)). To use the new asset system in existing Xcode project, do the following:
+The major change in this version happened to the CLI ([see changelog](https://github.com/facebook/react-native/releases/tag/v0.14.0-rc)) and static images ([see docs](docs/images.html)). To use the new asset system in existing Xcode project, do the following:
 
 Add new "Run Script" step to your project's build phases:
 
diff --git a/website/.gitignore b/website/.gitignore
index 850f11c1b9cd..9ece2944657e 100644
--- a/website/.gitignore
+++ b/website/.gitignore
@@ -1,3 +1,4 @@
 src/react-native/docs/**
 core/metadata.js
 *.log
+/build/
diff --git a/website/README.md b/website/README.md
index 5c162aab6fee..3c633b91216b 100644
--- a/website/README.md
+++ b/website/README.md
@@ -17,14 +17,8 @@ Anytime you change the contents, just refresh the page and it's going to be upda
 
 # Publish the website
 
-First setup your environment by having two folders, one `react-native` and one `react-native-gh-pages`. The publish script expects those exact names.
-
 ```sh
-./setup.sh
+cd website
+npm run publish-website
 ```
 
-Then, after you've done changes, just run the command and it'll automatically build the static version of the site and publish it to gh-pages.
-
-```sh
-./publish.sh
-```
diff --git a/website/core/DocsSidebar.js b/website/core/DocsSidebar.js
index 2c18c7c8e757..d8640e40d790 100644
--- a/website/core/DocsSidebar.js
+++ b/website/core/DocsSidebar.js
@@ -72,7 +72,7 @@ var DocsSidebar = React.createClass({
     if (metadata.permalink.match(/^https?:/)) {
       return metadata.permalink;
     }
-    return '/react-native/' + metadata.permalink + '#content';
+    return metadata.permalink + '#content';
   },
 
   render: function() {
diff --git a/website/core/HeaderLinks.js b/website/core/HeaderLinks.js
index afee22f2406b..6feaa91940fb 100644
--- a/website/core/HeaderLinks.js
+++ b/website/core/HeaderLinks.js
@@ -14,11 +14,11 @@ var AlgoliaDocSearch = require('AlgoliaDocSearch');
 
 var HeaderLinks = React.createClass({
   linksInternal: [
-    {section: 'docs', href: '/react-native/docs/getting-started.html', text: 'Docs'},
-    {section: 'support', href: '/react-native/support.html', text: 'Support'},
+    {section: 'docs', href: 'docs/getting-started.html', text: 'Docs'},
+    {section: 'support', href: 'support.html', text: 'Support'},
     {section: 'releases', href: 'https://github.com/facebook/react-native/releases', text: 'Releases'},
     {section: 'newsletter', href: 'http://reactnative.cc', text: 'Newsletter'},
-    {section: 'showcase', href: '/react-native/showcase.html', text: 'Showcase'},
+    {section: 'showcase', href: 'showcase.html', text: 'Showcase'},
   ],
   linksExternal: [
     {section: 'github', href: 'https://github.com/facebook/react-native', text: 'GitHub'},
diff --git a/website/core/Site.js b/website/core/Site.js
index c1cdc5a129e4..183690e919de 100644
--- a/website/core/Site.js
+++ b/website/core/Site.js
@@ -11,9 +11,12 @@
 
 var React = require('React');
 var HeaderLinks = require('HeaderLinks');
+var Metadata = require('Metadata');
 
 var Site = React.createClass({
   render: function() {
+    const path = Metadata.config.RN_DEPLOYMENT_PATH;
+    var basePath = '/react-native/' + (path ? path + '/' : '');
     var title = this.props.title ? this.props.title + ' – ' : '';
     var currentYear = (new Date()).getFullYear();
     title += 'React Native | A framework for building native apps using React';
@@ -30,10 +33,12 @@ var Site = React.createClass({
           <meta property="og:image" content="http://facebook.github.io/react-native/img/opengraph.png?2" />
           <meta property="og:description" content="A framework for building native apps using React" />
 
+          <base href={basePath} />
+
           <link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.css" />
 
-          <link rel="shortcut icon" href="/react-native/img/favicon.png?2" />
-          <link rel="stylesheet" href="/react-native/css/react-native.css" />
+          <link rel="shortcut icon" href="img/favicon.png?2" />
+          <link rel="stylesheet" href="css/react-native.css" />
 
           <script type="text/javascript" src="//use.typekit.net/vqa1hcx.js"></script>
           <script type="text/javascript">{'try{Typekit.load();}catch(e){}'}</script>
@@ -43,8 +48,8 @@ var Site = React.createClass({
           <div className="container">
             <div className="nav-main">
               <div className="wrap">
-                <a className="nav-home" href="/react-native/">
-                  <img src="/react-native/img/header_logo.png" />
+                <a className="nav-home" href="">
+                  <img src="img/header_logo.png" />
                   React Native
                 </a>
                 <HeaderLinks section={this.props.section} />
@@ -72,7 +77,7 @@ var Site = React.createClass({
             fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");
           `}} />
           <script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.js"></script>
-          <script src="/react-native/js/scripts.js" />
+          <script src="js/scripts.js" />
         </body>
       </html>
     );
diff --git a/website/layout/AutodocsLayout.js b/website/layout/AutodocsLayout.js
index e0b493ae192e..cbf78db59db6 100644
--- a/website/layout/AutodocsLayout.js
+++ b/website/layout/AutodocsLayout.js
@@ -122,7 +122,7 @@ var ComponentDoc = React.createClass({
         </Header>
         {prop.deprecationMessage && <div className="deprecated">
           <div className="deprecatedTitle">
-            <img className="deprecatedIcon" src="/react-native/img/Warning.png" />
+            <img className="deprecatedIcon" src="img/Warning.png" />
             <span>Deprecated</span>
           </div>
           <div className="deprecatedMessage">
@@ -416,7 +416,7 @@ var EmbeddedSimulator = React.createClass({
       <div className="column-left">
         <p><a className="modal-button-open"><strong>Run this example</strong></a></p>
         <div className="modal-button-open modal-button-open-img">
-          <img alt="Run example in simulator" width="170" height="358" src="/react-native/img/alertIOS.png" />
+          <img alt="Run example in simulator" width="170" height="358" src="img/alertIOS.png" />
         </div>
         <Modal />
       </div>
diff --git a/website/package.json b/website/package.json
index a653d6b4d94f..37aa934f7b7f 100644
--- a/website/package.json
+++ b/website/package.json
@@ -1,6 +1,7 @@
 {
   "scripts": {
-    "start": "node server/server.js"
+    "start": "node server/server.js",
+    "gh-pages": "node publish-gh-pages.js"
   },
   "dependencies": {
     "bluebird": "^2.9.21",
@@ -14,6 +15,7 @@
     "react": "~0.13.0",
     "react-docgen": "^2.0.1",
     "react-page-middleware": "git://github.com/facebook/react-page-middleware.git",
-    "request": "latest"
+    "request": "latest",
+    "shelljs": "^0.6.0"
   }
 }
diff --git a/website/publish-android.sh b/website/publish-android.sh
deleted file mode 100755
index 0476036b35c4..000000000000
--- a/website/publish-android.sh
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/bin/bash
-
-# 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.
-
-# This script publishes to gh-pages of the private github repo.
-# It assumes you have a react-native-android-gh-pages folder next to your react-native-android folder.
-# You can clone that using:
-# git clone -b gh-pages git@github.com:facebook/react-native-android.git react-native-android-gh-pages
-
-set -e
-
-# Start in website/ even if run from root directory
-cd "$(dirname "$0")"
-
-cd ../../react-native-android-gh-pages
-git checkout -- .
-git clean -dfx
-git fetch
-git rebase
-rm -Rf *
-cd ../react-native-android/website
-node server/generate.js
-cp -R build/react-native/* ../../react-native-android-gh-pages/
-rm -Rf build/
-cd ../../react-native-android-gh-pages
-git status
-if ! git diff-index --quiet HEAD --; then
-  git add -A .
-  git commit -m "update website"
-  git push origin gh-pages
-fi
diff --git a/website/publish-gh-pages.js b/website/publish-gh-pages.js
new file mode 100644
index 000000000000..fc30181c03f8
--- /dev/null
+++ b/website/publish-gh-pages.js
@@ -0,0 +1,99 @@
+/**
+ * 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.
+ */
+'use strict';
+
+const CIRCLE_BRANCH = process.env.CIRCLE_BRANCH || '';
+const CIRCLE_PROJECT_USERNAME = process.env.CIRCLE_PROJECT_USERNAME;
+const CIRCLE_PROJECT_REPONAME = process.env.CIRCLE_PROJECT_REPONAME;
+const CI_PULL_REQUESTS = process.env.CI_PULL_REQUESTS;
+const CI_PULL_REQUEST = process.env.CI_PULL_REQUEST;
+const GIT_USER = process.env.GIT_USER;
+const remoteBranch = `https://${GIT_USER}@github.com/facebook/react-native.git`;
+require(`shelljs/global`);
+
+if (!which(`git`)) {
+  echo(`Sorry, this script requires git`);
+  exit(1);
+}
+
+let version;
+if (CIRCLE_BRANCH.indexOf(`-stable`) !== -1) {
+  version = CIRCLE_BRANCH.slice(0, CIRCLE_BRANCH.indexOf(`-stable`));
+} else if (CIRCLE_BRANCH === `master`) {
+  version = `next`;
+}
+
+rm(`-rf`, `build`);
+mkdir(`-p`, `build`);
+// if current commit is tagged "latest" we do a release to gh-pages root
+let currentCommit = exec(`git rev-parse HEAD`).stdout.trim();
+let latestTagCommit = exec(`git ls-remote origin latest`).stdout.split(/\s/)[0];
+
+if (!CI_PULL_REQUEST && CIRCLE_PROJECT_USERNAME === `facebook`) {
+  echo(`Building branch ${version}, preparing to push to gh-pages`);
+  // if code is running in a branch in CI, commit changes to gh-pages branch
+  cd(`build`);
+  rm(`-rf`, `react-native-gh-pages`);
+
+  if (exec(`git clone ${remoteBranch} react-native-gh-pages`).code !== 0) {
+    echo(`Error: Git clone failed`);
+    exit(1);
+  }
+
+  cd(`react-native-gh-pages`);
+
+  if (exec(`git checkout origin/gh-pages`).code +
+    exec(`git checkout -b gh-pages`).code +
+    exec(`git branch --set-upstream-to=origin/gh-pages`).code !== 0
+    ) {
+    echo(`Error: Git checkout gh-pages failed`);
+    exit(1);
+  }
+  // generate to releases/XX when branch name indicates that it is some sort of release
+  if (!!version) {
+    echo(`------------ DEPLOYING /releases/${version}`);
+    rm(`-rf`, `releases/${version}`);
+    mkdir(`-p`, `releases/${version}`);
+    cd(`../..`);
+    if (exec(`RN_DEPLOYMENT_PATH=releases/${version} node server/generate.js`).code !== 0) {
+      echo(`Error: Generating HTML failed`);
+      exit(1);
+    }
+    cd(`build/react-native-gh-pages`);
+    exec(`cp -R ../react-native/* releases/${version}`);
+  }
+  if (currentCommit === latestTagCommit) {
+    echo(`------------ DEPLOYING latest`);
+    // leave only releases folder
+    rm(`-rf`, ls(`*`).filter(name => name !== 'releases'));
+    cd(`../..`);
+    if (exec(`node server/generate.js`).code !== 0) {
+      echo(`Error: Generating HTML failed`);
+      exit(1);
+    }
+    cd(`build/react-native-gh-pages`);
+    exec(`cp -R ../react-native/* .`);
+  }
+  if (currentCommit === latestTagCommit || version) {
+    exec(`git status`);
+    exec(`git add -A .`);
+    if (exec(`git diff-index --quiet HEAD --`).code !== 0) {
+      if (exec(`git commit -m "Updated docs for ${version}"`).code !== 0) {
+        echo(`Error: Git commit gh-pages failed`);
+        exit(1);
+      }
+      if (exec(`git push origin gh-pages`).code !== 0) {
+        echo(`Error: Git push gh-pages failed`);
+        exit(1);
+      }
+    }
+    echo(`------------ gh-pages updated`);
+  }
+
+}
diff --git a/website/publish.sh b/website/publish.sh
deleted file mode 100755
index 28ec151e9e9a..000000000000
--- a/website/publish.sh
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/bin/bash
-
-# 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.
-
-set -e
-
-# Start in website/ even if run from root directory
-cd "$(dirname "$0")"
-
-cd ../../react-native-gh-pages
-git checkout -- .
-git clean -dfx
-git fetch
-git rebase
-rm -Rf *
-cd ../react-native/website
-node server/generate.js
-cp -R build/react-native/* ../../react-native-gh-pages/
-cp ../circle.yml ../../react-native-gh-pages/
-rm -Rf build/
-cd ../../react-native-gh-pages
-git status
-git add -A .
-if ! git diff-index --quiet HEAD --; then
-  git commit -m "update website"
-  git push origin gh-pages
-fi
-cd ../react-native/website
diff --git a/website/server/convert.js b/website/server/convert.js
index 62289e34cdde..c1096758c53c 100644
--- a/website/server/convert.js
+++ b/website/server/convert.js
@@ -125,6 +125,17 @@ function execute() {
     }
   });
 
+  // we need to pass globals for the components to be configurable
+  // metadata is generated in this process which has access to process.env
+  // but the web pages are generated in a sandbox context and have only access to CommonJS module files
+  metadatas.config = Object.create(null);
+  Object
+    .keys(process.env)
+    .filter(key => key.startsWith('RN_'))
+    .forEach((key) => {
+      metadatas.config[key] = process.env[key];
+    });
+
   fs.writeFileSync(
     'core/metadata.js',
     '/**\n' +
diff --git a/website/server/extractDocs.js b/website/server/extractDocs.js
index 6cbbc489f315..8fd0992314cb 100644
--- a/website/server/extractDocs.js
+++ b/website/server/extractDocs.js
@@ -267,7 +267,7 @@ var stylesForEmbed = [
 ];
 
 var polyfills = [
-  '../Libraries/GeoLocation/Geolocation.js',
+  '../Libraries/Geolocation/Geolocation.js',
 ];
 
 var all = components
diff --git a/website/server/generate.js b/website/server/generate.js
index ab59a51ad048..dc96e2e8de8d 100644
--- a/website/server/generate.js
+++ b/website/server/generate.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.
  */
+'use strict';
 
 var Promise = require('bluebird');
 var request = require('request');
@@ -56,7 +57,7 @@ glob('src/**/*.*', function(er, files) {
   });
 
   queue = queue.then(function() {
-    console.log('It is live at: http://facebook.github.io/react-native/');
+    console.log('Generated HTML files from JS');
   }).finally(function() {
     server.close();
   }).catch(function(e) {
diff --git a/website/src/react-native/circle.yml b/website/src/react-native/circle.yml
new file mode 100644
index 000000000000..56ad41b2f149
--- /dev/null
+++ b/website/src/react-native/circle.yml
@@ -0,0 +1,4 @@
+general:
+  branches:
+    ignore:
+      - gh-pages
diff --git a/website/src/react-native/css/react-native.css b/website/src/react-native/css/react-native.css
index 83cf44113d98..59b4fa3391e5 100644
--- a/website/src/react-native/css/react-native.css
+++ b/website/src/react-native/css/react-native.css
@@ -1276,7 +1276,7 @@ input#algolia-doc-search {
   font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
   font-family: proxima-nova, "Helvetica Neue", Helvetica, Arial, sans-serif;
 
-  background: transparent url('/react-native/img/search.png') no-repeat left center;
+  background: transparent url('../img/search.png') no-repeat left center;
   background-size: 16px 16px;
 
   padding-left: 30px;
diff --git a/website/src/react-native/index.js b/website/src/react-native/index.js
index 919b799aeeb4..84dcbf26f257 100644
--- a/website/src/react-native/index.js
+++ b/website/src/react-native/index.js
@@ -89,7 +89,7 @@ var App = React.createClass({
           <p>
             See <a href="docs/debugging.html#content">Debugging</a>.
           </p>
-          <img src="/react-native/img/chrome_breakpoint.png" width="800" height="443" />
+          <img src="img/chrome_breakpoint.png" width="800" height="443" />
 
           <h2>Touch Handling</h2>
           <p>

From 228a1fe7d48d57a0fbb2d852135ef94247198aaa Mon Sep 17 00:00:00 2001
From: Andrei Coman <andreic@fb.com>
Date: Thu, 11 Feb 2016 06:32:40 -0800
Subject: [PATCH 1128/1411] Expose screen metrics and window metrics

Summary:
public
https://github.com/facebook/react-native/pull/4935 changed the window dimensions for android by replacing them with the actual screen dimensions. This changes the window dimensions back to their original values and adds `Dimensions.get('screen')` for the actual screen dimensions of the device.

Reviewed By: astreet

Differential Revision: D2921584

fb-gh-sync-id: 5d2677029c71d50691691dc651a11e9c8b115e8f
shipit-source-id: 5d2677029c71d50691691dc651a11e9c8b115e8f
---
 Libraries/Utilities/Dimensions.js             | 15 +++++++++
 .../react/ReactInstanceManagerImpl.java       | 18 +++++-----
 .../com/facebook/react/ReactRootView.java     |  4 +--
 .../react/uimanager/DisplayMetricsHolder.java | 33 ++++++++++++++++---
 .../facebook/react/uimanager/PixelUtil.java   |  6 ++--
 .../uimanager/UIManagerModuleConstants.java   | 17 ++++++++--
 .../react/views/art/ARTVirtualNode.java       |  3 +-
 .../java/com/facebook/react/RootViewTest.java |  2 +-
 .../LayoutPropertyApplicatorTest.java         |  8 +++--
 .../uimanager/ReactPropConstantsTest.java     |  3 +-
 .../UIManagerModuleConstantsTest.java         |  3 +-
 .../react/uimanager/UIManagerModuleTest.java  |  3 +-
 .../views/image/ReactImagePropertyTest.java   |  4 +--
 .../react/views/text/ReactTextTest.java       |  3 +-
 .../textinput/ReactTextInputPropertyTest.java |  2 +-
 .../react/views/textinput/TextInputTest.java  |  3 +-
 16 files changed, 93 insertions(+), 34 deletions(-)

diff --git a/Libraries/Utilities/Dimensions.js b/Libraries/Utilities/Dimensions.js
index 93e2cc21aa15..f73853473dc2 100644
--- a/Libraries/Utilities/Dimensions.js
+++ b/Libraries/Utilities/Dimensions.js
@@ -11,6 +11,7 @@
  */
 'use strict';
 
+var Platform = require('Platform');
 var UIManager = require('UIManager');
 
 var invariant = require('invariant');
@@ -31,7 +32,21 @@ if (dimensions && dimensions.windowPhysicalPixels) {
     scale: windowPhysicalPixels.scale,
     fontScale: windowPhysicalPixels.fontScale,
   };
+  if (Platform.OS === 'android') {
+    // Screen and window dimensions are different on android
+    var screenPhysicalPixels = dimensions.screenPhysicalPixels;
+    dimensions.screen = {
+      width: screenPhysicalPixels.width / screenPhysicalPixels.scale,
+      height: screenPhysicalPixels.height / screenPhysicalPixels.scale,
+      scale: screenPhysicalPixels.scale,
+      fontScale: screenPhysicalPixels.fontScale,
+    };
 
+    // delete so no callers rely on this existing
+    delete dimensions.screenPhysicalPixels;
+  } else {
+    dimensions.screen = dimensions.window;
+  }
   // delete so no callers rely on this existing
   delete dimensions.windowPhysicalPixels;
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index a92b151e1d17..a6a69810e5e3 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -308,8 +308,11 @@ private static void initializeSoLoaderIfNecessary(Context applicationContext) {
   }
 
   private static void setDisplayMetrics(Context context) {
-    DisplayMetrics displayMetrics = new DisplayMetrics();
-    displayMetrics.setTo(context.getResources().getDisplayMetrics());
+    DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+    DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics);
+
+    DisplayMetrics screenDisplayMetrics = new DisplayMetrics();
+    screenDisplayMetrics.setTo(displayMetrics);
     WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
     Display display = wm.getDefaultDisplay();
 
@@ -317,9 +320,8 @@ private static void setDisplayMetrics(Context context) {
     // The real metrics include system decor elements (e.g. soft menu bar).
     //
     // See: http://developer.android.com/reference/android/view/Display.html#getRealMetrics(android.util.DisplayMetrics)
-    if (Build.VERSION.SDK_INT >= 17){
-      display.getRealMetrics(displayMetrics);
-
+    if (Build.VERSION.SDK_INT >= 17) {
+      display.getRealMetrics(screenDisplayMetrics);
     } else {
       // For 14 <= API level <= 16, we need to invoke getRawHeight and getRawWidth to get the real dimensions.
       // Since react-native only supports API level 16+ we don't have to worry about other cases.
@@ -330,13 +332,13 @@ private static void setDisplayMetrics(Context context) {
       try {
         Method mGetRawH = Display.class.getMethod("getRawHeight");
         Method mGetRawW = Display.class.getMethod("getRawWidth");
-        displayMetrics.widthPixels = (Integer) mGetRawW.invoke(display);
-        displayMetrics.heightPixels = (Integer) mGetRawH.invoke(display);
+        screenDisplayMetrics.widthPixels = (Integer) mGetRawW.invoke(display);
+        screenDisplayMetrics.heightPixels = (Integer) mGetRawH.invoke(display);
       } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
         throw new RuntimeException("Error getting real dimensions for API level < 17", e);
       }
     }
-    DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
+    DisplayMetricsHolder.setScreenDisplayMetrics(screenDisplayMetrics);
   }
 
   /**
diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
index 2271b20fd46a..300be54bcfcf 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
@@ -390,7 +390,7 @@ private KeyboardListener getKeyboardListener() {
   private class KeyboardListener implements ViewTreeObserver.OnGlobalLayoutListener {
     private final Rect mVisibleViewArea;
     private final int mMinKeyboardHeightDetected;
-    
+
     private int mKeyboardHeight = 0;
 
     /* package */ KeyboardListener() {
@@ -410,7 +410,7 @@ public void onGlobalLayout() {
 
       getRootView().getWindowVisibleDisplayFrame(mVisibleViewArea);
       final int heightDiff =
-          DisplayMetricsHolder.getDisplayMetrics().heightPixels - mVisibleViewArea.bottom;
+          DisplayMetricsHolder.getWindowDisplayMetrics().heightPixels - mVisibleViewArea.bottom;
       if (mKeyboardHeight != heightDiff && heightDiff > mMinKeyboardHeightDetected) {
         // keyboard is now showing, or the keyboard height has changed
         mKeyboardHeight = heightDiff;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/DisplayMetricsHolder.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/DisplayMetricsHolder.java
index 18135146eeec..c465073f81a1 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/DisplayMetricsHolder.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/DisplayMetricsHolder.java
@@ -14,16 +14,39 @@
 /**
  * Holds an instance of the current DisplayMetrics so we don't have to thread it through all the
  * classes that need it.
+ * Note: windowDisplayMetrics are deprecated in favor of ScreenDisplayMetrics: window metrics
+ * are supposed to return the drawable area but there's no guarantee that they correspond to the
+ * actual size of the {@link ReactRootView}. Moreover, they are not consistent with what iOS
+ * returns. Screen metrics returns the metrics of the entire screen, is consistent with iOS and
+ * should be used instead.
  */
 public class DisplayMetricsHolder {
 
-  private static DisplayMetrics sCurrentDisplayMetrics;
+  private static DisplayMetrics sWindowDisplayMetrics;
+  private static DisplayMetrics sScreenDisplayMetrics;
 
-  public static void setDisplayMetrics(DisplayMetrics displayMetrics) {
-    sCurrentDisplayMetrics = displayMetrics;
+  /**
+   * @deprecated Use {@link #setScreenDisplayMetrics(DisplayMetrics)} instead. See comment above as
+   *    to why this is not correct to use.
+   */
+  public static void setWindowDisplayMetrics(DisplayMetrics displayMetrics) {
+    sWindowDisplayMetrics = displayMetrics;
   }
 
-  public static DisplayMetrics getDisplayMetrics() {
-    return sCurrentDisplayMetrics;
+  /**
+   * @deprecated Use {@link #getScreenDisplayMetrics()} instead. See comment above as to why this
+   *    is not correct to use.
+   */
+  @Deprecated
+  public static DisplayMetrics getWindowDisplayMetrics() {
+    return sWindowDisplayMetrics;
+  }
+
+  public static void setScreenDisplayMetrics(DisplayMetrics screenDisplayMetrics) {
+    sScreenDisplayMetrics = screenDisplayMetrics;
+  }
+
+  public static DisplayMetrics getScreenDisplayMetrics() {
+    return sScreenDisplayMetrics;
   }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/PixelUtil.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/PixelUtil.java
index bcb24667fc5d..6a3ecd0a5929 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/PixelUtil.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/PixelUtil.java
@@ -23,7 +23,7 @@ public static float toPixelFromDIP(float value) {
     return TypedValue.applyDimension(
         TypedValue.COMPLEX_UNIT_DIP,
         value,
-        DisplayMetricsHolder.getDisplayMetrics());
+        DisplayMetricsHolder.getWindowDisplayMetrics());
   }
 
   /**
@@ -40,7 +40,7 @@ public static float toPixelFromSP(float value) {
     return TypedValue.applyDimension(
         TypedValue.COMPLEX_UNIT_SP,
         value,
-        DisplayMetricsHolder.getDisplayMetrics());
+        DisplayMetricsHolder.getWindowDisplayMetrics());
   }
 
   /**
@@ -54,7 +54,7 @@ public static float toPixelFromSP(double value) {
    * Convert from PX to DP
    */
   public static float toDIPFromPixel(float value) {
-    return value / DisplayMetricsHolder.getDisplayMetrics().density;
+    return value / DisplayMetricsHolder.getWindowDisplayMetrics().density;
   }
 
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java
index 8981d4354d2a..b8363917e12c 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java
@@ -91,7 +91,8 @@ public static Map<String, Object> getConstants() {
                 "ScaleAspectFill",
                 ImageView.ScaleType.CENTER_CROP.ordinal())));
 
-    DisplayMetrics displayMetrics = DisplayMetricsHolder.getDisplayMetrics();
+    DisplayMetrics displayMetrics = DisplayMetricsHolder.getWindowDisplayMetrics();
+    DisplayMetrics screenDisplayMetrics = DisplayMetricsHolder.getScreenDisplayMetrics();
     constants.put(
         "Dimensions",
         MapBuilder.of(
@@ -106,7 +107,19 @@ public static Map<String, Object> getConstants() {
                 "fontScale",
                 displayMetrics.scaledDensity,
                 "densityDpi",
-                displayMetrics.densityDpi)));
+                displayMetrics.densityDpi),
+        "screenPhysicalPixels",
+        MapBuilder.of(
+            "width",
+            screenDisplayMetrics.widthPixels,
+            "height",
+            screenDisplayMetrics.heightPixels,
+            "scale",
+            screenDisplayMetrics.density,
+            "fontScale",
+            screenDisplayMetrics.scaledDensity,
+            "densityDpi",
+            screenDisplayMetrics.densityDpi)));
 
     constants.put(
         "StyleConstants",
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTVirtualNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTVirtualNode.java
index 289ad0b98515..70dc6faaf2af 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTVirtualNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTVirtualNode.java
@@ -17,7 +17,6 @@
 
 import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
 import com.facebook.react.bridge.ReadableArray;
-import com.facebook.react.uimanager.ReactStylesDiffMap;
 import com.facebook.react.uimanager.DisplayMetricsHolder;
 import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.ReactShadowNode;
@@ -39,7 +38,7 @@ public abstract class ARTVirtualNode extends ReactShadowNode {
   protected final float mScale;
 
   public ARTVirtualNode() {
-    mScale = DisplayMetricsHolder.getDisplayMetrics().density;
+    mScale = DisplayMetricsHolder.getWindowDisplayMetrics().density;
   }
 
   @Override
diff --git a/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java b/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java
index 7f3d96f30b1a..97e9d6e5392a 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java
@@ -82,7 +82,7 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
     mReactContext = new ReactApplicationContext(RuntimeEnvironment.application);
     mReactContext.initializeWithInstance(mCatalystInstanceMock);
     DisplayMetrics displayMetrics = mReactContext.getResources().getDisplayMetrics();
-    DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
+    DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics);
 
     UIManagerModule uiManagerModuleMock = mock(UIManagerModule.class);
     when(mCatalystInstanceMock.getNativeModule(UIManagerModule.class))
diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/LayoutPropertyApplicatorTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/LayoutPropertyApplicatorTest.java
index 5da10ac938e7..f1944ec12258 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/uimanager/LayoutPropertyApplicatorTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/LayoutPropertyApplicatorTest.java
@@ -54,12 +54,14 @@ public class LayoutPropertyApplicatorTest {
 
   @Before
   public void setup() {
-    DisplayMetricsHolder.setDisplayMetrics(new DisplayMetrics());
+    DisplayMetricsHolder.setWindowDisplayMetrics(new DisplayMetrics());
+    DisplayMetricsHolder.setScreenDisplayMetrics(new DisplayMetrics());
   }
 
   @After
   public void teardown() {
-    DisplayMetricsHolder.setDisplayMetrics(null);
+    DisplayMetricsHolder.setWindowDisplayMetrics(null);
+    DisplayMetricsHolder.setScreenDisplayMetrics(null);
   }
 
   public ReactStylesDiffMap buildStyles(Object... keysAndValues) {
@@ -309,7 +311,7 @@ public void testEnumerations() {
   public void testPropertiesResetToDefault() {
     DisplayMetrics displayMetrics = new DisplayMetrics();
     displayMetrics.density = 1.0f;
-    DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
+    DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics);
 
     LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode());
     ReactStylesDiffMap map = buildStyles(
diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropConstantsTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropConstantsTest.java
index 641e299920cb..bcc930fa63a8 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropConstantsTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropConstantsTest.java
@@ -147,7 +147,8 @@ public void testNativePropsIncludeCorrectTypes() {
     List<ViewManager> viewManagers = Arrays.<ViewManager>asList(new ViewManagerUnderTest());
     ReactApplicationContext reactContext = new ReactApplicationContext(RuntimeEnvironment.application);
     DisplayMetrics displayMetrics = reactContext.getResources().getDisplayMetrics();
-    DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
+    DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics);
+    DisplayMetricsHolder.setScreenDisplayMetrics(displayMetrics);
     UIManagerModule uiManagerModule = new UIManagerModule(
         reactContext,
         viewManagers,
diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleConstantsTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleConstantsTest.java
index 2652422e9834..0f8b7ec9195e 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleConstantsTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleConstantsTest.java
@@ -60,7 +60,8 @@ public void setUp() {
     mUIImplementation = mock(UIImplementation.class);
 
     DisplayMetrics displayMetrics = mReactContext.getResources().getDisplayMetrics();
-    DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
+    DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics);
+    DisplayMetricsHolder.setScreenDisplayMetrics(displayMetrics);
   }
 
   @Test
diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java
index d409752caf8a..3b9cd770647b 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java
@@ -109,7 +109,8 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
     mReactContext.initializeWithInstance(mCatalystInstanceMock);
 
     DisplayMetrics displayMetrics = mReactContext.getResources().getDisplayMetrics();
-    DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
+    DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics);
+    DisplayMetricsHolder.setScreenDisplayMetrics(displayMetrics);
 
     UIManagerModule uiManagerModuleMock = mock(UIManagerModule.class);
     when(mCatalystInstanceMock.getNativeModule(UIManagerModule.class))
diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/image/ReactImagePropertyTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/image/ReactImagePropertyTest.java
index c029d4653e32..186e4dca4fe9 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/views/image/ReactImagePropertyTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/views/image/ReactImagePropertyTest.java
@@ -59,12 +59,12 @@ public void setup() {
     mContext.initializeWithInstance(mCatalystInstanceMock);
     mThemeContext = new ThemedReactContext(mContext, mContext);
     Fresco.initialize(mContext);
-    DisplayMetricsHolder.setDisplayMetrics(new DisplayMetrics());
+    DisplayMetricsHolder.setWindowDisplayMetrics(new DisplayMetrics());
   }
 
   @After
   public void teardown() {
-    DisplayMetricsHolder.setDisplayMetrics(null);
+    DisplayMetricsHolder.setWindowDisplayMetrics(null);
   }
 
   public ReactStylesDiffMap buildStyles(Object... keysAndValues) {
diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java
index f23128ab3dd5..68734c4a502a 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java
@@ -373,7 +373,8 @@ private void executePendingChoreographerCallbacks() {
   public UIManagerModule getUIManagerModule() {
     ReactApplicationContext reactContext = ReactTestHelper.createCatalystContextForTest();
     DisplayMetrics displayMetrics = reactContext.getResources().getDisplayMetrics();
-    DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
+    DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics);
+    DisplayMetricsHolder.setScreenDisplayMetrics(displayMetrics);
     List<ViewManager> viewManagers = Arrays.asList(
         new ViewManager[] {
             new ReactTextViewManager(),
diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.java
index 08489bbc0257..5be0d0a79949 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.java
@@ -60,7 +60,7 @@ public void setup() {
     mContext.initializeWithInstance(mCatalystInstanceMock);
     mThemedContext = new ThemedReactContext(mContext, mContext);
     mManager = new ReactTextInputManager();
-    DisplayMetricsHolder.setDisplayMetrics(new DisplayMetrics());
+    DisplayMetricsHolder.setWindowDisplayMetrics(new DisplayMetrics());
   }
 
   public ReactStylesDiffMap buildStyles(Object... keysAndValues) {
diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java
index ef89b7df0029..630c80a723a9 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java
@@ -183,7 +183,8 @@ public UIManagerModule getUIManagerModule() {
             new ReactTextInputManager(),
         });
     DisplayMetrics displayMetrics = reactContext.getResources().getDisplayMetrics();
-    DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
+    DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics);
+    DisplayMetricsHolder.setScreenDisplayMetrics(displayMetrics);
     UIManagerModule uiManagerModule = new UIManagerModule(
         reactContext,
         viewManagers,

From 7d7508e25b353ba12727525ee4d70d8884c0bc22 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Thu, 11 Feb 2016 08:08:52 -0800
Subject: [PATCH 1129/1411] Fixed a wrong github user used for deployment of
 gh-pages

Reviewed By: mkonicek

Differential Revision: D2927075

fb-gh-sync-id: b3a7d1541d11d7d9ebf01f72dac48847750968f8
shipit-source-id: b3a7d1541d11d7d9ebf01f72dac48847750968f8
---
 circle.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/circle.yml b/circle.yml
index 7d396cc43eef..589a7c9a9d91 100644
--- a/circle.yml
+++ b/circle.yml
@@ -78,4 +78,4 @@ deployment:
       - git config --global user.email "bestnader@fb.com"
       - git config --global user.name "Website Deployment Script"
       - echo "machine github.com login reactjs-bot password $GITHUB_TOKEN" > ~/.netrc
-      - cd website && GIT_USER=bestander npm run gh-pages
+      - cd website && GIT_USER=reactjs-bot npm run gh-pages

From 8e9b70aa86137d4af940ae9049aea117750ff5ce Mon Sep 17 00:00:00 2001
From: Martin Konicek <martin.konicek@gmail.com>
Date: Thu, 11 Feb 2016 08:31:45 -0800
Subject: [PATCH 1130/1411] Bot testing: Update TicTacToeApp.js

Summary:
Just testing the shipit bot
Closes https://github.com/facebook/react-native/pull/5843

Reviewed By: svcscm

Differential Revision: D2917790

Pulled By: mkonicek

fb-gh-sync-id: f73a9bf3aee82d1074f68d650f2bf30ac720a66d
shipit-source-id: f73a9bf3aee82d1074f68d650f2bf30ac720a66d
---
 Examples/TicTacToe/TicTacToeApp.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Examples/TicTacToe/TicTacToeApp.js b/Examples/TicTacToe/TicTacToeApp.js
index 6d5c460cbea3..3b562194a044 100755
--- a/Examples/TicTacToe/TicTacToeApp.js
+++ b/Examples/TicTacToe/TicTacToeApp.js
@@ -305,7 +305,7 @@ var styles = StyleSheet.create({
     textAlign: 'center',
   },
   newGame: {
-    backgroundColor: '#887766',
+    backgroundColor: '#887765',
     padding: 20,
     borderRadius: 5,
   },

From 8720d4bc76892f574b29148f34f9602da07efb6f Mon Sep 17 00:00:00 2001
From: Felix Oghina <foghina@fb.com>
Date: Thu, 11 Feb 2016 13:34:09 -0800
Subject: [PATCH 1131/1411] strip devsupport from prod builds

Reviewed By: zen

Differential Revision: D2912192

fb-gh-sync-id: ff89fc16dcd86481657197055e31d2b67a94e7ea
shipit-source-id: ff89fc16dcd86481657197055e31d2b67a94e7ea
---
 .../react/ReactInstanceManagerImpl.java       | 17 ++---
 .../devsupport/DevSupportManagerFactory.java  | 62 +++++++++++++++++++
 2 files changed, 68 insertions(+), 11 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerFactory.java

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index a6a69810e5e3..c4f550495d84 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -58,8 +58,7 @@
 import com.facebook.react.common.annotations.VisibleForTesting;
 import com.facebook.react.devsupport.DevServerHelper;
 import com.facebook.react.devsupport.DevSupportManager;
-import com.facebook.react.devsupport.DevSupportManagerImpl;
-import com.facebook.react.devsupport.DisabledDevSupportManager;
+import com.facebook.react.devsupport.DevSupportManagerFactory;
 import com.facebook.react.devsupport.ReactInstanceDevCommandsHandler;
 import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
 import com.facebook.react.modules.core.DeviceEventManagerModule;
@@ -275,15 +274,11 @@ public T get() throws Exception {
     mJSMainModuleName = jsMainModuleName;
     mPackages = packages;
     mUseDeveloperSupport = useDeveloperSupport;
-    if (mUseDeveloperSupport) {
-      mDevSupportManager = new DevSupportManagerImpl(
-          applicationContext,
-          mDevInterface,
-          mJSMainModuleName,
-          useDeveloperSupport);
-    } else {
-      mDevSupportManager = new DisabledDevSupportManager();
-    }
+    mDevSupportManager = DevSupportManagerFactory.create(
+        applicationContext,
+        mDevInterface,
+        mJSMainModuleName,
+        useDeveloperSupport);
     mBridgeIdleDebugListener = bridgeIdleDebugListener;
     mLifecycleState = initialLifecycleState;
     mUIImplementationProvider = uiImplementationProvider;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerFactory.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerFactory.java
new file mode 100644
index 000000000000..22d925672598
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerFactory.java
@@ -0,0 +1,62 @@
+package com.facebook.react.devsupport;
+
+import javax.annotation.Nullable;
+
+import java.lang.reflect.Constructor;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.facebook.react.common.ReactConstants;
+import com.facebook.react.common.build.ReactBuildConfig;
+
+/**
+ * A simple factory that creates instances of {@link DevSupportManager} implementations. Uses
+ * reflection to create DevSupportManagerImpl if it exists. This allows ProGuard to strip that class
+ * and its dependencies in release builds. If the class isn't found,
+ * {@link DisabledDevSupportManager} is returned instead.
+ */
+public class DevSupportManagerFactory {
+
+  private static final String DEVSUPPORT_IMPL_PACKAGE = "com.facebook.react.devsupport";
+  private static final String DEVSUPPORT_IMPL_CLASS = "DevSupportManagerImpl";
+
+  public static DevSupportManager create(
+      Context applicationContext,
+      ReactInstanceDevCommandsHandler reactInstanceCommandsHandler,
+      @Nullable String packagerPathForJSBundleName,
+      boolean enableOnCreate) {
+    if (!enableOnCreate) {
+      return new DisabledDevSupportManager();
+    }
+    try {
+      // ProGuard is surprisingly smart in this case and will keep a class if it detects a call to
+      // Class.forName() with a static string. So instead we generate a quasi-dynamic string to
+      // confuse it.
+      String className =
+          new StringBuilder(DEVSUPPORT_IMPL_PACKAGE)
+              .append(".")
+              .append(DEVSUPPORT_IMPL_CLASS)
+              .toString();
+      Class<?> devSupportManagerClass =
+          Class.forName(className);
+      Constructor constructor =
+          devSupportManagerClass.getConstructor(
+              Context.class,
+              ReactInstanceDevCommandsHandler.class,
+              String.class,
+              boolean.class);
+      return (DevSupportManager) constructor.newInstance(
+          applicationContext,
+          reactInstanceCommandsHandler,
+          packagerPathForJSBundleName,
+          true);
+    } catch (Exception e) {
+      throw new RuntimeException(
+          "Requested enabled DevSupportManager, but DevSupportManagerImpl class was not found" +
+              " or could not be created",
+          e);
+    }
+  }
+
+}

From 5ca9245067b49738e376632580cf2799358d526a Mon Sep 17 00:00:00 2001
From: Hedger Wang <hedger@fb.com>
Date: Thu, 11 Feb 2016 22:27:08 -0800
Subject: [PATCH 1132/1411] stop wanring about using `onWillFocus` and
 `onDidFocus`.

Reviewed By: chaceliang

Differential Revision: D2925643

fb-gh-sync-id: d12b774b5c43d5369e2c02832d80541b2534fba6
shipit-source-id: d12b774b5c43d5369e2c02832d80541b2534fba6
---
 Libraries/CustomComponents/Navigator/Navigator.js | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/Libraries/CustomComponents/Navigator/Navigator.js b/Libraries/CustomComponents/Navigator/Navigator.js
index af1ceb2a4c08..095a4efd57f1 100644
--- a/Libraries/CustomComponents/Navigator/Navigator.js
+++ b/Libraries/CustomComponents/Navigator/Navigator.js
@@ -227,19 +227,13 @@ var Navigator = React.createClass({
     /**
      * Will emit the target route upon mounting and before each nav transition
      */
-    onWillFocus: deprecatedPropType(
-      PropTypes.func,
-      "Use `navigationContext.addListener('willfocus', callback)` instead."
-    ),
+    onWillFocus: PropTypes.func,
 
     /**
      * Will be called with the new route of each scene after the transition is
      * complete or after the initial mounting
      */
-    onDidFocus: deprecatedPropType(
-      PropTypes.func,
-      "Use `navigationContext.addListener('didfocus', callback)` instead."
-    ),
+    onDidFocus: PropTypes.func,
 
     /**
      * Optionally provide a navigation bar that persists across scene

From 065106678f249a1474118aecfea48928d66e834f Mon Sep 17 00:00:00 2001
From: Olivier Notteghem <oli@fb.com>
Date: Fri, 12 Feb 2016 00:04:28 -0800
Subject: [PATCH 1133/1411] Reset the animation config at the end of each batch

Reviewed By: sahrens

Differential Revision: D2931343

fb-gh-sync-id: 702b1df543fbdb9b244eb6cc2ce4d8557471004f
shipit-source-id: 702b1df543fbdb9b244eb6cc2ce4d8557471004f
---
 .../com/facebook/react/uimanager/UIViewOperationQueue.java | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
index 104e247b5e6c..9b2d81057740 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
@@ -673,6 +673,10 @@ public void run() {
                      operations.get(i).execute();
                    }
                  }
+
+                 // Clear layout animation, as animation only apply to current UI operations batch.
+                 mNativeViewHierarchyManager.clearLayoutAnimation();
+
                  if (mViewHierarchyUpdateDebugListener != null) {
                    mViewHierarchyUpdateDebugListener.onViewHierarchyUpdateFinished();
                  }
@@ -723,9 +727,6 @@ public void doFrameGuarded(long frameTimeNanos) {
           mDispatchUIRunnables.get(i).run();
         }
         mDispatchUIRunnables.clear();
-
-        // Clear layout animation, as animation only apply to current UI operations batch.
-        mNativeViewHierarchyManager.clearLayoutAnimation();
       }
 
       ReactChoreographer.getInstance().postFrameCallback(

From 3e72211cab9fe590254f73804a560639398932ba Mon Sep 17 00:00:00 2001
From: Olivier Notteghem <oli@fb.com>
Date: Fri, 12 Feb 2016 00:11:33 -0800
Subject: [PATCH 1134/1411] fix 'create' animation pivot to be relative to
 center of component

Reviewed By: sahrens

Differential Revision: D2931318

fb-gh-sync-id: b95ab0b5631f1780dab065b58340f25a274d0df9
shipit-source-id: b95ab0b5631f1780dab065b58340f25a274d0df9
---
 .../react/uimanager/layoutanimation/BaseLayoutAnimation.java  | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/BaseLayoutAnimation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/BaseLayoutAnimation.java
index 9d3d0f45aa79..f3c846864d1e 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/BaseLayoutAnimation.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/BaseLayoutAnimation.java
@@ -34,9 +34,9 @@ Animation createAnimationImpl(View view, int x, int y, int width, int height) {
               toValue,
               fromValue,
               toValue,
-              Animation.RELATIVE_TO_PARENT,
+              Animation.RELATIVE_TO_SELF,
               .5f,
-              Animation.RELATIVE_TO_PARENT,
+              Animation.RELATIVE_TO_SELF,
               .5f);
         default:
           throw new IllegalViewOperationException(

From 8f363a3f5f1661ccd3b939a7fb1eef2b9052bbe3 Mon Sep 17 00:00:00 2001
From: Kevin Johnson <kevinejohn@gmail.com>
Date: Fri, 12 Feb 2016 02:21:27 -0800
Subject: [PATCH 1135/1411] This is supposed to say LifecycleEventListener

Reviewed By: svcscm

Differential Revision: D2931715

fb-gh-sync-id: 450c4fc13a87eaba39d06835aa851d7256da7125
shipit-source-id: 450c4fc13a87eaba39d06835aa851d7256da7125
---
 docs/NativeModulesAndroid.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/NativeModulesAndroid.md b/docs/NativeModulesAndroid.md
index bd86b8217f8c..02281b2788bc 100644
--- a/docs/NativeModulesAndroid.md
+++ b/docs/NativeModulesAndroid.md
@@ -401,7 +401,7 @@ public class ImagePickerModule extends ReactContextBaseJavaModule implements Act
 
 ### Listening to LifeCycle events
 
-Listening to the activity's LifeCycle events such as `onResume`, `onPause` etc. is very similar to how we implemented `ActivityEventListener`. The module must implement `ActivityEventListener`. Then, you need to register a listener in the module's constructor,
+Listening to the activity's LifeCycle events such as `onResume`, `onPause` etc. is very similar to how we implemented `ActivityEventListener`. The module must implement `LifecycleEventListener`. Then, you need to register a listener in the module's constructor,
 
 ```java
 reactContext.addLifecycleEventListener(this);

From 84f51da123737d85c1eb9d8db0683a665411c05a Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Fri, 12 Feb 2016 03:49:51 -0800
Subject: [PATCH 1136/1411] Make JS async always the top thread in systrace

Reviewed By: tadeuzagallo

Differential Revision: D2905828

fb-gh-sync-id: b64cbe6b41771dc94d8d7e6d3610af845b4383f0
shipit-source-id: b64cbe6b41771dc94d8d7e6d3610af845b4383f0
---
 React/Executors/RCTJSCExecutor.h |  5 +++++
 React/Executors/RCTJSCExecutor.m |  4 +++-
 React/Profiler/RCTProfile.m      | 16 +++++++++++++++-
 3 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/React/Executors/RCTJSCExecutor.h b/React/Executors/RCTJSCExecutor.h
index cbcf224fcd8a..b34218f2b472 100644
--- a/React/Executors/RCTJSCExecutor.h
+++ b/React/Executors/RCTJSCExecutor.h
@@ -11,6 +11,11 @@
 
 #import "RCTJavaScriptExecutor.h"
 
+/**
+ * Default name for the JS thread
+ */
+RCT_EXTERN NSString *const RCTJSCThreadName;
+
 /**
  * Uses a JavaScriptCore context as the execution engine.
  */
diff --git a/React/Executors/RCTJSCExecutor.m b/React/Executors/RCTJSCExecutor.m
index f96d2992a9c3..176bffe87779 100644
--- a/React/Executors/RCTJSCExecutor.m
+++ b/React/Executors/RCTJSCExecutor.m
@@ -26,6 +26,8 @@
 #import "RCTRedBox.h"
 #import "RCTSourceCode.h"
 
+NSString *const RCTJSCThreadName = @"com.facebook.React.JavaScript";
+
 static NSString *const RCTJSCProfilerEnabledDefaultsKey = @"RCTJSCProfilerEnabled";
 
 @interface RCTJavaScriptContext : NSObject <RCTInvalidating>
@@ -172,7 +174,7 @@ - (instancetype)init
   NSThread *javaScriptThread = [[NSThread alloc] initWithTarget:[self class]
                                                        selector:@selector(runRunLoopThread)
                                                          object:nil];
-  javaScriptThread.name = @"com.facebook.React.JavaScript";
+  javaScriptThread.name = RCTJSCThreadName;
 
   if ([javaScriptThread respondsToSelector:@selector(setQualityOfService:)]) {
     [javaScriptThread setQualityOfService:NSOperationQualityOfServiceUserInteractive];
diff --git a/React/Profiler/RCTProfile.m b/React/Profiler/RCTProfile.m
index 32f63e91658c..6ed1e0f7d89b 100644
--- a/React/Profiler/RCTProfile.m
+++ b/React/Profiler/RCTProfile.m
@@ -27,6 +27,7 @@
 #import "RCTModuleData.h"
 #import "RCTUtils.h"
 #import "RCTUIManager.h"
+#import "RCTJSCExecutor.h"
 
 NSString *const RCTProfileDidStartProfiling = @"RCTProfileDidStartProfiling";
 NSString *const RCTProfileDidEndProfiling = @"RCTProfileDidEndProfiling";
@@ -372,7 +373,6 @@ BOOL RCTProfileIsProfiling(void)
 void RCTProfileInit(RCTBridge *bridge)
 {
   // TODO: enable assert JS thread from any file (and assert here)
-
   if (RCTProfileIsProfiling()) {
     return;
   }
@@ -395,6 +395,20 @@ void RCTProfileInit(RCTBridge *bridge)
     });
   }
 
+  // Set up thread ordering
+  dispatch_async(RCTProfileGetQueue(), ^{
+    NSString *shadowQueue = @(dispatch_queue_get_label([[bridge uiManager] methodQueue]));
+    NSArray *orderedThreads = @[@"JS async", RCTJSCThreadName, shadowQueue, @"main"];
+    [orderedThreads enumerateObjectsUsingBlock:^(NSString *thread, NSUInteger idx, BOOL *stop) {
+      RCTProfileAddEvent(RCTProfileTraceEvents,
+        @"ph": @"M", // metadata event
+        @"name": @"thread_sort_index",
+        @"tid": thread,
+        @"args": @{ @"sort_index": @(-1000 + (NSInteger)idx) }
+      );
+    }];
+  });
+
   RCTProfileHookModules(bridge);
 
   RCTProfileDisplayLink = [CADisplayLink displayLinkWithTarget:[RCTProfile class]

From a7521a23aeef1fade75c265331ae2bcdfca2936c Mon Sep 17 00:00:00 2001
From: Sreejumon <spurayil@imprivata.com>
Date: Fri, 12 Feb 2016 04:51:01 -0800
Subject: [PATCH 1137/1411] Created empty requestBody to solve the issue -
 "POST has no body"

Reviewed By: svcscm

Differential Revision: D2931739

fb-gh-sync-id: 04b6f59c257a35e4638c4c8f00bbffb34666145f
shipit-source-id: 04b6f59c257a35e4638c4c8f00bbffb34666145f
---
 .../com/facebook/react/modules/network/NetworkingModule.java   | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
index 50cd58a08da0..2bdcd82d65b0 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
@@ -197,8 +197,7 @@ public void sendRequest(
       requestBuilder.method(method, multipartBuilder.build());
     } else {
       // Nothing in data payload, at least nothing we could understand anyway.
-      // Ignore and treat it as if it were null.
-      requestBuilder.method(method, null);
+      requestBuilder.method(method, RequestBodyUtil.getEmptyBody(method));
     }
 
     client.newCall(requestBuilder.build()).enqueue(

From b5579e807edccdeb3a4393b314d812d6bec2212c Mon Sep 17 00:00:00 2001
From: Thomas Parslow <tom@almostobsolete.net>
Date: Fri, 12 Feb 2016 05:28:37 -0800
Subject: [PATCH 1138/1411] Updated RCTPromiseRejectBlock example to use new 3
 argument form

Reviewed By: svcscm

Differential Revision: D2931949

fb-gh-sync-id: d5da545c882e662f9c5d5b33cc3b152a4269bbb8
shipit-source-id: d5da545c882e662f9c5d5b33cc3b152a4269bbb8
---
 docs/NativeModulesIOS.md | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/docs/NativeModulesIOS.md b/docs/NativeModulesIOS.md
index 41266aad7b34..ca40d20cccd2 100644
--- a/docs/NativeModulesIOS.md
+++ b/docs/NativeModulesIOS.md
@@ -188,7 +188,8 @@ RCT_REMAP_METHOD(findEvents,
   if (events) {
     resolve(events);
   } else {
-    reject(error);
+    NSError *error = ...
+    reject(@"no_events", @"There were no events", error);
   }
 }
 ```

From 727a2a95d19086c9816da7014b41e123be7610b7 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Fri, 12 Feb 2016 06:13:19 -0800
Subject: [PATCH 1139/1411] Let the module cache depend on transform options

Reviewed By: martinbigio

Differential Revision: D2921693

fb-gh-sync-id: 6f95bdb03d59183a1b5f50db16c6aab2b16d3146
shipit-source-id: 6f95bdb03d59183a1b5f50db16c6aab2b16d3146
---
 .../__tests__/DependencyGraph-test.js         |  44 +++++-
 .../src/DependencyResolver/Module.js          | 133 +++++++++++-------
 .../__tests__/Module-test.js                  |  92 ++++++++++--
 3 files changed, 203 insertions(+), 66 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
index 990e234f82ad..c5b0b754f7b8 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
@@ -48,11 +48,41 @@ describe('DependencyGraph', function() {
       isWatchman: () => Promise.resolve(false),
     };
 
-    const Cache = jest.genMockFn();
-    Cache.prototype.get = jest.genMockFn().mockImplementation(
-      (filepath, field, cb) => cb(filepath)
-    );
-    Cache.prototype.invalidate = jest.genMockFn();
+    const Cache = jest.genMockFn().mockImplementation(function() {
+      this._maps = Object.create(null);
+    });
+    Cache.prototype.has = jest.genMockFn()
+      .mockImplementation(function(filepath, field) {
+        if (!(filepath in this._maps)) {
+          return false;
+        }
+        return !field || field in this._maps[filepath];
+      });
+    Cache.prototype.get = jest.genMockFn()
+      .mockImplementation(function(filepath, field, factory) {
+        let cacheForPath  = this._maps[filepath];
+        if (this.has(filepath, field)) {
+          return field ? cacheForPath[field] : cacheForPath;
+        }
+
+        if (!cacheForPath) {
+          cacheForPath = this._maps[filepath] = Object.create(null);
+        }
+        const value = cacheForPath[field] = factory();
+        return value;
+      });
+    Cache.prototype.invalidate = jest.genMockFn()
+      .mockImplementation(function(filepath, field) {
+        if (!this.has(filepath, field)) {
+          return;
+        }
+
+        if (field) {
+          delete this._maps[filepath][field];
+        } else {
+          delete this._maps[filepath];
+        }
+      });
     Cache.prototype.end = jest.genMockFn();
 
     defaults = {
@@ -3688,7 +3718,9 @@ describe('DependencyGraph', function() {
       });
     });
 
-    pit('updates package.json', function() {
+    //TODO(davidaurelio) Make this actually worked. The test only passed because
+    // the mocked cache didn't cache. In reality, it didn't work. I tried it.
+    xpit('updates package.json', function() {
       var root = '/root';
       var filesystem = fs.__setMockFilesystem({
         'root': {
diff --git a/packager/react-packager/src/DependencyResolver/Module.js b/packager/react-packager/src/DependencyResolver/Module.js
index 116a52e093ce..c75473acceba 100644
--- a/packager/react-packager/src/DependencyResolver/Module.js
+++ b/packager/react-packager/src/DependencyResolver/Module.js
@@ -8,6 +8,7 @@
  */
 'use strict';
 
+const crypto = require('crypto');
 const docblock = require('./DependencyGraph/docblock');
 const isAbsolutePath = require('absolute-path');
 const path = require('path');
@@ -43,12 +44,16 @@ class Module {
     return this._cache.get(
       this.path,
       'isHaste',
-      () => this._readDocBlock().then(data => !!data.id)
+      () => this._readDocBlock().then(({id}) => !!id)
     );
   }
 
-  getCode() {
-    return this.read().then(({code}) => code);
+  getCode(transformOptions) {
+    return this.read(transformOptions).then(({code}) => code);
+  }
+
+  getMap(transformOptions) {
+    return this.read(transformOptions).then(({map}) => map);
   }
 
   getName() {
@@ -83,12 +88,8 @@ class Module {
     return this._moduleCache.getPackageForModule(this);
   }
 
-  getDependencies() {
-    return this._cache.get(
-      this.path,
-      'dependencies',
-      () => this.read().then(data => data.dependencies)
-    );
+  getDependencies(transformOptions) {
+    return this.read(transformOptions).then(data => data.dependencies);
   }
 
   invalidate() {
@@ -108,56 +109,50 @@ class Module {
     const id = provides && !this._depGraphHelpers.isNodeModulesDir(this.path)
         ? /^\S+/.exec(provides)[0]
         : undefined;
-    return [id, moduleDocBlock];
+    return {id, moduleDocBlock};
   }
 
-  _readDocBlock() {
-    const reading = this._reading || this._docBlock;
-    if (reading) {
-      return reading;
+  _readDocBlock(contentPromise) {
+    if (!this._docBlock) {
+      if (!contentPromise) {
+        contentPromise = this._fastfs.readWhile(this.path, whileInDocBlock);
+      }
+      this._docBlock = contentPromise
+        .then(docBlock => this._parseDocBlock(docBlock));
     }
-    this._docBlock = this._fastfs.readWhile(this.path, whileInDocBlock)
-      .then(docBlock => {
-        const [id] = this._parseDocBlock(docBlock);
-        return {id};
-      });
     return this._docBlock;
   }
 
-  read() {
-    if (this._reading) {
-      return this._reading;
-    }
-
-    this._reading = this._fastfs.readFile(this.path).then(content => {
-      const [id, moduleDocBlock] = this._parseDocBlock(content);
-
-      // Ignore requires in JSON files or generated code. An example of this
-      // is prebuilt files like the SourceMap library.
-      if (this.isJSON() || 'extern' in moduleDocBlock) {
-        return {
-          id,
-          dependencies: [],
-          code: content,
-        };
-      } else {
-        const transformCode = this._transformCode;
-        const codePromise = transformCode
-            ? transformCode(this, content)
-            : Promise.resolve({code: content});
-
-        return codePromise.then(({code, dependencies}) => {
-          const {deps} = this._extractor(code);
-          return {
-            id,
-            code,
-            dependencies: dependencies || deps.sync,
-          };
-        });
+  read(transformOptions) {
+    return this._cache.get(
+      this.path,
+      cacheKey('moduleData', transformOptions),
+      () => {
+        const fileContentPromise = this._fastfs.readFile(this.path);
+        return Promise.all([
+          fileContentPromise,
+          this._readDocBlock(fileContentPromise)
+        ]).then(([code, {id, moduleDocBlock}]) => {
+          // Ignore requires in JSON files or generated code. An example of this
+          // is prebuilt files like the SourceMap library.
+          if (this.isJSON() || 'extern' in moduleDocBlock) {
+            return {id, code, dependencies: []};
+          } else {
+            const transformCode = this._transformCode;
+            const codePromise = transformCode
+                ? transformCode(this, code, transformOptions)
+                : Promise.resolve({code});
+
+            return codePromise.then(({code, dependencies, map}) => {
+              if (!dependencies) {
+                dependencies = this._extractor(code).deps.sync;
+              }
+              return {id, code, dependencies, map};
+            });
+          }
+        })
       }
-    });
-
-    return this._reading;
+    );
   }
 
   hash() {
@@ -207,4 +202,38 @@ function whileInDocBlock(chunk, i, result) {
   return !/\*\//.test(result);
 }
 
+// use weak map to speed up hash creation of known objects
+const knownHashes = new WeakMap();
+function stableObjectHash(object) {
+  let digest = knownHashes.get(object);
+
+  if (!digest) {
+    const hash = crypto.createHash('md5');
+    stableObjectHash.addTo(object, hash);
+    digest = hash.digest('base64');
+    knownHashes.set(object, digest);
+  }
+
+  return digest;
+}
+stableObjectHash.addTo = function addTo(value, hash) {
+  if (value === null || typeof value !== 'object') {
+    hash.update(JSON.stringify(value));
+  } else {
+    Object.keys(value).sort().forEach(key => {
+      const valueForKey = value[key];
+      if (valueForKey !== undefined) {
+        hash.update(key);
+        addTo(valueForKey, hash);
+      }
+    });
+  }
+};
+
+function cacheKey(field, transformOptions) {
+  return transformOptions !== undefined
+      ? stableObjectHash(transformOptions) + '\0' + field
+      : field;
+}
+
 module.exports = Module;
diff --git a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js b/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
index 71bc552278a2..71c3a43dca55 100644
--- a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
+++ b/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
@@ -178,16 +178,10 @@ describe('Module', () => {
         expect(code).toBe(fileContents))
     );
 
-    pit('exposes file contes via the `getCode()` method', () =>
+    pit('exposes file contents via the `getCode()` method', () =>
       createModule().getCode().then(code =>
         expect(code).toBe(fileContents))
     );
-
-    pit('does not save the code in the cache', () =>
-      createModule().getCode().then(() =>
-        expect(cache.get).not.toBeCalled()
-      )
-    );
   });
 
   describe('Extrators', () => {
@@ -221,10 +215,19 @@ describe('Module', () => {
       const module = createModule({transformCode});
       return module.read()
         .then(() => {
-          expect(transformCode).toBeCalledWith(module, fileContents);
+          expect(transformCode).toBeCalledWith(module, fileContents, undefined);
         });
     });
 
+    pit('passes any additional options to the transform function when reading', () => {
+      const module = createModule({transformCode});
+      const transformOptions = {arbitrary: Object()};
+      return module.read(transformOptions)
+        .then(() =>
+          expect(transformCode.mock.calls[0][2]).toBe(transformOptions)
+        );
+    });
+
     pit('uses the code that `transformCode` resolves to to extract dependencies', () => {
       transformCode.mockReturnValue(Promise.resolve({code: exampleCode}));
       const module = createModule({transformCode});
@@ -256,5 +259,78 @@ describe('Module', () => {
           expect(code).toBe(exampleCode);
         });
     });
+
+    pit('exposes a source map returned by the transform', () => {
+      const map = {version: 3};
+      transformCode.mockReturnValue(Promise.resolve({map, code: exampleCode}));
+      const module = createModule({transformCode});
+      return Promise.all([module.read(), module.getMap()])
+        .then(([data, sourceMap]) => {
+          expect(data.map).toBe(map);
+          expect(sourceMap).toBe(map);
+        });
+    });
+
+    describe('Caching based on options', () => {
+      let module;
+      beforeEach(function() {
+        module = createModule({transformCode});
+      });
+
+      const callsEqual = ([path1, key1], [path2, key2]) => {
+        expect(path1).toEqual(path2);
+        expect(key1).toEqual(key2);
+      }
+
+      it('gets dependencies from the cache with the same cache key for the same transform options', () => {
+        const options = {some: 'options'};
+        module.getDependencies(options); // first call
+        module.getDependencies(options); // second call
+
+        const {calls} = cache.get.mock;
+        callsEqual(calls[0], calls[1]);
+      });
+
+      it('gets dependencies from the cache with the same cache key for the equivalent transform options', () => {
+        const options = {some: 'options'};
+        module.getDependencies({a: 'b', c: 'd'}); // first call
+        module.getDependencies({c: 'd', a: 'b'}); // second call
+
+        const {calls} = cache.get.mock;
+        callsEqual(calls[0], calls[1]);
+      });
+
+      it('gets dependencies from the cache with different cache keys for different transform options', () => {
+        module.getDependencies({some: 'options'});
+        module.getDependencies({other: 'arbitrary options'});
+        const {calls} = cache.get.mock;
+        expect(calls[0][1]).not.toEqual(calls[1][1]);
+      });
+
+      it('gets code from the cache with the same cache key for the same transform options', () => {
+        const options = {some: 'options'};
+        module.getCode(options); // first call
+        module.getCode(options); // second call
+
+        const {calls} = cache.get.mock;
+        callsEqual(calls[0], calls[1]);
+      });
+
+      it('gets code from the cache with the same cache key for the equivalent transform options', () => {
+        const options = {some: 'options'};
+        module.getCode({a: 'b', c: 'd'}); // first call
+        module.getCode({c: 'd', a: 'b'}); // second call
+
+        const {calls} = cache.get.mock;
+        callsEqual(calls[0], calls[1]);
+      });
+
+      it('gets code from the cache with different cache keys for different transform options', () => {
+        module.getCode({some: 'options'});
+        module.getCode({other: 'arbitrary options'});
+        const {calls} = cache.get.mock;
+        expect(calls[0][1]).not.toEqual(calls[1][1]);
+      });
+    });
   });
 });

From 8eddead8687f0acc68fb2e857a00260912600f06 Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Fri, 12 Feb 2016 06:20:25 -0800
Subject: [PATCH 1140/1411] Add a deprecatedCallback helper

Reviewed By: svcscm

Differential Revision: D2926943

fb-gh-sync-id: 104bcd076f6427aac92e98081e492101ca78de26
shipit-source-id: 104bcd076f6427aac92e98081e492101ca78de26
---
 Libraries/Utilities/deprecatedCallback.js | 48 +++++++++++++++++++++++
 1 file changed, 48 insertions(+)
 create mode 100644 Libraries/Utilities/deprecatedCallback.js

diff --git a/Libraries/Utilities/deprecatedCallback.js b/Libraries/Utilities/deprecatedCallback.js
new file mode 100644
index 000000000000..8ed31254b13e
--- /dev/null
+++ b/Libraries/Utilities/deprecatedCallback.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.
+ *
+ * Helper for deprecated callback pattern
+ *
+ * @providesModule deprecatedCallback
+ * @flow
+ */
+
+'use strict';
+
+module.exports = function(promise: Promise, callbacks: Array<Function>, type: string, warning: string): Promise {
+  if (callbacks.length === 0) {
+    return promise;
+  }
+
+  let success, error;
+
+  console.warn(warning);
+
+  switch (type) {
+  case 'success-first': // handles func(success, error), func(success)
+    [ success, error ] = callbacks;
+    return promise.then(
+      res => success(res),
+      err => error && error(err)
+    );
+  case 'error-first': // handles func(error, success)
+    [ error, success ] = callbacks;
+    return promise.then(
+      res => success(res),
+      err => error(err)
+    );
+  case 'node': // handles func(callback)
+    const [ callback ] = callbacks;
+    return promise.then(
+      res => callback(null, res),
+      err => callback(err)
+    );
+  default:
+    throw new Error(`Type of callbacks not specified. Must be one of 'success-first', 'error-first', or 'node'`);
+  }
+};

From e018aa3100d93abf0e222cd70bbcbb6ab248eced Mon Sep 17 00:00:00 2001
From: Adam Miskiewicz <adam@sk3vy.com>
Date: Fri, 12 Feb 2016 08:09:43 -0800
Subject: [PATCH 1141/1411] Enable HMR

Reviewed By: svcscm

Differential Revision: D2932137

fb-gh-sync-id: 8bfab09aaac22ae498ac4fa896eee495111abc0d
shipit-source-id: 8bfab09aaac22ae498ac4fa896eee495111abc0d
---
 Libraries/Utilities/HMRClient.js              | 45 ++++++++++++-------
 React/Base/RCTBatchedBridge.m                 |  4 +-
 React/Executors/RCTJSCExecutor.m              | 29 ++++++------
 .../facebook/react/CoreModulesPackage.java    |  2 +
 .../react/devsupport/DevSupportManager.java   |  1 +
 .../devsupport/DevSupportManagerImpl.java     | 23 +++++++++-
 .../devsupport/DisabledDevSupportManager.java |  5 +++
 .../facebook/react/devsupport/HMRClient.java  | 32 +++++++++++++
 .../modules/core/ExceptionsManagerModule.java |  7 +++
 .../src/main/jni/react/JSCExecutor.cpp        | 22 ++++++++-
 10 files changed, 137 insertions(+), 33 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/devsupport/HMRClient.java

diff --git a/Libraries/Utilities/HMRClient.js b/Libraries/Utilities/HMRClient.js
index ed55ee6b912c..d9d8b79bdd62 100644
--- a/Libraries/Utilities/HMRClient.js
+++ b/Libraries/Utilities/HMRClient.js
@@ -10,6 +10,7 @@
  */
 'use strict';
 
+const Platform = require('Platform');
 const invariant = require('invariant');
 const processColor = require('processColor');
 
@@ -18,23 +19,26 @@ const processColor = require('processColor');
  * runtime to reflects those changes.
  */
 const HMRClient = {
-  enable(platform, bundleEntry) {
+  enable(platform, bundleEntry, host, port) {
     invariant(platform, 'Missing required parameter `platform`');
     invariant(bundleEntry, 'Missing required paramenter `bundleEntry`');
-
-    // TODO(martinb) receive host and port as parameters
-    const host = 'localhost';
-    const port = '8081';
+    invariant(host, 'Missing required paramenter `host`');
 
     // need to require WebSocket inside of `enable` function because
     // this module is defined as a `polyfillGlobal`.
     // See `InitializeJavascriptAppEngine.js`
     const WebSocket = require('WebSocket');
 
-    const activeWS = new WebSocket(
-      `ws://${host}:${port}/hot?platform=${platform}&` +
-      `bundleEntry=${bundleEntry.replace('.bundle', '.js')}`
-    );
+    const wsHostPort = port !== null && port !== ''
+      ? `${host}:${port}`
+      : host;
+
+    // Build the websocket url
+    const wsUrl = `ws://${wsHostPort}/hot?` +
+      `platform=${platform}&` +
+      `bundleEntry=${bundleEntry.replace('.bundle', '.js')}`;
+
+    const activeWS = new WebSocket(wsUrl);
     activeWS.onerror = (e) => {
       throw new Error(
 `Hot loading isn't working because it cannot connect to the development server.
@@ -50,10 +54,16 @@ Error: ${e.message}`
       );
     };
     activeWS.onmessage = ({data}) => {
-      const DevLoadingView = require('NativeModules').DevLoadingView;
+      let DevLoadingView = require('NativeModules').DevLoadingView;
+      if (!DevLoadingView) {
+        DevLoadingView = {
+          showMessage() {},
+          hide() {},
+        };
+      }
       data = JSON.parse(data);
 
-      switch(data.type) {
+      switch (data.type) {
         case 'update-start': {
           DevLoadingView.showMessage(
             'Hot Loading...',
@@ -67,8 +77,13 @@ Error: ${e.message}`
           const sourceMappingURLs = data.body.sourceMappingURLs;
           const sourceURLs = data.body.sourceURLs;
 
-          const RCTRedBox = require('NativeModules').RedBox;
-          RCTRedBox && RCTRedBox.dismiss && RCTRedBox.dismiss();
+          if (Platform.OS === 'ios') {
+            const RCTRedBox = require('NativeModules').RedBox;
+            RCTRedBox && RCTRedBox.dismiss && RCTRedBox.dismiss();
+          } else {
+            const RCTExceptionsManager = require('NativeModules').ExceptionsManager;
+            RCTExceptionsManager && RCTExceptionsManager.dismissRedbox && RCTExceptionsManager.dismissRedbox();
+          }
 
           modules.forEach((code, i) => {
             code = code + '\n\n' + sourceMappingURLs[i];
@@ -82,8 +97,8 @@ Error: ${e.message}`
             // on JSC we need to inject from native for sourcemaps to work
             // (Safari doesn't support `sourceMappingURL` nor any variant when
             // evaluating code) but on Chrome we can simply use eval
-            const injectFunction = typeof __injectHMRUpdate === 'function'
-              ? __injectHMRUpdate
+            const injectFunction = typeof global.nativeInjectHMRUpdate === 'function'
+              ? global.nativeInjectHMRUpdate
               : eval;
 
             injectFunction(code, sourceURLs[i]);
diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index debc00d9a026..49c4dcb7c6d5 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -461,7 +461,9 @@ - (void)executeSourceCode:(NSData *)sourceCode
 
   if (RCTGetURLQueryParam(self.bundleURL, @"hot")) {
     NSString *path = [self.bundleURL.path substringFromIndex:1]; // strip initial slash
-    [self enqueueJSCall:@"HMRClient.enable" args:@[@"ios", path]];
+    NSString *host = self.bundleURL.host;
+    NSNumber *port = self.bundleURL.port;
+    [self enqueueJSCall:@"HMRClient.enable" args:@[@"ios", path, host, RCTNullIfNil(port)]];
   }
 
 #endif
diff --git a/React/Executors/RCTJSCExecutor.m b/React/Executors/RCTJSCExecutor.m
index 176bffe87779..db08f806e97b 100644
--- a/React/Executors/RCTJSCExecutor.m
+++ b/React/Executors/RCTJSCExecutor.m
@@ -341,6 +341,20 @@ - (void)setUp
                                                  name:event
                                                object:nil];
   }
+
+  // Inject handler used by HMR
+  [self addSynchronousHookWithName:@"nativeInjectHMRUpdate" usingBlock:^(NSString *sourceCode, NSString *sourceCodeURL) {
+    RCTJSCExecutor *strongSelf = weakSelf;
+    if (!strongSelf.valid) {
+      return;
+    }
+
+    JSStringRef execJSString = JSStringCreateWithUTF8CString(sourceCode.UTF8String);
+    JSStringRef jsURL = JSStringCreateWithUTF8CString(sourceCodeURL.UTF8String);
+    JSEvaluateScript(strongSelf->_context.ctx, execJSString, NULL, jsURL, 0, NULL);
+    JSStringRelease(jsURL);
+    JSStringRelease(execJSString);
+  }];
 #endif
 }
 
@@ -513,21 +527,6 @@ - (void)executeApplicationScript:(NSData *)script
   RCTAssertParam(sourceURL);
 
   __weak RCTJSCExecutor *weakSelf = self;
-#if RCT_DEV
-  _context.context[@"__injectHMRUpdate"] = ^(NSString *sourceCode, NSString *sourceCodeURL) {
-    RCTJSCExecutor *strongSelf = weakSelf;
-
-    if (!strongSelf) {
-      return;
-    }
-
-    JSStringRef execJSString = JSStringCreateWithUTF8CString(sourceCode.UTF8String);
-    JSStringRef jsURL = JSStringCreateWithUTF8CString(sourceCodeURL.UTF8String);
-    JSEvaluateScript(strongSelf->_context.ctx, execJSString, NULL, jsURL, 0, NULL);
-    JSStringRelease(jsURL);
-    JSStringRelease(execJSString);
-  };
-#endif
 
   [self executeBlockOnJavaScriptQueue:RCTProfileBlock((^{
     RCTJSCExecutor *strongSelf = weakSelf;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java b/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java
index 07b18b066b30..d7b34e270ace 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java
@@ -19,6 +19,7 @@
 import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
 import com.facebook.react.modules.core.DeviceEventManagerModule;
 import com.facebook.react.modules.core.ExceptionsManagerModule;
+import com.facebook.react.devsupport.HMRClient;
 import com.facebook.react.modules.core.JSTimersExecution;
 import com.facebook.react.modules.core.RCTNativeAppEventEmitter;
 import com.facebook.react.modules.core.Timing;
@@ -95,6 +96,7 @@ public List<Class<? extends JavaScriptModule>> createJSModules() {
         RCTNativeAppEventEmitter.class,
         AppRegistry.class,
         com.facebook.react.bridge.Systrace.class,
+        HMRClient.class,
         DebugComponentOwnershipModule.RCTDebugComponentOwnership.class);
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
index 4f114ded6099..4b27023c06bf 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java
@@ -25,6 +25,7 @@ public interface DevSupportManager extends NativeModuleCallExceptionHandler {
   void addCustomDevOption(String optionName, DevOptionHandler optionHandler);
   void showNewJSError(String message, ReadableArray details, int errorCookie);
   void updateJSError(final String message, final ReadableArray details, final int errorCookie);
+  void hideRedboxDialog();
   void showDevOptionsDialog();
   void setDevSupportEnabled(boolean isDevSupportEnabled);
   boolean getDevSupportEnabled();
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java
index 120443eca3d1..75d7282a7f61 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java
@@ -13,6 +13,8 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.util.LinkedHashMap;
 import java.util.Locale;
 import java.util.concurrent.ExecutionException;
@@ -40,7 +42,6 @@
 import com.facebook.react.bridge.CatalystInstance;
 import com.facebook.react.bridge.DefaultNativeModuleCallExceptionHandler;
 import com.facebook.react.bridge.JavaJSExecutor;
-import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.bridge.UiThreadUtil;
@@ -216,6 +217,14 @@ public void run() {
         });
   }
 
+  @Override
+  public void hideRedboxDialog() {
+    // dismiss redbox if exists
+    if (mRedBoxDialog != null) {
+      mRedBoxDialog.dismiss();
+    }
+  }
+
   private void showNewError(
       final String message,
       final StackFrame[] stack,
@@ -522,6 +531,18 @@ private void resetCurrentContext(@Nullable ReactContext reactContext) {
       mDebugOverlayController = new DebugOverlayController(reactContext);
     }
 
+    if (mDevSettings.isHotModuleReplacementEnabled() && mCurrentContext != null) {
+      try {
+        URL sourceUrl = new URL(getSourceUrl());
+        String path = sourceUrl.getPath().substring(1); // strip initial slash in path
+        String host = sourceUrl.getHost();
+        int port = sourceUrl.getPort();
+        mCurrentContext.getJSModule(HMRClient.class).enable("android", path, host, port);
+      } catch (MalformedURLException e) {
+        showNewJavaError(e.getMessage(), e);
+      }
+    }
+
     reloadSettings();
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DisabledDevSupportManager.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DisabledDevSupportManager.java
index 54f5335cd21b..5388f98b7d1a 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DisabledDevSupportManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DisabledDevSupportManager.java
@@ -46,6 +46,11 @@ public void updateJSError(String message, ReadableArray details, int errorCookie
 
   }
 
+  @Override
+  public void hideRedboxDialog() {
+
+  }
+
   @Override
   public void showDevOptionsDialog() {
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/HMRClient.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/HMRClient.java
new file mode 100644
index 000000000000..8ef0e5e35bc1
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/HMRClient.java
@@ -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.
+ */
+
+package com.facebook.react.devsupport;
+
+import com.facebook.react.bridge.JavaScriptModule;
+
+/**
+ * JS module interface for HMRClient
+ *
+ * The HMR(Hot Module Replacement)Client allows for the application to receive updates
+ * from the packager server (over a web socket), allowing for injection of JavaScript to
+ * the running application (without a refresh).
+ */
+public interface HMRClient extends JavaScriptModule {
+
+  /**
+   * Enable the HMRClient so that the client will receive updates
+   * from the packager server.
+   * @param platform The platform in which HMR updates will be enabled. Should be "android".
+   * @param bundleEntry The path to the bundle entry file (e.g. index.ios.bundle).
+   * @param host The host that the HMRClient should communicate with.
+   * @param port The port that the HMRClient should communicate with on the host.
+   */
+  void enable(String platform, String bundleEntry, String host, int port);
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/ExceptionsManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/core/ExceptionsManagerModule.java
index ca12dd6c57d7..5b185d64b1d8 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/core/ExceptionsManagerModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/core/ExceptionsManagerModule.java
@@ -77,4 +77,11 @@ public void updateExceptionMessage(String title, ReadableArray details, int exce
       mDevSupportManager.updateJSError(title, details, exceptionId);
     }
   }
+
+  @ReactMethod
+  public void dismissRedbox() {
+    if (mDevSupportManager.getDevSupportEnabled()) {
+      mDevSupportManager.hideRedboxDialog();
+    }
+  }
 }
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index a951c5d8f4df..03d28562c634 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -59,6 +59,13 @@ static JSValueRef nativePerformanceNow(
     size_t argumentCount,
     const JSValueRef arguments[],
     JSValueRef *exception);
+static JSValueRef nativeInjectHMRUpdate(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[],
+    JSValueRef *exception);
 
 static std::string executeJSCallWithJSC(
     JSGlobalContextRef ctx,
@@ -93,6 +100,7 @@ JSCExecutor::JSCExecutor(FlushImmediateCallback cb, const std::string& cacheDir)
   installGlobalFunction(m_context, "nativeStartWorker", nativeStartWorker);
   installGlobalFunction(m_context, "nativePostMessageToWorker", nativePostMessageToWorker);
   installGlobalFunction(m_context, "nativeTerminateWorker", nativeTerminateWorker);
+  installGlobalFunction(m_context, "nativeInjectHMRUpdate", nativeInjectHMRUpdate);
 
   installGlobalFunction(m_context, "nativeLoggingHook", JSLogging::nativeHook);
 
@@ -140,7 +148,7 @@ void JSCExecutor::executeApplicationScript(
   if (!jsSourceURL) {
     evaluateScript(m_context, jsScript, jsSourceURL);
   } else {
-    // If we're evaluating a script, get the device's cache dir 
+    // If we're evaluating a script, get the device's cache dir
     //  in which a cache file for that script will be stored.
     evaluateScript(m_context, jsScript, jsSourceURL, m_deviceCacheDir.c_str());
   }
@@ -471,4 +479,16 @@ static JSValueRef nativePerformanceNow(
   return JSValueMakeNumber(ctx, (nano / (double)NANOSECONDS_IN_MILLISECOND));
 }
 
+static JSValueRef nativeInjectHMRUpdate(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[], JSValueRef *exception) {
+  String execJSString = Value(ctx, arguments[0]).toString();
+  String jsURL = Value(ctx, arguments[1]).toString();
+  evaluateScript(ctx, execJSString, jsURL);
+  return JSValueMakeUndefined(ctx);
+}
+
 } }

From 3781bf974dedcf966b9adedcce42d37e7f10a3d9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Fri, 12 Feb 2016 08:27:31 -0800
Subject: [PATCH 1142/1411] Fix RAM detection logic

Reviewed By: davidaurelio

Differential Revision: D2932012

fb-gh-sync-id: ae2340de09ec3a4fae9371c3b8e6148d4ef267b8
shipit-source-id: ae2340de09ec3a4fae9371c3b8e6148d4ef267b8
---
 packager/react-packager/src/Bundler/index.js  | 4 ++--
 packager/react-packager/src/Resolver/index.js | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index 99923e657620..bc25ab1d929a 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -149,9 +149,9 @@ class Bundler {
   }
 
   bundle(options) {
-    const {dev, isUnbundle, platform} = options;
+    const {dev, unbundle, platform} = options;
     const moduleSystemDeps =
-      this._resolver.getModuleSystemDependencies({dev, isUnbundle, platform});
+      this._resolver.getModuleSystemDependencies({dev, unbundle, platform});
     return this._bundle({
       bundle: new Bundle(options.sourceMapUrl),
       moduleSystemDeps,
diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index a677c2199da8..7e993a5d7df9 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -60,7 +60,7 @@ const getDependenciesValidateOpts = declareOpts({
     type: 'string',
     required: false,
   },
-  isUnbundle: {
+  unbundle: {
     type: 'boolean',
     default: false
   },
@@ -144,7 +144,7 @@ class Resolver {
         ? path.join(__dirname, 'polyfills/prelude_dev.js')
         : path.join(__dirname, 'polyfills/prelude.js');
 
-    const moduleSystem = opts.isUnbundle
+    const moduleSystem = opts.unbundle
         ? path.join(__dirname, 'polyfills/require-unbundle.js')
         : path.join(__dirname, 'polyfills/require.js');
 

From 313d84d507689a78a9f4084b162ac87c09d7d5e3 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Fri, 12 Feb 2016 08:31:54 -0800
Subject: [PATCH 1143/1411] Allocate RCTRootView.reactTag when it's first
 requested, instead of waiting until bundle has loaded.

Reviewed By: javache

Differential Revision: D2931937

fb-gh-sync-id: 1cc421a30028e3de1b2d22143edd645d8a34e4d4
shipit-source-id: 1cc421a30028e3de1b2d22143edd645d8a34e4d4
---
 React/Base/RCTRootView.m | 64 +++++++++++++++++++++++++---------------
 1 file changed, 40 insertions(+), 24 deletions(-)

diff --git a/React/Base/RCTRootView.m b/React/Base/RCTRootView.m
index d5726a2bcfa3..d571a0690b2d 100644
--- a/React/Base/RCTRootView.m
+++ b/React/Base/RCTRootView.m
@@ -38,10 +38,11 @@ - (NSNumber *)allocateRootTag;
 @interface RCTRootContentView : RCTView <RCTInvalidating>
 
 @property (nonatomic, readonly) BOOL contentHasAppeared;
-
 @property (nonatomic, readonly, strong) RCTTouchHandler *touchHandler;
 
-- (instancetype)initWithFrame:(CGRect)frame bridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithFrame:(CGRect)frame
+                       bridge:(RCTBridge *)bridge
+                     reactTag:(NSNumber *)reactTag NS_DESIGNATED_INITIALIZER;
 
 @end
 
@@ -74,6 +75,11 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
     _loadingViewFadeDuration = 0.25;
     _sizeFlexibility = RCTRootViewSizeFlexibilityNone;
 
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(bridgeDidReload)
+                                                 name:RCTJavaScriptWillStartLoadingNotification
+                                               object:_bridge];
+
     [[NSNotificationCenter defaultCenter] addObserver:self
                                              selector:@selector(javaScriptDidLoad:)
                                                  name:RCTJavaScriptDidLoadNotification
@@ -83,6 +89,7 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
                                              selector:@selector(hideLoadingView)
                                                  name:RCTContentDidAppearNotification
                                                object:self];
+
     if (!_bridge.loading) {
       [self bundleFinishedLoading:_bridge.batchedBridge];
     }
@@ -165,6 +172,29 @@ - (void)hideLoadingView
   }
 }
 
+- (NSNumber *)reactTag
+{
+  RCTAssertMainThread();
+  if (!super.reactTag) {
+    /**
+     * Every root view that is created must have a unique react tag.
+     * Numbering of these tags goes from 1, 11, 21, 31, etc
+     *
+     * NOTE: Since the bridge persists, the RootViews might be reused, so the
+     * react tag must be re-assigned every time a new UIManager is created.
+     */
+    self.reactTag = [_bridge.uiManager allocateRootTag];
+  }
+  return super.reactTag;
+}
+
+- (void)bridgeDidReload
+{
+  RCTAssertMainThread();
+  // Clear the reactTag so it can be re-assigned
+  self.reactTag = nil;
+}
+
 - (void)javaScriptDidLoad:(NSNotification *)notification
 {
   RCTAssertMainThread();
@@ -179,7 +209,9 @@ - (void)bundleFinishedLoading:(RCTBridge *)bridge
   }
 
   [_contentView removeFromSuperview];
-  _contentView = [[RCTRootContentView alloc] initWithFrame:self.bounds bridge:bridge];
+  _contentView = [[RCTRootContentView alloc] initWithFrame:self.bounds
+                                                    bridge:bridge
+                                                  reactTag:self.reactTag];
   [self runApplication:bridge];
 
   _contentView.backgroundColor = self.backgroundColor;
@@ -247,11 +279,6 @@ - (void)setIntrinsicSize:(CGSize)intrinsicSize
   [_delegate rootViewDidChangeIntrinsicSize:self];
 }
 
-- (NSNumber *)reactTag
-{
-  return _contentView.reactTag;
-}
-
 - (void)contentViewInvalidated
 {
   [_contentView removeFromSuperview];
@@ -291,10 +318,14 @@ @implementation RCTRootContentView
 
 - (instancetype)initWithFrame:(CGRect)frame
                        bridge:(RCTBridge *)bridge
+                     reactTag:(NSNumber *)reactTag
 {
   if ((self = [super initWithFrame:frame])) {
     _bridge = bridge;
-    [self setUp];
+    self.reactTag = reactTag;
+    _touchHandler = [[RCTTouchHandler alloc] initWithBridge:_bridge];
+    [self addGestureRecognizer:_touchHandler];
+    [_bridge.uiManager registerRootView:self];
     self.layer.backgroundColor = NULL;
   }
   return self;
@@ -337,21 +368,6 @@ - (UIColor *)backgroundColor
   return _backgroundColor;
 }
 
-- (void)setUp
-{
-  /**
-   * Every root view that is created must have a unique react tag.
-   * Numbering of these tags goes from 1, 11, 21, 31, etc
-   *
-   * NOTE: Since the bridge persists, the RootViews might be reused, so now
-   * the react tag is assigned every time we load new content.
-   */
-  self.reactTag = [_bridge.uiManager allocateRootTag];
-  _touchHandler = [[RCTTouchHandler alloc] initWithBridge:_bridge];
-  [self addGestureRecognizer:_touchHandler];
-  [_bridge.uiManager registerRootView:self];
-}
-
 - (void)invalidate
 {
   if (self.userInteractionEnabled) {

From 0f850b47608830a37a35497e4c1f7dc9488485fc Mon Sep 17 00:00:00 2001
From: Matteo Manchi <matteo.manchi@gmail.com>
Date: Fri, 12 Feb 2016 08:49:41 -0800
Subject: [PATCH 1144/1411] Adding MyPED to React Native Showcase

Reviewed By: svcscm

Differential Revision: D2932104

fb-gh-sync-id: 1b315b13fe96bcdd674e056fa650762e466282d6
shipit-source-id: 1b315b13fe96bcdd674e056fa650762e466282d6
---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 83ebcb88eac9..de1ad2a934c0 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -376,6 +376,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/mr.-dapper-men-fashion-app/id989735184?ls=1&mt=8',
     author: 'wei ping woon',
   },
+  {
+    name: 'MyPED',
+    icon: 'http://a2.mzstatic.com/eu/r30/Purple69/v4/88/1f/fb/881ffb3b-7986-d427-7fcf-eb5920a883af/icon175x175.png',
+    link: 'https://itunes.apple.com/it/app/myped/id1064907558?ls=1&mt=8',
+    author: 'Impronta Advance',
+  },
   {
     name: 'Nalathe Kerala',
     icon: 'https://lh3.googleusercontent.com/5N0WYat5WuFbhi5yR2ccdbqmiZ0wbTtKRG9GhT3YK7Z-qRvmykZyAgk0HNElOxD2JOPr=w300-rw',

From cf7a97cc0f44853b7ad17a5fc619a64c994b6cbc Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Fri, 12 Feb 2016 09:09:41 -0800
Subject: [PATCH 1145/1411] WebWorkers: Pass Bridge to JSExecutors

Reviewed By: cjhopman

Differential Revision: D2921840

fb-gh-sync-id: f89f9ffe2c3bb0dabce7e8cbb9c7dc8b5062e267
shipit-source-id: f89f9ffe2c3bb0dabce7e8cbb9c7dc8b5062e267
---
 ReactAndroid/src/main/jni/react/Bridge.cpp    | 34 ++++++---------
 ReactAndroid/src/main/jni/react/Bridge.h      | 13 +++---
 ReactAndroid/src/main/jni/react/Executor.h    | 24 +++++------
 .../src/main/jni/react/JSCExecutor.cpp        | 43 +++++++++----------
 ReactAndroid/src/main/jni/react/JSCExecutor.h | 35 +++++++++------
 .../src/main/jni/react/jni/OnLoad.cpp         |  9 +---
 .../src/main/jni/react/jni/ProxyExecutor.cpp  | 19 ++++----
 .../src/main/jni/react/jni/ProxyExecutor.h    | 13 +++---
 8 files changed, 89 insertions(+), 101 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/Bridge.cpp b/ReactAndroid/src/main/jni/react/Bridge.cpp
index a4bb6887eb2a..821975bffc06 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.cpp
+++ b/ReactAndroid/src/main/jni/react/Bridge.cpp
@@ -11,16 +11,9 @@ namespace facebook {
 namespace react {
 
 Bridge::Bridge(JSExecutorFactory* jsExecutorFactory, Callback callback) :
-  m_callback(std::move(callback)),
-  m_destroyed(std::shared_ptr<bool>(new bool(false)))
-{
-  auto destroyed = m_destroyed;
-  m_jsExecutor = jsExecutorFactory->createJSExecutor([this, destroyed] (std::string queueJSON, bool isEndOfBatch) {
-    if (*destroyed) {
-      return;
-    }
-    m_callback(parseMethodCalls(queueJSON), isEndOfBatch);
-  });
+    m_callback(std::move(callback)),
+    m_destroyed(std::shared_ptr<bool>(new bool(false))) {
+  m_jsExecutor = jsExecutorFactory->createJSExecutor(this);
 }
 
 // This must be called on the same thread on which the constructor was called.
@@ -40,14 +33,6 @@ void Bridge::loadApplicationUnbundle(
   m_jsExecutor->loadApplicationUnbundle(std::move(unbundle), startupCode, sourceURL);
 }
 
-void Bridge::flush() {
-  if (*m_destroyed) {
-    return;
-  }
-  auto returnedJSON = m_jsExecutor->flush();
-  m_callback(parseMethodCalls(returnedJSON), true /* = isEndOfBatch */);
-}
-
 void Bridge::callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) {
   if (*m_destroyed) {
     return;
@@ -55,8 +40,7 @@ void Bridge::callFunction(const double moduleId, const double methodId, const fo
   #ifdef WITH_FBSYSTRACE
   FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "Bridge.callFunction");
   #endif
-  auto returnedJSON = m_jsExecutor->callFunction(moduleId, methodId, arguments);
-  m_callback(parseMethodCalls(returnedJSON), true /* = isEndOfBatch */);
+  m_jsExecutor->callFunction(moduleId, methodId, arguments);
 }
 
 void Bridge::invokeCallback(const double callbackId, const folly::dynamic& arguments) {
@@ -66,8 +50,7 @@ void Bridge::invokeCallback(const double callbackId, const folly::dynamic& argum
   #ifdef WITH_FBSYSTRACE
   FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "Bridge.invokeCallback");
   #endif
-  auto returnedJSON = m_jsExecutor->invokeCallback(callbackId, arguments);
-  m_callback(parseMethodCalls(returnedJSON), true /* = isEndOfBatch */);
+  m_jsExecutor->invokeCallback(callbackId, arguments);
 }
 
 void Bridge::setGlobalVariable(const std::string& propName, const std::string& jsonValue) {
@@ -94,4 +77,11 @@ void Bridge::handleMemoryPressureCritical() {
   m_jsExecutor->handleMemoryPressureCritical();
 }
 
+void Bridge::callNativeModules(const std::string& callJSON, bool isEndOfBatch) {
+  if (*m_destroyed) {
+    return;
+  }
+  m_callback(parseMethodCalls(callJSON), isEndOfBatch);
+}
+
 } }
diff --git a/ReactAndroid/src/main/jni/react/Bridge.h b/ReactAndroid/src/main/jni/react/Bridge.h
index 26b1aa8ef9f6..adfff7ae0cc6 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.h
+++ b/ReactAndroid/src/main/jni/react/Bridge.h
@@ -5,10 +5,11 @@
 #include <functional>
 #include <map>
 #include <vector>
-#include "Value.h"
+
 #include "Executor.h"
 #include "MethodCall.h"
 #include "JSModulesUnbundle.h"
+#include "Value.h"
 
 namespace folly {
 
@@ -26,11 +27,6 @@ class Bridge {
   Bridge(JSExecutorFactory* jsExecutorFactory, Callback callback);
   virtual ~Bridge();
 
-  /**
-   * Flush get the next queue of changes.
-   */
-  void flush();
-
   /**
    * Executes a function with the module ID and method ID and any additional
    * arguments in JS.
@@ -62,6 +58,11 @@ class Bridge {
   void stopProfiler(const std::string& title, const std::string& filename);
   void handleMemoryPressureModerate();
   void handleMemoryPressureCritical();
+
+  /**
+   * TODO: get rid of isEndOfBatch
+   */
+  void callNativeModules(const std::string& callJSON, bool isEndOfBatch);
 private:
   Callback m_callback;
   // This is used to avoid a race condition where a proxyCallback gets queued after ~Bridge(),
diff --git a/ReactAndroid/src/main/jni/react/Executor.h b/ReactAndroid/src/main/jni/react/Executor.h
index fb740d9f9d41..beace69a4037 100644
--- a/ReactAndroid/src/main/jni/react/Executor.h
+++ b/ReactAndroid/src/main/jni/react/Executor.h
@@ -5,6 +5,7 @@
 #include <string>
 #include <vector>
 #include <memory>
+
 #include "JSModulesUnbundle.h"
 
 namespace folly {
@@ -16,13 +17,11 @@ struct dynamic;
 namespace facebook {
 namespace react {
 
+class Bridge;
 class JSExecutor;
-
-typedef std::function<void(std::string, bool)> FlushImmediateCallback;
-
 class JSExecutorFactory {
 public:
-  virtual std::unique_ptr<JSExecutor> createJSExecutor(FlushImmediateCallback cb) = 0;
+  virtual std::unique_ptr<JSExecutor> createJSExecutor(Bridge *bridge) = 0;
   virtual ~JSExecutorFactory() {};
 };
 
@@ -43,23 +42,20 @@ class JSExecutor {
     const std::string& startupCode,
     const std::string& sourceURL) = 0;
 
-  /**
-   * Executes BatchedBridge.flushedQueue in JS to get the next queue of changes.
-   */
-  virtual std::string flush() = 0;
-
   /**
    * Executes BatchedBridge.callFunctionReturnFlushedQueue with the module ID,
-   * method ID and optional additional arguments in JS, and returns the next
-   * queue.
+   * method ID and optional additional arguments in JS. The executor is responsible
+   * for using Bridge->callNativeModules to invoke any necessary native modules methods.
    */
-  virtual std::string callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) = 0;
+  virtual void callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) = 0;
 
   /**
    * Executes BatchedBridge.invokeCallbackAndReturnFlushedQueue with the cbID,
-   * and optional additional arguments in JS and returns the next queue.
+   * and optional additional arguments in JS and returns the next queue. The executor
+   * is responsible for using Bridge->callNativeModules to invoke any necessary
+   * native modules methods.
    */
-  virtual std::string invokeCallback(const double callbackId, const folly::dynamic& arguments) = 0;
+  virtual void invokeCallback(const double callbackId, const folly::dynamic& arguments) = 0;
 
   virtual void setGlobalVariable(
     const std::string& propName,
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index 03d28562c634..7815aae25645 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -10,9 +10,10 @@
 #include <folly/String.h>
 #include <sys/time.h>
 
+#include "Bridge.h"
 #include "JSCHelpers.h"
-#include "Value.h"
 #include "Platform.h"
+#include "Value.h"
 
 #ifdef WITH_JSC_EXTRA_TRACING
 #include "JSCTracing.h"
@@ -45,13 +46,6 @@ namespace react {
 
 static std::unordered_map<JSContextRef, JSCExecutor*> s_globalContextRefToJSCExecutor;
 
-static JSValueRef nativeFlushQueueImmediate(
-    JSContextRef ctx,
-    JSObjectRef function,
-    JSObjectRef thisObject,
-    size_t argumentCount,
-    const JSValueRef arguments[],
-    JSValueRef *exception);
 static JSValueRef nativePerformanceNow(
     JSContextRef ctx,
     JSObjectRef function,
@@ -86,14 +80,15 @@ static std::string executeJSCallWithJSC(
   return Value(ctx, result).toJSONString();
 }
 
-std::unique_ptr<JSExecutor> JSCExecutorFactory::createJSExecutor(FlushImmediateCallback cb) {
-  return std::unique_ptr<JSExecutor>(new JSCExecutor(cb, cacheDir_));
+std::unique_ptr<JSExecutor> JSCExecutorFactory::createJSExecutor(Bridge *bridge) {
+  return std::unique_ptr<JSExecutor>(new JSCExecutor(bridge, cacheDir_));
 }
 
-JSCExecutor::JSCExecutor(FlushImmediateCallback cb, const std::string& cacheDir) :
-    m_flushImmediateCallback(cb), m_deviceCacheDir(cacheDir) {
+JSCExecutor::JSCExecutor(Bridge *bridge, const std::string& cacheDir) :
+    m_bridge(bridge),
+    m_deviceCacheDir(cacheDir),
+    m_messageQueueThread(MessageQueues::getCurrentMessageQueueThread()) {
   m_context = JSGlobalContextCreateInGroup(nullptr, nullptr);
-  m_messageQueueThread = MessageQueues::getCurrentMessageQueueThread();
   s_globalContextRefToJSCExecutor[m_context] = this;
   installGlobalFunction(m_context, "nativeFlushQueueImmediate", nativeFlushQueueImmediate);
   installGlobalFunction(m_context, "nativePerformanceNow", nativePerformanceNow);
@@ -152,6 +147,7 @@ void JSCExecutor::executeApplicationScript(
     //  in which a cache file for that script will be stored.
     evaluateScript(m_context, jsScript, jsSourceURL, m_deviceCacheDir.c_str());
   }
+  flush();
 }
 
 void JSCExecutor::loadApplicationUnbundle(
@@ -165,28 +161,31 @@ void JSCExecutor::loadApplicationUnbundle(
   executeApplicationScript(startupCode, sourceURL);
 }
 
-std::string JSCExecutor::flush() {
+void JSCExecutor::flush() {
   // TODO: Make this a first class function instead of evaling. #9317773
-  return executeJSCallWithJSC(m_context, "flushedQueue", std::vector<folly::dynamic>());
+  std::string calls = executeJSCallWithJSC(m_context, "flushedQueue", std::vector<folly::dynamic>());
+  m_bridge->callNativeModules(calls, true);
 }
 
-std::string JSCExecutor::callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) {
+void JSCExecutor::callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) {
   // TODO:  Make this a first class function instead of evaling. #9317773
   std::vector<folly::dynamic> call{
     (double) moduleId,
     (double) methodId,
     std::move(arguments),
   };
-  return executeJSCallWithJSC(m_context, "callFunctionReturnFlushedQueue", std::move(call));
+  std::string calls = executeJSCallWithJSC(m_context, "callFunctionReturnFlushedQueue", std::move(call));
+  m_bridge->callNativeModules(calls, true);
 }
 
-std::string JSCExecutor::invokeCallback(const double callbackId, const folly::dynamic& arguments) {
+void JSCExecutor::invokeCallback(const double callbackId, const folly::dynamic& arguments) {
   // TODO: Make this a first class function instead of evaling. #9317773
   std::vector<folly::dynamic> call{
     (double) callbackId,
     std::move(arguments)
   };
-  return executeJSCallWithJSC(m_context, "invokeCallbackAndReturnFlushedQueue", std::move(call));
+  std::string calls = executeJSCallWithJSC(m_context, "invokeCallbackAndReturnFlushedQueue", std::move(call));
+  m_bridge->callNativeModules(calls, true);
 }
 
 void JSCExecutor::setGlobalVariable(const std::string& propName, const std::string& jsonValue) {
@@ -240,7 +239,7 @@ void JSCExecutor::handleMemoryPressureCritical() {
 }
 
 void JSCExecutor::flushQueueImmediate(std::string queueJSON) {
-  m_flushImmediateCallback(queueJSON, false);
+  m_bridge->callNativeModules(queueJSON, false);
 }
 
 void JSCExecutor::loadModule(uint32_t moduleId) {
@@ -271,7 +270,7 @@ void JSCExecutor::onMessageReceived(int workerId, const std::string& json) {
   JSValueRef args[] = { JSCWebWorker::createMessageObject(m_context, json) };
   onmessageValue.asObject().callAsFunction(1, args);
 
-  m_flushImmediateCallback(flush(), true);
+  flush();
 }
 
 int JSCExecutor::addWebWorker(const std::string& script, JSValueRef workerRef) {
@@ -348,7 +347,7 @@ static JSValueRef createErrorString(JSContextRef ctx, const char *msg) {
   return JSValueMakeString(ctx, String(msg));
 }
 
-static JSValueRef nativeFlushQueueImmediate(
+JSValueRef JSCExecutor::nativeFlushQueueImmediate(
     JSContextRef ctx,
     JSObjectRef function,
     JSObjectRef thisObject,
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.h b/ReactAndroid/src/main/jni/react/JSCExecutor.h
index d06071a2a7a8..4db73b058aaa 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.h
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.h
@@ -18,7 +18,7 @@ class MessageQueueThread;
 class JSCExecutorFactory : public JSExecutorFactory {
 public:
   JSCExecutorFactory(const std::string& cacheDir) : cacheDir_(cacheDir) {}
-  virtual std::unique_ptr<JSExecutor> createJSExecutor(FlushImmediateCallback cb) override;
+  virtual std::unique_ptr<JSExecutor> createJSExecutor(Bridge *bridge) override;
 private:
   std::string cacheDir_;
 };
@@ -28,7 +28,7 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
   /**
    * Should be invoked from the JS thread.
    */
-  explicit JSCExecutor(FlushImmediateCallback flushImmediateCallback, const std::string& cacheDir);
+  explicit JSCExecutor(Bridge *bridge, const std::string& cacheDir);
   ~JSCExecutor() override;
 
   virtual void executeApplicationScript(
@@ -38,12 +38,11 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
     std::unique_ptr<JSModulesUnbundle> unbundle,
     const std::string& startupCode,
     const std::string& sourceURL) override;
-  virtual std::string flush() override;
-  virtual std::string callFunction(
+  virtual void callFunction(
     const double moduleId,
     const double methodId,
     const folly::dynamic& arguments) override;
-  virtual std::string invokeCallback(
+  virtual void invokeCallback(
     const double callbackId,
     const folly::dynamic& arguments) override;
   virtual void setGlobalVariable(
@@ -55,7 +54,6 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
   virtual void handleMemoryPressureModerate() override;
   virtual void handleMemoryPressureCritical() override;
 
-  void flushQueueImmediate(std::string queueJSON);
   void installNativeHook(const char *name, JSObjectCallAsFunctionCallback callback);
   virtual void onMessageReceived(int workerId, const std::string& message) override;
   virtual JSGlobalContextRef getContext() override;
@@ -63,17 +61,19 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
 
 private:
   JSGlobalContextRef m_context;
-  FlushImmediateCallback m_flushImmediateCallback;
   std::unordered_map<int, JSCWebWorker> m_webWorkers;
   std::unordered_map<int, Object> m_webWorkerJSObjs;
-  std::shared_ptr<MessageQueueThread> m_messageQueueThread;
+  Bridge *m_bridge;
   std::string m_deviceCacheDir;
+  std::shared_ptr<MessageQueueThread> m_messageQueueThread;
   std::unique_ptr<JSModulesUnbundle> m_unbundle;
 
   int addWebWorker(const std::string& script, JSValueRef workerRef);
   void postMessageToWebWorker(int worker, JSValueRef message, JSValueRef *exn);
+  void flush();
   void terminateWebWorker(int worker);
   void loadModule(uint32_t moduleId);
+  void flushQueueImmediate(std::string queueJSON);
 
   static JSValueRef nativeStartWorker(
       JSContextRef ctx,
@@ -97,12 +97,19 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
       const JSValueRef arguments[],
       JSValueRef *exception);
   static JSValueRef nativeRequire(
-    JSContextRef ctx,
-    JSObjectRef function,
-    JSObjectRef thisObject,
-    size_t argumentCount,
-    const JSValueRef arguments[],
-    JSValueRef *exception);
+      JSContextRef ctx,
+      JSObjectRef function,
+      JSObjectRef thisObject,
+      size_t argumentCount,
+      const JSValueRef arguments[],
+      JSValueRef *exception);
+  static JSValueRef nativeFlushQueueImmediate(
+      JSContextRef ctx,
+      JSObjectRef function,
+      JSObjectRef thisObject,
+      size_t argumentCount,
+      const JSValueRef arguments[],
+      JSValueRef *exception);
 };
 
 } }
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 783b45dd91d6..a8dd4a0b5b3c 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -656,9 +656,7 @@ static void executeApplicationScript(
     const std::string& script,
     const std::string& sourceUri) {
   try {
-    // Execute the application script and collect/dispatch any native calls that might have occured
     bridge->executeApplicationScript(script, sourceUri);
-    bridge->flush();
   } catch (...) {
     translatePendingCppExceptionToJavaException();
   }
@@ -669,15 +667,12 @@ static void loadApplicationUnbundle(
     AAssetManager *assetManager,
     const std::string& startupCode,
     const std::string& startupFileName) {
-
   try {
-    // Load the application unbundle and collect/dispatch any native calls that might have occured
     bridge->loadApplicationUnbundle(
       std::unique_ptr<JSModulesUnbundle>(
         new JniJSModulesUnbundle(assetManager, startupFileName)),
       startupCode,
       startupFileName);
-    bridge->flush();
   } catch (...) {
     translatePendingCppExceptionToJavaException();
   }
@@ -818,8 +813,8 @@ std::string getDeviceCacheDir() {
 }
 
 struct CountableJSCExecutorFactory : CountableJSExecutorFactory  {
-  virtual std::unique_ptr<JSExecutor> createJSExecutor(FlushImmediateCallback cb) override {
-    return JSCExecutorFactory(getDeviceCacheDir()).createJSExecutor(cb);
+  virtual std::unique_ptr<JSExecutor> createJSExecutor(Bridge *bridge) override {
+    return JSCExecutorFactory(getDeviceCacheDir()).createJSExecutor(bridge);
   }
 };
 
diff --git a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
index e1025b06bba5..d43553a1d83e 100644
--- a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
@@ -8,6 +8,7 @@
 #include <jni/LocalString.h>
 #include <folly/json.h>
 
+#include <react/Bridge.h>
 namespace facebook {
 namespace react {
 
@@ -27,12 +28,12 @@ static std::string executeJSCallWithProxy(
   return result->toString();
 }
 
-std::unique_ptr<JSExecutor> ProxyExecutorOneTimeFactory::createJSExecutor(FlushImmediateCallback ignoredCallback) {
+std::unique_ptr<JSExecutor> ProxyExecutorOneTimeFactory::createJSExecutor(Bridge *bridge) {
   FBASSERTMSGF(
     m_executor.get() != nullptr,
     "Proxy instance should not be null. Did you attempt to call createJSExecutor() on this factory "
     "instance more than once?");
-  return std::unique_ptr<JSExecutor>(new ProxyExecutor(std::move(m_executor)));
+  return std::unique_ptr<JSExecutor>(new ProxyExecutor(std::move(m_executor), bridge));
 }
 
 ProxyExecutor::~ProxyExecutor() {
@@ -57,25 +58,23 @@ void ProxyExecutor::loadApplicationUnbundle(std::unique_ptr<JSModulesUnbundle>,
     "Loading application unbundles is not supported for proxy executors");
 }
 
-std::string ProxyExecutor::flush() {
-  return executeJSCallWithProxy(m_executor.get(), "flushedQueue", std::vector<folly::dynamic>());
-}
-
-std::string ProxyExecutor::callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) {
+void ProxyExecutor::callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) {
   std::vector<folly::dynamic> call{
     (double) moduleId,
     (double) methodId,
     std::move(arguments),
   };
-  return executeJSCallWithProxy(m_executor.get(), "callFunctionReturnFlushedQueue", std::move(call));
+  std::string result = executeJSCallWithProxy(m_executor.get(), "callFunctionReturnFlushedQueue", std::move(call));
+  m_bridge->callNativeModules(result, true);
 }
 
-std::string ProxyExecutor::invokeCallback(const double callbackId, const folly::dynamic& arguments) {
+void ProxyExecutor::invokeCallback(const double callbackId, const folly::dynamic& arguments) {
   std::vector<folly::dynamic> call{
     (double) callbackId,
     std::move(arguments)
   };
-  return executeJSCallWithProxy(m_executor.get(), "invokeCallbackAndReturnFlushedQueue", std::move(call));
+  std::string result = executeJSCallWithProxy(m_executor.get(), "invokeCallbackAndReturnFlushedQueue", std::move(call));
+  m_bridge->callNativeModules(result, true);
 }
 
 void ProxyExecutor::setGlobalVariable(const std::string& propName, const std::string& jsonValue) {
diff --git a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
index 09e7778b097e..1d9b8aebd8da 100644
--- a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
+++ b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
@@ -19,7 +19,7 @@ class ProxyExecutorOneTimeFactory : public CountableJSExecutorFactory {
 public:
   ProxyExecutorOneTimeFactory(jni::global_ref<jobject>&& executorInstance) :
     m_executor(std::move(executorInstance)) {}
-  virtual std::unique_ptr<JSExecutor> createJSExecutor(FlushImmediateCallback ignoredCallback) override;
+  virtual std::unique_ptr<JSExecutor> createJSExecutor(Bridge *bridge) override;
 
 private:
   jni::global_ref<jobject> m_executor;
@@ -27,8 +27,9 @@ class ProxyExecutorOneTimeFactory : public CountableJSExecutorFactory {
 
 class ProxyExecutor : public JSExecutor {
 public:
-  ProxyExecutor(jni::global_ref<jobject>&& executorInstance) :
-    m_executor(std::move(executorInstance)) {}
+  ProxyExecutor(jni::global_ref<jobject>&& executorInstance, Bridge *bridge) :
+    m_executor(std::move(executorInstance)),
+    m_bridge(bridge) {}
   virtual ~ProxyExecutor() override;
   virtual void executeApplicationScript(
     const std::string& script,
@@ -37,12 +38,11 @@ class ProxyExecutor : public JSExecutor {
     std::unique_ptr<JSModulesUnbundle> bundle,
     const std::string& startupCode,
     const std::string& sourceURL) override;
-  virtual std::string flush() override;
-  virtual std::string callFunction(
+  virtual void callFunction(
     const double moduleId,
     const double methodId,
     const folly::dynamic& arguments) override;
-  virtual std::string invokeCallback(
+  virtual void invokeCallback(
     const double callbackId,
     const folly::dynamic& arguments) override;
   virtual void setGlobalVariable(
@@ -51,6 +51,7 @@ class ProxyExecutor : public JSExecutor {
 
 private:
   jni::global_ref<jobject> m_executor;
+  Bridge *m_bridge;
 };
 
 } }

From 0de8860a46960a66af21eb78e7652abf9d871e50 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Fri, 12 Feb 2016 09:09:43 -0800
Subject: [PATCH 1146/1411] Rename executeApplicationScript ->
 loadApplicationScript

Reviewed By: davidaurelio

Differential Revision: D2921959

fb-gh-sync-id: 5bf44f5d037f2341000070f59309df0fab72aa29
shipit-source-id: 5bf44f5d037f2341000070f59309df0fab72aa29
---
 .../react/bridge/JSDebuggerWebSocketClient.java    |  2 +-
 .../com/facebook/react/bridge/JavaJSExecutor.java  |  2 +-
 .../react/bridge/WebsocketJavaScriptExecutor.java  |  6 +++---
 ReactAndroid/src/main/jni/react/Bridge.cpp         |  4 ++--
 ReactAndroid/src/main/jni/react/Bridge.h           |  3 ++-
 ReactAndroid/src/main/jni/react/Executor.h         |  2 +-
 ReactAndroid/src/main/jni/react/JSCExecutor.cpp    | 10 +++++-----
 ReactAndroid/src/main/jni/react/JSCExecutor.h      |  2 +-
 ReactAndroid/src/main/jni/react/jni/OnLoad.cpp     | 12 ++++++------
 .../src/main/jni/react/jni/ProxyExecutor.cpp       |  8 ++++----
 .../src/main/jni/react/jni/ProxyExecutor.h         |  2 +-
 .../src/main/jni/react/test/jscexecutor.cpp        | 14 +++++++-------
 .../src/main/jni/react/test/jsclogging.cpp         |  2 +-
 13 files changed, 35 insertions(+), 34 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSDebuggerWebSocketClient.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSDebuggerWebSocketClient.java
index 13c99c043d43..849a0ea79c9c 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSDebuggerWebSocketClient.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSDebuggerWebSocketClient.java
@@ -103,7 +103,7 @@ public void prepareJSRuntime(JSDebuggerCallback callback) {
     }
   }
 
-  public void executeApplicationScript(
+  public void loadApplicationScript(
       String sourceURL,
       HashMap<String, String> injectedObjects,
       JSDebuggerCallback callback) {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaJSExecutor.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaJSExecutor.java
index 5c1b01b2222e..991fdfb6f292 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaJSExecutor.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaJSExecutor.java
@@ -40,7 +40,7 @@ public ProxyExecutorException(Throwable cause) {
    * @param sourceURL url or file location from which script content was loaded
    */
   @DoNotStrip
-  void executeApplicationScript(String script, String sourceURL) throws ProxyExecutorException;
+  void loadApplicationScript(String script, String sourceURL) throws ProxyExecutorException;
 
   /**
    * Execute javascript method within js context
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/WebsocketJavaScriptExecutor.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/WebsocketJavaScriptExecutor.java
index cddadba00744..b9e1da2adbf0 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/WebsocketJavaScriptExecutor.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/WebsocketJavaScriptExecutor.java
@@ -159,10 +159,10 @@ public void close() {
   }
 
   @Override
-  public void executeApplicationScript(String script, String sourceURL)
+  public void loadApplicationScript(String script, String sourceURL)
       throws ProxyExecutorException {
     JSExecutorCallbackFuture callback = new JSExecutorCallbackFuture();
-    Assertions.assertNotNull(mWebSocketClient).executeApplicationScript(
+    Assertions.assertNotNull(mWebSocketClient).loadApplicationScript(
         sourceURL,
         mInjectedObjects,
         callback);
@@ -190,7 +190,7 @@ public void executeApplicationScript(String script, String sourceURL)
 
   @Override
   public void setGlobalVariable(String propertyName, String jsonEncodedValue) {
-    // Store and use in the next executeApplicationScript() call.
+    // Store and use in the next loadApplicationScript() call.
     mInjectedObjects.put(propertyName, jsonEncodedValue);
   }
 }
diff --git a/ReactAndroid/src/main/jni/react/Bridge.cpp b/ReactAndroid/src/main/jni/react/Bridge.cpp
index 821975bffc06..5cc7b2151fba 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.cpp
+++ b/ReactAndroid/src/main/jni/react/Bridge.cpp
@@ -22,8 +22,8 @@ Bridge::~Bridge() {
   m_jsExecutor.reset();
 }
 
-void Bridge::executeApplicationScript(const std::string& script, const std::string& sourceURL) {
-  m_jsExecutor->executeApplicationScript(script, sourceURL);
+void Bridge::loadApplicationScript(const std::string& script, const std::string& sourceURL) {
+  m_jsExecutor->loadApplicationScript(script, sourceURL);
 }
 
 void Bridge::loadApplicationUnbundle(
diff --git a/ReactAndroid/src/main/jni/react/Bridge.h b/ReactAndroid/src/main/jni/react/Bridge.h
index adfff7ae0cc6..d649c94fadbe 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.h
+++ b/ReactAndroid/src/main/jni/react/Bridge.h
@@ -43,7 +43,8 @@ class Bridge {
    * contains code for all modules and a runtime that resolves and
    * executes modules.
    */
-  void executeApplicationScript(const std::string& script, const std::string& sourceURL);
+  void loadApplicationScript(const std::string& script, const std::string& sourceURL);
+
   /**
    * Starts the JS application from an "unbundle", i.e. a backend that stores
    * and injects each module as individual file.
diff --git a/ReactAndroid/src/main/jni/react/Executor.h b/ReactAndroid/src/main/jni/react/Executor.h
index beace69a4037..8da103630a1c 100644
--- a/ReactAndroid/src/main/jni/react/Executor.h
+++ b/ReactAndroid/src/main/jni/react/Executor.h
@@ -30,7 +30,7 @@ class JSExecutor {
   /**
    * Execute an application script bundle in the JS context.
    */
-  virtual void executeApplicationScript(
+  virtual void loadApplicationScript(
     const std::string& script,
     const std::string& sourceURL) = 0;
 
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index 7815aae25645..2398988ba593 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -128,16 +128,16 @@ JSCExecutor::~JSCExecutor() {
   JSGlobalContextRelease(m_context);
 }
 
-void JSCExecutor::executeApplicationScript(
+void JSCExecutor::loadApplicationScript(
     const std::string& script,
     const std::string& sourceURL) {
-  ReactMarker::logMarker("executeApplicationScript_startStringConvert");
+  ReactMarker::logMarker("loadApplicationScript_startStringConvert");
   String jsScript = String::createExpectingAscii(script);
-  ReactMarker::logMarker("executeApplicationScript_endStringConvert");
+  ReactMarker::logMarker("loadApplicationScript_endStringConvert");
 
   String jsSourceURL(sourceURL.c_str());
   #ifdef WITH_FBSYSTRACE
-  FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor::executeApplicationScript",
+  FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor::loadApplicationScript",
     "sourceURL", sourceURL);
   #endif
   if (!jsSourceURL) {
@@ -158,7 +158,7 @@ void JSCExecutor::loadApplicationUnbundle(
     installGlobalFunction(m_context, "nativeRequire", nativeRequire);
   }
   m_unbundle = std::move(unbundle);
-  executeApplicationScript(startupCode, sourceURL);
+  loadApplicationScript(startupCode, sourceURL);
 }
 
 void JSCExecutor::flush() {
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.h b/ReactAndroid/src/main/jni/react/JSCExecutor.h
index 4db73b058aaa..41558bd4a800 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.h
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.h
@@ -31,7 +31,7 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
   explicit JSCExecutor(Bridge *bridge, const std::string& cacheDir);
   ~JSCExecutor() override;
 
-  virtual void executeApplicationScript(
+  virtual void loadApplicationScript(
     const std::string& script,
     const std::string& sourceURL) override;
   virtual void loadApplicationUnbundle(
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index a8dd4a0b5b3c..6fe35d73c1a7 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -651,12 +651,12 @@ static void create(JNIEnv* env, jobject obj, jobject executor, jobject callback,
   setCountableForJava(env, obj, std::move(bridge));
 }
 
-static void executeApplicationScript(
+static void loadApplicationScript(
     const RefPtr<CountableBridge>& bridge,
     const std::string& script,
     const std::string& sourceUri) {
   try {
-    bridge->executeApplicationScript(script, sourceUri);
+    bridge->loadApplicationScript(script, sourceUri);
   } catch (...) {
     translatePendingCppExceptionToJavaException();
   }
@@ -689,7 +689,7 @@ static void loadScriptFromAssets(JNIEnv* env, jobject obj, jobject assetManager,
   auto script = react::loadScriptFromAssets(manager, assetNameStr);
   #ifdef WITH_FBSYSTRACE
   FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "reactbridge_jni_"
-    "executeApplicationScript",
+    "loadApplicationScript",
     "assetName", assetNameStr);
   #endif
 
@@ -697,7 +697,7 @@ static void loadScriptFromAssets(JNIEnv* env, jobject obj, jobject assetManager,
   if (JniJSModulesUnbundle::isUnbundle(manager, assetNameStr)) {
     loadApplicationUnbundle(bridge, manager, script, "file://" + assetNameStr);
   } else {
-    executeApplicationScript(bridge, script, "file://" + assetNameStr);
+    loadApplicationScript(bridge, script, "file://" + assetNameStr);
   }
   if (env->ExceptionCheck()) {
     return;
@@ -715,11 +715,11 @@ static void loadScriptFromFile(JNIEnv* env, jobject obj, jstring fileName, jstri
   #ifdef WITH_FBSYSTRACE
   auto sourceURLStr = sourceURL == NULL ? fileNameStr : fromJString(env, sourceURL);
   FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "reactbridge_jni_"
-    "executeApplicationScript",
+    "loadApplicationScript",
     "sourceURL", sourceURLStr);
   #endif
   env->CallStaticVoidMethod(markerClass, gLogMarkerMethod, env->NewStringUTF("loadScriptFromFile_read"));
-  executeApplicationScript(bridge, script, jni::fromJString(env, sourceURL));
+  loadApplicationScript(bridge, script, jni::fromJString(env, sourceURL));
   if (env->ExceptionCheck()) {
     return;
   }
diff --git a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
index d43553a1d83e..c249f0ad3148 100644
--- a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
@@ -40,13 +40,13 @@ ProxyExecutor::~ProxyExecutor() {
   m_executor.reset();
 }
 
-void ProxyExecutor::executeApplicationScript(
+void ProxyExecutor::loadApplicationScript(
     const std::string& script,
     const std::string& sourceURL) {
-  static auto executeApplicationScript =
-    jni::findClassStatic(EXECUTOR_BASECLASS)->getMethod<void(jstring, jstring)>("executeApplicationScript");
+  static auto loadApplicationScript =
+    jni::findClassStatic(EXECUTOR_BASECLASS)->getMethod<void(jstring, jstring)>("loadApplicationScript");
 
-  executeApplicationScript(
+  loadApplicationScript(
     m_executor.get(),
     jni::make_jstring(script).get(),
     jni::make_jstring(sourceURL).get());
diff --git a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
index 1d9b8aebd8da..c66346424920 100644
--- a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
+++ b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h
@@ -31,7 +31,7 @@ class ProxyExecutor : public JSExecutor {
     m_executor(std::move(executorInstance)),
     m_bridge(bridge) {}
   virtual ~ProxyExecutor() override;
-  virtual void executeApplicationScript(
+  virtual void loadApplicationScript(
     const std::string& script,
     const std::string& sourceURL) override;
   virtual void loadApplicationUnbundle(
diff --git a/ReactAndroid/src/main/jni/react/test/jscexecutor.cpp b/ReactAndroid/src/main/jni/react/test/jscexecutor.cpp
index 9091c1125055..1de276f2093e 100644
--- a/ReactAndroid/src/main/jni/react/test/jscexecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/test/jscexecutor.cpp
@@ -33,7 +33,7 @@ TEST(JSCExecutor, CallFunction) {
   "function require() { return Bridge; }"
   "";
   JSCExecutor e;
-  e.executeApplicationScript(jsText, "");
+  e.loadApplicationScript(jsText, "");
   std::vector<MethodArgument> args;
   args.emplace_back(true);
   args.emplace_back(0.4);
@@ -62,7 +62,7 @@ TEST(JSCExecutor, CallFunctionWithMap) {
   "function require() { return Bridge; }"
   "";
   JSCExecutor e;
-  e.executeApplicationScript(jsText, "");
+  e.loadApplicationScript(jsText, "");
   std::vector<MethodArgument> args;
   std::map<std::string, MethodArgument> map {
     { "foo", MethodArgument("hello") },
@@ -89,7 +89,7 @@ TEST(JSCExecutor, CallFunctionReturningMap) {
   "function require() { return Bridge; }"
   "";
   JSCExecutor e;
-  e.executeApplicationScript(jsText, "");
+  e.loadApplicationScript(jsText, "");
   auto returnedCalls = executeForMethodCalls(e, 10, 9);
   ASSERT_EQ(1, returnedCalls.size());
   auto returnedCall = returnedCalls[0];
@@ -115,7 +115,7 @@ TEST(JSCExecutor, CallFunctionWithArray) {
   "function require() { return Bridge; }"
   "";
   JSCExecutor e;
-  e.executeApplicationScript(jsText, "");
+  e.loadApplicationScript(jsText, "");
   std::vector<MethodArgument> args;
   std::vector<MethodArgument> array {
     MethodArgument("hello"),
@@ -142,7 +142,7 @@ TEST(JSCExecutor, CallFunctionReturningNumberArray) {
   "function require() { return Bridge; }"
   "";
   JSCExecutor e;
-  e.executeApplicationScript(jsText, "");
+  e.loadApplicationScript(jsText, "");
   auto returnedCalls = executeForMethodCalls(e, 10, 9);
   ASSERT_EQ(1, returnedCalls.size());
   auto returnedCall = returnedCalls[0];
@@ -165,7 +165,7 @@ TEST(JSCExecutor, SetSimpleGlobalVariable) {
   "function require() { return Bridge; }"
   "";
   JSCExecutor e;
-  e.executeApplicationScript(jsText, "");
+  e.loadApplicationScript(jsText, "");
   e.setGlobalVariable("__foo", "42");
   auto returnedCalls = executeForMethodCalls(e, 10, 9);
   ASSERT_EQ(1, returnedCalls.size());
@@ -185,7 +185,7 @@ TEST(JSCExecutor, SetObjectGlobalVariable) {
   "function require() { return Bridge; }"
   "";
   JSCExecutor e;
-  e.executeApplicationScript(jsText, "");
+  e.loadApplicationScript(jsText, "");
   auto jsonObject = ""
   "{"
   "  \"foo\": \"hello\","
diff --git a/ReactAndroid/src/main/jni/react/test/jsclogging.cpp b/ReactAndroid/src/main/jni/react/test/jsclogging.cpp
index 0bf49e33d6fa..56ad010bc2e8 100644
--- a/ReactAndroid/src/main/jni/react/test/jsclogging.cpp
+++ b/ReactAndroid/src/main/jni/react/test/jsclogging.cpp
@@ -38,7 +38,7 @@ TEST_F(JSCLoggingTest, LogException) {
   expectedLogMessageSubstring = "I am a banana!";
 
   JSCExecutor e;
-  e.executeApplicationScript(jsText, "");
+  e.loadApplicationScript(jsText, "");
 
   ASSERT_TRUE(hasSeenExpectedLogMessage);
 }

From 9547264a96f16ea94fe6beee45a0fd774368dc68 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Fri, 12 Feb 2016 09:09:44 -0800
Subject: [PATCH 1147/1411] WebWorkers: Rename Bridge.m_jsExecutor ->
 Bridge.m_mainExecutor

Reviewed By: cjhopman

Differential Revision: D2921994

fb-gh-sync-id: ec06b922264a443932eb0446ff820aaf3dcacaa7
shipit-source-id: ec06b922264a443932eb0446ff820aaf3dcacaa7
---
 ReactAndroid/src/main/jni/react/Bridge.cpp | 24 +++++++++++-----------
 ReactAndroid/src/main/jni/react/Bridge.h   |  2 +-
 2 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/Bridge.cpp b/ReactAndroid/src/main/jni/react/Bridge.cpp
index 5cc7b2151fba..a8ee4c2f52bd 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.cpp
+++ b/ReactAndroid/src/main/jni/react/Bridge.cpp
@@ -13,24 +13,24 @@ namespace react {
 Bridge::Bridge(JSExecutorFactory* jsExecutorFactory, Callback callback) :
     m_callback(std::move(callback)),
     m_destroyed(std::shared_ptr<bool>(new bool(false))) {
-  m_jsExecutor = jsExecutorFactory->createJSExecutor(this);
+    m_mainExecutor = jsExecutorFactory->createJSExecutor(this);
 }
 
 // This must be called on the same thread on which the constructor was called.
 Bridge::~Bridge() {
   *m_destroyed = true;
-  m_jsExecutor.reset();
+  m_mainExecutor.reset();
 }
 
 void Bridge::loadApplicationScript(const std::string& script, const std::string& sourceURL) {
-  m_jsExecutor->loadApplicationScript(script, sourceURL);
+  m_mainExecutor->loadApplicationScript(script, sourceURL);
 }
 
 void Bridge::loadApplicationUnbundle(
     std::unique_ptr<JSModulesUnbundle> unbundle,
     const std::string& startupCode,
     const std::string& sourceURL) {
-  m_jsExecutor->loadApplicationUnbundle(std::move(unbundle), startupCode, sourceURL);
+  m_mainExecutor->loadApplicationUnbundle(std::move(unbundle), startupCode, sourceURL);
 }
 
 void Bridge::callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) {
@@ -40,7 +40,7 @@ void Bridge::callFunction(const double moduleId, const double methodId, const fo
   #ifdef WITH_FBSYSTRACE
   FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "Bridge.callFunction");
   #endif
-  m_jsExecutor->callFunction(moduleId, methodId, arguments);
+  m_mainExecutor->callFunction(moduleId, methodId, arguments);
 }
 
 void Bridge::invokeCallback(const double callbackId, const folly::dynamic& arguments) {
@@ -50,31 +50,31 @@ void Bridge::invokeCallback(const double callbackId, const folly::dynamic& argum
   #ifdef WITH_FBSYSTRACE
   FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "Bridge.invokeCallback");
   #endif
-  m_jsExecutor->invokeCallback(callbackId, arguments);
+  m_mainExecutor->invokeCallback(callbackId, arguments);
 }
 
 void Bridge::setGlobalVariable(const std::string& propName, const std::string& jsonValue) {
-  m_jsExecutor->setGlobalVariable(propName, jsonValue);
+  m_mainExecutor->setGlobalVariable(propName, jsonValue);
 }
 
 bool Bridge::supportsProfiling() {
-  return m_jsExecutor->supportsProfiling();
+  return m_mainExecutor->supportsProfiling();
 }
 
 void Bridge::startProfiler(const std::string& title) {
-  m_jsExecutor->startProfiler(title);
+  m_mainExecutor->startProfiler(title);
 }
 
 void Bridge::stopProfiler(const std::string& title, const std::string& filename) {
-  m_jsExecutor->stopProfiler(title, filename);
+  m_mainExecutor->stopProfiler(title, filename);
 }
 
 void Bridge::handleMemoryPressureModerate() {
-  m_jsExecutor->handleMemoryPressureModerate();
+  m_mainExecutor->handleMemoryPressureModerate();
 }
 
 void Bridge::handleMemoryPressureCritical() {
-  m_jsExecutor->handleMemoryPressureCritical();
+  m_mainExecutor->handleMemoryPressureCritical();
 }
 
 void Bridge::callNativeModules(const std::string& callJSON, bool isEndOfBatch) {
diff --git a/ReactAndroid/src/main/jni/react/Bridge.h b/ReactAndroid/src/main/jni/react/Bridge.h
index d649c94fadbe..d9c108a30d8b 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.h
+++ b/ReactAndroid/src/main/jni/react/Bridge.h
@@ -70,7 +70,7 @@ class Bridge {
   // on the same thread. In that case, the callback will try to run the task on m_callback which
   // will have been destroyed within ~Bridge(), thus causing a SIGSEGV.
   std::shared_ptr<bool> m_destroyed;
-  std::unique_ptr<JSExecutor> m_jsExecutor;
+  std::unique_ptr<JSExecutor> m_mainExecutor;
 };
 
 } }

From 194273f5f50109f21739ab11db944e65cd18f7c0 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Fri, 12 Feb 2016 09:27:21 -0800
Subject: [PATCH 1148/1411] Fixed hitTest crash due to sticky header
 out-of-range

Reviewed By: javache

Differential Revision: D2932227

fb-gh-sync-id: 05d69ec391685dd7e72d3d5f7d56b189a6eab413
shipit-source-id: 05d69ec391685dd7e72d3d5f7d56b189a6eab413
---
 React/Views/RCTScrollView.m | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/React/Views/RCTScrollView.m b/React/Views/RCTScrollView.m
index 10f2e5ec9c53..4cc9d4bc871c 100644
--- a/React/Views/RCTScrollView.m
+++ b/React/Views/RCTScrollView.m
@@ -349,8 +349,14 @@ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
 {
   __block UIView *hitView;
 
+  NSArray *subviews = [self contentView].reactSubviews;
+  NSUInteger subviewCount = subviews.count;
   [_stickyHeaderIndices enumerateIndexesWithOptions:0 usingBlock:^(NSUInteger idx, BOOL *stop) {
-    UIView *stickyHeader = [self contentView].reactSubviews[idx];
+    if (idx >= subviewCount) {
+      *stop = YES;
+      return;
+    }
+    UIView *stickyHeader = subviews[idx];
     CGPoint convertedPoint = [stickyHeader convertPoint:point fromView:self];
     hitView = [stickyHeader hitTest:convertedPoint withEvent:event];
     *stop = (hitView != nil);

From e93afad284fe467c5929ceb297fd1a5e0a353dce Mon Sep 17 00:00:00 2001
From: Emily Janzer <janzer@fb.com>
Date: Fri, 12 Feb 2016 11:32:06 -0800
Subject: [PATCH 1149/1411] Don't show underlay if no press handlers

Reviewed By: sahrens

Differential Revision: D2915003

fb-gh-sync-id: 56ba942ed464e393ea43229b1fa9ef6936a24ecc
shipit-source-id: 56ba942ed464e393ea43229b1fa9ef6936a24ecc
---
 .../Components/Touchable/TouchableHighlight.js      | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/Libraries/Components/Touchable/TouchableHighlight.js b/Libraries/Components/Touchable/TouchableHighlight.js
index 4c7324d6f6e7..ca94126665d3 100644
--- a/Libraries/Components/Touchable/TouchableHighlight.js
+++ b/Libraries/Components/Touchable/TouchableHighlight.js
@@ -189,7 +189,7 @@ var TouchableHighlight = React.createClass({
   },
 
   _showUnderlay: function() {
-    if (!this.isMounted()) {
+    if (!this.isMounted() || !this._hasPressHandler()) {
       return;
     }
 
@@ -201,7 +201,7 @@ var TouchableHighlight = React.createClass({
   _hideUnderlay: function() {
     this.clearTimeout(this._hideTimeout);
     this._hideTimeout = null;
-    if (this.refs[UNDERLAY_REF]) {
+    if (this._hasPressHandler() && this.refs[UNDERLAY_REF]) {
       this.refs[CHILD_REF].setNativeProps(INACTIVE_CHILD_PROPS);
       this.refs[UNDERLAY_REF].setNativeProps({
         ...INACTIVE_UNDERLAY_PROPS,
@@ -211,6 +211,15 @@ var TouchableHighlight = React.createClass({
     }
   },
 
+  _hasPressHandler: function() {
+    return !!(
+      this.props.onPress || 
+      this.props.onPressIn || 
+      this.props.onPressOut || 
+      this.props.onLongPress
+    );
+  },
+
   render: function() {
     return (
       <View

From 6c7991c3f27491f23ece011f8ad1891e278eafca Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Fri, 12 Feb 2016 11:57:01 -0800
Subject: [PATCH 1150/1411] Added ability to switch version in documentation
 website

Reviewed By: svcscm

Differential Revision: D2932534

fb-gh-sync-id: e67f028c914b64424458dad8fe52e588f6d0cd1c
shipit-source-id: e67f028c914b64424458dad8fe52e588f6d0cd1c
---
 website/core/Site.js                          |  4 ++
 website/package.json                          | 15 +++---
 website/publish-gh-pages.js                   | 23 +++++++--
 website/src/react-native/css/react-native.css | 17 +++++++
 website/src/react-native/versions.js          | 49 +++++++++++++++++++
 5 files changed, 96 insertions(+), 12 deletions(-)
 create mode 100644 website/src/react-native/versions.js

diff --git a/website/core/Site.js b/website/core/Site.js
index 183690e919de..19e3eaed058f 100644
--- a/website/core/Site.js
+++ b/website/core/Site.js
@@ -16,6 +16,7 @@ var Metadata = require('Metadata');
 var Site = React.createClass({
   render: function() {
     const path = Metadata.config.RN_DEPLOYMENT_PATH;
+    const version = Metadata.config.RN_VERSION;
     var basePath = '/react-native/' + (path ? path + '/' : '');
     var title = this.props.title ? this.props.title + ' – ' : '';
     var currentYear = (new Date()).getFullYear();
@@ -52,6 +53,9 @@ var Site = React.createClass({
                   <img src="img/header_logo.png" />
                   React Native
                 </a>
+                <a className="nav-version" href="/react-native/versions.html">
+                  {version}
+                </a>
                 <HeaderLinks section={this.props.section} />
               </div>
             </div>
diff --git a/website/package.json b/website/package.json
index 37aa934f7b7f..69e3093b99fd 100644
--- a/website/package.json
+++ b/website/package.json
@@ -1,21 +1,22 @@
 {
   "scripts": {
-    "start": "node server/server.js",
+    "start": "RN_VERSION=next node server/server.js",
     "gh-pages": "node publish-gh-pages.js"
   },
   "dependencies": {
     "bluebird": "^2.9.21",
     "connect": "2.8.3",
-    "esprima-fb": "latest",
-    "fs.extra": "latest",
-    "glob": "latest",
-    "jstransform": "latest",
-    "mkdirp": "latest",
+    "esprima-fb": "15001.1001.0-dev-harmony-fb",
+    "fs.extra": "1.3.2",
+    "glob": "6.0.4",
+    "jstransform": "11.0.3",
+    "mkdirp": "^0.5.1",
     "optimist": "0.6.0",
     "react": "~0.13.0",
     "react-docgen": "^2.0.1",
     "react-page-middleware": "git://github.com/facebook/react-page-middleware.git",
-    "request": "latest",
+    "request": "^2.69.0",
+    "semver-compare": "^1.0.0",
     "shelljs": "^0.6.0"
   }
 }
diff --git a/website/publish-gh-pages.js b/website/publish-gh-pages.js
index fc30181c03f8..bc2fa2f1a873 100644
--- a/website/publish-gh-pages.js
+++ b/website/publish-gh-pages.js
@@ -8,14 +8,15 @@
  */
 'use strict';
 
-const CIRCLE_BRANCH = process.env.CIRCLE_BRANCH || '';
+var semverCmp = require('semver-compare');
+require(`shelljs/global`);
+
+const CIRCLE_BRANCH = process.env.CIRCLE_BRANCH;
 const CIRCLE_PROJECT_USERNAME = process.env.CIRCLE_PROJECT_USERNAME;
-const CIRCLE_PROJECT_REPONAME = process.env.CIRCLE_PROJECT_REPONAME;
 const CI_PULL_REQUESTS = process.env.CI_PULL_REQUESTS;
 const CI_PULL_REQUEST = process.env.CI_PULL_REQUEST;
 const GIT_USER = process.env.GIT_USER;
 const remoteBranch = `https://${GIT_USER}@github.com/facebook/react-native.git`;
-require(`shelljs/global`);
 
 if (!which(`git`)) {
   echo(`Sorry, this script requires git`);
@@ -55,25 +56,37 @@ if (!CI_PULL_REQUEST && CIRCLE_PROJECT_USERNAME === `facebook`) {
     echo(`Error: Git checkout gh-pages failed`);
     exit(1);
   }
+  cd(`releases`);
+  var releasesFolders = ls(`-d`, `*`)
+  cd(`..`);
+  var versions = releasesFolders.filter(name => name !== `next`);
+  if (versions.indexOf(version) === -1) {
+    versions.push(version);
+  }
+  versions.sort(semverCmp).reverse();
+
   // generate to releases/XX when branch name indicates that it is some sort of release
   if (!!version) {
     echo(`------------ DEPLOYING /releases/${version}`);
     rm(`-rf`, `releases/${version}`);
     mkdir(`-p`, `releases/${version}`);
     cd(`../..`);
-    if (exec(`RN_DEPLOYMENT_PATH=releases/${version} node server/generate.js`).code !== 0) {
+    if (exec(`RN_DEPLOYMENT_PATH=releases/${version} RN_VERSION=${version} \
+    RN_AVAILABLE_DOCS_VERSIONS=${versions.join(',')} node server/generate.js`).code !== 0) {
       echo(`Error: Generating HTML failed`);
       exit(1);
     }
     cd(`build/react-native-gh-pages`);
     exec(`cp -R ../react-native/* releases/${version}`);
+    // versions.html is located in root of website and updated with every release
+    exec(`cp ../react-native/versions.html .`);
   }
   if (currentCommit === latestTagCommit) {
     echo(`------------ DEPLOYING latest`);
     // leave only releases folder
     rm(`-rf`, ls(`*`).filter(name => name !== 'releases'));
     cd(`../..`);
-    if (exec(`node server/generate.js`).code !== 0) {
+    if (exec(`RN_VERSION=${version} RN_AVAILABLE_DOCS_VERSIONS=${versions} node server/generate.js`).code !== 0) {
       echo(`Error: Generating HTML failed`);
       exit(1);
     }
diff --git a/website/src/react-native/css/react-native.css b/website/src/react-native/css/react-native.css
index 59b4fa3391e5..98e60504a1bf 100644
--- a/website/src/react-native/css/react-native.css
+++ b/website/src/react-native/css/react-native.css
@@ -312,6 +312,14 @@ h1:hover .hash-link, h2:hover .hash-link, h3:hover .hash-link, h4:hover .hash-li
   display: inline;
 }
 
+.nav-main a.nav-version {
+  font-size: 16px;
+  font-weight: 800;
+  color: #05A5D1;
+  margin-left: 5px;
+  text-decoration: underline;
+}
+
 .hero {
   background: #05A5D1;
   padding: 50px 0;
@@ -478,6 +486,15 @@ h1:hover .hash-link, h2:hover .hash-link, h3:hover .hash-link, h4:hover .hash-li
   box-shadow: 5px 5px 5px #888888;
 }
 
+.versions ul {
+  list-style: none;
+}
+
+.versions li {
+  font-size: 16px;
+  padding-top: 10px;
+}
+
 #examples h3, .home-presentation h3 {
   color: #2d2d2d;
   font-size: 24px;
diff --git a/website/src/react-native/versions.js b/website/src/react-native/versions.js
new file mode 100644
index 000000000000..336903867129
--- /dev/null
+++ b/website/src/react-native/versions.js
@@ -0,0 +1,49 @@
+/**
+ * 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.
+ */
+
+var React = require('React');
+var Site = require('Site');
+var Metadata = require('Metadata');
+
+var versions = React.createClass({
+  render: function() {
+
+    var availableDocs = (Metadata.config.RN_AVAILABLE_DOCS_VERSIONS || '').split(',');
+    var versions = [
+      {
+        title: 'next',
+        path: '/react-native/releases/next',
+      },
+      {
+        title: 'stable',
+        path: '/react-native',
+      },
+    ].concat(availableDocs.map((version) => {
+      return {
+        title: version,
+        path: '/react-native/releases/' + version
+      }
+    }));
+    var versionsLi = versions.map((version) =>
+      <li><a href={version.path}>{version.title}</a></li>
+    );
+    return (
+      <Site section="versions" title="Documentation archive">
+        <section className="content wrap versions documentationContent">
+          <h1>Documentation archive</h1>
+          <ul>
+            {versionsLi}
+          </ul>
+        </section>
+      </Site>
+    );
+  }
+});
+
+module.exports = versions;

From e6a39a1d18aa77917df2c4ec7ed1c4494fbcfeba Mon Sep 17 00:00:00 2001
From: Ali Najafizadeh <ali@pressly.com>
Date: Fri, 12 Feb 2016 12:57:48 -0800
Subject: [PATCH 1151/1411] Update Linking.js

Reviewed By: svcscm

Differential Revision: D2933128

fb-gh-sync-id: ef33f88db50d6ddb7dd208b7ba5dab41c1ee2f81
shipit-source-id: ef33f88db50d6ddb7dd208b7ba5dab41c1ee2f81
---
 Libraries/Linking/Linking.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/Linking/Linking.js b/Libraries/Linking/Linking.js
index a27e454647b6..d3603166f672 100644
--- a/Libraries/Linking/Linking.js
+++ b/Libraries/Linking/Linking.js
@@ -38,7 +38,7 @@ const DEVICE_NOTIF_EVENT = 'openURL';
  *
  * ```
  * componentDidMount() {
- *   var url = Linking.getInitialURL().then(url) => {
+ *   var url = Linking.getInitialURL().then((url) => {
  *     if (url) {
  *       console.log('Initial url is: ' + url);
  *     }

From 4b722d6d2ac46655ea144ad48d2f9d22fd122c61 Mon Sep 17 00:00:00 2001
From: Alex Krolick <whokilledtheelectricmonk@gmail.com>
Date: Fri, 12 Feb 2016 13:38:32 -0800
Subject: [PATCH 1152/1411] Add context to async example function in Network
 docs

Reviewed By: svcscm

Differential Revision: D2933584

fb-gh-sync-id: 24436b185791e3fa8047be521894545c08a90ee0
shipit-source-id: 24436b185791e3fa8047be521894545c08a90ee0
---
 docs/Network.md | 47 ++++++++++++++++++++++++++---------------------
 1 file changed, 26 insertions(+), 21 deletions(-)

diff --git a/docs/Network.md b/docs/Network.md
index 1997e47f3265..fa8566d2e301 100644
--- a/docs/Network.md
+++ b/docs/Network.md
@@ -41,29 +41,34 @@ fetch('https://mywebsite.com/endpoint/', {
 
 1.  Using `then` and `catch` in synchronous code:
 
-```js
-fetch('https://mywebsite.com/endpoint.php')
-  .then((response) => response.text())
-  .then((responseText) => {
-    console.log(responseText);
-  })
-  .catch((error) => {
-    console.warn(error);
-  });
-```
-
+  ```js
+  fetch('https://mywebsite.com/endpoint.php')
+    .then((response) => response.text())
+    .then((responseText) => {
+      console.log(responseText);
+    })
+    .catch((error) => {
+      console.warn(error);
+    });
+  ```
 2.  Called within an asynchronous function using ES7 `async`/`await` syntax:
-
-```js
-async getUsersFromApi() {
-  try {
-    let response = await fetch('https://mywebsite.com/endpoint/');
-    return response.users;
-  } catch(error) {
-    throw error;
+  
+  ```js
+  class MyComponent extends React.Component {
+    ...
+    async getUsersFromApi() {
+      try {
+        let response = await fetch('https://mywebsite.com/endpoint/');
+        let responseJson = await response.json();
+        return responseJson.users;
+      } catch(error) {
+        // Handle error
+        console.error(error);
+      }
+    }
+    ...
   }
-}
-```
+  ```
 
 - Note: Errors thrown by rejected Promises need to be caught, or they will be swallowed silently
 

From bb3d8d535000ad78a95776f2de9282130f80d0bd Mon Sep 17 00:00:00 2001
From: Matthew Dapena-Tretter <matthewwithanm@fb.com>
Date: Fri, 12 Feb 2016 14:53:36 -0800
Subject: [PATCH 1153/1411] Ensure recursion is terminated on objects with
 cyclical references

Reviewed By: spicyj

Differential Revision: D2922542

fb-gh-sync-id: 3820569027a5906ff844f1cda5e2e65c2692e235
shipit-source-id: 3820569027a5906ff844f1cda5e2e65c2692e235
---
 Libraries/ReactNative/ReactNativeBaseComponent.js        | 6 +++++-
 Libraries/Utilities/deepFreezeAndThrowOnMutationInDev.js | 8 +++++++-
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/Libraries/ReactNative/ReactNativeBaseComponent.js b/Libraries/ReactNative/ReactNativeBaseComponent.js
index 0beef933454f..ceb600aaaaa0 100644
--- a/Libraries/ReactNative/ReactNativeBaseComponent.js
+++ b/Libraries/ReactNative/ReactNativeBaseComponent.js
@@ -115,7 +115,11 @@ ReactNativeBaseComponent.Mixin = {
     this._currentElement = nextElement;
 
     if (__DEV__) {
-      deepFreezeAndThrowOnMutationInDev(this._currentElement.props);
+      for (var key in this.viewConfig.validAttributes) {
+        if (nextElement.props.hasOwnProperty(key)) {
+          deepFreezeAndThrowOnMutationInDev(nextElement.props[key]);
+        }
+      }
     }
 
     var updatePayload = ReactNativeAttributePayload.diff(
diff --git a/Libraries/Utilities/deepFreezeAndThrowOnMutationInDev.js b/Libraries/Utilities/deepFreezeAndThrowOnMutationInDev.js
index 9263116ed707..b1dac7777dea 100644
--- a/Libraries/Utilities/deepFreezeAndThrowOnMutationInDev.js
+++ b/Libraries/Utilities/deepFreezeAndThrowOnMutationInDev.js
@@ -42,11 +42,17 @@ function deepFreezeAndThrowOnMutationInDev(object: Object) {
       if (object.hasOwnProperty(key)) {
         object.__defineGetter__(key, identity.bind(null, object[key]));
         object.__defineSetter__(key, throwOnImmutableMutation.bind(null, key));
-        deepFreezeAndThrowOnMutationInDev(object[key]);
       }
     }
+
     Object.freeze(object);
     Object.seal(object);
+
+    for (var key in object) {
+      if (object.hasOwnProperty(key)) {
+        deepFreezeAndThrowOnMutationInDev(object[key]);
+      }
+    }
   }
 }
 

From dec54698533e2fd2357d6f4c27cdfdb4d22cf01a Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@gmail.com>
Date: Fri, 12 Feb 2016 14:57:51 -0800
Subject: [PATCH 1154/1411] =?UTF-8?q?fixes=20next=20version=20being=20adde?=
 =?UTF-8?q?d=20to=20versions.html=20when=20master=20branch=20is=E2=80=A6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Reviewed By: svcscm

Differential Revision: D2933806

fb-gh-sync-id: 65faeff07de53539f4a68b1d8811969f9fa8b996
shipit-source-id: 65faeff07de53539f4a68b1d8811969f9fa8b996
---
 website/publish-gh-pages.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/website/publish-gh-pages.js b/website/publish-gh-pages.js
index bc2fa2f1a873..2e2530622022 100644
--- a/website/publish-gh-pages.js
+++ b/website/publish-gh-pages.js
@@ -60,7 +60,7 @@ if (!CI_PULL_REQUEST && CIRCLE_PROJECT_USERNAME === `facebook`) {
   var releasesFolders = ls(`-d`, `*`)
   cd(`..`);
   var versions = releasesFolders.filter(name => name !== `next`);
-  if (versions.indexOf(version) === -1) {
+  if (version !== `next` && versions.indexOf(version) === -1) {
     versions.push(version);
   }
   versions.sort(semverCmp).reverse();

From e9f2ff0ee1a61ca572c4f82347b3192c5163b2f3 Mon Sep 17 00:00:00 2001
From: Brent Vatne <brentvatne@gmail.com>
Date: Fri, 12 Feb 2016 15:06:38 -0800
Subject: [PATCH 1155/1411] Add NavigationExperimental to UIExplorer on Android
 too

Reviewed By: svcscm

Differential Revision: D2933949

fb-gh-sync-id: fab82a3f15813efb3dfdbce56c7e3e0473d8c899
shipit-source-id: fab82a3f15813efb3dfdbce56c7e3e0473d8c899
---
 Examples/UIExplorer/UIExplorerList.android.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index 8959a0919f9a..804ed69d4c59 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -53,6 +53,7 @@ var APIS = [
   require('./ImageEditingExample'),
   require('./IntentAndroidExample.android'),
   require('./LayoutEventsExample'),
+  require('./NavigationExperimental/NavigationExperimentalExample'),
   require('./LayoutExample'),
   require('./NavigationExperimental/NavigationExperimentalExample'),
   require('./NetInfoExample'),

From 1beced56c88aa152b541bf9635df5fa88474a58a Mon Sep 17 00:00:00 2001
From: Eric Vicenti <evv@fb.com>
Date: Fri, 12 Feb 2016 15:36:34 -0800
Subject: [PATCH 1156/1411] Navigation TicTacToe Example

Reviewed By: hedgerwang

Differential Revision: D2931575

fb-gh-sync-id: a60509315da4732d67b9b30bfc61f6d6a16be234
shipit-source-id: a60509315da4732d67b9b30bfc61f6d6a16be234
---
 .../NavigationExperimentalExample.js          |   1 +
 .../NavigationTicTacToeExample.js             | 303 ++++++++++++++++++
 2 files changed, 304 insertions(+)
 create mode 100644 Examples/UIExplorer/NavigationExperimental/NavigationTicTacToeExample.js

diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js
index 4aade5303c17..90b059e6d617 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js
@@ -32,6 +32,7 @@ var EXAMPLES = {
   'Basic': require('./NavigationBasicExample'),
   'Animated Card Stack': require('./NavigationAnimatedExample'),
   'Composition': require('./NavigationCompositionExample'),
+  'Tic Tac Toe': require('./NavigationTicTacToeExample'),
 };
 
 var EXAMPLE_STORAGE_KEY = 'NavigationExampleExample';
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationTicTacToeExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationTicTacToeExample.js
new file mode 100644
index 000000000000..898599ad5334
--- /dev/null
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationTicTacToeExample.js
@@ -0,0 +1,303 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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 NavigationTicTacToeExample
+ * @flow
+ */
+'use strict';
+
+var React = require('react-native');
+var {
+  // $FlowFixMe : this does exist..
+  NavigationExperimental,
+  StyleSheet,
+  Text,
+  TouchableHighlight,
+  View,
+} = React;
+const {
+  Container: NavigationContainer,
+  RootContainer: NavigationRootContainer,
+} = NavigationExperimental;
+
+type GameGrid = Array<Array<?string>>;
+
+const evenOddPlayerMap = ['o', 'x'];
+const rowLeterMap = ['a', 'b', 'c'];
+
+function parseGame(game: string): GameGrid {
+  const gameTurns = game ? game.split('-') : [];
+  const grid = Array(3);
+  for (let i = 0; i < 3; i++) {
+    const row = Array(3);
+    for (let j = 0; j < 3; j++) {
+      const turnIndex = gameTurns.indexOf(rowLeterMap[i]+j);
+      if (turnIndex === -1) {
+        row[j] = null;
+      } else {
+        row[j] = evenOddPlayerMap[turnIndex % 2];
+      }
+    }
+    grid[i] = row;
+  }
+  return grid;
+}
+
+function playTurn(game: string, row: number, col: number): string {
+  const turn = rowLeterMap[row] + col;
+  return game ? (game + '-' + turn) : turn;
+}
+
+function getWinner(gameString: string): ?string {
+  const game = parseGame(gameString);
+  for (var i = 0; i < 3; i++) {
+    if (game[i][0] !== null && game[i][0] === game[i][1] &&
+        game[i][0] === game[i][2]) {
+      return game[i][0];
+    }
+  }
+  for (var i = 0; i < 3; i++) {
+    if (game[0][i] !== null && game[0][i] === game[1][i] &&
+        game[0][i] === game[2][i]) {
+      return game[0][i];
+    }
+  }
+  if (game[0][0] !== null && game[0][0] === game[1][1] &&
+      game[0][0] === game[2][2]) {
+    return game[0][0];
+  }
+  if (game[0][2] !== null && game[0][2] === game[1][1] &&
+      game[0][2] === game[2][0]) {
+    return game[0][2];
+  }
+  return null;
+}
+
+function isGameOver(gameString: string): boolean {
+  if (getWinner(gameString)) {
+    return true;
+  }
+  const game = parseGame(gameString);
+  for (var i = 0; i < 3; i++) {
+    for (var j = 0; j < 3; j++) {
+      if (game[i][j] === null) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+class Cell extends React.Component {
+  cellStyle() {
+    switch (this.props.value) {
+      case 'x':
+        return styles.cellX;
+      case 'o':
+        return styles.cellO;
+      default:
+        return null;
+    }
+  }
+  textStyle() {
+    switch (this.props.value) {
+      case 'x':
+        return styles.cellTextX;
+      case 'o':
+        return styles.cellTextO;
+      default:
+        return {};
+    }
+  }
+  render() {
+    return (
+      <TouchableHighlight
+        onPress={this.props.onPress}
+        underlayColor="transparent"
+        activeOpacity={0.5}>
+        <View style={[styles.cell, this.cellStyle()]}>
+          <Text style={[styles.cellText, this.textStyle()]}>
+            {this.props.player}
+          </Text>
+        </View>
+      </TouchableHighlight>
+    );
+  }
+}
+
+function GameEndOverlay(props) {
+  if (!isGameOver(props.game)) {
+    return <View />;
+  }
+  const winner = getWinner(props.game);
+  return (
+    <View style={styles.overlay}>
+      <Text style={styles.overlayMessage}>
+        {winner ? winner + ' wins!' : 'It\'s a tie!'}
+      </Text>
+      <TouchableHighlight
+        onPress={() => props.onNavigate(GameActions.Reset())}
+        underlayColor="transparent"
+        activeOpacity={0.5}>
+        <View style={styles.newGame}>
+          <Text style={styles.newGameText}>New Game</Text>
+        </View>
+      </TouchableHighlight>
+    </View>
+  );
+}
+GameEndOverlay = NavigationContainer.create(GameEndOverlay);
+
+function TicTacToeGame(props) {
+  var rows = parseGame(props.game).map((cells, row) =>
+    <View key={'row' + row} style={styles.row}>
+      {cells.map((player, col) =>
+        <Cell
+          key={'cell' + col}
+          player={player}
+          onPress={() => props.onNavigate(GameActions.Turn(row, col))}
+        />
+      )}
+    </View>
+  );
+  return (
+    <View style={styles.container}>
+      <Text style={styles.title}>EXTREME T3</Text>
+      <View style={styles.board}>
+        {rows}
+      </View>
+      <GameEndOverlay
+        game={props.game}
+      />
+    </View>
+  );
+}
+TicTacToeGame = NavigationContainer.create(TicTacToeGame);
+
+const GameActions = {
+  Turn: (row, col) => ({gameAction: 'turn', row, col }),
+  Reset: (row, col) => ({gameAction: 'reset' }),
+};
+
+function GameReducer(lastGame: ?string, action: Object): string {
+  if (!lastGame || !action || !action.gameAction) {
+    return lastGame || '';
+  }
+  if (action.gameAction === 'reset') {
+    return '';
+  }
+  if (!isGameOver(lastGame) && action.gameAction === 'turn') {
+    return playTurn(lastGame, action.row, action.col);
+  }
+  return lastGame;
+}
+
+class NavigationTicTacToeExample extends React.Component {
+  render() {
+    return (
+      <NavigationRootContainer
+        reducer={GameReducer}
+        persistenceKey="TicTacToeGame"
+        renderNavigation={(game) => (
+          <TicTacToeGame
+            game={game}
+          />
+        )}
+      />
+    );
+  }
+}
+NavigationTicTacToeExample.GameView = TicTacToeGame;
+NavigationTicTacToeExample.GameReducer = GameReducer;
+NavigationTicTacToeExample.GameActions = GameActions;
+
+const styles = StyleSheet.create({
+  container: {
+    flex: 1,
+    justifyContent: 'center',
+    alignItems: 'center',
+    backgroundColor: 'white'
+  },
+  title: {
+    fontFamily: 'Chalkduster',
+    fontSize: 39,
+    marginBottom: 20,
+  },
+  board: {
+    padding: 5,
+    backgroundColor: '#47525d',
+    borderRadius: 10,
+  },
+  row: {
+    flexDirection: 'row',
+  },
+  cell: {
+    width: 80,
+    height: 80,
+    borderRadius: 5,
+    backgroundColor: '#7b8994',
+    margin: 5,
+    flex: 1,
+    justifyContent: 'center',
+    alignItems: 'center',
+  },
+  cellX: {
+    backgroundColor: '#72d0eb',
+  },
+  cellO: {
+    backgroundColor: '#7ebd26',
+  },
+  cellText: {
+    borderRadius: 5,
+    fontSize: 50,
+    fontFamily: 'AvenirNext-Bold',
+  },
+  cellTextX: {
+    color: '#19a9e5',
+  },
+  cellTextO: {
+    color: '#b9dc2f',
+  },
+  overlay: {
+    position: 'absolute',
+    top: 0,
+    bottom: 0,
+    left: 0,
+    right: 0,
+    backgroundColor: 'rgba(221, 221, 221, 0.5)',
+    flex: 1,
+    flexDirection: 'column',
+    justifyContent: 'center',
+    alignItems: 'center',
+  },
+  overlayMessage: {
+    fontSize: 40,
+    marginBottom: 20,
+    marginLeft: 20,
+    marginRight: 20,
+    fontFamily: 'AvenirNext-DemiBold',
+    textAlign: 'center',
+  },
+  newGame: {
+    backgroundColor: '#887766',
+    padding: 20,
+    borderRadius: 5,
+  },
+  newGameText: {
+    color: 'white',
+    fontSize: 20,
+    fontFamily: 'AvenirNext-DemiBold',
+  },
+});
+
+module.exports = NavigationTicTacToeExample;

From 1c507e62910f00606f61e8ae4b8c9b7ccceec2e6 Mon Sep 17 00:00:00 2001
From: Spencer Ahrens <sahrens@fb.com>
Date: Fri, 12 Feb 2016 18:08:38 -0800
Subject: [PATCH 1157/1411] return remover function when adding NetInfo
 listener

Reviewed By: dmmiller

Differential Revision: D2931623

fb-gh-sync-id: d67e986e2b4a503c0966a3f90788e207c452f216
shipit-source-id: d67e986e2b4a503c0966a3f90788e207c452f216
---
 Libraries/Network/NetInfo.js | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/Libraries/Network/NetInfo.js b/Libraries/Network/NetInfo.js
index fff16c59860f..474ffd8f5bd1 100644
--- a/Libraries/Network/NetInfo.js
+++ b/Libraries/Network/NetInfo.js
@@ -166,7 +166,7 @@ const NetInfo = {
   addEventListener(
     eventName: ChangeEventName,
     handler: Function
-  ): void {
+  ): {remove: () => void} {
     const listener = RCTDeviceEventEmitter.addListener(
       DEVICE_CONNECTIVITY_EVENT,
       (appStateData) => {
@@ -174,6 +174,9 @@ const NetInfo = {
       }
     );
     _subscriptions.set(handler, listener);
+    return {
+      remove: () => NetInfo.removeEventListener(eventName, handler)
+    };
   },
 
   removeEventListener(
@@ -203,7 +206,7 @@ const NetInfo = {
     addEventListener(
       eventName: ChangeEventName,
       handler: Function
-    ): void {
+    ): {remove: () => void} {
       const listener = (connection) => {
         handler(_isConnected(connection));
       };
@@ -212,6 +215,9 @@ const NetInfo = {
         eventName,
         listener
       );
+      return {
+        remove: () => NetInfo.isConnected.removeEventListener(eventName, handler)
+      };
     },
 
     removeEventListener(

From dfacb6c8f21091cdbf5d56d46f81f7822dea173e Mon Sep 17 00:00:00 2001
From: Ahmed El-Helw <ahmedre@fb.com>
Date: Fri, 12 Feb 2016 20:16:23 -0800
Subject: [PATCH 1158/1411] Fix TextInput in React Nodes

Reviewed By: dkoroskin

Differential Revision: D2930800

fb-gh-sync-id: 072d573b29061fb61744a20a459292e271998e8d
shipit-source-id: 072d573b29061fb61744a20a459292e271998e8d
---
 .../react/views/textinput/ReactTextInputManager.java      | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
index 6cbb5894e1c2..f4b9e34dcc8c 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
@@ -34,6 +34,7 @@
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.common.MapBuilder;
 import com.facebook.react.uimanager.BaseViewManager;
+import com.facebook.react.uimanager.LayoutShadowNode;
 import com.facebook.react.uimanager.PixelUtil;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.UIManagerModule;
@@ -48,8 +49,7 @@
 /**
  * Manages instances of TextInput.
  */
-public class ReactTextInputManager extends
-    BaseViewManager<ReactEditText, ReactTextInputShadowNode> {
+public class ReactTextInputManager extends BaseViewManager<ReactEditText, LayoutShadowNode> {
 
   /* package */ static final String REACT_CLASS = "AndroidTextInput";
 
@@ -83,12 +83,12 @@ public ReactEditText createViewInstance(ThemedReactContext context) {
   }
 
   @Override
-  public ReactTextInputShadowNode createShadowNodeInstance() {
+  public LayoutShadowNode createShadowNodeInstance() {
     return new ReactTextInputShadowNode();
   }
 
   @Override
-  public Class<ReactTextInputShadowNode> getShadowNodeClass() {
+  public Class<? extends LayoutShadowNode> getShadowNodeClass() {
     return ReactTextInputShadowNode.class;
   }
 

From 75869519e6703b5afd74dfcbcb886c73098e199a Mon Sep 17 00:00:00 2001
From: Adam Miskiewicz <adam@sk3vy.com>
Date: Sat, 13 Feb 2016 15:27:22 -0800
Subject: [PATCH 1159/1411] Add npm-shrinkwrap.json to npm

Reviewed By: svcscm

Differential Revision: D2933826

fb-gh-sync-id: 48def92bfd9eb929cc092bea90bcbe1ed53f8675
shipit-source-id: 48def92bfd9eb929cc092bea90bcbe1ed53f8675
---
 package.json | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 8e606d2fc6b5..742cc4b40ab3 100644
--- a/package.json
+++ b/package.json
@@ -92,7 +92,8 @@
     "PATENTS",
     "README.md",
     "jestSupport",
-    ".flowconfig"
+    ".flowconfig",
+    "npm-shrinkwrap.json"
   ],
   "scripts": {
     "test": "NODE_ENV=test jest",

From 1463970f432cf7c1de328d8470ed772608142a8f Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@gmail.com>
Date: Sun, 14 Feb 2016 09:39:52 -0800
Subject: [PATCH 1160/1411] fixed a link to android setup docs

Reviewed By: svcscm

Differential Revision: D2936714

fb-gh-sync-id: fe97ee55cb5bf5ba736e0e5aa64462e5893a77c8
shipit-source-id: fe97ee55cb5bf5ba736e0e5aa64462e5893a77c8
---
 docs/GettingStarted.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/GettingStarted.md b/docs/GettingStarted.md
index dcee2490ad53..2762c51cf4b3 100644
--- a/docs/GettingStarted.md
+++ b/docs/GettingStarted.md
@@ -25,7 +25,7 @@ We recommend periodically running `brew update && brew upgrade` to keep your pro
 
 ## Android Setup
 
-To write React Native apps for Android, you will need to install the Android SDK (and an Android emulator if you want to work on your app without having to use a physical device). See [Android setup guide](android-setup.html) for instructions on how to set up your Android environment.
+To write React Native apps for Android, you will need to install the Android SDK (and an Android emulator if you want to work on your app without having to use a physical device). See [Android setup guide](docs/android-setup.html) for instructions on how to set up your Android environment.
 
 _NOTE:_ There is experimental [Windows and Linux support](docs/linux-windows-support.html) for Android development.
 

From 2260d900d4da1ea6809055e478688f3368c3f1f6 Mon Sep 17 00:00:00 2001
From: David Young-chan Kay <davidykay@gmail.com>
Date: Sun, 14 Feb 2016 10:35:41 -0800
Subject: [PATCH 1161/1411] Added guide for getting started on Linux.

Reviewed By: svcscm

Differential Revision: D2936728

fb-gh-sync-id: ead3daf31b624e096b12fa8db892724667e87f51
shipit-source-id: ead3daf31b624e096b12fa8db892724667e87f51
---
 docs/GettingStarted.md        |  10 ++-
 docs/GettingStartedOnLinux.md | 116 ++++++++++++++++++++++++++++++++++
 2 files changed, 125 insertions(+), 1 deletion(-)
 create mode 100644 docs/GettingStartedOnLinux.md

diff --git a/docs/GettingStarted.md b/docs/GettingStarted.md
index 2762c51cf4b3..245ecc4c5a34 100644
--- a/docs/GettingStarted.md
+++ b/docs/GettingStarted.md
@@ -4,7 +4,7 @@ title: Getting Started
 layout: docs
 category: Quick Start
 permalink: docs/getting-started.html
-next: android-setup
+next: getting-started-linux
 ---
 
 ## Requirements
@@ -31,9 +31,17 @@ _NOTE:_ There is experimental [Windows and Linux support](docs/linux-windows-sup
 
 ## Quick start
 
+Install the React Native command line tools:
+
     $ npm install -g react-native-cli
+
+__NOTE__: If you see the error, `EACCES: permission denied`, please run the command: `sudo npm install -g react-native-cli`.
+
+Create a React Native project:
+
     $ react-native init AwesomeProject
 
+
 **To run the iOS app:**
 
 - `$ cd AwesomeProject`
diff --git a/docs/GettingStartedOnLinux.md b/docs/GettingStartedOnLinux.md
new file mode 100644
index 000000000000..cbdef058f256
--- /dev/null
+++ b/docs/GettingStartedOnLinux.md
@@ -0,0 +1,116 @@
+---
+id: getting-started-linux
+title: Getting Started on Linux
+layout: docs
+category: Quick Start
+permalink: docs/getting-started-on-linux.html
+next: android-setup
+---
+
+This guide is essentially a beginner-friendly version of the [Getting Started](/react-native/docs/getting-started.html) page for React Native on Linux.
+
+### Prerequisites
+
+For the purposes of this guide, we assume that you're working on Ubuntu Linux 14.04 LTS.
+
+Before following this guide, you should have installed the Android SDK and run a successful Java-based "Hello World" app for Android.
+
+See [Android Setup](/react-native/docs/android-setup.html) for details.
+
+#### Installing NodeJS
+
+The first thing you need to do is to install NodeJS, a popular Javascript implementation.
+
+Fire up the Terminal and paste the following commands to install NodeJS from the [NodeSource](https://nodesource.com/) repository:
+
+```sh
+sudo apt-get install -y build-essential
+curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -
+sudo apt-get install -y nodejs
+sudo ln -s /usr/bin/nodejs /usr/bin/node
+```
+__NOTE__: The above instructions are for Ubuntu. If you're on a different distro,  please follow the instructions on the [NodeJS website](https://nodejs.org/en/download/).
+
+#### Installing Watchman
+
+[watchman](https://facebook.github.io/watchman/docs/install.html) is a tool by Facebook for watching changes in the filesystem. You need to install it for better performance and avoid a node file-watching bug.
+
+Paste the following into your terminal to compile watchman from source and install it:
+
+```sh
+git clone https://github.com/facebook/watchman.git
+cd watchman
+git checkout v4.1.0  # the latest stable release
+./autogen.sh
+./configure
+make
+sudo make install
+```
+
+#### Installing Flow
+
+Flow is a static type checker for JavaScript. To install it, paste the following in the terminal:
+
+```sh
+sudo npm install -g flow-bin
+```
+
+## Setting up an Android Device
+
+Let's set up an Android device to run our starter project. 
+
+First thing is to plug in your device and check the manufacturer code by using `lsusb`, which should output something like this:
+
+```bash
+$ lsusb
+Bus 002 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
+Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
+Bus 001 Device 003: ID 22b8:2e76 Motorola PCS 
+Bus 001 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
+Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
+Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
+Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
+```
+These lines represent the USB devices currently connected to your machine.
+
+You want the line that represents your phone. If you're in doubt, try unplugging your phone and running the command again:
+
+```bash
+$ lsusb
+Bus 002 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
+Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
+Bus 001 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
+Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
+Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
+Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
+```
+You'll see that after removing the phone, the line which has the phone model ("Motorola PCS" in this case) disappeared from the list. This is the line that we care about.
+
+`Bus 001 Device 003: ID 22b8:2e76 Motorola PCS`
+
+From the above line, you want to grab the first four digits from the device ID:
+
+`22b8:2e76` 
+
+In this case, it's `22b8`. That's the identifier for Motorola.
+
+You'll need to input this into your udev rules in order to get up and running:
+
+```sh
+echo SUBSYSTEM=="usb", ATTR{idVendor}=="22b8", MODE="0666", GROUP="plugdev" | sudo tee /etc/udev/rules.d/51-android-usb.rules
+```
+
+Make sure that you replace `22b8` with the identifier you get in the above command.
+
+Now check that your device is properly connecting to ADB, the Android Debug Bridge, by using `adb devices`.
+
+```bash
+List of devices attached
+TA9300GLMK	device
+```
+
+For more information, please see the docs for [running an Android app on your device](/react-native/docs/running-on-device-android.html).
+
+## Next Steps
+
+Your Android device and your tools are all ready to go. You can now follow the instructions in the [Quick Start](http://facebook.github.io/react-native/docs/getting-started.html#quick-start) guide to install React Native and start your first project.

From 3ae99d0fead8671a45ebc1d127550bcb8fb5e722 Mon Sep 17 00:00:00 2001
From: Mateusz Zatorski <mateuszzatorski@gmail.com>
Date: Sun, 14 Feb 2016 15:02:39 -0800
Subject: [PATCH 1162/1411] replace require with es6 import in docs

Reviewed By: svcscm

Differential Revision: D2936839

fb-gh-sync-id: 7a921709a37de5e9aadf324d5438d51851326348
shipit-source-id: 7a921709a37de5e9aadf324d5438d51851326348
---
 docs/Animations.md                  |  7 +++----
 docs/CommunicationIOS.md            |  9 ++++-----
 docs/EmbeddedAppAndroid.md          |  5 ++---
 docs/EmbeddedAppIOS.md              |  5 ++---
 docs/NativeComponentsAndroid.md     |  8 ++++----
 docs/NativeComponentsIOS.md         |  8 ++++----
 docs/NativeModulesAndroid.md        |  6 +++---
 docs/NativeModulesIOS.md            |  5 +++--
 docs/PlatformSpecificInformation.md | 12 ++++++------
 docs/Timers.md                      |  2 +-
 docs/Troubleshooting.md             |  6 +++---
 11 files changed, 35 insertions(+), 38 deletions(-)

diff --git a/docs/Animations.md b/docs/Animations.md
index 15dac519b865..10f39911a443 100644
--- a/docs/Animations.md
+++ b/docs/Animations.md
@@ -344,7 +344,7 @@ your project, you will need to install it with `npm i react-tween-state
 --save` from your project directory.
 
 ```javascript
-var tweenState = require('react-tween-state');
+import tweenState from 'react-tween-state';
 
 var App = React.createClass({
   mixins: [tweenState.Mixin],
@@ -402,7 +402,7 @@ the middle of a press, it will animate back from the current state to
 the original value.
 
 ```javascript
-var rebound = require('rebound');
+import rebound from 'rebound';
 
 var App = React.createClass({
   // First we initialize the spring and add a listener, which calls
@@ -532,8 +532,7 @@ make them customizable, React Native exposes a
 [NavigatorSceneConfigs](https://github.com/facebook/react-native/blob/master/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js) API.
 
 ```javascript
-var React = require('react-native');
-var { Dimensions } = React;
+import { Dimensions } from 'react-native';
 var SCREEN_WIDTH = Dimensions.get('window').width;
 var BaseConfig = Navigator.SceneConfigs.FloatFromRight;
 
diff --git a/docs/CommunicationIOS.md b/docs/CommunicationIOS.md
index dae65bc2737e..1e2d0ca073a0 100644
--- a/docs/CommunicationIOS.md
+++ b/docs/CommunicationIOS.md
@@ -39,11 +39,10 @@ RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
 ```
 'use strict';
 
-var React = require('react-native');
-  var {
+import React, {
   View,
   Image
-} = React;
+} from 'react-native';
 
 class ImageBrowserApp extends React.Component {
   renderImage: function(imgURI) {
@@ -100,8 +99,8 @@ Events are described in detail in [this article](docs/native-components-ios.html
 
 Events are powerful, because they allow us to change React Native components without needing a reference to them. However, there are some pitfalls that you can fall into while using them:
 
-* As events can be sent from anywhere, they can introduce spaghetti-style dependencies into your project. 
-* Events share namespace, which means that you may encounter some name collisions. Collisions will not be detected statically, what makes them hard to debug. 
+* As events can be sent from anywhere, they can introduce spaghetti-style dependencies into your project.
+* Events share namespace, which means that you may encounter some name collisions. Collisions will not be detected statically, what makes them hard to debug.
 * If you use several instances of the same React Native component and you want to distinguish them from the perspective of your event, you'll likely need to introduce some kind of identifiers and pass them along with events (you can use the native view's `reactTag` as an identifier).
 
 The common pattern we use when embedding native in React Native is to make the native component's RCTViewManager a delegate for the views, sending events back to JavaScript via the bridge. This keeps related event calls in one place.
diff --git a/docs/EmbeddedAppAndroid.md b/docs/EmbeddedAppAndroid.md
index eb8cc6fb4a45..7b72c7c9560e 100644
--- a/docs/EmbeddedAppAndroid.md
+++ b/docs/EmbeddedAppAndroid.md
@@ -128,11 +128,10 @@ Copy & paste the following code to `index.android.js` in your root folder — it
 ```js
 'use strict';
 
-var React = require('react-native');
-var {
+import React, {
   Text,
   View
-} = React;
+} from 'react-native';
 
 class MyAwesomeApp extends React.Component {
   render() {
diff --git a/docs/EmbeddedAppIOS.md b/docs/EmbeddedAppIOS.md
index 294d4b7fe30a..dbdb5e31d9c2 100644
--- a/docs/EmbeddedAppIOS.md
+++ b/docs/EmbeddedAppIOS.md
@@ -66,11 +66,10 @@ Copy & paste following starter code for `index.ios.js` – it’s a barebones Re
 ```
 'use strict';
 
-var React = require('react-native');
-var {
+import React, {
   Text,
   View
-} = React;
+} from 'react-native';
 
 var styles = React.StyleSheet.create({
   container: {
diff --git a/docs/NativeComponentsAndroid.md b/docs/NativeComponentsAndroid.md
index ca38d31af199..ada02d878d46 100644
--- a/docs/NativeComponentsAndroid.md
+++ b/docs/NativeComponentsAndroid.md
@@ -57,7 +57,7 @@ Views are created in the `createViewInstance` method, the view should initialize
 
 ## 3. Expose view property setters using `@ReactProp` (or `@ReactPropGroup`) annotation
 
-Properties that are to be reflected in JavaScript needs to be exposed as setter method annotated with `@ReactProp` (or `@ReactPropGroup`). Setter method should take view to be updated (of the current view type) as a first argument and property value as a second argument. Setter should be declared as a `void` method and should be `public`. Property type sent to JS is determined automatically based on the type of value argument of the setter. The following type of values are currently supported: `boolean`, `int`, `float`, `double`, `String`, `Boolean`, `Integer`, `ReadableArray`, `ReadableMap`. 
+Properties that are to be reflected in JavaScript needs to be exposed as setter method annotated with `@ReactProp` (or `@ReactPropGroup`). Setter method should take view to be updated (of the current view type) as a first argument and property value as a second argument. Setter should be declared as a `void` method and should be `public`. Property type sent to JS is determined automatically based on the type of value argument of the setter. The following type of values are currently supported: `boolean`, `int`, `float`, `double`, `String`, `Boolean`, `Integer`, `ReadableArray`, `ReadableMap`.
 
 Annotation `@ReactProp` has one obligatory argument `name` of type `String`. Name assigned to the `@ReactProp` annotation linked to the setter method is used to reference the property on JS side.
 
@@ -72,12 +72,12 @@ Setter declaration requirements for methods annotated with `@ReactPropGroup` are
   public void setSrc(ReactImageView view, @Nullable String src) {
     view.setSource(src);
   }
-  
+
   @ReactProp(name = "borderRadius", defaultFloat = 0f)
   public void setBorderRadius(ReactImageView view, float borderRadius) {
     view.setBorderRadius(borderRadius);
   }
-  
+
   @ReactProp(name = ViewProps.RESIZE_MODE)
   public void setResizeMode(ReactImageView view, @Nullable String resizeMode) {
     view.setScaleType(ImageResizeMode.toScaleType(resizeMode));
@@ -105,7 +105,7 @@ The very final step is to create the JavaScript module that defines the interfac
 ```js
 // ImageView.js
 
-var { requireNativeComponent, PropTypes } = require('react-native');
+import { requireNativeComponent, PropTypes } from 'react-native';
 
 var iface = {
   name: 'ImageView',
diff --git a/docs/NativeComponentsIOS.md b/docs/NativeComponentsIOS.md
index fffb06ecadcf..e78d86714766 100644
--- a/docs/NativeComponentsIOS.md
+++ b/docs/NativeComponentsIOS.md
@@ -49,7 +49,7 @@ Then you just need a little bit of JavaScript to make this a usable React compon
 ```javascript
 // MapView.js
 
-var { requireNativeComponent } = require('react-native');
+import { requireNativeComponent } from 'react-native';
 
 // requireNativeComponent automatically resolves this to "RCTMapManager"
 module.exports = requireNativeComponent('RCTMap', null);
@@ -79,8 +79,7 @@ This isn't very well documented though - in order to know what properties are av
 
 ```javascript
 // MapView.js
-var React = require('react-native');
-var { requireNativeComponent } = React;
+import React, { requireNativeComponent } from 'react-native';
 
 class MapView extends React.Component {
   render() {
@@ -302,7 +301,8 @@ Since all our native react views are subclasses of `UIView`, most style attribut
 ```javascript
 // DatePickerIOS.ios.js
 
-var RCTDatePickerIOSConsts = require('react-native').UIManager.RCTDatePicker.Constants;
+import { UIManager } from 'react-native';
+var RCTDatePickerIOSConsts = UIManager.RCTDatePicker.Constants;
 ...
   render: function() {
     return (
diff --git a/docs/NativeModulesAndroid.md b/docs/NativeModulesAndroid.md
index 02281b2788bc..5727c22606ad 100644
--- a/docs/NativeModulesAndroid.md
+++ b/docs/NativeModulesAndroid.md
@@ -130,14 +130,14 @@ To make it simpler to access your new functionality from JavaScript, it is commo
  * 2. int duration: The duration of the toast. May be ToastAndroid.SHORT or
  *    ToastAndroid.LONG
  */
-var { NativeModules } = require('react-native');
+import { NativeModules } from 'react-native';
 module.exports = NativeModules.ToastAndroid;
 ```
 
 Now, from your other JavaScript file you can call the method like this:
 
 ```js
-var ToastAndroid = require('./ToastAndroid');
+import ToastAndroid from './ToastAndroid';
 
 ToastAndroid.show('Awesome', ToastAndroid.SHORT);
 ```
@@ -275,7 +275,7 @@ sendEvent(reactContext, "keyboardWillShow", params);
 JavaScript modules can then register to receive events by `addListenerOn` using the `Subscribable` mixin
 
 ```js
-var { DeviceEventEmitter } = require('react-native');
+import { DeviceEventEmitter } from 'react-native';
 ...
 
 var ScrollResponderMixin = {
diff --git a/docs/NativeModulesIOS.md b/docs/NativeModulesIOS.md
index ca40d20cccd2..0f30191cda94 100644
--- a/docs/NativeModulesIOS.md
+++ b/docs/NativeModulesIOS.md
@@ -50,7 +50,8 @@ RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location)
 Now, from your JavaScript file you can call the method like this:
 
 ```javascript
-var CalendarManager = require('react-native').NativeModules.CalendarManager;
+import { NativeModules } from 'react-native';
+var CalendarManager = NativeModules.CalendarManager;
 CalendarManager.addEvent('Birthday Party', '4 Privet Drive, Surrey');
 ```
 
@@ -334,7 +335,7 @@ The native module can signal events to JavaScript without being invoked directly
 JavaScript code can subscribe to these events:
 
 ```javascript
-var { NativeAppEventEmitter } = require('react-native');
+import { NativeAppEventEmitter } from 'react-native';
 
 var subscription = NativeAppEventEmitter.addListener(
   'EventReminder',
diff --git a/docs/PlatformSpecificInformation.md b/docs/PlatformSpecificInformation.md
index 38345e541ca8..9c2f2e02f343 100644
--- a/docs/PlatformSpecificInformation.md
+++ b/docs/PlatformSpecificInformation.md
@@ -7,11 +7,11 @@ permalink: docs/platform-specific-code.html
 next: native-modules-ios
 ---
 
-When building a cross-platform app, the need to write different code for different platforms may arise. This can always be achieved by organizing the various components in different folders: 
+When building a cross-platform app, the need to write different code for different platforms may arise. This can always be achieved by organizing the various components in different folders:
 
 ```sh
-/common/components/   
-/android/components/   
+/common/components/
+/android/components/
 /ios/components/
 ```
 
@@ -25,7 +25,7 @@ BigButtonAndroid.js
 But React Native provides two alternatives to easily organize your code separating it by platform:
 
 ## Platform specific extensions
-React Native will detect when a file has a `.ios.` or `.android.` extension and load the right file for each platform when requiring them from other components. 
+React Native will detect when a file has a `.ios.` or `.android.` extension and load the right file for each platform when requiring them from other components.
 
 For example, you can have these files in your project:
 
@@ -37,7 +37,7 @@ BigButton.android.js
 With this setup, you can just require the files from a different component without paying attention to the platform in which the app will run.
 
 ```javascript
-var BigButton = require('./components/BigButton');
+import BigButton from './components/BigButton';
 ```
 
 React Native will import the correct component for the running platform.
@@ -46,7 +46,7 @@ React Native will import the correct component for the running platform.
 A module is provided by React Native to detect what is the platform in which the app is running. This piece of functionality can be useful when only small parts of a component are platform specific.
 
 ```javascript
-var {Platform} = React;
+var { Platform } = React;
 
 var styles = StyleSheet.create({
   height: (Platform.OS === 'ios') ? 200 : 100,
diff --git a/docs/Timers.md b/docs/Timers.md
index d4a9396decee..b90180d429e7 100644
--- a/docs/Timers.md
+++ b/docs/Timers.md
@@ -61,7 +61,7 @@ We found out that the primary cause of fatals in apps created with React Native
 This library does not ship with React Native - in order to use it on your project, you will need to install it with `npm i react-timer-mixin --save` from your project directory.
 
 ```javascript
-var TimerMixin = require('react-timer-mixin');
+import TimerMixin from 'react-timer-mixin';
 
 var Component = React.createClass({
   mixins: [TimerMixin],
diff --git a/docs/Troubleshooting.md b/docs/Troubleshooting.md
index b0063ae19cf2..875cfa2c8530 100644
--- a/docs/Troubleshooting.md
+++ b/docs/Troubleshooting.md
@@ -96,12 +96,12 @@ You need to run `adb reverse tcp:8081 tcp:8081` to forward requests from the dev
 
 ## Module that uses `WebSocket` (such as Firebase) throws an exception
 
-React Native implements a polyfill for WebSockets. These polyfills are initialized as part of the react-native module that you include in your application through `require('react-native')`. If you load another module that requires WebSockets, be sure to load/require it after react-native.
+React Native implements a polyfill for WebSockets. These polyfills are initialized as part of the react-native module that you include in your application through `import React from 'react-native'`. If you load another module that requires WebSockets, be sure to load/require it after react-native.
 
 So:
 ```
-var React = require('react-native');
-var Firebase = require('firebase');
+import React from 'react-native';
+import Firebase from 'firebase';
 ```
 
 Requiring firebase *before* react-native will result in a 'No transports available' redbox.

From d7e5392139347c756e338b3bd104dc1a44b15e11 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Mon, 15 Feb 2016 06:32:19 -0800
Subject: [PATCH 1163/1411] Remove test for missing feature

Reviewed By: cpojer

Differential Revision: D2937175

fb-gh-sync-id: 7c348018918a509e1cd681dfa8df9151b94ce765
shipit-source-id: 7c348018918a509e1cd681dfa8df9151b94ce765
---
 .../__tests__/DependencyGraph-test.js         | 66 -------------------
 1 file changed, 66 deletions(-)

diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
index c5b0b754f7b8..fa823286ab95 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
@@ -3718,72 +3718,6 @@ describe('DependencyGraph', function() {
       });
     });
 
-    //TODO(davidaurelio) Make this actually worked. The test only passed because
-    // the mocked cache didn't cache. In reality, it didn't work. I tried it.
-    xpit('updates package.json', function() {
-      var root = '/root';
-      var filesystem = fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("aPackage")',
-          ].join('\n'),
-          'aPackage': {
-            'package.json': JSON.stringify({
-              name: 'aPackage',
-              main: 'main.js',
-            }),
-            'main.js': 'main',
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function() {
-        filesystem.root['index.js'] = filesystem.root['index.js'].replace(/aPackage/, 'bPackage');
-        triggerFileChange('change', 'index.js', root, mockStat);
-
-        filesystem.root.aPackage['package.json'] = JSON.stringify({
-          name: 'bPackage',
-          main: 'main.js',
-        });
-        triggerFileChange('change', 'package.json', '/root/aPackage', mockStat);
-
-        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-          expect(deps)
-            .toEqual([
-              {
-                id: 'index',
-                path: '/root/index.js',
-                dependencies: ['bPackage'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-              {
-                id: 'bPackage/main.js',
-                path: '/root/aPackage/main.js',
-                dependencies: [],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-            ]);
-        });
-      });
-    });
-
     pit('changes to browser field', function() {
       var root = '/root';
       var filesystem = fs.__setMockFilesystem({

From 6c55d5b8514822930c28cb045a0cee777a72acc5 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Mon, 15 Feb 2016 06:57:26 -0800
Subject: [PATCH 1164/1411] Replace custom rolled stable string hashing with
 library

Reviewed By: cpojer

Differential Revision: D2937202

fb-gh-sync-id: dc08547c71da2bc35cfad108e63fd5e87f0ba734
shipit-source-id: dc08547c71da2bc35cfad108e63fd5e87f0ba734
---
 npm-shrinkwrap.json                           | 60 +++++++++++--------
 package.json                                  |  1 +
 .../src/DependencyResolver/Module.js          | 21 ++-----
 .../__tests__/Module-test.js                  |  1 +
 4 files changed, 41 insertions(+), 42 deletions(-)

diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index dc7c0be87142..7ad46f5e98e4 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -127,16 +127,16 @@
           "from": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz",
           "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz"
         },
-        "babylon": {
-          "version": "5.8.29",
-          "from": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz",
-          "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz"
-        },
         "globals": {
           "version": "6.4.1",
           "from": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz",
           "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
         },
+        "babylon": {
+          "version": "5.8.29",
+          "from": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz",
+          "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz"
+        },
         "js-tokens": {
           "version": "1.0.1",
           "from": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz",
@@ -1955,16 +1955,16 @@
           "from": "brace-expansion@>=1.0.0 <2.0.0",
           "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz"
         },
-        "chalk": {
-          "version": "1.1.1",
-          "from": "chalk@^1.1.1",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz"
-        },
         "caseless": {
           "version": "0.11.0",
           "from": "caseless@~0.11.0",
           "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
         },
+        "chalk": {
+          "version": "1.1.1",
+          "from": "chalk@^1.1.1",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz"
+        },
         "combined-stream": {
           "version": "1.0.5",
           "from": "combined-stream@~1.0.5",
@@ -2065,16 +2065,16 @@
           "from": "graceful-readlink@>= 1.0.0",
           "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
         },
-        "has-ansi": {
-          "version": "2.0.0",
-          "from": "has-ansi@^2.0.0",
-          "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
-        },
         "har-validator": {
           "version": "2.0.2",
           "from": "har-validator@~2.0.2",
           "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.2.tgz"
         },
+        "has-ansi": {
+          "version": "2.0.0",
+          "from": "has-ansi@^2.0.0",
+          "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
+        },
         "has-unicode": {
           "version": "1.0.1",
           "from": "has-unicode@^1.0.0",
@@ -2235,16 +2235,16 @@
           "from": "request@2.x",
           "resolved": "https://registry.npmjs.org/request/-/request-2.65.0.tgz"
         },
-        "sntp": {
-          "version": "1.0.9",
-          "from": "sntp@1.x.x",
-          "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
-        },
         "semver": {
           "version": "5.0.3",
           "from": "semver@~5.0.1",
           "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
         },
+        "sntp": {
+          "version": "1.0.9",
+          "from": "sntp@1.x.x",
+          "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
+        },
         "string_decoder": {
           "version": "0.10.31",
           "from": "string_decoder@~0.10.x",
@@ -2260,16 +2260,16 @@
           "from": "strip-ansi@^3.0.0",
           "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz"
         },
-        "supports-color": {
-          "version": "2.0.0",
-          "from": "supports-color@^2.0.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
-        },
         "strip-json-comments": {
           "version": "0.1.3",
           "from": "strip-json-comments@0.1.x",
           "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
         },
+        "supports-color": {
+          "version": "2.0.0",
+          "from": "supports-color@^2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
+        },
         "tar": {
           "version": "2.2.1",
           "from": "tar@~2.2.0",
@@ -3338,11 +3338,21 @@
       "from": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
       "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz"
     },
+    "json-stable-stringify": {
+      "version": "1.0.1",
+      "from": "json-stable-stringify@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz"
+    },
     "json5": {
       "version": "0.4.0",
       "from": "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz",
       "resolved": "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz"
     },
+    "jsonify": {
+      "version": "0.0.0",
+      "from": "jsonify@>=0.0.0 <0.1.0",
+      "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz"
+    },
     "jstransform": {
       "version": "11.0.3",
       "from": "https://registry.npmjs.org/jstransform/-/jstransform-11.0.3.tgz",
diff --git a/package.json b/package.json
index 742cc4b40ab3..ea74c16ff9b9 100644
--- a/package.json
+++ b/package.json
@@ -128,6 +128,7 @@
     "image-size": "^0.3.5",
     "immutable": "^3.7.5",
     "joi": "^6.6.1",
+    "json-stable-stringify": "^1.0.1",
     "json5": "^0.4.0",
     "jstransform": "^11.0.3",
     "mkdirp": "^0.5.1",
diff --git a/packager/react-packager/src/DependencyResolver/Module.js b/packager/react-packager/src/DependencyResolver/Module.js
index c75473acceba..6b68a620e4dc 100644
--- a/packager/react-packager/src/DependencyResolver/Module.js
+++ b/packager/react-packager/src/DependencyResolver/Module.js
@@ -11,6 +11,7 @@
 const crypto = require('crypto');
 const docblock = require('./DependencyGraph/docblock');
 const isAbsolutePath = require('absolute-path');
+const jsonStableStringify = require('json-stable-stringify');
 const path = require('path');
 const extractRequires = require('./lib/extractRequires');
 
@@ -206,29 +207,15 @@ function whileInDocBlock(chunk, i, result) {
 const knownHashes = new WeakMap();
 function stableObjectHash(object) {
   let digest = knownHashes.get(object);
-
   if (!digest) {
-    const hash = crypto.createHash('md5');
-    stableObjectHash.addTo(object, hash);
-    digest = hash.digest('base64');
+    digest = crypto.createHash('md5')
+      .update(jsonStableStringify(object))
+      .digest('base64');
     knownHashes.set(object, digest);
   }
 
   return digest;
 }
-stableObjectHash.addTo = function addTo(value, hash) {
-  if (value === null || typeof value !== 'object') {
-    hash.update(JSON.stringify(value));
-  } else {
-    Object.keys(value).sort().forEach(key => {
-      const valueForKey = value[key];
-      if (valueForKey !== undefined) {
-        hash.update(key);
-        addTo(valueForKey, hash);
-      }
-    });
-  }
-};
 
 function cacheKey(field, transformOptions) {
   return transformOptions !== undefined
diff --git a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js b/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
index 71c3a43dca55..bb4fa75eaf15 100644
--- a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
+++ b/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
@@ -10,6 +10,7 @@
 
 jest
   .dontMock('absolute-path')
+  .dontMock('json-stable-stringify')
   .dontMock('../fastfs')
   .dontMock('../lib/extractRequires')
   .dontMock('../lib/replacePatterns')

From 51a8b54015b2821a3f7942b3ea5f3e6535d0f4b7 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Mon, 15 Feb 2016 08:37:29 -0800
Subject: [PATCH 1165/1411] Cleaned up versions.html naming

Reviewed By: svcscm

Differential Revision: D2937512

fb-gh-sync-id: 172943b1df26591f6ba56e04a7ccad76ed5bf5e5
shipit-source-id: 172943b1df26591f6ba56e04a7ccad76ed5bf5e5
---
 website/publish-gh-pages.js          | 22 +++++++++++++++-------
 website/src/react-native/versions.js | 22 +++++++++++++++-------
 2 files changed, 30 insertions(+), 14 deletions(-)

diff --git a/website/publish-gh-pages.js b/website/publish-gh-pages.js
index 2e2530622022..2368f10cfc8a 100644
--- a/website/publish-gh-pages.js
+++ b/website/publish-gh-pages.js
@@ -13,7 +13,6 @@ require(`shelljs/global`);
 
 const CIRCLE_BRANCH = process.env.CIRCLE_BRANCH;
 const CIRCLE_PROJECT_USERNAME = process.env.CIRCLE_PROJECT_USERNAME;
-const CI_PULL_REQUESTS = process.env.CI_PULL_REQUESTS;
 const CI_PULL_REQUEST = process.env.CI_PULL_REQUEST;
 const GIT_USER = process.env.GIT_USER;
 const remoteBranch = `https://${GIT_USER}@github.com/facebook/react-native.git`;
@@ -33,8 +32,14 @@ if (CIRCLE_BRANCH.indexOf(`-stable`) !== -1) {
 rm(`-rf`, `build`);
 mkdir(`-p`, `build`);
 // if current commit is tagged "latest" we do a release to gh-pages root
-let currentCommit = exec(`git rev-parse HEAD`).stdout.trim();
-let latestTagCommit = exec(`git ls-remote origin latest`).stdout.split(/\s/)[0];
+const currentCommit = exec(`git rev-parse HEAD`).stdout.trim();
+const latestTagCommit = exec(`git ls-remote origin latest`).stdout.split(/\s/)[0];
+// pass along which branch contains latest version so that gh-pages root could mark it as latest
+const branchWithLatestTag = exec(`git branch --contains latest`).stdout;
+let latestVersion = ``;
+if (branchWithLatestTag.indexOf(`-stable`) !== -1) {
+  latestVersion = branchWithLatestTag.slice(0, branchWithLatestTag.indexOf(`-stable`)).trim();
+}
 
 if (!CI_PULL_REQUEST && CIRCLE_PROJECT_USERNAME === `facebook`) {
   echo(`Building branch ${version}, preparing to push to gh-pages`);
@@ -57,12 +62,13 @@ if (!CI_PULL_REQUEST && CIRCLE_PROJECT_USERNAME === `facebook`) {
     exit(1);
   }
   cd(`releases`);
-  var releasesFolders = ls(`-d`, `*`)
+  let releasesFolders = ls(`-d`, `*`);
   cd(`..`);
-  var versions = releasesFolders.filter(name => name !== `next`);
+  let versions = releasesFolders.filter(name => name !== `next`);
   if (version !== `next` && versions.indexOf(version) === -1) {
     versions.push(version);
   }
+
   versions.sort(semverCmp).reverse();
 
   // generate to releases/XX when branch name indicates that it is some sort of release
@@ -71,7 +77,7 @@ if (!CI_PULL_REQUEST && CIRCLE_PROJECT_USERNAME === `facebook`) {
     rm(`-rf`, `releases/${version}`);
     mkdir(`-p`, `releases/${version}`);
     cd(`../..`);
-    if (exec(`RN_DEPLOYMENT_PATH=releases/${version} RN_VERSION=${version} \
+    if (exec(`RN_DEPLOYMENT_PATH=releases/${version} RN_VERSION=${version} RN_LATEST_VERSION=${latestVersion} \
     RN_AVAILABLE_DOCS_VERSIONS=${versions.join(',')} node server/generate.js`).code !== 0) {
       echo(`Error: Generating HTML failed`);
       exit(1);
@@ -81,12 +87,14 @@ if (!CI_PULL_REQUEST && CIRCLE_PROJECT_USERNAME === `facebook`) {
     // versions.html is located in root of website and updated with every release
     exec(`cp ../react-native/versions.html .`);
   }
+  // generate to root folder when commit is tagged as latest, i.e. stable and needs to be shown at the root of repo
   if (currentCommit === latestTagCommit) {
     echo(`------------ DEPLOYING latest`);
     // leave only releases folder
     rm(`-rf`, ls(`*`).filter(name => name !== 'releases'));
     cd(`../..`);
-    if (exec(`RN_VERSION=${version} RN_AVAILABLE_DOCS_VERSIONS=${versions} node server/generate.js`).code !== 0) {
+    if (exec(`RN_VERSION=${version} RN_LATEST_VERSION=${latestVersion} \
+    RN_AVAILABLE_DOCS_VERSIONS=${versions} node server/generate.js`).code !== 0) {
       echo(`Error: Generating HTML failed`);
       exit(1);
     }
diff --git a/website/src/react-native/versions.js b/website/src/react-native/versions.js
index 336903867129..416dbc1eeab4 100644
--- a/website/src/react-native/versions.js
+++ b/website/src/react-native/versions.js
@@ -15,21 +15,29 @@ var versions = React.createClass({
   render: function() {
 
     var availableDocs = (Metadata.config.RN_AVAILABLE_DOCS_VERSIONS || '').split(',');
+
     var versions = [
       {
-        title: 'next',
+        title: 'master',
         path: '/react-native/releases/next',
       },
-      {
-        title: 'stable',
-        path: '/react-native',
-      },
     ].concat(availableDocs.map((version) => {
+      const isLatest =  Metadata.config.RN_LATEST_VERSION === version;
       return {
-        title: version,
-        path: '/react-native/releases/' + version
+        title: isLatest ? `${version} + (current)` : version,
+        path: isLatest ? '/react-native' : '/react-native/releases/' + version
       }
     }));
+
+    if (!Metadata.config.RN_LATEST_VERSION) {
+      versions = [
+        {
+          title: 'current',
+          path: '/react-native',
+        },
+      ].concat(versions);
+    }
+
     var versionsLi = versions.map((version) =>
       <li><a href={version.path}>{version.title}</a></li>
     );

From 46a8f1d8e0f2f779bc09395f02be1d0b71587482 Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Mon, 15 Feb 2016 10:04:45 -0800
Subject: [PATCH 1166/1411] Annotate Clipboard module

Reviewed By: svcscm

Differential Revision: D2866837

fb-gh-sync-id: 0f7da139e1296aec6a518d52056a6d0a1b9c07ca
shipit-source-id: 0f7da139e1296aec6a518d52056a6d0a1b9c07ca
---
 Libraries/Components/Clipboard/Clipboard.js | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/Libraries/Components/Clipboard/Clipboard.js b/Libraries/Components/Clipboard/Clipboard.js
index b09bc5b2f7b9..1a1e157238a8 100644
--- a/Libraries/Components/Clipboard/Clipboard.js
+++ b/Libraries/Components/Clipboard/Clipboard.js
@@ -7,10 +7,12 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule Clipboard
+ * @flow
  */
 'use strict';
 
-var Clipboard = require('NativeModules').Clipboard;
+const Clipboard = require('NativeModules').Clipboard;
+const deprecatedCallback = require('deprecatedCallback');
 
 /**
  * `Clipboard` gives you an interface for setting and getting content from Clipboard on both iOS and Android
@@ -24,14 +26,13 @@ module.exports = {
    * }
    * ```
    */
-  getString() {
-    if (arguments.length > 0) {
-      let callback = arguments[0];
-      console.warn('Clipboard.getString(callback) is deprecated. Use the returned Promise instead');
-      Clipboard.getString().then(callback);
-      return;
-    }
-    return Clipboard.getString();
+  getString(): Promise<string> {
+    return deprecatedCallback(
+      Clipboard.getString(),
+      Array.prototype.slice.call(arguments),
+      'success-first',
+      'Clipboard.getString(callback) is deprecated. Use the returned Promise instead'
+    );
   },
   /**
    * Set content of string type. You can use following code to set clipboard content
@@ -42,7 +43,7 @@ module.exports = {
    * ```
    * @param the content to be stored in the clipboard.
    */
-  setString(content) {
+  setString(content: string) {
     Clipboard.setString(content);
   }
 };

From e5ba46c30d5db1e660911ea2aee0daead89cf181 Mon Sep 17 00:00:00 2001
From: Scott Kyle <scott@appden.com>
Date: Mon, 15 Feb 2016 12:57:21 -0800
Subject: [PATCH 1167/1411] Expose way for native modules to modify JSC context

Reviewed By: svcscm

Differential Revision: D2933197

fb-gh-sync-id: 32eb943ab341804343bbcadd29f0377fccf75de6
shipit-source-id: 32eb943ab341804343bbcadd29f0377fccf75de6
---
 React/Executors/RCTJSCExecutor.h                    |  9 +++++++++
 React/Executors/RCTJSCExecutor.m                    | 13 ++++++++++++-
 .../com/facebook/react/bridge/BaseJavaModule.java   |  5 +++++
 .../facebook/react/bridge/CatalystInstanceImpl.java |  1 +
 .../com/facebook/react/bridge/NativeModule.java     |  9 +++++++++
 .../facebook/react/bridge/NativeModuleRegistry.java | 13 +++++++++++++
 .../java/com/facebook/react/bridge/ReactBridge.java |  9 +++++++++
 ReactAndroid/src/main/jni/react/Bridge.cpp          |  4 ++++
 ReactAndroid/src/main/jni/react/Bridge.h            |  1 +
 ReactAndroid/src/main/jni/react/Executor.h          |  3 +++
 ReactAndroid/src/main/jni/react/JSCExecutor.cpp     |  4 ++++
 ReactAndroid/src/main/jni/react/JSCExecutor.h       |  1 +
 ReactAndroid/src/main/jni/react/jni/OnLoad.cpp      |  7 ++++++-
 13 files changed, 77 insertions(+), 2 deletions(-)

diff --git a/React/Executors/RCTJSCExecutor.h b/React/Executors/RCTJSCExecutor.h
index b34218f2b472..f8beaa67373f 100644
--- a/React/Executors/RCTJSCExecutor.h
+++ b/React/Executors/RCTJSCExecutor.h
@@ -16,6 +16,15 @@
  */
 RCT_EXTERN NSString *const RCTJSCThreadName;
 
+/**
+ * This notification fires on the JS thread immediately after a `JSContext`
+ * is fully initialized, but before the JS bundle has been loaded. The object
+ * of this notification is the `JSContext`. Native modules should listen for
+ * notification only if they need to install custom functionality into the
+ * context. Note that this notification won't fire when debugging in Chrome.
+ */
+RCT_EXTERN NSString *const RCTJavaScriptContextCreatedNotification;
+
 /**
  * Uses a JavaScriptCore context as the execution engine.
  */
diff --git a/React/Executors/RCTJSCExecutor.m b/React/Executors/RCTJSCExecutor.m
index db08f806e97b..91c915a90cb4 100644
--- a/React/Executors/RCTJSCExecutor.m
+++ b/React/Executors/RCTJSCExecutor.m
@@ -28,6 +28,8 @@
 
 NSString *const RCTJSCThreadName = @"com.facebook.React.JavaScript";
 
+NSString *const RCTJavaScriptContextCreatedNotification = @"RCTJavaScriptContextCreatedNotification";
+
 static NSString *const RCTJSCProfilerEnabledDefaultsKey = @"RCTJSCProfilerEnabled";
 
 @interface RCTJavaScriptContext : NSObject <RCTInvalidating>
@@ -332,7 +334,16 @@ - (void)setUp
   }];
 
   [self executeBlockOnJavaScriptQueue:^{
-    RCTInstallJSCProfiler(_bridge, self.context.ctx);
+    RCTJSCExecutor *strongSelf = weakSelf;
+    if (!strongSelf.valid) {
+      return;
+    }
+
+    JSContext *context = strongSelf.context.context;
+    RCTInstallJSCProfiler(_bridge, context.JSGlobalContextRef);
+
+    [[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptContextCreatedNotification
+                                                        object:context];
   }];
 
   for (NSString *event in @[RCTProfileDidStartProfiling, RCTProfileDidEndProfiling]) {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java
index 1a84c05fa410..6d05c003ac7b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java
@@ -332,6 +332,11 @@ public boolean canOverrideExistingModule() {
     return false;
   }
 
+  @Override
+  public void onReactBridgeInitialized(ReactBridge bridge) {
+    // do nothing
+  }
+
   @Override
   public void onCatalystInstanceDestroy() {
     // do nothing
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
index d3bcc1abd09a..cc34bf6ffaa8 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
@@ -127,6 +127,7 @@ private ReactBridge initializeBridge(
       Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
     }
 
+    mJavaRegistry.notifyReactBridgeInitialized(bridge);
     return bridge;
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java
index 905b5be93521..5dae9ac3e499 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java
@@ -59,6 +59,15 @@ interface NativeMethod {
    */
   boolean canOverrideExistingModule();
 
+  /**
+   * Called on the JS thread after a ReactBridge has been created. This is useful for native modules
+   * that need to do any setup before the JS bundle has been loaded. An example of this would be
+   * installing custom functionality into the JavaScriptCore context.
+   *
+   * @param bridge the ReactBridge instance that has just been created
+   */
+  void onReactBridgeInitialized(ReactBridge bridge);
+
   /**
    * Called before {CatalystInstance#onHostDestroy}
    */
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java
index 389fd66b4616..131def5fb063 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java
@@ -114,6 +114,19 @@ private NativeModuleRegistry(
     }
   }
 
+  /* package */ void notifyReactBridgeInitialized(ReactBridge bridge) {
+    Systrace.beginSection(
+        Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
+        "NativeModuleRegistry_notifyReactBridgeInitialized");
+    try {
+      for (NativeModule nativeModule : mModuleInstances.values()) {
+        nativeModule.onReactBridgeInitialized(bridge);
+      }
+    } finally {
+      Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+    }
+  }
+
   public void onBatchComplete() {
     for (int i = 0; i < mBatchCompleteListenerModules.size(); i++) {
       mBatchCompleteListenerModules.get(i).onBatchComplete();
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java
index b809e680b6a8..c088de3a6bc8 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java
@@ -87,4 +87,13 @@ private native void initialize(
   public native void stopProfiler(String title, String filename);
   private native void handleMemoryPressureModerate();
   private native void handleMemoryPressureCritical();
+
+  /**
+   * This method will return a long representing the underlying JSGlobalContextRef pointer or
+   * 0 (representing NULL) when in Chrome debug mode, and is only useful if passed back through
+   * the JNI to native code that will use it with the JavaScriptCore C API.
+   * **WARNING:** This method is *experimental* and should only be used when no other option is
+   * available. It will likely change in a future release!
+   */
+  public native long getJavaScriptContextNativePtrExperimental();
 }
diff --git a/ReactAndroid/src/main/jni/react/Bridge.cpp b/ReactAndroid/src/main/jni/react/Bridge.cpp
index a8ee4c2f52bd..fe835fa51fba 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.cpp
+++ b/ReactAndroid/src/main/jni/react/Bridge.cpp
@@ -57,6 +57,10 @@ void Bridge::setGlobalVariable(const std::string& propName, const std::string& j
   m_mainExecutor->setGlobalVariable(propName, jsonValue);
 }
 
+void* Bridge::getJavaScriptContext() {
+  return m_mainExecutor->getJavaScriptContext();
+}
+
 bool Bridge::supportsProfiling() {
   return m_mainExecutor->supportsProfiling();
 }
diff --git a/ReactAndroid/src/main/jni/react/Bridge.h b/ReactAndroid/src/main/jni/react/Bridge.h
index d9c108a30d8b..1833ccba4e0c 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.h
+++ b/ReactAndroid/src/main/jni/react/Bridge.h
@@ -54,6 +54,7 @@ class Bridge {
     const std::string& startupCode,
     const std::string& sourceURL);
   void setGlobalVariable(const std::string& propName, const std::string& jsonValue);
+  void* getJavaScriptContext();
   bool supportsProfiling();
   void startProfiler(const std::string& title);
   void stopProfiler(const std::string& title, const std::string& filename);
diff --git a/ReactAndroid/src/main/jni/react/Executor.h b/ReactAndroid/src/main/jni/react/Executor.h
index 8da103630a1c..036b6414ea69 100644
--- a/ReactAndroid/src/main/jni/react/Executor.h
+++ b/ReactAndroid/src/main/jni/react/Executor.h
@@ -60,6 +60,9 @@ class JSExecutor {
   virtual void setGlobalVariable(
     const std::string& propName,
     const std::string& jsonValue) = 0;
+  virtual void* getJavaScriptContext() {
+    return nullptr;
+  };
   virtual bool supportsProfiling() {
     return false;
   };
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index 2398988ba593..ceb2564d5a6b 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -198,6 +198,10 @@ void JSCExecutor::setGlobalVariable(const std::string& propName, const std::stri
   JSObjectSetProperty(m_context, globalObject, jsPropertyName, valueToInject, 0, NULL);
 }
 
+void* JSCExecutor::getJavaScriptContext() {
+  return m_context;
+}
+
 bool JSCExecutor::supportsProfiling() {
   #ifdef WITH_FBSYSTRACE
   return true;
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.h b/ReactAndroid/src/main/jni/react/JSCExecutor.h
index 41558bd4a800..dbba889abfd7 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.h
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.h
@@ -48,6 +48,7 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
   virtual void setGlobalVariable(
     const std::string& propName,
     const std::string& jsonValue) override;
+  virtual void* getJavaScriptContext() override;
   virtual bool supportsProfiling() override;
   virtual void startProfiler(const std::string &titleString) override;
   virtual void stopProfiler(const std::string &titleString, const std::string &filename) override;
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 6fe35d73c1a7..1e4c37950352 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -760,6 +760,11 @@ static void setGlobalVariable(JNIEnv* env, jobject obj, jstring propName, jstrin
   bridge->setGlobalVariable(fromJString(env, propName), fromJString(env, jsonValue));
 }
 
+static jlong getJavaScriptContext(JNIEnv *env, jobject obj) {
+  auto bridge = extractRefPtr<CountableBridge>(env, obj);
+  return (uintptr_t) bridge->getJavaScriptContext();
+}
+
 static jboolean supportsProfiling(JNIEnv* env, jobject obj) {
   auto bridge = extractRefPtr<CountableBridge>(env, obj);
   return bridge->supportsProfiling() ? JNI_TRUE : JNI_FALSE;
@@ -944,7 +949,7 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
         makeNativeMethod("stopProfiler", bridge::stopProfiler),
         makeNativeMethod("handleMemoryPressureModerate", bridge::handleMemoryPressureModerate),
         makeNativeMethod("handleMemoryPressureCritical", bridge::handleMemoryPressureCritical),
-
+        makeNativeMethod("getJavaScriptContextNativePtrExperimental", bridge::getJavaScriptContext),
     });
 
     jclass nativeRunnableClass = env->FindClass("com/facebook/react/bridge/queue/NativeRunnableDeprecated");

From ecb1643feebf5409c0b7a8f2eb054e607ecd5254 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Mon, 15 Feb 2016 13:07:36 -0800
Subject: [PATCH 1168/1411] Yet another fix for CI to find branch that contaisn
 tag latest

Reviewed By: svcscm

Differential Revision: D2937802

fb-gh-sync-id: 3bd617d5fc7fea42d264acfbd229fd15b335a95d
shipit-source-id: 3bd617d5fc7fea42d264acfbd229fd15b335a95d
---
 circle.yml                           | 6 ++----
 website/publish-gh-pages.js          | 4 ++--
 website/src/react-native/versions.js | 2 +-
 3 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/circle.yml b/circle.yml
index 589a7c9a9d91..7500233d0cef 100644
--- a/circle.yml
+++ b/circle.yml
@@ -4,7 +4,7 @@ general:
       - gh-pages # list of branches to ignore
 machine:
   node:
-    version: 5.1.0
+    version: 5.6.0
   environment:
     PATH: "~/$CIRCLE_PROJECT_REPONAME/gradle-2.9/bin:$PATH"
     TERM: "dumb"
@@ -22,11 +22,8 @@ dependencies:
     - buck/bin/buck fetch ReactAndroid/src/main/java/com/facebook/react/shell
     - buck/bin/buck fetch ReactAndroid/src/test/...
     - buck/bin/buck fetch ReactAndroid/src/androidTest/...
-    # using npm@3 because of problems with shrink-wrapped optional deps installs on linux
-    - npm install -g npm@3.2
     - source scripts/circle-ci-android-setup.sh && getAndroidSDK
     - ./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog
-    - cd website && npm install
   cache_directories:
     - "ReactAndroid/build/downloads"
     - "buck"
@@ -34,6 +31,7 @@ dependencies:
     - "website/node_modules"
   override:
     - npm install
+    - cd website && npm install
 
 test:
   pre:
diff --git a/website/publish-gh-pages.js b/website/publish-gh-pages.js
index 2368f10cfc8a..25e43d6ea4df 100644
--- a/website/publish-gh-pages.js
+++ b/website/publish-gh-pages.js
@@ -35,10 +35,10 @@ mkdir(`-p`, `build`);
 const currentCommit = exec(`git rev-parse HEAD`).stdout.trim();
 const latestTagCommit = exec(`git ls-remote origin latest`).stdout.split(/\s/)[0];
 // pass along which branch contains latest version so that gh-pages root could mark it as latest
-const branchWithLatestTag = exec(`git branch --contains latest`).stdout;
+const branchWithLatestTag = exec(`git branch -r --contains ${latestTagCommit}`).stdout.split('/')[1];
 let latestVersion = ``;
 if (branchWithLatestTag.indexOf(`-stable`) !== -1) {
-  latestVersion = branchWithLatestTag.slice(0, branchWithLatestTag.indexOf(`-stable`)).trim();
+  latestVersion = branchWithLatestTag.slice(0, branchWithLatestTag.indexOf(`-stable`));
 }
 
 if (!CI_PULL_REQUEST && CIRCLE_PROJECT_USERNAME === `facebook`) {
diff --git a/website/src/react-native/versions.js b/website/src/react-native/versions.js
index 416dbc1eeab4..fecf68d5e175 100644
--- a/website/src/react-native/versions.js
+++ b/website/src/react-native/versions.js
@@ -24,7 +24,7 @@ var versions = React.createClass({
     ].concat(availableDocs.map((version) => {
       const isLatest =  Metadata.config.RN_LATEST_VERSION === version;
       return {
-        title: isLatest ? `${version} + (current)` : version,
+        title: isLatest ? `${version} (current)` : version,
         path: isLatest ? '/react-native' : '/react-native/releases/' + version
       }
     }));

From 14ec6f011e2afd32489345a6efec02623d9a31fd Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Mon, 15 Feb 2016 13:33:28 -0800
Subject: [PATCH 1169/1411] Use promises in 'NetInfo'

Reviewed By: svcscm

Differential Revision: D2938010

fb-gh-sync-id: 4a24ce680b37e49759f3325987b4b440eb033b94
shipit-source-id: 4a24ce680b37e49759f3325987b4b440eb033b94
---
 Examples/UIExplorer/NetInfoExample.js         |  4 +--
 Libraries/Network/NetInfo.js                  | 34 ++++++++-----------
 Libraries/Network/RCTNetInfo.m                |  6 ++--
 Libraries/Utilities/deprecatedCallback.js     | 14 +++++---
 .../react/modules/netinfo/NetInfoModule.java  | 22 +++++-------
 5 files changed, 39 insertions(+), 41 deletions(-)

diff --git a/Examples/UIExplorer/NetInfoExample.js b/Examples/UIExplorer/NetInfoExample.js
index a79ed67e2043..97af9e1e00be 100644
--- a/Examples/UIExplorer/NetInfoExample.js
+++ b/Examples/UIExplorer/NetInfoExample.js
@@ -134,8 +134,8 @@ const IsConnectionExpensive = React.createClass({
     };
   },
   _checkIfExpensive() {
-    NetInfo.isConnectionExpensive(
-        (isConnectionExpensive) => { this.setState({isConnectionExpensive}); }
+    NetInfo.isConnectionExpensive().then(
+        isConnectionExpensive => { this.setState({isConnectionExpensive}); }
     );
   },
   render() {
diff --git a/Libraries/Network/NetInfo.js b/Libraries/Network/NetInfo.js
index 474ffd8f5bd1..5399be0250c8 100644
--- a/Libraries/Network/NetInfo.js
+++ b/Libraries/Network/NetInfo.js
@@ -16,6 +16,7 @@ const NativeModules = require('NativeModules');
 const Platform = require('Platform');
 const RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
 const RCTNetInfo = NativeModules.NetInfo;
+const deprecatedCallback = require('deprecatedCallback');
 
 const DEVICE_CONNECTIVITY_EVENT = 'networkStatusDidChange';
 
@@ -135,8 +136,12 @@ const _isConnectedSubscriptions = new Map();
  * monetary costs, data limitations or battery/performance issues.
  *
  * ```
- * NetInfo.isConnectionExpensive((isConnectionExpensive) => {
+ * NetInfo.isConnectionExpensive()
+ * .then(isConnectionExpensive => {
  *   console.log('Connection is ' + (isConnectionExpensive ? 'Expensive' : 'Not Expensive'));
+ * })
+ * .catch(error => {
+ *   console.error(error);
  * });
  * ```
  *
@@ -146,7 +151,7 @@ const _isConnectedSubscriptions = new Map();
  * internet connectivity.
  *
  * ```
- * NetInfo.isConnected.fetch().done((isConnected) => {
+ * NetInfo.isConnected.fetch().then(isConnected => {
  *   console.log('First, is ' + (isConnected ? 'online' : 'offline'));
  * });
  * function handleFirstConnectivityChange(isConnected) {
@@ -192,14 +197,7 @@ const NetInfo = {
   },
 
   fetch(): Promise {
-    return new Promise((resolve, reject) => {
-      RCTNetInfo.getCurrentConnectivity(
-        function(resp) {
-          resolve(resp.network_info);
-        },
-        reject
-      );
-    });
+    return RCTNetInfo.getCurrentConnectivity().then(resp => resp.network_info);
   },
 
   isConnected: {
@@ -239,15 +237,13 @@ const NetInfo = {
     },
   },
 
-  isConnectionExpensive(callback: (metered: ?boolean, error?: string) => void): void {
-    if (Platform.OS === 'android') {
-      RCTNetInfo.isConnectionMetered((_isMetered) => {
-        callback(_isMetered);
-      });
-    } else {
-      // TODO t9296080 consider polyfill and more features later on
-      callback(null, "Unsupported");
-    }
+  isConnectionExpensive(): Promise {
+    return deprecatedCallback(
+      Platform.OS === 'android' ? RCTNetInfo.isConnectionMetered() : Promise.reject(new Error('Currently not supported on iOS')),
+      Array.prototype.slice.call(arguments),
+      'single-callback-value-first',
+      'NetInfo.isConnectionMetered(callback) is deprecated. Use the returned Promise instead.'
+    );
   },
 };
 
diff --git a/Libraries/Network/RCTNetInfo.m b/Libraries/Network/RCTNetInfo.m
index 78e1c3ab732d..067996b6c353 100644
--- a/Libraries/Network/RCTNetInfo.m
+++ b/Libraries/Network/RCTNetInfo.m
@@ -87,10 +87,10 @@ - (void)dealloc
 #pragma mark - Public API
 
 // TODO: remove error callback - not needed except by Subscribable interface
-RCT_EXPORT_METHOD(getCurrentConnectivity:(RCTResponseSenderBlock)getSuccess
-                  withErrorCallback:(__unused RCTResponseSenderBlock)getError)
+RCT_EXPORT_METHOD(getCurrentConnectivity:(RCTPromiseResolveBlock)resolve
+                  reject:(__unused RCTPromiseRejectBlock)reject)
 {
-  getSuccess(@[@{@"network_info": _status}]);
+  resolve(@[@{@"network_info": _status}]);
 }
 
 @end
diff --git a/Libraries/Utilities/deprecatedCallback.js b/Libraries/Utilities/deprecatedCallback.js
index 8ed31254b13e..3beefdc483a8 100644
--- a/Libraries/Utilities/deprecatedCallback.js
+++ b/Libraries/Utilities/deprecatedCallback.js
@@ -19,7 +19,7 @@ module.exports = function(promise: Promise, callbacks: Array<Function>, type: st
     return promise;
   }
 
-  let success, error;
+  let success, error, callback;
 
   console.warn(warning);
 
@@ -36,13 +36,19 @@ module.exports = function(promise: Promise, callbacks: Array<Function>, type: st
       res => success(res),
       err => error(err)
     );
-  case 'node': // handles func(callback)
-    const [ callback ] = callbacks;
+  case 'single-callback-value-first': // handles func(callback(value, err))
+    [ callback ] = callbacks;
+    return promise.then(
+      res => callback(res),
+      err => callback(null, err)
+    );
+  case 'node': // handles func(callback(err, value))
+    [ callback ] = callbacks;
     return promise.then(
       res => callback(null, res),
       err => callback(err)
     );
   default:
-    throw new Error(`Type of callbacks not specified. Must be one of 'success-first', 'error-first', or 'node'`);
+    throw new Error(`Type of callbacks not specified. Must be one of 'success-first', 'error-first', 'single-callback-value-first', or 'node'`);
   }
 };
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java
index 463ad17c4d59..19b571592239 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java
@@ -17,15 +17,13 @@
 import android.net.NetworkInfo;
 import android.support.v4.net.ConnectivityManagerCompat;
 
-import com.facebook.common.logging.FLog;
-import com.facebook.react.bridge.Callback;
 import com.facebook.react.bridge.LifecycleEventListener;
+import com.facebook.react.bridge.Promise;
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.ReactContextBaseJavaModule;
 import com.facebook.react.bridge.ReactMethod;
 import com.facebook.react.bridge.WritableMap;
 import com.facebook.react.bridge.WritableNativeMap;
-import com.facebook.react.common.ReactConstants;
 
 import static com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter;
 
@@ -41,6 +39,8 @@ public class NetInfoModule extends ReactContextBaseJavaModule
       "To use NetInfo on Android, add the following to your AndroidManifest.xml:\n" +
       "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />";
 
+  private static final String ERROR_MISSING_PERMISSION = "E_MISSING_PERMISSION";
+
   private final ConnectivityManager mConnectivityManager;
   private final ConnectivityManagerCompat mConnectivityManagerCompat;
   private final ConnectivityBroadcastReceiver mConnectivityBroadcastReceiver;
@@ -81,25 +81,21 @@ public String getName() {
   }
 
   @ReactMethod
-  public void getCurrentConnectivity(Callback successCallback, Callback errorCallback) {
+  public void getCurrentConnectivity(Promise promise) {
     if (mNoNetworkPermission) {
-      if (errorCallback == null) {
-        FLog.e(ReactConstants.TAG, MISSING_PERMISSION_MESSAGE);
-        return;
-      }
-      errorCallback.invoke(MISSING_PERMISSION_MESSAGE);
+      promise.reject(ERROR_MISSING_PERMISSION, MISSING_PERMISSION_MESSAGE, null);
       return;
     }
-    successCallback.invoke(createConnectivityEventMap());
+    promise.resolve(createConnectivityEventMap());
   }
 
   @ReactMethod
-  public void isConnectionMetered(Callback successCallback) {
+  public void isConnectionMetered(Promise promise) {
     if (mNoNetworkPermission) {
-      FLog.e(ReactConstants.TAG, MISSING_PERMISSION_MESSAGE);
+      promise.reject(ERROR_MISSING_PERMISSION, MISSING_PERMISSION_MESSAGE, null);
       return;
     }
-    successCallback.invoke(mConnectivityManagerCompat.isActiveNetworkMetered(mConnectivityManager));
+    promise.resolve(ConnectivityManagerCompat.isActiveNetworkMetered(mConnectivityManager));
   }
 
   private void registerReceiver() {

From 480f7cd348da27eb4994f1bb2587eb29723e2421 Mon Sep 17 00:00:00 2001
From: sunnylqm <sunnylqm@qq.com>
Date: Mon, 15 Feb 2016 14:54:49 -0800
Subject: [PATCH 1170/1411] fix es6 class method

Reviewed By: svcscm

Differential Revision: D2938099

fb-gh-sync-id: 1148fdb96ec36a72db6ac4562b12b07ca2fc0af6
shipit-source-id: 1148fdb96ec36a72db6ac4562b12b07ca2fc0af6
---
 docs/CommunicationIOS.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/CommunicationIOS.md b/docs/CommunicationIOS.md
index 1e2d0ca073a0..ebc08328dd27 100644
--- a/docs/CommunicationIOS.md
+++ b/docs/CommunicationIOS.md
@@ -45,11 +45,11 @@ import React, {
 } from 'react-native';
 
 class ImageBrowserApp extends React.Component {
-  renderImage: function(imgURI) {
+  renderImage(imgURI) {
     return (
       <Image source={{uri: imgURI}} />
     );
-  },
+  }
   render() {
     return (
       <View>

From 5c18158aa91b78b8e421e4c8e717abc67df0f6b5 Mon Sep 17 00:00:00 2001
From: briancaw <brian@appboy.com>
Date: Mon, 15 Feb 2016 14:56:01 -0800
Subject: [PATCH 1171/1411] Fixes NativeModules documentation typo

Reviewed By: svcscm

Differential Revision: D2938100

fb-gh-sync-id: f2a3a479fb504fdbbae3a864009e290ef9b5539d
shipit-source-id: f2a3a479fb504fdbbae3a864009e290ef9b5539d
---
 docs/NativeModulesIOS.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/NativeModulesIOS.md b/docs/NativeModulesIOS.md
index 0f30191cda94..a066d5e2b09f 100644
--- a/docs/NativeModulesIOS.md
+++ b/docs/NativeModulesIOS.md
@@ -288,7 +288,7 @@ You must create a class extension of RCTConvert like so:
 @implementation RCTConvert (StatusBarAnimation)
   RCT_ENUM_CONVERTER(UIStatusBarAnimation, (@{ @"statusBarAnimationNone" : @(UIStatusBarAnimationNone),
                                                @"statusBarAnimationFade" : @(UIStatusBarAnimationFade),
-                                               @"statusBarAnimationSlide" : @(UIStatusBarAnimationSlide)},
+                                               @"statusBarAnimationSlide" : @(UIStatusBarAnimationSlide)}),
                       UIStatusBarAnimationNone, integerValue)
 @end
 ```

From fae03355940952189a379dae8c1d21ab2901a6e4 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Tue, 16 Feb 2016 09:57:25 +0000
Subject: [PATCH 1172/1411] trying to fix fbsource sync, reverting showcase.js
 to how it was on 2.12.2016 at fbsource

---
 website/src/react-native/showcase.js | 55 ++++++----------------------
 1 file changed, 11 insertions(+), 44 deletions(-)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index de1ad2a934c0..c939af9f7a93 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -135,12 +135,6 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/beetroot/id1016159001?ls=1&mt=8',
     author: 'Alex Duckmanton',
   },
-  {
-    name: 'Bhagavad Gita Lite',
-    icon: 'https://s3-us-west-2.amazonaws.com/bhagavadgitaapp/gita-free.png',
-    link: 'https://itunes.apple.com/us/app/bhagavad-gita-lite/id1071711190?ls=1&mt=8',
-    author: 'Tom Goldenberg & Nick Brown'
-  },
   {
     name: 'Bionic eStore',
     icon: 'http://a5.mzstatic.com/us/r30/Purple7/v4/c1/9a/3f/c19a3f82-ecc3-d60b-f983-04acc203705f/icon175x175.jpeg',
@@ -154,12 +148,6 @@ var apps = [
     linkPlayStore: 'https://play.google.com/store/apps/details?id=com.canddi',
     author: 'CANDDi LTD.',
   },
-  {
-    name: 'CaratLane',
-    icon: 'https://lh3.googleusercontent.com/wEN-Vvpbnw_n89dbXPxWkNnXB7sALKBKvpX_hbzrWbuC4tFi5tVkWHq8k5TAvdbf5UQ=w300-rw',
-    link: 'https://play.google.com/store/apps/details?id=com.caratlane.android&hl=en',
-    author: 'CaratLane',
-  },
   {
     name: 'CBS Sports Franchise Football',
     icon: 'http://a2.mzstatic.com/us/r30/Purple69/v4/7b/0c/a0/7b0ca007-885a-7cfc-9fa2-2ec4394c2ecc/icon175x175.png',
@@ -235,12 +223,6 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/fast-paper/id1001174614',
     author: 'Liubomyr Mykhalchenko (@liubko)',
   },
-  {
-    name: 'Feline for Product Hunt',
-    icon: 'https://lh3.googleusercontent.com/MCoiCCwUan0dxzqRR_Mrr7kO308roYdI2aTsIpUGYWzUmpJT1-R2_J04weQKFEd3Mg=w300-rw',
-    link: 'https://play.google.com/store/apps/details?id=com.arjunkomath.product_hunt&hl=en',
-    author: 'Arjun Komath',
-  },
   {
     name: 'Foodstand',
     icon: 'http://a3.mzstatic.com/us/r30/Purple69/v4/33/c1/3b/33c13b88-8ec2-23c1-56bb-712ad9938290/icon350x350.jpeg',
@@ -317,8 +299,7 @@ var apps = [
   {
     name: 'LoadDocs',
     icon: 'http://a2.mzstatic.com/us/r30/Purple3/v4/b5/ca/78/b5ca78ca-392d-6874-48bf-762293482d42/icon350x350.jpeg',
-    linkAppStore: 'https://itunes.apple.com/us/app/loaddocs/id1041596066',
-    linkPlayStore: 'https://play.google.com/store/apps/details?id=com.convoy.loaddoc&hl=en',
+    link: 'https://itunes.apple.com/us/app/loaddocs/id1041596066',
     author: 'LoadDocs',
   },
   {
@@ -364,12 +345,12 @@ var apps = [
     link: 'https://itunes.apple.com/cn/app/mockingbot/id1050565468?l=en&mt=8',
     author: 'YuanYi Zhang (@mockingbot)',
   },
-	{
-		name: 'MoneyLion',
-		icon: 'http://a5.mzstatic.com/us/r30/Purple69/v4/d7/9d/ad/d79daddc-8d67-8a6c-61e2-950425946dd2/icon350x350.jpeg',
-		link: 'https://itunes.apple.com/us/app/moneylion/id1064677082?mt=8',
-		author: 'MoneyLion LLC',
-	},
+  {
+    name: 'MoneyLion',
+    icon: 'http://a5.mzstatic.com/us/r30/Purple69/v4/d7/9d/ad/d79daddc-8d67-8a6c-61e2-950425946dd2/icon350x350.jpeg',
+    link: 'https://itunes.apple.com/us/app/moneylion/id1064677082?mt=8',
+    author: 'MoneyLion LLC',
+  },
   {
     name: 'Mr. Dapper',
     icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple4/v4/e8/3f/7c/e83f7cb3-2602-f8e8-de9a-ce0a775a4a14/mzl.hmdjhfai.png',
@@ -481,8 +462,7 @@ var apps = [
   {
     name: 'ShareHows',
     icon: 'http://a4.mzstatic.com/us/r30/Purple5/v4/78/1c/83/781c8325-a1e1-4afc-f106-a629bcf3c6ef/icon175x175.png',
-    linkAppStore: 'https://itunes.apple.com/kr/app/sweeohauseu-sesang-ui-modeun/id1060914858?mt=8',
-    linkPlayStore: 'https://play.google.com/store/apps/details?id=kr.dobbit.sharehows',
+    link: 'https://itunes.apple.com/kr/app/sweeohauseu-sesang-ui-modeun/id1060914858?mt=8',
     author: 'Dobbit Co., Ltd.'
   },
   {
@@ -503,12 +483,6 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/thai-tone/id1064086189?mt=8',
     author: 'Alexey Ledak',
   },
-  {
-    name: 'This AM',
-    icon: 'http://s3.r29static.com//bin/public/efe/x/1542038/image.png',
-    link: 'https://itunes.apple.com/us/app/refinery29-this-am-top-breaking/id988472315?mt=8',
-    author: 'Refinery29',
-  },
   {
     name: 'Tong Xing Wang',
     icon: 'http://a3.mzstatic.com/us/r30/Purple1/v4/7d/52/a7/7d52a71f-9532-82a5-b92f-87076624fdb2/icon175x175.jpeg',
@@ -530,9 +504,9 @@ var apps = [
   },
   {
     name: 'WPV',
-    icon: 'http://a2.mzstatic.com/us/r30/Purple49/v4/a8/26/d7/a826d7bf-337b-c6b8-488d-aca98027754d/icon350x350.png',
+    icon: 'http://a1.mzstatic.com/us/r30/Purple3/v4/f1/ae/51/f1ae516b-d8e9-1b6d-acfe-755623a88327/icon350x350.png',
     link: 'https://itunes.apple.com/us/app/wpv/id725222647?mt=8',
-    author: 'Yamill Vallecillo',
+    author: 'Yamill Vallecillo (@yamill3)',
   },
   {
     name: 'Yoloci',
@@ -570,14 +544,7 @@ var apps = [
     icon: 'http://7xk1ez.com2.z0.glb.qiniucdn.com/logo-mobile-0114logo_welcom.png',
     link: 'https://itunes.apple.com/us/app/ni-zao-me/id1025294933?l=zh&ls=1&mt=8',
     author: 'Scott Chen(@NZAOM)'
-  },
-  {
-    name: 'うたよみん',
-    icon: 'http://a4.mzstatic.com/jp/r30/Purple69/v4/19/8f/fa/198ffafe-66a6-d682-c8d1-47faf2b0badb/icon175x175.jpeg',
-    linkAppStore: 'https://itunes.apple.com/jp/app/minnano-duan-ge-tou-gaokomyuniti/id675671254?mt=8',
-    linkPlayStore: 'https://play.google.com/store/apps/details?id=com.plasticaromantica.utayomin',
-    author: 'Takayuki IMAI'
-  },
+  }
 ];
 
 var AppList = React.createClass({

From d31b47c018180169c580d4b2ef023a248f5fefae Mon Sep 17 00:00:00 2001
From: Travis Fischer <fisch0920@gmail.com>
Date: Mon, 15 Feb 2016 15:09:26 -0800
Subject: [PATCH 1173/1411] Add Text Blast to Example App Showcase

Reviewed By: svcscm

Differential Revision: D2936849

fb-gh-sync-id: db5a64f460c682a6e9e6e2b71bebdafe587e4447
shipit-source-id: db5a64f460c682a6e9e6e2b71bebdafe587e4447
---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index c939af9f7a93..116b8e254998 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -483,6 +483,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/thai-tone/id1064086189?mt=8',
     author: 'Alexey Ledak',
   },
+  {
+    name: 'Text Blast',
+    icon: 'http://a3.mzstatic.com/us/r30/Purple49/v4/4f/29/58/4f2958a1-7f35-9260-6340-c67ac29d7740/icon175x175.png',
+    link: 'https://itunes.apple.com/us/app/text-blast-2016/id1023852862?mt=8',
+    author: 'Sesh',
+  },
   {
     name: 'Tong Xing Wang',
     icon: 'http://a3.mzstatic.com/us/r30/Purple1/v4/7d/52/a7/7d52a71f-9532-82a5-b92f-87076624fdb2/icon175x175.jpeg',

From 4237a27ec9bff8632b9603929a511dcbe06ec0fe Mon Sep 17 00:00:00 2001
From: trave7er <mathew.park.yu@gmail.com>
Date: Mon, 15 Feb 2016 15:13:42 -0800
Subject: [PATCH 1174/1411] pick up some easy-to-fix lint warnings

Reviewed By: svcscm

Differential Revision: D2938097

fb-gh-sync-id: e3373bd44267251d8351d5203be1c88676aa8685
shipit-source-id: e3373bd44267251d8351d5203be1c88676aa8685
---
 .../DatePickerAndroid/DatePickerAndroid.android.js          | 2 +-
 .../Components/DatePickerAndroid/DatePickerAndroid.ios.js   | 2 +-
 Libraries/Components/Picker/PickerAndroid.android.js        | 3 ++-
 Libraries/Components/Switch/Switch.js                       | 2 +-
 .../TimePickerAndroid/TimePickerAndroid.android.js          | 2 +-
 .../Components/TimePickerAndroid/TimePickerAndroid.ios.js   | 2 +-
 Libraries/Components/Touchable/TouchableHighlight.js        | 6 +++---
 Libraries/Components/Touchable/TouchableWithoutFeedback.js  | 2 +-
 Libraries/Components/View/View.js                           | 2 +-
 Libraries/Components/WebView/WebView.android.js             | 2 +-
 Libraries/Components/WebView/WebView.ios.js                 | 2 +-
 11 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js
index d446544c6aec..64ae4a506a75 100644
--- a/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js
+++ b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js
@@ -52,7 +52,7 @@ class DatePickerAndroid {
    *   * `date` (`Date` object or timestamp in milliseconds) - date to show by default
    *   * `minDate` (`Date` or timestamp in milliseconds) - minimum date that can be selected
    *   * `maxDate` (`Date` object or timestamp in milliseconds) - minimum date that can be selected
-   * 
+   *
    * Returns a Promise which will be invoked an object containing `action`, `year`, `month` (0-11),
    * `day` if the user picked a date. If the user dismissed the dialog, the Promise will
    * still be resolved with action being `DatePickerAndroid.dismissedAction` and all the other keys
diff --git a/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js
index b0ab643fa23d..784bc2c82147 100644
--- a/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js
+++ b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js
@@ -19,6 +19,6 @@ const DatePickerAndroid = {
       message: 'DatePickerAndroid is not supported on this platform.'
     });
   },
-}
+};
 
 module.exports = DatePickerAndroid;
diff --git a/Libraries/Components/Picker/PickerAndroid.android.js b/Libraries/Components/Picker/PickerAndroid.android.js
index 2e95b32f1a6a..71d7b35e81d1 100644
--- a/Libraries/Components/Picker/PickerAndroid.android.js
+++ b/Libraries/Components/Picker/PickerAndroid.android.js
@@ -134,7 +134,8 @@ var cfg = {
     items: true,
     selected: true,
   }
-}
+};
+
 var DropdownPicker = requireNativeComponent('AndroidDropdownPicker', PickerAndroid, cfg);
 var DialogPicker = requireNativeComponent('AndroidDialogPicker', PickerAndroid, cfg);
 
diff --git a/Libraries/Components/Switch/Switch.js b/Libraries/Components/Switch/Switch.js
index 9816db385c92..273139e7160f 100644
--- a/Libraries/Components/Switch/Switch.js
+++ b/Libraries/Components/Switch/Switch.js
@@ -44,7 +44,7 @@ var Switch = React.createClass({
      * Used to locate this view in end-to-end tests.
      */
     testID: React.PropTypes.string,
-    
+
     /**
      * Background color when the switch is turned off.
      * @platform ios
diff --git a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js
index 98bf034a8e02..14480040ca54 100644
--- a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js
+++ b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js
@@ -62,6 +62,6 @@ class TimePickerAndroid {
    * The dialog has been dismissed.
    */
   static get dismissedAction() { return 'dismissedAction'; }
-};
+}
 
 module.exports = TimePickerAndroid;
diff --git a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js
index df993ba92275..02eae1e1fee3 100644
--- a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js
+++ b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js
@@ -19,6 +19,6 @@ const TimePickerAndroid = {
       message: 'TimePickerAndroid is not supported on this platform.'
     });
   },
-}
+};
 
 module.exports = TimePickerAndroid;
diff --git a/Libraries/Components/Touchable/TouchableHighlight.js b/Libraries/Components/Touchable/TouchableHighlight.js
index ca94126665d3..9a514e46b7a9 100644
--- a/Libraries/Components/Touchable/TouchableHighlight.js
+++ b/Libraries/Components/Touchable/TouchableHighlight.js
@@ -213,9 +213,9 @@ var TouchableHighlight = React.createClass({
 
   _hasPressHandler: function() {
     return !!(
-      this.props.onPress || 
-      this.props.onPressIn || 
-      this.props.onPressOut || 
+      this.props.onPress ||
+      this.props.onPressIn ||
+      this.props.onPressOut ||
       this.props.onLongPress
     );
   },
diff --git a/Libraries/Components/Touchable/TouchableWithoutFeedback.js b/Libraries/Components/Touchable/TouchableWithoutFeedback.js
index 5a578a205a7c..5312c1f87886 100755
--- a/Libraries/Components/Touchable/TouchableWithoutFeedback.js
+++ b/Libraries/Components/Touchable/TouchableWithoutFeedback.js
@@ -29,7 +29,7 @@ var PRESS_RETENTION_OFFSET = {top: 20, left: 20, right: 20, bottom: 30};
  * Do not use unless you have a very good reason. All the elements that
  * respond to press should have a visual feedback when touched. This is
  * one of the primary reason a "web" app doesn't feel "native".
- * 
+ *
  * > **NOTE**: TouchableWithoutFeedback supports only one child
  * >
  * > If you wish to have several child components, wrap them in a View.
diff --git a/Libraries/Components/View/View.js b/Libraries/Components/View/View.js
index a7f31f9a0ac8..8dc69534192b 100644
--- a/Libraries/Components/View/View.js
+++ b/Libraries/Components/View/View.js
@@ -53,7 +53,7 @@ const AccessibilityComponentType = [
 
 const forceTouchAvailable = (UIManager.RCTView.Constants &&
   UIManager.RCTView.Constants.forceTouchAvailable) || false;
-  
+
 const statics = {
   AccessibilityTraits,
   AccessibilityComponentType,
diff --git a/Libraries/Components/WebView/WebView.android.js b/Libraries/Components/WebView/WebView.android.js
index 44ad8a925721..2c8e2312d5a2 100644
--- a/Libraries/Components/WebView/WebView.android.js
+++ b/Libraries/Components/WebView/WebView.android.js
@@ -186,7 +186,7 @@ var WebView = React.createClass({
     } else if (this.props.url) {
       source.uri = this.props.url;
     }
-    
+
     if (source.method === 'POST' && source.headers) {
       console.warn('WebView: `source.headers` is not supported when using POST.');
     } else if (source.method === 'GET' && source.body) {
diff --git a/Libraries/Components/WebView/WebView.ios.js b/Libraries/Components/WebView/WebView.ios.js
index 7714d383df87..3b37331ae2b0 100644
--- a/Libraries/Components/WebView/WebView.ios.js
+++ b/Libraries/Components/WebView/WebView.ios.js
@@ -18,7 +18,7 @@ var StyleSheet = require('StyleSheet');
 var Text = require('Text');
 var UIManager = require('UIManager');
 var View = require('View');
-var ScrollView = require('ScrollView')
+var ScrollView = require('ScrollView');
 
 var deprecatedPropType = require('deprecatedPropType');
 var invariant = require('invariant');

From c6a8fb977d5ac60f777cce4631c39d173b7313a3 Mon Sep 17 00:00:00 2001
From: Brent Vatne <brentvatne@gmail.com>
Date: Mon, 15 Feb 2016 16:59:49 -0800
Subject: [PATCH 1175/1411] Fix links to Flexbox / ShadowPropTypesIOS /
 Transforms in styles

Reviewed By: svcscm

Differential Revision: D2938201

fb-gh-sync-id: c20790fa69984f0b592c48fbfdca74f3dfc9d14d
shipit-source-id: c20790fa69984f0b592c48fbfdca74f3dfc9d14d
---
 website/layout/AutodocsLayout.js | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/website/layout/AutodocsLayout.js b/website/layout/AutodocsLayout.js
index cbf78db59db6..7ac083bc05df 100644
--- a/website/layout/AutodocsLayout.js
+++ b/website/layout/AutodocsLayout.js
@@ -175,15 +175,15 @@ var ComponentDoc = React.createClass({
           if (name === 'LayoutPropTypes') {
             name = 'Flexbox';
             link =
-              <a href={slugify(name) + '.html#proptypes'}>{name}...</a>;
+              <a href={'docs/' + slugify(name) + '.html#proptypes'}>{name}...</a>;
           } else if (name === 'TransformPropTypes') {
             name = 'Transforms';
             link =
-              <a href={slugify(name) + '.html#proptypes'}>{name}...</a>;
+              <a href={'docs/' + slugify(name) + '.html#proptypes'}>{name}...</a>;
           } else {
             name = name.replace('StylePropTypes', '');
             link =
-              <a href={slugify(name) + '.html#style'}>{name}#style...</a>;
+              <a href={'docs/' + slugify(name) + '.html#style'}>{name}#style...</a>;
           }
           return (
             <div className="prop" key={name}>

From fa638c79971298bc88cccfe13657faf23cd249f0 Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Mon, 15 Feb 2016 17:04:20 -0800
Subject: [PATCH 1176/1411] Remove React Devtools from debugging docs

Reviewed By: svcscm

Differential Revision: D2938227

fb-gh-sync-id: 3eb495509f99de448722cceef903d16f49dae88e
shipit-source-id: 3eb495509f99de448722cceef903d16f49dae88e
---
 docs/Debugging.md | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/docs/Debugging.md b/docs/Debugging.md
index 3e7793aabdb3..6c70ff22ce1a 100644
--- a/docs/Debugging.md
+++ b/docs/Debugging.md
@@ -43,9 +43,6 @@ To debug on a real device:
 1. On iOS - open the file `RCTWebSocketExecutor.m` and change `localhost` to the IP address of your computer. Shake the device to open the development menu with the option to start debugging.
 2. On Android, if you're running Android 5.0+ device connected via USB you can use `adb` command line tool to setup port forwarding from the device to your computer. For that run: `adb reverse tcp:8081 tcp:8081` (see [this link](http://developer.android.com/tools/help/adb.html) for help on `adb` command). Alternatively, you can [open dev menu](#debugging-react-native-apps) on the device and select `Dev Settings`, then update `Debug server host for device` setting to the IP address of your computer.
 
-#### React Developer Tools (optional)
-Install the [React Developer Tools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en) extension for Google Chrome. This will allow you to navigate the component hierarchy via the `React` in the developer tools (see [facebook/react-devtools](https://github.com/facebook/react-devtools) for more information).
-
 ### Live Reload
 This option allows for your JS changes to trigger automatic reload on the connected device/emulator. To enable this option:
 

From 9856a9726781939bb2b36bbe2e9c89861542da4f Mon Sep 17 00:00:00 2001
From: Xavier Carpentier <xcapetir@gmail.com>
Date: Mon, 15 Feb 2016 18:25:40 -0800
Subject: [PATCH 1177/1411] Add sneat app

Reviewed By: svcscm

Differential Revision: D2938292

fb-gh-sync-id: 72064ac712fd9fa011b406a35d60bf098ca6c994
shipit-source-id: 72064ac712fd9fa011b406a35d60bf098ca6c994
---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 116b8e254998..5e917f3242d4 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -465,6 +465,12 @@ var apps = [
     link: 'https://itunes.apple.com/kr/app/sweeohauseu-sesang-ui-modeun/id1060914858?mt=8',
     author: 'Dobbit Co., Ltd.'
   },
+  {
+    name: 'sneat: réservez les meilleurs restaurants de Paris',
+    icon: 'http://a3.mzstatic.com/eu/r30/Purple49/v4/71/71/df/7171df47-6e03-8619-19a8-07f52186b0ed/icon175x175.jpeg',
+    link: 'https://itunes.apple.com/fr/app/sneat-reservez-les-meilleurs/id1062510079?l=en&mt=8',
+    author: 'sneat'
+  },
   {
     name: 'Spero for Cancer',
     icon: 'https://s3-us-west-1.amazonaws.com/cancerspot/site_images/Spero1024.png',

From 9a918ef48fb943a9dcc1885a6cf09ca0f510c695 Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Mon, 15 Feb 2016 22:33:11 -0800
Subject: [PATCH 1178/1411] Improve performance of node-haste2 and
 react-packager

Reviewed By: davidaurelio

Differential Revision: D2911210

fb-gh-sync-id: 8ac2f213e8a9e089281bb065f9a7190d2e0f5b18
shipit-source-id: 8ac2f213e8a9e089281bb065f9a7190d2e0f5b18
---
 npm-shrinkwrap.json                           | 219 +++++++++---------
 package.json                                  |   4 +-
 packager/react-packager/index.js              |   1 +
 .../src/DependencyResolver/Cache/index.js     |   4 +-
 .../Cache/lib/getCacheFilePath.js             |   2 +-
 .../DependencyGraph/DependencyGraphHelpers.js |  14 +-
 .../DependencyGraph/DeprecatedAssetMap.js     |  24 +-
 .../DependencyGraph/HasteMap.js               |  28 +--
 .../DependencyGraph/ResolutionRequest.js      |   5 +-
 .../DependencyGraph/index.js                  |  36 +--
 .../FileWatcher/__mocks__/sane.js             |   1 +
 .../FileWatcher/__tests__/FileWatcher-test.js |  73 +++---
 .../DependencyResolver/FileWatcher/index.js   |  53 +++--
 .../src/DependencyResolver/Module.js          |   8 +-
 .../src/DependencyResolver/ModuleCache.js     |   5 +-
 .../src/DependencyResolver/Package.js         |   4 +-
 .../__tests__/Module-test.js                  |  10 +-
 .../src/DependencyResolver/crawlers/node.js   |   2 +-
 .../DependencyResolver/crawlers/watchman.js   |  16 +-
 .../src/DependencyResolver/fastfs.js          | 140 ++++-------
 .../DependencyResolver/lib/extractRequires.js |   2 +-
 .../lib/getAssetDataFromName.js               |   2 +-
 .../lib/getPlatformExtension.js               |  20 +-
 packager/react-packager/src/Server/index.js   |   2 +-
 24 files changed, 330 insertions(+), 345 deletions(-)

diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index 7ad46f5e98e4..fd91dc33f025 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -127,30 +127,30 @@
           "from": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz",
           "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz"
         },
-        "globals": {
-          "version": "6.4.1",
-          "from": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz",
-          "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
-        },
         "babylon": {
           "version": "5.8.29",
           "from": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz",
           "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz"
         },
+        "globals": {
+          "version": "6.4.1",
+          "from": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz",
+          "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
+        },
         "js-tokens": {
           "version": "1.0.1",
           "from": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz",
           "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
         },
-        "recast": {
-          "version": "0.10.33",
-          "from": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz",
-          "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
-        },
         "regenerator": {
           "version": "0.8.40",
           "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
           "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
+        },
+        "recast": {
+          "version": "0.10.33",
+          "from": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz",
+          "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
         }
       }
     },
@@ -228,16 +228,16 @@
           "from": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz",
           "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz"
         },
-        "babylon": {
-          "version": "5.8.29",
-          "from": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz",
-          "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz"
-        },
         "globals": {
           "version": "6.4.1",
           "from": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz",
           "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
         },
+        "babylon": {
+          "version": "5.8.29",
+          "from": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz",
+          "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz"
+        },
         "js-tokens": {
           "version": "1.0.1",
           "from": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz",
@@ -1814,6 +1814,11 @@
       "from": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.1.0.tgz",
       "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.1.0.tgz"
     },
+    "fast-path": {
+      "version": "1.1.0",
+      "from": "fast-path@*",
+      "resolved": "https://registry.npmjs.org/fast-path/-/fast-path-1.1.0.tgz"
+    },
     "fbjs": {
       "version": "0.6.0",
       "from": "https://registry.npmjs.org/fbjs/-/fbjs-0.6.0.tgz",
@@ -1890,76 +1895,71 @@
             }
           }
         },
-        "abbrev": {
-          "version": "1.0.7",
-          "from": "abbrev@1",
-          "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz"
-        },
         "ansi": {
           "version": "0.3.0",
           "from": "ansi@~0.3.0",
           "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.0.tgz"
         },
-        "ansi-regex": {
-          "version": "2.0.0",
-          "from": "ansi-regex@^2.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
-        },
         "ansi-styles": {
           "version": "2.1.0",
           "from": "ansi-styles@^2.1.0",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz"
         },
-        "are-we-there-yet": {
-          "version": "1.0.4",
-          "from": "are-we-there-yet@~1.0.0",
-          "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.4.tgz"
+        "abbrev": {
+          "version": "1.0.7",
+          "from": "abbrev@1",
+          "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz"
+        },
+        "ansi-regex": {
+          "version": "2.0.0",
+          "from": "ansi-regex@^2.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
         },
         "asn1": {
           "version": "0.1.11",
           "from": "asn1@0.1.11",
           "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
         },
-        "assert-plus": {
-          "version": "0.1.5",
-          "from": "assert-plus@^0.1.5",
-          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
+        "are-we-there-yet": {
+          "version": "1.0.4",
+          "from": "are-we-there-yet@~1.0.0",
+          "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.4.tgz"
+        },
+        "aws-sign2": {
+          "version": "0.6.0",
+          "from": "aws-sign2@~0.6.0",
+          "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
         },
         "async": {
           "version": "1.5.0",
           "from": "async@^1.4.0",
           "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz"
         },
-        "aws-sign2": {
-          "version": "0.6.0",
-          "from": "aws-sign2@~0.6.0",
-          "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
+        "assert-plus": {
+          "version": "0.1.5",
+          "from": "assert-plus@^0.1.5",
+          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
         },
         "balanced-match": {
           "version": "0.2.1",
           "from": "balanced-match@>=0.2.0 <0.3.0",
           "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.1.tgz"
         },
-        "block-stream": {
-          "version": "0.0.8",
-          "from": "block-stream@*",
-          "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.8.tgz"
-        },
         "boom": {
           "version": "2.10.1",
           "from": "boom@^2.8.x",
           "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz"
         },
+        "block-stream": {
+          "version": "0.0.8",
+          "from": "block-stream@*",
+          "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.8.tgz"
+        },
         "brace-expansion": {
           "version": "1.1.1",
           "from": "brace-expansion@>=1.0.0 <2.0.0",
           "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz"
         },
-        "caseless": {
-          "version": "0.11.0",
-          "from": "caseless@~0.11.0",
-          "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
-        },
         "chalk": {
           "version": "1.1.1",
           "from": "chalk@^1.1.1",
@@ -1970,21 +1970,26 @@
           "from": "combined-stream@~1.0.5",
           "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz"
         },
+        "caseless": {
+          "version": "0.11.0",
+          "from": "caseless@~0.11.0",
+          "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
+        },
         "commander": {
           "version": "2.9.0",
           "from": "commander@^2.8.1",
           "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz"
         },
-        "concat-map": {
-          "version": "0.0.1",
-          "from": "concat-map@0.0.1",
-          "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
-        },
         "core-util-is": {
           "version": "1.0.1",
           "from": "core-util-is@~1.0.0",
           "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
         },
+        "concat-map": {
+          "version": "0.0.1",
+          "from": "concat-map@0.0.1",
+          "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
+        },
         "cryptiles": {
           "version": "2.0.5",
           "from": "cryptiles@2.x.x",
@@ -1995,16 +2000,16 @@
           "from": "ctype@0.5.3",
           "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz"
         },
-        "debug": {
-          "version": "0.7.4",
-          "from": "debug@~0.7.2",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz"
-        },
         "deep-extend": {
           "version": "0.2.11",
           "from": "deep-extend@~0.2.5",
           "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.2.11.tgz"
         },
+        "debug": {
+          "version": "0.7.4",
+          "from": "debug@~0.7.2",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz"
+        },
         "delayed-stream": {
           "version": "1.0.0",
           "from": "delayed-stream@~1.0.0",
@@ -2055,16 +2060,16 @@
           "from": "generate-object-property@^1.1.0",
           "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz"
         },
-        "graceful-fs": {
-          "version": "4.1.2",
-          "from": "graceful-fs@4.1",
-          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.2.tgz"
-        },
         "graceful-readlink": {
           "version": "1.0.1",
           "from": "graceful-readlink@>= 1.0.0",
           "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
         },
+        "graceful-fs": {
+          "version": "4.1.2",
+          "from": "graceful-fs@4.1",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.2.tgz"
+        },
         "har-validator": {
           "version": "2.0.2",
           "from": "har-validator@~2.0.2",
@@ -2110,11 +2115,6 @@
           "from": "is-my-json-valid@^2.12.2",
           "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.2.tgz"
         },
-        "is-property": {
-          "version": "1.0.2",
-          "from": "is-property@^1.0.0",
-          "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz"
-        },
         "isarray": {
           "version": "0.0.1",
           "from": "isarray@0.0.1",
@@ -2125,21 +2125,26 @@
           "from": "isstream@~0.1.2",
           "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
         },
+        "is-property": {
+          "version": "1.0.2",
+          "from": "is-property@^1.0.0",
+          "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz"
+        },
         "json-stringify-safe": {
           "version": "5.0.1",
           "from": "json-stringify-safe@~5.0.1",
           "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
         },
-        "jsonpointer": {
-          "version": "2.0.0",
-          "from": "jsonpointer@2.0.0",
-          "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
-        },
         "lodash._basetostring": {
           "version": "3.0.1",
           "from": "lodash._basetostring@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz"
         },
+        "jsonpointer": {
+          "version": "2.0.0",
+          "from": "jsonpointer@2.0.0",
+          "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
+        },
         "lodash._createpadding": {
           "version": "3.6.1",
           "from": "lodash._createpadding@^3.0.0",
@@ -2150,31 +2155,31 @@
           "from": "lodash.pad@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-3.1.1.tgz"
         },
-        "lodash.padleft": {
-          "version": "3.1.1",
-          "from": "lodash.padleft@^3.0.0",
-          "resolved": "https://registry.npmjs.org/lodash.padleft/-/lodash.padleft-3.1.1.tgz"
-        },
         "lodash.padright": {
           "version": "3.1.1",
           "from": "lodash.padright@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash.padright/-/lodash.padright-3.1.1.tgz"
         },
+        "lodash.padleft": {
+          "version": "3.1.1",
+          "from": "lodash.padleft@^3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash.padleft/-/lodash.padleft-3.1.1.tgz"
+        },
         "lodash.repeat": {
           "version": "3.0.1",
           "from": "lodash.repeat@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash.repeat/-/lodash.repeat-3.0.1.tgz"
         },
-        "mime-db": {
-          "version": "1.19.0",
-          "from": "mime-db@~1.19.0",
-          "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.19.0.tgz"
-        },
         "mime-types": {
           "version": "2.1.7",
           "from": "mime-types@~2.1.7",
           "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.7.tgz"
         },
+        "mime-db": {
+          "version": "1.19.0",
+          "from": "mime-db@~1.19.0",
+          "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.19.0.tgz"
+        },
         "minimist": {
           "version": "0.0.8",
           "from": "minimist@0.0.8",
@@ -2195,21 +2200,26 @@
           "from": "npmlog@~1.2.0",
           "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz"
         },
-        "oauth-sign": {
-          "version": "0.8.0",
-          "from": "oauth-sign@~0.8.0",
-          "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.0.tgz"
-        },
         "once": {
           "version": "1.1.1",
           "from": "once@~1.1.1",
           "resolved": "https://registry.npmjs.org/once/-/once-1.1.1.tgz"
         },
+        "oauth-sign": {
+          "version": "0.8.0",
+          "from": "oauth-sign@~0.8.0",
+          "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.0.tgz"
+        },
         "path-is-absolute": {
           "version": "1.0.0",
           "from": "path-is-absolute@>=1.0.0 <2.0.0",
           "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz"
         },
+        "qs": {
+          "version": "5.2.0",
+          "from": "qs@~5.2.0",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz"
+        },
         "pinkie": {
           "version": "1.0.0",
           "from": "pinkie@^1.0.0",
@@ -2220,11 +2230,6 @@
           "from": "pinkie-promise@^1.0.0",
           "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz"
         },
-        "qs": {
-          "version": "5.2.0",
-          "from": "qs@~5.2.0",
-          "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz"
-        },
         "readable-stream": {
           "version": "1.1.13",
           "from": "readable-stream@^1.1.13",
@@ -2235,16 +2240,16 @@
           "from": "request@2.x",
           "resolved": "https://registry.npmjs.org/request/-/request-2.65.0.tgz"
         },
-        "semver": {
-          "version": "5.0.3",
-          "from": "semver@~5.0.1",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
-        },
         "sntp": {
           "version": "1.0.9",
           "from": "sntp@1.x.x",
           "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
         },
+        "semver": {
+          "version": "5.0.3",
+          "from": "semver@~5.0.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
+        },
         "string_decoder": {
           "version": "0.10.31",
           "from": "string_decoder@~0.10.x",
@@ -2255,26 +2260,26 @@
           "from": "stringstream@~0.0.4",
           "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
         },
-        "strip-ansi": {
-          "version": "3.0.0",
-          "from": "strip-ansi@^3.0.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz"
-        },
         "strip-json-comments": {
           "version": "0.1.3",
           "from": "strip-json-comments@0.1.x",
           "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
         },
-        "supports-color": {
-          "version": "2.0.0",
-          "from": "supports-color@^2.0.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
-        },
         "tar": {
           "version": "2.2.1",
           "from": "tar@~2.2.0",
           "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz"
         },
+        "strip-ansi": {
+          "version": "3.0.0",
+          "from": "strip-ansi@^3.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz"
+        },
+        "supports-color": {
+          "version": "2.0.0",
+          "from": "supports-color@^2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
+        },
         "tough-cookie": {
           "version": "2.2.0",
           "from": "tough-cookie@~2.2.0",
diff --git a/package.json b/package.json
index ea74c16ff9b9..78c359b2f293 100644
--- a/package.json
+++ b/package.json
@@ -75,7 +75,8 @@
     ],
     "unmockedModulePathPatterns": [
       "promise",
-      "source-map"
+      "source-map",
+      "fast-path"
     ]
   },
   "main": "Libraries/react-native/react-native.js",
@@ -122,6 +123,7 @@
     "connect": "^2.8.3",
     "debug": "^2.2.0",
     "event-target-shim": "^1.0.5",
+    "fast-path": "^1.1.0",
     "fbjs": "^0.6.0",
     "fbjs-scripts": "^0.4.0",
     "graceful-fs": "^4.1.2",
diff --git a/packager/react-packager/index.js b/packager/react-packager/index.js
index 5b28e7741a2b..a392bdf5dd96 100644
--- a/packager/react-packager/index.js
+++ b/packager/react-packager/index.js
@@ -10,6 +10,7 @@
 
 require('../babelRegisterOnly')([/react-packager\/src/]);
 
+require('fast-path').replace();
 useGracefulFs();
 
 var debug = require('debug');
diff --git a/packager/react-packager/src/DependencyResolver/Cache/index.js b/packager/react-packager/src/DependencyResolver/Cache/index.js
index 4e1698cb3fda..26ccb1e7cd97 100644
--- a/packager/react-packager/src/DependencyResolver/Cache/index.js
+++ b/packager/react-packager/src/DependencyResolver/Cache/index.js
@@ -51,11 +51,9 @@ class Cache {
       throw new Error('Use absolute paths');
     }
 
-    var recordP = this.has(filepath, field)
+    return this.has(filepath, field)
       ? this._data[filepath].data[field]
       : this.set(filepath, field, loaderCb(filepath));
-
-    return recordP.then(record => record);
   }
 
   invalidate(filepath, field) {
diff --git a/packager/react-packager/src/DependencyResolver/Cache/lib/getCacheFilePath.js b/packager/react-packager/src/DependencyResolver/Cache/lib/getCacheFilePath.js
index 3975b65a34b2..a14faf9ff853 100644
--- a/packager/react-packager/src/DependencyResolver/Cache/lib/getCacheFilePath.js
+++ b/packager/react-packager/src/DependencyResolver/Cache/lib/getCacheFilePath.js
@@ -9,7 +9,7 @@
 'use strict';
 
 const crypto = require('crypto');
-const path = require('path');
+const path = require('fast-path');
 
 function getCacheFilePath(tmpdir, ...args) {
   const hash = crypto.createHash('md5');
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/DependencyGraphHelpers.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/DependencyGraphHelpers.js
index d7d9f20e578e..ed5a1a7b7308 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/DependencyGraphHelpers.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/DependencyGraphHelpers.js
@@ -8,7 +8,7 @@
  */
 'use strict';
 
-const path = require('path');
+const path = require('fast-path');
 
 class DependencyGraphHelpers {
   constructor({ providesModuleNodeModules, assetExts }) {
@@ -17,17 +17,13 @@ class DependencyGraphHelpers {
   }
 
   isNodeModulesDir(file) {
-    let parts = path.normalize(file).split(path.sep);
-    const indexOfNodeModules = parts.lastIndexOf('node_modules');
-
-    if (indexOfNodeModules === -1) {
+    const index = file.lastIndexOf('/node_modules/');
+    if (index === -1) {
       return false;
     }
 
-    parts = parts.slice(indexOfNodeModules + 1);
-
+    const parts = file.substr(index + 14).split(path.sep);
     const dirs = this._providesModuleNodeModules;
-
     for (let i = 0; i < dirs.length; i++) {
       if (parts.indexOf(dirs[i]) > -1) {
         return false;
@@ -42,7 +38,7 @@ class DependencyGraphHelpers {
   }
 
   extname(name) {
-    return path.extname(name).replace(/^\./, '');
+    return path.extname(name).substr(1);
   }
 }
 
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/DeprecatedAssetMap.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/DeprecatedAssetMap.js
index 5f18875ae1fd..531d54bc472c 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/DeprecatedAssetMap.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/DeprecatedAssetMap.js
@@ -11,7 +11,7 @@
 const AssetModule_DEPRECATED = require('../AssetModule_DEPRECATED');
 const Fastfs = require('../fastfs');
 const debug = require('debug')('ReactNativePackager:DependencyGraph');
-const path = require('path');
+const path = require('fast-path');
 const Promise = require('promise');
 
 class DeprecatedAssetMap {
@@ -23,8 +23,9 @@ class DeprecatedAssetMap {
     ignoreFilePath,
     helpers,
     activity,
+    enabled,
   }) {
-    if (roots == null || roots.length === 0) {
+    if (roots == null || roots.length === 0 || !enabled) {
       this._disabled = true;
       return;
     }
@@ -32,15 +33,18 @@ class DeprecatedAssetMap {
     this._helpers = helpers;
     this._map = Object.create(null);
     this._assetExts = assetExts;
-    this._fastfs = new Fastfs(
-      'Assets',
-      roots,
-      fileWatcher,
-      { ignore: ignoreFilePath, crawling: fsCrawl, activity }
-    );
     this._activity = activity;
 
-    this._fastfs.on('change', this._processFileChange.bind(this));
+    if (!this._disabled) {
+      this._fastfs = new Fastfs(
+        'Assets',
+        roots,
+        fileWatcher,
+        { ignore: ignoreFilePath, crawling: fsCrawl, activity }
+      );
+
+      this._fastfs.on('change', this._processFileChange.bind(this));
+    }
   }
 
   build() {
@@ -89,7 +93,7 @@ class DeprecatedAssetMap {
     if (this._assetExts.indexOf(ext) !== -1) {
       const name = assetName(file, ext);
       if (this._map[name] != null) {
-        debug('Conflcting assets', name);
+        debug('Conflicting assets', name);
       }
 
       this._map[name] = new AssetModule_DEPRECATED({ file });
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/HasteMap.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/HasteMap.js
index 2f0b26af4773..47f93699b3b9 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/HasteMap.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/HasteMap.js
@@ -7,7 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  */
 'use strict';
-const path = require('path');
+const path = require('fast-path');
 const getPlatformExtension = require('../lib/getPlatformExtension');
 const Promise = require('promise');
 
@@ -31,18 +31,18 @@ class HasteMap {
 
   build() {
     this._map = Object.create(null);
-
-    let promises = this._fastfs.findFilesByExts(this._extensions, {
-      ignore: (file) => this._helpers.isNodeModulesDir(file),
-    }).map(file => this._processHasteModule(file));
-
-    promises = promises.concat(
-      this._fastfs.findFilesByName('package.json', {
-        ignore: (file) => this._helpers.isNodeModulesDir(file),
-      }).map(file => this._processHastePackage(file))
-    );
-
-    return Promise.all(promises);
+    const promises = [];
+    this._fastfs.getAllFiles().forEach(filePath => {
+      if (!this._helpers.isNodeModulesDir(filePath)) {
+        if (this._extensions.indexOf(path.extname(filePath).substr(1)) !== -1) {
+          promises.push(this._processHasteModule(filePath));
+        }
+        if (filePath.endsWith('/package.json')) {
+          promises.push(this._processHastePackage(filePath));
+        }
+      }
+    });
+    return Promise.all(promises).then(() => this._map);
   }
 
   processFileChange(type, absPath) {
@@ -106,7 +106,7 @@ class HasteMap {
 
   _processHastePackage(file) {
     file = path.resolve(file);
-    const p = this._moduleCache.getPackage(file, this._fastfs);
+    const p = this._moduleCache.getPackage(file);
     return p.isHaste()
       .then(isHaste => isHaste && p.getName()
             .then(name => this._updateHasteMap(name, p)))
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
index c4004ed75183..510b03fe393e 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
@@ -10,7 +10,8 @@
 
 const debug = require('debug')('ReactNativePackager:DependencyGraph');
 const util = require('util');
-const path = require('path');
+const path = require('fast-path');
+const realPath = require('path');
 const isAbsolutePath = require('absolute-path');
 const getAssetDataFromName = require('../lib/getAssetDataFromName');
 const Promise = require('promise');
@@ -287,7 +288,7 @@ class ResolutionRequest {
 
           const searchQueue = [];
           for (let currDir = path.dirname(fromModule.path);
-               currDir !== path.parse(fromModule.path).root;
+               currDir !== realPath.parse(fromModule.path).root;
                currDir = path.dirname(currDir)) {
             searchQueue.push(
               path.join(currDir, 'node_modules', realModuleName)
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
index 9241b18a119a..b3a987b1f79c 100644
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
+++ b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
@@ -14,7 +14,7 @@ const Promise = require('promise');
 const crawl = require('../crawlers');
 const getPlatformExtension = require('../lib/getPlatformExtension');
 const isAbsolutePath = require('absolute-path');
-const path = require('path');
+const path = require('fast-path');
 const util = require('util');
 const DependencyGraphHelpers = require('./DependencyGraphHelpers');
 const ResolutionRequest = require('./ResolutionRequest');
@@ -46,6 +46,7 @@ class DependencyGraph {
     extractRequires,
     transformCode,
     shouldThrowOnUnresolvedErrors = () => true,
+    enableAssetMap,
   }) {
     this._opts = {
       activity: activity || defaultActivity,
@@ -60,8 +61,9 @@ class DependencyGraph {
       extensions: extensions || ['js', 'json'],
       mocksPattern,
       extractRequires,
-      shouldThrowOnUnresolvedErrors,
       transformCode,
+      shouldThrowOnUnresolvedErrors,
+      enableAssetMap: enableAssetMap || true,
     };
     this._cache = cache;
     this._helpers = new DependencyGraphHelpers(this._opts);
@@ -121,25 +123,33 @@ class DependencyGraph {
       ignoreFilePath: this._opts.ignoreFilePath,
       assetExts: this._opts.assetExts,
       activity: this._opts.activity,
+      enabled: this._opts.enableAssetMap,
     });
 
     this._loading = Promise.all([
       this._fastfs.build()
         .then(() => {
           const hasteActivity = activity.startEvent('Building Haste Map');
-          return this._hasteMap.build().then(() => activity.endEvent(hasteActivity));
+          return this._hasteMap.build().then(map => {
+            activity.endEvent(hasteActivity);
+            return map;
+          });
         }),
       this._deprecatedAssetMap.build(),
-    ]).then(() =>
-      activity.endEvent(depGraphActivity)
-    ).catch(err => {
-      const error = new Error(
-        `Failed to build DependencyGraph: ${err.message}`
-      );
-      error.type = ERROR_BUILDING_DEP_GRAPH;
-      error.stack = err.stack;
-      throw error;
-    });
+    ]).then(
+      response => {
+        activity.endEvent(depGraphActivity);
+        return response[0]; // Return the haste map
+      },
+      err => {
+        const error = new Error(
+          `Failed to build DependencyGraph: ${err.message}`
+        );
+        error.type = ERROR_BUILDING_DEP_GRAPH;
+        error.stack = err.stack;
+        throw error;
+      }
+    );
 
     return this._loading;
   }
diff --git a/packager/react-packager/src/DependencyResolver/FileWatcher/__mocks__/sane.js b/packager/react-packager/src/DependencyResolver/FileWatcher/__mocks__/sane.js
index 2a36bb39dc3b..f59fa9104eb2 100644
--- a/packager/react-packager/src/DependencyResolver/FileWatcher/__mocks__/sane.js
+++ b/packager/react-packager/src/DependencyResolver/FileWatcher/__mocks__/sane.js
@@ -10,4 +10,5 @@
 
 module.exports = {
   WatchmanWatcher: jest.genMockFromModule('sane/src/watchman_watcher'),
+  NodeWatcher: jest.genMockFromModule('sane/src/node_watcher'),
 };
diff --git a/packager/react-packager/src/DependencyResolver/FileWatcher/__tests__/FileWatcher-test.js b/packager/react-packager/src/DependencyResolver/FileWatcher/__tests__/FileWatcher-test.js
index b0d2fd090bb7..650e510090ab 100644
--- a/packager/react-packager/src/DependencyResolver/FileWatcher/__tests__/FileWatcher-test.js
+++ b/packager/react-packager/src/DependencyResolver/FileWatcher/__tests__/FileWatcher-test.js
@@ -13,23 +13,27 @@ jest
   .dontMock('events')
   .dontMock('../')
   .setMock('child_process', {
-    exec: function(cmd, cb) {
-      cb(null, '/usr/bin/watchman');
-    },
+    exec: (cmd, cb) => cb(null, '/usr/bin/watchman'),
   });
 
-var sane = require('sane');
+const sane = require('sane');
 
-describe('FileWatcher', function() {
-  var Watcher;
-  var FileWatcher;
-  var config;
+describe('FileWatcher', () => {
+  let WatchmanWatcher;
+  let NodeWatcher;
+  let FileWatcher;
+  let config;
+
+  beforeEach(() => {
+    WatchmanWatcher = sane.WatchmanWatcher;
+    WatchmanWatcher.prototype.once.mockImplementation(
+      (type, callback) => callback()
+    );
+    NodeWatcher = sane.NodeWatcher;
+    NodeWatcher.prototype.once.mockImplementation(
+      (type, callback) => callback()
+    );
 
-  beforeEach(function() {
-    Watcher = sane.WatchmanWatcher;
-    Watcher.prototype.once.mockImplementation(function(type, callback) {
-      callback();
-    });
     FileWatcher = require('../');
 
     config = [{
@@ -41,38 +45,45 @@ describe('FileWatcher', function() {
     }];
   });
 
-  pit('it should get the watcher instance when ready', function() {
-    var fileWatcher = new FileWatcher(config);
-    return fileWatcher.getWatchers().then(function(watchers) {
-      watchers.forEach(function(watcher) {
-        expect(watcher instanceof Watcher).toBe(true);
+  pit('gets the watcher instance when ready', () => {
+    const fileWatcher = new FileWatcher(config, {useWatchman: true});
+    return fileWatcher.getWatchers().then(watchers => {
+      watchers.forEach(watcher => {
+        expect(watcher instanceof WatchmanWatcher).toBe(true);
       });
     });
   });
 
-  pit('should emit events', function() {
-    var cb;
-    Watcher.prototype.on.mockImplementation(function(type, callback) {
+  pit('gets the node watcher if watchman is disabled', () => {
+    const fileWatcher = new FileWatcher(config, {useWatchman: false});
+    return fileWatcher.getWatchers().then(watchers => {
+      watchers.forEach(watcher => {
+        expect(watcher instanceof NodeWatcher).toBe(true);
+      });
+    });
+  });
+
+  pit('emits events', () => {
+    let cb;
+    WatchmanWatcher.prototype.on.mockImplementation((type, callback) => {
       cb = callback;
     });
-    var fileWatcher = new FileWatcher(config);
-    var handler = jest.genMockFn();
+    const fileWatcher = new FileWatcher(config, {useWatchman: true});
+    const handler = jest.genMockFn();
     fileWatcher.on('all', handler);
-    return fileWatcher.getWatchers().then(function() {
+    return fileWatcher.getWatchers().then(watchers => {
       cb(1, 2, 3, 4);
       jest.runAllTimers();
       expect(handler.mock.calls[0]).toEqual([1, 2, 3, 4]);
     });
   });
 
-  pit('it should end the watcher', function() {
-    var fileWatcher = new FileWatcher(config);
-    Watcher.prototype.close.mockImplementation(function(callback) {
-      callback();
-    });
+  pit('ends the watcher', () => {
+    const fileWatcher = new FileWatcher(config, {useWatchman: true});
+    WatchmanWatcher.prototype.close.mockImplementation(callback => callback());
 
-    return fileWatcher.end().then(function() {
-      expect(Watcher.prototype.close).toBeCalled();
+    return fileWatcher.end().then(() => {
+      expect(WatchmanWatcher.prototype.close).toBeCalled();
     });
   });
 });
diff --git a/packager/react-packager/src/DependencyResolver/FileWatcher/index.js b/packager/react-packager/src/DependencyResolver/FileWatcher/index.js
index d75e02119c80..ab548366bcb7 100644
--- a/packager/react-packager/src/DependencyResolver/FileWatcher/index.js
+++ b/packager/react-packager/src/DependencyResolver/FileWatcher/index.js
@@ -30,17 +30,18 @@ let inited = false;
 
 class FileWatcher extends EventEmitter {
 
-  constructor(rootConfigs) {
+  constructor(rootConfigs, options) {
     if (inited) {
       throw new Error('FileWatcher can only be instantiated once');
     }
     inited = true;
 
     super();
+    this._useWatchman = options.useWatchman;
     this._watcherByRoot = Object.create(null);
 
     this._loading = Promise.all(
-      rootConfigs.map(createWatcher)
+      rootConfigs.map(rootConfig => this._createWatcher(rootConfig))
     ).then(watchers => {
       watchers.forEach((watcher, i) => {
         this._watcherByRoot[rootConfigs[i].dir] = watcher;
@@ -65,9 +66,9 @@ class FileWatcher extends EventEmitter {
   }
 
   isWatchman() {
-    return detectingWatcherClass.then(
+    return this._useWatchman ? detectingWatcherClass.then(
       Watcher => Watcher === sane.WatchmanWatcher
-    );
+    ) : Promise.resolve(false);
   }
 
   end() {
@@ -79,6 +80,30 @@ class FileWatcher extends EventEmitter {
     );
   }
 
+  _createWatcher(rootConfig) {
+    return detectingWatcherClass.then(Watcher => {
+      if (!this._useWatchman) {
+        Watcher = sane.NodeWatcher;
+      }
+      const watcher = new Watcher(rootConfig.dir, {
+        glob: rootConfig.globs,
+        dot: false,
+      });
+
+      return new Promise((resolve, reject) => {
+        const rejectTimeout = setTimeout(
+          () => reject(new Error(timeoutMessage(Watcher))),
+          MAX_WAIT_TIME
+        );
+
+        watcher.once('ready', () => {
+          clearTimeout(rejectTimeout);
+          resolve(watcher);
+        });
+      });
+    });
+  }
+
   static createDummyWatcher() {
     return Object.assign(new EventEmitter(), {
       isWatchman: () => Promise.resolve(false),
@@ -87,26 +112,6 @@ class FileWatcher extends EventEmitter {
   }
 }
 
-function createWatcher(rootConfig) {
-  return detectingWatcherClass.then(function(Watcher) {
-    const watcher = new Watcher(rootConfig.dir, {
-      glob: rootConfig.globs,
-      dot: false,
-    });
-
-    return new Promise(function(resolve, reject) {
-      const rejectTimeout = setTimeout(function() {
-        reject(new Error(timeoutMessage(Watcher)));
-      }, MAX_WAIT_TIME);
-
-      watcher.once('ready', function() {
-        clearTimeout(rejectTimeout);
-        resolve(watcher);
-      });
-    });
-  });
-}
-
 function timeoutMessage(Watcher) {
   const lines = [
     'Watcher took too long to load (' + Watcher.name + ')',
diff --git a/packager/react-packager/src/DependencyResolver/Module.js b/packager/react-packager/src/DependencyResolver/Module.js
index 6b68a620e4dc..6849c9220aa8 100644
--- a/packager/react-packager/src/DependencyResolver/Module.js
+++ b/packager/react-packager/src/DependencyResolver/Module.js
@@ -12,7 +12,7 @@ const crypto = require('crypto');
 const docblock = require('./DependencyGraph/docblock');
 const isAbsolutePath = require('absolute-path');
 const jsonStableStringify = require('json-stable-stringify');
-const path = require('path');
+const path = require('fast-path');
 const extractRequires = require('./lib/extractRequires');
 
 class Module {
@@ -30,7 +30,7 @@ class Module {
       throw new Error('Expected file to be absolute path but got ' + file);
     }
 
-    this.path = path.resolve(file);
+    this.path = file;
     this.type = 'Module';
 
     this._fastfs = fastfs;
@@ -132,7 +132,7 @@ class Module {
         const fileContentPromise = this._fastfs.readFile(this.path);
         return Promise.all([
           fileContentPromise,
-          this._readDocBlock(fileContentPromise)
+          this._readDocBlock(fileContentPromise),
         ]).then(([code, {id, moduleDocBlock}]) => {
           // Ignore requires in JSON files or generated code. An example of this
           // is prebuilt files like the SourceMap library.
@@ -151,7 +151,7 @@ class Module {
               return {id, code, dependencies, map};
             });
           }
-        })
+        });
       }
     );
   }
diff --git a/packager/react-packager/src/DependencyResolver/ModuleCache.js b/packager/react-packager/src/DependencyResolver/ModuleCache.js
index 3fcfb173ad97..11c56919c9a6 100644
--- a/packager/react-packager/src/DependencyResolver/ModuleCache.js
+++ b/packager/react-packager/src/DependencyResolver/ModuleCache.js
@@ -3,7 +3,7 @@
 const AssetModule = require('./AssetModule');
 const Package = require('./Package');
 const Module = require('./Module');
-const path = require('path');
+const path = require('fast-path');
 
 class ModuleCache {
 
@@ -26,7 +26,6 @@ class ModuleCache {
   }
 
   getModule(filePath) {
-    filePath = path.resolve(filePath);
     if (!this._moduleCache[filePath]) {
       this._moduleCache[filePath] = new Module({
         file: filePath,
@@ -46,7 +45,6 @@ class ModuleCache {
   }
 
   getAssetModule(filePath) {
-    filePath = path.resolve(filePath);
     if (!this._moduleCache[filePath]) {
       this._moduleCache[filePath] = new AssetModule({
         file: filePath,
@@ -59,7 +57,6 @@ class ModuleCache {
   }
 
   getPackage(filePath) {
-    filePath = path.resolve(filePath);
     if (!this._packageCache[filePath]) {
       this._packageCache[filePath] = new Package({
         file: filePath,
diff --git a/packager/react-packager/src/DependencyResolver/Package.js b/packager/react-packager/src/DependencyResolver/Package.js
index e88b0640ccbc..0d28b3b00823 100644
--- a/packager/react-packager/src/DependencyResolver/Package.js
+++ b/packager/react-packager/src/DependencyResolver/Package.js
@@ -1,12 +1,12 @@
 'use strict';
 
 const isAbsolutePath = require('absolute-path');
-const path = require('path');
+const path = require('fast-path');
 
 class Package {
 
   constructor({ file, fastfs, cache }) {
-    this.path = path.resolve(file);
+    this.path = file;
     this.root = path.dirname(this.path);
     this._fastfs = fastfs;
     this.type = 'Package';
diff --git a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js b/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
index bb4fa75eaf15..ee2623a3abda 100644
--- a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
+++ b/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
@@ -202,9 +202,9 @@ describe('Module', () => {
     let transformCode;
     const fileContents = 'arbitrary(code);';
     const exampleCode = `
-      require('a');
-      arbitrary.code('b');
-      require('c');`;
+      ${'require'}('a');
+      ${'System.import'}('b');
+      ${'require'}('c');`;
 
     beforeEach(function() {
       transformCode = jest.genMockFn();
@@ -281,7 +281,7 @@ describe('Module', () => {
       const callsEqual = ([path1, key1], [path2, key2]) => {
         expect(path1).toEqual(path2);
         expect(key1).toEqual(key2);
-      }
+      };
 
       it('gets dependencies from the cache with the same cache key for the same transform options', () => {
         const options = {some: 'options'};
@@ -293,7 +293,6 @@ describe('Module', () => {
       });
 
       it('gets dependencies from the cache with the same cache key for the equivalent transform options', () => {
-        const options = {some: 'options'};
         module.getDependencies({a: 'b', c: 'd'}); // first call
         module.getDependencies({c: 'd', a: 'b'}); // second call
 
@@ -318,7 +317,6 @@ describe('Module', () => {
       });
 
       it('gets code from the cache with the same cache key for the equivalent transform options', () => {
-        const options = {some: 'options'};
         module.getCode({a: 'b', c: 'd'}); // first call
         module.getCode({c: 'd', a: 'b'}); // second call
 
diff --git a/packager/react-packager/src/DependencyResolver/crawlers/node.js b/packager/react-packager/src/DependencyResolver/crawlers/node.js
index 88e32d8843c2..871bbc1d78f9 100644
--- a/packager/react-packager/src/DependencyResolver/crawlers/node.js
+++ b/packager/react-packager/src/DependencyResolver/crawlers/node.js
@@ -3,7 +3,7 @@
 const Promise = require('promise');
 const debug = require('debug')('ReactNativePackager:DependencyGraph');
 const fs = require('graceful-fs');
-const path = require('path');
+const path = require('fast-path');
 
 const readDir = Promise.denodeify(fs.readdir);
 const stat = Promise.denodeify(fs.stat);
diff --git a/packager/react-packager/src/DependencyResolver/crawlers/watchman.js b/packager/react-packager/src/DependencyResolver/crawlers/watchman.js
index 1871e3ead8b5..6e3d6a6c9421 100644
--- a/packager/react-packager/src/DependencyResolver/crawlers/watchman.js
+++ b/packager/react-packager/src/DependencyResolver/crawlers/watchman.js
@@ -1,7 +1,7 @@
 'use strict';
 
 const Promise = require('promise');
-const path = require('path');
+const path = require('fast-path');
 
 function watchmanRecReadDir(roots, {ignore, fileWatcher, exts}) {
   const files = [];
@@ -38,20 +38,16 @@ function watchmanRecReadDir(roots, {ignore, fileWatcher, exts}) {
 
           const cmd = Promise.denodeify(watcher.client.command.bind(watcher.client));
           return cmd(['query', watchedRoot, {
-            'suffix': exts,
-            'expression': ['allof', ['type', 'f'], 'exists', dirExpr],
-            'fields': ['name'],
+            suffix: exts,
+            expression: ['allof', ['type', 'f'], 'exists', dirExpr],
+            fields: ['name'],
           }]).then(resp => {
             if ('warning' in resp) {
               console.warn('watchman warning: ', resp.warning);
             }
 
             resp.files.forEach(filePath => {
-              filePath = path.join(
-                watchedRoot,
-                filePath
-              );
-
+              filePath = watchedRoot + path.sep + filePath;
               if (!ignore(filePath)) {
                 files.push(filePath);
               }
@@ -64,7 +60,7 @@ function watchmanRecReadDir(roots, {ignore, fileWatcher, exts}) {
 }
 
 function isDescendant(root, child) {
-  return path.relative(root, child).indexOf('..') !== 0;
+  return child.startsWith(root);
 }
 
 module.exports = watchmanRecReadDir;
diff --git a/packager/react-packager/src/DependencyResolver/fastfs.js b/packager/react-packager/src/DependencyResolver/fastfs.js
index 325604ffe08f..af2010086eff 100644
--- a/packager/react-packager/src/DependencyResolver/fastfs.js
+++ b/packager/react-packager/src/DependencyResolver/fastfs.js
@@ -12,7 +12,7 @@ const Promise = require('promise');
 const {EventEmitter} = require('events');
 
 const fs = require('graceful-fs');
-const path = require('path');
+const path = require('fast-path');
 
 // workaround for https://github.com/isaacs/node-graceful-fs/issues/56
 // fs.close is patched, whereas graceful-fs.close is not.
@@ -21,8 +21,6 @@ const fsClose = require('fs').close;
 const readFile = Promise.denodeify(fs.readFile);
 const stat = Promise.denodeify(fs.stat);
 
-const hasOwn = Object.prototype.hasOwnProperty;
-
 const NOT_FOUND_IN_ROOTS = 'NotFoundInRootsError';
 
 class Fastfs extends EventEmitter {
@@ -31,17 +29,20 @@ class Fastfs extends EventEmitter {
     this._name = name;
     this._fileWatcher = fileWatcher;
     this._ignore = ignore;
-    this._roots = roots.map(root => new File(root, { isDir: true }));
+    this._roots = roots.map(root => {
+      // If the path ends in a separator ("/"), remove it to make string
+      // operations on paths safer.
+      if (root.endsWith(path.sep)) {
+        root = root.substr(0, root.length - 1);
+      }
+      return new File(root, true);
+    });
     this._fastPaths = Object.create(null);
     this._crawling = crawling;
     this._activity = activity;
   }
 
   build() {
-    const rootsPattern = new RegExp(
-      '^(' + this._roots.map(root => escapeRegExp(root.path)).join('|') + ')'
-    );
-
     return this._crawling.then(files => {
       let fastfsActivity;
       const activity = this._activity;
@@ -49,18 +50,16 @@ class Fastfs extends EventEmitter {
         fastfsActivity = activity.startEvent('Building in-memory fs for ' + this._name);
       }
       files.forEach(filePath => {
-        if (filePath.match(rootsPattern)) {
-          const newFile = new File(filePath, { isDir: false });
-          const parent = this._fastPaths[path.dirname(filePath)];
+        const root = this._getRoot(filePath);
+        if (root) {
+          const newFile = new File(filePath, false);
+          const dirname = filePath.substr(0, filePath.lastIndexOf(path.sep));
+          const parent = this._fastPaths[dirname];
+          this._fastPaths[filePath] = newFile;
           if (parent) {
-            parent.addChild(newFile);
+            parent.addChild(newFile, this._fastPaths);
           } else {
-            this._add(newFile);
-            for (let file = newFile; file; file = file.parent) {
-              if (!this._fastPaths[file.path]) {
-                this._fastPaths[file.path] = file;
-              }
-            }
+            root.addChild(newFile, this._fastPaths);
           }
         }
       });
@@ -72,42 +71,24 @@ class Fastfs extends EventEmitter {
   }
 
   stat(filePath) {
-    return Promise.resolve().then(() => {
-      const file = this._getFile(filePath);
-      return file.stat();
-    });
+    return Promise.resolve().then(() => this._getFile(filePath).stat());
   }
 
   getAllFiles() {
-    // one-level-deep flatten of files
-    return [].concat(...this._roots.map(root => root.getFiles()));
-  }
-
-  findFilesByExt(ext, { ignore } = {}) {
-    return this.findFilesByExts([ext], {ignore});
+    return Object.keys(this._fastPaths)
+      .filter(filePath => !this._fastPaths[filePath].isDir);
   }
 
   findFilesByExts(exts, { ignore } = {}) {
     return this.getAllFiles()
-      .filter(file => (
-        exts.indexOf(file.ext()) !== -1 && (!ignore || !ignore(file.path))
-      ))
-      .map(file => file.path);
-  }
-
-  findFilesByName(name, { ignore } = {}) {
-    return this.getAllFiles()
-      .filter(
-        file => path.basename(file.path) === name &&
-          (!ignore || !ignore(file.path))
-      )
-      .map(file => file.path);
+      .filter(filePath => (
+        exts.indexOf(path.extname(filePath).substr(1)) !== -1 &&
+        (!ignore || !ignore(filePath))
+      ));
   }
 
   matchFilesByPattern(pattern) {
-    return this.getAllFiles()
-      .filter(file => file.path.match(pattern))
-      .map(file => file.path);
+    return this.getAllFiles().filter(file => file.match(pattern));
   }
 
   readFile(filePath) {
@@ -198,25 +179,25 @@ class Fastfs extends EventEmitter {
 
   _getFile(filePath) {
     filePath = path.normalize(filePath);
-    if (!hasOwn.call(this._fastPaths, filePath)) {
-      this._fastPaths[filePath] = this._getAndAssertRoot(filePath).getFileFromPath(filePath);
+    if (!this._fastPaths[filePath]) {
+      const file = this._getAndAssertRoot(filePath).getFileFromPath(filePath);
+      if (file) {
+        this._fastPaths[filePath] = file;
+      }
     }
 
     return this._fastPaths[filePath];
   }
 
-  _add(file) {
-    this._getAndAssertRoot(file.path).addChild(file);
-  }
-
-  _processFileChange(type, filePath, root, fstat) {
-    const absPath = path.join(root, filePath);
+  _processFileChange(type, filePath, rootPath, fstat) {
+    const absPath = path.join(rootPath, filePath);
     if (this._ignore(absPath) || (fstat && fstat.isDirectory())) {
       return;
     }
 
     // Make sure this event belongs to one of our roots.
-    if (!this._getRoot(absPath)) {
+    const root = this._getRoot(absPath);
+    if (!root) {
       return;
     }
 
@@ -230,20 +211,19 @@ class Fastfs extends EventEmitter {
     delete this._fastPaths[path.normalize(absPath)];
 
     if (type !== 'delete') {
-      this._add(new File(absPath, { isDir: false }));
+      const file = new File(absPath, false);
+      root.addChild(file, this._fastPaths);
     }
 
-    this.emit('change', type, filePath, root, fstat);
+    this.emit('change', type, filePath, rootPath, fstat);
   }
 }
 
 class File {
-  constructor(filePath, { isDir }) {
+  constructor(filePath, isDir) {
     this.path = filePath;
-    this.isDir = Boolean(isDir);
-    if (this.isDir) {
-      this.children = Object.create(null);
-    }
+    this.isDir = isDir;
+    this.children = this.isDir ? Object.create(null) : null;
   }
 
   read() {
@@ -270,29 +250,24 @@ class File {
     return this._stat;
   }
 
-  addChild(file) {
-    const parts = path.relative(this.path, file.path).split(path.sep);
-
-    if (parts.length === 0) {
-      return;
-    }
-
+  addChild(file, fileMap) {
+    const parts = file.path.substr(this.path.length + 1).split(path.sep);
     if (parts.length === 1) {
       this.children[parts[0]] = file;
       file.parent = this;
     } else if (this.children[parts[0]]) {
-      this.children[parts[0]].addChild(file);
+      this.children[parts[0]].addChild(file, fileMap);
     } else {
-      const dir = new File(path.join(this.path, parts[0]), { isDir: true });
+      const dir = new File(this.path + path.sep + parts[0], true);
       dir.parent = this;
       this.children[parts[0]] = dir;
-      dir.addChild(file);
+      fileMap[dir.path] = dir;
+      dir.addChild(file, fileMap);
     }
   }
 
   getFileFromPath(filePath) {
-    const parts = path.relative(this.path, filePath)
-            .split(path.sep);
+    const parts = path.relative(this.path, filePath).split(path.sep);
 
     /*eslint consistent-this:0*/
     let file = this;
@@ -313,21 +288,8 @@ class File {
     return file;
   }
 
-  getFiles() {
-    let files = [];
-    Object.keys(this.children).forEach(key => {
-      const file = this.children[key];
-      if (file.isDir) {
-        files = files.concat(file.getFiles());
-      } else {
-        files.push(file);
-      }
-    });
-    return files;
-  }
-
   ext() {
-    return path.extname(this.path).replace(/^\./, '');
+    return path.extname(this.path).substr(1);
   }
 
   remove() {
@@ -392,11 +354,7 @@ function makeReadCallback(fd, predicate, callback) {
 }
 
 function isDescendant(root, child) {
-  return path.relative(root, child).indexOf('..') !== 0;
-}
-
-function escapeRegExp(str) {
-  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
+  return child.startsWith(root);
 }
 
 module.exports = Fastfs;
diff --git a/packager/react-packager/src/DependencyResolver/lib/extractRequires.js b/packager/react-packager/src/DependencyResolver/lib/extractRequires.js
index 5dbf63cc6b4b..547ffbbb3165 100644
--- a/packager/react-packager/src/DependencyResolver/lib/extractRequires.js
+++ b/packager/react-packager/src/DependencyResolver/lib/extractRequires.js
@@ -39,7 +39,7 @@ function extractRequires(code) {
     .replace(replacePatterns.REQUIRE_RE, (match, pre, quot, dep, post) => {
       deps.sync.push(dep);
       return match;
-    })
+    });
 
   return {code, deps};
 }
diff --git a/packager/react-packager/src/DependencyResolver/lib/getAssetDataFromName.js b/packager/react-packager/src/DependencyResolver/lib/getAssetDataFromName.js
index 33fa13cea18d..a616d1084828 100644
--- a/packager/react-packager/src/DependencyResolver/lib/getAssetDataFromName.js
+++ b/packager/react-packager/src/DependencyResolver/lib/getAssetDataFromName.js
@@ -8,7 +8,7 @@
  */
 'use strict';
 
-const path = require('path');
+const path = require('fast-path');
 const getPlatformExtension = require('./getPlatformExtension');
 
 function getAssetDataFromName(filename) {
diff --git a/packager/react-packager/src/DependencyResolver/lib/getPlatformExtension.js b/packager/react-packager/src/DependencyResolver/lib/getPlatformExtension.js
index cfcb65016452..721470d106ae 100644
--- a/packager/react-packager/src/DependencyResolver/lib/getPlatformExtension.js
+++ b/packager/react-packager/src/DependencyResolver/lib/getPlatformExtension.js
@@ -8,19 +8,21 @@
  */
 'use strict';
 
-const SUPPORTED_PLATFORM_EXTS = ['android', 'ios', 'web'];
-
-const re = new RegExp(
-  '[^\\.]+\\.(' + SUPPORTED_PLATFORM_EXTS.join('|') + ')\\.\\w+$'
-);
+const SUPPORTED_PLATFORM_EXTS = {
+  android: true,
+  ios: true,
+  web: true,
+};
 
 // Extract platform extension: index.ios.js -> ios
 function getPlatformExtension(file) {
-  const match = file.match(re);
-  if (match && match[1]) {
-    return match[1];
+  const last = file.lastIndexOf('.');
+  const secondToLast = file.lastIndexOf('.', last - 1);
+  if (secondToLast === -1) {
+    return null;
   }
-  return null;
+  const platform = file.substring(secondToLast + 1, last);
+  return SUPPORTED_PLATFORM_EXTS[platform] ? platform : null;
 }
 
 module.exports = getPlatformExtension;
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index 0146e7d6695e..aa32175aaf17 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -182,7 +182,7 @@ class Server {
 
     this._fileWatcher = options.nonPersistent
       ? FileWatcher.createDummyWatcher()
-      : new FileWatcher(watchRootConfigs);
+      : new FileWatcher(watchRootConfigs, {useWatchman: true});
 
     this._assetServer = new AssetServer({
       projectRoots: opts.projectRoots,

From edbe6a2b248fa552da6ab4a9d4e274766a10ad04 Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Tue, 16 Feb 2016 03:04:16 -0800
Subject: [PATCH 1179/1411] Add imperative API to StatusBar

Reviewed By: svcscm

Differential Revision: D2938743

fb-gh-sync-id: 30af304efd5b089854d9a8defc1b77fd8e817d13
shipit-source-id: 30af304efd5b089854d9a8defc1b77fd8e817d13
---
 Examples/UIExplorer/StatusBarExample.js       | 131 ++++++++++++++++--
 Libraries/Components/StatusBar/StatusBar.js   |  88 ++++++++++--
 .../Components/StatusBar/StatusBarIOS.ios.js  |  32 ++---
 3 files changed, 212 insertions(+), 39 deletions(-)

diff --git a/Examples/UIExplorer/StatusBarExample.js b/Examples/UIExplorer/StatusBarExample.js
index 094148c4d71d..e33dbd71a98b 100644
--- a/Examples/UIExplorer/StatusBarExample.js
+++ b/Examples/UIExplorer/StatusBarExample.js
@@ -57,12 +57,16 @@ const showHideTransitions = [
   'slide',
 ];
 
+function getValue(values: Array<any>, index: number): any {
+  return values[index % values.length];
+}
+
 const StatusBarExample = React.createClass({
   getInitialState(): State {
     return {
       animated: true,
-      backgroundColor: this._getValue(colors, 0),
-      showHideTransition: this._getValue(showHideTransitions, 0),
+      backgroundColor: getValue(colors, 0),
+      showHideTransition: getValue(showHideTransitions, 0),
     };
   },
 
@@ -70,10 +74,6 @@ const StatusBarExample = React.createClass({
   _barStyleIndex: 0,
   _showHideTransitionIndex: 0,
 
-  _getValue(values: Array<any>, index: number): any {
-    return values[index % values.length];
-  },
-
   render() {
     return (
       <View>
@@ -110,10 +110,10 @@ const StatusBarExample = React.createClass({
             style={styles.wrapper}
             onPress={() => {
               this._barStyleIndex++;
-              this.setState({barStyle: this._getValue(barStyles, this._barStyleIndex)});
+              this.setState({barStyle: getValue(barStyles, this._barStyleIndex)});
             }}>
             <View style={styles.button}>
-              <Text>style: '{this._getValue(barStyles, this._barStyleIndex)}'</Text>
+              <Text>style: '{getValue(barStyles, this._barStyleIndex)}'</Text>
             </View>
           </TouchableHighlight>
         </View>
@@ -138,13 +138,13 @@ const StatusBarExample = React.createClass({
               this._showHideTransitionIndex++;
               this.setState({
                 showHideTransition:
-                this._getValue(showHideTransitions, this._showHideTransitionIndex),
+                getValue(showHideTransitions, this._showHideTransitionIndex),
               });
             }}>
             <View style={styles.button}>
               <Text>
                 showHideTransition:
-                '{this._getValue(showHideTransitions, this._showHideTransitionIndex)}'
+                '{getValue(showHideTransitions, this._showHideTransitionIndex)}'
               </Text>
             </View>
           </TouchableHighlight>
@@ -155,10 +155,10 @@ const StatusBarExample = React.createClass({
             style={styles.wrapper}
             onPress={() => {
               this._colorIndex++;
-              this.setState({backgroundColor: this._getValue(colors, this._colorIndex)});
+              this.setState({backgroundColor: getValue(colors, this._colorIndex)});
             }}>
             <View style={styles.button}>
-              <Text>backgroundColor: '{this._getValue(colors, this._colorIndex)}'</Text>
+              <Text>backgroundColor: '{getValue(colors, this._colorIndex)}'</Text>
             </View>
           </TouchableHighlight>
         </View>
@@ -181,11 +181,116 @@ const StatusBarExample = React.createClass({
   },
 });
 
+const StatusBarStaticExample = React.createClass({
+  _colorIndex: 0,
+  _barStyleIndex: 0,
+  _showHideTransitionIndex: 0,
+
+  getInitialState() {
+    return {
+      backgroundColor: getValue(colors, 0),
+      barStyle: getValue(barStyles, 0),
+      hidden: false,
+      networkActivityIndicatorVisible: false,
+      translucent: false,
+    };
+  },
+
+  render() {
+    return (
+      <View>
+        <View>
+          <TouchableHighlight
+            style={styles.wrapper}
+            onPress={() => {
+              const hidden = !this.state.hidden;
+              StatusBar.setHidden(hidden, 'slide');
+              this.setState({hidden});
+            }}>
+            <View style={styles.button}>
+              <Text>hidden: {this.state.hidden ? 'true' : 'false'}</Text>
+            </View>
+          </TouchableHighlight>
+        </View>
+        <Text style={styles.title}>iOS</Text>
+        <View>
+          <TouchableHighlight
+            style={styles.wrapper}
+            onPress={() => {
+              this._barStyleIndex++;
+              const barStyle = getValue(barStyles, this._barStyleIndex);
+              StatusBar.setBarStyle(barStyle, true);
+              this.setState({barStyle});
+            }}>
+            <View style={styles.button}>
+              <Text>style: '{getValue(barStyles, this._barStyleIndex)}'</Text>
+            </View>
+          </TouchableHighlight>
+        </View>
+        <View>
+          <TouchableHighlight
+            style={styles.wrapper}
+            onPress={() => {
+              const networkActivityIndicatorVisible = !this.state.networkActivityIndicatorVisible;
+              StatusBar.setNetworkActivityIndicatorVisible(networkActivityIndicatorVisible);
+              this.setState({networkActivityIndicatorVisible});
+            }}>
+            <View style={styles.button}>
+              <Text>
+                networkActivityIndicatorVisible:
+                {this.state.networkActivityIndicatorVisible ? 'true' : 'false'}
+              </Text>
+            </View>
+          </TouchableHighlight>
+        </View>
+        <Text style={styles.title}>Android</Text>
+        <View>
+          <TouchableHighlight
+            style={styles.wrapper}
+            onPress={() => {
+              this._colorIndex++;
+              const backgroundColor = getValue(colors, this._colorIndex);
+              StatusBar.setBackgroundColor(backgroundColor, true);
+              this.setState({backgroundColor});
+            }}>
+            <View style={styles.button}>
+              <Text>backgroundColor: '{getValue(colors, this._colorIndex)}'</Text>
+            </View>
+          </TouchableHighlight>
+        </View>
+        <View>
+          <TouchableHighlight
+            style={styles.wrapper}
+            onPress={() => {
+              const translucent = !this.state.translucent;
+              const backgroundColor = !this.state.translucent ? 'rgba(0, 0, 0, 0.4)' : 'black';
+              StatusBar.setTranslucent(translucent);
+              StatusBar.setBackgroundColor(backgroundColor, true);
+              this.setState({
+                translucent,
+                backgroundColor,
+              });
+            }}>
+            <View style={styles.button}>
+              <Text>translucent: {this.state.translucent ? 'true' : 'false'}</Text>
+            </View>
+          </TouchableHighlight>
+        </View>
+      </View>
+    );
+  },
+});
+
 exports.examples = [{
-  title: 'Status Bar',
+  title: 'StatusBar',
   render() {
     return <StatusBarExample />;
   },
+}, {
+  title: 'StatusBar static API',
+  render() {
+    return <StatusBarStaticExample />;
+  },
 }];
 
 var styles = StyleSheet.create({
diff --git a/Libraries/Components/StatusBar/StatusBar.js b/Libraries/Components/StatusBar/StatusBar.js
index b6571146af68..159577b585f1 100644
--- a/Libraries/Components/StatusBar/StatusBar.js
+++ b/Libraries/Components/StatusBar/StatusBar.js
@@ -19,6 +19,17 @@ const processColor = require('processColor');
 
 const StatusBarManager = require('NativeModules').StatusBarManager;
 
+export type StatusBarStyle = $Enum<{
+  'default': string,
+  'light-content': string,
+}>;
+
+export type StatusBarAnimation = $Enum<{
+  'none': string,
+  'fade': string,
+  'slide': string,
+}>;
+
 type DefaultProps = {
   animated: boolean;
 };
@@ -26,16 +37,10 @@ type DefaultProps = {
 /**
  * Merges the prop stack with the default values.
  */
-function mergePropsStack(propsStack: Array<Object>): Object {
+function mergePropsStack(propsStack: Array<Object>, defaultValues: Object): Object {
   return propsStack.reduce((prev, cur) => {
     return Object.assign(prev, cur);
-  }, {
-    backgroundColor: 'black',
-    barStyle: 'default',
-    translucent: false,
-    hidden: false,
-    networkActivityIndicatorVisible: false,
-  });
+  }, defaultValues);
 }
 
 /**
@@ -64,10 +69,75 @@ function mergePropsStack(propsStack: Array<Object>): Object {
  *    />
  *  </View>
  * ```
+ *
+ * ### Imperative API
+ *
+ * For cases where using a component is not ideal, there is also an imperative
+ * API exposed as static functions on the component. It is however not recommended
+ * to use the static API and the compoment for the same prop because any value
+ * set by the static API will get overriden by the one set by the component in
+ * the next render.
  */
 const StatusBar = React.createClass({
   statics: {
     _propsStack: [],
+    _defaultProps: {
+      backgroundColor: 'black',
+      barStyle: 'default',
+      translucent: false,
+      hidden: false,
+      networkActivityIndicatorVisible: false,
+    },
+
+    // Provide an imperative API as static functions of the component.
+    // See the corresponding prop for more detail.
+    setHidden(hidden: boolean, animation?: StatusBarAnimation) {
+      animation = animation || 'none';
+      StatusBar._defaultProps.hidden = hidden;
+      if (Platform.OS === 'ios') {
+        StatusBarManager.setHidden(hidden, animation);
+      } else if (Platform.OS === 'android') {
+        StatusBarManager.setHidden(hidden);
+      }
+    },
+
+    setBarStyle(style: StatusBarStyle, animated?: boolean) {
+      if (Platform.OS !== 'ios') {
+        console.warn('`setBarStyle` is only available on iOS');
+        return;
+      }
+      animated = animated || false;
+      StatusBar._defaultProps.barStyle = style;
+      StatusBarManager.setStyle(style, animated);
+    },
+
+    setNetworkActivityIndicatorVisible(visible: boolean) {
+      if (Platform.OS !== 'ios') {
+        console.warn('`setNetworkActivityIndicatorVisible` is only available on iOS');
+        return;
+      }
+      StatusBar._defaultProps.networkActivityIndicatorVisible = visible;
+      StatusBarManager.setNetworkActivityIndicatorVisible(visible);
+    },
+
+    setBackgroundColor(color, animated?: boolean) {
+      if (Platform.OS !== 'android') {
+        console.warn('`setBackgroundColor` is only available on Android');
+        return;
+      }
+      animated = animated || false;
+      StatusBar._defaultProps.backgroundColor = color;
+      StatusBarManager.setColor(processColor(color), animated);
+    },
+
+    setTranslucent(translucent: boolean) {
+      if (Platform.OS !== 'android') {
+        console.warn('`setTranslucent` is only available on Android');
+        return;
+      }
+      StatusBar._defaultProps.translucent = translucent;
+      StatusBarManager.setTranslucent(translucent);
+    },
   },
 
   propTypes: {
@@ -156,7 +226,7 @@ const StatusBar = React.createClass({
    * Updates the native status bar with the props from the stack.
    */
   _updatePropsStack() {
-    const mergedProps = mergePropsStack(StatusBar._propsStack);
+    const mergedProps = mergePropsStack(StatusBar._propsStack, StatusBar._defaultProps);
 
     if (Platform.OS === 'ios') {
       if (mergedProps.barStyle !== undefined) {
diff --git a/Libraries/Components/StatusBar/StatusBarIOS.ios.js b/Libraries/Components/StatusBar/StatusBarIOS.ios.js
index 59369ef143dd..a4c0357b0cf0 100644
--- a/Libraries/Components/StatusBar/StatusBarIOS.ios.js
+++ b/Libraries/Components/StatusBar/StatusBarIOS.ios.js
@@ -11,33 +11,31 @@
  */
 'use strict';
 
-var RCTStatusBarManager = require('NativeModules').StatusBarManager;
+const StatusBar = require('StatusBar');
 
-type StatusBarStyle = $Enum<{
-  'default': string,
-  'light-content': string,
-}>;
+import type {StatusBarStyle, StatusBarAnimation} from 'StatusBar';
 
-type StatusBarAnimation = $Enum<{
-  'none': string,
-  'fade': string,
-  'slide': string,
-}>;
-
-var StatusBarIOS = {
+/**
+ * Deprecated. Use `StatusBar` instead.
+ */
+const StatusBarIOS = {
 
   setStyle(style: StatusBarStyle, animated?: boolean) {
-    animated = animated || false;
-    RCTStatusBarManager.setStyle(style, animated);
+    console.warn('`StatusBarIOS.setStyle` is deprecated. Use `StatusBar.setBarStyle` instead.');
+    StatusBar.setBarStyle(style, animated);
   },
 
   setHidden(hidden: boolean, animation?: StatusBarAnimation) {
-    animation = animation || 'none';
-    RCTStatusBarManager.setHidden(hidden, animation);
+    console.warn('`StatusBarIOS.setHidden` is deprecated. Use `StatusBar.setHidden` instead.');
+    StatusBar.setHidden(hidden, animation);
   },
 
   setNetworkActivityIndicatorVisible(visible: boolean) {
-    RCTStatusBarManager.setNetworkActivityIndicatorVisible(visible);
+    console.warn(
+      '`StatusBarIOS.setNetworkActivityIndicatorVisible` is deprecated. ' +
+      'Use `StatusBar.setNetworkActivityIndicatorVisible` instead.'
+    );
+    StatusBar.setNetworkActivityIndicatorVisible(visible);
   },
 };
 

From 8f19f5bef4a86c046fd9dd0ad5501f6bb5bbd6c4 Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Tue, 16 Feb 2016 03:28:05 -0800
Subject: [PATCH 1180/1411] Annotate WebSocket with Flow

Reviewed By: svcscm

Differential Revision: D2938267

fb-gh-sync-id: b67623b79327bb78b5fab2ea492925ed20b17c1a
shipit-source-id: b67623b79327bb78b5fab2ea492925ed20b17c1a
---
 Libraries/WebSocket/WebSocket.js     |  1 +
 Libraries/WebSocket/WebSocketBase.js | 26 ++++++++++++++++----------
 2 files changed, 17 insertions(+), 10 deletions(-)

diff --git a/Libraries/WebSocket/WebSocket.js b/Libraries/WebSocket/WebSocket.js
index b9eb255cc76a..3814b4e555ce 100644
--- a/Libraries/WebSocket/WebSocket.js
+++ b/Libraries/WebSocket/WebSocket.js
@@ -7,6 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule WebSocket
+ * @flow
  */
 'use strict';
 
diff --git a/Libraries/WebSocket/WebSocketBase.js b/Libraries/WebSocket/WebSocketBase.js
index 931b297494c4..843ae403540c 100644
--- a/Libraries/WebSocket/WebSocketBase.js
+++ b/Libraries/WebSocket/WebSocketBase.js
@@ -7,11 +7,17 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule WebSocketBase
+ * @flow
  */
 'use strict';
 
 var EventTarget = require('event-target-shim');
 
+const CONNECTING = 0;
+const OPEN = 1;
+const CLOSING = 2;
+const CLOSED = 3;
+
 /**
  * Shared base for platform-specific WebSocket implementations.
  */
@@ -35,10 +41,10 @@ class WebSocketBase extends EventTarget {
 
   constructor(url: string, protocols: ?string | ?Array<string>, options: ?{origin?: string}) {
     super();
-    this.CONNECTING = 0;
-    this.OPEN = 1;
-    this.CLOSING = 2;
-    this.CLOSED = 3;
+    this.CONNECTING = CONNECTING;
+    this.OPEN = OPEN;
+    this.CLOSING = CLOSING;
+    this.CLOSED = CLOSED;
 
     if (typeof protocols === 'string') {
       protocols = [protocols];
@@ -84,7 +90,7 @@ class WebSocketBase extends EventTarget {
     throw new Error('Subclass must define closeConnectionImpl method');
   }
 
-  connectToSocketImpl(): void {
+  connectToSocketImpl(url: string, protocols: ?Array<string>, options: ?{origin?: string}): void {
     throw new Error('Subclass must define connectToSocketImpl method');
   }
 
@@ -92,7 +98,7 @@ class WebSocketBase extends EventTarget {
     throw new Error('Subclass must define cancelConnectionImpl method');
   }
 
-  sendStringImpl(): void {
+  sendStringImpl(message: string): void {
     throw new Error('Subclass must define sendStringImpl method');
   }
 
@@ -101,9 +107,9 @@ class WebSocketBase extends EventTarget {
   }
 }
 
-WebSocketBase.CONNECTING = 0;
-WebSocketBase.OPEN = 1;
-WebSocketBase.CLOSING = 2;
-WebSocketBase.CLOSED = 3;
+WebSocketBase.CONNECTING = CONNECTING;
+WebSocketBase.OPEN = OPEN;
+WebSocketBase.CLOSING = CLOSING;
+WebSocketBase.CLOSED = CLOSED;
 
 module.exports = WebSocketBase;

From 027f26df57e459523c76ded12b1b6aff053d6189 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Tue, 16 Feb 2016 07:01:38 -0800
Subject: [PATCH 1181/1411] Add back apps to showcase, making fbsource and
 GitHub consistent

Reviewed By: mkonicek

Differential Revision:D2939055
Ninja: React Native website

fb-gh-sync-id: da9001a696240af5bb66f95c724ac62282ede4f7
shipit-source-id: da9001a696240af5bb66f95c724ac62282ede4f7
---
 website/src/react-native/showcase.js | 40 +++++++++++++++++++++++++---
 1 file changed, 36 insertions(+), 4 deletions(-)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 5e917f3242d4..af3f1a100e99 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -135,6 +135,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/beetroot/id1016159001?ls=1&mt=8',
     author: 'Alex Duckmanton',
   },
+  {
+    name: 'Bhagavad Gita Lite',
+    icon: 'https://s3-us-west-2.amazonaws.com/bhagavadgitaapp/gita-free.png',
+    link: 'https://itunes.apple.com/us/app/bhagavad-gita-lite/id1071711190?ls=1&mt=8',
+    author: 'Tom Goldenberg & Nick Brown'
+  },
   {
     name: 'Bionic eStore',
     icon: 'http://a5.mzstatic.com/us/r30/Purple7/v4/c1/9a/3f/c19a3f82-ecc3-d60b-f983-04acc203705f/icon175x175.jpeg',
@@ -148,6 +154,12 @@ var apps = [
     linkPlayStore: 'https://play.google.com/store/apps/details?id=com.canddi',
     author: 'CANDDi LTD.',
   },
+  {
+    name: 'CaratLane',
+    icon: 'https://lh3.googleusercontent.com/wEN-Vvpbnw_n89dbXPxWkNnXB7sALKBKvpX_hbzrWbuC4tFi5tVkWHq8k5TAvdbf5UQ=w300-rw',
+    link: 'https://play.google.com/store/apps/details?id=com.caratlane.android&hl=en',
+    author: 'CaratLane',
+  },
   {
     name: 'CBS Sports Franchise Football',
     icon: 'http://a2.mzstatic.com/us/r30/Purple69/v4/7b/0c/a0/7b0ca007-885a-7cfc-9fa2-2ec4394c2ecc/icon175x175.png',
@@ -223,6 +235,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/fast-paper/id1001174614',
     author: 'Liubomyr Mykhalchenko (@liubko)',
   },
+  {
+    name: 'Feline for Product Hunt',
+    icon: 'https://lh3.googleusercontent.com/MCoiCCwUan0dxzqRR_Mrr7kO308roYdI2aTsIpUGYWzUmpJT1-R2_J04weQKFEd3Mg=w300-rw',
+    link: 'https://play.google.com/store/apps/details?id=com.arjunkomath.product_hunt&hl=en',
+    author: 'Arjun Komath',
+  },
   {
     name: 'Foodstand',
     icon: 'http://a3.mzstatic.com/us/r30/Purple69/v4/33/c1/3b/33c13b88-8ec2-23c1-56bb-712ad9938290/icon350x350.jpeg',
@@ -462,7 +480,8 @@ var apps = [
   {
     name: 'ShareHows',
     icon: 'http://a4.mzstatic.com/us/r30/Purple5/v4/78/1c/83/781c8325-a1e1-4afc-f106-a629bcf3c6ef/icon175x175.png',
-    link: 'https://itunes.apple.com/kr/app/sweeohauseu-sesang-ui-modeun/id1060914858?mt=8',
+    linkAppStore: 'https://itunes.apple.com/kr/app/sweeohauseu-sesang-ui-modeun/id1060914858?mt=8',
+    linkPlayStore: 'https://play.google.com/store/apps/details?id=kr.dobbit.sharehows',
     author: 'Dobbit Co., Ltd.'
   },
   {
@@ -495,6 +514,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/text-blast-2016/id1023852862?mt=8',
     author: 'Sesh',
   },
+  {
+    name: 'This AM',
+    icon: 'http://s3.r29static.com//bin/public/efe/x/1542038/image.png',
+    link: 'https://itunes.apple.com/us/app/refinery29-this-am-top-breaking/id988472315?mt=8',
+    author: 'Refinery29',
+  },
   {
     name: 'Tong Xing Wang',
     icon: 'http://a3.mzstatic.com/us/r30/Purple1/v4/7d/52/a7/7d52a71f-9532-82a5-b92f-87076624fdb2/icon175x175.jpeg',
@@ -516,9 +541,9 @@ var apps = [
   },
   {
     name: 'WPV',
-    icon: 'http://a1.mzstatic.com/us/r30/Purple3/v4/f1/ae/51/f1ae516b-d8e9-1b6d-acfe-755623a88327/icon350x350.png',
+    icon: 'http://a2.mzstatic.com/us/r30/Purple49/v4/a8/26/d7/a826d7bf-337b-c6b8-488d-aca98027754d/icon350x350.png',
     link: 'https://itunes.apple.com/us/app/wpv/id725222647?mt=8',
-    author: 'Yamill Vallecillo (@yamill3)',
+    author: 'Yamill Vallecillo',
   },
   {
     name: 'Yoloci',
@@ -556,7 +581,14 @@ var apps = [
     icon: 'http://7xk1ez.com2.z0.glb.qiniucdn.com/logo-mobile-0114logo_welcom.png',
     link: 'https://itunes.apple.com/us/app/ni-zao-me/id1025294933?l=zh&ls=1&mt=8',
     author: 'Scott Chen(@NZAOM)'
-  }
+  },
+  {
+    name: 'うたよみん',
+    icon: 'http://a4.mzstatic.com/jp/r30/Purple69/v4/19/8f/fa/198ffafe-66a6-d682-c8d1-47faf2b0badb/icon175x175.jpeg',
+    linkAppStore: 'https://itunes.apple.com/jp/app/minnano-duan-ge-tou-gaokomyuniti/id675671254?mt=8',
+    linkPlayStore: 'https://play.google.com/store/apps/details?id=com.plasticaromantica.utayomin',
+    author: 'Takayuki IMAI'
+  },
 ];
 
 var AppList = React.createClass({

From e1fed608e877ad081de1b04ef87f78f339209bd9 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Tue, 16 Feb 2016 10:07:35 -0800
Subject: [PATCH 1182/1411] Fix double-destruct of string on syntax error

Reviewed By: davidaurelio

Differential Revision: D2939260

fb-gh-sync-id: b080b70aae7e33297d549d387e40bde07f4fc765
shipit-source-id: b080b70aae7e33297d549d387e40bde07f4fc765
---
 ReactAndroid/src/main/jni/react/JSCHelpers.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/jni/react/JSCHelpers.cpp b/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
index 0711c273f140..b18e965c6b7d 100644
--- a/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCHelpers.cpp
@@ -55,7 +55,7 @@ JSValueRef evaluateScript(JSContextRef context, JSStringRef script, JSStringRef
     auto line = exception.asObject().getProperty("line");
 
     std::ostringstream locationInfo;
-    std::string file = source != nullptr ? String::adopt(source).str() : "";
+    std::string file = source != nullptr ? String::ref(source).str() : "";
     locationInfo << "(" << (file.length() ? file : "<unknown file>");
     if (line != nullptr && line.isNumber()) {
       locationInfo << ":" << line.asInteger();

From 41789e7929e027f320a705ddc6d129e612a39dee Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Tue, 16 Feb 2016 10:15:00 -0800
Subject: [PATCH 1183/1411] Simplify docs on generating Android release APK

Reviewed By: mkonicek

Differential Revision:D2939525
Ninja: Open source docs only

fb-gh-sync-id: bf5d0cd84a148bf366e15d22f934721151a35ef4
shipit-source-id: bf5d0cd84a148bf366e15d22f934721151a35ef4
---
 docs/SignedAPKAndroid.md | 35 +++++++----------------------------
 1 file changed, 7 insertions(+), 28 deletions(-)

diff --git a/docs/SignedAPKAndroid.md b/docs/SignedAPKAndroid.md
index b32defa06eaf..759ed7ae09ac 100644
--- a/docs/SignedAPKAndroid.md
+++ b/docs/SignedAPKAndroid.md
@@ -66,29 +66,15 @@ android {
 
 ### Generating the release APK
 
-#### If you have a `react.gradle` file in `android/app`
-
 Simply run the following in a terminal:
 
 ```sh
 $ cd android && ./gradlew assembleRelease
 ```
 
-If you need to change the way the JavaScript bundle and/or drawable resources are bundled (e.g. if you changed the default file/folder names or the general structure of the project), have a look at `android/app/build.gradle` to see how you can update it to reflect these changes.
-
-#### If you *don't* have a `react.gradle` file:
+Gradle's `assembleRelease` will bundle all the JavaScript needed to run your app into the APK. If you need to change the way the JavaScript bundle and/or drawable resources are bundled (e.g. if you changed the default file/folder names or the general structure of the project), have a look at `android/app/build.gradle` to see how you can update it to reflect these changes.
 
-You can [upgrade](docs/upgrading.html) to the latest version of React Native to get this file. Alternatively, you can bundle the JavaScript package and drawable resources manually by doing the following in a terminal:
-
-```sh
-$ mkdir -p android/app/src/main/assets
-$ react-native bundle --platform android --dev false --entry-file index.android.js \
-  --bundle-output android/app/src/main/assets/index.android.bundle \
-  --assets-dest android/app/src/main/res/
-$ cd android && ./gradlew assembleRelease
-```
-
-In both cases the generated APK can be found under `android/app/build/outputs/apk/app-release.apk`, and is ready to be distributed.
+The generated APK can be found under `android/app/build/outputs/apk/app-release.apk`, and is ready to be distributed.
 
 ### Testing the release build of your app
 
@@ -108,18 +94,11 @@ Proguard is a tool that can slightly reduce the size of the APK. It does this by
 
 _**IMPORTANT**: Make sure to thoroughly test your app if you've enabled Proguard. Proguard often requires configuration specific to each native library you're using. See `app/proguard-rules.pro`._
 
-To enable Proguard, set `minifyEnabled` to `true`:
+To enable Proguard, edit `android/app/build.gradle`:
 
 ```gradle
-...
-android {
-    ...
-    buildTypes {
-        release {
-            ...
-            minifyEnabled true
-        }
-    }
-}
-...
+/**
+ * Run Proguard to shrink the Java bytecode in release builds.
+ */
+def enableProguardInReleaseBuilds = true
 ```

From 3e52df8c2aa11de84fb6eb6664eda2043909d2d9 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Tue, 16 Feb 2016 10:20:56 -0800
Subject: [PATCH 1184/1411] Using an updated version of Sinopia that works with
 node 4&5

Differential Revision: D2939188

fb-gh-sync-id: 0189d820c818df249ed26dbeb0d2d6e1d43c82b1
shipit-source-id: 0189d820c818df249ed26dbeb0d2d6e1d43c82b1
---
 .travis.yml         | 7 +++----
 scripts/e2e-test.sh | 6 ++++--
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index c1d47f6c00f6..a5ff66f5132f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,9 +3,9 @@ language: objective-c
 osx_image: xcode7.2
 
 cache:
-    directories:
-        - node_modules
-        - .nvm
+  directories:
+    - node_modules
+    - .nvm
 
 install:
   - brew reinstall nvm
@@ -69,4 +69,3 @@ branches:
   only:
     - master
     - /^.*-stable$/
-    
\ No newline at end of file
diff --git a/scripts/e2e-test.sh b/scripts/e2e-test.sh
index 731a96edf7b2..5cfdc65cf0bf 100755
--- a/scripts/e2e-test.sh
+++ b/scripts/e2e-test.sh
@@ -42,7 +42,9 @@ cd $TEMP
 # sinopia is npm registry proxy, it is used to make npm
 # think react-native and react-native-cli are actually
 # published on npm
-which sinopia || npm install -g sinopia
+# Temporarily installing sinopia from a github fork
+# TODO t10060166 use npm repo when bug is fixed
+which sinopia || npm install -g git://github.com/bestander/sinopia.git#057155985fe955ed6066d1fc2edc159c63dec675
 
 # but in order to make npm use sinopia we temporarily
 # replace its config file
@@ -60,7 +62,7 @@ npm publish $ROOT
 npm publish $ROOT/react-native-cli
 
 npm install -g react-native-cli
-react-native init EndToEndTest --verbose
+react-native init EndToEndTest
 cd EndToEndTest/ios
 
 # Make sure we installed local version of react-native

From 97c799a6805780fec002e2739ec45c6bafc0fc96 Mon Sep 17 00:00:00 2001
From: Adam Ernst <adamjernst@me.com>
Date: Tue, 16 Feb 2016 11:50:39 -0800
Subject: [PATCH 1185/1411] Update README.md

Reviewed By: svcscm

Differential Revision: D2924282

fb-gh-sync-id: fe845cfa775470dc71dac8ab3bc62681e04f4f13
shipit-source-id: fe845cfa775470dc71dac8ab3bc62681e04f4f13
---
 packager/README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packager/README.md b/packager/README.md
index 039865ba6e14..8010cc383650 100644
--- a/packager/README.md
+++ b/packager/README.md
@@ -12,7 +12,7 @@ to wait more than a few seconds after starting the packager.
 
 The main deviation from the node module system is the support for our
 proprietary module format known as `@providesModule`. However, we
-discourage people to use this module format because going forward, we
+discourage people from using this module format because going forward we
 want to completely separate our infrastructure from React Native and
 provide an experience most JavaScript developers are familiar with,
 namely the node module format. We want to even go further, and let you

From f74981ac3267a677688fbff1b173a82c0b9fe758 Mon Sep 17 00:00:00 2001
From: Hedger Wang <hedger@fb.com>
Date: Tue, 16 Feb 2016 11:57:16 -0800
Subject: [PATCH 1186/1411] Add `@providesModule NavigatorExample` to
 NavigatorExample.js

Reviewed By: fkgozali

Differential Revision: D2936536

fb-gh-sync-id: 06923aa269d1687a562624de00e7a06328e6861d
shipit-source-id: 06923aa269d1687a562624de00e7a06328e6861d
---
 Examples/UIExplorer/Navigator/NavigatorExample.js | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Examples/UIExplorer/Navigator/NavigatorExample.js b/Examples/UIExplorer/Navigator/NavigatorExample.js
index d15939886f06..7346af4542d4 100644
--- a/Examples/UIExplorer/Navigator/NavigatorExample.js
+++ b/Examples/UIExplorer/Navigator/NavigatorExample.js
@@ -10,7 +10,9 @@
  * FACEBOOK 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 NavigatorExample
+ */
 'use strict';
 
 var React = require('react-native');

From 07a5f4407fd0d2a58b1d5b5508eb6911380daa51 Mon Sep 17 00:00:00 2001
From: Felix Oghina <foghina@fb.com>
Date: Tue, 16 Feb 2016 12:13:16 -0800
Subject: [PATCH 1187/1411] add removeReactInstanceEventListener and call it
 from onDestroy

Reviewed By: zahanm

Differential Revision: D2937547

fb-gh-sync-id: 95461fdada8ac86d2c4174dae7023c97a3101e2e
shipit-source-id: 95461fdada8ac86d2c4174dae7023c97a3101e2e
---
 .../java/com/facebook/react/ReactInstanceManager.java  |  5 +++++
 .../com/facebook/react/ReactInstanceManagerImpl.java   | 10 +++++++++-
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
index 17fb538b826d..1bcd68cc22ac 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
@@ -136,6 +136,11 @@ public abstract List<ViewManager> createAllViewManagers(
    */
   public abstract void addReactInstanceEventListener(ReactInstanceEventListener listener);
 
+  /**
+   * Remove a listener previously added with {@link #addReactInstanceEventListener}.
+   */
+  public abstract void removeReactInstanceEventListener(ReactInstanceEventListener listener);
+
   @VisibleForTesting
   public abstract @Nullable ReactContext getCurrentReactContext();
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index c4f550495d84..88a064c6cd0c 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -15,7 +15,10 @@
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
 
 import android.app.Activity;
@@ -110,7 +113,7 @@
   private String mSourceUrl;
   private @Nullable Activity mCurrentActivity;
   private final Collection<ReactInstanceEventListener> mReactInstanceEventListeners =
-      new ConcurrentLinkedQueue<>();
+      Collections.synchronizedSet(new HashSet<ReactInstanceEventListener>());
   private volatile boolean mHasStartedCreatingInitialContext = false;
   private final UIImplementationProvider mUIImplementationProvider;
   private final MemoryPressureRouter mMemoryPressureRouter;
@@ -599,6 +602,11 @@ public void addReactInstanceEventListener(ReactInstanceEventListener listener) {
     mReactInstanceEventListeners.add(listener);
   }
 
+  @Override
+  public void removeReactInstanceEventListener(ReactInstanceEventListener listener) {
+    mReactInstanceEventListeners.remove(listener);
+  }
+
   @VisibleForTesting
   @Override
   public @Nullable ReactContext getCurrentReactContext() {

From 0427c3d273bbc963a69c19518544ebdca1986a59 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Tue, 16 Feb 2016 12:41:20 -0800
Subject: [PATCH 1188/1411] Added throttling on requests made by RCTImageLoader

Reviewed By: javache

Differential Revision: D2938143

fb-gh-sync-id: bac1185d4792dcca0012905126c9ef2aa45905d5
shipit-source-id: bac1185d4792dcca0012905126c9ef2aa45905d5
---
 Libraries/Image/RCTImageLoader.h   |  25 +++++
 Libraries/Image/RCTImageLoader.m   | 153 +++++++++++++++++++++++------
 Libraries/Network/RCTNetworkTask.h |   8 ++
 Libraries/Network/RCTNetworkTask.m |   9 +-
 React/Profiler/RCTJSCProfiler.m    |   4 +-
 React/Profiler/RCTProfile.m        |   2 +-
 6 files changed, 168 insertions(+), 33 deletions(-)

diff --git a/Libraries/Image/RCTImageLoader.h b/Libraries/Image/RCTImageLoader.h
index e7805b135cfa..cfe3d83fc871 100644
--- a/Libraries/Image/RCTImageLoader.h
+++ b/Libraries/Image/RCTImageLoader.h
@@ -27,6 +27,31 @@ typedef void (^RCTImageLoaderCancellationBlock)(void);
 
 @interface RCTImageLoader : NSObject <RCTBridgeModule, RCTURLRequestHandler>
 
+/**
+ * The maximum number of concurrent image loading tasks. Loading and decoding
+ * images can consume a lot of memory, so setting this to a higher value may
+ * cause memory to spike. If you are seeing out-of-memory crashes, try reducing
+ * this value.
+ */
+@property (nonatomic, assign) NSUInteger maxConcurrentLoadingTasks;
+
+/**
+ * The maximum number of concurrent image decoding tasks. Decoding large
+ * images can be especially CPU and memory intensive, so if your are decoding a
+ * lot of large images in your app, you may wish to adjust this value.
+ */
+@property (nonatomic, assign) NSUInteger maxConcurrentDecodingTasks;
+
+/**
+ * Decoding large images can use a lot of memory, and potentially cause the app
+ * to crash. This value allows you to throttle the amount of memory used by the
+ * decoder independently of the number of concurrent threads. This means you can
+ * still decode a lot of small images in parallel, without allowing the decoder
+ * to try to decompress multiple huge images at once. Note that this value is
+ * only a hint, and not an indicator of the total memory used by the app.
+ */
+@property (nonatomic, assign) NSUInteger maxConcurrentDecodingBytes;
+
 /**
  * Loads the specified image at the highest available resolution.
  * Can be called from any thread, will call back on an unspecified thread.
diff --git a/Libraries/Image/RCTImageLoader.m b/Libraries/Image/RCTImageLoader.m
index 22bffa4a3d26..ea4d42acf664 100644
--- a/Libraries/Image/RCTImageLoader.m
+++ b/Libraries/Image/RCTImageLoader.m
@@ -41,6 +41,11 @@ @implementation RCTImageLoader
   NSOperationQueue *_imageDecodeQueue;
   dispatch_queue_t _URLCacheQueue;
   NSURLCache *_URLCache;
+  NSMutableArray *_pendingTasks;
+  NSInteger _activeTasks;
+  NSMutableArray *_pendingDecodes;
+  NSInteger _scheduledDecodes;
+  NSUInteger _activeBytes;
 }
 
 @synthesize bridge = _bridge;
@@ -49,6 +54,11 @@ @implementation RCTImageLoader
 
 - (void)setUp
 {
+  // Set defaults
+  _maxConcurrentLoadingTasks = _maxConcurrentLoadingTasks ?: 4;
+  _maxConcurrentDecodingTasks = _maxConcurrentDecodingTasks ?: 2;
+  _maxConcurrentDecodingBytes = _maxConcurrentDecodingBytes ?: 30 * 1024 *1024; // 30MB
+
   // Get image loaders and decoders
   NSMutableArray<id<RCTImageURLLoader>> *loaders = [NSMutableArray array];
   NSMutableArray<id<RCTImageDataDecoder>> *decoders = [NSMutableArray array];
@@ -203,6 +213,50 @@ - (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag
                 completionBlock:callback];
 }
 
+- (void)dequeueTasks
+{
+  dispatch_async(_URLCacheQueue, ^{
+
+    // Remove completed tasks
+    for (RCTNetworkTask *task in _pendingTasks.reverseObjectEnumerator) {
+      switch (task.status) {
+        case RCTNetworkTaskFinished:
+          [_pendingTasks removeObject:task];
+          _activeTasks--;
+          break;
+        case RCTNetworkTaskPending:
+        case RCTNetworkTaskInProgress:
+          // Do nothing
+          break;
+      }
+    }
+
+    // Start queued decode
+    NSInteger activeDecodes = _scheduledDecodes - _pendingDecodes.count;
+    while (activeDecodes == 0 || (_activeBytes <= _maxConcurrentDecodingBytes &&
+                                  activeDecodes <= _maxConcurrentDecodingTasks)) {
+      dispatch_block_t decodeBlock = _pendingDecodes.firstObject;
+      if (decodeBlock) {
+        [_pendingDecodes removeObjectAtIndex:0];
+        decodeBlock();
+      } else {
+        break;
+      }
+    }
+
+    // Start queued tasks
+    for (RCTNetworkTask *task in _pendingTasks) {
+      if (MAX(_activeTasks, _scheduledDecodes) >= _maxConcurrentLoadingTasks) {
+        break;
+      }
+      if (task.status == RCTNetworkTaskPending) {
+        [task start];
+        _activeTasks++;
+      }
+    }
+  });
+}
+
 /**
  * This returns either an image, or raw image data, depending on the loading
  * path taken. This is useful if you want to skip decoding, e.g. when preloading
@@ -327,8 +381,7 @@ - (RCTImageLoaderCancellationBlock)loadImageOrDataWithTag:(NSString *)imageTag
     }
 
     // Download image
-    RCTNetworkTask *task = [_bridge.networking networkTaskWithRequest:request completionBlock:
-                            ^(NSURLResponse *response, NSData *data, NSError *error) {
+    RCTNetworkTask *task = [_bridge.networking networkTaskWithRequest:request completionBlock:^(NSURLResponse *response, NSData *data, NSError *error) {
       if (error) {
         completionHandler(error, nil);
         return;
@@ -348,14 +401,26 @@ - (RCTImageLoaderCancellationBlock)loadImageOrDataWithTag:(NSString *)imageTag
         // Process image data
         processResponse(response, data, nil);
 
+        //clean up
+        [weakSelf dequeueTasks];
+
       });
 
     }];
     task.downloadProgressBlock = progressHandler;
-    [task start];
+
+    if (!_pendingTasks) {
+      _pendingTasks = [NSMutableArray new];
+    }
+    [_pendingTasks addObject:task];
+    if (MAX(_activeTasks, _scheduledDecodes) < _maxConcurrentLoadingTasks) {
+      [task start];
+      _activeTasks++;
+    }
 
     cancelLoad = ^{
       [task cancel];
+      [weakSelf dequeueTasks];
     };
 
   });
@@ -453,7 +518,6 @@ - (RCTImageLoaderCancellationBlock)decodeImageDataWithoutClipping:(NSData *)data
   __block volatile uint32_t cancelled = 0;
   void (^completionHandler)(NSError *, UIImage *) = ^(NSError *error, UIImage *image) {
     if ([NSThread isMainThread]) {
-
       // Most loaders do not return on the main thread, so caller is probably not
       // expecting it, and may do expensive post-processing in the callback
       dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@@ -475,40 +539,71 @@ - (RCTImageLoaderCancellationBlock)decodeImageDataWithoutClipping:(NSData *)data
                        completionHandler:completionHandler];
   } else {
 
-    // Serialize decoding to prevent excessive memory usage
-    if (!_imageDecodeQueue) {
-      _imageDecodeQueue = [NSOperationQueue new];
-      _imageDecodeQueue.name = @"com.facebook.react.ImageDecoderQueue";
-      _imageDecodeQueue.maxConcurrentOperationCount = 2;
-    }
-    [_imageDecodeQueue addOperationWithBlock:^{
-      if (cancelled) {
-        return;
-      }
+    dispatch_async(_URLCacheQueue, ^{
+      dispatch_block_t decodeBlock = ^{
+
+        // Calculate the size, in bytes, that the decompressed image will require
+        NSInteger decodedImageBytes = (size.width * scale) * (size.height * scale) * 4;
 
-      UIImage *image = RCTDecodeImageWithData(data, size, scale, resizeMode);
+        // Mark these bytes as in-use
+        _activeBytes += decodedImageBytes;
+
+        // Do actual decompression on a concurrent background queue
+        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+          if (!cancelled) {
+
+            // Decompress the image data (this may be CPU and memory intensive)
+            UIImage *image = RCTDecodeImageWithData(data, size, scale, resizeMode);
 
 #if RCT_DEV
 
-      CGSize imagePixelSize = RCTSizeInPixels(image.size, image.scale);
-      CGSize screenPixelSize = RCTSizeInPixels(RCTScreenSize(), RCTScreenScale());
-      if (imagePixelSize.width * imagePixelSize.height >
-          screenPixelSize.width * screenPixelSize.height) {
-        RCTLogInfo(@"[PERF ASSETS] Loading image at size %@, which is larger "
-                   "than the screen size %@", NSStringFromCGSize(imagePixelSize),
-                   NSStringFromCGSize(screenPixelSize));
-      }
+            CGSize imagePixelSize = RCTSizeInPixels(image.size, image.scale);
+            CGSize screenPixelSize = RCTSizeInPixels(RCTScreenSize(), RCTScreenScale());
+            if (imagePixelSize.width * imagePixelSize.height >
+                screenPixelSize.width * screenPixelSize.height) {
+              RCTLogInfo(@"[PERF ASSETS] Loading image at size %@, which is larger "
+                         "than the screen size %@", NSStringFromCGSize(imagePixelSize),
+                         NSStringFromCGSize(screenPixelSize));
+            }
 
 #endif
 
-      if (image) {
-        completionHandler(nil, image);
+            if (image) {
+              completionHandler(nil, image);
+            } else {
+              NSString *errorMessage = [NSString stringWithFormat:@"Error decoding image data <NSData %p; %tu bytes>", data, data.length];
+              NSError *finalError = RCTErrorWithMessage(errorMessage);
+              completionHandler(finalError, nil);
+            }
+          }
+
+          // We're no longer retaining the uncompressed data, so now we'll mark
+          // the decoding as complete so that the loading task queue can resume.
+          dispatch_async(_URLCacheQueue, ^{
+            _scheduledDecodes--;
+            _activeBytes -= decodedImageBytes;
+            [self dequeueTasks];
+          });
+        });
+      };
+
+      // The decode operation retains the compressed image data until it's
+      // complete, so we'll mark it as having started, in order to block
+      // further image loads from happening until we're done with the data.
+      _scheduledDecodes++;
+
+      if (!_pendingDecodes) {
+        _pendingDecodes = [NSMutableArray new];
+      }
+      NSInteger activeDecodes = _scheduledDecodes - _pendingDecodes.count - 1;
+      if (activeDecodes == 0 || (_activeBytes <= _maxConcurrentDecodingBytes &&
+                                 activeDecodes <= _maxConcurrentDecodingTasks)) {
+        decodeBlock();
       } else {
-        NSString *errorMessage = [NSString stringWithFormat:@"Error decoding image data <NSData %p; %tu bytes>", data, data.length];
-        NSError *finalError = RCTErrorWithMessage(errorMessage);
-        completionHandler(finalError, nil);
+        [_pendingDecodes addObject:decodeBlock];
       }
-    }];
+
+    });
 
     return ^{
       OSAtomicOr32Barrier(1, &cancelled);
diff --git a/Libraries/Network/RCTNetworkTask.h b/Libraries/Network/RCTNetworkTask.h
index 5265d8ef30c2..3f2de225ff8c 100644
--- a/Libraries/Network/RCTNetworkTask.h
+++ b/Libraries/Network/RCTNetworkTask.h
@@ -18,6 +18,12 @@ typedef void (^RCTURLRequestIncrementalDataBlock)(NSData *data);
 typedef void (^RCTURLRequestProgressBlock)(int64_t progress, int64_t total);
 typedef void (^RCTURLRequestResponseBlock)(NSURLResponse *response);
 
+typedef NS_ENUM(NSInteger, RCTNetworkTaskStatus) {
+  RCTNetworkTaskPending = 0,
+  RCTNetworkTaskInProgress,
+  RCTNetworkTaskFinished,
+};
+
 @interface RCTNetworkTask : NSObject <RCTURLRequestDelegate>
 
 @property (nonatomic, readonly) NSURLRequest *request;
@@ -31,6 +37,8 @@ typedef void (^RCTURLRequestResponseBlock)(NSURLResponse *response);
 @property (nonatomic, copy) RCTURLRequestResponseBlock responseBlock;
 @property (nonatomic, copy) RCTURLRequestProgressBlock uploadProgressBlock;
 
+@property (nonatomic, readonly) RCTNetworkTaskStatus status;
+
 - (instancetype)initWithRequest:(NSURLRequest *)request
                         handler:(id<RCTURLRequestHandler>)handler
                 completionBlock:(RCTURLRequestCompletionBlock)completionBlock NS_DESIGNATED_INITIALIZER;
diff --git a/Libraries/Network/RCTNetworkTask.m b/Libraries/Network/RCTNetworkTask.m
index 13aba182b9c3..ead015bccc27 100644
--- a/Libraries/Network/RCTNetworkTask.m
+++ b/Libraries/Network/RCTNetworkTask.m
@@ -33,6 +33,7 @@ - (instancetype)initWithRequest:(NSURLRequest *)request
     _request = request;
     _handler = handler;
     _completionBlock = completionBlock;
+    _status = RCTNetworkTaskPending;
   }
   return self;
 }
@@ -55,6 +56,7 @@ - (void)start
     if ([self validateRequestToken:[_handler sendRequest:_request
                                             withDelegate:self]]) {
       _selfReference = self;
+      _status = RCTNetworkTaskInProgress;
     }
   }
 }
@@ -66,6 +68,7 @@ - (void)cancel
     [_handler cancelRequest:strongToken];
   }
   [self invalidate];
+  _status = RCTNetworkTaskFinished;
 }
 
 - (BOOL)validateRequestToken:(id)requestToken
@@ -83,8 +86,9 @@ - (BOOL)validateRequestToken:(id)requestToken
     if (_completionBlock) {
       _completionBlock(_response, _data, [NSError errorWithDomain:RCTErrorDomain code:0
         userInfo:@{NSLocalizedDescriptionKey: @"Unrecognized request token."}]);
-      [self invalidate];
     }
+    [self invalidate];
+    _status = RCTNetworkTaskFinished;
     return NO;
   }
   return YES;
@@ -130,8 +134,9 @@ - (void)URLRequest:(id)requestToken didCompleteWithError:(NSError *)error
   if ([self validateRequestToken:requestToken]) {
     if (_completionBlock) {
       _completionBlock(_response, _data, error);
-      [self invalidate];
     }
+    [self invalidate];
+    _status = RCTNetworkTaskFinished;
   }
 }
 
diff --git a/React/Profiler/RCTJSCProfiler.m b/React/Profiler/RCTJSCProfiler.m
index 8ad34b62682e..fc0a21fff8bb 100644
--- a/React/Profiler/RCTJSCProfiler.m
+++ b/React/Profiler/RCTJSCProfiler.m
@@ -99,7 +99,9 @@ void RCTJSCProfilerStart(JSContextRef ctx)
     if (isProfiling) {
       NSString *filename = [NSString stringWithFormat:@"cpu_profile_%ld.json", (long)CFAbsoluteTimeGetCurrent()];
       outputFile = [NSTemporaryDirectory() stringByAppendingPathComponent:filename];
-      RCTNativeProfilerEnd(ctx, JSCProfileName, outputFile.UTF8String);
+      if (RCTNativeProfilerEnd) {
+        RCTNativeProfilerEnd(ctx, JSCProfileName, outputFile.UTF8String);
+      }
       RCTLogInfo(@"Stopped JSC profiler for context: %p", ctx);
     } else {
       RCTLogWarn(@"Trying to stop JSC profiler on a context which is not being profiled.");
diff --git a/React/Profiler/RCTProfile.m b/React/Profiler/RCTProfile.m
index 6ed1e0f7d89b..14dbefb1f140 100644
--- a/React/Profiler/RCTProfile.m
+++ b/React/Profiler/RCTProfile.m
@@ -399,7 +399,7 @@ void RCTProfileInit(RCTBridge *bridge)
   dispatch_async(RCTProfileGetQueue(), ^{
     NSString *shadowQueue = @(dispatch_queue_get_label([[bridge uiManager] methodQueue]));
     NSArray *orderedThreads = @[@"JS async", RCTJSCThreadName, shadowQueue, @"main"];
-    [orderedThreads enumerateObjectsUsingBlock:^(NSString *thread, NSUInteger idx, BOOL *stop) {
+    [orderedThreads enumerateObjectsUsingBlock:^(NSString *thread, NSUInteger idx, __unused BOOL *stop) {
       RCTProfileAddEvent(RCTProfileTraceEvents,
         @"ph": @"M", // metadata event
         @"name": @"thread_sort_index",

From d1dbe2dfa62dbe9da6db7383cf438765661841ea Mon Sep 17 00:00:00 2001
From: Josh Buchea <verctrl@joshbuchea.com>
Date: Tue, 16 Feb 2016 13:29:12 -0800
Subject: [PATCH 1189/1411] Add My IP to showcase

Summary: Closes https://github.com/facebook/react-native/pull/5961

Differential Revision: D2940219

Pulled By: androidtrunkagent

fb-gh-sync-id: 4f9623fb7fe462939982bd98cb789f3ec358509b
shipit-source-id: 4f9623fb7fe462939982bd98cb789f3ec358509b
---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index af3f1a100e99..6b16397699af 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -375,6 +375,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/mr.-dapper-men-fashion-app/id989735184?ls=1&mt=8',
     author: 'wei ping woon',
   },
+  {
+    name: 'My IP',
+    icon: 'http://a3.mzstatic.com/us/r30/Purple69/v4/a2/61/58/a261584d-a4cd-cbfa-cf9d-b5f1f15a7139/icon175x175.jpeg',
+    link: 'https://itunes.apple.com/app/id1031729525?mt=8&at=11l7ss&ct=reactnativeshowcase',
+    author: 'Josh Buchea',
+  }
   {
     name: 'MyPED',
     icon: 'http://a2.mzstatic.com/eu/r30/Purple69/v4/88/1f/fb/881ffb3b-7986-d427-7fcf-eb5920a883af/icon175x175.png',

From ecf6981093f7f9afe4a462eee9e7af864c6d9e70 Mon Sep 17 00:00:00 2001
From: Matthew Dapena-Tretter <matthewwithanm@fb.com>
Date: Tue, 16 Feb 2016 13:57:30 -0800
Subject: [PATCH 1190/1411] Only freeze valid attributes in `mountComponent`

Reviewed By: spicyj

Differential Revision: D2939910

fb-gh-sync-id: 2efe6ecd6d888d4185a8cc74ba9adbe7c68bcd3b
shipit-source-id: 2efe6ecd6d888d4185a8cc74ba9adbe7c68bcd3b
---
 Libraries/ReactNative/ReactNativeBaseComponent.js | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/Libraries/ReactNative/ReactNativeBaseComponent.js b/Libraries/ReactNative/ReactNativeBaseComponent.js
index ceb600aaaaa0..19afca80362e 100644
--- a/Libraries/ReactNative/ReactNativeBaseComponent.js
+++ b/Libraries/ReactNative/ReactNativeBaseComponent.js
@@ -185,7 +185,11 @@ ReactNativeBaseComponent.Mixin = {
     var tag = ReactNativeTagHandles.allocateTag();
 
     if (__DEV__) {
-      deepFreezeAndThrowOnMutationInDev(this._currentElement.props);
+      for (var key in this.viewConfig.validAttributes) {
+        if (this._currentElement.props.hasOwnProperty(key)) {
+          deepFreezeAndThrowOnMutationInDev(this._currentElement.props[key]);
+        }
+      }
     }
 
     var updatePayload = ReactNativeAttributePayload.create(

From 0176ac488e57b77dfa82984c114901d884e90b53 Mon Sep 17 00:00:00 2001
From: Jesse Ruder <jesse@fretboard.io>
Date: Tue, 16 Feb 2016 16:50:35 -0800
Subject: [PATCH 1191/1411] Add hitSlop prop on iOS and Android

Summary:New prop `hitSlop` allows extending the touch area of Touchable components. This makes it easier to touch small buttons without needing to change your styles.

It takes `top`, `bottom`, `left`, and `right` same as the `pressRetentionOffset` prop. When a touch is moved, `hitSlop` is combined with `pressRetentionOffset` to determine how far the touch can move off the button before deactivating the button.

On Android I had to add a new file `ids.xml` to generate a unique ID to use for the tag where I store the `hitSlop` state. The iOS side is more straightforward.

terribleben worked on the iOS and JS parts of this diff.

Fixes #110
Closes https://github.com/facebook/react-native/pull/5720

Differential Revision: D2941671

Pulled By: androidtrunkagent

fb-gh-sync-id: 07e3eb8b6a36eebf76968fdaac3c6ac335603194
shipit-source-id: 07e3eb8b6a36eebf76968fdaac3c6ac335603194
---
 Examples/UIExplorer/TouchableExample.js       | 58 ++++++++++++++++++-
 Libraries/Components/Touchable/Touchable.js   | 10 ++++
 .../Components/Touchable/TouchableBounce.js   | 14 +++++
 .../Touchable/TouchableHighlight.js           |  5 ++
 .../TouchableNativeFeedback.android.js        |  5 ++
 .../Components/Touchable/TouchableOpacity.js  |  5 ++
 .../Touchable/TouchableWithoutFeedback.js     | 14 +++++
 Libraries/Components/View/View.js             | 14 +++++
 React/Views/RCTView.h                         |  5 ++
 React/Views/RCTView.m                         | 10 ++++
 React/Views/RCTViewManager.m                  | 11 ++++
 .../react/touch/ReactHitSlopView.java         | 28 +++++++++
 .../react/uimanager/TouchTargetHelper.java    | 26 +++++++--
 .../react/views/view/ReactViewGroup.java      | 13 ++++-
 .../react/views/view/ReactViewManager.java    | 15 +++++
 15 files changed, 225 insertions(+), 8 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/touch/ReactHitSlopView.java

diff --git a/Examples/UIExplorer/TouchableExample.js b/Examples/UIExplorer/TouchableExample.js
index 515a0c2b858c..377a6ce48f90 100644
--- a/Examples/UIExplorer/TouchableExample.js
+++ b/Examples/UIExplorer/TouchableExample.js
@@ -93,7 +93,14 @@ exports.examples = [
     return <ForceTouchExample />;
   },
   platform: 'ios',
-}];
+}, {
+   title: 'Touchable Hit Slop',
+   description: '<Touchable*> components accept hitSlop prop which extends the touch area ' +
+     'without changing the view bounds.',
+   render: function(): ReactElement {
+     return <TouchableHitSlop />;
+   },
+ }];
 
 var TextOnPressBox = React.createClass({
   getInitialState: function() {
@@ -243,6 +250,48 @@ var ForceTouchExample = React.createClass({
   },
 });
 
+var TouchableHitSlop = React.createClass({
+  getInitialState: function() {
+    return {
+      timesPressed: 0,
+    };
+  },
+  onPress: function() {
+    this.setState({
+      timesPressed: this.state.timesPressed + 1,
+    });
+  },
+  render: function() {
+    var log = '';
+    if (this.state.timesPressed > 1) {
+      log = this.state.timesPressed + 'x onPress';
+    } else if (this.state.timesPressed > 0) {
+      log = 'onPress';
+    }
+
+    return (
+      <View testID="touchable_hit_slop">
+        <View style={[styles.row, {justifyContent: 'center'}]}>
+          <TouchableOpacity
+            onPress={this.onPress}
+            style={styles.hitSlopWrapper}
+            hitSlop={{top: 30, bottom: 30, left: 60, right: 60}}
+            testID="touchable_hit_slop_button">
+            <Text style={styles.hitSlopButton}>
+              Press Outside This View
+            </Text>
+          </TouchableOpacity>
+         </View>
+        <View style={styles.logBox}>
+          <Text>
+            {log}
+          </Text>
+        </View>
+      </View>
+    );
+  }
+});
+
 var heartImage = {uri: 'https://pbs.twimg.com/media/BlXBfT3CQAA6cVZ.png:small'};
 
 var styles = StyleSheet.create({
@@ -264,6 +313,9 @@ var styles = StyleSheet.create({
   button: {
     color: '#007AFF',
   },
+  hitSlopButton: {
+    color: 'white',
+  },
   wrapper: {
     borderRadius: 8,
   },
@@ -271,6 +323,10 @@ var styles = StyleSheet.create({
     borderRadius: 8,
     padding: 6,
   },
+  hitSlopWrapper: {
+    backgroundColor: 'red',
+    marginVertical: 30,
+  },
   logBox: {
     padding: 20,
     margin: 10,
diff --git a/Libraries/Components/Touchable/Touchable.js b/Libraries/Components/Touchable/Touchable.js
index 9f457c5c043a..6622ce8ad5ae 100644
--- a/Libraries/Components/Touchable/Touchable.js
+++ b/Libraries/Components/Touchable/Touchable.js
@@ -432,6 +432,16 @@ var TouchableMixin = {
     var pressExpandRight = pressRectOffset.right;
     var pressExpandBottom = pressRectOffset.bottom;
 
+    var hitSlop = this.touchableGetHitSlop ?
+      this.touchableGetHitSlop() : null;
+
+    if (hitSlop) {
+      pressExpandLeft += hitSlop.left;
+      pressExpandTop += hitSlop.top;
+      pressExpandRight += hitSlop.right;
+      pressExpandBottom += hitSlop.bottom;
+    }
+
     var touch = TouchEventUtils.extractSingleTouch(e.nativeEvent);
     var pageX = touch && touch.pageX;
     var pageY = touch && touch.pageY;
diff --git a/Libraries/Components/Touchable/TouchableBounce.js b/Libraries/Components/Touchable/TouchableBounce.js
index 1d7abcc71e83..5ea367ceba59 100644
--- a/Libraries/Components/Touchable/TouchableBounce.js
+++ b/Libraries/Components/Touchable/TouchableBounce.js
@@ -54,6 +54,15 @@ var TouchableBounce = React.createClass({
      * is disabled. Ensure you pass in a constant to reduce memory allocations.
      */
     pressRetentionOffset: EdgeInsetsPropType,
+    /**
+     * This defines how far your touch can start away from the button. This is
+     * added to `pressRetentionOffset` when moving off of the button.
+     * ** NOTE **
+     * The touch area never extends past the parent view bounds and the Z-index
+     * of sibling views always takes precedence if a touch hits two overlapping
+     * views.
+     */
+    hitSlop: EdgeInsetsPropType,
   },
 
   getInitialState: function(): State {
@@ -108,6 +117,10 @@ var TouchableBounce = React.createClass({
     return this.props.pressRetentionOffset || PRESS_RETENTION_OFFSET;
   },
 
+  touchableGetHitSlop: function(): ?Object {
+    return this.props.hitSlop;
+  },
+
   touchableGetHighlightDelayMS: function(): number {
     return 0;
   },
@@ -121,6 +134,7 @@ var TouchableBounce = React.createClass({
         accessibilityComponentType={this.props.accessibilityComponentType}
         accessibilityTraits={this.props.accessibilityTraits}
         testID={this.props.testID}
+        hitSlop={this.props.hitSlop}
         onStartShouldSetResponder={this.touchableHandleStartShouldSetResponder}
         onResponderTerminationRequest={this.touchableHandleResponderTerminationRequest}
         onResponderGrant={this.touchableHandleResponderGrant}
diff --git a/Libraries/Components/Touchable/TouchableHighlight.js b/Libraries/Components/Touchable/TouchableHighlight.js
index 9a514e46b7a9..1f6f9ed8176e 100644
--- a/Libraries/Components/Touchable/TouchableHighlight.js
+++ b/Libraries/Components/Touchable/TouchableHighlight.js
@@ -176,6 +176,10 @@ var TouchableHighlight = React.createClass({
     return this.props.pressRetentionOffset || PRESS_RETENTION_OFFSET;
   },
 
+  touchableGetHitSlop: function() {
+    return this.props.hitSlop;
+  },
+
   touchableGetHighlightDelayMS: function() {
     return this.props.delayPressIn;
   },
@@ -230,6 +234,7 @@ var TouchableHighlight = React.createClass({
         ref={UNDERLAY_REF}
         style={this.state.underlayStyle}
         onLayout={this.props.onLayout}
+        hitSlop={this.props.hitSlop}
         onStartShouldSetResponder={this.touchableHandleStartShouldSetResponder}
         onResponderTerminationRequest={this.touchableHandleResponderTerminationRequest}
         onResponderGrant={this.touchableHandleResponderGrant}
diff --git a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js
index 19439d4e5ff0..6d18182b8531 100644
--- a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js
+++ b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js
@@ -162,6 +162,10 @@ var TouchableNativeFeedback = React.createClass({
     return this.props.pressRetentionOffset || PRESS_RETENTION_OFFSET;
   },
 
+  touchableGetHitSlop: function() {
+    return this.props.hitSlop;
+  },
+
   touchableGetHighlightDelayMS: function() {
     return this.props.delayPressIn;
   },
@@ -205,6 +209,7 @@ var TouchableNativeFeedback = React.createClass({
       accessibilityTraits: this.props.accessibilityTraits,
       testID: this.props.testID,
       onLayout: this.props.onLayout,
+      hitSlop: this.props.hitSlop,
       onStartShouldSetResponder: this.touchableHandleStartShouldSetResponder,
       onResponderTerminationRequest: this.touchableHandleResponderTerminationRequest,
       onResponderGrant: this.touchableHandleResponderGrant,
diff --git a/Libraries/Components/Touchable/TouchableOpacity.js b/Libraries/Components/Touchable/TouchableOpacity.js
index 2cd0abefb470..29ceda28947e 100644
--- a/Libraries/Components/Touchable/TouchableOpacity.js
+++ b/Libraries/Components/Touchable/TouchableOpacity.js
@@ -124,6 +124,10 @@ var TouchableOpacity = React.createClass({
     return this.props.pressRetentionOffset || PRESS_RETENTION_OFFSET;
   },
 
+  touchableGetHitSlop: function() {
+    return this.props.hitSlop;
+  },
+
   touchableGetHighlightDelayMS: function() {
     return this.props.delayPressIn || 0;
   },
@@ -160,6 +164,7 @@ var TouchableOpacity = React.createClass({
         style={[this.props.style, {opacity: this.state.anim}]}
         testID={this.props.testID}
         onLayout={this.props.onLayout}
+        hitSlop={this.props.hitSlop}
         onStartShouldSetResponder={this.touchableHandleStartShouldSetResponder}
         onResponderTerminationRequest={this.touchableHandleResponderTerminationRequest}
         onResponderGrant={this.touchableHandleResponderGrant}
diff --git a/Libraries/Components/Touchable/TouchableWithoutFeedback.js b/Libraries/Components/Touchable/TouchableWithoutFeedback.js
index 5312c1f87886..1108c21e0bee 100755
--- a/Libraries/Components/Touchable/TouchableWithoutFeedback.js
+++ b/Libraries/Components/Touchable/TouchableWithoutFeedback.js
@@ -80,6 +80,15 @@ var TouchableWithoutFeedback = React.createClass({
      * is disabled. Ensure you pass in a constant to reduce memory allocations.
      */
     pressRetentionOffset: EdgeInsetsPropType,
+    /**
+     * This defines how far your touch can start away from the button. This is
+     * added to `pressRetentionOffset` when moving off of the button.
+     * ** NOTE **
+     * The touch area never extends past the parent view bounds and the Z-index
+     * of sibling views always takes precedence if a touch hits two overlapping
+     * views.
+     */
+    hitSlop: EdgeInsetsPropType,
   },
 
   getInitialState: function() {
@@ -118,6 +127,10 @@ var TouchableWithoutFeedback = React.createClass({
     return this.props.pressRetentionOffset || PRESS_RETENTION_OFFSET;
   },
 
+  touchableGetHitSlop: function(): ?Object {
+    return this.props.hitSlop;
+  },
+
   touchableGetHighlightDelayMS: function(): number {
     return this.props.delayPressIn || 0;
   },
@@ -140,6 +153,7 @@ var TouchableWithoutFeedback = React.createClass({
       accessibilityTraits: this.props.accessibilityTraits,
       testID: this.props.testID,
       onLayout: this.props.onLayout,
+      hitSlop: this.props.hitSlop,
       onStartShouldSetResponder: this.touchableHandleStartShouldSetResponder,
       onResponderTerminationRequest: this.touchableHandleResponderTerminationRequest,
       onResponderGrant: this.touchableHandleResponderGrant,
diff --git a/Libraries/Components/View/View.js b/Libraries/Components/View/View.js
index 8dc69534192b..20b9d9288344 100644
--- a/Libraries/Components/View/View.js
+++ b/Libraries/Components/View/View.js
@@ -11,6 +11,7 @@
  */
 'use strict';
 
+const EdgeInsetsPropType = require('EdgeInsetsPropType');
 const NativeMethodsMixin = require('NativeMethodsMixin');
 const PropTypes = require('ReactPropTypes');
 const React = require('React');
@@ -201,6 +202,19 @@ const View = React.createClass({
     onMoveShouldSetResponder: PropTypes.func,
     onMoveShouldSetResponderCapture: PropTypes.func,
 
+    /**
+     * This defines how far a touch event can start away from the view.
+     * Typical interface guidelines recommend touch targets that are at least
+     * 30 - 40 points/density-independent pixels. If a Touchable view has a
+     * height of 20 the touchable height can be extended to 40 with
+     * `hitSlop={{top: 10, bottom: 10, left: 0, right: 0}}`
+     * ** NOTE **
+     * The touch area never extends past the parent view bounds and the Z-index
+     * of sibling views always takes precedence if a touch hits two overlapping
+     * views.
+     */
+    hitSlop: EdgeInsetsPropType,
+
     /**
      * Invoked on mount and layout changes with
      *
diff --git a/React/Views/RCTView.h b/React/Views/RCTView.h
index 3f312abd1d87..7dc5bf3187ad 100644
--- a/React/Views/RCTView.h
+++ b/React/Views/RCTView.h
@@ -90,4 +90,9 @@
  */
 @property (nonatomic, assign) RCTBorderStyle borderStyle;
 
+/**
+ *  Insets used when hit testing inside this view.
+ */
+@property (nonatomic, assign) UIEdgeInsets hitTestEdgeInsets;
+
 @end
diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m
index 010c62c49293..ba0aa82a4337 100644
--- a/React/Views/RCTView.m
+++ b/React/Views/RCTView.m
@@ -109,6 +109,7 @@ - (instancetype)initWithFrame:(CGRect)frame
     _borderBottomLeftRadius = -1;
     _borderBottomRightRadius = -1;
     _borderStyle = RCTBorderStyleSolid;
+    _hitTestEdgeInsets = UIEdgeInsetsZero;
 
     _backgroundColor = super.backgroundColor;
   }
@@ -180,6 +181,15 @@ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
   }
 }
 
+- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
+{
+  if (UIEdgeInsetsEqualToEdgeInsets(self.hitTestEdgeInsets, UIEdgeInsetsZero)) {
+    return [super pointInside:point withEvent:event];
+  }
+  CGRect hitFrame = UIEdgeInsetsInsetRect(self.bounds, self.hitTestEdgeInsets);
+  return CGRectContainsPoint(hitFrame, point);
+}
+
 - (BOOL)accessibilityActivate
 {
   if (_onAccessibilityTap) {
diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m
index 5c5cb8f7c2d4..4bb2d7981d78 100644
--- a/React/Views/RCTViewManager.m
+++ b/React/Views/RCTViewManager.m
@@ -193,6 +193,17 @@ - (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(__unused NSDictio
     view.borderStyle = json ? [RCTConvert RCTBorderStyle:json] : defaultView.borderStyle;
   }
 }
+RCT_CUSTOM_VIEW_PROPERTY(hitSlop, UIEdgeInsets, RCTView)
+{
+  if ([view respondsToSelector:@selector(setHitTestEdgeInsets:)]) {
+    if (json) {
+      UIEdgeInsets hitSlopInsets = [RCTConvert UIEdgeInsets:json];
+      view.hitTestEdgeInsets = UIEdgeInsetsMake(-hitSlopInsets.top, -hitSlopInsets.left, -hitSlopInsets.bottom, -hitSlopInsets.right);
+    } else {
+      view.hitTestEdgeInsets = defaultView.hitTestEdgeInsets;
+    }
+  }
+}
 RCT_EXPORT_VIEW_PROPERTY(onAccessibilityTap, RCTDirectEventBlock)
 RCT_EXPORT_VIEW_PROPERTY(onMagicTap, RCTDirectEventBlock)
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/touch/ReactHitSlopView.java b/ReactAndroid/src/main/java/com/facebook/react/touch/ReactHitSlopView.java
new file mode 100644
index 000000000000..adda78ab020c
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/touch/ReactHitSlopView.java
@@ -0,0 +1,28 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.touch;
+
+import android.graphics.Rect;
+
+import javax.annotation.Nullable;
+
+/**
+ * This interface should be implemented by all {@link View} subclasses that want to use the
+ * hitSlop prop to extend their touch areas.
+ */
+public interface ReactHitSlopView {
+
+  /**
+   * Called when determining the touch area of a view.
+   * @return A {@link Rect} representing how far to extend the touch area in each direction.
+   */
+  public @Nullable Rect getHitSlopRect();
+
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java
index 9635d5bf6f1f..e998110b7bdc 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java
@@ -13,12 +13,14 @@
 
 import android.graphics.Matrix;
 import android.graphics.PointF;
+import android.graphics.Rect;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 
 import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
 import com.facebook.react.bridge.UiThreadUtil;
+import com.facebook.react.touch.ReactHitSlopView;
 
 /**
  * Class responsible for identifying which react view should handle a given {@link MotionEvent}.
@@ -118,7 +120,7 @@ private static View findTouchTargetView(float[] eventCoords, ViewGroup viewGroup
       }
     }
     return viewGroup;
-}
+  }
 
   /**
    * Returns whether the touch point is within the child View
@@ -144,12 +146,24 @@ private static boolean isTransformedTouchPointInView(
       localX = localXY[0];
       localY = localXY[1];
     }
-    if ((localX >= 0 && localX < (child.getRight() - child.getLeft()))
-        && (localY >= 0 && localY < (child.getBottom() - child.getTop()))) {
-      outLocalPoint.set(localX, localY);
-      return true;
+    if (child instanceof ReactHitSlopView && ((ReactHitSlopView) child).getHitSlopRect() != null) {
+      Rect hitSlopRect = ((ReactHitSlopView) child).getHitSlopRect();
+      if ((localX >= -hitSlopRect.left && localX < (child.getRight() - child.getLeft()) + hitSlopRect.right)
+          && (localY >= -hitSlopRect.top && localY < (child.getBottom() - child.getTop()) + hitSlopRect.bottom)) {
+        outLocalPoint.set(localX, localY);
+        return true;
+      }
+
+      return false;
+    } else {
+      if ((localX >= 0 && localX < (child.getRight() - child.getLeft()))
+          && (localY >= 0 && localY < (child.getBottom() - child.getTop()))) {
+        outLocalPoint.set(localX, localY);
+        return true;
+      }
+
+      return false;
     }
-    return false;
   }
 
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
index bf57e47a6554..fcd2fd5eb6f7 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java
@@ -23,6 +23,7 @@
 
 import com.facebook.infer.annotation.Assertions;
 import com.facebook.react.common.annotations.VisibleForTesting;
+import com.facebook.react.touch.ReactHitSlopView;
 import com.facebook.react.touch.ReactInterceptingViewGroup;
 import com.facebook.react.touch.OnInterceptTouchEventListener;
 import com.facebook.react.uimanager.MeasureSpecAssertions;
@@ -34,7 +35,7 @@
  * initializes most of the storage needed for them.
  */
 public class ReactViewGroup extends ViewGroup implements
-    ReactInterceptingViewGroup, ReactClippingViewGroup, ReactPointerEventsView {
+    ReactInterceptingViewGroup, ReactClippingViewGroup, ReactPointerEventsView, ReactHitSlopView {
 
   private static final int ARRAY_CAPACITY_INCREMENT = 12;
   private static final int DEFAULT_BACKGROUND_COLOR = Color.TRANSPARENT;
@@ -87,6 +88,7 @@ public void onLayoutChange(
   private @Nullable View[] mAllChildren = null;
   private int mAllChildrenCount;
   private @Nullable Rect mClippingRect;
+  private @Nullable Rect mHitSlopRect;
   private PointerEvents mPointerEvents = PointerEvents.AUTO;
   private @Nullable ChildrenLayoutChangeListener mChildrenLayoutChangeListener;
   private @Nullable ReactViewBackgroundDrawable mReactBackgroundDrawable;
@@ -513,4 +515,13 @@ private ReactViewBackgroundDrawable getOrCreateReactViewBackground() {
     return mReactBackgroundDrawable;
   }
 
+  @Override
+  public @Nullable Rect getHitSlopRect() {
+    return mHitSlopRect;
+  }
+
+  public void setHitSlopRect(@Nullable Rect rect) {
+    mHitSlopRect = rect;
+  }
+
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
index 789b294e1f94..6a4bd5d26491 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java
@@ -14,6 +14,7 @@
 import java.util.Locale;
 import java.util.Map;
 
+import android.graphics.Rect;
 import android.os.Build;
 import android.view.View;
 
@@ -75,6 +76,20 @@ public void setBorderStyle(ReactViewGroup view, @Nullable String borderStyle) {
     view.setBorderStyle(borderStyle);
   }
 
+  @ReactProp(name = "hitSlop")
+  public void setHitSlop(final ReactViewGroup view, @Nullable ReadableMap hitSlop) {
+    if (hitSlop == null) {
+      view.setHitSlopRect(null);
+    } else {
+      view.setHitSlopRect(new Rect(
+          (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("left")),
+          (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("top")),
+          (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("right")),
+          (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("bottom"))
+      ));
+    }
+  }
+
   @ReactProp(name = "pointerEvents")
   public void setPointerEvents(ReactViewGroup view, @Nullable String pointerEventsStr) {
     if (pointerEventsStr != null) {

From 1172e6478f86c1766ee1cb64f4b9b487853c9d13 Mon Sep 17 00:00:00 2001
From: Josh Buchea <verctrl@joshbuchea.com>
Date: Tue, 16 Feb 2016 17:03:41 -0800
Subject: [PATCH 1192/1411] Add missing comma

Summary: Closes https://github.com/facebook/react-native/pull/5965

Differential Revision: D2941870

Pulled By: androidtrunkagent

fb-gh-sync-id: efec0b07dd9614fc4d3937a290c3f243cba46718
shipit-source-id: efec0b07dd9614fc4d3937a290c3f243cba46718
---
 website/src/react-native/showcase.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 6b16397699af..e6974558c7cf 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -380,7 +380,7 @@ var apps = [
     icon: 'http://a3.mzstatic.com/us/r30/Purple69/v4/a2/61/58/a261584d-a4cd-cbfa-cf9d-b5f1f15a7139/icon175x175.jpeg',
     link: 'https://itunes.apple.com/app/id1031729525?mt=8&at=11l7ss&ct=reactnativeshowcase',
     author: 'Josh Buchea',
-  }
+  },
   {
     name: 'MyPED',
     icon: 'http://a2.mzstatic.com/eu/r30/Purple69/v4/88/1f/fb/881ffb3b-7986-d427-7fcf-eb5920a883af/icon175x175.png',

From dab24b4a6c2b4911c9af72ee88456804f71a2f2d Mon Sep 17 00:00:00 2001
From: Walter Luh <wluh@fb.com>
Date: Tue, 16 Feb 2016 23:04:18 -0800
Subject: [PATCH 1193/1411] Enable persistent socket between packager and
 bridge (1/N).

Reviewed By: javache

Differential Revision: D2920590

fb-gh-sync-id: 120d812d1e9bcb79b186d3e41e8f7e153ca34f8b
shipit-source-id: 120d812d1e9bcb79b186d3e41e8f7e153ca34f8b
---
 Libraries/WebSocket/RCTWebSocketManager.h |  19 +++
 Libraries/WebSocket/RCTWebSocketManager.m | 143 ++++++++++++++++++++++
 React/Base/RCTWebSocketProxy.h            |  26 ++++
 React/Base/RCTWebSocketProxyDelegate.h    |  20 +++
 React/Modules/RCTDevMenu.m                |  52 +++++++-
 5 files changed, 259 insertions(+), 1 deletion(-)
 create mode 100644 Libraries/WebSocket/RCTWebSocketManager.h
 create mode 100644 Libraries/WebSocket/RCTWebSocketManager.m
 create mode 100644 React/Base/RCTWebSocketProxy.h
 create mode 100644 React/Base/RCTWebSocketProxyDelegate.h

diff --git a/Libraries/WebSocket/RCTWebSocketManager.h b/Libraries/WebSocket/RCTWebSocketManager.h
new file mode 100644
index 000000000000..debc3f7676f3
--- /dev/null
+++ b/Libraries/WebSocket/RCTWebSocketManager.h
@@ -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.
+ */
+
+#import "RCTDefines.h"
+
+#if RCT_DEV // Only supported in dev mode
+
+#import "RCTWebSocketProxy.h"
+
+@interface RCTWebSocketManager : NSObject <RCTWebSocketProxy>
+@end
+
+#endif
diff --git a/Libraries/WebSocket/RCTWebSocketManager.m b/Libraries/WebSocket/RCTWebSocketManager.m
new file mode 100644
index 000000000000..7288dda09765
--- /dev/null
+++ b/Libraries/WebSocket/RCTWebSocketManager.m
@@ -0,0 +1,143 @@
+/**
+ * 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.
+ */
+
+#import "RCTDefines.h"
+
+#if RCT_DEV // Only supported in dev mode
+
+#import "RCTWebSocketManager.h"
+
+#import "RCTConvert.h"
+#import "RCTLog.h"
+#import "RCTUtils.h"
+#import "RCTSRWebSocket.h"
+
+#pragma mark - RCTWebSocketObserver
+
+@interface RCTWebSocketObserver : NSObject <RCTSRWebSocketDelegate>
+
+@property (nonatomic, strong) RCTSRWebSocket *socket;
+@property (nonatomic, weak) id<RCTWebSocketProxyDelegate> delegate;
+@property (nonatomic, strong) dispatch_semaphore_t socketOpenSemaphore;
+
+- (instancetype)initWithURL:(NSURL *)url delegate:(id<RCTWebSocketProxyDelegate>)delegate;
+
+@end
+
+@implementation RCTWebSocketObserver
+
+- (instancetype)initWithURL:(NSURL *)url delegate:(id<RCTWebSocketProxyDelegate>)delegate
+{
+  if ((self = [self init])) {
+    _socket = [[RCTSRWebSocket alloc] initWithURL:url];
+    _socket.delegate = self;
+
+    _delegate = delegate;
+}
+  return self;
+}
+
+- (void)start
+{
+  _socketOpenSemaphore = dispatch_semaphore_create(0);
+  [_socket open];
+  dispatch_semaphore_wait(_socketOpenSemaphore, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 2));
+}
+
+- (void)stop
+{
+  _socket.delegate = nil;
+  [_socket closeWithCode:1000 reason:@"Invalidated"];
+  _socket = nil;
+}
+
+- (void)webSocket:(RCTSRWebSocket *)webSocket didReceiveMessage:(id)message
+{
+  if (_delegate) {
+    NSError *error = nil;
+    NSDictionary<NSString *, id> *msg = RCTJSONParse(message, &error);
+
+    if (!error) {
+      [_delegate socketProxy:[RCTWebSocketManager sharedInstance] didReceiveMessage:msg];
+    } else {
+      RCTLogError(@"WebSocketManager failed to parse message with error %@\n<message>\n%@\n</message>", error, message);
+    }
+  }
+}
+
+- (void)webSocketDidOpen:(RCTSRWebSocket *)webSocket
+{
+  dispatch_semaphore_signal(_socketOpenSemaphore);
+}
+
+- (void)webSocket:(RCTSRWebSocket *)webSocket didFailWithError:(NSError *)error
+{
+  dispatch_semaphore_signal(_socketOpenSemaphore);
+  dispatch_async(dispatch_get_main_queue(), ^{
+    // Give the setUp method an opportunity to report an error first
+    RCTLogError(@"WebSocket connection failed with error %@", error);
+  });
+}
+
+@end
+
+#pragma mark - RCTWebSocketManager
+
+@interface RCTWebSocketManager()
+
+@property (nonatomic, strong) NSMutableDictionary *sockets;
+@property (nonatomic, strong) dispatch_queue_t queue;
+
+@end
+
+@implementation RCTWebSocketManager
+
++ (instancetype)sharedInstance
+{
+  static RCTWebSocketManager *sharedInstance = nil;
+  static dispatch_once_t onceToken;
+
+  dispatch_once(&onceToken, ^{
+    sharedInstance = [self new];
+  });
+
+  return sharedInstance;
+}
+
+- (void)setDelegate:(id<RCTWebSocketProxyDelegate>)delegate forURL:(NSURL *)url
+{
+  NSString *key = [url absoluteString];
+  RCTWebSocketObserver *observer = _sockets[key];
+
+  if (observer) {
+    if (!delegate) {
+      [observer stop];
+      [_sockets removeObjectForKey:key];
+    } else {
+      observer.delegate = delegate;
+    }
+  } else {
+    RCTWebSocketObserver *newObserver = [[RCTWebSocketObserver alloc] initWithURL:url delegate:delegate];
+    [newObserver start];
+    _sockets[key] = newObserver;
+  }
+}
+
+- (instancetype)init
+{
+  if ((self = [super init])) {
+    _sockets = [NSMutableDictionary new];
+    _queue = dispatch_queue_create("com.facebook.React.WebSocketManager", DISPATCH_QUEUE_SERIAL);
+  }
+  return self;
+}
+
+@end
+
+#endif
diff --git a/React/Base/RCTWebSocketProxy.h b/React/Base/RCTWebSocketProxy.h
new file mode 100644
index 000000000000..e823c3c8fe68
--- /dev/null
+++ b/React/Base/RCTWebSocketProxy.h
@@ -0,0 +1,26 @@
+/**
+ * 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.
+ */
+
+#import "RCTDefines.h"
+
+#if RCT_DEV // Only supported in dev mode
+
+#import "RCTWebSocketProxyDelegate.h"
+
+@protocol RCTWebSocketProxy
+
++ (instancetype)sharedInstance;
+
+- (void)setDelegate:(id<RCTWebSocketProxyDelegate>)delegate forURL:(NSURL *)url;
+
+- (instancetype) init   __attribute__((unavailable("init not available, call sharedInstance instead")));
+
+@end
+
+#endif
diff --git a/React/Base/RCTWebSocketProxyDelegate.h b/React/Base/RCTWebSocketProxyDelegate.h
new file mode 100644
index 000000000000..f668bf1610a3
--- /dev/null
+++ b/React/Base/RCTWebSocketProxyDelegate.h
@@ -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.
+ */
+
+#import "RCTDefines.h"
+
+#if RCT_DEV // Only supported in dev mode
+
+@protocol RCTWebSocketProxy;
+
+@protocol RCTWebSocketProxyDelegate
+- (void)socketProxy:(id<RCTWebSocketProxy>)sender didReceiveMessage:(NSDictionary<NSString *, id> *)message;
+@end
+
+#endif
diff --git a/React/Modules/RCTDevMenu.m b/React/Modules/RCTDevMenu.m
index c3a47cb27497..69773d26ca7a 100644
--- a/React/Modules/RCTDevMenu.m
+++ b/React/Modules/RCTDevMenu.m
@@ -19,6 +19,7 @@
 #import "RCTRootView.h"
 #import "RCTSourceCode.h"
 #import "RCTUtils.h"
+#import "RCTWebSocketProxy.h"
 
 #if RCT_DEV
 
@@ -117,7 +118,7 @@ - (void)callHandler
 
 @end
 
-@interface RCTDevMenu () <RCTBridgeModule, UIActionSheetDelegate, RCTInvalidating>
+@interface RCTDevMenu () <RCTBridgeModule, UIActionSheetDelegate, RCTInvalidating, RCTWebSocketProxyDelegate>
 
 @property (nonatomic, strong) Class executorClass;
 
@@ -194,6 +195,7 @@ - (instancetype)init
     // Delay setup until after Bridge init
     dispatch_async(dispatch_get_main_queue(), ^{
       [weakSelf updateSettings:_settings];
+      [weakSelf connectPackager];
     });
 
 #if TARGET_IPHONE_SIMULATOR
@@ -228,6 +230,54 @@ - (instancetype)init
   return self;
 }
 
+- (NSURL *)packagerURL
+{
+  NSString *host = [_bridge.bundleURL host];
+  if (!host) {
+    return nil;
+  }
+
+  NSString *scheme = [_bridge.bundleURL scheme];
+  NSNumber *port = [_bridge.bundleURL port];
+  return [NSURL URLWithString:[NSString stringWithFormat:@"%@://%@:%@/packager-proxy?role=client", scheme, host, port]];
+}
+
+// TODO: Move non-UI logic into separate RCTDevSettings module
+- (void)connectPackager
+{
+  Class webSocketManagerClass = NSClassFromString(@"RCTWebSocketManager");
+  id<RCTWebSocketProxy> webSocketManager = (id <RCTWebSocketProxy>)[webSocketManagerClass sharedInstance];
+  NSURL *url = [self packagerURL];
+  if (url) {
+    [webSocketManager setDelegate:self forURL:url];
+  }
+}
+
+- (BOOL)isSupportedVersion:(NSNumber *)version
+{
+  NSArray<NSNumber *> *const kSupportedVersions = @[ @1 ];
+  return [kSupportedVersions containsObject:version];
+}
+
+- (void)socketProxy:(id<RCTWebSocketProxy>)sender didReceiveMessage:(NSDictionary<NSString *, id> *)message
+{
+  if ([self isSupportedVersion:message[@"version"]]) {
+    [self processTarget:message[@"target"] action:message[@"action"] options:message[@"options"]];
+  }
+}
+
+- (void)processTarget:(NSString *)target action:(NSString *)action options:(NSDictionary<NSString *, id> *)options
+{
+  if ([target isEqualToString:@"bridge"]) {
+    if ([action isEqualToString:@"reload"]) {
+      if ([options[@"debug"] boolValue]) {
+        _bridge.executorClass = NSClassFromString(@"RCTWebSocketExecutor");
+      }
+      [_bridge reload];
+    }
+  }
+}
+
 - (dispatch_queue_t)methodQueue
 {
   return dispatch_get_main_queue();

From d8e07eab9527faa41c74657fb6ed25892a2acf5f Mon Sep 17 00:00:00 2001
From: Sreejumon <spurayil@imprivata.com>
Date: Tue, 16 Feb 2016 23:58:49 -0800
Subject: [PATCH 1194/1411] XMLHttpRequest.DONE is not defined. Fixes #5883

Summary:https://github.com/facebook/react-native/issues/5883
Closes https://github.com/facebook/react-native/pull/5895

Differential Revision: D2943443

Pulled By: androidtrunkagent

fb-gh-sync-id: 1c1c1d69dd0ad4fb28f23fa956d843464f693b43
shipit-source-id: 1c1c1d69dd0ad4fb28f23fa956d843464f693b43
---
 Libraries/Network/XMLHttpRequestBase.js | 28 ++++++++++++++++++++-----
 1 file changed, 23 insertions(+), 5 deletions(-)

diff --git a/Libraries/Network/XMLHttpRequestBase.js b/Libraries/Network/XMLHttpRequestBase.js
index 29073b7d1ca2..14e284ae596a 100644
--- a/Libraries/Network/XMLHttpRequestBase.js
+++ b/Libraries/Network/XMLHttpRequestBase.js
@@ -14,11 +14,23 @@
 var RCTNetworking = require('RCTNetworking');
 var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
 
+const UNSENT = 0;
+const OPENED = 1;
+const HEADERS_RECEIVED = 2;
+const LOADING = 3;
+const DONE = 4;
+
 /**
  * Shared base for platform-specific XMLHttpRequest implementations.
  */
 class XMLHttpRequestBase {
 
+  static UNSENT: number;
+  static OPENED: number;
+  static HEADERS_RECEIVED: number;
+  static LOADING: number;
+  static DONE: number;
+
   UNSENT: number;
   OPENED: number;
   HEADERS_RECEIVED: number;
@@ -50,11 +62,11 @@ class XMLHttpRequestBase {
   _lowerCaseResponseHeaders: Object;
 
   constructor() {
-    this.UNSENT = 0;
-    this.OPENED = 1;
-    this.HEADERS_RECEIVED = 2;
-    this.LOADING = 3;
-    this.DONE = 4;
+    this.UNSENT = UNSENT;
+    this.OPENED = OPENED;
+    this.HEADERS_RECEIVED = HEADERS_RECEIVED;
+    this.LOADING = LOADING;
+    this.DONE = DONE;
 
     this.onreadystatechange = null;
     this.onload = null;
@@ -265,4 +277,10 @@ class XMLHttpRequestBase {
   }
 }
 
+XMLHttpRequestBase.UNSENT = UNSENT;
+XMLHttpRequestBase.OPENED = OPENED;
+XMLHttpRequestBase.HEADERS_RECEIVED = HEADERS_RECEIVED;
+XMLHttpRequestBase.LOADING = LOADING;
+XMLHttpRequestBase.DONE = DONE;
+
 module.exports = XMLHttpRequestBase;

From 011dc8904fffba4cb0c87994fe6787d99664d457 Mon Sep 17 00:00:00 2001
From: Hedger Wang <hedger@fb.com>
Date: Wed, 17 Feb 2016 02:28:29 -0800
Subject: [PATCH 1195/1411] Unbreak master build.

Summary:public

== cause ==

The follow block is error-prone.

```
 for (ReactInstanceEventListener listener : mReactInstanceEventListeners) {
   listener.onReactContextInitialized(reactContext);
 }
```

Because calling `listener.onReactContextInitialized` may have side-effect that
removes the `listener` from `mReactInstanceEventListeners`, thus break the
iteration with exception.

I've found at least one place that has such side-effect
diffusion/FA/browse/master/java/com/facebook/fbreact/autoupdater/AutoUpdaterScheduler.java;9c09e5bbd411e093fb2ad022ee5d0ea473e9ebfe$32

The right way to fix this is to be side-effect proof.

Reviewed By: zahanm

Differential Revision: D2943494

fb-gh-sync-id: ba848ea736c5d2d0b8ef0b5a899603d734781361
shipit-source-id: ba848ea736c5d2d0b8ef0b5a899603d734781361
---
 .../java/com/facebook/react/ReactInstanceManagerImpl.java   | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index 88a064c6cd0c..1b8ac840abfa 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -663,7 +663,11 @@ private void setupReactContext(ReactApplicationContext reactContext) {
       attachMeasuredRootViewToInstance(rootView, catalystInstance);
     }
 
-    for (ReactInstanceEventListener listener : mReactInstanceEventListeners) {
+    ReactInstanceEventListener[] listeners =
+      new ReactInstanceEventListener[mReactInstanceEventListeners.size()];
+    listeners = mReactInstanceEventListeners.toArray(listeners);
+
+    for (ReactInstanceEventListener listener : listeners) {
       listener.onReactContextInitialized(reactContext);
     }
   }

From d0f1466cddd77685e68f54046eaeaacd36e226e1 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Wed, 17 Feb 2016 04:04:59 -0800
Subject: [PATCH 1196/1411] Default javaScriptEnabled to true

Summary:public
Default javaScriptEnabled to true on Android WebView
Also remove an old (about 6 weeks old) warning about a back compat supported property

Reviewed By: nicklockwood

Differential Revision: D2939482

fb-gh-sync-id: 2d476c3365f657da27ea370a033b23154750c2ea
shipit-source-id: 2d476c3365f657da27ea370a033b23154750c2ea
---
 .../Components/WebView/WebView.android.js     | 20 ++++++++-----------
 Libraries/Components/WebView/WebView.ios.js   | 10 ----------
 2 files changed, 8 insertions(+), 22 deletions(-)

diff --git a/Libraries/Components/WebView/WebView.android.js b/Libraries/Components/WebView/WebView.android.js
index 2c8e2312d5a2..e9577463fddb 100644
--- a/Libraries/Components/WebView/WebView.android.js
+++ b/Libraries/Components/WebView/WebView.android.js
@@ -142,6 +142,12 @@ var WebView = React.createClass({
     };
   },
 
+  getDefaultProps: function() {
+    return {
+      javaScriptEnabled : true,
+    };
+  },
+
   componentWillMount: function() {
     if (this.props.startInLoadingState) {
       this.setState({viewState: WebViewState.LOADING});
@@ -170,16 +176,6 @@ var WebView = React.createClass({
       webViewStyles.push(styles.hidden);
     }
 
-    var {javaScriptEnabled, domStorageEnabled} = this.props;
-    if (this.props.javaScriptEnabledAndroid) {
-      console.warn('javaScriptEnabledAndroid is deprecated. Use javaScriptEnabled instead');
-      javaScriptEnabled = this.props.javaScriptEnabledAndroid;
-    }
-    if (this.props.domStorageEnabledAndroid) {
-      console.warn('domStorageEnabledAndroid is deprecated. Use domStorageEnabled instead');
-      domStorageEnabled = this.props.domStorageEnabledAndroid;
-    }
-
     var source = this.props.source || {};
     if (this.props.html) {
       source.html = this.props.html;
@@ -201,8 +197,8 @@ var WebView = React.createClass({
         source={resolveAssetSource(source)}
         injectedJavaScript={this.props.injectedJavaScript}
         userAgent={this.props.userAgent}
-        javaScriptEnabled={javaScriptEnabled}
-        domStorageEnabled={domStorageEnabled}
+        javaScriptEnabled={this.props.javaScriptEnabled}
+        domStorageEnabled={this.props.domStorageEnabled}
         contentInset={this.props.contentInset}
         automaticallyAdjustContentInsets={this.props.automaticallyAdjustContentInsets}
         onLoadingStart={this.onLoadingStart}
diff --git a/Libraries/Components/WebView/WebView.ios.js b/Libraries/Components/WebView/WebView.ios.js
index 3b37331ae2b0..ec63402139fe 100644
--- a/Libraries/Components/WebView/WebView.ios.js
+++ b/Libraries/Components/WebView/WebView.ios.js
@@ -285,16 +285,6 @@ var WebView = React.createClass({
       RCTWebViewManager.startLoadWithResult(!!shouldStart, event.nativeEvent.lockIdentifier);
     });
 
-    var {javaScriptEnabled, domStorageEnabled} = this.props;
-    if (this.props.javaScriptEnabledAndroid) {
-      console.warn('javaScriptEnabledAndroid is deprecated. Use javaScriptEnabled instead');
-      javaScriptEnabled = this.props.javaScriptEnabledAndroid;
-    }
-    if (this.props.domStorageEnabledAndroid) {
-      console.warn('domStorageEnabledAndroid is deprecated. Use domStorageEnabled instead');
-      domStorageEnabled = this.props.domStorageEnabledAndroid;
-    }
-
     var decelerationRate = processDecelerationRate(this.props.decelerationRate);
 
     var source = this.props.source || {};

From 1e8991aa80c88629ed2bb7ae79ced79317017e96 Mon Sep 17 00:00:00 2001
From: Chris Hopman <cjhopman@fb.com>
Date: Wed, 17 Feb 2016 04:07:30 -0800
Subject: [PATCH 1197/1411] Add android ndk dep

Reviewed By: astreet

Differential Revision: D2943695

fb-gh-sync-id: a444b2506b7aadd200f5cd0fef626ce7fe66c660
shipit-source-id: a444b2506b7aadd200f5cd0fef626ce7fe66c660
---
 ReactAndroid/src/main/jni/react/Android.mk | 1 +
 ReactAndroid/src/main/jni/react/BUCK       | 1 +
 2 files changed, 2 insertions(+)

diff --git a/ReactAndroid/src/main/jni/react/Android.mk b/ReactAndroid/src/main/jni/react/Android.mk
index 073d091577cc..cafcb591b878 100644
--- a/ReactAndroid/src/main/jni/react/Android.mk
+++ b/ReactAndroid/src/main/jni/react/Android.mk
@@ -19,6 +19,7 @@ LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
 LOCAL_CFLAGS := \
   -DLOG_TAG=\"ReactNative\"
 
+LOCAL_LDLIBS += -landroid
 LOCAL_CFLAGS += -Wall -Werror -fexceptions -frtti
 CXX11_FLAGS := -std=c++11
 LOCAL_CFLAGS += $(CXX11_FLAGS)
diff --git a/ReactAndroid/src/main/jni/react/BUCK b/ReactAndroid/src/main/jni/react/BUCK
index ffa06d775025..c5b7d646221f 100644
--- a/ReactAndroid/src/main/jni/react/BUCK
+++ b/ReactAndroid/src/main/jni/react/BUCK
@@ -4,6 +4,7 @@ include_defs('//ReactAndroid/DEFS')
 SUPPORTED_PLATFORMS = '^android-(armv7|x86)$'
 
 DEPS = [
+  '//native/third-party/android-ndk:android',
   '//xplat/fbsystrace:fbsystrace',
   '//xplat/folly:molly',
   '//xplat/third-party/glog:glog',

From f73f41779a5698043e33c2621e05ca975d07e501 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Wed, 17 Feb 2016 07:30:04 -0800
Subject: [PATCH 1198/1411] Fixed relative links in generated docs

Summary:Relative links did not have 'docs/' prefix, so all of them lead to 404 page.
Fixes #5964
Closes https://github.com/facebook/react-native/pull/5975

Differential Revision: D2943886

Pulled By: androidtrunkagent

fb-gh-sync-id: dbc2355ecf7ea4f1dea0f8f6a5ef50e5f324dfda
shipit-source-id: dbc2355ecf7ea4f1dea0f8f6a5ef50e5f324dfda
---
 website/layout/AutodocsLayout.js | 10 +++++-----
 website/layout/DocsLayout.js     |  4 ++--
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/website/layout/AutodocsLayout.js b/website/layout/AutodocsLayout.js
index 7ac083bc05df..036ca0973137 100644
--- a/website/layout/AutodocsLayout.js
+++ b/website/layout/AutodocsLayout.js
@@ -56,10 +56,10 @@ function renderType(type) {
   if (type.name === 'custom') {
     if (styleReferencePattern.test(type.raw)) {
       var name = type.raw.substring(0, type.raw.indexOf('.'));
-      return <a href={slugify(name) + '.html#style'}>{name}#style</a>
+      return <a href={'docs/' + slugify(name) + '.html#style'}>{name}#style</a>
     }
     if (type.raw === 'ColorPropType') {
-      return <a href={'colors.html'}>color</a>
+      return <a href={'docs/colors.html'}>color</a>
     }
     if (type.raw === 'EdgeInsetsPropType') {
       return '{top: number, left: number, bottom: number, right: number}';
@@ -140,7 +140,7 @@ var ComponentDoc = React.createClass({
     return (
       <div className="prop" key={name}>
         <Header level={4} className="propTitle" toSlug={name}>
-          <a href={slugify(name) + '.html#props'}>{name} props...</a>
+          <a href={'docs/' + slugify(name) + '.html#props'}>{name} props...</a>
         </Header>
       </div>
     );
@@ -506,8 +506,8 @@ var Autodocs = React.createClass({
             {this.renderFullDescription(docs)}
             {this.renderExample(docs, metadata)}
             <div className="docs-prevnext">
-              {metadata.previous && <a className="docs-prev" href={metadata.previous + '.html#content'}>&larr; Prev</a>}
-              {metadata.next && <a className="docs-next" href={metadata.next + '.html#content'}>Next &rarr;</a>}
+              {metadata.previous && <a className="docs-prev" href={'docs/' + metadata.previous + '.html#content'}>&larr; Prev</a>}
+              {metadata.next && <a className="docs-next" href={'docs/' + metadata.next + '.html#content'}>Next &rarr;</a>}
             </div>
           </div>
 
diff --git a/website/layout/DocsLayout.js b/website/layout/DocsLayout.js
index 673496938b65..d92b5d06ebc8 100644
--- a/website/layout/DocsLayout.js
+++ b/website/layout/DocsLayout.js
@@ -32,8 +32,8 @@ var DocsLayout = React.createClass({
             />
             <Marked>{content}</Marked>
             <div className="docs-prevnext">
-              {metadata.previous && <a className="docs-prev" href={metadata.previous + '.html#content'}>&larr; Prev</a>}
-              {metadata.next && <a className="docs-next" href={metadata.next + '.html#content'}>Next &rarr;</a>}
+              {metadata.previous && <a className="docs-prev" href={'docs/' + metadata.previous + '.html#content'}>&larr; Prev</a>}
+              {metadata.next && <a className="docs-next" href={'docs/' + metadata.next + '.html#content'}>Next &rarr;</a>}
             </div>
           </div>
         </section>

From f9e81d9bccc2960be28e4583120dba28deab6276 Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Wed, 17 Feb 2016 07:38:11 -0800
Subject: [PATCH 1199/1411] Fix OSS iOS build

Reviewed By: majak

Differential Revision: D2943923

fb-gh-sync-id: d0a827780ee93a1e702295198c65729b1a72f045
shipit-source-id: d0a827780ee93a1e702295198c65729b1a72f045
---
 .../RCTWebSocket.xcodeproj/project.pbxproj         |  6 ++++++
 React/Modules/RCTDevMenu.m                         |  2 +-
 React/React.xcodeproj/project.pbxproj              | 14 +++++++++-----
 3 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/Libraries/WebSocket/RCTWebSocket.xcodeproj/project.pbxproj b/Libraries/WebSocket/RCTWebSocket.xcodeproj/project.pbxproj
index 62dbee6a7606..b1a875706918 100644
--- a/Libraries/WebSocket/RCTWebSocket.xcodeproj/project.pbxproj
+++ b/Libraries/WebSocket/RCTWebSocket.xcodeproj/project.pbxproj
@@ -10,6 +10,7 @@
 		1338BBE01B04ACC80064A9C9 /* RCTSRWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 1338BBDD1B04ACC80064A9C9 /* RCTSRWebSocket.m */; };
 		1338BBE11B04ACC80064A9C9 /* RCTWebSocketExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 1338BBDF1B04ACC80064A9C9 /* RCTWebSocketExecutor.m */; };
 		3C86DF7C1ADF695F0047B81A /* RCTWebSocketModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C86DF7B1ADF695F0047B81A /* RCTWebSocketModule.m */; };
+		3DB9106F1C74B1ED00838BBE /* RCTWebSocketManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DB9106E1C74B1ED00838BBE /* RCTWebSocketManager.m */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
@@ -20,6 +21,8 @@
 		3C86DF461ADF2C930047B81A /* libRCTWebSocket.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTWebSocket.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		3C86DF7A1ADF695F0047B81A /* RCTWebSocketModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebSocketModule.h; sourceTree = "<group>"; };
 		3C86DF7B1ADF695F0047B81A /* RCTWebSocketModule.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = RCTWebSocketModule.m; sourceTree = "<group>"; tabWidth = 2; };
+		3DB9106D1C74B1ED00838BBE /* RCTWebSocketManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebSocketManager.h; sourceTree = "<group>"; };
+		3DB9106E1C74B1ED00838BBE /* RCTWebSocketManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWebSocketManager.m; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -40,6 +43,8 @@
 				1338BBDD1B04ACC80064A9C9 /* RCTSRWebSocket.m */,
 				1338BBDE1B04ACC80064A9C9 /* RCTWebSocketExecutor.h */,
 				1338BBDF1B04ACC80064A9C9 /* RCTWebSocketExecutor.m */,
+				3DB9106D1C74B1ED00838BBE /* RCTWebSocketManager.h */,
+				3DB9106E1C74B1ED00838BBE /* RCTWebSocketManager.m */,
 				3C86DF7A1ADF695F0047B81A /* RCTWebSocketModule.h */,
 				3C86DF7B1ADF695F0047B81A /* RCTWebSocketModule.m */,
 				3C86DF471ADF2C930047B81A /* Products */,
@@ -114,6 +119,7 @@
 				1338BBE01B04ACC80064A9C9 /* RCTSRWebSocket.m in Sources */,
 				3C86DF7C1ADF695F0047B81A /* RCTWebSocketModule.m in Sources */,
 				1338BBE11B04ACC80064A9C9 /* RCTWebSocketExecutor.m in Sources */,
+				3DB9106F1C74B1ED00838BBE /* RCTWebSocketManager.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
diff --git a/React/Modules/RCTDevMenu.m b/React/Modules/RCTDevMenu.m
index 69773d26ca7a..30f3eff94205 100644
--- a/React/Modules/RCTDevMenu.m
+++ b/React/Modules/RCTDevMenu.m
@@ -259,7 +259,7 @@ - (BOOL)isSupportedVersion:(NSNumber *)version
   return [kSupportedVersions containsObject:version];
 }
 
-- (void)socketProxy:(id<RCTWebSocketProxy>)sender didReceiveMessage:(NSDictionary<NSString *, id> *)message
+- (void)socketProxy:(__unused id<RCTWebSocketProxy>)sender didReceiveMessage:(NSDictionary<NSString *, id> *)message
 {
   if ([self isSupportedVersion:message[@"version"]]) {
     [self processTarget:message[@"target"] action:message[@"action"] options:message[@"options"]];
diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj
index 40147b76de6f..30a1710b4a48 100644
--- a/React/React.xcodeproj/project.pbxproj
+++ b/React/React.xcodeproj/project.pbxproj
@@ -251,6 +251,8 @@
 		191E3EC01C29DC3800C180A6 /* RCTRefreshControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRefreshControl.m; sourceTree = "<group>"; };
 		391E86A21C623EC800009732 /* RCTTouchEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTouchEvent.m; sourceTree = "<group>"; };
 		391E86A31C623EC800009732 /* RCTTouchEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTouchEvent.h; sourceTree = "<group>"; };
+		3DB910701C74B21600838BBE /* RCTWebSocketProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebSocketProxy.h; sourceTree = "<group>"; };
+		3DB910711C74B21600838BBE /* RCTWebSocketProxyDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebSocketProxyDelegate.h; sourceTree = "<group>"; };
 		58114A121AAE854800E7D092 /* RCTPicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPicker.h; sourceTree = "<group>"; };
 		58114A131AAE854800E7D092 /* RCTPicker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPicker.m; sourceTree = "<group>"; };
 		58114A141AAE854800E7D092 /* RCTPickerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPickerManager.h; sourceTree = "<group>"; };
@@ -511,15 +513,15 @@
 		83CBBA491A601E3B00E9B192 /* Base */ = {
 			isa = PBXGroup;
 			children = (
-				6A15FB0C1BDF663500531DFB /* RCTRootViewInternal.h */,
 				83CBBA4A1A601E3B00E9B192 /* RCTAssert.h */,
 				83CBBA4B1A601E3B00E9B192 /* RCTAssert.m */,
 				14C2CA771B3ACB0400E6CBB2 /* RCTBatchedBridge.m */,
 				83CBBA5E1A601EAA00E9B192 /* RCTBridge.h */,
 				83CBBA5F1A601EAA00E9B192 /* RCTBridge.m */,
+				14A43DB81C1F849600794BC8 /* RCTBridge+Private.h */,
 				1482F9E61B55B927000ADFF3 /* RCTBridgeDelegate.h */,
-				830213F31A654E0800B993E6 /* RCTBridgeModule.h */,
 				13AFBCA11C07287B00BBAEAA /* RCTBridgeMethod.h */,
+				830213F31A654E0800B993E6 /* RCTBridgeModule.h */,
 				83CBBACA1A6023D300E9B192 /* RCTConvert.h */,
 				83CBBACB1A6023D300E9B192 /* RCTConvert.m */,
 				13AF1F851AE6E777005F5298 /* RCTDefines.h */,
@@ -527,6 +529,8 @@
 				83CBBA661A601EF300E9B192 /* RCTEventDispatcher.m */,
 				1436DD071ADE7AA000A5ED7D /* RCTFrameUpdate.h */,
 				14C2CA751B3AC64F00E6CBB2 /* RCTFrameUpdate.m */,
+				13BB3D001BECD54500932C10 /* RCTImageSource.h */,
+				13BB3D011BECD54500932C10 /* RCTImageSource.m */,
 				83CBBA4C1A601E3B00E9B192 /* RCTInvalidating.h */,
 				83CBBA631A601ECA00E9B192 /* RCTJavaScriptExecutor.h */,
 				14200DA81AC179B3008EE6BA /* RCTJavaScriptLoader.h */,
@@ -549,6 +553,7 @@
 				830A229C1A66C68A008503DA /* RCTRootView.h */,
 				830A229D1A66C68A008503DA /* RCTRootView.m */,
 				13AFBCA21C07287B00BBAEAA /* RCTRootViewDelegate.h */,
+				6A15FB0C1BDF663500531DFB /* RCTRootViewInternal.h */,
 				391E86A31C623EC800009732 /* RCTTouchEvent.h */,
 				391E86A21C623EC800009732 /* RCTTouchEvent.m */,
 				83CBBA961A6020BB00E9B192 /* RCTTouchHandler.h */,
@@ -557,9 +562,8 @@
 				1345A83B1B265A0E00583190 /* RCTURLRequestHandler.h */,
 				83CBBA4F1A601E3B00E9B192 /* RCTUtils.h */,
 				83CBBA501A601E3B00E9B192 /* RCTUtils.m */,
-				13BB3D001BECD54500932C10 /* RCTImageSource.h */,
-				13BB3D011BECD54500932C10 /* RCTImageSource.m */,
-				14A43DB81C1F849600794BC8 /* RCTBridge+Private.h */,
+				3DB910701C74B21600838BBE /* RCTWebSocketProxy.h */,
+				3DB910711C74B21600838BBE /* RCTWebSocketProxyDelegate.h */,
 			);
 			path = Base;
 			sourceTree = "<group>";

From b26f699c9a9278281057bf5952b51249930f4a97 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Wed, 17 Feb 2016 08:30:24 -0800
Subject: [PATCH 1200/1411] Add measureInWindow on Android

Summary:public
This adds the capability to get a View in absolute position on the screen, not just relative to the RootView.  This is the Android implementation

Reviewed By: andreicoman11

Differential Revision: D2939170

fb-gh-sync-id: 658f1ebe6a458088f657a7469389add1a12222cd
shipit-source-id: 658f1ebe6a458088f657a7469389add1a12222cd
---
 .../uimanager/NativeViewHierarchyManager.java | 22 ++++++++++
 .../react/uimanager/UIImplementation.java     | 13 +++++-
 .../react/uimanager/UIManagerModule.java      | 10 +++++
 .../react/uimanager/UIViewOperationQueue.java | 40 +++++++++++++++++++
 4 files changed, 83 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
index aada76ee9143..b5939823acf2 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java
@@ -482,6 +482,28 @@ public void measure(int tag, int[] outputBuffer) {
     outputBuffer[3] = v.getHeight();
   }
 
+  /**
+   * Returns the coordinates of a view relative to the entire phone screen (not just the RootView
+   * which is what measure will return)
+   *
+   * @param tag - the tag for the view
+   * @param outputBuffer - output buffer that contains [x,y,width,height] of the view in coordinates
+   *  relative to the device window
+   */
+  public void measureInWindow(int tag, int[] outputBuffer) {
+    UiThreadUtil.assertOnUiThread();
+    View v = mTagsToViews.get(tag);
+    if (v == null) {
+      throw new NoSuchNativeViewException("No native view for " + tag + " currently exists");
+    }
+
+    v.getLocationOnScreen(outputBuffer);
+
+    // outputBuffer[0,1] already contain what we want
+    outputBuffer[2] = v.getWidth();
+    outputBuffer[3] = v.getHeight();
+  }
+
   public int findTargetTagForTouch(int reactTag, float touchX, float touchY) {
     View view = mTagsToViews.get(reactTag);
     if (view == null) {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
index 95cd4756e2d9..9e63b313fbf2 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java
@@ -380,8 +380,8 @@ public void findSubviewIn(int reactTag, float targetX, float targetY, Callback c
   }
 
   /**
-   * Determines the location on screen, width, and height of the given view and returns the values
-   * via an async callback.
+   * Determines the location on screen, width, and height of the given view relative to the root
+   * view and returns the values via an async callback.
    */
   public void measure(int reactTag, Callback callback) {
     // This method is called by the implementation of JS touchable interface (see Touchable.js for
@@ -391,6 +391,15 @@ public void measure(int reactTag, Callback callback) {
     mOperationsQueue.enqueueMeasure(reactTag, callback);
   }
 
+  /**
+   * Determines the location on screen, width, and height of the given view relative to the device
+   * screen and returns the values via an async callback.  This is the absolute position including
+   * things like the status bar
+   */
+  public void measureInWindow(int reactTag, Callback callback) {
+    mOperationsQueue.enqueueMeasureInWindow(reactTag, callback);
+  }
+
   /**
    * Measures the view specified by tag relative to the given ancestorTag. This means that the
    * returned x, y are relative to the origin x, y of the ancestor view. Results are stored in the
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
index 9742fc041c27..ddeb94e6db2e 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java
@@ -253,6 +253,16 @@ public void measure(int reactTag, Callback callback) {
     mUIImplementation.measure(reactTag, callback);
   }
 
+  /**
+   * Determines the location on screen, width, and height of the given view relative to the device
+   * screen and returns the values via an async callback.  This is the absolute position including
+   * things like the status bar
+   */
+  @ReactMethod
+  public void measureInWindow(int reactTag, Callback callback) {
+    mUIImplementation.measureInWindow(reactTag, callback);
+  }
+
   /**
    * Measures the view specified by tag relative to the given ancestorTag. This means that the
    * returned x, y are relative to the origin x, y of the ancestor view. Results are stored in the
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
index 9b2d81057740..b3b931e0f8ef 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java
@@ -385,6 +385,38 @@ public void execute() {
     }
   }
 
+  private final class MeasureInWindowOperation implements UIOperation {
+
+    private final int mReactTag;
+    private final Callback mCallback;
+
+    private MeasureInWindowOperation(
+        final int reactTag,
+        final Callback callback) {
+      super();
+      mReactTag = reactTag;
+      mCallback = callback;
+    }
+
+    @Override
+    public void execute() {
+      try {
+        mNativeViewHierarchyManager.measureInWindow(mReactTag, mMeasureBuffer);
+      } catch (NoSuchNativeViewException e) {
+        // Invoke with no args to signal failure and to allow JS to clean up the callback
+        // handle.
+        mCallback.invoke();
+        return;
+      }
+
+      float x = PixelUtil.toDIPFromPixel(mMeasureBuffer[0]);
+      float y = PixelUtil.toDIPFromPixel(mMeasureBuffer[1]);
+      float width = PixelUtil.toDIPFromPixel(mMeasureBuffer[2]);
+      float height = PixelUtil.toDIPFromPixel(mMeasureBuffer[3]);
+      mCallback.invoke(x, y, width, height);
+    }
+  }
+
   private ArrayList<UIOperation> mOperations = new ArrayList<>();
 
   private final class FindTargetForTouchOperation implements UIOperation {
@@ -634,6 +666,14 @@ public void enqueueMeasure(
         new MeasureOperation(reactTag, callback));
   }
 
+  public void enqueueMeasureInWindow(
+      final int reactTag,
+      final Callback callback) {
+    mOperations.add(
+        new MeasureInWindowOperation(reactTag, callback)
+    );
+  }
+
   public void enqueueFindTargetForTouch(
       final int reactTag,
       final float targetX,

From 7dc1d460c6caaa31a8482973b624eddeb5e78def Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Wed, 17 Feb 2016 08:53:43 -0800
Subject: [PATCH 1201/1411] Fix the Portal display to not rerender the entire
 tree

Summary:public
We now wrap the	<RootComponent>	in an <View> where we can control the accessibility at a high level.  This was only used to turn it off for the faded out background view when we show a pop up.

We use setNativeProps instead of setState to avoid the render.	  We really just want to pass this value to the native Android View.

Reviewed By: davidaurelio

Differential Revision: D2928371

fb-gh-sync-id: 19c34471c33650acb526a2f5a02b6070e844e8d0
shipit-source-id: 19c34471c33650acb526a2f5a02b6070e844e8d0
---
 Libraries/ReactIOS/renderApplication.android.js | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/Libraries/ReactIOS/renderApplication.android.js b/Libraries/ReactIOS/renderApplication.android.js
index 05b87178b6f5..1abfeb8b3a99 100644
--- a/Libraries/ReactIOS/renderApplication.android.js
+++ b/Libraries/ReactIOS/renderApplication.android.js
@@ -73,8 +73,8 @@ var AppContainer = React.createClass({
       return;
     }
 
-    this.setState({
-      rootImportanceForAccessibility: modalVisible ? 'no-hide-descendants' : 'auto',
+    this.refs.accessibilityWrapper.setNativeProps({
+      importantForAccessibility: modalVisible ? 'no-hide-descendants' : 'auto',
     });
   },
 
@@ -85,10 +85,14 @@ var AppContainer = React.createClass({
         ref="main"
         collapsable={!this.state.inspectorVisible}
         style={styles.appContainer}>
-        <RootComponent
-          {...this.props.initialProps}
-          rootTag={this.props.rootTag}
-          importantForAccessibility={this.state.rootImportanceForAccessibility}/>
+        <View
+          ref="accessibilityWrapper"
+          collapsable={true}
+          style={styles.appContainer}>
+          <RootComponent
+            {...this.props.initialProps}
+            rootTag={this.props.rootTag}/>
+        </View>
         <Portal
           onModalVisibilityChanged={this.setRootAccessibility}/>
       </View>;

From f2b95f2b874168636a8db1072b184358215068e9 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Wed, 17 Feb 2016 09:04:58 -0800
Subject: [PATCH 1202/1411] Add commands for a new issue bot

Reviewed By: mkonicek

Differential Revision:D2944312
Ninja: yet to be used

fb-gh-sync-id: 17b22063539612ce48eb4acac62f452ca4d65c1d
shipit-source-id: 17b22063539612ce48eb4acac62f452ca4d65c1d
---
 bots/IssueCommands.txt | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
 create mode 100644 bots/IssueCommands.txt

diff --git a/bots/IssueCommands.txt b/bots/IssueCommands.txt
new file mode 100644
index 000000000000..1dcd91c6a8c5
--- /dev/null
+++ b/bots/IssueCommands.txt
@@ -0,0 +1,14 @@
+/answered
+comment Closing this issue as the question has been answered. Please help us by first discussing on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native) before filing a bug. It's the best system for Q&A. Many people from the community hang out there and will be able to see and answer your question. This lets us use the GitHub bug tracker for bugs.
+close
+
+/duplicate (#[0-9]+)
+comment This issue is a duplicate of {match0}.
+close
+
+/expected
+comment This is expected behavior. Closing as we'd like to use the GitHub issue tracker for bugs. If you'd like to change how this feature works please post a feature request on [Product Pains](https://productpains.com/product/react-native/) and let's discuss there. If it gets upvoted enough it might get implemented by the community.
+close
+
+/label (.*)
+add-label {match0}

From b5f80065d48e2196f4b648cbb734e47b84284d0e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Wed, 17 Feb 2016 10:00:35 -0800
Subject: [PATCH 1203/1411] Introduce transformer `cacheKey`

Summary:public

At the moment, the packager's cache can only be broken by changing packager's `package.json` version,by supplying a different `cacheKey` or by updating the `mtime` of the transformer. We need to add support for breaking the cache key when a plugin the transformer use gets updated. To do so, lets introduce a property on the transformer, namely `cacheKey`.

Reviewed By: davidaurelio

Differential Revision: D2940267

fb-gh-sync-id: 82c937d06c73abd32708bf97afe5f308c2a3b565
shipit-source-id: 82c937d06c73abd32708bf97afe5f308c2a3b565
---
 packager/react-packager/src/Bundler/index.js | 23 ++++++++++++++------
 1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index bc25ab1d929a..6285fcc286c4 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -103,15 +103,24 @@ class Bundler {
       mtime = '';
     }
 
+    const cacheKeyParts =  [
+      'react-packager-cache',
+      version,
+      opts.cacheVersion,
+      opts.projectRoots.join(',').split(path.sep).join('-'),
+      mtime,
+    ];
+
+    if (opts.transformModulePath) {
+      const transformer = require(opts.transformModulePath);
+      if (typeof transformer.cacheKey !== 'undefined') {
+        cacheKeyParts.push(transformer.cacheKey);
+      }
+    }
+
     this._cache = new Cache({
       resetCache: opts.resetCache,
-      cacheKey: [
-        'react-packager-cache',
-        version,
-        opts.cacheVersion,
-        opts.projectRoots.join(',').split(path.sep).join('-'),
-        mtime
-      ].join('$'),
+      cacheKey: cacheKeyParts.join('$'),
     });
 
     this._resolver = new Resolver({

From 80728226fcbe764c31080e1a54d13291c3625cd5 Mon Sep 17 00:00:00 2001
From: androidtrunkagent <androidtrunkagent@fb.com>
Date: Wed, 17 Feb 2016 11:36:46 -0800
Subject: [PATCH 1204/1411] Add video link and include new featured apps in
 showcase

Summary: Closes https://github.com/facebook/react-native/pull/5923

Differential Revision: D2936878

fb-gh-sync-id: 7d5121e3bbe24be36808d1dc250c90308de0185d
shipit-source-id: 7d5121e3bbe24be36808d1dc250c90308de0185d
---
 website/src/react-native/showcase.js | 88 ++++++++++++++++++----------
 1 file changed, 58 insertions(+), 30 deletions(-)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index e6974558c7cf..feb4d0ed915d 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -76,6 +76,12 @@ var featured = [
     link: 'https://itunes.apple.com/in/app/myntra-fashion-shopping-app/id907394059',
     author: 'Myntra Designs',
   },
+  {
+    name: 'Noodler',
+    icon: 'http://a5.mzstatic.com/us/r30/Purple6/v4/d9/9a/69/d99a6919-7f11-35ad-76ea-f1741643d875/icon175x175.png',
+    link: 'http://www.noodler-app.com/',
+    author: 'Michele Humes & Joshua Sierles',
+  },
   {
     name: 'React Native Playground',
     icon: 'http://is5.mzstatic.com/image/pf/us/r30/Purple1/v4/20/ec/8e/20ec8eb8-9e12-6686-cd16-7ac9e3ef1d52/mzl.ngvuoybx.png',
@@ -83,6 +89,12 @@ var featured = [
     linkPlayStore: 'https://play.google.com/store/apps/details?id=org.rnplay.playground',
     author: 'Joshua Sierles',
   },
+  {
+    name: 'Round - A better way to remember your medicine',
+    icon: 'https://s3.mzstatic.com/us/r30/Purple69/v4/d3/ee/54/d3ee54cf-13b6-5f56-0edc-6c70ac90b2be/icon175x175.png',
+    link: 'https://itunes.apple.com/us/app/round-beautiful-medication/id1059591124?mt=8',
+    author: 'Circadian Design',
+  },
   {
     name: 'Running',
     icon: 'http://a1.mzstatic.com/us/r30/Purple3/v4/33/eb/4f/33eb4f73-c7e3-8659-9285-f758e403485b/icon175x175.jpeg',
@@ -92,6 +104,15 @@ var featured = [
       'https://blog.gyrosco.pe/the-making-of-gyroscope-running-a4ad10acc0d0',
     ],
   },
+  {
+    name: 'Spero for Cancer',
+    icon: 'https://s3-us-west-1.amazonaws.com/cancerspot/site_images/Spero1024.png',
+    link: 'https://geo.itunes.apple.com/us/app/spero-for-cancer/id1033923573?mt=8',
+    author: 'Spero.io',
+    videos: [
+      'https://www.youtube.com/watch?v=JImX3L6qnj8',
+    ],
+  },
   {
     name: 'Squad',
     icon: 'http://a4.mzstatic.com/us/r30/Purple69/v4/e8/5b/3f/e85b3f52-72f3-f427-a32e-a73efe2e9682/icon175x175.jpeg',
@@ -104,6 +125,12 @@ var featured = [
     link: 'https://itunes.apple.com/us/app/start-medication-manager-for/id1012099928?mt=8',
     author: 'Iodine Inc.',
   },
+  {
+    name: 'This AM',
+    icon: 'http://s3.r29static.com//bin/public/efe/x/1542038/image.png',
+    link: 'https://itunes.apple.com/us/app/refinery29-this-am-top-breaking/id988472315?mt=8',
+    author: 'Refinery29',
+  },
   {
     name: 'Townske',
     icon: 'http://a3.mzstatic.com/us/r30/Purple69/v4/8b/42/20/8b4220af-5165-91fd-0f05-014332df73ef/icon175x175.png',
@@ -120,6 +147,12 @@ var featured = [
       'https://medium.com/@clayallsopp/making-tucci-the-technical-details-cc7aded6c75f#.wf72nq372',
     ],
   },
+  {
+    name: 'WPV',
+    icon: 'http://a2.mzstatic.com/us/r30/Purple49/v4/a8/26/d7/a826d7bf-337b-c6b8-488d-aca98027754d/icon350x350.png',
+    link: 'https://itunes.apple.com/us/app/wpv/id725222647?mt=8',
+    author: 'Yamill Vallecillo',
+  },
 ];
 
 var apps = [
@@ -393,18 +426,6 @@ var apps = [
     link: 'https://play.google.com/store/apps/details?id=com.rhyble.nalathekerala',
     author: 'Rhyble',
   },
-  {
-    name: 'Ncredible',
-    icon: 'http://a3.mzstatic.com/us/r30/Purple2/v4/a9/00/74/a9007400-7ccf-df10-553b-3b6cb67f3f5f/icon350x350.png',
-    link: 'https://itunes.apple.com/ca/app/ncredible/id1019662810?mt=8',
-    author: 'NBC News Digital, LLC',
-  },
-  {
-    name: 'Noodler',
-    icon: 'http://a5.mzstatic.com/us/r30/Purple6/v4/d9/9a/69/d99a6919-7f11-35ad-76ea-f1741643d875/icon175x175.png',
-    link: 'https://itunes.apple.com/us/app/noodler-noodle-soup-oracle/id1013183002?mt=8',
-    author: 'Michele Humes & Joshua Sierles',
-  },
   {
     name: 'Night Light',
     icon: 'http://is3.mzstatic.com/image/pf/us/r30/Purple7/v4/5f/50/5f/5f505fe5-0a30-6bbf-6ed9-81ef09351aba/mzl.lkeqxyeo.png',
@@ -465,12 +486,6 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/rota-worker-shifts-on-demand/id1042111289?mt=8',
     author: 'Rota',
   },
-  {
-    name: 'Round - A better way to remember your medicine',
-    icon: 'https://s3.mzstatic.com/us/r30/Purple69/v4/d3/ee/54/d3ee54cf-13b6-5f56-0edc-6c70ac90b2be/icon175x175.png',
-    link: 'https://itunes.apple.com/us/app/round-beautiful-medication/id1059591124?mt=8',
-    author: 'Circadian Design',
-  },
   {
     name: 'RWpodPlayer - audio player for RWpod podcast',
     icon: 'http://a1.mzstatic.com/us/r30/Purple69/v4/a8/c0/b1/a8c0b130-e44b-742d-6458-0c89fcc15b6b/icon175x175.png',
@@ -520,12 +535,6 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/text-blast-2016/id1023852862?mt=8',
     author: 'Sesh',
   },
-  {
-    name: 'This AM',
-    icon: 'http://s3.r29static.com//bin/public/efe/x/1542038/image.png',
-    link: 'https://itunes.apple.com/us/app/refinery29-this-am-top-breaking/id988472315?mt=8',
-    author: 'Refinery29',
-  },
   {
     name: 'Tong Xing Wang',
     icon: 'http://a3.mzstatic.com/us/r30/Purple1/v4/7d/52/a7/7d52a71f-9532-82a5-b92f-87076624fdb2/icon175x175.jpeg',
@@ -545,12 +554,6 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/woop-app/id790247988?mt=8',
     author: 'Moritz Schwörer (@mosch)',
   },
-  {
-    name: 'WPV',
-    icon: 'http://a2.mzstatic.com/us/r30/Purple49/v4/a8/26/d7/a826d7bf-337b-c6b8-488d-aca98027754d/icon350x350.png',
-    link: 'https://itunes.apple.com/us/app/wpv/id725222647?mt=8',
-    author: 'Yamill Vallecillo',
-  },
   {
     name: 'Yoloci',
     icon: 'http://a5.mzstatic.com/eu/r30/Purple7/v4/fa/e5/26/fae52635-b97c-bd53-2ade-89e2a4326745/icon175x175.jpeg',
@@ -615,6 +618,7 @@ var AppList = React.createClass({
         {app.linkAppStore && app.linkPlayStore ? this._renderLinks(app) : null}
         <p>By {app.author}</p>
         {this._renderBlogPosts(app)}
+        {this._renderVideos(app)}
       </div>
     );
 
@@ -655,6 +659,30 @@ var AppList = React.createClass({
     );
   },
 
+  _renderVideos: function(app) {
+    if (!app.videos) {
+      return;
+    }
+
+    if (app.videos.length === 1) {
+      return (
+        <p><a href={app.videos[0]} target="blank">Video</a></p>
+      );
+    } else if (app.videos.length > 1) {
+      return (
+        <p>Videos: {app.videos.map(this._renderVideo)}</p>
+      );
+    }
+  },
+
+  _renderVideo: function(url, i) {
+    return (
+      <a href={url} target="blank">
+        {i + 1}&nbsp;
+      </a>
+    );
+  },
+
   _renderLinks: function(app) {
     return (
       <p>

From 5ec33d1a69ee4e08045dd7fd06544408f0fa6d84 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Wed, 17 Feb 2016 15:39:46 -0800
Subject: [PATCH 1205/1411] Tweak Hot Loading yellow box wording

Summary: Users don't know what an accept callback is. Lets be more explicit on what type of modules we currently support hot loading.

Reviewed By: weicool

Differential Revision: D2945438

fb-gh-sync-id: d0fc228ab23833371f8fbbd86ed18e81c8ba0ebf
shipit-source-id: d0fc228ab23833371f8fbbd86ed18e81c8ba0ebf
---
 packager/react-packager/src/Resolver/polyfills/require.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/packager/react-packager/src/Resolver/polyfills/require.js b/packager/react-packager/src/Resolver/polyfills/require.js
index a5a7a55f01a5..bc2824bba868 100644
--- a/packager/react-packager/src/Resolver/polyfills/require.js
+++ b/packager/react-packager/src/Resolver/polyfills/require.js
@@ -118,8 +118,8 @@ if (__DEV__) { // HMR
       mod.module.hot.acceptCallback();
     } else {
       console.warn(
-        '[HMR] Module `' + id + '` can\'t be hot reloaded because it ' +
-        'doesn\'t provide accept callback hook. Reload the app to get the updates.'
+        '[HMR] Module `' + id + '` can\'t be hot reloaded because it\'s not a ' +
+        'React component. To get the changes reload the JS bundle.'
       );
     }
   }

From 1f6ad46598cdfaf874d8d64b2ce0f56bf4704084 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Wed, 17 Feb 2016 15:57:27 -0800
Subject: [PATCH 1206/1411] PR and Issue templates

Reviewed By: mkonicek

Differential Revision:D2946749
Ninja: GitHub-only

fb-gh-sync-id: ac8a316ca4c2982a063040d57ddc1f279b81b59d
shipit-source-id: ac8a316ca4c2982a063040d57ddc1f279b81b59d
---
 ISSUE_TEMPLATE.md        | 16 ++++++++++++++++
 PULL_REQUEST_TEMPLATE.md | 13 +++++++++++++
 2 files changed, 29 insertions(+)
 create mode 100644 ISSUE_TEMPLATE.md
 create mode 100644 PULL_REQUEST_TEMPLATE.md

diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md
new file mode 100644
index 000000000000..a1a214ae3e8b
--- /dev/null
+++ b/ISSUE_TEMPLATE.md
@@ -0,0 +1,16 @@
+React Native, as you've probably heard, is getting really popular and truth is we're getting a bit overwhelmed by the activity surrounding it. There are just too many issues for us to manage properly.
+
+Here are good ways to get help:
+
+- If you **don't know how to do something** or **not sure you've found a bug**, ask on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native) with the tag `react-native`. StackOverflow is amazing for Q&A and it is likely the community will see and answer your question there.
+
+- If this is a **feature request**, please report it on [Product Pains](https://productpains.com/product/react-native/). It has a ranking feature that lets us focus on the most important issues the community is experiencing.
+
+- Is this something you can debug and fix quickly? **Send a pull request!**
+
+If you want to file a GitHub issue, make sure it is actionable so someone can help:
+
+- Provide **screenshots** where appropriate
+- What's the **version** of React Native you're using?
+- Does this occur on iOS, Android or both?
+- The operating system: Mac, Linux or Windows
diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 000000000000..875b1d6edefb
--- /dev/null
+++ b/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,13 @@
+Explain the motivation for making this change. What existing problem does the pull request solve?
+
+Example: When saying "Add a function to do X", explain why it is necessary to have a way to do X.
+
+**Test plan (required)**
+
+Describe exact steps you've done to test that the code works. This means exact commands you ran, screenshots / videos if the pull request changes UI.
+
+Make sure tests pass on Circle CI.
+
+**Code formatting**
+
+See the simple [style guide](https://github.com/facebook/react-native/blob/master/CONTRIBUTING.md#style-guide).

From 403176ae9332fb7c8beac339dd41cbb067f995fd Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Wed, 17 Feb 2016 16:53:17 -0800
Subject: [PATCH 1207/1411] Also release Android sources to npm

Summary:Turns out also having sources (besides binaries in /android) in npm is useful:
https://facebook.github.io/react-native/docs/android-building-from-source.html

Reviewed By: mkonicek

Differential Revision:D2947237
Ninja: oss-only

fb-gh-sync-id: 80e3e79c9c5a5f54fd54e91ac147249a68c74847
shipit-source-id: 80e3e79c9c5a5f54fd54e91ac147249a68c74847
---
 package.json | 1 +
 1 file changed, 1 insertion(+)

diff --git a/package.json b/package.json
index 78c359b2f293..0964bfca8c29 100644
--- a/package.json
+++ b/package.json
@@ -83,6 +83,7 @@
   "files": [
     "React",
     "React.podspec",
+    "ReactAndroid",
     "android",
     "Libraries",
     "packager",

From 82eeca659e0dd087146458cf533caa4ccc60a905 Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Thu, 18 Feb 2016 00:12:42 -0800
Subject: [PATCH 1208/1411] Update + use node-haste2

Summary:This updates jest to 0.9 which will result in *much* faster startup time (1s vs. 10-15s) and better runtime overall (2-3x).

The route gen and cli integration tests are failing locally, but also on master. javache is this expected right now or is this related to my changes?

Reviewed By: javache

Differential Revision: D2943137

fb-gh-sync-id: 8b39ba5f51e30fbc5bacb84d67013ab0a4061f6e
shipit-source-id: 8b39ba5f51e30fbc5bacb84d67013ab0a4061f6e
---
 npm-shrinkwrap.json                           | 973 ++++++++++--------
 package.json                                  |  13 +-
 .../src/Server/__tests__/Server-test.js       |   1 +
 .../__tests__/SocketInterface-test.js         |   1 +
 .../{ => src}/__mocks__/debug.js              |   0
 5 files changed, 532 insertions(+), 456 deletions(-)
 rename packager/react-packager/{ => src}/__mocks__/debug.js (100%)

diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index fd91dc33f025..4ebb85ec3492 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -142,15 +142,15 @@
           "from": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz",
           "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
         },
-        "regenerator": {
-          "version": "0.8.40",
-          "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
-          "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
-        },
         "recast": {
           "version": "0.10.33",
           "from": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz",
           "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
+        },
+        "regenerator": {
+          "version": "0.8.40",
+          "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
+          "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
         }
       }
     },
@@ -228,16 +228,16 @@
           "from": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz",
           "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz"
         },
-        "globals": {
-          "version": "6.4.1",
-          "from": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz",
-          "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
-        },
         "babylon": {
           "version": "5.8.29",
           "from": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz",
           "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz"
         },
+        "globals": {
+          "version": "6.4.1",
+          "from": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz",
+          "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
+        },
         "js-tokens": {
           "version": "1.0.1",
           "from": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz",
@@ -1895,56 +1895,56 @@
             }
           }
         },
-        "ansi": {
-          "version": "0.3.0",
-          "from": "ansi@~0.3.0",
-          "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.0.tgz"
-        },
-        "ansi-styles": {
-          "version": "2.1.0",
-          "from": "ansi-styles@^2.1.0",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz"
-        },
         "abbrev": {
           "version": "1.0.7",
           "from": "abbrev@1",
           "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz"
         },
+        "ansi": {
+          "version": "0.3.0",
+          "from": "ansi@~0.3.0",
+          "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.0.tgz"
+        },
         "ansi-regex": {
           "version": "2.0.0",
           "from": "ansi-regex@^2.0.0",
           "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
         },
-        "asn1": {
-          "version": "0.1.11",
-          "from": "asn1@0.1.11",
-          "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
+        "ansi-styles": {
+          "version": "2.1.0",
+          "from": "ansi-styles@^2.1.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz"
         },
         "are-we-there-yet": {
           "version": "1.0.4",
           "from": "are-we-there-yet@~1.0.0",
           "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.4.tgz"
         },
-        "aws-sign2": {
-          "version": "0.6.0",
-          "from": "aws-sign2@~0.6.0",
-          "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
+        "assert-plus": {
+          "version": "0.1.5",
+          "from": "assert-plus@^0.1.5",
+          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
+        },
+        "asn1": {
+          "version": "0.1.11",
+          "from": "asn1@0.1.11",
+          "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
         },
         "async": {
           "version": "1.5.0",
           "from": "async@^1.4.0",
           "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz"
         },
-        "assert-plus": {
-          "version": "0.1.5",
-          "from": "assert-plus@^0.1.5",
-          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
-        },
         "balanced-match": {
           "version": "0.2.1",
           "from": "balanced-match@>=0.2.0 <0.3.0",
           "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.1.tgz"
         },
+        "aws-sign2": {
+          "version": "0.6.0",
+          "from": "aws-sign2@~0.6.0",
+          "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
+        },
         "boom": {
           "version": "2.10.1",
           "from": "boom@^2.8.x",
@@ -1960,36 +1960,36 @@
           "from": "brace-expansion@>=1.0.0 <2.0.0",
           "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz"
         },
-        "chalk": {
-          "version": "1.1.1",
-          "from": "chalk@^1.1.1",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz"
-        },
-        "combined-stream": {
-          "version": "1.0.5",
-          "from": "combined-stream@~1.0.5",
-          "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz"
-        },
         "caseless": {
           "version": "0.11.0",
           "from": "caseless@~0.11.0",
           "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
         },
+        "chalk": {
+          "version": "1.1.1",
+          "from": "chalk@^1.1.1",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz"
+        },
         "commander": {
           "version": "2.9.0",
           "from": "commander@^2.8.1",
           "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz"
         },
-        "core-util-is": {
-          "version": "1.0.1",
-          "from": "core-util-is@~1.0.0",
-          "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
+        "combined-stream": {
+          "version": "1.0.5",
+          "from": "combined-stream@~1.0.5",
+          "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz"
         },
         "concat-map": {
           "version": "0.0.1",
           "from": "concat-map@0.0.1",
           "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
         },
+        "core-util-is": {
+          "version": "1.0.1",
+          "from": "core-util-is@~1.0.0",
+          "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
+        },
         "cryptiles": {
           "version": "2.0.5",
           "from": "cryptiles@2.x.x",
@@ -2000,16 +2000,16 @@
           "from": "ctype@0.5.3",
           "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz"
         },
-        "deep-extend": {
-          "version": "0.2.11",
-          "from": "deep-extend@~0.2.5",
-          "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.2.11.tgz"
-        },
         "debug": {
           "version": "0.7.4",
           "from": "debug@~0.7.2",
           "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz"
         },
+        "deep-extend": {
+          "version": "0.2.11",
+          "from": "deep-extend@~0.2.5",
+          "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.2.11.tgz"
+        },
         "delayed-stream": {
           "version": "1.0.0",
           "from": "delayed-stream@~1.0.0",
@@ -2060,16 +2060,16 @@
           "from": "generate-object-property@^1.1.0",
           "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz"
         },
-        "graceful-readlink": {
-          "version": "1.0.1",
-          "from": "graceful-readlink@>= 1.0.0",
-          "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
-        },
         "graceful-fs": {
           "version": "4.1.2",
           "from": "graceful-fs@4.1",
           "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.2.tgz"
         },
+        "graceful-readlink": {
+          "version": "1.0.1",
+          "from": "graceful-readlink@>= 1.0.0",
+          "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
+        },
         "har-validator": {
           "version": "2.0.2",
           "from": "har-validator@~2.0.2",
@@ -2100,11 +2100,6 @@
           "from": "http-signature@~0.11.0",
           "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.11.0.tgz"
         },
-        "inherits": {
-          "version": "2.0.1",
-          "from": "inherits@*",
-          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-        },
         "ini": {
           "version": "1.3.4",
           "from": "ini@~1.3.0",
@@ -2115,36 +2110,41 @@
           "from": "is-my-json-valid@^2.12.2",
           "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.2.tgz"
         },
+        "is-property": {
+          "version": "1.0.2",
+          "from": "is-property@^1.0.0",
+          "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz"
+        },
         "isarray": {
           "version": "0.0.1",
           "from": "isarray@0.0.1",
           "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
         },
-        "isstream": {
-          "version": "0.1.2",
-          "from": "isstream@~0.1.2",
-          "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
+        "inherits": {
+          "version": "2.0.1",
+          "from": "inherits@*",
+          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
         },
-        "is-property": {
-          "version": "1.0.2",
-          "from": "is-property@^1.0.0",
-          "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz"
+        "jsonpointer": {
+          "version": "2.0.0",
+          "from": "jsonpointer@2.0.0",
+          "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
         },
         "json-stringify-safe": {
           "version": "5.0.1",
           "from": "json-stringify-safe@~5.0.1",
           "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
         },
+        "isstream": {
+          "version": "0.1.2",
+          "from": "isstream@~0.1.2",
+          "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
+        },
         "lodash._basetostring": {
           "version": "3.0.1",
           "from": "lodash._basetostring@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz"
         },
-        "jsonpointer": {
-          "version": "2.0.0",
-          "from": "jsonpointer@2.0.0",
-          "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
-        },
         "lodash._createpadding": {
           "version": "3.6.1",
           "from": "lodash._createpadding@^3.0.0",
@@ -2155,31 +2155,31 @@
           "from": "lodash.pad@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-3.1.1.tgz"
         },
-        "lodash.padright": {
-          "version": "3.1.1",
-          "from": "lodash.padright@^3.0.0",
-          "resolved": "https://registry.npmjs.org/lodash.padright/-/lodash.padright-3.1.1.tgz"
-        },
         "lodash.padleft": {
           "version": "3.1.1",
           "from": "lodash.padleft@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash.padleft/-/lodash.padleft-3.1.1.tgz"
         },
+        "lodash.padright": {
+          "version": "3.1.1",
+          "from": "lodash.padright@^3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash.padright/-/lodash.padright-3.1.1.tgz"
+        },
         "lodash.repeat": {
           "version": "3.0.1",
           "from": "lodash.repeat@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash.repeat/-/lodash.repeat-3.0.1.tgz"
         },
-        "mime-types": {
-          "version": "2.1.7",
-          "from": "mime-types@~2.1.7",
-          "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.7.tgz"
-        },
         "mime-db": {
           "version": "1.19.0",
           "from": "mime-db@~1.19.0",
           "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.19.0.tgz"
         },
+        "mime-types": {
+          "version": "2.1.7",
+          "from": "mime-types@~2.1.7",
+          "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.7.tgz"
+        },
         "minimist": {
           "version": "0.0.8",
           "from": "minimist@0.0.8",
@@ -2200,26 +2200,21 @@
           "from": "npmlog@~1.2.0",
           "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz"
         },
-        "once": {
-          "version": "1.1.1",
-          "from": "once@~1.1.1",
-          "resolved": "https://registry.npmjs.org/once/-/once-1.1.1.tgz"
-        },
         "oauth-sign": {
           "version": "0.8.0",
           "from": "oauth-sign@~0.8.0",
           "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.0.tgz"
         },
+        "once": {
+          "version": "1.1.1",
+          "from": "once@~1.1.1",
+          "resolved": "https://registry.npmjs.org/once/-/once-1.1.1.tgz"
+        },
         "path-is-absolute": {
           "version": "1.0.0",
           "from": "path-is-absolute@>=1.0.0 <2.0.0",
           "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz"
         },
-        "qs": {
-          "version": "5.2.0",
-          "from": "qs@~5.2.0",
-          "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz"
-        },
         "pinkie": {
           "version": "1.0.0",
           "from": "pinkie@^1.0.0",
@@ -2230,6 +2225,11 @@
           "from": "pinkie-promise@^1.0.0",
           "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz"
         },
+        "qs": {
+          "version": "5.2.0",
+          "from": "qs@~5.2.0",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz"
+        },
         "readable-stream": {
           "version": "1.1.13",
           "from": "readable-stream@^1.1.13",
@@ -2240,16 +2240,16 @@
           "from": "request@2.x",
           "resolved": "https://registry.npmjs.org/request/-/request-2.65.0.tgz"
         },
-        "sntp": {
-          "version": "1.0.9",
-          "from": "sntp@1.x.x",
-          "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
-        },
         "semver": {
           "version": "5.0.3",
           "from": "semver@~5.0.1",
           "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
         },
+        "sntp": {
+          "version": "1.0.9",
+          "from": "sntp@1.x.x",
+          "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
+        },
         "string_decoder": {
           "version": "0.10.31",
           "from": "string_decoder@~0.10.x",
@@ -2260,26 +2260,26 @@
           "from": "stringstream@~0.0.4",
           "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
         },
-        "strip-json-comments": {
-          "version": "0.1.3",
-          "from": "strip-json-comments@0.1.x",
-          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
-        },
-        "tar": {
-          "version": "2.2.1",
-          "from": "tar@~2.2.0",
-          "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz"
-        },
         "strip-ansi": {
           "version": "3.0.0",
           "from": "strip-ansi@^3.0.0",
           "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz"
         },
+        "strip-json-comments": {
+          "version": "0.1.3",
+          "from": "strip-json-comments@0.1.x",
+          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
+        },
         "supports-color": {
           "version": "2.0.0",
           "from": "supports-color@^2.0.0",
           "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
         },
+        "tar": {
+          "version": "2.2.1",
+          "from": "tar@~2.2.0",
+          "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz"
+        },
         "tough-cookie": {
           "version": "2.2.0",
           "from": "tough-cookie@~2.2.0",
@@ -2305,28 +2305,6 @@
           "from": "xtend@^4.0.0",
           "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz"
         },
-        "fstream-ignore": {
-          "version": "1.0.3",
-          "from": "fstream-ignore@~1.0.3",
-          "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.3.tgz",
-          "dependencies": {
-            "minimatch": {
-              "version": "3.0.0",
-              "from": "minimatch@>=3.0.0 <4.0.0"
-            }
-          }
-        },
-        "inflight": {
-          "version": "1.0.4",
-          "from": "inflight@>=1.0.4 <2.0.0",
-          "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz",
-          "dependencies": {
-            "once": {
-              "version": "1.3.2",
-              "from": "once@>=1.3.0 <2.0.0"
-            }
-          }
-        },
         "rc": {
           "version": "1.1.2",
           "from": "rc@~1.1.0",
@@ -2361,17 +2339,39 @@
             }
           }
         },
-        "bl": {
-          "version": "1.0.0",
-          "from": "bl@~1.0.0",
-          "resolved": "https://registry.npmjs.org/bl/-/bl-1.0.0.tgz",
+        "inflight": {
+          "version": "1.0.4",
+          "from": "inflight@>=1.0.4 <2.0.0",
+          "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz",
           "dependencies": {
-            "readable-stream": {
-              "version": "2.0.4",
-              "from": "readable-stream@~2.0.0",
-              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.4.tgz",
-              "dependencies": {
-                "core-util-is": {
+            "once": {
+              "version": "1.3.2",
+              "from": "once@>=1.3.0 <2.0.0"
+            }
+          }
+        },
+        "fstream-ignore": {
+          "version": "1.0.3",
+          "from": "fstream-ignore@~1.0.3",
+          "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.3.tgz",
+          "dependencies": {
+            "minimatch": {
+              "version": "3.0.0",
+              "from": "minimatch@>=3.0.0 <4.0.0"
+            }
+          }
+        },
+        "bl": {
+          "version": "1.0.0",
+          "from": "bl@~1.0.0",
+          "resolved": "https://registry.npmjs.org/bl/-/bl-1.0.0.tgz",
+          "dependencies": {
+            "readable-stream": {
+              "version": "2.0.4",
+              "from": "readable-stream@~2.0.0",
+              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.4.tgz",
+              "dependencies": {
+                "core-util-is": {
                   "version": "1.0.1",
                   "from": "core-util-is@~1.0.0",
                   "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
@@ -2641,166 +2641,170 @@
       "resolved": "https://registry.npmjs.org/isobject/-/isobject-1.0.2.tgz"
     },
     "jest-cli": {
-      "version": "0.8.2",
-      "from": "jest-cli@0.8.2",
-      "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-0.8.2.tgz",
+      "version": "0.9.0-fb1",
+      "from": "jest-cli@0.9.0-fb1",
       "dependencies": {
         "cover": {
           "version": "0.2.9",
-          "from": "https://registry.npmjs.org/cover/-/cover-0.2.9.tgz",
+          "from": "cover@>=0.2.9 <0.3.0",
           "resolved": "https://registry.npmjs.org/cover/-/cover-0.2.9.tgz",
           "dependencies": {
             "cli-table": {
               "version": "0.0.2",
-              "from": "https://registry.npmjs.org/cli-table/-/cli-table-0.0.2.tgz",
+              "from": "cli-table@>=0.0.0 <0.1.0",
               "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.0.2.tgz",
               "dependencies": {
                 "colors": {
                   "version": "0.3.0",
-                  "from": "https://registry.npmjs.org/colors/-/colors-0.3.0.tgz",
+                  "from": "colors@0.3.0",
                   "resolved": "https://registry.npmjs.org/colors/-/colors-0.3.0.tgz"
                 }
               }
             },
             "underscore": {
               "version": "1.2.4",
-              "from": "https://registry.npmjs.org/underscore/-/underscore-1.2.4.tgz",
+              "from": "underscore@>=1.2.0 <1.3.0",
               "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.2.4.tgz"
             },
             "underscore.string": {
               "version": "2.0.0",
-              "from": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.0.0.tgz",
+              "from": "underscore.string@>=2.0.0 <2.1.0",
               "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.0.0.tgz"
             },
             "which": {
               "version": "1.0.9",
-              "from": "https://registry.npmjs.org/which/-/which-1.0.9.tgz",
+              "from": "which@>=1.0.0 <1.1.0",
               "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz"
             }
           }
         },
         "diff": {
           "version": "2.2.1",
-          "from": "https://registry.npmjs.org/diff/-/diff-2.2.1.tgz",
+          "from": "diff@>=2.1.1 <3.0.0",
           "resolved": "https://registry.npmjs.org/diff/-/diff-2.2.1.tgz"
         },
+        "graceful-fs": {
+          "version": "4.1.3",
+          "from": "graceful-fs@>=4.1.3 <5.0.0",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.3.tgz"
+        },
         "istanbul": {
-          "version": "0.3.22",
-          "from": "https://registry.npmjs.org/istanbul/-/istanbul-0.3.22.tgz",
-          "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.3.22.tgz",
+          "version": "0.4.2",
+          "from": "istanbul@>=0.4.2 <0.5.0",
+          "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.2.tgz",
           "dependencies": {
             "abbrev": {
               "version": "1.0.7",
-              "from": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz",
+              "from": "abbrev@>=1.0.0 <1.1.0",
               "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz"
             },
             "async": {
-              "version": "1.5.0",
-              "from": "https://registry.npmjs.org/async/-/async-1.5.0.tgz",
-              "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz"
+              "version": "1.5.2",
+              "from": "async@>=1.0.0 <2.0.0",
+              "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz"
             },
             "escodegen": {
               "version": "1.7.1",
-              "from": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.1.tgz",
+              "from": "escodegen@>=1.7.0 <1.8.0",
               "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.1.tgz",
               "dependencies": {
                 "estraverse": {
                   "version": "1.9.3",
-                  "from": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz",
+                  "from": "estraverse@>=1.9.1 <2.0.0",
                   "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz"
                 },
                 "esprima": {
                   "version": "1.2.5",
-                  "from": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz",
+                  "from": "esprima@>=1.2.2 <2.0.0",
                   "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz"
                 },
                 "optionator": {
                   "version": "0.5.0",
-                  "from": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz",
+                  "from": "optionator@>=0.5.0 <0.6.0",
                   "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz",
                   "dependencies": {
                     "prelude-ls": {
                       "version": "1.1.2",
-                      "from": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+                      "from": "prelude-ls@>=1.1.1 <1.2.0",
                       "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz"
                     },
                     "deep-is": {
                       "version": "0.1.3",
-                      "from": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+                      "from": "deep-is@>=0.1.2 <0.2.0",
                       "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz"
                     },
                     "wordwrap": {
                       "version": "0.0.3",
-                      "from": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
+                      "from": "wordwrap@>=0.0.2 <0.1.0",
                       "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
                     },
                     "type-check": {
-                      "version": "0.3.1",
-                      "from": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz",
-                      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz"
+                      "version": "0.3.2",
+                      "from": "type-check@>=0.3.1 <0.4.0",
+                      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz"
                     },
                     "levn": {
                       "version": "0.2.5",
-                      "from": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz",
+                      "from": "levn@>=0.2.5 <0.3.0",
                       "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz"
                     },
                     "fast-levenshtein": {
                       "version": "1.0.7",
-                      "from": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz",
+                      "from": "fast-levenshtein@>=1.0.0 <1.1.0",
                       "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz"
                     }
                   }
                 },
                 "source-map": {
                   "version": "0.2.0",
-                  "from": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz",
+                  "from": "source-map@>=0.2.0 <0.3.0",
                   "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz"
                 }
               }
             },
             "esprima": {
-              "version": "2.5.0",
-              "from": "https://registry.npmjs.org/esprima/-/esprima-2.5.0.tgz",
-              "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.5.0.tgz"
+              "version": "2.7.2",
+              "from": "esprima@>=2.7.0 <2.8.0",
+              "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.2.tgz"
             },
             "fileset": {
               "version": "0.2.1",
-              "from": "https://registry.npmjs.org/fileset/-/fileset-0.2.1.tgz",
+              "from": "fileset@>=0.2.0 <0.3.0",
               "resolved": "https://registry.npmjs.org/fileset/-/fileset-0.2.1.tgz"
             },
             "handlebars": {
               "version": "4.0.5",
-              "from": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.5.tgz",
+              "from": "handlebars@>=4.0.1 <5.0.0",
               "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.5.tgz",
               "dependencies": {
                 "uglify-js": {
                   "version": "2.6.1",
-                  "from": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.1.tgz",
+                  "from": "uglify-js@>=2.6.0 <3.0.0",
                   "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.1.tgz",
                   "dependencies": {
                     "async": {
                       "version": "0.2.10",
-                      "from": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
+                      "from": "async@>=0.2.6 <0.3.0",
                       "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz"
                     },
                     "source-map": {
                       "version": "0.5.3",
-                      "from": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz",
+                      "from": "source-map@>=0.5.1 <0.6.0",
                       "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz"
                     },
                     "uglify-to-browserify": {
                       "version": "1.0.2",
-                      "from": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
+                      "from": "uglify-to-browserify@>=1.0.0 <1.1.0",
                       "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz"
                     },
                     "yargs": {
                       "version": "3.10.0",
-                      "from": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
+                      "from": "yargs@>=3.10.0 <3.11.0",
                       "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
                       "dependencies": {
                         "window-size": {
                           "version": "0.1.0",
-                          "from": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
+                          "from": "window-size@0.1.0",
                           "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz"
                         }
                       }
@@ -2810,47 +2814,37 @@
               }
             },
             "js-yaml": {
-              "version": "3.4.6",
-              "from": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.4.6.tgz",
-              "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.4.6.tgz",
+              "version": "3.5.3",
+              "from": "js-yaml@>=3.0.0 <4.0.0",
+              "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.5.3.tgz",
               "dependencies": {
                 "argparse": {
-                  "version": "1.0.3",
-                  "from": "https://registry.npmjs.org/argparse/-/argparse-1.0.3.tgz",
-                  "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.3.tgz",
+                  "version": "1.0.6",
+                  "from": "argparse@>=1.0.2 <2.0.0",
+                  "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.6.tgz",
                   "dependencies": {
                     "sprintf-js": {
                       "version": "1.0.3",
-                      "from": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+                      "from": "sprintf-js@>=1.0.2 <1.1.0",
                       "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz"
                     }
                   }
-                },
-                "esprima": {
-                  "version": "2.7.1",
-                  "from": "https://registry.npmjs.org/esprima/-/esprima-2.7.1.tgz",
-                  "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.1.tgz"
-                },
-                "inherit": {
-                  "version": "2.2.2",
-                  "from": "https://registry.npmjs.org/inherit/-/inherit-2.2.2.tgz",
-                  "resolved": "https://registry.npmjs.org/inherit/-/inherit-2.2.2.tgz"
                 }
               }
             },
             "nopt": {
               "version": "3.0.6",
-              "from": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
+              "from": "nopt@>=3.0.0 <4.0.0",
               "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz"
             },
             "supports-color": {
               "version": "3.1.2",
-              "from": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz",
+              "from": "supports-color@>=3.1.0 <4.0.0",
               "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz",
               "dependencies": {
                 "has-flag": {
                   "version": "1.0.0",
-                  "from": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+                  "from": "has-flag@>=1.0.0 <2.0.0",
                   "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz"
                 }
               }
@@ -2858,449 +2852,518 @@
           }
         },
         "jsdom": {
-          "version": "7.2.1",
-          "from": "https://registry.npmjs.org/jsdom/-/jsdom-7.2.1.tgz",
-          "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-7.2.1.tgz",
+          "version": "7.2.2",
+          "from": "jsdom@>=7.2.0 <8.0.0",
+          "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-7.2.2.tgz",
           "dependencies": {
             "abab": {
-              "version": "1.0.1",
-              "from": "https://registry.npmjs.org/abab/-/abab-1.0.1.tgz",
-              "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.1.tgz"
+              "version": "1.0.3",
+              "from": "abab@>=1.0.0 <2.0.0",
+              "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.3.tgz"
             },
             "acorn": {
-              "version": "2.6.4",
-              "from": "https://registry.npmjs.org/acorn/-/acorn-2.6.4.tgz",
-              "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.6.4.tgz"
+              "version": "2.7.0",
+              "from": "acorn@>=2.4.0 <3.0.0",
+              "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz"
             },
             "acorn-globals": {
               "version": "1.0.9",
-              "from": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz",
+              "from": "acorn-globals@>=1.0.4 <2.0.0",
               "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz"
             },
             "cssom": {
-              "version": "0.3.0",
-              "from": "https://registry.npmjs.org/cssom/-/cssom-0.3.0.tgz",
-              "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.0.tgz"
+              "version": "0.3.1",
+              "from": "cssom@>=0.3.0 <0.4.0",
+              "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.1.tgz"
             },
             "cssstyle": {
-              "version": "0.2.30",
-              "from": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.30.tgz",
-              "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.30.tgz"
+              "version": "0.2.34",
+              "from": "cssstyle@>=0.2.29 <0.3.0",
+              "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.34.tgz"
             },
             "escodegen": {
-              "version": "1.7.1",
-              "from": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.1.tgz",
-              "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.1.tgz",
+              "version": "1.8.0",
+              "from": "escodegen@>=1.6.1 <2.0.0",
+              "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.0.tgz",
               "dependencies": {
                 "estraverse": {
                   "version": "1.9.3",
-                  "from": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz",
+                  "from": "estraverse@>=1.9.1 <2.0.0",
                   "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz"
                 },
                 "esprima": {
-                  "version": "1.2.5",
-                  "from": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz",
-                  "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz"
+                  "version": "2.7.2",
+                  "from": "esprima@>=2.7.1 <3.0.0",
+                  "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.2.tgz"
                 },
                 "optionator": {
-                  "version": "0.5.0",
-                  "from": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz",
-                  "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz",
+                  "version": "0.8.1",
+                  "from": "optionator@>=0.8.1 <0.9.0",
+                  "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.1.tgz",
                   "dependencies": {
                     "prelude-ls": {
                       "version": "1.1.2",
-                      "from": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+                      "from": "prelude-ls@>=1.1.1 <1.2.0",
                       "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz"
                     },
                     "deep-is": {
                       "version": "0.1.3",
-                      "from": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+                      "from": "deep-is@>=0.1.2 <0.2.0",
                       "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz"
                     },
-                    "wordwrap": {
-                      "version": "0.0.3",
-                      "from": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
-                      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
-                    },
                     "type-check": {
-                      "version": "0.3.1",
-                      "from": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz",
-                      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz"
+                      "version": "0.3.2",
+                      "from": "type-check@>=0.3.1 <0.4.0",
+                      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz"
                     },
                     "levn": {
-                      "version": "0.2.5",
-                      "from": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz",
-                      "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz"
+                      "version": "0.3.0",
+                      "from": "levn@>=0.3.0 <0.4.0",
+                      "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz"
                     },
                     "fast-levenshtein": {
-                      "version": "1.0.7",
-                      "from": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz",
-                      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz"
+                      "version": "1.1.3",
+                      "from": "fast-levenshtein@>=1.1.0 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.3.tgz"
                     }
                   }
                 },
                 "source-map": {
                   "version": "0.2.0",
-                  "from": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz",
+                  "from": "source-map@>=0.2.0 <0.3.0",
                   "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz"
                 }
               }
             },
             "nwmatcher": {
               "version": "1.3.7",
-              "from": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.3.7.tgz",
+              "from": "nwmatcher@>=1.3.7 <2.0.0",
               "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.3.7.tgz"
             },
             "parse5": {
               "version": "1.5.1",
-              "from": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz",
+              "from": "parse5@>=1.5.1 <2.0.0",
               "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz"
             },
             "request": {
-              "version": "2.67.0",
-              "from": "https://registry.npmjs.org/request/-/request-2.67.0.tgz",
-              "resolved": "https://registry.npmjs.org/request/-/request-2.67.0.tgz",
+              "version": "2.69.0",
+              "from": "request@>=2.55.0 <3.0.0",
+              "resolved": "https://registry.npmjs.org/request/-/request-2.69.0.tgz",
               "dependencies": {
+                "aws-sign2": {
+                  "version": "0.6.0",
+                  "from": "aws-sign2@>=0.6.0 <0.7.0",
+                  "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
+                },
+                "aws4": {
+                  "version": "1.2.1",
+                  "from": "aws4@>=1.2.1 <2.0.0",
+                  "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.2.1.tgz",
+                  "dependencies": {
+                    "lru-cache": {
+                      "version": "2.7.3",
+                      "from": "lru-cache@>=2.6.5 <3.0.0",
+                      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz"
+                    }
+                  }
+                },
                 "bl": {
-                  "version": "1.0.0",
-                  "from": "https://registry.npmjs.org/bl/-/bl-1.0.0.tgz",
-                  "resolved": "https://registry.npmjs.org/bl/-/bl-1.0.0.tgz"
+                  "version": "1.0.3",
+                  "from": "bl@>=1.0.0 <1.1.0",
+                  "resolved": "https://registry.npmjs.org/bl/-/bl-1.0.3.tgz",
+                  "dependencies": {
+                    "readable-stream": {
+                      "version": "2.0.5",
+                      "from": "readable-stream@>=2.0.5 <2.1.0",
+                      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.5.tgz",
+                      "dependencies": {
+                        "process-nextick-args": {
+                          "version": "1.0.6",
+                          "from": "process-nextick-args@>=1.0.6 <1.1.0",
+                          "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.6.tgz"
+                        }
+                      }
+                    }
+                  }
                 },
                 "caseless": {
                   "version": "0.11.0",
-                  "from": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz",
+                  "from": "caseless@>=0.11.0 <0.12.0",
                   "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
                 },
+                "combined-stream": {
+                  "version": "1.0.5",
+                  "from": "combined-stream@>=1.0.5 <1.1.0",
+                  "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
+                  "dependencies": {
+                    "delayed-stream": {
+                      "version": "1.0.0",
+                      "from": "delayed-stream@>=1.0.0 <1.1.0",
+                      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
+                    }
+                  }
+                },
                 "extend": {
                   "version": "3.0.0",
-                  "from": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz",
+                  "from": "extend@>=3.0.0 <3.1.0",
                   "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz"
                 },
                 "forever-agent": {
                   "version": "0.6.1",
-                  "from": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+                  "from": "forever-agent@>=0.6.1 <0.7.0",
                   "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz"
                 },
                 "form-data": {
                   "version": "1.0.0-rc3",
-                  "from": "https://registry.npmjs.org/form-data/-/form-data-1.0.0-rc3.tgz",
+                  "from": "form-data@>=1.0.0-rc3 <1.1.0",
                   "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.0-rc3.tgz",
                   "dependencies": {
                     "async": {
-                      "version": "1.5.0",
-                      "from": "https://registry.npmjs.org/async/-/async-1.5.0.tgz",
-                      "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz"
+                      "version": "1.5.2",
+                      "from": "async@>=1.4.0 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz"
                     }
                   }
                 },
-                "json-stringify-safe": {
-                  "version": "5.0.1",
-                  "from": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
-                  "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
-                },
-                "mime-types": {
-                  "version": "2.1.8",
-                  "from": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.8.tgz",
-                  "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.8.tgz",
+                "har-validator": {
+                  "version": "2.0.6",
+                  "from": "har-validator@>=2.0.6 <2.1.0",
+                  "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz",
                   "dependencies": {
-                    "mime-db": {
-                      "version": "1.20.0",
-                      "from": "https://registry.npmjs.org/mime-db/-/mime-db-1.20.0.tgz",
-                      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.20.0.tgz"
+                    "is-my-json-valid": {
+                      "version": "2.12.4",
+                      "from": "is-my-json-valid@>=2.12.4 <3.0.0",
+                      "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.4.tgz",
+                      "dependencies": {
+                        "generate-function": {
+                          "version": "2.0.0",
+                          "from": "generate-function@>=2.0.0 <3.0.0",
+                          "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz"
+                        },
+                        "generate-object-property": {
+                          "version": "1.2.0",
+                          "from": "generate-object-property@>=1.1.0 <2.0.0",
+                          "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
+                          "dependencies": {
+                            "is-property": {
+                              "version": "1.0.2",
+                              "from": "is-property@>=1.0.0 <2.0.0",
+                              "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz"
+                            }
+                          }
+                        },
+                        "jsonpointer": {
+                          "version": "2.0.0",
+                          "from": "jsonpointer@2.0.0",
+                          "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
+                        }
+                      }
+                    },
+                    "pinkie-promise": {
+                      "version": "2.0.0",
+                      "from": "pinkie-promise@>=2.0.0 <3.0.0",
+                      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.0.tgz",
+                      "dependencies": {
+                        "pinkie": {
+                          "version": "2.0.4",
+                          "from": "pinkie@>=2.0.0 <3.0.0",
+                          "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz"
+                        }
+                      }
                     }
                   }
                 },
-                "node-uuid": {
-                  "version": "1.4.7",
-                  "from": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz",
-                  "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz"
-                },
-                "qs": {
-                  "version": "5.2.0",
-                  "from": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz",
-                  "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz"
-                },
-                "tunnel-agent": {
-                  "version": "0.4.2",
-                  "from": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.2.tgz",
-                  "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.2.tgz"
+                "hawk": {
+                  "version": "3.1.3",
+                  "from": "hawk@>=3.1.0 <3.2.0",
+                  "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
+                  "dependencies": {
+                    "hoek": {
+                      "version": "2.16.3",
+                      "from": "hoek@>=2.0.0 <3.0.0",
+                      "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz"
+                    },
+                    "boom": {
+                      "version": "2.10.1",
+                      "from": "boom@>=2.0.0 <3.0.0",
+                      "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz"
+                    },
+                    "cryptiles": {
+                      "version": "2.0.5",
+                      "from": "cryptiles@>=2.0.0 <3.0.0",
+                      "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz"
+                    },
+                    "sntp": {
+                      "version": "1.0.9",
+                      "from": "sntp@>=1.0.0 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
+                    }
+                  }
                 },
                 "http-signature": {
-                  "version": "1.1.0",
-                  "from": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.0.tgz",
-                  "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.0.tgz",
+                  "version": "1.1.1",
+                  "from": "http-signature@>=1.1.0 <1.2.0",
+                  "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz",
                   "dependencies": {
                     "assert-plus": {
-                      "version": "0.1.5",
-                      "from": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz",
-                      "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
+                      "version": "0.2.0",
+                      "from": "assert-plus@>=0.2.0 <0.3.0",
+                      "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz"
                     },
                     "jsprim": {
                       "version": "1.2.2",
-                      "from": "https://registry.npmjs.org/jsprim/-/jsprim-1.2.2.tgz",
+                      "from": "jsprim@>=1.2.2 <2.0.0",
                       "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.2.2.tgz",
                       "dependencies": {
                         "extsprintf": {
                           "version": "1.0.2",
-                          "from": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz",
+                          "from": "extsprintf@1.0.2",
                           "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz"
                         },
                         "json-schema": {
                           "version": "0.2.2",
-                          "from": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.2.tgz",
+                          "from": "json-schema@0.2.2",
                           "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.2.tgz"
                         },
                         "verror": {
                           "version": "1.3.6",
-                          "from": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz",
+                          "from": "verror@1.3.6",
                           "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz"
                         }
                       }
                     },
                     "sshpk": {
-                      "version": "1.7.1",
-                      "from": "https://registry.npmjs.org/sshpk/-/sshpk-1.7.1.tgz",
-                      "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.7.1.tgz",
+                      "version": "1.7.4",
+                      "from": "sshpk@>=1.7.0 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.7.4.tgz",
                       "dependencies": {
                         "asn1": {
                           "version": "0.2.3",
-                          "from": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
+                          "from": "asn1@>=0.2.3 <0.3.0",
                           "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz"
                         },
-                        "assert-plus": {
-                          "version": "0.2.0",
-                          "from": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz",
-                          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz"
-                        },
                         "dashdash": {
-                          "version": "1.10.1",
-                          "from": "https://registry.npmjs.org/dashdash/-/dashdash-1.10.1.tgz",
-                          "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.10.1.tgz",
+                          "version": "1.13.0",
+                          "from": "dashdash@>=1.10.1 <2.0.0",
+                          "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.13.0.tgz",
                           "dependencies": {
                             "assert-plus": {
-                              "version": "0.1.5",
-                              "from": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz",
-                              "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
+                              "version": "1.0.0",
+                              "from": "assert-plus@>=1.0.0 <2.0.0",
+                              "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz"
                             }
                           }
                         },
                         "jsbn": {
                           "version": "0.1.0",
-                          "from": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz",
+                          "from": "jsbn@>=0.1.0 <0.2.0",
                           "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz"
                         },
                         "tweetnacl": {
-                          "version": "0.13.2",
-                          "from": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.13.2.tgz",
-                          "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.13.2.tgz"
+                          "version": "0.13.3",
+                          "from": "tweetnacl@>=0.13.0 <1.0.0",
+                          "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.13.3.tgz"
                         },
                         "jodid25519": {
                           "version": "1.0.2",
-                          "from": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz",
+                          "from": "jodid25519@>=1.0.0 <2.0.0",
                           "resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz"
                         },
                         "ecc-jsbn": {
                           "version": "0.1.1",
-                          "from": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
+                          "from": "ecc-jsbn@>=0.0.1 <1.0.0",
                           "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz"
                         }
                       }
                     }
                   }
                 },
-                "oauth-sign": {
-                  "version": "0.8.0",
-                  "from": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.0.tgz",
-                  "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.0.tgz"
+                "is-typedarray": {
+                  "version": "1.0.0",
+                  "from": "is-typedarray@>=1.0.0 <1.1.0",
+                  "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz"
                 },
-                "hawk": {
-                  "version": "3.1.2",
-                  "from": "https://registry.npmjs.org/hawk/-/hawk-3.1.2.tgz",
-                  "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.2.tgz",
+                "isstream": {
+                  "version": "0.1.2",
+                  "from": "isstream@>=0.1.2 <0.2.0",
+                  "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
+                },
+                "json-stringify-safe": {
+                  "version": "5.0.1",
+                  "from": "json-stringify-safe@>=5.0.1 <5.1.0",
+                  "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
+                },
+                "mime-types": {
+                  "version": "2.1.10",
+                  "from": "mime-types@>=2.1.7 <2.2.0",
+                  "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.10.tgz",
                   "dependencies": {
-                    "hoek": {
-                      "version": "2.16.3",
-                      "from": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
-                      "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz"
-                    },
-                    "boom": {
-                      "version": "2.10.1",
-                      "from": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
-                      "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz"
-                    },
-                    "cryptiles": {
-                      "version": "2.0.5",
-                      "from": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
-                      "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz"
-                    },
-                    "sntp": {
-                      "version": "1.0.9",
-                      "from": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
-                      "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
+                    "mime-db": {
+                      "version": "1.22.0",
+                      "from": "mime-db@>=1.22.0 <1.23.0",
+                      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.22.0.tgz"
                     }
                   }
                 },
-                "aws-sign2": {
-                  "version": "0.6.0",
-                  "from": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz",
-                  "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
+                "node-uuid": {
+                  "version": "1.4.7",
+                  "from": "node-uuid@>=1.4.7 <1.5.0",
+                  "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz"
+                },
+                "oauth-sign": {
+                  "version": "0.8.1",
+                  "from": "oauth-sign@>=0.8.0 <0.9.0",
+                  "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.1.tgz"
+                },
+                "qs": {
+                  "version": "6.0.2",
+                  "from": "qs@>=6.0.2 <6.1.0",
+                  "resolved": "https://registry.npmjs.org/qs/-/qs-6.0.2.tgz"
                 },
                 "stringstream": {
                   "version": "0.0.5",
-                  "from": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
+                  "from": "stringstream@>=0.0.4 <0.1.0",
                   "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
                 },
-                "combined-stream": {
-                  "version": "1.0.5",
-                  "from": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
-                  "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
-                  "dependencies": {
-                    "delayed-stream": {
-                      "version": "1.0.0",
-                      "from": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
-                      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
-                    }
-                  }
-                },
-                "isstream": {
-                  "version": "0.1.2",
-                  "from": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
-                  "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
-                },
-                "is-typedarray": {
-                  "version": "1.0.0",
-                  "from": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
-                  "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz"
-                },
-                "har-validator": {
-                  "version": "2.0.3",
-                  "from": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.3.tgz",
-                  "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.3.tgz",
-                  "dependencies": {
-                    "is-my-json-valid": {
-                      "version": "2.12.3",
-                      "from": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.3.tgz",
-                      "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.3.tgz",
-                      "dependencies": {
-                        "generate-function": {
-                          "version": "2.0.0",
-                          "from": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz",
-                          "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz"
-                        },
-                        "generate-object-property": {
-                          "version": "1.2.0",
-                          "from": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
-                          "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
-                          "dependencies": {
-                            "is-property": {
-                              "version": "1.0.2",
-                              "from": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
-                              "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz"
-                            }
-                          }
-                        },
-                        "jsonpointer": {
-                          "version": "2.0.0",
-                          "from": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz",
-                          "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
-                        }
-                      }
-                    },
-                    "pinkie-promise": {
-                      "version": "2.0.0",
-                      "from": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.0.tgz",
-                      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.0.tgz",
-                      "dependencies": {
-                        "pinkie": {
-                          "version": "2.0.1",
-                          "from": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.1.tgz",
-                          "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.1.tgz"
-                        }
-                      }
-                    }
-                  }
+                "tunnel-agent": {
+                  "version": "0.4.2",
+                  "from": "tunnel-agent@>=0.4.1 <0.5.0",
+                  "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.2.tgz"
                 }
               }
             },
             "sax": {
-              "version": "1.1.4",
-              "from": "https://registry.npmjs.org/sax/-/sax-1.1.4.tgz",
-              "resolved": "https://registry.npmjs.org/sax/-/sax-1.1.4.tgz"
+              "version": "1.1.5",
+              "from": "sax@>=1.1.4 <2.0.0",
+              "resolved": "https://registry.npmjs.org/sax/-/sax-1.1.5.tgz"
             },
             "symbol-tree": {
               "version": "3.1.4",
-              "from": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.1.4.tgz",
+              "from": "symbol-tree@>=3.1.0 <4.0.0",
               "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.1.4.tgz"
             },
             "tough-cookie": {
               "version": "2.2.1",
-              "from": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.1.tgz",
+              "from": "tough-cookie@>=2.2.0 <3.0.0",
               "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.1.tgz"
             },
             "webidl-conversions": {
               "version": "2.0.1",
-              "from": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-2.0.1.tgz",
+              "from": "webidl-conversions@>=2.0.0 <3.0.0",
               "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-2.0.1.tgz"
             },
             "whatwg-url-compat": {
               "version": "0.6.5",
-              "from": "https://registry.npmjs.org/whatwg-url-compat/-/whatwg-url-compat-0.6.5.tgz",
+              "from": "whatwg-url-compat@>=0.6.5 <0.7.0",
               "resolved": "https://registry.npmjs.org/whatwg-url-compat/-/whatwg-url-compat-0.6.5.tgz",
               "dependencies": {
                 "tr46": {
-                  "version": "0.0.2",
-                  "from": "https://registry.npmjs.org/tr46/-/tr46-0.0.2.tgz",
-                  "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.2.tgz"
+                  "version": "0.0.3",
+                  "from": "tr46@>=0.0.1 <0.1.0",
+                  "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz"
                 }
               }
             },
             "xml-name-validator": {
               "version": "2.0.1",
-              "from": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz",
+              "from": "xml-name-validator@>=2.0.1 <3.0.0",
               "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz"
             }
           }
         },
-        "json-stable-stringify": {
-          "version": "1.0.0",
-          "from": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.0.tgz",
-          "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.0.tgz",
-          "dependencies": {
-            "jsonify": {
-              "version": "0.0.0",
-              "from": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
-              "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz"
-            }
-          }
-        },
         "node-haste": {
-          "version": "1.2.8",
-          "from": "https://registry.npmjs.org/node-haste/-/node-haste-1.2.8.tgz",
-          "resolved": "https://registry.npmjs.org/node-haste/-/node-haste-1.2.8.tgz",
+          "version": "2.0.0-alpha19",
+          "from": "node-haste@2.0.0-alpha19",
+          "resolved": "https://registry.npmjs.org/node-haste/-/node-haste-2.0.0-alpha19.tgz",
           "dependencies": {
-            "esprima-fb": {
-              "version": "4001.1001.0-dev-harmony-fb",
-              "from": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-4001.1001.0-dev-harmony-fb.tgz",
-              "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-4001.1001.0-dev-harmony-fb.tgz"
+            "sane": {
+              "version": "1.3.1",
+              "from": "sane@>=1.3.1 <2.0.0",
+              "resolved": "https://registry.npmjs.org/sane/-/sane-1.3.1.tgz",
+              "dependencies": {
+                "exec-sh": {
+                  "version": "0.2.0",
+                  "from": "exec-sh@>=0.2.0 <0.3.0",
+                  "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.0.tgz",
+                  "dependencies": {
+                    "merge": {
+                      "version": "1.2.0",
+                      "from": "merge@>=1.1.3 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz"
+                    }
+                  }
+                },
+                "fb-watchman": {
+                  "version": "1.9.0",
+                  "from": "fb-watchman@>=1.8.0 <2.0.0",
+                  "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.9.0.tgz"
+                },
+                "minimatch": {
+                  "version": "0.2.14",
+                  "from": "minimatch@>=0.2.14 <0.3.0",
+                  "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz",
+                  "dependencies": {
+                    "lru-cache": {
+                      "version": "2.7.3",
+                      "from": "lru-cache@>=2.0.0 <3.0.0",
+                      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz"
+                    },
+                    "sigmund": {
+                      "version": "1.0.1",
+                      "from": "sigmund@>=1.0.0 <1.1.0",
+                      "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz"
+                    }
+                  }
+                },
+                "walker": {
+                  "version": "1.0.7",
+                  "from": "walker@>=1.0.5 <1.1.0",
+                  "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz",
+                  "dependencies": {
+                    "makeerror": {
+                      "version": "1.0.11",
+                      "from": "makeerror@>=1.0.0 <1.1.0",
+                      "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz",
+                      "dependencies": {
+                        "tmpl": {
+                          "version": "1.0.4",
+                          "from": "tmpl@>=1.0.0 <1.1.0",
+                          "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz"
+                        }
+                      }
+                    }
+                  }
+                },
+                "watch": {
+                  "version": "0.10.0",
+                  "from": "watch@>=0.10.0 <0.11.0",
+                  "resolved": "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz"
+                }
+              }
             }
           }
         },
         "which": {
-          "version": "1.2.0",
-          "from": "https://registry.npmjs.org/which/-/which-1.2.0.tgz",
-          "resolved": "https://registry.npmjs.org/which/-/which-1.2.0.tgz",
+          "version": "1.2.4",
+          "from": "which@>=1.1.1 <2.0.0",
+          "resolved": "https://registry.npmjs.org/which/-/which-1.2.4.tgz",
           "dependencies": {
             "is-absolute": {
               "version": "0.1.7",
-              "from": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz",
+              "from": "is-absolute@>=0.1.7 <0.2.0",
               "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz",
               "dependencies": {
                 "is-relative": {
                   "version": "0.1.3",
-                  "from": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz",
+                  "from": "is-relative@>=0.1.0 <0.2.0",
                   "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz"
                 }
               }
+            },
+            "isexe": {
+              "version": "1.1.2",
+              "from": "isexe@>=1.1.1 <2.0.0",
+              "resolved": "https://registry.npmjs.org/isexe/-/isexe-1.1.2.tgz"
             }
           }
         }
diff --git a/package.json b/package.json
index 0964bfca8c29..852ae1cb3d83 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,17 @@
     "testPathIgnorePatterns": [
       "/node_modules/"
     ],
+    "haste": {
+      "defaultPlatform": "ios",
+      "providesModuleNodeModules": [
+        "fbjs",
+        "react",
+        "react-native",
+        "parse",
+        "react-transform-hmr"
+      ],
+      "platforms": ["ios", "android"]
+    },
     "modulePathIgnorePatterns": [
       "/node_modules/(?!react|fbjs|react-native|parse|react-transform-hmr|core-js|promise)/",
       "node_modules/react/lib/React.js",
@@ -160,7 +171,7 @@
     "yeoman-generator": "^0.20.3"
   },
   "devDependencies": {
-    "jest-cli": "0.8.2",
+    "jest-cli": "0.9.0-fb1",
     "babel-eslint": "4.1.4",
     "eslint": "1.3.1",
     "eslint-plugin-react": "3.3.1",
diff --git a/packager/react-packager/src/Server/__tests__/Server-test.js b/packager/react-packager/src/Server/__tests__/Server-test.js
index b731a026526e..e6a74aeb0a7b 100644
--- a/packager/react-packager/src/Server/__tests__/Server-test.js
+++ b/packager/react-packager/src/Server/__tests__/Server-test.js
@@ -10,6 +10,7 @@
 
 jest.setMock('worker-farm', function() { return () => {}; })
     .dontMock('os')
+    .dontMock('underscore')
     .dontMock('path')
     .dontMock('url')
     .setMock('timers', { setImmediate: (fn) => setTimeout(fn, 0) })
diff --git a/packager/react-packager/src/SocketInterface/__tests__/SocketInterface-test.js b/packager/react-packager/src/SocketInterface/__tests__/SocketInterface-test.js
index 729d2a1ddfb2..cf8345b3eb98 100644
--- a/packager/react-packager/src/SocketInterface/__tests__/SocketInterface-test.js
+++ b/packager/react-packager/src/SocketInterface/__tests__/SocketInterface-test.js
@@ -11,6 +11,7 @@
 jest.setMock('worker-farm', function() { return () => {}; })
     .setMock('uglify-js')
     .mock('child_process')
+    .dontMock('underscore')
     .dontMock('../');
 
 var SocketInterface = require('../');
diff --git a/packager/react-packager/__mocks__/debug.js b/packager/react-packager/src/__mocks__/debug.js
similarity index 100%
rename from packager/react-packager/__mocks__/debug.js
rename to packager/react-packager/src/__mocks__/debug.js

From 914862022c50ecb2fa036ba3566aed0a15b10a84 Mon Sep 17 00:00:00 2001
From: Fada Chen <chenfada@fb.com>
Date: Thu, 18 Feb 2016 00:37:29 -0800
Subject: [PATCH 1209/1411] fix an image cropping bug when displaySize is
 specified

Summary:Diff D2647083 cleaned up image editing related logics and introduced an image cropping bug.
The bug is that the result of the image cropping will be wrong if displaySize is specified.
In particular, in Ads Manager App, we generate thumbnail by calling the image cropping function with displaySize set.
With this bug, the thumbnail we get is not correct.
This diff fixed the bug by replacing `image` with `croppedImage`. It should be a typo from D2647083

Reviewed By: zjj010104

Differential Revision: D2947730

fb-gh-sync-id: df7c7f3ddac5b053425db884f808e27b8418116e
shipit-source-id: df7c7f3ddac5b053425db884f808e27b8418116e
---
 Libraries/Image/RCTImageEditingManager.m | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Libraries/Image/RCTImageEditingManager.m b/Libraries/Image/RCTImageEditingManager.m
index 2a2ea967161b..9ff231d64f7f 100644
--- a/Libraries/Image/RCTImageEditingManager.m
+++ b/Libraries/Image/RCTImageEditingManager.m
@@ -62,8 +62,8 @@ @implementation RCTImageEditingManager
       targetSize = [RCTConvert CGSize:cropData[@"displaySize"]]; // in pixels
       RCTResizeMode resizeMode = [RCTConvert RCTResizeMode:cropData[@"resizeMode"] ?: @"contain"];
       targetRect = RCTTargetRect(croppedImage.size, targetSize, 1, resizeMode);
-      transform = RCTTransformFromTargetRect(image.size, targetRect);
-      croppedImage = RCTTransformImage(image, targetSize, image.scale, transform);
+      transform = RCTTransformFromTargetRect(croppedImage.size, targetRect);
+      croppedImage = RCTTransformImage(croppedImage, targetSize, image.scale, transform);
     }
 
     // Store image

From 449d4d4edd98364be19587165561f777881f5ffb Mon Sep 17 00:00:00 2001
From: Al Sutton <alsutton@fb.com>
Date: Thu, 18 Feb 2016 01:09:05 -0800
Subject: [PATCH 1210/1411] Remove old android support library version

Differential Revision: D2943730

fb-gh-sync-id: 61a5981efe8c15594bcf7d3369cc24261894ef0b
shipit-source-id: 61a5981efe8c15594bcf7d3369cc24261894ef0b
---
 .../src/main/java/com/facebook/react/views/switchview/BUCK      | 2 +-
 .../src/main/java/com/facebook/react/views/toolbar/BUCK         | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK
index 1ac7f3c79e6b..896c30983591 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK
@@ -8,7 +8,7 @@ android_library(
     react_native_target('java/com/facebook/csslayout:csslayout'),
     react_native_target('java/com/facebook/react/uimanager:uimanager'),
     react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
-    react_native_dep('third-party/android-support-for-standalone-apps/v7/appcompat:appcompat-23.1'),
+    react_native_dep('third-party/android-support-for-standalone-apps/v7/appcompat:appcompat'),
     react_native_dep('third-party/android-support-for-standalone-apps/v7/appcompat:res-for-react-native'),
     react_native_dep('third-party/java/jsr-305:jsr-305'),
   ],
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK
index 253f3576a0f1..dbb6d2b26bb8 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK
@@ -12,7 +12,7 @@ android_library(
     react_native_dep('libraries/fresco/fresco-react-native:fresco-react-native'),
     react_native_dep('libraries/fresco/fresco-react-native:fresco-drawee'),
     react_native_dep('libraries/fresco/fresco-react-native:imagepipeline'),
-    react_native_dep('third-party/android-support-for-standalone-apps/v7/appcompat:appcompat-23.1'),
+    react_native_dep('third-party/android-support-for-standalone-apps/v7/appcompat:appcompat'),
     react_native_dep('third-party/android-support-for-standalone-apps/v7/appcompat:res-for-react-native'),
     react_native_dep('third-party/android/support/v4:lib-support-v4'),
     react_native_dep('third-party/java/jsr-305:jsr-305'),

From 774757d628cac1157a36c48204fc4d76facb6c5b Mon Sep 17 00:00:00 2001
From: hycner <hycner@gmail.com>
Date: Thu, 18 Feb 2016 04:09:59 -0800
Subject: [PATCH 1211/1411] Add Text destructuring to example

Summary:Destructuring of Text component was missing from example
Closes https://github.com/facebook/react-native/pull/5998

Differential Revision: D2948871

fb-gh-sync-id: 83c2c633f768028d28d5e9ba37463021c8dc5eea
shipit-source-id: 83c2c633f768028d28d5e9ba37463021c8dc5eea
---
 website/src/react-native/index.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/website/src/react-native/index.js b/website/src/react-native/index.js
index 84dcbf26f257..a85130d54412 100644
--- a/website/src/react-native/index.js
+++ b/website/src/react-native/index.js
@@ -68,7 +68,7 @@ var App = React.createClass({
 {`// Android
 
 var React = require('react-native');
-var { DrawerLayoutAndroid, ProgressBarAndroid } = React;
+var { DrawerLayoutAndroid, ProgressBarAndroid, Text } = React;
 
 var App = React.createClass({
   render: function() {

From 8770fd9c11300e0adf1eb7d5193a6a57178e68be Mon Sep 17 00:00:00 2001
From: CodeBaker <everfire130@users.noreply.github.com>
Date: Thu, 18 Feb 2016 04:17:57 -0800
Subject: [PATCH 1212/1411] =?UTF-8?q?add=20"=E7=83=98=E7=84=99=E5=B8=AE"?=
 =?UTF-8?q?=20case?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Summary:add "烘焙帮" case
Closes https://github.com/facebook/react-native/pull/5995

Differential Revision: D2948873

fb-gh-sync-id: 707bd5f36a14389dc46fb8a425e421c8be3309ef
shipit-source-id: 707bd5f36a14389dc46fb8a425e421c8be3309ef
---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index feb4d0ed915d..f435292d7634 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -598,6 +598,12 @@ var apps = [
     linkPlayStore: 'https://play.google.com/store/apps/details?id=com.plasticaromantica.utayomin',
     author: 'Takayuki IMAI'
   },
+  {
+    name: '烘焙帮',
+    icon: 'http://a1.mzstatic.com/us/r30/Purple69/v4/79/85/ba/7985ba1d-a807-7c34-98f1-e9e2ed5d2cb5/icon175x175.jpeg',
+    linkAppStore: 'https://itunes.apple.com/cn/app/hong-bei-bang-hai-liang-hong/id1007812319?mt=8',
+    author: 'Hongbeibang'
+  },
 ];
 
 var AppList = React.createClass({

From fc52a65e64ec3082753772992bca65dc886d9f57 Mon Sep 17 00:00:00 2001
From: Shawn Khameneh <skhameneh@gmail.com>
Date: Thu, 18 Feb 2016 04:23:34 -0800
Subject: [PATCH 1213/1411] Add MyMuesli to website showcase

Summary:Add MyMuesli to website showcase
Closes https://github.com/facebook/react-native/pull/5992

Differential Revision: D2948879

fb-gh-sync-id: ab1b9e586a78fd58ddf20fdd98932e758d6232c5
shipit-source-id: ab1b9e586a78fd58ddf20fdd98932e758d6232c5
---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index f435292d7634..63f9067c8744 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -70,6 +70,12 @@ var featured = [
     linkPlayStore: 'https://play.google.com/store/apps/details?id=com.movielala.trailers',
     author: 'MovieLaLa'
   },
+  {
+    name: 'MyMuesli',
+    icon: 'https://lh3.googleusercontent.com/1dCCeiyjuWRgY-Cnv-l-lOA1sVH3Cn0vkVWWZnaBQbhHOhsngLcnfy68WEerudPUysc=w300-rw',
+    link: 'https://play.google.com/store/apps/details?id=com.mymuesli',
+    author: 'Shawn Khameneh (@shawnscode), 3DWD'
+  },
   {
     name: 'Myntra',
     icon: 'http://a5.mzstatic.com/us/r30/Purple6/v4/9c/78/df/9c78dfa6-0061-1af2-5026-3e1d5a073c94/icon350x350.png',

From 62ac6aeb409f1b4ac078ef5dcf64abc43a4bc319 Mon Sep 17 00:00:00 2001
From: Grant Nestor <grantnestor@gmail.com>
Date: Thu, 18 Feb 2016 04:26:42 -0800
Subject: [PATCH 1214/1411] showcase/whammy

Summary:Added Whammy to showcase
Closes https://github.com/facebook/react-native/pull/5987

Differential Revision: D2948883

fb-gh-sync-id: cd2a3f7b228d051a055b6fe052be31cab5a98f9f
shipit-source-id: cd2a3f7b228d051a055b6fe052be31cab5a98f9f
---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 63f9067c8744..e341f7f07e9f 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -554,6 +554,12 @@ var apps = [
     linkPlayStore: 'https://play.google.com/store/apps/details?id=com.wearvr.app',
     author: 'WEARVR LLC',
   },
+  {
+    name: 'Whammy',
+    icon: 'http://a4.mzstatic.com/us/r30/Purple49/v4/8f/1c/21/8f1c2158-c7fb-1bbb-94db-e77b867aad1a/icon175x175.jpeg',
+    link: 'https://itunes.apple.com/us/app/whammy/id899759777',
+    author: 'Play Company',
+  },
   {
     name: 'WOOP',
     icon: 'http://a4.mzstatic.com/us/r30/Purple6/v4/b0/44/f9/b044f93b-dbf3-9ae5-0f36-9b4956628cab/icon350x350.jpeg',

From e0a0cac280cbe044862d35adf715b679d418d0de Mon Sep 17 00:00:00 2001
From: Qiao Liang <qiaoliang89@gmail.com>
Date: Thu, 18 Feb 2016 05:40:12 -0800
Subject: [PATCH 1215/1411] add getter as public api for
 ErrorUtils._globalHandler

Summary:As discussed here #1194 . This add an getter the default handler, so that custom handler can be added (monkey patch?) without overwriting the default handler
Closes https://github.com/facebook/react-native/pull/5575

Differential Revision: D2948994

fb-gh-sync-id: 2b6d1619cfe68f78b326c6d232b9bf57c489c45d
shipit-source-id: 2b6d1619cfe68f78b326c6d232b9bf57c489c45d
---
 packager/react-packager/src/Resolver/polyfills/error-guard.js | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/packager/react-packager/src/Resolver/polyfills/error-guard.js b/packager/react-packager/src/Resolver/polyfills/error-guard.js
index 8810a4b12a77..d013ec1104c8 100644
--- a/packager/react-packager/src/Resolver/polyfills/error-guard.js
+++ b/packager/react-packager/src/Resolver/polyfills/error-guard.js
@@ -20,6 +20,9 @@ var ErrorUtils = {
   setGlobalHandler: function(fun) {
     ErrorUtils._globalHandler = fun;
   },
+  getGlobalHandler: function() {
+    return ErrorUtils._globalHandler;
+  },
   reportError: function(error) {
     ErrorUtils._globalHandler && ErrorUtils._globalHandler(error);
   },

From 3415e31f467fc35273dfaec09768290f34ee0a54 Mon Sep 17 00:00:00 2001
From: Steve Kellock <steve@kellock.ca>
Date: Thu, 18 Feb 2016 07:35:18 -0800
Subject: [PATCH 1216/1411] Adds additional help when a module is missing.

Summary:Hey.  Long time fan, first time forker.

You know when you're working on a project with someone and they bring in a new dependency?

When you first pull their code and you haven't also installed that dependency, the error that is shown is this:

![image](https://cloud.githubusercontent.com/assets/68273/13145164/d8748b3e-d61c-11e5-9df9-3e47edf3fcfb.png)

This PR simply adds  `or running "npm install"` to the end of that message.

Just adds a little clarity to newcomers.  Hell knows I was lost for a while when I was starting.

![image](https://cloud.githubusercontent.com/assets/68273/13145253/65e8f31a-d61d-11e5-99ac-2d79d8e37123.png)
Closes https://github.com/facebook/react-native/pull/6009

Differential Revision: D2949127

Pulled By: davidaurelio

fb-gh-sync-id: b297d8c1570fec23cb179ddab4847e2438cc463b
shipit-source-id: b297d8c1570fec23cb179ddab4847e2438cc463b
---
 .../react-packager/src/Resolver/polyfills/require-unbundle.js   | 2 +-
 packager/react-packager/src/Resolver/polyfills/require.js       | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/packager/react-packager/src/Resolver/polyfills/require-unbundle.js b/packager/react-packager/src/Resolver/polyfills/require-unbundle.js
index 87e856013e1e..9c1e36e77ff5 100644
--- a/packager/react-packager/src/Resolver/polyfills/require-unbundle.js
+++ b/packager/react-packager/src/Resolver/polyfills/require-unbundle.js
@@ -80,7 +80,7 @@ function unknownModuleError(id) {
   let message = 'Requiring unknown module "' + id + '".';
   if (__DEV__) {
     message +=
-      'If you are sure the module is there, try restarting the packager.';
+      'If you are sure the module is there, try restarting the packager or running "npm install".';
   }
   return Error(message);
 }
diff --git a/packager/react-packager/src/Resolver/polyfills/require.js b/packager/react-packager/src/Resolver/polyfills/require.js
index bc2824bba868..764e4dd1e2e1 100644
--- a/packager/react-packager/src/Resolver/polyfills/require.js
+++ b/packager/react-packager/src/Resolver/polyfills/require.js
@@ -48,7 +48,7 @@ function requireImpl(id) {
   if (!mod) {
     var msg = 'Requiring unknown module "' + id + '"';
     if (__DEV__) {
-      msg += '. If you are sure the module is there, try restarting the packager.';
+      msg += '. If you are sure the module is there, try restarting the packager or running "npm install".';
     }
     throw new Error(msg);
   }

From f4e085a06cb87525904de194334f800d714ac092 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Thu, 18 Feb 2016 07:59:07 -0800
Subject: [PATCH 1217/1411] Clean up docs on building RN Android from source

Summary:Turns out we had two guides for the same thing.

Closes #6007

Reviewed By: mkonicek

Differential Revision:D2949234
Ninja: oss-only

fb-gh-sync-id: eda3a904ce8d8e7213a39021eb60b52449b20a43
shipit-source-id: eda3a904ce8d8e7213a39021eb60b52449b20a43
---
 ReactAndroid/README.md            | 100 +-----------------------------
 docs/AndroidBuildingFromSource.md |  11 +++-
 2 files changed, 10 insertions(+), 101 deletions(-)

diff --git a/ReactAndroid/README.md b/ReactAndroid/README.md
index 891b008ac522..08c34b992492 100644
--- a/ReactAndroid/README.md
+++ b/ReactAndroid/README.md
@@ -1,101 +1,3 @@
 # Building React Native for Android
 
-This guide contains instructions for building the Android code and running the sample apps.
-
-## Supported Operating Systems
-
-This setup has only been tested on Mac OS so far.
-
-## Prerequisites
-
-Assuming you have the [Android SDK](https://developer.android.com/sdk/installing/index.html) installed, run `android` to open the Android SDK Manager.
-
-Make sure you have the following installed:
-
-- Android SDK version 23 (compileSdkVersion in [`build.gradle`](build.gradle))
-- SDK build tools version 23.0.1 (buildToolsVersion in [`build.gradle`](build.gradle))
-- Android Support Repository >= 17 (for Android Support Library)
-- Android NDK (download & extraction instructions [here](http://developer.android.com/ndk/downloads/index.html))
-
-Point Gradle to your Android SDK: either have `$ANDROID_SDK` and `$ANDROID_NDK` defined, or create a `local.properties` file in the root of your `react-native` checkout with the following contents:
-
-    sdk.dir=absolute_path_to_android_sdk
-    ndk.dir=absolute_path_to_android_ndk
-
-Example:
-
-    sdk.dir=/Users/your_unix_name/android-sdk-macosx
-    ndk.dir=/Users/your_unix_name/android-ndk/android-ndk-r10e
-
-## Run `npm install`
-
-This is needed to fetch the dependencies for the packager.
-
-```bash
-cd react-native
-npm install
-```
-
-## Building from the command line
-
-To build the framework code:
-
-```bash
-cd react-native
-./gradlew :ReactAndroid:assembleDebug
-```
-
-To install a snapshot version of the framework code in your local Maven repo:
-
-```bash
-./gradlew :ReactAndroid:installArchives
-```
-
-## Running the examples
-
-To run the UIExplorer app:
-
-```bash
-cd react-native
-./gradlew :Examples:UIExplorer:android:app:installDebug
-# Start the packager in a separate shell:
-# Make sure you ran npm install
-./packager/packager.sh
-# Open UIExplorer in your emulator, Menu button -> Reload JS should work
-```
-
-You can run any other sample app the same way, e.g.:
-
-```bash
-./gradlew :Examples:Movies:android:app:installDebug
-```
-
-## Building from Android Studio
-
-You'll need to do one additional step until we release the React Native Gradle plugin to Maven central. This is because Android Studio has its own local Maven repo:
-
-    mkdir -p /Applications/Android\ Studio.app/Contents/gradle/m2repository/com/facebook/react
-    cp -r ~/.m2/repository/com/facebook/react/gradleplugin /Applications/Android\ Studio.app/Contents/gradle/m2repository/com/facebook/react/
-
-Now, open Android Studio, click _Import Non-Android Studio project_ and find your `react-native` repo.
-
-In the configurations dropdown, _app_ should be selected. Click _Run_.
-
-## Installing the React Native .aar in your local Maven repo
-
-In some cases, for example when working on the `react-native-cli` it's useful to publish a snapshot version of React Native into your local Maven repo. This way, Gradle can pick it up when building projects that have a Maven dependency on React Native.
-
-Run:
-
-```bash
-cd react-native-android
-./gradlew :ReactAndroid:installArchives
-```
-
-## Troubleshooting
-
-Gradle build fails in `ndk-build`. See the section about `local.properties` file above.
-
-Gradle build fails "Could not find any version that matches com.facebook.react:gradleplugin:...". See the section about the React Native Gradle plugin above.
-
-Packager throws an error saying a module is not found. Try running `npm install` in the root of the repo.
+See [docs on the website](https://facebook.github.io/react-native/docs/android-building-from-source.html).
diff --git a/docs/AndroidBuildingFromSource.md b/docs/AndroidBuildingFromSource.md
index 6a7cd37f1b0a..5c31274640f7 100644
--- a/docs/AndroidBuildingFromSource.md
+++ b/docs/AndroidBuildingFromSource.md
@@ -76,7 +76,6 @@ project(':ReactAndroid').projectDir = new File(
 ...
 ```
 
-
 Modify your `android/app/build.gradle` to use the `:ReactAndroid` project instead of the pre-compiled library, e.g. - replace `compile 'com.facebook.react:react-native:0.16.+'` with `compile project(':ReactAndroid')`:
 
 ```gradle
@@ -92,7 +91,6 @@ dependencies {
 ...
 ```
 
-
 #### 4. Making 3rd-party modules use your fork
 
 If you use 3rd-party React Native modules, you need to override their dependencies so that they don't bundle the pre-compiled library. Otherwise you'll get an error while compiling - `Error: more than one library with package name 'com.facebook.react'`.
@@ -105,6 +103,11 @@ compile(project(':react-native-custom-module')) {
 }
 ```
 
+## Building from Android Studio
+
+From the Welcome screen of Android Studio choose "Import project" and select the `android` folder of your app.
+
+You should be able to use the _Run_ button to run your app on a device. Android Studio won't start the packager automatically, you'll need to start it by running `npm start` on the command line.
 
 ## Additional notes
 
@@ -117,3 +120,7 @@ gradle.projectsLoaded {
     }
 }
 ```
+
+## Troubleshooting
+
+Gradle build fails in `ndk-build`. See the section about `local.properties` file above.

From 8956915ab16c0a57383487b14404878939625e0e Mon Sep 17 00:00:00 2001
From: Al Sutton <alsutton@fb.com>
Date: Thu, 18 Feb 2016 09:03:52 -0800
Subject: [PATCH 1218/1411] Move appcompat-orig alongside fork

Reviewed By: bestander

Differential Revision: D2949054

fb-gh-sync-id: d1efc1814d82fdd3c93d08bae469ec815e51c028
shipit-source-id: d1efc1814d82fdd3c93d08bae469ec815e51c028
---
 .../android/support/v7/appcompat-orig}/res-unpacker.py        | 0
 .../src/main/java/com/facebook/react/views/switchview/BUCK    | 4 ++--
 .../src/main/java/com/facebook/react/views/toolbar/BUCK       | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)
 rename ReactAndroid/src/main/{third-party/android-support-for-standalone-apps/v7/appcompat => android_res/android/support/v7/appcompat-orig}/res-unpacker.py (100%)

diff --git a/ReactAndroid/src/main/third-party/android-support-for-standalone-apps/v7/appcompat/res-unpacker.py b/ReactAndroid/src/main/android_res/android/support/v7/appcompat-orig/res-unpacker.py
similarity index 100%
rename from ReactAndroid/src/main/third-party/android-support-for-standalone-apps/v7/appcompat/res-unpacker.py
rename to ReactAndroid/src/main/android_res/android/support/v7/appcompat-orig/res-unpacker.py
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK
index 896c30983591..6972d308b2e9 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK
@@ -8,8 +8,8 @@ android_library(
     react_native_target('java/com/facebook/csslayout:csslayout'),
     react_native_target('java/com/facebook/react/uimanager:uimanager'),
     react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
-    react_native_dep('third-party/android-support-for-standalone-apps/v7/appcompat:appcompat'),
-    react_native_dep('third-party/android-support-for-standalone-apps/v7/appcompat:res-for-react-native'),
+    react_native_dep('android_res/android/support/v7/appcompat-orig:res-for-react-native'),
+    react_native_dep('third-party/android/support/v7/appcompat-orig:appcompat'),
     react_native_dep('third-party/java/jsr-305:jsr-305'),
   ],
   visibility = [
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK
index dbb6d2b26bb8..df52d70d0753 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK
@@ -9,11 +9,11 @@ android_library(
     react_native_target('java/com/facebook/react/common:common'),
     react_native_target('java/com/facebook/react/uimanager:uimanager'),
     react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
+    react_native_dep('android_res/android/support/v7/appcompat-orig:res-for-react-native'),
     react_native_dep('libraries/fresco/fresco-react-native:fresco-react-native'),
     react_native_dep('libraries/fresco/fresco-react-native:fresco-drawee'),
     react_native_dep('libraries/fresco/fresco-react-native:imagepipeline'),
-    react_native_dep('third-party/android-support-for-standalone-apps/v7/appcompat:appcompat'),
-    react_native_dep('third-party/android-support-for-standalone-apps/v7/appcompat:res-for-react-native'),
+    react_native_dep('third-party/android/support/v7/appcompat-orig:appcompat'),
     react_native_dep('third-party/android/support/v4:lib-support-v4'),
     react_native_dep('third-party/java/jsr-305:jsr-305'),
 ],

From e09b4a54b9c883c047addca1c8368c0102051cad Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Thu, 18 Feb 2016 10:53:41 -0800
Subject: [PATCH 1219/1411] Tweak PR and issue templates

Reviewed By: mkonicek

Differential Revision:D2949403
Ninja: oss-only

fb-gh-sync-id: 8e8f68140c833ff8d7c600647dabb52b5ce4d527
shipit-source-id: 8e8f68140c833ff8d7c600647dabb52b5ce4d527
---
 ISSUE_TEMPLATE.md        | 27 +++++++++++++++++++++------
 PULL_REQUEST_TEMPLATE.md |  4 +++-
 2 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md
index a1a214ae3e8b..67b73226a83b 100644
--- a/ISSUE_TEMPLATE.md
+++ b/ISSUE_TEMPLATE.md
@@ -1,16 +1,31 @@
+Hey there and thank you for using React Native!
+
 React Native, as you've probably heard, is getting really popular and truth is we're getting a bit overwhelmed by the activity surrounding it. There are just too many issues for us to manage properly.
 
-Here are good ways to get help:
+Please read the following tips before filing an issue:
+
+Have a question or not sure you've found a bug?
+-----------------------------------------------------------------
+Discuss on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native) with the tag `react-native`. StackOverflow is amazing for Q&A and it is likely the community will see and answer your question there.
+
+Make sure you **include a short code snippet to demonstrate the problem**.
+
+Is this something you can debug and fix?
+-------------------------------------------------------
 
-- If you **don't know how to do something** or **not sure you've found a bug**, ask on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native) with the tag `react-native`. StackOverflow is amazing for Q&A and it is likely the community will see and answer your question there.
+**Send a pull request**! Bug fixes and documentation fixes are very welcome.
 
-- If this is a **feature request**, please report it on [Product Pains](https://productpains.com/product/react-native/). It has a ranking feature that lets us focus on the most important issues the community is experiencing.
+Have an idea for a feature?
+-----------------------------------
+Post the feature request on [Product Pains](https://productpains.com/product/react-native/). It has a voting system that lets us focus on the most important issues the community is experiencing. The higher number of votes the more likely it is a feature will get implemented. You could always implement it yourself, too.
 
-- Is this something you can debug and fix quickly? **Send a pull request!**
+None of the above, want to create a GitHub issue
+------------------------------------------------------------------
 
-If you want to file a GitHub issue, make sure it is actionable so someone can help:
+Make sure to add **all the information needed to understand the issue** so that someone can help. If the info is missing we'll add the 'Needs more information' label and close the issue until there is enough information.
 
+- If this is a bug, provide a **minimal code snippet** that reproduces it
 - Provide **screenshots** where appropriate
 - What's the **version** of React Native you're using?
 - Does this occur on iOS, Android or both?
-- The operating system: Mac, Linux or Windows
+- Are you using Mac, Linux or Windows?
diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md
index 875b1d6edefb..3b3d851da6a8 100644
--- a/PULL_REQUEST_TEMPLATE.md
+++ b/PULL_REQUEST_TEMPLATE.md
@@ -1,4 +1,6 @@
-Explain the motivation for making this change. What existing problem does the pull request solve?
+Hey there and thanks for submitting a pull request! Please have a look at the following checklist so that others have enough information to review your pull request:
+
+Explain the **motivation** for making this change. What existing problem does the pull request solve?
 
 Example: When saying "Add a function to do X", explain why it is necessary to have a way to do X.
 

From 80e458110bd4a952cab9d925a87f21315a8c334b Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Thu, 18 Feb 2016 11:54:12 -0800
Subject: [PATCH 1220/1411] Issue bot: add reopen command

Reviewed By: mkonicek

Differential Revision:D2950378
Ninja: oss

fb-gh-sync-id: bf9e6d5a3889ca1c1e95bf4b8aed63afd3030da6
shipit-source-id: bf9e6d5a3889ca1c1e95bf4b8aed63afd3030da6
---
 bots/IssueCommands.txt | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/bots/IssueCommands.txt b/bots/IssueCommands.txt
index 1dcd91c6a8c5..a132deeb70c2 100644
--- a/bots/IssueCommands.txt
+++ b/bots/IssueCommands.txt
@@ -12,3 +12,6 @@ close
 
 /label (.*)
 add-label {match0}
+
+/reopen
+reopen

From 0fdb1671e3b49aab921b6fef0f8a019fb1058cb5 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Thu, 18 Feb 2016 15:10:14 -0800
Subject: [PATCH 1221/1411] Tweak bot messages and issue template to make them
 a bit more friendly

Reviewed By: mkonicek

Differential Revision:D2951452
Ninja: oss

fb-gh-sync-id: a42ee8061e37d7b389fcce0a26a16411b43c1d05
shipit-source-id: a42ee8061e37d7b389fcce0a26a16411b43c1d05
---
 ISSUE_TEMPLATE.md      | 14 +++++++-------
 bots/IssueCommands.txt | 11 ++++++++---
 2 files changed, 15 insertions(+), 10 deletions(-)

diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md
index 67b73226a83b..a552aab8fbb2 100644
--- a/ISSUE_TEMPLATE.md
+++ b/ISSUE_TEMPLATE.md
@@ -4,19 +4,19 @@ React Native, as you've probably heard, is getting really popular and truth is w
 
 Please read the following tips before filing an issue:
 
+Is this something you can debug and fix?
+-------------------------------------------------------
+
+Can you see anything in the logs? Can you debug why this happens? **Send a pull request**! Bug fixes and documentation fixes are very welcome.
+
 Have a question or not sure you've found a bug?
 -----------------------------------------------------------------
-Discuss on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native) with the tag `react-native`. StackOverflow is amazing for Q&A and it is likely the community will see and answer your question there.
+Please ask your question [StackOverflow](http://stackoverflow.com/questions/tagged/react-native) with the tag `react-native`. StackOverflow is amazing for Q&A and because of the reputation system it is likely the community will see and answer your question there.
 
 Make sure you **include a short code snippet to demonstrate the problem**.
 
-Is this something you can debug and fix?
--------------------------------------------------------
-
-**Send a pull request**! Bug fixes and documentation fixes are very welcome.
-
 Have an idea for a feature?
------------------------------------
+------------------------------------
 Post the feature request on [Product Pains](https://productpains.com/product/react-native/). It has a voting system that lets us focus on the most important issues the community is experiencing. The higher number of votes the more likely it is a feature will get implemented. You could always implement it yourself, too.
 
 None of the above, want to create a GitHub issue
diff --git a/bots/IssueCommands.txt b/bots/IssueCommands.txt
index a132deeb70c2..27f357058ee2 100644
--- a/bots/IssueCommands.txt
+++ b/bots/IssueCommands.txt
@@ -1,17 +1,22 @@
 /answered
-comment Closing this issue as the question has been answered. Please help us by first discussing on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native) before filing a bug. It's the best system for Q&A. Many people from the community hang out there and will be able to see and answer your question. This lets us use the GitHub bug tracker for bugs.
+comment Closing this issue as {author} says the question asked has been answered. Please help us by asking questions on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native). StackOverflow is amazing for Q&A and because of the reputation system it is likely the community will see and answer your question there. This also help us use the GitHub bug tracker for bugs only.
 close
 
 /duplicate (#[0-9]+)
-comment This issue is a duplicate of {match0}.
+comment {author} tells me this issue is a duplicate of {match0}. Let's discuss there, closing this one.
 close
 
 /expected
-comment This is expected behavior. Closing as we'd like to use the GitHub issue tracker for bugs. If you'd like to change how this feature works please post a feature request on [Product Pains](https://productpains.com/product/react-native/) and let's discuss there. If it gets upvoted enough it might get implemented by the community.
+comment The /expected comment above tells me this is expected behavior. Closing this as we'd like to use the GitHub issue tracker for bugs. If you'd like to change how this feature works please post a feature request on [Product Pains](https://productpains.com/product/react-native/) so that other people can vote on it.
 close
 
+/question
+comment Hey {issue_author} and thanks for posting this! {author} tells me this issue looks like a question that would be best asked on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native). StackOverflow is amazing for Q&A and because of the reputation system it is likely the community will see and answer your question there. This also help us use the GitHub bug tracker for bugs only. I'm posting this here because GitHub issues haven't been working very well for us and because StackOverflow is so much better. Thanks for reading! :)
+add-label For Stack Overflow
+
 /label (.*)
 add-label {match0}
 
 /reopen
+comment Okay, reopening this issue.
 reopen

From 7a87d380449d27a1d40d4e089fa96766478d4148 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Thu, 18 Feb 2016 15:59:41 -0800
Subject: [PATCH 1222/1411] Fix typos in bot messages

Reviewed By: mkonicek

Differential Revision:D2951913
Ninja: oss

fb-gh-sync-id: 0d2d43a39735e23ae456e10ee33276d70464e0ca
shipit-source-id: 0d2d43a39735e23ae456e10ee33276d70464e0ca
---
 ISSUE_TEMPLATE.md      | 2 +-
 bots/IssueCommands.txt | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md
index a552aab8fbb2..37d939a97571 100644
--- a/ISSUE_TEMPLATE.md
+++ b/ISSUE_TEMPLATE.md
@@ -11,7 +11,7 @@ Can you see anything in the logs? Can you debug why this happens? **Send a pull
 
 Have a question or not sure you've found a bug?
 -----------------------------------------------------------------
-Please ask your question [StackOverflow](http://stackoverflow.com/questions/tagged/react-native) with the tag `react-native`. StackOverflow is amazing for Q&A and because of the reputation system it is likely the community will see and answer your question there.
+Please ask your question [StackOverflow](http://stackoverflow.com/questions/tagged/react-native) with the tag `react-native`. StackOverflow is amazing for Q&A. Because of the reputation system it is likely the community will see and answer your question there.
 
 Make sure you **include a short code snippet to demonstrate the problem**.
 
diff --git a/bots/IssueCommands.txt b/bots/IssueCommands.txt
index 27f357058ee2..86be4159c6f1 100644
--- a/bots/IssueCommands.txt
+++ b/bots/IssueCommands.txt
@@ -1,5 +1,5 @@
 /answered
-comment Closing this issue as {author} says the question asked has been answered. Please help us by asking questions on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native). StackOverflow is amazing for Q&A and because of the reputation system it is likely the community will see and answer your question there. This also help us use the GitHub bug tracker for bugs only.
+comment Closing this issue as {author} says the question asked has been answered. Please help us by asking questions on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native). StackOverflow is amazing for Q&A. Because of the reputation system it is likely the community will see and answer your question there. This also helps us use the GitHub bug tracker for bugs only.
 close
 
 /duplicate (#[0-9]+)
@@ -11,7 +11,7 @@ comment The /expected comment above tells me this is expected behavior. Closing
 close
 
 /question
-comment Hey {issue_author} and thanks for posting this! {author} tells me this issue looks like a question that would be best asked on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native). StackOverflow is amazing for Q&A and because of the reputation system it is likely the community will see and answer your question there. This also help us use the GitHub bug tracker for bugs only. I'm posting this here because GitHub issues haven't been working very well for us and because StackOverflow is so much better. Thanks for reading! :)
+comment Hey {issue_author} and thanks for posting this! {author} tells me this issue looks like a question that would be best asked on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native). StackOverflow is amazing for Q&A. Because of the reputation system it is likely the community will see and answer your question there. This also helps us use the GitHub bug tracker for bugs only.
 add-label For Stack Overflow
 
 /label (.*)

From fa3a67e251fe235af511301f893b41df1444e808 Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Thu, 18 Feb 2016 18:02:21 -0800
Subject: [PATCH 1223/1411] Install node-haste2 and remove DependencyResolver

Summary: This installs the 2.0 version of node-haste, removes the DependencyResolver and fixes up all the tests.

Reviewed By: davidaurelio

Differential Revision: D2943416

fb-gh-sync-id: aa83d436a33f910d12ed4cc6e2ad8d5742c123a5
shipit-source-id: aa83d436a33f910d12ed4cc6e2ad8d5742c123a5
---
 npm-shrinkwrap.json                           |  258 +-
 package.json                                  |    1 +
 .../AssetServer/__tests__/AssetServer-test.js |    8 +-
 .../react-packager/src/AssetServer/index.js   |    2 +-
 packager/react-packager/src/Bundler/index.js  |    2 +-
 .../src/DependencyResolver/AssetModule.js     |   47 -
 .../AssetModule_DEPRECATED.js                 |   45 -
 .../Cache/__mocks__/index.js                  |   20 -
 .../Cache/__tests__/Cache-test.js             |  335 --
 .../src/DependencyResolver/Cache/index.js     |  190 -
 .../Cache/lib/getCacheFilePath.js             |   20 -
 .../Cache/lib/loadCacheSync.js                |   34 -
 .../DependencyGraph/DependencyGraphHelpers.js |   45 -
 .../DependencyGraph/DeprecatedAssetMap.js     |  119 -
 .../DependencyGraph/HasteMap.js               |  142 -
 .../DependencyGraph/ResolutionRequest.js      |  446 --
 .../DependencyGraph/ResolutionResponse.js     |   87 -
 .../__tests__/DependencyGraph-test.js         | 4285 -----------------
 .../DependencyGraph/docblock.js               |   83 -
 .../DependencyGraph/index.js                  |  287 --
 .../FileWatcher/__mocks__/sane.js             |   14 -
 .../FileWatcher/__tests__/FileWatcher-test.js |   89 -
 .../DependencyResolver/FileWatcher/index.js   |  128 -
 .../src/DependencyResolver/Module.js          |  226 -
 .../src/DependencyResolver/ModuleCache.js     |  104 -
 .../src/DependencyResolver/Package.js         |  100 -
 .../src/DependencyResolver/Polyfill.js        |   38 -
 .../__tests__/Module-test.js                  |  335 --
 .../DependencyResolver/__tests__/fastfs-data  |   39 -
 .../__tests__/fastfs-integrated-test.js       |   87 -
 .../src/DependencyResolver/crawlers/index.js  |   26 -
 .../src/DependencyResolver/crawlers/node.js   |   61 -
 .../DependencyResolver/crawlers/watchman.js   |   66 -
 .../src/DependencyResolver/fastfs.js          |  360 --
 .../__tests__/getAssetDataFromName-test.js    |  119 -
 .../__tests__/getPlatformExtension-test.js    |   25 -
 .../DependencyResolver/lib/extractRequires.js |   47 -
 .../lib/getAssetDataFromName.js               |   55 -
 .../lib/getPlatformExtension.js               |   28 -
 .../DependencyResolver/lib/replacePatterns.js |   14 -
 .../__tests__/Transformer-test.js             |    6 +-
 .../src/Resolver/__tests__/Resolver-test.js   |   28 +-
 packager/react-packager/src/Resolver/index.js |    6 +-
 .../src/Server/__tests__/Server-test.js       |    4 +-
 packager/react-packager/src/Server/index.js   |    4 +-
 .../__tests__/SocketInterface-test.js         |    3 +-
 .../__tests__/SocketServer-test.js            |    3 +-
 packager/react-packager/src/__mocks__/fs.js   |  179 +-
 48 files changed, 206 insertions(+), 8444 deletions(-)
 delete mode 100644 packager/react-packager/src/DependencyResolver/AssetModule.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/AssetModule_DEPRECATED.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/Cache/__mocks__/index.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/Cache/__tests__/Cache-test.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/Cache/index.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/Cache/lib/getCacheFilePath.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/Cache/lib/loadCacheSync.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/DependencyGraph/DependencyGraphHelpers.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/DependencyGraph/DeprecatedAssetMap.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/DependencyGraph/HasteMap.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/DependencyGraph/docblock.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/FileWatcher/__mocks__/sane.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/FileWatcher/__tests__/FileWatcher-test.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/FileWatcher/index.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/Module.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/ModuleCache.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/Package.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/Polyfill.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/__tests__/fastfs-data
 delete mode 100644 packager/react-packager/src/DependencyResolver/__tests__/fastfs-integrated-test.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/crawlers/index.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/crawlers/node.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/crawlers/watchman.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/fastfs.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/lib/__tests__/getAssetDataFromName-test.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/lib/__tests__/getPlatformExtension-test.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/lib/extractRequires.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/lib/getAssetDataFromName.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/lib/getPlatformExtension.js
 delete mode 100644 packager/react-packager/src/DependencyResolver/lib/replacePatterns.js

diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index 4ebb85ec3492..a7200713a435 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -122,16 +122,16 @@
           "from": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz"
         },
-        "ast-types": {
-          "version": "0.8.12",
-          "from": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz",
-          "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz"
-        },
         "babylon": {
           "version": "5.8.29",
           "from": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz",
           "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz"
         },
+        "ast-types": {
+          "version": "0.8.12",
+          "from": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz",
+          "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz"
+        },
         "globals": {
           "version": "6.4.1",
           "from": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz",
@@ -248,15 +248,15 @@
           "from": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz",
           "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
         },
-        "regenerator": {
-          "version": "0.8.40",
-          "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
-          "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
-        },
         "source-map": {
           "version": "0.5.3",
           "from": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz"
+        },
+        "regenerator": {
+          "version": "0.8.40",
+          "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
+          "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
         }
       }
     },
@@ -1900,16 +1900,16 @@
           "from": "abbrev@1",
           "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz"
         },
-        "ansi": {
-          "version": "0.3.0",
-          "from": "ansi@~0.3.0",
-          "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.0.tgz"
-        },
         "ansi-regex": {
           "version": "2.0.0",
           "from": "ansi-regex@^2.0.0",
           "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
         },
+        "ansi": {
+          "version": "0.3.0",
+          "from": "ansi@~0.3.0",
+          "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.0.tgz"
+        },
         "ansi-styles": {
           "version": "2.1.0",
           "from": "ansi-styles@^2.1.0",
@@ -1920,15 +1920,20 @@
           "from": "are-we-there-yet@~1.0.0",
           "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.4.tgz"
         },
+        "asn1": {
+          "version": "0.1.11",
+          "from": "asn1@0.1.11",
+          "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
+        },
         "assert-plus": {
           "version": "0.1.5",
           "from": "assert-plus@^0.1.5",
           "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
         },
-        "asn1": {
-          "version": "0.1.11",
-          "from": "asn1@0.1.11",
-          "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
+        "aws-sign2": {
+          "version": "0.6.0",
+          "from": "aws-sign2@~0.6.0",
+          "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
         },
         "async": {
           "version": "1.5.0",
@@ -1940,46 +1945,41 @@
           "from": "balanced-match@>=0.2.0 <0.3.0",
           "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.1.tgz"
         },
-        "aws-sign2": {
-          "version": "0.6.0",
-          "from": "aws-sign2@~0.6.0",
-          "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
+        "block-stream": {
+          "version": "0.0.8",
+          "from": "block-stream@*",
+          "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.8.tgz"
         },
         "boom": {
           "version": "2.10.1",
           "from": "boom@^2.8.x",
           "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz"
         },
-        "block-stream": {
-          "version": "0.0.8",
-          "from": "block-stream@*",
-          "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.8.tgz"
-        },
         "brace-expansion": {
           "version": "1.1.1",
           "from": "brace-expansion@>=1.0.0 <2.0.0",
           "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz"
         },
-        "caseless": {
-          "version": "0.11.0",
-          "from": "caseless@~0.11.0",
-          "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
-        },
         "chalk": {
           "version": "1.1.1",
           "from": "chalk@^1.1.1",
           "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz"
         },
-        "commander": {
-          "version": "2.9.0",
-          "from": "commander@^2.8.1",
-          "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz"
+        "caseless": {
+          "version": "0.11.0",
+          "from": "caseless@~0.11.0",
+          "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
         },
         "combined-stream": {
           "version": "1.0.5",
           "from": "combined-stream@~1.0.5",
           "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz"
         },
+        "commander": {
+          "version": "2.9.0",
+          "from": "commander@^2.8.1",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz"
+        },
         "concat-map": {
           "version": "0.0.1",
           "from": "concat-map@0.0.1",
@@ -2065,26 +2065,26 @@
           "from": "graceful-fs@4.1",
           "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.2.tgz"
         },
-        "graceful-readlink": {
-          "version": "1.0.1",
-          "from": "graceful-readlink@>= 1.0.0",
-          "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
-        },
         "har-validator": {
           "version": "2.0.2",
           "from": "har-validator@~2.0.2",
           "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.2.tgz"
         },
-        "has-ansi": {
-          "version": "2.0.0",
-          "from": "has-ansi@^2.0.0",
-          "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
+        "graceful-readlink": {
+          "version": "1.0.1",
+          "from": "graceful-readlink@>= 1.0.0",
+          "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
         },
         "has-unicode": {
           "version": "1.0.1",
           "from": "has-unicode@^1.0.0",
           "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-1.0.1.tgz"
         },
+        "has-ansi": {
+          "version": "2.0.0",
+          "from": "has-ansi@^2.0.0",
+          "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
+        },
         "hawk": {
           "version": "3.1.0",
           "from": "hawk@~3.1.0",
@@ -2100,6 +2100,11 @@
           "from": "http-signature@~0.11.0",
           "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.11.0.tgz"
         },
+        "inherits": {
+          "version": "2.0.1",
+          "from": "inherits@*",
+          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
+        },
         "ini": {
           "version": "1.3.4",
           "from": "ini@~1.3.0",
@@ -2120,36 +2125,31 @@
           "from": "isarray@0.0.1",
           "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
         },
-        "inherits": {
-          "version": "2.0.1",
-          "from": "inherits@*",
-          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-        },
-        "jsonpointer": {
-          "version": "2.0.0",
-          "from": "jsonpointer@2.0.0",
-          "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
+        "isstream": {
+          "version": "0.1.2",
+          "from": "isstream@~0.1.2",
+          "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
         },
         "json-stringify-safe": {
           "version": "5.0.1",
           "from": "json-stringify-safe@~5.0.1",
           "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
         },
-        "isstream": {
-          "version": "0.1.2",
-          "from": "isstream@~0.1.2",
-          "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
-        },
-        "lodash._basetostring": {
-          "version": "3.0.1",
-          "from": "lodash._basetostring@^3.0.0",
-          "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz"
+        "jsonpointer": {
+          "version": "2.0.0",
+          "from": "jsonpointer@2.0.0",
+          "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
         },
         "lodash._createpadding": {
           "version": "3.6.1",
           "from": "lodash._createpadding@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash._createpadding/-/lodash._createpadding-3.6.1.tgz"
         },
+        "lodash._basetostring": {
+          "version": "3.0.1",
+          "from": "lodash._basetostring@^3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz"
+        },
         "lodash.pad": {
           "version": "3.1.1",
           "from": "lodash.pad@^3.0.0",
@@ -2270,16 +2270,16 @@
           "from": "strip-json-comments@0.1.x",
           "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
         },
-        "supports-color": {
-          "version": "2.0.0",
-          "from": "supports-color@^2.0.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
-        },
         "tar": {
           "version": "2.2.1",
           "from": "tar@~2.2.0",
           "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz"
         },
+        "supports-color": {
+          "version": "2.0.0",
+          "from": "supports-color@^2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
+        },
         "tough-cookie": {
           "version": "2.2.0",
           "from": "tough-cookie@~2.2.0",
@@ -2305,6 +2305,28 @@
           "from": "xtend@^4.0.0",
           "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz"
         },
+        "fstream-ignore": {
+          "version": "1.0.3",
+          "from": "fstream-ignore@~1.0.3",
+          "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.3.tgz",
+          "dependencies": {
+            "minimatch": {
+              "version": "3.0.0",
+              "from": "minimatch@>=3.0.0 <4.0.0"
+            }
+          }
+        },
+        "inflight": {
+          "version": "1.0.4",
+          "from": "inflight@>=1.0.4 <2.0.0",
+          "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz",
+          "dependencies": {
+            "once": {
+              "version": "1.3.2",
+              "from": "once@>=1.3.0 <2.0.0"
+            }
+          }
+        },
         "rc": {
           "version": "1.1.2",
           "from": "rc@~1.1.0",
@@ -2339,28 +2361,6 @@
             }
           }
         },
-        "inflight": {
-          "version": "1.0.4",
-          "from": "inflight@>=1.0.4 <2.0.0",
-          "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz",
-          "dependencies": {
-            "once": {
-              "version": "1.3.2",
-              "from": "once@>=1.3.0 <2.0.0"
-            }
-          }
-        },
-        "fstream-ignore": {
-          "version": "1.0.3",
-          "from": "fstream-ignore@~1.0.3",
-          "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.3.tgz",
-          "dependencies": {
-            "minimatch": {
-              "version": "3.0.0",
-              "from": "minimatch@>=3.0.0 <4.0.0"
-            }
-          }
-        },
         "bl": {
           "version": "1.0.0",
           "from": "bl@~1.0.0",
@@ -3928,6 +3928,82 @@
         }
       }
     },
+    "node-haste": {
+      "version": "2.0.0",
+      "from": "node-haste@*",
+      "dependencies": {
+        "graceful-fs": {
+          "version": "4.1.3",
+          "from": "graceful-fs@>=4.1.3 <5.0.0",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.3.tgz"
+        },
+        "sane": {
+          "version": "1.3.1",
+          "from": "sane@>=1.3.1 <2.0.0",
+          "resolved": "https://registry.npmjs.org/sane/-/sane-1.3.1.tgz",
+          "dependencies": {
+            "exec-sh": {
+              "version": "0.2.0",
+              "from": "exec-sh@>=0.2.0 <0.3.0",
+              "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.0.tgz",
+              "dependencies": {
+                "merge": {
+                  "version": "1.2.0",
+                  "from": "merge@>=1.1.3 <2.0.0",
+                  "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz"
+                }
+              }
+            },
+            "fb-watchman": {
+              "version": "1.9.0",
+              "from": "fb-watchman@>=1.8.0 <2.0.0",
+              "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.9.0.tgz"
+            },
+            "minimatch": {
+              "version": "0.2.14",
+              "from": "minimatch@>=0.2.14 <0.3.0",
+              "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz",
+              "dependencies": {
+                "lru-cache": {
+                  "version": "2.7.3",
+                  "from": "lru-cache@>=2.0.0 <3.0.0",
+                  "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz"
+                },
+                "sigmund": {
+                  "version": "1.0.1",
+                  "from": "sigmund@>=1.0.0 <1.1.0",
+                  "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz"
+                }
+              }
+            },
+            "walker": {
+              "version": "1.0.7",
+              "from": "walker@>=1.0.5 <1.1.0",
+              "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz",
+              "dependencies": {
+                "makeerror": {
+                  "version": "1.0.11",
+                  "from": "makeerror@>=1.0.0 <1.1.0",
+                  "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz",
+                  "dependencies": {
+                    "tmpl": {
+                      "version": "1.0.4",
+                      "from": "tmpl@>=1.0.0 <1.1.0",
+                      "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz"
+                    }
+                  }
+                }
+              }
+            },
+            "watch": {
+              "version": "0.10.0",
+              "from": "watch@>=0.10.0 <0.11.0",
+              "resolved": "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz"
+            }
+          }
+        }
+      }
+    },
     "normalize-package-data": {
       "version": "2.3.5",
       "from": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.5.tgz",
diff --git a/package.json b/package.json
index 852ae1cb3d83..2ed9714e13ff 100644
--- a/package.json
+++ b/package.json
@@ -148,6 +148,7 @@
     "mkdirp": "^0.5.1",
     "module-deps": "^3.9.1",
     "node-fetch": "^1.3.3",
+    "node-haste": "^2.0.0",
     "opn": "^3.0.2",
     "optimist": "^0.6.1",
     "progress": "^1.1.8",
diff --git a/packager/react-packager/src/AssetServer/__tests__/AssetServer-test.js b/packager/react-packager/src/AssetServer/__tests__/AssetServer-test.js
index 1cb90b334bcc..0172f39b4e98 100644
--- a/packager/react-packager/src/AssetServer/__tests__/AssetServer-test.js
+++ b/packager/react-packager/src/AssetServer/__tests__/AssetServer-test.js
@@ -1,8 +1,7 @@
 'use strict';
 
 jest
-  .dontMock('../../DependencyResolver/lib/getPlatformExtension')
-  .dontMock('../../DependencyResolver/lib/getAssetDataFromName')
+  .dontMock('node-haste/lib/lib/getPlatformExtension')
   .dontMock('../');
 
 jest
@@ -16,6 +15,11 @@ var crypto = require('crypto');
 var fs = require('fs');
 
 describe('AssetServer', () => {
+  beforeEach(() => {
+    const NodeHaste = require('node-haste');
+    NodeHaste.getAssetDataFromName = require.requireActual('node-haste/lib/lib/getAssetDataFromName');
+  });
+
   describe('assetServer.get', () => {
     pit('should work for the simple case', () => {
       const server = new AssetServer({
diff --git a/packager/react-packager/src/AssetServer/index.js b/packager/react-packager/src/AssetServer/index.js
index bb411ce6ff4f..71356acf38f6 100644
--- a/packager/react-packager/src/AssetServer/index.js
+++ b/packager/react-packager/src/AssetServer/index.js
@@ -13,7 +13,7 @@ const Promise = require('promise');
 const crypto = require('crypto');
 const declareOpts = require('../lib/declareOpts');
 const fs = require('fs');
-const getAssetDataFromName = require('../DependencyResolver/lib/getAssetDataFromName');
+const getAssetDataFromName = require('node-haste').getAssetDataFromName;
 const path = require('path');
 
 const stat = Promise.denodeify(fs.stat);
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index 6285fcc286c4..22696cf59088 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -13,7 +13,7 @@ const fs = require('fs');
 const path = require('path');
 const Promise = require('promise');
 const ProgressBar = require('progress');
-const Cache = require('../DependencyResolver/Cache');
+const Cache = require('node-haste').Cache;
 const Transformer = require('../JSTransformer');
 const Resolver = require('../Resolver');
 const Bundle = require('./Bundle');
diff --git a/packager/react-packager/src/DependencyResolver/AssetModule.js b/packager/react-packager/src/DependencyResolver/AssetModule.js
deleted file mode 100644
index c2f51fbb2b44..000000000000
--- a/packager/react-packager/src/DependencyResolver/AssetModule.js
+++ /dev/null
@@ -1,47 +0,0 @@
-'use strict';
-
-const Module = require('./Module');
-const Promise = require('promise');
-const getAssetDataFromName = require('./lib/getAssetDataFromName');
-
-class AssetModule extends Module {
-  constructor(...args) {
-    super(...args);
-    const { resolution, name, type } = getAssetDataFromName(this.path);
-    this.resolution = resolution;
-    this._name = name;
-    this._type = type;
-  }
-
-  isHaste() {
-    return Promise.resolve(false);
-  }
-
-  getDependencies() {
-    return Promise.resolve([]);
-  }
-
-  read() {
-    return Promise.resolve({});
-  }
-
-  getName() {
-    return super.getName().then(
-      id => id.replace(/\/[^\/]+$/, `/${this._name}.${this._type}`)
-    );
-  }
-
-  hash() {
-    return `AssetModule : ${this.path}`;
-  }
-
-  isJSON() {
-    return false;
-  }
-
-  isAsset() {
-    return true;
-  }
-}
-
-module.exports = AssetModule;
diff --git a/packager/react-packager/src/DependencyResolver/AssetModule_DEPRECATED.js b/packager/react-packager/src/DependencyResolver/AssetModule_DEPRECATED.js
deleted file mode 100644
index 3c4659462aa8..000000000000
--- a/packager/react-packager/src/DependencyResolver/AssetModule_DEPRECATED.js
+++ /dev/null
@@ -1,45 +0,0 @@
-'use strict';
-
-const Module = require('./Module');
-const Promise = require('promise');
-const getAssetDataFromName = require('./lib/getAssetDataFromName');
-
-class AssetModule_DEPRECATED extends Module {
-  constructor(...args) {
-    super(...args);
-    const {resolution, name} = getAssetDataFromName(this.path);
-    this.resolution = resolution;
-    this.name = name;
-  }
-
-  isHaste() {
-    return Promise.resolve(false);
-  }
-
-  getName() {
-    return Promise.resolve(`image!${this.name}`);
-  }
-
-  getDependencies() {
-    return Promise.resolve([]);
-  }
-
-  hash() {
-    return `AssetModule_DEPRECATED : ${this.path}`;
-  }
-
-  isJSON() {
-    return false;
-  }
-
-  isAsset_DEPRECATED() {
-    return true;
-  }
-
-  resolution() {
-    return getAssetDataFromName(this.path).resolution;
-  }
-
-}
-
-module.exports = AssetModule_DEPRECATED;
diff --git a/packager/react-packager/src/DependencyResolver/Cache/__mocks__/index.js b/packager/react-packager/src/DependencyResolver/Cache/__mocks__/index.js
deleted file mode 100644
index 6f7632f66c69..000000000000
--- a/packager/react-packager/src/DependencyResolver/Cache/__mocks__/index.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-class Cache {
-  get(filepath, field, cb) {
-    return cb(filepath);
-  }
-
-  invalidate(filepath) { }
-  end() { }
-}
-
-module.exports = Cache;
diff --git a/packager/react-packager/src/DependencyResolver/Cache/__tests__/Cache-test.js b/packager/react-packager/src/DependencyResolver/Cache/__tests__/Cache-test.js
deleted file mode 100644
index 2de2318e454c..000000000000
--- a/packager/react-packager/src/DependencyResolver/Cache/__tests__/Cache-test.js
+++ /dev/null
@@ -1,335 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-jest
-  .dontMock('absolute-path')
-  .dontMock('../')
-  .dontMock('../lib/loadCacheSync')
-  .dontMock('../lib/getCacheFilePath');
-
-jest
-  .mock('fs')
-  .setMock('os', {
-    tmpDir() { return 'tmpDir'; },
-  });
-
-var Promise = require('promise');
-var fs = require('graceful-fs');
-
-var Cache = require('../');
-
-describe('Cache', () => {
-  describe('getting/setting', () => {
-    pit('calls loader callback for uncached file', () => {
-      fs.stat.mockImpl((file, callback) => {
-        callback(null, {
-          mtime: {
-            getTime: () => {},
-          },
-        });
-      });
-
-      var cache = new Cache({
-        cacheKey: 'cache',
-      });
-      var loaderCb = jest.genMockFn().mockImpl(() => Promise.resolve());
-
-      return cache
-        .get('/rootDir/someFile', 'field', loaderCb)
-        .then($ =>
-          expect(loaderCb).toBeCalledWith('/rootDir/someFile')
-        );
-    });
-
-    pit('supports storing multiple fields', () => {
-      fs.stat.mockImpl((file, callback) => {
-        callback(null, {
-          mtime: {
-            getTime: () => {},
-          },
-        });
-      });
-
-      var cache = new Cache({
-        cacheKey: 'cache',
-      });
-      var index = 0;
-      var loaderCb = jest.genMockFn().mockImpl(() =>
-        Promise.resolve(index++)
-      );
-
-      return cache
-        .get('/rootDir/someFile', 'field1', loaderCb)
-        .then(value => {
-          expect(value).toBe(0);
-          return cache
-            .get('/rootDir/someFile', 'field2', loaderCb)
-            .then(value2 => expect(value2).toBe(1));
-        });
-    });
-
-    pit('gets the value from the loader callback', () => {
-      fs.stat.mockImpl((file, callback) =>
-        callback(null, {
-          mtime: {
-            getTime: () => {},
-          },
-        })
-      );
-
-      var cache = new Cache({
-        cacheKey: 'cache',
-      });
-      var loaderCb = jest.genMockFn().mockImpl(() =>
-        Promise.resolve('lol')
-      );
-
-      return cache
-        .get('/rootDir/someFile', 'field', loaderCb)
-        .then(value => expect(value).toBe('lol'));
-    });
-
-    pit('caches the value after the first call', () => {
-      fs.stat.mockImpl((file, callback) => {
-        callback(null, {
-          mtime: {
-            getTime: () => {},
-          },
-        });
-      });
-
-      var cache = new Cache({
-        cacheKey: 'cache',
-      });
-      var loaderCb = jest.genMockFn().mockImpl(() =>
-        Promise.resolve('lol')
-      );
-
-      return cache
-        .get('/rootDir/someFile', 'field', loaderCb)
-        .then(() => {
-          var shouldNotBeCalled = jest.genMockFn();
-          return cache.get('/rootDir/someFile', 'field', shouldNotBeCalled)
-            .then(value => {
-              expect(shouldNotBeCalled).not.toBeCalled();
-              expect(value).toBe('lol');
-            });
-        });
-    });
-
-    pit('clears old field when getting new field and mtime changed', () => {
-      var mtime = 0;
-      fs.stat.mockImpl((file, callback) => {
-        callback(null, {
-          mtime: {
-            getTime: () => mtime++,
-          },
-        });
-      });
-
-      var cache = new Cache({
-        cacheKey: 'cache',
-      });
-      var loaderCb = jest.genMockFn().mockImpl(() =>
-        Promise.resolve('lol' + mtime)
-      );
-
-      return cache
-        .get('/rootDir/someFile', 'field1', loaderCb)
-        .then(value => cache
-          .get('/rootDir/someFile', 'field2', loaderCb)
-          .then(value2 => cache
-            .get('/rootDir/someFile', 'field1', loaderCb)
-            .then(value3 => expect(value3).toBe('lol2'))
-          )
-        );
-    });
-  });
-
-  describe('loading cache from disk', () => {
-    var fileStats;
-
-    beforeEach(() => {
-      fileStats = {
-        '/rootDir/someFile': {
-          mtime: {
-            getTime: () => 22,
-          },
-        },
-        '/rootDir/foo': {
-          mtime: {
-            getTime: () => 11,
-          },
-        },
-      };
-
-      fs.existsSync.mockImpl(() => true);
-
-      fs.statSync.mockImpl(filePath => fileStats[filePath]);
-
-      fs.readFileSync.mockImpl(() => JSON.stringify({
-        '/rootDir/someFile': {
-          metadata: {mtime: 22},
-          data: {field: 'oh hai'},
-        },
-        '/rootDir/foo': {
-          metadata: {mtime: 11},
-          data: {field: 'lol wat'},
-        },
-      }));
-    });
-
-    pit('should load cache from disk', () => {
-      var cache = new Cache({
-        cacheKey: 'cache',
-      });
-      var loaderCb = jest.genMockFn();
-
-      return cache
-        .get('/rootDir/someFile', 'field', loaderCb)
-        .then(value => {
-          expect(loaderCb).not.toBeCalled();
-          expect(value).toBe('oh hai');
-
-          return cache
-            .get('/rootDir/foo', 'field', loaderCb)
-            .then(val => {
-              expect(loaderCb).not.toBeCalled();
-              expect(val).toBe('lol wat');
-            });
-        });
-    });
-
-    pit('should not load outdated cache', () => {
-      fs.stat.mockImpl((file, callback) =>
-        callback(null, {
-          mtime: {
-            getTime: () => {},
-          },
-        })
-      );
-
-      fileStats['/rootDir/foo'].mtime.getTime = () => 123;
-
-      var cache = new Cache({
-        cacheKey: 'cache',
-      });
-      var loaderCb = jest.genMockFn().mockImpl(() =>
-        Promise.resolve('new value')
-      );
-
-      return cache
-        .get('/rootDir/someFile', 'field', loaderCb)
-        .then(value => {
-          expect(loaderCb).not.toBeCalled();
-          expect(value).toBe('oh hai');
-
-          return cache
-            .get('/rootDir/foo', 'field', loaderCb)
-            .then(val => {
-              expect(loaderCb).toBeCalled();
-              expect(val).toBe('new value');
-            });
-        });
-    });
-  });
-
-  describe('writing cache to disk', () => {
-    it('should write cache to disk', () => {
-      var index = 0;
-      var mtimes = [10, 20, 30];
-
-      fs.stat.mockImpl((file, callback) =>
-        callback(null, {
-          mtime: {
-            getTime: () => mtimes[index++],
-          },
-        })
-      );
-
-      var cache = new Cache({
-        cacheKey: 'cache',
-      });
-
-      cache.get('/rootDir/bar', 'field', () =>
-        Promise.resolve('bar value')
-      );
-      cache.get('/rootDir/foo', 'field', () =>
-        Promise.resolve('foo value')
-      );
-      cache.get('/rootDir/baz', 'field', () =>
-        Promise.resolve('baz value')
-      );
-
-      // jest has some trouble with promises and timeouts within promises :(
-      jest.runAllTimers();
-      jest.runAllTimers();
-
-      expect(fs.writeFile).toBeCalled();
-    });
-  });
-
-  describe('check for cache presence', () => {
-    it('synchronously resolves cache presence', () => {
-      fs.stat.mockImpl((file, callback) =>
-        callback(null, {
-          mtime: {
-            getTime: () => {},
-          },
-        })
-      );
-
-      var cache = new Cache({
-        cacheKey: 'cache',
-      });
-      var loaderCb = jest.genMockFn().mockImpl(() =>
-        Promise.resolve('banana')
-      );
-      var file = '/rootDir/someFile';
-
-      return cache
-        .get(file, 'field', loaderCb)
-        .then(() => {
-          expect(cache.has(file)).toBe(true);
-          expect(cache.has(file, 'field')).toBe(true);
-          expect(cache.has(file, 'foo')).toBe(false);
-        });
-    });
-  });
-
-  describe('invalidate', () => {
-    it('invalidates the cache per file or per-field', () => {
-      fs.stat.mockImpl((file, callback) =>
-        callback(null, {
-          mtime: {
-            getTime: () => {},
-          },
-        })
-      );
-
-      var cache = new Cache({
-        cacheKey: 'cache',
-      });
-      var loaderCb = jest.genMockFn().mockImpl(() =>
-        Promise.resolve('banana')
-      );
-      var file = '/rootDir/someFile';
-
-      return cache.get(file, 'field', loaderCb).then(() => {
-        expect(cache.has(file)).toBe(true);
-        cache.invalidate(file, 'field');
-        expect(cache.has(file)).toBe(true);
-        expect(cache.has(file, 'field')).toBe(false);
-        cache.invalidate(file);
-        expect(cache.has(file)).toBe(false);
-      });
-    });
-  });
-});
diff --git a/packager/react-packager/src/DependencyResolver/Cache/index.js b/packager/react-packager/src/DependencyResolver/Cache/index.js
deleted file mode 100644
index 26ccb1e7cd97..000000000000
--- a/packager/react-packager/src/DependencyResolver/Cache/index.js
+++ /dev/null
@@ -1,190 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-const Promise = require('promise');
-const fs = require('graceful-fs');
-const getCacheFilePath = require('./lib/getCacheFilePath');
-const isAbsolutePath = require('absolute-path');
-const loadCacheSync = require('./lib/loadCacheSync');
-const tmpDir = require('os').tmpDir();
-
-function getObjectValues(object) {
-  return Object.keys(object).map(key => object[key]);
-}
-
-function debounce(fn, delay) {
-  var timeout;
-  return () => {
-    clearTimeout(timeout);
-    timeout = setTimeout(fn, delay);
-  };
-}
-
-class Cache {
-  constructor({
-    resetCache,
-    cacheKey,
-    cacheDirectory = tmpDir,
-  }) {
-    this._cacheFilePath = getCacheFilePath(cacheDirectory, cacheKey);
-    if (!resetCache) {
-      this._data = this._loadCacheSync(this._cacheFilePath);
-    } else {
-      this._data = Object.create(null);
-    }
-
-    this._persistEventually = debounce(
-      this._persistCache.bind(this),
-      2000,
-    );
-  }
-
-  get(filepath, field, loaderCb) {
-    if (!isAbsolutePath(filepath)) {
-      throw new Error('Use absolute paths');
-    }
-
-    return this.has(filepath, field)
-      ? this._data[filepath].data[field]
-      : this.set(filepath, field, loaderCb(filepath));
-  }
-
-  invalidate(filepath, field) {
-    if (this.has(filepath, field)) {
-      if (field == null) {
-        delete this._data[filepath];
-      } else {
-        delete this._data[filepath].data[field];
-      }
-    }
-  }
-
-  end() {
-    return this._persistCache();
-  }
-
-  has(filepath, field) {
-    return Object.prototype.hasOwnProperty.call(this._data, filepath) &&
-      (field == null || Object.prototype.hasOwnProperty.call(this._data[filepath].data, field));
-  }
-
-  set(filepath, field, loaderPromise) {
-    let record = this._data[filepath];
-    if (!record) {
-      record = Object.create(null);
-      this._data[filepath] = record;
-      this._data[filepath].data = Object.create(null);
-      this._data[filepath].metadata = Object.create(null);
-    }
-
-    record.data[field] = loaderPromise
-      .then(data => Promise.all([
-        data,
-        Promise.denodeify(fs.stat)(filepath),
-      ]))
-      .then(([data, stat]) => {
-        this._persistEventually();
-
-        // Evict all existing field data from the cache if we're putting new
-        // more up to date data
-        var mtime = stat.mtime.getTime();
-        if (record.metadata.mtime !== mtime) {
-          record.data = Object.create(null);
-        }
-        record.metadata.mtime = mtime;
-
-        return data;
-      });
-
-    return record.data[field];
-  }
-
-  _persistCache() {
-    if (this._persisting != null) {
-      return this._persisting;
-    }
-
-    const data = this._data;
-    const cacheFilepath = this._cacheFilePath;
-
-    const allPromises = getObjectValues(data)
-      .map(record => {
-        const fieldNames = Object.keys(record.data);
-        const fieldValues = getObjectValues(record.data);
-
-        return Promise
-          .all(fieldValues)
-          .then(ref => {
-            const ret = Object.create(null);
-            ret.metadata = record.metadata;
-            ret.data = Object.create(null);
-            fieldNames.forEach((field, index) =>
-              ret.data[field] = ref[index]
-            );
-
-            return ret;
-          });
-      }
-    );
-
-    this._persisting = Promise.all(allPromises)
-      .then(values => {
-        const json = Object.create(null);
-        Object.keys(data).forEach((key, i) => {
-          // make sure the key wasn't added nor removed after we started
-          // persisting the cache
-          const value = values[i];
-          if (!value) {
-            return;
-          }
-
-          json[key] = Object.create(null);
-          json[key].metadata = data[key].metadata;
-          json[key].data = value.data;
-        });
-        return Promise.denodeify(fs.writeFile)(cacheFilepath, JSON.stringify(json));
-      })
-      .catch(e => console.error('Error while persisting cache:', e.message))
-      .then(() => {
-        this._persisting = null;
-        return true;
-      });
-
-    return this._persisting;
-  }
-
-  _loadCacheSync(cachePath) {
-    var ret = Object.create(null);
-    var cacheOnDisk = loadCacheSync(cachePath);
-
-    // Filter outdated cache and convert to promises.
-    Object.keys(cacheOnDisk).forEach(key => {
-      if (!fs.existsSync(key)) {
-        return;
-      }
-      var record = cacheOnDisk[key];
-      var stat = fs.statSync(key);
-      if (stat.mtime.getTime() === record.metadata.mtime) {
-        ret[key] = Object.create(null);
-        ret[key].metadata = Object.create(null);
-        ret[key].data = Object.create(null);
-        ret[key].metadata.mtime = record.metadata.mtime;
-
-        Object.keys(record.data).forEach(field => {
-          ret[key].data[field] = Promise.resolve(record.data[field]);
-        });
-      }
-    });
-
-    return ret;
-  }
-}
-
-module.exports = Cache;
diff --git a/packager/react-packager/src/DependencyResolver/Cache/lib/getCacheFilePath.js b/packager/react-packager/src/DependencyResolver/Cache/lib/getCacheFilePath.js
deleted file mode 100644
index a14faf9ff853..000000000000
--- a/packager/react-packager/src/DependencyResolver/Cache/lib/getCacheFilePath.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-const crypto = require('crypto');
-const path = require('fast-path');
-
-function getCacheFilePath(tmpdir, ...args) {
-  const hash = crypto.createHash('md5');
-  args.forEach(arg => hash.update(arg));
-  return path.join(tmpdir, hash.digest('hex'));
-}
-
-module.exports = getCacheFilePath;
diff --git a/packager/react-packager/src/DependencyResolver/Cache/lib/loadCacheSync.js b/packager/react-packager/src/DependencyResolver/Cache/lib/loadCacheSync.js
deleted file mode 100644
index 87d6944c1267..000000000000
--- a/packager/react-packager/src/DependencyResolver/Cache/lib/loadCacheSync.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-const fs = require('graceful-fs');
-
-function loadCacheSync(cachePath) {
-  if (!fs.existsSync(cachePath)) {
-    return Object.create(null);
-  }
-
-  try {
-    return JSON.parse(fs.readFileSync(cachePath));
-  } catch (e) {
-    if (e instanceof SyntaxError) {
-      console.warn('Unable to parse cache file. Will clear and continue.');
-      try {
-        fs.unlinkSync(cachePath);
-      } catch (err) {
-        // Someone else might've deleted it.
-      }
-      return Object.create(null);
-    }
-    throw e;
-  }
-}
-
-module.exports = loadCacheSync;
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/DependencyGraphHelpers.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/DependencyGraphHelpers.js
deleted file mode 100644
index ed5a1a7b7308..000000000000
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/DependencyGraphHelpers.js
+++ /dev/null
@@ -1,45 +0,0 @@
- /**
- * 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.
- */
-'use strict';
-
-const path = require('fast-path');
-
-class DependencyGraphHelpers {
-  constructor({ providesModuleNodeModules, assetExts }) {
-    this._providesModuleNodeModules = providesModuleNodeModules;
-    this._assetExts = assetExts;
-  }
-
-  isNodeModulesDir(file) {
-    const index = file.lastIndexOf('/node_modules/');
-    if (index === -1) {
-      return false;
-    }
-
-    const parts = file.substr(index + 14).split(path.sep);
-    const dirs = this._providesModuleNodeModules;
-    for (let i = 0; i < dirs.length; i++) {
-      if (parts.indexOf(dirs[i]) > -1) {
-        return false;
-      }
-    }
-
-    return true;
-  }
-
-  isAssetFile(file) {
-    return this._assetExts.indexOf(this.extname(file)) !== -1;
-  }
-
-  extname(name) {
-    return path.extname(name).substr(1);
-  }
-}
-
-module.exports = DependencyGraphHelpers;
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/DeprecatedAssetMap.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/DeprecatedAssetMap.js
deleted file mode 100644
index 531d54bc472c..000000000000
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/DeprecatedAssetMap.js
+++ /dev/null
@@ -1,119 +0,0 @@
- /**
- * 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.
- */
-'use strict';
-
-const AssetModule_DEPRECATED = require('../AssetModule_DEPRECATED');
-const Fastfs = require('../fastfs');
-const debug = require('debug')('ReactNativePackager:DependencyGraph');
-const path = require('fast-path');
-const Promise = require('promise');
-
-class DeprecatedAssetMap {
-  constructor({
-    fsCrawl,
-    roots,
-    assetExts,
-    fileWatcher,
-    ignoreFilePath,
-    helpers,
-    activity,
-    enabled,
-  }) {
-    if (roots == null || roots.length === 0 || !enabled) {
-      this._disabled = true;
-      return;
-    }
-
-    this._helpers = helpers;
-    this._map = Object.create(null);
-    this._assetExts = assetExts;
-    this._activity = activity;
-
-    if (!this._disabled) {
-      this._fastfs = new Fastfs(
-        'Assets',
-        roots,
-        fileWatcher,
-        { ignore: ignoreFilePath, crawling: fsCrawl, activity }
-      );
-
-      this._fastfs.on('change', this._processFileChange.bind(this));
-    }
-  }
-
-  build() {
-    if (this._disabled) {
-      return Promise.resolve();
-    }
-
-    return this._fastfs.build().then(
-      () => {
-        const activity = this._activity;
-        let processAsset_DEPRECATEDActivity;
-        if (activity) {
-          processAsset_DEPRECATEDActivity = activity.startEvent(
-            'Building (deprecated) Asset Map',
-          );
-        }
-
-        this._fastfs.findFilesByExts(this._assetExts).forEach(
-          file => this._processAsset(file)
-        );
-
-        if (activity) {
-          activity.endEvent(processAsset_DEPRECATEDActivity);
-        }
-      }
-    );
-  }
-
-  resolve(fromModule, toModuleName) {
-    if (this._disabled) {
-      return null;
-    }
-
-    const assetMatch = toModuleName.match(/^image!(.+)/);
-    if (assetMatch && assetMatch[1]) {
-      if (!this._map[assetMatch[1]]) {
-        debug('WARINING: Cannot find asset:', assetMatch[1]);
-        return null;
-      }
-      return this._map[assetMatch[1]];
-    }
-  }
-
-  _processAsset(file) {
-    const ext = this._helpers.extname(file);
-    if (this._assetExts.indexOf(ext) !== -1) {
-      const name = assetName(file, ext);
-      if (this._map[name] != null) {
-        debug('Conflicting assets', name);
-      }
-
-      this._map[name] = new AssetModule_DEPRECATED({ file });
-    }
-  }
-
-  _processFileChange(type, filePath, root, fstat) {
-    const name = assetName(filePath);
-    if (type === 'change' || type === 'delete') {
-      delete this._map[name];
-    }
-
-    if (type === 'change' || type === 'add') {
-      this._processAsset(path.join(root, filePath));
-    }
-  }
-}
-
-function assetName(file, ext) {
-  return path.basename(file, '.' + ext).replace(/@[\d\.]+x/, '');
-}
-
-module.exports = DeprecatedAssetMap;
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/HasteMap.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/HasteMap.js
deleted file mode 100644
index 47f93699b3b9..000000000000
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/HasteMap.js
+++ /dev/null
@@ -1,142 +0,0 @@
- /**
- * 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.
- */
-'use strict';
-const path = require('fast-path');
-const getPlatformExtension = require('../lib/getPlatformExtension');
-const Promise = require('promise');
-
-const GENERIC_PLATFORM = 'generic';
-const NATIVE_PLATFORM = 'native';
-
-class HasteMap {
-  constructor({
-    extensions,
-    fastfs,
-    moduleCache,
-    preferNativePlatform,
-    helpers,
-  }) {
-    this._extensions = extensions;
-    this._fastfs = fastfs;
-    this._moduleCache = moduleCache;
-    this._preferNativePlatform = preferNativePlatform;
-    this._helpers = helpers;
-  }
-
-  build() {
-    this._map = Object.create(null);
-    const promises = [];
-    this._fastfs.getAllFiles().forEach(filePath => {
-      if (!this._helpers.isNodeModulesDir(filePath)) {
-        if (this._extensions.indexOf(path.extname(filePath).substr(1)) !== -1) {
-          promises.push(this._processHasteModule(filePath));
-        }
-        if (filePath.endsWith('/package.json')) {
-          promises.push(this._processHastePackage(filePath));
-        }
-      }
-    });
-    return Promise.all(promises).then(() => this._map);
-  }
-
-  processFileChange(type, absPath) {
-    return Promise.resolve().then(() => {
-      /*eslint no-labels: 0 */
-      if (type === 'delete' || type === 'change') {
-        loop: for (const name in this._map) {
-          const modulesMap = this._map[name];
-          for (const platform in modulesMap) {
-            const module = modulesMap[platform];
-            if (module.path === absPath) {
-              delete modulesMap[platform];
-              break loop;
-            }
-          }
-        }
-
-        if (type === 'delete') {
-          return null;
-        }
-      }
-
-      if (this._extensions.indexOf(this._helpers.extname(absPath)) !== -1) {
-        if (path.basename(absPath) === 'package.json') {
-          return this._processHastePackage(absPath);
-        } else {
-          return this._processHasteModule(absPath);
-        }
-      }
-    });
-  }
-
-  getModule(name, platform = null) {
-    const modulesMap = this._map[name];
-    if (modulesMap == null) {
-      return null;
-    }
-
-    // If platform is 'ios', we prefer .ios.js to .native.js which we prefer to
-    // a plain .js file.
-    let module = undefined;
-    if (module == null && platform != null) {
-      module = modulesMap[platform];
-    }
-    if (module == null && this._preferNativePlatform) {
-      module = modulesMap[NATIVE_PLATFORM];
-    }
-    if (module == null) {
-      module = modulesMap[GENERIC_PLATFORM];
-    }
-    return module;
-  }
-
-  _processHasteModule(file) {
-    const module = this._moduleCache.getModule(file);
-    return module.isHaste().then(
-      isHaste => isHaste && module.getName()
-        .then(name => this._updateHasteMap(name, module))
-    );
-  }
-
-  _processHastePackage(file) {
-    file = path.resolve(file);
-    const p = this._moduleCache.getPackage(file);
-    return p.isHaste()
-      .then(isHaste => isHaste && p.getName()
-            .then(name => this._updateHasteMap(name, p)))
-      .catch(e => {
-        if (e instanceof SyntaxError) {
-          // Malformed package.json.
-          return;
-        }
-        throw e;
-      });
-  }
-
-  _updateHasteMap(name, mod) {
-    if (this._map[name] == null) {
-      this._map[name] = Object.create(null);
-    }
-
-    const moduleMap = this._map[name];
-    const modulePlatform = getPlatformExtension(mod.path) || GENERIC_PLATFORM;
-    const existingModule = moduleMap[modulePlatform];
-
-    if (existingModule && existingModule.path !== mod.path) {
-      throw new Error(
-        `Naming collision detected: ${mod.path} ` +
-        `collides with ${existingModule.path}`
-      );
-    }
-
-    moduleMap[modulePlatform] = mod;
-  }
-}
-
-module.exports = HasteMap;
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
deleted file mode 100644
index 510b03fe393e..000000000000
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js
+++ /dev/null
@@ -1,446 +0,0 @@
- /**
- * 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.
- */
-'use strict';
-
-const debug = require('debug')('ReactNativePackager:DependencyGraph');
-const util = require('util');
-const path = require('fast-path');
-const realPath = require('path');
-const isAbsolutePath = require('absolute-path');
-const getAssetDataFromName = require('../lib/getAssetDataFromName');
-const Promise = require('promise');
-
-class ResolutionRequest {
-  constructor({
-    platform,
-    preferNativePlatform,
-    entryPath,
-    hasteMap,
-    deprecatedAssetMap,
-    helpers,
-    moduleCache,
-    fastfs,
-    shouldThrowOnUnresolvedErrors,
-  }) {
-    this._platform = platform;
-    this._preferNativePlatform = preferNativePlatform;
-    this._entryPath = entryPath;
-    this._hasteMap = hasteMap;
-    this._deprecatedAssetMap = deprecatedAssetMap;
-    this._helpers = helpers;
-    this._moduleCache = moduleCache;
-    this._fastfs = fastfs;
-    this._shouldThrowOnUnresolvedErrors = shouldThrowOnUnresolvedErrors;
-    this._resetResolutionCache();
-  }
-
-  _tryResolve(action, secondaryAction) {
-    return action().catch((error) => {
-      if (error.type !== 'UnableToResolveError') {
-        throw error;
-      }
-      return secondaryAction();
-    });
-  }
-
-  resolveDependency(fromModule, toModuleName) {
-    const resHash = resolutionHash(fromModule.path, toModuleName);
-
-    if (this._immediateResolutionCache[resHash]) {
-      return Promise.resolve(this._immediateResolutionCache[resHash]);
-    }
-
-    const asset_DEPRECATED = this._deprecatedAssetMap.resolve(
-      fromModule,
-      toModuleName
-    );
-    if (asset_DEPRECATED) {
-      return Promise.resolve(asset_DEPRECATED);
-    }
-
-    const cacheResult = (result) => {
-      this._immediateResolutionCache[resHash] = result;
-      return result;
-    };
-
-    const forgive = (error) => {
-      if (
-        error.type !== 'UnableToResolveError' ||
-        this._shouldThrowOnUnresolvedErrors(this._entryPath, this._platform)
-      ) {
-        throw error;
-      }
-
-      debug(
-        'Unable to resolve module %s from %s',
-        toModuleName,
-        fromModule.path
-      );
-      return null;
-    };
-
-    if (!this._helpers.isNodeModulesDir(fromModule.path)
-        && toModuleName[0] !== '.' &&
-        toModuleName[0] !== '/') {
-      return this._tryResolve(
-        () => this._resolveHasteDependency(fromModule, toModuleName),
-        () => this._resolveNodeDependency(fromModule, toModuleName)
-      ).then(
-        cacheResult,
-        forgive,
-      );
-    }
-
-    return this._resolveNodeDependency(fromModule, toModuleName)
-      .then(
-        cacheResult,
-        forgive,
-      );
-  }
-
-  getOrderedDependencies(response, mocksPattern, recursive = true) {
-    return this._getAllMocks(mocksPattern).then(allMocks => {
-      const entry = this._moduleCache.getModule(this._entryPath);
-      const mocks = Object.create(null);
-      const visited = Object.create(null);
-      visited[entry.hash()] = true;
-
-      response.pushDependency(entry);
-      const collect = (mod) => {
-        return mod.getDependencies().then(
-          depNames => Promise.all(
-            depNames.map(name => this.resolveDependency(mod, name))
-          ).then((dependencies) => [depNames, dependencies])
-        ).then(([depNames, dependencies]) => {
-          if (allMocks) {
-            const list = [mod.getName()];
-            const pkg = mod.getPackage();
-            if (pkg) {
-              list.push(pkg.getName());
-            }
-            return Promise.all(list).then(names => {
-              names.forEach(name => {
-                if (allMocks[name] && !mocks[name]) {
-                  const mockModule =
-                    this._moduleCache.getModule(allMocks[name]);
-                  depNames.push(name);
-                  dependencies.push(mockModule);
-                  mocks[name] = allMocks[name];
-                }
-              });
-              return [depNames, dependencies];
-            });
-          }
-          return Promise.resolve([depNames, dependencies]);
-        }).then(([depNames, dependencies]) => {
-          let p = Promise.resolve();
-          const filteredPairs = [];
-
-          dependencies.forEach((modDep, i) => {
-            const name = depNames[i];
-            if (modDep == null) {
-              // It is possible to require mocks that don't have a real
-              // module backing them. If a dependency cannot be found but there
-              // exists a mock with the desired ID, resolve it and add it as
-              // a dependency.
-              if (allMocks && allMocks[name] && !mocks[name]) {
-                const mockModule = this._moduleCache.getModule(allMocks[name]);
-                mocks[name] = allMocks[name];
-                return filteredPairs.push([name, mockModule]);
-              }
-
-              debug(
-                'WARNING: Cannot find required module `%s` from module `%s`',
-                name,
-                mod.path
-              );
-              return false;
-            }
-            return filteredPairs.push([name, modDep]);
-          });
-
-          response.setResolvedDependencyPairs(mod, filteredPairs);
-
-          filteredPairs.forEach(([depName, modDep]) => {
-            p = p.then(() => {
-              if (!visited[modDep.hash()]) {
-                visited[modDep.hash()] = true;
-                response.pushDependency(modDep);
-                if (recursive) {
-                  return collect(modDep);
-                }
-              }
-              return null;
-            });
-          });
-
-          return p;
-        });
-      };
-
-      return collect(entry).then(() => response.setMocks(mocks));
-    });
-  }
-
-  _getAllMocks(pattern) {
-    // Take all mocks in all the roots into account. This is necessary
-    // because currently mocks are global: any module can be mocked by
-    // any mock in the system.
-    let mocks = null;
-    if (pattern) {
-      mocks = Object.create(null);
-      this._fastfs.matchFilesByPattern(pattern).forEach(file =>
-        mocks[path.basename(file, path.extname(file))] = file
-      );
-    }
-    return Promise.resolve(mocks);
-  }
-
-  _resolveHasteDependency(fromModule, toModuleName) {
-    toModuleName = normalizePath(toModuleName);
-
-    let p = fromModule.getPackage();
-    if (p) {
-      p = p.redirectRequire(toModuleName);
-    } else {
-      p = Promise.resolve(toModuleName);
-    }
-
-    return p.then((realModuleName) => {
-      let dep = this._hasteMap.getModule(realModuleName, this._platform);
-      if (dep && dep.type === 'Module') {
-        return dep;
-      }
-
-      let packageName = realModuleName;
-      while (packageName && packageName !== '.') {
-        dep = this._hasteMap.getModule(packageName, this._platform);
-        if (dep && dep.type === 'Package') {
-          break;
-        }
-        packageName = path.dirname(packageName);
-      }
-
-      if (dep && dep.type === 'Package') {
-        const potentialModulePath = path.join(
-          dep.root,
-          path.relative(packageName, realModuleName)
-        );
-        return this._tryResolve(
-          () => this._loadAsFile(
-            potentialModulePath,
-            fromModule,
-            toModuleName,
-          ),
-          () => this._loadAsDir(potentialModulePath, fromModule, toModuleName),
-        );
-      }
-
-      throw new UnableToResolveError(
-        fromModule,
-        toModuleName,
-        'Unable to resolve dependency',
-      );
-    });
-  }
-
-  _redirectRequire(fromModule, modulePath) {
-    return Promise.resolve(fromModule.getPackage()).then(p => {
-      if (p) {
-        return p.redirectRequire(modulePath);
-      }
-      return modulePath;
-    });
-  }
-
-  _resolveFileOrDir(fromModule, toModuleName) {
-    const potentialModulePath = isAbsolutePath(toModuleName) ?
-        toModuleName :
-        path.join(path.dirname(fromModule.path), toModuleName);
-
-    return this._redirectRequire(fromModule, potentialModulePath).then(
-      realModuleName => this._tryResolve(
-        () => this._loadAsFile(realModuleName, fromModule, toModuleName),
-        () => this._loadAsDir(realModuleName, fromModule, toModuleName)
-      )
-    );
-  }
-
-  _resolveNodeDependency(fromModule, toModuleName) {
-    if (toModuleName[0] === '.' || toModuleName[1] === '/') {
-      return this._resolveFileOrDir(fromModule, toModuleName);
-    } else {
-      return this._redirectRequire(fromModule, toModuleName).then(
-        realModuleName => {
-          if (realModuleName[0] === '.' || realModuleName[1] === '/') {
-            // derive absolute path /.../node_modules/fromModuleDir/realModuleName
-            const fromModuleParentIdx = fromModule.path.lastIndexOf('node_modules/') + 13;
-            const fromModuleDir = fromModule.path.slice(0, fromModule.path.indexOf('/', fromModuleParentIdx));
-            const absPath = path.join(fromModuleDir, realModuleName);
-            return this._resolveFileOrDir(fromModule, absPath);
-          }
-
-          const searchQueue = [];
-          for (let currDir = path.dirname(fromModule.path);
-               currDir !== realPath.parse(fromModule.path).root;
-               currDir = path.dirname(currDir)) {
-            searchQueue.push(
-              path.join(currDir, 'node_modules', realModuleName)
-            );
-          }
-
-          let p = Promise.reject(new UnableToResolveError(
-            fromModule,
-            toModuleName,
-            'Node module not found',
-          ));
-          searchQueue.forEach(potentialModulePath => {
-            p = this._tryResolve(
-              () => this._tryResolve(
-                () => p,
-                () => this._loadAsFile(potentialModulePath, fromModule, toModuleName),
-              ),
-              () => this._loadAsDir(potentialModulePath, fromModule, toModuleName)
-            );
-          });
-
-          return p;
-        });
-    }
-  }
-
-  _loadAsFile(potentialModulePath, fromModule, toModule) {
-    return Promise.resolve().then(() => {
-      if (this._helpers.isAssetFile(potentialModulePath)) {
-        const dirname = path.dirname(potentialModulePath);
-        if (!this._fastfs.dirExists(dirname)) {
-          throw new UnableToResolveError(
-            fromModule,
-            toModule,
-            `Directory ${dirname} doesn't exist`,
-          );
-        }
-
-        const {name, type} = getAssetDataFromName(potentialModulePath);
-
-        let pattern = '^' + name + '(@[\\d\\.]+x)?';
-        if (this._platform != null) {
-          pattern += '(\\.' + this._platform + ')?';
-        }
-        pattern += '\\.' + type;
-
-        // We arbitrarly grab the first one, because scale selection
-        // will happen somewhere
-        const [assetFile] = this._fastfs.matches(
-          dirname,
-          new RegExp(pattern)
-        );
-
-        if (assetFile) {
-          return this._moduleCache.getAssetModule(assetFile);
-        }
-      }
-
-      let file;
-      if (this._fastfs.fileExists(potentialModulePath)) {
-        file = potentialModulePath;
-      } else if (this._platform != null &&
-                 this._fastfs.fileExists(potentialModulePath + '.' + this._platform + '.js')) {
-        file = potentialModulePath + '.' + this._platform + '.js';
-      } else if (this._preferNativePlatform &&
-                 this._fastfs.fileExists(potentialModulePath + '.native.js')) {
-        file = potentialModulePath + '.native.js';
-      } else if (this._fastfs.fileExists(potentialModulePath + '.js')) {
-        file = potentialModulePath + '.js';
-      } else if (this._fastfs.fileExists(potentialModulePath + '.json')) {
-        file = potentialModulePath + '.json';
-      } else {
-        throw new UnableToResolveError(
-          fromModule,
-          toModule,
-          `File ${potentialModulePath} doesnt exist`,
-        );
-      }
-
-      return this._moduleCache.getModule(file);
-    });
-  }
-
-  _loadAsDir(potentialDirPath, fromModule, toModule) {
-    return Promise.resolve().then(() => {
-      if (!this._fastfs.dirExists(potentialDirPath)) {
-        throw new UnableToResolveError(
-          fromModule,
-          toModule,
-`Unable to find this module in its module map or any of the node_modules directories under ${potentialDirPath} and its parent directories
-
-This might be related to https://github.com/facebook/react-native/issues/4968
-To resolve try the following:
-  1. Clear watchman watches: \`watchman watch-del-all\`.
-  2. Delete the \`node_modules\` folder: \`rm -rf node_modules && npm install\`.
-  3. Reset packager cache: \`rm -fr $TMPDIR/react-*\` or \`npm start -- --reset-cache\`.`,
-        );
-      }
-
-      const packageJsonPath = path.join(potentialDirPath, 'package.json');
-      if (this._fastfs.fileExists(packageJsonPath)) {
-        return this._moduleCache.getPackage(packageJsonPath)
-          .getMain().then(
-            (main) => this._tryResolve(
-              () => this._loadAsFile(main, fromModule, toModule),
-              () => this._loadAsDir(main, fromModule, toModule)
-            )
-          );
-      }
-
-      return this._loadAsFile(
-        path.join(potentialDirPath, 'index'),
-        fromModule,
-        toModule,
-      );
-    });
-  }
-
-  _resetResolutionCache() {
-    this._immediateResolutionCache = Object.create(null);
-  }
-
-}
-
-
-function resolutionHash(modulePath, depName) {
-  return `${path.resolve(modulePath)}:${depName}`;
-}
-
-
-function UnableToResolveError(fromModule, toModule, message) {
-  Error.call(this);
-  Error.captureStackTrace(this, this.constructor);
-  this.message = util.format(
-    'Unable to resolve module %s from %s: %s',
-    toModule,
-    fromModule.path,
-    message,
-  );
-  this.type = this.name = 'UnableToResolveError';
-}
-
-util.inherits(UnableToResolveError, Error);
-
-function normalizePath(modulePath) {
-  if (path.sep === '/') {
-    modulePath = path.normalize(modulePath);
-  } else if (path.posix) {
-    modulePath = path.posix.normalize(modulePath);
-  }
-
-  return modulePath.replace(/\/$/, '');
-}
-
-module.exports = ResolutionRequest;
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js
deleted file mode 100644
index 56e1ed7a104b..000000000000
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js
+++ /dev/null
@@ -1,87 +0,0 @@
- /**
- * 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.
- */
-'use strict';
-
-class ResolutionResponse {
-  constructor() {
-    this.dependencies = [];
-    this.mainModuleId = null;
-    this.mocks = null;
-    this.numPrependedDependencies = 0;
-    this._mappings = Object.create(null);
-    this._finalized = false;
-  }
-
-  copy(properties) {
-    const {
-      dependencies = this.dependencies,
-      mainModuleId = this.mainModuleId,
-      mocks = this.mocks,
-    } = properties;
-    return Object.assign(new this.constructor(), this, {
-      dependencies,
-      mainModuleId,
-      mocks,
-    });
-  }
-
-  _assertNotFinalized() {
-    if (this._finalized) {
-      throw new Error('Attempted to mutate finalized response.');
-    }
-  }
-
-  _assertFinalized() {
-    if (!this._finalized) {
-      throw new Error('Attempted to access unfinalized response.');
-    }
-  }
-
-  finalize() {
-    return this._mainModule.getName().then(id => {
-      this.mainModuleId = id;
-      this._finalized = true;
-      return this;
-    });
-  }
-
-  pushDependency(module) {
-    this._assertNotFinalized();
-    if (this.dependencies.length === 0) {
-      this._mainModule = module;
-    }
-
-    this.dependencies.push(module);
-  }
-
-  prependDependency(module) {
-    this._assertNotFinalized();
-    this.dependencies.unshift(module);
-    this.numPrependedDependencies += 1;
-  }
-
-  setResolvedDependencyPairs(module, pairs) {
-    this._assertNotFinalized();
-    const hash = module.hash();
-    if (this._mappings[hash] == null) {
-      this._mappings[hash] = pairs;
-    }
-  }
-
-  setMocks(mocks) {
-    this.mocks = mocks;
-  }
-
-  getResolvedDependencyPairs(module) {
-    this._assertFinalized();
-    return this._mappings[module.hash()];
-  }
-}
-
-module.exports = ResolutionResponse;
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
deleted file mode 100644
index fa823286ab95..000000000000
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js
+++ /dev/null
@@ -1,4285 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-jest.autoMockOff();
-
-jest.mock('fs');
-
-const Promise = require('promise');
-const DependencyGraph = require('../index');
-const fs = require('graceful-fs');
-
-const mocksPattern = /(?:[\\/]|^)__mocks__[\\/]([^\/]+)\.js$/;
-
-describe('DependencyGraph', function() {
-  let defaults;
-
-  function getOrderedDependenciesAsJSON(dgraph, entry, platform, recursive = true) {
-    return dgraph.getDependencies(entry, platform, recursive)
-      .then(response => response.finalize())
-      .then(({ dependencies }) => Promise.all(dependencies.map(dep => Promise.all([
-        dep.getName(),
-        dep.getDependencies(),
-      ]).then(([name, moduleDependencies]) => ({
-        path: dep.path,
-        isJSON: dep.isJSON(),
-        isAsset: dep.isAsset(),
-        isAsset_DEPRECATED: dep.isAsset_DEPRECATED(),
-        isPolyfill: dep.isPolyfill(),
-        resolution: dep.resolution,
-        id: name,
-        dependencies: moduleDependencies,
-      })))
-    ));
-  }
-
-  beforeEach(function() {
-    const fileWatcher = {
-      on: function() {
-        return this;
-      },
-      isWatchman: () => Promise.resolve(false),
-    };
-
-    const Cache = jest.genMockFn().mockImplementation(function() {
-      this._maps = Object.create(null);
-    });
-    Cache.prototype.has = jest.genMockFn()
-      .mockImplementation(function(filepath, field) {
-        if (!(filepath in this._maps)) {
-          return false;
-        }
-        return !field || field in this._maps[filepath];
-      });
-    Cache.prototype.get = jest.genMockFn()
-      .mockImplementation(function(filepath, field, factory) {
-        let cacheForPath  = this._maps[filepath];
-        if (this.has(filepath, field)) {
-          return field ? cacheForPath[field] : cacheForPath;
-        }
-
-        if (!cacheForPath) {
-          cacheForPath = this._maps[filepath] = Object.create(null);
-        }
-        const value = cacheForPath[field] = factory();
-        return value;
-      });
-    Cache.prototype.invalidate = jest.genMockFn()
-      .mockImplementation(function(filepath, field) {
-        if (!this.has(filepath, field)) {
-          return;
-        }
-
-        if (field) {
-          delete this._maps[filepath][field];
-        } else {
-          delete this._maps[filepath];
-        }
-      });
-    Cache.prototype.end = jest.genMockFn();
-
-    defaults = {
-      assetExts: ['png', 'jpg'],
-      cache: new Cache(),
-      fileWatcher,
-      providesModuleNodeModules: [
-        'haste-fbjs',
-        'react-haste',
-        'react-native',
-        // Parse requires AsyncStorage. They will
-        // change that to require('react-native') which
-        // should work after this release and we can
-        // remove it from here.
-        'parse',
-      ],
-      platforms: ['ios', 'android'],
-      shouldThrowOnUnresolvedErrors: () => false,
-    };
-  });
-
-  describe('get sync dependencies', function() {
-    pit('should get dependencies', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("a")',
-          ].join('\n'),
-          'a.js': [
-            '/**',
-            ' * @providesModule a',
-            ' */',
-            'require("b")',
-          ].join('\n'),
-          'b.js': [
-            '/**',
-            ' * @providesModule b',
-            ' */',
-          ].join('\n'),
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['a'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-              resolveDependency: undefined,
-            },
-            {
-              id: 'a',
-              path: '/root/a.js',
-              dependencies: ['b'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-              resolveDependency: undefined,
-            },
-            {
-              id: 'b',
-              path: '/root/b.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-              resolveDependency: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should get shallow dependencies', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("a")',
-          ].join('\n'),
-          'a.js': [
-            '/**',
-            ' * @providesModule a',
-            ' */',
-            'require("b")',
-          ].join('\n'),
-          'b.js': [
-            '/**',
-            ' * @providesModule b',
-            ' */',
-          ].join('\n'),
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js', null, false).then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['a'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'a',
-              path: '/root/a.js',
-              dependencies: ['b'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should get dependencies with the correct extensions', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("a")',
-          ].join('\n'),
-          'a.js': [
-            '/**',
-            ' * @providesModule a',
-            ' */',
-          ].join('\n'),
-          'a.js.orig': [
-            '/**',
-            ' * @providesModule a',
-            ' */',
-          ].join('\n'),
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['a'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'a',
-              path: '/root/a.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should get json dependencies', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'package.json': JSON.stringify({
-            name: 'package',
-          }),
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("./a.json")',
-            'require("./b")',
-          ].join('\n'),
-          'a.json': JSON.stringify({}),
-          'b.json': JSON.stringify({}),
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['./a.json', './b'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'package/a.json',
-              isJSON: true,
-              path: '/root/a.json',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'package/b.json',
-              isJSON: true,
-              path: '/root/b.json',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should get package json as a dep', () => {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'package.json': JSON.stringify({
-            name: 'package',
-          }),
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("./package.json")',
-          ].join('\n'),
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(deps => {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['./package.json'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'package/package.json',
-              isJSON: true,
-              path: '/root/package.json',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should get dependencies with deprecated assets', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("image!a")',
-          ].join('\n'),
-          'imgs': {
-            'a.png': '',
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-        assetRoots_DEPRECATED: ['/root/imgs'],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['image!a'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'image!a',
-              path: '/root/imgs/a.png',
-              dependencies: [],
-              isAsset_DEPRECATED: true,
-              resolution: 1,
-              isAsset: false,
-              isJSON: false,
-              isPolyfill: false,
-            },
-          ]);
-      });
-    });
-
-    pit('should get dependencies with relative assets', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("./imgs/a.png")',
-          ].join('\n'),
-          'imgs': {
-            'a.png': '',
-          },
-          'package.json': JSON.stringify({
-            name: 'rootPackage',
-          }),
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['./imgs/a.png'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'rootPackage/imgs/a.png',
-              path: '/root/imgs/a.png',
-              dependencies: [],
-              isAsset: true,
-              resolution: 1,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-            },
-          ]);
-      });
-    });
-
-    pit('should get dependencies with assets and resolution', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("./imgs/a.png");',
-            'require("./imgs/b.png");',
-            'require("./imgs/c.png");',
-          ].join('\n'),
-          'imgs': {
-            'a@1.5x.png': '',
-            'b@.7x.png': '',
-            'c.png': '',
-            'c@2x.png': '',
-          },
-          'package.json': JSON.stringify({
-            name: 'rootPackage',
-          }),
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: [
-                './imgs/a.png',
-                './imgs/b.png',
-                './imgs/c.png',
-              ],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'rootPackage/imgs/a.png',
-              path: '/root/imgs/a@1.5x.png',
-              resolution: 1.5,
-              dependencies: [],
-              isAsset: true,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-            },
-            {
-              id: 'rootPackage/imgs/b.png',
-              path: '/root/imgs/b@.7x.png',
-              resolution: 0.7,
-              dependencies: [],
-              isAsset: true,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-            },
-            {
-              id: 'rootPackage/imgs/c.png',
-              path: '/root/imgs/c.png',
-              resolution: 1,
-              dependencies: [],
-              isAsset: true,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-            },
-          ]);
-      });
-    });
-
-    pit('should respect platform extension in assets', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("./imgs/a.png");',
-            'require("./imgs/b.png");',
-            'require("./imgs/c.png");',
-          ].join('\n'),
-          'imgs': {
-            'a@1.5x.ios.png': '',
-            'b@.7x.ios.png': '',
-            'c.ios.png': '',
-            'c@2x.ios.png': '',
-          },
-          'package.json': JSON.stringify({
-            name: 'rootPackage',
-          }),
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js', 'ios').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: [
-                './imgs/a.png',
-                './imgs/b.png',
-                './imgs/c.png',
-              ],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'rootPackage/imgs/a.png',
-              path: '/root/imgs/a@1.5x.ios.png',
-              resolution: 1.5,
-              dependencies: [],
-              isAsset: true,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-            },
-            {
-              id: 'rootPackage/imgs/b.png',
-              path: '/root/imgs/b@.7x.ios.png',
-              resolution: 0.7,
-              dependencies: [],
-              isAsset: true,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-            },
-            {
-              id: 'rootPackage/imgs/c.png',
-              path: '/root/imgs/c.ios.png',
-              resolution: 1,
-              dependencies: [],
-              isAsset: true,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-            },
-          ]);
-      });
-    });
-
-    pit('Deprecated and relative assets can live together', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("./imgs/a.png")',
-            'require("image!a")',
-          ].join('\n'),
-          'imgs': {
-            'a.png': '',
-          },
-          'package.json': JSON.stringify({
-            name: 'rootPackage',
-          }),
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-        assetRoots_DEPRECATED: ['/root/imgs'],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['./imgs/a.png', 'image!a'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'rootPackage/imgs/a.png',
-              path: '/root/imgs/a.png',
-              dependencies: [],
-              isAsset: true,
-              resolution: 1,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-            },
-            {
-              id: 'image!a',
-              path: '/root/imgs/a.png',
-              dependencies: [],
-              isAsset_DEPRECATED: true,
-              resolution: 1,
-              isAsset: false,
-              isJSON: false,
-              isPolyfill: false,
-            },
-          ]);
-      });
-    });
-
-    pit('should get recursive dependencies', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("a")',
-          ].join('\n'),
-          'a.js': [
-            '/**',
-            ' * @providesModule a',
-            ' */',
-            'require("index")',
-          ].join('\n'),
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['a'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'a',
-              path: '/root/a.js',
-              dependencies: ['index'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should work with packages', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("aPackage")',
-          ].join('\n'),
-          'aPackage': {
-            'package.json': JSON.stringify({
-              name: 'aPackage',
-              main: 'main.js',
-            }),
-            'main.js': 'lol',
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['aPackage'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'aPackage/main.js',
-              path: '/root/aPackage/main.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should work with packages', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("aPackage/")',
-          ].join('\n'),
-          'aPackage': {
-            'package.json': JSON.stringify({
-              name: 'aPackage',
-              main: 'main.js',
-            }),
-            'main.js': 'lol',
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['aPackage/'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'aPackage/main.js',
-              path: '/root/aPackage/main.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should work with packages with a dot in the name', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("sha.js")',
-            'require("x.y.z")',
-          ].join('\n'),
-          'sha.js': {
-            'package.json': JSON.stringify({
-              name: 'sha.js',
-              main: 'main.js',
-            }),
-            'main.js': 'lol',
-          },
-          'x.y.z': {
-            'package.json': JSON.stringify({
-              name: 'x.y.z',
-              main: 'main.js',
-            }),
-            'main.js': 'lol',
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['sha.js', 'x.y.z'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'sha.js/main.js',
-              path: '/root/sha.js/main.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'x.y.z/main.js',
-              path: '/root/x.y.z/main.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should default main package to index.js', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': 'require("aPackage")',
-          'aPackage': {
-            'package.json': JSON.stringify({
-              name: 'aPackage',
-            }),
-            'index.js': 'lol',
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: '/root/index.js',
-              path: '/root/index.js',
-              dependencies: ['aPackage'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'aPackage/index.js',
-              path: '/root/aPackage/index.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should resolve using alternative ids', () => {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': 'require("aPackage")',
-          'aPackage': {
-            'package.json': JSON.stringify({
-              name: 'aPackage',
-            }),
-            'index.js': [
-              '/**',
-              ' * @providesModule EpicModule',
-              ' */',
-            ].join('\n'),
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: '/root/index.js',
-              path: '/root/index.js',
-              dependencies: ['aPackage'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'EpicModule',
-              path: '/root/aPackage/index.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should default use index.js if main is a dir', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': 'require("aPackage")',
-          'aPackage': {
-            'package.json': JSON.stringify({
-              name: 'aPackage',
-              main: 'lib',
-            }),
-            lib: {
-              'index.js': 'lol',
-            },
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: '/root/index.js',
-              path: '/root/index.js',
-              dependencies: ['aPackage'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'aPackage/lib/index.js',
-              path: '/root/aPackage/lib/index.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should resolve require to index if it is a dir', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'package.json': JSON.stringify({
-            name: 'test',
-          }),
-          'index.js': 'require("./lib/")',
-          lib: {
-            'index.js': 'lol',
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'test/index.js',
-              path: '/root/index.js',
-              dependencies: ['./lib/'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'test/lib/index.js',
-              path: '/root/lib/index.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should resolve require to main if it is a dir w/ a package.json', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'package.json': JSON.stringify({
-            name: 'test',
-          }),
-          'index.js': 'require("./lib/")',
-          lib: {
-            'package.json': JSON.stringify({
-              'main': 'main.js',
-            }),
-            'index.js': 'lol',
-            'main.js': 'lol',
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'test/index.js',
-              path: '/root/index.js',
-              dependencies: ['./lib/'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: '/root/lib/main.js',
-              path: '/root/lib/main.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should ignore malformed packages', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-          ].join('\n'),
-          'aPackage': {
-            'package.json': 'lol',
-            'main.js': 'lol',
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should fatal on multiple modules with the same name', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-          ].join('\n'),
-          'b.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-          ].join('\n'),
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-
-      return dgraph.load().catch(err => {
-        expect(err.message).toEqual('Failed to build DependencyGraph: Naming collision detected: /root/b.js collides with /root/index.js');
-        expect(err.type).toEqual('DependencyGraphError');
-      });
-    });
-
-    pit('should be forgiving with missing requires', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("lolomg")',
-          ].join('\n'),
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['lolomg'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-              resolveDependency: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should work with packages with subdirs', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("aPackage/subdir/lolynot")',
-          ].join('\n'),
-          'aPackage': {
-            'package.json': JSON.stringify({
-              name: 'aPackage',
-              main: 'main.js',
-            }),
-            'main.js': 'lol',
-            'subdir': {
-              'lolynot.js': 'lolynot',
-            },
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['aPackage/subdir/lolynot'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-              resolveDependency: undefined,
-            },
-            {
-              id: 'aPackage/subdir/lolynot.js',
-              path: '/root/aPackage/subdir/lolynot.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-              resolveDependency: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should work with packages with symlinked subdirs', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'symlinkedPackage': {
-          'package.json': JSON.stringify({
-            name: 'aPackage',
-            main: 'main.js',
-          }),
-          'main.js': 'lol',
-          'subdir': {
-            'lolynot.js': 'lolynot',
-          },
-        },
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("aPackage/subdir/lolynot")',
-          ].join('\n'),
-          'aPackage': { SYMLINK: '/symlinkedPackage' },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['aPackage/subdir/lolynot'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-              resolveDependency: undefined,
-            },
-            {
-              id: 'aPackage/subdir/lolynot.js',
-              path: '/root/aPackage/subdir/lolynot.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-              resolveDependency: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should work with relative modules in packages', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("aPackage")',
-          ].join('\n'),
-          'aPackage': {
-            'package.json': JSON.stringify({
-              name: 'aPackage',
-              main: 'main.js',
-            }),
-            'main.js': 'require("./subdir/lolynot")',
-            'subdir': {
-              'lolynot.js': 'require("../other")',
-            },
-            'other.js': 'some code',
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['aPackage'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-              resolveDependency: undefined,
-            },
-            {
-              id: 'aPackage/main.js',
-              path: '/root/aPackage/main.js',
-              dependencies: ['./subdir/lolynot'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-              resolveDependency: undefined,
-            },
-            {
-              id: 'aPackage/subdir/lolynot.js',
-              path: '/root/aPackage/subdir/lolynot.js',
-              dependencies: ['../other'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-              resolveDependency: undefined,
-            },
-            {
-              id: 'aPackage/other.js',
-              path: '/root/aPackage/other.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-              resolveDependency: undefined,
-            },
-          ]);
-      });
-    });
-
-    testBrowserField('browser');
-    testBrowserField('react-native');
-
-    function replaceBrowserField(json, fieldName) {
-      if (fieldName !== 'browser') {
-        json[fieldName] = json.browser;
-        delete json.browser;
-      }
-
-      return json;
-    }
-
-    function testBrowserField(fieldName) {
-      pit('should support simple browser field in packages ("' + fieldName + '")', function() {
-        var root = '/root';
-        fs.__setMockFilesystem({
-          'root': {
-            'index.js': [
-              '/**',
-              ' * @providesModule index',
-              ' */',
-              'require("aPackage")',
-            ].join('\n'),
-            'aPackage': {
-              'package.json': JSON.stringify(replaceBrowserField({
-                name: 'aPackage',
-                main: 'main.js',
-                browser: 'client.js',
-              }, fieldName)),
-              'main.js': 'some other code',
-              'client.js': 'some code',
-            },
-          },
-        });
-
-        var dgraph = new DependencyGraph({
-          ...defaults,
-          roots: [root],
-        });
-        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-          expect(deps)
-            .toEqual([
-              {
-                id: 'index',
-                path: '/root/index.js',
-                dependencies: ['aPackage'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-              {
-                id: 'aPackage/client.js',
-                path: '/root/aPackage/client.js',
-                dependencies: [],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-            ]);
-        });
-      });
-
-      pit('should support browser field in packages w/o .js ext ("' + fieldName + '")', function() {
-        var root = '/root';
-        fs.__setMockFilesystem({
-          'root': {
-            'index.js': [
-              '/**',
-              ' * @providesModule index',
-              ' */',
-              'require("aPackage")',
-            ].join('\n'),
-            'aPackage': {
-              'package.json': JSON.stringify(replaceBrowserField({
-                name: 'aPackage',
-                main: 'main.js',
-                browser: 'client',
-              }, fieldName)),
-              'main.js': 'some other code',
-              'client.js': 'some code',
-            },
-          },
-        });
-
-        var dgraph = new DependencyGraph({
-          ...defaults,
-          roots: [root],
-        });
-        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-          expect(deps)
-            .toEqual([
-              {
-                id: 'index',
-                path: '/root/index.js',
-                dependencies: ['aPackage'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-              {
-                id: 'aPackage/client.js',
-                path: '/root/aPackage/client.js',
-                dependencies: [],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-            ]);
-        });
-      });
-
-      pit('should support mapping main in browser field json ("' + fieldName + '")', function() {
-        var root = '/root';
-        fs.__setMockFilesystem({
-          'root': {
-            'index.js': [
-              '/**',
-              ' * @providesModule index',
-              ' */',
-              'require("aPackage")',
-            ].join('\n'),
-            'aPackage': {
-              'package.json': JSON.stringify(replaceBrowserField({
-                name: 'aPackage',
-                main: './main.js',
-                browser: {
-                  './main.js': './client.js',
-                },
-              }, fieldName)),
-              'main.js': 'some other code',
-              'client.js': 'some code',
-            },
-          },
-        });
-
-        var dgraph = new DependencyGraph({
-          ...defaults,
-          roots: [root],
-          assetExts: ['png', 'jpg'],
-        });
-        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-          expect(deps)
-            .toEqual([
-              {
-                id: 'index',
-                path: '/root/index.js',
-                dependencies: ['aPackage'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-              { id: 'aPackage/client.js',
-                path: '/root/aPackage/client.js',
-                dependencies: [],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-            ]);
-        });
-      });
-
-      pit('should work do correct browser mapping w/o js ext ("' + fieldName + '")', function() {
-        var root = '/root';
-        fs.__setMockFilesystem({
-          'root': {
-            'index.js': [
-              '/**',
-              ' * @providesModule index',
-              ' */',
-              'require("aPackage")',
-            ].join('\n'),
-            'aPackage': {
-              'package.json': JSON.stringify(replaceBrowserField({
-                name: 'aPackage',
-                main: './main.js',
-                browser: {
-                  './main': './client.js',
-                },
-              }, fieldName)),
-              'main.js': 'some other code',
-              'client.js': 'some code',
-            },
-          },
-        });
-
-        var dgraph = new DependencyGraph({
-          ...defaults,
-          roots: [root],
-          assetExts: ['png', 'jpg'],
-        });
-        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-          expect(deps)
-            .toEqual([
-              {
-                id: 'index',
-                path: '/root/index.js',
-                dependencies: ['aPackage'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-              {
-                id: 'aPackage/client.js',
-                path: '/root/aPackage/client.js',
-                dependencies: [],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-            ]);
-        });
-      });
-
-      pit('should support browser mapping of files ("' + fieldName + '")', function() {
-        var root = '/root';
-        fs.__setMockFilesystem({
-          'root': {
-            'index.js': [
-              '/**',
-              ' * @providesModule index',
-              ' */',
-              'require("aPackage")',
-            ].join('\n'),
-            'aPackage': {
-              'package.json': JSON.stringify(replaceBrowserField({
-                name: 'aPackage',
-                main: './main.js',
-                browser: {
-                  './main': './client.js',
-                  './node.js': './not-node.js',
-                  './not-browser': './browser.js',
-                  './dir/server.js': './dir/client',
-                  './hello.js': './bye.js',
-                },
-              }, fieldName)),
-              'main.js': 'some other code',
-              'client.js': 'require("./node")\nrequire("./dir/server.js")',
-              'not-node.js': 'require("./not-browser")',
-              'not-browser.js': 'require("./dir/server")',
-              'browser.js': 'some browser code',
-              'dir': {
-                'server.js': 'some node code',
-                'client.js': 'require("../hello")',
-              },
-              'hello.js': 'hello',
-              'bye.js': 'bye',
-            },
-          },
-        });
-
-        const dgraph = new DependencyGraph({
-          ...defaults,
-          roots: [root],
-        });
-        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-          expect(deps)
-            .toEqual([
-              { id: 'index',
-                path: '/root/index.js',
-                dependencies: ['aPackage'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-              { id: 'aPackage/client.js',
-                path: '/root/aPackage/client.js',
-                dependencies: ['./node', './dir/server.js'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-              { id: 'aPackage/not-node.js',
-                path: '/root/aPackage/not-node.js',
-                dependencies: ['./not-browser'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-              { id: 'aPackage/browser.js',
-                path: '/root/aPackage/browser.js',
-                dependencies: [],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-              {
-                id: 'aPackage/dir/client.js',
-                path: '/root/aPackage/dir/client.js',
-                dependencies: ['../hello'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-              {
-                id: 'aPackage/bye.js',
-                path: '/root/aPackage/bye.js',
-                dependencies: [],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-            ]);
-        });
-      });
-
-      pit('should support browser mapping for packages ("' + fieldName + '")', function() {
-        var root = '/root';
-        fs.__setMockFilesystem({
-          'root': {
-            'index.js': [
-              '/**',
-              ' * @providesModule index',
-              ' */',
-              'require("aPackage")',
-            ].join('\n'),
-            'aPackage': {
-              'package.json': JSON.stringify(replaceBrowserField({
-                name: 'aPackage',
-                browser: {
-                  'node-package': 'browser-package',
-                },
-              }, fieldName)),
-              'index.js': 'require("node-package")',
-              'node-package': {
-                'package.json': JSON.stringify({
-                  'name': 'node-package',
-                }),
-                'index.js': 'some node code',
-              },
-              'browser-package': {
-                'package.json': JSON.stringify({
-                  'name': 'browser-package',
-                }),
-                'index.js': 'some browser code',
-              },
-            },
-          },
-        });
-
-        var dgraph = new DependencyGraph({
-          ...defaults,
-          roots: [root],
-        });
-        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-          expect(deps)
-            .toEqual([
-              { id: 'index',
-                path: '/root/index.js',
-                dependencies: ['aPackage'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-              { id: 'aPackage/index.js',
-                path: '/root/aPackage/index.js',
-                dependencies: ['node-package'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-              { id: 'browser-package/index.js',
-                path: '/root/aPackage/browser-package/index.js',
-                dependencies: [],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-            ]);
-        });
-      });
-
-      pit('should support browser mapping of a package to a file ("' + fieldName + '")', function() {
-        var root = '/root';
-        fs.__setMockFilesystem({
-          'root': {
-            'index.js': [
-              '/**',
-              ' * @providesModule index',
-              ' */',
-              'require("aPackage")',
-            ].join('\n'),
-            'aPackage': {
-              'package.json': JSON.stringify(replaceBrowserField({
-                name: 'aPackage',
-                browser: {
-                  'node-package': './dir/browser.js',
-                },
-              }, fieldName)),
-              'index.js': 'require("./dir/ooga")',
-              'dir': {
-                'ooga.js': 'require("node-package")',
-                'browser.js': 'some browser code',
-              },
-              'node-package': {
-                'package.json': JSON.stringify({
-                  'name': 'node-package',
-                }),
-                'index.js': 'some node code',
-              },
-            },
-          },
-        });
-
-        const dgraph = new DependencyGraph({
-          ...defaults,
-          roots: [root],
-        });
-        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-          expect(deps)
-            .toEqual([
-              { id: 'index',
-                path: '/root/index.js',
-                dependencies: ['aPackage'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-              { id: 'aPackage/index.js',
-                path: '/root/aPackage/index.js',
-                dependencies: ['./dir/ooga'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-              { id: 'aPackage/dir/ooga.js',
-                path: '/root/aPackage/dir/ooga.js',
-                dependencies: ['node-package'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-              { id: 'aPackage/dir/browser.js',
-                path: '/root/aPackage/dir/browser.js',
-                dependencies: [],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-            ]);
-        });
-      });
-
-      pit('should support browser mapping for packages ("' + fieldName + '")', function() {
-        var root = '/root';
-        fs.__setMockFilesystem({
-          'root': {
-            'index.js': [
-              '/**',
-              ' * @providesModule index',
-              ' */',
-              'require("aPackage")',
-            ].join('\n'),
-            'aPackage': {
-              'package.json': JSON.stringify(replaceBrowserField({
-                name: 'aPackage',
-                browser: {
-                  'node-package': 'browser-package',
-                },
-              }, fieldName)),
-              'index.js': 'require("node-package")',
-              'node-package': {
-                'package.json': JSON.stringify({
-                  'name': 'node-package',
-                }),
-                'index.js': 'some node code',
-              },
-              'browser-package': {
-                'package.json': JSON.stringify({
-                  'name': 'browser-package',
-                }),
-                'index.js': 'some browser code',
-              },
-            },
-          },
-        });
-
-        var dgraph = new DependencyGraph({
-          ...defaults,
-          roots: [root],
-        });
-        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-          expect(deps)
-            .toEqual([
-              { id: 'index',
-                path: '/root/index.js',
-                dependencies: ['aPackage'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-              { id: 'aPackage/index.js',
-                path: '/root/aPackage/index.js',
-                dependencies: ['node-package'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-              { id: 'browser-package/index.js',
-                path: '/root/aPackage/browser-package/index.js',
-                dependencies: [],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-            ]);
-        });
-      });
-    }
-
-    pit('should fall back to browser mapping from react-native mapping', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("aPackage")',
-          ].join('\n'),
-          'aPackage': {
-            'package.json': JSON.stringify({
-              name: 'aPackage',
-              'react-native': {
-                'node-package': 'rn-package',
-              },
-            }),
-            'index.js': 'require("node-package")',
-            'node_modules': {
-              'node-package': {
-                'package.json': JSON.stringify({
-                  'name': 'node-package',
-                }),
-                'index.js': 'some node code',
-              },
-              'rn-package': {
-                'package.json': JSON.stringify({
-                  'name': 'rn-package',
-                  browser: {
-                    'nested-package': 'nested-browser-package',
-                  },
-                }),
-                'index.js': 'require("nested-package")',
-              },
-              'nested-browser-package': {
-                'package.json': JSON.stringify({
-                  'name': 'nested-browser-package',
-                }),
-                'index.js': 'some code',
-              },
-            },
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            { id: 'index',
-              path: '/root/index.js',
-              dependencies: ['aPackage'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            { id: 'aPackage/index.js',
-              path: '/root/aPackage/index.js',
-              dependencies: ['node-package'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            { id: 'rn-package/index.js',
-              path: '/root/aPackage/node_modules/rn-package/index.js',
-              dependencies: ['nested-package'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            { id: 'nested-browser-package/index.js',
-              path: '/root/aPackage/node_modules/nested-browser-package/index.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-  });
-
-  describe('node_modules', function() {
-    pit('should work with nested node_modules', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("foo");',
-            'require("bar");',
-          ].join('\n'),
-          'node_modules': {
-            'foo': {
-              'package.json': JSON.stringify({
-                name: 'foo',
-                main: 'main.js',
-              }),
-              'main.js': 'require("bar");\nfoo module',
-              'node_modules': {
-                'bar': {
-                  'package.json': JSON.stringify({
-                    name: 'bar',
-                    main: 'main.js',
-                  }),
-                  'main.js': 'bar 1 module',
-                },
-              },
-            },
-            'bar': {
-              'package.json': JSON.stringify({
-                name: 'bar',
-                main: 'main.js',
-              }),
-              'main.js': 'bar 2 module',
-            },
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['foo', 'bar'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'foo/main.js',
-              path: '/root/node_modules/foo/main.js',
-              dependencies: ['bar'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'bar/main.js',
-              path: '/root/node_modules/foo/node_modules/bar/main.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'bar/main.js',
-              path: '/root/node_modules/bar/main.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('platform should work with node_modules', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.ios.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("foo");',
-            'require("bar");',
-          ].join('\n'),
-          'node_modules': {
-            'foo': {
-              'package.json': JSON.stringify({
-                name: 'foo',
-              }),
-              'index.ios.js': '',
-            },
-            'bar': {
-              'package.json': JSON.stringify({
-                name: 'bar',
-                main: 'main',
-              }),
-              'main.ios.js': '',
-            },
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.ios.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.ios.js',
-              dependencies: ['foo', 'bar'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'foo/index.ios.js',
-              path: '/root/node_modules/foo/index.ios.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'bar/main.ios.js',
-              path: '/root/node_modules/bar/main.ios.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('nested node_modules with specific paths', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("foo");',
-            'require("bar/");',
-          ].join('\n'),
-          'node_modules': {
-            'foo': {
-              'package.json': JSON.stringify({
-                name: 'foo',
-                main: 'main.js',
-              }),
-              'main.js': 'require("bar/lol");\nfoo module',
-              'node_modules': {
-                'bar': {
-                  'package.json': JSON.stringify({
-                    name: 'bar',
-                    main: 'main.js',
-                  }),
-                  'main.js': 'bar 1 module',
-                  'lol.js': '',
-                },
-              },
-            },
-            'bar': {
-              'package.json': JSON.stringify({
-                name: 'bar',
-                main: 'main.js',
-              }),
-              'main.js': 'bar 2 module',
-            },
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['foo', 'bar/'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'foo/main.js',
-              path: '/root/node_modules/foo/main.js',
-              dependencies: ['bar/lol'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'bar/lol.js',
-              path: '/root/node_modules/foo/node_modules/bar/lol.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'bar/main.js',
-              path: '/root/node_modules/bar/main.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('nested node_modules with browser field', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("foo");',
-            'require("bar");',
-          ].join('\n'),
-          'node_modules': {
-            'foo': {
-              'package.json': JSON.stringify({
-                name: 'foo',
-                main: 'main.js',
-              }),
-              'main.js': 'require("bar/lol");\nfoo module',
-              'node_modules': {
-                'bar': {
-                  'package.json': JSON.stringify({
-                    name: 'bar',
-                    main: 'main.js',
-                    browser: {
-                      './lol': './wow',
-                    },
-                  }),
-                  'main.js': 'bar 1 module',
-                  'lol.js': '',
-                  'wow.js': '',
-                },
-              },
-            },
-            'bar': {
-              'package.json': JSON.stringify({
-                name: 'bar',
-                browser: './main2',
-              }),
-              'main2.js': 'bar 2 module',
-            },
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['foo', 'bar'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'foo/main.js',
-              path: '/root/node_modules/foo/main.js',
-              dependencies: ['bar/lol'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'bar/lol.js',
-              path: '/root/node_modules/foo/node_modules/bar/lol.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'bar/main2.js',
-              path: '/root/node_modules/bar/main2.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('node_modules should support multi level', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("bar");',
-          ].join('\n'),
-          'node_modules': {
-            'foo': {
-              'package.json': JSON.stringify({
-                name: 'foo',
-                main: 'main.js',
-              }),
-              'main.js': '',
-            },
-          },
-          'path': {
-            'to': {
-              'bar.js': [
-                '/**',
-                ' * @providesModule bar',
-                ' */',
-                'require("foo")',
-              ].join('\n'),
-            },
-            'node_modules': {},
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['bar'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'bar',
-              path: '/root/path/to/bar.js',
-              dependencies: ['foo'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'foo/main.js',
-              path: '/root/node_modules/foo/main.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should selectively ignore providesModule in node_modules', function() {
-      var root = '/root';
-      var otherRoot = '/anotherRoot';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("shouldWork");',
-            'require("dontWork");',
-            'require("wontWork");',
-            'require("ember");',
-            'require("internalVendoredPackage");',
-            'require("anotherIndex");',
-          ].join('\n'),
-          'node_modules': {
-            'react-haste': {
-              'package.json': JSON.stringify({
-                name: 'react-haste',
-                main: 'main.js',
-              }),
-              // @providesModule should not be ignored here, because react-haste is whitelisted
-              'main.js': [
-                '/**',
-                ' * @providesModule shouldWork',
-                ' */',
-                'require("submodule");',
-              ].join('\n'),
-              'node_modules': {
-                'bar': {
-                  'package.json': JSON.stringify({
-                    name: 'bar',
-                    main: 'main.js',
-                  }),
-                  // @providesModule should be ignored here, because it's not whitelisted
-                  'main.js':[
-                    '/**',
-                    ' * @providesModule dontWork',
-                    ' */',
-                    'hi();',
-                  ].join('\n'),
-                },
-                'submodule': {
-                  'package.json': JSON.stringify({
-                    name: 'submodule',
-                    main: 'main.js',
-                  }),
-                  'main.js': 'log()',
-                },
-              },
-            },
-            'ember': {
-              'package.json': JSON.stringify({
-                name: 'ember',
-                main: 'main.js',
-              }),
-              // @providesModule should be ignored here, because it's not whitelisted,
-              // and also, the modules "id" should be ember/main.js, not it's haste name
-              'main.js':[
-                '/**',
-                ' * @providesModule wontWork',
-                ' */',
-                'hi();',
-              ].join('\n'),
-            },
-          },
-          // This part of the dep graph is meant to emulate internal facebook infra.
-          // By whitelisting `vendored_modules`, haste should still work.
-          'vendored_modules': {
-            'a-vendored-package': {
-              'package.json': JSON.stringify({
-                name: 'a-vendored-package',
-                main: 'main.js',
-              }),
-              // @providesModule should _not_ be ignored here, because it's whitelisted.
-              'main.js':[
-                '/**',
-                ' * @providesModule internalVendoredPackage',
-                ' */',
-                'hiFromInternalPackage();',
-              ].join('\n'),
-            },
-          },
-        },
-        // we need to support multiple roots and using haste between them
-        'anotherRoot': {
-          'index.js': [
-            '/**',
-            ' * @providesModule anotherIndex',
-            ' */',
-            'wazup()',
-          ].join('\n'),
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root, otherRoot],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: [
-                'shouldWork',
-                'dontWork',
-                'wontWork',
-                'ember',
-                'internalVendoredPackage',
-                'anotherIndex',
-              ],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'shouldWork',
-              path: '/root/node_modules/react-haste/main.js',
-              dependencies: ['submodule'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'submodule/main.js',
-              path: '/root/node_modules/react-haste/node_modules/submodule/main.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'ember/main.js',
-              path: '/root/node_modules/ember/main.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'internalVendoredPackage',
-              path: '/root/vendored_modules/a-vendored-package/main.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'anotherIndex',
-              path: '/anotherRoot/index.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should not be confused by prev occuring whitelisted names', function() {
-      var root = '/react-haste';
-      fs.__setMockFilesystem({
-        'react-haste': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("shouldWork");',
-          ].join('\n'),
-          'node_modules': {
-            'react-haste': {
-              'package.json': JSON.stringify({
-                name: 'react-haste',
-                main: 'main.js',
-              }),
-              'main.js': [
-                '/**',
-                ' * @providesModule shouldWork',
-                ' */',
-              ].join('\n'),
-            },
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/react-haste/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/react-haste/index.js',
-              dependencies: ['shouldWork'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'shouldWork',
-              path: '/react-haste/node_modules/react-haste/main.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-
-    pit('should ignore modules it cant find (assumes own require system)', function() {
-      // For example SourceMap.js implements it's own require system.
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("foo/lol");',
-          ].join('\n'),
-          'node_modules': {
-            'foo': {
-              'package.json': JSON.stringify({
-                name: 'foo',
-                main: 'main.js',
-              }),
-              'main.js': 'foo module',
-            },
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['foo/lol'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should work with node packages with a .js in the name', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("sha.js")',
-          ].join('\n'),
-          'node_modules': {
-            'sha.js': {
-              'package.json': JSON.stringify({
-                name: 'sha.js',
-                main: 'main.js',
-              }),
-              'main.js': 'lol',
-            },
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['sha.js'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'sha.js/main.js',
-              path: '/root/node_modules/sha.js/main.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should work with multiple platforms (haste)', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.ios.js': `
-            /**
-             * @providesModule index
-             */
-             require('a');
-          `,
-          'a.ios.js': `
-            /**
-             * @providesModule a
-             */
-          `,
-          'a.android.js': `
-            /**
-             * @providesModule a
-             */
-          `,
-          'a.js': `
-            /**
-             * @providesModule a
-             */
-          `,
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.ios.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.ios.js',
-              dependencies: ['a'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'a',
-              path: '/root/a.ios.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should pick the generic file', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.ios.js': `
-            /**
-             * @providesModule index
-             */
-             require('a');
-          `,
-          'a.android.js': `
-            /**
-             * @providesModule a
-             */
-          `,
-          'a.js': `
-            /**
-             * @providesModule a
-             */
-          `,
-          'a.web.js': `
-            /**
-             * @providesModule a
-             */
-          `,
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.ios.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.ios.js',
-              dependencies: ['a'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'a',
-              path: '/root/a.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should work with multiple platforms (node)', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.ios.js': `
-            /**
-             * @providesModule index
-             */
-             require('./a');
-          `,
-          'a.ios.js': '',
-          'a.android.js': '',
-          'a.js': '',
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.ios.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.ios.js',
-              dependencies: ['./a'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: '/root/a.ios.js',
-              path: '/root/a.ios.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-          ]);
-      });
-    });
-
-    pit('should require package.json', () => {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("foo/package.json");',
-            'require("bar");',
-          ].join('\n'),
-          'node_modules': {
-            'foo': {
-              'package.json': JSON.stringify({
-                name: 'foo',
-                main: 'main.js',
-              }),
-            },
-            'bar': {
-              'package.json': JSON.stringify({
-                name: 'bar',
-                main: 'main.js',
-              }),
-              'main.js': 'require("./package.json")',
-            },
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(deps => {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['foo/package.json', 'bar'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'foo/package.json',
-              path: '/root/node_modules/foo/package.json',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: true,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'bar/main.js',
-              path: '/root/node_modules/bar/main.js',
-              dependencies: ['./package.json'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-            {
-              id: 'bar/package.json',
-              path: '/root/node_modules/bar/package.json',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: true,
-              isPolyfill: false,
-              resolution: undefined,
-            },
-
-          ]);
-      });
-    });
-  });
-
-  describe('file watch updating', function() {
-    var triggerFileChange;
-    var mockStat = {
-      isDirectory: () => false,
-    };
-
-    beforeEach(function() {
-      var callbacks = [];
-      triggerFileChange = (...args) =>
-        callbacks.map(callback => callback(...args));
-
-      defaults.fileWatcher = {
-        on: function(eventType, callback) {
-          if (eventType !== 'all') {
-            throw new Error('Can only handle "all" event in watcher.');
-          }
-          callbacks.push(callback);
-          return this;
-        },
-        isWatchman: () => Promise.resolve(false),
-      };
-    });
-
-    pit('updates module dependencies', function() {
-      var root = '/root';
-      var filesystem = fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("aPackage")',
-            'require("foo")',
-          ].join('\n'),
-          'foo': [
-            '/**',
-            ' * @providesModule foo',
-            ' */',
-            'require("aPackage")',
-          ].join('\n'),
-          'aPackage': {
-            'package.json': JSON.stringify({
-              name: 'aPackage',
-              main: 'main.js',
-            }),
-            'main.js': 'main',
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function() {
-        filesystem.root['index.js'] =
-          filesystem.root['index.js'].replace('require("foo")', '');
-        triggerFileChange('change', 'index.js', root, mockStat);
-        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-          expect(deps)
-            .toEqual([
-              {
-                id: 'index',
-                path: '/root/index.js',
-                dependencies: ['aPackage'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-              {
-                id: 'aPackage/main.js',
-                path: '/root/aPackage/main.js',
-                dependencies: [],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-            ]);
-        });
-      });
-    });
-
-    pit('updates module dependencies on file change', function() {
-      var root = '/root';
-      var filesystem = fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("aPackage")',
-            'require("foo")',
-          ].join('\n'),
-          'foo.js': [
-            '/**',
-            ' * @providesModule foo',
-            ' */',
-            'require("aPackage")',
-          ].join('\n'),
-          'aPackage': {
-            'package.json': JSON.stringify({
-              name: 'aPackage',
-              main: 'main.js',
-            }),
-            'main.js': 'main',
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function() {
-        filesystem.root['index.js'] =
-          filesystem.root['index.js'].replace('require("foo")', '');
-        triggerFileChange('change', 'index.js', root, mockStat);
-        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-          expect(deps)
-            .toEqual([
-              {
-                id: 'index',
-                path: '/root/index.js',
-                dependencies: ['aPackage'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-              {
-                id: 'aPackage/main.js',
-                path: '/root/aPackage/main.js',
-                dependencies: [],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-            ]);
-        });
-      });
-    });
-
-    pit('updates module dependencies on file delete', function() {
-      var root = '/root';
-      var filesystem = fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("aPackage")',
-            'require("foo")',
-          ].join('\n'),
-          'foo.js': [
-            '/**',
-            ' * @providesModule foo',
-            ' */',
-            'require("aPackage")',
-          ].join('\n'),
-          'aPackage': {
-            'package.json': JSON.stringify({
-              name: 'aPackage',
-              main: 'main.js',
-            }),
-            'main.js': 'main',
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function() {
-        delete filesystem.root.foo;
-        triggerFileChange('delete', 'foo.js', root);
-        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-          expect(deps)
-            .toEqual([
-              {
-                id: 'index',
-                path: '/root/index.js',
-                dependencies: ['aPackage', 'foo'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-              {
-                id: 'aPackage/main.js',
-                path: '/root/aPackage/main.js',
-                dependencies: [],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-            ]);
-        });
-      });
-    });
-
-    pit('updates module dependencies on file add', function() {
-      var root = '/root';
-      var filesystem = fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("aPackage")',
-            'require("foo")',
-          ].join('\n'),
-          'foo.js': [
-            '/**',
-            ' * @providesModule foo',
-            ' */',
-            'require("aPackage")',
-          ].join('\n'),
-          'aPackage': {
-            'package.json': JSON.stringify({
-              name: 'aPackage',
-              main: 'main.js',
-            }),
-            'main.js': 'main',
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function() {
-        filesystem.root['bar.js'] = [
-          '/**',
-          ' * @providesModule bar',
-          ' */',
-          'require("foo")',
-        ].join('\n');
-        triggerFileChange('add', 'bar.js', root, mockStat);
-
-        filesystem.root.aPackage['main.js'] = 'require("bar")';
-        triggerFileChange('change', 'aPackage/main.js', root, mockStat);
-
-        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-          expect(deps)
-            .toEqual([
-              {
-                id: 'index',
-                path: '/root/index.js',
-                dependencies: ['aPackage', 'foo'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-              {
-                id: 'aPackage/main.js',
-                path: '/root/aPackage/main.js',
-                dependencies: ['bar'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-              },
-              {
-                id: 'bar',
-                path: '/root/bar.js',
-                dependencies: ['foo'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-              {
-                id: 'foo',
-                path: '/root/foo.js',
-                dependencies: ['aPackage'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-            ]);
-        });
-      });
-    });
-
-    pit('updates module dependencies on deprecated asset add', function() {
-      var root = '/root';
-      var filesystem = fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("image!foo")',
-          ].join('\n'),
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-        assetRoots_DEPRECATED: [root],
-        assetExts: ['png'],
-      });
-
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['image!foo'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-              resolveDependency: undefined,
-            },
-          ]);
-
-        filesystem.root['foo.png'] = '';
-        triggerFileChange('add', 'foo.png', root, mockStat);
-
-        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps2) {
-          expect(deps2)
-            .toEqual([
-              {
-                id: 'index',
-                path: '/root/index.js',
-                dependencies: ['image!foo'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-              {
-                id: 'image!foo',
-                path: '/root/foo.png',
-                dependencies: [],
-                isAsset_DEPRECATED: true,
-                resolution: 1,
-                isAsset: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolveDependency: undefined,
-              },
-            ]);
-        });
-      });
-    });
-
-    pit('updates module dependencies on relative asset add', function() {
-      var root = '/root';
-      var filesystem = fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("./foo.png")',
-          ].join('\n'),
-          'package.json': JSON.stringify({
-            name: 'aPackage',
-          }),
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-        assetExts: ['png'],
-      });
-
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            { id: 'index',
-              path: '/root/index.js',
-              dependencies: ['./foo.png'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-              resolveDependency: undefined,
-            },
-          ]);
-
-        filesystem.root['foo.png'] = '';
-        triggerFileChange('add', 'foo.png', root, mockStat);
-
-        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps2) {
-          expect(deps2)
-            .toEqual([
-              {
-                id: 'index',
-                path: '/root/index.js',
-                dependencies: ['./foo.png'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-              {
-                id: 'aPackage/foo.png',
-                path: '/root/foo.png',
-                dependencies: [],
-                isAsset: true,
-                resolution: 1,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolveDependency: undefined,
-              },
-            ]);
-        });
-      });
-    });
-
-    pit('runs changes through ignore filter', function() {
-      var root = '/root';
-      var filesystem = fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("aPackage")',
-            'require("foo")',
-          ].join('\n'),
-          'foo.js': [
-            '/**',
-            ' * @providesModule foo',
-            ' */',
-            'require("aPackage")',
-          ].join('\n'),
-          'aPackage': {
-            'package.json': JSON.stringify({
-              name: 'aPackage',
-              main: 'main.js',
-            }),
-            'main.js': 'main',
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-        ignoreFilePath: function(filePath) {
-          if (filePath === '/root/bar.js') {
-            return true;
-          }
-          return false;
-        },
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function() {
-        filesystem.root['bar.js'] = [
-          '/**',
-          ' * @providesModule bar',
-          ' */',
-          'require("foo")',
-        ].join('\n');
-        triggerFileChange('add', 'bar.js', root, mockStat);
-
-        filesystem.root.aPackage['main.js'] = 'require("bar")';
-        triggerFileChange('change', 'aPackage/main.js', root, mockStat);
-
-        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-          expect(deps)
-            .toEqual([
-              {
-                id: 'index',
-                path: '/root/index.js',
-                dependencies: ['aPackage', 'foo'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-              {
-                id: 'aPackage/main.js',
-                path: '/root/aPackage/main.js',
-                dependencies: ['bar'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-              {
-                id: 'foo',
-                path: '/root/foo.js',
-                dependencies: ['aPackage'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-            ]);
-        });
-      });
-    });
-
-    pit('should ignore directory updates', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("aPackage")',
-            'require("foo")',
-          ].join('\n'),
-          'foo.js': [
-            '/**',
-            ' * @providesModule foo',
-            ' */',
-            'require("aPackage")',
-          ].join('\n'),
-          'aPackage': {
-            'package.json': JSON.stringify({
-              name: 'aPackage',
-              main: 'main.js',
-            }),
-            'main.js': 'main',
-          },
-        },
-      });
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function() {
-        triggerFileChange('change', 'aPackage', '/root', {
-          isDirectory: () => true,
-        });
-        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-          expect(deps)
-            .toEqual([
-              {
-                id: 'index',
-                path: '/root/index.js',
-                dependencies: ['aPackage', 'foo'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-              {
-                id: 'aPackage/main.js',
-                path: '/root/aPackage/main.js',
-                dependencies: [],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-              {
-                id: 'foo',
-                path: '/root/foo.js',
-                dependencies: ['aPackage'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-            ]);
-        });
-      });
-    });
-
-    pit('changes to browser field', function() {
-      var root = '/root';
-      var filesystem = fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("aPackage")',
-          ].join('\n'),
-          'aPackage': {
-            'package.json': JSON.stringify({
-              name: 'aPackage',
-              main: 'main.js',
-            }),
-            'main.js': 'main',
-            'browser.js': 'browser',
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function() {
-        filesystem.root.aPackage['package.json'] = JSON.stringify({
-          name: 'aPackage',
-          main: 'main.js',
-          browser: 'browser.js',
-        });
-        triggerFileChange('change', 'package.json', '/root/aPackage', mockStat);
-
-        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-          expect(deps)
-            .toEqual([
-              {
-                id: 'index',
-                path: '/root/index.js',
-                dependencies: ['aPackage'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-              {
-                id: 'aPackage/browser.js',
-                path: '/root/aPackage/browser.js',
-                dependencies: [],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-            ]);
-        });
-      });
-    });
-
-    pit('removes old package from cache', function() {
-      var root = '/root';
-      var filesystem = fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("aPackage")',
-          ].join('\n'),
-          'aPackage': {
-            'package.json': JSON.stringify({
-              name: 'aPackage',
-              main: 'main.js',
-            }),
-            'main.js': 'main',
-            'browser.js': 'browser',
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function() {
-        filesystem.root.aPackage['package.json'] = JSON.stringify({
-          name: 'bPackage',
-          main: 'main.js',
-        });
-        triggerFileChange('change', 'package.json', '/root/aPackage', mockStat);
-
-        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-          expect(deps)
-            .toEqual([
-              {
-                id: 'index',
-                path: '/root/index.js',
-                dependencies: ['aPackage'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-            ]);
-        });
-      });
-    });
-
-    pit('should update node package changes', function() {
-      var root = '/root';
-      var filesystem = fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("foo");',
-          ].join('\n'),
-          'node_modules': {
-            'foo': {
-              'package.json': JSON.stringify({
-                name: 'foo',
-                main: 'main.js',
-              }),
-              'main.js': 'require("bar");\nfoo module',
-              'node_modules': {
-                'bar': {
-                  'package.json': JSON.stringify({
-                    name: 'bar',
-                    main: 'main.js',
-                  }),
-                  'main.js': 'bar 1 module',
-                },
-              },
-            },
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        expect(deps)
-          .toEqual([
-            {
-              id: 'index',
-              path: '/root/index.js',
-              dependencies: ['foo'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-              resolveDependency: undefined,
-            },
-            {
-              id: 'foo/main.js',
-              path: '/root/node_modules/foo/main.js',
-              dependencies: ['bar'],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-              resolveDependency: undefined,
-            },
-            {
-              id: 'bar/main.js',
-              path: '/root/node_modules/foo/node_modules/bar/main.js',
-              dependencies: [],
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              resolution: undefined,
-              resolveDependency: undefined,
-            },
-          ]);
-
-        filesystem.root.node_modules.foo['main.js'] = 'lol';
-        triggerFileChange('change', 'main.js', '/root/node_modules/foo', mockStat);
-
-        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps2) {
-          expect(deps2)
-            .toEqual([
-              {
-                id: 'index',
-                path: '/root/index.js',
-                dependencies: ['foo'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-              {
-                id: 'foo/main.js',
-                path: '/root/node_modules/foo/main.js',
-                dependencies: [],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-            ]);
-        });
-      });
-    });
-
-    pit('should update node package main changes', function() {
-      var root = '/root';
-      var filesystem = fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("foo");',
-          ].join('\n'),
-          'node_modules': {
-            'foo': {
-              'package.json': JSON.stringify({
-                name: 'foo',
-                main: 'main.js',
-              }),
-              'main.js': 'foo module',
-              'browser.js': 'foo module',
-            },
-          },
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
-        filesystem.root.node_modules.foo['package.json'] = JSON.stringify({
-          name: 'foo',
-          main: 'main.js',
-          browser: 'browser.js',
-        });
-        triggerFileChange('change', 'package.json', '/root/node_modules/foo', mockStat);
-
-        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps2) {
-          expect(deps2)
-            .toEqual([
-              {
-                id: 'index',
-                path: '/root/index.js',
-                dependencies: ['foo'],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-              {
-                id: 'foo/browser.js',
-                path: '/root/node_modules/foo/browser.js',
-                dependencies: [],
-                isAsset: false,
-                isAsset_DEPRECATED: false,
-                isJSON: false,
-                isPolyfill: false,
-                resolution: undefined,
-                resolveDependency: undefined,
-              },
-            ]);
-        });
-      });
-    });
-
-    pit('should not error when the watcher reports a known file as added', function() {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.js': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'var b = require("b");',
-          ].join('\n'),
-          'b.js': [
-            '/**',
-            ' * @providesModule b',
-            ' */',
-            'module.exports = function() {};',
-          ].join('\n'),
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-
-      return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function() {
-        triggerFileChange('add', 'index.js', root, mockStat);
-        return getOrderedDependenciesAsJSON(dgraph, '/root/index.js');
-      });
-    });
-  });
-
-  describe('Extensions', () => {
-    pit('supports custom file extensions', () => {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          'index.jsx': [
-            '/**',
-            ' * @providesModule index',
-            ' */',
-            'require("a")',
-          ].join('\n'),
-          'a.coffee': [
-            '/**',
-            ' * @providesModule a',
-            ' */',
-          ].join('\n'),
-          'X.js': '',
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-        extensions: ['jsx', 'coffee'],
-      });
-
-      return dgraph.matchFilesByPattern('.*')
-        .then(files => {
-          expect(files).toEqual([
-            '/root/index.jsx', '/root/a.coffee',
-          ]);
-        })
-        .then(() => getOrderedDependenciesAsJSON(dgraph, '/root/index.jsx'))
-        .then(deps => {
-          expect(deps).toEqual([
-            {
-              dependencies: ['a'],
-              id: 'index',
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              path: '/root/index.jsx',
-              resolution: undefined,
-            },
-            {
-              dependencies: [],
-              id: 'a',
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isJSON: false,
-              isPolyfill: false,
-              path: '/root/a.coffee',
-              resolution: undefined,
-            },
-          ]);
-        });
-    });
-  });
-
-  describe('Mocks', () => {
-    pit('resolves to null if mocksPattern is not specified', () => {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          '__mocks__': {
-            'A.js': '',
-          },
-          'index.js': '',
-        },
-      });
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-      });
-
-      return dgraph.getDependencies('/root/index.js')
-        .then(response => response.finalize())
-        .then(response => {
-          expect(response.mocks).toEqual({});
-        });
-    });
-
-    pit('retrieves a list of all required mocks', () => {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          '__mocks__': {
-            'A.js': '',
-            'b.js': '',
-          },
-          'b.js': [
-            '/**',
-            ' * @providesModule b',
-            ' */',
-            'require("A");',
-          ].join('\n'),
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-        mocksPattern,
-      });
-
-      return dgraph.getDependencies('/root/b.js')
-        .then(response => response.finalize())
-        .then(response => {
-          expect(response.mocks).toEqual({
-            A: '/root/__mocks__/A.js',
-            b: '/root/__mocks__/b.js',
-          });
-        });
-    });
-
-    pit('adds mocks as a dependency of their actual module', () => {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          '__mocks__': {
-            'A.js': [
-              'require("b");',
-            ].join('\n'),
-            'b.js': '',
-          },
-          'A.js': [
-            '/**',
-            ' * @providesModule A',
-            ' */',
-            'require("foo");',
-          ].join('\n'),
-          'foo.js': [
-            '/**',
-            ' * @providesModule foo',
-            ' */',
-          ].join('\n'),
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-        mocksPattern,
-      });
-
-      return getOrderedDependenciesAsJSON(dgraph, '/root/A.js')
-        .then(deps => {
-          expect(deps).toEqual([
-            {
-              path: '/root/A.js',
-              isJSON: false,
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isPolyfill: false,
-              id: 'A',
-              dependencies: ['foo', 'A'],
-            },
-            {
-              path: '/root/foo.js',
-              isJSON: false,
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isPolyfill: false,
-              id: 'foo',
-              dependencies: [],
-            },
-            {
-              path: '/root/__mocks__/A.js',
-              isJSON: false,
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isPolyfill: false,
-              id: '/root/__mocks__/A.js',
-              dependencies: ['b'],
-            },
-            {
-              path: '/root/__mocks__/b.js',
-              isJSON: false,
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isPolyfill: false,
-              id: '/root/__mocks__/b.js',
-              dependencies: [],
-            },
-          ]);
-        });
-    });
-
-    pit('resolves mocks that do not have a real module associated with them', () => {
-      var root = '/root';
-      fs.__setMockFilesystem({
-        'root': {
-          '__mocks__': {
-            'foo.js': [
-              'require("b");',
-            ].join('\n'),
-            'b.js': '',
-          },
-          'A.js': [
-            '/**',
-            ' * @providesModule A',
-            ' */',
-            'require("foo");',
-          ].join('\n'),
-        },
-      });
-
-      var dgraph = new DependencyGraph({
-        ...defaults,
-        roots: [root],
-        mocksPattern,
-      });
-
-      return getOrderedDependenciesAsJSON(dgraph, '/root/A.js')
-        .then(deps => {
-          expect(deps).toEqual([
-            {
-              path: '/root/A.js',
-              isJSON: false,
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isPolyfill: false,
-              id: 'A',
-              dependencies: ['foo'],
-            },
-            {
-              path: '/root/__mocks__/foo.js',
-              isJSON: false,
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isPolyfill: false,
-              id: '/root/__mocks__/foo.js',
-              dependencies: ['b'],
-            },
-            {
-              path: '/root/__mocks__/b.js',
-              isJSON: false,
-              isAsset: false,
-              isAsset_DEPRECATED: false,
-              isPolyfill: false,
-              id: '/root/__mocks__/b.js',
-              dependencies: [],
-            },
-          ]);
-        });
-    });
-  });
-});
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/docblock.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/docblock.js
deleted file mode 100644
index d710112a9587..000000000000
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/docblock.js
+++ /dev/null
@@ -1,83 +0,0 @@
-/**
- * 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.
- */
-
-'use strict';
-
-var docblockRe = /^\s*(\/\*\*(.|\r?\n)*?\*\/)/;
-
-var ltrimRe = /^\s*/;
-/**
- * @param {String} contents
- * @return {String}
- */
-function extract(contents) {
-  var match = contents.match(docblockRe);
-  if (match) {
-    return match[0].replace(ltrimRe, '') || '';
-  }
-  return '';
-}
-
-
-var commentStartRe = /^\/\*\*/;
-var commentEndRe = /\*\/$/;
-var wsRe = /[\t ]+/g;
-var stringStartRe = /(\r?\n|^) *\*/g;
-var multilineRe =
-      /(?:^|\r?\n) *(@[^\r\n]*?) *\r?\n *([^@\r\n\s][^@\r\n]+?) *\r?\n/g;
-var propertyRe = /(?:^|\r?\n) *@(\S+) *([^\r\n]*)/g;
-
-/**
- * @param {String} contents
- * @return {Array}
- */
-function parse(docblock) {
-  docblock = docblock
-    .replace(commentStartRe, '')
-    .replace(commentEndRe, '')
-    .replace(wsRe, ' ')
-    .replace(stringStartRe, '$1');
-
-  // Normalize multi-line directives
-  var prev = '';
-  while (prev !== docblock) {
-    prev = docblock;
-    docblock = docblock.replace(multilineRe, '\n$1 $2\n');
-  }
-  docblock = docblock.trim();
-
-  var result = [];
-  var match;
-  while ((match = propertyRe.exec(docblock))) {
-    result.push([match[1], match[2]]);
-  }
-
-  return result;
-}
-
-/**
- * Same as parse but returns an object of prop: value instead of array of paris
- * If a property appers more than once the last one will be returned
- *
- * @param {String} contents
- * @return {Object}
- */
-function parseAsObject(docblock) {
-  var pairs = parse(docblock);
-  var result = {};
-  for (var i = 0; i < pairs.length; i++) {
-    result[pairs[i][0]] = pairs[i][1];
-  }
-  return result;
-}
-
-
-exports.extract = extract;
-exports.parse = parse;
-exports.parseAsObject = parseAsObject;
diff --git a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js b/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
deleted file mode 100644
index b3a987b1f79c..000000000000
--- a/packager/react-packager/src/DependencyResolver/DependencyGraph/index.js
+++ /dev/null
@@ -1,287 +0,0 @@
- /**
- * 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.
- */
-'use strict';
-
-const Fastfs = require('../fastfs');
-const ModuleCache = require('../ModuleCache');
-const Promise = require('promise');
-const crawl = require('../crawlers');
-const getPlatformExtension = require('../lib/getPlatformExtension');
-const isAbsolutePath = require('absolute-path');
-const path = require('fast-path');
-const util = require('util');
-const DependencyGraphHelpers = require('./DependencyGraphHelpers');
-const ResolutionRequest = require('./ResolutionRequest');
-const ResolutionResponse = require('./ResolutionResponse');
-const HasteMap = require('./HasteMap');
-const DeprecatedAssetMap = require('./DeprecatedAssetMap');
-
-const ERROR_BUILDING_DEP_GRAPH = 'DependencyGraphError';
-
-const defaultActivity = {
-  startEvent: () => {},
-  endEvent: () => {},
-};
-
-class DependencyGraph {
-  constructor({
-    activity,
-    roots,
-    ignoreFilePath,
-    fileWatcher,
-    assetRoots_DEPRECATED,
-    assetExts,
-    providesModuleNodeModules,
-    platforms,
-    preferNativePlatform,
-    cache,
-    extensions,
-    mocksPattern,
-    extractRequires,
-    transformCode,
-    shouldThrowOnUnresolvedErrors = () => true,
-    enableAssetMap,
-  }) {
-    this._opts = {
-      activity: activity || defaultActivity,
-      roots,
-      ignoreFilePath: ignoreFilePath || (() => {}),
-      fileWatcher,
-      assetRoots_DEPRECATED: assetRoots_DEPRECATED || [],
-      assetExts: assetExts || [],
-      providesModuleNodeModules,
-      platforms: platforms || [],
-      preferNativePlatform: preferNativePlatform || false,
-      extensions: extensions || ['js', 'json'],
-      mocksPattern,
-      extractRequires,
-      transformCode,
-      shouldThrowOnUnresolvedErrors,
-      enableAssetMap: enableAssetMap || true,
-    };
-    this._cache = cache;
-    this._helpers = new DependencyGraphHelpers(this._opts);
-    this.load();
-  }
-
-  load() {
-    if (this._loading) {
-      return this._loading;
-    }
-
-    const {activity} = this._opts;
-    const depGraphActivity = activity.startEvent('Building Dependency Graph');
-    const crawlActivity = activity.startEvent('Crawling File System');
-    const allRoots = this._opts.roots.concat(this._opts.assetRoots_DEPRECATED);
-    this._crawling = crawl(allRoots, {
-      ignore: this._opts.ignoreFilePath,
-      exts: this._opts.extensions.concat(this._opts.assetExts),
-      fileWatcher: this._opts.fileWatcher,
-    });
-    this._crawling.then((files) => activity.endEvent(crawlActivity));
-
-    this._fastfs = new Fastfs(
-      'JavaScript',
-      this._opts.roots,
-      this._opts.fileWatcher,
-      {
-        ignore: this._opts.ignoreFilePath,
-        crawling: this._crawling,
-        activity: activity,
-      }
-    );
-
-    this._fastfs.on('change', this._processFileChange.bind(this));
-
-    this._moduleCache = new ModuleCache({
-      fastfs: this._fastfs,
-      cache: this._cache,
-      extractRequires: this._opts.extractRequires,
-      transformCode: this._opts.transformCode,
-      depGraphHelpers: this._helpers,
-    });
-
-    this._hasteMap = new HasteMap({
-      fastfs: this._fastfs,
-      extensions: this._opts.extensions,
-      moduleCache: this._moduleCache,
-      preferNativePlatform: this._opts.preferNativePlatform,
-      helpers: this._helpers,
-    });
-
-    this._deprecatedAssetMap = new DeprecatedAssetMap({
-      fsCrawl: this._crawling,
-      roots: this._opts.assetRoots_DEPRECATED,
-      helpers: this._helpers,
-      fileWatcher: this._opts.fileWatcher,
-      ignoreFilePath: this._opts.ignoreFilePath,
-      assetExts: this._opts.assetExts,
-      activity: this._opts.activity,
-      enabled: this._opts.enableAssetMap,
-    });
-
-    this._loading = Promise.all([
-      this._fastfs.build()
-        .then(() => {
-          const hasteActivity = activity.startEvent('Building Haste Map');
-          return this._hasteMap.build().then(map => {
-            activity.endEvent(hasteActivity);
-            return map;
-          });
-        }),
-      this._deprecatedAssetMap.build(),
-    ]).then(
-      response => {
-        activity.endEvent(depGraphActivity);
-        return response[0]; // Return the haste map
-      },
-      err => {
-        const error = new Error(
-          `Failed to build DependencyGraph: ${err.message}`
-        );
-        error.type = ERROR_BUILDING_DEP_GRAPH;
-        error.stack = err.stack;
-        throw error;
-      }
-    );
-
-    return this._loading;
-  }
-
-  /**
-   * Returns a promise with the direct dependencies the module associated to
-   * the given entryPath has.
-   */
-  getShallowDependencies(entryPath) {
-    return this._moduleCache.getModule(entryPath).getDependencies();
-  }
-
-  getFS() {
-    return this._fastfs;
-  }
-
-  /**
-   * Returns the module object for the given path.
-   */
-  getModuleForPath(entryFile) {
-    return this._moduleCache.getModule(entryFile);
-  }
-
-  getAllModules() {
-    return this.load().then(() => this._moduleCache.getAllModules());
-  }
-
-  getDependencies(entryPath, platform, recursive = true) {
-    return this.load().then(() => {
-      platform = this._getRequestPlatform(entryPath, platform);
-      const absPath = this._getAbsolutePath(entryPath);
-      const req = new ResolutionRequest({
-        platform,
-        preferNativePlatform: this._opts.preferNativePlatform,
-        entryPath: absPath,
-        deprecatedAssetMap: this._deprecatedAssetMap,
-        hasteMap: this._hasteMap,
-        helpers: this._helpers,
-        moduleCache: this._moduleCache,
-        fastfs: this._fastfs,
-        shouldThrowOnUnresolvedErrors: this._opts.shouldThrowOnUnresolvedErrors,
-      });
-
-      const response = new ResolutionResponse();
-
-      return req.getOrderedDependencies(
-        response,
-        this._opts.mocksPattern,
-        recursive,
-      ).then(() => response);
-    });
-  }
-
-  matchFilesByPattern(pattern) {
-    return this.load().then(() => this._fastfs.matchFilesByPattern(pattern));
-  }
-
-  _getRequestPlatform(entryPath, platform) {
-    if (platform == null) {
-      platform = getPlatformExtension(entryPath);
-      if (platform == null || this._opts.platforms.indexOf(platform) === -1) {
-        platform = null;
-      }
-    } else if (this._opts.platforms.indexOf(platform) === -1) {
-      throw new Error('Unrecognized platform: ' + platform);
-    }
-    return platform;
-  }
-
-  _getAbsolutePath(filePath) {
-    if (isAbsolutePath(filePath)) {
-      return path.resolve(filePath);
-    }
-
-    for (let i = 0; i < this._opts.roots.length; i++) {
-      const root = this._opts.roots[i];
-      const potentialAbsPath = path.join(root, filePath);
-      if (this._fastfs.fileExists(potentialAbsPath)) {
-        return path.resolve(potentialAbsPath);
-      }
-    }
-
-    throw new NotFoundError(
-      'Cannot find entry file %s in any of the roots: %j',
-      filePath,
-      this._opts.roots
-    );
-  }
-
-  _processFileChange(type, filePath, root, fstat) {
-    const absPath = path.join(root, filePath);
-    if (fstat && fstat.isDirectory() ||
-        this._opts.ignoreFilePath(absPath) ||
-        this._helpers.isNodeModulesDir(absPath)) {
-      return;
-    }
-
-    // Ok, this is some tricky promise code. Our requirements are:
-    // * we need to report back failures
-    // * failures shouldn't block recovery
-    // * Errors can leave `hasteMap` in an incorrect state, and we need to rebuild
-    // After we process a file change we record any errors which will also be
-    // reported via the next request. On the next file change, we'll see that
-    // we are in an error state and we should decide to do a full rebuild.
-    this._loading = this._loading.finally(() => {
-      if (this._hasteMapError) {
-        console.warn(
-          'Rebuilding haste map to recover from error:\n' +
-          this._hasteMapError.stack
-        );
-        this._hasteMapError = null;
-
-        // Rebuild the entire map if last change resulted in an error.
-        this._loading = this._hasteMap.build();
-      } else {
-        this._loading = this._hasteMap.processFileChange(type, absPath);
-        this._loading.catch((e) => this._hasteMapError = e);
-      }
-      return this._loading;
-    });
-  }
-
-}
-
-function NotFoundError() {
-  Error.call(this);
-  Error.captureStackTrace(this, this.constructor);
-  var msg = util.format.apply(util, arguments);
-  this.message = msg;
-  this.type = this.name = 'NotFoundError';
-  this.status = 404;
-}
-util.inherits(NotFoundError, Error);
-
-module.exports = DependencyGraph;
diff --git a/packager/react-packager/src/DependencyResolver/FileWatcher/__mocks__/sane.js b/packager/react-packager/src/DependencyResolver/FileWatcher/__mocks__/sane.js
deleted file mode 100644
index f59fa9104eb2..000000000000
--- a/packager/react-packager/src/DependencyResolver/FileWatcher/__mocks__/sane.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-module.exports = {
-  WatchmanWatcher: jest.genMockFromModule('sane/src/watchman_watcher'),
-  NodeWatcher: jest.genMockFromModule('sane/src/node_watcher'),
-};
diff --git a/packager/react-packager/src/DependencyResolver/FileWatcher/__tests__/FileWatcher-test.js b/packager/react-packager/src/DependencyResolver/FileWatcher/__tests__/FileWatcher-test.js
deleted file mode 100644
index 650e510090ab..000000000000
--- a/packager/react-packager/src/DependencyResolver/FileWatcher/__tests__/FileWatcher-test.js
+++ /dev/null
@@ -1,89 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-jest
-  .dontMock('util')
-  .dontMock('events')
-  .dontMock('../')
-  .setMock('child_process', {
-    exec: (cmd, cb) => cb(null, '/usr/bin/watchman'),
-  });
-
-const sane = require('sane');
-
-describe('FileWatcher', () => {
-  let WatchmanWatcher;
-  let NodeWatcher;
-  let FileWatcher;
-  let config;
-
-  beforeEach(() => {
-    WatchmanWatcher = sane.WatchmanWatcher;
-    WatchmanWatcher.prototype.once.mockImplementation(
-      (type, callback) => callback()
-    );
-    NodeWatcher = sane.NodeWatcher;
-    NodeWatcher.prototype.once.mockImplementation(
-      (type, callback) => callback()
-    );
-
-    FileWatcher = require('../');
-
-    config = [{
-      dir: 'rootDir',
-      globs: [
-        '**/*.js',
-        '**/*.json',
-      ],
-    }];
-  });
-
-  pit('gets the watcher instance when ready', () => {
-    const fileWatcher = new FileWatcher(config, {useWatchman: true});
-    return fileWatcher.getWatchers().then(watchers => {
-      watchers.forEach(watcher => {
-        expect(watcher instanceof WatchmanWatcher).toBe(true);
-      });
-    });
-  });
-
-  pit('gets the node watcher if watchman is disabled', () => {
-    const fileWatcher = new FileWatcher(config, {useWatchman: false});
-    return fileWatcher.getWatchers().then(watchers => {
-      watchers.forEach(watcher => {
-        expect(watcher instanceof NodeWatcher).toBe(true);
-      });
-    });
-  });
-
-  pit('emits events', () => {
-    let cb;
-    WatchmanWatcher.prototype.on.mockImplementation((type, callback) => {
-      cb = callback;
-    });
-    const fileWatcher = new FileWatcher(config, {useWatchman: true});
-    const handler = jest.genMockFn();
-    fileWatcher.on('all', handler);
-    return fileWatcher.getWatchers().then(watchers => {
-      cb(1, 2, 3, 4);
-      jest.runAllTimers();
-      expect(handler.mock.calls[0]).toEqual([1, 2, 3, 4]);
-    });
-  });
-
-  pit('ends the watcher', () => {
-    const fileWatcher = new FileWatcher(config, {useWatchman: true});
-    WatchmanWatcher.prototype.close.mockImplementation(callback => callback());
-
-    return fileWatcher.end().then(() => {
-      expect(WatchmanWatcher.prototype.close).toBeCalled();
-    });
-  });
-});
diff --git a/packager/react-packager/src/DependencyResolver/FileWatcher/index.js b/packager/react-packager/src/DependencyResolver/FileWatcher/index.js
deleted file mode 100644
index ab548366bcb7..000000000000
--- a/packager/react-packager/src/DependencyResolver/FileWatcher/index.js
+++ /dev/null
@@ -1,128 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-const EventEmitter  = require('events').EventEmitter;
-const sane = require('sane');
-const Promise = require('promise');
-const exec = require('child_process').exec;
-
-const MAX_WAIT_TIME = 120000;
-
-// TODO(amasad): can we use watchman version command instead?
-const detectingWatcherClass = new Promise(function(resolve) {
-  exec('which watchman', function(err, out) {
-    if (err || out.length === 0) {
-      resolve(sane.NodeWatcher);
-    } else {
-      resolve(sane.WatchmanWatcher);
-    }
-  });
-});
-
-let inited = false;
-
-class FileWatcher extends EventEmitter {
-
-  constructor(rootConfigs, options) {
-    if (inited) {
-      throw new Error('FileWatcher can only be instantiated once');
-    }
-    inited = true;
-
-    super();
-    this._useWatchman = options.useWatchman;
-    this._watcherByRoot = Object.create(null);
-
-    this._loading = Promise.all(
-      rootConfigs.map(rootConfig => this._createWatcher(rootConfig))
-    ).then(watchers => {
-      watchers.forEach((watcher, i) => {
-        this._watcherByRoot[rootConfigs[i].dir] = watcher;
-        watcher.on(
-          'all',
-          // args = (type, filePath, root, stat)
-          (...args) => this.emit('all', ...args)
-        );
-      });
-      return watchers;
-    });
-
-    this._loading.done();
-  }
-
-  getWatchers() {
-    return this._loading;
-  }
-
-  getWatcherForRoot(root) {
-    return this._loading.then(() => this._watcherByRoot[root]);
-  }
-
-  isWatchman() {
-    return this._useWatchman ? detectingWatcherClass.then(
-      Watcher => Watcher === sane.WatchmanWatcher
-    ) : Promise.resolve(false);
-  }
-
-  end() {
-    inited = false;
-    return this._loading.then(
-      (watchers) => watchers.map(
-        watcher => Promise.denodeify(watcher.close).call(watcher)
-      )
-    );
-  }
-
-  _createWatcher(rootConfig) {
-    return detectingWatcherClass.then(Watcher => {
-      if (!this._useWatchman) {
-        Watcher = sane.NodeWatcher;
-      }
-      const watcher = new Watcher(rootConfig.dir, {
-        glob: rootConfig.globs,
-        dot: false,
-      });
-
-      return new Promise((resolve, reject) => {
-        const rejectTimeout = setTimeout(
-          () => reject(new Error(timeoutMessage(Watcher))),
-          MAX_WAIT_TIME
-        );
-
-        watcher.once('ready', () => {
-          clearTimeout(rejectTimeout);
-          resolve(watcher);
-        });
-      });
-    });
-  }
-
-  static createDummyWatcher() {
-    return Object.assign(new EventEmitter(), {
-      isWatchman: () => Promise.resolve(false),
-      end: () => Promise.resolve(),
-    });
-  }
-}
-
-function timeoutMessage(Watcher) {
-  const lines = [
-    'Watcher took too long to load (' + Watcher.name + ')',
-  ];
-  if (Watcher === sane.WatchmanWatcher) {
-    lines.push(
-      'Try running `watchman version` from your terminal',
-      'https://facebook.github.io/watchman/docs/troubleshooting.html',
-    );
-  }
-  return lines.join('\n');
-}
-
-module.exports = FileWatcher;
diff --git a/packager/react-packager/src/DependencyResolver/Module.js b/packager/react-packager/src/DependencyResolver/Module.js
deleted file mode 100644
index 6849c9220aa8..000000000000
--- a/packager/react-packager/src/DependencyResolver/Module.js
+++ /dev/null
@@ -1,226 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-const crypto = require('crypto');
-const docblock = require('./DependencyGraph/docblock');
-const isAbsolutePath = require('absolute-path');
-const jsonStableStringify = require('json-stable-stringify');
-const path = require('fast-path');
-const extractRequires = require('./lib/extractRequires');
-
-class Module {
-
-  constructor({
-    file,
-    fastfs,
-    moduleCache,
-    cache,
-    extractor = extractRequires,
-    transformCode,
-    depGraphHelpers,
-  }) {
-    if (!isAbsolutePath(file)) {
-      throw new Error('Expected file to be absolute path but got ' + file);
-    }
-
-    this.path = file;
-    this.type = 'Module';
-
-    this._fastfs = fastfs;
-    this._moduleCache = moduleCache;
-    this._cache = cache;
-    this._extractor = extractor;
-    this._transformCode = transformCode;
-    this._depGraphHelpers = depGraphHelpers;
-  }
-
-  isHaste() {
-    return this._cache.get(
-      this.path,
-      'isHaste',
-      () => this._readDocBlock().then(({id}) => !!id)
-    );
-  }
-
-  getCode(transformOptions) {
-    return this.read(transformOptions).then(({code}) => code);
-  }
-
-  getMap(transformOptions) {
-    return this.read(transformOptions).then(({map}) => map);
-  }
-
-  getName() {
-    return this._cache.get(
-      this.path,
-      'name',
-      () => this._readDocBlock().then(({id}) => {
-        if (id) {
-          return id;
-        }
-
-        const p = this.getPackage();
-
-        if (!p) {
-          // Name is full path
-          return this.path;
-        }
-
-        return p.getName()
-          .then(name => {
-            if (!name) {
-              return this.path;
-            }
-
-            return path.join(name, path.relative(p.root, this.path)).replace(/\\/g, '/');
-          });
-      })
-    );
-  }
-
-  getPackage() {
-    return this._moduleCache.getPackageForModule(this);
-  }
-
-  getDependencies(transformOptions) {
-    return this.read(transformOptions).then(data => data.dependencies);
-  }
-
-  invalidate() {
-    this._cache.invalidate(this.path);
-  }
-
-  _parseDocBlock(docBlock) {
-    // Extract an id for the module if it's using @providesModule syntax
-    // and if it's NOT in node_modules (and not a whitelisted node_module).
-    // This handles the case where a project may have a dep that has @providesModule
-    // docblock comments, but doesn't want it to conflict with whitelisted @providesModule
-    // modules, such as react-haste, fbjs-haste, or react-native or with non-dependency,
-    // project-specific code that is using @providesModule.
-    const moduleDocBlock = docblock.parseAsObject(docBlock);
-    const provides = moduleDocBlock.providesModule || moduleDocBlock.provides;
-
-    const id = provides && !this._depGraphHelpers.isNodeModulesDir(this.path)
-        ? /^\S+/.exec(provides)[0]
-        : undefined;
-    return {id, moduleDocBlock};
-  }
-
-  _readDocBlock(contentPromise) {
-    if (!this._docBlock) {
-      if (!contentPromise) {
-        contentPromise = this._fastfs.readWhile(this.path, whileInDocBlock);
-      }
-      this._docBlock = contentPromise
-        .then(docBlock => this._parseDocBlock(docBlock));
-    }
-    return this._docBlock;
-  }
-
-  read(transformOptions) {
-    return this._cache.get(
-      this.path,
-      cacheKey('moduleData', transformOptions),
-      () => {
-        const fileContentPromise = this._fastfs.readFile(this.path);
-        return Promise.all([
-          fileContentPromise,
-          this._readDocBlock(fileContentPromise),
-        ]).then(([code, {id, moduleDocBlock}]) => {
-          // Ignore requires in JSON files or generated code. An example of this
-          // is prebuilt files like the SourceMap library.
-          if (this.isJSON() || 'extern' in moduleDocBlock) {
-            return {id, code, dependencies: []};
-          } else {
-            const transformCode = this._transformCode;
-            const codePromise = transformCode
-                ? transformCode(this, code, transformOptions)
-                : Promise.resolve({code});
-
-            return codePromise.then(({code, dependencies, map}) => {
-              if (!dependencies) {
-                dependencies = this._extractor(code).deps.sync;
-              }
-              return {id, code, dependencies, map};
-            });
-          }
-        });
-      }
-    );
-  }
-
-  hash() {
-    return `Module : ${this.path}`;
-  }
-
-  isJSON() {
-    return path.extname(this.path) === '.json';
-  }
-
-  isAsset() {
-    return false;
-  }
-
-  isPolyfill() {
-    return false;
-  }
-
-  isAsset_DEPRECATED() {
-    return false;
-  }
-
-  toJSON() {
-    return {
-      hash: this.hash(),
-      isJSON: this.isJSON(),
-      isAsset: this.isAsset(),
-      isAsset_DEPRECATED: this.isAsset_DEPRECATED(),
-      type: this.type,
-      path: this.path,
-    };
-  }
-}
-
-function whileInDocBlock(chunk, i, result) {
-  // consume leading whitespace
-  if (!/\S/.test(result)) {
-    return true;
-  }
-
-  // check for start of doc block
-  if (!/^\s*\/(\*{2}|\*?$)/.test(result)) {
-    return false;
-  }
-
-  // check for end of doc block
-  return !/\*\//.test(result);
-}
-
-// use weak map to speed up hash creation of known objects
-const knownHashes = new WeakMap();
-function stableObjectHash(object) {
-  let digest = knownHashes.get(object);
-  if (!digest) {
-    digest = crypto.createHash('md5')
-      .update(jsonStableStringify(object))
-      .digest('base64');
-    knownHashes.set(object, digest);
-  }
-
-  return digest;
-}
-
-function cacheKey(field, transformOptions) {
-  return transformOptions !== undefined
-      ? stableObjectHash(transformOptions) + '\0' + field
-      : field;
-}
-
-module.exports = Module;
diff --git a/packager/react-packager/src/DependencyResolver/ModuleCache.js b/packager/react-packager/src/DependencyResolver/ModuleCache.js
deleted file mode 100644
index 11c56919c9a6..000000000000
--- a/packager/react-packager/src/DependencyResolver/ModuleCache.js
+++ /dev/null
@@ -1,104 +0,0 @@
-'use strict';
-
-const AssetModule = require('./AssetModule');
-const Package = require('./Package');
-const Module = require('./Module');
-const path = require('fast-path');
-
-class ModuleCache {
-
-  constructor({
-    fastfs,
-    cache,
-    extractRequires,
-    transformCode,
-    depGraphHelpers,
-  }) {
-    this._moduleCache = Object.create(null);
-    this._packageCache = Object.create(null);
-    this._fastfs = fastfs;
-    this._cache = cache;
-    this._extractRequires = extractRequires;
-    this._transformCode = transformCode;
-    this._depGraphHelpers = depGraphHelpers;
-
-    fastfs.on('change', this._processFileChange.bind(this));
-  }
-
-  getModule(filePath) {
-    if (!this._moduleCache[filePath]) {
-      this._moduleCache[filePath] = new Module({
-        file: filePath,
-        fastfs: this._fastfs,
-        moduleCache: this,
-        cache: this._cache,
-        extractor: this._extractRequires,
-        transformCode: this._transformCode,
-        depGraphHelpers: this._depGraphHelpers,
-      });
-    }
-    return this._moduleCache[filePath];
-  }
-
-  getAllModules() {
-    return this._moduleCache;
-  }
-
-  getAssetModule(filePath) {
-    if (!this._moduleCache[filePath]) {
-      this._moduleCache[filePath] = new AssetModule({
-        file: filePath,
-        fastfs: this._fastfs,
-        moduleCache: this,
-        cache: this._cache,
-      });
-    }
-    return this._moduleCache[filePath];
-  }
-
-  getPackage(filePath) {
-    if (!this._packageCache[filePath]) {
-      this._packageCache[filePath] = new Package({
-        file: filePath,
-        fastfs: this._fastfs,
-        cache: this._cache,
-      });
-    }
-    return this._packageCache[filePath];
-  }
-
-  getPackageForModule(module) {
-    // TODO(amasad): use ES6 Map.
-    if (module.__package) {
-      if (this._packageCache[module.__package]) {
-        return this._packageCache[module.__package];
-      } else {
-        delete module.__package;
-      }
-    }
-
-    const packagePath = this._fastfs.closest(module.path, 'package.json');
-
-    if (!packagePath) {
-      return null;
-    }
-
-    module.__package = packagePath;
-    return this.getPackage(packagePath);
-  }
-
-  _processFileChange(type, filePath, root) {
-    const absPath = path.join(root, filePath);
-
-    if (this._moduleCache[absPath]) {
-      this._moduleCache[absPath].invalidate();
-      delete this._moduleCache[absPath];
-    }
-    if (this._packageCache[absPath]) {
-      this._packageCache[absPath].invalidate();
-      delete this._packageCache[absPath];
-    }
-  }
-}
-
-module.exports = ModuleCache;
diff --git a/packager/react-packager/src/DependencyResolver/Package.js b/packager/react-packager/src/DependencyResolver/Package.js
deleted file mode 100644
index 0d28b3b00823..000000000000
--- a/packager/react-packager/src/DependencyResolver/Package.js
+++ /dev/null
@@ -1,100 +0,0 @@
-'use strict';
-
-const isAbsolutePath = require('absolute-path');
-const path = require('fast-path');
-
-class Package {
-
-  constructor({ file, fastfs, cache }) {
-    this.path = file;
-    this.root = path.dirname(this.path);
-    this._fastfs = fastfs;
-    this.type = 'Package';
-    this._cache = cache;
-  }
-
-  getMain() {
-    return this.read().then(json => {
-      var replacements = getReplacements(json);
-      if (typeof replacements === 'string') {
-        return path.join(this.root, replacements);
-      }
-
-      let main = json.main || 'index';
-
-      if (replacements && typeof replacements === 'object') {
-        main = replacements[main] ||
-          replacements[main + '.js'] ||
-          replacements[main + '.json'] ||
-          replacements[main.replace(/(\.js|\.json)$/, '')] ||
-          main;
-      }
-
-      return path.join(this.root, main);
-    });
-  }
-
-  isHaste() {
-    return this._cache.get(this.path, 'package-haste', () =>
-      this.read().then(json => !!json.name)
-    );
-  }
-
-  getName() {
-    return this._cache.get(this.path, 'package-name', () =>
-      this.read().then(json => json.name)
-    );
-  }
-
-  invalidate() {
-    this._cache.invalidate(this.path);
-  }
-
-  redirectRequire(name) {
-    return this.read().then(json => {
-      var replacements = getReplacements(json);
-
-      if (!replacements || typeof replacements !== 'object') {
-        return name;
-      }
-
-      if (name[0] !== '/') {
-        return replacements[name] || name;
-      }
-
-      if (!isAbsolutePath(name)) {
-        throw new Error(`Expected ${name} to be absolute path`);
-      }
-
-      const relPath = './' + path.relative(this.root, name);
-      const redirect = replacements[relPath] ||
-              replacements[relPath + '.js'] ||
-              replacements[relPath + '.json'];
-      if (redirect) {
-        return path.join(
-          this.root,
-          redirect
-        );
-      }
-
-      return name;
-    });
-  }
-
-  read() {
-    if (!this._reading) {
-      this._reading = this._fastfs.readFile(this.path)
-        .then(jsonStr => JSON.parse(jsonStr));
-    }
-
-    return this._reading;
-  }
-}
-
-function getReplacements(pkg) {
-  return pkg['react-native'] == null
-    ? pkg.browser
-    : pkg['react-native'];
-}
-
-module.exports = Package;
diff --git a/packager/react-packager/src/DependencyResolver/Polyfill.js b/packager/react-packager/src/DependencyResolver/Polyfill.js
deleted file mode 100644
index 97c57adb7e9c..000000000000
--- a/packager/react-packager/src/DependencyResolver/Polyfill.js
+++ /dev/null
@@ -1,38 +0,0 @@
-'use strict';
-
-const Promise = require('promise');
-const Module = require('./Module');
-
-class Polyfill extends Module {
-  constructor({ path, id, dependencies }) {
-    super({ file: path });
-    this._id = id;
-    this._dependencies = dependencies;
-  }
-
-  isHaste() {
-    return Promise.resolve(false);
-  }
-
-  getName() {
-    return Promise.resolve(this._id);
-  }
-
-  getPackage() {
-    return null;
-  }
-
-  getDependencies() {
-    return Promise.resolve(this._dependencies);
-  }
-
-  isJSON() {
-    return false;
-  }
-
-  isPolyfill() {
-    return true;
-  }
-}
-
-module.exports = Polyfill;
diff --git a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js b/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
deleted file mode 100644
index ee2623a3abda..000000000000
--- a/packager/react-packager/src/DependencyResolver/__tests__/Module-test.js
+++ /dev/null
@@ -1,335 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-jest
-  .dontMock('absolute-path')
-  .dontMock('json-stable-stringify')
-  .dontMock('../fastfs')
-  .dontMock('../lib/extractRequires')
-  .dontMock('../lib/replacePatterns')
-  .dontMock('../DependencyGraph/docblock')
-  .dontMock('../Module');
-
-jest
-  .mock('fs');
-
-const Fastfs = require('../fastfs');
-const Module = require('../Module');
-const ModuleCache = require('../ModuleCache');
-const DependencyGraphHelpers = require('../DependencyGraph/DependencyGraphHelpers');
-const Promise = require('promise');
-const fs = require('graceful-fs');
-
-function mockIndexFile(indexJs) {
-  fs.__setMockFilesystem({'root': {'index.js': indexJs}});
-}
-
-describe('Module', () => {
-  const fileWatcher = {
-    on: () =>  this,
-    isWatchman: () => Promise.resolve(false),
-  };
-  const fileName = '/root/index.js';
-
-  let cache, fastfs;
-
-  const createCache = () => ({
-    get: jest.genMockFn().mockImplementation(
-      (filepath, field, cb) => cb(filepath)
-    ),
-    invalidate: jest.genMockFn(),
-    end: jest.genMockFn(),
-  });
-
-  const createModule = (options) =>
-    new Module({
-      cache,
-      fastfs,
-      file: fileName,
-      depGraphHelpers: new DependencyGraphHelpers(),
-      moduleCache: new ModuleCache({fastfs, cache}),
-      ...options,
-    });
-
-  beforeEach(function(done) {
-    cache = createCache();
-    fastfs = new Fastfs(
-      'test',
-      ['/root'],
-      fileWatcher,
-      {crawling: Promise.resolve([fileName]), ignore: []},
-    );
-
-    fastfs.build().then(done);
-  });
-
-  describe('Module ID', () => {
-    const moduleId = 'arbitraryModule';
-    const source =
-    `/**
-       * @providesModule ${moduleId}
-       */
-    `;
-
-    let module;
-    beforeEach(() => {
-      module = createModule();
-    });
-
-    describe('@providesModule annotations', () => {
-      beforeEach(() => {
-        mockIndexFile(source);
-      });
-
-      pit('extracts the module name from the header', () =>
-        module.getName().then(name => expect(name).toEqual(moduleId))
-      );
-
-      pit('identifies the module as haste module', () =>
-        module.isHaste().then(isHaste => expect(isHaste).toBe(true))
-      );
-
-      pit('does not transform the file in order to access the name', () => {
-        const transformCode =
-          jest.genMockFn().mockReturnValue(Promise.resolve());
-        return createModule({transformCode}).getName()
-          .then(() => expect(transformCode).not.toBeCalled());
-      });
-
-      pit('does not transform the file in order to access the haste status', () => {
-        const transformCode =
-          jest.genMockFn().mockReturnValue(Promise.resolve());
-        return createModule({transformCode}).isHaste()
-          .then(() => expect(transformCode).not.toBeCalled());
-      });
-    });
-
-    describe('@provides annotations', () => {
-      beforeEach(() => {
-        mockIndexFile(source.replace(/@providesModule/, '@provides'));
-      });
-
-      pit('extracts the module name from the header if it has a @provides annotation', () =>
-        module.getName().then(name => expect(name).toEqual(moduleId))
-      );
-
-      pit('identifies the module as haste module', () =>
-        module.isHaste().then(isHaste => expect(isHaste).toBe(true))
-      );
-
-      pit('does not transform the file in order to access the name', () => {
-        const transformCode =
-          jest.genMockFn().mockReturnValue(Promise.resolve());
-        return createModule({transformCode}).getName()
-          .then(() => expect(transformCode).not.toBeCalled());
-      });
-
-      pit('does not transform the file in order to access the haste status', () => {
-        const transformCode =
-          jest.genMockFn().mockReturnValue(Promise.resolve());
-        return createModule({transformCode}).isHaste()
-          .then(() => expect(transformCode).not.toBeCalled());
-      });
-    });
-
-    describe('no annotation', () => {
-      beforeEach(() => {
-        mockIndexFile('arbitrary(code);');
-      });
-
-      pit('uses the file name as module name', () =>
-        module.getName().then(name => expect(name).toEqual(fileName))
-      );
-
-      pit('does not identify the module as haste module', () =>
-        module.isHaste().then(isHaste => expect(isHaste).toBe(false))
-      );
-
-      pit('does not transform the file in order to access the name', () => {
-        const transformCode =
-          jest.genMockFn().mockReturnValue(Promise.resolve());
-        return createModule({transformCode}).getName()
-          .then(() => expect(transformCode).not.toBeCalled());
-      });
-
-      pit('does not transform the file in order to access the haste status', () => {
-        const transformCode =
-          jest.genMockFn().mockReturnValue(Promise.resolve());
-        return createModule({transformCode}).isHaste()
-          .then(() => expect(transformCode).not.toBeCalled());
-      });
-    });
-  });
-
-  describe('Code', () => {
-    const fileContents = 'arbitrary(code)';
-    beforeEach(function() {
-      mockIndexFile(fileContents);
-    });
-
-    pit('exposes file contents as `code` property on the data exposed by `read()`', () =>
-      createModule().read().then(({code}) =>
-        expect(code).toBe(fileContents))
-    );
-
-    pit('exposes file contents via the `getCode()` method', () =>
-      createModule().getCode().then(code =>
-        expect(code).toBe(fileContents))
-    );
-  });
-
-  describe('Extrators', () => {
-
-    pit('uses custom require extractors if specified', () => {
-      mockIndexFile('');
-      const module = createModule({
-        extractor: code => ({deps: {sync: ['foo', 'bar']}}),
-      });
-
-      return module.getDependencies().then(actual =>
-        expect(actual).toEqual(['foo', 'bar']));
-    });
-  });
-
-  describe('Custom Code Transform', () => {
-    let transformCode;
-    const fileContents = 'arbitrary(code);';
-    const exampleCode = `
-      ${'require'}('a');
-      ${'System.import'}('b');
-      ${'require'}('c');`;
-
-    beforeEach(function() {
-      transformCode = jest.genMockFn();
-      mockIndexFile(fileContents);
-      transformCode.mockReturnValue(Promise.resolve({code: ''}));
-    });
-
-    pit('passes the module and file contents to the transform function when reading', () => {
-      const module = createModule({transformCode});
-      return module.read()
-        .then(() => {
-          expect(transformCode).toBeCalledWith(module, fileContents, undefined);
-        });
-    });
-
-    pit('passes any additional options to the transform function when reading', () => {
-      const module = createModule({transformCode});
-      const transformOptions = {arbitrary: Object()};
-      return module.read(transformOptions)
-        .then(() =>
-          expect(transformCode.mock.calls[0][2]).toBe(transformOptions)
-        );
-    });
-
-    pit('uses the code that `transformCode` resolves to to extract dependencies', () => {
-      transformCode.mockReturnValue(Promise.resolve({code: exampleCode}));
-      const module = createModule({transformCode});
-
-      return module.getDependencies().then(dependencies => {
-        expect(dependencies).toEqual(['a', 'c']);
-      });
-    });
-
-    pit('uses dependencies that `transformCode` resolves to, instead of extracting them', () => {
-      const mockedDependencies = ['foo', 'bar'];
-      transformCode.mockReturnValue(Promise.resolve({
-        code: exampleCode,
-        dependencies: mockedDependencies,
-      }));
-      const module = createModule({transformCode});
-
-      return module.getDependencies().then(dependencies => {
-        expect(dependencies).toEqual(mockedDependencies);
-      });
-    });
-
-    pit('exposes the transformed code rather than the raw file contents', () => {
-      transformCode.mockReturnValue(Promise.resolve({code: exampleCode}));
-      const module = createModule({transformCode});
-      return Promise.all([module.read(), module.getCode()])
-        .then(([data, code]) => {
-          expect(data.code).toBe(exampleCode);
-          expect(code).toBe(exampleCode);
-        });
-    });
-
-    pit('exposes a source map returned by the transform', () => {
-      const map = {version: 3};
-      transformCode.mockReturnValue(Promise.resolve({map, code: exampleCode}));
-      const module = createModule({transformCode});
-      return Promise.all([module.read(), module.getMap()])
-        .then(([data, sourceMap]) => {
-          expect(data.map).toBe(map);
-          expect(sourceMap).toBe(map);
-        });
-    });
-
-    describe('Caching based on options', () => {
-      let module;
-      beforeEach(function() {
-        module = createModule({transformCode});
-      });
-
-      const callsEqual = ([path1, key1], [path2, key2]) => {
-        expect(path1).toEqual(path2);
-        expect(key1).toEqual(key2);
-      };
-
-      it('gets dependencies from the cache with the same cache key for the same transform options', () => {
-        const options = {some: 'options'};
-        module.getDependencies(options); // first call
-        module.getDependencies(options); // second call
-
-        const {calls} = cache.get.mock;
-        callsEqual(calls[0], calls[1]);
-      });
-
-      it('gets dependencies from the cache with the same cache key for the equivalent transform options', () => {
-        module.getDependencies({a: 'b', c: 'd'}); // first call
-        module.getDependencies({c: 'd', a: 'b'}); // second call
-
-        const {calls} = cache.get.mock;
-        callsEqual(calls[0], calls[1]);
-      });
-
-      it('gets dependencies from the cache with different cache keys for different transform options', () => {
-        module.getDependencies({some: 'options'});
-        module.getDependencies({other: 'arbitrary options'});
-        const {calls} = cache.get.mock;
-        expect(calls[0][1]).not.toEqual(calls[1][1]);
-      });
-
-      it('gets code from the cache with the same cache key for the same transform options', () => {
-        const options = {some: 'options'};
-        module.getCode(options); // first call
-        module.getCode(options); // second call
-
-        const {calls} = cache.get.mock;
-        callsEqual(calls[0], calls[1]);
-      });
-
-      it('gets code from the cache with the same cache key for the equivalent transform options', () => {
-        module.getCode({a: 'b', c: 'd'}); // first call
-        module.getCode({c: 'd', a: 'b'}); // second call
-
-        const {calls} = cache.get.mock;
-        callsEqual(calls[0], calls[1]);
-      });
-
-      it('gets code from the cache with different cache keys for different transform options', () => {
-        module.getCode({some: 'options'});
-        module.getCode({other: 'arbitrary options'});
-        const {calls} = cache.get.mock;
-        expect(calls[0][1]).not.toEqual(calls[1][1]);
-      });
-    });
-  });
-});
diff --git a/packager/react-packager/src/DependencyResolver/__tests__/fastfs-data b/packager/react-packager/src/DependencyResolver/__tests__/fastfs-data
deleted file mode 100644
index fe2c6388532b..000000000000
--- a/packager/react-packager/src/DependencyResolver/__tests__/fastfs-data
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * 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.
- * An arbitrary module header
- * @providesModule
- */
-
- const some: string = 'arbitrary code';
- const containing: string = 'ūñïčødę';
-
-/**
- * An arbitrary class that extends some thing
- * It exposes a random number, which may be reset at the callers discretion
- */
-class Arbitrary extends Something {
-  constructor() {
-    this.reset();
-  }
-
-  /**
-   * Returns the random number
-   * @returns number
-   */
-  get random(): number {
-    return this._random;
-  }
-
-  /**
-   * Re-creates the internal random number
-   * @returns void
-   */
-  reset(): void {
-    this._random = Math.random();
-  }
-}
diff --git a/packager/react-packager/src/DependencyResolver/__tests__/fastfs-integrated-test.js b/packager/react-packager/src/DependencyResolver/__tests__/fastfs-integrated-test.js
deleted file mode 100644
index cbff314af1a0..000000000000
--- a/packager/react-packager/src/DependencyResolver/__tests__/fastfs-integrated-test.js
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-jest.autoMockOff()
-  .dontMock('graceful-fs');
-
-const Fastfs = require('../fastfs');
-
-const {EventEmitter} = require('events');
-const fs = require('fs');
-const path = require('path');
-
-const fileName = path.resolve(__dirname, 'fastfs-data');
-const contents = fs.readFileSync(fileName, 'utf-8');
-
-describe('fastfs:', function() {
-  let fastfs;
-  const crawling = Promise.resolve([fileName]);
-  const roots = [__dirname];
-  const watcher = new EventEmitter();
-
-  beforeEach(function(done) {
-    fastfs = new Fastfs('arbitrary', roots, watcher, {crawling});
-    fastfs.build().then(done);
-  });
-
-  describe('partial reading', () => {
-    // these are integrated tests that read real files from disk
-
-    pit('reads a file while a predicate returns true', function() {
-      return fastfs.readWhile(fileName, () => true).then(readContent =>
-        expect(readContent).toEqual(contents)
-      );
-    });
-
-    pit('invokes the predicate with the new chunk, the invocation index, and the result collected so far', () => {
-      const predicate = jest.genMockFn().mockReturnValue(true);
-      return fastfs.readWhile(fileName, predicate).then(() => {
-        let aggregated = '';
-        const {calls} = predicate.mock;
-        expect(calls).not.toEqual([]);
-
-        calls.forEach((call, i) => {
-          const [chunk] = call;
-          aggregated += chunk;
-          expect(chunk).not.toBe('');
-          expect(call).toEqual([chunk, i, aggregated]);
-        });
-
-        expect(aggregated).toEqual(contents);
-      });
-    });
-
-    pit('stops reading when the predicate returns false', () => {
-      const predicate = jest.genMockFn().mockImpl((_, i) => i !== 0);
-      return fastfs.readWhile(fileName, predicate).then((readContent) => {
-        const {calls} = predicate.mock;
-        expect(calls.length).toBe(1);
-        expect(readContent).toBe(calls[0][2]);
-      });
-    });
-
-    pit('after reading the whole file with `readWhile`, `read()` still works', () => {
-      // this test allows to reuse the results of `readWhile` for `readFile`
-      return fastfs.readWhile(fileName, () => true).then(() => {
-        fastfs.readFile(fileName).then(readContent =>
-          expect(readContent).toEqual(contents)
-        );
-      });
-    });
-
-    pit('after reading parts of the file with `readWhile`, `read()` still works', () => {
-      return fastfs.readWhile(fileName, () => false).then(() => {
-        fastfs.readFile(fileName).then(readContent =>
-          expect(readContent).toEqual(contents)
-        );
-      });
-    });
-  });
-});
diff --git a/packager/react-packager/src/DependencyResolver/crawlers/index.js b/packager/react-packager/src/DependencyResolver/crawlers/index.js
deleted file mode 100644
index fe755bcb621e..000000000000
--- a/packager/react-packager/src/DependencyResolver/crawlers/index.js
+++ /dev/null
@@ -1,26 +0,0 @@
-'use strict';
-
-const nodeCrawl = require('./node');
-const watchmanCrawl = require('./watchman');
-
-function crawl(roots, options) {
-  const {fileWatcher} = options;
-  return fileWatcher.isWatchman().then(isWatchman => {
-    if (!isWatchman) {
-      return false;
-    }
-
-    // Make sure we're dealing with a version of watchman
-    // that's using `watch-project`
-    // TODO(amasad): properly expose (and document) used sane internals.
-    return fileWatcher.getWatchers().then(([watcher]) => !!watcher.watchProjectInfo.root);
-  }).then(isWatchman => {
-    if (isWatchman) {
-      return watchmanCrawl(roots, options);
-    }
-
-    return nodeCrawl(roots, options);
-  });
-}
-
-module.exports = crawl;
diff --git a/packager/react-packager/src/DependencyResolver/crawlers/node.js b/packager/react-packager/src/DependencyResolver/crawlers/node.js
deleted file mode 100644
index 871bbc1d78f9..000000000000
--- a/packager/react-packager/src/DependencyResolver/crawlers/node.js
+++ /dev/null
@@ -1,61 +0,0 @@
-'use strict';
-
-const Promise = require('promise');
-const debug = require('debug')('ReactNativePackager:DependencyGraph');
-const fs = require('graceful-fs');
-const path = require('fast-path');
-
-const readDir = Promise.denodeify(fs.readdir);
-const stat = Promise.denodeify(fs.stat);
-
-function nodeRecReadDir(roots, {ignore, exts}) {
-  const queue = roots.slice();
-  const retFiles = [];
-  const extPattern = new RegExp(
-    '\.(' + exts.join('|') + ')$'
-  );
-
-  function search() {
-    const currDir = queue.shift();
-    if (!currDir) {
-      return Promise.resolve();
-    }
-
-    return readDir(currDir)
-      .then(files => files.map(f => path.join(currDir, f)))
-      .then(files => Promise.all(
-        files.map(f => stat(f).catch(handleBrokenLink))
-      ).then(stats => [
-        // Remove broken links.
-        files.filter((file, i) => !!stats[i]),
-        stats.filter(Boolean),
-      ]))
-      .then(([files, stats]) => {
-        files.forEach((filePath, i) => {
-          if (ignore(filePath)) {
-            return;
-          }
-
-          if (stats[i].isDirectory()) {
-            queue.push(filePath);
-            return;
-          }
-
-          if (filePath.match(extPattern)) {
-            retFiles.push(filePath);
-          }
-        });
-
-        return search();
-      });
-  }
-
-  return search().then(() => retFiles);
-}
-
-function handleBrokenLink(e) {
-  debug('WARNING: error stating, possibly broken symlink', e.message);
-  return Promise.resolve();
-}
-
-module.exports = nodeRecReadDir;
diff --git a/packager/react-packager/src/DependencyResolver/crawlers/watchman.js b/packager/react-packager/src/DependencyResolver/crawlers/watchman.js
deleted file mode 100644
index 6e3d6a6c9421..000000000000
--- a/packager/react-packager/src/DependencyResolver/crawlers/watchman.js
+++ /dev/null
@@ -1,66 +0,0 @@
-'use strict';
-
-const Promise = require('promise');
-const path = require('fast-path');
-
-function watchmanRecReadDir(roots, {ignore, fileWatcher, exts}) {
-  const files = [];
-  return Promise.all(
-    roots.map(
-      root => fileWatcher.getWatcherForRoot(root)
-    )
-  ).then(
-    watchers => {
-      // All watchman roots for all watches we have.
-      const watchmanRoots = watchers.map(
-        watcher => watcher.watchProjectInfo.root
-      );
-
-      // Actual unique watchers (because we use watch-project we may end up with
-      // duplicate "real" watches, and that's by design).
-      // TODO(amasad): push this functionality into the `FileWatcher`.
-      const uniqueWatchers = watchers.filter(
-        (watcher, i) => watchmanRoots.indexOf(watcher.watchProjectInfo.root) === i
-      );
-
-      return Promise.all(
-        uniqueWatchers.map(watcher => {
-          const watchedRoot = watcher.watchProjectInfo.root;
-
-          // Build up an expression to filter the output by the relevant roots.
-          const dirExpr = ['anyof'];
-          for (let i = 0; i < roots.length; i++) {
-            const root = roots[i];
-            if (isDescendant(watchedRoot, root)) {
-              dirExpr.push(['dirname', path.relative(watchedRoot, root)]);
-            }
-          }
-
-          const cmd = Promise.denodeify(watcher.client.command.bind(watcher.client));
-          return cmd(['query', watchedRoot, {
-            suffix: exts,
-            expression: ['allof', ['type', 'f'], 'exists', dirExpr],
-            fields: ['name'],
-          }]).then(resp => {
-            if ('warning' in resp) {
-              console.warn('watchman warning: ', resp.warning);
-            }
-
-            resp.files.forEach(filePath => {
-              filePath = watchedRoot + path.sep + filePath;
-              if (!ignore(filePath)) {
-                files.push(filePath);
-              }
-              return false;
-            });
-          });
-        })
-      );
-    }).then(() => files);
-}
-
-function isDescendant(root, child) {
-  return child.startsWith(root);
-}
-
-module.exports = watchmanRecReadDir;
diff --git a/packager/react-packager/src/DependencyResolver/fastfs.js b/packager/react-packager/src/DependencyResolver/fastfs.js
deleted file mode 100644
index af2010086eff..000000000000
--- a/packager/react-packager/src/DependencyResolver/fastfs.js
+++ /dev/null
@@ -1,360 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-const Promise = require('promise');
-const {EventEmitter} = require('events');
-
-const fs = require('graceful-fs');
-const path = require('fast-path');
-
-// workaround for https://github.com/isaacs/node-graceful-fs/issues/56
-// fs.close is patched, whereas graceful-fs.close is not.
-const fsClose = require('fs').close;
-
-const readFile = Promise.denodeify(fs.readFile);
-const stat = Promise.denodeify(fs.stat);
-
-const NOT_FOUND_IN_ROOTS = 'NotFoundInRootsError';
-
-class Fastfs extends EventEmitter {
-  constructor(name, roots, fileWatcher, {ignore, crawling, activity}) {
-    super();
-    this._name = name;
-    this._fileWatcher = fileWatcher;
-    this._ignore = ignore;
-    this._roots = roots.map(root => {
-      // If the path ends in a separator ("/"), remove it to make string
-      // operations on paths safer.
-      if (root.endsWith(path.sep)) {
-        root = root.substr(0, root.length - 1);
-      }
-      return new File(root, true);
-    });
-    this._fastPaths = Object.create(null);
-    this._crawling = crawling;
-    this._activity = activity;
-  }
-
-  build() {
-    return this._crawling.then(files => {
-      let fastfsActivity;
-      const activity = this._activity;
-      if (activity) {
-        fastfsActivity = activity.startEvent('Building in-memory fs for ' + this._name);
-      }
-      files.forEach(filePath => {
-        const root = this._getRoot(filePath);
-        if (root) {
-          const newFile = new File(filePath, false);
-          const dirname = filePath.substr(0, filePath.lastIndexOf(path.sep));
-          const parent = this._fastPaths[dirname];
-          this._fastPaths[filePath] = newFile;
-          if (parent) {
-            parent.addChild(newFile, this._fastPaths);
-          } else {
-            root.addChild(newFile, this._fastPaths);
-          }
-        }
-      });
-      if (activity) {
-        activity.endEvent(fastfsActivity);
-      }
-      this._fileWatcher.on('all', this._processFileChange.bind(this));
-    });
-  }
-
-  stat(filePath) {
-    return Promise.resolve().then(() => this._getFile(filePath).stat());
-  }
-
-  getAllFiles() {
-    return Object.keys(this._fastPaths)
-      .filter(filePath => !this._fastPaths[filePath].isDir);
-  }
-
-  findFilesByExts(exts, { ignore } = {}) {
-    return this.getAllFiles()
-      .filter(filePath => (
-        exts.indexOf(path.extname(filePath).substr(1)) !== -1 &&
-        (!ignore || !ignore(filePath))
-      ));
-  }
-
-  matchFilesByPattern(pattern) {
-    return this.getAllFiles().filter(file => file.match(pattern));
-  }
-
-  readFile(filePath) {
-    const file = this._getFile(filePath);
-    if (!file) {
-      throw new Error(`Unable to find file with path: ${filePath}`);
-    }
-    return file.read();
-  }
-
-  readWhile(filePath, predicate) {
-    const file = this._getFile(filePath);
-    if (!file) {
-      throw new Error(`Unable to find file with path: ${filePath}`);
-    }
-    return file.readWhile(predicate);
-  }
-
-  closest(filePath, name) {
-    for (let file = this._getFile(filePath).parent;
-         file;
-         file = file.parent) {
-      if (file.children[name]) {
-        return file.children[name].path;
-      }
-    }
-    return null;
-  }
-
-  fileExists(filePath) {
-    let file;
-    try {
-      file = this._getFile(filePath);
-    } catch (e) {
-      if (e.type === NOT_FOUND_IN_ROOTS) {
-        return false;
-      }
-      throw e;
-    }
-
-    return file && !file.isDir;
-  }
-
-  dirExists(filePath) {
-    let file;
-    try {
-      file = this._getFile(filePath);
-    } catch (e) {
-      if (e.type === NOT_FOUND_IN_ROOTS) {
-        return false;
-      }
-      throw e;
-    }
-
-    return file && file.isDir;
-  }
-
-  matches(dir, pattern) {
-    const dirFile = this._getFile(dir);
-    if (!dirFile.isDir) {
-      throw new Error(`Expected file ${dirFile.path} to be a directory`);
-    }
-
-    return Object.keys(dirFile.children)
-      .filter(name => name.match(pattern))
-      .map(name => path.join(dirFile.path, name));
-  }
-
-  _getRoot(filePath) {
-    for (let i = 0; i < this._roots.length; i++) {
-      const possibleRoot = this._roots[i];
-      if (isDescendant(possibleRoot.path, filePath)) {
-        return possibleRoot;
-      }
-    }
-    return null;
-  }
-
-  _getAndAssertRoot(filePath) {
-    const root = this._getRoot(filePath);
-    if (!root) {
-      const error = new Error(`File ${filePath} not found in any of the roots`);
-      error.type = NOT_FOUND_IN_ROOTS;
-      throw error;
-    }
-    return root;
-  }
-
-  _getFile(filePath) {
-    filePath = path.normalize(filePath);
-    if (!this._fastPaths[filePath]) {
-      const file = this._getAndAssertRoot(filePath).getFileFromPath(filePath);
-      if (file) {
-        this._fastPaths[filePath] = file;
-      }
-    }
-
-    return this._fastPaths[filePath];
-  }
-
-  _processFileChange(type, filePath, rootPath, fstat) {
-    const absPath = path.join(rootPath, filePath);
-    if (this._ignore(absPath) || (fstat && fstat.isDirectory())) {
-      return;
-    }
-
-    // Make sure this event belongs to one of our roots.
-    const root = this._getRoot(absPath);
-    if (!root) {
-      return;
-    }
-
-    if (type === 'delete' || type === 'change') {
-      const file = this._getFile(absPath);
-      if (file) {
-        file.remove();
-      }
-    }
-
-    delete this._fastPaths[path.normalize(absPath)];
-
-    if (type !== 'delete') {
-      const file = new File(absPath, false);
-      root.addChild(file, this._fastPaths);
-    }
-
-    this.emit('change', type, filePath, rootPath, fstat);
-  }
-}
-
-class File {
-  constructor(filePath, isDir) {
-    this.path = filePath;
-    this.isDir = isDir;
-    this.children = this.isDir ? Object.create(null) : null;
-  }
-
-  read() {
-    if (!this._read) {
-      this._read = readFile(this.path, 'utf8');
-    }
-    return this._read;
-  }
-
-  readWhile(predicate) {
-    return readWhile(this.path, predicate).then(({result, completed}) => {
-      if (completed && !this._read) {
-        this._read = Promise.resolve(result);
-      }
-      return result;
-    });
-  }
-
-  stat() {
-    if (!this._stat) {
-      this._stat = stat(this.path);
-    }
-
-    return this._stat;
-  }
-
-  addChild(file, fileMap) {
-    const parts = file.path.substr(this.path.length + 1).split(path.sep);
-    if (parts.length === 1) {
-      this.children[parts[0]] = file;
-      file.parent = this;
-    } else if (this.children[parts[0]]) {
-      this.children[parts[0]].addChild(file, fileMap);
-    } else {
-      const dir = new File(this.path + path.sep + parts[0], true);
-      dir.parent = this;
-      this.children[parts[0]] = dir;
-      fileMap[dir.path] = dir;
-      dir.addChild(file, fileMap);
-    }
-  }
-
-  getFileFromPath(filePath) {
-    const parts = path.relative(this.path, filePath).split(path.sep);
-
-    /*eslint consistent-this:0*/
-    let file = this;
-    for (let i = 0; i < parts.length; i++) {
-      const fileName = parts[i];
-      if (!fileName) {
-        continue;
-      }
-
-      if (!file || !file.isDir) {
-        // File not found.
-        return null;
-      }
-
-      file = file.children[fileName];
-    }
-
-    return file;
-  }
-
-  ext() {
-    return path.extname(this.path).substr(1);
-  }
-
-  remove() {
-    if (!this.parent) {
-      throw new Error(`No parent to delete ${this.path} from`);
-    }
-
-    delete this.parent.children[path.basename(this.path)];
-  }
-}
-
-function readWhile(filePath, predicate) {
-  return new Promise((resolve, reject) => {
-    fs.open(filePath, 'r', (openError, fd) => {
-      if (openError) {
-        reject(openError);
-        return;
-      }
-
-      read(
-        fd,
-        /*global Buffer: true*/
-        new Buffer(512),
-        makeReadCallback(fd, predicate, (readError, result, completed) => {
-          if (readError) {
-            reject(readError);
-          } else {
-            resolve({result, completed});
-          }
-        })
-      );
-    });
-  });
-}
-
-function read(fd, buffer, callback) {
-  fs.read(fd, buffer, 0, buffer.length, -1, callback);
-}
-
-function close(fd, error, result, complete, callback) {
-  fsClose(fd, closeError => callback(error || closeError, result, complete));
-}
-
-function makeReadCallback(fd, predicate, callback) {
-  let result = '';
-  let index = 0;
-  return function readCallback(error, bytesRead, buffer) {
-    if (error) {
-      close(fd, error, undefined, false, callback);
-      return;
-    }
-
-    const completed = bytesRead === 0;
-    const chunk = completed ? '' : buffer.toString('utf8', 0, bytesRead);
-    result += chunk;
-    if (completed || !predicate(chunk, index++, result)) {
-      close(fd, null, result, completed, callback);
-    } else {
-      read(fd, buffer, readCallback);
-    }
-  };
-}
-
-function isDescendant(root, child) {
-  return child.startsWith(root);
-}
-
-module.exports = Fastfs;
diff --git a/packager/react-packager/src/DependencyResolver/lib/__tests__/getAssetDataFromName-test.js b/packager/react-packager/src/DependencyResolver/lib/__tests__/getAssetDataFromName-test.js
deleted file mode 100644
index ff61c40537d4..000000000000
--- a/packager/react-packager/src/DependencyResolver/lib/__tests__/getAssetDataFromName-test.js
+++ /dev/null
@@ -1,119 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-jest.dontMock('../getPlatformExtension')
-    .dontMock('../getAssetDataFromName');
-
-var getAssetDataFromName = require('../getAssetDataFromName');
-
-describe('getAssetDataFromName', () => {
-  it('should get data from name', () => {
-    expect(getAssetDataFromName('a/b/c.png')).toEqual({
-      resolution: 1,
-      assetName: 'a/b/c.png',
-      type: 'png',
-      name: 'c',
-      platform: null,
-    });
-
-    expect(getAssetDataFromName('a/b/c@1x.png')).toEqual({
-      resolution: 1,
-      assetName: 'a/b/c.png',
-      type: 'png',
-      name: 'c',
-      platform: null,
-    });
-
-    expect(getAssetDataFromName('a/b/c@2.5x.png')).toEqual({
-      resolution: 2.5,
-      assetName: 'a/b/c.png',
-      type: 'png',
-      name: 'c',
-      platform: null,
-    });
-
-    expect(getAssetDataFromName('a/b/c.ios.png')).toEqual({
-      resolution: 1,
-      assetName: 'a/b/c.png',
-      type: 'png',
-      name: 'c',
-      platform: 'ios',
-    });
-
-    expect(getAssetDataFromName('a/b/c@1x.ios.png')).toEqual({
-      resolution: 1,
-      assetName: 'a/b/c.png',
-      type: 'png',
-      name: 'c',
-      platform: 'ios',
-    });
-
-    expect(getAssetDataFromName('a/b/c@2.5x.ios.png')).toEqual({
-      resolution: 2.5,
-      assetName: 'a/b/c.png',
-      type: 'png',
-      name: 'c',
-      platform: 'ios',
-    });
-  });
-
-  describe('resolution extraction', () => {
-    it('should extract resolution simple case', () =>  {
-      var data = getAssetDataFromName('test@2x.png');
-      expect(data).toEqual({
-        assetName: 'test.png',
-        resolution: 2,
-        type: 'png',
-        name: 'test',
-        platform: null,
-      });
-    });
-
-    it('should default resolution to 1', () =>  {
-      var data = getAssetDataFromName('test.png');
-      expect(data).toEqual({
-        assetName: 'test.png',
-        resolution: 1,
-        type: 'png',
-        name: 'test',
-        platform: null,
-      });
-    });
-
-    it('should support float', () =>  {
-      var data = getAssetDataFromName('test@1.1x.png');
-      expect(data).toEqual({
-        assetName: 'test.png',
-        resolution: 1.1,
-        type: 'png',
-        name: 'test',
-        platform: null,
-      });
-
-      data = getAssetDataFromName('test@.1x.png');
-      expect(data).toEqual({
-        assetName: 'test.png',
-        resolution: 0.1,
-        type: 'png',
-        name: 'test',
-        platform: null,
-      });
-
-      data = getAssetDataFromName('test@0.2x.png');
-      expect(data).toEqual({
-        assetName: 'test.png',
-        resolution: 0.2,
-        type: 'png',
-        name: 'test',
-        platform: null,
-      });
-    });
-  });
-});
diff --git a/packager/react-packager/src/DependencyResolver/lib/__tests__/getPlatformExtension-test.js b/packager/react-packager/src/DependencyResolver/lib/__tests__/getPlatformExtension-test.js
deleted file mode 100644
index f5ccdc3ab9b4..000000000000
--- a/packager/react-packager/src/DependencyResolver/lib/__tests__/getPlatformExtension-test.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-jest.dontMock('../getPlatformExtension');
-
-var getPlatformExtension = require('../getPlatformExtension');
-
-describe('getPlatformExtension', function() {
-  it('should get platform ext', function() {
-    expect(getPlatformExtension('a.ios.js')).toBe('ios');
-    expect(getPlatformExtension('a.android.js')).toBe('android');
-    expect(getPlatformExtension('/b/c/a.ios.js')).toBe('ios');
-    expect(getPlatformExtension('/b/c.android/a.ios.js')).toBe('ios');
-    expect(getPlatformExtension('/b/c/a@1.5x.ios.png')).toBe('ios');
-    expect(getPlatformExtension('/b/c/a@1.5x.lol.png')).toBe(null);
-    expect(getPlatformExtension('/b/c/a.lol.png')).toBe(null);
-  });
-});
diff --git a/packager/react-packager/src/DependencyResolver/lib/extractRequires.js b/packager/react-packager/src/DependencyResolver/lib/extractRequires.js
deleted file mode 100644
index 547ffbbb3165..000000000000
--- a/packager/react-packager/src/DependencyResolver/lib/extractRequires.js
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-const replacePatterns = require('./replacePatterns');
-
-/**
- * Extract all required modules from a `code` string.
- */
-const blockCommentRe = /\/\*(.|\n)*?\*\//g;
-const lineCommentRe = /\/\/.+(\n|$)/g;
-function extractRequires(code) {
-  var deps = {
-    sync: [],
-  };
-
-  code = code
-    .replace(blockCommentRe, '')
-    .replace(lineCommentRe, '')
-    // Parse the sync dependencies this module has. When the module is
-    // required, all it's sync dependencies will be loaded into memory.
-    // Sync dependencies can be defined either using `require` or the ES6
-    // `import` or `export` syntaxes:
-    //   var dep1 = require('dep1');
-    .replace(replacePatterns.IMPORT_RE, (match, pre, quot, dep, post) => {
-      deps.sync.push(dep);
-      return match;
-    })
-    .replace(replacePatterns.EXPORT_RE, (match, pre, quot, dep, post) => {
-      deps.sync.push(dep);
-      return match;
-    })
-    .replace(replacePatterns.REQUIRE_RE, (match, pre, quot, dep, post) => {
-      deps.sync.push(dep);
-      return match;
-    });
-
-  return {code, deps};
-}
-
-module.exports = extractRequires;
diff --git a/packager/react-packager/src/DependencyResolver/lib/getAssetDataFromName.js b/packager/react-packager/src/DependencyResolver/lib/getAssetDataFromName.js
deleted file mode 100644
index a616d1084828..000000000000
--- a/packager/react-packager/src/DependencyResolver/lib/getAssetDataFromName.js
+++ /dev/null
@@ -1,55 +0,0 @@
- /**
- * 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.
- */
-'use strict';
-
-const path = require('fast-path');
-const getPlatformExtension = require('./getPlatformExtension');
-
-function getAssetDataFromName(filename) {
-  const ext = path.extname(filename);
-  const platformExt = getPlatformExtension(filename);
-
-  let pattern = '@([\\d\\.]+)x';
-  if (platformExt != null) {
-    pattern += '(\\.' + platformExt + ')?';
-  }
-  pattern += '\\' + ext + '$';
-  const re = new RegExp(pattern);
-
-  const match = filename.match(re);
-  let resolution;
-
-  if (!(match && match[1])) {
-    resolution = 1;
-  } else {
-    resolution = parseFloat(match[1], 10);
-    if (isNaN(resolution)) {
-      resolution = 1;
-    }
-  }
-
-  let assetName;
-  if (match) {
-    assetName = filename.replace(re, ext);
-  } else if (platformExt != null) {
-    assetName = filename.replace(new RegExp(`\\.${platformExt}\\${ext}`), ext);
-  } else {
-    assetName = filename;
-  }
-
-  return {
-    resolution: resolution,
-    assetName: assetName,
-    type: ext.slice(1),
-    name: path.basename(assetName, ext),
-    platform: platformExt,
-  };
-}
-
-module.exports = getAssetDataFromName;
diff --git a/packager/react-packager/src/DependencyResolver/lib/getPlatformExtension.js b/packager/react-packager/src/DependencyResolver/lib/getPlatformExtension.js
deleted file mode 100644
index 721470d106ae..000000000000
--- a/packager/react-packager/src/DependencyResolver/lib/getPlatformExtension.js
+++ /dev/null
@@ -1,28 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-const SUPPORTED_PLATFORM_EXTS = {
-  android: true,
-  ios: true,
-  web: true,
-};
-
-// Extract platform extension: index.ios.js -> ios
-function getPlatformExtension(file) {
-  const last = file.lastIndexOf('.');
-  const secondToLast = file.lastIndexOf('.', last - 1);
-  if (secondToLast === -1) {
-    return null;
-  }
-  const platform = file.substring(secondToLast + 1, last);
-  return SUPPORTED_PLATFORM_EXTS[platform] ? platform : null;
-}
-
-module.exports = getPlatformExtension;
diff --git a/packager/react-packager/src/DependencyResolver/lib/replacePatterns.js b/packager/react-packager/src/DependencyResolver/lib/replacePatterns.js
deleted file mode 100644
index 8c10710ec459..000000000000
--- a/packager/react-packager/src/DependencyResolver/lib/replacePatterns.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * 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.
- */
-
-'use strict';
-
-exports.IMPORT_RE = /(\bimport\s+(?:[^'"]+\s+from\s+)??)(['"])([^'"]+)(\2)/g;
-exports.EXPORT_RE = /(\bexport\s+(?:[^'"]+\s+from\s+)??)(['"])([^'"]+)(\2)/g;
-exports.REQUIRE_RE = /(\brequire\s*?\(\s*?)(['"])([^'"]+)(\2\s*?\))/g;
diff --git a/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js b/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js
index 7e12976895df..ad4dc4d4e3da 100644
--- a/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js
+++ b/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js
@@ -15,16 +15,20 @@ jest
 jest.mock('fs');
 jest.setMock('temp', {path: () => '/arbitrary/path'});
 
-var Cache = require('../../DependencyResolver/Cache');
 var Transformer = require('../');
 var fs = require('fs');
 
+var Cache;
 var options;
 
 describe('Transformer', function() {
   var workers;
 
   beforeEach(function() {
+    Cache = require('node-haste').Cache;
+
+    Cache.prototype.get = jest.genMockFn().mockImpl((a, b, c) => c());
+
     workers = jest.genMockFn();
     jest.setMock('worker-farm', jest.genMockFn().mockImpl(function() {
       return workers;
diff --git a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
index 2f1f65dea676..7b3a5616c823 100644
--- a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
+++ b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
@@ -9,29 +9,29 @@
 'use strict';
 
 jest.dontMock('../')
-  .dontMock('underscore')
-  .dontMock('../../DependencyResolver/lib/extractRequires')
-  .dontMock('../../DependencyResolver/lib/replacePatterns');
+  .dontMock('underscore');
 
 jest.mock('path');
 
-var Promise = require('promise');
-var Resolver = require('../');
-var Module = require('../../DependencyResolver/Module');
-var Polyfill = require('../../DependencyResolver/Polyfill');
-var DependencyGraph = require('../../DependencyResolver/DependencyGraph');
+const Promise = require('promise');
+const Resolver = require('../');
+const DependencyGraph = require('node-haste');
 
-var path = require('path');
-var _ = require('underscore');
+const path = require('path');
+const _ = require('underscore');
+
+let Module;
+let Polyfill;
 
 describe('Resolver', function() {
   beforeEach(function() {
-    Polyfill.mockClear();
+    Module = require('node-haste').Module;
+    Polyfill = require('node-haste').Polyfill;
+
+    DependencyGraph.replacePatterns = require.requireActual('node-haste/lib/lib/replacePatterns');
 
     // For the polyfillDeps
-    path.join.mockImpl(function(a, b) {
-      return b;
-    });
+    path.join = jest.genMockFn().mockImpl((a, b) => b);
 
     DependencyGraph.prototype.load.mockImpl(() => Promise.resolve());
   });
diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index 7e993a5d7df9..5b9e890241b0 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -11,9 +11,9 @@
 
 const path = require('path');
 const Activity = require('../Activity');
-const DependencyGraph = require('../DependencyResolver/DependencyGraph');
-const replacePatterns = require('../DependencyResolver/lib/replacePatterns');
-const Polyfill = require('../DependencyResolver/Polyfill');
+const DependencyGraph = require('node-haste');
+const replacePatterns = require('node-haste').replacePatterns;
+const Polyfill = require('node-haste').Polyfill;
 const declareOpts = require('../lib/declareOpts');
 const Promise = require('promise');
 
diff --git a/packager/react-packager/src/Server/__tests__/Server-test.js b/packager/react-packager/src/Server/__tests__/Server-test.js
index e6a74aeb0a7b..246397a2c2c8 100644
--- a/packager/react-packager/src/Server/__tests__/Server-test.js
+++ b/packager/react-packager/src/Server/__tests__/Server-test.js
@@ -21,11 +21,12 @@ jest.setMock('worker-farm', function() { return () => {}; })
 const Promise = require('promise');
 
 var Bundler = require('../../Bundler');
-var FileWatcher = require('../../DependencyResolver/FileWatcher');
 var Server = require('../');
 var Server = require('../../Server');
 var AssetServer = require('../../AssetServer');
 
+var FileWatcher;
+
 describe('processRequest', () => {
   var server;
 
@@ -58,6 +59,7 @@ describe('processRequest', () => {
   var triggerFileChange;
 
   beforeEach(() => {
+    FileWatcher = require('node-haste').FileWatcher;
     Bundler.prototype.bundle = jest.genMockFunction().mockImpl(() =>
       Promise.resolve({
         getSource: () => 'this is the source',
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index aa32175aaf17..7db64bf749e0 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -10,8 +10,8 @@
 
 const Activity = require('../Activity');
 const AssetServer = require('../AssetServer');
-const FileWatcher = require('../DependencyResolver/FileWatcher');
-const getPlatformExtension = require('../DependencyResolver/lib/getPlatformExtension');
+const FileWatcher = require('node-haste').FileWatcher;
+const getPlatformExtension = require('node-haste').getPlatformExtension;
 const Bundler = require('../Bundler');
 const Promise = require('promise');
 
diff --git a/packager/react-packager/src/SocketInterface/__tests__/SocketInterface-test.js b/packager/react-packager/src/SocketInterface/__tests__/SocketInterface-test.js
index cf8345b3eb98..b5a7b91605a8 100644
--- a/packager/react-packager/src/SocketInterface/__tests__/SocketInterface-test.js
+++ b/packager/react-packager/src/SocketInterface/__tests__/SocketInterface-test.js
@@ -8,8 +8,7 @@
  */
 'use strict';
 
-jest.setMock('worker-farm', function() { return () => {}; })
-    .setMock('uglify-js')
+jest.setMock('uglify-js')
     .mock('child_process')
     .dontMock('underscore')
     .dontMock('../');
diff --git a/packager/react-packager/src/SocketInterface/__tests__/SocketServer-test.js b/packager/react-packager/src/SocketInterface/__tests__/SocketServer-test.js
index 39c28d965f5e..c269a0e55847 100644
--- a/packager/react-packager/src/SocketInterface/__tests__/SocketServer-test.js
+++ b/packager/react-packager/src/SocketInterface/__tests__/SocketServer-test.js
@@ -8,8 +8,7 @@
  */
 'use strict';
 
-jest.setMock('worker-farm', function() { return () => {}; })
-    .setMock('uglify-js')
+jest.setMock('uglify-js')
     .mock('net')
     .mock('fs')
     .dontMock('../SocketServer');
diff --git a/packager/react-packager/src/__mocks__/fs.js b/packager/react-packager/src/__mocks__/fs.js
index 64b0c9b1896c..adcbf11ad8eb 100644
--- a/packager/react-packager/src/__mocks__/fs.js
+++ b/packager/react-packager/src/__mocks__/fs.js
@@ -8,181 +8,4 @@
  */
 'use strict';
 
-var fs = jest.genMockFromModule('fs');
-
-function asyncCallback(callback) {
-  return function() {
-    setImmediate(() => callback.apply(this, arguments));
-  };
-}
-
-fs.realpath.mockImpl(function(filepath, callback) {
-  callback = asyncCallback(callback);
-  var node;
-  try {
-    node = getToNode(filepath);
-  } catch (e) {
-    return callback(e);
-  }
-  if (node && typeof node === 'object' && node.SYMLINK != null) {
-    return callback(null, node.SYMLINK);
-  }
-  callback(null, filepath);
-});
-
-fs.readdir.mockImpl(function(filepath, callback) {
-  callback = asyncCallback(callback);
-  var node;
-  try {
-    node = getToNode(filepath);
-    if (node && typeof node === 'object' && node.SYMLINK != null) {
-      node = getToNode(node.SYMLINK);
-    }
-  } catch (e) {
-    return callback(e);
-  }
-
-  if (!(node && typeof node === 'object' && node.SYMLINK == null)) {
-    return callback(new Error(filepath + ' is not a directory.'));
-  }
-
-  callback(null, Object.keys(node));
-});
-
-fs.readFile.mockImpl(function(filepath, encoding, callback) {
-  callback = asyncCallback(callback);
-  if (arguments.length === 2) {
-    callback = encoding;
-    encoding = null;
-  }
-
-  try {
-    var node = getToNode(filepath);
-    // dir check
-    if (node && typeof node === 'object' && node.SYMLINK == null) {
-      callback(new Error('Error readFile a dir: ' + filepath));
-    }
-    return callback(null, node);
-  } catch (e) {
-    return callback(e);
-  }
-});
-
-fs.stat.mockImpl(function(filepath, callback) {
-  callback = asyncCallback(callback);
-  var node;
-  try {
-    node = getToNode(filepath);
-  } catch (e) {
-    callback(e);
-    return;
-  }
-
-  var mtime = {
-    getTime: function() {
-      return Math.ceil(Math.random() * 10000000);
-    },
-  };
-
-  if (node.SYMLINK) {
-    fs.stat(node.SYMLINK, callback);
-    return;
-  }
-
-  if (node && typeof node === 'object') {
-    callback(null, {
-      isDirectory: function() {
-        return true;
-      },
-      isSymbolicLink: function() {
-        return false;
-      },
-      mtime: mtime,
-    });
-  } else {
-    callback(null, {
-      isDirectory: function() {
-        return false;
-      },
-      isSymbolicLink: function() {
-        return false;
-      },
-      mtime: mtime,
-    });
-  }
-});
-
-const noop = () => {};
-fs.open.mockImpl(function(path) {
-  const callback = arguments[arguments.length - 1] || noop;
-  let data, error, fd;
-  try {
-    data = getToNode(path);
-  } catch (e) {
-    error = e;
-  }
-
-  if (error || data == null) {
-    error = Error(`ENOENT: no such file or directory, open ${path}`);
-  }
-  if (data != null) {
-    /* global Buffer: true */
-    fd = {
-      buffer: new Buffer(data, 'utf8'),
-      position: 0,
-    };
-  }
-
-  callback(error, fd);
-});
-
-fs.read.mockImpl((fd, buffer, writeOffset, length, position, callback = noop) => {
-  let bytesWritten;
-  try {
-    if (position == null || position < 0) {
-      ({position} = fd);
-    }
-    bytesWritten =
-      fd.buffer.copy(buffer, writeOffset, position, position + length);
-    fd.position = position + bytesWritten;
-  } catch (e) {
-    callback(Error('invalid argument'));
-    return;
-  }
-  callback(null, bytesWritten, buffer);
-});
-
-fs.close.mockImpl((fd, callback = noop) => {
-  try {
-    fd.buffer = fs.position = undefined;
-  } catch (e) {
-    callback(Error('invalid argument'));
-    return;
-  }
-  callback(null);
-});
-
-var filesystem;
-
-fs.__setMockFilesystem = function(object) {
-  filesystem = object;
-  return filesystem;
-};
-
-function getToNode(filepath) {
-  var parts = filepath.split('/');
-  if (parts[0] !== '') {
-    throw new Error('Make sure all paths are absolute.');
-  }
-  var node = filesystem;
-  parts.slice(1).forEach(function(part) {
-    if (node && node.SYMLINK) {
-      node = getToNode(node.SYMLINK);
-    }
-    node = node[part];
-  });
-
-  return node;
-}
-
-module.exports = fs;
+module.exports = require.requireActual('node-haste/mocks/graceful-fs');

From 26402ea0b585f03dba7a2246c9a679305efbca55 Mon Sep 17 00:00:00 2001
From: Eric Vicenti <evv@fb.com>
Date: Thu, 18 Feb 2016 21:55:52 -0800
Subject: [PATCH 1224/1411] Seperate NavigatorIOS Example from UIExplorer
 Navigation

Summary: We want to use a different navigation system for UIExplorer

Reviewed By: javache

Differential Revision: D2948412

fb-gh-sync-id: 43f2ff5e00582f065a992e32ea6d6ef159b92f60
shipit-source-id: 43f2ff5e00582f065a992e32ea6d6ef159b92f60
---
 Examples/UIExplorer/NavigatorIOSExample.js | 109 +++++++++++----------
 1 file changed, 59 insertions(+), 50 deletions(-)

diff --git a/Examples/UIExplorer/NavigatorIOSExample.js b/Examples/UIExplorer/NavigatorIOSExample.js
index 08d227c3f0a0..3c6f19f94dfc 100644
--- a/Examples/UIExplorer/NavigatorIOSExample.js
+++ b/Examples/UIExplorer/NavigatorIOSExample.js
@@ -15,11 +15,12 @@
  */
 'use strict';
 
-var React = require('react-native');
-var ViewExample = require('./ViewExample');
-var createExamplePage = require('./createExamplePage');
-var {
+const React = require('react-native');
+const ViewExample = require('./ViewExample');
+const createExamplePage = require('./createExamplePage');
+const {
   AlertIOS,
+  NavigatorIOS,
   ScrollView,
   StyleSheet,
   Text,
@@ -27,8 +28,7 @@ var {
   View,
 } = React;
 
-var EmptyPage = React.createClass({
-
+const EmptyPage = React.createClass({
   render: function() {
     return (
       <View style={styles.emptyPage}>
@@ -38,41 +38,24 @@ var EmptyPage = React.createClass({
       </View>
     );
   },
-
 });
 
-var NavigatorIOSExample = React.createClass({
-
-  statics: {
-    title: '<NavigatorIOS>',
-    description: 'iOS navigation capabilities',
-  },
-
+const NavigatorIOSExamplePage = React.createClass({
   render: function() {
     var recurseTitle = 'Recurse Navigation';
-    if (!this.props.topExampleRoute) {
+    if (!this.props.depth || this.props.depth === 1) {
       recurseTitle += ' - more examples here';
     }
     return (
       <ScrollView style={styles.list}>
-        <View style={styles.line}/>
-        <View style={styles.group}>
-          <View style={styles.row}>
-            <Text style={styles.rowNote}>
-              See &lt;UIExplorerApp&gt; for top-level usage.
-            </Text>
-          </View>
-        </View>
-        <View style={styles.line}/>
-        <View style={styles.groupSpace}/>
         <View style={styles.line}/>
         <View style={styles.group}>
           {this._renderRow(recurseTitle, () => {
             this.props.navigator.push({
               title: NavigatorIOSExample.title,
-              component: NavigatorIOSExample,
+              component: NavigatorIOSExamplePage,
               backButtonTitle: 'Custom Back',
-              passProps: {topExampleRoute: this.props.topExampleRoute || this.props.route},
+              passProps: {depth: this.props.depth ? this.props.depth + 1 : 1},
             });
           })}
           {this._renderRow('Push View Example', () => {
@@ -122,40 +105,39 @@ var NavigatorIOSExample = React.createClass({
           {this._renderRow('Pop to top', () => {
             this.props.navigator.popToTop();
           })}
-          {this._renderRow('Replace here', () => {
-            var prevRoute = this.props.route;
-            this.props.navigator.replace({
-              title: 'New Navigation',
-              component: EmptyPage,
-              rightButtonTitle: 'Undo',
-              onRightButtonPress: () => this.props.navigator.replace(prevRoute),
-              passProps: {
-                text: 'The component is replaced, but there is currently no ' +
-                  'way to change the right button or title of the current route',
-              }
-            });
-          })}
+          {this._renderReplace()}
           {this._renderReplacePrevious()}
           {this._renderReplacePreviousAndPop()}
-          {this._renderPopToTopNavExample()}
+          {this._renderRow('Exit NavigatorIOS Example', this.props.onExampleExit)}
         </View>
         <View style={styles.line}/>
       </ScrollView>
     );
   },
 
-  _renderPopToTopNavExample: function() {
-    if (!this.props.topExampleRoute) {
+  _renderReplace: function() {
+    if (!this.props.depth) {
+      // this is to avoid replacing the top of the stack
       return null;
     }
-    return this._renderRow('Pop to top NavigatorIOSExample', () => {
-      this.props.navigator.popToRoute(this.props.topExampleRoute);
+    return this._renderRow('Replace here', () => {
+      var prevRoute = this.props.route;
+      this.props.navigator.replace({
+        title: 'New Navigation',
+        component: EmptyPage,
+        rightButtonTitle: 'Undo',
+        onRightButtonPress: () => this.props.navigator.replace(prevRoute),
+        passProps: {
+          text: 'The component is replaced, but there is currently no ' +
+            'way to change the right button or title of the current route',
+        }
+      });
     });
   },
 
   _renderReplacePrevious: function() {
-    if (!this.props.topExampleRoute) {
-      // this is to avoid replacing the UIExplorerList at the top of the stack
+    if (!this.props.depth || this.props.depth < 2) {
+      // this is to avoid replacing the top of the stack
       return null;
     }
     return this._renderRow('Replace previous', () => {
@@ -171,8 +153,8 @@ var NavigatorIOSExample = React.createClass({
   },
 
   _renderReplacePreviousAndPop: function() {
-    if (!this.props.topExampleRoute) {
-      // this is to avoid replacing the UIExplorerList at the top of the stack
+    if (!this.props.depth || this.props.depth < 2) {
+      // this is to avoid replacing the top of the stack
       return null;
     }
     return this._renderRow('Replace previous and pop', () => {
@@ -203,7 +185,34 @@ var NavigatorIOSExample = React.createClass({
   },
 });
 
-var styles = StyleSheet.create({
+const NavigatorIOSExample = React.createClass({
+  statics: {
+    title: '<NavigatorIOS>',
+    description: 'iOS navigation capabilities',
+    external: true,
+  },
+
+  render: function() {
+    const {onExampleExit} = this.props;
+    return (
+      <NavigatorIOS
+        style={styles.container}
+        initialRoute={{
+          title: NavigatorIOSExample.title,
+          component: NavigatorIOSExamplePage,
+          passProps: {onExampleExit},
+        }}
+        itemWrapperStyle={styles.itemWrapper}
+        tintColor="#008888"
+      />
+    );
+  },
+});
+
+const styles = StyleSheet.create({
+  container: {
+    flex: 1,
+  },
   customWrapperStyle: {
     backgroundColor: '#bbdddd',
   },

From a91466f84a178c147e5913be0cea3086c44a4526 Mon Sep 17 00:00:00 2001
From: Eric Vicenti <evv@fb.com>
Date: Fri, 19 Feb 2016 01:24:07 -0800
Subject: [PATCH 1225/1411] Rename NavigationState module to
 NavigationStateUtils

Summary: There is a NavigationState type within this module so the name cannot be shared

Reviewed By: hedgerwang

Differential Revision: D2938311

fb-gh-sync-id: c5208755c9dfa5bf0e67666957c01e203ddd4218
shipit-source-id: c5208755c9dfa5bf0e67666957c01e203ddd4218
---
 .../NavigationTicTacToeExample.js             |  1 -
 .../NavigationExperimental/NavigationCard.js  |  2 +-
 .../NavigationHeader.js                       |  2 +-
 .../NavigationAnimatedView.js                 |  6 +--
 .../NavigationContainer.js                    |  2 +-
 .../NavigationExperimental.js                 |  4 +-
 .../NavigationRootContainer.js                |  2 +-
 ...gationState.js => NavigationStateUtils.js} | 40 +++++++++++++------
 .../NavigationExperimental/NavigationView.js  |  8 ++--
 .../Reducer/NavigationFindReducer.js          |  2 +-
 .../Reducer/NavigationStackReducer.js         |  4 +-
 .../Reducer/NavigationTabsReducer.js          |  4 +-
 ...e-test.js => NavigationStateUtils-test.js} | 12 +++---
 Libraries/react-native/react-native.js.flow   |  1 +
 14 files changed, 52 insertions(+), 38 deletions(-)
 rename Libraries/NavigationExperimental/{NavigationState.js => NavigationStateUtils.js} (78%)
 rename Libraries/NavigationExperimental/__tests__/{NavigationState-test.js => NavigationStateUtils-test.js} (76%)

diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationTicTacToeExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationTicTacToeExample.js
index 898599ad5334..86029ef3b444 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationTicTacToeExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationTicTacToeExample.js
@@ -18,7 +18,6 @@
 
 var React = require('react-native');
 var {
-  // $FlowFixMe : this does exist..
   NavigationExperimental,
   StyleSheet,
   Text,
diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationCard.js b/Libraries/CustomComponents/NavigationExperimental/NavigationCard.js
index 096e99d1c3ea..8907a6e008f1 100644
--- a/Libraries/CustomComponents/NavigationExperimental/NavigationCard.js
+++ b/Libraries/CustomComponents/NavigationExperimental/NavigationCard.js
@@ -40,7 +40,7 @@ const ENABLE_GESTURES = Platform.OS !== 'android';
 
 import type {
   NavigationParentState
-} from 'NavigationState';
+} from 'NavigationStateUtils';
 
 type Layout = {
   initWidth: number,
diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationHeader.js b/Libraries/CustomComponents/NavigationExperimental/NavigationHeader.js
index 98a4c5e9140c..0be15d1894ea 100644
--- a/Libraries/CustomComponents/NavigationExperimental/NavigationHeader.js
+++ b/Libraries/CustomComponents/NavigationExperimental/NavigationHeader.js
@@ -40,7 +40,7 @@ const View = require('View');
 import type {
   NavigationState,
   NavigationParentState
-} from 'NavigationState';
+} from 'NavigationStateUtils';
 
 type Props = {
   navigationState: NavigationParentState,
diff --git a/Libraries/NavigationExperimental/NavigationAnimatedView.js b/Libraries/NavigationExperimental/NavigationAnimatedView.js
index 8e6dce680452..76fcd79604e2 100644
--- a/Libraries/NavigationExperimental/NavigationAnimatedView.js
+++ b/Libraries/NavigationExperimental/NavigationAnimatedView.js
@@ -13,15 +13,15 @@
 
 var Animated = require('Animated');
 var Map = require('Map');
-var NavigationStateUtils = require('NavigationState');
+var NavigationStateUtils = require('NavigationStateUtils');
 var NavigationContainer = require('NavigationContainer');
-var React = require('react-native');
+var React = require('React');
 var View = require('View');
 
 import type {
   NavigationState,
   NavigationParentState,
-} from 'NavigationState';
+} from 'NavigationStateUtils';
 
 type NavigationScene = {
   index: number,
diff --git a/Libraries/NavigationExperimental/NavigationContainer.js b/Libraries/NavigationExperimental/NavigationContainer.js
index 8e178f1c6faa..133b498cb07a 100644
--- a/Libraries/NavigationExperimental/NavigationContainer.js
+++ b/Libraries/NavigationExperimental/NavigationContainer.js
@@ -11,7 +11,7 @@
  */
 'use strict';
 
-var React = require('react-native');
+var React = require('React');
 var NavigationRootContainer = require('NavigationRootContainer');
 
 function createNavigationContainer(Component: React.Component): React.Component {
diff --git a/Libraries/NavigationExperimental/NavigationExperimental.js b/Libraries/NavigationExperimental/NavigationExperimental.js
index 9d37015f6a17..0100fa69ca74 100644
--- a/Libraries/NavigationExperimental/NavigationExperimental.js
+++ b/Libraries/NavigationExperimental/NavigationExperimental.js
@@ -17,12 +17,12 @@ const NavigationContainer = require('NavigationContainer');
 const NavigationHeader = require('NavigationHeader');
 const NavigationRootContainer = require('NavigationRootContainer');
 const NavigationReducer = require('NavigationReducer');
-const NavigationState = require('NavigationState');
+const NavigationStateUtils = require('NavigationStateUtils');
 const NavigationView = require('NavigationView');
 
 const NavigationExperimental = {
   // Core
-  State: NavigationState,
+  StateUtils: NavigationStateUtils,
   Reducer: NavigationReducer,
 
   // Containers
diff --git a/Libraries/NavigationExperimental/NavigationRootContainer.js b/Libraries/NavigationExperimental/NavigationRootContainer.js
index b40c3114fdd3..685fd89c66a0 100644
--- a/Libraries/NavigationExperimental/NavigationRootContainer.js
+++ b/Libraries/NavigationExperimental/NavigationRootContainer.js
@@ -19,7 +19,7 @@ const Platform = require('Platform');
 import type {
   NavigationState,
   NavigationReducer
-} from 'NavigationState';
+} from 'NavigationStateUtils';
 
 export type NavigationRenderer = (
   navigationState: NavigationState,
diff --git a/Libraries/NavigationExperimental/NavigationState.js b/Libraries/NavigationExperimental/NavigationStateUtils.js
similarity index 78%
rename from Libraries/NavigationExperimental/NavigationState.js
rename to Libraries/NavigationExperimental/NavigationStateUtils.js
index d78d3559177c..fb5e2ac06f84 100644
--- a/Libraries/NavigationExperimental/NavigationState.js
+++ b/Libraries/NavigationExperimental/NavigationStateUtils.js
@@ -6,7 +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.
  *
- * @providesModule NavigationState
+ * @providesModule NavigationStateUtils
  * @flow
  */
 'use strict';
@@ -37,7 +37,7 @@ export type NavigationReducerWithDefault = (
   action: ?any
 ) => NavigationState;
 
-export function getParent(state: NavigationState): ?NavigationParentState {
+function getParent(state: NavigationState): ?NavigationParentState {
   if (
     (state instanceof Object) &&
     (state.children instanceof Array) &&
@@ -50,7 +50,7 @@ export function getParent(state: NavigationState): ?NavigationParentState {
   return null;
 }
 
-export function get(state: NavigationState, key: string): ?NavigationState {
+function get(state: NavigationState, key: string): ?NavigationState {
   const parentState = getParent(state);
   if (!parentState) {
     return null;
@@ -59,7 +59,7 @@ export function get(state: NavigationState, key: string): ?NavigationState {
   return childState || null;
 }
 
-export function indexOf(state: NavigationState, key: string): ?number {
+function indexOf(state: NavigationState, key: string): ?number {
   const parentState = getParent(state);
   if (!parentState) {
     return null;
@@ -71,7 +71,7 @@ export function indexOf(state: NavigationState, key: string): ?number {
   return index;
 }
 
-export function push(state: NavigationState, newChildState: NavigationState): NavigationState {
+function push(state: NavigationState, newChildState: NavigationState): NavigationState {
   const parentState = getParent(state);
   if (!parentState) {
     return state;
@@ -87,7 +87,7 @@ export function push(state: NavigationState, newChildState: NavigationState): Na
   };
 }
 
-export function pop(state: NavigationState): NavigationState {
+function pop(state: NavigationState): NavigationState {
   const parentState = getParent(state);
   if (!parentState) {
     return state;
@@ -100,7 +100,7 @@ export function pop(state: NavigationState): NavigationState {
   };
 }
 
-export function reset(state: NavigationState, nextChildren: ?Array<NavigationState>, nextIndex: ?number): NavigationState {
+function reset(state: NavigationState, nextChildren: ?Array<NavigationState>, nextIndex: ?number): NavigationState {
   const parentState = getParent(state);
   if (!parentState) {
     return state;
@@ -117,7 +117,7 @@ export function reset(state: NavigationState, nextChildren: ?Array<NavigationSta
   };
 }
 
-export function set(state: ?NavigationState, key: string, nextChildren: Array<NavigationState>, nextIndex: number): NavigationState {
+function set(state: ?NavigationState, key: string, nextChildren: Array<NavigationState>, nextIndex: number): NavigationState {
   if (!state) {
     return {
       children: nextChildren,
@@ -144,7 +144,7 @@ export function set(state: ?NavigationState, key: string, nextChildren: Array<Na
   };
 }
 
-export function jumpToIndex(state: NavigationState, index: number): NavigationState {
+function jumpToIndex(state: NavigationState, index: number): NavigationState {
   const parentState = getParent(state);
   if (parentState && parentState.index === index) {
     return parentState;
@@ -155,7 +155,7 @@ export function jumpToIndex(state: NavigationState, index: number): NavigationSt
   };
 }
 
-export function jumpTo(state: NavigationState, key: string): NavigationState {
+function jumpTo(state: NavigationState, key: string): NavigationState {
   const parentState = getParent(state);
   if (!parentState) {
     return state;
@@ -171,7 +171,7 @@ export function jumpTo(state: NavigationState, key: string): NavigationState {
   };
 }
 
-export function replaceAt(state: NavigationState, key: string, newState: NavigationState): NavigationState {
+function replaceAt(state: NavigationState, key: string, newState: NavigationState): NavigationState {
   const parentState = getParent(state);
   if (!parentState) {
     return state;
@@ -189,7 +189,7 @@ export function replaceAt(state: NavigationState, key: string, newState: Navigat
   };
 }
 
-export function replaceAtIndex(state: NavigationState, index: number, newState: NavigationState): NavigationState {
+function replaceAtIndex(state: NavigationState, index: number, newState: NavigationState): NavigationState {
   const parentState = getParent(state);
   if (!parentState) {
     return state;
@@ -201,3 +201,19 @@ export function replaceAtIndex(state: NavigationState, index: number, newState:
     children,
   };
 }
+
+const NavigationStateUtils = {
+  getParent,
+  get: get,
+  indexOf,
+  push,
+  pop,
+  reset,
+  set: set,
+  jumpToIndex,
+  jumpTo,
+  replaceAt,
+  replaceAtIndex,
+};
+
+module.exports = NavigationStateUtils;
diff --git a/Libraries/NavigationExperimental/NavigationView.js b/Libraries/NavigationExperimental/NavigationView.js
index 5e0fc8b28f71..5789cfbf3a9e 100644
--- a/Libraries/NavigationExperimental/NavigationView.js
+++ b/Libraries/NavigationExperimental/NavigationView.js
@@ -11,12 +11,10 @@
  */
 'use strict';
 
-var React = require('react-native');
+var React = require('React');
 var NavigationContainer = require('NavigationContainer');
-var {
-  StyleSheet,
-  View,
-} = React;
+var StyleSheet = require('StyleSheet');
+var View = require('View');
 
 var NavigationView = React.createClass({
   propTypes: {
diff --git a/Libraries/NavigationExperimental/Reducer/NavigationFindReducer.js b/Libraries/NavigationExperimental/Reducer/NavigationFindReducer.js
index f0947fd56645..e59405f08442 100644
--- a/Libraries/NavigationExperimental/Reducer/NavigationFindReducer.js
+++ b/Libraries/NavigationExperimental/Reducer/NavigationFindReducer.js
@@ -20,7 +20,7 @@
 import type {
   NavigationState,
   NavigationReducer
-} from 'NavigationState';
+} from 'NavigationStateUtils';
 
 function NavigationFindReducer(reducers: Array<NavigationReducer>): NavigationReducer {
   return function(lastState: ?NavigationState, action: ?any): ?NavigationState {
diff --git a/Libraries/NavigationExperimental/Reducer/NavigationStackReducer.js b/Libraries/NavigationExperimental/Reducer/NavigationStackReducer.js
index 5dcf34966daf..624d822e6513 100644
--- a/Libraries/NavigationExperimental/Reducer/NavigationStackReducer.js
+++ b/Libraries/NavigationExperimental/Reducer/NavigationStackReducer.js
@@ -11,12 +11,12 @@
  */
 'use strict';
 
-var NavigationStateUtils = require('NavigationState');
+var NavigationStateUtils = require('NavigationStateUtils');
 
 import type {
   NavigationState,
   NavigationReducer,
-} from 'NavigationState';
+} from 'NavigationStateUtils';
 
 import type {
   BackAction,
diff --git a/Libraries/NavigationExperimental/Reducer/NavigationTabsReducer.js b/Libraries/NavigationExperimental/Reducer/NavigationTabsReducer.js
index 9d6d76a4ff22..d98a1d91d1c7 100644
--- a/Libraries/NavigationExperimental/Reducer/NavigationTabsReducer.js
+++ b/Libraries/NavigationExperimental/Reducer/NavigationTabsReducer.js
@@ -12,14 +12,14 @@
 'use strict';
 
 const NavigationFindReducer = require('NavigationFindReducer');
-const NavigationStateUtils = require('NavigationState');
+const NavigationStateUtils = require('NavigationStateUtils');
 
 import type {
   NavigationReducer,
   NavigationReducerWithDefault,
   NavigationState,
   NavigationParentState
-} from 'NavigationState';
+} from 'NavigationStateUtils';
 
 const ActionTypes = {
   JUMP_TO: 'react-native/NavigationExperimental/tabs-jumpTo',
diff --git a/Libraries/NavigationExperimental/__tests__/NavigationState-test.js b/Libraries/NavigationExperimental/__tests__/NavigationStateUtils-test.js
similarity index 76%
rename from Libraries/NavigationExperimental/__tests__/NavigationState-test.js
rename to Libraries/NavigationExperimental/__tests__/NavigationStateUtils-test.js
index b28aaaca20dc..702d5937bb20 100644
--- a/Libraries/NavigationExperimental/__tests__/NavigationState-test.js
+++ b/Libraries/NavigationExperimental/__tests__/NavigationStateUtils-test.js
@@ -14,7 +14,7 @@ jest
  .autoMockOff()
  .mock('ErrorUtils');
 
-var NavigationState = require('NavigationState');
+var NavigationStateUtils = require('NavigationStateUtils');
 
 var VALID_PARENT_STATES = [
   {children: ['a','b'], index: 0},
@@ -35,23 +35,23 @@ var INVALID_PARENT_STATES = [
   [],
 ];
 
-describe('NavigationState', () => {
+describe('NavigationStateUtils', () => {
 
   it('identifies parents correctly with getParent', () => {
     for (var i = 0; i <= VALID_PARENT_STATES.length; i++) {
       var navState = VALID_PARENT_STATES[0];
-      expect(NavigationState.getParent(navState)).toBe(navState);
+      expect(NavigationStateUtils.getParent(navState)).toBe(navState);
     }
     for (var i = 0; i <= INVALID_PARENT_STATES.length; i++) {
       var navState = INVALID_PARENT_STATES[0];
-      expect(NavigationState.getParent(navState)).toBe(null);
+      expect(NavigationStateUtils.getParent(navState)).toBe(null);
     }
   });
 
   it('can get children', () => {
     var fooState = {key: 'foo'};
     var navState = {children: [{key: 'foobar'}, fooState], index: 0};
-    expect(NavigationState.get(navState, 'foo')).toBe(fooState);
-    expect(NavigationState.get(navState, 'missing')).toBe(null);
+    expect(NavigationStateUtils.get(navState, 'foo')).toBe(fooState);
+    expect(NavigationStateUtils.get(navState, 'missing')).toBe(null);
   });
 });
diff --git a/Libraries/react-native/react-native.js.flow b/Libraries/react-native/react-native.js.flow
index 6b4f333c03d2..bbe2acdfecc0 100644
--- a/Libraries/react-native/react-native.js.flow
+++ b/Libraries/react-native/react-native.js.flow
@@ -88,6 +88,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
   LayoutAnimation: require('LayoutAnimation'),
   Linking: require('Linking'),
   LinkingIOS: require('LinkingIOS'),
+  NavigationExperimental: require('NavigationExperimental'),
   NetInfo: require('NetInfo'),
   PanResponder: require('PanResponder'),
   PixelRatio: require('PixelRatio'),

From a6a4389bf4a581de5adfe0e5dda4aa4f70438dfc Mon Sep 17 00:00:00 2001
From: Huang Yu <huang@bitgo.com>
Date: Fri, 19 Feb 2016 02:58:27 -0800
Subject: [PATCH 1226/1411] add the ability to create triangles using css
 tricks

Summary:- modify ReactViewBackgroundDrawable.java to make each border a trapezoid
 - disable anti-alias to eliminate white spaces between borders
 - add examples to BorderExample.js (see last one)
Closes https://github.com/facebook/react-native/pull/5911

Differential Revision: D2953734

Pulled By: dmmiller

fb-gh-sync-id: dd103d80dec53ad35c9539ab1ceb93ef857feeb9
shipit-source-id: dd103d80dec53ad35c9539ab1ceb93ef857feeb9
---
 Examples/UIExplorer/BorderExample.js          | 25 ++++++++-
 .../view/ReactViewBackgroundDrawable.java     | 53 +++++++++++++++----
 2 files changed, 67 insertions(+), 11 deletions(-)

diff --git a/Examples/UIExplorer/BorderExample.js b/Examples/UIExplorer/BorderExample.js
index 1c547ea6ea21..2dedfdd8e6ae 100644
--- a/Examples/UIExplorer/BorderExample.js
+++ b/Examples/UIExplorer/BorderExample.js
@@ -110,8 +110,22 @@ var styles = StyleSheet.create({
     borderTopLeftRadius: 10,
     borderBottomRightRadius: 20,
     borderColor: 'black',
-    elevation: 10
-  }
+    elevation: 10,
+  },
+  border11: {
+    width: 0,
+    height: 0,
+    borderStyle: 'solid',
+    overflow: 'hidden',
+    borderTopWidth: 50,
+    borderRightWidth: 0,
+    borderBottomWidth: 50,
+    borderLeftWidth: 100,
+    borderTopColor: 'transparent',
+    borderRightColor: 'transparent',
+    borderBottomColor: 'transparent',
+    borderLeftColor: 'red',
+  },
 });
 
 exports.title = 'Border';
@@ -209,4 +223,11 @@ exports.examples = [
       return <View style={[styles.box, styles.border10]} />;
     }
   },
+  {
+    title: 'CSS Trick - Triangle',
+    description: 'create a triangle by manipulating border colors and widths',
+    render() {
+      return <View style={[styles.border11]} />;
+    }
+  },
 ];
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java
index 742adbd84b1b..fd8961cb8628 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java
@@ -80,6 +80,7 @@ private static enum BorderStyle {
   private @Nullable PathEffect mPathEffectForBorderStyle;
   private @Nullable Path mPathForBorderRadius;
   private @Nullable Path mPathForBorderRadiusOutline;
+  private @Nullable Path mPathForBorder;
   private @Nullable RectF mTempRectForBorderRadius;
   private @Nullable RectF mTempRectForBorderRadiusOutline;
   private boolean mNeedUpdatePathForBorderRadius = false;
@@ -343,30 +344,64 @@ private void drawRectangularBackgroundWithBorders(Canvas canvas) {
       int width = getBounds().width();
       int height = getBounds().height();
 
+      // If the path drawn previously is of the same color,
+      // there would be a slight white space between borders
+      // with anti-alias set to true.
+      // Therefore we need to disable anti-alias, and
+      // after drawing is done, we will re-enable it.
+
+      mPaint.setAntiAlias(false);
+
+      if (mPathForBorder == null) {
+        mPathForBorder = new Path();
+      }
+
       if (borderLeft > 0 && colorLeft != Color.TRANSPARENT) {
         mPaint.setColor(colorLeft);
-        canvas.drawRect(0, borderTop, borderLeft, height - borderBottom, mPaint);
+        mPathForBorder.reset();
+        mPathForBorder.moveTo(0, 0);
+        mPathForBorder.lineTo(borderLeft, borderTop);
+        mPathForBorder.lineTo(borderLeft, height - borderBottom);
+        mPathForBorder.lineTo(0, height);
+        mPathForBorder.lineTo(0, 0);
+        canvas.drawPath(mPathForBorder, mPaint);
       }
 
       if (borderTop > 0 && colorTop != Color.TRANSPARENT) {
         mPaint.setColor(colorTop);
-        canvas.drawRect(0, 0, width, borderTop, mPaint);
+        mPathForBorder.reset();
+        mPathForBorder.moveTo(0, 0);
+        mPathForBorder.lineTo(borderLeft, borderTop);
+        mPathForBorder.lineTo(width - borderRight, borderTop);
+        mPathForBorder.lineTo(width, 0);
+        mPathForBorder.lineTo(0, 0);
+        canvas.drawPath(mPathForBorder, mPaint);
       }
 
       if (borderRight > 0 && colorRight != Color.TRANSPARENT) {
         mPaint.setColor(colorRight);
-        canvas.drawRect(
-            width - borderRight,
-            borderTop,
-            width,
-            height - borderBottom,
-            mPaint);
+        mPathForBorder.reset();
+        mPathForBorder.moveTo(width, 0);
+        mPathForBorder.lineTo(width, height);
+        mPathForBorder.lineTo(width - borderRight, height - borderBottom);
+        mPathForBorder.lineTo(width - borderRight, borderTop);
+        mPathForBorder.lineTo(width, 0);
+        canvas.drawPath(mPathForBorder, mPaint);
       }
 
       if (borderBottom > 0 && colorBottom != Color.TRANSPARENT) {
         mPaint.setColor(colorBottom);
-        canvas.drawRect(0, height - borderBottom, width, height, mPaint);
+        mPathForBorder.reset();
+        mPathForBorder.moveTo(0, height);
+        mPathForBorder.lineTo(width, height);
+        mPathForBorder.lineTo(width - borderRight, height - borderBottom);
+        mPathForBorder.lineTo(borderLeft, height - borderBottom);
+        mPathForBorder.lineTo(0, height);
+        canvas.drawPath(mPathForBorder, mPaint);
       }
+
+      // re-enable anti alias
+      mPaint.setAntiAlias(true);
     }
   }
 

From 0107d1a67bed4447414fd1dd5c72856356116d8d Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Fri, 19 Feb 2016 11:43:54 +0000
Subject: [PATCH 1227/1411] manual sync for D2949054

---
 .../android/support/v7/appcompat-orig}/BUCK           |  6 ------
 .../android/support/v7/appcompat-orig/BUCK            | 11 +++++++++++
 2 files changed, 11 insertions(+), 6 deletions(-)
 rename ReactAndroid/src/main/{third-party/android-support-for-standalone-apps/v7/appcompat => android_res/android/support/v7/appcompat-orig}/BUCK (87%)
 create mode 100644 ReactAndroid/src/main/third-party/android/support/v7/appcompat-orig/BUCK

diff --git a/ReactAndroid/src/main/third-party/android-support-for-standalone-apps/v7/appcompat/BUCK b/ReactAndroid/src/main/android_res/android/support/v7/appcompat-orig/BUCK
similarity index 87%
rename from ReactAndroid/src/main/third-party/android-support-for-standalone-apps/v7/appcompat/BUCK
rename to ReactAndroid/src/main/android_res/android/support/v7/appcompat-orig/BUCK
index 626b8dcdac7a..d0aaa959857b 100644
--- a/ReactAndroid/src/main/third-party/android-support-for-standalone-apps/v7/appcompat/BUCK
+++ b/ReactAndroid/src/main/android_res/android/support/v7/appcompat-orig/BUCK
@@ -1,9 +1,3 @@
-android_prebuilt_aar(
-    name = 'appcompat-23.1',
-    aar = ':appcompat-binary-aar',
-    visibility = ['//ReactAndroid/...',],
-)
-
 # Unpack resources from the appcompat aar and merge their ids into the
 # generated com.facebook.react.R class.
 #
diff --git a/ReactAndroid/src/main/third-party/android/support/v7/appcompat-orig/BUCK b/ReactAndroid/src/main/third-party/android/support/v7/appcompat-orig/BUCK
new file mode 100644
index 000000000000..2d3ae44c64a1
--- /dev/null
+++ b/ReactAndroid/src/main/third-party/android/support/v7/appcompat-orig/BUCK
@@ -0,0 +1,11 @@
+android_prebuilt_aar(
+  name = 'appcompat',
+  aar = ':appcompat-binary-aar',
+  visibility = ['//ReactAndroid/...',],
+)
+
+remote_file(
+  name = 'appcompat-binary-aar',
+  url = 'mvn:com.android.support:appcompat-v7:aar:23.0.1',
+  sha1 = '7d659f671541394a8bc2b9f909950aa2a5ec87ff',
+)

From 44ea74c2c76b058b6e6205414827b8d2e5b68529 Mon Sep 17 00:00:00 2001
From: Christoph Pojer <cpojer@fb.com>
Date: Fri, 19 Feb 2016 04:40:06 -0800
Subject: [PATCH 1228/1411] Update jest to 0.9.0-fb2

Reviewed By: davidaurelio

Differential Revision: D2953741

fb-gh-sync-id: 10a76c7c00f542740eb820c400429ea81a7073ea
shipit-source-id: 10a76c7c00f542740eb820c400429ea81a7073ea
---
 npm-shrinkwrap.json | 244 ++++++++++++++++++++++----------------------
 package.json        |   2 +-
 2 files changed, 125 insertions(+), 121 deletions(-)

diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index a7200713a435..38b617109335 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -122,16 +122,16 @@
           "from": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz"
         },
-        "babylon": {
-          "version": "5.8.29",
-          "from": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz",
-          "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz"
-        },
         "ast-types": {
           "version": "0.8.12",
           "from": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz",
           "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz"
         },
+        "babylon": {
+          "version": "5.8.29",
+          "from": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz",
+          "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz"
+        },
         "globals": {
           "version": "6.4.1",
           "from": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz",
@@ -142,15 +142,15 @@
           "from": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz",
           "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
         },
-        "recast": {
-          "version": "0.10.33",
-          "from": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz",
-          "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
-        },
         "regenerator": {
           "version": "0.8.40",
           "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
           "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
+        },
+        "recast": {
+          "version": "0.10.33",
+          "from": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz",
+          "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
         }
       }
     },
@@ -223,25 +223,30 @@
           "from": "https://registry.npmjs.org/babel-core/-/babel-core-5.8.33.tgz",
           "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-5.8.33.tgz"
         },
+        "babylon": {
+          "version": "5.8.29",
+          "from": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz",
+          "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz"
+        },
         "ast-types": {
           "version": "0.8.12",
           "from": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz",
           "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz"
         },
-        "babylon": {
-          "version": "5.8.29",
-          "from": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz",
-          "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz"
+        "js-tokens": {
+          "version": "1.0.1",
+          "from": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz",
+          "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
         },
         "globals": {
           "version": "6.4.1",
           "from": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz",
           "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
         },
-        "js-tokens": {
-          "version": "1.0.1",
-          "from": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz",
-          "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
+        "regenerator": {
+          "version": "0.8.40",
+          "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
+          "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
         },
         "recast": {
           "version": "0.10.33",
@@ -252,11 +257,6 @@
           "version": "0.5.3",
           "from": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz"
-        },
-        "regenerator": {
-          "version": "0.8.40",
-          "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
-          "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
         }
       }
     },
@@ -1895,51 +1895,51 @@
             }
           }
         },
-        "abbrev": {
-          "version": "1.0.7",
-          "from": "abbrev@1",
-          "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz"
-        },
-        "ansi-regex": {
-          "version": "2.0.0",
-          "from": "ansi-regex@^2.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
-        },
         "ansi": {
           "version": "0.3.0",
           "from": "ansi@~0.3.0",
           "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.0.tgz"
         },
+        "abbrev": {
+          "version": "1.0.7",
+          "from": "abbrev@1",
+          "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz"
+        },
         "ansi-styles": {
           "version": "2.1.0",
           "from": "ansi-styles@^2.1.0",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz"
         },
+        "ansi-regex": {
+          "version": "2.0.0",
+          "from": "ansi-regex@^2.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
+        },
         "are-we-there-yet": {
           "version": "1.0.4",
           "from": "are-we-there-yet@~1.0.0",
           "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.4.tgz"
         },
-        "asn1": {
-          "version": "0.1.11",
-          "from": "asn1@0.1.11",
-          "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
-        },
         "assert-plus": {
           "version": "0.1.5",
           "from": "assert-plus@^0.1.5",
           "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
         },
-        "aws-sign2": {
-          "version": "0.6.0",
-          "from": "aws-sign2@~0.6.0",
-          "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
+        "asn1": {
+          "version": "0.1.11",
+          "from": "asn1@0.1.11",
+          "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
         },
         "async": {
           "version": "1.5.0",
           "from": "async@^1.4.0",
           "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz"
         },
+        "aws-sign2": {
+          "version": "0.6.0",
+          "from": "aws-sign2@~0.6.0",
+          "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
+        },
         "balanced-match": {
           "version": "0.2.1",
           "from": "balanced-match@>=0.2.0 <0.3.0",
@@ -1960,26 +1960,26 @@
           "from": "brace-expansion@>=1.0.0 <2.0.0",
           "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz"
         },
-        "chalk": {
-          "version": "1.1.1",
-          "from": "chalk@^1.1.1",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz"
-        },
         "caseless": {
           "version": "0.11.0",
           "from": "caseless@~0.11.0",
           "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
         },
-        "combined-stream": {
-          "version": "1.0.5",
-          "from": "combined-stream@~1.0.5",
-          "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz"
+        "chalk": {
+          "version": "1.1.1",
+          "from": "chalk@^1.1.1",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz"
         },
         "commander": {
           "version": "2.9.0",
           "from": "commander@^2.8.1",
           "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz"
         },
+        "combined-stream": {
+          "version": "1.0.5",
+          "from": "combined-stream@~1.0.5",
+          "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz"
+        },
         "concat-map": {
           "version": "0.0.1",
           "from": "concat-map@0.0.1",
@@ -2000,16 +2000,16 @@
           "from": "ctype@0.5.3",
           "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz"
         },
-        "debug": {
-          "version": "0.7.4",
-          "from": "debug@~0.7.2",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz"
-        },
         "deep-extend": {
           "version": "0.2.11",
           "from": "deep-extend@~0.2.5",
           "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.2.11.tgz"
         },
+        "debug": {
+          "version": "0.7.4",
+          "from": "debug@~0.7.2",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz"
+        },
         "delayed-stream": {
           "version": "1.0.0",
           "from": "delayed-stream@~1.0.0",
@@ -2055,16 +2055,16 @@
           "from": "generate-function@^2.0.0",
           "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz"
         },
-        "generate-object-property": {
-          "version": "1.2.0",
-          "from": "generate-object-property@^1.1.0",
-          "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz"
-        },
         "graceful-fs": {
           "version": "4.1.2",
           "from": "graceful-fs@4.1",
           "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.2.tgz"
         },
+        "generate-object-property": {
+          "version": "1.2.0",
+          "from": "generate-object-property@^1.1.0",
+          "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz"
+        },
         "har-validator": {
           "version": "2.0.2",
           "from": "har-validator@~2.0.2",
@@ -2075,11 +2075,6 @@
           "from": "graceful-readlink@>= 1.0.0",
           "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
         },
-        "has-unicode": {
-          "version": "1.0.1",
-          "from": "has-unicode@^1.0.0",
-          "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-1.0.1.tgz"
-        },
         "has-ansi": {
           "version": "2.0.0",
           "from": "has-ansi@^2.0.0",
@@ -2090,6 +2085,11 @@
           "from": "hawk@~3.1.0",
           "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.0.tgz"
         },
+        "has-unicode": {
+          "version": "1.0.1",
+          "from": "has-unicode@^1.0.0",
+          "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-1.0.1.tgz"
+        },
         "hoek": {
           "version": "2.16.3",
           "from": "hoek@2.x.x",
@@ -2110,11 +2110,6 @@
           "from": "ini@~1.3.0",
           "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz"
         },
-        "is-my-json-valid": {
-          "version": "2.12.2",
-          "from": "is-my-json-valid@^2.12.2",
-          "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.2.tgz"
-        },
         "is-property": {
           "version": "1.0.2",
           "from": "is-property@^1.0.0",
@@ -2125,51 +2120,56 @@
           "from": "isarray@0.0.1",
           "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
         },
+        "is-my-json-valid": {
+          "version": "2.12.2",
+          "from": "is-my-json-valid@^2.12.2",
+          "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.2.tgz"
+        },
         "isstream": {
           "version": "0.1.2",
           "from": "isstream@~0.1.2",
           "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
         },
-        "json-stringify-safe": {
-          "version": "5.0.1",
-          "from": "json-stringify-safe@~5.0.1",
-          "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
-        },
         "jsonpointer": {
           "version": "2.0.0",
           "from": "jsonpointer@2.0.0",
           "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
         },
-        "lodash._createpadding": {
-          "version": "3.6.1",
-          "from": "lodash._createpadding@^3.0.0",
-          "resolved": "https://registry.npmjs.org/lodash._createpadding/-/lodash._createpadding-3.6.1.tgz"
+        "json-stringify-safe": {
+          "version": "5.0.1",
+          "from": "json-stringify-safe@~5.0.1",
+          "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
         },
         "lodash._basetostring": {
           "version": "3.0.1",
           "from": "lodash._basetostring@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz"
         },
-        "lodash.pad": {
-          "version": "3.1.1",
-          "from": "lodash.pad@^3.0.0",
-          "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-3.1.1.tgz"
+        "lodash._createpadding": {
+          "version": "3.6.1",
+          "from": "lodash._createpadding@^3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash._createpadding/-/lodash._createpadding-3.6.1.tgz"
         },
         "lodash.padleft": {
           "version": "3.1.1",
           "from": "lodash.padleft@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash.padleft/-/lodash.padleft-3.1.1.tgz"
         },
-        "lodash.padright": {
+        "lodash.pad": {
           "version": "3.1.1",
-          "from": "lodash.padright@^3.0.0",
-          "resolved": "https://registry.npmjs.org/lodash.padright/-/lodash.padright-3.1.1.tgz"
+          "from": "lodash.pad@^3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-3.1.1.tgz"
         },
         "lodash.repeat": {
           "version": "3.0.1",
           "from": "lodash.repeat@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash.repeat/-/lodash.repeat-3.0.1.tgz"
         },
+        "lodash.padright": {
+          "version": "3.1.1",
+          "from": "lodash.padright@^3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash.padright/-/lodash.padright-3.1.1.tgz"
+        },
         "mime-db": {
           "version": "1.19.0",
           "from": "mime-db@~1.19.0",
@@ -2190,16 +2190,16 @@
           "from": "mkdirp@>=0.3.0 <0.4.0||>=0.4.0 <0.5.0||>=0.5.0 <0.6.0",
           "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz"
         },
-        "node-uuid": {
-          "version": "1.4.3",
-          "from": "node-uuid@~1.4.3",
-          "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.3.tgz"
-        },
         "npmlog": {
           "version": "1.2.1",
           "from": "npmlog@~1.2.0",
           "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz"
         },
+        "node-uuid": {
+          "version": "1.4.3",
+          "from": "node-uuid@~1.4.3",
+          "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.3.tgz"
+        },
         "oauth-sign": {
           "version": "0.8.0",
           "from": "oauth-sign@~0.8.0",
@@ -2215,16 +2215,16 @@
           "from": "path-is-absolute@>=1.0.0 <2.0.0",
           "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz"
         },
-        "pinkie": {
-          "version": "1.0.0",
-          "from": "pinkie@^1.0.0",
-          "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
-        },
         "pinkie-promise": {
           "version": "1.0.0",
           "from": "pinkie-promise@^1.0.0",
           "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz"
         },
+        "pinkie": {
+          "version": "1.0.0",
+          "from": "pinkie@^1.0.0",
+          "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
+        },
         "qs": {
           "version": "5.2.0",
           "from": "qs@~5.2.0",
@@ -2260,36 +2260,31 @@
           "from": "stringstream@~0.0.4",
           "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
         },
-        "strip-ansi": {
-          "version": "3.0.0",
-          "from": "strip-ansi@^3.0.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz"
+        "supports-color": {
+          "version": "2.0.0",
+          "from": "supports-color@^2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
         },
         "strip-json-comments": {
           "version": "0.1.3",
           "from": "strip-json-comments@0.1.x",
           "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
         },
+        "strip-ansi": {
+          "version": "3.0.0",
+          "from": "strip-ansi@^3.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz"
+        },
         "tar": {
           "version": "2.2.1",
           "from": "tar@~2.2.0",
           "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz"
         },
-        "supports-color": {
-          "version": "2.0.0",
-          "from": "supports-color@^2.0.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
-        },
         "tough-cookie": {
           "version": "2.2.0",
           "from": "tough-cookie@~2.2.0",
           "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.0.tgz"
         },
-        "tunnel-agent": {
-          "version": "0.4.1",
-          "from": "tunnel-agent@~0.4.1",
-          "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz"
-        },
         "uid-number": {
           "version": "0.0.3",
           "from": "uid-number@0.0.3",
@@ -2300,6 +2295,11 @@
           "from": "wrappy@>=1.0.0 <2.0.0",
           "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
         },
+        "tunnel-agent": {
+          "version": "0.4.1",
+          "from": "tunnel-agent@~0.4.1",
+          "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz"
+        },
         "xtend": {
           "version": "4.0.1",
           "from": "xtend@^4.0.0",
@@ -2641,8 +2641,8 @@
       "resolved": "https://registry.npmjs.org/isobject/-/isobject-1.0.2.tgz"
     },
     "jest-cli": {
-      "version": "0.9.0-fb1",
-      "from": "jest-cli@0.9.0-fb1",
+      "version": "0.9.0-fb2",
+      "from": "jest-cli@next",
       "dependencies": {
         "cover": {
           "version": "0.2.9",
@@ -2730,7 +2730,7 @@
                     },
                     "deep-is": {
                       "version": "0.1.3",
-                      "from": "deep-is@>=0.1.2 <0.2.0",
+                      "from": "deep-is@>=0.1.3 <0.2.0",
                       "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz"
                     },
                     "wordwrap": {
@@ -2908,7 +2908,7 @@
                     },
                     "deep-is": {
                       "version": "0.1.3",
-                      "from": "deep-is@>=0.1.2 <0.2.0",
+                      "from": "deep-is@>=0.1.3 <0.2.0",
                       "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz"
                     },
                     "type-check": {
@@ -3031,9 +3031,9 @@
                   "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz",
                   "dependencies": {
                     "is-my-json-valid": {
-                      "version": "2.12.4",
+                      "version": "2.13.0",
                       "from": "is-my-json-valid@>=2.12.4 <3.0.0",
-                      "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.4.tgz",
+                      "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.13.0.tgz",
                       "dependencies": {
                         "generate-function": {
                           "version": "2.0.0",
@@ -3272,9 +3272,8 @@
           }
         },
         "node-haste": {
-          "version": "2.0.0-alpha19",
-          "from": "node-haste@2.0.0-alpha19",
-          "resolved": "https://registry.npmjs.org/node-haste/-/node-haste-2.0.0-alpha19.tgz",
+          "version": "2.2.0",
+          "from": "node-haste@>=2.2.0 <3.0.0",
           "dependencies": {
             "sane": {
               "version": "1.3.1",
@@ -3340,6 +3339,11 @@
                   "resolved": "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz"
                 }
               }
+            },
+            "throat": {
+              "version": "2.0.2",
+              "from": "throat@>=2.0.2 <3.0.0",
+              "resolved": "https://registry.npmjs.org/throat/-/throat-2.0.2.tgz"
             }
           }
         },
diff --git a/package.json b/package.json
index 2ed9714e13ff..25f523657208 100644
--- a/package.json
+++ b/package.json
@@ -172,7 +172,7 @@
     "yeoman-generator": "^0.20.3"
   },
   "devDependencies": {
-    "jest-cli": "0.9.0-fb1",
+    "jest-cli": "0.9.0-fb2",
     "babel-eslint": "4.1.4",
     "eslint": "1.3.1",
     "eslint-plugin-react": "3.3.1",

From b51697645792b35214615552dbb66e6b262ec477 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Fri, 19 Feb 2016 05:02:27 -0800
Subject: [PATCH 1229/1411] Support custom ScrollView implementations in
 ListView

Summary: See https://github.com/facebook/react-native/commit/e9f64b2f3f3ff1e71e8592e4522ba1cf25c3c5b0#commitcomment-16166567

Reviewed By: tadeuzagallo

Differential Revision: D2953787

fb-gh-sync-id: b8978b3fa6ae9e848be918cc707335a06ea56cf6
shipit-source-id: b8978b3fa6ae9e848be918cc707335a06ea56cf6
---
 Libraries/CustomComponents/ListView/ListView.js | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js
index c10717b5a782..b4931fedb9c2 100644
--- a/Libraries/CustomComponents/ListView/ListView.js
+++ b/Libraries/CustomComponents/ListView/ListView.js
@@ -231,14 +231,18 @@ var ListView = React.createClass({
 
   /**
    * Provides a handle to the underlying scroll responder.
+   * Note that the view in `SCROLLVIEW_REF` may not be a `ScrollView`, so we
+   * need to check that it responds to `getScrollResponder` before calling it.
    */
   getScrollResponder: function() {
-    return this.refs[SCROLLVIEW_REF] && 
+    return this.refs[SCROLLVIEW_REF] &&
+      this.refs[SCROLLVIEW_REF].getScrollResponder &&
       this.refs[SCROLLVIEW_REF].getScrollResponder();
   },
 
   scrollTo: function(...args) {
-    this.refs[SCROLLVIEW_REF] && 
+    this.refs[SCROLLVIEW_REF] &&
+      this.refs[SCROLLVIEW_REF].scrollTo &&
       this.refs[SCROLLVIEW_REF].scrollTo(...args);
   },
 

From 19a1c4c22985ea6c7b475db71681bfc4dac4f1e0 Mon Sep 17 00:00:00 2001
From: Felix Oghina <foghina@fb.com>
Date: Fri, 19 Feb 2016 05:06:15 -0800
Subject: [PATCH 1230/1411] use a static react instance holder

Reviewed By: astreet

Differential Revision: D2937867

fb-gh-sync-id: cdda79929fa5993b6ef159aa73922909017c2ded
shipit-source-id: cdda79929fa5993b6ef159aa73922909017c2ded
---
 .../react/testing/ReactAppTestActivity.java   |  10 +-
 .../testing/ReactIntegrationTestCase.java     |   2 +-
 .../com/facebook/react/LifecycleState.java    |   2 +-
 .../com/facebook/react/ReactActivity.java     |   6 +-
 .../facebook/react/ReactInstanceManager.java  |  27 ++++-
 .../react/ReactInstanceManagerImpl.java       | 106 +++++++++++++-----
 .../facebook/react/bridge/ReactContext.java   |  16 ++-
 7 files changed, 123 insertions(+), 46 deletions(-)

diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java
index 9297f59a2460..f8cdb6f117da 100644
--- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java
@@ -75,7 +75,7 @@ protected void onPause() {
     overridePendingTransition(0, 0);
 
     if (mReactInstanceManager != null) {
-      mReactInstanceManager.onPause();
+      mReactInstanceManager.onHostPause();
     }
   }
 
@@ -86,7 +86,7 @@ protected void onResume() {
     mLifecycleState = LifecycleState.RESUMED;
 
     if (mReactInstanceManager != null) {
-      mReactInstanceManager.onResume(this, this);
+      mReactInstanceManager.onHostResume(this, this);
     }
   }
 
@@ -96,7 +96,7 @@ protected void onDestroy() {
     mDestroyCountDownLatch.countDown();
 
     if (mReactInstanceManager != null) {
-      mReactInstanceManager.onDestroy();
+      mReactInstanceManager.destroy();
     }
   }
 
@@ -114,7 +114,7 @@ public void loadApp(String appKey, ReactInstanceSpecForTest spec, String bundleN
 
   public void resetRootViewForScreenshotTests() {
     if (mReactInstanceManager != null) {
-      mReactInstanceManager.onDestroy();
+      mReactInstanceManager.destroy();
       mReactInstanceManager = null;
     }
     mReactRootView = new ReactRootView(this);
@@ -148,7 +148,7 @@ public void loadApp(
         .setInitialLifecycleState(mLifecycleState);
 
     mReactInstanceManager = builder.build();
-    mReactInstanceManager.onResume(this, this);
+    mReactInstanceManager.onHostResume(this, this);
 
     Assertions.assertNotNull(mReactRootView).getViewTreeObserver().addOnGlobalLayoutListener(
         new ViewTreeObserver.OnGlobalLayoutListener() {
diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java
index 5161a4aaab60..e1312d36a6e1 100644
--- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java
@@ -74,7 +74,7 @@ public void shutDownContext() {
         @Override
         public void run() {
           if (contextToDestroy != null) {
-            contextToDestroy.onDestroy();
+            contextToDestroy.destroy();
           }
         }
       });
diff --git a/ReactAndroid/src/main/java/com/facebook/react/LifecycleState.java b/ReactAndroid/src/main/java/com/facebook/react/LifecycleState.java
index f8598e908845..068bd063fb0c 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/LifecycleState.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/LifecycleState.java
@@ -21,7 +21,7 @@
  * RESUMED
  */
 public enum LifecycleState {
-
+  BEFORE_CREATE,
   BEFORE_RESUME,
   RESUMED,
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java b/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java
index c9679fafb96d..d708e7dc2e6b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java
@@ -150,7 +150,7 @@ protected void onPause() {
     mLifecycleState = LifecycleState.BEFORE_RESUME;
 
     if (mReactInstanceManager != null) {
-      mReactInstanceManager.onPause();
+      mReactInstanceManager.onHostPause();
     }
   }
 
@@ -161,7 +161,7 @@ protected void onResume() {
     mLifecycleState = LifecycleState.RESUMED;
 
     if (mReactInstanceManager != null) {
-      mReactInstanceManager.onResume(this, this);
+      mReactInstanceManager.onHostResume(this, this);
     }
   }
 
@@ -170,7 +170,7 @@ protected void onDestroy() {
     super.onDestroy();
 
     if (mReactInstanceManager != null) {
-      mReactInstanceManager.onDestroy();
+      mReactInstanceManager.destroy();
     }
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
index 1bcd68cc22ac..9ef96f5b80fb 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
@@ -41,8 +41,8 @@
  * The lifecycle of the instance of {@link ReactInstanceManager} should be bound to the activity
  * that owns the {@link ReactRootView} that is used to render react application using this
  * instance manager (see {@link ReactRootView#startReactApplication}). It's required to pass
- * owning activity's lifecycle events to the instance manager (see {@link #onPause},
- * {@link #onDestroy} and {@link #onResume}).
+ * owning activity's lifecycle events to the instance manager (see {@link #onHostPause},
+ * {@link #onHostDestroy} and {@link #onHostResume}).
  *
  * Ideally, this would be an interface, but because of the API used by earlier versions, it has to
  * have a static method, and so cannot (in Java < 8), be one.
@@ -84,22 +84,32 @@ public interface ReactInstanceEventListener {
    * consume the event, mDefaultBackButtonImpl will be invoked at the end of the round trip to JS.
    */
   public abstract void onBackPressed();
-  public abstract void onPause();
+
+  /**
+   * Call this from {@link Activity#onPause()}. This notifies any listening modules so they can do
+   * any necessary cleanup.
+   */
+  public abstract void onHostPause();
   /**
    * Use this method when the activity resumes to enable invoking the back button directly from JS.
    *
    * This method retains an instance to provided mDefaultBackButtonImpl. Thus it's
    * important to pass from the activity instance that owns this particular instance of {@link
-   * ReactInstanceManager}, so that once this instance receive {@link #onDestroy} event it will
+   * ReactInstanceManager}, so that once this instance receive {@link #onHostDestroy} event it will
    * clear the reference to that defaultBackButtonImpl.
    *
    * @param defaultBackButtonImpl a {@link DefaultHardwareBackBtnHandler} from an Activity that owns
    * this instance of {@link ReactInstanceManager}.
    */
-  public abstract void onResume(
+  public abstract void onHostResume(
     Activity activity,
     DefaultHardwareBackBtnHandler defaultBackButtonImpl);
-  public abstract void onDestroy();
+
+  /**
+   * Call this from {@link Activity#onDestroy()}. This notifies any listening modules so they can do
+   * any necessary cleanup.
+   */
+  public abstract void onHostDestroy();
   public abstract void onActivityResult(int requestCode, int resultCode, Intent data);
   public abstract void showDevOptionsDialog();
 
@@ -125,6 +135,11 @@ public abstract void onResume(
    */
   public abstract void detachRootView(ReactRootView rootView);
 
+  /**
+   * Destroy this React instance and the attached JS context.
+   */
+  public abstract void destroy();
+
   /**
    * Uses configured {@link ReactPackage} instances to create all view managers
    */
diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index 1b8ac840abfa..63380ecb05e3 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -18,8 +18,6 @@
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentLinkedQueue;
 
 import android.app.Activity;
 import android.app.Application;
@@ -73,7 +71,18 @@
 import com.facebook.soloader.SoLoader;
 import com.facebook.systrace.Systrace;
 
-import static com.facebook.react.bridge.ReactMarkerConstants.*;
+import static com.facebook.react.bridge.ReactMarkerConstants.BUILD_JS_MODULE_CONFIG_END;
+import static com.facebook.react.bridge.ReactMarkerConstants.BUILD_JS_MODULE_CONFIG_START;
+import static com.facebook.react.bridge.ReactMarkerConstants.BUILD_NATIVE_MODULE_REGISTRY_END;
+import static com.facebook.react.bridge.ReactMarkerConstants.BUILD_NATIVE_MODULE_REGISTRY_START;
+import static com.facebook.react.bridge.ReactMarkerConstants.CREATE_CATALYST_INSTANCE_END;
+import static com.facebook.react.bridge.ReactMarkerConstants.CREATE_CATALYST_INSTANCE_START;
+import static com.facebook.react.bridge.ReactMarkerConstants.CREATE_REACT_CONTEXT_END;
+import static com.facebook.react.bridge.ReactMarkerConstants.CREATE_REACT_CONTEXT_START;
+import static com.facebook.react.bridge.ReactMarkerConstants.PROCESS_PACKAGES_END;
+import static com.facebook.react.bridge.ReactMarkerConstants.PROCESS_PACKAGES_START;
+import static com.facebook.react.bridge.ReactMarkerConstants.RUN_JS_BUNDLE_END;
+import static com.facebook.react.bridge.ReactMarkerConstants.RUN_JS_BUNDLE_START;
 
 /**
  * This class is managing instances of {@link CatalystInstance}. It expose a way to configure
@@ -87,8 +96,8 @@
  * The lifecycle of the instance of {@link ReactInstanceManagerImpl} should be bound to the activity
  * that owns the {@link ReactRootView} that is used to render react application using this
  * instance manager (see {@link ReactRootView#startReactApplication}). It's required to pass
- * owning activity's lifecycle events to the instance manager (see {@link #onPause},
- * {@link #onDestroy} and {@link #onResume}).
+ * owning activity's lifecycle events to the instance manager (see {@link #onHostPause},
+ * {@link #onHostDestroy} and {@link #onHostResume}).
  *
  * To instantiate an instance of this class use {@link #builder}.
  */
@@ -458,20 +467,16 @@ private void toggleElementInspector() {
   }
 
   @Override
-  public void onPause() {
+  public void onHostPause() {
     UiThreadUtil.assertOnUiThread();
 
-    mLifecycleState = LifecycleState.BEFORE_RESUME;
-
     mDefaultBackButtonImpl = null;
     if (mUseDeveloperSupport) {
       mDevSupportManager.setDevSupportEnabled(false);
     }
 
+    moveToBeforeResumeLifecycleState();
     mCurrentActivity = null;
-    if (mCurrentReactContext != null) {
-      mCurrentReactContext.onPause();
-    }
   }
 
   /**
@@ -479,17 +484,16 @@ public void onPause() {
    *
    * This method retains an instance to provided mDefaultBackButtonImpl. Thus it's
    * important to pass from the activity instance that owns this particular instance of {@link
-   * ReactInstanceManagerImpl}, so that once this instance receive {@link #onDestroy} event it will
+   * ReactInstanceManagerImpl}, so that once this instance receive {@link #onHostDestroy} event it will
    * clear the reference to that defaultBackButtonImpl.
    *
    * @param defaultBackButtonImpl a {@link DefaultHardwareBackBtnHandler} from an Activity that owns
    * this instance of {@link ReactInstanceManagerImpl}.
    */
   @Override
-  public void onResume(Activity activity, DefaultHardwareBackBtnHandler defaultBackButtonImpl) {
+  public void onHostResume(Activity activity, DefaultHardwareBackBtnHandler defaultBackButtonImpl) {
     UiThreadUtil.assertOnUiThread();
 
-    mLifecycleState = LifecycleState.RESUMED;
 
     mDefaultBackButtonImpl = defaultBackButtonImpl;
     if (mUseDeveloperSupport) {
@@ -497,32 +501,82 @@ public void onResume(Activity activity, DefaultHardwareBackBtnHandler defaultBac
     }
 
     mCurrentActivity = activity;
-    if (mCurrentReactContext != null) {
-      mCurrentReactContext.onResume(activity);
+    moveToResumedLifecycleState(false);
+  }
+
+  @Override
+  public void onHostDestroy() {
+    UiThreadUtil.assertOnUiThread();
+
+    if (mUseDeveloperSupport) {
+      mDevSupportManager.setDevSupportEnabled(false);
     }
+
+    moveToBeforeCreateLifecycleState();
+    mCurrentActivity = null;
   }
 
   @Override
-  public void onDestroy() {
+  public void destroy() {
     UiThreadUtil.assertOnUiThread();
 
+    if (mUseDeveloperSupport) {
+      mDevSupportManager.setDevSupportEnabled(false);
+    }
+
+    moveToBeforeCreateLifecycleState();
+
     if (mReactContextInitAsyncTask != null) {
       mReactContextInitAsyncTask.cancel(true);
     }
 
     mMemoryPressureRouter.destroy(mApplicationContext);
-    if (mUseDeveloperSupport) {
-      mDevSupportManager.setDevSupportEnabled(false);
-    }
 
     if (mCurrentReactContext != null) {
-      mCurrentReactContext.onDestroy();
+      mCurrentReactContext.destroy();
       mCurrentReactContext = null;
       mHasStartedCreatingInitialContext = false;
     }
     mCurrentActivity = null;
   }
 
+  private void moveToResumedLifecycleState(boolean force) {
+    if (mCurrentReactContext != null) {
+      // we currently don't have an onCreate callback so we call onResume for both transitions
+      if (force ||
+          mLifecycleState == LifecycleState.BEFORE_RESUME ||
+          mLifecycleState == LifecycleState.BEFORE_CREATE) {
+        mCurrentReactContext.onHostResume(mCurrentActivity);
+      }
+    }
+    mLifecycleState = LifecycleState.RESUMED;
+  }
+
+  private void moveToBeforeResumeLifecycleState() {
+    if (mCurrentReactContext != null) {
+      if (mLifecycleState == LifecycleState.BEFORE_CREATE) {
+        mCurrentReactContext.onHostResume(mCurrentActivity);
+        mCurrentReactContext.onHostPause();
+      } else if (mLifecycleState == LifecycleState.RESUMED) {
+        mCurrentReactContext.onHostPause();
+      }
+    }
+    mLifecycleState = LifecycleState.BEFORE_RESUME;
+  }
+
+  private void moveToBeforeCreateLifecycleState() {
+    if (mCurrentReactContext != null) {
+      if (mLifecycleState == LifecycleState.RESUMED) {
+        mCurrentReactContext.onHostPause();
+        mLifecycleState = LifecycleState.BEFORE_RESUME;
+      }
+      if (mLifecycleState == LifecycleState.BEFORE_RESUME) {
+        mCurrentReactContext.onHostDestroy();
+      }
+    }
+    mLifecycleState = LifecycleState.BEFORE_CREATE;
+  }
+
   @Override
   public void onActivityResult(int requestCode, int resultCode, Intent data) {
     if (mCurrentReactContext != null) {
@@ -657,7 +711,7 @@ private void setupReactContext(ReactApplicationContext reactContext) {
     catalystInstance.initialize();
     mDevSupportManager.onNewReactContextCreated(reactContext);
     mMemoryPressureRouter.onNewReactContextCreated(reactContext);
-    moveReactContextToCurrentLifecycleState(reactContext);
+    moveReactContextToCurrentLifecycleState();
 
     for (ReactRootView rootView : mAttachedRootViews) {
       attachMeasuredRootViewToInstance(rootView, catalystInstance);
@@ -706,12 +760,12 @@ private void detachViewFromInstance(
   private void tearDownReactContext(ReactContext reactContext) {
     UiThreadUtil.assertOnUiThread();
     if (mLifecycleState == LifecycleState.RESUMED) {
-      reactContext.onPause();
+      reactContext.onHostPause();
     }
     for (ReactRootView rootView : mAttachedRootViews) {
       detachViewFromInstance(rootView, reactContext.getCatalystInstance());
     }
-    reactContext.onDestroy();
+    reactContext.destroy();
     mDevSupportManager.onReactInstanceDestroyed(reactContext);
     mMemoryPressureRouter.onReactInstanceDestroyed();
   }
@@ -831,9 +885,9 @@ private void processPackage(
     }
   }
 
-  private void moveReactContextToCurrentLifecycleState(ReactApplicationContext reactContext) {
+  private void moveReactContextToCurrentLifecycleState() {
     if (mLifecycleState == LifecycleState.RESUMED) {
-      reactContext.onResume(mCurrentActivity);
+      moveToResumedLifecycleState(true);
     }
   }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java
index 084ed5c20150..4ef692a8bdd1 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java
@@ -133,7 +133,7 @@ public void removeActivityEventListener(ActivityEventListener listener) {
   /**
    * Should be called by the hosting Fragment in {@link Fragment#onResume}
    */
-  public void onResume(@Nullable Activity activity) {
+  public void onHostResume(@Nullable Activity activity) {
     UiThreadUtil.assertOnUiThread();
     mCurrentActivity = activity;
     for (LifecycleEventListener listener : mLifecycleEventListeners) {
@@ -144,7 +144,7 @@ public void onResume(@Nullable Activity activity) {
   /**
    * Should be called by the hosting Fragment in {@link Fragment#onPause}
    */
-  public void onPause() {
+  public void onHostPause() {
     UiThreadUtil.assertOnUiThread();
     for (LifecycleEventListener listener : mLifecycleEventListeners) {
       listener.onHostPause();
@@ -154,15 +154,23 @@ public void onPause() {
   /**
    * Should be called by the hosting Fragment in {@link Fragment#onDestroy}
    */
-  public void onDestroy() {
+  public void onHostDestroy() {
     UiThreadUtil.assertOnUiThread();
     for (LifecycleEventListener listener : mLifecycleEventListeners) {
       listener.onHostDestroy();
     }
+    mCurrentActivity = null;
+  }
+
+  /**
+   * Destroy this instance, making it unusable.
+   */
+  public void destroy() {
+    UiThreadUtil.assertOnUiThread();
+
     if (mCatalystInstance != null) {
       mCatalystInstance.destroy();
     }
-    mCurrentActivity = null;
   }
 
   /**

From 78a9125de87006c0da40edcd5d6029d360247ded Mon Sep 17 00:00:00 2001
From: Jack Wink <jackwink@umich.edu>
Date: Fri, 19 Feb 2016 05:08:11 -0800
Subject: [PATCH 1231/1411] Update `ScrollResponder.js` to use new `scrollTo`
 API

Summary:`scrollResponderInputMeasureAndScrollToKeyboard` is the only non-deprecated method in `ScrollResponder.js` that doesn't use the [new `scrollTo` API](https://github.com/facebook/react-native/commit/6941c4e027abb582d7cef0e7c3b9b7ebf51bc070). The other method that uses the deprecated API (`scrollResponderScrollWithoutAnimationTo`) is also deprecated, so it has been left unaltered.
Closes https://github.com/facebook/react-native/pull/5990

Differential Revision: D2953916

Pulled By: nicklockwood

fb-gh-sync-id: d692c598e6b85d1050e58b87146d01b031653a49
shipit-source-id: d692c598e6b85d1050e58b87146d01b031653a49
---
 Libraries/Components/ScrollResponder.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/Components/ScrollResponder.js b/Libraries/Components/ScrollResponder.js
index 52c6c946b862..c37de7ba5ebf 100644
--- a/Libraries/Components/ScrollResponder.js
+++ b/Libraries/Components/ScrollResponder.js
@@ -461,7 +461,7 @@ var ScrollResponderMixin = {
     if (this.preventNegativeScrollOffset) {
       scrollOffsetY = Math.max(0, scrollOffsetY);
     }
-    this.scrollResponderScrollTo(0, scrollOffsetY);
+    this.scrollResponderScrollTo({x: 0, y: scrollOffsetY, animated: true});
 
     this.additionalOffset = 0;
     this.preventNegativeScrollOffset = false;

From 183d6a088cbc13f5e123a54cbe63430d92450e96 Mon Sep 17 00:00:00 2001
From: Alonso Holmes <hello@alonso.io>
Date: Fri, 19 Feb 2016 05:18:24 -0800
Subject: [PATCH 1232/1411] Adds category and alertAction properties to local
 notification details object

Summary:In order to use iOS notification actions with local notifications, we need to be able to specify a category string. This PR adds a category property to the `details` object used to create a local notification.

I also added support for the `alertAction` property, which is used to control the "slide to {alertAction}" text beneath the notification.

Finally, I added the doc for `userInfo` to `presentLocalNotification` (previously was only documented for `scheduleLocalNotification`.

**Test plan (required)**

I implemented the example from the [react-native-ios-notification-actions README](https://github.com/holmesal/react-native-ios-notification-actions), and created a couple of actions and grouped them under a category with identifier `something_happened`.

Prior to the changes in this PR, the shown local notification would not contain any actions.

With the changes in this PR, the shown local notification contains the specified actions.

Like so:
![demo](https://camo.githubusercontent.com/c4a86
Closes https://github.com/facebook/react-native/pull/5994

Differential Revision: D2953919

Pulled By: nicklockwood

fb-gh-sync-id: a05a9ea9ae8c150ff0714e106410e094c2747eca
shipit-source-id: a05a9ea9ae8c150ff0714e106410e094c2747eca
---
 Libraries/PushNotificationIOS/PushNotificationIOS.js       | 5 +++++
 Libraries/PushNotificationIOS/RCTPushNotificationManager.m | 2 ++
 2 files changed, 7 insertions(+)

diff --git a/Libraries/PushNotificationIOS/PushNotificationIOS.js b/Libraries/PushNotificationIOS/PushNotificationIOS.js
index a4adace18ac8..c93f644a43f6 100644
--- a/Libraries/PushNotificationIOS/PushNotificationIOS.js
+++ b/Libraries/PushNotificationIOS/PushNotificationIOS.js
@@ -79,7 +79,10 @@ class PushNotificationIOS {
    * details is an object containing:
    *
    * - `alertBody` : The message displayed in the notification alert.
+   * - `alertAction` : The "action" displayed beneath an actionable notification. Defaults to "view";
    * - `soundName` : The sound played when the notification is fired (optional).
+   * - `category`  : The category of this notification, required for actionable notifications (optional).
+   * - `userInfo`  : An optional object containing additional notification data.
    */
   static presentLocalNotification(details: Object) {
     RCTPushNotificationManager.presentLocalNotification(details);
@@ -92,7 +95,9 @@ class PushNotificationIOS {
    *
    * - `fireDate` : The date and time when the system should deliver the notification.
    * - `alertBody` : The message displayed in the notification alert.
+   * - `alertAction` : The "action" displayed beneath an actionable notification. Defaults to "view";
    * - `soundName` : The sound played when the notification is fired (optional).
+   * - `category`  : The category of this notification, required for actionable notifications (optional).
    * - `userInfo` : An optional object containing additional notification data.
    */
   static scheduleLocalNotification(details: Object) {
diff --git a/Libraries/PushNotificationIOS/RCTPushNotificationManager.m b/Libraries/PushNotificationIOS/RCTPushNotificationManager.m
index e9c68a5ec6f0..86c9a37ad209 100644
--- a/Libraries/PushNotificationIOS/RCTPushNotificationManager.m
+++ b/Libraries/PushNotificationIOS/RCTPushNotificationManager.m
@@ -36,8 +36,10 @@ + (UILocalNotification *)UILocalNotification:(id)json
   UILocalNotification *notification = [UILocalNotification new];
   notification.fireDate = [RCTConvert NSDate:details[@"fireDate"]] ?: [NSDate date];
   notification.alertBody = [RCTConvert NSString:details[@"alertBody"]];
+  notification.alertAction = [RCTConvert NSString:details[@"alertAction"]];
   notification.soundName = [RCTConvert NSString:details[@"soundName"]] ?: UILocalNotificationDefaultSoundName;
   notification.userInfo = [RCTConvert NSDictionary:details[@"userInfo"]];
+  notification.category = [RCTConvert NSString:details[@"category"]];
   return notification;
 }
 

From 671b975d92a462be63cb8edad45b455da2e81d5d Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Fri, 19 Feb 2016 05:54:46 -0800
Subject: [PATCH 1233/1411] Fix a bug with ListView with sticky headers +
 RefreshControl

Summary:The bug is caused by a weird race condition. What happens is that when calling `UIRefreshControl#endRefreshing` the `UIScrollView` delegate `scrollViewDidScroll` function is called synchronously and then `dockClosestSectionHeader` crashes because the sticky header indexes are updated but not the contentView children.

I fixed it by adding an updating property on `RCTRefreshControl` and setting it before calling `endRefreshing` so we can know not to call `dockClosestSectionHeader` at that moment.

Tested with both `RefreshControl` and `onRefreshStart` prop.

I reproduced the bug by replacing ListViewExample.js in UIExplorer with https://gist.github.com/janicduplessis/05fc58e852f3e80e51b9

Fixes #5440

cc nicklockwood
Closes https://github.com/facebook/react-native/pull/5445

Differential Revision: D2953984

Pulled By: nicklockwood

fb-gh-sync-id: c17a6a75ab31ef54d478706ed17a8115a11d734e
shipit-source-id: c17a6a75ab31ef54d478706ed17a8115a11d734e
---
 React/Views/RCTRefreshControl.m |  6 ++----
 React/Views/RCTScrollView.m     | 23 ++++++++++++++++++-----
 2 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/React/Views/RCTRefreshControl.m b/React/Views/RCTRefreshControl.m
index b066f1b632af..282cd7f30308 100644
--- a/React/Views/RCTRefreshControl.m
+++ b/React/Views/RCTRefreshControl.m
@@ -30,7 +30,7 @@ - (instancetype)init
 - (void)layoutSubviews
 {
   [super layoutSubviews];
-  
+
   // If the control is refreshing when mounted we need to call
   // beginRefreshing in layoutSubview or it doesn't work.
   if (_isInitialRender && _initialRefreshingState) {
@@ -46,9 +46,7 @@ - (void)beginRefreshing
   CGPoint offset = {scrollView.contentOffset.x, scrollView.contentOffset.y - self.frame.size.height};
   // Don't animate when the prop is set initialy.
   if (_isInitialRender) {
-    // Must use `[scrollView setContentOffset:offset animated:NO]` instead of just setting
-    // `scrollview.contentOffset` or it doesn't work, don't ask me why!
-    [scrollView setContentOffset:offset animated:NO];
+    scrollView.contentOffset = offset;
     [super beginRefreshing];
   } else {
     // `beginRefreshing` must be called after the animation is done. This is why it is impossible
diff --git a/React/Views/RCTScrollView.m b/React/Views/RCTScrollView.m
index 4cc9d4bc871c..af0091e03a71 100644
--- a/React/Views/RCTScrollView.m
+++ b/React/Views/RCTScrollView.m
@@ -145,7 +145,7 @@ @interface RCTCustomScrollView : UIScrollView<UIGestureRecognizerDelegate>
 
 @property (nonatomic, copy) NSIndexSet *stickyHeaderIndices;
 @property (nonatomic, assign) BOOL centerContent;
-@property (nonatomic, strong) UIRefreshControl *refreshControl;
+@property (nonatomic, strong) RCTRefreshControl *refreshControl;
 
 @end
 
@@ -287,10 +287,12 @@ - (void)dockClosestSectionHeader
   __block UIView *nextHeader = nil;
   NSUInteger subviewCount = contentView.reactSubviews.count;
   [_stickyHeaderIndices enumerateIndexesWithOptions:0 usingBlock:
-   ^(NSUInteger idx, __unused BOOL *stop) {
+   ^(NSUInteger idx, BOOL *stop) {
 
+    // If the subviews are out of sync with the sticky header indices don't
+    // do anything.
     if (idx >= subviewCount) {
-      RCTLogError(@"Sticky header index %zd was outside the range {0, %zd}", idx, subviewCount);
+      *stop = YES;
       return;
     }
 
@@ -365,7 +367,7 @@ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
   return hitView ?: [super hitTest:point withEvent:event];
 }
 
-- (void)setRefreshControl:(UIRefreshControl *)refreshControl
+- (void)setRefreshControl:(RCTRefreshControl *)refreshControl
 {
   if (_refreshControl) {
     [_refreshControl removeFromSuperview];
@@ -826,6 +828,17 @@ - (void)reactBridgeDidFinishTransaction
     _scrollView.contentSize = contentSize;
     _scrollView.contentOffset = newOffset;
   }
+
+  if (RCT_DEBUG) {
+    // Validate that sticky headers are not out of range.
+    NSUInteger subviewCount = _scrollView.contentView.reactSubviews.count;
+    NSUInteger lastIndex = _scrollView.stickyHeaderIndices.lastIndex;
+    if (lastIndex != NSNotFound && lastIndex >= subviewCount) {
+      RCTLogWarn(@"Sticky header index %zd was outside the range {0, %zd}",
+                 lastIndex, subviewCount);
+    }
+  }
+
   [_scrollView dockClosestSectionHeader];
 }
 
@@ -888,7 +901,7 @@ - (void)setOnRefreshStart:(RCTDirectEventBlock)onRefreshStart
   _onRefreshStart = [onRefreshStart copy];
 
   if (!_scrollView.refreshControl) {
-    UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
+    RCTRefreshControl *refreshControl = [[RCTRefreshControl alloc] init];
     [refreshControl addTarget:self action:@selector(refreshControlValueChanged) forControlEvents:UIControlEventValueChanged];
     _scrollView.refreshControl = refreshControl;
   }

From 4b97137eee9a46ebcd0fe4d2c5a473febb4377bb Mon Sep 17 00:00:00 2001
From: AbilashK <abikspnr@gmail.com>
Date: Fri, 19 Feb 2016 06:27:31 -0800
Subject: [PATCH 1234/1411] Enable scalesPageToFit on Android

Summary:PR for https://github.com/facebook/react-native/issues/5958. The viewport meta tags if present, are overridden from the page and it is rendered according to the screen size. An example has been added in the Web View section of UIExplorer demo app.
Closes https://github.com/facebook/react-native/pull/6013

Differential Revision: D2953940

Pulled By: nicklockwood

fb-gh-sync-id: 012769f3a2a3f7dc942b60de02a9d1b80a27236e
shipit-source-id: 012769f3a2a3f7dc942b60de02a9d1b80a27236e
---
 Examples/UIExplorer/WebViewExample.js         | 76 ++++++++++++++++++-
 .../Components/WebView/WebView.android.js     |  7 ++
 Libraries/Components/WebView/WebView.ios.js   |  1 -
 .../views/webview/ReactWebViewManager.java    |  5 ++
 4 files changed, 87 insertions(+), 2 deletions(-)

diff --git a/Examples/UIExplorer/WebViewExample.js b/Examples/UIExplorer/WebViewExample.js
index f7346149395c..6654551ad4eb 100644
--- a/Examples/UIExplorer/WebViewExample.js
+++ b/Examples/UIExplorer/WebViewExample.js
@@ -20,6 +20,7 @@ var {
   StyleSheet,
   Text,
   TextInput,
+  TouchableWithoutFeedback,
   TouchableOpacity,
   View,
   WebView
@@ -160,6 +161,60 @@ var WebViewExample = React.createClass({
 
 });
 
+var Button = React.createClass({
+  _handlePress: function() {
+    if (this.props.enabled && this.props.onPress) {
+      this.props.onPress();
+    }
+  },
+  render: function() {
+    return (
+      <TouchableWithoutFeedback onPress={this._handlePress}>
+        <View style={[styles.button, this.props.enabled ? {} : styles.buttonDisabled]}>
+          <Text style={styles.buttonText}>{this.props.text}</Text>
+        </View>
+      </TouchableWithoutFeedback>
+    );
+  }
+});
+
+var ScaledWebView = React.createClass({
+
+  getInitialState: function() {
+    return {
+      scalingEnabled: true
+    }
+  },
+
+  render: function() {
+    return (
+      <View style={{height:120}}>
+        <WebView
+          style={{
+            backgroundColor: BGWASH,
+            height: 100,
+          }}
+          source={{html: HTML}}
+          scalesPageToFit={this.state.scalingEnabled}
+        />
+        <View style={styles.buttons}>
+        { this.state.scalingEnabled ?
+          <Button
+            text="Scaling:ON"
+            enabled={true}
+            onPress={() => this.setState({scalingEnabled: false})}
+          /> :
+          <Button
+            text="Scaling:OFF"
+            enabled={true}
+            onPress={() => this.setState({scalingEnabled: true})}
+          /> }
+        </View>
+      </View>
+    );
+  },
+})
+
 var styles = StyleSheet.create({
   container: {
     flex: 1,
@@ -229,6 +284,21 @@ var styles = StyleSheet.create({
     width: 20,
     marginRight: 6,
   },
+  buttons: {
+    flexDirection: 'row',
+    height: 30,
+    backgroundColor: 'black',
+    alignItems: 'center',
+    justifyContent: 'space-between',
+  },
+  button: {
+    flex: 0.5,
+    width: 0,
+    margin: 5,
+    borderColor: 'gray',
+    borderWidth: 1,
+    backgroundColor: 'gray',
+  },
 });
 
 const HTML = `
@@ -237,7 +307,7 @@ const HTML = `
   <head>
     <title>Hello Static World</title>
     <meta http-equiv="content-type" content="text/html; charset=utf-8">
-    <meta name="viewport" content="width=320, user-scalable=no">
+    <meta name="viewport" content="width=640, user-scalable=no">
     <style type="text/css">
       body {
         margin: 0;
@@ -297,6 +367,10 @@ exports.examples = [
       );
     }
   },
+  {
+    title: 'Scale Page to Fit',
+    render(): ReactElement { return <ScaledWebView/>; }
+  },
   {
     title: 'POST Test',
     render(): ReactElement {
diff --git a/Libraries/Components/WebView/WebView.android.js b/Libraries/Components/WebView/WebView.android.js
index e9577463fddb..d8274855c368 100644
--- a/Libraries/Components/WebView/WebView.android.js
+++ b/Libraries/Components/WebView/WebView.android.js
@@ -122,6 +122,11 @@ var WebView = React.createClass({
      */
     injectedJavaScript: PropTypes.string,
 
+    /**
+     * Sets whether the webpage scales to fit the view and the user can change the scale.
+     */
+    scalesPageToFit: PropTypes.bool,
+
     /**
      * Sets the user-agent for this WebView. The user-agent can also be set in native using
      * WebViewConfig. This prop will overwrite that config.
@@ -145,6 +150,7 @@ var WebView = React.createClass({
   getDefaultProps: function() {
     return {
       javaScriptEnabled : true,
+      scalesPageToFit: true,
     };
   },
 
@@ -195,6 +201,7 @@ var WebView = React.createClass({
         key="webViewKey"
         style={webViewStyles}
         source={resolveAssetSource(source)}
+        scalesPageToFit={this.props.scalesPageToFit}
         injectedJavaScript={this.props.injectedJavaScript}
         userAgent={this.props.userAgent}
         javaScriptEnabled={this.props.javaScriptEnabled}
diff --git a/Libraries/Components/WebView/WebView.ios.js b/Libraries/Components/WebView/WebView.ios.js
index ec63402139fe..f733963e82b6 100644
--- a/Libraries/Components/WebView/WebView.ios.js
+++ b/Libraries/Components/WebView/WebView.ios.js
@@ -213,7 +213,6 @@ var WebView = React.createClass({
 
     /**
      * Sets whether the webpage scales to fit the view and the user can change the scale.
-     * @platform ios
      */
     scalesPageToFit: PropTypes.bool,
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
index aac2460c5929..4db9141b6a3e 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
@@ -259,6 +259,11 @@ public void setJavaScriptEnabled(WebView view, boolean enabled) {
     view.getSettings().setJavaScriptEnabled(enabled);
   }
 
+  @ReactProp(name = "scalesPageToFit")
+  public void setScalesPageToFit(WebView view, boolean enabled) {
+    view.getSettings().setUseWideViewPort(!enabled);
+  }
+
   @ReactProp(name = "domStorageEnabled")
   public void setDomStorageEnabled(WebView view, boolean enabled) {
     view.getSettings().setDomStorageEnabled(enabled);

From f961b78c5150316a1bb440f35ded0ae0efdf2017 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Fri, 19 Feb 2016 06:43:36 -0800
Subject: [PATCH 1235/1411] Set WebView baseURL to 'about:blank' instead of nil

Reviewed By: javache

Differential Revision: D2953831

fb-gh-sync-id: 2b11353ee453711f32e19011c13d89c128fa16ab
shipit-source-id: 2b11353ee453711f32e19011c13d89c128fa16ab
---
 React/Views/RCTWebView.m | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/React/Views/RCTWebView.m b/React/Views/RCTWebView.m
index cddd9ede1784..d0e1333330b7 100644
--- a/React/Views/RCTWebView.m
+++ b/React/Views/RCTWebView.m
@@ -80,6 +80,9 @@ - (void)setSource:(NSDictionary *)source
     NSString *html = [RCTConvert NSString:source[@"html"]];
     if (html) {
       NSURL *baseURL = [RCTConvert NSURL:source[@"baseUrl"]];
+      if (!baseURL) {
+        baseURL = [NSURL URLWithString:@"about:blank"];
+      }
       [_webView loadHTMLString:html baseURL:baseURL];
       return;
     }

From b454d31ab8d778c393a3a99869c50d1967baaaad Mon Sep 17 00:00:00 2001
From: Jimmy Mayoukou <bhullnatik@gmail.com>
Date: Fri, 19 Feb 2016 06:49:41 -0800
Subject: [PATCH 1236/1411] Add position to Picker onValueChange's call

Summary:According to the [docs](http://facebook.github.io/react-native/releases/0.20/docs/picker.html#onvaluechange), `Picker`'s `onValueChange` should be called with `itemValue` and `itemPosition` but currently only `itemValue` is passed. This PR fixes that.
The position is passed as the 2nd parameter to not introduce any breaking change, and also to respect the current documentation.
The documentation doesn't need to be changed as it will be correct with this PR, but maybe it needs to be updated until this is merged?
Closes https://github.com/facebook/react-native/pull/5874

Differential Revision: D2953936

Pulled By: nicklockwood

fb-gh-sync-id: b8c1283013d4c7ed315066d8750f601f76f6bbb2
shipit-source-id: b8c1283013d4c7ed315066d8750f601f76f6bbb2
---
 Libraries/Components/Picker/PickerAndroid.android.js | 4 ++--
 Libraries/Picker/PickerIOS.ios.js                    | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Libraries/Components/Picker/PickerAndroid.android.js b/Libraries/Components/Picker/PickerAndroid.android.js
index 71d7b35e81d1..797653d001df 100644
--- a/Libraries/Components/Picker/PickerAndroid.android.js
+++ b/Libraries/Components/Picker/PickerAndroid.android.js
@@ -100,9 +100,9 @@ var PickerAndroid = React.createClass({
       var position = event.nativeEvent.position;
       if (position >= 0) {
         var value = this.props.children[position].props.value;
-        this.props.onValueChange(value);
+        this.props.onValueChange(value, position);
       } else {
-        this.props.onValueChange(null);
+        this.props.onValueChange(null, position);
       }
     }
 
diff --git a/Libraries/Picker/PickerIOS.ios.js b/Libraries/Picker/PickerIOS.ios.js
index 0aa82bb5f8f8..84bb1c0e7f0f 100644
--- a/Libraries/Picker/PickerIOS.ios.js
+++ b/Libraries/Picker/PickerIOS.ios.js
@@ -54,7 +54,7 @@ var PickerIOS = React.createClass({
     });
     return {selectedIndex, items};
   },
-  
+
   render: function() {
     return (
       <View style={this.props.style}>
@@ -74,7 +74,7 @@ var PickerIOS = React.createClass({
       this.props.onChange(event);
     }
     if (this.props.onValueChange) {
-      this.props.onValueChange(event.nativeEvent.newValue);
+      this.props.onValueChange(event.nativeEvent.newValue, event.nativeEvent.newIndex);
     }
 
     // The picker is a controlled component. This means we expect the

From febb1fbe13173d8a800843200d6dbd420c86f008 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Fri, 19 Feb 2016 08:21:49 -0800
Subject: [PATCH 1237/1411] WebWorkers: Move web worker impl to JSCExecutor

Summary: Part of the plan to make web workers able to call native modules. We will reuse the infrastructure already present in JSCExecutor to allow web workers to call native modules via the Bridge.

Reviewed By: mhorowitz

Differential Revision: D2926896

fb-gh-sync-id: 259b766c46f79bbb5df9d1c648237b81fc1cc1f9
shipit-source-id: 259b766c46f79bbb5df9d1c648237b81fc1cc1f9
---
 .../react/bridge/CatalystInstanceImpl.java    |  22 ++-
 .../common/futures/SimpleSettableFuture.java  |   2 +-
 .../src/main/jni/react/JSCExecutor.cpp        | 172 ++++++++++++++----
 ReactAndroid/src/main/jni/react/JSCExecutor.h |  63 +++++--
 .../src/main/jni/react/JSCWebWorker.cpp       | 153 ----------------
 .../src/main/jni/react/JSCWebWorker.h         |  94 ----------
 .../src/main/jni/react/MessageQueueThread.h   |  20 ++
 7 files changed, 226 insertions(+), 300 deletions(-)
 delete mode 100644 ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
 delete mode 100644 ReactAndroid/src/main/jni/react/JSCWebWorker.h

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
index cc34bf6ffaa8..0cacb9b47762 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
@@ -27,6 +27,7 @@
 import com.facebook.react.bridge.queue.QueueThreadExceptionHandler;
 import com.facebook.react.common.ReactConstants;
 import com.facebook.react.common.annotations.VisibleForTesting;
+import com.facebook.react.common.futures.SimpleSettableFuture;
 import com.facebook.systrace.Systrace;
 import com.facebook.systrace.TraceListener;
 
@@ -264,6 +265,10 @@ public void destroy() {
     // TODO: tell all APIs to shut down
     mDestroyed = true;
     mJavaRegistry.notifyCatalystInstanceDestroy();
+
+    Systrace.unregisterListener(mTraceListener);
+
+    synchronouslyDisposeBridgeOnJSThread();
     mReactQueueConfiguration.destroy();
     boolean wasIdle = (mPendingJSCalls.getAndSet(0) == 0);
     if (!wasIdle && !mBridgeIdleListeners.isEmpty()) {
@@ -271,12 +276,19 @@ public void destroy() {
         listener.onTransitionToBridgeIdle();
       }
     }
+  }
 
-    Systrace.unregisterListener(mTraceListener);
-
-    // We can access the Bridge from any thread now because we know either we are on the JS thread
-    // or the JS thread has finished via ReactQueueConfiguration#destroy()
-    mBridge.dispose();
+  private void synchronouslyDisposeBridgeOnJSThread() {
+    final SimpleSettableFuture<Void> bridgeDisposeFuture = new SimpleSettableFuture<>();
+    mReactQueueConfiguration.getJSQueueThread().runOnQueue(
+        new Runnable() {
+          @Override
+          public void run() {
+            mBridge.dispose();
+            bridgeDisposeFuture.set(null);
+          }
+        });
+    bridgeDisposeFuture.getOrThrow();
   }
 
   @Override
diff --git a/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java b/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java
index 55fc9eb089e2..9caf34cd6231 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java
@@ -30,7 +30,7 @@ public class SimpleSettableFuture<T> implements Future<T> {
    * Sets the result. If another thread has called {@link #get}, they will immediately receive the
    * value. set or setException must only be called once.
    */
-  public void set(T result) {
+  public void set(@Nullable T result) {
     checkNotSet();
     mResult = result;
     mReadyLatch.countDown();
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index ceb2564d5a6b..5720905e72da 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -3,9 +3,11 @@
 #include "JSCExecutor.h"
 
 #include <algorithm>
-#include <atomic>
+#include <condition_variable>
+#include <mutex>
 #include <sstream>
 #include <string>
+
 #include <folly/json.h>
 #include <folly/String.h>
 #include <sys/time.h>
@@ -88,6 +90,45 @@ JSCExecutor::JSCExecutor(Bridge *bridge, const std::string& cacheDir) :
     m_bridge(bridge),
     m_deviceCacheDir(cacheDir),
     m_messageQueueThread(MessageQueues::getCurrentMessageQueueThread()) {
+  initOnJSVMThread();
+}
+
+JSCExecutor::JSCExecutor(
+    Bridge *bridge,
+    int workerId,
+    JSCExecutor *owner,
+    const std::string& script) :
+    m_bridge(bridge),
+    m_workerId(workerId),
+    m_owner(owner),
+    m_deviceCacheDir(owner->m_deviceCacheDir),
+    m_messageQueueThread(MessageQueues::getCurrentMessageQueueThread()) {
+  // We post initOnJSVMThread here so that the owner doesn't have to wait for
+  // initialization on its own thread
+  m_messageQueueThread->runOnQueue([this, script] () {
+    initOnJSVMThread();
+
+    installGlobalFunction(m_context, "postMessage", nativePostMessage);
+
+    // TODO(9604438): Protect against script does not exist
+    std::string scriptSrc = WebWorkerUtil::loadScriptFromAssets(script);
+    // TODO(9994180): Throw on error
+    loadApplicationScript(scriptSrc, script);
+  });
+}
+
+JSCExecutor::~JSCExecutor() {
+  *m_isDestroyed = true;
+  if (m_messageQueueThread->isOnThread()) {
+    terminateOnJSVMThread();
+  } else {
+    m_messageQueueThread->runOnQueueSync([this] () {
+      terminateOnJSVMThread();
+    });
+  }
+}
+
+void JSCExecutor::initOnJSVMThread() {
   m_context = JSGlobalContextCreateInGroup(nullptr, nullptr);
   s_globalContextRefToJSCExecutor[m_context] = this;
   installGlobalFunction(m_context, "nativeFlushQueueImmediate", nativeFlushQueueImmediate);
@@ -114,18 +155,20 @@ JSCExecutor::JSCExecutor(Bridge *bridge, const std::string& cacheDir) :
   #endif
 }
 
-JSCExecutor::~JSCExecutor() {
-  // terminateWebWorker mutates m_webWorkers so collect all the workers to terminate first
+void JSCExecutor::terminateOnJSVMThread() {
+  // terminateOwnedWebWorker mutates m_ownedWorkers so collect all the workers
+  // to terminate first
   std::vector<int> workerIds;
-  for (auto it = m_webWorkers.begin(); it != m_webWorkers.end(); it++) {
-    workerIds.push_back(it->first);
+  for (auto& it : m_ownedWorkers) {
+    workerIds.push_back(it.first);
   }
   for (int workerId : workerIds) {
-    terminateWebWorker(workerId);
+    terminateOwnedWebWorker(workerId);
   }
 
   s_globalContextRefToJSCExecutor.erase(m_context);
   JSGlobalContextRelease(m_context);
+  m_context = nullptr;
 }
 
 void JSCExecutor::loadApplicationScript(
@@ -162,6 +205,10 @@ void JSCExecutor::loadApplicationUnbundle(
 }
 
 void JSCExecutor::flush() {
+  if (m_owner != nullptr) {
+    // Web workers don't support native modules yet
+    return;
+  }
   // TODO: Make this a first class function instead of evaling. #9317773
   std::string calls = executeJSCallWithJSC(m_context, "flushedQueue", std::vector<folly::dynamic>());
   m_bridge->callNativeModules(calls, true);
@@ -253,56 +300,111 @@ void JSCExecutor::loadModule(uint32_t moduleId) {
   evaluateScript(m_context, source, sourceUrl);
 }
 
-// WebWorker impl
+int JSCExecutor::addWebWorker(
+    const std::string& script,
+    JSValueRef workerRef) {
+  static std::atomic_int nextWorkerId(1);
+  int workerId = nextWorkerId++;
 
-JSGlobalContextRef JSCExecutor::getContext() {
-  return m_context;
+  auto workerMQT = WebWorkerUtil::createWebWorkerThread(workerId, m_messageQueueThread.get());
+  std::unique_ptr<JSCExecutor> worker;
+  workerMQT->runOnQueueSync([this, &worker, &script, workerId] () {
+    worker.reset(new JSCExecutor(m_bridge, workerId, this, script));
+  });
+
+  Object workerObj = Value(m_context, workerRef).asObject();
+  workerObj.makeProtected();
+
+  m_ownedWorkers.emplace(std::piecewise_construct, std::forward_as_tuple(workerId), std::forward_as_tuple(std::move(worker), std::move(workerObj)));
+
+  return workerId;
 }
 
-std::shared_ptr<MessageQueueThread> JSCExecutor::getMessageQueueThread() {
-  return m_messageQueueThread;
+void JSCExecutor::postMessageToOwnedWebWorker(int workerId, JSValueRef message, JSValueRef *exn) {
+  auto worker = m_ownedWorkers.at(workerId).getExecutor();
+  std::string msgString = Value(m_context, message).toJSONString();
+
+  std::shared_ptr<bool> isWorkerDestroyed = worker->m_isDestroyed;
+  worker->m_messageQueueThread->runOnQueue([isWorkerDestroyed, worker, msgString] () {
+    if (*isWorkerDestroyed) {
+      return;
+    }
+    worker->receiveMessageFromOwner(msgString);
+  });
 }
 
-void JSCExecutor::onMessageReceived(int workerId, const std::string& json) {
-  Object& worker = m_webWorkerJSObjs.at(workerId);
+void JSCExecutor::postMessageToOwner(JSValueRef msg) {
+  std::string msgString = Value(m_context, msg).toJSONString();
+  std::shared_ptr<bool> ownerIsDestroyed = m_owner->m_isDestroyed;
+  m_owner->m_messageQueueThread->runOnQueue([workerId=m_workerId, owner=m_owner, ownerIsDestroyed, msgString] () {
+    if (*ownerIsDestroyed) {
+      return;
+    }
+    owner->receiveMessageFromOwnedWebWorker(workerId, msgString);
+  });
+}
+
+void JSCExecutor::receiveMessageFromOwnedWebWorker(int workerId, const std::string& json) {
+  Object* workerObj;
+  try {
+    workerObj = &m_ownedWorkers.at(workerId).jsObj;
+  } catch (std::out_of_range& e) {
+    // Worker was already terminated
+    return;
+  }
 
-  Value onmessageValue = worker.getProperty("onmessage");
+  Value onmessageValue = workerObj->getProperty("onmessage");
   if (onmessageValue.isUndefined()) {
     return;
   }
 
-  JSValueRef args[] = { JSCWebWorker::createMessageObject(m_context, json) };
+  JSValueRef args[] = { createMessageObject(json) };
   onmessageValue.asObject().callAsFunction(1, args);
 
   flush();
 }
 
-int JSCExecutor::addWebWorker(const std::string& script, JSValueRef workerRef) {
-  static std::atomic_int nextWorkerId(0);
-  int workerId = nextWorkerId++;
+void JSCExecutor::receiveMessageFromOwner(const std::string& msgString) {
+  CHECK(m_owner) << "Received message in a Executor that doesn't have an owner!";
 
-  m_webWorkers.emplace(std::piecewise_construct, std::forward_as_tuple(workerId), std::forward_as_tuple(workerId, this, script));
-  Object workerObj = Value(m_context, workerRef).asObject();
-  workerObj.makeProtected();
-  m_webWorkerJSObjs.emplace(workerId, std::move(workerObj));
-  return workerId;
+  JSValueRef args[] = { createMessageObject(msgString) };
+  Value onmessageValue = Object::getGlobalObject(m_context).getProperty("onmessage");
+  onmessageValue.asObject().callAsFunction(1, args);
 }
 
-void JSCExecutor::postMessageToWebWorker(int workerId, JSValueRef message, JSValueRef *exn) {
-  JSCWebWorker& worker = m_webWorkers.at(workerId);
-  worker.postMessage(message);
+void JSCExecutor::terminateOwnedWebWorker(int workerId) {
+  auto worker = m_ownedWorkers.at(workerId).getExecutor();
+  std::shared_ptr<MessageQueueThread> workerMQT = worker->m_messageQueueThread;
+  m_ownedWorkers.erase(workerId);
+  workerMQT->quitSynchronous();
 }
 
-void JSCExecutor::terminateWebWorker(int workerId) {
-  JSCWebWorker& worker = m_webWorkers.at(workerId);
-
-  worker.terminate();
-
-  m_webWorkers.erase(workerId);
-  m_webWorkerJSObjs.erase(workerId);
+Object JSCExecutor::createMessageObject(const std::string& msgJson) {
+  Value rebornJSMsg = Value::fromJSON(m_context, String(msgJson.c_str()));
+  Object messageObject = Object::create(m_context);
+  messageObject.setProperty("data", rebornJSMsg);
+  return messageObject;
 }
 
 // Native JS hooks
+JSValueRef JSCExecutor::nativePostMessage(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[],
+    JSValueRef *exception) {
+  if (argumentCount != 1) {
+    *exception = makeJSCException(ctx, "postMessage got wrong number of arguments");
+    return JSValueMakeUndefined(ctx);
+  }
+  JSValueRef msg = arguments[0];
+  JSCExecutor *webWorker = s_globalContextRefToJSCExecutor.at(JSContextGetGlobalContext(ctx));
+
+  webWorker->postMessageToOwner(msg);
+
+  return JSValueMakeUndefined(ctx);
+}
 
 static JSValueRef makeInvalidModuleIdJSCException(
     JSContextRef ctx,
@@ -433,7 +535,7 @@ JSValueRef JSCExecutor::nativePostMessageToWorker(
     return JSValueMakeUndefined(ctx);
   }
 
-  executor->postMessageToWebWorker((int) workerDouble, arguments[1], exception);
+  executor->postMessageToOwnedWebWorker((int) workerDouble, arguments[1], exception);
 
   return JSValueMakeUndefined(ctx);
 }
@@ -464,7 +566,7 @@ JSValueRef JSCExecutor::nativeTerminateWorker(
     return JSValueMakeUndefined(ctx);
   }
 
-  executor->terminateWebWorker((int) workerDouble);
+  executor->terminateOwnedWebWorker((int) workerDouble);
 
   return JSValueMakeUndefined(ctx);
 }
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.h b/ReactAndroid/src/main/jni/react/JSCExecutor.h
index dbba889abfd7..c60f33422a6a 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.h
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.h
@@ -6,9 +6,10 @@
 #include <memory>
 #include <unordered_map>
 #include <JavaScriptCore/JSContextRef.h>
+
 #include "Executor.h"
 #include "JSCHelpers.h"
-#include "JSCWebWorker.h"
+#include "Value.h"
 
 namespace facebook {
 namespace react {
@@ -23,10 +24,26 @@ class JSCExecutorFactory : public JSExecutorFactory {
   std::string cacheDir_;
 };
 
-class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
+class JSCExecutor;
+class WorkerRegistration : public noncopyable {
+public:
+  explicit WorkerRegistration(std::unique_ptr<JSCExecutor> executor, Object jsObj) :
+      jsObj(std::move(jsObj)),
+      executor(std::move(executor)) {}
+
+  JSCExecutor* getExecutor() {
+    return executor.get();
+  }
+
+  Object jsObj;
+private:
+  std::unique_ptr<JSCExecutor> executor;
+};
+
+class JSCExecutor : public JSExecutor {
 public:
   /**
-   * Should be invoked from the JS thread.
+   * Must be invoked from thread this Executor will run on.
    */
   explicit JSCExecutor(Bridge *bridge, const std::string& cacheDir);
   ~JSCExecutor() override;
@@ -56,25 +73,40 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
   virtual void handleMemoryPressureCritical() override;
 
   void installNativeHook(const char *name, JSObjectCallAsFunctionCallback callback);
-  virtual void onMessageReceived(int workerId, const std::string& message) override;
-  virtual JSGlobalContextRef getContext() override;
-  virtual std::shared_ptr<MessageQueueThread> getMessageQueueThread() override;
 
 private:
   JSGlobalContextRef m_context;
-  std::unordered_map<int, JSCWebWorker> m_webWorkers;
-  std::unordered_map<int, Object> m_webWorkerJSObjs;
   Bridge *m_bridge;
+  int m_workerId = 0; // if this is a worker executor, this is non-zero
+  JSCExecutor *m_owner = nullptr; // if this is a worker executor, this is non-null
+  std::shared_ptr<bool> m_isDestroyed = std::shared_ptr<bool>(new bool(false));
+  std::unordered_map<int, WorkerRegistration> m_ownedWorkers;
   std::string m_deviceCacheDir;
   std::shared_ptr<MessageQueueThread> m_messageQueueThread;
   std::unique_ptr<JSModulesUnbundle> m_unbundle;
 
-  int addWebWorker(const std::string& script, JSValueRef workerRef);
-  void postMessageToWebWorker(int worker, JSValueRef message, JSValueRef *exn);
+  /**
+   * WebWorker constructor. Must be invoked from thread this Executor will run on.
+   */
+  explicit JSCExecutor(
+      Bridge *bridge,
+      int workerId,
+      JSCExecutor *owner,
+      const std::string& script);
+
+  void initOnJSVMThread();
+  void terminateOnJSVMThread();
   void flush();
-  void terminateWebWorker(int worker);
-  void loadModule(uint32_t moduleId);
   void flushQueueImmediate(std::string queueJSON);
+  void loadModule(uint32_t moduleId);
+
+  int addWebWorker(const std::string& script, JSValueRef workerRef);
+  void postMessageToOwnedWebWorker(int worker, JSValueRef message, JSValueRef *exn);
+  void postMessageToOwner(JSValueRef result);
+  void receiveMessageFromOwnedWebWorker(int workerId, const std::string& message);
+  void receiveMessageFromOwner(const std::string &msgString);
+  void terminateOwnedWebWorker(int worker);
+  Object createMessageObject(const std::string& msgData);
 
   static JSValueRef nativeStartWorker(
       JSContextRef ctx,
@@ -97,6 +129,13 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
       size_t argumentCount,
       const JSValueRef arguments[],
       JSValueRef *exception);
+  static JSValueRef nativePostMessage(
+      JSContextRef ctx,
+      JSObjectRef function,
+      JSObjectRef thisObject,
+      size_t argumentCount,
+      const JSValueRef arguments[],
+      JSValueRef *exception);
   static JSValueRef nativeRequire(
       JSContextRef ctx,
       JSObjectRef function,
diff --git a/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp b/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
deleted file mode 100644
index e8e710bdf393..000000000000
--- a/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-#include "JSCWebWorker.h"
-
-#include <unistd.h>
-#include <condition_variable>
-#include <mutex>
-#include <unordered_map>
-
-#include <glog/logging.h>
-#include <folly/Memory.h>
-
-#include "JSCHelpers.h"
-#include "MessageQueueThread.h"
-#include "Platform.h"
-#include "Value.h"
-
-#include <JavaScriptCore/JSValueRef.h>
-
-namespace facebook {
-namespace react {
-
-// TODO(9604425): thread safety
-static std::unordered_map<JSContextRef, JSCWebWorker*> s_globalContextRefToJSCWebWorker;
-
-JSCWebWorker::JSCWebWorker(int id, JSCWebWorkerOwner *owner, std::string scriptSrc) :
-    id_(id),
-    scriptName_(std::move(scriptSrc)),
-    owner_(owner) {
-  ownerMessageQueueThread_ = owner->getMessageQueueThread();
-  CHECK(ownerMessageQueueThread_) << "Owner MessageQueue must not be null";
-  workerMessageQueueThread_ = WebWorkerUtil::createWebWorkerThread(id, ownerMessageQueueThread_.get());
-  CHECK(workerMessageQueueThread_) << "Failed to create worker thread";
-
-  workerMessageQueueThread_->runOnQueue([this] () {
-    initJSVMAndLoadScript();
-  });
-}
-
-
-JSCWebWorker::~JSCWebWorker() {
-  CHECK(isTerminated()) << "Didn't terminate the web worker before releasing it!";;
-}
-
-void JSCWebWorker::postMessage(JSValueRef msg) {
-  std::string msgString = Value(owner_->getContext(), msg).toJSONString();
-
-  workerMessageQueueThread_->runOnQueue([this, msgString] () {
-    if (isTerminated()) {
-      return;
-    }
-
-    JSValueRef args[] = { createMessageObject(context_, msgString) };
-    Value onmessageValue = Object::getGlobalObject(context_).getProperty("onmessage");
-    onmessageValue.asObject().callAsFunction(1, args);
-  });
-}
-
-void JSCWebWorker::terminate() {
-  if (isTerminated()) {
-    return;
-  }
-  isTerminated_.store(true, std::memory_order_release);
-
-  if (workerMessageQueueThread_->isOnThread()) {
-    terminateOnWorkerThread();
-  } else {
-    std::mutex signalMutex;
-    std::condition_variable signalCv;
-    bool terminationComplete = false;
-
-    workerMessageQueueThread_->runOnQueue([&] () mutable {
-      std::lock_guard<std::mutex> lock(signalMutex);
-
-      terminateOnWorkerThread();
-      terminationComplete = true;
-
-      signalCv.notify_one();
-    });
-
-    std::unique_lock<std::mutex> lock(signalMutex);
-    signalCv.wait(lock, [&terminationComplete] { return terminationComplete; });
-  }
-}
-
-void JSCWebWorker::terminateOnWorkerThread() {
-  s_globalContextRefToJSCWebWorker.erase(context_);
-  JSGlobalContextRelease(context_);
-  context_ = nullptr;
-  workerMessageQueueThread_->quitSynchronous();
-}
-
-bool JSCWebWorker::isTerminated() {
-  return isTerminated_.load(std::memory_order_acquire);
-}
-
-void JSCWebWorker::initJSVMAndLoadScript() {
-  CHECK(!isTerminated()) << "Worker was already finished!";
-  CHECK(!context_) << "Worker JS VM was already created!";
-
-  context_ = JSGlobalContextCreateInGroup(
-      NULL, // use default JS 'global' object
-      NULL // create new group (i.e. new VM)
-  );
-  s_globalContextRefToJSCWebWorker[context_] = this;
-
-  // TODO(9604438): Protect against script does not exist
-  std::string script = WebWorkerUtil::loadScriptFromAssets(scriptName_);
-  evaluateScript(context_, String(script.c_str()), String(scriptName_.c_str()));
-
-  installGlobalFunction(context_, "postMessage", nativePostMessage);
-}
-
-void JSCWebWorker::postMessageToOwner(JSValueRef msg) {
-  std::string msgString = Value(context_, msg).toJSONString();
-  ownerMessageQueueThread_->runOnQueue([this, msgString] () {
-      owner_->onMessageReceived(id_, msgString);
-  });
-}
-
-JSValueRef JSCWebWorker::nativePostMessage(
-    JSContextRef ctx,
-    JSObjectRef function,
-    JSObjectRef thisObject,
-    size_t argumentCount,
-    const JSValueRef arguments[],
-    JSValueRef *exception) {
-  if (argumentCount != 1) {
-    *exception = makeJSCException(ctx, "postMessage got wrong number of arguments");
-    return JSValueMakeUndefined(ctx);
-  }
-  JSValueRef msg = arguments[0];
-  JSCWebWorker *webWorker = s_globalContextRefToJSCWebWorker.at(JSContextGetGlobalContext(ctx));
-
-  if (webWorker->isTerminated()) {
-    return JSValueMakeUndefined(ctx);
-  }
-
-  webWorker->postMessageToOwner(msg);
-  
-  return JSValueMakeUndefined(ctx);
-}
-
-/*static*/
-Object JSCWebWorker::createMessageObject(JSContextRef context, const std::string& msgJson) {
-  Value rebornJSMsg = Value::fromJSON(context, String(msgJson.c_str()));
-  Object messageObject = Object::create(context);
-  messageObject.setProperty("data", rebornJSMsg);
-  return std::move(messageObject);
-}
-
-}
-}
diff --git a/ReactAndroid/src/main/jni/react/JSCWebWorker.h b/ReactAndroid/src/main/jni/react/JSCWebWorker.h
deleted file mode 100644
index 73d983cdfe7b..000000000000
--- a/ReactAndroid/src/main/jni/react/JSCWebWorker.h
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-#include <atomic>
-#include <functional>
-#include <mutex>
-#include <string>
-#include <thread>
-#include <queue>
-
-#include <JavaScriptCore/JSValueRef.h>
-
-#include "Value.h"
-
-namespace facebook {
-namespace react {
-
-class MessageQueueThread;
-
-/**
- * A class that can own the lifecycle, receive messages from, and dispatch messages
- * to JSCWebWorkers.
- */
-class JSCWebWorkerOwner {
-public:
-  /**
-   * Called when a worker has posted a message with `postMessage`.
-   */
-  virtual void onMessageReceived(int workerId, const std::string& message) = 0;
-  virtual JSGlobalContextRef getContext() = 0;
-
-  /**
-   * Should return the owner's MessageQueueThread. Calls to onMessageReceived will be enqueued
-   * on this thread.
-   */
-  virtual std::shared_ptr<MessageQueueThread> getMessageQueueThread() = 0;
-};
-
-/**
- * Implementation of a web worker for JSC. The web worker should be created from the owner's
- * (e.g., owning JSCExecutor instance) JS MessageQueueThread. The worker is responsible for
- * creating its own MessageQueueThread.
- *
- * During operation, the JSCExecutor should call postMessage **from its own MessageQueueThread**
- * to send messages to the worker. The worker will handle enqueueing those messages on its own
- * MessageQueueThread as appropriate. When the worker has a message to post to the owner, it will
- * enqueue a call to owner->onMessageReceived on the owner's MessageQueueThread.
- */
-class JSCWebWorker {
-public:
-  explicit JSCWebWorker(int id, JSCWebWorkerOwner *owner, std::string script);
-  ~JSCWebWorker();
-
-  /**
-   * Post a message to be received by the worker on its thread. This must be called from 
-   * ownerMessageQueueThread_.
-   */
-  void postMessage(JSValueRef msg);
-
-  /**
-   * Synchronously quits the current worker and cleans up its VM.
-   */
-  void terminate();
-
-  /**
-   * Whether terminate() has been called on this worker.
-   */
-  bool isTerminated();
-
-  static Object createMessageObject(JSContextRef context, const std::string& msgData);
-private:
-  void initJSVMAndLoadScript();
-  void postRunnableToEventLoop(std::function<void()>&& runnable);
-  void postMessageToOwner(JSValueRef result);
-  void terminateOnWorkerThread();
-
-  int id_;
-  std::atomic_bool isTerminated_ = ATOMIC_VAR_INIT(false);
-  std::string scriptName_;
-  JSCWebWorkerOwner *owner_ = nullptr;
-  std::shared_ptr<MessageQueueThread> ownerMessageQueueThread_;
-  std::unique_ptr<MessageQueueThread> workerMessageQueueThread_;
-  JSGlobalContextRef context_ = nullptr;
-
-  static JSValueRef nativePostMessage(
-      JSContextRef ctx,
-      JSObjectRef function,
-      JSObjectRef thisObject,
-      size_t argumentCount,
-      const JSValueRef arguments[],
-      JSValueRef *exception);
-};
-
-}
-}
diff --git a/ReactAndroid/src/main/jni/react/MessageQueueThread.h b/ReactAndroid/src/main/jni/react/MessageQueueThread.h
index 544b91142be9..f6352ab0d90a 100644
--- a/ReactAndroid/src/main/jni/react/MessageQueueThread.h
+++ b/ReactAndroid/src/main/jni/react/MessageQueueThread.h
@@ -2,7 +2,9 @@
 
 #pragma once
 
+#include <condition_variable>
 #include <functional>
+#include <mutex>
 
 namespace facebook {
 namespace react {
@@ -14,6 +16,24 @@ class MessageQueueThread {
   virtual bool isOnThread() = 0;
   // quitSynchronous() should synchronously ensure that no further tasks will run on the queue.
   virtual void quitSynchronous() = 0;
+
+  void runOnQueueSync(std::function<void()>&& runnable) {
+    std::mutex signalMutex;
+    std::condition_variable signalCv;
+    bool runnableComplete = false;
+
+    runOnQueue([&] () mutable {
+      std::lock_guard<std::mutex> lock(signalMutex);
+
+      runnable();
+      runnableComplete = true;
+
+      signalCv.notify_one();
+    });
+
+    std::unique_lock<std::mutex> lock(signalMutex);
+    signalCv.wait(lock, [&runnableComplete] { return runnableComplete; });
+  }
 };
 
 }}

From 2b251638a6d1b2eb5bf5c8e74734e89fae856cbf Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Fri, 19 Feb 2016 08:21:55 -0800
Subject: [PATCH 1238/1411] WebWorkers: Allow web worker owner to inject
 globals into worker, supply modified __fbBatchedBridgeConfig

Summary: Now that web workers are just JSCExecutors, we can move forward with adding native module support. The means we need to supply the worker with a correct __fbBatchedBridgeConfig global so it can appropriately set up its JS MessageQueue. Unfortunately, native modules can't support multiple JS execution contexts out-of-the-box, so we need to whitelist those modules that actually can be referenced from a webworker. In order to do that, we add the supportsWebWorkers call in NativeModule and the SupportsWebWorkers annotation for JS modules. These add metadata to __fbBatchedBridgeConfig which allows us to create a new config with only those modules that support web workers.

Reviewed By: lexs

Differential Revision: D2927091

fb-gh-sync-id: 9b47331253b277940b552e7d899198b5f0a3ed8c
shipit-source-id: 9b47331253b277940b552e7d899198b5f0a3ed8c
---
 .../facebook/react/bridge/BaseJavaModule.java |  5 ++++
 .../react/bridge/JavaScriptModulesConfig.java |  3 +++
 .../facebook/react/bridge/NativeModule.java   |  5 ++++
 .../react/bridge/NativeModuleRegistry.java    |  1 +
 .../react/bridge/SupportsWebWorkers.java      | 15 ++++++++++++
 .../src/main/jni/react/JSCExecutor.cpp        | 23 +++++++++++++------
 ReactAndroid/src/main/jni/react/JSCExecutor.h |  5 ++--
 7 files changed, 48 insertions(+), 9 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/SupportsWebWorkers.java

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java
index 6d05c003ac7b..82d347c8c8f1 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java
@@ -341,4 +341,9 @@ public void onReactBridgeInitialized(ReactBridge bridge) {
   public void onCatalystInstanceDestroy() {
     // do nothing
   }
+
+  @Override
+  public boolean supportsWebWorkers() {
+    return false;
+  }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModulesConfig.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModulesConfig.java
index abeba7230c2f..e6241f6e41cf 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModulesConfig.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModulesConfig.java
@@ -52,6 +52,9 @@ private void appendJSModuleToJSONObject(
       jg.writeEndObject();
     }
     jg.writeEndObject();
+    if (registration.getModuleInterface().isAnnotationPresent(SupportsWebWorkers.class)) {
+      jg.writeBooleanField("supportsWebWorkers", true);
+    }
   }
 
   public static class Builder {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java
index 5dae9ac3e499..8996547f257a 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java
@@ -72,4 +72,9 @@ interface NativeMethod {
    * Called before {CatalystInstance#onHostDestroy}
    */
   void onCatalystInstanceDestroy();
+
+  /**
+   * Whether this native module supports calls from web workers. Ignored for now.
+   */
+  boolean supportsWebWorkers();
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java
index 131def5fb063..c8a59e8f73ac 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java
@@ -65,6 +65,7 @@ private NativeModuleRegistry(
       for (ModuleDefinition moduleDef : mModuleTable) {
         jg.writeObjectFieldStart(moduleDef.name);
         jg.writeNumberField("moduleID", moduleDef.id);
+        jg.writeBooleanField("supportsWebWorkers", moduleDef.target.supportsWebWorkers());
         jg.writeObjectFieldStart("methods");
         for (int i = 0; i < moduleDef.methods.size(); i++) {
           MethodRegistration method = moduleDef.methods.get(i);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/SupportsWebWorkers.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/SupportsWebWorkers.java
new file mode 100644
index 000000000000..ad3dc87f4b2b
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/SupportsWebWorkers.java
@@ -0,0 +1,15 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.bridge;
+
+import java.lang.annotation.Retention;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Annotation indicating that a JS module should be made available to web
+ * workers spawned by the main JS executor.
+ */
+@Retention(RUNTIME)
+public @interface SupportsWebWorkers {
+}
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index 5720905e72da..38dd9e2372f2 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -97,7 +97,8 @@ JSCExecutor::JSCExecutor(
     Bridge *bridge,
     int workerId,
     JSCExecutor *owner,
-    const std::string& script) :
+    const std::string& script,
+    const std::unordered_map<std::string, std::string>& globalObjAsJSON) :
     m_bridge(bridge),
     m_workerId(workerId),
     m_owner(owner),
@@ -105,11 +106,15 @@ JSCExecutor::JSCExecutor(
     m_messageQueueThread(MessageQueues::getCurrentMessageQueueThread()) {
   // We post initOnJSVMThread here so that the owner doesn't have to wait for
   // initialization on its own thread
-  m_messageQueueThread->runOnQueue([this, script] () {
+  m_messageQueueThread->runOnQueue([this, script, globalObjAsJSON] () {
     initOnJSVMThread();
 
     installGlobalFunction(m_context, "postMessage", nativePostMessage);
 
+    for (auto& it : globalObjAsJSON) {
+      setGlobalVariable(it.first, it.second);
+    }
+
     // TODO(9604438): Protect against script does not exist
     std::string scriptSrc = WebWorkerUtil::loadScriptFromAssets(script);
     // TODO(9994180): Throw on error
@@ -302,14 +307,17 @@ void JSCExecutor::loadModule(uint32_t moduleId) {
 
 int JSCExecutor::addWebWorker(
     const std::string& script,
-    JSValueRef workerRef) {
+    JSValueRef workerRef,
+    JSValueRef globalObjRef) {
   static std::atomic_int nextWorkerId(1);
   int workerId = nextWorkerId++;
 
+  Object globalObj = Value(m_context, globalObjRef).asObject();
+
   auto workerMQT = WebWorkerUtil::createWebWorkerThread(workerId, m_messageQueueThread.get());
   std::unique_ptr<JSCExecutor> worker;
-  workerMQT->runOnQueueSync([this, &worker, &script, workerId] () {
-    worker.reset(new JSCExecutor(m_bridge, workerId, this, script));
+  workerMQT->runOnQueueSync([this, &worker, &script, &globalObj, workerId] () {
+    worker.reset(new JSCExecutor(m_bridge, workerId, this, script, globalObj.toJSONMap()));
   });
 
   Object workerObj = Value(m_context, workerRef).asObject();
@@ -487,7 +495,7 @@ JSValueRef JSCExecutor::nativeStartWorker(
     size_t argumentCount,
     const JSValueRef arguments[],
     JSValueRef *exception) {
-  if (argumentCount != 2) {
+  if (argumentCount != 3) {
     *exception = createErrorString(ctx, "Got wrong number of args");
     return JSValueMakeUndefined(ctx);
   }
@@ -495,6 +503,7 @@ JSValueRef JSCExecutor::nativeStartWorker(
   std::string scriptFile = Value(ctx, arguments[0]).toString().str();
 
   JSValueRef worker = arguments[1];
+  JSValueRef globalObj = arguments[2];
 
   JSCExecutor *executor;
   try {
@@ -504,7 +513,7 @@ JSValueRef JSCExecutor::nativeStartWorker(
     return JSValueMakeUndefined(ctx);
   }
 
-  int workerId = executor->addWebWorker(scriptFile, worker);
+  int workerId = executor->addWebWorker(scriptFile, worker, globalObj);
 
   return JSValueMakeNumber(ctx, workerId);
 }
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.h b/ReactAndroid/src/main/jni/react/JSCExecutor.h
index c60f33422a6a..6b2669dbe9d4 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.h
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.h
@@ -92,7 +92,8 @@ class JSCExecutor : public JSExecutor {
       Bridge *bridge,
       int workerId,
       JSCExecutor *owner,
-      const std::string& script);
+      const std::string& script,
+      const std::unordered_map<std::string, std::string>& globalObjAsJSON);
 
   void initOnJSVMThread();
   void terminateOnJSVMThread();
@@ -100,7 +101,7 @@ class JSCExecutor : public JSExecutor {
   void flushQueueImmediate(std::string queueJSON);
   void loadModule(uint32_t moduleId);
 
-  int addWebWorker(const std::string& script, JSValueRef workerRef);
+  int addWebWorker(const std::string& script, JSValueRef workerRef, JSValueRef globalObjRef);
   void postMessageToOwnedWebWorker(int worker, JSValueRef message, JSValueRef *exn);
   void postMessageToOwner(JSValueRef result);
   void receiveMessageFromOwnedWebWorker(int workerId, const std::string& message);

From 54a423e46639b80d2288a68aa4f82c241fd21672 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Fri, 19 Feb 2016 09:16:38 -0800
Subject: [PATCH 1239/1411] fixed master branch

Summary:shame to astreet and glory circle ci
Closes https://github.com/facebook/react-native/pull/6038

Differential Revision: D2954377

fb-gh-sync-id: cda4f1e4d46c5a477756131a4c65a9430cd3cd95
shipit-source-id: cda4f1e4d46c5a477756131a4c65a9430cd3cd95
---
 ReactAndroid/src/main/jni/react/Android.mk | 1 -
 1 file changed, 1 deletion(-)

diff --git a/ReactAndroid/src/main/jni/react/Android.mk b/ReactAndroid/src/main/jni/react/Android.mk
index cafcb591b878..f72729bdce26 100644
--- a/ReactAndroid/src/main/jni/react/Android.mk
+++ b/ReactAndroid/src/main/jni/react/Android.mk
@@ -8,7 +8,6 @@ LOCAL_SRC_FILES := \
   Bridge.cpp \
   JSCExecutor.cpp \
   JSCHelpers.cpp \
-  JSCWebWorker.cpp \
   MethodCall.cpp \
   Platform.cpp \
   Value.cpp \

From 9294c6f5d4afcaf4c1020c3b9de342b66ed258c9 Mon Sep 17 00:00:00 2001
From: Chris Hopman <cjhopman@fb.com>
Date: Fri, 19 Feb 2016 16:22:16 -0800
Subject: [PATCH 1240/1411] Initialize glog in react native.

Reviewed By: astreet

Differential Revision: D2931172

fb-gh-sync-id: 837af947846ba862f7e82110771a680f6991342f
shipit-source-id: 837af947846ba862f7e82110771a680f6991342f
---
 .../jni/first-party/fbgloginit/Android.mk     |  24 +++
 .../src/main/jni/first-party/fbgloginit/BUCK  |  21 +++
 .../jni/first-party/fbgloginit/fb/glog_init.h |  11 ++
 .../jni/first-party/fbgloginit/glog_init.cpp  | 142 ++++++++++++++++++
 .../src/main/jni/react/jni/Android.mk         |   3 +-
 ReactAndroid/src/main/jni/react/jni/BUCK      |   1 +
 .../src/main/jni/react/jni/OnLoad.cpp         |   2 +
 7 files changed, 203 insertions(+), 1 deletion(-)
 create mode 100644 ReactAndroid/src/main/jni/first-party/fbgloginit/Android.mk
 create mode 100644 ReactAndroid/src/main/jni/first-party/fbgloginit/BUCK
 create mode 100644 ReactAndroid/src/main/jni/first-party/fbgloginit/fb/glog_init.h
 create mode 100644 ReactAndroid/src/main/jni/first-party/fbgloginit/glog_init.cpp

diff --git a/ReactAndroid/src/main/jni/first-party/fbgloginit/Android.mk b/ReactAndroid/src/main/jni/first-party/fbgloginit/Android.mk
new file mode 100644
index 000000000000..e768bb21577a
--- /dev/null
+++ b/ReactAndroid/src/main/jni/first-party/fbgloginit/Android.mk
@@ -0,0 +1,24 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+       glog_init.cpp
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/..
+
+LOCAL_CFLAGS := -fexceptions -fno-omit-frame-pointer
+LOCAL_CFLAGS += -Wall -Werror
+
+CXX11_FLAGS := -std=gnu++11
+LOCAL_CFLAGS += $(CXX11_FLAGS)
+
+LOCAL_EXPORT_CPPFLAGS := $(CXX11_FLAGS)
+
+LOCAL_LDLIBS := -llog
+
+LOCAL_SHARED_LIBRARIES := libglog
+
+LOCAL_MODULE := libglog_init
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/ReactAndroid/src/main/jni/first-party/fbgloginit/BUCK b/ReactAndroid/src/main/jni/first-party/fbgloginit/BUCK
new file mode 100644
index 000000000000..c058851bdc80
--- /dev/null
+++ b/ReactAndroid/src/main/jni/first-party/fbgloginit/BUCK
@@ -0,0 +1,21 @@
+cxx_library(
+  name = 'fbgloginit',
+  force_static = True,
+  srcs = [
+    'glog_init.cpp',
+  ],
+  exported_headers = ['fb/glog_init.h'],
+  header_namespace = 'fbgloginit',
+  compiler_flags = [
+    '-fexceptions',
+    '-fno-omit-frame-pointer',
+  ],
+  linker_flags = [
+    '-llog',
+  ],
+  deps=[
+    '//xplat/third-party/glog:glog',
+  ],
+  visibility=['PUBLIC'],
+)
+
diff --git a/ReactAndroid/src/main/jni/first-party/fbgloginit/fb/glog_init.h b/ReactAndroid/src/main/jni/first-party/fbgloginit/fb/glog_init.h
new file mode 100644
index 000000000000..a377986223dd
--- /dev/null
+++ b/ReactAndroid/src/main/jni/first-party/fbgloginit/fb/glog_init.h
@@ -0,0 +1,11 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+#include <string>
+
+namespace facebook { namespace gloginit {
+
+void initialize(const char* tag = "fb");
+
+}}
diff --git a/ReactAndroid/src/main/jni/first-party/fbgloginit/glog_init.cpp b/ReactAndroid/src/main/jni/first-party/fbgloginit/glog_init.cpp
new file mode 100644
index 000000000000..771516a2dcdf
--- /dev/null
+++ b/ReactAndroid/src/main/jni/first-party/fbgloginit/glog_init.cpp
@@ -0,0 +1,142 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#include "fb/glog_init.h"
+
+#include <iostream>
+#include <mutex>
+#include <stdexcept>
+
+#include <glog/logging.h>
+
+#ifdef __ANDROID__
+
+#include <android/log.h>
+
+static int toAndroidLevel(google::LogSeverity severity) {
+  switch (severity) {
+  case google::GLOG_INFO:
+    return ANDROID_LOG_INFO;
+  case google::GLOG_WARNING:
+    return ANDROID_LOG_WARN;
+  case google::GLOG_ERROR:
+    return ANDROID_LOG_ERROR;
+  case google::GLOG_FATAL:
+    return ANDROID_LOG_FATAL;
+  default:
+    return ANDROID_LOG_FATAL;
+  }
+}
+
+/**
+ * Sends GLog output to adb logcat.
+ */
+class LogcatSink : public google::LogSink {
+ public:
+  void send(
+      google::LogSeverity severity,
+      const char* full_filename,
+      const char* base_filename,
+      int line,
+      const struct ::tm* tm_time,
+      const char* message,
+      size_t message_len) override {
+    auto level = toAndroidLevel(severity);
+    __android_log_print(
+        level,
+        base_filename,
+        "%.*s",
+        (int)message_len,
+        message);
+  }
+};
+
+/**
+ * Sends GLog output to adb logcat.
+ */
+class TaggedLogcatSink : public google::LogSink {
+  const std::string tag_;
+
+ public:
+  TaggedLogcatSink(const std::string &tag) : tag_{tag} {}
+
+  void send(
+      google::LogSeverity severity,
+      const char* full_filename,
+      const char* base_filename,
+      int line,
+      const struct ::tm* tm_time,
+      const char* message,
+      size_t message_len) override {
+    auto level = toAndroidLevel(severity);
+    __android_log_print(
+      level,
+      tag_.c_str(),
+      "%.*s",
+      (int)message_len,
+      message);
+  }
+};
+
+static google::LogSink* make_sink(const std::string& tag) {
+  if (tag.empty()) {
+    return new LogcatSink{};
+  } else {
+    return new TaggedLogcatSink{tag};
+  }
+}
+
+static void sendGlogOutputToLogcat(const char* tag) {
+  google::AddLogSink(make_sink(tag));
+
+  // Disable logging to files
+  for (auto i = 0; i < google::NUM_SEVERITIES; ++i) {
+    google::SetLogDestination(i, "");
+  }
+}
+
+#endif // __ANDROID__
+
+static void lastResort(const char* tag, const char* msg, const char* arg = nullptr) {
+#ifdef __ANDROID__
+  if (!arg) {
+    __android_log_write(ANDROID_LOG_ERROR, tag, msg);
+  } else {
+    __android_log_print(ANDROID_LOG_ERROR, tag, "%s: %s", msg, arg);
+  }
+#else 
+  std::cerr << msg;
+  if (arg) {
+    std::cerr << ": " << arg;
+  }
+  std::cerr << std::endl;
+#endif
+}
+
+namespace facebook { namespace gloginit {
+
+void initialize(const char* tag) {
+  static std::once_flag flag{};
+  static auto failed = false;
+
+  std::call_once(flag, [tag] {
+    try {
+      google::InitGoogleLogging(tag);
+
+#ifdef __ANDROID__
+      sendGlogOutputToLogcat(tag);
+#endif
+    } catch (std::exception& ex) {
+      lastResort(tag, "Failed to initialize glog", ex.what());
+      failed = true;
+    } catch (...) {
+      lastResort(tag, "Failed to initialize glog");
+      failed = true;
+    }
+  });
+
+  if (failed) {
+    throw std::runtime_error{"Failed to initialize glog"};
+  }
+}
+
+}}
diff --git a/ReactAndroid/src/main/jni/react/jni/Android.mk b/ReactAndroid/src/main/jni/react/jni/Android.mk
index 9d4d9b2b5fff..e5184d8e81fa 100644
--- a/ReactAndroid/src/main/jni/react/jni/Android.mk
+++ b/ReactAndroid/src/main/jni/react/jni/Android.mk
@@ -22,7 +22,7 @@ LOCAL_CFLAGS += $(CXX11_FLAGS)
 LOCAL_EXPORT_CPPFLAGS := $(CXX11_FLAGS)
 
 LOCAL_LDLIBS += -landroid
-LOCAL_SHARED_LIBRARIES := libfolly_json libfbjni libjsc
+LOCAL_SHARED_LIBRARIES := libfolly_json libfbjni libjsc libglog_init
 LOCAL_STATIC_LIBRARIES := libreactnative
 
 include $(BUILD_SHARED_LIBRARY)
@@ -30,5 +30,6 @@ include $(BUILD_SHARED_LIBRARY)
 $(call import-module,react)
 $(call import-module,jsc)
 $(call import-module,folly)
+$(call import-module,fbgloginit)
 $(call import-module,jni)
 $(call import-module,jsc)
diff --git a/ReactAndroid/src/main/jni/react/jni/BUCK b/ReactAndroid/src/main/jni/react/jni/BUCK
index bebdf54ce2a3..180bac5b87eb 100644
--- a/ReactAndroid/src/main/jni/react/jni/BUCK
+++ b/ReactAndroid/src/main/jni/react/jni/BUCK
@@ -4,6 +4,7 @@ include_defs('//ReactAndroid/DEFS')
 SUPPORTED_PLATFORMS = '^android-(armv7|x86)$'
 
 DEPS = [
+  react_native_target('jni/first-party/fbgloginit:fbgloginit'),
   '//native/jni:jni',
   '//native/third-party/android-ndk:android',
   '//xplat/folly:molly',
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 1e4c37950352..9f5d95698527 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -3,6 +3,7 @@
 #include <android/asset_manager_jni.h>
 #include <android/input.h>
 #include <fb/log.h>
+#include <fbgloginit/fb/glog_init.h>
 #include <folly/json.h>
 #include <jni/Countable.h>
 #include <jni/Environment.h>
@@ -844,6 +845,7 @@ jmethodID getLogMarkerMethod() {
 
 extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
   return initialize(vm, [] {
+    facebook::gloginit::initialize(LOG_TAG);
     // Inject some behavior into react/
     ReactMarker::logMarker = bridge::logMarker;
     WebWorkerUtil::createWebWorkerThread = WebWorkers::createWebWorkerThread;

From 2b46fd424d9f95fe82cbb302a66f02e09a56fcc5 Mon Sep 17 00:00:00 2001
From: Eric Vicenti <evv@fb.com>
Date: Fri, 19 Feb 2016 16:55:07 -0800
Subject: [PATCH 1241/1411] Clean up UIExplorer and seperate RCTRootView
 examples

Reviewed By: nicklockwood

Differential Revision: D2951030

fb-gh-sync-id: e7cf64035d8e9e30aafe8b4944b6a20e4bc55078
shipit-source-id: e7cf64035d8e9e30aafe8b4944b6a20e4bc55078
---
 .../RootViewSizeFlexibilityExampleApp.js      | 76 +++++++++++++++
 .../UIExplorer/SetPropertiesExampleApp.js     | 20 ++--
 Examples/UIExplorer/UIExplorerApp.android.js  | 62 ++++++------
 Examples/UIExplorer/UIExplorerApp.ios.js      | 96 ++++---------------
 Examples/UIExplorer/UIExplorerList.android.js |  1 -
 5 files changed, 136 insertions(+), 119 deletions(-)
 create mode 100644 Examples/UIExplorer/RootViewSizeFlexibilityExampleApp.js

diff --git a/Examples/UIExplorer/RootViewSizeFlexibilityExampleApp.js b/Examples/UIExplorer/RootViewSizeFlexibilityExampleApp.js
new file mode 100644
index 000000000000..baab38671791
--- /dev/null
+++ b/Examples/UIExplorer/RootViewSizeFlexibilityExampleApp.js
@@ -0,0 +1,76 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ *
+ * @flow
+ */
+'use strict';
+
+const React = require('react-native');
+const {
+  StyleSheet,
+  Text,
+  TouchableHighlight,
+  View,
+} = React;
+
+class RootViewSizeFlexibilityExampleApp extends React.Component {
+
+  constructor(props: {toggled: boolean}) {
+    super(props);
+    this.state = { toggled: false };
+  }
+
+  _onPressButton() {
+    this.setState({ toggled: !this.state.toggled });
+  }
+
+  render() {
+    const viewStyle = this.state.toggled ? styles.bigContainer : styles.smallContainer;
+
+    return (
+      <TouchableHighlight onPress={this._onPressButton.bind(this)}>
+        <View style={viewStyle}>
+          <View style={styles.center}>
+            <Text style={styles.whiteText}>
+              React Native Button
+            </Text>
+          </View>
+        </View>
+      </TouchableHighlight>
+    );
+  }
+
+}
+
+const styles = StyleSheet.create({
+  bigContainer: {
+    flex: 1,
+    height: 60,
+    backgroundColor: 'gray',
+  },
+  smallContainer: {
+    flex: 1,
+    height: 40,
+    backgroundColor: 'gray',
+  },
+  center: {
+    flex: 1,
+    alignItems: 'center',
+    justifyContent: 'center',
+  },
+  whiteText: {
+    color: 'white',
+  }
+});
+
+module.exports = RootViewSizeFlexibilityExampleApp;
diff --git a/Examples/UIExplorer/SetPropertiesExampleApp.js b/Examples/UIExplorer/SetPropertiesExampleApp.js
index 748bbc3ccb4a..f5dc9c8eab39 100644
--- a/Examples/UIExplorer/SetPropertiesExampleApp.js
+++ b/Examples/UIExplorer/SetPropertiesExampleApp.js
@@ -13,17 +13,18 @@
  *
  * @flow
  */
-
 'use strict';
 
-var React = require('React');
-var Text = require('Text');
-var View = require('View');
+const React = require('react-native');
+const {
+  Text,
+  View,
+} = React;
 
-var SetPropertiesExampleApp = React.createClass({
+class SetPropertiesExampleApp extends React.Component {
 
-  render: function() {
-    var wrapperStyle = {
+  render() {
+    const wrapperStyle = {
       backgroundColor: this.props.color,
       flex: 1,
       alignItems: 'center',
@@ -37,7 +38,8 @@ var SetPropertiesExampleApp = React.createClass({
         </Text>
       </View>
     );
-  },
-});
+  }
+
+}
 
 module.exports = SetPropertiesExampleApp;
diff --git a/Examples/UIExplorer/UIExplorerApp.android.js b/Examples/UIExplorer/UIExplorerApp.android.js
index cdf92c6848de..6446e8fa4df6 100644
--- a/Examples/UIExplorer/UIExplorerApp.android.js
+++ b/Examples/UIExplorer/UIExplorerApp.android.js
@@ -16,8 +16,8 @@
  */
 'use strict';
 
-var React = require('react-native');
-var {
+const React = require('react-native');
+const {
   AppRegistry,
   BackAndroid,
   Dimensions,
@@ -27,29 +27,32 @@ var {
   View,
   StatusBar,
 } = React;
-var UIExplorerList = require('./UIExplorerList.android');
+const UIExplorerList = require('./UIExplorerList.android');
 
-var DRAWER_WIDTH_LEFT = 56;
+const DRAWER_WIDTH_LEFT = 56;
 
-var UIExplorerApp = React.createClass({
-  getInitialState: function() {
-    return {
+class UIExplorerApp extends React.Component {
+  constructor(props) {
+    super(props);
+    this.onSelectExample = this.onSelectExample.bind(this);
+    this._handleBackButtonPress = this._handleBackButtonPress.bind(this);
+    this.state = {
       example: this._getUIExplorerHome(),
     };
-  },
+  }
 
-  _getUIExplorerHome: function() {
+  _getUIExplorerHome() {
     return {
       title: 'UIExplorer',
       component: this._renderHome(),
     };
-  },
+  }
 
-  componentWillMount: function() {
+  componentWillMount() {
     BackAndroid.addEventListener('hardwareBackPress', this._handleBackButtonPress);
-  },
+  }
 
-  render: function() {
+  render() {
     return (
       <DrawerLayoutAndroid
         drawerPosition={DrawerLayoutAndroid.positions.Left}
@@ -59,19 +62,19 @@ var UIExplorerApp = React.createClass({
         renderNavigationView={this._renderNavigationView}>
         {this._renderNavigation()}
       </DrawerLayoutAndroid>
-      );
-  },
+    );
+  }
 
-  _renderNavigationView: function() {
+  _renderNavigationView() {
     return (
       <UIExplorerList
         onSelectExample={this.onSelectExample}
         isInDrawer={true}
       />
     );
-  },
+  }
 
-  onSelectExample: function(example) {
+  onSelectExample(example) {
     this.drawer.closeDrawer();
     if (example.title === this._getUIExplorerHome().title) {
       example = this._getUIExplorerHome();
@@ -79,10 +82,10 @@ var UIExplorerApp = React.createClass({
     this.setState({
       example: example,
     });
-  },
+  }
 
-  _renderHome: function() {
-    var onSelectExample = this.onSelectExample;
+  _renderHome() {
+    const onSelectExample = this.onSelectExample;
     return React.createClass({
       render: function() {
         return (
@@ -93,10 +96,10 @@ var UIExplorerApp = React.createClass({
         );
       }
     });
-  },
+  }
 
-  _renderNavigation: function() {
-    var Component = this.state.example.component;
+  _renderNavigation() {
+    const Component = this.state.example.component;
     return (
       <View style={styles.container}>
         <StatusBar
@@ -114,9 +117,9 @@ var UIExplorerApp = React.createClass({
         />
       </View>
     );
-  },
+  }
 
-  _handleBackButtonPress: function() {
+  _handleBackButtonPress() {
     if (
       this._exampleRef &&
       this._exampleRef.handleBackAction &&
@@ -129,10 +132,11 @@ var UIExplorerApp = React.createClass({
       return true;
     }
     return false;
-  },
-});
+  }
+
+}
 
-var styles = StyleSheet.create({
+const styles = StyleSheet.create({
   container: {
     flex: 1,
   },
diff --git a/Examples/UIExplorer/UIExplorerApp.ios.js b/Examples/UIExplorer/UIExplorerApp.ios.js
index f93cc2a66a64..120c772d8da2 100644
--- a/Examples/UIExplorer/UIExplorerApp.ios.js
+++ b/Examples/UIExplorer/UIExplorerApp.ios.js
@@ -12,33 +12,33 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  *
  * @providesModule UIExplorerApp
- * @flow
  */
 'use strict';
 
-var React = require('react-native');
-var UIExplorerList = require('./UIExplorerList.ios');
-var {
+const React = require('react-native');
+const UIExplorerList = require('./UIExplorerList.ios');
+const SetPropertiesExampleApp = require('./SetPropertiesExampleApp');
+const RootViewSizeFlexibilityExampleApp = require('./RootViewSizeFlexibilityExampleApp');
+const {
   AppRegistry,
   NavigatorIOS,
   StyleSheet,
-  Text,
-  TouchableHighlight,
   View,
   StatusBar,
 } = React;
 
-var UIExplorerApp = React.createClass({
+class UIExplorerApp extends React.Component {
 
-  getInitialState: function() {
-    return {
+  constructor(props) {
+    super(props);
+    this.state = {
       openExternalExample: (null: ?React.Component),
     };
-  },
+  }
 
-  render: function() {
+  render() {
     if (this.state.openExternalExample) {
-      var Example = this.state.openExternalExample;
+      const Example = this.state.openExternalExample;
       return (
         <Example
           onExampleExit={() => {
@@ -49,7 +49,7 @@ var UIExplorerApp = React.createClass({
     }
 
     return (
-      <View style={{flex: 1}}>
+      <View style={styles.container}>
         <StatusBar barStyle="default" />
         <NavigatorIOS
           style={styles.container}
@@ -68,80 +68,16 @@ var UIExplorerApp = React.createClass({
       </View>
     );
   }
-});
 
-var styles = StyleSheet.create({
+}
+
+const styles = StyleSheet.create({
   container: {
     flex: 1,
   },
   itemWrapper: {
     backgroundColor: '#eaeaea',
   },
-  bigContainer: {
-    flex: 1,
-    height: 60,
-    backgroundColor: 'gray',
-  },
-  smallContainer: {
-    flex: 1,
-    height: 40,
-    backgroundColor: 'gray',
-  },
-  center: {
-    flex: 1,
-    alignItems: 'center',
-    justifyContent: 'center',
-  },
-  whiteText: {
-    color: 'white',
-  }
-});
-
-var SetPropertiesExampleApp = React.createClass({
-
-  render: function() {
-    var wrapperStyle = {
-      backgroundColor: this.props.color,
-      flex: 1,
-      alignItems: 'center',
-      justifyContent: 'center'
-    };
-
-    return (
-      <View style={wrapperStyle}>
-        <Text>
-          Embedded React Native view
-        </Text>
-      </View>
-    );
-  },
-});
-
-var RootViewSizeFlexibilityExampleApp = React.createClass({
-
-  getInitialState: function () {
-    return { toggled: false };
-  },
-
-  _onPressButton: function() {
-    this.setState({ toggled: !this.state.toggled });
-  },
-
-  render: function() {
-    var viewStyle = this.state.toggled ? styles.bigContainer : styles.smallContainer;
-
-    return (
-      <TouchableHighlight onPress={this._onPressButton}>
-        <View style={viewStyle}>
-          <View style={styles.center}>
-            <Text style={styles.whiteText}>
-              React Native Button
-            </Text>
-          </View>
-        </View>
-      </TouchableHighlight>
-    );
-  },
 });
 
 AppRegistry.registerComponent('SetPropertiesExampleApp', () => SetPropertiesExampleApp);
diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index 804ed69d4c59..8959a0919f9a 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -53,7 +53,6 @@ var APIS = [
   require('./ImageEditingExample'),
   require('./IntentAndroidExample.android'),
   require('./LayoutEventsExample'),
-  require('./NavigationExperimental/NavigationExperimentalExample'),
   require('./LayoutExample'),
   require('./NavigationExperimental/NavigationExperimentalExample'),
   require('./NetInfoExample'),

From 8e809e9b24eee6930427edf0b3e876bbda52da88 Mon Sep 17 00:00:00 2001
From: hedger wang <hedger@fb.com>
Date: Fri, 19 Feb 2016 22:58:38 -0800
Subject: [PATCH 1242/1411] fix broken drawer layout

Reviewed By: furdei

Differential Revision: D2953499

fb-gh-sync-id: 9f37af631b9540881c5af4dc8abe2b9fd334b807
shipit-source-id: 9f37af631b9540881c5af4dc8abe2b9fd334b807
---
 Libraries/ReactIOS/renderApplication.android.js | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/Libraries/ReactIOS/renderApplication.android.js b/Libraries/ReactIOS/renderApplication.android.js
index 1abfeb8b3a99..49715076acc8 100644
--- a/Libraries/ReactIOS/renderApplication.android.js
+++ b/Libraries/ReactIOS/renderApplication.android.js
@@ -132,11 +132,12 @@ var styles = StyleSheet.create({
   // This is needed so the application covers the whole screen
   // and therefore the contents of the Portal are not clipped.
   appContainer: {
-    position: 'absolute',
+    backgroundColor: 'transparent',
+    bottom: 0,
     left: 0,
-    top: 0,
+    position: 'absolute',
     right: 0,
-    bottom: 0,
+    top: 0,
   },
 });
 

From 6f565383ecf1c2ab3e0781116b8a06dd8e1ef18a Mon Sep 17 00:00:00 2001
From: Der-Nien Lee <dernienl@fb.com>
Date: Sat, 20 Feb 2016 02:18:10 -0800
Subject: [PATCH 1243/1411] Revert D2953499

Reviewed By: fkgozali

Differential Revision: D2958190

fb-gh-sync-id: cd52ad421d0b7d5c69109337c2a0caa0d072974b
shipit-source-id: cd52ad421d0b7d5c69109337c2a0caa0d072974b
---
 Libraries/ReactIOS/renderApplication.android.js | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/Libraries/ReactIOS/renderApplication.android.js b/Libraries/ReactIOS/renderApplication.android.js
index 49715076acc8..1abfeb8b3a99 100644
--- a/Libraries/ReactIOS/renderApplication.android.js
+++ b/Libraries/ReactIOS/renderApplication.android.js
@@ -132,12 +132,11 @@ var styles = StyleSheet.create({
   // This is needed so the application covers the whole screen
   // and therefore the contents of the Portal are not clipped.
   appContainer: {
-    backgroundColor: 'transparent',
-    bottom: 0,
-    left: 0,
     position: 'absolute',
-    right: 0,
+    left: 0,
     top: 0,
+    right: 0,
+    bottom: 0,
   },
 });
 

From 89ea98554046356f934d7607270a22d0924b49c9 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Sun, 21 Feb 2016 01:33:37 -0800
Subject: [PATCH 1244/1411] Restrict the version range of node-haste to ~2.0.0

Summary: This restricts the version range of node-haste to >=2.0.0 <2.1.0, because 2.1.0 has a breaking change.

Reviewed By: mkonicek

Differential Revision: D2958263

fb-gh-sync-id: b8a1c39857731865fd16f5287af53ad0536781c2
shipit-source-id: b8a1c39857731865fd16f5287af53ad0536781c2
---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 25f523657208..e69bcfbf6281 100644
--- a/package.json
+++ b/package.json
@@ -148,7 +148,7 @@
     "mkdirp": "^0.5.1",
     "module-deps": "^3.9.1",
     "node-fetch": "^1.3.3",
-    "node-haste": "^2.0.0",
+    "node-haste": "~2.0.0",
     "opn": "^3.0.2",
     "optimist": "^0.6.1",
     "progress": "^1.1.8",

From 91788d2bbd35a530269664c71cd17220cc7bc80a Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Sun, 21 Feb 2016 16:16:42 -0800
Subject: [PATCH 1245/1411] Deprecate PullToRefreshViewAndroid and remove it
 from the website

Summary:I forgot to add a deprecation warning to PullToRefreshViewAndroid when I worked on RefreshControl. This adds one as well as remove it from the website and remove the UIExplorer example. Now that we have versioned doc I think it is fine to remove deprecated stuff from the website so it is easier for users to know what component they should use. Last thing, I enabled flow in RefreshControl and fixed the one warning.
Closes https://github.com/facebook/react-native/pull/6055

Differential Revision: D2959502

Pulled By: mkonicek

fb-gh-sync-id: 9b23f84ea35c770bfe2a83d0fd3ec7e439669c33
shipit-source-id: 9b23f84ea35c770bfe2a83d0fd3ec7e439669c33
---
 ...PullToRefreshViewAndroidExample.android.js | 128 ------------------
 Examples/UIExplorer/UIExplorerList.android.js |   1 -
 .../RefreshControl/RefreshControl.js          |   7 +-
 .../PullToRefreshViewAndroid.android.js       |   8 +-
 website/server/extractDocs.js                 |   1 -
 5 files changed, 11 insertions(+), 134 deletions(-)
 delete mode 100644 Examples/UIExplorer/PullToRefreshViewAndroidExample.android.js

diff --git a/Examples/UIExplorer/PullToRefreshViewAndroidExample.android.js b/Examples/UIExplorer/PullToRefreshViewAndroidExample.android.js
deleted file mode 100644
index 3d22f7608e93..000000000000
--- a/Examples/UIExplorer/PullToRefreshViewAndroidExample.android.js
+++ /dev/null
@@ -1,128 +0,0 @@
-/**
-* The examples provided by Facebook are for non-commercial testing and
-* evaluation purposes only.
-*
-* Facebook reserves all rights not expressly granted.
-*
-* 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 NON INFRINGEMENT. IN NO EVENT SHALL
-* FACEBOOK 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.
-*
-*/
-'use strict';
-
-const React = require('react-native');
-const {
-  ScrollView,
-  StyleSheet,
-  PullToRefreshViewAndroid,
-  Text,
-  TouchableWithoutFeedback,
-  View,
-} = React;
-
-const styles = StyleSheet.create({
-  row: {
-    borderColor: 'grey',
-    borderWidth: 1,
-    padding: 20,
-    backgroundColor: '#3a5795',
-    margin: 5,
-  },
-  text: {
-    alignSelf: 'center',
-    color: '#fff',
-
-  },
-  layout: {
-    flex: 1,
-  },
-  scrollview: {
-    flex: 1,
-  },
-});
-
-const Row = React.createClass({
-  _onClick: function() {
-    this.props.onClick(this.props.data);
-  },
-  render: function() {
-    return (
-     <TouchableWithoutFeedback onPress={this._onClick} >
-        <View style={styles.row}>
-          <Text style={styles.text}>
-            {this.props.data.text + ' (' + this.props.data.clicks + ' clicks)'}
-          </Text>
-        </View>
-    </TouchableWithoutFeedback>
-    );
-  },
-});
-const PullToRefreshViewAndroidExample = React.createClass({
-  statics: {
-    title: '<PullToRefreshViewAndroid>',
-    description: 'Container that adds pull-to-refresh support to its child view.'
-  },
-
-  getInitialState() {
-    return {
-      isRefreshing: false,
-      loaded: 0,
-      rowData: Array.from(new Array(20)).map(
-        (val, i) => ({text: 'Initial row' + i, clicks: 0})
-      ),
-    };
-  },
-
-  _onClick(row) {
-    row.clicks++;
-    this.setState({
-      rowData: this.state.rowData,
-    });
-  },
-
-  render() {
-    const rows = this.state.rowData.map((row, ii) => {
-      return <Row key={ii} data={row} onClick={this._onClick}/>;
-    });
-    return (
-      <PullToRefreshViewAndroid
-        style={styles.layout}
-        refreshing={this.state.isRefreshing}
-        onRefresh={this._onRefresh}
-        colors={['#ff0000', '#00ff00', '#0000ff']}
-        progressBackgroundColor={'#ffff00'}
-        >
-        <ScrollView style={styles.scrollview}>
-          {rows}
-        </ScrollView>
-      </PullToRefreshViewAndroid>
-    );
-  },
-
-  _onRefresh() {
-    this.setState({isRefreshing: true});
-    setTimeout(() => {
-      // prepend 10 items
-      const rowData = Array.from(new Array(10))
-      .map((val, i) => ({
-        text: 'Loaded row' + (+this.state.loaded + i),
-        clicks: 0,
-      }))
-      .concat(this.state.rowData);
-
-      this.setState({
-        loaded: this.state.loaded + 10,
-        isRefreshing: false,
-        rowData: rowData,
-      });
-    }, 5000);
-  },
-
-});
-
-
-module.exports = PullToRefreshViewAndroidExample;
diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index 8959a0919f9a..4cd5649d7066 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -27,7 +27,6 @@ var COMPONENTS = [
   require('./ListViewExample'),
   require('./PickerAndroidExample'),
   require('./ProgressBarAndroidExample'),
-  require('./PullToRefreshViewAndroidExample.android'),
   require('./RefreshControlExample'),
   require('./ScrollViewSimpleExample'),
   require('./StatusBarExample'),
diff --git a/Libraries/Components/RefreshControl/RefreshControl.js b/Libraries/Components/RefreshControl/RefreshControl.js
index 1ae8119a1e2e..ee285a3c752b 100644
--- a/Libraries/Components/RefreshControl/RefreshControl.js
+++ b/Libraries/Components/RefreshControl/RefreshControl.js
@@ -7,6 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule RefreshControl
+ * @flow
  */
 'use strict';
 
@@ -17,10 +18,10 @@ const View = require('View');
 
 const requireNativeComponent = require('requireNativeComponent');
 
-if (Platform.OS === 'ios') {
-  var RefreshLayoutConsts = {SIZE: {}};
-} else if (Platform.OS === 'android') {
+if (Platform.OS === 'android') {
   var RefreshLayoutConsts = require('NativeModules').UIManager.AndroidSwipeRefreshLayout.Constants;
+} else {
+  var RefreshLayoutConsts = {SIZE: {}};
 }
 
 /**
diff --git a/Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js b/Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js
index c0f498ba2532..e784052c3960 100644
--- a/Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js
+++ b/Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js
@@ -21,9 +21,11 @@ var requireNativeComponent = require('requireNativeComponent');
 var NATIVE_REF = 'native_swiperefreshlayout';
 
 /**
+ * Deprecated. Use `RefreshControl` instead.
+ *
  * React view that supports a single scrollable child view (e.g. `ScrollView`). When this child
  * view is at `scrollY: 0`, swiping down triggers an `onRefresh` event.
- * 
+ *
  * The style `{flex: 1}` might be required to ensure the expected behavior of the child component
  * (e.g. when the child is expected to scroll with `ScrollView` or `ListView`).
  */
@@ -56,6 +58,10 @@ var PullToRefreshViewAndroid = React.createClass({
     size: React.PropTypes.oneOf(RefreshLayoutConsts.SIZE.DEFAULT, RefreshLayoutConsts.SIZE.LARGE),
   },
 
+  componentDidMount: function() {
+    console.warn('`PullToRefreshViewAndroid` is deprecated. Use `RefreshControl` instead.');
+  },
+
   getInnerViewNode: function() {
     return this.refs[NATIVE_REF];
   },
diff --git a/website/server/extractDocs.js b/website/server/extractDocs.js
index 8fd0992314cb..b74c029b76c0 100644
--- a/website/server/extractDocs.js
+++ b/website/server/extractDocs.js
@@ -203,7 +203,6 @@ var components = [
   '../Libraries/Components/Picker/Picker.js',
   '../Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js',
   '../Libraries/Components/ProgressViewIOS/ProgressViewIOS.ios.js',
-  '../Libraries/PullToRefresh/PullToRefreshViewAndroid.android.js',
   '../Libraries/Components/RefreshControl/RefreshControl.js',
   '../Libraries/Components/ScrollView/ScrollView.js',
   '../Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js',

From 93761c22de9fb56c035c384cea304ed244c72d49 Mon Sep 17 00:00:00 2001
From: Gaurav Arora <g.arora217@gmail.com>
Date: Sun, 21 Feb 2016 16:18:32 -0800
Subject: [PATCH 1246/1411] Add 'Collegiate - Learn Anywhere' to the showcase

Summary:Added Collegiate, an app that lets you learn from world's best colleges for free. Collegiate includes 650+ courses from MIT, Stanford, Yale, Berkeley, IIT Madras. The app is completely built using react native.
Closes https://github.com/facebook/react-native/pull/6033

Differential Revision: D2958238

fb-gh-sync-id: e55fed11e7fbef22552377e77359195c573bdd05
shipit-source-id: e55fed11e7fbef22552377e77359195c573bdd05
---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index e341f7f07e9f..191e42392a17 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -217,6 +217,12 @@ var apps = [
     link: 'https://www.codementor.io/downloads',
     author: 'Codementor',
   },
+  {
+    name: 'Collegiate - Learn Anywhere',
+    icon: 'http://a3.mzstatic.com/us/r30/Purple69/v4/17/a9/60/17a960d3-8cbd-913a-9f08-ebd9139c116c/icon175x175.png',
+    link: 'https://itunes.apple.com/app/id1072463482',
+    author: 'Gaurav Arora',
+  },
   {
     name: 'Company name search',
     icon: 'http://a4.mzstatic.com/us/r30/Purple69/v4/fd/47/53/fd47537c-5861-e208-d1d1-1e26b5e45a36/icon350x350.jpeg',

From ad17a2f2908f430b05fd2836d3f08873988bce10 Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Sun, 21 Feb 2016 16:35:44 -0800
Subject: [PATCH 1247/1411] Use ReactActivity for UIExplorer and Movies
 examples

Summary:This also fixes the examples since the app lifecycle methods were renamed recently.
Closes https://github.com/facebook/react-native/pull/6053

Differential Revision: D2959525

Pulled By: mkonicek

fb-gh-sync-id: 4a445b5e69b55aa75a1063054cf4c78de1f15da6
shipit-source-id: 4a445b5e69b55aa75a1063054cf4c78de1f15da6
---
 .../facebook/react/movies/MoviesActivity.java | 75 +++++--------------
 .../app/src/main/java/UIExplorerActivity.java | 74 +++++-------------
 2 files changed, 38 insertions(+), 111 deletions(-)

diff --git a/Examples/Movies/android/app/src/main/java/com/facebook/react/movies/MoviesActivity.java b/Examples/Movies/android/app/src/main/java/com/facebook/react/movies/MoviesActivity.java
index 3b2626601a34..a5dc16093b8d 100644
--- a/Examples/Movies/android/app/src/main/java/com/facebook/react/movies/MoviesActivity.java
+++ b/Examples/Movies/android/app/src/main/java/com/facebook/react/movies/MoviesActivity.java
@@ -11,79 +11,42 @@
  * 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.
  */
-
 package com.facebook.react.movies;
 
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.KeyEvent;
-
-import com.facebook.react.LifecycleState;
-import com.facebook.react.ReactInstanceManager;
-import com.facebook.react.ReactRootView;
-import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
+import com.facebook.react.ReactActivity;
+import com.facebook.react.ReactPackage;
 import com.facebook.react.shell.MainReactPackage;
 
-public class MoviesActivity extends Activity implements DefaultHardwareBackBtnHandler {
-
-  private ReactInstanceManager mReactInstanceManager;
-
-  @Override
-  protected void onCreate(Bundle savedInstanceState) {
-    super.onCreate(savedInstanceState);
-    setContentView(R.layout.activity_main);
-
-    mReactInstanceManager = ReactInstanceManager.builder()
-        .setApplication(getApplication())
-        .setBundleAssetName("MoviesApp.android.bundle")
-        .setJSMainModuleName("Examples/Movies/MoviesApp.android")
-        .addPackage(new MainReactPackage())
-        .setUseDeveloperSupport(true)
-        .setInitialLifecycleState(LifecycleState.RESUMED)
-        .build();
+import java.util.Arrays;
+import java.util.List;
 
-    ((ReactRootView) findViewById(R.id.react_root_view))
-        .startReactApplication(mReactInstanceManager, "MoviesApp", null);
-  }
+import javax.annotation.Nullable;
 
+public class MoviesActivity extends ReactActivity {
   @Override
-  public boolean onKeyUp(int keyCode, KeyEvent event) {
-    if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
-      mReactInstanceManager.showDevOptionsDialog();
-      return true;
-    }
-    return super.onKeyUp(keyCode, event);
+  protected String getMainComponentName() {
+    return "MoviesApp";
   }
 
   @Override
-  protected void onPause() {
-    super.onPause();
-
-    if (mReactInstanceManager != null) {
-      mReactInstanceManager.onPause();
-    }
-  }
+  protected @Nullable String getBundleAssetName() {
+    return "MoviesApp.android.bundle";
+  };
 
   @Override
-  protected void onResume() {
-    super.onResume();
-
-    if (mReactInstanceManager != null) {
-      mReactInstanceManager.onResume(this, this);
-    }
+  protected String getJSMainModuleName() {
+    return "Examples/Movies/MoviesApp.android";
   }
 
   @Override
-  public void onBackPressed() {
-    if (mReactInstanceManager != null) {
-      mReactInstanceManager.onBackPressed();
-    } else {
-      super.onBackPressed();
-    }
+  protected boolean getUseDeveloperSupport() {
+    return true;
   }
 
   @Override
-  public void invokeDefaultOnBackPressed() {
-    super.onBackPressed();
+  protected List<ReactPackage> getPackages() {
+    return Arrays.<ReactPackage>asList(
+      new MainReactPackage()
+    );
   }
 }
diff --git a/Examples/UIExplorer/android/app/src/main/java/UIExplorerActivity.java b/Examples/UIExplorer/android/app/src/main/java/UIExplorerActivity.java
index c1dd73f6d524..f4867da6b261 100644
--- a/Examples/UIExplorer/android/app/src/main/java/UIExplorerActivity.java
+++ b/Examples/UIExplorer/android/app/src/main/java/UIExplorerActivity.java
@@ -14,76 +14,40 @@
 
 package com.facebook.react.uiapp;
 
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.KeyEvent;
-
-import com.facebook.react.LifecycleState;
-import com.facebook.react.ReactInstanceManager;
-import com.facebook.react.ReactRootView;
-import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
+import com.facebook.react.ReactActivity;
+import com.facebook.react.ReactPackage;
 import com.facebook.react.shell.MainReactPackage;
 
-public class UIExplorerActivity extends Activity implements DefaultHardwareBackBtnHandler {
+import java.util.Arrays;
+import java.util.List;
 
-  private ReactInstanceManager mReactInstanceManager;
+import javax.annotation.Nullable;
 
+public class UIExplorerActivity extends ReactActivity {
   @Override
-  protected void onCreate(Bundle savedInstanceState) {
-    super.onCreate(savedInstanceState);
-    setContentView(R.layout.activity_main);
-
-    mReactInstanceManager = ReactInstanceManager.builder()
-        .setApplication(getApplication())
-        .setBundleAssetName("UIExplorerApp.android.bundle")
-        .setJSMainModuleName("Examples/UIExplorer/UIExplorerApp.android")
-        .addPackage(new MainReactPackage())
-        .setUseDeveloperSupport(true)
-        .setInitialLifecycleState(LifecycleState.RESUMED)
-        .build();
-
-    ((ReactRootView) findViewById(R.id.react_root_view))
-        .startReactApplication(mReactInstanceManager, "UIExplorerApp", null);
+  protected String getMainComponentName() {
+      return "UIExplorerApp";
   }
 
   @Override
-  public boolean onKeyUp(int keyCode, KeyEvent event) {
-    if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
-      mReactInstanceManager.showDevOptionsDialog();
-      return true;
-    }
-    return super.onKeyUp(keyCode, event);
-  }
+  protected @Nullable String getBundleAssetName() {
+    return "UIExplorerApp.android.bundle";
+  };
 
   @Override
-  protected void onPause() {
-    super.onPause();
-
-    if (mReactInstanceManager != null) {
-      mReactInstanceManager.onPause();
-    }
+  protected String getJSMainModuleName() {
+    return "Examples/UIExplorer/UIExplorerApp.android";
   }
 
   @Override
-  protected void onResume() {
-    super.onResume();
-
-    if (mReactInstanceManager != null) {
-      mReactInstanceManager.onResume(this, this);
-    }
-  }
-
-  @Override
-  public void onBackPressed() {
-    if (mReactInstanceManager != null) {
-      mReactInstanceManager.onBackPressed();
-    } else {
-      super.onBackPressed();
-    }
+  protected boolean getUseDeveloperSupport() {
+      return true;
   }
 
   @Override
-  public void invokeDefaultOnBackPressed() {
-    super.onBackPressed();
+  protected List<ReactPackage> getPackages() {
+    return Arrays.<ReactPackage>asList(
+      new MainReactPackage()
+    );
   }
 }

From b9ed72a043a67401a43b91f1d55c72d5f7e82bc1 Mon Sep 17 00:00:00 2001
From: djhi <gildas.garcia@gmail.com>
Date: Sun, 21 Feb 2016 16:52:58 -0800
Subject: [PATCH 1248/1411] Added a `root` option to the `run-android` command

Summary:Added a `root` option to the `run-android` command allowing to run it from a parent directory.

Use case: project is organized like this
```
- api
- apps
---- web
---- react-native
- package.json
```
You can use the root option on `react-native start` but not on `run-android`. This pr fixes that.
Closes https://github.com/facebook/react-native/pull/5597

Differential Revision: D2959523

Pulled By: mkonicek

fb-gh-sync-id: 03fb74b201fe9e89bf6fab80c9a98ca708464261
shipit-source-id: 03fb74b201fe9e89bf6fab80c9a98ca708464261
---
 local-cli/runAndroid/runAndroid.js | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/local-cli/runAndroid/runAndroid.js b/local-cli/runAndroid/runAndroid.js
index fa2836998c15..8cd14884a83c 100644
--- a/local-cli/runAndroid/runAndroid.js
+++ b/local-cli/runAndroid/runAndroid.js
@@ -30,9 +30,15 @@ function _runAndroid(argv, config, resolve, reject) {
     command: 'install-debug',
     type: 'string',
     required: false,
+  }, {
+    command: 'root',
+    type: 'string',
+    description: 'Override the root directory for the android build (which contains the android directory)',
   }], argv);
 
-  if (!checkAndroid()) {
+  args.root = args.root || '';
+
+  if (!checkAndroid(args)) {
     console.log(chalk.red('Android project not found. Maybe run react-native android first?'));
     return;
   }
@@ -52,13 +58,13 @@ function _runAndroid(argv, config, resolve, reject) {
 }
 
 // Verifies this is an Android project
-function checkAndroid() {
-  return fs.existsSync('android/gradlew');
+function checkAndroid(args) {
+  return fs.existsSync(path.join(args.root, 'android/gradlew'));
 }
 
 // Builds the app and runs it on a connected emulator / device.
 function buildAndRun(args, reject) {
-  process.chdir('android');
+  process.chdir(path.join(args.root, 'android'));
   try {
     const cmd = process.platform.startsWith('win')
       ? 'gradlew.bat'

From cf3bd9f9a17570e6b8db3cf9af3156b67243f696 Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Mon, 22 Feb 2016 01:49:46 -0800
Subject: [PATCH 1249/1411] Fix hidden StatusBar reappearing after exiting app
 on Android

Summary:I changed the technique used to hide the status bar and now it works properly. Also changed the way flags are set on the decorView to make sure it doesn't cause issues with other flags already set and fix deprecated Promise.reject

**Test plan**
Test using the UIExplorer StatusBar example, change the `hidden` prop value and go in and out of the app making sure the status bar has the right visibility.

Fixes #5991
Closes https://github.com/facebook/react-native/pull/6051

Differential Revision: D2960060

Pulled By: nicklockwood

fb-gh-sync-id: ee1c541896f5771d27cfd3ff18537edb6c017284
shipit-source-id: ee1c541896f5771d27cfd3ff18537edb6c017284
---
 .../modules/statusbar/StatusBarModule.java    | 29 ++++++++++---------
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.java
index ed905797a539..29d08a833f65 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.java
@@ -17,6 +17,7 @@
 import android.os.Build;
 import android.support.v4.view.ViewCompat;
 import android.view.View;
+import android.view.WindowManager;
 
 import com.facebook.react.bridge.Promise;
 import com.facebook.react.bridge.ReactApplicationContext;
@@ -26,11 +27,10 @@
 
 public class StatusBarModule extends ReactContextBaseJavaModule {
 
-  private static final String ERROR_NO_ACTIVITY =
+  private static final String ERROR_NO_ACTIVITY = "E_NO_ACTIVITY";
+  private static final String ERROR_NO_ACTIVITY_MESSAGE =
     "Tried to change the status bar while not attached to an Activity";
 
-  private int mWindowFlags = 0;
-
   public StatusBarModule(ReactApplicationContext reactContext) {
     super(reactContext);
   }
@@ -44,7 +44,7 @@ public String getName() {
   public void setColor(final int color, final boolean animated, final Promise res) {
     final Activity activity = getCurrentActivity();
     if (activity == null) {
-      res.reject(ERROR_NO_ACTIVITY);
+      res.reject(ERROR_NO_ACTIVITY, ERROR_NO_ACTIVITY_MESSAGE);
       return;
     }
 
@@ -85,21 +85,20 @@ public void onAnimationUpdate(ValueAnimator animator) {
   public void setTranslucent(final boolean translucent, final Promise res) {
     final Activity activity = getCurrentActivity();
     if (activity == null) {
-      res.reject(ERROR_NO_ACTIVITY);
+      res.reject(ERROR_NO_ACTIVITY, ERROR_NO_ACTIVITY_MESSAGE);
       return;
     }
     UiThreadUtil.runOnUiThread(
       new Runnable() {
         @Override
         public void run() {
+          int flags = activity.getWindow().getDecorView().getSystemUiVisibility();
           if (translucent) {
-            mWindowFlags |=
-              View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+            flags |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
           } else {
-            mWindowFlags &=
-              ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
+            flags &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
           }
-          activity.getWindow().getDecorView().setSystemUiVisibility(mWindowFlags);
+          activity.getWindow().getDecorView().setSystemUiVisibility(flags);
           ViewCompat.requestApplyInsets(activity.getWindow().getDecorView());
           res.resolve(null);
         }
@@ -111,7 +110,7 @@ public void run() {
   public void setHidden(final boolean hidden, final Promise res) {
     final Activity activity = getCurrentActivity();
     if (activity == null) {
-      res.reject(ERROR_NO_ACTIVITY);
+      res.reject(ERROR_NO_ACTIVITY, ERROR_NO_ACTIVITY_MESSAGE);
       return;
     }
     UiThreadUtil.runOnUiThread(
@@ -119,11 +118,13 @@ public void setHidden(final boolean hidden, final Promise res) {
         @Override
         public void run() {
           if (hidden) {
-            mWindowFlags |= View.SYSTEM_UI_FLAG_FULLSCREEN;
+            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+            activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
           } else {
-            mWindowFlags &= ~View.SYSTEM_UI_FLAG_FULLSCREEN;
+            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+            activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
           }
-          activity.getWindow().getDecorView().setSystemUiVisibility(mWindowFlags);
+
           res.resolve(null);
         }
       }

From b5d26679c4bcc6126d04a98022d86821b5e5de51 Mon Sep 17 00:00:00 2001
From: Andrei Coman <andreic@fb.com>
Date: Mon, 22 Feb 2016 03:25:58 -0800
Subject: [PATCH 1250/1411] Use nanoTime instead of currentTimeMillis for
 events

Reviewed By: foghina

Differential Revision: D2953917

fb-gh-sync-id: effd09849a5504c9eb7c684a510e616fdcfcdf6e
shipit-source-id: effd09849a5504c9eb7c684a510e616fdcfcdf6e
---
 .../com/facebook/react/ReactRootView.java     | 14 +++++------
 .../react/uimanager/OnLayoutEvent.java        |  4 ++--
 .../uimanager/events/EventDispatcher.java     |  9 +-------
 .../drawer/ReactDrawerLayoutManager.java      | 12 +++++-----
 .../react/views/image/ReactImageView.java     | 10 ++++----
 .../views/picker/ReactPickerManager.java      |  6 ++---
 .../RecyclerViewBackedScrollView.java         |  6 ++---
 .../views/scroll/ReactScrollViewHelper.java   |  4 ++--
 .../SwipeRefreshLayoutManager.java            |  6 ++---
 .../com/facebook/react/views/switchview/BUCK  |  1 +
 .../views/switchview/ReactSwitchManager.java  |  8 +++----
 .../textinput/ReactTextInputManager.java      | 16 ++++++-------
 .../views/toolbar/ReactToolbarManager.java    |  8 +++----
 .../react/views/viewpager/ReactViewPager.java |  8 +++----
 .../views/webview/ReactWebViewManager.java    | 23 +++++++++----------
 15 files changed, 64 insertions(+), 71 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
index 300be54bcfcf..bf4b8b4bc843 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
@@ -14,7 +14,6 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.os.Bundle;
-import android.os.SystemClock;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
@@ -28,6 +27,7 @@
 import com.facebook.react.bridge.UiThreadUtil;
 import com.facebook.react.bridge.WritableMap;
 import com.facebook.react.common.ReactConstants;
+import com.facebook.react.common.SystemClock;
 import com.facebook.react.common.annotations.VisibleForTesting;
 import com.facebook.react.modules.core.DeviceEventManagerModule;
 import com.facebook.react.uimanager.DisplayMetricsHolder;
@@ -151,7 +151,7 @@ private void handleTouchEvent(MotionEvent ev) {
       eventDispatcher.dispatchEvent(
           TouchEvent.obtain(
               mTargetTag,
-              SystemClock.uptimeMillis(),
+              SystemClock.nanoTime(),
               TouchEventType.START,
               ev,
               mTargetCoordinates[0],
@@ -173,7 +173,7 @@ private void handleTouchEvent(MotionEvent ev) {
       eventDispatcher.dispatchEvent(
           TouchEvent.obtain(
               mTargetTag,
-              SystemClock.uptimeMillis(),
+              SystemClock.nanoTime(),
               TouchEventType.END,
               ev,
               mTargetCoordinates[0],
@@ -184,7 +184,7 @@ private void handleTouchEvent(MotionEvent ev) {
       eventDispatcher.dispatchEvent(
           TouchEvent.obtain(
               mTargetTag,
-              SystemClock.uptimeMillis(),
+              SystemClock.nanoTime(),
               TouchEventType.MOVE,
               ev,
               mTargetCoordinates[0],
@@ -194,7 +194,7 @@ private void handleTouchEvent(MotionEvent ev) {
       eventDispatcher.dispatchEvent(
           TouchEvent.obtain(
               mTargetTag,
-              SystemClock.uptimeMillis(),
+              SystemClock.nanoTime(),
               TouchEventType.START,
               ev,
               mTargetCoordinates[0],
@@ -204,7 +204,7 @@ private void handleTouchEvent(MotionEvent ev) {
       eventDispatcher.dispatchEvent(
           TouchEvent.obtain(
               mTargetTag,
-              SystemClock.uptimeMillis(),
+              SystemClock.nanoTime(),
               TouchEventType.END,
               ev,
               mTargetCoordinates[0],
@@ -255,7 +255,7 @@ private void dispatchCancelEvent(MotionEvent androidEvent) {
     Assertions.assertNotNull(eventDispatcher).dispatchEvent(
         TouchEvent.obtain(
             mTargetTag,
-            SystemClock.uptimeMillis(),
+            SystemClock.nanoTime(),
             TouchEventType.CANCEL,
             androidEvent,
             mTargetCoordinates[0],
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/OnLayoutEvent.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/OnLayoutEvent.java
index 155776b71573..c2b5c8a6e9d8 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/OnLayoutEvent.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/OnLayoutEvent.java
@@ -9,11 +9,11 @@
 
 package com.facebook.react.uimanager;
 
-import android.os.SystemClock;
 import android.support.v4.util.Pools;
 
 import com.facebook.react.bridge.Arguments;
 import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.common.SystemClock;
 import com.facebook.react.uimanager.events.Event;
 import com.facebook.react.uimanager.events.RCTEventEmitter;
 
@@ -45,7 +45,7 @@ private OnLayoutEvent() {
   }
 
   protected void init(int viewTag, int x, int y, int width, int height) {
-    super.init(viewTag, SystemClock.uptimeMillis());
+    super.init(viewTag, SystemClock.nanoTime());
     mX = x;
     mY = y;
     mWidth = width;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java
index c8635d051588..d55401af6d29 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java
@@ -75,14 +75,7 @@ public int compare(Event lhs, Event rhs) {
         return 1;
       }
 
-      long diff = lhs.getTimestampMs() - rhs.getTimestampMs();
-      if (diff == 0) {
-        return 0;
-      } else if (diff < 0) {
-        return -1;
-      } else {
-        return 1;
-      }
+      return lhs.getTimestampMs() < rhs.getTimestampMs() ? -1 : 1;
     }
   };
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/drawer/ReactDrawerLayoutManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/drawer/ReactDrawerLayoutManager.java
index 37062918158e..d1ec7f83128d 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/drawer/ReactDrawerLayoutManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/drawer/ReactDrawerLayoutManager.java
@@ -13,7 +13,6 @@
 
 import java.util.Map;
 
-import android.os.SystemClock;
 import android.support.v4.widget.DrawerLayout;
 import android.view.Gravity;
 import android.view.View;
@@ -21,11 +20,12 @@
 import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.common.MapBuilder;
+import com.facebook.react.common.SystemClock;
 import com.facebook.react.uimanager.PixelUtil;
-import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.ViewGroupManager;
+import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.events.EventDispatcher;
 import com.facebook.react.views.drawer.events.DrawerClosedEvent;
 import com.facebook.react.views.drawer.events.DrawerOpenedEvent;
@@ -151,25 +151,25 @@ public DrawerEventEmitter(DrawerLayout drawerLayout, EventDispatcher eventDispat
     @Override
     public void onDrawerSlide(View view, float v) {
       mEventDispatcher.dispatchEvent(
-          new DrawerSlideEvent(mDrawerLayout.getId(), SystemClock.uptimeMillis(), v));
+          new DrawerSlideEvent(mDrawerLayout.getId(), SystemClock.nanoTime(), v));
     }
 
     @Override
     public void onDrawerOpened(View view) {
       mEventDispatcher.dispatchEvent(
-        new DrawerOpenedEvent(mDrawerLayout.getId(), SystemClock.uptimeMillis()));
+        new DrawerOpenedEvent(mDrawerLayout.getId(), SystemClock.nanoTime()));
     }
 
     @Override
     public void onDrawerClosed(View view) {
       mEventDispatcher.dispatchEvent(
-          new DrawerClosedEvent(mDrawerLayout.getId(), SystemClock.uptimeMillis()));
+          new DrawerClosedEvent(mDrawerLayout.getId(), SystemClock.nanoTime()));
     }
 
     @Override
     public void onDrawerStateChanged(int i) {
       mEventDispatcher.dispatchEvent(
-          new DrawerStateChangedEvent(mDrawerLayout.getId(), SystemClock.uptimeMillis(), i));
+          new DrawerStateChangedEvent(mDrawerLayout.getId(), SystemClock.nanoTime(), i));
     }
   }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
index 1c020acdcc8a..c45c0403b237 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java
@@ -24,7 +24,6 @@
 import android.graphics.drawable.Animatable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
-import android.os.SystemClock;
 
 import com.facebook.common.util.UriUtil;
 import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
@@ -44,6 +43,7 @@
 import com.facebook.imagepipeline.request.ImageRequestBuilder;
 import com.facebook.imagepipeline.request.Postprocessor;
 import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.common.SystemClock;
 import com.facebook.react.uimanager.PixelUtil;
 import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.events.EventDispatcher;
@@ -151,7 +151,7 @@ public void setShouldNotifyLoadEvents(boolean shouldNotify) {
         @Override
         public void onSubmit(String id, Object callerContext) {
           mEventDispatcher.dispatchEvent(
-              new ImageLoadEvent(getId(), SystemClock.uptimeMillis(), ImageLoadEvent.ON_LOAD_START)
+              new ImageLoadEvent(getId(), SystemClock.nanoTime(), ImageLoadEvent.ON_LOAD_START)
           );
         }
 
@@ -162,10 +162,10 @@ public void onFinalImageSet(
             @Nullable Animatable animatable) {
           if (imageInfo != null) {
             mEventDispatcher.dispatchEvent(
-                new ImageLoadEvent(getId(), SystemClock.uptimeMillis(), ImageLoadEvent.ON_LOAD_END)
+                new ImageLoadEvent(getId(), SystemClock.nanoTime(), ImageLoadEvent.ON_LOAD_END)
             );
             mEventDispatcher.dispatchEvent(
-                new ImageLoadEvent(getId(), SystemClock.uptimeMillis(), ImageLoadEvent.ON_LOAD)
+                new ImageLoadEvent(getId(), SystemClock.nanoTime(), ImageLoadEvent.ON_LOAD)
             );
           }
         }
@@ -173,7 +173,7 @@ public void onFinalImageSet(
         @Override
         public void onFailure(String id, Throwable throwable) {
           mEventDispatcher.dispatchEvent(
-              new ImageLoadEvent(getId(), SystemClock.uptimeMillis(), ImageLoadEvent.ON_LOAD_END)
+              new ImageLoadEvent(getId(), SystemClock.nanoTime(), ImageLoadEvent.ON_LOAD_END)
           );
         }
       };
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactPickerManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactPickerManager.java
index 2c8c24038907..11ea4c839fc9 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactPickerManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactPickerManager.java
@@ -12,7 +12,6 @@
 import javax.annotation.Nullable;
 
 import android.content.Context;
-import android.os.SystemClock;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -23,11 +22,12 @@
 import com.facebook.infer.annotation.Assertions;
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.bridge.ReadableMap;
-import com.facebook.react.uimanager.annotations.ReactProp;
+import com.facebook.react.common.SystemClock;
 import com.facebook.react.uimanager.SimpleViewManager;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.ViewProps;
+import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.events.EventDispatcher;
 import com.facebook.react.views.picker.events.PickerItemSelectEvent;
 
@@ -157,7 +157,7 @@ public PickerEventEmitter(ReactPicker reactPicker, EventDispatcher eventDispatch
     @Override
     public void onItemSelected(int position) {
       mEventDispatcher.dispatchEvent( new PickerItemSelectEvent(
-              mReactPicker.getId(), SystemClock.uptimeMillis(), position));
+              mReactPicker.getId(), SystemClock.nanoTime(), position));
     }
   }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollView.java
index f1729c55ca32..337fd5cfb393 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollView.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollView.java
@@ -6,7 +6,6 @@
 import java.util.List;
 
 import android.content.Context;
-import android.os.SystemClock;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.view.MotionEvent;
@@ -15,6 +14,7 @@
 
 import com.facebook.infer.annotation.Assertions;
 import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.common.SystemClock;
 import com.facebook.react.common.annotations.VisibleForTesting;
 import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.events.NativeGestureUtil;
@@ -344,7 +344,7 @@ protected void onScrollChanged(int l, int t, int oldl, int oldt) {
     ((ReactContext) getContext()).getNativeModule(UIManagerModule.class).getEventDispatcher()
         .dispatchEvent(ScrollEvent.obtain(
                 getId(),
-                SystemClock.uptimeMillis(),
+                SystemClock.nanoTime(),
                 ScrollEventType.SCROLL,
                 0, /* offsetX = 0, horizontal scrolling only */
                 calculateAbsoluteOffset(),
@@ -359,7 +359,7 @@ private void onTotalChildrenHeightChange(int newTotalChildrenHeight) {
       ((ReactContext) getContext()).getNativeModule(UIManagerModule.class).getEventDispatcher()
           .dispatchEvent(new ContentSizeChangeEvent(
                   getId(),
-                  SystemClock.uptimeMillis(),
+                  SystemClock.nanoTime(),
                   getWidth(),
                   newTotalChildrenHeight));
     }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java
index 3ee46350dbe1..fd46f677b795 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.java
@@ -9,11 +9,11 @@
 
 package com.facebook.react.views.scroll;
 
-import android.os.SystemClock;
 import android.view.View;
 import android.view.ViewGroup;
 
 import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.common.SystemClock;
 import com.facebook.react.uimanager.UIManagerModule;
 
 /**
@@ -57,7 +57,7 @@ private static void emitScrollEvent(ViewGroup scrollView, ScrollEventType scroll
     reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(
         ScrollEvent.obtain(
             scrollView.getId(),
-            SystemClock.uptimeMillis(),
+            SystemClock.nanoTime(),
             scrollEventType,
             scrollView.getScrollX(),
             scrollView.getScrollY(),
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/SwipeRefreshLayoutManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/SwipeRefreshLayoutManager.java
index 07a42e049455..009f5a126509 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/SwipeRefreshLayoutManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/SwipeRefreshLayoutManager.java
@@ -14,17 +14,17 @@
 import java.util.Map;
 
 import android.graphics.Color;
-import android.os.SystemClock;
 import android.support.v4.widget.SwipeRefreshLayout;
 import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener;
 
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.common.MapBuilder;
-import com.facebook.react.uimanager.annotations.ReactProp;
+import com.facebook.react.common.SystemClock;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.ViewGroupManager;
 import com.facebook.react.uimanager.ViewProps;
+import com.facebook.react.uimanager.annotations.ReactProp;
 
 /**
  * ViewManager for {@link ReactSwipeRefreshLayout} which allows the user to "pull to refresh" a
@@ -91,7 +91,7 @@ protected void addEventEmitters(
           @Override
           public void onRefresh() {
             reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher()
-                .dispatchEvent(new RefreshEvent(view.getId(), SystemClock.uptimeMillis()));
+                .dispatchEvent(new RefreshEvent(view.getId(), SystemClock.nanoTime()));
           }
         });
   }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK
index 6972d308b2e9..770afb9c9965 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK
@@ -5,6 +5,7 @@ android_library(
   srcs = glob(['*.java']),
   deps = [
     react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
     react_native_target('java/com/facebook/csslayout:csslayout'),
     react_native_target('java/com/facebook/react/uimanager:uimanager'),
     react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java
index 14d9fc0d6766..f99b3c7a7a4c 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitchManager.java
@@ -10,7 +10,6 @@
 // switchview because switch is a keyword
 package com.facebook.react.views.switchview;
 
-import android.os.SystemClock;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.CompoundButton;
@@ -18,12 +17,13 @@
 import com.facebook.csslayout.CSSNode;
 import com.facebook.csslayout.MeasureOutput;
 import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.common.SystemClock;
 import com.facebook.react.uimanager.LayoutShadowNode;
-import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.SimpleViewManager;
-import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.ThemedReactContext;
+import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.ViewProps;
+import com.facebook.react.uimanager.annotations.ReactProp;
 
 /**
  * View manager for {@link ReactSwitch} components.
@@ -71,7 +71,7 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
           reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(
               new ReactSwitchEvent(
                   buttonView.getId(),
-                  SystemClock.uptimeMillis(),
+                  SystemClock.nanoTime(),
                   isChecked));
         }
       };
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
index f4b9e34dcc8c..d6ce4f0def66 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
@@ -15,7 +15,6 @@
 import java.util.Map;
 
 import android.graphics.PorterDuff;
-import android.os.SystemClock;
 import android.text.Editable;
 import android.text.InputFilter;
 import android.text.InputType;
@@ -33,6 +32,7 @@
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.common.MapBuilder;
+import com.facebook.react.common.SystemClock;
 import com.facebook.react.uimanager.BaseViewManager;
 import com.facebook.react.uimanager.LayoutShadowNode;
 import com.facebook.react.uimanager.PixelUtil;
@@ -427,7 +427,7 @@ public void onTextChanged(CharSequence s, int start, int before, int count) {
       mEventDispatcher.dispatchEvent(
           new ReactTextChangedEvent(
               mEditText.getId(),
-              SystemClock.uptimeMillis(),
+              SystemClock.nanoTime(),
               s.toString(),
               (int) PixelUtil.toDIPFromPixel(contentWidth),
               (int) PixelUtil.toDIPFromPixel(contentHeight),
@@ -436,7 +436,7 @@ public void onTextChanged(CharSequence s, int start, int before, int count) {
       mEventDispatcher.dispatchEvent(
           new ReactTextInputEvent(
               mEditText.getId(),
-              SystemClock.uptimeMillis(),
+              SystemClock.nanoTime(),
               newText,
               oldText,
               start,
@@ -462,17 +462,17 @@ public void onFocusChange(View v, boolean hasFocus) {
               eventDispatcher.dispatchEvent(
                   new ReactTextInputFocusEvent(
                       editText.getId(),
-                      SystemClock.uptimeMillis()));
+                      SystemClock.nanoTime()));
             } else {
               eventDispatcher.dispatchEvent(
                   new ReactTextInputBlurEvent(
                       editText.getId(),
-                      SystemClock.uptimeMillis()));
+                      SystemClock.nanoTime()));
 
               eventDispatcher.dispatchEvent(
                   new ReactTextInputEndEditingEvent(
                       editText.getId(),
-                      SystemClock.uptimeMillis(),
+                      SystemClock.nanoTime(),
                       editText.getText().toString()));
             }
           }
@@ -490,7 +490,7 @@ public boolean onEditorAction(TextView v, int actionId, KeyEvent keyEvent) {
               eventDispatcher.dispatchEvent(
                   new ReactTextInputSubmitEditingEvent(
                       editText.getId(),
-                      SystemClock.uptimeMillis(),
+                      SystemClock.nanoTime(),
                       editText.getText().toString()));
             }
             return false;
@@ -520,7 +520,7 @@ public void onSelectionChanged(int start, int end) {
         mEventDispatcher.dispatchEvent(
             new ReactTextInputSelectionEvent(
                 mReactEditText.getId(),
-                SystemClock.uptimeMillis(),
+                SystemClock.nanoTime(),
                 start,
                 end
             )
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java
index 321d872c82eb..9f162f9f0b41 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java
@@ -17,7 +17,6 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Color;
-import android.os.SystemClock;
 import android.util.LayoutDirection;
 import android.view.MenuItem;
 import android.view.View;
@@ -26,11 +25,12 @@
 import com.facebook.react.bridge.ReadableArray;
 import com.facebook.react.bridge.ReadableMap;
 import com.facebook.react.common.MapBuilder;
+import com.facebook.react.common.SystemClock;
 import com.facebook.react.uimanager.PixelUtil;
-import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.ViewGroupManager;
+import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.events.EventDispatcher;
 import com.facebook.react.views.toolbar.events.ToolbarClickEvent;
 
@@ -131,7 +131,7 @@ protected void addEventEmitters(final ThemedReactContext reactContext, final Rea
           @Override
           public void onClick(View v) {
             mEventDispatcher.dispatchEvent(
-                new ToolbarClickEvent(view.getId(), SystemClock.uptimeMillis(), -1));
+                new ToolbarClickEvent(view.getId(), SystemClock.nanoTime(), -1));
           }
         });
 
@@ -142,7 +142,7 @@ public boolean onMenuItemClick(MenuItem menuItem) {
             mEventDispatcher.dispatchEvent(
                 new ToolbarClickEvent(
                     view.getId(),
-                    SystemClock.uptimeMillis(),
+                    SystemClock.nanoTime(),
                     menuItem.getOrder()));
             return true;
           }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/ReactViewPager.java b/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/ReactViewPager.java
index 3ad5c55e0cd5..c522e0391560 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/ReactViewPager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/ReactViewPager.java
@@ -12,7 +12,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import android.os.SystemClock;
 import android.support.v4.view.PagerAdapter;
 import android.support.v4.view.ViewPager;
 import android.view.MotionEvent;
@@ -20,6 +19,7 @@
 import android.view.ViewGroup;
 
 import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.common.SystemClock;
 import com.facebook.react.uimanager.UIManagerModule;
 import com.facebook.react.uimanager.events.EventDispatcher;
 import com.facebook.react.uimanager.events.NativeGestureUtil;
@@ -91,14 +91,14 @@ private class PageChangeListener implements OnPageChangeListener {
     @Override
     public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
       mEventDispatcher.dispatchEvent(
-          new PageScrollEvent(getId(), SystemClock.uptimeMillis(), position, positionOffset));
+          new PageScrollEvent(getId(), SystemClock.nanoTime(), position, positionOffset));
     }
 
     @Override
     public void onPageSelected(int position) {
       if (!mIsCurrentItemFromJs) {
         mEventDispatcher.dispatchEvent(
-            new PageSelectedEvent(getId(), SystemClock.uptimeMillis(), position));
+            new PageSelectedEvent(getId(), SystemClock.nanoTime(), position));
       }
     }
 
@@ -119,7 +119,7 @@ public void onPageScrollStateChanged(int state) {
           throw new IllegalStateException("Unsupported pageScrollState");
       }
       mEventDispatcher.dispatchEvent(
-        new PageScrollStateChangedEvent(getId(), SystemClock.uptimeMillis(), pageScrollState));
+        new PageScrollStateChangedEvent(getId(), SystemClock.nanoTime(), pageScrollState));
     }
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
index 4db9141b6a3e..616418bba35b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/webview/ReactWebViewManager.java
@@ -9,9 +9,14 @@
 
 package com.facebook.react.views.webview;
 
+import javax.annotation.Nullable;
+
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.Map;
+
 import android.graphics.Bitmap;
 import android.os.Build;
-import android.os.SystemClock;
 import android.text.TextUtils;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
@@ -27,6 +32,7 @@
 import com.facebook.react.bridge.ReadableMapKeySetIterator;
 import com.facebook.react.bridge.WritableMap;
 import com.facebook.react.common.MapBuilder;
+import com.facebook.react.common.SystemClock;
 import com.facebook.react.common.build.ReactBuildConfig;
 import com.facebook.react.uimanager.SimpleViewManager;
 import com.facebook.react.uimanager.ThemedReactContext;
@@ -35,13 +41,6 @@
 import com.facebook.react.uimanager.events.Event;
 import com.facebook.react.uimanager.events.EventDispatcher;
 
-import java.io.UnsupportedEncodingException;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.annotation.Nullable;
-
 /**
  * Manages instances of {@link WebView}
  *
@@ -106,7 +105,7 @@ public void onPageStarted(WebView webView, String url, Bitmap favicon) {
           webView,
           new TopLoadingStartEvent(
               webView.getId(),
-              SystemClock.uptimeMillis(),
+              SystemClock.nanoTime(),
               createWebViewEvent(webView, url)));
     }
 
@@ -129,7 +128,7 @@ public void onReceivedError(
 
       dispatchEvent(
           webView,
-          new TopLoadingErrorEvent(webView.getId(), SystemClock.uptimeMillis(), eventData));
+          new TopLoadingErrorEvent(webView.getId(), SystemClock.nanoTime(), eventData));
     }
 
     @Override
@@ -140,7 +139,7 @@ public void doUpdateVisitedHistory(WebView webView, String url, boolean isReload
           webView,
           new TopLoadingStartEvent(
               webView.getId(),
-              SystemClock.uptimeMillis(),
+              SystemClock.nanoTime(),
               createWebViewEvent(webView, url)));
     }
 
@@ -149,7 +148,7 @@ private void emitFinishEvent(WebView webView, String url) {
           webView,
           new TopLoadingFinishEvent(
               webView.getId(),
-              SystemClock.uptimeMillis(),
+              SystemClock.nanoTime(),
               createWebViewEvent(webView, url)));
     }
 

From 26a7335d4d913f9f0d0fd255a9fb6e1bbf7a8aec Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Mon, 22 Feb 2016 03:58:08 -0800
Subject: [PATCH 1251/1411] Backed out changeset 837af947846b

Reviewed By: astreet

Differential Revision: D2960159

fb-gh-sync-id: ec8df9c2f7213879470482b77346b3872c26413d
shipit-source-id: ec8df9c2f7213879470482b77346b3872c26413d
---
 .../jni/first-party/fbgloginit/Android.mk     |  24 ---
 .../src/main/jni/first-party/fbgloginit/BUCK  |  21 ---
 .../jni/first-party/fbgloginit/fb/glog_init.h |  11 --
 .../jni/first-party/fbgloginit/glog_init.cpp  | 142 ------------------
 .../src/main/jni/react/jni/Android.mk         |   3 +-
 ReactAndroid/src/main/jni/react/jni/BUCK      |   1 -
 .../src/main/jni/react/jni/OnLoad.cpp         |   2 -
 7 files changed, 1 insertion(+), 203 deletions(-)
 delete mode 100644 ReactAndroid/src/main/jni/first-party/fbgloginit/Android.mk
 delete mode 100644 ReactAndroid/src/main/jni/first-party/fbgloginit/BUCK
 delete mode 100644 ReactAndroid/src/main/jni/first-party/fbgloginit/fb/glog_init.h
 delete mode 100644 ReactAndroid/src/main/jni/first-party/fbgloginit/glog_init.cpp

diff --git a/ReactAndroid/src/main/jni/first-party/fbgloginit/Android.mk b/ReactAndroid/src/main/jni/first-party/fbgloginit/Android.mk
deleted file mode 100644
index e768bb21577a..000000000000
--- a/ReactAndroid/src/main/jni/first-party/fbgloginit/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-       glog_init.cpp
-
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/
-LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/..
-
-LOCAL_CFLAGS := -fexceptions -fno-omit-frame-pointer
-LOCAL_CFLAGS += -Wall -Werror
-
-CXX11_FLAGS := -std=gnu++11
-LOCAL_CFLAGS += $(CXX11_FLAGS)
-
-LOCAL_EXPORT_CPPFLAGS := $(CXX11_FLAGS)
-
-LOCAL_LDLIBS := -llog
-
-LOCAL_SHARED_LIBRARIES := libglog
-
-LOCAL_MODULE := libglog_init
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/ReactAndroid/src/main/jni/first-party/fbgloginit/BUCK b/ReactAndroid/src/main/jni/first-party/fbgloginit/BUCK
deleted file mode 100644
index c058851bdc80..000000000000
--- a/ReactAndroid/src/main/jni/first-party/fbgloginit/BUCK
+++ /dev/null
@@ -1,21 +0,0 @@
-cxx_library(
-  name = 'fbgloginit',
-  force_static = True,
-  srcs = [
-    'glog_init.cpp',
-  ],
-  exported_headers = ['fb/glog_init.h'],
-  header_namespace = 'fbgloginit',
-  compiler_flags = [
-    '-fexceptions',
-    '-fno-omit-frame-pointer',
-  ],
-  linker_flags = [
-    '-llog',
-  ],
-  deps=[
-    '//xplat/third-party/glog:glog',
-  ],
-  visibility=['PUBLIC'],
-)
-
diff --git a/ReactAndroid/src/main/jni/first-party/fbgloginit/fb/glog_init.h b/ReactAndroid/src/main/jni/first-party/fbgloginit/fb/glog_init.h
deleted file mode 100644
index a377986223dd..000000000000
--- a/ReactAndroid/src/main/jni/first-party/fbgloginit/fb/glog_init.h
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-#pragma once
-
-#include <string>
-
-namespace facebook { namespace gloginit {
-
-void initialize(const char* tag = "fb");
-
-}}
diff --git a/ReactAndroid/src/main/jni/first-party/fbgloginit/glog_init.cpp b/ReactAndroid/src/main/jni/first-party/fbgloginit/glog_init.cpp
deleted file mode 100644
index 771516a2dcdf..000000000000
--- a/ReactAndroid/src/main/jni/first-party/fbgloginit/glog_init.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-#include "fb/glog_init.h"
-
-#include <iostream>
-#include <mutex>
-#include <stdexcept>
-
-#include <glog/logging.h>
-
-#ifdef __ANDROID__
-
-#include <android/log.h>
-
-static int toAndroidLevel(google::LogSeverity severity) {
-  switch (severity) {
-  case google::GLOG_INFO:
-    return ANDROID_LOG_INFO;
-  case google::GLOG_WARNING:
-    return ANDROID_LOG_WARN;
-  case google::GLOG_ERROR:
-    return ANDROID_LOG_ERROR;
-  case google::GLOG_FATAL:
-    return ANDROID_LOG_FATAL;
-  default:
-    return ANDROID_LOG_FATAL;
-  }
-}
-
-/**
- * Sends GLog output to adb logcat.
- */
-class LogcatSink : public google::LogSink {
- public:
-  void send(
-      google::LogSeverity severity,
-      const char* full_filename,
-      const char* base_filename,
-      int line,
-      const struct ::tm* tm_time,
-      const char* message,
-      size_t message_len) override {
-    auto level = toAndroidLevel(severity);
-    __android_log_print(
-        level,
-        base_filename,
-        "%.*s",
-        (int)message_len,
-        message);
-  }
-};
-
-/**
- * Sends GLog output to adb logcat.
- */
-class TaggedLogcatSink : public google::LogSink {
-  const std::string tag_;
-
- public:
-  TaggedLogcatSink(const std::string &tag) : tag_{tag} {}
-
-  void send(
-      google::LogSeverity severity,
-      const char* full_filename,
-      const char* base_filename,
-      int line,
-      const struct ::tm* tm_time,
-      const char* message,
-      size_t message_len) override {
-    auto level = toAndroidLevel(severity);
-    __android_log_print(
-      level,
-      tag_.c_str(),
-      "%.*s",
-      (int)message_len,
-      message);
-  }
-};
-
-static google::LogSink* make_sink(const std::string& tag) {
-  if (tag.empty()) {
-    return new LogcatSink{};
-  } else {
-    return new TaggedLogcatSink{tag};
-  }
-}
-
-static void sendGlogOutputToLogcat(const char* tag) {
-  google::AddLogSink(make_sink(tag));
-
-  // Disable logging to files
-  for (auto i = 0; i < google::NUM_SEVERITIES; ++i) {
-    google::SetLogDestination(i, "");
-  }
-}
-
-#endif // __ANDROID__
-
-static void lastResort(const char* tag, const char* msg, const char* arg = nullptr) {
-#ifdef __ANDROID__
-  if (!arg) {
-    __android_log_write(ANDROID_LOG_ERROR, tag, msg);
-  } else {
-    __android_log_print(ANDROID_LOG_ERROR, tag, "%s: %s", msg, arg);
-  }
-#else 
-  std::cerr << msg;
-  if (arg) {
-    std::cerr << ": " << arg;
-  }
-  std::cerr << std::endl;
-#endif
-}
-
-namespace facebook { namespace gloginit {
-
-void initialize(const char* tag) {
-  static std::once_flag flag{};
-  static auto failed = false;
-
-  std::call_once(flag, [tag] {
-    try {
-      google::InitGoogleLogging(tag);
-
-#ifdef __ANDROID__
-      sendGlogOutputToLogcat(tag);
-#endif
-    } catch (std::exception& ex) {
-      lastResort(tag, "Failed to initialize glog", ex.what());
-      failed = true;
-    } catch (...) {
-      lastResort(tag, "Failed to initialize glog");
-      failed = true;
-    }
-  });
-
-  if (failed) {
-    throw std::runtime_error{"Failed to initialize glog"};
-  }
-}
-
-}}
diff --git a/ReactAndroid/src/main/jni/react/jni/Android.mk b/ReactAndroid/src/main/jni/react/jni/Android.mk
index e5184d8e81fa..9d4d9b2b5fff 100644
--- a/ReactAndroid/src/main/jni/react/jni/Android.mk
+++ b/ReactAndroid/src/main/jni/react/jni/Android.mk
@@ -22,7 +22,7 @@ LOCAL_CFLAGS += $(CXX11_FLAGS)
 LOCAL_EXPORT_CPPFLAGS := $(CXX11_FLAGS)
 
 LOCAL_LDLIBS += -landroid
-LOCAL_SHARED_LIBRARIES := libfolly_json libfbjni libjsc libglog_init
+LOCAL_SHARED_LIBRARIES := libfolly_json libfbjni libjsc
 LOCAL_STATIC_LIBRARIES := libreactnative
 
 include $(BUILD_SHARED_LIBRARY)
@@ -30,6 +30,5 @@ include $(BUILD_SHARED_LIBRARY)
 $(call import-module,react)
 $(call import-module,jsc)
 $(call import-module,folly)
-$(call import-module,fbgloginit)
 $(call import-module,jni)
 $(call import-module,jsc)
diff --git a/ReactAndroid/src/main/jni/react/jni/BUCK b/ReactAndroid/src/main/jni/react/jni/BUCK
index 180bac5b87eb..bebdf54ce2a3 100644
--- a/ReactAndroid/src/main/jni/react/jni/BUCK
+++ b/ReactAndroid/src/main/jni/react/jni/BUCK
@@ -4,7 +4,6 @@ include_defs('//ReactAndroid/DEFS')
 SUPPORTED_PLATFORMS = '^android-(armv7|x86)$'
 
 DEPS = [
-  react_native_target('jni/first-party/fbgloginit:fbgloginit'),
   '//native/jni:jni',
   '//native/third-party/android-ndk:android',
   '//xplat/folly:molly',
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 9f5d95698527..1e4c37950352 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -3,7 +3,6 @@
 #include <android/asset_manager_jni.h>
 #include <android/input.h>
 #include <fb/log.h>
-#include <fbgloginit/fb/glog_init.h>
 #include <folly/json.h>
 #include <jni/Countable.h>
 #include <jni/Environment.h>
@@ -845,7 +844,6 @@ jmethodID getLogMarkerMethod() {
 
 extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
   return initialize(vm, [] {
-    facebook::gloginit::initialize(LOG_TAG);
     // Inject some behavior into react/
     ReactMarker::logMarker = bridge::logMarker;
     WebWorkerUtil::createWebWorkerThread = WebWorkers::createWebWorkerThread;

From eb2cd077a960cb328eb058aebfe23c87de23f2aa Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Mon, 22 Feb 2016 04:43:51 -0800
Subject: [PATCH 1252/1411] Support rotation in RCTModalHostView

Summary: When rotating a modal view we should adjust the root view's frame.

Reviewed By: majak

Differential Revision: D2939712

fb-gh-sync-id: 974634276d2c0ad22b46976020d0a21e1dac9026
shipit-source-id: 974634276d2c0ad22b46976020d0a21e1dac9026
---
 React/Views/RCTModalHostView.m | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/React/Views/RCTModalHostView.m b/React/Views/RCTModalHostView.m
index aecb77dbaec9..63121a37f757 100644
--- a/React/Views/RCTModalHostView.m
+++ b/React/Views/RCTModalHostView.m
@@ -58,13 +58,17 @@ - (void)notifyForBoundsChange:(CGRect)newBounds
 
 - (void)insertReactSubview:(UIView *)subview atIndex:(__unused NSInteger)atIndex
 {
+  RCTAssert([_modalViewController.view reactTag] == nil, @"Modal view can only have one subview");
   [subview addGestureRecognizer:_touchHandler];
+  subview.autoresizingMask = UIViewAutoresizingFlexibleHeight |
+                             UIViewAutoresizingFlexibleWidth;
   _modalViewController.view = subview;
 }
 
 - (void)removeReactSubview:(UIView *)subview
 {
   RCTAssert(subview == _modalViewController.view, @"Cannot remove view other than modal view");
+  [subview removeGestureRecognizer:_touchHandler];
   _modalViewController.view = nil;
 }
 

From 7964d80759446209b08d4f4569b3a2ef3df03999 Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Mon, 22 Feb 2016 05:29:08 -0800
Subject: [PATCH 1253/1411] Replace ModalFullscreenView constants by Dimensions

Reviewed By: jingc

Differential Revision: D2954172

fb-gh-sync-id: 8b2f68d13632de25830678ddc32a36c239970427
shipit-source-id: 8b2f68d13632de25830678ddc32a36c239970427
---
 React/Modules/RCTUIManager.m | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m
index d98cf73363df..cc0821013198 100644
--- a/React/Modules/RCTUIManager.m
+++ b/React/Modules/RCTUIManager.m
@@ -1265,10 +1265,6 @@ static void RCTMeasureLayout(RCTShadowView *view,
         @"height": @(RCTScreenSize().height),
         @"scale": @(RCTScreenScale()),
       },
-      @"modalFullscreenView": @{
-        @"width": @(RCTScreenSize().width),
-        @"height": @(RCTScreenSize().height),
-      },
     },
   }];
 

From e6c65102d4b1e3b7509a2fc4d595da51e83c6b77 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Mon, 22 Feb 2016 05:33:31 -0800
Subject: [PATCH 1254/1411] Add support for sharing images or other media via
 iOS share sheet

Summary:`ActionSheetIOS` now supports sharing images or other media via the `showShareActionSheetWithOptions` method. Simply specify a local file or data uri using the `url` argument to share the file.

NOTE: this mechanism doesn't currently support sharing images from the camera roll, however you can work around this by first saving the image to the ImageStore, and then fetching the base64 data.

Reviewed By: javache

Differential Revision: D2954273

fb-gh-sync-id: d5158f9d167fe92199933ca703f40f561732ac37
shipit-source-id: d5158f9d167fe92199933ca703f40f561732ac37
---
 Examples/UIExplorer/ActionSheetIOSExample.js     | 13 ++++++++++---
 Libraries/ActionSheetIOS/ActionSheetIOS.js       | 13 ++++++++++++-
 Libraries/ActionSheetIOS/RCTActionSheetManager.m | 16 ++++++++++++++--
 3 files changed, 36 insertions(+), 6 deletions(-)

diff --git a/Examples/UIExplorer/ActionSheetIOSExample.js b/Examples/UIExplorer/ActionSheetIOSExample.js
index ccc86fba4a50..31fd79c38efb 100644
--- a/Examples/UIExplorer/ActionSheetIOSExample.js
+++ b/Examples/UIExplorer/ActionSheetIOSExample.js
@@ -98,7 +98,6 @@ var ActionSheetTintExample = React.createClass({
   }
 });
 
-
 var ShareActionSheetExample = React.createClass({
   getInitialState() {
     return {
@@ -121,7 +120,7 @@ var ShareActionSheetExample = React.createClass({
 
   showShareActionSheet() {
     ActionSheetIOS.showShareActionSheetWithOptions({
-      url: 'https://code.facebook.com',
+      url: this.props.url,
       message: 'message to go with the shared url',
       subject: 'a subject to go in the email heading',
       excludedActivityTypes: [
@@ -163,6 +162,14 @@ exports.examples = [
   },
   {
     title: 'Show Share Action Sheet',
-    render(): ReactElement { return <ShareActionSheetExample />; }
+    render(): ReactElement {
+      return <ShareActionSheetExample url="https://code.facebook.com" />;
+    }
+  },
+    {
+    title: 'Share Local Image',
+    render(): ReactElement {
+      return <ShareActionSheetExample url="bunny.png" />;
+    }
   }
 ];
diff --git a/Libraries/ActionSheetIOS/ActionSheetIOS.js b/Libraries/ActionSheetIOS/ActionSheetIOS.js
index c63618441bb0..9570d2b8c3f5 100644
--- a/Libraries/ActionSheetIOS/ActionSheetIOS.js
+++ b/Libraries/ActionSheetIOS/ActionSheetIOS.js
@@ -31,7 +31,18 @@ var ActionSheetIOS = {
       callback
     );
   },
-
+  
+  /**
+   * Display the iOS share sheet. The `options` object should contain
+   * one or both of:
+   * 
+   * - `message` (string) - a message to share
+   * - `url` (string) - a URL to share
+   *
+   * NOTE: if `url` points to a local file, or is a base64-encoded
+   * uri, the file it points to will be loaded and shared directly.
+   * In this way, you can share images, videos, PDF files, etc.
+   */
   showShareActionSheetWithOptions(
     options: Object,
     failureCallback: Function,
diff --git a/Libraries/ActionSheetIOS/RCTActionSheetManager.m b/Libraries/ActionSheetIOS/RCTActionSheetManager.m
index ab1a8c8d05be..18fc8596b115 100644
--- a/Libraries/ActionSheetIOS/RCTActionSheetManager.m
+++ b/Libraries/ActionSheetIOS/RCTActionSheetManager.m
@@ -156,14 +156,26 @@ - (CGRect)sourceRectInView:(UIView *)sourceView
     return;
   }
 
-  NSMutableArray<id /* NSString or NSURL */> *items = [NSMutableArray array];
+  NSMutableArray<id> *items = [NSMutableArray array];
   NSString *message = [RCTConvert NSString:options[@"message"]];
   if (message) {
     [items addObject:message];
   }
   NSURL *URL = [RCTConvert NSURL:options[@"url"]];
   if (URL) {
-    [items addObject:URL];
+    if (URL.fileURL || [URL.scheme.lowercaseString isEqualToString:@"data"]) {
+      NSError *error;
+      NSData *data = [NSData dataWithContentsOfURL:URL
+                                           options:(NSDataReadingOptions)0
+                                             error:&error];
+      if (!data) {
+        failureCallback(error);
+        return;
+      }
+      [items addObject:data];
+    } else {
+      [items addObject:URL];
+    }
   }
   if (items.count == 0) {
     RCTLogError(@"No `url` or `message` to share");

From 5534f8b7c7ab9e5458735346444283e775eb3e1d Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Mon, 22 Feb 2016 06:02:47 -0800
Subject: [PATCH 1255/1411] Fix instacrash on login in rnfeed

Summary:build-break

Proguard was renaming MessageQueueThread interface methods that we reference from c++.

Differential Revision: D2960332

fb-gh-sync-id: 572dcd8a64e774f65c5abfb8cdf891efcb2bd591
shipit-source-id: 572dcd8a64e774f65c5abfb8cdf891efcb2bd591
---
 .../com/facebook/react/bridge/queue/MessageQueueThread.java    | 3 +++
 .../facebook/react/bridge/queue/MessageQueueThreadImpl.java    | 3 +++
 2 files changed, 6 insertions(+)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThread.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThread.java
index 9829ddfc5cfc..84cc9accb2ba 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThread.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThread.java
@@ -36,12 +36,14 @@ public interface MessageQueueThread {
   /**
    * @return whether the current Thread is also the Thread associated with this MessageQueueThread.
    */
+  @DoNotStrip
   boolean isOnThread();
 
   /**
    * Asserts {@link #isOnThread()}, throwing a {@link AssertionException} (NOT an
    * {@link AssertionError}) if the assertion fails.
    */
+  @DoNotStrip
   void assertIsOnThread();
 
   /**
@@ -49,5 +51,6 @@ public interface MessageQueueThread {
    * thing the thread runs. If called from a separate thread, this will block until the thread can
    * be quit and joined.
    */
+  @DoNotStrip
   void quitSynchronous();
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java
index f4377f4fe420..5593cb02f7aa 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/queue/MessageQueueThreadImpl.java
@@ -82,6 +82,7 @@ public void run() {
   /**
    * @return whether the current Thread is also the Thread associated with this MessageQueueThread.
    */
+  @DoNotStrip
   @Override
   public boolean isOnThread() {
     return mLooper.getThread() == Thread.currentThread();
@@ -91,6 +92,7 @@ public boolean isOnThread() {
    * Asserts {@link #isOnThread()}, throwing a {@link AssertionException} (NOT an
    * {@link AssertionError}) if the assertion fails.
    */
+  @DoNotStrip
   @Override
   public void assertIsOnThread() {
     SoftAssertions.assertCondition(isOnThread(), mAssertionErrorMessage);
@@ -100,6 +102,7 @@ public void assertIsOnThread() {
    * Quits this queue's Looper. If that Looper was running on a different Thread than the current
    * Thread, also waits for the last message being processed to finish and the Thread to die.
    */
+  @DoNotStrip
   @Override
   public void quitSynchronous() {
     mIsFinished = true;

From c17428e9d2ce3efac88b99f10663159bddd1b881 Mon Sep 17 00:00:00 2001
From: Mark Hahnenberg <mhahnenberg@fb.com>
Date: Mon, 22 Feb 2016 07:45:51 -0800
Subject: [PATCH 1256/1411] Schedule memory pressure handlers onto JS queue
 thread

Reviewed By: lexs

Differential Revision: D2940927

fb-gh-sync-id: 2556925194a753a33f039dc841a4001d7ede2bce
shipit-source-id: 2556925194a753a33f039dc841a4001d7ede2bce
---
 .../facebook/react/bridge/CatalystInstanceImpl.java    | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
index 0cacb9b47762..325a123065b4 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
@@ -331,8 +331,14 @@ public Collection<NativeModule> getNativeModules() {
   }
 
   @Override
-  public void handleMemoryPressure(MemoryPressure level) {
-    Assertions.assertNotNull(mBridge).handleMemoryPressure(level);
+  public void handleMemoryPressure(final MemoryPressure level) {
+    mReactQueueConfiguration.getJSQueueThread().runOnQueue(
+        new Runnable() {
+          @Override
+          public void run() {
+            Assertions.assertNotNull(mBridge).handleMemoryPressure(level);
+          }
+        });
   }
 
   /**

From e3f19b176a14ecbd997c35ede16ca732c8ca4f35 Mon Sep 17 00:00:00 2001
From: DebbieFire <bin.liu919@gmail.com>
Date: Mon, 22 Feb 2016 08:25:21 -0800
Subject: [PATCH 1257/1411] Update EmbeddedAppAndroid.md

Summary:The version of 0.17 will cause error ("undefined is not an object (evaluating 'screenPhysicalPixels.width')") when run to devices/simulator.
also see https://github.com/facebook/react-native/issues/5963
Closes https://github.com/facebook/react-native/pull/6076

Differential Revision: D2960511

fb-gh-sync-id: bd71de789fa1501b285b9bde01cf12ab9ce75888
shipit-source-id: bd71de789fa1501b285b9bde01cf12ab9ce75888
---
 docs/EmbeddedAppAndroid.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/EmbeddedAppAndroid.md b/docs/EmbeddedAppAndroid.md
index 7b72c7c9560e..13d573d1f38a 100644
--- a/docs/EmbeddedAppAndroid.md
+++ b/docs/EmbeddedAppAndroid.md
@@ -18,7 +18,7 @@ Since React makes no assumptions about the rest of your technology stack, it's e
 
 In your app's `build.gradle` file add the React Native dependency:
 
-    compile 'com.facebook.react:react-native:0.17.+'
+    compile 'com.facebook.react:react-native:0.20.+'
 
 You can find the latest version of the react-native library on [Maven Central](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.facebook.react%22%20AND%20a%3A%22react-native%22). Next, make sure you have the Internet permission in your `AndroidManifest.xml`:
 

From c79fed476c26f8172674d83a2cb5ded6adbbbeab Mon Sep 17 00:00:00 2001
From: Scott Dixon <scott@howrefreshing.com.au>
Date: Mon, 22 Feb 2016 08:27:18 -0800
Subject: [PATCH 1258/1411] Resolved UIExplorer StatusBarIOS deprecation
 warning

Summary:UIExplorer `<NavigatorIOS> - Custom` was displaying a deprecation warning. I took the warning's advice and updated with `StatusBar.setBarStyle`.

Before:
![image](https://cloud.githubusercontent.com/assets/4726068/13193296/f5adfcbc-d72a-11e5-923f-f327382f0137.png)

After:
![image](https://cloud.githubusercontent.com/assets/4726068/13193303/0536ae4a-d72b-11e5-90ac-7338280ecac0.png)
Closes https://github.com/facebook/react-native/pull/6042

Differential Revision: D2960522

fb-gh-sync-id: 07569372d3f3446395bbad9f87aba91d4f693440
shipit-source-id: 07569372d3f3446395bbad9f87aba91d4f693440
---
 Examples/UIExplorer/NavigatorIOSColorsExample.js | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Examples/UIExplorer/NavigatorIOSColorsExample.js b/Examples/UIExplorer/NavigatorIOSColorsExample.js
index 4078cac6db64..1735633c9d34 100644
--- a/Examples/UIExplorer/NavigatorIOSColorsExample.js
+++ b/Examples/UIExplorer/NavigatorIOSColorsExample.js
@@ -16,7 +16,7 @@
 var React = require('react-native');
 var {
   NavigatorIOS,
-  StatusBarIOS,
+  StatusBar,
   StyleSheet,
   Text,
   View
@@ -45,7 +45,7 @@ var NavigatorIOSColors = React.createClass({
 
   render: function() {
     // Set StatusBar with light contents to get better contrast
-    StatusBarIOS.setStyle('light-content');
+    StatusBar.setBarStyle('light-content');
 
     return (
       <NavigatorIOS
@@ -55,7 +55,7 @@ var NavigatorIOSColors = React.createClass({
           title: '<NavigatorIOS>',
           rightButtonTitle: 'Done',
           onRightButtonPress: () => {
-            StatusBarIOS.setStyle('default');
+            StatusBar.setBarStyle('default');
             this.props.onExampleExit();
           },
           passProps: {

From 25515405401fcbb7bda68e55c49b4cc141f13972 Mon Sep 17 00:00:00 2001
From: RichardCao <richardcao@RichardCaodeMacBook-Pro.local>
Date: Mon, 22 Feb 2016 09:43:31 -0800
Subject: [PATCH 1259/1411] Add "Reading" case

Summary:Add "Reading" case
Closes https://github.com/facebook/react-native/pull/6078

Differential Revision: D2960611

fb-gh-sync-id: e8a236463f77061ba5c42c6871a7608abadb0c22
shipit-source-id: e8a236463f77061ba5c42c6871a7608abadb0c22
---
 website/src/react-native/showcase.js | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 191e42392a17..5025379c33d5 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -622,6 +622,15 @@ var apps = [
     linkAppStore: 'https://itunes.apple.com/cn/app/hong-bei-bang-hai-liang-hong/id1007812319?mt=8',
     author: 'Hongbeibang'
   },
+  {
+    name: 'Reading',
+    icon: 'http://7xr0xq.com1.z0.glb.clouddn.com/about_logo.png',
+    link: 'http://www.wandoujia.com/apps/com.reading',
+    author: 'RichardCao',
+    blogs: [
+      'http://richard-cao.github.io/2016/02/06/Reading-App-Write-In-React-Native/',
+    ],
+  },
 ];
 
 var AppList = React.createClass({

From 876ecb291fe80471ff49df687b59f38b48d705d8 Mon Sep 17 00:00:00 2001
From: Eric Vicenti <evv@fb.com>
Date: Mon, 22 Feb 2016 16:15:35 -0800
Subject: [PATCH 1260/1411] Adopt NavigationExperimental in UIExplorer

Summary:Use the new Navigation library to make the UIExplorer navigation more flexible.

Deep linking examples are coming soon (hint: we just need to convert URIs to UIExplorerActions!)

Reviewed By: javache

Differential Revision: D2798050

fb-gh-sync-id: c7775393e2d7a30a161d0770192309567dcc8b0c
shipit-source-id: c7775393e2d7a30a161d0770192309567dcc8b0c
---
 .../NavigationAnimatedExample.js              |   8 +-
 .../NavigationExperimentalExample.js          |   2 +-
 .../NavigationTicTacToeExample.js             |  41 +-
 Examples/UIExplorer/UIExplorerActions.js      |  51 +++
 Examples/UIExplorer/UIExplorerApp.android.js  | 147 ++++---
 Examples/UIExplorer/UIExplorerApp.ios.js      | 170 ++++++--
 Examples/UIExplorer/UIExplorerExampleList.js  | 218 +++++++++++
 Examples/UIExplorer/UIExplorerList.android.js | 245 +++++++-----
 Examples/UIExplorer/UIExplorerList.ios.js     | 370 +++++++++++-------
 Examples/UIExplorer/UIExplorerListBase.js     | 190 ---------
 .../UIExplorer/UIExplorerNavigationReducer.js |  95 +++++
 .../UIExplorer/UIExplorerStateTitleMap.js     |  32 ++
 .../NavigationRootContainer.js                |  12 +-
 .../NavigationStateUtils.js                   |   5 -
 .../Reducer/NavigationFindReducer.js          |   8 +-
 .../Reducer/NavigationTabsReducer.js          |  71 +---
 16 files changed, 1067 insertions(+), 598 deletions(-)
 create mode 100644 Examples/UIExplorer/UIExplorerActions.js
 create mode 100644 Examples/UIExplorer/UIExplorerExampleList.js
 delete mode 100644 Examples/UIExplorer/UIExplorerListBase.js
 create mode 100644 Examples/UIExplorer/UIExplorerNavigationReducer.js
 create mode 100644 Examples/UIExplorer/UIExplorerStateTitleMap.js

diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
index e9f85ed1cb68..7b343f08d748 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
@@ -32,8 +32,8 @@ const NavigationBasicReducer = NavigationReducer.StackReducer({
   initialStates: [
     {key: 'First Route'}
   ],
-  matchAction: action => true,
-  actionStateMap: actionString => ({key: actionString}),
+  matchAction: action => action.type === 'push',
+  actionStateMap: action => ({key: action.key}),
 });
 
 class NavigationAnimatedExample extends React.Component {
@@ -45,7 +45,7 @@ class NavigationAnimatedExample extends React.Component {
       <NavigationRootContainer
         reducer={NavigationBasicReducer}
         ref={navRootContainer => { this.navRootContainer = navRootContainer; }}
-        persistenceKey="NavigationAnimatedExampleState"
+        persistenceKey="NavigationAnimExampleState"
         renderNavigation={this._renderNavigated}
       />
     );
@@ -85,7 +85,7 @@ class NavigationAnimatedExample extends React.Component {
               <NavigationExampleRow
                 text="Push!"
                 onPress={() => {
-                  onNavigate('Route #' + navigationState.children.length);
+                  onNavigate({ type: 'push', key: 'Route #' + navigationState.children.length });
                 }}
               />
               <NavigationExampleRow
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js
index 90b059e6d617..0a813410d02c 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js
@@ -35,7 +35,7 @@ var EXAMPLES = {
   'Tic Tac Toe': require('./NavigationTicTacToeExample'),
 };
 
-var EXAMPLE_STORAGE_KEY = 'NavigationExampleExample';
+var EXAMPLE_STORAGE_KEY = 'NavigationExperimentalExample';
 
 var NavigationExperimentalExample = React.createClass({
   statics: {
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationTicTacToeExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationTicTacToeExample.js
index 86029ef3b444..f71327572c00 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationTicTacToeExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationTicTacToeExample.js
@@ -31,7 +31,7 @@ const {
 
 type GameGrid = Array<Array<?string>>;
 
-const evenOddPlayerMap = ['o', 'x'];
+const evenOddPlayerMap = ['O', 'X'];
 const rowLeterMap = ['a', 'b', 'c'];
 
 function parseGame(game: string): GameGrid {
@@ -99,20 +99,20 @@ function isGameOver(gameString: string): boolean {
 
 class Cell extends React.Component {
   cellStyle() {
-    switch (this.props.value) {
-      case 'x':
+    switch (this.props.player) {
+      case 'X':
         return styles.cellX;
-      case 'o':
+      case 'O':
         return styles.cellO;
       default:
         return null;
     }
   }
   textStyle() {
-    switch (this.props.value) {
-      case 'x':
+    switch (this.props.player) {
+      case 'X':
         return styles.cellTextX;
-      case 'o':
+      case 'O':
         return styles.cellTextO;
       default:
         return {};
@@ -171,6 +171,11 @@ function TicTacToeGame(props) {
   );
   return (
     <View style={styles.container}>
+      <Text
+        style={styles.closeButton}
+        onPress={props.onExampleExit}>
+        Close
+      </Text>
       <Text style={styles.title}>EXTREME T3</Text>
       <View style={styles.board}>
         {rows}
@@ -184,18 +189,18 @@ function TicTacToeGame(props) {
 TicTacToeGame = NavigationContainer.create(TicTacToeGame);
 
 const GameActions = {
-  Turn: (row, col) => ({gameAction: 'turn', row, col }),
-  Reset: (row, col) => ({gameAction: 'reset' }),
+  Turn: (row, col) => ({type: 'TicTacToeTurnAction', row, col }),
+  Reset: (row, col) => ({type: 'TicTacToeResetAction' }),
 };
 
 function GameReducer(lastGame: ?string, action: Object): string {
-  if (!lastGame || !action || !action.gameAction) {
-    return lastGame || '';
+  if (!lastGame) {
+    lastGame = '';
   }
-  if (action.gameAction === 'reset') {
+  if (action.type === 'TicTacToeResetAction') {
     return '';
   }
-  if (!isGameOver(lastGame) && action.gameAction === 'turn') {
+  if (!isGameOver(lastGame) && action.type === 'TicTacToeTurnAction') {
     return playTurn(lastGame, action.row, action.col);
   }
   return lastGame;
@@ -206,10 +211,11 @@ class NavigationTicTacToeExample extends React.Component {
     return (
       <NavigationRootContainer
         reducer={GameReducer}
-        persistenceKey="TicTacToeGame"
+        persistenceKey="TicTacToeGameState"
         renderNavigation={(game) => (
           <TicTacToeGame
             game={game}
+            onExampleExit={this.props.onExampleExit}
           />
         )}
       />
@@ -221,6 +227,12 @@ NavigationTicTacToeExample.GameReducer = GameReducer;
 NavigationTicTacToeExample.GameActions = GameActions;
 
 const styles = StyleSheet.create({
+  closeButton: {
+    position: 'absolute',
+    left: 10,
+    top: 30,
+    fontSize: 14,
+  },
   container: {
     flex: 1,
     justifyContent: 'center',
@@ -257,7 +269,6 @@ const styles = StyleSheet.create({
     backgroundColor: '#7ebd26',
   },
   cellText: {
-    borderRadius: 5,
     fontSize: 50,
     fontFamily: 'AvenirNext-Bold',
   },
diff --git a/Examples/UIExplorer/UIExplorerActions.js b/Examples/UIExplorer/UIExplorerActions.js
new file mode 100644
index 000000000000..8f7a59f4e23e
--- /dev/null
+++ b/Examples/UIExplorer/UIExplorerActions.js
@@ -0,0 +1,51 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ *
+ * @flow
+ */
+'use strict';
+
+export type UIExplorerListWithFilterAction = {
+  type: 'UIExplorerListWithFilterAction',
+  filter: ?string;
+};
+
+export type UIExplorerExampleAction = {
+  type: 'UIExplorerExampleAction',
+  openExample: string;
+};
+
+import type {BackAction} from 'NavigationRootContainer';
+
+export type UIExplorerAction = BackAction | UIExplorerListWithFilterAction | UIExplorerExampleAction;
+
+function ExampleListWithFilter(filter: ?string): UIExplorerListWithFilterAction {
+  return {
+    type: 'UIExplorerListWithFilterAction',
+    filter,
+  };
+}
+
+function ExampleAction(openExample: string): UIExplorerExampleAction {
+  return {
+    type: 'UIExplorerExampleAction',
+    openExample,
+  };
+}
+
+const UIExplorerActions = {
+  ExampleListWithFilter,
+  ExampleAction,
+};
+
+module.exports = UIExplorerActions;
diff --git a/Examples/UIExplorer/UIExplorerApp.android.js b/Examples/UIExplorer/UIExplorerApp.android.js
index 6446e8fa4df6..9e26c5f7b798 100644
--- a/Examples/UIExplorer/UIExplorerApp.android.js
+++ b/Examples/UIExplorer/UIExplorerApp.android.js
@@ -22,84 +22,111 @@ const {
   BackAndroid,
   Dimensions,
   DrawerLayoutAndroid,
+  NavigationExperimental,
   StyleSheet,
   ToolbarAndroid,
   View,
   StatusBar,
 } = React;
-const UIExplorerList = require('./UIExplorerList.android');
+const {
+  RootContainer: NavigationRootContainer,
+} = NavigationExperimental;
+const UIExplorerActions = require('./UIExplorerActions');
+const UIExplorerExampleList = require('./UIExplorerExampleList');
+const UIExplorerList = require('./UIExplorerList');
+const UIExplorerNavigationReducer = require('./UIExplorerNavigationReducer');
+const UIExplorerStateTitleMap = require('./UIExplorerStateTitleMap');
 
-const DRAWER_WIDTH_LEFT = 56;
+var DRAWER_WIDTH_LEFT = 56;
 
 class UIExplorerApp extends React.Component {
-  constructor(props) {
-    super(props);
-    this.onSelectExample = this.onSelectExample.bind(this);
-    this._handleBackButtonPress = this._handleBackButtonPress.bind(this);
-    this.state = {
-      example: this._getUIExplorerHome(),
-    };
-  }
-
-  _getUIExplorerHome() {
-    return {
-      title: 'UIExplorer',
-      component: this._renderHome(),
-    };
-  }
-
   componentWillMount() {
-    BackAndroid.addEventListener('hardwareBackPress', this._handleBackButtonPress);
+    BackAndroid.addEventListener('hardwareBackPress', this._handleBackButtonPress.bind(this));
   }
 
   render() {
+    return (
+      <NavigationRootContainer
+        persistenceKey="UIExplorerStateNavState"
+        ref={navRootRef => { this._navigationRootRef = navRootRef; }}
+        reducer={UIExplorerNavigationReducer}
+        renderNavigation={this._renderApp.bind(this)}
+      />
+    );
+  }
+
+  _renderApp(navigationState, onNavigate) {
+    if (!navigationState) {
+      return null;
+    }
     return (
       <DrawerLayoutAndroid
         drawerPosition={DrawerLayoutAndroid.positions.Left}
         drawerWidth={Dimensions.get('window').width - DRAWER_WIDTH_LEFT}
         keyboardDismissMode="on-drag"
+        onDrawerOpen={() => {
+          this._overrideBackPressForDrawerLayout = true;
+        }}
+        onDrawerClose={() => {
+          this._overrideBackPressForDrawerLayout = false;
+        }}
         ref={(drawer) => { this.drawer = drawer; }}
-        renderNavigationView={this._renderNavigationView}>
-        {this._renderNavigation()}
+        renderNavigationView={this._renderDrawerContent.bind(this, onNavigate)}>
+        {this._renderNavigation(navigationState, onNavigate)}
       </DrawerLayoutAndroid>
     );
   }
 
-  _renderNavigationView() {
+  _renderDrawerContent(onNavigate) {
     return (
-      <UIExplorerList
-        onSelectExample={this.onSelectExample}
-        isInDrawer={true}
+      <UIExplorerExampleList
+        list={UIExplorerList}
+        displayTitleRow={true}
+        disableSearch={true}
+        onNavigate={(action) => {
+          this.drawer && this.drawer.closeDrawer();
+          onNavigate(action);
+        }}
       />
     );
   }
 
-  onSelectExample(example) {
-    this.drawer.closeDrawer();
-    if (example.title === this._getUIExplorerHome().title) {
-      example = this._getUIExplorerHome();
+  _renderNavigation(navigationState, onNavigate) {
+    if (navigationState.externalExample) {
+      var Component = UIExplorerList.Modules[navigationState.externalExample];
+      return (
+        <Component
+          onExampleExit={() => {
+            onNavigate(NavigationRootContainer.getBackAction());
+          }}
+          ref={(example) => { this._exampleRef = example; }}
+        />
+      );
     }
-    this.setState({
-      example: example,
-    });
-  }
-
-  _renderHome() {
-    const onSelectExample = this.onSelectExample;
-    return React.createClass({
-      render: function() {
-        return (
-          <UIExplorerList
-            onSelectExample={onSelectExample}
-            isInDrawer={false}
+    const {stack} = navigationState;
+    const title = UIExplorerStateTitleMap(stack.children[stack.index]);
+    if (stack && stack.children[1]) {
+      const {key} = stack.children[1];
+      const ExampleModule = UIExplorerList.Modules[key];
+      const ExampleComponent = UIExplorerExampleList.makeRenderable(ExampleModule);
+      return (
+        <View style={styles.container}>
+          <StatusBar
+            backgroundColor="#589c90"
           />
-        );
-      }
-    });
-  }
-
-  _renderNavigation() {
-    const Component = this.state.example.component;
+          <ToolbarAndroid
+            logo={require('image!launcher_icon')}
+            navIcon={require('image!ic_menu_black_24dp')}
+            onIconClicked={() => this.drawer.openDrawer()}
+            style={styles.toolbar}
+            title={title}
+          />
+          <ExampleComponent
+            ref={(example) => { this._exampleRef = example; }}
+          />
+        </View>
+      );
+    }
     return (
       <View style={styles.container}>
         <StatusBar
@@ -110,16 +137,24 @@ class UIExplorerApp extends React.Component {
           navIcon={require('image!ic_menu_black_24dp')}
           onIconClicked={() => this.drawer.openDrawer()}
           style={styles.toolbar}
-          title={this.state.example.title}
+          title={title}
         />
-        <Component
-          ref={(example) => { this._exampleRef = example; }}
+        <UIExplorerExampleList
+          list={UIExplorerList}
+          {...stack.children[0]}
         />
       </View>
     );
   }
 
   _handleBackButtonPress() {
+    if (this._overrideBackPressForDrawerLayout) {
+      // This hack is necessary because drawer layout provides an imperative API
+      // with open and close methods. This code would be cleaner if the drawer
+      // layout provided an `isOpen` prop and allowed us to pass a `onDrawerClose` handler.
+      this.drawer && this.drawer.closeDrawer();
+      return true;
+    }
     if (
       this._exampleRef &&
       this._exampleRef.handleBackAction &&
@@ -127,13 +162,13 @@ class UIExplorerApp extends React.Component {
     ) {
       return true;
     }
-    if (this.state.example.title !== this._getUIExplorerHome().title) {
-      this.onSelectExample(this._getUIExplorerHome());
-      return true;
+    if (this._navigationRootRef) {
+      return this._navigationRootRef.handleNavigation(
+        NavigationRootContainer.getBackAction()
+      );
     }
     return false;
   }
-
 }
 
 const styles = StyleSheet.create({
diff --git a/Examples/UIExplorer/UIExplorerApp.ios.js b/Examples/UIExplorer/UIExplorerApp.ios.js
index 120c772d8da2..f9dfe5c87782 100644
--- a/Examples/UIExplorer/UIExplorerApp.ios.js
+++ b/Examples/UIExplorer/UIExplorerApp.ios.js
@@ -12,77 +12,173 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  *
  * @providesModule UIExplorerApp
+ * @flow
  */
 'use strict';
 
 const React = require('react-native');
+const UIExplorerActions = require('./UIExplorerActions');
 const UIExplorerList = require('./UIExplorerList.ios');
-const SetPropertiesExampleApp = require('./SetPropertiesExampleApp');
-const RootViewSizeFlexibilityExampleApp = require('./RootViewSizeFlexibilityExampleApp');
+const UIExplorerExampleList = require('./UIExplorerExampleList');
+const UIExplorerNavigationReducer = require('./UIExplorerNavigationReducer');
+const UIExplorerStateTitleMap = require('./UIExplorerStateTitleMap');
+
 const {
   AppRegistry,
-  NavigatorIOS,
+  NavigationExperimental,
+  SnapshotViewIOS,
   StyleSheet,
+  Text,
+  TouchableHighlight,
   View,
-  StatusBar,
 } = React;
+const {
+  AnimatedView: NavigationAnimatedView,
+  Card: NavigationCard,
+  Header: NavigationHeader,
+  Reducer: NavigationReducer,
+  RootContainer: NavigationRootContainer,
+} = NavigationExperimental;
+const StackReducer = NavigationReducer.StackReducer;
 
-class UIExplorerApp extends React.Component {
+import type {
+  NavigationState,
+} from 'NavigationStateUtils'
 
-  constructor(props) {
-    super(props);
-    this.state = {
-      openExternalExample: (null: ?React.Component),
-    };
-  }
+import type { Value } from 'Animated';
+import type { Layout } from 'NavigationAnimatedView';
+import type { UIExplorerNavigationState } from './UIExplorerNavigationReducer';
 
+import type {
+  UIExplorerExample,
+} from './UIExplorerList.ios'
+
+class UIExplorerApp extends React.Component {
+  _renderNavigation: Function;
+  componentWillMount() {
+    this._renderNavigation = this._renderNavigation.bind(this);
+  }
   render() {
-    if (this.state.openExternalExample) {
-      const Example = this.state.openExternalExample;
+    return (
+      <NavigationRootContainer
+        persistenceKey="UIExplorerState"
+        reducer={UIExplorerNavigationReducer}
+        renderNavigation={this._renderNavigation}
+      />
+    );
+  }
+  _renderNavigation(navigationState: UIExplorerNavigationState, onNavigate: Function) {
+    if (!navigationState) {
+      return null;
+    }
+    if (navigationState.externalExample) {
+      var Component = UIExplorerList.Modules[navigationState.externalExample];
       return (
-        <Example
+        <Component
           onExampleExit={() => {
-            this.setState({ openExternalExample: null, });
+            onNavigate(NavigationRootContainer.getBackAction());
           }}
         />
       );
     }
+    const {stack} = navigationState;
+    return (
+      <NavigationAnimatedView
+        navigationState={stack}
+        style={styles.container}
+        renderOverlay={this._renderOverlay.bind(this, stack)}
+        renderScene={this._renderSceneContainer.bind(this, stack)}
+      />
+    );
+  }
 
+  _renderOverlay(
+    navigationState: NavigationState,
+    position: Value,
+    layout: Layout
+  ): ReactElement {
     return (
-      <View style={styles.container}>
-        <StatusBar barStyle="default" />
-        <NavigatorIOS
-          style={styles.container}
-          initialRoute={{
-            title: 'UIExplorer',
-            component: UIExplorerList,
-            passProps: {
-              onExternalExampleRequested: (example) => {
-                this.setState({ openExternalExample: example, });
-              },
-            }
-          }}
-          itemWrapperStyle={styles.itemWrapper}
-          tintColor="#008888"
-        />
-      </View>
+      <NavigationHeader
+        navigationState={navigationState}
+        position={position}
+        getTitle={UIExplorerStateTitleMap}
+      />
+    );    
+  }
+
+  _renderSceneContainer(
+    navigationState: NavigationState,
+    scene: NavigationState,
+    index: number,
+    position: Value,
+    layout: Layout
+  ): ReactElement {
+    return (
+      <NavigationCard
+        key={scene.key}
+        index={index}
+        navigationState={navigationState}
+        position={position}
+        layout={layout}>
+        {this._renderScene(scene)}
+      </NavigationCard>
     );
   }
 
+  _renderScene(state: Object): ?ReactElement {
+    if (state.key === 'AppList') {
+      return (
+        <UIExplorerExampleList
+          list={UIExplorerList}
+          style={styles.exampleContainer}
+          {...state}
+        />
+      );
+    }
+
+    const Example = UIExplorerList.Modules[state.key];
+    if (Example) {
+      const Component = UIExplorerExampleList.makeRenderable(Example);
+      return (
+        <View style={styles.exampleContainer}>
+          <Component />
+        </View>
+      );
+    }
+    return null;
+  }
 }
 
 const styles = StyleSheet.create({
   container: {
     flex: 1,
   },
-  itemWrapper: {
-    backgroundColor: '#eaeaea',
+  exampleContainer: {
+    flex: 1,
+    paddingTop: 60,
   },
 });
 
-AppRegistry.registerComponent('SetPropertiesExampleApp', () => SetPropertiesExampleApp);
-AppRegistry.registerComponent('RootViewSizeFlexibilityExampleApp', () => RootViewSizeFlexibilityExampleApp);
+AppRegistry.registerComponent('SetPropertiesExampleApp', () => require('./SetPropertiesExampleApp'));
+AppRegistry.registerComponent('RootViewSizeFlexibilityExampleApp', () => require('./RootViewSizeFlexibilityExampleApp'));
 AppRegistry.registerComponent('UIExplorerApp', () => UIExplorerApp);
-UIExplorerList.registerComponents();
+
+// Register suitable examples for snapshot tests
+UIExplorerList.ComponentExamples.concat(UIExplorerList.APIExamples).forEach((Example: UIExplorerExample) => {
+  const ExampleModule = Example.module;
+  if (ExampleModule.displayName) {
+    var Snapshotter = React.createClass({
+      render: function() {
+        var Renderable = UIExplorerExampleList.makeRenderable(ExampleModule);
+        return (
+          <SnapshotViewIOS>
+            <Renderable />
+          </SnapshotViewIOS>
+        );
+      },
+    });
+    AppRegistry.registerComponent(ExampleModule.displayName, () => Snapshotter);
+  }
+});
 
 module.exports = UIExplorerApp;
diff --git a/Examples/UIExplorer/UIExplorerExampleList.js b/Examples/UIExplorer/UIExplorerExampleList.js
new file mode 100644
index 000000000000..07a07f381f4f
--- /dev/null
+++ b/Examples/UIExplorer/UIExplorerExampleList.js
@@ -0,0 +1,218 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ *
+ * @flow
+ */
+'use strict';
+
+const React = require('react-native');
+const UIExplorerActions = require('./UIExplorerActions');
+const {
+  ListView,
+  NavigationExperimental,
+  StyleSheet,
+  Text,
+  TextInput,
+  TouchableHighlight,
+  View,
+} = React;
+const createExamplePage = require('./createExamplePage');
+const {
+  Container: NavigationContainer,
+} = NavigationExperimental;
+
+import type {
+  UIExplorerExample,
+} from './UIExplorerList.ios'
+
+const ds = new ListView.DataSource({
+  rowHasChanged: (r1, r2) => r1 !== r2,
+  sectionHeaderHasChanged: (h1, h2) => h1 !== h2,
+});
+
+class UIExplorerExampleList extends React.Component {
+  constuctor(props: {
+    disableTitleRow: ?boolean,
+    onNavigate: Function,
+    filter: ?string,
+    list: {
+      ComponentExamples: Array<UIExplorerExample>,
+      APIExamples: Array<UIExplorerExample>,
+    },
+    style: ?any,
+  }) {
+
+  }
+  render(): ?ReactElement {
+    const filterText = this.props.filter || '';
+    const filterRegex = new RegExp(String(filterText), 'i');
+    const filter = (example) => filterRegex.test(example.module.title);
+
+    const dataSource = ds.cloneWithRowsAndSections({
+      components: this.props.list.ComponentExamples.filter(filter),
+      apis: this.props.list.APIExamples.filter(filter),
+    });
+    return (
+      <View style={[styles.listContainer, this.props.style]}>
+        {this._renderTitleRow()}
+        {this._renderTextInput()}
+        <ListView
+          style={styles.list}
+          dataSource={dataSource}
+          renderRow={this._renderExampleRow.bind(this)}
+          renderSectionHeader={this._renderSectionHeader}
+          keyboardShouldPersistTaps={true}
+          automaticallyAdjustContentInsets={false}
+          keyboardDismissMode="on-drag"
+        />
+      </View>
+    );
+  }
+
+  _renderTitleRow(): ?ReactElement {
+    if (!this.props.displayTitleRow) {
+      return null;
+    }
+    return this._renderRow(
+      'UIExplorer',
+      'React Native Examples',
+      'home_key',
+      () => {
+        this.props.onNavigate(
+          UIExplorerActions.ExampleListWithFilter('')
+        );
+      }
+    );
+  }
+
+  _renderTextInput(): ?ReactElement {
+    if (this.props.disableSearch) {
+      return null;
+    }
+    return (
+      <View style={styles.searchRow}>
+        <TextInput
+          autoCapitalize="none"
+          autoCorrect={false}
+          clearButtonMode="always"
+          onChangeText={text => {
+            this.props.onNavigate(UIExplorerActions.ExampleListWithFilter(text));
+          }}
+          placeholder="Search..."
+          style={[styles.searchTextInput, this.props.searchTextInputStyle]}
+          testID="explorer_search"
+          value={this.props.filter}
+        />
+      </View>
+    );
+  }
+
+  _renderSectionHeader(data: any, section: string): ?ReactElement {
+    return (
+      <Text style={styles.sectionHeader}>
+        {section.toUpperCase()}
+      </Text>
+    );
+  }
+
+  _renderExampleRow(example: {key: string, module: Object}): ?ReactElement {
+    return this._renderRow(
+      example.module.title,
+      example.module.description,
+      example.key,
+      () => this._handleRowPress(example.key)
+    );
+  }
+
+  _renderRow(title: string, description: string, key: ?string, handler: ?Function): ?ReactElement {
+    return (
+      <View key={key || title}>
+        <TouchableHighlight onPress={handler}>
+          <View style={styles.row}>
+            <Text style={styles.rowTitleText}>
+              {title}
+            </Text>
+            <Text style={styles.rowDetailText}>
+              {description}
+            </Text>
+          </View>
+        </TouchableHighlight>
+        <View style={styles.separator} />
+      </View>
+    );
+  }
+
+  _handleRowPress(exampleKey: string): void {
+    this.props.onNavigate(UIExplorerActions.ExampleAction(exampleKey))
+  }
+}
+
+function makeRenderable(example: any): ReactClass<any, any, any> {
+  return example.examples ?
+    createExamplePage(null, example) :
+    example;
+}
+
+UIExplorerExampleList = NavigationContainer.create(UIExplorerExampleList);
+UIExplorerExampleList.makeRenderable = makeRenderable;
+
+var styles = StyleSheet.create({
+  listContainer: {
+    flex: 1,
+  },
+  list: {
+    backgroundColor: '#eeeeee',
+  },
+  sectionHeader: {
+    padding: 5,
+    fontWeight: '500',
+    fontSize: 11,
+  },
+  group: {
+    backgroundColor: 'white',
+  },
+  row: {
+    backgroundColor: 'white',
+    justifyContent: 'center',
+    paddingHorizontal: 15,
+    paddingVertical: 8,
+  },
+  separator: {
+    height: StyleSheet.hairlineWidth,
+    backgroundColor: '#bbbbbb',
+    marginLeft: 15,
+  },
+  rowTitleText: {
+    fontSize: 17,
+    fontWeight: '500',
+  },
+  rowDetailText: {
+    fontSize: 15,
+    color: '#888888',
+    lineHeight: 20,
+  },
+  searchRow: {
+    backgroundColor: '#eeeeee',
+    padding: 10,
+  },
+  searchTextInput: {
+    backgroundColor: 'white',
+    borderColor: '#cccccc',
+    borderRadius: 3,
+    borderWidth: 1,
+    paddingLeft: 8,
+    height: 35,
+  },
+});
+
+module.exports = UIExplorerExampleList;
diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index 4cd5649d7066..321d84a41676 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -15,102 +15,167 @@
  */
 'use strict';
 
-var React = require('react-native');
-var {
-  StyleSheet,
-  View,
-} = React;
-var UIExplorerListBase = require('./UIExplorerListBase');
+export type UIExplorerExample = {
+  key: string;
+  module: React.Component;
+};
 
-var COMPONENTS = [
-  require('./ImageExample'),
-  require('./ListViewExample'),
-  require('./PickerAndroidExample'),
-  require('./ProgressBarAndroidExample'),
-  require('./RefreshControlExample'),
-  require('./ScrollViewSimpleExample'),
-  require('./StatusBarExample'),
-  require('./SwitchExample'),
-  require('./TextExample.android'),
-  require('./TextInputExample.android'),
-  require('./ToolbarAndroidExample'),
-  require('./TouchableExample'),
-  require('./ViewExample'),
-  require('./ViewPagerAndroidExample.android'),
-  require('./WebViewExample'),
+var ComponentExamples: Array<UIExplorerExample> = [
+  {
+    key: 'ImageExample',
+    module: require('./ImageExample'),
+  },
+  {
+    key: 'ListViewExample',
+    module: require('./ListViewExample'),
+  },
+  {
+    key: 'PickerAndroidExample',
+    module: require('./PickerAndroidExample'),
+  },
+  {
+    key: 'ProgressBarAndroidExample',
+    module: require('./ProgressBarAndroidExample'),
+  },
+  {
+    key: 'RefreshControlExample',
+    module: require('./RefreshControlExample'),
+  },
+  {
+    key: 'ScrollViewSimpleExample',
+    module: require('./ScrollViewSimpleExample'),
+  },
+  {
+    key: 'StatusBarExample',
+    module: require('./StatusBarExample'),
+  },
+  {
+    key: 'SwitchExample',
+    module: require('./SwitchExample'),
+  },
+  {
+    key: 'TextExample',
+    module: require('./TextExample'),
+  },
+  {
+    key: 'TextInputExample',
+    module: require('./TextInputExample'),
+  },
+  {
+    key: 'ToolbarAndroidExample',
+    module: require('./ToolbarAndroidExample'),
+  },
+  {
+    key: 'TouchableExample',
+    module: require('./TouchableExample'),
+  },
+  {
+    key: 'ViewExample',
+    module: require('./ViewExample'),
+  },
+  {
+    key: 'ViewPagerAndroidExample',
+    module: require('./ViewPagerAndroidExample'),
+  },
+  {
+    key: 'WebViewExample',
+    module: require('./WebViewExample'),
+  },
 ];
 
-var APIS = [
-  require('./AccessibilityAndroidExample.android'),
-  require('./AlertExample').AlertExample,
-  require('./AppStateExample'),
-  require('./BorderExample'),
-  require('./CameraRollExample'),
-  require('./ClipboardExample'),
-  require('./DatePickerAndroidExample'),
-  require('./GeolocationExample'),
-  require('./ImageEditingExample'),
-  require('./IntentAndroidExample.android'),
-  require('./LayoutEventsExample'),
-  require('./LayoutExample'),
-  require('./NavigationExperimental/NavigationExperimentalExample'),
-  require('./NetInfoExample'),
-  require('./PanResponderExample'),
-  require('./PointerEventsExample'),
-  require('./TimePickerAndroidExample'),
-  require('./TimerExample'),
-  require('./ToastAndroidExample.android'),
-  require('./XHRExample'),
+const APIExamples = [
+  {
+    key: 'AccessibilityAndroidExample',
+    module: require('./AccessibilityAndroidExample'),
+  },
+  {
+    key: 'AlertExample',
+    module: require('./AlertExample').AlertExample,
+  },
+  {
+    key: 'AppStateExample',
+    module: require('./AppStateExample'),
+  },
+  {
+    key: 'BorderExample',
+    module: require('./BorderExample'),
+  },
+  {
+    key: 'CameraRollExample',
+    module: require('./CameraRollExample'),
+  },
+  {
+    key: 'ClipboardExample',
+    module: require('./ClipboardExample'),
+  },
+  {
+    key: 'DatePickerAndroidExample',
+    module: require('./DatePickerAndroidExample'),
+  },
+  {
+    key: 'GeolocationExample',
+    module: require('./GeolocationExample'),
+  },
+  {
+    key: 'ImageEditingExample',
+    module: require('./ImageEditingExample'),
+  },
+  {
+    key: 'IntentAndroidExample',
+    module: require('./IntentAndroidExample'),
+  },
+  {
+    key: 'LayoutEventsExample',
+    module: require('./LayoutEventsExample'),
+  },
+  {
+    key: 'LayoutExample',
+    module: require('./LayoutExample'),
+  },
+  {
+    key: 'NavigationExperimentalExample',
+    module: require('./NavigationExperimental/NavigationExperimentalExample'),
+  },
+  {
+    key: 'NetInfoExample',
+    module: require('./NetInfoExample'),
+  },
+  {
+    key: 'PanResponderExample',
+    module: require('./PanResponderExample'),
+  },
+  {
+    key: 'PointerEventsExample',
+    module: require('./PointerEventsExample'),
+  },
+  {
+    key: 'TimePickerAndroidExample',
+    module: require('./TimePickerAndroidExample'),
+  },
+  {
+    key: 'TimerExample',
+    module: require('./TimerExample'),
+  },
+  {
+    key: 'ToastAndroidExample',
+    module: require('./ToastAndroidExample'),
+  },
+  {
+    key: 'XHRExample',
+    module: require('./XHRExample'),
+  },
 ];
 
-type Props = {
-  onSelectExample: Function,
-  isInDrawer: bool,
-};
-
-class UIExplorerList extends React.Component {
-  props: Props;
-
-  render() {
-    return (
-      <UIExplorerListBase
-        components={COMPONENTS}
-        apis={APIS}
-        searchText=""
-        renderAdditionalView={this.renderAdditionalView.bind(this)}
-        onPressRow={this.onPressRow.bind(this)}
-      />
-    );
-  }
+const Modules = {};
 
-  renderAdditionalView(renderRow, renderTextInput): React.Component {
-    if (this.props.isInDrawer) {
-      var homePage = renderRow({
-        title: 'UIExplorer',
-        description: 'List of examples',
-      }, -1);
-      return (
-        <View>
-          {homePage}
-        </View>
-      );
-    }
-    return renderTextInput(styles.searchTextInput);
-  }
-
-  onPressRow(example: any) {
-    var Component = UIExplorerListBase.makeRenderable(example);
-    this.props.onSelectExample({
-      title: Component.title,
-      component: Component,
-    });
-  }
-}
-
-var styles = StyleSheet.create({
-  searchTextInput: {
-    padding: 2,
-  },
+APIExamples.concat(ComponentExamples).forEach(Example => {
+  Modules[Example.key] = Example.module;
 });
 
+const UIExplorerList = {
+  APIExamples,
+  ComponentExamples,
+  Modules,
+};
+
 module.exports = UIExplorerList;
diff --git a/Examples/UIExplorer/UIExplorerList.ios.js b/Examples/UIExplorer/UIExplorerList.ios.js
index 5c33d7f645e5..70a6dbf4c591 100644
--- a/Examples/UIExplorer/UIExplorerList.ios.js
+++ b/Examples/UIExplorer/UIExplorerList.ios.js
@@ -15,151 +15,243 @@
  */
 'use strict';
 
-var React = require('react-native');
-var {
-  AppRegistry,
-  Settings,
-  SnapshotViewIOS,
-  StyleSheet,
-} = React;
-
-import type { NavigationContext } from 'NavigationContext';
-
-var UIExplorerListBase = require('./UIExplorerListBase');
-
-var COMPONENTS = [
-  require('./ActivityIndicatorIOSExample'),
-  require('./DatePickerIOSExample'),
-  require('./ImageExample'),
-  require('./LayoutEventsExample'),
-  require('./ListViewExample'),
-  require('./ListViewGridLayoutExample'),
-  require('./ListViewPagingExample'),
-  require('./MapViewExample'),
-  require('./ModalExample'),
-  require('./Navigator/NavigatorExample'),
-  require('./NavigatorIOSColorsExample'),
-  require('./NavigatorIOSExample'),
-  require('./PickerIOSExample'),
-  require('./ProgressViewIOSExample'),
-  require('./RefreshControlExample'),
-  require('./ScrollViewExample'),
-  require('./SegmentedControlIOSExample'),
-  require('./SliderIOSExample'),
-  require('./StatusBarExample'),
-  require('./SwitchExample'),
-  require('./TabBarIOSExample'),
-  require('./TextExample.ios'),
-  require('./TextInputExample.ios'),
-  require('./TouchableExample'),
-  require('./TransparentHitTestExample'),
-  require('./ViewExample'),
-  require('./WebViewExample'),
-];
+export type UIExplorerExample = {
+  key: string;
+  module: Object;
+};
 
-var APIS = [
-  require('./AccessibilityIOSExample'),
-  require('./ActionSheetIOSExample'),
-  require('./AdSupportIOSExample'),
-  require('./AlertIOSExample'),
-  require('./AnimatedExample'),
-  require('./AnimatedGratuitousApp/AnExApp'),
-  require('./AppStateIOSExample'),
-  require('./AppStateExample'),
-  require('./AsyncStorageExample'),
-  require('./BorderExample'),
-  require('./BoxShadowExample'),
-  require('./CameraRollExample'),
-  require('./ClipboardExample'),
-  require('./GeolocationExample'),
-  require('./ImageEditingExample'),
-  require('./LayoutExample'),
-  require('./NavigationExperimental/NavigationExperimentalExample'),
-  require('./NetInfoExample'),
-  require('./PanResponderExample'),
-  require('./PointerEventsExample'),
-  require('./PushNotificationIOSExample'),
-  require('./RCTRootViewIOSExample'),
-  require('./StatusBarIOSExample'),
-  require('./TimerExample'),
-  require('./TransformExample'),
-  require('./VibrationIOSExample'),
-  require('./XHRExample.ios'),
+var ComponentExamples: Array<UIExplorerExample> = [
+  {
+    key: 'ActivityIndicatorIOSExample',
+    module: require('./ActivityIndicatorIOSExample'),
+  },
+  {
+    key: 'DatePickerIOSExample',
+    module: require('./DatePickerIOSExample'),
+  },
+  {
+    key: 'ImageExample',
+    module: require('./ImageExample'),
+  },
+  {
+    key: 'LayoutEventsExample',
+    module: require('./LayoutEventsExample'),
+  },
+  {
+    key: 'ListViewExample',
+    module: require('./ListViewExample'),
+  },
+  {
+    key: 'ListViewGridLayoutExample',
+    module: require('./ListViewGridLayoutExample'),
+  },
+  {
+    key: 'ListViewPagingExample',
+    module: require('./ListViewPagingExample'),
+  },
+  {
+    key: 'MapViewExample',
+    module: require('./MapViewExample'),
+  },
+  {
+    key: 'ModalExample',
+    module: require('./ModalExample'),
+  },
+  {
+    key: 'NavigatorExample',
+    module: require('./Navigator/NavigatorExample'),
+  },
+  {
+    key: 'NavigatorIOSColorsExample',
+    module: require('./NavigatorIOSColorsExample'),
+  },
+  {
+    key: 'NavigatorIOSExample',
+    module: require('./NavigatorIOSExample'),
+  },
+  {
+    key: 'PickerIOSExample',
+    module: require('./PickerIOSExample'),
+  },
+  {
+    key: 'ProgressViewIOSExample',
+    module: require('./ProgressViewIOSExample'),
+  },
+  {
+    key: 'RefreshControlExample',
+    module: require('./RefreshControlExample'),
+  },
+  {
+    key: 'ScrollViewExample',
+    module: require('./ScrollViewExample'),
+  },
+  {
+    key: 'SegmentedControlIOSExample',
+    module: require('./SegmentedControlIOSExample'),
+  },
+  {
+    key: 'SliderIOSExample',
+    module: require('./SliderIOSExample'),
+  },
+  {
+    key: 'StatusBarExample',
+    module: require('./StatusBarExample'),
+  },
+  {
+    key: 'SwitchExample',
+    module: require('./SwitchExample'),
+  },
+  {
+    key: 'TabBarIOSExample',
+    module: require('./TabBarIOSExample'),
+  },
+  {
+    key: 'TextExample',
+    module: require('./TextExample.ios'),
+  },
+  {
+    key: 'TextInputExample',
+    module: require('./TextInputExample.ios'),
+  },
+  {
+    key: 'TouchableExample',
+    module: require('./TouchableExample'),
+  },
+  {
+    key: 'TransparentHitTestExample',
+    module: require('./TransparentHitTestExample'),
+  },
+  {
+    key: 'ViewExample',
+    module: require('./ViewExample'),
+  },
+  {
+    key: 'WebViewExample',
+    module: require('./WebViewExample'),
+  },
 ];
 
-type Props = {
-  navigator: {
-    navigationContext: NavigationContext,
-    push: (route: {title: string, component: ReactClass<any,any,any>}) => void,
+var APIExamples: Array<UIExplorerExample> = [
+  {
+    key: 'AccessibilityIOSExample',
+    module: require('./AccessibilityIOSExample'),
   },
-  onExternalExampleRequested: Function,
-};
-
-class UIExplorerList extends React.Component {
-  props: Props;
-
-  render() {
-    return (
-      <UIExplorerListBase
-        components={COMPONENTS}
-        apis={APIS}
-        searchText={Settings.get('searchText')}
-        renderAdditionalView={this.renderAdditionalView.bind(this)}
-        search={this.search.bind(this)}
-        onPressRow={this.onPressRow.bind(this)}
-      />
-    );
-  }
-
-  renderAdditionalView(renderRow: Function, renderTextInput: Function): React.Component {
-    return renderTextInput(styles.searchTextInput);
-  }
-
-  search(text: mixed) {
-    Settings.set({searchText: text});
-  }
-
-  _openExample(example: any) {
-    if (example.external) {
-      this.props.onExternalExampleRequested(example);
-      return;
-    }
-
-    var Component = UIExplorerListBase.makeRenderable(example);
-    this.props.navigator.push({
-      title: Component.title,
-      component: Component,
-    });
-  }
-
-  onPressRow(example: any) {
-    this._openExample(example);
-  }
+  {
+    key: 'ActionSheetIOSExample',
+    module: require('./ActionSheetIOSExample'),
+  },
+  {
+    key: 'AdSupportIOSExample',
+    module: require('./AdSupportIOSExample'),
+  },
+  {
+    key: 'AlertIOSExample',
+    module: require('./AlertIOSExample'),
+  },
+  {
+    key: 'AnimatedExample',
+    module: require('./AnimatedExample'),
+  },
+  {
+    key: 'AnExApp',
+    module: require('./AnimatedGratuitousApp/AnExApp'),
+  },
+  {
+    key: 'AppStateIOSExample',
+    module: require('./AppStateIOSExample'),
+  },
+  {
+    key: 'AppStateExample',
+    module: require('./AppStateExample'),
+  },
+  {
+    key: 'AsyncStorageExample',
+    module: require('./AsyncStorageExample'),
+  },
+  {
+    key: 'BorderExample',
+    module: require('./BorderExample'),
+  },
+  {
+    key: 'BoxShadowExample',
+    module: require('./BoxShadowExample'),
+  },
+  {
+    key: 'CameraRollExample',
+    module: require('./CameraRollExample'),
+  },
+  {
+    key: 'ClipboardExample',
+    module: require('./ClipboardExample'),
+  },
+  {
+    key: 'GeolocationExample',
+    module: require('./GeolocationExample'),
+  },
+  {
+    key: 'ImageEditingExample',
+    module: require('./ImageEditingExample'),
+  },
+  {
+    key: 'LayoutExample',
+    module: require('./LayoutExample'),
+  },
+  {
+    key: 'NavigationExperimentalExample',
+    module: require('./NavigationExperimental/NavigationExperimentalExample'),
+  },
+  {
+    key: 'NetInfoExample',
+    module: require('./NetInfoExample'),
+  },
+  {
+    key: 'PanResponderExample',
+    module: require('./PanResponderExample'),
+  },
+  {
+    key: 'PointerEventsExample',
+    module: require('./PointerEventsExample'),
+  },
+  {
+    key: 'PushNotificationIOSExample',
+    module: require('./PushNotificationIOSExample'),
+  },
+  {
+    key: 'RCTRootViewIOSExample',
+    module: require('./RCTRootViewIOSExample'),
+  },
+  {
+    key: 'StatusBarIOSExample',
+    module: require('./StatusBarIOSExample'),
+  },
+  {
+    key: 'TimerExample',
+    module: require('./TimerExample'),
+  },
+  {
+    key: 'TransformExample',
+    module: require('./TransformExample'),
+  },
+  {
+    key: 'VibrationIOSExample',
+    module: require('./VibrationIOSExample'),
+  },
+  {
+    key: 'XHRExample',
+    module: require('./XHRExample.ios'),
+  },
+];
 
-  // Register suitable examples for snapshot tests
-  static registerComponents() {
-    COMPONENTS.concat(APIS).forEach((Example) => {
-      if (Example.displayName) {
-        var Snapshotter = React.createClass({
-          render: function() {
-            var Renderable = UIExplorerListBase.makeRenderable(Example);
-            return (
-              <SnapshotViewIOS>
-                <Renderable />
-              </SnapshotViewIOS>
-            );
-          },
-        });
-        AppRegistry.registerComponent(Example.displayName, () => Snapshotter);
-      }
-    });
-  }
-}
+const Modules = {};
 
-var styles = StyleSheet.create({
-  searchTextInput: {
-    height: 30,
-  },
+APIExamples.concat(ComponentExamples).forEach(Example => {
+  Modules[Example.key] = Example.module;
 });
 
+const UIExplorerList = {
+  APIExamples,
+  ComponentExamples,
+  Modules,
+};
+
 module.exports = UIExplorerList;
diff --git a/Examples/UIExplorer/UIExplorerListBase.js b/Examples/UIExplorer/UIExplorerListBase.js
deleted file mode 100644
index 17ecd8dc2c02..000000000000
--- a/Examples/UIExplorer/UIExplorerListBase.js
+++ /dev/null
@@ -1,190 +0,0 @@
-/**
- * The examples provided by Facebook are for non-commercial testing and
- * evaluation purposes only.
- *
- * Facebook reserves all rights not expressly granted.
- *
- * 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 NON INFRINGEMENT. IN NO EVENT SHALL
- * FACEBOOK 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.
- *
- * @flow
- */
-'use strict';
-
-var React = require('react-native');
-var {
-  ListView,
-  StyleSheet,
-  Text,
-  TextInput,
-  TouchableHighlight,
-  View,
-} = React;
-var createExamplePage = require('./createExamplePage');
-
-var ds = new ListView.DataSource({
-  rowHasChanged: (r1, r2) => r1 !== r2,
-  sectionHeaderHasChanged: (h1, h2) => h1 !== h2,
-});
-
-class UIExplorerListBase extends React.Component {
-  constructor(props: any) {
-    super(props);
-    this.state = {
-      dataSource: ds.cloneWithRowsAndSections({
-        components: [],
-        apis: [],
-      }),
-      searchText: this.props.searchText || '',
-    };
-  }
-
-  componentDidMount(): void {
-    this.search(this.state.searchText);
-  }
-
-  render() {
-    var topView = this.props.renderAdditionalView &&
-      this.props.renderAdditionalView(this.renderRow.bind(this), this.renderTextInput.bind(this));
-
-    return (
-      <View style={styles.listContainer}>
-        {topView}
-        <ListView
-          style={styles.list}
-          dataSource={this.state.dataSource}
-          renderRow={this.renderRow.bind(this)}
-          renderSectionHeader={this._renderSectionHeader}
-          keyboardShouldPersistTaps={true}
-          automaticallyAdjustContentInsets={false}
-          keyboardDismissMode="on-drag"
-        />
-      </View>
-    );
-  }
-
-  renderTextInput(searchTextInputStyle: any) {
-    return (
-      <View style={styles.searchRow}>
-        <TextInput
-          autoCapitalize="none"
-          autoCorrect={false}
-          clearButtonMode="always"
-          onChangeText={this.search.bind(this)}
-          placeholder="Search..."
-          style={[styles.searchTextInput, searchTextInputStyle]}
-          testID="explorer_search"
-          value={this.state.searchText}
-        />
-      </View>
-    );
-  }
-
-  _renderSectionHeader(data: any, section: string) {
-    return (
-      <Text style={styles.sectionHeader}>
-        {section.toUpperCase()}
-      </Text>
-    );
-  }
-
-  renderRow(example: any, i: number) {
-    return (
-      <View key={i}>
-        <TouchableHighlight onPress={() => this.onPressRow(example)}>
-          <View style={styles.row}>
-            <Text style={styles.rowTitleText}>
-              {example.title}
-            </Text>
-            <Text style={styles.rowDetailText}>
-              {example.description}
-            </Text>
-          </View>
-        </TouchableHighlight>
-        <View style={styles.separator} />
-      </View>
-    );
-  }
-
-  search(text: mixed): void {
-    this.props.search && this.props.search(text);
-
-    var regex = new RegExp(String(text), 'i');
-    var filter = (component) => regex.test(component.title);
-
-    this.setState({
-      dataSource: ds.cloneWithRowsAndSections({
-        components: this.props.components.filter(filter),
-        apis: this.props.apis.filter(filter),
-      }),
-      searchText: text,
-    });
-  }
-
-  onPressRow(example: any): void {
-    this.props.onPressRow && this.props.onPressRow(example);
-  }
-
-  static makeRenderable(example: any): ReactClass<any, any, any> {
-    return example.examples ?
-      createExamplePage(null, example) :
-      example;
-  }
-}
-
-var styles = StyleSheet.create({
-  listContainer: {
-    flex: 1,
-  },
-  list: {
-    backgroundColor: '#eeeeee',
-  },
-  sectionHeader: {
-    padding: 5,
-    fontWeight: '500',
-    fontSize: 11,
-  },
-  group: {
-    backgroundColor: 'white',
-  },
-  row: {
-    backgroundColor: 'white',
-    justifyContent: 'center',
-    paddingHorizontal: 15,
-    paddingVertical: 8,
-  },
-  separator: {
-    height: StyleSheet.hairlineWidth,
-    backgroundColor: '#bbbbbb',
-    marginLeft: 15,
-  },
-  rowTitleText: {
-    fontSize: 17,
-    fontWeight: '500',
-  },
-  rowDetailText: {
-    fontSize: 15,
-    color: '#888888',
-    lineHeight: 20,
-  },
-  searchRow: {
-    backgroundColor: '#eeeeee',
-    paddingTop: 75,
-    paddingLeft: 10,
-    paddingRight: 10,
-    paddingBottom: 10,
-  },
-  searchTextInput: {
-    backgroundColor: 'white',
-    borderColor: '#cccccc',
-    borderRadius: 3,
-    borderWidth: 1,
-    paddingLeft: 8,
-  },
-});
-
-module.exports = UIExplorerListBase;
diff --git a/Examples/UIExplorer/UIExplorerNavigationReducer.js b/Examples/UIExplorer/UIExplorerNavigationReducer.js
new file mode 100644
index 000000000000..e2e5ebede15a
--- /dev/null
+++ b/Examples/UIExplorer/UIExplorerNavigationReducer.js
@@ -0,0 +1,95 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ *
+ * @flow
+ */
+'use strict';
+
+const React = require('react-native');
+// $FlowFixMe : This is a platform-forked component, and flow seems to only run on iOS?
+const UIExplorerList = require('./UIExplorerList');
+const {
+  NavigationExperimental,
+} = React;
+const {
+  Reducer: NavigationReducer,
+} = NavigationExperimental;
+const StackReducer = NavigationReducer.StackReducer;
+
+import type {NavigationState} from 'NavigationStateUtils';
+
+import type {UIExplorerAction} from './UIExplorerActions';
+
+export type UIExplorerNavigationState = {
+  externalExample: ?string;
+  stack: NavigationState;
+};
+
+const UIExplorerStackReducer = StackReducer({
+  key: 'UIExplorerMainStack',
+  initialStates: [
+    {key: 'AppList'},
+  ],
+  initialIndex: 0,
+  matchAction: action => action.openExample && !!UIExplorerList.Modules[action.openExample],
+  actionStateMap: action => ({ key: action.openExample, }),
+});
+
+function UIExplorerNavigationReducer(lastState: ?UIExplorerNavigationState, action: any): UIExplorerNavigationState {
+  if (!lastState) {
+    return {
+      externalExample: null,
+      stack: UIExplorerStackReducer(null, action),
+    };
+  }
+  if (action.type === 'UIExplorerListWithFilterAction') {
+    return {
+      externalExample: null,
+      stack: {
+        key: 'UIExplorerMainStack',
+        index: 0,
+        children: [
+          {
+            key: 'AppList',
+            filter: action.filter,
+          },
+        ],
+      },
+    };
+  }
+  if (action.type === 'BackAction' && lastState.externalExample) {
+    return {
+      ...lastState,
+      externalExample: null,
+    };
+  }
+  if (action.type === 'UIExplorerExampleAction') {
+    const ExampleModule = UIExplorerList.Modules[action.openExample];
+    if (ExampleModule && ExampleModule.external) {
+      return {
+        ...lastState,
+        externalExample: action.openExample,
+      };
+    }
+  }
+  const newStack = UIExplorerStackReducer(lastState.stack, action);
+  if (newStack !== lastState.stack) {
+    return {
+      externalExample: null,
+      stack: UIExplorerStackReducer(null, action),      
+    }
+  }
+  return lastState;
+}
+
+module.exports = UIExplorerNavigationReducer;
diff --git a/Examples/UIExplorer/UIExplorerStateTitleMap.js b/Examples/UIExplorer/UIExplorerStateTitleMap.js
new file mode 100644
index 000000000000..137a7cac6fc5
--- /dev/null
+++ b/Examples/UIExplorer/UIExplorerStateTitleMap.js
@@ -0,0 +1,32 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ *
+ * @flow
+ */
+'use strict';
+
+const UIExplorerList = require('./UIExplorerList.ios');
+
+import type {NavigationState} from 'NavigationStateUtils';
+
+function StateTitleMap(state: NavigationState): string {
+  if (UIExplorerList.Modules[state.key]) {
+    return UIExplorerList.Modules[state.key].title
+  }
+  if (state.key === 'AppList') {
+    return 'UIExplorer';
+  }
+  return 'Unknown';
+}
+
+module.exports = StateTitleMap;
diff --git a/Libraries/NavigationExperimental/NavigationRootContainer.js b/Libraries/NavigationExperimental/NavigationRootContainer.js
index 685fd89c66a0..e04fe98e2fc2 100644
--- a/Libraries/NavigationExperimental/NavigationRootContainer.js
+++ b/Libraries/NavigationExperimental/NavigationRootContainer.js
@@ -17,6 +17,7 @@ const BackAndroid = require('BackAndroid');
 const Platform = require('Platform');
 
 import type {
+  NavigationAction,
   NavigationState,
   NavigationReducer
 } from 'NavigationStateUtils';
@@ -38,6 +39,7 @@ type Props = {
   renderNavigation: NavigationRenderer;
   reducer: NavigationReducer;
   persistenceKey: ?string;
+  initialAction: NavigationAction;
 };
 
 class NavigationRootContainer extends React.Component {
@@ -47,7 +49,7 @@ class NavigationRootContainer extends React.Component {
     this.handleNavigation = this.handleNavigation.bind(this);
     let navState = null;
     if (!this.props.persistenceKey) {
-      navState = this.props.reducer(null, null);
+      navState = this.props.reducer(null, props.initialAction);
     }
     this.state = { navState };
   }
@@ -56,7 +58,7 @@ class NavigationRootContainer extends React.Component {
       AsyncStorage.getItem(this.props.persistenceKey, (err, storedString) => {
         if (err || !storedString) {
           this.setState({
-            navState: this.props.reducer(null, null),
+            navState: this.props.reducer(null, this.props.initialAction),
           });
           return;
         }
@@ -97,6 +99,12 @@ NavigationRootContainer.childContextTypes = {
   onNavigate: React.PropTypes.func,
 };
 
+NavigationRootContainer.defaultProps = {
+  initialAction: {
+    type: 'NavigationRootContainerInitialAction',
+  },
+};
+
 NavigationRootContainer.getBackAction = getBackAction;
 
 module.exports = NavigationRootContainer;
diff --git a/Libraries/NavigationExperimental/NavigationStateUtils.js b/Libraries/NavigationExperimental/NavigationStateUtils.js
index fb5e2ac06f84..ba652ea878a3 100644
--- a/Libraries/NavigationExperimental/NavigationStateUtils.js
+++ b/Libraries/NavigationExperimental/NavigationStateUtils.js
@@ -30,11 +30,6 @@ export type NavigationAction = {
 export type NavigationReducer = (
   state: ?NavigationState,
   action: ?NavigationAction
-) => ?NavigationState;
-
-export type NavigationReducerWithDefault = (
-  state: ?NavigationState,
-  action: ?any
 ) => NavigationState;
 
 function getParent(state: NavigationState): ?NavigationParentState {
diff --git a/Libraries/NavigationExperimental/Reducer/NavigationFindReducer.js b/Libraries/NavigationExperimental/Reducer/NavigationFindReducer.js
index e59405f08442..bca336ee6358 100644
--- a/Libraries/NavigationExperimental/Reducer/NavigationFindReducer.js
+++ b/Libraries/NavigationExperimental/Reducer/NavigationFindReducer.js
@@ -22,16 +22,16 @@ import type {
   NavigationReducer
 } from 'NavigationStateUtils';
 
-function NavigationFindReducer(reducers: Array<NavigationReducer>): NavigationReducer {
-  return function(lastState: ?NavigationState, action: ?any): ?NavigationState {
+function NavigationFindReducer(reducers: Array<NavigationReducer>, defaultState: NavigationState): NavigationReducer {
+  return function(lastState: ?NavigationState, action: ?any): NavigationState {
     for (let i = 0; i < reducers.length; i++) {
       let reducer = reducers[i];
       let newState = reducer(lastState, action);
       if (newState !== lastState) {
-        return newState;
+        return newState || defaultState;
       }
     }
-    return lastState;
+    return lastState || defaultState;
   };
 }
 
diff --git a/Libraries/NavigationExperimental/Reducer/NavigationTabsReducer.js b/Libraries/NavigationExperimental/Reducer/NavigationTabsReducer.js
index d98a1d91d1c7..3f849300b680 100644
--- a/Libraries/NavigationExperimental/Reducer/NavigationTabsReducer.js
+++ b/Libraries/NavigationExperimental/Reducer/NavigationTabsReducer.js
@@ -16,14 +16,12 @@ const NavigationStateUtils = require('NavigationStateUtils');
 
 import type {
   NavigationReducer,
-  NavigationReducerWithDefault,
   NavigationState,
   NavigationParentState
 } from 'NavigationStateUtils';
 
 const ActionTypes = {
   JUMP_TO: 'react-native/NavigationExperimental/tabs-jumpTo',
-  ON_TAB_ACTION: 'react-native/NavigationExperimental/tabs-onTabAction',
 };
 
 const DEFAULT_KEY = 'TABS_STATE_DEFAULT_KEY';
@@ -39,37 +37,21 @@ function NavigationTabsJumpToAction(index: number): JumpToAction {
   };
 }
 
-export type OnTabAction = {
-  type: string,
-  index: number,
-  action: any,
-};
-function NavigationTabsOnTabAction(index: number, action: any): OnTabAction {
-  return {
-    type: ActionTypes.ON_TAB_ACTION,
-    index,
-    action,
-  };
-}
-
 type TabsReducerConfig = {
   key: string;
-  initialIndex: ?number;
-  tabReducers: Array<NavigationReducerWithDefault>;
+  initialIndex: number;
+  tabReducers: Array<NavigationReducer>;
 };
 
 function NavigationTabsReducer({key, initialIndex, tabReducers}: TabsReducerConfig): NavigationReducer {
-  if (initialIndex == null) {
-    initialIndex = 0;
-  }
   if (key == null) {
     key = DEFAULT_KEY;
   }
-  return function(lastNavState: ?NavigationState, action: ?any): ?NavigationState {
+  return function(lastNavState: ?NavigationState, action: ?any): NavigationState {
     if (!lastNavState) {
       lastNavState = {
         children: tabReducers.map(reducer => reducer(null, null)),
-        index: initialIndex,
+        index: initialIndex || 0,
         key,
       };
     }
@@ -86,37 +68,17 @@ function NavigationTabsReducer({key, initialIndex, tabReducers}: TabsReducerConf
         action.index,
       );
     }
-    if (action.type === ActionTypes.ON_TAB_ACTION) {
-      const onTabAction: OnTabAction = action;
-      const lastTabRoute = lastParentNavState.children[onTabAction.index];
-      const tabReducer = tabReducers[onTabAction.index];
-      if (tabReducer) {
-        const newTabRoute = tabReducer(lastTabRoute, action.action);
-        if (newTabRoute && newTabRoute !== lastTabRoute) {
-          let navState = NavigationStateUtils.replaceAtIndex(
-            lastParentNavState,
-            onTabAction.index,
-            newTabRoute
-          );
-          navState = NavigationStateUtils.jumpToIndex(
-            navState,
-            onTabAction.index
-          );
-          return navState;
-        }
-      }
-    }
     const subReducers = tabReducers.map((tabReducer, tabIndex) => {
-      return function reduceTab(lastNavState: ?NavigationState, tabAction: ?any): ?NavigationState {
-        if (!tabReducer || !lastNavState) {
-          return lastNavState;
+      return function(navState: ?NavigationState, tabAction: any): NavigationState {
+        if (!navState) {
+          return lastParentNavState;
         }
-        const lastParentNavState = NavigationStateUtils.getParent(lastNavState);
-        const lastSubTabState = lastParentNavState && lastParentNavState.children[tabIndex];
-        const nextSubTabState = tabReducer(lastSubTabState, tabAction);
-        if (nextSubTabState && lastSubTabState !== nextSubTabState) {
-          const tabs = lastParentNavState && lastParentNavState.children || [];
-          tabs[tabIndex] = nextSubTabState;
+        const parentState = NavigationStateUtils.getParent(navState);
+        const tabState = parentState && parentState.children[tabIndex];
+        const nextTabState = tabReducer(tabState, tabAction);
+        if (nextTabState && tabState !== nextTabState) {
+          const tabs = parentState && parentState.children || [];
+          tabs[tabIndex] = nextTabState;
           return {
             ...lastParentNavState,
             tabs,
@@ -128,8 +90,8 @@ function NavigationTabsReducer({key, initialIndex, tabReducers}: TabsReducerConf
     });
     let selectedTabReducer = subReducers.splice(lastParentNavState.index, 1)[0];
     subReducers.unshift(selectedTabReducer);
-    subReducers.push((lastParentNavState: ?NavigationState, action: ?any) => {
-      if (lastParentNavState && action && action.type === 'BackAction') {
+    subReducers.push(function(navState: ?NavigationState, action: any): NavigationState {
+      if (navState && action.type === 'BackAction') {
         return NavigationStateUtils.jumpToIndex(
           lastParentNavState,
           0
@@ -137,12 +99,11 @@ function NavigationTabsReducer({key, initialIndex, tabReducers}: TabsReducerConf
       }
       return lastParentNavState;
     });
-    const findReducer = NavigationFindReducer(subReducers);
+    const findReducer = NavigationFindReducer(subReducers, lastParentNavState);
     return findReducer(lastParentNavState, action);
   };
 }
 
 NavigationTabsReducer.JumpToAction = NavigationTabsJumpToAction;
-NavigationTabsReducer.OnTabAction = NavigationTabsOnTabAction;
 
 module.exports = NavigationTabsReducer;

From dcb68db758dfd8bdddeddf23c81a523a8506d7af Mon Sep 17 00:00:00 2001
From: Eric Vicenti <evv@fb.com>
Date: Mon, 22 Feb 2016 16:15:42 -0800
Subject: [PATCH 1261/1411] Add sub-reducer support to NavigationStackReducer

Summary: Revise APIs of reducers, and ensure the stack reducer can support sub-reducers

Reviewed By: javache

Differential Revision: D2959915

fb-gh-sync-id: 20b28b9ead7ace3373489a806486999048d32aef
shipit-source-id: 20b28b9ead7ace3373489a806486999048d32aef
---
 .../NavigationAnimatedExample.js              |  19 +-
 .../NavigationBasicExample.js                 |  25 +-
 .../NavigationCompositionExample.js           | 136 ++++++-----
 .../UIExplorer/UIExplorerNavigationReducer.js |  23 +-
 .../NavigationExperimental/NavigationCard.js  |   4 +-
 .../NavigationHeader.js                       |   4 +-
 .../NavigationStateUtils.js                   |  20 +-
 .../Reducer/NavigationStackReducer.js         | 141 ++++-------
 .../Reducer/NavigationTabsReducer.js          |  11 +-
 .../__tests__/NavigationStackReducer-test.js  | 231 ++++++------------
 10 files changed, 249 insertions(+), 365 deletions(-)

diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
index 7b343f08d748..a44d44c1e687 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
@@ -29,11 +29,20 @@ var {
 } = NavigationExperimental;
 
 const NavigationBasicReducer = NavigationReducer.StackReducer({
-  initialStates: [
-    {key: 'First Route'}
-  ],
-  matchAction: action => action.type === 'push',
-  actionStateMap: action => ({key: action.key}),
+  getPushedReducerForAction: (action) => {
+    if (action.type === 'push') {
+      return (state) => state || {key: action.key};
+    }
+    return null;
+  },
+  getReducerForState: (initialState) => (state) => state || initialState,
+  initialState: {
+    key: 'AnimatedExampleStackKey',
+    index: 0,
+    children: [
+      {key: 'First Route'},
+    ],
+  },
 });
 
 class NavigationAnimatedExample extends React.Component {
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationBasicExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationBasicExample.js
index 8f8669fb4c23..447ab2051fba 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationBasicExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationBasicExample.js
@@ -26,12 +26,21 @@ const {
 } = NavigationExperimental;
 const StackReducer = NavigationReducer.StackReducer;
 
-const NavigationBasicReducer = StackReducer({
-  initialStates: [
-    {key: 'first_page'}
-  ],
-  matchAction: action => true,
-  actionStateMap: action => ({key: action}),
+const NavigationBasicReducer = NavigationReducer.StackReducer({
+  getPushedReducerForAction: (action) => {
+    if (action.type === 'push') {
+      return (state) => state || {key: action.key};
+    }
+    return null;
+  },
+  getReducerForState: (initialState) => (state) => state || initialState,
+  initialState: {
+    key: 'BasicExampleStackKey',
+    index: 0,
+    children: [
+      {key: 'First Route'},
+    ],
+  },
 });
 
 const NavigationBasicExample = React.createClass({
@@ -51,13 +60,13 @@ const NavigationBasicExample = React.createClass({
               <NavigationExampleRow
                 text={`Push page #${navState.children.length}`}
                 onPress={() => {
-                  onNavigate('page #' + navState.children.length);
+                  onNavigate({ type: 'push', key: 'page #' + navState.children.length });
                 }}
               />
               <NavigationExampleRow
                 text="pop"
                 onPress={() => {
-                  onNavigate(StackReducer.PopAction());
+                  onNavigate(NavigationRootContainer.getBackAction());
                 }}
               />
               <NavigationExampleRow
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js
index ee8472242c4a..79e2e94b55ed 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js
@@ -10,7 +10,9 @@
  * FACEBOOK 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.
-*/
+ *
+ * @flow
+ */
 'use strict';
 
 const React = require('react-native');
@@ -32,6 +34,8 @@ const {
 const NavigationExampleRow = require('./NavigationExampleRow');
 const NavigationExampleTabBar = require('./NavigationExampleTabBar');
 
+import type {NavigationParentState} from 'NavigationStateUtils';
+
 const ExampleExitAction = () => ({
   isExitAction: true,
 });
@@ -39,25 +43,25 @@ ExampleExitAction.match = (action) => (
   action && action.isExitAction === true
 );
 
-const ExamplePageAction = (type) => ({
+const PageAction = (type) => ({
   type,
   isPageAction: true,
 });
-ExamplePageAction.match = (action) => (
+PageAction.match = (action) => (
   action && action.isPageAction === true
 );
 
-const ExampleSettingsPageAction = (type) => ({
-  ...ExamplePageAction(type),
-  isSettingsPageAction: true,
+const ExampleProfilePageAction = (type) => ({
+  ...PageAction(type),
+  isProfilePageAction: true,
 });
-ExampleSettingsPageAction.match = (action) => (
-  action && action.isSettingsPageAction === true
+ExampleProfilePageAction.match = (action) => (
+  action && action.isProfilePageAction === true
 );
 
-const ExampleInfoAction = () => ExamplePageAction('InfoPage');
+const ExampleInfoAction = () => PageAction('InfoPage');
 
-const ExampleNotifSettingsAction = () => ExampleSettingsPageAction('NotifSettingsPage');
+const ExampleNotifProfileAction = () => ExampleProfilePageAction('NotifProfilePage');
 
 const _jsInstanceUniqueId = '' + Date.now();
 let _uniqueIdCount = 0;
@@ -68,70 +72,70 @@ function pageStateActionMap(action) {
   };
 }
 
-function getTabActionMatcher(key) {
-  return function (action) {
-    if (!ExamplePageAction.match(action)) {
-      return false;
-    }
-    if (ExampleSettingsPageAction.match(action)) {
-      return key === 'settings';
-    }
-    return true;
-  };
-}
-
-var ExampleTabs = [
-  {
-    label: 'Account',
-    reducer: NavigationReducer.StackReducer({
-      initialStates: [
-        {type: 'AccountPage', key: 'base'}
-      ],
-      key: 'account',
-      matchAction: getTabActionMatcher('account'),
-      actionStateMap: pageStateActionMap,
+const ExampleAppReducer = NavigationReducer.TabsReducer({
+  key: 'AppNavigationState',
+  initialIndex: 0,
+  tabReducers: [
+    NavigationReducer.StackReducer({
+      getPushedReducerForAction: (action) => {
+        if (PageAction.match(action) && !ExampleProfilePageAction.match(action)) {
+          return (state) => (state || pageStateActionMap(action));
+        }
+        return null;
+      },
+      initialState: {
+        key: 'notifs',
+        index: 0,
+        children: [
+          {key: 'base', type: 'NotifsPage'},
+        ],
+      },
     }),
-  },
-  {
-    label: 'Notifications',
-    reducer: NavigationReducer.StackReducer({
-      initialStates: [
-        {type: 'NotifsPage', key: 'base'}
-      ],
-      key: 'notifs',
-      matchAction: getTabActionMatcher('notifs'),
-      actionStateMap: pageStateActionMap,
+    NavigationReducer.StackReducer({
+      getPushedReducerForAction: (action) => {
+        if (PageAction.match(action) && !ExampleProfilePageAction.match(action)) {
+          return (state) => (state || pageStateActionMap(action));
+        }
+        return null;
+      },
+      initialState: {
+        key: 'settings',
+        index: 0,
+        children: [
+          {key: 'base', type: 'SettingsPage'},
+        ],
+      },
     }),
-  },
-  {
-    label: 'Settings',
-    reducer: NavigationReducer.StackReducer({
-      initialStates: [
-        {type: 'SettingsPage', key: 'base'}
-      ],
-      key: 'settings',
-      matchAction: getTabActionMatcher('settings'),
-      actionStateMap: pageStateActionMap,
+    NavigationReducer.StackReducer({
+      getPushedReducerForAction: (action) => {
+        if (PageAction.match(action) || ExampleProfilePageAction.match(action)) {
+          return (state) => (state || pageStateActionMap(action));
+        }
+        return null;
+      },
+      initialState: {
+        key: 'profile',
+        index: 0,
+        children: [
+          {key: 'base', type: 'ProfilePage'},
+        ],
+      },
     }),
-  },
-];
-
-const ExampleAppReducer = NavigationReducer.TabsReducer({
-  tabReducers: ExampleTabs.map(tab => tab.reducer),
+  ],
 });
 
 function stateTypeTitleMap(pageState) {
   switch (pageState.type) {
-    case 'AccountPage':
-      return 'Account Page';
+    case 'ProfilePage':
+      return 'Profile Page';
     case 'NotifsPage':
       return 'Notifications';
     case 'SettingsPage':
       return 'Settings';
     case 'InfoPage':
       return 'Info Page';
-    case 'NotifSettingsPage':
-      return 'Notification Settings';
+    case 'NotifProfilePage':
+      return 'Page in Profile';
   }
 }
 
@@ -173,9 +177,9 @@ class ExampleTabScreen extends React.Component {
             }}
           />
           <NavigationExampleRow
-            text="Open notifs settings in settings tab"
+            text="Open a page in the profile tab"
             onPress={() => {
-              this.props.onNavigate(ExampleNotifSettingsAction());
+              this.props.onNavigate(ExampleNotifProfileAction());
             }}
           />
           <NavigationExampleRow
@@ -196,19 +200,19 @@ class NavigationCompositionExample extends React.Component {
     return (
       <NavigationRootContainer
         reducer={ExampleAppReducer}
-        persistenceKey="NavigationCompositionExampleState"
+        persistenceKey="NavigationCompositionState"
         ref={navRootContainer => { this.navRootContainer = navRootContainer; }}
         renderNavigation={this.renderApp.bind(this)}
       />
     );
   }
-  handleBackAction() {
+  handleBackAction(): boolean {
     return (
       this.navRootContainer &&
       this.navRootContainer.handleNavigation(NavigationRootContainer.getBackAction())
     );
   }
-  renderApp(navigationState, onNavigate) {
+  renderApp(navigationState: NavigationParentState, onNavigate: Function) {
     if (!navigationState) {
       return null;
     }
diff --git a/Examples/UIExplorer/UIExplorerNavigationReducer.js b/Examples/UIExplorer/UIExplorerNavigationReducer.js
index e2e5ebede15a..3dee22c2c2eb 100644
--- a/Examples/UIExplorer/UIExplorerNavigationReducer.js
+++ b/Examples/UIExplorer/UIExplorerNavigationReducer.js
@@ -36,13 +36,20 @@ export type UIExplorerNavigationState = {
 };
 
 const UIExplorerStackReducer = StackReducer({
-  key: 'UIExplorerMainStack',
-  initialStates: [
-    {key: 'AppList'},
-  ],
-  initialIndex: 0,
-  matchAction: action => action.openExample && !!UIExplorerList.Modules[action.openExample],
-  actionStateMap: action => ({ key: action.openExample, }),
+  getPushedReducerForAction: (action) => {
+    if (action.type === 'UIExplorerExampleAction' && UIExplorerList.Modules[action.openExample]) {
+      return (state) => state || {key: action.openExample};
+    }
+    return null;
+  },
+  getReducerForState: (initialState) => (state) => state || initialState,
+  initialState: {
+    key: 'UIExplorerMainStack',
+    index: 0,
+    children: [
+      {key: 'AppList'},
+    ],
+  },
 });
 
 function UIExplorerNavigationReducer(lastState: ?UIExplorerNavigationState, action: any): UIExplorerNavigationState {
@@ -86,7 +93,7 @@ function UIExplorerNavigationReducer(lastState: ?UIExplorerNavigationState, acti
   if (newStack !== lastState.stack) {
     return {
       externalExample: null,
-      stack: UIExplorerStackReducer(null, action),      
+      stack: newStack,      
     }
   }
   return lastState;
diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationCard.js b/Libraries/CustomComponents/NavigationExperimental/NavigationCard.js
index 8907a6e008f1..7021e73abcce 100644
--- a/Libraries/CustomComponents/NavigationExperimental/NavigationCard.js
+++ b/Libraries/CustomComponents/NavigationExperimental/NavigationCard.js
@@ -28,7 +28,7 @@
 'use strict';
 
 const Animated = require('Animated');
-const NavigationReducer = require('NavigationReducer');
+const NavigationRootContainer = require('NavigationRootContainer');
 const NavigationContainer = require('NavigationContainer');
 const PanResponder = require('PanResponder');
 const Platform = require('Platform');
@@ -95,7 +95,7 @@ class NavigationCard extends React.Component {
         const doesPop = (xRatio + vx) > 0.45;
         if (doesPop) {
           // todo: add an action which accepts velocity of the pop action/gesture, which is caught and used by NavigationAnimatedView
-          this.props.onNavigate(NavigationReducer.StackReducer.PopAction());
+          this.props.onNavigate(NavigationRootContainer.getBackAction());
           return;
         }
         Animated.spring(this.props.position, {
diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationHeader.js b/Libraries/CustomComponents/NavigationExperimental/NavigationHeader.js
index 0be15d1894ea..82a807e2f27d 100644
--- a/Libraries/CustomComponents/NavigationExperimental/NavigationHeader.js
+++ b/Libraries/CustomComponents/NavigationExperimental/NavigationHeader.js
@@ -30,7 +30,7 @@
 const Animated = require('Animated');
 const Image = require('Image');
 const NavigationContainer = require('NavigationContainer');
-const NavigationReducer = require('NavigationReducer');
+const NavigationRootContainer = require('NavigationRootContainer');
 const React = require('react-native');
 const StyleSheet = require('StyleSheet');
 const Text = require('Text');
@@ -103,7 +103,7 @@ class NavigationHeader extends React.Component {
     );
   }
   _handleBackPress() {
-    this.props.onNavigate(NavigationReducer.StackReducer.PopAction());
+    this.props.onNavigate(NavigationRootContainer.getBackAction());
   }
 }
 
diff --git a/Libraries/NavigationExperimental/NavigationStateUtils.js b/Libraries/NavigationExperimental/NavigationStateUtils.js
index ba652ea878a3..c9d10ddfbb21 100644
--- a/Libraries/NavigationExperimental/NavigationStateUtils.js
+++ b/Libraries/NavigationExperimental/NavigationStateUtils.js
@@ -66,14 +66,10 @@ function indexOf(state: NavigationState, key: string): ?number {
   return index;
 }
 
-function push(state: NavigationState, newChildState: NavigationState): NavigationState {
-  const parentState = getParent(state);
-  if (!parentState) {
-    return state;
-  }
-  var lastChildren: Array<NavigationState> = parentState.children;
+function push(state: NavigationParentState, newChildState: NavigationState): NavigationParentState {
+  var lastChildren: Array<NavigationState> = state.children;
   return {
-    ...parentState,
+    ...state,
     children: [
       ...lastChildren,
       newChildState,
@@ -82,14 +78,10 @@ function push(state: NavigationState, newChildState: NavigationState): Navigatio
   };
 }
 
-function pop(state: NavigationState): NavigationState {
-  const parentState = getParent(state);
-  if (!parentState) {
-    return state;
-  }
-  const lastChildren = parentState.children;
+function pop(state: NavigationParentState): NavigationParentState {
+  const lastChildren = state.children;
   return {
-    ...parentState,
+    ...state,
     children: lastChildren.slice(0, lastChildren.length - 1),
     index: lastChildren.length - 2,
   };
diff --git a/Libraries/NavigationExperimental/Reducer/NavigationStackReducer.js b/Libraries/NavigationExperimental/Reducer/NavigationStackReducer.js
index 624d822e6513..89d96da097b0 100644
--- a/Libraries/NavigationExperimental/Reducer/NavigationStackReducer.js
+++ b/Libraries/NavigationExperimental/Reducer/NavigationStackReducer.js
@@ -15,6 +15,7 @@ var NavigationStateUtils = require('NavigationStateUtils');
 
 import type {
   NavigationState,
+  NavigationParentState,
   NavigationReducer,
 } from 'NavigationStateUtils';
 
@@ -26,121 +27,81 @@ export type NavigationStackReducerAction = BackAction | {
   type: string,
 };
 
-const ActionTypes = {
-  PUSH: 'react-native/NavigationExperimental/stack-push',
-  POP: 'react-native/NavigationExperimental/stack-pop',
-  JUMP_TO: 'react-native/NavigationExperimental/stack-jumpTo',
-  JUMP_TO_INDEX: 'react-native/NavigationExperimental/stack-jumpToIndex',
-  RESET: 'react-native/NavigationExperimental/stack-reset',
-};
-
-const DEFAULT_KEY = 'NAV_STACK_DEFAULT_KEY';
-
-function NavigationStackPushAction(state: NavigationState): NavigationStackReducerAction {
-  return {
-    type: ActionTypes.PUSH,
-    state,
-  };
-}
+export type ReducerForStateHandler = (state: NavigationState) => NavigationReducer;
 
-function NavigationStackPopAction(): NavigationStackReducerAction {
-  return {
-    type: ActionTypes.POP,
-  };
-}
+export type PushedReducerForActionHandler = (action: any) => ?NavigationReducer;
 
-function NavigationStackJumpToAction(key: string): NavigationStackReducerAction {
-  return {
-    type: ActionTypes.JUMP_TO,
-    key,
-  };
-}
+export type StackReducerConfig = {
+  /*
+   * The initialState is that the reducer will use when there is no previous state.
+   * Must be a NavigationParentState:
+   *
+   * {
+   *   children: [
+   *     {key: 'subState0'},
+   *     {key: 'subState1'},
+   *   ],
+   *   index: 0,
+   *   key: 'navStackKey'
+   * }
+   */
+  initialState: NavigationParentState;
 
-function NavigationStackJumpToIndexAction(index: number): NavigationStackReducerAction {
-  return {
-    type: ActionTypes.JUMP_TO_INDEX,
-    index,
-  };
-}
+  /*
+   * Returns the sub-reducer for a particular state to handle. This will be called
+   * when we need to handle an action on a sub-state. If no reducer is returned,
+   * no action will be taken
+   */
+  getReducerForState?: ReducerForStateHandler;
 
-function NavigationStackResetAction(children: Array<NavigationState>, index: number): NavigationStackReducerAction {
-  return {
-    type: ActionTypes.RESET,
-    index,
-    children,
-  };
-}
-
-type StackReducerConfig = {
-  initialStates: Array<NavigationState>;
-  initialIndex: ?number;
-  key: ?string;
-  matchAction: (action: any) => boolean;
-  actionStateMap: (action: any) => NavigationState;
+  /*
+   * Returns a sub-reducer that will be used when pushing a new route. If a reducer
+   * is returned, it be called to get the new state that will be pushed
+   */
+  getPushedReducerForAction: PushedReducerForActionHandler;
 };
 
-function NavigationStackReducer({initialStates, initialIndex, key, matchAction, actionStateMap}: StackReducerConfig): NavigationReducer {
+const defaultGetReducerForState = (initialState) => (state) => state || initialState;
+
+function NavigationStackReducer({initialState, getReducerForState, getPushedReducerForAction}: StackReducerConfig): NavigationReducer {
+  const getReducerForStateWithDefault = getReducerForState || defaultGetReducerForState;
   return function (lastState: ?NavigationState, action: any): NavigationState {
-    if (key == null) {
-      key = DEFAULT_KEY;
-    }
-    if (initialIndex == null) {
-      initialIndex = initialStates.length - 1;
-    }
     if (!lastState) {
-      lastState = {
-        index: initialIndex,
-        children: initialStates,
-        key,
-      };
+      return initialState;
     }
     const lastParentState = NavigationStateUtils.getParent(lastState);
-    if (!action || !lastParentState) {
+    if (!lastParentState) {
       return lastState;
     }
     switch (action.type) {
-      case ActionTypes.PUSH:
-        return NavigationStateUtils.push(
-          lastParentState,
-          action.state
-        );
-      case ActionTypes.POP:
       case 'BackAction':
         if (lastParentState.index === 0 || lastParentState.children.length === 1) {
           return lastParentState;
         }
         return NavigationStateUtils.pop(lastParentState);
-      case ActionTypes.JUMP_TO:
-        return NavigationStateUtils.jumpTo(
-          lastParentState,
-          action.key
-        );
-      case ActionTypes.JUMP_TO_INDEX:
-        return NavigationStateUtils.jumpToIndex(
-          lastParentState,
-          action.index
-        );
-      case ActionTypes.RESET:
-        return {
-          ...lastParentState,
-          index: action.index,
-          children: action.children,
-        };
     }
-    if (matchAction(action)) {
+
+    const activeSubState = lastParentState.children[lastParentState.index];
+    const activeSubReducer = getReducerForStateWithDefault(activeSubState);
+    const nextActiveState = activeSubReducer(activeSubState, action);
+    if (nextActiveState !== activeSubState) {
+      const nextChildren = [...lastParentState.children];
+      nextChildren[lastParentState.index] = nextActiveState;
+      return {
+        ...lastParentState,
+        children: nextChildren,
+      };
+    }
+
+    const subReducerToPush = getPushedReducerForAction(action);
+    if (subReducerToPush) {
       return NavigationStateUtils.push(
         lastParentState,
-        actionStateMap(action)
+        subReducerToPush(null, action)
       );
     }
     return lastParentState;
   };
 }
 
-NavigationStackReducer.PushAction = NavigationStackPushAction;
-NavigationStackReducer.PopAction = NavigationStackPopAction;
-NavigationStackReducer.JumpToAction = NavigationStackJumpToAction;
-NavigationStackReducer.JumpToIndexAction = NavigationStackJumpToIndexAction;
-NavigationStackReducer.ResetAction = NavigationStackResetAction;
-
 module.exports = NavigationStackReducer;
diff --git a/Libraries/NavigationExperimental/Reducer/NavigationTabsReducer.js b/Libraries/NavigationExperimental/Reducer/NavigationTabsReducer.js
index 3f849300b680..eaf9ef83b2b2 100644
--- a/Libraries/NavigationExperimental/Reducer/NavigationTabsReducer.js
+++ b/Libraries/NavigationExperimental/Reducer/NavigationTabsReducer.js
@@ -24,8 +24,6 @@ const ActionTypes = {
   JUMP_TO: 'react-native/NavigationExperimental/tabs-jumpTo',
 };
 
-const DEFAULT_KEY = 'TABS_STATE_DEFAULT_KEY';
-
 export type JumpToAction = {
   type: typeof ActionTypes.JUMP_TO,
   index: number,
@@ -44,9 +42,6 @@ type TabsReducerConfig = {
 };
 
 function NavigationTabsReducer({key, initialIndex, tabReducers}: TabsReducerConfig): NavigationReducer {
-  if (key == null) {
-    key = DEFAULT_KEY;
-  }
   return function(lastNavState: ?NavigationState, action: ?any): NavigationState {
     if (!lastNavState) {
       lastNavState = {
@@ -89,16 +84,16 @@ function NavigationTabsReducer({key, initialIndex, tabReducers}: TabsReducerConf
       };
     });
     let selectedTabReducer = subReducers.splice(lastParentNavState.index, 1)[0];
-    subReducers.unshift(selectedTabReducer);
-    subReducers.push(function(navState: ?NavigationState, action: any): NavigationState {
+    subReducers.unshift(function(navState: ?NavigationState, action: any): NavigationState {
       if (navState && action.type === 'BackAction') {
         return NavigationStateUtils.jumpToIndex(
           lastParentNavState,
-          0
+          initialIndex || 0
         );
       }
       return lastParentNavState;
     });
+    subReducers.unshift(selectedTabReducer);
     const findReducer = NavigationFindReducer(subReducers, lastParentNavState);
     return findReducer(lastParentNavState, action);
   };
diff --git a/Libraries/NavigationExperimental/Reducer/__tests__/NavigationStackReducer-test.js b/Libraries/NavigationExperimental/Reducer/__tests__/NavigationStackReducer-test.js
index 4d497346cfeb..400057ab04a2 100644
--- a/Libraries/NavigationExperimental/Reducer/__tests__/NavigationStackReducer-test.js
+++ b/Libraries/NavigationExperimental/Reducer/__tests__/NavigationStackReducer-test.js
@@ -15,183 +15,90 @@ jest
  .mock('ErrorUtils');
 
 const NavigationStackReducer = require('NavigationStackReducer');
-
-const {
-  JumpToAction,
-  JumpToIndexAction,
-  PopAction,
-  PushAction,
-  ResetAction,
-} = NavigationStackReducer;
+const NavigationRootContainer = require('NavigationRootContainer');
 
 describe('NavigationStackReducer', () => {
 
-  it('handles PushAction', () => {
-    const initialStates = [
-      {key: 'route0'},
-      {key: 'route1'},
-    ];
-    let reducer = NavigationStackReducer({
-      initialStates,
-      matchAction: () => true,
-      actionStateMap: (action) => action,
-    });
-
-    let state = reducer();
-    expect(state.children).toBe(initialStates);
-    expect(state.index).toBe(1);
-    expect(state.key).toBe('NAV_STACK_DEFAULT_KEY');
-
-    state = reducer(state, PushAction({key: 'route2'}));
-    expect(state.children[0].key).toBe('route0');
-    expect(state.children[1].key).toBe('route1');
-    expect(state.children[2].key).toBe('route2');
-    expect(state.index).toBe(2);
-  });
-
-  it('handles PopAction', () => {
-    let reducer = NavigationStackReducer({
-      initialStates: [
+  it('provides default/initial state', () => {
+    const initialState = {
+      children: [
         {key: 'a'},
-        {key: 'b'},
       ],
-      initialIndex: 1,
+      index: 0,
       key: 'myStack',
-      matchAction: () => true,
-      actionStateMap: (action) => action,
+    };
+    const reducer = NavigationStackReducer({
+      getPushedReducerForAction: (action) => null,
+      getReducerForState: (state) => () => state,
+      initialState,
     });
-
-    let state = reducer();
-    expect(state.children[0].key).toBe('a');
-    expect(state.children[1].key).toBe('b');
-    expect(state.children.length).toBe(2);
-    expect(state.index).toBe(1);
-    expect(state.key).toBe('myStack');
-
-    state = reducer(state, PopAction());
-    expect(state.children[0].key).toBe('a');
-    expect(state.children.length).toBe(1);
-    expect(state.index).toBe(0);
-    expect(state.key).toBe('myStack');
-
-    // make sure Pop on an single-route state is a no-op
-    state = reducer(state, PopAction());
-    expect(state.children[0].key).toBe('a');
-    expect(state.children.length).toBe(1);
-    expect(state.index).toBe(0);
-    expect(state.key).toBe('myStack');
+    const dummyAction = {type: 'dummyAction'};
+    expect(reducer(null, dummyAction)).toBe(initialState);
   });
 
-  it('handles JumpToAction', () => {
-    let reducer = NavigationStackReducer({
-      initialStates: [
-        {key: 'a'},
-        {key: 'b'},
-        {key: 'c'},
-      ],
-      initialIndex: 0,
-      key: 'myStack',
-      matchAction: () => true,
-      actionStateMap: (action) => action,
+  it('handles basic reducer pushing', () => {
+    const reducer = NavigationStackReducer({
+      getPushedReducerForAction: (action) => {
+        if (action.type === 'TestPushAction') {
+          return (state) => state || {key: action.testValue};
+        }
+        return null;
+      },
+      getReducerForState: (state) => () => state,
+      initialState: {
+        children: [
+          {key: 'first'},
+        ],
+        index: 0,
+        key: 'myStack'
+      }
     });
-
-    let state = reducer();
-    expect(state.children[0].key).toBe('a');
-    expect(state.children[1].key).toBe('b');
-    expect(state.children[2].key).toBe('c');
-    expect(state.children.length).toBe(3);
-    expect(state.index).toBe(0);
-
-    state = reducer(state, JumpToAction('b'));
-    expect(state.children[0].key).toBe('a');
-    expect(state.children[1].key).toBe('b');
-    expect(state.children[2].key).toBe('c');
-    expect(state.children.length).toBe(3);
-    expect(state.index).toBe(1);
-
-    state = reducer(state, JumpToAction('c'));
-    expect(state.children[0].key).toBe('a');
-    expect(state.children[1].key).toBe('b');
-    expect(state.children[2].key).toBe('c');
-    expect(state.children.length).toBe(3);
-    expect(state.index).toBe(2);
-
-    state = reducer(state, JumpToAction('c'));
-    expect(state.children[0].key).toBe('a');
-    expect(state.children[1].key).toBe('b');
-    expect(state.children[2].key).toBe('c');
-    expect(state.children.length).toBe(3);
-    expect(state.index).toBe(2);
-    expect(state.key).toBe('myStack');
-  });
-
-  it('handles JumpToIndexAction', () => {
-    let reducer = NavigationStackReducer({
-      initialStates: [
-        {key: 'a'},
-        {key: 'b'},
-        {key: 'c'},
-      ],
-      initialIndex: 2,
-      key: 'myStack',
-      matchAction: () => true,
-      actionStateMap: (action) => action,
-    });
-
-    let state = reducer();
-    expect(state.children.length).toBe(3);
-    expect(state.index).toBe(2);
-
-    state = reducer(state, JumpToIndexAction(0));
-    expect(state.children.length).toBe(3);
-    expect(state.index).toBe(0);
-
-    state = reducer(state, JumpToIndexAction(1));
-    expect(state.children[0].key).toBe('a');
-    expect(state.children[1].key).toBe('b');
-    expect(state.children[2].key).toBe('c');
-    expect(state.children.length).toBe(3);
-    expect(state.index).toBe(1);
-    expect(state.key).toBe('myStack');
+    const state1 = reducer(null, {type: 'default'});
+    expect(state1.children.length).toBe(1);
+    expect(state1.children[0].key).toBe('first');
+    expect(state1.index).toBe(0);
+
+    const action = {type: 'TestPushAction', testValue: 'second'};
+    const state2 = reducer(state1, action);
+    expect(state2.children.length).toBe(2);
+    expect(state2.children[0].key).toBe('first');
+    expect(state2.children[1].key).toBe('second');
+    expect(state2.index).toBe(1);
   });
 
-  it('handles ResetAction', () => {
-    let reducer = NavigationStackReducer({
-      initialStates: [
-        {key: 'a'},
-        {key: 'b'},
-      ],
-      initialIndex: 1,
-      key: 'myStack',
-      matchAction: () => true,
-      actionStateMap: (action) => action,
+  it('handles BackAction', () => {
+    const reducer = NavigationStackReducer({
+      getPushedReducerForAction: (action) => {
+        if (action.type === 'TestPushAction') {
+          return (state) => state || {key: action.testValue};
+        }
+        return null;
+      },
+      getReducerForState: (state) => () => state,
+      initialState: {
+        children: [
+          {key: 'a'},
+          {key: 'b'},
+        ],
+        index: 1,
+        key: 'myStack',
+      },
     });
 
-    let state = reducer();
-    expect(state.children[0].key).toBe('a');
-    expect(state.children[1].key).toBe('b');
-    expect(state.children.length).toBe(2);
-    expect(state.index).toBe(1);
-
-    state = reducer(state, ResetAction([{key: 'c'}, {key: 'd'}], 0));
-    expect(state.children[0].key).toBe('c');
-    expect(state.children[1].key).toBe('d');
-    expect(state.children.length).toBe(2);
-    expect(state.index).toBe(0);
+    const state1 = reducer(null, {type: 'MyDefaultAction'});
+    expect(state1.children[0].key).toBe('a');
+    expect(state1.children[1].key).toBe('b');
+    expect(state1.children.length).toBe(2);
+    expect(state1.index).toBe(1);
+    expect(state1.key).toBe('myStack');
 
-    const newStates = [
-      {key: 'e'},
-      {key: 'f'},
-      {key: 'g'},
-    ];
+    const state2 = reducer(state1, NavigationRootContainer.getBackAction());
+    expect(state2.children[0].key).toBe('a');
+    expect(state2.children.length).toBe(1);
+    expect(state2.index).toBe(0);
 
-    state = reducer(state, ResetAction(newStates, 1));
-    expect(state.children[0].key).toBe('e');
-    expect(state.children[1].key).toBe('f');
-    expect(state.children[2].key).toBe('g');
-    expect(state.children.length).toBe(3);
-    expect(state.index).toBe(1);
-    expect(state.key).toBe('myStack');
+    const state3 = reducer(state2, NavigationRootContainer.getBackAction());
+    expect(state3).toBe(state2);
   });
 
-});
+});
\ No newline at end of file

From 19f81be9b480b4662067e44bd75f023c5ecebc0b Mon Sep 17 00:00:00 2001
From: Eric Vicenti <evv@fb.com>
Date: Mon, 22 Feb 2016 16:15:43 -0800
Subject: [PATCH 1262/1411] NavigationAnimatedView configurable navigation
 timing

Summary:Add setTiming prop for custom timing configuration

Also improve the current timing of the navigation animation to look more natural and less springy

Reviewed By: javache

Differential Revision: D2938500

fb-gh-sync-id: 3e6c6dd6077ff9d6a343f760f7b762096ce76600
shipit-source-id: 3e6c6dd6077ff9d6a343f760f7b762096ce76600
---
 .../NavigationAnimatedExample.js              |  4 +++
 Examples/UIExplorer/UIExplorerApp.ios.js      |  1 +
 .../NavigationAnimatedView.js                 | 30 +++++++++++++++----
 3 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
index a44d44c1e687..3054a8a976e4 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
@@ -15,6 +15,7 @@
 
 var React = require('react-native');
 var {
+  Animated,
   NavigationExperimental,
   StyleSheet,
   ScrollView,
@@ -80,6 +81,9 @@ class NavigationAnimatedExample extends React.Component {
             getTitle={state => state.key}
           />
         )}
+        setTiming={(pos, navState) => {
+          Animated.timing(pos, {toValue: navState.index, duration: 1000}).start();
+        }}
         renderScene={(state, index, position, layout) => (
           <NavigationCard
             key={state.key}
diff --git a/Examples/UIExplorer/UIExplorerApp.ios.js b/Examples/UIExplorer/UIExplorerApp.ios.js
index f9dfe5c87782..99d08978f895 100644
--- a/Examples/UIExplorer/UIExplorerApp.ios.js
+++ b/Examples/UIExplorer/UIExplorerApp.ios.js
@@ -24,6 +24,7 @@ const UIExplorerNavigationReducer = require('./UIExplorerNavigationReducer');
 const UIExplorerStateTitleMap = require('./UIExplorerStateTitleMap');
 
 const {
+  Animated,
   AppRegistry,
   NavigationExperimental,
   SnapshotViewIOS,
diff --git a/Libraries/NavigationExperimental/NavigationAnimatedView.js b/Libraries/NavigationExperimental/NavigationAnimatedView.js
index 76fcd79604e2..8b24286df356 100644
--- a/Libraries/NavigationExperimental/NavigationAnimatedView.js
+++ b/Libraries/NavigationExperimental/NavigationAnimatedView.js
@@ -80,13 +80,20 @@ type SceneRenderer = (
   index: number,
   position: Animated.Value,
   layout: Layout
-) => ReactElement
+) => ReactElement;
+
+type TimingSetter = (
+  position: Animated.Value,
+  newState: NavigationParentState,
+  lastState: NavigationParentState
+) => void;
 
 type Props = {
   navigationState: NavigationParentState;
   renderScene: SceneRenderer;
   renderOverlay: ?OverlayRenderer;
   style: any;
+  setTiming: ?TimingSetter;
 };
 
 class NavigationAnimatedView extends React.Component {
@@ -120,11 +127,8 @@ class NavigationAnimatedView extends React.Component {
     }
   }
   componentDidUpdate(lastProps) {
-    if (lastProps.navigationState.index !== this.props.navigationState.index) {
-      Animated.spring(
-        this.state.position,
-        {toValue: this.props.navigationState.index}
-      ).start();
+    if (lastProps.navigationState.index !== this.props.navigationState.index && this.props.setTiming) {
+      this.props.setTiming(this.state.position, this.props.navigationState, lastProps.navigationState);
     }
   }
   componentWillUnmount() {
@@ -220,6 +224,20 @@ class NavigationAnimatedView extends React.Component {
   }
 }
 
+function setDefaultTiming(position, navigationState) {
+  Animated.spring(
+    position,
+    {
+      bounciness: 0,
+      toValue: navigationState.index,
+    }
+  ).start();
+}
+
+NavigationAnimatedView.defaultProps = {
+  setTiming: setDefaultTiming,
+};
+
 NavigationAnimatedView = NavigationContainer.create(NavigationAnimatedView);
 
 module.exports = NavigationAnimatedView;

From e0019f69c189c61d78fde00d62b98178c0082cee Mon Sep 17 00:00:00 2001
From: Eric Vicenti <evv@fb.com>
Date: Mon, 22 Feb 2016 16:15:44 -0800
Subject: [PATCH 1263/1411] App linking for UIExplorer iOS

Summary: Add a simple URL parser to add linking support for UIExplorer iOS. Android should be very similar

Reviewed By: javache

Differential Revision: D2931764

fb-gh-sync-id: 0b029106160620267b82bdba510635ce224c5381
shipit-source-id: 0b029106160620267b82bdba510635ce224c5381
---
 .../UIExplorer.xcodeproj/project.pbxproj      |  2 +-
 Examples/UIExplorer/UIExplorer/AppDelegate.m  |  9 ++++
 Examples/UIExplorer/UIExplorer/Info.plist     | 24 ++++++---
 Examples/UIExplorer/UIExplorerApp.ios.js      | 32 ++++++++++++
 .../NavigationAnimatedView.js                 |  2 +-
 .../NavigationRootContainer.js                | 49 ++++++++++++++++++-
 6 files changed, 109 insertions(+), 9 deletions(-)

diff --git a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
index e6dfc36585b7..b2608f0fc465 100644
--- a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
+++ b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
@@ -1276,4 +1276,4 @@
 /* End XCConfigurationList section */
 	};
 	rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
-}
+}
\ No newline at end of file
diff --git a/Examples/UIExplorer/UIExplorer/AppDelegate.m b/Examples/UIExplorer/UIExplorer/AppDelegate.m
index 577e6dd94b5d..b0d19a59c170 100644
--- a/Examples/UIExplorer/UIExplorer/AppDelegate.m
+++ b/Examples/UIExplorer/UIExplorer/AppDelegate.m
@@ -16,6 +16,7 @@
 
 #import "RCTBridge.h"
 #import "RCTJavaScriptLoader.h"
+#import "RCTLinkingManager.h"
 #import "RCTRootView.h"
 
 @interface AppDelegate() <RCTBridgeDelegate>
@@ -80,6 +81,14 @@ - (NSURL *)sourceURLForBridge:(__unused RCTBridge *)bridge
   return sourceURL;
 }
 
+
+- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
+  sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
+{
+  return [RCTLinkingManager application:application openURL:url
+                      sourceApplication:sourceApplication annotation:annotation];
+}
+
 - (void)loadSourceForBridge:(RCTBridge *)bridge
                   withBlock:(RCTSourceLoadBlock)loadCallback
 {
diff --git a/Examples/UIExplorer/UIExplorer/Info.plist b/Examples/UIExplorer/UIExplorer/Info.plist
index 9e91b1cef8cc..d2e82af92142 100644
--- a/Examples/UIExplorer/UIExplorer/Info.plist
+++ b/Examples/UIExplorer/UIExplorer/Info.plist
@@ -18,10 +18,28 @@
 	<string>1.0</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
+	<key>CFBundleURLTypes</key>
+	<array>
+		<dict>
+			<key>CFBundleTypeRole</key>
+			<string>Editor</string>
+			<key>CFBundleURLName</key>
+			<string>com.reactjs.ios</string>
+			<key>CFBundleURLSchemes</key>
+			<array>
+				<string>rnuiexplorer</string>
+			</array>
+		</dict>
+	</array>
 	<key>CFBundleVersion</key>
 	<string>1</string>
 	<key>LSRequiresIPhoneOS</key>
 	<true/>
+	<key>NSAppTransportSecurity</key>
+	<dict>
+		<key>NSAllowsArbitraryLoads</key>
+		<true/>
+	</dict>
 	<key>NSLocationWhenInUseUsageDescription</key>
 	<string>You need to add NSLocationWhenInUseUsageDescription key in Info.plist to enable geolocation, otherwise it is going to *fail silently*!</string>
 	<key>UILaunchStoryboardName</key>
@@ -38,11 +56,5 @@
 	</array>
 	<key>UIViewControllerBasedStatusBarAppearance</key>
 	<false/>
-	<key>NSAppTransportSecurity</key>
-  <dict>
-    <!--See http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/-->
-    <key>NSAllowsArbitraryLoads</key>
-    <true/>
-  </dict>
 </dict>
 </plist>
diff --git a/Examples/UIExplorer/UIExplorerApp.ios.js b/Examples/UIExplorer/UIExplorerApp.ios.js
index 99d08978f895..5a1733d433f4 100644
--- a/Examples/UIExplorer/UIExplorerApp.ios.js
+++ b/Examples/UIExplorer/UIExplorerApp.ios.js
@@ -24,6 +24,7 @@ const UIExplorerNavigationReducer = require('./UIExplorerNavigationReducer');
 const UIExplorerStateTitleMap = require('./UIExplorerStateTitleMap');
 
 const {
+  Alert,
   Animated,
   AppRegistry,
   NavigationExperimental,
@@ -54,7 +55,36 @@ import type {
   UIExplorerExample,
 } from './UIExplorerList.ios'
 
+function PathActionMap(path: string): ?Object {
+  // Warning! Hacky parsing for example code. Use a library for this!
+  const exampleParts = path.split('/example/');
+  const exampleKey = exampleParts[1];
+  if (exampleKey) {
+    if (!UIExplorerList.Modules[exampleKey]) {
+      Alert.alert(`${exampleKey} example could not be found!`);
+      return null;
+    }
+    return UIExplorerActions.ExampleAction(exampleKey);
+  }
+  return null;
+}
+
+function URIActionMap(uri: ?string): ?Object {
+  // Warning! Hacky parsing for example code. Use a library for this!
+  if (!uri) {
+    return null;
+  }
+  const parts = uri.split('rnuiexplorer:/');
+  if (!parts[1]) {
+    return null;
+  }
+  const path = parts[1];
+  return PathActionMap(path);
+}
+
+
 class UIExplorerApp extends React.Component {
+  _navigationRootRef: ?NavigationRootContainer;
   _renderNavigation: Function;
   componentWillMount() {
     this._renderNavigation = this._renderNavigation.bind(this);
@@ -64,7 +94,9 @@ class UIExplorerApp extends React.Component {
       <NavigationRootContainer
         persistenceKey="UIExplorerState"
         reducer={UIExplorerNavigationReducer}
+        ref={navRootRef => { this._navigationRootRef = navRootRef; }}
         renderNavigation={this._renderNavigation}
+        linkingActionMap={URIActionMap}
       />
     );
   }
diff --git a/Libraries/NavigationExperimental/NavigationAnimatedView.js b/Libraries/NavigationExperimental/NavigationAnimatedView.js
index 8b24286df356..c1f6a4040cec 100644
--- a/Libraries/NavigationExperimental/NavigationAnimatedView.js
+++ b/Libraries/NavigationExperimental/NavigationAnimatedView.js
@@ -164,7 +164,7 @@ class NavigationAnimatedView extends React.Component {
 
     if (lastState) {
       lastState.children.forEach((child, index) => {
-        if (!NavigationStateUtils.get(nextState, child.key)) {
+        if (!NavigationStateUtils.get(nextState, child.key) && index !== nextState.index) {
           nextScenes.push({
             index,
             state: child,
diff --git a/Libraries/NavigationExperimental/NavigationRootContainer.js b/Libraries/NavigationExperimental/NavigationRootContainer.js
index e04fe98e2fc2..18d7689e0760 100644
--- a/Libraries/NavigationExperimental/NavigationRootContainer.js
+++ b/Libraries/NavigationExperimental/NavigationRootContainer.js
@@ -12,6 +12,7 @@
 'use strict';
 
 const AsyncStorage = require('AsyncStorage');
+const Linking = require('Linking');
 const React = require('React');
 const BackAndroid = require('BackAndroid');
 const Platform = require('Platform');
@@ -36,17 +37,44 @@ function getBackAction(): BackAction {
 }
 
 type Props = {
+  /*
+   * Set up the rendering of the app for a given navigation state
+   */
   renderNavigation: NavigationRenderer;
+
+  /*
+   * A function that will output the latest navigation state as a function of
+   * the (optional) previous state, and an action
+   */
   reducer: NavigationReducer;
+
+  /*
+   * Provide this key, and the container will store the navigation state in
+   * AsyncStorage through refreshes, with the provided key
+   */
   persistenceKey: ?string;
+
+  /*
+   * The default action to be passed into the reducer when getting the first
+   * state. Defaults to {type: 'RootContainerInitialAction'}
+   */
   initialAction: NavigationAction;
+
+  /*
+   * Provide linkingActionMap to instruct the container to subscribe to linking
+   * events, and use this mapper to convert URIs into actions that your app can
+   * handle
+   */
+  linkingActionMap: (uri: string) => NavigationAction;
 };
 
 class NavigationRootContainer extends React.Component {
+  _handleOpenURLEvent: Function;
   props: Props;
   constructor(props: Props) {
     super(props);
     this.handleNavigation = this.handleNavigation.bind(this);
+    this._handleOpenURLEvent = this._handleOpenURLEvent.bind(this);
     let navState = null;
     if (!this.props.persistenceKey) {
       navState = this.props.reducer(null, props.initialAction);
@@ -54,6 +82,10 @@ class NavigationRootContainer extends React.Component {
     this.state = { navState };
   }
   componentDidMount() {
+    if (this.props.LinkingActionMap) {
+      Linking.getInitialURL().then(this._handleOpenURL.bind(this));
+      Platform.OS === 'ios' && Linking.addEventListener('url', this._handleOpenURLEvent);    
+    }
     if (this.props.persistenceKey) {
       AsyncStorage.getItem(this.props.persistenceKey, (err, storedString) => {
         if (err || !storedString) {
@@ -68,6 +100,21 @@ class NavigationRootContainer extends React.Component {
       });
     }
   }
+  componentWillUnmount() {
+    Platform.OS === 'ios' && Linking.removeEventListener('url', this._handleOpenURLEvent);
+  }
+  _handleOpenURLEvent(event: {url: string}) {
+    this._handleOpenURL(event.url);
+  }
+  _handleOpenURL(url: ?string) {
+    if (!this.props.LinkingActionMap) {
+      return;
+    }
+    const action = this.props.LinkingActionMap(url);
+    if (action) {
+      this.handleNavigation(action);
+    }
+  }
   getChildContext(): Object {
     return {
       onNavigate: this.handleNavigation,
@@ -101,7 +148,7 @@ NavigationRootContainer.childContextTypes = {
 
 NavigationRootContainer.defaultProps = {
   initialAction: {
-    type: 'NavigationRootContainerInitialAction',
+    type: 'RootContainerInitialAction',
   },
 };
 

From 0513d3abb553e7b53cfba93fec9bec7f421dbbe3 Mon Sep 17 00:00:00 2001
From: Hedger Wang <hedger@fb.com>
Date: Mon, 22 Feb 2016 22:45:10 -0800
Subject: [PATCH 1264/1411] revert D2928371 to unbreak drawer.

Reviewed By: furdei

Differential Revision: D2962152

fb-gh-sync-id: ca185efa1b93a905e3ee7ca1c2eb6cc612febdf2
shipit-source-id: ca185efa1b93a905e3ee7ca1c2eb6cc612febdf2
---
 Libraries/ReactIOS/renderApplication.android.js | 16 ++++++----------
 1 file changed, 6 insertions(+), 10 deletions(-)

diff --git a/Libraries/ReactIOS/renderApplication.android.js b/Libraries/ReactIOS/renderApplication.android.js
index 1abfeb8b3a99..05b87178b6f5 100644
--- a/Libraries/ReactIOS/renderApplication.android.js
+++ b/Libraries/ReactIOS/renderApplication.android.js
@@ -73,8 +73,8 @@ var AppContainer = React.createClass({
       return;
     }
 
-    this.refs.accessibilityWrapper.setNativeProps({
-      importantForAccessibility: modalVisible ? 'no-hide-descendants' : 'auto',
+    this.setState({
+      rootImportanceForAccessibility: modalVisible ? 'no-hide-descendants' : 'auto',
     });
   },
 
@@ -85,14 +85,10 @@ var AppContainer = React.createClass({
         ref="main"
         collapsable={!this.state.inspectorVisible}
         style={styles.appContainer}>
-        <View
-          ref="accessibilityWrapper"
-          collapsable={true}
-          style={styles.appContainer}>
-          <RootComponent
-            {...this.props.initialProps}
-            rootTag={this.props.rootTag}/>
-        </View>
+        <RootComponent
+          {...this.props.initialProps}
+          rootTag={this.props.rootTag}
+          importantForAccessibility={this.state.rootImportanceForAccessibility}/>
         <Portal
           onModalVisibilityChanged={this.setRootAccessibility}/>
       </View>;

From ac12f986899d8520527684438f76299675dc0daa Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Tue, 23 Feb 2016 02:26:11 -0800
Subject: [PATCH 1265/1411] Added support for taking snapshots of the screen,
 window or individual views

Summary:This adds a `takeSnapshot` method to UIManager that can be used to capture screenshots as an image.

The takeSnapshot method accepts either 'screen', 'window' or a view ref as an argument.

You can also specify the size, format and quality of the captured image.

I've added an example of capturing a screenshot at UIExplorer > Snapshot / Screenshot.
I've also added an example of sharing a screenshot to the UIExplorer > ActionSheetIOS demo.

Reviewed By: javache

Differential Revision: D2958351

fb-gh-sync-id: d2eb93fea3297ec5aaa312854dd6add724a7f4f8
shipit-source-id: d2eb93fea3297ec5aaa312854dd6add724a7f4f8
---
 Examples/UIExplorer/ActionSheetIOSExample.js | 57 +++++++++++++--
 Examples/UIExplorer/SnapshotExample.js       | 73 ++++++++++++++++++++
 Examples/UIExplorer/UIExplorerList.ios.js    |  4 ++
 Libraries/Utilities/UIManager.js             | 41 ++++++++++-
 React/Base/RCTUtils.h                        |  3 +
 React/Base/RCTUtils.m                        | 45 ++++++++++++
 React/Modules/RCTUIManager.m                 | 69 ++++++++++++++++++
 website/server/extractDocs.js                |  1 +
 8 files changed, 288 insertions(+), 5 deletions(-)
 create mode 100644 Examples/UIExplorer/SnapshotExample.js

diff --git a/Examples/UIExplorer/ActionSheetIOSExample.js b/Examples/UIExplorer/ActionSheetIOSExample.js
index 31fd79c38efb..b749400c037a 100644
--- a/Examples/UIExplorer/ActionSheetIOSExample.js
+++ b/Examples/UIExplorer/ActionSheetIOSExample.js
@@ -20,6 +20,7 @@ var {
   ActionSheetIOS,
   StyleSheet,
   Text,
+  UIManager,
   View,
 } = React;
 
@@ -127,9 +128,7 @@ var ShareActionSheetExample = React.createClass({
         'com.apple.UIKit.activity.PostToTwitter'
       ]
     },
-    (error) => {
-      console.error(error);
-    },
+    (error) => alert(error),
     (success, method) => {
       var text;
       if (success) {
@@ -142,6 +141,50 @@ var ShareActionSheetExample = React.createClass({
   }
 });
 
+var ShareScreenshotExample = React.createClass({
+  getInitialState() {
+    return {
+      text: ''
+    };
+  },
+
+  render() {
+    return (
+      <View>
+        <Text onPress={this.showShareActionSheet} style={style.button}>
+          Click to show the Share ActionSheet
+        </Text>
+        <Text>
+          {this.state.text}
+        </Text>
+      </View>
+    );
+  },
+
+  showShareActionSheet() {
+    // Take the snapshot (returns a temp file uri)
+    UIManager.takeSnapshot('window').then((uri) => {
+      // Share image data
+      ActionSheetIOS.showShareActionSheetWithOptions({
+        url: uri,
+        excludedActivityTypes: [
+          'com.apple.UIKit.activity.PostToTwitter'
+        ]
+      },
+      (error) => alert(error),
+      (success, method) => {
+        var text;
+        if (success) {
+          text = `Shared via ${method}`;
+        } else {
+          text = 'You didn\'t share';
+        }
+        this.setState({text});
+      });
+    }).catch((error) => alert(error));
+  }
+});
+
 var style = StyleSheet.create({
   button: {
     marginBottom: 10,
@@ -166,10 +209,16 @@ exports.examples = [
       return <ShareActionSheetExample url="https://code.facebook.com" />;
     }
   },
-    {
+  {
     title: 'Share Local Image',
     render(): ReactElement {
       return <ShareActionSheetExample url="bunny.png" />;
     }
+  },
+  {
+    title: 'Share Screenshot',
+    render(): ReactElement {
+      return <ShareScreenshotExample />;
+    }
   }
 ];
diff --git a/Examples/UIExplorer/SnapshotExample.js b/Examples/UIExplorer/SnapshotExample.js
new file mode 100644
index 000000000000..f5384c66630d
--- /dev/null
+++ b/Examples/UIExplorer/SnapshotExample.js
@@ -0,0 +1,73 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ *
+ * @flow
+ */
+'use strict';
+
+var React = require('react-native');
+var {
+  Image,
+  StyleSheet,
+  Text,
+  UIManager,
+  View,
+} = React;
+
+var ScreenshotExample = React.createClass({
+  getInitialState() {
+    return {
+      uri: undefined,
+    };
+  },
+
+  render() {
+    return (
+      <View>
+        <Text onPress={this.takeScreenshot} style={style.button}>
+          Click to take a screenshot
+        </Text>
+        <Image style={style.image} source={{uri: this.state.uri}}/>
+      </View>
+    );
+  },
+
+  takeScreenshot() {
+    UIManager
+      .takeSnapshot('screen', {format: 'jpeg', quality: 0.8}) // See UIManager.js for options
+      .then((uri) => this.setState({uri}))
+      .catch((error) => alert(error));
+  }
+});
+
+var style = StyleSheet.create({
+  button: {
+    marginBottom: 10,
+    fontWeight: '500',
+  },
+  image: {
+    flex: 1,
+    height: 300,
+    resizeMode: 'contain',
+    backgroundColor: 'black',
+  },
+});
+
+exports.title = 'Snapshot / Screenshot';
+exports.description = 'API to capture images from the screen.';
+exports.examples = [
+  {
+    title: 'Take screenshot',
+    render(): ReactElement { return <ScreenshotExample />; }
+  },
+];
diff --git a/Examples/UIExplorer/UIExplorerList.ios.js b/Examples/UIExplorer/UIExplorerList.ios.js
index 70a6dbf4c591..65781609d2c1 100644
--- a/Examples/UIExplorer/UIExplorerList.ios.js
+++ b/Examples/UIExplorer/UIExplorerList.ios.js
@@ -220,6 +220,10 @@ var APIExamples: Array<UIExplorerExample> = [
     key: 'RCTRootViewIOSExample',
     module: require('./RCTRootViewIOSExample'),
   },
+  {
+    key: 'SnapshotExample',
+    module: require('./SnapshotExample'),
+  },
   {
     key: 'StatusBarIOSExample',
     module: require('./StatusBarIOSExample'),
diff --git a/Libraries/Utilities/UIManager.js b/Libraries/Utilities/UIManager.js
index ff2fc23541de..068087a8f538 100644
--- a/Libraries/Utilities/UIManager.js
+++ b/Libraries/Utilities/UIManager.js
@@ -12,6 +12,7 @@
 'use strict';
 
 var UIManager = require('NativeModules').UIManager;
+var findNodeHandle = require('findNodeHandle');
 
 if (!UIManager.setChildren) {
 
@@ -39,7 +40,45 @@ if (!UIManager.setChildren) {
   UIManager.setChildren = function(containerTag, createdTags) {
     var indexes = this._cachedIndexArray(createdTags.length);
     UIManager.manageChildren(containerTag, null, null, createdTags, indexes, null);
-  } 
+  };
 }
 
+const _takeSnapshot = UIManager.takeSnapshot;
+
+/**
+ * Capture an image of the screen, window or an individual view. The image
+ * will be stored in a temporary file that will only exist for as long as the
+ * app is running.
+ * 
+ * The `view` argument can be the literal string `screen` or `window` if you
+ * want to capture the entire screen, or it can be a reference to a specific
+ * React Native component.
+ *
+ * The `options` argument may include:
+ * - width/height (number) - the width and height of the image to capture.
+ * - format (string) - either 'png' or 'jpeg'. Defaults to 'png'.
+ * - quality (number) - the quality when using jpeg. 0.0 - 1.0 (default).
+ *
+ * Returns a Promise.
+ * @platform ios
+ */
+UIManager.takeSnapshot = async function(
+  view ?: 'screen' | 'window' | ReactElement | number,
+  options ?: {
+    width ?: number;
+    height ?: number;
+    format ?: 'png' | 'jpeg';
+    quality ?: number;
+  },
+) {
+  if (!_takeSnapshot) {
+    console.warn('UIManager.takeSnapshot is not available on this platform');
+    return;
+  }
+  if (typeof view !== 'number' && view !== 'screen' && view !== 'window') {
+    view = findNodeHandle(view) || 'screen';
+  }
+  return _takeSnapshot(view, options);
+};
+
 module.exports = UIManager;
diff --git a/React/Base/RCTUtils.h b/React/Base/RCTUtils.h
index 9d63bdbf3379..ea319814588c 100644
--- a/React/Base/RCTUtils.h
+++ b/React/Base/RCTUtils.h
@@ -109,6 +109,9 @@ RCT_EXTERN NSString *__nullable RCTBundlePathForURL(NSURL *__nullable URL);
 // Determines if a given image URL actually refers to an XCAsset
 RCT_EXTERN BOOL RCTIsXCAssetURL(NSURL *__nullable imageURL);
 
+// Creates a new, unique temporary file path with the specified extension
+RCT_EXTERN NSString *__nullable RCTTempFilePath(NSString *__nullable extension, NSError **error);
+
 // Converts a CGColor to a hex string
 RCT_EXTERN NSString *RCTColorToHexString(CGColorRef color);
 
diff --git a/React/Base/RCTUtils.m b/React/Base/RCTUtils.m
index 68e3a15e520f..c693ea1a702e 100644
--- a/React/Base/RCTUtils.m
+++ b/React/Base/RCTUtils.m
@@ -589,6 +589,51 @@ BOOL RCTIsXCAssetURL(NSURL *__nullable imageURL)
   return YES;
 }
 
+RCT_EXTERN NSString *__nullable RCTTempFilePath(NSString *extension, NSError **error)
+{
+  static NSError *setupError = nil;
+  static NSString *directory;
+  static dispatch_once_t onceToken;
+  dispatch_once(&onceToken, ^{
+    directory = [NSTemporaryDirectory() stringByAppendingPathComponent:@"ReactNative"];
+    // If the temporary directory already exists, we'll delete it to ensure
+    // that temp files from the previous run have all been deleted. This is not
+    // a security measure, it simply prevents the temp directory from using too
+    // much space, as the circumstances under which iOS clears it automatically
+    // are not well-defined.
+    NSFileManager *fileManager = [NSFileManager new];
+    if ([fileManager fileExistsAtPath:directory]) {
+      [fileManager removeItemAtPath:directory error:NULL];
+    }
+    if (![fileManager fileExistsAtPath:directory]) {
+      NSError *localError = nil;
+      if (![fileManager createDirectoryAtPath:directory
+                  withIntermediateDirectories:YES
+                                   attributes:nil
+                                        error:&localError]) {
+        // This is bad
+        RCTLogError(@"Failed to create temporary directory: %@", localError);
+        setupError = localError;
+        directory = nil;
+      }
+    }
+  });
+
+  if (!directory || setupError) {
+    if (error) {
+      *error = setupError;
+    }
+    return nil;
+  }
+
+  // Append a unique filename
+  NSString *filename = [NSUUID new].UUIDString;
+  if (extension) {
+    filename = [filename stringByAppendingPathExtension:extension];
+  }
+  return [directory stringByAppendingPathComponent:filename];
+}
+
 static void RCTGetRGBAColorComponents(CGColorRef color, CGFloat rgba[4])
 {
   CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(color));
diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m
index cc0821013198..1186ac027ca6 100644
--- a/React/Modules/RCTUIManager.m
+++ b/React/Modules/RCTUIManager.m
@@ -1182,6 +1182,75 @@ static void RCTMeasureLayout(RCTShadowView *view,
   callback(@[results]);
 }
 
+RCT_EXPORT_METHOD(takeSnapshot:(id /* NSString or NSNumber */)target
+                  withOptions:(NSDictionary *)options
+                  resolve:(RCTPromiseResolveBlock)resolve
+                  reject:(RCTPromiseRejectBlock)reject)
+{
+  [self addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
+
+    // Get view
+    UIView *view;
+    if (target == nil || [target isEqual:@"screen"]) {
+      view = [[UIScreen mainScreen] snapshotViewAfterScreenUpdates:YES];
+    } else if ([target isEqual:@"window"]) {
+      view = RCTKeyWindow();
+    } else if ([target isKindOfClass:[NSNumber class]]) {
+      view = viewRegistry[target];
+      if (!view) {
+        RCTLogError(@"No view found with reactTag: %@", target);
+        return;
+      }
+    }
+
+    // Get options
+    CGSize size = [RCTConvert CGSize:options];
+    NSString *format = [RCTConvert NSString:options[@"format"] ?: @"png"];
+
+    // Capture image
+    if (size.width < 0.1 || size.height < 0.1) {
+      size = view.bounds.size;
+    }
+    UIGraphicsBeginImageContextWithOptions(size, NO, 0);
+    BOOL success = [view drawViewHierarchyInRect:(CGRect){CGPointZero, size} afterScreenUpdates:YES];
+    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
+    UIGraphicsEndImageContext();
+
+    if (!success || !image) {
+      reject(RCTErrorUnspecified, @"Failed to capture view snapshot", nil);
+      return;
+    }
+
+    // Convert image to data (on a background thread)
+    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+
+      NSData *data;
+      if ([format isEqualToString:@"png"]) {
+        data = UIImagePNGRepresentation(image);
+      } else if ([format isEqualToString:@"jpeg"]) {
+        CGFloat quality = [RCTConvert CGFloat:options[@"quality"] ?: @1];
+        data = UIImageJPEGRepresentation(image, quality);
+      } else {
+        RCTLogError(@"Unsupported image format: %@", format);
+        return;
+      }
+
+      // Save to a temp file
+      NSError *error = nil;
+      NSString *tempFilePath = RCTTempFilePath(format, &error);
+      if (tempFilePath) {
+        if ([data writeToFile:tempFilePath options:(NSDataWritingOptions)0 error:&error]) {
+          resolve(tempFilePath);
+          return;
+        }
+      }
+
+      // If we reached here, something went wrong
+      reject(RCTErrorUnspecified, error.localizedDescription, error);
+    });
+  }];
+}
+
 /**
  * JS sets what *it* considers to be the responder. Later, scroll views can use
  * this in order to determine if scrolling is appropriate.
diff --git a/website/server/extractDocs.js b/website/server/extractDocs.js
index b74c029b76c0..b263a94a8363 100644
--- a/website/server/extractDocs.js
+++ b/website/server/extractDocs.js
@@ -250,6 +250,7 @@ var apis = [
   '../Libraries/StyleSheet/StyleSheet.js',
   '../Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js',
   '../Libraries/Components/ToastAndroid/ToastAndroid.android.js',
+  '../Libraries/Utilities/UIManager.js',
   '../Libraries/Vibration/VibrationIOS.ios.js',
 ];
 

From b41ad9f5dc556f119f5512ec2e0b048aa16db642 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Tue, 23 Feb 2016 06:09:38 -0800
Subject: [PATCH 1266/1411] Upgrade node-haste to v2.3.0

Summary: This updates to the latest published node-haste version, and also adapts code and tests to that version. Future upgrades should be easier.

Reviewed By: bestander

Differential Revision: D2963144

fb-gh-sync-id: 9fd2c84fc49643fb85ee5d9674a5e458d43d44ca
shipit-source-id: 9fd2c84fc49643fb85ee5d9674a5e458d43d44ca
---
 npm-shrinkwrap.json                           | 208 +++++++++---------
 package.json                                  |   2 +-
 .../AssetServer/__tests__/AssetServer-test.js |   1 +
 .../src/Bundler/__tests__/Bundler-test.js     |   1 +
 .../__tests__/Transformer-test.js             |   3 +-
 .../src/Resolver/__tests__/Resolver-test.js   |  63 +++---
 packager/react-packager/src/Resolver/index.js |  26 +--
 .../src/Server/__tests__/Server-test.js       |   1 +
 .../__tests__/SocketServer-test.js            |   1 +
 9 files changed, 158 insertions(+), 148 deletions(-)

diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index 38b617109335..22c60ec9bc89 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -142,15 +142,15 @@
           "from": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz",
           "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
         },
-        "regenerator": {
-          "version": "0.8.40",
-          "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
-          "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
-        },
         "recast": {
           "version": "0.10.33",
           "from": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz",
           "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
+        },
+        "regenerator": {
+          "version": "0.8.40",
+          "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
+          "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
         }
       }
     },
@@ -223,36 +223,36 @@
           "from": "https://registry.npmjs.org/babel-core/-/babel-core-5.8.33.tgz",
           "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-5.8.33.tgz"
         },
-        "babylon": {
-          "version": "5.8.29",
-          "from": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz",
-          "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz"
-        },
         "ast-types": {
           "version": "0.8.12",
           "from": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz",
           "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz"
         },
-        "js-tokens": {
-          "version": "1.0.1",
-          "from": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz",
-          "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
+        "babylon": {
+          "version": "5.8.29",
+          "from": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz",
+          "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz"
         },
         "globals": {
           "version": "6.4.1",
           "from": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz",
           "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
         },
-        "regenerator": {
-          "version": "0.8.40",
-          "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
-          "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
+        "js-tokens": {
+          "version": "1.0.1",
+          "from": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz",
+          "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz"
         },
         "recast": {
           "version": "0.10.33",
           "from": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz",
           "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
         },
+        "regenerator": {
+          "version": "0.8.40",
+          "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
+          "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
+        },
         "source-map": {
           "version": "0.5.3",
           "from": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz",
@@ -1895,41 +1895,41 @@
             }
           }
         },
-        "ansi": {
-          "version": "0.3.0",
-          "from": "ansi@~0.3.0",
-          "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.0.tgz"
-        },
         "abbrev": {
           "version": "1.0.7",
           "from": "abbrev@1",
           "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz"
         },
-        "ansi-styles": {
-          "version": "2.1.0",
-          "from": "ansi-styles@^2.1.0",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz"
+        "ansi": {
+          "version": "0.3.0",
+          "from": "ansi@~0.3.0",
+          "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.0.tgz"
         },
         "ansi-regex": {
           "version": "2.0.0",
           "from": "ansi-regex@^2.0.0",
           "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
         },
+        "ansi-styles": {
+          "version": "2.1.0",
+          "from": "ansi-styles@^2.1.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz"
+        },
         "are-we-there-yet": {
           "version": "1.0.4",
           "from": "are-we-there-yet@~1.0.0",
           "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.4.tgz"
         },
-        "assert-plus": {
-          "version": "0.1.5",
-          "from": "assert-plus@^0.1.5",
-          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
-        },
         "asn1": {
           "version": "0.1.11",
           "from": "asn1@0.1.11",
           "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
         },
+        "assert-plus": {
+          "version": "0.1.5",
+          "from": "assert-plus@^0.1.5",
+          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
+        },
         "async": {
           "version": "1.5.0",
           "from": "async@^1.4.0",
@@ -1970,16 +1970,16 @@
           "from": "chalk@^1.1.1",
           "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz"
         },
-        "commander": {
-          "version": "2.9.0",
-          "from": "commander@^2.8.1",
-          "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz"
-        },
         "combined-stream": {
           "version": "1.0.5",
           "from": "combined-stream@~1.0.5",
           "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz"
         },
+        "commander": {
+          "version": "2.9.0",
+          "from": "commander@^2.8.1",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz"
+        },
         "concat-map": {
           "version": "0.0.1",
           "from": "concat-map@0.0.1",
@@ -2000,16 +2000,16 @@
           "from": "ctype@0.5.3",
           "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz"
         },
-        "deep-extend": {
-          "version": "0.2.11",
-          "from": "deep-extend@~0.2.5",
-          "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.2.11.tgz"
-        },
         "debug": {
           "version": "0.7.4",
           "from": "debug@~0.7.2",
           "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz"
         },
+        "deep-extend": {
+          "version": "0.2.11",
+          "from": "deep-extend@~0.2.5",
+          "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.2.11.tgz"
+        },
         "delayed-stream": {
           "version": "1.0.0",
           "from": "delayed-stream@~1.0.0",
@@ -2055,41 +2055,41 @@
           "from": "generate-function@^2.0.0",
           "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz"
         },
-        "graceful-fs": {
-          "version": "4.1.2",
-          "from": "graceful-fs@4.1",
-          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.2.tgz"
-        },
         "generate-object-property": {
           "version": "1.2.0",
           "from": "generate-object-property@^1.1.0",
           "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz"
         },
-        "har-validator": {
-          "version": "2.0.2",
-          "from": "har-validator@~2.0.2",
-          "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.2.tgz"
+        "graceful-fs": {
+          "version": "4.1.2",
+          "from": "graceful-fs@4.1",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.2.tgz"
         },
         "graceful-readlink": {
           "version": "1.0.1",
           "from": "graceful-readlink@>= 1.0.0",
           "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
         },
+        "har-validator": {
+          "version": "2.0.2",
+          "from": "har-validator@~2.0.2",
+          "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.2.tgz"
+        },
         "has-ansi": {
           "version": "2.0.0",
           "from": "has-ansi@^2.0.0",
           "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
         },
-        "hawk": {
-          "version": "3.1.0",
-          "from": "hawk@~3.1.0",
-          "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.0.tgz"
-        },
         "has-unicode": {
           "version": "1.0.1",
           "from": "has-unicode@^1.0.0",
           "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-1.0.1.tgz"
         },
+        "hawk": {
+          "version": "3.1.0",
+          "from": "hawk@~3.1.0",
+          "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.0.tgz"
+        },
         "hoek": {
           "version": "2.16.3",
           "from": "hoek@2.x.x",
@@ -2110,6 +2110,11 @@
           "from": "ini@~1.3.0",
           "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz"
         },
+        "is-my-json-valid": {
+          "version": "2.12.2",
+          "from": "is-my-json-valid@^2.12.2",
+          "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.2.tgz"
+        },
         "is-property": {
           "version": "1.0.2",
           "from": "is-property@^1.0.0",
@@ -2120,26 +2125,21 @@
           "from": "isarray@0.0.1",
           "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
         },
-        "is-my-json-valid": {
-          "version": "2.12.2",
-          "from": "is-my-json-valid@^2.12.2",
-          "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.2.tgz"
-        },
         "isstream": {
           "version": "0.1.2",
           "from": "isstream@~0.1.2",
           "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
         },
-        "jsonpointer": {
-          "version": "2.0.0",
-          "from": "jsonpointer@2.0.0",
-          "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
-        },
         "json-stringify-safe": {
           "version": "5.0.1",
           "from": "json-stringify-safe@~5.0.1",
           "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
         },
+        "jsonpointer": {
+          "version": "2.0.0",
+          "from": "jsonpointer@2.0.0",
+          "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
+        },
         "lodash._basetostring": {
           "version": "3.0.1",
           "from": "lodash._basetostring@^3.0.0",
@@ -2150,26 +2150,26 @@
           "from": "lodash._createpadding@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash._createpadding/-/lodash._createpadding-3.6.1.tgz"
         },
+        "lodash.pad": {
+          "version": "3.1.1",
+          "from": "lodash.pad@^3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-3.1.1.tgz"
+        },
         "lodash.padleft": {
           "version": "3.1.1",
           "from": "lodash.padleft@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash.padleft/-/lodash.padleft-3.1.1.tgz"
         },
-        "lodash.pad": {
+        "lodash.padright": {
           "version": "3.1.1",
-          "from": "lodash.pad@^3.0.0",
-          "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-3.1.1.tgz"
+          "from": "lodash.padright@^3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash.padright/-/lodash.padright-3.1.1.tgz"
         },
         "lodash.repeat": {
           "version": "3.0.1",
           "from": "lodash.repeat@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash.repeat/-/lodash.repeat-3.0.1.tgz"
         },
-        "lodash.padright": {
-          "version": "3.1.1",
-          "from": "lodash.padright@^3.0.0",
-          "resolved": "https://registry.npmjs.org/lodash.padright/-/lodash.padright-3.1.1.tgz"
-        },
         "mime-db": {
           "version": "1.19.0",
           "from": "mime-db@~1.19.0",
@@ -2190,16 +2190,16 @@
           "from": "mkdirp@>=0.3.0 <0.4.0||>=0.4.0 <0.5.0||>=0.5.0 <0.6.0",
           "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz"
         },
-        "npmlog": {
-          "version": "1.2.1",
-          "from": "npmlog@~1.2.0",
-          "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz"
-        },
         "node-uuid": {
           "version": "1.4.3",
           "from": "node-uuid@~1.4.3",
           "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.3.tgz"
         },
+        "npmlog": {
+          "version": "1.2.1",
+          "from": "npmlog@~1.2.0",
+          "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz"
+        },
         "oauth-sign": {
           "version": "0.8.0",
           "from": "oauth-sign@~0.8.0",
@@ -2215,16 +2215,16 @@
           "from": "path-is-absolute@>=1.0.0 <2.0.0",
           "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz"
         },
-        "pinkie-promise": {
-          "version": "1.0.0",
-          "from": "pinkie-promise@^1.0.0",
-          "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz"
-        },
         "pinkie": {
           "version": "1.0.0",
           "from": "pinkie@^1.0.0",
           "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz"
         },
+        "pinkie-promise": {
+          "version": "1.0.0",
+          "from": "pinkie-promise@^1.0.0",
+          "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz"
+        },
         "qs": {
           "version": "5.2.0",
           "from": "qs@~5.2.0",
@@ -2260,20 +2260,20 @@
           "from": "stringstream@~0.0.4",
           "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
         },
-        "supports-color": {
-          "version": "2.0.0",
-          "from": "supports-color@^2.0.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
+        "strip-ansi": {
+          "version": "3.0.0",
+          "from": "strip-ansi@^3.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz"
         },
         "strip-json-comments": {
           "version": "0.1.3",
           "from": "strip-json-comments@0.1.x",
           "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
         },
-        "strip-ansi": {
-          "version": "3.0.0",
-          "from": "strip-ansi@^3.0.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz"
+        "supports-color": {
+          "version": "2.0.0",
+          "from": "supports-color@^2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
         },
         "tar": {
           "version": "2.2.1",
@@ -2290,16 +2290,16 @@
           "from": "uid-number@0.0.3",
           "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.3.tgz"
         },
-        "wrappy": {
-          "version": "1.0.1",
-          "from": "wrappy@>=1.0.0 <2.0.0",
-          "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
-        },
         "tunnel-agent": {
           "version": "0.4.1",
           "from": "tunnel-agent@~0.4.1",
           "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz"
         },
+        "wrappy": {
+          "version": "1.0.1",
+          "from": "wrappy@>=1.0.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz"
+        },
         "xtend": {
           "version": "4.0.1",
           "from": "xtend@^4.0.0",
@@ -3933,8 +3933,9 @@
       }
     },
     "node-haste": {
-      "version": "2.0.0",
-      "from": "node-haste@*",
+      "version": "2.3.0",
+      "from": "node-haste@2.3.0",
+      "resolved": "https://registry.npmjs.org/node-haste/-/node-haste-2.3.0.tgz",
       "dependencies": {
         "graceful-fs": {
           "version": "4.1.3",
@@ -3942,9 +3943,9 @@
           "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.3.tgz"
         },
         "sane": {
-          "version": "1.3.1",
+          "version": "1.3.3",
           "from": "sane@>=1.3.1 <2.0.0",
-          "resolved": "https://registry.npmjs.org/sane/-/sane-1.3.1.tgz",
+          "resolved": "https://registry.npmjs.org/sane/-/sane-1.3.3.tgz",
           "dependencies": {
             "exec-sh": {
               "version": "0.2.0",
@@ -4005,6 +4006,11 @@
               "resolved": "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz"
             }
           }
+        },
+        "throat": {
+          "version": "2.0.2",
+          "from": "throat@>=2.0.2 <3.0.0",
+          "resolved": "https://registry.npmjs.org/throat/-/throat-2.0.2.tgz"
         }
       }
     },
diff --git a/package.json b/package.json
index e69bcfbf6281..aadb2436f154 100644
--- a/package.json
+++ b/package.json
@@ -148,7 +148,7 @@
     "mkdirp": "^0.5.1",
     "module-deps": "^3.9.1",
     "node-fetch": "^1.3.3",
-    "node-haste": "~2.0.0",
+    "node-haste": "~2.3.0",
     "opn": "^3.0.2",
     "optimist": "^0.6.1",
     "progress": "^1.1.8",
diff --git a/packager/react-packager/src/AssetServer/__tests__/AssetServer-test.js b/packager/react-packager/src/AssetServer/__tests__/AssetServer-test.js
index 0172f39b4e98..15bfc0ce05fb 100644
--- a/packager/react-packager/src/AssetServer/__tests__/AssetServer-test.js
+++ b/packager/react-packager/src/AssetServer/__tests__/AssetServer-test.js
@@ -2,6 +2,7 @@
 
 jest
   .dontMock('node-haste/lib/lib/getPlatformExtension')
+  .dontMock('node-haste/node_modules/throat')
   .dontMock('../');
 
 jest
diff --git a/packager/react-packager/src/Bundler/__tests__/Bundler-test.js b/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
index 5ed7d65877d8..1c72d0a426b5 100644
--- a/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
+++ b/packager/react-packager/src/Bundler/__tests__/Bundler-test.js
@@ -10,6 +10,7 @@
 
 jest
   .setMock('worker-farm', () => () => undefined)
+  .dontMock('node-haste/node_modules/throat')
   .dontMock('underscore')
   .dontMock('../../lib/ModuleTransport')
   .setMock('uglify-js')
diff --git a/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js b/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js
index ad4dc4d4e3da..cd73549c883e 100644
--- a/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js
+++ b/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js
@@ -25,8 +25,7 @@ describe('Transformer', function() {
   var workers;
 
   beforeEach(function() {
-    Cache = require('node-haste').Cache;
-
+    Cache = jest.genMockFn();
     Cache.prototype.get = jest.genMockFn().mockImpl((a, b, c) => c());
 
     workers = jest.genMockFn();
diff --git a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
index 7b3a5616c823..b12ebd48dfb4 100644
--- a/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
+++ b/packager/react-packager/src/Resolver/__tests__/Resolver-test.js
@@ -15,25 +15,37 @@ jest.mock('path');
 
 const Promise = require('promise');
 const Resolver = require('../');
-const DependencyGraph = require('node-haste');
 
 const path = require('path');
 const _ = require('underscore');
 
+let DependencyGraph = jest.genMockFn();
+jest.setMock('node-haste', DependencyGraph);
 let Module;
 let Polyfill;
 
 describe('Resolver', function() {
   beforeEach(function() {
-    Module = require('node-haste').Module;
-    Polyfill = require('node-haste').Polyfill;
+    DependencyGraph.mockClear();
+    Module = jest.genMockFn().mockImpl(function() {
+      this.getName = jest.genMockFn();
+      this.getDependencies = jest.genMockFn();
+      this.isPolyfill = jest.genMockFn().mockReturnValue(false);
+    });
+    Polyfill = jest.genMockFn().mockImpl(function() {
+      var polyfill = new Module();
+      polyfill.isPolyfill.mockReturnValue(true);
+      return polyfill;
+    });
 
     DependencyGraph.replacePatterns = require.requireActual('node-haste/lib/lib/replacePatterns');
+    DependencyGraph.prototype.createPolyfill = jest.genMockFn();
+    DependencyGraph.prototype.getDependencies = jest.genMockFn();
 
     // For the polyfillDeps
     path.join = jest.genMockFn().mockImpl((a, b) => b);
 
-    DependencyGraph.prototype.load.mockImpl(() => Promise.resolve());
+    DependencyGraph.prototype.load = jest.genMockFn().mockImpl(() => Promise.resolve());
   });
 
   class ResolutionResponseMock {
@@ -60,9 +72,9 @@ describe('Resolver', function() {
 
   function createPolyfill(id, dependencies) {
     var polyfill = new Polyfill({});
-    polyfill.getName.mockImpl(() => Promise.resolve(id));
-    polyfill.getDependencies.mockImpl(() => Promise.resolve(dependencies));
-    polyfill.isPolyfill.mockReturnValue(true);
+    polyfill.getName = jest.genMockFn().mockImpl(() => Promise.resolve(id));
+    polyfill.getDependencies =
+      jest.genMockFn().mockImpl(() => Promise.resolve(dependencies));
     return polyfill;
   }
 
@@ -86,30 +98,26 @@ describe('Resolver', function() {
         .then(function(result) {
           expect(result.mainModuleId).toEqual('index');
           expect(result.dependencies[result.dependencies.length - 1]).toBe(module);
-          expect(_.pluck(Polyfill.mock.calls, 0)).toEqual([
-            { path: 'polyfills/polyfills.js',
+          expect(_.pluck(DependencyGraph.prototype.createPolyfill.mock.calls, 0)).toEqual([
+            { file: 'polyfills/polyfills.js',
               id: 'polyfills/polyfills.js',
-              isPolyfill: true,
               dependencies: []
             },
             { id: 'polyfills/console.js',
-              isPolyfill: true,
-              path: 'polyfills/console.js',
+              file: 'polyfills/console.js',
               dependencies: [
                 'polyfills/polyfills.js'
               ],
             },
             { id: 'polyfills/error-guard.js',
-              isPolyfill: true,
-              path: 'polyfills/error-guard.js',
+              file: 'polyfills/error-guard.js',
               dependencies: [
                 'polyfills/polyfills.js',
                 'polyfills/console.js'
               ],
             },
             { id: 'polyfills/String.prototype.es6.js',
-              isPolyfill: true,
-              path: 'polyfills/String.prototype.es6.js',
+              file: 'polyfills/String.prototype.es6.js',
               dependencies: [
                 'polyfills/polyfills.js',
                 'polyfills/console.js',
@@ -117,8 +125,7 @@ describe('Resolver', function() {
               ],
             },
             { id: 'polyfills/Array.prototype.es6.js',
-              isPolyfill: true,
-              path: 'polyfills/Array.prototype.es6.js',
+              file: 'polyfills/Array.prototype.es6.js',
               dependencies: [
                 'polyfills/polyfills.js',
                 'polyfills/console.js',
@@ -127,8 +134,7 @@ describe('Resolver', function() {
               ],
             },
             { id: 'polyfills/Array.es6.js',
-              isPolyfill: true,
-              path: 'polyfills/Array.es6.js',
+              file: 'polyfills/Array.es6.js',
               dependencies: [
                 'polyfills/polyfills.js',
                 'polyfills/console.js',
@@ -138,8 +144,7 @@ describe('Resolver', function() {
               ],
             },
             { id: 'polyfills/Object.es7.js',
-              isPolyfill: true,
-              path: 'polyfills/Object.es7.js',
+              file: 'polyfills/Object.es7.js',
               dependencies: [
                 'polyfills/polyfills.js',
                 'polyfills/console.js',
@@ -150,8 +155,7 @@ describe('Resolver', function() {
               ],
             },
             { id: 'polyfills/babelHelpers.js',
-              isPolyfill: true,
-              path: 'polyfills/babelHelpers.js',
+              file: 'polyfills/babelHelpers.js',
               dependencies: [
                 'polyfills/polyfills.js',
                 'polyfills/console.js',
@@ -181,12 +185,14 @@ describe('Resolver', function() {
         }));
       });
 
+      const polyfill = {};
+      DependencyGraph.prototype.createPolyfill.mockReturnValueOnce(polyfill);
       return depResolver.getDependencies('/root/index.js', { dev: true })
         .then(function(result) {
           expect(result.mainModuleId).toEqual('index');
           expect(DependencyGraph.mock.instances[0].getDependencies)
-              .toBeCalledWith('/root/index.js', undefined, true);
-          expect(result.dependencies[0]).toBe(Polyfill.mock.instances[0]);
+              .toBeCalledWith({entryPath: '/root/index.js', recursive: true});
+          expect(result.dependencies[0]).toBe(polyfill);
           expect(result.dependencies[result.dependencies.length - 1])
               .toBe(module);
         });
@@ -211,10 +217,9 @@ describe('Resolver', function() {
       return depResolver.getDependencies('/root/index.js', { dev: false })
         .then((result) => {
           expect(result.mainModuleId).toEqual('index');
-          expect(Polyfill.mock.calls[result.dependencies.length - 2]).toEqual([
-            { path: 'some module',
+          expect(DependencyGraph.prototype.createPolyfill.mock.calls[result.dependencies.length - 2]).toEqual([
+            { file: 'some module',
               id: 'some module',
-              isPolyfill: true,
               dependencies: [
                 'polyfills/polyfills.js',
                 'polyfills/console.js',
diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index 5b9e890241b0..76d8d5af219b 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -13,7 +13,6 @@ const path = require('path');
 const Activity = require('../Activity');
 const DependencyGraph = require('node-haste');
 const replacePatterns = require('node-haste').replacePatterns;
-const Polyfill = require('node-haste').Polyfill;
 const declareOpts = require('../lib/declareOpts');
 const Promise = require('promise');
 
@@ -121,14 +120,13 @@ class Resolver {
     return this._depGraph.getModuleForPath(entryFile);
   }
 
-  getDependencies(main, options) {
-    const opts = getDependenciesValidateOpts(options);
-
-    return this._depGraph.getDependencies(
-      main,
-      opts.platform,
-      opts.recursive,
-    ).then(resolutionResponse => {
+  getDependencies(entryPath, options) {
+    const {platform, recursive} = getDependenciesValidateOpts(options);
+    return this._depGraph.getDependencies({
+      entryPath,
+      platform,
+      recursive,
+    }).then(resolutionResponse => {
       this._getPolyfillDependencies().reverse().forEach(
         polyfill => resolutionResponse.prependDependency(polyfill)
       );
@@ -151,11 +149,10 @@ class Resolver {
     return [
       prelude,
       moduleSystem
-    ].map(moduleName => new Polyfill({
-      path: moduleName,
+    ].map(moduleName => this._depGraph.createPolyfill({
+      file: moduleName,
       id: moduleName,
       dependencies: [],
-      isPolyfill: true,
     }));
   }
 
@@ -172,11 +169,10 @@ class Resolver {
     ].concat(this._polyfillModuleNames);
 
     return polyfillModuleNames.map(
-      (polyfillModuleName, idx) => new Polyfill({
-        path: polyfillModuleName,
+      (polyfillModuleName, idx) => this._depGraph.createPolyfill({
+        file: polyfillModuleName,
         id: polyfillModuleName,
         dependencies: polyfillModuleNames.slice(0, idx),
-        isPolyfill: true,
       })
     );
   }
diff --git a/packager/react-packager/src/Server/__tests__/Server-test.js b/packager/react-packager/src/Server/__tests__/Server-test.js
index 246397a2c2c8..a2248842371d 100644
--- a/packager/react-packager/src/Server/__tests__/Server-test.js
+++ b/packager/react-packager/src/Server/__tests__/Server-test.js
@@ -9,6 +9,7 @@
 'use strict';
 
 jest.setMock('worker-farm', function() { return () => {}; })
+    .dontMock('node-haste/node_modules/throat')
     .dontMock('os')
     .dontMock('underscore')
     .dontMock('path')
diff --git a/packager/react-packager/src/SocketInterface/__tests__/SocketServer-test.js b/packager/react-packager/src/SocketInterface/__tests__/SocketServer-test.js
index c269a0e55847..12512eedc69e 100644
--- a/packager/react-packager/src/SocketInterface/__tests__/SocketServer-test.js
+++ b/packager/react-packager/src/SocketInterface/__tests__/SocketServer-test.js
@@ -11,6 +11,7 @@
 jest.setMock('uglify-js')
     .mock('net')
     .mock('fs')
+    .dontMock('node-haste/node_modules/throat')
     .dontMock('../SocketServer');
 
 var PackagerServer = require('../../Server');

From df5dd0b395d62ecdaee743ba88582164148633ca Mon Sep 17 00:00:00 2001
From: "Dotan J. Nahum" <jondotan@gmail.com>
Date: Tue, 23 Feb 2016 08:39:28 -0800
Subject: [PATCH 1267/1411] Docs: Animations.md, clarify how navigation
 animation is configured.

Summary:This clarifies where the configuration goes, saves a few clicks.
Closes https://github.com/facebook/react-native/pull/6034

Differential Revision: D2965844

fb-gh-sync-id: d6ea469ead0dc380f1686e62a2211e8736c75516
shipit-source-id: d6ea469ead0dc380f1686e62a2211e8736c75516
---
 docs/Animations.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/Animations.md b/docs/Animations.md
index 10f39911a443..1c570a952e41 100644
--- a/docs/Animations.md
+++ b/docs/Animations.md
@@ -382,7 +382,7 @@ Here we animated the opacity, but as you might guess, we can animate any
 numeric value. Read more about react-tween-state in its
 [README](https://github.com/chenglou/react-tween-state).
 
-### Rebound (Not recommended - use [Animated](#animated) instead)
+### Rebound (Not recommended - use [Animated](docs/animation.html) instead)
 
 [Rebound.js](https://github.com/facebook/rebound-js) is a JavaScript port of
 [Rebound for Android](https://github.com/facebook/rebound). It is
@@ -529,7 +529,7 @@ around native functionality provided by `UINavigationController`, so
 these scene transitions apply only to `Navigator`. In order to re-create
 the various animations provided by `UINavigationController` and also
 make them customizable, React Native exposes a
-[NavigatorSceneConfigs](https://github.com/facebook/react-native/blob/master/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js) API.
+[NavigatorSceneConfigs](https://github.com/facebook/react-native/blob/master/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js) API which is then handed over to the [Navigator](https://github.com/facebook/react-native/blob/master/Libraries/CustomComponents/Navigator/Navigator.js) `configureScene` prop.
 
 ```javascript
 import { Dimensions } from 'react-native';

From 9e18b21904850d288db630c5757d897eec57c339 Mon Sep 17 00:00:00 2001
From: Jason Axelson <jason@hobnob.io>
Date: Tue, 23 Feb 2016 09:00:43 -0800
Subject: [PATCH 1268/1411] Minor improvements to Android docs

Summary:This is meant to help people who are just quickly scanning through the docs.

Please let me know of other ways this could be formatted to be more readable.
Closes https://github.com/facebook/react-native/pull/6102

Differential Revision: D2965869

fb-gh-sync-id: 00b9a29444709d409d34a1c016b52a03bf18d116
shipit-source-id: 00b9a29444709d409d34a1c016b52a03bf18d116
---
 docs/DevelopmentSetupAndroid.md |  3 ++-
 docs/Tutorial.md                | 16 ++++++++++++----
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/docs/DevelopmentSetupAndroid.md b/docs/DevelopmentSetupAndroid.md
index 9eee76088519..0d7265c9ddd5 100644
--- a/docs/DevelopmentSetupAndroid.md
+++ b/docs/DevelopmentSetupAndroid.md
@@ -72,7 +72,8 @@ Genymotion is much easier to set up than stock Google emulators. However, it's o
   * Intel x86 Atom System Image (for Android 5.1.1 - API 22)
   * Intel x86 Emulator Accelerator (HAXM installer)
 2. Click "Install Packages".
-3. [Configure hardware acceleration (HAXM)](http://developer.android.com/tools/devices/emulator.html#vm-mac), otherwise the emulator is going to be slow.
+3. [Configure hardware acceleration (HAXM)](http://developer.android.com/tools/devices/emulator.html#vm-mac), otherwise the emulator is going to be slow (or may not run at all).
+  * On a mac this is typically requires opening: `/usr/local/opt/android-sdk/extras/intel/Hardware_Accelerated_Execution_Manager/IntelHAXM_<version>.dmg` and installing the package within.
 4. Create an Android Virtual Device (AVD):
   1. Run `android avd` and click on **Create...**
   ![Create AVD dialog](img/CreateAVD.png)
diff --git a/docs/Tutorial.md b/docs/Tutorial.md
index 1e0be8a205e6..ec5a4d72bfc5 100644
--- a/docs/Tutorial.md
+++ b/docs/Tutorial.md
@@ -29,13 +29,21 @@ After installing these dependencies there are two simple commands to get a React
     This command fetches the React Native source code and dependencies and then creates a new Xcode project in `AwesomeProject/iOS/AwesomeProject.xcodeproj` and a gradle project in `AwesomeProject/android/app`.
 
 
-## Development
+## Overview
 
-For iOS, you can now open this new project (`AwesomeProject/ios/AwesomeProject.xcodeproj`) in Xcode and simply build and run it with `⌘+R`. Doing so will also start a Node server which enables live code reloading. With this you can see your changes by pressing `⌘+R` in the simulator rather than recompiling in Xcode.
+In this tutorial we'll be building a simple version of the Movies app that fetches 25 movies that are in theaters and displays them in a ListView.
 
-For Android, run `react-native run-android` from `AwesomeProject` to install the generated app on your emulator or device, and start the Node server which enables live code reloading. To see your changes you have to open the rage-shake-menu (either shake the device or press the menu button on devices, press F2 or Page Up for emulator, ⌘+M for Genymotion), and then press `Reload JS`.
+### Starting the app on iOS
 
-For this tutorial we'll be building a simple version of the Movies app that fetches 25 movies that are in theaters and displays them in a ListView.
+Open this new project (`AwesomeProject/ios/AwesomeProject.xcodeproj`) in Xcode and simply build and run it with `⌘+R`. Doing so will also start a Node server which enables live code reloading. With this you can see your changes by pressing `⌘+R` in the simulator rather than recompiling in Xcode.
+
+### Starting the app on Android
+
+In your terminal navigate into the `AwesomeProject` and run:
+
+    react-native run-android
+
+This will install the generated app on your emulator or device, as well as start the Node server which enables live code reloading. To see your changes you have to open the rage-shake-menu (either shake the device or press the menu button on devices, press F2 or Page Up for emulator, ⌘+M for Genymotion), and then press `Reload JS`.
 
 ### Hello World
 

From 7176c5291e57ccbcbeab962359bb2063ee43dace Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Tue, 23 Feb 2016 10:57:49 -0800
Subject: [PATCH 1269/1411] Dispatch JS calls to JS thread from c++ bridge

Summary: Instead of dispatching calls to the JS thread in Java, do it in the C++ bridge. This moves us closer to the cxx bridge and will allow us to dispatch to the correct web worker in C++ instead of in Java

Reviewed By: mhorowitz

Differential Revision: D2954115

fb-gh-sync-id: 7e7d4eff2c72601b8b4416f1ccd8d2985aebd755
shipit-source-id: 7e7d4eff2c72601b8b4416f1ccd8d2985aebd755
---
 .../testing/ReactIntegrationTestCase.java     |   3 +
 .../react/bridge/CatalystInstanceImpl.java    | 106 +++++-------------
 .../facebook/react/bridge/ReactBridge.java    |   2 +-
 ReactAndroid/src/main/jni/react/Bridge.cpp    |  56 ++++++++-
 ReactAndroid/src/main/jni/react/Bridge.h      |  15 ++-
 .../src/main/jni/react/jni/OnLoad.cpp         |   5 +-
 6 files changed, 99 insertions(+), 88 deletions(-)

diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java
index e1312d36a6e1..b8d85fe0ffdb 100644
--- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactIntegrationTestCase.java
@@ -70,14 +70,17 @@ public void shutDownContext() {
       mReactContext = null;
       mInstance = null;
 
+      final SimpleSettableFuture<Void> semaphore = new SimpleSettableFuture<>();
       UiThreadUtil.runOnUiThread(new Runnable() {
         @Override
         public void run() {
           if (contextToDestroy != null) {
             contextToDestroy.destroy();
           }
+          semaphore.set(null);
         }
       });
+      semaphore.getOrThrow();
     }
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
index 325a123065b4..cbf259f29a82 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
@@ -53,7 +53,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
   private final TraceListener mTraceListener;
   private final JavaScriptModuleRegistry mJSModuleRegistry;
   private final JSBundleLoader mJSBundleLoader;
-  private volatile int mTraceID = 0;
+  private final Object mTeardownLock = new Object();
 
   // Access from native modules thread
   private final NativeModuleRegistry mJavaRegistry;
@@ -168,42 +168,16 @@ public Boolean call() throws Exception {
       final int methodId,
       final NativeArray arguments,
       final String tracingName) {
-    if (mDestroyed) {
-      FLog.w(ReactConstants.TAG, "Calling JS function after bridge has been destroyed.");
-      return;
-    }
-
-    incrementPendingJSCalls();
-
-    final int traceID = mTraceID++;
-    Systrace.startAsyncFlow(
-        Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
-        tracingName,
-        traceID);
-
-    mReactQueueConfiguration.getJSQueueThread().runOnQueue(
-        new Runnable() {
-          @Override
-          public void run() {
-            mReactQueueConfiguration.getJSQueueThread().assertIsOnThread();
-
-            Systrace.endAsyncFlow(
-                Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
-                tracingName,
-                traceID);
+    synchronized (mTeardownLock) {
+      if (mDestroyed) {
+        FLog.w(ReactConstants.TAG, "Calling JS function after bridge has been destroyed.");
+        return;
+      }
 
-            if (mDestroyed) {
-              return;
-            }
+      incrementPendingJSCalls();
 
-            Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, tracingName);
-            try {
-              Assertions.assertNotNull(mBridge).callFunction(moduleId, methodId, arguments);
-            } finally {
-              Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
-            }
-          }
-        });
+      Assertions.assertNotNull(mBridge).callFunction(moduleId, methodId, arguments, tracingName);
+    }
   }
 
   // This is called from java code, so it won't be stripped anyway, but proguard will rename it,
@@ -211,42 +185,16 @@ public void run() {
   @DoNotStrip
   @Override
   public void invokeCallback(final int callbackID, final NativeArray arguments) {
-    if (mDestroyed) {
-      FLog.w(ReactConstants.TAG, "Invoking JS callback after bridge has been destroyed.");
-      return;
-    }
-
-    incrementPendingJSCalls();
-
-    final int traceID = mTraceID++;
-    Systrace.startAsyncFlow(
-        Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
-        "<callback>",
-        traceID);
-
-    mReactQueueConfiguration.getJSQueueThread().runOnQueue(
-        new Runnable() {
-          @Override
-          public void run() {
-            mReactQueueConfiguration.getJSQueueThread().assertIsOnThread();
-
-            Systrace.endAsyncFlow(
-                Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
-                "<callback>",
-                traceID);
+    synchronized (mTeardownLock) {
+      if (mDestroyed) {
+        FLog.w(ReactConstants.TAG, "Invoking JS callback after bridge has been destroyed.");
+        return;
+      }
 
-            if (mDestroyed) {
-              return;
-            }
+      incrementPendingJSCalls();
 
-            Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "<callback>");
-            try {
-              Assertions.assertNotNull(mBridge).invokeCallback(callbackID, arguments);
-            } finally {
-              Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
-            }
-          }
-        });
+      Assertions.assertNotNull(mBridge).invokeCallback(callbackID, arguments);
+    }
   }
 
   /**
@@ -258,18 +206,20 @@ public void run() {
   public void destroy() {
     UiThreadUtil.assertOnUiThread();
 
-    if (mDestroyed) {
-      return;
-    }
+    synchronized (mTeardownLock) {
+      if (mDestroyed) {
+        return;
+      }
 
-    // TODO: tell all APIs to shut down
-    mDestroyed = true;
-    mJavaRegistry.notifyCatalystInstanceDestroy();
+      // TODO: tell all APIs to shut down
+      mDestroyed = true;
+      mJavaRegistry.notifyCatalystInstanceDestroy();
 
-    Systrace.unregisterListener(mTraceListener);
+      Systrace.unregisterListener(mTraceListener);
 
-    synchronouslyDisposeBridgeOnJSThread();
-    mReactQueueConfiguration.destroy();
+      synchronouslyDisposeBridgeOnJSThread();
+      mReactQueueConfiguration.destroy();
+    }
     boolean wasIdle = (mPendingJSCalls.getAndSet(0) == 0);
     if (!wasIdle && !mBridgeIdleListeners.isEmpty()) {
       for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java
index c088de3a6bc8..89b6870bec7a 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java
@@ -79,7 +79,7 @@ private native void initialize(
    */
   public native void loadScriptFromAssets(AssetManager assetManager, String assetName);
   public native void loadScriptFromFile(@Nullable String fileName, @Nullable String sourceURL);
-  public native void callFunction(int moduleId, int methodId, NativeArray arguments);
+  public native void callFunction(int moduleId, int methodId, NativeArray arguments, String tracingName);
   public native void invokeCallback(int callbackID, NativeArray arguments);
   public native void setGlobalVariable(String propertyName, String jsonEncodedArgument);
   public native boolean supportsProfiling();
diff --git a/ReactAndroid/src/main/jni/react/Bridge.cpp b/ReactAndroid/src/main/jni/react/Bridge.cpp
index fe835fa51fba..1c1a2bf34dda 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.cpp
+++ b/ReactAndroid/src/main/jni/react/Bridge.cpp
@@ -5,14 +5,18 @@
 #ifdef WITH_FBSYSTRACE
 #include <fbsystrace.h>
 using fbsystrace::FbSystraceSection;
+using fbsystrace::FbSystraceAsyncFlow;
 #endif
 
+#include "Platform.h"
+
 namespace facebook {
 namespace react {
 
 Bridge::Bridge(JSExecutorFactory* jsExecutorFactory, Callback callback) :
     m_callback(std::move(callback)),
-    m_destroyed(std::shared_ptr<bool>(new bool(false))) {
+    m_destroyed(std::make_shared<bool>(false)),
+    m_mainJSMessageQueueThread(MessageQueues::getCurrentMessageQueueThread()) {
     m_mainExecutor = jsExecutorFactory->createJSExecutor(this);
 }
 
@@ -33,24 +37,64 @@ void Bridge::loadApplicationUnbundle(
   m_mainExecutor->loadApplicationUnbundle(std::move(unbundle), startupCode, sourceURL);
 }
 
-void Bridge::callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) {
+void Bridge::callFunction(
+    const double moduleId,
+    const double methodId,
+    const folly::dynamic& arguments,
+    const std::string& tracingName) {
   if (*m_destroyed) {
     return;
   }
+
   #ifdef WITH_FBSYSTRACE
-  FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "Bridge.callFunction");
+  int systraceCookie = m_systraceCookie++;
+  FbSystraceAsyncFlow::begin(
+      TRACE_TAG_REACT_CXX_BRIDGE,
+      tracingName.c_str(),
+      systraceCookie);
   #endif
-  m_mainExecutor->callFunction(moduleId, methodId, arguments);
+  std::shared_ptr<bool> isDestroyed = m_destroyed;
+  m_mainJSMessageQueueThread->runOnQueue([=] () {
+    if (*isDestroyed) {
+      return;
+    }
+    #ifdef WITH_FBSYSTRACE
+    FbSystraceAsyncFlow::end(
+        TRACE_TAG_REACT_CXX_BRIDGE,
+        tracingName.c_str(),
+        systraceCookie);
+    FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, tracingName.c_str());
+    #endif
+    m_mainExecutor->callFunction(moduleId, methodId, arguments);
+  });
 }
 
 void Bridge::invokeCallback(const double callbackId, const folly::dynamic& arguments) {
   if (*m_destroyed) {
     return;
   }
+
   #ifdef WITH_FBSYSTRACE
-  FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "Bridge.invokeCallback");
+  int systraceCookie = m_systraceCookie++;
+  FbSystraceAsyncFlow::begin(
+      TRACE_TAG_REACT_CXX_BRIDGE,
+      "<callback>",
+      systraceCookie);
   #endif
-  m_mainExecutor->invokeCallback(callbackId, arguments);
+  std::shared_ptr<bool> isDestroyed = m_destroyed;
+  m_mainJSMessageQueueThread->runOnQueue([=] () {
+    if (*isDestroyed) {
+      return;
+    }
+    #ifdef WITH_FBSYSTRACE
+    FbSystraceAsyncFlow::end(
+        TRACE_TAG_REACT_CXX_BRIDGE,
+        "<callback>",
+        systraceCookie);
+    FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "Bridge.invokeCallback");
+    #endif
+    m_mainExecutor->invokeCallback(callbackId, arguments);
+  });
 }
 
 void Bridge::setGlobalVariable(const std::string& propName, const std::string& jsonValue) {
diff --git a/ReactAndroid/src/main/jni/react/Bridge.h b/ReactAndroid/src/main/jni/react/Bridge.h
index 1833ccba4e0c..3868d507ff73 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.h
+++ b/ReactAndroid/src/main/jni/react/Bridge.h
@@ -2,11 +2,13 @@
 
 #pragma once
 
+#include <atomic>
 #include <functional>
 #include <map>
 #include <vector>
 
 #include "Executor.h"
+#include "MessageQueueThread.h"
 #include "MethodCall.h"
 #include "JSModulesUnbundle.h"
 #include "Value.h"
@@ -24,6 +26,9 @@ class Bridge {
 public:
   typedef std::function<void(std::vector<MethodCall>, bool isEndOfBatch)> Callback;
 
+  /**
+   * This must be called on the main JS thread.
+   */
   Bridge(JSExecutorFactory* jsExecutorFactory, Callback callback);
   virtual ~Bridge();
 
@@ -31,7 +36,11 @@ class Bridge {
    * Executes a function with the module ID and method ID and any additional
    * arguments in JS.
    */
-  void callFunction(const double moduleId, const double methodId, const folly::dynamic& args);
+  void callFunction(
+    const double moduleId,
+    const double methodId,
+    const folly::dynamic& args,
+    const std::string& tracingName);
 
   /**
    * Invokes a callback with the cbID, and optional additional arguments in JS.
@@ -72,6 +81,10 @@ class Bridge {
   // will have been destroyed within ~Bridge(), thus causing a SIGSEGV.
   std::shared_ptr<bool> m_destroyed;
   std::unique_ptr<JSExecutor> m_mainExecutor;
+  std::shared_ptr<MessageQueueThread> m_mainJSMessageQueueThread;
+  #ifdef WITH_FBSYSTRACE
+  std::atomic_uint_least32_t m_systraceCookie = ATOMIC_VAR_INIT();
+  #endif
 };
 
 } }
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 1e4c37950352..1a4dbe3c17da 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -727,14 +727,15 @@ static void loadScriptFromFile(JNIEnv* env, jobject obj, jstring fileName, jstri
 }
 
 static void callFunction(JNIEnv* env, jobject obj, jint moduleId, jint methodId,
-                         NativeArray::jhybridobject args) {
+                         NativeArray::jhybridobject args, jstring tracingName) {
   auto bridge = extractRefPtr<CountableBridge>(env, obj);
   auto arguments = cthis(wrap_alias(args));
   try {
     bridge->callFunction(
       (double) moduleId,
       (double) methodId,
-      std::move(arguments->array)
+      std::move(arguments->array),
+      fromJString(env, tracingName)
     );
   } catch (...) {
     translatePendingCppExceptionToJavaException();

From 9d1abf0cd54751e18d62d958569df81695f53b7e Mon Sep 17 00:00:00 2001
From: Frank Yan <frankyan@fb.com>
Date: Tue, 23 Feb 2016 16:11:55 -0800
Subject: [PATCH 1270/1411] Add the latest FIG colors to React Native color
 palette

Reviewed By: weicool

Differential Revision: D2965103

fb-gh-sync-id: 104d524af0547895ff976bcf4d68f199f1b6537b
shipit-source-id: 104d524af0547895ff976bcf4d68f199f1b6537b
---
 Libraries/Utilities/CSSVarConfig.js | 51 ++++++++++++++++++++++++++++-
 1 file changed, 50 insertions(+), 1 deletion(-)

diff --git a/Libraries/Utilities/CSSVarConfig.js b/Libraries/Utilities/CSSVarConfig.js
index d3177310ce9b..69f83c14e293 100644
--- a/Libraries/Utilities/CSSVarConfig.js
+++ b/Libraries/Utilities/CSSVarConfig.js
@@ -8,6 +8,56 @@
 // this a partial list of the constants in CSSConstants:: from PHP that are applicable to mobile
 
 module.exports = {
+  // FIG UI Core
+  'fbui-blue': '#4267b2',
+  'fbui-accent': '#4080ff',
+  'fbui-highlight': '#ecf3ff',
+  'fbui-green': '#4bc832',
+  'fbui-red': '#fa3e3e',
+  'fbui-white': '#ffffff',
+  'fbui-black': '#000000',
+
+  // FIG UI Light
+  'fbui-light-02': '#f6f7f9',
+  'fbui-light-05': '#e9ebee',
+  'fbui-light-10': '#dddfe2',
+  'fbui-light-15': '#ced0d4',
+  'fbui-light-20': '#bec2c9',
+  'fbui-light-30': '#90949c',
+  'fbui-light-50': '#4b4f56',
+  'fbui-light-80': '#1d2129',
+
+  // FIG UI Alpha
+  'fbui-white-alpha-15': 'rgba(255, 255, 255, .15)',
+  'fbui-white-alpha-30': 'rgba(255, 255, 255, .3)',
+  'fbui-white-alpha-40': 'rgba(255, 255, 255, .4)',
+  'fbui-white-alpha-50': 'rgba(255, 255, 255, .5)',
+  'fbui-white-alpha-80': 'rgba(255, 255, 255, .8)',
+  'fbui-black-alpha-15': 'rgba(0, 0, 0, .15)',
+  'fbui-black-alpha-30': 'rgba(0, 0, 0, .3)',
+  'fbui-black-alpha-40': 'rgba(0, 0, 0, .4)',
+  'fbui-black-alpha-50': 'rgba(0, 0, 0, .5)',
+  'fbui-black-alpha-80': 'rgba(0, 0, 0, .8)',
+
+  // FB UI Dark
+  'fbui-dark-20': '#cccccc',
+  'fbui-dark-50': '#7f7f7f',
+  'fbui-dark-70': '#4c4c4c',
+  'fbui-dark-80': '#333333',
+  'fbui-dark-85': '#262626',
+  'fbui-dark-90': '#191919',
+  'fbui-dark-95': '#0d0d0d',
+
+  // FIG UI Core - Blue variants
+  'fbui-blue-dark-1': '#29487d',
+  'fbui-blue-dark-2': '#20375f',
+  'fbui-blue-dark-3': '#162643',
+  'fbui-blue-tint-15': '#577fbc',
+  'fbui-blue-tint-30': '#7596c8',
+  'fbui-blue-tint-50': '#9cb4d8',
+  'fbui-blue-tint-70': '#c4d2e7',
+  'fbui-blue-tint-90': '#ecf0f7',
+
   'fbui-accent-blue': '#5890ff',
   'fbui-blue-90': '#4e69a2',
   'fbui-blue-80': '#627aad',
@@ -53,7 +103,6 @@ module.exports = {
   'fbui-gray-10': '#e5e5e5',
   'fbui-gray-5': '#f2f2f2',
   'fbui-gray-2': '#fafafa',
-  'fbui-red': '#da2929',
   'fbui-error': '#ce0d24',
   'x-mobile-dark-text': '#4e5665',
   'x-mobile-medium-text': '#6a7180',

From 9951e1ab04f4e4e78c14fcd6e002269e2a2f159e Mon Sep 17 00:00:00 2001
From: Kureev Alexey <kureev-mail@ya.ru>
Date: Tue, 23 Feb 2016 19:38:51 -0800
Subject: [PATCH 1271/1411] Introduce disabling for Touchable* elements

Summary:Introduce a `disabled` property for Touchable* components.

Fix https://github.com/facebook/react-native/issues/2103
Closes https://github.com/facebook/react-native/pull/5931

Differential Revision: D2969790

Pulled By: mkonicek

fb-gh-sync-id: 570a4ff882219f52f2d2ebef3eb73b1df50a0877
shipit-source-id: 570a4ff882219f52f2d2ebef3eb73b1df50a0877
---
 Examples/UIExplorer/TouchableExample.js       | 53 +++++++++++++++++++
 Libraries/Components/Touchable/Touchable.js   |  2 +-
 .../Touchable/TouchableWithoutFeedback.js     |  4 ++
 3 files changed, 58 insertions(+), 1 deletion(-)

diff --git a/Examples/UIExplorer/TouchableExample.js b/Examples/UIExplorer/TouchableExample.js
index 377a6ce48f90..0d2116a86b92 100644
--- a/Examples/UIExplorer/TouchableExample.js
+++ b/Examples/UIExplorer/TouchableExample.js
@@ -100,6 +100,13 @@ exports.examples = [
    render: function(): ReactElement {
      return <TouchableHitSlop />;
    },
+ }, {
+   title: 'Disabled Touchable*',
+   description: '<Touchable*> components accept disabled prop which prevents ' +
+     'any interaction with component',
+   render: function(): ReactElement {
+     return <TouchableDisabled />;
+   },
  }];
 
 var TextOnPressBox = React.createClass({
@@ -292,6 +299,45 @@ var TouchableHitSlop = React.createClass({
   }
 });
 
+var TouchableDisabled = React.createClass({
+  render: function() {
+    return (
+      <View>
+        <TouchableOpacity disabled={true} style={[styles.row, styles.block]}>
+          <Text style={styles.disabledButton}>Disabled TouchableOpacity</Text>
+        </TouchableOpacity>
+
+        <TouchableOpacity disabled={false} style={[styles.row, styles.block]}>
+          <Text style={styles.button}>Enabled TouchableOpacity</Text>
+        </TouchableOpacity>
+
+        <TouchableHighlight
+          activeOpacity={1}
+          disabled={true}
+          animationVelocity={0}
+          underlayColor="rgb(210, 230, 255)"
+          style={[styles.row, styles.block]}
+          onPress={() => console.log('custom THW text - hightlight')}>
+          <Text style={styles.disabledButton}>
+            Disabled TouchableHighlight
+          </Text>
+        </TouchableHighlight>
+
+        <TouchableHighlight
+          activeOpacity={1}
+          animationVelocity={0}
+          underlayColor="rgb(210, 230, 255)"
+          style={[styles.row, styles.block]}
+          onPress={() => console.log('custom THW text - hightlight')}>
+          <Text style={styles.button}>
+            Disabled TouchableHighlight
+          </Text>
+        </TouchableHighlight>
+      </View>
+    );
+  }
+});
+
 var heartImage = {uri: 'https://pbs.twimg.com/media/BlXBfT3CQAA6cVZ.png:small'};
 
 var styles = StyleSheet.create({
@@ -310,9 +356,16 @@ var styles = StyleSheet.create({
   text: {
     fontSize: 16,
   },
+  block: {
+    padding: 10,
+  },
   button: {
     color: '#007AFF',
   },
+  disabledButton: {
+    color: '#007AFF',
+    opacity: 0.5,
+  },
   hitSlopButton: {
     color: 'white',
   },
diff --git a/Libraries/Components/Touchable/Touchable.js b/Libraries/Components/Touchable/Touchable.js
index 6622ce8ad5ae..83b07248a7f8 100644
--- a/Libraries/Components/Touchable/Touchable.js
+++ b/Libraries/Components/Touchable/Touchable.js
@@ -337,7 +337,7 @@ var TouchableMixin = {
    * Must return true to start the process of `Touchable`.
    */
   touchableHandleStartShouldSetResponder: function() {
-    return true;
+    return !this.props.disabled;
   },
 
   /**
diff --git a/Libraries/Components/Touchable/TouchableWithoutFeedback.js b/Libraries/Components/Touchable/TouchableWithoutFeedback.js
index 1108c21e0bee..3b67ed00e2d0 100755
--- a/Libraries/Components/Touchable/TouchableWithoutFeedback.js
+++ b/Libraries/Components/Touchable/TouchableWithoutFeedback.js
@@ -44,6 +44,10 @@ var TouchableWithoutFeedback = React.createClass({
       React.PropTypes.oneOf(View.AccessibilityTraits),
       React.PropTypes.arrayOf(React.PropTypes.oneOf(View.AccessibilityTraits)),
     ]),
+    /**
+     * If true, disable all interactions for this component.
+     */
+    disabled: React.PropTypes.bool,
     /**
      * Called when the touch is released, but not if cancelled (e.g. by a scroll
      * that steals the responder lock).

From ecfd4f854ba3b40c71152855a3acc63e091a5704 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@gmail.com>
Date: Wed, 24 Feb 2016 10:01:37 +0000
Subject: [PATCH 1272/1411] patch commit that was not synced from fbsource

This one was not synced correctly https://phabricator.fb.com/rFAaebd840baa045b25f7c6641a0657b3cb1a01ba78
---
 ReactAndroid/DEFS | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/DEFS b/ReactAndroid/DEFS
index 1ba010a93988..d9b53b5017a6 100644
--- a/ReactAndroid/DEFS
+++ b/ReactAndroid/DEFS
@@ -24,6 +24,16 @@ def react_native_integration_tests_target(path):
 def react_native_dep(path):
   return '//ReactAndroid/src/main/' + path
 
+JSC_DEPS = [
+  '//native/third-party/jsc:jsc',
+  '//native/third-party/jsc:jsc_legacy_profiler',
+]
+
+JSC_INTERNAL_DEPS = [
+  '//native/third-party/jsc-internal:jsc',
+  '//native/third-party/jsc-internal:jsc_legacy_profiler',
+]
+
 INTERNAL_APP = 'PUBLIC'
 
 # React property preprocessor
@@ -86,4 +96,4 @@ def robolectric3_test(name, deps, vm_args=None, *args, **kwargs):
     vm_args=vm_args + extra_vm_args,
     *args,
     **kwargs
-  )
\ No newline at end of file
+  )

From 4cd1947d3019a264da3c471c20b3c719c8f693df Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@gmail.com>
Date: Wed, 24 Feb 2016 10:09:50 +0000
Subject: [PATCH 1273/1411] manual file sync for oss sync bot


From 25e1180b33c0ba26b21c9e760296ab6dd7a82249 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@gmail.com>
Date: Wed, 24 Feb 2016 10:13:01 +0000
Subject: [PATCH 1274/1411] manual file sync for oss sync bot


From 96ecfade116ec3c35ff01965843b8b9cc1d00bda Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@gmail.com>
Date: Wed, 24 Feb 2016 10:13:35 +0000
Subject: [PATCH 1275/1411] manual file sync for oss sync bot

---
 ReactAndroid/DEFS | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ReactAndroid/DEFS b/ReactAndroid/DEFS
index d9b53b5017a6..032570a63755 100644
--- a/ReactAndroid/DEFS
+++ b/ReactAndroid/DEFS
@@ -1,5 +1,5 @@
 # Helpers for referring to React Native open source code.
-#
+# test
 # This lets us build React Native:
 # - At Facebook by running buck from the root of the fb repo
 # - Outside of Facebook by running buck in the root of the git repo

From a759131ca16d16e325d7a72dd61ba0dcb522e5d0 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Wed, 24 Feb 2016 10:17:56 +0000
Subject: [PATCH 1276/1411] another patch hoping to fix chronos

---
 ReactAndroid/DEFS | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/DEFS b/ReactAndroid/DEFS
index 032570a63755..f9f43995ea80 100644
--- a/ReactAndroid/DEFS
+++ b/ReactAndroid/DEFS
@@ -1,5 +1,5 @@
 # Helpers for referring to React Native open source code.
-# test
+#
 # This lets us build React Native:
 # - At Facebook by running buck from the root of the fb repo
 # - Outside of Facebook by running buck in the root of the git repo
@@ -96,4 +96,4 @@ def robolectric3_test(name, deps, vm_args=None, *args, **kwargs):
     vm_args=vm_args + extra_vm_args,
     *args,
     **kwargs
-  )
+  )
\ No newline at end of file

From 11843fd10ebb4f4fa670ee635b7a8a5d4d7d2cfc Mon Sep 17 00:00:00 2001
From: Chris Hopman <cjhopman@fb.com>
Date: Tue, 23 Feb 2016 20:05:46 -0800
Subject: [PATCH 1277/1411] Initialize glog in react native.

Reviewed By: mhorowitz

Differential Revision: D2967180

fb-gh-sync-id: fe59b7f7c7dab8b5e7f3a449e72b467e1c2c2c67
shipit-source-id: fe59b7f7c7dab8b5e7f3a449e72b467e1c2c2c67
---
 ReactAndroid/DEFS                             |   5 +-
 .../jni/first-party/fbgloginit/Android.mk     |  24 +++
 .../src/main/jni/first-party/fbgloginit/BUCK  |  20 +++
 .../jni/first-party/fbgloginit/fb/glog_init.h |  11 ++
 .../jni/first-party/fbgloginit/glog_init.cpp  | 142 ++++++++++++++++++
 .../src/main/jni/react/jni/Android.mk         |   3 +-
 ReactAndroid/src/main/jni/react/jni/BUCK      |   1 +
 .../src/main/jni/react/jni/OnLoad.cpp         |   2 +
 8 files changed, 205 insertions(+), 3 deletions(-)
 create mode 100644 ReactAndroid/src/main/jni/first-party/fbgloginit/Android.mk
 create mode 100644 ReactAndroid/src/main/jni/first-party/fbgloginit/BUCK
 create mode 100644 ReactAndroid/src/main/jni/first-party/fbgloginit/fb/glog_init.h
 create mode 100644 ReactAndroid/src/main/jni/first-party/fbgloginit/glog_init.cpp

diff --git a/ReactAndroid/DEFS b/ReactAndroid/DEFS
index f9f43995ea80..104c161896f5 100644
--- a/ReactAndroid/DEFS
+++ b/ReactAndroid/DEFS
@@ -6,7 +6,6 @@
 
 import os
 
-
 # Example: react_native_target('java/com/facebook/react/common:common')
 def react_native_target(path):
   return '//ReactAndroid/src/main/' + path
@@ -34,6 +33,8 @@ JSC_INTERNAL_DEPS = [
   '//native/third-party/jsc-internal:jsc_legacy_profiler',
 ]
 
+FBGLOGINIT_TARGET = '//ReactAndroid/src/main/jni/first-party/fbgloginit:fbgloginit'
+
 INTERNAL_APP = 'PUBLIC'
 
 # React property preprocessor
@@ -96,4 +97,4 @@ def robolectric3_test(name, deps, vm_args=None, *args, **kwargs):
     vm_args=vm_args + extra_vm_args,
     *args,
     **kwargs
-  )
\ No newline at end of file
+  )
diff --git a/ReactAndroid/src/main/jni/first-party/fbgloginit/Android.mk b/ReactAndroid/src/main/jni/first-party/fbgloginit/Android.mk
new file mode 100644
index 000000000000..6d08079a7ebc
--- /dev/null
+++ b/ReactAndroid/src/main/jni/first-party/fbgloginit/Android.mk
@@ -0,0 +1,24 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+       glog_init.cpp
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
+
+LOCAL_CFLAGS := -fexceptions -fno-omit-frame-pointer
+LOCAL_CFLAGS += -Wall -Werror
+
+CXX11_FLAGS := -std=gnu++11
+LOCAL_CFLAGS += $(CXX11_FLAGS)
+
+LOCAL_EXPORT_CPPFLAGS := $(CXX11_FLAGS)
+
+LOCAL_LDLIBS := -llog
+
+LOCAL_SHARED_LIBRARIES := libglog
+
+LOCAL_MODULE := libglog_init
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/ReactAndroid/src/main/jni/first-party/fbgloginit/BUCK b/ReactAndroid/src/main/jni/first-party/fbgloginit/BUCK
new file mode 100644
index 000000000000..18ff2fbb4b30
--- /dev/null
+++ b/ReactAndroid/src/main/jni/first-party/fbgloginit/BUCK
@@ -0,0 +1,20 @@
+cxx_library(
+  name = 'fbgloginit',
+  force_static = True,
+  srcs = [
+    'glog_init.cpp',
+  ],
+  exported_headers = ['fb/glog_init.h'],
+  compiler_flags = [
+    '-fexceptions',
+    '-fno-omit-frame-pointer',
+  ],
+  linker_flags = [
+    '-llog',
+  ],
+  deps=[
+    '//xplat/third-party/glog:glog',
+  ],
+  visibility=['PUBLIC'],
+)
+
diff --git a/ReactAndroid/src/main/jni/first-party/fbgloginit/fb/glog_init.h b/ReactAndroid/src/main/jni/first-party/fbgloginit/fb/glog_init.h
new file mode 100644
index 000000000000..311f703500ae
--- /dev/null
+++ b/ReactAndroid/src/main/jni/first-party/fbgloginit/fb/glog_init.h
@@ -0,0 +1,11 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+#include <string>
+
+namespace facebook { namespace gloginit {
+
+void initialize(const char* tag = "ReactNativeJNI");
+
+}}
diff --git a/ReactAndroid/src/main/jni/first-party/fbgloginit/glog_init.cpp b/ReactAndroid/src/main/jni/first-party/fbgloginit/glog_init.cpp
new file mode 100644
index 000000000000..771516a2dcdf
--- /dev/null
+++ b/ReactAndroid/src/main/jni/first-party/fbgloginit/glog_init.cpp
@@ -0,0 +1,142 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#include "fb/glog_init.h"
+
+#include <iostream>
+#include <mutex>
+#include <stdexcept>
+
+#include <glog/logging.h>
+
+#ifdef __ANDROID__
+
+#include <android/log.h>
+
+static int toAndroidLevel(google::LogSeverity severity) {
+  switch (severity) {
+  case google::GLOG_INFO:
+    return ANDROID_LOG_INFO;
+  case google::GLOG_WARNING:
+    return ANDROID_LOG_WARN;
+  case google::GLOG_ERROR:
+    return ANDROID_LOG_ERROR;
+  case google::GLOG_FATAL:
+    return ANDROID_LOG_FATAL;
+  default:
+    return ANDROID_LOG_FATAL;
+  }
+}
+
+/**
+ * Sends GLog output to adb logcat.
+ */
+class LogcatSink : public google::LogSink {
+ public:
+  void send(
+      google::LogSeverity severity,
+      const char* full_filename,
+      const char* base_filename,
+      int line,
+      const struct ::tm* tm_time,
+      const char* message,
+      size_t message_len) override {
+    auto level = toAndroidLevel(severity);
+    __android_log_print(
+        level,
+        base_filename,
+        "%.*s",
+        (int)message_len,
+        message);
+  }
+};
+
+/**
+ * Sends GLog output to adb logcat.
+ */
+class TaggedLogcatSink : public google::LogSink {
+  const std::string tag_;
+
+ public:
+  TaggedLogcatSink(const std::string &tag) : tag_{tag} {}
+
+  void send(
+      google::LogSeverity severity,
+      const char* full_filename,
+      const char* base_filename,
+      int line,
+      const struct ::tm* tm_time,
+      const char* message,
+      size_t message_len) override {
+    auto level = toAndroidLevel(severity);
+    __android_log_print(
+      level,
+      tag_.c_str(),
+      "%.*s",
+      (int)message_len,
+      message);
+  }
+};
+
+static google::LogSink* make_sink(const std::string& tag) {
+  if (tag.empty()) {
+    return new LogcatSink{};
+  } else {
+    return new TaggedLogcatSink{tag};
+  }
+}
+
+static void sendGlogOutputToLogcat(const char* tag) {
+  google::AddLogSink(make_sink(tag));
+
+  // Disable logging to files
+  for (auto i = 0; i < google::NUM_SEVERITIES; ++i) {
+    google::SetLogDestination(i, "");
+  }
+}
+
+#endif // __ANDROID__
+
+static void lastResort(const char* tag, const char* msg, const char* arg = nullptr) {
+#ifdef __ANDROID__
+  if (!arg) {
+    __android_log_write(ANDROID_LOG_ERROR, tag, msg);
+  } else {
+    __android_log_print(ANDROID_LOG_ERROR, tag, "%s: %s", msg, arg);
+  }
+#else 
+  std::cerr << msg;
+  if (arg) {
+    std::cerr << ": " << arg;
+  }
+  std::cerr << std::endl;
+#endif
+}
+
+namespace facebook { namespace gloginit {
+
+void initialize(const char* tag) {
+  static std::once_flag flag{};
+  static auto failed = false;
+
+  std::call_once(flag, [tag] {
+    try {
+      google::InitGoogleLogging(tag);
+
+#ifdef __ANDROID__
+      sendGlogOutputToLogcat(tag);
+#endif
+    } catch (std::exception& ex) {
+      lastResort(tag, "Failed to initialize glog", ex.what());
+      failed = true;
+    } catch (...) {
+      lastResort(tag, "Failed to initialize glog");
+      failed = true;
+    }
+  });
+
+  if (failed) {
+    throw std::runtime_error{"Failed to initialize glog"};
+  }
+}
+
+}}
diff --git a/ReactAndroid/src/main/jni/react/jni/Android.mk b/ReactAndroid/src/main/jni/react/jni/Android.mk
index 9d4d9b2b5fff..e5184d8e81fa 100644
--- a/ReactAndroid/src/main/jni/react/jni/Android.mk
+++ b/ReactAndroid/src/main/jni/react/jni/Android.mk
@@ -22,7 +22,7 @@ LOCAL_CFLAGS += $(CXX11_FLAGS)
 LOCAL_EXPORT_CPPFLAGS := $(CXX11_FLAGS)
 
 LOCAL_LDLIBS += -landroid
-LOCAL_SHARED_LIBRARIES := libfolly_json libfbjni libjsc
+LOCAL_SHARED_LIBRARIES := libfolly_json libfbjni libjsc libglog_init
 LOCAL_STATIC_LIBRARIES := libreactnative
 
 include $(BUILD_SHARED_LIBRARY)
@@ -30,5 +30,6 @@ include $(BUILD_SHARED_LIBRARY)
 $(call import-module,react)
 $(call import-module,jsc)
 $(call import-module,folly)
+$(call import-module,fbgloginit)
 $(call import-module,jni)
 $(call import-module,jsc)
diff --git a/ReactAndroid/src/main/jni/react/jni/BUCK b/ReactAndroid/src/main/jni/react/jni/BUCK
index bebdf54ce2a3..830a38e0c696 100644
--- a/ReactAndroid/src/main/jni/react/jni/BUCK
+++ b/ReactAndroid/src/main/jni/react/jni/BUCK
@@ -4,6 +4,7 @@ include_defs('//ReactAndroid/DEFS')
 SUPPORTED_PLATFORMS = '^android-(armv7|x86)$'
 
 DEPS = [
+  FBGLOGINIT_TARGET,
   '//native/jni:jni',
   '//native/third-party/android-ndk:android',
   '//xplat/folly:molly',
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 1a4dbe3c17da..0cb6f5bc1c3c 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -3,6 +3,7 @@
 #include <android/asset_manager_jni.h>
 #include <android/input.h>
 #include <fb/log.h>
+#include <fb/glog_init.h>
 #include <folly/json.h>
 #include <jni/Countable.h>
 #include <jni/Environment.h>
@@ -845,6 +846,7 @@ jmethodID getLogMarkerMethod() {
 
 extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
   return initialize(vm, [] {
+    facebook::gloginit::initialize();
     // Inject some behavior into react/
     ReactMarker::logMarker = bridge::logMarker;
     WebWorkerUtil::createWebWorkerThread = WebWorkers::createWebWorkerThread;

From 9ae3714f4bebdd2bcab4d7fdbf23acebdc5ed2ba Mon Sep 17 00:00:00 2001
From: Geoffrey Goh <kg422@cornell.edu>
Date: Wed, 24 Feb 2016 03:11:08 -0800
Subject: [PATCH 1278/1411] Create offline package if not running in "Debug"
 config

Summary:**Problem**: As seen in https://github.com/facebook/react-native/issues/5820, many devs are confused by the fact that the offline bundle is not generated when running against the simulator, even when running in the "Release" configuration which is supposed to mimic "production" scenarios.

This pull request is a small change that fixes https://github.com/facebook/react-native/issues/5820 by updating the `react-native-xcode.sh` shell script to still generate the ofline bundle during Release configuration. It also updates `AppDelegate.m` to better document this behaviour in the comments so as to avoid any surprises.

**Test plan**: This is a simple change, the two tests done were
1. In a new React Native project, verify that an offline build is not generated when running against the simulator in "Debug" configuration as per normal.
2. Change to a "Release" configuration via Product > Scheme > Edit Scheme in XCode, then verify that the project runs with the offline build generated.

![screen shot 2016-02
Closes https://github.com/facebook/react-native/pull/6119

Differential Revision: D2970755

Pulled By: javache

fb-gh-sync-id: 64f658512869c73aa19286ca1e3dc6e31b5ac617
shipit-source-id: 64f658512869c73aa19286ca1e3dc6e31b5ac617
---
 .../generator-ios/templates/app/AppDelegate.m      |  4 +++-
 packager/react-native-xcode.sh                     | 14 +++++++-------
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/local-cli/generator-ios/templates/app/AppDelegate.m b/local-cli/generator-ios/templates/app/AppDelegate.m
index 6cf213bd4cbd..909092b9cc75 100644
--- a/local-cli/generator-ios/templates/app/AppDelegate.m
+++ b/local-cli/generator-ios/templates/app/AppDelegate.m
@@ -36,7 +36,9 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
   /**
    * OPTION 2
    * Load from pre-bundled file on disk. The static bundle is automatically
-   * generated by "Bundle React Native code and images" build step.
+   * generated by the "Bundle React Native code and images" build step when
+   * running the project on an actual device or running the project on the
+   * simulator in the "Release" build configuration.
    */
 
 //   jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
diff --git a/packager/react-native-xcode.sh b/packager/react-native-xcode.sh
index 66ecea85464c..9e6ffbe438c9 100755
--- a/packager/react-native-xcode.sh
+++ b/packager/react-native-xcode.sh
@@ -10,15 +10,15 @@
 # This script is supposed to be invoked as part of Xcode build process
 # and relies on environment variables (including PWD) set by Xcode
 
-# There is no point in creating an offline package for simulator builds
-# because the packager is supposed to be running during development anyways
-if [[ "$PLATFORM_NAME" = "iphonesimulator" ]]; then
-  echo "Skipping bundling for Simulator platform"
-  exit 0;
-fi
-
 case "$CONFIGURATION" in
   Debug)
+    # Speed up build times by skipping the creation of the offline package for debug
+    # builds on the simulator since the packager is supposed to be running anyways.
+    if [[ "$PLATFORM_NAME" = "iphonesimulator" ]]; then		
+      echo "Skipping bundling for Simulator platform"		
+      exit 0;		
+    fi
+    
     DEV=true
     ;;
   "")

From ec173b1a1767aa52cf85fe652044d19264def699 Mon Sep 17 00:00:00 2001
From: Andreas Drivenes <andreas.drivenes@gmail.com>
Date: Wed, 24 Feb 2016 03:24:50 -0800
Subject: [PATCH 1279/1411] Add drawerLockMode prop to DrawerLayoutAndroid

Summary:Closes #5270.
Closes https://github.com/facebook/react-native/pull/5534

Differential Revision: D2970771

fb-gh-sync-id: 36a814032283df7d4c469964f803b8d20d1b0c93
shipit-source-id: 36a814032283df7d4c469964f803b8d20d1b0c93
---
 .../DrawerAndroid/DrawerLayoutAndroid.android.js   | 14 ++++++++++++++
 .../views/drawer/ReactDrawerLayoutManager.java     | 13 +++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js
index 4383f9f84d25..8bb5e12ed7c2 100644
--- a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js
+++ b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js
@@ -28,6 +28,7 @@ var INNERVIEW_REF = 'innerView';
 var DrawerLayoutValidAttributes = {
   drawerWidth: true,
   drawerPosition: true,
+  drawerLockMode: true
 };
 
 var DRAWER_STATES = [
@@ -95,6 +96,18 @@ var DrawerLayoutAndroid = React.createClass({
      * from the edge of the window.
      */
     drawerWidth: ReactPropTypes.number,
+    /**
+     * Specifies the lock mode of the drawer. The drawer can be locked in 3 states:
+     * - unlocked (default), meaning that the drawer will respond (open/close) to touch gestures.
+     * - locked closed, meaning that the drawer will stay closed and not respond to gestures.
+     * - locked open, meaning that the drawer will stay opened and not respond to gestures.
+     * The drawer may still be opened and closed programmatically (`openDrawer`/`closeDrawer`).
+     */
+    drawerLockMode: ReactPropTypes.oneOf([
+      'unlocked',
+      'locked-closed',
+      'locked-open'
+    ]),
     /**
      * Function called whenever there is an interaction with the navigation view.
      */
@@ -142,6 +155,7 @@ var DrawerLayoutAndroid = React.createClass({
         ref={RK_DRAWER_REF}
         drawerWidth={this.props.drawerWidth}
         drawerPosition={this.props.drawerPosition}
+        drawerLockMode={this.props.drawerLockMode}
         style={styles.base}
         onDrawerSlide={this._onDrawerSlide}
         onDrawerOpen={this._onDrawerOpen}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/drawer/ReactDrawerLayoutManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/drawer/ReactDrawerLayoutManager.java
index d1ec7f83128d..1926c110abcd 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/drawer/ReactDrawerLayoutManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/drawer/ReactDrawerLayoutManager.java
@@ -76,6 +76,19 @@ public void getDrawerWidth(ReactDrawerLayout view, float width) {
     view.setDrawerWidth(widthInPx);
   }
 
+  @ReactProp(name = "drawerLockMode")
+  public void setDrawerLockMode(ReactDrawerLayout view, @Nullable String drawerLockMode) {
+    if (drawerLockMode == null || "unlocked".equals(drawerLockMode)) {
+      view.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
+    } else if ("locked-closed".equals(drawerLockMode)) {
+      view.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
+    } else if ("locked-open".equals(drawerLockMode)) {
+      view.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);
+    } else {
+      throw new JSApplicationIllegalArgumentException("Unknown drawerLockMode " + drawerLockMode);
+    }
+  }
+
   @Override
   public boolean needsCustomLayoutForChildren() {
     // Return true, since DrawerLayout will lay out it's own children.

From 5c418655bf3423bff268aca670477a1ec8f5058e Mon Sep 17 00:00:00 2001
From: Jacob Turner <poppa.bear.joe@gmail.com>
Date: Wed, 24 Feb 2016 03:55:40 -0800
Subject: [PATCH 1280/1411] Remove duplicate register call

Summary:Hello!

As described in #3288, the `PushNotificationsIOS` `register` callback fires twice.  See that issue for discussion.

There wasn't any feedback on a proposed PR, so this is the first effort.  This change does make the register callback act as expected on my device.  I can make any changes necessary.

Thanks!
Closes https://github.com/facebook/react-native/pull/6111

Differential Revision: D2970806

Pulled By: nicklockwood

fb-gh-sync-id: a8d0b53210f85cc24b4befdb0e90af46512fa4fb
shipit-source-id: a8d0b53210f85cc24b4befdb0e90af46512fa4fb
---
 Libraries/PushNotificationIOS/RCTPushNotificationManager.m | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Libraries/PushNotificationIOS/RCTPushNotificationManager.m b/Libraries/PushNotificationIOS/RCTPushNotificationManager.m
index 86c9a37ad209..5dd5b4774464 100644
--- a/Libraries/PushNotificationIOS/RCTPushNotificationManager.m
+++ b/Libraries/PushNotificationIOS/RCTPushNotificationManager.m
@@ -182,7 +182,6 @@ - (void)handleRemoteNotificationsRegistered:(NSNotification *)notification
     UIUserNotificationSettings *notificationSettings =
       [UIUserNotificationSettings settingsForTypes:(NSUInteger)types categories:nil];
     [app registerUserNotificationSettings:notificationSettings];
-    [app registerForRemoteNotifications];
   } else {
     [app registerForRemoteNotificationTypes:(NSUInteger)types];
   }

From f7f3e7be38320b20e7d667f21a761f222a90994d Mon Sep 17 00:00:00 2001
From: Kureev Alexey <kureev-mail@ya.ru>
Date: Wed, 24 Feb 2016 04:34:12 -0800
Subject: [PATCH 1281/1411] Fix UIExample typos: hightlight -> highligh

Summary:Follow-up PR for fixing typos in #5931

**Test plan (required)**
This PR contains only copy changes, so no additional testing is required.

**Code formatting**

This PR code style match the desired [style guide](https://github.com/facebook/react-native/blob/master/CONTRIBUTING.md#style-guide).

cc mkonicek
Closes https://github.com/facebook/react-native/pull/6122

Differential Revision: D2970751

Pulled By: javache

fb-gh-sync-id: 007ab6e732e88f39c7f392f00b2bd668ebb4d7d5
shipit-source-id: 007ab6e732e88f39c7f392f00b2bd668ebb4d7d5
---
 Examples/UIExplorer/TouchableExample.js | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Examples/UIExplorer/TouchableExample.js b/Examples/UIExplorer/TouchableExample.js
index 0d2116a86b92..630df75ad0b0 100644
--- a/Examples/UIExplorer/TouchableExample.js
+++ b/Examples/UIExplorer/TouchableExample.js
@@ -55,7 +55,7 @@ exports.examples = [
             activeOpacity={1}
             animationVelocity={0}
             underlayColor="rgb(210, 230, 255)"
-            onPress={() => console.log('custom THW text - hightlight')}>
+            onPress={() => console.log('custom THW text - highlight')}>
             <View style={styles.wrapperCustom}>
               <Text style={styles.text}>
                 Tap Here For Custom Highlight!
@@ -317,7 +317,7 @@ var TouchableDisabled = React.createClass({
           animationVelocity={0}
           underlayColor="rgb(210, 230, 255)"
           style={[styles.row, styles.block]}
-          onPress={() => console.log('custom THW text - hightlight')}>
+          onPress={() => console.log('custom THW text - highlight')}>
           <Text style={styles.disabledButton}>
             Disabled TouchableHighlight
           </Text>
@@ -328,7 +328,7 @@ var TouchableDisabled = React.createClass({
           animationVelocity={0}
           underlayColor="rgb(210, 230, 255)"
           style={[styles.row, styles.block]}
-          onPress={() => console.log('custom THW text - hightlight')}>
+          onPress={() => console.log('custom THW text - highlight')}>
           <Text style={styles.button}>
             Disabled TouchableHighlight
           </Text>

From 21ee7fde6e6f3054fe15e77e3d61cacca2948608 Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieter.debaets@gmail.com>
Date: Wed, 24 Feb 2016 05:10:53 -0800
Subject: [PATCH 1282/1411] Fix mocks in NavigationExperimental

Summary:Fixes mocking in NavigationExperimental tests and manually mock React to make things pass
Closes https://github.com/facebook/react-native/pull/6124

Differential Revision: D2970955

fb-gh-sync-id: ece45f1193a23a39d49fb9c2f529e1d709189f31
shipit-source-id: ece45f1193a23a39d49fb9c2f529e1d709189f31
---
 .../Reducer/__tests__/NavigationFindReducer-test.js        | 3 +--
 .../Reducer/__tests__/NavigationStackReducer-test.js       | 7 +++++--
 .../Reducer/__tests__/NavigationTabsReducer-test.js        | 5 +++--
 .../__tests__/NavigationStateUtils-test.js                 | 3 +--
 4 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/Libraries/NavigationExperimental/Reducer/__tests__/NavigationFindReducer-test.js b/Libraries/NavigationExperimental/Reducer/__tests__/NavigationFindReducer-test.js
index e67e64f2e481..660e1c03ef94 100644
--- a/Libraries/NavigationExperimental/Reducer/__tests__/NavigationFindReducer-test.js
+++ b/Libraries/NavigationExperimental/Reducer/__tests__/NavigationFindReducer-test.js
@@ -11,8 +11,7 @@
 'use strict';
 
 jest
- .autoMockOff()
- .mock('ErrorUtils');
+ .dontMock('NavigationFindReducer');
 
 const NavigationFindReducer = require('NavigationFindReducer');
 
diff --git a/Libraries/NavigationExperimental/Reducer/__tests__/NavigationStackReducer-test.js b/Libraries/NavigationExperimental/Reducer/__tests__/NavigationStackReducer-test.js
index 400057ab04a2..9a0d50326c8e 100644
--- a/Libraries/NavigationExperimental/Reducer/__tests__/NavigationStackReducer-test.js
+++ b/Libraries/NavigationExperimental/Reducer/__tests__/NavigationStackReducer-test.js
@@ -11,8 +11,11 @@
 'use strict';
 
 jest
- .autoMockOff()
- .mock('ErrorUtils');
+ .dontMock('NavigationRootContainer')
+ .dontMock('NavigationStackReducer')
+ .dontMock('NavigationStateUtils');
+
+jest.setMock('React', {Component() {}, PropTypes: {}});
 
 const NavigationStackReducer = require('NavigationStackReducer');
 const NavigationRootContainer = require('NavigationRootContainer');
diff --git a/Libraries/NavigationExperimental/Reducer/__tests__/NavigationTabsReducer-test.js b/Libraries/NavigationExperimental/Reducer/__tests__/NavigationTabsReducer-test.js
index a39aa76bfd23..9228d0c7b976 100644
--- a/Libraries/NavigationExperimental/Reducer/__tests__/NavigationTabsReducer-test.js
+++ b/Libraries/NavigationExperimental/Reducer/__tests__/NavigationTabsReducer-test.js
@@ -11,8 +11,9 @@
 'use strict';
 
 jest
- .autoMockOff()
- .mock('ErrorUtils');
+ .dontMock('NavigationTabsReducer')
+ .dontMock('NavigationFindReducer')
+ .dontMock('NavigationStateUtils');
 
 const NavigationTabsReducer = require('NavigationTabsReducer');
 
diff --git a/Libraries/NavigationExperimental/__tests__/NavigationStateUtils-test.js b/Libraries/NavigationExperimental/__tests__/NavigationStateUtils-test.js
index 702d5937bb20..5b8cf98b5ba4 100644
--- a/Libraries/NavigationExperimental/__tests__/NavigationStateUtils-test.js
+++ b/Libraries/NavigationExperimental/__tests__/NavigationStateUtils-test.js
@@ -11,8 +11,7 @@
 'use strict';
 
 jest
- .autoMockOff()
- .mock('ErrorUtils');
+ .dontMock('NavigationStateUtils');
 
 var NavigationStateUtils = require('NavigationStateUtils');
 

From b4992efca9f63ba61fd544500adaedb3a7c46b9a Mon Sep 17 00:00:00 2001
From: Kureev Alexey <kureev-mail@ya.ru>
Date: Wed, 24 Feb 2016 05:25:51 -0800
Subject: [PATCH 1283/1411] Add disabled TouchableNativeFeedback button example

Summary:Follow-up PR for #5931: Adding missing `TouchableNativeFeedback` example.

**Test plan**

- Run UIExplorer on iOS and Android devices

[Android]
- Go to Touchable* examples and scroll down to the `Disabled Touchable*` section. There are two new buttons there: `Enabled TouchableNativeFeedback` and `Disabled TouchableNativeFeedback`. Buttons should behave according their titles.

[iOS]
- Go to Touchable* examples and scroll down to the `Disabled Touchable*` section. As far as `TouchableNativeFeedback` is supported on Android only, you **wouldn't see** any new buttons there

**Code formatting**

This PR code style match the desired [style guide](https://github.com/facebook/react-native/blob/master/CONTRIBUTING.md#style-guide).

cc mkonicek
Closes https://github.com/facebook/react-native/pull/6123

Differential Revision: D2971021

fb-gh-sync-id: 3be18bda15b5b495caaf9e4444fd0deb47a44839
shipit-source-id: 3be18bda15b5b495caaf9e4444fd0deb47a44839
---
 Examples/UIExplorer/TouchableExample.js | 33 +++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/Examples/UIExplorer/TouchableExample.js b/Examples/UIExplorer/TouchableExample.js
index 630df75ad0b0..5b28f2e134d4 100644
--- a/Examples/UIExplorer/TouchableExample.js
+++ b/Examples/UIExplorer/TouchableExample.js
@@ -24,6 +24,8 @@ var {
   TouchableHighlight,
   TouchableOpacity,
   UIManager,
+  Platform,
+  TouchableNativeFeedback,
   View,
 } = React;
 
@@ -333,6 +335,33 @@ var TouchableDisabled = React.createClass({
             Disabled TouchableHighlight
           </Text>
         </TouchableHighlight>
+
+        {Platform.OS === 'android' &&
+          <TouchableNativeFeedback
+            style={[styles.row, styles.block]}
+            onPress={() => console.log('custom TNF has been clicked')}
+            background={TouchableNativeFeedback.SelectableBackground()}>
+            <View>
+              <Text style={[styles.button, styles.nativeFeedbackButton]}>
+                Enabled TouchableNativeFeedback
+              </Text>
+            </View>
+          </TouchableNativeFeedback>
+        }
+
+        {Platform.OS === 'android' &&
+          <TouchableNativeFeedback
+            disabled={true}
+            style={[styles.row, styles.block]}
+            onPress={() => console.log('custom TNF has been clicked')}
+            background={TouchableNativeFeedback.SelectableBackground()}>
+            <View>
+              <Text style={[styles.disabledButton, styles.nativeFeedbackButton]}>
+                Disabled TouchableNativeFeedback
+              </Text>
+            </View>
+          </TouchableNativeFeedback>
+        }
       </View>
     );
   }
@@ -366,6 +395,10 @@ var styles = StyleSheet.create({
     color: '#007AFF',
     opacity: 0.5,
   },
+  nativeFeedbackButton: {
+    textAlign: 'center',
+    margin: 10,
+  },
   hitSlopButton: {
     color: 'white',
   },

From 9a70ff0263b742364dd58ad353686cbe268894b9 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Wed, 24 Feb 2016 05:40:20 -0800
Subject: [PATCH 1284/1411] Fix site generation

Summary: Doc site generation is broken becuase the script can't parse the UIManager file properly. Removing for now.

Reviewed By: bestander

Differential Revision: D2970814

fb-gh-sync-id: fb782fa6514d875f7e1c289548e82040a7646971
shipit-source-id: fb782fa6514d875f7e1c289548e82040a7646971
---
 website/server/extractDocs.js | 1 -
 1 file changed, 1 deletion(-)

diff --git a/website/server/extractDocs.js b/website/server/extractDocs.js
index b263a94a8363..b74c029b76c0 100644
--- a/website/server/extractDocs.js
+++ b/website/server/extractDocs.js
@@ -250,7 +250,6 @@ var apis = [
   '../Libraries/StyleSheet/StyleSheet.js',
   '../Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js',
   '../Libraries/Components/ToastAndroid/ToastAndroid.android.js',
-  '../Libraries/Utilities/UIManager.js',
   '../Libraries/Vibration/VibrationIOS.ios.js',
 ];
 

From b8850df31bb4ac99418623281604cab12b9d2a74 Mon Sep 17 00:00:00 2001
From: Xing Zheng <betree.x@gmail.com>
Date: Wed, 24 Feb 2016 06:19:28 -0800
Subject: [PATCH 1285/1411] typo with in code, replace date.toTime with
 date.getTime

Summary:There is no toTime method on a Date object, It should be getTime.
Closes https://github.com/facebook/react-native/pull/6054

Differential Revision: D2971217

fb-gh-sync-id: 4140be25f0704f251cc0e2f47db8fa83992dc0f0
shipit-source-id: 4140be25f0704f251cc0e2f47db8fa83992dc0f0
---
 docs/NativeModulesIOS.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/NativeModulesIOS.md b/docs/NativeModulesIOS.md
index a066d5e2b09f..db20eda09ca8 100644
--- a/docs/NativeModulesIOS.md
+++ b/docs/NativeModulesIOS.md
@@ -133,7 +133,7 @@ and call it from JavaScript:
 ```javascript
 CalendarManager.addEvent('Birthday Party', {
   location: '4 Privet Drive, Surrey',
-  time: date.toTime(),
+  time: date.getTime(),
   description: '...'
 })
 ```

From 36034794717c8a881f329e328bad277d04536ac1 Mon Sep 17 00:00:00 2001
From: Daniel Friesen <daniel@nadir-seen-fire.com>
Date: Wed, 24 Feb 2016 06:20:37 -0800
Subject: [PATCH 1286/1411] Fix Platform.Version documentation

Summary:Version exposes the sdk level (which TBH is more useful anyways), not a version string.
Closes https://github.com/facebook/react-native/pull/6068

Differential Revision: D2971198

fb-gh-sync-id: 0ba1e10e48b2ca51c7b0cebcc1ec13d0b69df783
shipit-source-id: 0ba1e10e48b2ca51c7b0cebcc1ec13d0b69df783
---
 docs/PlatformSpecificInformation.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/PlatformSpecificInformation.md b/docs/PlatformSpecificInformation.md
index 9c2f2e02f343..03aa48bf1acc 100644
--- a/docs/PlatformSpecificInformation.md
+++ b/docs/PlatformSpecificInformation.md
@@ -61,7 +61,7 @@ On Android, the Platform module can be also used to detect which is the version
 ```javascript
 var {Platform} = React;
 
-if(Platform.Version === '5.0'){
+if(Platform.Version === 21){
   console.log('Running on Lollipop!');
 }
-```
\ No newline at end of file
+```

From 936b5e794be3a09dbcfb2bab2629289dbe697ade Mon Sep 17 00:00:00 2001
From: Andrei Coman <andreic@fb.com>
Date: Wed, 24 Feb 2016 08:39:09 -0800
Subject: [PATCH 1287/1411] Backed out changeset fe59b7f7c7da

Reviewed By: javache

Differential Revision: D2971309

fb-gh-sync-id: 0104f5499d32e0a4e4bd24128c58a9ee4aa7ca4e
shipit-source-id: 0104f5499d32e0a4e4bd24128c58a9ee4aa7ca4e
---
 ReactAndroid/DEFS                             |   5 +-
 .../jni/first-party/fbgloginit/Android.mk     |  24 ---
 .../src/main/jni/first-party/fbgloginit/BUCK  |  20 ---
 .../jni/first-party/fbgloginit/fb/glog_init.h |  11 --
 .../jni/first-party/fbgloginit/glog_init.cpp  | 142 ------------------
 .../src/main/jni/react/jni/Android.mk         |   3 +-
 ReactAndroid/src/main/jni/react/jni/BUCK      |   1 -
 .../src/main/jni/react/jni/OnLoad.cpp         |   2 -
 8 files changed, 3 insertions(+), 205 deletions(-)
 delete mode 100644 ReactAndroid/src/main/jni/first-party/fbgloginit/Android.mk
 delete mode 100644 ReactAndroid/src/main/jni/first-party/fbgloginit/BUCK
 delete mode 100644 ReactAndroid/src/main/jni/first-party/fbgloginit/fb/glog_init.h
 delete mode 100644 ReactAndroid/src/main/jni/first-party/fbgloginit/glog_init.cpp

diff --git a/ReactAndroid/DEFS b/ReactAndroid/DEFS
index 104c161896f5..f9f43995ea80 100644
--- a/ReactAndroid/DEFS
+++ b/ReactAndroid/DEFS
@@ -6,6 +6,7 @@
 
 import os
 
+
 # Example: react_native_target('java/com/facebook/react/common:common')
 def react_native_target(path):
   return '//ReactAndroid/src/main/' + path
@@ -33,8 +34,6 @@ JSC_INTERNAL_DEPS = [
   '//native/third-party/jsc-internal:jsc_legacy_profiler',
 ]
 
-FBGLOGINIT_TARGET = '//ReactAndroid/src/main/jni/first-party/fbgloginit:fbgloginit'
-
 INTERNAL_APP = 'PUBLIC'
 
 # React property preprocessor
@@ -97,4 +96,4 @@ def robolectric3_test(name, deps, vm_args=None, *args, **kwargs):
     vm_args=vm_args + extra_vm_args,
     *args,
     **kwargs
-  )
+  )
\ No newline at end of file
diff --git a/ReactAndroid/src/main/jni/first-party/fbgloginit/Android.mk b/ReactAndroid/src/main/jni/first-party/fbgloginit/Android.mk
deleted file mode 100644
index 6d08079a7ebc..000000000000
--- a/ReactAndroid/src/main/jni/first-party/fbgloginit/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-       glog_init.cpp
-
-LOCAL_C_INCLUDES := $(LOCAL_PATH)
-LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
-
-LOCAL_CFLAGS := -fexceptions -fno-omit-frame-pointer
-LOCAL_CFLAGS += -Wall -Werror
-
-CXX11_FLAGS := -std=gnu++11
-LOCAL_CFLAGS += $(CXX11_FLAGS)
-
-LOCAL_EXPORT_CPPFLAGS := $(CXX11_FLAGS)
-
-LOCAL_LDLIBS := -llog
-
-LOCAL_SHARED_LIBRARIES := libglog
-
-LOCAL_MODULE := libglog_init
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/ReactAndroid/src/main/jni/first-party/fbgloginit/BUCK b/ReactAndroid/src/main/jni/first-party/fbgloginit/BUCK
deleted file mode 100644
index 18ff2fbb4b30..000000000000
--- a/ReactAndroid/src/main/jni/first-party/fbgloginit/BUCK
+++ /dev/null
@@ -1,20 +0,0 @@
-cxx_library(
-  name = 'fbgloginit',
-  force_static = True,
-  srcs = [
-    'glog_init.cpp',
-  ],
-  exported_headers = ['fb/glog_init.h'],
-  compiler_flags = [
-    '-fexceptions',
-    '-fno-omit-frame-pointer',
-  ],
-  linker_flags = [
-    '-llog',
-  ],
-  deps=[
-    '//xplat/third-party/glog:glog',
-  ],
-  visibility=['PUBLIC'],
-)
-
diff --git a/ReactAndroid/src/main/jni/first-party/fbgloginit/fb/glog_init.h b/ReactAndroid/src/main/jni/first-party/fbgloginit/fb/glog_init.h
deleted file mode 100644
index 311f703500ae..000000000000
--- a/ReactAndroid/src/main/jni/first-party/fbgloginit/fb/glog_init.h
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-#pragma once
-
-#include <string>
-
-namespace facebook { namespace gloginit {
-
-void initialize(const char* tag = "ReactNativeJNI");
-
-}}
diff --git a/ReactAndroid/src/main/jni/first-party/fbgloginit/glog_init.cpp b/ReactAndroid/src/main/jni/first-party/fbgloginit/glog_init.cpp
deleted file mode 100644
index 771516a2dcdf..000000000000
--- a/ReactAndroid/src/main/jni/first-party/fbgloginit/glog_init.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-#include "fb/glog_init.h"
-
-#include <iostream>
-#include <mutex>
-#include <stdexcept>
-
-#include <glog/logging.h>
-
-#ifdef __ANDROID__
-
-#include <android/log.h>
-
-static int toAndroidLevel(google::LogSeverity severity) {
-  switch (severity) {
-  case google::GLOG_INFO:
-    return ANDROID_LOG_INFO;
-  case google::GLOG_WARNING:
-    return ANDROID_LOG_WARN;
-  case google::GLOG_ERROR:
-    return ANDROID_LOG_ERROR;
-  case google::GLOG_FATAL:
-    return ANDROID_LOG_FATAL;
-  default:
-    return ANDROID_LOG_FATAL;
-  }
-}
-
-/**
- * Sends GLog output to adb logcat.
- */
-class LogcatSink : public google::LogSink {
- public:
-  void send(
-      google::LogSeverity severity,
-      const char* full_filename,
-      const char* base_filename,
-      int line,
-      const struct ::tm* tm_time,
-      const char* message,
-      size_t message_len) override {
-    auto level = toAndroidLevel(severity);
-    __android_log_print(
-        level,
-        base_filename,
-        "%.*s",
-        (int)message_len,
-        message);
-  }
-};
-
-/**
- * Sends GLog output to adb logcat.
- */
-class TaggedLogcatSink : public google::LogSink {
-  const std::string tag_;
-
- public:
-  TaggedLogcatSink(const std::string &tag) : tag_{tag} {}
-
-  void send(
-      google::LogSeverity severity,
-      const char* full_filename,
-      const char* base_filename,
-      int line,
-      const struct ::tm* tm_time,
-      const char* message,
-      size_t message_len) override {
-    auto level = toAndroidLevel(severity);
-    __android_log_print(
-      level,
-      tag_.c_str(),
-      "%.*s",
-      (int)message_len,
-      message);
-  }
-};
-
-static google::LogSink* make_sink(const std::string& tag) {
-  if (tag.empty()) {
-    return new LogcatSink{};
-  } else {
-    return new TaggedLogcatSink{tag};
-  }
-}
-
-static void sendGlogOutputToLogcat(const char* tag) {
-  google::AddLogSink(make_sink(tag));
-
-  // Disable logging to files
-  for (auto i = 0; i < google::NUM_SEVERITIES; ++i) {
-    google::SetLogDestination(i, "");
-  }
-}
-
-#endif // __ANDROID__
-
-static void lastResort(const char* tag, const char* msg, const char* arg = nullptr) {
-#ifdef __ANDROID__
-  if (!arg) {
-    __android_log_write(ANDROID_LOG_ERROR, tag, msg);
-  } else {
-    __android_log_print(ANDROID_LOG_ERROR, tag, "%s: %s", msg, arg);
-  }
-#else 
-  std::cerr << msg;
-  if (arg) {
-    std::cerr << ": " << arg;
-  }
-  std::cerr << std::endl;
-#endif
-}
-
-namespace facebook { namespace gloginit {
-
-void initialize(const char* tag) {
-  static std::once_flag flag{};
-  static auto failed = false;
-
-  std::call_once(flag, [tag] {
-    try {
-      google::InitGoogleLogging(tag);
-
-#ifdef __ANDROID__
-      sendGlogOutputToLogcat(tag);
-#endif
-    } catch (std::exception& ex) {
-      lastResort(tag, "Failed to initialize glog", ex.what());
-      failed = true;
-    } catch (...) {
-      lastResort(tag, "Failed to initialize glog");
-      failed = true;
-    }
-  });
-
-  if (failed) {
-    throw std::runtime_error{"Failed to initialize glog"};
-  }
-}
-
-}}
diff --git a/ReactAndroid/src/main/jni/react/jni/Android.mk b/ReactAndroid/src/main/jni/react/jni/Android.mk
index e5184d8e81fa..9d4d9b2b5fff 100644
--- a/ReactAndroid/src/main/jni/react/jni/Android.mk
+++ b/ReactAndroid/src/main/jni/react/jni/Android.mk
@@ -22,7 +22,7 @@ LOCAL_CFLAGS += $(CXX11_FLAGS)
 LOCAL_EXPORT_CPPFLAGS := $(CXX11_FLAGS)
 
 LOCAL_LDLIBS += -landroid
-LOCAL_SHARED_LIBRARIES := libfolly_json libfbjni libjsc libglog_init
+LOCAL_SHARED_LIBRARIES := libfolly_json libfbjni libjsc
 LOCAL_STATIC_LIBRARIES := libreactnative
 
 include $(BUILD_SHARED_LIBRARY)
@@ -30,6 +30,5 @@ include $(BUILD_SHARED_LIBRARY)
 $(call import-module,react)
 $(call import-module,jsc)
 $(call import-module,folly)
-$(call import-module,fbgloginit)
 $(call import-module,jni)
 $(call import-module,jsc)
diff --git a/ReactAndroid/src/main/jni/react/jni/BUCK b/ReactAndroid/src/main/jni/react/jni/BUCK
index 830a38e0c696..bebdf54ce2a3 100644
--- a/ReactAndroid/src/main/jni/react/jni/BUCK
+++ b/ReactAndroid/src/main/jni/react/jni/BUCK
@@ -4,7 +4,6 @@ include_defs('//ReactAndroid/DEFS')
 SUPPORTED_PLATFORMS = '^android-(armv7|x86)$'
 
 DEPS = [
-  FBGLOGINIT_TARGET,
   '//native/jni:jni',
   '//native/third-party/android-ndk:android',
   '//xplat/folly:molly',
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 0cb6f5bc1c3c..1a4dbe3c17da 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -3,7 +3,6 @@
 #include <android/asset_manager_jni.h>
 #include <android/input.h>
 #include <fb/log.h>
-#include <fb/glog_init.h>
 #include <folly/json.h>
 #include <jni/Countable.h>
 #include <jni/Environment.h>
@@ -846,7 +845,6 @@ jmethodID getLogMarkerMethod() {
 
 extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
   return initialize(vm, [] {
-    facebook::gloginit::initialize();
     // Inject some behavior into react/
     ReactMarker::logMarker = bridge::logMarker;
     WebWorkerUtil::createWebWorkerThread = WebWorkers::createWebWorkerThread;

From f538032888976f0199659645ddecf0650133cc62 Mon Sep 17 00:00:00 2001
From: Jason Sendros <jsendros@fb.com>
Date: Wed, 24 Feb 2016 08:56:37 -0800
Subject: [PATCH 1288/1411] Sync CSSLayout: Make 'stretch' aligned children
 fill cross-axis in containers of undefined size in the cross-axis

Reviewed By: lucasr

Differential Revision: D2971032

fb-gh-sync-id: 90ec286ca2070d666571fd3d0db4037bc9d3cda7
shipit-source-id: 90ec286ca2070d666571fd3d0db4037bc9d3cda7
---
 .../com/facebook/csslayout/LayoutEngine.java  | 50 ++++++++++++-------
 .../main/java/com/facebook/csslayout/README   |  2 +-
 .../com/facebook/csslayout/README.facebook    |  2 +-
 3 files changed, 35 insertions(+), 19 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/csslayout/LayoutEngine.java b/ReactAndroid/src/main/java/com/facebook/csslayout/LayoutEngine.java
index 711aed2ab2d5..5efd88e3b2a1 100644
--- a/ReactAndroid/src/main/java/com/facebook/csslayout/LayoutEngine.java
+++ b/ReactAndroid/src/main/java/com/facebook/csslayout/LayoutEngine.java
@@ -7,7 +7,7 @@
  */
 
 // NOTE: this file is auto-copied from https://github.com/facebook/css-layout
-// @generated SignedSource<<df03fd95c4520badeed398c76e70242d>>
+// @generated SignedSource<<dcc87213906997ff353adb1148c8e77c>>
 
 package com.facebook.csslayout;
 
@@ -258,7 +258,7 @@ private static void layoutNodeImpl(
     float paddingAndBorderAxisColumn = ((node.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN])) + (node.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN])));
   
     if (isMeasureDefined(node)) {
-      boolean isResolvedRowDimDefined = !Float.isNaN(node.layout.dimensions[dim[resolvedRowAxis]]);
+      boolean isResolvedRowDimDefined = (!Float.isNaN(node.layout.dimensions[dim[resolvedRowAxis]]) && node.layout.dimensions[dim[resolvedRowAxis]] >= 0.0);
   
       float width = CSSConstants.UNDEFINED;
       if ((!Float.isNaN(node.style.dimensions[dim[resolvedRowAxis]]) && node.style.dimensions[dim[resolvedRowAxis]] >= 0.0)) {
@@ -274,7 +274,7 @@ private static void layoutNodeImpl(
       float height = CSSConstants.UNDEFINED;
       if ((!Float.isNaN(node.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]) && node.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
         height = node.style.dimensions[DIMENSION_HEIGHT];
-      } else if (!Float.isNaN(node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]])) {
+      } else if ((!Float.isNaN(node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]) && node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
         height = node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]];
       } else {
         height = parentMaxHeight -
@@ -320,8 +320,8 @@ private static void layoutNodeImpl(
     float paddingAndBorderAxisMain = ((node.style.padding.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + node.style.border.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis])) + (node.style.padding.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) + node.style.border.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis])));
     float paddingAndBorderAxisCross = ((node.style.padding.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + node.style.border.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis])) + (node.style.padding.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis]) + node.style.border.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis])));
   
-    boolean isMainDimDefined = !Float.isNaN(node.layout.dimensions[dim[mainAxis]]);
-    boolean isCrossDimDefined = !Float.isNaN(node.layout.dimensions[dim[crossAxis]]);
+    boolean isMainDimDefined = (!Float.isNaN(node.layout.dimensions[dim[mainAxis]]) && node.layout.dimensions[dim[mainAxis]] >= 0.0);
+    boolean isCrossDimDefined = (!Float.isNaN(node.layout.dimensions[dim[crossAxis]]) && node.layout.dimensions[dim[crossAxis]] >= 0.0);
     boolean isMainRowDirection = (mainAxis == CSS_FLEX_DIRECTION_ROW || mainAxis == CSS_FLEX_DIRECTION_ROW_REVERSE);
   
     int i;
@@ -383,8 +383,8 @@ private static void layoutNodeImpl(
       float mainDim = leadingPaddingAndBorderMain;
       float crossDim = 0;
   
-      float maxWidth;
-      float maxHeight;
+      float maxWidth = CSSConstants.UNDEFINED;
+      float maxHeight = CSSConstants.UNDEFINED;
       for (i = startLine; i < childCount; ++i) {
         child = node.getChildAt(i);
         child.lineIndex = linesCount;
@@ -421,7 +421,7 @@ private static void layoutNodeImpl(
           // left and right or top and bottom).
           for (ii = 0; ii < 2; ii++) {
             axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN;
-            if (!Float.isNaN(node.layout.dimensions[dim[axis]]) &&
+            if ((!Float.isNaN(node.layout.dimensions[dim[axis]]) && node.layout.dimensions[dim[axis]] >= 0.0) &&
                 !(!Float.isNaN(child.style.dimensions[dim[axis]]) && child.style.dimensions[dim[axis]] >= 0.0) &&
                 !Float.isNaN(child.style.position[leading[axis]]) &&
                 !Float.isNaN(child.style.position[trailing[axis]])) {
@@ -468,7 +468,7 @@ private static void layoutNodeImpl(
           maxHeight = CSSConstants.UNDEFINED;
   
           if (!isMainRowDirection) {
-            if ((!Float.isNaN(node.style.dimensions[dim[resolvedRowAxis]]) && node.style.dimensions[dim[resolvedRowAxis]] >= 0.0)) {
+            if ((!Float.isNaN(node.layout.dimensions[dim[resolvedRowAxis]]) && node.layout.dimensions[dim[resolvedRowAxis]] >= 0.0)) {
               maxWidth = node.layout.dimensions[dim[resolvedRowAxis]] -
                 paddingAndBorderAxisResolvedRow;
             } else {
@@ -477,7 +477,7 @@ private static void layoutNodeImpl(
                 paddingAndBorderAxisResolvedRow;
             }
           } else {
-            if ((!Float.isNaN(node.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]) && node.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
+            if ((!Float.isNaN(node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]) && node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
               maxHeight = node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] -
                   paddingAndBorderAxisColumn;
             } else {
@@ -528,7 +528,7 @@ private static void layoutNodeImpl(
         if (isSimpleStackCross &&
             (child.style.positionType != CSSPositionType.RELATIVE ||
                 (alignItem != CSSAlign.STRETCH && alignItem != CSSAlign.FLEX_START) ||
-                Float.isNaN(child.layout.dimensions[dim[crossAxis]]))) {
+                (alignItem == CSSAlign.STRETCH && !isCrossDimDefined))) {
           isSimpleStackCross = false;
           firstComplexCross = i;
         }
@@ -611,7 +611,7 @@ private static void layoutNodeImpl(
           );
   
           maxWidth = CSSConstants.UNDEFINED;
-          if ((!Float.isNaN(node.style.dimensions[dim[resolvedRowAxis]]) && node.style.dimensions[dim[resolvedRowAxis]] >= 0.0)) {
+          if ((!Float.isNaN(node.layout.dimensions[dim[resolvedRowAxis]]) && node.layout.dimensions[dim[resolvedRowAxis]] >= 0.0)) {
             maxWidth = node.layout.dimensions[dim[resolvedRowAxis]] -
               paddingAndBorderAxisResolvedRow;
           } else if (!isMainRowDirection) {
@@ -620,7 +620,7 @@ private static void layoutNodeImpl(
               paddingAndBorderAxisResolvedRow;
           }
           maxHeight = CSSConstants.UNDEFINED;
-          if ((!Float.isNaN(node.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]) && node.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
+          if ((!Float.isNaN(node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]) && node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
             maxHeight = node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] -
               paddingAndBorderAxisColumn;
           } else if (isMainRowDirection) {
@@ -738,15 +738,31 @@ private static void layoutNodeImpl(
             CSSAlign alignItem = getAlignItem(node, child);
             /*eslint-enable */
             if (alignItem == CSSAlign.STRETCH) {
-              // You can only stretch if the dimension has not already been set
+              // You can only stretch if the dimension has not already been defined
               // previously.
-              if (Float.isNaN(child.layout.dimensions[dim[crossAxis]])) {
+              if (!(!Float.isNaN(child.style.dimensions[dim[crossAxis]]) && child.style.dimensions[dim[crossAxis]] >= 0.0)) {
+                float dimCrossAxis = child.layout.dimensions[dim[crossAxis]];
                 child.layout.dimensions[dim[crossAxis]] = Math.max(
                   boundAxis(child, crossAxis, containerCrossAxis -
                     paddingAndBorderAxisCross - (child.style.margin.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + child.style.margin.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis]))),
                   // You never want to go smaller than padding
                   ((child.style.padding.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + child.style.border.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis])) + (child.style.padding.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis]) + child.style.border.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis])))
                 );
+  
+                // If the size has changed, and this child has children we need to re-layout this child
+                if (dimCrossAxis != child.layout.dimensions[dim[crossAxis]] && child.getChildCount() > 0) {
+                  // Reset child margins before re-layout as they are added back in layoutNode and would be doubled
+                  child.layout.position[leading[mainAxis]] -= child.style.margin.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) +
+                    getRelativePosition(child, mainAxis);
+                  child.layout.position[trailing[mainAxis]] -= child.style.margin.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) +
+                    getRelativePosition(child, mainAxis);
+                  child.layout.position[leading[crossAxis]] -= child.style.margin.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) +
+                    getRelativePosition(child, crossAxis);
+                  child.layout.position[trailing[crossAxis]] -= child.style.margin.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis]) +
+                    getRelativePosition(child, crossAxis);
+  
+                  layoutNode(layoutContext, child, maxWidth, maxHeight, direction);
+                }
               }
             } else if (alignItem != CSSAlign.FLEX_START) {
               // The remaining space between the parent dimensions+padding and child
@@ -824,7 +840,7 @@ private static void layoutNodeImpl(
           if (child.lineIndex != i) {
             break;
           }
-          if (!Float.isNaN(child.layout.dimensions[dim[crossAxis]])) {
+          if ((!Float.isNaN(child.layout.dimensions[dim[crossAxis]]) && child.layout.dimensions[dim[crossAxis]] >= 0.0)) {
             lineHeight = Math.max(
               lineHeight,
               child.layout.dimensions[dim[crossAxis]] + (child.style.margin.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + child.style.margin.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis]))
@@ -917,7 +933,7 @@ private static void layoutNodeImpl(
       for (ii = 0; ii < 2; ii++) {
         axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN;
   
-        if (!Float.isNaN(node.layout.dimensions[dim[axis]]) &&
+        if ((!Float.isNaN(node.layout.dimensions[dim[axis]]) && node.layout.dimensions[dim[axis]] >= 0.0) &&
             !(!Float.isNaN(currentAbsoluteChild.style.dimensions[dim[axis]]) && currentAbsoluteChild.style.dimensions[dim[axis]] >= 0.0) &&
             !Float.isNaN(currentAbsoluteChild.style.position[leading[axis]]) &&
             !Float.isNaN(currentAbsoluteChild.style.position[trailing[axis]])) {
diff --git a/ReactAndroid/src/main/java/com/facebook/csslayout/README b/ReactAndroid/src/main/java/com/facebook/csslayout/README
index 955473ba0b55..0de9f29a65f6 100644
--- a/ReactAndroid/src/main/java/com/facebook/csslayout/README
+++ b/ReactAndroid/src/main/java/com/facebook/csslayout/README
@@ -1,7 +1,7 @@
 The source of truth for css-layout is: https://github.com/facebook/css-layout
 
 The code here should be kept in sync with GitHub.
-HEAD at the time this code was synced: https://github.com/facebook/css-layout/commit/219bdaed15c16bbf7c1f2bab17ad629d04cc4199
+HEAD at the time this code was synced: https://github.com/facebook/css-layout/commit/3f0f4be2e868a9af4f3ed1e019f71efbc814e8a2
 
 There is generated code in:
  - README (this file)
diff --git a/ReactAndroid/src/main/java/com/facebook/csslayout/README.facebook b/ReactAndroid/src/main/java/com/facebook/csslayout/README.facebook
index 8d78b2695779..fc9720464910 100644
--- a/ReactAndroid/src/main/java/com/facebook/csslayout/README.facebook
+++ b/ReactAndroid/src/main/java/com/facebook/csslayout/README.facebook
@@ -1,7 +1,7 @@
 The source of truth for css-layout is: https://github.com/facebook/css-layout
 
 The code here should be kept in sync with GitHub.
-HEAD at the time this code was synced: https://github.com/facebook/css-layout/commit/219bdaed15c16bbf7c1f2bab17ad629d04cc4199
+HEAD at the time this code was synced: https://github.com/facebook/css-layout/commit/3f0f4be2e868a9af4f3ed1e019f71efbc814e8a2
 
 There is generated code in:
  - README.facebook (this file)

From 4b4455f8278d8d728d69d84804bbe8fed9b3d972 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Wed, 24 Feb 2016 09:05:28 -0800
Subject: [PATCH 1289/1411] Removed 'screen' option from snapshot API

Summary:Unfortunately the 'screen' option in the `UIManager.takeSnapshot` API appears to work only on the iOS simulator, not on an actual device.

This diff removes the 'screen' option until a solution can be found that works on the device.

(Taking a snapshot of the window still works fine - it just won't include the status bar, etc.)

Reviewed By: javache

Differential Revision: D2971091

fb-gh-sync-id: 026b9d4eb2f59f686f58c18a16381ff325df612b
shipit-source-id: 026b9d4eb2f59f686f58c18a16381ff325df612b
---
 Examples/UIExplorer/SnapshotExample.js |  2 +-
 Libraries/Utilities/UIManager.js       | 10 +++++-----
 React/Modules/RCTUIManager.m           |  6 ++----
 3 files changed, 8 insertions(+), 10 deletions(-)

diff --git a/Examples/UIExplorer/SnapshotExample.js b/Examples/UIExplorer/SnapshotExample.js
index f5384c66630d..d843acee80d3 100644
--- a/Examples/UIExplorer/SnapshotExample.js
+++ b/Examples/UIExplorer/SnapshotExample.js
@@ -44,7 +44,7 @@ var ScreenshotExample = React.createClass({
 
   takeScreenshot() {
     UIManager
-      .takeSnapshot('screen', {format: 'jpeg', quality: 0.8}) // See UIManager.js for options
+      .takeSnapshot('window', {format: 'jpeg', quality: 0.8}) // See UIManager.js for options
       .then((uri) => this.setState({uri}))
       .catch((error) => alert(error));
   }
diff --git a/Libraries/Utilities/UIManager.js b/Libraries/Utilities/UIManager.js
index 068087a8f538..efd8ce5b0728 100644
--- a/Libraries/Utilities/UIManager.js
+++ b/Libraries/Utilities/UIManager.js
@@ -50,8 +50,8 @@ const _takeSnapshot = UIManager.takeSnapshot;
  * will be stored in a temporary file that will only exist for as long as the
  * app is running.
  * 
- * The `view` argument can be the literal string `screen` or `window` if you
- * want to capture the entire screen, or it can be a reference to a specific
+ * The `view` argument can be the literal string `window` if you want to
+ * capture the entire window, or it can be a reference to a specific
  * React Native component.
  *
  * The `options` argument may include:
@@ -63,7 +63,7 @@ const _takeSnapshot = UIManager.takeSnapshot;
  * @platform ios
  */
 UIManager.takeSnapshot = async function(
-  view ?: 'screen' | 'window' | ReactElement | number,
+  view ?: 'window' | ReactElement | number,
   options ?: {
     width ?: number;
     height ?: number;
@@ -75,8 +75,8 @@ UIManager.takeSnapshot = async function(
     console.warn('UIManager.takeSnapshot is not available on this platform');
     return;
   }
-  if (typeof view !== 'number' && view !== 'screen' && view !== 'window') {
-    view = findNodeHandle(view) || 'screen';
+  if (typeof view !== 'number' && view !== 'window') {
+    view = findNodeHandle(view) || 'window';
   }
   return _takeSnapshot(view, options);
 };
diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m
index 1186ac027ca6..dd7d53448345 100644
--- a/React/Modules/RCTUIManager.m
+++ b/React/Modules/RCTUIManager.m
@@ -1191,9 +1191,7 @@ static void RCTMeasureLayout(RCTShadowView *view,
 
     // Get view
     UIView *view;
-    if (target == nil || [target isEqual:@"screen"]) {
-      view = [[UIScreen mainScreen] snapshotViewAfterScreenUpdates:YES];
-    } else if ([target isEqual:@"window"]) {
+    if (target == nil || [target isEqual:@"window"]) {
       view = RCTKeyWindow();
     } else if ([target isKindOfClass:[NSNumber class]]) {
       view = viewRegistry[target];
@@ -1217,7 +1215,7 @@ static void RCTMeasureLayout(RCTShadowView *view,
     UIGraphicsEndImageContext();
 
     if (!success || !image) {
-      reject(RCTErrorUnspecified, @"Failed to capture view snapshot", nil);
+      reject(RCTErrorUnspecified, @"Failed to capture view snapshot.", nil);
       return;
     }
 

From 3faa70ab4f461945a0b4c4f8b84199f7546e7cab Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Wed, 24 Feb 2016 09:37:35 -0800
Subject: [PATCH 1290/1411] Add guidelines for managing GitHub issues

Reviewed By: mkonicek

Differential Revision:D2971827
Ninja: oss only

fb-gh-sync-id: b86b74a8a582f159777fb90da23645ee730a4802
shipit-source-id: b86b74a8a582f159777fb90da23645ee730a4802
---
 ISSUE_TEMPLATE.md       |  2 +-
 bots/IssueCommands.txt  |  9 +++++++--
 bots/IssueGuidelines.md | 37 +++++++++++++++++++++++++++++++++++++
 3 files changed, 45 insertions(+), 3 deletions(-)
 create mode 100644 bots/IssueGuidelines.md

diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md
index 37d939a97571..8183779c30ac 100644
--- a/ISSUE_TEMPLATE.md
+++ b/ISSUE_TEMPLATE.md
@@ -11,7 +11,7 @@ Can you see anything in the logs? Can you debug why this happens? **Send a pull
 
 Have a question or not sure you've found a bug?
 -----------------------------------------------------------------
-Please ask your question [StackOverflow](http://stackoverflow.com/questions/tagged/react-native) with the tag `react-native`. StackOverflow is amazing for Q&A. Because of the reputation system it is likely the community will see and answer your question there.
+Please ask your question on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native) with the tag `react-native`. StackOverflow is amazing for Q&A. Because of the reputation system it is likely the community will see and answer your question there.
 
 Make sure you **include a short code snippet to demonstrate the problem**.
 
diff --git a/bots/IssueCommands.txt b/bots/IssueCommands.txt
index 86be4159c6f1..00a6114b3be1 100644
--- a/bots/IssueCommands.txt
+++ b/bots/IssueCommands.txt
@@ -1,5 +1,5 @@
 /answered
-comment Closing this issue as {author} says the question asked has been answered. Please help us by asking questions on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native). StackOverflow is amazing for Q&A. Because of the reputation system it is likely the community will see and answer your question there. This also helps us use the GitHub bug tracker for bugs only.
+comment Closing this issue as {author} says the question asked has been answered. Please help us by asking questions on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native). StackOverflow is amazing for Q&A: it has a reputation system, voting, the ability to mark a question as answered. Because of the reputation system it is likely the community will see and answer your question there. This also helps us use the GitHub bug tracker for bugs only.
 close
 
 /duplicate (#[0-9]+)
@@ -11,12 +11,17 @@ comment The /expected comment above tells me this is expected behavior. Closing
 close
 
 /question
-comment Hey {issue_author} and thanks for posting this! {author} tells me this issue looks like a question that would be best asked on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native). StackOverflow is amazing for Q&A. Because of the reputation system it is likely the community will see and answer your question there. This also helps us use the GitHub bug tracker for bugs only.
+comment Hey {issue_author} and thanks for posting this! {author} tells me this issue looks like a question that would be best asked on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native). StackOverflow is amazing for Q&A: it has a reputation system, voting, the ability to mark a question as answered. Because of the reputation system it is likely the community will see and answer your question there. This also helps us use the GitHub bug tracker for bugs only. Will close this as this is really a question that should be asked on SO.
 add-label For Stack Overflow
+close
 
 /label (.*)
 add-label {match0}
 
+/no-reply
+comment Closing this issue as more information is needed to debug this and we haven't heard back from the author. Once there's more information we can reopen the issue.
+close
+
 /reopen
 comment Okay, reopening this issue.
 reopen
diff --git a/bots/IssueGuidelines.md b/bots/IssueGuidelines.md
new file mode 100644
index 000000000000..35bf3a145dfd
--- /dev/null
+++ b/bots/IssueGuidelines.md
@@ -0,0 +1,37 @@
+Use the following tips when responding to GitHub issues.
+
+### An issue is a duplicate of another issue
+Comment e.g. `@facebook-github-bot /duplicate #123`. This will add a comment and close the issue.
+Example: #5977
+
+### An issue is a question
+StackOverflow is really good for Q&A. It has a reputation system and voting. Questions should absolutely be asked on StackOverflow rather than GitHub. However, to make this work we should hang out on StackOverflow every now and then and answer questions. A nice side effect is you'll get reputation for answering questions there rather than on GitHub.
+Comment `@facebook-github-bot /question` to close the issue.
+Examples: #6015, #6059, #6062
+
+### An issue is a question that's been answered
+Sometimes and issue has been resolved in the comments. Resolved issues should be closed.
+Comment `@facebook-github-bot /answered` to close it.
+Example: #6045
+
+### An issue needs more information
+It is impossible to understand and reproduce the issue without more information, e.g. a short code sample, screenshot.
+Do the following:
+- Explain what additional info you need to understand the issue
+- Comment `@facebook-github-bot /add-label Needs more information`
+Examples: #6056, #6008, #5491
+
+### An issue with label 'Needs more information' has been open for more than a week
+Comment mentioning the author asking if they plan to provide the additional information. If they don't come back close the issue using `@facebook-github-bot /no-reply`.
+Example: #6056
+
+### Want to add a label
+Add any relevant labels, for example 'Android', 'iOS'.
+Comment e.g. `@facebook-github-bot /add-label Android`.
+
+### Want to reopen a closed issue
+For example an issue was closed waiting for the author, the author replied and it turns out this is indeed a bug.
+Comment `@facebook-github-bot /reopen`
+
+### Commands for the bot
+When you mention the bot, it follows the commands defined in [IssueCommands.txt](https://github.com/facebook/react-native/blob/master/bots/IssueCommands.txt).

From 36400807ab968f9e48aee2292545147e74462caf Mon Sep 17 00:00:00 2001
From: Andrei Coman <andreic@fb.com>
Date: Wed, 24 Feb 2016 10:48:28 -0800
Subject: [PATCH 1291/1411] Remove unused variable

Reviewed By: bestander

Differential Revision: D2971225

fb-gh-sync-id: 827d4403d436ec74043e2dde02e19513f7bf811f
shipit-source-id: 827d4403d436ec74043e2dde02e19513f7bf811f
---
 .../java/com/facebook/react/modules/netinfo/NetInfoModule.java  | 2 --
 1 file changed, 2 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java
index 19b571592239..1b8b93cbe30f 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java
@@ -42,7 +42,6 @@ public class NetInfoModule extends ReactContextBaseJavaModule
   private static final String ERROR_MISSING_PERMISSION = "E_MISSING_PERMISSION";
 
   private final ConnectivityManager mConnectivityManager;
-  private final ConnectivityManagerCompat mConnectivityManagerCompat;
   private final ConnectivityBroadcastReceiver mConnectivityBroadcastReceiver;
   private boolean mNoNetworkPermission = false;
 
@@ -52,7 +51,6 @@ public NetInfoModule(ReactApplicationContext reactContext) {
     super(reactContext);
     mConnectivityManager =
         (ConnectivityManager) reactContext.getSystemService(Context.CONNECTIVITY_SERVICE);
-    mConnectivityManagerCompat = new ConnectivityManagerCompat();
     mConnectivityBroadcastReceiver = new ConnectivityBroadcastReceiver();
   }
 

From 9836b297ada9c53484e01dc37c1bed4505e24d19 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C5=82=20Gregorczyk?= <michalgr@fb.com>
Date: Wed, 24 Feb 2016 12:59:56 -0800
Subject: [PATCH 1292/1411] Align stack on all JSC API calls

Reviewed By: astreet

Differential Revision: D2971504

fb-gh-sync-id: 4f2cb5924c135aa39853e6746b0a35e30f3e93a4
shipit-source-id: 4f2cb5924c135aa39853e6746b0a35e30f3e93a4
---
 ReactAndroid/src/main/jni/react/AlignStack.h | 15 +++++
 ReactAndroid/src/main/jni/react/BUCK         |  1 +
 ReactAndroid/src/main/jni/react/JSCHelpers.h | 25 ++-----
 ReactAndroid/src/main/jni/react/Value.h      | 70 +++++++++++---------
 4 files changed, 60 insertions(+), 51 deletions(-)
 create mode 100644 ReactAndroid/src/main/jni/react/AlignStack.h

diff --git a/ReactAndroid/src/main/jni/react/AlignStack.h b/ReactAndroid/src/main/jni/react/AlignStack.h
new file mode 100644
index 000000000000..9919a4fefda5
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/AlignStack.h
@@ -0,0 +1,15 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+#ifdef __i386__
+// The Android x86 ABI states that the NDK toolchain assumes 16 byte stack
+// alignment: http://developer.android.com/ndk/guides/x86.html JSC checks for
+// stack alignment, and fails with SIGTRAP if it is not.  Empirically, the
+// google android x86 emulator does not provide this alignment, and so JSC
+// calls may crash.  All checked calls go through here, so the attribute here
+// is added to force alignment and prevent crashes.
+#define ALIGN_STACK __attribute__((force_align_arg_pointer))
+#else
+#define ALIGN_STACK
+#endif
diff --git a/ReactAndroid/src/main/jni/react/BUCK b/ReactAndroid/src/main/jni/react/BUCK
index c5b7d646221f..de41e5c82db5 100644
--- a/ReactAndroid/src/main/jni/react/BUCK
+++ b/ReactAndroid/src/main/jni/react/BUCK
@@ -53,6 +53,7 @@ react_library(
     'JSCMemory.h',
   ],
   exported_headers = [
+    'AlignStack.h',
     'Bridge.h',
     'Executor.h',
     'JSCExecutor.h',
diff --git a/ReactAndroid/src/main/jni/react/JSCHelpers.h b/ReactAndroid/src/main/jni/react/JSCHelpers.h
index c765421c4ca5..12a5af9a7377 100644
--- a/ReactAndroid/src/main/jni/react/JSCHelpers.h
+++ b/ReactAndroid/src/main/jni/react/JSCHelpers.h
@@ -9,6 +9,8 @@
 #include <stdexcept>
 #include <algorithm>
 
+#include "AlignStack.h"
+
 namespace facebook {
 namespace react {
 
@@ -16,11 +18,13 @@ struct JsException : std::runtime_error {
   using std::runtime_error::runtime_error;
 };
 
+ALIGN_STACK
 inline void throwJSExecutionException(const char* msg) {
   throw JsException(msg);
 }
 
 template <typename... Args>
+ALIGN_STACK
 inline void throwJSExecutionException(const char* fmt, Args... args) {
   int msgSize = snprintf(nullptr, 0, fmt, args...);
   msgSize = std::min(512, msgSize + 1);
@@ -32,31 +36,16 @@ inline void throwJSExecutionException(const char* fmt, Args... args) {
 void installGlobalFunction(
     JSGlobalContextRef ctx,
     const char* name,
-    JSObjectCallAsFunctionCallback callback);
+    JSObjectCallAsFunctionCallback callback) ALIGN_STACK;
 
 JSValueRef makeJSCException(
     JSContextRef ctx,
-    const char* exception_text);
-
-#ifdef __i386__
-// The Android x86 ABI states that the NDK toolchain assumes 16 byte stack
-// alignment: http://developer.android.com/ndk/guides/x86.html JSC checks for
-// stack alignment, and fails with SIGTRAP if it is not.  Empirically, the
-// google android x86 emulator does not provide this alignment, and so JSC
-// calls may crash.  All checked calls go through here, so the attribute here
-// is added to force alignment and prevent crashes.
+    const char* exception_text) ALIGN_STACK;
 
 JSValueRef evaluateScript(
     JSContextRef ctx,
     JSStringRef script,
     JSStringRef sourceURL,
-    const char* cachePath = nullptr) __attribute__((force_align_arg_pointer));
-#else
-JSValueRef evaluateScript(
-    JSContextRef ctx,
-    JSStringRef script,
-    JSStringRef sourceURL,
-    const char* cachePath = nullptr);
-#endif
+    const char* cachePath = nullptr) ALIGN_STACK;
 
 } }
diff --git a/ReactAndroid/src/main/jni/react/Value.h b/ReactAndroid/src/main/jni/react/Value.h
index 8549c7f1bc4d..279ecb7dc1dc 100644
--- a/ReactAndroid/src/main/jni/react/Value.h
+++ b/ReactAndroid/src/main/jni/react/Value.h
@@ -14,6 +14,8 @@
 
 #include "noncopyable.h"
 
+#include "AlignStack.h"
+
 #if WITH_FBJSCEXTENSIONS
 #include <jsc_stringref.h>
 #endif
@@ -26,13 +28,15 @@ class Context;
 
 class String : public noncopyable {
 public:
-  explicit String(const char* utf8) :
+  explicit String(const char* utf8) ALIGN_STACK :
     m_string(Adopt, JSStringCreateWithUTF8CString(utf8))
   {}
-  String(String&& other) :
+
+  String(String&& other) ALIGN_STACK :
     m_string(Adopt, other.m_string.leakRef())
   {}
-  String(const String& other) :
+
+  String(const String& other) ALIGN_STACK :
     m_string(other.m_string)
   {}
 
@@ -41,16 +45,16 @@ class String : public noncopyable {
   }
 
   // Length in characters
-  size_t length() const {
+  size_t length() const ALIGN_STACK {
     return JSStringGetLength(m_string.get());
   }
 
   // Length in bytes of a null-terminated utf8 encoded value
-  size_t utf8Size() const {
+  size_t utf8Size() const ALIGN_STACK {
     return JSStringGetMaximumUTF8CStringSize(m_string.get());
   }
 
-  std::string str() const {
+  std::string str() const ALIGN_STACK {
     size_t reserved = utf8Size();
     char* bytes = new char[reserved];
     size_t length = JSStringGetUTF8CString(m_string.get(), bytes, reserved) - 1;
@@ -59,11 +63,11 @@ class String : public noncopyable {
   }
 
   // Assumes that utf8 is null terminated
-  bool equals(const char* utf8) {
+  bool equals(const char* utf8) ALIGN_STACK {
     return JSStringIsEqualToUTF8CString(m_string.get(), utf8);
   }
 
-  static String createExpectingAscii(std::string const &utf8) {
+  static String createExpectingAscii(std::string const &utf8) ALIGN_STACK {
   #if WITH_FBJSCEXTENSIONS
     return String(Adopt, JSStringCreateWithUTF8CStringExpectAscii(utf8.c_str(), utf8.size()));
   #else
@@ -80,11 +84,11 @@ class String : public noncopyable {
   }
 
 private:
-  explicit String(JSStringRef string) :
+  explicit String(JSStringRef string) ALIGN_STACK :
     m_string(string)
   {}
 
-  String(AdoptTag tag, JSStringRef string) :
+  String(AdoptTag tag, JSStringRef string) ALIGN_STACK :
     m_string(tag, string)
   {}
 
@@ -106,7 +110,7 @@ class Object : public noncopyable {
     other.m_isProtected = false;
   }
 
-  ~Object() {
+  ~Object() ALIGN_STACK {
     if (m_isProtected && m_obj) {
       JSValueUnprotect(m_context, m_obj);
     }
@@ -118,28 +122,28 @@ class Object : public noncopyable {
 
   operator Value() const;
 
-  bool isFunction() const {
+  bool isFunction() const ALIGN_STACK {
     return JSObjectIsFunction(m_context, m_obj);
   }
 
-  Value callAsFunction(int nArgs, JSValueRef args[]);
+  Value callAsFunction(int nArgs, JSValueRef args[]) ALIGN_STACK;
 
-  Value getProperty(const String& propName) const;
+  Value getProperty(const String& propName) const ALIGN_STACK;
   Value getProperty(const char *propName) const;
-  Value getPropertyAtIndex(unsigned index) const;
-  void setProperty(const String& propName, const Value& value) const;
+  Value getPropertyAtIndex(unsigned index) const ALIGN_STACK;
+  void setProperty(const String& propName, const Value& value) const ALIGN_STACK;
   void setProperty(const char *propName, const Value& value) const;
-  std::vector<std::string> getPropertyNames() const;
-  std::unordered_map<std::string, std::string> toJSONMap() const;
+  std::vector<std::string> getPropertyNames() const ALIGN_STACK;
+  std::unordered_map<std::string, std::string> toJSONMap() const ALIGN_STACK;
 
-  void makeProtected() {
+  void makeProtected() ALIGN_STACK {
     if (!m_isProtected && m_obj) {
       JSValueProtect(m_context, m_obj);
       m_isProtected = true;
     }
   }
 
-  static Object getGlobalObject(JSContextRef ctx) {
+  static Object getGlobalObject(JSContextRef ctx) ALIGN_STACK {
     auto globalObj = JSContextGetGlobalObject(ctx);
     return Object(ctx, globalObj);
   }
@@ -147,7 +151,7 @@ class Object : public noncopyable {
   /**
    * Creates an instance of the default object class.
    */
-  static Object create(JSContextRef ctx);
+  static Object create(JSContextRef ctx) ALIGN_STACK;
 
 private:
   JSContextRef m_context;
@@ -164,27 +168,27 @@ class Value : public noncopyable {
     return m_value;
   }
 
-  bool isBoolean() const {
+  bool isBoolean() const ALIGN_STACK {
     return JSValueIsBoolean(context(), m_value);
   }
 
-  bool asBoolean() const {
+  bool asBoolean() const ALIGN_STACK {
     return JSValueToBoolean(context(), m_value);
   }
 
-  bool isNumber() const {
+  bool isNumber() const ALIGN_STACK {
     return JSValueIsNumber(context(), m_value);
   }
 
-  bool isNull() const {
+  bool isNull() const ALIGN_STACK {
     return JSValueIsNull(context(), m_value);
   }
 
-  bool isUndefined() const {
+  bool isUndefined() const ALIGN_STACK {
     return JSValueIsUndefined(context(), m_value);
   }
 
-  double asNumber() const {
+  double asNumber() const ALIGN_STACK {
     if (isNumber()) {
       return JSValueToNumber(context(), m_value, nullptr);
     } else {
@@ -200,22 +204,22 @@ class Value : public noncopyable {
     return static_cast<uint32_t>(asNumber());
   }
 
-  bool isObject() const {
+  bool isObject() const ALIGN_STACK {
     return JSValueIsObject(context(), m_value);
   }
 
-  Object asObject();
+  Object asObject() ALIGN_STACK;
 
-  bool isString() const {
+  bool isString() const ALIGN_STACK {
     return JSValueIsString(context(), m_value);
   }
 
-  String toString() {
+  String toString() ALIGN_STACK {
     return String::adopt(JSValueToStringCopy(context(), m_value, nullptr));
   }
 
-  std::string toJSONString(unsigned indent = 0) const;
-  static Value fromJSON(JSContextRef ctx, const String& json);
+  std::string toJSONString(unsigned indent = 0) const ALIGN_STACK;
+  static Value fromJSON(JSContextRef ctx, const String& json) ALIGN_STACK;
 protected:
   JSContextRef context() const;
   JSContextRef m_context;

From 6bcb2a05eb4eb2d614991d3c68351d101f6f1c76 Mon Sep 17 00:00:00 2001
From: Hedger Wang <hedger@fb.com>
Date: Wed, 24 Feb 2016 18:51:09 -0800
Subject: [PATCH 1293/1411] Introducing NavigationCardStack

Summary:Basic implementation of the component NavigationCardStack that animates
a list of NavigationCard.

This will be used to port the UX of teh current Navigator.

Reviewed By: ericvicenti, fkgozali

Differential Revision: D2967065

fb-gh-sync-id: a72920e141364fab328e45a083aef21ca5e6fe0c
shipit-source-id: a72920e141364fab328e45a083aef21ca5e6fe0c
---
 .../NavigationCardStackExample.js             | 114 +++++++++++++++++
 .../NavigationExperimentalExample.js          |   1 +
 .../NavigationCardStack.js                    | 115 ++++++++++++++++++
 .../NavigationAnimatedView.js                 |   4 +-
 .../NavigationExperimental.js                 |   4 +-
 5 files changed, 236 insertions(+), 2 deletions(-)
 create mode 100644 Examples/UIExplorer/NavigationExperimental/NavigationCardStackExample.js
 create mode 100644 Libraries/CustomComponents/NavigationExperimental/NavigationCardStack.js

diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationCardStackExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationCardStackExample.js
new file mode 100644
index 000000000000..2063e76151f6
--- /dev/null
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationCardStackExample.js
@@ -0,0 +1,114 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+*/
+'use strict';
+
+const NavigationExampleRow = require('./NavigationExampleRow');
+const React = require('react-native');
+
+const {
+  NavigationExperimental,
+  StyleSheet,
+  ScrollView,
+} = React;
+
+const NavigationCardStack = NavigationExperimental.CardStack;
+const NavigationStateUtils = NavigationExperimental.StateUtils;
+
+class NavigationCardStackExample extends React.Component {
+
+  constructor(props, context) {
+    super(props, context);
+    this.state = this._getInitialState();
+    this._renderScene = this._renderScene.bind(this);
+    this._push = this._push.bind(this);
+    this._pop = this._pop.bind(this);
+  }
+
+  render() {
+    return (
+      <NavigationCardStack
+        style={styles.main}
+        renderScene={this._renderScene}
+        navigationState={this.state.navigationState}
+      />
+    );
+  }
+
+  _getInitialState() {
+    const route = {key: 'First Route'};
+    const navigationState = {
+      index: 0,
+      children: [route],
+    };
+    return {
+      navigationState,
+    };
+  }
+
+  _push() {
+    const state = this.state.navigationState;
+    const nextRoute = {key: 'Route ' + (state.index + 1)};
+    const nextState = NavigationStateUtils.push(
+      state,
+      nextRoute,
+    );
+    this.setState({
+      navigationState: nextState,
+    });
+  }
+
+  _pop() {
+    const state = this.state.navigationState;
+    const nextState = state.index > 0 ?
+      NavigationStateUtils.pop(state) :
+      state;
+
+    this.setState({
+      navigationState: nextState,
+    });
+  }
+
+  _renderScene(navigationState, index, position, layout) {
+    return (
+      <ScrollView style={styles.scrollView}>
+        <NavigationExampleRow
+          text={JSON.stringify(navigationState)}
+        />
+        <NavigationExampleRow
+          text="Push Route"
+          onPress={this._push}
+        />
+        <NavigationExampleRow
+          text="Pop Route"
+          onPress={this._pop}
+        />
+        <NavigationExampleRow
+          text="Exit Card Stack Example"
+          onPress={this.props.onExampleExit}
+        />
+      </ScrollView>
+    );
+  }
+}
+
+const styles = StyleSheet.create({
+  main: {
+    flex: 1,
+  },
+  scrollView: {
+    marginTop: 64
+  },
+});
+
+module.exports = NavigationCardStackExample;
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js
index 0a813410d02c..f15b9926aa16 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js
@@ -32,6 +32,7 @@ var EXAMPLES = {
   'Basic': require('./NavigationBasicExample'),
   'Animated Card Stack': require('./NavigationAnimatedExample'),
   'Composition': require('./NavigationCompositionExample'),
+  'Card Stack Example': require('./NavigationCardStackExample'),
   'Tic Tac Toe': require('./NavigationTicTacToeExample'),
 };
 
diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationCardStack.js b/Libraries/CustomComponents/NavigationExperimental/NavigationCardStack.js
new file mode 100644
index 000000000000..f2cabdda8392
--- /dev/null
+++ b/Libraries/CustomComponents/NavigationExperimental/NavigationCardStack.js
@@ -0,0 +1,115 @@
+/**
+ * Copyright (c) 2015, Facebook, Inc.  All rights reserved.
+ *
+ * Facebook, Inc. ("Facebook") owns all right, title and interest, including
+ * all intellectual property and other proprietary rights, in and to the React
+ * Native CustomComponents software (the "Software").  Subject to your
+ * compliance with these terms, you are hereby granted a non-exclusive,
+ * worldwide, royalty-free copyright license to (1) use and copy the Software;
+ * and (2) reproduce and distribute the Software as part of your own software
+ * ("Your Software").  Facebook reserves all rights not expressly granted to
+ * you in this license agreement.
+ *
+ * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "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 FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
+ * EMPLOYEES 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 THE SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @providesModule NavigationCardStack
+ * @flow
+ */
+'use strict';
+
+const NavigationAnimatedView = require('NavigationAnimatedView');
+const NavigationCard = require('NavigationCard');
+const NavigationContainer = require('NavigationContainer');
+const React = require('React');
+const StyleSheet = require('StyleSheet');
+
+const emptyFunction = require('emptyFunction');
+
+const {PropTypes} = React;
+
+import type {
+  NavigationParentState,
+  NavigationState,
+} from 'NavigationStateUtils';
+
+import type {
+  Layout,
+  OverlayRenderer,
+  Position,
+  SceneRenderer,
+} from 'NavigationAnimatedView';
+
+type Props = {
+  navigationState: NavigationParentState,
+  renderOverlay: OverlayRenderer,
+  renderScene: SceneRenderer,
+};
+
+/**
+ * A controlled navigation view that renders a list of cards.
+ */
+class NavigationCardStack extends React.Component {
+  _renderScene : SceneRenderer;
+
+  constructor(props: Props, context: any) {
+    super(props, context);
+    this._renderScene = this._renderScene.bind(this);
+  }
+
+  render(): ReactElement {
+    return (
+      <NavigationAnimatedView
+        navigationState={this.props.navigationState}
+        style={[styles.animatedView, this.props.style]}
+        renderOverlay={this.props.renderOverlay}
+        renderScene={this._renderScene}
+      />
+    );
+  }
+
+  _renderScene(
+    navigationState: NavigationState,
+    index: number,
+    position: Position,
+    layout: Layout,
+  ): ReactElement {
+    return (
+      <NavigationCard
+        key={navigationState.key}
+        index={index}
+        navigationState={navigationState}
+        position={position}
+        layout={layout}>
+        {this.props.renderScene(navigationState, index, position, layout)}
+      </NavigationCard>
+    );
+  }
+}
+
+NavigationCardStack.propTypes = {
+  navigationState: PropTypes.object.isRequired,
+  renderOverlay: PropTypes.func,
+  renderScene: PropTypes.func.isRequired,
+};
+
+NavigationCardStack.defaultProps = {
+  renderOverlay: emptyFunction.thatReturnsNull,
+};
+
+const styles = StyleSheet.create({
+  animatedView: {
+    flex: 1,
+  },
+});
+
+module.exports = NavigationContainer.create(NavigationCardStack);
diff --git a/Libraries/NavigationExperimental/NavigationAnimatedView.js b/Libraries/NavigationExperimental/NavigationAnimatedView.js
index c1f6a4040cec..a1f5df0f3772 100644
--- a/Libraries/NavigationExperimental/NavigationAnimatedView.js
+++ b/Libraries/NavigationExperimental/NavigationAnimatedView.js
@@ -75,10 +75,12 @@ type OverlayRenderer = (
   layout: Layout
 ) => ReactElement;
 
+type Position = Animated.Value;
+
 type SceneRenderer = (
   state: NavigationState,
   index: number,
-  position: Animated.Value,
+  position: Position,
   layout: Layout
 ) => ReactElement;
 
diff --git a/Libraries/NavigationExperimental/NavigationExperimental.js b/Libraries/NavigationExperimental/NavigationExperimental.js
index 0100fa69ca74..f9153ea68aef 100644
--- a/Libraries/NavigationExperimental/NavigationExperimental.js
+++ b/Libraries/NavigationExperimental/NavigationExperimental.js
@@ -13,10 +13,11 @@
 
 const NavigationAnimatedView = require('NavigationAnimatedView');
 const NavigationCard = require('NavigationCard');
+const NavigationCardStack = require('NavigationCardStack');
 const NavigationContainer = require('NavigationContainer');
 const NavigationHeader = require('NavigationHeader');
-const NavigationRootContainer = require('NavigationRootContainer');
 const NavigationReducer = require('NavigationReducer');
+const NavigationRootContainer = require('NavigationRootContainer');
 const NavigationStateUtils = require('NavigationStateUtils');
 const NavigationView = require('NavigationView');
 
@@ -36,6 +37,7 @@ const NavigationExperimental = {
   // CustomComponents:
   Header: NavigationHeader,
   Card: NavigationCard,
+  CardStack: NavigationCardStack,
 };
 
 module.exports = NavigationExperimental;

From 6b80f11652d7937ace7fbe867c7d6cfacb7cab01 Mon Sep 17 00:00:00 2001
From: Ahmed El-Helw <ahmedre@fb.com>
Date: Wed, 24 Feb 2016 21:12:43 -0800
Subject: [PATCH 1294/1411] Add switch for enabling nodes screenshot tests

Summary: Allow customizing the UIImplementation passed in to loadApp.

Differential Revision: D2975785

fb-gh-sync-id: 2ce081fb488b78c0c91fcebe6a37dac4f587a467
shipit-source-id: 2ce081fb488b78c0c91fcebe6a37dac4f587a467
---
 .../react/testing/ReactAppTestActivity.java   | 23 +++++++++++++++++--
 1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java
index f8cdb6f117da..37f0a4db3955 100644
--- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java
@@ -28,7 +28,7 @@
 import com.facebook.react.ReactPackage;
 import com.facebook.react.ReactRootView;
 import com.facebook.react.shell.MainReactPackage;
-
+import com.facebook.react.uimanager.UIImplementationProvider;
 
 public class ReactAppTestActivity extends FragmentActivity implements
     DefaultHardwareBackBtnHandler
@@ -112,6 +112,14 @@ public void loadApp(String appKey, ReactInstanceSpecForTest spec, String bundleN
     loadApp(appKey, spec, null, bundleName, false /* = useDevSupport */);
   }
 
+  public void loadApp(
+    String appKey,
+    ReactInstanceSpecForTest spec,
+    String bundleName,
+    UIImplementationProvider uiImplementationProvider) {
+    loadApp(appKey, spec, null, bundleName, false /* = useDevSupport */, uiImplementationProvider);
+  }
+
   public void resetRootViewForScreenshotTests() {
     if (mReactInstanceManager != null) {
       mReactInstanceManager.destroy();
@@ -128,6 +136,16 @@ public void loadApp(
       @Nullable Bundle initialProps,
       String bundleName,
       boolean useDevSupport) {
+    loadApp(appKey, spec, initialProps, bundleName, useDevSupport, null);
+  }
+
+  public void loadApp(
+    String appKey,
+    ReactInstanceSpecForTest spec,
+    @Nullable Bundle initialProps,
+    String bundleName,
+    boolean useDevSupport,
+    UIImplementationProvider uiImplementationProvider) {
 
     final CountDownLatch currentLayoutEvent = mLayoutEvent = new CountDownLatch(1);
     mBridgeIdleSignaler = new ReactBridgeIdleSignaler();
@@ -145,7 +163,8 @@ public void loadApp(
         .addPackage(new InstanceSpecForTestPackage(spec))
         .setUseDeveloperSupport(useDevSupport)
         .setBridgeIdleDebugListener(mBridgeIdleSignaler)
-        .setInitialLifecycleState(mLifecycleState);
+        .setInitialLifecycleState(mLifecycleState)
+        .setUIImplementationProvider(uiImplementationProvider);
 
     mReactInstanceManager = builder.build();
     mReactInstanceManager.onHostResume(this, this);

From 2d921eeb7073d0286d13195e2975b344793998b0 Mon Sep 17 00:00:00 2001
From: Kyle Corbitt <kyle@corbt.com>
Date: Thu, 25 Feb 2016 02:44:58 -0800
Subject: [PATCH 1295/1411] Resolve react flow definitions

Summary:Currently, we're not taking advantage of Flow's built-in type definitions for the React library in all cases because Flow's definition uses `declare module react` and this file uses `import('React')`, which Flow thinks is a different library. After this change, the following starts working which didn't before:

```js
import { Component } from 'react-native';

class MyText extends Component<void, {text: string}, void> {
  render() { return <Text>{this.props.text}</Text> }
}

// Correctly throws a Flow error for the missing "text" prop
const renderedText = <MyText />;
```
Closes https://github.com/facebook/react-native/pull/5489

Differential Revision: D2856176

fb-gh-sync-id: 473ca188ad7d990c3e765526c4b33caf49ad9ffd
shipit-source-id: 473ca188ad7d990c3e765526c4b33caf49ad9ffd
---
 .flowconfig                                       |  3 +++
 Examples/2048/Game2048.js                         |  3 +++
 Examples/UIExplorer/AlertIOSExample.js            |  6 +++++-
 Examples/UIExplorer/AnimatedExample.js            |  4 ++++
 .../UIExplorer/AnimatedGratuitousApp/AnExApp.js   | 15 +++++++++++----
 .../AnimatedGratuitousApp/AnExBobble.js           |  2 ++
 .../AnimatedGratuitousApp/AnExChained.js          |  2 ++
 .../AnimatedGratuitousApp/AnExScroll.js           |  8 ++------
 .../UIExplorer/AnimatedGratuitousApp/AnExSet.js   |  2 ++
 .../UIExplorer/AnimatedGratuitousApp/AnExTilt.js  |  2 ++
 Examples/UIExplorer/ImageEditingExample.js        |  3 ++-
 .../NavigationCompositionExample.js               |  8 +++++++-
 .../NavigationTicTacToeExample.js                 |  7 ++++---
 Examples/UIExplorer/PushNotificationIOSExample.js |  8 +++++---
 Examples/UIExplorer/RCTRootViewIOSExample.js      |  4 ++--
 .../RootViewSizeFlexibilityExampleApp.js          |  1 +
 Examples/UIExplorer/TextInputExample.ios.js       |  8 ++++++++
 Examples/UIExplorer/XHRExample.ios.js             |  2 ++
 Examples/UIExplorer/XHRExampleCookies.js          |  3 +++
 Examples/UIExplorer/XHRExampleFetch.js            |  2 ++
 Examples/UIExplorer/createExamplePage.js          |  1 +
 Libraries/react-native/react-native.js.flow       |  2 +-
 22 files changed, 74 insertions(+), 22 deletions(-)

diff --git a/.flowconfig b/.flowconfig
index 78c0582045e1..db960b5f1b41 100644
--- a/.flowconfig
+++ b/.flowconfig
@@ -48,6 +48,9 @@ Libraries/react-native/react-native-interface.js
 [options]
 module.system=haste
 
+esproposal.class_static_fields=enable
+esproposal.class_instance_fields=enable
+
 munge_underscores=true
 
 module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub'
diff --git a/Examples/2048/Game2048.js b/Examples/2048/Game2048.js
index 239d1dadeca4..a6c97a3e3eda 100644
--- a/Examples/2048/Game2048.js
+++ b/Examples/2048/Game2048.js
@@ -53,6 +53,8 @@ class Board extends React.Component {
 }
 
 class Tile extends React.Component {
+  state: any;
+
   static _getPosition(index): number {
     return BOARD_PADDING + (index * (CELL_SIZE + CELL_MARGIN * 2) + CELL_MARGIN);
   }
@@ -147,6 +149,7 @@ class GameEndOverlay extends React.Component {
 class Game2048 extends React.Component {
   startX: number;
   startY: number;
+  state: any;
 
   constructor(props: {}) {
     super(props);
diff --git a/Examples/UIExplorer/AlertIOSExample.js b/Examples/UIExplorer/AlertIOSExample.js
index a52c1ab79521..d7f0bcf0d464 100644
--- a/Examples/UIExplorer/AlertIOSExample.js
+++ b/Examples/UIExplorer/AlertIOSExample.js
@@ -37,7 +37,7 @@ exports.examples = [{
 },
 {
   title: 'Prompt Options',
-  render(): React.Component {
+  render(): ReactElement {
     return <PromptOptions />;
   }
 },
@@ -85,9 +85,13 @@ exports.examples = [{
 }];
 
 class PromptOptions extends React.Component {
+  state: any;
+  customButtons: Array<Object>;
+
   constructor(props) {
     super(props);
 
+    // $FlowFixMe this seems to be a Flow bug, `saveResponse` is defined below
     this.saveResponse = this.saveResponse.bind(this);
 
     this.customButtons = [{
diff --git a/Examples/UIExplorer/AnimatedExample.js b/Examples/UIExplorer/AnimatedExample.js
index 5f6096338115..1068ac000268 100644
--- a/Examples/UIExplorer/AnimatedExample.js
+++ b/Examples/UIExplorer/AnimatedExample.js
@@ -39,6 +39,8 @@ exports.examples = [
       'mounts.',
     render: function() {
       class FadeInView extends React.Component {
+        state: any;
+
         constructor(props) {
           super(props);
           this.state = {
@@ -66,6 +68,8 @@ exports.examples = [
         }
       }
       class FadeInExample extends React.Component {
+        state: any;
+
         constructor(props) {
           super(props);
           this.state = {
diff --git a/Examples/UIExplorer/AnimatedGratuitousApp/AnExApp.js b/Examples/UIExplorer/AnimatedGratuitousApp/AnExApp.js
index d713b5f66d90..c87bc29823bc 100644
--- a/Examples/UIExplorer/AnimatedGratuitousApp/AnExApp.js
+++ b/Examples/UIExplorer/AnimatedGratuitousApp/AnExApp.js
@@ -32,6 +32,10 @@ var CIRCLE_MARGIN = 18;
 var NUM_CIRCLES = 30;
 
 class Circle extends React.Component {
+  state: any;
+  props: any;
+  longTimer: number;
+
   _onLongPress: () => void;
   _toggleIsActive: () => void;
   constructor(props: Object): void {
@@ -156,6 +160,13 @@ class Circle extends React.Component {
 }
 
 class AnExApp extends React.Component {
+  state: any;
+  props: any;
+
+  static title = 'Animated - Gratuitous App';
+  static description = 'Bunch of Animations - tap a circle to ' +
+    'open a view with more animations, or longPress and drag to reorder circles.';
+
   _onMove: (position: Point) => void;
   constructor(props: any): void {
     super(props);
@@ -266,10 +277,6 @@ function moveToClosest({activeKey, keys, restLayouts}, position) {
   }
 }
 
-AnExApp.title = 'Animated - Gratuitous App';
-AnExApp.description = 'Bunch of Animations - tap a circle to ' +
-  'open a view with more animations, or longPress and drag to reorder circles.';
-
 var styles = StyleSheet.create({
   container: {
     flex: 1,
diff --git a/Examples/UIExplorer/AnimatedGratuitousApp/AnExBobble.js b/Examples/UIExplorer/AnimatedGratuitousApp/AnExBobble.js
index d3e603738c34..39f15a8ec8ea 100644
--- a/Examples/UIExplorer/AnimatedGratuitousApp/AnExBobble.js
+++ b/Examples/UIExplorer/AnimatedGratuitousApp/AnExBobble.js
@@ -36,6 +36,8 @@ var BOBBLE_SPOTS = [...Array(NUM_BOBBLES)].map((_, i) => {  // static positions
 });
 
 class AnExBobble extends React.Component {
+  state: any;
+
   constructor(props: Object) {
     super(props);
     this.state = {};
diff --git a/Examples/UIExplorer/AnimatedGratuitousApp/AnExChained.js b/Examples/UIExplorer/AnimatedGratuitousApp/AnExChained.js
index f2c932a2449c..596617f1780e 100644
--- a/Examples/UIExplorer/AnimatedGratuitousApp/AnExChained.js
+++ b/Examples/UIExplorer/AnimatedGratuitousApp/AnExChained.js
@@ -26,6 +26,8 @@ var {
 } = React;
 
 class AnExChained extends React.Component {
+  state: any;
+
   constructor(props: Object) {
     super(props);
     this.state = {
diff --git a/Examples/UIExplorer/AnimatedGratuitousApp/AnExScroll.js b/Examples/UIExplorer/AnimatedGratuitousApp/AnExScroll.js
index f96acb380a8d..e7712cfc52e8 100644
--- a/Examples/UIExplorer/AnimatedGratuitousApp/AnExScroll.js
+++ b/Examples/UIExplorer/AnimatedGratuitousApp/AnExScroll.js
@@ -12,6 +12,7 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  *
  * @providesModule AnExScroll
+ * @flow
  */
 'use strict';
 
@@ -26,12 +27,7 @@ var {
 } = React;
 
 class AnExScroll extends React.Component {
-  constructor(props) {
-    super(props);
-    this.state = {
-      scrollX: new Animated.Value(0),
-    };
-  }
+  state: any = { scrollX: new Animated.Value(0) };
 
   render() {
     var width = this.props.panelWidth;
diff --git a/Examples/UIExplorer/AnimatedGratuitousApp/AnExSet.js b/Examples/UIExplorer/AnimatedGratuitousApp/AnExSet.js
index f25301f7756f..769a0f79a2d2 100644
--- a/Examples/UIExplorer/AnimatedGratuitousApp/AnExSet.js
+++ b/Examples/UIExplorer/AnimatedGratuitousApp/AnExSet.js
@@ -31,6 +31,8 @@ var AnExScroll = require('./AnExScroll');
 var AnExTilt = require('./AnExTilt');
 
 class AnExSet extends React.Component {
+  state: any;
+
   constructor(props: Object) {
     super(props);
     function randColor() {
diff --git a/Examples/UIExplorer/AnimatedGratuitousApp/AnExTilt.js b/Examples/UIExplorer/AnimatedGratuitousApp/AnExTilt.js
index 3cea77917088..42b5523c011c 100644
--- a/Examples/UIExplorer/AnimatedGratuitousApp/AnExTilt.js
+++ b/Examples/UIExplorer/AnimatedGratuitousApp/AnExTilt.js
@@ -26,6 +26,8 @@ var {
 } = React;
 
 class AnExTilt extends React.Component {
+  state: any;
+
   constructor(props: Object) {
     super(props);
     this.state = {
diff --git a/Examples/UIExplorer/ImageEditingExample.js b/Examples/UIExplorer/ImageEditingExample.js
index 1a8c931221d5..868bbd25f333 100644
--- a/Examples/UIExplorer/ImageEditingExample.js
+++ b/Examples/UIExplorer/ImageEditingExample.js
@@ -47,10 +47,11 @@ type ImageCropData = {
   offset: ImageOffset;
   size: ImageSize;
   displaySize?: ?ImageSize;
-  resizeMode?: ?any; 
+  resizeMode?: ?any;
 };
 
 class SquareImageCropper extends React.Component {
+  state: any;
   _isMounted: boolean;
   _transformData: ImageCropData;
 
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js
index 79e2e94b55ed..1dba3e14ac86 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js
@@ -36,10 +36,14 @@ const NavigationExampleTabBar = require('./NavigationExampleTabBar');
 
 import type {NavigationParentState} from 'NavigationStateUtils';
 
+type Action = {
+  isExitAction?: boolean,
+};
+
 const ExampleExitAction = () => ({
   isExitAction: true,
 });
-ExampleExitAction.match = (action) => (
+ExampleExitAction.match = (action: Action) => (
   action && action.isExitAction === true
 );
 
@@ -196,6 +200,8 @@ class ExampleTabScreen extends React.Component {
 ExampleTabScreen = NavigationContainer.create(ExampleTabScreen);
 
 class NavigationCompositionExample extends React.Component {
+  navRootContainer: NavigationRootContainer;
+
   render() {
     return (
       <NavigationRootContainer
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationTicTacToeExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationTicTacToeExample.js
index f71327572c00..d0604ec08eae 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationTicTacToeExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationTicTacToeExample.js
@@ -98,6 +98,7 @@ function isGameOver(gameString: string): boolean {
 }
 
 class Cell extends React.Component {
+  props: any;
   cellStyle() {
     switch (this.props.player) {
       case 'X':
@@ -207,6 +208,9 @@ function GameReducer(lastGame: ?string, action: Object): string {
 }
 
 class NavigationTicTacToeExample extends React.Component {
+  static GameView = TicTacToeGame;
+  static GameReducer = GameReducer;
+  static GameActions = GameActions;
   render() {
     return (
       <NavigationRootContainer
@@ -222,9 +226,6 @@ class NavigationTicTacToeExample extends React.Component {
     );
   }
 }
-NavigationTicTacToeExample.GameView = TicTacToeGame;
-NavigationTicTacToeExample.GameReducer = GameReducer;
-NavigationTicTacToeExample.GameActions = GameActions;
 
 const styles = StyleSheet.create({
   closeButton: {
diff --git a/Examples/UIExplorer/PushNotificationIOSExample.js b/Examples/UIExplorer/PushNotificationIOSExample.js
index bd6109f1f09b..9fcf8cd1c343 100644
--- a/Examples/UIExplorer/PushNotificationIOSExample.js
+++ b/Examples/UIExplorer/PushNotificationIOSExample.js
@@ -84,6 +84,8 @@ class NotificationExample extends React.Component {
 }
 
 class NotificationPermissionExample extends React.Component {
+  state: any;
+
   constructor(props) {
     super(props);
     this.state = {permissions: null};
@@ -126,7 +128,7 @@ exports.description = 'Apple PushNotification and badge value';
 exports.examples = [
 {
   title: 'Badge Number',
-  render(): React.Component {
+  render(): ReactElement {
     PushNotificationIOS.requestPermissions();
 
     return (
@@ -145,13 +147,13 @@ exports.examples = [
 },
 {
   title: 'Push Notifications',
-  render(): React.Component {
+  render(): ReactElement {
     return <NotificationExample />;
   }
 },
 {
   title: 'Notifications Permissions',
-  render(): React.Component {
+  render(): ReactElement {
     return <NotificationPermissionExample />;
   }
 }];
diff --git a/Examples/UIExplorer/RCTRootViewIOSExample.js b/Examples/UIExplorer/RCTRootViewIOSExample.js
index 69ecab0a7655..5aa56cf881e4 100644
--- a/Examples/UIExplorer/RCTRootViewIOSExample.js
+++ b/Examples/UIExplorer/RCTRootViewIOSExample.js
@@ -82,7 +82,7 @@ exports.description = 'Examples that show useful methods when embedding React Na
 exports.examples = [
 {
   title: 'Updating app properties in runtime',
-  render(): React.Component {
+  render(): ReactElement {
     return (
       <AppPropertiesUpdateExample/>
     );
@@ -90,7 +90,7 @@ exports.examples = [
 },
 {
   title: 'RCTRootView\'s size flexibility',
-  render(): React.Component {
+  render(): ReactElement {
     return (
       <RootViewSizeFlexibilityExample/>
     );
diff --git a/Examples/UIExplorer/RootViewSizeFlexibilityExampleApp.js b/Examples/UIExplorer/RootViewSizeFlexibilityExampleApp.js
index baab38671791..9c48357033fb 100644
--- a/Examples/UIExplorer/RootViewSizeFlexibilityExampleApp.js
+++ b/Examples/UIExplorer/RootViewSizeFlexibilityExampleApp.js
@@ -24,6 +24,7 @@ const {
 } = React;
 
 class RootViewSizeFlexibilityExampleApp extends React.Component {
+  state: any;
 
   constructor(props: {toggled: boolean}) {
     super(props);
diff --git a/Examples/UIExplorer/TextInputExample.ios.js b/Examples/UIExplorer/TextInputExample.ios.js
index eac262d77061..239197dbacbb 100644
--- a/Examples/UIExplorer/TextInputExample.ios.js
+++ b/Examples/UIExplorer/TextInputExample.ios.js
@@ -97,6 +97,8 @@ var TextEventsExample = React.createClass({
 });
 
 class AutoExpandingTextInput extends React.Component {
+  state: any;
+
   constructor(props) {
     super(props);
     this.state = {text: '', height: 0};
@@ -120,6 +122,8 @@ class AutoExpandingTextInput extends React.Component {
 }
 
 class RewriteExample extends React.Component {
+  state: any;
+
   constructor(props) {
     super(props);
     this.state = {text: ''};
@@ -149,6 +153,8 @@ class RewriteExample extends React.Component {
 }
 
 class RewriteExampleInvalidCharacters extends React.Component {
+  state: any;
+
   constructor(props) {
     super(props);
     this.state = {text: ''};
@@ -170,6 +176,8 @@ class RewriteExampleInvalidCharacters extends React.Component {
 }
 
 class TokenizedTextExample extends React.Component {
+  state: any;
+
   constructor(props) {
     super(props);
     this.state = {text: 'Hello #World'};
diff --git a/Examples/UIExplorer/XHRExample.ios.js b/Examples/UIExplorer/XHRExample.ios.js
index 5d909b3cb7e2..a9de630e2c2d 100644
--- a/Examples/UIExplorer/XHRExample.ios.js
+++ b/Examples/UIExplorer/XHRExample.ios.js
@@ -33,6 +33,7 @@ var XHRExampleHeaders = require('./XHRExampleHeaders');
 var XHRExampleFetch = require('./XHRExampleFetch');
 
 class Downloader extends React.Component {
+  state: any;
 
   xhr: XMLHttpRequest;
   cancelled: boolean;
@@ -120,6 +121,7 @@ class Downloader extends React.Component {
 var PAGE_SIZE = 20;
 
 class FormUploader extends React.Component {
+  state: any;
 
   _isMounted: boolean;
   _fetchRandomPhoto: () => void;
diff --git a/Examples/UIExplorer/XHRExampleCookies.js b/Examples/UIExplorer/XHRExampleCookies.js
index 310accc19b60..d4cfad0e5f14 100644
--- a/Examples/UIExplorer/XHRExampleCookies.js
+++ b/Examples/UIExplorer/XHRExampleCookies.js
@@ -26,6 +26,9 @@ var {
 var RCTNetworking = require('RCTNetworking');
 
 class XHRExampleCookies extends React.Component {
+  state: any;
+  cancelled: boolean;
+
   constructor(props: any) {
     super(props);
     this.cancelled = false;
diff --git a/Examples/UIExplorer/XHRExampleFetch.js b/Examples/UIExplorer/XHRExampleFetch.js
index 893dd7591201..87e8e1bb6465 100644
--- a/Examples/UIExplorer/XHRExampleFetch.js
+++ b/Examples/UIExplorer/XHRExampleFetch.js
@@ -26,6 +26,8 @@ var {
 
 
 class XHRExampleFetch extends React.Component {
+  state: any;
+  responseURL: ?string;
 
   constructor(props: any) {
     super(props);
diff --git a/Examples/UIExplorer/createExamplePage.js b/Examples/UIExplorer/createExamplePage.js
index 55ebd159961d..20d62badf73b 100644
--- a/Examples/UIExplorer/createExamplePage.js
+++ b/Examples/UIExplorer/createExamplePage.js
@@ -50,6 +50,7 @@ var createExamplePage = function(title: ?string, exampleModule: ExampleModule)
       // Hack warning: This is a hack because the www UI explorer requires
       // renderComponent to be called.
       var originalRender = React.render;
+      // $FlowFixMe React.renderComponent was deprecated in 0.12, should this be React.render?
       var originalRenderComponent = React.renderComponent;
       var originalIOSRender = ReactNative.render;
       var originalIOSRenderComponent = ReactNative.renderComponent;
diff --git a/Libraries/react-native/react-native.js.flow b/Libraries/react-native/react-native.js.flow
index bbe2acdfecc0..e7aa8059055c 100644
--- a/Libraries/react-native/react-native.js.flow
+++ b/Libraries/react-native/react-native.js.flow
@@ -23,7 +23,7 @@
 //
 //   var ReactNative = {...require('React'), /* additions */}
 //
-var ReactNative = Object.assign(Object.create(require('React')), {
+var ReactNative = Object.assign(Object.create(require('react')), {
   // Components
   ActivityIndicatorIOS: require('ActivityIndicatorIOS'),
   ART: require('ReactNativeART'),

From 3ed66ee7b5c5d81d173ab249569bd6f07c10a085 Mon Sep 17 00:00:00 2001
From: PJ Cabrera <pj.cabrera@gmail.com>
Date: Thu, 25 Feb 2016 06:25:29 -0800
Subject: [PATCH 1296/1411] Fix scrollResponderScrollTo deprecated warning

Summary:Fix the warning generated when some ScrollResponder methods call the deprecated form of scrollResponderScrollTo.
Closes https://github.com/facebook/react-native/pull/6138

Differential Revision: D2976681

fb-gh-sync-id: 3f5195aeebbffeccadb4bbffc55d52d7f89a9b2d
shipit-source-id: 3f5195aeebbffeccadb4bbffc55d52d7f89a9b2d
---
 Libraries/Components/ScrollResponder.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/Components/ScrollResponder.js b/Libraries/Components/ScrollResponder.js
index c37de7ba5ebf..f58db6c8f134 100644
--- a/Libraries/Components/ScrollResponder.js
+++ b/Libraries/Components/ScrollResponder.js
@@ -391,7 +391,7 @@ var ScrollResponderMixin = {
    */
   scrollResponderScrollWithoutAnimationTo: function(offsetX: number, offsetY: number) {
     console.warn('`scrollResponderScrollWithoutAnimationTo` is deprecated. Use `scrollResponderScrollTo` instead');
-    this.scrollResponderScrollTo(offsetX, offsetY, false);
+    this.scrollResponderScrollTo({x: offsetX, y: offsetY, animated: false});
   },
 
   /**

From f0689cf53431a4eb59c2815e1438406904eac083 Mon Sep 17 00:00:00 2001
From: Dae San Hwang <daesan@polle.com>
Date: Thu, 25 Feb 2016 07:08:33 -0800
Subject: [PATCH 1297/1411] add Universal Links support to
 Linking.getInitialURL(). Fixes #6099

Summary:Currently, Linking.getInitialURL() only supports custom URL scheme and not Universal Links. This PR fixes that. see #6099
Closes https://github.com/facebook/react-native/pull/6147

Differential Revision: D2976902

Pulled By: javache

fb-gh-sync-id: 750fe4a7c251ba57433c3a24866a4a510f125069
shipit-source-id: 750fe4a7c251ba57433c3a24866a4a510f125069
---
 Libraries/LinkingIOS/RCTLinkingManager.m | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/Libraries/LinkingIOS/RCTLinkingManager.m b/Libraries/LinkingIOS/RCTLinkingManager.m
index 1a30422175b1..5bbdd998f76e 100644
--- a/Libraries/LinkingIOS/RCTLinkingManager.m
+++ b/Libraries/LinkingIOS/RCTLinkingManager.m
@@ -33,7 +33,18 @@ - (void)setBridge:(RCTBridge *)bridge
 
 - (NSDictionary<NSString *, id> *)constantsToExport
 {
-  NSURL *initialURL = _bridge.launchOptions[UIApplicationLaunchOptionsURLKey];
+  NSURL *initialURL;
+  
+  if (_bridge.launchOptions[UIApplicationLaunchOptionsURLKey]) {
+    initialURL = _bridge.launchOptions[UIApplicationLaunchOptionsURLKey];
+  } else if (_bridge.launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey]) {
+    NSDictionary *userActivityDictionary = _bridge.launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey];
+
+    if ([userActivityDictionary[UIApplicationLaunchOptionsUserActivityTypeKey] isEqual:NSUserActivityTypeBrowsingWeb]) {
+      initialURL = ((NSUserActivity *)userActivityDictionary[@"UIApplicationLaunchOptionsUserActivityKey"]).webpageURL;
+    }
+  }
+  
   return @{@"initialURL": RCTNullIfNil(initialURL.absoluteString)};
 }
 

From 13f2aea85f8db9eec3bd42b66f9dc868e0d5a24e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C5=A1per=20=C5=BDnidar=C5=A1i=C4=8D=20Be=C4=8Daj?=
 <gapa@jotajomo.com>
Date: Thu, 25 Feb 2016 07:22:18 -0800
Subject: [PATCH 1298/1411] Fix for different geolocation timestamp for Android
 and iOS

Summary:Geolocation timestamp is different for Android and iOs. For Android it is returning in UTC time in milliseconds since January 1, 1970, for iOS it was returned as time interval relative to an absolute reference date (00:00:00 UTC on 1 January 2001). Also for iOS time returned was "current system absolute time" and not the time at which this location was determined.

Tested with 0.21.0-rc React Native. Init project with this additional code:
`constructor(props) {super(props);
    navigator.geolocation.getCurrentPosition(
      (position) => {
        let initialPosition = JSON.stringify(position);
        console.log(position.timestamp);
      },
      (error) => alert(error.message),
      {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000} );
  }
`

Tested with iOs simulator (iPhone 6S plus 9.2; iPhone 5s 8.4 )

sample result with change: 1456407795021.235
sample result without change: 23478100615007.884

Explaining links for iOS:
https://developer.apple.com/library/ios/do
Closes https://github.com/facebook/react-native/pull/6150

Differential Revision: D2976909

Pulled By: nicklockwood

fb-gh-sync-id: 9607ed669d7200591f8387e4186cf7c225ae9b3a
shipit-source-id: 9607ed669d7200591f8387e4186cf7c225ae9b3a
---
 Libraries/Geolocation/RCTLocationObserver.m | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/Geolocation/RCTLocationObserver.m b/Libraries/Geolocation/RCTLocationObserver.m
index 7320fae8980c..080cc9f4eab3 100644
--- a/Libraries/Geolocation/RCTLocationObserver.m
+++ b/Libraries/Geolocation/RCTLocationObserver.m
@@ -270,7 +270,7 @@ - (void)locationManager:(CLLocationManager *)manager
       @"heading": @(location.course),
       @"speed": @(location.speed),
     },
-    @"timestamp": @(CFAbsoluteTimeGetCurrent() * 1000.0) // in ms
+    @"timestamp": @([location.timestamp timeIntervalSince1970] * 1000) // in ms
   };
 
   // Send event

From b8e7fe4959ca3249aef1844cce2f83afb740df84 Mon Sep 17 00:00:00 2001
From: Alexander Blom <blom@fb.com>
Date: Thu, 25 Feb 2016 07:45:34 -0800
Subject: [PATCH 1299/1411] Copy exif data when resizing images in
 ImageEditingManager

Summary:Previously images that have exif orientation data would be cropped and the exif data
would be lost leading to us displaying pictures rotated in error.

Reviewed By: foghina

Differential Revision: D2971596

fb-gh-sync-id: 40f92e27089455259a7d8b83c92d0cf36367e5df
shipit-source-id: 40f92e27089455259a7d8b83c92d0cf36367e5df
---
 .../modules/camera/ImageEditingManager.java   | 81 +++++++++++++++++++
 1 file changed, 81 insertions(+)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageEditingManager.java b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageEditingManager.java
index cbcfbb596e00..be9ef2f892ea 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageEditingManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageEditingManager.java
@@ -24,13 +24,19 @@
 import java.util.List;
 import java.util.Map;
 
+import android.annotation.SuppressLint;
 import android.content.Context;
+import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Matrix;
+import android.media.ExifInterface;
 import android.net.Uri;
 import android.os.AsyncTask;
+import android.provider.MediaStore;
+import android.text.TextUtils;
 
+import com.facebook.common.logging.FLog;
 import com.facebook.react.bridge.Callback;
 import com.facebook.react.bridge.GuardedAsyncTask;
 import com.facebook.react.bridge.ReactApplicationContext;
@@ -40,6 +46,7 @@
 import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
 import com.facebook.react.bridge.ReadableMap;
 import com.facebook.infer.annotation.Assertions;
+import com.facebook.react.common.ReactConstants;
 
 /**
  * Native module that provides image cropping functionality.
@@ -54,6 +61,35 @@ public class ImageEditingManager extends ReactContextBaseJavaModule {
   /** Compress quality of the output file. */
   private static final int COMPRESS_QUALITY = 90;
 
+  @SuppressLint("InlinedApi") private static final String[] EXIF_ATTRIBUTES = new String[] {
+    ExifInterface.TAG_APERTURE,
+    ExifInterface.TAG_DATETIME,
+    ExifInterface.TAG_DATETIME_DIGITIZED,
+    ExifInterface.TAG_EXPOSURE_TIME,
+    ExifInterface.TAG_FLASH,
+    ExifInterface.TAG_FOCAL_LENGTH,
+    ExifInterface.TAG_GPS_ALTITUDE,
+    ExifInterface.TAG_GPS_ALTITUDE_REF,
+    ExifInterface.TAG_GPS_DATESTAMP,
+    ExifInterface.TAG_GPS_LATITUDE,
+    ExifInterface.TAG_GPS_LATITUDE_REF,
+    ExifInterface.TAG_GPS_LONGITUDE,
+    ExifInterface.TAG_GPS_LONGITUDE_REF,
+    ExifInterface.TAG_GPS_PROCESSING_METHOD,
+    ExifInterface.TAG_GPS_TIMESTAMP,
+    ExifInterface.TAG_IMAGE_LENGTH,
+    ExifInterface.TAG_IMAGE_WIDTH,
+    ExifInterface.TAG_ISO,
+    ExifInterface.TAG_MAKE,
+    ExifInterface.TAG_MODEL,
+    ExifInterface.TAG_ORIENTATION,
+    ExifInterface.TAG_SUBSEC_TIME,
+    ExifInterface.TAG_SUBSEC_TIME_DIG,
+    ExifInterface.TAG_SUBSEC_TIME_ORIG,
+    ExifInterface.TAG_WHITE_BALANCE
+  };
+
+
   public ImageEditingManager(ReactApplicationContext reactContext) {
     super(reactContext);
     new CleanTask(getReactApplicationContext()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
@@ -241,6 +277,10 @@ protected void doInBackgroundGuarded(Void... params) {
         File tempFile = createTempFile(mContext, mimeType);
         writeCompressedBitmapToFile(cropped, mimeType, tempFile);
 
+        if (mimeType.equals("image/jpeg")) {
+          copyExif(mContext, Uri.parse(mUri), tempFile);
+        }
+
         mSuccess.invoke(Uri.fromFile(tempFile).toString());
 
       } catch (Exception e) {
@@ -352,6 +392,47 @@ private Bitmap cropAndResize(
 
   // Utils
 
+  private static void copyExif(Context context, Uri oldImage, File newFile) throws IOException {
+    File oldFile = getFileFromUri(context, oldImage);
+    if (oldFile == null) {
+      FLog.w(ReactConstants.TAG, "Couldn't get real path for uri: " + oldImage);
+      return;
+    }
+
+    ExifInterface oldExif = new ExifInterface(oldFile.getAbsolutePath());
+    ExifInterface newExif = new ExifInterface(newFile.getAbsolutePath());
+    for (String attribute : EXIF_ATTRIBUTES) {
+      String value = oldExif.getAttribute(attribute);
+      if (value != null) {
+        newExif.setAttribute(attribute, value);
+      }
+    }
+    newExif.saveAttributes();
+  }
+
+  private static @Nullable File getFileFromUri(Context context, Uri uri) {
+    if (uri.getScheme().equals("file")) {
+      return new File(uri.getPath());
+    } else if (uri.getScheme().equals("content")) {
+      Cursor cursor = context.getContentResolver()
+        .query(uri, new String[] { MediaStore.MediaColumns.DATA }, null, null, null);
+      if (cursor != null) {
+        try {
+          if (cursor.moveToFirst()) {
+            String path = cursor.getString(0);
+            if (!TextUtils.isEmpty(path)) {
+              return new File(path);
+            }
+          }
+        } finally {
+          cursor.close();
+        }
+      }
+    }
+
+    return null;
+  }
+
   private static boolean isLocalUri(String uri) {
     for (String localPrefix : LOCAL_URI_PREFIXES) {
       if (uri.startsWith(localPrefix)) {

From f51c16b2709dd5fac42f7f538f5988e799e03be3 Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Thu, 25 Feb 2016 09:38:23 -0800
Subject: [PATCH 1300/1411] Avoid dirtying layout when frame doesn't change

Reviewed By: nicklockwood

Differential Revision: D2939782

fb-gh-sync-id: e2346f053e9594e5d24d1e73d493a34446fb228c
shipit-source-id: e2346f053e9594e5d24d1e73d493a34446fb228c
---
 React/Modules/RCTUIManager.m | 34 ++++++++++++++++++++--------------
 1 file changed, 20 insertions(+), 14 deletions(-)

diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m
index dd7d53448345..803d139b0205 100644
--- a/React/Modules/RCTUIManager.m
+++ b/React/Modules/RCTUIManager.m
@@ -375,19 +375,27 @@ - (void)setFrame:(CGRect)frame forView:(UIView *)view
 
   NSNumber *reactTag = view.reactTag;
   dispatch_async(_shadowQueue, ^{
-    RCTShadowView *rootShadowView = _shadowViewRegistry[reactTag];
-    RCTAssert(rootShadowView != nil, @"Could not locate root view with tag #%@", reactTag);
+    RCTShadowView *shadowView = _shadowViewRegistry[reactTag];
+    RCTAssert(shadowView != nil, @"Could not locate shadow view with tag #%@", reactTag);
 
-    if (RCTIsReactRootView(reactTag)) {
-      rootShadowView.frame = frame;
-      rootShadowView.sizeFlexibility = sizeFlexibility;
-    } else {
-      rootShadowView.frame = frame;
+    BOOL dirtyLayout = NO;
+
+    if (!CGRectEqualToRect(frame, shadowView.frame)) {
+      shadowView.frame = frame;
+      dirtyLayout = YES;
     }
 
-    [rootShadowView dirtyLayout];
+    // Trigger re-layout when size flexibility changes, as the root view might grow or
+    // shrink in the flexible dimensions.
+    if (RCTIsReactRootView(reactTag) && shadowView.sizeFlexibility != sizeFlexibility) {
+      shadowView.sizeFlexibility = sizeFlexibility;
+      dirtyLayout = YES;
+    }
 
-    [self batchDidComplete];
+    if (dirtyLayout) {
+      [shadowView dirtyLayout];
+      [self batchDidComplete];
+    }
   });
 }
 
@@ -1045,18 +1053,16 @@ - (void)setNeedsLayout
       callback(@[]);
       return;
     }
-    CGRect frame = view.frame;
 
+    // If in a <Modal>, rootView will be the root of the modal container.
     UIView *rootView = view;
-    while (rootView && ![rootView isReactRootView]) {
+    while (rootView.superview && ![rootView isReactRootView]) {
       rootView = rootView.superview;
     }
 
-    // TODO: this doesn't work because sometimes view is inside a modal window
-    // RCTAssert([rootView isReactRootView], @"React view is not inside a React root view");
-
     // By convention, all coordinates, whether they be touch coordinates, or
     // measurement coordinates are with respect to the root view.
+    CGRect frame = view.frame;
     CGPoint pagePoint = [view.superview convertPoint:frame.origin toView:rootView];
 
     callback(@[

From 45a52c72ff933af8fc01d1b02611eecde6c63c04 Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Thu, 25 Feb 2016 09:52:01 -0800
Subject: [PATCH 1301/1411] Support multiple interface orientations in
 RCTDevLoadingView

Summary: When rotating on iPad, the dev loading view just looks clowny since it doesn't rotate properly.

Reviewed By: majak

Differential Revision: D2939721

fb-gh-sync-id: 7f1926f5cee4761cde8881e9387ae6e0063c5d6c
shipit-source-id: 7f1926f5cee4761cde8881e9387ae6e0063c5d6c
---
 React/Modules/RCTDevLoadingView.m        |  4 ++++
 React/Views/RCTModalHostViewController.m | 10 ++++++++++
 2 files changed, 14 insertions(+)

diff --git a/React/Modules/RCTDevLoadingView.m b/React/Modules/RCTDevLoadingView.m
index 5c799791cf2a..708454754fd5 100644
--- a/React/Modules/RCTDevLoadingView.m
+++ b/React/Modules/RCTDevLoadingView.m
@@ -13,6 +13,7 @@
 #import "RCTDevLoadingView.h"
 #import "RCTDefines.h"
 #import "RCTUtils.h"
+#import "RCTModalHostViewController.h"
 
 #if RCT_DEV
 
@@ -68,6 +69,9 @@ - (void)setBridge:(RCTBridge *)bridge
       _window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, screenWidth, 22)];
       _window.windowLevel = UIWindowLevelStatusBar + 1;
 
+      // set a root VC so rotation is supported
+      _window.rootViewController = [RCTModalHostViewController new];
+
       _label = [[UILabel alloc] initWithFrame:_window.bounds];
       _label.font = [UIFont systemFontOfSize:12.0];
       _label.textAlignment = NSTextAlignmentCenter;
diff --git a/React/Views/RCTModalHostViewController.m b/React/Views/RCTModalHostViewController.m
index ce40551bddc0..192e7ffb9d36 100644
--- a/React/Views/RCTModalHostViewController.m
+++ b/React/Views/RCTModalHostViewController.m
@@ -24,4 +24,14 @@ - (void)viewDidLayoutSubviews
   }
 }
 
+- (UIInterfaceOrientationMask)supportedInterfaceOrientations
+{
+  // Picking some defaults here, we should probably make this configurable
+  if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
+    return UIInterfaceOrientationMaskAll;
+  } else {
+    return UIInterfaceOrientationMaskPortrait;
+  }
+}
+
 @end

From 480e9abec5473121199ed64d9dd0d5cf6b046687 Mon Sep 17 00:00:00 2001
From: Hedger Wang <hedger@fb.com>
Date: Thu, 25 Feb 2016 14:50:28 -0800
Subject: [PATCH 1302/1411] Sets up example for LegacyNavigator.

Summary:We'd plan to build the `NavigationLegacyNavigator` that is meant to replace
Navigator seemlessly without  API changes. While the APIs remain
compatible with Navigator, it should be built with the new
Navigation API such as `NavigationAnimatedView`...etc.

To ensure that the new NavigationLegacyNavigagtor delivers the same
UX and maintains APIs compability, we'd start with using the exact same
examples as the same ones that Navigator uses.

Reviewed By: ericvicenti

Differential Revision: D2955273

fb-gh-sync-id: b4723cf54ea2258e5589f39dceeaee88be2b93f0
shipit-source-id: b4723cf54ea2258e5589f39dceeaee88be2b93f0
---
 .../LegacyNavigator/BreadcrumbNavSample.js    | 164 +++++++++++++
 .../LegacyNavigator/JumpingNavSample.js       | 218 ++++++++++++++++++
 .../LegacyNavigator/LegacyNavigatorExample.js | 212 +++++++++++++++++
 .../LegacyNavigator/NavigationBarSample.js    | 203 ++++++++++++++++
 .../NavigationExperimentalExample.js          |   2 +-
 Examples/UIExplorer/UIExplorerList.ios.js     |   4 +
 .../NavigationLegacyNavigator.js              |  37 +++
 .../NavigationExperimental.js                 |   4 +-
 8 files changed, 842 insertions(+), 2 deletions(-)
 create mode 100644 Examples/UIExplorer/NavigationExperimental/LegacyNavigator/BreadcrumbNavSample.js
 create mode 100644 Examples/UIExplorer/NavigationExperimental/LegacyNavigator/JumpingNavSample.js
 create mode 100644 Examples/UIExplorer/NavigationExperimental/LegacyNavigator/LegacyNavigatorExample.js
 create mode 100644 Examples/UIExplorer/NavigationExperimental/LegacyNavigator/NavigationBarSample.js
 create mode 100644 Libraries/CustomComponents/NavigationExperimental/NavigationLegacyNavigator.js

diff --git a/Examples/UIExplorer/NavigationExperimental/LegacyNavigator/BreadcrumbNavSample.js b/Examples/UIExplorer/NavigationExperimental/LegacyNavigator/BreadcrumbNavSample.js
new file mode 100644
index 000000000000..15251a4cf2f7
--- /dev/null
+++ b/Examples/UIExplorer/NavigationExperimental/LegacyNavigator/BreadcrumbNavSample.js
@@ -0,0 +1,164 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+*/
+'use strict';
+
+var React = require('react-native');
+var {
+  NavigationExperimental,
+  StyleSheet,
+  ScrollView,
+  Text,
+  TouchableHighlight,
+  TouchableOpacity
+} = React;
+
+var _getRandomRoute = function() {
+  return {
+    title: '#' + Math.ceil(Math.random() * 1000),
+  };
+};
+
+var Navigator = NavigationExperimental.LegacyNavigator;
+
+class NavButton extends React.Component {
+  render() {
+    return (
+      <TouchableHighlight
+        style={styles.button}
+        underlayColor="#B5B5B5"
+        onPress={this.props.onPress}>
+        <Text style={styles.buttonText}>{this.props.text}</Text>
+      </TouchableHighlight>
+    );
+  }
+}
+
+var BreadcrumbNavSample = React.createClass({
+
+  componentWillMount: function() {
+    this._navBarRouteMapper = {
+      rightContentForRoute: function(route, navigator) {
+        return null;
+      },
+      titleContentForRoute: function(route, navigator) {
+        return (
+          <TouchableOpacity
+            onPress={() => navigator.push(_getRandomRoute())}>
+            <Text style={styles.titleText}>{route.title}</Text>
+          </TouchableOpacity>
+        );
+      },
+      iconForRoute: function(route, navigator) {
+        return (
+          <TouchableOpacity
+            onPress={() => { navigator.popToRoute(route); }}
+            style={styles.crumbIconPlaceholder}
+          />
+        );
+      },
+      separatorForRoute: function(route, navigator) {
+        return (
+          <TouchableOpacity
+            onPress={navigator.pop}
+            style={styles.crumbSeparatorPlaceholder}
+          />
+        );
+      }
+    };
+  },
+
+  _renderScene: function(route, navigator) {
+    return (
+      <ScrollView style={styles.scene}>
+        <NavButton
+          onPress={() => { navigator.push(_getRandomRoute()); }}
+          text="Push"
+        />
+        <NavButton
+          onPress={() => { navigator.immediatelyResetRouteStack([_getRandomRoute(), _getRandomRoute()]); }}
+          text="Reset w/ 2 scenes"
+        />
+        <NavButton
+          onPress={() => { navigator.popToTop(); }}
+          text="Pop to top"
+        />
+        <NavButton
+          onPress={() => { navigator.replace(_getRandomRoute()); }}
+          text="Replace"
+        />
+        <NavButton
+          onPress={() => { this.props.navigator.pop(); }}
+          text="Close breadcrumb example"
+        />
+      </ScrollView>
+    );
+  },
+
+  render: function() {
+    return (
+      <Navigator
+        style={styles.container}
+        initialRoute={_getRandomRoute()}
+        renderScene={this._renderScene}
+        navigationBar={
+          <Navigator.BreadcrumbNavigationBar
+            routeMapper={this._navBarRouteMapper}
+          />
+        }
+      />
+    );
+  },
+
+
+
+});
+
+var styles = StyleSheet.create({
+  scene: {
+    paddingTop: 50,
+    flex: 1,
+  },
+  button: {
+    backgroundColor: 'white',
+    padding: 15,
+    borderBottomWidth: StyleSheet.hairlineWidth,
+    borderBottomColor: '#CDCDCD',
+  },
+  buttonText: {
+    fontSize: 17,
+    fontWeight: '500',
+  },
+  container: {
+    overflow: 'hidden',
+    backgroundColor: '#dddddd',
+    flex: 1,
+  },
+  titleText: {
+    fontSize: 18,
+    color: '#666666',
+    textAlign: 'center',
+    fontWeight: 'bold',
+    lineHeight: 32,
+  },
+  crumbIconPlaceholder: {
+    flex: 1,
+    backgroundColor: '#666666',
+  },
+  crumbSeparatorPlaceholder: {
+    flex: 1,
+    backgroundColor: '#aaaaaa',
+  },
+});
+
+module.exports = BreadcrumbNavSample;
diff --git a/Examples/UIExplorer/NavigationExperimental/LegacyNavigator/JumpingNavSample.js b/Examples/UIExplorer/NavigationExperimental/LegacyNavigator/JumpingNavSample.js
new file mode 100644
index 000000000000..aa2b9fd7df6c
--- /dev/null
+++ b/Examples/UIExplorer/NavigationExperimental/LegacyNavigator/JumpingNavSample.js
@@ -0,0 +1,218 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+*/
+'use strict';
+
+var React = require('react-native');
+var {
+  NavigationExperimental,
+  StyleSheet,
+  ScrollView,
+  TabBarIOS,
+  Text,
+  TouchableHighlight,
+  View,
+} = React;
+
+var _getRandomRoute = function() {
+  return {
+    randNumber: Math.ceil(Math.random() * 1000),
+  };
+};
+
+var Navigator = NavigationExperimental.LegacyNavigator;
+
+class NavButton extends React.Component {
+  render() {
+    return (
+      <TouchableHighlight
+        style={styles.button}
+        underlayColor="#B5B5B5"
+        onPress={this.props.onPress}>
+        <Text style={styles.buttonText}>{this.props.text}</Text>
+      </TouchableHighlight>
+    );
+  }
+}
+
+var ROUTE_STACK = [
+  _getRandomRoute(),
+  _getRandomRoute(),
+  _getRandomRoute(),
+];
+var INIT_ROUTE_INDEX = 1;
+
+class JumpingNavBar extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      tabIndex: props.initTabIndex,
+    };
+  }
+  handleWillFocus(route) {
+    var tabIndex = ROUTE_STACK.indexOf(route);
+    this.setState({ tabIndex, });
+  }
+  render() {
+    return (
+      <View style={styles.tabs}>
+        <TabBarIOS>
+          <TabBarIOS.Item
+            icon={require('image!tabnav_notification')}
+            selected={this.state.tabIndex === 0}
+            onPress={() => {
+              this.props.onTabIndex(0);
+              this.setState({ tabIndex: 0, });
+            }}>
+            <View />
+          </TabBarIOS.Item>
+          <TabBarIOS.Item
+            icon={require('image!tabnav_list')}
+            selected={this.state.tabIndex === 1}
+            onPress={() => {
+              this.props.onTabIndex(1);
+              this.setState({ tabIndex: 1, });
+            }}>
+            <View />
+          </TabBarIOS.Item>
+          <TabBarIOS.Item
+            icon={require('image!tabnav_settings')}
+            selected={this.state.tabIndex === 2}
+            onPress={() => {
+              this.props.onTabIndex(2);
+              this.setState({ tabIndex: 2, });
+            }}>
+            <View />
+          </TabBarIOS.Item>
+        </TabBarIOS>
+      </View>
+    );
+  }
+}
+
+var JumpingNavSample = React.createClass({
+  render: function() {
+    return (
+      <Navigator
+        debugOverlay={false}
+        style={styles.appContainer}
+        ref={(navigator) => {
+          this._navigator = navigator;
+        }}
+        initialRoute={ROUTE_STACK[INIT_ROUTE_INDEX]}
+        initialRouteStack={ROUTE_STACK}
+        renderScene={this.renderScene}
+        configureScene={() => ({
+          ...Navigator.SceneConfigs.HorizontalSwipeJump,
+        })}
+        navigationBar={
+          <JumpingNavBar
+            ref={(navBar) => { this.navBar = navBar; }}
+            initTabIndex={INIT_ROUTE_INDEX}
+            routeStack={ROUTE_STACK}
+            onTabIndex={(index) => {
+              this._navigator.jumpTo(ROUTE_STACK[index]);
+            }}
+          />
+        }
+      />
+    );
+  },
+
+  renderScene: function(route, navigator) {
+    var backBtn;
+    var forwardBtn;
+    if (ROUTE_STACK.indexOf(route) !== 0) {
+      backBtn = (
+        <NavButton
+          onPress={() => {
+            navigator.jumpBack();
+          }}
+          text="jumpBack"
+        />
+      );
+    }
+    if (ROUTE_STACK.indexOf(route) !== ROUTE_STACK.length - 1) {
+      forwardBtn = (
+        <NavButton
+          onPress={() => {
+            navigator.jumpForward();
+          }}
+          text="jumpForward"
+        />
+      );
+    }
+    return (
+      <ScrollView style={styles.scene}>
+        <Text style={styles.messageText}>#{route.randNumber}</Text>
+        {backBtn}
+        {forwardBtn}
+        <NavButton
+          onPress={() => {
+            navigator.jumpTo(ROUTE_STACK[1]);
+          }}
+          text="jumpTo middle route"
+        />
+        <NavButton
+          onPress={() => {
+            this.props.navigator.pop();
+          }}
+          text="Exit Navigation Example"
+        />
+        <NavButton
+          onPress={() => {
+            this.props.navigator.push({
+              message: 'Came from jumping example',
+            });
+          }}
+          text="Nav Menu"
+        />
+      </ScrollView>
+    );
+  },
+});
+
+var styles = StyleSheet.create({
+  button: {
+    backgroundColor: 'white',
+    padding: 15,
+    borderBottomWidth: StyleSheet.hairlineWidth,
+    borderBottomColor: '#CDCDCD',
+  },
+  buttonText: {
+    fontSize: 17,
+    fontWeight: '500',
+  },
+  appContainer: {
+    overflow: 'hidden',
+    backgroundColor: '#dddddd',
+    flex: 1,
+  },
+  messageText: {
+    fontSize: 17,
+    fontWeight: '500',
+    padding: 15,
+    marginTop: 50,
+    marginLeft: 15,
+  },
+  scene: {
+    flex: 1,
+    paddingTop: 20,
+    backgroundColor: '#EAEAEA',
+  },
+  tabs: {
+    height: 50,
+  }
+});
+
+module.exports = JumpingNavSample;
diff --git a/Examples/UIExplorer/NavigationExperimental/LegacyNavigator/LegacyNavigatorExample.js b/Examples/UIExplorer/NavigationExperimental/LegacyNavigator/LegacyNavigatorExample.js
new file mode 100644
index 000000000000..ed4169751418
--- /dev/null
+++ b/Examples/UIExplorer/NavigationExperimental/LegacyNavigator/LegacyNavigatorExample.js
@@ -0,0 +1,212 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ */
+'use strict';
+
+var React = require('react-native');
+var {
+  NavigationExperimental,
+  ScrollView,
+  StyleSheet,
+  Text,
+  TouchableHighlight,
+} = React;
+
+var BreadcrumbNavSample = require('./BreadcrumbNavSample');
+var NavigationBarSample = require('./NavigationBarSample');
+var JumpingNavSample = require('./JumpingNavSample');
+
+var Navigator = NavigationExperimental.LegacyNavigator;
+
+class NavButton extends React.Component {
+  render() {
+    return (
+      <TouchableHighlight
+        style={styles.button}
+        underlayColor="#B5B5B5"
+        onPress={this.props.onPress}>
+        <Text style={styles.buttonText}>{this.props.text}</Text>
+      </TouchableHighlight>
+    );
+  }
+}
+
+class NavMenu extends React.Component {
+  render() {
+    return (
+      <ScrollView style={styles.scene}>
+        <Text style={styles.messageText}>{this.props.message}</Text>
+        <NavButton
+          onPress={() => {
+            this.props.navigator.push({
+              message: 'Swipe right to dismiss',
+              sceneConfig: Navigator.SceneConfigs.FloatFromRight,
+            });
+          }}
+          text="Float in from right"
+        />
+        <NavButton
+          onPress={() => {
+            this.props.navigator.push({
+              message: 'Swipe down to dismiss',
+              sceneConfig: Navigator.SceneConfigs.FloatFromBottom,
+            });
+          }}
+          text="Float in from bottom"
+        />
+        <NavButton
+          onPress={() => {
+            this.props.navigator.pop();
+          }}
+          text="Pop"
+        />
+        <NavButton
+          onPress={() => {
+            this.props.navigator.popToTop();
+          }}
+          text="Pop to top"
+        />
+        <NavButton
+          onPress={() => {
+            this.props.navigator.push({ id: 'navbar' });
+          }}
+          text="Navbar Example"
+        />
+        <NavButton
+          onPress={() => {
+            this.props.navigator.push({ id: 'jumping' });
+          }}
+          text="Jumping Example"
+        />
+        <NavButton
+          onPress={() => {
+            this.props.navigator.push({ id: 'breadcrumbs' });
+          }}
+          text="Breadcrumbs Example"
+        />
+        <NavButton
+          onPress={() => {
+            this.props.onExampleExit();
+          }}
+          text="Exit <LegacyNavigator> Example"
+        />
+      </ScrollView>
+    );
+  }
+}
+
+var TabBarExample = React.createClass({
+
+  statics: {
+    title: '<LegacyNavigator> (Experimental)',
+    description: 'Experimental navigator that ports the API of the current ' +
+      'Navigator component',
+  },
+
+  renderScene: function(route, nav) {
+    switch (route.id) {
+      case 'navbar':
+        return <NavigationBarSample navigator={nav} />;
+      case 'breadcrumbs':
+        return <BreadcrumbNavSample navigator={nav} />;
+      case 'jumping':
+        return <JumpingNavSample navigator={nav} />;
+      default:
+        return (
+          <NavMenu
+            message={route.message}
+            navigator={nav}
+            onExampleExit={this.props.onExampleExit}
+          />
+        );
+    }
+  },
+
+  render: function() {
+    return (
+      <Navigator
+        ref={this._setNavigatorRef}
+        style={styles.container}
+        initialRoute={{ message: 'First Scene', }}
+        renderScene={this.renderScene}
+        configureScene={(route) => {
+          if (route.sceneConfig) {
+            return route.sceneConfig;
+          }
+          return Navigator.SceneConfigs.FloatFromBottom;
+        }}
+      />
+    );
+  },
+
+
+  componentWillUnmount: function() {
+    this._listeners && this._listeners.forEach(listener => listener.remove());
+  },
+
+  _setNavigatorRef: function(navigator) {
+    if (navigator !== this._navigator) {
+      this._navigator = navigator;
+
+      if (navigator) {
+        var callback = (event) => {
+          console.log(
+            `TabBarExample: event ${event.type}`,
+            {
+              route: JSON.stringify(event.data.route),
+              target: event.target,
+              type: event.type,
+            }
+          );
+        };
+        // Observe focus change events from the owner.
+        this._listeners = [
+          navigator.navigationContext.addListener('willfocus', callback),
+          navigator.navigationContext.addListener('didfocus', callback),
+        ];
+      }
+    }
+  },
+});
+
+var styles = StyleSheet.create({
+  messageText: {
+    fontSize: 17,
+    fontWeight: '500',
+    padding: 15,
+    marginTop: 50,
+    marginLeft: 15,
+  },
+  container: {
+    flex: 1,
+  },
+  button: {
+    backgroundColor: 'white',
+    padding: 15,
+    borderBottomWidth: StyleSheet.hairlineWidth,
+    borderBottomColor: '#CDCDCD',
+  },
+  buttonText: {
+    fontSize: 17,
+    fontWeight: '500',
+  },
+  scene: {
+    flex: 1,
+    paddingTop: 20,
+    backgroundColor: '#ccc',
+  }
+});
+
+TabBarExample.external = true;
+
+module.exports = TabBarExample;
diff --git a/Examples/UIExplorer/NavigationExperimental/LegacyNavigator/NavigationBarSample.js b/Examples/UIExplorer/NavigationExperimental/LegacyNavigator/NavigationBarSample.js
new file mode 100644
index 000000000000..9b9081dd0c7f
--- /dev/null
+++ b/Examples/UIExplorer/NavigationExperimental/LegacyNavigator/NavigationBarSample.js
@@ -0,0 +1,203 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+*/
+'use strict';
+
+
+var React = require('react-native');
+var {
+  NavigationExperimental,
+  ScrollView,
+  StyleSheet,
+  Text,
+  TouchableHighlight,
+  TouchableOpacity,
+} = React;
+
+var cssVar = require('cssVar');
+
+var Navigator = NavigationExperimental.LegacyNavigator;
+
+class NavButton extends React.Component {
+  render() {
+    return (
+      <TouchableHighlight
+        style={styles.button}
+        underlayColor="#B5B5B5"
+        onPress={this.props.onPress}>
+        <Text style={styles.buttonText}>{this.props.text}</Text>
+      </TouchableHighlight>
+    );
+  }
+}
+
+var NavigationBarRouteMapper = {
+
+  LeftButton: function(route, navigator, index, navState) {
+    if (index === 0) {
+      return null;
+    }
+
+    var previousRoute = navState.routeStack[index - 1];
+    return (
+      <TouchableOpacity
+        onPress={() => navigator.pop()}
+        style={styles.navBarLeftButton}>
+        <Text style={[styles.navBarText, styles.navBarButtonText]}>
+          {previousRoute.title}
+        </Text>
+      </TouchableOpacity>
+    );
+  },
+
+  RightButton: function(route, navigator, index, navState) {
+    return (
+      <TouchableOpacity
+        onPress={() => navigator.push(newRandomRoute())}
+        style={styles.navBarRightButton}>
+        <Text style={[styles.navBarText, styles.navBarButtonText]}>
+          Next
+        </Text>
+      </TouchableOpacity>
+    );
+  },
+
+  Title: function(route, navigator, index, navState) {
+    return (
+      <Text style={[styles.navBarText, styles.navBarTitleText]}>
+        {route.title} [{index}]
+      </Text>
+    );
+  },
+
+};
+
+function newRandomRoute() {
+  return {
+    title: '#' + Math.ceil(Math.random() * 1000),
+  };
+}
+
+var NavigationBarSample = React.createClass({
+
+  componentWillMount: function() {
+    var navigator = this.props.navigator;
+
+    var callback = (event) => {
+      console.log(
+        `NavigationBarSample : event ${event.type}`,
+        {
+          route: JSON.stringify(event.data.route),
+          target: event.target,
+          type: event.type,
+        }
+      );
+    };
+
+    // Observe focus change events from this component.
+    this._listeners = [
+      navigator.navigationContext.addListener('willfocus', callback),
+      navigator.navigationContext.addListener('didfocus', callback),
+    ];
+  },
+
+  componentWillUnmount: function() {
+    this._listeners && this._listeners.forEach(listener => listener.remove());
+  },
+
+  render: function() {
+    return (
+      <Navigator
+        debugOverlay={false}
+        style={styles.appContainer}
+        initialRoute={newRandomRoute()}
+        renderScene={(route, navigator) => (
+          <ScrollView style={styles.scene}>
+            <Text style={styles.messageText}>{route.content}</Text>
+            <NavButton
+              onPress={() => {
+                navigator.immediatelyResetRouteStack([
+                  newRandomRoute(),
+                  newRandomRoute(),
+                  newRandomRoute(),
+                ]);
+              }}
+              text="Reset w/ 3 scenes"
+            />
+            <NavButton
+              onPress={() => {
+                this.props.navigator.pop();
+              }}
+              text="Exit NavigationBar Example"
+            />
+          </ScrollView>
+        )}
+        navigationBar={
+          <Navigator.NavigationBar
+            routeMapper={NavigationBarRouteMapper}
+            style={styles.navBar}
+          />
+        }
+      />
+    );
+  },
+
+});
+
+var styles = StyleSheet.create({
+  messageText: {
+    fontSize: 17,
+    fontWeight: '500',
+    padding: 15,
+    marginTop: 50,
+    marginLeft: 15,
+  },
+  button: {
+    backgroundColor: 'white',
+    padding: 15,
+    borderBottomWidth: StyleSheet.hairlineWidth,
+    borderBottomColor: '#CDCDCD',
+  },
+  buttonText: {
+    fontSize: 17,
+    fontWeight: '500',
+  },
+  navBar: {
+    backgroundColor: 'white',
+  },
+  navBarText: {
+    fontSize: 16,
+    marginVertical: 10,
+  },
+  navBarTitleText: {
+    color: cssVar('fbui-bluegray-60'),
+    fontWeight: '500',
+    marginVertical: 9,
+  },
+  navBarLeftButton: {
+    paddingLeft: 10,
+  },
+  navBarRightButton: {
+    paddingRight: 10,
+  },
+  navBarButtonText: {
+    color: cssVar('fbui-accent-blue'),
+  },
+  scene: {
+    flex: 1,
+    paddingTop: 20,
+    backgroundColor: '#EAEAEA',
+  },
+});
+
+module.exports = NavigationBarSample;
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js
index f15b9926aa16..f90ab6ef76a8 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js
@@ -36,7 +36,7 @@ var EXAMPLES = {
   'Tic Tac Toe': require('./NavigationTicTacToeExample'),
 };
 
-var EXAMPLE_STORAGE_KEY = 'NavigationExperimentalExample';
+var EXAMPLE_STORAGE_KEY = 'xNavigationExperimentalExample';
 
 var NavigationExperimentalExample = React.createClass({
   statics: {
diff --git a/Examples/UIExplorer/UIExplorerList.ios.js b/Examples/UIExplorer/UIExplorerList.ios.js
index 65781609d2c1..ae7248430ab6 100644
--- a/Examples/UIExplorer/UIExplorerList.ios.js
+++ b/Examples/UIExplorer/UIExplorerList.ios.js
@@ -200,6 +200,10 @@ var APIExamples: Array<UIExplorerExample> = [
     key: 'NavigationExperimentalExample',
     module: require('./NavigationExperimental/NavigationExperimentalExample'),
   },
+  {
+    key: 'NavigationExperimentalLegacyNavigatorExample',
+    module: require('./NavigationExperimental/LegacyNavigator/LegacyNavigatorExample'),
+  },
   {
     key: 'NetInfoExample',
     module: require('./NetInfoExample'),
diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationLegacyNavigator.js b/Libraries/CustomComponents/NavigationExperimental/NavigationLegacyNavigator.js
new file mode 100644
index 000000000000..a03bd9f4a797
--- /dev/null
+++ b/Libraries/CustomComponents/NavigationExperimental/NavigationLegacyNavigator.js
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2015, Facebook, Inc.  All rights reserved.
+ *
+ * Facebook, Inc. ("Facebook") owns all right, title and interest, including
+ * all intellectual property and other proprietary rights, in and to the React
+ * Native CustomComponents software (the "Software").  Subject to your
+ * compliance with these terms, you are hereby granted a non-exclusive,
+ * worldwide, royalty-free copyright license to (1) use and copy the Software;
+ * and (2) reproduce and distribute the Software as part of your own software
+ * ("Your Software").  Facebook reserves all rights not expressly granted to
+ * you in this license agreement.
+ *
+ * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "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 FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
+ * EMPLOYEES 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 THE SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @providesModule NavigationLegacyNavigator
+ * @flow
+ */
+'use strict';
+
+/**
+ * NavigationLegacyNavigator is meant to replace Navigator seemlessly without
+ * API changes. While the APIs remain compatible with Navigator, it should
+ * be built with the new Navigation API such as `NavigationAnimatedView`...etc.
+ */
+const NavigationLegacyNavigator = require('Navigator');
+
+module.exports = NavigationLegacyNavigator;
diff --git a/Libraries/NavigationExperimental/NavigationExperimental.js b/Libraries/NavigationExperimental/NavigationExperimental.js
index f9153ea68aef..ca6bb627d559 100644
--- a/Libraries/NavigationExperimental/NavigationExperimental.js
+++ b/Libraries/NavigationExperimental/NavigationExperimental.js
@@ -16,6 +16,7 @@ const NavigationCard = require('NavigationCard');
 const NavigationCardStack = require('NavigationCardStack');
 const NavigationContainer = require('NavigationContainer');
 const NavigationHeader = require('NavigationHeader');
+const NavigationLegacyNavigator = require('NavigationLegacyNavigator');
 const NavigationReducer = require('NavigationReducer');
 const NavigationRootContainer = require('NavigationRootContainer');
 const NavigationStateUtils = require('NavigationStateUtils');
@@ -35,9 +36,10 @@ const NavigationExperimental = {
   AnimatedView: NavigationAnimatedView,
 
   // CustomComponents:
-  Header: NavigationHeader,
   Card: NavigationCard,
   CardStack: NavigationCardStack,
+  Header: NavigationHeader,
+  LegacyNavigator: NavigationLegacyNavigator,
 };
 
 module.exports = NavigationExperimental;

From 29e6bac17a48949810d187e08ab12702f83a5126 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Thu, 25 Feb 2016 14:54:57 -0800
Subject: [PATCH 1303/1411] Fixed UIExplorerStateTitleMap.js being .ios only

Reviewed By: foghina

Differential Revision: D2977953

fb-gh-sync-id: de650f82535fa4389602ce8b743ddf0442324c87
shipit-source-id: de650f82535fa4389602ce8b743ddf0442324c87
---
 Examples/UIExplorer/UIExplorerStateTitleMap.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Examples/UIExplorer/UIExplorerStateTitleMap.js b/Examples/UIExplorer/UIExplorerStateTitleMap.js
index 137a7cac6fc5..c4be82bc7185 100644
--- a/Examples/UIExplorer/UIExplorerStateTitleMap.js
+++ b/Examples/UIExplorer/UIExplorerStateTitleMap.js
@@ -15,7 +15,7 @@
  */
 'use strict';
 
-const UIExplorerList = require('./UIExplorerList.ios');
+const UIExplorerList = require('./UIExplorerList');
 
 import type {NavigationState} from 'NavigationStateUtils';
 

From d9c0f24116705ec28777fb04106e4bedef8f6164 Mon Sep 17 00:00:00 2001
From: Kevin Johnson <kevinejohn@gmail.com>
Date: Thu, 25 Feb 2016 15:19:00 -0800
Subject: [PATCH 1304/1411] Added the app Hover to the React Native showcase

Summary: Closes https://github.com/facebook/react-native/pull/6135

Differential Revision: D2979226

fb-gh-sync-id: 8a6b0ab760d7511f5e13c10bcad0e368f72204b4
shipit-source-id: 8a6b0ab760d7511f5e13c10bcad0e368f72204b4
---
 website/src/react-native/showcase.js | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 5025379c33d5..52dab1a8f44a 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -322,6 +322,13 @@ var apps = [
     link: 'https://play.google.com/store/apps/details?id=com.techulus.honestreviews&hl=en',
     author: 'Arjun Komath',
   },
+  {
+    name: 'Hover',
+    icon: 'http://a5.mzstatic.com/us/r30/Purple3/v4/ba/55/e6/ba55e6ee-71cf-b843-f592-0917c9b6c645/icon175x175.png',
+    linkAppStore: 'https://itunes.apple.com/us/app/hover-1-drone-uav-pilot-app!/id947641516?mt=8',
+    linkPlayStore: 'https://play.google.com/store/apps/details?id=com.analyticadevelopment.android.hover',
+    author: 'KevinEJohn',
+  },
   {
     name: 'HSK Level 1 Chinese Flashcards',
     icon: 'http://is2.mzstatic.com/image/pf/us/r30/Purple1/v4/b2/4f/3a/b24f3ae3-2597-cc70-1040-731b425a5904/mzl.amxdcktl.jpg',

From 652c1c11e4c81f2e42c1fdd82f4d433bf822b89e Mon Sep 17 00:00:00 2001
From: Ahmed El-Helw <ahmedre@fb.com>
Date: Thu, 25 Feb 2016 16:26:29 -0800
Subject: [PATCH 1305/1411] Fix incorrect MeasureSpec in
 ReactTextInputShadowNode

Summary:WRAP_CONTENT is not a valid size for MeasureSpec. While 0 is
a valid value size to pass to makeMeasureSpec, it's slightly cheaper to just
pass in 0 instead since makeMeasureSpec(0, UNSPECIFIED) is 0 anyway.

Differential Revision: D2968322

fb-gh-sync-id: 2ca0e27b12c1a8263800d96fec32127a4b967497
shipit-source-id: 2ca0e27b12c1a8263800d96fec32127a4b967497
---
 .../react/views/textinput/ReactTextInputShadowNode.java  | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java
index 6172770dd3e2..69bb727740cd 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java
@@ -13,7 +13,6 @@
 
 import android.text.Spannable;
 import android.util.TypedValue;
-import android.view.View;
 import android.view.ViewGroup;
 import android.widget.EditText;
 
@@ -23,10 +22,10 @@
 import com.facebook.infer.annotation.Assertions;
 import com.facebook.react.common.annotations.VisibleForTesting;
 import com.facebook.react.uimanager.PixelUtil;
-import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.ThemedReactContext;
 import com.facebook.react.uimanager.UIViewOperationQueue;
 import com.facebook.react.uimanager.ViewDefaults;
+import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.views.text.ReactTextShadowNode;
 import com.facebook.react.views.text.ReactTextUpdate;
 
@@ -34,10 +33,6 @@
 public class ReactTextInputShadowNode extends ReactTextShadowNode implements
     CSSNode.MeasureFunction {
 
-  private static final int MEASURE_SPEC = View.MeasureSpec.makeMeasureSpec(
-      ViewGroup.LayoutParams.WRAP_CONTENT,
-      View.MeasureSpec.UNSPECIFIED);
-
   private @Nullable EditText mEditText;
   private @Nullable float[] mComputedPadding;
   private int mJsEventCount = UNSET;
@@ -88,7 +83,7 @@ public void measure(CSSNode node, float width, float height, MeasureOutput measu
       editText.setLines(mNumberOfLines);
     }
 
-    editText.measure(MEASURE_SPEC, MEASURE_SPEC);
+    editText.measure(0 /* unspecified */, 0 /* unspecified */);
     measureOutput.height = editText.getMeasuredHeight();
   }
 

From 9d3d9dfbce3fb3b76642a6051e369911ffa195d2 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Thu, 25 Feb 2016 17:12:45 -0800
Subject: [PATCH 1306/1411] Make fbsource and GitHub consistent

---
 Libraries/Animated/examples/pic1.jpg          | Bin 0 -> 18446 bytes
 Libraries/Animated/examples/pic2.jpg          | Bin 0 -> 22628 bytes
 Libraries/Animated/examples/pic3.jpg          | Bin 0 -> 20286 bytes
 ReactAndroid/src/main/jni/react/BUCK          |  23 +++++++++++++-----
 ReactAndroid/src/main/jni/react/jni/BUCK      |  13 +++++++---
 .../android/support/v7/appcompat-orig/BUCK    |  12 ++++-----
 6 files changed, 33 insertions(+), 15 deletions(-)
 create mode 100644 Libraries/Animated/examples/pic1.jpg
 create mode 100644 Libraries/Animated/examples/pic2.jpg
 create mode 100644 Libraries/Animated/examples/pic3.jpg

diff --git a/Libraries/Animated/examples/pic1.jpg b/Libraries/Animated/examples/pic1.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..a9f2e824fe6903b452270e3c16a14ea6f908dee7
GIT binary patch
diff --git a/Libraries/Animated/examples/pic2.jpg b/Libraries/Animated/examples/pic2.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..34d30966ae9868db7d8567bf2d6320b01fc8e076
GIT binary patch
diff --git a/Libraries/Animated/examples/pic3.jpg b/Libraries/Animated/examples/pic3.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..47a97c8018040759bd293b5656f0eecdf6490cb9
GIT binary patch
diff --git a/ReactAndroid/src/main/jni/react/BUCK b/ReactAndroid/src/main/jni/react/BUCK
index de41e5c82db5..f9ac1edb5f8d 100644
--- a/ReactAndroid/src/main/jni/react/BUCK
+++ b/ReactAndroid/src/main/jni/react/BUCK
@@ -22,14 +22,27 @@ def react_library(**kwargs):
     visibility = [
       react_native_target('jni/react/jni:jni'),
     ],
-    deps = DEPS + [
-      '//native/third-party/jsc:jsc',
-      '//native/third-party/jsc:jsc_legacy_profiler',
-    ],
+    deps = DEPS + JSC_DEPS,
     preprocessor_flags = PREPROCESSOR_FLAGS,
     **kwargs
   )
 
+  cxx_library(
+    name = 'react-internal',
+    visibility = [
+      react_native_target('jni/react/jni:jni-internal'),
+    ],
+    deps = DEPS + JSC_INTERNAL_DEPS,
+    preprocessor_flags = PREPROCESSOR_FLAGS + [
+      '-DWITH_FB_JSC_TUNING=1',
+      '-DWITH_JSC_MEMORY_PRESSURE=1',
+      '-DWITH_FBJSCEXTENSIONS=1',
+      '-DWITH_JSC_INTERNAL=1',
+      '-DWITH_FB_MEMORY_PROFILING=1',
+    ],
+    **kwargs
+  )
+
 react_library(
   soname = 'libreactnative.so',
   header_namespace = 'react',
@@ -44,7 +57,6 @@ react_library(
     'JSCTracing.cpp',
     'JSCMemory.cpp',
     'JSCLegacyProfiler.cpp',
-    'JSCWebWorker.cpp',
     'Platform.cpp',
   ],
   headers = [
@@ -58,7 +70,6 @@ react_library(
     'Executor.h',
     'JSCExecutor.h',
     'JSCHelpers.h',
-    'JSCWebWorker.h',
     'MessageQueueThread.h',
     'MethodCall.h',
     'JSModulesUnbundle.h',
diff --git a/ReactAndroid/src/main/jni/react/jni/BUCK b/ReactAndroid/src/main/jni/react/jni/BUCK
index bebdf54ce2a3..4d23d95ad3a0 100644
--- a/ReactAndroid/src/main/jni/react/jni/BUCK
+++ b/ReactAndroid/src/main/jni/react/jni/BUCK
@@ -15,10 +15,17 @@ def jni_library(**kwargs):
     visibility = [
       'PUBLIC',
     ],
-    deps = DEPS + [
+    deps = DEPS + JSC_DEPS + [
       react_native_target('jni/react:react'),
-      '//native/third-party/jsc:jsc',
-      '//native/third-party/jsc:jsc_legacy_profiler',
+    ],
+    **kwargs
+  )
+
+  cxx_library(
+    name='jni-internal',
+    visibility = [INTERNAL_APP],
+    deps = DEPS + JSC_INTERNAL_DEPS + [
+      react_native_target('jni/react:react-internal'),
     ],
     **kwargs
   )
diff --git a/ReactAndroid/src/main/third-party/android/support/v7/appcompat-orig/BUCK b/ReactAndroid/src/main/third-party/android/support/v7/appcompat-orig/BUCK
index 2d3ae44c64a1..c0164418b053 100644
--- a/ReactAndroid/src/main/third-party/android/support/v7/appcompat-orig/BUCK
+++ b/ReactAndroid/src/main/third-party/android/support/v7/appcompat-orig/BUCK
@@ -1,11 +1,11 @@
 android_prebuilt_aar(
-  name = 'appcompat',
-  aar = ':appcompat-binary-aar',
-  visibility = ['//ReactAndroid/...',],
+    name = 'appcompat-23.1',
+    aar = ':appcompat-binary-aar',
+    visibility = ['//ReactAndroid/...',],
 )
 
 remote_file(
-  name = 'appcompat-binary-aar',
-  url = 'mvn:com.android.support:appcompat-v7:aar:23.0.1',
-  sha1 = '7d659f671541394a8bc2b9f909950aa2a5ec87ff',
+    name = 'appcompat-binary-aar',
+    url = 'mvn:com.android.support:appcompat-v7:aar:23.0.1',
+    sha1 = '7d659f671541394a8bc2b9f909950aa2a5ec87ff',
 )

From 5112a6395378eb79886b00859e05609cf9c9424c Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Thu, 25 Feb 2016 16:39:29 -0800
Subject: [PATCH 1307/1411] Added ability to run Movies app with BUCK

Reviewed By: mkonicek

Differential Revision: D2874873

fb-gh-sync-id: 9feface8d9a18742e68206dbafb804de25f53ed8
shipit-source-id: 9feface8d9a18742e68206dbafb804de25f53ed8
---
 .buckconfig                                   |   3 +
 .gitignore                                    |   2 +
 Examples/Movies/android/app/BUCK              |  43 ++++++++++++++
 .../android/app/src/main/AndroidManifest.xml  |   1 +
 .../android/app/src/main/AndroidManifest.xml  |   1 +
 .../app/src/main/java/UIExplorerActivity.java |   2 +-
 ReactAndroid/build.gradle                     |   5 ++
 .../android/support/v7/appcompat-orig/BUCK    |  36 +++--------
 .../com/facebook/react/views/switchview/BUCK  |   1 -
 .../toolbar/DrawableWithIntrinsicSize.java    |   9 ++-
 .../react/views/toolbar/ReactToolbar.java     |   9 ++-
 .../java/com/facebook/common/logging/BUCK     |  15 +++--
 .../main/third-party/android/support/v4/BUCK  |   2 +-
 .../android/support/v7/appcompat-orig/BUCK    |  56 +++++++++++++++++-
 .../v7/appcompat-orig/aar-unpacker.py}        |   6 +-
 .../src/main/third-party/java/jsr-305/BUCK    |   2 +-
 gradle/wrapper/gradle-wrapper.properties      |   2 +-
 keystores/BUCK                                |   8 +++
 keystores/debug.keystore                      | Bin 0 -> 2257 bytes
 keystores/debug.keystore.properties           |   4 ++
 20 files changed, 158 insertions(+), 49 deletions(-)
 create mode 100644 Examples/Movies/android/app/BUCK
 rename ReactAndroid/src/main/{android_res/android/support/v7/appcompat-orig/res-unpacker.py => third-party/android/support/v7/appcompat-orig/aar-unpacker.py} (70%)
 create mode 100644 keystores/BUCK
 create mode 100644 keystores/debug.keystore
 create mode 100644 keystores/debug.keystore.properties

diff --git a/.buckconfig b/.buckconfig
index 934256cb29d4..9f6c686b2fc1 100644
--- a/.buckconfig
+++ b/.buckconfig
@@ -4,3 +4,6 @@
 
 [maven_repositories]
   central = https://repo1.maven.org/maven2
+
+[alias]
+  movies = //Examples/Movies/android/app:app
diff --git a/.gitignore b/.gitignore
index fe61f843f91d..cd545b912fdc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,6 +29,8 @@ project.xcworkspace
 # Buck
 .buckd
 buck-out
+/ReactAndroid/src/main/jni/prebuilt/lib/armeabi-v7a/
+/ReactAndroid/src/main/jni/prebuilt/lib/x86/
 
 # Android
 .idea
diff --git a/Examples/Movies/android/app/BUCK b/Examples/Movies/android/app/BUCK
new file mode 100644
index 000000000000..25c73fd54415
--- /dev/null
+++ b/Examples/Movies/android/app/BUCK
@@ -0,0 +1,43 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_binary(
+  name = 'app',
+  manifest = 'src/main/AndroidManifest.xml',
+  keystore = '//keystores:debug',
+  deps = [
+    ':movies-lib',
+  ],
+)
+
+android_library(
+  name = 'movies-lib',
+  srcs = glob(['src/main/java/**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/csslayout:csslayout'),
+    react_native_target('java/com/facebook/react:react'),
+    react_native_target('java/com/facebook/react/devsupport:devsupport'),
+    react_native_target('java/com/facebook/react/modules/core:core'),
+    react_native_target('java/com/facebook/react/shell:shell'),
+    react_native_target('java/com/facebook/react/touch:touch'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
+    react_native_target('java/com/facebook/react/views/image:image'),
+    react_native_target('java/com/facebook/react/views/recyclerview:recyclerview'),
+    react_native_target('java/com/facebook/react/views/scroll:scroll'),
+    react_native_target('java/com/facebook/react/views/text:text'),
+    react_native_target('java/com/facebook/react/views/view:view'),
+    # .so files are prebuilt by Gradle with `./gradlew :ReactAndroid:packageReactNdkLibsForBuck`
+    react_native_target('jni/prebuilt:reactnative-libs'),
+    react_native_target('jni/prebuilt:android-jsc'),
+    react_native_dep('libraries/soloader/java/com/facebook/soloader:soloader'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+    ':res',
+  ],
+)
+
+
+android_resource(
+  name = 'res',
+  res = 'src/main/res',
+  package = 'com.facebook.react.movies',
+)
diff --git a/Examples/Movies/android/app/src/main/AndroidManifest.xml b/Examples/Movies/android/app/src/main/AndroidManifest.xml
index 185ffa506021..8aaec60819da 100644
--- a/Examples/Movies/android/app/src/main/AndroidManifest.xml
+++ b/Examples/Movies/android/app/src/main/AndroidManifest.xml
@@ -3,6 +3,7 @@
 
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
 
     <application
       android:allowBackup="true"
diff --git a/Examples/UIExplorer/android/app/src/main/AndroidManifest.xml b/Examples/UIExplorer/android/app/src/main/AndroidManifest.xml
index abb275d7055d..968a554cf2a3 100644
--- a/Examples/UIExplorer/android/app/src/main/AndroidManifest.xml
+++ b/Examples/UIExplorer/android/app/src/main/AndroidManifest.xml
@@ -5,6 +5,7 @@
   <uses-permission android:name="android.permission.INTERNET" />
   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
   <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+  <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
 
   <application
       android:allowBackup="true"
diff --git a/Examples/UIExplorer/android/app/src/main/java/UIExplorerActivity.java b/Examples/UIExplorer/android/app/src/main/java/UIExplorerActivity.java
index f4867da6b261..f9a50e93f44b 100644
--- a/Examples/UIExplorer/android/app/src/main/java/UIExplorerActivity.java
+++ b/Examples/UIExplorer/android/app/src/main/java/UIExplorerActivity.java
@@ -17,10 +17,10 @@
 import com.facebook.react.ReactActivity;
 import com.facebook.react.ReactPackage;
 import com.facebook.react.shell.MainReactPackage;
+import com.facebook.react.uiapp.R;
 
 import java.util.Arrays;
 import java.util.List;
-
 import javax.annotation.Nullable;
 
 public class UIExplorerActivity extends ReactActivity {
diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle
index 913dcbb73347..e6fc06a58c3d 100644
--- a/ReactAndroid/build.gradle
+++ b/ReactAndroid/build.gradle
@@ -204,6 +204,11 @@ task packageReactNdkLibs(dependsOn: buildReactNdkLib, type: Copy) {
     into "$buildDir/react-ndk/exported"
 }
 
+task packageReactNdkLibsForBuck(dependsOn: packageReactNdkLibs, type: Copy) {
+  from "$buildDir/react-ndk/exported"
+  into "src/main/jni/prebuilt/lib"
+}
+
 android {
     compileSdkVersion 23
     buildToolsVersion "23.0.1"
diff --git a/ReactAndroid/src/main/android_res/android/support/v7/appcompat-orig/BUCK b/ReactAndroid/src/main/android_res/android/support/v7/appcompat-orig/BUCK
index d0aaa959857b..8dd771536fa1 100644
--- a/ReactAndroid/src/main/android_res/android/support/v7/appcompat-orig/BUCK
+++ b/ReactAndroid/src/main/android_res/android/support/v7/appcompat-orig/BUCK
@@ -1,30 +1,10 @@
-# Unpack resources from the appcompat aar and merge their ids into the
-# generated com.facebook.react.R class.
-#
-# We do this for compatibility with Gradle: we build the open source
-# version React Native with both Buck and Gradle. See for example
-# ReactToolbarManager.java where we access the appcompat resources
-# via com.facebook.react.R.
-android_resource(
-    name = 'res-for-react-native',
-    res = ':res-unpacker-cmd',
-    package = 'com.facebook.react',
-    visibility = ['//ReactAndroid/...',],
-)
-
-genrule(
-    name = 'res-unpacker-cmd',
-    cmd = '$(exe :res-unpacker) $(location :appcompat-binary-aar) $OUT',
-    out = 'res',
-)
+include_defs('//ReactAndroid/DEFS')
 
-python_binary(
-    name = 'res-unpacker',
-    main = 'res-unpacker.py',
-)
-
-remote_file(
-    name = 'appcompat-binary-aar',
-    url = 'mvn:com.android.support:appcompat-v7:aar:23.0.1',
-    sha1 = '7d659f671541394a8bc2b9f909950aa2a5ec87ff',
+# used by ReactToolbarManager because of Gradle
+# TODO t10182713 will be replaced with res-for-appcompat when we stop using Gradle
+android_resource(
+  name = 'res-for-react-native',
+  res = react_native_dep('third-party/android/support/v7/appcompat-orig:res-unpacker-cmd'),
+  package = 'com.facebook.react',
+  visibility = ['//ReactAndroid/...',],
 )
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK
index 770afb9c9965..f7ff35e9d822 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/BUCK
@@ -9,7 +9,6 @@ android_library(
     react_native_target('java/com/facebook/csslayout:csslayout'),
     react_native_target('java/com/facebook/react/uimanager:uimanager'),
     react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
-    react_native_dep('android_res/android/support/v7/appcompat-orig:res-for-react-native'),
     react_native_dep('third-party/android/support/v7/appcompat-orig:appcompat'),
     react_native_dep('third-party/java/jsr-305:jsr-305'),
   ],
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/DrawableWithIntrinsicSize.java b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/DrawableWithIntrinsicSize.java
index 49a9a4b390b6..8b92242914c9 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/DrawableWithIntrinsicSize.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/DrawableWithIntrinsicSize.java
@@ -1,4 +1,11 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
+/**
+ * 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.
+ */
 
 package com.facebook.react.views.toolbar;
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbar.java b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbar.java
index aae498379410..92c585d71bd3 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbar.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbar.java
@@ -1,4 +1,11 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
+/**
+ * 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.
+ */
 
 package com.facebook.react.views.toolbar;
 
diff --git a/ReactAndroid/src/main/libraries/fbcore/src/main/java/com/facebook/common/logging/BUCK b/ReactAndroid/src/main/libraries/fbcore/src/main/java/com/facebook/common/logging/BUCK
index cf221085156f..93661768e1bd 100644
--- a/ReactAndroid/src/main/libraries/fbcore/src/main/java/com/facebook/common/logging/BUCK
+++ b/ReactAndroid/src/main/libraries/fbcore/src/main/java/com/facebook/common/logging/BUCK
@@ -1,11 +1,10 @@
-android_prebuilt_aar(
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
     name = 'logging',
-    aar = ':fbcore-binary-aar',
-    visibility = ['//ReactAndroid/...'],
+    exported_deps = [
+        react_native_dep('libraries/fresco/fresco-react-native:fbcore'),
+    ],
+    visibility = ['//ReactAndroid/...',],
 )
 
-remote_file(
-    name = 'fbcore-binary-aar',
-    url = 'mvn:com.facebook.fresco:fbcore:aar:0.8.1',
-    sha1 = 'cc46b3d564139bf63bb41534c7a723ee8119ae5f',
-)
diff --git a/ReactAndroid/src/main/third-party/android/support/v4/BUCK b/ReactAndroid/src/main/third-party/android/support/v4/BUCK
index b0a85e26b286..3f34e9424b66 100644
--- a/ReactAndroid/src/main/third-party/android/support/v4/BUCK
+++ b/ReactAndroid/src/main/third-party/android/support/v4/BUCK
@@ -1,7 +1,7 @@
 android_prebuilt_aar(
     name = 'lib-support-v4',
     aar = ':lib-support-v4-binary-aar',
-    visibility = ['//ReactAndroid/...',],
+    visibility = ['PUBLIC',],
 )
 
 remote_file(
diff --git a/ReactAndroid/src/main/third-party/android/support/v7/appcompat-orig/BUCK b/ReactAndroid/src/main/third-party/android/support/v7/appcompat-orig/BUCK
index c0164418b053..9afb2e02fd6a 100644
--- a/ReactAndroid/src/main/third-party/android/support/v7/appcompat-orig/BUCK
+++ b/ReactAndroid/src/main/third-party/android/support/v7/appcompat-orig/BUCK
@@ -1,9 +1,59 @@
-android_prebuilt_aar(
-    name = 'appcompat-23.1',
-    aar = ':appcompat-binary-aar',
+include_defs('//ReactAndroid/DEFS')
+
+# This is a bit messy and hopefully a temporary thing
+# The problem is that Gradle extracts appcompat resources into app namespace, com.facebook.react
+# While BUCK behaves properly and extracts them into android.support.v7.appcompat package.
+# We want to support both Gradle and BUCK builds so we hack a bit how BUCK extracts resources.
+# Besides that we still need JAVA classes from appcompat-v7.aar, that is why android_library
+# extracts classes.jar but the trick is that we can't take full appcompat.aar because resources
+# extracted from it by BUCK would conflict with resources we use under Gradelified package
+# All this mumbo jumbo will go away after t10182713
+
+android_library(
+  name = 'appcompat',
+  deps = [
+    ':res-for-appcompat',
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+  exported_deps = [
+    ':classes-for-react-native',
+  ],
+)
+
+# still used by appcompat library internally, so we need both during the build
+android_resource(
+  name = 'res-for-appcompat',
+  res = ':res-unpacker-cmd',
+  package = 'android.support.v7.appcompat',
+  visibility = ['//ReactAndroid/...',],
+)
+
+prebuilt_jar(
+    name = 'classes-for-react-native',
+    binary_jar = ':classes-unpacker-cmd',
     visibility = ['//ReactAndroid/...',],
 )
 
+genrule(
+    name = 'classes-unpacker-cmd',
+    cmd = '$(exe :aar-unpacker) $(location :appcompat-binary-aar) "classes.jar" $OUT',
+    out = 'classes.jar',
+)
+
+genrule(
+    name = 'res-unpacker-cmd',
+    cmd = '$(exe :aar-unpacker) $(location :appcompat-binary-aar) "res/" $OUT',
+    out = 'res',
+    visibility = ['//ReactAndroid/...',],
+)
+
+python_binary(
+    name = 'aar-unpacker',
+    main = 'aar-unpacker.py',
+)
+
 remote_file(
     name = 'appcompat-binary-aar',
     url = 'mvn:com.android.support:appcompat-v7:aar:23.0.1',
diff --git a/ReactAndroid/src/main/android_res/android/support/v7/appcompat-orig/res-unpacker.py b/ReactAndroid/src/main/third-party/android/support/v7/appcompat-orig/aar-unpacker.py
similarity index 70%
rename from ReactAndroid/src/main/android_res/android/support/v7/appcompat-orig/res-unpacker.py
rename to ReactAndroid/src/main/third-party/android/support/v7/appcompat-orig/aar-unpacker.py
index 145d09b02a73..ddb65efb2192 100644
--- a/ReactAndroid/src/main/android_res/android/support/v7/appcompat-orig/res-unpacker.py
+++ b/ReactAndroid/src/main/third-party/android/support/v7/appcompat-orig/aar-unpacker.py
@@ -5,7 +5,7 @@
 import tempfile
 import zipfile
 
-# Helper that unpacks the contents of the res folder of an .aar file
+# Helper that unpacks the contents of an .aar file
 # into given destination.
 
 @contextlib.contextmanager
@@ -16,5 +16,5 @@ def cleanup(path):
 if __name__ == '__main__':
     with zipfile.ZipFile(sys.argv[1], 'r') as z:
         with cleanup(tempfile.mkdtemp()) as temp_path:
-            z.extractall(temp_path, filter(lambda n: n.startswith('res/'), z.namelist()))
-            shutil.move(os.path.join(temp_path, 'res'), sys.argv[2])
+            z.extractall(temp_path, filter(lambda n: n.startswith(sys.argv[2]), z.namelist()))
+            shutil.move(os.path.join(temp_path, sys.argv[2]), sys.argv[3])
diff --git a/ReactAndroid/src/main/third-party/java/jsr-305/BUCK b/ReactAndroid/src/main/third-party/java/jsr-305/BUCK
index 3b5bb0b0e0b8..0c02a2716a7a 100644
--- a/ReactAndroid/src/main/third-party/java/jsr-305/BUCK
+++ b/ReactAndroid/src/main/third-party/java/jsr-305/BUCK
@@ -1,7 +1,7 @@
 prebuilt_jar(
     name = 'jsr-305',
     binary_jar = ':jsr305-binary-jar',
-    visibility = ['//ReactAndroid/...',],
+    visibility = ['PUBLIC'],
 )
 
 remote_file(
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 9881fc8cf8b3..0c42144e8035 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.9-bin.zip
+distributionUrl=https://services.gradle.org/distributions/gradle-2.11-all.zip
diff --git a/keystores/BUCK b/keystores/BUCK
new file mode 100644
index 000000000000..15da20e6b92c
--- /dev/null
+++ b/keystores/BUCK
@@ -0,0 +1,8 @@
+keystore(
+  name = 'debug',
+  store = 'debug.keystore',
+  properties = 'debug.keystore.properties',
+  visibility = [
+    'PUBLIC',
+  ],
+)
diff --git a/keystores/debug.keystore b/keystores/debug.keystore
new file mode 100644
index 0000000000000000000000000000000000000000..364e105ed39fbfd62001429a68140672b06ec0de
GIT binary patch
diff --git a/keystores/debug.keystore.properties b/keystores/debug.keystore.properties
new file mode 100644
index 000000000000..121bfb49f0df
--- /dev/null
+++ b/keystores/debug.keystore.properties
@@ -0,0 +1,4 @@
+key.store=debug.keystore
+key.alias=androiddebugkey
+key.store.password=android
+key.alias.password=android

From 8b88cae74783b226a747510cf8d1f33f92a8d755 Mon Sep 17 00:00:00 2001
From: AbilashK <abikspnr@gmail.com>
Date: Thu, 25 Feb 2016 16:54:43 -0800
Subject: [PATCH 1308/1411] Fix android's image tintColor prop when used with
 alpha

Summary:Fixes https://github.com/facebook/react-native/issues/6075
UIExplorer example has been tested with 4 levels of opacity(100,75,50,25)

![selection_029](https://cloud.githubusercontent.com/assets/11550281/13228124/31c85dcc-d9c0-11e5-90e3-3938e155d5a2.png)
Closes https://github.com/facebook/react-native/pull/6090

Differential Revision: D2979913

Pulled By: mkonicek

fb-gh-sync-id: ff30dec853935a059979096d9b1da9088d146249
shipit-source-id: ff30dec853935a059979096d9b1da9088d146249
---
 .../java/com/facebook/react/views/image/ReactImageManager.java | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
index 4231d207d9aa..6ebd2e8c8cda 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java
@@ -14,6 +14,7 @@
 import java.util.Map;
 
 import android.graphics.Color;
+import android.graphics.PorterDuff.Mode;
 
 import com.facebook.drawee.backends.pipeline.Fresco;
 import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
@@ -120,7 +121,7 @@ public void setTintColor(ReactImageView view, @Nullable Integer tintColor) {
     if (tintColor == null) {
       view.clearColorFilter();
     } else {
-      view.setColorFilter(tintColor);
+      view.setColorFilter(tintColor, Mode.SRC_IN);
     }
   }
 

From a9846da9fa638fdbb3073cb8f3fbe67d8fba94fe Mon Sep 17 00:00:00 2001
From: Zack <zack@root-two.com>
Date: Thu, 25 Feb 2016 16:59:22 -0800
Subject: [PATCH 1309/1411] support plain numbers in add and multiply operators

Summary:This adds support for passing plain numbers into the add and multiply operators. This can be useful if you want to have one AnimatedValue for a component that is say a scale 0 -> 1 and then animated many style properties accordingly using derivative Animated values.

Thoughts?

As far as implementation, there may be more performant implementations that do not require creating a whole new AnimatedValue for every static number. I am open to suggestion.
Closes https://github.com/facebook/react-native/pull/6154

Differential Revision: D2979962

Pulled By: vjeux

fb-gh-sync-id: b5ecb568b4c64b995dc4100991f02c17f0dd97dd
shipit-source-id: b5ecb568b4c64b995dc4100991f02c17f0dd97dd
---
 Libraries/Animated/src/AnimatedImplementation.js | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/Libraries/Animated/src/AnimatedImplementation.js b/Libraries/Animated/src/AnimatedImplementation.js
index 01b701a77706..830ab929d70d 100644
--- a/Libraries/Animated/src/AnimatedImplementation.js
+++ b/Libraries/Animated/src/AnimatedImplementation.js
@@ -844,10 +844,10 @@ class AnimatedAddition extends AnimatedWithChildren {
   _a: Animated;
   _b: Animated;
 
-  constructor(a: Animated, b: Animated) {
+  constructor(a: Animated | number, b: Animated | number) {
     super();
-    this._a = a;
-    this._b = b;
+    this._a = typeof a === 'number' ? new AnimatedValue(a) : a;
+    this._b = typeof b === 'number' ? new AnimatedValue(b) : b;
   }
 
   __getValue(): number {
@@ -873,10 +873,10 @@ class AnimatedMultiplication extends AnimatedWithChildren {
   _a: Animated;
   _b: Animated;
 
-  constructor(a: Animated, b: Animated) {
+  constructor(a: Animated | number, b: Animated | number) {
     super();
-    this._a = a;
-    this._b = b;
+    this._a = typeof a === 'number' ? new AnimatedValue(a) : a;
+    this._b = typeof b === 'number' ? new AnimatedValue(b) : b;
   }
 
   __getValue(): number {

From c449d9e72d46f840a70668cfda18ec6e5d7e024d Mon Sep 17 00:00:00 2001
From: Christoph Jerolimov <jerolimov+git+2016@gmail.com>
Date: Thu, 25 Feb 2016 17:07:37 -0800
Subject: [PATCH 1310/1411] Fix an issue (Sticky header index was outside the
 range) when renderSeparator is defined but returns null

Summary:Fix an issue when using ListView and define `renderSeparator` but the implementation returns null.

In such cases the sectionHeaderIndices mismatch the child element index and the app shows a warning like "Sticky header index 18 was outside the range {0, 13}".
Closes https://github.com/facebook/react-native/pull/5800

Differential Revision: D2980005

Pulled By: vjeux

fb-gh-sync-id: cd2d51d83698ed189bb65ea40b7b073644136b49
shipit-source-id: cd2d51d83698ed189bb65ea40b7b073644136b49
---
 Libraries/CustomComponents/ListView/ListView.js | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js
index b4931fedb9c2..357994735f4b 100644
--- a/Libraries/CustomComponents/ListView/ListView.js
+++ b/Libraries/CustomComponents/ListView/ListView.js
@@ -394,8 +394,10 @@ var ListView = React.createClass({
             rowID,
             adjacentRowHighlighted
           );
-          bodyComponents.push(separator);
-          totalIndex++;
+          if (separator) {
+            bodyComponents.push(separator);
+            totalIndex++;
+          }
         }
         if (++rowCount === this.state.curRenderedRowsCount) {
           break;

From 7d96dbb9198fa64406afe388c7eeb52163dcc2ab Mon Sep 17 00:00:00 2001
From: Emilio Rodriguez <emiliorodriguez@gmail.com>
Date: Thu, 25 Feb 2016 17:08:26 -0800
Subject: [PATCH 1311/1411] Added new app for showcase: Deskbookers

Summary: Closes https://github.com/facebook/react-native/pull/6129

Differential Revision: D2980013

Pulled By: mkonicek

fb-gh-sync-id: 5389965296b44e1a3a887c868f18e2aa17cf758c
shipit-source-id: 5389965296b44e1a3a887c868f18e2aa17cf758c
---
 website/src/react-native/showcase.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 52dab1a8f44a..37ebe9cfdcd9 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -638,6 +638,12 @@ var apps = [
       'http://richard-cao.github.io/2016/02/06/Reading-App-Write-In-React-Native/',
     ],
   },
+  {
+    name: 'Deskbookers',
+    icon: 'http://a4.mzstatic.com/eu/r30/Purple69/v4/be/61/7d/be617d63-88f5-5629-7ac0-bc2c9eb4802a/icon175x175.png',
+    linkAppStore: 'https://itunes.apple.com/nl/app/deskbookers/id964447401?mt=8',
+    author: 'Emilio Rodriguez'
+  },
 ];
 
 var AppList = React.createClass({

From ae0ad1fc7e8d7a591b5b1c0789c39bdcdfd3f388 Mon Sep 17 00:00:00 2001
From: Zack <zack@root-two.com>
Date: Thu, 25 Feb 2016 17:18:27 -0800
Subject: [PATCH 1312/1411] Implement modulo operator method

Summary:This is an initial take on how to allow for value wrapping in Animated (currently `.timing` only). It adds a wrap config options which is an array specifying a range of values to be wrapped around. Anytime the delta of `toValue and fromValue > wrapDistance / 2` instead of animating the long way it will animate towards the range extremity and then after breaching the range it will readjust to animated to the true toValue.

Example Usage:
```js
Animated.timing(
  this.state.animatedDegrees,
  {toValue: Math.random()*360, wrap: [0, 360]}
).start()
```

This is presumably very valuable in rotation based animations, but could also be useful in other applications like wrapping the edges of the viewport.

Questions & Todo:
- Is `wrap` as a config key semantically meaningful and accurate?
- Is there a way to expose this as a config option on `.interpolate` rather than timing
- Generalize to all animated API's (spring, decay), and will this work with ValueXY out of the box?
- Add tests
Closes https://github.com/facebook/react-native/pull/5743

Differential Revision: D2979992

fb-gh-sync-id: 69be510feba8c43acb10c253036f5854adff9258
shipit-source-id: 69be510feba8c43acb10c253036f5854adff9258
---
 .../Animated/src/AnimatedImplementation.js    | 41 +++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/Libraries/Animated/src/AnimatedImplementation.js b/Libraries/Animated/src/AnimatedImplementation.js
index 830ab929d70d..4c7a85a4d0fd 100644
--- a/Libraries/Animated/src/AnimatedImplementation.js
+++ b/Libraries/Animated/src/AnimatedImplementation.js
@@ -898,6 +898,33 @@ class AnimatedMultiplication extends AnimatedWithChildren {
   }
 }
 
+class AnimatedModulo extends AnimatedWithChildren {
+  _a: Animated;
+  _modulus: number;
+
+  constructor(a: Animated, modulus: number) {
+    super();
+    this._a = a;
+    this._modulus = modulus;
+  }
+
+  __getValue(): number {
+    return (this._a.__getValue() % this._modulus + this._modulus) % this._modulus;
+  }
+
+  interpolate(config: InterpolationConfigType): AnimatedInterpolation {
+    return new AnimatedInterpolation(this, Interpolation.create(config));
+  }
+
+  __attach(): void {
+    this._a.__addChild(this);
+  }
+
+  __detach(): void {
+    this._a.__removeChild(this);
+  }
+}
+
 class AnimatedTransform extends AnimatedWithChildren {
   _transforms: Array<Object>;
 
@@ -1233,6 +1260,14 @@ var multiply = function(
   return new AnimatedMultiplication(a, b);
 };
 
+var modulo = function(
+  a: Animated,
+  modulus: number
+): AnimatedModulo {
+  return new AnimatedModulo(a, modulus);
+};
+
+
 var maybeVectorAnim = function(
   value: AnimatedValue | AnimatedValueXY,
   config: Object,
@@ -1604,6 +1639,12 @@ module.exports = {
    */
   multiply,
 
+  /**
+   * Creates a new Animated value that is the (non-negative) modulo of the
+   * provided Animated value
+   */
+  modulo,
+
   /**
    * Starts an animation after the given delay.
    */

From 7eb7b947d72a782a2e35c896c6d648a17eab2b67 Mon Sep 17 00:00:00 2001
From: Levy Klots <levyklots@gmail.com>
Date: Thu, 25 Feb 2016 17:20:43 -0800
Subject: [PATCH 1313/1411] fix resources build variable name

Summary:If jsBundleDir variable was defined, then RN image assets would be
thrown into the assets folder along with the js bundle. This is a
bug. Image assets should be published into a different folder than the
js bundle.

A new variable resourcesDir is defined where RN image assets and the
like should be published into.
Closes https://github.com/facebook/react-native/pull/5828

Differential Revision: D2980235

Pulled By: mkonicek

fb-gh-sync-id: af913814e2fcce42aaa1fbed2a68fd719198f306
shipit-source-id: af913814e2fcce42aaa1fbed2a68fd719198f306
---
 local-cli/generator-android/templates/src/app/react.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/local-cli/generator-android/templates/src/app/react.gradle b/local-cli/generator-android/templates/src/app/react.gradle
index 11a4f8b871de..348fb127368b 100644
--- a/local-cli/generator-android/templates/src/app/react.gradle
+++ b/local-cli/generator-android/templates/src/app/react.gradle
@@ -41,7 +41,7 @@ gradle.projectsEvaluated {
             def jsBundleDir = elvisFile(config."$jsBundleDirConfigName") ?:
                     file("$buildDir/intermediates/assets/${targetPath}")
 
-            def resourcesDirConfigName = "jsBundleDir${targetName}"
+            def resourcesDirConfigName = "resourcesDir${targetName}"
             def resourcesDir = elvisFile(config."${resourcesDirConfigName}") ?:
                     file("$buildDir/intermediates/res/merged/${targetPath}")
             def jsBundleFile = file("$jsBundleDir/$bundleAssetName")

From c377f2a1633af590b03dca272b7b4b4228ce9d4e Mon Sep 17 00:00:00 2001
From: Walter Luh <wluh@fb.com>
Date: Thu, 25 Feb 2016 18:14:55 -0800
Subject: [PATCH 1314/1411] Add message channel to packager for sending
 commands to bridge (2/N)

Reviewed By: frantic

Differential Revision: D2957599

fb-gh-sync-id: 0d3f39bb5757c7af8ee6d178f4839af81928b8de
shipit-source-id: 0d3f39bb5757c7af8ee6d178f4839af81928b8de
---
 local-cli/server/runServer.js          |  4 ++
 local-cli/server/util/messageSocket.js | 88 ++++++++++++++++++++++++++
 2 files changed, 92 insertions(+)
 create mode 100644 local-cli/server/util/messageSocket.js

diff --git a/local-cli/server/runServer.js b/local-cli/server/runServer.js
index 3f5f33aeeddf..57c0be9d2627 100644
--- a/local-cli/server/runServer.js
+++ b/local-cli/server/runServer.js
@@ -15,6 +15,7 @@ const getDevToolsMiddleware = require('./middleware/getDevToolsMiddleware');
 const http = require('http');
 const isAbsolutePath = require('absolute-path');
 const loadRawBodyMiddleware = require('./middleware/loadRawBodyMiddleware');
+const messageSocket = require('./util/messageSocket.js');
 const openStackFrameInEditorMiddleware = require('./middleware/openStackFrameInEditorMiddleware');
 const path = require('path');
 const ReactPackager = require('../../packager/react-packager');
@@ -24,11 +25,13 @@ const webSocketProxy = require('./util/webSocketProxy.js');
 
 function runServer(args, config, readyCallback) {
   var wsProxy = null;
+  var ms = null;
   const packagerServer = getPackagerServer(args, config);
   const app = connect()
     .use(loadRawBodyMiddleware)
     .use(connect.compress())
     .use(getDevToolsMiddleware(args, () => wsProxy && wsProxy.isChromeConnected()))
+    .use(getDevToolsMiddleware(args, () => ms && ms.isChromeConnected()))
     .use(openStackFrameInEditorMiddleware)
     .use(statusPageMiddleware)
     .use(systraceProfileMiddleware)
@@ -51,6 +54,7 @@ function runServer(args, config, readyCallback) {
       });
 
       wsProxy = webSocketProxy.attachToServer(serverInstance, '/debugger-proxy');
+      ms = messageSocket.attachToServer(serverInstance, '/message');
       webSocketProxy.attachToServer(serverInstance, '/devtools');
       readyCallback();
     }
diff --git a/local-cli/server/util/messageSocket.js b/local-cli/server/util/messageSocket.js
new file mode 100644
index 000000000000..3c56aa0544cd
--- /dev/null
+++ b/local-cli/server/util/messageSocket.js
@@ -0,0 +1,88 @@
+/**
+ * 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.
+ */
+'use strict';
+
+
+function attachToServer(server, path) {
+  var WebSocketServer = require('ws').Server;
+  var wss = new WebSocketServer({
+    server: server,
+    path: path
+  });
+  var interfaceSocket, shellSocket;
+
+  function send(dest, message) {
+    if (!dest) {
+      return;
+    }
+
+    try {
+      dest.send(message);
+    } catch(e) {
+      console.warn(e);
+      // Sometimes this call throws 'not opened'
+    }
+  }
+
+  wss.on('connection', function(ws) {
+    const {url} = ws.upgradeReq;
+
+    if (url.indexOf('role=interface') > -1) {
+      if (interfaceSocket) {
+        ws.close(1011, 'Another debugger is already connected');
+        return;
+      }
+      interfaceSocket = ws;
+      interfaceSocket.onerror =
+      interfaceSocket.onclose = () => {
+        interfaceSocket = null;
+        // if (shellSocket) {
+        //   shellSocket.close(1011, 'Interface was disconnected');
+        // }
+      };
+
+      interfaceSocket.onmessage = ({data}) => {
+        send(shellSocket, data)
+      };
+    } else if (url.indexOf('role=shell') > -1) {
+      if (shellSocket) {
+        shellSocket.onerror = shellSocket.onclose = shellSocket.onmessage = null;
+        shellSocket.close(1011, 'Another client connected');
+      }
+      shellSocket = ws;
+      shellSocket.onerror =
+      shellSocket.onclose = () => {
+        shellSocket = null;
+        send(interfaceSocket, JSON.stringify({method: '$disconnected'}));
+      };
+      shellSocket.onmessage = ({data}) => send(interfaceSocket, data);
+
+      // console.log('CLIENT ----');
+      // if (doIt) {
+      //   console.log('> sending: %s', str);
+      //   send(shellSocket, str);
+      //   console.log('< sending');
+      // }
+
+    } else {
+      ws.close(1011, 'Missing role param');
+    }
+  });
+
+  return {
+    server: wss,
+    isChromeConnected: function() {
+      return !!interfaceSocket;
+    }
+  };
+}
+
+module.exports = {
+  attachToServer: attachToServer
+};

From 732f2e17ac31328327ef2af6e4b610880745f5a1 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Thu, 25 Feb 2016 18:29:43 -0800
Subject: [PATCH 1315/1411] List people who manage GitHub issues

Reviewed By: mkonicek

Differential Revision:D2980915
Ninja: oss only

fb-gh-sync-id: 36aa06a4b5c189f452939ce563d2857f793de015
shipit-source-id: 36aa06a4b5c189f452939ce563d2857f793de015
---
 bots/IssueCommands.txt | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/bots/IssueCommands.txt b/bots/IssueCommands.txt
index 00a6114b3be1..3d2b2b103dc0 100644
--- a/bots/IssueCommands.txt
+++ b/bots/IssueCommands.txt
@@ -1,27 +1,29 @@
-/answered
+React Native GitHub Issue Task Force: brentvatne, chirag04, christopherdro, corbt, dsibiski, grabbou, ide, jsierles, kmagiera, Kureev, lelandrichardson, satya164, skevy
+
+@facebook-github-bot answered
 comment Closing this issue as {author} says the question asked has been answered. Please help us by asking questions on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native). StackOverflow is amazing for Q&A: it has a reputation system, voting, the ability to mark a question as answered. Because of the reputation system it is likely the community will see and answer your question there. This also helps us use the GitHub bug tracker for bugs only.
 close
 
-/duplicate (#[0-9]+)
+@facebook-github-bot duplicate (#[0-9]+)
 comment {author} tells me this issue is a duplicate of {match0}. Let's discuss there, closing this one.
 close
 
-/expected
+@facebook-github-bot expected
 comment The /expected comment above tells me this is expected behavior. Closing this as we'd like to use the GitHub issue tracker for bugs. If you'd like to change how this feature works please post a feature request on [Product Pains](https://productpains.com/product/react-native/) so that other people can vote on it.
 close
 
-/question
+@facebook-github-bot stack-overflow
 comment Hey {issue_author} and thanks for posting this! {author} tells me this issue looks like a question that would be best asked on [StackOverflow](http://stackoverflow.com/questions/tagged/react-native). StackOverflow is amazing for Q&A: it has a reputation system, voting, the ability to mark a question as answered. Because of the reputation system it is likely the community will see and answer your question there. This also helps us use the GitHub bug tracker for bugs only. Will close this as this is really a question that should be asked on SO.
 add-label For Stack Overflow
 close
 
-/label (.*)
+@facebook-github-bot label (.*)
 add-label {match0}
 
-/no-reply
+@facebook-github-bot no-reply
 comment Closing this issue as more information is needed to debug this and we haven't heard back from the author. Once there's more information we can reopen the issue.
 close
 
-/reopen
+@facebook-github-bot reopen
 comment Okay, reopening this issue.
 reopen

From b860897cd5e5d48d804829d205c926ce9b9f553d Mon Sep 17 00:00:00 2001
From: Matthew Denner <matthew.denner@uswitch.com>
Date: Fri, 26 Feb 2016 00:41:25 -0800
Subject: [PATCH 1316/1411] Restore canvas once group has been drawn

Summary:The implementation of ARTGroupShadowNode saved the canvas and then drew the child nodes but did not reset the canvas afterwards, unlike the behaviour of the other ART shadow nodes.  Because of this the matrix operations were compounded for sibling nodes in the surface.

As an example the following code should draw a green circle in the bottom right corner of the surface and a red circle in the top left, which it does on iOS; on Android you'll find that the red circle is drawn in the bottom right corner instead.

```
'use strict';
import React, {
  AppRegistry,
  Component,
  StyleSheet,
  View,
} from 'react-native';

const { Surface, Group, Shape } = React.ART;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#808080',
  },
  surface: {
    backgroundColor: '#ffffff'
  },
});

class ARTGroupBug extends Component {
  render() {
    return (
      <View style={styles.container}>
        <
Closes https://github.com/facebook/react-native/pull/5619

Differential Revision: D2981865

Pulled By: spicyj

fb-gh-sync-id: 95ca701354fe728ed6ee78f8c02d1e1eb70c181e
shipit-source-id: 95ca701354fe728ed6ee78f8c02d1e1eb70c181e
---
 .../java/com/facebook/react/views/art/ARTGroupShadowNode.java   | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTGroupShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTGroupShadowNode.java
index 9586a7b0f88b..f01ca1ccf97d 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTGroupShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTGroupShadowNode.java
@@ -32,6 +32,8 @@ public void draw(Canvas canvas, Paint paint, float opacity) {
         child.draw(canvas, paint, opacity);
         child.markUpdateSeen();
       }
+
+      restoreCanvas(canvas);
     }
   }
 }

From 542432fc3e33ee9ade74e89d21238da9165af3c5 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Fri, 26 Feb 2016 03:11:30 -0800
Subject: [PATCH 1317/1411] Launch a new task if openURL is called with a url
 in a different package

Summary: Change the default handling of openURL to attach the NEW_TASK flag if the package we will be launching is different than the currently running package.

Reviewed By: foghina

Differential Revision: D2977441

fb-gh-sync-id: 01d1ac1d791345f815bfc9e8358bce6420c08c1b
shipit-source-id: 01d1ac1d791345f815bfc9e8358bce6420c08c1b
---
 .../facebook/react/modules/intent/IntentModule.java  | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java
index 8f57f570ea73..6a84f50cd11a 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java
@@ -10,6 +10,7 @@
 package com.facebook.react.modules.intent;
 
 import android.app.Activity;
+import android.content.ComponentName;
 import android.content.Intent;
 import android.net.Uri;
 
@@ -80,9 +81,20 @@ public void openURL(String url, Promise promise) {
       Activity currentActivity = getCurrentActivity();
       Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
 
+      String selfPackageName = getReactApplicationContext().getPackageName();
+      ComponentName componentName = intent.resolveActivity(
+        getReactApplicationContext().getPackageManager());
+      String otherPackageName = (componentName != null ? componentName.getPackageName() : "");
+
+      // Always add the FLAG_ACTIVITY_NEW_TASK if we are launching to a different package
+      if (!selfPackageName.equals(otherPackageName)) {
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+      }
+
       if (currentActivity != null) {
         currentActivity.startActivity(intent);
       } else {
+        // If no currentActivity, we want to always start a new task regardless of logic above
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         getReactApplicationContext().startActivity(intent);
       }

From d032cc967dcd077a2dce3fd5ea6bcf083a798616 Mon Sep 17 00:00:00 2001
From: Andrei Coman <andreic@fb.com>
Date: Fri, 26 Feb 2016 03:23:19 -0800
Subject: [PATCH 1318/1411] Pass jsc config to JSC

Reviewed By: astreet

Differential Revision: D2965497

fb-gh-sync-id: 1aef5a1f2d7ccb8de8ca403e51ebcf247bd6b034
shipit-source-id: 1aef5a1f2d7ccb8de8ca403e51ebcf247bd6b034
---
 .../react/testing/ReactTestHelper.java        |  5 +++--
 .../java/com/facebook/react/JSCConfig.java    | 12 ++++++++++++
 .../facebook/react/ReactInstanceManager.java  |  9 ++++++++-
 .../react/ReactInstanceManagerImpl.java       |  9 +++++++--
 .../react/bridge/JSCJavaScriptExecutor.java   | 10 +++++-----
 .../react/bridge/JavaScriptExecutor.java      |  2 +-
 .../react/bridge/ProxyJavaScriptExecutor.java |  2 +-
 .../src/main/jni/react/JSCExecutor.cpp        | 19 ++++++++++++-------
 ReactAndroid/src/main/jni/react/JSCExecutor.h | 12 +++++++++---
 .../src/main/jni/react/jni/OnLoad.cpp         | 17 +++++++++++++----
 10 files changed, 71 insertions(+), 26 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/JSCConfig.java

diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java
index fbe1c0db2395..20afcb234106 100644
--- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java
+++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java
@@ -12,6 +12,7 @@
 
 import android.app.Instrumentation;
 import android.content.Context;
+import android.support.test.InstrumentationRegistry;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -24,9 +25,9 @@
 import com.facebook.react.bridge.NativeModule;
 import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
 import com.facebook.react.bridge.NativeModuleRegistry;
+import com.facebook.react.bridge.WritableNativeMap;
 import com.facebook.react.bridge.queue.ReactQueueConfigurationSpec;
 
-import android.support.test.InstrumentationRegistry;
 import com.android.internal.util.Predicate;
 
 public class ReactTestHelper {
@@ -60,7 +61,7 @@ public ReactInstanceEasyBuilder addJSModule(Class moduleInterfaceClass) {
       public CatalystInstance build() {
         return new CatalystInstanceImpl.Builder()
           .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
-          .setJSExecutor(new JSCJavaScriptExecutor())
+          .setJSExecutor(new JSCJavaScriptExecutor(new WritableNativeMap()))
           .setRegistry(mNativeModuleRegistryBuilder.build())
           .setJSModulesConfig(mJSModulesConfigBuilder.build())
           .setJSBundleLoader(JSBundleLoader.createFileLoader(
diff --git a/ReactAndroid/src/main/java/com/facebook/react/JSCConfig.java b/ReactAndroid/src/main/java/com/facebook/react/JSCConfig.java
new file mode 100644
index 000000000000..959a6f8d36c9
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/JSCConfig.java
@@ -0,0 +1,12 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react;
+
+import com.facebook.react.bridge.WritableNativeMap;
+
+/**
+ * Interface for the configuration object that is passed to JSC.
+ */
+public interface JSCConfig {
+  public WritableNativeMap getConfigMap();
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
index 9ef96f5b80fb..990202ebe8c0 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
@@ -181,6 +181,7 @@ public static class Builder {
     protected @Nullable LifecycleState mInitialLifecycleState;
     protected @Nullable UIImplementationProvider mUIImplementationProvider;
     protected @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
+    protected @Nullable JSCConfig mJSCConfig;
 
     protected Builder() {
     }
@@ -274,6 +275,11 @@ public Builder setNativeModuleCallExceptionHandler(NativeModuleCallExceptionHand
       return this;
     }
 
+    public Builder setJSCConfig(JSCConfig jscConfig) {
+      mJSCConfig = jscConfig;
+      return this;
+    }
+
     /**
      * Instantiates a new {@link ReactInstanceManagerImpl}.
      * Before calling {@code build}, the following must be called:
@@ -307,7 +313,8 @@ public ReactInstanceManager build() {
           mBridgeIdleDebugListener,
           Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"),
           mUIImplementationProvider,
-          mNativeModuleCallExceptionHandler);
+          mNativeModuleCallExceptionHandler,
+          mJSCConfig);
     }
   }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index 63380ecb05e3..faba27bafed9 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -127,6 +127,7 @@
   private final UIImplementationProvider mUIImplementationProvider;
   private final MemoryPressureRouter mMemoryPressureRouter;
   private final @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
+  private final @Nullable JSCConfig mJSCConfig;
 
   private final ReactInstanceDevCommandsHandler mDevInterface =
       new ReactInstanceDevCommandsHandler() {
@@ -193,7 +194,9 @@ protected void onPreExecute() {
     protected Result<ReactApplicationContext> doInBackground(ReactContextInitParams... params) {
       Assertions.assertCondition(params != null && params.length > 0 && params[0] != null);
       try {
-        JavaScriptExecutor jsExecutor = params[0].getJsExecutorFactory().create();
+        JavaScriptExecutor jsExecutor =
+            params[0].getJsExecutorFactory().create(
+              mJSCConfig == null ? new WritableNativeMap() : mJSCConfig.getConfigMap());
         return Result.of(createReactContext(jsExecutor, params[0].getJsBundleLoader()));
       } catch (Exception e) {
         // Pass exception to onPostExecute() so it can be handled on the main thread
@@ -274,7 +277,8 @@ public T get() throws Exception {
       @Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener,
       LifecycleState initialLifecycleState,
       UIImplementationProvider uiImplementationProvider,
-      NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
+      NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler,
+      @Nullable JSCConfig jscConfig) {
     initializeSoLoaderIfNecessary(applicationContext);
 
     // TODO(9577825): remove this
@@ -296,6 +300,7 @@ public T get() throws Exception {
     mUIImplementationProvider = uiImplementationProvider;
     mMemoryPressureRouter = new MemoryPressureRouter(applicationContext);
     mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
+    mJSCConfig = jscConfig;
   }
 
   @Override
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSCJavaScriptExecutor.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSCJavaScriptExecutor.java
index 32b2619309f3..b4431c0d66d9 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSCJavaScriptExecutor.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSCJavaScriptExecutor.java
@@ -16,8 +16,8 @@
 public class JSCJavaScriptExecutor extends JavaScriptExecutor {
   public static class Factory implements JavaScriptExecutor.Factory {
     @Override
-    public JavaScriptExecutor create() throws Exception {
-      return new JSCJavaScriptExecutor();
+    public JavaScriptExecutor create(WritableNativeMap jscConfig) throws Exception {
+      return new JSCJavaScriptExecutor(jscConfig);
     }
   }
 
@@ -25,10 +25,10 @@ public JavaScriptExecutor create() throws Exception {
     SoLoader.loadLibrary(ReactBridge.REACT_NATIVE_LIB);
   }
 
-  public JSCJavaScriptExecutor() {
-    initialize();
+  public JSCJavaScriptExecutor(WritableNativeMap jscConfig) {
+    initialize(jscConfig);
   }
 
-  private native void initialize();
+  private native void initialize(WritableNativeMap jscConfig);
 
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptExecutor.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptExecutor.java
index bdf7e4fc6136..92499d314412 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptExecutor.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptExecutor.java
@@ -15,7 +15,7 @@
 @DoNotStrip
 public abstract class JavaScriptExecutor extends Countable {
   public interface Factory {
-    JavaScriptExecutor create() throws Exception;
+    JavaScriptExecutor create(WritableNativeMap jscConfig) throws Exception;
   }
 
   /**
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ProxyJavaScriptExecutor.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ProxyJavaScriptExecutor.java
index 80cd6f4b3259..37d83b338617 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ProxyJavaScriptExecutor.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ProxyJavaScriptExecutor.java
@@ -32,7 +32,7 @@ public Factory(JavaJSExecutor.Factory javaJSExecutorFactory) {
     }
 
     @Override
-    public JavaScriptExecutor create() throws Exception {
+    public JavaScriptExecutor create(WritableNativeMap jscConfig) throws Exception {
       return new ProxyJavaScriptExecutor(mJavaJSExecutorFactory.create());
     }
   }
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index 38dd9e2372f2..ad9f3c05a762 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -7,7 +7,7 @@
 #include <mutex>
 #include <sstream>
 #include <string>
-
+#include <glog/logging.h>
 #include <folly/json.h>
 #include <folly/String.h>
 #include <sys/time.h>
@@ -83,13 +83,14 @@ static std::string executeJSCallWithJSC(
 }
 
 std::unique_ptr<JSExecutor> JSCExecutorFactory::createJSExecutor(Bridge *bridge) {
-  return std::unique_ptr<JSExecutor>(new JSCExecutor(bridge, cacheDir_));
+  return std::unique_ptr<JSExecutor>(new JSCExecutor(bridge, cacheDir_, m_jscConfig));
 }
 
-JSCExecutor::JSCExecutor(Bridge *bridge, const std::string& cacheDir) :
+JSCExecutor::JSCExecutor(Bridge *bridge, const std::string& cacheDir, const folly::dynamic& jscConfig) :
     m_bridge(bridge),
     m_deviceCacheDir(cacheDir),
-    m_messageQueueThread(MessageQueues::getCurrentMessageQueueThread()) {
+    m_messageQueueThread(MessageQueues::getCurrentMessageQueueThread()),
+    m_jscConfig(jscConfig) {
   initOnJSVMThread();
 }
 
@@ -98,12 +99,14 @@ JSCExecutor::JSCExecutor(
     int workerId,
     JSCExecutor *owner,
     const std::string& script,
-    const std::unordered_map<std::string, std::string>& globalObjAsJSON) :
+    const std::unordered_map<std::string, std::string>& globalObjAsJSON,
+    const folly::dynamic& jscConfig) :
     m_bridge(bridge),
     m_workerId(workerId),
     m_owner(owner),
     m_deviceCacheDir(owner->m_deviceCacheDir),
-    m_messageQueueThread(MessageQueues::getCurrentMessageQueueThread()) {
+    m_messageQueueThread(MessageQueues::getCurrentMessageQueueThread()),
+    m_jscConfig(jscConfig) {
   // We post initOnJSVMThread here so that the owner doesn't have to wait for
   // initialization on its own thread
   m_messageQueueThread->runOnQueue([this, script, globalObjAsJSON] () {
@@ -145,6 +148,8 @@ void JSCExecutor::initOnJSVMThread() {
 
   installGlobalFunction(m_context, "nativeLoggingHook", JSLogging::nativeHook);
 
+  // TODO (t10136849): Pass the config options from map to JSC
+
   #ifdef WITH_FB_JSC_TUNING
   configureJSCForAndroid();
   #endif
@@ -317,7 +322,7 @@ int JSCExecutor::addWebWorker(
   auto workerMQT = WebWorkerUtil::createWebWorkerThread(workerId, m_messageQueueThread.get());
   std::unique_ptr<JSCExecutor> worker;
   workerMQT->runOnQueueSync([this, &worker, &script, &globalObj, workerId] () {
-    worker.reset(new JSCExecutor(m_bridge, workerId, this, script, globalObj.toJSONMap()));
+    worker.reset(new JSCExecutor(m_bridge, workerId, this, script, globalObj.toJSONMap(), m_jscConfig));
   });
 
   Object workerObj = Value(m_context, workerRef).asObject();
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.h b/ReactAndroid/src/main/jni/react/JSCExecutor.h
index 6b2669dbe9d4..33622014458b 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.h
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.h
@@ -5,6 +5,7 @@
 #include <cstdint>
 #include <memory>
 #include <unordered_map>
+#include <folly/json.h>
 #include <JavaScriptCore/JSContextRef.h>
 
 #include "Executor.h"
@@ -18,10 +19,13 @@ class MessageQueueThread;
 
 class JSCExecutorFactory : public JSExecutorFactory {
 public:
-  JSCExecutorFactory(const std::string& cacheDir) : cacheDir_(cacheDir) {}
+  JSCExecutorFactory(const std::string& cacheDir, const folly::dynamic& jscConfig) :
+  cacheDir_(cacheDir),
+  m_jscConfig(jscConfig) {}
   virtual std::unique_ptr<JSExecutor> createJSExecutor(Bridge *bridge) override;
 private:
   std::string cacheDir_;
+  folly::dynamic m_jscConfig;
 };
 
 class JSCExecutor;
@@ -45,7 +49,7 @@ class JSCExecutor : public JSExecutor {
   /**
    * Must be invoked from thread this Executor will run on.
    */
-  explicit JSCExecutor(Bridge *bridge, const std::string& cacheDir);
+  explicit JSCExecutor(Bridge *bridge, const std::string& cacheDir, const folly::dynamic& jscConfig);
   ~JSCExecutor() override;
 
   virtual void loadApplicationScript(
@@ -84,6 +88,7 @@ class JSCExecutor : public JSExecutor {
   std::string m_deviceCacheDir;
   std::shared_ptr<MessageQueueThread> m_messageQueueThread;
   std::unique_ptr<JSModulesUnbundle> m_unbundle;
+  folly::dynamic m_jscConfig;
 
   /**
    * WebWorker constructor. Must be invoked from thread this Executor will run on.
@@ -93,7 +98,8 @@ class JSCExecutor : public JSExecutor {
       int workerId,
       JSCExecutor *owner,
       const std::string& script,
-      const std::unordered_map<std::string, std::string>& globalObjAsJSON);
+      const std::unordered_map<std::string, std::string>& globalObjAsJSON,
+      const folly::dynamic& jscConfig);
 
   void initOnJSVMThread();
   void terminateOnJSVMThread();
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 1a4dbe3c17da..5081bd67f90e 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -819,13 +819,21 @@ std::string getDeviceCacheDir() {
 }
 
 struct CountableJSCExecutorFactory : CountableJSExecutorFactory  {
+public:
+  CountableJSCExecutorFactory(folly::dynamic jscConfig) : m_jscConfig(jscConfig) {}
   virtual std::unique_ptr<JSExecutor> createJSExecutor(Bridge *bridge) override {
-    return JSCExecutorFactory(getDeviceCacheDir()).createJSExecutor(bridge);
+    return JSCExecutorFactory(getDeviceCacheDir(), m_jscConfig).createJSExecutor(bridge);
   }
+
+private:
+  folly::dynamic m_jscConfig;
 };
 
-static void createJSCExecutor(JNIEnv *env, jobject obj) {
-  auto executor = createNew<CountableJSCExecutorFactory>();
+static void createJSCExecutor(JNIEnv *env, jobject obj, jobject jscConfig) {
+  auto nativeMap = extractRefPtr<NativeMap>(env, jscConfig);
+  exceptions::throwIfObjectAlreadyConsumed(nativeMap, "Map to push already consumed");
+  auto executor = createNew<CountableJSCExecutorFactory>(std::move(nativeMap->map));
+  nativeMap->isConsumed = true;
   setCountableForJava(env, obj, std::move(executor));
 }
 
@@ -920,7 +928,8 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
     });
 
     registerNatives("com/facebook/react/bridge/JSCJavaScriptExecutor", {
-      makeNativeMethod("initialize", executors::createJSCExecutor),
+      makeNativeMethod("initialize", "(Lcom/facebook/react/bridge/WritableNativeMap;)V",
+        executors::createJSCExecutor),
     });
 
     registerNatives("com/facebook/react/bridge/ProxyJavaScriptExecutor", {

From 251d5a5959b2d1bf21ccd46f28674a4bf33ff30b Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Fri, 26 Feb 2016 04:33:34 -0800
Subject: [PATCH 1319/1411] Fixed flow error about require platform forked
 component

Summary:Commit 29e6bac17a48949810d187e08ab12702f83a5126 introduced a flow break in e2e tests.
This commit fixes float.

**Test plan (required)**

```bash
flow check Libraries
npm test
```

Make sure JS tests pass on TravisCI.
Closes https://github.com/facebook/react-native/pull/6168

Differential Revision: D2982108

fb-gh-sync-id: 0aea38f7b7e00c7ce91284e7ca6a01318792cc75
shipit-source-id: 0aea38f7b7e00c7ce91284e7ca6a01318792cc75
---
 Examples/UIExplorer/UIExplorerStateTitleMap.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Examples/UIExplorer/UIExplorerStateTitleMap.js b/Examples/UIExplorer/UIExplorerStateTitleMap.js
index c4be82bc7185..111d2c49ab21 100644
--- a/Examples/UIExplorer/UIExplorerStateTitleMap.js
+++ b/Examples/UIExplorer/UIExplorerStateTitleMap.js
@@ -15,6 +15,7 @@
  */
 'use strict';
 
+// $FlowFixMe : This is a platform-forked component, and flow seems to only run on iOS?
 const UIExplorerList = require('./UIExplorerList');
 
 import type {NavigationState} from 'NavigationStateUtils';

From 50141f9d3fcf7cad09dfc44bb8b7951e8e8f830b Mon Sep 17 00:00:00 2001
From: "wenzhao.yin" <wenzhao.yin@qunar.com>
Date: Fri, 26 Feb 2016 04:53:38 -0800
Subject: [PATCH 1320/1411] fix RCTPerfMonitor display unit error

Summary:The  RCTPerformanceLogger log the time in ms not us. Especially the unit of RCTPLBundleSize is byte.
Closes https://github.com/facebook/react-native/pull/5919

Differential Revision: D2982116

Pulled By: nicklockwood

fb-gh-sync-id: 18aad5ff2eb83c6f302b2c10382bf214b51df133
shipit-source-id: 18aad5ff2eb83c6f302b2c10382bf214b51df133
---
 Libraries/Inspector/PerformanceOverlay.js | 3 ++-
 React/Profiler/RCTPerfMonitor.m           | 9 +++++----
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/Libraries/Inspector/PerformanceOverlay.js b/Libraries/Inspector/PerformanceOverlay.js
index c0be512421a8..3329dc341d37 100644
--- a/Libraries/Inspector/PerformanceOverlay.js
+++ b/Libraries/Inspector/PerformanceOverlay.js
@@ -24,11 +24,12 @@ var PerformanceOverlay = React.createClass({
 
     for (var key in perfLogs) {
       if (perfLogs[key].totalTime) {
+        var unit = (key === 'BundleSize') ? 'b' : 'ms';
         items.push(
           <View style={styles.row}>
             <Text style={[styles.text, styles.label]}>{key}</Text>
             <Text style={[styles.text, styles.totalTime]}>
-              {perfLogs[key].totalTime + 'ms'}
+              {perfLogs[key].totalTime + unit}
             </Text>
           </View>
         );
diff --git a/React/Profiler/RCTPerfMonitor.m b/React/Profiler/RCTPerfMonitor.m
index 93a6fd70a47d..caf660385e8b 100644
--- a/React/Profiler/RCTPerfMonitor.m
+++ b/React/Profiler/RCTPerfMonitor.m
@@ -501,12 +501,13 @@ - (void)threadUpdate:(CADisplayLink *)displayLink
 
 - (void)loadPerformanceLoggerData
 {
-  NSMutableArray *data = [NSMutableArray new];
-  NSArray *times = RCTPerformanceLoggerOutput();
   NSUInteger i = 0;
+  NSMutableArray<NSString *> *data = [NSMutableArray new];
+  NSArray<NSNumber *> *values = RCTPerformanceLoggerOutput();
   for (NSString *label in RCTPerformanceLoggerLabels()) {
-    [data addObject:[NSString stringWithFormat:@"%@: %lldus", label,
-                     [times[i+1] longLongValue] - [times[i] longLongValue]]];
+    long long value = values[i+1].longLongValue - values[i].longLongValue;
+    NSString *unit = [label isEqualToString:@"BundleSize"] ? @"b" : @"ms";
+    [data addObject:[NSString stringWithFormat:@"%@: %lld%@", label, value, unit]];
     i += 2;
   }
   _perfLoggerMarks = [data copy];

From c32e5fd84f6e4859e4039eda2ff654565ccdd3cd Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Fri, 26 Feb 2016 05:55:56 -0800
Subject: [PATCH 1321/1411] Revert D2926896 WebWorkers: Move web worker impl to
 JSCExecutor

Reviewed By: lexs

Differential Revision: D2982150

fb-gh-sync-id: c75d05988df50b9788608e7c1bf00c4952ccfce1
shipit-source-id: c75d05988df50b9788608e7c1bf00c4952ccfce1
---
 .../react/bridge/CatalystInstanceImpl.java    |  20 +-
 .../common/futures/SimpleSettableFuture.java  |   2 +-
 ReactAndroid/src/main/jni/react/Android.mk    |   1 +
 ReactAndroid/src/main/jni/react/BUCK          |   2 +
 .../src/main/jni/react/JSCExecutor.cpp        | 184 ++++--------------
 ReactAndroid/src/main/jni/react/JSCExecutor.h |  65 ++-----
 .../src/main/jni/react/JSCWebWorker.cpp       | 153 +++++++++++++++
 .../src/main/jni/react/JSCWebWorker.h         |  94 +++++++++
 .../src/main/jni/react/MessageQueueThread.h   |  20 --
 9 files changed, 312 insertions(+), 229 deletions(-)
 create mode 100644 ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
 create mode 100644 ReactAndroid/src/main/jni/react/JSCWebWorker.h

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
index cbf259f29a82..0b3476cb92fb 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
@@ -226,18 +226,24 @@ public void destroy() {
         listener.onTransitionToBridgeIdle();
       }
     }
+
+    Systrace.unregisterListener(mTraceListener);
+
+    // We can access the Bridge from any thread now because we know either we are on the JS thread
+    // or the JS thread has finished via ReactQueueConfiguration#destroy()
+    mBridge.dispose();
   }
 
   private void synchronouslyDisposeBridgeOnJSThread() {
     final SimpleSettableFuture<Void> bridgeDisposeFuture = new SimpleSettableFuture<>();
     mReactQueueConfiguration.getJSQueueThread().runOnQueue(
-        new Runnable() {
-          @Override
-          public void run() {
-            mBridge.dispose();
-            bridgeDisposeFuture.set(null);
-          }
-        });
+      new Runnable() {
+        @Override
+        public void run() {
+          mBridge.dispose();
+          bridgeDisposeFuture.set(null);
+        }
+      });
     bridgeDisposeFuture.getOrThrow();
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java b/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java
index 9caf34cd6231..55fc9eb089e2 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java
@@ -30,7 +30,7 @@ public class SimpleSettableFuture<T> implements Future<T> {
    * Sets the result. If another thread has called {@link #get}, they will immediately receive the
    * value. set or setException must only be called once.
    */
-  public void set(@Nullable T result) {
+  public void set(T result) {
     checkNotSet();
     mResult = result;
     mReadyLatch.countDown();
diff --git a/ReactAndroid/src/main/jni/react/Android.mk b/ReactAndroid/src/main/jni/react/Android.mk
index f72729bdce26..cafcb591b878 100644
--- a/ReactAndroid/src/main/jni/react/Android.mk
+++ b/ReactAndroid/src/main/jni/react/Android.mk
@@ -8,6 +8,7 @@ LOCAL_SRC_FILES := \
   Bridge.cpp \
   JSCExecutor.cpp \
   JSCHelpers.cpp \
+  JSCWebWorker.cpp \
   MethodCall.cpp \
   Platform.cpp \
   Value.cpp \
diff --git a/ReactAndroid/src/main/jni/react/BUCK b/ReactAndroid/src/main/jni/react/BUCK
index f9ac1edb5f8d..e397d252c8cc 100644
--- a/ReactAndroid/src/main/jni/react/BUCK
+++ b/ReactAndroid/src/main/jni/react/BUCK
@@ -57,6 +57,7 @@ react_library(
     'JSCTracing.cpp',
     'JSCMemory.cpp',
     'JSCLegacyProfiler.cpp',
+    'JSCWebWorker.cpp',
     'Platform.cpp',
   ],
   headers = [
@@ -70,6 +71,7 @@ react_library(
     'Executor.h',
     'JSCExecutor.h',
     'JSCHelpers.h',
+    'JSCWebWorker.h',
     'MessageQueueThread.h',
     'MethodCall.h',
     'JSModulesUnbundle.h',
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index ad9f3c05a762..bc91fd10343a 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -3,8 +3,7 @@
 #include "JSCExecutor.h"
 
 #include <algorithm>
-#include <condition_variable>
-#include <mutex>
+#include <atomic>
 #include <sstream>
 #include <string>
 #include <glog/logging.h>
@@ -91,52 +90,6 @@ JSCExecutor::JSCExecutor(Bridge *bridge, const std::string& cacheDir, const foll
     m_deviceCacheDir(cacheDir),
     m_messageQueueThread(MessageQueues::getCurrentMessageQueueThread()),
     m_jscConfig(jscConfig) {
-  initOnJSVMThread();
-}
-
-JSCExecutor::JSCExecutor(
-    Bridge *bridge,
-    int workerId,
-    JSCExecutor *owner,
-    const std::string& script,
-    const std::unordered_map<std::string, std::string>& globalObjAsJSON,
-    const folly::dynamic& jscConfig) :
-    m_bridge(bridge),
-    m_workerId(workerId),
-    m_owner(owner),
-    m_deviceCacheDir(owner->m_deviceCacheDir),
-    m_messageQueueThread(MessageQueues::getCurrentMessageQueueThread()),
-    m_jscConfig(jscConfig) {
-  // We post initOnJSVMThread here so that the owner doesn't have to wait for
-  // initialization on its own thread
-  m_messageQueueThread->runOnQueue([this, script, globalObjAsJSON] () {
-    initOnJSVMThread();
-
-    installGlobalFunction(m_context, "postMessage", nativePostMessage);
-
-    for (auto& it : globalObjAsJSON) {
-      setGlobalVariable(it.first, it.second);
-    }
-
-    // TODO(9604438): Protect against script does not exist
-    std::string scriptSrc = WebWorkerUtil::loadScriptFromAssets(script);
-    // TODO(9994180): Throw on error
-    loadApplicationScript(scriptSrc, script);
-  });
-}
-
-JSCExecutor::~JSCExecutor() {
-  *m_isDestroyed = true;
-  if (m_messageQueueThread->isOnThread()) {
-    terminateOnJSVMThread();
-  } else {
-    m_messageQueueThread->runOnQueueSync([this] () {
-      terminateOnJSVMThread();
-    });
-  }
-}
-
-void JSCExecutor::initOnJSVMThread() {
   m_context = JSGlobalContextCreateInGroup(nullptr, nullptr);
   s_globalContextRefToJSCExecutor[m_context] = this;
   installGlobalFunction(m_context, "nativeFlushQueueImmediate", nativeFlushQueueImmediate);
@@ -165,20 +118,18 @@ void JSCExecutor::initOnJSVMThread() {
   #endif
 }
 
-void JSCExecutor::terminateOnJSVMThread() {
-  // terminateOwnedWebWorker mutates m_ownedWorkers so collect all the workers
-  // to terminate first
+JSCExecutor::~JSCExecutor() {
+  // terminateWebWorker mutates m_webWorkers so collect all the workers to terminate first
   std::vector<int> workerIds;
-  for (auto& it : m_ownedWorkers) {
-    workerIds.push_back(it.first);
+  for (auto it = m_webWorkers.begin(); it != m_webWorkers.end(); it++) {
+    workerIds.push_back(it->first);
   }
   for (int workerId : workerIds) {
-    terminateOwnedWebWorker(workerId);
+    terminateWebWorker(workerId);
   }
 
   s_globalContextRefToJSCExecutor.erase(m_context);
   JSGlobalContextRelease(m_context);
-  m_context = nullptr;
 }
 
 void JSCExecutor::loadApplicationScript(
@@ -215,10 +166,6 @@ void JSCExecutor::loadApplicationUnbundle(
 }
 
 void JSCExecutor::flush() {
-  if (m_owner != nullptr) {
-    // Web workers don't support native modules yet
-    return;
-  }
   // TODO: Make this a first class function instead of evaling. #9317773
   std::string calls = executeJSCallWithJSC(m_context, "flushedQueue", std::vector<folly::dynamic>());
   m_bridge->callNativeModules(calls, true);
@@ -310,115 +257,57 @@ void JSCExecutor::loadModule(uint32_t moduleId) {
   evaluateScript(m_context, source, sourceUrl);
 }
 
-int JSCExecutor::addWebWorker(
-    const std::string& script,
-    JSValueRef workerRef,
-    JSValueRef globalObjRef) {
-  static std::atomic_int nextWorkerId(1);
-  int workerId = nextWorkerId++;
-
-  Object globalObj = Value(m_context, globalObjRef).asObject();
+// WebWorker impl
 
-  auto workerMQT = WebWorkerUtil::createWebWorkerThread(workerId, m_messageQueueThread.get());
-  std::unique_ptr<JSCExecutor> worker;
-  workerMQT->runOnQueueSync([this, &worker, &script, &globalObj, workerId] () {
-    worker.reset(new JSCExecutor(m_bridge, workerId, this, script, globalObj.toJSONMap(), m_jscConfig));
-  });
-
-  Object workerObj = Value(m_context, workerRef).asObject();
-  workerObj.makeProtected();
-
-  m_ownedWorkers.emplace(std::piecewise_construct, std::forward_as_tuple(workerId), std::forward_as_tuple(std::move(worker), std::move(workerObj)));
-
-  return workerId;
-}
-
-void JSCExecutor::postMessageToOwnedWebWorker(int workerId, JSValueRef message, JSValueRef *exn) {
-  auto worker = m_ownedWorkers.at(workerId).getExecutor();
-  std::string msgString = Value(m_context, message).toJSONString();
-
-  std::shared_ptr<bool> isWorkerDestroyed = worker->m_isDestroyed;
-  worker->m_messageQueueThread->runOnQueue([isWorkerDestroyed, worker, msgString] () {
-    if (*isWorkerDestroyed) {
-      return;
-    }
-    worker->receiveMessageFromOwner(msgString);
-  });
+JSGlobalContextRef JSCExecutor::getContext() {
+  return m_context;
 }
 
-void JSCExecutor::postMessageToOwner(JSValueRef msg) {
-  std::string msgString = Value(m_context, msg).toJSONString();
-  std::shared_ptr<bool> ownerIsDestroyed = m_owner->m_isDestroyed;
-  m_owner->m_messageQueueThread->runOnQueue([workerId=m_workerId, owner=m_owner, ownerIsDestroyed, msgString] () {
-    if (*ownerIsDestroyed) {
-      return;
-    }
-    owner->receiveMessageFromOwnedWebWorker(workerId, msgString);
-  });
+std::shared_ptr<MessageQueueThread> JSCExecutor::getMessageQueueThread() {
+  return m_messageQueueThread;
 }
 
-void JSCExecutor::receiveMessageFromOwnedWebWorker(int workerId, const std::string& json) {
-  Object* workerObj;
-  try {
-    workerObj = &m_ownedWorkers.at(workerId).jsObj;
-  } catch (std::out_of_range& e) {
-    // Worker was already terminated
-    return;
-  }
+void JSCExecutor::onMessageReceived(int workerId, const std::string& json) {
+  Object& worker = m_webWorkerJSObjs.at(workerId);
 
-  Value onmessageValue = workerObj->getProperty("onmessage");
+  Value onmessageValue = worker.getProperty("onmessage");
   if (onmessageValue.isUndefined()) {
     return;
   }
 
-  JSValueRef args[] = { createMessageObject(json) };
+  JSValueRef args[] = { JSCWebWorker::createMessageObject(m_context, json) };
   onmessageValue.asObject().callAsFunction(1, args);
 
   flush();
 }
 
-void JSCExecutor::receiveMessageFromOwner(const std::string& msgString) {
-  CHECK(m_owner) << "Received message in a Executor that doesn't have an owner!";
-
-  JSValueRef args[] = { createMessageObject(msgString) };
-  Value onmessageValue = Object::getGlobalObject(m_context).getProperty("onmessage");
-  onmessageValue.asObject().callAsFunction(1, args);
-}
+int JSCExecutor::addWebWorker(const std::string& script, JSValueRef workerRef) {
+  static std::atomic_int nextWorkerId(0);
+  int workerId = nextWorkerId++;
 
-void JSCExecutor::terminateOwnedWebWorker(int workerId) {
-  auto worker = m_ownedWorkers.at(workerId).getExecutor();
-  std::shared_ptr<MessageQueueThread> workerMQT = worker->m_messageQueueThread;
-  m_ownedWorkers.erase(workerId);
-  workerMQT->quitSynchronous();
+  m_webWorkers.emplace(std::piecewise_construct, std::forward_as_tuple(workerId), std::forward_as_tuple(workerId, this, script));
+  Object workerObj = Value(m_context, workerRef).asObject();
+  workerObj.makeProtected();
+  m_webWorkerJSObjs.emplace(workerId, std::move(workerObj));
+  return workerId;
 }
 
-Object JSCExecutor::createMessageObject(const std::string& msgJson) {
-  Value rebornJSMsg = Value::fromJSON(m_context, String(msgJson.c_str()));
-  Object messageObject = Object::create(m_context);
-  messageObject.setProperty("data", rebornJSMsg);
-  return messageObject;
+void JSCExecutor::postMessageToWebWorker(int workerId, JSValueRef message, JSValueRef *exn) {
+  JSCWebWorker& worker = m_webWorkers.at(workerId);
+  worker.postMessage(message);
 }
 
-// Native JS hooks
-JSValueRef JSCExecutor::nativePostMessage(
-    JSContextRef ctx,
-    JSObjectRef function,
-    JSObjectRef thisObject,
-    size_t argumentCount,
-    const JSValueRef arguments[],
-    JSValueRef *exception) {
-  if (argumentCount != 1) {
-    *exception = makeJSCException(ctx, "postMessage got wrong number of arguments");
-    return JSValueMakeUndefined(ctx);
-  }
-  JSValueRef msg = arguments[0];
-  JSCExecutor *webWorker = s_globalContextRefToJSCExecutor.at(JSContextGetGlobalContext(ctx));
+void JSCExecutor::terminateWebWorker(int workerId) {
+  JSCWebWorker& worker = m_webWorkers.at(workerId);
 
-  webWorker->postMessageToOwner(msg);
+  worker.terminate();
 
-  return JSValueMakeUndefined(ctx);
+  m_webWorkers.erase(workerId);
+  m_webWorkerJSObjs.erase(workerId);
 }
 
+// Native JS hooks
+
 static JSValueRef makeInvalidModuleIdJSCException(
     JSContextRef ctx,
     const JSValueRef id,
@@ -508,7 +397,6 @@ JSValueRef JSCExecutor::nativeStartWorker(
   std::string scriptFile = Value(ctx, arguments[0]).toString().str();
 
   JSValueRef worker = arguments[1];
-  JSValueRef globalObj = arguments[2];
 
   JSCExecutor *executor;
   try {
@@ -518,7 +406,7 @@ JSValueRef JSCExecutor::nativeStartWorker(
     return JSValueMakeUndefined(ctx);
   }
 
-  int workerId = executor->addWebWorker(scriptFile, worker, globalObj);
+  int workerId = executor->addWebWorker(scriptFile, worker);
 
   return JSValueMakeNumber(ctx, workerId);
 }
@@ -549,7 +437,7 @@ JSValueRef JSCExecutor::nativePostMessageToWorker(
     return JSValueMakeUndefined(ctx);
   }
 
-  executor->postMessageToOwnedWebWorker((int) workerDouble, arguments[1], exception);
+  executor->postMessageToWebWorker((int) workerDouble, arguments[1], exception);
 
   return JSValueMakeUndefined(ctx);
 }
@@ -580,7 +468,7 @@ JSValueRef JSCExecutor::nativeTerminateWorker(
     return JSValueMakeUndefined(ctx);
   }
 
-  executor->terminateOwnedWebWorker((int) workerDouble);
+  executor->terminateWebWorker((int) workerDouble);
 
   return JSValueMakeUndefined(ctx);
 }
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.h b/ReactAndroid/src/main/jni/react/JSCExecutor.h
index 33622014458b..3084a7195ec6 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.h
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.h
@@ -7,10 +7,9 @@
 #include <unordered_map>
 #include <folly/json.h>
 #include <JavaScriptCore/JSContextRef.h>
-
 #include "Executor.h"
 #include "JSCHelpers.h"
-#include "Value.h"
+#include "JSCWebWorker.h"
 
 namespace facebook {
 namespace react {
@@ -28,26 +27,10 @@ class JSCExecutorFactory : public JSExecutorFactory {
   folly::dynamic m_jscConfig;
 };
 
-class JSCExecutor;
-class WorkerRegistration : public noncopyable {
-public:
-  explicit WorkerRegistration(std::unique_ptr<JSCExecutor> executor, Object jsObj) :
-      jsObj(std::move(jsObj)),
-      executor(std::move(executor)) {}
-
-  JSCExecutor* getExecutor() {
-    return executor.get();
-  }
-
-  Object jsObj;
-private:
-  std::unique_ptr<JSCExecutor> executor;
-};
-
-class JSCExecutor : public JSExecutor {
+class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
 public:
   /**
-   * Must be invoked from thread this Executor will run on.
+   * Should be invoked from the JS thread.
    */
   explicit JSCExecutor(Bridge *bridge, const std::string& cacheDir, const folly::dynamic& jscConfig);
   ~JSCExecutor() override;
@@ -77,43 +60,26 @@ class JSCExecutor : public JSExecutor {
   virtual void handleMemoryPressureCritical() override;
 
   void installNativeHook(const char *name, JSObjectCallAsFunctionCallback callback);
+  virtual void onMessageReceived(int workerId, const std::string& message) override;
+  virtual JSGlobalContextRef getContext() override;
+  virtual std::shared_ptr<MessageQueueThread> getMessageQueueThread() override;
 
 private:
   JSGlobalContextRef m_context;
+  std::unordered_map<int, JSCWebWorker> m_webWorkers;
+  std::unordered_map<int, Object> m_webWorkerJSObjs;
   Bridge *m_bridge;
-  int m_workerId = 0; // if this is a worker executor, this is non-zero
-  JSCExecutor *m_owner = nullptr; // if this is a worker executor, this is non-null
-  std::shared_ptr<bool> m_isDestroyed = std::shared_ptr<bool>(new bool(false));
-  std::unordered_map<int, WorkerRegistration> m_ownedWorkers;
   std::string m_deviceCacheDir;
   std::shared_ptr<MessageQueueThread> m_messageQueueThread;
   std::unique_ptr<JSModulesUnbundle> m_unbundle;
   folly::dynamic m_jscConfig;
 
-  /**
-   * WebWorker constructor. Must be invoked from thread this Executor will run on.
-   */
-  explicit JSCExecutor(
-      Bridge *bridge,
-      int workerId,
-      JSCExecutor *owner,
-      const std::string& script,
-      const std::unordered_map<std::string, std::string>& globalObjAsJSON,
-      const folly::dynamic& jscConfig);
-
-  void initOnJSVMThread();
-  void terminateOnJSVMThread();
+  int addWebWorker(const std::string& script, JSValueRef workerRef);
+  void postMessageToWebWorker(int worker, JSValueRef message, JSValueRef *exn);
   void flush();
-  void flushQueueImmediate(std::string queueJSON);
+  void terminateWebWorker(int worker);
   void loadModule(uint32_t moduleId);
-
-  int addWebWorker(const std::string& script, JSValueRef workerRef, JSValueRef globalObjRef);
-  void postMessageToOwnedWebWorker(int worker, JSValueRef message, JSValueRef *exn);
-  void postMessageToOwner(JSValueRef result);
-  void receiveMessageFromOwnedWebWorker(int workerId, const std::string& message);
-  void receiveMessageFromOwner(const std::string &msgString);
-  void terminateOwnedWebWorker(int worker);
-  Object createMessageObject(const std::string& msgData);
+  void flushQueueImmediate(std::string queueJSON);
 
   static JSValueRef nativeStartWorker(
       JSContextRef ctx,
@@ -136,13 +102,6 @@ class JSCExecutor : public JSExecutor {
       size_t argumentCount,
       const JSValueRef arguments[],
       JSValueRef *exception);
-  static JSValueRef nativePostMessage(
-      JSContextRef ctx,
-      JSObjectRef function,
-      JSObjectRef thisObject,
-      size_t argumentCount,
-      const JSValueRef arguments[],
-      JSValueRef *exception);
   static JSValueRef nativeRequire(
       JSContextRef ctx,
       JSObjectRef function,
diff --git a/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp b/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
new file mode 100644
index 000000000000..e8e710bdf393
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
@@ -0,0 +1,153 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#include "JSCWebWorker.h"
+
+#include <unistd.h>
+#include <condition_variable>
+#include <mutex>
+#include <unordered_map>
+
+#include <glog/logging.h>
+#include <folly/Memory.h>
+
+#include "JSCHelpers.h"
+#include "MessageQueueThread.h"
+#include "Platform.h"
+#include "Value.h"
+
+#include <JavaScriptCore/JSValueRef.h>
+
+namespace facebook {
+namespace react {
+
+// TODO(9604425): thread safety
+static std::unordered_map<JSContextRef, JSCWebWorker*> s_globalContextRefToJSCWebWorker;
+
+JSCWebWorker::JSCWebWorker(int id, JSCWebWorkerOwner *owner, std::string scriptSrc) :
+    id_(id),
+    scriptName_(std::move(scriptSrc)),
+    owner_(owner) {
+  ownerMessageQueueThread_ = owner->getMessageQueueThread();
+  CHECK(ownerMessageQueueThread_) << "Owner MessageQueue must not be null";
+  workerMessageQueueThread_ = WebWorkerUtil::createWebWorkerThread(id, ownerMessageQueueThread_.get());
+  CHECK(workerMessageQueueThread_) << "Failed to create worker thread";
+
+  workerMessageQueueThread_->runOnQueue([this] () {
+    initJSVMAndLoadScript();
+  });
+}
+
+
+JSCWebWorker::~JSCWebWorker() {
+  CHECK(isTerminated()) << "Didn't terminate the web worker before releasing it!";;
+}
+
+void JSCWebWorker::postMessage(JSValueRef msg) {
+  std::string msgString = Value(owner_->getContext(), msg).toJSONString();
+
+  workerMessageQueueThread_->runOnQueue([this, msgString] () {
+    if (isTerminated()) {
+      return;
+    }
+
+    JSValueRef args[] = { createMessageObject(context_, msgString) };
+    Value onmessageValue = Object::getGlobalObject(context_).getProperty("onmessage");
+    onmessageValue.asObject().callAsFunction(1, args);
+  });
+}
+
+void JSCWebWorker::terminate() {
+  if (isTerminated()) {
+    return;
+  }
+  isTerminated_.store(true, std::memory_order_release);
+
+  if (workerMessageQueueThread_->isOnThread()) {
+    terminateOnWorkerThread();
+  } else {
+    std::mutex signalMutex;
+    std::condition_variable signalCv;
+    bool terminationComplete = false;
+
+    workerMessageQueueThread_->runOnQueue([&] () mutable {
+      std::lock_guard<std::mutex> lock(signalMutex);
+
+      terminateOnWorkerThread();
+      terminationComplete = true;
+
+      signalCv.notify_one();
+    });
+
+    std::unique_lock<std::mutex> lock(signalMutex);
+    signalCv.wait(lock, [&terminationComplete] { return terminationComplete; });
+  }
+}
+
+void JSCWebWorker::terminateOnWorkerThread() {
+  s_globalContextRefToJSCWebWorker.erase(context_);
+  JSGlobalContextRelease(context_);
+  context_ = nullptr;
+  workerMessageQueueThread_->quitSynchronous();
+}
+
+bool JSCWebWorker::isTerminated() {
+  return isTerminated_.load(std::memory_order_acquire);
+}
+
+void JSCWebWorker::initJSVMAndLoadScript() {
+  CHECK(!isTerminated()) << "Worker was already finished!";
+  CHECK(!context_) << "Worker JS VM was already created!";
+
+  context_ = JSGlobalContextCreateInGroup(
+      NULL, // use default JS 'global' object
+      NULL // create new group (i.e. new VM)
+  );
+  s_globalContextRefToJSCWebWorker[context_] = this;
+
+  // TODO(9604438): Protect against script does not exist
+  std::string script = WebWorkerUtil::loadScriptFromAssets(scriptName_);
+  evaluateScript(context_, String(script.c_str()), String(scriptName_.c_str()));
+
+  installGlobalFunction(context_, "postMessage", nativePostMessage);
+}
+
+void JSCWebWorker::postMessageToOwner(JSValueRef msg) {
+  std::string msgString = Value(context_, msg).toJSONString();
+  ownerMessageQueueThread_->runOnQueue([this, msgString] () {
+      owner_->onMessageReceived(id_, msgString);
+  });
+}
+
+JSValueRef JSCWebWorker::nativePostMessage(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[],
+    JSValueRef *exception) {
+  if (argumentCount != 1) {
+    *exception = makeJSCException(ctx, "postMessage got wrong number of arguments");
+    return JSValueMakeUndefined(ctx);
+  }
+  JSValueRef msg = arguments[0];
+  JSCWebWorker *webWorker = s_globalContextRefToJSCWebWorker.at(JSContextGetGlobalContext(ctx));
+
+  if (webWorker->isTerminated()) {
+    return JSValueMakeUndefined(ctx);
+  }
+
+  webWorker->postMessageToOwner(msg);
+  
+  return JSValueMakeUndefined(ctx);
+}
+
+/*static*/
+Object JSCWebWorker::createMessageObject(JSContextRef context, const std::string& msgJson) {
+  Value rebornJSMsg = Value::fromJSON(context, String(msgJson.c_str()));
+  Object messageObject = Object::create(context);
+  messageObject.setProperty("data", rebornJSMsg);
+  return std::move(messageObject);
+}
+
+}
+}
diff --git a/ReactAndroid/src/main/jni/react/JSCWebWorker.h b/ReactAndroid/src/main/jni/react/JSCWebWorker.h
new file mode 100644
index 000000000000..73d983cdfe7b
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/JSCWebWorker.h
@@ -0,0 +1,94 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#include <atomic>
+#include <functional>
+#include <mutex>
+#include <string>
+#include <thread>
+#include <queue>
+
+#include <JavaScriptCore/JSValueRef.h>
+
+#include "Value.h"
+
+namespace facebook {
+namespace react {
+
+class MessageQueueThread;
+
+/**
+ * A class that can own the lifecycle, receive messages from, and dispatch messages
+ * to JSCWebWorkers.
+ */
+class JSCWebWorkerOwner {
+public:
+  /**
+   * Called when a worker has posted a message with `postMessage`.
+   */
+  virtual void onMessageReceived(int workerId, const std::string& message) = 0;
+  virtual JSGlobalContextRef getContext() = 0;
+
+  /**
+   * Should return the owner's MessageQueueThread. Calls to onMessageReceived will be enqueued
+   * on this thread.
+   */
+  virtual std::shared_ptr<MessageQueueThread> getMessageQueueThread() = 0;
+};
+
+/**
+ * Implementation of a web worker for JSC. The web worker should be created from the owner's
+ * (e.g., owning JSCExecutor instance) JS MessageQueueThread. The worker is responsible for
+ * creating its own MessageQueueThread.
+ *
+ * During operation, the JSCExecutor should call postMessage **from its own MessageQueueThread**
+ * to send messages to the worker. The worker will handle enqueueing those messages on its own
+ * MessageQueueThread as appropriate. When the worker has a message to post to the owner, it will
+ * enqueue a call to owner->onMessageReceived on the owner's MessageQueueThread.
+ */
+class JSCWebWorker {
+public:
+  explicit JSCWebWorker(int id, JSCWebWorkerOwner *owner, std::string script);
+  ~JSCWebWorker();
+
+  /**
+   * Post a message to be received by the worker on its thread. This must be called from 
+   * ownerMessageQueueThread_.
+   */
+  void postMessage(JSValueRef msg);
+
+  /**
+   * Synchronously quits the current worker and cleans up its VM.
+   */
+  void terminate();
+
+  /**
+   * Whether terminate() has been called on this worker.
+   */
+  bool isTerminated();
+
+  static Object createMessageObject(JSContextRef context, const std::string& msgData);
+private:
+  void initJSVMAndLoadScript();
+  void postRunnableToEventLoop(std::function<void()>&& runnable);
+  void postMessageToOwner(JSValueRef result);
+  void terminateOnWorkerThread();
+
+  int id_;
+  std::atomic_bool isTerminated_ = ATOMIC_VAR_INIT(false);
+  std::string scriptName_;
+  JSCWebWorkerOwner *owner_ = nullptr;
+  std::shared_ptr<MessageQueueThread> ownerMessageQueueThread_;
+  std::unique_ptr<MessageQueueThread> workerMessageQueueThread_;
+  JSGlobalContextRef context_ = nullptr;
+
+  static JSValueRef nativePostMessage(
+      JSContextRef ctx,
+      JSObjectRef function,
+      JSObjectRef thisObject,
+      size_t argumentCount,
+      const JSValueRef arguments[],
+      JSValueRef *exception);
+};
+
+}
+}
diff --git a/ReactAndroid/src/main/jni/react/MessageQueueThread.h b/ReactAndroid/src/main/jni/react/MessageQueueThread.h
index f6352ab0d90a..544b91142be9 100644
--- a/ReactAndroid/src/main/jni/react/MessageQueueThread.h
+++ b/ReactAndroid/src/main/jni/react/MessageQueueThread.h
@@ -2,9 +2,7 @@
 
 #pragma once
 
-#include <condition_variable>
 #include <functional>
-#include <mutex>
 
 namespace facebook {
 namespace react {
@@ -16,24 +14,6 @@ class MessageQueueThread {
   virtual bool isOnThread() = 0;
   // quitSynchronous() should synchronously ensure that no further tasks will run on the queue.
   virtual void quitSynchronous() = 0;
-
-  void runOnQueueSync(std::function<void()>&& runnable) {
-    std::mutex signalMutex;
-    std::condition_variable signalCv;
-    bool runnableComplete = false;
-
-    runOnQueue([&] () mutable {
-      std::lock_guard<std::mutex> lock(signalMutex);
-
-      runnable();
-      runnableComplete = true;
-
-      signalCv.notify_one();
-    });
-
-    std::unique_lock<std::mutex> lock(signalMutex);
-    signalCv.wait(lock, [&runnableComplete] { return runnableComplete; });
-  }
 };
 
 }}

From 9baef484984d161c77a60ae3fcd5aebf6fd25c08 Mon Sep 17 00:00:00 2001
From: Felix Oghina <foghina@fb.com>
Date: Fri, 26 Feb 2016 06:15:58 -0800
Subject: [PATCH 1322/1411] decouple textview from fresco

Reviewed By: andreicoman11

Differential Revision: D2960626

fb-gh-sync-id: c03aa7f16cdea795cefe39da2c5d660ae6278a37
shipit-source-id: c03aa7f16cdea795cefe39da2c5d660ae6278a37
---
 .../main/java/com/facebook/react/shell/BUCK   |   1 +
 .../react/shell/MainReactPackage.java         |   8 +-
 .../java/com/facebook/react/views/text/BUCK   |   4 -
 .../react/views/text/ReactRawTextManager.java |   1 -
 .../text/ReactTextInlineImageShadowNode.java  |  87 +------
 .../react/views/text/ReactTextShadowNode.java |  54 ++---
 .../react/views/text/TextInlineImageSpan.java | 221 +++++-------------
 .../react/views/text/frescosupport/BUCK       |  27 +++
 ...coBasedReactTextInlineImageShadowNode.java | 114 +++++++++
 .../FrescoBasedReactTextInlineImageSpan.java  | 155 ++++++++++++
 ...BasedReactTextInlineImageViewManager.java} |  34 +--
 .../textinput/ReactTextInputManager.java      |   2 +-
 12 files changed, 406 insertions(+), 302 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageShadowNode.java
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageSpan.java
 rename ReactAndroid/src/main/java/com/facebook/react/views/text/{ReactTextInlineImageViewManager.java => frescosupport/FrescoBasedReactTextInlineImageViewManager.java} (56%)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK
index 88b94ebdaae3..ec0c816b8364 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK
+++ b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK
@@ -19,6 +19,7 @@ android_library(
     react_native_target('java/com/facebook/react/views/swiperefresh:swiperefresh'),
     react_native_target('java/com/facebook/react/views/switchview:switchview'),
     react_native_target('java/com/facebook/react/views/text:text'),
+    react_native_target('java/com/facebook/react/views/text/frescosupport:frescosupport'),
     react_native_target('java/com/facebook/react/views/textinput:textinput'),
     react_native_target('java/com/facebook/react/views/toolbar:toolbar'),
     react_native_target('java/com/facebook/react/views/view:view'),
diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
index d3ec2880ff71..01a30148daa8 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
@@ -22,8 +22,8 @@
 import com.facebook.react.modules.camera.ImageEditingManager;
 import com.facebook.react.modules.camera.ImageStoreManager;
 import com.facebook.react.modules.clipboard.ClipboardModule;
-import com.facebook.react.modules.dialog.DialogModule;
 import com.facebook.react.modules.datepicker.DatePickerDialogModule;
+import com.facebook.react.modules.dialog.DialogModule;
 import com.facebook.react.modules.fresco.FrescoModule;
 import com.facebook.react.modules.intent.IntentModule;
 import com.facebook.react.modules.location.LocationModule;
@@ -45,16 +45,16 @@
 import com.facebook.react.views.recyclerview.RecyclerViewBackedScrollViewManager;
 import com.facebook.react.views.scroll.ReactHorizontalScrollViewManager;
 import com.facebook.react.views.scroll.ReactScrollViewManager;
+import com.facebook.react.views.swiperefresh.SwipeRefreshLayoutManager;
 import com.facebook.react.views.switchview.ReactSwitchManager;
 import com.facebook.react.views.text.ReactRawTextManager;
 import com.facebook.react.views.text.ReactTextViewManager;
-import com.facebook.react.views.text.ReactTextInlineImageViewManager;
 import com.facebook.react.views.text.ReactVirtualTextViewManager;
+import com.facebook.react.views.textfrescosupport.FrescoBasedReactTextInlineImageViewManager;
 import com.facebook.react.views.textinput.ReactTextInputManager;
 import com.facebook.react.views.toolbar.ReactToolbarManager;
 import com.facebook.react.views.view.ReactViewManager;
 import com.facebook.react.views.viewpager.ReactViewPagerManager;
-import com.facebook.react.views.swiperefresh.SwipeRefreshLayoutManager;
 import com.facebook.react.views.webview.ReactWebViewManager;
 
 /**
@@ -106,7 +106,7 @@ public List<ViewManager> createViewManagers(ReactApplicationContext reactContext
       new ReactRawTextManager(),
       new ReactScrollViewManager(),
       new ReactSwitchManager(),
-      new ReactTextInlineImageViewManager(),
+      new FrescoBasedReactTextInlineImageViewManager(),
       new ReactTextInputManager(),
       new ReactTextViewManager(),
       new ReactToolbarManager(),
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK
index df5bd7dee3c0..8d1e02e6c3d8 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK
@@ -9,10 +9,6 @@ android_library(
     react_native_target('java/com/facebook/csslayout:csslayout'),
     react_native_target('java/com/facebook/react/uimanager:uimanager'),
     react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
-    react_native_dep('libraries/fresco/fresco-react-native:fbcore'),
-    react_native_dep('libraries/fresco/fresco-react-native:fresco-react-native'),
-    react_native_dep('libraries/fresco/fresco-react-native:fresco-drawee'),
-    react_native_dep('libraries/fresco/fresco-react-native:imagepipeline'),
     react_native_dep('third-party/java/infer-annotations:infer-annotations'),
     react_native_dep('third-party/java/jsr-305:jsr-305'),
   ],
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactRawTextManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactRawTextManager.java
index aa71c74b9ff0..98e02829ae6d 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactRawTextManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactRawTextManager.java
@@ -10,7 +10,6 @@
 package com.facebook.react.views.text;
 
 import com.facebook.react.common.annotations.VisibleForTesting;
-import com.facebook.react.uimanager.ReactStylesDiffMap;
 import com.facebook.react.uimanager.ThemedReactContext;
 
 /**
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextInlineImageShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextInlineImageShadowNode.java
index 3a4eed131906..4e986644e16b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextInlineImageShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextInlineImageShadowNode.java
@@ -9,90 +9,17 @@
 
 package com.facebook.react.views.text;
 
-import javax.annotation.Nullable;
-
-import java.util.Locale;
-
-import android.content.Context;
-import android.net.Uri;
-
-import com.facebook.common.util.UriUtil;
-import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
 import com.facebook.react.uimanager.LayoutShadowNode;
-import com.facebook.react.uimanager.annotations.ReactProp;
-import com.facebook.react.uimanager.ReactShadowNode;
 
 /**
- * {@link ReactShadowNode} class for Image embedded within a TextView.
- *
+ * Base class for {@link com.facebook.csslayout.CSSNode}s that represent inline images.
  */
-public class ReactTextInlineImageShadowNode extends LayoutShadowNode {
-
-  private @Nullable Uri mUri;
-  private final AbstractDraweeControllerBuilder mDraweeControllerBuilder;
-  private final @Nullable Object mCallerContext;
-
-  public ReactTextInlineImageShadowNode(
-      AbstractDraweeControllerBuilder draweeControllerBuilder,
-      @Nullable Object callerContext) {
-    mDraweeControllerBuilder = draweeControllerBuilder;
-    mCallerContext = callerContext;
-  }
-
-  @ReactProp(name = "src")
-  public void setSource(@Nullable String source) {
-    Uri uri = null;
-    if (source != null) {
-      try {
-        uri = Uri.parse(source);
-        // Verify scheme is set, so that relative uri (used by static resources) are not handled.
-        if (uri.getScheme() == null) {
-          uri = null;
-        }
-      } catch (Exception e) {
-        // ignore malformed uri, then attempt to extract resource ID.
-      }
-      if (uri == null) {
-        uri = getResourceDrawableUri(getThemedContext(), source);
-      }
-    }
-    if (uri != mUri) {
-      markUpdated();
-    }
-    mUri = uri;
-  }
-
-  public @Nullable Uri getUri() {
-    return mUri;
-  }
-
-  // TODO: t9053573 is tracking that this code should be shared
-  private static @Nullable Uri getResourceDrawableUri(Context context, @Nullable String name) {
-    if (name == null || name.isEmpty()) {
-      return null;
-    }
-    name = name.toLowerCase(Locale.getDefault()).replace("-", "_");
-    int resId = context.getResources().getIdentifier(
-        name,
-        "drawable",
-        context.getPackageName());
-    return new Uri.Builder()
-        .scheme(UriUtil.LOCAL_RESOURCE_SCHEME)
-        .path(String.valueOf(resId))
-        .build();
-  }
-
-  @Override
-  public boolean isVirtual() {
-    return true;
-  }
-
-  public AbstractDraweeControllerBuilder getDraweeControllerBuilder() {
-    return mDraweeControllerBuilder;
-  }
+public abstract class ReactTextInlineImageShadowNode extends LayoutShadowNode {
 
-  public @Nullable Object getCallerContext() {
-    return mCallerContext;
-  }
+  /**
+   * Build a {@link TextInlineImageSpan} from this node. This will be added to the TextView in
+   * place of this node.
+   */
+  public abstract TextInlineImageSpan buildInlineImageSpan();
 
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java
index 314df23ef3d5..2d98703c2f67 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java
@@ -14,7 +14,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import android.content.res.Resources;
 import android.graphics.Typeface;
 import android.text.BoringLayout;
 import android.text.Layout;
@@ -37,11 +36,11 @@
 import com.facebook.react.uimanager.IllegalViewOperationException;
 import com.facebook.react.uimanager.LayoutShadowNode;
 import com.facebook.react.uimanager.PixelUtil;
-import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.ReactShadowNode;
 import com.facebook.react.uimanager.UIViewOperationQueue;
 import com.facebook.react.uimanager.ViewDefaults;
 import com.facebook.react.uimanager.ViewProps;
+import com.facebook.react.uimanager.annotations.ReactProp;
 
 /**
  * {@link ReactShadowNode} class for spannable text view.
@@ -94,7 +93,7 @@ public void execute(SpannableStringBuilder sb) {
     }
   }
 
-  private static final void buildSpannedFromTextCSSNode(
+  private static void buildSpannedFromTextCSSNode(
       ReactTextShadowNode textCSSNode,
       SpannableStringBuilder sb,
       List<SetSpanOperation> ops) {
@@ -107,7 +106,14 @@ private static final void buildSpannedFromTextCSSNode(
       if (child instanceof ReactTextShadowNode) {
         buildSpannedFromTextCSSNode((ReactTextShadowNode) child, sb, ops);
       } else if (child instanceof ReactTextInlineImageShadowNode) {
-        buildSpannedFromImageNode((ReactTextInlineImageShadowNode) child, sb, ops);
+        // We make the image take up 1 character in the span and put a corresponding character into
+        // the text so that the image doesn't run over any following text.
+        sb.append(INLINE_IMAGE_PLACEHOLDER);
+        ops.add(
+          new SetSpanOperation(
+            sb.length() - INLINE_IMAGE_PLACEHOLDER.length(),
+            sb.length(),
+            ((ReactTextInlineImageShadowNode) child).buildInlineImageSpan()));
       } else {
         throw new IllegalViewOperationException("Unexpected view type nested under text node: "
                 + child.getClass());
@@ -154,36 +160,14 @@ private static final void buildSpannedFromTextCSSNode(
     }
   }
 
-  private static final void buildSpannedFromImageNode(
-      ReactTextInlineImageShadowNode node,
-      SpannableStringBuilder sb,
-      List<SetSpanOperation> ops) {
-    int start = sb.length();
-    // Create our own internal ImageSpan which will allow us to correctly layout the Image
-    Resources resources = node.getThemedContext().getResources();
-    int height = (int) Math.ceil(node.getStyleHeight());
-    int width = (int) Math.ceil(node.getStyleWidth());
-    TextInlineImageSpan imageSpan = new TextInlineImageSpan(
-        resources,
-        height,
-        width,
-        node.getUri(),
-        node.getDraweeControllerBuilder(),
-        node.getCallerContext());
-    // We make the image take up 1 character in the span and put a corresponding character into the
-    // text so that the image doesn't run over any following text.
-    sb.append(INLINE_IMAGE_PLACEHOLDER);
-    ops.add(new SetSpanOperation(start, sb.length(), imageSpan));
-  }
-
-  protected static final Spannable fromTextCSSNode(ReactTextShadowNode textCSSNode) {
+  protected static Spannable fromTextCSSNode(ReactTextShadowNode textCSSNode) {
     SpannableStringBuilder sb = new SpannableStringBuilder();
     // TODO(5837930): Investigate whether it's worth optimizing this part and do it if so
 
     // The {@link SpannableStringBuilder} implementation require setSpan operation to be called
     // up-to-bottom, otherwise all the spannables that are withing the region for which one may set
     // a new spannable will be wiped out
-    List<SetSpanOperation> ops = new ArrayList<SetSpanOperation>();
+    List<SetSpanOperation> ops = new ArrayList<>();
     buildSpannedFromTextCSSNode(textCSSNode, sb, ops);
     if (textCSSNode.mFontSize == UNSET) {
       sb.setSpan(
@@ -330,6 +314,13 @@ private static int parseNumericFontWeight(String fontWeightString) {
 
   protected boolean mContainsImages = false;
 
+  public ReactTextShadowNode(boolean isVirtual) {
+    mIsVirtual = isVirtual;
+    if (!isVirtual) {
+      setMeasureFunction(TEXT_MEASURE_FUNCTION);
+    }
+  }
+
   @Override
   public void onBeforeLayout() {
     if (mIsVirtual) {
@@ -483,11 +474,4 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
       uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
     }
   }
-
-  public ReactTextShadowNode(boolean isVirtual) {
-    mIsVirtual = isVirtual;
-    if (!isVirtual) {
-      setMeasureFunction(TEXT_MEASURE_FUNCTION);
-    }
-  }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextInlineImageSpan.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextInlineImageSpan.java
index 6079ce00b552..0308ee20c28c 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextInlineImageSpan.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextInlineImageSpan.java
@@ -7,163 +7,64 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  */
 
-package com.facebook.react.views.text;
-
-import javax.annotation.Nullable;
-
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.text.Spannable;
-import android.text.style.ReplacementSpan;
-import android.widget.TextView;
-
-import com.facebook.drawee.backends.pipeline.Fresco;
-import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
-import com.facebook.drawee.generic.GenericDraweeHierarchy;
-import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
-import com.facebook.drawee.interfaces.DraweeController;
-import com.facebook.drawee.view.DraweeHolder;
-import com.facebook.imagepipeline.request.ImageRequest;
-import com.facebook.imagepipeline.request.ImageRequestBuilder;
-
-/**
- * TextInlineImageSpan is a span for Images that are inside <Text/>.  It computes it's size based
- * on the input size.  When it is time to draw, it will use the Fresco framework to get the right
- * Drawable and let that draw.
- *
- * Since Fresco needs to callback to the TextView that contains this, in the ViewManager, you must
- * tell the Span about the TextView
- *
- * Note: It borrows code from DynamicDrawableSpan and if that code updates how it computes size or
- * draws, we need to update this as well.
- */
-public class TextInlineImageSpan extends ReplacementSpan {
-
-  private @Nullable Drawable mDrawable;
-  private final AbstractDraweeControllerBuilder mDraweeControllerBuilder;
-  private final DraweeHolder<GenericDraweeHierarchy> mDraweeHolder;
-  private final @Nullable Object mCallerContext;
-
-  private int mHeight;
-  private Uri mUri;
-  private int mWidth;
-
-  private @Nullable TextView mTextView;
-
-  public TextInlineImageSpan(
-      Resources resources,
-      int height,
-      int width,
-      @Nullable Uri uri,
-      AbstractDraweeControllerBuilder draweeControllerBuilder,
-      @Nullable Object callerContext) {
-    mDraweeHolder = new DraweeHolder(
-        GenericDraweeHierarchyBuilder.newInstance(resources)
-            .build()
-    );
-    mDraweeControllerBuilder = draweeControllerBuilder;
-    mCallerContext = callerContext;
-
-    mHeight = height;
-    mWidth = width;
-    mUri = (uri != null) ? uri : Uri.EMPTY;
-  }
-
-  /**
-   * The ReactTextView that holds this ImageSpan is responsible for passing these methods on so
-   * that we can do proper lifetime management for Fresco
-   */
-  public void onDetachedFromWindow() {
-    mDraweeHolder.onDetach();
-  }
-
-  public void onStartTemporaryDetach() {
-    mDraweeHolder.onDetach();
-  }
-
-  public void onAttachedToWindow() {
-    mDraweeHolder.onAttach();
-  }
-
-  public void onFinishTemporaryDetach() {
-    mDraweeHolder.onAttach();
-  }
-
-  public @Nullable Drawable getDrawable() {
-    return mDrawable;
-  }
-
-  @Override
-  public int getSize(
-      Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
-    // NOTE: This getSize code is copied from DynamicDrawableSpan and modified to not use a Drawable
-
-    if (fm != null) {
-      fm.ascent = -mHeight;
-      fm.descent = 0;
-
-      fm.top = fm.ascent;
-      fm.bottom = 0;
-    }
-
-    return mWidth;
-  }
-
-  @Override
-  public void draw(
-      Canvas canvas,
-      CharSequence text,
-      int start,
-      int end,
-      float x,
-      int top,
-      int y,
-      int bottom,
-      Paint paint) {
-    if (mDrawable == null) {
-      ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(mUri)
-          .build();
-
-      DraweeController draweeController = mDraweeControllerBuilder
-          .reset()
-          .setOldController(mDraweeHolder.getController())
-          .setCallerContext(mCallerContext)
-          .setImageRequest(imageRequest)
-          .build();
-      mDraweeHolder.setController(draweeController);
-
-      mDrawable = mDraweeHolder.getTopLevelDrawable();
-      mDrawable.setBounds(0, 0, mWidth, mHeight);
-      mDrawable.setCallback(mTextView);
-    }
-
-    // NOTE: This drawing code is copied from DynamicDrawableSpan
-
-    canvas.save();
-
-    int transY = bottom - mDrawable.getBounds().bottom;
-
-    canvas.translate(x, transY);
-    mDrawable.draw(canvas);
-    canvas.restore();
-  }
-
-  /**
-   * For TextInlineImageSpan we need to update the Span to know that the window is attached and
-   * the TextView that we will set as the callback on the Drawable.
-   *
-   * @param spannable The spannable that may contain TextInlineImageSpans
-   * @param view The view which will be set as the callback for the Drawable
-   */
-  public static void possiblyUpdateInlineImageSpans(Spannable spannable, TextView view) {
-    TextInlineImageSpan[] spans =
-        spannable.getSpans(0, spannable.length(), TextInlineImageSpan.class);
-    for (TextInlineImageSpan span : spans) {
-      span.onAttachedToWindow();
-      span.mTextView = view;
-    }
-  };
-}
+ package com.facebook.react.views.text;
+
+ import javax.annotation.Nullable;
+
+ import android.graphics.drawable.Drawable;
+ import android.text.Spannable;
+ import android.text.style.ReplacementSpan;
+ import android.view.View;
+ import android.widget.TextView;
+
+ /**
+  * Base class for inline image spans.
+  */
+ public abstract class TextInlineImageSpan extends ReplacementSpan {
+
+   /**
+    * For TextInlineImageSpan we need to update the Span to know that the window is attached and
+    * the TextView that we will set as the callback on the Drawable.
+    *
+    * @param spannable The spannable that may contain TextInlineImageSpans
+    * @param view The view which will be set as the callback for the Drawable
+    */
+   public static void possiblyUpdateInlineImageSpans(Spannable spannable, TextView view) {
+     TextInlineImageSpan[] spans =
+       spannable.getSpans(0, spannable.length(), TextInlineImageSpan.class);
+     for (TextInlineImageSpan span : spans) {
+       span.onAttachedToWindow();
+       span.setTextView(view);
+     }
+   }
+
+   /**
+    * Get the drawable that is span represents.
+    */
+   public abstract @Nullable Drawable getDrawable();
+
+   /**
+    * Called by the text view from {@link View#onDetachedFromWindow()},
+    */
+   public abstract void onDetachedFromWindow();
+
+   /**
+    * Called by the text view from {@link View#onStartTemporaryDetach()}.
+    */
+   public abstract void onStartTemporaryDetach();
+
+   /**
+    * Called by the text view from {@link View#onAttachedToWindow()}.
+    */
+   public abstract void onAttachedToWindow();
+
+   /**
+    * Called by the text view from {@link View#onFinishTemporaryDetach()}.
+    */
+   public abstract void onFinishTemporaryDetach();
+
+   /**
+    * Set the textview that will contain this span.
+    */
+   public abstract void setTextView(TextView textView);
+ }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/BUCK
new file mode 100644
index 000000000000..e8ddbceb6d95
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/BUCK
@@ -0,0 +1,27 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'frescosupport',
+  srcs = glob(['*.java']),
+  deps = [
+    react_native_target('java/com/facebook/csslayout:csslayout'),
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/uimanager:uimanager'),
+    react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
+    react_native_target('java/com/facebook/react/views/text:text'),
+    react_native_dep('libraries/fresco/fresco-react-native:fbcore'),
+    react_native_dep('libraries/fresco/fresco-react-native:fresco-drawee'),
+    react_native_dep('libraries/fresco/fresco-react-native:fresco-react-native'),
+    react_native_dep('libraries/fresco/fresco-react-native:imagepipeline'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':frescosupport',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageShadowNode.java
new file mode 100644
index 000000000000..643a2c136fe5
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageShadowNode.java
@@ -0,0 +1,114 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.textfrescosupport;
+
+import javax.annotation.Nullable;
+
+import java.util.Locale;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.Uri;
+
+import com.facebook.common.util.UriUtil;
+import com.facebook.csslayout.CSSNode;
+import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
+import com.facebook.react.uimanager.annotations.ReactProp;
+import com.facebook.react.views.text.ReactTextInlineImageShadowNode;
+import com.facebook.react.views.text.TextInlineImageSpan;
+
+/**
+ * {@link CSSNode} that represents an inline image. Loading is done using Fresco.
+ *
+ */
+public class FrescoBasedReactTextInlineImageShadowNode extends ReactTextInlineImageShadowNode {
+
+  private @Nullable Uri mUri;
+  private final AbstractDraweeControllerBuilder mDraweeControllerBuilder;
+  private final @Nullable Object mCallerContext;
+
+  public FrescoBasedReactTextInlineImageShadowNode(
+    AbstractDraweeControllerBuilder draweeControllerBuilder,
+    @Nullable Object callerContext) {
+    mDraweeControllerBuilder = draweeControllerBuilder;
+    mCallerContext = callerContext;
+  }
+
+  @ReactProp(name = "src")
+  public void setSource(@Nullable String source) {
+    Uri uri = null;
+    if (source != null) {
+      try {
+        uri = Uri.parse(source);
+        // Verify scheme is set, so that relative uri (used by static resources) are not handled.
+        if (uri.getScheme() == null) {
+          uri = null;
+        }
+      } catch (Exception e) {
+        // ignore malformed uri, then attempt to extract resource ID.
+      }
+      if (uri == null) {
+        uri = getResourceDrawableUri(getThemedContext(), source);
+      }
+    }
+    if (uri != mUri) {
+      markUpdated();
+    }
+    mUri = uri;
+  }
+
+  public @Nullable Uri getUri() {
+    return mUri;
+  }
+
+  // TODO: t9053573 is tracking that this code should be shared
+  private static @Nullable Uri getResourceDrawableUri(Context context, @Nullable String name) {
+    if (name == null || name.isEmpty()) {
+      return null;
+    }
+    name = name.toLowerCase(Locale.getDefault()).replace("-", "_");
+    int resId = context.getResources().getIdentifier(
+      name,
+      "drawable",
+      context.getPackageName());
+    return new Uri.Builder()
+      .scheme(UriUtil.LOCAL_RESOURCE_SCHEME)
+      .path(String.valueOf(resId))
+      .build();
+  }
+
+  @Override
+  public boolean isVirtual() {
+    return true;
+  }
+
+  @Override
+  public TextInlineImageSpan buildInlineImageSpan() {
+    Resources resources = getThemedContext().getResources();
+    int height = (int) Math.ceil(getStyleHeight());
+    int width = (int) Math.ceil(getStyleWidth());
+    return new FrescoBasedReactTextInlineImageSpan(
+      resources,
+      height,
+      width,
+      getUri(),
+      getDraweeControllerBuilder(),
+      getCallerContext());
+  }
+
+  public AbstractDraweeControllerBuilder getDraweeControllerBuilder() {
+    return mDraweeControllerBuilder;
+  }
+
+  public @Nullable Object getCallerContext() {
+    return mCallerContext;
+  }
+
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageSpan.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageSpan.java
new file mode 100644
index 000000000000..d62ecf0ce4c4
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageSpan.java
@@ -0,0 +1,155 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.views.textfrescosupport;
+
+import javax.annotation.Nullable;
+
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.widget.TextView;
+
+import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
+import com.facebook.drawee.generic.GenericDraweeHierarchy;
+import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
+import com.facebook.drawee.interfaces.DraweeController;
+import com.facebook.drawee.view.DraweeHolder;
+import com.facebook.imagepipeline.request.ImageRequest;
+import com.facebook.imagepipeline.request.ImageRequestBuilder;
+import com.facebook.react.views.text.TextInlineImageSpan;
+
+/**
+ * FrescoBasedTextInlineImageSpan is a span for Images that are inside <Text/>. It computes
+ * its size based on the input size. When it is time to draw, it will use the Fresco framework to
+ * get the right Drawable and let that draw.
+ *
+ * Since Fresco needs to callback to the TextView that contains this, in the ViewManager, you must
+ * tell the Span about the TextView
+ *
+ * Note: It borrows code from DynamicDrawableSpan and if that code updates how it computes size or
+ * draws, we need to update this as well.
+ */
+public class FrescoBasedReactTextInlineImageSpan extends TextInlineImageSpan {
+
+  private @Nullable Drawable mDrawable;
+  private final AbstractDraweeControllerBuilder mDraweeControllerBuilder;
+  private final DraweeHolder<GenericDraweeHierarchy> mDraweeHolder;
+  private final @Nullable Object mCallerContext;
+
+  private int mHeight;
+  private Uri mUri;
+  private int mWidth;
+
+  private @Nullable TextView mTextView;
+
+  public FrescoBasedReactTextInlineImageSpan(
+      Resources resources,
+      int height,
+      int width,
+      @Nullable Uri uri,
+      AbstractDraweeControllerBuilder draweeControllerBuilder,
+      @Nullable Object callerContext) {
+    mDraweeHolder = new DraweeHolder(
+        GenericDraweeHierarchyBuilder.newInstance(resources)
+            .build()
+    );
+    mDraweeControllerBuilder = draweeControllerBuilder;
+    mCallerContext = callerContext;
+
+    mHeight = height;
+    mWidth = width;
+    mUri = (uri != null) ? uri : Uri.EMPTY;
+  }
+
+  /**
+   * The ReactTextView that holds this ImageSpan is responsible for passing these methods on so
+   * that we can do proper lifetime management for Fresco
+   */
+  public void onDetachedFromWindow() {
+    mDraweeHolder.onDetach();
+  }
+
+  public void onStartTemporaryDetach() {
+    mDraweeHolder.onDetach();
+  }
+
+  public void onAttachedToWindow() {
+    mDraweeHolder.onAttach();
+  }
+
+  public void onFinishTemporaryDetach() {
+    mDraweeHolder.onAttach();
+  }
+
+  public @Nullable Drawable getDrawable() {
+    return mDrawable;
+  }
+
+  @Override
+  public int getSize(
+      Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
+    // NOTE: This getSize code is copied from DynamicDrawableSpan and modified to not use a Drawable
+
+    if (fm != null) {
+      fm.ascent = -mHeight;
+      fm.descent = 0;
+
+      fm.top = fm.ascent;
+      fm.bottom = 0;
+    }
+
+    return mWidth;
+  }
+
+  public void setTextView(TextView textView) {
+    mTextView = textView;
+  }
+
+  @Override
+  public void draw(
+      Canvas canvas,
+      CharSequence text,
+      int start,
+      int end,
+      float x,
+      int top,
+      int y,
+      int bottom,
+      Paint paint) {
+    if (mDrawable == null) {
+      ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(mUri)
+          .build();
+
+      DraweeController draweeController = mDraweeControllerBuilder
+          .reset()
+          .setOldController(mDraweeHolder.getController())
+          .setCallerContext(mCallerContext)
+          .setImageRequest(imageRequest)
+          .build();
+      mDraweeHolder.setController(draweeController);
+
+      mDrawable = mDraweeHolder.getTopLevelDrawable();
+      mDrawable.setBounds(0, 0, mWidth, mHeight);
+      mDrawable.setCallback(mTextView);
+    }
+
+    // NOTE: This drawing code is copied from DynamicDrawableSpan
+
+    canvas.save();
+
+    int transY = bottom - mDrawable.getBounds().bottom;
+
+    canvas.translate(x, transY);
+    mDrawable.draw(canvas);
+    canvas.restore();
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextInlineImageViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageViewManager.java
similarity index 56%
rename from ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextInlineImageViewManager.java
rename to ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageViewManager.java
index b16b42deaf94..c272bf39d89a 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextInlineImageViewManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageViewManager.java
@@ -7,7 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  */
 
-package com.facebook.react.views.text;
+package com.facebook.react.views.textfrescosupport;
 
 import javax.annotation.Nullable;
 
@@ -19,24 +19,24 @@
 import com.facebook.react.uimanager.ViewManager;
 
 /**
- * Manages Images embedded in Text nodes. Since they are used only as a virtual nodes any type of
- * native view operation will throw an {@link IllegalStateException}
+ * Manages Images embedded in Text nodes using Fresco. Since they are used only as a virtual nodes
+ * any type of native view operation will throw an {@link IllegalStateException}.
  */
-public class ReactTextInlineImageViewManager
-    extends ViewManager<View, ReactTextInlineImageShadowNode> {
+public class FrescoBasedReactTextInlineImageViewManager
+  extends ViewManager<View, FrescoBasedReactTextInlineImageShadowNode> {
 
   static final String REACT_CLASS = "RCTTextInlineImage";
 
   private final @Nullable AbstractDraweeControllerBuilder mDraweeControllerBuilder;
   private final @Nullable Object mCallerContext;
 
-  public ReactTextInlineImageViewManager() {
+  public FrescoBasedReactTextInlineImageViewManager() {
     this(null, null);
   }
 
-  public ReactTextInlineImageViewManager(
-      @Nullable AbstractDraweeControllerBuilder draweeControllerBuilder,
-      @Nullable Object callerContext) {
+  public FrescoBasedReactTextInlineImageViewManager(
+    @Nullable AbstractDraweeControllerBuilder draweeControllerBuilder,
+    @Nullable Object callerContext) {
     mDraweeControllerBuilder = draweeControllerBuilder;
     mCallerContext = callerContext;
   }
@@ -52,18 +52,18 @@ public View createViewInstance(ThemedReactContext context) {
   }
 
   @Override
-  public ReactTextInlineImageShadowNode createShadowNodeInstance() {
-    return new ReactTextInlineImageShadowNode(
-        (mDraweeControllerBuilder != null) ?
-            mDraweeControllerBuilder :
-            Fresco.newDraweeControllerBuilder(),
-        mCallerContext
+  public FrescoBasedReactTextInlineImageShadowNode createShadowNodeInstance() {
+    return new FrescoBasedReactTextInlineImageShadowNode(
+      (mDraweeControllerBuilder != null) ?
+        mDraweeControllerBuilder :
+        Fresco.newDraweeControllerBuilder(),
+      mCallerContext
     );
   }
 
   @Override
-  public Class<ReactTextInlineImageShadowNode> getShadowNodeClass() {
-    return ReactTextInlineImageShadowNode.class;
+  public Class<FrescoBasedReactTextInlineImageShadowNode> getShadowNodeClass() {
+    return FrescoBasedReactTextInlineImageShadowNode.class;
   }
 
   @Override
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
index d6ce4f0def66..2ac07ddc66e2 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
@@ -43,8 +43,8 @@
 import com.facebook.react.uimanager.annotations.ReactProp;
 import com.facebook.react.uimanager.events.EventDispatcher;
 import com.facebook.react.views.text.DefaultStyleValuesUtil;
-import com.facebook.react.views.text.ReactTextUpdate;
 import com.facebook.react.views.text.TextInlineImageSpan;
+import com.facebook.react.views.text.ReactTextUpdate;
 
 /**
  * Manages instances of TextInput.

From 9edfd945d141bdcb428ad3387c08a362883dbe17 Mon Sep 17 00:00:00 2001
From: Dave Miller <dmmiller@fb.com>
Date: Fri, 26 Feb 2016 06:45:37 -0800
Subject: [PATCH 1323/1411] Fix minor code nit from D2977441

Reviewed By: andreicoman11

Differential Revision: D2982182

fb-gh-sync-id: dba3c6ea0dfbd375e3c27d3ad2ba3481d05e06e8
shipit-source-id: dba3c6ea0dfbd375e3c27d3ad2ba3481d05e06e8
---
 .../com/facebook/react/modules/intent/IntentModule.java    | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java
index 6a84f50cd11a..8139797ae633 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java
@@ -86,16 +86,15 @@ public void openURL(String url, Promise promise) {
         getReactApplicationContext().getPackageManager());
       String otherPackageName = (componentName != null ? componentName.getPackageName() : "");
 
-      // Always add the FLAG_ACTIVITY_NEW_TASK if we are launching to a different package
-      if (!selfPackageName.equals(otherPackageName)) {
+      // If there is no currentActivity or we are launching to a different package we need to set
+      // the FLAG_ACTIVITY_NEW_TASK flag
+      if (currentActivity == null || !selfPackageName.equals(otherPackageName)) {
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
       }
 
       if (currentActivity != null) {
         currentActivity.startActivity(intent);
       } else {
-        // If no currentActivity, we want to always start a new task regardless of logic above
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         getReactApplicationContext().startActivity(intent);
       }
 

From c8835d02263f6ff975a2783cfbcc79f689ff02d6 Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Fri, 26 Feb 2016 06:49:20 -0800
Subject: [PATCH 1324/1411] Fix RCTLinkingManager crash on iOS7

Reviewed By: nicklockwood

Differential Revision: D2982199

fb-gh-sync-id: 28ff6ddfe850df5925424423115ba953651ca94f
shipit-source-id: 28ff6ddfe850df5925424423115ba953651ca94f
---
 Libraries/LinkingIOS/RCTLinkingManager.m | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/Libraries/LinkingIOS/RCTLinkingManager.m b/Libraries/LinkingIOS/RCTLinkingManager.m
index 5bbdd998f76e..9538981298a0 100644
--- a/Libraries/LinkingIOS/RCTLinkingManager.m
+++ b/Libraries/LinkingIOS/RCTLinkingManager.m
@@ -34,17 +34,18 @@ - (void)setBridge:(RCTBridge *)bridge
 - (NSDictionary<NSString *, id> *)constantsToExport
 {
   NSURL *initialURL;
-  
+
   if (_bridge.launchOptions[UIApplicationLaunchOptionsURLKey]) {
     initialURL = _bridge.launchOptions[UIApplicationLaunchOptionsURLKey];
-  } else if (_bridge.launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey]) {
+  } else if (&UIApplicationLaunchOptionsUserActivityDictionaryKey &&
+      _bridge.launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey]) {
     NSDictionary *userActivityDictionary = _bridge.launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey];
 
     if ([userActivityDictionary[UIApplicationLaunchOptionsUserActivityTypeKey] isEqual:NSUserActivityTypeBrowsingWeb]) {
       initialURL = ((NSUserActivity *)userActivityDictionary[@"UIApplicationLaunchOptionsUserActivityKey"]).webpageURL;
     }
   }
-  
+
   return @{@"initialURL": RCTNullIfNil(initialURL.absoluteString)};
 }
 

From f7df3bb78abcccffabdffb813ef5f117d9521713 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Fri, 26 Feb 2016 08:17:39 -0800
Subject: [PATCH 1325/1411] Removed eager init of all ViewManagers on layout

Summary:The `uiBlockToAmendWithShadowViewRegistry:` is called on every single view manager, on every single layout pass. This causes all view managers to be eagerly intiialized, even if not being used.

In practice very few modules actually use this method, so by checking if the method is implemented before calling it, we can eliminate most of this work.

(Hopefully in future we can get ride of this method altogether, but right now it's integral to the way that text layout is implemented).

Reviewed By: majak, javache

Differential Revision: D2982181

fb-gh-sync-id: 818d0aac61197df89263c919c2c80a003e293ac5
shipit-source-id: 818d0aac61197df89263c919c2c80a003e293ac5
---
 React/Modules/RCTUIManager.m   |  2 +-
 React/Views/RCTComponentData.h |  4 +++-
 React/Views/RCTComponentData.m | 18 +++++++++++++++++-
 3 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m
index 803d139b0205..fdce48583276 100644
--- a/React/Modules/RCTUIManager.m
+++ b/React/Modules/RCTUIManager.m
@@ -963,7 +963,7 @@ - (void)_layoutAndMount
   // Gather blocks to be executed now that all view hierarchy manipulations have
   // been completed (note that these may still take place before layout has finished)
   for (RCTComponentData *componentData in _componentDataByName.allValues) {
-    RCTViewManagerUIBlock uiBlock = [componentData.manager uiBlockToAmendWithShadowViewRegistry:_shadowViewRegistry];
+    RCTViewManagerUIBlock uiBlock = [componentData uiBlockToAmendWithShadowViewRegistry:_shadowViewRegistry];
     [self addUIBlock:uiBlock];
   }
 
diff --git a/React/Views/RCTComponentData.h b/React/Views/RCTComponentData.h
index 38b242602d83..596dcc8399b7 100644
--- a/React/Views/RCTComponentData.h
+++ b/React/Views/RCTComponentData.h
@@ -11,10 +11,10 @@
 
 #import "RCTComponent.h"
 #import "RCTDefines.h"
+#import "RCTViewManager.h"
 
 @class RCTBridge;
 @class RCTShadowView;
-@class RCTViewManager;
 @class UIView;
 
 @interface RCTComponentData : NSObject
@@ -33,4 +33,6 @@
 
 - (NSDictionary<NSString *, id> *)viewConfig;
 
+- (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(NSDictionary<NSNumber *, RCTShadowView *> *)registry;
+
 @end
diff --git a/React/Views/RCTComponentData.m b/React/Views/RCTComponentData.m
index 34f2742a6dd7..d5d34f5f8f8d 100644
--- a/React/Views/RCTComponentData.m
+++ b/React/Views/RCTComponentData.m
@@ -14,7 +14,6 @@
 #import "RCTBridge.h"
 #import "RCTShadowView.h"
 #import "RCTUtils.h"
-#import "RCTViewManager.h"
 #import "UIView+React.h"
 
 typedef void (^RCTPropBlock)(id<RCTComponent> view, id json);
@@ -44,6 +43,7 @@ @implementation RCTComponentData
   RCTShadowView *_defaultShadowView;
   NSMutableDictionary<NSString *, RCTPropBlock> *_viewPropBlocks;
   NSMutableDictionary<NSString *, RCTPropBlock> *_shadowPropBlocks;
+  BOOL _implementsUIBlockToAmendWithShadowViewRegistry;
   __weak RCTBridge *_bridge;
 }
 
@@ -63,6 +63,14 @@ - (instancetype)initWithManagerClass:(Class)managerClass
     if ([_name hasSuffix:@"Manager"]) {
       _name = [_name substringToIndex:_name.length - @"Manager".length];
     }
+
+    _implementsUIBlockToAmendWithShadowViewRegistry = NO;
+    Class cls = _managerClass;
+    while (cls != [RCTViewManager class]) {
+      _implementsUIBlockToAmendWithShadowViewRegistry = _implementsUIBlockToAmendWithShadowViewRegistry ||
+      RCTClassOverridesInstanceMethod(cls, @selector(uiBlockToAmendWithShadowViewRegistry:));
+      cls = [cls superclass];
+    }
   }
   return self;
 }
@@ -412,4 +420,12 @@ - (void)setProps:(NSDictionary<NSString *, id> *)props forShadowView:(RCTShadowV
   };
 }
 
+- (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(NSDictionary<NSNumber *,RCTShadowView *> *)registry
+{
+  if (_implementsUIBlockToAmendWithShadowViewRegistry) {
+    return [[self manager] uiBlockToAmendWithShadowViewRegistry:registry];
+  }
+  return nil;
+}
+
 @end

From 7032a640e7eb661e3be45a494e7311191c329ced Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Fri, 26 Feb 2016 08:19:40 -0800
Subject: [PATCH 1326/1411] Fix WebView example on iOS

Summary: Fixed broken scaling logic in Webview example for iOS. Pages must be reloaded after toggling `scalesPageToFit`, but that wasn't happening.

Reviewed By: javache

Differential Revision: D2982371

fb-gh-sync-id: 8442609179bfe9ade10d1d0bac1807e4a8855d00
shipit-source-id: 8442609179bfe9ade10d1d0bac1807e4a8855d00
---
 Examples/UIExplorer/WebViewExample.js | 20 ++++++++++----------
 React/Views/RCTWebView.h              |  1 +
 React/Views/RCTWebView.m              | 13 +++++++++++++
 React/Views/RCTWebViewManager.m       |  2 +-
 4 files changed, 25 insertions(+), 11 deletions(-)

diff --git a/Examples/UIExplorer/WebViewExample.js b/Examples/UIExplorer/WebViewExample.js
index 6654551ad4eb..1b5f836df601 100644
--- a/Examples/UIExplorer/WebViewExample.js
+++ b/Examples/UIExplorer/WebViewExample.js
@@ -163,7 +163,7 @@ var WebViewExample = React.createClass({
 
 var Button = React.createClass({
   _handlePress: function() {
-    if (this.props.enabled && this.props.onPress) {
+    if (this.props.enabled !== false && this.props.onPress) {
       this.props.onPress();
     }
   },
@@ -182,19 +182,19 @@ var ScaledWebView = React.createClass({
 
   getInitialState: function() {
     return {
-      scalingEnabled: true
+      scalingEnabled: true,
     }
   },
 
   render: function() {
     return (
-      <View style={{height:120}}>
+      <View>
         <WebView
           style={{
             backgroundColor: BGWASH,
-            height: 100,
+            height: 200,
           }}
-          source={{html: HTML}}
+          source={{uri: 'https://facebook.github.io/react/'}}
           scalesPageToFit={this.state.scalingEnabled}
         />
         <View style={styles.buttons}>
@@ -307,7 +307,7 @@ const HTML = `
   <head>
     <title>Hello Static World</title>
     <meta http-equiv="content-type" content="text/html; charset=utf-8">
-    <meta name="viewport" content="width=640, user-scalable=no">
+    <meta name="viewport" content="width=320, user-scalable=no">
     <style type="text/css">
       body {
         margin: 0;
@@ -337,6 +337,10 @@ exports.examples = [
     title: 'Simple Browser',
     render(): ReactElement { return <WebViewExample />; }
   },
+  {
+    title: 'Scale Page to Fit',
+    render(): ReactElement { return <ScaledWebView/>; }
+  },
   {
     title: 'Bundled HTML',
     render(): ReactElement {
@@ -367,10 +371,6 @@ exports.examples = [
       );
     }
   },
-  {
-    title: 'Scale Page to Fit',
-    render(): ReactElement { return <ScaledWebView/>; }
-  },
   {
     title: 'POST Test',
     render(): ReactElement {
diff --git a/React/Views/RCTWebView.h b/React/Views/RCTWebView.h
index 386ce8990cef..05246a09b788 100644
--- a/React/Views/RCTWebView.h
+++ b/React/Views/RCTWebView.h
@@ -35,6 +35,7 @@ shouldStartLoadForRequest:(NSMutableDictionary<NSString *, id> *)request
 @property (nonatomic, assign) UIEdgeInsets contentInset;
 @property (nonatomic, assign) BOOL automaticallyAdjustContentInsets;
 @property (nonatomic, copy) NSString *injectedJavaScript;
+@property (nonatomic, assign) BOOL scalesPageToFit;
 
 - (void)goForward;
 - (void)goBack;
diff --git a/React/Views/RCTWebView.m b/React/Views/RCTWebView.m
index d0e1333330b7..f7240ec97009 100644
--- a/React/Views/RCTWebView.m
+++ b/React/Views/RCTWebView.m
@@ -118,6 +118,19 @@ - (void)setContentInset:(UIEdgeInsets)contentInset
                       updateOffset:NO];
 }
 
+- (void)setScalesPageToFit:(BOOL)scalesPageToFit
+{
+  if (_webView.scalesPageToFit != scalesPageToFit) {
+    _webView.scalesPageToFit = scalesPageToFit;
+    [_webView reload];
+  }
+}
+
+- (BOOL)scalesPageToFit
+{
+  return _webView.scalesPageToFit;
+}
+
 - (void)setBackgroundColor:(UIColor *)backgroundColor
 {
   CGFloat alpha = CGColorGetAlpha(backgroundColor.CGColor);
diff --git a/React/Views/RCTWebViewManager.m b/React/Views/RCTWebViewManager.m
index 33a5d77937fb..d79e5827c54d 100644
--- a/React/Views/RCTWebViewManager.m
+++ b/React/Views/RCTWebViewManager.m
@@ -36,8 +36,8 @@ - (UIView *)view
 RCT_EXPORT_VIEW_PROPERTY(source, NSDictionary)
 RCT_REMAP_VIEW_PROPERTY(bounces, _webView.scrollView.bounces, BOOL)
 RCT_REMAP_VIEW_PROPERTY(scrollEnabled, _webView.scrollView.scrollEnabled, BOOL)
-RCT_REMAP_VIEW_PROPERTY(scalesPageToFit, _webView.scalesPageToFit, BOOL)
 RCT_REMAP_VIEW_PROPERTY(decelerationRate, _webView.scrollView.decelerationRate, CGFloat)
+RCT_EXPORT_VIEW_PROPERTY(scalesPageToFit, BOOL)
 RCT_EXPORT_VIEW_PROPERTY(injectedJavaScript, NSString)
 RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets)
 RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets, BOOL)

From f420f811c5d74148c495ab0d4f7c8f253fec5f67 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Fri, 26 Feb 2016 08:42:25 -0800
Subject: [PATCH 1327/1411] Revert D2982150: Revert D2926896 WebWorkers: Move
 web worker impl to JSCExecutor

Reviewed By: lexs

Differential Revision: D2982364

fb-gh-sync-id: 25f099377acca75298768072d38d77dcb9c1bff3
shipit-source-id: 25f099377acca75298768072d38d77dcb9c1bff3
---
 .../react/bridge/CatalystInstanceImpl.java    |  20 +-
 .../common/futures/SimpleSettableFuture.java  |   2 +-
 ReactAndroid/src/main/jni/react/Android.mk    |   1 -
 ReactAndroid/src/main/jni/react/BUCK          |   2 -
 .../src/main/jni/react/JSCExecutor.cpp        | 184 ++++++++++++++----
 ReactAndroid/src/main/jni/react/JSCExecutor.h |  65 +++++--
 .../src/main/jni/react/JSCWebWorker.cpp       | 153 ---------------
 .../src/main/jni/react/JSCWebWorker.h         |  94 ---------
 .../src/main/jni/react/MessageQueueThread.h   |  20 ++
 9 files changed, 229 insertions(+), 312 deletions(-)
 delete mode 100644 ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
 delete mode 100644 ReactAndroid/src/main/jni/react/JSCWebWorker.h

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
index 0b3476cb92fb..cbf259f29a82 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
@@ -226,24 +226,18 @@ public void destroy() {
         listener.onTransitionToBridgeIdle();
       }
     }
-
-    Systrace.unregisterListener(mTraceListener);
-
-    // We can access the Bridge from any thread now because we know either we are on the JS thread
-    // or the JS thread has finished via ReactQueueConfiguration#destroy()
-    mBridge.dispose();
   }
 
   private void synchronouslyDisposeBridgeOnJSThread() {
     final SimpleSettableFuture<Void> bridgeDisposeFuture = new SimpleSettableFuture<>();
     mReactQueueConfiguration.getJSQueueThread().runOnQueue(
-      new Runnable() {
-        @Override
-        public void run() {
-          mBridge.dispose();
-          bridgeDisposeFuture.set(null);
-        }
-      });
+        new Runnable() {
+          @Override
+          public void run() {
+            mBridge.dispose();
+            bridgeDisposeFuture.set(null);
+          }
+        });
     bridgeDisposeFuture.getOrThrow();
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java b/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java
index 55fc9eb089e2..9caf34cd6231 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/common/futures/SimpleSettableFuture.java
@@ -30,7 +30,7 @@ public class SimpleSettableFuture<T> implements Future<T> {
    * Sets the result. If another thread has called {@link #get}, they will immediately receive the
    * value. set or setException must only be called once.
    */
-  public void set(T result) {
+  public void set(@Nullable T result) {
     checkNotSet();
     mResult = result;
     mReadyLatch.countDown();
diff --git a/ReactAndroid/src/main/jni/react/Android.mk b/ReactAndroid/src/main/jni/react/Android.mk
index cafcb591b878..f72729bdce26 100644
--- a/ReactAndroid/src/main/jni/react/Android.mk
+++ b/ReactAndroid/src/main/jni/react/Android.mk
@@ -8,7 +8,6 @@ LOCAL_SRC_FILES := \
   Bridge.cpp \
   JSCExecutor.cpp \
   JSCHelpers.cpp \
-  JSCWebWorker.cpp \
   MethodCall.cpp \
   Platform.cpp \
   Value.cpp \
diff --git a/ReactAndroid/src/main/jni/react/BUCK b/ReactAndroid/src/main/jni/react/BUCK
index e397d252c8cc..f9ac1edb5f8d 100644
--- a/ReactAndroid/src/main/jni/react/BUCK
+++ b/ReactAndroid/src/main/jni/react/BUCK
@@ -57,7 +57,6 @@ react_library(
     'JSCTracing.cpp',
     'JSCMemory.cpp',
     'JSCLegacyProfiler.cpp',
-    'JSCWebWorker.cpp',
     'Platform.cpp',
   ],
   headers = [
@@ -71,7 +70,6 @@ react_library(
     'Executor.h',
     'JSCExecutor.h',
     'JSCHelpers.h',
-    'JSCWebWorker.h',
     'MessageQueueThread.h',
     'MethodCall.h',
     'JSModulesUnbundle.h',
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index bc91fd10343a..ad9f3c05a762 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -3,7 +3,8 @@
 #include "JSCExecutor.h"
 
 #include <algorithm>
-#include <atomic>
+#include <condition_variable>
+#include <mutex>
 #include <sstream>
 #include <string>
 #include <glog/logging.h>
@@ -90,6 +91,52 @@ JSCExecutor::JSCExecutor(Bridge *bridge, const std::string& cacheDir, const foll
     m_deviceCacheDir(cacheDir),
     m_messageQueueThread(MessageQueues::getCurrentMessageQueueThread()),
     m_jscConfig(jscConfig) {
+  initOnJSVMThread();
+}
+
+JSCExecutor::JSCExecutor(
+    Bridge *bridge,
+    int workerId,
+    JSCExecutor *owner,
+    const std::string& script,
+    const std::unordered_map<std::string, std::string>& globalObjAsJSON,
+    const folly::dynamic& jscConfig) :
+    m_bridge(bridge),
+    m_workerId(workerId),
+    m_owner(owner),
+    m_deviceCacheDir(owner->m_deviceCacheDir),
+    m_messageQueueThread(MessageQueues::getCurrentMessageQueueThread()),
+    m_jscConfig(jscConfig) {
+  // We post initOnJSVMThread here so that the owner doesn't have to wait for
+  // initialization on its own thread
+  m_messageQueueThread->runOnQueue([this, script, globalObjAsJSON] () {
+    initOnJSVMThread();
+
+    installGlobalFunction(m_context, "postMessage", nativePostMessage);
+
+    for (auto& it : globalObjAsJSON) {
+      setGlobalVariable(it.first, it.second);
+    }
+
+    // TODO(9604438): Protect against script does not exist
+    std::string scriptSrc = WebWorkerUtil::loadScriptFromAssets(script);
+    // TODO(9994180): Throw on error
+    loadApplicationScript(scriptSrc, script);
+  });
+}
+
+JSCExecutor::~JSCExecutor() {
+  *m_isDestroyed = true;
+  if (m_messageQueueThread->isOnThread()) {
+    terminateOnJSVMThread();
+  } else {
+    m_messageQueueThread->runOnQueueSync([this] () {
+      terminateOnJSVMThread();
+    });
+  }
+}
+
+void JSCExecutor::initOnJSVMThread() {
   m_context = JSGlobalContextCreateInGroup(nullptr, nullptr);
   s_globalContextRefToJSCExecutor[m_context] = this;
   installGlobalFunction(m_context, "nativeFlushQueueImmediate", nativeFlushQueueImmediate);
@@ -118,18 +165,20 @@ JSCExecutor::JSCExecutor(Bridge *bridge, const std::string& cacheDir, const foll
   #endif
 }
 
-JSCExecutor::~JSCExecutor() {
-  // terminateWebWorker mutates m_webWorkers so collect all the workers to terminate first
+void JSCExecutor::terminateOnJSVMThread() {
+  // terminateOwnedWebWorker mutates m_ownedWorkers so collect all the workers
+  // to terminate first
   std::vector<int> workerIds;
-  for (auto it = m_webWorkers.begin(); it != m_webWorkers.end(); it++) {
-    workerIds.push_back(it->first);
+  for (auto& it : m_ownedWorkers) {
+    workerIds.push_back(it.first);
   }
   for (int workerId : workerIds) {
-    terminateWebWorker(workerId);
+    terminateOwnedWebWorker(workerId);
   }
 
   s_globalContextRefToJSCExecutor.erase(m_context);
   JSGlobalContextRelease(m_context);
+  m_context = nullptr;
 }
 
 void JSCExecutor::loadApplicationScript(
@@ -166,6 +215,10 @@ void JSCExecutor::loadApplicationUnbundle(
 }
 
 void JSCExecutor::flush() {
+  if (m_owner != nullptr) {
+    // Web workers don't support native modules yet
+    return;
+  }
   // TODO: Make this a first class function instead of evaling. #9317773
   std::string calls = executeJSCallWithJSC(m_context, "flushedQueue", std::vector<folly::dynamic>());
   m_bridge->callNativeModules(calls, true);
@@ -257,56 +310,114 @@ void JSCExecutor::loadModule(uint32_t moduleId) {
   evaluateScript(m_context, source, sourceUrl);
 }
 
-// WebWorker impl
+int JSCExecutor::addWebWorker(
+    const std::string& script,
+    JSValueRef workerRef,
+    JSValueRef globalObjRef) {
+  static std::atomic_int nextWorkerId(1);
+  int workerId = nextWorkerId++;
 
-JSGlobalContextRef JSCExecutor::getContext() {
-  return m_context;
+  Object globalObj = Value(m_context, globalObjRef).asObject();
+
+  auto workerMQT = WebWorkerUtil::createWebWorkerThread(workerId, m_messageQueueThread.get());
+  std::unique_ptr<JSCExecutor> worker;
+  workerMQT->runOnQueueSync([this, &worker, &script, &globalObj, workerId] () {
+    worker.reset(new JSCExecutor(m_bridge, workerId, this, script, globalObj.toJSONMap(), m_jscConfig));
+  });
+
+  Object workerObj = Value(m_context, workerRef).asObject();
+  workerObj.makeProtected();
+
+  m_ownedWorkers.emplace(std::piecewise_construct, std::forward_as_tuple(workerId), std::forward_as_tuple(std::move(worker), std::move(workerObj)));
+
+  return workerId;
 }
 
-std::shared_ptr<MessageQueueThread> JSCExecutor::getMessageQueueThread() {
-  return m_messageQueueThread;
+void JSCExecutor::postMessageToOwnedWebWorker(int workerId, JSValueRef message, JSValueRef *exn) {
+  auto worker = m_ownedWorkers.at(workerId).getExecutor();
+  std::string msgString = Value(m_context, message).toJSONString();
+
+  std::shared_ptr<bool> isWorkerDestroyed = worker->m_isDestroyed;
+  worker->m_messageQueueThread->runOnQueue([isWorkerDestroyed, worker, msgString] () {
+    if (*isWorkerDestroyed) {
+      return;
+    }
+    worker->receiveMessageFromOwner(msgString);
+  });
 }
 
-void JSCExecutor::onMessageReceived(int workerId, const std::string& json) {
-  Object& worker = m_webWorkerJSObjs.at(workerId);
+void JSCExecutor::postMessageToOwner(JSValueRef msg) {
+  std::string msgString = Value(m_context, msg).toJSONString();
+  std::shared_ptr<bool> ownerIsDestroyed = m_owner->m_isDestroyed;
+  m_owner->m_messageQueueThread->runOnQueue([workerId=m_workerId, owner=m_owner, ownerIsDestroyed, msgString] () {
+    if (*ownerIsDestroyed) {
+      return;
+    }
+    owner->receiveMessageFromOwnedWebWorker(workerId, msgString);
+  });
+}
 
-  Value onmessageValue = worker.getProperty("onmessage");
+void JSCExecutor::receiveMessageFromOwnedWebWorker(int workerId, const std::string& json) {
+  Object* workerObj;
+  try {
+    workerObj = &m_ownedWorkers.at(workerId).jsObj;
+  } catch (std::out_of_range& e) {
+    // Worker was already terminated
+    return;
+  }
+
+  Value onmessageValue = workerObj->getProperty("onmessage");
   if (onmessageValue.isUndefined()) {
     return;
   }
 
-  JSValueRef args[] = { JSCWebWorker::createMessageObject(m_context, json) };
+  JSValueRef args[] = { createMessageObject(json) };
   onmessageValue.asObject().callAsFunction(1, args);
 
   flush();
 }
 
-int JSCExecutor::addWebWorker(const std::string& script, JSValueRef workerRef) {
-  static std::atomic_int nextWorkerId(0);
-  int workerId = nextWorkerId++;
+void JSCExecutor::receiveMessageFromOwner(const std::string& msgString) {
+  CHECK(m_owner) << "Received message in a Executor that doesn't have an owner!";
 
-  m_webWorkers.emplace(std::piecewise_construct, std::forward_as_tuple(workerId), std::forward_as_tuple(workerId, this, script));
-  Object workerObj = Value(m_context, workerRef).asObject();
-  workerObj.makeProtected();
-  m_webWorkerJSObjs.emplace(workerId, std::move(workerObj));
-  return workerId;
+  JSValueRef args[] = { createMessageObject(msgString) };
+  Value onmessageValue = Object::getGlobalObject(m_context).getProperty("onmessage");
+  onmessageValue.asObject().callAsFunction(1, args);
 }
 
-void JSCExecutor::postMessageToWebWorker(int workerId, JSValueRef message, JSValueRef *exn) {
-  JSCWebWorker& worker = m_webWorkers.at(workerId);
-  worker.postMessage(message);
+void JSCExecutor::terminateOwnedWebWorker(int workerId) {
+  auto worker = m_ownedWorkers.at(workerId).getExecutor();
+  std::shared_ptr<MessageQueueThread> workerMQT = worker->m_messageQueueThread;
+  m_ownedWorkers.erase(workerId);
+  workerMQT->quitSynchronous();
 }
 
-void JSCExecutor::terminateWebWorker(int workerId) {
-  JSCWebWorker& worker = m_webWorkers.at(workerId);
-
-  worker.terminate();
-
-  m_webWorkers.erase(workerId);
-  m_webWorkerJSObjs.erase(workerId);
+Object JSCExecutor::createMessageObject(const std::string& msgJson) {
+  Value rebornJSMsg = Value::fromJSON(m_context, String(msgJson.c_str()));
+  Object messageObject = Object::create(m_context);
+  messageObject.setProperty("data", rebornJSMsg);
+  return messageObject;
 }
 
 // Native JS hooks
+JSValueRef JSCExecutor::nativePostMessage(
+    JSContextRef ctx,
+    JSObjectRef function,
+    JSObjectRef thisObject,
+    size_t argumentCount,
+    const JSValueRef arguments[],
+    JSValueRef *exception) {
+  if (argumentCount != 1) {
+    *exception = makeJSCException(ctx, "postMessage got wrong number of arguments");
+    return JSValueMakeUndefined(ctx);
+  }
+  JSValueRef msg = arguments[0];
+  JSCExecutor *webWorker = s_globalContextRefToJSCExecutor.at(JSContextGetGlobalContext(ctx));
+
+  webWorker->postMessageToOwner(msg);
+
+  return JSValueMakeUndefined(ctx);
+}
 
 static JSValueRef makeInvalidModuleIdJSCException(
     JSContextRef ctx,
@@ -397,6 +508,7 @@ JSValueRef JSCExecutor::nativeStartWorker(
   std::string scriptFile = Value(ctx, arguments[0]).toString().str();
 
   JSValueRef worker = arguments[1];
+  JSValueRef globalObj = arguments[2];
 
   JSCExecutor *executor;
   try {
@@ -406,7 +518,7 @@ JSValueRef JSCExecutor::nativeStartWorker(
     return JSValueMakeUndefined(ctx);
   }
 
-  int workerId = executor->addWebWorker(scriptFile, worker);
+  int workerId = executor->addWebWorker(scriptFile, worker, globalObj);
 
   return JSValueMakeNumber(ctx, workerId);
 }
@@ -437,7 +549,7 @@ JSValueRef JSCExecutor::nativePostMessageToWorker(
     return JSValueMakeUndefined(ctx);
   }
 
-  executor->postMessageToWebWorker((int) workerDouble, arguments[1], exception);
+  executor->postMessageToOwnedWebWorker((int) workerDouble, arguments[1], exception);
 
   return JSValueMakeUndefined(ctx);
 }
@@ -468,7 +580,7 @@ JSValueRef JSCExecutor::nativeTerminateWorker(
     return JSValueMakeUndefined(ctx);
   }
 
-  executor->terminateWebWorker((int) workerDouble);
+  executor->terminateOwnedWebWorker((int) workerDouble);
 
   return JSValueMakeUndefined(ctx);
 }
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.h b/ReactAndroid/src/main/jni/react/JSCExecutor.h
index 3084a7195ec6..33622014458b 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.h
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.h
@@ -7,9 +7,10 @@
 #include <unordered_map>
 #include <folly/json.h>
 #include <JavaScriptCore/JSContextRef.h>
+
 #include "Executor.h"
 #include "JSCHelpers.h"
-#include "JSCWebWorker.h"
+#include "Value.h"
 
 namespace facebook {
 namespace react {
@@ -27,10 +28,26 @@ class JSCExecutorFactory : public JSExecutorFactory {
   folly::dynamic m_jscConfig;
 };
 
-class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
+class JSCExecutor;
+class WorkerRegistration : public noncopyable {
+public:
+  explicit WorkerRegistration(std::unique_ptr<JSCExecutor> executor, Object jsObj) :
+      jsObj(std::move(jsObj)),
+      executor(std::move(executor)) {}
+
+  JSCExecutor* getExecutor() {
+    return executor.get();
+  }
+
+  Object jsObj;
+private:
+  std::unique_ptr<JSCExecutor> executor;
+};
+
+class JSCExecutor : public JSExecutor {
 public:
   /**
-   * Should be invoked from the JS thread.
+   * Must be invoked from thread this Executor will run on.
    */
   explicit JSCExecutor(Bridge *bridge, const std::string& cacheDir, const folly::dynamic& jscConfig);
   ~JSCExecutor() override;
@@ -60,26 +77,43 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
   virtual void handleMemoryPressureCritical() override;
 
   void installNativeHook(const char *name, JSObjectCallAsFunctionCallback callback);
-  virtual void onMessageReceived(int workerId, const std::string& message) override;
-  virtual JSGlobalContextRef getContext() override;
-  virtual std::shared_ptr<MessageQueueThread> getMessageQueueThread() override;
 
 private:
   JSGlobalContextRef m_context;
-  std::unordered_map<int, JSCWebWorker> m_webWorkers;
-  std::unordered_map<int, Object> m_webWorkerJSObjs;
   Bridge *m_bridge;
+  int m_workerId = 0; // if this is a worker executor, this is non-zero
+  JSCExecutor *m_owner = nullptr; // if this is a worker executor, this is non-null
+  std::shared_ptr<bool> m_isDestroyed = std::shared_ptr<bool>(new bool(false));
+  std::unordered_map<int, WorkerRegistration> m_ownedWorkers;
   std::string m_deviceCacheDir;
   std::shared_ptr<MessageQueueThread> m_messageQueueThread;
   std::unique_ptr<JSModulesUnbundle> m_unbundle;
   folly::dynamic m_jscConfig;
 
-  int addWebWorker(const std::string& script, JSValueRef workerRef);
-  void postMessageToWebWorker(int worker, JSValueRef message, JSValueRef *exn);
+  /**
+   * WebWorker constructor. Must be invoked from thread this Executor will run on.
+   */
+  explicit JSCExecutor(
+      Bridge *bridge,
+      int workerId,
+      JSCExecutor *owner,
+      const std::string& script,
+      const std::unordered_map<std::string, std::string>& globalObjAsJSON,
+      const folly::dynamic& jscConfig);
+
+  void initOnJSVMThread();
+  void terminateOnJSVMThread();
   void flush();
-  void terminateWebWorker(int worker);
-  void loadModule(uint32_t moduleId);
   void flushQueueImmediate(std::string queueJSON);
+  void loadModule(uint32_t moduleId);
+
+  int addWebWorker(const std::string& script, JSValueRef workerRef, JSValueRef globalObjRef);
+  void postMessageToOwnedWebWorker(int worker, JSValueRef message, JSValueRef *exn);
+  void postMessageToOwner(JSValueRef result);
+  void receiveMessageFromOwnedWebWorker(int workerId, const std::string& message);
+  void receiveMessageFromOwner(const std::string &msgString);
+  void terminateOwnedWebWorker(int worker);
+  Object createMessageObject(const std::string& msgData);
 
   static JSValueRef nativeStartWorker(
       JSContextRef ctx,
@@ -102,6 +136,13 @@ class JSCExecutor : public JSExecutor, public JSCWebWorkerOwner {
       size_t argumentCount,
       const JSValueRef arguments[],
       JSValueRef *exception);
+  static JSValueRef nativePostMessage(
+      JSContextRef ctx,
+      JSObjectRef function,
+      JSObjectRef thisObject,
+      size_t argumentCount,
+      const JSValueRef arguments[],
+      JSValueRef *exception);
   static JSValueRef nativeRequire(
       JSContextRef ctx,
       JSObjectRef function,
diff --git a/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp b/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
deleted file mode 100644
index e8e710bdf393..000000000000
--- a/ReactAndroid/src/main/jni/react/JSCWebWorker.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-#include "JSCWebWorker.h"
-
-#include <unistd.h>
-#include <condition_variable>
-#include <mutex>
-#include <unordered_map>
-
-#include <glog/logging.h>
-#include <folly/Memory.h>
-
-#include "JSCHelpers.h"
-#include "MessageQueueThread.h"
-#include "Platform.h"
-#include "Value.h"
-
-#include <JavaScriptCore/JSValueRef.h>
-
-namespace facebook {
-namespace react {
-
-// TODO(9604425): thread safety
-static std::unordered_map<JSContextRef, JSCWebWorker*> s_globalContextRefToJSCWebWorker;
-
-JSCWebWorker::JSCWebWorker(int id, JSCWebWorkerOwner *owner, std::string scriptSrc) :
-    id_(id),
-    scriptName_(std::move(scriptSrc)),
-    owner_(owner) {
-  ownerMessageQueueThread_ = owner->getMessageQueueThread();
-  CHECK(ownerMessageQueueThread_) << "Owner MessageQueue must not be null";
-  workerMessageQueueThread_ = WebWorkerUtil::createWebWorkerThread(id, ownerMessageQueueThread_.get());
-  CHECK(workerMessageQueueThread_) << "Failed to create worker thread";
-
-  workerMessageQueueThread_->runOnQueue([this] () {
-    initJSVMAndLoadScript();
-  });
-}
-
-
-JSCWebWorker::~JSCWebWorker() {
-  CHECK(isTerminated()) << "Didn't terminate the web worker before releasing it!";;
-}
-
-void JSCWebWorker::postMessage(JSValueRef msg) {
-  std::string msgString = Value(owner_->getContext(), msg).toJSONString();
-
-  workerMessageQueueThread_->runOnQueue([this, msgString] () {
-    if (isTerminated()) {
-      return;
-    }
-
-    JSValueRef args[] = { createMessageObject(context_, msgString) };
-    Value onmessageValue = Object::getGlobalObject(context_).getProperty("onmessage");
-    onmessageValue.asObject().callAsFunction(1, args);
-  });
-}
-
-void JSCWebWorker::terminate() {
-  if (isTerminated()) {
-    return;
-  }
-  isTerminated_.store(true, std::memory_order_release);
-
-  if (workerMessageQueueThread_->isOnThread()) {
-    terminateOnWorkerThread();
-  } else {
-    std::mutex signalMutex;
-    std::condition_variable signalCv;
-    bool terminationComplete = false;
-
-    workerMessageQueueThread_->runOnQueue([&] () mutable {
-      std::lock_guard<std::mutex> lock(signalMutex);
-
-      terminateOnWorkerThread();
-      terminationComplete = true;
-
-      signalCv.notify_one();
-    });
-
-    std::unique_lock<std::mutex> lock(signalMutex);
-    signalCv.wait(lock, [&terminationComplete] { return terminationComplete; });
-  }
-}
-
-void JSCWebWorker::terminateOnWorkerThread() {
-  s_globalContextRefToJSCWebWorker.erase(context_);
-  JSGlobalContextRelease(context_);
-  context_ = nullptr;
-  workerMessageQueueThread_->quitSynchronous();
-}
-
-bool JSCWebWorker::isTerminated() {
-  return isTerminated_.load(std::memory_order_acquire);
-}
-
-void JSCWebWorker::initJSVMAndLoadScript() {
-  CHECK(!isTerminated()) << "Worker was already finished!";
-  CHECK(!context_) << "Worker JS VM was already created!";
-
-  context_ = JSGlobalContextCreateInGroup(
-      NULL, // use default JS 'global' object
-      NULL // create new group (i.e. new VM)
-  );
-  s_globalContextRefToJSCWebWorker[context_] = this;
-
-  // TODO(9604438): Protect against script does not exist
-  std::string script = WebWorkerUtil::loadScriptFromAssets(scriptName_);
-  evaluateScript(context_, String(script.c_str()), String(scriptName_.c_str()));
-
-  installGlobalFunction(context_, "postMessage", nativePostMessage);
-}
-
-void JSCWebWorker::postMessageToOwner(JSValueRef msg) {
-  std::string msgString = Value(context_, msg).toJSONString();
-  ownerMessageQueueThread_->runOnQueue([this, msgString] () {
-      owner_->onMessageReceived(id_, msgString);
-  });
-}
-
-JSValueRef JSCWebWorker::nativePostMessage(
-    JSContextRef ctx,
-    JSObjectRef function,
-    JSObjectRef thisObject,
-    size_t argumentCount,
-    const JSValueRef arguments[],
-    JSValueRef *exception) {
-  if (argumentCount != 1) {
-    *exception = makeJSCException(ctx, "postMessage got wrong number of arguments");
-    return JSValueMakeUndefined(ctx);
-  }
-  JSValueRef msg = arguments[0];
-  JSCWebWorker *webWorker = s_globalContextRefToJSCWebWorker.at(JSContextGetGlobalContext(ctx));
-
-  if (webWorker->isTerminated()) {
-    return JSValueMakeUndefined(ctx);
-  }
-
-  webWorker->postMessageToOwner(msg);
-  
-  return JSValueMakeUndefined(ctx);
-}
-
-/*static*/
-Object JSCWebWorker::createMessageObject(JSContextRef context, const std::string& msgJson) {
-  Value rebornJSMsg = Value::fromJSON(context, String(msgJson.c_str()));
-  Object messageObject = Object::create(context);
-  messageObject.setProperty("data", rebornJSMsg);
-  return std::move(messageObject);
-}
-
-}
-}
diff --git a/ReactAndroid/src/main/jni/react/JSCWebWorker.h b/ReactAndroid/src/main/jni/react/JSCWebWorker.h
deleted file mode 100644
index 73d983cdfe7b..000000000000
--- a/ReactAndroid/src/main/jni/react/JSCWebWorker.h
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-#include <atomic>
-#include <functional>
-#include <mutex>
-#include <string>
-#include <thread>
-#include <queue>
-
-#include <JavaScriptCore/JSValueRef.h>
-
-#include "Value.h"
-
-namespace facebook {
-namespace react {
-
-class MessageQueueThread;
-
-/**
- * A class that can own the lifecycle, receive messages from, and dispatch messages
- * to JSCWebWorkers.
- */
-class JSCWebWorkerOwner {
-public:
-  /**
-   * Called when a worker has posted a message with `postMessage`.
-   */
-  virtual void onMessageReceived(int workerId, const std::string& message) = 0;
-  virtual JSGlobalContextRef getContext() = 0;
-
-  /**
-   * Should return the owner's MessageQueueThread. Calls to onMessageReceived will be enqueued
-   * on this thread.
-   */
-  virtual std::shared_ptr<MessageQueueThread> getMessageQueueThread() = 0;
-};
-
-/**
- * Implementation of a web worker for JSC. The web worker should be created from the owner's
- * (e.g., owning JSCExecutor instance) JS MessageQueueThread. The worker is responsible for
- * creating its own MessageQueueThread.
- *
- * During operation, the JSCExecutor should call postMessage **from its own MessageQueueThread**
- * to send messages to the worker. The worker will handle enqueueing those messages on its own
- * MessageQueueThread as appropriate. When the worker has a message to post to the owner, it will
- * enqueue a call to owner->onMessageReceived on the owner's MessageQueueThread.
- */
-class JSCWebWorker {
-public:
-  explicit JSCWebWorker(int id, JSCWebWorkerOwner *owner, std::string script);
-  ~JSCWebWorker();
-
-  /**
-   * Post a message to be received by the worker on its thread. This must be called from 
-   * ownerMessageQueueThread_.
-   */
-  void postMessage(JSValueRef msg);
-
-  /**
-   * Synchronously quits the current worker and cleans up its VM.
-   */
-  void terminate();
-
-  /**
-   * Whether terminate() has been called on this worker.
-   */
-  bool isTerminated();
-
-  static Object createMessageObject(JSContextRef context, const std::string& msgData);
-private:
-  void initJSVMAndLoadScript();
-  void postRunnableToEventLoop(std::function<void()>&& runnable);
-  void postMessageToOwner(JSValueRef result);
-  void terminateOnWorkerThread();
-
-  int id_;
-  std::atomic_bool isTerminated_ = ATOMIC_VAR_INIT(false);
-  std::string scriptName_;
-  JSCWebWorkerOwner *owner_ = nullptr;
-  std::shared_ptr<MessageQueueThread> ownerMessageQueueThread_;
-  std::unique_ptr<MessageQueueThread> workerMessageQueueThread_;
-  JSGlobalContextRef context_ = nullptr;
-
-  static JSValueRef nativePostMessage(
-      JSContextRef ctx,
-      JSObjectRef function,
-      JSObjectRef thisObject,
-      size_t argumentCount,
-      const JSValueRef arguments[],
-      JSValueRef *exception);
-};
-
-}
-}
diff --git a/ReactAndroid/src/main/jni/react/MessageQueueThread.h b/ReactAndroid/src/main/jni/react/MessageQueueThread.h
index 544b91142be9..f6352ab0d90a 100644
--- a/ReactAndroid/src/main/jni/react/MessageQueueThread.h
+++ b/ReactAndroid/src/main/jni/react/MessageQueueThread.h
@@ -2,7 +2,9 @@
 
 #pragma once
 
+#include <condition_variable>
 #include <functional>
+#include <mutex>
 
 namespace facebook {
 namespace react {
@@ -14,6 +16,24 @@ class MessageQueueThread {
   virtual bool isOnThread() = 0;
   // quitSynchronous() should synchronously ensure that no further tasks will run on the queue.
   virtual void quitSynchronous() = 0;
+
+  void runOnQueueSync(std::function<void()>&& runnable) {
+    std::mutex signalMutex;
+    std::condition_variable signalCv;
+    bool runnableComplete = false;
+
+    runOnQueue([&] () mutable {
+      std::lock_guard<std::mutex> lock(signalMutex);
+
+      runnable();
+      runnableComplete = true;
+
+      signalCv.notify_one();
+    });
+
+    std::unique_lock<std::mutex> lock(signalMutex);
+    signalCv.wait(lock, [&runnableComplete] { return runnableComplete; });
+  }
 };
 
 }}

From 20588a6bf869ae06e690c76fe8978f198d009505 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Fri, 26 Feb 2016 08:51:28 -0800
Subject: [PATCH 1328/1411] Log HMR events

Summary:We've received reports saying that sometimes HRM updates take a couple of seconds to get applied. The feature is very optimized so that it takes around 100ms for most common type of changes. Only changes that require rebuilding caches could take longer than that, maybe up to 1 second.

We think the problem is that watchman delays sending the file change notification because the system is under heavy use. It worth mentioning this is not a watchman issue!. This could happen for instance if flow is enabled. So, to better understand what's going on lets log when a file is changed and just before sending the HMR update to the client. The client codepath is extremelly fast so no need to log any of that.

Reviewed By: davidaurelio

Differential Revision: D2978694

fb-gh-sync-id: abd3b473d0b7ac7cd4461effce9813ccfda32c2b
shipit-source-id: abd3b473d0b7ac7cd4461effce9813ccfda32c2b
---
 local-cli/server/util/attachHMRServer.js | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js
index 54f510fd71ee..f461141426ae 100644
--- a/local-cli/server/util/attachHMRServer.js
+++ b/local-cli/server/util/attachHMRServer.js
@@ -111,6 +111,9 @@ function attachHMRServer({httpServer, path, packagerServer}) {
           if (!client) {
             return;
           }
+          console.log(
+            `[Hot Module Replacement] File change detected (${time()})`
+          );
 
           client.ws.send(JSON.stringify({type: 'update-start'}));
           stat.then(() => {
@@ -230,6 +233,10 @@ function attachHMRServer({httpServer, path, packagerServer}) {
                   return;
                 }
 
+                console.log(
+                  '[Hot Module Replacement] Sending HMR update to client (' +
+                  time() + ')'
+                );
                 client.ws.send(update);
               });
             },
@@ -263,4 +270,9 @@ function arrayEquals(arrayA, arrayB) {
   );
 }
 
+function time() {
+  const date = new Date();
+  return `${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}:${date.getMilliseconds()}`;
+}
+
 module.exports = attachHMRServer;

From b2b41da37f70c2b0da381ad86a701443f13b27f4 Mon Sep 17 00:00:00 2001
From: Adam Miskiewicz <adam@sk3vy.com>
Date: Fri, 26 Feb 2016 09:14:18 -0800
Subject: [PATCH 1329/1411] Don't hardcode 'localhost:8081' as the _hmrURL in
 the Bundler

Summary:martinbigio this fixes your TODO. :rocket: :rocket: :rocket:
Closes https://github.com/facebook/react-native/pull/5827

Differential Revision: D2932188

Pulled By: martinbigio

fb-gh-sync-id: 8c8caf0782f05b51c90c8d09fdb743ddd3e6f97e
shipit-source-id: 8c8caf0782f05b51c90c8d09fdb743ddd3e6f97e
---
 local-cli/server/util/attachHMRServer.js     | 14 +++++++++++++-
 packager/react-packager/src/Bundler/index.js |  8 ++++----
 packager/react-packager/src/Server/index.js  |  4 ++--
 3 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js
index f461141426ae..e0495e3d7006 100644
--- a/local-cli/server/util/attachHMRServer.js
+++ b/local-cli/server/util/attachHMRServer.js
@@ -185,11 +185,23 @@ function attachHMRServer({httpServer, path, packagerServer}) {
                   return;
                 }
 
+                const httpServerAddress = httpServer.address();
+
+                // Sanitize the value from the HTTP server
+                let packagerHost = 'localhost';
+                if (httpServer.address().address &&
+                    httpServer.address().address !== '::' &&
+                    httpServer.address().address !== '') {
+                  packagerHost = httpServerAddress.address;
+                }
+
+                let packagerPort = httpServerAddress.port;
+
                 return packagerServer.buildBundleForHMR({
                   entryFile: client.bundleEntry,
                   platform: client.platform,
                   resolutionResponse,
-                });
+                }, packagerHost, packagerPort);
               })
               .then(bundle => {
                 if (!client || !bundle || bundle.isEmpty()) {
diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js
index 22696cf59088..9da681d6586c 100644
--- a/packager/react-packager/src/Bundler/index.js
+++ b/packager/react-packager/src/Bundler/index.js
@@ -168,9 +168,9 @@ class Bundler {
     });
   }
 
-  _sourceHMRURL(platform, path) {
+  _sourceHMRURL(platform, host, port, path) {
     return this._hmrURL(
-      'http://localhost:8081', // TODO: (martinb) avoid hardcoding
+      `http://${host}:${port}`,
       platform,
       'bundle',
       path,
@@ -211,10 +211,10 @@ class Bundler {
     );
   }
 
-  hmrBundle(options) {
+  hmrBundle(options, host, port) {
     return this._bundle({
       bundle: new HMRBundle({
-        sourceURLFn: this._sourceHMRURL.bind(this, options.platform),
+        sourceURLFn: this._sourceHMRURL.bind(this, options.platform, host, port),
         sourceMappingURLFn: this._sourceMappingHMRURL.bind(
           this,
           options.platform,
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index 7db64bf749e0..5949bd0c72f2 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -240,8 +240,8 @@ class Server {
     return this.buildBundle(options);
   }
 
-  buildBundleForHMR(modules) {
-    return this._bundler.hmrBundle(modules);
+  buildBundleForHMR(modules, host, port) {
+    return this._bundler.hmrBundle(modules, host, port);
   }
 
   getShallowDependencies(entryFile) {

From 4b98511a3e10bf1fe4ddc210d393849bfe608c47 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Fri, 26 Feb 2016 09:35:58 -0800
Subject: [PATCH 1330/1411] Remove gating code for HMR on iOS

Reviewed By: javache

Differential Revision: D2977197

fb-gh-sync-id: 001447ad0b0275f5de6f6454aa8cd0b1c34ce3d8
shipit-source-id: 001447ad0b0275f5de6f6454aa8cd0b1c34ce3d8
---
 React/Base/RCTBridgeDelegate.h | 6 ------
 React/Modules/RCTDevMenu.m     | 4 +---
 2 files changed, 1 insertion(+), 9 deletions(-)

diff --git a/React/Base/RCTBridgeDelegate.h b/React/Base/RCTBridgeDelegate.h
index e29dc64a6e96..d8606c8d953a 100644
--- a/React/Base/RCTBridgeDelegate.h
+++ b/React/Base/RCTBridgeDelegate.h
@@ -47,10 +47,4 @@ typedef void (^RCTSourceLoadBlock)(NSError *error, NSData *source);
 - (void)loadSourceForBridge:(RCTBridge *)bridge
                   withBlock:(RCTSourceLoadBlock)loadCallback;
 
-/**
- * Indicates whether Hot Loading is supported or not.
- * Note: this method will be removed soon, once Hot Loading is supported on OSS.
- */
-- (BOOL)bridgeSupportsHotLoading:(RCTBridge *)bridge;
-
 @end
diff --git a/React/Modules/RCTDevMenu.m b/React/Modules/RCTDevMenu.m
index 30f3eff94205..9e84ab01df87 100644
--- a/React/Modules/RCTDevMenu.m
+++ b/React/Modules/RCTDevMenu.m
@@ -581,9 +581,7 @@ - (void)setLiveReloadEnabled:(BOOL)enabled
 
 - (BOOL)hotLoadingAvailable
 {
-  return !_bridge.bundleURL.fileURL // Only works when running from server
-  && [_bridge.delegate respondsToSelector:@selector(bridgeSupportsHotLoading:)]
-  && [_bridge.delegate bridgeSupportsHotLoading:_bridge];
+  return !_bridge.bundleURL.fileURL; // Only works when running from server
 }
 
 - (void)setHotLoadingEnabled:(BOOL)enabled

From f99579adaa1d312ba0ee4a71badba84e57f197e6 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Fri, 26 Feb 2016 10:57:55 -0800
Subject: [PATCH 1331/1411] Try/catch exceptions in JSCExecutor for debugging
 crash

Reviewed By: lexs

Differential Revision: D2982534

fb-gh-sync-id: 4eda4116cd60e2e46771ecddefc1d27eee761762
shipit-source-id: 4eda4116cd60e2e46771ecddefc1d27eee761762
---
 ReactAndroid/src/main/jni/react/JSCExecutor.cpp | 16 ++++++++++------
 ReactAndroid/src/main/jni/react/Platform.cpp    |  8 ++++++--
 ReactAndroid/src/main/jni/react/Platform.h      |  9 +++++++--
 ReactAndroid/src/main/jni/react/jni/OnLoad.cpp  |  3 +++
 4 files changed, 26 insertions(+), 10 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index ad9f3c05a762..56af90b9bfdd 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -126,13 +126,17 @@ JSCExecutor::JSCExecutor(
 }
 
 JSCExecutor::~JSCExecutor() {
-  *m_isDestroyed = true;
-  if (m_messageQueueThread->isOnThread()) {
-    terminateOnJSVMThread();
-  } else {
-    m_messageQueueThread->runOnQueueSync([this] () {
+  try {
+    *m_isDestroyed = true;
+    if (m_messageQueueThread->isOnThread()) {
       terminateOnJSVMThread();
-    });
+    } else {
+      m_messageQueueThread->runOnQueueSync([this] () {
+        terminateOnJSVMThread();
+      });
+    }
+  } catch (...) {
+    Exceptions::handleUncaughtException();
   }
 }
 
diff --git a/ReactAndroid/src/main/jni/react/Platform.cpp b/ReactAndroid/src/main/jni/react/Platform.cpp
index 03edca72c635..3e1c700b78b5 100644
--- a/ReactAndroid/src/main/jni/react/Platform.cpp
+++ b/ReactAndroid/src/main/jni/react/Platform.cpp
@@ -20,10 +20,14 @@ LoadScriptFromAssets loadScriptFromAssets;
 
 namespace PerfLogging {
 InstallNativeHooks installNativeHooks;
-}
+};
 
 namespace JSLogging {
 JSCNativeHook nativeHook = nullptr;
-}
+};
+
+namespace Exceptions {
+HandleUncaughtException handleUncaughtException;
+};
 
 } }
diff --git a/ReactAndroid/src/main/jni/react/Platform.h b/ReactAndroid/src/main/jni/react/Platform.h
index c5c1c5043b04..5ad664dbfe5e 100644
--- a/ReactAndroid/src/main/jni/react/Platform.h
+++ b/ReactAndroid/src/main/jni/react/Platform.h
@@ -34,7 +34,7 @@ extern LoadScriptFromAssets loadScriptFromAssets;
 namespace PerfLogging {
 using InstallNativeHooks = std::function<void(JSGlobalContextRef)>;
 extern InstallNativeHooks installNativeHooks;
-}
+};
 
 namespace JSLogging {
   using JSCNativeHook = JSValueRef (*) (
@@ -44,6 +44,11 @@ namespace JSLogging {
       size_t argumentCount,
       const JSValueRef arguments[], JSValueRef *exception);
   extern JSCNativeHook nativeHook;
-}
+};
+
+namespace Exceptions {
+  using HandleUncaughtException = std::function<void()>;
+  extern HandleUncaughtException handleUncaughtException;
+};
 
 } }
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index 5081bd67f90e..fad41e7cc598 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -865,6 +865,9 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
         return std::unique_ptr<MessageQueueThread>(
             JMessageQueueThread::currentMessageQueueThread().release());
       };
+    Exceptions::handleUncaughtException = [] () {
+      translatePendingCppExceptionToJavaException();
+    };
     PerfLogging::installNativeHooks = addNativePerfLoggingHooks;
     JSLogging::nativeHook = nativeLoggingHook;
 

From 738337815dd17c92083d1d752674f337f5366a43 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Fri, 26 Feb 2016 11:41:18 -0800
Subject: [PATCH 1332/1411] Fixed issue with opaque thumbnails being given an
 alpha channel

Summary:Images cropped using the ImageEditor were always given an alpha channel, even if opaque.

This causes them to be saved as PNGs instead of JPEGs (increasing memory and bridge traffic) and also causes unnecessary blending when they are drawn.

Reviewed By: fkgozali

Differential Revision: D2982682

fb-gh-sync-id: b65f361efd78e35f259836111b38d914bae49847
shipit-source-id: b65f361efd78e35f259836111b38d914bae49847
---
 Libraries/Image/RCTImageUtils.m | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/Libraries/Image/RCTImageUtils.m b/Libraries/Image/RCTImageUtils.m
index edc1cb926c16..5aeefad1247d 100644
--- a/Libraries/Image/RCTImageUtils.m
+++ b/Libraries/Image/RCTImageUtils.m
@@ -316,7 +316,8 @@ BOOL RCTUpscalingRequired(CGSize sourceSize, CGFloat sourceScale,
     return nil;
   }
 
-  UIGraphicsBeginImageContextWithOptions(destSize, NO, destScale);
+  BOOL opaque = !RCTImageHasAlpha(image.CGImage);
+  UIGraphicsBeginImageContextWithOptions(destSize, opaque, destScale);
   CGContextRef currentContext = UIGraphicsGetCurrentContext();
   CGContextConcatCTM(currentContext, transform);
   [image drawAtPoint:CGPointZero];

From d7cee3a5f94a4fa50912e8e57992cc36c3697871 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Fri, 26 Feb 2016 15:14:44 -0800
Subject: [PATCH 1333/1411] bump node-haste to 2.4.0

Reviewed By: sam-swarr

Differential Revision: D2982427

fb-gh-sync-id: 3a78f6e10c6af8eb92a711dd59760215c3f21b14
shipit-source-id: 3a78f6e10c6af8eb92a711dd59760215c3f21b14
---
 npm-shrinkwrap.json | 142 ++++++++++++++++++++++----------------------
 package.json        |   2 +-
 2 files changed, 72 insertions(+), 72 deletions(-)

diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index 22c60ec9bc89..4cf8daa434b8 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -137,6 +137,11 @@
           "from": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz",
           "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
         },
+        "regenerator": {
+          "version": "0.8.40",
+          "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
+          "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
+        },
         "js-tokens": {
           "version": "1.0.1",
           "from": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz",
@@ -146,11 +151,6 @@
           "version": "0.10.33",
           "from": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz",
           "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
-        },
-        "regenerator": {
-          "version": "0.8.40",
-          "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
-          "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
         }
       }
     },
@@ -248,15 +248,15 @@
           "from": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz",
           "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
         },
-        "regenerator": {
-          "version": "0.8.40",
-          "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
-          "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
-        },
         "source-map": {
           "version": "0.5.3",
           "from": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz"
+        },
+        "regenerator": {
+          "version": "0.8.40",
+          "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
+          "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
         }
       }
     },
@@ -1905,26 +1905,26 @@
           "from": "ansi@~0.3.0",
           "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.0.tgz"
         },
-        "ansi-regex": {
-          "version": "2.0.0",
-          "from": "ansi-regex@^2.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
-        },
         "ansi-styles": {
           "version": "2.1.0",
           "from": "ansi-styles@^2.1.0",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz"
         },
-        "are-we-there-yet": {
-          "version": "1.0.4",
-          "from": "are-we-there-yet@~1.0.0",
-          "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.4.tgz"
-        },
         "asn1": {
           "version": "0.1.11",
           "from": "asn1@0.1.11",
           "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
         },
+        "ansi-regex": {
+          "version": "2.0.0",
+          "from": "ansi-regex@^2.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
+        },
+        "are-we-there-yet": {
+          "version": "1.0.4",
+          "from": "are-we-there-yet@~1.0.0",
+          "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.4.tgz"
+        },
         "assert-plus": {
           "version": "0.1.5",
           "from": "assert-plus@^0.1.5",
@@ -1945,31 +1945,31 @@
           "from": "balanced-match@>=0.2.0 <0.3.0",
           "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.1.tgz"
         },
-        "block-stream": {
-          "version": "0.0.8",
-          "from": "block-stream@*",
-          "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.8.tgz"
-        },
         "boom": {
           "version": "2.10.1",
           "from": "boom@^2.8.x",
           "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz"
         },
+        "block-stream": {
+          "version": "0.0.8",
+          "from": "block-stream@*",
+          "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.8.tgz"
+        },
         "brace-expansion": {
           "version": "1.1.1",
           "from": "brace-expansion@>=1.0.0 <2.0.0",
           "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz"
         },
-        "caseless": {
-          "version": "0.11.0",
-          "from": "caseless@~0.11.0",
-          "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
-        },
         "chalk": {
           "version": "1.1.1",
           "from": "chalk@^1.1.1",
           "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz"
         },
+        "caseless": {
+          "version": "0.11.0",
+          "from": "caseless@~0.11.0",
+          "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
+        },
         "combined-stream": {
           "version": "1.0.5",
           "from": "combined-stream@~1.0.5",
@@ -2000,16 +2000,16 @@
           "from": "ctype@0.5.3",
           "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz"
         },
-        "debug": {
-          "version": "0.7.4",
-          "from": "debug@~0.7.2",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz"
-        },
         "deep-extend": {
           "version": "0.2.11",
           "from": "deep-extend@~0.2.5",
           "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.2.11.tgz"
         },
+        "debug": {
+          "version": "0.7.4",
+          "from": "debug@~0.7.2",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz"
+        },
         "delayed-stream": {
           "version": "1.0.0",
           "from": "delayed-stream@~1.0.0",
@@ -2120,16 +2120,16 @@
           "from": "is-property@^1.0.0",
           "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz"
         },
-        "isarray": {
-          "version": "0.0.1",
-          "from": "isarray@0.0.1",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
-        },
         "isstream": {
           "version": "0.1.2",
           "from": "isstream@~0.1.2",
           "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
         },
+        "isarray": {
+          "version": "0.0.1",
+          "from": "isarray@0.0.1",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
+        },
         "json-stringify-safe": {
           "version": "5.0.1",
           "from": "json-stringify-safe@~5.0.1",
@@ -2140,51 +2140,51 @@
           "from": "jsonpointer@2.0.0",
           "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
         },
-        "lodash._basetostring": {
-          "version": "3.0.1",
-          "from": "lodash._basetostring@^3.0.0",
-          "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz"
-        },
         "lodash._createpadding": {
           "version": "3.6.1",
           "from": "lodash._createpadding@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash._createpadding/-/lodash._createpadding-3.6.1.tgz"
         },
-        "lodash.pad": {
-          "version": "3.1.1",
-          "from": "lodash.pad@^3.0.0",
-          "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-3.1.1.tgz"
-        },
         "lodash.padleft": {
           "version": "3.1.1",
           "from": "lodash.padleft@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash.padleft/-/lodash.padleft-3.1.1.tgz"
         },
-        "lodash.padright": {
+        "lodash._basetostring": {
+          "version": "3.0.1",
+          "from": "lodash._basetostring@^3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz"
+        },
+        "lodash.pad": {
           "version": "3.1.1",
-          "from": "lodash.padright@^3.0.0",
-          "resolved": "https://registry.npmjs.org/lodash.padright/-/lodash.padright-3.1.1.tgz"
+          "from": "lodash.pad@^3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-3.1.1.tgz"
         },
         "lodash.repeat": {
           "version": "3.0.1",
           "from": "lodash.repeat@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash.repeat/-/lodash.repeat-3.0.1.tgz"
         },
+        "lodash.padright": {
+          "version": "3.1.1",
+          "from": "lodash.padright@^3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash.padright/-/lodash.padright-3.1.1.tgz"
+        },
         "mime-db": {
           "version": "1.19.0",
           "from": "mime-db@~1.19.0",
           "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.19.0.tgz"
         },
-        "mime-types": {
-          "version": "2.1.7",
-          "from": "mime-types@~2.1.7",
-          "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.7.tgz"
-        },
         "minimist": {
           "version": "0.0.8",
           "from": "minimist@0.0.8",
           "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
         },
+        "mime-types": {
+          "version": "2.1.7",
+          "from": "mime-types@~2.1.7",
+          "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.7.tgz"
+        },
         "mkdirp": {
           "version": "0.5.1",
           "from": "mkdirp@>=0.3.0 <0.4.0||>=0.4.0 <0.5.0||>=0.5.0 <0.6.0",
@@ -2200,11 +2200,6 @@
           "from": "npmlog@~1.2.0",
           "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz"
         },
-        "oauth-sign": {
-          "version": "0.8.0",
-          "from": "oauth-sign@~0.8.0",
-          "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.0.tgz"
-        },
         "once": {
           "version": "1.1.1",
           "from": "once@~1.1.1",
@@ -2215,6 +2210,11 @@
           "from": "path-is-absolute@>=1.0.0 <2.0.0",
           "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz"
         },
+        "oauth-sign": {
+          "version": "0.8.0",
+          "from": "oauth-sign@~0.8.0",
+          "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.0.tgz"
+        },
         "pinkie": {
           "version": "1.0.0",
           "from": "pinkie@^1.0.0",
@@ -2265,11 +2265,6 @@
           "from": "strip-ansi@^3.0.0",
           "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz"
         },
-        "strip-json-comments": {
-          "version": "0.1.3",
-          "from": "strip-json-comments@0.1.x",
-          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
-        },
         "supports-color": {
           "version": "2.0.0",
           "from": "supports-color@^2.0.0",
@@ -2285,6 +2280,11 @@
           "from": "tough-cookie@~2.2.0",
           "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.0.tgz"
         },
+        "strip-json-comments": {
+          "version": "0.1.3",
+          "from": "strip-json-comments@0.1.x",
+          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
+        },
         "uid-number": {
           "version": "0.0.3",
           "from": "uid-number@0.0.3",
@@ -3933,9 +3933,9 @@
       }
     },
     "node-haste": {
-      "version": "2.3.0",
-      "from": "node-haste@2.3.0",
-      "resolved": "https://registry.npmjs.org/node-haste/-/node-haste-2.3.0.tgz",
+      "version": "2.4.0",
+      "from": "node-haste@2.4.0",
+      "resolved": "https://registry.npmjs.org/node-haste/-/node-haste-2.4.0.tgz",
       "dependencies": {
         "graceful-fs": {
           "version": "4.1.3",
diff --git a/package.json b/package.json
index aadb2436f154..9d6cfa9935e9 100644
--- a/package.json
+++ b/package.json
@@ -148,7 +148,7 @@
     "mkdirp": "^0.5.1",
     "module-deps": "^3.9.1",
     "node-fetch": "^1.3.3",
-    "node-haste": "~2.3.0",
+    "node-haste": "~2.4.0",
     "opn": "^3.0.2",
     "optimist": "^0.6.1",
     "progress": "^1.1.8",

From 436db67126f1e64d1889c2d084b77c98c8d63f8d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Fri, 26 Feb 2016 15:14:47 -0800
Subject: [PATCH 1334/1411] Allow parents to accept children modules

Summary:In order to be able to Hot Load Redux stores and modules that export functions, we need to build infrastructure to bubble up the HMR updates similar to how webpack does: https://webpack.github.io/docs/hot-module-replacement-with-webpack.html.

In here we introduce the minimum of this infrastructure we need to make this work. The Packager server needs to send the inverse dependencies to the HMR runtime that runs on the client so that it can bubble up the patches if they cannot be self accepted by the module that was changed.

This diff relies on https://github.com/facebook/node-haste/pull/40/files which adds support for getting the inverse dependencies.

Reviewed By: davidaurelio

Differential Revision: D2950662

fb-gh-sync-id: 26dcd4aa15da76a727026a9d7ee06e7ae4d22eaa
shipit-source-id: 26dcd4aa15da76a727026a9d7ee06e7ae4d22eaa
---
 Libraries/Utilities/HMRClient.js              | 21 ++++++--
 local-cli/server/util/attachHMRServer.js      | 30 ++++++++----
 .../react-packager/src/Bundler/HMRBundle.js   | 12 +++--
 .../src/Resolver/polyfills/require.js         | 49 +++++++++++++++----
 4 files changed, 83 insertions(+), 29 deletions(-)

diff --git a/Libraries/Utilities/HMRClient.js b/Libraries/Utilities/HMRClient.js
index d9d8b79bdd62..887bab88000c 100644
--- a/Libraries/Utilities/HMRClient.js
+++ b/Libraries/Utilities/HMRClient.js
@@ -73,9 +73,12 @@ Error: ${e.message}`
           break;
         }
         case 'update': {
-          const modules = data.body.modules;
-          const sourceMappingURLs = data.body.sourceMappingURLs;
-          const sourceURLs = data.body.sourceURLs;
+          const {
+            modules,
+            sourceMappingURLs,
+            sourceURLs,
+            inverseDependencies,
+          } = data.body;
 
           if (Platform.OS === 'ios') {
             const RCTRedBox = require('NativeModules').RedBox;
@@ -85,7 +88,7 @@ Error: ${e.message}`
             RCTExceptionsManager && RCTExceptionsManager.dismissRedbox && RCTExceptionsManager.dismissRedbox();
           }
 
-          modules.forEach((code, i) => {
+          modules.forEach(({name, code}, i) => {
             code = code + '\n\n' + sourceMappingURLs[i];
 
             require('SourceMapsCache').fetch({
@@ -101,6 +104,16 @@ Error: ${e.message}`
               ? global.nativeInjectHMRUpdate
               : eval;
 
+            // TODO: (martinb) yellow box if cannot accept module
+            code = `
+              __accept(
+                ${name},
+                function(global, require, module, exports) {
+                  ${code}
+                },
+                ${JSON.stringify(inverseDependencies)}
+              );`;
+
             injectFunction(code, sourceURLs[i]);
           });
 
diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js
index e0495e3d7006..22323d071e23 100644
--- a/local-cli/server/util/attachHMRServer.js
+++ b/local-cli/server/util/attachHMRServer.js
@@ -8,6 +8,7 @@
  */
 'use strict';
 
+const getInverseDependencies = require('node-haste').getInverseDependencies;
 const querystring = require('querystring');
 const url = require('url');
 
@@ -23,9 +24,10 @@ function attachHMRServer({httpServer, path, packagerServer}) {
     packagerServer.setHMRFileChangeListener(null);
   }
 
-  // Returns a promise with the full list of dependencies and the shallow
-  // dependencies each file on the dependency list has for the give platform
-  // and entry file.
+  // For the give platform and entry file, returns a promise with:
+  //   - The full list of dependencies.
+  //   - The shallow dependencies each file on the dependency list has
+  //   - Inverse shallow dependencies map
   function getDependencies(platform, bundleEntry) {
     return packagerServer.getDependencies({
       platform: platform,
@@ -70,12 +72,16 @@ function attachHMRServer({httpServer, path, packagerServer}) {
             dependenciesModulesCache[depName] = dep;
           });
         })).then(() => {
-          return {
-            dependenciesCache,
-            dependenciesModulesCache,
-            shallowDependencies,
-            resolutionResponse: response,
-          };
+          return getInverseDependencies(response)
+            .then(inverseDependenciesCache => {
+              return {
+                dependenciesCache,
+                dependenciesModulesCache,
+                shallowDependencies,
+                inverseDependenciesCache,
+                resolutionResponse: response,
+              };
+            });
         });
       });
     });
@@ -97,6 +103,7 @@ function attachHMRServer({httpServer, path, packagerServer}) {
         dependenciesCache,
         dependenciesModulesCache,
         shallowDependencies,
+        inverseDependenciesCache,
       }) => {
         client = {
           ws,
@@ -105,6 +112,7 @@ function attachHMRServer({httpServer, path, packagerServer}) {
           dependenciesCache,
           dependenciesModulesCache,
           shallowDependencies,
+          inverseDependenciesCache,
         };
 
         packagerServer.setHMRFileChangeListener((filename, stat) => {
@@ -151,6 +159,7 @@ function attachHMRServer({httpServer, path, packagerServer}) {
                     dependenciesCache,
                     dependenciesModulesCache,
                     shallowDependencies,
+                    inverseDependenciesCache,
                     resolutionResponse,
                   }) => {
                     if (!client) {
@@ -211,7 +220,8 @@ function attachHMRServer({httpServer, path, packagerServer}) {
                 return JSON.stringify({
                   type: 'update',
                   body: {
-                    modules: bundle.getModulesCode(),
+                    modules: bundle.getModulesNamesAndCode(),
+                    inverseDependencies: inverseDependenciesCache,
                     sourceURLs: bundle.getSourceURLs(),
                     sourceMappingURLs: bundle.getSourceMappingURLs(),
                   },
diff --git a/packager/react-packager/src/Bundler/HMRBundle.js b/packager/react-packager/src/Bundler/HMRBundle.js
index 49a21dfd8bc7..72850778846c 100644
--- a/packager/react-packager/src/Bundler/HMRBundle.js
+++ b/packager/react-packager/src/Bundler/HMRBundle.js
@@ -26,9 +26,6 @@ class HMRBundle extends BundleBase {
       module,
       transformed.code,
     ).then(({name, code}) => {
-      // need to be in single line so that lines match on sourcemaps
-      code = `__accept(${JSON.stringify(name)}, function(global, require, module, exports) { ${code} });`;
-
       const moduleTransport = new ModuleTransport({
         code,
         name,
@@ -44,8 +41,13 @@ class HMRBundle extends BundleBase {
     });
   }
 
-  getModulesCode() {
-    return this._modules.map(module => module.code);
+  getModulesNamesAndCode() {
+    return this._modules.map(module => {
+      return {
+        name: JSON.stringify(module.name),
+        code: module.code,
+      };
+    });
   }
 
   getSourceURLs() {
diff --git a/packager/react-packager/src/Resolver/polyfills/require.js b/packager/react-packager/src/Resolver/polyfills/require.js
index 764e4dd1e2e1..d5b0cd81a2f5 100644
--- a/packager/react-packager/src/Resolver/polyfills/require.js
+++ b/packager/react-packager/src/Resolver/polyfills/require.js
@@ -94,12 +94,12 @@ global.__d = define;
 global.require = require;
 
 if (__DEV__) { // HMR
-  function accept(id, factory) {
+  function accept(id, factory, inverseDependencies) {
     var mod = modules[id];
 
     if (!mod) {
       define(id, factory);
-      return; // new modules don't need to be accepted
+      return true; // new modules don't need to be accepted
     }
 
     if (!mod.module.hot) {
@@ -107,21 +107,50 @@ if (__DEV__) { // HMR
         'Cannot accept module because Hot Module Replacement ' +
         'API was not installed.'
       );
-      return;
+      return false;
     }
 
-    if (mod.module.hot.acceptCallback) {
+    // replace and initialize factory
+    if (factory) {
       mod.factory = factory;
-      mod.isInitialized = false;
-      require(id);
+    }
+    mod.isInitialized = false;
+    require(id);
 
+    if (mod.module.hot.acceptCallback) {
       mod.module.hot.acceptCallback();
+      return true;
     } else {
-      console.warn(
-        '[HMR] Module `' + id + '` can\'t be hot reloaded because it\'s not a ' +
-        'React component. To get the changes reload the JS bundle.'
-      );
+      // need to have inverseDependencies to bubble up accept
+      if (!inverseDependencies) {
+        throw new Error('Undefined `inverseDependencies`');
+      }
+
+      // accept parent modules recursively up until all siblings are accepted
+      return acceptAll(inverseDependencies[id], inverseDependencies);
+    }
+  }
+
+  function acceptAll(modules, inverseDependencies) {
+    if (modules.length === 0) {
+      return true;
     }
+
+    var notAccepted = modules.filter(function(module) {
+      return !accept(module, /*factory*/ undefined, inverseDependencies);
+    });
+
+    var parents = [];
+    for (var i = 0; i < notAccepted.length; i++) {
+      // if this the module has no parents then the change cannot be hot loaded
+      if (inverseDependencies[notAccepted[i]].length === 0) {
+        return false;
+      }
+
+      parents.pushAll(inverseDependencies[notAccepted[i]]);
+    }
+
+    return acceptAll(parents, inverseDependencies);
   }
 
   global.__accept = accept;

From 3812c74e7c7f1e847b118cfdc328fc36c31b5411 Mon Sep 17 00:00:00 2001
From: Hedger Wang <hedger@fb.com>
Date: Fri, 26 Feb 2016 18:10:44 -0800
Subject: [PATCH 1335/1411] Guard navigator from dismatching gestures.

Reviewed By: fkgozali

Differential Revision: D2985510

fb-gh-sync-id: 72639c37fa61c91bbd75ba74166eed96f11d7564
shipit-source-id: 72639c37fa61c91bbd75ba74166eed96f11d7564
---
 Libraries/CustomComponents/Navigator/Navigator.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libraries/CustomComponents/Navigator/Navigator.js b/Libraries/CustomComponents/Navigator/Navigator.js
index 095a4efd57f1..d905c603d1b3 100644
--- a/Libraries/CustomComponents/Navigator/Navigator.js
+++ b/Libraries/CustomComponents/Navigator/Navigator.js
@@ -776,7 +776,7 @@ var Navigator = React.createClass({
   },
 
   _matchGestureAction: function(eligibleGestures, gestures, gestureState) {
-    if (!gestures) {
+    if (!gestures || !eligibleGestures || !eligibleGestures.some) {
       return null;
     }
     var matchedGesture = null;

From 8a042f46544161b7ca80fcbe00c1d115c9f72aab Mon Sep 17 00:00:00 2001
From: Walter Luh <wluh@fb.com>
Date: Fri, 26 Feb 2016 18:17:22 -0800
Subject: [PATCH 1336/1411] Minor path change for message socket between
 packager and bridge (3/N)

Summary: New path is '{base_url}/message?role=shell'

Reviewed By: javache

Differential Revision: D2957640

fb-gh-sync-id: 2994857d874fd2314c9056e71acda008573911eb
shipit-source-id: 2994857d874fd2314c9056e71acda008573911eb
---
 React/Modules/RCTDevMenu.m | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/React/Modules/RCTDevMenu.m b/React/Modules/RCTDevMenu.m
index 9e84ab01df87..911bddce6478 100644
--- a/React/Modules/RCTDevMenu.m
+++ b/React/Modules/RCTDevMenu.m
@@ -239,7 +239,7 @@ - (NSURL *)packagerURL
 
   NSString *scheme = [_bridge.bundleURL scheme];
   NSNumber *port = [_bridge.bundleURL port];
-  return [NSURL URLWithString:[NSString stringWithFormat:@"%@://%@:%@/packager-proxy?role=client", scheme, host, port]];
+  return [NSURL URLWithString:[NSString stringWithFormat:@"%@://%@:%@/message?role=shell", scheme, host, port]];
 }
 
 // TODO: Move non-UI logic into separate RCTDevSettings module

From 7c2c6a9d3f1eb48462cf5fbb333b2d438e9b48b2 Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Sat, 27 Feb 2016 15:57:14 -0800
Subject: [PATCH 1337/1411] Show a Toast for HMR

Summary:This is just to try out the experience with HMR if we show toasts (might be annoying). Let's try it out before deciding on merging/closing.

Related #5906
Closes https://github.com/facebook/react-native/pull/5947

Differential Revision: D2987132

fb-gh-sync-id: 7bfbb6e1f0363a416805b67eb5674f79ac0881ad
shipit-source-id: 7bfbb6e1f0363a416805b67eb5674f79ac0881ad
---
 Libraries/Utilities/HMRClient.js              | 26 +++++--------
 Libraries/Utilities/HMRLoadingView.android.js | 38 +++++++++++++++++++
 Libraries/Utilities/HMRLoadingView.ios.js     | 32 ++++++++++++++++
 3 files changed, 79 insertions(+), 17 deletions(-)
 create mode 100644 Libraries/Utilities/HMRLoadingView.android.js
 create mode 100644 Libraries/Utilities/HMRLoadingView.ios.js

diff --git a/Libraries/Utilities/HMRClient.js b/Libraries/Utilities/HMRClient.js
index 887bab88000c..16f32368cc26 100644
--- a/Libraries/Utilities/HMRClient.js
+++ b/Libraries/Utilities/HMRClient.js
@@ -7,19 +7,19 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule HMRClient
+ * @flow
  */
 'use strict';
 
 const Platform = require('Platform');
 const invariant = require('invariant');
-const processColor = require('processColor');
 
 /**
  * HMR Client that receives from the server HMR updates and propagates them
  * runtime to reflects those changes.
  */
 const HMRClient = {
-  enable(platform, bundleEntry, host, port) {
+  enable(platform: string, bundleEntry: string, host: string, port: number) {
     invariant(platform, 'Missing required parameter `platform`');
     invariant(bundleEntry, 'Missing required paramenter `bundleEntry`');
     invariant(host, 'Missing required paramenter `host`');
@@ -54,22 +54,14 @@ Error: ${e.message}`
       );
     };
     activeWS.onmessage = ({data}) => {
-      let DevLoadingView = require('NativeModules').DevLoadingView;
-      if (!DevLoadingView) {
-        DevLoadingView = {
-          showMessage() {},
-          hide() {},
-        };
-      }
+      // Moving to top gives errors due to NativeModules not being initialized
+      const HMRLoadingView = require('HMRLoadingView');
+
       data = JSON.parse(data);
 
       switch (data.type) {
         case 'update-start': {
-          DevLoadingView.showMessage(
-            'Hot Loading...',
-            processColor('#000000'),
-            processColor('#aaaaaa'),
-          );
+          HMRLoadingView.showMessage('Hot Loading...');
           break;
         }
         case 'update': {
@@ -117,15 +109,15 @@ Error: ${e.message}`
             injectFunction(code, sourceURLs[i]);
           });
 
-          DevLoadingView.hide();
+          HMRLoadingView.hide();
           break;
         }
         case 'update-done': {
-          DevLoadingView.hide();
+          HMRLoadingView.hide();
           break;
         }
         case 'error': {
-          DevLoadingView.hide();
+          HMRLoadingView.hide();
           throw new Error(data.body.type + ' ' + data.body.description);
         }
         default: {
diff --git a/Libraries/Utilities/HMRLoadingView.android.js b/Libraries/Utilities/HMRLoadingView.android.js
new file mode 100644
index 000000000000..82075ffa1920
--- /dev/null
+++ b/Libraries/Utilities/HMRLoadingView.android.js
@@ -0,0 +1,38 @@
+/**
+ * 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 HMRLoadingView
+ * @flow
+ */
+
+'use strict';
+
+var ToastAndroid = require('ToastAndroid');
+
+const TOAST_SHORT_DELAY = 2000;
+
+class HMRLoadingView {
+  static _showing: boolean;
+
+  static showMessage(message: string) {
+    if (HMRLoadingView._showing) {
+      return;
+    }
+    ToastAndroid.show(message, ToastAndroid.SHORT);
+    HMRLoadingView._showing = true;
+    setTimeout(() => {
+      HMRLoadingView._showing = false;
+    }, TOAST_SHORT_DELAY);
+  }
+
+  static hide() {
+    // noop
+  }
+}
+
+module.exports = HMRLoadingView;
diff --git a/Libraries/Utilities/HMRLoadingView.ios.js b/Libraries/Utilities/HMRLoadingView.ios.js
new file mode 100644
index 000000000000..ea0559fc41d0
--- /dev/null
+++ b/Libraries/Utilities/HMRLoadingView.ios.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 HMRLoadingView
+ * @flow
+ */
+
+'use strict';
+
+const processColor = require('processColor');
+const { DevLoadingView } = require('NativeModules');
+
+class HMRLoadingView {
+  static showMessage(message: string) {
+    DevLoadingView.showMessage(
+      message,
+      processColor('#000000'),
+      processColor('#aaaaaa'),
+    );
+  }
+
+  static hide() {
+    DevLoadingView.hide();
+  }
+}
+
+module.exports = HMRLoadingView;

From 3cc4f97f0449ed922868c8d7532df9d3cad14c30 Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Sat, 27 Feb 2016 16:18:40 -0800
Subject: [PATCH 1338/1411] Remove 'displayName' prop from 'PickerExample'
 component

Summary:The value of the displayName was wrong (had space in it). Also the babel plugin for display name already adds display names. So we shouldn't need to do it manually.

As a side effect, it breaks the UIExplorer app when HMR is enabled (that's how I found it).
Closes https://github.com/facebook/react-native/pull/6193

Differential Revision: D2987160

fb-gh-sync-id: fd64112c26741fab1385454a0ce978ec1eaf2415
shipit-source-id: fd64112c26741fab1385454a0ce978ec1eaf2415
---
 Examples/UIExplorer/PickerAndroidExample.js | 2 --
 1 file changed, 2 deletions(-)

diff --git a/Examples/UIExplorer/PickerAndroidExample.js b/Examples/UIExplorer/PickerAndroidExample.js
index 0f76f6e8480a..cdbc649626b4 100644
--- a/Examples/UIExplorer/PickerAndroidExample.js
+++ b/Examples/UIExplorer/PickerAndroidExample.js
@@ -44,8 +44,6 @@ const PickerExample = React.createClass({
     };
   },
 
-  displayName: 'Android Picker',
-
   render: function() {
     return (
       <UIExplorerPage title="<Picker>">

From 44fcf22074ca32e5f6869b88f7b6c00ea990cb08 Mon Sep 17 00:00:00 2001
From: Janic Duplessis <janicduplessis@gmail.com>
Date: Sun, 28 Feb 2016 11:40:50 -0800
Subject: [PATCH 1339/1411] Fix crash when passing null to clearImmediate

Summary:Passing `undefined` or `null` to `clearImmediate` caused apps to crash. It it caused because we try to find the index of the null/undefined timer when we should just do nothing when passed these values.

It is already handled properly in the other Timer functions.

**Test plan**
Calling `clearImmediate` with `undefined` or `null` should do nothing.
Closes https://github.com/facebook/react-native/pull/6192

Differential Revision: D2987778

Pulled By: vjeux

fb-gh-sync-id: 6fd38cfa3c10012caa2afb27cbdab95df696a769
shipit-source-id: 6fd38cfa3c10012caa2afb27cbdab95df696a769
---
 Libraries/JavaScriptAppEngine/System/JSTimers/JSTimers.js | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimers.js b/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimers.js
index f6a8bddc7a43..0ec0a4c08c28 100644
--- a/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimers.js
+++ b/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimers.js
@@ -106,10 +106,10 @@ var JSTimers = {
 
   clearImmediate: function(timerID) {
     JSTimers._clearTimerID(timerID);
-    JSTimersExecution.immediates.splice(
-      JSTimersExecution.immediates.indexOf(timerID),
-      1
-    );
+    var index = JSTimersExecution.immediates.indexOf(timerID);
+    if (index !== -1) {
+      JSTimersExecution.immediates.splice(index, 1);
+    }
   },
 
   cancelAnimationFrame: function(timerID) {

From 79e9489580c48f8c0f0020eb5a3cc2e92db7a3b3 Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Mon, 29 Feb 2016 03:28:48 -0800
Subject: [PATCH 1340/1411] Add 'Linking' example

Summary:Since `IntentAndroid` is being deprecated and `Linking` is the new API to deal with URLs, here comes the basic `Linking` API example. :)
Closes https://github.com/facebook/react-native/pull/6194

Differential Revision: D2988614

Pulled By: javache

fb-gh-sync-id: a98daa8e57ec6f59ecf3182fa4b21e81ad55f1c0
shipit-source-id: a98daa8e57ec6f59ecf3182fa4b21e81ad55f1c0
---
 ...ntAndroidExample.android.js => LinkingExample.js} | 12 +++++++-----
 Examples/UIExplorer/UIExplorerList.android.js        |  8 ++++----
 Examples/UIExplorer/UIExplorerList.ios.js            |  4 ++++
 3 files changed, 15 insertions(+), 9 deletions(-)
 rename Examples/UIExplorer/{IntentAndroidExample.android.js => LinkingExample.js} (87%)

diff --git a/Examples/UIExplorer/IntentAndroidExample.android.js b/Examples/UIExplorer/LinkingExample.js
similarity index 87%
rename from Examples/UIExplorer/IntentAndroidExample.android.js
rename to Examples/UIExplorer/LinkingExample.js
index e655bd9650c8..fbf36bfc071d 100644
--- a/Examples/UIExplorer/IntentAndroidExample.android.js
+++ b/Examples/UIExplorer/LinkingExample.js
@@ -15,7 +15,7 @@
 
 var React = require('react-native');
 var {
-  IntentAndroid,
+  Linking,
   StyleSheet,
   Text,
   TouchableNativeFeedback,
@@ -30,9 +30,9 @@ var OpenURLButton = React.createClass({
   },
 
   handleClick: function() {
-    IntentAndroid.canOpenURL(this.props.url, (supported) => {
+    Linking.canOpenURL(this.props.url).then(supported => {
       if (supported) {
-        IntentAndroid.openURL(this.props.url);
+        Linking.openURL(this.props.url);
       } else {
         console.log('Don\'t know how to open URI: ' + this.props.url);
       }
@@ -54,8 +54,8 @@ var OpenURLButton = React.createClass({
 var IntentAndroidExample = React.createClass({
 
   statics: {
-    title: 'IntentAndroid',
-    description: 'Shows how to use Android Intents to open URLs.',
+    title: 'Linking',
+    description: 'Shows how to use Linking to open URLs.',
   },
 
   render: function() {
@@ -64,7 +64,9 @@ var IntentAndroidExample = React.createClass({
         <OpenURLButton url={'https://www.facebook.com'} />
         <OpenURLButton url={'http://www.facebook.com'} />
         <OpenURLButton url={'http://facebook.com'} />
+        <OpenURLButton url={'fb://notifications'} />
         <OpenURLButton url={'geo:37.484847,-122.148386'} />
+        <OpenURLButton url={'tel:9876543210'} />
       </UIExplorerBlock>
     );
   },
diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index 321d84a41676..78e74c48e841 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -120,14 +120,14 @@ const APIExamples = [
     key: 'ImageEditingExample',
     module: require('./ImageEditingExample'),
   },
-  {
-    key: 'IntentAndroidExample',
-    module: require('./IntentAndroidExample'),
-  },
   {
     key: 'LayoutEventsExample',
     module: require('./LayoutEventsExample'),
   },
+  {
+    key: 'LinkingExample',
+    module: require('./LinkingExample'),
+  },
   {
     key: 'LayoutExample',
     module: require('./LayoutExample'),
diff --git a/Examples/UIExplorer/UIExplorerList.ios.js b/Examples/UIExplorer/UIExplorerList.ios.js
index ae7248430ab6..b2fefd125056 100644
--- a/Examples/UIExplorer/UIExplorerList.ios.js
+++ b/Examples/UIExplorer/UIExplorerList.ios.js
@@ -196,6 +196,10 @@ var APIExamples: Array<UIExplorerExample> = [
     key: 'LayoutExample',
     module: require('./LayoutExample'),
   },
+  {
+    key: 'LinkingExample',
+    module: require('./LinkingExample'),
+  },
   {
     key: 'NavigationExperimentalExample',
     module: require('./NavigationExperimental/NavigationExperimentalExample'),

From cf0c3d434232bd828e3ec2d53ccd531a6cfbca58 Mon Sep 17 00:00:00 2001
From: Gord Tanner <gtanner@gmail.com>
Date: Mon, 29 Feb 2016 07:09:21 -0800
Subject: [PATCH 1341/1411] Update wc to latest version to remove insecure
 warning

Summary:- [x] Updated wc dependency to latest version.
 - Noticed on bitHound wc was marked as insecure: [![bitHound Dependencies](https://www.bithound.io/github/facebook/react-native/badges/dependencies.svg)]
(https://www.bithound.io/github/facebook/react-native/master/dependencies/npm)
 - details on bitHound [here](https://www.bithound.io/github/facebook/react-native/master/dependencies/npm/ws)
 - Updated the dep to remove that warning: [![bitHound Dependencies](https://www.bithound.io/github/gtanner/react-native/badges/dependencies.svg)](https://www.bithound.io/github/gtanner/react-native/master/dependencies/npm)
  - bitHound generated pr can be seen [here](https://github.com/gtanner/react-native/pull/1)
- [x] Added a bitHound badge to the readme to track the state of your dependencies.

**Test plan**

* Ran `npm test` before and after updating the dependency
* Build the 2048 sample app and ensured that livereload / remote debugging / packaging was all still working since that is where I could see `ws
Closes https://github.com/facebook/react-native/pull/6153

Differential Revision: D2988876

fb-gh-sync-id: e19cce39d57214df082d42c59ac0d615496b0743
shipit-source-id: e19cce39d57214df082d42c59ac0d615496b0743
---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 04dbd5e4b03b..d539d122a98b 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# React Native [![Build Status](https://travis-ci.org/facebook/react-native.svg?branch=master)](https://travis-ci.org/facebook/react-native) [![Circle CI](https://circleci.com/gh/facebook/react-native.svg?style=svg)](https://circleci.com/gh/facebook/react-native) [![npm version](https://badge.fury.io/js/react-native.svg)](http://badge.fury.io/js/react-native)
+# React Native [![Build Status](https://travis-ci.org/facebook/react-native.svg?branch=master)](https://travis-ci.org/facebook/react-native) [![Circle CI](https://circleci.com/gh/facebook/react-native.svg?style=svg)](https://circleci.com/gh/facebook/react-native) [![npm version](https://badge.fury.io/js/react-native.svg)](http://badge.fury.io/js/react-native) [![bitHound Dependencies](https://www.bithound.io/github/facebook/react-native/badges/dependencies.svg)](https://www.bithound.io/github/facebook/react-native/master/dependencies/npm)
 
 React Native enables you to build world-class application experiences on native platforms using a consistent developer experience based on JavaScript and [React](http://facebook.github.io/react). The focus of React Native is on developer efficiency across all the platforms you care about - learn once, write anywhere. Facebook uses React Native in multiple production apps and will continue investing in React Native.
 

From fcd468d4eb092b43347432569cb45ad87b87c8a0 Mon Sep 17 00:00:00 2001
From: Sokovikov <skv-headless@yandex.ru>
Date: Mon, 29 Feb 2016 07:32:56 -0800
Subject: [PATCH 1342/1411] fix props anchor links

Summary:All anchor links are broken because of https://github.com/facebook/react-native/blob/master/website/core/Site.js#L37 base tag it means that relative urls won't work.
closes #5450
proof
![screen shot 2016-02-29 at 13 34 35](https://cloud.githubusercontent.com/assets/1488195/13392082/3d14a00e-dee9-11e5-8611-bc6bfaf6c752.png)
Closes https://github.com/facebook/react-native/pull/6208

Differential Revision: D2988892

Pulled By: vjeux

fb-gh-sync-id: da8b621af92d792a258812e38ae15f7cf53873ca
shipit-source-id: da8b621af92d792a258812e38ae15f7cf53873ca
---
 website/core/Header.js           | 6 +++++-
 website/layout/AutodocsLayout.js | 4 ++--
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/website/core/Header.js b/website/core/Header.js
index c84c98c401b0..00de9353cb78 100644
--- a/website/core/Header.js
+++ b/website/core/Header.js
@@ -13,6 +13,10 @@ var React = require('React');
 var slugify = require('slugify');
 
 var Header = React.createClass({
+  getDefaultProps: function() {
+    return {permalink: ''};
+  },
+
   render: function() {
     var slug = slugify(this.props.toSlug || this.props.children);
     var H = 'h' + this.props.level;
@@ -20,7 +24,7 @@ var Header = React.createClass({
       <H {...this.props}>
         <a className="anchor" name={slug}></a>
         {this.props.children}
-        {' '}<a className="hash-link" href={'#' + slug}>#</a>
+        {' '}<a className="hash-link" href={this.props.permalink + '#' + slug}>#</a>
       </H>
     );
   }
diff --git a/website/layout/AutodocsLayout.js b/website/layout/AutodocsLayout.js
index 036ca0973137..66bb70018fb9 100644
--- a/website/layout/AutodocsLayout.js
+++ b/website/layout/AutodocsLayout.js
@@ -110,7 +110,7 @@ var ComponentDoc = React.createClass({
   renderProp: function(name, prop) {
     return (
       <div className="prop" key={name}>
-        <Header level={4} className="propTitle" toSlug={name}>
+        <Header level={4} className="propTitle" toSlug={name} permalink={this.props.permalink}>
           {prop.platforms && prop.platforms.map(platform =>
             <span className="platform">{platform}</span>
           )}
@@ -488,7 +488,7 @@ var Autodocs = React.createClass({
     var metadata = this.props.metadata;
     var docs = JSON.parse(this.props.children);
     var content  = docs.type === 'component' || docs.type === 'style' ?
-      <ComponentDoc content={docs} /> :
+      <ComponentDoc content={docs} permalink={metadata.permalink}/> :
       <APIDoc content={docs} apiName={metadata.title} />;
 
     return (

From 5a53d90003139a2d32a67435af880980a142c50f Mon Sep 17 00:00:00 2001
From: Sokovikov <skv-headless@yandex.ru>
Date: Mon, 29 Feb 2016 09:20:24 -0800
Subject: [PATCH 1343/1411] fix all anchor links in docs

Summary: Closes https://github.com/facebook/react-native/pull/6213

Differential Revision: D2989119

Pulled By: vjeux

fb-gh-sync-id: 3a069dcebbf8dec40702a7bab5268ce4a82db731
shipit-source-id: 3a069dcebbf8dec40702a7bab5268ce4a82db731
---
 website/core/Header.js              |  7 ++++---
 website/layout/AutodocsLayout.js    | 12 ++++++++++--
 website/layout/DocsLayout.js        |  8 ++++++++
 website/layout/PageLayout.js        |  8 ++++++++
 website/src/react-native/support.js |  7 +++++++
 5 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/website/core/Header.js b/website/core/Header.js
index 00de9353cb78..c83d7334b1b7 100644
--- a/website/core/Header.js
+++ b/website/core/Header.js
@@ -13,18 +13,19 @@ var React = require('React');
 var slugify = require('slugify');
 
 var Header = React.createClass({
-  getDefaultProps: function() {
-    return {permalink: ''};
+  contextTypes: {
+    permalink: React.PropTypes.string
   },
 
   render: function() {
     var slug = slugify(this.props.toSlug || this.props.children);
     var H = 'h' + this.props.level;
+    var base = this.context.permalink || '';
     return (
       <H {...this.props}>
         <a className="anchor" name={slug}></a>
         {this.props.children}
-        {' '}<a className="hash-link" href={this.props.permalink + '#' + slug}>#</a>
+        {' '}<a className="hash-link" href={base + '#' + slug}>#</a>
       </H>
     );
   }
diff --git a/website/layout/AutodocsLayout.js b/website/layout/AutodocsLayout.js
index 66bb70018fb9..269314cb1e04 100644
--- a/website/layout/AutodocsLayout.js
+++ b/website/layout/AutodocsLayout.js
@@ -110,7 +110,7 @@ var ComponentDoc = React.createClass({
   renderProp: function(name, prop) {
     return (
       <div className="prop" key={name}>
-        <Header level={4} className="propTitle" toSlug={name} permalink={this.props.permalink}>
+        <Header level={4} className="propTitle" toSlug={name}>
           {prop.platforms && prop.platforms.map(platform =>
             <span className="platform">{platform}</span>
           )}
@@ -448,6 +448,14 @@ var Modal = React.createClass({
 });
 
 var Autodocs = React.createClass({
+  childContextTypes: {
+    permalink: React.PropTypes.string
+  },
+
+  getChildContext: function() {
+    return {permalink: this.props.metadata.permalink};
+  },
+
   renderFullDescription: function(docs) {
     if (!docs.fullDescription) {
       return;
@@ -488,7 +496,7 @@ var Autodocs = React.createClass({
     var metadata = this.props.metadata;
     var docs = JSON.parse(this.props.children);
     var content  = docs.type === 'component' || docs.type === 'style' ?
-      <ComponentDoc content={docs} permalink={metadata.permalink}/> :
+      <ComponentDoc content={docs} /> :
       <APIDoc content={docs} apiName={metadata.title} />;
 
     return (
diff --git a/website/layout/DocsLayout.js b/website/layout/DocsLayout.js
index d92b5d06ebc8..d84d9682d7a1 100644
--- a/website/layout/DocsLayout.js
+++ b/website/layout/DocsLayout.js
@@ -16,6 +16,14 @@ var React = require('React');
 var Site = require('Site');
 
 var DocsLayout = React.createClass({
+  childContextTypes: {
+    permalink: React.PropTypes.string
+  },
+
+  getChildContext: function() {
+    return {permalink: this.props.metadata.permalink};
+  },
+
   render: function() {
     var metadata = this.props.metadata;
     var content = this.props.children;
diff --git a/website/layout/PageLayout.js b/website/layout/PageLayout.js
index a4ff02c60458..94697a207d6e 100644
--- a/website/layout/PageLayout.js
+++ b/website/layout/PageLayout.js
@@ -14,6 +14,14 @@ var Site = require('Site');
 var Marked = require('Marked');
 
 var support = React.createClass({
+  childContextTypes: {
+    permalink: React.PropTypes.string
+  },
+
+  getChildContext: function() {
+    return {permalink: this.props.metadata.permalink};
+  },
+
   render: function() {
     var metadata = this.props.metadata;
     var content = this.props.children;
diff --git a/website/src/react-native/support.js b/website/src/react-native/support.js
index abf51306be98..de1b4bbe7f41 100644
--- a/website/src/react-native/support.js
+++ b/website/src/react-native/support.js
@@ -13,6 +13,13 @@ var center = require('center');
 var H2 = require('H2');
 
 var support = React.createClass({
+  childContextTypes: {
+    permalink: React.PropTypes.string
+  },
+
+  getChildContext: function() {
+    return {permalink: 'support.html'};
+  },
   render: function() {
     return (
       <Site section="support" title="Support">

From 8d44c2db4f62af0fd9382413bb0e0155225b4c64 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Mon, 29 Feb 2016 09:24:19 -0800
Subject: [PATCH 1344/1411] Fix bridge tests

Summary:The `RCTDevMenu.hotLoadingAvailable` check always returned YES if `bridge.bundleURL` was nil. This caused the `setHotLoadingEnabled:` method to repeatedly reload the bridge, resulting in the following tests failing:

`- [RCTBridgeTests testHookRegistration];`
`- [RCTBridgeTests testCallNativeMethod];`

Also, the `RUN_RUNLOOP_WHILE()` macro did not actually assert when timing out, and the logic in `- [RCTBridgeTests tearDown];` was broken in such a way that tests would always take 5 seconds to run (and then timeout silently). This adds an assertion, and removes the broken nil check for `jsExecutor`.

Reviewed By: majak

Differential Revision: D2988885

fb-gh-sync-id: 91307585ac8acb0181f0cddeeddf6cb4b198e4fe
shipit-source-id: 91307585ac8acb0181f0cddeeddf6cb4b198e4fe
---
 Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m | 9 +++++----
 React/Modules/RCTDevMenu.m                               | 2 +-
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m
index 31fc8f74ee9e..f415f6da6130 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m
@@ -24,8 +24,12 @@
 #define RUN_RUNLOOP_WHILE(CONDITION) \
 { \
   NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:5]; \
-  while ((CONDITION) && [timeout timeIntervalSinceNow] > 0) { \
+  while ((CONDITION)) { \
     [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; \
+    if ([timeout timeIntervalSinceNow] <= 0) { \
+      XCTFail(@"Runloop timed out before condition was met"); \
+      break; \
+    } \
   } \
 }
 
@@ -140,9 +144,6 @@ - (void)tearDown
 
   [_bridge invalidate];
   _bridge = nil;
-
-  RUN_RUNLOOP_WHILE(_jsExecutor != nil);
-  XCTAssertNotNil(_jsExecutor);
 }
 
 - (void)testHookRegistration
diff --git a/React/Modules/RCTDevMenu.m b/React/Modules/RCTDevMenu.m
index 911bddce6478..5e1132a21df0 100644
--- a/React/Modules/RCTDevMenu.m
+++ b/React/Modules/RCTDevMenu.m
@@ -581,7 +581,7 @@ - (void)setLiveReloadEnabled:(BOOL)enabled
 
 - (BOOL)hotLoadingAvailable
 {
-  return !_bridge.bundleURL.fileURL; // Only works when running from server
+  return _bridge.bundleURL && !_bridge.bundleURL.fileURL; // Only works when running from server
 }
 
 - (void)setHotLoadingEnabled:(BOOL)enabled

From d7d47d812064d0db4b7d17070e0eca919cce11ce Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Mon, 29 Feb 2016 09:47:14 -0800
Subject: [PATCH 1345/1411] Defer constants gathering until after setup

Reviewed By: javache

Differential Revision: D2986095

fb-gh-sync-id: 1f449e69ca74466e7951d621ceaf624abe034139
shipit-source-id: 1f449e69ca74466e7951d621ceaf624abe034139
---
 React/Base/RCTBatchedBridge.m |  6 ++++++
 React/Base/RCTModuleData.h    |  8 ++++++++
 React/Base/RCTModuleData.m    | 21 ++++++++++++++-------
 3 files changed, 28 insertions(+), 7 deletions(-)

diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index 49c4dcb7c6d5..b574d62bed8b 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -342,6 +342,12 @@ - (void)initModules
     }
   }
 
+  for (RCTModuleData *moduleData in _moduleDataByID) {
+    if (moduleData.hasInstance) {
+      [moduleData gatherConstants];
+    }
+  }
+
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
 
diff --git a/React/Base/RCTModuleData.h b/React/Base/RCTModuleData.h
index ec922c8042c9..6d5b00c7aa97 100644
--- a/React/Base/RCTModuleData.h
+++ b/React/Base/RCTModuleData.h
@@ -37,6 +37,14 @@
  */
 - (void)finishSetupForInstance;
 
+/**
+ * Calls `constantsToExport` on the module and stores the result. Note that
+ * this will init the module if it has not already been created. This method
+ * can be called on any thread, but may block the main thread briefly if the
+ * module implements `constantsToExport`.
+ */
+- (void)gatherConstants;
+
 @property (nonatomic, strong, readonly) Class moduleClass;
 @property (nonatomic, copy, readonly) NSString *name;
 
diff --git a/React/Base/RCTModuleData.m b/React/Base/RCTModuleData.m
index 78ef8471e6f6..5175fb16d3b1 100644
--- a/React/Base/RCTModuleData.m
+++ b/React/Base/RCTModuleData.m
@@ -80,11 +80,6 @@ - (void)finishSetupForInstance
     [[NSNotificationCenter defaultCenter] postNotificationName:RCTDidInitializeModuleNotification
                                                         object:_bridge
                                                       userInfo:@{@"module": _instance}];
-
-    if (RCTClassOverridesInstanceMethod(_moduleClass, @selector(constantsToExport))) {
-      RCTAssertMainThread();
-      _constantsToExport = [_instance constantsToExport];
-    }
   }
 }
 
@@ -140,7 +135,6 @@ - (BOOL)hasInstance
   [_instanceLock unlock];
 
   [self finishSetupForInstance];
-
   return _instance;
 }
 
@@ -185,10 +179,23 @@ - (NSString *)name
   return _methods;
 }
 
+- (void)gatherConstants
+{
+  if (!_constantsToExport) {
+    if (RCTClassOverridesInstanceMethod(_moduleClass, @selector(constantsToExport))) {
+      RCTAssert(_instance, @"constantsToExport called before instance created.");
+      RCTExecuteOnMainThread(^{
+        _constantsToExport = [_instance constantsToExport] ?: @{};
+      }, YES);
+    } else {
+      _constantsToExport = @{};
+    }
+  }
+}
+
 - (NSArray *)config
 {
   __block NSDictionary<NSString *, id> *constants = _constantsToExport;
-  _constantsToExport = nil; // Not needed any more
 
   if (constants.count == 0 && self.methods.count == 0) {
     return (id)kCFNull; // Nothing to export

From f331a58ed0dc936dc597748f28f82c91838934ba Mon Sep 17 00:00:00 2001
From: Marc Horowitz <mhorowitz@fb.com>
Date: Mon, 29 Feb 2016 10:04:15 -0800
Subject: [PATCH 1346/1411] Move initialization of RCTBatchedBridge into its
 own method.

Summary: This makes room for local development without touching OSS code.

Reviewed By: tadeuzagallo

Differential Revision: D2986122

fb-gh-sync-id: 2f23088a078b0f0fb4b74946490fd5b67b01c0ac
shipit-source-id: 2f23088a078b0f0fb4b74946490fd5b67b01c0ac
---
 React/Base/RCTBridge.m | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m
index 650d3c958d63..2c3455d7c6a0 100644
--- a/React/Base/RCTBridge.m
+++ b/React/Base/RCTBridge.m
@@ -268,6 +268,11 @@ - (void)setUp
   // Sanitize the bundle URL
   _bundleURL = [RCTConvert NSURL:_bundleURL.absoluteString];
 
+  [self createBatchedBridge];
+}
+
+- (void)createBatchedBridge
+{
   self.batchedBridge = [[RCTBatchedBridge alloc] initWithParentBridge:self];
 }
 
@@ -288,7 +293,7 @@ - (BOOL)isBatchActive
 
 - (void)invalidate
 {
-  RCTBatchedBridge *batchedBridge = (RCTBatchedBridge *)self.batchedBridge;
+  RCTBridge *batchedBridge = self.batchedBridge;
   self.batchedBridge = nil;
 
   if (batchedBridge) {

From ffdd3e43b054c25c9b2263df31ff2997ad57f0bc Mon Sep 17 00:00:00 2001
From: Marc Horowitz <mhorowitz@fb.com>
Date: Mon, 29 Feb 2016 10:07:33 -0800
Subject: [PATCH 1347/1411] remove dead code

Summary: This property is now in the bridge.

Reviewed By: tadeuzagallo

Differential Revision: D2985894

fb-gh-sync-id: 38821e0c5998bc96fc8f6164fbbc82c721f5c5ad
shipit-source-id: 38821e0c5998bc96fc8f6164fbbc82c721f5c5ad
---
 React/Base/RCTRootView.h | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/React/Base/RCTRootView.h b/React/Base/RCTRootView.h
index ba1fe8712c53..de5908974719 100644
--- a/React/Base/RCTRootView.h
+++ b/React/Base/RCTRootView.h
@@ -83,13 +83,6 @@ extern NSString *const RCTContentDidAppearNotification;
  */
 @property (nonatomic, copy, readwrite) NSDictionary *appProperties;
 
-/**
- * The class of the RCTJavaScriptExecutor to use with this view.
- * If not specified, it will default to using RCTJSCExecutor.
- * Changes will take effect next time the bundle is reloaded.
- */
-@property (nonatomic, strong) Class executorClass;
-
 /**
  * The size flexibility mode of the root view.
  */

From 10e8e38677d78db24d71c747ee8a68de52fabd17 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Mon, 29 Feb 2016 11:12:12 -0800
Subject: [PATCH 1348/1411] Update GitHub issue guidelines

Reviewed By: mkonicek

Differential Revision:D2989742
Ninja: oss docs

fb-gh-sync-id: c9fc233b248d5ddda4c046d04cdfcafc3c97af90
shipit-source-id: c9fc233b248d5ddda4c046d04cdfcafc3c97af90
---
 bots/IssueGuidelines.md | 33 +++++++++++++++++++++------------
 1 file changed, 21 insertions(+), 12 deletions(-)

diff --git a/bots/IssueGuidelines.md b/bots/IssueGuidelines.md
index 35bf3a145dfd..3bdef613abee 100644
--- a/bots/IssueGuidelines.md
+++ b/bots/IssueGuidelines.md
@@ -1,37 +1,46 @@
 Use the following tips when responding to GitHub issues.
 
 ### An issue is a duplicate of another issue
-Comment e.g. `@facebook-github-bot /duplicate #123`. This will add a comment and close the issue.
-Example: #5977
+Comment e.g. `@facebook-github-bot duplicate #123`. This will add a comment and close the issue.
+Example: [#5977](https://github.com/facebook/react-native/issues/5977)
 
 ### An issue is a question
 StackOverflow is really good for Q&A. It has a reputation system and voting. Questions should absolutely be asked on StackOverflow rather than GitHub. However, to make this work we should hang out on StackOverflow every now and then and answer questions. A nice side effect is you'll get reputation for answering questions there rather than on GitHub.
-Comment `@facebook-github-bot /question` to close the issue.
-Examples: #6015, #6059, #6062
+Comment `@facebook-github-bot stack-overflow` to close the issue.
+Examples: [#6015](https://github.com/facebook/react-native/issues/6015), [#6059](https://github.com/facebook/react-native/issues/6059), [#6062](https://github.com/facebook/react-native/issues/6062)
 
 ### An issue is a question that's been answered
 Sometimes and issue has been resolved in the comments. Resolved issues should be closed.
-Comment `@facebook-github-bot /answered` to close it.
-Example: #6045
+Comment `@facebook-github-bot answered` to close it.
+Example: [#6045](https://github.com/facebook/react-native/issues/6045)
 
 ### An issue needs more information
 It is impossible to understand and reproduce the issue without more information, e.g. a short code sample, screenshot.
 Do the following:
 - Explain what additional info you need to understand the issue
-- Comment `@facebook-github-bot /add-label Needs more information`
-Examples: #6056, #6008, #5491
+- Comment `@facebook-github-bot label Needs more information`
+Examples: [#6056](https://github.com/facebook/react-native/issues/6056), [#6008](https://github.com/facebook/react-native/issues/6008), [#5491](https://github.com/facebook/react-native/issues/5491)
 
 ### An issue with label 'Needs more information' has been open for more than a week
-Comment mentioning the author asking if they plan to provide the additional information. If they don't come back close the issue using `@facebook-github-bot /no-reply`.
-Example: #6056
+Comment mentioning the author asking if they plan to provide the additional information. If they don't come back close the issue using `@facebook-github-bot no-reply`.
+Example: [#6056](https://github.com/facebook/react-native/issues/6056)
 
 ### Want to add a label
 Add any relevant labels, for example 'Android', 'iOS'.
-Comment e.g. `@facebook-github-bot /add-label Android`.
+Comment e.g. `@facebook-github-bot label Android`
 
 ### Want to reopen a closed issue
 For example an issue was closed waiting for the author, the author replied and it turns out this is indeed a bug.
-Comment `@facebook-github-bot /reopen`
+Comment `@facebook-github-bot reopen`
+
+### An issue is a valid bug report
+Yes, there are issues that have good repro information and describe an actual bug :) These are some of the highest quality issues! Thank the author for finding it, politely explain that React Native is a community project and ask them if they would be up for sending a fix.
+
+### An issue is a feature request and you're pretty sure React Native should have that feature
+Tell the author that: Pull requests are welcome. If they're not up for sending a PR, they should post to [Product Pains](https://productpains.com/product/react-native/?tab=top). It has a voting system and if the feature gets upvoted enough it might get implemented.
+
+### An issue is a feature request for feature we don't want
+This especially includes **new modules** Facebook doesn't use in production. Explain that those modules should be released to npm separately and that everyone will still be able to use the module super easily that way.
 
 ### Commands for the bot
 When you mention the bot, it follows the commands defined in [IssueCommands.txt](https://github.com/facebook/react-native/blob/master/bots/IssueCommands.txt).

From d03338073f034d8045934d63613f2750056fb573 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Mon, 29 Feb 2016 11:37:12 -0800
Subject: [PATCH 1349/1411] Tweak wording of issue guidelines

Reviewed By: mkonicek

Differential Revision:D2990021
Ninja: oss docs

fb-gh-sync-id: ba79d6b78c55439fc1dbbf081d93edad84690f73
shipit-source-id: ba79d6b78c55439fc1dbbf081d93edad84690f73
---
 bots/IssueGuidelines.md | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/bots/IssueGuidelines.md b/bots/IssueGuidelines.md
index 3bdef613abee..1453ebd0cccf 100644
--- a/bots/IssueGuidelines.md
+++ b/bots/IssueGuidelines.md
@@ -25,22 +25,22 @@ Examples: [#6056](https://github.com/facebook/react-native/issues/6056), [#6008]
 Comment mentioning the author asking if they plan to provide the additional information. If they don't come back close the issue using `@facebook-github-bot no-reply`.
 Example: [#6056](https://github.com/facebook/react-native/issues/6056)
 
-### Want to add a label
-Add any relevant labels, for example 'Android', 'iOS'.
-Comment e.g. `@facebook-github-bot label Android`
-
-### Want to reopen a closed issue
-For example an issue was closed waiting for the author, the author replied and it turns out this is indeed a bug.
-Comment `@facebook-github-bot reopen`
-
 ### An issue is a valid bug report
-Yes, there are issues that have good repro information and describe an actual bug :) These are some of the highest quality issues! Thank the author for finding it, politely explain that React Native is a community project and ask them if they would be up for sending a fix.
+Valid bug reports with good repro steps are some of the best issues! Thank the author for finding it, explain that React Native is a community project and ask them if they would be up for sending a fix.
 
 ### An issue is a feature request and you're pretty sure React Native should have that feature
-Tell the author that: Pull requests are welcome. If they're not up for sending a PR, they should post to [Product Pains](https://productpains.com/product/react-native/?tab=top). It has a voting system and if the feature gets upvoted enough it might get implemented.
+Tell the author something like: "Pull requests are welcome. In case you're not up for sending a PR, you should post to [Product Pains](https://productpains.com/product/react-native/?tab=top). It has a voting system and if the feature gets upvoted enough it might get implemented."
 
-### An issue is a feature request for feature we don't want
+### An issue is a feature request for a feature we don't want
 This especially includes **new modules** Facebook doesn't use in production. Explain that those modules should be released to npm separately and that everyone will still be able to use the module super easily that way.
 
-### Commands for the bot
+### How to add a label
+Add any relevant labels, for example 'Android', 'iOS'.
+Comment e.g. `@facebook-github-bot label Android`
+
+### How to reopen a closed issue
+For example an issue was closed waiting for the author, the author replied and it turns out this is indeed a bug.
+Comment `@facebook-github-bot reopen`
+
+### What are all the available commands for the bot?
 When you mention the bot, it follows the commands defined in [IssueCommands.txt](https://github.com/facebook/react-native/blob/master/bots/IssueCommands.txt).

From 86d6d54cb50d27747d093b3a2276eedc76a4d401 Mon Sep 17 00:00:00 2001
From: Peter Piekarczyk <ppiekarczyk@users.noreply.github.com>
Date: Mon, 29 Feb 2016 11:39:26 -0800
Subject: [PATCH 1350/1411] Add React.js 2016 Conf videos

Summary:Here are all the conference videos for 2016.

Thanks!
Closes https://github.com/facebook/react-native/pull/6177

Differential Revision: D2989805

Pulled By: mkonicek

fb-gh-sync-id: ebc0d652706d579b3823be91bd00766053bfad55
shipit-source-id: ebc0d652706d579b3823be91bd00766053bfad55
---
 docs/Videos.md | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/docs/Videos.md b/docs/Videos.md
index 488c16f1adcb..aec0c770fe91 100644
--- a/docs/Videos.md
+++ b/docs/Videos.md
@@ -7,6 +7,35 @@ permalink: docs/videos.html
 next: style
 ---
 
+### React.js Conf 2016
+
+<iframe width="650" height="315" src="//www.youtube.com/embed/2Zthnq-hIXA" frameborder="0" allowfullscreen></iframe>
+
+<iframe width="650" height="315" src="//www.youtube.com/embed/Xnqy_zkBAew" frameborder="0" allowfullscreen></iframe>
+
+<iframe width="650" height="315" src="//www.youtube.com/embed/RBg2_uQE4KM" frameborder="0" allowfullscreen></iframe>
+
+<iframe width="650" height="315" src="//www.youtube.com/embed/0MlT74erp60" frameborder="0" allowfullscreen></iframe>
+
+<iframe width="650" height="315" src="//www.youtube.com/embed/B8J8xn3pLpk" frameborder="0" allowfullscreen></iframe>
+
+<iframe width="650" height="315" src="//www.youtube.com/embed/f1Sj48rJE3I" frameborder="0" allowfullscreen></iframe>
+
+<iframe width="650" height="315" src="//www.youtube.com/embed/uBYPqb83C7k" frameborder="0" allowfullscreen></iframe>
+
+<iframe width="650" height="315" src="//www.youtube.com/embed/09ddrCaLo10" frameborder="0" allowfullscreen></iframe>
+
+<iframe width="650" height="315" src="//www.youtube.com/embed/d3VVfA9hWjc" frameborder="0" allowfullscreen></iframe>
+
+<iframe width="650" height="315" src="//www.youtube.com/embed/impQkQOCbMw" frameborder="0" allowfullscreen></iframe>
+
+<iframe width="650" height="315" src="//www.youtube.com/embed/wuLKELLuwVk" frameborder="0" allowfullscreen></iframe>
+
+<iframe width="650" height="315" src="//www.youtube.com/embed/Zoerbz5Mu5U" frameborder="0" allowfullscreen></iframe>
+
+
+### React.js Conf 2015 
+
 <iframe width="650" height="315" src="//www.youtube.com/embed/KVZ-P-ZI6W4" frameborder="0" allowfullscreen></iframe>
 
 <iframe width="650" height="315" src="//www.youtube.com/embed/7rDsRXj9-cU" frameborder="0" allowfullscreen></iframe>

From e55cefc476e720dd3c3b1726f21d2b63ee41a19c Mon Sep 17 00:00:00 2001
From: Chris Hopman <cjhopman@fb.com>
Date: Mon, 29 Feb 2016 12:46:35 -0800
Subject: [PATCH 1351/1411] Add log message to bridge init

Reviewed By: mhorowitz

Differential Revision: D2983352

fb-gh-sync-id: d87fcb7d7728115ae45cdb6f061fa094da7dfba8
shipit-source-id: d87fcb7d7728115ae45cdb6f061fa094da7dfba8
---
 .../java/com/facebook/react/bridge/CatalystInstanceImpl.java     | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
index cbf259f29a82..18291a66f524 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
@@ -71,6 +71,7 @@ private CatalystInstanceImpl(
       final JavaScriptModulesConfig jsModulesConfig,
       final JSBundleLoader jsBundleLoader,
       NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
+    FLog.d(ReactConstants.TAG, "Initializing React Bridge.");
     mReactQueueConfiguration = ReactQueueConfigurationImpl.create(
         ReactQueueConfigurationSpec,
         new NativeExceptionHandler());

From 73bdef4089d6290c5146b265b3df5719410788e1 Mon Sep 17 00:00:00 2001
From: Hedger Wang <hedger@fb.com>
Date: Mon, 29 Feb 2016 13:21:43 -0800
Subject: [PATCH 1352/1411] Unify scene rederer params that are used render the
 scene / header.

Reviewed By: fkgozali

Differential Revision: D2981045

fb-gh-sync-id: 21688d92e31d882c5a31dd83ca064c2a01837164
shipit-source-id: 21688d92e31d882c5a31dd83ca064c2a01837164
---
 .../NavigationAnimatedExample.js              | 25 ++++----
 .../NavigationCardStackExample.js             |  4 +-
 .../NavigationCompositionExample.js           | 21 ++++---
 .../NavigationExperimentalExample.js          |  8 +--
 Examples/UIExplorer/UIExplorerApp.ios.js      | 54 +++++++----------
 .../NavigationCardStack.js                    | 28 ++++-----
 .../NavigationAnimatedView.js                 | 58 ++++++++++++-------
 7 files changed, 103 insertions(+), 95 deletions(-)

diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
index 3054a8a976e4..e74d80e26306 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
@@ -74,31 +74,34 @@ class NavigationAnimatedExample extends React.Component {
       <NavigationAnimatedView
         navigationState={navigationState}
         style={styles.animatedView}
-        renderOverlay={(position, layout) => (
+        renderOverlay={(props) => (
           <NavigationHeader
-            navigationState={navigationState}
-            position={position}
+            navigationState={props.navigationParentState}
+            position={props.position}
             getTitle={state => state.key}
           />
         )}
         setTiming={(pos, navState) => {
           Animated.timing(pos, {toValue: navState.index, duration: 1000}).start();
         }}
-        renderScene={(state, index, position, layout) => (
+        renderScene={(props) => (
           <NavigationCard
-            key={state.key}
-            index={index}
-            navigationState={navigationState}
-            position={position}
-            layout={layout}>
+            key={props.navigationState.key}
+            index={props.index}
+            navigationState={props.navigationParentState}
+            position={props.position}
+            layout={props.layout}>
             <ScrollView style={styles.scrollView}>
               <NavigationExampleRow
-                text={navigationState.children[navigationState.index].key}
+                text={props.navigationState.key}
               />
               <NavigationExampleRow
                 text="Push!"
                 onPress={() => {
-                  onNavigate({ type: 'push', key: 'Route #' + navigationState.children.length });
+                  onNavigate({
+                    type: 'push',
+                    key: 'Route #' + props.navigationParentState.children.length
+                  });
                 }}
               />
               <NavigationExampleRow
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationCardStackExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationCardStackExample.js
index 2063e76151f6..94a6735d05ca 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationCardStackExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationCardStackExample.js
@@ -79,11 +79,11 @@ class NavigationCardStackExample extends React.Component {
     });
   }
 
-  _renderScene(navigationState, index, position, layout) {
+  _renderScene(props) {
     return (
       <ScrollView style={styles.scrollView}>
         <NavigationExampleRow
-          text={JSON.stringify(navigationState)}
+          text={JSON.stringify(props.navigationState)}
         />
         <NavigationExampleRow
           text="Push Route"
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js
index 1dba3e14ac86..bc1d184db5de 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js
@@ -154,25 +154,24 @@ class ExampleTabScreen extends React.Component {
       />
     );
   }
-  _renderHeader(position, layout) {
+  _renderHeader(props) {
     return (
       <NavigationHeader
-        navigationState={this.props.navigationState}
-        position={position}
-        layout={layout}
+        navigationState={props.navigationParentState}
+        position={props.position}
+        layout={props.layout}
         getTitle={state => stateTypeTitleMap(state)}
       />
     );
   }
-  _renderScene(child, index, position, layout) {
+  _renderScene(props) {
     return (
       <NavigationCard
-        key={child.key}
-        index={index}
-        childState={child}
-        navigationState={this.props.navigationState}
-        position={position}
-        layout={layout}>
+        key={props.navigationState.key}
+        index={props.index}
+        navigationState={props.navigationParentState}
+        position={props.position}
+        layout={props.layout}>
         <ScrollView style={styles.scrollView}>
           <NavigationExampleRow
             text="Open page"
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js
index f90ab6ef76a8..0781570da28d 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationExperimentalExample.js
@@ -30,13 +30,13 @@ var NavigationExampleRow = require('./NavigationExampleRow');
 var EXAMPLES = {
   'Tabs': require('./NavigationTabsExample'),
   'Basic': require('./NavigationBasicExample'),
-  'Animated Card Stack': require('./NavigationAnimatedExample'),
+  'Animated Example': require('./NavigationAnimatedExample'),
   'Composition': require('./NavigationCompositionExample'),
   'Card Stack Example': require('./NavigationCardStackExample'),
   'Tic Tac Toe': require('./NavigationTicTacToeExample'),
 };
 
-var EXAMPLE_STORAGE_KEY = 'xNavigationExperimentalExample';
+var EXAMPLE_STORAGE_KEY = 'NavigationExperimentalExample';
 
 var NavigationExperimentalExample = React.createClass({
   statics: {
@@ -47,13 +47,13 @@ var NavigationExperimentalExample = React.createClass({
 
   getInitialState: function() {
     return {
-      exampe: null,
+      example: null,
     };
   },
 
   componentDidMount() {
     AsyncStorage.getItem(EXAMPLE_STORAGE_KEY, (err, example) => {
-      if (err || !example) {
+      if (err || !example || !EXAMPLES[example]) {
         this.setState({
           example: 'menu',
         });
diff --git a/Examples/UIExplorer/UIExplorerApp.ios.js b/Examples/UIExplorer/UIExplorerApp.ios.js
index 5a1733d433f4..3bfb2e28a5d5 100644
--- a/Examples/UIExplorer/UIExplorerApp.ios.js
+++ b/Examples/UIExplorer/UIExplorerApp.ios.js
@@ -34,6 +34,7 @@ const {
   TouchableHighlight,
   View,
 } = React;
+
 const {
   AnimatedView: NavigationAnimatedView,
   Card: NavigationCard,
@@ -41,19 +42,14 @@ const {
   Reducer: NavigationReducer,
   RootContainer: NavigationRootContainer,
 } = NavigationExperimental;
-const StackReducer = NavigationReducer.StackReducer;
-
-import type {
-  NavigationState,
-} from 'NavigationStateUtils'
 
 import type { Value } from 'Animated';
-import type { Layout } from 'NavigationAnimatedView';
+
+import type { NavigationStateRendererProps } from 'NavigationAnimatedView';
+
 import type { UIExplorerNavigationState } from './UIExplorerNavigationReducer';
 
-import type {
-  UIExplorerExample,
-} from './UIExplorerList.ios'
+import type { UIExplorerExample } from './UIExplorerList.ios';
 
 function PathActionMap(path: string): ?Object {
   // Warning! Hacky parsing for example code. Use a library for this!
@@ -86,8 +82,12 @@ function URIActionMap(uri: ?string): ?Object {
 class UIExplorerApp extends React.Component {
   _navigationRootRef: ?NavigationRootContainer;
   _renderNavigation: Function;
+  _renderOverlay: Function;
+  _renderScene: Function;
   componentWillMount() {
     this._renderNavigation = this._renderNavigation.bind(this);
+    this._renderOverlay = this._renderOverlay.bind(this);
+    this._renderScene = this._renderScene.bind(this);
   }
   render() {
     return (
@@ -119,41 +119,31 @@ class UIExplorerApp extends React.Component {
       <NavigationAnimatedView
         navigationState={stack}
         style={styles.container}
-        renderOverlay={this._renderOverlay.bind(this, stack)}
-        renderScene={this._renderSceneContainer.bind(this, stack)}
+        renderOverlay={this._renderOverlay}
+        renderScene={this._renderScene}
       />
     );
   }
 
-  _renderOverlay(
-    navigationState: NavigationState,
-    position: Value,
-    layout: Layout
-  ): ReactElement {
+  _renderOverlay(props: NavigationStateRendererProps): ReactElement {
     return (
       <NavigationHeader
-        navigationState={navigationState}
-        position={position}
+        navigationState={props.navigationParentState}
+        position={props.position}
         getTitle={UIExplorerStateTitleMap}
       />
-    );    
+    );
   }
 
-  _renderSceneContainer(
-    navigationState: NavigationState,
-    scene: NavigationState,
-    index: number,
-    position: Value,
-    layout: Layout
-  ): ReactElement {
+  _renderOverlay(props: NavigationStateRendererProps): ReactElement {
     return (
       <NavigationCard
-        key={scene.key}
-        index={index}
-        navigationState={navigationState}
-        position={position}
-        layout={layout}>
-        {this._renderScene(scene)}
+        index={props.index}
+        key={props.navigationState.key}
+        layout={props.layout}
+        navigationState={props.navigationParentState}
+        position={props.position}>
+        {this._renderScene(props.navigationState)}
       </NavigationCard>
     );
   }
diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationCardStack.js b/Libraries/CustomComponents/NavigationExperimental/NavigationCardStack.js
index f2cabdda8392..b4e53a63a470 100644
--- a/Libraries/CustomComponents/NavigationExperimental/NavigationCardStack.js
+++ b/Libraries/CustomComponents/NavigationExperimental/NavigationCardStack.js
@@ -44,22 +44,22 @@ import type {
 
 import type {
   Layout,
-  OverlayRenderer,
+  NavigationStateRenderer,
+  NavigationStateRendererProps,
   Position,
-  SceneRenderer,
 } from 'NavigationAnimatedView';
 
 type Props = {
   navigationState: NavigationParentState,
-  renderOverlay: OverlayRenderer,
-  renderScene: SceneRenderer,
+  renderOverlay: NavigationStateRenderer,
+  renderScene: NavigationStateRenderer,
 };
 
 /**
  * A controlled navigation view that renders a list of cards.
  */
 class NavigationCardStack extends React.Component {
-  _renderScene : SceneRenderer;
+  _renderScene : NavigationStateRenderer;
 
   constructor(props: Props, context: any) {
     super(props, context);
@@ -77,20 +77,22 @@ class NavigationCardStack extends React.Component {
     );
   }
 
-  _renderScene(
-    navigationState: NavigationState,
-    index: number,
-    position: Position,
-    layout: Layout,
-  ): ReactElement {
+  _renderScene(props: NavigationStateRendererProps): ReactElement {
+    const {
+      index,
+      layout,
+      navigationParentState,
+      navigationState,
+      position,
+    } = props;
     return (
       <NavigationCard
         key={navigationState.key}
         index={index}
-        navigationState={navigationState}
+        navigationState={navigationParentState}
         position={position}
         layout={layout}>
-        {this.props.renderScene(navigationState, index, position, layout)}
+        {this.props.renderScene(props)}
       </NavigationCard>
     );
   }
diff --git a/Libraries/NavigationExperimental/NavigationAnimatedView.js b/Libraries/NavigationExperimental/NavigationAnimatedView.js
index a1f5df0f3772..b19502166eda 100644
--- a/Libraries/NavigationExperimental/NavigationAnimatedView.js
+++ b/Libraries/NavigationExperimental/NavigationAnimatedView.js
@@ -70,30 +70,39 @@ type Layout = {
   height: Animated.Value;
 };
 
-type OverlayRenderer = (
-  position: Animated.Value,
-  layout: Layout
-) => ReactElement;
-
 type Position = Animated.Value;
 
-type SceneRenderer = (
-  state: NavigationState,
+/**
+ * Definition of the props object that is passed to the functions
+ * that render the overlay and the scene.
+ */
+type NavigationStateRendererProps = {
+  // The state of the child view.
+  navigationState: NavigationState,
+  // The index of the child view.
   index: number,
+  // The "progressive index" of the containing navigation state.
   position: Position,
-  layout: Layout
+  // The layout of the the containing navigation view.
+  layout: Layout,
+  // The state of the the containing navigation view.
+  navigationParentState: NavigationParentState,
+};
+
+type NavigationStateRenderer = (
+  props: NavigationStateRendererProps,
 ) => ReactElement;
 
 type TimingSetter = (
   position: Animated.Value,
   newState: NavigationParentState,
-  lastState: NavigationParentState
+  lastState: NavigationParentState,
 ) => void;
 
 type Props = {
   navigationState: NavigationParentState;
-  renderScene: SceneRenderer;
-  renderOverlay: ?OverlayRenderer;
+  renderScene: NavigationStateRenderer;
+  renderOverlay: ?NavigationStateRenderer;
   style: any;
   setTiming: ?TimingSetter;
 };
@@ -194,7 +203,7 @@ class NavigationAnimatedView extends React.Component {
         }}
         style={this.props.style}>
         {this.state.scenes.map(this._renderScene, this)}
-        {this._renderOverlay(this._renderOverlay, this)}
+        {this._renderOverlay()}
       </View>
     );
   }
@@ -207,20 +216,25 @@ class NavigationAnimatedView extends React.Component {
     };
   }
   _renderScene(scene: NavigationScene) {
-    return this.props.renderScene(
-      scene.state,
-      scene.index,
-      this.state.position,
-      this._getLayout()
-    );
+    return this.props.renderScene({
+      index: scene.index,
+      layout: this._getLayout(),
+      navigationParentState: this.props.navigationState,
+      navigationState: scene.state,
+      position: this.state.position,
+    });
   }
   _renderOverlay() {
     const {renderOverlay} = this.props;
     if (renderOverlay) {
-      return renderOverlay(
-        this.state.position,
-        this._getLayout()
-      );
+      const parentState = this.props.navigationState;
+      return renderOverlay({
+        index: parentState.index,
+        layout: this._getLayout(),
+        navigationParentState: parentState,
+        navigationState: parentState.children[parentState.index],
+        position: this.state.position,
+      });
     }
     return null;
   }

From f130a365e6c7106a9a05707b1b861356c47fff95 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Mon, 29 Feb 2016 14:03:07 -0800
Subject: [PATCH 1353/1411] Update known issues

Summary: CameraRoll and Spinner have been released.

Reviewed By: mkonicek

Differential Revision:D2990290
Ninja: oss docs

fb-gh-sync-id: c0611a112f5488b1a7bcb67b6b39099200e7a14e
shipit-source-id: c0611a112f5488b1a7bcb67b6b39099200e7a14e
---
 docs/KnownIssues.md | 20 ++++++--------------
 1 file changed, 6 insertions(+), 14 deletions(-)

diff --git a/docs/KnownIssues.md b/docs/KnownIssues.md
index 8a2616c023ff..fb205cb2be30 100644
--- a/docs/KnownIssues.md
+++ b/docs/KnownIssues.md
@@ -15,26 +15,18 @@ However, you can still use the Console feature of the devtools, and debugging Ja
 
 ### Missing Modules and Native Views
 
-This is an initial release of React Native Android and therefore not all of the views present on iOS are released on Android. We are very much interested in the communities' feedback on the next set of modules and views for Open Source. Not all native views between iOS and Android have a 100% equivalent representation, here it will be necessary to use a counterpart eg using ProgressBar on Android in place of ActivityIndicator on iOS.
-
-Our provisional plan for common views and modules includes:
+The work on React Native for Android started later than React Native for iOS. Not all of the views present on iOS have been released on Android yet.
 
 #### Views
 
-```
-Maps
-Modal
-Spinner (http://developer.android.com/guide/topics/ui/controls/spinner.html)
-Slider (known as SeekBar)
-```
+- Maps - Please use Leland Richardson's [react-native-maps](https://github.com/lelandrichardson/react-native-maps) as it is more feature-complete than our internal implementation at fb.
+- Modal
+- Slider (also known as SeekBar)
 
 #### Modules
 
-```
-Camera Roll
-Media
-PushNotificationIOS
-```
+- Media
+- PushNotificationIOS
 
 ### Some props are only supported on one platform
 

From 9be1216c7f8e81f6b074e17d0c8380e11f58d1e7 Mon Sep 17 00:00:00 2001
From: Ahmed El-Helw <ahmedre@fb.com>
Date: Mon, 29 Feb 2016 16:42:21 -0800
Subject: [PATCH 1354/1411] Minor code improvements for RCTTextInput

Summary: Expose hasUnseenUpdates in ReactShadowNode. Various text input cleanup and fixes.

Differential Revision: D2975870

fb-gh-sync-id: 26c4c0d36e82aaa025b4760603cc48c47ebf46a3
shipit-source-id: 26c4c0d36e82aaa025b4760603cc48c47ebf46a3
---
 .../java/com/facebook/react/uimanager/ReactShadowNode.java    | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java
index eb287bef45a1..df8ad675d294 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java
@@ -105,6 +105,10 @@ protected void markUpdated() {
     }
   }
 
+  public boolean hasUnseenUpdates() {
+    return mNodeUpdated;
+  }
+
   @Override
   protected void dirty() {
     if (!isVirtual()) {

From 7e3266d7de976aedccafa2fdcaa53b43e04cecb1 Mon Sep 17 00:00:00 2001
From: Rui Chen <halfjuice@fb.com>
Date: Mon, 29 Feb 2016 18:02:11 -0800
Subject: [PATCH 1355/1411] Fix attributes checking for Image.android.js

Reviewed By: sahrens

Differential Revision: D2975018

fb-gh-sync-id: 226f2d3d3dcb538f0c3967346a9b226960c1d15c
shipit-source-id: 226f2d3d3dcb538f0c3967346a9b226960c1d15c
---
 Libraries/Image/Image.android.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Libraries/Image/Image.android.js b/Libraries/Image/Image.android.js
index fdc8c2f64cec..566e95d72c59 100644
--- a/Libraries/Image/Image.android.js
+++ b/Libraries/Image/Image.android.js
@@ -121,14 +121,14 @@ var Image = React.createClass({
    */
   viewConfig: {
     uiViewClassName: 'RCTView',
-    validAttributes: ReactNativeViewAttributes.RKView
+    validAttributes: ReactNativeViewAttributes.RCTView,
   },
 
   _updateViewConfig: function(props) {
     if (props.children) {
       this.viewConfig = {
         uiViewClassName: 'RCTView',
-        validAttributes: ReactNativeViewAttributes.RKView,
+        validAttributes: ReactNativeViewAttributes.RCTView,
       };
     } else {
       this.viewConfig = {

From a72c2950d6719d44dee2750b70605901cdf3eb07 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Tue, 1 Mar 2016 03:20:54 -0800
Subject: [PATCH 1356/1411] babel-preset-react-native: Make sure that
 `react-transform-hmr/lib/index.js` is included correctly for every module in
 the bundle
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Summary:This imports `react-transform-hmr/lib/index.js` with a relative path from every module, to make sure we don’t rely on the current (broken) behaviour.

It works now, because:
- the dependency is added by a transform
- we extract dependencies before transforming
- we include `react-transform-hmr/lib/index.js` manually
- packager incorrectly names modules by the name of their package (i.e. packages with multiple versions overwrite each other)

This blocks transforming before extracting dependencies, switching to numeric module IDs, and unbundling/random access bundles.

Reviewed By: bestander

Differential Revision: D2994024

fb-gh-sync-id: 23c56397b768775ff56e3d6924f50a9e39e8ce8c
shipit-source-id: 23c56397b768775ff56e3d6924f50a9e39e8ce8c
---
 babel-preset/configs/hmr.js | 11 +++++++++--
 babel-preset/package.json   |  2 +-
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/babel-preset/configs/hmr.js b/babel-preset/configs/hmr.js
index 2a4bb9a93703..e88e2c67d5be 100644
--- a/babel-preset/configs/hmr.js
+++ b/babel-preset/configs/hmr.js
@@ -8,16 +8,23 @@
  */
 'use strict';
 
+var path = require('path');
 var resolvePlugins = require('../lib/resolvePlugins');
 
-module.exports = function(options) {
+var hmrTransform = 'react-transform-hmr/lib/index.js';
+var transformPath = require.resolve(hmrTransform);
+
+module.exports = function(options, filename) {
+  var transform = filename
+      ? path.relative(path.dirname(filename), transformPath) // packager can't handle absolute paths
+      : hmrTransform;
   return {
     plugins: resolvePlugins([
       [
         'react-transform',
         {
           transforms: [{
-            transform: 'react-transform-hmr/lib/index.js',
+            transform: transform,
             imports: ['React'],
             locals: ['module'],
           }]
diff --git a/babel-preset/package.json b/babel-preset/package.json
index 0ab0579b1532..00d24728afdd 100644
--- a/babel-preset/package.json
+++ b/babel-preset/package.json
@@ -1,6 +1,6 @@
 {
   "name": "babel-preset-react-native",
-  "version": "1.4.0",
+  "version": "1.5.0",
   "description": "Babel preset for React Native applications",
   "main": "index.js",
   "repository": "https://github.com/facebook/react-native/tree/master/babel-preset",

From 58f86b2d91f5e0cde43166c3bb6b0d02bd5e918f Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Tue, 1 Mar 2016 04:25:24 -0800
Subject: [PATCH 1357/1411] Don't execute things that may throw in
 Bridge/JSCExecutor dtors

Summary:In testing, I've found that there's no good way to return stack traces to the server for exceptions that happen in dtor's. If the dtor is not marked nothrow(false), the exceptions are uncatchable (and bubble up as a std::abort without exception info) and if annotated properly, the program instead crashes trying to resume the stack, again a std::abort without exception info.

Instead, I created a separate destroy method that can be called (and protected via fbjni) to make the dtor's no longer execute code that may throw. Note that we don't really expect the code that was previously in ~JSCExecutor() to throw, but it was in production and we had absolutely no info to help debug it.

Reviewed By: mhorowitz

Differential Revision: D2989999

fb-gh-sync-id: 4cf9de5e0592fe6830a9903375363a78e1339a94
shipit-source-id: 4cf9de5e0592fe6830a9903375363a78e1339a94
---
 .../react/bridge/CatalystInstanceImpl.java    |  1 +
 .../facebook/react/bridge/ReactBridge.java    |  1 +
 ReactAndroid/src/main/jni/react/Bridge.cpp    |  9 ++++++--
 ReactAndroid/src/main/jni/react/Bridge.h      |  5 +++++
 ReactAndroid/src/main/jni/react/Executor.h    |  1 +
 .../src/main/jni/react/JSCExecutor.cpp        | 21 ++++++++++---------
 ReactAndroid/src/main/jni/react/JSCExecutor.h |  1 +
 ReactAndroid/src/main/jni/react/Platform.cpp  |  4 ----
 ReactAndroid/src/main/jni/react/Platform.h    |  5 -----
 .../src/main/jni/react/jni/OnLoad.cpp         | 13 +++++++++---
 10 files changed, 37 insertions(+), 24 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
index 18291a66f524..40618ac95c15 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
@@ -235,6 +235,7 @@ private void synchronouslyDisposeBridgeOnJSThread() {
         new Runnable() {
           @Override
           public void run() {
+            mBridge.destroy();
             mBridge.dispose();
             bridgeDisposeFuture.set(null);
           }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java
index 89b6870bec7a..1e9fe67482db 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java
@@ -87,6 +87,7 @@ private native void initialize(
   public native void stopProfiler(String title, String filename);
   private native void handleMemoryPressureModerate();
   private native void handleMemoryPressureCritical();
+  public native void destroy();
 
   /**
    * This method will return a long representing the underlying JSGlobalContextRef pointer or
diff --git a/ReactAndroid/src/main/jni/react/Bridge.cpp b/ReactAndroid/src/main/jni/react/Bridge.cpp
index 1c1a2bf34dda..ed758d1f0079 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.cpp
+++ b/ReactAndroid/src/main/jni/react/Bridge.cpp
@@ -22,8 +22,7 @@ Bridge::Bridge(JSExecutorFactory* jsExecutorFactory, Callback callback) :
 
 // This must be called on the same thread on which the constructor was called.
 Bridge::~Bridge() {
-  *m_destroyed = true;
-  m_mainExecutor.reset();
+  CHECK(*m_destroyed) << "Bridge::destroy() must be called before deallocating the Bridge!";
 }
 
 void Bridge::loadApplicationScript(const std::string& script, const std::string& sourceURL) {
@@ -132,4 +131,10 @@ void Bridge::callNativeModules(const std::string& callJSON, bool isEndOfBatch) {
   m_callback(parseMethodCalls(callJSON), isEndOfBatch);
 }
 
+void Bridge::destroy() {
+  *m_destroyed = true;
+  m_mainExecutor->destroy();
+  m_mainExecutor.reset();
+}
+
 } }
diff --git a/ReactAndroid/src/main/jni/react/Bridge.h b/ReactAndroid/src/main/jni/react/Bridge.h
index 3868d507ff73..16edc62ac10c 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.h
+++ b/ReactAndroid/src/main/jni/react/Bridge.h
@@ -74,6 +74,11 @@ class Bridge {
    * TODO: get rid of isEndOfBatch
    */
   void callNativeModules(const std::string& callJSON, bool isEndOfBatch);
+
+  /**
+   * Synchronously tears down the bridge and the main executor.
+   */
+  void destroy();
 private:
   Callback m_callback;
   // This is used to avoid a race condition where a proxyCallback gets queued after ~Bridge(),
diff --git a/ReactAndroid/src/main/jni/react/Executor.h b/ReactAndroid/src/main/jni/react/Executor.h
index 036b6414ea69..6f392a3cd8fa 100644
--- a/ReactAndroid/src/main/jni/react/Executor.h
+++ b/ReactAndroid/src/main/jni/react/Executor.h
@@ -72,6 +72,7 @@ class JSExecutor {
   virtual void handleMemoryPressureCritical() {
     handleMemoryPressureModerate();
   };
+  virtual void destroy() {};
   virtual ~JSExecutor() {};
 };
 
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index 56af90b9bfdd..01ccc8188928 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -126,17 +126,17 @@ JSCExecutor::JSCExecutor(
 }
 
 JSCExecutor::~JSCExecutor() {
-  try {
-    *m_isDestroyed = true;
-    if (m_messageQueueThread->isOnThread()) {
+  CHECK(*m_isDestroyed) << "JSCExecutor::destroy() must be called before its destructor!";
+}
+
+void JSCExecutor::destroy() {
+  *m_isDestroyed = true;
+  if (m_messageQueueThread->isOnThread()) {
+    terminateOnJSVMThread();
+  } else {
+    m_messageQueueThread->runOnQueueSync([this] () {
       terminateOnJSVMThread();
-    } else {
-      m_messageQueueThread->runOnQueueSync([this] () {
-        terminateOnJSVMThread();
-      });
-    }
-  } catch (...) {
-    Exceptions::handleUncaughtException();
+    });
   }
 }
 
@@ -392,6 +392,7 @@ void JSCExecutor::receiveMessageFromOwner(const std::string& msgString) {
 void JSCExecutor::terminateOwnedWebWorker(int workerId) {
   auto worker = m_ownedWorkers.at(workerId).getExecutor();
   std::shared_ptr<MessageQueueThread> workerMQT = worker->m_messageQueueThread;
+  worker->destroy();
   m_ownedWorkers.erase(workerId);
   workerMQT->quitSynchronous();
 }
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.h b/ReactAndroid/src/main/jni/react/JSCExecutor.h
index 33622014458b..a10907ccff0d 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.h
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.h
@@ -75,6 +75,7 @@ class JSCExecutor : public JSExecutor {
   virtual void stopProfiler(const std::string &titleString, const std::string &filename) override;
   virtual void handleMemoryPressureModerate() override;
   virtual void handleMemoryPressureCritical() override;
+  virtual void destroy() override;
 
   void installNativeHook(const char *name, JSObjectCallAsFunctionCallback callback);
 
diff --git a/ReactAndroid/src/main/jni/react/Platform.cpp b/ReactAndroid/src/main/jni/react/Platform.cpp
index 3e1c700b78b5..ace85bd92423 100644
--- a/ReactAndroid/src/main/jni/react/Platform.cpp
+++ b/ReactAndroid/src/main/jni/react/Platform.cpp
@@ -26,8 +26,4 @@ namespace JSLogging {
 JSCNativeHook nativeHook = nullptr;
 };
 
-namespace Exceptions {
-HandleUncaughtException handleUncaughtException;
-};
-
 } }
diff --git a/ReactAndroid/src/main/jni/react/Platform.h b/ReactAndroid/src/main/jni/react/Platform.h
index 5ad664dbfe5e..608fbc1a854d 100644
--- a/ReactAndroid/src/main/jni/react/Platform.h
+++ b/ReactAndroid/src/main/jni/react/Platform.h
@@ -46,9 +46,4 @@ namespace JSLogging {
   extern JSCNativeHook nativeHook;
 };
 
-namespace Exceptions {
-  using HandleUncaughtException = std::function<void()>;
-  extern HandleUncaughtException handleUncaughtException;
-};
-
 } }
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index fad41e7cc598..d684b5823c05 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -651,6 +651,15 @@ static void create(JNIEnv* env, jobject obj, jobject executor, jobject callback,
   setCountableForJava(env, obj, std::move(bridge));
 }
 
+static void destroy(JNIEnv* env, jobject jbridge) {
+  auto bridge = extractRefPtr<CountableBridge>(env, jbridge);
+  try {
+    bridge->destroy();
+  } catch (...) {
+    translatePendingCppExceptionToJavaException();
+  }
+}
+
 static void loadApplicationScript(
     const RefPtr<CountableBridge>& bridge,
     const std::string& script,
@@ -865,9 +874,6 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
         return std::unique_ptr<MessageQueueThread>(
             JMessageQueueThread::currentMessageQueueThread().release());
       };
-    Exceptions::handleUncaughtException = [] () {
-      translatePendingCppExceptionToJavaException();
-    };
     PerfLogging::installNativeHooks = addNativePerfLoggingHooks;
     JSLogging::nativeHook = nativeLoggingHook;
 
@@ -950,6 +956,7 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
 
     registerNatives("com/facebook/react/bridge/ReactBridge", {
         makeNativeMethod("initialize", "(Lcom/facebook/react/bridge/JavaScriptExecutor;Lcom/facebook/react/bridge/ReactCallback;Lcom/facebook/react/bridge/queue/MessageQueueThread;)V", bridge::create),
+        makeNativeMethod("destroy", bridge::destroy),
         makeNativeMethod(
           "loadScriptFromAssets", "(Landroid/content/res/AssetManager;Ljava/lang/String;)V",
           bridge::loadScriptFromAssets),

From d94a56747d83d7eb3e1c0215dc01df654b31d8e6 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Tue, 1 Mar 2016 04:40:40 -0800
Subject: [PATCH 1358/1411] Add new worker for code transform, optimization,
 and dependency extraction

Summary:This adds a new worker implementation that

- uses the existing transforms to transform code
- optionally inline `__DEV__`, `process.env.NODE_ENV`, and `Platform.OS`
- optionally eliminate branches of conditionals with constant conditions
- extracts dependencies
- optionally minifies

This will land as part of a multi-commit stack, not in isolation

Reviewed By: martinbigio

Differential Revision: D2976677

fb-gh-sync-id: 38e317f90b6948b28ef2e3fe8b66fc0b9c75aa38
shipit-source-id: 38e317f90b6948b28ef2e3fe8b66fc0b9c75aa38
---
 .../worker/__tests__/constant-folding-test.js | 112 ++++++++
 .../__tests__/extract-dependencies-test.js    |  96 +++++++
 .../worker/__tests__/inline-test.js           | 133 ++++++++++
 .../worker/__tests__/minify-test.js           | 111 ++++++++
 .../worker/__tests__/worker-test.js           | 244 ++++++++++++++++++
 .../JSTransformer/worker/constant-folding.js  |  82 ++++++
 .../worker/extract-dependencies.js            | 126 +++++++++
 .../src/JSTransformer/worker/index.js         |  79 ++++++
 .../src/JSTransformer/worker/inline.js        | 102 ++++++++
 .../src/JSTransformer/worker/minify.js        |  88 +++++++
 10 files changed, 1173 insertions(+)
 create mode 100644 packager/react-packager/src/JSTransformer/worker/__tests__/constant-folding-test.js
 create mode 100644 packager/react-packager/src/JSTransformer/worker/__tests__/extract-dependencies-test.js
 create mode 100644 packager/react-packager/src/JSTransformer/worker/__tests__/inline-test.js
 create mode 100644 packager/react-packager/src/JSTransformer/worker/__tests__/minify-test.js
 create mode 100644 packager/react-packager/src/JSTransformer/worker/__tests__/worker-test.js
 create mode 100644 packager/react-packager/src/JSTransformer/worker/constant-folding.js
 create mode 100644 packager/react-packager/src/JSTransformer/worker/extract-dependencies.js
 create mode 100644 packager/react-packager/src/JSTransformer/worker/index.js
 create mode 100644 packager/react-packager/src/JSTransformer/worker/inline.js
 create mode 100644 packager/react-packager/src/JSTransformer/worker/minify.js

diff --git a/packager/react-packager/src/JSTransformer/worker/__tests__/constant-folding-test.js b/packager/react-packager/src/JSTransformer/worker/__tests__/constant-folding-test.js
new file mode 100644
index 000000000000..a39a1e970930
--- /dev/null
+++ b/packager/react-packager/src/JSTransformer/worker/__tests__/constant-folding-test.js
@@ -0,0 +1,112 @@
+/**
+ * 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.
+ */
+'use strict';
+
+jest.autoMockOff();
+const babel = require('babel-core');
+const constantFolding = require('../constant-folding');
+
+function parse(code) {
+  return babel.transform(code, {code: false, babelrc: false, compact: true});
+}
+
+describe('constant expressions', () => {
+  it('can optimize conditional expressions with constant conditions', () => {
+    const code = `
+      a(
+        'production'=="production",
+        'production'!=='development',
+        false && 1 || 0 || 2,
+        true || 3,
+        'android'==='ios' ? null : {},
+        'android'==='android' ? {a:1} : {a:0},
+        'foo'==='bar' ? b : c,
+        f() ? g() : h()
+      );`;
+    expect(constantFolding('arbitrary.js', parse(code)).code)
+      .toEqual(`a(true,true,2,true,{},{a:1},c,f()?g():h());`);
+  });
+
+  it('can optimize ternary expressions with constant conditions', () => {
+    const code =
+      `var a = true ? 1 : 2;
+       var b = 'android' == 'android'
+         ? ('production' != 'production' ? 'a' : 'A')
+         : 'i';`;
+    expect(constantFolding('arbitrary.js', parse(code)).code)
+      .toEqual(`var a=1;var b='A';`);
+  });
+
+  it('can optimize logical operator expressions with constant conditions', () => {
+    const code = `
+      var a = true || 1;
+      var b = 'android' == 'android' &&
+        'production' != 'production' || null || "A";`;
+    expect(constantFolding('arbitrary.js', parse(code)).code)
+      .toEqual(`var a=true;var b="A";`);
+  });
+
+  it('can optimize logical operators with partly constant operands', () => {
+    const code = `
+      var a = "truthy" || z();
+      var b = "truthy" && z();
+      var c = null && z();
+      var d = null || z();
+      var e = !1 && z();
+    `;
+    expect(constantFolding('arbitrary.js', parse(code)).code)
+      .toEqual(`var a="truthy";var b=z();var c=null;var d=z();var e=false;`);
+  });
+
+  it('can remode an if statement with a falsy constant test', () => {
+    const code = `
+      if ('production' === 'development' || false) {
+        var a = 1;
+      }
+    `;
+    expect(constantFolding('arbitrary.js', parse(code)).code)
+      .toEqual(``);
+  });
+
+  it('can optimize if-else-branches with constant conditions', () => {
+    const code = `
+      if ('production' == 'development') {
+        var a = 1;
+        var b = a + 2;
+      } else if ('development' == 'development') {
+        var a = 3;
+        var b = a + 4;
+      } else {
+        var a = 'b';
+      }
+    `;
+    expect(constantFolding('arbitrary.js', parse(code)).code)
+      .toEqual(`{var a=3;var b=a+4;}`);
+  });
+
+  it('can optimize nested if-else constructs', () => {
+    const code = `
+      if ('ios' === "android") {
+        if (true) {
+          require('a');
+        } else {
+          require('b');
+        }
+      } else if ('android' === 'android') {
+        if (true) {
+          require('c');
+        } else {
+          require('d');
+        }
+      }
+    `;
+    expect(constantFolding('arbitrary.js', parse(code)).code)
+      .toEqual(`{{require('c');}}`);
+  });
+});
diff --git a/packager/react-packager/src/JSTransformer/worker/__tests__/extract-dependencies-test.js b/packager/react-packager/src/JSTransformer/worker/__tests__/extract-dependencies-test.js
new file mode 100644
index 000000000000..a27def1dc442
--- /dev/null
+++ b/packager/react-packager/src/JSTransformer/worker/__tests__/extract-dependencies-test.js
@@ -0,0 +1,96 @@
+/**
+ * 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.
+ */
+'use strict';
+
+jest.autoMockOff();
+
+const extractDependencies = require('../extract-dependencies');
+
+describe('Dependency extraction:', () => {
+  it('can extract calls to require', () => {
+    const code = `require('foo/bar');
+      var React = require("React");
+      var A = React.createClass({
+        render: function() {
+          return require (  "Component" );
+        }
+      });
+      require
+      ('more');`
+    const {dependencies, dependencyOffsets} = extractDependencies(code);
+    expect(dependencies)
+      .toEqual(['foo/bar', 'React', 'Component', 'more']);
+    expect(dependencyOffsets).toEqual([8, 46, 147, 203]);
+  });
+
+  it('does not extract require method calls', () => {
+    const code = `
+      require('a');
+      foo.require('b');
+      bar.
+      require ( 'c').require('d')require('e')`;
+
+    const {dependencies, dependencyOffsets} = extractDependencies(code);
+    expect(dependencies).toEqual(['a', 'e']);
+    expect(dependencyOffsets).toEqual([15, 97]);
+  });
+
+  it('does not extract require calls from strings', () => {
+    const code = `require('foo');
+      var React = '\\'require("React")';
+      var a = ' // require("yadda")';
+      var a = ' /* require("yadda") */';
+      var A = React.createClass({
+        render: function() {
+          return require (  "Component" );
+        }
+      });
+      " \\" require('more')";`
+
+    const {dependencies, dependencyOffsets} = extractDependencies(code);
+    expect(dependencies).toEqual(['foo', 'Component']);
+    expect(dependencyOffsets).toEqual([8, 226]);
+  });
+
+  it('does not extract require calls in comments', () => {
+    const code = `require('foo')//require("not/this")
+      /* A comment here with a require('call') that should not be extracted */require('bar')
+    // ending comment without newline require("baz")`;
+
+    const {dependencies, dependencyOffsets} = extractDependencies(code);
+    expect(dependencies).toEqual(['foo', 'bar']);
+    expect(dependencyOffsets).toEqual([8, 122]);
+  });
+
+  it('deduplicates dependencies', () => {
+    const code = `require('foo');require( "foo" );
+      require("foo");`;
+
+    const {dependencies, dependencyOffsets} = extractDependencies(code);
+    expect(dependencies).toEqual(['foo']);
+    expect(dependencyOffsets).toEqual([8, 24, 47]);
+  });
+
+  it('does not extract calls to function with names that start with "require"', () => {
+    const code = `arbitraryrequire('foo');`;
+
+    const {dependencies, dependencyOffsets} = extractDependencies(code);
+    expect(dependencies).toEqual([]);
+    expect(dependencyOffsets).toEqual([]);
+  });
+
+  it('does not get confused by previous states', () => {
+    // yes, this was a bug
+    const code = `require("a");/* a comment */ var a = /[a]/.test('a');`
+
+    const {dependencies, dependencyOffsets} = extractDependencies(code);
+    expect(dependencies).toEqual(['a']);
+    expect(dependencyOffsets).toEqual([8]);
+  });
+});
diff --git a/packager/react-packager/src/JSTransformer/worker/__tests__/inline-test.js b/packager/react-packager/src/JSTransformer/worker/__tests__/inline-test.js
new file mode 100644
index 000000000000..53fe1ed8f362
--- /dev/null
+++ b/packager/react-packager/src/JSTransformer/worker/__tests__/inline-test.js
@@ -0,0 +1,133 @@
+/**
+ * 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.
+ */
+'use strict';
+
+jest.autoMockOff();
+const inline = require('../inline');
+const {transform, transformFromAst} = require('babel-core');
+
+const babelOptions = {
+  babelrc: false,
+  compact: true,
+};
+
+function toString(ast) {
+  return normalize(transformFromAst(ast, babelOptions).code);
+}
+
+function normalize(code) {
+  return transform(code, babelOptions).code;
+}
+
+function toAst(code) {
+  return transform(code, {...babelOptions, code: false}).ast;
+}
+
+describe('inline constants', () => {
+  it('replaces __DEV__ in the code', () => {
+    const code = `function a() {
+      var a = __DEV__ ? 1 : 2;
+      var b = a.__DEV__;
+      var c = function __DEV__(__DEV__) {};
+    }`
+    const {ast} = inline('arbitrary.js', {code}, {dev: true});
+    expect(toString(ast)).toEqual(normalize(code.replace(/__DEV__/, 'true')));
+  });
+
+  it('replaces Platform.OS in the code if Platform is a global', () => {
+    const code = `function a() {
+      var a = Platform.OS;
+      var b = a.Platform.OS;
+    }`
+    const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'});
+    expect(toString(ast)).toEqual(normalize(code.replace(/Platform\.OS/, '"ios"')));
+  });
+
+  it('replaces Platform.OS in the code if Platform is a top level import', () => {
+    const code = `
+      var Platform = require('Platform');
+      function a() {
+        if (Platform.OS === 'android') a = function() {};
+        var b = a.Platform.OS;
+      }`
+    const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'});
+    expect(toString(ast)).toEqual(normalize(code.replace(/Platform\.OS/, '"ios"')));
+  });
+
+  it('replaces require("Platform").OS in the code', () => {
+    const code = `function a() {
+      var a = require('Platform').OS;
+      var b = a.require('Platform').OS;
+    }`
+    const {ast} = inline('arbitrary.js', {code}, {platform: 'android'});
+    expect(toString(ast)).toEqual(
+      normalize(code.replace(/require\('Platform'\)\.OS/, '"android"')));
+  });
+
+  it('replaces React.Platform.OS in the code if React is a global', () => {
+    const code = `function a() {
+      var a = React.Platform.OS;
+      var b = a.React.Platform.OS;
+    }`
+    const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'});
+    expect(toString(ast)).toEqual(normalize(code.replace(/React\.Platform\.OS/, '"ios"')));
+  });
+
+  it('replaces React.Platform.OS in the code if React is a top level import', () => {
+    const code = `
+      var React = require('React');
+      function a() {
+        if (React.Platform.OS === 'android') a = function() {};
+        var b = a.React.Platform.OS;
+      }`
+    const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'});
+    expect(toString(ast)).toEqual(normalize(code.replace(/React.Platform\.OS/, '"ios"')));
+  });
+
+  it('replaces require("React").Platform.OS in the code', () => {
+    const code = `function a() {
+      var a = require('React').Platform.OS;
+      var b = a.require('React').Platform.OS;
+    }`
+    const {ast} = inline('arbitrary.js', {code}, {platform: 'android'});
+    expect(toString(ast)).toEqual(
+      normalize(code.replace(/require\('React'\)\.Platform\.OS/, '"android"')));
+  });
+
+  it('replaces process.env.NODE_ENV in the code', () => {
+    const code = `function a() {
+      if (process.env.NODE_ENV === 'production') {
+        return require('Prod');
+      }
+      return require('Dev');
+    }`
+    const {ast} = inline('arbitrary.js', {code}, {dev: false});
+    expect(toString(ast)).toEqual(
+      normalize(code.replace(/process\.env\.NODE_ENV/, '"production"')));
+  });
+
+  it('replaces process.env.NODE_ENV in the code', () => {
+    const code = `function a() {
+      if (process.env.NODE_ENV === 'production') {
+        return require('Prod');
+      }
+      return require('Dev');
+    }`
+    const {ast} = inline('arbitrary.js', {code}, {dev: true});
+    expect(toString(ast)).toEqual(
+      normalize(code.replace(/process\.env\.NODE_ENV/, '"development"')));
+  });
+
+  it('accepts an AST as input', function() {
+    const code = `function ifDev(a,b){return __DEV__?a:b;}`;
+    const {ast} = inline('arbitrary.hs', {ast: toAst(code)}, {dev: false});
+    expect(toString(ast)).toEqual(code.replace(/__DEV__/, 'false'))
+  });
+});
+
diff --git a/packager/react-packager/src/JSTransformer/worker/__tests__/minify-test.js b/packager/react-packager/src/JSTransformer/worker/__tests__/minify-test.js
new file mode 100644
index 000000000000..e65594e7cabe
--- /dev/null
+++ b/packager/react-packager/src/JSTransformer/worker/__tests__/minify-test.js
@@ -0,0 +1,111 @@
+/**
+ * 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.
+ */
+'use strict';
+
+jest.autoMockOff();
+
+const uglify = {
+  minify: jest.genMockFunction().mockImplementation(code => {
+    return {
+      code: code.replace(/(^|\W)\s+/g, '$1'),
+      map: {},
+    };
+  }),
+};
+jest.setMock('uglify-js', uglify);
+
+const minify = require('../minify');
+const {any} = jasmine;
+
+describe('Minification:', () => {
+  const fileName = '/arbitrary/file.js';
+  const DEPENDENCY_MARKER = '\u0002\ueffe\ue277\uead5';
+  let map;
+
+  beforeEach(() => {
+    uglify.minify.mockClear();
+    map = {version: 3, sources: [fileName], mappings: ''};
+  });
+
+  it('passes the transformed code to `uglify.minify`, wrapped in an immediately invoked function expression', () => {
+    const code = 'arbitrary(code)';
+    minify('', code, {}, [], []);
+    expect(uglify.minify).toBeCalledWith(
+      `(function(){${code}}());`, any(Object));
+  });
+
+  it('uses the passed module locals as parameters of the IIFE', () => {
+    const moduleLocals = ['arbitrary', 'parameters'];
+    minify('', '', {}, [], moduleLocals);
+    expect(uglify.minify).toBeCalledWith(
+      `(function(${moduleLocals}){}());`, any(Object));
+  });
+
+  it('passes the transformed source map to `uglify.minify`', () => {
+    minify('', '', map, [], []);
+    const [, options] = uglify.minify.mock.calls[0];
+    expect(options.inSourceMap).toEqual(map);
+  });
+
+  it('passes the file name as `outSourceMap` to `uglify.minify` (uglify uses it for the `file` field on the source map)', () => {
+    minify(fileName, '', {}, [], []);
+    const [, options] = uglify.minify.mock.calls[0];
+    expect(options.outSourceMap).toEqual(fileName);
+  });
+
+  it('inserts a marker for every dependency offset before minifing', () => {
+    const code = `
+      var React = require('React');
+      var Immutable = require('Immutable');`;
+    const dependencyOffsets = [27, 67];
+    const expectedCode =
+      code.replace(/require\('/g, '$&' + DEPENDENCY_MARKER);
+
+    minify('', code, {}, dependencyOffsets, []);
+    expect(uglify.minify).toBeCalledWith(
+      `(function(){${expectedCode}}());`, any(Object));
+  });
+
+  it('returns the code provided by uglify', () => {
+    const code = 'some(source) + code';
+    uglify.minify.mockReturnValue({code: `!function(a,b,c){${code}}()`});
+
+    const result = minify('', '', {}, [], []);
+    expect(result.code).toBe(code);
+  });
+
+  it('extracts dependency offsets from the code provided by uglify', () => {
+    const code = `
+      var a=r("${DEPENDENCY_MARKER}a-dependency");
+      var b=r("\\x02\\ueffe\\ue277\\uead5b-dependency");
+      var e=r(a()?'\\u0002\\ueffe\\ue277\\uead5c-dependency'
+                 :'\x02\ueffe\ue277\uead5d-dependency');`;
+    uglify.minify.mockReturnValue({code: `!function(){${code}}());`});
+
+    const result = minify('', '', {}, [], []);
+    expect(result.dependencyOffsets).toEqual([15, 46, 81, 114]);
+  });
+
+  it('returns the source map object provided by uglify', () => {
+    uglify.minify.mockReturnValue({map, code: ''});
+    const result = minify('', '', {}, [], []);
+    expect(result.map).toBe(map);
+  });
+
+  it('adds a `moduleLocals` object to the result that reflects the names of the minified module locals', () => {
+    const moduleLocals = ['arbitrary', 'parameters', 'here'];
+    uglify.minify.mockReturnValue({code: '(function(a,ll,d){}());'});
+    const result = minify('', '', {}, [], moduleLocals);
+    expect(result.moduleLocals).toEqual({
+      arbitrary: 'a',
+      parameters: 'll',
+      here: 'd',
+    });
+  });
+});
diff --git a/packager/react-packager/src/JSTransformer/worker/__tests__/worker-test.js b/packager/react-packager/src/JSTransformer/worker/__tests__/worker-test.js
new file mode 100644
index 000000000000..a6acb668960d
--- /dev/null
+++ b/packager/react-packager/src/JSTransformer/worker/__tests__/worker-test.js
@@ -0,0 +1,244 @@
+/**
+ * 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.
+ */
+'use strict';
+
+jest.autoMockOff();
+jest.mock('../constant-folding');
+jest.mock('../extract-dependencies');
+jest.mock('../inline');
+jest.mock('../minify');
+
+const {transformCode} = require('..');
+const {any, objectContaining} = jasmine;
+
+describe('code transformation worker:', () => {
+  let extractDependencies, transform;
+  beforeEach(() => {
+    extractDependencies =
+      require('../extract-dependencies').mockReturnValue({});
+    transform = jest.genMockFunction();
+  });
+
+  it('calls the transform with file name, source code, and transform options', function() {
+    const filename = 'arbitrary/file.js';
+    const sourceCode = 'arbitrary(code)';
+    const transformOptions = {arbitrary: 'options'};
+    transformCode(transform, filename, sourceCode, {transform: transformOptions});
+    expect(transform).toBeCalledWith(
+      {filename, sourceCode, options: transformOptions}, any(Function));
+  });
+
+  it('prefixes JSON files with an assignment to module.exports to make the code valid', function() {
+    const filename = 'arbitrary/file.json';
+    const sourceCode = '{"arbitrary":"property"}';
+    transformCode(transform, filename, sourceCode, {});
+    expect(transform).toBeCalledWith(
+      {filename, sourceCode: `module.exports=${sourceCode}`}, any(Function));
+  });
+
+  it('calls back with the result of the transform', done => {
+    const result = {
+      code: 'some.other(code)',
+      map: {}
+    };
+    transform.mockImplementation((_, callback) =>
+      callback(null, result));
+
+    transformCode(transform, 'filename', 'code', {}, (_, data) => {
+      expect(data).toEqual(objectContaining(result));
+      done();
+    });
+  });
+
+  it('removes the leading assignment to `module.exports` before passing on the result if the file is a JSON file, even if minified', done => {
+    const result = {
+      code: 'p.exports={a:1,b:2}',
+    };
+    transform.mockImplementation((_, callback) =>
+      callback(null, result));
+
+    transformCode(transform, 'aribtrary/file.json', 'b', {}, (_, data) => {
+      expect(data.code).toBe('{a:1,b:2}');
+      done();
+    });
+  });
+
+  it('calls back with any error yielded by the transform', done => {
+    const error = Error('arbitrary error');
+    transform.mockImplementation((_, callback) => callback(error));
+    transformCode(transform, 'filename', 'code', {}, e => {
+      expect(e).toBe(error);
+      done();
+    });
+  });
+
+  it('puts an empty `moduleLocals` object on the result', done => {
+    transform.mockImplementation(
+      (_, callback) => callback(null, {code: 'arbitrary'}));
+    transformCode(transform, 'filename', 'code', {}, (_, data) => {
+      expect(data.moduleLocals).toEqual({});
+      done();
+    });
+  });
+
+  it('if a `moduleLocals` array is passed, the `moduleLocals` object is a key mirror of its items', done => {
+    transform.mockImplementation(
+      (_, callback) => callback(null, {code: 'arbitrary'}));
+    const moduleLocals =
+      ['arbitrary', 'list', 'containing', 'variable', 'names'];
+
+    transformCode(transform, 'filename', 'code', {moduleLocals}, (_, data) => {
+      expect(data.moduleLocals).toEqual({
+        arbitrary: 'arbitrary',
+        list: 'list',
+        containing: 'containing',
+        variable: 'variable',
+        names: 'names',
+      });
+      done();
+    });
+  });
+
+  describe('dependency extraction:', () => {
+    let code;
+
+    beforeEach(() => {
+      transform.mockImplementation(
+        (_, callback) => callback(null, {code}));
+    });
+
+    it('passes the transformed code the `extractDependencies`', done => {
+      code = 'arbitrary(code)';
+
+      transformCode(transform, 'filename', 'code', {}, (_, data) => {
+        expect(extractDependencies).toBeCalledWith(code);
+        done();
+      });
+    });
+
+    it('uses `dependencies` and `dependencyOffsets` provided by `extractDependencies` for the result', done => {
+      const dependencyData = {
+        dependencies: ['arbitrary', 'list', 'of', 'dependencies'],
+        dependencyOffsets: [12,  119, 185, 328, 471],
+      };
+      extractDependencies.mockReturnValue(dependencyData);
+
+      transformCode(transform, 'filename', 'code', {}, (_, data) => {
+        expect(data).toEqual(objectContaining(dependencyData));
+        done();
+      });
+    });
+
+    it('does not extract requires if files are marked as "extern"', done => {
+      transformCode(transform, 'filename', 'code', {extern: true}, (_, {dependencies, dependencyOffsets}) => {
+        expect(extractDependencies).not.toBeCalled();
+        expect(dependencies).toEqual([]);
+        expect(dependencyOffsets).toEqual([]);
+        done();
+      });
+    });
+
+    it('does not extract requires of JSON files', done => {
+      transformCode(transform, 'arbitrary.json', '{"arbitrary":"json"}', {}, (_, {dependencies, dependencyOffsets}) => {
+        expect(extractDependencies).not.toBeCalled();
+        expect(dependencies).toEqual([]);
+        expect(dependencyOffsets).toEqual([]);
+        done();
+      });
+    });
+  });
+
+  describe('Minifications:', () => {
+    let constantFolding, extractDependencies, inline, minify, options;
+    let transformResult, dependencyData, moduleLocals;
+    const filename = 'arbitrary/file.js';
+    const foldedCode = 'arbitrary(folded(code));'
+    const foldedMap = {version: 3, sources: ['fold.js']}
+
+    beforeEach(() => {
+      constantFolding = require('../constant-folding')
+        .mockReturnValue({code: foldedCode, map: foldedMap});
+      extractDependencies = require('../extract-dependencies');
+      inline = require('../inline');
+      minify = require('../minify').mockReturnValue({});
+
+      moduleLocals = ['module', 'require', 'exports'];
+      options = {moduleLocals, minify: true};
+      dependencyData = {
+        dependencies: ['a', 'b', 'c'],
+        dependencyOffsets: [100, 120, 140]
+      };
+
+      extractDependencies.mockImplementation(
+        code => code === foldedCode ? dependencyData : {});
+
+      transform.mockImplementation(
+        (_, callback) => callback(null, transformResult));
+    });
+
+    it('passes the transform result to `inline` for constant inlining', done => {
+      transformResult = {map: {version: 3}, code: 'arbitrary(code)'};
+      transformCode(transform, filename, 'code', options, () => {
+        expect(inline).toBeCalledWith(filename, transformResult, options);
+        done();
+      });
+    });
+
+    it('passes the result obtained from `inline` on to `constant-folding`', done => {
+      const inlineResult = {map: {version: 3, sources: []}, ast: {}};
+      inline.mockReturnValue(inlineResult);
+      transformCode(transform, filename, 'code', options, () => {
+        expect(constantFolding).toBeCalledWith(filename, inlineResult);
+        done();
+      });
+    });
+
+    it('Uses the code obtained from `constant-folding` to extract dependencies', done => {
+      transformCode(transform, filename, 'code', options, () => {
+        expect(extractDependencies).toBeCalledWith(foldedCode);
+        done();
+      });
+    });
+
+    it('passes the code obtained from `constant-folding` to `minify`', done => {
+      transformCode(transform, filename, 'code', options, () => {
+        expect(minify).toBeCalledWith(
+          filename,
+          foldedCode,
+          foldedMap,
+          dependencyData.dependencyOffsets,
+          moduleLocals
+        );
+        done();
+      });
+    });
+
+    it('uses the dependencies obtained from the optimized result', done => {
+      transformCode(transform, filename, 'code', options, (_, result) => {
+        expect(result.dependencies).toEqual(dependencyData.dependencies);
+        done();
+      });
+    });
+
+    it('uses data produced by `minify` for the result', done => {
+      const minifyResult = {
+        code: 'minified(code)',
+        dependencyOffsets: [10, 30, 60],
+        map: {version: 3, sources: ['minified.js']},
+        moduleLocals: {module: 'x', require: 'y', exports: 'z'},
+      };
+      minify.mockReturnValue(minifyResult);
+
+      transformCode(transform, 'filename', 'code', options, (_, result) => {
+        expect(result).toEqual(objectContaining(minifyResult))
+        done();
+      });
+    });
+  });
+});
diff --git a/packager/react-packager/src/JSTransformer/worker/constant-folding.js b/packager/react-packager/src/JSTransformer/worker/constant-folding.js
new file mode 100644
index 000000000000..acf14f687b02
--- /dev/null
+++ b/packager/react-packager/src/JSTransformer/worker/constant-folding.js
@@ -0,0 +1,82 @@
+/**
+ * Copyright (c) 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.
+ */
+'use strict';
+
+const babel = require('babel-core');
+const t = babel.types;
+
+const isLiteral = binaryExpression =>
+  t.isLiteral(binaryExpression.left) && t.isLiteral(binaryExpression.right);
+
+const Conditional = {
+  exit(path) {
+    const node = path.node;
+    const test = node.test;
+    if (t.isLiteral(test)) {
+      if (test.value || node.alternate) {
+        path.replaceWith(test.value ? node.consequent : node.alternate);
+      } else if (!test.value) {
+        path.remove();
+      }
+    }
+  },
+};
+
+const plugin = {
+  visitor: {
+    BinaryExpression: {
+      exit(path) {
+        const node = path.node;
+        if (t.isLiteral(node.left) && t.isLiteral(node.right)) {
+          const result = path.evaluate();
+          if (result.confident) {
+            path.replaceWith(t.valueToNode(result.value));
+          }
+        }
+      },
+    },
+    ConditionalExpression: Conditional,
+    IfStatement: Conditional,
+    LogicalExpression: {
+      exit(path) {
+        const node = path.node;
+        const left = node.left;
+        if (t.isLiteral(left)) {
+          const value = t.isNullLiteral(left) ? null : left.value;
+          if (node.operator === '||') {
+            path.replaceWith(value ? left : node.right);
+          } else {
+            path.replaceWith(value ? node.right : left);
+          }
+        }
+      }
+    },
+    UnaryExpression: {
+      exit(path) {
+        const node = path.node;
+        if (node.operator === '!' && t.isLiteral(node.argument)) {
+          path.replaceWith(t.valueToNode(!node.argument.value));
+        }
+      }
+    },
+  },
+};
+
+function constantFolding(filename, transformResult) {
+  return babel.transformFromAst(transformResult.ast, transformResult.code, {
+    filename,
+    plugins: [plugin],
+    inputSourceMap: transformResult.map,
+    babelrc: false,
+    compact: true,
+  })
+}
+
+module.exports = constantFolding;
+
diff --git a/packager/react-packager/src/JSTransformer/worker/extract-dependencies.js b/packager/react-packager/src/JSTransformer/worker/extract-dependencies.js
new file mode 100644
index 000000000000..3ca221641ab7
--- /dev/null
+++ b/packager/react-packager/src/JSTransformer/worker/extract-dependencies.js
@@ -0,0 +1,126 @@
+/**
+ * Copyright (c) 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.
+ */
+'use strict';
+
+const SINGLE_QUOTE = "'".charCodeAt(0);
+const DOUBLE_QUOTE = '"'.charCodeAt(0);
+const BACKSLASH = '\\'.charCodeAt(0);
+const SLASH = '/'.charCodeAt(0);
+const NEWLINE = '\n'.charCodeAt(0);
+const ASTERISK = '*'.charCodeAt(0);
+
+// dollar is the only regex special character valid in identifiers
+const escapeRegExp = identifier => identifier.replace(/[$]/g, '\\$');
+
+function binarySearch(indexes, index) {
+  var low = 0;
+  var high = indexes.length - 1;
+  var i = 0;
+
+  if (indexes[low] === index) {
+    return low;
+  }
+  while (high - low > 1) {
+    var current = low + ((high - low) >>> 1); // right shift divides by 2 and floors
+    if (index === indexes[current]) {
+      return current;
+    }
+    if (index > indexes[current]) {
+      low = current;
+    } else {
+      high = current;
+    }
+  }
+  return low;
+}
+
+function indexOfCharCode(string, needle, i) {
+  for (var charCode; (charCode = string.charCodeAt(i)); i++) {
+    if (charCode === needle) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+const reRequire = /(?:^|[^.\s])\s*\brequire\s*\(\s*(['"])(.*?)\1/g;
+
+/**
+ * Extracts dependencies (module IDs imported with the `require` function) from
+ * a string containing code.
+ * The function is regular expression based for speed reasons.
+ *
+ * The code is traversed twice:
+ *  1. An array of ranges is built, where indexes 0-1, 2-3, 4-5, etc. are code,
+ *     and indexes 1-2, 3-4, 5-6, etc. are string literals and comments.
+ *  2. require calls are extracted with a regular expression.
+ *
+ * The result of the dependency extraction is an de-duplicated array of
+ * dependencies, and an array of offsets to the string literals with module IDs.
+ * The index points to the opening quote.
+ */
+function extractDependencies(code) {
+  const ranges = [0];
+  // are we currently in a quoted string? -> SINGLE_QUOTE or DOUBLE_QUOTE, else undefined
+  var currentQuote;
+  // scan the code for string literals and comments.
+  for (var i = 0, charCode; (charCode = code.charCodeAt(i)); i++) {
+    if (charCode === BACKSLASH) {
+      i += 1;
+      continue;
+    }
+
+    if (charCode === SLASH && currentQuote === undefined) {
+      var next = code.charCodeAt(i + 1);
+      var end = undefined;
+      if (next === SLASH) {
+        end = indexOfCharCode(code, NEWLINE, i + 2);
+      } else if (next === ASTERISK) {
+        end = code.indexOf('*/', i + 2) + 1; // assume valid JS input here
+      }
+      if (end === -1) {
+        // if the comment does not end, it goes to the end of the file
+        end += code.length;
+      }
+      if (end !== undefined) {
+        ranges.push(i, end);
+        i = end;
+        continue;
+      }
+    }
+
+    var isQuoteStart = currentQuote === undefined &&
+                       (charCode === SINGLE_QUOTE || charCode === DOUBLE_QUOTE);
+    if (isQuoteStart || currentQuote === charCode) {
+      ranges.push(i);
+      currentQuote = currentQuote === charCode ? undefined : charCode;
+    }
+  }
+  ranges.push(i);
+
+  // extract dependencies
+  const dependencies = new Set();
+  const dependencyOffsets = [];
+  for (var match; (match = reRequire.exec(code)); ) {
+    // check whether the match is in a code range, and not inside of a string
+    // literal or a comment
+    if (binarySearch(ranges, match.index) % 2 === 0) {
+      dependencies.add(match[2]);
+      dependencyOffsets.push(
+        match[0].length - match[2].length - 2 + match.index);
+    }
+  }
+
+  return {
+    dependencyOffsets,
+    dependencies: Array.from(dependencies.values()),
+  };
+}
+
+module.exports = extractDependencies;
diff --git a/packager/react-packager/src/JSTransformer/worker/index.js b/packager/react-packager/src/JSTransformer/worker/index.js
new file mode 100644
index 000000000000..bc6e93338017
--- /dev/null
+++ b/packager/react-packager/src/JSTransformer/worker/index.js
@@ -0,0 +1,79 @@
+/**
+ * Copyright (c) 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.
+ */
+'use strict';
+
+const constantFolding = require('./constant-folding');
+const extractDependencies = require('./extract-dependencies');
+const inline = require('./inline');
+const minify = require('./minify');
+
+function keyMirrorFromArray(array) {
+  var keyMirror = {};
+  array.forEach(key => keyMirror[key] = key);
+  return keyMirror;
+}
+
+function makeTransformParams(filename, sourceCode, options) {
+  if (filename.endsWith('.json')) {
+    sourceCode = 'module.exports=' + sourceCode;
+  }
+  return {filename, sourceCode, options};
+}
+
+function transformCode(transform, filename, sourceCode, options, callback) {
+  const params = makeTransformParams(filename, sourceCode, options.transform);
+  const moduleLocals = options.moduleLocals || [];
+  const isJson = filename.endsWith('.json');
+
+  transform(params, (error, transformed) => {
+    if (error) {
+      callback(error);
+      return;
+    }
+
+    var code, map;
+    if (options.minify) {
+      const optimized =
+        constantFolding(filename, inline(filename, transformed, options));
+      code = optimized.code;
+      map = optimized.map;
+    } else {
+      code = transformed.code;
+      map = transformed.map;
+    }
+
+    if (isJson) {
+      code = code.replace(/^\w+\.exports=/, '');
+    }
+
+    const moduleLocals = options.moduleLocals || [];
+    const dependencyData = isJson || options.extern
+      ? {dependencies: [], dependencyOffsets: []}
+      : extractDependencies(code);
+
+    var result;
+    if (options.minify) {
+      result = minify(
+        filename, code, map, dependencyData.dependencyOffsets, moduleLocals);
+      result.dependencies = dependencyData.dependencies;
+    } else {
+      result = dependencyData;
+      result.code = code;
+      result.map = map;
+      result.moduleLocals = keyMirrorFromArray(moduleLocals);
+    }
+
+    callback(null, result);
+  });
+}
+
+module.exports = function(transform, filename, sourceCode, options, callback) {
+  transformCode(require(transform), filename, sourceCode, options || {}, callback);
+};
+module.exports.transformCode = transformCode; // for easier testing
diff --git a/packager/react-packager/src/JSTransformer/worker/inline.js b/packager/react-packager/src/JSTransformer/worker/inline.js
new file mode 100644
index 000000000000..2a419933af87
--- /dev/null
+++ b/packager/react-packager/src/JSTransformer/worker/inline.js
@@ -0,0 +1,102 @@
+/**
+ * Copyright (c) 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.
+ */
+'use strict';
+
+const babel = require('babel-core');
+const t = babel.types;
+
+const react = {name: 'React'};
+const platform = {name: 'Platform'};
+const os = {name: 'OS'};
+const requirePattern = {name: 'require'};
+
+const env = {name: 'env'};
+const nodeEnv = {name: 'NODE_ENV'};
+const processId = {name: 'process'};
+
+const dev = {name: '__DEV__'};
+
+const isGlobal = (binding) => !binding;
+
+const isToplevelBinding = (binding) => isGlobal(binding) || !binding.scope.parent;
+
+const isRequireCall = (node, dependencyId, scope) =>
+  t.isCallExpression(node) &&
+  t.isIdentifier(node.callee, requirePattern) &&
+  t.isStringLiteral(node.arguments[0], t.stringLiteral(dependencyId));
+
+const isImport = (node, scope, pattern) =>
+  t.isIdentifier(node, pattern) &&
+  isToplevelBinding(scope.getBinding(pattern.name)) ||
+  isRequireCall(node, pattern.name, scope);
+
+const isPlatformOS = (node, scope) =>
+  t.isIdentifier(node.property, os) &&
+  isImport(node.object, scope, platform);
+
+const isReactPlatformOS = (node, scope) =>
+  t.isIdentifier(node.property, os) &&
+  t.isMemberExpression(node.object) &&
+  t.isIdentifier(node.object.property, platform) &&
+  isImport(node.object.object, scope, react);
+
+const isProcessEnvNodeEnv = (node, scope) =>
+  t.isIdentifier(node.property, nodeEnv) &&
+  t.isMemberExpression(node.object) &&
+  t.isIdentifier(node.object.property, env) &&
+  t.isIdentifier(node.object.object, processId) &&
+  isGlobal(scope.getBinding(processId.name));
+
+const isDev = (node, parent, scope) =>
+  t.isIdentifier(node, dev) &&
+  isGlobal(scope.getBinding(dev.name)) &&
+  !(t.isMemberExpression(parent));
+
+const inlinePlugin = {
+  visitor: {
+    Identifier(path, state) {
+      if (isDev(path.node, path.parent, path.scope)) {
+        path.replaceWith(t.booleanLiteral(state.opts.dev));
+      }
+    },
+    MemberExpression(path, state) {
+      const node = path.node;
+      const scope = path.scope;
+
+      if (isPlatformOS(node, scope) || isReactPlatformOS(node, scope)) {
+        path.replaceWith(t.stringLiteral(state.opts.platform));
+      }
+
+      if(isProcessEnvNodeEnv(node, scope)) {
+        path.replaceWith(
+          t.stringLiteral(state.opts.dev ? 'development' : 'production'));
+      }
+    },
+  },
+};
+
+const plugin = () => inlinePlugin;
+
+function inline(filename, transformResult, options) {
+  const code = transformResult.code;
+  const babelOptions = {
+    filename,
+    plugins: [[plugin, options]],
+    inputSourceMap: transformResult.map,
+    code: false,
+    babelrc: false,
+    compact: true,
+  };
+
+  return transformResult.ast
+      ? babel.transformFromAst(transformResult.ast, code, babelOptions)
+      : babel.transform(code, babelOptions);
+}
+
+module.exports = inline;
diff --git a/packager/react-packager/src/JSTransformer/worker/minify.js b/packager/react-packager/src/JSTransformer/worker/minify.js
new file mode 100644
index 000000000000..d343591874e4
--- /dev/null
+++ b/packager/react-packager/src/JSTransformer/worker/minify.js
@@ -0,0 +1,88 @@
+/**
+ * Copyright (c) 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.
+ */
+'use strict';
+
+const uglify = require('uglify-js');
+
+const MAGIC_MARKER = '\u0002\ueffe\ue277\uead5';
+const MAGIC_MARKER_SPLITTER =
+  /(?:\x02|\\u0002|\\x02)(?:\ueffe|\\ueffe)(?:\ue277|\\ue277)(?:\uead5|\\uead5)/;
+
+// IIFE = "immediately invoked function expression"
+// we wrap modules in functions to allow the minifier to mangle local variables
+function wrapCodeInIIFE(code, moduleLocals) {
+  return `(function(${moduleLocals.join(',')}){${code}}());`;
+}
+
+function extractCodeFromIIFE(code) {
+  return code.substring(code.indexOf('{') + 1, code.lastIndexOf('}'));
+}
+
+function extractModuleLocalsFromIIFE(code) {
+  return code.substring(code.indexOf('(', 1) + 1, code.indexOf(')')).split(',');
+}
+
+function splitFirstElementAt(array, offset) {
+  const first = array.shift();
+  array.unshift(first.slice(0, offset + 1), first.slice(offset + 1));
+  return array;
+}
+
+function insertMarkers(code, dependencyOffsets) {
+  return dependencyOffsets
+    .reduceRight(splitFirstElementAt, [code])
+    .join(MAGIC_MARKER);
+}
+
+function extractMarkers(codeWithMarkers) {
+  const dependencyOffsets = [];
+  const codeBits = codeWithMarkers.split(MAGIC_MARKER_SPLITTER);
+  var offset = 0;
+  for (var i = 0, max = codeBits.length - 1; i < max; i++) {
+    offset += codeBits[i].length;
+    dependencyOffsets.push(offset - 1);
+  }
+
+  return {code: codeBits.join(''), dependencyOffsets};
+}
+
+function minify(filename, code, map, dependencyOffsets, moduleLocals) {
+  // before minifying, code is wrapped in an immediately invoked function
+  // expression, so that top level variables can be shortened safely
+  code = wrapCodeInIIFE(
+    // since we don't know where the strings specifying dependencies will be
+    // located in the minified code, we mark them with a special marker string
+    // and extract them afterwards.
+    // That way, post-processing code can use these positions
+    insertMarkers(code, dependencyOffsets),
+    moduleLocals
+  );
+
+  const minifyResult = uglify.minify(code, {
+    fromString: true,
+    inSourceMap: map,
+    outSourceMap: filename,
+    output: {
+      ascii_only: true,
+      screw_ie8: true,
+    },
+  });
+
+  const minifiedModuleLocals = extractModuleLocalsFromIIFE(minifyResult.code);
+  const codeWithMarkers = extractCodeFromIIFE(minifyResult.code);
+  const result = extractMarkers(codeWithMarkers);
+  result.map = minifyResult.map;
+  result.moduleLocals = {};
+  moduleLocals.forEach(
+    (key, i) => result.moduleLocals[key] = minifiedModuleLocals[i]);
+
+  return result;
+}
+
+module.exports = minify;

From f67fa82008918e9e2875387db658911d197a6956 Mon Sep 17 00:00:00 2001
From: Pieter De Baets <pieterdb@fb.com>
Date: Tue, 1 Mar 2016 06:50:33 -0800
Subject: [PATCH 1359/1411] Add UIManager.measureInWindow to get window
 coordinates

Summary: When embedding in a hybrid app, we sometimes present new modal views or windows that have a different frame from the original root view. This API allows us to get coordinates in the application's window frame, which should be valid in any fullscreen view.

Reviewed By: majak

Differential Revision: D2939827

fb-gh-sync-id: 06b93cc2cb3519a25819c6efa445c779314dd673
shipit-source-id: 06b93cc2cb3519a25819c6efa445c779314dd673
---
 Libraries/ReactIOS/NativeMethodsMixin.js | 29 ++++++++++++++++++++++++
 React/Modules/RCTUIManager.m             | 23 +++++++++++++++++++
 2 files changed, 52 insertions(+)

diff --git a/Libraries/ReactIOS/NativeMethodsMixin.js b/Libraries/ReactIOS/NativeMethodsMixin.js
index c288ea8a01b0..f70a2821165e 100644
--- a/Libraries/ReactIOS/NativeMethodsMixin.js
+++ b/Libraries/ReactIOS/NativeMethodsMixin.js
@@ -27,6 +27,13 @@ type MeasureOnSuccessCallback = (
   pageY: number
 ) => void
 
+type MeasureInWindowOnSuccessCallback = (
+  x: number,
+  y: number,
+  width: number,
+  height: number,
+) => void
+
 type MeasureLayoutOnSuccessCallback = (
   left: number,
   top: number,
@@ -83,6 +90,28 @@ var NativeMethodsMixin = {
     );
   },
 
+  /**
+   * 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 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
diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m
index fdce48583276..d71939130f32 100644
--- a/React/Modules/RCTUIManager.m
+++ b/React/Modules/RCTUIManager.m
@@ -1076,6 +1076,29 @@ - (void)setNeedsLayout
   }];
 }
 
+RCT_EXPORT_METHOD(measureInWindow:(nonnull NSNumber *)reactTag
+                  callback:(RCTResponseSenderBlock)callback)
+{
+  [self addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
+    UIView *view = viewRegistry[reactTag];
+    if (!view) {
+      // this view was probably collapsed out
+      RCTLogWarn(@"measure cannot find view with tag #%@", reactTag);
+      callback(@[]);
+      return;
+    }
+
+    // Return frame coordinates in window
+    CGRect windowFrame = [view.window convertRect:view.frame fromView:view.superview];
+    callback(@[
+      @(windowFrame.origin.x),
+      @(windowFrame.origin.y),
+      @(windowFrame.size.width),
+      @(windowFrame.size.height),
+    ]);
+  }];
+}
+
 static void RCTMeasureLayout(RCTShadowView *view,
                              RCTShadowView *ancestor,
                              RCTResponseSenderBlock callback)

From bd95b22844e9facd2c6f34c644f4b33fd116c2d7 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Tue, 1 Mar 2016 07:57:11 -0800
Subject: [PATCH 1360/1411] WebWorkers: Add ExecutorToken to route native
 module calls to/from workers

Summary:To support native modules in web workers, native modules need to have an notion of the JS executor/thread that called into them in order to respond via Callback or JS module call to the right executor on the right thread.

ExecutorToken is an object that only serves as a token that can be used to identify an executor/message queue thread in the bridge. It doesn't expose any methods. Native modules Callback objects automatically have this ExecutionContext attached -- JSModule calls for modules that support workers will need to supply an appropriate ExecutorToken when retrieving the JSModule implementation from the ReactContext.

Reviewed By: mhorowitz

Differential Revision: D2965458

fb-gh-sync-id: 6e354d4df8536d40b12d02bd055f6d06b4ca595d
shipit-source-id: 6e354d4df8536d40b12d02bd055f6d06b4ca595d
---
 .../facebook/react/bridge/BaseJavaModule.java |  59 ++++---
 .../facebook/react/bridge/CallbackImpl.java   |   6 +-
 .../react/bridge/CatalystInstance.java        |   4 +-
 .../react/bridge/CatalystInstanceImpl.java    |  33 ++--
 .../facebook/react/bridge/ExecutorToken.java  |  24 +++
 .../bridge/JavaScriptModuleRegistry.java      |  56 +++++--
 .../facebook/react/bridge/NativeModule.java   |  22 ++-
 .../react/bridge/NativeModuleRegistry.java    |   6 +-
 .../facebook/react/bridge/ReactBridge.java    |   5 +-
 .../facebook/react/bridge/ReactCallback.java  |   2 +-
 .../facebook/react/bridge/ReactContext.java   |   7 +
 ReactAndroid/src/main/jni/react/BUCK          |   2 +
 ReactAndroid/src/main/jni/react/Bridge.cpp    | 150 +++++++++++++++---
 ReactAndroid/src/main/jni/react/Bridge.h      |  68 +++++++-
 .../src/main/jni/react/ExecutorToken.h        |  54 +++++++
 .../src/main/jni/react/ExecutorTokenFactory.h |  25 +++
 .../src/main/jni/react/JSCExecutor.cpp        |  31 ++--
 ReactAndroid/src/main/jni/react/JSCExecutor.h |  16 +-
 .../src/main/jni/react/jni/Android.mk         |   1 +
 ReactAndroid/src/main/jni/react/jni/BUCK      |   5 +-
 .../src/main/jni/react/jni/JExecutorToken.cpp |  20 +++
 .../src/main/jni/react/jni/JExecutorToken.h   |  59 +++++++
 .../jni/react/jni/JExecutorTokenFactory.h     |  24 +++
 .../src/main/jni/react/jni/OnLoad.cpp         |  41 +++--
 .../src/main/jni/react/jni/ProxyExecutor.cpp  |   4 +-
 .../react/bridge/BaseJavaModuleTest.java      |   6 +-
 26 files changed, 614 insertions(+), 116 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/ExecutorToken.java
 create mode 100644 ReactAndroid/src/main/jni/react/ExecutorToken.h
 create mode 100644 ReactAndroid/src/main/jni/react/ExecutorTokenFactory.h
 create mode 100644 ReactAndroid/src/main/jni/react/jni/JExecutorToken.cpp
 create mode 100644 ReactAndroid/src/main/jni/react/jni/JExecutorToken.h
 create mode 100644 ReactAndroid/src/main/jni/react/jni/JExecutorTokenFactory.h

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java
index 82d347c8c8f1..afa121acb402 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java
@@ -57,14 +57,14 @@ public int getJSArgumentsNeeded() {
     }
 
     public abstract @Nullable T extractArgument(
-        CatalystInstance catalystInstance, ReadableNativeArray jsArguments, int atIndex);
+        CatalystInstance catalystInstance, ExecutorToken executorToken, ReadableNativeArray jsArguments, int atIndex);
   }
 
   static final private ArgumentExtractor<Boolean> ARGUMENT_EXTRACTOR_BOOLEAN =
       new ArgumentExtractor<Boolean>() {
         @Override
         public Boolean extractArgument(
-            CatalystInstance catalystInstance, ReadableNativeArray jsArguments, int atIndex) {
+            CatalystInstance catalystInstance, ExecutorToken executorToken, ReadableNativeArray jsArguments, int atIndex) {
           return jsArguments.getBoolean(atIndex);
         }
       };
@@ -73,7 +73,7 @@ public Boolean extractArgument(
       new ArgumentExtractor<Double>() {
         @Override
         public Double extractArgument(
-            CatalystInstance catalystInstance, ReadableNativeArray jsArguments, int atIndex) {
+            CatalystInstance catalystInstance, ExecutorToken executorToken, ReadableNativeArray jsArguments, int atIndex) {
           return jsArguments.getDouble(atIndex);
         }
       };
@@ -82,7 +82,7 @@ public Double extractArgument(
       new ArgumentExtractor<Float>() {
         @Override
         public Float extractArgument(
-            CatalystInstance catalystInstance, ReadableNativeArray jsArguments, int atIndex) {
+            CatalystInstance catalystInstance, ExecutorToken executorToken, ReadableNativeArray jsArguments, int atIndex) {
           return (float) jsArguments.getDouble(atIndex);
         }
       };
@@ -91,7 +91,7 @@ public Float extractArgument(
       new ArgumentExtractor<Integer>() {
         @Override
         public Integer extractArgument(
-            CatalystInstance catalystInstance, ReadableNativeArray jsArguments, int atIndex) {
+            CatalystInstance catalystInstance, ExecutorToken executorToken, ReadableNativeArray jsArguments, int atIndex) {
           return (int) jsArguments.getDouble(atIndex);
         }
       };
@@ -100,7 +100,7 @@ public Integer extractArgument(
       new ArgumentExtractor<String>() {
         @Override
         public String extractArgument(
-            CatalystInstance catalystInstance, ReadableNativeArray jsArguments, int atIndex) {
+            CatalystInstance catalystInstance, ExecutorToken executorToken, ReadableNativeArray jsArguments, int atIndex) {
           return jsArguments.getString(atIndex);
         }
       };
@@ -109,7 +109,7 @@ public String extractArgument(
       new ArgumentExtractor<ReadableNativeArray>() {
         @Override
         public ReadableNativeArray extractArgument(
-            CatalystInstance catalystInstance, ReadableNativeArray jsArguments, int atIndex) {
+            CatalystInstance catalystInstance, ExecutorToken executorToken, ReadableNativeArray jsArguments, int atIndex) {
           return jsArguments.getArray(atIndex);
         }
       };
@@ -118,7 +118,7 @@ public ReadableNativeArray extractArgument(
       new ArgumentExtractor<ReadableMap>() {
         @Override
         public ReadableMap extractArgument(
-            CatalystInstance catalystInstance, ReadableNativeArray jsArguments, int atIndex) {
+            CatalystInstance catalystInstance, ExecutorToken executorToken, ReadableNativeArray jsArguments, int atIndex) {
           return jsArguments.getMap(atIndex);
         }
       };
@@ -127,12 +127,12 @@ public ReadableMap extractArgument(
       new ArgumentExtractor<Callback>() {
         @Override
         public @Nullable Callback extractArgument(
-            CatalystInstance catalystInstance, ReadableNativeArray jsArguments, int atIndex) {
+            CatalystInstance catalystInstance, ExecutorToken executorToken, ReadableNativeArray jsArguments, int atIndex) {
           if (jsArguments.isNull(atIndex)) {
             return null;
           } else {
             int id = (int) jsArguments.getDouble(atIndex);
-            return new CallbackImpl(catalystInstance, id);
+            return new CallbackImpl(catalystInstance, executorToken, id);
           }
         }
       };
@@ -146,11 +146,11 @@ public int getJSArgumentsNeeded() {
 
         @Override
         public Promise extractArgument(
-            CatalystInstance catalystInstance, ReadableNativeArray jsArguments, int atIndex) {
+            CatalystInstance catalystInstance, ExecutorToken executorToken, ReadableNativeArray jsArguments, int atIndex) {
           Callback resolve = ARGUMENT_EXTRACTOR_CALLBACK
-              .extractArgument(catalystInstance, jsArguments, atIndex);
+              .extractArgument(catalystInstance, executorToken, jsArguments, atIndex);
           Callback reject = ARGUMENT_EXTRACTOR_CALLBACK
-              .extractArgument(catalystInstance, jsArguments, atIndex + 1);
+              .extractArgument(catalystInstance, executorToken, jsArguments, atIndex + 1);
           return new PromiseImpl(resolve, reject);
         }
       };
@@ -174,9 +174,21 @@ public JavaMethod(Method method) {
     }
 
     private ArgumentExtractor[] buildArgumentExtractors(Class[] paramTypes) {
-      ArgumentExtractor[] argumentExtractors = new ArgumentExtractor[paramTypes.length];
-      for (int i = 0; i < paramTypes.length; i += argumentExtractors[i].getJSArgumentsNeeded()) {
-        Class argumentClass = paramTypes[i];
+      // Modules that support web workers are expected to take an ExecutorToken as the first
+      // parameter to all their @ReactMethod-annotated methods. We compensate for that here.
+      int executorTokenOffset = 0;
+      if (BaseJavaModule.this.supportsWebWorkers()) {
+        if (paramTypes[0] != ExecutorToken.class) {
+          throw new RuntimeException(
+              "Module " + BaseJavaModule.this + " supports web workers, but " + mMethod.getName() +
+                  "does not take an ExecutorToken as its first parameter.");
+        }
+        executorTokenOffset = 1;
+      }
+
+      ArgumentExtractor[] argumentExtractors = new ArgumentExtractor[paramTypes.length - executorTokenOffset];
+      for (int i = 0; i < paramTypes.length - executorTokenOffset; i += argumentExtractors[i].getJSArgumentsNeeded()) {
+        Class argumentClass = paramTypes[i + executorTokenOffset];
         if (argumentClass == Boolean.class || argumentClass == boolean.class) {
           argumentExtractors[i] = ARGUMENT_EXTRACTOR_BOOLEAN;
         } else if (argumentClass == Integer.class || argumentClass == int.class) {
@@ -220,7 +232,7 @@ private String getAffectedRange(int startIndex, int jsArgumentsNeeded) {
     }
 
     @Override
-    public void invoke(CatalystInstance catalystInstance, ReadableNativeArray parameters) {
+    public void invoke(CatalystInstance catalystInstance, ExecutorToken executorToken, ReadableNativeArray parameters) {
       Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "callJavaModuleMethod");
       try {
         if (mJSArgumentsNeeded != parameters.size()) {
@@ -229,11 +241,18 @@ public void invoke(CatalystInstance catalystInstance, ReadableNativeArray parame
               parameters.size() + " arguments, expected " + mJSArgumentsNeeded);
         }
 
+        // Modules that support web workers are expected to take an ExecutorToken as the first
+        // parameter to all their @ReactMethod-annotated methods. We compensate for that here.
         int i = 0, jsArgumentsConsumed = 0;
+        int executorTokenOffset = 0;
+        if (BaseJavaModule.this.supportsWebWorkers()) {
+          mArguments[0] = executorToken;
+          executorTokenOffset = 1;
+        }
         try {
           for (; i < mArgumentExtractors.length; i++) {
-            mArguments[i] = mArgumentExtractors[i].extractArgument(
-                catalystInstance, parameters, jsArgumentsConsumed);
+            mArguments[i + executorTokenOffset] = mArgumentExtractors[i].extractArgument(
+                catalystInstance, executorToken, parameters, jsArgumentsConsumed);
             jsArgumentsConsumed += mArgumentExtractors[i].getJSArgumentsNeeded();
           }
         } catch (UnexpectedNativeTypeException e) {
@@ -341,7 +360,7 @@ public void onReactBridgeInitialized(ReactBridge bridge) {
   public void onCatalystInstanceDestroy() {
     // do nothing
   }
-
+  
   @Override
   public boolean supportsWebWorkers() {
     return false;
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CallbackImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CallbackImpl.java
index 8b5153e5cc51..a7bc858026ee 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CallbackImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CallbackImpl.java
@@ -15,15 +15,17 @@
 public final class CallbackImpl implements Callback {
 
   private final CatalystInstance mCatalystInstance;
+  private final ExecutorToken mExecutorToken;
   private final int mCallbackId;
 
-  public CallbackImpl(CatalystInstance bridge, int callbackId) {
+  public CallbackImpl(CatalystInstance bridge, ExecutorToken executorToken, int callbackId) {
     mCatalystInstance = bridge;
+    mExecutorToken = executorToken;
     mCallbackId = callbackId;
   }
 
   @Override
   public void invoke(Object... args) {
-    mCatalystInstance.invokeCallback(mCallbackId, Arguments.fromJavaArgs(args));
+    mCatalystInstance.invokeCallback(mExecutorToken, mCallbackId, Arguments.fromJavaArgs(args));
   }
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
index 466f229d151d..98ac8d76398b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
@@ -14,7 +14,6 @@
 import com.facebook.react.bridge.queue.ReactQueueConfiguration;
 import com.facebook.react.common.annotations.VisibleForTesting;
 import com.facebook.proguard.annotations.DoNotStrip;
-import com.facebook.react.common.annotations.VisibleForTesting;
 
 /**
  * A higher level API on top of the asynchronous JSC bridge. This provides an
@@ -27,7 +26,7 @@ public interface CatalystInstance {
   // This is called from java code, so it won't be stripped anyway, but proguard will rename it,
   // which this prevents.
   @DoNotStrip
-  void invokeCallback(final int callbackID, final NativeArray arguments);
+  void invokeCallback(ExecutorToken executorToken, final int callbackID, final NativeArray arguments);
   /**
    * Destroys this catalyst instance, waiting for any other threads in ReactQueueConfiguration
    * (besides the UI thread) to finish running. Must be called from the UI thread so that we can
@@ -45,6 +44,7 @@ public interface CatalystInstance {
   ReactQueueConfiguration getReactQueueConfiguration();
 
   <T extends JavaScriptModule> T getJSModule(Class<T> jsInterface);
+  <T extends JavaScriptModule> T getJSModule(ExecutorToken executorToken, Class<T> jsInterface);
   <T extends NativeModule> T getNativeModule(Class<T> nativeModuleInterface);
   Collection<NativeModule> getNativeModules();
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
index 40618ac95c15..df8b26604c47 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
@@ -54,6 +54,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
   private final JavaScriptModuleRegistry mJSModuleRegistry;
   private final JSBundleLoader mJSBundleLoader;
   private final Object mTeardownLock = new Object();
+  private @Nullable ExecutorToken mMainExecutorToken;
 
   // Access from native modules thread
   private final NativeModuleRegistry mJavaRegistry;
@@ -113,6 +114,7 @@ private ReactBridge initializeBridge(
           jsExecutor,
           new NativeModulesReactCallback(),
           mReactQueueConfiguration.getNativeModulesQueueThread());
+      mMainExecutorToken = bridge.getMainExecutorToken();
     } finally {
       Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
     }
@@ -165,10 +167,11 @@ public Boolean call() throws Exception {
   }
 
   /* package */ void callFunction(
-      final int moduleId,
-      final int methodId,
-      final NativeArray arguments,
-      final String tracingName) {
+      ExecutorToken executorToken,
+      int moduleId,
+      int methodId,
+      NativeArray arguments,
+      String tracingName) {
     synchronized (mTeardownLock) {
       if (mDestroyed) {
         FLog.w(ReactConstants.TAG, "Calling JS function after bridge has been destroyed.");
@@ -177,7 +180,7 @@ public Boolean call() throws Exception {
 
       incrementPendingJSCalls();
 
-      Assertions.assertNotNull(mBridge).callFunction(moduleId, methodId, arguments, tracingName);
+      Assertions.assertNotNull(mBridge).callFunction(executorToken, moduleId, methodId, arguments, tracingName);
     }
   }
 
@@ -185,7 +188,7 @@ public Boolean call() throws Exception {
   // which this prevents.
   @DoNotStrip
   @Override
-  public void invokeCallback(final int callbackID, final NativeArray arguments) {
+  public void invokeCallback(ExecutorToken executorToken, int callbackID, NativeArray arguments) {
     synchronized (mTeardownLock) {
       if (mDestroyed) {
         FLog.w(ReactConstants.TAG, "Invoking JS callback after bridge has been destroyed.");
@@ -194,7 +197,7 @@ public void invokeCallback(final int callbackID, final NativeArray arguments) {
 
       incrementPendingJSCalls();
 
-      Assertions.assertNotNull(mBridge).invokeCallback(callbackID, arguments);
+      Assertions.assertNotNull(mBridge).invokeCallback(executorToken, callbackID, arguments);
     }
   }
 
@@ -269,7 +272,12 @@ public ReactQueueConfiguration getReactQueueConfiguration() {
 
   @Override
   public <T extends JavaScriptModule> T getJSModule(Class<T> jsInterface) {
-    return Assertions.assertNotNull(mJSModuleRegistry).getJavaScriptModule(jsInterface);
+    return getJSModule(Assertions.assertNotNull(mMainExecutorToken), jsInterface);
+  }
+
+  @Override
+  public <T extends JavaScriptModule> T getJSModule(ExecutorToken executorToken, Class<T> jsInterface) {
+    return Assertions.assertNotNull(mJSModuleRegistry).getJavaScriptModule(executorToken, jsInterface);
   }
 
   @Override
@@ -388,7 +396,7 @@ private void decrementPendingJSCalls() {
   private class NativeModulesReactCallback implements ReactCallback {
 
     @Override
-    public void call(int moduleId, int methodId, ReadableNativeArray parameters) {
+    public void call(ExecutorToken executorToken, int moduleId, int methodId, ReadableNativeArray parameters) {
       mReactQueueConfiguration.getNativeModulesQueueThread().assertIsOnThread();
 
       // Suppress any callbacks if destroyed - will only lead to sadness.
@@ -396,7 +404,7 @@ public void call(int moduleId, int methodId, ReadableNativeArray parameters) {
         return;
       }
 
-      mJavaRegistry.call(CatalystInstanceImpl.this, moduleId, methodId, parameters);
+      mJavaRegistry.call(CatalystInstanceImpl.this, executorToken, moduleId, methodId, parameters);
     }
 
     @Override
@@ -441,12 +449,13 @@ public void run() {
   private class JSProfilerTraceListener implements TraceListener {
     @Override
     public void onTraceStarted() {
-      getJSModule(com.facebook.react.bridge.Systrace.class).setEnabled(true);
+      getJSModule(Assertions.assertNotNull(mMainExecutorToken), com.facebook.react.bridge.Systrace.class).setEnabled(
+          true);
     }
 
     @Override
     public void onTraceStopped() {
-      getJSModule(com.facebook.react.bridge.Systrace.class).setEnabled(false);
+      getJSModule(Assertions.assertNotNull(mMainExecutorToken), com.facebook.react.bridge.Systrace.class).setEnabled(false);
     }
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ExecutorToken.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ExecutorToken.java
new file mode 100644
index 000000000000..e23bbebfb7d1
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ExecutorToken.java
@@ -0,0 +1,24 @@
+package com.facebook.react.bridge;
+
+import com.facebook.jni.HybridData;
+import com.facebook.proguard.annotations.DoNotStrip;
+
+/**
+ * Class corresponding to a JS VM that can call into native modules. In Java, this should
+ * just be treated as a black box to be used to help the framework route native->JS calls back to
+ * the proper JS VM. See {@link ReactContext#getJSModule(ExecutorToken, Class)} and
+ * {@link BaseJavaModule#supportsWebWorkers()}.
+ *
+ * Note: If your application doesn't use web workers, it will only have a single ExecutorToken
+ * per instance of React Native.
+ */
+@DoNotStrip
+public class ExecutorToken {
+
+  private final HybridData mHybridData;
+
+  @DoNotStrip
+  private ExecutorToken(HybridData hybridData) {
+    mHybridData = hybridData;
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModuleRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModuleRegistry.java
index 093770fe05fd..9a48e686bb55 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModuleRegistry.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptModuleRegistry.java
@@ -12,12 +12,16 @@
 import javax.annotation.Nullable;
 
 import java.lang.Class;
+import java.lang.ref.WeakReference;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
 import java.util.HashMap;
+import java.util.WeakHashMap;
 
+import com.facebook.common.logging.FLog;
 import com.facebook.infer.annotation.Assertions;
+import com.facebook.react.common.ReactConstants;
 
 /**
  * Class responsible for holding all the {@link JavaScriptModule}s registered to this
@@ -27,45 +31,71 @@
  */
 /*package*/ class JavaScriptModuleRegistry {
 
-  private final HashMap<Class<? extends JavaScriptModule>, JavaScriptModule> mModuleInstances;
+  private final CatalystInstanceImpl mCatalystInstance;
+  private final WeakHashMap<ExecutorToken, HashMap<Class<? extends JavaScriptModule>, JavaScriptModule>> mModuleInstances;
+  private final HashMap<Class<? extends JavaScriptModule>, JavaScriptModuleRegistration> mModuleRegistrations;
 
   public JavaScriptModuleRegistry(
       CatalystInstanceImpl instance,
       JavaScriptModulesConfig config) {
-    mModuleInstances = new HashMap<>();
+    mCatalystInstance = instance;
+    mModuleInstances = new WeakHashMap<>();
+    mModuleRegistrations = new HashMap<>();
     for (JavaScriptModuleRegistration registration : config.getModuleDefinitions()) {
-      Class<? extends JavaScriptModule> moduleInterface = registration.getModuleInterface();
-      JavaScriptModule interfaceProxy = (JavaScriptModule) Proxy.newProxyInstance(
-          moduleInterface.getClassLoader(),
-          new Class[]{moduleInterface},
-          new JavaScriptModuleInvocationHandler(instance, registration));
-
-      mModuleInstances.put(moduleInterface, interfaceProxy);
+      mModuleRegistrations.put(registration.getModuleInterface(), registration);
     }
   }
 
-  public <T extends JavaScriptModule> T getJavaScriptModule(Class<T> moduleInterface) {
-    return (T) Assertions.assertNotNull(
-        mModuleInstances.get(moduleInterface),
-        "JS module " + moduleInterface.getSimpleName() + " hasn't been registered!");
+  public synchronized  <T extends JavaScriptModule> T getJavaScriptModule(ExecutorToken executorToken, Class<T> moduleInterface) {
+    HashMap<Class<? extends JavaScriptModule>, JavaScriptModule> instancesForContext =
+        mModuleInstances.get(executorToken);
+    if (instancesForContext == null) {
+      instancesForContext = new HashMap<>();
+      mModuleInstances.put(executorToken, instancesForContext);
+    }
+
+    JavaScriptModule module = instancesForContext.get(moduleInterface);
+    if (module != null) {
+      return (T) module;
+    }
+
+    JavaScriptModuleRegistration registration =
+        Assertions.assertNotNull(
+            mModuleRegistrations.get(moduleInterface),
+            "JS module " + moduleInterface.getSimpleName() + " hasn't been registered!");
+    JavaScriptModule interfaceProxy = (JavaScriptModule) Proxy.newProxyInstance(
+        moduleInterface.getClassLoader(),
+        new Class[]{moduleInterface},
+        new JavaScriptModuleInvocationHandler(executorToken, mCatalystInstance, registration));
+    instancesForContext.put(moduleInterface, interfaceProxy);
+    return (T) interfaceProxy;
   }
 
   private static class JavaScriptModuleInvocationHandler implements InvocationHandler {
 
+    private final WeakReference<ExecutorToken> mExecutorToken;
     private final CatalystInstanceImpl mCatalystInstance;
     private final JavaScriptModuleRegistration mModuleRegistration;
 
     public JavaScriptModuleInvocationHandler(
+        ExecutorToken executorToken,
         CatalystInstanceImpl catalystInstance,
         JavaScriptModuleRegistration moduleRegistration) {
+      mExecutorToken = new WeakReference<>(executorToken);
       mCatalystInstance = catalystInstance;
       mModuleRegistration = moduleRegistration;
     }
 
     @Override
     public @Nullable Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+      ExecutorToken executorToken = mExecutorToken.get();
+      if (executorToken == null) {
+        FLog.w(ReactConstants.TAG, "Dropping JS call, ExecutorToken went away...");
+        return null;
+      }
       String tracingName = mModuleRegistration.getTracingName(method);
       mCatalystInstance.callFunction(
+        executorToken,
           mModuleRegistration.getModuleId(),
           mModuleRegistration.getMethodId(method),
           Arguments.fromJavaArgs(args),
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java
index 8996547f257a..e954bc901552 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModule.java
@@ -23,7 +23,7 @@
  */
 public interface NativeModule {
   interface NativeMethod {
-    void invoke(CatalystInstance catalystInstance, ReadableNativeArray parameters);
+    void invoke(CatalystInstance catalystInstance, ExecutorToken executorToken, ReadableNativeArray parameters);
     String getType();
   }
 
@@ -74,7 +74,25 @@ interface NativeMethod {
   void onCatalystInstanceDestroy();
 
   /**
-   * Whether this native module supports calls from web workers. Ignored for now.
+   * In order to support web workers, a module must be aware that it can be invoked from multiple
+   * different JS VMs. Supporting web workers means recognizing things like:
+   *
+   * 1) ids (e.g. timer ids, request ids, etc.) may only unique on a per-VM basis
+   * 2) the module needs to make sure to enqueue callbacks and JS module calls to the correct VM
+   *
+   * In order to facilitate this, modules that support web workers will have all their @ReactMethod-
+   * annotated methods passed a {@link ExecutorToken} as the first parameter before any arguments
+   * from JS. This ExecutorToken internally maps to a specific JS VM and can be used by the
+   * framework to route calls appropriately. In order to make JS module calls correctly, start using
+   * the version of {@link ReactContext#getJSModule(ExecutorToken, Class)} that takes an
+   * ExecutorToken. It will ensure that any calls you dispatch to the returned object will go to
+   * the right VM. For Callbacks, you don't have to do anything special -- the framework
+   * automatically tags them with the correct ExecutorToken when the are created.
+   *
+   * Note: even though calls can come from multiple JS VMs on multiple threads, calls to this module
+   * will still only occur on a single thread.
+   *
+   * @return whether this module supports web workers.
    */
   boolean supportsWebWorkers();
 }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java
index c8a59e8f73ac..0d5cc0e65a78 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java
@@ -48,6 +48,7 @@ private NativeModuleRegistry(
 
   /* package */ void call(
       CatalystInstance catalystInstance,
+      ExecutorToken executorToken,
       int moduleId,
       int methodId,
       ReadableNativeArray parameters) {
@@ -55,7 +56,7 @@ private NativeModuleRegistry(
     if (definition == null) {
       throw new RuntimeException("Call to unknown module: " + moduleId);
     }
-    definition.call(catalystInstance, methodId, parameters);
+    definition.call(catalystInstance, executorToken, methodId, parameters);
   }
 
   /* package */ void writeModuleDescriptions(JsonGenerator jg) throws IOException {
@@ -164,12 +165,13 @@ public ModuleDefinition(int id, String name, NativeModule target) {
 
     public void call(
         CatalystInstance catalystInstance,
+        ExecutorToken executorToken,
         int methodId,
         ReadableNativeArray parameters) {
       MethodRegistration method = this.methods.get(methodId);
       Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, method.tracingName);
       try {
-        this.methods.get(methodId).method.invoke(catalystInstance, parameters);
+        this.methods.get(methodId).method.invoke(catalystInstance, executorToken, parameters);
       } finally {
         Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
       }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java
index 1e9fe67482db..3c8128244f4b 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java
@@ -79,12 +79,13 @@ private native void initialize(
    */
   public native void loadScriptFromAssets(AssetManager assetManager, String assetName);
   public native void loadScriptFromFile(@Nullable String fileName, @Nullable String sourceURL);
-  public native void callFunction(int moduleId, int methodId, NativeArray arguments, String tracingName);
-  public native void invokeCallback(int callbackID, NativeArray arguments);
+  public native void callFunction(ExecutorToken executorToken, int moduleId, int methodId, NativeArray arguments, String tracingName);
+  public native void invokeCallback(ExecutorToken executorToken, int callbackID, NativeArray arguments);
   public native void setGlobalVariable(String propertyName, String jsonEncodedArgument);
   public native boolean supportsProfiling();
   public native void startProfiler(String title);
   public native void stopProfiler(String title, String filename);
+  public native ExecutorToken getMainExecutorToken();
   private native void handleMemoryPressureModerate();
   private native void handleMemoryPressureCritical();
   public native void destroy();
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactCallback.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactCallback.java
index 7e4376c56851..0399f27cf7a7 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactCallback.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactCallback.java
@@ -15,7 +15,7 @@
 public interface ReactCallback {
 
   @DoNotStrip
-  void call(int moduleId, int methodId, ReadableNativeArray parameters);
+  void call(ExecutorToken executorToken, int moduleId, int methodId, ReadableNativeArray parameters);
 
   @DoNotStrip
   void onBatchComplete();
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java
index 4ef692a8bdd1..8e7880b594e2 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java
@@ -96,6 +96,13 @@ public <T extends JavaScriptModule> T getJSModule(Class<T> jsInterface) {
     return mCatalystInstance.getJSModule(jsInterface);
   }
 
+  public <T extends JavaScriptModule> T getJSModule(ExecutorToken executorToken, Class<T> jsInterface) {
+    if (mCatalystInstance == null) {
+      throw new RuntimeException("Trying to invoke JS before CatalystInstance has been set!");
+    }
+    return mCatalystInstance.getJSModule(executorToken, jsInterface);
+  }
+
   /**
    * @return the instance of the specified module interface associated with this ReactContext.
    */
diff --git a/ReactAndroid/src/main/jni/react/BUCK b/ReactAndroid/src/main/jni/react/BUCK
index f9ac1edb5f8d..4c9a9d66bf5f 100644
--- a/ReactAndroid/src/main/jni/react/BUCK
+++ b/ReactAndroid/src/main/jni/react/BUCK
@@ -67,6 +67,8 @@ react_library(
   exported_headers = [
     'AlignStack.h',
     'Bridge.h',
+    'ExecutorToken.h',
+    'ExecutorTokenFactory.h',
     'Executor.h',
     'JSCExecutor.h',
     'JSCHelpers.h',
diff --git a/ReactAndroid/src/main/jni/react/Bridge.cpp b/ReactAndroid/src/main/jni/react/Bridge.cpp
index ed758d1f0079..84568b16ff1f 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.cpp
+++ b/ReactAndroid/src/main/jni/react/Bridge.cpp
@@ -7,17 +7,26 @@
 using fbsystrace::FbSystraceSection;
 using fbsystrace::FbSystraceAsyncFlow;
 #endif
+#include <folly/Memory.h>
 
 #include "Platform.h"
 
 namespace facebook {
 namespace react {
 
-Bridge::Bridge(JSExecutorFactory* jsExecutorFactory, Callback callback) :
-    m_callback(std::move(callback)),
-    m_destroyed(std::make_shared<bool>(false)),
-    m_mainJSMessageQueueThread(MessageQueues::getCurrentMessageQueueThread()) {
-    m_mainExecutor = jsExecutorFactory->createJSExecutor(this);
+Bridge::Bridge(
+    JSExecutorFactory* jsExecutorFactory,
+    std::unique_ptr<ExecutorTokenFactory> executorTokenFactory,
+    Callback callback) :
+  m_callback(std::move(callback)),
+  m_destroyed(std::make_shared<bool>(false)),
+  m_executorTokenFactory(std::move(executorTokenFactory)) {
+  std::unique_ptr<JSExecutor> mainExecutor = jsExecutorFactory->createJSExecutor(this);
+  // cached to avoid locked map lookup in the common case
+  m_mainExecutor = mainExecutor.get();
+  m_mainExecutorToken = folly::make_unique<ExecutorToken>(registerExecutor(
+      std::move(mainExecutor),
+      MessageQueues::getCurrentMessageQueueThread()));
 }
 
 // This must be called on the same thread on which the constructor was called.
@@ -37,6 +46,7 @@ void Bridge::loadApplicationUnbundle(
 }
 
 void Bridge::callFunction(
+    ExecutorToken executorToken,
     const double moduleId,
     const double methodId,
     const folly::dynamic& arguments,
@@ -52,11 +62,15 @@ void Bridge::callFunction(
       tracingName.c_str(),
       systraceCookie);
   #endif
+
+  auto executorMessageQueueThread = getMessageQueueThread(executorToken);
+  if (executorMessageQueueThread == nullptr) {
+    LOG(WARNING) << "Dropping JS call for executor that has been unregistered...";
+    return;
+  }
+
   std::shared_ptr<bool> isDestroyed = m_destroyed;
-  m_mainJSMessageQueueThread->runOnQueue([=] () {
-    if (*isDestroyed) {
-      return;
-    }
+  executorMessageQueueThread->runOnQueue([=] () {
     #ifdef WITH_FBSYSTRACE
     FbSystraceAsyncFlow::end(
         TRACE_TAG_REACT_CXX_BRIDGE,
@@ -64,11 +78,25 @@ void Bridge::callFunction(
         systraceCookie);
     FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, tracingName.c_str());
     #endif
-    m_mainExecutor->callFunction(moduleId, methodId, arguments);
+
+    if (*isDestroyed) {
+      return;
+    }
+
+    JSExecutor *executor = getExecutor(executorToken);
+    if (executor == nullptr) {
+      LOG(WARNING) << "Dropping JS call for executor that has been unregistered...";
+      return;
+    }
+
+    // This is safe because we are running on the executor's thread: it won't
+    // destruct until after it's been unregistered (which we check above) and
+    // that will happen on this thread
+    executor->callFunction(moduleId, methodId, arguments);
   });
 }
 
-void Bridge::invokeCallback(const double callbackId, const folly::dynamic& arguments) {
+void Bridge::invokeCallback(ExecutorToken executorToken, const double callbackId, const folly::dynamic& arguments) {
   if (*m_destroyed) {
     return;
   }
@@ -80,11 +108,15 @@ void Bridge::invokeCallback(const double callbackId, const folly::dynamic& argum
       "<callback>",
       systraceCookie);
   #endif
+
+  auto executorMessageQueueThread = getMessageQueueThread(executorToken);
+  if (executorMessageQueueThread == nullptr) {
+    LOG(WARNING) << "Dropping JS call for executor that has been unregistered...";
+    return;
+  }
+
   std::shared_ptr<bool> isDestroyed = m_destroyed;
-  m_mainJSMessageQueueThread->runOnQueue([=] () {
-    if (*isDestroyed) {
-      return;
-    }
+  executorMessageQueueThread->runOnQueue([=] () {
     #ifdef WITH_FBSYSTRACE
     FbSystraceAsyncFlow::end(
         TRACE_TAG_REACT_CXX_BRIDGE,
@@ -92,7 +124,21 @@ void Bridge::invokeCallback(const double callbackId, const folly::dynamic& argum
         systraceCookie);
     FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "Bridge.invokeCallback");
     #endif
-    m_mainExecutor->invokeCallback(callbackId, arguments);
+
+    if (*isDestroyed) {
+      return;
+    }
+
+    JSExecutor *executor = getExecutor(executorToken);
+    if (executor == nullptr) {
+      LOG(WARNING) << "Dropping JS call for executor that has been unregistered...";
+      return;
+    }
+
+    // This is safe because we are running on the executor's thread: it won't
+    // destruct until after it's been unregistered (which we check above) and
+    // that will happen on this thread
+    executor->invokeCallback(callbackId, arguments);
   });
 }
 
@@ -124,17 +170,83 @@ void Bridge::handleMemoryPressureCritical() {
   m_mainExecutor->handleMemoryPressureCritical();
 }
 
-void Bridge::callNativeModules(const std::string& callJSON, bool isEndOfBatch) {
+void Bridge::callNativeModules(JSExecutor& executor, const std::string& callJSON, bool isEndOfBatch) {
   if (*m_destroyed) {
     return;
   }
-  m_callback(parseMethodCalls(callJSON), isEndOfBatch);
+  m_callback(getTokenForExecutor(executor), parseMethodCalls(callJSON), isEndOfBatch);
+}
+
+ExecutorToken Bridge::getMainExecutorToken() const {
+  return *m_mainExecutorToken.get();
+}
+
+ExecutorToken Bridge::registerExecutor(
+    std::unique_ptr<JSExecutor> executor,
+    std::shared_ptr<MessageQueueThread> messageQueueThread) {
+  auto token = m_executorTokenFactory->createExecutorToken();
+
+  std::lock_guard<std::mutex> registrationGuard(m_registrationMutex);
+
+  CHECK(m_executorTokenMap.find(executor.get()) == m_executorTokenMap.end())
+      << "Trying to register an already registered executor!";
+
+  m_executorTokenMap.emplace(executor.get(), token);
+  m_executorMap.emplace(
+      token,
+      folly::make_unique<ExecutorRegistration>(std::move(executor), std::move(messageQueueThread)));
+
+  return token;
+}
+
+std::unique_ptr<JSExecutor> Bridge::unregisterExecutor(ExecutorToken executorToken) {
+  std::unique_ptr<JSExecutor> executor;
+
+  {
+    std::lock_guard<std::mutex> registrationGuard(m_registrationMutex);
+
+    auto it = m_executorMap.find(executorToken);
+    CHECK(it != m_executorMap.end())
+        << "Trying to unregister an executor that was never registered!";
+
+    executor = std::move(it->second->executor_);
+    m_executorMap.erase(it);
+    m_executorTokenMap.erase(executor.get());
+  }
+
+  // TODO: Notify native modules that ExecutorToken destroyed
+
+  return executor;
+}
+
+MessageQueueThread* Bridge::getMessageQueueThread(const ExecutorToken& executorToken) {
+  std::lock_guard<std::mutex> registrationGuard(m_registrationMutex);
+  auto it = m_executorMap.find(executorToken);
+  if (it == m_executorMap.end()) {
+    return nullptr;
+  }
+  return it->second->messageQueueThread_.get();
+}
+
+JSExecutor* Bridge::getExecutor(const ExecutorToken& executorToken) {
+  std::lock_guard<std::mutex> registrationGuard(m_registrationMutex);
+  auto it = m_executorMap.find(executorToken);
+  if (it == m_executorMap.end()) {
+    return nullptr;
+  }
+  return it->second->executor_.get();
+}
+
+ExecutorToken Bridge::getTokenForExecutor(JSExecutor& executor) {
+  std::lock_guard<std::mutex> registrationGuard(m_registrationMutex);
+  return m_executorTokenMap.at(&executor);
 }
 
 void Bridge::destroy() {
   *m_destroyed = true;
+  std::unique_ptr<JSExecutor> mainExecutor = unregisterExecutor(*m_mainExecutorToken);
   m_mainExecutor->destroy();
-  m_mainExecutor.reset();
+  mainExecutor.reset();
 }
 
 } }
diff --git a/ReactAndroid/src/main/jni/react/Bridge.h b/ReactAndroid/src/main/jni/react/Bridge.h
index 16edc62ac10c..05a0e64189c9 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.h
+++ b/ReactAndroid/src/main/jni/react/Bridge.h
@@ -7,6 +7,8 @@
 #include <map>
 #include <vector>
 
+#include "ExecutorToken.h"
+#include "ExecutorTokenFactory.h"
 #include "Executor.h"
 #include "MessageQueueThread.h"
 #include "MethodCall.h"
@@ -22,14 +24,30 @@ struct dynamic;
 namespace facebook {
 namespace react {
 
+class Bridge;
+class ExecutorRegistration {
+public:
+  ExecutorRegistration(
+      std::unique_ptr<JSExecutor> executor,
+      std::shared_ptr<MessageQueueThread> executorMessageQueueThread) :
+    executor_(std::move(executor)),
+    messageQueueThread_(executorMessageQueueThread) {}
+
+  std::unique_ptr<JSExecutor> executor_;
+  std::shared_ptr<MessageQueueThread> messageQueueThread_;
+};
+
 class Bridge {
 public:
-  typedef std::function<void(std::vector<MethodCall>, bool isEndOfBatch)> Callback;
+  typedef std::function<void(ExecutorToken executorToken, std::vector<MethodCall>, bool isEndOfBatch)> Callback;
 
   /**
    * This must be called on the main JS thread.
    */
-  Bridge(JSExecutorFactory* jsExecutorFactory, Callback callback);
+  Bridge(
+      JSExecutorFactory* jsExecutorFactory,
+      std::unique_ptr<ExecutorTokenFactory> executorTokenFactory,
+      Callback callback);
   virtual ~Bridge();
 
   /**
@@ -37,6 +55,7 @@ class Bridge {
    * arguments in JS.
    */
   void callFunction(
+    ExecutorToken executorToken,
     const double moduleId,
     const double methodId,
     const folly::dynamic& args,
@@ -45,7 +64,7 @@ class Bridge {
   /**
    * Invokes a callback with the cbID, and optional additional arguments in JS.
    */
-  void invokeCallback(const double callbackId, const folly::dynamic& args);
+  void invokeCallback(ExecutorToken executorToken, const double callbackId, const folly::dynamic& args);
 
   /**
    * Starts the JS application from an "bundle", i.e. a JavaScript file that
@@ -71,9 +90,38 @@ class Bridge {
   void handleMemoryPressureCritical();
 
   /**
+   * Invokes a set of native module calls on behalf of the given executor.
+   *
    * TODO: get rid of isEndOfBatch
    */
-  void callNativeModules(const std::string& callJSON, bool isEndOfBatch);
+  void callNativeModules(JSExecutor& executor, const std::string& callJSON, bool isEndOfBatch);
+
+  /**
+   * Returns the ExecutorToken corresponding to the main JSExecutor.
+   */
+  ExecutorToken getMainExecutorToken() const;
+
+  /**
+   * Registers the given JSExecutor which runs on the given MessageQueueThread
+   * with the Bridge. Part of this registration is transfering ownership of this
+   * JSExecutor to the Bridge for the duration of the registration.
+   *
+   * Returns a ExecutorToken which can be used to refer to this JSExecutor
+   * in the Bridge.
+   */
+  ExecutorToken registerExecutor(
+      std::unique_ptr<JSExecutor> executor,
+      std::shared_ptr<MessageQueueThread> executorMessageQueueThread);
+
+  /**
+   * Unregisters a JSExecutor that was previously registered with this Bridge
+   * using registerExecutor. Use the ExecutorToken returned from this
+   * registerExecutor call. This method will return ownership of the unregistered
+   * executor to the caller for it to retain or tear down.
+   *
+   * Returns ownership of the unregistered executor.
+   */
+  std::unique_ptr<JSExecutor> unregisterExecutor(ExecutorToken executorToken);
 
   /**
    * Synchronously tears down the bridge and the main executor.
@@ -85,11 +133,19 @@ class Bridge {
   // on the same thread. In that case, the callback will try to run the task on m_callback which
   // will have been destroyed within ~Bridge(), thus causing a SIGSEGV.
   std::shared_ptr<bool> m_destroyed;
-  std::unique_ptr<JSExecutor> m_mainExecutor;
-  std::shared_ptr<MessageQueueThread> m_mainJSMessageQueueThread;
+  JSExecutor* m_mainExecutor;
+  std::unique_ptr<ExecutorToken> m_mainExecutorToken;
+  std::unique_ptr<ExecutorTokenFactory> m_executorTokenFactory;
+  std::unordered_map<JSExecutor*, ExecutorToken> m_executorTokenMap;
+  std::unordered_map<ExecutorToken, std::unique_ptr<ExecutorRegistration>> m_executorMap;
+  std::mutex m_registrationMutex;
   #ifdef WITH_FBSYSTRACE
   std::atomic_uint_least32_t m_systraceCookie = ATOMIC_VAR_INIT();
   #endif
+
+  MessageQueueThread* getMessageQueueThread(const ExecutorToken& executorToken);
+  JSExecutor* getExecutor(const ExecutorToken& executorToken);
+  inline ExecutorToken getTokenForExecutor(JSExecutor& executor);
 };
 
 } }
diff --git a/ReactAndroid/src/main/jni/react/ExecutorToken.h b/ReactAndroid/src/main/jni/react/ExecutorToken.h
new file mode 100644
index 000000000000..a630e90d34a1
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/ExecutorToken.h
@@ -0,0 +1,54 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+#include "Executor.h"
+
+namespace facebook {
+namespace react {
+
+/**
+ * This class exists so that we have a type for the shared_ptr on ExecutorToken
+ * that implements a virtual destructor.
+ */
+class PlatformExecutorToken {
+public:
+  virtual ~PlatformExecutorToken() {}
+};
+
+/**
+ * Class corresponding to a JS VM that can call into native modules. This is
+ * passed to native modules to allow their JS module calls/callbacks to be
+ * routed back to the proper JS VM on the proper thread.
+ */
+class ExecutorToken {
+public:
+  /**
+   * This should only be used by the implementation of the platform ExecutorToken.
+   * Do not use as a client of ExecutorToken.
+   */
+  explicit ExecutorToken(std::shared_ptr<PlatformExecutorToken> platformToken) :
+      platformToken_(platformToken) {}
+
+  std::shared_ptr<PlatformExecutorToken> getPlatformExecutorToken() const {
+    return platformToken_;
+  }
+
+  bool operator==(const ExecutorToken& other) const {
+    return platformToken_.get() == other.platformToken_.get();
+  }
+
+private:
+  std::shared_ptr<PlatformExecutorToken> platformToken_;
+};
+
+} }
+
+namespace std {
+  template<>
+  struct hash<facebook::react::ExecutorToken> {
+    const size_t operator()(const facebook::react::ExecutorToken& token) const {
+      return (size_t) token.getPlatformExecutorToken().get();
+    }
+  };
+}
diff --git a/ReactAndroid/src/main/jni/react/ExecutorTokenFactory.h b/ReactAndroid/src/main/jni/react/ExecutorTokenFactory.h
new file mode 100644
index 000000000000..5d2d42179073
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/ExecutorTokenFactory.h
@@ -0,0 +1,25 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+#include "ExecutorToken.h"
+#include "Executor.h"
+
+namespace facebook {
+namespace react {
+
+/**
+ * Class that knows how to create the platform-specific implementation
+ * of ExecutorToken.
+ */
+class ExecutorTokenFactory {
+public:
+  virtual ~ExecutorTokenFactory() {}
+
+  /**
+   * Creates a new ExecutorToken.
+   */
+  virtual ExecutorToken createExecutorToken() const = 0;
+};
+
+} }
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index 01ccc8188928..04856494a2ca 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -225,7 +225,7 @@ void JSCExecutor::flush() {
   }
   // TODO: Make this a first class function instead of evaling. #9317773
   std::string calls = executeJSCallWithJSC(m_context, "flushedQueue", std::vector<folly::dynamic>());
-  m_bridge->callNativeModules(calls, true);
+  m_bridge->callNativeModules(*this, calls, true);
 }
 
 void JSCExecutor::callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) {
@@ -236,7 +236,7 @@ void JSCExecutor::callFunction(const double moduleId, const double methodId, con
     std::move(arguments),
   };
   std::string calls = executeJSCallWithJSC(m_context, "callFunctionReturnFlushedQueue", std::move(call));
-  m_bridge->callNativeModules(calls, true);
+  m_bridge->callNativeModules(*this, calls, true);
 }
 
 void JSCExecutor::invokeCallback(const double callbackId, const folly::dynamic& arguments) {
@@ -246,7 +246,7 @@ void JSCExecutor::invokeCallback(const double callbackId, const folly::dynamic&
     std::move(arguments)
   };
   std::string calls = executeJSCallWithJSC(m_context, "invokeCallbackAndReturnFlushedQueue", std::move(call));
-  m_bridge->callNativeModules(calls, true);
+  m_bridge->callNativeModules(*this, calls, true);
 }
 
 void JSCExecutor::setGlobalVariable(const std::string& propName, const std::string& jsonValue) {
@@ -304,7 +304,7 @@ void JSCExecutor::handleMemoryPressureCritical() {
 }
 
 void JSCExecutor::flushQueueImmediate(std::string queueJSON) {
-  m_bridge->callNativeModules(queueJSON, false);
+  m_bridge->callNativeModules(*this, queueJSON, false);
 }
 
 void JSCExecutor::loadModule(uint32_t moduleId) {
@@ -332,13 +332,22 @@ int JSCExecutor::addWebWorker(
   Object workerObj = Value(m_context, workerRef).asObject();
   workerObj.makeProtected();
 
-  m_ownedWorkers.emplace(std::piecewise_construct, std::forward_as_tuple(workerId), std::forward_as_tuple(std::move(worker), std::move(workerObj)));
+  JSCExecutor *workerPtr = worker.get();
+  std::shared_ptr<MessageQueueThread> sharedMessageQueueThread = worker->m_messageQueueThread;
+  ExecutorToken token = m_bridge->registerExecutor(
+      std::move(worker),
+      std::move(sharedMessageQueueThread));
+
+  m_ownedWorkers.emplace(
+      std::piecewise_construct,
+      std::forward_as_tuple(workerId),
+      std::forward_as_tuple(workerPtr, token, std::move(workerObj)));
 
   return workerId;
 }
 
 void JSCExecutor::postMessageToOwnedWebWorker(int workerId, JSValueRef message, JSValueRef *exn) {
-  auto worker = m_ownedWorkers.at(workerId).getExecutor();
+  auto worker = m_ownedWorkers.at(workerId).executor;
   std::string msgString = Value(m_context, message).toJSONString();
 
   std::shared_ptr<bool> isWorkerDestroyed = worker->m_isDestroyed;
@@ -390,10 +399,14 @@ void JSCExecutor::receiveMessageFromOwner(const std::string& msgString) {
 }
 
 void JSCExecutor::terminateOwnedWebWorker(int workerId) {
-  auto worker = m_ownedWorkers.at(workerId).getExecutor();
-  std::shared_ptr<MessageQueueThread> workerMQT = worker->m_messageQueueThread;
-  worker->destroy();
+  auto& workerRegistration = m_ownedWorkers.at(workerId);
+  std::shared_ptr<MessageQueueThread> workerMQT = workerRegistration.executor->m_messageQueueThread;
+  ExecutorToken workerExecutorToken = workerRegistration.executorToken;
   m_ownedWorkers.erase(workerId);
+
+  std::unique_ptr<JSExecutor> worker = m_bridge->unregisterExecutor(workerExecutorToken);
+  worker->destroy();
+  worker.reset();
   workerMQT->quitSynchronous();
 }
 
diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.h b/ReactAndroid/src/main/jni/react/JSCExecutor.h
index a10907ccff0d..7f41170c8c44 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.h
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.h
@@ -8,6 +8,7 @@
 #include <folly/json.h>
 #include <JavaScriptCore/JSContextRef.h>
 
+#include "ExecutorToken.h"
 #include "Executor.h"
 #include "JSCHelpers.h"
 #include "Value.h"
@@ -31,17 +32,14 @@ class JSCExecutorFactory : public JSExecutorFactory {
 class JSCExecutor;
 class WorkerRegistration : public noncopyable {
 public:
-  explicit WorkerRegistration(std::unique_ptr<JSCExecutor> executor, Object jsObj) :
-      jsObj(std::move(jsObj)),
-      executor(std::move(executor)) {}
-
-  JSCExecutor* getExecutor() {
-    return executor.get();
-  }
+  explicit WorkerRegistration(JSCExecutor* executor, ExecutorToken executorToken, Object jsObj) :
+      executor(executor),
+      executorToken(executorToken),
+      jsObj(std::move(jsObj)) {}
 
+  JSCExecutor *executor;
+  ExecutorToken executorToken;
   Object jsObj;
-private:
-  std::unique_ptr<JSCExecutor> executor;
 };
 
 class JSCExecutor : public JSExecutor {
diff --git a/ReactAndroid/src/main/jni/react/jni/Android.mk b/ReactAndroid/src/main/jni/react/jni/Android.mk
index 9d4d9b2b5fff..7d46f9ef8baf 100644
--- a/ReactAndroid/src/main/jni/react/jni/Android.mk
+++ b/ReactAndroid/src/main/jni/react/jni/Android.mk
@@ -5,6 +5,7 @@ include $(CLEAR_VARS)
 LOCAL_MODULE := reactnativejni
 
 LOCAL_SRC_FILES := \
+	JExecutorToken.cpp \
   JMessageQueueThread.cpp \
   JSCPerfLogging.cpp \
   JSLoader.cpp \
diff --git a/ReactAndroid/src/main/jni/react/jni/BUCK b/ReactAndroid/src/main/jni/react/jni/BUCK
index 4d23d95ad3a0..34c030641a8f 100644
--- a/ReactAndroid/src/main/jni/react/jni/BUCK
+++ b/ReactAndroid/src/main/jni/react/jni/BUCK
@@ -35,6 +35,7 @@ jni_library(
   header_namespace = 'react/jni',
   supported_platforms_regex = SUPPORTED_PLATFORMS,
   srcs = [
+    'JExecutorToken.cpp',
     'JMessageQueueThread.cpp',
     'JSCPerfLogging.cpp',
     'JSLoader.cpp',
@@ -46,12 +47,14 @@ jni_library(
   ],
   headers = [
     'JSLoader.h',
-    'ProxyExecutor.h',
+    'JExecutorToken.h',
+    'JExecutorTokenFactory.h',
     'JMessageQueueThread.h',
     'JNativeRunnable.h',
     'JniJSModulesUnbundle.h',
     'JSCPerfLogging.h',
     'JSLogging.h',
+    'ProxyExecutor.h',
     'WebWorkers.h',
   ],
   exported_headers = [
diff --git a/ReactAndroid/src/main/jni/react/jni/JExecutorToken.cpp b/ReactAndroid/src/main/jni/react/jni/JExecutorToken.cpp
new file mode 100644
index 000000000000..97e80948b196
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/jni/JExecutorToken.cpp
@@ -0,0 +1,20 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#include "JExecutorToken.h"
+
+using namespace facebook::jni;
+
+namespace facebook {
+namespace react {
+
+ExecutorToken JExecutorToken::getExecutorToken(alias_ref<JExecutorToken::javaobject> jobj) {
+  std::lock_guard<std::mutex> guard(createTokenGuard_);
+  auto sharedOwner = owner_.lock();
+  if (!sharedOwner) {
+    sharedOwner = std::shared_ptr<PlatformExecutorToken>(new JExecutorTokenHolder(jobj));
+    owner_ = sharedOwner;
+  }
+  return ExecutorToken(sharedOwner);
+}
+
+} }
diff --git a/ReactAndroid/src/main/jni/react/jni/JExecutorToken.h b/ReactAndroid/src/main/jni/react/jni/JExecutorToken.h
new file mode 100644
index 000000000000..ac348f0ecd73
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/jni/JExecutorToken.h
@@ -0,0 +1,59 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+#include <mutex>
+
+#include <jni/fbjni.h>
+
+#include <react/ExecutorToken.h>
+
+using namespace facebook::jni;
+
+namespace facebook {
+namespace react {
+
+class JExecutorTokenHolder;
+class JExecutorToken : public HybridClass<JExecutorToken> {
+public:
+  static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/ExecutorToken;";
+
+  ExecutorToken getExecutorToken(alias_ref<JExecutorToken::javaobject> jobj);
+
+private:
+  friend HybridBase;
+  friend JExecutorTokenHolder;
+
+  JExecutorToken() {}
+
+  std::weak_ptr<PlatformExecutorToken> owner_;
+  std::mutex createTokenGuard_;
+};
+
+/**
+ * Wrapper class to hold references to both the c++ and Java parts of the
+ * ExecutorToken object. The goal is to allow a reference to a token from either
+ * c++ or Java to keep both the Java object and c++ hybrid part alive. For c++
+ * references, we accomplish this by having JExecutorTokenHolder keep a reference
+ * to the Java object (which has a reference to the JExecutorToken hybrid part).
+ * For Java references, we allow the JExecutorTokenHolder to be deallocated if there
+ * are no references to it in c++ from a PlatformExecutorToken, but will dynamically
+ * create a new one in JExecutorToken.getExecutorToken if needed.
+ */
+class JExecutorTokenHolder : public PlatformExecutorToken, public noncopyable {
+public:
+  explicit JExecutorTokenHolder(alias_ref<JExecutorToken::javaobject> jobj) :
+    jobj_(make_global(jobj)),
+    impl_(cthis(jobj)) {
+  }
+
+  JExecutorToken::javaobject getJobj() {
+    return jobj_.get();
+  }
+
+private:
+  global_ref<JExecutorToken::javaobject> jobj_;
+  JExecutorToken *impl_;
+};
+
+} }
diff --git a/ReactAndroid/src/main/jni/react/jni/JExecutorTokenFactory.h b/ReactAndroid/src/main/jni/react/jni/JExecutorTokenFactory.h
new file mode 100644
index 000000000000..d7d923111395
--- /dev/null
+++ b/ReactAndroid/src/main/jni/react/jni/JExecutorTokenFactory.h
@@ -0,0 +1,24 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+#include <jni/fbjni.h>
+#include <react/ExecutorTokenFactory.h>
+
+#include "JExecutorToken.h"
+
+using namespace facebook::jni;
+
+namespace facebook {
+namespace react {
+
+class JExecutorTokenFactory : public ExecutorTokenFactory {
+public:
+  virtual ExecutorToken createExecutorToken() const override {
+    auto jExecutorToken = JExecutorToken::newObjectCxxArgs();
+    auto jExecutorTokenNativePart = cthis(jExecutorToken);
+    return jExecutorTokenNativePart->getExecutorToken(jExecutorToken);
+  }
+};
+
+} }
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index d684b5823c05..bb70f2f280ec 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -16,6 +16,8 @@
 #include <react/JSCExecutor.h>
 #include <react/JSModulesUnbundle.h>
 #include <react/Platform.h>
+#include "JExecutorToken.h"
+#include "JExecutorTokenFactory.h"
 #include "JNativeRunnable.h"
 #include "JSLoader.h"
 #include "ReadableNativeArray.h"
@@ -580,7 +582,7 @@ static void logMarker(const std::string& marker) {
   env->DeleteLocalRef(jmarker);
 }
 
-static void makeJavaCall(JNIEnv* env, jobject callback, MethodCall&& call) {
+static void makeJavaCall(JNIEnv* env, ExecutorToken executorToken, jobject callback, MethodCall&& call) {
   if (call.arguments.isNull()) {
     return;
   }
@@ -592,14 +594,21 @@ static void makeJavaCall(JNIEnv* env, jobject callback, MethodCall&& call) {
   #endif
 
   auto newArray = ReadableNativeArray::newObjectCxxArgs(std::move(call.arguments));
-  env->CallVoidMethod(callback, gCallbackMethod, call.moduleId, call.methodId, newArray.get());
+  env->CallVoidMethod(
+      callback,
+      gCallbackMethod,
+      static_cast<JExecutorTokenHolder*>(executorToken.getPlatformExecutorToken().get())->getJobj(),
+      call.moduleId,
+      call.methodId,
+      newArray.get());
 }
 
 static void signalBatchComplete(JNIEnv* env, jobject callback) {
   env->CallVoidMethod(callback, gOnBatchCompleteMethod);
 }
 
-static void dispatchCallbacksToJava(const RefPtr<WeakReference>& weakCallback,
+static void dispatchCallbacksToJava(ExecutorToken executorToken,
+                                    const RefPtr<WeakReference>& weakCallback,
                                     const RefPtr<WeakReference>& weakCallbackQueueThread,
                                     std::vector<MethodCall>&& calls,
                                     bool isEndOfBatch) {
@@ -615,7 +624,7 @@ static void dispatchCallbacksToJava(const RefPtr<WeakReference>& weakCallback,
     return;
   }
 
-  auto runnableFunction = std::bind([weakCallback, isEndOfBatch] (std::vector<MethodCall>& calls) {
+  auto runnableFunction = std::bind([executorToken, weakCallback, isEndOfBatch] (std::vector<MethodCall>& calls) {
     auto env = Environment::current();
     if (env->ExceptionCheck()) {
       FBLOGW("Dropped calls because of pending exception");
@@ -624,7 +633,7 @@ static void dispatchCallbacksToJava(const RefPtr<WeakReference>& weakCallback,
     ResolvedWeakReference callback(weakCallback);
     if (callback) {
       for (auto&& call : calls) {
-        makeJavaCall(env, callback, std::move(call));
+        makeJavaCall(env, executorToken, callback, std::move(call));
         if (env->ExceptionCheck()) {
           return;
         }
@@ -643,11 +652,12 @@ static void create(JNIEnv* env, jobject obj, jobject executor, jobject callback,
                    jobject callbackQueueThread) {
   auto weakCallback = createNew<WeakReference>(callback);
   auto weakCallbackQueueThread = createNew<WeakReference>(callbackQueueThread);
-  auto bridgeCallback = [weakCallback, weakCallbackQueueThread] (std::vector<MethodCall> calls, bool isEndOfBatch) {
-    dispatchCallbacksToJava(weakCallback, weakCallbackQueueThread, std::move(calls), isEndOfBatch);
+  auto bridgeCallback = [weakCallback, weakCallbackQueueThread] (ExecutorToken executorToken, std::vector<MethodCall> calls, bool isEndOfBatch) {
+    dispatchCallbacksToJava(executorToken, weakCallback, weakCallbackQueueThread, std::move(calls), isEndOfBatch);
   };
   auto nativeExecutorFactory = extractRefPtr<CountableJSExecutorFactory>(env, executor);
-  auto bridge = createNew<CountableBridge>(nativeExecutorFactory.get(), bridgeCallback);
+  auto executorTokenFactory = folly::make_unique<JExecutorTokenFactory>();
+  auto bridge = createNew<CountableBridge>(nativeExecutorFactory.get(), std::move(executorTokenFactory), bridgeCallback);
   setCountableForJava(env, obj, std::move(bridge));
 }
 
@@ -735,12 +745,13 @@ static void loadScriptFromFile(JNIEnv* env, jobject obj, jstring fileName, jstri
   env->CallStaticVoidMethod(markerClass, gLogMarkerMethod, env->NewStringUTF("loadScriptFromFile_exec"));
 }
 
-static void callFunction(JNIEnv* env, jobject obj, jint moduleId, jint methodId,
+static void callFunction(JNIEnv* env, jobject obj, JExecutorToken::jhybridobject jExecutorToken, jint moduleId, jint methodId,
                          NativeArray::jhybridobject args, jstring tracingName) {
   auto bridge = extractRefPtr<CountableBridge>(env, obj);
   auto arguments = cthis(wrap_alias(args));
   try {
     bridge->callFunction(
+      cthis(wrap_alias(jExecutorToken))->getExecutorToken(wrap_alias(jExecutorToken)),
       (double) moduleId,
       (double) methodId,
       std::move(arguments->array),
@@ -751,12 +762,13 @@ static void callFunction(JNIEnv* env, jobject obj, jint moduleId, jint methodId,
   }
 }
 
-static void invokeCallback(JNIEnv* env, jobject obj, jint callbackId,
+static void invokeCallback(JNIEnv* env, jobject obj, JExecutorToken::jhybridobject jExecutorToken, jint callbackId,
                            NativeArray::jhybridobject args) {
   auto bridge = extractRefPtr<CountableBridge>(env, obj);
   auto arguments = cthis(wrap_alias(args));
   try {
     bridge->invokeCallback(
+      cthis(wrap_alias(jExecutorToken))->getExecutorToken(wrap_alias(jExecutorToken)),
       (double) callbackId,
       std::move(arguments->array)
     );
@@ -775,6 +787,12 @@ static jlong getJavaScriptContext(JNIEnv *env, jobject obj) {
   return (uintptr_t) bridge->getJavaScriptContext();
 }
 
+static jobject getMainExecutorToken(JNIEnv* env, jobject obj) {
+  auto bridge = extractRefPtr<CountableBridge>(env, obj);
+  auto token = bridge->getMainExecutorToken();
+  return static_cast<JExecutorTokenHolder*>(token.getPlatformExecutorToken().get())->getJobj();
+}
+
 static jboolean supportsProfiling(JNIEnv* env, jobject obj) {
   auto bridge = extractRefPtr<CountableBridge>(env, obj);
   return bridge->supportsProfiling() ? JNI_TRUE : JNI_FALSE;
@@ -948,7 +966,7 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
     });
 
     jclass callbackClass = env->FindClass("com/facebook/react/bridge/ReactCallback");
-    bridge::gCallbackMethod = env->GetMethodID(callbackClass, "call", "(IILcom/facebook/react/bridge/ReadableNativeArray;)V");
+    bridge::gCallbackMethod = env->GetMethodID(callbackClass, "call", "(Lcom/facebook/react/bridge/ExecutorToken;IILcom/facebook/react/bridge/ReadableNativeArray;)V");
     bridge::gOnBatchCompleteMethod = env->GetMethodID(callbackClass, "onBatchComplete", "()V");
 
     jclass markerClass = env->FindClass("com/facebook/react/bridge/ReactMarker");
@@ -964,6 +982,7 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
         makeNativeMethod("callFunction", bridge::callFunction),
         makeNativeMethod("invokeCallback", bridge::invokeCallback),
         makeNativeMethod("setGlobalVariable", bridge::setGlobalVariable),
+        makeNativeMethod("getMainExecutorToken", "()Lcom/facebook/react/bridge/ExecutorToken;", bridge::getMainExecutorToken),
         makeNativeMethod("supportsProfiling", bridge::supportsProfiling),
         makeNativeMethod("startProfiler", bridge::startProfiler),
         makeNativeMethod("stopProfiler", bridge::stopProfiler),
diff --git a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
index c249f0ad3148..07743bed896a 100644
--- a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp
@@ -65,7 +65,7 @@ void ProxyExecutor::callFunction(const double moduleId, const double methodId, c
     std::move(arguments),
   };
   std::string result = executeJSCallWithProxy(m_executor.get(), "callFunctionReturnFlushedQueue", std::move(call));
-  m_bridge->callNativeModules(result, true);
+  m_bridge->callNativeModules(*this, result, true);
 }
 
 void ProxyExecutor::invokeCallback(const double callbackId, const folly::dynamic& arguments) {
@@ -74,7 +74,7 @@ void ProxyExecutor::invokeCallback(const double callbackId, const folly::dynamic
     std::move(arguments)
   };
   std::string result = executeJSCallWithProxy(m_executor.get(), "invokeCallbackAndReturnFlushedQueue", std::move(call));
-  m_bridge->callNativeModules(result, true);
+  m_bridge->callNativeModules(*this, result, true);
 }
 
 void ProxyExecutor::setGlobalVariable(const std::string& propName, const std::string& jsonValue) {
diff --git a/ReactAndroid/src/test/java/com/facebook/react/bridge/BaseJavaModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/bridge/BaseJavaModuleTest.java
index 8a681ccb51bf..dec87ebe3c6f 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/bridge/BaseJavaModuleTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/bridge/BaseJavaModuleTest.java
@@ -52,21 +52,21 @@ public void setup() {
   public void testCallMethodWithoutEnoughArgs() throws Exception {
     BaseJavaModule.NativeMethod regularMethod = mMethods.get("regularMethod");
     Mockito.stub(mArguments.size()).toReturn(1);
-    regularMethod.invoke(null, mArguments);
+    regularMethod.invoke(null, null, mArguments);
   }
 
   @Test(expected = NativeArgumentsParseException.class)
   public void testCallAsyncMethodWithoutEnoughArgs() throws Exception {
     BaseJavaModule.NativeMethod asyncMethod = mMethods.get("asyncMethod");
     Mockito.stub(mArguments.size()).toReturn(2);
-    asyncMethod.invoke(null, mArguments);
+    asyncMethod.invoke(null, null, mArguments);
   }
 
   @Test()
   public void testCallAsyncMethodWithEnoughArgs() throws Exception {
     BaseJavaModule.NativeMethod asyncMethod = mMethods.get("asyncMethod");
     Mockito.stub(mArguments.size()).toReturn(3);
-    asyncMethod.invoke(null, mArguments);
+    asyncMethod.invoke(null, null, mArguments);
   }
 
   private static class MethodsModule extends BaseJavaModule {

From c60ebf266043deca1e22cb7d4df61dcb3f301760 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Tue, 1 Mar 2016 09:33:59 -0800
Subject: [PATCH 1361/1411] Update release schedule and steps

Reviewed By: mkonicek

Differential Revision:D2991042
Ninja: oss docs

fb-gh-sync-id: 7c95f7717deea645871d761fd540a72431428fbe
shipit-source-id: 7c95f7717deea645871d761fd540a72431428fbe
---
 Releases.md | 115 +++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 91 insertions(+), 24 deletions(-)

diff --git a/Releases.md b/Releases.md
index b41c73c82d08..649b5f177e60 100644
--- a/Releases.md
+++ b/Releases.md
@@ -1,16 +1,16 @@
 The list of releases with notes can be found at:
 https://github.com/facebook/react-native/releases
 
-Future releases:
+Release schedule:
 
-- **0.20 branch cut**, 0.20.0-rc - **week of Feb 1**
-- 0.20.0 - Feb 15
 - **0.21 branch cut**, 0.21.0-rc - **week of Feb 15**
 - 0.21.0 - Feb 29
 - **0.22 branch cut**, 0.22.0-rc - **week of Feb 29**
-- 0.22.0 - Mar 7
-- **0.23 branch cut**, 0.23.0-rc - **week of Mar 7**
-- 0.23.0 - Mar 21
+- 0.22.0 - Mar 14
+- **0.23 branch cut**, 0.23.0-rc - **week of Mar 14**
+- 0.23.0 - Mar 28
+- **0.24 branch cut**, 0.23.0-rc - **week of Mar 28**
+- 0.24.0 - Apr 11
 - ...
 
 ## One time setup
@@ -24,7 +24,7 @@ To cut a release branch and check that everything works, you'll need Mac OS with
 Run:
 
     cd react-native
-    ./scripts/release.sh 0.19   # Replace 0.19 with the version you're cutting the branch for :)
+    ./scripts/release.sh version_you_are_releasing # e.g. ./scripts/release.sh 0.22
 
 #### Check that everything works
 
@@ -32,32 +32,99 @@ Make absolutely sure a basic iOS and Android workflow works on the release branc
   
 #### Push to github
 
-  - Check git history, the last commit should be "[0.19-rc] Bump version numbers" (with the correct version)
-  - `git push origin 0.version_you_are_releasing-stable`
+  - Check git history, the last commit should be "[0.22-rc] Bump version numbers" (with the correct version)
+  - `git push origin 0.version_you_are_releasing-stable  # e.g. git push origin 0.22-stable`
 
-#### Update https://facebook.github.io/react-native
+## Make sure we have release notes
+
+Post that we're ready to release so a voluteer can write release notes:
+https://github.com/facebook/react-native/releases
+
+To go through all the commits that went into a release, one way is to use the GitHub compare view: https://github.com/facebook/react-native/compare/0.18-stable...0.19-stable
+
+## Do an RC release (e.g. 0.22.0-rc)
+
+IMPORTANT: `npm publish` will automatically set the latest tag. **When doing an RC release**, run `npm publish --tag next` - this way people need to opt in to get the RC release.
+
+## IMPORTANT: Track bug reports from the community during the following two weeks and make sure they get fixed
+
+A good way to do this is to create a github issue and post about it so people can report bugs. Examples: https://github.com/facebook/react-native/issues/6087, https://github.com/facebook/react-native/issues/5201
 
-Move `latest` tag when doing a release and pushing to `0.x-stable` branch, CI will build and deploy the
-latest docs to the website.
+We should only be tracking bugs with small and non-risky fixes. Don't pick new features into the release as this greatly increases the risk of something breaking. The main point of the RC is to let people to use it for two weeks and fix the most serious bugs.
+
+-------------------
+
+## Do a release (e.g. 0.22.0, 0.22.1)
+
+Roughly two weeks after the branch cut (see the release schedule above) it's time to promote the RC to a real realease.
+
+Make sure you know which bug fixes should definitely be cheery-picked, example: https://github.com/facebook/react-native/issues/6087
+
+We should only cherry-pick small and non-risky bug fixes. Don't pick new features into the release as this greatly increases the risk of something breaking. The main point of the RC is to let people to use it for two weeks and fix the most serious bugs.
+
+Do the following:
+
+**NOTE: Most of these steps are similar to what the script `release.sh` does. The script is used to cut the release branch only, can be made more generic to help with this step too.**
 
 ```
-git tag -d latest
-git push origin :latest
-git tag latest
-git push origin version_you_are_releasing-stable --tags
+cd react-native
+git checkout master
+git pull
+git checkout 0.version_you_are_releasing-stable   # e.g. git checkout 0.22-stable
+git pull origin 0.version_you_are_releasing-stable  # e.g. git pull origin 0.22-stable
+# Cherry-pick those commits, test everything again using Sinopia
+git cherry-pick commitHash1
+# Create the 'android' folder to be published to npm.
+./gradlew :ReactAndroid:installArchives
+# Check that it's there: `ls android`
+...
+npm set registry http://localhost:4873
+sinopia
+# change versions in package.json and React.podspec
+npm publish
+cd /tmp
+react-native init TestAapp
+cd TestApp
+react-native run-ios
+# Check that you can Reload JS and the Chrome debugger works
+# Kill packager
+open ios/TestApp.xcodeproj
+# Click run
+# Check that you can Reload JS and the Chrome debugger works
+cd android && ./gradlew dependencies
+# Double check the react-native dep has the correct version
+cd ..
+react-native run-android
+# Check that you can Reload JS and the Chrome debugger works
 ```
 
-## Make sure we have release notes
+If everything worked:
 
-Post that we're ready to release so voluteers can write release notes:
-https://github.com/facebook/react-native/releases
+```
+npm set registry https://registry.npmjs.org
+npm publish
+```
 
-To go through all the commits that went into a release, one way is to use the github compare view: https://github.com/facebook/react-native/compare/0.18-stable...0.19-stable
+Tag the release in Git:
 
-## Do a release
+```
+git tag v-version_you_are_releasing  # e.g. git tag v0.22.0, git tag v0.22.1
+git push --tags
+```
+
+To update the [website](https://facebook.github.io/react-native), move the `latest` tag and push to the `0.x-stable` branch. CircleCI will build and deploy the latest docs to the website.
+
+```
+git tag -d latest
+git push origin :latest
+git tag latest
+git push origin version_you_are_releasing-stable --tags  # e.g git push origin 0.22-stable --tags
+```
 
-IMPORTANT:  `npm publish` will automatically set the latest tag. **When doing an RC release**, run `npm publish --tag next` - this way people need to opt in to get the RC release.
+Once you see the version in the top left corner of the website has been updated:
+Move the release notes to the tag you've just created. We want single release notes per version, for example if there is v0.22.0-rc and later we release v0.22.0, the release notes should live on v0.22.0:
+https://github.com/facebook/react-native/tags
 
-## Track bug reports from the community during the following two weeks and make sure they get fixed
+Uncheck the box "This is a pre-release" and publish the notes.
 
-A good way to do this is to create a github issue and post about it so people can report bugs: https://github.com/facebook/react-native/issues/5201
+Tweet about it! :) ([example tweet](https://twitter.com/grabbou/status/701510554758856704))

From cbc0e21926594cbe650db34c466b934fda5c13ef Mon Sep 17 00:00:00 2001
From: Sreejumon <spurayil@imprivata.com>
Date: Tue, 1 Mar 2016 09:35:14 -0800
Subject: [PATCH 1362/1411] Support for XHR responseType and response
 attributes

Summary:Currently the XMLHttpRequest don't support any response types other than text. This PR will add responseType attribute as well response attribute.

This PR will partially solve the issue https://github.com/facebook/react-native/issues/6017
Closes https://github.com/facebook/react-native/pull/6156

Differential Revision: D2994267

Pulled By: nicklockwood

fb-gh-sync-id: 24642c48655930c8350112bac38e6ed4a42bd40d
shipit-source-id: 24642c48655930c8350112bac38e6ed4a42bd40d
---
 Libraries/Network/XMLHttpRequestBase.js | 33 +++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/Libraries/Network/XMLHttpRequestBase.js b/Libraries/Network/XMLHttpRequestBase.js
index 14e284ae596a..96d2ec1d24af 100644
--- a/Libraries/Network/XMLHttpRequestBase.js
+++ b/Libraries/Network/XMLHttpRequestBase.js
@@ -43,6 +43,8 @@ class XMLHttpRequestBase {
   readyState: number;
   responseHeaders: ?Object;
   responseText: ?string;
+  response: string | ArrayBuffer | null;
+  responseType: '' | 'arraybuffer' | 'text';
   status: number;
   timeout: number;
   responseURL: ?string;
@@ -83,6 +85,8 @@ class XMLHttpRequestBase {
     this.readyState = this.UNSENT;
     this.responseHeaders = undefined;
     this.responseText = '';
+    this.response = null;
+    this.responseType = '';
     this.status = 0;
     delete this.responseURL;
 
@@ -139,6 +143,15 @@ class XMLHttpRequestBase {
     }
   }
 
+  _stringToArrayBuffer(str: string): ArrayBuffer {
+    var buffer = new ArrayBuffer(str.length);
+    var bufferView = new Uint8Array(buffer);
+    for (var i = 0, l = str.length; i < l; i++) {
+      bufferView[i] = str.charCodeAt(i);
+    }
+    return buffer;
+  }
+
   _didReceiveData(requestId: number, responseText: string): void {
     if (requestId === this._requestId) {
       if (!this.responseText) {
@@ -146,6 +159,17 @@ class XMLHttpRequestBase {
       } else {
         this.responseText += responseText;
       }
+      switch(this.responseType) {
+      case '':
+      case 'text':
+        this.response = this.responseText;
+        break;
+      case 'arraybuffer': // NOTE: not supported by fetch
+        this.response = this._stringToArrayBuffer(this.responseText);
+        break;
+      default: //TODO: Support the other response type as well (eg:- document, json, blob)
+        this.response = null;
+      }
       this.setReadyState(this.LOADING);
     }
   }
@@ -214,6 +238,12 @@ class XMLHttpRequestBase {
     throw new Error('Subclass must define sendImpl method');
   }
 
+  _uintToString(uintArray: Int8Array): string {
+    // $FlowFixMe - Function.apply accepts Int8Array, but Flow thinks it doesn't
+    var encodedString = String.fromCharCode.apply(null, uintArray);
+    return decodeURIComponent(encodedString);
+  }
+
   send(data: any): void {
     if (this.readyState !== this.OPENED) {
       throw new Error('Request has not been opened');
@@ -222,6 +252,9 @@ class XMLHttpRequestBase {
       throw new Error('Request has already been sent');
     }
     this._sent = true;
+    if (data instanceof Int8Array) {
+      data = this._uintToString(data);
+    }
     this.sendImpl(this._method, this._url, this._headers, data, this.timeout);
   }
 

From 0db22f184df5b1ca04f2dc2a2aa7f3362d3823c1 Mon Sep 17 00:00:00 2001
From: Hedger Wang <hedger@fb.com>
Date: Tue, 1 Mar 2016 09:43:35 -0800
Subject: [PATCH 1363/1411] NavigationCardStack - Add card stack item.

Summary: Add card stack item that moves from the right or the bottom.

Reviewed By: ericvicenti

Differential Revision: D2975659

fb-gh-sync-id: a04724943375ba0a9931eafb2aa82d6d8c31acfe
shipit-source-id: a04724943375ba0a9931eafb2aa82d6d8c31acfe
---
 .../NavigationCardStackExample.js             |  29 ++-
 .../NavigationCardStack.js                    |  50 +++-
 .../NavigationCardStackItem.js                | 242 ++++++++++++++++++
 .../NavigationAnimatedView.js                 |   7 +-
 4 files changed, 309 insertions(+), 19 deletions(-)
 create mode 100644 Libraries/CustomComponents/NavigationExperimental/NavigationCardStackItem.js

diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationCardStackExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationCardStackExample.js
index 94a6735d05ca..ae08ac75d252 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationCardStackExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationCardStackExample.js
@@ -33,35 +33,36 @@ class NavigationCardStackExample extends React.Component {
     this._renderScene = this._renderScene.bind(this);
     this._push = this._push.bind(this);
     this._pop = this._pop.bind(this);
+    this._toggleDirection = this._toggleDirection.bind(this);
   }
 
   render() {
     return (
       <NavigationCardStack
-        style={styles.main}
-        renderScene={this._renderScene}
+        direction={this.state.isHorizontal ? 'horizontal' : 'vertical'}
         navigationState={this.state.navigationState}
+        renderScene={this._renderScene}
+        style={styles.main}
       />
     );
   }
 
   _getInitialState() {
-    const route = {key: 'First Route'};
     const navigationState = {
       index: 0,
-      children: [route],
+      children: [{key: 'First Route'}],
     };
     return {
+      isHorizontal: true,
       navigationState,
     };
   }
 
   _push() {
     const state = this.state.navigationState;
-    const nextRoute = {key: 'Route ' + (state.index + 1)};
     const nextState = NavigationStateUtils.push(
       state,
-      nextRoute,
+      {key: 'Route ' + (state.index + 1)},
     );
     this.setState({
       navigationState: nextState,
@@ -83,7 +84,15 @@ class NavigationCardStackExample extends React.Component {
     return (
       <ScrollView style={styles.scrollView}>
         <NavigationExampleRow
-          text={JSON.stringify(props.navigationState)}
+          text={
+            this.state.isHorizontal ?
+            'direction = "horizontal"' :
+            'direction = "vertical"'
+          }
+          onPress={this._toggleDirection}
+        />
+        <NavigationExampleRow
+          text={'route = ' + props.navigationState.key}
         />
         <NavigationExampleRow
           text="Push Route"
@@ -100,6 +109,12 @@ class NavigationCardStackExample extends React.Component {
       </ScrollView>
     );
   }
+
+  _toggleDirection() {
+    this.setState({
+      isHorizontal: !this.state.isHorizontal,
+    });
+  }
 }
 
 const styles = StyleSheet.create({
diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationCardStack.js b/Libraries/CustomComponents/NavigationExperimental/NavigationCardStack.js
index b4e53a63a470..dbb81eff8d99 100644
--- a/Libraries/CustomComponents/NavigationExperimental/NavigationCardStack.js
+++ b/Libraries/CustomComponents/NavigationExperimental/NavigationCardStack.js
@@ -27,19 +27,21 @@
  */
 'use strict';
 
+const Animated = require('Animated');
 const NavigationAnimatedView = require('NavigationAnimatedView');
-const NavigationCard = require('NavigationCard');
+const NavigationCardStackItem = require('NavigationCardStackItem');
 const NavigationContainer = require('NavigationContainer');
 const React = require('React');
+const ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
 const StyleSheet = require('StyleSheet');
 
 const emptyFunction = require('emptyFunction');
 
 const {PropTypes} = React;
+const {Directions} = NavigationCardStackItem;
 
 import type {
   NavigationParentState,
-  NavigationState,
 } from 'NavigationStateUtils';
 
 import type {
@@ -47,9 +49,11 @@ import type {
   NavigationStateRenderer,
   NavigationStateRendererProps,
   Position,
+  TimingSetter,
 } from 'NavigationAnimatedView';
 
 type Props = {
+  direction: string,
   navigationState: NavigationParentState,
   renderOverlay: NavigationStateRenderer,
   renderScene: NavigationStateRenderer,
@@ -60,19 +64,30 @@ type Props = {
  */
 class NavigationCardStack extends React.Component {
   _renderScene : NavigationStateRenderer;
+  _setTiming: TimingSetter;
 
   constructor(props: Props, context: any) {
     super(props, context);
     this._renderScene = this._renderScene.bind(this);
+    this._setTiming = this._setTiming.bind(this);
+  }
+
+  shouldComponentUpdate(nextProps: Object, nextState: Object): boolean {
+    return ReactComponentWithPureRenderMixin.shouldComponentUpdate.call(
+      this,
+      nextProps,
+      nextState
+    );
   }
 
   render(): ReactElement {
     return (
       <NavigationAnimatedView
         navigationState={this.props.navigationState}
-        style={[styles.animatedView, this.props.style]}
         renderOverlay={this.props.renderOverlay}
         renderScene={this._renderScene}
+        setTiming={this._setTiming}
+        style={[styles.animatedView, this.props.style]}
       />
     );
   }
@@ -81,33 +96,48 @@ class NavigationCardStack extends React.Component {
     const {
       index,
       layout,
-      navigationParentState,
       navigationState,
       position,
     } = props;
+
     return (
-      <NavigationCard
-        key={navigationState.key}
+      <NavigationCardStackItem
+        direction={this.props.direction}
         index={index}
-        navigationState={navigationParentState}
+        key={navigationState.key}
+        layout={layout}
+        navigationState={navigationState}
         position={position}
-        layout={layout}>
-        {this.props.renderScene(props)}
-      </NavigationCard>
+        renderScene={this.props.renderScene}
+      />
     );
   }
+
+  _setTiming(position: Position, navigationState: NavigationParentState): void {
+    Animated.timing(
+      position,
+      {
+        duration: 500,
+        toValue: navigationState.index,
+      }
+    ).start();
+  }
 }
 
 NavigationCardStack.propTypes = {
+  direction: PropTypes.oneOf([Directions.HORIZONTAL, Directions.VERTICAL]),
   navigationState: PropTypes.object.isRequired,
   renderOverlay: PropTypes.func,
   renderScene: PropTypes.func.isRequired,
 };
 
 NavigationCardStack.defaultProps = {
+  direction: Directions.HORIZONTAL,
   renderOverlay: emptyFunction.thatReturnsNull,
 };
 
+NavigationCardStack.Directions = Directions;
+
 const styles = StyleSheet.create({
   animatedView: {
     flex: 1,
diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationCardStackItem.js b/Libraries/CustomComponents/NavigationExperimental/NavigationCardStackItem.js
new file mode 100644
index 000000000000..ff9d5f26824c
--- /dev/null
+++ b/Libraries/CustomComponents/NavigationExperimental/NavigationCardStackItem.js
@@ -0,0 +1,242 @@
+/**
+ * Copyright (c) 2015, Facebook, Inc.  All rights reserved.
+ *
+ * Facebook, Inc. ("Facebook") owns all right, title and interest, including
+ * all intellectual property and other proprietary rights, in and to the React
+ * Native CustomComponents software (the "Software").  Subject to your
+ * compliance with these terms, you are hereby granted a non-exclusive,
+ * worldwide, royalty-free copyright license to (1) use and copy the Software;
+ * and (2) reproduce and distribute the Software as part of your own software
+ * ("Your Software").  Facebook reserves all rights not expressly granted to
+ * you in this license agreement.
+ *
+ * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "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 FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
+ * EMPLOYEES 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 THE SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @providesModule NavigationCardStackItem
+ * @flow
+ */
+'use strict';
+
+const Animated = require('Animated');
+const NavigationContainer = require('NavigationContainer');
+const React = require('React');
+const StyleSheet = require('StyleSheet');
+const View = require('View');
+const ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
+
+const {PropTypes} = React;
+
+import type {
+  NavigationParentState,
+} from 'NavigationStateUtils';
+
+
+import type {
+  Layout,
+  Position,
+  NavigationStateRenderer,
+} from 'NavigationAnimatedView';
+
+type AnimatedValue = Animated.Value;
+
+type Props = {
+  direction: string,
+  index: number;
+  layout: Layout;
+  navigationState: NavigationParentState;
+  position: Position;
+  renderScene: NavigationStateRenderer;
+};
+
+type State = {
+  hash: string,
+  height: number,
+  width: number,
+};
+
+class AmimatedValueSubscription {
+  _value: AnimatedValue;
+  _token: string;
+
+  constructor(value: AnimatedValue, callback: Function) {
+    this._value = value;
+    this._token = value.addListener(callback);
+  }
+
+  remove() {
+    this._value.removeListener(this._token);
+  }
+}
+
+/**
+ * Component that renders the scene as card for the <NavigationCardStack />.
+ */
+class NavigationCardStackItem extends React.Component {
+  props: Props;
+  state: State;
+  _calculateState: (t: Layout) => State;
+  _layoutListeners: Array<AmimatedValueSubscription>;
+
+  constructor(props: Props, context: any) {
+    super(props, context);
+
+    this._calculateState = this._calculateState.bind(this);
+    this.state = this._calculateState(props.layout);
+    this._layoutListeners = [];
+  }
+
+  shouldComponentUpdate(nextProps: Object, nextState: Object): boolean {
+    return ReactComponentWithPureRenderMixin.shouldComponentUpdate.call(
+      this,
+      nextProps,
+      nextState
+    );
+  }
+
+  componentDidMount(): void {
+    this._applyLayout(this.props.layout);
+  }
+
+  componentWillUnmount(): void {
+    this._layoutListeners.forEach(subscription => subscription.remove);
+  }
+
+  componentWillReceiveProps(nextProps: Props): void {
+    this._applyLayout(nextProps.layout);
+  }
+
+  render(): ReactElement {
+    const {
+      direction,
+      index,
+      navigationState,
+      position,
+      layout,
+    } = this.props;
+    const {
+      height,
+      width,
+    } = this.state;
+
+    const isVertical = direction === 'vertical';
+    const inputRange = [index - 1, index, index + 1];
+    const animatedStyle = {
+
+      opacity: position.interpolate({
+        inputRange,
+        outputRange: [1, 1, 0.3],
+      }),
+
+      transform: [
+        {
+          scale: position.interpolate({
+            inputRange,
+            outputRange: [1, 1, 0.95],
+          }),
+        },
+        {
+          translateX: isVertical ? 0 :
+            position.interpolate({
+              inputRange,
+              outputRange: [width, 0, -10],
+            }),
+        },
+        {
+          translateY: !isVertical ? 0 :
+            position.interpolate({
+              inputRange,
+              outputRange: [height, 0, -10],
+            }),
+        },
+      ],
+    };
+
+    return (
+      <Animated.View
+        style={[styles.main, animatedStyle]}>
+        {this.props.renderScene(this.props)}
+      </Animated.View>
+    );
+  }
+
+  _calculateState(layout: Layout): State {
+    const width = layout.width.__getValue();
+    const height = layout.height.__getValue();
+    const hash = 'layout-' + width + '-' + height;
+    const state = {
+      height,
+      width,
+      hash,
+    };
+    return state;
+  }
+
+  _applyLayout(layout: Layout) {
+    this._layoutListeners.forEach(subscription => subscription.remove);
+
+    this._layoutListeners.length = 0;
+
+    const callback = this._applyLayout.bind(this, layout);
+
+    this._layoutListeners.push(
+      new AmimatedValueSubscription(layout.width, callback),
+      new AmimatedValueSubscription(layout.height, callback),
+    );
+
+    const nextState = this._calculateState(layout);
+    if (nextState.hash !== this.state.hash) {
+      this.setState(nextState);
+    }
+  }
+}
+
+const Directions = {
+  HORIZONTAL: 'horizontal',
+  VERTICAL: 'vertical',
+};
+
+NavigationCardStackItem.propTypes = {
+  direction: PropTypes.oneOf([Directions.HORIZONTAL, Directions.VERTICAL]),
+  index: PropTypes.number.isRequired,
+  layout: PropTypes.object.isRequired,
+  navigationState: PropTypes.object.isRequired,
+  position: PropTypes.object.isRequired,
+  renderScene: PropTypes.func.isRequired,
+};
+
+NavigationCardStackItem.defaultProps = {
+  direction: Directions.HORIZONTAL,
+};
+
+NavigationCardStackItem = NavigationContainer.create(NavigationCardStackItem);
+
+NavigationCardStackItem.Directions = Directions;
+
+const styles = StyleSheet.create({
+  main: {
+    backgroundColor: '#E9E9EF',
+    bottom: 0,
+    left: 0,
+    position: 'absolute',
+    right: 0,
+    shadowColor: 'black',
+    shadowOffset: {width: 0, height: 0},
+    shadowOpacity: 0.4,
+    shadowRadius: 10,
+    top: 0,
+  },
+});
+
+
+
+module.exports = NavigationCardStackItem;
diff --git a/Libraries/NavigationExperimental/NavigationAnimatedView.js b/Libraries/NavigationExperimental/NavigationAnimatedView.js
index b19502166eda..bf3024ce870c 100644
--- a/Libraries/NavigationExperimental/NavigationAnimatedView.js
+++ b/Libraries/NavigationExperimental/NavigationAnimatedView.js
@@ -115,8 +115,11 @@ class NavigationAnimatedView extends React.Component {
   props: Props;
   constructor(props) {
     super(props);
-    this._animatedHeight = new Animated.Value(0);
-    this._animatedWidth = new Animated.Value(0);
+    this._lastWidth = 0;
+    this._lastHeight = 0;
+    this._animatedHeight = new Animated.Value(this._lastHeight);
+    this._animatedWidth = new Animated.Value(this._lastWidth);
+
     this.state = {
       position: new Animated.Value(this.props.navigationState.index),
       scenes: new Map(),

From 35da174339968689b5db2f1a135da7c86a35fa39 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Tue, 1 Mar 2016 09:44:05 -0800
Subject: [PATCH 1364/1411] Added unit tests for module init

Summary: The module initialization process is complex and full of race conditions. This diff adds a set of unit tests that verify that modules setup happens in the correct order, and enforces all the various conditions for main/background init.

Reviewed By: javache

Differential Revision: D2994145

fb-gh-sync-id: 92ea84508cdeeb280ff0fb9e9b2dffa8dbc37e66
shipit-source-id: 92ea84508cdeeb280ff0fb9e9b2dffa8dbc37e66
---
 .../UIExplorer.xcodeproj/project.pbxproj      |  10 +-
 .../UIExplorerUnitTests/RCTBridgeTests.m      |  12 +-
 .../RCTModuleInitNotificationRaceTests.m      | 142 ++++++++++
 .../UIExplorerUnitTests/RCTModuleInitTests.m  | 254 ++++++++++++++++++
 React/Base/RCTBatchedBridge.m                 |   2 +-
 React/Base/RCTBridge+Private.h                |   5 +
 React/Base/RCTBridge.m                        |  40 +--
 React/Base/RCTLog.m                           |   7 +-
 React/Base/RCTModuleData.m                    |   5 +
 React/Modules/RCTDevMenu.m                    |   2 +-
 10 files changed, 451 insertions(+), 28 deletions(-)
 create mode 100644 Examples/UIExplorer/UIExplorerUnitTests/RCTModuleInitNotificationRaceTests.m
 create mode 100644 Examples/UIExplorer/UIExplorerUnitTests/RCTModuleInitTests.m

diff --git a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
index b2608f0fc465..95f9215cee98 100644
--- a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
+++ b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
@@ -8,6 +8,7 @@
 
 /* Begin PBXBuildFile section */
 		1300627F1B59179B0043FE5A /* RCTGzipTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1300627E1B59179B0043FE5A /* RCTGzipTests.m */; };
+		13129DD41C85F87C007D611C /* RCTModuleInitNotificationRaceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 13129DD31C85F87C007D611C /* RCTModuleInitNotificationRaceTests.m */; };
 		1323F1891C04AB9F0091BED0 /* bunny.png in Resources */ = {isa = PBXBuildFile; fileRef = 1323F1851C04AB9F0091BED0 /* bunny.png */; };
 		1323F18A1C04AB9F0091BED0 /* flux@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1323F1861C04AB9F0091BED0 /* flux@3x.png */; };
 		1323F18B1C04AB9F0091BED0 /* hawk.png in Resources */ = {isa = PBXBuildFile; fileRef = 1323F1871C04AB9F0091BED0 /* hawk.png */; };
@@ -18,6 +19,7 @@
 		1341802C1AA9178B003F314A /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1341802B1AA91779003F314A /* libRCTNetwork.a */; };
 		134454601AAFCABD003F0779 /* libRCTAdSupport.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1344545A1AAFCAAE003F0779 /* libRCTAdSupport.a */; };
 		134A8A2A1AACED7A00945AAE /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 134A8A251AACED6A00945AAE /* libRCTGeolocation.a */; };
+		134CB92A1C85A38800265FA6 /* RCTModuleInitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 134CB9291C85A38800265FA6 /* RCTModuleInitTests.m */; };
 		138D6A181B53CD440074A87E /* RCTShadowViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 138D6A161B53CD440074A87E /* RCTShadowViewTests.m */; };
 		138DEE241B9EDFB6007F4EA5 /* libRCTCameraRoll.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 138DEE091B9EDDDB007F4EA5 /* libRCTCameraRoll.a */; };
 		1393D0381B68CD1300E1B601 /* RCTModuleMethodTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1393D0371B68CD1300E1B601 /* RCTModuleMethodTests.m */; };
@@ -178,6 +180,7 @@
 /* Begin PBXFileReference section */
 		004D289E1AAF61C70097A701 /* UIExplorerUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UIExplorerUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 		1300627E1B59179B0043FE5A /* RCTGzipTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTGzipTests.m; sourceTree = "<group>"; };
+		13129DD31C85F87C007D611C /* RCTModuleInitNotificationRaceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTModuleInitNotificationRaceTests.m; sourceTree = "<group>"; };
 		1323F1851C04AB9F0091BED0 /* bunny.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = bunny.png; sourceTree = "<group>"; };
 		1323F1861C04AB9F0091BED0 /* flux@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "flux@3x.png"; sourceTree = "<group>"; };
 		1323F1871C04AB9F0091BED0 /* hawk.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = hawk.png; sourceTree = "<group>"; };
@@ -188,6 +191,7 @@
 		134180261AA91779003F314A /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../../Libraries/Network/RCTNetwork.xcodeproj; sourceTree = "<group>"; };
 		134454551AAFCAAE003F0779 /* RCTAdSupport.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAdSupport.xcodeproj; path = ../../Libraries/AdSupport/RCTAdSupport.xcodeproj; sourceTree = "<group>"; };
 		134A8A201AACED6A00945AAE /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = ../../Libraries/Geolocation/RCTGeolocation.xcodeproj; sourceTree = "<group>"; };
+		134CB9291C85A38800265FA6 /* RCTModuleInitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTModuleInitTests.m; sourceTree = "<group>"; };
 		138D6A161B53CD440074A87E /* RCTShadowViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTShadowViewTests.m; sourceTree = "<group>"; };
 		138DEE021B9EDDDB007F4EA5 /* RCTCameraRoll.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTCameraRoll.xcodeproj; path = ../../Libraries/CameraRoll/RCTCameraRoll.xcodeproj; sourceTree = "<group>"; };
 		1393D0371B68CD1300E1B601 /* RCTModuleMethodTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTModuleMethodTests.m; sourceTree = "<group>"; };
@@ -422,6 +426,8 @@
 				144D21231B2204C5006DB32B /* RCTImageUtilTests.m */,
 				13DB03471B5D2ED500C27245 /* RCTJSONTests.m */,
 				13DF61B51B67A45000EDB188 /* RCTMethodArgumentTests.m */,
+				134CB9291C85A38800265FA6 /* RCTModuleInitTests.m */,
+				13129DD31C85F87C007D611C /* RCTModuleInitNotificationRaceTests.m */,
 				1393D0371B68CD1300E1B601 /* RCTModuleMethodTests.m */,
 				138D6A161B53CD440074A87E /* RCTShadowViewTests.m */,
 				1497CFAB1B21F5E400C1F8F2 /* RCTUIManagerTests.m */,
@@ -882,7 +888,9 @@
 				1300627F1B59179B0043FE5A /* RCTGzipTests.m in Sources */,
 				1497CFAF1B21F5E400C1F8F2 /* RCTConvert_NSURLTests.m in Sources */,
 				1497CFAE1B21F5E400C1F8F2 /* RCTJSCExecutorTests.m in Sources */,
+				13129DD41C85F87C007D611C /* RCTModuleInitNotificationRaceTests.m in Sources */,
 				1497CFAD1B21F5E400C1F8F2 /* RCTBridgeTests.m in Sources */,
+				134CB92A1C85A38800265FA6 /* RCTModuleInitTests.m in Sources */,
 				1497CFB11B21F5E400C1F8F2 /* RCTEventDispatcherTests.m in Sources */,
 				1497CFB31B21F5E400C1F8F2 /* RCTUIManagerTests.m in Sources */,
 				13DB03481B5D2ED500C27245 /* RCTJSONTests.m in Sources */,
@@ -1276,4 +1284,4 @@
 /* End XCConfigurationList section */
 	};
 	rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
-}
\ No newline at end of file
+}
diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m
index f415f6da6130..08a1a1e37fec 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTBridgeTests.m
@@ -41,6 +41,8 @@ @interface TestExecutor : NSObject <RCTJavaScriptExecutor>
 
 @implementation TestExecutor
 
+@synthesize valid = _valid;
+
 RCT_EXPORT_MODULE()
 
 - (void)setUp {}
@@ -55,7 +57,7 @@ - (instancetype)init
 
 - (BOOL)isValid
 {
-  return YES;
+  return _valid;
 }
 
 - (void)flushedQueue:(RCTJavaScriptCallback)onComplete
@@ -98,7 +100,10 @@ - (void)injectJSONText:(NSString *)script
   onComplete(nil);
 }
 
-- (void)invalidate {}
+- (void)invalidate
+{
+  _valid = NO;
+}
 
 @end
 
@@ -132,7 +137,7 @@ - (void)setUp
   [_bridge invalidate];
   [_bridge setUp];
 
-  _jsExecutor = [_bridge.batchedBridge valueForKey:@"javaScriptExecutor"];
+  _jsExecutor = _bridge.batchedBridge.javaScriptExecutor;
   XCTAssertNotNil(_jsExecutor);
 }
 
@@ -143,6 +148,7 @@ - (void)tearDown
   _testMethodCalled = NO;
 
   [_bridge invalidate];
+  RUN_RUNLOOP_WHILE(_jsExecutor.isValid);
   _bridge = nil;
 }
 
diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleInitNotificationRaceTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleInitNotificationRaceTests.m
new file mode 100644
index 000000000000..39650db2769b
--- /dev/null
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleInitNotificationRaceTests.m
@@ -0,0 +1,142 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ */
+
+#import <Foundation/Foundation.h>
+#import <XCTest/XCTest.h>
+
+#import "RCTBridge.h"
+#import "RCTBridge+Private.h"
+#import "RCTBridgeModule.h"
+#import "RCTUtils.h"
+#import "RCTUIManager.h"
+#import "RCTViewManager.h"
+
+#define RUN_RUNLOOP_WHILE(CONDITION) \
+{ \
+  NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:5]; \
+  while ((CONDITION)) { \
+    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; \
+    if ([timeout timeIntervalSinceNow] <= 0) { \
+      XCTFail(@"Runloop timed out before condition was met"); \
+      break; \
+    } \
+  } \
+}
+
+// Must be declared before RCTTestCustomSetBridgeModule in order to trigger the
+// race condition that we are testing for - namely that the
+// RCTDidInitializeModuleNotification for RCTTestViewManager gets sent before
+// setBridge: is called on RCTTestCustomSetBridgeModule
+@interface RCTTestViewManager : RCTViewManager
+@end
+
+@implementation RCTTestViewManager
+
+@synthesize bridge = _bridge;
+@synthesize methodQueue = _methodQueue;
+
+RCT_EXPORT_MODULE()
+
+- (void)setBridge:(RCTBridge *)bridge
+{
+  _bridge = bridge;
+  (void)[_bridge uiManager]; // Needed to trigger a race condition
+}
+
+- (NSArray<NSString *> *)customDirectEventTypes
+{
+  return @[@"foo"];
+}
+
+@end
+
+
+@interface RCTNotificationObserverModule : NSObject <RCTBridgeModule>
+
+@property (nonatomic, assign) BOOL didDetectViewManagerInit;
+
+@end
+
+@implementation RCTNotificationObserverModule
+
+@synthesize bridge = _bridge;
+
+RCT_EXPORT_MODULE()
+
+- (void)setBridge:(RCTBridge *)bridge
+{
+  _bridge = bridge;
+  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didInitViewManager:) name:RCTDidInitializeModuleNotification object:nil];
+}
+
+- (void)didInitViewManager:(NSNotification *)note
+{
+  id<RCTBridgeModule> module = note.userInfo[@"module"];
+  if ([module isKindOfClass:[RCTTestViewManager class]]) {
+    _didDetectViewManagerInit = YES;
+  }
+}
+
+- (void)dealloc
+{
+  [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+@end
+
+
+@interface RCTModuleInitNotificationRaceTests : XCTestCase <RCTBridgeDelegate>
+{
+  RCTBridge *_bridge;
+  RCTNotificationObserverModule *_notificationObserver;
+}
+@end
+
+@implementation RCTModuleInitNotificationRaceTests
+
+- (NSURL *)sourceURLForBridge:(__unused RCTBridge *)bridge
+{
+  return nil;
+}
+
+- (NSArray *)extraModulesForBridge:(__unused RCTBridge *)bridge
+{
+  return @[_notificationObserver];
+}
+
+- (void)setUp
+{
+  [super setUp];
+
+  _notificationObserver = [RCTNotificationObserverModule new];
+  _bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:nil];
+}
+
+- (void)tearDown
+{
+  [super tearDown];
+
+  _notificationObserver = nil;
+  id<RCTJavaScriptExecutor> jsExecutor = _bridge.batchedBridge.javaScriptExecutor;
+  [_bridge invalidate];
+  RUN_RUNLOOP_WHILE(jsExecutor.isValid);
+  _bridge = nil;
+}
+
+- (void)testViewManagerNotInitializedBeforeSetBridgeModule
+{
+  RUN_RUNLOOP_WHILE(!_notificationObserver.didDetectViewManagerInit);
+}
+
+@end
diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleInitTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleInitTests.m
new file mode 100644
index 000000000000..a0289b2e40ee
--- /dev/null
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleInitTests.m
@@ -0,0 +1,254 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ */
+
+#import <Foundation/Foundation.h>
+#import <XCTest/XCTest.h>
+
+#import "RCTBridge.h"
+#import "RCTBridge+Private.h"
+#import "RCTBridgeModule.h"
+#import "RCTUtils.h"
+
+#define RUN_RUNLOOP_WHILE(CONDITION) \
+{ \
+  NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:5]; \
+  while ((CONDITION)) { \
+    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; \
+    if ([timeout timeIntervalSinceNow] <= 0) { \
+      XCTFail(@"Runloop timed out before condition was met"); \
+      break; \
+    } \
+  } \
+}
+
+
+@interface RCTTestInjectedModule : NSObject <RCTBridgeModule>
+@end
+
+@implementation RCTTestInjectedModule
+
+@synthesize bridge = _bridge;
+@synthesize methodQueue = _methodQueue;
+
+RCT_EXPORT_MODULE()
+
+@end
+
+
+@interface RCTTestCustomInitModule : NSObject <RCTBridgeModule>
+
+@property (nonatomic, assign) BOOL initializedOnMainThread;
+
+@end
+
+@implementation RCTTestCustomInitModule
+
+@synthesize bridge = _bridge;
+@synthesize methodQueue = _methodQueue;
+
+RCT_EXPORT_MODULE()
+
+- (id)init
+{
+  if ((self = [super init])) {
+    _initializedOnMainThread = [NSThread isMainThread];
+  }
+  return self;
+}
+
+@end
+
+
+@interface RCTTestCustomSetBridgeModule : NSObject <RCTBridgeModule>
+
+@property (nonatomic, assign) BOOL setBridgeOnMainThread;
+
+@end
+
+@implementation RCTTestCustomSetBridgeModule
+
+@synthesize bridge = _bridge;
+@synthesize methodQueue = _methodQueue;
+
+RCT_EXPORT_MODULE()
+
+- (void)setBridge:(RCTBridge *)bridge
+{
+  _bridge = bridge;
+  _setBridgeOnMainThread = [NSThread isMainThread];
+}
+
+@end
+
+
+@interface RCTTestExportConstantsModule : NSObject <RCTBridgeModule>
+
+@property (nonatomic, assign) BOOL exportedConstants;
+@property (nonatomic, assign) BOOL exportedConstantsOnMainThread;
+
+@end
+
+@implementation RCTTestExportConstantsModule
+
+@synthesize bridge = _bridge;
+@synthesize methodQueue = _methodQueue;
+
+RCT_EXPORT_MODULE()
+
+- (NSDictionary<NSString *, id> *)constantsToExport
+{
+  _exportedConstants = YES;
+  _exportedConstantsOnMainThread = [NSThread isMainThread];
+  return @{ @"foo": @"bar" };
+}
+
+@end
+
+
+@interface RCTLazyInitModule : NSObject <RCTBridgeModule>
+@end
+
+@implementation RCTLazyInitModule
+
+@synthesize bridge = _bridge;
+@synthesize methodQueue = _methodQueue;
+
+RCT_EXPORT_MODULE()
+
+@end
+
+
+@interface RCTModuleInitTests : XCTestCase <RCTBridgeDelegate>
+{
+  RCTBridge *_bridge;
+  BOOL _injectedModuleInitNotificationSent;
+  BOOL _customInitModuleNotificationSent;
+  BOOL _customSetBridgeModuleNotificationSent;
+  BOOL _exportConstantsModuleNotificationSent;
+  BOOL _lazyInitModuleNotificationSent;
+  BOOL _lazyInitModuleNotificationSentOnMainThread;
+  BOOL _viewManagerModuleNotificationSent;
+  RCTTestInjectedModule *_injectedModule;
+}
+@end
+
+@implementation RCTModuleInitTests
+
+- (NSURL *)sourceURLForBridge:(__unused RCTBridge *)bridge
+{
+  return nil;
+}
+
+- (NSArray *)extraModulesForBridge:(__unused RCTBridge *)bridge
+{
+  return @[_injectedModule];
+}
+
+- (void)setUp
+{
+  [super setUp];
+
+  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(moduleDidInit:) name:RCTDidInitializeModuleNotification object:nil];
+
+  _injectedModuleInitNotificationSent = NO;
+  _customInitModuleNotificationSent = NO;
+  _customSetBridgeModuleNotificationSent = NO;
+  _exportConstantsModuleNotificationSent = NO;
+  _lazyInitModuleNotificationSent = NO;
+  _viewManagerModuleNotificationSent = NO;
+  _injectedModule = [RCTTestInjectedModule new];
+  _bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:nil];
+}
+
+- (void)tearDown
+{
+  [super tearDown];
+
+  [[NSNotificationCenter defaultCenter] removeObserver:self name:RCTDidInitializeModuleNotification object:nil];
+
+  id<RCTJavaScriptExecutor> jsExecutor = _bridge.batchedBridge.javaScriptExecutor;
+  [_bridge invalidate];
+  RUN_RUNLOOP_WHILE(jsExecutor.isValid);
+  _bridge = nil;
+}
+
+- (void)moduleDidInit:(NSNotification *)note
+{
+  id<RCTBridgeModule> module = note.userInfo[@"module"];
+  if ([module isKindOfClass:[RCTTestInjectedModule class]]) {
+    _injectedModuleInitNotificationSent = YES;
+  } else if ([module isKindOfClass:[RCTTestCustomInitModule class]]) {
+    _customInitModuleNotificationSent = YES;
+  } else if ([module isKindOfClass:[RCTTestCustomSetBridgeModule class]]) {
+    _customSetBridgeModuleNotificationSent = YES;
+  } else if ([module isKindOfClass:[RCTTestExportConstantsModule class]]) {
+    _exportConstantsModuleNotificationSent = YES;
+  } else if ([module isKindOfClass:[RCTLazyInitModule class]]) {
+    _lazyInitModuleNotificationSent = YES;
+    _lazyInitModuleNotificationSentOnMainThread = [NSThread isMainThread];
+  }
+}
+
+- (void)testInjectedModulesInitializedDuringBridgeInit
+{
+  XCTAssertTrue(_injectedModuleInitNotificationSent);
+  XCTAssertEqual(_injectedModule, [_bridge moduleForClass:[RCTTestInjectedModule class]]);
+  XCTAssertEqual(_injectedModule.bridge, _bridge.batchedBridge);
+  XCTAssertNotNil(_injectedModule.methodQueue);
+}
+
+- (void)testCustomInitModuleInitializedAtBridgeStartup
+{
+  RUN_RUNLOOP_WHILE(!_customInitModuleNotificationSent);
+  XCTAssertTrue(_customInitModuleNotificationSent);
+  RCTTestCustomInitModule *module = [_bridge moduleForClass:[RCTTestCustomInitModule class]];
+  XCTAssertTrue(module.initializedOnMainThread);
+}
+
+- (void)testCustomSetBridgeModuleInitializedAtBridgeStartup
+{
+  RUN_RUNLOOP_WHILE(!_customSetBridgeModuleNotificationSent);
+  XCTAssertTrue(_customSetBridgeModuleNotificationSent);
+  RCTTestCustomSetBridgeModule *module = [_bridge moduleForClass:[RCTTestCustomSetBridgeModule class]];
+  XCTAssertTrue(module.setBridgeOnMainThread);
+}
+
+- (void)testExportConstantsModuleInitializedAtBridgeStartup
+{
+  RUN_RUNLOOP_WHILE(!_exportConstantsModuleNotificationSent);
+  XCTAssertTrue(_exportConstantsModuleNotificationSent);
+  RCTTestExportConstantsModule *module = [_bridge moduleForClass:[RCTTestExportConstantsModule class]];
+  RUN_RUNLOOP_WHILE(!module.exportedConstants);
+  XCTAssertTrue(module.exportedConstants);
+  XCTAssertTrue(module.exportedConstantsOnMainThread);
+}
+
+- (void)testLazyInitModuleNotInitializedDuringBridgeInit
+{
+  XCTAssertFalse(_lazyInitModuleNotificationSent);
+
+  __block RCTLazyInitModule *module;
+  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+    module = [_bridge moduleForClass:[RCTLazyInitModule class]];
+  });
+
+  RUN_RUNLOOP_WHILE(!module);
+  XCTAssertTrue(_lazyInitModuleNotificationSent);
+  XCTAssertFalse(_lazyInitModuleNotificationSentOnMainThread);
+  XCTAssertNotNil(module);
+  XCTAssertEqual(module.bridge, _bridge.batchedBridge);
+  XCTAssertNotNil(module.methodQueue);
+}
+
+@end
diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index b574d62bed8b..3dd44ec9eae0 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -44,6 +44,7 @@ typedef NS_ENUM(NSUInteger, RCTBridgeFields) {
 @interface RCTBatchedBridge : RCTBridge
 
 @property (nonatomic, weak) RCTBridge *parentBridge;
+@property (nonatomic, weak) id<RCTJavaScriptExecutor> javaScriptExecutor;
 
 @end
 
@@ -52,7 +53,6 @@ @implementation RCTBatchedBridge
   BOOL _loading;
   BOOL _valid;
   BOOL _wasBatchActive;
-  __weak id<RCTJavaScriptExecutor> _javaScriptExecutor;
   NSMutableArray<dispatch_block_t> *_pendingCalls;
   NSMutableDictionary<NSString *, RCTModuleData *> *_moduleDataByName;
   NSArray<RCTModuleData *> *_moduleDataByID;
diff --git a/React/Base/RCTBridge+Private.h b/React/Base/RCTBridge+Private.h
index eedda8cd8b77..c954561efddb 100644
--- a/React/Base/RCTBridge+Private.h
+++ b/React/Base/RCTBridge+Private.h
@@ -54,6 +54,11 @@
 
 @interface RCTBridge (RCTBatchedBridge)
 
+/**
+ * Used for unit testing, to detect when executor has been invalidated.
+ */
+@property (nonatomic, weak, readonly) id<RCTJavaScriptExecutor> javaScriptExecutor;
+
 /**
  * Used by RCTModuleData to register the module for frame updates after it is
  * lazily initialized.
diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m
index 2c3455d7c6a0..aa939eae66c5 100644
--- a/React/Base/RCTBridge.m
+++ b/React/Base/RCTBridge.m
@@ -68,7 +68,8 @@ void RCTRegisterModule(Class moduleClass)
 NSString *RCTBridgeModuleNameForClass(Class cls)
 {
 #if RCT_DEV
-  RCTAssert([cls conformsToProtocol:@protocol(RCTBridgeModule)], @"Bridge module classes must conform to RCTBridgeModule");
+  RCTAssert([cls conformsToProtocol:@protocol(RCTBridgeModule)],
+            @"Bridge module `%@` does not conform to RCTBridgeModule", cls);
 #endif
 
   NSString *name = [cls moduleName];
@@ -104,34 +105,33 @@ + (void)initialize
     // Set up JS thread
     RCTJSThread = (id)kCFNull;
 
-#if RCT_DEBUG
+    if (RCT_DEBUG && !RCTRunningInTestEnvironment()) {
 
-    // Set up module classes
-    static unsigned int classCount;
-    Class *classes = objc_copyClassList(&classCount);
+      // Set up module classes
+      static unsigned int classCount;
+      Class *classes = objc_copyClassList(&classCount);
 
-    for (unsigned int i = 0; i < classCount; i++)
-    {
-      Class cls = classes[i];
-      Class superclass = cls;
-      while (superclass)
+      for (unsigned int i = 0; i < classCount; i++)
       {
-        if (class_conformsToProtocol(superclass, @protocol(RCTBridgeModule)))
+        Class cls = classes[i];
+        Class superclass = cls;
+        while (superclass)
         {
-          if (![RCTModuleClasses containsObject:cls]) {
-            RCTLogWarn(@"Class %@ was not exported. Did you forget to use "
-                       "RCT_EXPORT_MODULE()?", cls);
+          if (class_conformsToProtocol(superclass, @protocol(RCTBridgeModule)))
+          {
+            if (![RCTModuleClasses containsObject:cls]) {
+              RCTLogWarn(@"Class %@ was not exported. Did you forget to use "
+                         "RCT_EXPORT_MODULE()?", cls);
+            }
+            break;
           }
-          break;
+          superclass = class_getSuperclass(superclass);
         }
-        superclass = class_getSuperclass(superclass);
       }
-    }
-
-    free(classes);
 
-#endif
+      free(classes);
 
+    }
   });
 }
 
diff --git a/React/Base/RCTLog.m b/React/Base/RCTLog.m
index efcc12659b84..459d8a6660d5 100644
--- a/React/Base/RCTLog.m
+++ b/React/Base/RCTLog.m
@@ -16,6 +16,7 @@
 #import "RCTBridge+Private.h"
 #import "RCTDefines.h"
 #import "RCTRedBox.h"
+#import "RCTUtils.h"
 
 static NSString *const RCTLogFunctionStack = @"RCTLogFunctionStack";
 
@@ -226,8 +227,10 @@ void _RCTLogNativeInternal(RCTLogLevel level, const char *fileName, int lineNumb
       });
     }
 
-    // Log to JS executor
-    [[RCTBridge currentBridge] logMessage:message level:level ? @(RCTLogLevels[level]) : @"info"];
+    if (!RCTRunningInTestEnvironment()) {
+      // Log to JS executor
+      [[RCTBridge currentBridge] logMessage:message level:level ? @(RCTLogLevels[level]) : @"info"];
+    }
 
 #endif
 
diff --git a/React/Base/RCTModuleData.m b/React/Base/RCTModuleData.m
index 5175fb16d3b1..93427f52e59e 100644
--- a/React/Base/RCTModuleData.m
+++ b/React/Base/RCTModuleData.m
@@ -238,4 +238,9 @@ - (void)invalidate
   _methodQueue = nil;
 }
 
+- (NSString *)description
+{
+  return [NSString stringWithFormat:@"<%@: %p; name=\"%@\">", [self class], self, self.name];
+}
+
 @end
diff --git a/React/Modules/RCTDevMenu.m b/React/Modules/RCTDevMenu.m
index 5e1132a21df0..d9e39b7023fd 100644
--- a/React/Modules/RCTDevMenu.m
+++ b/React/Modules/RCTDevMenu.m
@@ -369,7 +369,7 @@ - (void)jsLoaded:(NSNotification *)notification
   if (!sourceCodeModule.scriptURL) {
     if (!sourceCodeModule) {
       RCTLogWarn(@"RCTSourceCode module not found");
-    } else {
+    } else if (!RCTRunningInTestEnvironment()) {
       RCTLogWarn(@"RCTSourceCode module scriptURL has not been set");
     }
   } else if (!sourceCodeModule.scriptURL.fileURL) {

From b4dc5e3e81a719faa3f0184d1a375ba04ab082ae Mon Sep 17 00:00:00 2001
From: Marcus Roberts <m.roberts@nittygritty.net>
Date: Tue, 1 Mar 2016 10:01:18 -0800
Subject: [PATCH 1365/1411] Added TeamWarden App to website showcase

Summary:My update is to the app showcase on the react native website, adding my TeamWarden iOS and Android app (in alphabetical order)
Closes https://github.com/facebook/react-native/pull/6163

Differential Revision: D2994724

fb-gh-sync-id: c739f347c704ced139b871d52d84f0b6acc5a17c
shipit-source-id: c739f347c704ced139b871d52d84f0b6acc5a17c
---
 website/src/react-native/showcase.js | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index 37ebe9cfdcd9..a7fb649a50fa 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -548,6 +548,13 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/thai-tone/id1064086189?mt=8',
     author: 'Alexey Ledak',
   },
+  {
+    name: 'TeamWarden',
+    icon: 'http://a1.mzstatic.com/eu/r30/Purple69/v4/09/37/61/0937613a-46e3-3278-5457-5de49a4ee9ab/icon175x175.png',
+    linkAppStore: 'https://itunes.apple.com/gb/app/teamwarden/id1052570507?mt=8',
+    linkPlayStore: 'https://play.google.com/store/apps/details?id=com.teamwarden',
+    author: 'nittygritty.net',
+  },
   {
     name: 'Text Blast',
     icon: 'http://a3.mzstatic.com/us/r30/Purple49/v4/4f/29/58/4f2958a1-7f35-9260-6340-c67ac29d7740/icon175x175.png',

From 6bae7f93f5f3eeb2a50a8aa162b3b2a9af64d97d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Eloy=20Dur=C3=A1n?= <eloy.de.enige@gmail.com>
Date: Tue, 1 Mar 2016 10:13:22 -0800
Subject: [PATCH 1366/1411] =?UTF-8?q?Add=20suggested=20=E2=80=98view=20siz?=
 =?UTF-8?q?e=E2=80=99=20powers=20to=20-[RCTShadowView=20setFrame:]?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Summary:The UICollectionView example is actually my use-case, which is discussed in a
bit more detail [here](https://github.com/alloy/ReactNativeExperiments/issues/2).

----

This is useful when wrapping native iOS components that determine their
own suggested size and which would be too hard/unnecessary to replicate
in the shadow view. For instance a `UICollectionView` that after layout
will update its `contentSize`, which could be used to suggest a size to
the shadow view.

The reason for adding it to -[RCTShadowView setFrame:] is mainly so it
can be used via the existing -[RCTUIManager setFrame:forView:] API and
because it might not be a feature you want to expose too prominently.

An origin of `{ NAN, NAN }` is used as a sentinel to indicate that the
frame should be used as a size suggestion. The size portion of the rect
may contain a `NAN` to skip that dimension or a suggested value for the
dimension which will be used if no explicit styling has been assigned.

Examples:

* Without any expl
Closes https://github.com/facebook/react-native/pull/6114

Differential Revision: D2994796

Pulled By: nicklockwood

fb-gh-sync-id: 6dd3dd86a352ca7d31a0da38bc38a2859ed0a410
shipit-source-id: 6dd3dd86a352ca7d31a0da38bc38a2859ed0a410
---
 .../UIExplorerUnitTests/RCTShadowViewTests.m  | 112 ++++++++++++++----
 React/Modules/RCTUIManager.h                  |   6 +
 React/Modules/RCTUIManager.m                  |  15 +++
 React/Views/RCTShadowView.h                   |   6 +
 React/Views/RCTShadowView.m                   |  23 ++++
 runXcodeTests.sh                              |   9 +-
 6 files changed, 140 insertions(+), 31 deletions(-)

diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTShadowViewTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTShadowViewTests.m
index f2715947a4ea..cfe3959bc756 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTShadowViewTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTShadowViewTests.m
@@ -17,11 +17,23 @@
 #import "RCTShadowView.h"
 
 @interface RCTShadowViewTests : XCTestCase
-
+@property (nonatomic, strong) RCTShadowView *parentView;
 @end
 
 @implementation RCTShadowViewTests
 
+- (void)setUp
+{
+  [super setUp];
+  
+  self.parentView = [self _shadowViewWithStyle:^(css_style_t *style) {
+    style->flex_direction = CSS_FLEX_DIRECTION_COLUMN;
+    style->dimensions[0] = 440;
+    style->dimensions[1] = 440;
+  }];
+  self.parentView.reactTag = @1; // must be valid rootView tag
+}
+
 // Just a basic sanity test to ensure css-layout is applied correctly in the context of our shadow view hierarchy.
 //
 // ====================================
@@ -69,33 +81,87 @@ - (void)testApplyingLayoutRecursivelyToShadowView
     style->flex = 1;
   }];
 
-  RCTShadowView *parentView = [self _shadowViewWithStyle:^(css_style_t *style) {
-    style->flex_direction = CSS_FLEX_DIRECTION_COLUMN;
-    style->padding[0] = 10;
-    style->padding[1] = 10;
-    style->padding[2] = 10;
-    style->padding[3] = 10;
-    style->dimensions[0] = 440;
-    style->dimensions[1] = 440;
-  }];
+  self.parentView.cssNode->style.padding[0] = 10;
+  self.parentView.cssNode->style.padding[1] = 10;
+  self.parentView.cssNode->style.padding[2] = 10;
+  self.parentView.cssNode->style.padding[3] = 10;
+
+  [self.parentView insertReactSubview:headerView atIndex:0];
+  [self.parentView insertReactSubview:mainView atIndex:1];
+  [self.parentView insertReactSubview:footerView atIndex:2];
 
-  [parentView insertReactSubview:headerView atIndex:0];
-  [parentView insertReactSubview:mainView atIndex:1];
-  [parentView insertReactSubview:footerView atIndex:2];
+  [self.parentView collectRootUpdatedFrames];
 
-  parentView.reactTag = @1; // must be valid rootView tag
-  [parentView collectRootUpdatedFrames];
+  XCTAssertTrue(CGRectEqualToRect([self.parentView measureLayoutRelativeToAncestor:self.parentView], CGRectMake(0, 0, 440, 440)));
+  XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets([self.parentView paddingAsInsets], UIEdgeInsetsMake(10, 10, 10, 10)));
 
-  XCTAssertTrue(CGRectEqualToRect([parentView measureLayoutRelativeToAncestor:parentView], CGRectMake(0, 0, 440, 440)));
-  XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets([parentView paddingAsInsets], UIEdgeInsetsMake(10, 10, 10, 10)));
+  XCTAssertTrue(CGRectEqualToRect([headerView measureLayoutRelativeToAncestor:self.parentView], CGRectMake(10, 10, 420, 100)));
+  XCTAssertTrue(CGRectEqualToRect([mainView measureLayoutRelativeToAncestor:self.parentView], CGRectMake(10, 120, 420, 200)));
+  XCTAssertTrue(CGRectEqualToRect([footerView measureLayoutRelativeToAncestor:self.parentView], CGRectMake(10, 330, 420, 100)));
 
-  XCTAssertTrue(CGRectEqualToRect([headerView measureLayoutRelativeToAncestor:parentView], CGRectMake(10, 10, 420, 100)));
-  XCTAssertTrue(CGRectEqualToRect([mainView measureLayoutRelativeToAncestor:parentView], CGRectMake(10, 120, 420, 200)));
-  XCTAssertTrue(CGRectEqualToRect([footerView measureLayoutRelativeToAncestor:parentView], CGRectMake(10, 330, 420, 100)));
+  XCTAssertTrue(CGRectEqualToRect([leftView measureLayoutRelativeToAncestor:self.parentView], CGRectMake(10, 120, 100, 200)));
+  XCTAssertTrue(CGRectEqualToRect([centerView measureLayoutRelativeToAncestor:self.parentView], CGRectMake(120, 120, 200, 200)));
+  XCTAssertTrue(CGRectEqualToRect([rightView measureLayoutRelativeToAncestor:self.parentView], CGRectMake(330, 120, 100, 200)));
+}
 
-  XCTAssertTrue(CGRectEqualToRect([leftView measureLayoutRelativeToAncestor:parentView], CGRectMake(10, 120, 100, 200)));
-  XCTAssertTrue(CGRectEqualToRect([centerView measureLayoutRelativeToAncestor:parentView], CGRectMake(120, 120, 200, 200)));
-  XCTAssertTrue(CGRectEqualToRect([rightView measureLayoutRelativeToAncestor:parentView], CGRectMake(330, 120, 100, 200)));
+- (void)testAssignsSuggestedWidthDimension
+{
+  [self _withShadowViewWithStyle:^(css_style_t *style) {
+                                   style->position[CSS_LEFT] = 0;
+                                   style->position[CSS_TOP] = 0;
+                                   style->dimensions[CSS_HEIGHT] = 10;
+                                 }
+            assertRelativeLayout:CGRectMake(0, 0, 3, 10)
+        withIntrinsicContentSize:CGSizeMake(3, UIViewNoIntrinsicMetric)];
+}
+
+- (void)testAssignsSuggestedHeightDimension
+{
+  [self _withShadowViewWithStyle:^(css_style_t *style) {
+                                   style->position[CSS_LEFT] = 0;
+                                   style->position[CSS_TOP] = 0;
+                                   style->dimensions[CSS_WIDTH] = 10;
+                                 }
+            assertRelativeLayout:CGRectMake(0, 0, 10, 4)
+        withIntrinsicContentSize:CGSizeMake(UIViewNoIntrinsicMetric, 4)];
+}
+
+- (void)testDoesNotOverrideDimensionStyleWithSuggestedDimensions
+{
+  [self _withShadowViewWithStyle:^(css_style_t *style) {
+                                   style->position[CSS_LEFT] = 0;
+                                   style->position[CSS_TOP] = 0;
+                                   style->dimensions[CSS_WIDTH] = 10;
+                                   style->dimensions[CSS_HEIGHT] = 10;
+                                 }
+          assertRelativeLayout:CGRectMake(0, 0, 10, 10)
+      withIntrinsicContentSize:CGSizeMake(3, 4)];
+}
+
+- (void)testDoesNotAssignSuggestedDimensionsWhenStyledWithFlexAttribute
+{
+  float parentWidth = self.parentView.cssNode->style.dimensions[CSS_WIDTH];
+  float parentHeight = self.parentView.cssNode->style.dimensions[CSS_HEIGHT];
+  [self _withShadowViewWithStyle:^(css_style_t *style) {
+                                   style->flex = 1;
+                                 }
+            assertRelativeLayout:CGRectMake(0, 0, parentWidth, parentHeight)
+        withIntrinsicContentSize:CGSizeMake(3, 4)];
+}
+
+- (void)_withShadowViewWithStyle:(void(^)(css_style_t *style))styleBlock
+            assertRelativeLayout:(CGRect)expectedRect
+        withIntrinsicContentSize:(CGSize)contentSize
+{
+  RCTShadowView *view = [self _shadowViewWithStyle:styleBlock];
+  [self.parentView insertReactSubview:view atIndex:0];
+  view.intrinsicContentSize = contentSize;
+  [self.parentView collectRootUpdatedFrames];
+  CGRect actualRect = [view measureLayoutRelativeToAncestor:self.parentView];
+  XCTAssertTrue(CGRectEqualToRect(expectedRect, actualRect),
+                @"Expected layout to be %@, got %@",
+                NSStringFromCGRect(expectedRect),
+                NSStringFromCGRect(actualRect));
 }
 
 - (RCTShadowView *)_shadowViewWithStyle:(void(^)(css_style_t *style))styleBlock
diff --git a/React/Modules/RCTUIManager.h b/React/Modules/RCTUIManager.h
index bdcf2e2c5350..8a14a4a02eee 100644
--- a/React/Modules/RCTUIManager.h
+++ b/React/Modules/RCTUIManager.h
@@ -60,6 +60,12 @@ RCT_EXTERN NSString *const RCTUIManagerRootViewKey;
  */
 - (void)setFrame:(CGRect)frame forView:(UIView *)view;
 
+/**
+ * Set the natural size of a view, which is used when no explicit size is set.
+ * Use UIViewNoIntrinsicMetric to ignore a dimension.
+ */
+- (void)setIntrinsicContentSize:(CGSize)size forView:(UIView *)view;
+
 /**
  * Update the background color of a root view. This is usually triggered by
  * manually setting the background color of the root view with native code.
diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m
index d71939130f32..d0db1c40aa5b 100644
--- a/React/Modules/RCTUIManager.m
+++ b/React/Modules/RCTUIManager.m
@@ -399,6 +399,21 @@ - (void)setFrame:(CGRect)frame forView:(UIView *)view
   });
 }
 
+- (void)setIntrinsicContentSize:(CGSize)size forView:(UIView *)view
+{
+  RCTAssertMainThread();
+
+  NSNumber *reactTag = view.reactTag;
+  dispatch_async(_shadowQueue, ^{
+    RCTShadowView *shadowView = _shadowViewRegistry[reactTag];
+    RCTAssert(shadowView != nil, @"Could not locate root view with tag #%@", reactTag);
+
+    shadowView.intrinsicContentSize = size;
+
+    [self batchDidComplete];
+  });
+}
+
 - (void)setBackgroundColor:(UIColor *)color forRootView:(UIView *)rootView
 {
   RCTAssertMainThread();
diff --git a/React/Views/RCTShadowView.h b/React/Views/RCTShadowView.h
index 40917304d483..e845060f9595 100644
--- a/React/Views/RCTShadowView.h
+++ b/React/Views/RCTShadowView.h
@@ -68,6 +68,12 @@ typedef void (^RCTApplierBlock)(NSDictionary<NSNumber *, UIView *> *viewRegistry
 - (void)setTopLeft:(CGPoint)topLeft;
 - (void)setSize:(CGSize)size;
 
+/**
+ * Set the natural size of the view, which is used when no explicit size is set.
+ * Use UIViewNoIntrinsicMetric to ignore a dimension.
+ */
+- (void)setIntrinsicContentSize:(CGSize)size;
+
 /**
  * Size flexibility type used to find size constraints.
  * Default to RCTRootViewSizeFlexibilityNone
diff --git a/React/Views/RCTShadowView.m b/React/Views/RCTShadowView.m
index 42a2f1b8847f..c755bbade042 100644
--- a/React/Views/RCTShadowView.m
+++ b/React/Views/RCTShadowView.m
@@ -535,6 +535,29 @@ - (void)setFrame:(CGRect)frame
   [self dirtyLayout];
 }
 
+static inline BOOL
+RCTAssignSuggestedDimension(css_node_t *css_node, int dimension, CGFloat amount)
+{
+  if (amount != UIViewNoIntrinsicMetric
+      && isnan(css_node->style.dimensions[dimension])) {
+    css_node->style.dimensions[dimension] = amount;
+    return YES;
+  }
+  return NO;
+}
+
+- (void)setIntrinsicContentSize:(CGSize)size
+{
+  if (_cssNode->style.flex == 0) {
+    BOOL dirty = NO;
+    dirty |= RCTAssignSuggestedDimension(_cssNode, CSS_HEIGHT, size.height);
+    dirty |= RCTAssignSuggestedDimension(_cssNode, CSS_WIDTH, size.width);
+    if (dirty) {
+      [self dirtyLayout];
+    }
+  }
+}
+
 - (void)setTopLeft:(CGPoint)topLeft
 {
   _cssNode->style.position[CSS_LEFT] = topLeft.x;
diff --git a/runXcodeTests.sh b/runXcodeTests.sh
index ab7ce69c1acc..fda82d67f0be 100755
--- a/runXcodeTests.sh
+++ b/runXcodeTests.sh
@@ -10,16 +10,9 @@ if [ -z "$1" ]
     exit 255
 fi
 
-xctool \
-  -project IntegrationTests/IntegrationTests.xcodeproj \
-  -scheme IntegrationTests \
-  -sdk iphonesimulator8.1 \
-  -destination "platform=iOS Simulator,OS=${1},name=iPhone 5" \
-  build test
-
 xctool \
   -project Examples/UIExplorer/UIExplorer.xcodeproj \
   -scheme UIExplorer \
-  -sdk iphonesimulator8.1 \
+  -sdk iphonesimulator${1} \
   -destination "platform=iOS Simulator,OS=${1},name=iPhone 5" \
   build test

From 2957f734b4149b57c33a6787b3eb1239145d9390 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@gmail.com>
Date: Tue, 1 Mar 2016 10:52:26 -0800
Subject: [PATCH 1367/1411] removed bithound badge

Summary:see
Closes https://github.com/facebook/react-native/pull/6232

Differential Revision: D2994958

fb-gh-sync-id: 6dacce080dac48bc645c58ce5b87d96e0ec3ff04
shipit-source-id: 6dacce080dac48bc645c58ce5b87d96e0ec3ff04
---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index d539d122a98b..04dbd5e4b03b 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# React Native [![Build Status](https://travis-ci.org/facebook/react-native.svg?branch=master)](https://travis-ci.org/facebook/react-native) [![Circle CI](https://circleci.com/gh/facebook/react-native.svg?style=svg)](https://circleci.com/gh/facebook/react-native) [![npm version](https://badge.fury.io/js/react-native.svg)](http://badge.fury.io/js/react-native) [![bitHound Dependencies](https://www.bithound.io/github/facebook/react-native/badges/dependencies.svg)](https://www.bithound.io/github/facebook/react-native/master/dependencies/npm)
+# React Native [![Build Status](https://travis-ci.org/facebook/react-native.svg?branch=master)](https://travis-ci.org/facebook/react-native) [![Circle CI](https://circleci.com/gh/facebook/react-native.svg?style=svg)](https://circleci.com/gh/facebook/react-native) [![npm version](https://badge.fury.io/js/react-native.svg)](http://badge.fury.io/js/react-native)
 
 React Native enables you to build world-class application experiences on native platforms using a consistent developer experience based on JavaScript and [React](http://facebook.github.io/react). The focus of React Native is on developer efficiency across all the platforms you care about - learn once, write anywhere. Facebook uses React Native in multiple production apps and will continue investing in React Native.
 

From 85801ef87491e25323d3d8f9cb387f96776f3ff8 Mon Sep 17 00:00:00 2001
From: Spencer Ahrens <sahrens@fb.com>
Date: Tue, 1 Mar 2016 13:42:12 -0800
Subject: [PATCH 1368/1411] Remove invariant hack for jest

Reviewed By: vjeux, cpojer

Differential Revision: D2988899

fb-gh-sync-id: e1b2a32a3f665b8f8a246e73e8dd620ff8506ea7
shipit-source-id: e1b2a32a3f665b8f8a246e73e8dd620ff8506ea7
---
 Libraries/Animated/src/Interpolation.js | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/Libraries/Animated/src/Interpolation.js b/Libraries/Animated/src/Interpolation.js
index b97d063b949a..c8daa2406d2c 100644
--- a/Libraries/Animated/src/Interpolation.js
+++ b/Libraries/Animated/src/Interpolation.js
@@ -12,17 +12,9 @@
 /* eslint no-bitwise: 0 */
 'use strict';
 
+var invariant = require('invariant');
 var normalizeColor = require('normalizeColor');
 
-// TODO(#7644673): fix this hack once github jest actually checks invariants
-var invariant = function(condition, message) {
-  if (!condition) {
-    var error = new Error(message);
-    (error: any).framesToPop = 1; // $FlowIssue
-    throw error;
-  }
-};
-
 type ExtrapolateType = 'extend' | 'identity' | 'clamp';
 
 export type InterpolationConfigType = {

From caac52095260beabd7038ec82a93847cc38b3f04 Mon Sep 17 00:00:00 2001
From: Hedger Wang <hedger@fb.com>
Date: Tue, 1 Mar 2016 18:44:58 -0800
Subject: [PATCH 1369/1411] Add gesture handling for the card stack.

Reviewed By: ericvicenti

Differential Revision: D2995958

fb-gh-sync-id: f66759440b03072b650a572f011cadd06a0180d2
shipit-source-id: f66759440b03072b650a572f011cadd06a0180d2
---
 .../NavigationCardStackExample.js             | 100 ++++++----
 .../NavigationCardStack.js                    |  10 +-
 .../NavigationCardStackItem.js                |  78 ++++++--
 .../NavigationAbstractPanResponder.js         |  47 +++++
 .../NavigationAnimatedView.js                 |  28 ++-
 .../NavigationLinearPanResponder.js           | 183 ++++++++++++++++++
 6 files changed, 372 insertions(+), 74 deletions(-)
 create mode 100644 Libraries/NavigationExperimental/NavigationAbstractPanResponder.js
 create mode 100644 Libraries/NavigationExperimental/NavigationLinearPanResponder.js

diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationCardStackExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationCardStackExample.js
index ae08ac75d252..e7feb7c60b9b 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationCardStackExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationCardStackExample.js
@@ -14,6 +14,7 @@
 'use strict';
 
 const NavigationExampleRow = require('./NavigationExampleRow');
+const NavigationRootContainer = require('NavigationRootContainer');
 const React = require('react-native');
 
 const {
@@ -25,62 +26,68 @@ const {
 const NavigationCardStack = NavigationExperimental.CardStack;
 const NavigationStateUtils = NavigationExperimental.StateUtils;
 
+function reduceNavigationState(initialState) {
+  return (currentState, action) => {
+    switch (action.type) {
+      case 'RootContainerInitialAction':
+        return initialState;
+
+      case 'push':
+        return NavigationStateUtils.push(currentState, {key: action.key});
+
+      case 'back':
+      case 'pop':
+        return currentState.index > 0 ?
+          NavigationStateUtils.pop(currentState) :
+          currentState;
+
+      default:
+        return currentState;
+    }
+  };
+}
+
+const ExampleReducer = reduceNavigationState({
+  index: 0,
+  children: [{key: 'First Route'}],
+});
+
 class NavigationCardStackExample extends React.Component {
 
   constructor(props, context) {
     super(props, context);
-    this.state = this._getInitialState();
+
+    this._renderNavigation = this._renderNavigation.bind(this);
     this._renderScene = this._renderScene.bind(this);
-    this._push = this._push.bind(this);
-    this._pop = this._pop.bind(this);
     this._toggleDirection = this._toggleDirection.bind(this);
+
+    this.state = {isHorizontal: true};
   }
 
   render() {
     return (
-      <NavigationCardStack
-        direction={this.state.isHorizontal ? 'horizontal' : 'vertical'}
-        navigationState={this.state.navigationState}
-        renderScene={this._renderScene}
+      <NavigationRootContainer
+        reducer={ExampleReducer}
+        renderNavigation={this._renderNavigation}
         style={styles.main}
       />
     );
   }
 
-  _getInitialState() {
-    const navigationState = {
-      index: 0,
-      children: [{key: 'First Route'}],
-    };
-    return {
-      isHorizontal: true,
-      navigationState,
-    };
-  }
-
-  _push() {
-    const state = this.state.navigationState;
-    const nextState = NavigationStateUtils.push(
-      state,
-      {key: 'Route ' + (state.index + 1)},
+  _renderNavigation(navigationState, onNavigate) {
+    return (
+      <NavigationCardStack
+        direction={this.state.isHorizontal ? 'horizontal' : 'vertical'}
+        navigationState={navigationState}
+        onNavigate={onNavigate}
+        renderScene={this._renderScene}
+        style={styles.main}
+      />
     );
-    this.setState({
-      navigationState: nextState,
-    });
-  }
-
-  _pop() {
-    const state = this.state.navigationState;
-    const nextState = state.index > 0 ?
-      NavigationStateUtils.pop(state) :
-      state;
-
-    this.setState({
-      navigationState: nextState,
-    });
   }
 
   _renderScene(props) {
+    const {navigationParentState, onNavigate} = props;
     return (
       <ScrollView style={styles.scrollView}>
         <NavigationExampleRow
@@ -96,11 +103,20 @@ class NavigationCardStackExample extends React.Component {
         />
         <NavigationExampleRow
           text="Push Route"
-          onPress={this._push}
+          onPress={() => {
+            onNavigate({
+              type: 'push',
+              key: 'Route ' + navigationParentState.children.length,
+            });
+          }}
         />
         <NavigationExampleRow
           text="Pop Route"
-          onPress={this._pop}
+          onPress={() => {
+            onNavigate({
+              type: 'pop',
+            });
+          }}
         />
         <NavigationExampleRow
           text="Exit Card Stack Example"
@@ -115,6 +131,12 @@ class NavigationCardStackExample extends React.Component {
       isHorizontal: !this.state.isHorizontal,
     });
   }
+
+  _onNavigate(action) {
+    if (action && action.type === 'back') {
+      this._pop();
+    }
+  }
 }
 
 const styles = StyleSheet.create({
diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationCardStack.js b/Libraries/CustomComponents/NavigationExperimental/NavigationCardStack.js
index dbb81eff8d99..f58c49926c95 100644
--- a/Libraries/CustomComponents/NavigationExperimental/NavigationCardStack.js
+++ b/Libraries/CustomComponents/NavigationExperimental/NavigationCardStack.js
@@ -31,6 +31,7 @@ const Animated = require('Animated');
 const NavigationAnimatedView = require('NavigationAnimatedView');
 const NavigationCardStackItem = require('NavigationCardStackItem');
 const NavigationContainer = require('NavigationContainer');
+const NavigationLinearPanResponder = require('NavigationLinearPanResponder');
 const React = require('React');
 const ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
 const StyleSheet = require('StyleSheet');
@@ -38,14 +39,13 @@ const StyleSheet = require('StyleSheet');
 const emptyFunction = require('emptyFunction');
 
 const {PropTypes} = React;
-const {Directions} = NavigationCardStackItem;
+const {Directions} = NavigationLinearPanResponder;
 
 import type {
   NavigationParentState,
 } from 'NavigationStateUtils';
 
 import type {
-  Layout,
   NavigationStateRenderer,
   NavigationStateRendererProps,
   Position,
@@ -55,7 +55,7 @@ import type {
 type Props = {
   direction: string,
   navigationState: NavigationParentState,
-  renderOverlay: NavigationStateRenderer,
+  renderOverlay: ?NavigationStateRenderer,
   renderScene: NavigationStateRenderer,
 };
 
@@ -98,6 +98,7 @@ class NavigationCardStack extends React.Component {
       layout,
       navigationState,
       position,
+      navigationParentState,
     } = props;
 
     return (
@@ -106,6 +107,7 @@ class NavigationCardStack extends React.Component {
         index={index}
         key={navigationState.key}
         layout={layout}
+        navigationParentState={navigationParentState}
         navigationState={navigationState}
         position={position}
         renderScene={this.props.renderScene}
@@ -136,8 +138,6 @@ NavigationCardStack.defaultProps = {
   renderOverlay: emptyFunction.thatReturnsNull,
 };
 
-NavigationCardStack.Directions = Directions;
-
 const styles = StyleSheet.create({
   animatedView: {
     flex: 1,
diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationCardStackItem.js b/Libraries/CustomComponents/NavigationExperimental/NavigationCardStackItem.js
index ff9d5f26824c..4fe0abf4990a 100644
--- a/Libraries/CustomComponents/NavigationExperimental/NavigationCardStackItem.js
+++ b/Libraries/CustomComponents/NavigationExperimental/NavigationCardStackItem.js
@@ -29,33 +29,41 @@
 
 const Animated = require('Animated');
 const NavigationContainer = require('NavigationContainer');
+const NavigationLinearPanResponder = require('NavigationLinearPanResponder');
 const React = require('React');
+const ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
 const StyleSheet = require('StyleSheet');
 const View = require('View');
-const ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
 
 const {PropTypes} = React;
+const {Directions} = NavigationLinearPanResponder;
 
 import type {
   NavigationParentState,
 } from 'NavigationStateUtils';
 
-
 import type {
   Layout,
   Position,
   NavigationStateRenderer,
 } from 'NavigationAnimatedView';
 
+import type {
+  Direction,
+  OnNavigateHandler,
+} from 'NavigationLinearPanResponder';
+
 type AnimatedValue = Animated.Value;
 
 type Props = {
-  direction: string,
+  direction: Direction,
   index: number;
   layout: Layout;
-  navigationState: NavigationParentState;
-  position: Position;
-  renderScene: NavigationStateRenderer;
+  navigationParentState: NavigationParentState,
+  navigationState: NavigationParentState,
+  position: Position,
+  onNavigate: ?OnNavigateHandler,
+  renderScene: NavigationStateRenderer,
 };
 
 type State = {
@@ -78,6 +86,39 @@ class AmimatedValueSubscription {
   }
 }
 
+/**
+ * Class that provides the required information for the
+ * `NavigationLinearPanResponder`. This class must implement
+ * the interface `NavigationLinearPanResponderDelegate`.
+ */
+class PanResponderDelegate {
+  _props : Props;
+
+  constructor(props: Props) {
+    this._props = props;
+  }
+
+  getDirection(): Direction {
+    return this._props.direction;
+  }
+
+  getIndex(): number {
+    return this._props.navigationParentState.index;
+  }
+
+  getLayout(): Layout {
+    return this._props.layout;
+  }
+
+  getPosition(): Position {
+    return this._props.position;
+  }
+
+  onNavigate(action: {type: string}): void {
+    this._props.onNavigate && this._props.onNavigate(action);
+  }
+}
+
 /**
  * Component that renders the scene as card for the <NavigationCardStack />.
  */
@@ -119,9 +160,8 @@ class NavigationCardStackItem extends React.Component {
     const {
       direction,
       index,
-      navigationState,
+      navigationParentState,
       position,
-      layout,
     } = this.props;
     const {
       height,
@@ -161,8 +201,16 @@ class NavigationCardStackItem extends React.Component {
       ],
     };
 
+    let panHandlers = null;
+    if (navigationParentState.index === index) {
+      const delegate = new PanResponderDelegate(this.props);
+      const panResponder = new NavigationLinearPanResponder(delegate);
+      panHandlers = panResponder.panHandlers;
+    }
+
     return (
       <Animated.View
+        {...panHandlers}
         style={[styles.main, animatedStyle]}>
         {this.props.renderScene(this.props)}
       </Animated.View>
@@ -200,16 +248,12 @@ class NavigationCardStackItem extends React.Component {
   }
 }
 
-const Directions = {
-  HORIZONTAL: 'horizontal',
-  VERTICAL: 'vertical',
-};
-
 NavigationCardStackItem.propTypes = {
   direction: PropTypes.oneOf([Directions.HORIZONTAL, Directions.VERTICAL]),
   index: PropTypes.number.isRequired,
   layout: PropTypes.object.isRequired,
   navigationState: PropTypes.object.isRequired,
+  navigationParentState: PropTypes.object.isRequired,
   position: PropTypes.object.isRequired,
   renderScene: PropTypes.func.isRequired,
 };
@@ -218,10 +262,6 @@ NavigationCardStackItem.defaultProps = {
   direction: Directions.HORIZONTAL,
 };
 
-NavigationCardStackItem = NavigationContainer.create(NavigationCardStackItem);
-
-NavigationCardStackItem.Directions = Directions;
-
 const styles = StyleSheet.create({
   main: {
     backgroundColor: '#E9E9EF',
@@ -237,6 +277,4 @@ const styles = StyleSheet.create({
   },
 });
 
-
-
-module.exports = NavigationCardStackItem;
+module.exports = NavigationContainer.create(NavigationCardStackItem);
diff --git a/Libraries/NavigationExperimental/NavigationAbstractPanResponder.js b/Libraries/NavigationExperimental/NavigationAbstractPanResponder.js
new file mode 100644
index 000000000000..d6000a4ce68c
--- /dev/null
+++ b/Libraries/NavigationExperimental/NavigationAbstractPanResponder.js
@@ -0,0 +1,47 @@
+/**
+ * Copyright 2004-present Facebook. All Rights Reserved.
+ *
+ * @providesModule NavigationAbstractPanResponder
+ * @flow
+ */
+'use strict';
+
+const PanResponder = require('PanResponder');
+
+const invariant = require('invariant');
+
+const EmptyPanHandlers = {
+  onMoveShouldSetPanResponder: null,
+  onPanResponderGrant: null,
+  onPanResponderMove: null,
+  onPanResponderRelease: null,
+  onPanResponderTerminate: null,
+};
+
+/**
+ * Abstract class that defines the common interface of PanResponder that handles
+ * the gesture actions.
+ */
+class NavigationAbstractPanResponder {
+
+  panHandlers: Object;
+
+  constructor() {
+    const config = {};
+    Object.keys(EmptyPanHandlers).forEach(name => {
+      const fn: any = (this: any)[name];
+
+      invariant(
+        typeof fn === 'function',
+        'subclass of `NavigationAbstractPanResponder` must implement method %s',
+        name
+      );
+
+      config[name] = fn.bind(this);
+    }, this);
+
+    this.panHandlers = PanResponder.create(config).panHandlers;
+  }
+}
+
+module.exports = NavigationAbstractPanResponder;
diff --git a/Libraries/NavigationExperimental/NavigationAnimatedView.js b/Libraries/NavigationExperimental/NavigationAnimatedView.js
index bf3024ce870c..4d1f5b68f16e 100644
--- a/Libraries/NavigationExperimental/NavigationAnimatedView.js
+++ b/Libraries/NavigationExperimental/NavigationAnimatedView.js
@@ -87,6 +87,8 @@ type NavigationStateRendererProps = {
   layout: Layout,
   // The state of the the containing navigation view.
   navigationParentState: NavigationParentState,
+
+  onNavigate: (action: any) => void,
 };
 
 type NavigationStateRenderer = (
@@ -100,11 +102,12 @@ type TimingSetter = (
 ) => void;
 
 type Props = {
-  navigationState: NavigationParentState;
-  renderScene: NavigationStateRenderer;
-  renderOverlay: ?NavigationStateRenderer;
-  style: any;
-  setTiming: ?TimingSetter;
+  navigationState: NavigationParentState,
+  onNavigate: (action: any) => void,
+  renderScene: NavigationStateRenderer,
+  renderOverlay: ?NavigationStateRenderer,
+  style: any,
+  setTiming: ?TimingSetter,
 };
 
 class NavigationAnimatedView extends React.Component {
@@ -224,18 +227,23 @@ class NavigationAnimatedView extends React.Component {
       layout: this._getLayout(),
       navigationParentState: this.props.navigationState,
       navigationState: scene.state,
+      onNavigate: this.props.onNavigate,
       position: this.state.position,
     });
   }
   _renderOverlay() {
-    const {renderOverlay} = this.props;
+    const {
+      onNavigate,
+      renderOverlay,
+      navigationState,
+    } = this.props;
     if (renderOverlay) {
-      const parentState = this.props.navigationState;
       return renderOverlay({
-        index: parentState.index,
+        index: navigationState.index,
         layout: this._getLayout(),
-        navigationParentState: parentState,
-        navigationState: parentState.children[parentState.index],
+        navigationParentState: navigationState,
+        navigationState: navigationState.children[navigationState.index],
+        onNavigate: onNavigate,
         position: this.state.position,
       });
     }
diff --git a/Libraries/NavigationExperimental/NavigationLinearPanResponder.js b/Libraries/NavigationExperimental/NavigationLinearPanResponder.js
new file mode 100644
index 000000000000..704f305c7704
--- /dev/null
+++ b/Libraries/NavigationExperimental/NavigationLinearPanResponder.js
@@ -0,0 +1,183 @@
+/**
+ * Copyright 2004-present Facebook. All Rights Reserved.
+ *
+ * @providesModule NavigationLinearPanResponder
+ * @flow
+ * @typechecks
+ */
+'use strict';
+
+const Animated = require('Animated');
+const NavigationAbstractPanResponder = require('NavigationAbstractPanResponder');
+
+const clamp = require('clamp');
+
+/**
+ * The duration of the card animation in milliseconds.
+ */
+const ANIMATION_DURATION = 250;
+
+/**
+ * The threshold to invoke the `onNavigate` action.
+ * For instance, `1 / 3` means that moving greater than 1 / 3 of the width of
+ * the view will navigate.
+ */
+const POSITION_THRESHOLD = 1 / 3;
+
+/**
+ * The threshold (in pixels) to start the gesture action.
+ */
+const RESPOND_THRESHOLD = 15;
+
+/**
+ * The threshold (in speed) to finish the gesture action.
+ */
+const VELOCITY_THRESHOLD = 100;
+
+/**
+ * Primitive gesture directions.
+ */
+const Directions = {
+  'HORIZONTAL': 'horizontal',
+  'VERTICAL': 'vertical',
+};
+
+/**
+ * Primitive gesture actions.
+ */
+const Actions = {
+  // The gesture to navigate backward.
+  // This is done by swiping from the left to the right or from the top to the
+  // bottom.
+  BACK: {type: 'back'},
+};
+
+import type {
+  Layout,
+  Position,
+} from 'NavigationAnimatedView';
+
+export type OnNavigateHandler = (action: {type: string}) => void;
+
+export type Direction = $Enum<typeof Directions>;
+
+/**
+ * The type interface of the object that provides the information required by
+ * NavigationLinearPanResponder.
+ */
+export type NavigationLinearPanResponderDelegate = {
+  getDirection: () => Direction;
+  getIndex: () => number,
+  getLayout: () => Layout,
+  getPosition: () => Position,
+  onNavigate: OnNavigateHandler,
+};
+
+/**
+ * Pan responder that handles the One-dimensional gesture (horizontal or
+ * vertical).
+ */
+class NavigationLinearPanResponder extends NavigationAbstractPanResponder {
+  static Actions: Object;
+  static Directions: Object;
+
+  _isResponding: boolean;
+  _startValue: number;
+  _delegate: NavigationLinearPanResponderDelegate;
+
+  constructor(delegate: NavigationLinearPanResponderDelegate) {
+    super();
+    this._isResponding = false;
+    this._startValue = 0;
+    this._delegate = delegate;
+  }
+
+  onMoveShouldSetPanResponder(event: any, gesture: any): boolean {
+    const delegate = this._delegate;
+    const layout = delegate.getLayout();
+    const isVertical = delegate.getDirection() === Directions.VERTICAL;
+    const axis = isVertical ? 'dy' : 'dx';
+    const index = delegate.getIndex();
+    const distance = isVertical ?
+      layout.height.__getValue() :
+      layout.width.__getValue();
+
+    return (
+      Math.abs(gesture[axis]) > RESPOND_THRESHOLD &&
+      distance > 0 &&
+      index > 0
+    );
+  }
+
+  onPanResponderGrant(): void {
+    this._isResponding = false;
+    this._delegate.getPosition().stopAnimation((value: number) => {
+      this._isResponding = true;
+      this._startValue = value;
+    });
+  }
+
+  onPanResponderMove(event: any, gesture: any): void {
+    if (!this._isResponding) {
+      return;
+    }
+
+    const delegate = this._delegate;
+    const layout = delegate.getLayout();
+    const isVertical = delegate.getDirection() === Directions.VERTICAL;
+    const axis = isVertical ? 'dy' : 'dx';
+    const index = delegate.getIndex();
+    const distance = isVertical ?
+      layout.height.__getValue() :
+      layout.width.__getValue();
+
+    const value = clamp(
+      index - 1,
+      this._startValue - (gesture[axis] / distance),
+      index
+    );
+
+    this._delegate.getPosition().setValue(value);
+  }
+
+  onPanResponderRelease(event: any, gesture: any): void {
+    if (!this._isResponding) {
+      return;
+    }
+
+    this._isResponding = false;
+
+    const delegate = this._delegate;
+    const isVertical = delegate.getDirection() === Directions.VERTICAL;
+    const axis = isVertical ? 'dy' : 'dx';
+    const index = delegate.getIndex();
+    const velocity = gesture[axis];
+
+    delegate.getPosition().stopAnimation((value: number) => {
+      this._reset();
+       if (velocity > VELOCITY_THRESHOLD  || value <= index - POSITION_THRESHOLD) {
+        delegate.onNavigate(Actions.BACK);
+      }
+    });
+  }
+
+  onPanResponderTerminate(): void {
+    this._isResponding = false;
+    this._reset();
+  }
+
+  _reset(): void {
+    Animated.timing(
+      this._delegate.getPosition(),
+      {
+        toValue: this._delegate.getIndex(),
+        duration: ANIMATION_DURATION,
+      }
+    ).start();
+  }
+}
+
+NavigationLinearPanResponder.Actions = Actions;
+NavigationLinearPanResponder.Directions = Directions;
+
+module.exports = NavigationLinearPanResponder;

From 25f78020e1443518887c91ed5d77e3fc911c4609 Mon Sep 17 00:00:00 2001
From: Eric Vicenti <evv@fb.com>
Date: Tue, 1 Mar 2016 19:36:18 -0800
Subject: [PATCH 1370/1411] Fix UIExplorer Header

Summary: The UIExplorer header was broken somehow

Reviewed By: vjeux

Differential Revision: D2995823

fb-gh-sync-id: 17f283e8d95c53bcf6dca210896074a3fb2c6cd9
shipit-source-id: 17f283e8d95c53bcf6dca210896074a3fb2c6cd9
---
 Examples/UIExplorer/UIExplorerApp.ios.js | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/Examples/UIExplorer/UIExplorerApp.ios.js b/Examples/UIExplorer/UIExplorerApp.ios.js
index 3bfb2e28a5d5..3072b36f71fe 100644
--- a/Examples/UIExplorer/UIExplorerApp.ios.js
+++ b/Examples/UIExplorer/UIExplorerApp.ios.js
@@ -84,10 +84,12 @@ class UIExplorerApp extends React.Component {
   _renderNavigation: Function;
   _renderOverlay: Function;
   _renderScene: Function;
+  _renderCard: Function;
   componentWillMount() {
     this._renderNavigation = this._renderNavigation.bind(this);
     this._renderOverlay = this._renderOverlay.bind(this);
     this._renderScene = this._renderScene.bind(this);
+    this._renderCard = this._renderCard.bind(this);
   }
   render() {
     return (
@@ -120,7 +122,7 @@ class UIExplorerApp extends React.Component {
         navigationState={stack}
         style={styles.container}
         renderOverlay={this._renderOverlay}
-        renderScene={this._renderScene}
+        renderScene={this._renderCard}
       />
     );
   }
@@ -135,7 +137,7 @@ class UIExplorerApp extends React.Component {
     );
   }
 
-  _renderOverlay(props: NavigationStateRendererProps): ReactElement {
+  _renderCard(props: NavigationStateRendererProps): ReactElement {
     return (
       <NavigationCard
         index={props.index}

From 00178b7b36135e0a25fa83e1824f4035b2932544 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Wed, 2 Mar 2016 11:09:31 +0000
Subject: [PATCH 1371/1411] Added prebuilt folder with BUCK files to support
 BUCK run of ReactAndroid in OSS

This is a manualt sync of a folder from fbsource that was previously in ignored list
---
 ReactAndroid/src/main/jni/prebuilt/BUCK      | 22 ++++++++++++++++++++
 ReactAndroid/src/main/jni/prebuilt/lib/DUMMY |  1 +
 2 files changed, 23 insertions(+)
 create mode 100644 ReactAndroid/src/main/jni/prebuilt/BUCK
 create mode 100644 ReactAndroid/src/main/jni/prebuilt/lib/DUMMY

diff --git a/ReactAndroid/src/main/jni/prebuilt/BUCK b/ReactAndroid/src/main/jni/prebuilt/BUCK
new file mode 100644
index 000000000000..69e71a637360
--- /dev/null
+++ b/ReactAndroid/src/main/jni/prebuilt/BUCK
@@ -0,0 +1,22 @@
+include_defs('//ReactAndroid/DEFS')
+
+# Temp workaround to get the build working e2e, Gradle builds them for us
+
+prebuilt_native_library(
+  name = 'reactnative-libs',
+  native_libs = 'lib',
+  visibility = ['PUBLIC'],
+)
+
+
+android_prebuilt_aar(
+  name = 'android-jsc',
+  aar = ':android-jsc-aar',
+  visibility = ['PUBLIC'],
+)
+
+remote_file(
+  name = 'android-jsc-aar',
+  url = 'mvn:org.webkit:android-jsc:aar:r174650',
+  sha1 = '880cedd93f43e0fc841f01f2fa185a63d9230f85',
+)
diff --git a/ReactAndroid/src/main/jni/prebuilt/lib/DUMMY b/ReactAndroid/src/main/jni/prebuilt/lib/DUMMY
new file mode 100644
index 000000000000..dc29e4d637e6
--- /dev/null
+++ b/ReactAndroid/src/main/jni/prebuilt/lib/DUMMY
@@ -0,0 +1 @@
+# just a dummy temporarily to make BUCK happy about folder not present before Gradle built it

From ca67648f032f0bdfdec67895b544f73c6b6b5391 Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Wed, 2 Mar 2016 04:07:15 -0800
Subject: [PATCH 1372/1411] Revert ArrayBuffer support

Summary:The ArrayBuffer support added in https://github.com/facebook/react-native/pull/6156 crashed on iOS7 as Uint8Array is unavailable.

This diff removes that feature. We can revisit it again once we drop support for iOS 7.

Reviewed By: javache

Differential Revision: D2999762

fb-gh-sync-id: b497eac92ca5a0865b308d2a08c9409fcce97156
shipit-source-id: b497eac92ca5a0865b308d2a08c9409fcce97156
---
 Libraries/Network/XMLHttpRequestBase.js | 27 +++----------------------
 1 file changed, 3 insertions(+), 24 deletions(-)

diff --git a/Libraries/Network/XMLHttpRequestBase.js b/Libraries/Network/XMLHttpRequestBase.js
index 96d2ec1d24af..da96cc13f098 100644
--- a/Libraries/Network/XMLHttpRequestBase.js
+++ b/Libraries/Network/XMLHttpRequestBase.js
@@ -43,8 +43,8 @@ class XMLHttpRequestBase {
   readyState: number;
   responseHeaders: ?Object;
   responseText: ?string;
-  response: string | ArrayBuffer | null;
-  responseType: '' | 'arraybuffer' | 'text';
+  response: ?string;
+  responseType: '' | 'text';
   status: number;
   timeout: number;
   responseURL: ?string;
@@ -143,15 +143,6 @@ class XMLHttpRequestBase {
     }
   }
 
-  _stringToArrayBuffer(str: string): ArrayBuffer {
-    var buffer = new ArrayBuffer(str.length);
-    var bufferView = new Uint8Array(buffer);
-    for (var i = 0, l = str.length; i < l; i++) {
-      bufferView[i] = str.charCodeAt(i);
-    }
-    return buffer;
-  }
-
   _didReceiveData(requestId: number, responseText: string): void {
     if (requestId === this._requestId) {
       if (!this.responseText) {
@@ -164,10 +155,7 @@ class XMLHttpRequestBase {
       case 'text':
         this.response = this.responseText;
         break;
-      case 'arraybuffer': // NOTE: not supported by fetch
-        this.response = this._stringToArrayBuffer(this.responseText);
-        break;
-      default: //TODO: Support the other response type as well (eg:- document, json, blob)
+      default: //TODO: Support other types, eg: document, arraybuffer, json, blob
         this.response = null;
       }
       this.setReadyState(this.LOADING);
@@ -238,12 +226,6 @@ class XMLHttpRequestBase {
     throw new Error('Subclass must define sendImpl method');
   }
 
-  _uintToString(uintArray: Int8Array): string {
-    // $FlowFixMe - Function.apply accepts Int8Array, but Flow thinks it doesn't
-    var encodedString = String.fromCharCode.apply(null, uintArray);
-    return decodeURIComponent(encodedString);
-  }
-
   send(data: any): void {
     if (this.readyState !== this.OPENED) {
       throw new Error('Request has not been opened');
@@ -252,9 +234,6 @@ class XMLHttpRequestBase {
       throw new Error('Request has already been sent');
     }
     this._sent = true;
-    if (data instanceof Int8Array) {
-      data = this._uintToString(data);
-    }
     this.sendImpl(this._method, this._url, this._headers, data, this.timeout);
   }
 

From ad8a33586410c6f9048983f64f8f86e0715e73b8 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Wed, 2 Mar 2016 04:27:13 -0800
Subject: [PATCH 1373/1411] Remove knowledge of fbjs from the packager
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Summary:Follow-up to https://github.com/facebook/react-native/pull/5084

This…
- changes all requires within RN to `require('fbjs/lib/…')`
- updates `.flowconfig`
- updates `packager/blacklist.js`
- adapts tests
- removes things from `Libraries/vendor/{core,emitter}` that are also in fbjs
- removes knowledge of `fbjs` from the packager

Closes https://github.com/facebook/react-native/pull/5084

Reviewed By: bestander

Differential Revision: D2926835

fb-gh-sync-id: 2095e22b2f38e032599d1f2601722b3560e8b6e9
shipit-source-id: 2095e22b2f38e032599d1f2601722b3560e8b6e9
---
 .flowconfig                                   |   8 +-
 Examples/Movies/SearchScreen.js               |   2 +-
 Examples/UIExplorer/createExamplePage.js      |   2 +-
 .../IntegrationTestHarnessTest.js             |   2 +-
 IntegrationTests/LoggingTestModule.js         |   4 +-
 IntegrationTests/SimpleSnapshotTest.js        |   2 +-
 Libraries/ActionSheetIOS/ActionSheetIOS.js    |   2 +-
 .../Animated/src/AnimatedImplementation.js    |   4 +-
 Libraries/AppRegistry/AppRegistry.js          |   2 +-
 Libraries/AppState/AppState.js                |   2 +-
 Libraries/AppStateIOS/AppStateIOS.android.js  |   2 +-
 Libraries/AppStateIOS/AppStateIOS.ios.js      |   2 +-
 Libraries/CameraRoll/CameraRoll.js            |   2 +-
 .../DatePickerAndroid.ios.js                  |   2 +-
 .../Intent/IntentAndroid.android.js           |   2 +-
 .../Components/Navigation/NavigatorIOS.ios.js |   2 +-
 Libraries/Components/ScrollResponder.js       |   4 +-
 Libraries/Components/ScrollView/ScrollView.js |   2 +-
 Libraries/Components/TextInput/TextInput.js   |   4 +-
 .../TimePickerAndroid.ios.js                  |   2 +-
 .../ToastAndroid/ToastAndroid.ios.js          |   2 +-
 Libraries/Components/Touchable/Touchable.js   |   4 +-
 .../Touchable/TouchableHighlight.js           |   2 +-
 .../Touchable/TouchableWithoutFeedback.js     |   2 +-
 .../Touchable/ensureComponentIsNative.js      |   2 +-
 .../Touchable/ensurePositiveDelayProps.js     |   2 +-
 .../View/ReactNativeStyleAttributes.js        |   2 +-
 .../Components/WebView/WebView.android.js     |   2 +-
 Libraries/Components/WebView/WebView.ios.js   |   4 +-
 .../CustomComponents/ListView/ListView.js     |   4 +-
 .../ListView/ListViewDataSource.js            |   6 +-
 .../Navigator/Navigation/NavigationContext.js |   4 +-
 .../Navigator/Navigation/NavigationEvent.js   |   2 +-
 .../Navigation/NavigationRouteStack.js        |   2 +-
 .../Navigation/NavigationTreeNode.js          |   2 +-
 .../__tests__/NavigationEvent-test.js         |   2 +-
 .../__tests__/NavigationEventEmitter-test.js  |   1 +
 .../__tests__/NavigationTreeNode-test.js      |   2 +-
 .../CustomComponents/Navigator/Navigator.js   |   2 +-
 .../NavigatorBreadcrumbNavigationBar.js       |   2 +-
 Libraries/Geolocation/Geolocation.js          |   4 +-
 Libraries/Image/Image.android.js              |   2 +-
 Libraries/Image/Image.ios.js                  |   4 +-
 Libraries/Image/ImageResizeMode.js            |   2 +-
 Libraries/Interaction/InteractionManager.js   |   4 +-
 Libraries/Interaction/TaskQueue.js            |   2 +-
 .../__tests__/InteractionManager-test.js      |   1 +
 .../System/JSTimers/JSTimersExecution.js      |   8 +-
 Libraries/LayoutAnimation/LayoutAnimation.js  |   2 +-
 Libraries/Linking/Linking.js                  |   4 +-
 Libraries/LinkingIOS/LinkingIOS.js            |   2 +-
 Libraries/Promise.js                          |  36 +---
 .../PushNotificationIOS.js                    |   2 +-
 .../ReactIOS/IOSNativeBridgeEventPlugin.js    |   2 +-
 Libraries/ReactIOS/NativeMethodsMixin.js      |   2 +-
 .../ReactIOS/renderApplication.android.js     |   2 +-
 Libraries/ReactIOS/renderApplication.ios.js   |   2 +-
 Libraries/ReactIOS/requireNativeComponent.js  |   2 +-
 Libraries/ReactNative/ReactNative.js          |   4 +-
 .../ReactNative/ReactNativeBaseComponent.js   |   4 +-
 .../ReactNativeDefaultInjection.js            |   2 +-
 .../ReactNative/ReactNativeEventEmitter.js    |   2 +-
 Libraries/ReactNative/ReactNativeMount.js     |   2 +-
 .../ReactNative/ReactNativeTagHandles.js      |   4 +-
 .../ReactNative/ReactNativeTextComponent.js   |   2 +-
 Libraries/ReactNative/findNodeHandle.js       |   4 +-
 Libraries/Sample/Sample.android.js            |   2 +-
 Libraries/Settings/Settings.ios.js            |   2 +-
 Libraries/StyleSheet/StyleSheetValidation.js  |   2 +-
 Libraries/StyleSheet/flattenStyle.js          |   2 +-
 Libraries/StyleSheet/processTransform.js      |   2 +-
 Libraries/Utilities/Dimensions.js             |   2 +-
 Libraries/Utilities/HMRClient.js              |   2 +-
 Libraries/Utilities/MatrixMath.js             |   2 +-
 Libraries/Utilities/MessageQueue.js           |   4 +-
 Libraries/Utilities/PerformanceLogger.js      |   2 +-
 Libraries/Utilities/RCTLog.js                 |   2 +-
 Libraries/Utilities/RCTRenderingPerf.js       |   2 +-
 .../Utilities/__tests__/MatrixMath-test.js    |   2 +-
 .../Utilities/__tests__/MessageQueue-test.js  |   2 +-
 Libraries/Utilities/buildStyleInterpolator.js |   2 +-
 .../Utilities/createStrictShapeTypeChecker.js |   2 +-
 Libraries/Utilities/cssVar.js                 |   2 +-
 Libraries/Vibration/VibrationIOS.android.js   |   2 +-
 Libraries/Vibration/VibrationIOS.ios.js       |   2 +-
 Libraries/vendor/core/isEmpty.js              |  34 ----
 Libraries/vendor/core/mergeHelpers.js         |   4 +-
 Libraries/vendor/crypto/crc32.js              |  92 ---------
 Libraries/vendor/emitter/EventEmitter.js      |   4 +-
 Libraries/vendor/emitter/EventHolder.js       |   2 +-
 .../vendor/emitter/EventSubscriptionVendor.js |   2 +-
 Libraries/vendor/emitter/mixInEventEmitter.js |   4 +-
 .../worker/UniversalWorkerNodeHandle.js       |   2 +-
 npm-shrinkwrap.json                           | 177 ++++++++++--------
 package.json                                  |   9 +-
 packager/blacklist.js                         |  49 -----
 packager/package.json                         |   2 +-
 packager/react-packager/src/Resolver/index.js |   1 -
 98 files changed, 232 insertions(+), 402 deletions(-)
 delete mode 100644 Libraries/vendor/core/isEmpty.js
 delete mode 100644 Libraries/vendor/crypto/crc32.js

diff --git a/.flowconfig b/.flowconfig
index db960b5f1b41..3d5e14681dcd 100644
--- a/.flowconfig
+++ b/.flowconfig
@@ -15,11 +15,8 @@
 # Ignore react and fbjs where there are overlaps, but don't ignore
 # anything that react-native relies on
 .*/node_modules/fbjs/lib/Map.js
-.*/node_modules/fbjs/lib/Promise.js
 .*/node_modules/fbjs/lib/fetch.js
 .*/node_modules/fbjs/lib/ExecutionEnvironment.js
-.*/node_modules/fbjs/lib/isEmpty.js
-.*/node_modules/fbjs/lib/crc32.js
 .*/node_modules/fbjs/lib/ErrorUtils.js
 
 # Flow has a built-in definition for the 'react' module which we prefer to use
@@ -28,6 +25,11 @@
 .*/node_modules/react/lib/React.js
 .*/node_modules/react/lib/ReactDOM.js
 
+.*/__mocks__/.*
+.*/__tests__/.*
+
+.*/commoner/test/source/widget/share.js
+
 # Ignore commoner tests
 .*/node_modules/commoner/test/.*
 
diff --git a/Examples/Movies/SearchScreen.js b/Examples/Movies/SearchScreen.js
index ad1f9b72bfdd..2e681ed34f50 100644
--- a/Examples/Movies/SearchScreen.js
+++ b/Examples/Movies/SearchScreen.js
@@ -27,7 +27,7 @@ var {
 } = React;
 var TimerMixin = require('react-timer-mixin');
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 var dismissKeyboard = require('dismissKeyboard');
 
 var MovieCell = require('./MovieCell');
diff --git a/Examples/UIExplorer/createExamplePage.js b/Examples/UIExplorer/createExamplePage.js
index 20d62badf73b..3d722029516c 100644
--- a/Examples/UIExplorer/createExamplePage.js
+++ b/Examples/UIExplorer/createExamplePage.js
@@ -24,7 +24,7 @@ var ReactNative = require('ReactNative');
 var UIExplorerBlock = require('./UIExplorerBlock');
 var UIExplorerPage = require('./UIExplorerPage');
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 import type { Example, ExampleModule } from 'ExampleTypes';
 
diff --git a/IntegrationTests/IntegrationTestHarnessTest.js b/IntegrationTests/IntegrationTestHarnessTest.js
index 27ef7428dc4b..bfc9c5d88bae 100644
--- a/IntegrationTests/IntegrationTestHarnessTest.js
+++ b/IntegrationTests/IntegrationTestHarnessTest.js
@@ -10,7 +10,7 @@
  */
 'use strict';
 
-var requestAnimationFrame = require('requestAnimationFrame');
+var requestAnimationFrame = require('fbjs/lib/requestAnimationFrame');
 var React = require('react-native');
 var {
   Text,
diff --git a/IntegrationTests/LoggingTestModule.js b/IntegrationTests/LoggingTestModule.js
index 5d3073a37715..cb801a0af088 100644
--- a/IntegrationTests/LoggingTestModule.js
+++ b/IntegrationTests/LoggingTestModule.js
@@ -12,8 +12,8 @@
 
 var BatchedBridge = require('BatchedBridge');
 
-var warning = require('warning');
-var invariant = require('invariant');
+var warning = require('fbjs/lib/warning');
+var invariant = require('fbjs/lib/invariant');
 
 var LoggingTestModule = {
   logToConsole: function(str) {
diff --git a/IntegrationTests/SimpleSnapshotTest.js b/IntegrationTests/SimpleSnapshotTest.js
index 2f0e93358a57..181077acd175 100644
--- a/IntegrationTests/SimpleSnapshotTest.js
+++ b/IntegrationTests/SimpleSnapshotTest.js
@@ -11,7 +11,7 @@
 'use strict';
 
 var React = require('react-native');
-var requestAnimationFrame = require('requestAnimationFrame');
+var requestAnimationFrame = require('fbjs/lib/requestAnimationFrame');
 
 var {
   StyleSheet,
diff --git a/Libraries/ActionSheetIOS/ActionSheetIOS.js b/Libraries/ActionSheetIOS/ActionSheetIOS.js
index 9570d2b8c3f5..a6f5dc2342af 100644
--- a/Libraries/ActionSheetIOS/ActionSheetIOS.js
+++ b/Libraries/ActionSheetIOS/ActionSheetIOS.js
@@ -13,7 +13,7 @@
 
 var RCTActionSheetManager = require('NativeModules').ActionSheetManager;
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 var processColor = require('processColor');
 
 var ActionSheetIOS = {
diff --git a/Libraries/Animated/src/AnimatedImplementation.js b/Libraries/Animated/src/AnimatedImplementation.js
index 4c7a85a4d0fd..8cfacf29860b 100644
--- a/Libraries/Animated/src/AnimatedImplementation.js
+++ b/Libraries/Animated/src/AnimatedImplementation.js
@@ -20,8 +20,8 @@ var SpringConfig = require('SpringConfig');
 var ViewStylePropTypes = require('ViewStylePropTypes');
 
 var flattenStyle = require('flattenStyle');
-var invariant = require('invariant');
-var requestAnimationFrame = require('requestAnimationFrame');
+var invariant = require('fbjs/lib/invariant');
+var requestAnimationFrame = require('fbjs/lib/requestAnimationFrame');
 
 import type { InterpolationConfigType } from 'Interpolation';
 
diff --git a/Libraries/AppRegistry/AppRegistry.js b/Libraries/AppRegistry/AppRegistry.js
index 57bafd2da85a..6077d8663085 100644
--- a/Libraries/AppRegistry/AppRegistry.js
+++ b/Libraries/AppRegistry/AppRegistry.js
@@ -14,7 +14,7 @@
 var BatchedBridge = require('BatchedBridge');
 var ReactNative = require('ReactNative');
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 var renderApplication = require('renderApplication');
 
 if (__DEV__) {
diff --git a/Libraries/AppState/AppState.js b/Libraries/AppState/AppState.js
index ed06c9203b32..8f9a7cf4be9a 100644
--- a/Libraries/AppState/AppState.js
+++ b/Libraries/AppState/AppState.js
@@ -17,7 +17,7 @@ var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
 var RCTAppState = NativeModules.AppState;
 
 var logError = require('logError');
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 var _eventHandlers = {
   change: new Map(),
diff --git a/Libraries/AppStateIOS/AppStateIOS.android.js b/Libraries/AppStateIOS/AppStateIOS.android.js
index 0f59cbea06cf..511174138562 100644
--- a/Libraries/AppStateIOS/AppStateIOS.android.js
+++ b/Libraries/AppStateIOS/AppStateIOS.android.js
@@ -11,7 +11,7 @@
  */
 'use strict';
 
-var warning = require('warning');
+var warning = require('fbjs/lib/warning');
 
 class AppStateIOS {
 
diff --git a/Libraries/AppStateIOS/AppStateIOS.ios.js b/Libraries/AppStateIOS/AppStateIOS.ios.js
index d482b4e7d7b1..82d968ce9afe 100644
--- a/Libraries/AppStateIOS/AppStateIOS.ios.js
+++ b/Libraries/AppStateIOS/AppStateIOS.ios.js
@@ -16,7 +16,7 @@ var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
 var RCTAppState = NativeModules.AppState;
 
 var logError = require('logError');
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 var _eventHandlers = {
   change: new Map(),
diff --git a/Libraries/CameraRoll/CameraRoll.js b/Libraries/CameraRoll/CameraRoll.js
index 985fc2c74cba..8f9cc1bc6186 100644
--- a/Libraries/CameraRoll/CameraRoll.js
+++ b/Libraries/CameraRoll/CameraRoll.js
@@ -17,7 +17,7 @@ var RCTCameraRollManager = require('NativeModules').CameraRollManager;
 var createStrictShapeTypeChecker = require('createStrictShapeTypeChecker');
 var deepFreezeAndThrowOnMutationInDev =
   require('deepFreezeAndThrowOnMutationInDev');
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 var GROUP_TYPES_OPTIONS = [
   'Album',
diff --git a/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js
index 784bc2c82147..4a6d99423f3d 100644
--- a/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js
+++ b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js
@@ -11,7 +11,7 @@
  */
 'use strict';
 
-var warning = require('warning');
+var warning = require('fbjs/lib/warning');
 
 const DatePickerAndroid = {
   async open(options: Object): Promise<Object> {
diff --git a/Libraries/Components/Intent/IntentAndroid.android.js b/Libraries/Components/Intent/IntentAndroid.android.js
index 48877dd6b1ee..0e563d2860d6 100644
--- a/Libraries/Components/Intent/IntentAndroid.android.js
+++ b/Libraries/Components/Intent/IntentAndroid.android.js
@@ -12,7 +12,7 @@
 'use strict';
 
 var Linking = require('Linking');
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 /**
  * NOTE: `IntentAndroid` is being deprecated. Use `Linking` instead.
diff --git a/Libraries/Components/Navigation/NavigatorIOS.ios.js b/Libraries/Components/Navigation/NavigatorIOS.ios.js
index ea5b395a3cf1..c4a2405258df 100644
--- a/Libraries/Components/Navigation/NavigatorIOS.ios.js
+++ b/Libraries/Components/Navigation/NavigatorIOS.ios.js
@@ -20,7 +20,7 @@ var StaticContainer = require('StaticContainer.react');
 var StyleSheet = require('StyleSheet');
 var View = require('View');
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 var logError = require('logError');
 var requireNativeComponent = require('requireNativeComponent');
 var resolveAssetSource = require('resolveAssetSource');
diff --git a/Libraries/Components/ScrollResponder.js b/Libraries/Components/ScrollResponder.js
index f58db6c8f134..f2372fdccb08 100644
--- a/Libraries/Components/ScrollResponder.js
+++ b/Libraries/Components/ScrollResponder.js
@@ -21,8 +21,8 @@ var UIManager = require('UIManager');
 
 var { ScrollViewManager } = require('NativeModules');
 
-var invariant = require('invariant');
-var warning = require('warning');
+var invariant = require('fbjs/lib/invariant');
+var warning = require('fbjs/lib/warning');
 
 import type ReactComponent from 'ReactComponent';
 
diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js
index bdc8978e5166..dfb9e2b61c30 100644
--- a/Libraries/Components/ScrollView/ScrollView.js
+++ b/Libraries/Components/ScrollView/ScrollView.js
@@ -29,7 +29,7 @@ var deprecatedPropType = require('deprecatedPropType');
 var dismissKeyboard = require('dismissKeyboard');
 var flattenStyle = require('flattenStyle');
 var insetsDiffer = require('insetsDiffer');
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 var pointsDiffer = require('pointsDiffer');
 var requireNativeComponent = require('requireNativeComponent');
 var processDecelerationRate = require('processDecelerationRate');
diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js
index 7a902576c7ef..b2080a61f572 100644
--- a/Libraries/Components/TextInput/TextInput.js
+++ b/Libraries/Components/TextInput/TextInput.js
@@ -27,8 +27,8 @@ var UIManager = require('UIManager');
 var View = require('View');
 
 var createReactNativeComponentClass = require('createReactNativeComponentClass');
-var emptyFunction = require('emptyFunction');
-var invariant = require('invariant');
+var emptyFunction = require('fbjs/lib/emptyFunction');
+var invariant = require('fbjs/lib/invariant');
 var requireNativeComponent = require('requireNativeComponent');
 
 var onlyMultiline = {
diff --git a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js
index 02eae1e1fee3..0d7ceee4b64b 100644
--- a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js
+++ b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js
@@ -11,7 +11,7 @@
  */
 'use strict';
 
-var warning = require('warning');
+var warning = require('fbjs/lib/warning');
 
 const TimePickerAndroid = {
   async open(options: Object): Promise<Object> {
diff --git a/Libraries/Components/ToastAndroid/ToastAndroid.ios.js b/Libraries/Components/ToastAndroid/ToastAndroid.ios.js
index 8eb79dfb0dff..4fc912777abb 100644
--- a/Libraries/Components/ToastAndroid/ToastAndroid.ios.js
+++ b/Libraries/Components/ToastAndroid/ToastAndroid.ios.js
@@ -11,7 +11,7 @@
  */
 'use strict';
 
-var warning = require('warning');
+var warning = require('fbjs/lib/warning');
 
 var ToastAndroid = {
 
diff --git a/Libraries/Components/Touchable/Touchable.js b/Libraries/Components/Touchable/Touchable.js
index 83b07248a7f8..4f5000c5ce88 100644
--- a/Libraries/Components/Touchable/Touchable.js
+++ b/Libraries/Components/Touchable/Touchable.js
@@ -6,9 +6,9 @@
 
 var BoundingDimensions = require('BoundingDimensions');
 var Position = require('Position');
-var TouchEventUtils = require('TouchEventUtils');
+var TouchEventUtils = require('fbjs/lib/TouchEventUtils');
 
-var keyMirror = require('keyMirror');
+var keyMirror = require('fbjs/lib/keyMirror');
 var queryLayoutByID = require('queryLayoutByID');
 
 /**
diff --git a/Libraries/Components/Touchable/TouchableHighlight.js b/Libraries/Components/Touchable/TouchableHighlight.js
index 1f6f9ed8176e..a15501bebba8 100644
--- a/Libraries/Components/Touchable/TouchableHighlight.js
+++ b/Libraries/Components/Touchable/TouchableHighlight.js
@@ -25,7 +25,7 @@ var View = require('View');
 
 var ensureComponentIsNative = require('ensureComponentIsNative');
 var ensurePositiveDelayProps = require('ensurePositiveDelayProps');
-var keyOf = require('keyOf');
+var keyOf = require('fbjs/lib/keyOf');
 var merge = require('merge');
 var onlyChild = require('onlyChild');
 
diff --git a/Libraries/Components/Touchable/TouchableWithoutFeedback.js b/Libraries/Components/Touchable/TouchableWithoutFeedback.js
index 3b67ed00e2d0..d48e15856303 100755
--- a/Libraries/Components/Touchable/TouchableWithoutFeedback.js
+++ b/Libraries/Components/Touchable/TouchableWithoutFeedback.js
@@ -18,7 +18,7 @@ var TimerMixin = require('react-timer-mixin');
 var Touchable = require('Touchable');
 var View = require('View');
 var ensurePositiveDelayProps = require('ensurePositiveDelayProps');
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 var onlyChild = require('onlyChild');
 
 type Event = Object;
diff --git a/Libraries/Components/Touchable/ensureComponentIsNative.js b/Libraries/Components/Touchable/ensureComponentIsNative.js
index 944093f78e13..c66735b508b1 100644
--- a/Libraries/Components/Touchable/ensureComponentIsNative.js
+++ b/Libraries/Components/Touchable/ensureComponentIsNative.js
@@ -11,7 +11,7 @@
  */
 'use strict';
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 var ensureComponentIsNative = function(component: any) {
   invariant(
diff --git a/Libraries/Components/Touchable/ensurePositiveDelayProps.js b/Libraries/Components/Touchable/ensurePositiveDelayProps.js
index 4c6525a54130..d2f6a09e8c89 100644
--- a/Libraries/Components/Touchable/ensurePositiveDelayProps.js
+++ b/Libraries/Components/Touchable/ensurePositiveDelayProps.js
@@ -11,7 +11,7 @@
  */
 'use strict';
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 var ensurePositiveDelayProps = function(props: any) {
   invariant(
diff --git a/Libraries/Components/View/ReactNativeStyleAttributes.js b/Libraries/Components/View/ReactNativeStyleAttributes.js
index b9e909a17ecf..1e91b1ef265f 100644
--- a/Libraries/Components/View/ReactNativeStyleAttributes.js
+++ b/Libraries/Components/View/ReactNativeStyleAttributes.js
@@ -16,7 +16,7 @@ var ImageStylePropTypes = require('ImageStylePropTypes');
 var TextStylePropTypes = require('TextStylePropTypes');
 var ViewStylePropTypes = require('ViewStylePropTypes');
 
-var keyMirror = require('keyMirror');
+var keyMirror = require('fbjs/lib/keyMirror');
 var matricesDiffer = require('matricesDiffer');
 var processColor = require('processColor');
 var processTransform = require('processTransform');
diff --git a/Libraries/Components/WebView/WebView.android.js b/Libraries/Components/WebView/WebView.android.js
index d8274855c368..ebf06456671d 100644
--- a/Libraries/Components/WebView/WebView.android.js
+++ b/Libraries/Components/WebView/WebView.android.js
@@ -18,7 +18,7 @@ var UIManager = require('UIManager');
 var View = require('View');
 
 var deprecatedPropType = require('deprecatedPropType');
-var keyMirror = require('keyMirror');
+var keyMirror = require('fbjs/lib/keyMirror');
 var merge = require('merge');
 var requireNativeComponent = require('requireNativeComponent');
 var resolveAssetSource = require('resolveAssetSource');
diff --git a/Libraries/Components/WebView/WebView.ios.js b/Libraries/Components/WebView/WebView.ios.js
index f733963e82b6..9fc11a5c50d5 100644
--- a/Libraries/Components/WebView/WebView.ios.js
+++ b/Libraries/Components/WebView/WebView.ios.js
@@ -21,8 +21,8 @@ var View = require('View');
 var ScrollView = require('ScrollView');
 
 var deprecatedPropType = require('deprecatedPropType');
-var invariant = require('invariant');
-var keyMirror = require('keyMirror');
+var invariant = require('fbjs/lib/invariant');
+var keyMirror = require('fbjs/lib/keyMirror');
 var processDecelerationRate = require('processDecelerationRate');
 var requireNativeComponent = require('requireNativeComponent');
 var resolveAssetSource = require('resolveAssetSource');
diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js
index 357994735f4b..b068737d45bf 100644
--- a/Libraries/CustomComponents/ListView/ListView.js
+++ b/Libraries/CustomComponents/ListView/ListView.js
@@ -34,7 +34,7 @@ var ScrollResponder = require('ScrollResponder');
 var StaticRenderer = require('StaticRenderer');
 var TimerMixin = require('react-timer-mixin');
 
-var isEmpty = require('isEmpty');
+var isEmpty = require('fbjs/lib/isEmpty');
 var merge = require('merge');
 
 var PropTypes = React.PropTypes;
@@ -247,7 +247,7 @@ var ListView = React.createClass({
   },
 
   setNativeProps: function(props) {
-    this.refs[SCROLLVIEW_REF] && 
+    this.refs[SCROLLVIEW_REF] &&
       this.refs[SCROLLVIEW_REF].setNativeProps(props);
   },
 
diff --git a/Libraries/CustomComponents/ListView/ListViewDataSource.js b/Libraries/CustomComponents/ListView/ListViewDataSource.js
index 0c18aa646c0b..cedf8b584a6a 100644
--- a/Libraries/CustomComponents/ListView/ListViewDataSource.js
+++ b/Libraries/CustomComponents/ListView/ListViewDataSource.js
@@ -28,9 +28,9 @@
  */
 'use strict';
 
-var invariant = require('invariant');
-var isEmpty = require('isEmpty');
-var warning = require('warning');
+var invariant = require('fbjs/lib/invariant');
+var isEmpty = require('fbjs/lib/isEmpty');
+var warning = require('fbjs/lib/warning');
 
 function defaultGetRowData(
   dataBlob: any,
diff --git a/Libraries/CustomComponents/Navigator/Navigation/NavigationContext.js b/Libraries/CustomComponents/Navigator/Navigation/NavigationContext.js
index 7024081d2079..406e8be2fc63 100644
--- a/Libraries/CustomComponents/Navigator/Navigation/NavigationContext.js
+++ b/Libraries/CustomComponents/Navigator/Navigation/NavigationContext.js
@@ -33,8 +33,8 @@ var NavigationTreeNode = require('NavigationTreeNode');
 
 var Set = require('Set');
 
-var emptyFunction = require('emptyFunction');
-var invariant = require('invariant');
+var emptyFunction = require('fbjs/lib/emptyFunction');
+var invariant = require('fbjs/lib/invariant');
 
 import type EventSubscription from 'EventSubscription';
 
diff --git a/Libraries/CustomComponents/Navigator/Navigation/NavigationEvent.js b/Libraries/CustomComponents/Navigator/Navigation/NavigationEvent.js
index 6e27f5d5e708..5307e1f869c7 100644
--- a/Libraries/CustomComponents/Navigator/Navigation/NavigationEvent.js
+++ b/Libraries/CustomComponents/Navigator/Navigation/NavigationEvent.js
@@ -27,7 +27,7 @@
  */
 'use strict';
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 class NavigationEventPool {
   _list: Array<any>;
diff --git a/Libraries/CustomComponents/Navigator/Navigation/NavigationRouteStack.js b/Libraries/CustomComponents/Navigator/Navigation/NavigationRouteStack.js
index 16a95b55f9b7..fd0d93222ab7 100644
--- a/Libraries/CustomComponents/Navigator/Navigation/NavigationRouteStack.js
+++ b/Libraries/CustomComponents/Navigator/Navigation/NavigationRouteStack.js
@@ -7,7 +7,7 @@
 'use strict';
 
 var immutable = require('immutable');
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 type IterationCallback = (route: any, index: number, key: string) => void;
 
diff --git a/Libraries/CustomComponents/Navigator/Navigation/NavigationTreeNode.js b/Libraries/CustomComponents/Navigator/Navigation/NavigationTreeNode.js
index b100ab5e43e3..5fdb573f223f 100644
--- a/Libraries/CustomComponents/Navigator/Navigation/NavigationTreeNode.js
+++ b/Libraries/CustomComponents/Navigator/Navigation/NavigationTreeNode.js
@@ -8,7 +8,7 @@
 
 'use strict';
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 var immutable = require('immutable');
 
 var {List} = immutable;
diff --git a/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationEvent-test.js b/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationEvent-test.js
index c3fc0f5ef6cc..81fb1695ef13 100644
--- a/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationEvent-test.js
+++ b/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationEvent-test.js
@@ -27,7 +27,7 @@
 
 jest
   .dontMock('NavigationEvent')
-  .dontMock('invariant');
+  .dontMock('fbjs/lib/invariant');
 
 var NavigationEvent = require('NavigationEvent');
 
diff --git a/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationEventEmitter-test.js b/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationEventEmitter-test.js
index 361892084e53..63b1ccd0ba1e 100644
--- a/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationEventEmitter-test.js
+++ b/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationEventEmitter-test.js
@@ -26,6 +26,7 @@
 
 jest
   .dontMock('EmitterSubscription')
+  .dontMock('EventSubscription')
   .dontMock('EventEmitter')
   .dontMock('EventSubscriptionVendor')
   .dontMock('NavigationEvent')
diff --git a/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationTreeNode-test.js b/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationTreeNode-test.js
index 7a00f72ddc5e..68de370caf75 100644
--- a/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationTreeNode-test.js
+++ b/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationTreeNode-test.js
@@ -6,7 +6,7 @@
 
 jest
   .dontMock('NavigationTreeNode')
-  .dontMock('invariant')
+  .dontMock('fbjs/lib/invariant')
   .dontMock('immutable');
 
 var NavigationTreeNode = require('NavigationTreeNode');
diff --git a/Libraries/CustomComponents/Navigator/Navigator.js b/Libraries/CustomComponents/Navigator/Navigator.js
index d905c603d1b3..e5a8a3a846b4 100644
--- a/Libraries/CustomComponents/Navigator/Navigator.js
+++ b/Libraries/CustomComponents/Navigator/Navigator.js
@@ -44,7 +44,7 @@ var View = require('View');
 var clamp = require('clamp');
 var deprecatedPropType = require('deprecatedPropType');
 var flattenStyle = require('flattenStyle');
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 var rebound = require('rebound');
 
 var PropTypes = React.PropTypes;
diff --git a/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js b/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js
index e224253c21be..6ec0a546d7be 100644
--- a/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js
+++ b/Libraries/CustomComponents/Navigator/NavigatorBreadcrumbNavigationBar.js
@@ -37,7 +37,7 @@ var View = require('View');
 var { Map } = require('immutable');
 
 var guid = require('guid');
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 var Interpolators = NavigatorBreadcrumbNavigationBarStyles.Interpolators;
 var NavigatorNavigationBarStyles = Platform.OS === 'android' ?
diff --git a/Libraries/Geolocation/Geolocation.js b/Libraries/Geolocation/Geolocation.js
index 42d7378eb102..3ed401a5d37c 100644
--- a/Libraries/Geolocation/Geolocation.js
+++ b/Libraries/Geolocation/Geolocation.js
@@ -14,9 +14,9 @@
 var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
 var RCTLocationObserver = require('NativeModules').LocationObserver;
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 var logError = require('logError');
-var warning = require('warning');
+var warning = require('fbjs/lib/warning');
 
 var subscriptions = [];
 
diff --git a/Libraries/Image/Image.android.js b/Libraries/Image/Image.android.js
index 566e95d72c59..7adbe13c206c 100644
--- a/Libraries/Image/Image.android.js
+++ b/Libraries/Image/Image.android.js
@@ -23,7 +23,7 @@ var StyleSheetPropType = require('StyleSheetPropType');
 var View = require('View');
 
 var flattenStyle = require('flattenStyle');
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 var merge = require('merge');
 var requireNativeComponent = require('requireNativeComponent');
 var resolveAssetSource = require('resolveAssetSource');
diff --git a/Libraries/Image/Image.ios.js b/Libraries/Image/Image.ios.js
index 625dc8d50eca..43f694b43ecc 100644
--- a/Libraries/Image/Image.ios.js
+++ b/Libraries/Image/Image.ios.js
@@ -23,10 +23,10 @@ var StyleSheet = require('StyleSheet');
 var StyleSheetPropType = require('StyleSheetPropType');
 
 var flattenStyle = require('flattenStyle');
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 var requireNativeComponent = require('requireNativeComponent');
 var resolveAssetSource = require('resolveAssetSource');
-var warning = require('warning');
+var warning = require('fbjs/lib/warning');
 
 var {
   ImageViewManager,
diff --git a/Libraries/Image/ImageResizeMode.js b/Libraries/Image/ImageResizeMode.js
index 538287258ffc..531212d86794 100644
--- a/Libraries/Image/ImageResizeMode.js
+++ b/Libraries/Image/ImageResizeMode.js
@@ -11,7 +11,7 @@
  */
 'use strict';
 
-var keyMirror = require('keyMirror');
+var keyMirror = require('fbjs/lib/keyMirror');
 
 /**
  * ImageResizeMode - Enum for different image resizing modes, set via
diff --git a/Libraries/Interaction/InteractionManager.js b/Libraries/Interaction/InteractionManager.js
index 8fac8edb8a64..9d0547251a21 100644
--- a/Libraries/Interaction/InteractionManager.js
+++ b/Libraries/Interaction/InteractionManager.js
@@ -16,8 +16,8 @@ const EventEmitter = require('EventEmitter');
 const Set = require('Set');
 const TaskQueue = require('TaskQueue');
 
-const invariant = require('invariant');
-const keyMirror = require('keyMirror');
+const invariant = require('fbjs/lib/invariant');
+const keyMirror = require('fbjs/lib/keyMirror');
 const setImmediate = require('setImmediate');
 
 type Handle = number;
diff --git a/Libraries/Interaction/TaskQueue.js b/Libraries/Interaction/TaskQueue.js
index 91698470dfc3..f623f7a3ad9d 100644
--- a/Libraries/Interaction/TaskQueue.js
+++ b/Libraries/Interaction/TaskQueue.js
@@ -13,7 +13,7 @@
 
 const ErrorUtils = require('ErrorUtils');
 
-const invariant = require('invariant');
+const invariant = require('fbjs/lib/invariant');
 
 type SimpleTask = {
   name: string;
diff --git a/Libraries/Interaction/__tests__/InteractionManager-test.js b/Libraries/Interaction/__tests__/InteractionManager-test.js
index 736fc93c585f..032acf255546 100644
--- a/Libraries/Interaction/__tests__/InteractionManager-test.js
+++ b/Libraries/Interaction/__tests__/InteractionManager-test.js
@@ -6,6 +6,7 @@
 
 jest
   .autoMockOff()
+  .mock('ErrorUtils')
   .mock('BatchedBridge');
 
 function expectToBeCalledOnce(fn) {
diff --git a/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimersExecution.js b/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimersExecution.js
index c85c155a7726..df1b609723e6 100644
--- a/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimersExecution.js
+++ b/Libraries/JavaScriptAppEngine/System/JSTimers/JSTimersExecution.js
@@ -10,10 +10,10 @@
  */
 'use strict';
 
-var invariant = require('invariant');
-var keyMirror = require('keyMirror');
-var performanceNow = require('performanceNow');
-var warning = require('warning');
+var invariant = require('fbjs/lib/invariant');
+var keyMirror = require('fbjs/lib/keyMirror');
+var performanceNow = require('fbjs/lib/performanceNow');
+var warning = require('fbjs/lib/warning');
 var Systrace = require('Systrace');
 
 /**
diff --git a/Libraries/LayoutAnimation/LayoutAnimation.js b/Libraries/LayoutAnimation/LayoutAnimation.js
index 140c35ff8785..108c4d5428e5 100644
--- a/Libraries/LayoutAnimation/LayoutAnimation.js
+++ b/Libraries/LayoutAnimation/LayoutAnimation.js
@@ -15,7 +15,7 @@ var PropTypes = require('ReactPropTypes');
 var UIManager = require('UIManager');
 
 var createStrictShapeTypeChecker = require('createStrictShapeTypeChecker');
-var keyMirror = require('keyMirror');
+var keyMirror = require('fbjs/lib/keyMirror');
 
 var TypesEnum = {
   spring: true,
diff --git a/Libraries/Linking/Linking.js b/Libraries/Linking/Linking.js
index d3603166f672..280b48ec8a85 100644
--- a/Libraries/Linking/Linking.js
+++ b/Libraries/Linking/Linking.js
@@ -18,7 +18,7 @@ const {
   LinkingManager: LinkingManagerIOS
 } = require('NativeModules');
 const LinkingManager = Platform.OS === 'android' ? IntentAndroid : LinkingManagerIOS;
-const invariant = require('invariant');
+const invariant = require('fbjs/lib/invariant');
 const Map = require('Map');
 
 const _notifHandlers = new Map();
@@ -53,7 +53,7 @@ const DEVICE_NOTIF_EVENT = 'openURL';
  * execution you'll need to add the following lines to you `*AppDelegate.m`:
  *
  * ```
- *#import "RCTLinkingManager.h" 
+ *#import "RCTLinkingManager.h"
  *
  * - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
  *   sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
diff --git a/Libraries/LinkingIOS/LinkingIOS.js b/Libraries/LinkingIOS/LinkingIOS.js
index aa252c7d62aa..b5ec9f7a6c60 100644
--- a/Libraries/LinkingIOS/LinkingIOS.js
+++ b/Libraries/LinkingIOS/LinkingIOS.js
@@ -13,7 +13,7 @@
 
 var Linking = require('Linking');
 var RCTLinkingManager = require('NativeModules').LinkingManager;
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 var _initialURL = RCTLinkingManager && RCTLinkingManager.initialURL;
 
diff --git a/Libraries/Promise.js b/Libraries/Promise.js
index 004741948e4d..16cf30bf4706 100644
--- a/Libraries/Promise.js
+++ b/Libraries/Promise.js
@@ -1,30 +1,18 @@
 /**
+ * Copyright (c) 2016-present, Facebook, Inc.
+ * All rights reserved.
  *
- * Copyright 2013-2014 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.
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule Promise
- *
- * This module wraps and augments the minimally ES6-compliant Promise
- * implementation provided by the promise npm package.
+ * @flow
  */
-
 'use strict';
 
-global.setImmediate = require('setImmediate');
-var Promise = require('promise/setimmediate/es6-extensions');
-require('promise/setimmediate/done');
+const Promise = require('fbjs/lib/Promise.native');
+
 if (__DEV__) {
   require('promise/setimmediate/rejection-tracking').enable({
     allRejections: true,
@@ -46,12 +34,4 @@ if (__DEV__) {
   });
 }
 
-/**
- * Handle either fulfillment or rejection with the same callback.
- */
-Promise.prototype.finally = function(onSettled) {
-  return this.then(onSettled, onSettled);
-};
-
-
 module.exports = Promise;
diff --git a/Libraries/PushNotificationIOS/PushNotificationIOS.js b/Libraries/PushNotificationIOS/PushNotificationIOS.js
index c93f644a43f6..f22beb36501f 100644
--- a/Libraries/PushNotificationIOS/PushNotificationIOS.js
+++ b/Libraries/PushNotificationIOS/PushNotificationIOS.js
@@ -13,7 +13,7 @@
 
 var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
 var RCTPushNotificationManager = require('NativeModules').PushNotificationManager;
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 var _notifHandlers = new Map();
 var _initialNotification = RCTPushNotificationManager &&
diff --git a/Libraries/ReactIOS/IOSNativeBridgeEventPlugin.js b/Libraries/ReactIOS/IOSNativeBridgeEventPlugin.js
index 6c1d887e555d..d1ffc1d402e2 100644
--- a/Libraries/ReactIOS/IOSNativeBridgeEventPlugin.js
+++ b/Libraries/ReactIOS/IOSNativeBridgeEventPlugin.js
@@ -16,7 +16,7 @@ var SyntheticEvent = require('SyntheticEvent');
 var UIManager = require('UIManager');
 
 var merge = require('merge');
-var warning = require('warning');
+var warning = require('fbjs/lib/warning');
 
 var customBubblingEventTypes = UIManager.customBubblingEventTypes;
 var customDirectEventTypes = UIManager.customDirectEventTypes;
diff --git a/Libraries/ReactIOS/NativeMethodsMixin.js b/Libraries/ReactIOS/NativeMethodsMixin.js
index f70a2821165e..128752d1ac75 100644
--- a/Libraries/ReactIOS/NativeMethodsMixin.js
+++ b/Libraries/ReactIOS/NativeMethodsMixin.js
@@ -16,7 +16,7 @@ var TextInputState = require('TextInputState');
 var UIManager = require('UIManager');
 
 var findNodeHandle = require('findNodeHandle');
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 type MeasureOnSuccessCallback = (
   x: number,
diff --git a/Libraries/ReactIOS/renderApplication.android.js b/Libraries/ReactIOS/renderApplication.android.js
index 05b87178b6f5..b809ba08d0df 100644
--- a/Libraries/ReactIOS/renderApplication.android.js
+++ b/Libraries/ReactIOS/renderApplication.android.js
@@ -19,7 +19,7 @@ var StyleSheet = require('StyleSheet');
 var Subscribable = require('Subscribable');
 var View = require('View');
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 var YellowBox = __DEV__ ? require('YellowBox') : null;
 
diff --git a/Libraries/ReactIOS/renderApplication.ios.js b/Libraries/ReactIOS/renderApplication.ios.js
index ad000f643051..2e37716cc135 100644
--- a/Libraries/ReactIOS/renderApplication.ios.js
+++ b/Libraries/ReactIOS/renderApplication.ios.js
@@ -18,7 +18,7 @@ var StyleSheet = require('StyleSheet');
 var Subscribable = require('Subscribable');
 var View = require('View');
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 var Inspector = __DEV__ ? require('Inspector') : null;
 var YellowBox = __DEV__ ? require('YellowBox') : null;
diff --git a/Libraries/ReactIOS/requireNativeComponent.js b/Libraries/ReactIOS/requireNativeComponent.js
index 4f8ddaf2e4f4..61993f799fb9 100644
--- a/Libraries/ReactIOS/requireNativeComponent.js
+++ b/Libraries/ReactIOS/requireNativeComponent.js
@@ -24,7 +24,7 @@ var processColor = require('processColor');
 var resolveAssetSource = require('resolveAssetSource');
 var sizesDiffer = require('sizesDiffer');
 var verifyPropTypes = require('verifyPropTypes');
-var warning = require('warning');
+var warning = require('fbjs/lib/warning');
 
 /**
  * Used to create React components that directly wrap native component
diff --git a/Libraries/ReactNative/ReactNative.js b/Libraries/ReactNative/ReactNative.js
index e2314ba581f9..148a366663ef 100644
--- a/Libraries/ReactNative/ReactNative.js
+++ b/Libraries/ReactNative/ReactNative.js
@@ -27,9 +27,9 @@ var ReactPropTypes = require('ReactPropTypes');
 var ReactUpdates = require('ReactUpdates');
 
 var findNodeHandle = require('findNodeHandle');
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 var onlyChild = require('onlyChild');
-var warning = require('warning');
+var warning = require('fbjs/lib/warning');
 
 ReactNativeDefaultInjection.inject();
 
diff --git a/Libraries/ReactNative/ReactNativeBaseComponent.js b/Libraries/ReactNative/ReactNativeBaseComponent.js
index 19afca80362e..b879b45b6a51 100644
--- a/Libraries/ReactNative/ReactNativeBaseComponent.js
+++ b/Libraries/ReactNative/ReactNativeBaseComponent.js
@@ -19,8 +19,8 @@ var ReactMultiChild = require('ReactMultiChild');
 var UIManager = require('UIManager');
 
 var deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
-var invariant = require('invariant');
-var warning = require('warning');
+var invariant = require('fbjs/lib/invariant');
+var warning = require('fbjs/lib/warning');
 
 var registrationNames = ReactNativeEventEmitter.registrationNames;
 var putListener = ReactNativeEventEmitter.putListener;
diff --git a/Libraries/ReactNative/ReactNativeDefaultInjection.js b/Libraries/ReactNative/ReactNativeDefaultInjection.js
index 0d55d670c40e..ee97c2560e61 100644
--- a/Libraries/ReactNative/ReactNativeDefaultInjection.js
+++ b/Libraries/ReactNative/ReactNativeDefaultInjection.js
@@ -38,7 +38,7 @@ var ReactUpdates = require('ReactUpdates');
 var ResponderEventPlugin = require('ResponderEventPlugin');
 var UniversalWorkerNodeHandle = require('UniversalWorkerNodeHandle');
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 // Just to ensure this gets packaged, since its only caller is from Native.
 require('RCTEventEmitter');
diff --git a/Libraries/ReactNative/ReactNativeEventEmitter.js b/Libraries/ReactNative/ReactNativeEventEmitter.js
index ac8854b6cb65..c7680257aff5 100644
--- a/Libraries/ReactNative/ReactNativeEventEmitter.js
+++ b/Libraries/ReactNative/ReactNativeEventEmitter.js
@@ -18,7 +18,7 @@ var NodeHandle = require('NodeHandle');
 var EventConstants = require('EventConstants');
 
 var merge = require('merge');
-var warning = require('warning');
+var warning = require('fbjs/lib/warning');
 
 var topLevelTypes = EventConstants.topLevelTypes;
 
diff --git a/Libraries/ReactNative/ReactNativeMount.js b/Libraries/ReactNative/ReactNativeMount.js
index 2a38c3dbba8c..cf8c5bb336fd 100644
--- a/Libraries/ReactNative/ReactNativeMount.js
+++ b/Libraries/ReactNative/ReactNativeMount.js
@@ -19,7 +19,7 @@ var ReactUpdateQueue = require('ReactUpdateQueue');
 var ReactUpdates = require('ReactUpdates');
 var UIManager = require('UIManager');
 
-var emptyObject = require('emptyObject');
+var emptyObject = require('fbjs/lib/emptyObject');
 var instantiateReactComponent = require('instantiateReactComponent');
 var shouldUpdateReactComponent = require('shouldUpdateReactComponent');
 
diff --git a/Libraries/ReactNative/ReactNativeTagHandles.js b/Libraries/ReactNative/ReactNativeTagHandles.js
index ab350817c6e9..5a0de4cda393 100644
--- a/Libraries/ReactNative/ReactNativeTagHandles.js
+++ b/Libraries/ReactNative/ReactNativeTagHandles.js
@@ -11,8 +11,8 @@
  */
 'use strict';
 
-var invariant = require('invariant');
-var warning = require('warning');
+var invariant = require('fbjs/lib/invariant');
+var warning = require('fbjs/lib/warning');
 
 /**
  * Keeps track of allocating and associating native "tags" which are numeric,
diff --git a/Libraries/ReactNative/ReactNativeTextComponent.js b/Libraries/ReactNative/ReactNativeTextComponent.js
index e9f67ce59fdb..0eb5e0a6b0d0 100644
--- a/Libraries/ReactNative/ReactNativeTextComponent.js
+++ b/Libraries/ReactNative/ReactNativeTextComponent.js
@@ -15,7 +15,7 @@ var ReactNativeTagHandles = require('ReactNativeTagHandles');
 var UIManager = require('UIManager');
 
 var assign = require('Object.assign');
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 var ReactNativeTextComponent = function(props) {
   // This constructor and its argument is currently used by mocks.
diff --git a/Libraries/ReactNative/findNodeHandle.js b/Libraries/ReactNative/findNodeHandle.js
index 37c772760c50..dd3191b82d92 100644
--- a/Libraries/ReactNative/findNodeHandle.js
+++ b/Libraries/ReactNative/findNodeHandle.js
@@ -16,8 +16,8 @@ var ReactCurrentOwner = require('ReactCurrentOwner');
 var ReactInstanceMap = require('ReactInstanceMap');
 var ReactNativeTagHandles = require('ReactNativeTagHandles');
 
-var invariant = require('invariant');
-var warning = require('warning');
+var invariant = require('fbjs/lib/invariant');
+var warning = require('fbjs/lib/warning');
 
 /**
  * ReactNative vs ReactWeb
diff --git a/Libraries/Sample/Sample.android.js b/Libraries/Sample/Sample.android.js
index 2024dbdaeafc..1a66fb9bf575 100644
--- a/Libraries/Sample/Sample.android.js
+++ b/Libraries/Sample/Sample.android.js
@@ -6,7 +6,7 @@
  */
 'use strict';
 
-var warning = require('warning');
+var warning = require('fbjs/lib/warning');
 
 var Sample = {
   test: function() {
diff --git a/Libraries/Settings/Settings.ios.js b/Libraries/Settings/Settings.ios.js
index 73d66ca587c3..3d1036fedf49 100644
--- a/Libraries/Settings/Settings.ios.js
+++ b/Libraries/Settings/Settings.ios.js
@@ -14,7 +14,7 @@
 var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
 var RCTSettingsManager = require('NativeModules').SettingsManager;
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 var subscriptions: Array<{keys: Array<string>; callback: ?Function}> = [];
 
diff --git a/Libraries/StyleSheet/StyleSheetValidation.js b/Libraries/StyleSheet/StyleSheetValidation.js
index f61decb3cc2c..2be4ca2f2496 100644
--- a/Libraries/StyleSheet/StyleSheetValidation.js
+++ b/Libraries/StyleSheet/StyleSheetValidation.js
@@ -16,7 +16,7 @@ var ReactPropTypeLocations = require('ReactPropTypeLocations');
 var TextStylePropTypes = require('TextStylePropTypes');
 var ViewStylePropTypes = require('ViewStylePropTypes');
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 class StyleSheetValidation {
   static validateStyleProp(prop, style, caller) {
diff --git a/Libraries/StyleSheet/flattenStyle.js b/Libraries/StyleSheet/flattenStyle.js
index 621c614ffd9f..a3af4f46e63d 100644
--- a/Libraries/StyleSheet/flattenStyle.js
+++ b/Libraries/StyleSheet/flattenStyle.js
@@ -12,7 +12,7 @@
 'use strict';
 
 var StyleSheetRegistry = require('StyleSheetRegistry');
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 import type { StyleObj } from 'StyleSheetTypes';
 
diff --git a/Libraries/StyleSheet/processTransform.js b/Libraries/StyleSheet/processTransform.js
index 4a523f909108..6978efdcfbe6 100644
--- a/Libraries/StyleSheet/processTransform.js
+++ b/Libraries/StyleSheet/processTransform.js
@@ -14,7 +14,7 @@
 var MatrixMath = require('MatrixMath');
 var Platform = require('Platform');
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 var stringifySafe = require('stringifySafe');
 
 /**
diff --git a/Libraries/Utilities/Dimensions.js b/Libraries/Utilities/Dimensions.js
index f73853473dc2..5cf5f21edc21 100644
--- a/Libraries/Utilities/Dimensions.js
+++ b/Libraries/Utilities/Dimensions.js
@@ -14,7 +14,7 @@
 var Platform = require('Platform');
 var UIManager = require('UIManager');
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 var dimensions = UIManager.Dimensions;
 
diff --git a/Libraries/Utilities/HMRClient.js b/Libraries/Utilities/HMRClient.js
index 16f32368cc26..14850f860ba6 100644
--- a/Libraries/Utilities/HMRClient.js
+++ b/Libraries/Utilities/HMRClient.js
@@ -12,7 +12,7 @@
 'use strict';
 
 const Platform = require('Platform');
-const invariant = require('invariant');
+const invariant = require('fbjs/lib/invariant');
 
 /**
  * HMR Client that receives from the server HMR updates and propagates them
diff --git a/Libraries/Utilities/MatrixMath.js b/Libraries/Utilities/MatrixMath.js
index 32f3cd32f4de..6900106a6e0f 100755
--- a/Libraries/Utilities/MatrixMath.js
+++ b/Libraries/Utilities/MatrixMath.js
@@ -7,7 +7,7 @@
 /* eslint-disable space-infix-ops */
 'use strict';
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 /**
  * Memory conservative (mutative) matrix math utilities. Uses "command"
diff --git a/Libraries/Utilities/MessageQueue.js b/Libraries/Utilities/MessageQueue.js
index 7b31c114914a..2e542b6c40f3 100644
--- a/Libraries/Utilities/MessageQueue.js
+++ b/Libraries/Utilities/MessageQueue.js
@@ -18,8 +18,8 @@ let ErrorUtils = require('ErrorUtils');
 let JSTimersExecution = require('JSTimersExecution');
 let Platform = require('Platform');
 
-let invariant = require('invariant');
-let keyMirror = require('keyMirror');
+let invariant = require('fbjs/lib/invariant');
+let keyMirror = require('fbjs/lib/keyMirror');
 let stringifySafe = require('stringifySafe');
 
 let MODULE_IDS = 0;
diff --git a/Libraries/Utilities/PerformanceLogger.js b/Libraries/Utilities/PerformanceLogger.js
index e2d0e5c81ad2..03e5df830bbe 100644
--- a/Libraries/Utilities/PerformanceLogger.js
+++ b/Libraries/Utilities/PerformanceLogger.js
@@ -12,7 +12,7 @@
 
 var BatchedBridge = require('BatchedBridge');
 
-var performanceNow = require('performanceNow');
+var performanceNow = require('fbjs/lib/performanceNow');
 
 var timespans = {};
 var extras = {};
diff --git a/Libraries/Utilities/RCTLog.js b/Libraries/Utilities/RCTLog.js
index 65abc5883d03..32394684cb9d 100644
--- a/Libraries/Utilities/RCTLog.js
+++ b/Libraries/Utilities/RCTLog.js
@@ -13,7 +13,7 @@
 
 var BatchedBridge = require('BatchedBridge');
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 var levelsMap = {
   log: 'log',
diff --git a/Libraries/Utilities/RCTRenderingPerf.js b/Libraries/Utilities/RCTRenderingPerf.js
index 126c8a032852..3979780ba364 100644
--- a/Libraries/Utilities/RCTRenderingPerf.js
+++ b/Libraries/Utilities/RCTRenderingPerf.js
@@ -13,7 +13,7 @@
 
 var ReactDefaultPerf = require('ReactDefaultPerf');
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 type perfModule = {
   start: () => void;
diff --git a/Libraries/Utilities/__tests__/MatrixMath-test.js b/Libraries/Utilities/__tests__/MatrixMath-test.js
index 5bfa1e9d7b81..b8c10ac402e2 100644
--- a/Libraries/Utilities/__tests__/MatrixMath-test.js
+++ b/Libraries/Utilities/__tests__/MatrixMath-test.js
@@ -9,7 +9,7 @@
 'use strict';
 
 jest.dontMock('MatrixMath');
-jest.dontMock('invariant');
+jest.dontMock('fbjs/lib/invariant');
 
 var MatrixMath = require('MatrixMath');
 
diff --git a/Libraries/Utilities/__tests__/MessageQueue-test.js b/Libraries/Utilities/__tests__/MessageQueue-test.js
index ab04d0fe54cf..14c50e746d7d 100644
--- a/Libraries/Utilities/__tests__/MessageQueue-test.js
+++ b/Libraries/Utilities/__tests__/MessageQueue-test.js
@@ -9,7 +9,7 @@
 'use strict';
 
 jest.dontMock('MessageQueue')
-  .dontMock('keyMirror');
+  .dontMock('fbjs/lib/keyMirror');
 var MessageQueue = require('MessageQueue');
 
 let MODULE_IDS = 0;
diff --git a/Libraries/Utilities/buildStyleInterpolator.js b/Libraries/Utilities/buildStyleInterpolator.js
index 0c0fa7fd1221..ff51699b033d 100644
--- a/Libraries/Utilities/buildStyleInterpolator.js
+++ b/Libraries/Utilities/buildStyleInterpolator.js
@@ -9,7 +9,7 @@
  */
 /* eslint-disable global-strict */
 
-var keyOf = require('keyOf');
+var keyOf = require('fbjs/lib/keyOf');
 
 var X_DIM = keyOf({x: null});
 var Y_DIM = keyOf({y: null});
diff --git a/Libraries/Utilities/createStrictShapeTypeChecker.js b/Libraries/Utilities/createStrictShapeTypeChecker.js
index 883da2459f7c..b5fe14a1b950 100644
--- a/Libraries/Utilities/createStrictShapeTypeChecker.js
+++ b/Libraries/Utilities/createStrictShapeTypeChecker.js
@@ -13,7 +13,7 @@
 
 var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames');
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 var merge = require('merge');
 
 function createStrictShapeTypeChecker(
diff --git a/Libraries/Utilities/cssVar.js b/Libraries/Utilities/cssVar.js
index 0ab64e7f9ca5..094689ae25f1 100644
--- a/Libraries/Utilities/cssVar.js
+++ b/Libraries/Utilities/cssVar.js
@@ -6,7 +6,7 @@
  */
 'use strict';
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 var CSSVarConfig = require('CSSVarConfig');
 
 var cssVar = function(/*string*/ key) /*string*/ {
diff --git a/Libraries/Vibration/VibrationIOS.android.js b/Libraries/Vibration/VibrationIOS.android.js
index f52be6b7501b..37cdf859c1eb 100644
--- a/Libraries/Vibration/VibrationIOS.android.js
+++ b/Libraries/Vibration/VibrationIOS.android.js
@@ -12,7 +12,7 @@
  */
 'use strict';
 
-var warning = require('warning');
+var warning = require('fbjs/lib/warning');
 
 var VibrationIOS = {
   vibrate: function() {
diff --git a/Libraries/Vibration/VibrationIOS.ios.js b/Libraries/Vibration/VibrationIOS.ios.js
index 2a1dc701c173..1e0a17942d67 100644
--- a/Libraries/Vibration/VibrationIOS.ios.js
+++ b/Libraries/Vibration/VibrationIOS.ios.js
@@ -13,7 +13,7 @@
 
 var RCTVibration = require('NativeModules').Vibration;
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 /**
  * The Vibration API is exposed at `VibrationIOS.vibrate()`. On iOS, calling this
diff --git a/Libraries/vendor/core/isEmpty.js b/Libraries/vendor/core/isEmpty.js
deleted file mode 100644
index 27f4c0069a06..000000000000
--- a/Libraries/vendor/core/isEmpty.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * @generated SignedSource<<97ffcebc9ae390e734026a4f3964bff6>>
- *
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !! This file is a check-in of a static_upstream project!      !!
- * !!                                                            !!
- * !! You should not modify this file directly. Instead:         !!
- * !! 1) Use `fjs use-upstream` to temporarily replace this with !!
- * !!    the latest version from upstream.                       !!
- * !! 2) Make your changes, test them, etc.                      !!
- * !! 3) Use `fjs push-upstream` to copy your changes back to    !!
- * !!    static_upstream.                                        !!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- *
- * @providesModule isEmpty
- */
-
-/**
- * Mimics empty from PHP.
- */
-function isEmpty(obj) {
-  if (Array.isArray(obj)) {
-    return obj.length === 0;
-  } else if (typeof obj === 'object') {
-    for (var i in obj) {
-      return false;
-    }
-    return true;
-  } else {
-    return !obj;
-  }
-}
-
-module.exports = isEmpty;
diff --git a/Libraries/vendor/core/mergeHelpers.js b/Libraries/vendor/core/mergeHelpers.js
index 58fa238d4f2b..d0c506b3d924 100644
--- a/Libraries/vendor/core/mergeHelpers.js
+++ b/Libraries/vendor/core/mergeHelpers.js
@@ -33,8 +33,8 @@
 
 "use strict";
 
-var invariant = require('invariant');
-var keyMirror = require('keyMirror');
+var invariant = require('fbjs/lib/invariant');
+var keyMirror = require('fbjs/lib/keyMirror');
 
 /**
  * Maximum number of levels to traverse. Will catch circular structures.
diff --git a/Libraries/vendor/crypto/crc32.js b/Libraries/vendor/crypto/crc32.js
deleted file mode 100644
index 540d60aa832b..000000000000
--- a/Libraries/vendor/crypto/crc32.js
+++ /dev/null
@@ -1,92 +0,0 @@
-/**
- * @generated SignedSource<<77bdeb858138636c96c405d64b6be55c>>
- *
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- * !! This file is a check-in of a static_upstream project!      !!
- * !!                                                            !!
- * !! You should not modify this file directly. Instead:         !!
- * !! 1) Use `fjs use-upstream` to temporarily replace this with !!
- * !!    the latest version from upstream.                       !!
- * !! 2) Make your changes, test them, etc.                      !!
- * !! 3) Use `fjs push-upstream` to copy your changes back to    !!
- * !!    static_upstream.                                        !!
- * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- *
- * Copyright 2004-present Facebook. All Rights Reserved.
- *
- * @providesModule crc32
- */
-
-/* jslint bitwise: true */
-
-/**
- * Modified from the original for performance improvements.
- *
- * @see http://create.stephan-brumme.com/crc32/
- * @see http://stackoverflow.com/questions/18638900/
- * @copyright 2006 Andrea Ercolino
- * @license MIT
- */
-
-var table = [
-  0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
-  0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
-  0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
-  0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
-  0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
-  0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
-  0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
-  0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
-  0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
-  0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
-  0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
-  0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
-  0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
-  0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
-  0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
-  0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
-  0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
-  0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
-  0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
-  0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
-  0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
-  0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
-  0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
-  0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
-  0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
-  0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
-  0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
-  0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
-  0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
-  0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
-  0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
-  0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
-  0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
-  0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
-  0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
-  0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
-  0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
-  0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
-  0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
-  0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
-  0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
-  0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
-  0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
-];
-
-if (global.Int32Array !== undefined) {
-  table = new Int32Array(table);
-}
-
-/**
- * @returns Number
- */
-function crc32(str) {
-  var crc = -1;
-  for (var i = 0, len = str.length; i < len; i++) {
-    crc = (crc >>> 8) ^ table[(crc ^ str.charCodeAt(i)) & 0xFF];
-  }
-  return ~crc;
-}
-
-module.exports = crc32;
diff --git a/Libraries/vendor/emitter/EventEmitter.js b/Libraries/vendor/emitter/EventEmitter.js
index b5c14a66a7c7..ba6781a57e3f 100644
--- a/Libraries/vendor/emitter/EventEmitter.js
+++ b/Libraries/vendor/emitter/EventEmitter.js
@@ -14,8 +14,8 @@
 var EmitterSubscription = require('EmitterSubscription');
 var ErrorUtils = require('ErrorUtils');
 var EventSubscriptionVendor = require('EventSubscriptionVendor');
-var emptyFunction = require('emptyFunction');
-var invariant = require('invariant');
+var emptyFunction = require('fbjs/lib/emptyFunction');
+var invariant = require('fbjs/lib/invariant');
 
 /**
  * @class EventEmitter
diff --git a/Libraries/vendor/emitter/EventHolder.js b/Libraries/vendor/emitter/EventHolder.js
index 4345c3d387cd..76cfd33141e8 100644
--- a/Libraries/vendor/emitter/EventHolder.js
+++ b/Libraries/vendor/emitter/EventHolder.js
@@ -17,7 +17,7 @@
  */
 'use strict';
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 class EventHolder {
   constructor() {
diff --git a/Libraries/vendor/emitter/EventSubscriptionVendor.js b/Libraries/vendor/emitter/EventSubscriptionVendor.js
index add1f408e4a8..d992a69a5536 100644
--- a/Libraries/vendor/emitter/EventSubscriptionVendor.js
+++ b/Libraries/vendor/emitter/EventSubscriptionVendor.js
@@ -17,7 +17,7 @@
  */
 'use strict';
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 /**
  * EventSubscriptionVendor stores a set of EventSubscriptions that are
diff --git a/Libraries/vendor/emitter/mixInEventEmitter.js b/Libraries/vendor/emitter/mixInEventEmitter.js
index 4dc938199d40..fc39f7b649e1 100644
--- a/Libraries/vendor/emitter/mixInEventEmitter.js
+++ b/Libraries/vendor/emitter/mixInEventEmitter.js
@@ -21,8 +21,8 @@ var EventHolder = require('EventHolder');
 var EventValidator = require('EventValidator');
 
 var copyProperties = require('copyProperties');
-var invariant = require('invariant');
-var keyOf = require('keyOf');
+var invariant = require('fbjs/lib/invariant');
+var keyOf = require('fbjs/lib/keyOf');
 
 var TYPES_KEY = keyOf({__types: true});
 
diff --git a/Libraries/vendor/react/platformImplementations/universal/worker/UniversalWorkerNodeHandle.js b/Libraries/vendor/react/platformImplementations/universal/worker/UniversalWorkerNodeHandle.js
index b91feba9b1e2..ca7faa7fecfe 100644
--- a/Libraries/vendor/react/platformImplementations/universal/worker/UniversalWorkerNodeHandle.js
+++ b/Libraries/vendor/react/platformImplementations/universal/worker/UniversalWorkerNodeHandle.js
@@ -4,7 +4,7 @@
 
 var ReactNativeTagHandles = require('ReactNativeTagHandles');
 
-var invariant = require('invariant');
+var invariant = require('fbjs/lib/invariant');
 
 var UniversalWorkerNodeHandle = {
   getRootNodeID: function(nodeHandle) {
diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index 4cf8daa434b8..bc519c383b22 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -137,11 +137,6 @@
           "from": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz",
           "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz"
         },
-        "regenerator": {
-          "version": "0.8.40",
-          "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
-          "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
-        },
         "js-tokens": {
           "version": "1.0.1",
           "from": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz",
@@ -151,6 +146,11 @@
           "version": "0.10.33",
           "from": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz",
           "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
+        },
+        "regenerator": {
+          "version": "0.8.40",
+          "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
+          "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
         }
       }
     },
@@ -248,15 +248,15 @@
           "from": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz",
           "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz"
         },
-        "source-map": {
-          "version": "0.5.3",
-          "from": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz"
-        },
         "regenerator": {
           "version": "0.8.40",
           "from": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz",
           "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz"
+        },
+        "source-map": {
+          "version": "0.5.3",
+          "from": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz"
         }
       }
     },
@@ -1820,19 +1820,21 @@
       "resolved": "https://registry.npmjs.org/fast-path/-/fast-path-1.1.0.tgz"
     },
     "fbjs": {
-      "version": "0.6.0",
-      "from": "https://registry.npmjs.org/fbjs/-/fbjs-0.6.0.tgz",
-      "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.6.0.tgz",
+      "version": "0.7.2",
+      "from": "fbjs@0.7.2",
+      "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.7.2.tgz",
       "dependencies": {
-        "ua-parser-js": {
-          "version": "0.7.10",
-          "from": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.10.tgz",
-          "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.10.tgz"
-        },
-        "whatwg-fetch": {
-          "version": "0.9.0",
-          "from": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz",
-          "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz"
+        "isomorphic-fetch": {
+          "version": "2.2.1",
+          "from": "isomorphic-fetch@>=2.1.1 <3.0.0",
+          "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
+          "dependencies": {
+            "whatwg-fetch": {
+              "version": "0.11.0",
+              "from": "whatwg-fetch@>=0.10.0",
+              "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.11.0.tgz"
+            }
+          }
         }
       }
     },
@@ -1905,26 +1907,26 @@
           "from": "ansi@~0.3.0",
           "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.0.tgz"
         },
-        "ansi-styles": {
-          "version": "2.1.0",
-          "from": "ansi-styles@^2.1.0",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz"
-        },
-        "asn1": {
-          "version": "0.1.11",
-          "from": "asn1@0.1.11",
-          "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
-        },
         "ansi-regex": {
           "version": "2.0.0",
           "from": "ansi-regex@^2.0.0",
           "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
         },
+        "ansi-styles": {
+          "version": "2.1.0",
+          "from": "ansi-styles@^2.1.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz"
+        },
         "are-we-there-yet": {
           "version": "1.0.4",
           "from": "are-we-there-yet@~1.0.0",
           "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.4.tgz"
         },
+        "asn1": {
+          "version": "0.1.11",
+          "from": "asn1@0.1.11",
+          "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
+        },
         "assert-plus": {
           "version": "0.1.5",
           "from": "assert-plus@^0.1.5",
@@ -1960,16 +1962,16 @@
           "from": "brace-expansion@>=1.0.0 <2.0.0",
           "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz"
         },
-        "chalk": {
-          "version": "1.1.1",
-          "from": "chalk@^1.1.1",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz"
-        },
         "caseless": {
           "version": "0.11.0",
           "from": "caseless@~0.11.0",
           "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
         },
+        "chalk": {
+          "version": "1.1.1",
+          "from": "chalk@^1.1.1",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz"
+        },
         "combined-stream": {
           "version": "1.0.5",
           "from": "combined-stream@~1.0.5",
@@ -2000,16 +2002,16 @@
           "from": "ctype@0.5.3",
           "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz"
         },
-        "deep-extend": {
-          "version": "0.2.11",
-          "from": "deep-extend@~0.2.5",
-          "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.2.11.tgz"
-        },
         "debug": {
           "version": "0.7.4",
           "from": "debug@~0.7.2",
           "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz"
         },
+        "deep-extend": {
+          "version": "0.2.11",
+          "from": "deep-extend@~0.2.5",
+          "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.2.11.tgz"
+        },
         "delayed-stream": {
           "version": "1.0.0",
           "from": "delayed-stream@~1.0.0",
@@ -2120,16 +2122,16 @@
           "from": "is-property@^1.0.0",
           "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz"
         },
-        "isstream": {
-          "version": "0.1.2",
-          "from": "isstream@~0.1.2",
-          "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
-        },
         "isarray": {
           "version": "0.0.1",
           "from": "isarray@0.0.1",
           "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
         },
+        "isstream": {
+          "version": "0.1.2",
+          "from": "isstream@~0.1.2",
+          "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
+        },
         "json-stringify-safe": {
           "version": "5.0.1",
           "from": "json-stringify-safe@~5.0.1",
@@ -2140,51 +2142,51 @@
           "from": "jsonpointer@2.0.0",
           "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
         },
+        "lodash._basetostring": {
+          "version": "3.0.1",
+          "from": "lodash._basetostring@^3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz"
+        },
         "lodash._createpadding": {
           "version": "3.6.1",
           "from": "lodash._createpadding@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash._createpadding/-/lodash._createpadding-3.6.1.tgz"
         },
+        "lodash.pad": {
+          "version": "3.1.1",
+          "from": "lodash.pad@^3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-3.1.1.tgz"
+        },
         "lodash.padleft": {
           "version": "3.1.1",
           "from": "lodash.padleft@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash.padleft/-/lodash.padleft-3.1.1.tgz"
         },
-        "lodash._basetostring": {
-          "version": "3.0.1",
-          "from": "lodash._basetostring@^3.0.0",
-          "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz"
-        },
-        "lodash.pad": {
+        "lodash.padright": {
           "version": "3.1.1",
-          "from": "lodash.pad@^3.0.0",
-          "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-3.1.1.tgz"
+          "from": "lodash.padright@^3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash.padright/-/lodash.padright-3.1.1.tgz"
         },
         "lodash.repeat": {
           "version": "3.0.1",
           "from": "lodash.repeat@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash.repeat/-/lodash.repeat-3.0.1.tgz"
         },
-        "lodash.padright": {
-          "version": "3.1.1",
-          "from": "lodash.padright@^3.0.0",
-          "resolved": "https://registry.npmjs.org/lodash.padright/-/lodash.padright-3.1.1.tgz"
-        },
         "mime-db": {
           "version": "1.19.0",
           "from": "mime-db@~1.19.0",
           "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.19.0.tgz"
         },
-        "minimist": {
-          "version": "0.0.8",
-          "from": "minimist@0.0.8",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
-        },
         "mime-types": {
           "version": "2.1.7",
           "from": "mime-types@~2.1.7",
           "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.7.tgz"
         },
+        "minimist": {
+          "version": "0.0.8",
+          "from": "minimist@0.0.8",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
+        },
         "mkdirp": {
           "version": "0.5.1",
           "from": "mkdirp@>=0.3.0 <0.4.0||>=0.4.0 <0.5.0||>=0.5.0 <0.6.0",
@@ -2200,6 +2202,11 @@
           "from": "npmlog@~1.2.0",
           "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz"
         },
+        "oauth-sign": {
+          "version": "0.8.0",
+          "from": "oauth-sign@~0.8.0",
+          "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.0.tgz"
+        },
         "once": {
           "version": "1.1.1",
           "from": "once@~1.1.1",
@@ -2210,11 +2217,6 @@
           "from": "path-is-absolute@>=1.0.0 <2.0.0",
           "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz"
         },
-        "oauth-sign": {
-          "version": "0.8.0",
-          "from": "oauth-sign@~0.8.0",
-          "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.0.tgz"
-        },
         "pinkie": {
           "version": "1.0.0",
           "from": "pinkie@^1.0.0",
@@ -2265,6 +2267,11 @@
           "from": "strip-ansi@^3.0.0",
           "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz"
         },
+        "strip-json-comments": {
+          "version": "0.1.3",
+          "from": "strip-json-comments@0.1.x",
+          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
+        },
         "supports-color": {
           "version": "2.0.0",
           "from": "supports-color@^2.0.0",
@@ -2280,21 +2287,16 @@
           "from": "tough-cookie@~2.2.0",
           "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.0.tgz"
         },
-        "strip-json-comments": {
-          "version": "0.1.3",
-          "from": "strip-json-comments@0.1.x",
-          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
+        "tunnel-agent": {
+          "version": "0.4.1",
+          "from": "tunnel-agent@~0.4.1",
+          "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz"
         },
         "uid-number": {
           "version": "0.0.3",
           "from": "uid-number@0.0.3",
           "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.3.tgz"
         },
-        "tunnel-agent": {
-          "version": "0.4.1",
-          "from": "tunnel-agent@~0.4.1",
-          "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz"
-        },
         "wrappy": {
           "version": "1.0.1",
           "from": "wrappy@>=1.0.0 <2.0.0",
@@ -4222,6 +4224,18 @@
               }
             }
           }
+        },
+        "fbjs": {
+          "version": "0.6.0",
+          "from": "https://registry.npmjs.org/fbjs/-/fbjs-0.6.0.tgz",
+          "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.6.0.tgz",
+          "dependencies": {
+            "whatwg-fetch": {
+              "version": "0.9.0",
+              "from": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz",
+              "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz"
+            }
+          }
         }
       }
     },
@@ -4708,6 +4722,11 @@
       "from": "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz",
       "resolved": "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz"
     },
+    "ua-parser-js": {
+      "version": "0.7.10",
+      "from": "ua-parser-js@>=0.7.9 <0.8.0",
+      "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.10.tgz"
+    },
     "uglify-js": {
       "version": "2.4.24",
       "from": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.4.24.tgz",
diff --git a/package.json b/package.json
index 9d6cfa9935e9..4884bdcda808 100644
--- a/package.json
+++ b/package.json
@@ -34,6 +34,7 @@
     },
     "modulePathIgnorePatterns": [
       "/node_modules/(?!react|fbjs|react-native|parse|react-transform-hmr|core-js|promise)/",
+      "node_modules/react/node_modules/fbjs/",
       "node_modules/react/lib/React.js",
       "node_modules/react/lib/ReactDOM.js",
       "node_modules/fbjs/lib/Map.js",
@@ -79,7 +80,8 @@
       "downstream/core/nativeRequestAnimationFrame.js",
       "downstream/core/toArray.js",
       "node_modules/jest-cli",
-      "node_modules/react/dist"
+      "node_modules/react/dist",
+      "/node_modules/fbjs/.*/__mocks__/"
     ],
     "testFileExtensions": [
       "js"
@@ -87,7 +89,8 @@
     "unmockedModulePathPatterns": [
       "promise",
       "source-map",
-      "fast-path"
+      "fast-path",
+      "fbjs"
     ]
   },
   "main": "Libraries/react-native/react-native.js",
@@ -136,7 +139,7 @@
     "debug": "^2.2.0",
     "event-target-shim": "^1.0.5",
     "fast-path": "^1.1.0",
-    "fbjs": "^0.6.0",
+    "fbjs": "^0.7.2",
     "fbjs-scripts": "^0.4.0",
     "graceful-fs": "^4.1.2",
     "image-size": "^0.3.5",
diff --git a/packager/blacklist.js b/packager/blacklist.js
index ee369e1af726..27ec2899300f 100644
--- a/packager/blacklist.js
+++ b/packager/blacklist.js
@@ -17,57 +17,8 @@ var sharedBlacklist = [
   'node_modules/react/lib/React.js',
   'node_modules/react/lib/ReactDOM.js',
 
-  // For each of these fbjs files (especially the non-forks/stubs), we should
-  // consider deleting the conflicting copy and just using the fbjs version.
-  //
   // fbjs forks:
   'node_modules/fbjs/lib/Map.js',
-  'node_modules/fbjs/lib/Promise.js',
-  'node_modules/fbjs/lib/fetch.js',
-  // fbjs stubs:
-  'node_modules/fbjs/lib/ErrorUtils.js',
-  'node_modules/fbjs/lib/URI.js',
-  // fbjs modules:
-  'node_modules/fbjs/lib/Deferred.js',
-  'node_modules/fbjs/lib/PromiseMap.js',
-  'node_modules/fbjs/lib/UserAgent.js',
-  'node_modules/fbjs/lib/areEqual.js',
-  'node_modules/fbjs/lib/base62.js',
-  'node_modules/fbjs/lib/crc32.js',
-  'node_modules/fbjs/lib/everyObject.js',
-  'node_modules/fbjs/lib/fetchWithRetries.js',
-  'node_modules/fbjs/lib/filterObject.js',
-  'node_modules/fbjs/lib/flattenArray.js',
-  'node_modules/fbjs/lib/forEachObject.js',
-  'node_modules/fbjs/lib/isEmpty.js',
-  'node_modules/fbjs/lib/nullthrows.js',
-  'node_modules/fbjs/lib/removeFromArray.js',
-  'node_modules/fbjs/lib/resolveImmediate.js',
-  'node_modules/fbjs/lib/someObject.js',
-  'node_modules/fbjs/lib/sprintf.js',
-  'node_modules/fbjs/lib/xhrSimpleDataSerializer.js',
-
-  // Those conflicts with the ones in fbjs/. We need to blacklist the
-  // internal version otherwise they won't work in open source.
-  'downstream/core/CSSCore.js',
-  'downstream/core/TouchEventUtils.js',
-  'downstream/core/camelize.js',
-  'downstream/core/createArrayFromMixed.js',
-  'downstream/core/createNodesFromMarkup.js',
-  'downstream/core/dom/containsNode.js',
-  'downstream/core/dom/focusNode.js',
-  'downstream/core/dom/getActiveElement.js',
-  'downstream/core/dom/getUnboundedScrollPosition.js',
-  'downstream/core/dom/isNode.js',
-  'downstream/core/dom/isTextNode.js',
-  'downstream/core/emptyFunction.js',
-  'downstream/core/emptyObject.js',
-  'downstream/core/getMarkupWrap.js',
-  'downstream/core/hyphenate.js',
-  'downstream/core/hyphenateStyleName.js',
-  'downstream/core/invariant.js',
-  'downstream/core/nativeRequestAnimationFrame.js',
-  'downstream/core/toArray.js',
 
   /website\/node_modules\/.*/,
 
diff --git a/packager/package.json b/packager/package.json
index 117369a73bf1..cf2306f0ff05 100644
--- a/packager/package.json
+++ b/packager/package.json
@@ -1,5 +1,5 @@
 {
-  "version": "0.1.3",
+  "version": "0.1.4",
   "name": "react-native-packager",
   "description": "Build native apps with React!",
   "repository": {
diff --git a/packager/react-packager/src/Resolver/index.js b/packager/react-packager/src/Resolver/index.js
index 76d8d5af219b..d60e0fb2b4d5 100644
--- a/packager/react-packager/src/Resolver/index.js
+++ b/packager/react-packager/src/Resolver/index.js
@@ -84,7 +84,6 @@ class Resolver {
           (opts.blacklistRE && opts.blacklistRE.test(filepath));
       },
       providesModuleNodeModules: [
-        'fbjs',
         'react',
         'react-native',
         // Parse requires AsyncStorage. They will

From 170f4526f567b40245e75386df5f303085b32ac5 Mon Sep 17 00:00:00 2001
From: Lucas Feliciano <mail@lucasfeliciano.com>
Date: Wed, 2 Mar 2016 04:35:47 -0800
Subject: [PATCH 1374/1411] Fix broken link

Summary:Broken link on docs
Closes https://github.com/facebook/react-native/pull/6173

Differential Revision: D2999841

fb-gh-sync-id: a7162ee94ea24512ad4b992a5820a0fe89eea0ea
shipit-source-id: a7162ee94ea24512ad4b992a5820a0fe89eea0ea
---
 docs/NativeComponentsAndroid.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/NativeComponentsAndroid.md b/docs/NativeComponentsAndroid.md
index ada02d878d46..3c32591c4579 100644
--- a/docs/NativeComponentsAndroid.md
+++ b/docs/NativeComponentsAndroid.md
@@ -86,7 +86,7 @@ Setter declaration requirements for methods annotated with `@ReactPropGroup` are
 
 ## 4. Register the `ViewManager`
 
-The final Java step is to register the ViewManager to the application, this happens in a similar way to [Native Modules](native-modules-android.html), via the applications package member function `createViewManagers.`
+The final Java step is to register the ViewManager to the application, this happens in a similar way to [Native Modules](docs/native-modules-android.html), via the applications package member function `createViewManagers.`
 
 ```java
   @Override

From 4654b34c971a9b30eca902f9ffe893effb40edf4 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Wed, 2 Mar 2016 05:45:50 -0800
Subject: [PATCH 1375/1411] Revert Remove invariant hack for jest

Summary: This reverts D2988899 as it consistently broke the Invariant test on Travis: https://travis-ci.org/facebook/react-native

Reviewed By: bestander

Differential Revision: D2999915

fb-gh-sync-id: 781ab5f6fc8e3b97bc4d215af855823f4b5014dd
shipit-source-id: 781ab5f6fc8e3b97bc4d215af855823f4b5014dd
---
 Libraries/Animated/src/Interpolation.js | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/Libraries/Animated/src/Interpolation.js b/Libraries/Animated/src/Interpolation.js
index c8daa2406d2c..b97d063b949a 100644
--- a/Libraries/Animated/src/Interpolation.js
+++ b/Libraries/Animated/src/Interpolation.js
@@ -12,9 +12,17 @@
 /* eslint no-bitwise: 0 */
 'use strict';
 
-var invariant = require('invariant');
 var normalizeColor = require('normalizeColor');
 
+// TODO(#7644673): fix this hack once github jest actually checks invariants
+var invariant = function(condition, message) {
+  if (!condition) {
+    var error = new Error(message);
+    (error: any).framesToPop = 1; // $FlowIssue
+    throw error;
+  }
+};
+
 type ExtrapolateType = 'extend' | 'identity' | 'clamp';
 
 export type InterpolationConfigType = {

From f827f7b79a1f8a5c575d1e4270da61095b08a5cc Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Wed, 2 Mar 2016 06:55:09 -0800
Subject: [PATCH 1376/1411] instrumentation tests are executed with BUCK

Summary:Added ability to run instrumentation tests with BUCK.

This change uses BUCK to build and run instrumentation tests facebook style.
The gains are that we can execute the same tests internally at FB and in OSS.
Also running tests not via graddle:connect command is 1.5 minutes faster.

I'll keep keep an eye on stability Gradle and BUCK builds for a while.
Closes https://github.com/facebook/react-native/pull/6176

Differential Revision: D2999878

Pulled By: bestander

fb-gh-sync-id: d715ba231769e57100685a1256f2e530c589921c
shipit-source-id: d715ba231769e57100685a1256f2e530c589921c
---
 ReactAndroid/build.gradle                     |  2 +-
 .../src/androidTest/AndroidManifest.xml       |  6 +-
 ReactAndroid/src/androidTest/BUCK_temp        | 66 -------------------
 ReactAndroid/src/androidTest/assets/BUCK      |  5 ++
 .../buck-runner/AndroidManifest.xml           | 24 +++++++
 ReactAndroid/src/androidTest/buck-runner/BUCK | 23 +++++++
 ReactAndroid/src/androidTest/buildBundle.sh   |  4 --
 circle.yml                                    | 24 ++++---
 scripts/run-android-instrumentation-tests.sh  | 52 +++++++++++++++
 9 files changed, 123 insertions(+), 83 deletions(-)
 delete mode 100644 ReactAndroid/src/androidTest/BUCK_temp
 create mode 100644 ReactAndroid/src/androidTest/assets/BUCK
 create mode 100644 ReactAndroid/src/androidTest/buck-runner/AndroidManifest.xml
 create mode 100644 ReactAndroid/src/androidTest/buck-runner/BUCK
 delete mode 100755 ReactAndroid/src/androidTest/buildBundle.sh
 create mode 100755 scripts/run-android-instrumentation-tests.sh

diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle
index e6fc06a58c3d..8f26d7997656 100644
--- a/ReactAndroid/build.gradle
+++ b/ReactAndroid/build.gradle
@@ -224,7 +224,7 @@ android {
         }
 
         buildConfigField 'boolean', 'IS_INTERNAL_BUILD', 'false'
-        testApplicationId "com.facebook.react.tests"
+        testApplicationId "com.facebook.react.tests.gradle"
         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
     }
 
diff --git a/ReactAndroid/src/androidTest/AndroidManifest.xml b/ReactAndroid/src/androidTest/AndroidManifest.xml
index 4275a7ea6856..f23091978dfa 100644
--- a/ReactAndroid/src/androidTest/AndroidManifest.xml
+++ b/ReactAndroid/src/androidTest/AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.facebook.react.tests"
+          package="com.facebook.react.tests.gradle"
           android:versionCode="1"
           android:versionName="1.0" >
   <uses-sdk android:targetSdkVersion="7" />
@@ -12,8 +12,8 @@
 
   <application>
     <activity
-            android:name="com.facebook.react.testing.ReactAppTestActivity"
-            android:theme="@style/Theme.ReactNative.AppCompat.Light.NoActionBar.FullScreen"
+      android:name="com.facebook.react.testing.ReactAppTestActivity"
+      android:theme="@style/Theme.ReactNative.AppCompat.Light.NoActionBar.FullScreen"
     />
   </application>
 </manifest>
diff --git a/ReactAndroid/src/androidTest/BUCK_temp b/ReactAndroid/src/androidTest/BUCK_temp
deleted file mode 100644
index d33209cedb57..000000000000
--- a/ReactAndroid/src/androidTest/BUCK_temp
+++ /dev/null
@@ -1,66 +0,0 @@
-include_defs('//ReactAndroid/DEFS')
-
-
-CATALYST_PRIMERY_DEX_PATTERNS =  [
-  '/CatalystAppShell^',
-  '/CatalystApplicationImpl^',
-  '^com/facebook/buck/android/support/exopackage/',
-  '/FbInstrumentationTestRunner^',
-  '/PrimaryDexFactories^',
-  '/Screenshot^',
-  '/DexmakerMockMaker^',
-  '/AndroidJUnitRunner^',
-  '/InstrumentationRunListener^',
-  '/ExposedInstrumentationApi^',
-  '/TestApplication^',
-  '/ApplicationWithInjector^',
-  '/RunListener^',
-]
-
-JS_BUNDLE_DEPS = [
-  #':intern-schema',
-#   '//java/com/facebook/graphql:schema',
-#   '//java/com/facebook/graphql/graphql-data:locate_node'
-]
-
-
-# instrumentation tests that will run for tests located in GitHub open sourced folder
-android_binary (
-  name = 'react_oss',
-  manifest = 'AndroidManifest.xml',
-  keystore = '//keystores:debug',
-  use_split_dex = True,
-  linear_alloc_hard_limit = 10 * 1024 * 1024,
-  primary_dex_patterns = CATALYST_PRIMERY_DEX_PATTERNS,
-  deps = [
-#     ':integration_test_oss_bundle_js',
-    react_native_integration_tests_target('java/com/facebook/react/tests:tests'),
-  #     '//java/com/facebook/catalyst/js/react-native-github/ReactAndroid/src/main/res:shell',
-  ],
-)
-
-# Building this rule will produce a file named messenger_test.apk
-android_instrumentation_apk(
-  name = 'react_oss_test_apk',
-  manifest = 'AndroidManifest.xml',
-  apk = ':react_oss',
-  deps = [
-#     react_native_integration_tests_target('java/com/facebook/react/tests:tests'),
-    #     react_native_integration_tests_target('java/com/facebook/react/tests:tests'),
-    #     '//java/com/facebook/catalyst:integration_test_oss_bundle_js#dev',
-  ],
-)
-
-
-
-android_instrumentation_test(
-  name = 'react_oss_test',
-  apk = ':react_oss_test_apk',
-)
-
-sh_binary(
-  name = 'integration_test_oss_bundle_js',
-  main = 'buildBundle.sh',
-#     deps = [':InstallReactNativeNodeModules'],
-  visibility = ['PUBLIC'],
-)
diff --git a/ReactAndroid/src/androidTest/assets/BUCK b/ReactAndroid/src/androidTest/assets/BUCK
new file mode 100644
index 000000000000..4648c5ef94f5
--- /dev/null
+++ b/ReactAndroid/src/androidTest/assets/BUCK
@@ -0,0 +1,5 @@
+android_resource(
+  name = 'assets',
+  assets = '.',
+  visibility = ['PUBLIC'],
+)
diff --git a/ReactAndroid/src/androidTest/buck-runner/AndroidManifest.xml b/ReactAndroid/src/androidTest/buck-runner/AndroidManifest.xml
new file mode 100644
index 000000000000..8220d4fb478c
--- /dev/null
+++ b/ReactAndroid/src/androidTest/buck-runner/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.facebook.react.tests">
+
+  <supports-screens android:anyDensity="true" />
+  <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+  <!-- needed for screenshot tests -->
+  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+  <application>
+    <uses-library android:name="android.test.runner" />
+    <activity
+      android:name="com.facebook.react.testing.ReactAppTestActivity"
+      android:theme="@style/Theme.ReactNative.AppCompat.Light.NoActionBar.FullScreen">
+    </activity>
+  </application>
+
+  <instrumentation
+    android:name="android.support.test.runner.AndroidJUnitRunner"
+    android:targetPackage="com.facebook.react.tests"
+    android:label="Buck runs instrumentation tests"/>
+
+</manifest>
diff --git a/ReactAndroid/src/androidTest/buck-runner/BUCK b/ReactAndroid/src/androidTest/buck-runner/BUCK
new file mode 100644
index 000000000000..337e846c1e05
--- /dev/null
+++ b/ReactAndroid/src/androidTest/buck-runner/BUCK
@@ -0,0 +1,23 @@
+include_defs('//ReactAndroid/DEFS')
+
+# We are running instrumentation tests in simple mode: app code and instrumentation are in the same APK
+# Currently you need to run these commands to execute tests:
+#
+# node local-cli/cli.js bundle --platform android --dev true --entry-file ReactAndroid/src/androidTest/assets/TestBundle.js --bundle-output ReactAndroid/src/androidTest/assets/AndroidTestBundle.js
+# gradle :ReactAndroid:packageReactNdkLibsForBuck
+# buck install ReactAndroid/src/androidTest/buck-runner:instrumentation-tests
+# ./scripts/run-android-instrumentation-tests.sh com.facebook.react.tests
+android_binary(
+  name = 'instrumentation-tests',
+  manifest = 'AndroidManifest.xml',
+  keystore = '//keystores:debug',
+  deps = [
+    react_native_integration_tests_target('java/com/facebook/react/tests:tests'),
+    react_native_integration_tests_target('assets:assets'),
+    react_native_target('jni/prebuilt:reactnative-libs'),
+    react_native_target('jni/prebuilt:android-jsc'),
+    react_native_dep('libraries/soloader/java/com/facebook/soloader:soloader'),
+    react_native_target('java/com/facebook/react/devsupport:devsupport'),
+  ],
+)
+
diff --git a/ReactAndroid/src/androidTest/buildBundle.sh b/ReactAndroid/src/androidTest/buildBundle.sh
deleted file mode 100755
index 6a61faa90ed2..000000000000
--- a/ReactAndroid/src/androidTest/buildBundle.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/bash
-
-# TODO put output to temp folder?
-node ./local-cli/cli.js bundle --entry-file ReactAndroid/src/androidTest/assets/TestBundle.js --dev --platform android --bundle-output ReactAndroid/src/androidTest/assets/ReactAndroidTestBundle.js
diff --git a/circle.yml b/circle.yml
index 7500233d0cef..f16f69e1ed5a 100644
--- a/circle.yml
+++ b/circle.yml
@@ -38,25 +38,29 @@ test:
     # starting emulator in advance because it takes very long to boot
     - $ANDROID_HOME/tools/emulator -avd testAVD -no-skin -no-audio -no-window:
             background: true
-    # assemble done separately because it requires quite a lot of memory and also gives time for emulator to load
-    - ./gradlew :ReactAndroid:assembleDebug -PdisablePreDex -Pjobs=1:
-            timeout: 360
     - source scripts/circle-ci-android-setup.sh && waitForAVD
 
   override:
-    # buck tests
-    - buck/bin/buck test ReactAndroid/src/test/... --config build.threads=1
+    # build app
     - buck/bin/buck build ReactAndroid/src/main/java/com/facebook/react
     - buck/bin/buck build ReactAndroid/src/main/java/com/facebook/react/shell
-    # temp, we can't run instrumentation tests yet
-    - buck/bin/buck build ReactAndroid/src/androidTest/java/com/facebook/react/tests
 
     # unit tests
-    - ./gradlew :ReactAndroid:testDebugUnitTest -PdisablePreDex
+    - buck/bin/buck test ReactAndroid/src/test/... --config build.threads=1
 
+    # instrumentation tests
+    # compile native libs with Gradle script
+    - ./gradlew :ReactAndroid:packageReactNdkLibsForBuck -PdisablePreDex -Pjobs=1:
+        timeout: 360
     # build JS bundle for instrumentation tests
     - node local-cli/cli.js bundle --platform android --dev true --entry-file ReactAndroid/src/androidTest/assets/TestBundle.js --bundle-output ReactAndroid/src/androidTest/assets/AndroidTestBundle.js
-    # run tests on the emulator
+    # build test APK
+    - buck/bin/buck install ReactAndroid/src/androidTest/buck-runner:instrumentation-tests --config build.threads=1
+    # run installed apk with tests
+    - ./scripts/run-android-instrumentation-tests.sh com.facebook.react.tests
+
+    # Deprecated: run tests with Gradle, we keep them for a while to compare performance
+    - ./gradlew :ReactAndroid:testDebugUnitTest -PdisablePreDex
     - ./gradlew :ReactAndroid:connectedAndroidTest -PdisablePreDex --stacktrace --info:
         timeout: 360
 
@@ -67,6 +71,8 @@ test:
     - mkdir -p $CIRCLE_TEST_REPORTS/junit/
     - find . -type f -regex ".*/build/test-results/debug/.*xml" -exec cp {} $CIRCLE_TEST_REPORTS/junit/ \;
     - find . -type f -regex ".*/outputs/androidTest-results/connected/.*xml" -exec cp {} $CIRCLE_TEST_REPORTS/junit/ \;
+    # TODO circle does not understand Buck's report, maybe need to transform xml slightly
+    #- find . -type f -regex ".*/buck-out/gen/ReactAndroid/src/test/.*/.*xml" -exec cp {} $CIRCLE_TEST_REPORTS/junit/ \;
 
 deployment:
   website:
diff --git a/scripts/run-android-instrumentation-tests.sh b/scripts/run-android-instrumentation-tests.sh
new file mode 100755
index 000000000000..fb2960847ac7
--- /dev/null
+++ b/scripts/run-android-instrumentation-tests.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+export PATH="$ANDROID_HOME/platform-tools:$ANDROID_HOME/tools:$PATH"
+
+# clear the logs
+adb logcat -c
+
+# run tests and check output
+python - $1 << END
+import re
+import subprocess as sp
+import sys
+import threading
+import time
+
+done = False
+test_app = sys.argv[1]
+
+def update():
+  # prevent CircleCI from killing the process for inactivity
+  while not done:
+    time.sleep(5)
+    print "Running in background.  Waiting for 'adb' command reponse..."
+
+t = threading.Thread(target=update)
+t.dameon = True
+t.start()
+
+def run():
+  sp.Popen(['adb', 'wait-for-device']).communicate()
+  p = sp.Popen('adb shell am instrument -w %s/android.support.test.runner.AndroidJUnitRunner' % test_app,
+               shell=True, stdout=sp.PIPE, stderr=sp.PIPE, stdin=sp.PIPE)
+  return p.communicate()
+
+success = re.compile(r'OK \(\d+ tests\)')
+stdout, stderr = run()
+
+done = True
+print stderr
+print stdout
+
+if success.search(stderr + stdout):
+  sys.exit(0)
+else:
+  # dump the logs
+  sp.Popen(['adb', 'logcat', '-d']).communicate()
+  sys.exit(1) # make sure we fail if the test failed
+END
+
+RETVAL=$?
+
+exit $RETVAL

From ab12189f87d8e7fd84a4f1b92fa97e8894e984c7 Mon Sep 17 00:00:00 2001
From: AbilashK <abikspnr@gmail.com>
Date: Wed, 2 Mar 2016 07:06:37 -0800
Subject: [PATCH 1377/1411] Enable blurOnSubmit for text input in android

Summary:PR for https://github.com/facebook/react-native/issues/6098, Added tests to UIExplorer based on existing iOS example.

Before:
![blur_true](https://cloud.githubusercontent.com/assets/11550281/13401854/cd66117a-df33-11e5-875d-e1f132e2fc82.gif)

After:
![blur_false](https://cloud.githubusercontent.com/assets/11550281/13401874/de1dd1ce-df33-11e5-8210-e6bee80240fb.gif)
Closes https://github.com/facebook/react-native/pull/6215

Differential Revision: D3000042

Pulled By: mkonicek

fb-gh-sync-id: 7f01270580b198498505d92e38a456c0b3a01488
shipit-source-id: 7f01270580b198498505d92e38a456c0b3a01488
---
 .../UIExplorer/TextInputExample.android.js    | 58 +++++++++++++++++++
 Libraries/Components/TextInput/TextInput.js   |  2 +-
 .../react/views/textinput/ReactEditText.java  | 10 ++++
 .../textinput/ReactTextInputManager.java      |  7 ++-
 4 files changed, 75 insertions(+), 2 deletions(-)

diff --git a/Examples/UIExplorer/TextInputExample.android.js b/Examples/UIExplorer/TextInputExample.android.js
index 3652b974c8fc..1a436a91236d 100644
--- a/Examples/UIExplorer/TextInputExample.android.js
+++ b/Examples/UIExplorer/TextInputExample.android.js
@@ -178,6 +178,60 @@ class TokenizedTextExample extends React.Component {
   }
 }
 
+var BlurOnSubmitExample = React.createClass({
+  focusNextField(nextField) {
+    this.refs[nextField].focus();
+  },
+
+  render: function() {
+    return (
+      <View>
+        <TextInput
+          ref="1"
+          style={styles.singleLine}
+          placeholder="blurOnSubmit = false"
+          returnKeyType="next"
+          blurOnSubmit={false}
+          onSubmitEditing={() => this.focusNextField('2')}
+        />
+        <TextInput
+          ref="2"
+          style={styles.singleLine}
+          keyboardType="email-address"
+          placeholder="blurOnSubmit = false"
+          returnKeyType="next"
+          blurOnSubmit={false}
+          onSubmitEditing={() => this.focusNextField('3')}
+        />
+        <TextInput
+          ref="3"
+          style={styles.singleLine}
+          keyboardType="url"
+          placeholder="blurOnSubmit = false"
+          returnKeyType="next"
+          blurOnSubmit={false}
+          onSubmitEditing={() => this.focusNextField('4')}
+        />
+        <TextInput
+          ref="4"
+          style={styles.singleLine}
+          keyboardType="numeric"
+          placeholder="blurOnSubmit = false"
+          blurOnSubmit={false}
+          onSubmitEditing={() => this.focusNextField('5')}
+        />
+        <TextInput
+          ref="5"
+          style={styles.singleLine}
+          keyboardType="numbers-and-punctuation"
+          placeholder="blurOnSubmit = true"
+          returnKeyType="done"
+        />
+      </View>
+    );
+  }
+});
+
 var styles = StyleSheet.create({
   multiline: {
     height: 60,
@@ -286,6 +340,10 @@ exports.examples = [
       return <View>{examples}</View>;
     }
   },
+  {
+    title: 'Blur on submit',
+    render: function(): ReactElement { return <BlurOnSubmitExample />; },
+  },
   {
     title: 'Event handling',
     render: function(): ReactElement { return <TextEventsExample />; },
diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js
index b2080a61f572..2243ee4b454c 100644
--- a/Libraries/Components/TextInput/TextInput.js
+++ b/Libraries/Components/TextInput/TextInput.js
@@ -283,7 +283,6 @@ var TextInput = React.createClass({
      * multiline fields. Note that for multiline fields, setting blurOnSubmit
      * to true means that pressing return will blur the field and trigger the
      * onSubmitEditing event instead of inserting a newline into the field.
-     * @platform ios
      */
     blurOnSubmit: PropTypes.bool,
     /**
@@ -505,6 +504,7 @@ var TextInput = React.createClass({
         onTextInput={this._onTextInput}
         onEndEditing={this.props.onEndEditing}
         onSubmitEditing={this.props.onSubmitEditing}
+        blurOnSubmit={this.props.blurOnSubmit}
         onLayout={this.props.onLayout}
         password={this.props.password || this.props.secureTextEntry}
         placeholder={this.props.placeholder}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
index 58e3e5a560a0..14752e1589fc 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
@@ -67,6 +67,7 @@ public class ReactEditText extends EditText {
   private @Nullable TextWatcherDelegator mTextWatcherDelegator;
   private int mStagedInputType;
   private boolean mContainsImages;
+  private boolean mBlurOnSubmit;
   private @Nullable SelectionWatcher mSelectionWatcher;
   private final InternalKeyListener mKeyListener;
 
@@ -84,6 +85,7 @@ public ReactEditText(Context context) {
     mNativeEventCount = 0;
     mIsSettingTextFromJS = false;
     mIsJSSettingFocus = false;
+    mBlurOnSubmit = true;
     mListeners = null;
     mTextWatcherDelegator = null;
     mStagedInputType = getInputType();
@@ -179,6 +181,14 @@ public void setSelectionWatcher(SelectionWatcher selectionWatcher) {
     mSelectionWatcher = selectionWatcher;
   }
 
+  public void setBlurOnSubmit(boolean blurOnSubmit) {
+    mBlurOnSubmit = blurOnSubmit;
+  }
+
+  public boolean getBlurOnSubmit() {
+    return mBlurOnSubmit;
+  }
+
   /*protected*/ int getStagedInputType() {
     return mStagedInputType;
   }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
index 2ac07ddc66e2..8376c2d6bfdb 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
@@ -181,6 +181,11 @@ public void setOnSelectionChange(final ReactEditText view, boolean onSelectionCh
     }
   }
 
+  @ReactProp(name = "blurOnSubmit", defaultBoolean = true)
+  public void setBlurOnSubmit(ReactEditText view, boolean blurOnSubmit) {
+    view.setBlurOnSubmit(blurOnSubmit);
+  }
+
   @ReactProp(name = "placeholder")
   public void setPlaceholder(ReactEditText view, @Nullable String placeholder) {
     view.setHint(placeholder);
@@ -493,7 +498,7 @@ public boolean onEditorAction(TextView v, int actionId, KeyEvent keyEvent) {
                       SystemClock.nanoTime(),
                       editText.getText().toString()));
             }
-            return false;
+            return !editText.getBlurOnSubmit();
           }
         });
   }

From d3f2081d9091179ed0ac6511c6c660947b950e45 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Wed, 2 Mar 2016 07:06:50 -0800
Subject: [PATCH 1378/1411] Fix unit tests in open source environment

Summary:**Test plan**

run `npm test`, see all tests pass
Closes https://github.com/facebook/react-native/pull/6243

Differential Revision: D2999993

Pulled By: davidaurelio

fb-gh-sync-id: 54f2d5f9d28a31d132783694133df78370660421
shipit-source-id: 54f2d5f9d28a31d132783694133df78370660421
---
 Libraries/Animated/src/Interpolation.js | 10 +---------
 Libraries/vendor/core/Map.js            |  2 +-
 2 files changed, 2 insertions(+), 10 deletions(-)

diff --git a/Libraries/Animated/src/Interpolation.js b/Libraries/Animated/src/Interpolation.js
index b97d063b949a..50f77ed7102d 100644
--- a/Libraries/Animated/src/Interpolation.js
+++ b/Libraries/Animated/src/Interpolation.js
@@ -12,17 +12,9 @@
 /* eslint no-bitwise: 0 */
 'use strict';
 
+var invariant = require('fbjs/lib/invariant');
 var normalizeColor = require('normalizeColor');
 
-// TODO(#7644673): fix this hack once github jest actually checks invariants
-var invariant = function(condition, message) {
-  if (!condition) {
-    var error = new Error(message);
-    (error: any).framesToPop = 1; // $FlowIssue
-    throw error;
-  }
-};
-
 type ExtrapolateType = 'extend' | 'identity' | 'clamp';
 
 export type InterpolationConfigType = {
diff --git a/Libraries/vendor/core/Map.js b/Libraries/vendor/core/Map.js
index 114add77b308..b3153b39df1f 100644
--- a/Libraries/vendor/core/Map.js
+++ b/Libraries/vendor/core/Map.js
@@ -19,7 +19,7 @@
  */
 
 var guid = require('guid');
-var isNode = require('isNode');
+var isNode = require('fbjs/lib/isNode');
 var toIterator = require('toIterator');
 var _shouldPolyfillES6Collection = require('_shouldPolyfillES6Collection');
 

From 5df3eeb7230bebef3abc916fa8f4047c90825588 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C5=82=20Gregorczyk?= <michalgr@fb.com>
Date: Wed, 2 Mar 2016 07:23:47 -0800
Subject: [PATCH 1379/1411] Force 16 byte stack alignment on JNI method
 invocations on x86

Reviewed By: dcolascione

Differential Revision: D2989293

fb-gh-sync-id: 9140ced55ef0b8a73fdc03a6d307af87cd2335ef
shipit-source-id: 9140ced55ef0b8a73fdc03a6d307af87cd2335ef
---
 ReactAndroid/src/main/jni/react/AlignStack.h | 15 -----
 ReactAndroid/src/main/jni/react/BUCK         |  1 -
 ReactAndroid/src/main/jni/react/JSCHelpers.h | 10 +--
 ReactAndroid/src/main/jni/react/Value.h      | 68 ++++++++++----------
 4 files changed, 36 insertions(+), 58 deletions(-)
 delete mode 100644 ReactAndroid/src/main/jni/react/AlignStack.h

diff --git a/ReactAndroid/src/main/jni/react/AlignStack.h b/ReactAndroid/src/main/jni/react/AlignStack.h
deleted file mode 100644
index 9919a4fefda5..000000000000
--- a/ReactAndroid/src/main/jni/react/AlignStack.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2004-present Facebook. All Rights Reserved.
-
-#pragma once
-
-#ifdef __i386__
-// The Android x86 ABI states that the NDK toolchain assumes 16 byte stack
-// alignment: http://developer.android.com/ndk/guides/x86.html JSC checks for
-// stack alignment, and fails with SIGTRAP if it is not.  Empirically, the
-// google android x86 emulator does not provide this alignment, and so JSC
-// calls may crash.  All checked calls go through here, so the attribute here
-// is added to force alignment and prevent crashes.
-#define ALIGN_STACK __attribute__((force_align_arg_pointer))
-#else
-#define ALIGN_STACK
-#endif
diff --git a/ReactAndroid/src/main/jni/react/BUCK b/ReactAndroid/src/main/jni/react/BUCK
index 4c9a9d66bf5f..292463593df2 100644
--- a/ReactAndroid/src/main/jni/react/BUCK
+++ b/ReactAndroid/src/main/jni/react/BUCK
@@ -65,7 +65,6 @@ react_library(
     'JSCMemory.h',
   ],
   exported_headers = [
-    'AlignStack.h',
     'Bridge.h',
     'ExecutorToken.h',
     'ExecutorTokenFactory.h',
diff --git a/ReactAndroid/src/main/jni/react/JSCHelpers.h b/ReactAndroid/src/main/jni/react/JSCHelpers.h
index 12a5af9a7377..9b61a566b970 100644
--- a/ReactAndroid/src/main/jni/react/JSCHelpers.h
+++ b/ReactAndroid/src/main/jni/react/JSCHelpers.h
@@ -9,8 +9,6 @@
 #include <stdexcept>
 #include <algorithm>
 
-#include "AlignStack.h"
-
 namespace facebook {
 namespace react {
 
@@ -18,13 +16,11 @@ struct JsException : std::runtime_error {
   using std::runtime_error::runtime_error;
 };
 
-ALIGN_STACK
 inline void throwJSExecutionException(const char* msg) {
   throw JsException(msg);
 }
 
 template <typename... Args>
-ALIGN_STACK
 inline void throwJSExecutionException(const char* fmt, Args... args) {
   int msgSize = snprintf(nullptr, 0, fmt, args...);
   msgSize = std::min(512, msgSize + 1);
@@ -36,16 +32,16 @@ inline void throwJSExecutionException(const char* fmt, Args... args) {
 void installGlobalFunction(
     JSGlobalContextRef ctx,
     const char* name,
-    JSObjectCallAsFunctionCallback callback) ALIGN_STACK;
+    JSObjectCallAsFunctionCallback callback);
 
 JSValueRef makeJSCException(
     JSContextRef ctx,
-    const char* exception_text) ALIGN_STACK;
+    const char* exception_text);
 
 JSValueRef evaluateScript(
     JSContextRef ctx,
     JSStringRef script,
     JSStringRef sourceURL,
-    const char* cachePath = nullptr) ALIGN_STACK;
+    const char* cachePath = nullptr);
 
 } }
diff --git a/ReactAndroid/src/main/jni/react/Value.h b/ReactAndroid/src/main/jni/react/Value.h
index 279ecb7dc1dc..5fcb89e3812f 100644
--- a/ReactAndroid/src/main/jni/react/Value.h
+++ b/ReactAndroid/src/main/jni/react/Value.h
@@ -14,8 +14,6 @@
 
 #include "noncopyable.h"
 
-#include "AlignStack.h"
-
 #if WITH_FBJSCEXTENSIONS
 #include <jsc_stringref.h>
 #endif
@@ -28,15 +26,15 @@ class Context;
 
 class String : public noncopyable {
 public:
-  explicit String(const char* utf8) ALIGN_STACK :
+  explicit String(const char* utf8) :
     m_string(Adopt, JSStringCreateWithUTF8CString(utf8))
   {}
 
-  String(String&& other) ALIGN_STACK :
+  String(String&& other) :
     m_string(Adopt, other.m_string.leakRef())
   {}
 
-  String(const String& other) ALIGN_STACK :
+  String(const String& other) :
     m_string(other.m_string)
   {}
 
@@ -45,16 +43,16 @@ class String : public noncopyable {
   }
 
   // Length in characters
-  size_t length() const ALIGN_STACK {
+  size_t length() const {
     return JSStringGetLength(m_string.get());
   }
 
   // Length in bytes of a null-terminated utf8 encoded value
-  size_t utf8Size() const ALIGN_STACK {
+  size_t utf8Size() const {
     return JSStringGetMaximumUTF8CStringSize(m_string.get());
   }
 
-  std::string str() const ALIGN_STACK {
+  std::string str() const {
     size_t reserved = utf8Size();
     char* bytes = new char[reserved];
     size_t length = JSStringGetUTF8CString(m_string.get(), bytes, reserved) - 1;
@@ -63,11 +61,11 @@ class String : public noncopyable {
   }
 
   // Assumes that utf8 is null terminated
-  bool equals(const char* utf8) ALIGN_STACK {
+  bool equals(const char* utf8) {
     return JSStringIsEqualToUTF8CString(m_string.get(), utf8);
   }
 
-  static String createExpectingAscii(std::string const &utf8) ALIGN_STACK {
+  static String createExpectingAscii(std::string const &utf8) {
   #if WITH_FBJSCEXTENSIONS
     return String(Adopt, JSStringCreateWithUTF8CStringExpectAscii(utf8.c_str(), utf8.size()));
   #else
@@ -84,11 +82,11 @@ class String : public noncopyable {
   }
 
 private:
-  explicit String(JSStringRef string) ALIGN_STACK :
+  explicit String(JSStringRef string) :
     m_string(string)
   {}
 
-  String(AdoptTag tag, JSStringRef string) ALIGN_STACK :
+  String(AdoptTag tag, JSStringRef string) :
     m_string(tag, string)
   {}
 
@@ -110,7 +108,7 @@ class Object : public noncopyable {
     other.m_isProtected = false;
   }
 
-  ~Object() ALIGN_STACK {
+  ~Object() {
     if (m_isProtected && m_obj) {
       JSValueUnprotect(m_context, m_obj);
     }
@@ -122,28 +120,28 @@ class Object : public noncopyable {
 
   operator Value() const;
 
-  bool isFunction() const ALIGN_STACK {
+  bool isFunction() const {
     return JSObjectIsFunction(m_context, m_obj);
   }
 
-  Value callAsFunction(int nArgs, JSValueRef args[]) ALIGN_STACK;
+  Value callAsFunction(int nArgs, JSValueRef args[]);
 
-  Value getProperty(const String& propName) const ALIGN_STACK;
+  Value getProperty(const String& propName) const;
   Value getProperty(const char *propName) const;
-  Value getPropertyAtIndex(unsigned index) const ALIGN_STACK;
-  void setProperty(const String& propName, const Value& value) const ALIGN_STACK;
+  Value getPropertyAtIndex(unsigned index) const;
+  void setProperty(const String& propName, const Value& value) const;
   void setProperty(const char *propName, const Value& value) const;
-  std::vector<std::string> getPropertyNames() const ALIGN_STACK;
-  std::unordered_map<std::string, std::string> toJSONMap() const ALIGN_STACK;
+  std::vector<std::string> getPropertyNames() const;
+  std::unordered_map<std::string, std::string> toJSONMap() const;
 
-  void makeProtected() ALIGN_STACK {
+  void makeProtected() {
     if (!m_isProtected && m_obj) {
       JSValueProtect(m_context, m_obj);
       m_isProtected = true;
     }
   }
 
-  static Object getGlobalObject(JSContextRef ctx) ALIGN_STACK {
+  static Object getGlobalObject(JSContextRef ctx) {
     auto globalObj = JSContextGetGlobalObject(ctx);
     return Object(ctx, globalObj);
   }
@@ -151,7 +149,7 @@ class Object : public noncopyable {
   /**
    * Creates an instance of the default object class.
    */
-  static Object create(JSContextRef ctx) ALIGN_STACK;
+  static Object create(JSContextRef ctx);
 
 private:
   JSContextRef m_context;
@@ -168,27 +166,27 @@ class Value : public noncopyable {
     return m_value;
   }
 
-  bool isBoolean() const ALIGN_STACK {
+  bool isBoolean() const {
     return JSValueIsBoolean(context(), m_value);
   }
 
-  bool asBoolean() const ALIGN_STACK {
+  bool asBoolean() const {
     return JSValueToBoolean(context(), m_value);
   }
 
-  bool isNumber() const ALIGN_STACK {
+  bool isNumber() const {
     return JSValueIsNumber(context(), m_value);
   }
 
-  bool isNull() const ALIGN_STACK {
+  bool isNull() const {
     return JSValueIsNull(context(), m_value);
   }
 
-  bool isUndefined() const ALIGN_STACK {
+  bool isUndefined() const {
     return JSValueIsUndefined(context(), m_value);
   }
 
-  double asNumber() const ALIGN_STACK {
+  double asNumber() const {
     if (isNumber()) {
       return JSValueToNumber(context(), m_value, nullptr);
     } else {
@@ -204,22 +202,22 @@ class Value : public noncopyable {
     return static_cast<uint32_t>(asNumber());
   }
 
-  bool isObject() const ALIGN_STACK {
+  bool isObject() const {
     return JSValueIsObject(context(), m_value);
   }
 
-  Object asObject() ALIGN_STACK;
+  Object asObject();
 
-  bool isString() const ALIGN_STACK {
+  bool isString() const {
     return JSValueIsString(context(), m_value);
   }
 
-  String toString() ALIGN_STACK {
+  String toString() {
     return String::adopt(JSValueToStringCopy(context(), m_value, nullptr));
   }
 
-  std::string toJSONString(unsigned indent = 0) const ALIGN_STACK;
-  static Value fromJSON(JSContextRef ctx, const String& json) ALIGN_STACK;
+  std::string toJSONString(unsigned indent = 0) const;
+  static Value fromJSON(JSContextRef ctx, const String& json);
 protected:
   JSContextRef context() const;
   JSContextRef m_context;

From 5a6a94b05a109a431640972726ced86e516d390f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C5=82=20Gregorczyk?= <michalgr@fb.com>
Date: Wed, 2 Mar 2016 07:23:48 -0800
Subject: [PATCH 1380/1411] sync fbjni

Differential Revision: D2990551

fb-gh-sync-id: 587f2b5cd09295dc1829926c12e38f2880440a5e
shipit-source-id: 587f2b5cd09295dc1829926c12e38f2880440a5e
---
 .../java/com/facebook/jni/CppException.java   |   2 +-
 .../facebook/jni/CppSystemErrorException.java |   2 +-
 .../com/facebook/jni/UnknownCppException.java |   2 +-
 .../src/main/jni/first-party/jni/Android.mk   |   1 +
 .../src/main/jni/first-party/jni/BUCK         |   1 +
 .../main/jni/first-party/jni/Countable.cpp    |   2 +-
 .../main/jni/first-party/jni/LocalReference.h |   2 +-
 .../main/jni/first-party/jni/LocalString.cpp  |  80 ++-
 .../main/jni/first-party/jni/LocalString.h    |  29 +
 .../src/main/jni/first-party/jni/fbjni.cpp    | 187 +++----
 .../src/main/jni/first-party/jni/fbjni.h      |   1 +
 .../jni/first-party/jni/fbjni/ByteBuffer.cpp  |  76 +++
 .../jni/first-party/jni/fbjni/ByteBuffer.h    |  32 ++
 .../main/jni/first-party/jni/fbjni/Common.h   |  29 +-
 .../main/jni/first-party/jni/fbjni/Context.h  |  31 ++
 .../first-party/jni/fbjni/CoreClasses-inl.h   | 509 ++++++++++++-----
 .../jni/first-party/jni/fbjni/CoreClasses.h   | 523 ++++++++++--------
 .../jni/first-party/jni/fbjni/Exceptions.cpp  |   4 +-
 .../src/main/jni/first-party/jni/fbjni/File.h |  30 +
 .../main/jni/first-party/jni/fbjni/Hybrid.cpp |  34 +-
 .../main/jni/first-party/jni/fbjni/Hybrid.h   | 285 ++++------
 .../jni/first-party/jni/fbjni/Iterator-inl.h  | 199 +++++++
 .../main/jni/first-party/jni/fbjni/Iterator.h | 146 +++++
 .../jni/first-party/jni/fbjni/Meta-forward.h  |  36 ++
 .../main/jni/first-party/jni/fbjni/Meta-inl.h | 224 ++++----
 .../src/main/jni/first-party/jni/fbjni/Meta.h | 168 +++---
 .../jni/first-party/jni/fbjni/MetaConvert.h   | 122 ++++
 .../jni/fbjni/ReferenceAllocators-inl.h       |   1 -
 .../jni/fbjni/References-forward.h            |  67 +++
 .../first-party/jni/fbjni/References-inl.h    | 327 +++++++----
 .../jni/first-party/jni/fbjni/References.h    | 313 +++++++----
 .../first-party/jni/fbjni/Registration-inl.h  |  59 +-
 .../jni/first-party/jni/fbjni/TypeTraits.h    |  45 +-
 33 files changed, 2437 insertions(+), 1132 deletions(-)
 create mode 100644 ReactAndroid/src/main/jni/first-party/jni/fbjni/ByteBuffer.cpp
 create mode 100644 ReactAndroid/src/main/jni/first-party/jni/fbjni/ByteBuffer.h
 create mode 100644 ReactAndroid/src/main/jni/first-party/jni/fbjni/Context.h
 create mode 100644 ReactAndroid/src/main/jni/first-party/jni/fbjni/File.h
 create mode 100644 ReactAndroid/src/main/jni/first-party/jni/fbjni/Iterator-inl.h
 create mode 100644 ReactAndroid/src/main/jni/first-party/jni/fbjni/Iterator.h
 create mode 100644 ReactAndroid/src/main/jni/first-party/jni/fbjni/Meta-forward.h
 create mode 100644 ReactAndroid/src/main/jni/first-party/jni/fbjni/MetaConvert.h
 create mode 100644 ReactAndroid/src/main/jni/first-party/jni/fbjni/References-forward.h

diff --git a/ReactAndroid/src/main/java/com/facebook/jni/CppException.java b/ReactAndroid/src/main/java/com/facebook/jni/CppException.java
index 3006da53a95c..a0c845dd6287 100644
--- a/ReactAndroid/src/main/java/com/facebook/jni/CppException.java
+++ b/ReactAndroid/src/main/java/com/facebook/jni/CppException.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2015-present, Facebook, Inc.
  * All rights reserved.
  *
diff --git a/ReactAndroid/src/main/java/com/facebook/jni/CppSystemErrorException.java b/ReactAndroid/src/main/java/com/facebook/jni/CppSystemErrorException.java
index 18f754bf4749..13090a18ce30 100644
--- a/ReactAndroid/src/main/java/com/facebook/jni/CppSystemErrorException.java
+++ b/ReactAndroid/src/main/java/com/facebook/jni/CppSystemErrorException.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2015-present, Facebook, Inc.
  * All rights reserved.
  *
diff --git a/ReactAndroid/src/main/java/com/facebook/jni/UnknownCppException.java b/ReactAndroid/src/main/java/com/facebook/jni/UnknownCppException.java
index fa6e971f6d41..45e9bfe0cee0 100644
--- a/ReactAndroid/src/main/java/com/facebook/jni/UnknownCppException.java
+++ b/ReactAndroid/src/main/java/com/facebook/jni/UnknownCppException.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2015-present, Facebook, Inc.
  * All rights reserved.
  *
diff --git a/ReactAndroid/src/main/jni/first-party/jni/Android.mk b/ReactAndroid/src/main/jni/first-party/jni/Android.mk
index e77eaf1a0aad..1ee4d08986ca 100644
--- a/ReactAndroid/src/main/jni/first-party/jni/Android.mk
+++ b/ReactAndroid/src/main/jni/first-party/jni/Android.mk
@@ -9,6 +9,7 @@ LOCAL_SRC_FILES:= \
        LocalString.cpp \
        OnLoad.cpp \
        WeakReference.cpp \
+       fbjni/ByteBuffer.cpp \
        fbjni/Exceptions.cpp \
        fbjni/Hybrid.cpp \
        fbjni/References.cpp
diff --git a/ReactAndroid/src/main/jni/first-party/jni/BUCK b/ReactAndroid/src/main/jni/first-party/jni/BUCK
index 56d89123450a..36574b0b39cb 100644
--- a/ReactAndroid/src/main/jni/first-party/jni/BUCK
+++ b/ReactAndroid/src/main/jni/first-party/jni/BUCK
@@ -10,6 +10,7 @@ cxx_library(
     'LocalString.cpp',
     'OnLoad.cpp',
     'WeakReference.cpp',
+    'fbjni/ByteBuffer.cpp',
     'fbjni/Exceptions.cpp',
     'fbjni/Hybrid.cpp',
     'fbjni/References.cpp',
diff --git a/ReactAndroid/src/main/jni/first-party/jni/Countable.cpp b/ReactAndroid/src/main/jni/first-party/jni/Countable.cpp
index 6ff7efe9068b..3ed52f782484 100644
--- a/ReactAndroid/src/main/jni/first-party/jni/Countable.cpp
+++ b/ReactAndroid/src/main/jni/first-party/jni/Countable.cpp
@@ -41,7 +41,7 @@ void setCountableForJava(JNIEnv* env, jobject obj, RefPtr<Countable>&& countable
  *
  * This method deletes the corresponding native object on whatever thread the method is called
  * on. In the common case when this is called by Countable#finalize(), this will be called on the
- * system finalizer thread. If you manually call dispose on the Java object, the native object
+ * system finalizer thread. If you manually call dispose on the Java object, the native object 
  * will be deleted synchronously on that thread.
  */
 void dispose(JNIEnv* env, jobject obj) {
diff --git a/ReactAndroid/src/main/jni/first-party/jni/LocalReference.h b/ReactAndroid/src/main/jni/first-party/jni/LocalReference.h
index b5d9c54a13b0..09aa641fd290 100644
--- a/ReactAndroid/src/main/jni/first-party/jni/LocalReference.h
+++ b/ReactAndroid/src/main/jni/first-party/jni/LocalReference.h
@@ -27,7 +27,7 @@ struct LocalReferenceDeleter {
     if (localReference != nullptr) {
       Environment::current()->DeleteLocalRef(localReference);
     }
-  }
+  } 
  };
 
 template<class T>
diff --git a/ReactAndroid/src/main/jni/first-party/jni/LocalString.cpp b/ReactAndroid/src/main/jni/first-party/jni/LocalString.cpp
index 5fc8d0c84828..a268072677d0 100644
--- a/ReactAndroid/src/main/jni/first-party/jni/LocalString.cpp
+++ b/ReactAndroid/src/main/jni/first-party/jni/LocalString.cpp
@@ -18,6 +18,12 @@ namespace jni {
 
 namespace {
 
+const uint16_t kUtf8OneByteBoundary       = 0x80;
+const uint16_t kUtf8TwoBytesBoundary      = 0x800;
+const uint16_t kUtf16HighSubLowBoundary   = 0xD800;
+const uint16_t kUtf16HighSubHighBoundary  = 0xDC00;
+const uint16_t kUtf16LowSubHighBoundary   = 0xE000;
+
 inline void encode3ByteUTF8(char32_t code, uint8_t* out) {
   FBASSERTMSGF((code & 0xffff0000) == 0, "3 byte utf-8 encodings only valid for up to 16 bits");
 
@@ -194,6 +200,72 @@ std::string modifiedUTF8ToUTF8(const uint8_t* modified, size_t len) {
   return utf8;
 }
 
+// Calculate how many bytes are needed to convert an UTF16 string into UTF8
+// UTF16 string
+size_t utf16toUTF8Length(const uint16_t* utf16String, size_t utf16StringLen) {
+  if (!utf16String || utf16StringLen == 0) {
+    return 0;
+  }
+
+  uint32_t utf8StringLen = 0;
+  auto utf16StringEnd = utf16String + utf16StringLen;
+  auto idx16 = utf16String;
+  while (idx16 < utf16StringEnd) {
+    auto ch = *idx16++;
+    if (ch < kUtf8OneByteBoundary) {
+      utf8StringLen++;
+    } else if (ch < kUtf8TwoBytesBoundary) {
+      utf8StringLen += 2;
+    } else if (
+        (ch >= kUtf16HighSubLowBoundary) && (ch < kUtf16HighSubHighBoundary) &&
+        (idx16 < utf16StringEnd) &&
+        (*idx16 >= kUtf16HighSubHighBoundary) && (*idx16 < kUtf16LowSubHighBoundary)) {
+      utf8StringLen += 4;
+      idx16++;
+    } else {
+      utf8StringLen += 3;
+    }
+  }
+
+  return utf8StringLen;
+}
+
+std::string utf16toUTF8(const uint16_t* utf16String, size_t utf16StringLen) {
+  if (!utf16String || utf16StringLen <= 0) {
+    return "";
+  }
+
+  std::string utf8String(utf16toUTF8Length(utf16String, utf16StringLen), '\0');
+  auto idx8 = utf8String.begin();
+  auto idx16 = utf16String;
+  auto utf16StringEnd = utf16String + utf16StringLen;
+  while (idx16 < utf16StringEnd) {
+    auto ch = *idx16++;
+    if (ch < kUtf8OneByteBoundary) {
+      *idx8++ = (ch & 0x7F);
+    } else if (ch < kUtf8TwoBytesBoundary) {
+      *idx8++ = 0b11000000 | (ch >> 6);
+      *idx8++ = 0b10000000 | (ch & 0x3F);
+    } else if (
+        (ch >= kUtf16HighSubLowBoundary) && (ch < kUtf16HighSubHighBoundary) &&
+        (idx16 < utf16StringEnd) &&
+        (*idx16 >= kUtf16HighSubHighBoundary) && (*idx16 < kUtf16LowSubHighBoundary)) {
+      auto ch2 = *idx16++;
+      uint8_t trunc_byte = (((ch >> 6) & 0x0F) + 1);
+      *idx8++ = 0b11110000 | (trunc_byte >> 2);
+      *idx8++ = 0b10000000 | ((trunc_byte & 0x03) << 4) | ((ch >> 2) & 0x0F);
+      *idx8++ = 0b10000000 | ((ch & 0x03) << 4) | ((ch2 >> 6) & 0x0F);
+      *idx8++ = 0b10000000 | (ch2 & 0x3F);
+    } else {
+      *idx8++ = 0b11100000 | (ch >> 12);
+      *idx8++ = 0b10000000 | ((ch >> 6) & 0x3F);
+      *idx8++ = 0b10000000 | (ch & 0x3F);
+    }
+  }
+
+  return utf8String;
+}
+
 }
 
 LocalString::LocalString(const std::string& str)
@@ -232,11 +304,9 @@ LocalString::~LocalString() {
 }
 
 std::string fromJString(JNIEnv* env, jstring str) {
-  const char* modified = env->GetStringUTFChars(str, NULL);
-  jsize length = env->GetStringUTFLength(str);
-  std::string s = detail::modifiedUTF8ToUTF8(reinterpret_cast<const uint8_t*>(modified), length);
-  env->ReleaseStringUTFChars(str, modified);
-  return s;
+  auto utf16String = JStringUtf16Extractor(env, str);
+  auto length = env->GetStringLength(str);
+  return detail::utf16toUTF8(utf16String, length);
 }
 
 } }
diff --git a/ReactAndroid/src/main/jni/first-party/jni/LocalString.h b/ReactAndroid/src/main/jni/first-party/jni/LocalString.h
index a85efa48adaf..2290af10dc97 100644
--- a/ReactAndroid/src/main/jni/first-party/jni/LocalString.h
+++ b/ReactAndroid/src/main/jni/first-party/jni/LocalString.h
@@ -20,6 +20,7 @@ void utf8ToModifiedUTF8(const uint8_t* bytes, size_t len, uint8_t* modified, siz
 size_t modifiedLength(const std::string& str);
 size_t modifiedLength(const uint8_t* str, size_t* length);
 std::string modifiedUTF8ToUTF8(const uint8_t* modified, size_t len);
+std::string utf16toUTF8(const uint16_t* utf16Bytes, size_t len);
 
 }
 
@@ -54,6 +55,34 @@ class LocalString {
   jstring m_string;
 };
 
+// JString to UTF16 extractor using RAII idiom
+class JStringUtf16Extractor {
+public:
+  JStringUtf16Extractor(JNIEnv* env, jstring javaString)
+  : env_(env)
+  , javaString_(javaString)
+  , utf16String_(nullptr) {
+    if (env_ && javaString_) {
+      utf16String_ = env_->GetStringCritical(javaString_, nullptr);
+    }
+  }
+
+  ~JStringUtf16Extractor() {
+    if (utf16String_) {
+      env_->ReleaseStringCritical(javaString_, utf16String_);
+    }
+  }
+
+  operator const jchar* () const {
+    return utf16String_;
+  }
+
+private:
+  JNIEnv* env_;
+  jstring javaString_;
+  const jchar* utf16String_;
+};
+
 // The string from JNI is converted to standard UTF-8 if the string contains supplementary
 // characters.
 std::string fromJString(JNIEnv* env, jstring str);
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni.cpp b/ReactAndroid/src/main/jni/first-party/jni/fbjni.cpp
index a083371b2695..22d4dc2a4d19 100644
--- a/ReactAndroid/src/main/jni/first-party/jni/fbjni.cpp
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni.cpp
@@ -16,36 +16,33 @@
 namespace facebook {
 namespace jni {
 
-template<typename... Args>
-static void log(Args... args) {
-// TODO (7623232) Migrate to glog
-#ifdef __ANDROID__
-  facebook::alog::loge("fbjni", args...);
-#endif
-}
-
-jint initialize(JavaVM* vm, void(*init_fn)()) noexcept {
-  static std::once_flag init_flag;
-  static auto failed = false;
+jint initialize(JavaVM* vm, std::function<void()>&& init_fn) noexcept {
+  static std::once_flag flag{};
+  // TODO (t7832883): DTRT when we have exception pointers
+  static auto error_msg = std::string{"Failed to initialize fbjni"};
+  static auto error_occured = false;
 
-  std::call_once(init_flag, [vm] {
+  std::call_once(flag, [vm] {
     try {
       Environment::initialize(vm);
       internal::initExceptionHelpers();
     } catch (std::exception& ex) {
-      log("Failed to initialize fbjni: %s", ex.what());
-      failed = true;
+      error_occured = true;
+      try {
+        error_msg = std::string{"Failed to initialize fbjni: "} + ex.what();
+      } catch (...) {
+        // Ignore, we already have a fall back message
+      }
     } catch (...) {
-      log("Failed to initialize fbjni");
-      failed = true;
+      error_occured = true;
     }
   });
 
-  if (failed) {
-    return JNI_ERR;
-  }
-
   try {
+    if (error_occured) {
+      throw std::runtime_error(error_msg);
+    }
+
     init_fn();
   } catch (...) {
     translatePendingCppExceptionToJavaException();
@@ -55,7 +52,7 @@ jint initialize(JavaVM* vm, void(*init_fn)()) noexcept {
   return JNI_VERSION_1_6;
 }
 
-alias_ref<jclass> findClassStatic(const char* name) {
+alias_ref<JClass> findClassStatic(const char* name) {
   const auto env = internal::getEnv();
   auto cls = env->FindClass(name);
   FACEBOOK_JNI_THROW_EXCEPTION_IF(!cls);
@@ -64,7 +61,7 @@ alias_ref<jclass> findClassStatic(const char* name) {
   return wrap_alias(leaking_ref);
 }
 
-local_ref<jclass> findClassLocal(const char* name) {
+local_ref<JClass> findClassLocal(const char* name) {
   const auto env = internal::getEnv();
   auto cls = env->FindClass(name);
   FACEBOOK_JNI_THROW_EXCEPTION_IF(!cls);
@@ -74,16 +71,14 @@ local_ref<jclass> findClassLocal(const char* name) {
 
 // jstring /////////////////////////////////////////////////////////////////////////////////////////
 
-std::string JObjectWrapper<jstring>::toStdString() const {
+std::string JString::toStdString() const {
   const auto env = internal::getEnv();
-  auto modified = env->GetStringUTFChars(self(), nullptr);
-  auto length = env->GetStringUTFLength(self());
-  auto string = detail::modifiedUTF8ToUTF8(reinterpret_cast<const uint8_t*>(modified), length);
-  env->ReleaseStringUTFChars(self(), modified);
-  return string;
+  auto utf16String = JStringUtf16Extractor(env, self());
+  auto length = env->GetStringLength(self());
+  return detail::utf16toUTF8(utf16String, length);
 }
 
-local_ref<jstring> make_jstring(const char* utf8) {
+local_ref<JString> make_jstring(const char* utf8) {
   if (!utf8) {
     return {};
   }
@@ -111,96 +106,76 @@ local_ref<jstring> make_jstring(const char* utf8) {
 }
 
 
-// PinnedPrimitiveArray ///////////////////////////////////////////////////////////////////////////
+// JniPrimitiveArrayFunctions //////////////////////////////////////////////////////////////////////
 
-// TODO(T7847300): Allow array to be specified as constant so that JNI_ABORT can be passed
-// on release, as opposed to 0, which results in unnecessary copying.
 #pragma push_macro("DEFINE_PRIMITIVE_METHODS")
 #undef DEFINE_PRIMITIVE_METHODS
-#define DEFINE_PRIMITIVE_METHODS(TYPE, NAME)                                                \
-template<>                                                                                  \
-TYPE* PinnedPrimitiveArray<TYPE>::get() {                                                   \
-  FACEBOOK_JNI_THROW_EXCEPTION_IF(array_.get() == nullptr);                                 \
-  const auto env = internal::getEnv();                                                      \
-  elements_ = env->Get ## NAME ## ArrayElements(                                            \
-      static_cast<TYPE ## Array>(array_.get()), &isCopy_);                                  \
-  size_ = array_->size();                                                                   \
-  return elements_;                                                                         \
-}                                                                                           \
-template<>                                                                                  \
-void PinnedPrimitiveArray<TYPE>::release() {                                                \
-  FACEBOOK_JNI_THROW_EXCEPTION_IF(array_.get() == nullptr);                                 \
-  const auto env = internal::getEnv();                                                      \
-  env->Release ## NAME ## ArrayElements(                                                    \
-      static_cast<TYPE ## Array>(array_.get()), elements_, 0);                              \
-  elements_ = nullptr;                                                                      \
-  size_ = 0;                                                                                \
-}
-
-DEFINE_PRIMITIVE_METHODS(jboolean, Boolean)
-DEFINE_PRIMITIVE_METHODS(jbyte, Byte)
-DEFINE_PRIMITIVE_METHODS(jchar, Char)
-DEFINE_PRIMITIVE_METHODS(jshort, Short)
-DEFINE_PRIMITIVE_METHODS(jint, Int)
-DEFINE_PRIMITIVE_METHODS(jlong, Long)
-DEFINE_PRIMITIVE_METHODS(jfloat, Float)
-DEFINE_PRIMITIVE_METHODS(jdouble, Double)
+#define DEFINE_PRIMITIVE_METHODS(TYPE, NAME, SMALLNAME)                        \
+                                                                               \
+template<>                                                                     \
+TYPE* JPrimitiveArray<TYPE ## Array>::getElements(jboolean* isCopy) {          \
+  auto env = internal::getEnv();                                               \
+  TYPE* res =  env->Get ## NAME ## ArrayElements(self(), isCopy);              \
+  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();                                      \
+  return res;                                                                  \
+}                                                                              \
+                                                                               \
+template<>                                                                     \
+void JPrimitiveArray<TYPE ## Array>::releaseElements(                          \
+    TYPE* elements, jint mode) {                                               \
+  auto env = internal::getEnv();                                               \
+  env->Release ## NAME ## ArrayElements(self(), elements, mode);               \
+  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();                                      \
+}                                                                              \
+                                                                               \
+template<>                                                                     \
+void JPrimitiveArray<TYPE ## Array>::getRegion(                                \
+    jsize start, jsize length, TYPE* buf) {                                    \
+  auto env = internal::getEnv();                                               \
+  env->Get ## NAME ## ArrayRegion(self(), start, length, buf);                 \
+  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();                                      \
+}                                                                              \
+                                                                               \
+template<>                                                                     \
+void JPrimitiveArray<TYPE ## Array>::setRegion(                                \
+    jsize start, jsize length, const TYPE* elements) {                         \
+  auto env = internal::getEnv();                                               \
+  env->Set ## NAME ## ArrayRegion(self(), start, length, elements);            \
+  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();                                      \
+}                                                                              \
+                                                                               \
+local_ref<TYPE ## Array> make_ ## SMALLNAME ## _array(jsize size) {            \
+  auto array = internal::getEnv()->New ## NAME ## Array(size);                 \
+  FACEBOOK_JNI_THROW_EXCEPTION_IF(!array);                                     \
+  return adopt_local(array);                                                   \
+}                                                                              \
+                                                                               \
+template<>                                                                     \
+local_ref<TYPE ## Array> JArray ## NAME::newArray(size_t count) {              \
+  return make_ ## SMALLNAME ## _array(count);                                  \
+}                                                                              \
+                                                                               \
+
+DEFINE_PRIMITIVE_METHODS(jboolean, Boolean, boolean)
+DEFINE_PRIMITIVE_METHODS(jbyte, Byte, byte)
+DEFINE_PRIMITIVE_METHODS(jchar, Char, char)
+DEFINE_PRIMITIVE_METHODS(jshort, Short, short)
+DEFINE_PRIMITIVE_METHODS(jint, Int, int)
+DEFINE_PRIMITIVE_METHODS(jlong, Long, long)
+DEFINE_PRIMITIVE_METHODS(jfloat, Float, float)
+DEFINE_PRIMITIVE_METHODS(jdouble, Double, double)
 #pragma pop_macro("DEFINE_PRIMITIVE_METHODS")
 
-
-#define DEFINE_PRIMITIVE_ARRAY_UTILS(TYPE, NAME)                                                \
-                                                                                                \
-local_ref<j ## TYPE ## Array> make_ ## TYPE ## _array(jsize size) {                             \
-  auto array = internal::getEnv()->New ## NAME ## Array(size);                                  \
-  FACEBOOK_JNI_THROW_EXCEPTION_IF(!array);                                                      \
-  return adopt_local(array);                                                                    \
-}                                                                                               \
-                                                                                                \
-local_ref<j ## TYPE ## Array> JArray ## NAME::newArray(size_t count) {                          \
-  return make_ ## TYPE ## _array(count);                                                        \
-}                                                                                               \
-                                                                                                \
-j ## TYPE* JArray ## NAME::getRegion(jsize start, jsize length, j ## TYPE* buf) {               \
-  internal::getEnv()->Get ## NAME ## ArrayRegion(self(), start, length, buf);                   \
-  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();                                                       \
-  return buf;                                                                                   \
-}                                                                                               \
-                                                                                                \
-std::unique_ptr<j ## TYPE[]> JArray ## NAME::getRegion(jsize start, jsize length) {             \
-  auto buf = std::unique_ptr<j ## TYPE[]>{new j ## TYPE[length]};                               \
-  internal::getEnv()->Get ## NAME ## ArrayRegion(self(), start, length, buf.get());             \
-  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();                                                       \
-  return buf;                                                                                   \
-}                                                                                               \
-                                                                                                \
-void JArray ## NAME::setRegion(jsize start, jsize length, const j ## TYPE* buf) {               \
-  internal::getEnv()->Set ## NAME ## ArrayRegion(self(), start, length, buf);                   \
-  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();                                                       \
-}                                                                                               \
-                                                                                                \
-PinnedPrimitiveArray<j ## TYPE> JArray ## NAME::pin() {                                         \
-  return PinnedPrimitiveArray<j ## TYPE>{self()};                                               \
-}                                                                                               \
-
-DEFINE_PRIMITIVE_ARRAY_UTILS(boolean, Boolean)
-DEFINE_PRIMITIVE_ARRAY_UTILS(byte, Byte)
-DEFINE_PRIMITIVE_ARRAY_UTILS(char, Char)
-DEFINE_PRIMITIVE_ARRAY_UTILS(short, Short)
-DEFINE_PRIMITIVE_ARRAY_UTILS(int, Int)
-DEFINE_PRIMITIVE_ARRAY_UTILS(long, Long)
-DEFINE_PRIMITIVE_ARRAY_UTILS(float, Float)
-DEFINE_PRIMITIVE_ARRAY_UTILS(double, Double)
-
-
 // Internal debug /////////////////////////////////////////////////////////////////////////////////
 
 namespace internal {
+
 ReferenceStats g_reference_stats;
 
 void facebook::jni::internal::ReferenceStats::reset() noexcept {
   locals_deleted = globals_deleted = weaks_deleted = 0;
 }
+
 }
 
 }}
-
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni.h b/ReactAndroid/src/main/jni/first-party/jni/fbjni.h
index 7ea816b60e58..7728153cd629 100644
--- a/ReactAndroid/src/main/jni/first-party/jni/fbjni.h
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni.h
@@ -19,5 +19,6 @@
 #include "fbjni/References.h"
 #include "fbjni/Meta.h"
 #include "fbjni/CoreClasses.h"
+#include "fbjni/Iterator.h"
 #include "fbjni/Hybrid.h"
 #include "fbjni/Registration.h"
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/ByteBuffer.cpp b/ReactAndroid/src/main/jni/first-party/jni/fbjni/ByteBuffer.cpp
new file mode 100644
index 000000000000..a41f9106ed92
--- /dev/null
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/ByteBuffer.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#include "ByteBuffer.h"
+
+#include "References.h"
+#include <stdexcept>
+
+namespace facebook {
+namespace jni {
+
+namespace {
+local_ref<JByteBuffer> createEmpty() {
+  static auto cls = JByteBuffer::javaClassStatic();
+  static auto meth = cls->getStaticMethod<JByteBuffer::javaobject(int)>("allocateDirect");
+  return meth(cls, 0);
+}
+}
+
+local_ref<JByteBuffer> JByteBuffer::wrapBytes(uint8_t* data, size_t size) {
+  // env->NewDirectByteBuffer requires that size is positive. Android's
+  // dalvik returns an invalid result and Android's art aborts if size == 0.
+  // Workaround this by using a slow path through Java in that case.
+  if (!size) {
+    return createEmpty();
+  }
+  auto res = adopt_local(static_cast<javaobject>(Environment::current()->NewDirectByteBuffer(data, size)));
+  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();
+  if (!res) {
+    throw std::runtime_error("Direct byte buffers are unsupported.");
+  }
+  return res;
+}
+
+uint8_t* JByteBuffer::getDirectBytes() {
+  if (!self()) {
+    throwNewJavaException("java/lang/NullPointerException", "java.lang.NullPointerException");
+  }
+  void* bytes = Environment::current()->GetDirectBufferAddress(self());
+  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();
+  if (!bytes) {
+    throw std::runtime_error(
+        isDirect() ?
+          "Attempt to get direct bytes of non-direct byte buffer." :
+          "Error getting direct bytes of byte buffer.");
+  }
+  return static_cast<uint8_t*>(bytes);
+}
+
+size_t JByteBuffer::getDirectSize() {
+  if (!self()) {
+    throwNewJavaException("java/lang/NullPointerException", "java.lang.NullPointerException");
+  }
+  int size = Environment::current()->GetDirectBufferCapacity(self());
+  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();
+  if (size < 0) {
+    throw std::runtime_error(
+        isDirect() ?
+          "Attempt to get direct size of non-direct byte buffer." :
+          "Error getting direct size of byte buffer.");
+  }
+  return static_cast<size_t>(size);
+}
+
+bool JByteBuffer::isDirect() {
+  static auto meth = javaClassStatic()->getMethod<jboolean()>("isDirect");
+  return meth(self());
+}
+
+}}
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/ByteBuffer.h b/ReactAndroid/src/main/jni/first-party/jni/fbjni/ByteBuffer.h
new file mode 100644
index 000000000000..b10573752b03
--- /dev/null
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/ByteBuffer.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#pragma once
+
+#include "CoreClasses.h"
+#include "References-forward.h"
+
+namespace facebook {
+namespace jni {
+
+// JNI's NIO support has some awkward preconditions and error reporting. This
+// class provides much more user-friendly access.
+class JByteBuffer : public JavaClass<JByteBuffer> {
+ public:
+  static constexpr const char* kJavaDescriptor = "Ljava/nio/ByteBuffer;";
+
+  static local_ref<JByteBuffer> wrapBytes(uint8_t* data, size_t size);
+
+  bool isDirect();
+
+  uint8_t* getDirectBytes();
+  size_t getDirectSize();
+};
+
+}}
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/Common.h b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Common.h
index 479f43713a3b..9fa80c7a4df0 100644
--- a/ReactAndroid/src/main/jni/first-party/jni/fbjni/Common.h
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Common.h
@@ -14,10 +14,19 @@
 
 #pragma once
 
+#include <functional>
+
 #include <jni.h>
 
 #include <jni/Environment.h>
-#include <jni/ALog.h>
+
+#ifdef FBJNI_DEBUG_REFS
+# ifdef __ANDROID__
+#  include <android/log.h>
+# else
+#  include <cstdio>
+# endif
+#endif
 
 /// @cond INTERNAL
 
@@ -38,7 +47,7 @@ namespace jni {
  * unhelpful way (typically a segfault) while trying to handle an exception
  * which occurs later.
  */
-jint initialize(JavaVM*, void(*)()) noexcept;
+jint initialize(JavaVM*, std::function<void()>&&) noexcept;
 
 namespace internal {
 
@@ -53,14 +62,22 @@ inline JNIEnv* getEnv() noexcept {
 }
 
 // Define to get extremely verbose logging of references and to enable reference stats
-#if defined(__ANDROID__) && defined(FBJNI_DEBUG_REFS)
+#ifdef FBJNI_DEBUG_REFS
 template<typename... Args>
-inline void dbglog(Args... args) noexcept {
-  facebook::alog::logv("fbjni_ref", args...);
+inline void dbglog(const char* msg, Args... args) {
+# ifdef __ANDROID__
+  __android_log_print(ANDROID_LOG_VERBOSE, "fbjni_dbg", msg, args...);
+# else
+  std::fprintf(stderr, msg, args...);
+# endif
 }
+
 #else
+
 template<typename... Args>
-inline void dbglog(Args...) noexcept {}
+inline void dbglog(const char*, Args...) {
+}
+
 #endif
 
 }}}
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/Context.h b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Context.h
new file mode 100644
index 000000000000..136ca82f1917
--- /dev/null
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Context.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#pragma once
+
+#include "CoreClasses.h"
+#include "File.h"
+
+namespace facebook {
+namespace jni {
+
+class AContext : public JavaClass<AContext> {
+ public:
+  static constexpr const char* kJavaDescriptor = "Landroid/content/Context;";
+
+  // Define a method that calls into the represented Java class
+  local_ref<JFile::javaobject> getCacheDir() {
+    static auto method = getClass()->getMethod<JFile::javaobject()>("getCacheDir");
+    return method(self());
+  }
+
+};
+
+}
+}
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/CoreClasses-inl.h b/ReactAndroid/src/main/jni/first-party/jni/fbjni/CoreClasses-inl.h
index 134acc87e27e..f5f861ba3c6d 100644
--- a/ReactAndroid/src/main/jni/first-party/jni/fbjni/CoreClasses-inl.h
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/CoreClasses-inl.h
@@ -11,75 +11,134 @@
 
 #include <string.h>
 #include <type_traits>
+#include <stdlib.h>
 
 #include "Common.h"
 #include "Exceptions.h"
+#include "Meta.h"
+#include "MetaConvert.h"
 
 namespace facebook {
 namespace jni {
 
-inline bool isSameObject(alias_ref<jobject> lhs, alias_ref<jobject> rhs) noexcept {
-  return internal::getEnv()->IsSameObject(lhs.get(), rhs.get()) != JNI_FALSE;
-}
-
-
 // jobject /////////////////////////////////////////////////////////////////////////////////////////
 
-inline JObjectWrapper<jobject>::JObjectWrapper(jobject reference) noexcept
-  : this_{reference}
-{}
-
-inline JObjectWrapper<jobject>::JObjectWrapper(const JObjectWrapper<jobject>& other) noexcept
-  : this_{other.this_} {
-  internal::dbglog("wrapper copy from this=%p ref=%p other=%p", this, other.this_, &other);
+inline bool isSameObject(alias_ref<JObject> lhs, alias_ref<JObject> rhs) noexcept {
+  return internal::getEnv()->IsSameObject(lhs.get(), rhs.get()) != JNI_FALSE;
 }
 
-inline local_ref<jclass> JObjectWrapper<jobject>::getClass() const noexcept {
+inline local_ref<JClass> JObject::getClass() const noexcept {
   return adopt_local(internal::getEnv()->GetObjectClass(self()));
 }
 
-inline bool JObjectWrapper<jobject>::isInstanceOf(alias_ref<jclass> cls) const noexcept {
+inline bool JObject::isInstanceOf(alias_ref<JClass> cls) const noexcept {
   return internal::getEnv()->IsInstanceOf(self(), cls.get()) != JNI_FALSE;
 }
 
 template<typename T>
-inline T JObjectWrapper<jobject>::getFieldValue(JField<T> field) const noexcept {
+inline T JObject::getFieldValue(JField<T> field) const noexcept {
   return field.get(self());
 }
 
 template<typename T>
-inline local_ref<T*> JObjectWrapper<jobject>::getFieldValue(JField<T*> field) noexcept {
+inline local_ref<T*> JObject::getFieldValue(JField<T*> field) const noexcept {
   return adopt_local(field.get(self()));
 }
 
 template<typename T>
-inline void JObjectWrapper<jobject>::setFieldValue(JField<T> field, T value) noexcept {
+inline void JObject::setFieldValue(JField<T> field, T value) noexcept {
   field.set(self(), value);
 }
 
-inline std::string JObjectWrapper<jobject>::toString() const {
+inline std::string JObject::toString() const {
   static auto method = findClassLocal("java/lang/Object")->getMethod<jstring()>("toString");
 
   return method(self())->toStdString();
 }
 
-inline void JObjectWrapper<jobject>::set(jobject reference) noexcept {
-  this_ = reference;
+
+// Class is here instead of CoreClasses.h because we need
+// alias_ref to be complete.
+class MonitorLock {
+ public:
+  inline MonitorLock() noexcept;
+  inline MonitorLock(alias_ref<JObject> object) noexcept;
+  inline ~MonitorLock() noexcept;
+
+  inline MonitorLock(MonitorLock&& other) noexcept;
+  inline MonitorLock& operator=(MonitorLock&& other) noexcept;
+
+  inline MonitorLock(const MonitorLock&) = delete;
+  inline MonitorLock& operator=(const MonitorLock&) = delete;
+
+ private:
+  inline void reset() noexcept;
+  alias_ref<JObject> owned_;
+};
+
+MonitorLock::MonitorLock() noexcept : owned_(nullptr) {}
+
+MonitorLock::MonitorLock(alias_ref<JObject> object) noexcept
+    : owned_(object) {
+  internal::getEnv()->MonitorEnter(object.get());
 }
 
-inline jobject JObjectWrapper<jobject>::get() const noexcept {
-  return this_;
+void MonitorLock::reset() noexcept {
+  if (owned_) {
+    internal::getEnv()->MonitorExit(owned_.get());
+    if (internal::getEnv()->ExceptionCheck()) {
+      abort(); // Lock mismatch
+    }
+    owned_ = nullptr;
+  }
 }
 
-inline jobject JObjectWrapper<jobject>::self() const noexcept {
+MonitorLock::~MonitorLock() noexcept {
+  reset();
+}
+
+MonitorLock::MonitorLock(MonitorLock&& other) noexcept
+    : owned_(other.owned_)
+{
+  other.owned_ = nullptr;
+}
+
+MonitorLock& MonitorLock::operator=(MonitorLock&& other) noexcept {
+  reset();
+  owned_ = other.owned_;
+  other.owned_ = nullptr;
+  return *this;
+}
+
+inline MonitorLock JObject::lock() const noexcept {
+  return MonitorLock(this_);
+}
+
+inline jobject JObject::self() const noexcept {
   return this_;
 }
 
-inline void swap(JObjectWrapper<jobject>& a, JObjectWrapper<jobject>& b) noexcept {
+inline void swap(JObject& a, JObject& b) noexcept {
   using std::swap;
   swap(a.this_, b.this_);
 }
 
+// JavaClass ///////////////////////////////////////////////////////////////////////////////////////
+
+namespace detail {
+template<typename JC, typename... Args>
+static local_ref<JC> newInstance(Args... args) {
+  static auto cls = JC::javaClassStatic();
+  static auto constructor = cls->template getConstructor<typename JC::javaobject(Args...)>();
+  return cls->newObject(constructor, args...);
+}
+}
+
+
+template <typename T, typename B, typename J>
+auto JavaClass<T, B, J>::self() const noexcept -> javaobject {
+  return static_cast<javaobject>(JObject::self());
+}
 
 // jclass //////////////////////////////////////////////////////////////////////////////////////////
 
@@ -89,7 +148,7 @@ namespace detail {
 // use a void* to initialize a NativeMethod.
 struct NativeMethodWrapper;
 
-};
+}
 
 struct NativeMethod {
   const char* name;
@@ -97,11 +156,11 @@ struct NativeMethod {
   detail::NativeMethodWrapper* wrapper;
 };
 
-inline local_ref<jclass> JObjectWrapper<jclass>::getSuperclass() const noexcept {
+inline local_ref<JClass> JClass::getSuperclass() const noexcept {
   return adopt_local(internal::getEnv()->GetSuperclass(self()));
 }
 
-inline void JObjectWrapper<jclass>::registerNatives(std::initializer_list<NativeMethod> methods) {
+inline void JClass::registerNatives(std::initializer_list<NativeMethod> methods) {
   const auto env = internal::getEnv();
 
   JNINativeMethod jnimethods[methods.size()];
@@ -116,30 +175,30 @@ inline void JObjectWrapper<jclass>::registerNatives(std::initializer_list<Native
   FACEBOOK_JNI_THROW_EXCEPTION_IF(result != JNI_OK);
 }
 
-inline bool JObjectWrapper<jclass>::isAssignableFrom(alias_ref<jclass> other) const noexcept {
+inline bool JClass::isAssignableFrom(alias_ref<JClass> other) const noexcept {
   const auto env = internal::getEnv();
   const auto result = env->IsAssignableFrom(self(), other.get());
   return result;
 }
 
 template<typename F>
-inline JConstructor<F> JObjectWrapper<jclass>::getConstructor() const {
-  return getConstructor<F>(jmethod_traits<F>::constructor_descriptor().c_str());
+inline JConstructor<F> JClass::getConstructor() const {
+  return getConstructor<F>(jmethod_traits_from_cxx<F>::constructor_descriptor().c_str());
 }
 
 template<typename F>
-inline JConstructor<F> JObjectWrapper<jclass>::getConstructor(const char* descriptor) const {
+inline JConstructor<F> JClass::getConstructor(const char* descriptor) const {
   constexpr auto constructor_method_name = "<init>";
   return getMethod<F>(constructor_method_name, descriptor);
 }
 
 template<typename F>
-inline JMethod<F> JObjectWrapper<jclass>::getMethod(const char* name) const {
-  return getMethod<F>(name, jmethod_traits<F>::descriptor().c_str());
+inline JMethod<F> JClass::getMethod(const char* name) const {
+  return getMethod<F>(name, jmethod_traits_from_cxx<F>::descriptor().c_str());
 }
 
 template<typename F>
-inline JMethod<F> JObjectWrapper<jclass>::getMethod(
+inline JMethod<F> JClass::getMethod(
     const char* name,
     const char* descriptor) const {
   const auto env = internal::getEnv();
@@ -149,12 +208,12 @@ inline JMethod<F> JObjectWrapper<jclass>::getMethod(
 }
 
 template<typename F>
-inline JStaticMethod<F> JObjectWrapper<jclass>::getStaticMethod(const char* name) const {
-  return getStaticMethod<F>(name, jmethod_traits<F>::descriptor().c_str());
+inline JStaticMethod<F> JClass::getStaticMethod(const char* name) const {
+  return getStaticMethod<F>(name, jmethod_traits_from_cxx<F>::descriptor().c_str());
 }
 
 template<typename F>
-inline JStaticMethod<F> JObjectWrapper<jclass>::getStaticMethod(
+inline JStaticMethod<F> JClass::getStaticMethod(
     const char* name,
     const char* descriptor) const {
   const auto env = internal::getEnv();
@@ -164,12 +223,12 @@ inline JStaticMethod<F> JObjectWrapper<jclass>::getStaticMethod(
 }
 
 template<typename F>
-inline JNonvirtualMethod<F> JObjectWrapper<jclass>::getNonvirtualMethod(const char* name) const {
-  return getNonvirtualMethod<F>(name, jmethod_traits<F>::descriptor().c_str());
+inline JNonvirtualMethod<F> JClass::getNonvirtualMethod(const char* name) const {
+  return getNonvirtualMethod<F>(name, jmethod_traits_from_cxx<F>::descriptor().c_str());
 }
 
 template<typename F>
-inline JNonvirtualMethod<F> JObjectWrapper<jclass>::getNonvirtualMethod(
+inline JNonvirtualMethod<F> JClass::getNonvirtualMethod(
     const char* name,
     const char* descriptor) const {
   const auto env = internal::getEnv();
@@ -180,12 +239,12 @@ inline JNonvirtualMethod<F> JObjectWrapper<jclass>::getNonvirtualMethod(
 
 template<typename T>
 inline JField<enable_if_t<IsJniScalar<T>(), T>>
-JObjectWrapper<jclass>::getField(const char* name) const {
+JClass::getField(const char* name) const {
   return getField<T>(name, jtype_traits<T>::descriptor().c_str());
 }
 
 template<typename T>
-inline JField<enable_if_t<IsJniScalar<T>(), T>> JObjectWrapper<jclass>::getField(
+inline JField<enable_if_t<IsJniScalar<T>(), T>> JClass::getField(
     const char* name,
     const char* descriptor) const {
   const auto env = internal::getEnv();
@@ -195,13 +254,13 @@ inline JField<enable_if_t<IsJniScalar<T>(), T>> JObjectWrapper<jclass>::getField
 }
 
 template<typename T>
-inline JStaticField<enable_if_t<IsJniScalar<T>(), T>> JObjectWrapper<jclass>::getStaticField(
+inline JStaticField<enable_if_t<IsJniScalar<T>(), T>> JClass::getStaticField(
     const char* name) const {
   return getStaticField<T>(name, jtype_traits<T>::descriptor().c_str());
 }
 
 template<typename T>
-inline JStaticField<enable_if_t<IsJniScalar<T>(), T>> JObjectWrapper<jclass>::getStaticField(
+inline JStaticField<enable_if_t<IsJniScalar<T>(), T>> JClass::getStaticField(
     const char* name,
     const char* descriptor) const {
   const auto env = internal::getEnv();
@@ -211,32 +270,34 @@ inline JStaticField<enable_if_t<IsJniScalar<T>(), T>> JObjectWrapper<jclass>::ge
 }
 
 template<typename T>
-inline T JObjectWrapper<jclass>::getStaticFieldValue(JStaticField<T> field) const noexcept {
+inline T JClass::getStaticFieldValue(JStaticField<T> field) const noexcept {
   return field.get(self());
 }
 
 template<typename T>
-inline local_ref<T*> JObjectWrapper<jclass>::getStaticFieldValue(JStaticField<T*> field) noexcept {
+inline local_ref<T*> JClass::getStaticFieldValue(JStaticField<T*> field) noexcept {
   return adopt_local(field.get(self()));
 }
 
 template<typename T>
-inline void JObjectWrapper<jclass>::setStaticFieldValue(JStaticField<T> field, T value) noexcept {
+inline void JClass::setStaticFieldValue(JStaticField<T> field, T value) noexcept {
   field.set(self(), value);
 }
 
 template<typename R, typename... Args>
-inline local_ref<R> JObjectWrapper<jclass>::newObject(
+inline local_ref<R> JClass::newObject(
     JConstructor<R(Args...)> constructor,
     Args... args) const {
   const auto env = internal::getEnv();
-  auto object = env->NewObject(self(), constructor.getId(), args...);
+  auto object = env->NewObject(self(), constructor.getId(),
+      detail::callToJni(
+        detail::Convert<typename std::decay<Args>::type>::toCall(args))...);
   FACEBOOK_JNI_THROW_EXCEPTION_IF(!object);
   return adopt_local(static_cast<R>(object));
 }
 
-inline jclass JObjectWrapper<jclass>::self() const noexcept {
-  return static_cast<jclass>(this_);
+inline jclass JClass::self() const noexcept {
+  return static_cast<jclass>(JObject::self());
 }
 
 inline void registerNatives(const char* name, std::initializer_list<NativeMethod> methods) {
@@ -246,197 +307,349 @@ inline void registerNatives(const char* name, std::initializer_list<NativeMethod
 
 // jstring /////////////////////////////////////////////////////////////////////////////////////////
 
-inline local_ref<jstring> make_jstring(const std::string& modifiedUtf8) {
+inline local_ref<JString> make_jstring(const std::string& modifiedUtf8) {
   return make_jstring(modifiedUtf8.c_str());
 }
 
-inline jstring JObjectWrapper<jstring>::self() const noexcept {
-  return static_cast<jstring>(this_);
-}
+namespace detail {
+// convert to std::string from jstring
+template <>
+struct Convert<std::string> {
+  typedef jstring jniType;
+  static std::string fromJni(jniType t) {
+    return wrap_alias(t)->toStdString();
+  }
+  static jniType toJniRet(const std::string& t) {
+    return make_jstring(t).release();
+  }
+  static local_ref<JString> toCall(const std::string& t) {
+    return make_jstring(t);
+  }
+};
 
+// convert return from const char*
+template <>
+struct Convert<const char*> {
+  typedef jstring jniType;
+  // no automatic synthesis of const char*.  (It can't be freed.)
+  static jniType toJniRet(const char* t) {
+    return make_jstring(t).release();
+  }
+  static local_ref<JString> toCall(const char* t) {
+    return make_jstring(t);
+  }
+};
+}
 
-// jthrowable //////////////////////////////////////////////////////////////////////////////////////
+// jtypeArray //////////////////////////////////////////////////////////////////////////////////////
 
-inline jthrowable JObjectWrapper<jthrowable>::self() const noexcept {
-  return static_cast<jthrowable>(this_);
+namespace detail {
+inline size_t JArray::size() const noexcept {
+  const auto env = internal::getEnv();
+  return env->GetArrayLength(self());
+}
 }
 
-
-// jtypeArray //////////////////////////////////////////////////////////////////////////////////////
-template<typename T>
-inline ElementProxy<T>::ElementProxy(
-    JObjectWrapper<_jtypeArray<T>*>* target,
+namespace detail {
+template<typename Target>
+inline ElementProxy<Target>::ElementProxy(
+    Target* target,
     size_t idx)
     : target_{target}, idx_{idx} {}
 
-template<typename T>
-inline ElementProxy<T>& ElementProxy<T>::operator=(const T& o) {
+template<typename Target>
+inline ElementProxy<Target>& ElementProxy<Target>::operator=(const T& o) {
   target_->setElement(idx_, o);
   return *this;
 }
 
-template<typename T>
-inline ElementProxy<T>& ElementProxy<T>::operator=(alias_ref<T>& o) {
+template<typename Target>
+inline ElementProxy<Target>& ElementProxy<Target>::operator=(alias_ref<T>& o) {
   target_->setElement(idx_, o.get());
   return *this;
 }
 
-template<typename T>
-inline ElementProxy<T>& ElementProxy<T>::operator=(alias_ref<T>&& o) {
+template<typename Target>
+inline ElementProxy<Target>& ElementProxy<Target>::operator=(alias_ref<T>&& o) {
   target_->setElement(idx_, o.get());
   return *this;
 }
 
-template<typename T>
-inline ElementProxy<T>& ElementProxy<T>::operator=(const ElementProxy<T>& o) {
+template<typename Target>
+inline ElementProxy<Target>& ElementProxy<Target>::operator=(const ElementProxy<Target>& o) {
   auto src = o.target_->getElement(o.idx_);
   target_->setElement(idx_, src.get());
   return *this;
 }
 
-template<typename T>
-inline ElementProxy<T>::ElementProxy::operator const local_ref<T> () const {
+template<typename Target>
+inline ElementProxy<Target>::ElementProxy::operator const local_ref<T> () const {
   return target_->getElement(idx_);
 }
 
-template<typename T>
-inline ElementProxy<T>::ElementProxy::operator local_ref<T> () {
+template<typename Target>
+inline ElementProxy<Target>::ElementProxy::operator local_ref<T> () {
   return target_->getElement(idx_);
 }
+}
+
+template <typename T>
+std::string JArrayClass<T>::get_instantiated_java_descriptor() {
+  return "[" + jtype_traits<T>::descriptor();
+};
+
+template <typename T>
+std::string JArrayClass<T>::get_instantiated_base_name() {
+  return get_instantiated_java_descriptor();
+};
 
 template<typename T>
-local_ref<jtypeArray<T>> JObjectWrapper<jtypeArray<T>>::newArray(size_t size) {
+auto JArrayClass<T>::newArray(size_t size) -> local_ref<javaobject> {
   static auto elementClass = findClassStatic(jtype_traits<T>::base_name().c_str());
   const auto env = internal::getEnv();
   auto rawArray = env->NewObjectArray(size, elementClass.get(), nullptr);
   FACEBOOK_JNI_THROW_EXCEPTION_IF(!rawArray);
-  return adopt_local(static_cast<jtypeArray<T>>(rawArray));
+  return adopt_local(static_cast<javaobject>(rawArray));
 }
 
 template<typename T>
-inline void JObjectWrapper<jtypeArray<T>>::setElement(size_t idx, const T& value) {
+inline void JArrayClass<T>::setElement(size_t idx, const T& value) {
   const auto env = internal::getEnv();
-  env->SetObjectArrayElement(static_cast<jobjectArray>(self()), idx, value);
+  env->SetObjectArrayElement(this->self(), idx, value);
 }
 
 template<typename T>
-inline local_ref<T> JObjectWrapper<jtypeArray<T>>::getElement(size_t idx) {
+inline local_ref<T> JArrayClass<T>::getElement(size_t idx) {
   const auto env = internal::getEnv();
-  auto rawElement = env->GetObjectArrayElement(static_cast<jobjectArray>(self()), idx);
+  auto rawElement = env->GetObjectArrayElement(this->self(), idx);
   return adopt_local(static_cast<T>(rawElement));
 }
 
 template<typename T>
-inline size_t JObjectWrapper<jtypeArray<T>>::size() {
-  const auto env = internal::getEnv();
-  return env->GetArrayLength(static_cast<jobjectArray>(self()));
+inline detail::ElementProxy<JArrayClass<T>> JArrayClass<T>::operator[](size_t index) {
+  return detail::ElementProxy<JArrayClass<T>>(this, index);
 }
 
-template<typename T>
-inline ElementProxy<T> JObjectWrapper<jtypeArray<T>>::operator[](size_t index) {
-  return ElementProxy<T>(this, index);
-}
+// jarray /////////////////////////////////////////////////////////////////////////////////////////
 
-template<typename T>
-inline jtypeArray<T> JObjectWrapper<jtypeArray<T>>::self() const noexcept {
-  return static_cast<jtypeArray<T>>(this_);
+template <typename JArrayType>
+auto JPrimitiveArray<JArrayType>::getRegion(jsize start, jsize length)
+    -> std::unique_ptr<T[]> {
+  using T = typename jtype_traits<JArrayType>::entry_type;
+  auto buf = std::unique_ptr<T[]>{new T[length]};
+  getRegion(start, length, buf.get());
+  return buf;
 }
 
+template <typename JArrayType>
+std::string JPrimitiveArray<JArrayType>::get_instantiated_java_descriptor() {
+  return jtype_traits<JArrayType>::descriptor();
+}
+template <typename JArrayType>
+std::string JPrimitiveArray<JArrayType>::get_instantiated_base_name() {
+  return JPrimitiveArray::get_instantiated_java_descriptor();
+}
 
-// jarray /////////////////////////////////////////////////////////////////////////////////////////
+template <typename JArrayType>
+auto JPrimitiveArray<JArrayType>::pin() -> PinnedPrimitiveArray<T, PinnedArrayAlloc<T>> {
+  return PinnedPrimitiveArray<T, PinnedArrayAlloc<T>>{this->self(), 0, 0};
+}
 
-inline size_t JObjectWrapper<jarray>::size() const noexcept {
-  const auto env = internal::getEnv();
-  return env->GetArrayLength(self());
+template <typename JArrayType>
+auto JPrimitiveArray<JArrayType>::pinRegion(jsize start, jsize length)
+    -> PinnedPrimitiveArray<T, PinnedRegionAlloc<T>> {
+  return PinnedPrimitiveArray<T, PinnedRegionAlloc<T>>{this->self(), start, length};
 }
 
-inline jarray JObjectWrapper<jarray>::self() const noexcept {
-  return static_cast<jarray>(this_);
+template <typename JArrayType>
+auto JPrimitiveArray<JArrayType>::pinCritical()
+    -> PinnedPrimitiveArray<T, PinnedCriticalAlloc<T>> {
+  return PinnedPrimitiveArray<T, PinnedCriticalAlloc<T>>{this->self(), 0, 0};
 }
 
+template <typename T>
+class PinnedArrayAlloc {
+ public:
+  static void allocate(
+      alias_ref<typename jtype_traits<T>::array_type> array,
+      jsize start,
+      jsize length,
+      T** elements,
+      size_t* size,
+      jboolean* isCopy) {
+    (void) start;
+    (void) length;
+    *elements = array->getElements(isCopy);
+    *size = array->size();
+  }
+  static void release(
+      alias_ref<typename jtype_traits<T>::array_type> array,
+      T* elements,
+      jint start,
+      jint size,
+      jint mode) {
+    (void) start;
+    (void) size;
+    array->releaseElements(elements, mode);
+  }
+};
+
+template <typename T>
+class PinnedCriticalAlloc {
+ public:
+  static void allocate(
+      alias_ref<typename jtype_traits<T>::array_type> array,
+      jsize start,
+      jsize length,
+      T** elements,
+      size_t* size,
+      jboolean* isCopy) {
+    const auto env = internal::getEnv();
+    *elements = static_cast<T*>(env->GetPrimitiveArrayCritical(array.get(), isCopy));
+    FACEBOOK_JNI_THROW_EXCEPTION_IF(!elements);
+    *size = array->size();
+  }
+  static void release(
+      alias_ref<typename jtype_traits<T>::array_type> array,
+      T* elements,
+      jint start,
+      jint size,
+      jint mode) {
+    const auto env = internal::getEnv();
+    env->ReleasePrimitiveArrayCritical(array.get(), elements, mode);
+  }
+};
+
+template <typename T>
+class PinnedRegionAlloc {
+ public:
+  static void allocate(
+      alias_ref<typename jtype_traits<T>::array_type> array,
+      jsize start,
+      jsize length,
+      T** elements,
+      size_t* size,
+      jboolean* isCopy) {
+    auto buf = array->getRegion(start, length);
+    FACEBOOK_JNI_THROW_EXCEPTION_IF(!buf);
+    *elements = buf.release();
+    *size = length;
+    *isCopy = true;
+  }
+  static void release(
+      alias_ref<typename jtype_traits<T>::array_type> array,
+      T* elements,
+      jint start,
+      jint size,
+      jint mode) {
+    std::unique_ptr<T[]> holder;
+    if (mode == 0 || mode == JNI_ABORT) {
+      holder.reset(elements);
+    }
+    if (mode == 0 || mode == JNI_COMMIT) {
+      array->setRegion(start, size, elements);
+    }
+  }
+};
 
 // PinnedPrimitiveArray ///////////////////////////////////////////////////////////////////////////
 
-template<typename T>
-inline PinnedPrimitiveArray<T>::PinnedPrimitiveArray(alias_ref<jarray> array) noexcept
-  : array_{array} {
-  get();
+template<typename T, typename Alloc>
+PinnedPrimitiveArray<T, Alloc>::PinnedPrimitiveArray(PinnedPrimitiveArray&& o) {
+  *this = std::move(o);
 }
 
-template<typename T>
-PinnedPrimitiveArray<T>::PinnedPrimitiveArray(PinnedPrimitiveArray&& o) noexcept {
+template<typename T, typename Alloc>
+PinnedPrimitiveArray<T, Alloc>&
+PinnedPrimitiveArray<T, Alloc>::operator=(PinnedPrimitiveArray&& o) {
+  if (array_) {
+    release();
+  }
   array_ = std::move(o.array_);
   elements_ = o.elements_;
   isCopy_ = o.isCopy_;
   size_ = o.size_;
-  o.elements_ = nullptr;
-  o.isCopy_ = false;
-  o.size_ = 0;
+  start_ = o.start_;
+  o.clear();
+  return *this;
 }
 
-template<typename T>
-PinnedPrimitiveArray<T>&
-PinnedPrimitiveArray<T>::operator=(PinnedPrimitiveArray&& o) noexcept {
-  array_ = std::move(o.array_);
-  elements_ = o.elements_;
-  isCopy_ = o.isCopy_;
-  size_ = o.size_;
-  o.elements_ = nullptr;
-  o.isCopy_ = false;
-  o.size_ = 0;
-  return *this;
+template<typename T, typename Alloc>
+T* PinnedPrimitiveArray<T, Alloc>::get() {
+  return elements_;
 }
 
-template<typename T>
-inline T& PinnedPrimitiveArray<T>::operator[](size_t index) {
+template<typename T, typename Alloc>
+inline void PinnedPrimitiveArray<T, Alloc>::release() {
+  releaseImpl(0);
+  clear();
+}
+
+template<typename T, typename Alloc>
+inline void PinnedPrimitiveArray<T, Alloc>::commit() {
+  releaseImpl(JNI_COMMIT);
+}
+
+template<typename T, typename Alloc>
+inline void PinnedPrimitiveArray<T, Alloc>::abort() {
+  releaseImpl(JNI_ABORT);
+  clear();
+}
+
+template <typename T, typename Alloc>
+inline void PinnedPrimitiveArray<T, Alloc>::releaseImpl(jint mode) {
+  FACEBOOK_JNI_THROW_EXCEPTION_IF(array_.get() == nullptr);
+  Alloc::release(array_, elements_, start_, size_, mode);
+}
+
+template<typename T, typename Alloc>
+inline void PinnedPrimitiveArray<T, Alloc>::clear() noexcept {
+  array_ = nullptr;
+  elements_ = nullptr;
+  isCopy_ = false;
+  start_ = 0;
+  size_ = 0;
+}
+
+template<typename T, typename Alloc>
+inline T& PinnedPrimitiveArray<T, Alloc>::operator[](size_t index) {
   FACEBOOK_JNI_THROW_EXCEPTION_IF(elements_ == nullptr);
   return elements_[index];
 }
 
-template<typename T>
-inline bool PinnedPrimitiveArray<T>::isCopy() const noexcept {
+template<typename T, typename Alloc>
+inline bool PinnedPrimitiveArray<T, Alloc>::isCopy() const noexcept {
   return isCopy_ == JNI_TRUE;
 }
 
-template<typename T>
-inline size_t PinnedPrimitiveArray<T>::size() const noexcept {
+template<typename T, typename Alloc>
+inline size_t PinnedPrimitiveArray<T, Alloc>::size() const noexcept {
   return size_;
 }
 
-template<typename T>
-inline PinnedPrimitiveArray<T>::~PinnedPrimitiveArray() noexcept {
+template<typename T, typename Alloc>
+inline PinnedPrimitiveArray<T, Alloc>::~PinnedPrimitiveArray() noexcept {
   if (elements_) {
     release();
   }
 }
 
-#pragma push_macro("DECLARE_PRIMITIVE_METHODS")
-#undef DECLARE_PRIMITIVE_METHODS
-#define DECLARE_PRIMITIVE_METHODS(TYPE, NAME)          \
-template<> TYPE* PinnedPrimitiveArray<TYPE>::get();    \
-template<> void PinnedPrimitiveArray<TYPE>::release(); \
-
-DECLARE_PRIMITIVE_METHODS(jboolean, Boolean)
-DECLARE_PRIMITIVE_METHODS(jbyte, Byte)
-DECLARE_PRIMITIVE_METHODS(jchar, Char)
-DECLARE_PRIMITIVE_METHODS(jshort, Short)
-DECLARE_PRIMITIVE_METHODS(jint, Int)
-DECLARE_PRIMITIVE_METHODS(jlong, Long)
-DECLARE_PRIMITIVE_METHODS(jfloat, Float)
-DECLARE_PRIMITIVE_METHODS(jdouble, Double)
-#pragma pop_macro("DECLARE_PRIMITIVE_METHODS")
-
+template<typename T, typename Alloc>
+inline PinnedPrimitiveArray<T, Alloc>::PinnedPrimitiveArray(alias_ref<typename jtype_traits<T>::array_type> array, jint start, jint length) {
+  array_ = array;
+  start_ = start;
+  Alloc::allocate(array, start, length, &elements_, &size_, &isCopy_);
+}
 
-template<typename T, typename Base>
-inline alias_ref<jclass> JavaClass<T, Base>::javaClassStatic() {
-  static auto cls = findClassStatic(
-    std::string(T::kJavaDescriptor + 1, strlen(T::kJavaDescriptor) - 2).c_str());
+template<typename T, typename Base, typename JType>
+inline alias_ref<JClass> JavaClass<T, Base, JType>::javaClassStatic() {
+  static auto cls = findClassStatic(jtype_traits<typename T::javaobject>::base_name().c_str());
   return cls;
 }
 
-template<typename T, typename Base>
-inline local_ref<jclass> JavaClass<T, Base>::javaClassLocal() {
-  std::string className(T::kJavaDescriptor + 1, strlen(T::kJavaDescriptor) - 2);
+template<typename T, typename Base, typename JType>
+inline local_ref<JClass> JavaClass<T, Base, JType>::javaClassLocal() {
+  std::string className(jtype_traits<typename T::javaobject>::base_name().c_str());
   return findClassLocal(className.c_str());
 }
 
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/CoreClasses.h b/ReactAndroid/src/main/jni/first-party/jni/fbjni/CoreClasses.h
index 457b79b55d67..ed129af1bdce 100644
--- a/ReactAndroid/src/main/jni/first-party/jni/fbjni/CoreClasses.h
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/CoreClasses.h
@@ -15,8 +15,9 @@
  * to provide access to corresponding JNI functions + some conveniance.
  */
 
-#include "Meta.h"
-#include "References.h"
+#include "References-forward.h"
+#include "Meta-forward.h"
+#include "TypeTraits.h"
 
 #include <memory>
 
@@ -25,6 +26,9 @@
 namespace facebook {
 namespace jni {
 
+class JClass;
+class JObject;
+
 /// Lookup a class by name. Note this functions returns an alias_ref that
 /// points to a leaked global reference.  This is appropriate for classes
 /// that are never unloaded (which is any class in an Android app and most
@@ -34,7 +38,7 @@ namespace jni {
 /// in a "static auto" variable, or a static global.
 ///
 /// @return Returns a leaked global reference to the class
-alias_ref<jclass> findClassStatic(const char* name);
+alias_ref<JClass> findClassStatic(const char* name);
 
 /// Lookup a class by name. Note this functions returns a local reference,
 /// which means that it must not be stored in a static variable.
@@ -43,34 +47,66 @@ alias_ref<jclass> findClassStatic(const char* name);
 /// (like caching method ids).
 ///
 /// @return Returns a global reference to the class
-local_ref<jclass> findClassLocal(const char* name);
+local_ref<JClass> findClassLocal(const char* name);
 
 /// Check to see if two references refer to the same object. Comparison with nullptr
 /// returns true if and only if compared to another nullptr. A weak reference that
 /// refers to a reclaimed object count as nullptr.
-bool isSameObject(alias_ref<jobject> lhs, alias_ref<jobject> rhs) noexcept;
+bool isSameObject(alias_ref<JObject> lhs, alias_ref<JObject> rhs) noexcept;
 
+// Together, these classes allow convenient use of any class with the fbjni
+// helpers.  To use:
+//
+// struct MyClass : public JavaClass<MyClass> {
+//   constexpr static auto kJavaDescriptor = "Lcom/example/package/MyClass;";
+// };
+//
+// Then, an alias_ref<MyClass::javaobject> will be backed by an instance of
+// MyClass. JavaClass provides a convenient way to add functionality to these
+// smart references.
+//
+// For example:
+//
+// struct MyClass : public JavaClass<MyClass> {
+//   constexpr static auto kJavaDescriptor = "Lcom/example/package/MyClass;";
+//
+//   void foo() {
+//     static auto method = javaClassStatic()->getMethod<void()>("foo");
+//     method(self());
+//   }
+//
+//   static local_ref<javaobject> create(int i) {
+//     return newInstance(i);
+//   }
+// };
+//
+// auto obj = MyClass::create(10);
+// obj->foo();
+//
+// While users of a JavaClass-type can lookup methods and fields through the
+// underlying JClass, those calls can only be checked at runtime. It is recommended
+// that the JavaClass-type instead explicitly expose it's methods as in the example
+// above.
 
-/// Wrapper to provide functionality to jobject references
-template<>
-class JObjectWrapper<jobject> {
- public:
-  /// Java type descriptor
-  static constexpr const char* kJavaDescriptor = "Ljava/lang/Object;";
+namespace detail {
+template<typename JC, typename... Args>
+static local_ref<JC> newInstance(Args... args);
+}
 
-  static constexpr const char* get_instantiated_java_descriptor() { return nullptr; }
+class MonitorLock;
 
-  /// Wrap an existing JNI reference
-  JObjectWrapper(jobject reference = nullptr) noexcept;
+class JObject : detail::JObjectBase {
+public:
+  static constexpr auto kJavaDescriptor = "Ljava/lang/Object;";
 
-  // Copy constructor
-  JObjectWrapper(const JObjectWrapper& other) noexcept;
+  static constexpr const char* get_instantiated_java_descriptor() { return nullptr; }
+  static constexpr const char* get_instantiated_base_name() { return nullptr; }
 
   /// Get a @ref local_ref of the object's class
-  local_ref<jclass> getClass() const noexcept;
+  local_ref<JClass> getClass() const noexcept;
 
   /// Checks if the object is an instance of a class
-  bool isInstanceOf(alias_ref<jclass> cls) const noexcept;
+  bool isInstanceOf(alias_ref<JClass> cls) const noexcept;
 
   /// Get the primitive value of a field
   template<typename T>
@@ -78,7 +114,7 @@ class JObjectWrapper<jobject> {
 
   /// Get and wrap the value of a field in a @ref local_ref
   template<typename T>
-  local_ref<T*> getFieldValue(JField<T*> field) noexcept;
+  local_ref<T*> getFieldValue(JField<T*> field) const noexcept;
 
   /// Set the value of field. Any Java type is accepted, including the primitive types
   /// and raw reference types.
@@ -88,41 +124,108 @@ class JObjectWrapper<jobject> {
   /// Convenience method to create a std::string representing the object
   std::string toString() const;
 
- protected:
-  jobject this_;
+  // Take this object's monitor lock
+  MonitorLock lock() const noexcept;
 
- private:
-  template<typename T, typename A>
-  friend class base_owned_ref;
+  typedef _jobject _javaobject;
+  typedef _javaobject* javaobject;
 
-  template<typename T>
-  friend class alias_ref;
+protected:
+  jobject self() const noexcept;
+private:
+  friend void swap(JObject& a, JObject& b) noexcept;
+  template<typename>
+  friend struct detail::ReprAccess;
+  template<typename, typename, typename>
+  friend class JavaClass;
+
+  template <typename, typename>
+  friend class JObjectWrapper;
+};
 
-  friend void swap(JObjectWrapper<jobject>& a, JObjectWrapper<jobject>& b) noexcept;
+// This is only to maintain backwards compatibility with things that are
+// already providing a specialization of JObjectWrapper. Any such instances
+// should be updated to use a JavaClass.
+template<>
+class JObjectWrapper<jobject> : public JObject {
+};
 
-  void set(jobject reference) noexcept;
-  jobject get() const noexcept;
-  jobject self() const noexcept;
+
+namespace detail {
+template <typename, typename Base, typename JType>
+struct JTypeFor {
+  static_assert(
+      std::is_base_of<
+        std::remove_pointer<jobject>::type,
+        typename std::remove_pointer<JType>::type
+      >::value, "");
+  using _javaobject = typename std::remove_pointer<JType>::type;
+  using javaobject = JType;
 };
 
-using JObject = JObjectWrapper<jobject>;
+template <typename T, typename Base>
+struct JTypeFor<T, Base, void> {
+  // JNI pattern for jobject assignable pointer
+  struct _javaobject :  Base::_javaobject {
+    // This allows us to map back to the defining type (in ReprType, for
+    // example).
+    typedef T JniRefRepr;
+  };
+  using javaobject = _javaobject*;
+};
+}
 
-void swap(JObjectWrapper<jobject>& a, JObjectWrapper<jobject>& b) noexcept;
+// JavaClass provides a method to inform fbjni about user-defined Java types.
+// Given a class:
+// struct Foo : JavaClass<Foo> {
+//   static constexpr auto kJavaDescriptor = "Lcom/example/package/Foo;";
+// };
+// fbjni can determine the java type/method signatures for Foo::javaobject and
+// smart refs (like alias_ref<Foo::javaobject>) will hold an instance of Foo
+// and provide access to it through the -> and * operators.
+//
+// The "Base" template argument can be used to specify the JavaClass superclass
+// of this type (for instance, JString's Base is JObject).
+//
+// The "JType" template argument is used to provide a jni type (like jstring,
+// jthrowable) to be used as javaobject. This should only be necessary for
+// built-in jni types and not user-defined ones.
+template <typename T, typename Base = JObject, typename JType = void>
+class JavaClass : public Base {
+  using JObjType = typename detail::JTypeFor<T, Base, JType>;
+public:
+  using _javaobject = typename JObjType::_javaobject;
+  using javaobject = typename JObjType::javaobject;
+
+  using JavaBase = JavaClass;
+
+  static alias_ref<JClass> javaClassStatic();
+  static local_ref<JClass> javaClassLocal();
+protected:
+  /// Allocates a new object and invokes the specified constructor
+  /// Like JClass's getConstructor, this function can only check at runtime if
+  /// the class actually has a constructor that accepts the corresponding types.
+  /// While a JavaClass-type can expose this function directly, it is recommended
+  /// to instead to use this to explicitly only expose those constructors that
+  /// the Java class actually has (i.e. with static create() functions).
+  template<typename... Args>
+  static local_ref<T> newInstance(Args... args) {
+    return detail::newInstance<JavaClass>(args...);
+  }
 
+  javaobject self() const noexcept;
+};
 
 /// Wrapper to provide functionality to jclass references
 struct NativeMethod;
 
-template<>
-class JObjectWrapper<jclass> : public JObjectWrapper<jobject> {
+class JClass : public JavaClass<JClass, JObject, jclass> {
  public:
   /// Java type descriptor
   static constexpr const char* kJavaDescriptor = "Ljava/lang/Class;";
 
-  using JObjectWrapper<jobject>::JObjectWrapper;
-
   /// Get a @local_ref to the super class of this class
-  local_ref<jclass> getSuperclass() const noexcept;
+  local_ref<JClass> getSuperclass() const noexcept;
 
   /// Register native methods for the class.  Usage looks like this:
   ///
@@ -141,7 +244,7 @@ class JObjectWrapper<jclass> : public JObjectWrapper<jobject> {
 
   /// Check to see if the class is assignable from another class
   /// @pre cls != nullptr
-  bool isAssignableFrom(alias_ref<jclass> cls) const noexcept;
+  bool isAssignableFrom(alias_ref<JClass> cls) const noexcept;
 
   /// Convenience method to lookup the constructor with descriptor as specified by the
   /// type arguments
@@ -212,95 +315,96 @@ class JObjectWrapper<jclass> : public JObjectWrapper<jobject> {
   template<typename F>
   JNonvirtualMethod<F> getNonvirtualMethod(const char* name, const char* descriptor) const;
 
- private:
+private:
   jclass self() const noexcept;
 };
 
-using JClass = JObjectWrapper<jclass>;
-
 // Convenience method to register methods on a class without holding
 // onto the class object.
 void registerNatives(const char* name, std::initializer_list<NativeMethod> methods);
 
 /// Wrapper to provide functionality to jstring references
-template<>
-class JObjectWrapper<jstring> : public JObjectWrapper<jobject> {
+class JString : public JavaClass<JString, JObject, jstring> {
  public:
   /// Java type descriptor
   static constexpr const char* kJavaDescriptor = "Ljava/lang/String;";
 
-  using JObjectWrapper<jobject>::JObjectWrapper;
-
   /// Convenience method to convert a jstring object to a std::string
   std::string toStdString() const;
-
- private:
-  jstring self() const noexcept;
 };
 
 /// Convenience functions to convert a std::string or const char* into a @ref local_ref to a
 /// jstring
-local_ref<jstring> make_jstring(const char* modifiedUtf8);
-local_ref<jstring> make_jstring(const std::string& modifiedUtf8);
-
-using JString = JObjectWrapper<jstring>;
+local_ref<JString> make_jstring(const char* modifiedUtf8);
+local_ref<JString> make_jstring(const std::string& modifiedUtf8);
 
 /// Wrapper to provide functionality to jthrowable references
-template<>
-class JObjectWrapper<jthrowable> : public JObjectWrapper<jobject> {
+class JThrowable : public JavaClass<JThrowable, JObject, jthrowable> {
  public:
-  /// Java type descriptor
   static constexpr const char* kJavaDescriptor = "Ljava/lang/Throwable;";
+};
 
-  using JObjectWrapper<jobject>::JObjectWrapper;
-
+namespace detail {
+template<typename Target>
+class ElementProxy {
  private:
-  jthrowable self() const noexcept;
-};
+  Target* target_;
+  size_t idx_;
 
+ public:
+  using T = typename Target::javaentry;
+  ElementProxy(Target* target, size_t idx);
 
-/// @cond INTERNAL
-template<class T> class _jtypeArray : public _jobjectArray {};
-// @endcond
-/// Wrapper to provide functionality for arrays of j-types
-template<class T> using jtypeArray = _jtypeArray<T>*;
+  ElementProxy& operator=(const T& o);
 
-template<typename T>
-class ElementProxy {
-   private:
-    JObjectWrapper<_jtypeArray<T>*>* target_;
-    size_t idx_;
-
-   public:
-    ElementProxy(JObjectWrapper<_jtypeArray<T>*>* target, size_t idx);
+  ElementProxy& operator=(alias_ref<T>& o);
 
-    ElementProxy<T>& operator=(const T& o);
+  ElementProxy& operator=(alias_ref<T>&& o);
 
-    ElementProxy<T>& operator=(alias_ref<T>& o);
+  ElementProxy& operator=(const ElementProxy& o);
 
-    ElementProxy<T>& operator=(alias_ref<T>&& o);
+  operator const local_ref<T> () const;
 
-    ElementProxy<T>& operator=(const ElementProxy<T>& o);
+  operator local_ref<T> ();
+};
+}
 
-    operator const local_ref<T> () const;
+namespace detail {
+class JArray : public JavaClass<JArray, JObject, jarray> {
+ public:
+  // This cannot be used in a scope that derives a descriptor (like in a method
+  // signature). Use a more derived type instead (like JArrayInt or
+  // JArrayClass<T>).
+  static constexpr const char* kJavaDescriptor = nullptr;
+  size_t size() const noexcept;
+};
 
-    operator local_ref<T> ();
-  };
+// This is used so that the JArrayClass<T> javaobject extends jni's
+// jobjectArray. This class should not be used directly. A general Object[]
+// should use JArrayClass<jobject>.
+class JTypeArray : public JavaClass<JTypeArray, JArray, jobjectArray> {
+  // This cannot be used in a scope that derives a descriptor (like in a method
+  // signature).
+  static constexpr const char* kJavaDescriptor = nullptr;
+};
+}
 
 template<typename T>
-class JObjectWrapper<jtypeArray<T>> : public JObjectWrapper<jobject> {
+class JArrayClass : public JavaClass<JArrayClass<T>, detail::JTypeArray> {
  public:
+  static_assert(is_plain_jni_reference<T>(), "");
+  // javaentry is the jni type of an entry in the array (i.e. jint).
+  using javaentry = T;
+  // javaobject is the jni type of the array.
+  using javaobject = typename JavaClass<JArrayClass<T>, detail::JTypeArray>::javaobject;
   static constexpr const char* kJavaDescriptor = nullptr;
-  static std::string get_instantiated_java_descriptor() {
-    return "[" + jtype_traits<T>::descriptor();
-  };
-
-  using JObjectWrapper<jobject>::JObjectWrapper;
+  static std::string get_instantiated_java_descriptor();
+  static std::string get_instantiated_base_name();
 
   /// Allocate a new array from Java heap, for passing as a JNI parameter or return value.
   /// NOTE: if using as a return value, you want to call release() instead of get() on the
   /// smart pointer.
-  static local_ref<jtypeArray<T>> newArray(size_t count);
+  static local_ref<javaobject> newArray(size_t count);
 
   /// Assign an object to the array.
   /// Typically you will use the shorthand (*ref)[idx]=value;
@@ -312,9 +416,6 @@ class JObjectWrapper<jtypeArray<T>> : public JObjectWrapper<jobject> {
   /// If you use auto, you'll get an ElementProxy, which may need to be cast.
   local_ref<T> getElement(size_t idx);
 
-  /// Get the size of the array.
-  size_t size();
-
   /// EXPERIMENTAL SUBSCRIPT SUPPORT
   /// This implementation of [] returns a proxy object which then has a bunch of specializations
   /// (adopt_local free function, operator= and casting overloads on the ElementProxy) that can
@@ -324,187 +425,167 @@ class JObjectWrapper<jtypeArray<T>> : public JObjectWrapper<jobject> {
   /// by using idioms that haven't been tried yet. Consider yourself warned. On the other hand,
   /// it does make for some idiomatic assignment code; see TestBuildStringArray in fbjni_tests
   /// for some examples.
-  ElementProxy<T> operator[](size_t idx);
-
- private:
-  jtypeArray<T> self() const noexcept;
+  detail::ElementProxy<JArrayClass> operator[](size_t idx);
 };
 
-template <class T>
-using JArrayClass = JObjectWrapper<jtypeArray<T>>;
+template <typename T>
+using jtypeArray = typename JArrayClass<T>::javaobject;
 
 template<typename T>
-local_ref<jtypeArray<T>> adopt_local_array(jobjectArray ref) {
-  return adopt_local(static_cast<jtypeArray<T>>(ref));
+local_ref<typename JArrayClass<T>::javaobject> adopt_local_array(jobjectArray ref) {
+  return adopt_local(static_cast<typename JArrayClass<T>::javaobject>(ref));
 }
 
-template<typename T>
-local_ref<T> adopt_local(ElementProxy<T> elementProxy) {
-  return static_cast<local_ref<T>>(elementProxy);
+template<typename Target>
+local_ref<typename Target::javaentry> adopt_local(detail::ElementProxy<Target> elementProxy) {
+  return static_cast<local_ref<typename Target::javaentry>>(elementProxy);
 }
 
+template <typename T, typename PinAlloc>
+class PinnedPrimitiveArray;
+
+template <typename T> class PinnedArrayAlloc;
+template <typename T> class PinnedRegionAlloc;
+template <typename T> class PinnedCriticalAlloc;
+
 /// Wrapper to provide functionality to jarray references.
 /// This is an empty holder by itself. Construct a PinnedPrimitiveArray to actually interact with
 /// the elements of the array.
-template<>
-class JObjectWrapper<jarray> : public JObjectWrapper<jobject> {
+template <typename JArrayType>
+class JPrimitiveArray :
+    public JavaClass<JPrimitiveArray<JArrayType>, detail::JArray, JArrayType> {
+  static_assert(is_jni_primitive_array<JArrayType>(), "");
  public:
   static constexpr const char* kJavaDescriptor = nullptr;
-
-  using JObjectWrapper<jobject>::JObjectWrapper;
-  size_t size() const noexcept;
-
- private:
-  jarray self() const noexcept;
+  static std::string get_instantiated_java_descriptor();
+  static std::string get_instantiated_base_name();
+
+  using T = typename jtype_traits<JArrayType>::entry_type;
+
+  static local_ref<JArrayType> newArray(size_t count);
+
+  void getRegion(jsize start, jsize length, T* buf);
+  std::unique_ptr<T[]> getRegion(jsize start, jsize length);
+  void setRegion(jsize start, jsize length, const T* buf);
+
+  /// Returns a view of the underlying array. This will either be a "pinned"
+  /// version of the array (in which case changes to one immediately affect the
+  /// other) or a copy of the array (in which cases changes to the view will take
+  /// affect when destroyed or on calls to release()/commit()).
+  PinnedPrimitiveArray<T, PinnedArrayAlloc<T>> pin();
+
+  /// Returns a view of part of the underlying array. A pinned region is always
+  /// backed by a copy of the region.
+  PinnedPrimitiveArray<T, PinnedRegionAlloc<T>> pinRegion(jsize start, jsize length);
+
+  /// Returns a view of the underlying array like pin(). However, while the pin
+  /// is held, the code is considered within a "critical region". In a critical
+  /// region, native code must not call JNI functions or make any calls that may
+  /// block on other Java threads. These restrictions make it more likely that
+  /// the view will be "pinned" rather than copied (for example, the VM may
+  /// suspend garbage collection within a critical region).
+  PinnedPrimitiveArray<T, PinnedCriticalAlloc<T>> pinCritical();
+
+private:
+  friend class PinnedArrayAlloc<T>;
+  T* getElements(jboolean* isCopy);
+  void releaseElements(T* elements, jint mode);
 };
 
-using JArray = JObjectWrapper<jarray>;
-
-template <typename T>
-class PinnedPrimitiveArray;
-
-#pragma push_macro("DECLARE_PRIMITIVE_ARRAY_UTILS")
-#undef DECLARE_PRIMITIVE_ARRAY_UTILS
-#define DECLARE_PRIMITIVE_ARRAY_UTILS(TYPE, NAME, DESC)                \
-                                                                       \
-local_ref<j ## TYPE ## Array> make_ ## TYPE ## _array(jsize size);     \
-                                                                       \
-template<> class JObjectWrapper<j ## TYPE ## Array> : public JArray {  \
- public:                                                               \
-  static constexpr const char* kJavaDescriptor = "[" # DESC;           \
-                                                                       \
-  using JArray::JArray;                                                \
-                                                                       \
-  static local_ref<j ## TYPE ## Array> newArray(size_t count);         \
-                                                                       \
-  j ## TYPE* getRegion(jsize start, jsize length, j ## TYPE* buf);     \
-  std::unique_ptr<j ## TYPE[]> getRegion(jsize start, jsize length);   \
-  void setRegion(jsize start, jsize length, const j ## TYPE* buf);     \
-  PinnedPrimitiveArray<j ## TYPE> pin();                               \
-                                                                       \
- private:                                                              \
-  j ## TYPE ## Array self() const noexcept {                           \
-    return static_cast<j ## TYPE ## Array>(this_);                     \
-  }                                                                    \
-};                                                                     \
-                                                                       \
-using JArray ## NAME = JObjectWrapper<j ## TYPE ## Array>              \
-
-
-DECLARE_PRIMITIVE_ARRAY_UTILS(boolean, Boolean, "Z");
-DECLARE_PRIMITIVE_ARRAY_UTILS(byte, Byte, "B");
-DECLARE_PRIMITIVE_ARRAY_UTILS(char, Char, "C");
-DECLARE_PRIMITIVE_ARRAY_UTILS(short, Short, "S");
-DECLARE_PRIMITIVE_ARRAY_UTILS(int, Int, "I");
-DECLARE_PRIMITIVE_ARRAY_UTILS(long, Long, "J");
-DECLARE_PRIMITIVE_ARRAY_UTILS(float, Float, "F");
-DECLARE_PRIMITIVE_ARRAY_UTILS(double, Double, "D");
-
-#pragma pop_macro("DECLARE_PRIMITIVE_ARRAY_UTILS")
-
+local_ref<jbooleanArray> make_boolean_array(jsize size);
+local_ref<jbyteArray> make_byte_array(jsize size);
+local_ref<jcharArray> make_char_array(jsize size);
+local_ref<jshortArray> make_short_array(jsize size);
+local_ref<jintArray> make_int_array(jsize size);
+local_ref<jlongArray> make_long_array(jsize size);
+local_ref<jfloatArray> make_float_array(jsize size);
+local_ref<jdoubleArray> make_double_array(jsize size);
+
+using JArrayBoolean = JPrimitiveArray<jbooleanArray>;
+using JArrayByte = JPrimitiveArray<jbyteArray>;
+using JArrayChar = JPrimitiveArray<jcharArray>;
+using JArrayShort = JPrimitiveArray<jshortArray>;
+using JArrayInt = JPrimitiveArray<jintArray>;
+using JArrayLong = JPrimitiveArray<jlongArray>;
+using JArrayFloat = JPrimitiveArray<jfloatArray>;
+using JArrayDouble = JPrimitiveArray<jdoubleArray>;
 
 /// RAII class for pinned primitive arrays
 /// This currently only supports read/write access to existing java arrays. You can't create a
 /// primitive array this way yet. This class also pins the entire array into memory during the
 /// lifetime of the PinnedPrimitiveArray. If you need to unpin the array manually, call the
-/// release() function. During a long-running block of code, you should unpin the array as soon
-/// as you're done with it, to avoid holding up the Java garbage collector.
-template <typename T>
+/// release() or abort() functions. During a long-running block of code, you
+/// should unpin the array as soon as you're done with it, to avoid holding up
+/// the Java garbage collector.
+template <typename T, typename PinAlloc>
 class PinnedPrimitiveArray {
   public:
    static_assert(is_jni_primitive<T>::value,
        "PinnedPrimitiveArray requires primitive jni type.");
 
-   PinnedPrimitiveArray(PinnedPrimitiveArray&&) noexcept;
+   using ArrayType = typename jtype_traits<T>::array_type;
+
+   PinnedPrimitiveArray(PinnedPrimitiveArray&&);
    PinnedPrimitiveArray(const PinnedPrimitiveArray&) = delete;
    ~PinnedPrimitiveArray() noexcept;
 
-   PinnedPrimitiveArray& operator=(PinnedPrimitiveArray&&) noexcept;
+   PinnedPrimitiveArray& operator=(PinnedPrimitiveArray&&);
    PinnedPrimitiveArray& operator=(const PinnedPrimitiveArray&) = delete;
 
    T* get();
    void release();
+   /// Unpins the array. If the array is a copy, pending changes are discarded.
+   void abort();
+   /// If the array is a copy, copies pending changes to the underlying java array.
+   void commit();
+
+   bool isCopy() const noexcept;
 
    const T& operator[](size_t index) const;
    T& operator[](size_t index);
-   bool isCopy() const noexcept;
    size_t size() const noexcept;
 
   private:
-   alias_ref<jarray> array_;
+   alias_ref<ArrayType> array_;
+   size_t start_;
    T* elements_;
    jboolean isCopy_;
    size_t size_;
 
-   PinnedPrimitiveArray(alias_ref<jarray>) noexcept;
+   void allocate(alias_ref<ArrayType>, jint start, jint length);
+   void releaseImpl(jint mode);
+   void clear() noexcept;
 
-   friend class JObjectWrapper<jbooleanArray>;
-   friend class JObjectWrapper<jbyteArray>;
-   friend class JObjectWrapper<jcharArray>;
-   friend class JObjectWrapper<jshortArray>;
-   friend class JObjectWrapper<jintArray>;
-   friend class JObjectWrapper<jlongArray>;
-   friend class JObjectWrapper<jfloatArray>;
-   friend class JObjectWrapper<jdoubleArray>;
-};
-
-
-namespace detail {
+   PinnedPrimitiveArray(alias_ref<ArrayType>, jint start, jint length);
 
-class BaseJavaClass {
-public:
-  typedef _jobject _javaobject;
-  typedef _javaobject* javaobject;
+   friend class JPrimitiveArray<typename jtype_traits<T>::array_type>;
 };
 
+#pragma push_macro("PlainJniRefMap")
+#undef PlainJniRefMap
+#define PlainJniRefMap(rtype, jtype) \
+namespace detail { \
+template<> \
+struct RefReprType<jtype> { \
+  using type = rtype; \
+}; \
 }
 
-// Together, these classes allow convenient use of any class with the fbjni
-// helpers.  To use:
-//
-// struct MyClass : public JavaClass<MyClass> {
-//   constexpr static auto kJavaDescriptor = "Lcom/example/package/MyClass;";
-// };
-//
-// alias_ref<MyClass::javaobject> myClass = foo();
-
-template <typename T, typename Base = detail::BaseJavaClass>
-class JavaClass {
-public:
-  // JNI pattern for jobject assignable pointer
-  struct _javaobject : public Base::_javaobject {
-    typedef T javaClass;
-  };
-  typedef _javaobject* javaobject;
-
-  static alias_ref<jclass> javaClassStatic();
-  static local_ref<jclass> javaClassLocal();
-};
-
-template <typename T>
-class JObjectWrapper<T,
-    typename std::enable_if<
-      is_plain_jni_reference<T>::value &&
-      std::is_class<typename std::remove_pointer<T>::type::javaClass>::value
-    >::type>
-  : public JObjectWrapper<jobject> {
-public:
-  static constexpr const char* kJavaDescriptor =
-    std::remove_pointer<T>::type::javaClass::kJavaDescriptor;
-
-  using JObjectWrapper<jobject>::JObjectWrapper;
-
-  template<typename U>
-  JObjectWrapper(const JObjectWrapper<U>& w)
-    : JObjectWrapper<jobject>(w) {
-    static_assert(std::is_convertible<U, T>::value,
-                  "U must be convertible to T");
-  }
-};
+PlainJniRefMap(JArrayBoolean, jbooleanArray);
+PlainJniRefMap(JArrayByte, jbyteArray);
+PlainJniRefMap(JArrayChar, jcharArray);
+PlainJniRefMap(JArrayShort, jshortArray);
+PlainJniRefMap(JArrayInt, jintArray);
+PlainJniRefMap(JArrayLong, jlongArray);
+PlainJniRefMap(JArrayFloat, jfloatArray);
+PlainJniRefMap(JArrayDouble, jdoubleArray);
+PlainJniRefMap(JObject, jobject);
+PlainJniRefMap(JClass, jclass);
+PlainJniRefMap(JString, jstring);
+PlainJniRefMap(JThrowable, jthrowable);
+
+#pragma pop_macro("PlainJniRefMap")
 
 }}
 
 #include "CoreClasses-inl.h"
-// This is here because code in Meta-inl.h uses alias_ref, which
-// requires JObjectWrapper<jobject> to be concrete before it can work.
-#include "Meta-inl.h"
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/Exceptions.cpp b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Exceptions.cpp
index 710a6836f1ca..6a3516cd3f7d 100644
--- a/ReactAndroid/src/main/jni/first-party/jni/fbjni/Exceptions.cpp
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Exceptions.cpp
@@ -7,9 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  */
 
-#include "Exceptions.h"
-#include "CoreClasses.h"
-#include <jni/ALog.h>
+#include "jni/fbjni.h"
 
 #include <fb/assert.h>
 
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/File.h b/ReactAndroid/src/main/jni/first-party/jni/fbjni/File.h
new file mode 100644
index 000000000000..29fc9850a95c
--- /dev/null
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/File.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#pragma once
+
+#include "CoreClasses.h"
+
+namespace facebook {
+namespace jni {
+
+class JFile : public JavaClass<JFile> {
+ public:
+  static constexpr const char* kJavaDescriptor = "Ljava/io/File;";
+
+  // Define a method that calls into the represented Java class
+  std::string getAbsolutePath() {
+    static auto method = getClass()->getMethod<jstring()>("getAbsolutePath");
+    return method(self())->toStdString();
+  }
+
+};
+
+}
+}
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/Hybrid.cpp b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Hybrid.cpp
index ebcb778de9e1..c779cde4ef79 100644
--- a/ReactAndroid/src/main/jni/first-party/jni/fbjni/Hybrid.cpp
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Hybrid.cpp
@@ -7,20 +7,17 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  */
 
-#include "Hybrid.h"
+#include "jni/fbjni.h"
 
-#include "Exceptions.h"
-#include "Registration.h"
 
 namespace facebook {
 namespace jni {
 
 namespace detail {
 
-void setNativePointer(alias_ref<HybridData::javaobject> hybridData,
-                      std::unique_ptr<BaseHybridClass> new_value) {
-  static auto pointerField = hybridData->getClass()->getField<jlong>("mNativePointer");
-  auto* old_value = reinterpret_cast<BaseHybridClass*>(hybridData->getFieldValue(pointerField));
+void HybridData::setNativePointer(std::unique_ptr<BaseHybridClass> new_value) {
+  static auto pointerField = getClass()->getField<jlong>("mNativePointer");
+  auto* old_value = reinterpret_cast<BaseHybridClass*>(getFieldValue(pointerField));
   if (new_value) {
     // Modify should only ever be called once with a non-null
     // new_value.  If this happens again it's a programmer error, so
@@ -35,35 +32,28 @@ void setNativePointer(alias_ref<HybridData::javaobject> hybridData,
   // ownership of it, to HybridData which is managed by the java GC.  The
   // finalizer on hybridData calls resetNative which will delete the object, if
   // reseetNative has not already been called.
-  hybridData->setFieldValue(pointerField, reinterpret_cast<jlong>(new_value.release()));
+  setFieldValue(pointerField, reinterpret_cast<jlong>(new_value.release()));
 }
 
-BaseHybridClass* getNativePointer(alias_ref<HybridData::javaobject> hybridData) {
-  static auto pointerField = hybridData->getClass()->getField<jlong>("mNativePointer");
-  auto* value = reinterpret_cast<BaseHybridClass*>(hybridData->getFieldValue(pointerField));
+BaseHybridClass* HybridData::getNativePointer() {
+  static auto pointerField = getClass()->getField<jlong>("mNativePointer");
+  auto* value = reinterpret_cast<BaseHybridClass*>(getFieldValue(pointerField));
   if (!value) {
     throwNewJavaException("java/lang/NullPointerException", "java.lang.NullPointerException");
   }
   return value;
 }
 
-local_ref<HybridData::javaobject> getHybridData(alias_ref<jobject> jthis,
-                                                JField<HybridData::javaobject> field) {
-  auto hybridData = jthis->getFieldValue(field);
-  if (!hybridData) {
-    throwNewJavaException("java/lang/NullPointerException", "java.lang.NullPointerException");
-  }
-  return hybridData;
+local_ref<HybridData> HybridData::create() {
+  return newInstance();
 }
 
 }
 
 namespace {
-
-void resetNative(alias_ref<detail::HybridData::javaobject> jthis) {
-  detail::setNativePointer(jthis, nullptr);
+void resetNative(alias_ref<detail::HybridData> jthis) {
+  jthis->setNativePointer(nullptr);
 }
-
 }
 
 void HybridDataOnLoad() {
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/Hybrid.h b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Hybrid.h
index 8b62ccdedec4..70fc670f5c8e 100644
--- a/ReactAndroid/src/main/jni/first-party/jni/fbjni/Hybrid.h
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Hybrid.h
@@ -19,169 +19,108 @@ namespace jni {
 
 namespace detail {
 
-class BaseHybridClass : public BaseJavaClass {
+class BaseHybridClass {
 public:
   virtual ~BaseHybridClass() {}
 };
 
 struct HybridData : public JavaClass<HybridData> {
   constexpr static auto kJavaDescriptor = "Lcom/facebook/jni/HybridData;";
+  void setNativePointer(std::unique_ptr<BaseHybridClass> new_value);
+  BaseHybridClass* getNativePointer();
+  static local_ref<HybridData> create();
 };
 
-void setNativePointer(alias_ref<HybridData::javaobject> hybridData,
-                      std::unique_ptr<BaseHybridClass> new_value);
-BaseHybridClass* getNativePointer(alias_ref<HybridData::javaobject> hybridData);
-local_ref<HybridData::javaobject> getHybridData(alias_ref<jobject> jthis,
-                                                JField<HybridData::javaobject> field);
-
-// Normally, pass through types unmolested.
-template <typename T, typename Enabled = void>
-struct Convert {
-  typedef T jniType;
-  static jniType fromJni(jniType t) {
-    return t;
-  }
-  static jniType toJniRet(jniType t) {
-    return t;
-  }
-  static jniType toCall(jniType t) {
-    return t;
-  }
+template <typename Base, typename Enabled = void>
+struct HybridTraits {
+  // This static assert should actually always fail if we don't use one of the
+  // specializations below.
+  static_assert(
+      std::is_base_of<JObject, Base>::value ||
+      std::is_base_of<BaseHybridClass, Base>::value,
+      "The base of a HybridClass must be either another HybridClass or derived from JObject.");
 };
 
-// This is needed for return conversion
 template <>
-struct Convert<void> {
-  typedef void jniType;
+struct HybridTraits<BaseHybridClass> {
+ using CxxBase = BaseHybridClass;
+ using JavaBase = JObject;
 };
 
-// convert to std::string from jstring
-template <>
-struct Convert<std::string> {
-  typedef jstring jniType;
-  static std::string fromJni(jniType t) {
-    return wrap_alias(t)->toStdString();
-  }
-  static jniType toJniRet(const std::string& t) {
-    return make_jstring(t).release();
-  }
-  static local_ref<jstring> toCall(const std::string& t) {
-    return make_jstring(t);
-  }
+template <typename Base>
+struct HybridTraits<
+    Base,
+    typename std::enable_if<std::is_base_of<BaseHybridClass, Base>::value>::type> {
+ using CxxBase = Base;
+ using JavaBase = typename Base::JavaPart;
 };
 
-// convert return from const char*
-template <>
-struct Convert<const char*> {
-  typedef jstring jniType;
-  // no automatic synthesis of const char*.  (It can't be freed.)
-  static jniType toJniRet(const char* t) {
-    return make_jstring(t).release();
-  }
-  static local_ref<jstring> toCall(const char* t) {
-    return make_jstring(t);
-  }
-};
-
-// jboolean is an unsigned char, not a bool. Allow it to work either way.
-template<>
-struct Convert<bool> {
-  typedef jboolean jniType;
-  static bool fromJni(jniType t) {
-    return t;
-  }
-  static jniType toJniRet(bool t) {
-    return t;
-  }
-  static jniType toCall(bool t) {
-    return t;
-  }
+template <typename Base>
+struct HybridTraits<
+    Base,
+    typename std::enable_if<std::is_base_of<JObject, Base>::value>::type> {
+ using CxxBase = BaseHybridClass;
+ using JavaBase = Base;
 };
 
-// convert to alias_ref<T> from T
+// convert to HybridClass* from jhybridobject
 template <typename T>
-struct Convert<alias_ref<T>> {
-  typedef T jniType;
-  static alias_ref<jniType> fromJni(jniType t) {
-    return wrap_alias(t);
-  }
-  static jniType toJniRet(alias_ref<jniType> t) {
-    return t.get();
-  }
-  static jniType toCall(alias_ref<jniType> t) {
-    return t.get();
-  }
-};
-
-// convert return from local_ref<T>
-template <typename T>
-struct Convert<local_ref<T>> {
-  typedef T jniType;
-  // No automatic synthesis of local_ref
-  static jniType toJniRet(local_ref<jniType> t) {
-    return t.release();
-  }
-  static jniType toCall(local_ref<jniType> t) {
-    return t.get();
-  }
+struct Convert<
+  T, typename std::enable_if<
+    std::is_base_of<BaseHybridClass, typename std::remove_pointer<T>::type>::value>::type> {
+  typedef typename std::remove_pointer<T>::type::jhybridobject jniType;
+  static T fromJni(jniType t) {
+    if (t == nullptr) {
+      return nullptr;
+    }
+    return wrap_alias(t)->cthis();
+  }
+  // There is no automatic return conversion for objects.
 };
 
-// convert return from global_ref<T>
-template <typename T>
-struct Convert<global_ref<T>> {
-  typedef T jniType;
-  // No automatic synthesis of global_ref
-  static jniType toJniRet(global_ref<jniType> t) {
-    return t.get();
-  }
-  static jniType toCall(global_ref<jniType> t) {
-    return t.get();
-  }
+template<typename T>
+struct RefReprType<T, typename std::enable_if<std::is_base_of<BaseHybridClass, T>::value, void>::type> {
+  static_assert(std::is_same<T, void>::value,
+      "HybridFoo (where HybridFoo derives from HybridClass<HybridFoo>) is not supported in this context. "
+      "For an xxx_ref<HybridFoo>, you may want: xxx_ref<HybridFoo::javaobject> or HybridFoo*.");
+  using Repr = T;
 };
 
-// In order to avoid potentially filling the jni locals table,
-// temporary objects (right now, this is just jstrings) need to be
-// released.  This is done by returning a holder which autoconverts to
-// jstring.  This is only relevant when the jniType is passed down, as
-// in newObjectJavaArgs.
-
-template <typename T>
-inline T callToJni(T&& t) {
-  return t;
-}
 
-inline jstring callToJni(local_ref<jstring>&& sref) {
-  return sref.get();
 }
 
-struct jstring_holder {
-  local_ref<jstring> s_;
-  jstring_holder(const char* s) : s_(make_jstring(s)) {}
-  operator jstring() { return s_.get(); }
-};
+template <typename T, typename Base = detail::BaseHybridClass>
+class HybridClass : public detail::HybridTraits<Base>::CxxBase {
+public:
+  struct JavaPart : JavaClass<JavaPart, typename detail::HybridTraits<Base>::JavaBase> {
+    // At this point, T is incomplete, and so we cannot access
+    // T::kJavaDescriptor directly. jtype_traits support this escape hatch for
+    // such a case.
+    static constexpr const char* kJavaDescriptor = nullptr;
+    static std::string get_instantiated_java_descriptor();
+    static std::string get_instantiated_base_name();
 
-template <typename T, typename Enabled = void>
-struct HybridRoot {};
+    using HybridType = T;
 
-template <typename T>
-struct HybridRoot<T,
-                  typename std::enable_if<!std::is_base_of<BaseHybridClass, T>::value>::type>
-    : public BaseHybridClass {};
+    // This will reach into the java object and extract the C++ instance from
+    // the mHybridData and return it.
+    T* cthis();
 
-}
+    friend class HybridClass;
+  };
 
-template <typename T, typename Base = detail::BaseHybridClass>
-class HybridClass : public Base
-                  , public detail::HybridRoot<Base>
-                  , public JavaClass<T, Base> {
-public:
+  using jhybridobject = typename JavaPart::javaobject;
+  using javaobject = typename JavaPart::javaobject;
   typedef detail::HybridData::javaobject jhybriddata;
-  typedef typename JavaClass<T, Base>::javaobject jhybridobject;
 
-  using JavaClass<T, Base>::javaClassStatic;
-  using JavaClass<T, Base>::javaClassLocal;
-  using JavaClass<T, Base>::javaobject;
-  typedef typename JavaClass<T, Base>::_javaobject _javaobject;
+  static alias_ref<JClass> javaClassStatic() {
+    return JavaPart::javaClassStatic();
+  }
+
+  static local_ref<JClass> javaClassLocal() {
+    std::string className(T::kJavaDescriptor + 1, strlen(T::kJavaDescriptor) - 2);
+    return findClassLocal(className.c_str());
+  }
 
 protected:
   typedef HybridClass HybridBase;
@@ -189,21 +128,20 @@ class HybridClass : public Base
   // This ensures that a C++ hybrid part cannot be created on its own
   // by default.  If a hybrid wants to enable this, it can provide its
   // own public ctor, or change the accessibility of this to public.
-  using Base::Base;
+  using detail::HybridTraits<Base>::CxxBase::CxxBase;
 
   static void registerHybrid(std::initializer_list<NativeMethod> methods) {
     javaClassStatic()->registerNatives(methods);
   }
 
-  static local_ref<jhybriddata> makeHybridData(std::unique_ptr<T> cxxPart) {
-    static auto dataCtor = detail::HybridData::javaClassStatic()->getConstructor<jhybriddata()>();
-    auto hybridData = detail::HybridData::javaClassStatic()->newObject(dataCtor);
-    detail::setNativePointer(hybridData, std::move(cxxPart));
+  static local_ref<detail::HybridData> makeHybridData(std::unique_ptr<T> cxxPart) {
+    auto hybridData = detail::HybridData::create();
+    hybridData->setNativePointer(std::move(cxxPart));
     return hybridData;
   }
 
   template <typename... Args>
-  static local_ref<jhybriddata> makeCxxInstance(Args&&... args) {
+  static local_ref<detail::HybridData> makeCxxInstance(Args&&... args) {
     return makeHybridData(std::unique_ptr<T>(new T(std::forward<Args>(args)...)));
   }
 
@@ -219,31 +157,27 @@ class HybridClass : public Base
   // Exception behavior: This can throw an exception if creating the
   // C++ object fails, or any JNI methods throw.
   template <typename... Args>
-  static local_ref<jhybridobject> newObjectCxxArgs(Args&&... args) {
+  static local_ref<JavaPart> newObjectCxxArgs(Args&&... args) {
     auto hybridData = makeCxxInstance(std::forward<Args>(args)...);
-    static auto ctor = javaClassStatic()->template getConstructor<jhybridobject(jhybriddata)>();
-    return javaClassStatic()->newObject(ctor, hybridData.get());
+    return JavaPart::newInstance(hybridData);
+  }
+
+  // TODO? Create reusable interface for Allocatable classes and use it to
+  // strengthen type-checking (and possibly provide a default
+  // implementation of allocate().)
+  template <typename... Args>
+  static local_ref<jhybridobject> allocateWithCxxArgs(Args&&... args) {
+    auto hybridData = makeCxxInstance(std::forward<Args>(args)...);
+    static auto allocateMethod =
+        javaClassStatic()->template getStaticMethod<jhybridobject(jhybriddata)>("allocate");
+    return allocateMethod(javaClassStatic(), hybridData.get());
   }
 
   // Factory method for creating a hybrid object where the arguments
   // are passed to the java ctor.
   template <typename... Args>
-  static local_ref<jhybridobject> newObjectJavaArgs(Args&&... args) {
-    static auto ctor =
-      javaClassStatic()->template getConstructor<
-        jhybridobject(typename detail::Convert<typename std::decay<Args>::type>::jniType...)>();
-    // This can't use the same impl as Convert::toJniRet because that
-    // function sometimes creates and then releases local_refs, which
-    // could potentially cause the locals table to fill.  Instead, we
-    // use two calls, one which can return a local_ref if needed, and
-    // a second which extracts its value.  The lifetime of the
-    // local_ref is the expression, after which it is destroyed and
-    // the local_ref is cleaned up.
-    auto lref =
-      javaClassStatic()->newObject(
-        ctor, detail::callToJni(
-          detail::Convert<typename std::decay<Args>::type>::toCall(args))...);
-    return lref;
+  static local_ref<JavaPart> newObjectJavaArgs(Args&&... args) {
+    return JavaPart::newInstance(std::move(args)...);
   }
 
   // If a hybrid class throws an exception which derives from
@@ -256,19 +190,38 @@ class HybridClass : public Base
   static void mapException(const std::exception& ex) {}
 };
 
-// Given a *_ref object which refers to a hybrid class, this will reach inside
-// of it, find the mHybridData, extract the C++ instance pointer, cast it to
-// the appropriate type, and return it.
-template <typename T>
-inline typename std::remove_pointer<typename T::PlainJniType>::type::javaClass* cthis(T jthis) {
-  static auto dataField =
-    jthis->getClass()->template getField<detail::HybridData::javaobject>("mHybridData");
+template <typename T, typename B>
+inline T* HybridClass<T, B>::JavaPart::cthis() {
+  static auto field =
+    HybridClass<T, B>::JavaPart::javaClassStatic()->template getField<detail::HybridData::javaobject>("mHybridData");
+  auto hybridData = this->getFieldValue(field);
+  if (!hybridData) {
+    throwNewJavaException("java/lang/NullPointerException", "java.lang.NullPointerException");
+  }
   // I'd like to use dynamic_cast here, but -fno-rtti is the default.
-  auto* value = static_cast<typename std::remove_pointer<typename T::PlainJniType>::type::javaClass*>(
-    detail::getNativePointer(detail::getHybridData(jthis, dataField)));
+  T* value = static_cast<T*>(hybridData->getNativePointer());
   // This would require some serious programmer error.
   FBASSERTMSGF(value != 0, "Incorrect C++ type in hybrid field");
   return value;
+};
+
+template <typename T, typename B>
+/* static */ inline std::string HybridClass<T, B>::JavaPart::get_instantiated_java_descriptor() {
+  return T::kJavaDescriptor;
+}
+
+template <typename T, typename B>
+/* static */ inline std::string HybridClass<T, B>::JavaPart::get_instantiated_base_name() {
+  auto name = get_instantiated_java_descriptor();
+  return name.substr(1, name.size() - 2);
+}
+
+// Given a *_ref object which refers to a hybrid class, this will reach inside
+// of it, find the mHybridData, extract the C++ instance pointer, cast it to
+// the appropriate type, and return it.
+template <typename T>
+inline auto cthis(T jthis) -> decltype(jthis->cthis()) {
+  return jthis->cthis();
 }
 
 void HybridDataOnLoad();
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/Iterator-inl.h b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Iterator-inl.h
new file mode 100644
index 000000000000..206d2b4b17a5
--- /dev/null
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Iterator-inl.h
@@ -0,0 +1,199 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+namespace facebook {
+namespace jni {
+
+namespace detail {
+
+template <typename E>
+struct IteratorHelper : public JavaClass<IteratorHelper<E>> {
+  constexpr static auto kJavaDescriptor = "Lcom/facebook/jni/IteratorHelper;";
+
+  typedef local_ref<E> value_type;
+  typedef ptrdiff_t difference_type;
+  typedef value_type* pointer;
+  typedef value_type& reference;
+  typedef std::forward_iterator_tag iterator_category;
+
+  typedef JavaClass<IteratorHelper<E>> JavaBase_;
+
+  bool hasNext() const {
+    static auto hasNextMethod =
+      JavaBase_::javaClassStatic()->template getMethod<jboolean()>("hasNext");
+    return hasNextMethod(JavaBase_::self());
+  }
+
+  value_type next() {
+    static auto elementField =
+      JavaBase_::javaClassStatic()->template getField<jobject>("mElement");
+    return dynamic_ref_cast<E>(JavaBase_::getFieldValue(elementField));
+  }
+
+  static void reset(value_type& v) {
+    v.reset();
+  }
+};
+
+template <typename K, typename V>
+struct MapIteratorHelper : public JavaClass<MapIteratorHelper<K,V>> {
+  constexpr static auto kJavaDescriptor = "Lcom/facebook/jni/MapIteratorHelper;";
+
+  typedef std::pair<local_ref<K>, local_ref<V>> value_type;
+
+  typedef JavaClass<MapIteratorHelper<K,V>> JavaBase_;
+
+  bool hasNext() const {
+    static auto hasNextMethod =
+      JavaBase_::javaClassStatic()->template getMethod<jboolean()>("hasNext");
+    return hasNextMethod(JavaBase_::self());
+  }
+
+  value_type next() {
+    static auto keyField = JavaBase_::javaClassStatic()->template getField<jobject>("mKey");
+    static auto valueField = JavaBase_::javaClassStatic()->template getField<jobject>("mValue");
+    return std::make_pair(dynamic_ref_cast<K>(JavaBase_::getFieldValue(keyField)),
+                          dynamic_ref_cast<V>(JavaBase_::getFieldValue(valueField)));
+  }
+
+  static void reset(value_type& v) {
+    v.first.reset();
+    v.second.reset();
+  }
+};
+
+template <typename T>
+class Iterator {
+ public:
+  typedef typename T::value_type value_type;
+  typedef ptrdiff_t difference_type;
+  typedef value_type* pointer;
+  typedef value_type& reference;
+  typedef std::input_iterator_tag iterator_category;
+
+  // begin ctor
+  Iterator(global_ref<typename T::javaobject>&& helper)
+      : helper_(std::move(helper))
+      , i_(-1) {
+    ++(*this);
+  }
+
+  // end ctor
+  Iterator()
+      : i_(-1) {}
+
+  bool operator==(const Iterator& it) const { return i_ == it.i_; }
+  bool operator!=(const Iterator& it) const { return !(*this == it); }
+  const value_type& operator*() const { assert(i_ != -1); return entry_; }
+  const value_type* operator->() const { assert(i_ != -1); return &entry_; }
+  Iterator& operator++() {  // preincrement
+    bool hasNext = helper_->hasNext();
+    if (hasNext) {
+      ++i_;
+      entry_ = helper_->next();
+    } else {
+      i_ = -1;
+      helper_->reset(entry_);
+    }
+    return *this;
+  }
+  Iterator operator++(int) {  // postincrement
+    Iterator ret;
+    ret.i_ = i_;
+    ret.entry_ = std::move(entry_);
+    ++(*this);
+    return ret;
+  }
+
+  global_ref<typename T::javaobject> helper_;
+  // set to -1 at end
+  std::ptrdiff_t i_;
+  value_type entry_;
+};
+
+}
+
+template <typename E>
+struct JIterator<E>::Iterator : public detail::Iterator<detail::IteratorHelper<E>> {
+  using detail::Iterator<detail::IteratorHelper<E>>::Iterator;
+};
+
+template <typename E>
+typename JIterator<E>::Iterator JIterator<E>::begin() const {
+  static auto ctor = detail::IteratorHelper<E>::javaClassStatic()->
+    template getConstructor<typename detail::IteratorHelper<E>::javaobject(
+                              typename JIterator<E>::javaobject)>();
+  return Iterator(
+    make_global(
+      detail::IteratorHelper<E>::javaClassStatic()->newObject(ctor, this->self())));
+}
+
+template <typename E>
+typename JIterator<E>::Iterator JIterator<E>::end() const {
+  return Iterator();
+}
+
+template <typename E>
+struct JIterable<E>::Iterator : public detail::Iterator<detail::IteratorHelper<E>> {
+  using detail::Iterator<detail::IteratorHelper<E>>::Iterator;
+};
+
+template <typename E>
+typename JIterable<E>::Iterator JIterable<E>::begin() const {
+  static auto ctor = detail::IteratorHelper<E>::javaClassStatic()->
+    template getConstructor<typename detail::IteratorHelper<E>::javaobject(
+                              typename JIterable<E>::javaobject)>();
+  return Iterator(
+    make_global(
+      detail::IteratorHelper<E>::javaClassStatic()->newObject(ctor, this->self())));
+}
+
+template <typename E>
+typename JIterable<E>::Iterator JIterable<E>::end() const {
+  return Iterator();
+}
+
+template <typename E>
+size_t JCollection<E>::size() const {
+  static auto sizeMethod =
+    JCollection<E>::javaClassStatic()->template getMethod<jint()>("size");
+  return sizeMethod(this->self());
+}
+
+template <typename K, typename V>
+struct JMap<K,V>::Iterator : public detail::Iterator<detail::MapIteratorHelper<K,V>> {
+  using detail::Iterator<detail::MapIteratorHelper<K,V>>::Iterator;
+};
+
+template <typename K, typename V>
+size_t JMap<K,V>::size() const {
+  static auto sizeMethod =
+    JMap<K,V>::javaClassStatic()->template getMethod<jint()>("size");
+  return sizeMethod(this->self());
+}
+
+template <typename K, typename V>
+typename JMap<K,V>::Iterator JMap<K,V>::begin() const {
+  static auto ctor = detail::MapIteratorHelper<K,V>::javaClassStatic()->
+    template getConstructor<typename detail::MapIteratorHelper<K,V>::javaobject(
+                              typename JMap<K,V>::javaobject)>();
+  return Iterator(
+    make_global(
+      detail::MapIteratorHelper<K,V>::javaClassStatic()->newObject(ctor, this->self())));
+}
+
+template <typename K, typename V>
+typename JMap<K,V>::Iterator JMap<K,V>::end() const {
+  return Iterator();
+}
+
+}
+}
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/Iterator.h b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Iterator.h
new file mode 100644
index 000000000000..aa3652666e7d
--- /dev/null
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Iterator.h
@@ -0,0 +1,146 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "CoreClasses.h"
+
+namespace facebook {
+namespace jni {
+
+/**
+ * JavaClass which represents a reference to a java.util.Iterator instance.  It
+ * provides begin()/end() methods to provide C++-style iteration over the
+ * underlying collection.  The class has a template parameter for the element
+ * type, which defaults to jobject.  For example:
+ *
+ * alias_ref<JIterator<jstring>::javaobject> my_iter = ...;
+ *
+ * In the simplest case, it can be used just as alias_ref<JIterator<>::javaobject>,
+ * for example in a method declaration.
+ */
+template <typename E = jobject>
+struct JIterator : JavaClass<JIterator<E>> {
+  constexpr static auto kJavaDescriptor = "Ljava/util/Iterator;";
+
+  struct Iterator;
+
+  /**
+   * To iterate:
+   *
+   * for (const auto& element : *jiter) { ... }
+   *
+   * The JIterator iterator value_type is local_ref<E>, containing a reference
+   * to an element instance.
+   *
+   * If the Iterator returns objects whch are not convertible to the given
+   * element type, iteration will throw a java ClassCastException.
+   *
+   * For example, to convert an iterator over a collection of java strings to
+   * an std::vector of std::strings:
+   *
+   * std::vector<std::string> vs;
+   * for (const auto& elem : *jiter) {
+   *    vs.push_back(elem->toStdString());
+   * }
+   *
+   * Or if you prefer using std algorithms:
+   *
+   * std::vector<std::string> vs;
+   * std::transform(jiter->begin(), jiter->end(), std::back_inserter(vs),
+   *                [](const local_ref<jstring>& elem) { return elem->toStdString(); });
+   *
+   * The iterator is a InputIterator.
+   */
+  Iterator begin() const;
+  Iterator end() const;
+};
+
+/**
+ * Similar to JIterator, except this represents any object which implements the
+ * java.lang.Iterable interface. It will create the Java Iterator as a part of
+ * begin().
+ */
+template <typename E = jobject>
+struct JIterable : JavaClass<JIterable<E>> {
+  constexpr static auto kJavaDescriptor = "Ljava/lang/Iterable;";
+
+  struct Iterator;
+
+  Iterator begin() const;
+  Iterator end() const;
+};
+
+/**
+ * JavaClass types which represent Collection, List, and Set are also provided.
+ * These preserve the Java class heirarchy.
+ */
+template <typename E = jobject>
+struct JCollection : JavaClass<JCollection<E>, JIterable<E>> {
+  constexpr static auto kJavaDescriptor = "Ljava/util/Collection;";
+
+  /**
+   * Returns the number of elements in the collection.
+   */
+  size_t size() const;
+};
+
+template <typename E = jobject>
+struct JList : JavaClass<JList<E>, JCollection<E>> {
+  constexpr static auto kJavaDescriptor = "Ljava/util/List;";
+};
+
+template <typename E = jobject>
+struct JSet : JavaClass<JSet<E>, JCollection<E>> {
+  constexpr static auto kJavaDescriptor = "Ljava/util/Set;";
+};
+
+/**
+ * JavaClass which represents a reference to a java.util.Map instance.  It adds
+ * wrappers around Java methods, including begin()/end() methods to provide
+ * C++-style iteration over the Java Map.  The class has template parameters
+ * for the key and value types, which default to jobject.  For example:
+ *
+ * alias_ref<JMap<jstring, MyJClass::javaobject>::javaobject> my_map = ...;
+ *
+ * In the simplest case, it can be used just as alias_ref<JMap<>::javaobject>,
+ * for example in a method declaration.
+ */
+template <typename K = jobject, typename V = jobject>
+struct JMap : JavaClass<JMap<K,V>> {
+  constexpr static auto kJavaDescriptor = "Ljava/util/Map;";
+
+  struct Iterator;
+
+  /**
+   * Returns the number of pairs in the map.
+   */
+  size_t size() const;
+
+  /**
+   * To iterate over the Map:
+   *
+   * for (const auto& entry : *jmap) { ... }
+   *
+   * The JMap iterator value_type is std::pair<local_ref<K>, local_ref<V>>
+   * containing references to key and value instances.
+   *
+   * If the Map contains objects whch are not convertible to the given key and
+   * value types, iteration will throw a java ClassCastException.
+   *
+   * The iterator is a InputIterator.
+   */
+  Iterator begin() const;
+  Iterator end() const;
+};
+
+}
+}
+
+#include "Iterator-inl.h"
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/Meta-forward.h b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Meta-forward.h
new file mode 100644
index 000000000000..2f524ad062af
--- /dev/null
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Meta-forward.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+namespace facebook {
+namespace jni {
+
+template<typename F>
+class JMethod;
+template<typename F>
+class JStaticMethod;
+template<typename F>
+class JNonvirtualMethod;
+template<typename F>
+class JConstructor;
+template<typename F>
+class JField;
+template<typename F>
+class JStaticField;
+
+/// Type traits for Java types (currently providing Java type descriptors)
+template<typename T>
+struct jtype_traits;
+
+/// Type traits for Java methods (currently providing Java type descriptors)
+template<typename F>
+struct jmethod_traits;
+
+}}
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/Meta-inl.h b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Meta-inl.h
index d51157b16072..38fabc500e35 100644
--- a/ReactAndroid/src/main/jni/first-party/jni/fbjni/Meta-inl.h
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Meta-inl.h
@@ -13,6 +13,8 @@
 
 #include "Common.h"
 #include "Exceptions.h"
+#include "MetaConvert.h"
+#include "References.h"
 
 namespace facebook {
 namespace jni {
@@ -34,19 +36,25 @@ inline jmethodID JMethodBase::getId() const noexcept {
 template<typename... Args>
 inline void JMethod<void(Args...)>::operator()(alias_ref<jobject> self, Args... args) {
   const auto env = internal::getEnv();
-        env->CallVoidMethod(self.get(), getId(), args...);
+  env->CallVoidMethod(
+        self.get(),
+        getId(),
+        detail::callToJni(detail::Convert<typename std::decay<Args>::type>::toCall(args))...);
   FACEBOOK_JNI_THROW_PENDING_EXCEPTION();
 }
 
 #pragma push_macro("DEFINE_PRIMITIVE_CALL")
 #undef DEFINE_PRIMITIVE_CALL
-#define DEFINE_PRIMITIVE_CALL(TYPE, METHOD)                                                 \
-template<typename... Args>                                                                  \
-inline TYPE JMethod<TYPE(Args...)>::operator()(alias_ref<jobject> self, Args... args) {     \
-  const auto env = internal::getEnv();                                                      \
-  auto result = env->Call ## METHOD ## Method(self.get(), getId(), args...);                \
-  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();                                                   \
-  return result;                                                                            \
+#define DEFINE_PRIMITIVE_CALL(TYPE, METHOD)                                                    \
+template<typename... Args>                                                                     \
+inline TYPE JMethod<TYPE(Args...)>::operator()(alias_ref<jobject> self, Args... args) {        \
+  const auto env = internal::getEnv();                                                         \
+  auto result = env->Call ## METHOD ## Method(                                                 \
+        self.get(),                                                                            \
+        getId(),                                                                               \
+        detail::callToJni(detail::Convert<typename std::decay<Args>::type>::toCall(args))...); \
+  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();                                                      \
+  return result;                                                                               \
 }
 
 DEFINE_PRIMITIVE_CALL(jboolean, Boolean)
@@ -59,30 +67,54 @@ DEFINE_PRIMITIVE_CALL(jfloat, Float)
 DEFINE_PRIMITIVE_CALL(jdouble, Double)
 #pragma pop_macro("DEFINE_PRIMITIVE_CALL")
 
-template<typename T, typename... Args>
-inline local_ref<T*> JMethod<T*(Args...)>::operator()(alias_ref<jobject> self, Args... args) {
-  const auto env = internal::getEnv();
-        auto result = env->CallObjectMethod(self.get(), getId(), args...);
-  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();
-        return adopt_local(static_cast<T*>(result));
-}
+
+/// JMethod specialization for references that wraps the return value in a @ref local_ref
+template<typename R, typename... Args>
+class JMethod<R(Args...)> : public JMethodBase {
+ public:
+   // TODO: static_assert is jobject-derived or local_ref jobject
+  using JniRet = typename detail::Convert<typename std::decay<R>::type>::jniType;
+  static_assert(IsPlainJniReference<JniRet>(), "JniRet must be a JNI reference");
+  using JMethodBase::JMethodBase;
+  JMethod() noexcept {};
+  JMethod(const JMethod& other) noexcept = default;
+
+  /// Invoke a method and return a local reference wrapping the result
+  local_ref<JniRet> operator()(alias_ref<jobject> self, Args... args) {
+    const auto env = internal::getEnv();
+    auto result = env->CallObjectMethod(
+        self.get(),
+        getId(),
+        detail::callToJni(detail::Convert<typename std::decay<Args>::type>::toCall(args))...);
+    FACEBOOK_JNI_THROW_PENDING_EXCEPTION();
+    return adopt_local(static_cast<JniRet>(result));
+  }
+
+  friend class JClass;
+};
 
 template<typename... Args>
 inline void JStaticMethod<void(Args...)>::operator()(alias_ref<jclass> cls, Args... args) {
   const auto env = internal::getEnv();
-  env->CallStaticVoidMethod(cls.get(), getId(), args...);
+  env->CallStaticVoidMethod(
+        cls.get(),
+        getId(),
+        detail::callToJni(detail::Convert<typename std::decay<Args>::type>::toCall(args))...);
   FACEBOOK_JNI_THROW_PENDING_EXCEPTION();
 }
 
 #pragma push_macro("DEFINE_PRIMITIVE_STATIC_CALL")
 #undef DEFINE_PRIMITIVE_STATIC_CALL
-#define DEFINE_PRIMITIVE_STATIC_CALL(TYPE, METHOD)                                          \
-template<typename... Args>                                                                  \
-inline TYPE JStaticMethod<TYPE(Args...)>::operator()(alias_ref<jclass> cls, Args... args) { \
-  const auto env = internal::getEnv();                                                      \
-  auto result = env->CallStatic ## METHOD ## Method(cls.get(), getId(), args...);           \
-  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();                                                   \
-        return result;                                                                      \
+#define DEFINE_PRIMITIVE_STATIC_CALL(TYPE, METHOD)                                             \
+template<typename... Args>                                                                     \
+inline TYPE JStaticMethod<TYPE(Args...)>::operator()(alias_ref<jclass> cls, Args... args) {    \
+  const auto env = internal::getEnv();                                                         \
+  auto result = env->CallStatic ## METHOD ## Method(                                           \
+        cls.get(),                                                                             \
+        getId(),                                                                               \
+        detail::callToJni(detail::Convert<typename std::decay<Args>::type>::toCall(args))...); \
+  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();                                                      \
+        return result;                                                                         \
 }
 
 DEFINE_PRIMITIVE_STATIC_CALL(jboolean, Boolean)
@@ -95,33 +127,57 @@ DEFINE_PRIMITIVE_STATIC_CALL(jfloat, Float)
 DEFINE_PRIMITIVE_STATIC_CALL(jdouble, Double)
 #pragma pop_macro("DEFINE_PRIMITIVE_STATIC_CALL")
 
-template<typename T, typename... Args>
-inline local_ref<T*> JStaticMethod<T*(Args...)>::operator()(alias_ref<jclass> cls, Args... args) {
-  const auto env = internal::getEnv();
-  auto result = env->CallStaticObjectMethod(cls.get(), getId(), args...);
-  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();
-  return adopt_local(static_cast<T*>(result));
-}
+/// JStaticMethod specialization for references that wraps the return value in a @ref local_ref
+template<typename R, typename... Args>
+class JStaticMethod<R(Args...)> : public JMethodBase {
+
+ public:
+  using JniRet = typename detail::Convert<typename std::decay<R>::type>::jniType;
+  static_assert(IsPlainJniReference<JniRet>(), "T* must be a JNI reference");
+  using JMethodBase::JMethodBase;
+  JStaticMethod() noexcept {};
+  JStaticMethod(const JStaticMethod& other) noexcept = default;
+
+  /// Invoke a method and return a local reference wrapping the result
+  local_ref<JniRet> operator()(alias_ref<jclass> cls, Args... args) {
+    const auto env = internal::getEnv();
+    auto result = env->CallStaticObjectMethod(
+          cls.get(),
+          getId(),
+          detail::callToJni(detail::Convert<typename std::decay<Args>::type>::toCall(args))...);
+    FACEBOOK_JNI_THROW_PENDING_EXCEPTION();
+    return adopt_local(static_cast<JniRet>(result));
+  }
 
+  friend class JClass;
+};
 
 template<typename... Args>
 inline void
-JNonvirtualMethod<void(Args...)>::operator()(alias_ref<jobject> self, jclass cls, Args... args) {
+JNonvirtualMethod<void(Args...)>::operator()(alias_ref<jobject> self, alias_ref<jclass> cls, Args... args) {
   const auto env = internal::getEnv();
-  env->CallNonvirtualVoidMethod(self.get(), cls, getId(), args...);
+  env->CallNonvirtualVoidMethod(
+        self.get(),
+        cls.get(),
+        getId(),
+        detail::callToJni(detail::Convert<typename std::decay<Args>::type>::toCall(args))...);
   FACEBOOK_JNI_THROW_PENDING_EXCEPTION();
 }
 
 #pragma push_macro("DEFINE_PRIMITIVE_NON_VIRTUAL_CALL")
 #undef DEFINE_PRIMITIVE_NON_VIRTUAL_CALL
-#define DEFINE_PRIMITIVE_NON_VIRTUAL_CALL(TYPE, METHOD)                                           \
-template<typename... Args>                                                                        \
-inline TYPE                                                                                       \
-JNonvirtualMethod<TYPE(Args...)>::operator()(alias_ref<jobject> self, jclass cls, Args... args) { \
-  const auto env = internal::getEnv();                                                            \
-  auto result = env->CallNonvirtual ## METHOD ## Method(self.get(), cls, getId(), args...);       \
-  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();                                                         \
-  return result;                                                                                  \
+#define DEFINE_PRIMITIVE_NON_VIRTUAL_CALL(TYPE, METHOD)                                                      \
+template<typename... Args>                                                                                   \
+inline TYPE                                                                                                  \
+JNonvirtualMethod<TYPE(Args...)>::operator()(alias_ref<jobject> self, alias_ref<jclass> cls, Args... args) { \
+  const auto env = internal::getEnv();                                                                       \
+  auto result = env->CallNonvirtual ## METHOD ## Method(                                                     \
+        self.get(),                                                                                          \
+        cls.get(),                                                                                           \
+        getId(),                                                                                             \
+        detail::callToJni(detail::Convert<typename std::decay<Args>::type>::toCall(args))...);               \
+  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();                                                                    \
+  return result;                                                                                             \
 }
 
 DEFINE_PRIMITIVE_NON_VIRTUAL_CALL(jboolean, Boolean)
@@ -134,77 +190,31 @@ DEFINE_PRIMITIVE_NON_VIRTUAL_CALL(jfloat, Float)
 DEFINE_PRIMITIVE_NON_VIRTUAL_CALL(jdouble, Double)
 #pragma pop_macro("DEFINE_PRIMITIVE_NON_VIRTUAL_CALL")
 
-template<typename T, typename... Args>
-inline local_ref<T*> JNonvirtualMethod<T*(Args...)>::operator()(
-    alias_ref<jobject> self,
-    jclass cls,
-    Args... args) {
-  const auto env = internal::getEnv();
-  auto result = env->CallNonvirtualObjectMethod(self.get(), cls, getId(), args...);
-  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();
-  return adopt_local(static_cast<T*>(result));
-}
-
-
-// jtype_traits ////////////////////////////////////////////////////////////////////////////////////
-
-/// The generic way to associate a descriptor to a type is to look it up in the
-/// corresponding @ref JObjectWrapper specialization. This makes it easy to add
-/// support for your user defined type.
-template<typename T>
-struct jtype_traits {
-  // The jni type signature (described at
-  // http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/types.html).
-  static std::string descriptor() {
-    static const auto descriptor = JObjectWrapper<T>::kJavaDescriptor != nullptr ?
-      std::string{JObjectWrapper<T>::kJavaDescriptor} :
-      JObjectWrapper<T>::get_instantiated_java_descriptor();
-    return descriptor;
-  }
-
-  // The signature used for class lookups. See
-  // http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#getName().
-  static std::string base_name() {
-    if (JObjectWrapper<T>::kJavaDescriptor != nullptr) {
-      std::string base_name = JObjectWrapper<T>::kJavaDescriptor;
-      return base_name.substr(1, base_name.size() - 2);
-    }
-    return JObjectWrapper<T>::get_instantiated_java_descriptor();
+/// JNonvirtualMethod specialization for references that wraps the return value in a @ref local_ref
+template<typename R, typename... Args>
+class JNonvirtualMethod<R(Args...)> : public JMethodBase {
+ public:
+  using JniRet = typename detail::Convert<typename std::decay<R>::type>::jniType;
+  static_assert(IsPlainJniReference<JniRet>(), "T* must be a JNI reference");
+  using JMethodBase::JMethodBase;
+  JNonvirtualMethod() noexcept {};
+  JNonvirtualMethod(const JNonvirtualMethod& other) noexcept = default;
+
+  /// Invoke a method and return a local reference wrapping the result
+  local_ref<JniRet> operator()(alias_ref<jobject> self, alias_ref<jclass> cls, Args... args){
+    const auto env = internal::getEnv();
+    auto result = env->CallNonvirtualObjectMethod(
+          self.get(),
+          cls.get(),
+          getId(),
+          detail::callToJni(detail::Convert<typename std::decay<Args>::type>::toCall(args))...);
+    FACEBOOK_JNI_THROW_PENDING_EXCEPTION();
+    return adopt_local(static_cast<JniRet>(result));
   }
-};
 
-#pragma push_macro("DEFINE_FIELD_AND_ARRAY_TRAIT")
-#undef DEFINE_FIELD_AND_ARRAY_TRAIT
-
-#define DEFINE_FIELD_AND_ARRAY_TRAIT(TYPE, DSC)                     \
-template<>                                                          \
-struct jtype_traits<TYPE> {                                         \
-  static std::string descriptor() { return std::string{#DSC}; }     \
-  static std::string base_name() { return descriptor(); }           \
-};                                                                  \
-template<>                                                          \
-struct jtype_traits<TYPE ## Array> {                                \
-  static std::string descriptor() { return std::string{"[" #DSC}; } \
-  static std::string base_name() { return descriptor(); }           \
+  friend class JClass;
 };
 
-// There is no voidArray, handle that without the macro.
-template<>
-struct jtype_traits<void> {
-  static std::string descriptor() { return std::string{"V"}; };
-};
-
-DEFINE_FIELD_AND_ARRAY_TRAIT(jboolean, Z)
-DEFINE_FIELD_AND_ARRAY_TRAIT(jbyte,    B)
-DEFINE_FIELD_AND_ARRAY_TRAIT(jchar,    C)
-DEFINE_FIELD_AND_ARRAY_TRAIT(jshort,   S)
-DEFINE_FIELD_AND_ARRAY_TRAIT(jint,     I)
-DEFINE_FIELD_AND_ARRAY_TRAIT(jlong,    J)
-DEFINE_FIELD_AND_ARRAY_TRAIT(jfloat,   F)
-DEFINE_FIELD_AND_ARRAY_TRAIT(jdouble,  D)
-
-#pragma pop_macro("DEFINE_FIELD_AND_ARRAY_TRAIT")
-
 
 // JField<T> ///////////////////////////////////////////////////////////////////////////////////////
 
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/Meta.h b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Meta.h
index de1bde0d542b..23c7450506bb 100644
--- a/ReactAndroid/src/main/jni/first-party/jni/fbjni/Meta.h
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Meta.h
@@ -19,11 +19,25 @@
 
 #include <jni.h>
 
-#include "References.h"
+#include "References-forward.h"
+
+#ifdef __ANDROID__
+# include <android/log.h>
+# define XLOG_TAG "fb-jni"
+# define XLOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, XLOG_TAG, __VA_ARGS__)
+# define XLOGD(...) __android_log_print(ANDROID_LOG_DEBUG, XLOG_TAG, __VA_ARGS__)
+# define XLOGI(...) __android_log_print(ANDROID_LOG_INFO, XLOG_TAG, __VA_ARGS__)
+# define XLOGW(...) __android_log_print(ANDROID_LOG_WARN, XLOG_TAG, __VA_ARGS__)
+# define XLOGE(...) __android_log_print(ANDROID_LOG_ERROR, XLOG_TAG, __VA_ARGS__)
+# define XLOGWTF(...) __android_log_print(ANDROID_LOG_FATAL, XLOG_TAG, __VA_ARGS__)
+#endif
 
 namespace facebook {
 namespace jni {
 
+class JObject;
+
+
 /// Wrapper of a jmethodID. Provides a common base for JMethod specializations
 class JMethodBase {
  public:
@@ -65,7 +79,7 @@ class JMethod<TYPE(Args...)> : public JMethodBase {
                                                                                  \
   TYPE operator()(alias_ref<jobject> self, Args... args);                        \
                                                                                  \
-  friend class JObjectWrapper<jclass>;                                           \
+  friend class JClass;                                                           \
 }
 
 DEFINE_PRIMITIVE_METHOD_CLASS(void);
@@ -82,26 +96,15 @@ DEFINE_PRIMITIVE_METHOD_CLASS(jdouble);
 /// @endcond
 
 
-/// JMethod specialization for references that wraps the return value in a @ref local_ref
-template<typename T, typename... Args>
-class JMethod<T*(Args...)> : public JMethodBase {
- public:
-  static_assert(IsPlainJniReference<T*>(), "T* must be a JNI reference");
-
-  using JMethodBase::JMethodBase;
-  JMethod() noexcept {};
-  JMethod(const JMethod& other) noexcept = default;
-
-  /// Invoke a method and return a local reference wrapping the result
-  local_ref<T*> operator()(alias_ref<jobject> self, Args... args);
-
-  friend class JObjectWrapper<jclass>;
-};
-
-
 /// Convenience type representing constructors
+/// These should only be used with JClass::getConstructor and JClass::newObject.
 template<typename F>
-using JConstructor = JMethod<F>;
+struct JConstructor : private JMethod<F> {
+  using JMethod<F>::JMethod;
+ private:
+  JConstructor(const JMethod<F>& other) : JMethod<F>(other.getId()) {}
+  friend class JClass;
+};
 
 /// Representation of a jStaticMethodID
 template<typename F>
@@ -126,7 +129,7 @@ class JStaticMethod<TYPE(Args...)> : public JMethodBase {                   \
                                                                             \
   TYPE operator()(alias_ref<jclass> cls, Args... args);                     \
                                                                             \
-  friend class JObjectWrapper<jclass>;                                      \
+  friend class JClass;                                                      \
 }
 
 DEFINE_PRIMITIVE_STATIC_METHOD_CLASS(void);
@@ -143,22 +146,6 @@ DEFINE_PRIMITIVE_STATIC_METHOD_CLASS(jdouble);
 /// @endcond
 
 
-/// JStaticMethod specialization for references that wraps the return value in a @ref local_ref
-template<typename T, typename... Args>
-class JStaticMethod<T*(Args...)> : public JMethodBase {
-  static_assert(IsPlainJniReference<T*>(), "T* must be a JNI reference");
-
- public:
-  using JMethodBase::JMethodBase;
-  JStaticMethod() noexcept {};
-  JStaticMethod(const JStaticMethod& other) noexcept = default;
-
-  /// Invoke a method and return a local reference wrapping the result
-  local_ref<T*> operator()(alias_ref<jclass> cls, Args... args);
-
-  friend class JObjectWrapper<jclass>;
-};
-
 /// Representation of a jNonvirtualMethodID
 template<typename F>
 class JNonvirtualMethod;
@@ -180,9 +167,9 @@ class JNonvirtualMethod<TYPE(Args...)> : public JMethodBase {               \
   JNonvirtualMethod() noexcept {};                                          \
   JNonvirtualMethod(const JNonvirtualMethod& other) noexcept = default;     \
                                                                             \
-  TYPE operator()(alias_ref<jobject> self, jclass cls, Args... args);       \
+  TYPE operator()(alias_ref<jobject> self, alias_ref<jclass> cls, Args... args);       \
                                                                             \
-  friend class JObjectWrapper<jclass>;                                      \
+  friend class JClass;                                                      \
 }
 
 DEFINE_PRIMITIVE_NON_VIRTUAL_METHOD_CLASS(void);
@@ -199,23 +186,6 @@ DEFINE_PRIMITIVE_NON_VIRTUAL_METHOD_CLASS(jdouble);
 /// @endcond
 
 
-/// JNonvirtualMethod specialization for references that wraps the return value in a @ref local_ref
-template<typename T, typename... Args>
-class JNonvirtualMethod<T*(Args...)> : public JMethodBase {
-  static_assert(IsPlainJniReference<T*>(), "T* must be a JNI reference");
-
- public:
-  using JMethodBase::JMethodBase;
-  JNonvirtualMethod() noexcept {};
-  JNonvirtualMethod(const JNonvirtualMethod& other) noexcept = default;
-
-  /// Invoke a method and return a local reference wrapping the result
-  local_ref<T*> operator()(alias_ref<jobject> self, jclass cls, Args... args);
-
-  friend class JObjectWrapper<jclass>;
-};
-
-
 /**
  * JField represents typed fields and simplifies their access. Note that object types return
  * raw pointers which generally should promptly get a wrap_local treatment.
@@ -245,7 +215,7 @@ class JField {
   /// @pre object != nullptr
   void set(jobject object, T value) noexcept;
 
-  friend class JObjectWrapper<jobject>;
+  friend class JObject;
 };
 
 
@@ -278,20 +248,11 @@ class JStaticField {
   /// @pre object != nullptr
   void set(jclass jcls, T value) noexcept;
 
-  friend class JObjectWrapper<jclass>;
-
+  friend class JClass;
+  friend class JObject;
 };
 
 
-/// Type traits for Java types (currently providing Java type descriptors)
-template<typename T>
-struct jtype_traits;
-
-
-/// Type traits for Java methods (currently providing Java type descriptors)
-template<typename F>
-struct jmethod_traits;
-
 /// Template magic to provide @ref jmethod_traits
 template<typename R, typename... Args>
 struct jmethod_traits<R(Args...)> {
@@ -299,4 +260,75 @@ struct jmethod_traits<R(Args...)> {
   static std::string constructor_descriptor();
 };
 
+
+// jtype_traits ////////////////////////////////////////////////////////////////////////////////////
+
+template<typename T>
+struct jtype_traits {
+private:
+  using Repr = ReprType<T>;
+public:
+  // The jni type signature (described at
+  // http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/types.html).
+  static std::string descriptor() {
+    std::string descriptor;
+    if (Repr::kJavaDescriptor == nullptr) {
+      descriptor = Repr::get_instantiated_java_descriptor();
+    } else {
+      descriptor = Repr::kJavaDescriptor;
+    }
+    return descriptor;
+  }
+
+  // The signature used for class lookups. See
+  // http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#getName().
+  static std::string base_name() {
+    if (Repr::kJavaDescriptor != nullptr) {
+      std::string base_name = Repr::kJavaDescriptor;
+      return base_name.substr(1, base_name.size() - 2);
+    }
+    return Repr::get_instantiated_base_name();
+  }
+};
+
+#pragma push_macro("DEFINE_FIELD_AND_ARRAY_TRAIT")
+#undef DEFINE_FIELD_AND_ARRAY_TRAIT
+
+#define DEFINE_FIELD_AND_ARRAY_TRAIT(TYPE, DSC)                     \
+template<>                                                          \
+struct jtype_traits<TYPE> {                                         \
+  static std::string descriptor() { return std::string{#DSC}; }     \
+  static std::string base_name() { return descriptor(); }           \
+  using array_type = TYPE ## Array;                                 \
+};                                                                  \
+template<>                                                          \
+struct jtype_traits<TYPE ## Array> {                                \
+  static std::string descriptor() { return std::string{"[" #DSC}; } \
+  static std::string base_name() { return descriptor(); }           \
+  using entry_type = TYPE;                                          \
+};
+
+// There is no voidArray, handle that without the macro.
+template<>
+struct jtype_traits<void> {
+  static std::string descriptor() { return std::string{"V"}; };
+};
+
+DEFINE_FIELD_AND_ARRAY_TRAIT(jboolean, Z)
+DEFINE_FIELD_AND_ARRAY_TRAIT(jbyte,    B)
+DEFINE_FIELD_AND_ARRAY_TRAIT(jchar,    C)
+DEFINE_FIELD_AND_ARRAY_TRAIT(jshort,   S)
+DEFINE_FIELD_AND_ARRAY_TRAIT(jint,     I)
+DEFINE_FIELD_AND_ARRAY_TRAIT(jlong,    J)
+DEFINE_FIELD_AND_ARRAY_TRAIT(jfloat,   F)
+DEFINE_FIELD_AND_ARRAY_TRAIT(jdouble,  D)
+
+#pragma pop_macro("DEFINE_FIELD_AND_ARRAY_TRAIT")
+
+
+template <typename T>
+struct jmethod_traits_from_cxx;
+
 }}
+
+#include "Meta-inl.h"
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/MetaConvert.h b/ReactAndroid/src/main/jni/first-party/jni/fbjni/MetaConvert.h
new file mode 100644
index 000000000000..33027c7e96b3
--- /dev/null
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/MetaConvert.h
@@ -0,0 +1,122 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+#include <jni.h>
+
+#include "Common.h"
+#include "References.h"
+
+namespace facebook {
+namespace jni {
+
+namespace detail {
+
+// In order to avoid potentially filling the jni locals table,
+// temporary objects (right now, this is just jstrings) need to be
+// released. This is done by returning a holder which autoconverts to
+// jstring.
+template <typename T>
+inline T callToJni(T&& t) {
+  return t;
+}
+
+template <typename T>
+inline JniType<T> callToJni(local_ref<T>&& sref) {
+  return sref.get();
+}
+
+// Normally, pass through types unmolested.
+template <typename T, typename Enabled = void>
+struct Convert {
+  typedef T jniType;
+  static jniType fromJni(jniType t) {
+    return t;
+  }
+  static jniType toJniRet(jniType t) {
+    return t;
+  }
+  static jniType toCall(jniType t) {
+    return t;
+  }
+};
+
+// This is needed for return conversion
+template <>
+struct Convert<void> {
+  typedef void jniType;
+};
+
+// jboolean is an unsigned char, not a bool. Allow it to work either way.
+template<>
+struct Convert<bool> {
+  typedef jboolean jniType;
+  static bool fromJni(jniType t) {
+    return t;
+  }
+  static jniType toJniRet(bool t) {
+    return t;
+  }
+  static jniType toCall(bool t) {
+    return t;
+  }
+};
+
+// convert to alias_ref<T> from T
+template <typename T>
+struct Convert<alias_ref<T>> {
+  typedef JniType<T> jniType;
+  static alias_ref<jniType> fromJni(jniType t) {
+    return wrap_alias(t);
+  }
+  static jniType toJniRet(alias_ref<jniType> t) {
+    return t.get();
+  }
+  static jniType toCall(alias_ref<jniType> t) {
+    return t.get();
+  }
+};
+
+// convert return from local_ref<T>
+template <typename T>
+struct Convert<local_ref<T>> {
+  typedef JniType<T> jniType;
+  // No automatic synthesis of local_ref
+  static jniType toJniRet(local_ref<jniType> t) {
+    return t.release();
+  }
+  static jniType toCall(local_ref<jniType> t) {
+    return t.get();
+  }
+};
+
+// convert return from global_ref<T>
+template <typename T>
+struct Convert<global_ref<T>> {
+  typedef JniType<T> jniType;
+  // No automatic synthesis of global_ref
+  static jniType toJniRet(global_ref<jniType> t) {
+    return t.get();
+  }
+  static jniType toCall(global_ref<jniType> t) {
+    return t.get();
+  }
+};
+
+template <typename T> struct jni_sig_from_cxx_t;
+template <typename R, typename... Args>
+struct jni_sig_from_cxx_t<R(Args...)> {
+  using JniRet = typename Convert<typename std::decay<R>::type>::jniType;
+  using JniSig = JniRet(typename Convert<typename std::decay<Args>::type>::jniType...);
+};
+
+template <typename T>
+using jni_sig_from_cxx = typename jni_sig_from_cxx_t<T>::JniSig;
+
+} // namespace detail
+
+template <typename R, typename... Args>
+struct jmethod_traits_from_cxx<R(Args...)> : jmethod_traits<detail::jni_sig_from_cxx<R(Args...)>> {
+};
+
+}}
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/ReferenceAllocators-inl.h b/ReactAndroid/src/main/jni/first-party/jni/fbjni/ReferenceAllocators-inl.h
index d60c90022723..5f69a3b41503 100644
--- a/ReactAndroid/src/main/jni/first-party/jni/fbjni/ReferenceAllocators-inl.h
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/ReferenceAllocators-inl.h
@@ -14,7 +14,6 @@
 #include <atomic>
 
 #include "Exceptions.h"
-#include "References.h"
 
 namespace facebook {
 namespace jni {
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/References-forward.h b/ReactAndroid/src/main/jni/first-party/jni/fbjni/References-forward.h
new file mode 100644
index 000000000000..8dabf67cb62e
--- /dev/null
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/References-forward.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "ReferenceAllocators.h"
+
+namespace facebook {
+namespace jni {
+
+template<typename T, typename Enable = void>
+class JObjectWrapper;
+
+namespace detail {
+struct JObjectBase {
+  jobject get() const noexcept;
+  void set(jobject reference) noexcept;
+  jobject this_;
+};
+
+// RefReprType maps a type to the representation used by fbjni smart references.
+template <typename T, typename Enable = void>
+struct RefReprType;
+
+template <typename T>
+struct JavaObjectType;
+
+template <typename T>
+struct ReprAccess;
+}
+
+// Given T, either a jobject-like type or a JavaClass-derived type, ReprType<T>
+// is the corresponding JavaClass-derived type and JniType<T> is the
+// jobject-like type.
+template <typename T>
+using ReprType = typename detail::RefReprType<T>::type;
+
+template <typename T>
+using JniType = typename detail::JavaObjectType<T>::type;
+
+template<typename T, typename Alloc>
+class base_owned_ref;
+
+template<typename T, typename Alloc>
+class basic_strong_ref;
+
+template<typename T>
+class weak_ref;
+
+template<typename T>
+class alias_ref;
+
+/// A smart unique reference owning a local JNI reference
+template<typename T>
+using local_ref = basic_strong_ref<T, LocalReferenceAllocator>;
+
+/// A smart unique reference owning a global JNI reference
+template<typename T>
+using global_ref = basic_strong_ref<T, GlobalReferenceAllocator>;
+
+}} // namespace facebook::jni
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/References-inl.h b/ReactAndroid/src/main/jni/first-party/jni/fbjni/References-inl.h
index bae3d5d636d1..2176d1e022ea 100644
--- a/ReactAndroid/src/main/jni/first-party/jni/fbjni/References-inl.h
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/References-inl.h
@@ -16,48 +16,86 @@ namespace facebook {
 namespace jni {
 
 template<typename T>
-inline enable_if_t<IsPlainJniReference<T>(), local_ref<T>> adopt_local(T ref) noexcept {
-  return local_ref<T>{ref};
+inline enable_if_t<IsPlainJniReference<T>(), T> getPlainJniReference(T ref) {
+  return ref;
 }
 
 template<typename T>
-inline enable_if_t<IsPlainJniReference<T>(), global_ref<T>> adopt_global(T ref) noexcept {
-  return global_ref<T>{ref};
+inline JniType<T> getPlainJniReference(alias_ref<T> ref) {
+  return ref.get();
 }
 
-template<typename T>
-inline enable_if_t<IsPlainJniReference<T>(), weak_ref<T>> adopt_weak_global(T ref) noexcept {
-  return weak_ref<T>{ref};
+template<typename T, typename A>
+inline JniType<T> getPlainJniReference(const base_owned_ref<T, A>& ref) {
+  return ref.get();
 }
 
 
-template<typename T>
-inline enable_if_t<IsPlainJniReference<T>(), alias_ref<T>> wrap_alias(T ref) noexcept {
-  return alias_ref<T>(ref);
+namespace detail {
+template <typename Repr>
+struct ReprAccess {
+  using javaobject = JniType<Repr>;
+  static void set(Repr& repr, javaobject obj) noexcept {
+    repr.JObjectBase::set(obj);
+  }
+  static javaobject get(const Repr& repr) {
+    return static_cast<javaobject>(repr.JObject::get());
+  }
+};
+
+namespace {
+template <typename Repr>
+void StaticAssertValidRepr() noexcept {
+  static_assert(std::is_base_of<JObject, Repr>::value,
+      "A smart ref representation must be derived from JObject.");
+  static_assert(IsPlainJniReference<JniType<Repr>>(), "T must be a JNI reference");
+  static_assert(sizeof(Repr) == sizeof(JObjectBase), "");
+  static_assert(alignof(Repr) == alignof(JObjectBase), "");
+}
 }
 
+template <typename Repr>
+ReprStorage<Repr>::ReprStorage(JniType<Repr> obj) noexcept {
+  StaticAssertValidRepr<Repr>();
+  set(obj);
+}
 
-template<typename T>
-enable_if_t<IsPlainJniReference<T>(), alias_ref<T>> wrap_alias(T ref) noexcept;
+template <typename Repr>
+void ReprStorage<Repr>::set(JniType<Repr> obj) noexcept {
+  new (&storage_) Repr;
+  ReprAccess<Repr>::set(get(), obj);
+}
 
+template <typename Repr>
+Repr& ReprStorage<Repr>::get() noexcept {
+  return *reinterpret_cast<Repr*>(&storage_);
+}
 
-template<typename T>
-inline enable_if_t<IsPlainJniReference<T>(), T> getPlainJniReference(T ref) {
-  return ref;
+template <typename Repr>
+const Repr& ReprStorage<Repr>::get() const noexcept {
+  return *reinterpret_cast<const Repr*>(&storage_);
 }
 
-template<typename T>
-inline T getPlainJniReference(alias_ref<T> ref) {
-  return ref.get();
+template <typename Repr>
+JniType<Repr> ReprStorage<Repr>::jobj() const noexcept {
+  ReprAccess<Repr>::get(get());
+  return ReprAccess<Repr>::get(get());
 }
 
-template<typename T, typename A>
-inline T getPlainJniReference(const base_owned_ref<T, A>& ref) {
-  return ref.getPlainJniReference();
+template <typename Repr>
+void ReprStorage<Repr>::swap(ReprStorage& other) noexcept {
+  StaticAssertValidRepr<Repr>();
+  using std::swap;
+  swap(get(), other.get());
 }
 
+inline void JObjectBase::set(jobject reference) noexcept {
+  this_ = reference;
+}
 
-namespace internal {
+inline jobject JObjectBase::get() const noexcept {
+  return this_;
+}
 
 template<typename T, typename Alloc>
 enable_if_t<IsNonWeakReference<T>(), plain_jni_reference_t<T>> make_ref(const T& reference) {
@@ -77,24 +115,53 @@ enable_if_t<IsNonWeakReference<T>(), plain_jni_reference_t<T>> make_ref(const T&
   return static_cast<plain_jni_reference_t<T>>(ref);
 }
 
+} // namespace detail
+
+template<typename T>
+inline local_ref<T> adopt_local(T ref) noexcept {
+  static_assert(IsPlainJniReference<T>(), "T must be a plain jni reference");
+  return local_ref<T>{ref};
+}
+
+template<typename T>
+inline global_ref<T> adopt_global(T ref) noexcept {
+  static_assert(IsPlainJniReference<T>(), "T must be a plain jni reference");
+  return global_ref<T>{ref};
+}
+
+template<typename T>
+inline weak_ref<T> adopt_weak_global(T ref) noexcept {
+  static_assert(IsPlainJniReference<T>(), "T must be a plain jni reference");
+  return weak_ref<T>{ref};
+}
+
+
+template<typename T>
+inline enable_if_t<IsPlainJniReference<T>(), alias_ref<T>> wrap_alias(T ref) noexcept {
+  return alias_ref<T>(ref);
 }
 
+
+template<typename T>
+enable_if_t<IsPlainJniReference<T>(), alias_ref<T>> wrap_alias(T ref) noexcept;
+
+
 template<typename T>
 enable_if_t<IsNonWeakReference<T>(), local_ref<plain_jni_reference_t<T>>>
 make_local(const T& ref) {
-  return adopt_local(internal::make_ref<T, LocalReferenceAllocator>(ref));
+  return adopt_local(detail::make_ref<T, LocalReferenceAllocator>(ref));
 }
 
 template<typename T>
 enable_if_t<IsNonWeakReference<T>(), global_ref<plain_jni_reference_t<T>>>
 make_global(const T& ref) {
-  return adopt_global(internal::make_ref<T, GlobalReferenceAllocator>(ref));
+  return adopt_global(detail::make_ref<T, GlobalReferenceAllocator>(ref));
 }
 
 template<typename T>
 enable_if_t<IsNonWeakReference<T>(), weak_ref<plain_jni_reference_t<T>>>
 make_weak(const T& ref) {
-  return adopt_weak_global(internal::make_ref<T, WeakGlobalReferenceAllocator>(ref));
+  return adopt_weak_global(detail::make_ref<T, WeakGlobalReferenceAllocator>(ref));
 }
 
 template<typename T1, typename T2>
@@ -113,69 +180,67 @@ operator!=(const T1& a, const T2& b) {
 // base_owned_ref ///////////////////////////////////////////////////////////////////////
 
 template<typename T, typename Alloc>
-inline constexpr base_owned_ref<T, Alloc>::base_owned_ref() noexcept
-  : object_{nullptr}
+inline base_owned_ref<T, Alloc>::base_owned_ref() noexcept
+  : base_owned_ref(nullptr)
 {}
 
 template<typename T, typename Alloc>
-inline constexpr base_owned_ref<T, Alloc>::base_owned_ref(
-    std::nullptr_t t) noexcept
-  : object_{nullptr}
+inline base_owned_ref<T, Alloc>::base_owned_ref(std::nullptr_t t) noexcept
+  : base_owned_ref(static_cast<javaobject>(nullptr))
 {}
 
 template<typename T, typename Alloc>
-inline base_owned_ref<T, Alloc>::base_owned_ref(
-    const base_owned_ref& other)
-  : object_{Alloc{}.newReference(other.getPlainJniReference())}
+inline base_owned_ref<T, Alloc>::base_owned_ref(const base_owned_ref& other)
+  : storage_{static_cast<javaobject>(Alloc{}.newReference(other.get()))}
 {}
 
 template<typename T, typename Alloc>
 template<typename U>
 inline base_owned_ref<T, Alloc>::base_owned_ref(const base_owned_ref<U, Alloc>& other)
-  : object_{Alloc{}.newReference(other.getPlainJniReference())}
+  : storage_{static_cast<javaobject>(Alloc{}.newReference(other.get()))}
 {}
 
 template<typename T, typename Alloc>
 inline facebook::jni::base_owned_ref<T, Alloc>::base_owned_ref(
-    T reference) noexcept
-  : object_{reference} {
+    javaobject reference) noexcept
+  : storage_(reference) {
   assert(Alloc{}.verifyReference(reference));
-  internal::dbglog("New wrapped ref=%p this=%p", getPlainJniReference(), this);
+  internal::dbglog("New wrapped ref=%p this=%p", get(), this);
 }
 
 template<typename T, typename Alloc>
 inline base_owned_ref<T, Alloc>::base_owned_ref(
     base_owned_ref<T, Alloc>&& other) noexcept
-  : object_{other.object_} {
-  internal::dbglog("New move from ref=%p other=%p", other.getPlainJniReference(), &other);
-  internal::dbglog("New move to ref=%p this=%p", getPlainJniReference(), this);
-  // JObjectWrapper is a simple type and does not support move semantics so we explicitly
+  : storage_(other.get()) {
+  internal::dbglog("New move from ref=%p other=%p", other.get(), &other);
+  internal::dbglog("New move to ref=%p this=%p", get(), this);
+  // JObject is a simple type and does not support move semantics so we explicitly
   // clear other
-  other.object_.set(nullptr);
+  other.set(nullptr);
 }
 
 template<typename T, typename Alloc>
 template<typename U>
 base_owned_ref<T, Alloc>::base_owned_ref(base_owned_ref<U, Alloc>&& other) noexcept
-  : object_{other.object_} {
-  internal::dbglog("New move from ref=%p other=%p", other.getPlainJniReference(), &other);
-  internal::dbglog("New move to ref=%p this=%p", getPlainJniReference(), this);
-  // JObjectWrapper is a simple type and does not support move semantics so we explicitly
+  : storage_(other.get()) {
+  internal::dbglog("New move from ref=%p other=%p", other.get(), &other);
+  internal::dbglog("New move to ref=%p this=%p", get(), this);
+  // JObject is a simple type and does not support move semantics so we explicitly
   // clear other
-  other.object_.set(nullptr);
+  other.set(nullptr);
 }
 
 template<typename T, typename Alloc>
 inline base_owned_ref<T, Alloc>::~base_owned_ref() noexcept {
   reset();
-  internal::dbglog("Ref destruct ref=%p this=%p", getPlainJniReference(), this);
+  internal::dbglog("Ref destruct ref=%p this=%p", get(), this);
 }
 
 template<typename T, typename Alloc>
-inline T base_owned_ref<T, Alloc>::release() noexcept {
-  auto value = getPlainJniReference();
+inline auto base_owned_ref<T, Alloc>::release() noexcept -> javaobject {
+  auto value = get();
   internal::dbglog("Ref release ref=%p this=%p", value, this);
-  object_.set(nullptr);
+  set(nullptr);
   return value;
 }
 
@@ -185,17 +250,22 @@ inline void base_owned_ref<T,Alloc>::reset() noexcept {
 }
 
 template<typename T, typename Alloc>
-inline void base_owned_ref<T,Alloc>::reset(T reference) noexcept {
-  if (getPlainJniReference()) {
+inline void base_owned_ref<T,Alloc>::reset(javaobject reference) noexcept {
+  if (get()) {
     assert(Alloc{}.verifyReference(reference));
-    Alloc{}.deleteReference(getPlainJniReference());
+    Alloc{}.deleteReference(get());
   }
-  object_.set(reference);
+  set(reference);
+}
+
+template<typename T, typename Alloc>
+inline auto base_owned_ref<T, Alloc>::get() const noexcept -> javaobject {
+  return storage_.jobj();
 }
 
 template<typename T, typename Alloc>
-inline T base_owned_ref<T, Alloc>::getPlainJniReference() const noexcept {
-  return static_cast<T>(object_.get());
+inline void base_owned_ref<T, Alloc>::set(javaobject ref) noexcept {
+  storage_.set(ref);
 }
 
 
@@ -213,19 +283,21 @@ template<typename T>
 inline weak_ref<T>& weak_ref<T>::operator=(
     weak_ref<T>&& other) noexcept {
   internal::dbglog("Op= move ref=%p this=%p oref=%p other=%p",
-      getPlainJniReference(), this, other.getPlainJniReference(), &other);
+      get(), this, other.get(), &other);
   reset(other.release());
   return *this;
 }
 
 template<typename T>
-local_ref<T> weak_ref<T>::lockLocal() {
-  return adopt_local(static_cast<T>(LocalReferenceAllocator{}.newReference(getPlainJniReference())));
+local_ref<T> weak_ref<T>::lockLocal() const {
+  return adopt_local(
+      static_cast<javaobject>(LocalReferenceAllocator{}.newReference(get())));
 }
 
 template<typename T>
-global_ref<T> weak_ref<T>::lockGlobal() {
-  return adopt_global(static_cast<T>(GlobalReferenceAllocator{}.newReference(getPlainJniReference())));
+global_ref<T> weak_ref<T>::lockGlobal() const {
+  return adopt_global(
+      static_cast<javaobject>(GlobalReferenceAllocator{}.newReference(get())));
 }
 
 template<typename T>
@@ -233,9 +305,8 @@ inline void swap(
     weak_ref<T>& a,
     weak_ref<T>& b) noexcept {
   internal::dbglog("Ref swap a.ref=%p a=%p b.ref=%p b=%p",
-      a.getPlainJniReference(), &a, b.getPlainJniReference(), &b);
-  using std::swap;
-  swap(a.object_, b.object_);
+      a.get(), &a, b.get(), &b);
+  a.storage_.swap(b.storage_);
 }
 
 
@@ -253,7 +324,7 @@ template<typename T, typename Alloc>
 inline basic_strong_ref<T, Alloc>& basic_strong_ref<T, Alloc>::operator=(
     basic_strong_ref<T, Alloc>&& other) noexcept {
   internal::dbglog("Op= move ref=%p this=%p oref=%p other=%p",
-      getPlainJniReference(), this, other.getPlainJniReference(), &other);
+      get(), this, other.get(), &other);
   reset(other.release());
   return *this;
 }
@@ -269,28 +340,23 @@ inline basic_strong_ref<T, Alloc>::operator bool() const noexcept {
 }
 
 template<typename T, typename Alloc>
-inline T basic_strong_ref<T, Alloc>::get() const noexcept {
-  return getPlainJniReference();
+inline auto basic_strong_ref<T, Alloc>::operator->() noexcept -> Repr* {
+  return &storage_.get();
 }
 
 template<typename T, typename Alloc>
-inline JObjectWrapper<T>* basic_strong_ref<T, Alloc>::operator->() noexcept {
-  return &object_;
+inline auto basic_strong_ref<T, Alloc>::operator->() const noexcept -> const Repr* {
+  return &storage_.get();
 }
 
 template<typename T, typename Alloc>
-inline const JObjectWrapper<T>* basic_strong_ref<T, Alloc>::operator->() const noexcept {
-  return &object_;
+inline auto basic_strong_ref<T, Alloc>::operator*() noexcept -> Repr& {
+  return storage_.get();
 }
 
 template<typename T, typename Alloc>
-inline JObjectWrapper<T>& basic_strong_ref<T, Alloc>::operator*() noexcept {
-  return object_;
-}
-
-template<typename T, typename Alloc>
-inline const JObjectWrapper<T>& basic_strong_ref<T, Alloc>::operator*() const noexcept {
-  return object_;
+inline auto basic_strong_ref<T, Alloc>::operator*() const noexcept -> const Repr& {
+  return storage_.get();
 }
 
 template<typename T, typename Alloc>
@@ -298,33 +364,32 @@ inline void swap(
     basic_strong_ref<T, Alloc>& a,
     basic_strong_ref<T, Alloc>& b) noexcept {
   internal::dbglog("Ref swap a.ref=%p a=%p b.ref=%p b=%p",
-      a.getPlainJniReference(), &a, b.getPlainJniReference(), &b);
+      a.get(), &a, b.get(), &b);
   using std::swap;
-  swap(a.object_, b.object_);
+  a.storage_.swap(b.storage_);
 }
 
 
 // alias_ref //////////////////////////////////////////////////////////////////////////////
 
 template<typename T>
-inline constexpr alias_ref<T>::alias_ref() noexcept
-  : object_{nullptr}
+inline alias_ref<T>::alias_ref() noexcept
+  : storage_{nullptr}
 {}
 
 template<typename T>
-inline constexpr alias_ref<T>::alias_ref(std::nullptr_t) noexcept
-  : object_{nullptr}
+inline alias_ref<T>::alias_ref(std::nullptr_t) noexcept
+  : storage_{nullptr}
 {}
 
 template<typename T>
 inline alias_ref<T>::alias_ref(const alias_ref& other) noexcept
-  : object_{other.object_}
+  : storage_{other.get()}
 {}
 
-
 template<typename T>
-inline alias_ref<T>::alias_ref(T ref) noexcept
-  : object_{ref} {
+inline alias_ref<T>::alias_ref(javaobject ref) noexcept
+  : storage_(ref) {
   assert(
       LocalReferenceAllocator{}.verifyReference(ref) ||
       GlobalReferenceAllocator{}.verifyReference(ref));
@@ -333,13 +398,13 @@ inline alias_ref<T>::alias_ref(T ref) noexcept
 template<typename T>
 template<typename TOther, typename /* for SFINAE */>
 inline alias_ref<T>::alias_ref(alias_ref<TOther> other) noexcept
-  : object_{other.get()}
+  : storage_{other.get()}
 {}
 
 template<typename T>
 template<typename TOther, typename AOther, typename /* for SFINAE */>
 inline alias_ref<T>::alias_ref(const basic_strong_ref<TOther, AOther>& other) noexcept
-  : object_{other.get()}
+  : storage_{other.get()}
 {}
 
 template<typename T>
@@ -354,34 +419,90 @@ inline alias_ref<T>::operator bool() const noexcept {
 }
 
 template<typename T>
-inline T facebook::jni::alias_ref<T>::get() const noexcept {
-  return static_cast<T>(object_.get());
+inline auto facebook::jni::alias_ref<T>::get() const noexcept -> javaobject {
+  return storage_.jobj();
+}
+
+template<typename T>
+inline auto alias_ref<T>::operator->() noexcept -> Repr* {
+  return &(**this);
 }
 
 template<typename T>
-inline JObjectWrapper<T>* alias_ref<T>::operator->() noexcept {
-  return &object_;
+inline auto alias_ref<T>::operator->() const noexcept -> const Repr* {
+  return &(**this);
 }
 
 template<typename T>
-inline const JObjectWrapper<T>* alias_ref<T>::operator->() const noexcept {
-  return &object_;
+inline auto alias_ref<T>::operator*() noexcept -> Repr& {
+  return storage_.get();
 }
 
 template<typename T>
-inline JObjectWrapper<T>& alias_ref<T>::operator*() noexcept {
-  return object_;
+inline auto alias_ref<T>::operator*() const noexcept -> const Repr& {
+  return storage_.get();
 }
 
 template<typename T>
-inline const JObjectWrapper<T>& alias_ref<T>::operator*() const noexcept {
-  return object_;
+inline void alias_ref<T>::set(javaobject ref) noexcept {
+  storage_.set(ref);
 }
 
 template<typename T>
 inline void swap(alias_ref<T>& a, alias_ref<T>& b) noexcept {
-  using std::swap;
-  swap(a.object_, b.object_);
+  a.storage_.swap(b.storage_);
+}
+
+// Could reduce code duplication by using a pointer-to-function
+// template argument.  I'm not sure whether that would make the code
+// more maintainable (DRY), or less (too clever/confusing.).
+template<typename T, typename U>
+enable_if_t<IsPlainJniReference<T>(), local_ref<T>>
+static_ref_cast(const local_ref<U>& ref) noexcept
+{
+  T p = static_cast<T>(ref.get());
+  return make_local(p);
+}
+
+template<typename T, typename U>
+enable_if_t<IsPlainJniReference<T>(), global_ref<T>>
+static_ref_cast(const global_ref<U>& ref) noexcept
+{
+  T p = static_cast<T>(ref.get());
+  return make_global(p);
+}
+
+template<typename T, typename U>
+enable_if_t<IsPlainJniReference<T>(), alias_ref<T>>
+static_ref_cast(const alias_ref<U>& ref) noexcept
+{
+  T p = static_cast<T>(ref.get());
+  return wrap_alias(p);
+}
+
+template<typename T, typename RefType>
+auto dynamic_ref_cast(const RefType& ref) ->
+enable_if_t<IsPlainJniReference<T>(), decltype(static_ref_cast<T>(ref))>
+{
+  if (! ref) {
+    return decltype(static_ref_cast<T>(ref))();
+  }
+
+  std::string target_class_name{jtype_traits<T>::base_name()};
+
+  // If not found, will throw an exception.
+  alias_ref<jclass> target_class = findClassStatic(target_class_name.c_str());
+
+  local_ref<jclass> source_class = ref->getClass();
+
+  if ( ! source_class->isAssignableFrom(target_class)) {
+    throwNewJavaException("java/lang/ClassCastException",
+                          "Tried to cast from %s to %s.",
+                          source_class->toString().c_str(),
+                          target_class_name.c_str());
+  }
+
+  return static_ref_cast<T>(ref);
 }
 
 }}
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/References.h b/ReactAndroid/src/main/jni/first-party/jni/fbjni/References.h
index 575f2cc6e559..b578c5c91507 100644
--- a/ReactAndroid/src/main/jni/first-party/jni/fbjni/References.h
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/References.h
@@ -79,53 +79,131 @@
 
 #include "ReferenceAllocators.h"
 #include "TypeTraits.h"
+#include "References-forward.h"
 
 namespace facebook {
 namespace jni {
 
-/**
- * The JObjectWrapper is specialized to provide functionality for various Java classes, some
- * specializations are provided, and it is easy to add your own. See example
- * @sample WrapperSample.cpp
- */
-template<typename T, typename Enable = void>
-class JObjectWrapper;
+/// Convenience function to wrap an existing local reference
+template<typename T>
+local_ref<T> adopt_local(T ref) noexcept;
 
+/// Convenience function to wrap an existing global reference
+template<typename T>
+global_ref<T> adopt_global(T ref) noexcept;
 
-template<typename T, typename Alloc>
-class base_owned_ref;
+/// Convenience function to wrap an existing weak reference
+template<typename T>
+weak_ref<T> adopt_weak_global(T ref) noexcept;
+
+
+/// Swaps two owning references of the same type
+template<typename T>
+void swap(weak_ref<T>& a, weak_ref<T>& b) noexcept;
 
+/// Swaps two owning references of the same type
 template<typename T, typename Alloc>
-class basic_strong_ref;
+void swap(basic_strong_ref<T, Alloc>& a, basic_strong_ref<T, Alloc>& b) noexcept;
 
+/**
+ * Retrieve the plain reference from a plain reference.
+ */
 template<typename T>
-class weak_ref;
+enable_if_t<IsPlainJniReference<T>(), T> getPlainJniReference(T ref);
 
+/**
+ * Retrieve the plain reference from an alias reference.
+ */
 template<typename T>
-class alias_ref;
+JniType<T> getPlainJniReference(alias_ref<T> ref);
+
+/**
+ * Retrieve the plain JNI reference from any reference owned reference.
+ */
+template<typename T, typename Alloc>
+JniType<T> getPlainJniReference(const base_owned_ref<T, Alloc>& ref);
 
+class JObject;
+class JClass;
 
-/// A smart unique reference owning a local JNI reference
-template<typename T>
-using local_ref = basic_strong_ref<T, LocalReferenceAllocator>;
+namespace detail {
 
-/// A smart unique reference owning a global JNI reference
-template<typename T>
-using global_ref = basic_strong_ref<T, GlobalReferenceAllocator>;
+template <typename T, typename Enable = void>
+struct HasJniRefRepr : std::false_type {};
 
+template <typename T>
+struct HasJniRefRepr<T, typename std::enable_if<!std::is_same<typename T::JniRefRepr, void>::value, void>::type> : std::true_type {
+  using type = typename T::JniRefRepr;
+};
 
-/// Convenience function to wrap an existing local reference
-template<typename T>
-enable_if_t<IsPlainJniReference<T>(), local_ref<T>> adopt_local(T ref) noexcept;
+template <typename T>
+struct RefReprType<T*> {
+  using type = typename std::conditional<HasJniRefRepr<T>::value, typename HasJniRefRepr<T>::type, JObjectWrapper<T*>>::type;
+  static_assert(std::is_base_of<JObject, type>::value,
+      "Repr type missing JObject base.");
+  static_assert(std::is_same<type, typename RefReprType<type>::type>::value,
+      "RefReprType<T> not idempotent");
+};
 
-/// Convenience function to wrap an existing global reference
-template<typename T>
-enable_if_t<IsPlainJniReference<T>(), global_ref<T>> adopt_global(T ref) noexcept;
+template <typename T>
+struct RefReprType<T, typename std::enable_if<std::is_base_of<JObject, T>::value, void>::type> {
+  using type = T;
+  static_assert(std::is_base_of<JObject, type>::value,
+      "Repr type missing JObject base.");
+  static_assert(std::is_same<type, typename RefReprType<type>::type>::value,
+      "RefReprType<T> not idempotent");
+};
 
-/// Convenience function to wrap an existing weak reference
-template<typename T>
-enable_if_t<IsPlainJniReference<T>(), weak_ref<T>> adopt_weak_global(T ref) noexcept;
+template <typename T>
+struct JavaObjectType {
+  using type = typename RefReprType<T>::type::javaobject;
+  static_assert(IsPlainJniReference<type>(),
+      "JavaObjectType<T> not a plain jni reference");
+  static_assert(std::is_same<type, typename JavaObjectType<type>::type>::value,
+      "JavaObjectType<T> not idempotent");
+};
 
+template <typename T>
+struct JavaObjectType<JObjectWrapper<T>> {
+  using type = T;
+  static_assert(IsPlainJniReference<type>(),
+      "JavaObjectType<T> not a plain jni reference");
+  static_assert(std::is_same<type, typename JavaObjectType<type>::type>::value,
+      "JavaObjectType<T> not idempotent");
+};
+
+template <typename T>
+struct JavaObjectType<T*> {
+  using type = T*;
+  static_assert(IsPlainJniReference<type>(),
+      "JavaObjectType<T> not a plain jni reference");
+  static_assert(std::is_same<type, typename JavaObjectType<type>::type>::value,
+      "JavaObjectType<T> not idempotent");
+};
+
+template <typename Repr>
+struct ReprStorage {
+  explicit ReprStorage(JniType<Repr> obj) noexcept;
+
+  void set(JniType<Repr> obj) noexcept;
+
+  Repr& get() noexcept;
+  const Repr& get() const noexcept;
+  JniType<Repr> jobj() const noexcept;
+
+  void swap(ReprStorage& other) noexcept;
+ private:
+  ReprStorage() = delete;
+  ReprStorage(const ReprStorage&) = delete;
+  ReprStorage(ReprStorage&&) = delete;
+  ReprStorage& operator=(const ReprStorage&) = delete;
+  ReprStorage& operator=(ReprStorage&&) = delete;
+
+  using Storage = typename std::aligned_storage<sizeof(JObjectBase), alignof(JObjectBase)>::type;
+  Storage storage_;
+};
+
+} // namespace detail
 
 /**
  * Create a new local reference from an existing reference
@@ -160,33 +238,6 @@ template<typename T>
 enable_if_t<IsNonWeakReference<T>(), weak_ref<plain_jni_reference_t<T>>>
 make_weak(const T& r);
 
-
-/// Swaps two owning references of the same type
-template<typename T>
-void swap(weak_ref<T>& a, weak_ref<T>& b) noexcept;
-
-/// Swaps two owning references of the same type
-template<typename T, typename Alloc>
-void swap(basic_strong_ref<T, Alloc>& a, basic_strong_ref<T, Alloc>& b) noexcept;
-
-/**
- * Retrieve the plain reference from a plain reference.
- */
-template<typename T>
-enable_if_t<IsPlainJniReference<T>(), T> getPlainJniReference(T ref);
-
-/**
- * Retrieve the plain reference from an alias reference.
- */
-template<typename T>
-T getPlainJniReference(alias_ref<T> ref);
-
-/**
- * Retrieve the plain JNI reference from any reference owned reference.
- */
-template<typename T, typename Alloc>
-T getPlainJniReference(const base_owned_ref<T, Alloc>& ref);
-
 /**
  * Compare two references to see if they refer to the same object
  */
@@ -201,19 +252,16 @@ template<typename T1, typename T2>
 enable_if_t<IsNonWeakReference<T1>() && IsNonWeakReference<T2>(), bool>
 operator!=(const T1& a, const T2& b);
 
-
 template<typename T, typename Alloc>
 class base_owned_ref {
-
-  static_assert(IsPlainJniReference<T>(), "T must be a JNI reference");
-
  public:
+  using javaobject = JniType<T>;
 
   /**
    * Release the ownership and set the reference to null. Thus no deleter is invoked.
    * @return Returns the reference
    */
-  T release() noexcept;
+  javaobject release() noexcept;
 
   /**
    * Reset the reference to refer to nullptr.
@@ -221,20 +269,23 @@ class base_owned_ref {
   void reset() noexcept;
 
  protected:
+  using Repr = ReprType<T>;
+  detail::ReprStorage<Repr> storage_;
 
-  JObjectWrapper<T> object_;
+  javaobject get() const noexcept;
+  void set(javaobject ref) noexcept;
 
   /*
    * Wrap an existing reference and transfers its ownership to the newly created unique reference.
    * NB! Does not create a new reference
    */
-  explicit base_owned_ref(T reference) noexcept;
+  explicit base_owned_ref(javaobject reference) noexcept;
 
   /// Create a null reference
-  constexpr base_owned_ref() noexcept;
+  base_owned_ref() noexcept;
 
   /// Create a null reference
-  constexpr explicit base_owned_ref(std::nullptr_t) noexcept;
+  explicit base_owned_ref(std::nullptr_t) noexcept;
 
   /// Copy constructor (note creates a new reference)
   base_owned_ref(const base_owned_ref& other);
@@ -256,13 +307,9 @@ class base_owned_ref {
   /// Assignment by moving a reference thus not creating a new reference
   base_owned_ref& operator=(base_owned_ref&& rhs) noexcept;
 
+  void reset(javaobject reference) noexcept;
 
-  T getPlainJniReference() const noexcept;
-
-  void reset(T reference) noexcept;
-
-
-  friend T jni::getPlainJniReference<>(const base_owned_ref& ref);
+  friend javaobject jni::getPlainJniReference<>(const base_owned_ref& ref);
 
   template<typename U, typename UAlloc>
   friend class base_owned_ref;
@@ -278,29 +325,31 @@ class base_owned_ref {
  */
 template<typename T>
 class weak_ref : public base_owned_ref<T, WeakGlobalReferenceAllocator> {
-
-  static_assert(IsPlainJniReference<T>(), "T must be a JNI reference");
-
  public:
+  using javaobject = JniType<T>;
 
-  using PlainJniType = T;
   using Allocator = WeakGlobalReferenceAllocator;
 
   // This inherits non-default, non-copy, non-move ctors.
   using base_owned_ref<T, Allocator>::base_owned_ref;
 
   /// Create a null reference
-  constexpr weak_ref() noexcept
+  weak_ref() noexcept
     : base_owned_ref<T, Allocator>{} {}
 
   /// Create a null reference
-  constexpr explicit weak_ref(std::nullptr_t) noexcept
+  explicit weak_ref(std::nullptr_t) noexcept
     : base_owned_ref<T, Allocator>{nullptr} {}
 
   /// Copy constructor (note creates a new reference)
   weak_ref(const weak_ref& other)
     : base_owned_ref<T, Allocator>{other} {}
 
+  // This needs to be explicit to change its visibility.
+  template<typename U>
+  weak_ref(const weak_ref<U>& other)
+    : base_owned_ref<T, Allocator>{other} {}
+
   /// Transfers ownership of an underlying reference from one unique reference to another
   weak_ref(weak_ref&& other) noexcept
     : base_owned_ref<T, Allocator>{std::move(other)} {}
@@ -312,28 +361,26 @@ class weak_ref : public base_owned_ref<T, WeakGlobalReferenceAllocator> {
   /// Assignment by moving a reference thus not creating a new reference
   weak_ref& operator=(weak_ref&& rhs) noexcept;
 
-
   // Creates an owned local reference to the referred object or to null if the object is reclaimed
-  local_ref<T> lockLocal();
+  local_ref<T> lockLocal() const;
 
   // Creates an owned global reference to the referred object or to null if the object is reclaimed
-  global_ref<T> lockGlobal();
+  global_ref<T> lockGlobal() const;
 
  private:
-
-  using base_owned_ref<T, Allocator>::getPlainJniReference;
-
+  // get/release/reset on weak_ref are not exposed to users.
+  using base_owned_ref<T, Allocator>::get;
+  using base_owned_ref<T, Allocator>::release;
+  using base_owned_ref<T, Allocator>::reset;
   /*
    * Wrap an existing reference and transfers its ownership to the newly created unique reference.
    * NB! Does not create a new reference
    */
-  explicit weak_ref(T reference) noexcept
+  explicit weak_ref(javaobject reference) noexcept
     : base_owned_ref<T, Allocator>{reference} {}
 
-
   template<typename T2> friend class weak_ref;
-  friend weak_ref<enable_if_t<IsPlainJniReference<T>(), T>>
-    adopt_weak_global<T>(T ref) noexcept;
+  friend weak_ref<javaobject> adopt_weak_global<javaobject>(javaobject ref) noexcept;
   friend void swap<T>(weak_ref& a, weak_ref& b) noexcept;
 };
 
@@ -344,12 +391,10 @@ class weak_ref : public base_owned_ref<T, WeakGlobalReferenceAllocator> {
  */
 template<typename T, typename Alloc>
 class basic_strong_ref : public base_owned_ref<T, Alloc> {
-
-  static_assert(IsPlainJniReference<T>(), "T must be a JNI reference");
-
+  using typename base_owned_ref<T, Alloc>::Repr;
  public:
+  using javaobject = JniType<T>;
 
-  using PlainJniType = T;
   using Allocator = Alloc;
 
   // This inherits non-default, non-copy, non-move ctors.
@@ -358,17 +403,22 @@ class basic_strong_ref : public base_owned_ref<T, Alloc> {
   using base_owned_ref<T, Alloc>::reset;
 
   /// Create a null reference
-  constexpr basic_strong_ref() noexcept
+  basic_strong_ref() noexcept
     : base_owned_ref<T, Alloc>{} {}
 
   /// Create a null reference
-  constexpr explicit basic_strong_ref(std::nullptr_t) noexcept
+  explicit basic_strong_ref(std::nullptr_t) noexcept
     : base_owned_ref<T, Alloc>{nullptr} {}
 
   /// Copy constructor (note creates a new reference)
   basic_strong_ref(const basic_strong_ref& other)
     : base_owned_ref<T, Alloc>{other} {}
 
+  // This needs to be explicit to change its visibility.
+  template<typename U>
+  basic_strong_ref(const basic_strong_ref<U, Alloc>& other)
+    : base_owned_ref<T, Alloc>{other} {}
+
   /// Transfers ownership of an underlying reference from one unique reference to another
   basic_strong_ref(basic_strong_ref&& other) noexcept
     : base_owned_ref<T, Alloc>{std::move(other)} {}
@@ -379,6 +429,8 @@ class basic_strong_ref : public base_owned_ref<T, Alloc> {
   /// Assignment by moving a reference thus not creating a new reference
   basic_strong_ref& operator=(basic_strong_ref&& rhs) noexcept;
 
+  /// Get the plain JNI reference
+  using base_owned_ref<T, Allocator>::get;
 
   /// Release the ownership of the reference and return the wrapped reference in an alias
   alias_ref<T> releaseAlias() noexcept;
@@ -386,37 +438,33 @@ class basic_strong_ref : public base_owned_ref<T, Alloc> {
   /// Checks if the reference points to a non-null object
   explicit operator bool() const noexcept;
 
-  /// Get the plain JNI reference
-  T get() const noexcept;
-
   /// Access the functionality provided by the object wrappers
-  JObjectWrapper<T>* operator->() noexcept;
+  Repr* operator->() noexcept;
 
   /// Access the functionality provided by the object wrappers
-  const JObjectWrapper<T>* operator->() const noexcept;
+  const Repr* operator->() const noexcept;
 
   /// Provide a reference to the underlying wrapper (be sure that it is non-null before invoking)
-  JObjectWrapper<T>& operator*() noexcept;
+  Repr& operator*() noexcept;
 
   /// Provide a const reference to the underlying wrapper (be sure that it is non-null
   /// before invoking)
-  const JObjectWrapper<T>& operator*() const noexcept;
+  const Repr& operator*() const noexcept;
 
  private:
 
-  using base_owned_ref<T, Alloc>::object_;
-  using base_owned_ref<T, Alloc>::getPlainJniReference;
+  using base_owned_ref<T, Alloc>::storage_;
 
   /*
    * Wrap an existing reference and transfers its ownership to the newly created unique reference.
    * NB! Does not create a new reference
    */
-  explicit basic_strong_ref(T reference) noexcept
+  explicit basic_strong_ref(javaobject reference) noexcept
     : base_owned_ref<T, Alloc>{reference} {}
 
 
-  friend enable_if_t<IsPlainJniReference<T>(), local_ref<T>> adopt_local<T>(T ref) noexcept;
-  friend enable_if_t<IsPlainJniReference<T>(), global_ref<T>> adopt_global<T>(T ref) noexcept;
+  friend local_ref<T> adopt_local<T>(T ref) noexcept;
+  friend global_ref<T> adopt_global<T>(T ref) noexcept;
   friend void swap<T, Alloc>(basic_strong_ref& a, basic_strong_ref& b) noexcept;
 };
 
@@ -424,7 +472,7 @@ class basic_strong_ref : public base_owned_ref<T, Alloc> {
 template<typename T>
 enable_if_t<IsPlainJniReference<T>(), alias_ref<T>> wrap_alias(T ref) noexcept;
 
-/// Swaps to alias referencec of the same type
+/// Swaps to alias reference of the same type
 template<typename T>
 void swap(alias_ref<T>& a, alias_ref<T>& b) noexcept;
 
@@ -437,35 +485,40 @@ void swap(alias_ref<T>& a, alias_ref<T>& b) noexcept;
  */
 template<typename T>
 class alias_ref {
-
-  static_assert(IsPlainJniReference<T>(), "T must be a JNI reference");
+  using Repr = ReprType<T>;
 
  public:
-
-  using PlainJniType = T;
-
+  using javaobject = JniType<T>;
 
   /// Create a null reference
-  constexpr alias_ref() noexcept;
+  alias_ref() noexcept;
 
   /// Create a null reference
-  constexpr alias_ref(std::nullptr_t) noexcept;
+  alias_ref(std::nullptr_t) noexcept;
 
   /// Copy constructor
   alias_ref(const alias_ref& other) noexcept;
 
   /// Wrap an existing plain JNI reference
-  alias_ref(T ref) noexcept;
+  /* implicit */ alias_ref(javaobject ref) noexcept;
 
   /// Wrap an existing smart reference of any type convertible to T
-  template<typename TOther, typename = enable_if_t<IsConvertible<TOther, T>(), T>>
+  template<
+    typename TOther,
+    typename = enable_if_t<
+      IsConvertible<JniType<TOther>, javaobject>(), T>
+    >
   alias_ref(alias_ref<TOther> other) noexcept;
 
   /// Wrap an existing alias reference of a type convertible to T
-  template<typename TOther, typename AOther, typename = enable_if_t<IsConvertible<TOther, T>(), T>>
+  template<
+    typename TOther,
+    typename AOther,
+    typename = enable_if_t<
+      IsConvertible<JniType<TOther>, javaobject>(), T>
+    >
   alias_ref(const basic_strong_ref<TOther, AOther>& other) noexcept;
 
-
   /// Assignment operator
   alias_ref& operator=(alias_ref other) noexcept;
 
@@ -473,22 +526,24 @@ class alias_ref {
   explicit operator bool() const noexcept;
 
   /// Converts back to a plain JNI reference
-  T get() const noexcept;
+  javaobject get() const noexcept;
 
   /// Access the functionality provided by the object wrappers
-  JObjectWrapper<T>* operator->() noexcept;
+  Repr* operator->() noexcept;
 
   /// Access the functionality provided by the object wrappers
-  const JObjectWrapper<T>* operator->() const noexcept;
+  const Repr* operator->() const noexcept;
 
   /// Provide a guaranteed non-null reference (be sure that it is non-null before invoking)
-  JObjectWrapper<T>& operator*() noexcept;
+  Repr& operator*() noexcept;
 
   /// Provide a guaranteed non-null reference (be sure that it is non-null before invoking)
-  const JObjectWrapper<T>& operator*() const noexcept;
+  const Repr& operator*() const noexcept;
 
  private:
-  JObjectWrapper<T> object_;
+  void set(javaobject ref) noexcept;
+
+  detail::ReprStorage<Repr> storage_;
 
   friend void swap<T>(alias_ref& a, alias_ref& b) noexcept;
 };
@@ -510,6 +565,22 @@ class JniLocalScope {
   bool hasFrame_;
 };
 
+template<typename T, typename U>
+enable_if_t<IsPlainJniReference<T>(), local_ref<T>>
+static_ref_cast(const local_ref<U>& ref) noexcept;
+
+template<typename T, typename U>
+enable_if_t<IsPlainJniReference<T>(), global_ref<T>>
+static_ref_cast(const global_ref<U>& ref) noexcept;
+
+template<typename T, typename U>
+enable_if_t<IsPlainJniReference<T>(), alias_ref<T>>
+static_ref_cast(const alias_ref<U>& ref) noexcept;
+
+template<typename T, typename RefType>
+auto dynamic_ref_cast(const RefType& ref) ->
+enable_if_t<IsPlainJniReference<T>(), decltype(static_ref_cast<T>(ref))> ;
+
 }}
 
 #include "References-inl.h"
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/Registration-inl.h b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Registration-inl.h
index 29414d195fee..2ac6abaf4de8 100644
--- a/ReactAndroid/src/main/jni/first-party/jni/fbjni/Registration-inl.h
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/Registration-inl.h
@@ -17,27 +17,24 @@ namespace jni {
 
 namespace detail {
 
-// convert to HybridClass* from jhybridobject
-template <typename T>
-struct Convert<
-  T, typename std::enable_if<
-    std::is_base_of<BaseHybridClass, typename std::remove_pointer<T>::type>::value>::type> {
-  typedef typename std::remove_pointer<T>::type::jhybridobject jniType;
-  static T fromJni(jniType t) {
-    if (t == nullptr) {
-      return nullptr;
-    }
-    return facebook::jni::cthis(wrap_alias(t));
-  }
-  // There is no automatic return conversion for objects.
-};
+#ifdef __i386__
+// X86 ABI forces 16 byte stack allignment on calls. Unfortunately
+// sometimes Dalvik chooses not to obey the ABI:
+// - https://code.google.com/p/android/issues/detail?id=61012
+// - https://android.googlesource.com/platform/ndk/+/81696d2%5E!/
+// Therefore, we tell the compiler to re-align the stack on entry
+// to our JNI functions.
+#define JNI_ENTRY_POINT __attribute__((force_align_arg_pointer))
+#else
+#define JNI_ENTRY_POINT
+#endif
 
 // registration wrapper for legacy JNI-style functions
 
 template<typename F, F func, typename C, typename... Args>
 inline NativeMethodWrapper* exceptionWrapJNIMethod(void (*)(JNIEnv*, C, Args... args)) {
   struct funcWrapper {
-    static void call(JNIEnv* env, jobject obj, Args... args) {
+    JNI_ENTRY_POINT static void call(JNIEnv* env, jobject obj, Args... args) {
       // Note that if func was declared noexcept, then both gcc and clang are smart
       // enough to elide the try/catch.
       try {
@@ -55,9 +52,9 @@ inline NativeMethodWrapper* exceptionWrapJNIMethod(void (*)(JNIEnv*, C, Args...
 template<typename F, F func, typename C, typename R, typename... Args>
 inline NativeMethodWrapper* exceptionWrapJNIMethod(R (*)(JNIEnv*, C, Args... args)) {
   struct funcWrapper {
-    static R call(JNIEnv* env, jobject obj, Args... args) {
+    JNI_ENTRY_POINT static R call(JNIEnv* env, jobject obj, Args... args) {
       try {
-        return (*func)(env, static_cast<C>(obj), args...);
+        return (*func)(env, static_cast<JniType<C>>(obj), args...);
       } catch (...) {
         translatePendingCppExceptionToJavaException();
         return R{};
@@ -74,10 +71,10 @@ inline NativeMethodWrapper* exceptionWrapJNIMethod(R (*)(JNIEnv*, C, Args... arg
 template<typename F, F func, typename C, typename... Args>
 inline NativeMethodWrapper* exceptionWrapJNIMethod(void (*)(alias_ref<C>, Args... args)) {
   struct funcWrapper {
-    static void call(JNIEnv*, jobject obj,
-                     typename Convert<typename std::decay<Args>::type>::jniType... args) {
+    JNI_ENTRY_POINT static void call(JNIEnv*, jobject obj,
+                                     typename Convert<typename std::decay<Args>::type>::jniType... args) {
       try {
-        (*func)(static_cast<C>(obj), Convert<typename std::decay<Args>::type>::fromJni(args)...);
+        (*func)(static_cast<JniType<C>>(obj), Convert<typename std::decay<Args>::type>::fromJni(args)...);
       } catch (...) {
         translatePendingCppExceptionToJavaException();
       }
@@ -93,11 +90,11 @@ inline NativeMethodWrapper* exceptionWrapJNIMethod(R (*)(alias_ref<C>, Args... a
   struct funcWrapper {
     typedef typename Convert<typename std::decay<R>::type>::jniType jniRet;
 
-    static jniRet call(JNIEnv*, jobject obj,
-                       typename Convert<typename std::decay<Args>::type>::jniType... args) {
+    JNI_ENTRY_POINT static jniRet call(JNIEnv*, jobject obj,
+                                       typename Convert<typename std::decay<Args>::type>::jniType... args) {
       try {
         return Convert<typename std::decay<R>::type>::toJniRet(
-          (*func)(static_cast<C>(obj), Convert<typename std::decay<Args>::type>::fromJni(args)...));
+          (*func)(static_cast<JniType<C>>(obj), Convert<typename std::decay<Args>::type>::fromJni(args)...));
       } catch (...) {
         translatePendingCppExceptionToJavaException();
         return jniRet{};
@@ -114,8 +111,8 @@ inline NativeMethodWrapper* exceptionWrapJNIMethod(R (*)(alias_ref<C>, Args... a
 template<typename M, M method, typename C, typename... Args>
 inline NativeMethodWrapper* exceptionWrapJNIMethod(void (C::*method0)(Args... args)) {
   struct funcWrapper {
-    static void call(JNIEnv* env, jobject obj,
-                     typename Convert<typename std::decay<Args>::type>::jniType... args) {
+    JNI_ENTRY_POINT static void call(JNIEnv* env, jobject obj,
+                                     typename Convert<typename std::decay<Args>::type>::jniType... args) {
       try {
         try {
           auto aref = wrap_alias(static_cast<typename C::jhybridobject>(obj));
@@ -143,8 +140,8 @@ inline NativeMethodWrapper* exceptionWrapJNIMethod(R (C::*method0)(Args... args)
   struct funcWrapper {
     typedef typename Convert<typename std::decay<R>::type>::jniType jniRet;
 
-    static jniRet call(JNIEnv* env, jobject obj,
-                       typename Convert<typename std::decay<Args>::type>::jniType... args) {
+    JNI_ENTRY_POINT static jniRet call(JNIEnv* env, jobject obj,
+                                       typename Convert<typename std::decay<Args>::type>::jniType... args) {
       try {
         try {
           auto aref = wrap_alias(static_cast<typename C::jhybridobject>(obj));
@@ -176,16 +173,12 @@ inline std::string makeDescriptor(R (*)(JNIEnv*, C, Args... args)) {
 
 template<typename R, typename C, typename... Args>
 inline std::string makeDescriptor(R (*)(alias_ref<C>, Args... args)) {
-  typedef typename Convert<typename std::decay<R>::type>::jniType jniRet;
-  return jmethod_traits<jniRet(typename Convert<typename std::decay<Args>::type>::jniType...)>
-    ::descriptor();
+  return jmethod_traits_from_cxx<R(Args...)>::descriptor();
 }
 
 template<typename R, typename C, typename... Args>
 inline std::string makeDescriptor(R (C::*)(Args... args)) {
-  typedef typename Convert<typename std::decay<R>::type>::jniType jniRet;
-  return jmethod_traits<jniRet(typename Convert<typename std::decay<Args>::type>::jniType...)>
-    ::descriptor();
+  return jmethod_traits_from_cxx<R(Args...)>::descriptor();
 }
 
 }
diff --git a/ReactAndroid/src/main/jni/first-party/jni/fbjni/TypeTraits.h b/ReactAndroid/src/main/jni/first-party/jni/fbjni/TypeTraits.h
index b4bdd15ea2f1..26472669dc71 100644
--- a/ReactAndroid/src/main/jni/first-party/jni/fbjni/TypeTraits.h
+++ b/ReactAndroid/src/main/jni/first-party/jni/fbjni/TypeTraits.h
@@ -11,6 +11,8 @@
 
 #include <type_traits>
 
+#include "References-forward.h"
+
 namespace facebook {
 namespace jni {
 
@@ -69,6 +71,25 @@ constexpr bool IsJniPrimitive() {
   return is_jni_primitive<T>::value;
 }
 
+/// Metafunction to determine whether a type is a JNI array of primitives or not
+template <typename T>
+struct is_jni_primitive_array :
+  std::integral_constant<bool,
+    std::is_same<jbooleanArray, T>::value ||
+    std::is_same<jbyteArray, T>::value ||
+    std::is_same<jcharArray, T>::value ||
+    std::is_same<jshortArray, T>::value ||
+    std::is_same<jintArray, T>::value ||
+    std::is_same<jlongArray, T>::value ||
+    std::is_same<jfloatArray, T>::value ||
+    std::is_same<jdoubleArray, T>::value> {};
+
+/// Helper to simplify use of is_jni_primitive_array
+template <typename T>
+constexpr bool IsJniPrimitiveArray() {
+  return is_jni_primitive_array<T>::value;
+}
+
 /// Metafunction to determine if a type is a scalar (primitive or reference) JNI type
 template<typename T>
 struct is_jni_scalar :
@@ -95,15 +116,6 @@ constexpr bool IsJniType() {
   return is_jni_type<T>::value;
 }
 
-template<typename T>
-class weak_global_ref;
-
-template<typename T, typename Alloc>
-class basic_strong_ref;
-
-template<typename T>
-class alias_ref;
-
 template<typename T>
 struct is_non_weak_reference :
   std::integral_constant<bool,
@@ -120,7 +132,7 @@ template<typename T>
 struct is_any_reference :
   std::integral_constant<bool,
     IsPlainJniReference<T>() ||
-    IsInstantiationOf<weak_global_ref, T>() ||
+    IsInstantiationOf<weak_ref, T>() ||
     IsInstantiationOf<basic_strong_ref, T>() ||
     IsInstantiationOf<alias_ref, T>()> {};
 
@@ -131,19 +143,18 @@ constexpr bool IsAnyReference() {
 
 template<typename T>
 struct reference_traits {
-  static_assert(IsPlainJniReference<T>(), "Need a plain JNI reference");
-  using plain_jni_reference_t = T;
+  using plain_jni_reference_t = JniType<T>;
+  static_assert(IsPlainJniReference<plain_jni_reference_t>(), "Need a plain JNI reference");
 };
 
 template<template <typename...> class R, typename T, typename... A>
 struct reference_traits<R<T, A...>> {
-  static_assert(IsAnyReference<T>(), "Need an fbjni reference");
-  using plain_jni_reference_t = T;
+  using plain_jni_reference_t = JniType<T>;
+  static_assert(IsPlainJniReference<plain_jni_reference_t>(), "Need a plain JNI reference");
 };
 
 template<typename T>
 using plain_jni_reference_t = typename reference_traits<T>::plain_jni_reference_t;
 
-}
-}
-
+} // namespace jni
+} // namespace facebook

From e7499e39a4f957d49aca7c7c11afa74cae7826a7 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Wed, 2 Mar 2016 07:31:11 -0800
Subject: [PATCH 1381/1411] limit number of workers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Summary:This limits the number of spawned transformation workers depending on the number of available cores (`n`):

```
n < 3   → n
n < 8   → floor(3/4 * n)
n < 24  → floor(3/8 * n + 3) // factor going from 3/4 to 1/2
n >= 24 → floor(n / 2)
```

Reviewed By: bestander

Differential Revision: D2999894

fb-gh-sync-id: 0163240b5f066432f9ba07161c0dfa2ec767ba58
shipit-source-id: 0163240b5f066432f9ba07161c0dfa2ec767ba58
---
 .../react-packager/src/JSTransformer/index.js | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/packager/react-packager/src/JSTransformer/index.js b/packager/react-packager/src/JSTransformer/index.js
index 9767985926b5..a25cd57d9098 100644
--- a/packager/react-packager/src/JSTransformer/index.js
+++ b/packager/react-packager/src/JSTransformer/index.js
@@ -12,6 +12,7 @@ const ModuleTransport = require('../lib/ModuleTransport');
 const Promise = require('promise');
 const declareOpts = require('../lib/declareOpts');
 const fs = require('fs');
+const os = require('os');
 const temp = require('temp');
 const util = require('util');
 const workerFarm = require('worker-farm');
@@ -60,6 +61,23 @@ const validateOpts = declareOpts({
   },
 });
 
+const maxConcurrentWorkers = ((cores, override) => {
+  if (override) {
+    return Math.min(cores, override);
+  }
+
+  if (cores < 3) {
+    return cores;
+  }
+  if (cores < 8) {
+    return Math.floor(cores * 0.75);
+  }
+  if (cores < 24) {
+    return Math.floor(3/8 * cores + 3); // between cores *.75 and cores / 2
+  }
+  return cores / 2;
+})(os.cpus().length, process.env.REACT_NATIVE_MAX_WORKERS);
+
 class Transformer {
   constructor(options) {
     const opts = this._opts = validateOpts(options);
@@ -87,6 +105,7 @@ class Transformer {
       this._workers = workerFarm({
         autoStart: true,
         maxConcurrentCallsPerWorker: 1,
+        maxConcurrentWorkers: maxConcurrentWorkers,
         maxCallsPerWorker: MAX_CALLS_PER_WORKER,
         maxCallTime: opts.transformTimeoutInterval,
         maxRetries: MAX_RETRIES,

From c331d113dc40500b2db4eed849b8265423015a08 Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Wed, 2 Mar 2016 08:26:11 -0800
Subject: [PATCH 1382/1411] Fix breakages caused by switch to fbjs

Summary: This fixes a couple of breakages introduced by the switch to fbjs

Reviewed By: bestander

Differential Revision: D3000078

fb-gh-sync-id: 2971d049030f754d5001f6729716373a64078ddf
shipit-source-id: 2971d049030f754d5001f6729716373a64078ddf
---
 .../CustomComponents/ListView/ListView.js     |  2 +-
 .../ListView/ListViewDataSource.js            |  2 +-
 .../NavigationCardStack.js                    |  2 +-
 Libraries/vendor/core/isEmpty.js              | 34 +++++++++++++++++++
 packager/blacklist.js                         |  1 +
 5 files changed, 38 insertions(+), 3 deletions(-)
 create mode 100644 Libraries/vendor/core/isEmpty.js

diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js
index b068737d45bf..eb642d73fbec 100644
--- a/Libraries/CustomComponents/ListView/ListView.js
+++ b/Libraries/CustomComponents/ListView/ListView.js
@@ -34,7 +34,7 @@ var ScrollResponder = require('ScrollResponder');
 var StaticRenderer = require('StaticRenderer');
 var TimerMixin = require('react-timer-mixin');
 
-var isEmpty = require('fbjs/lib/isEmpty');
+var isEmpty = require('isEmpty');
 var merge = require('merge');
 
 var PropTypes = React.PropTypes;
diff --git a/Libraries/CustomComponents/ListView/ListViewDataSource.js b/Libraries/CustomComponents/ListView/ListViewDataSource.js
index cedf8b584a6a..1d14e50f5b74 100644
--- a/Libraries/CustomComponents/ListView/ListViewDataSource.js
+++ b/Libraries/CustomComponents/ListView/ListViewDataSource.js
@@ -29,7 +29,7 @@
 'use strict';
 
 var invariant = require('fbjs/lib/invariant');
-var isEmpty = require('fbjs/lib/isEmpty');
+var isEmpty = require('isEmpty');
 var warning = require('fbjs/lib/warning');
 
 function defaultGetRowData(
diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationCardStack.js b/Libraries/CustomComponents/NavigationExperimental/NavigationCardStack.js
index f58c49926c95..f36fbc0fe325 100644
--- a/Libraries/CustomComponents/NavigationExperimental/NavigationCardStack.js
+++ b/Libraries/CustomComponents/NavigationExperimental/NavigationCardStack.js
@@ -36,7 +36,7 @@ const React = require('React');
 const ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
 const StyleSheet = require('StyleSheet');
 
-const emptyFunction = require('emptyFunction');
+const emptyFunction = require('fbjs/lib/emptyFunction');
 
 const {PropTypes} = React;
 const {Directions} = NavigationLinearPanResponder;
diff --git a/Libraries/vendor/core/isEmpty.js b/Libraries/vendor/core/isEmpty.js
new file mode 100644
index 000000000000..27f4c0069a06
--- /dev/null
+++ b/Libraries/vendor/core/isEmpty.js
@@ -0,0 +1,34 @@
+/**
+ * @generated SignedSource<<97ffcebc9ae390e734026a4f3964bff6>>
+ *
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * !! This file is a check-in of a static_upstream project!      !!
+ * !!                                                            !!
+ * !! You should not modify this file directly. Instead:         !!
+ * !! 1) Use `fjs use-upstream` to temporarily replace this with !!
+ * !!    the latest version from upstream.                       !!
+ * !! 2) Make your changes, test them, etc.                      !!
+ * !! 3) Use `fjs push-upstream` to copy your changes back to    !!
+ * !!    static_upstream.                                        !!
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ *
+ * @providesModule isEmpty
+ */
+
+/**
+ * Mimics empty from PHP.
+ */
+function isEmpty(obj) {
+  if (Array.isArray(obj)) {
+    return obj.length === 0;
+  } else if (typeof obj === 'object') {
+    for (var i in obj) {
+      return false;
+    }
+    return true;
+  } else {
+    return !obj;
+  }
+}
+
+module.exports = isEmpty;
diff --git a/packager/blacklist.js b/packager/blacklist.js
index 27ec2899300f..acca4c167c81 100644
--- a/packager/blacklist.js
+++ b/packager/blacklist.js
@@ -19,6 +19,7 @@ var sharedBlacklist = [
 
   // fbjs forks:
   'node_modules/fbjs/lib/Map.js',
+  'node_modules/fbjs/lib/isEmpty.js',
 
   /website\/node_modules\/.*/,
 

From f6b0c13fd6196ba8599badfb3c3e52ab004f4fd5 Mon Sep 17 00:00:00 2001
From: Jimmy Mayoukou <bhullnatik@gmail.com>
Date: Wed, 2 Mar 2016 08:47:37 -0800
Subject: [PATCH 1383/1411] Expose Clipboard docs

Summary:This exposes the `Clipboard` API by showing it in the documentation.

**Test plan**

Ran the website locally, made sure it worked. :palm_tree:
Closes https://github.com/facebook/react-native/pull/6247

Differential Revision: D3000208

Pulled By: vjeux

fb-gh-sync-id: 2154cfe0532d3a39f90bfc19402ac7a5814ea2db
shipit-source-id: 2154cfe0532d3a39f90bfc19402ac7a5814ea2db
---
 website/server/extractDocs.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/website/server/extractDocs.js b/website/server/extractDocs.js
index b74c029b76c0..be0c8e2f5125 100644
--- a/website/server/extractDocs.js
+++ b/website/server/extractDocs.js
@@ -234,6 +234,7 @@ var apis = [
   '../Libraries/Storage/AsyncStorage.js',
   '../Libraries/Utilities/BackAndroid.android.js',
   '../Libraries/CameraRoll/CameraRoll.js',
+  '../Libraries/Components/Clipboard/Clipboard.js',
   '../Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js',
   '../Libraries/Utilities/Dimensions.js',
   '../Libraries/Components/Intent/IntentAndroid.android.js',

From eb531943aab37ec59c9e160f8b602313b4aa954f Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Wed, 2 Mar 2016 10:14:12 -0800
Subject: [PATCH 1384/1411] Fix the last imports of `'invariant'`

Summary:This changes the last two imports of `'invariant'` that I could find to `'fbjs/lib/invariant'`.
Closes https://github.com/facebook/react-native/pull/6248

Differential Revision: D3000440

fb-gh-sync-id: 15ebd08bb749d1d82b12902dd3dec00914fc1ed5
shipit-source-id: 15ebd08bb749d1d82b12902dd3dec00914fc1ed5
---
 .../NavigationExperimental/NavigationAbstractPanResponder.js    | 2 +-
 Libraries/NavigationExperimental/NavigationStateUtils.js        | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Libraries/NavigationExperimental/NavigationAbstractPanResponder.js b/Libraries/NavigationExperimental/NavigationAbstractPanResponder.js
index d6000a4ce68c..98fdbf32d005 100644
--- a/Libraries/NavigationExperimental/NavigationAbstractPanResponder.js
+++ b/Libraries/NavigationExperimental/NavigationAbstractPanResponder.js
@@ -8,7 +8,7 @@
 
 const PanResponder = require('PanResponder');
 
-const invariant = require('invariant');
+const invariant = require('fbjs/lib/invariant');
 
 const EmptyPanHandlers = {
   onMoveShouldSetPanResponder: null,
diff --git a/Libraries/NavigationExperimental/NavigationStateUtils.js b/Libraries/NavigationExperimental/NavigationStateUtils.js
index c9d10ddfbb21..d457ebea8ada 100644
--- a/Libraries/NavigationExperimental/NavigationStateUtils.js
+++ b/Libraries/NavigationExperimental/NavigationStateUtils.js
@@ -11,7 +11,7 @@
  */
 'use strict';
 
-const invariant = require('invariant');
+const invariant = require('fbjs/lib/invariant');
 
 export type NavigationState = {
   key: string;

From 8717b2d19cf7fbe8898a039507f8f41d1c7baa06 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Wed, 2 Mar 2016 12:20:56 -0800
Subject: [PATCH 1385/1411] Rework the NavigationHeader

Reviewed By: dmmiller, ericvicenti

Differential Revision: D3000972

fb-gh-sync-id: fcd4e63b72a70440e611289f03ed4757e230dc5b
shipit-source-id: fcd4e63b72a70440e611289f03ed4757e230dc5b
---
 .../NavigationAnimatedExample.js              |  19 +-
 .../NavigationBasicExample.js                 |   3 +-
 .../NavigationCompositionExample.js           |  15 +-
 .../NavigationExampleRow.js                   |   3 +-
 Examples/UIExplorer/UIExplorerList.android.js |   2 +
 .../NavigationHeader.js                       | 286 ++++++++++++------
 .../NavigationHeaderBackButton.js             |  59 ++++
 .../NavigationHeaderTitle.js                  |  74 +++++
 .../assets/back-icon@1.5x.android.png         | Bin 0 -> 134 bytes
 .../assets/back-icon@1.5x.ios.png             | Bin 0 -> 273 bytes
 .../assets/back-icon@1x.android.png           | Bin 0 -> 100 bytes
 .../assets/back-icon@1x.ios.png               | Bin 0 -> 177 bytes
 .../assets/back-icon@2x.android.png           | Bin 0 -> 134 bytes
 .../assets/back-icon@2x.ios.png               | Bin 0 -> 303 bytes
 .../assets/back-icon@3x.android.png           | Bin 0 -> 167 bytes
 .../assets/back-icon@3x.ios.png               | Bin 0 -> 439 bytes
 .../assets/back-icon@4x.android.png           | Bin 0 -> 207 bytes
 .../assets/back-icon@4x.ios.png               | Bin 0 -> 586 bytes
 .../NavigationExperimental/back_chevron.png   | Bin 575 -> 0 bytes
 .../NavigationAnimatedView.js                 |  19 +-
 .../NavigationExperimental.js                 |   4 +
 .../NavigationStateUtils.js                   |   6 +
 22 files changed, 373 insertions(+), 117 deletions(-)
 create mode 100644 Libraries/CustomComponents/NavigationExperimental/NavigationHeaderBackButton.js
 create mode 100644 Libraries/CustomComponents/NavigationExperimental/NavigationHeaderTitle.js
 create mode 100644 Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1.5x.android.png
 create mode 100644 Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1.5x.ios.png
 create mode 100644 Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1x.android.png
 create mode 100644 Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1x.ios.png
 create mode 100644 Libraries/CustomComponents/NavigationExperimental/assets/back-icon@2x.android.png
 create mode 100644 Libraries/CustomComponents/NavigationExperimental/assets/back-icon@2x.ios.png
 create mode 100644 Libraries/CustomComponents/NavigationExperimental/assets/back-icon@3x.android.png
 create mode 100644 Libraries/CustomComponents/NavigationExperimental/assets/back-icon@3x.ios.png
 create mode 100644 Libraries/CustomComponents/NavigationExperimental/assets/back-icon@4x.android.png
 create mode 100644 Libraries/CustomComponents/NavigationExperimental/assets/back-icon@4x.ios.png
 delete mode 100644 Libraries/CustomComponents/NavigationExperimental/back_chevron.png

diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
index e74d80e26306..8ef14c56ac83 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
@@ -27,6 +27,7 @@ var {
   RootContainer: NavigationRootContainer,
   Reducer: NavigationReducer,
   Header: NavigationHeader,
+  HeaderTitle: NavigationHeaderTitle,
 } = NavigationExperimental;
 
 const NavigationBasicReducer = NavigationReducer.StackReducer({
@@ -60,12 +61,6 @@ class NavigationAnimatedExample extends React.Component {
       />
     );
   }
-  handleBackAction() {
-    return (
-      this.navRootContainer &&
-      this.navRootContainer.handleNavigation(NavigationRootContainer.getBackAction())
-    );
-  }
   _renderNavigated(navigationState, onNavigate) {
     if (!navigationState) {
       return null;
@@ -74,11 +69,13 @@ class NavigationAnimatedExample extends React.Component {
       <NavigationAnimatedView
         navigationState={navigationState}
         style={styles.animatedView}
-        renderOverlay={(props) => (
+        renderOverlay={(scenes, index, position, layout) => (
           <NavigationHeader
-            navigationState={props.navigationParentState}
-            position={props.position}
-            getTitle={state => state.key}
+            scenes={scenes}
+            index={index}
+            position={position}
+            layout={layout}
+            renderTitleComponent={pageState => <NavigationHeaderTitle>{pageState.key}</NavigationHeaderTitle>}
           />
         )}
         setTiming={(pos, navState) => {
@@ -121,7 +118,7 @@ const styles = StyleSheet.create({
     flex: 1,
   },
   scrollView: {
-    marginTop: 64
+    marginTop: NavigationHeader.APPBAR_HEIGHT + NavigationHeader.STATUSBAR_HEIGHT,
   },
 });
 
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationBasicExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationBasicExample.js
index 447ab2051fba..8508c047368a 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationBasicExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationBasicExample.js
@@ -23,6 +23,7 @@ const NavigationExampleRow = require('./NavigationExampleRow');
 const {
   RootContainer: NavigationRootContainer,
   Reducer: NavigationReducer,
+  Header: NavigationHeader,
 } = NavigationExperimental;
 const StackReducer = NavigationReducer.StackReducer;
 
@@ -93,7 +94,7 @@ const styles = StyleSheet.create({
   topView: {
     backgroundColor: '#E9E9EF',
     flex: 1,
-    paddingTop: 30,
+    paddingTop: NavigationHeader.STATUSBAR_HEIGHT,
   },
 });
 
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js
index bc1d184db5de..6a79a5cdc04e 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js
@@ -28,6 +28,7 @@ const {
   Container: NavigationContainer,
   RootContainer: NavigationRootContainer,
   Header: NavigationHeader,
+  HeaderTitle: NavigationHeaderTitle,
   Reducer: NavigationReducer,
   View: NavigationView,
 } = NavigationExperimental;
@@ -154,13 +155,15 @@ class ExampleTabScreen extends React.Component {
       />
     );
   }
-  _renderHeader(props) {
+
+  _renderHeader(scenes, index, position, layout) {
     return (
       <NavigationHeader
-        navigationState={props.navigationParentState}
-        position={props.position}
-        layout={props.layout}
-        getTitle={state => stateTypeTitleMap(state)}
+        scenes={scenes}
+        index={index}
+        position={position}
+        layout={layout}
+        renderTitleComponent={pageState => <NavigationHeaderTitle>{stateTypeTitleMap(pageState)}</NavigationHeaderTitle>}
       />
     );
   }
@@ -270,7 +273,7 @@ const styles = StyleSheet.create({
     flex: 1,
   },
   scrollView: {
-    marginTop: 64
+    marginTop: NavigationHeader.APPBAR_HEIGHT + NavigationHeader.STATUSBAR_HEIGHT,
   },
   tabContent: {
     flex: 1,
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationExampleRow.js b/Examples/UIExplorer/NavigationExperimental/NavigationExampleRow.js
index 4e431e30a722..9fceec7bc3bc 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationExampleRow.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationExampleRow.js
@@ -16,7 +16,6 @@
 var React = require('react-native');
 var {
   Text,
-  PixelRatio,
   StyleSheet,
   View,
   TouchableHighlight,
@@ -50,7 +49,7 @@ const styles = StyleSheet.create({
   row: {
     padding: 15,
     backgroundColor: 'white',
-    borderBottomWidth: 1 / PixelRatio.get(),
+    borderBottomWidth: StyleSheet.hairlineWidth,
     borderBottomColor: '#CDCDCD',
   },
   rowText: {
diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index 78e74c48e841..3dfd365d1996 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -15,6 +15,8 @@
  */
 'use strict';
 
+const React = require('react');
+
 export type UIExplorerExample = {
   key: string;
   module: React.Component;
diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationHeader.js b/Libraries/CustomComponents/NavigationExperimental/NavigationHeader.js
index 82a807e2f27d..fac681c1a39d 100644
--- a/Libraries/CustomComponents/NavigationExperimental/NavigationHeader.js
+++ b/Libraries/CustomComponents/NavigationExperimental/NavigationHeader.js
@@ -27,123 +27,227 @@
  */
 'use strict';
 
-const Animated = require('Animated');
-const Image = require('Image');
-const NavigationContainer = require('NavigationContainer');
-const NavigationRootContainer = require('NavigationRootContainer');
 const React = require('react-native');
-const StyleSheet = require('StyleSheet');
-const Text = require('Text');
-const TouchableOpacity = require('TouchableOpacity');
-const View = require('View');
+const NavigationContainer = require('NavigationContainer');
+const NavigationHeaderTitle = require('NavigationHeaderTitle');
+const NavigationHeaderBackButton = require('NavigationHeaderBackButton');
+
+const {
+  Animated,
+  Platform,
+  StyleSheet,
+  View,
+} = React;
+
+const APPBAR_HEIGHT = Platform.OS === 'ios' ? 44 : 56;
+const STATUSBAR_HEIGHT = Platform.OS === 'ios' ? 20 : 0;
 
 import type {
-  NavigationState,
-  NavigationParentState
+  NavigationScene,
 } from 'NavigationStateUtils';
 
+type Renderer = (scene: NavigationScene) => ReactElement;
+
+type DefaultProps = {
+  renderTitleComponent: Renderer;
+  renderLeftComponent: Renderer;
+};
+
 type Props = {
-  navigationState: NavigationParentState,
-  onNavigate: Function,
   position: Animated.Value,
-  getTitle: (navState: NavigationState) => string,
+  scenes: Array<NavigationScene>;
+  index: number;
+  renderTitleComponent: Renderer;
+  renderLeftComponent: Renderer;
+  renderRightComponent: Renderer;
+  style: any,
 };
 
-class NavigationHeader extends React.Component {
-  _handleBackPress: Function;
-  props: Props;
-  componentWillMount() {
-    this._handleBackPress = this._handleBackPress.bind(this);
+class NavigationHeader extends React.Component<DefaultProps, Props, void> {
+  _renderLeftComponent(scene) {
+    const {
+      renderLeftComponent,
+      position,
+    } = this.props;
+
+    if (renderLeftComponent) {
+      const {
+        index,
+        state,
+      } = scene;
+
+      return (
+        <Animated.View
+          pointerEvents={this.props.index === index ? 'auto' : 'none'}
+          key={state.key}
+          style={[
+            styles.left,
+            {
+              opacity: position.interpolate({
+                inputRange: [ index - 1, index, index + 1 ],
+                outputRange: [ 0, 1, 0 ],
+              })
+            }
+          ]}
+        >
+          {renderLeftComponent(state, index)}
+        </Animated.View>
+      );
+    }
+
+    return null;
   }
-  render() {
-    var state = this.props.navigationState;
-    return (
-      <Animated.View
-        style={[
-          styles.header,
-        ]}>
-        {state.children.map(this._renderTitle, this)}
-        {this._renderBackButton()}
-      </Animated.View>
-    );
+
+  _renderRightComponent(scene) {
+    const {
+      renderRightComponent,
+      position,
+    } = this.props;
+
+    if (renderRightComponent) {
+      const {
+        index,
+        state,
+      } = scene;
+
+      return (
+        <Animated.View
+          pointerEvents={this.props.index === index ? 'auto' : 'none'}
+          key={state.key}
+          style={[
+            styles.right,
+            {
+              opacity: position.interpolate({
+                inputRange: [ index - 1, index, index + 1 ],
+                outputRange: [ 0, 1, 0 ],
+              })
+            }
+          ]}
+        >
+          {renderRightComponent(state, index)}
+        </Animated.View>
+      );
+    }
+
+    return null;
   }
-  _renderBackButton() {
-    if (this.props.navigationState.index === 0) {
-      return null;
+
+  _renderTitleComponent(scene) {
+    const {
+      renderTitleComponent,
+      position,
+    } = this.props;
+
+    if (renderTitleComponent) {
+      const {
+        index,
+        state,
+      } = scene;
+
+      return (
+        <Animated.View
+          pointerEvents={this.props.index === index ? 'auto' : 'none'}
+          key={state.key}
+          style={[
+            styles.title,
+            {
+              opacity: position.interpolate({
+                inputRange: [ index - 1, index, index + 1 ],
+                outputRange: [ 0, 1, 0 ],
+              }),
+              transform: [
+                {
+                  translateX: position.interpolate({
+                    inputRange: [ index - 1, index + 1 ],
+                    outputRange: [ 200, -200 ],
+                  }),
+                }
+              ],
+            }
+          ]}
+        >
+          {renderTitleComponent(state, index)}
+        </Animated.View>
+      );
     }
-    return (
-      <TouchableOpacity style={styles.backButton} onPress={this._handleBackPress}>
-        <Image source={require('./back_chevron.png')} style={styles.backButtonImage} />
-      </TouchableOpacity>
-    );
+
+    return null;
   }
-  _renderTitle(childState, index) {
+
+  render() {
+    const { scenes } = this.props;
+
     return (
-      <Animated.Text
-        key={childState.key}
-        style={[
-          styles.title,
-          {
-            opacity: this.props.position.interpolate({
-              inputRange: [index - 1, index, index + 1],
-              outputRange: [0, 1, 0],
-            }),
-            left: this.props.position.interpolate({
-              inputRange: [index - 1, index + 1],
-              outputRange: [200, -200],
-            }),
-            right: this.props.position.interpolate({
-              inputRange: [index - 1, index + 1],
-              outputRange: [-200, 200],
-            }),
-          },
-        ]}>
-        {this.props.getTitle(childState)}
-      </Animated.Text>
+      <View style={[ styles.appbar, this.props.style ]}>
+        {scenes.map(this._renderLeftComponent, this)}
+        {scenes.map(this._renderTitleComponent, this)}
+        {scenes.map(this._renderRightComponent, this)}
+      </View>
     );
   }
-  _handleBackPress() {
-    this.props.onNavigate(NavigationRootContainer.getBackAction());
-  }
 }
 
-NavigationHeader = NavigationContainer.create(NavigationHeader);
+const renderTitleComponent = pageState => <NavigationHeaderTitle>{pageState.title}</NavigationHeaderTitle>;
+const renderLeftComponent = (pageState, index) => index !== 0 ? <NavigationHeaderBackButton /> : null;
+
+NavigationHeader.defaultProps = {
+  renderTitleComponent,
+  renderLeftComponent,
+};
+
+NavigationHeader.propTypes = {
+  position: React.PropTypes.object.isRequired,
+  scenes: React.PropTypes.arrayOf(React.PropTypes.shape({
+    index: React.PropTypes.number,
+    state: React.PropTypes.any,
+  })).isRequired,
+  index: React.PropTypes.number.isRequired,
+  renderTitleComponent: React.PropTypes.func,
+  renderLeftComponent: React.PropTypes.func,
+  renderRightComponent: React.PropTypes.func,
+  style: View.propTypes.style,
+};
+
+NavigationHeader.APPBAR_HEIGHT = APPBAR_HEIGHT;
+NavigationHeader.STATUSBAR_HEIGHT = STATUSBAR_HEIGHT;
 
 const styles = StyleSheet.create({
+  appbar: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    justifyContent: 'flex-start',
+    backgroundColor: Platform.OS === 'ios' ? 'rgba(255, 255, 255, .9)' : 'rgba(255, 255, 255, 1)',
+    borderBottomWidth: Platform.OS === 'ios' ? StyleSheet.hairlineWidth : 0,
+    borderBottomColor: 'rgba(0, 0, 0, .15)',
+    height: APPBAR_HEIGHT + STATUSBAR_HEIGHT,
+    marginBottom: 16, // This is needed for elevation shadow
+    elevation: 2,
+  },
+
   title: {
-    textAlign: 'center',
-    marginTop: 10,
-    fontSize: 18,
-    fontWeight: '500',
-    color: '#0A0A0A',
     position: 'absolute',
-    top: 20,
-    left: 0,
-    right: 0,
+    top: 0,
+    bottom: 0,
+    left: APPBAR_HEIGHT,
+    right: APPBAR_HEIGHT,
+    marginTop: STATUSBAR_HEIGHT,
   },
-  header: {
-    backgroundColor: '#EFEFF2',
-    paddingTop: 20,
+
+  left: {
+    position: 'absolute',
     top: 0,
-    height: 64,
-    right: 0,
+    bottom: 0,
     left: 0,
-    borderBottomWidth: 0.5,
-    borderBottomColor: '#828287',
-    position: 'absolute',
+    marginTop: STATUSBAR_HEIGHT,
   },
-  backButton: {
-    width: 29,
-    height: 37,
+
+  right: {
     position: 'absolute',
-    bottom: 4,
-    left: 2,
-    padding: 8,
-  },
-  backButtonImage: {
-    width: 13,
-    height: 21,
-  },
+    top: 0,
+    bottom: 0,
+    right: 0,
+    marginTop: STATUSBAR_HEIGHT,
+  }
 });
 
-module.exports = NavigationHeader;
+module.exports = NavigationContainer.create(NavigationHeader);
diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationHeaderBackButton.js b/Libraries/CustomComponents/NavigationExperimental/NavigationHeaderBackButton.js
new file mode 100644
index 000000000000..4cd4a867676c
--- /dev/null
+++ b/Libraries/CustomComponents/NavigationExperimental/NavigationHeaderBackButton.js
@@ -0,0 +1,59 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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 NavigationHeaderBackButton
+ * @flow
+*/
+'use strict';
+
+const React = require('react-native');
+const NavigationContainer = require('NavigationContainer');
+const NavigationRootContainer = require('NavigationRootContainer');
+
+const {
+  Image,
+  Platform,
+  StyleSheet,
+  TouchableOpacity,
+} = React;
+
+type Props = {
+  onNavigate: Function
+}
+
+const NavigationHeaderBackButton = (props: Props) => (
+  <TouchableOpacity style={styles.buttonContainer} onPress={() => props.onNavigate(NavigationRootContainer.getBackAction())}>
+    <Image style={styles.button} source={require('./assets/back-icon.png')} />
+  </TouchableOpacity>
+);
+
+NavigationHeaderBackButton.propTypes = {
+  onNavigate: React.PropTypes.func.isRequired
+};
+
+const styles = StyleSheet.create({
+  buttonContainer: {
+    flex: 1,
+    flexDirection: 'row',
+    alignItems: 'center',
+    justifyContent: 'center',
+  },
+  button: {
+    height: 24,
+    width: 24,
+    margin: Platform.OS === 'ios' ? 10 : 16,
+    resizeMode: 'contain'
+  }
+});
+
+module.exports = NavigationContainer.create(NavigationHeaderBackButton);
diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationHeaderTitle.js b/Libraries/CustomComponents/NavigationExperimental/NavigationHeaderTitle.js
new file mode 100644
index 000000000000..94fd4c00a8d4
--- /dev/null
+++ b/Libraries/CustomComponents/NavigationExperimental/NavigationHeaderTitle.js
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2015, Facebook, Inc.  All rights reserved.
+ *
+ * Facebook, Inc. ("Facebook") owns all right, title and interest, including
+ * all intellectual property and other proprietary rights, in and to the React
+ * Native CustomComponents software (the "Software").  Subject to your
+ * compliance with these terms, you are hereby granted a non-exclusive,
+ * worldwide, royalty-free copyright license to (1) use and copy the Software;
+ * and (2) reproduce and distribute the Software as part of your own software
+ * ("Your Software").  Facebook reserves all rights not expressly granted to
+ * you in this license agreement.
+ *
+ * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "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 FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
+ * EMPLOYEES 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 THE SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @providesModule NavigationHeaderTitle
+ * @flow
+ */
+'use strict';
+
+const React = require('react-native');
+
+const {
+  Platform,
+  StyleSheet,
+  View,
+  Text,
+} = React;
+
+type Props = {
+  children: ReactElement;
+  style: any;
+  textStyle: any;
+}
+
+const NavigationHeaderTitle = ({ children, style, textStyle }: Props) => (
+  <View style={[ styles.title, style ]}>
+    <Text style={[ styles.titleText, textStyle ]}>{children}</Text>
+  </View>
+);
+
+const styles = StyleSheet.create({
+  title: {
+    flex: 1,
+    flexDirection: 'row',
+    alignItems: 'center',
+    marginHorizontal: 16
+  },
+
+  titleText: {
+    flex: 1,
+    fontSize: 18,
+    fontWeight: '500',
+    color: 'rgba(0, 0, 0, .9)',
+    textAlign: Platform.OS === 'ios' ? 'center' : 'left'
+  }
+});
+
+NavigationHeaderTitle.propTypes = {
+  children: React.PropTypes.string.isRequired,
+  style: View.propTypes.style,
+  textStyle: Text.propTypes.style
+};
+
+module.exports = NavigationHeaderTitle;
diff --git a/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1.5x.android.png b/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1.5x.android.png
new file mode 100644
index 0000000000000000000000000000000000000000..ad03a63bf3caba175695f5acca85a690dda2d02c
GIT binary patch
diff --git a/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1.5x.ios.png b/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1.5x.ios.png
new file mode 100644
index 0000000000000000000000000000000000000000..e43fa0622f1994f253465b85a59cabc490f25254
GIT binary patch
diff --git a/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1x.android.png b/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1x.android.png
new file mode 100644
index 0000000000000000000000000000000000000000..083db295f474b9903408258c71818c2c49151d35
GIT binary patch
diff --git a/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1x.ios.png b/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1x.ios.png
new file mode 100644
index 0000000000000000000000000000000000000000..4244656b92fb7078e26e9387bc79092e40e32134
GIT binary patch
diff --git a/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@2x.android.png b/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@2x.android.png
new file mode 100644
index 0000000000000000000000000000000000000000..6de0a1cbb365dfd5d9274890d243ca2321f32235
GIT binary patch
diff --git a/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@2x.ios.png b/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@2x.ios.png
new file mode 100644
index 0000000000000000000000000000000000000000..a8b6e9a63e5954e88cdc2c4b376350f0d00df554
GIT binary patch
diff --git a/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@3x.android.png b/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@3x.android.png
new file mode 100644
index 0000000000000000000000000000000000000000..15a983a67d97c9a6c39d91550a528c37c53a9e3e
GIT binary patch
diff --git a/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@3x.ios.png b/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@3x.ios.png
new file mode 100644
index 0000000000000000000000000000000000000000..07ea37b4e1e252d9a406eb33af2efe80e8612330
GIT binary patch
diff --git a/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@4x.android.png b/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@4x.android.png
new file mode 100644
index 0000000000000000000000000000000000000000..17e52e8550e5668f7117bcb755beb70c3a21c9e9
GIT binary patch
diff --git a/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@4x.ios.png b/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@4x.ios.png
new file mode 100644
index 0000000000000000000000000000000000000000..7899053f61b38b1b3f3e4400d208265e5b9752cf
GIT binary patch
diff --git a/Libraries/CustomComponents/NavigationExperimental/back_chevron.png b/Libraries/CustomComponents/NavigationExperimental/back_chevron.png
deleted file mode 100644
index af21cf9d5718b71d1d2be0c445fa7f6012813609..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/Libraries/NavigationExperimental/NavigationAnimatedView.js b/Libraries/NavigationExperimental/NavigationAnimatedView.js
index 4d1f5b68f16e..918307210311 100644
--- a/Libraries/NavigationExperimental/NavigationAnimatedView.js
+++ b/Libraries/NavigationExperimental/NavigationAnimatedView.js
@@ -21,14 +21,9 @@ var View = require('View');
 import type {
   NavigationState,
   NavigationParentState,
+  NavigationScene,
 } from 'NavigationStateUtils';
 
-type NavigationScene = {
-  index: number,
-  state: NavigationState,
-  isStale: boolean,
-};
-
 /**
  * Helper function to compare route keys (e.g. "9", "11").
  */
@@ -70,6 +65,13 @@ type Layout = {
   height: Animated.Value;
 };
 
+type OverlayRenderer = (
+  scenes: Array<NavigationScene>,
+  index: number,
+  position: Animated.Value,
+  layout: Layout
+) => ReactElement;
+
 type Position = Animated.Value;
 
 /**
@@ -251,6 +253,11 @@ class NavigationAnimatedView extends React.Component {
   }
 }
 
+NavigationAnimatedView.propTypes = {
+  navigationState: React.PropTypes.instanceOf(NavigationStateUtils),
+  style: View.propTypes.style,
+};
+
 function setDefaultTiming(position, navigationState) {
   Animated.spring(
     position,
diff --git a/Libraries/NavigationExperimental/NavigationExperimental.js b/Libraries/NavigationExperimental/NavigationExperimental.js
index ca6bb627d559..0f4e9fa63c4e 100644
--- a/Libraries/NavigationExperimental/NavigationExperimental.js
+++ b/Libraries/NavigationExperimental/NavigationExperimental.js
@@ -16,6 +16,8 @@ const NavigationCard = require('NavigationCard');
 const NavigationCardStack = require('NavigationCardStack');
 const NavigationContainer = require('NavigationContainer');
 const NavigationHeader = require('NavigationHeader');
+const NavigationHeaderTitle = require('NavigationHeaderTitle');
+const NavigationHeaderBackButton = require('NavigationHeaderBackButton');
 const NavigationLegacyNavigator = require('NavigationLegacyNavigator');
 const NavigationReducer = require('NavigationReducer');
 const NavigationRootContainer = require('NavigationRootContainer');
@@ -39,6 +41,8 @@ const NavigationExperimental = {
   Card: NavigationCard,
   CardStack: NavigationCardStack,
   Header: NavigationHeader,
+  HeaderTitle: NavigationHeaderTitle,
+  HeaderBackButton: NavigationHeaderBackButton,
   LegacyNavigator: NavigationLegacyNavigator,
 };
 
diff --git a/Libraries/NavigationExperimental/NavigationStateUtils.js b/Libraries/NavigationExperimental/NavigationStateUtils.js
index d457ebea8ada..28d5c85bd3ac 100644
--- a/Libraries/NavigationExperimental/NavigationStateUtils.js
+++ b/Libraries/NavigationExperimental/NavigationStateUtils.js
@@ -23,6 +23,12 @@ export type NavigationParentState = {
   children: Array<NavigationState>;
 };
 
+export type NavigationScene = {
+  index: number;
+  state: NavigationState;
+  isStale: boolean;
+};
+
 export type NavigationAction = {
   type: string;
 };

From 854c5ddf166c7a309ade0ca9935eca07122b5aa3 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Wed, 2 Mar 2016 15:24:44 -0800
Subject: [PATCH 1386/1411] Simplified Travis configuration

Summary:Merged Travis js tests into one test run.

This should simplify test runs, reduce chances of external infra failures and make CI reports more focused.

**Test plan (required)**

See how travis runs it.
Need to double check that APPETIZE_TOKEN and S3_TOKEN aren't used.
Closes https://github.com/facebook/react-native/pull/6172

Differential Revision: D3001437

fb-gh-sync-id: 203e18ce0706d4ab1ab55cfe016beed3e3558dcc
shipit-source-id: 203e18ce0706d4ab1ab55cfe016beed3e3558dcc
---
 .travis.yml | 29 +++++++----------------------
 circle.yml  |  2 ++
 2 files changed, 9 insertions(+), 22 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index a5ff66f5132f..fea5c97a1c24 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -15,6 +15,7 @@ install:
   - nvm install 5
   - rm -Rf "${TMPDIR}/jest_preprocess_cache"
   - npm config set spin=false
+  - npm config set progress=false
   - npm install -g flow-bin@`node -p "require('fs').readFileSync('.flowconfig', 'utf8').split('[version]')[1].trim()"`
   - npm install
 
@@ -23,29 +24,20 @@ script:
   if [ "$TEST_TYPE" = objc ]
   then
 
-    ./scripts/objc-test.sh
+    travis_retry ./scripts/objc-test.sh
 
   elif [ "$TEST_TYPE" = js ]
   then
 
     npm install github@0.2.4
     cat <(echo eslint; npm run lint --silent -- --format=json; echo flow; flow --json) | GITHUB_TOKEN="af6ef0d15709bc91d""06a6217a5a826a226fb57b7" node bots/code-analysis-bot.js
-    flow check && npm test -- '\/Libraries\/'
+    flow check
+    npm test
 
-  elif [ "$TEST_TYPE" = packager ]
+  elif [ "$TEST_TYPE" = e2e-objc ]
   then
 
-    npm test -- '\/packager\/'
-
-  elif [ "$TEST_TYPE" = cli ]
-  then
-
-    npm test -- '\/(local|private|react-native)-cli\/'
-
-  elif [ "$TEST_TYPE" = e2e ]
-  then
-
-    ./scripts/e2e-test.sh
+    travis_retry ./scripts/e2e-test.sh
 
   else
     echo "Unknown test type: $TEST_TYPE"
@@ -56,14 +48,7 @@ env:
   matrix:
     - TEST_TYPE=objc
     - TEST_TYPE=js
-    - TEST_TYPE=packager
-    - TEST_TYPE=cli
-    - TEST_TYPE=e2e
-  global:
-    # $APPETIZE_TOKEN
-    - secure: "egsvVSpszTzrNd6bN62DsVAzMiSZI/OHgdizfPryqvqWBf655ztE6XFQSEFNpuIAzSKDDF25ioT8iPfVsbC1iK6HDWHfmqYxML0L+OoU0gi+hV2oKUBFZDZ1fwSnFoWuBdNdMDpLlUxvJp6N1WyfNOB2dxuZUt8eTt48Hi3+Hpc="
-    # $S3_TOKEN
-    - secure: "lY8JZPA0A7zT7L5KF9BBg34XYWIeR/RJiEvE7l7oVr88KnEPtyd//79eHhhVKnUnav7zsk5QJwkcX0MxKTp/dp4G0Am+zOX+sfA8kQrJ+2/+FzFW7AEsW/kHByfaIEIly9DQvUFt4I4oMm8nQZysJLahDgNWglyI3RTuJp//hcY="
+    - TEST_TYPE=e2e-objc
 
 branches:
   only:
diff --git a/circle.yml b/circle.yml
index f16f69e1ed5a..f8e17b4c1801 100644
--- a/circle.yml
+++ b/circle.yml
@@ -30,6 +30,8 @@ dependencies:
     - "buck-out/bin"
     - "website/node_modules"
   override:
+    - npm config set spin=false
+    - npm config set progress=false
     - npm install
     - cd website && npm install
 

From 2708df49e3d7e1404bbf36604c14c72068cce08c Mon Sep 17 00:00:00 2001
From: David Aurelio <davidaurelio@fb.com>
Date: Wed, 2 Mar 2016 17:13:47 -0800
Subject: [PATCH 1387/1411] Use `invariant` from fbjs everywhere

Reviewed By: yungsters

Differential Revision: D3002422

fb-gh-sync-id: c7d308e6cfc717726dbbc43a2462fdabb052b2fe
shipit-source-id: c7d308e6cfc717726dbbc43a2462fdabb052b2fe
---
 packager/blacklist.js | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/packager/blacklist.js b/packager/blacklist.js
index acca4c167c81..b6476dc45063 100644
--- a/packager/blacklist.js
+++ b/packager/blacklist.js
@@ -21,6 +21,8 @@ var sharedBlacklist = [
   'node_modules/fbjs/lib/Map.js',
   'node_modules/fbjs/lib/isEmpty.js',
 
+  'downstream/core/invariant.js',
+
   /website\/node_modules\/.*/,
 
   // TODO(jkassens, #9876132): Remove this rule when it's no longer needed.

From 8f3e5b1e93bac84514dbc0775afdbef30d570722 Mon Sep 17 00:00:00 2001
From: Frank Yan <frankyan@fb.com>
Date: Thu, 3 Mar 2016 00:51:05 -0800
Subject: [PATCH 1388/1411] Update usage names of React Native color palette

Reviewed By: weicool

Differential Revision: D2978557

fb-gh-sync-id: ef6b6b24e7db7faf3aecee0a9755565e1b41be58
shipit-source-id: ef6b6b24e7db7faf3aecee0a9755565e1b41be58
---
 Libraries/Utilities/CSSVarConfig.js | 85 +----------------------------
 1 file changed, 1 insertion(+), 84 deletions(-)

diff --git a/Libraries/Utilities/CSSVarConfig.js b/Libraries/Utilities/CSSVarConfig.js
index 69f83c14e293..55c0244c3d7e 100644
--- a/Libraries/Utilities/CSSVarConfig.js
+++ b/Libraries/Utilities/CSSVarConfig.js
@@ -5,85 +5,9 @@
  */
 'use strict';
 
-// this a partial list of the constants in CSSConstants:: from PHP that are applicable to mobile
-
 module.exports = {
-  // FIG UI Core
-  'fbui-blue': '#4267b2',
-  'fbui-accent': '#4080ff',
-  'fbui-highlight': '#ecf3ff',
-  'fbui-green': '#4bc832',
-  'fbui-red': '#fa3e3e',
-  'fbui-white': '#ffffff',
-  'fbui-black': '#000000',
-
-  // FIG UI Light
-  'fbui-light-02': '#f6f7f9',
-  'fbui-light-05': '#e9ebee',
-  'fbui-light-10': '#dddfe2',
-  'fbui-light-15': '#ced0d4',
-  'fbui-light-20': '#bec2c9',
-  'fbui-light-30': '#90949c',
-  'fbui-light-50': '#4b4f56',
-  'fbui-light-80': '#1d2129',
-
-  // FIG UI Alpha
-  'fbui-white-alpha-15': 'rgba(255, 255, 255, .15)',
-  'fbui-white-alpha-30': 'rgba(255, 255, 255, .3)',
-  'fbui-white-alpha-40': 'rgba(255, 255, 255, .4)',
-  'fbui-white-alpha-50': 'rgba(255, 255, 255, .5)',
-  'fbui-white-alpha-80': 'rgba(255, 255, 255, .8)',
-  'fbui-black-alpha-15': 'rgba(0, 0, 0, .15)',
-  'fbui-black-alpha-30': 'rgba(0, 0, 0, .3)',
-  'fbui-black-alpha-40': 'rgba(0, 0, 0, .4)',
-  'fbui-black-alpha-50': 'rgba(0, 0, 0, .5)',
-  'fbui-black-alpha-80': 'rgba(0, 0, 0, .8)',
-
-  // FB UI Dark
-  'fbui-dark-20': '#cccccc',
-  'fbui-dark-50': '#7f7f7f',
-  'fbui-dark-70': '#4c4c4c',
-  'fbui-dark-80': '#333333',
-  'fbui-dark-85': '#262626',
-  'fbui-dark-90': '#191919',
-  'fbui-dark-95': '#0d0d0d',
-
-  // FIG UI Core - Blue variants
-  'fbui-blue-dark-1': '#29487d',
-  'fbui-blue-dark-2': '#20375f',
-  'fbui-blue-dark-3': '#162643',
-  'fbui-blue-tint-15': '#577fbc',
-  'fbui-blue-tint-30': '#7596c8',
-  'fbui-blue-tint-50': '#9cb4d8',
-  'fbui-blue-tint-70': '#c4d2e7',
-  'fbui-blue-tint-90': '#ecf0f7',
-
   'fbui-accent-blue': '#5890ff',
-  'fbui-blue-90': '#4e69a2',
-  'fbui-blue-80': '#627aad',
-  'fbui-blue-70': '#758ab7',
-  'fbui-blue-60': '#899bc1',
-  'fbui-blue-50': '#9daccb',
-  'fbui-blue-40': '#b1bdd6',
-  'fbui-blue-30': '#c4cde0',
-  'fbui-blue-20': '#d8deea',
-  'fbui-blue-10': '#ebeef4',
-  'fbui-blue-5': '#f5f7fa',
-  'fbui-blue-2': '#fbfcfd',
-  'fbui-blueblack-90': '#06090f',
-  'fbui-blueblack-80': '#0c121e',
-  'fbui-blueblack-70': '#121b2e',
-  'fbui-blueblack-60': '#18243d',
-  'fbui-blueblack-50': '#1e2d4c',
-  'fbui-blueblack-40': '#23355b',
-  'fbui-blueblack-30': '#293e6b',
-  'fbui-blueblack-20': '#2f477a',
-  'fbui-blueblack-10': '#355089',
-  'fbui-blueblack-5': '#385490',
-  'fbui-blueblack-2': '#3a5795',
-  'fbui-bluegray-90': '#080a10',
   'fbui-bluegray-80': '#141823',
-  'fbui-bluegray-70': '#232937',
   'fbui-bluegray-60': '#373e4d',
   'fbui-bluegray-50': '#4e5665',
   'fbui-bluegray-40': '#6a7180',
@@ -92,20 +16,13 @@ module.exports = {
   'fbui-bluegray-10': '#dcdee3',
   'fbui-bluegray-5': '#e9eaed',
   'fbui-bluegray-2': '#f6f7f8',
-  'fbui-gray-90': '#191919',
   'fbui-gray-80': '#333333',
-  'fbui-gray-70': '#4c4c4c',
   'fbui-gray-60': '#666666',
-  'fbui-gray-50': '#7f7f7f',
   'fbui-gray-40': '#999999',
-  'fbui-gray-30': '#b2b2b2',
   'fbui-gray-20': '#cccccc',
   'fbui-gray-10': '#e5e5e5',
   'fbui-gray-5': '#f2f2f2',
   'fbui-gray-2': '#fafafa',
-  'fbui-error': '#ce0d24',
-  'x-mobile-dark-text': '#4e5665',
+  'fbui-red': '#dc3847',
   'x-mobile-medium-text': '#6a7180',
-  'x-mobile-light-text': '#9197a3',
-  'x-mobile-base-wash': '#dcdee3',
 };

From dc13115445681c1e04079f6a47668e1f12e6020a Mon Sep 17 00:00:00 2001
From: Nick Lockwood <nicklockwood@fb.com>
Date: Thu, 3 Mar 2016 02:20:20 -0800
Subject: [PATCH 1389/1411] Dispatch module setup asynchronously to avoid
 blocking main thread when bridge starts

Summary:Initializing native modules can block the main thread for tens of milliseconds when it starts up, making it difficult to instantiate the bridge on demand without causing a performance blip.

This diff splits up the initialization of modules so that - although they still happen on the main thread - they don't block the thread continuously.

Reviewed By: javache

Differential Revision: D2965438

fb-gh-sync-id: 38c9c9d281e4672b5874d68b57d4c60d1d268344
shipit-source-id: 38c9c9d281e4672b5874d68b57d4c60d1d268344
---
 .../UIExplorerUnitTests/RCTImageLoaderTests.m |  20 +-
 .../RCTModuleInitNotificationRaceTests.m      |  15 +-
 .../UIExplorerUnitTests/RCTModuleInitTests.m  |   9 +-
 Libraries/Image/RCTImageLoader.h              |   9 +
 Libraries/Image/RCTImageLoader.m              |  82 +++---
 Libraries/Network/RCTNetworking.m             |  15 +-
 React/Base/RCTBatchedBridge.m                 | 240 +++++++++---------
 React/Base/RCTBridge+Private.h                |   5 +
 React/Base/RCTBridge.h                        |  37 +--
 React/Base/RCTBridge.m                        |  53 +---
 React/Base/RCTModuleData.h                    |  26 +-
 React/Base/RCTModuleData.m                    | 109 ++++++--
 React/Views/RCTViewManager.m                  |   3 +
 13 files changed, 308 insertions(+), 315 deletions(-)

diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderTests.m
index 5713d03473a7..5a7cc12bd28e 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderTests.m
@@ -47,10 +47,9 @@ - (void)testImageLoading
     return nil;
   }];
 
-  RCTImageLoader *imageLoader = [RCTImageLoader new];
-  NS_VALID_UNTIL_END_OF_SCOPE RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil moduleProvider:^{ return @[loader, imageLoader]; } launchOptions:nil];
+  NS_VALID_UNTIL_END_OF_SCOPE RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil moduleProvider:^{ return @[loader]; } launchOptions:nil];
 
-  [imageLoader loadImageWithTag:@"http://facebook.github.io/react/img/logo_og.png" size:CGSizeMake(100, 100) scale:1.0 resizeMode:RCTResizeModeContain progressBlock:^(int64_t progress, int64_t total) {
+  [bridge.imageLoader loadImageWithTag:@"http://facebook.github.io/react/img/logo_og.png" size:CGSizeMake(100, 100) scale:1.0 resizeMode:RCTResizeModeContain progressBlock:^(int64_t progress, int64_t total) {
     XCTAssertEqual(progress, 1);
     XCTAssertEqual(total, 1);
   } completionBlock:^(NSError *loadError, id loadedImage) {
@@ -78,10 +77,9 @@ - (void)testImageLoaderUsesImageURLLoaderWithHighestPriority
     return nil;
   }];
 
-  RCTImageLoader *imageLoader = [RCTImageLoader new];
-  NS_VALID_UNTIL_END_OF_SCOPE RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil moduleProvider:^{ return @[loader1, loader2, imageLoader]; } launchOptions:nil];
+  NS_VALID_UNTIL_END_OF_SCOPE RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil moduleProvider:^{ return @[loader1, loader2]; } launchOptions:nil];
 
-  [imageLoader loadImageWithTag:@"http://facebook.github.io/react/img/logo_og.png" size:CGSizeMake(100, 100) scale:1.0 resizeMode:RCTResizeModeContain progressBlock:^(int64_t progress, int64_t total) {
+  [bridge.imageLoader loadImageWithTag:@"http://facebook.github.io/react/img/logo_og.png" size:CGSizeMake(100, 100) scale:1.0 resizeMode:RCTResizeModeContain progressBlock:^(int64_t progress, int64_t total) {
     XCTAssertEqual(progress, 1);
     XCTAssertEqual(total, 1);
   } completionBlock:^(NSError *loadError, id loadedImage) {
@@ -103,10 +101,9 @@ - (void)testImageDecoding
     return nil;
   }];
 
-  RCTImageLoader *imageLoader = [RCTImageLoader new];
-  NS_VALID_UNTIL_END_OF_SCOPE RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil moduleProvider:^{ return @[decoder, imageLoader]; } launchOptions:nil];
+  NS_VALID_UNTIL_END_OF_SCOPE RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil moduleProvider:^{ return @[decoder]; } launchOptions:nil];
 
-  RCTImageLoaderCancellationBlock cancelBlock = [imageLoader decodeImageData:data size:CGSizeMake(1, 1) scale:1.0 resizeMode:RCTResizeModeStretch completionBlock:^(NSError *decodeError, id decodedImage) {
+  RCTImageLoaderCancellationBlock cancelBlock = [bridge.imageLoader decodeImageDataWithoutClipping:data size:CGSizeMake(1, 1) scale:1.0 resizeMode:RCTResizeModeStretch completionBlock:^(NSError *decodeError, id decodedImage) {
     XCTAssertEqualObjects(decodedImage, image);
     XCTAssertNil(decodeError);
   }];
@@ -133,10 +130,9 @@ - (void)testImageLoaderUsesImageDecoderWithHighestPriority
     return nil;
   }];
 
-  RCTImageLoader *imageLoader = [RCTImageLoader new];
-  NS_VALID_UNTIL_END_OF_SCOPE RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil moduleProvider:^{ return @[decoder1, decoder2, imageLoader]; } launchOptions:nil];
+  NS_VALID_UNTIL_END_OF_SCOPE RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil moduleProvider:^{ return @[decoder1, decoder2]; } launchOptions:nil];
 
-  RCTImageLoaderCancellationBlock cancelBlock = [imageLoader decodeImageData:data size:CGSizeMake(1, 1) scale:1.0 resizeMode:RCTResizeModeStretch completionBlock:^(NSError *decodeError, id decodedImage) {
+  RCTImageLoaderCancellationBlock cancelBlock = [bridge.imageLoader decodeImageDataWithoutClipping:data size:CGSizeMake(1, 1) scale:1.0 resizeMode:RCTResizeModeStretch completionBlock:^(NSError *decodeError, id decodedImage) {
     XCTAssertEqualObjects(decodedImage, image);
     XCTAssertNil(decodeError);
   }];
diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleInitNotificationRaceTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleInitNotificationRaceTests.m
index 39650db2769b..77a997a4baa5 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleInitNotificationRaceTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleInitNotificationRaceTests.m
@@ -34,26 +34,13 @@
   } \
 }
 
-// Must be declared before RCTTestCustomSetBridgeModule in order to trigger the
-// race condition that we are testing for - namely that the
-// RCTDidInitializeModuleNotification for RCTTestViewManager gets sent before
-// setBridge: is called on RCTTestCustomSetBridgeModule
 @interface RCTTestViewManager : RCTViewManager
 @end
 
 @implementation RCTTestViewManager
 
-@synthesize bridge = _bridge;
-@synthesize methodQueue = _methodQueue;
-
 RCT_EXPORT_MODULE()
 
-- (void)setBridge:(RCTBridge *)bridge
-{
-  _bridge = bridge;
-  (void)[_bridge uiManager]; // Needed to trigger a race condition
-}
-
 - (NSArray<NSString *> *)customDirectEventTypes
 {
   return @[@"foo"];
@@ -112,7 +99,7 @@ - (NSURL *)sourceURLForBridge:(__unused RCTBridge *)bridge
 
 - (NSArray *)extraModulesForBridge:(__unused RCTBridge *)bridge
 {
-  return @[_notificationObserver];
+  return @[[RCTTestViewManager new], _notificationObserver];
 }
 
 - (void)setUp
diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleInitTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleInitTests.m
index a0289b2e40ee..83a549736809 100644
--- a/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleInitTests.m
+++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTModuleInitTests.m
@@ -202,10 +202,11 @@ - (void)moduleDidInit:(NSNotification *)note
 
 - (void)testInjectedModulesInitializedDuringBridgeInit
 {
-  XCTAssertTrue(_injectedModuleInitNotificationSent);
   XCTAssertEqual(_injectedModule, [_bridge moduleForClass:[RCTTestInjectedModule class]]);
   XCTAssertEqual(_injectedModule.bridge, _bridge.batchedBridge);
   XCTAssertNotNil(_injectedModule.methodQueue);
+  RUN_RUNLOOP_WHILE(!_injectedModuleInitNotificationSent);
+  XCTAssertTrue(_injectedModuleInitNotificationSent);
 }
 
 - (void)testCustomInitModuleInitializedAtBridgeStartup
@@ -214,6 +215,8 @@ - (void)testCustomInitModuleInitializedAtBridgeStartup
   XCTAssertTrue(_customInitModuleNotificationSent);
   RCTTestCustomInitModule *module = [_bridge moduleForClass:[RCTTestCustomInitModule class]];
   XCTAssertTrue(module.initializedOnMainThread);
+  XCTAssertEqual(module.bridge, _bridge.batchedBridge);
+  XCTAssertNotNil(module.methodQueue);
 }
 
 - (void)testCustomSetBridgeModuleInitializedAtBridgeStartup
@@ -222,6 +225,8 @@ - (void)testCustomSetBridgeModuleInitializedAtBridgeStartup
   XCTAssertTrue(_customSetBridgeModuleNotificationSent);
   RCTTestCustomSetBridgeModule *module = [_bridge moduleForClass:[RCTTestCustomSetBridgeModule class]];
   XCTAssertTrue(module.setBridgeOnMainThread);
+  XCTAssertEqual(module.bridge, _bridge.batchedBridge);
+  XCTAssertNotNil(module.methodQueue);
 }
 
 - (void)testExportConstantsModuleInitializedAtBridgeStartup
@@ -232,6 +237,8 @@ - (void)testExportConstantsModuleInitializedAtBridgeStartup
   RUN_RUNLOOP_WHILE(!module.exportedConstants);
   XCTAssertTrue(module.exportedConstants);
   XCTAssertTrue(module.exportedConstantsOnMainThread);
+  XCTAssertEqual(module.bridge, _bridge.batchedBridge);
+  XCTAssertNotNil(module.methodQueue);
 }
 
 - (void)testLazyInitModuleNotInitializedDuringBridgeInit
diff --git a/Libraries/Image/RCTImageLoader.h b/Libraries/Image/RCTImageLoader.h
index cfe3d83fc871..d11c424103d3 100644
--- a/Libraries/Image/RCTImageLoader.h
+++ b/Libraries/Image/RCTImageLoader.h
@@ -91,6 +91,15 @@ typedef void (^RCTImageLoaderCancellationBlock)(void);
                                         resizeMode:(RCTResizeMode)resizeMode
                                    completionBlock:(RCTImageLoaderCompletionBlock)completionBlock;
 
+/**
+ * Decodes an image without clipping the result to fit.
+ */
+- (RCTImageLoaderCancellationBlock)decodeImageDataWithoutClipping:(NSData *)data
+                                                             size:(CGSize)size
+                                                            scale:(CGFloat)scale
+                                                       resizeMode:(RCTResizeMode)resizeMode
+                                                  completionBlock:(RCTImageLoaderCompletionBlock)completionBlock;
+
 /**
  * Get image size, in pixels. This method will do the least work possible to get
  * the information, and won't decode the image if it doesn't have to.
diff --git a/Libraries/Image/RCTImageLoader.m b/Libraries/Image/RCTImageLoader.m
index ea4d42acf664..207ecf7024b2 100644
--- a/Libraries/Image/RCTImageLoader.m
+++ b/Libraries/Image/RCTImageLoader.m
@@ -59,54 +59,31 @@ - (void)setUp
   _maxConcurrentDecodingTasks = _maxConcurrentDecodingTasks ?: 2;
   _maxConcurrentDecodingBytes = _maxConcurrentDecodingBytes ?: 30 * 1024 *1024; // 30MB
 
-  // Get image loaders and decoders
-  NSMutableArray<id<RCTImageURLLoader>> *loaders = [NSMutableArray array];
-  NSMutableArray<id<RCTImageDataDecoder>> *decoders = [NSMutableArray array];
-  for (Class moduleClass in _bridge.moduleClasses) {
-    if ([moduleClass conformsToProtocol:@protocol(RCTImageURLLoader)]) {
-      [loaders addObject:[_bridge moduleForClass:moduleClass]];
-    }
-    if ([moduleClass conformsToProtocol:@protocol(RCTImageDataDecoder)]) {
-      [decoders addObject:[_bridge moduleForClass:moduleClass]];
-    }
-  }
-
-  // Sort loaders in reverse priority order (highest priority first)
-  [loaders sortUsingComparator:^NSComparisonResult(id<RCTImageURLLoader> a, id<RCTImageURLLoader> b) {
-    float priorityA = [a respondsToSelector:@selector(loaderPriority)] ? [a loaderPriority] : 0;
-    float priorityB = [b respondsToSelector:@selector(loaderPriority)] ? [b loaderPriority] : 0;
-    if (priorityA > priorityB) {
-      return NSOrderedAscending;
-    } else if (priorityA < priorityB) {
-      return NSOrderedDescending;
-    } else {
-      return NSOrderedSame;
-    }
-  }];
-
-  // Sort decoders in reverse priority order (highest priority first)
-  [decoders sortUsingComparator:^NSComparisonResult(id<RCTImageDataDecoder> a, id<RCTImageDataDecoder> b) {
-    float priorityA = [a respondsToSelector:@selector(decoderPriority)] ? [a decoderPriority] : 0;
-    float priorityB = [b respondsToSelector:@selector(decoderPriority)] ? [b decoderPriority] : 0;
-    if (priorityA > priorityB) {
-      return NSOrderedAscending;
-    } else if (priorityA < priorityB) {
-      return NSOrderedDescending;
-    } else {
-      return NSOrderedSame;
-    }
-  }];
-
-  _loaders = loaders;
-  _decoders = decoders;
+  _URLCacheQueue = dispatch_queue_create("com.facebook.react.ImageLoaderURLCacheQueue", DISPATCH_QUEUE_SERIAL);
 }
 
 - (id<RCTImageURLLoader>)imageURLLoaderForURL:(NSURL *)URL
 {
-  if (!_loaders) {
+  if (!_maxConcurrentLoadingTasks) {
     [self setUp];
   }
 
+  if (!_loaders) {
+    // Get loaders, sorted in reverse priority order (highest priority first)
+    RCTAssert(_bridge, @"Bridge not set");
+    _loaders = [[_bridge modulesConformingToProtocol:@protocol(RCTImageURLLoader)] sortedArrayUsingComparator:^NSComparisonResult(id<RCTImageURLLoader> a, id<RCTImageURLLoader> b) {
+      float priorityA = [a respondsToSelector:@selector(loaderPriority)] ? [a loaderPriority] : 0;
+      float priorityB = [b respondsToSelector:@selector(loaderPriority)] ? [b loaderPriority] : 0;
+      if (priorityA > priorityB) {
+        return NSOrderedAscending;
+      } else if (priorityA < priorityB) {
+        return NSOrderedDescending;
+      } else {
+        return NSOrderedSame;
+      }
+    }];
+  }
+
   if (RCT_DEBUG) {
     // Check for handler conflicts
     float previousPriority = 0;
@@ -144,10 +121,26 @@ - (void)setUp
 
 - (id<RCTImageDataDecoder>)imageDataDecoderForData:(NSData *)data
 {
-  if (!_decoders) {
+  if (!_maxConcurrentLoadingTasks) {
     [self setUp];
   }
 
+  if (!_decoders) {
+    // Get decoders, sorted in reverse priority order (highest priority first)
+    RCTAssert(_bridge, @"Bridge not set");
+    _decoders = [[_bridge modulesConformingToProtocol:@protocol(RCTImageDataDecoder)] sortedArrayUsingComparator:^NSComparisonResult(id<RCTImageDataDecoder> a, id<RCTImageDataDecoder> b) {
+      float priorityA = [a respondsToSelector:@selector(decoderPriority)] ? [a decoderPriority] : 0;
+      float priorityB = [b respondsToSelector:@selector(decoderPriority)] ? [b decoderPriority] : 0;
+      if (priorityA > priorityB) {
+        return NSOrderedAscending;
+      } else if (priorityA < priorityB) {
+        return NSOrderedDescending;
+      } else {
+        return NSOrderedSame;
+      }
+    }];
+  }
+
   if (RCT_DEBUG) {
     // Check for handler conflicts
     float previousPriority = 0;
@@ -295,7 +288,7 @@ - (RCTImageLoaderCancellationBlock)loadImageOrDataWithTag:(NSString *)imageTag
 
   // All access to URL cache must be serialized
   if (!_URLCacheQueue) {
-    _URLCacheQueue = dispatch_queue_create("com.facebook.react.ImageLoaderURLCacheQueue", DISPATCH_QUEUE_SERIAL);
+    [self setUp];
   }
   dispatch_async(_URLCacheQueue, ^{
 
@@ -539,6 +532,9 @@ - (RCTImageLoaderCancellationBlock)decodeImageDataWithoutClipping:(NSData *)data
                        completionHandler:completionHandler];
   } else {
 
+    if (!_URLCacheQueue) {
+      [self setUp];
+    }
     dispatch_async(_URLCacheQueue, ^{
       dispatch_block_t decodeBlock = ^{
 
diff --git a/Libraries/Network/RCTNetworking.m b/Libraries/Network/RCTNetworking.m
index 47cbc74d222a..88c2de0e06fe 100644
--- a/Libraries/Network/RCTNetworking.m
+++ b/Libraries/Network/RCTNetworking.m
@@ -141,17 +141,8 @@ @implementation RCTNetworking
   }
 
   if (!_handlers) {
-
-    // get handlers
-    NSMutableArray<id<RCTURLRequestHandler>> *handlers = [NSMutableArray array];
-    for (Class moduleClass in _bridge.moduleClasses) {
-      if ([moduleClass conformsToProtocol:@protocol(RCTURLRequestHandler)]) {
-        [handlers addObject:[_bridge moduleForClass:moduleClass]];
-      }
-    }
-
-    // Sort handlers in reverse priority order (highest priority first)
-    [handlers sortUsingComparator:^NSComparisonResult(id<RCTURLRequestHandler> a, id<RCTURLRequestHandler> b) {
+    // Get handlers, sorted in reverse priority order (highest priority first)
+    _handlers = [[_bridge modulesConformingToProtocol:@protocol(RCTURLRequestHandler)] sortedArrayUsingComparator:^NSComparisonResult(id<RCTURLRequestHandler> a, id<RCTURLRequestHandler> b) {
       float priorityA = [a respondsToSelector:@selector(handlerPriority)] ? [a handlerPriority] : 0;
       float priorityB = [b respondsToSelector:@selector(handlerPriority)] ? [b handlerPriority] : 0;
       if (priorityA > priorityB) {
@@ -162,8 +153,6 @@ @implementation RCTNetworking
         return NSOrderedSame;
       }
     }];
-
-    _handlers = handlers;
   }
 
   if (RCT_DEBUG) {
diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m
index 3dd44ec9eae0..3154e4813c7c 100644
--- a/React/Base/RCTBatchedBridge.m
+++ b/React/Base/RCTBatchedBridge.m
@@ -45,29 +45,25 @@ @interface RCTBatchedBridge : RCTBridge
 
 @property (nonatomic, weak) RCTBridge *parentBridge;
 @property (nonatomic, weak) id<RCTJavaScriptExecutor> javaScriptExecutor;
+@property (nonatomic, assign) BOOL moduleSetupComplete;
 
 @end
 
 @implementation RCTBatchedBridge
 {
-  BOOL _loading;
-  BOOL _valid;
   BOOL _wasBatchActive;
   NSMutableArray<dispatch_block_t> *_pendingCalls;
   NSMutableDictionary<NSString *, RCTModuleData *> *_moduleDataByName;
   NSArray<RCTModuleData *> *_moduleDataByID;
-  NSDictionary<NSString *, id<RCTBridgeModule>> *_modulesByName_DEPRECATED;
   NSArray<Class> *_moduleClassesByID;
   CADisplayLink *_jsDisplayLink;
   NSMutableSet<RCTModuleData *> *_frameUpdateObservers;
-
-  // Bridge startup stats (TODO: capture in perf logger)
-  NSUInteger _syncInitializedModules;
-  NSUInteger _asyncInitializedModules;
 }
 
 @synthesize flowID = _flowID;
 @synthesize flowIDMap = _flowIDMap;
+@synthesize loading = _loading;
+@synthesize valid = _valid;
 
 - (instancetype)initWithParentBridge:(RCTBridge *)bridge
 {
@@ -122,11 +118,7 @@ - (void)start
   }];
 
   // Synchronously initialize all native modules that cannot be loaded lazily
-  [self initModules];
-
-#if RCT_DEBUG
-  _syncInitializedModules = [[_moduleDataByID valueForKeyPath:@"@sum.hasInstance"] integerValue];
-#endif
+  [self initModulesWithDispatchGroup:initModulesAndLoadSource];
 
   if (RCTProfileIsProfiling()) {
     // Depends on moduleDataByID being loaded
@@ -145,17 +137,10 @@ - (void)start
 
     // Asynchronously gather the module config
     dispatch_group_async(setupJSExecutorAndModuleConfig, bridgeQueue, ^{
-      if (weakSelf.isValid) {
-
+      if (weakSelf.valid) {
         RCTPerformanceLoggerStart(RCTPLNativeModulePrepareConfig);
         config = [weakSelf moduleConfig];
         RCTPerformanceLoggerEnd(RCTPLNativeModulePrepareConfig);
-
-#if RCT_DEBUG
-        NSInteger total = [[_moduleDataByID valueForKeyPath:@"@sum.hasInstance"] integerValue];
-        _asyncInitializedModules = total - _syncInitializedModules;
-#endif
-
       }
     });
 
@@ -217,7 +202,7 @@ - (void)loadSource:(RCTSourceLoadBlock)_onSourceLoad
 
 - (NSArray<Class> *)moduleClasses
 {
-  if (RCT_DEBUG && self.isValid && _moduleClassesByID == nil) {
+  if (RCT_DEBUG && _valid && _moduleClassesByID == nil) {
     RCTLogError(@"Bridge modules have not yet been initialized. You may be "
                 "trying to access a module too early in the startup procedure.");
   }
@@ -234,8 +219,7 @@ - (RCTModuleData *)moduleDataForName:(NSString *)moduleName
 
 - (id)moduleForName:(NSString *)moduleName
 {
-  RCTModuleData *moduleData = _moduleDataByName[moduleName];
-  return moduleData.instance;
+  return _moduleDataByName[moduleName].instance;
 }
 
 - (NSArray *)configForModuleName:(NSString *)moduleName
@@ -250,14 +234,11 @@ - (NSArray *)configForModuleName:(NSString *)moduleName
   return (id)kCFNull;
 }
 
-- (void)initModules
+- (void)initModulesWithDispatchGroup:(dispatch_group_t)dispatchGroup
 {
   RCTAssertMainThread();
   RCTPerformanceLoggerStart(RCTPLNativeModuleInit);
 
-  // Register passed-in module instances
-  NSMutableDictionary *preregisteredModules = [NSMutableDictionary new];
-
   NSArray<id<RCTBridgeModule>> *extraModules = nil;
   if (self.delegate) {
     if ([self.delegate respondsToSelector:@selector(extraModulesForBridge:)]) {
@@ -267,95 +248,133 @@ - (void)initModules
     extraModules = self.moduleProvider();
   }
 
-  for (id<RCTBridgeModule> module in extraModules) {
-    preregisteredModules[RCTBridgeModuleNameForClass([module class])] = module;
-  }
+  if (RCT_DEBUG && !RCTRunningInTestEnvironment()) {
 
-  SEL setBridgeSelector = NSSelectorFromString(@"setBridge:");
-  IMP objectInitMethod = [NSObject instanceMethodForSelector:@selector(init)];
+    // Check for unexported modules
+    static Class *classes;
+    static unsigned int classCount;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+      classes = objc_copyClassList(&classCount);
+    });
 
-  // Set up moduleData and pre-initialize module instances
-  NSMutableArray<RCTModuleData *> *moduleDataByID = [NSMutableArray new];
-  NSMutableDictionary<NSString *, RCTModuleData *> *moduleDataByName = [NSMutableDictionary new];
-  for (Class moduleClass in RCTGetModuleClasses()) {
-    NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass);
-    id module = preregisteredModules[moduleName];
-    if (!module) {
-      // Check if the module class, or any of its superclasses override init
-      // or setBridge:, or has exported constants. If they do, we assume that
-      // they are expecting to be initialized when the bridge first loads.
-      if ([moduleClass instanceMethodForSelector:@selector(init)] != objectInitMethod ||
-          [moduleClass instancesRespondToSelector:setBridgeSelector] ||
-          RCTClassOverridesInstanceMethod(moduleClass, @selector(constantsToExport))) {
-        module = [moduleClass new];
-        if (!module) {
-          module = (id)kCFNull;
+    NSMutableSet *moduleClasses = [NSMutableSet new];
+    [moduleClasses addObjectsFromArray:RCTGetModuleClasses()];
+    [moduleClasses addObjectsFromArray:[extraModules valueForKeyPath:@"class"]];
+
+    for (unsigned int i = 0; i < classCount; i++)
+    {
+      Class cls = classes[i];
+      Class superclass = cls;
+      while (superclass)
+      {
+        if (class_conformsToProtocol(superclass, @protocol(RCTBridgeModule)))
+        {
+          if (![moduleClasses containsObject:cls]) {
+            RCTLogWarn(@"Class %@ was not exported. Did you forget to use "
+                       "RCT_EXPORT_MODULE()?", cls);
+          }
+          break;
         }
+        superclass = class_getSuperclass(superclass);
       }
     }
+  }
 
-    // Check for module name collisions.
-    // It's OK to have a name collision as long as the second instance is null.
-    if (module != (id)kCFNull && moduleDataByName[moduleName] && !preregisteredModules[moduleName]) {
-      RCTLogError(@"Attempted to register RCTBridgeModule class %@ for the name "
-                  "'%@', but name was already registered by class %@", moduleClass,
-                  moduleName, moduleDataByName[moduleName].moduleClass);
-    }
+  NSMutableArray<Class> *moduleClassesByID = [NSMutableArray new];
+  NSMutableArray<RCTModuleData *> *moduleDataByID = [NSMutableArray new];
+  NSMutableDictionary<NSString *, RCTModuleData *> *moduleDataByName = [NSMutableDictionary new];
+
+  // Set up moduleData for pre-initialized module instances
+  for (id<RCTBridgeModule> module in extraModules) {
+    Class moduleClass = [module class];
+    NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass);
 
-    // Instantiate moduleData (TODO: defer this until config generation)
-    RCTModuleData *moduleData;
-    if (module) {
-      if (module != (id)kCFNull) {
-        moduleData = [[RCTModuleData alloc] initWithModuleInstance:module
-                                                            bridge:self];
+    if (RCT_DEBUG) {
+      // Check for name collisions between preregistered modules
+      RCTModuleData *moduleData = moduleDataByName[moduleName];
+      if (moduleData) {
+        RCTLogError(@"Attempted to register RCTBridgeModule class %@ for the "
+                    "name '%@', but name was already registered by class %@",
+                    moduleClass, moduleName, moduleData.moduleClass);
+        continue;
       }
-    } else {
-       moduleData = [[RCTModuleData alloc] initWithModuleClass:moduleClass
-                                                        bridge:self];
     }
+
+    // Instantiate moduleData container
+    RCTModuleData *moduleData = [[RCTModuleData alloc] initWithModuleInstance:module
+                                                                       bridge:self];
+    moduleDataByName[moduleName] = moduleData;
+    [moduleClassesByID addObject:moduleClass];
+    [moduleDataByID addObject:moduleData];
+  }
+
+  // Set up moduleData for automatically-exported modules
+  for (Class moduleClass in RCTGetModuleClasses()) {
+    NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass);
+
+    // Check for module name collisions
+    RCTModuleData *moduleData = moduleDataByName[moduleName];
     if (moduleData) {
-      moduleDataByName[moduleName] = moduleData;
-      [moduleDataByID addObject:moduleData];
+      if (moduleData.hasInstance) {
+        // Existing module was preregistered, so it takes precedence
+        continue;
+      } else if ([moduleClass new] == nil) {
+        // The new module returned nil from init, so use the old module
+        continue;
+      } else if ([moduleData.moduleClass new] != nil) {
+        // Both modules were non-nil, so it's unclear which should take precedence
+        RCTLogError(@"Attempted to register RCTBridgeModule class %@ for the "
+                    "name '%@', but name was already registered by class %@",
+                    moduleClass, moduleName, moduleData.moduleClass);
+      }
     }
+    
+    // Instantiate moduleData (TODO: can we defer this until config generation?)
+    moduleData = [[RCTModuleData alloc] initWithModuleClass:moduleClass
+                                                     bridge:self];
+    moduleDataByName[moduleName] = moduleData;
+    [moduleClassesByID addObject:moduleClass];
+    [moduleDataByID addObject:moduleData];
   }
 
   // Store modules
   _moduleDataByID = [moduleDataByID copy];
   _moduleDataByName = [moduleDataByName copy];
-  _moduleClassesByID = [moduleDataByID valueForKey:@"moduleClass"];
+  _moduleClassesByID = [moduleClassesByID copy];
 
-  /**
-   * The executor is a bridge module, wait for it to be created and set it before
-   * any other module has access to the bridge
-   */
+  // The executor is a bridge module, wait for it to be created and set it up
+  // before any other module has access to the bridge.
   _javaScriptExecutor = [self moduleForClass:self.executorClass];
 
+  // Dispatch module init onto main thead for those modules that require it
   for (RCTModuleData *moduleData in _moduleDataByID) {
     if (moduleData.hasInstance) {
-      [moduleData setBridgeForInstance];
+      // Modules that were pre-initialized need to be set up before bridge init
+      // has finished, otherwise the caller may try to access the module
+      // directly rather than via `[bridge moduleForClass:]`, which won't
+      // trigger the lazy initialization process.
+      (void)[moduleData instance];
     }
-  }
-
-  for (RCTModuleData *moduleData in _moduleDataByID) {
-    if (moduleData.hasInstance) {
-      [moduleData finishSetupForInstance];
-    }
-  }
-
-  for (RCTModuleData *moduleData in _moduleDataByID) {
-    if (moduleData.hasInstance) {
-      [moduleData gatherConstants];
+    if (moduleData.requiresMainThreadSetup) {
+      // Modules that need to be set up on the main thread cannot be initialized
+      // lazily when required without doing a dispatch_sync to the main thread,
+      // which can result in deadlock. To avoid this, we initialize all of these
+      // modules on the main thread in parallel with loading the JS code, so that
+      // they will already be available before they are ever required.
+      __weak RCTBatchedBridge *weakSelf = self;
+      dispatch_group_async(dispatchGroup, dispatch_get_main_queue(), ^{
+        if (weakSelf.valid) {
+          (void)[moduleData instance];
+          [moduleData gatherConstants];
+        }
+      });
     }
   }
 
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
-
-  [[NSNotificationCenter defaultCenter]
-   postNotificationName:RCTDidCreateNativeModules
-   object:self userInfo:@{@"bridge": self}];
-
-#pragma clang diagnostic pop
+  // From this point on, RCTDidInitializeModuleNotification notifications will
+  // be sent the first time a module is accessed.
+  _moduleSetupComplete = YES;
 
   RCTPerformanceLoggerEnd(RCTPLNativeModuleInit);
 }
@@ -418,7 +437,7 @@ - (void)updateJSDisplayLinkState
 - (void)injectJSONConfiguration:(NSString *)configJSON
                      onComplete:(void (^)(NSError *))onComplete
 {
-  if (!self.valid) {
+  if (!_valid) {
     return;
   }
 
@@ -429,7 +448,7 @@ - (void)injectJSONConfiguration:(NSString *)configJSON
 
 - (void)executeSourceCode:(NSData *)sourceCode
 {
-  if (!self.valid || !_javaScriptExecutor) {
+  if (!_valid || !_javaScriptExecutor) {
     return;
   }
 
@@ -438,7 +457,7 @@ - (void)executeSourceCode:(NSData *)sourceCode
   sourceCodeModule.scriptData = sourceCode;
 
   [self enqueueApplicationScript:sourceCode url:self.bundleURL onComplete:^(NSError *loadError) {
-    if (!self.isValid) {
+    if (!_valid) {
       return;
     }
 
@@ -490,7 +509,7 @@ - (void)stopLoadingWithError:(NSError *)error
 {
   RCTAssertMainThread();
 
-  if (!self.isValid || !self.loading) {
+  if (!_valid || !_loading) {
     return;
   }
 
@@ -570,7 +589,7 @@ - (void)dispatchBlock:(dispatch_block_t)block
 
 - (void)invalidate
 {
-  if (!self.valid) {
+  if (!_valid) {
     return;
   }
 
@@ -615,7 +634,6 @@ - (void)invalidate
       _moduleDataByName = nil;
       _moduleDataByID = nil;
       _moduleClassesByID = nil;
-      _modulesByName_DEPRECATED = nil;
       _frameUpdateObservers = nil;
       _pendingCalls = nil;
 
@@ -771,7 +789,7 @@ - (void)_actuallyInvokeAndProcessModule:(NSString *)module
       RCTFatal(error);
     }
 
-    if (!self.isValid) {
+    if (!_valid) {
       return;
     }
     [self handleBuffer:json batchEnded:YES];
@@ -793,7 +811,7 @@ - (void)_actuallyInvokeCallback:(NSNumber *)cbID
       RCTFatal(error);
     }
 
-    if (!self.isValid) {
+    if (!_valid) {
       return;
     }
     [self handleBuffer:json batchEnded:YES];
@@ -931,7 +949,7 @@ - (BOOL)_handleRequestNumber:(NSUInteger)i
                     methodID:(NSUInteger)methodID
                       params:(NSArray *)params
 {
-  if (!self.isValid) {
+  if (!_valid) {
     return NO;
   }
 
@@ -989,7 +1007,6 @@ - (void)_jsThreadUpdate:(CADisplayLink *)displayLink
 
   [self updateJSDisplayLinkState];
 
-
   RCTProfileImmediateEvent(0, @"JS Thread Tick", displayLink.timestamp, 'g');
 
   RCT_PROFILE_END_EVENT(0, @"objc_call", nil);
@@ -1022,24 +1039,3 @@ - (BOOL)isBatchActive
 }
 
 @end
-
-@implementation RCTBatchedBridge(Deprecated)
-
-- (NSDictionary *)modules
-{
-  if (!_modulesByName_DEPRECATED) {
-    // Check classes are set up
-    [self moduleClasses];
-    NSMutableDictionary *modulesByName = [NSMutableDictionary new];
-    for (NSString *moduleName in _moduleDataByName) {
-      id module = [self moduleForName:moduleName];
-      if (module) {
-         modulesByName[moduleName] = module;
-      }
-    };
-    _modulesByName_DEPRECATED = [modulesByName copy];
-  }
-  return _modulesByName_DEPRECATED;
-}
-
-@end
diff --git a/React/Base/RCTBridge+Private.h b/React/Base/RCTBridge+Private.h
index c954561efddb..19f33c1a3ffe 100644
--- a/React/Base/RCTBridge+Private.h
+++ b/React/Base/RCTBridge+Private.h
@@ -59,6 +59,11 @@
  */
 @property (nonatomic, weak, readonly) id<RCTJavaScriptExecutor> javaScriptExecutor;
 
+/**
+ * Used by RCTModuleData
+ */
+@property (nonatomic, assign, readonly) BOOL moduleSetupComplete;
+
 /**
  * Used by RCTModuleData to register the module for frame updates after it is
  * lazily initialized.
diff --git a/React/Base/RCTBridge.h b/React/Base/RCTBridge.h
index 0b9fc6960560..1d8548607e2b 100644
--- a/React/Base/RCTBridge.h
+++ b/React/Base/RCTBridge.h
@@ -110,11 +110,18 @@ RCT_EXTERN BOOL RCTBridgeModuleClassIsRegistered(Class);
  * Retrieve a bridge module instance by name or class. Note that modules are
  * lazily instantiated, so calling these methods for the first time with a given
  * module name/class may cause the class to be sychronously instantiated,
- * blocking both the calling thread and main thread for a short time.
+ * potentially blocking both the calling thread and main thread for a short time.
  */
 - (id)moduleForName:(NSString *)moduleName;
 - (id)moduleForClass:(Class)moduleClass;
 
+/**
+ * Convenience method for retrieving all modules conforming to a given protocol.
+ * Modules will be sychronously instantiated if they haven't already been,
+ * potentially blocking both the calling thread and main thread for a short time.
+ */
+- (NSArray *)modulesConformingToProtocol:(Protocol *)protocol;
+
 /**
  * All registered bridge module classes.
  */
@@ -173,31 +180,3 @@ RCT_EXTERN BOOL RCTBridgeModuleClassIsRegistered(Class);
 - (BOOL)isBatchActive;
 
 @end
-
-/**
- * These features are deprecated and should not be used.
- */
-@interface RCTBridge (Deprecated)
-
-/**
- * This notification used to fire after all native modules has been initialized,
- * but now that native modules are instantiated lazily on demand, its original
- * purpose is meaningless.
- *
- * If you need to access a module, you can do so as soon as the bridge has been
- * initialized, by calling `[bridge moduleForClass:]`. If you need to know when
- * an individual module has been instantiated, add an observer for the
- * `RCTDidInitializeModuleNotification` instead.
- */
-RCT_EXTERN NSString *const RCTDidCreateNativeModules
-__deprecated_msg("Use RCTDidInitializeModuleNotification to observe init of individual modules");
-
-/**
- * Accessing the modules property causes all modules to be eagerly initialized,
- * which stalls the main thread. Use moduleClasses to enumerate through modules
- * without causing them to be instantiated.
- */
-@property (nonatomic, copy, readonly) NSDictionary *modules
-__deprecated_msg("Use moduleClasses and/or moduleForName: instead");
-
-@end
diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m
index aa939eae66c5..cd3edd45fd6e 100644
--- a/React/Base/RCTBridge.m
+++ b/React/Base/RCTBridge.m
@@ -104,34 +104,6 @@ + (void)initialize
 
     // Set up JS thread
     RCTJSThread = (id)kCFNull;
-
-    if (RCT_DEBUG && !RCTRunningInTestEnvironment()) {
-
-      // Set up module classes
-      static unsigned int classCount;
-      Class *classes = objc_copyClassList(&classCount);
-
-      for (unsigned int i = 0; i < classCount; i++)
-      {
-        Class cls = classes[i];
-        Class superclass = cls;
-        while (superclass)
-        {
-          if (class_conformsToProtocol(superclass, @protocol(RCTBridgeModule)))
-          {
-            if (![RCTModuleClasses containsObject:cls]) {
-              RCTLogWarn(@"Class %@ was not exported. Did you forget to use "
-                         "RCT_EXPORT_MODULE()?", cls);
-            }
-            break;
-          }
-          superclass = class_getSuperclass(superclass);
-        }
-      }
-
-      free(classes);
-
-    }
   });
 }
 
@@ -238,6 +210,20 @@ - (id)moduleForClass:(Class)moduleClass
   return [self moduleForName:RCTBridgeModuleNameForClass(moduleClass)];
 }
 
+- (NSArray *)modulesConformingToProtocol:(Protocol *)protocol
+{
+  NSMutableArray *modules = [NSMutableArray new];
+  for (Class moduleClass in self.moduleClasses) {
+    if ([moduleClass conformsToProtocol:protocol]) {
+      id module = [self moduleForClass:moduleClass];
+      if (module) {
+        [modules addObject:module];
+      }
+    }
+  }
+  return [modules copy];
+}
+
 - (RCTEventDispatcher *)eventDispatcher
 {
   return [self moduleForClass:[RCTEventDispatcher class]];
@@ -314,14 +300,3 @@ - (void)enqueueCallback:(NSNumber *)cbID args:(NSArray *)args
 }
 
 @end
-
-@implementation RCTBridge(Deprecated)
-
-NSString *const RCTDidCreateNativeModules = @"RCTDidCreateNativeModules";
-
-- (NSDictionary *)modules
-{
-  return self.batchedBridge.modules;
-}
-
-@end
diff --git a/React/Base/RCTModuleData.h b/React/Base/RCTModuleData.h
index 6d5b00c7aa97..a851b2a387b2 100644
--- a/React/Base/RCTModuleData.h
+++ b/React/Base/RCTModuleData.h
@@ -21,21 +21,7 @@
                              bridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
 
 - (instancetype)initWithModuleInstance:(id<RCTBridgeModule>)instance
-                                bridge:(RCTBridge *)bridge;
-
-/**
- * Sets the bridge for the module instance. This is only needed when using the
- * `initWithModuleInstance:bridge:` constructor. Otherwise, the bridge will be set
- * automatically when the module is first accessed.
- */
-- (void)setBridgeForInstance;
-
-/**
- * Sets the methodQueue and performs the remaining setup for the module. This is
- * only needed when using the `initWithModuleInstance:bridge:` constructor.
- * Otherwise it will be done automatically when the module is first accessed.
- */
-- (void)finishSetupForInstance;
+                                bridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
 
 /**
  * Calls `constantsToExport` on the module and stores the result. Note that
@@ -59,6 +45,11 @@
  */
 @property (nonatomic, assign, readonly) BOOL hasInstance;
 
+/**
+ * Returns YES if module instance must be created on the main thread.
+ */
+@property (nonatomic, assign, readonly) BOOL requiresMainThreadSetup;
+
 /**
  * Returns the current module instance. Note that this will init the instance
  * if it has not already been created. To check if the module instance exists
@@ -73,9 +64,8 @@
 @property (nonatomic, strong, readonly) dispatch_queue_t methodQueue;
 
 /**
- * Returns the module config. Note that this will init the module if it has
- * not already been created. This method can be called on any thread, but will
- * block the main thread briefly if the module implements `constantsToExport`.
+ * Returns the module config. Calls `gatherConstants` internally, so the same
+ * usage caveats apply.
  */
 @property (nonatomic, copy, readonly) NSArray *config;
 
diff --git a/React/Base/RCTModuleData.m b/React/Base/RCTModuleData.m
index 93427f52e59e..b3569db110e9 100644
--- a/React/Base/RCTModuleData.m
+++ b/React/Base/RCTModuleData.m
@@ -28,17 +28,37 @@ @implementation RCTModuleData
 @synthesize instance = _instance;
 @synthesize methodQueue = _methodQueue;
 
+- (void)setUp
+{
+  _implementsBatchDidComplete = [_moduleClass instancesRespondToSelector:@selector(batchDidComplete)];
+  _implementsPartialBatchDidFlush = [_moduleClass instancesRespondToSelector:@selector(partialBatchDidFlush)];
+
+  _instanceLock = [NSLock new];
+
+  static IMP objectInitMethod;
+  static SEL setBridgeSelector;
+  static dispatch_once_t onceToken;
+  dispatch_once(&onceToken, ^{
+    objectInitMethod = [NSObject instanceMethodForSelector:@selector(init)];
+    setBridgeSelector = NSSelectorFromString(@"setBridge:");
+  });
+
+  // If a module overrides `init`, `setBridge:`, or `constantsToExport` then we
+  // must assume that it expects for both of those methods to be called on the
+  // main thread, because those methods often need to access UIKit.
+  _requiresMainThreadSetup = _instance ||
+  [_moduleClass instancesRespondToSelector:setBridgeSelector] ||
+  RCTClassOverridesInstanceMethod(_moduleClass, @selector(constantsToExport)) ||
+  [_moduleClass instanceMethodForSelector:@selector(init)] != objectInitMethod;
+}
+
 - (instancetype)initWithModuleClass:(Class)moduleClass
                              bridge:(RCTBridge *)bridge
 {
   if ((self = [super init])) {
-    _moduleClass = moduleClass;
     _bridge = bridge;
-
-    _implementsBatchDidComplete = [_moduleClass instancesRespondToSelector:@selector(batchDidComplete)];
-    _implementsPartialBatchDidFlush = [_moduleClass instancesRespondToSelector:@selector(partialBatchDidFlush)];
-
-    _instanceLock = [NSLock new];
+    _moduleClass = moduleClass;
+    [self setUp];
   }
   return self;
 }
@@ -46,8 +66,11 @@ - (instancetype)initWithModuleClass:(Class)moduleClass
 - (instancetype)initWithModuleInstance:(id<RCTBridgeModule>)instance
                                 bridge:(RCTBridge *)bridge
 {
-  if ((self = [self initWithModuleClass:[instance class] bridge:bridge])) {
+  if ((self = [super init])) {
+    _bridge = bridge;
     _instance = instance;
+    _moduleClass = [instance class];
+    [self setUp];
   }
   return self;
 }
@@ -56,9 +79,47 @@ - (instancetype)initWithModuleInstance:(id<RCTBridgeModule>)instance
 
 #pragma mark - private setup methods
 
+- (void)setUpInstanceAndBridge
+{
+  [_instanceLock lock];
+  if (!_setupComplete && _bridge.valid) {
+    if (!_instance) {
+      if (RCT_DEBUG && _requiresMainThreadSetup) {
+        RCTAssertMainThread();
+      }
+      _instance = [_moduleClass new];
+      if (!_instance) {
+        // Module init returned nil, probably because automatic instantatiation
+        // of the module is not supported, and it is supposed to be passed in to
+        // the bridge constructor. Mark setup complete to avoid doing more work.
+        _setupComplete = YES;
+        RCTLogWarn(@"The module %@ is returning nil from its constructor. You "
+                   "may need to instantiate it yourself and pass it into the "
+                   "bridge.", _moduleClass);
+      }
+    }
+    // Bridge must be set before methodQueue is set up, as methodQueue
+    // initialization requires it (View Managers get their queue by calling
+    // self.bridge.uiManager.methodQueue)
+    [self setBridgeForInstance];
+  }
+  [_instanceLock unlock];
+
+  // This is called outside of the lock in order to prevent deadlock issues
+  // because the logic in `setUpMethodQueue` can cause `moduleData.instance`
+  // to be accessed re-entrantly.
+  [self setUpMethodQueue];
+
+  // This is called outside of the lock in order to prevent deadlock issues
+  // because the logic in `finishSetupForInstance` can cause
+  // `moduleData.instance` to be accessed re-entrantly.
+  if (_bridge.moduleSetupComplete) {
+    [self finishSetupForInstance];
+  }
+}
+
 - (void)setBridgeForInstance
 {
-  RCTAssert(_instance, @"setBridgeForInstance called before %@ initialized", self.name);
   if ([_instance respondsToSelector:@selector(bridge)] && _instance.bridge != _bridge) {
     @try {
       [(id)_instance setValue:_bridge forKey:@"bridge"];
@@ -73,9 +134,8 @@ - (void)setBridgeForInstance
 
 - (void)finishSetupForInstance
 {
-  if (!_setupComplete) {
+  if (!_setupComplete && _instance) {
     _setupComplete = YES;
-    [self setUpMethodQueue];
     [_bridge registerModuleForFrameUpdates:_instance withModuleData:self];
     [[NSNotificationCenter defaultCenter] postNotificationName:RCTDidInitializeModuleNotification
                                                         object:_bridge
@@ -85,8 +145,7 @@ - (void)finishSetupForInstance
 
 - (void)setUpMethodQueue
 {
-  if (!_methodQueue) {
-    RCTAssert(_instance, @"setUpMethodQueue called before %@ initialized", self.name);
+  if (_instance && !_methodQueue) {
     BOOL implementsMethodQueue = [_instance respondsToSelector:@selector(methodQueue)];
     if (implementsMethodQueue) {
       _methodQueue = _instance.methodQueue;
@@ -122,19 +181,19 @@ - (BOOL)hasInstance
 
 - (id<RCTBridgeModule>)instance
 {
-  [_instanceLock lock];
   if (!_setupComplete) {
-    if (!_instance) {
-      _instance = [_moduleClass new];
+    if (_requiresMainThreadSetup) {
+      // The chances of deadlock here are low, because module init very rarely
+      // calls out to other threads, however we can't control when a module might
+      // get accessed by client code during bridge setup, and a very low risk of
+      // deadlock is better than a fairly high risk of an assertion being thrown.
+      RCTExecuteOnMainThread(^{
+        [self setUpInstanceAndBridge];
+      }, YES);
+    } else {
+      [self setUpInstanceAndBridge];
     }
-    // Bridge must be set before methodQueue is set up, as methodQueue
-    // initialization requires it (View Managers get their queue by calling
-    // self.bridge.uiManager.methodQueue)
-    [self setBridgeForInstance];
   }
-  [_instanceLock unlock];
-
-  [self finishSetupForInstance];
   return _instance;
 }
 
@@ -183,8 +242,8 @@ - (void)gatherConstants
 {
   if (!_constantsToExport) {
     if (RCTClassOverridesInstanceMethod(_moduleClass, @selector(constantsToExport))) {
-      RCTAssert(_instance, @"constantsToExport called before instance created.");
       RCTExecuteOnMainThread(^{
+        [self setUpInstanceAndBridge];
         _constantsToExport = [_instance constantsToExport] ?: @{};
       }, YES);
     } else {
@@ -195,7 +254,9 @@ - (void)gatherConstants
 
 - (NSArray *)config
 {
+  [self gatherConstants];
   __block NSDictionary<NSString *, id> *constants = _constantsToExport;
+  _constantsToExport = nil; // Not needed anymore
 
   if (constants.count == 0 && self.methods.count == 0) {
     return (id)kCFNull; // Nothing to export
@@ -229,7 +290,7 @@ - (NSArray *)config
 
 - (dispatch_queue_t)methodQueue
 {
-  [self instance];
+  (void)[self instance];
   return _methodQueue;
 }
 
diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m
index 4bb2d7981d78..88368290acf1 100644
--- a/React/Views/RCTViewManager.m
+++ b/React/Views/RCTViewManager.m
@@ -52,6 +52,9 @@ @implementation RCTViewManager
 
 - (dispatch_queue_t)methodQueue
 {
+  RCTAssert(_bridge, @"Bridge not set");
+  RCTAssert(_bridge.uiManager, @"UIManager not initialized");
+  RCTAssert(_bridge.uiManager.methodQueue, @"UIManager.methodQueue not initialized");
   return _bridge.uiManager.methodQueue;
 }
 

From d2d00e0fcda4f666a5d4b8527d445900551d889a Mon Sep 17 00:00:00 2001
From: Dan Caspi <danca@fb.com>
Date: Thu, 3 Mar 2016 04:04:15 -0800
Subject: [PATCH 1390/1411] Adding GC Timer Sweeping to Android

Reviewed By: mhahnenberg

Differential Revision: D2972822

fb-gh-sync-id: b0ed28c26e3f1141c798d9d107d9e198611f9dce
shipit-source-id: b0ed28c26e3f1141c798d9d107d9e198611f9dce
---
 ReactAndroid/src/main/jni/react/JSCExecutor.cpp | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index 04856494a2ca..6d2c7e5d8873 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -141,6 +141,10 @@ void JSCExecutor::destroy() {
 }
 
 void JSCExecutor::initOnJSVMThread() {
+  #if defined(WITH_FB_JSC_TUNING) && !defined(WITH_JSC_INTERNAL)
+  // TODO: Find a way to pass m_jscConfig to configureJSCForAndroid()
+  configureJSCForAndroid(m_jscConfig.getDefault("GCTimers", false).asBool());
+  #endif
   m_context = JSGlobalContextCreateInGroup(nullptr, nullptr);
   s_globalContextRefToJSCExecutor[m_context] = this;
   installGlobalFunction(m_context, "nativeFlushQueueImmediate", nativeFlushQueueImmediate);
@@ -152,9 +156,7 @@ void JSCExecutor::initOnJSVMThread() {
 
   installGlobalFunction(m_context, "nativeLoggingHook", JSLogging::nativeHook);
 
-  // TODO (t10136849): Pass the config options from map to JSC
-
-  #ifdef WITH_FB_JSC_TUNING
+  #if defined(WITH_JSC_INTERNAL) && defined(WITH_FB_JSC_TUNING)
   configureJSCForAndroid();
   #endif
 

From 1bab7c5182415ea6f1bee41ad2cc7bec629005af Mon Sep 17 00:00:00 2001
From: Sokovikov <skv-headless@yandex.ru>
Date: Thu, 3 Mar 2016 04:08:10 -0800
Subject: [PATCH 1391/1411] vibration module

Summary:I will fix other notes from https://github.com/facebook/react-native/pull/2794 if I get positive feedback.
Closes https://github.com/facebook/react-native/pull/6061

Reviewed By: nicklockwood

Differential Revision: D2982173

Pulled By: dmmiller

fb-gh-sync-id: d1e9407798b0293b090897a10996085b0f0c1b3e
shipit-source-id: d1e9407798b0293b090897a10996085b0f0c1b3e
---
 Examples/UIExplorer/UIExplorerList.android.js |  4 ++
 Examples/UIExplorer/UIExplorerList.ios.js     |  4 +-
 Examples/UIExplorer/VibrationExample.js       | 54 +++++++++++++++++++
 .../android/app/src/main/AndroidManifest.xml  |  1 +
 Libraries/Vibration/Vibration.js              | 39 ++++++++++++++
 Libraries/Vibration/VibrationIOS.ios.js       |  5 ++
 Libraries/react-native/react-native.js        |  1 +
 Libraries/react-native/react-native.js.flow   |  1 +
 .../com/facebook/react/modules/vibration/BUCK | 21 ++++++++
 .../modules/vibration/VibrationModule.java    | 37 +++++++++++++
 .../main/java/com/facebook/react/shell/BUCK   |  1 +
 .../react/shell/MainReactPackage.java         |  2 +
 website/server/extractDocs.js                 |  1 +
 13 files changed, 169 insertions(+), 2 deletions(-)
 create mode 100644 Examples/UIExplorer/VibrationExample.js
 create mode 100644 Libraries/Vibration/Vibration.js
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/vibration/BUCK
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/vibration/VibrationModule.java

diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index 3dfd365d1996..a912ae9abf81 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -162,6 +162,10 @@ const APIExamples = [
     key: 'ToastAndroidExample',
     module: require('./ToastAndroidExample'),
   },
+  {
+    key: 'VibrationExample',
+    module: require('./VibrationExample'),
+  },
   {
     key: 'XHRExample',
     module: require('./XHRExample'),
diff --git a/Examples/UIExplorer/UIExplorerList.ios.js b/Examples/UIExplorer/UIExplorerList.ios.js
index b2fefd125056..8d770d1f40be 100644
--- a/Examples/UIExplorer/UIExplorerList.ios.js
+++ b/Examples/UIExplorer/UIExplorerList.ios.js
@@ -245,8 +245,8 @@ var APIExamples: Array<UIExplorerExample> = [
     module: require('./TransformExample'),
   },
   {
-    key: 'VibrationIOSExample',
-    module: require('./VibrationIOSExample'),
+    key: 'VibrationExample',
+    module: require('./VibrationExample'),
   },
   {
     key: 'XHRExample',
diff --git a/Examples/UIExplorer/VibrationExample.js b/Examples/UIExplorer/VibrationExample.js
new file mode 100644
index 000000000000..11f17d368b86
--- /dev/null
+++ b/Examples/UIExplorer/VibrationExample.js
@@ -0,0 +1,54 @@
+/**
+ * The examples provided by Facebook are for non-commercial testing and
+ * evaluation purposes only.
+ *
+ * Facebook reserves all rights not expressly granted.
+ *
+ * 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 NON INFRINGEMENT. IN NO EVENT SHALL
+ * FACEBOOK 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.
+ *
+ * @flow
+ */
+'use strict';
+
+var React = require('react-native');
+var {
+  StyleSheet,
+  View,
+  Text,
+  TouchableHighlight,
+  Vibration,
+} = React;
+
+exports.framework = 'React';
+exports.title = 'Vibration';
+exports.description = 'Vibration API';
+exports.examples = [{
+  title: 'Vibration.vibrate()',
+  render() {
+    return (
+      <TouchableHighlight
+        style={styles.wrapper}
+        onPress={() => Vibration.vibrate()}>
+        <View style={styles.button}>
+          <Text>Vibrate</Text>
+        </View>
+      </TouchableHighlight>
+    );
+  },
+}];
+
+var styles = StyleSheet.create({
+  wrapper: {
+    borderRadius: 5,
+    marginBottom: 5,
+  },
+  button: {
+    backgroundColor: '#eeeeee',
+    padding: 10,
+  },
+});
diff --git a/Examples/UIExplorer/android/app/src/main/AndroidManifest.xml b/Examples/UIExplorer/android/app/src/main/AndroidManifest.xml
index 968a554cf2a3..c1e8475153ee 100644
--- a/Examples/UIExplorer/android/app/src/main/AndroidManifest.xml
+++ b/Examples/UIExplorer/android/app/src/main/AndroidManifest.xml
@@ -6,6 +6,7 @@
   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
   <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
   <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
+  <uses-permission android:name="android.permission.VIBRATE"/>
 
   <application
       android:allowBackup="true"
diff --git a/Libraries/Vibration/Vibration.js b/Libraries/Vibration/Vibration.js
new file mode 100644
index 000000000000..9258eadaa2a7
--- /dev/null
+++ b/Libraries/Vibration/Vibration.js
@@ -0,0 +1,39 @@
+/**
+ * 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 Vibration
+ * @flow
+ */
+'use strict';
+
+var RCTVibration = require('NativeModules').Vibration;
+var Platform = require('Platform');
+
+/**
+ * The Vibration API is exposed at `Vibration.vibrate()`.
+ * The vibration is asynchronous so this method will return immediately.
+ *
+ * There will be no effect on devices that do not support Vibration, eg. the simulator.
+ *
+ * Note for android
+ * add `<uses-permission android:name="android.permission.VIBRATE"/>` to `AndroidManifest.xml`
+ *
+ * Vibration patterns are currently unsupported.
+ */
+
+var Vibration = {
+  vibrate: function(duration: number = 400) {
+    if (Platform.OS === 'android') {
+      RCTVibration.vibrate(duration);
+    } else {
+      RCTVibration.vibrate();
+    }
+  }
+};
+
+module.exports = Vibration;
diff --git a/Libraries/Vibration/VibrationIOS.ios.js b/Libraries/Vibration/VibrationIOS.ios.js
index 1e0a17942d67..56da5a815b12 100644
--- a/Libraries/Vibration/VibrationIOS.ios.js
+++ b/Libraries/Vibration/VibrationIOS.ios.js
@@ -16,6 +16,8 @@ var RCTVibration = require('NativeModules').Vibration;
 var invariant = require('fbjs/lib/invariant');
 
 /**
+ * NOTE: `VibrationIOS` is being deprecated. Use `Vibration` instead.
+ *
  * The Vibration API is exposed at `VibrationIOS.vibrate()`. On iOS, calling this
  * function will trigger a one second vibration. The vibration is asynchronous
  * so this method will return immediately.
@@ -27,6 +29,9 @@ var invariant = require('fbjs/lib/invariant');
  */
 
 var VibrationIOS = {
+  /**
+   * @deprecated
+   */
   vibrate: function() {
     invariant(
       arguments[0] === undefined,
diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js
index e8eca3c72a5a..2b5a0bc964f6 100644
--- a/Libraries/react-native/react-native.js
+++ b/Libraries/react-native/react-native.js
@@ -86,6 +86,7 @@ var ReactNative = {
   get StyleSheet() { return require('StyleSheet'); },
   get TimePickerAndroid() { return require('TimePickerAndroid'); },
   get UIManager() { return require('UIManager'); },
+  get Vibration() { return require('Vibration'); },
   get VibrationIOS() { return require('VibrationIOS'); },
 
   // Plugins
diff --git a/Libraries/react-native/react-native.js.flow b/Libraries/react-native/react-native.js.flow
index e7aa8059055c..70d05ead71ca 100644
--- a/Libraries/react-native/react-native.js.flow
+++ b/Libraries/react-native/react-native.js.flow
@@ -98,6 +98,7 @@ var ReactNative = Object.assign(Object.create(require('react')), {
   StyleSheet: require('StyleSheet'),
   TimePickerAndroid: require('TimePickerAndroid'),
   UIManager: require('UIManager'),
+  Vibration: require('Vibration'),
   VibrationIOS: require('VibrationIOS'),
 
   // Plugins
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/vibration/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/vibration/BUCK
new file mode 100644
index 000000000000..19ceed59d6f9
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/vibration/BUCK
@@ -0,0 +1,21 @@
+include_defs('//ReactAndroid/DEFS')
+
+android_library(
+  name = 'vibration',
+  srcs = glob(['**/*.java']),
+  deps = [
+    react_native_target('java/com/facebook/react/bridge:bridge'),
+    react_native_target('java/com/facebook/react/common:common'),
+    react_native_target('java/com/facebook/react/modules/core:core'),
+    react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'),
+    react_native_dep('third-party/java/infer-annotations:infer-annotations'),
+    react_native_dep('third-party/java/jsr-305:jsr-305'),
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+project_config(
+  src_target = ':vibration',
+)
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/vibration/VibrationModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/vibration/VibrationModule.java
new file mode 100644
index 000000000000..1a0023ac0524
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/vibration/VibrationModule.java
@@ -0,0 +1,37 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.modules.vibration;
+
+import android.content.Context;
+import android.os.Vibrator;
+
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+
+public class VibrationModule extends ReactContextBaseJavaModule {
+
+  public VibrationModule(ReactApplicationContext reactContext) {
+    super(reactContext);
+  }
+
+  @Override
+  public String getName() {
+    return "Vibration";
+  }
+
+  @ReactMethod
+  public void vibrate(int duration) {
+    Vibrator v = (Vibrator) getReactApplicationContext().getSystemService(Context.VIBRATOR_SERVICE);
+    if (v != null) {
+      v.vibrate(duration);
+    }
+  }
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK
index ec0c816b8364..198de5a74dc7 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK
+++ b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK
@@ -26,6 +26,7 @@ android_library(
     react_native_target('java/com/facebook/react/views/viewpager:viewpager'),
     react_native_target('java/com/facebook/react/views/webview:webview'),
     react_native_target('java/com/facebook/react/modules/appstate:appstate'),
+    react_native_target('java/com/facebook/react/modules/vibration:vibration'),
     react_native_target('java/com/facebook/react/modules/camera:camera'),
     react_native_target('java/com/facebook/react/modules/clipboard:clipboard'),
     react_native_target('java/com/facebook/react/modules/core:core'),
diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
index 01a30148daa8..f75c8d92bea2 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java
@@ -33,6 +33,7 @@
 import com.facebook.react.modules.storage.AsyncStorageModule;
 import com.facebook.react.modules.timepicker.TimePickerDialogModule;
 import com.facebook.react.modules.toast.ToastModule;
+import com.facebook.react.modules.vibration.VibrationModule;
 import com.facebook.react.modules.websocket.WebSocketModule;
 import com.facebook.react.uimanager.ViewManager;
 import com.facebook.react.views.art.ARTRenderableViewManager;
@@ -81,6 +82,7 @@ public List<NativeModule> createNativeModules(ReactApplicationContext reactConte
       new StatusBarModule(reactContext),
       new TimePickerDialogModule(reactContext),
       new ToastModule(reactContext),
+      new VibrationModule(reactContext),
       new WebSocketModule(reactContext)
     );
   }
diff --git a/website/server/extractDocs.js b/website/server/extractDocs.js
index be0c8e2f5125..782d006fbe6e 100644
--- a/website/server/extractDocs.js
+++ b/website/server/extractDocs.js
@@ -252,6 +252,7 @@ var apis = [
   '../Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js',
   '../Libraries/Components/ToastAndroid/ToastAndroid.android.js',
   '../Libraries/Vibration/VibrationIOS.ios.js',
+  '../Libraries/Vibration/Vibration.js',
 ];
 
 var stylesWithPermalink = [

From 6d5f9ddfffbdcc9abbb73341ba467622b1b17aef Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Thu, 3 Mar 2016 04:09:27 -0800
Subject: [PATCH 1392/1411] WebWorkers: Allow native modules to be notified
 when executors are unregistered

Summary: This will allow them to clean up resources when a web worker goes away.

Reviewed By: mhorowitz, lexs

Differential Revision: D2994721

fb-gh-sync-id: c7ca1afc7290e85038cf692a139f6478dba0ef61
shipit-source-id: c7ca1afc7290e85038cf692a139f6478dba0ef61
---
 .../react/bridge/CatalystInstanceImpl.java    | 61 ++++++++----
 .../react/bridge/NativeModuleRegistry.java    | 13 ++-
 .../OnExecutorUnregisteredListener.java       | 22 +++++
 .../facebook/react/bridge/ReactCallback.java  |  3 +
 ReactAndroid/src/main/jni/react/Bridge.cpp    |  6 +-
 ReactAndroid/src/main/jni/react/Bridge.h      | 18 +++-
 .../src/main/jni/react/jni/OnLoad.cpp         | 92 ++++++++++++-------
 7 files changed, 157 insertions(+), 58 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/OnExecutorUnregisteredListener.java

diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
index df8b26604c47..533c8721ff00 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java
@@ -222,8 +222,10 @@ public void destroy() {
       Systrace.unregisterListener(mTraceListener);
 
       synchronouslyDisposeBridgeOnJSThread();
-      mReactQueueConfiguration.destroy();
     }
+
+    mReactQueueConfiguration.destroy();
+
     boolean wasIdle = (mPendingJSCalls.getAndSet(0) == 0);
     if (!wasIdle && !mBridgeIdleListeners.isEmpty()) {
       for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) {
@@ -293,12 +295,12 @@ public Collection<NativeModule> getNativeModules() {
   @Override
   public void handleMemoryPressure(final MemoryPressure level) {
     mReactQueueConfiguration.getJSQueueThread().runOnQueue(
-        new Runnable() {
-          @Override
-          public void run() {
-            Assertions.assertNotNull(mBridge).handleMemoryPressure(level);
-          }
-        });
+      new Runnable() {
+        @Override
+        public void run() {
+          Assertions.assertNotNull(mBridge).handleMemoryPressure(level);
+        }
+      });
   }
 
   /**
@@ -399,12 +401,14 @@ private class NativeModulesReactCallback implements ReactCallback {
     public void call(ExecutorToken executorToken, int moduleId, int methodId, ReadableNativeArray parameters) {
       mReactQueueConfiguration.getNativeModulesQueueThread().assertIsOnThread();
 
-      // Suppress any callbacks if destroyed - will only lead to sadness.
-      if (mDestroyed) {
-        return;
-      }
+      synchronized (mTeardownLock) {
+        // Suppress any callbacks if destroyed - will only lead to sadness.
+        if (mDestroyed) {
+          return;
+        }
 
-      mJavaRegistry.call(CatalystInstanceImpl.this, executorToken, moduleId, methodId, parameters);
+        mJavaRegistry.call(CatalystInstanceImpl.this, executorToken, moduleId, methodId, parameters);
+      }
     }
 
     @Override
@@ -415,17 +419,38 @@ public void onBatchComplete() {
       // native modules could be in a bad state so we don't want to call anything on them. We
       // still want to trigger the debug listener since it allows instrumentation tests to end and
       // check their assertions without waiting for a timeout.
-      if (!mDestroyed) {
-        Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "onBatchComplete");
-        try {
-          mJavaRegistry.onBatchComplete();
-        } finally {
-          Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+      synchronized (mTeardownLock) {
+        if (!mDestroyed) {
+          Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "onBatchComplete");
+          try {
+            mJavaRegistry.onBatchComplete();
+          } finally {
+            Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+          }
         }
       }
 
       decrementPendingJSCalls();
     }
+
+    @Override
+    public void onExecutorUnregistered(ExecutorToken executorToken) {
+      mReactQueueConfiguration.getNativeModulesQueueThread().assertIsOnThread();
+
+      // Since onCatalystInstanceDestroy happens on the UI thread, we don't want to also execute
+      // this callback on the native modules thread at the same time. Longer term, onCatalystInstanceDestroy
+      // should probably be executed on the native modules thread as well instead.
+      synchronized (mTeardownLock) {
+        if (!mDestroyed) {
+          Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "onExecutorUnregistered");
+          try {
+            mJavaRegistry.onExecutorUnregistered(executorToken);
+          } finally {
+            Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
+          }
+        }
+      }
+    }
   }
 
   private class NativeExceptionHandler implements QueueThreadExceptionHandler {
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java
index 0d5cc0e65a78..adb48a364764 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java
@@ -30,6 +30,7 @@ public class NativeModuleRegistry {
   private final List<ModuleDefinition> mModuleTable;
   private final Map<Class<? extends NativeModule>, NativeModule> mModuleInstances;
   private final ArrayList<OnBatchCompleteListener> mBatchCompleteListenerModules;
+  private final ArrayList<OnExecutorUnregisteredListener> mOnExecutorUnregisteredListenerModules;
 
   private NativeModuleRegistry(
       List<ModuleDefinition> moduleTable,
@@ -37,12 +38,16 @@ private NativeModuleRegistry(
     mModuleTable = moduleTable;
     mModuleInstances = moduleInstances;
 
-    mBatchCompleteListenerModules = new ArrayList<OnBatchCompleteListener>(mModuleTable.size());
+    mBatchCompleteListenerModules = new ArrayList<>(mModuleTable.size());
+    mOnExecutorUnregisteredListenerModules = new ArrayList<>(mModuleTable.size());
     for (int i = 0; i < mModuleTable.size(); i++) {
       ModuleDefinition definition = mModuleTable.get(i);
       if (definition.target instanceof OnBatchCompleteListener) {
         mBatchCompleteListenerModules.add((OnBatchCompleteListener) definition.target);
       }
+      if (definition.target instanceof OnExecutorUnregisteredListener) {
+        mOnExecutorUnregisteredListenerModules.add((OnExecutorUnregisteredListener) definition.target);
+      }
     }
   }
 
@@ -135,6 +140,12 @@ public void onBatchComplete() {
     }
   }
 
+  public void onExecutorUnregistered(ExecutorToken executorToken) {
+    for (int i = 0; i < mOnExecutorUnregisteredListenerModules.size(); i++) {
+      mOnExecutorUnregisteredListenerModules.get(i).onExecutorDestroyed(executorToken);
+    }
+  }
+
   public <T extends NativeModule> T getModule(Class<T> moduleInterface) {
     return (T) Assertions.assertNotNull(mModuleInstances.get(moduleInterface));
   }
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/OnExecutorUnregisteredListener.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/OnExecutorUnregisteredListener.java
new file mode 100644
index 000000000000..d7cbe6cee334
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/OnExecutorUnregisteredListener.java
@@ -0,0 +1,22 @@
+/**
+ * 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.
+ */
+
+package com.facebook.react.bridge;
+
+/**
+ * Interface for a module that will be notified when JS executors have been unregistered from the bridge.
+ * Note that this will NOT notify listeners about the main executor being destroyed: use
+ * {@link NativeModule#onCatalystInstanceDestroy()} for that. Once a module has received a
+ * {@link NativeModule#onCatalystInstanceDestroy()} call, it will not receive any onExecutorUnregistered
+ * calls.
+ */
+public interface OnExecutorUnregisteredListener {
+
+  void onExecutorDestroyed(ExecutorToken executorToken);
+}
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactCallback.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactCallback.java
index 0399f27cf7a7..3e5c36be13f0 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactCallback.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactCallback.java
@@ -19,4 +19,7 @@ public interface ReactCallback {
 
   @DoNotStrip
   void onBatchComplete();
+
+  @DoNotStrip
+  void onExecutorUnregistered(ExecutorToken executorToken);
 }
diff --git a/ReactAndroid/src/main/jni/react/Bridge.cpp b/ReactAndroid/src/main/jni/react/Bridge.cpp
index 84568b16ff1f..6654e8bd45d8 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.cpp
+++ b/ReactAndroid/src/main/jni/react/Bridge.cpp
@@ -17,7 +17,7 @@ namespace react {
 Bridge::Bridge(
     JSExecutorFactory* jsExecutorFactory,
     std::unique_ptr<ExecutorTokenFactory> executorTokenFactory,
-    Callback callback) :
+    std::unique_ptr<BridgeCallback> callback) :
   m_callback(std::move(callback)),
   m_destroyed(std::make_shared<bool>(false)),
   m_executorTokenFactory(std::move(executorTokenFactory)) {
@@ -174,7 +174,7 @@ void Bridge::callNativeModules(JSExecutor& executor, const std::string& callJSON
   if (*m_destroyed) {
     return;
   }
-  m_callback(getTokenForExecutor(executor), parseMethodCalls(callJSON), isEndOfBatch);
+  m_callback->onCallNativeModules(getTokenForExecutor(executor), parseMethodCalls(callJSON), isEndOfBatch);
 }
 
 ExecutorToken Bridge::getMainExecutorToken() const {
@@ -214,7 +214,7 @@ std::unique_ptr<JSExecutor> Bridge::unregisterExecutor(ExecutorToken executorTok
     m_executorTokenMap.erase(executor.get());
   }
 
-  // TODO: Notify native modules that ExecutorToken destroyed
+  m_callback->onExecutorUnregistered(executorToken);
 
   return executor;
 }
diff --git a/ReactAndroid/src/main/jni/react/Bridge.h b/ReactAndroid/src/main/jni/react/Bridge.h
index 05a0e64189c9..3618ef04fe48 100644
--- a/ReactAndroid/src/main/jni/react/Bridge.h
+++ b/ReactAndroid/src/main/jni/react/Bridge.h
@@ -24,6 +24,18 @@ struct dynamic;
 namespace facebook {
 namespace react {
 
+class BridgeCallback {
+public:
+  virtual ~BridgeCallback() {};
+
+  virtual void onCallNativeModules(
+      ExecutorToken executorToken,
+      std::vector<MethodCall>&& calls,
+      bool isEndOfBatch) = 0;
+
+  virtual void onExecutorUnregistered(ExecutorToken executorToken) = 0;
+};
+
 class Bridge;
 class ExecutorRegistration {
 public:
@@ -39,15 +51,13 @@ class ExecutorRegistration {
 
 class Bridge {
 public:
-  typedef std::function<void(ExecutorToken executorToken, std::vector<MethodCall>, bool isEndOfBatch)> Callback;
-
   /**
    * This must be called on the main JS thread.
    */
   Bridge(
       JSExecutorFactory* jsExecutorFactory,
       std::unique_ptr<ExecutorTokenFactory> executorTokenFactory,
-      Callback callback);
+      std::unique_ptr<BridgeCallback> callback);
   virtual ~Bridge();
 
   /**
@@ -128,7 +138,7 @@ class Bridge {
    */
   void destroy();
 private:
-  Callback m_callback;
+  std::unique_ptr<BridgeCallback> m_callback;
   // This is used to avoid a race condition where a proxyCallback gets queued after ~Bridge(),
   // on the same thread. In that case, the callback will try to run the task on m_callback which
   // will have been destroyed within ~Bridge(), thus causing a SIGSEGV.
diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index bb70f2f280ec..eeef4d6fe67d 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -567,6 +567,7 @@ namespace bridge {
 
 static jmethodID gCallbackMethod;
 static jmethodID gOnBatchCompleteMethod;
+static jmethodID gOnExecutorUnregisteredMethod;
 static jmethodID gLogMarkerMethod;
 
 struct CountableBridge : Bridge, Countable {
@@ -582,7 +583,7 @@ static void logMarker(const std::string& marker) {
   env->DeleteLocalRef(jmarker);
 }
 
-static void makeJavaCall(JNIEnv* env, ExecutorToken executorToken, jobject callback, MethodCall&& call) {
+static void makeJavaCall(JNIEnv* env, ExecutorToken executorToken, jobject callback, const MethodCall& call) {
   if (call.arguments.isNull()) {
     return;
   }
@@ -607,33 +608,51 @@ static void signalBatchComplete(JNIEnv* env, jobject callback) {
   env->CallVoidMethod(callback, gOnBatchCompleteMethod);
 }
 
-static void dispatchCallbacksToJava(ExecutorToken executorToken,
-                                    const RefPtr<WeakReference>& weakCallback,
-                                    const RefPtr<WeakReference>& weakCallbackQueueThread,
-                                    std::vector<MethodCall>&& calls,
-                                    bool isEndOfBatch) {
-  auto env = Environment::current();
-  if (env->ExceptionCheck()) {
-    FBLOGW("Dropped calls because of pending exception");
-    return;
-  }
-
-  ResolvedWeakReference callbackQueueThread(weakCallbackQueueThread);
-  if (!callbackQueueThread) {
-    FBLOGW("Dropped calls because of callback queue thread went away");
-    return;
-  }
+class PlatformBridgeCallback : public BridgeCallback {
+public:
+  PlatformBridgeCallback(
+      RefPtr<WeakReference> weakCallback_,
+      RefPtr<WeakReference> weakCallbackQueueThread_) :
+    weakCallback_(std::move(weakCallback_)),
+    weakCallbackQueueThread_(std::move(weakCallbackQueueThread_)) {}
 
-  auto runnableFunction = std::bind([executorToken, weakCallback, isEndOfBatch] (std::vector<MethodCall>& calls) {
+  void executeCallbackOnCallbackQueueThread(std::function<void(ResolvedWeakReference&)>&& runnable) {
     auto env = Environment::current();
     if (env->ExceptionCheck()) {
-      FBLOGW("Dropped calls because of pending exception");
+      FBLOGW("Dropped callback because of pending exception");
+      return;
+    }
+
+    ResolvedWeakReference callbackQueueThread(weakCallbackQueueThread_);
+    if (!callbackQueueThread) {
+      FBLOGW("Dropped callback because callback queue thread went away");
       return;
     }
-    ResolvedWeakReference callback(weakCallback);
-    if (callback) {
-      for (auto&& call : calls) {
-        makeJavaCall(env, executorToken, callback, std::move(call));
+
+    auto runnableWrapper = std::bind([this] (std::function<void(ResolvedWeakReference&)>& runnable) {
+      auto env = Environment::current();
+      if (env->ExceptionCheck()) {
+        FBLOGW("Dropped calls because of pending exception");
+        return;
+      }
+      ResolvedWeakReference callback(weakCallback_);
+      if (callback) {
+        runnable(callback);
+      }
+    }, std::move(runnable));
+
+    auto jNativeRunnable = runnable::createNativeRunnable(env, std::move(runnableWrapper));
+    queue::enqueueNativeRunnableOnQueue(env, callbackQueueThread, jNativeRunnable.get());
+  }
+
+  virtual void onCallNativeModules(
+      ExecutorToken executorToken,
+      std::vector<MethodCall>&& calls,
+      bool isEndOfBatch) override {
+    executeCallbackOnCallbackQueueThread([executorToken, calls, isEndOfBatch] (ResolvedWeakReference& callback) {
+      JNIEnv* env = Environment::current();
+      for (auto& call : calls) {
+        makeJavaCall(env, executorToken, callback, call);
         if (env->ExceptionCheck()) {
           return;
         }
@@ -641,23 +660,31 @@ static void dispatchCallbacksToJava(ExecutorToken executorToken,
       if (isEndOfBatch) {
         signalBatchComplete(env, callback);
       }
-    }
-  }, std::move(calls));
+    });
+  }
 
-  auto jNativeRunnable = runnable::createNativeRunnable(env, std::move(runnableFunction));
-  queue::enqueueNativeRunnableOnQueue(env, callbackQueueThread, jNativeRunnable.get());
-}
+  virtual void onExecutorUnregistered(ExecutorToken executorToken) override {
+    executeCallbackOnCallbackQueueThread([executorToken] (ResolvedWeakReference& callback) {
+      JNIEnv *env = Environment::current();
+      env->CallVoidMethod(
+          callback,
+          gOnExecutorUnregisteredMethod,
+          static_cast<JExecutorTokenHolder*>(executorToken.getPlatformExecutorToken().get())->getJobj());
+    });
+  }
+private:
+  RefPtr<WeakReference> weakCallback_;
+  RefPtr<WeakReference> weakCallbackQueueThread_;
+};
 
 static void create(JNIEnv* env, jobject obj, jobject executor, jobject callback,
                    jobject callbackQueueThread) {
   auto weakCallback = createNew<WeakReference>(callback);
   auto weakCallbackQueueThread = createNew<WeakReference>(callbackQueueThread);
-  auto bridgeCallback = [weakCallback, weakCallbackQueueThread] (ExecutorToken executorToken, std::vector<MethodCall> calls, bool isEndOfBatch) {
-    dispatchCallbacksToJava(executorToken, weakCallback, weakCallbackQueueThread, std::move(calls), isEndOfBatch);
-  };
+  auto bridgeCallback = folly::make_unique<PlatformBridgeCallback>(weakCallback, weakCallbackQueueThread);
   auto nativeExecutorFactory = extractRefPtr<CountableJSExecutorFactory>(env, executor);
   auto executorTokenFactory = folly::make_unique<JExecutorTokenFactory>();
-  auto bridge = createNew<CountableBridge>(nativeExecutorFactory.get(), std::move(executorTokenFactory), bridgeCallback);
+  auto bridge = createNew<CountableBridge>(nativeExecutorFactory.get(), std::move(executorTokenFactory), std::move(bridgeCallback));
   setCountableForJava(env, obj, std::move(bridge));
 }
 
@@ -968,6 +995,7 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
     jclass callbackClass = env->FindClass("com/facebook/react/bridge/ReactCallback");
     bridge::gCallbackMethod = env->GetMethodID(callbackClass, "call", "(Lcom/facebook/react/bridge/ExecutorToken;IILcom/facebook/react/bridge/ReadableNativeArray;)V");
     bridge::gOnBatchCompleteMethod = env->GetMethodID(callbackClass, "onBatchComplete", "()V");
+    bridge::gOnExecutorUnregisteredMethod = env->GetMethodID(callbackClass, "onExecutorUnregistered", "(Lcom/facebook/react/bridge/ExecutorToken;)V");
 
     jclass markerClass = env->FindClass("com/facebook/react/bridge/ReactMarker");
     bridge::gLogMarkerMethod = env->GetStaticMethodID(markerClass, "logMarker", "(Ljava/lang/String;)V");

From 36f1961003a7983918f12180a4d18bb2424ee494 Mon Sep 17 00:00:00 2001
From: Satyajit Sahoo <satyajit.happy@gmail.com>
Date: Thu, 3 Mar 2016 04:15:15 -0800
Subject: [PATCH 1393/1411] Use flow-bin to typecheck locally, update ESLint to
 2.0

Summary:Using local version of the Flow make it easy to have project specific version instead of relying on the user to have the correct version installed globally. For example, React Native uses an older version of Flow, while I have the latest version installed. Now I cannot typecheck the code because my version doesn't match the `.flowconfig`.

**Test plan (required)**

Run `npm run lint` and `npm run flow` to run `eslint` and `flow`.

cc bestander mkonicek
Closes https://github.com/facebook/react-native/pull/6145

Reviewed By: dmmiller

Differential Revision: D2976616

Pulled By: bestander

fb-gh-sync-id: bb08f6f8ceb09f644ec1d45c40b4cb7a9d3cfef5
shipit-source-id: bb08f6f8ceb09f644ec1d45c40b4cb7a9d3cfef5
---
 .eslintrc           |    6 +-
 .travis.yml         |    6 +-
 npm-shrinkwrap.json | 1791 +++++++++++++++++++++++++++++++++++++------
 package.json        |   13 +-
 4 files changed, 1549 insertions(+), 267 deletions(-)

diff --git a/.eslintrc b/.eslintrc
index 8c33d4d3842d..d707517a0d62 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -113,7 +113,6 @@
     "no-caller": 1,                  // disallow use of arguments.caller or arguments.callee
     "no-div-regex": 1,               // disallow division operators explicitly at beginning of regular expression (off by default)
     "no-else-return": 0,             // disallow else after a return in an if (off by default)
-    "no-empty-label": 1,             // disallow use of labels for anything other then loops and switches
     "no-eq-null": 0,                 // disallow comparisons to null without a type-checking operator (off by default)
     "no-eval": 1,                    // disallow use of eval()
     "no-extend-native": 1,           // disallow adding to native types
@@ -182,6 +181,8 @@
   // These rules are purely matters of style and are quite subjective.
 
     "key-spacing": 0,
+    "keyword-spacing": 1,            // enforce spacing before and after keywords
+    "jsx-quotes": [1, "prefer-double"],
     "comma-spacing": 0,
     "no-multi-spaces": 0,
     "brace-style": 0,                // enforce one true brace style (off by default)
@@ -205,11 +206,9 @@
     "quote-props": 0,                // require quotes around object literal property names (off by default)
     "semi": 1,                       // require or disallow use of semicolons instead of ASI
     "sort-vars": 0,                  // sort variables within the same declaration block (off by default)
-    "space-after-keywords": 1,       // require a space after certain keywords (off by default)
     "space-in-brackets": 0,          // require or disallow spaces inside brackets (off by default)
     "space-in-parens": 0,            // require or disallow spaces inside parentheses (off by default)
     "space-infix-ops": 1,            // require spaces around operators
-    "space-return-throw-case": 1,    // require a space after return, throw, and case
     "space-unary-ops": [1, { "words": true, "nonwords": false }], // require or disallow spaces before/after unary operators (words on by default, nonwords off by default)
     "max-nested-callbacks": 0,       // specify the maximum depth callbacks can be nested (off by default)
     "one-var": 0,                    // allow just one var statement per function (off by default)
@@ -227,7 +226,6 @@
 
     "react/display-name": 0,
     "react/jsx-boolean-value": 0,
-    "react/jsx-quotes": [1, "double", "avoid-escape"],
     "react/jsx-no-undef": 1,
     "react/jsx-sort-props": 0,
     "react/jsx-uses-react": 0,
diff --git a/.travis.yml b/.travis.yml
index fea5c97a1c24..341efe0a4f96 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,7 +16,6 @@ install:
   - rm -Rf "${TMPDIR}/jest_preprocess_cache"
   - npm config set spin=false
   - npm config set progress=false
-  - npm install -g flow-bin@`node -p "require('fs').readFileSync('.flowconfig', 'utf8').split('[version]')[1].trim()"`
   - npm install
 
 script:
@@ -30,9 +29,8 @@ script:
   then
 
     npm install github@0.2.4
-    cat <(echo eslint; npm run lint --silent -- --format=json; echo flow; flow --json) | GITHUB_TOKEN="af6ef0d15709bc91d""06a6217a5a826a226fb57b7" node bots/code-analysis-bot.js
-    flow check
-    npm test
+    cat <(echo eslint; npm run lint --silent -- --format=json; echo flow; npm run flow --silent -- --json) | GITHUB_TOKEN="af6ef0d15709bc91d""06a6217a5a826a226fb57b7" node bots/code-analysis-bot.js
+    npm run flow && npm test
 
   elif [ "$TEST_TYPE" = e2e-objc ]
   then
diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index bc519c383b22..402033f54913 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -122,16 +122,16 @@
           "from": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.3.tgz"
         },
-        "ast-types": {
-          "version": "0.8.12",
-          "from": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz",
-          "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz"
-        },
         "babylon": {
           "version": "5.8.29",
           "from": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz",
           "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.29.tgz"
         },
+        "ast-types": {
+          "version": "0.8.12",
+          "from": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz",
+          "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz"
+        },
         "globals": {
           "version": "6.4.1",
           "from": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz",
@@ -1865,253 +1865,1534 @@
         }
       }
     },
-    "for-in": {
-      "version": "0.1.4",
-      "from": "https://registry.npmjs.org/for-in/-/for-in-0.1.4.tgz",
-      "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.4.tgz"
-    },
-    "for-own": {
-      "version": "0.1.3",
-      "from": "https://registry.npmjs.org/for-own/-/for-own-0.1.3.tgz",
-      "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.3.tgz"
-    },
-    "fs-readdir-recursive": {
-      "version": "0.1.2",
-      "from": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz",
-      "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz"
-    },
-    "fsevents": {
-      "version": "1.0.5",
-      "from": "https://registry.npmjs.org/fsevents/-/fsevents-1.0.5.tgz",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.0.5.tgz",
+    "flow-bin": {
+      "version": "0.21.0",
+      "from": "flow-bin@>=0.21.0 <0.22.0",
+      "resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.21.0.tgz",
       "dependencies": {
-        "node-pre-gyp": {
-          "version": "0.6.15",
-          "from": "node-pre-gyp@latest",
-          "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.6.15.tgz",
+        "bin-wrapper": {
+          "version": "2.1.3",
+          "from": "bin-wrapper@>=2.0.0 <3.0.0",
+          "resolved": "https://registry.npmjs.org/bin-wrapper/-/bin-wrapper-2.1.3.tgz",
           "dependencies": {
-            "nopt": {
-              "version": "3.0.4",
-              "from": "nopt@>=3.0.1 <3.1.0",
-              "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.4.tgz"
-            }
-          }
-        },
-        "abbrev": {
-          "version": "1.0.7",
-          "from": "abbrev@1",
-          "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz"
-        },
-        "ansi": {
-          "version": "0.3.0",
-          "from": "ansi@~0.3.0",
-          "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.0.tgz"
-        },
-        "ansi-regex": {
-          "version": "2.0.0",
-          "from": "ansi-regex@^2.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
-        },
-        "ansi-styles": {
-          "version": "2.1.0",
-          "from": "ansi-styles@^2.1.0",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz"
-        },
-        "are-we-there-yet": {
-          "version": "1.0.4",
-          "from": "are-we-there-yet@~1.0.0",
-          "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.4.tgz"
-        },
-        "asn1": {
-          "version": "0.1.11",
-          "from": "asn1@0.1.11",
-          "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
-        },
-        "assert-plus": {
-          "version": "0.1.5",
-          "from": "assert-plus@^0.1.5",
-          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
-        },
-        "async": {
-          "version": "1.5.0",
-          "from": "async@^1.4.0",
-          "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz"
-        },
-        "aws-sign2": {
-          "version": "0.6.0",
-          "from": "aws-sign2@~0.6.0",
-          "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
-        },
-        "balanced-match": {
-          "version": "0.2.1",
-          "from": "balanced-match@>=0.2.0 <0.3.0",
-          "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.1.tgz"
-        },
-        "boom": {
-          "version": "2.10.1",
-          "from": "boom@^2.8.x",
-          "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz"
-        },
-        "block-stream": {
-          "version": "0.0.8",
-          "from": "block-stream@*",
-          "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.8.tgz"
-        },
-        "brace-expansion": {
-          "version": "1.1.1",
-          "from": "brace-expansion@>=1.0.0 <2.0.0",
-          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz"
-        },
-        "caseless": {
-          "version": "0.11.0",
-          "from": "caseless@~0.11.0",
-          "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
-        },
-        "chalk": {
-          "version": "1.1.1",
-          "from": "chalk@^1.1.1",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz"
-        },
-        "combined-stream": {
-          "version": "1.0.5",
-          "from": "combined-stream@~1.0.5",
-          "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz"
-        },
-        "commander": {
-          "version": "2.9.0",
-          "from": "commander@^2.8.1",
-          "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz"
-        },
-        "concat-map": {
-          "version": "0.0.1",
-          "from": "concat-map@0.0.1",
-          "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
-        },
-        "core-util-is": {
-          "version": "1.0.1",
-          "from": "core-util-is@~1.0.0",
-          "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
-        },
-        "cryptiles": {
-          "version": "2.0.5",
-          "from": "cryptiles@2.x.x",
-          "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz"
-        },
-        "ctype": {
-          "version": "0.5.3",
-          "from": "ctype@0.5.3",
-          "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz"
-        },
-        "debug": {
-          "version": "0.7.4",
-          "from": "debug@~0.7.2",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz"
-        },
-        "deep-extend": {
-          "version": "0.2.11",
-          "from": "deep-extend@~0.2.5",
-          "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.2.11.tgz"
-        },
-        "delayed-stream": {
-          "version": "1.0.0",
-          "from": "delayed-stream@~1.0.0",
-          "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
-        },
-        "delegates": {
-          "version": "0.1.0",
-          "from": "delegates@^0.1.0",
-          "resolved": "https://registry.npmjs.org/delegates/-/delegates-0.1.0.tgz"
-        },
-        "escape-string-regexp": {
-          "version": "1.0.3",
-          "from": "escape-string-regexp@^1.0.2",
-          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz"
-        },
-        "extend": {
-          "version": "3.0.0",
-          "from": "extend@~3.0.0",
-          "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz"
-        },
-        "forever-agent": {
-          "version": "0.6.1",
-          "from": "forever-agent@~0.6.1",
-          "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz"
-        },
-        "form-data": {
-          "version": "1.0.0-rc3",
-          "from": "form-data@~1.0.0-rc3",
-          "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.0-rc3.tgz"
-        },
-        "fstream": {
-          "version": "1.0.8",
-          "from": "fstream@^1.0.2",
-          "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.8.tgz"
-        },
-        "gauge": {
-          "version": "1.2.2",
-          "from": "gauge@~1.2.0",
-          "resolved": "https://registry.npmjs.org/gauge/-/gauge-1.2.2.tgz"
-        },
-        "generate-function": {
-          "version": "2.0.0",
-          "from": "generate-function@^2.0.0",
-          "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz"
-        },
-        "generate-object-property": {
-          "version": "1.2.0",
-          "from": "generate-object-property@^1.1.0",
-          "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz"
-        },
-        "graceful-fs": {
-          "version": "4.1.2",
-          "from": "graceful-fs@4.1",
-          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.2.tgz"
-        },
-        "graceful-readlink": {
-          "version": "1.0.1",
-          "from": "graceful-readlink@>= 1.0.0",
-          "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
-        },
-        "har-validator": {
-          "version": "2.0.2",
-          "from": "har-validator@~2.0.2",
-          "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.2.tgz"
-        },
-        "has-ansi": {
-          "version": "2.0.0",
-          "from": "has-ansi@^2.0.0",
-          "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
-        },
-        "has-unicode": {
-          "version": "1.0.1",
-          "from": "has-unicode@^1.0.0",
-          "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-1.0.1.tgz"
-        },
-        "hawk": {
-          "version": "3.1.0",
-          "from": "hawk@~3.1.0",
-          "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.0.tgz"
-        },
-        "hoek": {
-          "version": "2.16.3",
-          "from": "hoek@2.x.x",
-          "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz"
-        },
-        "http-signature": {
-          "version": "0.11.0",
-          "from": "http-signature@~0.11.0",
-          "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.11.0.tgz"
-        },
-        "inherits": {
-          "version": "2.0.1",
-          "from": "inherits@*",
-          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
-        },
-        "ini": {
-          "version": "1.3.4",
-          "from": "ini@~1.3.0",
-          "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz"
-        },
+            "bin-check": {
+              "version": "1.1.0",
+              "from": "bin-check@>=1.0.0 <2.0.0",
+              "resolved": "https://registry.npmjs.org/bin-check/-/bin-check-1.1.0.tgz",
+              "dependencies": {
+                "executable": {
+                  "version": "1.1.0",
+                  "from": "executable@>=1.0.0 <2.0.0",
+                  "resolved": "https://registry.npmjs.org/executable/-/executable-1.1.0.tgz"
+                },
+                "spawn-sync": {
+                  "version": "1.0.15",
+                  "from": "spawn-sync@>=1.0.6 <2.0.0",
+                  "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz",
+                  "dependencies": {
+                    "concat-stream": {
+                      "version": "1.5.1",
+                      "from": "concat-stream@>=1.4.6 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.1.tgz",
+                      "dependencies": {
+                        "typedarray": {
+                          "version": "0.0.6",
+                          "from": "typedarray@>=0.0.5 <0.1.0",
+                          "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
+                        }
+                      }
+                    },
+                    "os-shim": {
+                      "version": "0.1.3",
+                      "from": "os-shim@>=0.1.2 <0.2.0",
+                      "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz"
+                    }
+                  }
+                }
+              }
+            },
+            "bin-version-check": {
+              "version": "2.1.0",
+              "from": "bin-version-check@>=2.1.0 <3.0.0",
+              "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-2.1.0.tgz",
+              "dependencies": {
+                "bin-version": {
+                  "version": "1.0.4",
+                  "from": "bin-version@>=1.0.0 <2.0.0",
+                  "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-1.0.4.tgz",
+                  "dependencies": {
+                    "find-versions": {
+                      "version": "1.2.1",
+                      "from": "find-versions@>=1.0.0 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-1.2.1.tgz",
+                      "dependencies": {
+                        "semver-regex": {
+                          "version": "1.0.0",
+                          "from": "semver-regex@>=1.0.0 <2.0.0",
+                          "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-1.0.0.tgz"
+                        }
+                      }
+                    }
+                  }
+                },
+                "semver": {
+                  "version": "4.3.6",
+                  "from": "semver@>=4.0.3 <5.0.0",
+                  "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz"
+                },
+                "semver-truncate": {
+                  "version": "1.1.0",
+                  "from": "semver-truncate@>=1.0.0 <2.0.0",
+                  "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-1.1.0.tgz",
+                  "dependencies": {
+                    "semver": {
+                      "version": "5.1.0",
+                      "from": "semver@>=5.0.3 <6.0.0",
+                      "resolved": "https://registry.npmjs.org/semver/-/semver-5.1.0.tgz"
+                    }
+                  }
+                }
+              }
+            },
+            "download": {
+              "version": "3.3.0",
+              "from": "download@>=3.3.0 <4.0.0",
+              "resolved": "https://registry.npmjs.org/download/-/download-3.3.0.tgz",
+              "dependencies": {
+                "concat-stream": {
+                  "version": "1.5.1",
+                  "from": "concat-stream@>=1.4.6 <2.0.0",
+                  "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.1.tgz",
+                  "dependencies": {
+                    "typedarray": {
+                      "version": "0.0.6",
+                      "from": "typedarray@>=0.0.5 <0.1.0",
+                      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
+                    }
+                  }
+                },
+                "decompress-tar": {
+                  "version": "2.0.2",
+                  "from": "decompress-tar@>=2.0.1 <3.0.0",
+                  "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-2.0.2.tgz",
+                  "dependencies": {
+                    "is-tar": {
+                      "version": "1.0.0",
+                      "from": "is-tar@>=1.0.0 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/is-tar/-/is-tar-1.0.0.tgz"
+                    },
+                    "strip-dirs": {
+                      "version": "0.1.1",
+                      "from": "strip-dirs@>=0.1.1 <0.2.0",
+                      "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-0.1.1.tgz",
+                      "dependencies": {
+                        "chalk": {
+                          "version": "0.5.1",
+                          "from": "chalk@>=0.5.1 <0.6.0",
+                          "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz",
+                          "dependencies": {
+                            "ansi-styles": {
+                              "version": "1.1.0",
+                              "from": "ansi-styles@>=1.1.0 <2.0.0",
+                              "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz"
+                            },
+                            "has-ansi": {
+                              "version": "0.1.0",
+                              "from": "has-ansi@>=0.1.0 <0.2.0",
+                              "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz",
+                              "dependencies": {
+                                "ansi-regex": {
+                                  "version": "0.2.1",
+                                  "from": "ansi-regex@>=0.2.0 <0.3.0",
+                                  "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz"
+                                }
+                              }
+                            },
+                            "strip-ansi": {
+                              "version": "0.3.0",
+                              "from": "strip-ansi@>=0.3.0 <0.4.0",
+                              "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz",
+                              "dependencies": {
+                                "ansi-regex": {
+                                  "version": "0.2.1",
+                                  "from": "ansi-regex@>=0.2.0 <0.3.0",
+                                  "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz"
+                                }
+                              }
+                            },
+                            "supports-color": {
+                              "version": "0.2.0",
+                              "from": "supports-color@>=0.2.0 <0.3.0",
+                              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz"
+                            }
+                          }
+                        },
+                        "is-absolute": {
+                          "version": "0.1.7",
+                          "from": "is-absolute@>=0.1.4 <0.2.0",
+                          "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz",
+                          "dependencies": {
+                            "is-relative": {
+                              "version": "0.1.3",
+                              "from": "is-relative@>=0.1.0 <0.2.0",
+                              "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz"
+                            }
+                          }
+                        }
+                      }
+                    },
+                    "tar-stream": {
+                      "version": "0.4.7",
+                      "from": "tar-stream@>=0.4.5 <0.5.0",
+                      "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-0.4.7.tgz",
+                      "dependencies": {
+                        "bl": {
+                          "version": "0.9.5",
+                          "from": "bl@>=0.9.0 <0.10.0",
+                          "resolved": "https://registry.npmjs.org/bl/-/bl-0.9.5.tgz",
+                          "dependencies": {
+                            "readable-stream": {
+                              "version": "1.0.33",
+                              "from": "readable-stream@>=1.0.26 <1.1.0",
+                              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz"
+                            }
+                          }
+                        },
+                        "end-of-stream": {
+                          "version": "1.1.0",
+                          "from": "end-of-stream@>=1.0.0 <2.0.0",
+                          "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.1.0.tgz"
+                        },
+                        "readable-stream": {
+                          "version": "1.1.13",
+                          "from": "readable-stream@>=1.0.27-1 <2.0.0",
+                          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz"
+                        }
+                      }
+                    }
+                  }
+                },
+                "decompress-tarbz2": {
+                  "version": "2.0.2",
+                  "from": "decompress-tarbz2@>=2.0.1 <3.0.0",
+                  "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-2.0.2.tgz",
+                  "dependencies": {
+                    "is-bzip2": {
+                      "version": "1.0.0",
+                      "from": "is-bzip2@>=1.0.0 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/is-bzip2/-/is-bzip2-1.0.0.tgz"
+                    },
+                    "seek-bzip": {
+                      "version": "1.0.5",
+                      "from": "seek-bzip@>=1.0.3 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz",
+                      "dependencies": {
+                        "commander": {
+                          "version": "2.8.1",
+                          "from": "commander@>=2.8.1 <2.9.0",
+                          "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz"
+                        }
+                      }
+                    },
+                    "strip-dirs": {
+                      "version": "0.1.1",
+                      "from": "strip-dirs@>=0.1.1 <0.2.0",
+                      "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-0.1.1.tgz",
+                      "dependencies": {
+                        "chalk": {
+                          "version": "0.5.1",
+                          "from": "chalk@>=0.5.1 <0.6.0",
+                          "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz",
+                          "dependencies": {
+                            "ansi-styles": {
+                              "version": "1.1.0",
+                              "from": "ansi-styles@>=1.1.0 <2.0.0",
+                              "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz"
+                            },
+                            "has-ansi": {
+                              "version": "0.1.0",
+                              "from": "has-ansi@>=0.1.0 <0.2.0",
+                              "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz",
+                              "dependencies": {
+                                "ansi-regex": {
+                                  "version": "0.2.1",
+                                  "from": "ansi-regex@>=0.2.0 <0.3.0",
+                                  "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz"
+                                }
+                              }
+                            },
+                            "strip-ansi": {
+                              "version": "0.3.0",
+                              "from": "strip-ansi@>=0.3.0 <0.4.0",
+                              "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz",
+                              "dependencies": {
+                                "ansi-regex": {
+                                  "version": "0.2.1",
+                                  "from": "ansi-regex@>=0.2.0 <0.3.0",
+                                  "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz"
+                                }
+                              }
+                            },
+                            "supports-color": {
+                              "version": "0.2.0",
+                              "from": "supports-color@>=0.2.0 <0.3.0",
+                              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz"
+                            }
+                          }
+                        },
+                        "is-absolute": {
+                          "version": "0.1.7",
+                          "from": "is-absolute@>=0.1.4 <0.2.0",
+                          "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz",
+                          "dependencies": {
+                            "is-relative": {
+                              "version": "0.1.3",
+                              "from": "is-relative@>=0.1.0 <0.2.0",
+                              "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz"
+                            }
+                          }
+                        }
+                      }
+                    },
+                    "tar-stream": {
+                      "version": "0.4.7",
+                      "from": "tar-stream@>=0.4.5 <0.5.0",
+                      "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-0.4.7.tgz",
+                      "dependencies": {
+                        "bl": {
+                          "version": "0.9.5",
+                          "from": "bl@>=0.9.0 <0.10.0",
+                          "resolved": "https://registry.npmjs.org/bl/-/bl-0.9.5.tgz",
+                          "dependencies": {
+                            "readable-stream": {
+                              "version": "1.0.33",
+                              "from": "readable-stream@>=1.0.26 <1.1.0",
+                              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz"
+                            }
+                          }
+                        },
+                        "end-of-stream": {
+                          "version": "1.1.0",
+                          "from": "end-of-stream@>=1.0.0 <2.0.0",
+                          "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.1.0.tgz"
+                        },
+                        "readable-stream": {
+                          "version": "1.1.13",
+                          "from": "readable-stream@>=1.0.27-1 <2.0.0",
+                          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz"
+                        }
+                      }
+                    }
+                  }
+                },
+                "decompress-targz": {
+                  "version": "2.1.0",
+                  "from": "decompress-targz@>=2.0.1 <3.0.0",
+                  "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-2.1.0.tgz",
+                  "dependencies": {
+                    "is-gzip": {
+                      "version": "1.0.0",
+                      "from": "is-gzip@>=1.0.0 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/is-gzip/-/is-gzip-1.0.0.tgz"
+                    },
+                    "strip-dirs": {
+                      "version": "1.1.1",
+                      "from": "strip-dirs@>=1.0.0 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-1.1.1.tgz",
+                      "dependencies": {
+                        "get-stdin": {
+                          "version": "4.0.1",
+                          "from": "get-stdin@>=4.0.1 <5.0.0",
+                          "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz"
+                        },
+                        "is-absolute": {
+                          "version": "0.1.7",
+                          "from": "is-absolute@>=0.1.4 <0.2.0",
+                          "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz",
+                          "dependencies": {
+                            "is-relative": {
+                              "version": "0.1.3",
+                              "from": "is-relative@>=0.1.0 <0.2.0",
+                              "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz"
+                            }
+                          }
+                        },
+                        "is-natural-number": {
+                          "version": "2.0.0",
+                          "from": "is-natural-number@>=2.0.0 <3.0.0",
+                          "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-2.0.0.tgz"
+                        },
+                        "sum-up": {
+                          "version": "1.0.2",
+                          "from": "sum-up@>=1.0.1 <2.0.0",
+                          "resolved": "https://registry.npmjs.org/sum-up/-/sum-up-1.0.2.tgz"
+                        }
+                      }
+                    },
+                    "tar-stream": {
+                      "version": "1.3.2",
+                      "from": "tar-stream@>=1.1.1 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.3.2.tgz",
+                      "dependencies": {
+                        "bl": {
+                          "version": "1.1.2",
+                          "from": "bl@>=1.0.0 <2.0.0",
+                          "resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz",
+                          "dependencies": {
+                            "readable-stream": {
+                              "version": "2.0.5",
+                              "from": "readable-stream@>=2.0.5 <2.1.0",
+                              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.5.tgz",
+                              "dependencies": {
+                                "process-nextick-args": {
+                                  "version": "1.0.6",
+                                  "from": "process-nextick-args@>=1.0.6 <1.1.0",
+                                  "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.6.tgz"
+                                }
+                              }
+                            }
+                          }
+                        },
+                        "end-of-stream": {
+                          "version": "1.1.0",
+                          "from": "end-of-stream@>=1.0.0 <2.0.0",
+                          "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.1.0.tgz"
+                        }
+                      }
+                    }
+                  }
+                },
+                "decompress-unzip": {
+                  "version": "2.1.2",
+                  "from": "decompress-unzip@>=2.0.0 <3.0.0",
+                  "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-2.1.2.tgz",
+                  "dependencies": {
+                    "is-zip": {
+                      "version": "1.0.0",
+                      "from": "is-zip@>=1.0.0 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/is-zip/-/is-zip-1.0.0.tgz"
+                    },
+                    "strip-dirs": {
+                      "version": "1.1.1",
+                      "from": "strip-dirs@>=1.0.0 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-1.1.1.tgz",
+                      "dependencies": {
+                        "get-stdin": {
+                          "version": "4.0.1",
+                          "from": "get-stdin@>=4.0.1 <5.0.0",
+                          "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz"
+                        },
+                        "is-absolute": {
+                          "version": "0.1.7",
+                          "from": "is-absolute@>=0.1.5 <0.2.0",
+                          "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz",
+                          "dependencies": {
+                            "is-relative": {
+                              "version": "0.1.3",
+                              "from": "is-relative@>=0.1.0 <0.2.0",
+                              "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz"
+                            }
+                          }
+                        },
+                        "is-natural-number": {
+                          "version": "2.0.0",
+                          "from": "is-natural-number@>=2.0.0 <3.0.0",
+                          "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-2.0.0.tgz"
+                        },
+                        "sum-up": {
+                          "version": "1.0.2",
+                          "from": "sum-up@>=1.0.1 <2.0.0",
+                          "resolved": "https://registry.npmjs.org/sum-up/-/sum-up-1.0.2.tgz"
+                        }
+                      }
+                    },
+                    "yauzl": {
+                      "version": "2.4.1",
+                      "from": "yauzl@>=2.2.1 <3.0.0",
+                      "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz",
+                      "dependencies": {
+                        "fd-slicer": {
+                          "version": "1.0.1",
+                          "from": "fd-slicer@>=1.0.1 <1.1.0",
+                          "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz",
+                          "dependencies": {
+                            "pend": {
+                              "version": "1.2.0",
+                              "from": "pend@>=1.2.0 <1.3.0",
+                              "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz"
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                },
+                "each-async": {
+                  "version": "1.1.1",
+                  "from": "each-async@>=1.0.0 <2.0.0",
+                  "resolved": "https://registry.npmjs.org/each-async/-/each-async-1.1.1.tgz",
+                  "dependencies": {
+                    "onetime": {
+                      "version": "1.1.0",
+                      "from": "onetime@>=1.0.0 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz"
+                    },
+                    "set-immediate-shim": {
+                      "version": "1.0.1",
+                      "from": "set-immediate-shim@>=1.0.0 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz"
+                    }
+                  }
+                },
+                "get-stdin": {
+                  "version": "3.0.2",
+                  "from": "get-stdin@>=3.0.0 <4.0.0",
+                  "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-3.0.2.tgz"
+                },
+                "gulp-rename": {
+                  "version": "1.2.2",
+                  "from": "gulp-rename@>=1.2.0 <2.0.0",
+                  "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-1.2.2.tgz"
+                },
+                "meow": {
+                  "version": "2.1.0",
+                  "from": "meow@>=2.0.0 <3.0.0",
+                  "resolved": "https://registry.npmjs.org/meow/-/meow-2.1.0.tgz",
+                  "dependencies": {
+                    "indent-string": {
+                      "version": "1.2.2",
+                      "from": "indent-string@>=1.1.0 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-1.2.2.tgz",
+                      "dependencies": {
+                        "get-stdin": {
+                          "version": "4.0.1",
+                          "from": "get-stdin@>=4.0.1 <5.0.0",
+                          "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz"
+                        }
+                      }
+                    },
+                    "object-assign": {
+                      "version": "2.1.1",
+                      "from": "object-assign@>=2.0.0 <3.0.0",
+                      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz"
+                    }
+                  }
+                },
+                "rc": {
+                  "version": "0.5.5",
+                  "from": "rc@>=0.5.1 <0.6.0",
+                  "resolved": "https://registry.npmjs.org/rc/-/rc-0.5.5.tgz",
+                  "dependencies": {
+                    "minimist": {
+                      "version": "0.0.10",
+                      "from": "minimist@>=0.0.7 <0.1.0",
+                      "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz"
+                    },
+                    "deep-extend": {
+                      "version": "0.2.11",
+                      "from": "deep-extend@>=0.2.5 <0.3.0",
+                      "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.2.11.tgz"
+                    },
+                    "strip-json-comments": {
+                      "version": "0.1.3",
+                      "from": "strip-json-comments@>=0.1.0 <0.2.0",
+                      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
+                    },
+                    "ini": {
+                      "version": "1.3.4",
+                      "from": "ini@>=1.3.0 <1.4.0",
+                      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz"
+                    }
+                  }
+                },
+                "request": {
+                  "version": "2.69.0",
+                  "from": "request@>=2.34.0 <3.0.0",
+                  "resolved": "https://registry.npmjs.org/request/-/request-2.69.0.tgz",
+                  "dependencies": {
+                    "aws-sign2": {
+                      "version": "0.6.0",
+                      "from": "aws-sign2@>=0.6.0 <0.7.0",
+                      "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
+                    },
+                    "aws4": {
+                      "version": "1.3.2",
+                      "from": "aws4@>=1.2.1 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.3.2.tgz",
+                      "dependencies": {
+                        "lru-cache": {
+                          "version": "4.0.0",
+                          "from": "lru-cache@>=4.0.0 <5.0.0",
+                          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.0.tgz",
+                          "dependencies": {
+                            "pseudomap": {
+                              "version": "1.0.2",
+                              "from": "pseudomap@>=1.0.1 <2.0.0",
+                              "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz"
+                            },
+                            "yallist": {
+                              "version": "2.0.0",
+                              "from": "yallist@>=2.0.0 <3.0.0",
+                              "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.0.0.tgz"
+                            }
+                          }
+                        }
+                      }
+                    },
+                    "bl": {
+                      "version": "1.0.3",
+                      "from": "bl@>=1.0.0 <1.1.0",
+                      "resolved": "https://registry.npmjs.org/bl/-/bl-1.0.3.tgz",
+                      "dependencies": {
+                        "readable-stream": {
+                          "version": "2.0.5",
+                          "from": "readable-stream@>=2.0.5 <2.1.0",
+                          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.5.tgz",
+                          "dependencies": {
+                            "process-nextick-args": {
+                              "version": "1.0.6",
+                              "from": "process-nextick-args@>=1.0.6 <1.1.0",
+                              "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.6.tgz"
+                            }
+                          }
+                        }
+                      }
+                    },
+                    "caseless": {
+                      "version": "0.11.0",
+                      "from": "caseless@>=0.11.0 <0.12.0",
+                      "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
+                    },
+                    "combined-stream": {
+                      "version": "1.0.5",
+                      "from": "combined-stream@>=1.0.5 <1.1.0",
+                      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
+                      "dependencies": {
+                        "delayed-stream": {
+                          "version": "1.0.0",
+                          "from": "delayed-stream@>=1.0.0 <1.1.0",
+                          "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
+                        }
+                      }
+                    },
+                    "extend": {
+                      "version": "3.0.0",
+                      "from": "extend@>=3.0.0 <3.1.0",
+                      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz"
+                    },
+                    "forever-agent": {
+                      "version": "0.6.1",
+                      "from": "forever-agent@>=0.6.1 <0.7.0",
+                      "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz"
+                    },
+                    "form-data": {
+                      "version": "1.0.0-rc3",
+                      "from": "form-data@>=1.0.0-rc3 <1.1.0",
+                      "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.0-rc3.tgz",
+                      "dependencies": {
+                        "async": {
+                          "version": "1.5.2",
+                          "from": "async@>=1.4.0 <2.0.0",
+                          "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz"
+                        }
+                      }
+                    },
+                    "har-validator": {
+                      "version": "2.0.6",
+                      "from": "har-validator@>=2.0.6 <2.1.0",
+                      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz",
+                      "dependencies": {
+                        "is-my-json-valid": {
+                          "version": "2.13.1",
+                          "from": "is-my-json-valid@>=2.12.4 <3.0.0",
+                          "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.13.1.tgz",
+                          "dependencies": {
+                            "generate-function": {
+                              "version": "2.0.0",
+                              "from": "generate-function@>=2.0.0 <3.0.0",
+                              "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz"
+                            },
+                            "generate-object-property": {
+                              "version": "1.2.0",
+                              "from": "generate-object-property@>=1.1.0 <2.0.0",
+                              "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
+                              "dependencies": {
+                                "is-property": {
+                                  "version": "1.0.2",
+                                  "from": "is-property@>=1.0.0 <2.0.0",
+                                  "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz"
+                                }
+                              }
+                            },
+                            "jsonpointer": {
+                              "version": "2.0.0",
+                              "from": "jsonpointer@2.0.0",
+                              "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
+                            }
+                          }
+                        },
+                        "pinkie-promise": {
+                          "version": "2.0.0",
+                          "from": "pinkie-promise@>=2.0.0 <3.0.0",
+                          "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.0.tgz",
+                          "dependencies": {
+                            "pinkie": {
+                              "version": "2.0.4",
+                              "from": "pinkie@>=2.0.0 <3.0.0",
+                              "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz"
+                            }
+                          }
+                        }
+                      }
+                    },
+                    "hawk": {
+                      "version": "3.1.3",
+                      "from": "hawk@>=3.1.0 <3.2.0",
+                      "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
+                      "dependencies": {
+                        "hoek": {
+                          "version": "2.16.3",
+                          "from": "hoek@>=2.0.0 <3.0.0",
+                          "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz"
+                        },
+                        "boom": {
+                          "version": "2.10.1",
+                          "from": "boom@>=2.0.0 <3.0.0",
+                          "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz"
+                        },
+                        "cryptiles": {
+                          "version": "2.0.5",
+                          "from": "cryptiles@>=2.0.0 <3.0.0",
+                          "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz"
+                        },
+                        "sntp": {
+                          "version": "1.0.9",
+                          "from": "sntp@>=1.0.0 <2.0.0",
+                          "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
+                        }
+                      }
+                    },
+                    "http-signature": {
+                      "version": "1.1.1",
+                      "from": "http-signature@>=1.1.0 <1.2.0",
+                      "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz",
+                      "dependencies": {
+                        "assert-plus": {
+                          "version": "0.2.0",
+                          "from": "assert-plus@>=0.2.0 <0.3.0",
+                          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz"
+                        },
+                        "jsprim": {
+                          "version": "1.2.2",
+                          "from": "jsprim@>=1.2.2 <2.0.0",
+                          "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.2.2.tgz",
+                          "dependencies": {
+                            "extsprintf": {
+                              "version": "1.0.2",
+                              "from": "extsprintf@1.0.2",
+                              "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz"
+                            },
+                            "json-schema": {
+                              "version": "0.2.2",
+                              "from": "json-schema@0.2.2",
+                              "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.2.tgz"
+                            },
+                            "verror": {
+                              "version": "1.3.6",
+                              "from": "verror@1.3.6",
+                              "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz"
+                            }
+                          }
+                        },
+                        "sshpk": {
+                          "version": "1.7.4",
+                          "from": "sshpk@>=1.7.0 <2.0.0",
+                          "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.7.4.tgz",
+                          "dependencies": {
+                            "asn1": {
+                              "version": "0.2.3",
+                              "from": "asn1@>=0.2.3 <0.3.0",
+                              "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz"
+                            },
+                            "dashdash": {
+                              "version": "1.13.0",
+                              "from": "dashdash@>=1.10.1 <2.0.0",
+                              "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.13.0.tgz",
+                              "dependencies": {
+                                "assert-plus": {
+                                  "version": "1.0.0",
+                                  "from": "assert-plus@>=1.0.0 <2.0.0",
+                                  "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz"
+                                }
+                              }
+                            },
+                            "jsbn": {
+                              "version": "0.1.0",
+                              "from": "jsbn@>=0.1.0 <0.2.0",
+                              "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz"
+                            },
+                            "tweetnacl": {
+                              "version": "0.14.1",
+                              "from": "tweetnacl@>=0.13.0 <1.0.0",
+                              "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.1.tgz"
+                            },
+                            "jodid25519": {
+                              "version": "1.0.2",
+                              "from": "jodid25519@>=1.0.0 <2.0.0",
+                              "resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz"
+                            },
+                            "ecc-jsbn": {
+                              "version": "0.1.1",
+                              "from": "ecc-jsbn@>=0.0.1 <1.0.0",
+                              "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz"
+                            }
+                          }
+                        }
+                      }
+                    },
+                    "is-typedarray": {
+                      "version": "1.0.0",
+                      "from": "is-typedarray@>=1.0.0 <1.1.0",
+                      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz"
+                    },
+                    "isstream": {
+                      "version": "0.1.2",
+                      "from": "isstream@>=0.1.2 <0.2.0",
+                      "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
+                    },
+                    "json-stringify-safe": {
+                      "version": "5.0.1",
+                      "from": "json-stringify-safe@>=5.0.1 <5.1.0",
+                      "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
+                    },
+                    "mime-types": {
+                      "version": "2.1.10",
+                      "from": "mime-types@>=2.1.7 <2.2.0",
+                      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.10.tgz",
+                      "dependencies": {
+                        "mime-db": {
+                          "version": "1.22.0",
+                          "from": "mime-db@>=1.22.0 <1.23.0",
+                          "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.22.0.tgz"
+                        }
+                      }
+                    },
+                    "node-uuid": {
+                      "version": "1.4.7",
+                      "from": "node-uuid@>=1.4.7 <1.5.0",
+                      "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz"
+                    },
+                    "oauth-sign": {
+                      "version": "0.8.1",
+                      "from": "oauth-sign@>=0.8.0 <0.9.0",
+                      "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.1.tgz"
+                    },
+                    "qs": {
+                      "version": "6.0.2",
+                      "from": "qs@>=6.0.2 <6.1.0",
+                      "resolved": "https://registry.npmjs.org/qs/-/qs-6.0.2.tgz"
+                    },
+                    "stringstream": {
+                      "version": "0.0.5",
+                      "from": "stringstream@>=0.0.4 <0.1.0",
+                      "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
+                    },
+                    "tough-cookie": {
+                      "version": "2.2.1",
+                      "from": "tough-cookie@>=2.2.0 <2.3.0",
+                      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.1.tgz"
+                    },
+                    "tunnel-agent": {
+                      "version": "0.4.2",
+                      "from": "tunnel-agent@>=0.4.1 <0.5.0",
+                      "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.2.tgz"
+                    }
+                  }
+                },
+                "stream-combiner": {
+                  "version": "0.2.2",
+                  "from": "stream-combiner@>=0.2.1 <0.3.0",
+                  "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz",
+                  "dependencies": {
+                    "duplexer": {
+                      "version": "0.1.1",
+                      "from": "duplexer@>=0.1.1 <0.2.0",
+                      "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz"
+                    }
+                  }
+                },
+                "through2": {
+                  "version": "0.6.5",
+                  "from": "through2@>=0.6.1 <0.7.0",
+                  "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
+                  "dependencies": {
+                    "readable-stream": {
+                      "version": "1.0.33",
+                      "from": "readable-stream@>=1.0.33-1 <1.1.0-0",
+                      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz"
+                    }
+                  }
+                },
+                "url-regex": {
+                  "version": "2.1.3",
+                  "from": "url-regex@>=2.0.2 <3.0.0",
+                  "resolved": "https://registry.npmjs.org/url-regex/-/url-regex-2.1.3.tgz",
+                  "dependencies": {
+                    "ip-regex": {
+                      "version": "1.0.3",
+                      "from": "ip-regex@>=1.0.1 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-1.0.3.tgz"
+                    }
+                  }
+                },
+                "vinyl": {
+                  "version": "0.4.6",
+                  "from": "vinyl@>=0.4.3 <0.5.0",
+                  "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz",
+                  "dependencies": {
+                    "clone": {
+                      "version": "0.2.0",
+                      "from": "clone@>=0.2.0 <0.3.0",
+                      "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz"
+                    }
+                  }
+                },
+                "vinyl-fs": {
+                  "version": "0.3.14",
+                  "from": "vinyl-fs@>=0.3.7 <0.4.0",
+                  "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-0.3.14.tgz",
+                  "dependencies": {
+                    "defaults": {
+                      "version": "1.0.3",
+                      "from": "defaults@>=1.0.0 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz"
+                    },
+                    "glob-stream": {
+                      "version": "3.1.18",
+                      "from": "glob-stream@>=3.1.5 <4.0.0",
+                      "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-3.1.18.tgz",
+                      "dependencies": {
+                        "glob": {
+                          "version": "4.5.3",
+                          "from": "glob@>=4.3.1 <5.0.0",
+                          "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz"
+                        },
+                        "ordered-read-streams": {
+                          "version": "0.1.0",
+                          "from": "ordered-read-streams@>=0.1.0 <0.2.0",
+                          "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz"
+                        },
+                        "glob2base": {
+                          "version": "0.0.12",
+                          "from": "glob2base@>=0.0.12 <0.0.13",
+                          "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz",
+                          "dependencies": {
+                            "find-index": {
+                              "version": "0.1.1",
+                              "from": "find-index@>=0.1.1 <0.2.0",
+                              "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz"
+                            }
+                          }
+                        },
+                        "unique-stream": {
+                          "version": "1.0.0",
+                          "from": "unique-stream@>=1.0.0 <2.0.0",
+                          "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-1.0.0.tgz"
+                        }
+                      }
+                    },
+                    "glob-watcher": {
+                      "version": "0.0.6",
+                      "from": "glob-watcher@>=0.0.6 <0.0.7",
+                      "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-0.0.6.tgz",
+                      "dependencies": {
+                        "gaze": {
+                          "version": "0.5.2",
+                          "from": "gaze@>=0.5.1 <0.6.0",
+                          "resolved": "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz",
+                          "dependencies": {
+                            "globule": {
+                              "version": "0.1.0",
+                              "from": "globule@>=0.1.0 <0.2.0",
+                              "resolved": "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz",
+                              "dependencies": {
+                                "lodash": {
+                                  "version": "1.0.2",
+                                  "from": "lodash@>=1.0.1 <1.1.0",
+                                  "resolved": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz"
+                                },
+                                "glob": {
+                                  "version": "3.1.21",
+                                  "from": "glob@>=3.1.21 <3.2.0",
+                                  "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz",
+                                  "dependencies": {
+                                    "graceful-fs": {
+                                      "version": "1.2.3",
+                                      "from": "graceful-fs@>=1.2.0 <1.3.0",
+                                      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz"
+                                    },
+                                    "inherits": {
+                                      "version": "1.0.2",
+                                      "from": "inherits@>=1.0.0 <2.0.0",
+                                      "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz"
+                                    }
+                                  }
+                                },
+                                "minimatch": {
+                                  "version": "0.2.14",
+                                  "from": "minimatch@>=0.2.11 <0.3.0",
+                                  "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz",
+                                  "dependencies": {
+                                    "lru-cache": {
+                                      "version": "2.7.3",
+                                      "from": "lru-cache@>=2.0.0 <3.0.0",
+                                      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz"
+                                    },
+                                    "sigmund": {
+                                      "version": "1.0.1",
+                                      "from": "sigmund@>=1.0.0 <1.1.0",
+                                      "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz"
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    },
+                    "graceful-fs": {
+                      "version": "3.0.8",
+                      "from": "graceful-fs@>=3.0.0 <4.0.0",
+                      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.8.tgz"
+                    },
+                    "strip-bom": {
+                      "version": "1.0.0",
+                      "from": "strip-bom@>=1.0.0 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-1.0.0.tgz",
+                      "dependencies": {
+                        "first-chunk-stream": {
+                          "version": "1.0.0",
+                          "from": "first-chunk-stream@>=1.0.0 <2.0.0",
+                          "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz"
+                        }
+                      }
+                    }
+                  }
+                },
+                "ware": {
+                  "version": "1.3.0",
+                  "from": "ware@>=1.0.1 <2.0.0",
+                  "resolved": "https://registry.npmjs.org/ware/-/ware-1.3.0.tgz",
+                  "dependencies": {
+                    "wrap-fn": {
+                      "version": "0.1.5",
+                      "from": "wrap-fn@>=0.1.0 <0.2.0",
+                      "resolved": "https://registry.npmjs.org/wrap-fn/-/wrap-fn-0.1.5.tgz",
+                      "dependencies": {
+                        "co": {
+                          "version": "3.1.0",
+                          "from": "co@3.1.0",
+                          "resolved": "https://registry.npmjs.org/co/-/co-3.1.0.tgz"
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            },
+            "download-status": {
+              "version": "2.2.1",
+              "from": "download-status@>=2.0.0 <3.0.0",
+              "resolved": "https://registry.npmjs.org/download-status/-/download-status-2.2.1.tgz",
+              "dependencies": {
+                "chalk": {
+                  "version": "0.5.1",
+                  "from": "chalk@>=0.5.1 <0.6.0",
+                  "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz",
+                  "dependencies": {
+                    "ansi-styles": {
+                      "version": "1.1.0",
+                      "from": "ansi-styles@>=1.1.0 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz"
+                    },
+                    "has-ansi": {
+                      "version": "0.1.0",
+                      "from": "has-ansi@>=0.1.0 <0.2.0",
+                      "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz",
+                      "dependencies": {
+                        "ansi-regex": {
+                          "version": "0.2.1",
+                          "from": "ansi-regex@>=0.2.0 <0.3.0",
+                          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz"
+                        }
+                      }
+                    },
+                    "strip-ansi": {
+                      "version": "0.3.0",
+                      "from": "strip-ansi@>=0.3.0 <0.4.0",
+                      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz",
+                      "dependencies": {
+                        "ansi-regex": {
+                          "version": "0.2.1",
+                          "from": "ansi-regex@>=0.2.0 <0.3.0",
+                          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz"
+                        }
+                      }
+                    },
+                    "supports-color": {
+                      "version": "0.2.0",
+                      "from": "supports-color@>=0.2.0 <0.3.0",
+                      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz"
+                    }
+                  }
+                },
+                "lpad-align": {
+                  "version": "1.1.0",
+                  "from": "lpad-align@>=1.0.1 <2.0.0",
+                  "resolved": "https://registry.npmjs.org/lpad-align/-/lpad-align-1.1.0.tgz",
+                  "dependencies": {
+                    "lpad": {
+                      "version": "2.0.1",
+                      "from": "lpad@>=2.0.1 <3.0.0",
+                      "resolved": "https://registry.npmjs.org/lpad/-/lpad-2.0.1.tgz"
+                    }
+                  }
+                },
+                "object-assign": {
+                  "version": "2.1.1",
+                  "from": "object-assign@>=2.0.0 <3.0.0",
+                  "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz"
+                }
+              }
+            },
+            "globby": {
+              "version": "1.2.0",
+              "from": "globby@>=1.0.0 <2.0.0",
+              "resolved": "https://registry.npmjs.org/globby/-/globby-1.2.0.tgz",
+              "dependencies": {
+                "array-union": {
+                  "version": "1.0.1",
+                  "from": "array-union@>=1.0.1 <2.0.0",
+                  "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.1.tgz"
+                },
+                "async": {
+                  "version": "0.9.2",
+                  "from": "async@>=0.9.0 <0.10.0",
+                  "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz"
+                },
+                "glob": {
+                  "version": "4.5.3",
+                  "from": "glob@>=4.4.0 <5.0.0",
+                  "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz"
+                },
+                "object-assign": {
+                  "version": "2.1.1",
+                  "from": "object-assign@>=2.0.0 <3.0.0",
+                  "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz"
+                }
+              }
+            },
+            "is-path-global": {
+              "version": "1.0.2",
+              "from": "is-path-global@>=1.0.0 <2.0.0",
+              "resolved": "https://registry.npmjs.org/is-path-global/-/is-path-global-1.0.2.tgz",
+              "dependencies": {
+                "is-path-inside": {
+                  "version": "1.0.0",
+                  "from": "is-path-inside@>=1.0.0 <2.0.0",
+                  "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz",
+                  "dependencies": {
+                    "path-is-inside": {
+                      "version": "1.0.1",
+                      "from": "path-is-inside@>=1.0.1 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.1.tgz"
+                    }
+                  }
+                }
+              }
+            },
+            "lnfs": {
+              "version": "1.1.0",
+              "from": "lnfs@>=1.0.0 <2.0.0",
+              "resolved": "https://registry.npmjs.org/lnfs/-/lnfs-1.1.0.tgz",
+              "dependencies": {
+                "rimraf": {
+                  "version": "2.5.2",
+                  "from": "rimraf@>=2.2.8 <3.0.0",
+                  "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.2.tgz",
+                  "dependencies": {
+                    "glob": {
+                      "version": "7.0.0",
+                      "from": "glob@>=7.0.0 <8.0.0",
+                      "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.0.tgz"
+                    }
+                  }
+                }
+              }
+            },
+            "npm-installed": {
+              "version": "1.0.0",
+              "from": "npm-installed@>=1.0.0 <2.0.0",
+              "resolved": "https://registry.npmjs.org/npm-installed/-/npm-installed-1.0.0.tgz",
+              "dependencies": {
+                "npm-which": {
+                  "version": "1.0.2",
+                  "from": "npm-which@>=1.0.1 <2.0.0",
+                  "resolved": "https://registry.npmjs.org/npm-which/-/npm-which-1.0.2.tgz",
+                  "dependencies": {
+                    "npm-path": {
+                      "version": "1.1.0",
+                      "from": "npm-path@>=1.0.0 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/npm-path/-/npm-path-1.1.0.tgz"
+                    },
+                    "which": {
+                      "version": "1.2.4",
+                      "from": "which@>=1.0.5 <2.0.0",
+                      "resolved": "https://registry.npmjs.org/which/-/which-1.2.4.tgz",
+                      "dependencies": {
+                        "is-absolute": {
+                          "version": "0.1.7",
+                          "from": "is-absolute@>=0.1.7 <0.2.0",
+                          "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz",
+                          "dependencies": {
+                            "is-relative": {
+                              "version": "0.1.3",
+                              "from": "is-relative@>=0.1.0 <0.2.0",
+                              "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz"
+                            }
+                          }
+                        },
+                        "isexe": {
+                          "version": "1.1.2",
+                          "from": "isexe@>=1.1.1 <2.0.0",
+                          "resolved": "https://registry.npmjs.org/isexe/-/isexe-1.1.2.tgz"
+                        }
+                      }
+                    }
+                  }
+                },
+                "rc": {
+                  "version": "0.5.5",
+                  "from": "rc@>=0.5.1 <0.6.0",
+                  "resolved": "https://registry.npmjs.org/rc/-/rc-0.5.5.tgz",
+                  "dependencies": {
+                    "minimist": {
+                      "version": "0.0.10",
+                      "from": "minimist@>=0.0.7 <0.1.0",
+                      "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz"
+                    },
+                    "deep-extend": {
+                      "version": "0.2.11",
+                      "from": "deep-extend@>=0.2.5 <0.3.0",
+                      "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.2.11.tgz"
+                    },
+                    "strip-json-comments": {
+                      "version": "0.1.3",
+                      "from": "strip-json-comments@>=0.1.0 <0.2.0",
+                      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz"
+                    },
+                    "ini": {
+                      "version": "1.3.4",
+                      "from": "ini@>=1.3.0 <1.4.0",
+                      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz"
+                    }
+                  }
+                }
+              }
+            },
+            "os-filter-obj": {
+              "version": "1.0.3",
+              "from": "os-filter-obj@>=1.0.0 <2.0.0",
+              "resolved": "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-1.0.3.tgz"
+            }
+          }
+        },
+        "logalot": {
+          "version": "2.1.0",
+          "from": "logalot@>=2.0.0 <3.0.0",
+          "resolved": "https://registry.npmjs.org/logalot/-/logalot-2.1.0.tgz",
+          "dependencies": {
+            "figures": {
+              "version": "1.4.0",
+              "from": "figures@>=1.3.5 <2.0.0",
+              "resolved": "https://registry.npmjs.org/figures/-/figures-1.4.0.tgz"
+            },
+            "squeak": {
+              "version": "1.3.0",
+              "from": "squeak@>=1.0.0 <2.0.0",
+              "resolved": "https://registry.npmjs.org/squeak/-/squeak-1.3.0.tgz",
+              "dependencies": {
+                "console-stream": {
+                  "version": "0.1.1",
+                  "from": "console-stream@>=0.1.1 <0.2.0",
+                  "resolved": "https://registry.npmjs.org/console-stream/-/console-stream-0.1.1.tgz"
+                },
+                "lpad-align": {
+                  "version": "1.1.0",
+                  "from": "lpad-align@>=1.0.1 <2.0.0",
+                  "resolved": "https://registry.npmjs.org/lpad-align/-/lpad-align-1.1.0.tgz",
+                  "dependencies": {
+                    "lpad": {
+                      "version": "2.0.1",
+                      "from": "lpad@>=2.0.1 <3.0.0",
+                      "resolved": "https://registry.npmjs.org/lpad/-/lpad-2.0.1.tgz"
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "for-in": {
+      "version": "0.1.4",
+      "from": "https://registry.npmjs.org/for-in/-/for-in-0.1.4.tgz",
+      "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.4.tgz"
+    },
+    "for-own": {
+      "version": "0.1.3",
+      "from": "https://registry.npmjs.org/for-own/-/for-own-0.1.3.tgz",
+      "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.3.tgz"
+    },
+    "fs-readdir-recursive": {
+      "version": "0.1.2",
+      "from": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz",
+      "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz"
+    },
+    "fsevents": {
+      "version": "1.0.5",
+      "from": "https://registry.npmjs.org/fsevents/-/fsevents-1.0.5.tgz",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.0.5.tgz",
+      "dependencies": {
+        "node-pre-gyp": {
+          "version": "0.6.15",
+          "from": "node-pre-gyp@latest",
+          "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.6.15.tgz",
+          "dependencies": {
+            "nopt": {
+              "version": "3.0.4",
+              "from": "nopt@>=3.0.1 <3.1.0",
+              "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.4.tgz"
+            }
+          }
+        },
+        "abbrev": {
+          "version": "1.0.7",
+          "from": "abbrev@1",
+          "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz"
+        },
+        "ansi": {
+          "version": "0.3.0",
+          "from": "ansi@~0.3.0",
+          "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.0.tgz"
+        },
+        "ansi-regex": {
+          "version": "2.0.0",
+          "from": "ansi-regex@^2.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
+        },
+        "ansi-styles": {
+          "version": "2.1.0",
+          "from": "ansi-styles@^2.1.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz"
+        },
+        "are-we-there-yet": {
+          "version": "1.0.4",
+          "from": "are-we-there-yet@~1.0.0",
+          "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.4.tgz"
+        },
+        "assert-plus": {
+          "version": "0.1.5",
+          "from": "assert-plus@^0.1.5",
+          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
+        },
+        "asn1": {
+          "version": "0.1.11",
+          "from": "asn1@0.1.11",
+          "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz"
+        },
+        "async": {
+          "version": "1.5.0",
+          "from": "async@^1.4.0",
+          "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz"
+        },
+        "aws-sign2": {
+          "version": "0.6.0",
+          "from": "aws-sign2@~0.6.0",
+          "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
+        },
+        "balanced-match": {
+          "version": "0.2.1",
+          "from": "balanced-match@>=0.2.0 <0.3.0",
+          "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.1.tgz"
+        },
+        "block-stream": {
+          "version": "0.0.8",
+          "from": "block-stream@*",
+          "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.8.tgz"
+        },
+        "brace-expansion": {
+          "version": "1.1.1",
+          "from": "brace-expansion@>=1.0.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.1.tgz"
+        },
+        "boom": {
+          "version": "2.10.1",
+          "from": "boom@^2.8.x",
+          "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz"
+        },
+        "caseless": {
+          "version": "0.11.0",
+          "from": "caseless@~0.11.0",
+          "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
+        },
+        "chalk": {
+          "version": "1.1.1",
+          "from": "chalk@^1.1.1",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz"
+        },
+        "combined-stream": {
+          "version": "1.0.5",
+          "from": "combined-stream@~1.0.5",
+          "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz"
+        },
+        "commander": {
+          "version": "2.9.0",
+          "from": "commander@^2.8.1",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz"
+        },
+        "concat-map": {
+          "version": "0.0.1",
+          "from": "concat-map@0.0.1",
+          "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
+        },
+        "core-util-is": {
+          "version": "1.0.1",
+          "from": "core-util-is@~1.0.0",
+          "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
+        },
+        "ctype": {
+          "version": "0.5.3",
+          "from": "ctype@0.5.3",
+          "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz"
+        },
+        "cryptiles": {
+          "version": "2.0.5",
+          "from": "cryptiles@2.x.x",
+          "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz"
+        },
+        "debug": {
+          "version": "0.7.4",
+          "from": "debug@~0.7.2",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz"
+        },
+        "deep-extend": {
+          "version": "0.2.11",
+          "from": "deep-extend@~0.2.5",
+          "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.2.11.tgz"
+        },
+        "delayed-stream": {
+          "version": "1.0.0",
+          "from": "delayed-stream@~1.0.0",
+          "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
+        },
+        "delegates": {
+          "version": "0.1.0",
+          "from": "delegates@^0.1.0",
+          "resolved": "https://registry.npmjs.org/delegates/-/delegates-0.1.0.tgz"
+        },
+        "escape-string-regexp": {
+          "version": "1.0.3",
+          "from": "escape-string-regexp@^1.0.2",
+          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz"
+        },
+        "extend": {
+          "version": "3.0.0",
+          "from": "extend@~3.0.0",
+          "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz"
+        },
+        "forever-agent": {
+          "version": "0.6.1",
+          "from": "forever-agent@~0.6.1",
+          "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz"
+        },
+        "form-data": {
+          "version": "1.0.0-rc3",
+          "from": "form-data@~1.0.0-rc3",
+          "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.0-rc3.tgz"
+        },
+        "fstream": {
+          "version": "1.0.8",
+          "from": "fstream@^1.0.2",
+          "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.8.tgz"
+        },
+        "gauge": {
+          "version": "1.2.2",
+          "from": "gauge@~1.2.0",
+          "resolved": "https://registry.npmjs.org/gauge/-/gauge-1.2.2.tgz"
+        },
+        "generate-function": {
+          "version": "2.0.0",
+          "from": "generate-function@^2.0.0",
+          "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz"
+        },
+        "generate-object-property": {
+          "version": "1.2.0",
+          "from": "generate-object-property@^1.1.0",
+          "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz"
+        },
+        "graceful-fs": {
+          "version": "4.1.2",
+          "from": "graceful-fs@4.1",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.2.tgz"
+        },
+        "graceful-readlink": {
+          "version": "1.0.1",
+          "from": "graceful-readlink@>= 1.0.0",
+          "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
+        },
+        "har-validator": {
+          "version": "2.0.2",
+          "from": "har-validator@~2.0.2",
+          "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.2.tgz"
+        },
+        "has-ansi": {
+          "version": "2.0.0",
+          "from": "has-ansi@^2.0.0",
+          "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
+        },
+        "has-unicode": {
+          "version": "1.0.1",
+          "from": "has-unicode@^1.0.0",
+          "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-1.0.1.tgz"
+        },
+        "hawk": {
+          "version": "3.1.0",
+          "from": "hawk@~3.1.0",
+          "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.0.tgz"
+        },
+        "hoek": {
+          "version": "2.16.3",
+          "from": "hoek@2.x.x",
+          "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz"
+        },
+        "http-signature": {
+          "version": "0.11.0",
+          "from": "http-signature@~0.11.0",
+          "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.11.0.tgz"
+        },
+        "inherits": {
+          "version": "2.0.1",
+          "from": "inherits@*",
+          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
+        },
+        "ini": {
+          "version": "1.3.4",
+          "from": "ini@~1.3.0",
+          "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz"
+        },
         "is-my-json-valid": {
           "version": "2.12.2",
           "from": "is-my-json-valid@^2.12.2",
@@ -2142,16 +3423,16 @@
           "from": "jsonpointer@2.0.0",
           "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz"
         },
-        "lodash._basetostring": {
-          "version": "3.0.1",
-          "from": "lodash._basetostring@^3.0.0",
-          "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz"
-        },
         "lodash._createpadding": {
           "version": "3.6.1",
           "from": "lodash._createpadding@^3.0.0",
           "resolved": "https://registry.npmjs.org/lodash._createpadding/-/lodash._createpadding-3.6.1.tgz"
         },
+        "lodash._basetostring": {
+          "version": "3.0.1",
+          "from": "lodash._basetostring@^3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz"
+        },
         "lodash.pad": {
           "version": "3.1.1",
           "from": "lodash.pad@^3.0.0",
diff --git a/package.json b/package.json
index 4884bdcda808..34a0d874f0d9 100644
--- a/package.json
+++ b/package.json
@@ -30,7 +30,10 @@
         "parse",
         "react-transform-hmr"
       ],
-      "platforms": ["ios", "android"]
+      "platforms": [
+        "ios",
+        "android"
+      ]
     },
     "modulePathIgnorePatterns": [
       "/node_modules/(?!react|fbjs|react-native|parse|react-transform-hmr|core-js|promise)/",
@@ -113,6 +116,7 @@
   ],
   "scripts": {
     "test": "NODE_ENV=test jest",
+    "flow": "flow",
     "lint": "eslint Examples/ Libraries/",
     "start": "/usr/bin/env bash -c './packager/packager.sh \"$@\" || true' --"
   },
@@ -175,10 +179,11 @@
     "yeoman-generator": "^0.20.3"
   },
   "devDependencies": {
+    "babel-eslint": "^5.0.0",
+    "eslint": "^2.2.0",
+    "eslint-plugin-react": "^4.1.0",
+    "flow-bin": "^0.21.0",
     "jest-cli": "0.9.0-fb2",
-    "babel-eslint": "4.1.4",
-    "eslint": "1.3.1",
-    "eslint-plugin-react": "3.3.1",
     "portfinder": "0.4.0"
   }
 }

From 5ffeb9764c72def0f771c714b3f2143dc000f1ee Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Thu, 3 Mar 2016 04:20:34 -0800
Subject: [PATCH 1394/1411] Back out of D3000972

Reviewed By: dmmiller

Differential Revision: D3003211

fb-gh-sync-id: e64f1f17dcbf19a32066de91d6e839d59cd5d27c
shipit-source-id: e64f1f17dcbf19a32066de91d6e839d59cd5d27c
---
 .../NavigationAnimatedExample.js              |  19 +-
 .../NavigationBasicExample.js                 |   3 +-
 .../NavigationCompositionExample.js           |  15 +-
 .../NavigationExampleRow.js                   |   3 +-
 Examples/UIExplorer/UIExplorerList.android.js |   2 -
 .../NavigationHeader.js                       | 286 ++++++------------
 .../NavigationHeaderBackButton.js             |  59 ----
 .../NavigationHeaderTitle.js                  |  74 -----
 .../assets/back-icon@1.5x.android.png         | Bin 134 -> 0 bytes
 .../assets/back-icon@1.5x.ios.png             | Bin 273 -> 0 bytes
 .../assets/back-icon@1x.android.png           | Bin 100 -> 0 bytes
 .../assets/back-icon@1x.ios.png               | Bin 177 -> 0 bytes
 .../assets/back-icon@2x.android.png           | Bin 134 -> 0 bytes
 .../assets/back-icon@2x.ios.png               | Bin 303 -> 0 bytes
 .../assets/back-icon@3x.android.png           | Bin 167 -> 0 bytes
 .../assets/back-icon@3x.ios.png               | Bin 439 -> 0 bytes
 .../assets/back-icon@4x.android.png           | Bin 207 -> 0 bytes
 .../assets/back-icon@4x.ios.png               | Bin 586 -> 0 bytes
 .../NavigationExperimental/back_chevron.png   | Bin 0 -> 575 bytes
 .../NavigationAnimatedView.js                 |  19 +-
 .../NavigationExperimental.js                 |   4 -
 .../NavigationStateUtils.js                   |   6 -
 22 files changed, 117 insertions(+), 373 deletions(-)
 delete mode 100644 Libraries/CustomComponents/NavigationExperimental/NavigationHeaderBackButton.js
 delete mode 100644 Libraries/CustomComponents/NavigationExperimental/NavigationHeaderTitle.js
 delete mode 100644 Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1.5x.android.png
 delete mode 100644 Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1.5x.ios.png
 delete mode 100644 Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1x.android.png
 delete mode 100644 Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1x.ios.png
 delete mode 100644 Libraries/CustomComponents/NavigationExperimental/assets/back-icon@2x.android.png
 delete mode 100644 Libraries/CustomComponents/NavigationExperimental/assets/back-icon@2x.ios.png
 delete mode 100644 Libraries/CustomComponents/NavigationExperimental/assets/back-icon@3x.android.png
 delete mode 100644 Libraries/CustomComponents/NavigationExperimental/assets/back-icon@3x.ios.png
 delete mode 100644 Libraries/CustomComponents/NavigationExperimental/assets/back-icon@4x.android.png
 delete mode 100644 Libraries/CustomComponents/NavigationExperimental/assets/back-icon@4x.ios.png
 create mode 100644 Libraries/CustomComponents/NavigationExperimental/back_chevron.png

diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
index 8ef14c56ac83..e74d80e26306 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationAnimatedExample.js
@@ -27,7 +27,6 @@ var {
   RootContainer: NavigationRootContainer,
   Reducer: NavigationReducer,
   Header: NavigationHeader,
-  HeaderTitle: NavigationHeaderTitle,
 } = NavigationExperimental;
 
 const NavigationBasicReducer = NavigationReducer.StackReducer({
@@ -61,6 +60,12 @@ class NavigationAnimatedExample extends React.Component {
       />
     );
   }
+  handleBackAction() {
+    return (
+      this.navRootContainer &&
+      this.navRootContainer.handleNavigation(NavigationRootContainer.getBackAction())
+    );
+  }
   _renderNavigated(navigationState, onNavigate) {
     if (!navigationState) {
       return null;
@@ -69,13 +74,11 @@ class NavigationAnimatedExample extends React.Component {
       <NavigationAnimatedView
         navigationState={navigationState}
         style={styles.animatedView}
-        renderOverlay={(scenes, index, position, layout) => (
+        renderOverlay={(props) => (
           <NavigationHeader
-            scenes={scenes}
-            index={index}
-            position={position}
-            layout={layout}
-            renderTitleComponent={pageState => <NavigationHeaderTitle>{pageState.key}</NavigationHeaderTitle>}
+            navigationState={props.navigationParentState}
+            position={props.position}
+            getTitle={state => state.key}
           />
         )}
         setTiming={(pos, navState) => {
@@ -118,7 +121,7 @@ const styles = StyleSheet.create({
     flex: 1,
   },
   scrollView: {
-    marginTop: NavigationHeader.APPBAR_HEIGHT + NavigationHeader.STATUSBAR_HEIGHT,
+    marginTop: 64
   },
 });
 
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationBasicExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationBasicExample.js
index 8508c047368a..447ab2051fba 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationBasicExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationBasicExample.js
@@ -23,7 +23,6 @@ const NavigationExampleRow = require('./NavigationExampleRow');
 const {
   RootContainer: NavigationRootContainer,
   Reducer: NavigationReducer,
-  Header: NavigationHeader,
 } = NavigationExperimental;
 const StackReducer = NavigationReducer.StackReducer;
 
@@ -94,7 +93,7 @@ const styles = StyleSheet.create({
   topView: {
     backgroundColor: '#E9E9EF',
     flex: 1,
-    paddingTop: NavigationHeader.STATUSBAR_HEIGHT,
+    paddingTop: 30,
   },
 });
 
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js b/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js
index 6a79a5cdc04e..bc1d184db5de 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationCompositionExample.js
@@ -28,7 +28,6 @@ const {
   Container: NavigationContainer,
   RootContainer: NavigationRootContainer,
   Header: NavigationHeader,
-  HeaderTitle: NavigationHeaderTitle,
   Reducer: NavigationReducer,
   View: NavigationView,
 } = NavigationExperimental;
@@ -155,15 +154,13 @@ class ExampleTabScreen extends React.Component {
       />
     );
   }
-
-  _renderHeader(scenes, index, position, layout) {
+  _renderHeader(props) {
     return (
       <NavigationHeader
-        scenes={scenes}
-        index={index}
-        position={position}
-        layout={layout}
-        renderTitleComponent={pageState => <NavigationHeaderTitle>{stateTypeTitleMap(pageState)}</NavigationHeaderTitle>}
+        navigationState={props.navigationParentState}
+        position={props.position}
+        layout={props.layout}
+        getTitle={state => stateTypeTitleMap(state)}
       />
     );
   }
@@ -273,7 +270,7 @@ const styles = StyleSheet.create({
     flex: 1,
   },
   scrollView: {
-    marginTop: NavigationHeader.APPBAR_HEIGHT + NavigationHeader.STATUSBAR_HEIGHT,
+    marginTop: 64
   },
   tabContent: {
     flex: 1,
diff --git a/Examples/UIExplorer/NavigationExperimental/NavigationExampleRow.js b/Examples/UIExplorer/NavigationExperimental/NavigationExampleRow.js
index 9fceec7bc3bc..4e431e30a722 100644
--- a/Examples/UIExplorer/NavigationExperimental/NavigationExampleRow.js
+++ b/Examples/UIExplorer/NavigationExperimental/NavigationExampleRow.js
@@ -16,6 +16,7 @@
 var React = require('react-native');
 var {
   Text,
+  PixelRatio,
   StyleSheet,
   View,
   TouchableHighlight,
@@ -49,7 +50,7 @@ const styles = StyleSheet.create({
   row: {
     padding: 15,
     backgroundColor: 'white',
-    borderBottomWidth: StyleSheet.hairlineWidth,
+    borderBottomWidth: 1 / PixelRatio.get(),
     borderBottomColor: '#CDCDCD',
   },
   rowText: {
diff --git a/Examples/UIExplorer/UIExplorerList.android.js b/Examples/UIExplorer/UIExplorerList.android.js
index a912ae9abf81..68be333e5109 100644
--- a/Examples/UIExplorer/UIExplorerList.android.js
+++ b/Examples/UIExplorer/UIExplorerList.android.js
@@ -15,8 +15,6 @@
  */
 'use strict';
 
-const React = require('react');
-
 export type UIExplorerExample = {
   key: string;
   module: React.Component;
diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationHeader.js b/Libraries/CustomComponents/NavigationExperimental/NavigationHeader.js
index fac681c1a39d..82a807e2f27d 100644
--- a/Libraries/CustomComponents/NavigationExperimental/NavigationHeader.js
+++ b/Libraries/CustomComponents/NavigationExperimental/NavigationHeader.js
@@ -27,227 +27,123 @@
  */
 'use strict';
 
-const React = require('react-native');
+const Animated = require('Animated');
+const Image = require('Image');
 const NavigationContainer = require('NavigationContainer');
-const NavigationHeaderTitle = require('NavigationHeaderTitle');
-const NavigationHeaderBackButton = require('NavigationHeaderBackButton');
-
-const {
-  Animated,
-  Platform,
-  StyleSheet,
-  View,
-} = React;
-
-const APPBAR_HEIGHT = Platform.OS === 'ios' ? 44 : 56;
-const STATUSBAR_HEIGHT = Platform.OS === 'ios' ? 20 : 0;
+const NavigationRootContainer = require('NavigationRootContainer');
+const React = require('react-native');
+const StyleSheet = require('StyleSheet');
+const Text = require('Text');
+const TouchableOpacity = require('TouchableOpacity');
+const View = require('View');
 
 import type {
-  NavigationScene,
+  NavigationState,
+  NavigationParentState
 } from 'NavigationStateUtils';
 
-type Renderer = (scene: NavigationScene) => ReactElement;
-
-type DefaultProps = {
-  renderTitleComponent: Renderer;
-  renderLeftComponent: Renderer;
-};
-
 type Props = {
+  navigationState: NavigationParentState,
+  onNavigate: Function,
   position: Animated.Value,
-  scenes: Array<NavigationScene>;
-  index: number;
-  renderTitleComponent: Renderer;
-  renderLeftComponent: Renderer;
-  renderRightComponent: Renderer;
-  style: any,
+  getTitle: (navState: NavigationState) => string,
 };
 
-class NavigationHeader extends React.Component<DefaultProps, Props, void> {
-  _renderLeftComponent(scene) {
-    const {
-      renderLeftComponent,
-      position,
-    } = this.props;
-
-    if (renderLeftComponent) {
-      const {
-        index,
-        state,
-      } = scene;
-
-      return (
-        <Animated.View
-          pointerEvents={this.props.index === index ? 'auto' : 'none'}
-          key={state.key}
-          style={[
-            styles.left,
-            {
-              opacity: position.interpolate({
-                inputRange: [ index - 1, index, index + 1 ],
-                outputRange: [ 0, 1, 0 ],
-              })
-            }
-          ]}
-        >
-          {renderLeftComponent(state, index)}
-        </Animated.View>
-      );
-    }
-
-    return null;
+class NavigationHeader extends React.Component {
+  _handleBackPress: Function;
+  props: Props;
+  componentWillMount() {
+    this._handleBackPress = this._handleBackPress.bind(this);
   }
-
-  _renderRightComponent(scene) {
-    const {
-      renderRightComponent,
-      position,
-    } = this.props;
-
-    if (renderRightComponent) {
-      const {
-        index,
-        state,
-      } = scene;
-
-      return (
-        <Animated.View
-          pointerEvents={this.props.index === index ? 'auto' : 'none'}
-          key={state.key}
-          style={[
-            styles.right,
-            {
-              opacity: position.interpolate({
-                inputRange: [ index - 1, index, index + 1 ],
-                outputRange: [ 0, 1, 0 ],
-              })
-            }
-          ]}
-        >
-          {renderRightComponent(state, index)}
-        </Animated.View>
-      );
-    }
-
-    return null;
+  render() {
+    var state = this.props.navigationState;
+    return (
+      <Animated.View
+        style={[
+          styles.header,
+        ]}>
+        {state.children.map(this._renderTitle, this)}
+        {this._renderBackButton()}
+      </Animated.View>
+    );
   }
-
-  _renderTitleComponent(scene) {
-    const {
-      renderTitleComponent,
-      position,
-    } = this.props;
-
-    if (renderTitleComponent) {
-      const {
-        index,
-        state,
-      } = scene;
-
-      return (
-        <Animated.View
-          pointerEvents={this.props.index === index ? 'auto' : 'none'}
-          key={state.key}
-          style={[
-            styles.title,
-            {
-              opacity: position.interpolate({
-                inputRange: [ index - 1, index, index + 1 ],
-                outputRange: [ 0, 1, 0 ],
-              }),
-              transform: [
-                {
-                  translateX: position.interpolate({
-                    inputRange: [ index - 1, index + 1 ],
-                    outputRange: [ 200, -200 ],
-                  }),
-                }
-              ],
-            }
-          ]}
-        >
-          {renderTitleComponent(state, index)}
-        </Animated.View>
-      );
+  _renderBackButton() {
+    if (this.props.navigationState.index === 0) {
+      return null;
     }
-
-    return null;
+    return (
+      <TouchableOpacity style={styles.backButton} onPress={this._handleBackPress}>
+        <Image source={require('./back_chevron.png')} style={styles.backButtonImage} />
+      </TouchableOpacity>
+    );
   }
-
-  render() {
-    const { scenes } = this.props;
-
+  _renderTitle(childState, index) {
     return (
-      <View style={[ styles.appbar, this.props.style ]}>
-        {scenes.map(this._renderLeftComponent, this)}
-        {scenes.map(this._renderTitleComponent, this)}
-        {scenes.map(this._renderRightComponent, this)}
-      </View>
+      <Animated.Text
+        key={childState.key}
+        style={[
+          styles.title,
+          {
+            opacity: this.props.position.interpolate({
+              inputRange: [index - 1, index, index + 1],
+              outputRange: [0, 1, 0],
+            }),
+            left: this.props.position.interpolate({
+              inputRange: [index - 1, index + 1],
+              outputRange: [200, -200],
+            }),
+            right: this.props.position.interpolate({
+              inputRange: [index - 1, index + 1],
+              outputRange: [-200, 200],
+            }),
+          },
+        ]}>
+        {this.props.getTitle(childState)}
+      </Animated.Text>
     );
   }
+  _handleBackPress() {
+    this.props.onNavigate(NavigationRootContainer.getBackAction());
+  }
 }
 
-const renderTitleComponent = pageState => <NavigationHeaderTitle>{pageState.title}</NavigationHeaderTitle>;
-const renderLeftComponent = (pageState, index) => index !== 0 ? <NavigationHeaderBackButton /> : null;
-
-NavigationHeader.defaultProps = {
-  renderTitleComponent,
-  renderLeftComponent,
-};
-
-NavigationHeader.propTypes = {
-  position: React.PropTypes.object.isRequired,
-  scenes: React.PropTypes.arrayOf(React.PropTypes.shape({
-    index: React.PropTypes.number,
-    state: React.PropTypes.any,
-  })).isRequired,
-  index: React.PropTypes.number.isRequired,
-  renderTitleComponent: React.PropTypes.func,
-  renderLeftComponent: React.PropTypes.func,
-  renderRightComponent: React.PropTypes.func,
-  style: View.propTypes.style,
-};
-
-NavigationHeader.APPBAR_HEIGHT = APPBAR_HEIGHT;
-NavigationHeader.STATUSBAR_HEIGHT = STATUSBAR_HEIGHT;
+NavigationHeader = NavigationContainer.create(NavigationHeader);
 
 const styles = StyleSheet.create({
-  appbar: {
-    flexDirection: 'row',
-    alignItems: 'center',
-    justifyContent: 'flex-start',
-    backgroundColor: Platform.OS === 'ios' ? 'rgba(255, 255, 255, .9)' : 'rgba(255, 255, 255, 1)',
-    borderBottomWidth: Platform.OS === 'ios' ? StyleSheet.hairlineWidth : 0,
-    borderBottomColor: 'rgba(0, 0, 0, .15)',
-    height: APPBAR_HEIGHT + STATUSBAR_HEIGHT,
-    marginBottom: 16, // This is needed for elevation shadow
-    elevation: 2,
-  },
-
   title: {
+    textAlign: 'center',
+    marginTop: 10,
+    fontSize: 18,
+    fontWeight: '500',
+    color: '#0A0A0A',
     position: 'absolute',
-    top: 0,
-    bottom: 0,
-    left: APPBAR_HEIGHT,
-    right: APPBAR_HEIGHT,
-    marginTop: STATUSBAR_HEIGHT,
+    top: 20,
+    left: 0,
+    right: 0,
   },
-
-  left: {
-    position: 'absolute',
+  header: {
+    backgroundColor: '#EFEFF2',
+    paddingTop: 20,
     top: 0,
-    bottom: 0,
+    height: 64,
+    right: 0,
     left: 0,
-    marginTop: STATUSBAR_HEIGHT,
+    borderBottomWidth: 0.5,
+    borderBottomColor: '#828287',
+    position: 'absolute',
   },
-
-  right: {
+  backButton: {
+    width: 29,
+    height: 37,
     position: 'absolute',
-    top: 0,
-    bottom: 0,
-    right: 0,
-    marginTop: STATUSBAR_HEIGHT,
-  }
+    bottom: 4,
+    left: 2,
+    padding: 8,
+  },
+  backButtonImage: {
+    width: 13,
+    height: 21,
+  },
 });
 
-module.exports = NavigationContainer.create(NavigationHeader);
+module.exports = NavigationHeader;
diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationHeaderBackButton.js b/Libraries/CustomComponents/NavigationExperimental/NavigationHeaderBackButton.js
deleted file mode 100644
index 4cd4a867676c..000000000000
--- a/Libraries/CustomComponents/NavigationExperimental/NavigationHeaderBackButton.js
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * The examples provided by Facebook are for non-commercial testing and
- * evaluation purposes only.
- *
- * Facebook reserves all rights not expressly granted.
- *
- * 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 NON INFRINGEMENT. IN NO EVENT SHALL
- * FACEBOOK 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 NavigationHeaderBackButton
- * @flow
-*/
-'use strict';
-
-const React = require('react-native');
-const NavigationContainer = require('NavigationContainer');
-const NavigationRootContainer = require('NavigationRootContainer');
-
-const {
-  Image,
-  Platform,
-  StyleSheet,
-  TouchableOpacity,
-} = React;
-
-type Props = {
-  onNavigate: Function
-}
-
-const NavigationHeaderBackButton = (props: Props) => (
-  <TouchableOpacity style={styles.buttonContainer} onPress={() => props.onNavigate(NavigationRootContainer.getBackAction())}>
-    <Image style={styles.button} source={require('./assets/back-icon.png')} />
-  </TouchableOpacity>
-);
-
-NavigationHeaderBackButton.propTypes = {
-  onNavigate: React.PropTypes.func.isRequired
-};
-
-const styles = StyleSheet.create({
-  buttonContainer: {
-    flex: 1,
-    flexDirection: 'row',
-    alignItems: 'center',
-    justifyContent: 'center',
-  },
-  button: {
-    height: 24,
-    width: 24,
-    margin: Platform.OS === 'ios' ? 10 : 16,
-    resizeMode: 'contain'
-  }
-});
-
-module.exports = NavigationContainer.create(NavigationHeaderBackButton);
diff --git a/Libraries/CustomComponents/NavigationExperimental/NavigationHeaderTitle.js b/Libraries/CustomComponents/NavigationExperimental/NavigationHeaderTitle.js
deleted file mode 100644
index 94fd4c00a8d4..000000000000
--- a/Libraries/CustomComponents/NavigationExperimental/NavigationHeaderTitle.js
+++ /dev/null
@@ -1,74 +0,0 @@
-/**
- * Copyright (c) 2015, Facebook, Inc.  All rights reserved.
- *
- * Facebook, Inc. ("Facebook") owns all right, title and interest, including
- * all intellectual property and other proprietary rights, in and to the React
- * Native CustomComponents software (the "Software").  Subject to your
- * compliance with these terms, you are hereby granted a non-exclusive,
- * worldwide, royalty-free copyright license to (1) use and copy the Software;
- * and (2) reproduce and distribute the Software as part of your own software
- * ("Your Software").  Facebook reserves all rights not expressly granted to
- * you in this license agreement.
- *
- * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "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 FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
- * EMPLOYEES 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 THE SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * @providesModule NavigationHeaderTitle
- * @flow
- */
-'use strict';
-
-const React = require('react-native');
-
-const {
-  Platform,
-  StyleSheet,
-  View,
-  Text,
-} = React;
-
-type Props = {
-  children: ReactElement;
-  style: any;
-  textStyle: any;
-}
-
-const NavigationHeaderTitle = ({ children, style, textStyle }: Props) => (
-  <View style={[ styles.title, style ]}>
-    <Text style={[ styles.titleText, textStyle ]}>{children}</Text>
-  </View>
-);
-
-const styles = StyleSheet.create({
-  title: {
-    flex: 1,
-    flexDirection: 'row',
-    alignItems: 'center',
-    marginHorizontal: 16
-  },
-
-  titleText: {
-    flex: 1,
-    fontSize: 18,
-    fontWeight: '500',
-    color: 'rgba(0, 0, 0, .9)',
-    textAlign: Platform.OS === 'ios' ? 'center' : 'left'
-  }
-});
-
-NavigationHeaderTitle.propTypes = {
-  children: React.PropTypes.string.isRequired,
-  style: View.propTypes.style,
-  textStyle: Text.propTypes.style
-};
-
-module.exports = NavigationHeaderTitle;
diff --git a/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1.5x.android.png b/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1.5x.android.png
deleted file mode 100644
index ad03a63bf3caba175695f5acca85a690dda2d02c..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1.5x.ios.png b/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1.5x.ios.png
deleted file mode 100644
index e43fa0622f1994f253465b85a59cabc490f25254..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1x.android.png b/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1x.android.png
deleted file mode 100644
index 083db295f474b9903408258c71818c2c49151d35..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1x.ios.png b/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@1x.ios.png
deleted file mode 100644
index 4244656b92fb7078e26e9387bc79092e40e32134..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@2x.android.png b/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@2x.android.png
deleted file mode 100644
index 6de0a1cbb365dfd5d9274890d243ca2321f32235..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@2x.ios.png b/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@2x.ios.png
deleted file mode 100644
index a8b6e9a63e5954e88cdc2c4b376350f0d00df554..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@3x.android.png b/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@3x.android.png
deleted file mode 100644
index 15a983a67d97c9a6c39d91550a528c37c53a9e3e..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@3x.ios.png b/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@3x.ios.png
deleted file mode 100644
index 07ea37b4e1e252d9a406eb33af2efe80e8612330..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@4x.android.png b/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@4x.android.png
deleted file mode 100644
index 17e52e8550e5668f7117bcb755beb70c3a21c9e9..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@4x.ios.png b/Libraries/CustomComponents/NavigationExperimental/assets/back-icon@4x.ios.png
deleted file mode 100644
index 7899053f61b38b1b3f3e4400d208265e5b9752cf..0000000000000000000000000000000000000000
GIT binary patch
diff --git a/Libraries/CustomComponents/NavigationExperimental/back_chevron.png b/Libraries/CustomComponents/NavigationExperimental/back_chevron.png
new file mode 100644
index 0000000000000000000000000000000000000000..af21cf9d5718b71d1d2be0c445fa7f6012813609
GIT binary patch
diff --git a/Libraries/NavigationExperimental/NavigationAnimatedView.js b/Libraries/NavigationExperimental/NavigationAnimatedView.js
index 918307210311..4d1f5b68f16e 100644
--- a/Libraries/NavigationExperimental/NavigationAnimatedView.js
+++ b/Libraries/NavigationExperimental/NavigationAnimatedView.js
@@ -21,9 +21,14 @@ var View = require('View');
 import type {
   NavigationState,
   NavigationParentState,
-  NavigationScene,
 } from 'NavigationStateUtils';
 
+type NavigationScene = {
+  index: number,
+  state: NavigationState,
+  isStale: boolean,
+};
+
 /**
  * Helper function to compare route keys (e.g. "9", "11").
  */
@@ -65,13 +70,6 @@ type Layout = {
   height: Animated.Value;
 };
 
-type OverlayRenderer = (
-  scenes: Array<NavigationScene>,
-  index: number,
-  position: Animated.Value,
-  layout: Layout
-) => ReactElement;
-
 type Position = Animated.Value;
 
 /**
@@ -253,11 +251,6 @@ class NavigationAnimatedView extends React.Component {
   }
 }
 
-NavigationAnimatedView.propTypes = {
-  navigationState: React.PropTypes.instanceOf(NavigationStateUtils),
-  style: View.propTypes.style,
-};
-
 function setDefaultTiming(position, navigationState) {
   Animated.spring(
     position,
diff --git a/Libraries/NavigationExperimental/NavigationExperimental.js b/Libraries/NavigationExperimental/NavigationExperimental.js
index 0f4e9fa63c4e..ca6bb627d559 100644
--- a/Libraries/NavigationExperimental/NavigationExperimental.js
+++ b/Libraries/NavigationExperimental/NavigationExperimental.js
@@ -16,8 +16,6 @@ const NavigationCard = require('NavigationCard');
 const NavigationCardStack = require('NavigationCardStack');
 const NavigationContainer = require('NavigationContainer');
 const NavigationHeader = require('NavigationHeader');
-const NavigationHeaderTitle = require('NavigationHeaderTitle');
-const NavigationHeaderBackButton = require('NavigationHeaderBackButton');
 const NavigationLegacyNavigator = require('NavigationLegacyNavigator');
 const NavigationReducer = require('NavigationReducer');
 const NavigationRootContainer = require('NavigationRootContainer');
@@ -41,8 +39,6 @@ const NavigationExperimental = {
   Card: NavigationCard,
   CardStack: NavigationCardStack,
   Header: NavigationHeader,
-  HeaderTitle: NavigationHeaderTitle,
-  HeaderBackButton: NavigationHeaderBackButton,
   LegacyNavigator: NavigationLegacyNavigator,
 };
 
diff --git a/Libraries/NavigationExperimental/NavigationStateUtils.js b/Libraries/NavigationExperimental/NavigationStateUtils.js
index 28d5c85bd3ac..d457ebea8ada 100644
--- a/Libraries/NavigationExperimental/NavigationStateUtils.js
+++ b/Libraries/NavigationExperimental/NavigationStateUtils.js
@@ -23,12 +23,6 @@ export type NavigationParentState = {
   children: Array<NavigationState>;
 };
 
-export type NavigationScene = {
-  index: number;
-  state: NavigationState;
-  isStale: boolean;
-};
-
 export type NavigationAction = {
   type: string;
 };

From 39409dda2de179a3e051461209fd24ab8d262754 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Thu, 3 Mar 2016 05:40:00 -0800
Subject: [PATCH 1395/1411] another fix

Summary:quick fix to get CI stable
Closes https://github.com/facebook/react-native/pull/6271

Differential Revision: D3005703

fb-gh-sync-id: 88941f2bb058d65637a06a3710108cdf131c3bda
shipit-source-id: 88941f2bb058d65637a06a3710108cdf131c3bda
---
 scripts/e2e-test.sh | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/scripts/e2e-test.sh b/scripts/e2e-test.sh
index 5cfdc65cf0bf..dc90ceb589d3 100755
--- a/scripts/e2e-test.sh
+++ b/scripts/e2e-test.sh
@@ -68,7 +68,8 @@ cd EndToEndTest/ios
 # Make sure we installed local version of react-native
 ls EndToEndTest/`basename $MARKER` > /dev/null
 
-flow --retries 10
+# disabling temporarily, flow is not isntalled globally anymore
+# npm run flow --retries 10
 
 ../node_modules/react-native/packager/packager.sh --nonPersistent &
 SERVER_PID=$!

From 32dd1fe35a59e8b2e3d75fb9164477d81fcb6c0d Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Thu, 3 Mar 2016 07:29:31 -0800
Subject: [PATCH 1396/1411] fixed instrumentation tests crashes in emulator

Summary:Improving CircleCI stability running tests
Closes https://github.com/facebook/react-native/pull/6270

Differential Revision: D3005903

fb-gh-sync-id: 3421546a19b20db5485b3f816e2c6008e8121749
shipit-source-id: 3421546a19b20db5485b3f816e2c6008e8121749
---
 ReactAndroid/src/androidTest/AndroidManifest.xml             | 3 ++-
 ReactAndroid/src/androidTest/buck-runner/AndroidManifest.xml | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/androidTest/AndroidManifest.xml b/ReactAndroid/src/androidTest/AndroidManifest.xml
index f23091978dfa..f6ce0fa0511c 100644
--- a/ReactAndroid/src/androidTest/AndroidManifest.xml
+++ b/ReactAndroid/src/androidTest/AndroidManifest.xml
@@ -10,7 +10,8 @@
   <!-- needed for screenshot tests -->
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
-  <application>
+  <application
+    android:hardwareAccelerated="false">
     <activity
       android:name="com.facebook.react.testing.ReactAppTestActivity"
       android:theme="@style/Theme.ReactNative.AppCompat.Light.NoActionBar.FullScreen"
diff --git a/ReactAndroid/src/androidTest/buck-runner/AndroidManifest.xml b/ReactAndroid/src/androidTest/buck-runner/AndroidManifest.xml
index 8220d4fb478c..8fd01fc76607 100644
--- a/ReactAndroid/src/androidTest/buck-runner/AndroidManifest.xml
+++ b/ReactAndroid/src/androidTest/buck-runner/AndroidManifest.xml
@@ -8,7 +8,8 @@
   <!-- needed for screenshot tests -->
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
-  <application>
+  <application
+    android:hardwareAccelerated="false">
     <uses-library android:name="android.test.runner" />
     <activity
       android:name="com.facebook.react.testing.ReactAppTestActivity"

From 7fb33032f66df1b2b88b19441374e089a45da676 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Thu, 3 Mar 2016 07:51:51 -0800
Subject: [PATCH 1397/1411] Copy weak reference to callback object when
 dispatching calls to Java

Summary: The bridge could be destructed, meaning we can't try to resolve member variables of PlatformBridgeCallback.

Reviewed By: lexs

Differential Revision: D3005994

fb-gh-sync-id: f83de432148ce62fd1060c6b84ec39ad2fa10a55
shipit-source-id: f83de432148ce62fd1060c6b84ec39ad2fa10a55
---
 ReactAndroid/src/main/jni/react/jni/OnLoad.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
index eeef4d6fe67d..4748d825c89a 100644
--- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
+++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp
@@ -629,13 +629,13 @@ class PlatformBridgeCallback : public BridgeCallback {
       return;
     }
 
-    auto runnableWrapper = std::bind([this] (std::function<void(ResolvedWeakReference&)>& runnable) {
+    auto runnableWrapper = std::bind([weakCallback=weakCallback_] (std::function<void(ResolvedWeakReference&)>& runnable) {
       auto env = Environment::current();
       if (env->ExceptionCheck()) {
         FBLOGW("Dropped calls because of pending exception");
         return;
       }
-      ResolvedWeakReference callback(weakCallback_);
+      ResolvedWeakReference callback(weakCallback);
       if (callback) {
         runnable(callback);
       }

From 39b399e77bfea617f7b2e51ea5b2b56e73569e25 Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Thu, 3 Mar 2016 07:59:49 -0800
Subject: [PATCH 1398/1411] returned flow check to e2e test

Summary:e2e improvement
Closes https://github.com/facebook/react-native/pull/6274

Differential Revision: D3005954

fb-gh-sync-id: 6bd640b78e46f79bb2aaaa900aa8ec78cab04fb3
shipit-source-id: 6bd640b78e46f79bb2aaaa900aa8ec78cab04fb3
---
 scripts/e2e-test.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/scripts/e2e-test.sh b/scripts/e2e-test.sh
index dc90ceb589d3..b3b418c9e7e2 100755
--- a/scripts/e2e-test.sh
+++ b/scripts/e2e-test.sh
@@ -68,8 +68,8 @@ cd EndToEndTest/ios
 # Make sure we installed local version of react-native
 ls EndToEndTest/`basename $MARKER` > /dev/null
 
-# disabling temporarily, flow is not isntalled globally anymore
-# npm run flow --retries 10
+npm install --g flow-bin@0.21.0
+flow --retries 10
 
 ../node_modules/react-native/packager/packager.sh --nonPersistent &
 SERVER_PID=$!

From e4766b79797119015caa68f0641645829fbd9591 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Thu, 3 Mar 2016 08:50:52 -0800
Subject: [PATCH 1399/1411] WebWorkers: Update Timing module to support web
 workers

Summary: Example of a conversion to web worker support using the ExecutionContext API changes made in the last set of web worker diffs. WebWorkerSample now creates timers to show that we can dispatch timer calls to multiple JS contexts.

Reviewed By: lexs

Differential Revision: D2928657

fb-gh-sync-id: 17c5f8cd7c63624da43383da7c4160dc48482fe5
shipit-source-id: 17c5f8cd7c63624da43383da7c4160dc48482fe5
---
 .../react/modules/core/JSTimersExecution.java |  2 +
 .../facebook/react/modules/core/Timing.java   | 74 ++++++++++++++-----
 .../modules/timing/TimingModuleTest.java      | 15 ++--
 3 files changed, 68 insertions(+), 23 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/JSTimersExecution.java b/ReactAndroid/src/main/java/com/facebook/react/modules/core/JSTimersExecution.java
index 67f5ca2312f1..9e0ba2a3d728 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/core/JSTimersExecution.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/core/JSTimersExecution.java
@@ -10,8 +10,10 @@
 package com.facebook.react.modules.core;
 
 import com.facebook.react.bridge.JavaScriptModule;
+import com.facebook.react.bridge.SupportsWebWorkers;
 import com.facebook.react.bridge.WritableArray;
 
+@SupportsWebWorkers
 public interface JSTimersExecution extends JavaScriptModule {
 
   public void callTimers(WritableArray timerIDs);
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java b/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java
index 36954a125f86..b0bf332da5ea 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/core/Timing.java
@@ -12,6 +12,8 @@
 import javax.annotation.Nullable;
 
 import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.PriorityQueue;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -20,7 +22,9 @@
 
 import com.facebook.infer.annotation.Assertions;
 import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.ExecutorToken;
 import com.facebook.react.bridge.LifecycleEventListener;
+import com.facebook.react.bridge.OnExecutorUnregisteredListener;
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.ReactContextBaseJavaModule;
 import com.facebook.react.bridge.ReactMethod;
@@ -31,16 +35,24 @@
 /**
  * Native module for JS timer execution. Timers fire on frame boundaries.
  */
-public final class Timing extends ReactContextBaseJavaModule implements LifecycleEventListener {
+public final class Timing extends ReactContextBaseJavaModule implements LifecycleEventListener,
+  OnExecutorUnregisteredListener {
 
   private static class Timer {
 
+    private final ExecutorToken mExecutorToken;
     private final int mCallbackID;
     private final boolean mRepeat;
     private final int mInterval;
     private long mTargetTime;
 
-    private Timer(int callbackID, long initialTargetTime, int duration, boolean repeat) {
+    private Timer(
+        ExecutorToken executorToken,
+        int callbackID,
+        long initialTargetTime,
+        int duration,
+        boolean repeat) {
+      mExecutorToken = executorToken;
       mCallbackID = callbackID;
       mTargetTime = initialTargetTime;
       mInterval = duration;
@@ -50,6 +62,9 @@ private Timer(int callbackID, long initialTargetTime, int duration, boolean repe
 
   private class FrameCallback implements Choreographer.FrameCallback {
 
+    // Temporary map for constructing the individual arrays of timers per ExecutorToken
+    private final HashMap<ExecutorToken, WritableArray> mTimersToCall = new HashMap<>();
+
     /**
      * Calls all timers that have expired since the last time this frame callback was called.
      */
@@ -60,14 +75,15 @@ public void doFrame(long frameTimeNanos) {
       }
 
       long frameTimeMillis = frameTimeNanos / 1000000;
-      WritableArray timersToCall = null;
       synchronized (mTimerGuard) {
         while (!mTimers.isEmpty() && mTimers.peek().mTargetTime < frameTimeMillis) {
           Timer timer = mTimers.poll();
-          if (timersToCall == null) {
-            timersToCall = Arguments.createArray();
+          WritableArray timersForContext = mTimersToCall.get(timer.mExecutorToken);
+          if (timersForContext == null) {
+            timersForContext = Arguments.createArray();
+            mTimersToCall.put(timer.mExecutorToken, timersForContext);
           }
-          timersToCall.pushInt(timer.mCallbackID);
+          timersForContext.pushInt(timer.mCallbackID);
           if (timer.mRepeat) {
             timer.mTargetTime = frameTimeMillis + timer.mInterval;
             mTimers.add(timer);
@@ -77,9 +93,11 @@ public void doFrame(long frameTimeNanos) {
         }
       }
 
-      if (timersToCall != null) {
-        Assertions.assertNotNull(mJSTimersModule).callTimers(timersToCall);
+      for (Map.Entry<ExecutorToken, WritableArray> entry : mTimersToCall.entrySet()) {
+        getReactApplicationContext().getJSModule(entry.getKey(), JSTimersExecution.class)
+            .callTimers(entry.getValue());
       }
+      mTimersToCall.clear();
 
       Assertions.assertNotNull(mReactChoreographer)
           .postFrameCallback(ReactChoreographer.CallbackType.TIMERS_EVENTS, this);
@@ -88,11 +106,10 @@ public void doFrame(long frameTimeNanos) {
 
   private final Object mTimerGuard = new Object();
   private final PriorityQueue<Timer> mTimers;
-  private final SparseArray<Timer> mTimerIdsToTimers;
+  private final HashMap<ExecutorToken, SparseArray<Timer>> mTimerIdsToTimers;
   private final AtomicBoolean isPaused = new AtomicBoolean(true);
   private final FrameCallback mFrameCallback = new FrameCallback();
   private @Nullable ReactChoreographer mReactChoreographer;
-  private @Nullable JSTimersExecution mJSTimersModule;
   private boolean mFrameCallbackPosted = false;
 
   public Timing(ReactApplicationContext reactContext) {
@@ -113,15 +130,13 @@ public int compare(Timer lhs, Timer rhs) {
             }
           }
         });
-    mTimerIdsToTimers = new SparseArray<Timer>();
+    mTimerIdsToTimers = new HashMap<>();
   }
 
   @Override
   public void initialize() {
     // Safe to acquire choreographer here, as initialize() is invoked from UI thread.
     mReactChoreographer = ReactChoreographer.getInstance();
-    mJSTimersModule = getReactApplicationContext().getCatalystInstance()
-        .getJSModule(JSTimersExecution.class);
     getReactApplicationContext().addLifecycleEventListener(this);
   }
 
@@ -172,8 +187,28 @@ public String getName() {
     return "RKTiming";
   }
 
+  @Override
+  public boolean supportsWebWorkers() {
+    return true;
+  }
+
+  @Override
+  public void onExecutorDestroyed(ExecutorToken executorToken) {
+    synchronized (mTimerGuard) {
+      SparseArray<Timer> timersForContext = mTimerIdsToTimers.remove(executorToken);
+      if (timersForContext == null) {
+        return;
+      }
+      for (int i = 0; i < timersForContext.size(); i++) {
+        Timer timer = timersForContext.get(timersForContext.keyAt(i));
+        mTimers.remove(timer);
+      }
+    }
+  }
+
   @ReactMethod
   public void createTimer(
+      ExecutorToken executorToken,
       final int callbackID,
       final int duration,
       final double jsSchedulingTime,
@@ -183,17 +218,22 @@ public void createTimer(
         0,
         jsSchedulingTime - SystemClock.currentTimeMillis() + duration);
     long initialTargetTime = SystemClock.nanoTime() / 1000000 + adjustedDuration;
-    Timer timer = new Timer(callbackID, initialTargetTime, duration, repeat);
+    Timer timer = new Timer(executorToken, callbackID, initialTargetTime, duration, repeat);
     synchronized (mTimerGuard) {
       mTimers.add(timer);
-      mTimerIdsToTimers.put(callbackID, timer);
+      SparseArray<Timer> timersForContext = mTimerIdsToTimers.get(executorToken);
+      if (timersForContext == null) {
+        timersForContext = new SparseArray<>();
+        mTimerIdsToTimers.put(executorToken, timersForContext);
+      }
+      timersForContext.put(callbackID, timer);
     }
   }
 
   @ReactMethod
-  public void deleteTimer(int timerId) {
+  public void deleteTimer(ExecutorToken executorToken, int timerId) {
     synchronized (mTimerGuard) {
-      Timer timer = mTimerIdsToTimers.get(timerId);
+      Timer timer = mTimerIdsToTimers.get(executorToken).get(timerId);
       if (timer != null) {
         // We may have already called/removed it
         mTimerIdsToTimers.remove(timerId);
diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java
index 423480cda275..1597d84e3641 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java
@@ -12,6 +12,7 @@
 import android.view.Choreographer;
 
 import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.ExecutorToken;
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.CatalystInstance;
 import com.facebook.react.bridge.JavaOnlyArray;
@@ -54,6 +55,7 @@ public class TimingModuleTest {
   private PostFrameCallbackHandler mPostFrameCallbackHandler;
   private long mCurrentTimeNs;
   private JSTimersExecution mJSTimersMock;
+  private ExecutorToken mExecutorTokenMock;
 
   @Rule
   public PowerMockRule rule = new PowerMockRule();
@@ -92,7 +94,8 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
 
     mTiming = new Timing(reactContext);
     mJSTimersMock = mock(JSTimersExecution.class);
-    when(reactInstance.getJSModule(JSTimersExecution.class)).thenReturn(mJSTimersMock);
+    mExecutorTokenMock = mock(ExecutorToken.class);
+    when(reactContext.getJSModule(mExecutorTokenMock, JSTimersExecution.class)).thenReturn(mJSTimersMock);
     mTiming.initialize();
   }
 
@@ -107,7 +110,7 @@ private void stepChoreographerFrame() {
   @Test
   public void testSimpleTimer() {
     mTiming.onHostResume();
-    mTiming.createTimer(1, 0, 0, false);
+    mTiming.createTimer(mExecutorTokenMock, 1, 0, 0, false);
     stepChoreographerFrame();
     verify(mJSTimersMock).callTimers(JavaOnlyArray.of(1));
     reset(mJSTimersMock);
@@ -117,7 +120,7 @@ public void testSimpleTimer() {
 
   @Test
   public void testSimpleRecurringTimer() {
-    mTiming.createTimer(100, 0, 0, true);
+    mTiming.createTimer(mExecutorTokenMock, 100, 0, 0, true);
     mTiming.onHostResume();
     stepChoreographerFrame();
     verify(mJSTimersMock).callTimers(JavaOnlyArray.of(100));
@@ -130,13 +133,13 @@ public void testSimpleRecurringTimer() {
   @Test
   public void testCancelRecurringTimer() {
     mTiming.onHostResume();
-    mTiming.createTimer(105, 0, 0, true);
+    mTiming.createTimer(mExecutorTokenMock, 105, 0, 0, true);
 
     stepChoreographerFrame();
     verify(mJSTimersMock).callTimers(JavaOnlyArray.of(105));
 
     reset(mJSTimersMock);
-    mTiming.deleteTimer(105);
+    mTiming.deleteTimer(mExecutorTokenMock, 105);
     stepChoreographerFrame();
     verifyNoMoreInteractions(mJSTimersMock);
   }
@@ -144,7 +147,7 @@ public void testCancelRecurringTimer() {
   @Test
   public void testPausingAndResuming() {
     mTiming.onHostResume();
-    mTiming.createTimer(41, 0, 0, true);
+    mTiming.createTimer(mExecutorTokenMock, 41, 0, 0, true);
 
     stepChoreographerFrame();
     verify(mJSTimersMock).callTimers(JavaOnlyArray.of(41));

From c2c71ca21cd35732de96aaba420e2e4f9b20ca88 Mon Sep 17 00:00:00 2001
From: Pimm Hogeling <pimmhogeling@gmail.com>
Date: Thu, 3 Mar 2016 09:29:28 -0800
Subject: [PATCH 1400/1411] =?UTF-8?q?"loosing"=E2=86=92"losing"=20(typo)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Summary:♥
Closes https://github.com/facebook/react-native/pull/6273

Differential Revision: D3006141

fb-gh-sync-id: 393e05b3a747cc905a1aae1505ed8c7e770f7835
shipit-source-id: 393e05b3a747cc905a1aae1505ed8c7e770f7835
---
 docs/SignedAPKAndroid.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/SignedAPKAndroid.md b/docs/SignedAPKAndroid.md
index 759ed7ae09ac..e4ecc0d51935 100644
--- a/docs/SignedAPKAndroid.md
+++ b/docs/SignedAPKAndroid.md
@@ -35,7 +35,7 @@ MYAPP_RELEASE_KEY_PASSWORD=*****
 
 These are going to be global gradle variables, which we can later use in our gradle config to sign our app.
 
-_Note: Once you publish the app on the Play Store, you will need to republish your app under a different package name (loosing all downloads and ratings) if you want to change the signing key at any point. So backup your keystore and don't forget the passwords._
+_Note: Once you publish the app on the Play Store, you will need to republish your app under a different package name (losing all downloads and ratings) if you want to change the signing key at any point. So backup your keystore and don't forget the passwords._
 
 ### Adding signing config to your app's gradle config
 

From a48db5c563e955767d90109de8ea1bd112579d8e Mon Sep 17 00:00:00 2001
From: Konstantin Raev <bestander@fb.com>
Date: Thu, 3 Mar 2016 09:50:52 -0800
Subject: [PATCH 1401/1411] added bestander for notifications of travis ci
 status changes

Summary:for tracking Travis stability
Closes https://github.com/facebook/react-native/pull/6277

Differential Revision: D3006229

fb-gh-sync-id: 31266cb3b73d57946cfd1518365f465642f0173a
shipit-source-id: 31266cb3b73d57946cfd1518365f465642f0173a
---
 .travis.yml | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/.travis.yml b/.travis.yml
index 341efe0a4f96..03c02d963e77 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -52,3 +52,10 @@ branches:
   only:
     - master
     - /^.*-stable$/
+
+notifications:
+  email:
+    recipients:
+      - bestander@gmail.com
+    on_failure: change
+    on_success: change

From 532e41105bf6b020561c132ac044e137949b6a0f Mon Sep 17 00:00:00 2001
From: Lukas Liesis <liesislukas@gmail.com>
Date: Thu, 3 Mar 2016 10:02:03 -0800
Subject: [PATCH 1402/1411] added ArcChat.com Android app to showcase

Summary:Added http://arcchat.com/ android app https://play.google.com/store/apps/details?id=com.arcchat  to showcase https://facebook.github.io/react-native/showcase.html
Closes https://github.com/facebook/react-native/pull/6267

Differential Revision: D3006203

fb-gh-sync-id: 7ff9d0b6d2536671a5fec1aec081aacfcd4489d3
shipit-source-id: 7ff9d0b6d2536671a5fec1aec081aacfcd4489d3
---
 website/src/react-native/showcase.js | 62 +++++++++++++++-------------
 1 file changed, 34 insertions(+), 28 deletions(-)

diff --git a/website/src/react-native/showcase.js b/website/src/react-native/showcase.js
index a7fb649a50fa..5746d97a1f6d 100644
--- a/website/src/react-native/showcase.js
+++ b/website/src/react-native/showcase.js
@@ -168,6 +168,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/accio-on-demand-delivery/id1047060673?mt=8',
     author: 'Accio Delivery Inc.',
   },
+  {
+    name: 'ArcChat.com',
+    icon: 'https://lh3.googleusercontent.com/mZJjidMobu3NAZApdtp-vdBBzIWzCNTaIcKShbGqwXRRzL3B9bbi6E0eRuykgT6vmg=w300-rw',
+    link: 'https://play.google.com/store/apps/details?id=com.arcchat',
+    author: 'Lukas Liesis',
+  },
   {
     name: 'Beetroot',
     icon: 'http://is1.mzstatic.com/image/pf/us/r30/Purple5/v4/66/fd/dd/66fddd70-f848-4fc5-43ee-4d52197ccab8/pr_source.png',
@@ -238,6 +244,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/dareu-dare-your-friends-dare/id1046434563?mt=8',
     author: 'Rishabh Mehan',
   },
+  {
+    name: 'Deskbookers',
+    icon: 'http://a4.mzstatic.com/eu/r30/Purple69/v4/be/61/7d/be617d63-88f5-5629-7ac0-bc2c9eb4802a/icon175x175.png',
+    linkAppStore: 'https://itunes.apple.com/nl/app/deskbookers/id964447401?mt=8',
+    author: 'Emilio Rodriguez'
+  },
   {
     name: 'DockMan',
     icon: 'http://a1.mzstatic.com/us/r30/Purple49/v4/91/b5/75/91b57552-d9bc-d8bc-10a1-617de920aaa6/icon175x175.png',
@@ -248,13 +260,6 @@ var apps = [
     ],
     author: 'Genki Takiuchi (s21g Inc.)',
   },
-  {
-    name: 'Fixt',
-    icon: 'http://a5.mzstatic.com/us/r30/Purple69/v4/46/bc/66/46bc66a2-7775-4d24-235d-e1fe28d55d7f/icon175x175.png',
-    linkAppStore:  'https://itunes.apple.com/us/app/dropbot-phone-replacement/id1000855694?mt=8',
-    linkPlayStore:  'https://play.google.com/store/apps/details?id=co.fixt',
-    author: 'Fixt',
-  },
   {
     name: 'Due',
     icon: 'http://a1.mzstatic.com/us/r30/Purple69/v4/a2/41/5d/a2415d5f-407a-c565-ffb4-4f27f23d8ac2/icon175x175.png',
@@ -286,6 +291,13 @@ var apps = [
     link: 'https://play.google.com/store/apps/details?id=com.arjunkomath.product_hunt&hl=en',
     author: 'Arjun Komath',
   },
+  {
+    name: 'Fixt',
+    icon: 'http://a5.mzstatic.com/us/r30/Purple69/v4/46/bc/66/46bc66a2-7775-4d24-235d-e1fe28d55d7f/icon175x175.png',
+    linkAppStore:  'https://itunes.apple.com/us/app/dropbot-phone-replacement/id1000855694?mt=8',
+    linkPlayStore:  'https://play.google.com/store/apps/details?id=co.fixt',
+    author: 'Fixt',
+  },
   {
     name: 'Foodstand',
     icon: 'http://a3.mzstatic.com/us/r30/Purple69/v4/33/c1/3b/33c13b88-8ec2-23c1-56bb-712ad9938290/icon350x350.jpeg',
@@ -481,6 +493,15 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/reactto36/id989009293?mt=8',
     author: 'Jonathan Solichin',
   },
+  {
+    name: 'Reading',
+    icon: 'http://7xr0xq.com1.z0.glb.clouddn.com/about_logo.png',
+    link: 'http://www.wandoujia.com/apps/com.reading',
+    author: 'RichardCao',
+    blogs: [
+      'http://richard-cao.github.io/2016/02/06/Reading-App-Write-In-React-Native/',
+    ],
+  },
   {
     name: 'RenovationFind',
     icon: 'http://a2.mzstatic.com/us/r30/Purple3/v4/4f/89/af/4f89af72-9733-2f59-6876-161983a0ee82/icon175x175.png',
@@ -542,12 +563,6 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/tabtor-math/id1018651199?utm_source=ParentAppLP',
     author: 'PrazAs Learning Inc.',
   },
-  {
-    name: 'Thai Tone',
-    icon: 'http://a5.mzstatic.com/us/r30/Purple2/v4/b1/e6/2b/b1e62b3d-6747-0d0b-2a21-b6ba316a7890/icon175x175.png',
-    link: 'https://itunes.apple.com/us/app/thai-tone/id1064086189?mt=8',
-    author: 'Alexey Ledak',
-  },
   {
     name: 'TeamWarden',
     icon: 'http://a1.mzstatic.com/eu/r30/Purple69/v4/09/37/61/0937613a-46e3-3278-5457-5de49a4ee9ab/icon175x175.png',
@@ -561,6 +576,12 @@ var apps = [
     link: 'https://itunes.apple.com/us/app/text-blast-2016/id1023852862?mt=8',
     author: 'Sesh',
   },
+  {
+    name: 'Thai Tone',
+    icon: 'http://a5.mzstatic.com/us/r30/Purple2/v4/b1/e6/2b/b1e62b3d-6747-0d0b-2a21-b6ba316a7890/icon175x175.png',
+    link: 'https://itunes.apple.com/us/app/thai-tone/id1064086189?mt=8',
+    author: 'Alexey Ledak',
+  },
   {
     name: 'Tong Xing Wang',
     icon: 'http://a3.mzstatic.com/us/r30/Purple1/v4/7d/52/a7/7d52a71f-9532-82a5-b92f-87076624fdb2/icon175x175.jpeg',
@@ -636,21 +657,6 @@ var apps = [
     linkAppStore: 'https://itunes.apple.com/cn/app/hong-bei-bang-hai-liang-hong/id1007812319?mt=8',
     author: 'Hongbeibang'
   },
-  {
-    name: 'Reading',
-    icon: 'http://7xr0xq.com1.z0.glb.clouddn.com/about_logo.png',
-    link: 'http://www.wandoujia.com/apps/com.reading',
-    author: 'RichardCao',
-    blogs: [
-      'http://richard-cao.github.io/2016/02/06/Reading-App-Write-In-React-Native/',
-    ],
-  },
-  {
-    name: 'Deskbookers',
-    icon: 'http://a4.mzstatic.com/eu/r30/Purple69/v4/be/61/7d/be617d63-88f5-5629-7ac0-bc2c9eb4802a/icon175x175.png',
-    linkAppStore: 'https://itunes.apple.com/nl/app/deskbookers/id964447401?mt=8',
-    author: 'Emilio Rodriguez'
-  },
 ];
 
 var AppList = React.createClass({

From 9a3f11d3e701e36dfae1cb55864f7efebc171935 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Thu, 3 Mar 2016 11:06:45 -0800
Subject: [PATCH 1403/1411] WebWorkers: Convert NetworkingModule to support web
 workers

Summary: Converts NetworkingModule to dispatch callbacks to the appropriate ExecutionContext.

Reviewed By: lexs

Differential Revision: D2932170

fb-gh-sync-id: ac77eec1a176ede4d2257bfd8ddb13153331c8a4
shipit-source-id: ac77eec1a176ede4d2257bfd8ddb13153331c8a4
---
 .../core/DeviceEventManagerModule.java        |   5 +-
 .../modules/network/NetworkingModule.java     | 108 ++++++++++-----
 .../modules/network/NetworkingModuleTest.java | 127 ++++++++++--------
 3 files changed, 143 insertions(+), 97 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/DeviceEventManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/core/DeviceEventManagerModule.java
index 1329a5b7c6d8..37a34283c813 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/core/DeviceEventManagerModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/core/DeviceEventManagerModule.java
@@ -12,10 +12,10 @@
 import javax.annotation.Nullable;
 
 import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.ReactContextBaseJavaModule;
 import com.facebook.react.bridge.ReactMethod;
 import com.facebook.react.bridge.JavaScriptModule;
+import com.facebook.react.bridge.SupportsWebWorkers;
 import com.facebook.react.bridge.UiThreadUtil;
 
 /**
@@ -23,7 +23,8 @@
  */
 public class DeviceEventManagerModule extends ReactContextBaseJavaModule {
 
-  public static interface RCTDeviceEventEmitter extends JavaScriptModule {
+  @SupportsWebWorkers
+  public interface RCTDeviceEventEmitter extends JavaScriptModule {
     void emit(String eventName, @Nullable Object data);
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
index 2bdcd82d65b0..cd9e6b98ca37 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
@@ -18,6 +18,7 @@
 import java.util.concurrent.TimeUnit;
 
 import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.ExecutorToken;
 import com.facebook.react.bridge.GuardedAsyncTask;
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.ReactContextBaseJavaModule;
@@ -116,9 +117,10 @@ public void onCatalystInstanceDestroy() {
 
   @ReactMethod
   /**
-  * @param timeout value of 0 results in no timeout
-  */
+   * @param timeout value of 0 results in no timeout
+   */
   public void sendRequest(
+      final ExecutorToken executorToken,
       String method,
       String url,
       final int requestId,
@@ -144,7 +146,7 @@ public void sendRequest(
 
     Headers requestHeaders = extractHeaders(headers, data);
     if (requestHeaders == null) {
-      onRequestError(requestId, "Unrecognized headers format");
+      onRequestError(executorToken, requestId, "Unrecognized headers format");
       return;
     }
     String contentType = requestHeaders.get(CONTENT_TYPE_HEADER_NAME);
@@ -155,7 +157,10 @@ public void sendRequest(
       requestBuilder.method(method, RequestBodyUtil.getEmptyBody(method));
     } else if (data.hasKey(REQUEST_BODY_KEY_STRING)) {
       if (contentType == null) {
-        onRequestError(requestId, "Payload is set but no content-type header specified");
+        onRequestError(
+            executorToken,
+            requestId,
+            "Payload is set but no content-type header specified");
         return;
       }
       String body = data.getString(REQUEST_BODY_KEY_STRING);
@@ -163,7 +168,7 @@ public void sendRequest(
       if (RequestBodyUtil.isGzipEncoding(contentEncoding)) {
         RequestBody requestBody = RequestBodyUtil.createGzip(contentMediaType, body);
         if (requestBody == null) {
-          onRequestError(requestId, "Failed to gzip request body");
+          onRequestError(executorToken, requestId, "Failed to gzip request body");
           return;
         }
         requestBuilder.method(method, requestBody);
@@ -172,14 +177,17 @@ public void sendRequest(
       }
     } else if (data.hasKey(REQUEST_BODY_KEY_URI)) {
       if (contentType == null) {
-        onRequestError(requestId, "Payload is set but no content-type header specified");
+        onRequestError(
+            executorToken,
+            requestId,
+            "Payload is set but no content-type header specified");
         return;
       }
       String uri = data.getString(REQUEST_BODY_KEY_URI);
       InputStream fileInputStream =
           RequestBodyUtil.getFileInputStream(getReactApplicationContext(), uri);
       if (fileInputStream == null) {
-        onRequestError(requestId, "Could not retrieve file for uri " + uri);
+        onRequestError(executorToken, requestId, "Could not retrieve file for uri " + uri);
         return;
       }
       requestBuilder.method(
@@ -190,7 +198,8 @@ public void sendRequest(
         contentType = "multipart/form-data";
       }
       ReadableArray parts = data.getArray(REQUEST_BODY_KEY_FORMDATA);
-      MultipartBuilder multipartBuilder = constructMultipartBody(parts, contentType, requestId);
+      MultipartBuilder multipartBuilder =
+          constructMultipartBody(executorToken, parts, contentType, requestId);
       if (multipartBuilder == null) {
         return;
       }
@@ -207,7 +216,7 @@ public void onFailure(Request request, IOException e) {
             if (mShuttingDown) {
               return;
             }
-            onRequestError(requestId, e.getMessage());
+            onRequestError(executorToken, requestId, e.getMessage());
           }
 
           @Override
@@ -217,25 +226,28 @@ public void onResponse(Response response) throws IOException {
             }
 
             // Before we touch the body send headers to JS
-            onResponseReceived(requestId, response);
+            onResponseReceived(executorToken, requestId, response);
 
             ResponseBody responseBody = response.body();
             try {
               if (useIncrementalUpdates) {
-                readWithProgress(requestId, responseBody);
-                onRequestSuccess(requestId);
+                readWithProgress(executorToken, requestId, responseBody);
+                onRequestSuccess(executorToken, requestId);
               } else {
-                onDataReceived(requestId, responseBody.string());
-                onRequestSuccess(requestId);
+                onDataReceived(executorToken, requestId, responseBody.string());
+                onRequestSuccess(executorToken, requestId);
               }
             } catch (IOException e) {
-              onRequestError(requestId, e.getMessage());
+              onRequestError(executorToken, requestId, e.getMessage());
             }
           }
         });
   }
 
-  private void readWithProgress(int requestId, ResponseBody responseBody) throws IOException {
+  private void readWithProgress(
+      ExecutorToken executorToken,
+      int requestId,
+      ResponseBody responseBody) throws IOException {
     Reader reader = responseBody.charStream();
     try {
       StringBuilder sb = new StringBuilder(getBufferSize(responseBody));
@@ -246,14 +258,14 @@ private void readWithProgress(int requestId, ResponseBody responseBody) throws I
         sb.append(buffer, 0, read);
         long now = System.nanoTime();
         if (shouldDispatch(now, last)) {
-          onDataReceived(requestId, sb.toString());
+          onDataReceived(executorToken, requestId, sb.toString());
           sb.setLength(0);
           last = now;
         }
       }
 
       if (sb.length() > 0) {
-        onDataReceived(requestId, sb.toString());
+        onDataReceived(executorToken, requestId, sb.toString());
       }
     } finally {
       reader.close();
@@ -273,31 +285,34 @@ private static int getBufferSize(ResponseBody responseBody) throws IOException {
     }
   }
 
-  private void onDataReceived(int requestId, String data) {
+  private void onDataReceived(ExecutorToken ExecutorToken, int requestId, String data) {
     WritableArray args = Arguments.createArray();
     args.pushInt(requestId);
     args.pushString(data);
 
-    getEventEmitter().emit("didReceiveNetworkData", args);
+    getEventEmitter(ExecutorToken).emit("didReceiveNetworkData", args);
   }
 
-  private void onRequestError(int requestId, String error) {
+  private void onRequestError(ExecutorToken ExecutorToken, int requestId, String error) {
     WritableArray args = Arguments.createArray();
     args.pushInt(requestId);
     args.pushString(error);
 
-    getEventEmitter().emit("didCompleteNetworkResponse", args);
+    getEventEmitter(ExecutorToken).emit("didCompleteNetworkResponse", args);
   }
 
-  private void onRequestSuccess(int requestId) {
+  private void onRequestSuccess(ExecutorToken ExecutorToken, int requestId) {
     WritableArray args = Arguments.createArray();
     args.pushInt(requestId);
     args.pushNull();
 
-    getEventEmitter().emit("didCompleteNetworkResponse", args);
+    getEventEmitter(ExecutorToken).emit("didCompleteNetworkResponse", args);
   }
 
-  private void onResponseReceived(int requestId, Response response) {
+  private void onResponseReceived(
+      ExecutorToken ExecutorToken,
+      int requestId,
+      Response response) {
     WritableMap headers = translateHeaders(response.headers());
 
     WritableArray args = Arguments.createArray();
@@ -306,7 +321,7 @@ private void onResponseReceived(int requestId, Response response) {
     args.pushMap(headers);
     args.pushString(response.request().urlString());
 
-    getEventEmitter().emit("didReceiveNetworkResponse", args);
+    getEventEmitter(ExecutorToken).emit("didReceiveNetworkResponse", args);
   }
 
   private static WritableMap translateHeaders(Headers headers) {
@@ -326,7 +341,7 @@ private static WritableMap translateHeaders(Headers headers) {
   }
 
   @ReactMethod
-  public void abortRequest(final int requestId) {
+  public void abortRequest(ExecutorToken executorToken, final int requestId) {
     // We have to use AsyncTask since this might trigger a NetworkOnMainThreadException, this is an
     // open issue on OkHttp: https://github.com/square/okhttp/issues/869
     new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
@@ -338,11 +353,21 @@ protected void doInBackgroundGuarded(Void... params) {
   }
 
   @ReactMethod
-  public void clearCookies(com.facebook.react.bridge.Callback callback) {
+  public void clearCookies(
+      ExecutorToken executorToken,
+      com.facebook.react.bridge.Callback callback) {
     mCookieHandler.clearCookies(callback);
   }
 
-  private @Nullable MultipartBuilder constructMultipartBody(
+  @Override
+  public boolean supportsWebWorkers() {
+    return true;
+  }
+
+  private
+  @Nullable
+  MultipartBuilder constructMultipartBody(
+      ExecutorToken ExecutorToken,
       ReadableArray body,
       String contentType,
       int requestId) {
@@ -356,7 +381,10 @@ public void clearCookies(com.facebook.react.bridge.Callback callback) {
       ReadableArray headersArray = bodyPart.getArray("headers");
       Headers headers = extractHeaders(headersArray, null);
       if (headers == null) {
-        onRequestError(requestId, "Missing or invalid header format for FormData part.");
+        onRequestError(
+            ExecutorToken,
+            requestId,
+            "Missing or invalid header format for FormData part.");
         return null;
       }
       MediaType partContentType = null;
@@ -373,19 +401,25 @@ public void clearCookies(com.facebook.react.bridge.Callback callback) {
         multipartBuilder.addPart(headers, RequestBody.create(partContentType, bodyValue));
       } else if (bodyPart.hasKey(REQUEST_BODY_KEY_URI)) {
         if (partContentType == null) {
-          onRequestError(requestId, "Binary FormData part needs a content-type header.");
+          onRequestError(
+              ExecutorToken,
+              requestId,
+              "Binary FormData part needs a content-type header.");
           return null;
         }
         String fileContentUriStr = bodyPart.getString(REQUEST_BODY_KEY_URI);
         InputStream fileInputStream =
             RequestBodyUtil.getFileInputStream(getReactApplicationContext(), fileContentUriStr);
         if (fileInputStream == null) {
-          onRequestError(requestId, "Could not retrieve file for uri " + fileContentUriStr);
+          onRequestError(
+              ExecutorToken,
+              requestId,
+              "Could not retrieve file for uri " + fileContentUriStr);
           return null;
         }
         multipartBuilder.addPart(headers, RequestBodyUtil.create(partContentType, fileInputStream));
       } else {
-        onRequestError(requestId, "Unrecognized FormData part.");
+        onRequestError(ExecutorToken, requestId, "Unrecognized FormData part.");
       }
     }
     return multipartBuilder;
@@ -394,7 +428,9 @@ public void clearCookies(com.facebook.react.bridge.Callback callback) {
   /**
    * Extracts the headers from the Array. If the format is invalid, this method will return null.
    */
-  private @Nullable Headers extractHeaders(
+  private
+  @Nullable
+  Headers extractHeaders(
       @Nullable ReadableArray headersArray,
       @Nullable ReadableMap requestData) {
     if (headersArray == null) {
@@ -423,8 +459,8 @@ public void clearCookies(com.facebook.react.bridge.Callback callback) {
     return headersBuilder.build();
   }
 
-  private DeviceEventManagerModule.RCTDeviceEventEmitter getEventEmitter() {
+  private DeviceEventManagerModule.RCTDeviceEventEmitter getEventEmitter(ExecutorToken ExecutorToken) {
     return getReactApplicationContext()
-        .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class);
+        .getJSModule(ExecutorToken, DeviceEventManagerModule.RCTDeviceEventEmitter.class);
   }
 }
diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkingModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkingModuleTest.java
index 63707bae0ebf..ce38961233cb 100644
--- a/ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkingModuleTest.java
+++ b/ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkingModuleTest.java
@@ -14,6 +14,7 @@
 import java.util.List;
 
 import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.ExecutorToken;
 import com.facebook.react.bridge.ReactApplicationContext;
 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.bridge.JavaOnlyArray;
@@ -88,13 +89,14 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
     NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient);
 
     networkingModule.sendRequest(
-        "GET",
-        "http://somedomain/foo",
-        0,
-        JavaOnlyArray.of(),
-        null,
-        true,
-        0);
+      mock(ExecutorToken.class),
+      "GET",
+      "http://somedomain/foo",
+      0,
+      JavaOnlyArray.of(),
+      null,
+      true,
+      0);
 
     ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
     verify(httpClient).newCall(argumentCaptor.capture());
@@ -108,7 +110,7 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
   public void testFailGetWithInvalidHeadersStruct() throws Exception {
     RCTDeviceEventEmitter emitter = mock(RCTDeviceEventEmitter.class);
     ReactApplicationContext context = mock(ReactApplicationContext.class);
-    when(context.getJSModule(any(Class.class))).thenReturn(emitter);
+    when(context.getJSModule(any(ExecutorToken.class), any(Class.class))).thenReturn(emitter);
 
     OkHttpClient httpClient = mock(OkHttpClient.class);
     NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient);
@@ -118,13 +120,14 @@ public void testFailGetWithInvalidHeadersStruct() throws Exception {
     mockEvents();
 
     networkingModule.sendRequest(
-        "GET",
-        "http://somedoman/foo",
-        0,
-        JavaOnlyArray.from(invalidHeaders),
-        null,
-        true,
-        0);
+      mock(ExecutorToken.class),
+      "GET",
+      "http://somedoman/foo",
+      0,
+      JavaOnlyArray.from(invalidHeaders),
+      null,
+      true,
+      0);
 
     verifyErrorEmit(emitter, 0);
   }
@@ -133,7 +136,7 @@ public void testFailGetWithInvalidHeadersStruct() throws Exception {
   public void testFailPostWithoutContentType() throws Exception {
     RCTDeviceEventEmitter emitter = mock(RCTDeviceEventEmitter.class);
     ReactApplicationContext context = mock(ReactApplicationContext.class);
-    when(context.getJSModule(any(Class.class))).thenReturn(emitter);
+    when(context.getJSModule(any(ExecutorToken.class), any(Class.class))).thenReturn(emitter);
 
     OkHttpClient httpClient = mock(OkHttpClient.class);
     NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient);
@@ -144,13 +147,14 @@ public void testFailPostWithoutContentType() throws Exception {
     mockEvents();
 
     networkingModule.sendRequest(
-        "POST",
-        "http://somedomain/bar",
-        0,
-        JavaOnlyArray.of(),
-        body,
-        true,
-        0);
+      mock(ExecutorToken.class),
+      "POST",
+      "http://somedomain/bar",
+      0,
+      JavaOnlyArray.of(),
+      body,
+      true,
+      0);
 
     verifyErrorEmit(emitter, 0);
   }
@@ -184,7 +188,7 @@ public WritableMap answer(InvocationOnMock invocation) throws Throwable {
   }
 
   @Test
-  public void testSuccessfullPostRequest() throws Exception {
+  public void testSuccessfulPostRequest() throws Exception {
     OkHttpClient httpClient = mock(OkHttpClient.class);
     when(httpClient.newCall(any(Request.class))).thenAnswer(new Answer<Object>() {
           @Override
@@ -200,13 +204,14 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
     body.putString("string", "This is request body");
 
     networkingModule.sendRequest(
-        "POST",
-        "http://somedomain/bar",
-        0,
-        JavaOnlyArray.of(JavaOnlyArray.of("Content-Type", "text/plain")),
-        body,
-        true,
-        0);
+      mock(ExecutorToken.class),
+      "POST",
+      "http://somedomain/bar",
+      0,
+      JavaOnlyArray.of(JavaOnlyArray.of("Content-Type", "text/plain")),
+      body,
+      true,
+      0);
 
     ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
     verify(httpClient).newCall(argumentCaptor.capture());
@@ -237,13 +242,14 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
         JavaOnlyArray.of("User-Agent", "React test agent/1.0"));
 
     networkingModule.sendRequest(
-        "GET",
-        "http://someurl/baz",
-        0,
-        JavaOnlyArray.from(headers),
-        null,
-        true,
-        0);
+      mock(ExecutorToken.class),
+      "GET",
+      "http://someurl/baz",
+      0,
+      JavaOnlyArray.from(headers),
+      null,
+      true,
+      0);
     ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
     verify(httpClient).newCall(argumentCaptor.capture());
     Headers requestHeaders = argumentCaptor.getValue().headers();
@@ -284,13 +290,14 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
 
     NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient);
     networkingModule.sendRequest(
-        "POST",
-        "http://someurl/uploadFoo",
-        0,
-        new JavaOnlyArray(),
-        body,
-        true,
-        0);
+      mock(ExecutorToken.class),
+      "POST",
+      "http://someurl/uploadFoo",
+      0,
+      new JavaOnlyArray(),
+      body,
+      true,
+      0);
 
     // verify url, method, headers
     ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
@@ -342,13 +349,14 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
 
     NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient);
     networkingModule.sendRequest(
-        "POST",
-        "http://someurl/uploadFoo",
-        0,
-        JavaOnlyArray.from(headers),
-        body,
-        true,
-        0);
+      mock(ExecutorToken.class),
+      "POST",
+      "http://someurl/uploadFoo",
+      0,
+      JavaOnlyArray.from(headers),
+      body,
+      true,
+      0);
 
     // verify url, method, headers
     ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
@@ -437,13 +445,14 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
 
     NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient);
     networkingModule.sendRequest(
-        "POST",
-        "http://someurl/uploadFoo",
-        0,
-        JavaOnlyArray.from(headers),
-        body,
-        true,
-        0);
+      mock(ExecutorToken.class),
+      "POST",
+      "http://someurl/uploadFoo",
+      0,
+      JavaOnlyArray.from(headers),
+      body,
+      true,
+      0);
 
     // verify RequestBodyPart for image
     PowerMockito.verifyStatic(times(1));

From c027f05ef48b3980c726c78a28117ad79750b8b1 Mon Sep 17 00:00:00 2001
From: Felix Oghina <foghina@fb.com>
Date: Thu, 3 Mar 2016 11:11:21 -0800
Subject: [PATCH 1404/1411] add generic memory pressure listener interface

Reviewed By: lexs

Differential Revision: D2989071

fb-gh-sync-id: 375c7551bd4b281096850732432f016c2684add0
shipit-source-id: 375c7551bd4b281096850732432f016c2684add0
---
 .../facebook/react/MemoryPressureRouter.java  | 32 +++++++++++++------
 .../react/ReactInstanceManagerImpl.java       |  4 +--
 .../react/bridge/CatalystInstance.java        |  4 +--
 .../react/bridge/MemoryPressureListener.java  | 15 +++++++++
 4 files changed, 40 insertions(+), 15 deletions(-)
 create mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/MemoryPressureListener.java

diff --git a/ReactAndroid/src/main/java/com/facebook/react/MemoryPressureRouter.java b/ReactAndroid/src/main/java/com/facebook/react/MemoryPressureRouter.java
index 58f2833110e2..c209bef26fb9 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/MemoryPressureRouter.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/MemoryPressureRouter.java
@@ -2,7 +2,9 @@
 
 package com.facebook.react;
 
-import javax.annotation.Nullable;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
 
 import android.annotation.TargetApi;
 import android.app.Activity;
@@ -11,9 +13,8 @@
 import android.content.res.Configuration;
 import android.os.Build;
 
-import com.facebook.react.bridge.CatalystInstance;
 import com.facebook.react.bridge.MemoryPressure;
-import com.facebook.react.bridge.ReactContext;
+import com.facebook.react.bridge.MemoryPressureListener;
 
 import static android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
 import static android.content.ComponentCallbacks2.TRIM_MEMORY_MODERATE;
@@ -27,7 +28,8 @@ public class MemoryPressureRouter {
   // am start -a "com.facebook.catalyst.ACTION_TRIM_MEMORY" --activity-single-top -n <activity>
   private static final String ACTION_TRIM_MEMORY ="com.facebook.catalyst.ACTION_TRIM_MEMORY";
 
-  private @Nullable CatalystInstance mCatalystInstance;
+  private final Set<MemoryPressureListener> mListeners =
+    Collections.synchronizedSet(new LinkedHashSet<MemoryPressureListener>());
   private final ComponentCallbacks2 mCallbacks = new ComponentCallbacks2() {
     @Override
     public void onTrimMemory(int level) {
@@ -60,12 +62,18 @@ public static boolean handleDebugIntent(Activity activity, String action) {
     context.getApplicationContext().registerComponentCallbacks(mCallbacks);
   }
 
-  public void onNewReactContextCreated(ReactContext reactContext) {
-    mCatalystInstance = reactContext.getCatalystInstance();
+  /**
+   * Add a listener to be notified of memory pressure events.
+   */
+  public void addMemoryPressureListener(MemoryPressureListener listener) {
+    mListeners.add(listener);
   }
 
-  public void onReactInstanceDestroyed() {
-    mCatalystInstance = null;
+  /**
+   * Remove a listener previously added with {@link #addMemoryPressureListener}.
+   */
+  public void removeMemoryPressureListener(MemoryPressureListener listener) {
+    mListeners.remove(listener);
   }
 
   public void destroy(Context context) {
@@ -81,8 +89,12 @@ private void trimMemory(int level) {
   }
 
   private void dispatchMemoryPressure(MemoryPressure level) {
-    if (mCatalystInstance != null) {
-      mCatalystInstance.handleMemoryPressure(level);
+    // copy listeners array to avoid ConcurrentModificationException if any of the listeners remove
+    // themselves in handleMemoryPressure()
+    MemoryPressureListener[] listeners =
+      mListeners.toArray(new MemoryPressureListener[mListeners.size()]);
+    for (MemoryPressureListener listener : listeners) {
+      listener.handleMemoryPressure(level);
     }
   }
 
diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index faba27bafed9..56812d6ec67c 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -715,7 +715,7 @@ private void setupReactContext(ReactApplicationContext reactContext) {
 
     catalystInstance.initialize();
     mDevSupportManager.onNewReactContextCreated(reactContext);
-    mMemoryPressureRouter.onNewReactContextCreated(reactContext);
+    mMemoryPressureRouter.addMemoryPressureListener(catalystInstance);
     moveReactContextToCurrentLifecycleState();
 
     for (ReactRootView rootView : mAttachedRootViews) {
@@ -772,7 +772,7 @@ private void tearDownReactContext(ReactContext reactContext) {
     }
     reactContext.destroy();
     mDevSupportManager.onReactInstanceDestroyed(reactContext);
-    mMemoryPressureRouter.onReactInstanceDestroyed();
+    mMemoryPressureRouter.removeMemoryPressureListener(reactContext.getCatalystInstance());
   }
 
   /**
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
index 98ac8d76398b..17c01f542869 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java
@@ -21,7 +21,7 @@
  * Java APIs be invokable from JavaScript as well.
  */
 @DoNotStrip
-public interface CatalystInstance {
+public interface CatalystInstance extends MemoryPressureListener {
   void runJSBundle();
   // This is called from java code, so it won't be stripped anyway, but proguard will rename it,
   // which this prevents.
@@ -48,8 +48,6 @@ public interface CatalystInstance {
   <T extends NativeModule> T getNativeModule(Class<T> nativeModuleInterface);
   Collection<NativeModule> getNativeModules();
 
-  void handleMemoryPressure(MemoryPressure level);
-
   /**
    * Adds a idle listener for this Catalyst instance. The listener will receive notifications
    * whenever the bridge transitions from idle to busy and vice-versa, where the busy state is
diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/MemoryPressureListener.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/MemoryPressureListener.java
new file mode 100644
index 000000000000..e4640b96e277
--- /dev/null
+++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/MemoryPressureListener.java
@@ -0,0 +1,15 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+package com.facebook.react.bridge;
+
+/**
+ * Listener interface for memory pressure events.
+ */
+public interface MemoryPressureListener {
+
+  /**
+   * Called when the system generates a memory warning.
+   */
+  void handleMemoryPressure(MemoryPressure level);
+
+}

From 4b52d185acfae2d7e81a9aa2b3bafad253903f7d Mon Sep 17 00:00:00 2001
From: Felix Oghina <foghina@fb.com>
Date: Thu, 3 Mar 2016 11:11:29 -0800
Subject: [PATCH 1405/1411] support simulating critical memory pressure, even
 when activity is destroyed

Reviewed By: lexs

Differential Revision: D2989094

fb-gh-sync-id: 17bbcac390ab1a3a745f1e85f7cb23d1dcf7043b
shipit-source-id: 17bbcac390ab1a3a745f1e85f7cb23d1dcf7043b
---
 .../facebook/react/MemoryPressureRouter.java  | 23 +++++++++++--------
 1 file changed, 14 insertions(+), 9 deletions(-)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/MemoryPressureRouter.java b/ReactAndroid/src/main/java/com/facebook/react/MemoryPressureRouter.java
index c209bef26fb9..e9fd7574895f 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/MemoryPressureRouter.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/MemoryPressureRouter.java
@@ -7,7 +7,7 @@
 import java.util.Set;
 
 import android.annotation.TargetApi;
-import android.app.Activity;
+import android.app.Application;
 import android.content.ComponentCallbacks2;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -17,6 +17,7 @@
 import com.facebook.react.bridge.MemoryPressureListener;
 
 import static android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
+import static android.content.ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
 import static android.content.ComponentCallbacks2.TRIM_MEMORY_MODERATE;
 import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
 
@@ -25,8 +26,11 @@
  */
 public class MemoryPressureRouter {
   // Trigger this by sending an intent to your activity with adb shell:
-  // am start -a "com.facebook.catalyst.ACTION_TRIM_MEMORY" --activity-single-top -n <activity>
-  private static final String ACTION_TRIM_MEMORY ="com.facebook.catalyst.ACTION_TRIM_MEMORY";
+  // am broadcast -a com.facebook.catalyst.ACTION_TRIM_MEMORY_MODERATE
+  private static final String ACTION_TRIM_MEMORY_MODERATE =
+    "com.facebook.rnfeed.ACTION_TRIM_MEMORY_MODERATE";
+  private static final String ACTION_TRIM_MEMORY_CRITICAL =
+    "com.facebook.rnfeed.ACTION_TRIM_MEMORY_CRITICAL";
 
   private final Set<MemoryPressureListener> mListeners =
     Collections.synchronizedSet(new LinkedHashSet<MemoryPressureListener>());
@@ -46,11 +50,13 @@ public void onLowMemory() {
   };
 
   @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
-  public static boolean handleDebugIntent(Activity activity, String action) {
+  public static boolean handleDebugIntent(Application application, String action) {
     switch (action) {
-      case ACTION_TRIM_MEMORY:
-        simulateTrimMemory(activity, TRIM_MEMORY_MODERATE);
+      case ACTION_TRIM_MEMORY_MODERATE:
+        simulateTrimMemory(application, TRIM_MEMORY_MODERATE);
         break;
+      case ACTION_TRIM_MEMORY_CRITICAL:
+        simulateTrimMemory(application, TRIM_MEMORY_COMPLETE);
       default:
         return false;
     }
@@ -98,8 +104,7 @@ private void dispatchMemoryPressure(MemoryPressure level) {
     }
   }
 
-  private static void simulateTrimMemory(Activity activity, int level) {
-    activity.getApplication().onTrimMemory(level);
-    activity.onTrimMemory(level);
+  private static void simulateTrimMemory(Application application, int level) {
+    application.onTrimMemory(level);
   }
 }

From 2e4bb5364daa7d7881c43e81b34bdb25a9cbbfa4 Mon Sep 17 00:00:00 2001
From: Felix Oghina <foghina@fb.com>
Date: Thu, 3 Mar 2016 11:11:30 -0800
Subject: [PATCH 1406/1411] destroy react instance on background critical
 memory pressure

Reviewed By: astreet

Differential Revision: D2989125

fb-gh-sync-id: 0e441409d6b0ea7d5ff6a037730cc1c36818a2da
shipit-source-id: 0e441409d6b0ea7d5ff6a037730cc1c36818a2da
---
 .../java/com/facebook/react/ReactInstanceManager.java    | 4 ++++
 .../com/facebook/react/ReactInstanceManagerImpl.java     | 9 +++++++++
 2 files changed, 13 insertions(+)

diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
index 990202ebe8c0..2e2ca160301f 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java
@@ -62,6 +62,8 @@ public interface ReactInstanceEventListener {
 
   public abstract DevSupportManager getDevSupportManager();
 
+  public abstract MemoryPressureRouter getMemoryPressureRouter();
+
   /**
    * Trigger react context initialization asynchronously in a background async task. This enables
    * applications to pre-load the application JS, and execute global code before
@@ -159,6 +161,8 @@ public abstract List<ViewManager> createAllViewManagers(
   @VisibleForTesting
   public abstract @Nullable ReactContext getCurrentReactContext();
 
+  public abstract LifecycleState getLifecycleState();
+
   /**
    * Creates a builder that is capable of creating an instance of {@link ReactInstanceManagerImpl}.
    */
diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
index 56812d6ec67c..0c480eb58680 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java
@@ -308,6 +308,11 @@ public DevSupportManager getDevSupportManager() {
     return mDevSupportManager;
   }
 
+  @Override
+  public MemoryPressureRouter getMemoryPressureRouter() {
+    return mMemoryPressureRouter;
+  }
+
   private static void initializeSoLoaderIfNecessary(Context applicationContext) {
     // Call SoLoader.initialize here, this is required for apps that does not use exopackage and
     // does not use SoLoader for loading other native code except from the one used by React Native
@@ -582,6 +587,10 @@ private void moveToBeforeCreateLifecycleState() {
     mLifecycleState = LifecycleState.BEFORE_CREATE;
   }
 
+  public LifecycleState getLifecycleState() {
+    return mLifecycleState;
+  }
+
   @Override
   public void onActivityResult(int requestCode, int resultCode, Intent data) {
     if (mCurrentReactContext != null) {

From 44997b47e2bb5ba17ac55ca130a51b58a93dddf4 Mon Sep 17 00:00:00 2001
From: Martin Konicek <mkonicek@fb.com>
Date: Thu, 3 Mar 2016 12:42:22 -0800
Subject: [PATCH 1407/1411] Skeleton for running Android e2e or a separate
 packager e2e test

Summary:The e2e-test.sh currently only supports iOS. Most of the script will be identical for Android,
let's therefore reuse it. This diff adds one argument: --ios, --android or --packager.

`--packager` starts the packager and checks it produces a bundle. The idea is to run this
on CircleCI even before we implement the actual Android e2e test in order to reliably catch
breakages to package.json quickly.

We should only land this once Travis is green again.

**Test plan**

Ran:

    git checkout master
    ./scripts/e2e-test.sh  # Error message about required argument was printed
    ./scripts/e2e-test.sh --ios       # Ran the test as before (all the way up to xctool which I don't have locally)
    ./scripts/e2e-test.sh --android   # Message was printed
    ./scripts/e2e-test.sh --packager  # The packager created the bundle, exit code was 0
    # Made the packager fails on bad JS
    ./scripts/e2e-test.sh --packager  # Exit code was 1
Closes https://github.com/facebook/react-native/pull/6279

Differential Revision: D3007281

fb-gh-sync-id: 6ece06b933001ba0939806c69ed7c7471b134931
shipit-source-id: 6ece06b933001ba0939806c69ed7c7471b134931
---
 .travis.yml         |  2 +-
 scripts/e2e-test.sh | 54 +++++++++++++++++++++++++++++++++++++--------
 2 files changed, 46 insertions(+), 10 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 03c02d963e77..32ad533ff3a5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -35,7 +35,7 @@ script:
   elif [ "$TEST_TYPE" = e2e-objc ]
   then
 
-    travis_retry ./scripts/e2e-test.sh
+    travis_retry ./scripts/e2e-test.sh --ios
 
   else
     echo "Unknown test type: $TEST_TYPE"
diff --git a/scripts/e2e-test.sh b/scripts/e2e-test.sh
index b3b418c9e7e2..63e6647e420e 100755
--- a/scripts/e2e-test.sh
+++ b/scripts/e2e-test.sh
@@ -1,9 +1,19 @@
 #!/bin/bash
 
+# The script has one required argument:
+# --packager: react-native init, make sure the packager starts
+# --ios: react-native init, start the packager and run the iOS app
+# --android: same but run the Android app
+
 # Abort the mission if any command fails
 set -e
 set -x
 
+if [ -z $1 ]; then
+  echo "Please run the script with --ios, --android or --packager"
+  exit 1
+fi
+
 SCRIPTS=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
 ROOT=$(dirname $SCRIPTS)
 TEMP=$(mktemp -d /tmp/react-native-XXXXXXXX)
@@ -16,7 +26,8 @@ export REACT_PACKAGER_LOG="$TEMP/server.log"
 # To make sure we actually installed the local version
 # of react-native, we will create a temp file inside the template
 # and check that it exists after `react-native init`
-MARKER=$(mktemp $ROOT/local-cli/generator-ios/templates/app/XXXXXXXX)
+MARKER_IOS=$(mktemp $ROOT/local-cli/generator-ios/templates/app/XXXXXXXX)
+MARKER_ANDROID=$(mktemp $ROOT/local-cli/generator-android/templates/src/XXXXXXXX)
 
 function cleanup {
   EXIT_CODE=$?
@@ -30,7 +41,8 @@ function cleanup {
     [ -f $REACT_PACKAGER_LOG ] && cat $REACT_PACKAGER_LOG
   fi
 
-  rm $MARKER
+  rm $MARKER_IOS
+  rm $MARKER_ANDROID
   [ $SINOPIA_PID ] && kill -9 $SINOPIA_PID
   [ $SERVER_PID ] && kill -9 $SERVER_PID
   [ -f ~/.npmrc.bak ] && mv ~/.npmrc.bak ~/.npmrc
@@ -63,14 +75,38 @@ npm publish $ROOT/react-native-cli
 
 npm install -g react-native-cli
 react-native init EndToEndTest
-cd EndToEndTest/ios
-
-# Make sure we installed local version of react-native
-ls EndToEndTest/`basename $MARKER` > /dev/null
+cd EndToEndTest
 
 npm install --g flow-bin@0.21.0
 flow --retries 10
 
-../node_modules/react-native/packager/packager.sh --nonPersistent &
-SERVER_PID=$!
-xctool -scheme EndToEndTest -sdk iphonesimulator test
+case $1 in
+"--packager"*)
+  echo "Running a basic packager test"
+  # Check the packager produces a bundle (doesn't throw an error)
+  react-native bundle --platform android --dev true --entry-file index.android.js --bundle-output android-bundle.js
+  ;;
+"--ios"*)
+  echo "Running an iOS app"
+  cd ios
+  # Make sure we installed local version of react-native
+  ls EndToEndTest/`basename $MARKER_IOS` > /dev/null
+  ../node_modules/react-native/packager/packager.sh --nonPersistent &
+  SERVER_PID=$!
+  # Start the app on the simulator
+  xctool -scheme EndToEndTest -sdk iphonesimulator test
+  ;;
+"--android"*)
+  echo "Running an Android app"
+  cd android
+  # Make sure we installed local version of react-native
+  ls `basename $MARKER_ANDROID` > /dev/null
+  ../node_modules/react-native/packager/packager.sh --nonPersistent &
+  SERVER_PID=$!
+  # TODO Start the app and check it renders "Welcome to React Native"
+  echo "The Android e2e test is not implemented yet"
+  ;;
+*)
+  echo "Please run the script with --ios, --android or --packager"
+  ;;
+esac

From 8c25181c441e117b33ee696d3f32e5c579b73947 Mon Sep 17 00:00:00 2001
From: Eric Lo <erlo@fb.com>
Date: Thu, 3 Mar 2016 12:42:41 -0800
Subject: [PATCH 1408/1411] Add onShow callback for RCTModalHostView

Summary: Added ability to include a callback to the modal. The callback is invoked when the modal is shown.

Reviewed By: javache

Differential Revision: D3005212

fb-gh-sync-id: 12648e17bd1cf831daf65529b87ae8cfdb901c65
shipit-source-id: 12648e17bd1cf831daf65529b87ae8cfdb901c65
---
 Libraries/Modal/Modal.js              | 2 ++
 React/Views/RCTModalHostView.h        | 3 +++
 React/Views/RCTModalHostView.m        | 6 +++++-
 React/Views/RCTModalHostViewManager.m | 1 +
 4 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/Libraries/Modal/Modal.js b/Libraries/Modal/Modal.js
index 9df6208d7860..318171e3de09 100644
--- a/Libraries/Modal/Modal.js
+++ b/Libraries/Modal/Modal.js
@@ -49,6 +49,7 @@ class Modal extends React.Component {
         animated={this.props.animated}
         transparent={this.props.transparent}
         onDismiss={this.props.onDismiss}
+        onShow={this.props.onShow}
         style={styles.modal}>
         <View style={[styles.container, containerBackgroundColor]}>
           {this.props.children}
@@ -63,6 +64,7 @@ Modal.propTypes = {
   transparent: PropTypes.bool,
   visible: PropTypes.bool,
   onDismiss: PropTypes.func,
+  onShow: PropTypes.func,
 };
 
 Modal.defaultProps = {
diff --git a/React/Views/RCTModalHostView.h b/React/Views/RCTModalHostView.h
index cafe771c8f5e..c67579da0236 100644
--- a/React/Views/RCTModalHostView.h
+++ b/React/Views/RCTModalHostView.h
@@ -10,6 +10,7 @@
 #import <UIKit/UIKit.h>
 
 #import "RCTInvalidating.h"
+#import "RCTView.h"
 
 @class RCTBridge;
 
@@ -18,6 +19,8 @@
 @property (nonatomic, assign, getter=isAnimated) BOOL animated;
 @property (nonatomic, assign, getter=isTransparent) BOOL transparent;
 
+@property (nonatomic, copy) RCTDirectEventBlock onShow;
+
 - (instancetype)initWithBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
 
 @end
diff --git a/React/Views/RCTModalHostView.m b/React/Views/RCTModalHostView.m
index 63121a37f757..75e50105c488 100644
--- a/React/Views/RCTModalHostView.m
+++ b/React/Views/RCTModalHostView.m
@@ -86,7 +86,11 @@ - (void)didMoveToWindow
 
   if (!_isPresented && self.window) {
     RCTAssert(self.reactViewController, @"Can't present modal view controller without a presenting view controller");
-    [self.reactViewController presentViewController:_modalViewController animated:self.animated completion:nil];
+    [self.reactViewController presentViewController:_modalViewController animated:self.animated completion:^{
+      if (_onShow) {
+        _onShow(nil);
+      }
+    }];
     _isPresented = YES;
   }
 }
diff --git a/React/Views/RCTModalHostViewManager.m b/React/Views/RCTModalHostViewManager.m
index ae3b21f2c063..be4e6b79e050 100644
--- a/React/Views/RCTModalHostViewManager.m
+++ b/React/Views/RCTModalHostViewManager.m
@@ -40,5 +40,6 @@ - (void)invalidate
 
 RCT_EXPORT_VIEW_PROPERTY(animated, BOOL)
 RCT_EXPORT_VIEW_PROPERTY(transparent, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(onShow, RCTDirectEventBlock)
 
 @end

From 1b4c23e001c622fdb65d58e5da9fb249005cfad3 Mon Sep 17 00:00:00 2001
From: Andy Street <andrews@fb.com>
Date: Thu, 3 Mar 2016 13:33:14 -0800
Subject: [PATCH 1409/1411] WebWorkers: Update WebWorker sample to use
 networking/timers

Summary: Updates the sample to use native modules.

Differential Revision: D2932319

fb-gh-sync-id: 9dc12789839ec2d65e98205508d958d0c8c5b46e
shipit-source-id: 9dc12789839ec2d65e98205508d958d0c8c5b46e
---
 ReactAndroid/src/main/jni/react/JSCExecutor.cpp | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
index 6d2c7e5d8873..0341677d973c 100644
--- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
+++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp
@@ -221,10 +221,6 @@ void JSCExecutor::loadApplicationUnbundle(
 }
 
 void JSCExecutor::flush() {
-  if (m_owner != nullptr) {
-    // Web workers don't support native modules yet
-    return;
-  }
   // TODO: Make this a first class function instead of evaling. #9317773
   std::string calls = executeJSCallWithJSC(m_context, "flushedQueue", std::vector<folly::dynamic>());
   m_bridge->callNativeModules(*this, calls, true);

From d5d9c5a7c668c45042ab0a79f3f42dc0f4a616ac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mart=C3=ADn=20Bigio?= <martinb@fb.com>
Date: Thu, 3 Mar 2016 16:06:30 -0800
Subject: [PATCH 1410/1411] Tweak HMR updates order

Reviewed By: sam-swarr

Differential Revision: D3007914

fb-gh-sync-id: efceeeafdaaf82e47ee2d2e8a313b64694988b5c
shipit-source-id: efceeeafdaaf82e47ee2d2e8a313b64694988b5c
---
 local-cli/server/util/attachHMRServer.js | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js
index 22323d071e23..362fdadf57a5 100644
--- a/local-cli/server/util/attachHMRServer.js
+++ b/local-cli/server/util/attachHMRServer.js
@@ -174,6 +174,16 @@ function attachHMRServer({httpServer, path, packagerServer}) {
                       }
                     });
 
+                    // Need to send modules to the client in an order it can
+                    // process them: if a new dependency graph was uncovered
+                    // because a new dependency was added, the file that was
+                    // changed, which is the root of the dependency tree that
+                    // will be sent, needs to be the last module that gets
+                    // processed. Reversing the new modules makes sense
+                    // because we get them through the resolver which returns
+                    // a BFS ordered list.
+                    modulesToUpdate.reverse();
+
                     // invalidate caches
                     client.dependenciesCache = dependenciesCache;
                     client.dependenciesModulesCache = dependenciesModulesCache;

From 8a1629166edea6064f409b6206f1cc2d2eee61a4 Mon Sep 17 00:00:00 2001
From: Wenjing Wang <wenjingw@fb.com>
Date: Thu, 3 Mar 2016 18:56:27 -0800
Subject: [PATCH 1411/1411] nested emit call in a queue should be handled in
 FIFO

Summary: I think we should dispose events in FIFO order

Reviewed By: fkgozali

Differential Revision: D2987425

fb-gh-sync-id: a4ad256512725d0bed0086b642e10fe7e7715070
shipit-source-id: a4ad256512725d0bed0086b642e10fe7e7715070
---
 .../Navigation/NavigationEventEmitter.js      |  2 +-
 .../__tests__/NavigationEventEmitter-test.js  | 26 +++++++++++++++++++
 2 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/Libraries/CustomComponents/Navigator/Navigation/NavigationEventEmitter.js b/Libraries/CustomComponents/Navigator/Navigation/NavigationEventEmitter.js
index a2abd3d55bdf..339c95734038 100644
--- a/Libraries/CustomComponents/Navigator/Navigation/NavigationEventEmitter.js
+++ b/Libraries/CustomComponents/Navigator/Navigation/NavigationEventEmitter.js
@@ -59,7 +59,7 @@ class NavigationEventEmitter extends EventEmitter {
       // An event cycle that was previously created hasn't finished yet.
       // Put this event cycle into the queue and will finish them later.
       var args: any = Array.prototype.slice.call(arguments);
-      this._emitQueue.unshift(args);
+      this._emitQueue.push(args);
       return;
     }
 
diff --git a/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationEventEmitter-test.js b/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationEventEmitter-test.js
index 63b1ccd0ba1e..9e9aef476807 100644
--- a/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationEventEmitter-test.js
+++ b/Libraries/CustomComponents/Navigator/Navigation/__tests__/NavigationEventEmitter-test.js
@@ -100,6 +100,32 @@ describe('NavigationEventEmitter', () => {
     expect(logs).toEqual([1, 2, 3, 4, 5]);
   });
 
+  it('puts nested emit call in a queue should be in sequence order', () => {
+    var context = {};
+    var emitter = new NavigationEventEmitter(context);
+    var logs = [];
+
+    emitter.addListener('one', () => {
+      logs.push(1);
+      emitter.emit('two');
+      emitter.emit('three');
+      logs.push(2);
+    });
+
+    emitter.addListener('two', () => {
+      logs.push(3);
+      logs.push(4);
+    });
+
+    emitter.addListener('three', () => {
+      logs.push(5);
+    });
+
+    emitter.emit('one');
+
+    expect(logs).toEqual([1, 2, 3, 4, 5]);
+  });
+
   it('calls callback after emitting', () => {
     var context = {};
     var emitter = new NavigationEventEmitter(context);
